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