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_init_creds(krb5_context ctx,
202 krb5_principal client,
203 krb5_get_init_creds_opt *opt,
206 krb5_init_creds_context icc;
207 krb5_error_code code;
208 #ifdef HAVE_E_DATA_POINTER_IN_KRB5_ERROR
212 krb5_error *error = NULL;
216 code = krb5_init_creds_init(ctx,
224 DBG_WARNING("krb5_init_creds_init failed with: %s\n",
225 error_message(code));
229 code = krb5_init_creds_get_error(ctx,
233 DBG_WARNING("krb5_init_creds_get_error failed with: %s\n",
234 error_message(code));
237 krb5_init_creds_free(ctx, icc);
239 #ifdef HAVE_E_DATA_POINTER_IN_KRB5_ERROR
240 ok = smb_krb5_get_ntstatus_from_krb5_error(&error, nt_status);
242 krb5_free_error_contents(ctx, &error);
244 ok = smb_krb5_get_ntstatus_from_krb5_error(error, nt_status);
246 krb5_free_error(ctx, error);
253 simulate a kinit, putting the tgt in the given cache location. If cache_name == NULL
254 place in default cache location.
257 int kerberos_kinit_password_ext(const char *principal,
258 const char *password,
261 time_t *renew_till_time,
262 const char *cache_name,
264 bool add_netbios_addr,
265 time_t renewable_time,
268 krb5_context ctx = NULL;
269 krb5_error_code code = 0;
270 krb5_ccache cc = NULL;
271 krb5_principal me = NULL;
273 krb5_get_init_creds_opt *opt = NULL;
274 smb_krb5_addresses *addr = NULL;
276 ZERO_STRUCT(my_creds);
278 initialize_krb5_error_table();
279 if ((code = krb5_init_context(&ctx)))
282 if (time_offset != 0) {
283 krb5_set_real_time(ctx, time(NULL) + time_offset, 0);
286 DEBUG(10,("kerberos_kinit_password: as %s using [%s] as ccache and config [%s]\n",
288 cache_name ? cache_name: krb5_cc_default_name(ctx),
289 getenv("KRB5_CONFIG")));
291 if ((code = krb5_cc_resolve(ctx, cache_name ? cache_name : krb5_cc_default_name(ctx), &cc))) {
295 if ((code = smb_krb5_parse_name(ctx, principal, &me))) {
299 if ((code = krb5_get_init_creds_opt_alloc(ctx, &opt))) {
303 krb5_get_init_creds_opt_set_renew_life(opt, renewable_time);
304 krb5_get_init_creds_opt_set_forwardable(opt, True);
307 krb5_get_init_creds_opt_set_tkt_life(opt, 60);
310 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PAC_REQUEST
312 if ((code = krb5_get_init_creds_opt_set_pac_request(ctx, opt, (krb5_boolean)request_pac))) {
317 if (add_netbios_addr) {
318 if ((code = smb_krb5_gen_netbios_krb5_address(&addr,
319 lp_netbios_name()))) {
322 krb5_get_init_creds_opt_set_address_list(opt, addr->addrs);
325 if ((code = krb5_get_init_creds_password(ctx, &my_creds, me, discard_const_p(char,password),
326 kerb_prompter, discard_const_p(char, password),
331 if ((code = krb5_cc_initialize(ctx, cc, me))) {
335 if ((code = krb5_cc_store_cred(ctx, cc, &my_creds))) {
340 *expire_time = (time_t) my_creds.times.endtime;
343 if (renew_till_time) {
344 *renew_till_time = (time_t) my_creds.times.renew_till;
353 *ntstatus = NT_STATUS_OK;
357 /* try to get ntstatus code out of krb5_error when we have it
358 * inside the krb5_get_init_creds_opt - gd */
363 ok = smb_krb5_get_ntstatus_from_init_creds(ctx,
373 /* fall back to self-made-mapping */
374 *ntstatus = krb5_to_nt_status(code);
378 krb5_free_cred_contents(ctx, &my_creds);
380 krb5_free_principal(ctx, me);
383 smb_krb5_free_addresses(ctx, addr);
386 krb5_get_init_creds_opt_free(ctx, opt);
389 krb5_cc_close(ctx, cc);
392 krb5_free_context(ctx);
397 int ads_kdestroy(const char *cc_name)
399 krb5_error_code code;
400 krb5_context ctx = NULL;
401 krb5_ccache cc = NULL;
403 initialize_krb5_error_table();
404 if ((code = krb5_init_context (&ctx))) {
405 DEBUG(3, ("ads_kdestroy: kdb5_init_context failed: %s\n",
406 error_message(code)));
411 if ((code = krb5_cc_default(ctx, &cc))) {
412 krb5_free_context(ctx);
416 if ((code = krb5_cc_resolve(ctx, cc_name, &cc))) {
417 DEBUG(3, ("ads_kdestroy: krb5_cc_resolve failed: %s\n",
418 error_message(code)));
419 krb5_free_context(ctx);
424 if ((code = krb5_cc_destroy (ctx, cc))) {
425 DEBUG(3, ("ads_kdestroy: krb5_cc_destroy failed: %s\n",
426 error_message(code)));
429 krb5_free_context (ctx);
433 /************************************************************************
434 Routine to fetch the salting principal for a service. Active
435 Directory may use a non-obvious principal name to generate the salt
436 when it determines the key to use for encrypting tickets for a service,
437 and hopefully we detected that when we joined the domain.
438 ************************************************************************/
440 static char *kerberos_secrets_fetch_salting_principal(const char *service, int enctype)
445 if (asprintf(&key, "%s/%s/enctype=%d",
446 SECRETS_SALTING_PRINCIPAL, service, enctype) == -1) {
449 ret = (char *)secrets_fetch(key, NULL);
454 /************************************************************************
455 Return the standard DES salt key
456 ************************************************************************/
458 char* kerberos_standard_des_salt( void )
462 fstr_sprintf( salt, "host/%s.%s@", lp_netbios_name(), lp_realm() );
463 (void)strlower_m( salt );
464 fstrcat( salt, lp_realm() );
466 return SMB_STRDUP( salt );
469 /************************************************************************
470 ************************************************************************/
472 static char* des_salt_key( void )
476 if (asprintf(&key, "%s/DES/%s", SECRETS_SALTING_PRINCIPAL,
484 /************************************************************************
485 ************************************************************************/
487 bool kerberos_secrets_store_des_salt( const char* salt )
492 if ( (key = des_salt_key()) == NULL ) {
493 DEBUG(0,("kerberos_secrets_store_des_salt: failed to generate key!\n"));
498 DEBUG(8,("kerberos_secrets_store_des_salt: deleting salt\n"));
499 secrets_delete( key );
503 DEBUG(3,("kerberos_secrets_store_des_salt: Storing salt \"%s\"\n", salt));
505 ret = secrets_store( key, salt, strlen(salt)+1 );
512 /************************************************************************
513 ************************************************************************/
516 char* kerberos_secrets_fetch_des_salt( void )
520 if ( (key = des_salt_key()) == NULL ) {
521 DEBUG(0,("kerberos_secrets_fetch_des_salt: failed to generate key!\n"));
525 salt = (char*)secrets_fetch( key, NULL );
532 /************************************************************************
533 Routine to get the salting principal for this service. This is
534 maintained for backwards compatibilty with releases prior to 3.0.24.
535 Since we store the salting principal string only at join, we may have
536 to look for the older tdb keys. Caller must free if return is not null.
537 ************************************************************************/
539 char *kerberos_fetch_salt_princ_for_host_princ(krb5_context context,
540 const char *host_princ_s,
544 /* lookup new key first */
546 salt_princ_s = kerberos_secrets_fetch_des_salt();
547 if (salt_princ_s == NULL) {
549 /* look under the old key. If this fails, just use the standard key */
550 salt_princ_s = kerberos_secrets_fetch_salting_principal(host_princ_s,
552 if (salt_princ_s == NULL) {
553 /* fall back to host/machine.realm@REALM */
554 salt_princ_s = kerberos_standard_des_salt();
561 int create_kerberos_key_from_string(krb5_context context,
562 krb5_principal host_princ,
563 krb5_principal salt_princ,
566 krb5_enctype enctype,
571 * Check if we've determined that the KDC is salting keys for this
572 * principal/enctype in a non-obvious way. If it is, try to match
576 KRB5_KEY_DATA(key) = (KRB5_KEY_DATA_CAST *)SMB_MALLOC(password->length);
577 if (!KRB5_KEY_DATA(key)) {
580 memcpy(KRB5_KEY_DATA(key), password->data, password->length);
581 KRB5_KEY_LENGTH(key) = password->length;
582 KRB5_KEY_TYPE(key) = enctype;
585 ret = smb_krb5_create_key_from_string(context,
586 salt_princ ? salt_princ : host_princ,
594 /************************************************************************
595 Routine to set the salting principal for this service. Active
596 Directory may use a non-obvious principal name to generate the salt
597 when it determines the key to use for encrypting tickets for a service,
598 and hopefully we detected that when we joined the domain.
599 Setting principal to NULL deletes this entry.
600 ************************************************************************/
602 bool kerberos_secrets_store_salting_principal(const char *service,
604 const char *principal)
608 krb5_context context = NULL;
609 krb5_principal princ = NULL;
610 char *princ_s = NULL;
611 char *unparsed_name = NULL;
612 krb5_error_code code;
614 if (((code = krb5_init_context(&context)) != 0) || (context == NULL)) {
615 DEBUG(5, ("kerberos_secrets_store_salting_pricipal: kdb5_init_context failed: %s\n",
616 error_message(code)));
619 if (strchr_m(service, '@')) {
620 if (asprintf(&princ_s, "%s", service) == -1) {
624 if (asprintf(&princ_s, "%s@%s", service, lp_realm()) == -1) {
629 if (smb_krb5_parse_name(context, princ_s, &princ) != 0) {
632 if (smb_krb5_unparse_name(talloc_tos(), context, princ, &unparsed_name) != 0) {
636 if (asprintf(&key, "%s/%s/enctype=%d",
637 SECRETS_SALTING_PRINCIPAL, unparsed_name, enctype)
642 if ((principal != NULL) && (strlen(principal) > 0)) {
643 ret = secrets_store(key, principal, strlen(principal) + 1);
645 ret = secrets_delete(key);
652 TALLOC_FREE(unparsed_name);
655 krb5_free_principal(context, princ);
659 krb5_free_context(context);
666 /************************************************************************
667 ************************************************************************/
669 int kerberos_kinit_password(const char *principal,
670 const char *password,
672 const char *cache_name)
674 return kerberos_kinit_password_ext(principal,
686 /************************************************************************
687 ************************************************************************/
689 /************************************************************************
690 Create a string list of available kdc's, possibly searching by sitename.
693 If "sitename" is given, the DC's in that site are listed first.
695 ************************************************************************/
697 static void add_sockaddr_unique(struct sockaddr_storage *addrs, int *num_addrs,
698 const struct sockaddr_storage *addr)
702 for (i=0; i<*num_addrs; i++) {
703 if (sockaddr_equal((const struct sockaddr *)&addrs[i],
704 (const struct sockaddr *)addr)) {
712 /* print_canonical_sockaddr prints an ipv6 addr in the form of
713 * [ipv6.addr]. This string, when put in a generated krb5.conf file is not
714 * always properly dealt with by some older krb5 libraries. Adding the hard-coded
715 * portnumber workarounds the issue. - gd */
717 static char *print_canonical_sockaddr_with_port(TALLOC_CTX *mem_ctx,
718 const struct sockaddr_storage *pss)
722 str = print_canonical_sockaddr(mem_ctx, pss);
727 if (pss->ss_family != AF_INET6) {
731 #if defined(HAVE_IPV6)
732 str = talloc_asprintf_append(str, ":88");
737 static char *get_kdc_ip_string(char *mem_ctx,
739 const char *sitename,
740 const struct sockaddr_storage *pss)
742 TALLOC_CTX *frame = talloc_stackframe();
744 struct ip_service *ip_srv_site = NULL;
745 struct ip_service *ip_srv_nonsite = NULL;
749 struct sockaddr_storage *dc_addrs;
750 struct tsocket_address **dc_addrs2 = NULL;
751 const struct tsocket_address * const *dc_addrs3 = NULL;
753 struct netlogon_samlogon_response **responses = NULL;
755 char *kdc_str = talloc_asprintf(mem_ctx, "%s\t\tkdc = %s\n", "",
756 print_canonical_sockaddr_with_port(mem_ctx, pss));
758 if (kdc_str == NULL) {
764 * First get the KDC's only in this site, the rest will be
769 get_kdc_list(realm, sitename, &ip_srv_site, &count_site);
770 DEBUG(10, ("got %d addresses from site %s search\n", count_site,
776 get_kdc_list(realm, NULL, &ip_srv_nonsite, &count_nonsite);
777 DEBUG(10, ("got %d addresses from site-less search\n", count_nonsite));
779 dc_addrs = talloc_array(talloc_tos(), struct sockaddr_storage,
780 count_site + count_nonsite);
781 if (dc_addrs == NULL) {
787 for (i = 0; i < count_site; i++) {
789 (const struct sockaddr *)pss,
790 (const struct sockaddr *)&ip_srv_site[i].ss)) {
791 add_sockaddr_unique(dc_addrs, &num_dcs,
796 for (i = 0; i < count_nonsite; i++) {
798 (const struct sockaddr *)pss,
799 (const struct sockaddr *)&ip_srv_nonsite[i].ss)) {
800 add_sockaddr_unique(dc_addrs, &num_dcs,
801 &ip_srv_nonsite[i].ss);
805 dc_addrs2 = talloc_zero_array(talloc_tos(),
806 struct tsocket_address *,
809 DEBUG(10, ("%d additional KDCs to test\n", num_dcs));
813 if (dc_addrs2 == NULL) {
817 for (i=0; i<num_dcs; i++) {
818 char addr[INET6_ADDRSTRLEN];
821 print_sockaddr(addr, sizeof(addr), &dc_addrs[i]);
823 ret = tsocket_address_inet_from_strings(dc_addrs2, "ip",
827 status = map_nt_error_from_unix(errno);
828 DEBUG(2,("Failed to create tsocket_address for %s - %s\n",
829 addr, nt_errstr(status)));
834 dc_addrs3 = (const struct tsocket_address * const *)dc_addrs2;
836 status = cldap_multi_netlogon(talloc_tos(),
838 realm, lp_netbios_name(),
839 NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX,
840 MIN(num_dcs, 3), timeval_current_ofs(3, 0), &responses);
841 TALLOC_FREE(dc_addrs2);
844 if (!NT_STATUS_IS_OK(status)) {
845 DEBUG(10,("get_kdc_ip_string: cldap_multi_netlogon failed: "
846 "%s\n", nt_errstr(status)));
850 for (i=0; i<num_dcs; i++) {
853 if (responses[i] == NULL) {
857 /* Append to the string - inefficient but not done often. */
858 new_kdc_str = talloc_asprintf(mem_ctx, "%s\t\tkdc = %s\n",
860 print_canonical_sockaddr_with_port(mem_ctx, &dc_addrs[i]));
861 if (new_kdc_str == NULL) {
864 TALLOC_FREE(kdc_str);
865 kdc_str = new_kdc_str;
869 DEBUG(10, ("get_kdc_ip_string: Returning %s\n", kdc_str));
872 SAFE_FREE(ip_srv_site);
873 SAFE_FREE(ip_srv_nonsite);
878 /************************************************************************
879 Create a specific krb5.conf file in the private directory pointing
880 at a specific kdc for a realm. Keyed off domain name. Sets
881 KRB5_CONFIG environment variable to point to this file. Must be
882 run as root or will fail (which is a good thing :-).
883 ************************************************************************/
885 #if !defined(SAMBA4_USES_HEIMDAL) /* MIT version */
886 static char *get_enctypes(TALLOC_CTX *mem_ctx)
888 char *aes_enctypes = NULL;
889 const char *legacy_enctypes = "";
890 char *enctypes = NULL;
892 aes_enctypes = talloc_strdup(mem_ctx, "");
893 if (aes_enctypes == NULL) {
897 if (lp_kerberos_encryption_types() == KERBEROS_ETYPES_ALL ||
898 lp_kerberos_encryption_types() == KERBEROS_ETYPES_STRONG) {
899 #ifdef HAVE_ENCTYPE_AES256_CTS_HMAC_SHA1_96
900 aes_enctypes = talloc_asprintf_append(
901 aes_enctypes, "%s", "aes256-cts-hmac-sha1-96 ");
902 if (aes_enctypes == NULL) {
906 #ifdef HAVE_ENCTYPE_AES128_CTS_HMAC_SHA1_96
907 aes_enctypes = talloc_asprintf_append(
908 aes_enctypes, "%s", "aes128-cts-hmac-sha1-96");
909 if (aes_enctypes == NULL) {
915 if (lp_kerberos_encryption_types() == KERBEROS_ETYPES_ALL ||
916 lp_kerberos_encryption_types() == KERBEROS_ETYPES_LEGACY) {
917 legacy_enctypes = "RC4-HMAC DES-CBC-CRC DES-CBC-MD5";
921 talloc_asprintf(mem_ctx, "\tdefault_tgs_enctypes = %s %s\n"
922 "\tdefault_tkt_enctypes = %s %s\n"
923 "\tpreferred_enctypes = %s %s\n",
924 aes_enctypes, legacy_enctypes, aes_enctypes,
925 legacy_enctypes, aes_enctypes, legacy_enctypes);
927 TALLOC_FREE(aes_enctypes);
930 #else /* Heimdal version */
931 static char *get_enctypes(TALLOC_CTX *mem_ctx)
933 const char *aes_enctypes = "";
934 const char *legacy_enctypes = "";
935 char *enctypes = NULL;
937 if (lp_kerberos_encryption_types() == KERBEROS_ETYPES_ALL ||
938 lp_kerberos_encryption_types() == KERBEROS_ETYPES_STRONG) {
940 "aes256-cts-hmac-sha1-96 aes128-cts-hmac-sha1-96";
943 if (lp_kerberos_encryption_types() == KERBEROS_ETYPES_ALL ||
944 lp_kerberos_encryption_types() == KERBEROS_ETYPES_LEGACY) {
945 legacy_enctypes = "arcfour-hmac-md5 des-cbc-crc des-cbc-md5";
948 enctypes = talloc_asprintf(mem_ctx, "\tdefault_etypes = %s %s\n",
949 aes_enctypes, legacy_enctypes);
955 bool create_local_private_krb5_conf_for_domain(const char *realm,
957 const char *sitename,
958 const struct sockaddr_storage *pss)
961 char *tmpname = NULL;
963 char *file_contents = NULL;
964 char *kdc_ip_string = NULL;
968 char *realm_upper = NULL;
970 char *enctypes = NULL;
973 if (!lp_create_krb5_conf()) {
978 DEBUG(0, ("No realm has been specified! Do you really want to "
979 "join an Active Directory server?\n"));
983 if (domain == NULL || pss == NULL) {
987 dname = lock_path("smb_krb5");
991 if ((mkdir(dname, 0755)==-1) && (errno != EEXIST)) {
992 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
993 "failed to create directory %s. Error was %s\n",
994 dname, strerror(errno) ));
998 tmpname = lock_path("smb_tmp_krb5.XXXXXX");
1003 fname = talloc_asprintf(dname, "%s/krb5.conf.%s", dname, domain);
1008 DEBUG(10,("create_local_private_krb5_conf_for_domain: fname = %s, realm = %s, domain = %s\n",
1009 fname, realm, domain ));
1011 realm_upper = talloc_strdup(fname, realm);
1012 if (!strupper_m(realm_upper)) {
1016 kdc_ip_string = get_kdc_ip_string(dname, realm, sitename, pss);
1017 if (!kdc_ip_string) {
1021 enctypes = get_enctypes(fname);
1022 if (enctypes == NULL) {
1027 talloc_asprintf(fname, "[libdefaults]\n\tdefault_realm = %s\n"
1029 "\tdns_lookup_realm = false\n\n"
1030 "[realms]\n\t%s = {\n"
1032 realm_upper, enctypes, realm_upper, kdc_ip_string);
1034 if (!file_contents) {
1038 flen = strlen(file_contents);
1040 mask = umask(S_IRWXO | S_IRWXG);
1041 fd = mkstemp(tmpname);
1044 DEBUG(0,("create_local_private_krb5_conf_for_domain: smb_mkstemp failed,"
1045 " for file %s. Errno %s\n",
1046 tmpname, strerror(errno) ));
1050 if (fchmod(fd, 0644)==-1) {
1051 DEBUG(0,("create_local_private_krb5_conf_for_domain: fchmod failed for %s."
1053 tmpname, strerror(errno) ));
1059 ret = write(fd, file_contents, flen);
1061 DEBUG(0,("create_local_private_krb5_conf_for_domain: write failed,"
1062 " returned %d (should be %u). Errno %s\n",
1063 (int)ret, (unsigned int)flen, strerror(errno) ));
1068 if (close(fd)==-1) {
1069 DEBUG(0,("create_local_private_krb5_conf_for_domain: close failed."
1070 " Errno %s\n", strerror(errno) ));
1075 if (rename(tmpname, fname) == -1) {
1076 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
1077 "of %s to %s failed. Errno %s\n",
1078 tmpname, fname, strerror(errno) ));
1083 DEBUG(5,("create_local_private_krb5_conf_for_domain: wrote "
1084 "file %s with realm %s KDC list = %s\n",
1085 fname, realm_upper, kdc_ip_string));
1087 /* Set the environment variable to this file. */
1088 setenv("KRB5_CONFIG", fname, 1);
1092 #if defined(OVERWRITE_SYSTEM_KRB5_CONF)
1094 #define SYSTEM_KRB5_CONF_PATH "/etc/krb5.conf"
1095 /* Insanity, sheer insanity..... */
1097 if (strequal(realm, lp_realm())) {
1098 SMB_STRUCT_STAT sbuf;
1100 if (sys_lstat(SYSTEM_KRB5_CONF_PATH, &sbuf, false) == 0) {
1101 if (S_ISLNK(sbuf.st_ex_mode) && sbuf.st_ex_size) {
1103 size_t alloc_size = sbuf.st_ex_size + 1;
1104 char *linkpath = talloc_array(talloc_tos(), char,
1109 lret = readlink(SYSTEM_KRB5_CONF_PATH, linkpath,
1112 TALLOC_FREE(linkpath);
1115 linkpath[lret] = '\0';
1117 if (strcmp(linkpath, fname) == 0) {
1118 /* Symlink already exists. */
1119 TALLOC_FREE(linkpath);
1122 TALLOC_FREE(linkpath);
1126 /* Try and replace with a symlink. */
1127 if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
1128 const char *newpath = SYSTEM_KRB5_CONF_PATH ".saved";
1129 if (errno != EEXIST) {
1130 DEBUG(0,("create_local_private_krb5_conf_for_domain: symlink "
1131 "of %s to %s failed. Errno %s\n",
1132 fname, SYSTEM_KRB5_CONF_PATH, strerror(errno) ));
1133 goto done; /* Not a fatal error. */
1136 /* Yes, this is a race conditon... too bad. */
1137 if (rename(SYSTEM_KRB5_CONF_PATH, newpath) == -1) {
1138 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
1139 "of %s to %s failed. Errno %s\n",
1140 SYSTEM_KRB5_CONF_PATH, newpath,
1142 goto done; /* Not a fatal error. */
1145 if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
1146 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
1147 "forced symlink of %s to /etc/krb5.conf failed. Errno %s\n",
1148 fname, strerror(errno) ));
1149 goto done; /* Not a fatal error. */
1156 TALLOC_FREE(tmpname);