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;
50 if (num_prompts
== 2) {
52 * only heimdal has a prompt type and we need to deal with it here to
55 * removing the prompter completely is not an option as at least these
56 * versions would crash: heimdal-1.0.2 and heimdal-1.1. Later heimdal
57 * version have looping detection and return with a proper error code.
60 #if HAVE_KRB5_PROMPT_TYPE /* Heimdal */
61 if (prompts
[0].type
== KRB5_PROMPT_TYPE_NEW_PASSWORD
&&
62 prompts
[1].type
== KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN
) {
64 * We don't want to change passwords here. We're
65 * called from heimal when the KDC returns
66 * KRB5KDC_ERR_KEY_EXPIRED, but at this point we don't
67 * have the chance to ask the user for a new
68 * password. If we return 0 (i.e. success), we will be
69 * spinning in the endless for-loop in
70 * change_password() in
71 * source4/heimdal/lib/krb5/init_creds_pw.c:526ff
73 return KRB5KDC_ERR_KEY_EXPIRED
;
75 #elif defined(HAVE_KRB5_GET_PROMPT_TYPES) /* MIT */
76 krb5_prompt_type
*prompt_types
= NULL
;
78 prompt_types
= krb5_get_prompt_types(ctx
);
79 if (prompt_types
!= NULL
) {
80 if (prompt_types
[0] == KRB5_PROMPT_TYPE_NEW_PASSWORD
&&
81 prompt_types
[1] == KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN
) {
82 return KRB5KDC_ERR_KEY_EXP
;
88 memset(prompts
[0].reply
->data
, '\0', prompts
[0].reply
->length
);
89 if (prompts
[0].reply
->length
> 0) {
91 strncpy((char *)prompts
[0].reply
->data
, (const char *)data
,
92 prompts
[0].reply
->length
-1);
93 prompts
[0].reply
->length
= strlen((const char *)prompts
[0].reply
->data
);
95 prompts
[0].reply
->length
= 0;
101 static bool smb_krb5_get_ntstatus_from_krb5_error(krb5_error
*error
,
105 DATA_BLOB unwrapped_edata
;
107 struct KRB5_EDATA_NTSTATUS parsed_edata
;
108 enum ndr_err_code ndr_err
;
110 #ifdef HAVE_E_DATA_POINTER_IN_KRB5_ERROR
111 edata
= data_blob(error
->e_data
->data
, error
->e_data
->length
);
113 edata
= data_blob(error
->e_data
.data
, error
->e_data
.length
);
114 #endif /* HAVE_E_DATA_POINTER_IN_KRB5_ERROR */
117 dump_data(10, edata
.data
, edata
.length
);
118 #endif /* DEVELOPER */
120 mem_ctx
= talloc_init("smb_krb5_get_ntstatus_from_krb5_error");
121 if (mem_ctx
== NULL
) {
122 data_blob_free(&edata
);
126 if (!unwrap_edata_ntstatus(mem_ctx
, &edata
, &unwrapped_edata
)) {
127 data_blob_free(&edata
);
128 TALLOC_FREE(mem_ctx
);
132 data_blob_free(&edata
);
134 ndr_err
= ndr_pull_struct_blob_all(&unwrapped_edata
, mem_ctx
,
135 &parsed_edata
, (ndr_pull_flags_fn_t
)ndr_pull_KRB5_EDATA_NTSTATUS
);
136 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
137 data_blob_free(&unwrapped_edata
);
138 TALLOC_FREE(mem_ctx
);
142 data_blob_free(&unwrapped_edata
);
145 *nt_status
= parsed_edata
.ntstatus
;
148 TALLOC_FREE(mem_ctx
);
153 static bool smb_krb5_get_ntstatus_from_krb5_error_init_creds_opt(krb5_context ctx
,
154 krb5_get_init_creds_opt
*opt
,
158 krb5_error
*error
= NULL
;
160 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_GET_ERROR
161 ret
= krb5_get_init_creds_opt_get_error(ctx
, opt
, &error
);
163 DEBUG(1,("krb5_get_init_creds_opt_get_error gave: %s\n",
164 error_message(ret
)));
167 #endif /* HAVE_KRB5_GET_INIT_CREDS_OPT_GET_ERROR */
170 DEBUG(1,("no krb5_error\n"));
174 #ifdef HAVE_E_DATA_POINTER_IN_KRB5_ERROR
175 if (!error
->e_data
) {
177 if (error
->e_data
.data
== NULL
) {
178 #endif /* HAVE_E_DATA_POINTER_IN_KRB5_ERROR */
179 DEBUG(1,("no edata in krb5_error\n"));
180 krb5_free_error(ctx
, error
);
184 ret
= smb_krb5_get_ntstatus_from_krb5_error(error
, nt_status
);
186 krb5_free_error(ctx
, error
);
192 simulate a kinit, putting the tgt in the given cache location. If cache_name == NULL
193 place in default cache location.
196 int kerberos_kinit_password_ext(const char *principal
,
197 const char *password
,
200 time_t *renew_till_time
,
201 const char *cache_name
,
203 bool add_netbios_addr
,
204 time_t renewable_time
,
207 krb5_context ctx
= NULL
;
208 krb5_error_code code
= 0;
209 krb5_ccache cc
= NULL
;
210 krb5_principal me
= NULL
;
212 krb5_get_init_creds_opt
*opt
= NULL
;
213 smb_krb5_addresses
*addr
= NULL
;
215 ZERO_STRUCT(my_creds
);
217 initialize_krb5_error_table();
218 if ((code
= krb5_init_context(&ctx
)))
221 if (time_offset
!= 0) {
222 krb5_set_real_time(ctx
, time(NULL
) + time_offset
, 0);
225 DEBUG(10,("kerberos_kinit_password: as %s using [%s] as ccache and config [%s]\n",
227 cache_name
? cache_name
: krb5_cc_default_name(ctx
),
228 getenv("KRB5_CONFIG")));
230 if ((code
= krb5_cc_resolve(ctx
, cache_name
? cache_name
: krb5_cc_default_name(ctx
), &cc
))) {
234 if ((code
= smb_krb5_parse_name(ctx
, principal
, &me
))) {
238 if ((code
= smb_krb5_get_init_creds_opt_alloc(ctx
, &opt
))) {
242 krb5_get_init_creds_opt_set_renew_life(opt
, renewable_time
);
243 krb5_get_init_creds_opt_set_forwardable(opt
, True
);
246 krb5_get_init_creds_opt_set_tkt_life(opt
, 60);
249 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PAC_REQUEST
251 if ((code
= krb5_get_init_creds_opt_set_pac_request(ctx
, opt
, (krb5_boolean
)request_pac
))) {
256 if (add_netbios_addr
) {
257 if ((code
= smb_krb5_gen_netbios_krb5_address(&addr
,
258 lp_netbios_name()))) {
261 krb5_get_init_creds_opt_set_address_list(opt
, addr
->addrs
);
264 if ((code
= krb5_get_init_creds_password(ctx
, &my_creds
, me
, discard_const_p(char,password
),
265 kerb_prompter
, discard_const_p(char, password
),
270 if ((code
= krb5_cc_initialize(ctx
, cc
, me
))) {
274 if ((code
= krb5_cc_store_cred(ctx
, cc
, &my_creds
))) {
279 *expire_time
= (time_t) my_creds
.times
.endtime
;
282 if (renew_till_time
) {
283 *renew_till_time
= (time_t) my_creds
.times
.renew_till
;
292 *ntstatus
= NT_STATUS_OK
;
296 /* try to get ntstatus code out of krb5_error when we have it
297 * inside the krb5_get_init_creds_opt - gd */
299 if (opt
&& smb_krb5_get_ntstatus_from_krb5_error_init_creds_opt(ctx
, opt
, &status
)) {
304 /* fall back to self-made-mapping */
305 *ntstatus
= krb5_to_nt_status(code
);
309 krb5_free_cred_contents(ctx
, &my_creds
);
311 krb5_free_principal(ctx
, me
);
314 smb_krb5_free_addresses(ctx
, addr
);
317 smb_krb5_get_init_creds_opt_free(ctx
, opt
);
320 krb5_cc_close(ctx
, cc
);
323 krb5_free_context(ctx
);
328 int ads_kdestroy(const char *cc_name
)
330 krb5_error_code code
;
331 krb5_context ctx
= NULL
;
332 krb5_ccache cc
= NULL
;
334 initialize_krb5_error_table();
335 if ((code
= krb5_init_context (&ctx
))) {
336 DEBUG(3, ("ads_kdestroy: kdb5_init_context failed: %s\n",
337 error_message(code
)));
342 if ((code
= krb5_cc_default(ctx
, &cc
))) {
343 krb5_free_context(ctx
);
347 if ((code
= krb5_cc_resolve(ctx
, cc_name
, &cc
))) {
348 DEBUG(3, ("ads_kdestroy: krb5_cc_resolve failed: %s\n",
349 error_message(code
)));
350 krb5_free_context(ctx
);
355 if ((code
= krb5_cc_destroy (ctx
, cc
))) {
356 DEBUG(3, ("ads_kdestroy: krb5_cc_destroy failed: %s\n",
357 error_message(code
)));
360 krb5_free_context (ctx
);
364 /************************************************************************
365 Routine to fetch the salting principal for a service. Active
366 Directory may use a non-obvious principal name to generate the salt
367 when it determines the key to use for encrypting tickets for a service,
368 and hopefully we detected that when we joined the domain.
369 ************************************************************************/
371 static char *kerberos_secrets_fetch_salting_principal(const char *service
, int enctype
)
376 if (asprintf(&key
, "%s/%s/enctype=%d",
377 SECRETS_SALTING_PRINCIPAL
, service
, enctype
) == -1) {
380 ret
= (char *)secrets_fetch(key
, NULL
);
385 /************************************************************************
386 Return the standard DES salt key
387 ************************************************************************/
389 char* kerberos_standard_des_salt( void )
393 fstr_sprintf( salt
, "host/%s.%s@", lp_netbios_name(), lp_realm() );
394 (void)strlower_m( salt
);
395 fstrcat( salt
, lp_realm() );
397 return SMB_STRDUP( salt
);
400 /************************************************************************
401 ************************************************************************/
403 static char* des_salt_key( void )
407 if (asprintf(&key
, "%s/DES/%s", SECRETS_SALTING_PRINCIPAL
,
415 /************************************************************************
416 ************************************************************************/
418 bool kerberos_secrets_store_des_salt( const char* salt
)
423 if ( (key
= des_salt_key()) == NULL
) {
424 DEBUG(0,("kerberos_secrets_store_des_salt: failed to generate key!\n"));
429 DEBUG(8,("kerberos_secrets_store_des_salt: deleting salt\n"));
430 secrets_delete( key
);
434 DEBUG(3,("kerberos_secrets_store_des_salt: Storing salt \"%s\"\n", salt
));
436 ret
= secrets_store( key
, salt
, strlen(salt
)+1 );
443 /************************************************************************
444 ************************************************************************/
447 char* kerberos_secrets_fetch_des_salt( void )
451 if ( (key
= des_salt_key()) == NULL
) {
452 DEBUG(0,("kerberos_secrets_fetch_des_salt: failed to generate key!\n"));
456 salt
= (char*)secrets_fetch( key
, NULL
);
463 /************************************************************************
464 Routine to get the salting principal for this service. This is
465 maintained for backwards compatibilty with releases prior to 3.0.24.
466 Since we store the salting principal string only at join, we may have
467 to look for the older tdb keys. Caller must free if return is not null.
468 ************************************************************************/
470 char *kerberos_fetch_salt_princ_for_host_princ(krb5_context context
,
471 const char *host_princ_s
,
475 /* lookup new key first */
477 salt_princ_s
= kerberos_secrets_fetch_des_salt();
478 if (salt_princ_s
== NULL
) {
480 /* look under the old key. If this fails, just use the standard key */
481 salt_princ_s
= kerberos_secrets_fetch_salting_principal(host_princ_s
,
483 if (salt_princ_s
== NULL
) {
484 /* fall back to host/machine.realm@REALM */
485 salt_princ_s
= kerberos_standard_des_salt();
492 int create_kerberos_key_from_string(krb5_context context
,
493 krb5_principal host_princ
,
494 krb5_principal salt_princ
,
497 krb5_enctype enctype
,
502 * Check if we've determined that the KDC is salting keys for this
503 * principal/enctype in a non-obvious way. If it is, try to match
507 KRB5_KEY_DATA(key
) = (KRB5_KEY_DATA_CAST
*)SMB_MALLOC(password
->length
);
508 if (!KRB5_KEY_DATA(key
)) {
511 memcpy(KRB5_KEY_DATA(key
), password
->data
, password
->length
);
512 KRB5_KEY_LENGTH(key
) = password
->length
;
513 KRB5_KEY_TYPE(key
) = enctype
;
516 ret
= smb_krb5_create_key_from_string(context
,
517 salt_princ
? salt_princ
: host_princ
,
525 /************************************************************************
526 Routine to set the salting principal for this service. Active
527 Directory may use a non-obvious principal name to generate the salt
528 when it determines the key to use for encrypting tickets for a service,
529 and hopefully we detected that when we joined the domain.
530 Setting principal to NULL deletes this entry.
531 ************************************************************************/
533 bool kerberos_secrets_store_salting_principal(const char *service
,
535 const char *principal
)
539 krb5_context context
= NULL
;
540 krb5_principal princ
= NULL
;
541 char *princ_s
= NULL
;
542 char *unparsed_name
= NULL
;
543 krb5_error_code code
;
545 if (((code
= krb5_init_context(&context
)) != 0) || (context
== NULL
)) {
546 DEBUG(5, ("kerberos_secrets_store_salting_pricipal: kdb5_init_context failed: %s\n",
547 error_message(code
)));
550 if (strchr_m(service
, '@')) {
551 if (asprintf(&princ_s
, "%s", service
) == -1) {
555 if (asprintf(&princ_s
, "%s@%s", service
, lp_realm()) == -1) {
560 if (smb_krb5_parse_name(context
, princ_s
, &princ
) != 0) {
563 if (smb_krb5_unparse_name(talloc_tos(), context
, princ
, &unparsed_name
) != 0) {
567 if (asprintf(&key
, "%s/%s/enctype=%d",
568 SECRETS_SALTING_PRINCIPAL
, unparsed_name
, enctype
)
573 if ((principal
!= NULL
) && (strlen(principal
) > 0)) {
574 ret
= secrets_store(key
, principal
, strlen(principal
) + 1);
576 ret
= secrets_delete(key
);
583 TALLOC_FREE(unparsed_name
);
586 krb5_free_principal(context
, princ
);
590 krb5_free_context(context
);
597 /************************************************************************
598 ************************************************************************/
600 int kerberos_kinit_password(const char *principal
,
601 const char *password
,
603 const char *cache_name
)
605 return kerberos_kinit_password_ext(principal
,
617 /************************************************************************
618 ************************************************************************/
620 /************************************************************************
621 Create a string list of available kdc's, possibly searching by sitename.
624 If "sitename" is given, the DC's in that site are listed first.
626 ************************************************************************/
628 static void add_sockaddr_unique(struct sockaddr_storage
*addrs
, int *num_addrs
,
629 const struct sockaddr_storage
*addr
)
633 for (i
=0; i
<*num_addrs
; i
++) {
634 if (sockaddr_equal((const struct sockaddr
*)&addrs
[i
],
635 (const struct sockaddr
*)addr
)) {
643 /* print_canonical_sockaddr prints an ipv6 addr in the form of
644 * [ipv6.addr]. This string, when put in a generated krb5.conf file is not
645 * always properly dealt with by some older krb5 libraries. Adding the hard-coded
646 * portnumber workarounds the issue. - gd */
648 static char *print_canonical_sockaddr_with_port(TALLOC_CTX
*mem_ctx
,
649 const struct sockaddr_storage
*pss
)
653 str
= print_canonical_sockaddr(mem_ctx
, pss
);
658 if (pss
->ss_family
!= AF_INET6
) {
662 #if defined(HAVE_IPV6)
663 str
= talloc_asprintf_append(str
, ":88");
668 static char *get_kdc_ip_string(char *mem_ctx
,
670 const char *sitename
,
671 const struct sockaddr_storage
*pss
)
673 TALLOC_CTX
*frame
= talloc_stackframe();
675 struct ip_service
*ip_srv_site
= NULL
;
676 struct ip_service
*ip_srv_nonsite
= NULL
;
680 struct sockaddr_storage
*dc_addrs
;
681 struct tsocket_address
**dc_addrs2
= NULL
;
682 const struct tsocket_address
* const *dc_addrs3
= NULL
;
684 struct netlogon_samlogon_response
**responses
= NULL
;
686 char *kdc_str
= talloc_asprintf(mem_ctx
, "%s\t\tkdc = %s\n", "",
687 print_canonical_sockaddr_with_port(mem_ctx
, pss
));
689 if (kdc_str
== NULL
) {
695 * First get the KDC's only in this site, the rest will be
700 get_kdc_list(realm
, sitename
, &ip_srv_site
, &count_site
);
701 DEBUG(10, ("got %d addresses from site %s search\n", count_site
,
707 get_kdc_list(realm
, NULL
, &ip_srv_nonsite
, &count_nonsite
);
708 DEBUG(10, ("got %d addresses from site-less search\n", count_nonsite
));
710 dc_addrs
= talloc_array(talloc_tos(), struct sockaddr_storage
,
711 count_site
+ count_nonsite
);
712 if (dc_addrs
== NULL
) {
718 for (i
= 0; i
< count_site
; i
++) {
720 (const struct sockaddr
*)pss
,
721 (const struct sockaddr
*)&ip_srv_site
[i
].ss
)) {
722 add_sockaddr_unique(dc_addrs
, &num_dcs
,
727 for (i
= 0; i
< count_nonsite
; i
++) {
729 (const struct sockaddr
*)pss
,
730 (const struct sockaddr
*)&ip_srv_nonsite
[i
].ss
)) {
731 add_sockaddr_unique(dc_addrs
, &num_dcs
,
732 &ip_srv_nonsite
[i
].ss
);
736 dc_addrs2
= talloc_zero_array(talloc_tos(),
737 struct tsocket_address
*,
740 DEBUG(10, ("%d additional KDCs to test\n", num_dcs
));
744 if (dc_addrs2
== NULL
) {
748 for (i
=0; i
<num_dcs
; i
++) {
749 char addr
[INET6_ADDRSTRLEN
];
752 print_sockaddr(addr
, sizeof(addr
), &dc_addrs
[i
]);
754 ret
= tsocket_address_inet_from_strings(dc_addrs2
, "ip",
758 status
= map_nt_error_from_unix(errno
);
759 DEBUG(2,("Failed to create tsocket_address for %s - %s\n",
760 addr
, nt_errstr(status
)));
765 dc_addrs3
= (const struct tsocket_address
* const *)dc_addrs2
;
767 status
= cldap_multi_netlogon(talloc_tos(),
769 realm
, lp_netbios_name(),
770 NETLOGON_NT_VERSION_5
| NETLOGON_NT_VERSION_5EX
,
771 MIN(num_dcs
, 3), timeval_current_ofs(3, 0), &responses
);
772 TALLOC_FREE(dc_addrs2
);
775 if (!NT_STATUS_IS_OK(status
)) {
776 DEBUG(10,("get_kdc_ip_string: cldap_multi_netlogon failed: "
777 "%s\n", nt_errstr(status
)));
781 for (i
=0; i
<num_dcs
; i
++) {
784 if (responses
[i
] == NULL
) {
788 /* Append to the string - inefficient but not done often. */
789 new_kdc_str
= talloc_asprintf(mem_ctx
, "%s\t\tkdc = %s\n",
791 print_canonical_sockaddr_with_port(mem_ctx
, &dc_addrs
[i
]));
792 if (new_kdc_str
== NULL
) {
795 TALLOC_FREE(kdc_str
);
796 kdc_str
= new_kdc_str
;
800 DEBUG(10, ("get_kdc_ip_string: Returning %s\n", kdc_str
));
803 SAFE_FREE(ip_srv_site
);
804 SAFE_FREE(ip_srv_nonsite
);
809 /************************************************************************
810 Create a specific krb5.conf file in the private directory pointing
811 at a specific kdc for a realm. Keyed off domain name. Sets
812 KRB5_CONFIG environment variable to point to this file. Must be
813 run as root or will fail (which is a good thing :-).
814 ************************************************************************/
816 bool create_local_private_krb5_conf_for_domain(const char *realm
,
818 const char *sitename
,
819 const struct sockaddr_storage
*pss
)
822 char *tmpname
= NULL
;
824 char *file_contents
= NULL
;
825 char *kdc_ip_string
= NULL
;
829 char *realm_upper
= NULL
;
831 char *aes_enctypes
= NULL
;
834 if (!lp_create_krb5_conf()) {
839 DEBUG(0, ("No realm has been specified! Do you really want to "
840 "join an Active Directory server?\n"));
844 if (domain
== NULL
|| pss
== NULL
) {
848 dname
= lock_path("smb_krb5");
852 if ((mkdir(dname
, 0755)==-1) && (errno
!= EEXIST
)) {
853 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
854 "failed to create directory %s. Error was %s\n",
855 dname
, strerror(errno
) ));
859 tmpname
= lock_path("smb_tmp_krb5.XXXXXX");
864 fname
= talloc_asprintf(dname
, "%s/krb5.conf.%s", dname
, domain
);
869 DEBUG(10,("create_local_private_krb5_conf_for_domain: fname = %s, realm = %s, domain = %s\n",
870 fname
, realm
, domain
));
872 realm_upper
= talloc_strdup(fname
, realm
);
873 if (!strupper_m(realm_upper
)) {
877 kdc_ip_string
= get_kdc_ip_string(dname
, realm
, sitename
, pss
);
878 if (!kdc_ip_string
) {
882 aes_enctypes
= talloc_strdup(fname
, "");
883 if (aes_enctypes
== NULL
) {
887 #ifdef HAVE_ENCTYPE_AES256_CTS_HMAC_SHA1_96
888 aes_enctypes
= talloc_asprintf_append(aes_enctypes
, "%s", "aes256-cts-hmac-sha1-96 ");
889 if (aes_enctypes
== NULL
) {
893 #ifdef HAVE_ENCTYPE_AES128_CTS_HMAC_SHA1_96
894 aes_enctypes
= talloc_asprintf_append(aes_enctypes
, "%s", "aes128-cts-hmac-sha1-96");
895 if (aes_enctypes
== NULL
) {
900 file_contents
= talloc_asprintf(fname
,
901 "[libdefaults]\n\tdefault_realm = %s\n"
902 "\tdefault_tgs_enctypes = %s RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
903 "\tdefault_tkt_enctypes = %s RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
904 "\tpreferred_enctypes = %s RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
905 "\tdns_lookup_realm = false\n\n"
906 "[realms]\n\t%s = {\n"
908 realm_upper
, aes_enctypes
, aes_enctypes
, aes_enctypes
,
909 realm_upper
, kdc_ip_string
);
911 if (!file_contents
) {
915 flen
= strlen(file_contents
);
917 mask
= umask(S_IRWXO
| S_IRWXG
);
918 fd
= mkstemp(tmpname
);
921 DEBUG(0,("create_local_private_krb5_conf_for_domain: smb_mkstemp failed,"
922 " for file %s. Errno %s\n",
923 tmpname
, strerror(errno
) ));
927 if (fchmod(fd
, 0644)==-1) {
928 DEBUG(0,("create_local_private_krb5_conf_for_domain: fchmod failed for %s."
930 tmpname
, strerror(errno
) ));
936 ret
= write(fd
, file_contents
, flen
);
938 DEBUG(0,("create_local_private_krb5_conf_for_domain: write failed,"
939 " returned %d (should be %u). Errno %s\n",
940 (int)ret
, (unsigned int)flen
, strerror(errno
) ));
946 DEBUG(0,("create_local_private_krb5_conf_for_domain: close failed."
947 " Errno %s\n", strerror(errno
) ));
952 if (rename(tmpname
, fname
) == -1) {
953 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
954 "of %s to %s failed. Errno %s\n",
955 tmpname
, fname
, strerror(errno
) ));
960 DEBUG(5,("create_local_private_krb5_conf_for_domain: wrote "
961 "file %s with realm %s KDC list = %s\n",
962 fname
, realm_upper
, kdc_ip_string
));
964 /* Set the environment variable to this file. */
965 setenv("KRB5_CONFIG", fname
, 1);
969 #if defined(OVERWRITE_SYSTEM_KRB5_CONF)
971 #define SYSTEM_KRB5_CONF_PATH "/etc/krb5.conf"
972 /* Insanity, sheer insanity..... */
974 if (strequal(realm
, lp_realm())) {
975 SMB_STRUCT_STAT sbuf
;
977 if (sys_lstat(SYSTEM_KRB5_CONF_PATH
, &sbuf
, false) == 0) {
978 if (S_ISLNK(sbuf
.st_ex_mode
) && sbuf
.st_ex_size
) {
980 size_t alloc_size
= sbuf
.st_ex_size
+ 1;
981 char *linkpath
= talloc_array(talloc_tos(), char,
986 lret
= readlink(SYSTEM_KRB5_CONF_PATH
, linkpath
,
989 TALLOC_FREE(linkpath
);
992 linkpath
[lret
] = '\0';
994 if (strcmp(linkpath
, fname
) == 0) {
995 /* Symlink already exists. */
996 TALLOC_FREE(linkpath
);
999 TALLOC_FREE(linkpath
);
1003 /* Try and replace with a symlink. */
1004 if (symlink(fname
, SYSTEM_KRB5_CONF_PATH
) == -1) {
1005 const char *newpath
= SYSTEM_KRB5_CONF_PATH
".saved";
1006 if (errno
!= EEXIST
) {
1007 DEBUG(0,("create_local_private_krb5_conf_for_domain: symlink "
1008 "of %s to %s failed. Errno %s\n",
1009 fname
, SYSTEM_KRB5_CONF_PATH
, strerror(errno
) ));
1010 goto done
; /* Not a fatal error. */
1013 /* Yes, this is a race conditon... too bad. */
1014 if (rename(SYSTEM_KRB5_CONF_PATH
, newpath
) == -1) {
1015 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
1016 "of %s to %s failed. Errno %s\n",
1017 SYSTEM_KRB5_CONF_PATH
, newpath
,
1019 goto done
; /* Not a fatal error. */
1022 if (symlink(fname
, SYSTEM_KRB5_CONF_PATH
) == -1) {
1023 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
1024 "forced symlink of %s to /etc/krb5.conf failed. Errno %s\n",
1025 fname
, strerror(errno
) ));
1026 goto done
; /* Not a fatal error. */
1033 TALLOC_FREE(tmpname
);