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