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/>.
29 #define DEFAULT_KRB5_PORT 88
31 #define LIBADS_CCACHE_NAME "MEMORY:libads"
34 we use a prompter to avoid a crash bug in the kerberos libs when
35 dealing with empty passwords
36 this prompter is just a string copy ...
38 static krb5_error_code
39 kerb_prompter(krb5_context ctx
, void *data
,
43 krb5_prompt prompts
[])
45 if (num_prompts
== 0) return 0;
47 memset(prompts
[0].reply
->data
, '\0', prompts
[0].reply
->length
);
48 if (prompts
[0].reply
->length
> 0) {
50 strncpy((char *)prompts
[0].reply
->data
, (const char *)data
,
51 prompts
[0].reply
->length
-1);
52 prompts
[0].reply
->length
= strlen((const char *)prompts
[0].reply
->data
);
54 prompts
[0].reply
->length
= 0;
60 static bool smb_krb5_err_io_nstatus(TALLOC_CTX
*mem_ctx
,
61 DATA_BLOB
*edata_blob
,
62 KRB5_EDATA_NTSTATUS
*edata
)
67 if (!mem_ctx
|| !edata_blob
|| !edata
)
70 if (!prs_init(&ps
, edata_blob
->length
, mem_ctx
, UNMARSHALL
))
73 if (!prs_copy_data_in(&ps
, (char *)edata_blob
->data
, edata_blob
->length
))
76 prs_set_offset(&ps
, 0);
78 if (!prs_ntstatus("ntstatus", &ps
, 1, &edata
->ntstatus
))
81 if (!prs_uint32("unknown1", &ps
, 1, &edata
->unknown1
))
84 if (!prs_uint32("unknown2", &ps
, 1, &edata
->unknown2
)) /* only seen 00000001 here */
94 static bool smb_krb5_get_ntstatus_from_krb5_error(krb5_error
*error
,
98 DATA_BLOB unwrapped_edata
;
100 KRB5_EDATA_NTSTATUS parsed_edata
;
102 #ifdef HAVE_E_DATA_POINTER_IN_KRB5_ERROR
103 edata
= data_blob(error
->e_data
->data
, error
->e_data
->length
);
105 edata
= data_blob(error
->e_data
.data
, error
->e_data
.length
);
106 #endif /* HAVE_E_DATA_POINTER_IN_KRB5_ERROR */
109 dump_data(10, edata
.data
, edata
.length
);
110 #endif /* DEVELOPER */
112 mem_ctx
= talloc_init("smb_krb5_get_ntstatus_from_krb5_error");
113 if (mem_ctx
== NULL
) {
114 data_blob_free(&edata
);
118 if (!unwrap_edata_ntstatus(mem_ctx
, &edata
, &unwrapped_edata
)) {
119 data_blob_free(&edata
);
120 TALLOC_FREE(mem_ctx
);
124 data_blob_free(&edata
);
126 if (!smb_krb5_err_io_nstatus(mem_ctx
, &unwrapped_edata
, &parsed_edata
)) {
127 data_blob_free(&unwrapped_edata
);
128 TALLOC_FREE(mem_ctx
);
132 data_blob_free(&unwrapped_edata
);
135 *nt_status
= parsed_edata
.ntstatus
;
138 TALLOC_FREE(mem_ctx
);
143 static bool smb_krb5_get_ntstatus_from_krb5_error_init_creds_opt(krb5_context ctx
,
144 krb5_get_init_creds_opt
*opt
,
148 krb5_error
*error
= NULL
;
150 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_GET_ERROR
151 ret
= krb5_get_init_creds_opt_get_error(ctx
, opt
, &error
);
153 DEBUG(1,("krb5_get_init_creds_opt_get_error gave: %s\n",
154 error_message(ret
)));
157 #endif /* HAVE_KRB5_GET_INIT_CREDS_OPT_GET_ERROR */
160 DEBUG(1,("no krb5_error\n"));
164 #ifdef HAVE_E_DATA_POINTER_IN_KRB5_ERROR
165 if (!error
->e_data
) {
167 if (error
->e_data
.data
== NULL
) {
168 #endif /* HAVE_E_DATA_POINTER_IN_KRB5_ERROR */
169 DEBUG(1,("no edata in krb5_error\n"));
170 krb5_free_error(ctx
, error
);
174 ret
= smb_krb5_get_ntstatus_from_krb5_error(error
, nt_status
);
176 krb5_free_error(ctx
, error
);
182 simulate a kinit, putting the tgt in the given cache location. If cache_name == NULL
183 place in default cache location.
186 int kerberos_kinit_password_ext(const char *principal
,
187 const char *password
,
190 time_t *renew_till_time
,
191 const char *cache_name
,
193 bool add_netbios_addr
,
194 time_t renewable_time
,
197 krb5_context ctx
= NULL
;
198 krb5_error_code code
= 0;
199 krb5_ccache cc
= NULL
;
200 krb5_principal me
= NULL
;
202 krb5_get_init_creds_opt
*opt
= NULL
;
203 smb_krb5_addresses
*addr
= NULL
;
205 ZERO_STRUCT(my_creds
);
207 initialize_krb5_error_table();
208 if ((code
= krb5_init_context(&ctx
)))
211 if (time_offset
!= 0) {
212 krb5_set_real_time(ctx
, time(NULL
) + time_offset
, 0);
215 DEBUG(10,("kerberos_kinit_password: as %s using [%s] as ccache and config [%s]\n",
217 cache_name
? cache_name
: krb5_cc_default_name(ctx
),
218 getenv("KRB5_CONFIG")));
220 if ((code
= krb5_cc_resolve(ctx
, cache_name
? cache_name
: krb5_cc_default_name(ctx
), &cc
))) {
224 if ((code
= smb_krb5_parse_name(ctx
, principal
, &me
))) {
228 if ((code
= smb_krb5_get_init_creds_opt_alloc(ctx
, &opt
))) {
232 krb5_get_init_creds_opt_set_renew_life(opt
, renewable_time
);
233 krb5_get_init_creds_opt_set_forwardable(opt
, True
);
236 krb5_get_init_creds_opt_set_tkt_life(opt
, 60);
239 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PAC_REQUEST
241 if ((code
= krb5_get_init_creds_opt_set_pac_request(ctx
, opt
, (krb5_boolean
)request_pac
))) {
246 if (add_netbios_addr
) {
247 if ((code
= smb_krb5_gen_netbios_krb5_address(&addr
))) {
250 krb5_get_init_creds_opt_set_address_list(opt
, addr
->addrs
);
253 if ((code
= krb5_get_init_creds_password(ctx
, &my_creds
, me
, CONST_DISCARD(char *,password
),
254 kerb_prompter
, CONST_DISCARD(char *,password
),
259 if ((code
= krb5_cc_initialize(ctx
, cc
, me
))) {
263 if ((code
= krb5_cc_store_cred(ctx
, cc
, &my_creds
))) {
268 *expire_time
= (time_t) my_creds
.times
.endtime
;
271 if (renew_till_time
) {
272 *renew_till_time
= (time_t) my_creds
.times
.renew_till
;
281 *ntstatus
= NT_STATUS_OK
;
285 /* try to get ntstatus code out of krb5_error when we have it
286 * inside the krb5_get_init_creds_opt - gd */
288 if (opt
&& smb_krb5_get_ntstatus_from_krb5_error_init_creds_opt(ctx
, opt
, &status
)) {
293 /* fall back to self-made-mapping */
294 *ntstatus
= krb5_to_nt_status(code
);
298 krb5_free_cred_contents(ctx
, &my_creds
);
300 krb5_free_principal(ctx
, me
);
303 smb_krb5_free_addresses(ctx
, addr
);
306 smb_krb5_get_init_creds_opt_free(ctx
, opt
);
309 krb5_cc_close(ctx
, cc
);
312 krb5_free_context(ctx
);
319 /* run kinit to setup our ccache */
320 int ads_kinit_password(ADS_STRUCT
*ads
)
324 const char *account_name
;
327 if (ads
->auth
.flags
& ADS_AUTH_USER_CREDS
) {
328 account_name
= ads
->auth
.user_name
;
329 goto got_accountname
;
333 /* this will end up getting a ticket for DOMAIN@RUSTED.REA.LM */
334 account_name
= lp_workgroup();
336 /* always use the sAMAccountName for security = domain */
337 /* global_myname()$@REA.LM */
338 if ( lp_security() == SEC_DOMAIN
) {
339 fstr_sprintf( acct_name
, "%s$", global_myname() );
340 account_name
= acct_name
;
343 /* This looks like host/global_myname()@REA.LM */
344 account_name
= ads
->auth
.user_name
;
348 if (asprintf(&s
, "%s@%s", account_name
, ads
->auth
.realm
) == -1) {
349 return KRB5_CC_NOMEM
;
352 if (!ads
->auth
.password
) {
354 return KRB5_LIBOS_CANTREADPWD
;
357 ret
= kerberos_kinit_password_ext(s
, ads
->auth
.password
, ads
->auth
.time_offset
,
358 &ads
->auth
.tgt_expire
, NULL
, NULL
, False
, False
, ads
->auth
.renewable
,
362 DEBUG(0,("kerberos_kinit_password %s failed: %s\n",
363 s
, error_message(ret
)));
369 int ads_kdestroy(const char *cc_name
)
371 krb5_error_code code
;
372 krb5_context ctx
= NULL
;
373 krb5_ccache cc
= NULL
;
375 initialize_krb5_error_table();
376 if ((code
= krb5_init_context (&ctx
))) {
377 DEBUG(3, ("ads_kdestroy: kdb5_init_context failed: %s\n",
378 error_message(code
)));
383 if ((code
= krb5_cc_default(ctx
, &cc
))) {
384 krb5_free_context(ctx
);
388 if ((code
= krb5_cc_resolve(ctx
, cc_name
, &cc
))) {
389 DEBUG(3, ("ads_kdestroy: krb5_cc_resolve failed: %s\n",
390 error_message(code
)));
391 krb5_free_context(ctx
);
396 if ((code
= krb5_cc_destroy (ctx
, cc
))) {
397 DEBUG(3, ("ads_kdestroy: krb5_cc_destroy failed: %s\n",
398 error_message(code
)));
401 krb5_free_context (ctx
);
405 /************************************************************************
406 Routine to fetch the salting principal for a service. Active
407 Directory may use a non-obvious principal name to generate the salt
408 when it determines the key to use for encrypting tickets for a service,
409 and hopefully we detected that when we joined the domain.
410 ************************************************************************/
412 static char *kerberos_secrets_fetch_salting_principal(const char *service
, int enctype
)
417 if (asprintf(&key
, "%s/%s/enctype=%d",
418 SECRETS_SALTING_PRINCIPAL
, service
, enctype
) == -1) {
421 ret
= (char *)secrets_fetch(key
, NULL
);
426 /************************************************************************
427 Return the standard DES salt key
428 ************************************************************************/
430 char* kerberos_standard_des_salt( void )
434 fstr_sprintf( salt
, "host/%s.%s@", global_myname(), lp_realm() );
436 fstrcat( salt
, lp_realm() );
438 return SMB_STRDUP( salt
);
441 /************************************************************************
442 ************************************************************************/
444 static char* des_salt_key( void )
448 if (asprintf(&key
, "%s/DES/%s", SECRETS_SALTING_PRINCIPAL
,
456 /************************************************************************
457 ************************************************************************/
459 bool kerberos_secrets_store_des_salt( const char* salt
)
464 if ( (key
= des_salt_key()) == NULL
) {
465 DEBUG(0,("kerberos_secrets_store_des_salt: failed to generate key!\n"));
470 DEBUG(8,("kerberos_secrets_store_des_salt: deleting salt\n"));
471 secrets_delete( key
);
475 DEBUG(3,("kerberos_secrets_store_des_salt: Storing salt \"%s\"\n", salt
));
477 ret
= secrets_store( key
, salt
, strlen(salt
)+1 );
484 /************************************************************************
485 ************************************************************************/
487 char* kerberos_secrets_fetch_des_salt( void )
491 if ( (key
= des_salt_key()) == NULL
) {
492 DEBUG(0,("kerberos_secrets_fetch_des_salt: failed to generate key!\n"));
496 salt
= (char*)secrets_fetch( key
, NULL
);
503 /************************************************************************
504 Routine to get the default realm from the kerberos credentials cache.
505 Caller must free if the return value is not NULL.
506 ************************************************************************/
508 char *kerberos_get_default_realm_from_ccache( void )
511 krb5_context ctx
= NULL
;
512 krb5_ccache cc
= NULL
;
513 krb5_principal princ
= NULL
;
515 initialize_krb5_error_table();
516 if (krb5_init_context(&ctx
)) {
520 DEBUG(5,("kerberos_get_default_realm_from_ccache: "
521 "Trying to read krb5 cache: %s\n",
522 krb5_cc_default_name(ctx
)));
523 if (krb5_cc_default(ctx
, &cc
)) {
524 DEBUG(0,("kerberos_get_default_realm_from_ccache: "
525 "failed to read default cache\n"));
528 if (krb5_cc_get_principal(ctx
, cc
, &princ
)) {
529 DEBUG(0,("kerberos_get_default_realm_from_ccache: "
530 "failed to get default principal\n"));
534 #if defined(HAVE_KRB5_PRINCIPAL_GET_REALM)
535 realm
= SMB_STRDUP(krb5_principal_get_realm(ctx
, princ
));
536 #elif defined(HAVE_KRB5_PRINC_REALM)
538 krb5_data
*realm_data
= krb5_princ_realm(ctx
, princ
);
539 realm
= SMB_STRNDUP(realm_data
->data
, realm_data
->length
);
547 krb5_free_principal(ctx
, princ
);
550 krb5_cc_close(ctx
, cc
);
552 krb5_free_context(ctx
);
559 /************************************************************************
560 Routine to get the salting principal for this service. This is
561 maintained for backwards compatibilty with releases prior to 3.0.24.
562 Since we store the salting principal string only at join, we may have
563 to look for the older tdb keys. Caller must free if return is not null.
564 ************************************************************************/
566 krb5_principal
kerberos_fetch_salt_princ_for_host_princ(krb5_context context
,
567 krb5_principal host_princ
,
570 char *unparsed_name
= NULL
, *salt_princ_s
= NULL
;
571 krb5_principal ret_princ
= NULL
;
573 /* lookup new key first */
575 if ( (salt_princ_s
= kerberos_secrets_fetch_des_salt()) == NULL
) {
577 /* look under the old key. If this fails, just use the standard key */
579 if (smb_krb5_unparse_name(context
, host_princ
, &unparsed_name
) != 0) {
580 return (krb5_principal
)NULL
;
582 if ((salt_princ_s
= kerberos_secrets_fetch_salting_principal(unparsed_name
, enctype
)) == NULL
) {
583 /* fall back to host/machine.realm@REALM */
584 salt_princ_s
= kerberos_standard_des_salt();
588 if (smb_krb5_parse_name(context
, salt_princ_s
, &ret_princ
) != 0) {
592 SAFE_FREE(unparsed_name
);
593 SAFE_FREE(salt_princ_s
);
598 /************************************************************************
599 Routine to set the salting principal for this service. Active
600 Directory may use a non-obvious principal name to generate the salt
601 when it determines the key to use for encrypting tickets for a service,
602 and hopefully we detected that when we joined the domain.
603 Setting principal to NULL deletes this entry.
604 ************************************************************************/
606 bool kerberos_secrets_store_salting_principal(const char *service
,
608 const char *principal
)
612 krb5_context context
= NULL
;
613 krb5_principal princ
= NULL
;
614 char *princ_s
= NULL
;
615 char *unparsed_name
= NULL
;
616 krb5_error_code code
;
618 if (((code
= krb5_init_context(&context
)) != 0) || (context
== NULL
)) {
619 DEBUG(5, ("kerberos_secrets_store_salting_pricipal: kdb5_init_context failed: %s\n",
620 error_message(code
)));
623 if (strchr_m(service
, '@')) {
624 if (asprintf(&princ_s
, "%s", service
) == -1) {
628 if (asprintf(&princ_s
, "%s@%s", service
, lp_realm()) == -1) {
633 if (smb_krb5_parse_name(context
, princ_s
, &princ
) != 0) {
637 if (smb_krb5_unparse_name(context
, princ
, &unparsed_name
) != 0) {
641 if (asprintf(&key
, "%s/%s/enctype=%d",
642 SECRETS_SALTING_PRINCIPAL
, unparsed_name
, enctype
)
647 if ((principal
!= NULL
) && (strlen(principal
) > 0)) {
648 ret
= secrets_store(key
, principal
, strlen(principal
) + 1);
650 ret
= secrets_delete(key
);
657 SAFE_FREE(unparsed_name
);
660 krb5_free_principal(context
, princ
);
664 krb5_free_context(context
);
671 /************************************************************************
672 ************************************************************************/
674 int kerberos_kinit_password(const char *principal
,
675 const char *password
,
677 const char *cache_name
)
679 return kerberos_kinit_password_ext(principal
,
691 /************************************************************************
692 ************************************************************************/
694 static char *print_kdc_line(char *mem_ctx
,
695 const char *prev_line
,
696 const struct sockaddr_storage
*pss
)
698 char *kdc_str
= NULL
;
700 if (pss
->ss_family
== AF_INET
) {
701 kdc_str
= talloc_asprintf(mem_ctx
, "%s\tkdc = %s\n",
703 print_canonical_sockaddr(mem_ctx
, pss
));
705 char addr
[INET6_ADDRSTRLEN
];
706 uint16_t port
= get_sockaddr_port(pss
);
708 if (port
!= 0 && port
!= DEFAULT_KRB5_PORT
) {
709 /* Currently for IPv6 we can't specify a non-default
710 krb5 port with an address, as this requires a ':'.
711 Resolve to a name. */
712 char hostname
[MAX_DNS_NAME_LENGTH
];
713 int ret
= sys_getnameinfo((const struct sockaddr
*)pss
,
715 hostname
, sizeof(hostname
),
719 DEBUG(0,("print_kdc_line: can't resolve name "
720 "for kdc with non-default port %s. "
722 print_canonical_sockaddr(mem_ctx
, pss
),
725 /* Success, use host:port */
726 kdc_str
= talloc_asprintf(mem_ctx
,
732 kdc_str
= talloc_asprintf(mem_ctx
, "%s\tkdc = %s\n",
742 /************************************************************************
743 Create a string list of available kdc's, possibly searching by sitename.
746 If "sitename" is given, the DC's in that site are listed first.
748 ************************************************************************/
750 static char *get_kdc_ip_string(char *mem_ctx
,
752 const char *sitename
,
753 struct sockaddr_storage
*pss
)
756 struct ip_service
*ip_srv_site
= NULL
;
757 struct ip_service
*ip_srv_nonsite
= NULL
;
760 char *kdc_str
= print_kdc_line(mem_ctx
, "", pss
);
762 if (kdc_str
== NULL
) {
767 * First get the KDC's only in this site, the rest will be
773 get_kdc_list(realm
, sitename
, &ip_srv_site
, &count_site
);
775 for (i
= 0; i
< count_site
; i
++) {
776 if (sockaddr_equal(&ip_srv_site
[i
].ss
, pss
)) {
779 /* Append to the string - inefficient
780 * but not done often. */
781 kdc_str
= print_kdc_line(mem_ctx
,
785 SAFE_FREE(ip_srv_site
);
793 get_kdc_list(realm
, NULL
, &ip_srv_nonsite
, &count_nonsite
);
795 for (i
= 0; i
< count_nonsite
; i
++) {
798 if (sockaddr_equal(&ip_srv_nonsite
[i
].ss
, pss
)) {
802 /* Ensure this isn't an IP already seen (YUK! this is n*n....) */
803 for (j
= 0; j
< count_site
; j
++) {
804 if (sockaddr_equal(&ip_srv_nonsite
[i
].ss
,
805 &ip_srv_site
[j
].ss
)) {
808 /* As the lists are sorted we can break early if nonsite > site. */
809 if (ip_service_compare(&ip_srv_nonsite
[i
], &ip_srv_site
[j
]) > 0) {
817 /* Append to the string - inefficient but not done often. */
818 kdc_str
= print_kdc_line(mem_ctx
,
820 &ip_srv_nonsite
[i
].ss
);
822 SAFE_FREE(ip_srv_site
);
823 SAFE_FREE(ip_srv_nonsite
);
829 SAFE_FREE(ip_srv_site
);
830 SAFE_FREE(ip_srv_nonsite
);
832 DEBUG(10,("get_kdc_ip_string: Returning %s\n",
838 /************************************************************************
839 Create a specific krb5.conf file in the private directory pointing
840 at a specific kdc for a realm. Keyed off domain name. Sets
841 KRB5_CONFIG environment variable to point to this file. Must be
842 run as root or will fail (which is a good thing :-).
843 ************************************************************************/
845 bool create_local_private_krb5_conf_for_domain(const char *realm
,
847 const char *sitename
,
848 struct sockaddr_storage
*pss
)
850 char *dname
= talloc_asprintf(NULL
, "%s/smb_krb5", lp_lockdir());
851 char *tmpname
= NULL
;
853 char *file_contents
= NULL
;
854 char *kdc_ip_string
= NULL
;
858 char *realm_upper
= NULL
;
863 if ((mkdir(dname
, 0755)==-1) && (errno
!= EEXIST
)) {
864 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
865 "failed to create directory %s. Error was %s\n",
866 dname
, strerror(errno
) ));
871 tmpname
= talloc_asprintf(dname
, "%s/smb_tmp_krb5.XXXXXX", lp_lockdir());
877 fname
= talloc_asprintf(dname
, "%s/krb5.conf.%s", dname
, domain
);
883 DEBUG(10,("create_local_private_krb5_conf_for_domain: fname = %s, realm = %s, domain = %s\n",
884 fname
, realm
, domain
));
886 realm_upper
= talloc_strdup(fname
, realm
);
887 strupper_m(realm_upper
);
889 kdc_ip_string
= get_kdc_ip_string(dname
, realm
, sitename
, pss
);
890 if (!kdc_ip_string
) {
895 file_contents
= talloc_asprintf(fname
,
896 "[libdefaults]\n\tdefault_realm = %s\n"
897 "\tdefault_tgs_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
898 "\tdefault_tkt_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
899 "\tpreferred_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n\n"
900 "[realms]\n\t%s = {\n"
902 realm_upper
, realm_upper
, kdc_ip_string
);
904 if (!file_contents
) {
909 flen
= strlen(file_contents
);
911 fd
= smb_mkstemp(tmpname
);
913 DEBUG(0,("create_local_private_krb5_conf_for_domain: smb_mkstemp failed,"
914 " for file %s. Errno %s\n",
915 tmpname
, strerror(errno
) ));
920 if (fchmod(fd
, 0644)==-1) {
921 DEBUG(0,("create_local_private_krb5_conf_for_domain: fchmod failed for %s."
923 tmpname
, strerror(errno
) ));
930 ret
= write(fd
, file_contents
, flen
);
932 DEBUG(0,("create_local_private_krb5_conf_for_domain: write failed,"
933 " returned %d (should be %u). Errno %s\n",
934 (int)ret
, (unsigned int)flen
, strerror(errno
) ));
941 DEBUG(0,("create_local_private_krb5_conf_for_domain: close failed."
942 " Errno %s\n", strerror(errno
) ));
948 if (rename(tmpname
, fname
) == -1) {
949 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
950 "of %s to %s failed. Errno %s\n",
951 tmpname
, fname
, strerror(errno
) ));
957 DEBUG(5,("create_local_private_krb5_conf_for_domain: wrote "
958 "file %s with realm %s KDC list = %s\n",
959 fname
, realm_upper
, kdc_ip_string
));
961 /* Set the environment variable to this file. */
962 setenv("KRB5_CONFIG", fname
, 1);
964 #if defined(OVERWRITE_SYSTEM_KRB5_CONF)
966 #define SYSTEM_KRB5_CONF_PATH "/etc/krb5.conf"
967 /* Insanity, sheer insanity..... */
969 if (strequal(realm
, lp_realm())) {
970 char linkpath
[PATH_MAX
+1];
973 lret
= readlink(SYSTEM_KRB5_CONF_PATH
, linkpath
, sizeof(linkpath
)-1);
975 linkpath
[lret
] = '\0';
978 if (lret
!= -1 || strcmp(linkpath
, fname
) == 0) {
979 /* Symlink already exists. */
984 /* Try and replace with a symlink. */
985 if (symlink(fname
, SYSTEM_KRB5_CONF_PATH
) == -1) {
986 const char *newpath
= SYSTEM_KRB5_CONF_PATH
## ".saved";
987 if (errno
!= EEXIST
) {
988 DEBUG(0,("create_local_private_krb5_conf_for_domain: symlink "
989 "of %s to %s failed. Errno %s\n",
990 fname
, SYSTEM_KRB5_CONF_PATH
, strerror(errno
) ));
992 return True
; /* Not a fatal error. */
995 /* Yes, this is a race conditon... too bad. */
996 if (rename(SYSTEM_KRB5_CONF_PATH
, newpath
) == -1) {
997 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
998 "of %s to %s failed. Errno %s\n",
999 SYSTEM_KRB5_CONF_PATH
, newpath
,
1002 return True
; /* Not a fatal error. */
1005 if (symlink(fname
, SYSTEM_KRB5_CONF_PATH
) == -1) {
1006 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
1007 "forced symlink of %s to /etc/krb5.conf failed. Errno %s\n",
1008 fname
, strerror(errno
) ));
1010 return True
; /* Not a fatal error. */