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;
51 if ((num_prompts == 2) &&
52 (prompts[0].type == KRB5_PROMPT_TYPE_NEW_PASSWORD) &&
53 (prompts[1].type == KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN)) {
55 * We don't want to change passwords here. We're
56 * called from heimal when the KDC returns
57 * KRB5KDC_ERR_KEY_EXPIRED, but at this point we don't
58 * have the chance to ask the user for a new
59 * password. If we return 0 (i.e. success), we will be
60 * spinning in the endless for-loop in
61 * change_password() in
62 * source4/heimdal/lib/krb5/init_creds_pw.c:526ff
64 return KRB5KDC_ERR_KEY_EXPIRED;
67 memset(prompts[0].reply->data, '\0', prompts[0].reply->length);
68 if (prompts[0].reply->length > 0) {
70 strncpy((char *)prompts[0].reply->data, (const char *)data,
71 prompts[0].reply->length-1);
72 prompts[0].reply->length = strlen((const char *)prompts[0].reply->data);
74 prompts[0].reply->length = 0;
80 static bool smb_krb5_get_ntstatus_from_krb5_error(krb5_error *error,
84 DATA_BLOB unwrapped_edata;
86 struct KRB5_EDATA_NTSTATUS parsed_edata;
87 enum ndr_err_code ndr_err;
89 #ifdef HAVE_E_DATA_POINTER_IN_KRB5_ERROR
90 edata = data_blob(error->e_data->data, error->e_data->length);
92 edata = data_blob(error->e_data.data, error->e_data.length);
93 #endif /* HAVE_E_DATA_POINTER_IN_KRB5_ERROR */
96 dump_data(10, edata.data, edata.length);
97 #endif /* DEVELOPER */
99 mem_ctx = talloc_init("smb_krb5_get_ntstatus_from_krb5_error");
100 if (mem_ctx == NULL) {
101 data_blob_free(&edata);
105 if (!unwrap_edata_ntstatus(mem_ctx, &edata, &unwrapped_edata)) {
106 data_blob_free(&edata);
107 TALLOC_FREE(mem_ctx);
111 data_blob_free(&edata);
113 ndr_err = ndr_pull_struct_blob_all(&unwrapped_edata, mem_ctx,
114 &parsed_edata, (ndr_pull_flags_fn_t)ndr_pull_KRB5_EDATA_NTSTATUS);
115 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
116 data_blob_free(&unwrapped_edata);
117 TALLOC_FREE(mem_ctx);
121 data_blob_free(&unwrapped_edata);
124 *nt_status = parsed_edata.ntstatus;
127 TALLOC_FREE(mem_ctx);
132 static bool smb_krb5_get_ntstatus_from_krb5_error_init_creds_opt(krb5_context ctx,
133 krb5_get_init_creds_opt *opt,
137 krb5_error *error = NULL;
139 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_GET_ERROR
140 ret = krb5_get_init_creds_opt_get_error(ctx, opt, &error);
142 DEBUG(1,("krb5_get_init_creds_opt_get_error gave: %s\n",
143 error_message(ret)));
146 #endif /* HAVE_KRB5_GET_INIT_CREDS_OPT_GET_ERROR */
149 DEBUG(1,("no krb5_error\n"));
153 #ifdef HAVE_E_DATA_POINTER_IN_KRB5_ERROR
154 if (!error->e_data) {
156 if (error->e_data.data == NULL) {
157 #endif /* HAVE_E_DATA_POINTER_IN_KRB5_ERROR */
158 DEBUG(1,("no edata in krb5_error\n"));
159 krb5_free_error(ctx, error);
163 ret = smb_krb5_get_ntstatus_from_krb5_error(error, nt_status);
165 krb5_free_error(ctx, error);
171 simulate a kinit, putting the tgt in the given cache location. If cache_name == NULL
172 place in default cache location.
175 int kerberos_kinit_password_ext(const char *principal,
176 const char *password,
179 time_t *renew_till_time,
180 const char *cache_name,
182 bool add_netbios_addr,
183 time_t renewable_time,
186 krb5_context ctx = NULL;
187 krb5_error_code code = 0;
188 krb5_ccache cc = NULL;
189 krb5_principal me = NULL;
191 krb5_get_init_creds_opt *opt = NULL;
192 smb_krb5_addresses *addr = NULL;
194 ZERO_STRUCT(my_creds);
196 initialize_krb5_error_table();
197 if ((code = krb5_init_context(&ctx)))
200 if (time_offset != 0) {
201 krb5_set_real_time(ctx, time(NULL) + time_offset, 0);
204 DEBUG(10,("kerberos_kinit_password: as %s using [%s] as ccache and config [%s]\n",
206 cache_name ? cache_name: krb5_cc_default_name(ctx),
207 getenv("KRB5_CONFIG")));
209 if ((code = krb5_cc_resolve(ctx, cache_name ? cache_name : krb5_cc_default_name(ctx), &cc))) {
213 if ((code = smb_krb5_parse_name(ctx, principal, &me))) {
217 if ((code = smb_krb5_get_init_creds_opt_alloc(ctx, &opt))) {
221 krb5_get_init_creds_opt_set_renew_life(opt, renewable_time);
222 krb5_get_init_creds_opt_set_forwardable(opt, True);
225 krb5_get_init_creds_opt_set_tkt_life(opt, 60);
228 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PAC_REQUEST
230 if ((code = krb5_get_init_creds_opt_set_pac_request(ctx, opt, (krb5_boolean)request_pac))) {
235 if (add_netbios_addr) {
236 if ((code = smb_krb5_gen_netbios_krb5_address(&addr,
237 lp_netbios_name()))) {
240 krb5_get_init_creds_opt_set_address_list(opt, addr->addrs);
243 if ((code = krb5_get_init_creds_password(ctx, &my_creds, me, discard_const_p(char,password),
244 kerb_prompter, discard_const_p(char, password),
249 if ((code = krb5_cc_initialize(ctx, cc, me))) {
253 if ((code = krb5_cc_store_cred(ctx, cc, &my_creds))) {
258 *expire_time = (time_t) my_creds.times.endtime;
261 if (renew_till_time) {
262 *renew_till_time = (time_t) my_creds.times.renew_till;
271 *ntstatus = NT_STATUS_OK;
275 /* try to get ntstatus code out of krb5_error when we have it
276 * inside the krb5_get_init_creds_opt - gd */
278 if (opt && smb_krb5_get_ntstatus_from_krb5_error_init_creds_opt(ctx, opt, &status)) {
283 /* fall back to self-made-mapping */
284 *ntstatus = krb5_to_nt_status(code);
288 krb5_free_cred_contents(ctx, &my_creds);
290 krb5_free_principal(ctx, me);
293 smb_krb5_free_addresses(ctx, addr);
296 smb_krb5_get_init_creds_opt_free(ctx, opt);
299 krb5_cc_close(ctx, cc);
302 krb5_free_context(ctx);
307 int ads_kdestroy(const char *cc_name)
309 krb5_error_code code;
310 krb5_context ctx = NULL;
311 krb5_ccache cc = NULL;
313 initialize_krb5_error_table();
314 if ((code = krb5_init_context (&ctx))) {
315 DEBUG(3, ("ads_kdestroy: kdb5_init_context failed: %s\n",
316 error_message(code)));
321 if ((code = krb5_cc_default(ctx, &cc))) {
322 krb5_free_context(ctx);
326 if ((code = krb5_cc_resolve(ctx, cc_name, &cc))) {
327 DEBUG(3, ("ads_kdestroy: krb5_cc_resolve failed: %s\n",
328 error_message(code)));
329 krb5_free_context(ctx);
334 if ((code = krb5_cc_destroy (ctx, cc))) {
335 DEBUG(3, ("ads_kdestroy: krb5_cc_destroy failed: %s\n",
336 error_message(code)));
339 krb5_free_context (ctx);
343 /************************************************************************
344 Routine to fetch the salting principal for a service. Active
345 Directory may use a non-obvious principal name to generate the salt
346 when it determines the key to use for encrypting tickets for a service,
347 and hopefully we detected that when we joined the domain.
348 ************************************************************************/
350 static char *kerberos_secrets_fetch_salting_principal(const char *service, int enctype)
355 if (asprintf(&key, "%s/%s/enctype=%d",
356 SECRETS_SALTING_PRINCIPAL, service, enctype) == -1) {
359 ret = (char *)secrets_fetch(key, NULL);
364 /************************************************************************
365 Return the standard DES salt key
366 ************************************************************************/
368 char* kerberos_standard_des_salt( void )
372 fstr_sprintf( salt, "host/%s.%s@", lp_netbios_name(), lp_realm() );
373 (void)strlower_m( salt );
374 fstrcat( salt, lp_realm() );
376 return SMB_STRDUP( salt );
379 /************************************************************************
380 ************************************************************************/
382 static char* des_salt_key( void )
386 if (asprintf(&key, "%s/DES/%s", SECRETS_SALTING_PRINCIPAL,
394 /************************************************************************
395 ************************************************************************/
397 bool kerberos_secrets_store_des_salt( const char* salt )
402 if ( (key = des_salt_key()) == NULL ) {
403 DEBUG(0,("kerberos_secrets_store_des_salt: failed to generate key!\n"));
408 DEBUG(8,("kerberos_secrets_store_des_salt: deleting salt\n"));
409 secrets_delete( key );
413 DEBUG(3,("kerberos_secrets_store_des_salt: Storing salt \"%s\"\n", salt));
415 ret = secrets_store( key, salt, strlen(salt)+1 );
422 /************************************************************************
423 ************************************************************************/
426 char* kerberos_secrets_fetch_des_salt( void )
430 if ( (key = des_salt_key()) == NULL ) {
431 DEBUG(0,("kerberos_secrets_fetch_des_salt: failed to generate key!\n"));
435 salt = (char*)secrets_fetch( key, NULL );
442 /************************************************************************
443 Routine to get the salting principal for this service. This is
444 maintained for backwards compatibilty with releases prior to 3.0.24.
445 Since we store the salting principal string only at join, we may have
446 to look for the older tdb keys. Caller must free if return is not null.
447 ************************************************************************/
450 krb5_principal kerberos_fetch_salt_princ_for_host_princ(krb5_context context,
451 krb5_principal host_princ,
454 char *unparsed_name = NULL, *salt_princ_s = NULL;
455 krb5_principal ret_princ = NULL;
457 /* lookup new key first */
459 if ( (salt_princ_s = kerberos_secrets_fetch_des_salt()) == NULL ) {
461 /* look under the old key. If this fails, just use the standard key */
463 if (smb_krb5_unparse_name(talloc_tos(), context, host_princ, &unparsed_name) != 0) {
464 return (krb5_principal)NULL;
466 if ((salt_princ_s = kerberos_secrets_fetch_salting_principal(unparsed_name, enctype)) == NULL) {
467 /* fall back to host/machine.realm@REALM */
468 salt_princ_s = kerberos_standard_des_salt();
472 if (smb_krb5_parse_name(context, salt_princ_s, &ret_princ) != 0) {
476 TALLOC_FREE(unparsed_name);
477 SAFE_FREE(salt_princ_s);
482 int create_kerberos_key_from_string(krb5_context context,
483 krb5_principal host_princ,
486 krb5_enctype enctype,
489 krb5_principal salt_princ = NULL;
492 * Check if we've determined that the KDC is salting keys for this
493 * principal/enctype in a non-obvious way. If it is, try to match
497 KRB5_KEY_DATA(key) = (KRB5_KEY_DATA_CAST *)SMB_MALLOC(password->length);
498 if (!KRB5_KEY_DATA(key)) {
501 memcpy(KRB5_KEY_DATA(key), password->data, password->length);
502 KRB5_KEY_LENGTH(key) = password->length;
503 KRB5_KEY_TYPE(key) = enctype;
506 salt_princ = kerberos_fetch_salt_princ_for_host_princ(context, host_princ, enctype);
507 ret = smb_krb5_create_key_from_string(context,
508 salt_princ ? salt_princ : host_princ,
514 krb5_free_principal(context, salt_princ);
519 /************************************************************************
520 Routine to set the salting principal for this service. Active
521 Directory may use a non-obvious principal name to generate the salt
522 when it determines the key to use for encrypting tickets for a service,
523 and hopefully we detected that when we joined the domain.
524 Setting principal to NULL deletes this entry.
525 ************************************************************************/
527 bool kerberos_secrets_store_salting_principal(const char *service,
529 const char *principal)
533 krb5_context context = NULL;
534 krb5_principal princ = NULL;
535 char *princ_s = NULL;
536 char *unparsed_name = NULL;
537 krb5_error_code code;
539 if (((code = krb5_init_context(&context)) != 0) || (context == NULL)) {
540 DEBUG(5, ("kerberos_secrets_store_salting_pricipal: kdb5_init_context failed: %s\n",
541 error_message(code)));
544 if (strchr_m(service, '@')) {
545 if (asprintf(&princ_s, "%s", service) == -1) {
549 if (asprintf(&princ_s, "%s@%s", service, lp_realm()) == -1) {
554 if (smb_krb5_parse_name(context, princ_s, &princ) != 0) {
557 if (smb_krb5_unparse_name(talloc_tos(), context, princ, &unparsed_name) != 0) {
561 if (asprintf(&key, "%s/%s/enctype=%d",
562 SECRETS_SALTING_PRINCIPAL, unparsed_name, enctype)
567 if ((principal != NULL) && (strlen(principal) > 0)) {
568 ret = secrets_store(key, principal, strlen(principal) + 1);
570 ret = secrets_delete(key);
577 TALLOC_FREE(unparsed_name);
580 krb5_free_principal(context, princ);
584 krb5_free_context(context);
591 /************************************************************************
592 ************************************************************************/
594 int kerberos_kinit_password(const char *principal,
595 const char *password,
597 const char *cache_name)
599 return kerberos_kinit_password_ext(principal,
611 /************************************************************************
612 ************************************************************************/
614 /************************************************************************
615 Create a string list of available kdc's, possibly searching by sitename.
618 If "sitename" is given, the DC's in that site are listed first.
620 ************************************************************************/
622 static void add_sockaddr_unique(struct sockaddr_storage *addrs, int *num_addrs,
623 const struct sockaddr_storage *addr)
627 for (i=0; i<*num_addrs; i++) {
628 if (sockaddr_equal((const struct sockaddr *)&addrs[i],
629 (const struct sockaddr *)addr)) {
637 /* print_canonical_sockaddr prints an ipv6 addr in the form of
638 * [ipv6.addr]. This string, when put in a generated krb5.conf file is not
639 * always properly dealt with by some older krb5 libraries. Adding the hard-coded
640 * portnumber workarounds the issue. - gd */
642 static char *print_canonical_sockaddr_with_port(TALLOC_CTX *mem_ctx,
643 const struct sockaddr_storage *pss)
647 str = print_canonical_sockaddr(mem_ctx, pss);
652 if (pss->ss_family != AF_INET6) {
656 #if defined(HAVE_IPV6)
657 str = talloc_asprintf_append(str, ":88");
662 static char *get_kdc_ip_string(char *mem_ctx,
664 const char *sitename,
665 const struct sockaddr_storage *pss)
667 TALLOC_CTX *frame = talloc_stackframe();
669 struct ip_service *ip_srv_site = NULL;
670 struct ip_service *ip_srv_nonsite = NULL;
674 struct sockaddr_storage *dc_addrs;
675 struct tsocket_address **dc_addrs2 = NULL;
676 const struct tsocket_address * const *dc_addrs3 = NULL;
678 struct netlogon_samlogon_response **responses = NULL;
680 char *kdc_str = talloc_asprintf(mem_ctx, "%s\t\tkdc = %s\n", "",
681 print_canonical_sockaddr_with_port(mem_ctx, pss));
683 if (kdc_str == NULL) {
689 * First get the KDC's only in this site, the rest will be
694 get_kdc_list(realm, sitename, &ip_srv_site, &count_site);
695 DEBUG(10, ("got %d addresses from site %s search\n", count_site,
701 get_kdc_list(realm, NULL, &ip_srv_nonsite, &count_nonsite);
702 DEBUG(10, ("got %d addresses from site-less search\n", count_nonsite));
704 dc_addrs = talloc_array(talloc_tos(), struct sockaddr_storage,
705 count_site + count_nonsite);
706 if (dc_addrs == NULL) {
712 for (i = 0; i < count_site; i++) {
714 (const struct sockaddr *)pss,
715 (const struct sockaddr *)&ip_srv_site[i].ss)) {
716 add_sockaddr_unique(dc_addrs, &num_dcs,
721 for (i = 0; i < count_nonsite; i++) {
723 (const struct sockaddr *)pss,
724 (const struct sockaddr *)&ip_srv_nonsite[i].ss)) {
725 add_sockaddr_unique(dc_addrs, &num_dcs,
726 &ip_srv_nonsite[i].ss);
730 dc_addrs2 = talloc_zero_array(talloc_tos(),
731 struct tsocket_address *,
734 DEBUG(10, ("%d additional KDCs to test\n", num_dcs));
738 if (dc_addrs2 == NULL) {
742 for (i=0; i<num_dcs; i++) {
743 char addr[INET6_ADDRSTRLEN];
746 print_sockaddr(addr, sizeof(addr), &dc_addrs[i]);
748 ret = tsocket_address_inet_from_strings(dc_addrs2, "ip",
752 status = map_nt_error_from_unix(errno);
753 DEBUG(2,("Failed to create tsocket_address for %s - %s\n",
754 addr, nt_errstr(status)));
759 dc_addrs3 = (const struct tsocket_address * const *)dc_addrs2;
761 status = cldap_multi_netlogon(talloc_tos(),
763 realm, lp_netbios_name(),
764 NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX,
765 MIN(num_dcs, 3), timeval_current_ofs(3, 0), &responses);
766 TALLOC_FREE(dc_addrs2);
769 if (!NT_STATUS_IS_OK(status)) {
770 DEBUG(10,("get_kdc_ip_string: cldap_multi_netlogon failed: "
771 "%s\n", nt_errstr(status)));
775 for (i=0; i<num_dcs; i++) {
778 if (responses[i] == NULL) {
782 /* Append to the string - inefficient but not done often. */
783 new_kdc_str = talloc_asprintf(mem_ctx, "%s\t\tkdc = %s\n",
785 print_canonical_sockaddr_with_port(mem_ctx, &dc_addrs[i]));
786 if (new_kdc_str == NULL) {
789 TALLOC_FREE(kdc_str);
790 kdc_str = new_kdc_str;
794 DEBUG(10, ("get_kdc_ip_string: Returning %s\n", kdc_str));
797 SAFE_FREE(ip_srv_site);
798 SAFE_FREE(ip_srv_nonsite);
803 /************************************************************************
804 Create a specific krb5.conf file in the private directory pointing
805 at a specific kdc for a realm. Keyed off domain name. Sets
806 KRB5_CONFIG environment variable to point to this file. Must be
807 run as root or will fail (which is a good thing :-).
808 ************************************************************************/
810 bool create_local_private_krb5_conf_for_domain(const char *realm,
812 const char *sitename,
813 const struct sockaddr_storage *pss)
816 char *tmpname = NULL;
818 char *file_contents = NULL;
819 char *kdc_ip_string = NULL;
823 char *realm_upper = NULL;
825 char *aes_enctypes = NULL;
828 if (!lp_create_krb5_conf()) {
833 DEBUG(0, ("No realm has been specified! Do you really want to "
834 "join an Active Directory server?\n"));
838 if (domain == NULL || pss == NULL) {
842 dname = lock_path("smb_krb5");
846 if ((mkdir(dname, 0755)==-1) && (errno != EEXIST)) {
847 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
848 "failed to create directory %s. Error was %s\n",
849 dname, strerror(errno) ));
853 tmpname = lock_path("smb_tmp_krb5.XXXXXX");
858 fname = talloc_asprintf(dname, "%s/krb5.conf.%s", dname, domain);
863 DEBUG(10,("create_local_private_krb5_conf_for_domain: fname = %s, realm = %s, domain = %s\n",
864 fname, realm, domain ));
866 realm_upper = talloc_strdup(fname, realm);
867 if (!strupper_m(realm_upper)) {
871 kdc_ip_string = get_kdc_ip_string(dname, realm, sitename, pss);
872 if (!kdc_ip_string) {
876 aes_enctypes = talloc_strdup(fname, "");
877 if (aes_enctypes == NULL) {
881 #ifdef HAVE_ENCTYPE_AES256_CTS_HMAC_SHA1_96
882 aes_enctypes = talloc_asprintf_append(aes_enctypes, "%s", "aes256-cts-hmac-sha1-96 ");
883 if (aes_enctypes == NULL) {
887 #ifdef HAVE_ENCTYPE_AES128_CTS_HMAC_SHA1_96
888 aes_enctypes = talloc_asprintf_append(aes_enctypes, "%s", "aes128-cts-hmac-sha1-96");
889 if (aes_enctypes == NULL) {
894 file_contents = talloc_asprintf(fname,
895 "[libdefaults]\n\tdefault_realm = %s\n"
896 "\tdefault_tgs_enctypes = %s RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
897 "\tdefault_tkt_enctypes = %s RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
898 "\tpreferred_enctypes = %s RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
899 "\tdns_lookup_realm = false\n\n"
900 "[realms]\n\t%s = {\n"
902 realm_upper, aes_enctypes, aes_enctypes, aes_enctypes,
903 realm_upper, kdc_ip_string);
905 if (!file_contents) {
909 flen = strlen(file_contents);
911 mask = umask(S_IRWXO | S_IRWXG);
912 fd = mkstemp(tmpname);
915 DEBUG(0,("create_local_private_krb5_conf_for_domain: smb_mkstemp failed,"
916 " for file %s. Errno %s\n",
917 tmpname, strerror(errno) ));
921 if (fchmod(fd, 0644)==-1) {
922 DEBUG(0,("create_local_private_krb5_conf_for_domain: fchmod failed for %s."
924 tmpname, strerror(errno) ));
930 ret = write(fd, file_contents, flen);
932 DEBUG(0,("create_local_private_krb5_conf_for_domain: write failed,"
933 " returned %d (should be %u). Errno %s\n",
934 (int)ret, (unsigned int)flen, strerror(errno) ));
940 DEBUG(0,("create_local_private_krb5_conf_for_domain: close failed."
941 " Errno %s\n", strerror(errno) ));
946 if (rename(tmpname, fname) == -1) {
947 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
948 "of %s to %s failed. Errno %s\n",
949 tmpname, fname, strerror(errno) ));
954 DEBUG(5,("create_local_private_krb5_conf_for_domain: wrote "
955 "file %s with realm %s KDC list = %s\n",
956 fname, realm_upper, kdc_ip_string));
958 /* Set the environment variable to this file. */
959 setenv("KRB5_CONFIG", fname, 1);
963 #if defined(OVERWRITE_SYSTEM_KRB5_CONF)
965 #define SYSTEM_KRB5_CONF_PATH "/etc/krb5.conf"
966 /* Insanity, sheer insanity..... */
968 if (strequal(realm, lp_realm())) {
969 SMB_STRUCT_STAT sbuf;
971 if (sys_lstat(SYSTEM_KRB5_CONF_PATH, &sbuf, false) == 0) {
972 if (S_ISLNK(sbuf.st_ex_mode) && sbuf.st_ex_size) {
974 size_t alloc_size = sbuf.st_ex_size + 1;
975 char *linkpath = talloc_array(talloc_tos(), char,
980 lret = readlink(SYSTEM_KRB5_CONF_PATH, linkpath,
983 TALLOC_FREE(linkpath);
986 linkpath[lret] = '\0';
988 if (strcmp(linkpath, fname) == 0) {
989 /* Symlink already exists. */
990 TALLOC_FREE(linkpath);
993 TALLOC_FREE(linkpath);
997 /* Try and replace with a symlink. */
998 if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
999 const char *newpath = SYSTEM_KRB5_CONF_PATH ".saved";
1000 if (errno != EEXIST) {
1001 DEBUG(0,("create_local_private_krb5_conf_for_domain: symlink "
1002 "of %s to %s failed. Errno %s\n",
1003 fname, SYSTEM_KRB5_CONF_PATH, strerror(errno) ));
1004 goto done; /* Not a fatal error. */
1007 /* Yes, this is a race conditon... too bad. */
1008 if (rename(SYSTEM_KRB5_CONF_PATH, newpath) == -1) {
1009 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
1010 "of %s to %s failed. Errno %s\n",
1011 SYSTEM_KRB5_CONF_PATH, newpath,
1013 goto done; /* Not a fatal error. */
1016 if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
1017 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
1018 "forced symlink of %s to /etc/krb5.conf failed. Errno %s\n",
1019 fname, strerror(errno) ));
1020 goto done; /* Not a fatal error. */
1027 TALLOC_FREE(tmpname);