s3-libsmb/clidfs.c: remove cli_nt_error()
[Samba/gebeck_regimport.git] / source3 / libads / kerberos.c
blobd111d018e0fef78df78693fdf9bb4f30d97f1961
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 False;
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( void )
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 = SMB_STRDUP(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 = SMB_STRNDUP(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. Returns malloc'ed memory.
483 Caller must free() if the return value is not NULL.
484 ************************************************************************/
486 char *kerberos_get_realm_from_hostname(const char *hostname)
488 #if defined(HAVE_KRB5_GET_HOST_REALM) && defined(HAVE_KRB5_FREE_HOST_REALM)
489 #if defined(HAVE_KRB5_REALM_TYPE)
490 /* Heimdal. */
491 krb5_realm *realm_list = NULL;
492 #else
493 /* MIT */
494 char **realm_list = NULL;
495 #endif
496 char *realm = NULL;
497 krb5_error_code kerr;
498 krb5_context ctx = NULL;
500 initialize_krb5_error_table();
501 if (krb5_init_context(&ctx)) {
502 return NULL;
505 kerr = krb5_get_host_realm(ctx, hostname, &realm_list);
506 if (kerr != 0) {
507 DEBUG(3,("kerberos_get_realm_from_hostname %s: "
508 "failed %s\n",
509 hostname ? hostname : "(NULL)",
510 error_message(kerr) ));
511 goto out;
514 if (realm_list && realm_list[0]) {
515 realm = SMB_STRDUP(realm_list[0]);
518 out:
520 if (ctx) {
521 if (realm_list) {
522 krb5_free_host_realm(ctx, realm_list);
523 realm_list = NULL;
525 krb5_free_context(ctx);
526 ctx = NULL;
528 return realm;
529 #else
530 return NULL;
531 #endif
534 /************************************************************************
535 Routine to get the salting principal for this service. This is
536 maintained for backwards compatibilty with releases prior to 3.0.24.
537 Since we store the salting principal string only at join, we may have
538 to look for the older tdb keys. Caller must free if return is not null.
539 ************************************************************************/
541 krb5_principal kerberos_fetch_salt_princ_for_host_princ(krb5_context context,
542 krb5_principal host_princ,
543 int enctype)
545 char *unparsed_name = NULL, *salt_princ_s = NULL;
546 krb5_principal ret_princ = NULL;
548 /* lookup new key first */
550 if ( (salt_princ_s = kerberos_secrets_fetch_des_salt()) == NULL ) {
552 /* look under the old key. If this fails, just use the standard key */
554 if (smb_krb5_unparse_name(talloc_tos(), context, host_princ, &unparsed_name) != 0) {
555 return (krb5_principal)NULL;
557 if ((salt_princ_s = kerberos_secrets_fetch_salting_principal(unparsed_name, enctype)) == NULL) {
558 /* fall back to host/machine.realm@REALM */
559 salt_princ_s = kerberos_standard_des_salt();
563 if (smb_krb5_parse_name(context, salt_princ_s, &ret_princ) != 0) {
564 ret_princ = NULL;
567 TALLOC_FREE(unparsed_name);
568 SAFE_FREE(salt_princ_s);
570 return ret_princ;
573 /************************************************************************
574 Routine to set the salting principal for this service. Active
575 Directory may use a non-obvious principal name to generate the salt
576 when it determines the key to use for encrypting tickets for a service,
577 and hopefully we detected that when we joined the domain.
578 Setting principal to NULL deletes this entry.
579 ************************************************************************/
581 bool kerberos_secrets_store_salting_principal(const char *service,
582 int enctype,
583 const char *principal)
585 char *key = NULL;
586 bool ret = False;
587 krb5_context context = NULL;
588 krb5_principal princ = NULL;
589 char *princ_s = NULL;
590 char *unparsed_name = NULL;
591 krb5_error_code code;
593 if (((code = krb5_init_context(&context)) != 0) || (context == NULL)) {
594 DEBUG(5, ("kerberos_secrets_store_salting_pricipal: kdb5_init_context failed: %s\n",
595 error_message(code)));
596 return False;
598 if (strchr_m(service, '@')) {
599 if (asprintf(&princ_s, "%s", service) == -1) {
600 goto out;
602 } else {
603 if (asprintf(&princ_s, "%s@%s", service, lp_realm()) == -1) {
604 goto out;
608 if (smb_krb5_parse_name(context, princ_s, &princ) != 0) {
609 goto out;
611 if (smb_krb5_unparse_name(talloc_tos(), context, princ, &unparsed_name) != 0) {
612 goto out;
615 if (asprintf(&key, "%s/%s/enctype=%d",
616 SECRETS_SALTING_PRINCIPAL, unparsed_name, enctype)
617 == -1) {
618 goto out;
621 if ((principal != NULL) && (strlen(principal) > 0)) {
622 ret = secrets_store(key, principal, strlen(principal) + 1);
623 } else {
624 ret = secrets_delete(key);
627 out:
629 SAFE_FREE(key);
630 SAFE_FREE(princ_s);
631 TALLOC_FREE(unparsed_name);
633 if (princ) {
634 krb5_free_principal(context, princ);
637 if (context) {
638 krb5_free_context(context);
641 return ret;
645 /************************************************************************
646 ************************************************************************/
648 int kerberos_kinit_password(const char *principal,
649 const char *password,
650 int time_offset,
651 const char *cache_name)
653 return kerberos_kinit_password_ext(principal,
654 password,
655 time_offset,
658 cache_name,
659 False,
660 False,
662 NULL);
665 /************************************************************************
666 ************************************************************************/
668 static char *print_kdc_line(char *mem_ctx,
669 const char *prev_line,
670 const struct sockaddr_storage *pss,
671 const char *kdc_name)
673 char addr[INET6_ADDRSTRLEN];
674 uint16_t port = get_sockaddr_port(pss);
676 if (pss->ss_family == AF_INET) {
677 return talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
678 prev_line,
679 print_canonical_sockaddr(mem_ctx, pss));
683 * IPv6 starts here
686 DEBUG(10, ("print_kdc_line: IPv6 case for kdc_name: %s, port: %d\n",
687 kdc_name, port));
689 if (port != 0 && port != DEFAULT_KRB5_PORT) {
690 /* Currently for IPv6 we can't specify a non-default
691 krb5 port with an address, as this requires a ':'.
692 Resolve to a name. */
693 char hostname[MAX_DNS_NAME_LENGTH];
694 int ret = sys_getnameinfo((const struct sockaddr *)pss,
695 sizeof(*pss),
696 hostname, sizeof(hostname),
697 NULL, 0,
698 NI_NAMEREQD);
699 if (ret) {
700 DEBUG(0,("print_kdc_line: can't resolve name "
701 "for kdc with non-default port %s. "
702 "Error %s\n.",
703 print_canonical_sockaddr(mem_ctx, pss),
704 gai_strerror(ret)));
705 return NULL;
707 /* Success, use host:port */
708 return talloc_asprintf(mem_ctx,
709 "%s\tkdc = %s:%u\n",
710 prev_line,
711 hostname,
712 (unsigned int)port);
715 /* no krb5 lib currently supports "kdc = ipv6 address"
716 * at all, so just fill in just the kdc_name if we have
717 * it and let the krb5 lib figure out the appropriate
718 * ipv6 address - gd */
720 if (kdc_name) {
721 return talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
722 prev_line, kdc_name);
725 return talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
726 prev_line,
727 print_sockaddr(addr,
728 sizeof(addr),
729 pss));
732 /************************************************************************
733 Create a string list of available kdc's, possibly searching by sitename.
734 Does DNS queries.
736 If "sitename" is given, the DC's in that site are listed first.
738 ************************************************************************/
740 static void add_sockaddr_unique(struct sockaddr_storage *addrs, int *num_addrs,
741 const struct sockaddr_storage *addr)
743 int i;
745 for (i=0; i<*num_addrs; i++) {
746 if (sockaddr_equal((const struct sockaddr *)&addrs[i],
747 (const struct sockaddr *)addr)) {
748 return;
751 addrs[i] = *addr;
752 *num_addrs += 1;
755 static char *get_kdc_ip_string(char *mem_ctx,
756 const char *realm,
757 const char *sitename,
758 const struct sockaddr_storage *pss,
759 const char *kdc_name)
761 TALLOC_CTX *frame = talloc_stackframe();
762 int i;
763 struct ip_service *ip_srv_site = NULL;
764 struct ip_service *ip_srv_nonsite = NULL;
765 int count_site = 0;
766 int count_nonsite;
767 int num_dcs;
768 struct sockaddr_storage *dc_addrs;
769 struct tsocket_address **dc_addrs2 = NULL;
770 const struct tsocket_address * const *dc_addrs3 = NULL;
771 char *result = NULL;
772 struct netlogon_samlogon_response **responses = NULL;
773 NTSTATUS status;
774 char *kdc_str = print_kdc_line(mem_ctx, "", pss, kdc_name);
776 if (kdc_str == NULL) {
777 return NULL;
781 * First get the KDC's only in this site, the rest will be
782 * appended later
785 if (sitename) {
786 get_kdc_list(realm, sitename, &ip_srv_site, &count_site);
789 /* Get all KDC's. */
791 get_kdc_list(realm, NULL, &ip_srv_nonsite, &count_nonsite);
793 dc_addrs = talloc_array(talloc_tos(), struct sockaddr_storage,
794 1 + count_site + count_nonsite);
795 if (dc_addrs == NULL) {
796 goto fail;
799 dc_addrs[0] = *pss;
800 num_dcs = 1;
802 for (i=0; i<count_site; i++) {
803 add_sockaddr_unique(dc_addrs, &num_dcs, &ip_srv_site[i].ss);
806 for (i=0; i<count_nonsite; i++) {
807 add_sockaddr_unique(dc_addrs, &num_dcs, &ip_srv_nonsite[i].ss);
810 dc_addrs2 = talloc_zero_array(talloc_tos(),
811 struct tsocket_address *,
812 num_dcs);
813 if (dc_addrs2 == NULL) {
814 goto fail;
817 for (i=0; i<num_dcs; i++) {
818 char addr[INET6_ADDRSTRLEN];
819 int ret;
821 print_sockaddr(addr, sizeof(addr), &dc_addrs[i]);
823 ret = tsocket_address_inet_from_strings(dc_addrs2, "ip",
824 addr, LDAP_PORT,
825 &dc_addrs2[i]);
826 if (ret != 0) {
827 status = map_nt_error_from_unix(errno);
828 DEBUG(2,("Failed to create tsocket_address for %s - %s\n",
829 addr, nt_errstr(status)));
830 goto fail;
834 dc_addrs3 = (const struct tsocket_address * const *)dc_addrs2;
836 status = cldap_multi_netlogon(talloc_tos(),
837 dc_addrs3, num_dcs,
838 realm, lp_netbios_name(),
839 NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX,
840 MIN(num_dcs, 3), timeval_current_ofs(3, 0), &responses);
841 TALLOC_FREE(dc_addrs2);
842 dc_addrs3 = NULL;
844 if (!NT_STATUS_IS_OK(status)) {
845 DEBUG(10,("get_kdc_ip_string: cldap_multi_netlogon failed: "
846 "%s\n", nt_errstr(status)));
847 goto fail;
850 kdc_str = talloc_strdup(mem_ctx, "");
851 if (kdc_str == NULL) {
852 goto fail;
855 for (i=0; i<num_dcs; i++) {
856 char *new_kdc_str;
858 if (responses[i] == NULL) {
859 continue;
862 /* Append to the string - inefficient but not done often. */
863 new_kdc_str = print_kdc_line(mem_ctx, kdc_str,
864 &dc_addrs[i],
865 kdc_name);
866 if (new_kdc_str == NULL) {
867 goto fail;
869 TALLOC_FREE(kdc_str);
870 kdc_str = new_kdc_str;
873 DEBUG(10,("get_kdc_ip_string: Returning %s\n",
874 kdc_str ));
876 result = kdc_str;
877 fail:
878 SAFE_FREE(ip_srv_site);
879 SAFE_FREE(ip_srv_nonsite);
880 TALLOC_FREE(frame);
881 return result;
884 /************************************************************************
885 Create a specific krb5.conf file in the private directory pointing
886 at a specific kdc for a realm. Keyed off domain name. Sets
887 KRB5_CONFIG environment variable to point to this file. Must be
888 run as root or will fail (which is a good thing :-).
889 ************************************************************************/
891 bool create_local_private_krb5_conf_for_domain(const char *realm,
892 const char *domain,
893 const char *sitename,
894 const struct sockaddr_storage *pss,
895 const char *kdc_name)
897 char *dname;
898 char *tmpname = NULL;
899 char *fname = NULL;
900 char *file_contents = NULL;
901 char *kdc_ip_string = NULL;
902 size_t flen = 0;
903 ssize_t ret;
904 int fd;
905 char *realm_upper = NULL;
906 bool result = false;
908 if (!lp_create_krb5_conf()) {
909 return false;
912 dname = lock_path("smb_krb5");
913 if (!dname) {
914 return false;
916 if ((mkdir(dname, 0755)==-1) && (errno != EEXIST)) {
917 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
918 "failed to create directory %s. Error was %s\n",
919 dname, strerror(errno) ));
920 goto done;
923 tmpname = lock_path("smb_tmp_krb5.XXXXXX");
924 if (!tmpname) {
925 goto done;
928 fname = talloc_asprintf(dname, "%s/krb5.conf.%s", dname, domain);
929 if (!fname) {
930 goto done;
933 DEBUG(10,("create_local_private_krb5_conf_for_domain: fname = %s, realm = %s, domain = %s\n",
934 fname, realm, domain ));
936 realm_upper = talloc_strdup(fname, realm);
937 strupper_m(realm_upper);
939 kdc_ip_string = get_kdc_ip_string(dname, realm, sitename, pss, kdc_name);
940 if (!kdc_ip_string) {
941 goto done;
944 file_contents = talloc_asprintf(fname,
945 "[libdefaults]\n\tdefault_realm = %s\n"
946 "\tdefault_tgs_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
947 "\tdefault_tkt_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
948 "\tpreferred_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n\n"
949 "[realms]\n\t%s = {\n"
950 "\t%s\t}\n",
951 realm_upper, realm_upper, kdc_ip_string);
953 if (!file_contents) {
954 goto done;
957 flen = strlen(file_contents);
959 fd = mkstemp(tmpname);
960 if (fd == -1) {
961 DEBUG(0,("create_local_private_krb5_conf_for_domain: smb_mkstemp failed,"
962 " for file %s. Errno %s\n",
963 tmpname, strerror(errno) ));
964 goto done;
967 if (fchmod(fd, 0644)==-1) {
968 DEBUG(0,("create_local_private_krb5_conf_for_domain: fchmod failed for %s."
969 " Errno %s\n",
970 tmpname, strerror(errno) ));
971 unlink(tmpname);
972 close(fd);
973 goto done;
976 ret = write(fd, file_contents, flen);
977 if (flen != ret) {
978 DEBUG(0,("create_local_private_krb5_conf_for_domain: write failed,"
979 " returned %d (should be %u). Errno %s\n",
980 (int)ret, (unsigned int)flen, strerror(errno) ));
981 unlink(tmpname);
982 close(fd);
983 goto done;
985 if (close(fd)==-1) {
986 DEBUG(0,("create_local_private_krb5_conf_for_domain: close failed."
987 " Errno %s\n", strerror(errno) ));
988 unlink(tmpname);
989 goto done;
992 if (rename(tmpname, fname) == -1) {
993 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
994 "of %s to %s failed. Errno %s\n",
995 tmpname, fname, strerror(errno) ));
996 unlink(tmpname);
997 goto done;
1000 DEBUG(5,("create_local_private_krb5_conf_for_domain: wrote "
1001 "file %s with realm %s KDC list = %s\n",
1002 fname, realm_upper, kdc_ip_string));
1004 /* Set the environment variable to this file. */
1005 setenv("KRB5_CONFIG", fname, 1);
1007 result = true;
1009 #if defined(OVERWRITE_SYSTEM_KRB5_CONF)
1011 #define SYSTEM_KRB5_CONF_PATH "/etc/krb5.conf"
1012 /* Insanity, sheer insanity..... */
1014 if (strequal(realm, lp_realm())) {
1015 SMB_STRUCT_STAT sbuf;
1017 if (sys_lstat(SYSTEM_KRB5_CONF_PATH, &sbuf, false) == 0) {
1018 if (S_ISLNK(sbuf.st_ex_mode) && sbuf.st_ex_size) {
1019 int lret;
1020 size_t alloc_size = sbuf.st_ex_size + 1;
1021 char *linkpath = talloc_array(talloc_tos(), char,
1022 alloc_size);
1023 if (!linkpath) {
1024 goto done;
1026 lret = readlink(SYSTEM_KRB5_CONF_PATH, linkpath,
1027 alloc_size - 1);
1028 if (lret == -1) {
1029 TALLOC_FREE(linkpath);
1030 goto done;
1032 linkpath[lret] = '\0';
1034 if (strcmp(linkpath, fname) == 0) {
1035 /* Symlink already exists. */
1036 TALLOC_FREE(linkpath);
1037 goto done;
1039 TALLOC_FREE(linkpath);
1043 /* Try and replace with a symlink. */
1044 if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
1045 const char *newpath = SYSTEM_KRB5_CONF_PATH ".saved";
1046 if (errno != EEXIST) {
1047 DEBUG(0,("create_local_private_krb5_conf_for_domain: symlink "
1048 "of %s to %s failed. Errno %s\n",
1049 fname, SYSTEM_KRB5_CONF_PATH, strerror(errno) ));
1050 goto done; /* Not a fatal error. */
1053 /* Yes, this is a race conditon... too bad. */
1054 if (rename(SYSTEM_KRB5_CONF_PATH, newpath) == -1) {
1055 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
1056 "of %s to %s failed. Errno %s\n",
1057 SYSTEM_KRB5_CONF_PATH, newpath,
1058 strerror(errno) ));
1059 goto done; /* Not a fatal error. */
1062 if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
1063 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
1064 "forced symlink of %s to /etc/krb5.conf failed. Errno %s\n",
1065 fname, strerror(errno) ));
1066 goto done; /* Not a fatal error. */
1070 #endif
1072 done:
1073 TALLOC_FREE(tmpname);
1074 TALLOC_FREE(dname);
1076 return result;
1078 #endif