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_get_ntstatus_from_krb5_error(krb5_error
*error
,
64 DATA_BLOB unwrapped_edata
;
66 struct KRB5_EDATA_NTSTATUS parsed_edata
;
67 enum ndr_err_code ndr_err
;
69 #ifdef HAVE_E_DATA_POINTER_IN_KRB5_ERROR
70 edata
= data_blob(error
->e_data
->data
, error
->e_data
->length
);
72 edata
= data_blob(error
->e_data
.data
, error
->e_data
.length
);
73 #endif /* HAVE_E_DATA_POINTER_IN_KRB5_ERROR */
76 dump_data(10, edata
.data
, edata
.length
);
77 #endif /* DEVELOPER */
79 mem_ctx
= talloc_init("smb_krb5_get_ntstatus_from_krb5_error");
80 if (mem_ctx
== NULL
) {
81 data_blob_free(&edata
);
85 if (!unwrap_edata_ntstatus(mem_ctx
, &edata
, &unwrapped_edata
)) {
86 data_blob_free(&edata
);
91 data_blob_free(&edata
);
93 ndr_err
= ndr_pull_struct_blob_all(&unwrapped_edata
, mem_ctx
, NULL
,
95 (ndr_pull_flags_fn_t
)ndr_pull_KRB5_EDATA_NTSTATUS
);
96 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
97 data_blob_free(&unwrapped_edata
);
102 data_blob_free(&unwrapped_edata
);
105 *nt_status
= parsed_edata
.ntstatus
;
108 TALLOC_FREE(mem_ctx
);
113 static bool smb_krb5_get_ntstatus_from_krb5_error_init_creds_opt(krb5_context ctx
,
114 krb5_get_init_creds_opt
*opt
,
118 krb5_error
*error
= NULL
;
120 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_GET_ERROR
121 ret
= krb5_get_init_creds_opt_get_error(ctx
, opt
, &error
);
123 DEBUG(1,("krb5_get_init_creds_opt_get_error gave: %s\n",
124 error_message(ret
)));
127 #endif /* HAVE_KRB5_GET_INIT_CREDS_OPT_GET_ERROR */
130 DEBUG(1,("no krb5_error\n"));
134 #ifdef HAVE_E_DATA_POINTER_IN_KRB5_ERROR
135 if (!error
->e_data
) {
137 if (error
->e_data
.data
== NULL
) {
138 #endif /* HAVE_E_DATA_POINTER_IN_KRB5_ERROR */
139 DEBUG(1,("no edata in krb5_error\n"));
140 krb5_free_error(ctx
, error
);
144 ret
= smb_krb5_get_ntstatus_from_krb5_error(error
, nt_status
);
146 krb5_free_error(ctx
, error
);
152 simulate a kinit, putting the tgt in the given cache location. If cache_name == NULL
153 place in default cache location.
156 int kerberos_kinit_password_ext(const char *principal
,
157 const char *password
,
160 time_t *renew_till_time
,
161 const char *cache_name
,
163 bool add_netbios_addr
,
164 time_t renewable_time
,
167 krb5_context ctx
= NULL
;
168 krb5_error_code code
= 0;
169 krb5_ccache cc
= NULL
;
170 krb5_principal me
= NULL
;
172 krb5_get_init_creds_opt
*opt
= NULL
;
173 smb_krb5_addresses
*addr
= NULL
;
175 ZERO_STRUCT(my_creds
);
177 initialize_krb5_error_table();
178 if ((code
= krb5_init_context(&ctx
)))
181 if (time_offset
!= 0) {
182 krb5_set_real_time(ctx
, time(NULL
) + time_offset
, 0);
185 DEBUG(10,("kerberos_kinit_password: as %s using [%s] as ccache and config [%s]\n",
187 cache_name
? cache_name
: krb5_cc_default_name(ctx
),
188 getenv("KRB5_CONFIG")));
190 if ((code
= krb5_cc_resolve(ctx
, cache_name
? cache_name
: krb5_cc_default_name(ctx
), &cc
))) {
194 if ((code
= smb_krb5_parse_name(ctx
, principal
, &me
))) {
198 if ((code
= smb_krb5_get_init_creds_opt_alloc(ctx
, &opt
))) {
202 krb5_get_init_creds_opt_set_renew_life(opt
, renewable_time
);
203 krb5_get_init_creds_opt_set_forwardable(opt
, True
);
206 krb5_get_init_creds_opt_set_tkt_life(opt
, 60);
209 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PAC_REQUEST
211 if ((code
= krb5_get_init_creds_opt_set_pac_request(ctx
, opt
, (krb5_boolean
)request_pac
))) {
216 if (add_netbios_addr
) {
217 if ((code
= smb_krb5_gen_netbios_krb5_address(&addr
))) {
220 krb5_get_init_creds_opt_set_address_list(opt
, addr
->addrs
);
223 if ((code
= krb5_get_init_creds_password(ctx
, &my_creds
, me
, CONST_DISCARD(char *,password
),
224 kerb_prompter
, CONST_DISCARD(char *,password
),
229 if ((code
= krb5_cc_initialize(ctx
, cc
, me
))) {
233 if ((code
= krb5_cc_store_cred(ctx
, cc
, &my_creds
))) {
238 *expire_time
= (time_t) my_creds
.times
.endtime
;
241 if (renew_till_time
) {
242 *renew_till_time
= (time_t) my_creds
.times
.renew_till
;
251 *ntstatus
= NT_STATUS_OK
;
255 /* try to get ntstatus code out of krb5_error when we have it
256 * inside the krb5_get_init_creds_opt - gd */
258 if (opt
&& smb_krb5_get_ntstatus_from_krb5_error_init_creds_opt(ctx
, opt
, &status
)) {
263 /* fall back to self-made-mapping */
264 *ntstatus
= krb5_to_nt_status(code
);
268 krb5_free_cred_contents(ctx
, &my_creds
);
270 krb5_free_principal(ctx
, me
);
273 smb_krb5_free_addresses(ctx
, addr
);
276 smb_krb5_get_init_creds_opt_free(ctx
, opt
);
279 krb5_cc_close(ctx
, cc
);
282 krb5_free_context(ctx
);
289 /* run kinit to setup our ccache */
290 int ads_kinit_password(ADS_STRUCT
*ads
)
294 const char *account_name
;
297 if (ads
->auth
.flags
& ADS_AUTH_USER_CREDS
) {
298 account_name
= ads
->auth
.user_name
;
299 goto got_accountname
;
303 /* this will end up getting a ticket for DOMAIN@RUSTED.REA.LM */
304 account_name
= lp_workgroup();
306 /* always use the sAMAccountName for security = domain */
307 /* global_myname()$@REA.LM */
308 if ( lp_security() == SEC_DOMAIN
) {
309 fstr_sprintf( acct_name
, "%s$", global_myname() );
310 account_name
= acct_name
;
313 /* This looks like host/global_myname()@REA.LM */
314 account_name
= ads
->auth
.user_name
;
318 if (asprintf(&s
, "%s@%s", account_name
, ads
->auth
.realm
) == -1) {
319 return KRB5_CC_NOMEM
;
322 if (!ads
->auth
.password
) {
324 return KRB5_LIBOS_CANTREADPWD
;
327 ret
= kerberos_kinit_password_ext(s
, ads
->auth
.password
, ads
->auth
.time_offset
,
328 &ads
->auth
.tgt_expire
, NULL
, NULL
, False
, False
, ads
->auth
.renewable
,
332 DEBUG(0,("kerberos_kinit_password %s failed: %s\n",
333 s
, error_message(ret
)));
339 int ads_kdestroy(const char *cc_name
)
341 krb5_error_code code
;
342 krb5_context ctx
= NULL
;
343 krb5_ccache cc
= NULL
;
345 initialize_krb5_error_table();
346 if ((code
= krb5_init_context (&ctx
))) {
347 DEBUG(3, ("ads_kdestroy: kdb5_init_context failed: %s\n",
348 error_message(code
)));
353 if ((code
= krb5_cc_default(ctx
, &cc
))) {
354 krb5_free_context(ctx
);
358 if ((code
= krb5_cc_resolve(ctx
, cc_name
, &cc
))) {
359 DEBUG(3, ("ads_kdestroy: krb5_cc_resolve failed: %s\n",
360 error_message(code
)));
361 krb5_free_context(ctx
);
366 if ((code
= krb5_cc_destroy (ctx
, cc
))) {
367 DEBUG(3, ("ads_kdestroy: krb5_cc_destroy failed: %s\n",
368 error_message(code
)));
371 krb5_free_context (ctx
);
375 /************************************************************************
376 Routine to fetch the salting principal for a service. Active
377 Directory may use a non-obvious principal name to generate the salt
378 when it determines the key to use for encrypting tickets for a service,
379 and hopefully we detected that when we joined the domain.
380 ************************************************************************/
382 static char *kerberos_secrets_fetch_salting_principal(const char *service
, int enctype
)
387 if (asprintf(&key
, "%s/%s/enctype=%d",
388 SECRETS_SALTING_PRINCIPAL
, service
, enctype
) == -1) {
391 ret
= (char *)secrets_fetch(key
, NULL
);
396 /************************************************************************
397 Return the standard DES salt key
398 ************************************************************************/
400 char* kerberos_standard_des_salt( void )
404 fstr_sprintf( salt
, "host/%s.%s@", global_myname(), lp_realm() );
406 fstrcat( salt
, lp_realm() );
408 return SMB_STRDUP( salt
);
411 /************************************************************************
412 ************************************************************************/
414 static char* des_salt_key( void )
418 if (asprintf(&key
, "%s/DES/%s", SECRETS_SALTING_PRINCIPAL
,
426 /************************************************************************
427 ************************************************************************/
429 bool kerberos_secrets_store_des_salt( const char* salt
)
434 if ( (key
= des_salt_key()) == NULL
) {
435 DEBUG(0,("kerberos_secrets_store_des_salt: failed to generate key!\n"));
440 DEBUG(8,("kerberos_secrets_store_des_salt: deleting salt\n"));
441 secrets_delete( key
);
445 DEBUG(3,("kerberos_secrets_store_des_salt: Storing salt \"%s\"\n", salt
));
447 ret
= secrets_store( key
, salt
, strlen(salt
)+1 );
454 /************************************************************************
455 ************************************************************************/
457 char* kerberos_secrets_fetch_des_salt( void )
461 if ( (key
= des_salt_key()) == NULL
) {
462 DEBUG(0,("kerberos_secrets_fetch_des_salt: failed to generate key!\n"));
466 salt
= (char*)secrets_fetch( key
, NULL
);
473 /************************************************************************
474 Routine to get the default realm from the kerberos credentials cache.
475 Caller must free if the return value is not NULL.
476 ************************************************************************/
478 char *kerberos_get_default_realm_from_ccache( void )
481 krb5_context ctx
= NULL
;
482 krb5_ccache cc
= NULL
;
483 krb5_principal princ
= NULL
;
485 initialize_krb5_error_table();
486 if (krb5_init_context(&ctx
)) {
490 DEBUG(5,("kerberos_get_default_realm_from_ccache: "
491 "Trying to read krb5 cache: %s\n",
492 krb5_cc_default_name(ctx
)));
493 if (krb5_cc_default(ctx
, &cc
)) {
494 DEBUG(0,("kerberos_get_default_realm_from_ccache: "
495 "failed to read default cache\n"));
498 if (krb5_cc_get_principal(ctx
, cc
, &princ
)) {
499 DEBUG(0,("kerberos_get_default_realm_from_ccache: "
500 "failed to get default principal\n"));
504 #if defined(HAVE_KRB5_PRINCIPAL_GET_REALM)
505 realm
= SMB_STRDUP(krb5_principal_get_realm(ctx
, princ
));
506 #elif defined(HAVE_KRB5_PRINC_REALM)
508 krb5_data
*realm_data
= krb5_princ_realm(ctx
, princ
);
509 realm
= SMB_STRNDUP(realm_data
->data
, realm_data
->length
);
517 krb5_free_principal(ctx
, princ
);
520 krb5_cc_close(ctx
, cc
);
522 krb5_free_context(ctx
);
528 /************************************************************************
529 Routine to get the realm from a given DNS name. Returns malloc'ed memory.
530 Caller must free() if the return value is not NULL.
531 ************************************************************************/
533 char *kerberos_get_realm_from_hostname(const char *hostname
)
535 #if defined(HAVE_KRB5_GET_HOST_REALM) && defined(HAVE_KRB5_FREE_HOST_REALM)
536 #if defined(HAVE_KRB5_REALM_TYPE)
538 krb5_realm
*realm_list
= NULL
;
541 char **realm_list
= NULL
;
544 krb5_error_code kerr
;
545 krb5_context ctx
= NULL
;
547 initialize_krb5_error_table();
548 if (krb5_init_context(&ctx
)) {
552 kerr
= krb5_get_host_realm(ctx
, hostname
, &realm_list
);
554 DEBUG(3,("kerberos_get_realm_from_hostname %s: "
556 hostname
? hostname
: "(NULL)",
557 error_message(kerr
) ));
561 if (realm_list
&& realm_list
[0]) {
562 realm
= SMB_STRDUP(realm_list
[0]);
569 krb5_free_host_realm(ctx
, realm_list
);
572 krb5_free_context(ctx
);
581 /************************************************************************
582 Routine to get the salting principal for this service. This is
583 maintained for backwards compatibilty with releases prior to 3.0.24.
584 Since we store the salting principal string only at join, we may have
585 to look for the older tdb keys. Caller must free if return is not null.
586 ************************************************************************/
588 krb5_principal
kerberos_fetch_salt_princ_for_host_princ(krb5_context context
,
589 krb5_principal host_princ
,
592 char *unparsed_name
= NULL
, *salt_princ_s
= NULL
;
593 krb5_principal ret_princ
= NULL
;
595 /* lookup new key first */
597 if ( (salt_princ_s
= kerberos_secrets_fetch_des_salt()) == NULL
) {
599 /* look under the old key. If this fails, just use the standard key */
601 if (smb_krb5_unparse_name(talloc_tos(), context
, host_princ
, &unparsed_name
) != 0) {
602 return (krb5_principal
)NULL
;
604 if ((salt_princ_s
= kerberos_secrets_fetch_salting_principal(unparsed_name
, enctype
)) == NULL
) {
605 /* fall back to host/machine.realm@REALM */
606 salt_princ_s
= kerberos_standard_des_salt();
610 if (smb_krb5_parse_name(context
, salt_princ_s
, &ret_princ
) != 0) {
614 TALLOC_FREE(unparsed_name
);
615 SAFE_FREE(salt_princ_s
);
620 /************************************************************************
621 Routine to set the salting principal for this service. Active
622 Directory may use a non-obvious principal name to generate the salt
623 when it determines the key to use for encrypting tickets for a service,
624 and hopefully we detected that when we joined the domain.
625 Setting principal to NULL deletes this entry.
626 ************************************************************************/
628 bool kerberos_secrets_store_salting_principal(const char *service
,
630 const char *principal
)
634 krb5_context context
= NULL
;
635 krb5_principal princ
= NULL
;
636 char *princ_s
= NULL
;
637 char *unparsed_name
= NULL
;
638 krb5_error_code code
;
640 if (((code
= krb5_init_context(&context
)) != 0) || (context
== NULL
)) {
641 DEBUG(5, ("kerberos_secrets_store_salting_pricipal: kdb5_init_context failed: %s\n",
642 error_message(code
)));
645 if (strchr_m(service
, '@')) {
646 if (asprintf(&princ_s
, "%s", service
) == -1) {
650 if (asprintf(&princ_s
, "%s@%s", service
, lp_realm()) == -1) {
655 if (smb_krb5_parse_name(context
, princ_s
, &princ
) != 0) {
659 if (smb_krb5_unparse_name(talloc_tos(), context
, princ
, &unparsed_name
) != 0) {
663 if (asprintf(&key
, "%s/%s/enctype=%d",
664 SECRETS_SALTING_PRINCIPAL
, unparsed_name
, enctype
)
669 if ((principal
!= NULL
) && (strlen(principal
) > 0)) {
670 ret
= secrets_store(key
, principal
, strlen(principal
) + 1);
672 ret
= secrets_delete(key
);
679 TALLOC_FREE(unparsed_name
);
682 krb5_free_principal(context
, princ
);
686 krb5_free_context(context
);
693 /************************************************************************
694 ************************************************************************/
696 int kerberos_kinit_password(const char *principal
,
697 const char *password
,
699 const char *cache_name
)
701 return kerberos_kinit_password_ext(principal
,
713 /************************************************************************
714 ************************************************************************/
716 static char *print_kdc_line(char *mem_ctx
,
717 const char *prev_line
,
718 const struct sockaddr_storage
*pss
,
719 const char *kdc_name
)
721 char *kdc_str
= NULL
;
723 if (pss
->ss_family
== AF_INET
) {
724 kdc_str
= talloc_asprintf(mem_ctx
, "%s\tkdc = %s\n",
726 print_canonical_sockaddr(mem_ctx
, pss
));
728 char addr
[INET6_ADDRSTRLEN
];
729 uint16_t port
= get_sockaddr_port(pss
);
731 DEBUG(10,("print_kdc_line: IPv6 case for kdc_name: %s, port: %d\n",
734 if (port
!= 0 && port
!= DEFAULT_KRB5_PORT
) {
735 /* Currently for IPv6 we can't specify a non-default
736 krb5 port with an address, as this requires a ':'.
737 Resolve to a name. */
738 char hostname
[MAX_DNS_NAME_LENGTH
];
739 int ret
= sys_getnameinfo((const struct sockaddr
*)pss
,
741 hostname
, sizeof(hostname
),
745 DEBUG(0,("print_kdc_line: can't resolve name "
746 "for kdc with non-default port %s. "
748 print_canonical_sockaddr(mem_ctx
, pss
),
752 /* Success, use host:port */
753 kdc_str
= talloc_asprintf(mem_ctx
,
760 /* no krb5 lib currently supports "kdc = ipv6 address"
761 * at all, so just fill in just the kdc_name if we have
762 * it and let the krb5 lib figure out the appropriate
763 * ipv6 address - gd */
766 kdc_str
= talloc_asprintf(mem_ctx
, "%s\tkdc = %s\n",
767 prev_line
, kdc_name
);
769 kdc_str
= talloc_asprintf(mem_ctx
, "%s\tkdc = %s\n",
780 /************************************************************************
781 Create a string list of available kdc's, possibly searching by sitename.
784 If "sitename" is given, the DC's in that site are listed first.
786 ************************************************************************/
788 static char *get_kdc_ip_string(char *mem_ctx
,
790 const char *sitename
,
791 struct sockaddr_storage
*pss
,
792 const char *kdc_name
)
795 struct ip_service
*ip_srv_site
= NULL
;
796 struct ip_service
*ip_srv_nonsite
= NULL
;
799 char *kdc_str
= print_kdc_line(mem_ctx
, "", pss
, kdc_name
);
801 if (kdc_str
== NULL
) {
806 * First get the KDC's only in this site, the rest will be
812 get_kdc_list(realm
, sitename
, &ip_srv_site
, &count_site
);
814 for (i
= 0; i
< count_site
; i
++) {
815 if (sockaddr_equal((struct sockaddr
*)&ip_srv_site
[i
].ss
,
816 (struct sockaddr
*)pss
)) {
819 /* Append to the string - inefficient
820 * but not done often. */
821 kdc_str
= print_kdc_line(mem_ctx
,
826 SAFE_FREE(ip_srv_site
);
834 get_kdc_list(realm
, NULL
, &ip_srv_nonsite
, &count_nonsite
);
836 for (i
= 0; i
< count_nonsite
; i
++) {
839 if (sockaddr_equal((struct sockaddr
*)&ip_srv_nonsite
[i
].ss
, (struct sockaddr
*)pss
)) {
843 /* Ensure this isn't an IP already seen (YUK! this is n*n....) */
844 for (j
= 0; j
< count_site
; j
++) {
845 if (sockaddr_equal((struct sockaddr
*)&ip_srv_nonsite
[i
].ss
,
846 (struct sockaddr
*)&ip_srv_site
[j
].ss
)) {
849 /* As the lists are sorted we can break early if nonsite > site. */
850 if (ip_service_compare(&ip_srv_nonsite
[i
], &ip_srv_site
[j
]) > 0) {
858 /* Append to the string - inefficient but not done often. */
859 kdc_str
= print_kdc_line(mem_ctx
,
861 &ip_srv_nonsite
[i
].ss
,
864 SAFE_FREE(ip_srv_site
);
865 SAFE_FREE(ip_srv_nonsite
);
871 SAFE_FREE(ip_srv_site
);
872 SAFE_FREE(ip_srv_nonsite
);
874 DEBUG(10,("get_kdc_ip_string: Returning %s\n",
880 /************************************************************************
881 Create a specific krb5.conf file in the private directory pointing
882 at a specific kdc for a realm. Keyed off domain name. Sets
883 KRB5_CONFIG environment variable to point to this file. Must be
884 run as root or will fail (which is a good thing :-).
885 ************************************************************************/
887 bool create_local_private_krb5_conf_for_domain(const char *realm
,
889 const char *sitename
,
890 struct sockaddr_storage
*pss
,
891 const char *kdc_name
)
894 char *tmpname
= NULL
;
896 char *file_contents
= NULL
;
897 char *kdc_ip_string
= NULL
;
901 char *realm_upper
= NULL
;
904 if (!lp_create_krb5_conf()) {
908 dname
= lock_path("smb_krb5");
912 if ((mkdir(dname
, 0755)==-1) && (errno
!= EEXIST
)) {
913 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
914 "failed to create directory %s. Error was %s\n",
915 dname
, strerror(errno
) ));
919 tmpname
= lock_path("smb_tmp_krb5.XXXXXX");
924 fname
= talloc_asprintf(dname
, "%s/krb5.conf.%s", dname
, domain
);
929 DEBUG(10,("create_local_private_krb5_conf_for_domain: fname = %s, realm = %s, domain = %s\n",
930 fname
, realm
, domain
));
932 realm_upper
= talloc_strdup(fname
, realm
);
933 strupper_m(realm_upper
);
935 kdc_ip_string
= get_kdc_ip_string(dname
, realm
, sitename
, pss
, kdc_name
);
936 if (!kdc_ip_string
) {
940 file_contents
= talloc_asprintf(fname
,
941 "[libdefaults]\n\tdefault_realm = %s\n"
942 "\tdefault_tgs_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
943 "\tdefault_tkt_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
944 "\tpreferred_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n\n"
945 "[realms]\n\t%s = {\n"
947 realm_upper
, realm_upper
, kdc_ip_string
);
949 if (!file_contents
) {
953 flen
= strlen(file_contents
);
955 fd
= mkstemp(tmpname
);
957 DEBUG(0,("create_local_private_krb5_conf_for_domain: smb_mkstemp failed,"
958 " for file %s. Errno %s\n",
959 tmpname
, strerror(errno
) ));
963 if (fchmod(fd
, 0644)==-1) {
964 DEBUG(0,("create_local_private_krb5_conf_for_domain: fchmod failed for %s."
966 tmpname
, strerror(errno
) ));
972 ret
= write(fd
, file_contents
, flen
);
974 DEBUG(0,("create_local_private_krb5_conf_for_domain: write failed,"
975 " returned %d (should be %u). Errno %s\n",
976 (int)ret
, (unsigned int)flen
, strerror(errno
) ));
982 DEBUG(0,("create_local_private_krb5_conf_for_domain: close failed."
983 " Errno %s\n", strerror(errno
) ));
988 if (rename(tmpname
, fname
) == -1) {
989 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
990 "of %s to %s failed. Errno %s\n",
991 tmpname
, fname
, strerror(errno
) ));
996 DEBUG(5,("create_local_private_krb5_conf_for_domain: wrote "
997 "file %s with realm %s KDC list = %s\n",
998 fname
, realm_upper
, kdc_ip_string
));
1000 /* Set the environment variable to this file. */
1001 setenv("KRB5_CONFIG", fname
, 1);
1005 #if defined(OVERWRITE_SYSTEM_KRB5_CONF)
1007 #define SYSTEM_KRB5_CONF_PATH "/etc/krb5.conf"
1008 /* Insanity, sheer insanity..... */
1010 if (strequal(realm
, lp_realm())) {
1011 char linkpath
[PATH_MAX
+1];
1014 lret
= readlink(SYSTEM_KRB5_CONF_PATH
, linkpath
, sizeof(linkpath
)-1);
1016 linkpath
[lret
] = '\0';
1019 if (lret
!= -1 || strcmp(linkpath
, fname
) == 0) {
1020 /* Symlink already exists. */
1024 /* Try and replace with a symlink. */
1025 if (symlink(fname
, SYSTEM_KRB5_CONF_PATH
) == -1) {
1026 const char *newpath
= SYSTEM_KRB5_CONF_PATH
## ".saved";
1027 if (errno
!= EEXIST
) {
1028 DEBUG(0,("create_local_private_krb5_conf_for_domain: symlink "
1029 "of %s to %s failed. Errno %s\n",
1030 fname
, SYSTEM_KRB5_CONF_PATH
, strerror(errno
) ));
1031 goto done
; /* Not a fatal error. */
1034 /* Yes, this is a race conditon... too bad. */
1035 if (rename(SYSTEM_KRB5_CONF_PATH
, newpath
) == -1) {
1036 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
1037 "of %s to %s failed. Errno %s\n",
1038 SYSTEM_KRB5_CONF_PATH
, newpath
,
1040 goto done
; /* Not a fatal error. */
1043 if (symlink(fname
, SYSTEM_KRB5_CONF_PATH
) == -1) {
1044 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
1045 "forced symlink of %s to /etc/krb5.conf failed. Errno %s\n",
1046 fname
, strerror(errno
) ));
1047 goto done
; /* Not a fatal error. */
1054 TALLOC_FREE(tmpname
);