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/>.
26 #include "../librpc/gen_ndr/ndr_misc.h"
27 #include "libads/kerberos_proto.h"
32 #define DEFAULT_KRB5_PORT 88
34 #define LIBADS_CCACHE_NAME "MEMORY:libads"
37 we use a prompter to avoid a crash bug in the kerberos libs when
38 dealing with empty passwords
39 this prompter is just a string copy ...
41 static krb5_error_code
42 kerb_prompter(krb5_context ctx
, void *data
,
46 krb5_prompt prompts
[])
48 if (num_prompts
== 0) return 0;
50 memset(prompts
[0].reply
->data
, '\0', prompts
[0].reply
->length
);
51 if (prompts
[0].reply
->length
> 0) {
53 strncpy((char *)prompts
[0].reply
->data
, (const char *)data
,
54 prompts
[0].reply
->length
-1);
55 prompts
[0].reply
->length
= strlen((const char *)prompts
[0].reply
->data
);
57 prompts
[0].reply
->length
= 0;
63 static bool smb_krb5_get_ntstatus_from_krb5_error(krb5_error
*error
,
67 DATA_BLOB unwrapped_edata
;
69 struct KRB5_EDATA_NTSTATUS parsed_edata
;
70 enum ndr_err_code ndr_err
;
72 #ifdef HAVE_E_DATA_POINTER_IN_KRB5_ERROR
73 edata
= data_blob(error
->e_data
->data
, error
->e_data
->length
);
75 edata
= data_blob(error
->e_data
.data
, error
->e_data
.length
);
76 #endif /* HAVE_E_DATA_POINTER_IN_KRB5_ERROR */
79 dump_data(10, edata
.data
, edata
.length
);
80 #endif /* DEVELOPER */
82 mem_ctx
= talloc_init("smb_krb5_get_ntstatus_from_krb5_error");
83 if (mem_ctx
== NULL
) {
84 data_blob_free(&edata
);
88 if (!unwrap_edata_ntstatus(mem_ctx
, &edata
, &unwrapped_edata
)) {
89 data_blob_free(&edata
);
94 data_blob_free(&edata
);
96 ndr_err
= ndr_pull_struct_blob_all(&unwrapped_edata
, mem_ctx
,
97 &parsed_edata
, (ndr_pull_flags_fn_t
)ndr_pull_KRB5_EDATA_NTSTATUS
);
98 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
99 data_blob_free(&unwrapped_edata
);
100 TALLOC_FREE(mem_ctx
);
104 data_blob_free(&unwrapped_edata
);
107 *nt_status
= parsed_edata
.ntstatus
;
110 TALLOC_FREE(mem_ctx
);
115 static bool smb_krb5_get_ntstatus_from_krb5_error_init_creds_opt(krb5_context ctx
,
116 krb5_get_init_creds_opt
*opt
,
120 krb5_error
*error
= NULL
;
122 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_GET_ERROR
123 ret
= krb5_get_init_creds_opt_get_error(ctx
, opt
, &error
);
125 DEBUG(1,("krb5_get_init_creds_opt_get_error gave: %s\n",
126 error_message(ret
)));
129 #endif /* HAVE_KRB5_GET_INIT_CREDS_OPT_GET_ERROR */
132 DEBUG(1,("no krb5_error\n"));
136 #ifdef HAVE_E_DATA_POINTER_IN_KRB5_ERROR
137 if (!error
->e_data
) {
139 if (error
->e_data
.data
== NULL
) {
140 #endif /* HAVE_E_DATA_POINTER_IN_KRB5_ERROR */
141 DEBUG(1,("no edata in krb5_error\n"));
142 krb5_free_error(ctx
, error
);
146 ret
= smb_krb5_get_ntstatus_from_krb5_error(error
, nt_status
);
148 krb5_free_error(ctx
, error
);
154 simulate a kinit, putting the tgt in the given cache location. If cache_name == NULL
155 place in default cache location.
158 int kerberos_kinit_password_ext(const char *principal
,
159 const char *password
,
162 time_t *renew_till_time
,
163 const char *cache_name
,
165 bool add_netbios_addr
,
166 time_t renewable_time
,
169 krb5_context ctx
= NULL
;
170 krb5_error_code code
= 0;
171 krb5_ccache cc
= NULL
;
172 krb5_principal me
= NULL
;
174 krb5_get_init_creds_opt
*opt
= NULL
;
175 smb_krb5_addresses
*addr
= NULL
;
177 ZERO_STRUCT(my_creds
);
179 initialize_krb5_error_table();
180 if ((code
= krb5_init_context(&ctx
)))
183 if (time_offset
!= 0) {
184 krb5_set_real_time(ctx
, time(NULL
) + time_offset
, 0);
187 DEBUG(10,("kerberos_kinit_password: as %s using [%s] as ccache and config [%s]\n",
189 cache_name
? cache_name
: krb5_cc_default_name(ctx
),
190 getenv("KRB5_CONFIG")));
192 if ((code
= krb5_cc_resolve(ctx
, cache_name
? cache_name
: krb5_cc_default_name(ctx
), &cc
))) {
196 if ((code
= smb_krb5_parse_name(ctx
, principal
, &me
))) {
200 if ((code
= smb_krb5_get_init_creds_opt_alloc(ctx
, &opt
))) {
204 krb5_get_init_creds_opt_set_renew_life(opt
, renewable_time
);
205 krb5_get_init_creds_opt_set_forwardable(opt
, True
);
208 krb5_get_init_creds_opt_set_tkt_life(opt
, 60);
211 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PAC_REQUEST
213 if ((code
= krb5_get_init_creds_opt_set_pac_request(ctx
, opt
, (krb5_boolean
)request_pac
))) {
218 if (add_netbios_addr
) {
219 if ((code
= smb_krb5_gen_netbios_krb5_address(&addr
))) {
222 krb5_get_init_creds_opt_set_address_list(opt
, addr
->addrs
);
225 if ((code
= krb5_get_init_creds_password(ctx
, &my_creds
, me
, CONST_DISCARD(char *,password
),
226 kerb_prompter
, CONST_DISCARD(char *,password
),
231 if ((code
= krb5_cc_initialize(ctx
, cc
, me
))) {
235 if ((code
= krb5_cc_store_cred(ctx
, cc
, &my_creds
))) {
240 *expire_time
= (time_t) my_creds
.times
.endtime
;
243 if (renew_till_time
) {
244 *renew_till_time
= (time_t) my_creds
.times
.renew_till
;
253 *ntstatus
= NT_STATUS_OK
;
257 /* try to get ntstatus code out of krb5_error when we have it
258 * inside the krb5_get_init_creds_opt - gd */
260 if (opt
&& smb_krb5_get_ntstatus_from_krb5_error_init_creds_opt(ctx
, opt
, &status
)) {
265 /* fall back to self-made-mapping */
266 *ntstatus
= krb5_to_nt_status(code
);
270 krb5_free_cred_contents(ctx
, &my_creds
);
272 krb5_free_principal(ctx
, me
);
275 smb_krb5_free_addresses(ctx
, addr
);
278 smb_krb5_get_init_creds_opt_free(ctx
, opt
);
281 krb5_cc_close(ctx
, cc
);
284 krb5_free_context(ctx
);
289 int ads_kdestroy(const char *cc_name
)
291 krb5_error_code code
;
292 krb5_context ctx
= NULL
;
293 krb5_ccache cc
= NULL
;
295 initialize_krb5_error_table();
296 if ((code
= krb5_init_context (&ctx
))) {
297 DEBUG(3, ("ads_kdestroy: kdb5_init_context failed: %s\n",
298 error_message(code
)));
303 if ((code
= krb5_cc_default(ctx
, &cc
))) {
304 krb5_free_context(ctx
);
308 if ((code
= krb5_cc_resolve(ctx
, cc_name
, &cc
))) {
309 DEBUG(3, ("ads_kdestroy: krb5_cc_resolve failed: %s\n",
310 error_message(code
)));
311 krb5_free_context(ctx
);
316 if ((code
= krb5_cc_destroy (ctx
, cc
))) {
317 DEBUG(3, ("ads_kdestroy: krb5_cc_destroy failed: %s\n",
318 error_message(code
)));
321 krb5_free_context (ctx
);
325 /************************************************************************
326 Routine to fetch the salting principal for a service. Active
327 Directory may use a non-obvious principal name to generate the salt
328 when it determines the key to use for encrypting tickets for a service,
329 and hopefully we detected that when we joined the domain.
330 ************************************************************************/
332 static char *kerberos_secrets_fetch_salting_principal(const char *service
, int enctype
)
337 if (asprintf(&key
, "%s/%s/enctype=%d",
338 SECRETS_SALTING_PRINCIPAL
, service
, enctype
) == -1) {
341 ret
= (char *)secrets_fetch(key
, NULL
);
346 /************************************************************************
347 Return the standard DES salt key
348 ************************************************************************/
350 char* kerberos_standard_des_salt( void )
354 fstr_sprintf( salt
, "host/%s.%s@", global_myname(), lp_realm() );
356 fstrcat( salt
, lp_realm() );
358 return SMB_STRDUP( salt
);
361 /************************************************************************
362 ************************************************************************/
364 static char* des_salt_key( void )
368 if (asprintf(&key
, "%s/DES/%s", SECRETS_SALTING_PRINCIPAL
,
376 /************************************************************************
377 ************************************************************************/
379 bool kerberos_secrets_store_des_salt( const char* salt
)
384 if ( (key
= des_salt_key()) == NULL
) {
385 DEBUG(0,("kerberos_secrets_store_des_salt: failed to generate key!\n"));
390 DEBUG(8,("kerberos_secrets_store_des_salt: deleting salt\n"));
391 secrets_delete( key
);
395 DEBUG(3,("kerberos_secrets_store_des_salt: Storing salt \"%s\"\n", salt
));
397 ret
= secrets_store( key
, salt
, strlen(salt
)+1 );
404 /************************************************************************
405 ************************************************************************/
407 char* kerberos_secrets_fetch_des_salt( void )
411 if ( (key
= des_salt_key()) == NULL
) {
412 DEBUG(0,("kerberos_secrets_fetch_des_salt: failed to generate key!\n"));
416 salt
= (char*)secrets_fetch( key
, NULL
);
423 /************************************************************************
424 Routine to get the default realm from the kerberos credentials cache.
425 Caller must free if the return value is not NULL.
426 ************************************************************************/
428 char *kerberos_get_default_realm_from_ccache( void )
431 krb5_context ctx
= NULL
;
432 krb5_ccache cc
= NULL
;
433 krb5_principal princ
= NULL
;
435 initialize_krb5_error_table();
436 if (krb5_init_context(&ctx
)) {
440 DEBUG(5,("kerberos_get_default_realm_from_ccache: "
441 "Trying to read krb5 cache: %s\n",
442 krb5_cc_default_name(ctx
)));
443 if (krb5_cc_default(ctx
, &cc
)) {
444 DEBUG(0,("kerberos_get_default_realm_from_ccache: "
445 "failed to read default cache\n"));
448 if (krb5_cc_get_principal(ctx
, cc
, &princ
)) {
449 DEBUG(0,("kerberos_get_default_realm_from_ccache: "
450 "failed to get default principal\n"));
454 #if defined(HAVE_KRB5_PRINCIPAL_GET_REALM)
455 realm
= SMB_STRDUP(krb5_principal_get_realm(ctx
, princ
));
456 #elif defined(HAVE_KRB5_PRINC_REALM)
458 krb5_data
*realm_data
= krb5_princ_realm(ctx
, princ
);
459 realm
= SMB_STRNDUP(realm_data
->data
, realm_data
->length
);
467 krb5_free_principal(ctx
, princ
);
470 krb5_cc_close(ctx
, cc
);
472 krb5_free_context(ctx
);
478 /************************************************************************
479 Routine to get the realm from a given DNS name. Returns malloc'ed memory.
480 Caller must free() if the return value is not NULL.
481 ************************************************************************/
483 char *kerberos_get_realm_from_hostname(const char *hostname
)
485 #if defined(HAVE_KRB5_GET_HOST_REALM) && defined(HAVE_KRB5_FREE_HOST_REALM)
486 #if defined(HAVE_KRB5_REALM_TYPE)
488 krb5_realm
*realm_list
= NULL
;
491 char **realm_list
= NULL
;
494 krb5_error_code kerr
;
495 krb5_context ctx
= NULL
;
497 initialize_krb5_error_table();
498 if (krb5_init_context(&ctx
)) {
502 kerr
= krb5_get_host_realm(ctx
, hostname
, &realm_list
);
504 DEBUG(3,("kerberos_get_realm_from_hostname %s: "
506 hostname
? hostname
: "(NULL)",
507 error_message(kerr
) ));
511 if (realm_list
&& realm_list
[0]) {
512 realm
= SMB_STRDUP(realm_list
[0]);
519 krb5_free_host_realm(ctx
, realm_list
);
522 krb5_free_context(ctx
);
531 /************************************************************************
532 Routine to get the salting principal for this service. This is
533 maintained for backwards compatibilty with releases prior to 3.0.24.
534 Since we store the salting principal string only at join, we may have
535 to look for the older tdb keys. Caller must free if return is not null.
536 ************************************************************************/
538 krb5_principal
kerberos_fetch_salt_princ_for_host_princ(krb5_context context
,
539 krb5_principal host_princ
,
542 char *unparsed_name
= NULL
, *salt_princ_s
= NULL
;
543 krb5_principal ret_princ
= NULL
;
545 /* lookup new key first */
547 if ( (salt_princ_s
= kerberos_secrets_fetch_des_salt()) == NULL
) {
549 /* look under the old key. If this fails, just use the standard key */
551 if (smb_krb5_unparse_name(talloc_tos(), context
, host_princ
, &unparsed_name
) != 0) {
552 return (krb5_principal
)NULL
;
554 if ((salt_princ_s
= kerberos_secrets_fetch_salting_principal(unparsed_name
, enctype
)) == NULL
) {
555 /* fall back to host/machine.realm@REALM */
556 salt_princ_s
= kerberos_standard_des_salt();
560 if (smb_krb5_parse_name(context
, salt_princ_s
, &ret_princ
) != 0) {
564 TALLOC_FREE(unparsed_name
);
565 SAFE_FREE(salt_princ_s
);
570 /************************************************************************
571 Routine to set the salting principal for this service. Active
572 Directory may use a non-obvious principal name to generate the salt
573 when it determines the key to use for encrypting tickets for a service,
574 and hopefully we detected that when we joined the domain.
575 Setting principal to NULL deletes this entry.
576 ************************************************************************/
578 bool kerberos_secrets_store_salting_principal(const char *service
,
580 const char *principal
)
584 krb5_context context
= NULL
;
585 krb5_principal princ
= NULL
;
586 char *princ_s
= NULL
;
587 char *unparsed_name
= NULL
;
588 krb5_error_code code
;
590 if (((code
= krb5_init_context(&context
)) != 0) || (context
== NULL
)) {
591 DEBUG(5, ("kerberos_secrets_store_salting_pricipal: kdb5_init_context failed: %s\n",
592 error_message(code
)));
595 if (strchr_m(service
, '@')) {
596 if (asprintf(&princ_s
, "%s", service
) == -1) {
600 if (asprintf(&princ_s
, "%s@%s", service
, lp_realm()) == -1) {
605 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
;
854 if (!lp_create_krb5_conf()) {
858 dname
= lock_path("smb_krb5");
862 if ((mkdir(dname
, 0755)==-1) && (errno
!= EEXIST
)) {
863 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
864 "failed to create directory %s. Error was %s\n",
865 dname
, strerror(errno
) ));
869 tmpname
= lock_path("smb_tmp_krb5.XXXXXX");
874 fname
= talloc_asprintf(dname
, "%s/krb5.conf.%s", dname
, domain
);
879 DEBUG(10,("create_local_private_krb5_conf_for_domain: fname = %s, realm = %s, domain = %s\n",
880 fname
, realm
, domain
));
882 realm_upper
= talloc_strdup(fname
, realm
);
883 strupper_m(realm_upper
);
885 kdc_ip_string
= get_kdc_ip_string(dname
, realm
, sitename
, pss
, kdc_name
);
886 if (!kdc_ip_string
) {
890 file_contents
= talloc_asprintf(fname
,
891 "[libdefaults]\n\tdefault_realm = %s\n"
892 "\tdefault_tgs_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
893 "\tdefault_tkt_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
894 "\tpreferred_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n\n"
895 "[realms]\n\t%s = {\n"
897 realm_upper
, realm_upper
, kdc_ip_string
);
899 if (!file_contents
) {
903 flen
= strlen(file_contents
);
905 fd
= mkstemp(tmpname
);
907 DEBUG(0,("create_local_private_krb5_conf_for_domain: smb_mkstemp failed,"
908 " for file %s. Errno %s\n",
909 tmpname
, strerror(errno
) ));
913 if (fchmod(fd
, 0644)==-1) {
914 DEBUG(0,("create_local_private_krb5_conf_for_domain: fchmod failed for %s."
916 tmpname
, strerror(errno
) ));
922 ret
= write(fd
, file_contents
, flen
);
924 DEBUG(0,("create_local_private_krb5_conf_for_domain: write failed,"
925 " returned %d (should be %u). Errno %s\n",
926 (int)ret
, (unsigned int)flen
, strerror(errno
) ));
932 DEBUG(0,("create_local_private_krb5_conf_for_domain: close failed."
933 " Errno %s\n", strerror(errno
) ));
938 if (rename(tmpname
, fname
) == -1) {
939 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
940 "of %s to %s failed. Errno %s\n",
941 tmpname
, fname
, strerror(errno
) ));
946 DEBUG(5,("create_local_private_krb5_conf_for_domain: wrote "
947 "file %s with realm %s KDC list = %s\n",
948 fname
, realm_upper
, kdc_ip_string
));
950 /* Set the environment variable to this file. */
951 setenv("KRB5_CONFIG", fname
, 1);
955 #if defined(OVERWRITE_SYSTEM_KRB5_CONF)
957 #define SYSTEM_KRB5_CONF_PATH "/etc/krb5.conf"
958 /* Insanity, sheer insanity..... */
960 if (strequal(realm
, lp_realm())) {
961 char linkpath
[PATH_MAX
+1];
964 lret
= readlink(SYSTEM_KRB5_CONF_PATH
, linkpath
, sizeof(linkpath
)-1);
966 linkpath
[lret
] = '\0';
969 if (lret
!= -1 || strcmp(linkpath
, fname
) == 0) {
970 /* Symlink already exists. */
974 /* Try and replace with a symlink. */
975 if (symlink(fname
, SYSTEM_KRB5_CONF_PATH
) == -1) {
976 const char *newpath
= SYSTEM_KRB5_CONF_PATH
## ".saved";
977 if (errno
!= EEXIST
) {
978 DEBUG(0,("create_local_private_krb5_conf_for_domain: symlink "
979 "of %s to %s failed. Errno %s\n",
980 fname
, SYSTEM_KRB5_CONF_PATH
, strerror(errno
) ));
981 goto done
; /* Not a fatal error. */
984 /* Yes, this is a race conditon... too bad. */
985 if (rename(SYSTEM_KRB5_CONF_PATH
, newpath
) == -1) {
986 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
987 "of %s to %s failed. Errno %s\n",
988 SYSTEM_KRB5_CONF_PATH
, newpath
,
990 goto done
; /* Not a fatal error. */
993 if (symlink(fname
, SYSTEM_KRB5_CONF_PATH
) == -1) {
994 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
995 "forced symlink of %s to /etc/krb5.conf failed. Errno %s\n",
996 fname
, strerror(errno
) ));
997 goto done
; /* Not a fatal error. */
1004 TALLOC_FREE(tmpname
);