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

Generated by: LCOV version 1.13