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/>.
28 #define DEFAULT_KRB5_PORT 88
30 #define LIBADS_CCACHE_NAME "MEMORY:libads"
33 we use a prompter to avoid a crash bug in the kerberos libs when
34 dealing with empty passwords
35 this prompter is just a string copy ...
37 static krb5_error_code
38 kerb_prompter(krb5_context ctx
, void *data
,
42 krb5_prompt prompts
[])
44 if (num_prompts
== 0) return 0;
46 memset(prompts
[0].reply
->data
, '\0', prompts
[0].reply
->length
);
47 if (prompts
[0].reply
->length
> 0) {
49 strncpy(prompts
[0].reply
->data
, (const char *)data
,
50 prompts
[0].reply
->length
-1);
51 prompts
[0].reply
->length
= strlen(prompts
[0].reply
->data
);
53 prompts
[0].reply
->length
= 0;
59 static bool smb_krb5_get_ntstatus_from_krb5_error(krb5_error
*error
,
63 DATA_BLOB unwrapped_edata
;
65 struct KRB5_EDATA_NTSTATUS parsed_edata
;
66 enum ndr_err_code ndr_err
;
68 #ifdef HAVE_E_DATA_POINTER_IN_KRB5_ERROR
69 edata
= data_blob(error
->e_data
->data
, error
->e_data
->length
);
71 edata
= data_blob(error
->e_data
.data
, error
->e_data
.length
);
72 #endif /* HAVE_E_DATA_POINTER_IN_KRB5_ERROR */
75 dump_data(10, edata
.data
, edata
.length
);
76 #endif /* DEVELOPER */
78 mem_ctx
= talloc_init("smb_krb5_get_ntstatus_from_krb5_error");
79 if (mem_ctx
== NULL
) {
80 data_blob_free(&edata
);
84 if (!unwrap_edata_ntstatus(mem_ctx
, &edata
, &unwrapped_edata
)) {
85 data_blob_free(&edata
);
90 data_blob_free(&edata
);
92 ndr_err
= ndr_pull_struct_blob_all(&unwrapped_edata
, mem_ctx
, NULL
,
94 (ndr_pull_flags_fn_t
)ndr_pull_KRB5_EDATA_NTSTATUS
);
95 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
96 data_blob_free(&unwrapped_edata
);
101 data_blob_free(&unwrapped_edata
);
104 *nt_status
= parsed_edata
.ntstatus
;
107 TALLOC_FREE(mem_ctx
);
112 static bool smb_krb5_get_ntstatus_from_krb5_error_init_creds_opt(krb5_context ctx
,
113 krb5_get_init_creds_opt
*opt
,
117 krb5_error
*error
= NULL
;
119 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_GET_ERROR
120 ret
= krb5_get_init_creds_opt_get_error(ctx
, opt
, &error
);
122 DEBUG(1,("krb5_get_init_creds_opt_get_error gave: %s\n",
123 error_message(ret
)));
126 #endif /* HAVE_KRB5_GET_INIT_CREDS_OPT_GET_ERROR */
129 DEBUG(1,("no krb5_error\n"));
133 #ifdef HAVE_E_DATA_POINTER_IN_KRB5_ERROR
134 if (!error
->e_data
) {
136 if (error
->e_data
.data
== NULL
) {
137 #endif /* HAVE_E_DATA_POINTER_IN_KRB5_ERROR */
138 DEBUG(1,("no edata in krb5_error\n"));
139 krb5_free_error(ctx
, error
);
143 ret
= smb_krb5_get_ntstatus_from_krb5_error(error
, nt_status
);
145 krb5_free_error(ctx
, error
);
151 simulate a kinit, putting the tgt in the given cache location. If cache_name == NULL
152 place in default cache location.
155 int kerberos_kinit_password_ext(const char *principal
,
156 const char *password
,
159 time_t *renew_till_time
,
160 const char *cache_name
,
162 bool add_netbios_addr
,
163 time_t renewable_time
,
166 krb5_context ctx
= NULL
;
167 krb5_error_code code
= 0;
168 krb5_ccache cc
= NULL
;
169 krb5_principal me
= NULL
;
171 krb5_get_init_creds_opt
*opt
= NULL
;
172 smb_krb5_addresses
*addr
= NULL
;
174 ZERO_STRUCT(my_creds
);
176 initialize_krb5_error_table();
177 if ((code
= krb5_init_context(&ctx
)))
180 if (time_offset
!= 0) {
181 krb5_set_real_time(ctx
, time(NULL
) + time_offset
, 0);
184 DEBUG(10,("kerberos_kinit_password: as %s using [%s] as ccache and config [%s]\n",
186 cache_name
? cache_name
: krb5_cc_default_name(ctx
),
187 getenv("KRB5_CONFIG")));
189 if ((code
= krb5_cc_resolve(ctx
, cache_name
? cache_name
: krb5_cc_default_name(ctx
), &cc
))) {
193 if ((code
= smb_krb5_parse_name(ctx
, principal
, &me
))) {
197 if ((code
= smb_krb5_get_init_creds_opt_alloc(ctx
, &opt
))) {
201 krb5_get_init_creds_opt_set_renew_life(opt
, renewable_time
);
202 krb5_get_init_creds_opt_set_forwardable(opt
, True
);
205 krb5_get_init_creds_opt_set_tkt_life(opt
, 60);
208 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PAC_REQUEST
210 if ((code
= krb5_get_init_creds_opt_set_pac_request(ctx
, opt
, (krb5_boolean
)request_pac
))) {
215 if (add_netbios_addr
) {
216 if ((code
= smb_krb5_gen_netbios_krb5_address(&addr
))) {
219 krb5_get_init_creds_opt_set_address_list(opt
, addr
->addrs
);
222 if ((code
= krb5_get_init_creds_password(ctx
, &my_creds
, me
, CONST_DISCARD(char *,password
),
223 kerb_prompter
, CONST_DISCARD(char *,password
),
228 if ((code
= krb5_cc_initialize(ctx
, cc
, me
))) {
232 if ((code
= krb5_cc_store_cred(ctx
, cc
, &my_creds
))) {
237 *expire_time
= (time_t) my_creds
.times
.endtime
;
240 if (renew_till_time
) {
241 *renew_till_time
= (time_t) my_creds
.times
.renew_till
;
250 *ntstatus
= NT_STATUS_OK
;
254 /* try to get ntstatus code out of krb5_error when we have it
255 * inside the krb5_get_init_creds_opt - gd */
257 if (opt
&& smb_krb5_get_ntstatus_from_krb5_error_init_creds_opt(ctx
, opt
, &status
)) {
262 /* fall back to self-made-mapping */
263 *ntstatus
= krb5_to_nt_status(code
);
267 krb5_free_cred_contents(ctx
, &my_creds
);
269 krb5_free_principal(ctx
, me
);
272 smb_krb5_free_addresses(ctx
, addr
);
275 smb_krb5_get_init_creds_opt_free(ctx
, opt
);
278 krb5_cc_close(ctx
, cc
);
281 krb5_free_context(ctx
);
288 /* run kinit to setup our ccache */
289 int ads_kinit_password(ADS_STRUCT
*ads
)
293 const char *account_name
;
296 if (ads
->auth
.flags
& ADS_AUTH_USER_CREDS
) {
297 account_name
= ads
->auth
.user_name
;
298 goto got_accountname
;
302 /* this will end up getting a ticket for DOMAIN@RUSTED.REA.LM */
303 account_name
= lp_workgroup();
305 /* always use the sAMAccountName for security = domain */
306 /* global_myname()$@REA.LM */
307 if ( lp_security() == SEC_DOMAIN
) {
308 fstr_sprintf( acct_name
, "%s$", global_myname() );
309 account_name
= acct_name
;
312 /* This looks like host/global_myname()@REA.LM */
313 account_name
= ads
->auth
.user_name
;
317 if (asprintf(&s
, "%s@%s", account_name
, ads
->auth
.realm
) == -1) {
318 return KRB5_CC_NOMEM
;
321 if (!ads
->auth
.password
) {
323 return KRB5_LIBOS_CANTREADPWD
;
326 ret
= kerberos_kinit_password_ext(s
, ads
->auth
.password
, ads
->auth
.time_offset
,
327 &ads
->auth
.tgt_expire
, NULL
, NULL
, False
, False
, ads
->auth
.renewable
,
331 DEBUG(0,("kerberos_kinit_password %s failed: %s\n",
332 s
, error_message(ret
)));
338 int ads_kdestroy(const char *cc_name
)
340 krb5_error_code code
;
341 krb5_context ctx
= NULL
;
342 krb5_ccache cc
= NULL
;
344 initialize_krb5_error_table();
345 if ((code
= krb5_init_context (&ctx
))) {
346 DEBUG(3, ("ads_kdestroy: kdb5_init_context failed: %s\n",
347 error_message(code
)));
352 if ((code
= krb5_cc_default(ctx
, &cc
))) {
353 krb5_free_context(ctx
);
357 if ((code
= krb5_cc_resolve(ctx
, cc_name
, &cc
))) {
358 DEBUG(3, ("ads_kdestroy: krb5_cc_resolve failed: %s\n",
359 error_message(code
)));
360 krb5_free_context(ctx
);
365 if ((code
= krb5_cc_destroy (ctx
, cc
))) {
366 DEBUG(3, ("ads_kdestroy: krb5_cc_destroy failed: %s\n",
367 error_message(code
)));
370 krb5_free_context (ctx
);
374 /************************************************************************
375 Routine to fetch the salting principal for a service. Active
376 Directory may use a non-obvious principal name to generate the salt
377 when it determines the key to use for encrypting tickets for a service,
378 and hopefully we detected that when we joined the domain.
379 ************************************************************************/
381 static char *kerberos_secrets_fetch_salting_principal(const char *service
, int enctype
)
386 if (asprintf(&key
, "%s/%s/enctype=%d",
387 SECRETS_SALTING_PRINCIPAL
, service
, enctype
) == -1) {
390 ret
= (char *)secrets_fetch(key
, NULL
);
395 /************************************************************************
396 Return the standard DES salt key
397 ************************************************************************/
399 char* kerberos_standard_des_salt( void )
403 fstr_sprintf( salt
, "host/%s.%s@", global_myname(), lp_realm() );
405 fstrcat( salt
, lp_realm() );
407 return SMB_STRDUP( salt
);
410 /************************************************************************
411 ************************************************************************/
413 static char* des_salt_key( void )
417 if (asprintf(&key
, "%s/DES/%s", SECRETS_SALTING_PRINCIPAL
,
425 /************************************************************************
426 ************************************************************************/
428 bool kerberos_secrets_store_des_salt( const char* salt
)
433 if ( (key
= des_salt_key()) == NULL
) {
434 DEBUG(0,("kerberos_secrets_store_des_salt: failed to generate key!\n"));
439 DEBUG(8,("kerberos_secrets_store_des_salt: deleting salt\n"));
440 secrets_delete( key
);
444 DEBUG(3,("kerberos_secrets_store_des_salt: Storing salt \"%s\"\n", salt
));
446 ret
= secrets_store( key
, salt
, strlen(salt
)+1 );
453 /************************************************************************
454 ************************************************************************/
456 char* kerberos_secrets_fetch_des_salt( void )
460 if ( (key
= des_salt_key()) == NULL
) {
461 DEBUG(0,("kerberos_secrets_fetch_des_salt: failed to generate key!\n"));
465 salt
= (char*)secrets_fetch( key
, NULL
);
472 /************************************************************************
473 Routine to get the default realm from the kerberos credentials cache.
474 Caller must free if the return value is not NULL.
475 ************************************************************************/
477 char *kerberos_get_default_realm_from_ccache( void )
480 krb5_context ctx
= NULL
;
481 krb5_ccache cc
= NULL
;
482 krb5_principal princ
= NULL
;
484 initialize_krb5_error_table();
485 if (krb5_init_context(&ctx
)) {
489 DEBUG(5,("kerberos_get_default_realm_from_ccache: "
490 "Trying to read krb5 cache: %s\n",
491 krb5_cc_default_name(ctx
)));
492 if (krb5_cc_default(ctx
, &cc
)) {
493 DEBUG(0,("kerberos_get_default_realm_from_ccache: "
494 "failed to read default cache\n"));
497 if (krb5_cc_get_principal(ctx
, cc
, &princ
)) {
498 DEBUG(0,("kerberos_get_default_realm_from_ccache: "
499 "failed to get default principal\n"));
503 #if defined(HAVE_KRB5_PRINCIPAL_GET_REALM)
504 realm
= SMB_STRDUP(krb5_principal_get_realm(ctx
, princ
));
505 #elif defined(HAVE_KRB5_PRINC_REALM)
507 krb5_data
*realm_data
= krb5_princ_realm(ctx
, princ
);
508 realm
= SMB_STRNDUP(realm_data
->data
, realm_data
->length
);
516 krb5_free_principal(ctx
, princ
);
519 krb5_cc_close(ctx
, cc
);
521 krb5_free_context(ctx
);
528 /************************************************************************
529 Routine to get the salting principal for this service. This is
530 maintained for backwards compatibilty with releases prior to 3.0.24.
531 Since we store the salting principal string only at join, we may have
532 to look for the older tdb keys. Caller must free if return is not null.
533 ************************************************************************/
535 krb5_principal
kerberos_fetch_salt_princ_for_host_princ(krb5_context context
,
536 krb5_principal host_princ
,
539 char *unparsed_name
= NULL
, *salt_princ_s
= NULL
;
540 krb5_principal ret_princ
= NULL
;
542 /* lookup new key first */
544 if ( (salt_princ_s
= kerberos_secrets_fetch_des_salt()) == NULL
) {
546 /* look under the old key. If this fails, just use the standard key */
548 if (smb_krb5_unparse_name(talloc_tos(), context
, host_princ
, &unparsed_name
) != 0) {
549 return (krb5_principal
)NULL
;
551 if ((salt_princ_s
= kerberos_secrets_fetch_salting_principal(unparsed_name
, enctype
)) == NULL
) {
552 /* fall back to host/machine.realm@REALM */
553 salt_princ_s
= kerberos_standard_des_salt();
557 if (smb_krb5_parse_name(context
, salt_princ_s
, &ret_princ
) != 0) {
561 TALLOC_FREE(unparsed_name
);
562 SAFE_FREE(salt_princ_s
);
567 /************************************************************************
568 Routine to set the salting principal for this service. Active
569 Directory may use a non-obvious principal name to generate the salt
570 when it determines the key to use for encrypting tickets for a service,
571 and hopefully we detected that when we joined the domain.
572 Setting principal to NULL deletes this entry.
573 ************************************************************************/
575 bool kerberos_secrets_store_salting_principal(const char *service
,
577 const char *principal
)
581 krb5_context context
= NULL
;
582 krb5_principal princ
= NULL
;
583 char *princ_s
= NULL
;
584 char *unparsed_name
= NULL
;
585 krb5_error_code code
;
587 if (((code
= krb5_init_context(&context
)) != 0) || (context
== NULL
)) {
588 DEBUG(5, ("kerberos_secrets_store_salting_pricipal: kdb5_init_context failed: %s\n",
589 error_message(code
)));
592 if (strchr_m(service
, '@')) {
593 if (asprintf(&princ_s
, "%s", service
) == -1) {
597 if (asprintf(&princ_s
, "%s@%s", service
, lp_realm()) == -1) {
602 if (smb_krb5_parse_name(context
, princ_s
, &princ
) != 0) {
606 if (smb_krb5_unparse_name(talloc_tos(), context
, princ
, &unparsed_name
) != 0) {
610 if (asprintf(&key
, "%s/%s/enctype=%d",
611 SECRETS_SALTING_PRINCIPAL
, unparsed_name
, enctype
)
616 if ((principal
!= NULL
) && (strlen(principal
) > 0)) {
617 ret
= secrets_store(key
, principal
, strlen(principal
) + 1);
619 ret
= secrets_delete(key
);
626 TALLOC_FREE(unparsed_name
);
629 krb5_free_principal(context
, princ
);
633 krb5_free_context(context
);
640 /************************************************************************
641 ************************************************************************/
643 int kerberos_kinit_password(const char *principal
,
644 const char *password
,
646 const char *cache_name
)
648 return kerberos_kinit_password_ext(principal
,
660 /************************************************************************
661 ************************************************************************/
663 static char *print_kdc_line(char *mem_ctx
,
664 const char *prev_line
,
665 const struct sockaddr_storage
*pss
)
667 char *kdc_str
= NULL
;
669 if (pss
->ss_family
== AF_INET
) {
670 kdc_str
= talloc_asprintf(mem_ctx
, "%s\tkdc = %s\n",
672 print_canonical_sockaddr(mem_ctx
, pss
));
674 char addr
[INET6_ADDRSTRLEN
];
675 uint16_t port
= get_sockaddr_port(pss
);
677 if (port
!= 0 && port
!= DEFAULT_KRB5_PORT
) {
678 /* Currently for IPv6 we can't specify a non-default
679 krb5 port with an address, as this requires a ':'.
680 Resolve to a name. */
681 char hostname
[MAX_DNS_NAME_LENGTH
];
682 int ret
= sys_getnameinfo((const struct sockaddr
*)pss
,
684 hostname
, sizeof(hostname
),
688 DEBUG(0,("print_kdc_line: can't resolve name "
689 "for kdc with non-default port %s. "
691 print_canonical_sockaddr(mem_ctx
, pss
),
694 /* Success, use host:port */
695 kdc_str
= talloc_asprintf(mem_ctx
,
701 kdc_str
= talloc_asprintf(mem_ctx
, "%s\tkdc = %s\n",
711 /************************************************************************
712 Create a string list of available kdc's, possibly searching by sitename.
715 If "sitename" is given, the DC's in that site are listed first.
717 ************************************************************************/
719 static char *get_kdc_ip_string(char *mem_ctx
,
721 const char *sitename
,
722 struct sockaddr_storage
*pss
)
725 struct ip_service
*ip_srv_site
= NULL
;
726 struct ip_service
*ip_srv_nonsite
= NULL
;
729 char *kdc_str
= print_kdc_line(mem_ctx
, "", pss
);
731 if (kdc_str
== NULL
) {
736 * First get the KDC's only in this site, the rest will be
742 get_kdc_list(realm
, sitename
, &ip_srv_site
, &count_site
);
744 for (i
= 0; i
< count_site
; i
++) {
745 if (sockaddr_equal((struct sockaddr
*)&ip_srv_site
[i
].ss
,
746 (struct sockaddr
*)pss
)) {
749 /* Append to the string - inefficient
750 * but not done often. */
751 kdc_str
= print_kdc_line(mem_ctx
,
755 SAFE_FREE(ip_srv_site
);
763 get_kdc_list(realm
, NULL
, &ip_srv_nonsite
, &count_nonsite
);
765 for (i
= 0; i
< count_nonsite
; i
++) {
768 if (sockaddr_equal((struct sockaddr
*)&ip_srv_nonsite
[i
].ss
, (struct sockaddr
*)pss
)) {
772 /* Ensure this isn't an IP already seen (YUK! this is n*n....) */
773 for (j
= 0; j
< count_site
; j
++) {
774 if (sockaddr_equal((struct sockaddr
*)&ip_srv_nonsite
[i
].ss
,
775 (struct sockaddr
*)&ip_srv_site
[j
].ss
)) {
778 /* As the lists are sorted we can break early if nonsite > site. */
779 if (ip_service_compare(&ip_srv_nonsite
[i
], &ip_srv_site
[j
]) > 0) {
787 /* Append to the string - inefficient but not done often. */
788 kdc_str
= print_kdc_line(mem_ctx
,
790 &ip_srv_nonsite
[i
].ss
);
792 SAFE_FREE(ip_srv_site
);
793 SAFE_FREE(ip_srv_nonsite
);
799 SAFE_FREE(ip_srv_site
);
800 SAFE_FREE(ip_srv_nonsite
);
802 DEBUG(10,("get_kdc_ip_string: Returning %s\n",
808 /************************************************************************
809 Create a specific krb5.conf file in the private directory pointing
810 at a specific kdc for a realm. Keyed off domain name. Sets
811 KRB5_CONFIG environment variable to point to this file. Must be
812 run as root or will fail (which is a good thing :-).
813 ************************************************************************/
815 bool create_local_private_krb5_conf_for_domain(const char *realm
,
817 const char *sitename
,
818 struct sockaddr_storage
*pss
)
820 char *dname
= lock_path("smb_krb5");
821 char *tmpname
= NULL
;
823 char *file_contents
= NULL
;
824 char *kdc_ip_string
= NULL
;
828 char *realm_upper
= NULL
;
834 if ((mkdir(dname
, 0755)==-1) && (errno
!= EEXIST
)) {
835 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
836 "failed to create directory %s. Error was %s\n",
837 dname
, strerror(errno
) ));
841 tmpname
= lock_path("smb_tmp_krb5.XXXXXX");
846 fname
= talloc_asprintf(dname
, "%s/krb5.conf.%s", dname
, domain
);
851 DEBUG(10,("create_local_private_krb5_conf_for_domain: fname = %s, realm = %s, domain = %s\n",
852 fname
, realm
, domain
));
854 realm_upper
= talloc_strdup(fname
, realm
);
855 strupper_m(realm_upper
);
857 kdc_ip_string
= get_kdc_ip_string(dname
, realm
, sitename
, pss
);
858 if (!kdc_ip_string
) {
862 file_contents
= talloc_asprintf(fname
,
863 "[libdefaults]\n\tdefault_realm = %s\n"
864 "\tdefault_tgs_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
865 "\tdefault_tkt_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
866 "\tpreferred_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n\n"
867 "[realms]\n\t%s = {\n"
869 realm_upper
, realm_upper
, kdc_ip_string
);
871 if (!file_contents
) {
875 flen
= strlen(file_contents
);
877 fd
= smb_mkstemp(tmpname
);
879 DEBUG(0,("create_local_private_krb5_conf_for_domain: smb_mkstemp failed,"
880 " for file %s. Errno %s\n",
881 tmpname
, strerror(errno
) ));
885 if (fchmod(fd
, 0644)==-1) {
886 DEBUG(0,("create_local_private_krb5_conf_for_domain: fchmod failed for %s."
888 tmpname
, strerror(errno
) ));
894 ret
= write(fd
, file_contents
, flen
);
896 DEBUG(0,("create_local_private_krb5_conf_for_domain: write failed,"
897 " returned %d (should be %u). Errno %s\n",
898 (int)ret
, (unsigned int)flen
, strerror(errno
) ));
904 DEBUG(0,("create_local_private_krb5_conf_for_domain: close failed."
905 " Errno %s\n", strerror(errno
) ));
910 if (rename(tmpname
, fname
) == -1) {
911 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
912 "of %s to %s failed. Errno %s\n",
913 tmpname
, fname
, strerror(errno
) ));
918 DEBUG(5,("create_local_private_krb5_conf_for_domain: wrote "
919 "file %s with realm %s KDC list = %s\n",
920 fname
, realm_upper
, kdc_ip_string
));
922 /* Set the environment variable to this file. */
923 setenv("KRB5_CONFIG", fname
, 1);
927 #if defined(OVERWRITE_SYSTEM_KRB5_CONF)
929 #define SYSTEM_KRB5_CONF_PATH "/etc/krb5.conf"
930 /* Insanity, sheer insanity..... */
932 if (strequal(realm
, lp_realm())) {
933 char linkpath
[PATH_MAX
+1];
936 lret
= readlink(SYSTEM_KRB5_CONF_PATH
, linkpath
, sizeof(linkpath
)-1);
938 linkpath
[lret
] = '\0';
941 if (lret
!= -1 || strcmp(linkpath
, fname
) == 0) {
942 /* Symlink already exists. */
946 /* Try and replace with a symlink. */
947 if (symlink(fname
, SYSTEM_KRB5_CONF_PATH
) == -1) {
948 const char *newpath
= SYSTEM_KRB5_CONF_PATH
## ".saved";
949 if (errno
!= EEXIST
) {
950 DEBUG(0,("create_local_private_krb5_conf_for_domain: symlink "
951 "of %s to %s failed. Errno %s\n",
952 fname
, SYSTEM_KRB5_CONF_PATH
, strerror(errno
) ));
953 goto done
; /* Not a fatal error. */
956 /* Yes, this is a race conditon... too bad. */
957 if (rename(SYSTEM_KRB5_CONF_PATH
, newpath
) == -1) {
958 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
959 "of %s to %s failed. Errno %s\n",
960 SYSTEM_KRB5_CONF_PATH
, newpath
,
962 goto done
; /* Not a fatal error. */
965 if (symlink(fname
, SYSTEM_KRB5_CONF_PATH
) == -1) {
966 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
967 "forced symlink of %s to /etc/krb5.conf failed. Errno %s\n",
968 fname
, strerror(errno
) ));
969 goto done
; /* Not a fatal error. */
976 TALLOC_FREE(tmpname
);