s3-libads: Print a message if no realm has been specified.
[Samba.git] / source3 / libads / kerberos.c
blob1153ccb28856901e7364ad5cbb1863ad4b2e36da
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 "secrets.h"
31 #ifdef HAVE_KRB5
33 #define DEFAULT_KRB5_PORT 88
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 goto out;
223 krb5_get_init_creds_opt_set_address_list(opt, addr->addrs);
226 if ((code = krb5_get_init_creds_password(ctx, &my_creds, me, CONST_DISCARD(char *,password),
227 kerb_prompter, CONST_DISCARD(char *,password),
228 0, NULL, opt))) {
229 goto out;
232 if ((code = krb5_cc_initialize(ctx, cc, me))) {
233 goto out;
236 if ((code = krb5_cc_store_cred(ctx, cc, &my_creds))) {
237 goto out;
240 if (expire_time) {
241 *expire_time = (time_t) my_creds.times.endtime;
244 if (renew_till_time) {
245 *renew_till_time = (time_t) my_creds.times.renew_till;
247 out:
248 if (ntstatus) {
250 NTSTATUS status;
252 /* fast path */
253 if (code == 0) {
254 *ntstatus = NT_STATUS_OK;
255 goto cleanup;
258 /* try to get ntstatus code out of krb5_error when we have it
259 * inside the krb5_get_init_creds_opt - gd */
261 if (opt && smb_krb5_get_ntstatus_from_krb5_error_init_creds_opt(ctx, opt, &status)) {
262 *ntstatus = status;
263 goto cleanup;
266 /* fall back to self-made-mapping */
267 *ntstatus = krb5_to_nt_status(code);
270 cleanup:
271 krb5_free_cred_contents(ctx, &my_creds);
272 if (me) {
273 krb5_free_principal(ctx, me);
275 if (addr) {
276 smb_krb5_free_addresses(ctx, addr);
278 if (opt) {
279 smb_krb5_get_init_creds_opt_free(ctx, opt);
281 if (cc) {
282 krb5_cc_close(ctx, cc);
284 if (ctx) {
285 krb5_free_context(ctx);
287 return code;
290 int ads_kdestroy(const char *cc_name)
292 krb5_error_code code;
293 krb5_context ctx = NULL;
294 krb5_ccache cc = NULL;
296 initialize_krb5_error_table();
297 if ((code = krb5_init_context (&ctx))) {
298 DEBUG(3, ("ads_kdestroy: kdb5_init_context failed: %s\n",
299 error_message(code)));
300 return code;
303 if (!cc_name) {
304 if ((code = krb5_cc_default(ctx, &cc))) {
305 krb5_free_context(ctx);
306 return code;
308 } else {
309 if ((code = krb5_cc_resolve(ctx, cc_name, &cc))) {
310 DEBUG(3, ("ads_kdestroy: krb5_cc_resolve failed: %s\n",
311 error_message(code)));
312 krb5_free_context(ctx);
313 return code;
317 if ((code = krb5_cc_destroy (ctx, cc))) {
318 DEBUG(3, ("ads_kdestroy: krb5_cc_destroy failed: %s\n",
319 error_message(code)));
322 krb5_free_context (ctx);
323 return code;
326 /************************************************************************
327 Routine to fetch the salting principal for a service. Active
328 Directory may use a non-obvious principal name to generate the salt
329 when it determines the key to use for encrypting tickets for a service,
330 and hopefully we detected that when we joined the domain.
331 ************************************************************************/
333 static char *kerberos_secrets_fetch_salting_principal(const char *service, int enctype)
335 char *key = NULL;
336 char *ret = NULL;
338 if (asprintf(&key, "%s/%s/enctype=%d",
339 SECRETS_SALTING_PRINCIPAL, service, enctype) == -1) {
340 return NULL;
342 ret = (char *)secrets_fetch(key, NULL);
343 SAFE_FREE(key);
344 return ret;
347 /************************************************************************
348 Return the standard DES salt key
349 ************************************************************************/
351 char* kerberos_standard_des_salt( void )
353 fstring salt;
355 fstr_sprintf( salt, "host/%s.%s@", global_myname(), lp_realm() );
356 strlower_m( salt );
357 fstrcat( salt, lp_realm() );
359 return SMB_STRDUP( salt );
362 /************************************************************************
363 ************************************************************************/
365 static char* des_salt_key( void )
367 char *key;
369 if (asprintf(&key, "%s/DES/%s", SECRETS_SALTING_PRINCIPAL,
370 lp_realm()) == -1) {
371 return NULL;
374 return key;
377 /************************************************************************
378 ************************************************************************/
380 bool kerberos_secrets_store_des_salt( const char* salt )
382 char* key;
383 bool ret;
385 if ( (key = des_salt_key()) == NULL ) {
386 DEBUG(0,("kerberos_secrets_store_des_salt: failed to generate key!\n"));
387 return False;
390 if ( !salt ) {
391 DEBUG(8,("kerberos_secrets_store_des_salt: deleting salt\n"));
392 secrets_delete( key );
393 return True;
396 DEBUG(3,("kerberos_secrets_store_des_salt: Storing salt \"%s\"\n", salt));
398 ret = secrets_store( key, salt, strlen(salt)+1 );
400 SAFE_FREE( key );
402 return ret;
405 /************************************************************************
406 ************************************************************************/
408 char* kerberos_secrets_fetch_des_salt( void )
410 char *salt, *key;
412 if ( (key = des_salt_key()) == NULL ) {
413 DEBUG(0,("kerberos_secrets_fetch_des_salt: failed to generate key!\n"));
414 return False;
417 salt = (char*)secrets_fetch( key, NULL );
419 SAFE_FREE( key );
421 return salt;
424 /************************************************************************
425 Routine to get the default realm from the kerberos credentials cache.
426 Caller must free if the return value is not NULL.
427 ************************************************************************/
429 char *kerberos_get_default_realm_from_ccache( void )
431 char *realm = NULL;
432 krb5_context ctx = NULL;
433 krb5_ccache cc = NULL;
434 krb5_principal princ = NULL;
436 initialize_krb5_error_table();
437 if (krb5_init_context(&ctx)) {
438 return NULL;
441 DEBUG(5,("kerberos_get_default_realm_from_ccache: "
442 "Trying to read krb5 cache: %s\n",
443 krb5_cc_default_name(ctx)));
444 if (krb5_cc_default(ctx, &cc)) {
445 DEBUG(0,("kerberos_get_default_realm_from_ccache: "
446 "failed to read default cache\n"));
447 goto out;
449 if (krb5_cc_get_principal(ctx, cc, &princ)) {
450 DEBUG(0,("kerberos_get_default_realm_from_ccache: "
451 "failed to get default principal\n"));
452 goto out;
455 #if defined(HAVE_KRB5_PRINCIPAL_GET_REALM)
456 realm = SMB_STRDUP(krb5_principal_get_realm(ctx, princ));
457 #elif defined(HAVE_KRB5_PRINC_REALM)
459 krb5_data *realm_data = krb5_princ_realm(ctx, princ);
460 realm = SMB_STRNDUP(realm_data->data, realm_data->length);
462 #endif
464 out:
466 if (ctx) {
467 if (princ) {
468 krb5_free_principal(ctx, princ);
470 if (cc) {
471 krb5_cc_close(ctx, cc);
473 krb5_free_context(ctx);
476 return realm;
479 /************************************************************************
480 Routine to get the realm from a given DNS name. Returns malloc'ed memory.
481 Caller must free() if the return value is not NULL.
482 ************************************************************************/
484 char *kerberos_get_realm_from_hostname(const char *hostname)
486 #if defined(HAVE_KRB5_GET_HOST_REALM) && defined(HAVE_KRB5_FREE_HOST_REALM)
487 #if defined(HAVE_KRB5_REALM_TYPE)
488 /* Heimdal. */
489 krb5_realm *realm_list = NULL;
490 #else
491 /* MIT */
492 char **realm_list = NULL;
493 #endif
494 char *realm = NULL;
495 krb5_error_code kerr;
496 krb5_context ctx = NULL;
498 initialize_krb5_error_table();
499 if (krb5_init_context(&ctx)) {
500 return NULL;
503 kerr = krb5_get_host_realm(ctx, hostname, &realm_list);
504 if (kerr != 0) {
505 DEBUG(3,("kerberos_get_realm_from_hostname %s: "
506 "failed %s\n",
507 hostname ? hostname : "(NULL)",
508 error_message(kerr) ));
509 goto out;
512 if (realm_list && realm_list[0]) {
513 realm = SMB_STRDUP(realm_list[0]);
516 out:
518 if (ctx) {
519 if (realm_list) {
520 krb5_free_host_realm(ctx, realm_list);
521 realm_list = NULL;
523 krb5_free_context(ctx);
524 ctx = NULL;
526 return realm;
527 #else
528 return NULL;
529 #endif
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 krb5_principal kerberos_fetch_salt_princ_for_host_princ(krb5_context context,
540 krb5_principal host_princ,
541 int enctype)
543 char *unparsed_name = NULL, *salt_princ_s = NULL;
544 krb5_principal ret_princ = NULL;
546 /* lookup new key first */
548 if ( (salt_princ_s = kerberos_secrets_fetch_des_salt()) == NULL ) {
550 /* look under the old key. If this fails, just use the standard key */
552 if (smb_krb5_unparse_name(talloc_tos(), context, host_princ, &unparsed_name) != 0) {
553 return (krb5_principal)NULL;
555 if ((salt_princ_s = kerberos_secrets_fetch_salting_principal(unparsed_name, enctype)) == NULL) {
556 /* fall back to host/machine.realm@REALM */
557 salt_princ_s = kerberos_standard_des_salt();
561 if (smb_krb5_parse_name(context, salt_princ_s, &ret_princ) != 0) {
562 ret_princ = NULL;
565 TALLOC_FREE(unparsed_name);
566 SAFE_FREE(salt_princ_s);
568 return ret_princ;
571 /************************************************************************
572 Routine to set the salting principal for this service. Active
573 Directory may use a non-obvious principal name to generate the salt
574 when it determines the key to use for encrypting tickets for a service,
575 and hopefully we detected that when we joined the domain.
576 Setting principal to NULL deletes this entry.
577 ************************************************************************/
579 bool kerberos_secrets_store_salting_principal(const char *service,
580 int enctype,
581 const char *principal)
583 char *key = NULL;
584 bool ret = False;
585 krb5_context context = NULL;
586 krb5_principal princ = NULL;
587 char *princ_s = NULL;
588 char *unparsed_name = NULL;
589 krb5_error_code code;
591 if (((code = krb5_init_context(&context)) != 0) || (context == NULL)) {
592 DEBUG(5, ("kerberos_secrets_store_salting_pricipal: kdb5_init_context failed: %s\n",
593 error_message(code)));
594 return False;
596 if (strchr_m(service, '@')) {
597 if (asprintf(&princ_s, "%s", service) == -1) {
598 goto out;
600 } else {
601 if (asprintf(&princ_s, "%s@%s", service, lp_realm()) == -1) {
602 goto out;
606 if (smb_krb5_parse_name(context, princ_s, &princ) != 0) {
607 goto out;
609 if (smb_krb5_unparse_name(talloc_tos(), context, princ, &unparsed_name) != 0) {
610 goto out;
613 if (asprintf(&key, "%s/%s/enctype=%d",
614 SECRETS_SALTING_PRINCIPAL, unparsed_name, enctype)
615 == -1) {
616 goto out;
619 if ((principal != NULL) && (strlen(principal) > 0)) {
620 ret = secrets_store(key, principal, strlen(principal) + 1);
621 } else {
622 ret = secrets_delete(key);
625 out:
627 SAFE_FREE(key);
628 SAFE_FREE(princ_s);
629 TALLOC_FREE(unparsed_name);
631 if (princ) {
632 krb5_free_principal(context, princ);
635 if (context) {
636 krb5_free_context(context);
639 return ret;
643 /************************************************************************
644 ************************************************************************/
646 int kerberos_kinit_password(const char *principal,
647 const char *password,
648 int time_offset,
649 const char *cache_name)
651 return kerberos_kinit_password_ext(principal,
652 password,
653 time_offset,
656 cache_name,
657 False,
658 False,
660 NULL);
663 /************************************************************************
664 ************************************************************************/
666 static char *print_kdc_line(char *mem_ctx,
667 const char *prev_line,
668 const struct sockaddr_storage *pss,
669 const char *kdc_name)
671 char *kdc_str = NULL;
673 if (pss->ss_family == AF_INET) {
674 kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
675 prev_line,
676 print_canonical_sockaddr(mem_ctx, pss));
677 } else {
678 char addr[INET6_ADDRSTRLEN];
679 uint16_t port = get_sockaddr_port(pss);
681 DEBUG(10,("print_kdc_line: IPv6 case for kdc_name: %s, port: %d\n",
682 kdc_name, port));
684 if (port != 0 && port != DEFAULT_KRB5_PORT) {
685 /* Currently for IPv6 we can't specify a non-default
686 krb5 port with an address, as this requires a ':'.
687 Resolve to a name. */
688 char hostname[MAX_DNS_NAME_LENGTH];
689 int ret = sys_getnameinfo((const struct sockaddr *)pss,
690 sizeof(*pss),
691 hostname, sizeof(hostname),
692 NULL, 0,
693 NI_NAMEREQD);
694 if (ret) {
695 DEBUG(0,("print_kdc_line: can't resolve name "
696 "for kdc with non-default port %s. "
697 "Error %s\n.",
698 print_canonical_sockaddr(mem_ctx, pss),
699 gai_strerror(ret)));
700 return NULL;
702 /* Success, use host:port */
703 kdc_str = talloc_asprintf(mem_ctx,
704 "%s\tkdc = %s:%u\n",
705 prev_line,
706 hostname,
707 (unsigned int)port);
708 } else {
710 /* no krb5 lib currently supports "kdc = ipv6 address"
711 * at all, so just fill in just the kdc_name if we have
712 * it and let the krb5 lib figure out the appropriate
713 * ipv6 address - gd */
715 if (kdc_name) {
716 kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
717 prev_line, kdc_name);
718 } else {
719 kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
720 prev_line,
721 print_sockaddr(addr,
722 sizeof(addr),
723 pss));
727 return kdc_str;
730 /************************************************************************
731 Create a string list of available kdc's, possibly searching by sitename.
732 Does DNS queries.
734 If "sitename" is given, the DC's in that site are listed first.
736 ************************************************************************/
738 static char *get_kdc_ip_string(char *mem_ctx,
739 const char *realm,
740 const char *sitename,
741 struct sockaddr_storage *pss,
742 const char *kdc_name)
744 int i;
745 struct ip_service *ip_srv_site = NULL;
746 struct ip_service *ip_srv_nonsite = NULL;
747 int count_site = 0;
748 int count_nonsite;
749 char *kdc_str = print_kdc_line(mem_ctx, "", pss, kdc_name);
751 if (kdc_str == NULL) {
752 return NULL;
756 * First get the KDC's only in this site, the rest will be
757 * appended later
760 if (sitename) {
762 get_kdc_list(realm, sitename, &ip_srv_site, &count_site);
764 for (i = 0; i < count_site; i++) {
765 if (sockaddr_equal((struct sockaddr *)&ip_srv_site[i].ss,
766 (struct sockaddr *)pss)) {
767 continue;
769 /* Append to the string - inefficient
770 * but not done often. */
771 kdc_str = print_kdc_line(mem_ctx,
772 kdc_str,
773 &ip_srv_site[i].ss,
774 NULL);
775 if (!kdc_str) {
776 SAFE_FREE(ip_srv_site);
777 return NULL;
782 /* Get all KDC's. */
784 get_kdc_list(realm, NULL, &ip_srv_nonsite, &count_nonsite);
786 for (i = 0; i < count_nonsite; i++) {
787 int j;
789 if (sockaddr_equal((struct sockaddr *)&ip_srv_nonsite[i].ss, (struct sockaddr *)pss)) {
790 continue;
793 /* Ensure this isn't an IP already seen (YUK! this is n*n....) */
794 for (j = 0; j < count_site; j++) {
795 if (sockaddr_equal((struct sockaddr *)&ip_srv_nonsite[i].ss,
796 (struct sockaddr *)&ip_srv_site[j].ss)) {
797 break;
799 /* As the lists are sorted we can break early if nonsite > site. */
800 if (ip_service_compare(&ip_srv_nonsite[i], &ip_srv_site[j]) > 0) {
801 break;
804 if (j != i) {
805 continue;
808 /* Append to the string - inefficient but not done often. */
809 kdc_str = print_kdc_line(mem_ctx,
810 kdc_str,
811 &ip_srv_nonsite[i].ss,
812 NULL);
813 if (!kdc_str) {
814 SAFE_FREE(ip_srv_site);
815 SAFE_FREE(ip_srv_nonsite);
816 return NULL;
821 SAFE_FREE(ip_srv_site);
822 SAFE_FREE(ip_srv_nonsite);
824 DEBUG(10,("get_kdc_ip_string: Returning %s\n",
825 kdc_str ));
827 return kdc_str;
830 /************************************************************************
831 Create a specific krb5.conf file in the private directory pointing
832 at a specific kdc for a realm. Keyed off domain name. Sets
833 KRB5_CONFIG environment variable to point to this file. Must be
834 run as root or will fail (which is a good thing :-).
835 ************************************************************************/
837 bool create_local_private_krb5_conf_for_domain(const char *realm,
838 const char *domain,
839 const char *sitename,
840 struct sockaddr_storage *pss,
841 const char *kdc_name)
843 char *dname;
844 char *tmpname = NULL;
845 char *fname = NULL;
846 char *file_contents = NULL;
847 char *kdc_ip_string = NULL;
848 size_t flen = 0;
849 ssize_t ret;
850 int fd;
851 char *realm_upper = NULL;
852 bool result = false;
853 char *aes_enctypes = NULL;
855 if (!lp_create_krb5_conf()) {
856 return false;
859 if (realm == NULL) {
860 DEBUG(0, ("No realm has been specified! Do you really want to "
861 "join an Active Directory server?\n"));
862 return false;
865 if (domain == NULL || pss == NULL || kdc_name == NULL) {
866 return false;
869 dname = lock_path("smb_krb5");
870 if (!dname) {
871 return false;
873 if ((mkdir(dname, 0755)==-1) && (errno != EEXIST)) {
874 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
875 "failed to create directory %s. Error was %s\n",
876 dname, strerror(errno) ));
877 goto done;
880 tmpname = lock_path("smb_tmp_krb5.XXXXXX");
881 if (!tmpname) {
882 goto done;
885 fname = talloc_asprintf(dname, "%s/krb5.conf.%s", dname, domain);
886 if (!fname) {
887 goto done;
890 DEBUG(10,("create_local_private_krb5_conf_for_domain: fname = %s, realm = %s, domain = %s\n",
891 fname, realm, domain ));
893 realm_upper = talloc_strdup(fname, realm);
894 strupper_m(realm_upper);
896 kdc_ip_string = get_kdc_ip_string(dname, realm, sitename, pss, kdc_name);
897 if (!kdc_ip_string) {
898 goto done;
901 aes_enctypes = talloc_strdup(fname, "");
902 if (aes_enctypes == NULL) {
903 goto done;
906 #ifdef HAVE_ENCTYPE_AES256_CTS_HMAC_SHA1_96
907 aes_enctypes = talloc_asprintf_append(aes_enctypes, "%s", "aes256-cts-hmac-sha1-96 ");
908 if (aes_enctypes == NULL) {
909 goto done;
911 #endif
912 #ifdef HAVE_ENCTYPE_AES128_CTS_HMAC_SHA1_96
913 aes_enctypes = talloc_asprintf_append(aes_enctypes, "%s", "aes128-cts-hmac-sha1-96");
914 if (aes_enctypes == NULL) {
915 goto done;
917 #endif
919 file_contents = talloc_asprintf(fname,
920 "[libdefaults]\n\tdefault_realm = %s\n"
921 "\tdefault_tgs_enctypes = %s RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
922 "\tdefault_tkt_enctypes = %s RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
923 "\tpreferred_enctypes = %s RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n\n"
924 "[realms]\n\t%s = {\n"
925 "\t%s\t}\n",
926 realm_upper, aes_enctypes, aes_enctypes, aes_enctypes,
927 realm_upper, kdc_ip_string);
929 if (!file_contents) {
930 goto done;
933 flen = strlen(file_contents);
935 fd = mkstemp(tmpname);
936 if (fd == -1) {
937 DEBUG(0,("create_local_private_krb5_conf_for_domain: smb_mkstemp failed,"
938 " for file %s. Errno %s\n",
939 tmpname, strerror(errno) ));
940 goto done;
943 if (fchmod(fd, 0644)==-1) {
944 DEBUG(0,("create_local_private_krb5_conf_for_domain: fchmod failed for %s."
945 " Errno %s\n",
946 tmpname, strerror(errno) ));
947 unlink(tmpname);
948 close(fd);
949 goto done;
952 ret = write(fd, file_contents, flen);
953 if (flen != ret) {
954 DEBUG(0,("create_local_private_krb5_conf_for_domain: write failed,"
955 " returned %d (should be %u). Errno %s\n",
956 (int)ret, (unsigned int)flen, strerror(errno) ));
957 unlink(tmpname);
958 close(fd);
959 goto done;
961 if (close(fd)==-1) {
962 DEBUG(0,("create_local_private_krb5_conf_for_domain: close failed."
963 " Errno %s\n", strerror(errno) ));
964 unlink(tmpname);
965 goto done;
968 if (rename(tmpname, fname) == -1) {
969 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
970 "of %s to %s failed. Errno %s\n",
971 tmpname, fname, strerror(errno) ));
972 unlink(tmpname);
973 goto done;
976 DEBUG(5,("create_local_private_krb5_conf_for_domain: wrote "
977 "file %s with realm %s KDC list = %s\n",
978 fname, realm_upper, kdc_ip_string));
980 /* Set the environment variable to this file. */
981 setenv("KRB5_CONFIG", fname, 1);
983 result = true;
985 #if defined(OVERWRITE_SYSTEM_KRB5_CONF)
987 #define SYSTEM_KRB5_CONF_PATH "/etc/krb5.conf"
988 /* Insanity, sheer insanity..... */
990 if (strequal(realm, lp_realm())) {
991 char linkpath[PATH_MAX+1];
992 int lret;
994 lret = readlink(SYSTEM_KRB5_CONF_PATH, linkpath, sizeof(linkpath)-1);
995 if (lret != -1) {
996 linkpath[lret] = '\0';
999 if (lret != -1 || strcmp(linkpath, fname) == 0) {
1000 /* Symlink already exists. */
1001 goto done;
1004 /* Try and replace with a symlink. */
1005 if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
1006 const char *newpath = SYSTEM_KRB5_CONF_PATH ## ".saved";
1007 if (errno != EEXIST) {
1008 DEBUG(0,("create_local_private_krb5_conf_for_domain: symlink "
1009 "of %s to %s failed. Errno %s\n",
1010 fname, SYSTEM_KRB5_CONF_PATH, strerror(errno) ));
1011 goto done; /* Not a fatal error. */
1014 /* Yes, this is a race conditon... too bad. */
1015 if (rename(SYSTEM_KRB5_CONF_PATH, newpath) == -1) {
1016 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
1017 "of %s to %s failed. Errno %s\n",
1018 SYSTEM_KRB5_CONF_PATH, newpath,
1019 strerror(errno) ));
1020 goto done; /* Not a fatal error. */
1023 if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
1024 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
1025 "forced symlink of %s to /etc/krb5.conf failed. Errno %s\n",
1026 fname, strerror(errno) ));
1027 goto done; /* Not a fatal error. */
1031 #endif
1033 done:
1034 TALLOC_FREE(tmpname);
1035 TALLOC_FREE(dname);
1037 return result;
1039 #endif