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