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