s3: Initialize aio_pending_size from aio_pthread
[Samba/gebeck_regimport.git] / source3 / libads / kerberos.c
bloba43c7b167c2a56a1374afaddb6c4fc339c4567cd
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 DEFAULT_KRB5_PORT 88
37 #define LIBADS_CCACHE_NAME "MEMORY:libads"
40 we use a prompter to avoid a crash bug in the kerberos libs when
41 dealing with empty passwords
42 this prompter is just a string copy ...
44 static krb5_error_code
45 kerb_prompter(krb5_context ctx, void *data,
46 const char *name,
47 const char *banner,
48 int num_prompts,
49 krb5_prompt prompts[])
51 if (num_prompts == 0) return 0;
53 memset(prompts[0].reply->data, '\0', prompts[0].reply->length);
54 if (prompts[0].reply->length > 0) {
55 if (data) {
56 strncpy((char *)prompts[0].reply->data, (const char *)data,
57 prompts[0].reply->length-1);
58 prompts[0].reply->length = strlen((const char *)prompts[0].reply->data);
59 } else {
60 prompts[0].reply->length = 0;
63 return 0;
66 static bool smb_krb5_get_ntstatus_from_krb5_error(krb5_error *error,
67 NTSTATUS *nt_status)
69 DATA_BLOB edata;
70 DATA_BLOB unwrapped_edata;
71 TALLOC_CTX *mem_ctx;
72 struct KRB5_EDATA_NTSTATUS parsed_edata;
73 enum ndr_err_code ndr_err;
75 #ifdef HAVE_E_DATA_POINTER_IN_KRB5_ERROR
76 edata = data_blob(error->e_data->data, error->e_data->length);
77 #else
78 edata = data_blob(error->e_data.data, error->e_data.length);
79 #endif /* HAVE_E_DATA_POINTER_IN_KRB5_ERROR */
81 #ifdef DEVELOPER
82 dump_data(10, edata.data, edata.length);
83 #endif /* DEVELOPER */
85 mem_ctx = talloc_init("smb_krb5_get_ntstatus_from_krb5_error");
86 if (mem_ctx == NULL) {
87 data_blob_free(&edata);
88 return False;
91 if (!unwrap_edata_ntstatus(mem_ctx, &edata, &unwrapped_edata)) {
92 data_blob_free(&edata);
93 TALLOC_FREE(mem_ctx);
94 return False;
97 data_blob_free(&edata);
99 ndr_err = ndr_pull_struct_blob_all(&unwrapped_edata, mem_ctx,
100 &parsed_edata, (ndr_pull_flags_fn_t)ndr_pull_KRB5_EDATA_NTSTATUS);
101 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
102 data_blob_free(&unwrapped_edata);
103 TALLOC_FREE(mem_ctx);
104 return False;
107 data_blob_free(&unwrapped_edata);
109 if (nt_status) {
110 *nt_status = parsed_edata.ntstatus;
113 TALLOC_FREE(mem_ctx);
115 return True;
118 static bool smb_krb5_get_ntstatus_from_krb5_error_init_creds_opt(krb5_context ctx,
119 krb5_get_init_creds_opt *opt,
120 NTSTATUS *nt_status)
122 bool ret = False;
123 krb5_error *error = NULL;
125 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_GET_ERROR
126 ret = krb5_get_init_creds_opt_get_error(ctx, opt, &error);
127 if (ret) {
128 DEBUG(1,("krb5_get_init_creds_opt_get_error gave: %s\n",
129 error_message(ret)));
130 return False;
132 #endif /* HAVE_KRB5_GET_INIT_CREDS_OPT_GET_ERROR */
134 if (!error) {
135 DEBUG(1,("no krb5_error\n"));
136 return False;
139 #ifdef HAVE_E_DATA_POINTER_IN_KRB5_ERROR
140 if (!error->e_data) {
141 #else
142 if (error->e_data.data == NULL) {
143 #endif /* HAVE_E_DATA_POINTER_IN_KRB5_ERROR */
144 DEBUG(1,("no edata in krb5_error\n"));
145 krb5_free_error(ctx, error);
146 return False;
149 ret = smb_krb5_get_ntstatus_from_krb5_error(error, nt_status);
151 krb5_free_error(ctx, error);
153 return ret;
157 simulate a kinit, putting the tgt in the given cache location. If cache_name == NULL
158 place in default cache location.
159 remus@snapserver.com
161 int kerberos_kinit_password_ext(const char *principal,
162 const char *password,
163 int time_offset,
164 time_t *expire_time,
165 time_t *renew_till_time,
166 const char *cache_name,
167 bool request_pac,
168 bool add_netbios_addr,
169 time_t renewable_time,
170 NTSTATUS *ntstatus)
172 krb5_context ctx = NULL;
173 krb5_error_code code = 0;
174 krb5_ccache cc = NULL;
175 krb5_principal me = NULL;
176 krb5_creds my_creds;
177 krb5_get_init_creds_opt *opt = NULL;
178 smb_krb5_addresses *addr = NULL;
180 ZERO_STRUCT(my_creds);
182 initialize_krb5_error_table();
183 if ((code = krb5_init_context(&ctx)))
184 goto out;
186 if (time_offset != 0) {
187 krb5_set_real_time(ctx, time(NULL) + time_offset, 0);
190 DEBUG(10,("kerberos_kinit_password: as %s using [%s] as ccache and config [%s]\n",
191 principal,
192 cache_name ? cache_name: krb5_cc_default_name(ctx),
193 getenv("KRB5_CONFIG")));
195 if ((code = krb5_cc_resolve(ctx, cache_name ? cache_name : krb5_cc_default_name(ctx), &cc))) {
196 goto out;
199 if ((code = smb_krb5_parse_name(ctx, principal, &me))) {
200 goto out;
203 if ((code = smb_krb5_get_init_creds_opt_alloc(ctx, &opt))) {
204 goto out;
207 krb5_get_init_creds_opt_set_renew_life(opt, renewable_time);
208 krb5_get_init_creds_opt_set_forwardable(opt, True);
209 #if 0
210 /* insane testing */
211 krb5_get_init_creds_opt_set_tkt_life(opt, 60);
212 #endif
214 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PAC_REQUEST
215 if (request_pac) {
216 if ((code = krb5_get_init_creds_opt_set_pac_request(ctx, opt, (krb5_boolean)request_pac))) {
217 goto out;
220 #endif
221 if (add_netbios_addr) {
222 if ((code = smb_krb5_gen_netbios_krb5_address(&addr))) {
223 goto out;
225 krb5_get_init_creds_opt_set_address_list(opt, addr->addrs);
228 if ((code = krb5_get_init_creds_password(ctx, &my_creds, me, discard_const_p(char,password),
229 kerb_prompter, discard_const_p(char, password),
230 0, NULL, opt))) {
231 goto out;
234 if ((code = krb5_cc_initialize(ctx, cc, me))) {
235 goto out;
238 if ((code = krb5_cc_store_cred(ctx, cc, &my_creds))) {
239 goto out;
242 if (expire_time) {
243 *expire_time = (time_t) my_creds.times.endtime;
246 if (renew_till_time) {
247 *renew_till_time = (time_t) my_creds.times.renew_till;
249 out:
250 if (ntstatus) {
252 NTSTATUS status;
254 /* fast path */
255 if (code == 0) {
256 *ntstatus = NT_STATUS_OK;
257 goto cleanup;
260 /* try to get ntstatus code out of krb5_error when we have it
261 * inside the krb5_get_init_creds_opt - gd */
263 if (opt && smb_krb5_get_ntstatus_from_krb5_error_init_creds_opt(ctx, opt, &status)) {
264 *ntstatus = status;
265 goto cleanup;
268 /* fall back to self-made-mapping */
269 *ntstatus = krb5_to_nt_status(code);
272 cleanup:
273 krb5_free_cred_contents(ctx, &my_creds);
274 if (me) {
275 krb5_free_principal(ctx, me);
277 if (addr) {
278 smb_krb5_free_addresses(ctx, addr);
280 if (opt) {
281 smb_krb5_get_init_creds_opt_free(ctx, opt);
283 if (cc) {
284 krb5_cc_close(ctx, cc);
286 if (ctx) {
287 krb5_free_context(ctx);
289 return code;
292 int ads_kdestroy(const char *cc_name)
294 krb5_error_code code;
295 krb5_context ctx = NULL;
296 krb5_ccache cc = NULL;
298 initialize_krb5_error_table();
299 if ((code = krb5_init_context (&ctx))) {
300 DEBUG(3, ("ads_kdestroy: kdb5_init_context failed: %s\n",
301 error_message(code)));
302 return code;
305 if (!cc_name) {
306 if ((code = krb5_cc_default(ctx, &cc))) {
307 krb5_free_context(ctx);
308 return code;
310 } else {
311 if ((code = krb5_cc_resolve(ctx, cc_name, &cc))) {
312 DEBUG(3, ("ads_kdestroy: krb5_cc_resolve failed: %s\n",
313 error_message(code)));
314 krb5_free_context(ctx);
315 return code;
319 if ((code = krb5_cc_destroy (ctx, cc))) {
320 DEBUG(3, ("ads_kdestroy: krb5_cc_destroy failed: %s\n",
321 error_message(code)));
324 krb5_free_context (ctx);
325 return code;
328 /************************************************************************
329 Routine to fetch the salting principal for a service. Active
330 Directory may use a non-obvious principal name to generate the salt
331 when it determines the key to use for encrypting tickets for a service,
332 and hopefully we detected that when we joined the domain.
333 ************************************************************************/
335 static char *kerberos_secrets_fetch_salting_principal(const char *service, int enctype)
337 char *key = NULL;
338 char *ret = NULL;
340 if (asprintf(&key, "%s/%s/enctype=%d",
341 SECRETS_SALTING_PRINCIPAL, service, enctype) == -1) {
342 return NULL;
344 ret = (char *)secrets_fetch(key, NULL);
345 SAFE_FREE(key);
346 return ret;
349 /************************************************************************
350 Return the standard DES salt key
351 ************************************************************************/
353 char* kerberos_standard_des_salt( void )
355 fstring salt;
357 fstr_sprintf( salt, "host/%s.%s@", lp_netbios_name(), lp_realm() );
358 strlower_m( salt );
359 fstrcat( salt, lp_realm() );
361 return SMB_STRDUP( salt );
364 /************************************************************************
365 ************************************************************************/
367 static char* des_salt_key( void )
369 char *key;
371 if (asprintf(&key, "%s/DES/%s", SECRETS_SALTING_PRINCIPAL,
372 lp_realm()) == -1) {
373 return NULL;
376 return key;
379 /************************************************************************
380 ************************************************************************/
382 bool kerberos_secrets_store_des_salt( const char* salt )
384 char* key;
385 bool ret;
387 if ( (key = des_salt_key()) == NULL ) {
388 DEBUG(0,("kerberos_secrets_store_des_salt: failed to generate key!\n"));
389 return False;
392 if ( !salt ) {
393 DEBUG(8,("kerberos_secrets_store_des_salt: deleting salt\n"));
394 secrets_delete( key );
395 return True;
398 DEBUG(3,("kerberos_secrets_store_des_salt: Storing salt \"%s\"\n", salt));
400 ret = secrets_store( key, salt, strlen(salt)+1 );
402 SAFE_FREE( key );
404 return ret;
407 /************************************************************************
408 ************************************************************************/
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 default realm from the kerberos credentials cache.
428 Caller must free if the return value is not NULL.
429 ************************************************************************/
431 char *kerberos_get_default_realm_from_ccache(TALLOC_CTX *mem_ctx)
433 char *realm = NULL;
434 krb5_context ctx = NULL;
435 krb5_ccache cc = NULL;
436 krb5_principal princ = NULL;
438 initialize_krb5_error_table();
439 if (krb5_init_context(&ctx)) {
440 return NULL;
443 DEBUG(5,("kerberos_get_default_realm_from_ccache: "
444 "Trying to read krb5 cache: %s\n",
445 krb5_cc_default_name(ctx)));
446 if (krb5_cc_default(ctx, &cc)) {
447 DEBUG(0,("kerberos_get_default_realm_from_ccache: "
448 "failed to read default cache\n"));
449 goto out;
451 if (krb5_cc_get_principal(ctx, cc, &princ)) {
452 DEBUG(0,("kerberos_get_default_realm_from_ccache: "
453 "failed to get default principal\n"));
454 goto out;
457 #if defined(HAVE_KRB5_PRINCIPAL_GET_REALM)
458 realm = talloc_strdup(mem_ctx, krb5_principal_get_realm(ctx, princ));
459 #elif defined(HAVE_KRB5_PRINC_REALM)
461 krb5_data *realm_data = krb5_princ_realm(ctx, princ);
462 realm = talloc_strndup(mem_ctx, realm_data->data, realm_data->length);
464 #endif
466 out:
468 if (ctx) {
469 if (princ) {
470 krb5_free_principal(ctx, princ);
472 if (cc) {
473 krb5_cc_close(ctx, cc);
475 krb5_free_context(ctx);
478 return realm;
481 /************************************************************************
482 Routine to get the realm from a given DNS name.
483 ************************************************************************/
485 char *kerberos_get_realm_from_hostname(TALLOC_CTX *mem_ctx, const char *hostname)
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 = talloc_strdup(mem_ctx, 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;
529 char *kerberos_get_principal_from_service_hostname(TALLOC_CTX *mem_ctx,
530 const char *service,
531 const char *remote_name)
533 char *realm = NULL;
534 char *host = NULL;
535 char *principal;
536 host = strchr_m(remote_name, '.');
537 if (host) {
538 /* DNS name. */
539 realm = kerberos_get_realm_from_hostname(talloc_tos(), remote_name);
540 } else {
541 /* NetBIOS name - use our realm. */
542 realm = kerberos_get_default_realm_from_ccache(talloc_tos());
545 if (realm == NULL || *realm == '\0') {
546 realm = talloc_strdup(talloc_tos(), lp_realm());
547 if (!realm) {
548 return NULL;
550 DEBUG(3,("kerberos_get_principal_from_service_hostname: "
551 "cannot get realm from, "
552 "desthost %s or default ccache. Using default "
553 "smb.conf realm %s\n",
554 remote_name,
555 realm));
558 principal = talloc_asprintf(mem_ctx,
559 "%s/%s@%s",
560 service, remote_name,
561 realm);
562 TALLOC_FREE(realm);
563 return principal;
566 /************************************************************************
567 Routine to get the salting principal for this service. This is
568 maintained for backwards compatibilty with releases prior to 3.0.24.
569 Since we store the salting principal string only at join, we may have
570 to look for the older tdb keys. Caller must free if return is not null.
571 ************************************************************************/
573 krb5_principal kerberos_fetch_salt_princ_for_host_princ(krb5_context context,
574 krb5_principal host_princ,
575 int enctype)
577 char *unparsed_name = NULL, *salt_princ_s = NULL;
578 krb5_principal ret_princ = NULL;
580 /* lookup new key first */
582 if ( (salt_princ_s = kerberos_secrets_fetch_des_salt()) == NULL ) {
584 /* look under the old key. If this fails, just use the standard key */
586 if (smb_krb5_unparse_name(talloc_tos(), context, host_princ, &unparsed_name) != 0) {
587 return (krb5_principal)NULL;
589 if ((salt_princ_s = kerberos_secrets_fetch_salting_principal(unparsed_name, enctype)) == NULL) {
590 /* fall back to host/machine.realm@REALM */
591 salt_princ_s = kerberos_standard_des_salt();
595 if (smb_krb5_parse_name(context, salt_princ_s, &ret_princ) != 0) {
596 ret_princ = NULL;
599 TALLOC_FREE(unparsed_name);
600 SAFE_FREE(salt_princ_s);
602 return ret_princ;
605 /************************************************************************
606 Routine to set the salting principal for this service. Active
607 Directory may use a non-obvious principal name to generate the salt
608 when it determines the key to use for encrypting tickets for a service,
609 and hopefully we detected that when we joined the domain.
610 Setting principal to NULL deletes this entry.
611 ************************************************************************/
613 bool kerberos_secrets_store_salting_principal(const char *service,
614 int enctype,
615 const char *principal)
617 char *key = NULL;
618 bool ret = False;
619 krb5_context context = NULL;
620 krb5_principal princ = NULL;
621 char *princ_s = NULL;
622 char *unparsed_name = NULL;
623 krb5_error_code code;
625 if (((code = krb5_init_context(&context)) != 0) || (context == NULL)) {
626 DEBUG(5, ("kerberos_secrets_store_salting_pricipal: kdb5_init_context failed: %s\n",
627 error_message(code)));
628 return False;
630 if (strchr_m(service, '@')) {
631 if (asprintf(&princ_s, "%s", service) == -1) {
632 goto out;
634 } else {
635 if (asprintf(&princ_s, "%s@%s", service, lp_realm()) == -1) {
636 goto out;
640 if (smb_krb5_parse_name(context, princ_s, &princ) != 0) {
641 goto out;
643 if (smb_krb5_unparse_name(talloc_tos(), context, princ, &unparsed_name) != 0) {
644 goto out;
647 if (asprintf(&key, "%s/%s/enctype=%d",
648 SECRETS_SALTING_PRINCIPAL, unparsed_name, enctype)
649 == -1) {
650 goto out;
653 if ((principal != NULL) && (strlen(principal) > 0)) {
654 ret = secrets_store(key, principal, strlen(principal) + 1);
655 } else {
656 ret = secrets_delete(key);
659 out:
661 SAFE_FREE(key);
662 SAFE_FREE(princ_s);
663 TALLOC_FREE(unparsed_name);
665 if (princ) {
666 krb5_free_principal(context, princ);
669 if (context) {
670 krb5_free_context(context);
673 return ret;
677 /************************************************************************
678 ************************************************************************/
680 int kerberos_kinit_password(const char *principal,
681 const char *password,
682 int time_offset,
683 const char *cache_name)
685 return kerberos_kinit_password_ext(principal,
686 password,
687 time_offset,
690 cache_name,
691 False,
692 False,
694 NULL);
697 /************************************************************************
698 ************************************************************************/
700 static char *print_kdc_line(char *mem_ctx,
701 const char *prev_line,
702 const struct sockaddr_storage *pss,
703 const char *kdc_name)
705 char addr[INET6_ADDRSTRLEN];
706 uint16_t port = get_sockaddr_port(pss);
708 if (pss->ss_family == AF_INET) {
709 return talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
710 prev_line,
711 print_canonical_sockaddr(mem_ctx, pss));
715 * IPv6 starts here
718 DEBUG(10, ("print_kdc_line: IPv6 case for kdc_name: %s, port: %d\n",
719 kdc_name, port));
721 if (port != 0 && port != DEFAULT_KRB5_PORT) {
722 /* Currently for IPv6 we can't specify a non-default
723 krb5 port with an address, as this requires a ':'.
724 Resolve to a name. */
725 char hostname[MAX_DNS_NAME_LENGTH];
726 int ret = sys_getnameinfo((const struct sockaddr *)pss,
727 sizeof(*pss),
728 hostname, sizeof(hostname),
729 NULL, 0,
730 NI_NAMEREQD);
731 if (ret) {
732 DEBUG(0,("print_kdc_line: can't resolve name "
733 "for kdc with non-default port %s. "
734 "Error %s\n.",
735 print_canonical_sockaddr(mem_ctx, pss),
736 gai_strerror(ret)));
737 return NULL;
739 /* Success, use host:port */
740 return talloc_asprintf(mem_ctx,
741 "%s\tkdc = %s:%u\n",
742 prev_line,
743 hostname,
744 (unsigned int)port);
747 /* no krb5 lib currently supports "kdc = ipv6 address"
748 * at all, so just fill in just the kdc_name if we have
749 * it and let the krb5 lib figure out the appropriate
750 * ipv6 address - gd */
752 if (kdc_name) {
753 return talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
754 prev_line, kdc_name);
757 return talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
758 prev_line,
759 print_sockaddr(addr,
760 sizeof(addr),
761 pss));
764 /************************************************************************
765 Create a string list of available kdc's, possibly searching by sitename.
766 Does DNS queries.
768 If "sitename" is given, the DC's in that site are listed first.
770 ************************************************************************/
772 static void add_sockaddr_unique(struct sockaddr_storage *addrs, int *num_addrs,
773 const struct sockaddr_storage *addr)
775 int i;
777 for (i=0; i<*num_addrs; i++) {
778 if (sockaddr_equal((const struct sockaddr *)&addrs[i],
779 (const struct sockaddr *)addr)) {
780 return;
783 addrs[i] = *addr;
784 *num_addrs += 1;
787 static char *get_kdc_ip_string(char *mem_ctx,
788 const char *realm,
789 const char *sitename,
790 const struct sockaddr_storage *pss,
791 const char *kdc_name)
793 TALLOC_CTX *frame = talloc_stackframe();
794 int i;
795 struct ip_service *ip_srv_site = NULL;
796 struct ip_service *ip_srv_nonsite = NULL;
797 int count_site = 0;
798 int count_nonsite;
799 int num_dcs;
800 struct sockaddr_storage *dc_addrs;
801 struct tsocket_address **dc_addrs2 = NULL;
802 const struct tsocket_address * const *dc_addrs3 = NULL;
803 char *result = NULL;
804 struct netlogon_samlogon_response **responses = NULL;
805 NTSTATUS status;
806 char *kdc_str = print_kdc_line(mem_ctx, "", pss, kdc_name);
808 if (kdc_str == NULL) {
809 return NULL;
813 * First get the KDC's only in this site, the rest will be
814 * appended later
817 if (sitename) {
818 get_kdc_list(realm, sitename, &ip_srv_site, &count_site);
821 /* Get all KDC's. */
823 get_kdc_list(realm, NULL, &ip_srv_nonsite, &count_nonsite);
825 dc_addrs = talloc_array(talloc_tos(), struct sockaddr_storage,
826 1 + count_site + count_nonsite);
827 if (dc_addrs == NULL) {
828 goto fail;
831 dc_addrs[0] = *pss;
832 num_dcs = 1;
834 for (i=0; i<count_site; i++) {
835 add_sockaddr_unique(dc_addrs, &num_dcs, &ip_srv_site[i].ss);
838 for (i=0; i<count_nonsite; i++) {
839 add_sockaddr_unique(dc_addrs, &num_dcs, &ip_srv_nonsite[i].ss);
842 dc_addrs2 = talloc_zero_array(talloc_tos(),
843 struct tsocket_address *,
844 num_dcs);
845 if (dc_addrs2 == NULL) {
846 goto fail;
849 for (i=0; i<num_dcs; i++) {
850 char addr[INET6_ADDRSTRLEN];
851 int ret;
853 print_sockaddr(addr, sizeof(addr), &dc_addrs[i]);
855 ret = tsocket_address_inet_from_strings(dc_addrs2, "ip",
856 addr, LDAP_PORT,
857 &dc_addrs2[i]);
858 if (ret != 0) {
859 status = map_nt_error_from_unix(errno);
860 DEBUG(2,("Failed to create tsocket_address for %s - %s\n",
861 addr, nt_errstr(status)));
862 goto fail;
866 dc_addrs3 = (const struct tsocket_address * const *)dc_addrs2;
868 status = cldap_multi_netlogon(talloc_tos(),
869 dc_addrs3, num_dcs,
870 realm, lp_netbios_name(),
871 NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX,
872 MIN(num_dcs, 3), timeval_current_ofs(3, 0), &responses);
873 TALLOC_FREE(dc_addrs2);
874 dc_addrs3 = NULL;
876 if (!NT_STATUS_IS_OK(status)) {
877 DEBUG(10,("get_kdc_ip_string: cldap_multi_netlogon failed: "
878 "%s\n", nt_errstr(status)));
879 goto fail;
882 kdc_str = talloc_strdup(mem_ctx, "");
883 if (kdc_str == NULL) {
884 goto fail;
887 for (i=0; i<num_dcs; i++) {
888 char *new_kdc_str;
890 if (responses[i] == NULL) {
891 continue;
894 /* Append to the string - inefficient but not done often. */
895 new_kdc_str = print_kdc_line(mem_ctx, kdc_str,
896 &dc_addrs[i],
897 kdc_name);
898 if (new_kdc_str == NULL) {
899 goto fail;
901 TALLOC_FREE(kdc_str);
902 kdc_str = new_kdc_str;
905 DEBUG(10,("get_kdc_ip_string: Returning %s\n",
906 kdc_str ));
908 result = kdc_str;
909 fail:
910 SAFE_FREE(ip_srv_site);
911 SAFE_FREE(ip_srv_nonsite);
912 TALLOC_FREE(frame);
913 return result;
916 /************************************************************************
917 Create a specific krb5.conf file in the private directory pointing
918 at a specific kdc for a realm. Keyed off domain name. Sets
919 KRB5_CONFIG environment variable to point to this file. Must be
920 run as root or will fail (which is a good thing :-).
921 ************************************************************************/
923 bool create_local_private_krb5_conf_for_domain(const char *realm,
924 const char *domain,
925 const char *sitename,
926 const struct sockaddr_storage *pss,
927 const char *kdc_name)
929 char *dname;
930 char *tmpname = NULL;
931 char *fname = NULL;
932 char *file_contents = NULL;
933 char *kdc_ip_string = NULL;
934 size_t flen = 0;
935 ssize_t ret;
936 int fd;
937 char *realm_upper = NULL;
938 bool result = false;
940 if (!lp_create_krb5_conf()) {
941 return false;
944 dname = lock_path("smb_krb5");
945 if (!dname) {
946 return false;
948 if ((mkdir(dname, 0755)==-1) && (errno != EEXIST)) {
949 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
950 "failed to create directory %s. Error was %s\n",
951 dname, strerror(errno) ));
952 goto done;
955 tmpname = lock_path("smb_tmp_krb5.XXXXXX");
956 if (!tmpname) {
957 goto done;
960 fname = talloc_asprintf(dname, "%s/krb5.conf.%s", dname, domain);
961 if (!fname) {
962 goto done;
965 DEBUG(10,("create_local_private_krb5_conf_for_domain: fname = %s, realm = %s, domain = %s\n",
966 fname, realm, domain ));
968 realm_upper = talloc_strdup(fname, realm);
969 strupper_m(realm_upper);
971 kdc_ip_string = get_kdc_ip_string(dname, realm, sitename, pss, kdc_name);
972 if (!kdc_ip_string) {
973 goto done;
976 file_contents = talloc_asprintf(fname,
977 "[libdefaults]\n\tdefault_realm = %s\n"
978 "\tdefault_tgs_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
979 "\tdefault_tkt_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
980 "\tpreferred_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n\n"
981 "[realms]\n\t%s = {\n"
982 "\t%s\t}\n",
983 realm_upper, realm_upper, kdc_ip_string);
985 if (!file_contents) {
986 goto done;
989 flen = strlen(file_contents);
991 fd = mkstemp(tmpname);
992 if (fd == -1) {
993 DEBUG(0,("create_local_private_krb5_conf_for_domain: smb_mkstemp failed,"
994 " for file %s. Errno %s\n",
995 tmpname, strerror(errno) ));
996 goto done;
999 if (fchmod(fd, 0644)==-1) {
1000 DEBUG(0,("create_local_private_krb5_conf_for_domain: fchmod failed for %s."
1001 " Errno %s\n",
1002 tmpname, strerror(errno) ));
1003 unlink(tmpname);
1004 close(fd);
1005 goto done;
1008 ret = write(fd, file_contents, flen);
1009 if (flen != ret) {
1010 DEBUG(0,("create_local_private_krb5_conf_for_domain: write failed,"
1011 " returned %d (should be %u). Errno %s\n",
1012 (int)ret, (unsigned int)flen, strerror(errno) ));
1013 unlink(tmpname);
1014 close(fd);
1015 goto done;
1017 if (close(fd)==-1) {
1018 DEBUG(0,("create_local_private_krb5_conf_for_domain: close failed."
1019 " Errno %s\n", strerror(errno) ));
1020 unlink(tmpname);
1021 goto done;
1024 if (rename(tmpname, fname) == -1) {
1025 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
1026 "of %s to %s failed. Errno %s\n",
1027 tmpname, fname, strerror(errno) ));
1028 unlink(tmpname);
1029 goto done;
1032 DEBUG(5,("create_local_private_krb5_conf_for_domain: wrote "
1033 "file %s with realm %s KDC list = %s\n",
1034 fname, realm_upper, kdc_ip_string));
1036 /* Set the environment variable to this file. */
1037 setenv("KRB5_CONFIG", fname, 1);
1039 result = true;
1041 #if defined(OVERWRITE_SYSTEM_KRB5_CONF)
1043 #define SYSTEM_KRB5_CONF_PATH "/etc/krb5.conf"
1044 /* Insanity, sheer insanity..... */
1046 if (strequal(realm, lp_realm())) {
1047 SMB_STRUCT_STAT sbuf;
1049 if (sys_lstat(SYSTEM_KRB5_CONF_PATH, &sbuf, false) == 0) {
1050 if (S_ISLNK(sbuf.st_ex_mode) && sbuf.st_ex_size) {
1051 int lret;
1052 size_t alloc_size = sbuf.st_ex_size + 1;
1053 char *linkpath = talloc_array(talloc_tos(), char,
1054 alloc_size);
1055 if (!linkpath) {
1056 goto done;
1058 lret = readlink(SYSTEM_KRB5_CONF_PATH, linkpath,
1059 alloc_size - 1);
1060 if (lret == -1) {
1061 TALLOC_FREE(linkpath);
1062 goto done;
1064 linkpath[lret] = '\0';
1066 if (strcmp(linkpath, fname) == 0) {
1067 /* Symlink already exists. */
1068 TALLOC_FREE(linkpath);
1069 goto done;
1071 TALLOC_FREE(linkpath);
1075 /* Try and replace with a symlink. */
1076 if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
1077 const char *newpath = SYSTEM_KRB5_CONF_PATH ".saved";
1078 if (errno != EEXIST) {
1079 DEBUG(0,("create_local_private_krb5_conf_for_domain: symlink "
1080 "of %s to %s failed. Errno %s\n",
1081 fname, SYSTEM_KRB5_CONF_PATH, strerror(errno) ));
1082 goto done; /* Not a fatal error. */
1085 /* Yes, this is a race conditon... too bad. */
1086 if (rename(SYSTEM_KRB5_CONF_PATH, newpath) == -1) {
1087 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
1088 "of %s to %s failed. Errno %s\n",
1089 SYSTEM_KRB5_CONF_PATH, newpath,
1090 strerror(errno) ));
1091 goto done; /* Not a fatal error. */
1094 if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
1095 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
1096 "forced symlink of %s to /etc/krb5.conf failed. Errno %s\n",
1097 fname, strerror(errno) ));
1098 goto done; /* Not a fatal error. */
1102 #endif
1104 done:
1105 TALLOC_FREE(tmpname);
1106 TALLOC_FREE(dname);
1108 return result;
1110 #endif