LCOV - code coverage report
Current view: top level - source3/libads - kerberos.c (source / functions) Hit Total Coverage
Test: coverage report for master 70ed9daf Lines: 230 363 63.4 %
Date: 2024-01-11 09:59:51 Functions: 9 10 90.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          17 : 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          17 :         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 heimdal 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             :                          * third_party/heimdal/lib/krb5/init_creds_pw.c
      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       14532 : 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       14532 :         TALLOC_CTX *frame = talloc_stackframe();
     123       14532 :         krb5_context ctx = NULL;
     124       14532 :         krb5_error_code code = 0;
     125       14532 :         krb5_ccache cc = NULL;
     126       14532 :         krb5_principal me = NULL;
     127       14532 :         krb5_principal canon_princ = NULL;
     128           0 :         krb5_creds my_creds;
     129       14532 :         krb5_get_init_creds_opt *opt = NULL;
     130       14532 :         smb_krb5_addresses *addr = NULL;
     131       14532 :         char *canon_principal = NULL;
     132       14532 :         char *canon_realm = NULL;
     133             : 
     134       14532 :         ZERO_STRUCT(my_creds);
     135             : 
     136       14532 :         code = smb_krb5_init_context_common(&ctx);
     137       14532 :         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       14532 :         if (time_offset != 0) {
     145           0 :                 krb5_set_real_time(ctx, time(NULL) + time_offset, 0);
     146             :         }
     147             : 
     148       14532 :         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       14532 :         if ((code = krb5_cc_resolve(ctx, cache_name ? cache_name : krb5_cc_default_name(ctx), &cc))) {
     154           0 :                 goto out;
     155             :         }
     156             : 
     157       14532 :         if ((code = smb_krb5_parse_name(ctx, given_principal, &me))) {
     158           0 :                 goto out;
     159             :         }
     160             : 
     161       14532 :         if ((code = krb5_get_init_creds_opt_alloc(ctx, &opt))) {
     162           0 :                 goto out;
     163             :         }
     164             : 
     165       14532 :         krb5_get_init_creds_opt_set_renew_life(opt, renewable_time);
     166       14532 :         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       13534 :         krb5_get_init_creds_opt_set_win2k(ctx, opt, true);
     171       13534 :         krb5_get_init_creds_opt_set_canonicalize(ctx, opt, true);
     172             : #else /* MIT */
     173         998 :         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       14532 :         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       14532 :         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       14532 :         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       12111 :                 goto out;
     199             :         }
     200             : 
     201        2421 :         canon_princ = my_creds.client;
     202             : 
     203        2421 :         code = smb_krb5_unparse_name(frame,
     204             :                                      ctx,
     205             :                                      canon_princ,
     206             :                                      &canon_principal);
     207        2421 :         if (code != 0) {
     208           0 :                 goto out;
     209             :         }
     210             : 
     211        2421 :         DBG_DEBUG("%s mapped to %s\n", given_principal, canon_principal);
     212             : 
     213        2421 :         canon_realm = smb_krb5_principal_get_realm(frame, ctx, canon_princ);
     214        2421 :         if (canon_realm == NULL) {
     215           0 :                 code = ENOMEM;
     216           0 :                 goto out;
     217             :         }
     218             : 
     219        2421 :         if ((code = krb5_cc_initialize(ctx, cc, canon_princ))) {
     220           0 :                 goto out;
     221             :         }
     222             : 
     223        2421 :         if ((code = krb5_cc_store_cred(ctx, cc, &my_creds))) {
     224           0 :                 goto out;
     225             :         }
     226             : 
     227        2421 :         if (expire_time) {
     228         354 :                 *expire_time = (time_t) my_creds.times.endtime;
     229             :         }
     230             : 
     231        2421 :         if (renew_till_time) {
     232           0 :                 *renew_till_time = (time_t) my_creds.times.renew_till;
     233             :         }
     234             : 
     235        2421 :         if (_canon_principal != NULL) {
     236        2059 :                 *_canon_principal = talloc_move(mem_ctx, &canon_principal);
     237             :         }
     238        2421 :         if (_canon_realm != NULL) {
     239        2059 :                 *_canon_realm = talloc_move(mem_ctx, &canon_realm);
     240             :         }
     241         362 :  out:
     242       14532 :         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       14532 :  cleanup:
     254       14532 :         krb5_free_cred_contents(ctx, &my_creds);
     255       14532 :         if (me) {
     256       14532 :                 krb5_free_principal(ctx, me);
     257             :         }
     258       14532 :         if (addr) {
     259           0 :                 smb_krb5_free_addresses(ctx, addr);
     260             :         }
     261       14532 :         if (opt) {
     262       14532 :                 krb5_get_init_creds_opt_free(ctx, opt);
     263             :         }
     264       14532 :         if (cc) {
     265       14532 :                 krb5_cc_close(ctx, cc);
     266             :         }
     267       14532 :         if (ctx) {
     268       14532 :                 krb5_free_context(ctx);
     269             :         }
     270       14532 :         TALLOC_FREE(frame);
     271       14532 :         return code;
     272             : }
     273             : 
     274          40 : int ads_kdestroy(const char *cc_name)
     275             : {
     276           0 :         krb5_error_code code;
     277          40 :         krb5_context ctx = NULL;
     278          40 :         krb5_ccache cc = NULL;
     279             : 
     280          40 :         code = smb_krb5_init_context_common(&ctx);
     281          40 :         if (code != 0) {
     282           0 :                 DBG_ERR("kerberos init context failed (%s)\n",
     283             :                         error_message(code));
     284           0 :                 return code;
     285             :         }
     286             : 
     287          40 :         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          40 :                 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          40 :         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          40 :         krb5_free_context (ctx);
     307          40 :         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           0 :         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           8 : int kerberos_kinit_password(const char *principal,
     347             :                             const char *password,
     348             :                             int time_offset,
     349             :                             const char *cache_name)
     350             : {
     351           8 :         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         392 : static void add_sockaddr_unique(struct sockaddr_storage *addrs, size_t *num_addrs,
     378             :                                 const struct sockaddr_storage *addr)
     379             : {
     380           0 :         size_t i;
     381             : 
     382         392 :         for (i=0; i<*num_addrs; i++) {
     383         196 :                 if (sockaddr_equal((const struct sockaddr *)&addrs[i],
     384             :                                    (const struct sockaddr *)addr)) {
     385         196 :                         return;
     386             :                 }
     387             :         }
     388         196 :         addrs[i] = *addr;
     389         196 :         *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         448 : static char *print_canonical_sockaddr_with_port(TALLOC_CTX *mem_ctx,
     398             :                                                 const struct sockaddr_storage *pss)
     399             : {
     400         448 :         char *str = NULL;
     401             : 
     402         448 :         str = print_canonical_sockaddr(mem_ctx, pss);
     403         448 :         if (str == NULL) {
     404           0 :                 return NULL;
     405             :         }
     406             : 
     407         448 :         if (pss->ss_family != AF_INET6) {
     408         260 :                 return str;
     409             :         }
     410             : 
     411             : #if defined(HAVE_IPV6)
     412         188 :         str = talloc_asprintf_append(str, ":88");
     413             : #endif
     414         188 :         return str;
     415             : }
     416             : 
     417         252 : 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         252 :         TALLOC_CTX *frame = talloc_stackframe();
     423           0 :         size_t i;
     424         252 :         struct samba_sockaddr *ip_sa_site = NULL;
     425         252 :         struct samba_sockaddr *ip_sa_nonsite = NULL;
     426         252 :         struct samba_sockaddr sa = {0};
     427         252 :         size_t count_site = 0;
     428           0 :         size_t count_nonsite;
     429           0 :         size_t num_dcs;
     430         252 :         struct sockaddr_storage *dc_addrs = NULL;
     431         252 :         struct tsocket_address **dc_addrs2 = NULL;
     432         252 :         const struct tsocket_address * const *dc_addrs3 = NULL;
     433         252 :         char *result = NULL;
     434         252 :         struct netlogon_samlogon_response **responses = NULL;
     435           0 :         NTSTATUS status;
     436           0 :         bool ok;
     437         252 :         char *kdc_str = NULL;
     438         252 :         char *canon_sockaddr = NULL;
     439             : 
     440         252 :         SMB_ASSERT(pss != NULL);
     441             : 
     442         252 :         canon_sockaddr = print_canonical_sockaddr_with_port(frame, pss);
     443         252 :         if (canon_sockaddr == NULL) {
     444           0 :                 goto out;
     445             :         }
     446             : 
     447         252 :         kdc_str = talloc_asprintf(frame,
     448             :                                   "\t\tkdc = %s\n",
     449             :                                   canon_sockaddr);
     450         252 :         if (kdc_str == NULL) {
     451           0 :                 goto out;
     452             :         }
     453             : 
     454         252 :         ok = sockaddr_storage_to_samba_sockaddr(&sa, pss);
     455         252 :         if (!ok) {
     456           0 :                 goto out;
     457             :         }
     458             : 
     459             :         /*
     460             :          * First get the KDC's only in this site, the rest will be
     461             :          * appended later
     462             :          */
     463             : 
     464         252 :         if (sitename) {
     465         250 :                 status = get_kdc_list(frame,
     466             :                                         realm,
     467             :                                         sitename,
     468             :                                         &ip_sa_site,
     469             :                                         &count_site);
     470         250 :                 if (!NT_STATUS_IS_OK(status)) {
     471           0 :                         DBG_ERR("get_kdc_list fail %s\n",
     472             :                                 nt_errstr(status));
     473           0 :                         goto out;
     474             :                 }
     475         250 :                 DBG_DEBUG("got %zu addresses from site %s search\n",
     476             :                         count_site,
     477             :                         sitename);
     478             :         }
     479             : 
     480             :         /* Get all KDC's. */
     481             : 
     482         252 :         status = get_kdc_list(frame,
     483             :                                         realm,
     484             :                                         NULL,
     485             :                                         &ip_sa_nonsite,
     486             :                                         &count_nonsite);
     487         252 :         if (!NT_STATUS_IS_OK(status)) {
     488           0 :                 DBG_ERR("get_kdc_list (site-less) fail %s\n",
     489             :                         nt_errstr(status));
     490           0 :                 goto out;
     491             :         }
     492         252 :         DBG_DEBUG("got %zu addresses from site-less search\n", count_nonsite);
     493             : 
     494         252 :         if (count_site + count_nonsite < count_site) {
     495             :                 /* Wrap check. */
     496           0 :                 DBG_ERR("get_kdc_list_talloc (site-less) fail wrap error\n");
     497           0 :                 goto out;
     498             :         }
     499             : 
     500             : 
     501         252 :         dc_addrs = talloc_array(talloc_tos(), struct sockaddr_storage,
     502             :                                 count_site + count_nonsite);
     503         252 :         if (dc_addrs == NULL) {
     504           0 :                 goto out;
     505             :         }
     506             : 
     507         252 :         num_dcs = 0;
     508             : 
     509         694 :         for (i = 0; i < count_site; i++) {
     510         442 :                 if (!sockaddr_equal(&sa.u.sa, &ip_sa_site[i].u.sa)) {
     511         196 :                         add_sockaddr_unique(dc_addrs, &num_dcs,
     512         196 :                                             &ip_sa_site[i].u.ss);
     513             :                 }
     514             :         }
     515             : 
     516         696 :         for (i = 0; i < count_nonsite; i++) {
     517         444 :                 if (!sockaddr_equal(&sa.u.sa, &ip_sa_nonsite[i].u.sa)) {
     518         196 :                         add_sockaddr_unique(dc_addrs, &num_dcs,
     519         196 :                                             &ip_sa_nonsite[i].u.ss);
     520             :                 }
     521             :         }
     522             : 
     523         252 :         DBG_DEBUG("%zu additional KDCs to test\n", num_dcs);
     524         252 :         if (num_dcs == 0) {
     525             :                 /*
     526             :                  * We do not have additional KDCs, but we have the one passed
     527             :                  * in via `pss`. So just use that one and leave.
     528             :                  */
     529          56 :                 result = talloc_move(mem_ctx, &kdc_str);
     530          56 :                 goto out;
     531             :         }
     532             : 
     533         196 :         dc_addrs2 = talloc_zero_array(talloc_tos(),
     534             :                                       struct tsocket_address *,
     535             :                                       num_dcs);
     536         196 :         if (dc_addrs2 == NULL) {
     537           0 :                 goto out;
     538             :         }
     539             : 
     540         392 :         for (i=0; i<num_dcs; i++) {
     541           0 :                 char addr[INET6_ADDRSTRLEN];
     542           0 :                 int ret;
     543             : 
     544         196 :                 print_sockaddr(addr, sizeof(addr), &dc_addrs[i]);
     545             : 
     546         196 :                 ret = tsocket_address_inet_from_strings(dc_addrs2, "ip",
     547             :                                                         addr, LDAP_PORT,
     548             :                                                         &dc_addrs2[i]);
     549         196 :                 if (ret != 0) {
     550           0 :                         status = map_nt_error_from_unix(errno);
     551           0 :                         DEBUG(2,("Failed to create tsocket_address for %s - %s\n",
     552             :                                  addr, nt_errstr(status)));
     553           0 :                         goto out;
     554             :                 }
     555             :         }
     556             : 
     557         196 :         dc_addrs3 = (const struct tsocket_address * const *)dc_addrs2;
     558             : 
     559         392 :         status = cldap_multi_netlogon(talloc_tos(),
     560             :                         dc_addrs3, num_dcs,
     561             :                         realm, lp_netbios_name(),
     562             :                         NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX,
     563         196 :                         MIN(num_dcs, 3), timeval_current_ofs(3, 0), &responses);
     564         196 :         TALLOC_FREE(dc_addrs2);
     565         196 :         dc_addrs3 = NULL;
     566             : 
     567         196 :         if (!NT_STATUS_IS_OK(status)) {
     568           0 :                 DEBUG(10,("get_kdc_ip_string: cldap_multi_netlogon failed: "
     569             :                           "%s\n", nt_errstr(status)));
     570           0 :                 goto out;
     571             :         }
     572             : 
     573         392 :         for (i=0; i<num_dcs; i++) {
     574           0 :                 char *new_kdc_str;
     575             : 
     576         196 :                 if (responses[i] == NULL) {
     577           0 :                         continue;
     578             :                 }
     579             : 
     580             :                 /* Append to the string - inefficient but not done often. */
     581         196 :                 new_kdc_str = talloc_asprintf_append(
     582             :                                 kdc_str,
     583             :                                 "\t\tkdc = %s\n",
     584             :                                 print_canonical_sockaddr_with_port(
     585         196 :                                         mem_ctx, &dc_addrs[i]));
     586         196 :                 if (new_kdc_str == NULL) {
     587           0 :                         goto out;
     588             :                 }
     589         196 :                 kdc_str = new_kdc_str;
     590             :         }
     591             : 
     592         196 :         result = talloc_move(mem_ctx, &kdc_str);
     593         252 : out:
     594         252 :         if (result != NULL) {
     595         252 :                 DBG_DEBUG("Returning\n%s\n", result);
     596             :         } else {
     597           0 :                 DBG_NOTICE("Failed to get KDC ip address\n");
     598             :         }
     599             : 
     600         252 :         TALLOC_FREE(frame);
     601         252 :         return result;
     602             : }
     603             : 
     604             : /************************************************************************
     605             :  Create  a specific krb5.conf file in the private directory pointing
     606             :  at a specific kdc for a realm. Keyed off domain name. Sets
     607             :  KRB5_CONFIG environment variable to point to this file. Must be
     608             :  run as root or will fail (which is a good thing :-).
     609             : ************************************************************************/
     610             : 
     611             : #if !defined(SAMBA4_USES_HEIMDAL) /* MIT version */
     612         123 : static char *get_enctypes(TALLOC_CTX *mem_ctx)
     613             : {
     614         123 :         char *aes_enctypes = NULL;
     615         123 :         const char *legacy_enctypes = "";
     616         123 :         char *enctypes = NULL;
     617             : 
     618         123 :         aes_enctypes = talloc_strdup(mem_ctx, "");
     619         123 :         if (aes_enctypes == NULL) {
     620           0 :                 goto done;
     621             :         }
     622             : 
     623         123 :         if (lp_kerberos_encryption_types() == KERBEROS_ETYPES_ALL ||
     624           0 :             lp_kerberos_encryption_types() == KERBEROS_ETYPES_STRONG) {
     625         123 :                 aes_enctypes = talloc_asprintf_append(
     626             :                     aes_enctypes, "%s", "aes256-cts-hmac-sha1-96 ");
     627         123 :                 if (aes_enctypes == NULL) {
     628           0 :                         goto done;
     629             :                 }
     630         123 :                 aes_enctypes = talloc_asprintf_append(
     631             :                     aes_enctypes, "%s", "aes128-cts-hmac-sha1-96");
     632         123 :                 if (aes_enctypes == NULL) {
     633           0 :                         goto done;
     634             :                 }
     635             :         }
     636             : 
     637         245 :         if (lp_weak_crypto() == SAMBA_WEAK_CRYPTO_ALLOWED &&
     638         122 :             (lp_kerberos_encryption_types() == KERBEROS_ETYPES_ALL ||
     639           0 :              lp_kerberos_encryption_types() == KERBEROS_ETYPES_LEGACY)) {
     640         122 :                 legacy_enctypes = "RC4-HMAC";
     641             :         }
     642             : 
     643             :         enctypes =
     644         123 :             talloc_asprintf(mem_ctx, "\tdefault_tgs_enctypes = %s %s\n"
     645             :                                      "\tdefault_tkt_enctypes = %s %s\n"
     646             :                                      "\tpreferred_enctypes = %s %s\n",
     647             :                             aes_enctypes, legacy_enctypes, aes_enctypes,
     648             :                             legacy_enctypes, aes_enctypes, legacy_enctypes);
     649         123 : done:
     650         123 :         TALLOC_FREE(aes_enctypes);
     651         123 :         return enctypes;
     652             : }
     653             : #else /* Heimdal version */
     654         129 : static char *get_enctypes(TALLOC_CTX *mem_ctx)
     655             : {
     656         129 :         const char *aes_enctypes = "";
     657         129 :         const char *legacy_enctypes = "";
     658         129 :         char *enctypes = NULL;
     659             : 
     660         129 :         if (lp_kerberos_encryption_types() == KERBEROS_ETYPES_ALL ||
     661           0 :             lp_kerberos_encryption_types() == KERBEROS_ETYPES_STRONG) {
     662         129 :                 aes_enctypes =
     663             :                     "aes256-cts-hmac-sha1-96 aes128-cts-hmac-sha1-96";
     664             :         }
     665             : 
     666         129 :         if (lp_kerberos_encryption_types() == KERBEROS_ETYPES_ALL ||
     667           0 :             lp_kerberos_encryption_types() == KERBEROS_ETYPES_LEGACY) {
     668         129 :                 legacy_enctypes = "arcfour-hmac-md5";
     669             :         }
     670             : 
     671         129 :         enctypes = talloc_asprintf(mem_ctx, "\tdefault_etypes = %s %s\n",
     672             :                                    aes_enctypes, legacy_enctypes);
     673             : 
     674         129 :         return enctypes;
     675             : }
     676             : #endif
     677             : 
     678         256 : bool create_local_private_krb5_conf_for_domain(const char *realm,
     679             :                                                 const char *domain,
     680             :                                                 const char *sitename,
     681             :                                                 const struct sockaddr_storage *pss)
     682             : {
     683           0 :         char *dname;
     684         256 :         char *tmpname = NULL;
     685         256 :         char *fname = NULL;
     686         256 :         char *file_contents = NULL;
     687         256 :         char *kdc_ip_string = NULL;
     688         256 :         size_t flen = 0;
     689           0 :         ssize_t ret;
     690           0 :         int fd;
     691         256 :         char *realm_upper = NULL;
     692         256 :         bool result = false;
     693         256 :         char *enctypes = NULL;
     694         256 :         const char *include_system_krb5 = "";
     695           0 :         mode_t mask;
     696             : 
     697         256 :         if (!lp_create_krb5_conf()) {
     698           4 :                 return false;
     699             :         }
     700             : 
     701         252 :         if (realm == NULL) {
     702           0 :                 DEBUG(0, ("No realm has been specified! Do you really want to "
     703             :                           "join an Active Directory server?\n"));
     704           0 :                 return false;
     705             :         }
     706             : 
     707         252 :         if (domain == NULL || pss == NULL) {
     708           0 :                 return false;
     709             :         }
     710             : 
     711         252 :         dname = lock_path(talloc_tos(), "smb_krb5");
     712         252 :         if (!dname) {
     713           0 :                 return false;
     714             :         }
     715         252 :         if ((mkdir(dname, 0755)==-1) && (errno != EEXIST)) {
     716           0 :                 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
     717             :                         "failed to create directory %s. Error was %s\n",
     718             :                         dname, strerror(errno) ));
     719           0 :                 goto done;
     720             :         }
     721             : 
     722         252 :         tmpname = lock_path(talloc_tos(), "smb_tmp_krb5.XXXXXX");
     723         252 :         if (!tmpname) {
     724           0 :                 goto done;
     725             :         }
     726             : 
     727         252 :         fname = talloc_asprintf(dname, "%s/krb5.conf.%s", dname, domain);
     728         252 :         if (!fname) {
     729           0 :                 goto done;
     730             :         }
     731             : 
     732         252 :         DEBUG(10,("create_local_private_krb5_conf_for_domain: fname = %s, realm = %s, domain = %s\n",
     733             :                 fname, realm, domain ));
     734             : 
     735         252 :         realm_upper = talloc_strdup(fname, realm);
     736         252 :         if (!strupper_m(realm_upper)) {
     737           0 :                 goto done;
     738             :         }
     739             : 
     740         252 :         kdc_ip_string = get_kdc_ip_string(dname, realm, sitename, pss);
     741         252 :         if (!kdc_ip_string) {
     742           0 :                 goto done;
     743             :         }
     744             : 
     745         252 :         enctypes = get_enctypes(fname);
     746         252 :         if (enctypes == NULL) {
     747           0 :                 goto done;
     748             :         }
     749             : 
     750             : #if !defined(SAMBA4_USES_HEIMDAL)
     751         123 :         if (lp_include_system_krb5_conf()) {
     752           2 :                 include_system_krb5 = "include /etc/krb5.conf";
     753             :         }
     754             : #endif
     755             : 
     756             :         /*
     757             :          * We are setting 'dns_lookup_kdc' to true, because we want to lookup
     758             :          * KDCs which are not configured via DNS SRV records, eg. if we do:
     759             :          *
     760             :          *     net ads join -Uadmin@otherdomain
     761             :          */
     762           0 :         file_contents =
     763         252 :             talloc_asprintf(fname,
     764             :                             "[libdefaults]\n"
     765             :                             "\tdefault_realm = %s\n"
     766             :                             "%s"
     767             :                             "\tdns_lookup_realm = false\n"
     768             :                             "\tdns_lookup_kdc = true\n\n"
     769             :                             "[realms]\n\t%s = {\n"
     770             :                             "%s\t}\n"
     771             :                             "\t%s = {\n"
     772             :                             "%s\t}\n"
     773             :                             "%s\n",
     774             :                             realm_upper,
     775             :                             enctypes,
     776             :                             realm_upper,
     777             :                             kdc_ip_string,
     778             :                             domain,
     779             :                             kdc_ip_string,
     780             :                             include_system_krb5);
     781             : 
     782         252 :         if (!file_contents) {
     783           0 :                 goto done;
     784             :         }
     785             : 
     786         252 :         flen = strlen(file_contents);
     787             : 
     788         252 :         mask = umask(S_IRWXO | S_IRWXG);
     789         252 :         fd = mkstemp(tmpname);
     790         252 :         umask(mask);
     791         252 :         if (fd == -1) {
     792           0 :                 DBG_ERR("mkstemp failed, for file %s. Errno %s\n",
     793             :                         tmpname,
     794             :                         strerror(errno));
     795           0 :                 goto done;
     796             :         }
     797             : 
     798         252 :         if (fchmod(fd, 0644)==-1) {
     799           0 :                 DEBUG(0,("create_local_private_krb5_conf_for_domain: fchmod failed for %s."
     800             :                         " Errno %s\n",
     801             :                         tmpname, strerror(errno) ));
     802           0 :                 unlink(tmpname);
     803           0 :                 close(fd);
     804           0 :                 goto done;
     805             :         }
     806             : 
     807         252 :         ret = write(fd, file_contents, flen);
     808         252 :         if (flen != ret) {
     809           0 :                 DEBUG(0,("create_local_private_krb5_conf_for_domain: write failed,"
     810             :                         " returned %d (should be %u). Errno %s\n",
     811             :                         (int)ret, (unsigned int)flen, strerror(errno) ));
     812           0 :                 unlink(tmpname);
     813           0 :                 close(fd);
     814           0 :                 goto done;
     815             :         }
     816         252 :         if (close(fd)==-1) {
     817           0 :                 DEBUG(0,("create_local_private_krb5_conf_for_domain: close failed."
     818             :                         " Errno %s\n", strerror(errno) ));
     819           0 :                 unlink(tmpname);
     820           0 :                 goto done;
     821             :         }
     822             : 
     823         252 :         if (rename(tmpname, fname) == -1) {
     824           0 :                 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
     825             :                         "of %s to %s failed. Errno %s\n",
     826             :                         tmpname, fname, strerror(errno) ));
     827           0 :                 unlink(tmpname);
     828           0 :                 goto done;
     829             :         }
     830             : 
     831         252 :         DBG_INFO("wrote file %s with realm %s KDC list:\n%s\n",
     832             :                  fname, realm_upper, kdc_ip_string);
     833             : 
     834             :         /* Set the environment variable to this file. */
     835         252 :         setenv("KRB5_CONFIG", fname, 1);
     836             : 
     837         252 :         result = true;
     838             : 
     839             : #if defined(OVERWRITE_SYSTEM_KRB5_CONF)
     840             : 
     841             : #define SYSTEM_KRB5_CONF_PATH "/etc/krb5.conf"
     842             :         /* Insanity, sheer insanity..... */
     843             : 
     844             :         if (strequal(realm, lp_realm())) {
     845             :                 SMB_STRUCT_STAT sbuf;
     846             : 
     847             :                 if (sys_lstat(SYSTEM_KRB5_CONF_PATH, &sbuf, false) == 0) {
     848             :                         if (S_ISLNK(sbuf.st_ex_mode) && sbuf.st_ex_size) {
     849             :                                 int lret;
     850             :                                 size_t alloc_size = sbuf.st_ex_size + 1;
     851             :                                 char *linkpath = talloc_array(talloc_tos(), char,
     852             :                                                 alloc_size);
     853             :                                 if (!linkpath) {
     854             :                                         goto done;
     855             :                                 }
     856             :                                 lret = readlink(SYSTEM_KRB5_CONF_PATH, linkpath,
     857             :                                                 alloc_size - 1);
     858             :                                 if (lret == -1) {
     859             :                                         TALLOC_FREE(linkpath);
     860             :                                         goto done;
     861             :                                 }
     862             :                                 linkpath[lret] = '\0';
     863             : 
     864             :                                 if (strcmp(linkpath, fname) == 0) {
     865             :                                         /* Symlink already exists. */
     866             :                                         TALLOC_FREE(linkpath);
     867             :                                         goto done;
     868             :                                 }
     869             :                                 TALLOC_FREE(linkpath);
     870             :                         }
     871             :                 }
     872             : 
     873             :                 /* Try and replace with a symlink. */
     874             :                 if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
     875             :                         const char *newpath = SYSTEM_KRB5_CONF_PATH ".saved";
     876             :                         if (errno != EEXIST) {
     877             :                                 DEBUG(0,("create_local_private_krb5_conf_for_domain: symlink "
     878             :                                         "of %s to %s failed. Errno %s\n",
     879             :                                         fname, SYSTEM_KRB5_CONF_PATH, strerror(errno) ));
     880             :                                 goto done; /* Not a fatal error. */
     881             :                         }
     882             : 
     883             :                         /* Yes, this is a race condition... too bad. */
     884             :                         if (rename(SYSTEM_KRB5_CONF_PATH, newpath) == -1) {
     885             :                                 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
     886             :                                         "of %s to %s failed. Errno %s\n",
     887             :                                         SYSTEM_KRB5_CONF_PATH, newpath,
     888             :                                         strerror(errno) ));
     889             :                                 goto done; /* Not a fatal error. */
     890             :                         }
     891             : 
     892             :                         if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
     893             :                                 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
     894             :                                         "forced symlink of %s to /etc/krb5.conf failed. Errno %s\n",
     895             :                                         fname, strerror(errno) ));
     896             :                                 goto done; /* Not a fatal error. */
     897             :                         }
     898             :                 }
     899             :         }
     900             : #endif
     901             : 
     902         252 : done:
     903         252 :         TALLOC_FREE(tmpname);
     904         252 :         TALLOC_FREE(dname);
     905             : 
     906         252 :         return result;
     907             : }
     908             : #endif

Generated by: LCOV version 1.14