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
,
223 lp_netbios_name()))) {
226 krb5_get_init_creds_opt_set_address_list(opt
, addr
->addrs
);
229 if ((code
= krb5_get_init_creds_password(ctx
, &my_creds
, me
, discard_const_p(char,password
),
230 kerb_prompter
, discard_const_p(char, password
),
235 if ((code
= krb5_cc_initialize(ctx
, cc
, me
))) {
239 if ((code
= krb5_cc_store_cred(ctx
, cc
, &my_creds
))) {
244 *expire_time
= (time_t) my_creds
.times
.endtime
;
247 if (renew_till_time
) {
248 *renew_till_time
= (time_t) my_creds
.times
.renew_till
;
257 *ntstatus
= NT_STATUS_OK
;
261 /* try to get ntstatus code out of krb5_error when we have it
262 * inside the krb5_get_init_creds_opt - gd */
264 if (opt
&& smb_krb5_get_ntstatus_from_krb5_error_init_creds_opt(ctx
, opt
, &status
)) {
269 /* fall back to self-made-mapping */
270 *ntstatus
= krb5_to_nt_status(code
);
274 krb5_free_cred_contents(ctx
, &my_creds
);
276 krb5_free_principal(ctx
, me
);
279 smb_krb5_free_addresses(ctx
, addr
);
282 smb_krb5_get_init_creds_opt_free(ctx
, opt
);
285 krb5_cc_close(ctx
, cc
);
288 krb5_free_context(ctx
);
293 int ads_kdestroy(const char *cc_name
)
295 krb5_error_code code
;
296 krb5_context ctx
= NULL
;
297 krb5_ccache cc
= NULL
;
299 initialize_krb5_error_table();
300 if ((code
= krb5_init_context (&ctx
))) {
301 DEBUG(3, ("ads_kdestroy: kdb5_init_context failed: %s\n",
302 error_message(code
)));
307 if ((code
= krb5_cc_default(ctx
, &cc
))) {
308 krb5_free_context(ctx
);
312 if ((code
= krb5_cc_resolve(ctx
, cc_name
, &cc
))) {
313 DEBUG(3, ("ads_kdestroy: krb5_cc_resolve failed: %s\n",
314 error_message(code
)));
315 krb5_free_context(ctx
);
320 if ((code
= krb5_cc_destroy (ctx
, cc
))) {
321 DEBUG(3, ("ads_kdestroy: krb5_cc_destroy failed: %s\n",
322 error_message(code
)));
325 krb5_free_context (ctx
);
329 /************************************************************************
330 Routine to fetch the salting principal for a service. Active
331 Directory may use a non-obvious principal name to generate the salt
332 when it determines the key to use for encrypting tickets for a service,
333 and hopefully we detected that when we joined the domain.
334 ************************************************************************/
336 static char *kerberos_secrets_fetch_salting_principal(const char *service
, int enctype
)
341 if (asprintf(&key
, "%s/%s/enctype=%d",
342 SECRETS_SALTING_PRINCIPAL
, service
, enctype
) == -1) {
345 ret
= (char *)secrets_fetch(key
, NULL
);
350 /************************************************************************
351 Return the standard DES salt key
352 ************************************************************************/
354 char* kerberos_standard_des_salt( void )
358 fstr_sprintf( salt
, "host/%s.%s@", lp_netbios_name(), lp_realm() );
359 (void)strlower_m( salt
);
360 fstrcat( salt
, lp_realm() );
362 return SMB_STRDUP( salt
);
365 /************************************************************************
366 ************************************************************************/
368 static char* des_salt_key( void )
372 if (asprintf(&key
, "%s/DES/%s", SECRETS_SALTING_PRINCIPAL
,
380 /************************************************************************
381 ************************************************************************/
383 bool kerberos_secrets_store_des_salt( const char* salt
)
388 if ( (key
= des_salt_key()) == NULL
) {
389 DEBUG(0,("kerberos_secrets_store_des_salt: failed to generate key!\n"));
394 DEBUG(8,("kerberos_secrets_store_des_salt: deleting salt\n"));
395 secrets_delete( key
);
399 DEBUG(3,("kerberos_secrets_store_des_salt: Storing salt \"%s\"\n", salt
));
401 ret
= secrets_store( key
, salt
, strlen(salt
)+1 );
408 /************************************************************************
409 ************************************************************************/
412 char* kerberos_secrets_fetch_des_salt( void )
416 if ( (key
= des_salt_key()) == NULL
) {
417 DEBUG(0,("kerberos_secrets_fetch_des_salt: failed to generate key!\n"));
421 salt
= (char*)secrets_fetch( key
, NULL
);
428 /************************************************************************
429 Routine to get the salting principal for this service. This is
430 maintained for backwards compatibilty with releases prior to 3.0.24.
431 Since we store the salting principal string only at join, we may have
432 to look for the older tdb keys. Caller must free if return is not null.
433 ************************************************************************/
436 krb5_principal
kerberos_fetch_salt_princ_for_host_princ(krb5_context context
,
437 krb5_principal host_princ
,
440 char *unparsed_name
= NULL
, *salt_princ_s
= NULL
;
441 krb5_principal ret_princ
= NULL
;
443 /* lookup new key first */
445 if ( (salt_princ_s
= kerberos_secrets_fetch_des_salt()) == NULL
) {
447 /* look under the old key. If this fails, just use the standard key */
449 if (smb_krb5_unparse_name(talloc_tos(), context
, host_princ
, &unparsed_name
) != 0) {
450 return (krb5_principal
)NULL
;
452 if ((salt_princ_s
= kerberos_secrets_fetch_salting_principal(unparsed_name
, enctype
)) == NULL
) {
453 /* fall back to host/machine.realm@REALM */
454 salt_princ_s
= kerberos_standard_des_salt();
458 if (smb_krb5_parse_name(context
, salt_princ_s
, &ret_princ
) != 0) {
462 TALLOC_FREE(unparsed_name
);
463 SAFE_FREE(salt_princ_s
);
468 int create_kerberos_key_from_string(krb5_context context
,
469 krb5_principal host_princ
,
472 krb5_enctype enctype
,
475 krb5_principal salt_princ
= NULL
;
478 * Check if we've determined that the KDC is salting keys for this
479 * principal/enctype in a non-obvious way. If it is, try to match
483 KRB5_KEY_DATA(key
) = (KRB5_KEY_DATA_CAST
*)SMB_MALLOC(password
->length
);
484 if (!KRB5_KEY_DATA(key
)) {
487 memcpy(KRB5_KEY_DATA(key
), password
->data
, password
->length
);
488 KRB5_KEY_LENGTH(key
) = password
->length
;
489 KRB5_KEY_TYPE(key
) = enctype
;
492 salt_princ
= kerberos_fetch_salt_princ_for_host_princ(context
, host_princ
, enctype
);
493 ret
= create_kerberos_key_from_string_direct(context
, salt_princ
? salt_princ
: host_princ
, password
, key
, enctype
);
495 krb5_free_principal(context
, salt_princ
);
500 /************************************************************************
501 Routine to set the salting principal for this service. Active
502 Directory may use a non-obvious principal name to generate the salt
503 when it determines the key to use for encrypting tickets for a service,
504 and hopefully we detected that when we joined the domain.
505 Setting principal to NULL deletes this entry.
506 ************************************************************************/
508 bool kerberos_secrets_store_salting_principal(const char *service
,
510 const char *principal
)
514 krb5_context context
= NULL
;
515 krb5_principal princ
= NULL
;
516 char *princ_s
= NULL
;
517 char *unparsed_name
= NULL
;
518 krb5_error_code code
;
520 if (((code
= krb5_init_context(&context
)) != 0) || (context
== NULL
)) {
521 DEBUG(5, ("kerberos_secrets_store_salting_pricipal: kdb5_init_context failed: %s\n",
522 error_message(code
)));
525 if (strchr_m(service
, '@')) {
526 if (asprintf(&princ_s
, "%s", service
) == -1) {
530 if (asprintf(&princ_s
, "%s@%s", service
, lp_realm()) == -1) {
535 if (smb_krb5_parse_name(context
, princ_s
, &princ
) != 0) {
538 if (smb_krb5_unparse_name(talloc_tos(), context
, princ
, &unparsed_name
) != 0) {
542 if (asprintf(&key
, "%s/%s/enctype=%d",
543 SECRETS_SALTING_PRINCIPAL
, unparsed_name
, enctype
)
548 if ((principal
!= NULL
) && (strlen(principal
) > 0)) {
549 ret
= secrets_store(key
, principal
, strlen(principal
) + 1);
551 ret
= secrets_delete(key
);
558 TALLOC_FREE(unparsed_name
);
561 krb5_free_principal(context
, princ
);
565 krb5_free_context(context
);
572 /************************************************************************
573 ************************************************************************/
575 int kerberos_kinit_password(const char *principal
,
576 const char *password
,
578 const char *cache_name
)
580 return kerberos_kinit_password_ext(principal
,
592 /************************************************************************
593 ************************************************************************/
595 /************************************************************************
596 Create a string list of available kdc's, possibly searching by sitename.
599 If "sitename" is given, the DC's in that site are listed first.
601 ************************************************************************/
603 static void add_sockaddr_unique(struct sockaddr_storage
*addrs
, int *num_addrs
,
604 const struct sockaddr_storage
*addr
)
608 for (i
=0; i
<*num_addrs
; i
++) {
609 if (sockaddr_equal((const struct sockaddr
*)&addrs
[i
],
610 (const struct sockaddr
*)addr
)) {
618 /* print_canonical_sockaddr prints an ipv6 addr in the form of
619 * [ipv6.addr]. This string, when put in a generated krb5.conf file is not
620 * always properly dealt with by some older krb5 libraries. Adding the hard-coded
621 * portnumber workarounds the issue. - gd */
623 static char *print_canonical_sockaddr_with_port(TALLOC_CTX
*mem_ctx
,
624 const struct sockaddr_storage
*pss
)
628 str
= print_canonical_sockaddr(mem_ctx
, pss
);
633 if (pss
->ss_family
!= AF_INET6
) {
637 #if defined(HAVE_IPV6)
638 str
= talloc_asprintf_append(str
, ":88");
643 static char *get_kdc_ip_string(char *mem_ctx
,
645 const char *sitename
,
646 const struct sockaddr_storage
*pss
)
648 TALLOC_CTX
*frame
= talloc_stackframe();
650 struct ip_service
*ip_srv_site
= NULL
;
651 struct ip_service
*ip_srv_nonsite
= NULL
;
655 struct sockaddr_storage
*dc_addrs
;
656 struct tsocket_address
**dc_addrs2
= NULL
;
657 const struct tsocket_address
* const *dc_addrs3
= NULL
;
659 struct netlogon_samlogon_response
**responses
= NULL
;
661 char *kdc_str
= talloc_asprintf(mem_ctx
, "%s\tkdc = %s\n", "",
662 print_canonical_sockaddr_with_port(mem_ctx
, pss
));
664 if (kdc_str
== NULL
) {
670 * First get the KDC's only in this site, the rest will be
675 get_kdc_list(realm
, sitename
, &ip_srv_site
, &count_site
);
680 get_kdc_list(realm
, NULL
, &ip_srv_nonsite
, &count_nonsite
);
682 dc_addrs
= talloc_array(talloc_tos(), struct sockaddr_storage
,
683 1 + count_site
+ count_nonsite
);
684 if (dc_addrs
== NULL
) {
691 for (i
=0; i
<count_site
; i
++) {
692 add_sockaddr_unique(dc_addrs
, &num_dcs
, &ip_srv_site
[i
].ss
);
695 for (i
=0; i
<count_nonsite
; i
++) {
696 add_sockaddr_unique(dc_addrs
, &num_dcs
, &ip_srv_nonsite
[i
].ss
);
699 dc_addrs2
= talloc_zero_array(talloc_tos(),
700 struct tsocket_address
*,
702 if (dc_addrs2
== NULL
) {
706 for (i
=0; i
<num_dcs
; i
++) {
707 char addr
[INET6_ADDRSTRLEN
];
710 print_sockaddr(addr
, sizeof(addr
), &dc_addrs
[i
]);
712 ret
= tsocket_address_inet_from_strings(dc_addrs2
, "ip",
716 status
= map_nt_error_from_unix(errno
);
717 DEBUG(2,("Failed to create tsocket_address for %s - %s\n",
718 addr
, nt_errstr(status
)));
723 dc_addrs3
= (const struct tsocket_address
* const *)dc_addrs2
;
725 status
= cldap_multi_netlogon(talloc_tos(),
727 realm
, lp_netbios_name(),
728 NETLOGON_NT_VERSION_5
| NETLOGON_NT_VERSION_5EX
,
729 MIN(num_dcs
, 3), timeval_current_ofs(3, 0), &responses
);
730 TALLOC_FREE(dc_addrs2
);
733 if (!NT_STATUS_IS_OK(status
)) {
734 DEBUG(10,("get_kdc_ip_string: cldap_multi_netlogon failed: "
735 "%s\n", nt_errstr(status
)));
739 kdc_str
= talloc_strdup(mem_ctx
, "");
740 if (kdc_str
== NULL
) {
744 for (i
=0; i
<num_dcs
; i
++) {
747 if (responses
[i
] == NULL
) {
751 /* Append to the string - inefficient but not done often. */
752 new_kdc_str
= talloc_asprintf(mem_ctx
, "%s\tkdc = %s\n",
754 print_canonical_sockaddr_with_port(mem_ctx
, &dc_addrs
[i
]));
755 if (new_kdc_str
== NULL
) {
758 TALLOC_FREE(kdc_str
);
759 kdc_str
= new_kdc_str
;
762 DEBUG(10,("get_kdc_ip_string: Returning %s\n",
767 SAFE_FREE(ip_srv_site
);
768 SAFE_FREE(ip_srv_nonsite
);
773 /************************************************************************
774 Create a specific krb5.conf file in the private directory pointing
775 at a specific kdc for a realm. Keyed off domain name. Sets
776 KRB5_CONFIG environment variable to point to this file. Must be
777 run as root or will fail (which is a good thing :-).
778 ************************************************************************/
780 bool create_local_private_krb5_conf_for_domain(const char *realm
,
782 const char *sitename
,
783 const struct sockaddr_storage
*pss
)
786 char *tmpname
= NULL
;
788 char *file_contents
= NULL
;
789 char *kdc_ip_string
= NULL
;
793 char *realm_upper
= NULL
;
795 char *aes_enctypes
= NULL
;
798 if (!lp_create_krb5_conf()) {
803 DEBUG(0, ("No realm has been specified! Do you really want to "
804 "join an Active Directory server?\n"));
808 if (domain
== NULL
|| pss
== NULL
) {
812 dname
= lock_path("smb_krb5");
816 if ((mkdir(dname
, 0755)==-1) && (errno
!= EEXIST
)) {
817 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
818 "failed to create directory %s. Error was %s\n",
819 dname
, strerror(errno
) ));
823 tmpname
= lock_path("smb_tmp_krb5.XXXXXX");
828 fname
= talloc_asprintf(dname
, "%s/krb5.conf.%s", dname
, domain
);
833 DEBUG(10,("create_local_private_krb5_conf_for_domain: fname = %s, realm = %s, domain = %s\n",
834 fname
, realm
, domain
));
836 realm_upper
= talloc_strdup(fname
, realm
);
837 if (!strupper_m(realm_upper
)) {
841 kdc_ip_string
= get_kdc_ip_string(dname
, realm
, sitename
, pss
);
842 if (!kdc_ip_string
) {
846 aes_enctypes
= talloc_strdup(fname
, "");
847 if (aes_enctypes
== NULL
) {
851 #ifdef HAVE_ENCTYPE_AES256_CTS_HMAC_SHA1_96
852 aes_enctypes
= talloc_asprintf_append(aes_enctypes
, "%s", "aes256-cts-hmac-sha1-96 ");
853 if (aes_enctypes
== NULL
) {
857 #ifdef HAVE_ENCTYPE_AES128_CTS_HMAC_SHA1_96
858 aes_enctypes
= talloc_asprintf_append(aes_enctypes
, "%s", "aes128-cts-hmac-sha1-96");
859 if (aes_enctypes
== NULL
) {
864 file_contents
= talloc_asprintf(fname
,
865 "[libdefaults]\n\tdefault_realm = %s\n"
866 "\tdefault_tgs_enctypes = %s RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
867 "\tdefault_tkt_enctypes = %s RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
868 "\tpreferred_enctypes = %s RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n\n"
869 "[realms]\n\t%s = {\n"
871 realm_upper
, aes_enctypes
, aes_enctypes
, aes_enctypes
,
872 realm_upper
, kdc_ip_string
);
874 if (!file_contents
) {
878 flen
= strlen(file_contents
);
880 mask
= umask(S_IRWXO
| S_IRWXG
);
881 fd
= mkstemp(tmpname
);
884 DEBUG(0,("create_local_private_krb5_conf_for_domain: smb_mkstemp failed,"
885 " for file %s. Errno %s\n",
886 tmpname
, strerror(errno
) ));
890 if (fchmod(fd
, 0644)==-1) {
891 DEBUG(0,("create_local_private_krb5_conf_for_domain: fchmod failed for %s."
893 tmpname
, strerror(errno
) ));
899 ret
= write(fd
, file_contents
, flen
);
901 DEBUG(0,("create_local_private_krb5_conf_for_domain: write failed,"
902 " returned %d (should be %u). Errno %s\n",
903 (int)ret
, (unsigned int)flen
, strerror(errno
) ));
909 DEBUG(0,("create_local_private_krb5_conf_for_domain: close failed."
910 " Errno %s\n", strerror(errno
) ));
915 if (rename(tmpname
, fname
) == -1) {
916 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
917 "of %s to %s failed. Errno %s\n",
918 tmpname
, fname
, strerror(errno
) ));
923 DEBUG(5,("create_local_private_krb5_conf_for_domain: wrote "
924 "file %s with realm %s KDC list = %s\n",
925 fname
, realm_upper
, kdc_ip_string
));
927 /* Set the environment variable to this file. */
928 setenv("KRB5_CONFIG", fname
, 1);
932 #if defined(OVERWRITE_SYSTEM_KRB5_CONF)
934 #define SYSTEM_KRB5_CONF_PATH "/etc/krb5.conf"
935 /* Insanity, sheer insanity..... */
937 if (strequal(realm
, lp_realm())) {
938 SMB_STRUCT_STAT sbuf
;
940 if (sys_lstat(SYSTEM_KRB5_CONF_PATH
, &sbuf
, false) == 0) {
941 if (S_ISLNK(sbuf
.st_ex_mode
) && sbuf
.st_ex_size
) {
943 size_t alloc_size
= sbuf
.st_ex_size
+ 1;
944 char *linkpath
= talloc_array(talloc_tos(), char,
949 lret
= readlink(SYSTEM_KRB5_CONF_PATH
, linkpath
,
952 TALLOC_FREE(linkpath
);
955 linkpath
[lret
] = '\0';
957 if (strcmp(linkpath
, fname
) == 0) {
958 /* Symlink already exists. */
959 TALLOC_FREE(linkpath
);
962 TALLOC_FREE(linkpath
);
966 /* Try and replace with a symlink. */
967 if (symlink(fname
, SYSTEM_KRB5_CONF_PATH
) == -1) {
968 const char *newpath
= SYSTEM_KRB5_CONF_PATH
".saved";
969 if (errno
!= EEXIST
) {
970 DEBUG(0,("create_local_private_krb5_conf_for_domain: symlink "
971 "of %s to %s failed. Errno %s\n",
972 fname
, SYSTEM_KRB5_CONF_PATH
, strerror(errno
) ));
973 goto done
; /* Not a fatal error. */
976 /* Yes, this is a race conditon... too bad. */
977 if (rename(SYSTEM_KRB5_CONF_PATH
, newpath
) == -1) {
978 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
979 "of %s to %s failed. Errno %s\n",
980 SYSTEM_KRB5_CONF_PATH
, newpath
,
982 goto done
; /* Not a fatal error. */
985 if (symlink(fname
, SYSTEM_KRB5_CONF_PATH
) == -1) {
986 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
987 "forced symlink of %s to /etc/krb5.conf failed. Errno %s\n",
988 fname
, strerror(errno
) ));
989 goto done
; /* Not a fatal error. */
996 TALLOC_FREE(tmpname
);