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"
33 #define DEFAULT_KRB5_PORT 88
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;
51 memset(prompts
[0].reply
->data
, '\0', prompts
[0].reply
->length
);
52 if (prompts
[0].reply
->length
> 0) {
54 strncpy((char *)prompts
[0].reply
->data
, (const char *)data
,
55 prompts
[0].reply
->length
-1);
56 prompts
[0].reply
->length
= strlen((const char *)prompts
[0].reply
->data
);
58 prompts
[0].reply
->length
= 0;
64 static bool smb_krb5_get_ntstatus_from_krb5_error(krb5_error
*error
,
68 DATA_BLOB unwrapped_edata
;
70 struct KRB5_EDATA_NTSTATUS parsed_edata
;
71 enum ndr_err_code ndr_err
;
73 #ifdef HAVE_E_DATA_POINTER_IN_KRB5_ERROR
74 edata
= data_blob(error
->e_data
->data
, error
->e_data
->length
);
76 edata
= data_blob(error
->e_data
.data
, error
->e_data
.length
);
77 #endif /* HAVE_E_DATA_POINTER_IN_KRB5_ERROR */
80 dump_data(10, edata
.data
, edata
.length
);
81 #endif /* DEVELOPER */
83 mem_ctx
= talloc_init("smb_krb5_get_ntstatus_from_krb5_error");
84 if (mem_ctx
== NULL
) {
85 data_blob_free(&edata
);
89 if (!unwrap_edata_ntstatus(mem_ctx
, &edata
, &unwrapped_edata
)) {
90 data_blob_free(&edata
);
95 data_blob_free(&edata
);
97 ndr_err
= ndr_pull_struct_blob_all(&unwrapped_edata
, mem_ctx
,
98 &parsed_edata
, (ndr_pull_flags_fn_t
)ndr_pull_KRB5_EDATA_NTSTATUS
);
99 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
100 data_blob_free(&unwrapped_edata
);
101 TALLOC_FREE(mem_ctx
);
105 data_blob_free(&unwrapped_edata
);
108 *nt_status
= parsed_edata
.ntstatus
;
111 TALLOC_FREE(mem_ctx
);
116 static bool smb_krb5_get_ntstatus_from_krb5_error_init_creds_opt(krb5_context ctx
,
117 krb5_get_init_creds_opt
*opt
,
121 krb5_error
*error
= NULL
;
123 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_GET_ERROR
124 ret
= krb5_get_init_creds_opt_get_error(ctx
, opt
, &error
);
126 DEBUG(1,("krb5_get_init_creds_opt_get_error gave: %s\n",
127 error_message(ret
)));
130 #endif /* HAVE_KRB5_GET_INIT_CREDS_OPT_GET_ERROR */
133 DEBUG(1,("no krb5_error\n"));
137 #ifdef HAVE_E_DATA_POINTER_IN_KRB5_ERROR
138 if (!error
->e_data
) {
140 if (error
->e_data
.data
== NULL
) {
141 #endif /* HAVE_E_DATA_POINTER_IN_KRB5_ERROR */
142 DEBUG(1,("no edata in krb5_error\n"));
143 krb5_free_error(ctx
, error
);
147 ret
= smb_krb5_get_ntstatus_from_krb5_error(error
, nt_status
);
149 krb5_free_error(ctx
, error
);
155 simulate a kinit, putting the tgt in the given cache location. If cache_name == NULL
156 place in default cache location.
159 int kerberos_kinit_password_ext(const char *principal
,
160 const char *password
,
163 time_t *renew_till_time
,
164 const char *cache_name
,
166 bool add_netbios_addr
,
167 time_t renewable_time
,
170 krb5_context ctx
= NULL
;
171 krb5_error_code code
= 0;
172 krb5_ccache cc
= NULL
;
173 krb5_principal me
= NULL
;
175 krb5_get_init_creds_opt
*opt
= NULL
;
176 smb_krb5_addresses
*addr
= NULL
;
178 ZERO_STRUCT(my_creds
);
180 initialize_krb5_error_table();
181 if ((code
= krb5_init_context(&ctx
)))
184 if (time_offset
!= 0) {
185 krb5_set_real_time(ctx
, time(NULL
) + time_offset
, 0);
188 DEBUG(10,("kerberos_kinit_password: as %s using [%s] as ccache and config [%s]\n",
190 cache_name
? cache_name
: krb5_cc_default_name(ctx
),
191 getenv("KRB5_CONFIG")));
193 if ((code
= krb5_cc_resolve(ctx
, cache_name
? cache_name
: krb5_cc_default_name(ctx
), &cc
))) {
197 if ((code
= smb_krb5_parse_name(ctx
, principal
, &me
))) {
201 if ((code
= smb_krb5_get_init_creds_opt_alloc(ctx
, &opt
))) {
205 krb5_get_init_creds_opt_set_renew_life(opt
, renewable_time
);
206 krb5_get_init_creds_opt_set_forwardable(opt
, True
);
209 krb5_get_init_creds_opt_set_tkt_life(opt
, 60);
212 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PAC_REQUEST
214 if ((code
= krb5_get_init_creds_opt_set_pac_request(ctx
, opt
, (krb5_boolean
)request_pac
))) {
219 if (add_netbios_addr
) {
220 if ((code
= smb_krb5_gen_netbios_krb5_address(&addr
))) {
223 krb5_get_init_creds_opt_set_address_list(opt
, addr
->addrs
);
226 if ((code
= krb5_get_init_creds_password(ctx
, &my_creds
, me
, CONST_DISCARD(char *,password
),
227 kerb_prompter
, CONST_DISCARD(char *,password
),
232 if ((code
= krb5_cc_initialize(ctx
, cc
, me
))) {
236 if ((code
= krb5_cc_store_cred(ctx
, cc
, &my_creds
))) {
241 *expire_time
= (time_t) my_creds
.times
.endtime
;
244 if (renew_till_time
) {
245 *renew_till_time
= (time_t) my_creds
.times
.renew_till
;
254 *ntstatus
= NT_STATUS_OK
;
258 /* try to get ntstatus code out of krb5_error when we have it
259 * inside the krb5_get_init_creds_opt - gd */
261 if (opt
&& smb_krb5_get_ntstatus_from_krb5_error_init_creds_opt(ctx
, opt
, &status
)) {
266 /* fall back to self-made-mapping */
267 *ntstatus
= krb5_to_nt_status(code
);
271 krb5_free_cred_contents(ctx
, &my_creds
);
273 krb5_free_principal(ctx
, me
);
276 smb_krb5_free_addresses(ctx
, addr
);
279 smb_krb5_get_init_creds_opt_free(ctx
, opt
);
282 krb5_cc_close(ctx
, cc
);
285 krb5_free_context(ctx
);
290 int ads_kdestroy(const char *cc_name
)
292 krb5_error_code code
;
293 krb5_context ctx
= NULL
;
294 krb5_ccache cc
= NULL
;
296 initialize_krb5_error_table();
297 if ((code
= krb5_init_context (&ctx
))) {
298 DEBUG(3, ("ads_kdestroy: kdb5_init_context failed: %s\n",
299 error_message(code
)));
304 if ((code
= krb5_cc_default(ctx
, &cc
))) {
305 krb5_free_context(ctx
);
309 if ((code
= krb5_cc_resolve(ctx
, cc_name
, &cc
))) {
310 DEBUG(3, ("ads_kdestroy: krb5_cc_resolve failed: %s\n",
311 error_message(code
)));
312 krb5_free_context(ctx
);
317 if ((code
= krb5_cc_destroy (ctx
, cc
))) {
318 DEBUG(3, ("ads_kdestroy: krb5_cc_destroy failed: %s\n",
319 error_message(code
)));
322 krb5_free_context (ctx
);
326 /************************************************************************
327 Routine to fetch the salting principal for a service. Active
328 Directory may use a non-obvious principal name to generate the salt
329 when it determines the key to use for encrypting tickets for a service,
330 and hopefully we detected that when we joined the domain.
331 ************************************************************************/
333 static char *kerberos_secrets_fetch_salting_principal(const char *service
, int enctype
)
338 if (asprintf(&key
, "%s/%s/enctype=%d",
339 SECRETS_SALTING_PRINCIPAL
, service
, enctype
) == -1) {
342 ret
= (char *)secrets_fetch(key
, NULL
);
347 /************************************************************************
348 Return the standard DES salt key
349 ************************************************************************/
351 char* kerberos_standard_des_salt( void )
355 fstr_sprintf( salt
, "host/%s.%s@", global_myname(), lp_realm() );
357 fstrcat( salt
, lp_realm() );
359 return SMB_STRDUP( salt
);
362 /************************************************************************
363 ************************************************************************/
365 static char* des_salt_key( void )
369 if (asprintf(&key
, "%s/DES/%s", SECRETS_SALTING_PRINCIPAL
,
377 /************************************************************************
378 ************************************************************************/
380 bool kerberos_secrets_store_des_salt( const char* salt
)
385 if ( (key
= des_salt_key()) == NULL
) {
386 DEBUG(0,("kerberos_secrets_store_des_salt: failed to generate key!\n"));
391 DEBUG(8,("kerberos_secrets_store_des_salt: deleting salt\n"));
392 secrets_delete( key
);
396 DEBUG(3,("kerberos_secrets_store_des_salt: Storing salt \"%s\"\n", salt
));
398 ret
= secrets_store( key
, salt
, strlen(salt
)+1 );
405 /************************************************************************
406 ************************************************************************/
408 char* kerberos_secrets_fetch_des_salt( void )
412 if ( (key
= des_salt_key()) == NULL
) {
413 DEBUG(0,("kerberos_secrets_fetch_des_salt: failed to generate key!\n"));
417 salt
= (char*)secrets_fetch( key
, NULL
);
424 /************************************************************************
425 Routine to get the default realm from the kerberos credentials cache.
426 Caller must free if the return value is not NULL.
427 ************************************************************************/
429 char *kerberos_get_default_realm_from_ccache( void )
432 krb5_context ctx
= NULL
;
433 krb5_ccache cc
= NULL
;
434 krb5_principal princ
= NULL
;
436 initialize_krb5_error_table();
437 if (krb5_init_context(&ctx
)) {
441 DEBUG(5,("kerberos_get_default_realm_from_ccache: "
442 "Trying to read krb5 cache: %s\n",
443 krb5_cc_default_name(ctx
)));
444 if (krb5_cc_default(ctx
, &cc
)) {
445 DEBUG(0,("kerberos_get_default_realm_from_ccache: "
446 "failed to read default cache\n"));
449 if (krb5_cc_get_principal(ctx
, cc
, &princ
)) {
450 DEBUG(0,("kerberos_get_default_realm_from_ccache: "
451 "failed to get default principal\n"));
455 #if defined(HAVE_KRB5_PRINCIPAL_GET_REALM)
456 realm
= SMB_STRDUP(krb5_principal_get_realm(ctx
, princ
));
457 #elif defined(HAVE_KRB5_PRINC_REALM)
459 krb5_data
*realm_data
= krb5_princ_realm(ctx
, princ
);
460 realm
= SMB_STRNDUP(realm_data
->data
, realm_data
->length
);
468 krb5_free_principal(ctx
, princ
);
471 krb5_cc_close(ctx
, cc
);
473 krb5_free_context(ctx
);
479 /************************************************************************
480 Routine to get the realm from a given DNS name. Returns malloc'ed memory.
481 Caller must free() if the return value is not NULL.
482 ************************************************************************/
484 char *kerberos_get_realm_from_hostname(const char *hostname
)
486 #if defined(HAVE_KRB5_GET_HOST_REALM) && defined(HAVE_KRB5_FREE_HOST_REALM)
487 #if defined(HAVE_KRB5_REALM_TYPE)
489 krb5_realm
*realm_list
= NULL
;
492 char **realm_list
= NULL
;
495 krb5_error_code kerr
;
496 krb5_context ctx
= NULL
;
498 initialize_krb5_error_table();
499 if (krb5_init_context(&ctx
)) {
503 kerr
= krb5_get_host_realm(ctx
, hostname
, &realm_list
);
505 DEBUG(3,("kerberos_get_realm_from_hostname %s: "
507 hostname
? hostname
: "(NULL)",
508 error_message(kerr
) ));
512 if (realm_list
&& realm_list
[0]) {
513 realm
= SMB_STRDUP(realm_list
[0]);
520 krb5_free_host_realm(ctx
, realm_list
);
523 krb5_free_context(ctx
);
532 /************************************************************************
533 Routine to get the salting principal for this service. This is
534 maintained for backwards compatibilty with releases prior to 3.0.24.
535 Since we store the salting principal string only at join, we may have
536 to look for the older tdb keys. Caller must free if return is not null.
537 ************************************************************************/
539 krb5_principal
kerberos_fetch_salt_princ_for_host_princ(krb5_context context
,
540 krb5_principal host_princ
,
543 char *unparsed_name
= NULL
, *salt_princ_s
= NULL
;
544 krb5_principal ret_princ
= NULL
;
546 /* lookup new key first */
548 if ( (salt_princ_s
= kerberos_secrets_fetch_des_salt()) == NULL
) {
550 /* look under the old key. If this fails, just use the standard key */
552 if (smb_krb5_unparse_name(talloc_tos(), context
, host_princ
, &unparsed_name
) != 0) {
553 return (krb5_principal
)NULL
;
555 if ((salt_princ_s
= kerberos_secrets_fetch_salting_principal(unparsed_name
, enctype
)) == NULL
) {
556 /* fall back to host/machine.realm@REALM */
557 salt_princ_s
= kerberos_standard_des_salt();
561 if (smb_krb5_parse_name(context
, salt_princ_s
, &ret_princ
) != 0) {
565 TALLOC_FREE(unparsed_name
);
566 SAFE_FREE(salt_princ_s
);
571 /************************************************************************
572 Routine to set the salting principal for this service. Active
573 Directory may use a non-obvious principal name to generate the salt
574 when it determines the key to use for encrypting tickets for a service,
575 and hopefully we detected that when we joined the domain.
576 Setting principal to NULL deletes this entry.
577 ************************************************************************/
579 bool kerberos_secrets_store_salting_principal(const char *service
,
581 const char *principal
)
585 krb5_context context
= NULL
;
586 krb5_principal princ
= NULL
;
587 char *princ_s
= NULL
;
588 char *unparsed_name
= NULL
;
589 krb5_error_code code
;
591 if (((code
= krb5_init_context(&context
)) != 0) || (context
== NULL
)) {
592 DEBUG(5, ("kerberos_secrets_store_salting_pricipal: kdb5_init_context failed: %s\n",
593 error_message(code
)));
596 if (strchr_m(service
, '@')) {
597 if (asprintf(&princ_s
, "%s", service
) == -1) {
601 if (asprintf(&princ_s
, "%s@%s", service
, lp_realm()) == -1) {
606 if (smb_krb5_parse_name(context
, princ_s
, &princ
) != 0) {
609 if (smb_krb5_unparse_name(talloc_tos(), context
, princ
, &unparsed_name
) != 0) {
613 if (asprintf(&key
, "%s/%s/enctype=%d",
614 SECRETS_SALTING_PRINCIPAL
, unparsed_name
, enctype
)
619 if ((principal
!= NULL
) && (strlen(principal
) > 0)) {
620 ret
= secrets_store(key
, principal
, strlen(principal
) + 1);
622 ret
= secrets_delete(key
);
629 TALLOC_FREE(unparsed_name
);
632 krb5_free_principal(context
, princ
);
636 krb5_free_context(context
);
643 /************************************************************************
644 ************************************************************************/
646 int kerberos_kinit_password(const char *principal
,
647 const char *password
,
649 const char *cache_name
)
651 return kerberos_kinit_password_ext(principal
,
663 /************************************************************************
664 ************************************************************************/
666 static char *print_kdc_line(char *mem_ctx
,
667 const char *prev_line
,
668 const struct sockaddr_storage
*pss
,
669 const char *kdc_name
)
671 char *kdc_str
= NULL
;
673 if (pss
->ss_family
== AF_INET
) {
674 kdc_str
= talloc_asprintf(mem_ctx
, "%s\tkdc = %s\n",
676 print_canonical_sockaddr(mem_ctx
, pss
));
678 char addr
[INET6_ADDRSTRLEN
];
679 uint16_t port
= get_sockaddr_port(pss
);
681 DEBUG(10,("print_kdc_line: IPv6 case for kdc_name: %s, port: %d\n",
684 if (port
!= 0 && port
!= DEFAULT_KRB5_PORT
) {
685 /* Currently for IPv6 we can't specify a non-default
686 krb5 port with an address, as this requires a ':'.
687 Resolve to a name. */
688 char hostname
[MAX_DNS_NAME_LENGTH
];
689 int ret
= sys_getnameinfo((const struct sockaddr
*)pss
,
691 hostname
, sizeof(hostname
),
695 DEBUG(0,("print_kdc_line: can't resolve name "
696 "for kdc with non-default port %s. "
698 print_canonical_sockaddr(mem_ctx
, pss
),
702 /* Success, use host:port */
703 kdc_str
= talloc_asprintf(mem_ctx
,
710 /* no krb5 lib currently supports "kdc = ipv6 address"
711 * at all, so just fill in just the kdc_name if we have
712 * it and let the krb5 lib figure out the appropriate
713 * ipv6 address - gd */
716 kdc_str
= talloc_asprintf(mem_ctx
, "%s\tkdc = %s\n",
717 prev_line
, kdc_name
);
719 kdc_str
= talloc_asprintf(mem_ctx
, "%s\tkdc = %s\n",
730 /************************************************************************
731 Create a string list of available kdc's, possibly searching by sitename.
734 If "sitename" is given, the DC's in that site are listed first.
736 ************************************************************************/
738 static char *get_kdc_ip_string(char *mem_ctx
,
740 const char *sitename
,
741 struct sockaddr_storage
*pss
,
742 const char *kdc_name
)
745 struct ip_service
*ip_srv_site
= NULL
;
746 struct ip_service
*ip_srv_nonsite
= NULL
;
749 char *kdc_str
= print_kdc_line(mem_ctx
, "", pss
, kdc_name
);
751 if (kdc_str
== NULL
) {
756 * First get the KDC's only in this site, the rest will be
762 get_kdc_list(realm
, sitename
, &ip_srv_site
, &count_site
);
764 for (i
= 0; i
< count_site
; i
++) {
765 if (sockaddr_equal((struct sockaddr
*)&ip_srv_site
[i
].ss
,
766 (struct sockaddr
*)pss
)) {
769 /* Append to the string - inefficient
770 * but not done often. */
771 kdc_str
= print_kdc_line(mem_ctx
,
776 SAFE_FREE(ip_srv_site
);
784 get_kdc_list(realm
, NULL
, &ip_srv_nonsite
, &count_nonsite
);
786 for (i
= 0; i
< count_nonsite
; i
++) {
789 if (sockaddr_equal((struct sockaddr
*)&ip_srv_nonsite
[i
].ss
, (struct sockaddr
*)pss
)) {
793 /* Ensure this isn't an IP already seen (YUK! this is n*n....) */
794 for (j
= 0; j
< count_site
; j
++) {
795 if (sockaddr_equal((struct sockaddr
*)&ip_srv_nonsite
[i
].ss
,
796 (struct sockaddr
*)&ip_srv_site
[j
].ss
)) {
799 /* As the lists are sorted we can break early if nonsite > site. */
800 if (ip_service_compare(&ip_srv_nonsite
[i
], &ip_srv_site
[j
]) > 0) {
808 /* Append to the string - inefficient but not done often. */
809 kdc_str
= print_kdc_line(mem_ctx
,
811 &ip_srv_nonsite
[i
].ss
,
814 SAFE_FREE(ip_srv_site
);
815 SAFE_FREE(ip_srv_nonsite
);
821 SAFE_FREE(ip_srv_site
);
822 SAFE_FREE(ip_srv_nonsite
);
824 DEBUG(10,("get_kdc_ip_string: Returning %s\n",
830 /************************************************************************
831 Create a specific krb5.conf file in the private directory pointing
832 at a specific kdc for a realm. Keyed off domain name. Sets
833 KRB5_CONFIG environment variable to point to this file. Must be
834 run as root or will fail (which is a good thing :-).
835 ************************************************************************/
837 bool create_local_private_krb5_conf_for_domain(const char *realm
,
839 const char *sitename
,
840 struct sockaddr_storage
*pss
,
841 const char *kdc_name
)
844 char *tmpname
= NULL
;
846 char *file_contents
= NULL
;
847 char *kdc_ip_string
= NULL
;
851 char *realm_upper
= NULL
;
853 char *aes_enctypes
= NULL
;
855 if (!lp_create_krb5_conf()) {
859 if (!realm
|| !domain
|| !pss
|| !kdc_name
) {
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 strupper_m(realm_upper
);
890 kdc_ip_string
= get_kdc_ip_string(dname
, realm
, sitename
, pss
, kdc_name
);
891 if (!kdc_ip_string
) {
895 aes_enctypes
= talloc_strdup(fname
, "");
896 if (aes_enctypes
== NULL
) {
900 #ifdef HAVE_ENCTYPE_AES256_CTS_HMAC_SHA1_96
901 aes_enctypes
= talloc_asprintf_append(aes_enctypes
, "%s", "aes256-cts-hmac-sha1-96 ");
902 if (aes_enctypes
== NULL
) {
906 #ifdef HAVE_ENCTYPE_AES128_CTS_HMAC_SHA1_96
907 aes_enctypes
= talloc_asprintf_append(aes_enctypes
, "%s", "aes128-cts-hmac-sha1-96");
908 if (aes_enctypes
== NULL
) {
913 file_contents
= talloc_asprintf(fname
,
914 "[libdefaults]\n\tdefault_realm = %s\n"
915 "\tdefault_tgs_enctypes = %s RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
916 "\tdefault_tkt_enctypes = %s RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
917 "\tpreferred_enctypes = %s RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n\n"
918 "[realms]\n\t%s = {\n"
920 realm_upper
, aes_enctypes
, aes_enctypes
, aes_enctypes
,
921 realm_upper
, kdc_ip_string
);
923 if (!file_contents
) {
927 flen
= strlen(file_contents
);
929 fd
= mkstemp(tmpname
);
931 DEBUG(0,("create_local_private_krb5_conf_for_domain: smb_mkstemp failed,"
932 " for file %s. Errno %s\n",
933 tmpname
, strerror(errno
) ));
937 if (fchmod(fd
, 0644)==-1) {
938 DEBUG(0,("create_local_private_krb5_conf_for_domain: fchmod failed for %s."
940 tmpname
, strerror(errno
) ));
946 ret
= write(fd
, file_contents
, flen
);
948 DEBUG(0,("create_local_private_krb5_conf_for_domain: write failed,"
949 " returned %d (should be %u). Errno %s\n",
950 (int)ret
, (unsigned int)flen
, strerror(errno
) ));
956 DEBUG(0,("create_local_private_krb5_conf_for_domain: close failed."
957 " Errno %s\n", strerror(errno
) ));
962 if (rename(tmpname
, fname
) == -1) {
963 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
964 "of %s to %s failed. Errno %s\n",
965 tmpname
, fname
, strerror(errno
) ));
970 DEBUG(5,("create_local_private_krb5_conf_for_domain: wrote "
971 "file %s with realm %s KDC list = %s\n",
972 fname
, realm_upper
, kdc_ip_string
));
974 /* Set the environment variable to this file. */
975 setenv("KRB5_CONFIG", fname
, 1);
979 #if defined(OVERWRITE_SYSTEM_KRB5_CONF)
981 #define SYSTEM_KRB5_CONF_PATH "/etc/krb5.conf"
982 /* Insanity, sheer insanity..... */
984 if (strequal(realm
, lp_realm())) {
985 char linkpath
[PATH_MAX
+1];
988 lret
= readlink(SYSTEM_KRB5_CONF_PATH
, linkpath
, sizeof(linkpath
)-1);
990 linkpath
[lret
] = '\0';
993 if (lret
!= -1 || strcmp(linkpath
, fname
) == 0) {
994 /* Symlink already exists. */
998 /* Try and replace with a symlink. */
999 if (symlink(fname
, SYSTEM_KRB5_CONF_PATH
) == -1) {
1000 const char *newpath
= SYSTEM_KRB5_CONF_PATH
## ".saved";
1001 if (errno
!= EEXIST
) {
1002 DEBUG(0,("create_local_private_krb5_conf_for_domain: symlink "
1003 "of %s to %s failed. Errno %s\n",
1004 fname
, SYSTEM_KRB5_CONF_PATH
, strerror(errno
) ));
1005 goto done
; /* Not a fatal error. */
1008 /* Yes, this is a race conditon... too bad. */
1009 if (rename(SYSTEM_KRB5_CONF_PATH
, newpath
) == -1) {
1010 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
1011 "of %s to %s failed. Errno %s\n",
1012 SYSTEM_KRB5_CONF_PATH
, newpath
,
1014 goto done
; /* Not a fatal error. */
1017 if (symlink(fname
, SYSTEM_KRB5_CONF_PATH
) == -1) {
1018 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
1019 "forced symlink of %s to /etc/krb5.conf failed. Errno %s\n",
1020 fname
, strerror(errno
) ));
1021 goto done
; /* Not a fatal error. */
1028 TALLOC_FREE(tmpname
);