Fix bug #7079 - cliconnect gets realm wrong with trusted domains.
[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 "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 {
720         char *kdc_str = NULL;
721
722         if (pss->ss_family == AF_INET) {
723                 kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
724                                         prev_line,
725                                         print_canonical_sockaddr(mem_ctx, pss));
726         } else {
727                 char addr[INET6_ADDRSTRLEN];
728                 uint16_t port = get_sockaddr_port(pss);
729
730                 if (port != 0 && port != DEFAULT_KRB5_PORT) {
731                         /* Currently for IPv6 we can't specify a non-default
732                            krb5 port with an address, as this requires a ':'.
733                            Resolve to a name. */
734                         char hostname[MAX_DNS_NAME_LENGTH];
735                         int ret = sys_getnameinfo((const struct sockaddr *)pss,
736                                         sizeof(*pss),
737                                         hostname, sizeof(hostname),
738                                         NULL, 0,
739                                         NI_NAMEREQD);
740                         if (ret) {
741                                 DEBUG(0,("print_kdc_line: can't resolve name "
742                                         "for kdc with non-default port %s. "
743                                         "Error %s\n.",
744                                         print_canonical_sockaddr(mem_ctx, pss),
745                                         gai_strerror(ret)));
746                         }
747                         /* Success, use host:port */
748                         kdc_str = talloc_asprintf(mem_ctx,
749                                         "%s\tkdc = %s:%u\n",
750                                         prev_line,
751                                         hostname,
752                                         (unsigned int)port);
753                 } else {
754                         kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
755                                         prev_line,
756                                         print_sockaddr(addr,
757                                                 sizeof(addr),
758                                                 pss));
759                 }
760         }
761         return kdc_str;
762 }
763
764 /************************************************************************
765  Create a string list of available kdc's, possibly searching by sitename.
766  Does DNS queries.
767
768  If "sitename" is given, the DC's in that site are listed first.
769
770 ************************************************************************/
771
772 static char *get_kdc_ip_string(char *mem_ctx,
773                 const char *realm,
774                 const char *sitename,
775                 struct sockaddr_storage *pss)
776 {
777         int i;
778         struct ip_service *ip_srv_site = NULL;
779         struct ip_service *ip_srv_nonsite = NULL;
780         int count_site = 0;
781         int count_nonsite;
782         char *kdc_str = print_kdc_line(mem_ctx, "", pss);
783
784         if (kdc_str == NULL) {
785                 return NULL;
786         }
787
788         /*
789          * First get the KDC's only in this site, the rest will be
790          * appended later
791          */
792
793         if (sitename) {
794
795                 get_kdc_list(realm, sitename, &ip_srv_site, &count_site);
796
797                 for (i = 0; i < count_site; i++) {
798                         if (sockaddr_equal((struct sockaddr *)&ip_srv_site[i].ss,
799                                                    (struct sockaddr *)pss)) {
800                                 continue;
801                         }
802                         /* Append to the string - inefficient
803                          * but not done often. */
804                         kdc_str = print_kdc_line(mem_ctx,
805                                                 kdc_str,
806                                                 &ip_srv_site[i].ss);
807                         if (!kdc_str) {
808                                 SAFE_FREE(ip_srv_site);
809                                 return NULL;
810                         }
811                 }
812         }
813
814         /* Get all KDC's. */
815
816         get_kdc_list(realm, NULL, &ip_srv_nonsite, &count_nonsite);
817
818         for (i = 0; i < count_nonsite; i++) {
819                 int j;
820
821                 if (sockaddr_equal((struct sockaddr *)&ip_srv_nonsite[i].ss, (struct sockaddr *)pss)) {
822                         continue;
823                 }
824
825                 /* Ensure this isn't an IP already seen (YUK! this is n*n....) */
826                 for (j = 0; j < count_site; j++) {
827                         if (sockaddr_equal((struct sockaddr *)&ip_srv_nonsite[i].ss,
828                                                 (struct sockaddr *)&ip_srv_site[j].ss)) {
829                                 break;
830                         }
831                         /* As the lists are sorted we can break early if nonsite > site. */
832                         if (ip_service_compare(&ip_srv_nonsite[i], &ip_srv_site[j]) > 0) {
833                                 break;
834                         }
835                 }
836                 if (j != i) {
837                         continue;
838                 }
839
840                 /* Append to the string - inefficient but not done often. */
841                 kdc_str = print_kdc_line(mem_ctx,
842                                 kdc_str,
843                                 &ip_srv_nonsite[i].ss);
844                 if (!kdc_str) {
845                         SAFE_FREE(ip_srv_site);
846                         SAFE_FREE(ip_srv_nonsite);
847                         return NULL;
848                 }
849         }
850
851
852         SAFE_FREE(ip_srv_site);
853         SAFE_FREE(ip_srv_nonsite);
854
855         DEBUG(10,("get_kdc_ip_string: Returning %s\n",
856                 kdc_str ));
857
858         return kdc_str;
859 }
860
861 /************************************************************************
862  Create  a specific krb5.conf file in the private directory pointing
863  at a specific kdc for a realm. Keyed off domain name. Sets
864  KRB5_CONFIG environment variable to point to this file. Must be
865  run as root or will fail (which is a good thing :-).
866 ************************************************************************/
867
868 bool create_local_private_krb5_conf_for_domain(const char *realm,
869                                                 const char *domain,
870                                                 const char *sitename,
871                                                 struct sockaddr_storage *pss)
872 {
873         char *dname;
874         char *tmpname = NULL;
875         char *fname = NULL;
876         char *file_contents = NULL;
877         char *kdc_ip_string = NULL;
878         size_t flen = 0;
879         ssize_t ret;
880         int fd;
881         char *realm_upper = NULL;
882         bool result = false;
883
884         if (!lp_create_krb5_conf()) {
885                 return false;
886         }
887
888         dname = lock_path("smb_krb5");
889         if (!dname) {
890                 return false;
891         }
892         if ((mkdir(dname, 0755)==-1) && (errno != EEXIST)) {
893                 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
894                         "failed to create directory %s. Error was %s\n",
895                         dname, strerror(errno) ));
896                 goto done;
897         }
898
899         tmpname = lock_path("smb_tmp_krb5.XXXXXX");
900         if (!tmpname) {
901                 goto done;
902         }
903
904         fname = talloc_asprintf(dname, "%s/krb5.conf.%s", dname, domain);
905         if (!fname) {
906                 goto done;
907         }
908
909         DEBUG(10,("create_local_private_krb5_conf_for_domain: fname = %s, realm = %s, domain = %s\n",
910                 fname, realm, domain ));
911
912         realm_upper = talloc_strdup(fname, realm);
913         strupper_m(realm_upper);
914
915         kdc_ip_string = get_kdc_ip_string(dname, realm, sitename, pss);
916         if (!kdc_ip_string) {
917                 goto done;
918         }
919
920         file_contents = talloc_asprintf(fname,
921                                         "[libdefaults]\n\tdefault_realm = %s\n"
922                                         "\tdefault_tgs_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
923                                         "\tdefault_tkt_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
924                                         "\tpreferred_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n\n"
925                                         "[realms]\n\t%s = {\n"
926                                         "\t%s\t}\n",
927                                         realm_upper, realm_upper, kdc_ip_string);
928
929         if (!file_contents) {
930                 goto done;
931         }
932
933         flen = strlen(file_contents);
934
935         fd = mkstemp(tmpname);
936         if (fd == -1) {
937                 DEBUG(0,("create_local_private_krb5_conf_for_domain: smb_mkstemp failed,"
938                         " for file %s. Errno %s\n",
939                         tmpname, strerror(errno) ));
940                 goto done;
941         }
942
943         if (fchmod(fd, 0644)==-1) {
944                 DEBUG(0,("create_local_private_krb5_conf_for_domain: fchmod failed for %s."
945                         " Errno %s\n",
946                         tmpname, strerror(errno) ));
947                 unlink(tmpname);
948                 close(fd);
949                 goto done;
950         }
951
952         ret = write(fd, file_contents, flen);
953         if (flen != ret) {
954                 DEBUG(0,("create_local_private_krb5_conf_for_domain: write failed,"
955                         " returned %d (should be %u). Errno %s\n",
956                         (int)ret, (unsigned int)flen, strerror(errno) ));
957                 unlink(tmpname);
958                 close(fd);
959                 goto done;
960         }
961         if (close(fd)==-1) {
962                 DEBUG(0,("create_local_private_krb5_conf_for_domain: close failed."
963                         " Errno %s\n", strerror(errno) ));
964                 unlink(tmpname);
965                 goto done;
966         }
967
968         if (rename(tmpname, fname) == -1) {
969                 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
970                         "of %s to %s failed. Errno %s\n",
971                         tmpname, fname, strerror(errno) ));
972                 unlink(tmpname);
973                 goto done;
974         }
975
976         DEBUG(5,("create_local_private_krb5_conf_for_domain: wrote "
977                 "file %s with realm %s KDC list = %s\n",
978                 fname, realm_upper, kdc_ip_string));
979
980         /* Set the environment variable to this file. */
981         setenv("KRB5_CONFIG", fname, 1);
982
983         result = true;
984
985 #if defined(OVERWRITE_SYSTEM_KRB5_CONF)
986
987 #define SYSTEM_KRB5_CONF_PATH "/etc/krb5.conf"
988         /* Insanity, sheer insanity..... */
989
990         if (strequal(realm, lp_realm())) {
991                 char linkpath[PATH_MAX+1];
992                 int lret;
993
994                 lret = readlink(SYSTEM_KRB5_CONF_PATH, linkpath, sizeof(linkpath)-1);
995                 if (lret != -1) {
996                         linkpath[lret] = '\0';
997                 }
998
999                 if (lret != -1 || strcmp(linkpath, fname) == 0) {
1000                         /* Symlink already exists. */
1001                         goto done;
1002                 }
1003
1004                 /* Try and replace with a symlink. */
1005                 if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
1006                         const char *newpath = SYSTEM_KRB5_CONF_PATH ## ".saved";
1007                         if (errno != EEXIST) {
1008                                 DEBUG(0,("create_local_private_krb5_conf_for_domain: symlink "
1009                                         "of %s to %s failed. Errno %s\n",
1010                                         fname, SYSTEM_KRB5_CONF_PATH, strerror(errno) ));
1011                                 goto done; /* Not a fatal error. */
1012                         }
1013
1014                         /* Yes, this is a race conditon... too bad. */
1015                         if (rename(SYSTEM_KRB5_CONF_PATH, newpath) == -1) {
1016                                 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
1017                                         "of %s to %s failed. Errno %s\n",
1018                                         SYSTEM_KRB5_CONF_PATH, newpath,
1019                                         strerror(errno) ));
1020                                 goto done; /* Not a fatal error. */
1021                         }
1022
1023                         if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
1024                                 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
1025                                         "forced symlink of %s to /etc/krb5.conf failed. Errno %s\n",
1026                                         fname, strerror(errno) ));
1027                                 goto done; /* Not a fatal error. */
1028                         }
1029                 }
1030         }
1031 #endif
1032
1033 done:
1034         TALLOC_FREE(tmpname);
1035         TALLOC_FREE(dname);
1036
1037         return result;
1038 }
1039 #endif