Revert "winbind: Fix 100% loop"
[Samba.git] / source3 / libads / kerberos.c
blobe4bad749286834b523719535a5c710f7c542b76e
1 /*
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/>.
24 #include "includes.h"
25 #include "system/filesys.h"
26 #include "smb_krb5.h"
27 #include "../librpc/gen_ndr/ndr_misc.h"
28 #include "libads/kerberos_proto.h"
29 #include "libads/cldap.h"
30 #include "secrets.h"
31 #include "../lib/tsocket/tsocket.h"
33 #ifdef HAVE_KRB5
35 #define LIBADS_CCACHE_NAME "MEMORY:libads"
38 we use a prompter to avoid a crash bug in the kerberos libs when
39 dealing with empty passwords
40 this prompter is just a string copy ...
42 static krb5_error_code
43 kerb_prompter(krb5_context ctx, void *data,
44 const char *name,
45 const char *banner,
46 int num_prompts,
47 krb5_prompt prompts[])
49 if (num_prompts == 0) return 0;
51 memset(prompts[0].reply->data, '\0', prompts[0].reply->length);
52 if (prompts[0].reply->length > 0) {
53 if (data) {
54 strncpy((char *)prompts[0].reply->data, (const char *)data,
55 prompts[0].reply->length-1);
56 prompts[0].reply->length = strlen((const char *)prompts[0].reply->data);
57 } else {
58 prompts[0].reply->length = 0;
61 return 0;
64 static bool smb_krb5_get_ntstatus_from_krb5_error(krb5_error *error,
65 NTSTATUS *nt_status)
67 DATA_BLOB edata;
68 DATA_BLOB unwrapped_edata;
69 TALLOC_CTX *mem_ctx;
70 struct KRB5_EDATA_NTSTATUS parsed_edata;
71 enum ndr_err_code ndr_err;
73 #ifdef HAVE_E_DATA_POINTER_IN_KRB5_ERROR
74 edata = data_blob(error->e_data->data, error->e_data->length);
75 #else
76 edata = data_blob(error->e_data.data, error->e_data.length);
77 #endif /* HAVE_E_DATA_POINTER_IN_KRB5_ERROR */
79 #ifdef DEVELOPER
80 dump_data(10, edata.data, edata.length);
81 #endif /* DEVELOPER */
83 mem_ctx = talloc_init("smb_krb5_get_ntstatus_from_krb5_error");
84 if (mem_ctx == NULL) {
85 data_blob_free(&edata);
86 return False;
89 if (!unwrap_edata_ntstatus(mem_ctx, &edata, &unwrapped_edata)) {
90 data_blob_free(&edata);
91 TALLOC_FREE(mem_ctx);
92 return False;
95 data_blob_free(&edata);
97 ndr_err = ndr_pull_struct_blob_all(&unwrapped_edata, mem_ctx,
98 &parsed_edata, (ndr_pull_flags_fn_t)ndr_pull_KRB5_EDATA_NTSTATUS);
99 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
100 data_blob_free(&unwrapped_edata);
101 TALLOC_FREE(mem_ctx);
102 return False;
105 data_blob_free(&unwrapped_edata);
107 if (nt_status) {
108 *nt_status = parsed_edata.ntstatus;
111 TALLOC_FREE(mem_ctx);
113 return True;
116 static bool smb_krb5_get_ntstatus_from_krb5_error_init_creds_opt(krb5_context ctx,
117 krb5_get_init_creds_opt *opt,
118 NTSTATUS *nt_status)
120 bool ret = False;
121 krb5_error *error = NULL;
123 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_GET_ERROR
124 ret = krb5_get_init_creds_opt_get_error(ctx, opt, &error);
125 if (ret) {
126 DEBUG(1,("krb5_get_init_creds_opt_get_error gave: %s\n",
127 error_message(ret)));
128 return False;
130 #endif /* HAVE_KRB5_GET_INIT_CREDS_OPT_GET_ERROR */
132 if (!error) {
133 DEBUG(1,("no krb5_error\n"));
134 return False;
137 #ifdef HAVE_E_DATA_POINTER_IN_KRB5_ERROR
138 if (!error->e_data) {
139 #else
140 if (error->e_data.data == NULL) {
141 #endif /* HAVE_E_DATA_POINTER_IN_KRB5_ERROR */
142 DEBUG(1,("no edata in krb5_error\n"));
143 krb5_free_error(ctx, error);
144 return False;
147 ret = smb_krb5_get_ntstatus_from_krb5_error(error, nt_status);
149 krb5_free_error(ctx, error);
151 return ret;
155 simulate a kinit, putting the tgt in the given cache location. If cache_name == NULL
156 place in default cache location.
157 remus@snapserver.com
159 int kerberos_kinit_password_ext(const char *principal,
160 const char *password,
161 int time_offset,
162 time_t *expire_time,
163 time_t *renew_till_time,
164 const char *cache_name,
165 bool request_pac,
166 bool add_netbios_addr,
167 time_t renewable_time,
168 NTSTATUS *ntstatus)
170 krb5_context ctx = NULL;
171 krb5_error_code code = 0;
172 krb5_ccache cc = NULL;
173 krb5_principal me = NULL;
174 krb5_creds my_creds;
175 krb5_get_init_creds_opt *opt = NULL;
176 smb_krb5_addresses *addr = NULL;
178 ZERO_STRUCT(my_creds);
180 initialize_krb5_error_table();
181 if ((code = krb5_init_context(&ctx)))
182 goto out;
184 if (time_offset != 0) {
185 krb5_set_real_time(ctx, time(NULL) + time_offset, 0);
188 DEBUG(10,("kerberos_kinit_password: as %s using [%s] as ccache and config [%s]\n",
189 principal,
190 cache_name ? cache_name: krb5_cc_default_name(ctx),
191 getenv("KRB5_CONFIG")));
193 if ((code = krb5_cc_resolve(ctx, cache_name ? cache_name : krb5_cc_default_name(ctx), &cc))) {
194 goto out;
197 if ((code = smb_krb5_parse_name(ctx, principal, &me))) {
198 goto out;
201 if ((code = smb_krb5_get_init_creds_opt_alloc(ctx, &opt))) {
202 goto out;
205 krb5_get_init_creds_opt_set_renew_life(opt, renewable_time);
206 krb5_get_init_creds_opt_set_forwardable(opt, True);
207 #if 0
208 /* insane testing */
209 krb5_get_init_creds_opt_set_tkt_life(opt, 60);
210 #endif
212 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PAC_REQUEST
213 if (request_pac) {
214 if ((code = krb5_get_init_creds_opt_set_pac_request(ctx, opt, (krb5_boolean)request_pac))) {
215 goto out;
218 #endif
219 if (add_netbios_addr) {
220 if ((code = smb_krb5_gen_netbios_krb5_address(&addr,
221 lp_netbios_name()))) {
222 goto out;
224 krb5_get_init_creds_opt_set_address_list(opt, addr->addrs);
227 if ((code = krb5_get_init_creds_password(ctx, &my_creds, me, discard_const_p(char,password),
228 kerb_prompter, discard_const_p(char, password),
229 0, NULL, opt))) {
230 goto out;
233 if ((code = krb5_cc_initialize(ctx, cc, me))) {
234 goto out;
237 if ((code = krb5_cc_store_cred(ctx, cc, &my_creds))) {
238 goto out;
241 if (expire_time) {
242 *expire_time = (time_t) my_creds.times.endtime;
245 if (renew_till_time) {
246 *renew_till_time = (time_t) my_creds.times.renew_till;
248 out:
249 if (ntstatus) {
251 NTSTATUS status;
253 /* fast path */
254 if (code == 0) {
255 *ntstatus = NT_STATUS_OK;
256 goto cleanup;
259 /* try to get ntstatus code out of krb5_error when we have it
260 * inside the krb5_get_init_creds_opt - gd */
262 if (opt && smb_krb5_get_ntstatus_from_krb5_error_init_creds_opt(ctx, opt, &status)) {
263 *ntstatus = status;
264 goto cleanup;
267 /* fall back to self-made-mapping */
268 *ntstatus = krb5_to_nt_status(code);
271 cleanup:
272 krb5_free_cred_contents(ctx, &my_creds);
273 if (me) {
274 krb5_free_principal(ctx, me);
276 if (addr) {
277 smb_krb5_free_addresses(ctx, addr);
279 if (opt) {
280 smb_krb5_get_init_creds_opt_free(ctx, opt);
282 if (cc) {
283 krb5_cc_close(ctx, cc);
285 if (ctx) {
286 krb5_free_context(ctx);
288 return code;
291 int ads_kdestroy(const char *cc_name)
293 krb5_error_code code;
294 krb5_context ctx = NULL;
295 krb5_ccache cc = NULL;
297 initialize_krb5_error_table();
298 if ((code = krb5_init_context (&ctx))) {
299 DEBUG(3, ("ads_kdestroy: kdb5_init_context failed: %s\n",
300 error_message(code)));
301 return code;
304 if (!cc_name) {
305 if ((code = krb5_cc_default(ctx, &cc))) {
306 krb5_free_context(ctx);
307 return code;
309 } else {
310 if ((code = krb5_cc_resolve(ctx, cc_name, &cc))) {
311 DEBUG(3, ("ads_kdestroy: krb5_cc_resolve failed: %s\n",
312 error_message(code)));
313 krb5_free_context(ctx);
314 return code;
318 if ((code = krb5_cc_destroy (ctx, cc))) {
319 DEBUG(3, ("ads_kdestroy: krb5_cc_destroy failed: %s\n",
320 error_message(code)));
323 krb5_free_context (ctx);
324 return code;
327 /************************************************************************
328 Routine to fetch the salting principal for a service. Active
329 Directory may use a non-obvious principal name to generate the salt
330 when it determines the key to use for encrypting tickets for a service,
331 and hopefully we detected that when we joined the domain.
332 ************************************************************************/
334 static char *kerberos_secrets_fetch_salting_principal(const char *service, int enctype)
336 char *key = NULL;
337 char *ret = NULL;
339 if (asprintf(&key, "%s/%s/enctype=%d",
340 SECRETS_SALTING_PRINCIPAL, service, enctype) == -1) {
341 return NULL;
343 ret = (char *)secrets_fetch(key, NULL);
344 SAFE_FREE(key);
345 return ret;
348 /************************************************************************
349 Return the standard DES salt key
350 ************************************************************************/
352 char* kerberos_standard_des_salt( void )
354 fstring salt;
356 fstr_sprintf( salt, "host/%s.%s@", lp_netbios_name(), lp_realm() );
357 (void)strlower_m( salt );
358 fstrcat( salt, lp_realm() );
360 return SMB_STRDUP( salt );
363 /************************************************************************
364 ************************************************************************/
366 static char* des_salt_key( void )
368 char *key;
370 if (asprintf(&key, "%s/DES/%s", SECRETS_SALTING_PRINCIPAL,
371 lp_realm()) == -1) {
372 return NULL;
375 return key;
378 /************************************************************************
379 ************************************************************************/
381 bool kerberos_secrets_store_des_salt( const char* salt )
383 char* key;
384 bool ret;
386 if ( (key = des_salt_key()) == NULL ) {
387 DEBUG(0,("kerberos_secrets_store_des_salt: failed to generate key!\n"));
388 return False;
391 if ( !salt ) {
392 DEBUG(8,("kerberos_secrets_store_des_salt: deleting salt\n"));
393 secrets_delete( key );
394 return True;
397 DEBUG(3,("kerberos_secrets_store_des_salt: Storing salt \"%s\"\n", salt));
399 ret = secrets_store( key, salt, strlen(salt)+1 );
401 SAFE_FREE( key );
403 return ret;
406 /************************************************************************
407 ************************************************************************/
409 static
410 char* kerberos_secrets_fetch_des_salt( void )
412 char *salt, *key;
414 if ( (key = des_salt_key()) == NULL ) {
415 DEBUG(0,("kerberos_secrets_fetch_des_salt: failed to generate key!\n"));
416 return NULL;
419 salt = (char*)secrets_fetch( key, NULL );
421 SAFE_FREE( key );
423 return salt;
426 /************************************************************************
427 Routine to get the salting principal for this service. This is
428 maintained for backwards compatibilty with releases prior to 3.0.24.
429 Since we store the salting principal string only at join, we may have
430 to look for the older tdb keys. Caller must free if return is not null.
431 ************************************************************************/
433 static
434 krb5_principal kerberos_fetch_salt_princ_for_host_princ(krb5_context context,
435 krb5_principal host_princ,
436 int enctype)
438 char *unparsed_name = NULL, *salt_princ_s = NULL;
439 krb5_principal ret_princ = NULL;
441 /* lookup new key first */
443 if ( (salt_princ_s = kerberos_secrets_fetch_des_salt()) == NULL ) {
445 /* look under the old key. If this fails, just use the standard key */
447 if (smb_krb5_unparse_name(talloc_tos(), context, host_princ, &unparsed_name) != 0) {
448 return (krb5_principal)NULL;
450 if ((salt_princ_s = kerberos_secrets_fetch_salting_principal(unparsed_name, enctype)) == NULL) {
451 /* fall back to host/machine.realm@REALM */
452 salt_princ_s = kerberos_standard_des_salt();
456 if (smb_krb5_parse_name(context, salt_princ_s, &ret_princ) != 0) {
457 ret_princ = NULL;
460 TALLOC_FREE(unparsed_name);
461 SAFE_FREE(salt_princ_s);
463 return ret_princ;
466 int create_kerberos_key_from_string(krb5_context context,
467 krb5_principal host_princ,
468 krb5_data *password,
469 krb5_keyblock *key,
470 krb5_enctype enctype,
471 bool no_salt)
473 krb5_principal salt_princ = NULL;
474 int ret;
476 * Check if we've determined that the KDC is salting keys for this
477 * principal/enctype in a non-obvious way. If it is, try to match
478 * its behavior.
480 if (no_salt) {
481 KRB5_KEY_DATA(key) = (KRB5_KEY_DATA_CAST *)SMB_MALLOC(password->length);
482 if (!KRB5_KEY_DATA(key)) {
483 return ENOMEM;
485 memcpy(KRB5_KEY_DATA(key), password->data, password->length);
486 KRB5_KEY_LENGTH(key) = password->length;
487 KRB5_KEY_TYPE(key) = enctype;
488 return 0;
490 salt_princ = kerberos_fetch_salt_princ_for_host_princ(context, host_princ, enctype);
491 ret = smb_krb5_create_key_from_string(context,
492 salt_princ ? salt_princ : host_princ,
493 NULL,
494 password,
495 enctype,
496 key);
497 if (salt_princ) {
498 krb5_free_principal(context, salt_princ);
500 return ret;
503 /************************************************************************
504 Routine to set the salting principal for this service. Active
505 Directory may use a non-obvious principal name to generate the salt
506 when it determines the key to use for encrypting tickets for a service,
507 and hopefully we detected that when we joined the domain.
508 Setting principal to NULL deletes this entry.
509 ************************************************************************/
511 bool kerberos_secrets_store_salting_principal(const char *service,
512 int enctype,
513 const char *principal)
515 char *key = NULL;
516 bool ret = False;
517 krb5_context context = NULL;
518 krb5_principal princ = NULL;
519 char *princ_s = NULL;
520 char *unparsed_name = NULL;
521 krb5_error_code code;
523 if (((code = krb5_init_context(&context)) != 0) || (context == NULL)) {
524 DEBUG(5, ("kerberos_secrets_store_salting_pricipal: kdb5_init_context failed: %s\n",
525 error_message(code)));
526 return False;
528 if (strchr_m(service, '@')) {
529 if (asprintf(&princ_s, "%s", service) == -1) {
530 goto out;
532 } else {
533 if (asprintf(&princ_s, "%s@%s", service, lp_realm()) == -1) {
534 goto out;
538 if (smb_krb5_parse_name(context, princ_s, &princ) != 0) {
539 goto out;
541 if (smb_krb5_unparse_name(talloc_tos(), context, princ, &unparsed_name) != 0) {
542 goto out;
545 if (asprintf(&key, "%s/%s/enctype=%d",
546 SECRETS_SALTING_PRINCIPAL, unparsed_name, enctype)
547 == -1) {
548 goto out;
551 if ((principal != NULL) && (strlen(principal) > 0)) {
552 ret = secrets_store(key, principal, strlen(principal) + 1);
553 } else {
554 ret = secrets_delete(key);
557 out:
559 SAFE_FREE(key);
560 SAFE_FREE(princ_s);
561 TALLOC_FREE(unparsed_name);
563 if (princ) {
564 krb5_free_principal(context, princ);
567 if (context) {
568 krb5_free_context(context);
571 return ret;
575 /************************************************************************
576 ************************************************************************/
578 int kerberos_kinit_password(const char *principal,
579 const char *password,
580 int time_offset,
581 const char *cache_name)
583 return kerberos_kinit_password_ext(principal,
584 password,
585 time_offset,
588 cache_name,
589 False,
590 False,
592 NULL);
595 /************************************************************************
596 ************************************************************************/
598 /************************************************************************
599 Create a string list of available kdc's, possibly searching by sitename.
600 Does DNS queries.
602 If "sitename" is given, the DC's in that site are listed first.
604 ************************************************************************/
606 static void add_sockaddr_unique(struct sockaddr_storage *addrs, int *num_addrs,
607 const struct sockaddr_storage *addr)
609 int i;
611 for (i=0; i<*num_addrs; i++) {
612 if (sockaddr_equal((const struct sockaddr *)&addrs[i],
613 (const struct sockaddr *)addr)) {
614 return;
617 addrs[i] = *addr;
618 *num_addrs += 1;
621 /* print_canonical_sockaddr prints an ipv6 addr in the form of
622 * [ipv6.addr]. This string, when put in a generated krb5.conf file is not
623 * always properly dealt with by some older krb5 libraries. Adding the hard-coded
624 * portnumber workarounds the issue. - gd */
626 static char *print_canonical_sockaddr_with_port(TALLOC_CTX *mem_ctx,
627 const struct sockaddr_storage *pss)
629 char *str = NULL;
631 str = print_canonical_sockaddr(mem_ctx, pss);
632 if (str == NULL) {
633 return NULL;
636 if (pss->ss_family != AF_INET6) {
637 return str;
640 #if defined(HAVE_IPV6)
641 str = talloc_asprintf_append(str, ":88");
642 #endif
643 return str;
646 static char *get_kdc_ip_string(char *mem_ctx,
647 const char *realm,
648 const char *sitename,
649 const struct sockaddr_storage *pss)
651 TALLOC_CTX *frame = talloc_stackframe();
652 int i;
653 struct ip_service *ip_srv_site = NULL;
654 struct ip_service *ip_srv_nonsite = NULL;
655 int count_site = 0;
656 int count_nonsite;
657 int num_dcs;
658 struct sockaddr_storage *dc_addrs;
659 struct tsocket_address **dc_addrs2 = NULL;
660 const struct tsocket_address * const *dc_addrs3 = NULL;
661 char *result = NULL;
662 struct netlogon_samlogon_response **responses = NULL;
663 NTSTATUS status;
664 char *kdc_str = talloc_asprintf(mem_ctx, "%s\t\tkdc = %s\n", "",
665 print_canonical_sockaddr_with_port(mem_ctx, pss));
667 if (kdc_str == NULL) {
668 TALLOC_FREE(frame);
669 return NULL;
673 * First get the KDC's only in this site, the rest will be
674 * appended later
677 if (sitename) {
678 get_kdc_list(realm, sitename, &ip_srv_site, &count_site);
679 DEBUG(10, ("got %d addresses from site %s search\n", count_site,
680 sitename));
683 /* Get all KDC's. */
685 get_kdc_list(realm, NULL, &ip_srv_nonsite, &count_nonsite);
686 DEBUG(10, ("got %d addresses from site-less search\n", count_nonsite));
688 dc_addrs = talloc_array(talloc_tos(), struct sockaddr_storage,
689 count_site + count_nonsite);
690 if (dc_addrs == NULL) {
691 goto out;
694 num_dcs = 0;
696 for (i = 0; i < count_site; i++) {
697 if (!sockaddr_equal(
698 (const struct sockaddr *)pss,
699 (const struct sockaddr *)&ip_srv_site[i].ss)) {
700 add_sockaddr_unique(dc_addrs, &num_dcs,
701 &ip_srv_site[i].ss);
705 for (i = 0; i < count_nonsite; i++) {
706 if (!sockaddr_equal(
707 (const struct sockaddr *)pss,
708 (const struct sockaddr *)&ip_srv_nonsite[i].ss)) {
709 add_sockaddr_unique(dc_addrs, &num_dcs,
710 &ip_srv_nonsite[i].ss);
714 dc_addrs2 = talloc_zero_array(talloc_tos(),
715 struct tsocket_address *,
716 num_dcs);
718 DEBUG(10, ("%d additional KDCs to test\n", num_dcs));
719 if (num_dcs == 0) {
720 goto out;
722 if (dc_addrs2 == NULL) {
723 goto out;
726 for (i=0; i<num_dcs; i++) {
727 char addr[INET6_ADDRSTRLEN];
728 int ret;
730 print_sockaddr(addr, sizeof(addr), &dc_addrs[i]);
732 ret = tsocket_address_inet_from_strings(dc_addrs2, "ip",
733 addr, LDAP_PORT,
734 &dc_addrs2[i]);
735 if (ret != 0) {
736 status = map_nt_error_from_unix(errno);
737 DEBUG(2,("Failed to create tsocket_address for %s - %s\n",
738 addr, nt_errstr(status)));
739 goto out;
743 dc_addrs3 = (const struct tsocket_address * const *)dc_addrs2;
745 status = cldap_multi_netlogon(talloc_tos(),
746 dc_addrs3, num_dcs,
747 realm, lp_netbios_name(),
748 NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX,
749 MIN(num_dcs, 3), timeval_current_ofs(3, 0), &responses);
750 TALLOC_FREE(dc_addrs2);
751 dc_addrs3 = NULL;
753 if (!NT_STATUS_IS_OK(status)) {
754 DEBUG(10,("get_kdc_ip_string: cldap_multi_netlogon failed: "
755 "%s\n", nt_errstr(status)));
756 goto out;
759 for (i=0; i<num_dcs; i++) {
760 char *new_kdc_str;
762 if (responses[i] == NULL) {
763 continue;
766 /* Append to the string - inefficient but not done often. */
767 new_kdc_str = talloc_asprintf(mem_ctx, "%s\t\tkdc = %s\n",
768 kdc_str,
769 print_canonical_sockaddr_with_port(mem_ctx, &dc_addrs[i]));
770 if (new_kdc_str == NULL) {
771 goto out;
773 TALLOC_FREE(kdc_str);
774 kdc_str = new_kdc_str;
777 out:
778 DEBUG(10, ("get_kdc_ip_string: Returning %s\n", kdc_str));
780 result = kdc_str;
781 SAFE_FREE(ip_srv_site);
782 SAFE_FREE(ip_srv_nonsite);
783 TALLOC_FREE(frame);
784 return result;
787 /************************************************************************
788 Create a specific krb5.conf file in the private directory pointing
789 at a specific kdc for a realm. Keyed off domain name. Sets
790 KRB5_CONFIG environment variable to point to this file. Must be
791 run as root or will fail (which is a good thing :-).
792 ************************************************************************/
794 bool create_local_private_krb5_conf_for_domain(const char *realm,
795 const char *domain,
796 const char *sitename,
797 const struct sockaddr_storage *pss)
799 char *dname;
800 char *tmpname = NULL;
801 char *fname = NULL;
802 char *file_contents = NULL;
803 char *kdc_ip_string = NULL;
804 size_t flen = 0;
805 ssize_t ret;
806 int fd;
807 char *realm_upper = NULL;
808 bool result = false;
809 char *aes_enctypes = NULL;
810 mode_t mask;
812 if (!lp_create_krb5_conf()) {
813 return false;
816 if (realm == NULL) {
817 DEBUG(0, ("No realm has been specified! Do you really want to "
818 "join an Active Directory server?\n"));
819 return false;
822 if (domain == NULL || pss == NULL) {
823 return false;
826 dname = lock_path("smb_krb5");
827 if (!dname) {
828 return false;
830 if ((mkdir(dname, 0755)==-1) && (errno != EEXIST)) {
831 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
832 "failed to create directory %s. Error was %s\n",
833 dname, strerror(errno) ));
834 goto done;
837 tmpname = lock_path("smb_tmp_krb5.XXXXXX");
838 if (!tmpname) {
839 goto done;
842 fname = talloc_asprintf(dname, "%s/krb5.conf.%s", dname, domain);
843 if (!fname) {
844 goto done;
847 DEBUG(10,("create_local_private_krb5_conf_for_domain: fname = %s, realm = %s, domain = %s\n",
848 fname, realm, domain ));
850 realm_upper = talloc_strdup(fname, realm);
851 if (!strupper_m(realm_upper)) {
852 goto done;
855 kdc_ip_string = get_kdc_ip_string(dname, realm, sitename, pss);
856 if (!kdc_ip_string) {
857 goto done;
860 aes_enctypes = talloc_strdup(fname, "");
861 if (aes_enctypes == NULL) {
862 goto done;
865 #ifdef HAVE_ENCTYPE_AES256_CTS_HMAC_SHA1_96
866 aes_enctypes = talloc_asprintf_append(aes_enctypes, "%s", "aes256-cts-hmac-sha1-96 ");
867 if (aes_enctypes == NULL) {
868 goto done;
870 #endif
871 #ifdef HAVE_ENCTYPE_AES128_CTS_HMAC_SHA1_96
872 aes_enctypes = talloc_asprintf_append(aes_enctypes, "%s", "aes128-cts-hmac-sha1-96");
873 if (aes_enctypes == NULL) {
874 goto done;
876 #endif
878 file_contents = talloc_asprintf(fname,
879 "[libdefaults]\n\tdefault_realm = %s\n"
880 "\tdefault_tgs_enctypes = %s RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
881 "\tdefault_tkt_enctypes = %s RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
882 "\tpreferred_enctypes = %s RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
883 "\tdns_lookup_realm = false\n\n"
884 "[realms]\n\t%s = {\n"
885 "%s\t}\n",
886 realm_upper, aes_enctypes, aes_enctypes, aes_enctypes,
887 realm_upper, kdc_ip_string);
889 if (!file_contents) {
890 goto done;
893 flen = strlen(file_contents);
895 mask = umask(S_IRWXO | S_IRWXG);
896 fd = mkstemp(tmpname);
897 umask(mask);
898 if (fd == -1) {
899 DEBUG(0,("create_local_private_krb5_conf_for_domain: smb_mkstemp failed,"
900 " for file %s. Errno %s\n",
901 tmpname, strerror(errno) ));
902 goto done;
905 if (fchmod(fd, 0644)==-1) {
906 DEBUG(0,("create_local_private_krb5_conf_for_domain: fchmod failed for %s."
907 " Errno %s\n",
908 tmpname, strerror(errno) ));
909 unlink(tmpname);
910 close(fd);
911 goto done;
914 ret = write(fd, file_contents, flen);
915 if (flen != ret) {
916 DEBUG(0,("create_local_private_krb5_conf_for_domain: write failed,"
917 " returned %d (should be %u). Errno %s\n",
918 (int)ret, (unsigned int)flen, strerror(errno) ));
919 unlink(tmpname);
920 close(fd);
921 goto done;
923 if (close(fd)==-1) {
924 DEBUG(0,("create_local_private_krb5_conf_for_domain: close failed."
925 " Errno %s\n", strerror(errno) ));
926 unlink(tmpname);
927 goto done;
930 if (rename(tmpname, fname) == -1) {
931 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
932 "of %s to %s failed. Errno %s\n",
933 tmpname, fname, strerror(errno) ));
934 unlink(tmpname);
935 goto done;
938 DEBUG(5,("create_local_private_krb5_conf_for_domain: wrote "
939 "file %s with realm %s KDC list = %s\n",
940 fname, realm_upper, kdc_ip_string));
942 /* Set the environment variable to this file. */
943 setenv("KRB5_CONFIG", fname, 1);
945 result = true;
947 #if defined(OVERWRITE_SYSTEM_KRB5_CONF)
949 #define SYSTEM_KRB5_CONF_PATH "/etc/krb5.conf"
950 /* Insanity, sheer insanity..... */
952 if (strequal(realm, lp_realm())) {
953 SMB_STRUCT_STAT sbuf;
955 if (sys_lstat(SYSTEM_KRB5_CONF_PATH, &sbuf, false) == 0) {
956 if (S_ISLNK(sbuf.st_ex_mode) && sbuf.st_ex_size) {
957 int lret;
958 size_t alloc_size = sbuf.st_ex_size + 1;
959 char *linkpath = talloc_array(talloc_tos(), char,
960 alloc_size);
961 if (!linkpath) {
962 goto done;
964 lret = readlink(SYSTEM_KRB5_CONF_PATH, linkpath,
965 alloc_size - 1);
966 if (lret == -1) {
967 TALLOC_FREE(linkpath);
968 goto done;
970 linkpath[lret] = '\0';
972 if (strcmp(linkpath, fname) == 0) {
973 /* Symlink already exists. */
974 TALLOC_FREE(linkpath);
975 goto done;
977 TALLOC_FREE(linkpath);
981 /* Try and replace with a symlink. */
982 if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
983 const char *newpath = SYSTEM_KRB5_CONF_PATH ".saved";
984 if (errno != EEXIST) {
985 DEBUG(0,("create_local_private_krb5_conf_for_domain: symlink "
986 "of %s to %s failed. Errno %s\n",
987 fname, SYSTEM_KRB5_CONF_PATH, strerror(errno) ));
988 goto done; /* Not a fatal error. */
991 /* Yes, this is a race conditon... too bad. */
992 if (rename(SYSTEM_KRB5_CONF_PATH, newpath) == -1) {
993 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
994 "of %s to %s failed. Errno %s\n",
995 SYSTEM_KRB5_CONF_PATH, newpath,
996 strerror(errno) ));
997 goto done; /* Not a fatal error. */
1000 if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
1001 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
1002 "forced symlink of %s to /etc/krb5.conf failed. Errno %s\n",
1003 fname, strerror(errno) ));
1004 goto done; /* Not a fatal error. */
1008 #endif
1010 done:
1011 TALLOC_FREE(tmpname);
1012 TALLOC_FREE(dname);
1014 return result;
1016 #endif