s3-kerberos: avoid entering a password change dialogue also when using MIT.
[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 = smb_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                 smb_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 static
471 krb5_principal kerberos_fetch_salt_princ_for_host_princ(krb5_context context,
472                                                         krb5_principal host_princ,
473                                                         int enctype)
474 {
475         char *unparsed_name = NULL, *salt_princ_s = NULL;
476         krb5_principal ret_princ = NULL;
477
478         /* lookup new key first */
479
480         if ( (salt_princ_s = kerberos_secrets_fetch_des_salt()) == NULL ) {
481
482                 /* look under the old key.  If this fails, just use the standard key */
483
484                 if (smb_krb5_unparse_name(talloc_tos(), context, host_princ, &unparsed_name) != 0) {
485                         return (krb5_principal)NULL;
486                 }
487                 if ((salt_princ_s = kerberos_secrets_fetch_salting_principal(unparsed_name, enctype)) == NULL) {
488                         /* fall back to host/machine.realm@REALM */
489                         salt_princ_s = kerberos_standard_des_salt();
490                 }
491         }
492
493         if (smb_krb5_parse_name(context, salt_princ_s, &ret_princ) != 0) {
494                 ret_princ = NULL;
495         }
496
497         TALLOC_FREE(unparsed_name);
498         SAFE_FREE(salt_princ_s);
499
500         return ret_princ;
501 }
502
503 int create_kerberos_key_from_string(krb5_context context,
504                                         krb5_principal host_princ,
505                                         krb5_data *password,
506                                         krb5_keyblock *key,
507                                         krb5_enctype enctype,
508                                         bool no_salt)
509 {
510         krb5_principal salt_princ = NULL;
511         int ret;
512         /*
513          * Check if we've determined that the KDC is salting keys for this
514          * principal/enctype in a non-obvious way.  If it is, try to match
515          * its behavior.
516          */
517         if (no_salt) {
518                 KRB5_KEY_DATA(key) = (KRB5_KEY_DATA_CAST *)SMB_MALLOC(password->length);
519                 if (!KRB5_KEY_DATA(key)) {
520                         return ENOMEM;
521                 }
522                 memcpy(KRB5_KEY_DATA(key), password->data, password->length);
523                 KRB5_KEY_LENGTH(key) = password->length;
524                 KRB5_KEY_TYPE(key) = enctype;
525                 return 0;
526         }
527         salt_princ = kerberos_fetch_salt_princ_for_host_princ(context, host_princ, enctype);
528         ret = smb_krb5_create_key_from_string(context,
529                                               salt_princ ? salt_princ : host_princ,
530                                               NULL,
531                                               password,
532                                               enctype,
533                                               key);
534         if (salt_princ) {
535                 krb5_free_principal(context, salt_princ);
536         }
537         return ret;
538 }
539
540 /************************************************************************
541  Routine to set the salting principal for this service.  Active
542  Directory may use a non-obvious principal name to generate the salt
543  when it determines the key to use for encrypting tickets for a service,
544  and hopefully we detected that when we joined the domain.
545  Setting principal to NULL deletes this entry.
546  ************************************************************************/
547
548 bool kerberos_secrets_store_salting_principal(const char *service,
549                                               int enctype,
550                                               const char *principal)
551 {
552         char *key = NULL;
553         bool ret = False;
554         krb5_context context = NULL;
555         krb5_principal princ = NULL;
556         char *princ_s = NULL;
557         char *unparsed_name = NULL;
558         krb5_error_code code;
559
560         if (((code = krb5_init_context(&context)) != 0) || (context == NULL)) {
561                 DEBUG(5, ("kerberos_secrets_store_salting_pricipal: kdb5_init_context failed: %s\n",
562                           error_message(code)));
563                 return False;
564         }
565         if (strchr_m(service, '@')) {
566                 if (asprintf(&princ_s, "%s", service) == -1) {
567                         goto out;
568                 }
569         } else {
570                 if (asprintf(&princ_s, "%s@%s", service, lp_realm()) == -1) {
571                         goto out;
572                 }
573         }
574
575         if (smb_krb5_parse_name(context, princ_s, &princ) != 0) {
576                 goto out;
577         }
578         if (smb_krb5_unparse_name(talloc_tos(), context, princ, &unparsed_name) != 0) {
579                 goto out;
580         }
581
582         if (asprintf(&key, "%s/%s/enctype=%d",
583                      SECRETS_SALTING_PRINCIPAL, unparsed_name, enctype)
584             == -1) {
585                 goto out;
586         }
587
588         if ((principal != NULL) && (strlen(principal) > 0)) {
589                 ret = secrets_store(key, principal, strlen(principal) + 1);
590         } else {
591                 ret = secrets_delete(key);
592         }
593
594  out:
595
596         SAFE_FREE(key);
597         SAFE_FREE(princ_s);
598         TALLOC_FREE(unparsed_name);
599
600         if (princ) {
601                 krb5_free_principal(context, princ);
602         }
603
604         if (context) {
605                 krb5_free_context(context);
606         }
607
608         return ret;
609 }
610
611
612 /************************************************************************
613 ************************************************************************/
614
615 int kerberos_kinit_password(const char *principal,
616                             const char *password,
617                             int time_offset,
618                             const char *cache_name)
619 {
620         return kerberos_kinit_password_ext(principal, 
621                                            password, 
622                                            time_offset, 
623                                            0, 
624                                            0,
625                                            cache_name,
626                                            False,
627                                            False,
628                                            0,
629                                            NULL);
630 }
631
632 /************************************************************************
633 ************************************************************************/
634
635 /************************************************************************
636  Create a string list of available kdc's, possibly searching by sitename.
637  Does DNS queries.
638
639  If "sitename" is given, the DC's in that site are listed first.
640
641 ************************************************************************/
642
643 static void add_sockaddr_unique(struct sockaddr_storage *addrs, int *num_addrs,
644                                 const struct sockaddr_storage *addr)
645 {
646         int i;
647
648         for (i=0; i<*num_addrs; i++) {
649                 if (sockaddr_equal((const struct sockaddr *)&addrs[i],
650                                    (const struct sockaddr *)addr)) {
651                         return;
652                 }
653         }
654         addrs[i] = *addr;
655         *num_addrs += 1;
656 }
657
658 /* print_canonical_sockaddr prints an ipv6 addr in the form of
659 * [ipv6.addr]. This string, when put in a generated krb5.conf file is not
660 * always properly dealt with by some older krb5 libraries. Adding the hard-coded
661 * portnumber workarounds the issue. - gd */
662
663 static char *print_canonical_sockaddr_with_port(TALLOC_CTX *mem_ctx,
664                                                 const struct sockaddr_storage *pss)
665 {
666         char *str = NULL;
667
668         str = print_canonical_sockaddr(mem_ctx, pss);
669         if (str == NULL) {
670                 return NULL;
671         }
672
673         if (pss->ss_family != AF_INET6) {
674                 return str;
675         }
676
677 #if defined(HAVE_IPV6)
678         str = talloc_asprintf_append(str, ":88");
679 #endif
680         return str;
681 }
682
683 static char *get_kdc_ip_string(char *mem_ctx,
684                 const char *realm,
685                 const char *sitename,
686                 const struct sockaddr_storage *pss)
687 {
688         TALLOC_CTX *frame = talloc_stackframe();
689         int i;
690         struct ip_service *ip_srv_site = NULL;
691         struct ip_service *ip_srv_nonsite = NULL;
692         int count_site = 0;
693         int count_nonsite;
694         int num_dcs;
695         struct sockaddr_storage *dc_addrs;
696         struct tsocket_address **dc_addrs2 = NULL;
697         const struct tsocket_address * const *dc_addrs3 = NULL;
698         char *result = NULL;
699         struct netlogon_samlogon_response **responses = NULL;
700         NTSTATUS status;
701         char *kdc_str = talloc_asprintf(mem_ctx, "%s\t\tkdc = %s\n", "",
702                                         print_canonical_sockaddr_with_port(mem_ctx, pss));
703
704         if (kdc_str == NULL) {
705                 TALLOC_FREE(frame);
706                 return NULL;
707         }
708
709         /*
710          * First get the KDC's only in this site, the rest will be
711          * appended later
712          */
713
714         if (sitename) {
715                 get_kdc_list(realm, sitename, &ip_srv_site, &count_site);
716                 DEBUG(10, ("got %d addresses from site %s search\n", count_site,
717                            sitename));
718         }
719
720         /* Get all KDC's. */
721
722         get_kdc_list(realm, NULL, &ip_srv_nonsite, &count_nonsite);
723         DEBUG(10, ("got %d addresses from site-less search\n", count_nonsite));
724
725         dc_addrs = talloc_array(talloc_tos(), struct sockaddr_storage,
726                                 count_site + count_nonsite);
727         if (dc_addrs == NULL) {
728                 goto out;
729         }
730
731         num_dcs = 0;
732
733         for (i = 0; i < count_site; i++) {
734                 if (!sockaddr_equal(
735                         (const struct sockaddr *)pss,
736                         (const struct sockaddr *)&ip_srv_site[i].ss)) {
737                         add_sockaddr_unique(dc_addrs, &num_dcs,
738                                             &ip_srv_site[i].ss);
739                 }
740         }
741
742         for (i = 0; i < count_nonsite; i++) {
743                 if (!sockaddr_equal(
744                         (const struct sockaddr *)pss,
745                         (const struct sockaddr *)&ip_srv_nonsite[i].ss)) {
746                         add_sockaddr_unique(dc_addrs, &num_dcs,
747                                             &ip_srv_nonsite[i].ss);
748                 }
749         }
750
751         dc_addrs2 = talloc_zero_array(talloc_tos(),
752                                       struct tsocket_address *,
753                                       num_dcs);
754
755         DEBUG(10, ("%d additional KDCs to test\n", num_dcs));
756         if (num_dcs == 0) {
757                 goto out;
758         }
759         if (dc_addrs2 == NULL) {
760                 goto out;
761         }
762
763         for (i=0; i<num_dcs; i++) {
764                 char addr[INET6_ADDRSTRLEN];
765                 int ret;
766
767                 print_sockaddr(addr, sizeof(addr), &dc_addrs[i]);
768
769                 ret = tsocket_address_inet_from_strings(dc_addrs2, "ip",
770                                                         addr, LDAP_PORT,
771                                                         &dc_addrs2[i]);
772                 if (ret != 0) {
773                         status = map_nt_error_from_unix(errno);
774                         DEBUG(2,("Failed to create tsocket_address for %s - %s\n",
775                                  addr, nt_errstr(status)));
776                         goto out;
777                 }
778         }
779
780         dc_addrs3 = (const struct tsocket_address * const *)dc_addrs2;
781
782         status = cldap_multi_netlogon(talloc_tos(),
783                         dc_addrs3, num_dcs,
784                         realm, lp_netbios_name(),
785                         NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX,
786                         MIN(num_dcs, 3), timeval_current_ofs(3, 0), &responses);
787         TALLOC_FREE(dc_addrs2);
788         dc_addrs3 = NULL;
789
790         if (!NT_STATUS_IS_OK(status)) {
791                 DEBUG(10,("get_kdc_ip_string: cldap_multi_netlogon failed: "
792                           "%s\n", nt_errstr(status)));
793                 goto out;
794         }
795
796         for (i=0; i<num_dcs; i++) {
797                 char *new_kdc_str;
798
799                 if (responses[i] == NULL) {
800                         continue;
801                 }
802
803                 /* Append to the string - inefficient but not done often. */
804                 new_kdc_str = talloc_asprintf(mem_ctx, "%s\t\tkdc = %s\n",
805                                               kdc_str,
806                                               print_canonical_sockaddr_with_port(mem_ctx, &dc_addrs[i]));
807                 if (new_kdc_str == NULL) {
808                         goto out;
809                 }
810                 TALLOC_FREE(kdc_str);
811                 kdc_str = new_kdc_str;
812         }
813
814 out:
815         DEBUG(10, ("get_kdc_ip_string: Returning %s\n", kdc_str));
816
817         result = kdc_str;
818         SAFE_FREE(ip_srv_site);
819         SAFE_FREE(ip_srv_nonsite);
820         TALLOC_FREE(frame);
821         return result;
822 }
823
824 /************************************************************************
825  Create  a specific krb5.conf file in the private directory pointing
826  at a specific kdc for a realm. Keyed off domain name. Sets
827  KRB5_CONFIG environment variable to point to this file. Must be
828  run as root or will fail (which is a good thing :-).
829 ************************************************************************/
830
831 bool create_local_private_krb5_conf_for_domain(const char *realm,
832                                                 const char *domain,
833                                                 const char *sitename,
834                                                 const struct sockaddr_storage *pss)
835 {
836         char *dname;
837         char *tmpname = NULL;
838         char *fname = NULL;
839         char *file_contents = NULL;
840         char *kdc_ip_string = NULL;
841         size_t flen = 0;
842         ssize_t ret;
843         int fd;
844         char *realm_upper = NULL;
845         bool result = false;
846         char *aes_enctypes = NULL;
847         mode_t mask;
848
849         if (!lp_create_krb5_conf()) {
850                 return false;
851         }
852
853         if (realm == NULL) {
854                 DEBUG(0, ("No realm has been specified! Do you really want to "
855                           "join an Active Directory server?\n"));
856                 return false;
857         }
858
859         if (domain == NULL || pss == NULL) {
860                 return false;
861         }
862
863         dname = lock_path("smb_krb5");
864         if (!dname) {
865                 return false;
866         }
867         if ((mkdir(dname, 0755)==-1) && (errno != EEXIST)) {
868                 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
869                         "failed to create directory %s. Error was %s\n",
870                         dname, strerror(errno) ));
871                 goto done;
872         }
873
874         tmpname = lock_path("smb_tmp_krb5.XXXXXX");
875         if (!tmpname) {
876                 goto done;
877         }
878
879         fname = talloc_asprintf(dname, "%s/krb5.conf.%s", dname, domain);
880         if (!fname) {
881                 goto done;
882         }
883
884         DEBUG(10,("create_local_private_krb5_conf_for_domain: fname = %s, realm = %s, domain = %s\n",
885                 fname, realm, domain ));
886
887         realm_upper = talloc_strdup(fname, realm);
888         if (!strupper_m(realm_upper)) {
889                 goto done;
890         }
891
892         kdc_ip_string = get_kdc_ip_string(dname, realm, sitename, pss);
893         if (!kdc_ip_string) {
894                 goto done;
895         }
896
897         aes_enctypes = talloc_strdup(fname, "");
898         if (aes_enctypes == NULL) {
899                 goto done;
900         }
901
902 #ifdef HAVE_ENCTYPE_AES256_CTS_HMAC_SHA1_96
903         aes_enctypes = talloc_asprintf_append(aes_enctypes, "%s", "aes256-cts-hmac-sha1-96 ");
904         if (aes_enctypes == NULL) {
905                 goto done;
906         }
907 #endif
908 #ifdef HAVE_ENCTYPE_AES128_CTS_HMAC_SHA1_96
909         aes_enctypes = talloc_asprintf_append(aes_enctypes, "%s", "aes128-cts-hmac-sha1-96");
910         if (aes_enctypes == NULL) {
911                 goto done;
912         }
913 #endif
914
915         file_contents = talloc_asprintf(fname,
916                                         "[libdefaults]\n\tdefault_realm = %s\n"
917                                         "\tdefault_tgs_enctypes = %s RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
918                                         "\tdefault_tkt_enctypes = %s RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
919                                         "\tpreferred_enctypes = %s RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
920                                         "\tdns_lookup_realm = false\n\n"
921                                         "[realms]\n\t%s = {\n"
922                                         "%s\t}\n",
923                                         realm_upper, aes_enctypes, aes_enctypes, aes_enctypes,
924                                         realm_upper, kdc_ip_string);
925
926         if (!file_contents) {
927                 goto done;
928         }
929
930         flen = strlen(file_contents);
931
932         mask = umask(S_IRWXO | S_IRWXG);
933         fd = mkstemp(tmpname);
934         umask(mask);
935         if (fd == -1) {
936                 DEBUG(0,("create_local_private_krb5_conf_for_domain: smb_mkstemp failed,"
937                         " for file %s. Errno %s\n",
938                         tmpname, strerror(errno) ));
939                 goto done;
940         }
941
942         if (fchmod(fd, 0644)==-1) {
943                 DEBUG(0,("create_local_private_krb5_conf_for_domain: fchmod failed for %s."
944                         " Errno %s\n",
945                         tmpname, strerror(errno) ));
946                 unlink(tmpname);
947                 close(fd);
948                 goto done;
949         }
950
951         ret = write(fd, file_contents, flen);
952         if (flen != ret) {
953                 DEBUG(0,("create_local_private_krb5_conf_for_domain: write failed,"
954                         " returned %d (should be %u). Errno %s\n",
955                         (int)ret, (unsigned int)flen, strerror(errno) ));
956                 unlink(tmpname);
957                 close(fd);
958                 goto done;
959         }
960         if (close(fd)==-1) {
961                 DEBUG(0,("create_local_private_krb5_conf_for_domain: close failed."
962                         " Errno %s\n", strerror(errno) ));
963                 unlink(tmpname);
964                 goto done;
965         }
966
967         if (rename(tmpname, fname) == -1) {
968                 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
969                         "of %s to %s failed. Errno %s\n",
970                         tmpname, fname, strerror(errno) ));
971                 unlink(tmpname);
972                 goto done;
973         }
974
975         DEBUG(5,("create_local_private_krb5_conf_for_domain: wrote "
976                 "file %s with realm %s KDC list = %s\n",
977                 fname, realm_upper, kdc_ip_string));
978
979         /* Set the environment variable to this file. */
980         setenv("KRB5_CONFIG", fname, 1);
981
982         result = true;
983
984 #if defined(OVERWRITE_SYSTEM_KRB5_CONF)
985
986 #define SYSTEM_KRB5_CONF_PATH "/etc/krb5.conf"
987         /* Insanity, sheer insanity..... */
988
989         if (strequal(realm, lp_realm())) {
990                 SMB_STRUCT_STAT sbuf;
991
992                 if (sys_lstat(SYSTEM_KRB5_CONF_PATH, &sbuf, false) == 0) {
993                         if (S_ISLNK(sbuf.st_ex_mode) && sbuf.st_ex_size) {
994                                 int lret;
995                                 size_t alloc_size = sbuf.st_ex_size + 1;
996                                 char *linkpath = talloc_array(talloc_tos(), char,
997                                                 alloc_size);
998                                 if (!linkpath) {
999                                         goto done;
1000                                 }
1001                                 lret = readlink(SYSTEM_KRB5_CONF_PATH, linkpath,
1002                                                 alloc_size - 1);
1003                                 if (lret == -1) {
1004                                         TALLOC_FREE(linkpath);
1005                                         goto done;
1006                                 }
1007                                 linkpath[lret] = '\0';
1008
1009                                 if (strcmp(linkpath, fname) == 0) {
1010                                         /* Symlink already exists. */
1011                                         TALLOC_FREE(linkpath);
1012                                         goto done;
1013                                 }
1014                                 TALLOC_FREE(linkpath);
1015                         }
1016                 }
1017
1018                 /* Try and replace with a symlink. */
1019                 if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
1020                         const char *newpath = SYSTEM_KRB5_CONF_PATH ".saved";
1021                         if (errno != EEXIST) {
1022                                 DEBUG(0,("create_local_private_krb5_conf_for_domain: symlink "
1023                                         "of %s to %s failed. Errno %s\n",
1024                                         fname, SYSTEM_KRB5_CONF_PATH, strerror(errno) ));
1025                                 goto done; /* Not a fatal error. */
1026                         }
1027
1028                         /* Yes, this is a race conditon... too bad. */
1029                         if (rename(SYSTEM_KRB5_CONF_PATH, newpath) == -1) {
1030                                 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
1031                                         "of %s to %s failed. Errno %s\n",
1032                                         SYSTEM_KRB5_CONF_PATH, newpath,
1033                                         strerror(errno) ));
1034                                 goto done; /* Not a fatal error. */
1035                         }
1036
1037                         if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
1038                                 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
1039                                         "forced symlink of %s to /etc/krb5.conf failed. Errno %s\n",
1040                                         fname, strerror(errno) ));
1041                                 goto done; /* Not a fatal error. */
1042                         }
1043                 }
1044         }
1045 #endif
1046
1047 done:
1048         TALLOC_FREE(tmpname);
1049         TALLOC_FREE(dname);
1050
1051         return result;
1052 }
1053 #endif