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 #ifdef HAVE_E_DATA_POINTER_IN_KRB5_ERROR
209 krb5_init_creds_context icc;
210 krb5_error_code code;
214 code = krb5_init_creds_init(ctx,
222 DBG_WARNING("krb5_init_creds_init failed with: %s\n",
223 error_message(code));
227 code = krb5_init_creds_get_error(ctx,
231 DBG_WARNING("krb5_init_creds_get_error failed with: %s\n",
232 error_message(code));
235 krb5_init_creds_free(ctx, icc);
237 ok = smb_krb5_get_ntstatus_from_krb5_error(&error, nt_status);
239 krb5_free_error_contents(ctx, &error);
248 simulate a kinit, putting the tgt in the given cache location. If cache_name == NULL
249 place in default cache location.
252 int kerberos_kinit_password_ext(const char *principal,
253 const char *password,
256 time_t *renew_till_time,
257 const char *cache_name,
259 bool add_netbios_addr,
260 time_t renewable_time,
263 krb5_context ctx = NULL;
264 krb5_error_code code = 0;
265 krb5_ccache cc = NULL;
266 krb5_principal me = NULL;
268 krb5_get_init_creds_opt *opt = NULL;
269 smb_krb5_addresses *addr = NULL;
271 ZERO_STRUCT(my_creds);
273 initialize_krb5_error_table();
274 if ((code = krb5_init_context(&ctx)))
277 if (time_offset != 0) {
278 krb5_set_real_time(ctx, time(NULL) + time_offset, 0);
281 DEBUG(10,("kerberos_kinit_password: as %s using [%s] as ccache and config [%s]\n",
283 cache_name ? cache_name: krb5_cc_default_name(ctx),
284 getenv("KRB5_CONFIG")));
286 if ((code = krb5_cc_resolve(ctx, cache_name ? cache_name : krb5_cc_default_name(ctx), &cc))) {
290 if ((code = smb_krb5_parse_name(ctx, principal, &me))) {
294 if ((code = krb5_get_init_creds_opt_alloc(ctx, &opt))) {
298 krb5_get_init_creds_opt_set_renew_life(opt, renewable_time);
299 krb5_get_init_creds_opt_set_forwardable(opt, True);
302 krb5_get_init_creds_opt_set_tkt_life(opt, 60);
305 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PAC_REQUEST
307 if ((code = krb5_get_init_creds_opt_set_pac_request(ctx, opt, (krb5_boolean)request_pac))) {
312 if (add_netbios_addr) {
313 if ((code = smb_krb5_gen_netbios_krb5_address(&addr,
314 lp_netbios_name()))) {
317 krb5_get_init_creds_opt_set_address_list(opt, addr->addrs);
320 if ((code = krb5_get_init_creds_password(ctx, &my_creds, me, discard_const_p(char,password),
321 kerb_prompter, discard_const_p(char, password),
326 if ((code = krb5_cc_initialize(ctx, cc, me))) {
330 if ((code = krb5_cc_store_cred(ctx, cc, &my_creds))) {
335 *expire_time = (time_t) my_creds.times.endtime;
338 if (renew_till_time) {
339 *renew_till_time = (time_t) my_creds.times.renew_till;
348 *ntstatus = NT_STATUS_OK;
352 /* try to get ntstatus code out of krb5_error when we have it
353 * inside the krb5_get_init_creds_opt - gd */
358 ok = smb_krb5_get_ntstatus_from_init_creds(ctx,
368 /* fall back to self-made-mapping */
369 *ntstatus = krb5_to_nt_status(code);
373 krb5_free_cred_contents(ctx, &my_creds);
375 krb5_free_principal(ctx, me);
378 smb_krb5_free_addresses(ctx, addr);
381 krb5_get_init_creds_opt_free(ctx, opt);
384 krb5_cc_close(ctx, cc);
387 krb5_free_context(ctx);
392 int ads_kdestroy(const char *cc_name)
394 krb5_error_code code;
395 krb5_context ctx = NULL;
396 krb5_ccache cc = NULL;
398 initialize_krb5_error_table();
399 if ((code = krb5_init_context (&ctx))) {
400 DEBUG(3, ("ads_kdestroy: kdb5_init_context failed: %s\n",
401 error_message(code)));
406 if ((code = krb5_cc_default(ctx, &cc))) {
407 krb5_free_context(ctx);
411 if ((code = krb5_cc_resolve(ctx, cc_name, &cc))) {
412 DEBUG(3, ("ads_kdestroy: krb5_cc_resolve failed: %s\n",
413 error_message(code)));
414 krb5_free_context(ctx);
419 if ((code = krb5_cc_destroy (ctx, cc))) {
420 DEBUG(3, ("ads_kdestroy: krb5_cc_destroy failed: %s\n",
421 error_message(code)));
424 krb5_free_context (ctx);
428 /************************************************************************
429 Routine to fetch the salting principal for a service. Active
430 Directory may use a non-obvious principal name to generate the salt
431 when it determines the key to use for encrypting tickets for a service,
432 and hopefully we detected that when we joined the domain.
433 ************************************************************************/
435 static char *kerberos_secrets_fetch_salting_principal(const char *service, int enctype)
440 if (asprintf(&key, "%s/%s/enctype=%d",
441 SECRETS_SALTING_PRINCIPAL, service, enctype) == -1) {
444 ret = (char *)secrets_fetch(key, NULL);
449 /************************************************************************
450 Return the standard DES salt key
451 ************************************************************************/
453 char* kerberos_standard_des_salt( void )
457 fstr_sprintf( salt, "host/%s.%s@", lp_netbios_name(), lp_realm() );
458 (void)strlower_m( salt );
459 fstrcat( salt, lp_realm() );
461 return SMB_STRDUP( salt );
464 /************************************************************************
465 ************************************************************************/
467 static char* des_salt_key( void )
471 if (asprintf(&key, "%s/DES/%s", SECRETS_SALTING_PRINCIPAL,
479 /************************************************************************
480 ************************************************************************/
482 bool kerberos_secrets_store_des_salt( const char* salt )
487 if ( (key = des_salt_key()) == NULL ) {
488 DEBUG(0,("kerberos_secrets_store_des_salt: failed to generate key!\n"));
493 DEBUG(8,("kerberos_secrets_store_des_salt: deleting salt\n"));
494 secrets_delete( key );
498 DEBUG(3,("kerberos_secrets_store_des_salt: Storing salt \"%s\"\n", salt));
500 ret = secrets_store( key, salt, strlen(salt)+1 );
507 /************************************************************************
508 ************************************************************************/
511 char* kerberos_secrets_fetch_des_salt( void )
515 if ( (key = des_salt_key()) == NULL ) {
516 DEBUG(0,("kerberos_secrets_fetch_des_salt: failed to generate key!\n"));
520 salt = (char*)secrets_fetch( key, NULL );
527 /************************************************************************
528 Routine to get the salting principal for this service. This is
529 maintained for backwards compatibilty with releases prior to 3.0.24.
530 Since we store the salting principal string only at join, we may have
531 to look for the older tdb keys. Caller must free if return is not null.
532 ************************************************************************/
534 char *kerberos_fetch_salt_princ_for_host_princ(krb5_context context,
535 const char *host_princ_s,
539 /* lookup new key first */
541 salt_princ_s = kerberos_secrets_fetch_des_salt();
542 if (salt_princ_s == NULL) {
544 /* look under the old key. If this fails, just use the standard key */
545 salt_princ_s = kerberos_secrets_fetch_salting_principal(host_princ_s,
547 if (salt_princ_s == NULL) {
548 /* fall back to host/machine.realm@REALM */
549 salt_princ_s = kerberos_standard_des_salt();
556 int create_kerberos_key_from_string(krb5_context context,
557 krb5_principal host_princ,
558 krb5_principal salt_princ,
561 krb5_enctype enctype,
566 * Check if we've determined that the KDC is salting keys for this
567 * principal/enctype in a non-obvious way. If it is, try to match
571 KRB5_KEY_DATA(key) = (KRB5_KEY_DATA_CAST *)SMB_MALLOC(password->length);
572 if (!KRB5_KEY_DATA(key)) {
575 memcpy(KRB5_KEY_DATA(key), password->data, password->length);
576 KRB5_KEY_LENGTH(key) = password->length;
577 KRB5_KEY_TYPE(key) = enctype;
580 ret = smb_krb5_create_key_from_string(context,
581 salt_princ ? salt_princ : host_princ,
589 /************************************************************************
590 Routine to set the salting principal for this service. Active
591 Directory may use a non-obvious principal name to generate the salt
592 when it determines the key to use for encrypting tickets for a service,
593 and hopefully we detected that when we joined the domain.
594 Setting principal to NULL deletes this entry.
595 ************************************************************************/
597 bool kerberos_secrets_store_salting_principal(const char *service,
599 const char *principal)
603 krb5_context context = NULL;
604 krb5_principal princ = NULL;
605 char *princ_s = NULL;
606 char *unparsed_name = NULL;
607 krb5_error_code code;
609 if (((code = krb5_init_context(&context)) != 0) || (context == NULL)) {
610 DEBUG(5, ("kerberos_secrets_store_salting_pricipal: kdb5_init_context failed: %s\n",
611 error_message(code)));
614 if (strchr_m(service, '@')) {
615 if (asprintf(&princ_s, "%s", service) == -1) {
619 if (asprintf(&princ_s, "%s@%s", service, lp_realm()) == -1) {
624 if (smb_krb5_parse_name(context, princ_s, &princ) != 0) {
627 if (smb_krb5_unparse_name(talloc_tos(), context, princ, &unparsed_name) != 0) {
631 if (asprintf(&key, "%s/%s/enctype=%d",
632 SECRETS_SALTING_PRINCIPAL, unparsed_name, enctype)
637 if ((principal != NULL) && (strlen(principal) > 0)) {
638 ret = secrets_store(key, principal, strlen(principal) + 1);
640 ret = secrets_delete(key);
647 TALLOC_FREE(unparsed_name);
650 krb5_free_principal(context, princ);
654 krb5_free_context(context);
661 /************************************************************************
662 ************************************************************************/
664 int kerberos_kinit_password(const char *principal,
665 const char *password,
667 const char *cache_name)
669 return kerberos_kinit_password_ext(principal,
681 /************************************************************************
682 ************************************************************************/
684 /************************************************************************
685 Create a string list of available kdc's, possibly searching by sitename.
688 If "sitename" is given, the DC's in that site are listed first.
690 ************************************************************************/
692 static void add_sockaddr_unique(struct sockaddr_storage *addrs, int *num_addrs,
693 const struct sockaddr_storage *addr)
697 for (i=0; i<*num_addrs; i++) {
698 if (sockaddr_equal((const struct sockaddr *)&addrs[i],
699 (const struct sockaddr *)addr)) {
707 /* print_canonical_sockaddr prints an ipv6 addr in the form of
708 * [ipv6.addr]. This string, when put in a generated krb5.conf file is not
709 * always properly dealt with by some older krb5 libraries. Adding the hard-coded
710 * portnumber workarounds the issue. - gd */
712 static char *print_canonical_sockaddr_with_port(TALLOC_CTX *mem_ctx,
713 const struct sockaddr_storage *pss)
717 str = print_canonical_sockaddr(mem_ctx, pss);
722 if (pss->ss_family != AF_INET6) {
726 #if defined(HAVE_IPV6)
727 str = talloc_asprintf_append(str, ":88");
732 static char *get_kdc_ip_string(char *mem_ctx,
734 const char *sitename,
735 const struct sockaddr_storage *pss)
737 TALLOC_CTX *frame = talloc_stackframe();
739 struct ip_service *ip_srv_site = NULL;
740 struct ip_service *ip_srv_nonsite = NULL;
744 struct sockaddr_storage *dc_addrs;
745 struct tsocket_address **dc_addrs2 = NULL;
746 const struct tsocket_address * const *dc_addrs3 = NULL;
748 struct netlogon_samlogon_response **responses = NULL;
750 char *kdc_str = talloc_asprintf(mem_ctx, "%s\t\tkdc = %s\n", "",
751 print_canonical_sockaddr_with_port(mem_ctx, pss));
753 if (kdc_str == NULL) {
759 * First get the KDC's only in this site, the rest will be
764 get_kdc_list(realm, sitename, &ip_srv_site, &count_site);
765 DEBUG(10, ("got %d addresses from site %s search\n", count_site,
771 get_kdc_list(realm, NULL, &ip_srv_nonsite, &count_nonsite);
772 DEBUG(10, ("got %d addresses from site-less search\n", count_nonsite));
774 dc_addrs = talloc_array(talloc_tos(), struct sockaddr_storage,
775 count_site + count_nonsite);
776 if (dc_addrs == NULL) {
782 for (i = 0; i < count_site; i++) {
784 (const struct sockaddr *)pss,
785 (const struct sockaddr *)&ip_srv_site[i].ss)) {
786 add_sockaddr_unique(dc_addrs, &num_dcs,
791 for (i = 0; i < count_nonsite; i++) {
793 (const struct sockaddr *)pss,
794 (const struct sockaddr *)&ip_srv_nonsite[i].ss)) {
795 add_sockaddr_unique(dc_addrs, &num_dcs,
796 &ip_srv_nonsite[i].ss);
800 dc_addrs2 = talloc_zero_array(talloc_tos(),
801 struct tsocket_address *,
804 DEBUG(10, ("%d additional KDCs to test\n", num_dcs));
808 if (dc_addrs2 == NULL) {
812 for (i=0; i<num_dcs; i++) {
813 char addr[INET6_ADDRSTRLEN];
816 print_sockaddr(addr, sizeof(addr), &dc_addrs[i]);
818 ret = tsocket_address_inet_from_strings(dc_addrs2, "ip",
822 status = map_nt_error_from_unix(errno);
823 DEBUG(2,("Failed to create tsocket_address for %s - %s\n",
824 addr, nt_errstr(status)));
829 dc_addrs3 = (const struct tsocket_address * const *)dc_addrs2;
831 status = cldap_multi_netlogon(talloc_tos(),
833 realm, lp_netbios_name(),
834 NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX,
835 MIN(num_dcs, 3), timeval_current_ofs(3, 0), &responses);
836 TALLOC_FREE(dc_addrs2);
839 if (!NT_STATUS_IS_OK(status)) {
840 DEBUG(10,("get_kdc_ip_string: cldap_multi_netlogon failed: "
841 "%s\n", nt_errstr(status)));
845 for (i=0; i<num_dcs; i++) {
848 if (responses[i] == NULL) {
852 /* Append to the string - inefficient but not done often. */
853 new_kdc_str = talloc_asprintf(mem_ctx, "%s\t\tkdc = %s\n",
855 print_canonical_sockaddr_with_port(mem_ctx, &dc_addrs[i]));
856 if (new_kdc_str == NULL) {
859 TALLOC_FREE(kdc_str);
860 kdc_str = new_kdc_str;
864 DEBUG(10, ("get_kdc_ip_string: Returning %s\n", kdc_str));
867 SAFE_FREE(ip_srv_site);
868 SAFE_FREE(ip_srv_nonsite);
873 /************************************************************************
874 Create a specific krb5.conf file in the private directory pointing
875 at a specific kdc for a realm. Keyed off domain name. Sets
876 KRB5_CONFIG environment variable to point to this file. Must be
877 run as root or will fail (which is a good thing :-).
878 ************************************************************************/
880 #if !defined(SAMBA4_USES_HEIMDAL) /* MIT version */
881 static char *get_enctypes(TALLOC_CTX *mem_ctx)
883 char *aes_enctypes = NULL;
884 const char *legacy_enctypes = "";
885 char *enctypes = NULL;
887 aes_enctypes = talloc_strdup(mem_ctx, "");
888 if (aes_enctypes == NULL) {
892 if (lp_kerberos_encryption_types() == KERBEROS_ETYPES_ALL ||
893 lp_kerberos_encryption_types() == KERBEROS_ETYPES_STRONG) {
894 #ifdef HAVE_ENCTYPE_AES256_CTS_HMAC_SHA1_96
895 aes_enctypes = talloc_asprintf_append(
896 aes_enctypes, "%s", "aes256-cts-hmac-sha1-96 ");
897 if (aes_enctypes == NULL) {
901 #ifdef HAVE_ENCTYPE_AES128_CTS_HMAC_SHA1_96
902 aes_enctypes = talloc_asprintf_append(
903 aes_enctypes, "%s", "aes128-cts-hmac-sha1-96");
904 if (aes_enctypes == NULL) {
910 if (lp_kerberos_encryption_types() == KERBEROS_ETYPES_ALL ||
911 lp_kerberos_encryption_types() == KERBEROS_ETYPES_LEGACY) {
912 legacy_enctypes = "RC4-HMAC DES-CBC-CRC DES-CBC-MD5";
916 talloc_asprintf(mem_ctx, "\tdefault_tgs_enctypes = %s %s\n"
917 "\tdefault_tkt_enctypes = %s %s\n"
918 "\tpreferred_enctypes = %s %s\n",
919 aes_enctypes, legacy_enctypes, aes_enctypes,
920 legacy_enctypes, aes_enctypes, legacy_enctypes);
922 TALLOC_FREE(aes_enctypes);
925 #else /* Heimdal version */
926 static char *get_enctypes(TALLOC_CTX *mem_ctx)
928 const char *aes_enctypes = "";
929 const char *legacy_enctypes = "";
930 char *enctypes = NULL;
932 if (lp_kerberos_encryption_types() == KERBEROS_ETYPES_ALL ||
933 lp_kerberos_encryption_types() == KERBEROS_ETYPES_STRONG) {
935 "aes256-cts-hmac-sha1-96 aes128-cts-hmac-sha1-96";
938 if (lp_kerberos_encryption_types() == KERBEROS_ETYPES_ALL ||
939 lp_kerberos_encryption_types() == KERBEROS_ETYPES_LEGACY) {
940 legacy_enctypes = "arcfour-hmac-md5 des-cbc-crc des-cbc-md5";
943 enctypes = talloc_asprintf(mem_ctx, "\tdefault_etypes = %s %s\n",
944 aes_enctypes, legacy_enctypes);
950 bool create_local_private_krb5_conf_for_domain(const char *realm,
952 const char *sitename,
953 const struct sockaddr_storage *pss)
956 char *tmpname = NULL;
958 char *file_contents = NULL;
959 char *kdc_ip_string = NULL;
963 char *realm_upper = NULL;
965 char *enctypes = NULL;
968 if (!lp_create_krb5_conf()) {
973 DEBUG(0, ("No realm has been specified! Do you really want to "
974 "join an Active Directory server?\n"));
978 if (domain == NULL || pss == NULL) {
982 dname = lock_path("smb_krb5");
986 if ((mkdir(dname, 0755)==-1) && (errno != EEXIST)) {
987 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
988 "failed to create directory %s. Error was %s\n",
989 dname, strerror(errno) ));
993 tmpname = lock_path("smb_tmp_krb5.XXXXXX");
998 fname = talloc_asprintf(dname, "%s/krb5.conf.%s", dname, domain);
1003 DEBUG(10,("create_local_private_krb5_conf_for_domain: fname = %s, realm = %s, domain = %s\n",
1004 fname, realm, domain ));
1006 realm_upper = talloc_strdup(fname, realm);
1007 if (!strupper_m(realm_upper)) {
1011 kdc_ip_string = get_kdc_ip_string(dname, realm, sitename, pss);
1012 if (!kdc_ip_string) {
1016 enctypes = get_enctypes(fname);
1017 if (enctypes == NULL) {
1022 talloc_asprintf(fname, "[libdefaults]\n\tdefault_realm = %s\n"
1024 "\tdns_lookup_realm = false\n\n"
1025 "[realms]\n\t%s = {\n"
1027 realm_upper, enctypes, realm_upper, kdc_ip_string);
1029 if (!file_contents) {
1033 flen = strlen(file_contents);
1035 mask = umask(S_IRWXO | S_IRWXG);
1036 fd = mkstemp(tmpname);
1039 DEBUG(0,("create_local_private_krb5_conf_for_domain: smb_mkstemp failed,"
1040 " for file %s. Errno %s\n",
1041 tmpname, strerror(errno) ));
1045 if (fchmod(fd, 0644)==-1) {
1046 DEBUG(0,("create_local_private_krb5_conf_for_domain: fchmod failed for %s."
1048 tmpname, strerror(errno) ));
1054 ret = write(fd, file_contents, flen);
1056 DEBUG(0,("create_local_private_krb5_conf_for_domain: write failed,"
1057 " returned %d (should be %u). Errno %s\n",
1058 (int)ret, (unsigned int)flen, strerror(errno) ));
1063 if (close(fd)==-1) {
1064 DEBUG(0,("create_local_private_krb5_conf_for_domain: close failed."
1065 " Errno %s\n", strerror(errno) ));
1070 if (rename(tmpname, fname) == -1) {
1071 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
1072 "of %s to %s failed. Errno %s\n",
1073 tmpname, fname, strerror(errno) ));
1078 DEBUG(5,("create_local_private_krb5_conf_for_domain: wrote "
1079 "file %s with realm %s KDC list = %s\n",
1080 fname, realm_upper, kdc_ip_string));
1082 /* Set the environment variable to this file. */
1083 setenv("KRB5_CONFIG", fname, 1);
1087 #if defined(OVERWRITE_SYSTEM_KRB5_CONF)
1089 #define SYSTEM_KRB5_CONF_PATH "/etc/krb5.conf"
1090 /* Insanity, sheer insanity..... */
1092 if (strequal(realm, lp_realm())) {
1093 SMB_STRUCT_STAT sbuf;
1095 if (sys_lstat(SYSTEM_KRB5_CONF_PATH, &sbuf, false) == 0) {
1096 if (S_ISLNK(sbuf.st_ex_mode) && sbuf.st_ex_size) {
1098 size_t alloc_size = sbuf.st_ex_size + 1;
1099 char *linkpath = talloc_array(talloc_tos(), char,
1104 lret = readlink(SYSTEM_KRB5_CONF_PATH, linkpath,
1107 TALLOC_FREE(linkpath);
1110 linkpath[lret] = '\0';
1112 if (strcmp(linkpath, fname) == 0) {
1113 /* Symlink already exists. */
1114 TALLOC_FREE(linkpath);
1117 TALLOC_FREE(linkpath);
1121 /* Try and replace with a symlink. */
1122 if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
1123 const char *newpath = SYSTEM_KRB5_CONF_PATH ".saved";
1124 if (errno != EEXIST) {
1125 DEBUG(0,("create_local_private_krb5_conf_for_domain: symlink "
1126 "of %s to %s failed. Errno %s\n",
1127 fname, SYSTEM_KRB5_CONF_PATH, strerror(errno) ));
1128 goto done; /* Not a fatal error. */
1131 /* Yes, this is a race conditon... too bad. */
1132 if (rename(SYSTEM_KRB5_CONF_PATH, newpath) == -1) {
1133 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
1134 "of %s to %s failed. Errno %s\n",
1135 SYSTEM_KRB5_CONF_PATH, newpath,
1137 goto done; /* Not a fatal error. */
1140 if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
1141 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
1142 "forced symlink of %s to /etc/krb5.conf failed. Errno %s\n",
1143 fname, strerror(errno) ));
1144 goto done; /* Not a fatal error. */
1151 TALLOC_FREE(tmpname);