ea14350e6bc7f04d95c916118a0611d629e5f993
[samba.git] / source3 / libads / kerberos.c
1 /* 
2    Unix SMB/CIFS implementation.
3    kerberos utility library
4    Copyright (C) Andrew Tridgell 2001
5    Copyright (C) Remus Koos 2001
6    Copyright (C) Nalin Dahyabhai <nalin@redhat.com> 2004.
7    Copyright (C) Jeremy Allison 2004.
8    Copyright (C) Gerald Carter 2006.
9
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 */
23
24 #include "includes.h"
25 #include "system/filesys.h"
26 #include "smb_krb5.h"
27 #include "../librpc/gen_ndr/ndr_misc.h"
28 #include "libads/kerberos_proto.h"
29 #include "libads/cldap.h"
30 #include "secrets.h"
31 #include "../lib/tsocket/tsocket.h"
32
33 #ifdef HAVE_KRB5
34
35 #define 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 static char *get_kdc_ip_string(char *mem_ctx,
619                 const char *realm,
620                 const char *sitename,
621                 const struct sockaddr_storage *pss,
622                 const char *kdc_name)
623 {
624         TALLOC_CTX *frame = talloc_stackframe();
625         int i;
626         struct ip_service *ip_srv_site = NULL;
627         struct ip_service *ip_srv_nonsite = NULL;
628         int count_site = 0;
629         int count_nonsite;
630         int num_dcs;
631         struct sockaddr_storage *dc_addrs;
632         struct tsocket_address **dc_addrs2 = NULL;
633         const struct tsocket_address * const *dc_addrs3 = NULL;
634         char *result = NULL;
635         struct netlogon_samlogon_response **responses = NULL;
636         NTSTATUS status;
637         char *kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n", "",
638                                         print_canonical_sockaddr(mem_ctx, pss));
639
640         if (kdc_str == NULL) {
641                 TALLOC_FREE(frame);
642                 return NULL;
643         }
644
645         /*
646          * First get the KDC's only in this site, the rest will be
647          * appended later
648          */
649
650         if (sitename) {
651                 get_kdc_list(realm, sitename, &ip_srv_site, &count_site);
652         }
653
654         /* Get all KDC's. */
655
656         get_kdc_list(realm, NULL, &ip_srv_nonsite, &count_nonsite);
657
658         dc_addrs = talloc_array(talloc_tos(), struct sockaddr_storage,
659                                 1 + count_site + count_nonsite);
660         if (dc_addrs == NULL) {
661                 goto fail;
662         }
663
664         dc_addrs[0] = *pss;
665         num_dcs = 1;
666
667         for (i=0; i<count_site; i++) {
668                 add_sockaddr_unique(dc_addrs, &num_dcs, &ip_srv_site[i].ss);
669         }
670
671         for (i=0; i<count_nonsite; i++) {
672                 add_sockaddr_unique(dc_addrs, &num_dcs, &ip_srv_nonsite[i].ss);
673         }
674
675         dc_addrs2 = talloc_zero_array(talloc_tos(),
676                                       struct tsocket_address *,
677                                       num_dcs);
678         if (dc_addrs2 == NULL) {
679                 goto fail;
680         }
681
682         for (i=0; i<num_dcs; i++) {
683                 char addr[INET6_ADDRSTRLEN];
684                 int ret;
685
686                 print_sockaddr(addr, sizeof(addr), &dc_addrs[i]);
687
688                 ret = tsocket_address_inet_from_strings(dc_addrs2, "ip",
689                                                         addr, LDAP_PORT,
690                                                         &dc_addrs2[i]);
691                 if (ret != 0) {
692                         status = map_nt_error_from_unix(errno);
693                         DEBUG(2,("Failed to create tsocket_address for %s - %s\n",
694                                  addr, nt_errstr(status)));
695                         goto fail;
696                 }
697         }
698
699         dc_addrs3 = (const struct tsocket_address * const *)dc_addrs2;
700
701         status = cldap_multi_netlogon(talloc_tos(),
702                         dc_addrs3, num_dcs,
703                         realm, lp_netbios_name(),
704                         NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX,
705                         MIN(num_dcs, 3), timeval_current_ofs(3, 0), &responses);
706         TALLOC_FREE(dc_addrs2);
707         dc_addrs3 = NULL;
708
709         if (!NT_STATUS_IS_OK(status)) {
710                 DEBUG(10,("get_kdc_ip_string: cldap_multi_netlogon failed: "
711                           "%s\n", nt_errstr(status)));
712                 goto fail;
713         }
714
715         kdc_str = talloc_strdup(mem_ctx, "");
716         if (kdc_str == NULL) {
717                 goto fail;
718         }
719
720         for (i=0; i<num_dcs; i++) {
721                 char *new_kdc_str;
722
723                 if (responses[i] == NULL) {
724                         continue;
725                 }
726
727                 /* Append to the string - inefficient but not done often. */
728                 new_kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
729                                               kdc_str,
730                                               print_canonical_sockaddr(mem_ctx, &dc_addrs[i]));
731                 if (new_kdc_str == NULL) {
732                         goto fail;
733                 }
734                 TALLOC_FREE(kdc_str);
735                 kdc_str = new_kdc_str;
736         }
737
738         DEBUG(10,("get_kdc_ip_string: Returning %s\n",
739                 kdc_str ));
740
741         result = kdc_str;
742 fail:
743         SAFE_FREE(ip_srv_site);
744         SAFE_FREE(ip_srv_nonsite);
745         TALLOC_FREE(frame);
746         return result;
747 }
748
749 /************************************************************************
750  Create  a specific krb5.conf file in the private directory pointing
751  at a specific kdc for a realm. Keyed off domain name. Sets
752  KRB5_CONFIG environment variable to point to this file. Must be
753  run as root or will fail (which is a good thing :-).
754 ************************************************************************/
755
756 bool create_local_private_krb5_conf_for_domain(const char *realm,
757                                                 const char *domain,
758                                                 const char *sitename,
759                                                 const struct sockaddr_storage *pss,
760                                                 const char *kdc_name)
761 {
762         char *dname;
763         char *tmpname = NULL;
764         char *fname = NULL;
765         char *file_contents = NULL;
766         char *kdc_ip_string = NULL;
767         size_t flen = 0;
768         ssize_t ret;
769         int fd;
770         char *realm_upper = NULL;
771         bool result = false;
772         char *aes_enctypes = NULL;
773         mode_t mask;
774
775         if (!lp_create_krb5_conf()) {
776                 return false;
777         }
778
779         if (realm == NULL) {
780                 DEBUG(0, ("No realm has been specified! Do you really want to "
781                           "join an Active Directory server?\n"));
782                 return false;
783         }
784
785         if (domain == NULL || pss == NULL || kdc_name == NULL) {
786                 return false;
787         }
788
789         dname = lock_path("smb_krb5");
790         if (!dname) {
791                 return false;
792         }
793         if ((mkdir(dname, 0755)==-1) && (errno != EEXIST)) {
794                 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
795                         "failed to create directory %s. Error was %s\n",
796                         dname, strerror(errno) ));
797                 goto done;
798         }
799
800         tmpname = lock_path("smb_tmp_krb5.XXXXXX");
801         if (!tmpname) {
802                 goto done;
803         }
804
805         fname = talloc_asprintf(dname, "%s/krb5.conf.%s", dname, domain);
806         if (!fname) {
807                 goto done;
808         }
809
810         DEBUG(10,("create_local_private_krb5_conf_for_domain: fname = %s, realm = %s, domain = %s\n",
811                 fname, realm, domain ));
812
813         realm_upper = talloc_strdup(fname, realm);
814         if (!strupper_m(realm_upper)) {
815                 goto done;
816         }
817
818         kdc_ip_string = get_kdc_ip_string(dname, realm, sitename, pss, kdc_name);
819         if (!kdc_ip_string) {
820                 goto done;
821         }
822
823         aes_enctypes = talloc_strdup(fname, "");
824         if (aes_enctypes == NULL) {
825                 goto done;
826         }
827
828 #ifdef HAVE_ENCTYPE_AES256_CTS_HMAC_SHA1_96
829         aes_enctypes = talloc_asprintf_append(aes_enctypes, "%s", "aes256-cts-hmac-sha1-96 ");
830         if (aes_enctypes == NULL) {
831                 goto done;
832         }
833 #endif
834 #ifdef HAVE_ENCTYPE_AES128_CTS_HMAC_SHA1_96
835         aes_enctypes = talloc_asprintf_append(aes_enctypes, "%s", "aes128-cts-hmac-sha1-96");
836         if (aes_enctypes == NULL) {
837                 goto done;
838         }
839 #endif
840
841         file_contents = talloc_asprintf(fname,
842                                         "[libdefaults]\n\tdefault_realm = %s\n"
843                                         "\tdefault_tgs_enctypes = %s RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
844                                         "\tdefault_tkt_enctypes = %s RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
845                                         "\tpreferred_enctypes = %s RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n\n"
846                                         "[realms]\n\t%s = {\n"
847                                         "\t%s\t}\n",
848                                         realm_upper, aes_enctypes, aes_enctypes, aes_enctypes,
849                                         realm_upper, kdc_ip_string);
850
851         if (!file_contents) {
852                 goto done;
853         }
854
855         flen = strlen(file_contents);
856
857         mask = umask(S_IRWXO | S_IRWXG);
858         fd = mkstemp(tmpname);
859         umask(mask);
860         if (fd == -1) {
861                 DEBUG(0,("create_local_private_krb5_conf_for_domain: smb_mkstemp failed,"
862                         " for file %s. Errno %s\n",
863                         tmpname, strerror(errno) ));
864                 goto done;
865         }
866
867         if (fchmod(fd, 0644)==-1) {
868                 DEBUG(0,("create_local_private_krb5_conf_for_domain: fchmod failed for %s."
869                         " Errno %s\n",
870                         tmpname, strerror(errno) ));
871                 unlink(tmpname);
872                 close(fd);
873                 goto done;
874         }
875
876         ret = write(fd, file_contents, flen);
877         if (flen != ret) {
878                 DEBUG(0,("create_local_private_krb5_conf_for_domain: write failed,"
879                         " returned %d (should be %u). Errno %s\n",
880                         (int)ret, (unsigned int)flen, strerror(errno) ));
881                 unlink(tmpname);
882                 close(fd);
883                 goto done;
884         }
885         if (close(fd)==-1) {
886                 DEBUG(0,("create_local_private_krb5_conf_for_domain: close failed."
887                         " Errno %s\n", strerror(errno) ));
888                 unlink(tmpname);
889                 goto done;
890         }
891
892         if (rename(tmpname, fname) == -1) {
893                 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
894                         "of %s to %s failed. Errno %s\n",
895                         tmpname, fname, strerror(errno) ));
896                 unlink(tmpname);
897                 goto done;
898         }
899
900         DEBUG(5,("create_local_private_krb5_conf_for_domain: wrote "
901                 "file %s with realm %s KDC list = %s\n",
902                 fname, realm_upper, kdc_ip_string));
903
904         /* Set the environment variable to this file. */
905         setenv("KRB5_CONFIG", fname, 1);
906
907         result = true;
908
909 #if defined(OVERWRITE_SYSTEM_KRB5_CONF)
910
911 #define SYSTEM_KRB5_CONF_PATH "/etc/krb5.conf"
912         /* Insanity, sheer insanity..... */
913
914         if (strequal(realm, lp_realm())) {
915                 SMB_STRUCT_STAT sbuf;
916
917                 if (sys_lstat(SYSTEM_KRB5_CONF_PATH, &sbuf, false) == 0) {
918                         if (S_ISLNK(sbuf.st_ex_mode) && sbuf.st_ex_size) {
919                                 int lret;
920                                 size_t alloc_size = sbuf.st_ex_size + 1;
921                                 char *linkpath = talloc_array(talloc_tos(), char,
922                                                 alloc_size);
923                                 if (!linkpath) {
924                                         goto done;
925                                 }
926                                 lret = readlink(SYSTEM_KRB5_CONF_PATH, linkpath,
927                                                 alloc_size - 1);
928                                 if (lret == -1) {
929                                         TALLOC_FREE(linkpath);
930                                         goto done;
931                                 }
932                                 linkpath[lret] = '\0';
933
934                                 if (strcmp(linkpath, fname) == 0) {
935                                         /* Symlink already exists. */
936                                         TALLOC_FREE(linkpath);
937                                         goto done;
938                                 }
939                                 TALLOC_FREE(linkpath);
940                         }
941                 }
942
943                 /* Try and replace with a symlink. */
944                 if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
945                         const char *newpath = SYSTEM_KRB5_CONF_PATH ".saved";
946                         if (errno != EEXIST) {
947                                 DEBUG(0,("create_local_private_krb5_conf_for_domain: symlink "
948                                         "of %s to %s failed. Errno %s\n",
949                                         fname, SYSTEM_KRB5_CONF_PATH, strerror(errno) ));
950                                 goto done; /* Not a fatal error. */
951                         }
952
953                         /* Yes, this is a race conditon... too bad. */
954                         if (rename(SYSTEM_KRB5_CONF_PATH, newpath) == -1) {
955                                 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
956                                         "of %s to %s failed. Errno %s\n",
957                                         SYSTEM_KRB5_CONF_PATH, newpath,
958                                         strerror(errno) ));
959                                 goto done; /* Not a fatal error. */
960                         }
961
962                         if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
963                                 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
964                                         "forced symlink of %s to /etc/krb5.conf failed. Errno %s\n",
965                                         fname, strerror(errno) ));
966                                 goto done; /* Not a fatal error. */
967                         }
968                 }
969         }
970 #endif
971
972 done:
973         TALLOC_FREE(tmpname);
974         TALLOC_FREE(dname);
975
976         return result;
977 }
978 #endif