s3: only use netlogon/nbt header when needed.
[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 #include "../librpc/gen_ndr/ndr_misc.h"
27
28 #ifdef HAVE_KRB5
29
30 #define DEFAULT_KRB5_PORT 88
31
32 #define LIBADS_CCACHE_NAME "MEMORY:libads"
33
34 /*
35   we use a prompter to avoid a crash bug in the kerberos libs when 
36   dealing with empty passwords
37   this prompter is just a string copy ...
38 */
39 static krb5_error_code 
40 kerb_prompter(krb5_context ctx, void *data,
41                const char *name,
42                const char *banner,
43                int num_prompts,
44                krb5_prompt prompts[])
45 {
46         if (num_prompts == 0) return 0;
47
48         memset(prompts[0].reply->data, '\0', prompts[0].reply->length);
49         if (prompts[0].reply->length > 0) {
50                 if (data) {
51                         strncpy((char *)prompts[0].reply->data, (const char *)data,
52                                 prompts[0].reply->length-1);
53                         prompts[0].reply->length = strlen((const char *)prompts[0].reply->data);
54                 } else {
55                         prompts[0].reply->length = 0;
56                 }
57         }
58         return 0;
59 }
60
61  static bool smb_krb5_get_ntstatus_from_krb5_error(krb5_error *error,
62                                                    NTSTATUS *nt_status)
63 {
64         DATA_BLOB edata;
65         DATA_BLOB unwrapped_edata;
66         TALLOC_CTX *mem_ctx;
67         struct KRB5_EDATA_NTSTATUS parsed_edata;
68         enum ndr_err_code ndr_err;
69
70 #ifdef HAVE_E_DATA_POINTER_IN_KRB5_ERROR
71         edata = data_blob(error->e_data->data, error->e_data->length);
72 #else
73         edata = data_blob(error->e_data.data, error->e_data.length);
74 #endif /* HAVE_E_DATA_POINTER_IN_KRB5_ERROR */
75
76 #ifdef DEVELOPER
77         dump_data(10, edata.data, edata.length);
78 #endif /* DEVELOPER */
79
80         mem_ctx = talloc_init("smb_krb5_get_ntstatus_from_krb5_error");
81         if (mem_ctx == NULL) {
82                 data_blob_free(&edata);
83                 return False;
84         }
85
86         if (!unwrap_edata_ntstatus(mem_ctx, &edata, &unwrapped_edata)) {
87                 data_blob_free(&edata);
88                 TALLOC_FREE(mem_ctx);
89                 return False;
90         }
91
92         data_blob_free(&edata);
93
94         ndr_err = ndr_pull_struct_blob_all(&unwrapped_edata, mem_ctx, 
95                 &parsed_edata, (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                 DEBUG(10,("print_kdc_line: IPv6 case for kdc_name: %s, port: %d\n",
732                         kdc_name, port));
733
734                 if (port != 0 && port != DEFAULT_KRB5_PORT) {
735                         /* Currently for IPv6 we can't specify a non-default
736                            krb5 port with an address, as this requires a ':'.
737                            Resolve to a name. */
738                         char hostname[MAX_DNS_NAME_LENGTH];
739                         int ret = sys_getnameinfo((const struct sockaddr *)pss,
740                                         sizeof(*pss),
741                                         hostname, sizeof(hostname),
742                                         NULL, 0,
743                                         NI_NAMEREQD);
744                         if (ret) {
745                                 DEBUG(0,("print_kdc_line: can't resolve name "
746                                         "for kdc with non-default port %s. "
747                                         "Error %s\n.",
748                                         print_canonical_sockaddr(mem_ctx, pss),
749                                         gai_strerror(ret)));
750                                 return NULL;
751                         }
752                         /* Success, use host:port */
753                         kdc_str = talloc_asprintf(mem_ctx,
754                                         "%s\tkdc = %s:%u\n",
755                                         prev_line,
756                                         hostname,
757                                         (unsigned int)port);
758                 } else {
759
760                         /* no krb5 lib currently supports "kdc = ipv6 address"
761                          * at all, so just fill in just the kdc_name if we have
762                          * it and let the krb5 lib figure out the appropriate
763                          * ipv6 address - gd */
764
765                         if (kdc_name) {
766                                 kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
767                                                 prev_line, kdc_name);
768                         } else {
769                                 kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
770                                                 prev_line,
771                                                 print_sockaddr(addr,
772                                                         sizeof(addr),
773                                                         pss));
774                         }
775                 }
776         }
777         return kdc_str;
778 }
779
780 /************************************************************************
781  Create a string list of available kdc's, possibly searching by sitename.
782  Does DNS queries.
783
784  If "sitename" is given, the DC's in that site are listed first.
785
786 ************************************************************************/
787
788 static char *get_kdc_ip_string(char *mem_ctx,
789                 const char *realm,
790                 const char *sitename,
791                 struct sockaddr_storage *pss,
792                 const char *kdc_name)
793 {
794         int i;
795         struct ip_service *ip_srv_site = NULL;
796         struct ip_service *ip_srv_nonsite = NULL;
797         int count_site = 0;
798         int count_nonsite;
799         char *kdc_str = print_kdc_line(mem_ctx, "", pss, kdc_name);
800
801         if (kdc_str == NULL) {
802                 return NULL;
803         }
804
805         /*
806          * First get the KDC's only in this site, the rest will be
807          * appended later
808          */
809
810         if (sitename) {
811
812                 get_kdc_list(realm, sitename, &ip_srv_site, &count_site);
813
814                 for (i = 0; i < count_site; i++) {
815                         if (sockaddr_equal((struct sockaddr *)&ip_srv_site[i].ss,
816                                                    (struct sockaddr *)pss)) {
817                                 continue;
818                         }
819                         /* Append to the string - inefficient
820                          * but not done often. */
821                         kdc_str = print_kdc_line(mem_ctx,
822                                                 kdc_str,
823                                                 &ip_srv_site[i].ss,
824                                                 NULL);
825                         if (!kdc_str) {
826                                 SAFE_FREE(ip_srv_site);
827                                 return NULL;
828                         }
829                 }
830         }
831
832         /* Get all KDC's. */
833
834         get_kdc_list(realm, NULL, &ip_srv_nonsite, &count_nonsite);
835
836         for (i = 0; i < count_nonsite; i++) {
837                 int j;
838
839                 if (sockaddr_equal((struct sockaddr *)&ip_srv_nonsite[i].ss, (struct sockaddr *)pss)) {
840                         continue;
841                 }
842
843                 /* Ensure this isn't an IP already seen (YUK! this is n*n....) */
844                 for (j = 0; j < count_site; j++) {
845                         if (sockaddr_equal((struct sockaddr *)&ip_srv_nonsite[i].ss,
846                                                 (struct sockaddr *)&ip_srv_site[j].ss)) {
847                                 break;
848                         }
849                         /* As the lists are sorted we can break early if nonsite > site. */
850                         if (ip_service_compare(&ip_srv_nonsite[i], &ip_srv_site[j]) > 0) {
851                                 break;
852                         }
853                 }
854                 if (j != i) {
855                         continue;
856                 }
857
858                 /* Append to the string - inefficient but not done often. */
859                 kdc_str = print_kdc_line(mem_ctx,
860                                 kdc_str,
861                                 &ip_srv_nonsite[i].ss,
862                                 NULL);
863                 if (!kdc_str) {
864                         SAFE_FREE(ip_srv_site);
865                         SAFE_FREE(ip_srv_nonsite);
866                         return NULL;
867                 }
868         }
869
870
871         SAFE_FREE(ip_srv_site);
872         SAFE_FREE(ip_srv_nonsite);
873
874         DEBUG(10,("get_kdc_ip_string: Returning %s\n",
875                 kdc_str ));
876
877         return kdc_str;
878 }
879
880 /************************************************************************
881  Create  a specific krb5.conf file in the private directory pointing
882  at a specific kdc for a realm. Keyed off domain name. Sets
883  KRB5_CONFIG environment variable to point to this file. Must be
884  run as root or will fail (which is a good thing :-).
885 ************************************************************************/
886
887 bool create_local_private_krb5_conf_for_domain(const char *realm,
888                                                 const char *domain,
889                                                 const char *sitename,
890                                                 struct sockaddr_storage *pss,
891                                                 const char *kdc_name)
892 {
893         char *dname;
894         char *tmpname = NULL;
895         char *fname = NULL;
896         char *file_contents = NULL;
897         char *kdc_ip_string = NULL;
898         size_t flen = 0;
899         ssize_t ret;
900         int fd;
901         char *realm_upper = NULL;
902         bool result = false;
903
904         if (!lp_create_krb5_conf()) {
905                 return false;
906         }
907
908         dname = lock_path("smb_krb5");
909         if (!dname) {
910                 return false;
911         }
912         if ((mkdir(dname, 0755)==-1) && (errno != EEXIST)) {
913                 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
914                         "failed to create directory %s. Error was %s\n",
915                         dname, strerror(errno) ));
916                 goto done;
917         }
918
919         tmpname = lock_path("smb_tmp_krb5.XXXXXX");
920         if (!tmpname) {
921                 goto done;
922         }
923
924         fname = talloc_asprintf(dname, "%s/krb5.conf.%s", dname, domain);
925         if (!fname) {
926                 goto done;
927         }
928
929         DEBUG(10,("create_local_private_krb5_conf_for_domain: fname = %s, realm = %s, domain = %s\n",
930                 fname, realm, domain ));
931
932         realm_upper = talloc_strdup(fname, realm);
933         strupper_m(realm_upper);
934
935         kdc_ip_string = get_kdc_ip_string(dname, realm, sitename, pss, kdc_name);
936         if (!kdc_ip_string) {
937                 goto done;
938         }
939
940         file_contents = talloc_asprintf(fname,
941                                         "[libdefaults]\n\tdefault_realm = %s\n"
942                                         "\tdefault_tgs_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
943                                         "\tdefault_tkt_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
944                                         "\tpreferred_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n\n"
945                                         "[realms]\n\t%s = {\n"
946                                         "\t%s\t}\n",
947                                         realm_upper, realm_upper, kdc_ip_string);
948
949         if (!file_contents) {
950                 goto done;
951         }
952
953         flen = strlen(file_contents);
954
955         fd = mkstemp(tmpname);
956         if (fd == -1) {
957                 DEBUG(0,("create_local_private_krb5_conf_for_domain: smb_mkstemp failed,"
958                         " for file %s. Errno %s\n",
959                         tmpname, strerror(errno) ));
960                 goto done;
961         }
962
963         if (fchmod(fd, 0644)==-1) {
964                 DEBUG(0,("create_local_private_krb5_conf_for_domain: fchmod failed for %s."
965                         " Errno %s\n",
966                         tmpname, strerror(errno) ));
967                 unlink(tmpname);
968                 close(fd);
969                 goto done;
970         }
971
972         ret = write(fd, file_contents, flen);
973         if (flen != ret) {
974                 DEBUG(0,("create_local_private_krb5_conf_for_domain: write failed,"
975                         " returned %d (should be %u). Errno %s\n",
976                         (int)ret, (unsigned int)flen, strerror(errno) ));
977                 unlink(tmpname);
978                 close(fd);
979                 goto done;
980         }
981         if (close(fd)==-1) {
982                 DEBUG(0,("create_local_private_krb5_conf_for_domain: close failed."
983                         " Errno %s\n", strerror(errno) ));
984                 unlink(tmpname);
985                 goto done;
986         }
987
988         if (rename(tmpname, fname) == -1) {
989                 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
990                         "of %s to %s failed. Errno %s\n",
991                         tmpname, fname, strerror(errno) ));
992                 unlink(tmpname);
993                 goto done;
994         }
995
996         DEBUG(5,("create_local_private_krb5_conf_for_domain: wrote "
997                 "file %s with realm %s KDC list = %s\n",
998                 fname, realm_upper, kdc_ip_string));
999
1000         /* Set the environment variable to this file. */
1001         setenv("KRB5_CONFIG", fname, 1);
1002
1003         result = true;
1004
1005 #if defined(OVERWRITE_SYSTEM_KRB5_CONF)
1006
1007 #define SYSTEM_KRB5_CONF_PATH "/etc/krb5.conf"
1008         /* Insanity, sheer insanity..... */
1009
1010         if (strequal(realm, lp_realm())) {
1011                 char linkpath[PATH_MAX+1];
1012                 int lret;
1013
1014                 lret = readlink(SYSTEM_KRB5_CONF_PATH, linkpath, sizeof(linkpath)-1);
1015                 if (lret != -1) {
1016                         linkpath[lret] = '\0';
1017                 }
1018
1019                 if (lret != -1 || strcmp(linkpath, fname) == 0) {
1020                         /* Symlink already exists. */
1021                         goto done;
1022                 }
1023
1024                 /* Try and replace with a symlink. */
1025                 if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
1026                         const char *newpath = SYSTEM_KRB5_CONF_PATH ## ".saved";
1027                         if (errno != EEXIST) {
1028                                 DEBUG(0,("create_local_private_krb5_conf_for_domain: symlink "
1029                                         "of %s to %s failed. Errno %s\n",
1030                                         fname, SYSTEM_KRB5_CONF_PATH, strerror(errno) ));
1031                                 goto done; /* Not a fatal error. */
1032                         }
1033
1034                         /* Yes, this is a race conditon... too bad. */
1035                         if (rename(SYSTEM_KRB5_CONF_PATH, newpath) == -1) {
1036                                 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
1037                                         "of %s to %s failed. Errno %s\n",
1038                                         SYSTEM_KRB5_CONF_PATH, newpath,
1039                                         strerror(errno) ));
1040                                 goto done; /* Not a fatal error. */
1041                         }
1042
1043                         if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
1044                                 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
1045                                         "forced symlink of %s to /etc/krb5.conf failed. Errno %s\n",
1046                                         fname, strerror(errno) ));
1047                                 goto done; /* Not a fatal error. */
1048                         }
1049                 }
1050         }
1051 #endif
1052
1053 done:
1054         TALLOC_FREE(tmpname);
1055         TALLOC_FREE(dname);
1056
1057         return result;
1058 }
1059 #endif