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