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
))) {
225 krb5_get_init_creds_opt_set_address_list(opt
, addr
->addrs
);
228 if ((code
= krb5_get_init_creds_password(ctx
, &my_creds
, me
, discard_const_p(char,password
),
229 kerb_prompter
, discard_const_p(char, password
),
234 if ((code
= krb5_cc_initialize(ctx
, cc
, me
))) {
238 if ((code
= krb5_cc_store_cred(ctx
, cc
, &my_creds
))) {
243 *expire_time
= (time_t) my_creds
.times
.endtime
;
246 if (renew_till_time
) {
247 *renew_till_time
= (time_t) my_creds
.times
.renew_till
;
256 *ntstatus
= NT_STATUS_OK
;
260 /* try to get ntstatus code out of krb5_error when we have it
261 * inside the krb5_get_init_creds_opt - gd */
263 if (opt
&& smb_krb5_get_ntstatus_from_krb5_error_init_creds_opt(ctx
, opt
, &status
)) {
268 /* fall back to self-made-mapping */
269 *ntstatus
= krb5_to_nt_status(code
);
273 krb5_free_cred_contents(ctx
, &my_creds
);
275 krb5_free_principal(ctx
, me
);
278 smb_krb5_free_addresses(ctx
, addr
);
281 smb_krb5_get_init_creds_opt_free(ctx
, opt
);
284 krb5_cc_close(ctx
, cc
);
287 krb5_free_context(ctx
);
292 int ads_kdestroy(const char *cc_name
)
294 krb5_error_code code
;
295 krb5_context ctx
= NULL
;
296 krb5_ccache cc
= NULL
;
298 initialize_krb5_error_table();
299 if ((code
= krb5_init_context (&ctx
))) {
300 DEBUG(3, ("ads_kdestroy: kdb5_init_context failed: %s\n",
301 error_message(code
)));
306 if ((code
= krb5_cc_default(ctx
, &cc
))) {
307 krb5_free_context(ctx
);
311 if ((code
= krb5_cc_resolve(ctx
, cc_name
, &cc
))) {
312 DEBUG(3, ("ads_kdestroy: krb5_cc_resolve failed: %s\n",
313 error_message(code
)));
314 krb5_free_context(ctx
);
319 if ((code
= krb5_cc_destroy (ctx
, cc
))) {
320 DEBUG(3, ("ads_kdestroy: krb5_cc_destroy failed: %s\n",
321 error_message(code
)));
324 krb5_free_context (ctx
);
328 /************************************************************************
329 Routine to fetch the salting principal for a service. Active
330 Directory may use a non-obvious principal name to generate the salt
331 when it determines the key to use for encrypting tickets for a service,
332 and hopefully we detected that when we joined the domain.
333 ************************************************************************/
335 static char *kerberos_secrets_fetch_salting_principal(const char *service
, int enctype
)
340 if (asprintf(&key
, "%s/%s/enctype=%d",
341 SECRETS_SALTING_PRINCIPAL
, service
, enctype
) == -1) {
344 ret
= (char *)secrets_fetch(key
, NULL
);
349 /************************************************************************
350 Return the standard DES salt key
351 ************************************************************************/
353 char* kerberos_standard_des_salt( void )
357 fstr_sprintf( salt
, "host/%s.%s@", lp_netbios_name(), lp_realm() );
359 fstrcat( salt
, lp_realm() );
361 return SMB_STRDUP( salt
);
364 /************************************************************************
365 ************************************************************************/
367 static char* des_salt_key( void )
371 if (asprintf(&key
, "%s/DES/%s", SECRETS_SALTING_PRINCIPAL
,
379 /************************************************************************
380 ************************************************************************/
382 bool kerberos_secrets_store_des_salt( const char* salt
)
387 if ( (key
= des_salt_key()) == NULL
) {
388 DEBUG(0,("kerberos_secrets_store_des_salt: failed to generate key!\n"));
393 DEBUG(8,("kerberos_secrets_store_des_salt: deleting salt\n"));
394 secrets_delete( key
);
398 DEBUG(3,("kerberos_secrets_store_des_salt: Storing salt \"%s\"\n", salt
));
400 ret
= secrets_store( key
, salt
, strlen(salt
)+1 );
407 /************************************************************************
408 ************************************************************************/
410 char* kerberos_secrets_fetch_des_salt( void )
414 if ( (key
= des_salt_key()) == NULL
) {
415 DEBUG(0,("kerberos_secrets_fetch_des_salt: failed to generate key!\n"));
419 salt
= (char*)secrets_fetch( key
, NULL
);
426 /************************************************************************
427 Routine to get the default realm from the kerberos credentials cache.
428 Caller must free if the return value is not NULL.
429 ************************************************************************/
431 char *kerberos_get_default_realm_from_ccache( void )
434 krb5_context ctx
= NULL
;
435 krb5_ccache cc
= NULL
;
436 krb5_principal princ
= NULL
;
438 initialize_krb5_error_table();
439 if (krb5_init_context(&ctx
)) {
443 DEBUG(5,("kerberos_get_default_realm_from_ccache: "
444 "Trying to read krb5 cache: %s\n",
445 krb5_cc_default_name(ctx
)));
446 if (krb5_cc_default(ctx
, &cc
)) {
447 DEBUG(0,("kerberos_get_default_realm_from_ccache: "
448 "failed to read default cache\n"));
451 if (krb5_cc_get_principal(ctx
, cc
, &princ
)) {
452 DEBUG(0,("kerberos_get_default_realm_from_ccache: "
453 "failed to get default principal\n"));
457 #if defined(HAVE_KRB5_PRINCIPAL_GET_REALM)
458 realm
= SMB_STRDUP(krb5_principal_get_realm(ctx
, princ
));
459 #elif defined(HAVE_KRB5_PRINC_REALM)
461 krb5_data
*realm_data
= krb5_princ_realm(ctx
, princ
);
462 realm
= SMB_STRNDUP(realm_data
->data
, realm_data
->length
);
470 krb5_free_principal(ctx
, princ
);
473 krb5_cc_close(ctx
, cc
);
475 krb5_free_context(ctx
);
481 /************************************************************************
482 Routine to get the realm from a given DNS name. Returns malloc'ed memory.
483 Caller must free() if the return value is not NULL.
484 ************************************************************************/
486 char *kerberos_get_realm_from_hostname(const char *hostname
)
488 #if defined(HAVE_KRB5_GET_HOST_REALM) && defined(HAVE_KRB5_FREE_HOST_REALM)
489 #if defined(HAVE_KRB5_REALM_TYPE)
491 krb5_realm
*realm_list
= NULL
;
494 char **realm_list
= NULL
;
497 krb5_error_code kerr
;
498 krb5_context ctx
= NULL
;
500 initialize_krb5_error_table();
501 if (krb5_init_context(&ctx
)) {
505 kerr
= krb5_get_host_realm(ctx
, hostname
, &realm_list
);
507 DEBUG(3,("kerberos_get_realm_from_hostname %s: "
509 hostname
? hostname
: "(NULL)",
510 error_message(kerr
) ));
514 if (realm_list
&& realm_list
[0]) {
515 realm
= SMB_STRDUP(realm_list
[0]);
522 krb5_free_host_realm(ctx
, realm_list
);
525 krb5_free_context(ctx
);
534 /************************************************************************
535 Routine to get the salting principal for this service. This is
536 maintained for backwards compatibilty with releases prior to 3.0.24.
537 Since we store the salting principal string only at join, we may have
538 to look for the older tdb keys. Caller must free if return is not null.
539 ************************************************************************/
541 krb5_principal
kerberos_fetch_salt_princ_for_host_princ(krb5_context context
,
542 krb5_principal host_princ
,
545 char *unparsed_name
= NULL
, *salt_princ_s
= NULL
;
546 krb5_principal ret_princ
= NULL
;
548 /* lookup new key first */
550 if ( (salt_princ_s
= kerberos_secrets_fetch_des_salt()) == NULL
) {
552 /* look under the old key. If this fails, just use the standard key */
554 if (smb_krb5_unparse_name(talloc_tos(), context
, host_princ
, &unparsed_name
) != 0) {
555 return (krb5_principal
)NULL
;
557 if ((salt_princ_s
= kerberos_secrets_fetch_salting_principal(unparsed_name
, enctype
)) == NULL
) {
558 /* fall back to host/machine.realm@REALM */
559 salt_princ_s
= kerberos_standard_des_salt();
563 if (smb_krb5_parse_name(context
, salt_princ_s
, &ret_princ
) != 0) {
567 TALLOC_FREE(unparsed_name
);
568 SAFE_FREE(salt_princ_s
);
573 /************************************************************************
574 Routine to set the salting principal for this service. Active
575 Directory may use a non-obvious principal name to generate the salt
576 when it determines the key to use for encrypting tickets for a service,
577 and hopefully we detected that when we joined the domain.
578 Setting principal to NULL deletes this entry.
579 ************************************************************************/
581 bool kerberos_secrets_store_salting_principal(const char *service
,
583 const char *principal
)
587 krb5_context context
= NULL
;
588 krb5_principal princ
= NULL
;
589 char *princ_s
= NULL
;
590 char *unparsed_name
= NULL
;
591 krb5_error_code code
;
593 if (((code
= krb5_init_context(&context
)) != 0) || (context
== NULL
)) {
594 DEBUG(5, ("kerberos_secrets_store_salting_pricipal: kdb5_init_context failed: %s\n",
595 error_message(code
)));
598 if (strchr_m(service
, '@')) {
599 if (asprintf(&princ_s
, "%s", service
) == -1) {
603 if (asprintf(&princ_s
, "%s@%s", service
, lp_realm()) == -1) {
608 if (smb_krb5_parse_name(context
, princ_s
, &princ
) != 0) {
611 if (smb_krb5_unparse_name(talloc_tos(), context
, princ
, &unparsed_name
) != 0) {
615 if (asprintf(&key
, "%s/%s/enctype=%d",
616 SECRETS_SALTING_PRINCIPAL
, unparsed_name
, enctype
)
621 if ((principal
!= NULL
) && (strlen(principal
) > 0)) {
622 ret
= secrets_store(key
, principal
, strlen(principal
) + 1);
624 ret
= secrets_delete(key
);
631 TALLOC_FREE(unparsed_name
);
634 krb5_free_principal(context
, princ
);
638 krb5_free_context(context
);
645 /************************************************************************
646 ************************************************************************/
648 int kerberos_kinit_password(const char *principal
,
649 const char *password
,
651 const char *cache_name
)
653 return kerberos_kinit_password_ext(principal
,
665 /************************************************************************
666 ************************************************************************/
668 static char *print_kdc_line(char *mem_ctx
,
669 const char *prev_line
,
670 const struct sockaddr_storage
*pss
,
671 const char *kdc_name
)
673 char addr
[INET6_ADDRSTRLEN
];
674 uint16_t port
= get_sockaddr_port(pss
);
676 if (pss
->ss_family
== AF_INET
) {
677 return talloc_asprintf(mem_ctx
, "%s\tkdc = %s\n",
679 print_canonical_sockaddr(mem_ctx
, pss
));
686 DEBUG(10, ("print_kdc_line: IPv6 case for kdc_name: %s, port: %d\n",
689 if (port
!= 0 && port
!= DEFAULT_KRB5_PORT
) {
690 /* Currently for IPv6 we can't specify a non-default
691 krb5 port with an address, as this requires a ':'.
692 Resolve to a name. */
693 char hostname
[MAX_DNS_NAME_LENGTH
];
694 int ret
= sys_getnameinfo((const struct sockaddr
*)pss
,
696 hostname
, sizeof(hostname
),
700 DEBUG(0,("print_kdc_line: can't resolve name "
701 "for kdc with non-default port %s. "
703 print_canonical_sockaddr(mem_ctx
, pss
),
707 /* Success, use host:port */
708 return talloc_asprintf(mem_ctx
,
715 /* no krb5 lib currently supports "kdc = ipv6 address"
716 * at all, so just fill in just the kdc_name if we have
717 * it and let the krb5 lib figure out the appropriate
718 * ipv6 address - gd */
721 return talloc_asprintf(mem_ctx
, "%s\tkdc = %s\n",
722 prev_line
, kdc_name
);
725 return talloc_asprintf(mem_ctx
, "%s\tkdc = %s\n",
732 /************************************************************************
733 Create a string list of available kdc's, possibly searching by sitename.
736 If "sitename" is given, the DC's in that site are listed first.
738 ************************************************************************/
740 static void add_sockaddr_unique(struct sockaddr_storage
*addrs
, int *num_addrs
,
741 const struct sockaddr_storage
*addr
)
745 for (i
=0; i
<*num_addrs
; i
++) {
746 if (sockaddr_equal((const struct sockaddr
*)&addrs
[i
],
747 (const struct sockaddr
*)addr
)) {
755 static char *get_kdc_ip_string(char *mem_ctx
,
757 const char *sitename
,
758 const struct sockaddr_storage
*pss
,
759 const char *kdc_name
)
761 TALLOC_CTX
*frame
= talloc_stackframe();
763 struct ip_service
*ip_srv_site
= NULL
;
764 struct ip_service
*ip_srv_nonsite
= NULL
;
768 struct sockaddr_storage
*dc_addrs
;
769 struct tsocket_address
**dc_addrs2
= NULL
;
770 const struct tsocket_address
* const *dc_addrs3
= NULL
;
772 struct netlogon_samlogon_response
**responses
= NULL
;
774 char *kdc_str
= print_kdc_line(mem_ctx
, "", pss
, kdc_name
);
776 if (kdc_str
== NULL
) {
781 * First get the KDC's only in this site, the rest will be
786 get_kdc_list(realm
, sitename
, &ip_srv_site
, &count_site
);
791 get_kdc_list(realm
, NULL
, &ip_srv_nonsite
, &count_nonsite
);
793 dc_addrs
= talloc_array(talloc_tos(), struct sockaddr_storage
,
794 1 + count_site
+ count_nonsite
);
795 if (dc_addrs
== NULL
) {
802 for (i
=0; i
<count_site
; i
++) {
803 add_sockaddr_unique(dc_addrs
, &num_dcs
, &ip_srv_site
[i
].ss
);
806 for (i
=0; i
<count_nonsite
; i
++) {
807 add_sockaddr_unique(dc_addrs
, &num_dcs
, &ip_srv_nonsite
[i
].ss
);
810 dc_addrs2
= talloc_zero_array(talloc_tos(),
811 struct tsocket_address
*,
813 if (dc_addrs2
== NULL
) {
817 for (i
=0; i
<num_dcs
; i
++) {
818 char addr
[INET6_ADDRSTRLEN
];
821 print_sockaddr(addr
, sizeof(addr
), &dc_addrs
[i
]);
823 ret
= tsocket_address_inet_from_strings(dc_addrs2
, "ip",
827 status
= map_nt_error_from_unix(errno
);
828 DEBUG(2,("Failed to create tsocket_address for %s - %s\n",
829 addr
, nt_errstr(status
)));
834 dc_addrs3
= (const struct tsocket_address
* const *)dc_addrs2
;
836 status
= cldap_multi_netlogon(talloc_tos(),
838 realm
, lp_netbios_name(),
839 NETLOGON_NT_VERSION_5
| NETLOGON_NT_VERSION_5EX
,
840 MIN(num_dcs
, 3), timeval_current_ofs(3, 0), &responses
);
841 TALLOC_FREE(dc_addrs2
);
844 if (!NT_STATUS_IS_OK(status
)) {
845 DEBUG(10,("get_kdc_ip_string: cldap_multi_netlogon failed: "
846 "%s\n", nt_errstr(status
)));
850 kdc_str
= talloc_strdup(mem_ctx
, "");
851 if (kdc_str
== NULL
) {
855 for (i
=0; i
<num_dcs
; i
++) {
858 if (responses
[i
] == NULL
) {
862 /* Append to the string - inefficient but not done often. */
863 new_kdc_str
= print_kdc_line(mem_ctx
, kdc_str
,
866 if (new_kdc_str
== NULL
) {
869 TALLOC_FREE(kdc_str
);
870 kdc_str
= new_kdc_str
;
873 DEBUG(10,("get_kdc_ip_string: Returning %s\n",
878 SAFE_FREE(ip_srv_site
);
879 SAFE_FREE(ip_srv_nonsite
);
884 /************************************************************************
885 Create a specific krb5.conf file in the private directory pointing
886 at a specific kdc for a realm. Keyed off domain name. Sets
887 KRB5_CONFIG environment variable to point to this file. Must be
888 run as root or will fail (which is a good thing :-).
889 ************************************************************************/
891 bool create_local_private_krb5_conf_for_domain(const char *realm
,
893 const char *sitename
,
894 const struct sockaddr_storage
*pss
,
895 const char *kdc_name
)
898 char *tmpname
= NULL
;
900 char *file_contents
= NULL
;
901 char *kdc_ip_string
= NULL
;
905 char *realm_upper
= NULL
;
908 if (!lp_create_krb5_conf()) {
912 dname
= lock_path("smb_krb5");
916 if ((mkdir(dname
, 0755)==-1) && (errno
!= EEXIST
)) {
917 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
918 "failed to create directory %s. Error was %s\n",
919 dname
, strerror(errno
) ));
923 tmpname
= lock_path("smb_tmp_krb5.XXXXXX");
928 fname
= talloc_asprintf(dname
, "%s/krb5.conf.%s", dname
, domain
);
933 DEBUG(10,("create_local_private_krb5_conf_for_domain: fname = %s, realm = %s, domain = %s\n",
934 fname
, realm
, domain
));
936 realm_upper
= talloc_strdup(fname
, realm
);
937 strupper_m(realm_upper
);
939 kdc_ip_string
= get_kdc_ip_string(dname
, realm
, sitename
, pss
, kdc_name
);
940 if (!kdc_ip_string
) {
944 file_contents
= talloc_asprintf(fname
,
945 "[libdefaults]\n\tdefault_realm = %s\n"
946 "\tdefault_tgs_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
947 "\tdefault_tkt_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
948 "\tpreferred_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n\n"
949 "[realms]\n\t%s = {\n"
951 realm_upper
, realm_upper
, kdc_ip_string
);
953 if (!file_contents
) {
957 flen
= strlen(file_contents
);
959 fd
= mkstemp(tmpname
);
961 DEBUG(0,("create_local_private_krb5_conf_for_domain: smb_mkstemp failed,"
962 " for file %s. Errno %s\n",
963 tmpname
, strerror(errno
) ));
967 if (fchmod(fd
, 0644)==-1) {
968 DEBUG(0,("create_local_private_krb5_conf_for_domain: fchmod failed for %s."
970 tmpname
, strerror(errno
) ));
976 ret
= write(fd
, file_contents
, flen
);
978 DEBUG(0,("create_local_private_krb5_conf_for_domain: write failed,"
979 " returned %d (should be %u). Errno %s\n",
980 (int)ret
, (unsigned int)flen
, strerror(errno
) ));
986 DEBUG(0,("create_local_private_krb5_conf_for_domain: close failed."
987 " Errno %s\n", strerror(errno
) ));
992 if (rename(tmpname
, fname
) == -1) {
993 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
994 "of %s to %s failed. Errno %s\n",
995 tmpname
, fname
, strerror(errno
) ));
1000 DEBUG(5,("create_local_private_krb5_conf_for_domain: wrote "
1001 "file %s with realm %s KDC list = %s\n",
1002 fname
, realm_upper
, kdc_ip_string
));
1004 /* Set the environment variable to this file. */
1005 setenv("KRB5_CONFIG", fname
, 1);
1009 #if defined(OVERWRITE_SYSTEM_KRB5_CONF)
1011 #define SYSTEM_KRB5_CONF_PATH "/etc/krb5.conf"
1012 /* Insanity, sheer insanity..... */
1014 if (strequal(realm
, lp_realm())) {
1015 SMB_STRUCT_STAT sbuf
;
1017 if (sys_lstat(SYSTEM_KRB5_CONF_PATH
, &sbuf
, false) == 0) {
1018 if (S_ISLNK(sbuf
.st_ex_mode
) && sbuf
.st_ex_size
) {
1020 size_t alloc_size
= sbuf
.st_ex_size
+ 1;
1021 char *linkpath
= talloc_array(talloc_tos(), char,
1026 lret
= readlink(SYSTEM_KRB5_CONF_PATH
, linkpath
,
1029 TALLOC_FREE(linkpath
);
1032 linkpath
[lret
] = '\0';
1034 if (strcmp(linkpath
, fname
) == 0) {
1035 /* Symlink already exists. */
1036 TALLOC_FREE(linkpath
);
1039 TALLOC_FREE(linkpath
);
1043 /* Try and replace with a symlink. */
1044 if (symlink(fname
, SYSTEM_KRB5_CONF_PATH
) == -1) {
1045 const char *newpath
= SYSTEM_KRB5_CONF_PATH
".saved";
1046 if (errno
!= EEXIST
) {
1047 DEBUG(0,("create_local_private_krb5_conf_for_domain: symlink "
1048 "of %s to %s failed. Errno %s\n",
1049 fname
, SYSTEM_KRB5_CONF_PATH
, strerror(errno
) ));
1050 goto done
; /* Not a fatal error. */
1053 /* Yes, this is a race conditon... too bad. */
1054 if (rename(SYSTEM_KRB5_CONF_PATH
, newpath
) == -1) {
1055 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
1056 "of %s to %s failed. Errno %s\n",
1057 SYSTEM_KRB5_CONF_PATH
, newpath
,
1059 goto done
; /* Not a fatal error. */
1062 if (symlink(fname
, SYSTEM_KRB5_CONF_PATH
) == -1) {
1063 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
1064 "forced symlink of %s to /etc/krb5.conf failed. Errno %s\n",
1065 fname
, strerror(errno
) ));
1066 goto done
; /* Not a fatal error. */
1073 TALLOC_FREE(tmpname
);