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 ************************************************************************/
471 krb5_principal
kerberos_fetch_salt_princ_for_host_princ(krb5_context context
,
472 krb5_principal host_princ
,
475 char *unparsed_name
= NULL
, *salt_princ_s
= NULL
;
476 krb5_principal ret_princ
= NULL
;
478 /* lookup new key first */
480 if ( (salt_princ_s
= kerberos_secrets_fetch_des_salt()) == NULL
) {
482 /* look under the old key. If this fails, just use the standard key */
484 if (smb_krb5_unparse_name(talloc_tos(), context
, host_princ
, &unparsed_name
) != 0) {
485 return (krb5_principal
)NULL
;
487 if ((salt_princ_s
= kerberos_secrets_fetch_salting_principal(unparsed_name
, enctype
)) == NULL
) {
488 /* fall back to host/machine.realm@REALM */
489 salt_princ_s
= kerberos_standard_des_salt();
493 if (smb_krb5_parse_name(context
, salt_princ_s
, &ret_princ
) != 0) {
497 TALLOC_FREE(unparsed_name
);
498 SAFE_FREE(salt_princ_s
);
503 int create_kerberos_key_from_string(krb5_context context
,
504 krb5_principal host_princ
,
507 krb5_enctype enctype
,
510 krb5_principal salt_princ
= NULL
;
513 * Check if we've determined that the KDC is salting keys for this
514 * principal/enctype in a non-obvious way. If it is, try to match
518 KRB5_KEY_DATA(key
) = (KRB5_KEY_DATA_CAST
*)SMB_MALLOC(password
->length
);
519 if (!KRB5_KEY_DATA(key
)) {
522 memcpy(KRB5_KEY_DATA(key
), password
->data
, password
->length
);
523 KRB5_KEY_LENGTH(key
) = password
->length
;
524 KRB5_KEY_TYPE(key
) = enctype
;
527 salt_princ
= kerberos_fetch_salt_princ_for_host_princ(context
, host_princ
, enctype
);
528 ret
= smb_krb5_create_key_from_string(context
,
529 salt_princ
? salt_princ
: host_princ
,
535 krb5_free_principal(context
, salt_princ
);
540 /************************************************************************
541 Routine to set the salting principal for this service. Active
542 Directory may use a non-obvious principal name to generate the salt
543 when it determines the key to use for encrypting tickets for a service,
544 and hopefully we detected that when we joined the domain.
545 Setting principal to NULL deletes this entry.
546 ************************************************************************/
548 bool kerberos_secrets_store_salting_principal(const char *service
,
550 const char *principal
)
554 krb5_context context
= NULL
;
555 krb5_principal princ
= NULL
;
556 char *princ_s
= NULL
;
557 char *unparsed_name
= NULL
;
558 krb5_error_code code
;
560 if (((code
= krb5_init_context(&context
)) != 0) || (context
== NULL
)) {
561 DEBUG(5, ("kerberos_secrets_store_salting_pricipal: kdb5_init_context failed: %s\n",
562 error_message(code
)));
565 if (strchr_m(service
, '@')) {
566 if (asprintf(&princ_s
, "%s", service
) == -1) {
570 if (asprintf(&princ_s
, "%s@%s", service
, lp_realm()) == -1) {
575 if (smb_krb5_parse_name(context
, princ_s
, &princ
) != 0) {
578 if (smb_krb5_unparse_name(talloc_tos(), context
, princ
, &unparsed_name
) != 0) {
582 if (asprintf(&key
, "%s/%s/enctype=%d",
583 SECRETS_SALTING_PRINCIPAL
, unparsed_name
, enctype
)
588 if ((principal
!= NULL
) && (strlen(principal
) > 0)) {
589 ret
= secrets_store(key
, principal
, strlen(principal
) + 1);
591 ret
= secrets_delete(key
);
598 TALLOC_FREE(unparsed_name
);
601 krb5_free_principal(context
, princ
);
605 krb5_free_context(context
);
612 /************************************************************************
613 ************************************************************************/
615 int kerberos_kinit_password(const char *principal
,
616 const char *password
,
618 const char *cache_name
)
620 return kerberos_kinit_password_ext(principal
,
632 /************************************************************************
633 ************************************************************************/
635 /************************************************************************
636 Create a string list of available kdc's, possibly searching by sitename.
639 If "sitename" is given, the DC's in that site are listed first.
641 ************************************************************************/
643 static void add_sockaddr_unique(struct sockaddr_storage
*addrs
, int *num_addrs
,
644 const struct sockaddr_storage
*addr
)
648 for (i
=0; i
<*num_addrs
; i
++) {
649 if (sockaddr_equal((const struct sockaddr
*)&addrs
[i
],
650 (const struct sockaddr
*)addr
)) {
658 /* print_canonical_sockaddr prints an ipv6 addr in the form of
659 * [ipv6.addr]. This string, when put in a generated krb5.conf file is not
660 * always properly dealt with by some older krb5 libraries. Adding the hard-coded
661 * portnumber workarounds the issue. - gd */
663 static char *print_canonical_sockaddr_with_port(TALLOC_CTX
*mem_ctx
,
664 const struct sockaddr_storage
*pss
)
668 str
= print_canonical_sockaddr(mem_ctx
, pss
);
673 if (pss
->ss_family
!= AF_INET6
) {
677 #if defined(HAVE_IPV6)
678 str
= talloc_asprintf_append(str
, ":88");
683 static char *get_kdc_ip_string(char *mem_ctx
,
685 const char *sitename
,
686 const struct sockaddr_storage
*pss
)
688 TALLOC_CTX
*frame
= talloc_stackframe();
690 struct ip_service
*ip_srv_site
= NULL
;
691 struct ip_service
*ip_srv_nonsite
= NULL
;
695 struct sockaddr_storage
*dc_addrs
;
696 struct tsocket_address
**dc_addrs2
= NULL
;
697 const struct tsocket_address
* const *dc_addrs3
= NULL
;
699 struct netlogon_samlogon_response
**responses
= NULL
;
701 char *kdc_str
= talloc_asprintf(mem_ctx
, "%s\t\tkdc = %s\n", "",
702 print_canonical_sockaddr_with_port(mem_ctx
, pss
));
704 if (kdc_str
== NULL
) {
710 * First get the KDC's only in this site, the rest will be
715 get_kdc_list(realm
, sitename
, &ip_srv_site
, &count_site
);
716 DEBUG(10, ("got %d addresses from site %s search\n", count_site
,
722 get_kdc_list(realm
, NULL
, &ip_srv_nonsite
, &count_nonsite
);
723 DEBUG(10, ("got %d addresses from site-less search\n", count_nonsite
));
725 dc_addrs
= talloc_array(talloc_tos(), struct sockaddr_storage
,
726 count_site
+ count_nonsite
);
727 if (dc_addrs
== NULL
) {
733 for (i
= 0; i
< count_site
; i
++) {
735 (const struct sockaddr
*)pss
,
736 (const struct sockaddr
*)&ip_srv_site
[i
].ss
)) {
737 add_sockaddr_unique(dc_addrs
, &num_dcs
,
742 for (i
= 0; i
< count_nonsite
; i
++) {
744 (const struct sockaddr
*)pss
,
745 (const struct sockaddr
*)&ip_srv_nonsite
[i
].ss
)) {
746 add_sockaddr_unique(dc_addrs
, &num_dcs
,
747 &ip_srv_nonsite
[i
].ss
);
751 dc_addrs2
= talloc_zero_array(talloc_tos(),
752 struct tsocket_address
*,
755 DEBUG(10, ("%d additional KDCs to test\n", num_dcs
));
759 if (dc_addrs2
== NULL
) {
763 for (i
=0; i
<num_dcs
; i
++) {
764 char addr
[INET6_ADDRSTRLEN
];
767 print_sockaddr(addr
, sizeof(addr
), &dc_addrs
[i
]);
769 ret
= tsocket_address_inet_from_strings(dc_addrs2
, "ip",
773 status
= map_nt_error_from_unix(errno
);
774 DEBUG(2,("Failed to create tsocket_address for %s - %s\n",
775 addr
, nt_errstr(status
)));
780 dc_addrs3
= (const struct tsocket_address
* const *)dc_addrs2
;
782 status
= cldap_multi_netlogon(talloc_tos(),
784 realm
, lp_netbios_name(),
785 NETLOGON_NT_VERSION_5
| NETLOGON_NT_VERSION_5EX
,
786 MIN(num_dcs
, 3), timeval_current_ofs(3, 0), &responses
);
787 TALLOC_FREE(dc_addrs2
);
790 if (!NT_STATUS_IS_OK(status
)) {
791 DEBUG(10,("get_kdc_ip_string: cldap_multi_netlogon failed: "
792 "%s\n", nt_errstr(status
)));
796 for (i
=0; i
<num_dcs
; i
++) {
799 if (responses
[i
] == NULL
) {
803 /* Append to the string - inefficient but not done often. */
804 new_kdc_str
= talloc_asprintf(mem_ctx
, "%s\t\tkdc = %s\n",
806 print_canonical_sockaddr_with_port(mem_ctx
, &dc_addrs
[i
]));
807 if (new_kdc_str
== NULL
) {
810 TALLOC_FREE(kdc_str
);
811 kdc_str
= new_kdc_str
;
815 DEBUG(10, ("get_kdc_ip_string: Returning %s\n", kdc_str
));
818 SAFE_FREE(ip_srv_site
);
819 SAFE_FREE(ip_srv_nonsite
);
824 /************************************************************************
825 Create a specific krb5.conf file in the private directory pointing
826 at a specific kdc for a realm. Keyed off domain name. Sets
827 KRB5_CONFIG environment variable to point to this file. Must be
828 run as root or will fail (which is a good thing :-).
829 ************************************************************************/
831 bool create_local_private_krb5_conf_for_domain(const char *realm
,
833 const char *sitename
,
834 const struct sockaddr_storage
*pss
)
837 char *tmpname
= NULL
;
839 char *file_contents
= NULL
;
840 char *kdc_ip_string
= NULL
;
844 char *realm_upper
= NULL
;
846 char *aes_enctypes
= NULL
;
849 if (!lp_create_krb5_conf()) {
854 DEBUG(0, ("No realm has been specified! Do you really want to "
855 "join an Active Directory server?\n"));
859 if (domain
== NULL
|| pss
== NULL
) {
863 dname
= lock_path("smb_krb5");
867 if ((mkdir(dname
, 0755)==-1) && (errno
!= EEXIST
)) {
868 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
869 "failed to create directory %s. Error was %s\n",
870 dname
, strerror(errno
) ));
874 tmpname
= lock_path("smb_tmp_krb5.XXXXXX");
879 fname
= talloc_asprintf(dname
, "%s/krb5.conf.%s", dname
, domain
);
884 DEBUG(10,("create_local_private_krb5_conf_for_domain: fname = %s, realm = %s, domain = %s\n",
885 fname
, realm
, domain
));
887 realm_upper
= talloc_strdup(fname
, realm
);
888 if (!strupper_m(realm_upper
)) {
892 kdc_ip_string
= get_kdc_ip_string(dname
, realm
, sitename
, pss
);
893 if (!kdc_ip_string
) {
897 aes_enctypes
= talloc_strdup(fname
, "");
898 if (aes_enctypes
== NULL
) {
902 #ifdef HAVE_ENCTYPE_AES256_CTS_HMAC_SHA1_96
903 aes_enctypes
= talloc_asprintf_append(aes_enctypes
, "%s", "aes256-cts-hmac-sha1-96 ");
904 if (aes_enctypes
== NULL
) {
908 #ifdef HAVE_ENCTYPE_AES128_CTS_HMAC_SHA1_96
909 aes_enctypes
= talloc_asprintf_append(aes_enctypes
, "%s", "aes128-cts-hmac-sha1-96");
910 if (aes_enctypes
== NULL
) {
915 file_contents
= talloc_asprintf(fname
,
916 "[libdefaults]\n\tdefault_realm = %s\n"
917 "\tdefault_tgs_enctypes = %s RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
918 "\tdefault_tkt_enctypes = %s RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
919 "\tpreferred_enctypes = %s RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
920 "\tdns_lookup_realm = false\n\n"
921 "[realms]\n\t%s = {\n"
923 realm_upper
, aes_enctypes
, aes_enctypes
, aes_enctypes
,
924 realm_upper
, kdc_ip_string
);
926 if (!file_contents
) {
930 flen
= strlen(file_contents
);
932 mask
= umask(S_IRWXO
| S_IRWXG
);
933 fd
= mkstemp(tmpname
);
936 DEBUG(0,("create_local_private_krb5_conf_for_domain: smb_mkstemp failed,"
937 " for file %s. Errno %s\n",
938 tmpname
, strerror(errno
) ));
942 if (fchmod(fd
, 0644)==-1) {
943 DEBUG(0,("create_local_private_krb5_conf_for_domain: fchmod failed for %s."
945 tmpname
, strerror(errno
) ));
951 ret
= write(fd
, file_contents
, flen
);
953 DEBUG(0,("create_local_private_krb5_conf_for_domain: write failed,"
954 " returned %d (should be %u). Errno %s\n",
955 (int)ret
, (unsigned int)flen
, strerror(errno
) ));
961 DEBUG(0,("create_local_private_krb5_conf_for_domain: close failed."
962 " Errno %s\n", strerror(errno
) ));
967 if (rename(tmpname
, fname
) == -1) {
968 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
969 "of %s to %s failed. Errno %s\n",
970 tmpname
, fname
, strerror(errno
) ));
975 DEBUG(5,("create_local_private_krb5_conf_for_domain: wrote "
976 "file %s with realm %s KDC list = %s\n",
977 fname
, realm_upper
, kdc_ip_string
));
979 /* Set the environment variable to this file. */
980 setenv("KRB5_CONFIG", fname
, 1);
984 #if defined(OVERWRITE_SYSTEM_KRB5_CONF)
986 #define SYSTEM_KRB5_CONF_PATH "/etc/krb5.conf"
987 /* Insanity, sheer insanity..... */
989 if (strequal(realm
, lp_realm())) {
990 SMB_STRUCT_STAT sbuf
;
992 if (sys_lstat(SYSTEM_KRB5_CONF_PATH
, &sbuf
, false) == 0) {
993 if (S_ISLNK(sbuf
.st_ex_mode
) && sbuf
.st_ex_size
) {
995 size_t alloc_size
= sbuf
.st_ex_size
+ 1;
996 char *linkpath
= talloc_array(talloc_tos(), char,
1001 lret
= readlink(SYSTEM_KRB5_CONF_PATH
, linkpath
,
1004 TALLOC_FREE(linkpath
);
1007 linkpath
[lret
] = '\0';
1009 if (strcmp(linkpath
, fname
) == 0) {
1010 /* Symlink already exists. */
1011 TALLOC_FREE(linkpath
);
1014 TALLOC_FREE(linkpath
);
1018 /* Try and replace with a symlink. */
1019 if (symlink(fname
, SYSTEM_KRB5_CONF_PATH
) == -1) {
1020 const char *newpath
= SYSTEM_KRB5_CONF_PATH
".saved";
1021 if (errno
!= EEXIST
) {
1022 DEBUG(0,("create_local_private_krb5_conf_for_domain: symlink "
1023 "of %s to %s failed. Errno %s\n",
1024 fname
, SYSTEM_KRB5_CONF_PATH
, strerror(errno
) ));
1025 goto done
; /* Not a fatal error. */
1028 /* Yes, this is a race conditon... too bad. */
1029 if (rename(SYSTEM_KRB5_CONF_PATH
, newpath
) == -1) {
1030 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
1031 "of %s to %s failed. Errno %s\n",
1032 SYSTEM_KRB5_CONF_PATH
, newpath
,
1034 goto done
; /* Not a fatal error. */
1037 if (symlink(fname
, SYSTEM_KRB5_CONF_PATH
) == -1) {
1038 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
1039 "forced symlink of %s to /etc/krb5.conf failed. Errno %s\n",
1040 fname
, strerror(errno
) ));
1041 goto done
; /* Not a fatal error. */
1048 TALLOC_FREE(tmpname
);