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 DEFAULT_KRB5_PORT 88
37 #define LIBADS_CCACHE_NAME "MEMORY:libads"
40 we use a prompter to avoid a crash bug in the kerberos libs when
41 dealing with empty passwords
42 this prompter is just a string copy ...
44 static krb5_error_code
45 kerb_prompter(krb5_context ctx
, void *data
,
49 krb5_prompt prompts
[])
51 if (num_prompts
== 0) return 0;
53 memset(prompts
[0].reply
->data
, '\0', prompts
[0].reply
->length
);
54 if (prompts
[0].reply
->length
> 0) {
56 strncpy((char *)prompts
[0].reply
->data
, (const char *)data
,
57 prompts
[0].reply
->length
-1);
58 prompts
[0].reply
->length
= strlen((const char *)prompts
[0].reply
->data
);
60 prompts
[0].reply
->length
= 0;
66 static bool smb_krb5_get_ntstatus_from_krb5_error(krb5_error
*error
,
70 DATA_BLOB unwrapped_edata
;
72 struct KRB5_EDATA_NTSTATUS parsed_edata
;
73 enum ndr_err_code ndr_err
;
75 #ifdef HAVE_E_DATA_POINTER_IN_KRB5_ERROR
76 edata
= data_blob(error
->e_data
->data
, error
->e_data
->length
);
78 edata
= data_blob(error
->e_data
.data
, error
->e_data
.length
);
79 #endif /* HAVE_E_DATA_POINTER_IN_KRB5_ERROR */
82 dump_data(10, edata
.data
, edata
.length
);
83 #endif /* DEVELOPER */
85 mem_ctx
= talloc_init("smb_krb5_get_ntstatus_from_krb5_error");
86 if (mem_ctx
== NULL
) {
87 data_blob_free(&edata
);
91 if (!unwrap_edata_ntstatus(mem_ctx
, &edata
, &unwrapped_edata
)) {
92 data_blob_free(&edata
);
97 data_blob_free(&edata
);
99 ndr_err
= ndr_pull_struct_blob_all(&unwrapped_edata
, mem_ctx
,
100 &parsed_edata
, (ndr_pull_flags_fn_t
)ndr_pull_KRB5_EDATA_NTSTATUS
);
101 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
102 data_blob_free(&unwrapped_edata
);
103 TALLOC_FREE(mem_ctx
);
107 data_blob_free(&unwrapped_edata
);
110 *nt_status
= parsed_edata
.ntstatus
;
113 TALLOC_FREE(mem_ctx
);
118 static bool smb_krb5_get_ntstatus_from_krb5_error_init_creds_opt(krb5_context ctx
,
119 krb5_get_init_creds_opt
*opt
,
123 krb5_error
*error
= NULL
;
125 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_GET_ERROR
126 ret
= krb5_get_init_creds_opt_get_error(ctx
, opt
, &error
);
128 DEBUG(1,("krb5_get_init_creds_opt_get_error gave: %s\n",
129 error_message(ret
)));
132 #endif /* HAVE_KRB5_GET_INIT_CREDS_OPT_GET_ERROR */
135 DEBUG(1,("no krb5_error\n"));
139 #ifdef HAVE_E_DATA_POINTER_IN_KRB5_ERROR
140 if (!error
->e_data
) {
142 if (error
->e_data
.data
== NULL
) {
143 #endif /* HAVE_E_DATA_POINTER_IN_KRB5_ERROR */
144 DEBUG(1,("no edata in krb5_error\n"));
145 krb5_free_error(ctx
, error
);
149 ret
= smb_krb5_get_ntstatus_from_krb5_error(error
, nt_status
);
151 krb5_free_error(ctx
, error
);
157 simulate a kinit, putting the tgt in the given cache location. If cache_name == NULL
158 place in default cache location.
161 int kerberos_kinit_password_ext(const char *principal
,
162 const char *password
,
165 time_t *renew_till_time
,
166 const char *cache_name
,
168 bool add_netbios_addr
,
169 time_t renewable_time
,
172 krb5_context ctx
= NULL
;
173 krb5_error_code code
= 0;
174 krb5_ccache cc
= NULL
;
175 krb5_principal me
= NULL
;
177 krb5_get_init_creds_opt
*opt
= NULL
;
178 smb_krb5_addresses
*addr
= NULL
;
180 ZERO_STRUCT(my_creds
);
182 initialize_krb5_error_table();
183 if ((code
= krb5_init_context(&ctx
)))
186 if (time_offset
!= 0) {
187 krb5_set_real_time(ctx
, time(NULL
) + time_offset
, 0);
190 DEBUG(10,("kerberos_kinit_password: as %s using [%s] as ccache and config [%s]\n",
192 cache_name
? cache_name
: krb5_cc_default_name(ctx
),
193 getenv("KRB5_CONFIG")));
195 if ((code
= krb5_cc_resolve(ctx
, cache_name
? cache_name
: krb5_cc_default_name(ctx
), &cc
))) {
199 if ((code
= smb_krb5_parse_name(ctx
, principal
, &me
))) {
203 if ((code
= smb_krb5_get_init_creds_opt_alloc(ctx
, &opt
))) {
207 krb5_get_init_creds_opt_set_renew_life(opt
, renewable_time
);
208 krb5_get_init_creds_opt_set_forwardable(opt
, True
);
211 krb5_get_init_creds_opt_set_tkt_life(opt
, 60);
214 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PAC_REQUEST
216 if ((code
= krb5_get_init_creds_opt_set_pac_request(ctx
, opt
, (krb5_boolean
)request_pac
))) {
221 if (add_netbios_addr
) {
222 if ((code
= smb_krb5_gen_netbios_krb5_address(&addr
))) {
225 krb5_get_init_creds_opt_set_address_list(opt
, addr
->addrs
);
228 if ((code
= krb5_get_init_creds_password(ctx
, &my_creds
, me
, discard_const_p(char,password
),
229 kerb_prompter
, discard_const_p(char, password
),
234 if ((code
= krb5_cc_initialize(ctx
, cc
, me
))) {
238 if ((code
= krb5_cc_store_cred(ctx
, cc
, &my_creds
))) {
243 *expire_time
= (time_t) my_creds
.times
.endtime
;
246 if (renew_till_time
) {
247 *renew_till_time
= (time_t) my_creds
.times
.renew_till
;
256 *ntstatus
= NT_STATUS_OK
;
260 /* try to get ntstatus code out of krb5_error when we have it
261 * inside the krb5_get_init_creds_opt - gd */
263 if (opt
&& smb_krb5_get_ntstatus_from_krb5_error_init_creds_opt(ctx
, opt
, &status
)) {
268 /* fall back to self-made-mapping */
269 *ntstatus
= krb5_to_nt_status(code
);
273 krb5_free_cred_contents(ctx
, &my_creds
);
275 krb5_free_principal(ctx
, me
);
278 smb_krb5_free_addresses(ctx
, addr
);
281 smb_krb5_get_init_creds_opt_free(ctx
, opt
);
284 krb5_cc_close(ctx
, cc
);
287 krb5_free_context(ctx
);
292 int ads_kdestroy(const char *cc_name
)
294 krb5_error_code code
;
295 krb5_context ctx
= NULL
;
296 krb5_ccache cc
= NULL
;
298 initialize_krb5_error_table();
299 if ((code
= krb5_init_context (&ctx
))) {
300 DEBUG(3, ("ads_kdestroy: kdb5_init_context failed: %s\n",
301 error_message(code
)));
306 if ((code
= krb5_cc_default(ctx
, &cc
))) {
307 krb5_free_context(ctx
);
311 if ((code
= krb5_cc_resolve(ctx
, cc_name
, &cc
))) {
312 DEBUG(3, ("ads_kdestroy: krb5_cc_resolve failed: %s\n",
313 error_message(code
)));
314 krb5_free_context(ctx
);
319 if ((code
= krb5_cc_destroy (ctx
, cc
))) {
320 DEBUG(3, ("ads_kdestroy: krb5_cc_destroy failed: %s\n",
321 error_message(code
)));
324 krb5_free_context (ctx
);
328 /************************************************************************
329 Routine to fetch the salting principal for a service. Active
330 Directory may use a non-obvious principal name to generate the salt
331 when it determines the key to use for encrypting tickets for a service,
332 and hopefully we detected that when we joined the domain.
333 ************************************************************************/
335 static char *kerberos_secrets_fetch_salting_principal(const char *service
, int enctype
)
340 if (asprintf(&key
, "%s/%s/enctype=%d",
341 SECRETS_SALTING_PRINCIPAL
, service
, enctype
) == -1) {
344 ret
= (char *)secrets_fetch(key
, NULL
);
349 /************************************************************************
350 Return the standard DES salt key
351 ************************************************************************/
353 char* kerberos_standard_des_salt( void )
357 fstr_sprintf( salt
, "host/%s.%s@", lp_netbios_name(), lp_realm() );
359 fstrcat( salt
, lp_realm() );
361 return SMB_STRDUP( salt
);
364 /************************************************************************
365 ************************************************************************/
367 static char* des_salt_key( void )
371 if (asprintf(&key
, "%s/DES/%s", SECRETS_SALTING_PRINCIPAL
,
379 /************************************************************************
380 ************************************************************************/
382 bool kerberos_secrets_store_des_salt( const char* salt
)
387 if ( (key
= des_salt_key()) == NULL
) {
388 DEBUG(0,("kerberos_secrets_store_des_salt: failed to generate key!\n"));
393 DEBUG(8,("kerberos_secrets_store_des_salt: deleting salt\n"));
394 secrets_delete( key
);
398 DEBUG(3,("kerberos_secrets_store_des_salt: Storing salt \"%s\"\n", salt
));
400 ret
= secrets_store( key
, salt
, strlen(salt
)+1 );
407 /************************************************************************
408 ************************************************************************/
410 char* kerberos_secrets_fetch_des_salt( void )
414 if ( (key
= des_salt_key()) == NULL
) {
415 DEBUG(0,("kerberos_secrets_fetch_des_salt: failed to generate key!\n"));
419 salt
= (char*)secrets_fetch( key
, NULL
);
426 /************************************************************************
427 Routine to get the salting principal for this service. This is
428 maintained for backwards compatibilty with releases prior to 3.0.24.
429 Since we store the salting principal string only at join, we may have
430 to look for the older tdb keys. Caller must free if return is not null.
431 ************************************************************************/
433 krb5_principal
kerberos_fetch_salt_princ_for_host_princ(krb5_context context
,
434 krb5_principal host_princ
,
437 char *unparsed_name
= NULL
, *salt_princ_s
= NULL
;
438 krb5_principal ret_princ
= NULL
;
440 /* lookup new key first */
442 if ( (salt_princ_s
= kerberos_secrets_fetch_des_salt()) == NULL
) {
444 /* look under the old key. If this fails, just use the standard key */
446 if (smb_krb5_unparse_name(talloc_tos(), context
, host_princ
, &unparsed_name
) != 0) {
447 return (krb5_principal
)NULL
;
449 if ((salt_princ_s
= kerberos_secrets_fetch_salting_principal(unparsed_name
, enctype
)) == NULL
) {
450 /* fall back to host/machine.realm@REALM */
451 salt_princ_s
= kerberos_standard_des_salt();
455 if (smb_krb5_parse_name(context
, salt_princ_s
, &ret_princ
) != 0) {
459 TALLOC_FREE(unparsed_name
);
460 SAFE_FREE(salt_princ_s
);
465 /************************************************************************
466 Routine to set the salting principal for this service. Active
467 Directory may use a non-obvious principal name to generate the salt
468 when it determines the key to use for encrypting tickets for a service,
469 and hopefully we detected that when we joined the domain.
470 Setting principal to NULL deletes this entry.
471 ************************************************************************/
473 bool kerberos_secrets_store_salting_principal(const char *service
,
475 const char *principal
)
479 krb5_context context
= NULL
;
480 krb5_principal princ
= NULL
;
481 char *princ_s
= NULL
;
482 char *unparsed_name
= NULL
;
483 krb5_error_code code
;
485 if (((code
= krb5_init_context(&context
)) != 0) || (context
== NULL
)) {
486 DEBUG(5, ("kerberos_secrets_store_salting_pricipal: kdb5_init_context failed: %s\n",
487 error_message(code
)));
490 if (strchr_m(service
, '@')) {
491 if (asprintf(&princ_s
, "%s", service
) == -1) {
495 if (asprintf(&princ_s
, "%s@%s", service
, lp_realm()) == -1) {
500 if (smb_krb5_parse_name(context
, princ_s
, &princ
) != 0) {
503 if (smb_krb5_unparse_name(talloc_tos(), context
, princ
, &unparsed_name
) != 0) {
507 if (asprintf(&key
, "%s/%s/enctype=%d",
508 SECRETS_SALTING_PRINCIPAL
, unparsed_name
, enctype
)
513 if ((principal
!= NULL
) && (strlen(principal
) > 0)) {
514 ret
= secrets_store(key
, principal
, strlen(principal
) + 1);
516 ret
= secrets_delete(key
);
523 TALLOC_FREE(unparsed_name
);
526 krb5_free_principal(context
, princ
);
530 krb5_free_context(context
);
537 /************************************************************************
538 ************************************************************************/
540 int kerberos_kinit_password(const char *principal
,
541 const char *password
,
543 const char *cache_name
)
545 return kerberos_kinit_password_ext(principal
,
557 /************************************************************************
558 ************************************************************************/
560 static char *print_kdc_line(char *mem_ctx
,
561 const char *prev_line
,
562 const struct sockaddr_storage
*pss
,
563 const char *kdc_name
)
565 char addr
[INET6_ADDRSTRLEN
];
566 uint16_t port
= get_sockaddr_port(pss
);
568 if (pss
->ss_family
== AF_INET
) {
569 return talloc_asprintf(mem_ctx
, "%s\tkdc = %s\n",
571 print_canonical_sockaddr(mem_ctx
, pss
));
578 DEBUG(10, ("print_kdc_line: IPv6 case for kdc_name: %s, port: %d\n",
581 if (port
!= 0 && port
!= DEFAULT_KRB5_PORT
) {
582 /* Currently for IPv6 we can't specify a non-default
583 krb5 port with an address, as this requires a ':'.
584 Resolve to a name. */
585 char hostname
[MAX_DNS_NAME_LENGTH
];
586 int ret
= sys_getnameinfo((const struct sockaddr
*)pss
,
588 hostname
, sizeof(hostname
),
592 DEBUG(0,("print_kdc_line: can't resolve name "
593 "for kdc with non-default port %s. "
595 print_canonical_sockaddr(mem_ctx
, pss
),
599 /* Success, use host:port */
600 return talloc_asprintf(mem_ctx
,
607 /* no krb5 lib currently supports "kdc = ipv6 address"
608 * at all, so just fill in just the kdc_name if we have
609 * it and let the krb5 lib figure out the appropriate
610 * ipv6 address - gd */
613 return talloc_asprintf(mem_ctx
, "%s\tkdc = %s\n",
614 prev_line
, kdc_name
);
617 return talloc_asprintf(mem_ctx
, "%s\tkdc = %s\n",
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 static char *get_kdc_ip_string(char *mem_ctx
,
649 const char *sitename
,
650 const struct sockaddr_storage
*pss
,
651 const char *kdc_name
)
653 TALLOC_CTX
*frame
= talloc_stackframe();
655 struct ip_service
*ip_srv_site
= NULL
;
656 struct ip_service
*ip_srv_nonsite
= NULL
;
660 struct sockaddr_storage
*dc_addrs
;
661 struct tsocket_address
**dc_addrs2
= NULL
;
662 const struct tsocket_address
* const *dc_addrs3
= NULL
;
664 struct netlogon_samlogon_response
**responses
= NULL
;
666 char *kdc_str
= print_kdc_line(mem_ctx
, "", pss
, kdc_name
);
668 if (kdc_str
== NULL
) {
673 * First get the KDC's only in this site, the rest will be
678 get_kdc_list(realm
, sitename
, &ip_srv_site
, &count_site
);
683 get_kdc_list(realm
, NULL
, &ip_srv_nonsite
, &count_nonsite
);
685 dc_addrs
= talloc_array(talloc_tos(), struct sockaddr_storage
,
686 1 + count_site
+ count_nonsite
);
687 if (dc_addrs
== NULL
) {
694 for (i
=0; i
<count_site
; i
++) {
695 add_sockaddr_unique(dc_addrs
, &num_dcs
, &ip_srv_site
[i
].ss
);
698 for (i
=0; i
<count_nonsite
; i
++) {
699 add_sockaddr_unique(dc_addrs
, &num_dcs
, &ip_srv_nonsite
[i
].ss
);
702 dc_addrs2
= talloc_zero_array(talloc_tos(),
703 struct tsocket_address
*,
705 if (dc_addrs2
== NULL
) {
709 for (i
=0; i
<num_dcs
; i
++) {
710 char addr
[INET6_ADDRSTRLEN
];
713 print_sockaddr(addr
, sizeof(addr
), &dc_addrs
[i
]);
715 ret
= tsocket_address_inet_from_strings(dc_addrs2
, "ip",
719 status
= map_nt_error_from_unix(errno
);
720 DEBUG(2,("Failed to create tsocket_address for %s - %s\n",
721 addr
, nt_errstr(status
)));
726 dc_addrs3
= (const struct tsocket_address
* const *)dc_addrs2
;
728 status
= cldap_multi_netlogon(talloc_tos(),
730 realm
, lp_netbios_name(),
731 NETLOGON_NT_VERSION_5
| NETLOGON_NT_VERSION_5EX
,
732 MIN(num_dcs
, 3), timeval_current_ofs(3, 0), &responses
);
733 TALLOC_FREE(dc_addrs2
);
736 if (!NT_STATUS_IS_OK(status
)) {
737 DEBUG(10,("get_kdc_ip_string: cldap_multi_netlogon failed: "
738 "%s\n", nt_errstr(status
)));
742 kdc_str
= talloc_strdup(mem_ctx
, "");
743 if (kdc_str
== NULL
) {
747 for (i
=0; i
<num_dcs
; i
++) {
750 if (responses
[i
] == NULL
) {
754 /* Append to the string - inefficient but not done often. */
755 new_kdc_str
= print_kdc_line(mem_ctx
, kdc_str
,
758 if (new_kdc_str
== NULL
) {
761 TALLOC_FREE(kdc_str
);
762 kdc_str
= new_kdc_str
;
765 DEBUG(10,("get_kdc_ip_string: Returning %s\n",
770 SAFE_FREE(ip_srv_site
);
771 SAFE_FREE(ip_srv_nonsite
);
776 /************************************************************************
777 Create a specific krb5.conf file in the private directory pointing
778 at a specific kdc for a realm. Keyed off domain name. Sets
779 KRB5_CONFIG environment variable to point to this file. Must be
780 run as root or will fail (which is a good thing :-).
781 ************************************************************************/
783 bool create_local_private_krb5_conf_for_domain(const char *realm
,
785 const char *sitename
,
786 const struct sockaddr_storage
*pss
,
787 const char *kdc_name
)
790 char *tmpname
= NULL
;
792 char *file_contents
= NULL
;
793 char *kdc_ip_string
= NULL
;
797 char *realm_upper
= NULL
;
800 if (!lp_create_krb5_conf()) {
804 dname
= lock_path("smb_krb5");
808 if ((mkdir(dname
, 0755)==-1) && (errno
!= EEXIST
)) {
809 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
810 "failed to create directory %s. Error was %s\n",
811 dname
, strerror(errno
) ));
815 tmpname
= lock_path("smb_tmp_krb5.XXXXXX");
820 fname
= talloc_asprintf(dname
, "%s/krb5.conf.%s", dname
, domain
);
825 DEBUG(10,("create_local_private_krb5_conf_for_domain: fname = %s, realm = %s, domain = %s\n",
826 fname
, realm
, domain
));
828 realm_upper
= talloc_strdup(fname
, realm
);
829 strupper_m(realm_upper
);
831 kdc_ip_string
= get_kdc_ip_string(dname
, realm
, sitename
, pss
, kdc_name
);
832 if (!kdc_ip_string
) {
836 file_contents
= talloc_asprintf(fname
,
837 "[libdefaults]\n\tdefault_realm = %s\n"
838 "\tdefault_tgs_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
839 "\tdefault_tkt_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
840 "\tpreferred_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n\n"
841 "[realms]\n\t%s = {\n"
843 realm_upper
, realm_upper
, kdc_ip_string
);
845 if (!file_contents
) {
849 flen
= strlen(file_contents
);
851 fd
= mkstemp(tmpname
);
853 DEBUG(0,("create_local_private_krb5_conf_for_domain: smb_mkstemp failed,"
854 " for file %s. Errno %s\n",
855 tmpname
, strerror(errno
) ));
859 if (fchmod(fd
, 0644)==-1) {
860 DEBUG(0,("create_local_private_krb5_conf_for_domain: fchmod failed for %s."
862 tmpname
, strerror(errno
) ));
868 ret
= write(fd
, file_contents
, flen
);
870 DEBUG(0,("create_local_private_krb5_conf_for_domain: write failed,"
871 " returned %d (should be %u). Errno %s\n",
872 (int)ret
, (unsigned int)flen
, strerror(errno
) ));
878 DEBUG(0,("create_local_private_krb5_conf_for_domain: close failed."
879 " Errno %s\n", strerror(errno
) ));
884 if (rename(tmpname
, fname
) == -1) {
885 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
886 "of %s to %s failed. Errno %s\n",
887 tmpname
, fname
, strerror(errno
) ));
892 DEBUG(5,("create_local_private_krb5_conf_for_domain: wrote "
893 "file %s with realm %s KDC list = %s\n",
894 fname
, realm_upper
, kdc_ip_string
));
896 /* Set the environment variable to this file. */
897 setenv("KRB5_CONFIG", fname
, 1);
901 #if defined(OVERWRITE_SYSTEM_KRB5_CONF)
903 #define SYSTEM_KRB5_CONF_PATH "/etc/krb5.conf"
904 /* Insanity, sheer insanity..... */
906 if (strequal(realm
, lp_realm())) {
907 SMB_STRUCT_STAT sbuf
;
909 if (sys_lstat(SYSTEM_KRB5_CONF_PATH
, &sbuf
, false) == 0) {
910 if (S_ISLNK(sbuf
.st_ex_mode
) && sbuf
.st_ex_size
) {
912 size_t alloc_size
= sbuf
.st_ex_size
+ 1;
913 char *linkpath
= talloc_array(talloc_tos(), char,
918 lret
= readlink(SYSTEM_KRB5_CONF_PATH
, linkpath
,
921 TALLOC_FREE(linkpath
);
924 linkpath
[lret
] = '\0';
926 if (strcmp(linkpath
, fname
) == 0) {
927 /* Symlink already exists. */
928 TALLOC_FREE(linkpath
);
931 TALLOC_FREE(linkpath
);
935 /* Try and replace with a symlink. */
936 if (symlink(fname
, SYSTEM_KRB5_CONF_PATH
) == -1) {
937 const char *newpath
= SYSTEM_KRB5_CONF_PATH
".saved";
938 if (errno
!= EEXIST
) {
939 DEBUG(0,("create_local_private_krb5_conf_for_domain: symlink "
940 "of %s to %s failed. Errno %s\n",
941 fname
, SYSTEM_KRB5_CONF_PATH
, strerror(errno
) ));
942 goto done
; /* Not a fatal error. */
945 /* Yes, this is a race conditon... too bad. */
946 if (rename(SYSTEM_KRB5_CONF_PATH
, newpath
) == -1) {
947 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
948 "of %s to %s failed. Errno %s\n",
949 SYSTEM_KRB5_CONF_PATH
, newpath
,
951 goto done
; /* Not a fatal error. */
954 if (symlink(fname
, SYSTEM_KRB5_CONF_PATH
) == -1) {
955 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
956 "forced symlink of %s to /etc/krb5.conf failed. Errno %s\n",
957 fname
, strerror(errno
) ));
958 goto done
; /* Not a fatal error. */
965 TALLOC_FREE(tmpname
);