krb5_wrap: Remove unneeded smb_krb5_get_init_creds_opt_free()
[samba.git] / source3 / libads / kerberos.c
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 "system/filesys.h"
26 #include "smb_krb5.h"
27 #include "../librpc/gen_ndr/ndr_misc.h"
28 #include "libads/kerberos_proto.h"
29 #include "libads/cldap.h"
30 #include "secrets.h"
31 #include "../lib/tsocket/tsocket.h"
32
33 #ifdef HAVE_KRB5
34
35 #define LIBADS_CCACHE_NAME "MEMORY:libads"
36
37 /*
38   we use a prompter to avoid a crash bug in the kerberos libs when 
39   dealing with empty passwords
40   this prompter is just a string copy ...
41 */
42 static krb5_error_code 
43 kerb_prompter(krb5_context ctx, void *data,
44                const char *name,
45                const char *banner,
46                int num_prompts,
47                krb5_prompt prompts[])
48 {
49         if (num_prompts == 0) return 0;
50         if (num_prompts == 2) {
51                 /*
52                  * only heimdal has a prompt type and we need to deal with it here to
53                  * avoid loops.
54                  *
55                  * removing the prompter completely is not an option as at least these
56                  * versions would crash: heimdal-1.0.2 and heimdal-1.1. Later heimdal
57                  * version have looping detection and return with a proper error code.
58                  */
59
60 #if HAVE_KRB5_PROMPT_TYPE /* Heimdal */
61                  if (prompts[0].type == KRB5_PROMPT_TYPE_NEW_PASSWORD &&
62                      prompts[1].type == KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN) {
63                         /*
64                          * We don't want to change passwords here. We're
65                          * called from heimal when the KDC returns
66                          * KRB5KDC_ERR_KEY_EXPIRED, but at this point we don't
67                          * have the chance to ask the user for a new
68                          * password. If we return 0 (i.e. success), we will be
69                          * spinning in the endless for-loop in
70                          * change_password() in
71                          * source4/heimdal/lib/krb5/init_creds_pw.c:526ff
72                          */
73                         return KRB5KDC_ERR_KEY_EXPIRED;
74                 }
75 #elif defined(HAVE_KRB5_GET_PROMPT_TYPES) /* MIT */
76                 krb5_prompt_type *prompt_types = NULL;
77
78                 prompt_types = krb5_get_prompt_types(ctx);
79                 if (prompt_types != NULL) {
80                         if (prompt_types[0] == KRB5_PROMPT_TYPE_NEW_PASSWORD &&
81                             prompt_types[1] == KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN) {
82                                 return KRB5KDC_ERR_KEY_EXP;
83                         }
84                 }
85 #endif
86         }
87
88         memset(prompts[0].reply->data, '\0', prompts[0].reply->length);
89         if (prompts[0].reply->length > 0) {
90                 if (data) {
91                         strncpy((char *)prompts[0].reply->data, (const char *)data,
92                                 prompts[0].reply->length-1);
93                         prompts[0].reply->length = strlen((const char *)prompts[0].reply->data);
94                 } else {
95                         prompts[0].reply->length = 0;
96                 }
97         }
98         return 0;
99 }
100
101  static bool smb_krb5_get_ntstatus_from_krb5_error(krb5_error *error,
102                                                    NTSTATUS *nt_status)
103 {
104         DATA_BLOB edata;
105         DATA_BLOB unwrapped_edata;
106         TALLOC_CTX *mem_ctx;
107         struct KRB5_EDATA_NTSTATUS parsed_edata;
108         enum ndr_err_code ndr_err;
109
110 #ifdef HAVE_E_DATA_POINTER_IN_KRB5_ERROR
111         edata = data_blob(error->e_data->data, error->e_data->length);
112 #else
113         edata = data_blob(error->e_data.data, error->e_data.length);
114 #endif /* HAVE_E_DATA_POINTER_IN_KRB5_ERROR */
115
116 #ifdef DEVELOPER
117         dump_data(10, edata.data, edata.length);
118 #endif /* DEVELOPER */
119
120         mem_ctx = talloc_init("smb_krb5_get_ntstatus_from_krb5_error");
121         if (mem_ctx == NULL) {
122                 data_blob_free(&edata);
123                 return False;
124         }
125
126         if (!unwrap_edata_ntstatus(mem_ctx, &edata, &unwrapped_edata)) {
127                 data_blob_free(&edata);
128                 TALLOC_FREE(mem_ctx);
129                 return False;
130         }
131
132         data_blob_free(&edata);
133
134         ndr_err = ndr_pull_struct_blob_all(&unwrapped_edata, mem_ctx, 
135                 &parsed_edata, (ndr_pull_flags_fn_t)ndr_pull_KRB5_EDATA_NTSTATUS);
136         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
137                 data_blob_free(&unwrapped_edata);
138                 TALLOC_FREE(mem_ctx);
139                 return False;
140         }
141
142         data_blob_free(&unwrapped_edata);
143
144         if (nt_status) {
145                 *nt_status = parsed_edata.ntstatus;
146         }
147
148         TALLOC_FREE(mem_ctx);
149
150         return True;
151 }
152
153  static bool smb_krb5_get_ntstatus_from_krb5_error_init_creds_opt(krb5_context ctx, 
154                                                                   krb5_get_init_creds_opt *opt, 
155                                                                   NTSTATUS *nt_status)
156 {
157         bool ret = False;
158         krb5_error *error = NULL;
159
160 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_GET_ERROR
161         ret = krb5_get_init_creds_opt_get_error(ctx, opt, &error);
162         if (ret) {
163                 DEBUG(1,("krb5_get_init_creds_opt_get_error gave: %s\n", 
164                         error_message(ret)));
165                 return False;
166         }
167 #endif /* HAVE_KRB5_GET_INIT_CREDS_OPT_GET_ERROR */
168
169         if (!error) {
170                 DEBUG(1,("no krb5_error\n"));
171                 return False;
172         }
173
174 #ifdef HAVE_E_DATA_POINTER_IN_KRB5_ERROR
175         if (!error->e_data) {
176 #else
177         if (error->e_data.data == NULL) {
178 #endif /* HAVE_E_DATA_POINTER_IN_KRB5_ERROR */
179                 DEBUG(1,("no edata in krb5_error\n")); 
180                 krb5_free_error(ctx, error);
181                 return False;
182         }
183
184         ret = smb_krb5_get_ntstatus_from_krb5_error(error, nt_status);
185
186         krb5_free_error(ctx, error);
187
188         return ret;
189 }
190
191 /*
192   simulate a kinit, putting the tgt in the given cache location. If cache_name == NULL
193   place in default cache location.
194   remus@snapserver.com
195 */
196 int kerberos_kinit_password_ext(const char *principal,
197                                 const char *password,
198                                 int time_offset,
199                                 time_t *expire_time,
200                                 time_t *renew_till_time,
201                                 const char *cache_name,
202                                 bool request_pac,
203                                 bool add_netbios_addr,
204                                 time_t renewable_time,
205                                 NTSTATUS *ntstatus)
206 {
207         krb5_context ctx = NULL;
208         krb5_error_code code = 0;
209         krb5_ccache cc = NULL;
210         krb5_principal me = NULL;
211         krb5_creds my_creds;
212         krb5_get_init_creds_opt *opt = NULL;
213         smb_krb5_addresses *addr = NULL;
214
215         ZERO_STRUCT(my_creds);
216
217         initialize_krb5_error_table();
218         if ((code = krb5_init_context(&ctx)))
219                 goto out;
220
221         if (time_offset != 0) {
222                 krb5_set_real_time(ctx, time(NULL) + time_offset, 0);
223         }
224
225         DEBUG(10,("kerberos_kinit_password: as %s using [%s] as ccache and config [%s]\n",
226                         principal,
227                         cache_name ? cache_name: krb5_cc_default_name(ctx),
228                         getenv("KRB5_CONFIG")));
229
230         if ((code = krb5_cc_resolve(ctx, cache_name ? cache_name : krb5_cc_default_name(ctx), &cc))) {
231                 goto out;
232         }
233
234         if ((code = smb_krb5_parse_name(ctx, principal, &me))) {
235                 goto out;
236         }
237
238         if ((code = krb5_get_init_creds_opt_alloc(ctx, &opt))) {
239                 goto out;
240         }
241
242         krb5_get_init_creds_opt_set_renew_life(opt, renewable_time);
243         krb5_get_init_creds_opt_set_forwardable(opt, True);
244 #if 0
245         /* insane testing */
246         krb5_get_init_creds_opt_set_tkt_life(opt, 60);
247 #endif
248
249 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PAC_REQUEST
250         if (request_pac) {
251                 if ((code = krb5_get_init_creds_opt_set_pac_request(ctx, opt, (krb5_boolean)request_pac))) {
252                         goto out;
253                 }
254         }
255 #endif
256         if (add_netbios_addr) {
257                 if ((code = smb_krb5_gen_netbios_krb5_address(&addr,
258                                                         lp_netbios_name()))) {
259                         goto out;
260                 }
261                 krb5_get_init_creds_opt_set_address_list(opt, addr->addrs);
262         }
263
264         if ((code = krb5_get_init_creds_password(ctx, &my_creds, me, discard_const_p(char,password), 
265                                                  kerb_prompter, discard_const_p(char, password),
266                                                  0, NULL, opt))) {
267                 goto out;
268         }
269
270         if ((code = krb5_cc_initialize(ctx, cc, me))) {
271                 goto out;
272         }
273
274         if ((code = krb5_cc_store_cred(ctx, cc, &my_creds))) {
275                 goto out;
276         }
277
278         if (expire_time) {
279                 *expire_time = (time_t) my_creds.times.endtime;
280         }
281
282         if (renew_till_time) {
283                 *renew_till_time = (time_t) my_creds.times.renew_till;
284         }
285  out:
286         if (ntstatus) {
287
288                 NTSTATUS status;
289
290                 /* fast path */
291                 if (code == 0) {
292                         *ntstatus = NT_STATUS_OK;
293                         goto cleanup;
294                 }
295
296                 /* try to get ntstatus code out of krb5_error when we have it
297                  * inside the krb5_get_init_creds_opt - gd */
298
299                 if (opt && smb_krb5_get_ntstatus_from_krb5_error_init_creds_opt(ctx, opt, &status)) {
300                         *ntstatus = status;
301                         goto cleanup;
302                 }
303
304                 /* fall back to self-made-mapping */
305                 *ntstatus = krb5_to_nt_status(code);
306         }
307
308  cleanup:
309         krb5_free_cred_contents(ctx, &my_creds);
310         if (me) {
311                 krb5_free_principal(ctx, me);
312         }
313         if (addr) {
314                 smb_krb5_free_addresses(ctx, addr);
315         }
316         if (opt) {
317                 krb5_get_init_creds_opt_free(ctx, opt);
318         }
319         if (cc) {
320                 krb5_cc_close(ctx, cc);
321         }
322         if (ctx) {
323                 krb5_free_context(ctx);
324         }
325         return code;
326 }
327
328 int ads_kdestroy(const char *cc_name)
329 {
330         krb5_error_code code;
331         krb5_context ctx = NULL;
332         krb5_ccache cc = NULL;
333
334         initialize_krb5_error_table();
335         if ((code = krb5_init_context (&ctx))) {
336                 DEBUG(3, ("ads_kdestroy: kdb5_init_context failed: %s\n", 
337                         error_message(code)));
338                 return code;
339         }
340
341         if (!cc_name) {
342                 if ((code = krb5_cc_default(ctx, &cc))) {
343                         krb5_free_context(ctx);
344                         return code;
345                 }
346         } else {
347                 if ((code = krb5_cc_resolve(ctx, cc_name, &cc))) {
348                         DEBUG(3, ("ads_kdestroy: krb5_cc_resolve failed: %s\n",
349                                   error_message(code)));
350                         krb5_free_context(ctx);
351                         return code;
352                 }
353         }
354
355         if ((code = krb5_cc_destroy (ctx, cc))) {
356                 DEBUG(3, ("ads_kdestroy: krb5_cc_destroy failed: %s\n", 
357                         error_message(code)));
358         }
359
360         krb5_free_context (ctx);
361         return code;
362 }
363
364 /************************************************************************
365  Routine to fetch the salting principal for a service.  Active
366  Directory may use a non-obvious principal name to generate the salt
367  when it determines the key to use for encrypting tickets for a service,
368  and hopefully we detected that when we joined the domain.
369  ************************************************************************/
370
371 static char *kerberos_secrets_fetch_salting_principal(const char *service, int enctype)
372 {
373         char *key = NULL;
374         char *ret = NULL;
375
376         if (asprintf(&key, "%s/%s/enctype=%d",
377                      SECRETS_SALTING_PRINCIPAL, service, enctype) == -1) {
378                 return NULL;
379         }
380         ret = (char *)secrets_fetch(key, NULL);
381         SAFE_FREE(key);
382         return ret;
383 }
384
385 /************************************************************************
386  Return the standard DES salt key
387 ************************************************************************/
388
389 char* kerberos_standard_des_salt( void )
390 {
391         fstring salt;
392
393         fstr_sprintf( salt, "host/%s.%s@", lp_netbios_name(), lp_realm() );
394         (void)strlower_m( salt );
395         fstrcat( salt, lp_realm() );
396
397         return SMB_STRDUP( salt );
398 }
399
400 /************************************************************************
401 ************************************************************************/
402
403 static char* des_salt_key( void )
404 {
405         char *key;
406
407         if (asprintf(&key, "%s/DES/%s", SECRETS_SALTING_PRINCIPAL,
408                      lp_realm()) == -1) {
409                 return NULL;
410         }
411
412         return key;
413 }
414
415 /************************************************************************
416 ************************************************************************/
417
418 bool kerberos_secrets_store_des_salt( const char* salt )
419 {
420         char* key;
421         bool ret;
422
423         if ( (key = des_salt_key()) == NULL ) {
424                 DEBUG(0,("kerberos_secrets_store_des_salt: failed to generate key!\n"));
425                 return False;
426         }
427
428         if ( !salt ) {
429                 DEBUG(8,("kerberos_secrets_store_des_salt: deleting salt\n"));
430                 secrets_delete( key );
431                 return True;
432         }
433
434         DEBUG(3,("kerberos_secrets_store_des_salt: Storing salt \"%s\"\n", salt));
435
436         ret = secrets_store( key, salt, strlen(salt)+1 );
437
438         SAFE_FREE( key );
439
440         return ret;
441 }
442
443 /************************************************************************
444 ************************************************************************/
445
446 static
447 char* kerberos_secrets_fetch_des_salt( void )
448 {
449         char *salt, *key;
450
451         if ( (key = des_salt_key()) == NULL ) {
452                 DEBUG(0,("kerberos_secrets_fetch_des_salt: failed to generate key!\n"));
453                 return NULL;
454         }
455
456         salt = (char*)secrets_fetch( key, NULL );
457
458         SAFE_FREE( key );
459
460         return salt;
461 }
462
463 /************************************************************************
464  Routine to get the salting principal for this service.  This is 
465  maintained for backwards compatibilty with releases prior to 3.0.24.
466  Since we store the salting principal string only at join, we may have 
467  to look for the older tdb keys.  Caller must free if return is not null.
468  ************************************************************************/
469
470 char *kerberos_fetch_salt_princ_for_host_princ(krb5_context context,
471                                                const char *host_princ_s,
472                                                int enctype)
473 {
474         char *salt_princ_s;
475         /* lookup new key first */
476
477         salt_princ_s = kerberos_secrets_fetch_des_salt();
478         if (salt_princ_s == NULL) {
479
480                 /* look under the old key.  If this fails, just use the standard key */
481                 salt_princ_s = kerberos_secrets_fetch_salting_principal(host_princ_s,
482                                                                         enctype);
483                 if (salt_princ_s == NULL) {
484                         /* fall back to host/machine.realm@REALM */
485                         salt_princ_s = kerberos_standard_des_salt();
486                 }
487         }
488
489         return salt_princ_s;
490 }
491
492 int create_kerberos_key_from_string(krb5_context context,
493                                         krb5_principal host_princ,
494                                         krb5_principal salt_princ,
495                                         krb5_data *password,
496                                         krb5_keyblock *key,
497                                         krb5_enctype enctype,
498                                         bool no_salt)
499 {
500         int ret;
501         /*
502          * Check if we've determined that the KDC is salting keys for this
503          * principal/enctype in a non-obvious way.  If it is, try to match
504          * its behavior.
505          */
506         if (no_salt) {
507                 KRB5_KEY_DATA(key) = (KRB5_KEY_DATA_CAST *)SMB_MALLOC(password->length);
508                 if (!KRB5_KEY_DATA(key)) {
509                         return ENOMEM;
510                 }
511                 memcpy(KRB5_KEY_DATA(key), password->data, password->length);
512                 KRB5_KEY_LENGTH(key) = password->length;
513                 KRB5_KEY_TYPE(key) = enctype;
514                 return 0;
515         }
516         ret = smb_krb5_create_key_from_string(context,
517                                               salt_princ ? salt_princ : host_princ,
518                                               NULL,
519                                               password,
520                                               enctype,
521                                               key);
522         return ret;
523 }
524
525 /************************************************************************
526  Routine to set the salting principal for this service.  Active
527  Directory may use a non-obvious principal name to generate the salt
528  when it determines the key to use for encrypting tickets for a service,
529  and hopefully we detected that when we joined the domain.
530  Setting principal to NULL deletes this entry.
531  ************************************************************************/
532
533 bool kerberos_secrets_store_salting_principal(const char *service,
534                                               int enctype,
535                                               const char *principal)
536 {
537         char *key = NULL;
538         bool ret = False;
539         krb5_context context = NULL;
540         krb5_principal princ = NULL;
541         char *princ_s = NULL;
542         char *unparsed_name = NULL;
543         krb5_error_code code;
544
545         if (((code = krb5_init_context(&context)) != 0) || (context == NULL)) {
546                 DEBUG(5, ("kerberos_secrets_store_salting_pricipal: kdb5_init_context failed: %s\n",
547                           error_message(code)));
548                 return False;
549         }
550         if (strchr_m(service, '@')) {
551                 if (asprintf(&princ_s, "%s", service) == -1) {
552                         goto out;
553                 }
554         } else {
555                 if (asprintf(&princ_s, "%s@%s", service, lp_realm()) == -1) {
556                         goto out;
557                 }
558         }
559
560         if (smb_krb5_parse_name(context, princ_s, &princ) != 0) {
561                 goto out;
562         }
563         if (smb_krb5_unparse_name(talloc_tos(), context, princ, &unparsed_name) != 0) {
564                 goto out;
565         }
566
567         if (asprintf(&key, "%s/%s/enctype=%d",
568                      SECRETS_SALTING_PRINCIPAL, unparsed_name, enctype)
569             == -1) {
570                 goto out;
571         }
572
573         if ((principal != NULL) && (strlen(principal) > 0)) {
574                 ret = secrets_store(key, principal, strlen(principal) + 1);
575         } else {
576                 ret = secrets_delete(key);
577         }
578
579  out:
580
581         SAFE_FREE(key);
582         SAFE_FREE(princ_s);
583         TALLOC_FREE(unparsed_name);
584
585         if (princ) {
586                 krb5_free_principal(context, princ);
587         }
588
589         if (context) {
590                 krb5_free_context(context);
591         }
592
593         return ret;
594 }
595
596
597 /************************************************************************
598 ************************************************************************/
599
600 int kerberos_kinit_password(const char *principal,
601                             const char *password,
602                             int time_offset,
603                             const char *cache_name)
604 {
605         return kerberos_kinit_password_ext(principal, 
606                                            password, 
607                                            time_offset, 
608                                            0, 
609                                            0,
610                                            cache_name,
611                                            False,
612                                            False,
613                                            0,
614                                            NULL);
615 }
616
617 /************************************************************************
618 ************************************************************************/
619
620 /************************************************************************
621  Create a string list of available kdc's, possibly searching by sitename.
622  Does DNS queries.
623
624  If "sitename" is given, the DC's in that site are listed first.
625
626 ************************************************************************/
627
628 static void add_sockaddr_unique(struct sockaddr_storage *addrs, int *num_addrs,
629                                 const struct sockaddr_storage *addr)
630 {
631         int i;
632
633         for (i=0; i<*num_addrs; i++) {
634                 if (sockaddr_equal((const struct sockaddr *)&addrs[i],
635                                    (const struct sockaddr *)addr)) {
636                         return;
637                 }
638         }
639         addrs[i] = *addr;
640         *num_addrs += 1;
641 }
642
643 /* print_canonical_sockaddr prints an ipv6 addr in the form of
644 * [ipv6.addr]. This string, when put in a generated krb5.conf file is not
645 * always properly dealt with by some older krb5 libraries. Adding the hard-coded
646 * portnumber workarounds the issue. - gd */
647
648 static char *print_canonical_sockaddr_with_port(TALLOC_CTX *mem_ctx,
649                                                 const struct sockaddr_storage *pss)
650 {
651         char *str = NULL;
652
653         str = print_canonical_sockaddr(mem_ctx, pss);
654         if (str == NULL) {
655                 return NULL;
656         }
657
658         if (pss->ss_family != AF_INET6) {
659                 return str;
660         }
661
662 #if defined(HAVE_IPV6)
663         str = talloc_asprintf_append(str, ":88");
664 #endif
665         return str;
666 }
667
668 static char *get_kdc_ip_string(char *mem_ctx,
669                 const char *realm,
670                 const char *sitename,
671                 const struct sockaddr_storage *pss)
672 {
673         TALLOC_CTX *frame = talloc_stackframe();
674         int i;
675         struct ip_service *ip_srv_site = NULL;
676         struct ip_service *ip_srv_nonsite = NULL;
677         int count_site = 0;
678         int count_nonsite;
679         int num_dcs;
680         struct sockaddr_storage *dc_addrs;
681         struct tsocket_address **dc_addrs2 = NULL;
682         const struct tsocket_address * const *dc_addrs3 = NULL;
683         char *result = NULL;
684         struct netlogon_samlogon_response **responses = NULL;
685         NTSTATUS status;
686         char *kdc_str = talloc_asprintf(mem_ctx, "%s\t\tkdc = %s\n", "",
687                                         print_canonical_sockaddr_with_port(mem_ctx, pss));
688
689         if (kdc_str == NULL) {
690                 TALLOC_FREE(frame);
691                 return NULL;
692         }
693
694         /*
695          * First get the KDC's only in this site, the rest will be
696          * appended later
697          */
698
699         if (sitename) {
700                 get_kdc_list(realm, sitename, &ip_srv_site, &count_site);
701                 DEBUG(10, ("got %d addresses from site %s search\n", count_site,
702                            sitename));
703         }
704
705         /* Get all KDC's. */
706
707         get_kdc_list(realm, NULL, &ip_srv_nonsite, &count_nonsite);
708         DEBUG(10, ("got %d addresses from site-less search\n", count_nonsite));
709
710         dc_addrs = talloc_array(talloc_tos(), struct sockaddr_storage,
711                                 count_site + count_nonsite);
712         if (dc_addrs == NULL) {
713                 goto out;
714         }
715
716         num_dcs = 0;
717
718         for (i = 0; i < count_site; i++) {
719                 if (!sockaddr_equal(
720                         (const struct sockaddr *)pss,
721                         (const struct sockaddr *)&ip_srv_site[i].ss)) {
722                         add_sockaddr_unique(dc_addrs, &num_dcs,
723                                             &ip_srv_site[i].ss);
724                 }
725         }
726
727         for (i = 0; i < count_nonsite; i++) {
728                 if (!sockaddr_equal(
729                         (const struct sockaddr *)pss,
730                         (const struct sockaddr *)&ip_srv_nonsite[i].ss)) {
731                         add_sockaddr_unique(dc_addrs, &num_dcs,
732                                             &ip_srv_nonsite[i].ss);
733                 }
734         }
735
736         dc_addrs2 = talloc_zero_array(talloc_tos(),
737                                       struct tsocket_address *,
738                                       num_dcs);
739
740         DEBUG(10, ("%d additional KDCs to test\n", num_dcs));
741         if (num_dcs == 0) {
742                 goto out;
743         }
744         if (dc_addrs2 == NULL) {
745                 goto out;
746         }
747
748         for (i=0; i<num_dcs; i++) {
749                 char addr[INET6_ADDRSTRLEN];
750                 int ret;
751
752                 print_sockaddr(addr, sizeof(addr), &dc_addrs[i]);
753
754                 ret = tsocket_address_inet_from_strings(dc_addrs2, "ip",
755                                                         addr, LDAP_PORT,
756                                                         &dc_addrs2[i]);
757                 if (ret != 0) {
758                         status = map_nt_error_from_unix(errno);
759                         DEBUG(2,("Failed to create tsocket_address for %s - %s\n",
760                                  addr, nt_errstr(status)));
761                         goto out;
762                 }
763         }
764
765         dc_addrs3 = (const struct tsocket_address * const *)dc_addrs2;
766
767         status = cldap_multi_netlogon(talloc_tos(),
768                         dc_addrs3, num_dcs,
769                         realm, lp_netbios_name(),
770                         NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX,
771                         MIN(num_dcs, 3), timeval_current_ofs(3, 0), &responses);
772         TALLOC_FREE(dc_addrs2);
773         dc_addrs3 = NULL;
774
775         if (!NT_STATUS_IS_OK(status)) {
776                 DEBUG(10,("get_kdc_ip_string: cldap_multi_netlogon failed: "
777                           "%s\n", nt_errstr(status)));
778                 goto out;
779         }
780
781         for (i=0; i<num_dcs; i++) {
782                 char *new_kdc_str;
783
784                 if (responses[i] == NULL) {
785                         continue;
786                 }
787
788                 /* Append to the string - inefficient but not done often. */
789                 new_kdc_str = talloc_asprintf(mem_ctx, "%s\t\tkdc = %s\n",
790                                               kdc_str,
791                                               print_canonical_sockaddr_with_port(mem_ctx, &dc_addrs[i]));
792                 if (new_kdc_str == NULL) {
793                         goto out;
794                 }
795                 TALLOC_FREE(kdc_str);
796                 kdc_str = new_kdc_str;
797         }
798
799 out:
800         DEBUG(10, ("get_kdc_ip_string: Returning %s\n", kdc_str));
801
802         result = kdc_str;
803         SAFE_FREE(ip_srv_site);
804         SAFE_FREE(ip_srv_nonsite);
805         TALLOC_FREE(frame);
806         return result;
807 }
808
809 /************************************************************************
810  Create  a specific krb5.conf file in the private directory pointing
811  at a specific kdc for a realm. Keyed off domain name. Sets
812  KRB5_CONFIG environment variable to point to this file. Must be
813  run as root or will fail (which is a good thing :-).
814 ************************************************************************/
815
816 #if !defined(SAMBA4_USES_HEIMDAL) /* MIT version */
817 static char *get_enctypes(TALLOC_CTX *mem_ctx)
818 {
819         char *aes_enctypes = NULL;
820         const char *legacy_enctypes = "";
821         char *enctypes = NULL;
822
823         aes_enctypes = talloc_strdup(mem_ctx, "");
824         if (aes_enctypes == NULL) {
825                 goto done;
826         }
827
828         if (lp_kerberos_encryption_types() == KERBEROS_ETYPES_ALL ||
829             lp_kerberos_encryption_types() == KERBEROS_ETYPES_STRONG) {
830 #ifdef HAVE_ENCTYPE_AES256_CTS_HMAC_SHA1_96
831                 aes_enctypes = talloc_asprintf_append(
832                     aes_enctypes, "%s", "aes256-cts-hmac-sha1-96 ");
833                 if (aes_enctypes == NULL) {
834                         goto done;
835                 }
836 #endif
837 #ifdef HAVE_ENCTYPE_AES128_CTS_HMAC_SHA1_96
838                 aes_enctypes = talloc_asprintf_append(
839                     aes_enctypes, "%s", "aes128-cts-hmac-sha1-96");
840                 if (aes_enctypes == NULL) {
841                         goto done;
842                 }
843 #endif
844         }
845
846         if (lp_kerberos_encryption_types() == KERBEROS_ETYPES_ALL ||
847             lp_kerberos_encryption_types() == KERBEROS_ETYPES_LEGACY) {
848                 legacy_enctypes = "RC4-HMAC DES-CBC-CRC DES-CBC-MD5";
849         }
850
851         enctypes =
852             talloc_asprintf(mem_ctx, "\tdefault_tgs_enctypes = %s %s\n"
853                                      "\tdefault_tkt_enctypes = %s %s\n"
854                                      "\tpreferred_enctypes = %s %s\n",
855                             aes_enctypes, legacy_enctypes, aes_enctypes,
856                             legacy_enctypes, aes_enctypes, legacy_enctypes);
857 done:
858         TALLOC_FREE(aes_enctypes);
859         return enctypes;
860 }
861 #else /* Heimdal version */
862 static char *get_enctypes(TALLOC_CTX *mem_ctx)
863 {
864         const char *aes_enctypes = "";
865         const char *legacy_enctypes = "";
866         char *enctypes = NULL;
867
868         if (lp_kerberos_encryption_types() == KERBEROS_ETYPES_ALL ||
869             lp_kerberos_encryption_types() == KERBEROS_ETYPES_STRONG) {
870                 aes_enctypes =
871                     "aes256-cts-hmac-sha1-96 aes128-cts-hmac-sha1-96";
872         }
873
874         if (lp_kerberos_encryption_types() == KERBEROS_ETYPES_ALL ||
875             lp_kerberos_encryption_types() == KERBEROS_ETYPES_LEGACY) {
876                 legacy_enctypes = "arcfour-hmac-md5 des-cbc-crc des-cbc-md5";
877         }
878
879         enctypes = talloc_asprintf(mem_ctx, "\tdefault_etypes = %s %s\n",
880                                    aes_enctypes, legacy_enctypes);
881
882         return enctypes;
883 }
884 #endif
885
886 bool create_local_private_krb5_conf_for_domain(const char *realm,
887                                                 const char *domain,
888                                                 const char *sitename,
889                                                 const struct sockaddr_storage *pss)
890 {
891         char *dname;
892         char *tmpname = NULL;
893         char *fname = NULL;
894         char *file_contents = NULL;
895         char *kdc_ip_string = NULL;
896         size_t flen = 0;
897         ssize_t ret;
898         int fd;
899         char *realm_upper = NULL;
900         bool result = false;
901         char *enctypes = NULL;
902         mode_t mask;
903
904         if (!lp_create_krb5_conf()) {
905                 return false;
906         }
907
908         if (realm == NULL) {
909                 DEBUG(0, ("No realm has been specified! Do you really want to "
910                           "join an Active Directory server?\n"));
911                 return false;
912         }
913
914         if (domain == NULL || pss == NULL) {
915                 return false;
916         }
917
918         dname = lock_path("smb_krb5");
919         if (!dname) {
920                 return false;
921         }
922         if ((mkdir(dname, 0755)==-1) && (errno != EEXIST)) {
923                 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
924                         "failed to create directory %s. Error was %s\n",
925                         dname, strerror(errno) ));
926                 goto done;
927         }
928
929         tmpname = lock_path("smb_tmp_krb5.XXXXXX");
930         if (!tmpname) {
931                 goto done;
932         }
933
934         fname = talloc_asprintf(dname, "%s/krb5.conf.%s", dname, domain);
935         if (!fname) {
936                 goto done;
937         }
938
939         DEBUG(10,("create_local_private_krb5_conf_for_domain: fname = %s, realm = %s, domain = %s\n",
940                 fname, realm, domain ));
941
942         realm_upper = talloc_strdup(fname, realm);
943         if (!strupper_m(realm_upper)) {
944                 goto done;
945         }
946
947         kdc_ip_string = get_kdc_ip_string(dname, realm, sitename, pss);
948         if (!kdc_ip_string) {
949                 goto done;
950         }
951
952         enctypes = get_enctypes(fname);
953         if (enctypes == NULL) {
954                 goto done;
955         }
956
957         file_contents =
958             talloc_asprintf(fname, "[libdefaults]\n\tdefault_realm = %s\n"
959                                    "%s"
960                                    "\tdns_lookup_realm = false\n\n"
961                                    "[realms]\n\t%s = {\n"
962                                    "%s\t}\n",
963                             realm_upper, enctypes, realm_upper, kdc_ip_string);
964
965         if (!file_contents) {
966                 goto done;
967         }
968
969         flen = strlen(file_contents);
970
971         mask = umask(S_IRWXO | S_IRWXG);
972         fd = mkstemp(tmpname);
973         umask(mask);
974         if (fd == -1) {
975                 DEBUG(0,("create_local_private_krb5_conf_for_domain: smb_mkstemp failed,"
976                         " for file %s. Errno %s\n",
977                         tmpname, strerror(errno) ));
978                 goto done;
979         }
980
981         if (fchmod(fd, 0644)==-1) {
982                 DEBUG(0,("create_local_private_krb5_conf_for_domain: fchmod failed for %s."
983                         " Errno %s\n",
984                         tmpname, strerror(errno) ));
985                 unlink(tmpname);
986                 close(fd);
987                 goto done;
988         }
989
990         ret = write(fd, file_contents, flen);
991         if (flen != ret) {
992                 DEBUG(0,("create_local_private_krb5_conf_for_domain: write failed,"
993                         " returned %d (should be %u). Errno %s\n",
994                         (int)ret, (unsigned int)flen, strerror(errno) ));
995                 unlink(tmpname);
996                 close(fd);
997                 goto done;
998         }
999         if (close(fd)==-1) {
1000                 DEBUG(0,("create_local_private_krb5_conf_for_domain: close failed."
1001                         " Errno %s\n", strerror(errno) ));
1002                 unlink(tmpname);
1003                 goto done;
1004         }
1005
1006         if (rename(tmpname, fname) == -1) {
1007                 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
1008                         "of %s to %s failed. Errno %s\n",
1009                         tmpname, fname, strerror(errno) ));
1010                 unlink(tmpname);
1011                 goto done;
1012         }
1013
1014         DEBUG(5,("create_local_private_krb5_conf_for_domain: wrote "
1015                 "file %s with realm %s KDC list = %s\n",
1016                 fname, realm_upper, kdc_ip_string));
1017
1018         /* Set the environment variable to this file. */
1019         setenv("KRB5_CONFIG", fname, 1);
1020
1021         result = true;
1022
1023 #if defined(OVERWRITE_SYSTEM_KRB5_CONF)
1024
1025 #define SYSTEM_KRB5_CONF_PATH "/etc/krb5.conf"
1026         /* Insanity, sheer insanity..... */
1027
1028         if (strequal(realm, lp_realm())) {
1029                 SMB_STRUCT_STAT sbuf;
1030
1031                 if (sys_lstat(SYSTEM_KRB5_CONF_PATH, &sbuf, false) == 0) {
1032                         if (S_ISLNK(sbuf.st_ex_mode) && sbuf.st_ex_size) {
1033                                 int lret;
1034                                 size_t alloc_size = sbuf.st_ex_size + 1;
1035                                 char *linkpath = talloc_array(talloc_tos(), char,
1036                                                 alloc_size);
1037                                 if (!linkpath) {
1038                                         goto done;
1039                                 }
1040                                 lret = readlink(SYSTEM_KRB5_CONF_PATH, linkpath,
1041                                                 alloc_size - 1);
1042                                 if (lret == -1) {
1043                                         TALLOC_FREE(linkpath);
1044                                         goto done;
1045                                 }
1046                                 linkpath[lret] = '\0';
1047
1048                                 if (strcmp(linkpath, fname) == 0) {
1049                                         /* Symlink already exists. */
1050                                         TALLOC_FREE(linkpath);
1051                                         goto done;
1052                                 }
1053                                 TALLOC_FREE(linkpath);
1054                         }
1055                 }
1056
1057                 /* Try and replace with a symlink. */
1058                 if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
1059                         const char *newpath = SYSTEM_KRB5_CONF_PATH ".saved";
1060                         if (errno != EEXIST) {
1061                                 DEBUG(0,("create_local_private_krb5_conf_for_domain: symlink "
1062                                         "of %s to %s failed. Errno %s\n",
1063                                         fname, SYSTEM_KRB5_CONF_PATH, strerror(errno) ));
1064                                 goto done; /* Not a fatal error. */
1065                         }
1066
1067                         /* Yes, this is a race conditon... too bad. */
1068                         if (rename(SYSTEM_KRB5_CONF_PATH, newpath) == -1) {
1069                                 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
1070                                         "of %s to %s failed. Errno %s\n",
1071                                         SYSTEM_KRB5_CONF_PATH, newpath,
1072                                         strerror(errno) ));
1073                                 goto done; /* Not a fatal error. */
1074                         }
1075
1076                         if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
1077                                 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
1078                                         "forced symlink of %s to /etc/krb5.conf failed. Errno %s\n",
1079                                         fname, strerror(errno) ));
1080                                 goto done; /* Not a fatal error. */
1081                         }
1082                 }
1083         }
1084 #endif
1085
1086 done:
1087         TALLOC_FREE(tmpname);
1088         TALLOC_FREE(dname);
1089
1090         return result;
1091 }
1092 #endif