Print principal in debug statement in kerberos_kinit_password() as well.
[Samba/gebeck_regimport.git] / source / libads / kerberos.c
blobe9222e840189b3715c6493451ab7794dd2ef9b77
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.
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.
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.
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/>.
24 #include "includes.h"
26 #ifdef HAVE_KRB5
28 #define LIBADS_CCACHE_NAME "MEMORY:libads"
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 ...
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[])
42 if (num_prompts == 0) return 0;
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;
54 return 0;
57 static bool smb_krb5_err_io_nstatus(TALLOC_CTX *mem_ctx,
58 DATA_BLOB *edata_blob,
59 KRB5_EDATA_NTSTATUS *edata)
61 bool ret = False;
62 prs_struct ps;
64 if (!mem_ctx || !edata_blob || !edata)
65 return False;
67 if (!prs_init(&ps, edata_blob->length, mem_ctx, UNMARSHALL))
68 return False;
70 if (!prs_copy_data_in(&ps, (char *)edata_blob->data, edata_blob->length))
71 goto out;
73 prs_set_offset(&ps, 0);
75 if (!prs_ntstatus("ntstatus", &ps, 1, &edata->ntstatus))
76 goto out;
78 if (!prs_uint32("unknown1", &ps, 1, &edata->unknown1))
79 goto out;
81 if (!prs_uint32("unknown2", &ps, 1, &edata->unknown2)) /* only seen 00000001 here */
82 goto out;
84 ret = True;
85 out:
86 prs_mem_free(&ps);
88 return ret;
91 static bool smb_krb5_get_ntstatus_from_krb5_error(krb5_error *error,
92 NTSTATUS *nt_status)
94 DATA_BLOB edata;
95 DATA_BLOB unwrapped_edata;
96 TALLOC_CTX *mem_ctx;
97 KRB5_EDATA_NTSTATUS parsed_edata;
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 */
105 #ifdef DEVELOPER
106 dump_data(10, edata.data, edata.length);
107 #endif /* DEVELOPER */
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;
115 if (!unwrap_edata_ntstatus(mem_ctx, &edata, &unwrapped_edata)) {
116 data_blob_free(&edata);
117 TALLOC_FREE(mem_ctx);
118 return False;
121 data_blob_free(&edata);
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;
129 data_blob_free(&unwrapped_edata);
131 if (nt_status) {
132 *nt_status = parsed_edata.ntstatus;
135 TALLOC_FREE(mem_ctx);
137 return True;
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)
144 bool ret = False;
145 krb5_error *error = NULL;
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;
154 #endif /* HAVE_KRB5_GET_INIT_CREDS_OPT_GET_ERROR */
156 if (!error) {
157 DEBUG(1,("no krb5_error\n"));
158 return False;
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;
171 ret = smb_krb5_get_ntstatus_from_krb5_error(error, nt_status);
173 krb5_free_error(ctx, error);
175 return ret;
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
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)
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;
202 ZERO_STRUCT(my_creds);
204 initialize_krb5_error_table();
205 if ((code = krb5_init_context(&ctx)))
206 goto out;
208 if (time_offset != 0) {
209 krb5_set_real_time(ctx, time(NULL) + time_offset, 0);
212 DEBUG(10,("kerberos_kinit_password: as %s using [%s] as ccache and config [%s]\n",
213 principal,
214 cache_name ? cache_name: krb5_cc_default_name(ctx),
215 getenv("KRB5_CONFIG")));
217 if ((code = krb5_cc_resolve(ctx, cache_name ? cache_name : krb5_cc_default_name(ctx), &cc))) {
218 goto out;
221 if ((code = smb_krb5_parse_name(ctx, principal, &me))) {
222 goto out;
225 if ((code = smb_krb5_get_init_creds_opt_alloc(ctx, &opt))) {
226 goto out;
229 krb5_get_init_creds_opt_set_renew_life(opt, renewable_time);
230 krb5_get_init_creds_opt_set_forwardable(opt, True);
231 #if 0
232 /* insane testing */
233 krb5_get_init_creds_opt_set_tkt_life(opt, 60);
234 #endif
236 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PAC_REQUEST
237 if (request_pac) {
238 if ((code = krb5_get_init_creds_opt_set_pac_request(ctx, opt, (krb5_boolean)request_pac))) {
239 goto out;
242 #endif
243 if (add_netbios_addr) {
244 if ((code = smb_krb5_gen_netbios_krb5_address(&addr))) {
245 goto out;
247 krb5_get_init_creds_opt_set_address_list(opt, addr->addrs);
250 if ((code = krb5_get_init_creds_password(ctx, &my_creds, me, CONST_DISCARD(char *,password),
251 kerb_prompter, CONST_DISCARD(char *,password),
252 0, NULL, opt))) {
253 goto out;
256 if ((code = krb5_cc_initialize(ctx, cc, me))) {
257 goto out;
260 if ((code = krb5_cc_store_cred(ctx, cc, &my_creds))) {
261 goto out;
264 if (expire_time) {
265 *expire_time = (time_t) my_creds.times.endtime;
268 if (renew_till_time) {
269 *renew_till_time = (time_t) my_creds.times.renew_till;
271 out:
272 if (ntstatus) {
274 NTSTATUS status;
276 /* fast path */
277 if (code == 0) {
278 *ntstatus = NT_STATUS_OK;
279 goto cleanup;
282 /* try to get ntstatus code out of krb5_error when we have it
283 * inside the krb5_get_init_creds_opt - gd */
285 if (opt && smb_krb5_get_ntstatus_from_krb5_error_init_creds_opt(ctx, opt, &status)) {
286 *ntstatus = status;
287 goto cleanup;
290 /* fall back to self-made-mapping */
291 *ntstatus = krb5_to_nt_status(code);
294 cleanup:
295 krb5_free_cred_contents(ctx, &my_creds);
296 if (me) {
297 krb5_free_principal(ctx, me);
299 if (addr) {
300 smb_krb5_free_addresses(ctx, addr);
302 if (opt) {
303 smb_krb5_get_init_creds_opt_free(ctx, opt);
305 if (cc) {
306 krb5_cc_close(ctx, cc);
308 if (ctx) {
309 krb5_free_context(ctx);
311 return code;
316 /* run kinit to setup our ccache */
317 int ads_kinit_password(ADS_STRUCT *ads)
319 char *s;
320 int ret;
321 const char *account_name;
322 fstring acct_name;
324 if ( IS_DC ) {
325 /* this will end up getting a ticket for DOMAIN@RUSTED.REA.LM */
326 account_name = lp_workgroup();
327 } else {
328 /* always use the sAMAccountName for security = domain */
329 /* global_myname()$@REA.LM */
330 if ( lp_security() == SEC_DOMAIN ) {
331 fstr_sprintf( acct_name, "%s$", global_myname() );
332 account_name = acct_name;
334 else
335 /* This looks like host/global_myname()@REA.LM */
336 account_name = ads->auth.user_name;
339 if (asprintf(&s, "%s@%s", account_name, ads->auth.realm) == -1) {
340 return KRB5_CC_NOMEM;
343 if (!ads->auth.password) {
344 SAFE_FREE(s);
345 return KRB5_LIBOS_CANTREADPWD;
348 ret = kerberos_kinit_password_ext(s, ads->auth.password, ads->auth.time_offset,
349 &ads->auth.tgt_expire, NULL, NULL, False, False, ads->auth.renewable,
350 NULL);
352 if (ret) {
353 DEBUG(0,("kerberos_kinit_password %s failed: %s\n",
354 s, error_message(ret)));
356 SAFE_FREE(s);
357 return ret;
360 int ads_kdestroy(const char *cc_name)
362 krb5_error_code code;
363 krb5_context ctx = NULL;
364 krb5_ccache cc = NULL;
366 initialize_krb5_error_table();
367 if ((code = krb5_init_context (&ctx))) {
368 DEBUG(3, ("ads_kdestroy: kdb5_init_context failed: %s\n",
369 error_message(code)));
370 return code;
373 if (!cc_name) {
374 if ((code = krb5_cc_default(ctx, &cc))) {
375 krb5_free_context(ctx);
376 return code;
378 } else {
379 if ((code = krb5_cc_resolve(ctx, cc_name, &cc))) {
380 DEBUG(3, ("ads_kdestroy: krb5_cc_resolve failed: %s\n",
381 error_message(code)));
382 krb5_free_context(ctx);
383 return code;
387 if ((code = krb5_cc_destroy (ctx, cc))) {
388 DEBUG(3, ("ads_kdestroy: krb5_cc_destroy failed: %s\n",
389 error_message(code)));
392 krb5_free_context (ctx);
393 return code;
396 /************************************************************************
397 Routine to fetch the salting principal for a service. Active
398 Directory may use a non-obvious principal name to generate the salt
399 when it determines the key to use for encrypting tickets for a service,
400 and hopefully we detected that when we joined the domain.
401 ************************************************************************/
403 static char *kerberos_secrets_fetch_salting_principal(const char *service, int enctype)
405 char *key = NULL;
406 char *ret = NULL;
408 asprintf(&key, "%s/%s/enctype=%d", SECRETS_SALTING_PRINCIPAL, service, enctype);
409 if (!key) {
410 return NULL;
412 ret = (char *)secrets_fetch(key, NULL);
413 SAFE_FREE(key);
414 return ret;
417 /************************************************************************
418 Return the standard DES salt key
419 ************************************************************************/
421 char* kerberos_standard_des_salt( void )
423 fstring salt;
425 fstr_sprintf( salt, "host/%s.%s@", global_myname(), lp_realm() );
426 strlower_m( salt );
427 fstrcat( salt, lp_realm() );
429 return SMB_STRDUP( salt );
432 /************************************************************************
433 ************************************************************************/
435 static char* des_salt_key( void )
437 char *key;
439 asprintf(&key, "%s/DES/%s", SECRETS_SALTING_PRINCIPAL, lp_realm());
441 return key;
444 /************************************************************************
445 ************************************************************************/
447 bool kerberos_secrets_store_des_salt( const char* salt )
449 char* key;
450 bool ret;
452 if ( (key = des_salt_key()) == NULL ) {
453 DEBUG(0,("kerberos_secrets_store_des_salt: failed to generate key!\n"));
454 return False;
457 if ( !salt ) {
458 DEBUG(8,("kerberos_secrets_store_des_salt: deleting salt\n"));
459 secrets_delete( key );
460 return True;
463 DEBUG(3,("kerberos_secrets_store_des_salt: Storing salt \"%s\"\n", salt));
465 ret = secrets_store( key, salt, strlen(salt)+1 );
467 SAFE_FREE( key );
469 return ret;
472 /************************************************************************
473 ************************************************************************/
475 char* kerberos_secrets_fetch_des_salt( void )
477 char *salt, *key;
479 if ( (key = des_salt_key()) == NULL ) {
480 DEBUG(0,("kerberos_secrets_fetch_des_salt: failed to generate key!\n"));
481 return False;
484 salt = (char*)secrets_fetch( key, NULL );
486 SAFE_FREE( key );
488 return salt;
491 /************************************************************************
492 Routine to get the default realm from the kerberos credentials cache.
493 Caller must free if the return value is not NULL.
494 ************************************************************************/
496 char *kerberos_get_default_realm_from_ccache( void )
498 char *realm = NULL;
499 krb5_context ctx = NULL;
500 krb5_ccache cc = NULL;
501 krb5_principal princ = NULL;
503 initialize_krb5_error_table();
504 if (krb5_init_context(&ctx)) {
505 return NULL;
508 DEBUG(5,("kerberos_get_default_realm_from_ccache: "
509 "Trying to read krb5 cache: %s\n",
510 krb5_cc_default_name(ctx)));
511 if (krb5_cc_default(ctx, &cc)) {
512 DEBUG(0,("kerberos_get_default_realm_from_ccache: "
513 "failed to read default cache\n"));
514 goto out;
516 if (krb5_cc_get_principal(ctx, cc, &princ)) {
517 DEBUG(0,("kerberos_get_default_realm_from_ccache: "
518 "failed to get default principal\n"));
519 goto out;
522 #if defined(HAVE_KRB5_PRINCIPAL_GET_REALM)
523 realm = SMB_STRDUP(krb5_principal_get_realm(ctx, princ));
524 #elif defined(HAVE_KRB5_PRINC_REALM)
526 krb5_data *realm_data = krb5_princ_realm(ctx, princ);
527 realm = SMB_STRNDUP(realm_data->data, realm_data->length);
529 #endif
531 out:
533 if (princ) {
534 krb5_free_principal(ctx, princ);
536 if (cc) {
537 krb5_cc_close(ctx, cc);
539 if (ctx) {
540 krb5_free_context(ctx);
543 return realm;
547 /************************************************************************
548 Routine to get the salting principal for this service. This is
549 maintained for backwards compatibilty with releases prior to 3.0.24.
550 Since we store the salting principal string only at join, we may have
551 to look for the older tdb keys. Caller must free if return is not null.
552 ************************************************************************/
554 krb5_principal kerberos_fetch_salt_princ_for_host_princ(krb5_context context,
555 krb5_principal host_princ,
556 int enctype)
558 char *unparsed_name = NULL, *salt_princ_s = NULL;
559 krb5_principal ret_princ = NULL;
561 /* lookup new key first */
563 if ( (salt_princ_s = kerberos_secrets_fetch_des_salt()) == NULL ) {
565 /* look under the old key. If this fails, just use the standard key */
567 if (smb_krb5_unparse_name(context, host_princ, &unparsed_name) != 0) {
568 return (krb5_principal)NULL;
570 if ((salt_princ_s = kerberos_secrets_fetch_salting_principal(unparsed_name, enctype)) == NULL) {
571 /* fall back to host/machine.realm@REALM */
572 salt_princ_s = kerberos_standard_des_salt();
576 if (smb_krb5_parse_name(context, salt_princ_s, &ret_princ) != 0) {
577 ret_princ = NULL;
580 SAFE_FREE(unparsed_name);
581 SAFE_FREE(salt_princ_s);
583 return ret_princ;
586 /************************************************************************
587 Routine to set the salting principal for this service. Active
588 Directory may use a non-obvious principal name to generate the salt
589 when it determines the key to use for encrypting tickets for a service,
590 and hopefully we detected that when we joined the domain.
591 Setting principal to NULL deletes this entry.
592 ************************************************************************/
594 bool kerberos_secrets_store_salting_principal(const char *service,
595 int enctype,
596 const char *principal)
598 char *key = NULL;
599 bool ret = False;
600 krb5_context context = NULL;
601 krb5_principal princ = NULL;
602 char *princ_s = NULL;
603 char *unparsed_name = NULL;
605 krb5_init_context(&context);
606 if (!context) {
607 return False;
609 if (strchr_m(service, '@')) {
610 asprintf(&princ_s, "%s", service);
611 } else {
612 asprintf(&princ_s, "%s@%s", service, lp_realm());
615 if (smb_krb5_parse_name(context, princ_s, &princ) != 0) {
616 goto out;
619 if (smb_krb5_unparse_name(context, princ, &unparsed_name) != 0) {
620 goto out;
623 asprintf(&key, "%s/%s/enctype=%d", SECRETS_SALTING_PRINCIPAL, unparsed_name, enctype);
624 if (!key) {
625 goto out;
628 if ((principal != NULL) && (strlen(principal) > 0)) {
629 ret = secrets_store(key, principal, strlen(principal) + 1);
630 } else {
631 ret = secrets_delete(key);
634 out:
636 SAFE_FREE(key);
637 SAFE_FREE(princ_s);
638 SAFE_FREE(unparsed_name);
640 if (context) {
641 krb5_free_context(context);
644 return ret;
648 /************************************************************************
649 ************************************************************************/
651 int kerberos_kinit_password(const char *principal,
652 const char *password,
653 int time_offset,
654 const char *cache_name)
656 return kerberos_kinit_password_ext(principal,
657 password,
658 time_offset,
661 cache_name,
662 False,
663 False,
665 NULL);
668 /************************************************************************
669 Create a string list of available kdc's, possibly searching by sitename.
670 Does DNS queries.
671 ************************************************************************/
673 static char *get_kdc_ip_string(char *mem_ctx,
674 const char *realm,
675 const char *sitename,
676 struct sockaddr_storage *pss)
678 int i;
679 struct ip_service *ip_srv_site = NULL;
680 struct ip_service *ip_srv_nonsite;
681 int count_site = 0;
682 int count_nonsite;
683 char *kdc_str = talloc_asprintf(mem_ctx, "\tkdc = %s\n",
684 print_canonical_sockaddr(mem_ctx,
685 pss));
687 if (kdc_str == NULL) {
688 return NULL;
691 /* Get the KDC's only in this site. */
693 if (sitename) {
695 get_kdc_list(realm, sitename, &ip_srv_site, &count_site);
697 for (i = 0; i < count_site; i++) {
698 if (addr_equal(&ip_srv_site[i].ss, pss)) {
699 continue;
701 /* Append to the string - inefficient
702 * but not done often. */
703 kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
704 kdc_str,
705 print_canonical_sockaddr(mem_ctx,
706 &ip_srv_site[i].ss));
707 if (!kdc_str) {
708 SAFE_FREE(ip_srv_site);
709 return NULL;
714 /* Get all KDC's. */
716 get_kdc_list(realm, NULL, &ip_srv_nonsite, &count_nonsite);
718 for (i = 0; i < count_nonsite; i++) {
719 int j;
721 if (addr_equal(&ip_srv_nonsite[i].ss, pss)) {
722 continue;
725 /* Ensure this isn't an IP already seen (YUK! this is n*n....) */
726 for (j = 0; j < count_site; j++) {
727 if (addr_equal(&ip_srv_nonsite[i].ss,
728 &ip_srv_site[j].ss)) {
729 break;
731 /* As the lists are sorted we can break early if nonsite > site. */
732 if (ip_service_compare(&ip_srv_nonsite[i], &ip_srv_site[j]) > 0) {
733 break;
736 if (j != i) {
737 continue;
740 /* Append to the string - inefficient but not done often. */
741 kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
742 kdc_str,
743 print_canonical_sockaddr(mem_ctx,
744 &ip_srv_nonsite[i].ss));
745 if (!kdc_str) {
746 SAFE_FREE(ip_srv_site);
747 SAFE_FREE(ip_srv_nonsite);
748 return NULL;
753 SAFE_FREE(ip_srv_site);
754 SAFE_FREE(ip_srv_nonsite);
756 DEBUG(10,("get_kdc_ip_string: Returning %s\n",
757 kdc_str ));
759 return kdc_str;
762 /************************************************************************
763 Create a specific krb5.conf file in the private directory pointing
764 at a specific kdc for a realm. Keyed off domain name. Sets
765 KRB5_CONFIG environment variable to point to this file. Must be
766 run as root or will fail (which is a good thing :-).
767 ************************************************************************/
769 bool create_local_private_krb5_conf_for_domain(const char *realm,
770 const char *domain,
771 const char *sitename,
772 struct sockaddr_storage *pss)
774 char *dname = talloc_asprintf(NULL, "%s/smb_krb5", lp_lockdir());
775 char *tmpname = NULL;
776 char *fname = NULL;
777 char *file_contents = NULL;
778 char *kdc_ip_string = NULL;
779 size_t flen = 0;
780 ssize_t ret;
781 int fd;
782 char *realm_upper = NULL;
784 if (!dname) {
785 return False;
787 if ((mkdir(dname, 0755)==-1) && (errno != EEXIST)) {
788 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
789 "failed to create directory %s. Error was %s\n",
790 dname, strerror(errno) ));
791 TALLOC_FREE(dname);
792 return False;
795 tmpname = talloc_asprintf(dname, "%s/smb_tmp_krb5.XXXXXX", lp_lockdir());
796 if (!tmpname) {
797 TALLOC_FREE(dname);
798 return False;
801 fname = talloc_asprintf(dname, "%s/krb5.conf.%s", dname, domain);
802 if (!fname) {
803 TALLOC_FREE(dname);
804 return False;
807 DEBUG(10,("create_local_private_krb5_conf_for_domain: fname = %s, realm = %s, domain = %s\n",
808 fname, realm, domain ));
810 realm_upper = talloc_strdup(fname, realm);
811 strupper_m(realm_upper);
813 kdc_ip_string = get_kdc_ip_string(dname, realm, sitename, pss);
814 if (!kdc_ip_string) {
815 TALLOC_FREE(dname);
816 return False;
819 file_contents = talloc_asprintf(fname, "[libdefaults]\n\tdefault_realm = %s\n\n"
820 "[realms]\n\t%s = {\n"
821 "\t%s\t}\n",
822 realm_upper, realm_upper, kdc_ip_string);
824 if (!file_contents) {
825 TALLOC_FREE(dname);
826 return False;
829 flen = strlen(file_contents);
831 fd = smb_mkstemp(tmpname);
832 if (fd == -1) {
833 DEBUG(0,("create_local_private_krb5_conf_for_domain: smb_mkstemp failed,"
834 " for file %s. Errno %s\n",
835 tmpname, strerror(errno) ));
838 if (fchmod(fd, 0644)==-1) {
839 DEBUG(0,("create_local_private_krb5_conf_for_domain: fchmod failed for %s."
840 " Errno %s\n",
841 tmpname, strerror(errno) ));
842 unlink(tmpname);
843 close(fd);
844 TALLOC_FREE(dname);
845 return False;
848 ret = write(fd, file_contents, flen);
849 if (flen != ret) {
850 DEBUG(0,("create_local_private_krb5_conf_for_domain: write failed,"
851 " returned %d (should be %u). Errno %s\n",
852 (int)ret, (unsigned int)flen, strerror(errno) ));
853 unlink(tmpname);
854 close(fd);
855 TALLOC_FREE(dname);
856 return False;
858 if (close(fd)==-1) {
859 DEBUG(0,("create_local_private_krb5_conf_for_domain: close failed."
860 " Errno %s\n", strerror(errno) ));
861 unlink(tmpname);
862 TALLOC_FREE(dname);
863 return False;
866 if (rename(tmpname, fname) == -1) {
867 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
868 "of %s to %s failed. Errno %s\n",
869 tmpname, fname, strerror(errno) ));
870 unlink(tmpname);
871 TALLOC_FREE(dname);
872 return False;
875 DEBUG(5,("create_local_private_krb5_conf_for_domain: wrote "
876 "file %s with realm %s KDC = %s\n",
877 fname, realm_upper, print_canonical_sockaddr(dname, pss) ));
879 /* Set the environment variable to this file. */
880 setenv("KRB5_CONFIG", fname, 1);
882 #if defined(OVERWRITE_SYSTEM_KRB5_CONF)
884 #define SYSTEM_KRB5_CONF_PATH "/etc/krb5.conf"
885 /* Insanity, sheer insanity..... */
887 if (strequal(realm, lp_realm())) {
888 char linkpath[PATH_MAX+1];
889 int lret;
891 lret = readlink(SYSTEM_KRB5_CONF_PATH, linkpath, sizeof(linkpath)-1);
892 if (lret != -1) {
893 linkpath[lret] = '\0';
896 if (lret != -1 || strcmp(linkpath, fname) == 0) {
897 /* Symlink already exists. */
898 TALLOC_FREE(dname);
899 return True;
902 /* Try and replace with a symlink. */
903 if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
904 const char *newpath = SYSTEM_KRB5_CONF_PATH ## ".saved";
905 if (errno != EEXIST) {
906 DEBUG(0,("create_local_private_krb5_conf_for_domain: symlink "
907 "of %s to %s failed. Errno %s\n",
908 fname, SYSTEM_KRB5_CONF_PATH, strerror(errno) ));
909 TALLOC_FREE(dname);
910 return True; /* Not a fatal error. */
913 /* Yes, this is a race conditon... too bad. */
914 if (rename(SYSTEM_KRB5_CONF_PATH, newpath) == -1) {
915 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
916 "of %s to %s failed. Errno %s\n",
917 SYSTEM_KRB5_CONF_PATH, newpath,
918 strerror(errno) ));
919 TALLOC_FREE(dname);
920 return True; /* Not a fatal error. */
923 if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
924 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
925 "forced symlink of %s to /etc/krb5.conf failed. Errno %s\n",
926 fname, strerror(errno) ));
927 TALLOC_FREE(dname);
928 return True; /* Not a fatal error. */
932 #endif
934 TALLOC_FREE(dname);
936 return True;
938 #endif