50a409c1af58e30d451e9011724b224cfe55d125
[metze/samba/wip.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                                                         lp_netbios_name()))) {
224                         goto out;
225                 }
226                 krb5_get_init_creds_opt_set_address_list(opt, addr->addrs);
227         }
228
229         if ((code = krb5_get_init_creds_password(ctx, &my_creds, me, discard_const_p(char,password), 
230                                                  kerb_prompter, discard_const_p(char, password),
231                                                  0, NULL, opt))) {
232                 goto out;
233         }
234
235         if ((code = krb5_cc_initialize(ctx, cc, me))) {
236                 goto out;
237         }
238
239         if ((code = krb5_cc_store_cred(ctx, cc, &my_creds))) {
240                 goto out;
241         }
242
243         if (expire_time) {
244                 *expire_time = (time_t) my_creds.times.endtime;
245         }
246
247         if (renew_till_time) {
248                 *renew_till_time = (time_t) my_creds.times.renew_till;
249         }
250  out:
251         if (ntstatus) {
252
253                 NTSTATUS status;
254
255                 /* fast path */
256                 if (code == 0) {
257                         *ntstatus = NT_STATUS_OK;
258                         goto cleanup;
259                 }
260
261                 /* try to get ntstatus code out of krb5_error when we have it
262                  * inside the krb5_get_init_creds_opt - gd */
263
264                 if (opt && smb_krb5_get_ntstatus_from_krb5_error_init_creds_opt(ctx, opt, &status)) {
265                         *ntstatus = status;
266                         goto cleanup;
267                 }
268
269                 /* fall back to self-made-mapping */
270                 *ntstatus = krb5_to_nt_status(code);
271         }
272
273  cleanup:
274         krb5_free_cred_contents(ctx, &my_creds);
275         if (me) {
276                 krb5_free_principal(ctx, me);
277         }
278         if (addr) {
279                 smb_krb5_free_addresses(ctx, addr);
280         }
281         if (opt) {
282                 smb_krb5_get_init_creds_opt_free(ctx, opt);
283         }
284         if (cc) {
285                 krb5_cc_close(ctx, cc);
286         }
287         if (ctx) {
288                 krb5_free_context(ctx);
289         }
290         return code;
291 }
292
293 int ads_kdestroy(const char *cc_name)
294 {
295         krb5_error_code code;
296         krb5_context ctx = NULL;
297         krb5_ccache cc = NULL;
298
299         initialize_krb5_error_table();
300         if ((code = krb5_init_context (&ctx))) {
301                 DEBUG(3, ("ads_kdestroy: kdb5_init_context failed: %s\n", 
302                         error_message(code)));
303                 return code;
304         }
305
306         if (!cc_name) {
307                 if ((code = krb5_cc_default(ctx, &cc))) {
308                         krb5_free_context(ctx);
309                         return code;
310                 }
311         } else {
312                 if ((code = krb5_cc_resolve(ctx, cc_name, &cc))) {
313                         DEBUG(3, ("ads_kdestroy: krb5_cc_resolve failed: %s\n",
314                                   error_message(code)));
315                         krb5_free_context(ctx);
316                         return code;
317                 }
318         }
319
320         if ((code = krb5_cc_destroy (ctx, cc))) {
321                 DEBUG(3, ("ads_kdestroy: krb5_cc_destroy failed: %s\n", 
322                         error_message(code)));
323         }
324
325         krb5_free_context (ctx);
326         return code;
327 }
328
329 /************************************************************************
330  Routine to fetch the salting principal for a service.  Active
331  Directory may use a non-obvious principal name to generate the salt
332  when it determines the key to use for encrypting tickets for a service,
333  and hopefully we detected that when we joined the domain.
334  ************************************************************************/
335
336 static char *kerberos_secrets_fetch_salting_principal(const char *service, int enctype)
337 {
338         char *key = NULL;
339         char *ret = NULL;
340
341         if (asprintf(&key, "%s/%s/enctype=%d",
342                      SECRETS_SALTING_PRINCIPAL, service, enctype) == -1) {
343                 return NULL;
344         }
345         ret = (char *)secrets_fetch(key, NULL);
346         SAFE_FREE(key);
347         return ret;
348 }
349
350 /************************************************************************
351  Return the standard DES salt key
352 ************************************************************************/
353
354 char* kerberos_standard_des_salt( void )
355 {
356         fstring salt;
357
358         fstr_sprintf( salt, "host/%s.%s@", lp_netbios_name(), lp_realm() );
359         (void)strlower_m( salt );
360         fstrcat( salt, lp_realm() );
361
362         return SMB_STRDUP( salt );
363 }
364
365 /************************************************************************
366 ************************************************************************/
367
368 static char* des_salt_key( void )
369 {
370         char *key;
371
372         if (asprintf(&key, "%s/DES/%s", SECRETS_SALTING_PRINCIPAL,
373                      lp_realm()) == -1) {
374                 return NULL;
375         }
376
377         return key;
378 }
379
380 /************************************************************************
381 ************************************************************************/
382
383 bool kerberos_secrets_store_des_salt( const char* salt )
384 {
385         char* key;
386         bool ret;
387
388         if ( (key = des_salt_key()) == NULL ) {
389                 DEBUG(0,("kerberos_secrets_store_des_salt: failed to generate key!\n"));
390                 return False;
391         }
392
393         if ( !salt ) {
394                 DEBUG(8,("kerberos_secrets_store_des_salt: deleting salt\n"));
395                 secrets_delete( key );
396                 return True;
397         }
398
399         DEBUG(3,("kerberos_secrets_store_des_salt: Storing salt \"%s\"\n", salt));
400
401         ret = secrets_store( key, salt, strlen(salt)+1 );
402
403         SAFE_FREE( key );
404
405         return ret;
406 }
407
408 /************************************************************************
409 ************************************************************************/
410
411 static
412 char* kerberos_secrets_fetch_des_salt( void )
413 {
414         char *salt, *key;
415
416         if ( (key = des_salt_key()) == NULL ) {
417                 DEBUG(0,("kerberos_secrets_fetch_des_salt: failed to generate key!\n"));
418                 return NULL;
419         }
420
421         salt = (char*)secrets_fetch( key, NULL );
422
423         SAFE_FREE( key );
424
425         return salt;
426 }
427
428 /************************************************************************
429  Routine to get the salting principal for this service.  This is 
430  maintained for backwards compatibilty with releases prior to 3.0.24.
431  Since we store the salting principal string only at join, we may have 
432  to look for the older tdb keys.  Caller must free if return is not null.
433  ************************************************************************/
434
435 static
436 krb5_principal kerberos_fetch_salt_princ_for_host_princ(krb5_context context,
437                                                         krb5_principal host_princ,
438                                                         int enctype)
439 {
440         char *unparsed_name = NULL, *salt_princ_s = NULL;
441         krb5_principal ret_princ = NULL;
442
443         /* lookup new key first */
444
445         if ( (salt_princ_s = kerberos_secrets_fetch_des_salt()) == NULL ) {
446
447                 /* look under the old key.  If this fails, just use the standard key */
448
449                 if (smb_krb5_unparse_name(talloc_tos(), context, host_princ, &unparsed_name) != 0) {
450                         return (krb5_principal)NULL;
451                 }
452                 if ((salt_princ_s = kerberos_secrets_fetch_salting_principal(unparsed_name, enctype)) == NULL) {
453                         /* fall back to host/machine.realm@REALM */
454                         salt_princ_s = kerberos_standard_des_salt();
455                 }
456         }
457
458         if (smb_krb5_parse_name(context, salt_princ_s, &ret_princ) != 0) {
459                 ret_princ = NULL;
460         }
461
462         TALLOC_FREE(unparsed_name);
463         SAFE_FREE(salt_princ_s);
464
465         return ret_princ;
466 }
467
468 int create_kerberos_key_from_string(krb5_context context,
469                                         krb5_principal host_princ,
470                                         krb5_data *password,
471                                         krb5_keyblock *key,
472                                         krb5_enctype enctype,
473                                         bool no_salt)
474 {
475         krb5_principal salt_princ = NULL;
476         int ret;
477         /*
478          * Check if we've determined that the KDC is salting keys for this
479          * principal/enctype in a non-obvious way.  If it is, try to match
480          * its behavior.
481          */
482         if (no_salt) {
483                 KRB5_KEY_DATA(key) = (KRB5_KEY_DATA_CAST *)SMB_MALLOC(password->length);
484                 if (!KRB5_KEY_DATA(key)) {
485                         return ENOMEM;
486                 }
487                 memcpy(KRB5_KEY_DATA(key), password->data, password->length);
488                 KRB5_KEY_LENGTH(key) = password->length;
489                 KRB5_KEY_TYPE(key) = enctype;
490                 return 0;
491         }
492         salt_princ = kerberos_fetch_salt_princ_for_host_princ(context, host_princ, enctype);
493         ret = create_kerberos_key_from_string_direct(context, salt_princ ? salt_princ : host_princ, password, key, enctype);
494         if (salt_princ) {
495                 krb5_free_principal(context, salt_princ);
496         }
497         return ret;
498 }
499
500 /************************************************************************
501  Routine to set the salting principal for this service.  Active
502  Directory may use a non-obvious principal name to generate the salt
503  when it determines the key to use for encrypting tickets for a service,
504  and hopefully we detected that when we joined the domain.
505  Setting principal to NULL deletes this entry.
506  ************************************************************************/
507
508 bool kerberos_secrets_store_salting_principal(const char *service,
509                                               int enctype,
510                                               const char *principal)
511 {
512         char *key = NULL;
513         bool ret = False;
514         krb5_context context = NULL;
515         krb5_principal princ = NULL;
516         char *princ_s = NULL;
517         char *unparsed_name = NULL;
518         krb5_error_code code;
519
520         if (((code = krb5_init_context(&context)) != 0) || (context == NULL)) {
521                 DEBUG(5, ("kerberos_secrets_store_salting_pricipal: kdb5_init_context failed: %s\n",
522                           error_message(code)));
523                 return False;
524         }
525         if (strchr_m(service, '@')) {
526                 if (asprintf(&princ_s, "%s", service) == -1) {
527                         goto out;
528                 }
529         } else {
530                 if (asprintf(&princ_s, "%s@%s", service, lp_realm()) == -1) {
531                         goto out;
532                 }
533         }
534
535         if (smb_krb5_parse_name(context, princ_s, &princ) != 0) {
536                 goto out;
537         }
538         if (smb_krb5_unparse_name(talloc_tos(), context, princ, &unparsed_name) != 0) {
539                 goto out;
540         }
541
542         if (asprintf(&key, "%s/%s/enctype=%d",
543                      SECRETS_SALTING_PRINCIPAL, unparsed_name, enctype)
544             == -1) {
545                 goto out;
546         }
547
548         if ((principal != NULL) && (strlen(principal) > 0)) {
549                 ret = secrets_store(key, principal, strlen(principal) + 1);
550         } else {
551                 ret = secrets_delete(key);
552         }
553
554  out:
555
556         SAFE_FREE(key);
557         SAFE_FREE(princ_s);
558         TALLOC_FREE(unparsed_name);
559
560         if (princ) {
561                 krb5_free_principal(context, princ);
562         }
563
564         if (context) {
565                 krb5_free_context(context);
566         }
567
568         return ret;
569 }
570
571
572 /************************************************************************
573 ************************************************************************/
574
575 int kerberos_kinit_password(const char *principal,
576                             const char *password,
577                             int time_offset,
578                             const char *cache_name)
579 {
580         return kerberos_kinit_password_ext(principal, 
581                                            password, 
582                                            time_offset, 
583                                            0, 
584                                            0,
585                                            cache_name,
586                                            False,
587                                            False,
588                                            0,
589                                            NULL);
590 }
591
592 /************************************************************************
593 ************************************************************************/
594
595 static char *print_kdc_line(char *mem_ctx,
596                         const char *prev_line,
597                         const struct sockaddr_storage *pss,
598                         const char *kdc_name)
599 {
600         char addr[INET6_ADDRSTRLEN];
601         uint16_t port = get_sockaddr_port(pss);
602
603         if (pss->ss_family == AF_INET) {
604                 return talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
605                                        prev_line,
606                                        print_canonical_sockaddr(mem_ctx, pss));
607         }
608
609         /*
610          * IPv6 starts here
611          */
612
613         DEBUG(10, ("print_kdc_line: IPv6 case for kdc_name: %s, port: %d\n",
614                    kdc_name, port));
615
616         if (port != 0 && port != DEFAULT_KRB5_PORT) {
617                 /* Currently for IPv6 we can't specify a non-default
618                    krb5 port with an address, as this requires a ':'.
619                    Resolve to a name. */
620                 char hostname[MAX_DNS_NAME_LENGTH];
621                 int ret = sys_getnameinfo((const struct sockaddr *)pss,
622                                           sizeof(*pss),
623                                           hostname, sizeof(hostname),
624                                           NULL, 0,
625                                           NI_NAMEREQD);
626                 if (ret) {
627                         DEBUG(0,("print_kdc_line: can't resolve name "
628                                  "for kdc with non-default port %s. "
629                                  "Error %s\n.",
630                                  print_canonical_sockaddr(mem_ctx, pss),
631                                  gai_strerror(ret)));
632                         return NULL;
633                 }
634                 /* Success, use host:port */
635                 return talloc_asprintf(mem_ctx,
636                                        "%s\tkdc = %s:%u\n",
637                                        prev_line,
638                                        hostname,
639                                        (unsigned int)port);
640         }
641
642         /* no krb5 lib currently supports "kdc = ipv6 address"
643          * at all, so just fill in just the kdc_name if we have
644          * it and let the krb5 lib figure out the appropriate
645          * ipv6 address - gd */
646
647         if (kdc_name) {
648                 return talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
649                                        prev_line, kdc_name);
650         }
651
652         return talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
653                                prev_line,
654                                print_sockaddr(addr,
655                                               sizeof(addr),
656                                               pss));
657 }
658
659 /************************************************************************
660  Create a string list of available kdc's, possibly searching by sitename.
661  Does DNS queries.
662
663  If "sitename" is given, the DC's in that site are listed first.
664
665 ************************************************************************/
666
667 static void add_sockaddr_unique(struct sockaddr_storage *addrs, int *num_addrs,
668                                 const struct sockaddr_storage *addr)
669 {
670         int i;
671
672         for (i=0; i<*num_addrs; i++) {
673                 if (sockaddr_equal((const struct sockaddr *)&addrs[i],
674                                    (const struct sockaddr *)addr)) {
675                         return;
676                 }
677         }
678         addrs[i] = *addr;
679         *num_addrs += 1;
680 }
681
682 static char *get_kdc_ip_string(char *mem_ctx,
683                 const char *realm,
684                 const char *sitename,
685                 const struct sockaddr_storage *pss,
686                 const char *kdc_name)
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 = print_kdc_line(mem_ctx, "", pss, kdc_name);
702
703         if (kdc_str == NULL) {
704                 TALLOC_FREE(frame);
705                 return NULL;
706         }
707
708         /*
709          * First get the KDC's only in this site, the rest will be
710          * appended later
711          */
712
713         if (sitename) {
714                 get_kdc_list(realm, sitename, &ip_srv_site, &count_site);
715         }
716
717         /* Get all KDC's. */
718
719         get_kdc_list(realm, NULL, &ip_srv_nonsite, &count_nonsite);
720
721         dc_addrs = talloc_array(talloc_tos(), struct sockaddr_storage,
722                                 1 + count_site + count_nonsite);
723         if (dc_addrs == NULL) {
724                 goto fail;
725         }
726
727         dc_addrs[0] = *pss;
728         num_dcs = 1;
729
730         for (i=0; i<count_site; i++) {
731                 add_sockaddr_unique(dc_addrs, &num_dcs, &ip_srv_site[i].ss);
732         }
733
734         for (i=0; i<count_nonsite; i++) {
735                 add_sockaddr_unique(dc_addrs, &num_dcs, &ip_srv_nonsite[i].ss);
736         }
737
738         dc_addrs2 = talloc_zero_array(talloc_tos(),
739                                       struct tsocket_address *,
740                                       num_dcs);
741         if (dc_addrs2 == NULL) {
742                 goto fail;
743         }
744
745         for (i=0; i<num_dcs; i++) {
746                 char addr[INET6_ADDRSTRLEN];
747                 int ret;
748
749                 print_sockaddr(addr, sizeof(addr), &dc_addrs[i]);
750
751                 ret = tsocket_address_inet_from_strings(dc_addrs2, "ip",
752                                                         addr, LDAP_PORT,
753                                                         &dc_addrs2[i]);
754                 if (ret != 0) {
755                         status = map_nt_error_from_unix(errno);
756                         DEBUG(2,("Failed to create tsocket_address for %s - %s\n",
757                                  addr, nt_errstr(status)));
758                         goto fail;
759                 }
760         }
761
762         dc_addrs3 = (const struct tsocket_address * const *)dc_addrs2;
763
764         status = cldap_multi_netlogon(talloc_tos(),
765                         dc_addrs3, num_dcs,
766                         realm, lp_netbios_name(),
767                         NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX,
768                         MIN(num_dcs, 3), timeval_current_ofs(3, 0), &responses);
769         TALLOC_FREE(dc_addrs2);
770         dc_addrs3 = NULL;
771
772         if (!NT_STATUS_IS_OK(status)) {
773                 DEBUG(10,("get_kdc_ip_string: cldap_multi_netlogon failed: "
774                           "%s\n", nt_errstr(status)));
775                 goto fail;
776         }
777
778         kdc_str = talloc_strdup(mem_ctx, "");
779         if (kdc_str == NULL) {
780                 goto fail;
781         }
782
783         for (i=0; i<num_dcs; i++) {
784                 char *new_kdc_str;
785
786                 if (responses[i] == NULL) {
787                         continue;
788                 }
789
790                 /* Append to the string - inefficient but not done often. */
791                 new_kdc_str = print_kdc_line(mem_ctx, kdc_str,
792                                              &dc_addrs[i],
793                                              kdc_name);
794                 if (new_kdc_str == NULL) {
795                         goto fail;
796                 }
797                 TALLOC_FREE(kdc_str);
798                 kdc_str = new_kdc_str;
799         }
800
801         DEBUG(10,("get_kdc_ip_string: Returning %s\n",
802                 kdc_str ));
803
804         result = kdc_str;
805 fail:
806         SAFE_FREE(ip_srv_site);
807         SAFE_FREE(ip_srv_nonsite);
808         TALLOC_FREE(frame);
809         return result;
810 }
811
812 /************************************************************************
813  Create  a specific krb5.conf file in the private directory pointing
814  at a specific kdc for a realm. Keyed off domain name. Sets
815  KRB5_CONFIG environment variable to point to this file. Must be
816  run as root or will fail (which is a good thing :-).
817 ************************************************************************/
818
819 bool create_local_private_krb5_conf_for_domain(const char *realm,
820                                                 const char *domain,
821                                                 const char *sitename,
822                                                 const struct sockaddr_storage *pss,
823                                                 const char *kdc_name)
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
837         if (!lp_create_krb5_conf()) {
838                 return false;
839         }
840
841         dname = lock_path("smb_krb5");
842         if (!dname) {
843                 return false;
844         }
845         if ((mkdir(dname, 0755)==-1) && (errno != EEXIST)) {
846                 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
847                         "failed to create directory %s. Error was %s\n",
848                         dname, strerror(errno) ));
849                 goto done;
850         }
851
852         tmpname = lock_path("smb_tmp_krb5.XXXXXX");
853         if (!tmpname) {
854                 goto done;
855         }
856
857         fname = talloc_asprintf(dname, "%s/krb5.conf.%s", dname, domain);
858         if (!fname) {
859                 goto done;
860         }
861
862         DEBUG(10,("create_local_private_krb5_conf_for_domain: fname = %s, realm = %s, domain = %s\n",
863                 fname, realm, domain ));
864
865         realm_upper = talloc_strdup(fname, realm);
866         if (!strupper_m(realm_upper)) {
867                 goto done;
868         }
869
870         kdc_ip_string = get_kdc_ip_string(dname, realm, sitename, pss, kdc_name);
871         if (!kdc_ip_string) {
872                 goto done;
873         }
874
875         aes_enctypes = talloc_strdup(fname, "");
876         if (aes_enctypes == NULL) {
877                 goto done;
878         }
879
880 #ifdef HAVE_ENCTYPE_AES256_CTS_HMAC_SHA1_96
881         aes_enctypes = talloc_asprintf_append(aes_enctypes, "%s", "aes256-cts-hmac-sha1-96 ");
882         if (aes_enctypes == NULL) {
883                 goto done;
884         }
885 #endif
886 #ifdef HAVE_ENCTYPE_AES128_CTS_HMAC_SHA1_96
887         aes_enctypes = talloc_asprintf_append(aes_enctypes, "%s", "aes128-cts-hmac-sha1-96");
888         if (aes_enctypes == NULL) {
889                 goto done;
890         }
891 #endif
892
893         file_contents = talloc_asprintf(fname,
894                                         "[libdefaults]\n\tdefault_realm = %s\n"
895                                         "\tdefault_tgs_enctypes = %s RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
896                                         "\tdefault_tkt_enctypes = %s RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
897                                         "\tpreferred_enctypes = %s RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n\n"
898                                         "[realms]\n\t%s = {\n"
899                                         "\t%s\t}\n",
900                                         realm_upper, aes_enctypes, aes_enctypes, aes_enctypes,
901                                         realm_upper, kdc_ip_string);
902
903         if (!file_contents) {
904                 goto done;
905         }
906
907         flen = strlen(file_contents);
908
909         fd = mkstemp(tmpname);
910         if (fd == -1) {
911                 DEBUG(0,("create_local_private_krb5_conf_for_domain: smb_mkstemp failed,"
912                         " for file %s. Errno %s\n",
913                         tmpname, strerror(errno) ));
914                 goto done;
915         }
916
917         if (fchmod(fd, 0644)==-1) {
918                 DEBUG(0,("create_local_private_krb5_conf_for_domain: fchmod failed for %s."
919                         " Errno %s\n",
920                         tmpname, strerror(errno) ));
921                 unlink(tmpname);
922                 close(fd);
923                 goto done;
924         }
925
926         ret = write(fd, file_contents, flen);
927         if (flen != ret) {
928                 DEBUG(0,("create_local_private_krb5_conf_for_domain: write failed,"
929                         " returned %d (should be %u). Errno %s\n",
930                         (int)ret, (unsigned int)flen, strerror(errno) ));
931                 unlink(tmpname);
932                 close(fd);
933                 goto done;
934         }
935         if (close(fd)==-1) {
936                 DEBUG(0,("create_local_private_krb5_conf_for_domain: close failed."
937                         " Errno %s\n", strerror(errno) ));
938                 unlink(tmpname);
939                 goto done;
940         }
941
942         if (rename(tmpname, fname) == -1) {
943                 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
944                         "of %s to %s failed. Errno %s\n",
945                         tmpname, fname, strerror(errno) ));
946                 unlink(tmpname);
947                 goto done;
948         }
949
950         DEBUG(5,("create_local_private_krb5_conf_for_domain: wrote "
951                 "file %s with realm %s KDC list = %s\n",
952                 fname, realm_upper, kdc_ip_string));
953
954         /* Set the environment variable to this file. */
955         setenv("KRB5_CONFIG", fname, 1);
956
957         result = true;
958
959 #if defined(OVERWRITE_SYSTEM_KRB5_CONF)
960
961 #define SYSTEM_KRB5_CONF_PATH "/etc/krb5.conf"
962         /* Insanity, sheer insanity..... */
963
964         if (strequal(realm, lp_realm())) {
965                 SMB_STRUCT_STAT sbuf;
966
967                 if (sys_lstat(SYSTEM_KRB5_CONF_PATH, &sbuf, false) == 0) {
968                         if (S_ISLNK(sbuf.st_ex_mode) && sbuf.st_ex_size) {
969                                 int lret;
970                                 size_t alloc_size = sbuf.st_ex_size + 1;
971                                 char *linkpath = talloc_array(talloc_tos(), char,
972                                                 alloc_size);
973                                 if (!linkpath) {
974                                         goto done;
975                                 }
976                                 lret = readlink(SYSTEM_KRB5_CONF_PATH, linkpath,
977                                                 alloc_size - 1);
978                                 if (lret == -1) {
979                                         TALLOC_FREE(linkpath);
980                                         goto done;
981                                 }
982                                 linkpath[lret] = '\0';
983
984                                 if (strcmp(linkpath, fname) == 0) {
985                                         /* Symlink already exists. */
986                                         TALLOC_FREE(linkpath);
987                                         goto done;
988                                 }
989                                 TALLOC_FREE(linkpath);
990                         }
991                 }
992
993                 /* Try and replace with a symlink. */
994                 if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
995                         const char *newpath = SYSTEM_KRB5_CONF_PATH ".saved";
996                         if (errno != EEXIST) {
997                                 DEBUG(0,("create_local_private_krb5_conf_for_domain: symlink "
998                                         "of %s to %s failed. Errno %s\n",
999                                         fname, SYSTEM_KRB5_CONF_PATH, strerror(errno) ));
1000                                 goto done; /* Not a fatal error. */
1001                         }
1002
1003                         /* Yes, this is a race conditon... too bad. */
1004                         if (rename(SYSTEM_KRB5_CONF_PATH, newpath) == -1) {
1005                                 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
1006                                         "of %s to %s failed. Errno %s\n",
1007                                         SYSTEM_KRB5_CONF_PATH, newpath,
1008                                         strerror(errno) ));
1009                                 goto done; /* Not a fatal error. */
1010                         }
1011
1012                         if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
1013                                 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
1014                                         "forced symlink of %s to /etc/krb5.conf failed. Errno %s\n",
1015                                         fname, strerror(errno) ));
1016                                 goto done; /* Not a fatal error. */
1017                         }
1018                 }
1019         }
1020 #endif
1021
1022 done:
1023         TALLOC_FREE(tmpname);
1024         TALLOC_FREE(dname);
1025
1026         return result;
1027 }
1028 #endif