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"
32 #include "lib/util/asn1.h"
36 #define LIBADS_CCACHE_NAME "MEMORY:libads"
39 we use a prompter to avoid a crash bug in the kerberos libs when
40 dealing with empty passwords
41 this prompter is just a string copy ...
43 static krb5_error_code
44 kerb_prompter(krb5_context ctx, void *data,
48 krb5_prompt prompts[])
50 if (num_prompts == 0) return 0;
51 if (num_prompts == 2) {
53 * only heimdal has a prompt type and we need to deal with it here to
56 * removing the prompter completely is not an option as at least these
57 * versions would crash: heimdal-1.0.2 and heimdal-1.1. Later heimdal
58 * version have looping detection and return with a proper error code.
61 #if HAVE_KRB5_PROMPT_TYPE /* Heimdal */
62 if (prompts[0].type == KRB5_PROMPT_TYPE_NEW_PASSWORD &&
63 prompts[1].type == KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN) {
65 * We don't want to change passwords here. We're
66 * called from heimal when the KDC returns
67 * KRB5KDC_ERR_KEY_EXPIRED, but at this point we don't
68 * have the chance to ask the user for a new
69 * password. If we return 0 (i.e. success), we will be
70 * spinning in the endless for-loop in
71 * change_password() in
72 * source4/heimdal/lib/krb5/init_creds_pw.c:526ff
74 return KRB5KDC_ERR_KEY_EXPIRED;
76 #elif defined(HAVE_KRB5_GET_PROMPT_TYPES) /* MIT */
77 krb5_prompt_type *prompt_types = NULL;
79 prompt_types = krb5_get_prompt_types(ctx);
80 if (prompt_types != NULL) {
81 if (prompt_types[0] == KRB5_PROMPT_TYPE_NEW_PASSWORD &&
82 prompt_types[1] == KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN) {
83 return KRB5KDC_ERR_KEY_EXP;
89 memset(prompts[0].reply->data, '\0', prompts[0].reply->length);
90 if (prompts[0].reply->length > 0) {
92 strncpy((char *)prompts[0].reply->data, (const char *)data,
93 prompts[0].reply->length-1);
94 prompts[0].reply->length = strlen((const char *)prompts[0].reply->data);
96 prompts[0].reply->length = 0;
102 static bool unwrap_edata_ntstatus(TALLOC_CTX *mem_ctx,
104 DATA_BLOB *edata_out)
106 DATA_BLOB edata_contents;
110 if (!edata->length) {
114 data = asn1_init(mem_ctx);
119 if (!asn1_load(data, *edata)) goto err;
120 if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) goto err;
121 if (!asn1_start_tag(data, ASN1_CONTEXT(1))) goto err;
122 if (!asn1_read_Integer(data, &edata_type)) goto err;
124 if (edata_type != KRB5_PADATA_PW_SALT) {
125 DEBUG(0,("edata is not of required type %d but of type %d\n",
126 KRB5_PADATA_PW_SALT, edata_type));
130 if (!asn1_start_tag(data, ASN1_CONTEXT(2))) goto err;
131 if (!asn1_read_OctetString(data, talloc_tos(), &edata_contents)) goto err;
132 if (!asn1_end_tag(data)) goto err;
133 if (!asn1_end_tag(data)) goto err;
134 if (!asn1_end_tag(data)) goto err;
137 *edata_out = data_blob_talloc(mem_ctx, edata_contents.data, edata_contents.length);
139 data_blob_free(&edata_contents);
149 static bool smb_krb5_get_ntstatus_from_krb5_error(krb5_error *error,
153 DATA_BLOB unwrapped_edata;
155 struct KRB5_EDATA_NTSTATUS parsed_edata;
156 enum ndr_err_code ndr_err;
158 #ifdef HAVE_E_DATA_POINTER_IN_KRB5_ERROR
159 edata = data_blob(error->e_data->data, error->e_data->length);
161 edata = data_blob(error->e_data.data, error->e_data.length);
162 #endif /* HAVE_E_DATA_POINTER_IN_KRB5_ERROR */
165 dump_data(10, edata.data, edata.length);
166 #endif /* DEVELOPER */
168 mem_ctx = talloc_init("smb_krb5_get_ntstatus_from_krb5_error");
169 if (mem_ctx == NULL) {
170 data_blob_free(&edata);
174 if (!unwrap_edata_ntstatus(mem_ctx, &edata, &unwrapped_edata)) {
175 data_blob_free(&edata);
176 TALLOC_FREE(mem_ctx);
180 data_blob_free(&edata);
182 ndr_err = ndr_pull_struct_blob_all(&unwrapped_edata, mem_ctx,
183 &parsed_edata, (ndr_pull_flags_fn_t)ndr_pull_KRB5_EDATA_NTSTATUS);
184 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
185 data_blob_free(&unwrapped_edata);
186 TALLOC_FREE(mem_ctx);
190 data_blob_free(&unwrapped_edata);
193 *nt_status = parsed_edata.ntstatus;
196 TALLOC_FREE(mem_ctx);
201 static bool smb_krb5_get_ntstatus_from_krb5_error_init_creds_opt(krb5_context ctx,
202 krb5_get_init_creds_opt *opt,
206 krb5_error *error = NULL;
208 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_GET_ERROR
209 ret = krb5_get_init_creds_opt_get_error(ctx, opt, &error);
211 DEBUG(1,("krb5_get_init_creds_opt_get_error gave: %s\n",
212 error_message(ret)));
215 #endif /* HAVE_KRB5_GET_INIT_CREDS_OPT_GET_ERROR */
218 DEBUG(1,("no krb5_error\n"));
222 #ifdef HAVE_E_DATA_POINTER_IN_KRB5_ERROR
223 if (!error->e_data) {
225 if (error->e_data.data == NULL) {
226 #endif /* HAVE_E_DATA_POINTER_IN_KRB5_ERROR */
227 DEBUG(1,("no edata in krb5_error\n"));
228 krb5_free_error(ctx, error);
232 ret = smb_krb5_get_ntstatus_from_krb5_error(error, nt_status);
234 krb5_free_error(ctx, error);
240 simulate a kinit, putting the tgt in the given cache location. If cache_name == NULL
241 place in default cache location.
244 int kerberos_kinit_password_ext(const char *principal,
245 const char *password,
248 time_t *renew_till_time,
249 const char *cache_name,
251 bool add_netbios_addr,
252 time_t renewable_time,
255 krb5_context ctx = NULL;
256 krb5_error_code code = 0;
257 krb5_ccache cc = NULL;
258 krb5_principal me = NULL;
260 krb5_get_init_creds_opt *opt = NULL;
261 smb_krb5_addresses *addr = NULL;
263 ZERO_STRUCT(my_creds);
265 initialize_krb5_error_table();
266 if ((code = krb5_init_context(&ctx)))
269 if (time_offset != 0) {
270 krb5_set_real_time(ctx, time(NULL) + time_offset, 0);
273 DEBUG(10,("kerberos_kinit_password: as %s using [%s] as ccache and config [%s]\n",
275 cache_name ? cache_name: krb5_cc_default_name(ctx),
276 getenv("KRB5_CONFIG")));
278 if ((code = krb5_cc_resolve(ctx, cache_name ? cache_name : krb5_cc_default_name(ctx), &cc))) {
282 if ((code = smb_krb5_parse_name(ctx, principal, &me))) {
286 if ((code = krb5_get_init_creds_opt_alloc(ctx, &opt))) {
290 krb5_get_init_creds_opt_set_renew_life(opt, renewable_time);
291 krb5_get_init_creds_opt_set_forwardable(opt, True);
294 krb5_get_init_creds_opt_set_tkt_life(opt, 60);
297 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PAC_REQUEST
299 if ((code = krb5_get_init_creds_opt_set_pac_request(ctx, opt, (krb5_boolean)request_pac))) {
304 if (add_netbios_addr) {
305 if ((code = smb_krb5_gen_netbios_krb5_address(&addr,
306 lp_netbios_name()))) {
309 krb5_get_init_creds_opt_set_address_list(opt, addr->addrs);
312 if ((code = krb5_get_init_creds_password(ctx, &my_creds, me, discard_const_p(char,password),
313 kerb_prompter, discard_const_p(char, password),
318 if ((code = krb5_cc_initialize(ctx, cc, me))) {
322 if ((code = krb5_cc_store_cred(ctx, cc, &my_creds))) {
327 *expire_time = (time_t) my_creds.times.endtime;
330 if (renew_till_time) {
331 *renew_till_time = (time_t) my_creds.times.renew_till;
340 *ntstatus = NT_STATUS_OK;
344 /* try to get ntstatus code out of krb5_error when we have it
345 * inside the krb5_get_init_creds_opt - gd */
347 if (opt && smb_krb5_get_ntstatus_from_krb5_error_init_creds_opt(ctx, opt, &status)) {
352 /* fall back to self-made-mapping */
353 *ntstatus = krb5_to_nt_status(code);
357 krb5_free_cred_contents(ctx, &my_creds);
359 krb5_free_principal(ctx, me);
362 smb_krb5_free_addresses(ctx, addr);
365 krb5_get_init_creds_opt_free(ctx, opt);
368 krb5_cc_close(ctx, cc);
371 krb5_free_context(ctx);
376 int ads_kdestroy(const char *cc_name)
378 krb5_error_code code;
379 krb5_context ctx = NULL;
380 krb5_ccache cc = NULL;
382 initialize_krb5_error_table();
383 if ((code = krb5_init_context (&ctx))) {
384 DEBUG(3, ("ads_kdestroy: kdb5_init_context failed: %s\n",
385 error_message(code)));
390 if ((code = krb5_cc_default(ctx, &cc))) {
391 krb5_free_context(ctx);
395 if ((code = krb5_cc_resolve(ctx, cc_name, &cc))) {
396 DEBUG(3, ("ads_kdestroy: krb5_cc_resolve failed: %s\n",
397 error_message(code)));
398 krb5_free_context(ctx);
403 if ((code = krb5_cc_destroy (ctx, cc))) {
404 DEBUG(3, ("ads_kdestroy: krb5_cc_destroy failed: %s\n",
405 error_message(code)));
408 krb5_free_context (ctx);
412 /************************************************************************
413 Routine to fetch the salting principal for a service. Active
414 Directory may use a non-obvious principal name to generate the salt
415 when it determines the key to use for encrypting tickets for a service,
416 and hopefully we detected that when we joined the domain.
417 ************************************************************************/
419 static char *kerberos_secrets_fetch_salting_principal(const char *service, int enctype)
424 if (asprintf(&key, "%s/%s/enctype=%d",
425 SECRETS_SALTING_PRINCIPAL, service, enctype) == -1) {
428 ret = (char *)secrets_fetch(key, NULL);
433 /************************************************************************
434 Return the standard DES salt key
435 ************************************************************************/
437 char* kerberos_standard_des_salt( void )
441 fstr_sprintf( salt, "host/%s.%s@", lp_netbios_name(), lp_realm() );
442 (void)strlower_m( salt );
443 fstrcat( salt, lp_realm() );
445 return SMB_STRDUP( salt );
448 /************************************************************************
449 ************************************************************************/
451 static char* des_salt_key( void )
455 if (asprintf(&key, "%s/DES/%s", SECRETS_SALTING_PRINCIPAL,
463 /************************************************************************
464 ************************************************************************/
466 bool kerberos_secrets_store_des_salt( const char* salt )
471 if ( (key = des_salt_key()) == NULL ) {
472 DEBUG(0,("kerberos_secrets_store_des_salt: failed to generate key!\n"));
477 DEBUG(8,("kerberos_secrets_store_des_salt: deleting salt\n"));
478 secrets_delete( key );
482 DEBUG(3,("kerberos_secrets_store_des_salt: Storing salt \"%s\"\n", salt));
484 ret = secrets_store( key, salt, strlen(salt)+1 );
491 /************************************************************************
492 ************************************************************************/
495 char* kerberos_secrets_fetch_des_salt( void )
499 if ( (key = des_salt_key()) == NULL ) {
500 DEBUG(0,("kerberos_secrets_fetch_des_salt: failed to generate key!\n"));
504 salt = (char*)secrets_fetch( key, NULL );
511 /************************************************************************
512 Routine to get the salting principal for this service. This is
513 maintained for backwards compatibilty with releases prior to 3.0.24.
514 Since we store the salting principal string only at join, we may have
515 to look for the older tdb keys. Caller must free if return is not null.
516 ************************************************************************/
518 char *kerberos_fetch_salt_princ_for_host_princ(krb5_context context,
519 const char *host_princ_s,
523 /* lookup new key first */
525 salt_princ_s = kerberos_secrets_fetch_des_salt();
526 if (salt_princ_s == NULL) {
528 /* look under the old key. If this fails, just use the standard key */
529 salt_princ_s = kerberos_secrets_fetch_salting_principal(host_princ_s,
531 if (salt_princ_s == NULL) {
532 /* fall back to host/machine.realm@REALM */
533 salt_princ_s = kerberos_standard_des_salt();
540 int create_kerberos_key_from_string(krb5_context context,
541 krb5_principal host_princ,
542 krb5_principal salt_princ,
545 krb5_enctype enctype,
550 * Check if we've determined that the KDC is salting keys for this
551 * principal/enctype in a non-obvious way. If it is, try to match
555 KRB5_KEY_DATA(key) = (KRB5_KEY_DATA_CAST *)SMB_MALLOC(password->length);
556 if (!KRB5_KEY_DATA(key)) {
559 memcpy(KRB5_KEY_DATA(key), password->data, password->length);
560 KRB5_KEY_LENGTH(key) = password->length;
561 KRB5_KEY_TYPE(key) = enctype;
564 ret = smb_krb5_create_key_from_string(context,
565 salt_princ ? salt_princ : host_princ,
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 /************************************************************************
669 Create a string list of available kdc's, possibly searching by sitename.
672 If "sitename" is given, the DC's in that site are listed first.
674 ************************************************************************/
676 static void add_sockaddr_unique(struct sockaddr_storage *addrs, int *num_addrs,
677 const struct sockaddr_storage *addr)
681 for (i=0; i<*num_addrs; i++) {
682 if (sockaddr_equal((const struct sockaddr *)&addrs[i],
683 (const struct sockaddr *)addr)) {
691 /* print_canonical_sockaddr prints an ipv6 addr in the form of
692 * [ipv6.addr]. This string, when put in a generated krb5.conf file is not
693 * always properly dealt with by some older krb5 libraries. Adding the hard-coded
694 * portnumber workarounds the issue. - gd */
696 static char *print_canonical_sockaddr_with_port(TALLOC_CTX *mem_ctx,
697 const struct sockaddr_storage *pss)
701 str = print_canonical_sockaddr(mem_ctx, pss);
706 if (pss->ss_family != AF_INET6) {
710 #if defined(HAVE_IPV6)
711 str = talloc_asprintf_append(str, ":88");
716 static char *get_kdc_ip_string(char *mem_ctx,
718 const char *sitename,
719 const struct sockaddr_storage *pss)
721 TALLOC_CTX *frame = talloc_stackframe();
723 struct ip_service *ip_srv_site = NULL;
724 struct ip_service *ip_srv_nonsite = NULL;
728 struct sockaddr_storage *dc_addrs;
729 struct tsocket_address **dc_addrs2 = NULL;
730 const struct tsocket_address * const *dc_addrs3 = NULL;
732 struct netlogon_samlogon_response **responses = NULL;
734 char *kdc_str = talloc_asprintf(mem_ctx, "%s\t\tkdc = %s\n", "",
735 print_canonical_sockaddr_with_port(mem_ctx, pss));
737 if (kdc_str == NULL) {
743 * First get the KDC's only in this site, the rest will be
748 get_kdc_list(realm, sitename, &ip_srv_site, &count_site);
749 DEBUG(10, ("got %d addresses from site %s search\n", count_site,
755 get_kdc_list(realm, NULL, &ip_srv_nonsite, &count_nonsite);
756 DEBUG(10, ("got %d addresses from site-less search\n", count_nonsite));
758 dc_addrs = talloc_array(talloc_tos(), struct sockaddr_storage,
759 count_site + count_nonsite);
760 if (dc_addrs == NULL) {
766 for (i = 0; i < count_site; i++) {
768 (const struct sockaddr *)pss,
769 (const struct sockaddr *)&ip_srv_site[i].ss)) {
770 add_sockaddr_unique(dc_addrs, &num_dcs,
775 for (i = 0; i < count_nonsite; i++) {
777 (const struct sockaddr *)pss,
778 (const struct sockaddr *)&ip_srv_nonsite[i].ss)) {
779 add_sockaddr_unique(dc_addrs, &num_dcs,
780 &ip_srv_nonsite[i].ss);
784 dc_addrs2 = talloc_zero_array(talloc_tos(),
785 struct tsocket_address *,
788 DEBUG(10, ("%d additional KDCs to test\n", num_dcs));
792 if (dc_addrs2 == NULL) {
796 for (i=0; i<num_dcs; i++) {
797 char addr[INET6_ADDRSTRLEN];
800 print_sockaddr(addr, sizeof(addr), &dc_addrs[i]);
802 ret = tsocket_address_inet_from_strings(dc_addrs2, "ip",
806 status = map_nt_error_from_unix(errno);
807 DEBUG(2,("Failed to create tsocket_address for %s - %s\n",
808 addr, nt_errstr(status)));
813 dc_addrs3 = (const struct tsocket_address * const *)dc_addrs2;
815 status = cldap_multi_netlogon(talloc_tos(),
817 realm, lp_netbios_name(),
818 NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX,
819 MIN(num_dcs, 3), timeval_current_ofs(3, 0), &responses);
820 TALLOC_FREE(dc_addrs2);
823 if (!NT_STATUS_IS_OK(status)) {
824 DEBUG(10,("get_kdc_ip_string: cldap_multi_netlogon failed: "
825 "%s\n", nt_errstr(status)));
829 for (i=0; i<num_dcs; i++) {
832 if (responses[i] == NULL) {
836 /* Append to the string - inefficient but not done often. */
837 new_kdc_str = talloc_asprintf(mem_ctx, "%s\t\tkdc = %s\n",
839 print_canonical_sockaddr_with_port(mem_ctx, &dc_addrs[i]));
840 if (new_kdc_str == NULL) {
843 TALLOC_FREE(kdc_str);
844 kdc_str = new_kdc_str;
848 DEBUG(10, ("get_kdc_ip_string: Returning %s\n", kdc_str));
851 SAFE_FREE(ip_srv_site);
852 SAFE_FREE(ip_srv_nonsite);
857 /************************************************************************
858 Create a specific krb5.conf file in the private directory pointing
859 at a specific kdc for a realm. Keyed off domain name. Sets
860 KRB5_CONFIG environment variable to point to this file. Must be
861 run as root or will fail (which is a good thing :-).
862 ************************************************************************/
864 #if !defined(SAMBA4_USES_HEIMDAL) /* MIT version */
865 static char *get_enctypes(TALLOC_CTX *mem_ctx)
867 char *aes_enctypes = NULL;
868 const char *legacy_enctypes = "";
869 char *enctypes = NULL;
871 aes_enctypes = talloc_strdup(mem_ctx, "");
872 if (aes_enctypes == NULL) {
876 if (lp_kerberos_encryption_types() == KERBEROS_ETYPES_ALL ||
877 lp_kerberos_encryption_types() == KERBEROS_ETYPES_STRONG) {
878 #ifdef HAVE_ENCTYPE_AES256_CTS_HMAC_SHA1_96
879 aes_enctypes = talloc_asprintf_append(
880 aes_enctypes, "%s", "aes256-cts-hmac-sha1-96 ");
881 if (aes_enctypes == NULL) {
885 #ifdef HAVE_ENCTYPE_AES128_CTS_HMAC_SHA1_96
886 aes_enctypes = talloc_asprintf_append(
887 aes_enctypes, "%s", "aes128-cts-hmac-sha1-96");
888 if (aes_enctypes == NULL) {
894 if (lp_kerberos_encryption_types() == KERBEROS_ETYPES_ALL ||
895 lp_kerberos_encryption_types() == KERBEROS_ETYPES_LEGACY) {
896 legacy_enctypes = "RC4-HMAC DES-CBC-CRC DES-CBC-MD5";
900 talloc_asprintf(mem_ctx, "\tdefault_tgs_enctypes = %s %s\n"
901 "\tdefault_tkt_enctypes = %s %s\n"
902 "\tpreferred_enctypes = %s %s\n",
903 aes_enctypes, legacy_enctypes, aes_enctypes,
904 legacy_enctypes, aes_enctypes, legacy_enctypes);
906 TALLOC_FREE(aes_enctypes);
909 #else /* Heimdal version */
910 static char *get_enctypes(TALLOC_CTX *mem_ctx)
912 const char *aes_enctypes = "";
913 const char *legacy_enctypes = "";
914 char *enctypes = NULL;
916 if (lp_kerberos_encryption_types() == KERBEROS_ETYPES_ALL ||
917 lp_kerberos_encryption_types() == KERBEROS_ETYPES_STRONG) {
919 "aes256-cts-hmac-sha1-96 aes128-cts-hmac-sha1-96";
922 if (lp_kerberos_encryption_types() == KERBEROS_ETYPES_ALL ||
923 lp_kerberos_encryption_types() == KERBEROS_ETYPES_LEGACY) {
924 legacy_enctypes = "arcfour-hmac-md5 des-cbc-crc des-cbc-md5";
927 enctypes = talloc_asprintf(mem_ctx, "\tdefault_etypes = %s %s\n",
928 aes_enctypes, legacy_enctypes);
934 bool create_local_private_krb5_conf_for_domain(const char *realm,
936 const char *sitename,
937 const struct sockaddr_storage *pss)
940 char *tmpname = NULL;
942 char *file_contents = NULL;
943 char *kdc_ip_string = NULL;
947 char *realm_upper = NULL;
949 char *enctypes = NULL;
952 if (!lp_create_krb5_conf()) {
957 DEBUG(0, ("No realm has been specified! Do you really want to "
958 "join an Active Directory server?\n"));
962 if (domain == NULL || pss == NULL) {
966 dname = lock_path("smb_krb5");
970 if ((mkdir(dname, 0755)==-1) && (errno != EEXIST)) {
971 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
972 "failed to create directory %s. Error was %s\n",
973 dname, strerror(errno) ));
977 tmpname = lock_path("smb_tmp_krb5.XXXXXX");
982 fname = talloc_asprintf(dname, "%s/krb5.conf.%s", dname, domain);
987 DEBUG(10,("create_local_private_krb5_conf_for_domain: fname = %s, realm = %s, domain = %s\n",
988 fname, realm, domain ));
990 realm_upper = talloc_strdup(fname, realm);
991 if (!strupper_m(realm_upper)) {
995 kdc_ip_string = get_kdc_ip_string(dname, realm, sitename, pss);
996 if (!kdc_ip_string) {
1000 enctypes = get_enctypes(fname);
1001 if (enctypes == NULL) {
1006 talloc_asprintf(fname, "[libdefaults]\n\tdefault_realm = %s\n"
1008 "\tdns_lookup_realm = false\n\n"
1009 "[realms]\n\t%s = {\n"
1011 realm_upper, enctypes, realm_upper, kdc_ip_string);
1013 if (!file_contents) {
1017 flen = strlen(file_contents);
1019 mask = umask(S_IRWXO | S_IRWXG);
1020 fd = mkstemp(tmpname);
1023 DEBUG(0,("create_local_private_krb5_conf_for_domain: smb_mkstemp failed,"
1024 " for file %s. Errno %s\n",
1025 tmpname, strerror(errno) ));
1029 if (fchmod(fd, 0644)==-1) {
1030 DEBUG(0,("create_local_private_krb5_conf_for_domain: fchmod failed for %s."
1032 tmpname, strerror(errno) ));
1038 ret = write(fd, file_contents, flen);
1040 DEBUG(0,("create_local_private_krb5_conf_for_domain: write failed,"
1041 " returned %d (should be %u). Errno %s\n",
1042 (int)ret, (unsigned int)flen, strerror(errno) ));
1047 if (close(fd)==-1) {
1048 DEBUG(0,("create_local_private_krb5_conf_for_domain: close failed."
1049 " Errno %s\n", strerror(errno) ));
1054 if (rename(tmpname, fname) == -1) {
1055 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
1056 "of %s to %s failed. Errno %s\n",
1057 tmpname, fname, strerror(errno) ));
1062 DEBUG(5,("create_local_private_krb5_conf_for_domain: wrote "
1063 "file %s with realm %s KDC list = %s\n",
1064 fname, realm_upper, kdc_ip_string));
1066 /* Set the environment variable to this file. */
1067 setenv("KRB5_CONFIG", fname, 1);
1071 #if defined(OVERWRITE_SYSTEM_KRB5_CONF)
1073 #define SYSTEM_KRB5_CONF_PATH "/etc/krb5.conf"
1074 /* Insanity, sheer insanity..... */
1076 if (strequal(realm, lp_realm())) {
1077 SMB_STRUCT_STAT sbuf;
1079 if (sys_lstat(SYSTEM_KRB5_CONF_PATH, &sbuf, false) == 0) {
1080 if (S_ISLNK(sbuf.st_ex_mode) && sbuf.st_ex_size) {
1082 size_t alloc_size = sbuf.st_ex_size + 1;
1083 char *linkpath = talloc_array(talloc_tos(), char,
1088 lret = readlink(SYSTEM_KRB5_CONF_PATH, linkpath,
1091 TALLOC_FREE(linkpath);
1094 linkpath[lret] = '\0';
1096 if (strcmp(linkpath, fname) == 0) {
1097 /* Symlink already exists. */
1098 TALLOC_FREE(linkpath);
1101 TALLOC_FREE(linkpath);
1105 /* Try and replace with a symlink. */
1106 if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
1107 const char *newpath = SYSTEM_KRB5_CONF_PATH ".saved";
1108 if (errno != EEXIST) {
1109 DEBUG(0,("create_local_private_krb5_conf_for_domain: symlink "
1110 "of %s to %s failed. Errno %s\n",
1111 fname, SYSTEM_KRB5_CONF_PATH, strerror(errno) ));
1112 goto done; /* Not a fatal error. */
1115 /* Yes, this is a race conditon... too bad. */
1116 if (rename(SYSTEM_KRB5_CONF_PATH, newpath) == -1) {
1117 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
1118 "of %s to %s failed. Errno %s\n",
1119 SYSTEM_KRB5_CONF_PATH, newpath,
1121 goto done; /* Not a fatal error. */
1124 if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
1125 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
1126 "forced symlink of %s to /etc/krb5.conf failed. Errno %s\n",
1127 fname, strerror(errno) ));
1128 goto done; /* Not a fatal error. */
1135 TALLOC_FREE(tmpname);