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"
32 #include "lib/util/asn1.h"
36 #define LIBADS_CCACHE_NAME "MEMORY:libads"
39 we use a prompter to avoid a crash bug in the kerberos libs when
40 dealing with empty passwords
41 this prompter is just a string copy ...
43 static krb5_error_code
44 kerb_prompter(krb5_context ctx
, void *data
,
48 krb5_prompt prompts
[])
50 if (num_prompts
== 0) return 0;
51 if (num_prompts
== 2) {
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 HAVE_KRB5_PROMPT_TYPE /* Heimdal */
62 if (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 #elif defined(HAVE_KRB5_GET_PROMPT_TYPES) /* MIT */
77 krb5_prompt_type
*prompt_types
= NULL
;
79 prompt_types
= krb5_get_prompt_types(ctx
);
80 if (prompt_types
!= NULL
) {
81 if (prompt_types
[0] == KRB5_PROMPT_TYPE_NEW_PASSWORD
&&
82 prompt_types
[1] == KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN
) {
83 return KRB5KDC_ERR_KEY_EXP
;
89 memset(prompts
[0].reply
->data
, '\0', prompts
[0].reply
->length
);
90 if (prompts
[0].reply
->length
> 0) {
92 strncpy((char *)prompts
[0].reply
->data
, (const char *)data
,
93 prompts
[0].reply
->length
-1);
94 prompts
[0].reply
->length
= strlen((const char *)prompts
[0].reply
->data
);
96 prompts
[0].reply
->length
= 0;
103 simulate a kinit, putting the tgt in the given cache location. If cache_name == NULL
104 place in default cache location.
107 int kerberos_kinit_password_ext(const char *principal
,
108 const char *password
,
111 time_t *renew_till_time
,
112 const char *cache_name
,
114 bool add_netbios_addr
,
115 time_t renewable_time
,
118 krb5_context ctx
= NULL
;
119 krb5_error_code code
= 0;
120 krb5_ccache cc
= NULL
;
121 krb5_principal me
= NULL
;
122 krb5_principal canon_princ
= NULL
;
124 krb5_get_init_creds_opt
*opt
= NULL
;
125 smb_krb5_addresses
*addr
= NULL
;
127 ZERO_STRUCT(my_creds
);
129 initialize_krb5_error_table();
130 if ((code
= krb5_init_context(&ctx
)))
133 if (time_offset
!= 0) {
134 krb5_set_real_time(ctx
, time(NULL
) + time_offset
, 0);
137 DEBUG(10,("kerberos_kinit_password: as %s using [%s] as ccache and config [%s]\n",
139 cache_name
? cache_name
: krb5_cc_default_name(ctx
),
140 getenv("KRB5_CONFIG")));
142 if ((code
= krb5_cc_resolve(ctx
, cache_name
? cache_name
: krb5_cc_default_name(ctx
), &cc
))) {
146 if ((code
= smb_krb5_parse_name(ctx
, principal
, &me
))) {
150 if ((code
= krb5_get_init_creds_opt_alloc(ctx
, &opt
))) {
154 krb5_get_init_creds_opt_set_renew_life(opt
, renewable_time
);
155 krb5_get_init_creds_opt_set_forwardable(opt
, True
);
157 /* Turn on canonicalization for lower case realm support */
158 #ifndef SAMBA4_USES_HEIMDAL /* MIT */
159 krb5_get_init_creds_opt_set_canonicalize(opt
, true);
163 krb5_get_init_creds_opt_set_tkt_life(opt
, 60);
166 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PAC_REQUEST
168 if ((code
= krb5_get_init_creds_opt_set_pac_request(ctx
, opt
, (krb5_boolean
)request_pac
))) {
173 if (add_netbios_addr
) {
174 if ((code
= smb_krb5_gen_netbios_krb5_address(&addr
,
175 lp_netbios_name()))) {
178 krb5_get_init_creds_opt_set_address_list(opt
, addr
->addrs
);
181 if ((code
= krb5_get_init_creds_password(ctx
, &my_creds
, me
, discard_const_p(char,password
),
182 kerb_prompter
, discard_const_p(char, password
),
188 #ifndef SAMBA4_USES_HEIMDAL /* MIT */
189 canon_princ
= my_creds
.client
;
192 if ((code
= krb5_cc_initialize(ctx
, cc
, canon_princ
))) {
196 if ((code
= krb5_cc_store_cred(ctx
, cc
, &my_creds
))) {
201 *expire_time
= (time_t) my_creds
.times
.endtime
;
204 if (renew_till_time
) {
205 *renew_till_time
= (time_t) my_creds
.times
.renew_till
;
211 *ntstatus
= NT_STATUS_OK
;
215 /* fall back to self-made-mapping */
216 *ntstatus
= krb5_to_nt_status(code
);
220 krb5_free_cred_contents(ctx
, &my_creds
);
222 krb5_free_principal(ctx
, me
);
225 smb_krb5_free_addresses(ctx
, addr
);
228 krb5_get_init_creds_opt_free(ctx
, opt
);
231 krb5_cc_close(ctx
, cc
);
234 krb5_free_context(ctx
);
239 int ads_kdestroy(const char *cc_name
)
241 krb5_error_code code
;
242 krb5_context ctx
= NULL
;
243 krb5_ccache cc
= NULL
;
245 initialize_krb5_error_table();
246 if ((code
= krb5_init_context (&ctx
))) {
247 DEBUG(3, ("ads_kdestroy: kdb5_init_context failed: %s\n",
248 error_message(code
)));
253 if ((code
= krb5_cc_default(ctx
, &cc
))) {
254 krb5_free_context(ctx
);
258 if ((code
= krb5_cc_resolve(ctx
, cc_name
, &cc
))) {
259 DEBUG(3, ("ads_kdestroy: krb5_cc_resolve failed: %s\n",
260 error_message(code
)));
261 krb5_free_context(ctx
);
266 if ((code
= krb5_cc_destroy (ctx
, cc
))) {
267 DEBUG(3, ("ads_kdestroy: krb5_cc_destroy failed: %s\n",
268 error_message(code
)));
271 krb5_free_context (ctx
);
275 /************************************************************************
276 Routine to fetch the salting principal for a service. Active
277 Directory may use a non-obvious principal name to generate the salt
278 when it determines the key to use for encrypting tickets for a service,
279 and hopefully we detected that when we joined the domain.
280 ************************************************************************/
282 static char *kerberos_secrets_fetch_salting_principal(const char *service
, int enctype
)
287 if (asprintf(&key
, "%s/%s/enctype=%d",
288 SECRETS_SALTING_PRINCIPAL
, service
, enctype
) == -1) {
291 ret
= (char *)secrets_fetch(key
, NULL
);
296 /************************************************************************
297 Return the standard DES salt key
298 ************************************************************************/
300 char* kerberos_standard_des_salt( void )
304 fstr_sprintf( salt
, "host/%s.%s@", lp_netbios_name(), lp_realm() );
305 (void)strlower_m( salt
);
306 fstrcat( salt
, lp_realm() );
308 return SMB_STRDUP( salt
);
311 /************************************************************************
312 ************************************************************************/
314 static char* des_salt_key( void )
318 if (asprintf(&key
, "%s/DES/%s", SECRETS_SALTING_PRINCIPAL
,
326 /************************************************************************
327 ************************************************************************/
329 bool kerberos_secrets_store_des_salt( const char* salt
)
334 if ( (key
= des_salt_key()) == NULL
) {
335 DEBUG(0,("kerberos_secrets_store_des_salt: failed to generate key!\n"));
340 DEBUG(8,("kerberos_secrets_store_des_salt: deleting salt\n"));
341 secrets_delete( key
);
345 DEBUG(3,("kerberos_secrets_store_des_salt: Storing salt \"%s\"\n", salt
));
347 ret
= secrets_store( key
, salt
, strlen(salt
)+1 );
354 /************************************************************************
355 ************************************************************************/
358 char* kerberos_secrets_fetch_des_salt( void )
362 if ( (key
= des_salt_key()) == NULL
) {
363 DEBUG(0,("kerberos_secrets_fetch_des_salt: failed to generate key!\n"));
367 salt
= (char*)secrets_fetch( key
, NULL
);
374 /************************************************************************
375 Routine to get the salting principal for this service. This is
376 maintained for backwards compatibilty with releases prior to 3.0.24.
377 Since we store the salting principal string only at join, we may have
378 to look for the older tdb keys. Caller must free if return is not null.
379 ************************************************************************/
381 char *kerberos_fetch_salt_princ_for_host_princ(krb5_context context
,
382 const char *host_princ_s
,
386 /* lookup new key first */
388 salt_princ_s
= kerberos_secrets_fetch_des_salt();
389 if (salt_princ_s
== NULL
) {
391 /* look under the old key. If this fails, just use the standard key */
392 salt_princ_s
= kerberos_secrets_fetch_salting_principal(host_princ_s
,
394 if (salt_princ_s
== NULL
) {
395 /* fall back to host/machine.realm@REALM */
396 salt_princ_s
= kerberos_standard_des_salt();
403 int create_kerberos_key_from_string(krb5_context context
,
404 krb5_principal host_princ
,
405 krb5_principal salt_princ
,
408 krb5_enctype enctype
,
413 * Check if we've determined that the KDC is salting keys for this
414 * principal/enctype in a non-obvious way. If it is, try to match
418 KRB5_KEY_DATA(key
) = (KRB5_KEY_DATA_CAST
*)SMB_MALLOC(password
->length
);
419 if (!KRB5_KEY_DATA(key
)) {
422 memcpy(KRB5_KEY_DATA(key
), password
->data
, password
->length
);
423 KRB5_KEY_LENGTH(key
) = password
->length
;
424 KRB5_KEY_TYPE(key
) = enctype
;
427 ret
= smb_krb5_create_key_from_string(context
,
428 salt_princ
? salt_princ
: host_princ
,
436 /************************************************************************
437 Routine to set the salting principal for this service. Active
438 Directory may use a non-obvious principal name to generate the salt
439 when it determines the key to use for encrypting tickets for a service,
440 and hopefully we detected that when we joined the domain.
441 Setting principal to NULL deletes this entry.
442 ************************************************************************/
444 bool kerberos_secrets_store_salting_principal(const char *service
,
446 const char *principal
)
450 krb5_context context
= NULL
;
451 krb5_principal princ
= NULL
;
452 char *princ_s
= NULL
;
453 char *unparsed_name
= NULL
;
454 krb5_error_code code
;
456 if (((code
= krb5_init_context(&context
)) != 0) || (context
== NULL
)) {
457 DEBUG(5, ("kerberos_secrets_store_salting_pricipal: kdb5_init_context failed: %s\n",
458 error_message(code
)));
461 if (strchr_m(service
, '@')) {
462 if (asprintf(&princ_s
, "%s", service
) == -1) {
466 if (asprintf(&princ_s
, "%s@%s", service
, lp_realm()) == -1) {
471 if (smb_krb5_parse_name(context
, princ_s
, &princ
) != 0) {
474 if (smb_krb5_unparse_name(talloc_tos(), context
, princ
, &unparsed_name
) != 0) {
478 if (asprintf(&key
, "%s/%s/enctype=%d",
479 SECRETS_SALTING_PRINCIPAL
, unparsed_name
, enctype
)
484 if ((principal
!= NULL
) && (strlen(principal
) > 0)) {
485 ret
= secrets_store(key
, principal
, strlen(principal
) + 1);
487 ret
= secrets_delete(key
);
494 TALLOC_FREE(unparsed_name
);
497 krb5_free_principal(context
, princ
);
501 krb5_free_context(context
);
508 /************************************************************************
509 ************************************************************************/
511 int kerberos_kinit_password(const char *principal
,
512 const char *password
,
514 const char *cache_name
)
516 return kerberos_kinit_password_ext(principal
,
528 /************************************************************************
529 ************************************************************************/
531 /************************************************************************
532 Create a string list of available kdc's, possibly searching by sitename.
535 If "sitename" is given, the DC's in that site are listed first.
537 ************************************************************************/
539 static void add_sockaddr_unique(struct sockaddr_storage
*addrs
, int *num_addrs
,
540 const struct sockaddr_storage
*addr
)
544 for (i
=0; i
<*num_addrs
; i
++) {
545 if (sockaddr_equal((const struct sockaddr
*)&addrs
[i
],
546 (const struct sockaddr
*)addr
)) {
554 /* print_canonical_sockaddr prints an ipv6 addr in the form of
555 * [ipv6.addr]. This string, when put in a generated krb5.conf file is not
556 * always properly dealt with by some older krb5 libraries. Adding the hard-coded
557 * portnumber workarounds the issue. - gd */
559 static char *print_canonical_sockaddr_with_port(TALLOC_CTX
*mem_ctx
,
560 const struct sockaddr_storage
*pss
)
564 str
= print_canonical_sockaddr(mem_ctx
, pss
);
569 if (pss
->ss_family
!= AF_INET6
) {
573 #if defined(HAVE_IPV6)
574 str
= talloc_asprintf_append(str
, ":88");
579 static char *get_kdc_ip_string(char *mem_ctx
,
581 const char *sitename
,
582 const struct sockaddr_storage
*pss
)
584 TALLOC_CTX
*frame
= talloc_stackframe();
586 struct ip_service
*ip_srv_site
= NULL
;
587 struct ip_service
*ip_srv_nonsite
= NULL
;
591 struct sockaddr_storage
*dc_addrs
;
592 struct tsocket_address
**dc_addrs2
= NULL
;
593 const struct tsocket_address
* const *dc_addrs3
= NULL
;
595 struct netlogon_samlogon_response
**responses
= NULL
;
597 char *kdc_str
= talloc_asprintf(mem_ctx
, "%s\t\tkdc = %s\n", "",
598 print_canonical_sockaddr_with_port(mem_ctx
, pss
));
600 if (kdc_str
== NULL
) {
606 * First get the KDC's only in this site, the rest will be
611 get_kdc_list(realm
, sitename
, &ip_srv_site
, &count_site
);
612 DEBUG(10, ("got %d addresses from site %s search\n", count_site
,
618 get_kdc_list(realm
, NULL
, &ip_srv_nonsite
, &count_nonsite
);
619 DEBUG(10, ("got %d addresses from site-less search\n", count_nonsite
));
621 dc_addrs
= talloc_array(talloc_tos(), struct sockaddr_storage
,
622 count_site
+ count_nonsite
);
623 if (dc_addrs
== NULL
) {
629 for (i
= 0; i
< count_site
; i
++) {
631 (const struct sockaddr
*)pss
,
632 (const struct sockaddr
*)&ip_srv_site
[i
].ss
)) {
633 add_sockaddr_unique(dc_addrs
, &num_dcs
,
638 for (i
= 0; i
< count_nonsite
; i
++) {
640 (const struct sockaddr
*)pss
,
641 (const struct sockaddr
*)&ip_srv_nonsite
[i
].ss
)) {
642 add_sockaddr_unique(dc_addrs
, &num_dcs
,
643 &ip_srv_nonsite
[i
].ss
);
647 dc_addrs2
= talloc_zero_array(talloc_tos(),
648 struct tsocket_address
*,
651 DEBUG(10, ("%d additional KDCs to test\n", num_dcs
));
655 if (dc_addrs2
== NULL
) {
659 for (i
=0; i
<num_dcs
; i
++) {
660 char addr
[INET6_ADDRSTRLEN
];
663 print_sockaddr(addr
, sizeof(addr
), &dc_addrs
[i
]);
665 ret
= tsocket_address_inet_from_strings(dc_addrs2
, "ip",
669 status
= map_nt_error_from_unix(errno
);
670 DEBUG(2,("Failed to create tsocket_address for %s - %s\n",
671 addr
, nt_errstr(status
)));
676 dc_addrs3
= (const struct tsocket_address
* const *)dc_addrs2
;
678 status
= cldap_multi_netlogon(talloc_tos(),
680 realm
, lp_netbios_name(),
681 NETLOGON_NT_VERSION_5
| NETLOGON_NT_VERSION_5EX
,
682 MIN(num_dcs
, 3), timeval_current_ofs(3, 0), &responses
);
683 TALLOC_FREE(dc_addrs2
);
686 if (!NT_STATUS_IS_OK(status
)) {
687 DEBUG(10,("get_kdc_ip_string: cldap_multi_netlogon failed: "
688 "%s\n", nt_errstr(status
)));
692 for (i
=0; i
<num_dcs
; i
++) {
695 if (responses
[i
] == NULL
) {
699 /* Append to the string - inefficient but not done often. */
700 new_kdc_str
= talloc_asprintf(mem_ctx
, "%s\t\tkdc = %s\n",
702 print_canonical_sockaddr_with_port(mem_ctx
, &dc_addrs
[i
]));
703 if (new_kdc_str
== NULL
) {
706 TALLOC_FREE(kdc_str
);
707 kdc_str
= new_kdc_str
;
711 DEBUG(10, ("get_kdc_ip_string: Returning %s\n", kdc_str
));
714 SAFE_FREE(ip_srv_site
);
715 SAFE_FREE(ip_srv_nonsite
);
720 /************************************************************************
721 Create a specific krb5.conf file in the private directory pointing
722 at a specific kdc for a realm. Keyed off domain name. Sets
723 KRB5_CONFIG environment variable to point to this file. Must be
724 run as root or will fail (which is a good thing :-).
725 ************************************************************************/
727 #if !defined(SAMBA4_USES_HEIMDAL) /* MIT version */
728 static char *get_enctypes(TALLOC_CTX
*mem_ctx
)
730 char *aes_enctypes
= NULL
;
731 const char *legacy_enctypes
= "";
732 char *enctypes
= NULL
;
734 aes_enctypes
= talloc_strdup(mem_ctx
, "");
735 if (aes_enctypes
== NULL
) {
739 if (lp_kerberos_encryption_types() == KERBEROS_ETYPES_ALL
||
740 lp_kerberos_encryption_types() == KERBEROS_ETYPES_STRONG
) {
741 #ifdef HAVE_ENCTYPE_AES256_CTS_HMAC_SHA1_96
742 aes_enctypes
= talloc_asprintf_append(
743 aes_enctypes
, "%s", "aes256-cts-hmac-sha1-96 ");
744 if (aes_enctypes
== NULL
) {
748 #ifdef HAVE_ENCTYPE_AES128_CTS_HMAC_SHA1_96
749 aes_enctypes
= talloc_asprintf_append(
750 aes_enctypes
, "%s", "aes128-cts-hmac-sha1-96");
751 if (aes_enctypes
== NULL
) {
757 if (lp_kerberos_encryption_types() == KERBEROS_ETYPES_ALL
||
758 lp_kerberos_encryption_types() == KERBEROS_ETYPES_LEGACY
) {
759 legacy_enctypes
= "RC4-HMAC DES-CBC-CRC DES-CBC-MD5";
763 talloc_asprintf(mem_ctx
, "\tdefault_tgs_enctypes = %s %s\n"
764 "\tdefault_tkt_enctypes = %s %s\n"
765 "\tpreferred_enctypes = %s %s\n",
766 aes_enctypes
, legacy_enctypes
, aes_enctypes
,
767 legacy_enctypes
, aes_enctypes
, legacy_enctypes
);
769 TALLOC_FREE(aes_enctypes
);
772 #else /* Heimdal version */
773 static char *get_enctypes(TALLOC_CTX
*mem_ctx
)
775 const char *aes_enctypes
= "";
776 const char *legacy_enctypes
= "";
777 char *enctypes
= NULL
;
779 if (lp_kerberos_encryption_types() == KERBEROS_ETYPES_ALL
||
780 lp_kerberos_encryption_types() == KERBEROS_ETYPES_STRONG
) {
782 "aes256-cts-hmac-sha1-96 aes128-cts-hmac-sha1-96";
785 if (lp_kerberos_encryption_types() == KERBEROS_ETYPES_ALL
||
786 lp_kerberos_encryption_types() == KERBEROS_ETYPES_LEGACY
) {
787 legacy_enctypes
= "arcfour-hmac-md5 des-cbc-crc des-cbc-md5";
790 enctypes
= talloc_asprintf(mem_ctx
, "\tdefault_etypes = %s %s\n",
791 aes_enctypes
, legacy_enctypes
);
797 bool create_local_private_krb5_conf_for_domain(const char *realm
,
799 const char *sitename
,
800 const struct sockaddr_storage
*pss
)
803 char *tmpname
= NULL
;
805 char *file_contents
= NULL
;
806 char *kdc_ip_string
= NULL
;
810 char *realm_upper
= NULL
;
812 char *enctypes
= NULL
;
813 const char *include_system_krb5
= "";
816 if (!lp_create_krb5_conf()) {
821 DEBUG(0, ("No realm has been specified! Do you really want to "
822 "join an Active Directory server?\n"));
826 if (domain
== NULL
|| pss
== NULL
) {
830 dname
= lock_path("smb_krb5");
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 if (!strupper_m(realm_upper
)) {
859 kdc_ip_string
= get_kdc_ip_string(dname
, realm
, sitename
, pss
);
860 if (!kdc_ip_string
) {
864 enctypes
= get_enctypes(fname
);
865 if (enctypes
== NULL
) {
869 #if !defined(SAMBA4_USES_HEIMDAL)
870 if (lp_include_system_krb5_conf()) {
871 include_system_krb5
= "include /etc/krb5.conf";
876 talloc_asprintf(fname
,
877 "[libdefaults]\n\tdefault_realm = %s\n"
879 "\tdns_lookup_realm = false\n\n"
880 "[realms]\n\t%s = {\n"
887 include_system_krb5
);
889 if (!file_contents
) {
893 flen
= strlen(file_contents
);
895 mask
= umask(S_IRWXO
| S_IRWXG
);
896 fd
= mkstemp(tmpname
);
899 DEBUG(0,("create_local_private_krb5_conf_for_domain: smb_mkstemp failed,"
900 " for file %s. Errno %s\n",
901 tmpname
, strerror(errno
) ));
905 if (fchmod(fd
, 0644)==-1) {
906 DEBUG(0,("create_local_private_krb5_conf_for_domain: fchmod failed for %s."
908 tmpname
, strerror(errno
) ));
914 ret
= write(fd
, file_contents
, flen
);
916 DEBUG(0,("create_local_private_krb5_conf_for_domain: write failed,"
917 " returned %d (should be %u). Errno %s\n",
918 (int)ret
, (unsigned int)flen
, strerror(errno
) ));
924 DEBUG(0,("create_local_private_krb5_conf_for_domain: close failed."
925 " Errno %s\n", strerror(errno
) ));
930 if (rename(tmpname
, fname
) == -1) {
931 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
932 "of %s to %s failed. Errno %s\n",
933 tmpname
, fname
, strerror(errno
) ));
938 DEBUG(5,("create_local_private_krb5_conf_for_domain: wrote "
939 "file %s with realm %s KDC list = %s\n",
940 fname
, realm_upper
, kdc_ip_string
));
942 /* Set the environment variable to this file. */
943 setenv("KRB5_CONFIG", fname
, 1);
947 #if defined(OVERWRITE_SYSTEM_KRB5_CONF)
949 #define SYSTEM_KRB5_CONF_PATH "/etc/krb5.conf"
950 /* Insanity, sheer insanity..... */
952 if (strequal(realm
, lp_realm())) {
953 SMB_STRUCT_STAT sbuf
;
955 if (sys_lstat(SYSTEM_KRB5_CONF_PATH
, &sbuf
, false) == 0) {
956 if (S_ISLNK(sbuf
.st_ex_mode
) && sbuf
.st_ex_size
) {
958 size_t alloc_size
= sbuf
.st_ex_size
+ 1;
959 char *linkpath
= talloc_array(talloc_tos(), char,
964 lret
= readlink(SYSTEM_KRB5_CONF_PATH
, linkpath
,
967 TALLOC_FREE(linkpath
);
970 linkpath
[lret
] = '\0';
972 if (strcmp(linkpath
, fname
) == 0) {
973 /* Symlink already exists. */
974 TALLOC_FREE(linkpath
);
977 TALLOC_FREE(linkpath
);
981 /* Try and replace with a symlink. */
982 if (symlink(fname
, SYSTEM_KRB5_CONF_PATH
) == -1) {
983 const char *newpath
= SYSTEM_KRB5_CONF_PATH
".saved";
984 if (errno
!= EEXIST
) {
985 DEBUG(0,("create_local_private_krb5_conf_for_domain: symlink "
986 "of %s to %s failed. Errno %s\n",
987 fname
, SYSTEM_KRB5_CONF_PATH
, strerror(errno
) ));
988 goto done
; /* Not a fatal error. */
991 /* Yes, this is a race conditon... too bad. */
992 if (rename(SYSTEM_KRB5_CONF_PATH
, newpath
) == -1) {
993 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
994 "of %s to %s failed. Errno %s\n",
995 SYSTEM_KRB5_CONF_PATH
, newpath
,
997 goto done
; /* Not a fatal error. */
1000 if (symlink(fname
, SYSTEM_KRB5_CONF_PATH
) == -1) {
1001 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
1002 "forced symlink of %s to /etc/krb5.conf failed. Errno %s\n",
1003 fname
, strerror(errno
) ));
1004 goto done
; /* Not a fatal error. */
1011 TALLOC_FREE(tmpname
);