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/>.
25 #include "system/filesys.h"
27 #include "../librpc/gen_ndr/ndr_misc.h"
28 #include "libads/kerberos_proto.h"
29 #include "libads/cldap.h"
31 #include "../lib/tsocket/tsocket.h"
35 #define LIBADS_CCACHE_NAME "MEMORY:libads"
38 we use a prompter to avoid a crash bug in the kerberos libs when
39 dealing with empty passwords
40 this prompter is just a string copy ...
42 static krb5_error_code
43 kerb_prompter(krb5_context ctx, void *data,
47 krb5_prompt prompts[])
49 if (num_prompts == 0) return 0;
50 #if HAVE_KRB5_PROMPT_TYPE
53 * only heimdal has a prompt type and we need to deal with it here to
56 * removing the prompter completely is not an option as at least these
57 * versions would crash: heimdal-1.0.2 and heimdal-1.1. Later heimdal
58 * version have looping detection and return with a proper error code.
61 if ((num_prompts == 2) &&
62 (prompts[0].type == KRB5_PROMPT_TYPE_NEW_PASSWORD) &&
63 (prompts[1].type == KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN)) {
65 * We don't want to change passwords here. We're
66 * called from heimal when the KDC returns
67 * KRB5KDC_ERR_KEY_EXPIRED, but at this point we don't
68 * have the chance to ask the user for a new
69 * password. If we return 0 (i.e. success), we will be
70 * spinning in the endless for-loop in
71 * change_password() in
72 * source4/heimdal/lib/krb5/init_creds_pw.c:526ff
74 return KRB5KDC_ERR_KEY_EXPIRED;
76 #endif /* HAVE_KRB5_PROMPT_TYPE */
77 memset(prompts[0].reply->data, '\0', prompts[0].reply->length);
78 if (prompts[0].reply->length > 0) {
80 strncpy((char *)prompts[0].reply->data, (const char *)data,
81 prompts[0].reply->length-1);
82 prompts[0].reply->length = strlen((const char *)prompts[0].reply->data);
84 prompts[0].reply->length = 0;
90 static bool smb_krb5_get_ntstatus_from_krb5_error(krb5_error *error,
94 DATA_BLOB unwrapped_edata;
96 struct KRB5_EDATA_NTSTATUS parsed_edata;
97 enum ndr_err_code ndr_err;
99 #ifdef HAVE_E_DATA_POINTER_IN_KRB5_ERROR
100 edata = data_blob(error->e_data->data, error->e_data->length);
102 edata = data_blob(error->e_data.data, error->e_data.length);
103 #endif /* HAVE_E_DATA_POINTER_IN_KRB5_ERROR */
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);
115 if (!unwrap_edata_ntstatus(mem_ctx, &edata, &unwrapped_edata)) {
116 data_blob_free(&edata);
117 TALLOC_FREE(mem_ctx);
121 data_blob_free(&edata);
123 ndr_err = ndr_pull_struct_blob_all(&unwrapped_edata, mem_ctx,
124 &parsed_edata, (ndr_pull_flags_fn_t)ndr_pull_KRB5_EDATA_NTSTATUS);
125 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
126 data_blob_free(&unwrapped_edata);
127 TALLOC_FREE(mem_ctx);
131 data_blob_free(&unwrapped_edata);
134 *nt_status = parsed_edata.ntstatus;
137 TALLOC_FREE(mem_ctx);
142 static bool smb_krb5_get_ntstatus_from_krb5_error_init_creds_opt(krb5_context ctx,
143 krb5_get_init_creds_opt *opt,
147 krb5_error *error = NULL;
149 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_GET_ERROR
150 ret = krb5_get_init_creds_opt_get_error(ctx, opt, &error);
152 DEBUG(1,("krb5_get_init_creds_opt_get_error gave: %s\n",
153 error_message(ret)));
156 #endif /* HAVE_KRB5_GET_INIT_CREDS_OPT_GET_ERROR */
159 DEBUG(1,("no krb5_error\n"));
163 #ifdef HAVE_E_DATA_POINTER_IN_KRB5_ERROR
164 if (!error->e_data) {
166 if (error->e_data.data == NULL) {
167 #endif /* HAVE_E_DATA_POINTER_IN_KRB5_ERROR */
168 DEBUG(1,("no edata in krb5_error\n"));
169 krb5_free_error(ctx, error);
173 ret = smb_krb5_get_ntstatus_from_krb5_error(error, nt_status);
175 krb5_free_error(ctx, error);
181 simulate a kinit, putting the tgt in the given cache location. If cache_name == NULL
182 place in default cache location.
185 int kerberos_kinit_password_ext(const char *principal,
186 const char *password,
189 time_t *renew_till_time,
190 const char *cache_name,
192 bool add_netbios_addr,
193 time_t renewable_time,
196 krb5_context ctx = NULL;
197 krb5_error_code code = 0;
198 krb5_ccache cc = NULL;
199 krb5_principal me = NULL;
201 krb5_get_init_creds_opt *opt = NULL;
202 smb_krb5_addresses *addr = NULL;
204 ZERO_STRUCT(my_creds);
206 initialize_krb5_error_table();
207 if ((code = krb5_init_context(&ctx)))
210 if (time_offset != 0) {
211 krb5_set_real_time(ctx, time(NULL) + time_offset, 0);
214 DEBUG(10,("kerberos_kinit_password: as %s using [%s] as ccache and config [%s]\n",
216 cache_name ? cache_name: krb5_cc_default_name(ctx),
217 getenv("KRB5_CONFIG")));
219 if ((code = krb5_cc_resolve(ctx, cache_name ? cache_name : krb5_cc_default_name(ctx), &cc))) {
223 if ((code = smb_krb5_parse_name(ctx, principal, &me))) {
227 if ((code = smb_krb5_get_init_creds_opt_alloc(ctx, &opt))) {
231 krb5_get_init_creds_opt_set_renew_life(opt, renewable_time);
232 krb5_get_init_creds_opt_set_forwardable(opt, True);
235 krb5_get_init_creds_opt_set_tkt_life(opt, 60);
238 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PAC_REQUEST
240 if ((code = krb5_get_init_creds_opt_set_pac_request(ctx, opt, (krb5_boolean)request_pac))) {
245 if (add_netbios_addr) {
246 if ((code = smb_krb5_gen_netbios_krb5_address(&addr,
247 lp_netbios_name()))) {
250 krb5_get_init_creds_opt_set_address_list(opt, addr->addrs);
253 if ((code = krb5_get_init_creds_password(ctx, &my_creds, me, discard_const_p(char,password),
254 kerb_prompter, discard_const_p(char, password),
259 if ((code = krb5_cc_initialize(ctx, cc, me))) {
263 if ((code = krb5_cc_store_cred(ctx, cc, &my_creds))) {
268 *expire_time = (time_t) my_creds.times.endtime;
271 if (renew_till_time) {
272 *renew_till_time = (time_t) my_creds.times.renew_till;
281 *ntstatus = NT_STATUS_OK;
285 /* try to get ntstatus code out of krb5_error when we have it
286 * inside the krb5_get_init_creds_opt - gd */
288 if (opt && smb_krb5_get_ntstatus_from_krb5_error_init_creds_opt(ctx, opt, &status)) {
293 /* fall back to self-made-mapping */
294 *ntstatus = krb5_to_nt_status(code);
298 krb5_free_cred_contents(ctx, &my_creds);
300 krb5_free_principal(ctx, me);
303 smb_krb5_free_addresses(ctx, addr);
306 smb_krb5_get_init_creds_opt_free(ctx, opt);
309 krb5_cc_close(ctx, cc);
312 krb5_free_context(ctx);
317 int ads_kdestroy(const char *cc_name)
319 krb5_error_code code;
320 krb5_context ctx = NULL;
321 krb5_ccache cc = NULL;
323 initialize_krb5_error_table();
324 if ((code = krb5_init_context (&ctx))) {
325 DEBUG(3, ("ads_kdestroy: kdb5_init_context failed: %s\n",
326 error_message(code)));
331 if ((code = krb5_cc_default(ctx, &cc))) {
332 krb5_free_context(ctx);
336 if ((code = krb5_cc_resolve(ctx, cc_name, &cc))) {
337 DEBUG(3, ("ads_kdestroy: krb5_cc_resolve failed: %s\n",
338 error_message(code)));
339 krb5_free_context(ctx);
344 if ((code = krb5_cc_destroy (ctx, cc))) {
345 DEBUG(3, ("ads_kdestroy: krb5_cc_destroy failed: %s\n",
346 error_message(code)));
349 krb5_free_context (ctx);
353 /************************************************************************
354 Routine to fetch the salting principal for a service. Active
355 Directory may use a non-obvious principal name to generate the salt
356 when it determines the key to use for encrypting tickets for a service,
357 and hopefully we detected that when we joined the domain.
358 ************************************************************************/
360 static char *kerberos_secrets_fetch_salting_principal(const char *service, int enctype)
365 if (asprintf(&key, "%s/%s/enctype=%d",
366 SECRETS_SALTING_PRINCIPAL, service, enctype) == -1) {
369 ret = (char *)secrets_fetch(key, NULL);
374 /************************************************************************
375 Return the standard DES salt key
376 ************************************************************************/
378 char* kerberos_standard_des_salt( void )
382 fstr_sprintf( salt, "host/%s.%s@", lp_netbios_name(), lp_realm() );
383 (void)strlower_m( salt );
384 fstrcat( salt, lp_realm() );
386 return SMB_STRDUP( salt );
389 /************************************************************************
390 ************************************************************************/
392 static char* des_salt_key( void )
396 if (asprintf(&key, "%s/DES/%s", SECRETS_SALTING_PRINCIPAL,
404 /************************************************************************
405 ************************************************************************/
407 bool kerberos_secrets_store_des_salt( const char* salt )
412 if ( (key = des_salt_key()) == NULL ) {
413 DEBUG(0,("kerberos_secrets_store_des_salt: failed to generate key!\n"));
418 DEBUG(8,("kerberos_secrets_store_des_salt: deleting salt\n"));
419 secrets_delete( key );
423 DEBUG(3,("kerberos_secrets_store_des_salt: Storing salt \"%s\"\n", salt));
425 ret = secrets_store( key, salt, strlen(salt)+1 );
432 /************************************************************************
433 ************************************************************************/
436 char* kerberos_secrets_fetch_des_salt( void )
440 if ( (key = des_salt_key()) == NULL ) {
441 DEBUG(0,("kerberos_secrets_fetch_des_salt: failed to generate key!\n"));
445 salt = (char*)secrets_fetch( key, NULL );
452 /************************************************************************
453 Routine to get the salting principal for this service. This is
454 maintained for backwards compatibilty with releases prior to 3.0.24.
455 Since we store the salting principal string only at join, we may have
456 to look for the older tdb keys. Caller must free if return is not null.
457 ************************************************************************/
460 krb5_principal kerberos_fetch_salt_princ_for_host_princ(krb5_context context,
461 krb5_principal host_princ,
464 char *unparsed_name = NULL, *salt_princ_s = NULL;
465 krb5_principal ret_princ = NULL;
467 /* lookup new key first */
469 if ( (salt_princ_s = kerberos_secrets_fetch_des_salt()) == NULL ) {
471 /* look under the old key. If this fails, just use the standard key */
473 if (smb_krb5_unparse_name(talloc_tos(), context, host_princ, &unparsed_name) != 0) {
474 return (krb5_principal)NULL;
476 if ((salt_princ_s = kerberos_secrets_fetch_salting_principal(unparsed_name, enctype)) == NULL) {
477 /* fall back to host/machine.realm@REALM */
478 salt_princ_s = kerberos_standard_des_salt();
482 if (smb_krb5_parse_name(context, salt_princ_s, &ret_princ) != 0) {
486 TALLOC_FREE(unparsed_name);
487 SAFE_FREE(salt_princ_s);
492 int create_kerberos_key_from_string(krb5_context context,
493 krb5_principal host_princ,
496 krb5_enctype enctype,
499 krb5_principal salt_princ = NULL;
502 * Check if we've determined that the KDC is salting keys for this
503 * principal/enctype in a non-obvious way. If it is, try to match
507 KRB5_KEY_DATA(key) = (KRB5_KEY_DATA_CAST *)SMB_MALLOC(password->length);
508 if (!KRB5_KEY_DATA(key)) {
511 memcpy(KRB5_KEY_DATA(key), password->data, password->length);
512 KRB5_KEY_LENGTH(key) = password->length;
513 KRB5_KEY_TYPE(key) = enctype;
516 salt_princ = kerberos_fetch_salt_princ_for_host_princ(context, host_princ, enctype);
517 ret = smb_krb5_create_key_from_string(context,
518 salt_princ ? salt_princ : host_princ,
524 krb5_free_principal(context, salt_princ);
529 /************************************************************************
530 Routine to set the salting principal for this service. Active
531 Directory may use a non-obvious principal name to generate the salt
532 when it determines the key to use for encrypting tickets for a service,
533 and hopefully we detected that when we joined the domain.
534 Setting principal to NULL deletes this entry.
535 ************************************************************************/
537 bool kerberos_secrets_store_salting_principal(const char *service,
539 const char *principal)
543 krb5_context context = NULL;
544 krb5_principal princ = NULL;
545 char *princ_s = NULL;
546 char *unparsed_name = NULL;
547 krb5_error_code code;
549 if (((code = krb5_init_context(&context)) != 0) || (context == NULL)) {
550 DEBUG(5, ("kerberos_secrets_store_salting_pricipal: kdb5_init_context failed: %s\n",
551 error_message(code)));
554 if (strchr_m(service, '@')) {
555 if (asprintf(&princ_s, "%s", service) == -1) {
559 if (asprintf(&princ_s, "%s@%s", service, lp_realm()) == -1) {
564 if (smb_krb5_parse_name(context, princ_s, &princ) != 0) {
567 if (smb_krb5_unparse_name(talloc_tos(), context, princ, &unparsed_name) != 0) {
571 if (asprintf(&key, "%s/%s/enctype=%d",
572 SECRETS_SALTING_PRINCIPAL, unparsed_name, enctype)
577 if ((principal != NULL) && (strlen(principal) > 0)) {
578 ret = secrets_store(key, principal, strlen(principal) + 1);
580 ret = secrets_delete(key);
587 TALLOC_FREE(unparsed_name);
590 krb5_free_principal(context, princ);
594 krb5_free_context(context);
601 /************************************************************************
602 ************************************************************************/
604 int kerberos_kinit_password(const char *principal,
605 const char *password,
607 const char *cache_name)
609 return kerberos_kinit_password_ext(principal,
621 /************************************************************************
622 ************************************************************************/
624 /************************************************************************
625 Create a string list of available kdc's, possibly searching by sitename.
628 If "sitename" is given, the DC's in that site are listed first.
630 ************************************************************************/
632 static void add_sockaddr_unique(struct sockaddr_storage *addrs, int *num_addrs,
633 const struct sockaddr_storage *addr)
637 for (i=0; i<*num_addrs; i++) {
638 if (sockaddr_equal((const struct sockaddr *)&addrs[i],
639 (const struct sockaddr *)addr)) {
647 /* print_canonical_sockaddr prints an ipv6 addr in the form of
648 * [ipv6.addr]. This string, when put in a generated krb5.conf file is not
649 * always properly dealt with by some older krb5 libraries. Adding the hard-coded
650 * portnumber workarounds the issue. - gd */
652 static char *print_canonical_sockaddr_with_port(TALLOC_CTX *mem_ctx,
653 const struct sockaddr_storage *pss)
657 str = print_canonical_sockaddr(mem_ctx, pss);
662 if (pss->ss_family != AF_INET6) {
666 #if defined(HAVE_IPV6)
667 str = talloc_asprintf_append(str, ":88");
672 static char *get_kdc_ip_string(char *mem_ctx,
674 const char *sitename,
675 const struct sockaddr_storage *pss)
677 TALLOC_CTX *frame = talloc_stackframe();
679 struct ip_service *ip_srv_site = NULL;
680 struct ip_service *ip_srv_nonsite = NULL;
684 struct sockaddr_storage *dc_addrs;
685 struct tsocket_address **dc_addrs2 = NULL;
686 const struct tsocket_address * const *dc_addrs3 = NULL;
688 struct netlogon_samlogon_response **responses = NULL;
690 char *kdc_str = talloc_asprintf(mem_ctx, "%s\t\tkdc = %s\n", "",
691 print_canonical_sockaddr_with_port(mem_ctx, pss));
693 if (kdc_str == NULL) {
699 * First get the KDC's only in this site, the rest will be
704 get_kdc_list(realm, sitename, &ip_srv_site, &count_site);
705 DEBUG(10, ("got %d addresses from site %s search\n", count_site,
711 get_kdc_list(realm, NULL, &ip_srv_nonsite, &count_nonsite);
712 DEBUG(10, ("got %d addresses from site-less search\n", count_nonsite));
714 dc_addrs = talloc_array(talloc_tos(), struct sockaddr_storage,
715 count_site + count_nonsite);
716 if (dc_addrs == NULL) {
722 for (i = 0; i < count_site; i++) {
724 (const struct sockaddr *)pss,
725 (const struct sockaddr *)&ip_srv_site[i].ss)) {
726 add_sockaddr_unique(dc_addrs, &num_dcs,
731 for (i = 0; i < count_nonsite; i++) {
733 (const struct sockaddr *)pss,
734 (const struct sockaddr *)&ip_srv_nonsite[i].ss)) {
735 add_sockaddr_unique(dc_addrs, &num_dcs,
736 &ip_srv_nonsite[i].ss);
740 dc_addrs2 = talloc_zero_array(talloc_tos(),
741 struct tsocket_address *,
744 DEBUG(10, ("%d additional KDCs to test\n", num_dcs));
748 if (dc_addrs2 == NULL) {
752 for (i=0; i<num_dcs; i++) {
753 char addr[INET6_ADDRSTRLEN];
756 print_sockaddr(addr, sizeof(addr), &dc_addrs[i]);
758 ret = tsocket_address_inet_from_strings(dc_addrs2, "ip",
762 status = map_nt_error_from_unix(errno);
763 DEBUG(2,("Failed to create tsocket_address for %s - %s\n",
764 addr, nt_errstr(status)));
769 dc_addrs3 = (const struct tsocket_address * const *)dc_addrs2;
771 status = cldap_multi_netlogon(talloc_tos(),
773 realm, lp_netbios_name(),
774 NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX,
775 MIN(num_dcs, 3), timeval_current_ofs(3, 0), &responses);
776 TALLOC_FREE(dc_addrs2);
779 if (!NT_STATUS_IS_OK(status)) {
780 DEBUG(10,("get_kdc_ip_string: cldap_multi_netlogon failed: "
781 "%s\n", nt_errstr(status)));
785 for (i=0; i<num_dcs; i++) {
788 if (responses[i] == NULL) {
792 /* Append to the string - inefficient but not done often. */
793 new_kdc_str = talloc_asprintf(mem_ctx, "%s\t\tkdc = %s\n",
795 print_canonical_sockaddr_with_port(mem_ctx, &dc_addrs[i]));
796 if (new_kdc_str == NULL) {
799 TALLOC_FREE(kdc_str);
800 kdc_str = new_kdc_str;
804 DEBUG(10, ("get_kdc_ip_string: Returning %s\n", kdc_str));
807 SAFE_FREE(ip_srv_site);
808 SAFE_FREE(ip_srv_nonsite);
813 /************************************************************************
814 Create a specific krb5.conf file in the private directory pointing
815 at a specific kdc for a realm. Keyed off domain name. Sets
816 KRB5_CONFIG environment variable to point to this file. Must be
817 run as root or will fail (which is a good thing :-).
818 ************************************************************************/
820 bool create_local_private_krb5_conf_for_domain(const char *realm,
822 const char *sitename,
823 const struct sockaddr_storage *pss)
826 char *tmpname = NULL;
828 char *file_contents = NULL;
829 char *kdc_ip_string = NULL;
833 char *realm_upper = NULL;
835 char *aes_enctypes = NULL;
838 if (!lp_create_krb5_conf()) {
843 DEBUG(0, ("No realm has been specified! Do you really want to "
844 "join an Active Directory server?\n"));
848 if (domain == NULL || pss == NULL) {
852 dname = lock_path("smb_krb5");
856 if ((mkdir(dname, 0755)==-1) && (errno != EEXIST)) {
857 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
858 "failed to create directory %s. Error was %s\n",
859 dname, strerror(errno) ));
863 tmpname = lock_path("smb_tmp_krb5.XXXXXX");
868 fname = talloc_asprintf(dname, "%s/krb5.conf.%s", dname, domain);
873 DEBUG(10,("create_local_private_krb5_conf_for_domain: fname = %s, realm = %s, domain = %s\n",
874 fname, realm, domain ));
876 realm_upper = talloc_strdup(fname, realm);
877 if (!strupper_m(realm_upper)) {
881 kdc_ip_string = get_kdc_ip_string(dname, realm, sitename, pss);
882 if (!kdc_ip_string) {
886 aes_enctypes = talloc_strdup(fname, "");
887 if (aes_enctypes == NULL) {
891 #ifdef HAVE_ENCTYPE_AES256_CTS_HMAC_SHA1_96
892 aes_enctypes = talloc_asprintf_append(aes_enctypes, "%s", "aes256-cts-hmac-sha1-96 ");
893 if (aes_enctypes == NULL) {
897 #ifdef HAVE_ENCTYPE_AES128_CTS_HMAC_SHA1_96
898 aes_enctypes = talloc_asprintf_append(aes_enctypes, "%s", "aes128-cts-hmac-sha1-96");
899 if (aes_enctypes == NULL) {
904 file_contents = talloc_asprintf(fname,
905 "[libdefaults]\n\tdefault_realm = %s\n"
906 "\tdefault_tgs_enctypes = %s RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
907 "\tdefault_tkt_enctypes = %s RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
908 "\tpreferred_enctypes = %s RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
909 "\tdns_lookup_realm = false\n\n"
910 "[realms]\n\t%s = {\n"
912 realm_upper, aes_enctypes, aes_enctypes, aes_enctypes,
913 realm_upper, kdc_ip_string);
915 if (!file_contents) {
919 flen = strlen(file_contents);
921 mask = umask(S_IRWXO | S_IRWXG);
922 fd = mkstemp(tmpname);
925 DEBUG(0,("create_local_private_krb5_conf_for_domain: smb_mkstemp failed,"
926 " for file %s. Errno %s\n",
927 tmpname, strerror(errno) ));
931 if (fchmod(fd, 0644)==-1) {
932 DEBUG(0,("create_local_private_krb5_conf_for_domain: fchmod failed for %s."
934 tmpname, strerror(errno) ));
940 ret = write(fd, file_contents, flen);
942 DEBUG(0,("create_local_private_krb5_conf_for_domain: write failed,"
943 " returned %d (should be %u). Errno %s\n",
944 (int)ret, (unsigned int)flen, strerror(errno) ));
950 DEBUG(0,("create_local_private_krb5_conf_for_domain: close failed."
951 " Errno %s\n", strerror(errno) ));
956 if (rename(tmpname, fname) == -1) {
957 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
958 "of %s to %s failed. Errno %s\n",
959 tmpname, fname, strerror(errno) ));
964 DEBUG(5,("create_local_private_krb5_conf_for_domain: wrote "
965 "file %s with realm %s KDC list = %s\n",
966 fname, realm_upper, kdc_ip_string));
968 /* Set the environment variable to this file. */
969 setenv("KRB5_CONFIG", fname, 1);
973 #if defined(OVERWRITE_SYSTEM_KRB5_CONF)
975 #define SYSTEM_KRB5_CONF_PATH "/etc/krb5.conf"
976 /* Insanity, sheer insanity..... */
978 if (strequal(realm, lp_realm())) {
979 SMB_STRUCT_STAT sbuf;
981 if (sys_lstat(SYSTEM_KRB5_CONF_PATH, &sbuf, false) == 0) {
982 if (S_ISLNK(sbuf.st_ex_mode) && sbuf.st_ex_size) {
984 size_t alloc_size = sbuf.st_ex_size + 1;
985 char *linkpath = talloc_array(talloc_tos(), char,
990 lret = readlink(SYSTEM_KRB5_CONF_PATH, linkpath,
993 TALLOC_FREE(linkpath);
996 linkpath[lret] = '\0';
998 if (strcmp(linkpath, fname) == 0) {
999 /* Symlink already exists. */
1000 TALLOC_FREE(linkpath);
1003 TALLOC_FREE(linkpath);
1007 /* Try and replace with a symlink. */
1008 if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
1009 const char *newpath = SYSTEM_KRB5_CONF_PATH ".saved";
1010 if (errno != EEXIST) {
1011 DEBUG(0,("create_local_private_krb5_conf_for_domain: symlink "
1012 "of %s to %s failed. Errno %s\n",
1013 fname, SYSTEM_KRB5_CONF_PATH, strerror(errno) ));
1014 goto done; /* Not a fatal error. */
1017 /* Yes, this is a race conditon... too bad. */
1018 if (rename(SYSTEM_KRB5_CONF_PATH, newpath) == -1) {
1019 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
1020 "of %s to %s failed. Errno %s\n",
1021 SYSTEM_KRB5_CONF_PATH, newpath,
1023 goto done; /* Not a fatal error. */
1026 if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
1027 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
1028 "forced symlink of %s to /etc/krb5.conf failed. Errno %s\n",
1029 fname, strerror(errno) ));
1030 goto done; /* Not a fatal error. */
1037 TALLOC_FREE(tmpname);