s3-kerberos: make ipv6 support for generated krb5 config files more robust.
[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 /************************************************************************
596  Create a string list of available kdc's, possibly searching by sitename.
597  Does DNS queries.
598
599  If "sitename" is given, the DC's in that site are listed first.
600
601 ************************************************************************/
602
603 static void add_sockaddr_unique(struct sockaddr_storage *addrs, int *num_addrs,
604                                 const struct sockaddr_storage *addr)
605 {
606         int i;
607
608         for (i=0; i<*num_addrs; i++) {
609                 if (sockaddr_equal((const struct sockaddr *)&addrs[i],
610                                    (const struct sockaddr *)addr)) {
611                         return;
612                 }
613         }
614         addrs[i] = *addr;
615         *num_addrs += 1;
616 }
617
618 /* print_canonical_sockaddr prints an ipv6 addr in the form of
619 * [ipv6.addr]. This string, when put in a generated krb5.conf file is not
620 * always properly dealt with by some older krb5 libraries. Adding the hard-coded
621 * portnumber workarounds the issue. - gd */
622
623 static char *print_canonical_sockaddr_with_port(TALLOC_CTX *mem_ctx,
624                                                 const struct sockaddr_storage *pss)
625 {
626         char *str = NULL;
627
628         str = print_canonical_sockaddr(mem_ctx, pss);
629         if (str == NULL) {
630                 return NULL;
631         }
632
633         if (pss->ss_family != AF_INET6) {
634                 return str;
635         }
636
637 #if defined(HAVE_IPV6)
638         str = talloc_asprintf_append(str, ":88");
639 #endif
640         return str;
641 }
642
643 static char *get_kdc_ip_string(char *mem_ctx,
644                 const char *realm,
645                 const char *sitename,
646                 const struct sockaddr_storage *pss)
647 {
648         TALLOC_CTX *frame = talloc_stackframe();
649         int i;
650         struct ip_service *ip_srv_site = NULL;
651         struct ip_service *ip_srv_nonsite = NULL;
652         int count_site = 0;
653         int count_nonsite;
654         int num_dcs;
655         struct sockaddr_storage *dc_addrs;
656         struct tsocket_address **dc_addrs2 = NULL;
657         const struct tsocket_address * const *dc_addrs3 = NULL;
658         char *result = NULL;
659         struct netlogon_samlogon_response **responses = NULL;
660         NTSTATUS status;
661         char *kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n", "",
662                                         print_canonical_sockaddr_with_port(mem_ctx, pss));
663
664         if (kdc_str == NULL) {
665                 TALLOC_FREE(frame);
666                 return NULL;
667         }
668
669         /*
670          * First get the KDC's only in this site, the rest will be
671          * appended later
672          */
673
674         if (sitename) {
675                 get_kdc_list(realm, sitename, &ip_srv_site, &count_site);
676         }
677
678         /* Get all KDC's. */
679
680         get_kdc_list(realm, NULL, &ip_srv_nonsite, &count_nonsite);
681
682         dc_addrs = talloc_array(talloc_tos(), struct sockaddr_storage,
683                                 1 + count_site + count_nonsite);
684         if (dc_addrs == NULL) {
685                 goto fail;
686         }
687
688         dc_addrs[0] = *pss;
689         num_dcs = 1;
690
691         for (i=0; i<count_site; i++) {
692                 add_sockaddr_unique(dc_addrs, &num_dcs, &ip_srv_site[i].ss);
693         }
694
695         for (i=0; i<count_nonsite; i++) {
696                 add_sockaddr_unique(dc_addrs, &num_dcs, &ip_srv_nonsite[i].ss);
697         }
698
699         dc_addrs2 = talloc_zero_array(talloc_tos(),
700                                       struct tsocket_address *,
701                                       num_dcs);
702         if (dc_addrs2 == NULL) {
703                 goto fail;
704         }
705
706         for (i=0; i<num_dcs; i++) {
707                 char addr[INET6_ADDRSTRLEN];
708                 int ret;
709
710                 print_sockaddr(addr, sizeof(addr), &dc_addrs[i]);
711
712                 ret = tsocket_address_inet_from_strings(dc_addrs2, "ip",
713                                                         addr, LDAP_PORT,
714                                                         &dc_addrs2[i]);
715                 if (ret != 0) {
716                         status = map_nt_error_from_unix(errno);
717                         DEBUG(2,("Failed to create tsocket_address for %s - %s\n",
718                                  addr, nt_errstr(status)));
719                         goto fail;
720                 }
721         }
722
723         dc_addrs3 = (const struct tsocket_address * const *)dc_addrs2;
724
725         status = cldap_multi_netlogon(talloc_tos(),
726                         dc_addrs3, num_dcs,
727                         realm, lp_netbios_name(),
728                         NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX,
729                         MIN(num_dcs, 3), timeval_current_ofs(3, 0), &responses);
730         TALLOC_FREE(dc_addrs2);
731         dc_addrs3 = NULL;
732
733         if (!NT_STATUS_IS_OK(status)) {
734                 DEBUG(10,("get_kdc_ip_string: cldap_multi_netlogon failed: "
735                           "%s\n", nt_errstr(status)));
736                 goto fail;
737         }
738
739         kdc_str = talloc_strdup(mem_ctx, "");
740         if (kdc_str == NULL) {
741                 goto fail;
742         }
743
744         for (i=0; i<num_dcs; i++) {
745                 char *new_kdc_str;
746
747                 if (responses[i] == NULL) {
748                         continue;
749                 }
750
751                 /* Append to the string - inefficient but not done often. */
752                 new_kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
753                                               kdc_str,
754                                               print_canonical_sockaddr_with_port(mem_ctx, &dc_addrs[i]));
755                 if (new_kdc_str == NULL) {
756                         goto fail;
757                 }
758                 TALLOC_FREE(kdc_str);
759                 kdc_str = new_kdc_str;
760         }
761
762         DEBUG(10,("get_kdc_ip_string: Returning %s\n",
763                 kdc_str ));
764
765         result = kdc_str;
766 fail:
767         SAFE_FREE(ip_srv_site);
768         SAFE_FREE(ip_srv_nonsite);
769         TALLOC_FREE(frame);
770         return result;
771 }
772
773 /************************************************************************
774  Create  a specific krb5.conf file in the private directory pointing
775  at a specific kdc for a realm. Keyed off domain name. Sets
776  KRB5_CONFIG environment variable to point to this file. Must be
777  run as root or will fail (which is a good thing :-).
778 ************************************************************************/
779
780 bool create_local_private_krb5_conf_for_domain(const char *realm,
781                                                 const char *domain,
782                                                 const char *sitename,
783                                                 const struct sockaddr_storage *pss)
784 {
785         char *dname;
786         char *tmpname = NULL;
787         char *fname = NULL;
788         char *file_contents = NULL;
789         char *kdc_ip_string = NULL;
790         size_t flen = 0;
791         ssize_t ret;
792         int fd;
793         char *realm_upper = NULL;
794         bool result = false;
795         char *aes_enctypes = NULL;
796         mode_t mask;
797
798         if (!lp_create_krb5_conf()) {
799                 return false;
800         }
801
802         if (realm == NULL) {
803                 DEBUG(0, ("No realm has been specified! Do you really want to "
804                           "join an Active Directory server?\n"));
805                 return false;
806         }
807
808         if (domain == NULL || pss == NULL) {
809                 return false;
810         }
811
812         dname = lock_path("smb_krb5");
813         if (!dname) {
814                 return false;
815         }
816         if ((mkdir(dname, 0755)==-1) && (errno != EEXIST)) {
817                 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
818                         "failed to create directory %s. Error was %s\n",
819                         dname, strerror(errno) ));
820                 goto done;
821         }
822
823         tmpname = lock_path("smb_tmp_krb5.XXXXXX");
824         if (!tmpname) {
825                 goto done;
826         }
827
828         fname = talloc_asprintf(dname, "%s/krb5.conf.%s", dname, domain);
829         if (!fname) {
830                 goto done;
831         }
832
833         DEBUG(10,("create_local_private_krb5_conf_for_domain: fname = %s, realm = %s, domain = %s\n",
834                 fname, realm, domain ));
835
836         realm_upper = talloc_strdup(fname, realm);
837         if (!strupper_m(realm_upper)) {
838                 goto done;
839         }
840
841         kdc_ip_string = get_kdc_ip_string(dname, realm, sitename, pss);
842         if (!kdc_ip_string) {
843                 goto done;
844         }
845
846         aes_enctypes = talloc_strdup(fname, "");
847         if (aes_enctypes == NULL) {
848                 goto done;
849         }
850
851 #ifdef HAVE_ENCTYPE_AES256_CTS_HMAC_SHA1_96
852         aes_enctypes = talloc_asprintf_append(aes_enctypes, "%s", "aes256-cts-hmac-sha1-96 ");
853         if (aes_enctypes == NULL) {
854                 goto done;
855         }
856 #endif
857 #ifdef HAVE_ENCTYPE_AES128_CTS_HMAC_SHA1_96
858         aes_enctypes = talloc_asprintf_append(aes_enctypes, "%s", "aes128-cts-hmac-sha1-96");
859         if (aes_enctypes == NULL) {
860                 goto done;
861         }
862 #endif
863
864         file_contents = talloc_asprintf(fname,
865                                         "[libdefaults]\n\tdefault_realm = %s\n"
866                                         "\tdefault_tgs_enctypes = %s RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
867                                         "\tdefault_tkt_enctypes = %s RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
868                                         "\tpreferred_enctypes = %s RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n\n"
869                                         "[realms]\n\t%s = {\n"
870                                         "\t%s\t}\n",
871                                         realm_upper, aes_enctypes, aes_enctypes, aes_enctypes,
872                                         realm_upper, kdc_ip_string);
873
874         if (!file_contents) {
875                 goto done;
876         }
877
878         flen = strlen(file_contents);
879
880         mask = umask(S_IRWXO | S_IRWXG);
881         fd = mkstemp(tmpname);
882         umask(mask);
883         if (fd == -1) {
884                 DEBUG(0,("create_local_private_krb5_conf_for_domain: smb_mkstemp failed,"
885                         " for file %s. Errno %s\n",
886                         tmpname, strerror(errno) ));
887                 goto done;
888         }
889
890         if (fchmod(fd, 0644)==-1) {
891                 DEBUG(0,("create_local_private_krb5_conf_for_domain: fchmod failed for %s."
892                         " Errno %s\n",
893                         tmpname, strerror(errno) ));
894                 unlink(tmpname);
895                 close(fd);
896                 goto done;
897         }
898
899         ret = write(fd, file_contents, flen);
900         if (flen != ret) {
901                 DEBUG(0,("create_local_private_krb5_conf_for_domain: write failed,"
902                         " returned %d (should be %u). Errno %s\n",
903                         (int)ret, (unsigned int)flen, strerror(errno) ));
904                 unlink(tmpname);
905                 close(fd);
906                 goto done;
907         }
908         if (close(fd)==-1) {
909                 DEBUG(0,("create_local_private_krb5_conf_for_domain: close failed."
910                         " Errno %s\n", strerror(errno) ));
911                 unlink(tmpname);
912                 goto done;
913         }
914
915         if (rename(tmpname, fname) == -1) {
916                 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
917                         "of %s to %s failed. Errno %s\n",
918                         tmpname, fname, strerror(errno) ));
919                 unlink(tmpname);
920                 goto done;
921         }
922
923         DEBUG(5,("create_local_private_krb5_conf_for_domain: wrote "
924                 "file %s with realm %s KDC list = %s\n",
925                 fname, realm_upper, kdc_ip_string));
926
927         /* Set the environment variable to this file. */
928         setenv("KRB5_CONFIG", fname, 1);
929
930         result = true;
931
932 #if defined(OVERWRITE_SYSTEM_KRB5_CONF)
933
934 #define SYSTEM_KRB5_CONF_PATH "/etc/krb5.conf"
935         /* Insanity, sheer insanity..... */
936
937         if (strequal(realm, lp_realm())) {
938                 SMB_STRUCT_STAT sbuf;
939
940                 if (sys_lstat(SYSTEM_KRB5_CONF_PATH, &sbuf, false) == 0) {
941                         if (S_ISLNK(sbuf.st_ex_mode) && sbuf.st_ex_size) {
942                                 int lret;
943                                 size_t alloc_size = sbuf.st_ex_size + 1;
944                                 char *linkpath = talloc_array(talloc_tos(), char,
945                                                 alloc_size);
946                                 if (!linkpath) {
947                                         goto done;
948                                 }
949                                 lret = readlink(SYSTEM_KRB5_CONF_PATH, linkpath,
950                                                 alloc_size - 1);
951                                 if (lret == -1) {
952                                         TALLOC_FREE(linkpath);
953                                         goto done;
954                                 }
955                                 linkpath[lret] = '\0';
956
957                                 if (strcmp(linkpath, fname) == 0) {
958                                         /* Symlink already exists. */
959                                         TALLOC_FREE(linkpath);
960                                         goto done;
961                                 }
962                                 TALLOC_FREE(linkpath);
963                         }
964                 }
965
966                 /* Try and replace with a symlink. */
967                 if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
968                         const char *newpath = SYSTEM_KRB5_CONF_PATH ".saved";
969                         if (errno != EEXIST) {
970                                 DEBUG(0,("create_local_private_krb5_conf_for_domain: symlink "
971                                         "of %s to %s failed. Errno %s\n",
972                                         fname, SYSTEM_KRB5_CONF_PATH, strerror(errno) ));
973                                 goto done; /* Not a fatal error. */
974                         }
975
976                         /* Yes, this is a race conditon... too bad. */
977                         if (rename(SYSTEM_KRB5_CONF_PATH, newpath) == -1) {
978                                 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
979                                         "of %s to %s failed. Errno %s\n",
980                                         SYSTEM_KRB5_CONF_PATH, newpath,
981                                         strerror(errno) ));
982                                 goto done; /* Not a fatal error. */
983                         }
984
985                         if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
986                                 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
987                                         "forced symlink of %s to /etc/krb5.conf failed. Errno %s\n",
988                                         fname, strerror(errno) ));
989                                 goto done; /* Not a fatal error. */
990                         }
991                 }
992         }
993 #endif
994
995 done:
996         TALLOC_FREE(tmpname);
997         TALLOC_FREE(dname);
998
999         return result;
1000 }
1001 #endif