LCOV - code coverage report
Current view: top level - source3/libads - kerberos.c (source / functions) Hit Total Coverage
Test: coverage report for master 98b443d9 Lines: 220 366 60.1 %
Date: 2024-05-31 13:13:24 Functions: 8 10 80.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             :    kerberos utility library
       4             :    Copyright (C) Andrew Tridgell 2001
       5             :    Copyright (C) Remus Koos 2001
       6             :    Copyright (C) Nalin Dahyabhai <nalin@redhat.com> 2004.
       7             :    Copyright (C) Jeremy Allison 2004.
       8             :    Copyright (C) Gerald Carter 2006.
       9             : 
      10             :    This program is free software; you can redistribute it and/or modify
      11             :    it under the terms of the GNU General Public License as published by
      12             :    the Free Software Foundation; either version 3 of the License, or
      13             :    (at your option) any later version.
      14             : 
      15             :    This program is distributed in the hope that it will be useful,
      16             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      17             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      18             :    GNU General Public License for more details.
      19             : 
      20             :    You should have received a copy of the GNU General Public License
      21             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      22             : */
      23             : 
      24             : #include "includes.h"
      25             : #include "libsmb/namequery.h"
      26             : #include "system/filesys.h"
      27             : #include "smb_krb5.h"
      28             : #include "../librpc/gen_ndr/ndr_misc.h"
      29             : #include "libads/kerberos_proto.h"
      30             : #include "libads/cldap.h"
      31             : #include "secrets.h"
      32             : #include "../lib/tsocket/tsocket.h"
      33             : #include "lib/util/asn1.h"
      34             : 
      35             : #ifdef HAVE_KRB5
      36             : 
      37             : /*
      38             :   we use a prompter to avoid a crash bug in the kerberos libs when
      39             :   dealing with empty passwords
      40             :   this prompter is just a string copy ...
      41             : */
      42             : static krb5_error_code
      43          16 : kerb_prompter(krb5_context ctx, void *data,
      44             :                const char *name,
      45             :                const char *banner,
      46             :                int num_prompts,
      47             :                krb5_prompt prompts[])
      48             : {
      49          16 :         if (num_prompts == 0) return 0;
      50           0 :         if (num_prompts == 2) {
      51             :                 /*
      52             :                  * only heimdal has a prompt type and we need to deal with it here to
      53             :                  * avoid loops.
      54             :                  *
      55             :                  * removing the prompter completely is not an option as at least these
      56             :                  * versions would crash: heimdal-1.0.2 and heimdal-1.1. Later heimdal
      57             :                  * version have looping detection and return with a proper error code.
      58             :                  */
      59             : 
      60             : #if defined(HAVE_KRB5_PROMPT_TYPE) /* Heimdal */
      61           0 :                  if (prompts[0].type == KRB5_PROMPT_TYPE_NEW_PASSWORD &&
      62           0 :                      prompts[1].type == KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN) {
      63             :                         /*
      64             :                          * We don't want to change passwords here. We're
      65             :                          * called from heimdal when the KDC returns
      66             :                          * KRB5KDC_ERR_KEY_EXPIRED, but at this point we don't
      67             :                          * have the chance to ask the user for a new
      68             :                          * password. If we return 0 (i.e. success), we will be
      69             :                          * spinning in the endless for-loop in
      70             :                          * change_password() in
      71             :                          * third_party/heimdal/lib/krb5/init_creds_pw.c
      72             :                          */
      73           0 :                         return KRB5KDC_ERR_KEY_EXPIRED;
      74             :                 }
      75             : #elif defined(HAVE_KRB5_GET_PROMPT_TYPES) /* MIT */
      76           0 :                 krb5_prompt_type *prompt_types = NULL;
      77             : 
      78           0 :                 prompt_types = krb5_get_prompt_types(ctx);
      79           0 :                 if (prompt_types != NULL) {
      80           0 :                         if (prompt_types[0] == KRB5_PROMPT_TYPE_NEW_PASSWORD &&
      81           0 :                             prompt_types[1] == KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN) {
      82           0 :                                 return KRB5KDC_ERR_KEY_EXP;
      83             :                         }
      84             :                 }
      85             : #endif
      86             :         }
      87             : 
      88           0 :         memset(prompts[0].reply->data, '\0', prompts[0].reply->length);
      89           0 :         if (prompts[0].reply->length > 0) {
      90           0 :                 if (data) {
      91           0 :                         strncpy((char *)prompts[0].reply->data, (const char *)data,
      92           0 :                                 prompts[0].reply->length-1);
      93           0 :                         prompts[0].reply->length = strlen((const char *)prompts[0].reply->data);
      94             :                 } else {
      95           0 :                         prompts[0].reply->length = 0;
      96             :                 }
      97             :         }
      98           0 :         return 0;
      99             : }
     100             : 
     101             : /*
     102             :   simulate a kinit, putting the tgt in the given cache location. If cache_name == NULL
     103             :   place in default cache location.
     104             :   remus@snapserver.com
     105             : */
     106        2483 : int kerberos_kinit_password_ext(const char *given_principal,
     107             :                                 const char *password,
     108             :                                 int time_offset,
     109             :                                 time_t *expire_time,
     110             :                                 time_t *renew_till_time,
     111             :                                 const char *cache_name,
     112             :                                 bool request_pac,
     113             :                                 bool add_netbios_addr,
     114             :                                 time_t renewable_time,
     115             :                                 TALLOC_CTX *mem_ctx,
     116             :                                 char **_canon_principal,
     117             :                                 char **_canon_realm,
     118             :                                 NTSTATUS *ntstatus)
     119             : {
     120        2483 :         TALLOC_CTX *frame = talloc_stackframe();
     121        2483 :         krb5_context ctx = NULL;
     122        2483 :         krb5_error_code code = 0;
     123        2483 :         krb5_ccache cc = NULL;
     124        2483 :         krb5_principal me = NULL;
     125        2483 :         krb5_principal canon_princ = NULL;
     126           0 :         krb5_creds my_creds;
     127        2483 :         krb5_get_init_creds_opt *opt = NULL;
     128        2483 :         smb_krb5_addresses *addr = NULL;
     129        2483 :         char *canon_principal = NULL;
     130        2483 :         char *canon_realm = NULL;
     131             : 
     132        2483 :         ZERO_STRUCT(my_creds);
     133             : 
     134        2483 :         if (cache_name == NULL) {
     135           0 :                 DBG_DEBUG("Missing ccache for [%s] and config [%s]\n",
     136             :                           given_principal,
     137             :                           getenv("KRB5_CONFIG"));
     138           0 :                 TALLOC_FREE(frame);
     139           0 :                 return EINVAL;
     140             :         }
     141             : 
     142        2483 :         code = smb_krb5_init_context_common(&ctx);
     143        2483 :         if (code != 0) {
     144           0 :                 DBG_ERR("kerberos init context failed (%s)\n",
     145             :                         error_message(code));
     146           0 :                 TALLOC_FREE(frame);
     147           0 :                 return code;
     148             :         }
     149             : 
     150        2483 :         if (time_offset != 0) {
     151           0 :                 krb5_set_real_time(ctx, time(NULL) + time_offset, 0);
     152             :         }
     153             : 
     154        2483 :         DBG_DEBUG("as %s using [%s] as ccache and config [%s]\n",
     155             :                   given_principal,
     156             :                   cache_name,
     157             :                   getenv("KRB5_CONFIG"));
     158             : 
     159        2483 :         if ((code = krb5_cc_resolve(ctx, cache_name, &cc))) {
     160           0 :                 goto out;
     161             :         }
     162             : 
     163        2483 :         if ((code = smb_krb5_parse_name(ctx, given_principal, &me))) {
     164           0 :                 goto out;
     165             :         }
     166             : 
     167        2483 :         if ((code = krb5_get_init_creds_opt_alloc(ctx, &opt))) {
     168           0 :                 goto out;
     169             :         }
     170             : 
     171        2483 :         krb5_get_init_creds_opt_set_renew_life(opt, renewable_time);
     172        2483 :         krb5_get_init_creds_opt_set_forwardable(opt, True);
     173             : 
     174             :         /* Turn on canonicalization for lower case realm support */
     175             : #ifdef SAMBA4_USES_HEIMDAL
     176        1586 :         krb5_get_init_creds_opt_set_win2k(ctx, opt, true);
     177        1586 :         krb5_get_init_creds_opt_set_canonicalize(ctx, opt, true);
     178             : #else /* MIT */
     179         897 :         krb5_get_init_creds_opt_set_canonicalize(opt, true);
     180             : #endif /* MIT */
     181             : #if 0
     182             :         /* insane testing */
     183             :         krb5_get_init_creds_opt_set_tkt_life(opt, 60);
     184             : #endif
     185             : 
     186             : #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PAC_REQUEST
     187        2483 :         if (request_pac) {
     188           0 :                 if ((code = krb5_get_init_creds_opt_set_pac_request(ctx, opt, (krb5_boolean)request_pac))) {
     189           0 :                         goto out;
     190             :                 }
     191             :         }
     192             : #endif
     193        2483 :         if (add_netbios_addr) {
     194           0 :                 if ((code = smb_krb5_gen_netbios_krb5_address(&addr,
     195             :                                                         lp_netbios_name()))) {
     196           0 :                         goto out;
     197             :                 }
     198           0 :                 krb5_get_init_creds_opt_set_address_list(opt, addr->addrs);
     199             :         }
     200             : 
     201        2483 :         if ((code = krb5_get_init_creds_password(ctx, &my_creds, me, discard_const_p(char,password),
     202             :                                                  kerb_prompter, discard_const_p(char, password),
     203             :                                                  0, NULL, opt))) {
     204         431 :                 goto out;
     205             :         }
     206             : 
     207        2052 :         canon_princ = my_creds.client;
     208             : 
     209        2052 :         code = smb_krb5_unparse_name(frame,
     210             :                                      ctx,
     211             :                                      canon_princ,
     212             :                                      &canon_principal);
     213        2052 :         if (code != 0) {
     214           0 :                 goto out;
     215             :         }
     216             : 
     217        2052 :         DBG_DEBUG("%s mapped to %s\n", given_principal, canon_principal);
     218             : 
     219        2052 :         canon_realm = smb_krb5_principal_get_realm(frame, ctx, canon_princ);
     220        2052 :         if (canon_realm == NULL) {
     221           0 :                 code = ENOMEM;
     222           0 :                 goto out;
     223             :         }
     224             : 
     225        2052 :         if ((code = krb5_cc_initialize(ctx, cc, canon_princ))) {
     226           0 :                 goto out;
     227             :         }
     228             : 
     229        2052 :         if ((code = krb5_cc_store_cred(ctx, cc, &my_creds))) {
     230           0 :                 goto out;
     231             :         }
     232             : 
     233        2052 :         if (expire_time) {
     234           0 :                 *expire_time = (time_t) my_creds.times.endtime;
     235             :         }
     236             : 
     237        2052 :         if (renew_till_time) {
     238           0 :                 *renew_till_time = (time_t) my_creds.times.renew_till;
     239             :         }
     240             : 
     241        2052 :         if (_canon_principal != NULL) {
     242        2050 :                 *_canon_principal = talloc_move(mem_ctx, &canon_principal);
     243             :         }
     244        2052 :         if (_canon_realm != NULL) {
     245        2050 :                 *_canon_realm = talloc_move(mem_ctx, &canon_realm);
     246             :         }
     247           2 :  out:
     248        2483 :         if (ntstatus) {
     249             :                 /* fast path */
     250           0 :                 if (code == 0) {
     251           0 :                         *ntstatus = NT_STATUS_OK;
     252           0 :                         goto cleanup;
     253             :                 }
     254             : 
     255             :                 /* fall back to self-made-mapping */
     256           0 :                 *ntstatus = krb5_to_nt_status(code);
     257             :         }
     258             : 
     259        2483 :  cleanup:
     260        2483 :         krb5_free_cred_contents(ctx, &my_creds);
     261        2483 :         if (me) {
     262        2483 :                 krb5_free_principal(ctx, me);
     263             :         }
     264        2483 :         if (addr) {
     265           0 :                 smb_krb5_free_addresses(ctx, addr);
     266             :         }
     267        2483 :         if (opt) {
     268        2483 :                 krb5_get_init_creds_opt_free(ctx, opt);
     269             :         }
     270        2483 :         if (cc) {
     271        2483 :                 krb5_cc_close(ctx, cc);
     272             :         }
     273        2483 :         if (ctx) {
     274        2483 :                 krb5_free_context(ctx);
     275             :         }
     276        2483 :         TALLOC_FREE(frame);
     277        2483 :         return code;
     278             : }
     279             : 
     280           0 : int ads_kdestroy(const char *cc_name)
     281             : {
     282           0 :         krb5_error_code code;
     283           0 :         krb5_context ctx = NULL;
     284           0 :         krb5_ccache cc = NULL;
     285             : 
     286           0 :         code = smb_krb5_init_context_common(&ctx);
     287           0 :         if (code != 0) {
     288           0 :                 DBG_ERR("kerberos init context failed (%s)\n",
     289             :                         error_message(code));
     290           0 :                 return code;
     291             :         }
     292             : 
     293             :         /*
     294             :          * This should not happen, if
     295             :          * we need that behaviour we
     296             :          * should add an ads_kdestroy_default()
     297             :          */
     298           0 :         SMB_ASSERT(cc_name != NULL);
     299             : 
     300           0 :         code = krb5_cc_resolve(ctx, cc_name, &cc);
     301           0 :         if (code != 0) {
     302           0 :                 DBG_NOTICE("krb5_cc_resolve(%s) failed: %s\n",
     303             :                            cc_name, error_message(code));
     304           0 :                 krb5_free_context(ctx);
     305           0 :                 return code;
     306             :         }
     307             : 
     308           0 :         code = krb5_cc_destroy(ctx, cc);
     309           0 :         if (code != 0) {
     310           0 :                 DBG_ERR("krb5_cc_destroy(%s) failed: %s\n",
     311             :                         cc_name, error_message(code));
     312             :         }
     313             : 
     314           0 :         krb5_free_context (ctx);
     315           0 :         return code;
     316             : }
     317             : 
     318           0 : int create_kerberos_key_from_string(krb5_context context,
     319             :                                         krb5_principal host_princ,
     320             :                                         krb5_principal salt_princ,
     321             :                                         krb5_data *password,
     322             :                                         krb5_keyblock *key,
     323             :                                         krb5_enctype enctype,
     324             :                                         bool no_salt)
     325             : {
     326           0 :         int ret;
     327             :         /*
     328             :          * Check if we've determined that the KDC is salting keys for this
     329             :          * principal/enctype in a non-obvious way.  If it is, try to match
     330             :          * its behavior.
     331             :          */
     332           0 :         if (no_salt) {
     333           0 :                 KRB5_KEY_DATA(key) = (KRB5_KEY_DATA_CAST *)SMB_MALLOC(password->length);
     334           0 :                 if (!KRB5_KEY_DATA(key)) {
     335           0 :                         return ENOMEM;
     336             :                 }
     337           0 :                 memcpy(KRB5_KEY_DATA(key), password->data, password->length);
     338           0 :                 KRB5_KEY_LENGTH(key) = password->length;
     339           0 :                 KRB5_KEY_TYPE(key) = enctype;
     340           0 :                 return 0;
     341             :         }
     342           0 :         ret = smb_krb5_create_key_from_string(context,
     343             :                                               salt_princ ? salt_princ : host_princ,
     344             :                                               NULL,
     345             :                                               password,
     346             :                                               enctype,
     347             :                                               key);
     348           0 :         return ret;
     349             : }
     350             : 
     351             : /************************************************************************
     352             : ************************************************************************/
     353             : 
     354           2 : int kerberos_kinit_password(const char *principal,
     355             :                             const char *password,
     356             :                             int time_offset,
     357             :                             const char *cache_name)
     358             : {
     359           2 :         return kerberos_kinit_password_ext(principal,
     360             :                                            password,
     361             :                                            time_offset,
     362             :                                            0,
     363             :                                            0,
     364             :                                            cache_name,
     365             :                                            False,
     366             :                                            False,
     367             :                                            0,
     368             :                                            NULL,
     369             :                                            NULL,
     370             :                                            NULL,
     371             :                                            NULL);
     372             : }
     373             : 
     374             : /************************************************************************
     375             : ************************************************************************/
     376             : 
     377             : /************************************************************************
     378             :  Create a string list of available kdc's, possibly searching by sitename.
     379             :  Does DNS queries.
     380             : 
     381             :  If "sitename" is given, the DC's in that site are listed first.
     382             : 
     383             : ************************************************************************/
     384             : 
     385         432 : static void add_sockaddr_unique(struct sockaddr_storage *addrs, size_t *num_addrs,
     386             :                                 const struct sockaddr_storage *addr)
     387             : {
     388           0 :         size_t i;
     389             : 
     390         432 :         for (i=0; i<*num_addrs; i++) {
     391         216 :                 if (sockaddr_equal((const struct sockaddr *)&addrs[i],
     392             :                                    (const struct sockaddr *)addr)) {
     393         216 :                         return;
     394             :                 }
     395             :         }
     396         216 :         addrs[i] = *addr;
     397         216 :         *num_addrs += 1;
     398             : }
     399             : 
     400             : /* print_canonical_sockaddr prints an ipv6 addr in the form of
     401             : * [ipv6.addr]. This string, when put in a generated krb5.conf file is not
     402             : * always properly dealt with by some older krb5 libraries. Adding the hard-coded
     403             : * portnumber workarounds the issue. - gd */
     404             : 
     405         490 : static char *print_canonical_sockaddr_with_port(TALLOC_CTX *mem_ctx,
     406             :                                                 const struct sockaddr_storage *pss)
     407             : {
     408         490 :         char *str = NULL;
     409             : 
     410         490 :         str = print_canonical_sockaddr(mem_ctx, pss);
     411         490 :         if (str == NULL) {
     412           0 :                 return NULL;
     413             :         }
     414             : 
     415         490 :         if (pss->ss_family != AF_INET6) {
     416         282 :                 return str;
     417             :         }
     418             : 
     419             : #if defined(HAVE_IPV6)
     420         208 :         str = talloc_asprintf_append(str, ":88");
     421             : #endif
     422         208 :         return str;
     423             : }
     424             : 
     425         274 : static char *get_kdc_ip_string(char *mem_ctx,
     426             :                 const char *realm,
     427             :                 const char *sitename,
     428             :                 const struct sockaddr_storage *pss)
     429             : {
     430         274 :         TALLOC_CTX *frame = talloc_stackframe();
     431           0 :         size_t i;
     432         274 :         struct samba_sockaddr *ip_sa_site = NULL;
     433         274 :         struct samba_sockaddr *ip_sa_nonsite = NULL;
     434         274 :         struct samba_sockaddr sa = {0};
     435         274 :         size_t count_site = 0;
     436           0 :         size_t count_nonsite;
     437           0 :         size_t num_dcs;
     438         274 :         struct sockaddr_storage *dc_addrs = NULL;
     439         274 :         struct tsocket_address **dc_addrs2 = NULL;
     440         274 :         const struct tsocket_address * const *dc_addrs3 = NULL;
     441         274 :         char *result = NULL;
     442         274 :         struct netlogon_samlogon_response **responses = NULL;
     443           0 :         NTSTATUS status;
     444           0 :         bool ok;
     445         274 :         char *kdc_str = NULL;
     446         274 :         char *canon_sockaddr = NULL;
     447             : 
     448         274 :         SMB_ASSERT(pss != NULL);
     449             : 
     450         274 :         canon_sockaddr = print_canonical_sockaddr_with_port(frame, pss);
     451         274 :         if (canon_sockaddr == NULL) {
     452           0 :                 goto out;
     453             :         }
     454             : 
     455         274 :         kdc_str = talloc_asprintf(frame,
     456             :                                   "\t\tkdc = %s\n",
     457             :                                   canon_sockaddr);
     458         274 :         if (kdc_str == NULL) {
     459           0 :                 goto out;
     460             :         }
     461             : 
     462         274 :         ok = sockaddr_storage_to_samba_sockaddr(&sa, pss);
     463         274 :         if (!ok) {
     464           0 :                 goto out;
     465             :         }
     466             : 
     467             :         /*
     468             :          * First get the KDC's only in this site, the rest will be
     469             :          * appended later
     470             :          */
     471             : 
     472         274 :         if (sitename) {
     473         272 :                 status = get_kdc_list(frame,
     474             :                                         realm,
     475             :                                         sitename,
     476             :                                         &ip_sa_site,
     477             :                                         &count_site);
     478         272 :                 if (!NT_STATUS_IS_OK(status)) {
     479           0 :                         DBG_ERR("get_kdc_list fail %s\n",
     480             :                                 nt_errstr(status));
     481           0 :                         goto out;
     482             :                 }
     483         272 :                 DBG_DEBUG("got %zu addresses from site %s search\n",
     484             :                         count_site,
     485             :                         sitename);
     486             :         }
     487             : 
     488             :         /* Get all KDC's. */
     489             : 
     490         274 :         status = get_kdc_list(frame,
     491             :                                         realm,
     492             :                                         NULL,
     493             :                                         &ip_sa_nonsite,
     494             :                                         &count_nonsite);
     495         274 :         if (!NT_STATUS_IS_OK(status)) {
     496           0 :                 DBG_ERR("get_kdc_list (site-less) fail %s\n",
     497             :                         nt_errstr(status));
     498           0 :                 goto out;
     499             :         }
     500         274 :         DBG_DEBUG("got %zu addresses from site-less search\n", count_nonsite);
     501             : 
     502         274 :         if (count_site + count_nonsite < count_site) {
     503             :                 /* Wrap check. */
     504           0 :                 DBG_ERR("get_kdc_list_talloc (site-less) fail wrap error\n");
     505           0 :                 goto out;
     506             :         }
     507             : 
     508             : 
     509         274 :         dc_addrs = talloc_array(talloc_tos(), struct sockaddr_storage,
     510             :                                 count_site + count_nonsite);
     511         274 :         if (dc_addrs == NULL) {
     512           0 :                 goto out;
     513             :         }
     514             : 
     515         274 :         num_dcs = 0;
     516             : 
     517         758 :         for (i = 0; i < count_site; i++) {
     518         484 :                 if (!sockaddr_equal(&sa.u.sa, &ip_sa_site[i].u.sa)) {
     519         216 :                         add_sockaddr_unique(dc_addrs, &num_dcs,
     520         216 :                                             &ip_sa_site[i].u.ss);
     521             :                 }
     522             :         }
     523             : 
     524         760 :         for (i = 0; i < count_nonsite; i++) {
     525         486 :                 if (!sockaddr_equal(&sa.u.sa, &ip_sa_nonsite[i].u.sa)) {
     526         216 :                         add_sockaddr_unique(dc_addrs, &num_dcs,
     527         216 :                                             &ip_sa_nonsite[i].u.ss);
     528             :                 }
     529             :         }
     530             : 
     531         274 :         DBG_DEBUG("%zu additional KDCs to test\n", num_dcs);
     532         274 :         if (num_dcs == 0) {
     533             :                 /*
     534             :                  * We do not have additional KDCs, but we have the one passed
     535             :                  * in via `pss`. So just use that one and leave.
     536             :                  */
     537          58 :                 result = talloc_move(mem_ctx, &kdc_str);
     538          58 :                 goto out;
     539             :         }
     540             : 
     541         216 :         dc_addrs2 = talloc_zero_array(talloc_tos(),
     542             :                                       struct tsocket_address *,
     543             :                                       num_dcs);
     544         216 :         if (dc_addrs2 == NULL) {
     545           0 :                 goto out;
     546             :         }
     547             : 
     548         432 :         for (i=0; i<num_dcs; i++) {
     549           0 :                 char addr[INET6_ADDRSTRLEN];
     550           0 :                 int ret;
     551             : 
     552         216 :                 print_sockaddr(addr, sizeof(addr), &dc_addrs[i]);
     553             : 
     554         216 :                 ret = tsocket_address_inet_from_strings(dc_addrs2, "ip",
     555             :                                                         addr, LDAP_PORT,
     556             :                                                         &dc_addrs2[i]);
     557         216 :                 if (ret != 0) {
     558           0 :                         status = map_nt_error_from_unix(errno);
     559           0 :                         DEBUG(2,("Failed to create tsocket_address for %s - %s\n",
     560             :                                  addr, nt_errstr(status)));
     561           0 :                         goto out;
     562             :                 }
     563             :         }
     564             : 
     565         216 :         dc_addrs3 = (const struct tsocket_address * const *)dc_addrs2;
     566             : 
     567         432 :         status = cldap_multi_netlogon(talloc_tos(),
     568             :                         dc_addrs3, num_dcs,
     569             :                         realm, lp_netbios_name(),
     570             :                         NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX,
     571         216 :                         MIN(num_dcs, 3), timeval_current_ofs(3, 0), &responses);
     572         216 :         TALLOC_FREE(dc_addrs2);
     573         216 :         dc_addrs3 = NULL;
     574             : 
     575         216 :         if (!NT_STATUS_IS_OK(status)) {
     576           0 :                 DEBUG(10,("get_kdc_ip_string: cldap_multi_netlogon failed: "
     577             :                           "%s\n", nt_errstr(status)));
     578           0 :                 goto out;
     579             :         }
     580             : 
     581         432 :         for (i=0; i<num_dcs; i++) {
     582           0 :                 char *new_kdc_str;
     583             : 
     584         216 :                 if (responses[i] == NULL) {
     585           0 :                         continue;
     586             :                 }
     587             : 
     588             :                 /* Append to the string - inefficient but not done often. */
     589         216 :                 new_kdc_str = talloc_asprintf_append(
     590             :                                 kdc_str,
     591             :                                 "\t\tkdc = %s\n",
     592             :                                 print_canonical_sockaddr_with_port(
     593         216 :                                         mem_ctx, &dc_addrs[i]));
     594         216 :                 if (new_kdc_str == NULL) {
     595           0 :                         goto out;
     596             :                 }
     597         216 :                 kdc_str = new_kdc_str;
     598             :         }
     599             : 
     600         216 :         result = talloc_move(mem_ctx, &kdc_str);
     601         274 : out:
     602         274 :         if (result != NULL) {
     603         274 :                 DBG_DEBUG("Returning\n%s\n", result);
     604             :         } else {
     605           0 :                 DBG_NOTICE("Failed to get KDC ip address\n");
     606             :         }
     607             : 
     608         274 :         TALLOC_FREE(frame);
     609         274 :         return result;
     610             : }
     611             : 
     612             : /************************************************************************
     613             :  Create  a specific krb5.conf file in the private directory pointing
     614             :  at a specific kdc for a realm. Keyed off domain name. Sets
     615             :  KRB5_CONFIG environment variable to point to this file. Must be
     616             :  run as root or will fail (which is a good thing :-).
     617             : ************************************************************************/
     618             : 
     619             : #if !defined(SAMBA4_USES_HEIMDAL) /* MIT version */
     620         134 : static char *get_enctypes(TALLOC_CTX *mem_ctx)
     621             : {
     622         134 :         char *aes_enctypes = NULL;
     623         134 :         const char *legacy_enctypes = "";
     624         134 :         char *enctypes = NULL;
     625             : 
     626         134 :         aes_enctypes = talloc_strdup(mem_ctx, "");
     627         134 :         if (aes_enctypes == NULL) {
     628           0 :                 goto done;
     629             :         }
     630             : 
     631         134 :         if (lp_kerberos_encryption_types() == KERBEROS_ETYPES_ALL ||
     632           0 :             lp_kerberos_encryption_types() == KERBEROS_ETYPES_STRONG) {
     633         134 :                 aes_enctypes = talloc_asprintf_append(
     634             :                     aes_enctypes, "%s", "aes256-cts-hmac-sha1-96 ");
     635         134 :                 if (aes_enctypes == NULL) {
     636           0 :                         goto done;
     637             :                 }
     638         134 :                 aes_enctypes = talloc_asprintf_append(
     639             :                     aes_enctypes, "%s", "aes128-cts-hmac-sha1-96");
     640         134 :                 if (aes_enctypes == NULL) {
     641           0 :                         goto done;
     642             :                 }
     643             :         }
     644             : 
     645         267 :         if (lp_weak_crypto() == SAMBA_WEAK_CRYPTO_ALLOWED &&
     646         133 :             (lp_kerberos_encryption_types() == KERBEROS_ETYPES_ALL ||
     647           0 :              lp_kerberos_encryption_types() == KERBEROS_ETYPES_LEGACY)) {
     648         133 :                 legacy_enctypes = "RC4-HMAC";
     649             :         }
     650             : 
     651             :         enctypes =
     652         134 :             talloc_asprintf(mem_ctx, "\tdefault_tgs_enctypes = %s %s\n"
     653             :                                      "\tdefault_tkt_enctypes = %s %s\n"
     654             :                                      "\tpreferred_enctypes = %s %s\n",
     655             :                             aes_enctypes, legacy_enctypes, aes_enctypes,
     656             :                             legacy_enctypes, aes_enctypes, legacy_enctypes);
     657         134 : done:
     658         134 :         TALLOC_FREE(aes_enctypes);
     659         134 :         return enctypes;
     660             : }
     661             : #else /* Heimdal version */
     662         140 : static char *get_enctypes(TALLOC_CTX *mem_ctx)
     663             : {
     664         140 :         const char *aes_enctypes = "";
     665         140 :         const char *legacy_enctypes = "";
     666         140 :         char *enctypes = NULL;
     667             : 
     668         140 :         if (lp_kerberos_encryption_types() == KERBEROS_ETYPES_ALL ||
     669           0 :             lp_kerberos_encryption_types() == KERBEROS_ETYPES_STRONG) {
     670         140 :                 aes_enctypes =
     671             :                     "aes256-cts-hmac-sha1-96 aes128-cts-hmac-sha1-96";
     672             :         }
     673             : 
     674         140 :         if (lp_kerberos_encryption_types() == KERBEROS_ETYPES_ALL ||
     675           0 :             lp_kerberos_encryption_types() == KERBEROS_ETYPES_LEGACY) {
     676         140 :                 legacy_enctypes = "arcfour-hmac-md5";
     677             :         }
     678             : 
     679         140 :         enctypes = talloc_asprintf(mem_ctx, "\tdefault_etypes = %s %s\n",
     680             :                                    aes_enctypes, legacy_enctypes);
     681             : 
     682         140 :         return enctypes;
     683             : }
     684             : #endif
     685             : 
     686         282 : bool create_local_private_krb5_conf_for_domain(const char *realm,
     687             :                                                 const char *domain,
     688             :                                                 const char *sitename,
     689             :                                                 const struct sockaddr_storage *pss)
     690             : {
     691           0 :         char *dname;
     692         282 :         char *tmpname = NULL;
     693         282 :         char *fname = NULL;
     694         282 :         char *file_contents = NULL;
     695         282 :         char *kdc_ip_string = NULL;
     696         282 :         size_t flen = 0;
     697           0 :         ssize_t ret;
     698           0 :         int fd;
     699         282 :         char *realm_upper = NULL;
     700         282 :         bool result = false;
     701         282 :         char *enctypes = NULL;
     702         282 :         const char *include_system_krb5 = "";
     703           0 :         mode_t mask;
     704             : 
     705         282 :         if (!lp_create_krb5_conf()) {
     706           8 :                 return false;
     707             :         }
     708             : 
     709         274 :         if (realm == NULL) {
     710           0 :                 DEBUG(0, ("No realm has been specified! Do you really want to "
     711             :                           "join an Active Directory server?\n"));
     712           0 :                 return false;
     713             :         }
     714             : 
     715         274 :         if (domain == NULL || pss == NULL) {
     716           0 :                 return false;
     717             :         }
     718             : 
     719         274 :         dname = lock_path(talloc_tos(), "smb_krb5");
     720         274 :         if (!dname) {
     721           0 :                 return false;
     722             :         }
     723         274 :         if ((mkdir(dname, 0755)==-1) && (errno != EEXIST)) {
     724           0 :                 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
     725             :                         "failed to create directory %s. Error was %s\n",
     726             :                         dname, strerror(errno) ));
     727           0 :                 goto done;
     728             :         }
     729             : 
     730         274 :         tmpname = lock_path(talloc_tos(), "smb_tmp_krb5.XXXXXX");
     731         274 :         if (!tmpname) {
     732           0 :                 goto done;
     733             :         }
     734             : 
     735         274 :         fname = talloc_asprintf(dname, "%s/krb5.conf.%s", dname, domain);
     736         274 :         if (!fname) {
     737           0 :                 goto done;
     738             :         }
     739             : 
     740         274 :         DEBUG(10,("create_local_private_krb5_conf_for_domain: fname = %s, realm = %s, domain = %s\n",
     741             :                 fname, realm, domain ));
     742             : 
     743         274 :         realm_upper = talloc_strdup(fname, realm);
     744         274 :         if (!strupper_m(realm_upper)) {
     745           0 :                 goto done;
     746             :         }
     747             : 
     748         274 :         kdc_ip_string = get_kdc_ip_string(dname, realm, sitename, pss);
     749         274 :         if (!kdc_ip_string) {
     750           0 :                 goto done;
     751             :         }
     752             : 
     753         274 :         enctypes = get_enctypes(fname);
     754         274 :         if (enctypes == NULL) {
     755           0 :                 goto done;
     756             :         }
     757             : 
     758             : #if !defined(SAMBA4_USES_HEIMDAL)
     759         134 :         if (lp_include_system_krb5_conf()) {
     760           2 :                 include_system_krb5 = "include /etc/krb5.conf";
     761             :         }
     762             : #endif
     763             : 
     764             :         /*
     765             :          * We are setting 'dns_lookup_kdc' to true, because we want to lookup
     766             :          * KDCs which are not configured via DNS SRV records, eg. if we do:
     767             :          *
     768             :          *     net ads join -Uadmin@otherdomain
     769             :          */
     770           0 :         file_contents =
     771         274 :             talloc_asprintf(fname,
     772             :                             "[libdefaults]\n"
     773             :                             "\tdefault_realm = %s\n"
     774             :                             "%s"
     775             :                             "\tdns_lookup_realm = false\n"
     776             :                             "\tdns_lookup_kdc = true\n\n"
     777             :                             "[realms]\n\t%s = {\n"
     778             :                             "%s\t}\n"
     779             :                             "\t%s = {\n"
     780             :                             "%s\t}\n"
     781             :                             "%s\n",
     782             :                             realm_upper,
     783             :                             enctypes,
     784             :                             realm_upper,
     785             :                             kdc_ip_string,
     786             :                             domain,
     787             :                             kdc_ip_string,
     788             :                             include_system_krb5);
     789             : 
     790         274 :         if (!file_contents) {
     791           0 :                 goto done;
     792             :         }
     793             : 
     794         274 :         flen = strlen(file_contents);
     795             : 
     796         274 :         mask = umask(S_IRWXO | S_IRWXG);
     797         274 :         fd = mkstemp(tmpname);
     798         274 :         umask(mask);
     799         274 :         if (fd == -1) {
     800           0 :                 DBG_ERR("mkstemp failed, for file %s. Errno %s\n",
     801             :                         tmpname,
     802             :                         strerror(errno));
     803           0 :                 goto done;
     804             :         }
     805             : 
     806         274 :         if (fchmod(fd, 0644)==-1) {
     807           0 :                 DEBUG(0,("create_local_private_krb5_conf_for_domain: fchmod failed for %s."
     808             :                         " Errno %s\n",
     809             :                         tmpname, strerror(errno) ));
     810           0 :                 unlink(tmpname);
     811           0 :                 close(fd);
     812           0 :                 goto done;
     813             :         }
     814             : 
     815         274 :         ret = write(fd, file_contents, flen);
     816         274 :         if (flen != ret) {
     817           0 :                 DEBUG(0,("create_local_private_krb5_conf_for_domain: write failed,"
     818             :                         " returned %d (should be %u). Errno %s\n",
     819             :                         (int)ret, (unsigned int)flen, strerror(errno) ));
     820           0 :                 unlink(tmpname);
     821           0 :                 close(fd);
     822           0 :                 goto done;
     823             :         }
     824         274 :         if (close(fd)==-1) {
     825           0 :                 DEBUG(0,("create_local_private_krb5_conf_for_domain: close failed."
     826             :                         " Errno %s\n", strerror(errno) ));
     827           0 :                 unlink(tmpname);
     828           0 :                 goto done;
     829             :         }
     830             : 
     831         274 :         if (rename(tmpname, fname) == -1) {
     832           0 :                 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
     833             :                         "of %s to %s failed. Errno %s\n",
     834             :                         tmpname, fname, strerror(errno) ));
     835           0 :                 unlink(tmpname);
     836           0 :                 goto done;
     837             :         }
     838             : 
     839         274 :         DBG_INFO("wrote file %s with realm %s KDC list:\n%s\n",
     840             :                  fname, realm_upper, kdc_ip_string);
     841             : 
     842             :         /* Set the environment variable to this file. */
     843         274 :         setenv("KRB5_CONFIG", fname, 1);
     844             : 
     845         274 :         result = true;
     846             : 
     847             : #if defined(OVERWRITE_SYSTEM_KRB5_CONF)
     848             : 
     849             : #define SYSTEM_KRB5_CONF_PATH "/etc/krb5.conf"
     850             :         /* Insanity, sheer insanity..... */
     851             : 
     852             :         if (strequal(realm, lp_realm())) {
     853             :                 SMB_STRUCT_STAT sbuf;
     854             : 
     855             :                 if (sys_lstat(SYSTEM_KRB5_CONF_PATH, &sbuf, false) == 0) {
     856             :                         if (S_ISLNK(sbuf.st_ex_mode) && sbuf.st_ex_size) {
     857             :                                 int lret;
     858             :                                 size_t alloc_size = sbuf.st_ex_size + 1;
     859             :                                 char *linkpath = talloc_array(talloc_tos(), char,
     860             :                                                 alloc_size);
     861             :                                 if (!linkpath) {
     862             :                                         goto done;
     863             :                                 }
     864             :                                 lret = readlink(SYSTEM_KRB5_CONF_PATH, linkpath,
     865             :                                                 alloc_size - 1);
     866             :                                 if (lret == -1) {
     867             :                                         TALLOC_FREE(linkpath);
     868             :                                         goto done;
     869             :                                 }
     870             :                                 linkpath[lret] = '\0';
     871             : 
     872             :                                 if (strcmp(linkpath, fname) == 0) {
     873             :                                         /* Symlink already exists. */
     874             :                                         TALLOC_FREE(linkpath);
     875             :                                         goto done;
     876             :                                 }
     877             :                                 TALLOC_FREE(linkpath);
     878             :                         }
     879             :                 }
     880             : 
     881             :                 /* Try and replace with a symlink. */
     882             :                 if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
     883             :                         const char *newpath = SYSTEM_KRB5_CONF_PATH ".saved";
     884             :                         if (errno != EEXIST) {
     885             :                                 DEBUG(0,("create_local_private_krb5_conf_for_domain: symlink "
     886             :                                         "of %s to %s failed. Errno %s\n",
     887             :                                         fname, SYSTEM_KRB5_CONF_PATH, strerror(errno) ));
     888             :                                 goto done; /* Not a fatal error. */
     889             :                         }
     890             : 
     891             :                         /* Yes, this is a race condition... too bad. */
     892             :                         if (rename(SYSTEM_KRB5_CONF_PATH, newpath) == -1) {
     893             :                                 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
     894             :                                         "of %s to %s failed. Errno %s\n",
     895             :                                         SYSTEM_KRB5_CONF_PATH, newpath,
     896             :                                         strerror(errno) ));
     897             :                                 goto done; /* Not a fatal error. */
     898             :                         }
     899             : 
     900             :                         if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
     901             :                                 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
     902             :                                         "forced symlink of %s to /etc/krb5.conf failed. Errno %s\n",
     903             :                                         fname, strerror(errno) ));
     904             :                                 goto done; /* Not a fatal error. */
     905             :                         }
     906             :                 }
     907             :         }
     908             : #endif
     909             : 
     910         274 : done:
     911         274 :         TALLOC_FREE(tmpname);
     912         274 :         TALLOC_FREE(dname);
     913             : 
     914         274 :         return result;
     915             : }
     916             : #endif

Generated by: LCOV version 1.14