While 'data' is usually 0 terminated, nothing in the spec requires that. The correct...
[Samba/bb.git] / source / libads / kerberos.c
blob4fc23956bdef17689263021d2715bedff73bbd62
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: using [%s] as ccache and config [%s]\n",
213 cache_name ? cache_name: krb5_cc_default_name(ctx),
214 getenv("KRB5_CONFIG")));
216 if ((code = krb5_cc_resolve(ctx, cache_name ? cache_name : krb5_cc_default_name(ctx), &cc))) {
217 goto out;
220 if ((code = smb_krb5_parse_name(ctx, principal, &me))) {
221 goto out;
224 if ((code = smb_krb5_get_init_creds_opt_alloc(ctx, &opt))) {
225 goto out;
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
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;
241 #endif
242 if (add_netbios_addr) {
243 if ((code = smb_krb5_gen_netbios_krb5_address(&addr))) {
244 goto out;
246 krb5_get_init_creds_opt_set_address_list(opt, addr->addrs);
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;
255 if ((code = krb5_cc_initialize(ctx, cc, me))) {
256 goto out;
259 if ((code = krb5_cc_store_cred(ctx, cc, &my_creds))) {
260 goto out;
263 if (expire_time) {
264 *expire_time = (time_t) my_creds.times.endtime;
267 if (renew_till_time) {
268 *renew_till_time = (time_t) my_creds.times.renew_till;
270 out:
271 if (ntstatus) {
273 NTSTATUS status;
275 /* fast path */
276 if (code == 0) {
277 *ntstatus = NT_STATUS_OK;
278 goto cleanup;
281 /* try to get ntstatus code out of krb5_error when we have it
282 * inside the krb5_get_init_creds_opt - gd */
284 if (opt && smb_krb5_get_ntstatus_from_krb5_error_init_creds_opt(ctx, opt, &status)) {
285 *ntstatus = status;
286 goto cleanup;
289 /* fall back to self-made-mapping */
290 *ntstatus = krb5_to_nt_status(code);
293 cleanup:
294 krb5_free_cred_contents(ctx, &my_creds);
295 if (me) {
296 krb5_free_principal(ctx, me);
298 if (addr) {
299 smb_krb5_free_addresses(ctx, addr);
301 if (opt) {
302 smb_krb5_get_init_creds_opt_free(ctx, opt);
304 if (cc) {
305 krb5_cc_close(ctx, cc);
307 if (ctx) {
308 krb5_free_context(ctx);
310 return code;
315 /* run kinit to setup our ccache */
316 int ads_kinit_password(ADS_STRUCT *ads)
318 char *s;
319 int ret;
320 const char *account_name;
321 fstring acct_name;
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;
333 else
334 /* This looks like host/global_myname()@REA.LM */
335 account_name = ads->auth.user_name;
338 if (asprintf(&s, "%s@%s", account_name, ads->auth.realm) == -1) {
339 return KRB5_CC_NOMEM;
342 if (!ads->auth.password) {
343 SAFE_FREE(s);
344 return KRB5_LIBOS_CANTREADPWD;
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);
351 if (ret) {
352 DEBUG(0,("kerberos_kinit_password %s failed: %s\n",
353 s, error_message(ret)));
355 SAFE_FREE(s);
356 return ret;
359 int ads_kdestroy(const char *cc_name)
361 krb5_error_code code;
362 krb5_context ctx = NULL;
363 krb5_ccache cc = NULL;
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;
372 if (!cc_name) {
373 if ((code = krb5_cc_default(ctx, &cc))) {
374 krb5_free_context(ctx);
375 return code;
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;
386 if ((code = krb5_cc_destroy (ctx, cc))) {
387 DEBUG(3, ("ads_kdestroy: krb5_cc_destroy failed: %s\n",
388 error_message(code)));
391 krb5_free_context (ctx);
392 return code;
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 ************************************************************************/
402 static char *kerberos_secrets_fetch_salting_principal(const char *service, int enctype)
404 char *key = NULL;
405 char *ret = NULL;
407 asprintf(&key, "%s/%s/enctype=%d", SECRETS_SALTING_PRINCIPAL, service, enctype);
408 if (!key) {
409 return NULL;
411 ret = (char *)secrets_fetch(key, NULL);
412 SAFE_FREE(key);
413 return ret;
416 /************************************************************************
417 Return the standard DES salt key
418 ************************************************************************/
420 char* kerberos_standard_des_salt( void )
422 fstring salt;
424 fstr_sprintf( salt, "host/%s.%s@", global_myname(), lp_realm() );
425 strlower_m( salt );
426 fstrcat( salt, lp_realm() );
428 return SMB_STRDUP( salt );
431 /************************************************************************
432 ************************************************************************/
434 static char* des_salt_key( void )
436 char *key;
438 asprintf(&key, "%s/DES/%s", SECRETS_SALTING_PRINCIPAL, lp_realm());
440 return key;
443 /************************************************************************
444 ************************************************************************/
446 bool kerberos_secrets_store_des_salt( const char* salt )
448 char* key;
449 bool ret;
451 if ( (key = des_salt_key()) == NULL ) {
452 DEBUG(0,("kerberos_secrets_store_des_salt: failed to generate key!\n"));
453 return False;
456 if ( !salt ) {
457 DEBUG(8,("kerberos_secrets_store_des_salt: deleting salt\n"));
458 secrets_delete( key );
459 return True;
462 DEBUG(3,("kerberos_secrets_store_des_salt: Storing salt \"%s\"\n", salt));
464 ret = secrets_store( key, salt, strlen(salt)+1 );
466 SAFE_FREE( key );
468 return ret;
471 /************************************************************************
472 ************************************************************************/
474 char* kerberos_secrets_fetch_des_salt( void )
476 char *salt, *key;
478 if ( (key = des_salt_key()) == NULL ) {
479 DEBUG(0,("kerberos_secrets_fetch_des_salt: failed to generate key!\n"));
480 return False;
483 salt = (char*)secrets_fetch( key, NULL );
485 SAFE_FREE( key );
487 return salt;
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 ************************************************************************/
495 char *kerberos_get_default_realm_from_ccache( void )
497 char *realm = NULL;
498 krb5_context ctx = NULL;
499 krb5_ccache cc = NULL;
500 krb5_principal princ = NULL;
502 initialize_krb5_error_table();
503 if (krb5_init_context(&ctx)) {
504 return NULL;
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;
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;
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)
525 krb5_data *realm_data = krb5_princ_realm(ctx, princ);
526 realm = SMB_STRNDUP(realm_data->data, realm_data->length);
528 #endif
530 out:
532 if (princ) {
533 krb5_free_principal(ctx, princ);
535 if (cc) {
536 krb5_cc_close(ctx, cc);
538 if (ctx) {
539 krb5_free_context(ctx);
542 return realm;
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 ************************************************************************/
553 krb5_principal kerberos_fetch_salt_princ_for_host_princ(krb5_context context,
554 krb5_principal host_princ,
555 int enctype)
557 char *unparsed_name = NULL, *salt_princ_s = NULL;
558 krb5_principal ret_princ = NULL;
560 /* lookup new key first */
562 if ( (salt_princ_s = kerberos_secrets_fetch_des_salt()) == NULL ) {
564 /* look under the old key. If this fails, just use the standard key */
566 if (smb_krb5_unparse_name(context, host_princ, &unparsed_name) != 0) {
567 return (krb5_principal)NULL;
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();
575 if (smb_krb5_parse_name(context, salt_princ_s, &ret_princ) != 0) {
576 ret_princ = NULL;
579 SAFE_FREE(unparsed_name);
580 SAFE_FREE(salt_princ_s);
582 return ret_princ;
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 ************************************************************************/
593 bool kerberos_secrets_store_salting_principal(const char *service,
594 int enctype,
595 const char *principal)
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;
604 krb5_init_context(&context);
605 if (!context) {
606 return False;
608 if (strchr_m(service, '@')) {
609 asprintf(&princ_s, "%s", service);
610 } else {
611 asprintf(&princ_s, "%s@%s", service, lp_realm());
614 if (smb_krb5_parse_name(context, princ_s, &princ) != 0) {
615 goto out;
618 if (smb_krb5_unparse_name(context, princ, &unparsed_name) != 0) {
619 goto out;
622 asprintf(&key, "%s/%s/enctype=%d", SECRETS_SALTING_PRINCIPAL, unparsed_name, enctype);
623 if (!key) {
624 goto out;
627 if ((principal != NULL) && (strlen(principal) > 0)) {
628 ret = secrets_store(key, principal, strlen(principal) + 1);
629 } else {
630 ret = secrets_delete(key);
633 out:
635 SAFE_FREE(key);
636 SAFE_FREE(princ_s);
637 SAFE_FREE(unparsed_name);
639 if (context) {
640 krb5_free_context(context);
643 return ret;
647 /************************************************************************
648 ************************************************************************/
650 int kerberos_kinit_password(const char *principal,
651 const char *password,
652 int time_offset,
653 const char *cache_name)
655 return kerberos_kinit_password_ext(principal,
656 password,
657 time_offset,
660 cache_name,
661 False,
662 False,
664 NULL);
667 /************************************************************************
668 Create a string list of available kdc's, possibly searching by sitename.
669 Does DNS queries.
670 ************************************************************************/
672 static char *get_kdc_ip_string(char *mem_ctx,
673 const char *realm,
674 const char *sitename,
675 struct sockaddr_storage *pss)
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));
686 if (kdc_str == NULL) {
687 return NULL;
690 /* Get the KDC's only in this site. */
692 if (sitename) {
694 get_kdc_list(realm, sitename, &ip_srv_site, &count_site);
696 for (i = 0; i < count_site; i++) {
697 if (addr_equal(&ip_srv_site[i].ss, pss)) {
698 continue;
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;
713 /* Get all KDC's. */
715 get_kdc_list(realm, NULL, &ip_srv_nonsite, &count_nonsite);
717 for (i = 0; i < count_nonsite; i++) {
718 int j;
720 if (addr_equal(&ip_srv_nonsite[i].ss, pss)) {
721 continue;
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;
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;
735 if (j != i) {
736 continue;
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;
752 SAFE_FREE(ip_srv_site);
753 SAFE_FREE(ip_srv_nonsite);
755 DEBUG(10,("get_kdc_ip_string: Returning %s\n",
756 kdc_str ));
758 return kdc_str;
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 ************************************************************************/
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)
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;
783 if (!dname) {
784 return False;
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;
794 tmpname = talloc_asprintf(dname, "%s/smb_tmp_krb5.XXXXXX", lp_lockdir());
795 if (!tmpname) {
796 TALLOC_FREE(dname);
797 return False;
800 fname = talloc_asprintf(dname, "%s/krb5.conf.%s", dname, domain);
801 if (!fname) {
802 TALLOC_FREE(dname);
803 return False;
806 DEBUG(10,("create_local_private_krb5_conf_for_domain: fname = %s, realm = %s, domain = %s\n",
807 fname, realm, domain ));
809 realm_upper = talloc_strdup(fname, realm);
810 strupper_m(realm_upper);
812 kdc_ip_string = get_kdc_ip_string(dname, realm, sitename, pss);
813 if (!kdc_ip_string) {
814 TALLOC_FREE(dname);
815 return False;
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);
823 if (!file_contents) {
824 TALLOC_FREE(dname);
825 return False;
828 flen = strlen(file_contents);
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) ));
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;
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;
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;
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;
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) ));
878 /* Set the environment variable to this file. */
879 setenv("KRB5_CONFIG", fname, 1);
881 #if defined(OVERWRITE_SYSTEM_KRB5_CONF)
883 #define SYSTEM_KRB5_CONF_PATH "/etc/krb5.conf"
884 /* Insanity, sheer insanity..... */
886 if (strequal(realm, lp_realm())) {
887 char linkpath[PATH_MAX+1];
888 int lret;
890 lret = readlink(SYSTEM_KRB5_CONF_PATH, linkpath, sizeof(linkpath)-1);
891 if (lret != -1) {
892 linkpath[lret] = '\0';
895 if (lret != -1 || strcmp(linkpath, fname) == 0) {
896 /* Symlink already exists. */
897 TALLOC_FREE(dname);
898 return True;
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. */
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. */
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. */
931 #endif
933 TALLOC_FREE(dname);
935 return True;
937 #endif