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