Allow reinit_after_fork to be called safely from within swat and other binaries that...
[Samba.git] / source / winbindd / winbindd_cm.c
bloba139b32f2d42e28ebb2967a873cb7845c61768a1
1 /*
2 Unix SMB/CIFS implementation.
4 Winbind daemon connection manager
6 Copyright (C) Tim Potter 2001
7 Copyright (C) Andrew Bartlett 2002
8 Copyright (C) Gerald (Jerry) Carter 2003-2005.
9 Copyright (C) Volker Lendecke 2004-2005
10 Copyright (C) Jeremy Allison 2006
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 3 of the License, or
15 (at your option) any later version.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program. If not, see <http://www.gnu.org/licenses/>.
27 We need to manage connections to domain controllers without having to
28 mess up the main winbindd code with other issues. The aim of the
29 connection manager is to:
31 - make connections to domain controllers and cache them
32 - re-establish connections when networks or servers go down
33 - centralise the policy on connection timeouts, domain controller
34 selection etc
35 - manage re-entrancy for when winbindd becomes able to handle
36 multiple outstanding rpc requests
38 Why not have connection management as part of the rpc layer like tng?
39 Good question. This code may morph into libsmb/rpc_cache.c or something
40 like that but at the moment it's simply staying as part of winbind. I
41 think the TNG architecture of forcing every user of the rpc layer to use
42 the connection caching system is a bad idea. It should be an optional
43 method of using the routines.
45 The TNG design is quite good but I disagree with some aspects of the
46 implementation. -tpot
51 TODO:
53 - I'm pretty annoyed by all the make_nmb_name() stuff. It should be
54 moved down into another function.
56 - Take care when destroying cli_structs as they can be shared between
57 various sam handles.
61 #include "includes.h"
62 #include "winbindd.h"
64 #undef DBGC_CLASS
65 #define DBGC_CLASS DBGC_WINBIND
67 struct dc_name_ip {
68 fstring name;
69 struct sockaddr_storage ss;
72 extern struct winbindd_methods reconnect_methods;
73 extern bool override_logfile;
75 static NTSTATUS init_dc_connection_network(struct winbindd_domain *domain);
76 static void set_dc_type_and_flags( struct winbindd_domain *domain );
77 static bool get_dcs(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
78 struct dc_name_ip **dcs, int *num_dcs);
80 /****************************************************************
81 Child failed to find DC's. Reschedule check.
82 ****************************************************************/
84 static void msg_failed_to_go_online(struct messaging_context *msg,
85 void *private_data,
86 uint32_t msg_type,
87 struct server_id server_id,
88 DATA_BLOB *data)
90 struct winbindd_domain *domain;
91 const char *domainname = (const char *)data->data;
93 if (data->data == NULL || data->length == 0) {
94 return;
97 DEBUG(5,("msg_fail_to_go_online: received for domain %s.\n", domainname));
99 for (domain = domain_list(); domain; domain = domain->next) {
100 if (domain->internal) {
101 continue;
104 if (strequal(domain->name, domainname)) {
105 if (domain->online) {
106 /* We're already online, ignore. */
107 DEBUG(5,("msg_fail_to_go_online: domain %s "
108 "already online.\n", domainname));
109 continue;
112 /* Reschedule the online check. */
113 set_domain_offline(domain);
114 break;
119 /****************************************************************
120 Actually cause a reconnect from a message.
121 ****************************************************************/
123 static void msg_try_to_go_online(struct messaging_context *msg,
124 void *private_data,
125 uint32_t msg_type,
126 struct server_id server_id,
127 DATA_BLOB *data)
129 struct winbindd_domain *domain;
130 const char *domainname = (const char *)data->data;
132 if (data->data == NULL || data->length == 0) {
133 return;
136 DEBUG(5,("msg_try_to_go_online: received for domain %s.\n", domainname));
138 for (domain = domain_list(); domain; domain = domain->next) {
139 if (domain->internal) {
140 continue;
143 if (strequal(domain->name, domainname)) {
145 if (domain->online) {
146 /* We're already online, ignore. */
147 DEBUG(5,("msg_try_to_go_online: domain %s "
148 "already online.\n", domainname));
149 continue;
152 /* This call takes care of setting the online
153 flag to true if we connected, or re-adding
154 the offline handler if false. Bypasses online
155 check so always does network calls. */
157 init_dc_connection_network(domain);
158 break;
163 /****************************************************************
164 Fork a child to try and contact a DC. Do this as contacting a
165 DC requires blocking lookups and we don't want to block our
166 parent.
167 ****************************************************************/
169 static bool fork_child_dc_connect(struct winbindd_domain *domain)
171 struct dc_name_ip *dcs = NULL;
172 int num_dcs = 0;
173 TALLOC_CTX *mem_ctx = NULL;
174 pid_t child_pid;
175 pid_t parent_pid = sys_getpid();
176 char *lfile = NULL;
178 /* Stop zombies */
179 CatchChild();
181 child_pid = sys_fork();
183 if (child_pid == -1) {
184 DEBUG(0, ("fork_child_dc_connect: Could not fork: %s\n", strerror(errno)));
185 return False;
188 if (child_pid != 0) {
189 /* Parent */
190 messaging_register(winbind_messaging_context(), NULL,
191 MSG_WINBIND_TRY_TO_GO_ONLINE,
192 msg_try_to_go_online);
193 messaging_register(winbind_messaging_context(), NULL,
194 MSG_WINBIND_FAILED_TO_GO_ONLINE,
195 msg_failed_to_go_online);
196 return True;
199 /* Child. */
201 /* Leave messages blocked - we will never process one. */
203 if (!override_logfile) {
204 if (asprintf(&lfile, "%s/log.winbindd-dc-connect", get_dyn_LOGFILEBASE()) == -1) {
205 DEBUG(0, ("fork_child_dc_connect: out of memory!\n"));
206 _exit(1);
210 if (!winbindd_reinit_after_fork(lfile)) {
211 DEBUG(0,("reinit_after_fork() failed\n"));
212 messaging_send_buf(winbind_messaging_context(),
213 pid_to_procid(parent_pid),
214 MSG_WINBIND_FAILED_TO_GO_ONLINE,
215 (uint8 *)domain->name,
216 strlen(domain->name) + 1);
217 _exit(1);
220 SAFE_FREE(lfile);
222 mem_ctx = talloc_init("fork_child_dc_connect");
223 if (!mem_ctx) {
224 DEBUG(0,("talloc_init failed.\n"));
225 _exit(1);
228 if ((!get_dcs(mem_ctx, domain, &dcs, &num_dcs)) || (num_dcs == 0)) {
229 /* Still offline ? Can't find DC's. */
230 messaging_send_buf(winbind_messaging_context(),
231 pid_to_procid(parent_pid),
232 MSG_WINBIND_FAILED_TO_GO_ONLINE,
233 (uint8 *)domain->name,
234 strlen(domain->name)+1);
235 _exit(0);
238 /* We got a DC. Send a message to our parent to get it to
239 try and do the same. */
241 messaging_send_buf(winbind_messaging_context(),
242 pid_to_procid(parent_pid),
243 MSG_WINBIND_TRY_TO_GO_ONLINE,
244 (uint8 *)domain->name,
245 strlen(domain->name)+1);
246 _exit(0);
249 /****************************************************************
250 Handler triggered if we're offline to try and detect a DC.
251 ****************************************************************/
253 static void check_domain_online_handler(struct event_context *ctx,
254 struct timed_event *te,
255 const struct timeval *now,
256 void *private_data)
258 struct winbindd_domain *domain =
259 (struct winbindd_domain *)private_data;
261 DEBUG(10,("check_domain_online_handler: called for domain "
262 "%s (online = %s)\n", domain->name,
263 domain->online ? "True" : "False" ));
265 TALLOC_FREE(domain->check_online_event);
267 /* Are we still in "startup" mode ? */
269 if (domain->startup && (now->tv_sec > domain->startup_time + 30)) {
270 /* No longer in "startup" mode. */
271 DEBUG(10,("check_domain_online_handler: domain %s no longer in 'startup' mode.\n",
272 domain->name ));
273 domain->startup = False;
276 /* We've been told to stay offline, so stay
277 that way. */
279 if (get_global_winbindd_state_offline()) {
280 DEBUG(10,("check_domain_online_handler: domain %s remaining globally offline\n",
281 domain->name ));
282 return;
285 /* Fork a child to test if it can contact a DC.
286 If it can then send ourselves a message to
287 cause a reconnect. */
289 fork_child_dc_connect(domain);
292 /****************************************************************
293 If we're still offline setup the timeout check.
294 ****************************************************************/
296 static void calc_new_online_timeout_check(struct winbindd_domain *domain)
298 int wbc = lp_winbind_cache_time();
300 if (domain->startup) {
301 domain->check_online_timeout = 10;
302 } else if (domain->check_online_timeout < wbc) {
303 domain->check_online_timeout = wbc;
307 /****************************************************************
308 Set domain offline and also add handler to put us back online
309 if we detect a DC.
310 ****************************************************************/
312 void set_domain_offline(struct winbindd_domain *domain)
314 DEBUG(10,("set_domain_offline: called for domain %s\n",
315 domain->name ));
317 TALLOC_FREE(domain->check_online_event);
319 if (domain->internal) {
320 DEBUG(3,("set_domain_offline: domain %s is internal - logic error.\n",
321 domain->name ));
322 return;
325 domain->online = False;
327 /* Offline domains are always initialized. They're
328 re-initialized when they go back online. */
330 domain->initialized = True;
332 /* We only add the timeout handler that checks and
333 allows us to go back online when we've not
334 been told to remain offline. */
336 if (get_global_winbindd_state_offline()) {
337 DEBUG(10,("set_domain_offline: domain %s remaining globally offline\n",
338 domain->name ));
339 return;
342 /* If we're in statup mode, check again in 10 seconds, not in
343 lp_winbind_cache_time() seconds (which is 5 mins by default). */
345 calc_new_online_timeout_check(domain);
347 domain->check_online_event = event_add_timed(winbind_event_context(),
348 NULL,
349 timeval_current_ofs(domain->check_online_timeout,0),
350 "check_domain_online_handler",
351 check_domain_online_handler,
352 domain);
354 /* The above *has* to succeed for winbindd to work. */
355 if (!domain->check_online_event) {
356 smb_panic("set_domain_offline: failed to add online handler");
359 DEBUG(10,("set_domain_offline: added event handler for domain %s\n",
360 domain->name ));
362 /* Send an offline message to the idmap child when our
363 primary domain goes offline */
365 if ( domain->primary ) {
366 struct winbindd_child *idmap = idmap_child();
368 if ( idmap->pid != 0 ) {
369 messaging_send_buf(winbind_messaging_context(),
370 pid_to_procid(idmap->pid),
371 MSG_WINBIND_OFFLINE,
372 (uint8 *)domain->name,
373 strlen(domain->name)+1);
377 return;
380 /****************************************************************
381 Set domain online - if allowed.
382 ****************************************************************/
384 void ccache_regain_all_now(void);
386 static void set_domain_online(struct winbindd_domain *domain)
389 DEBUG(10,("set_domain_online: called for domain %s\n",
390 domain->name ));
392 if (domain->internal) {
393 DEBUG(3,("set_domain_online: domain %s is internal - logic error.\n",
394 domain->name ));
395 return;
398 if (get_global_winbindd_state_offline()) {
399 DEBUG(10,("set_domain_online: domain %s remaining globally offline\n",
400 domain->name ));
401 return;
404 winbindd_set_locator_kdc_envs(domain);
406 /* If we are waiting to get a krb5 ticket, trigger immediately. */
407 ccache_regain_all_now();
409 /* Ok, we're out of any startup mode now... */
410 domain->startup = False;
412 if (domain->online == False) {
413 /* We were offline - now we're online. We default to
414 using the MS-RPC backend if we started offline,
415 and if we're going online for the first time we
416 should really re-initialize the backends and the
417 checks to see if we're talking to an AD or NT domain.
420 domain->initialized = False;
422 /* 'reconnect_methods' is the MS-RPC backend. */
423 if (domain->backend == &reconnect_methods) {
424 domain->backend = NULL;
428 /* Ensure we have no online timeout checks. */
429 domain->check_online_timeout = 0;
430 TALLOC_FREE(domain->check_online_event);
432 /* Ensure we ignore any pending child messages. */
433 messaging_deregister(winbind_messaging_context(),
434 MSG_WINBIND_TRY_TO_GO_ONLINE, NULL);
435 messaging_deregister(winbind_messaging_context(),
436 MSG_WINBIND_FAILED_TO_GO_ONLINE, NULL);
438 domain->online = True;
440 /* Send an online message to the idmap child when our
441 primary domain comes online */
443 if ( domain->primary ) {
444 struct winbindd_child *idmap = idmap_child();
446 if ( idmap->pid != 0 ) {
447 messaging_send_buf(winbind_messaging_context(),
448 pid_to_procid(idmap->pid),
449 MSG_WINBIND_ONLINE,
450 (uint8 *)domain->name,
451 strlen(domain->name)+1);
455 return;
458 /****************************************************************
459 Requested to set a domain online.
460 ****************************************************************/
462 void set_domain_online_request(struct winbindd_domain *domain)
464 struct timeval tev;
466 DEBUG(10,("set_domain_online_request: called for domain %s\n",
467 domain->name ));
469 if (get_global_winbindd_state_offline()) {
470 DEBUG(10,("set_domain_online_request: domain %s remaining globally offline\n",
471 domain->name ));
472 return;
475 /* We've been told it's safe to go online and
476 try and connect to a DC. But I don't believe it
477 because network manager seems to lie.
478 Wait at least 5 seconds. Heuristics suck... */
480 GetTimeOfDay(&tev);
482 /* Go into "startup" mode again. */
483 domain->startup_time = tev.tv_sec;
484 domain->startup = True;
486 tev.tv_sec += 5;
487 if (!domain->check_online_event) {
488 /* If we've come from being globally offline we
489 don't have a check online event handler set.
490 We need to add one now we're trying to go
491 back online. */
492 DEBUG(10,("set_domain_online_request: domain %s was globally offline.\n",
493 domain->name ));
496 TALLOC_FREE(domain->check_online_event);
498 domain->check_online_event = event_add_timed(winbind_event_context(),
499 NULL,
500 tev,
501 "check_domain_online_handler",
502 check_domain_online_handler,
503 domain);
505 /* The above *has* to succeed for winbindd to work. */
506 if (!domain->check_online_event) {
507 smb_panic("set_domain_online_request: failed to add online handler");
511 /****************************************************************
512 Add -ve connection cache entries for domain and realm.
513 ****************************************************************/
515 void winbind_add_failed_connection_entry(const struct winbindd_domain *domain,
516 const char *server,
517 NTSTATUS result)
519 add_failed_connection_entry(domain->name, server, result);
520 /* If this was the saf name for the last thing we talked to,
521 remove it. */
522 saf_delete(domain->name);
523 if (*domain->alt_name) {
524 add_failed_connection_entry(domain->alt_name, server, result);
525 saf_delete(domain->alt_name);
527 winbindd_unset_locator_kdc_env(domain);
530 /* Choose between anonymous or authenticated connections. We need to use
531 an authenticated connection if DCs have the RestrictAnonymous registry
532 entry set > 0, or the "Additional restrictions for anonymous
533 connections" set in the win2k Local Security Policy.
535 Caller to free() result in domain, username, password
538 static void cm_get_ipc_userpass(char **username, char **domain, char **password)
540 *username = (char *)secrets_fetch(SECRETS_AUTH_USER, NULL);
541 *domain = (char *)secrets_fetch(SECRETS_AUTH_DOMAIN, NULL);
542 *password = (char *)secrets_fetch(SECRETS_AUTH_PASSWORD, NULL);
544 if (*username && **username) {
546 if (!*domain || !**domain)
547 *domain = smb_xstrdup(lp_workgroup());
549 if (!*password || !**password)
550 *password = smb_xstrdup("");
552 DEBUG(3, ("cm_get_ipc_userpass: Retrieved auth-user from secrets.tdb [%s\\%s]\n",
553 *domain, *username));
555 } else {
556 DEBUG(3, ("cm_get_ipc_userpass: No auth-user defined\n"));
557 *username = smb_xstrdup("");
558 *domain = smb_xstrdup("");
559 *password = smb_xstrdup("");
563 static bool get_dc_name_via_netlogon(struct winbindd_domain *domain,
564 fstring dcname,
565 struct sockaddr_storage *dc_ss)
567 struct winbindd_domain *our_domain = NULL;
568 struct rpc_pipe_client *netlogon_pipe = NULL;
569 NTSTATUS result;
570 WERROR werr;
571 TALLOC_CTX *mem_ctx;
572 unsigned int orig_timeout;
573 const char *tmp = NULL;
574 const char *p;
576 /* Hmmmm. We can only open one connection to the NETLOGON pipe at the
577 * moment.... */
579 if (IS_DC) {
580 return False;
583 if (domain->primary) {
584 return False;
587 our_domain = find_our_domain();
589 if ((mem_ctx = talloc_init("get_dc_name_via_netlogon")) == NULL) {
590 return False;
593 result = cm_connect_netlogon(our_domain, &netlogon_pipe);
594 if (!NT_STATUS_IS_OK(result)) {
595 talloc_destroy(mem_ctx);
596 return False;
599 /* This call can take a long time - allow the server to time out.
600 35 seconds should do it. */
602 orig_timeout = cli_set_timeout(netlogon_pipe->cli, 35000);
604 if (our_domain->active_directory) {
605 struct netr_DsRGetDCNameInfo *domain_info = NULL;
607 result = rpccli_netr_DsRGetDCName(netlogon_pipe,
608 mem_ctx,
609 our_domain->dcname,
610 domain->name,
611 NULL,
612 NULL,
613 DS_RETURN_DNS_NAME,
614 &domain_info,
615 &werr);
616 if (NT_STATUS_IS_OK(result) && W_ERROR_IS_OK(werr)) {
617 tmp = talloc_strdup(
618 mem_ctx, domain_info->dc_unc);
619 if (tmp == NULL) {
620 DEBUG(0, ("talloc_strdup failed\n"));
621 talloc_destroy(mem_ctx);
622 return false;
624 if (strlen(domain->alt_name) == 0) {
625 fstrcpy(domain->alt_name,
626 domain_info->domain_name);
628 if (strlen(domain->forest_name) == 0) {
629 fstrcpy(domain->forest_name,
630 domain_info->forest_name);
633 } else {
634 result = rpccli_netr_GetAnyDCName(netlogon_pipe, mem_ctx,
635 our_domain->dcname,
636 domain->name,
637 &tmp,
638 &werr);
641 /* And restore our original timeout. */
642 cli_set_timeout(netlogon_pipe->cli, orig_timeout);
644 if (!NT_STATUS_IS_OK(result)) {
645 DEBUG(10,("rpccli_netr_GetAnyDCName failed: %s\n",
646 nt_errstr(result)));
647 talloc_destroy(mem_ctx);
648 return false;
651 if (!W_ERROR_IS_OK(werr)) {
652 DEBUG(10,("rpccli_netr_GetAnyDCName failed: %s\n",
653 dos_errstr(werr)));
654 talloc_destroy(mem_ctx);
655 return false;
658 /* rpccli_netr_GetAnyDCName gives us a name with \\ */
659 p = strip_hostname(tmp);
661 fstrcpy(dcname, p);
663 talloc_destroy(mem_ctx);
665 DEBUG(10,("rpccli_netr_GetAnyDCName returned %s\n", dcname));
667 if (!resolve_name(dcname, dc_ss, 0x20)) {
668 return False;
671 return True;
675 * Helper function to assemble trust password and account name
677 static NTSTATUS get_trust_creds(const struct winbindd_domain *domain,
678 char **machine_password,
679 char **machine_account,
680 char **machine_krb5_principal)
682 const char *account_name;
683 const char *name = NULL;
685 /* If we are a DC and this is not our own domain */
687 if (IS_DC) {
688 name = domain->name;
689 } else {
690 struct winbindd_domain *our_domain = find_our_domain();
692 if (!our_domain)
693 return NT_STATUS_INVALID_SERVER_STATE;
695 name = our_domain->name;
698 if (!get_trust_pw_clear(name, machine_password,
699 &account_name, NULL))
701 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
704 if ((machine_account != NULL) &&
705 (asprintf(machine_account, "%s$", account_name) == -1))
707 return NT_STATUS_NO_MEMORY;
710 /* For now assume our machine account only exists in our domain */
712 if (machine_krb5_principal != NULL)
714 if (asprintf(machine_krb5_principal, "%s$@%s",
715 account_name, lp_realm()) == -1)
717 return NT_STATUS_NO_MEMORY;
720 strupper_m(*machine_krb5_principal);
723 return NT_STATUS_OK;
726 /************************************************************************
727 Given a fd with a just-connected TCP connection to a DC, open a connection
728 to the pipe.
729 ************************************************************************/
731 static NTSTATUS cm_prepare_connection(const struct winbindd_domain *domain,
732 const int sockfd,
733 const char *controller,
734 struct cli_state **cli,
735 bool *retry)
737 char *machine_password = NULL;
738 char *machine_krb5_principal = NULL;
739 char *machine_account = NULL;
740 char *ipc_username = NULL;
741 char *ipc_domain = NULL;
742 char *ipc_password = NULL;
744 struct named_mutex *mutex;
746 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
748 struct sockaddr peeraddr;
749 socklen_t peeraddr_len;
751 struct sockaddr_in *peeraddr_in = (struct sockaddr_in *)&peeraddr;
753 DEBUG(10,("cm_prepare_connection: connecting to DC %s for domain %s\n",
754 controller, domain->name ));
756 *retry = True;
758 mutex = grab_named_mutex(talloc_tos(), controller,
759 WINBIND_SERVER_MUTEX_WAIT_TIME);
760 if (mutex == NULL) {
761 DEBUG(0,("cm_prepare_connection: mutex grab failed for %s\n",
762 controller));
763 result = NT_STATUS_POSSIBLE_DEADLOCK;
764 goto done;
767 if ((*cli = cli_initialise()) == NULL) {
768 DEBUG(1, ("Could not cli_initialize\n"));
769 result = NT_STATUS_NO_MEMORY;
770 goto done;
773 (*cli)->timeout = 10000; /* 10 seconds */
774 (*cli)->fd = sockfd;
775 fstrcpy((*cli)->desthost, controller);
776 (*cli)->use_kerberos = True;
778 peeraddr_len = sizeof(peeraddr);
780 if ((getpeername((*cli)->fd, &peeraddr, &peeraddr_len) != 0) ||
781 (peeraddr_len != sizeof(struct sockaddr_in)) ||
782 (peeraddr_in->sin_family != PF_INET))
784 DEBUG(0,("cm_prepare_connection: %s\n", strerror(errno)));
785 result = NT_STATUS_UNSUCCESSFUL;
786 goto done;
789 if (ntohs(peeraddr_in->sin_port) == 139) {
790 struct nmb_name calling;
791 struct nmb_name called;
793 make_nmb_name(&calling, global_myname(), 0x0);
794 make_nmb_name(&called, "*SMBSERVER", 0x20);
796 if (!cli_session_request(*cli, &calling, &called)) {
797 DEBUG(8, ("cli_session_request failed for %s\n",
798 controller));
799 result = NT_STATUS_UNSUCCESSFUL;
800 goto done;
804 cli_setup_signing_state(*cli, Undefined);
806 if (!cli_negprot(*cli)) {
807 DEBUG(1, ("cli_negprot failed\n"));
808 result = NT_STATUS_UNSUCCESSFUL;
809 goto done;
812 if (!is_trusted_domain_situation(domain->name) &&
813 (*cli)->protocol >= PROTOCOL_NT1 &&
814 (*cli)->capabilities & CAP_EXTENDED_SECURITY)
816 ADS_STATUS ads_status;
818 result = get_trust_creds(domain, &machine_password,
819 &machine_account,
820 &machine_krb5_principal);
821 if (!NT_STATUS_IS_OK(result)) {
822 goto anon_fallback;
825 if (lp_security() == SEC_ADS) {
827 /* Try a krb5 session */
829 (*cli)->use_kerberos = True;
830 DEBUG(5, ("connecting to %s from %s with kerberos principal "
831 "[%s] and realm [%s]\n", controller, global_myname(),
832 machine_krb5_principal, domain->alt_name));
834 winbindd_set_locator_kdc_envs(domain);
836 ads_status = cli_session_setup_spnego(*cli,
837 machine_krb5_principal,
838 machine_password,
839 lp_workgroup(),
840 domain->name);
842 if (!ADS_ERR_OK(ads_status)) {
843 DEBUG(4,("failed kerberos session setup with %s\n",
844 ads_errstr(ads_status)));
847 result = ads_ntstatus(ads_status);
848 if (NT_STATUS_IS_OK(result)) {
849 /* Ensure creds are stored for NTLMSSP authenticated pipe access. */
850 cli_init_creds(*cli, machine_account, lp_workgroup(), machine_password);
851 goto session_setup_done;
855 /* Fall back to non-kerberos session setup using NTLMSSP SPNEGO with the machine account. */
856 (*cli)->use_kerberos = False;
858 DEBUG(5, ("connecting to %s from %s with username "
859 "[%s]\\[%s]\n", controller, global_myname(),
860 lp_workgroup(), machine_account));
862 ads_status = cli_session_setup_spnego(*cli,
863 machine_account,
864 machine_password,
865 lp_workgroup(),
866 NULL);
867 if (!ADS_ERR_OK(ads_status)) {
868 DEBUG(4, ("authenticated session setup failed with %s\n",
869 ads_errstr(ads_status)));
872 result = ads_ntstatus(ads_status);
873 if (NT_STATUS_IS_OK(result)) {
874 /* Ensure creds are stored for NTLMSSP authenticated pipe access. */
875 cli_init_creds(*cli, machine_account, lp_workgroup(), machine_password);
876 goto session_setup_done;
880 /* Fall back to non-kerberos session setup with auth_user */
882 (*cli)->use_kerberos = False;
884 cm_get_ipc_userpass(&ipc_username, &ipc_domain, &ipc_password);
886 if ((((*cli)->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) != 0) &&
887 (strlen(ipc_username) > 0)) {
889 /* Only try authenticated if we have a username */
891 DEBUG(5, ("connecting to %s from %s with username "
892 "[%s]\\[%s]\n", controller, global_myname(),
893 ipc_domain, ipc_username));
895 if (NT_STATUS_IS_OK(cli_session_setup(
896 *cli, ipc_username,
897 ipc_password, strlen(ipc_password)+1,
898 ipc_password, strlen(ipc_password)+1,
899 ipc_domain))) {
900 /* Successful logon with given username. */
901 cli_init_creds(*cli, ipc_username, ipc_domain, ipc_password);
902 goto session_setup_done;
903 } else {
904 DEBUG(4, ("authenticated session setup with user %s\\%s failed.\n",
905 ipc_domain, ipc_username ));
909 anon_fallback:
911 /* Fall back to anonymous connection, this might fail later */
912 DEBUG(10,("cm_prepare_connection: falling back to anonymous "
913 "connection for DC %s\n",
914 controller ));
916 if (NT_STATUS_IS_OK(cli_session_setup(*cli, "", NULL, 0,
917 NULL, 0, ""))) {
918 DEBUG(5, ("Connected anonymously\n"));
919 cli_init_creds(*cli, "", "", "");
920 goto session_setup_done;
923 result = cli_nt_error(*cli);
925 if (NT_STATUS_IS_OK(result))
926 result = NT_STATUS_UNSUCCESSFUL;
928 /* We can't session setup */
930 goto done;
932 session_setup_done:
934 /* cache the server name for later connections */
936 saf_store( domain->name, (*cli)->desthost );
937 if (domain->alt_name && (*cli)->use_kerberos) {
938 saf_store( domain->alt_name, (*cli)->desthost );
941 winbindd_set_locator_kdc_envs(domain);
943 if (!cli_send_tconX(*cli, "IPC$", "IPC", "", 0)) {
945 result = cli_nt_error(*cli);
947 DEBUG(1,("failed tcon_X with %s\n", nt_errstr(result)));
949 if (NT_STATUS_IS_OK(result))
950 result = NT_STATUS_UNSUCCESSFUL;
952 goto done;
955 TALLOC_FREE(mutex);
956 *retry = False;
958 /* set the domain if empty; needed for schannel connections */
959 if ( !*(*cli)->domain ) {
960 fstrcpy( (*cli)->domain, domain->name );
963 result = NT_STATUS_OK;
965 done:
966 TALLOC_FREE(mutex);
967 SAFE_FREE(machine_account);
968 SAFE_FREE(machine_password);
969 SAFE_FREE(machine_krb5_principal);
970 SAFE_FREE(ipc_username);
971 SAFE_FREE(ipc_domain);
972 SAFE_FREE(ipc_password);
974 if (!NT_STATUS_IS_OK(result)) {
975 winbind_add_failed_connection_entry(domain, controller, result);
976 if ((*cli) != NULL) {
977 cli_shutdown(*cli);
978 *cli = NULL;
982 return result;
985 /*******************************************************************
986 Add a dcname and sockaddr_storage pair to the end of a dc_name_ip
987 array.
989 Keeps the list unique by not adding duplicate entries.
991 @param[in] mem_ctx talloc memory context to allocate from
992 @param[in] domain_name domain of the DC
993 @param[in] dcname name of the DC to add to the list
994 @param[in] pss Internet address and port pair to add to the list
995 @param[in,out] dcs array of dc_name_ip structures to add to
996 @param[in,out] num_dcs number of dcs returned in the dcs array
997 @return true if the list was added to, false otherwise
998 *******************************************************************/
1000 static bool add_one_dc_unique(TALLOC_CTX *mem_ctx, const char *domain_name,
1001 const char *dcname, struct sockaddr_storage *pss,
1002 struct dc_name_ip **dcs, int *num)
1004 int i = 0;
1006 if (!NT_STATUS_IS_OK(check_negative_conn_cache(domain_name, dcname))) {
1007 DEBUG(10, ("DC %s was in the negative conn cache\n", dcname));
1008 return False;
1011 /* Make sure there's no duplicates in the list */
1012 for (i=0; i<*num; i++)
1013 if (sockaddr_equal(&(*dcs)[i].ss, pss))
1014 return False;
1016 *dcs = TALLOC_REALLOC_ARRAY(mem_ctx, *dcs, struct dc_name_ip, (*num)+1);
1018 if (*dcs == NULL)
1019 return False;
1021 fstrcpy((*dcs)[*num].name, dcname);
1022 (*dcs)[*num].ss = *pss;
1023 *num += 1;
1024 return True;
1027 static bool add_sockaddr_to_array(TALLOC_CTX *mem_ctx,
1028 struct sockaddr_storage *pss, uint16 port,
1029 struct sockaddr_storage **addrs, int *num)
1031 *addrs = TALLOC_REALLOC_ARRAY(mem_ctx, *addrs, struct sockaddr_storage, (*num)+1);
1033 if (*addrs == NULL) {
1034 *num = 0;
1035 return False;
1038 (*addrs)[*num] = *pss;
1039 set_sockaddr_port(&(*addrs)[*num], port);
1041 *num += 1;
1042 return True;
1045 /*******************************************************************
1046 convert an ip to a name
1047 *******************************************************************/
1049 static bool dcip_to_name(TALLOC_CTX *mem_ctx,
1050 const struct winbindd_domain *domain,
1051 struct sockaddr_storage *pss,
1052 fstring name )
1054 struct ip_service ip_list;
1055 uint32_t nt_version = NETLOGON_VERSION_1;
1057 ip_list.ss = *pss;
1058 ip_list.port = 0;
1060 #ifdef WITH_ADS
1061 /* For active directory servers, try to get the ldap server name.
1062 None of these failures should be considered critical for now */
1064 if (lp_security() == SEC_ADS) {
1065 ADS_STRUCT *ads;
1066 char addr[INET6_ADDRSTRLEN];
1068 print_sockaddr(addr, sizeof(addr), pss);
1070 ads = ads_init(domain->alt_name, domain->name, NULL);
1071 ads->auth.flags |= ADS_AUTH_NO_BIND;
1073 if (ads_try_connect(ads, addr)) {
1074 /* We got a cldap packet. */
1075 fstrcpy(name, ads->config.ldap_server_name);
1076 namecache_store(name, 0x20, 1, &ip_list);
1078 DEBUG(10,("dcip_to_name: flags = 0x%x\n", (unsigned int)ads->config.flags));
1080 if (domain->primary && (ads->config.flags & NBT_SERVER_KDC)) {
1081 if (ads_closest_dc(ads)) {
1082 char *sitename = sitename_fetch(ads->config.realm);
1084 /* We're going to use this KDC for this realm/domain.
1085 If we are using sites, then force the krb5 libs
1086 to use this KDC. */
1088 create_local_private_krb5_conf_for_domain(domain->alt_name,
1089 domain->name,
1090 sitename,
1091 pss);
1093 SAFE_FREE(sitename);
1094 } else {
1095 /* use an off site KDC */
1096 create_local_private_krb5_conf_for_domain(domain->alt_name,
1097 domain->name,
1098 NULL,
1099 pss);
1101 winbindd_set_locator_kdc_envs(domain);
1103 /* Ensure we contact this DC also. */
1104 saf_store( domain->name, name);
1105 saf_store( domain->alt_name, name);
1108 ads_destroy( &ads );
1109 return True;
1112 ads_destroy( &ads );
1114 #endif
1116 /* try GETDC requests next */
1118 if (send_getdc_request(mem_ctx, winbind_messaging_context(),
1119 pss, domain->name, &domain->sid,
1120 nt_version)) {
1121 const char *dc_name = NULL;
1122 int i;
1123 smb_msleep(100);
1124 for (i=0; i<5; i++) {
1125 if (receive_getdc_response(mem_ctx, pss, domain->name,
1126 &nt_version,
1127 &dc_name, NULL)) {
1128 fstrcpy(name, dc_name);
1129 namecache_store(name, 0x20, 1, &ip_list);
1130 return True;
1132 smb_msleep(500);
1136 /* try node status request */
1138 if ( name_status_find(domain->name, 0x1c, 0x20, pss, name) ) {
1139 namecache_store(name, 0x20, 1, &ip_list);
1140 return True;
1142 return False;
1145 /*******************************************************************
1146 Retrieve a list of IP addresses for domain controllers.
1148 The array is sorted in the preferred connection order.
1150 @param[in] mem_ctx talloc memory context to allocate from
1151 @param[in] domain domain to retrieve DCs for
1152 @param[out] dcs array of dcs that will be returned
1153 @param[out] num_dcs number of dcs returned in the dcs array
1154 @return always true
1155 *******************************************************************/
1157 static bool get_dcs(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
1158 struct dc_name_ip **dcs, int *num_dcs)
1160 fstring dcname;
1161 struct sockaddr_storage ss;
1162 struct ip_service *ip_list = NULL;
1163 int iplist_size = 0;
1164 int i;
1165 bool is_our_domain;
1166 enum security_types sec = (enum security_types)lp_security();
1168 is_our_domain = strequal(domain->name, lp_workgroup());
1170 /* If not our domain, get the preferred DC, by asking our primary DC */
1171 if ( !is_our_domain
1172 && get_dc_name_via_netlogon(domain, dcname, &ss)
1173 && add_one_dc_unique(mem_ctx, domain->name, dcname, &ss, dcs,
1174 num_dcs) )
1176 char addr[INET6_ADDRSTRLEN];
1177 print_sockaddr(addr, sizeof(addr), &ss);
1178 DEBUG(10, ("Retrieved DC %s at %s via netlogon\n",
1179 dcname, addr));
1180 return True;
1183 if (sec == SEC_ADS) {
1184 char *sitename = NULL;
1186 /* We need to make sure we know the local site before
1187 doing any DNS queries, as this will restrict the
1188 get_sorted_dc_list() call below to only fetching
1189 DNS records for the correct site. */
1191 /* Find any DC to get the site record.
1192 We deliberately don't care about the
1193 return here. */
1195 get_dc_name(domain->name, domain->alt_name, dcname, &ss);
1197 sitename = sitename_fetch(domain->alt_name);
1198 if (sitename) {
1200 /* Do the site-specific AD dns lookup first. */
1201 get_sorted_dc_list(domain->alt_name, sitename, &ip_list,
1202 &iplist_size, True);
1204 /* Add ips to the DC array. We don't look up the name
1205 of the DC in this function, but we fill in the char*
1206 of the ip now to make the failed connection cache
1207 work */
1208 for ( i=0; i<iplist_size; i++ ) {
1209 char addr[INET6_ADDRSTRLEN];
1210 print_sockaddr(addr, sizeof(addr),
1211 &ip_list[i].ss);
1212 add_one_dc_unique(mem_ctx,
1213 domain->name,
1214 addr,
1215 &ip_list[i].ss,
1216 dcs,
1217 num_dcs);
1220 SAFE_FREE(ip_list);
1221 SAFE_FREE(sitename);
1222 iplist_size = 0;
1225 /* Now we add DCs from the main AD DNS lookup. */
1226 get_sorted_dc_list(domain->alt_name, NULL, &ip_list,
1227 &iplist_size, True);
1229 for ( i=0; i<iplist_size; i++ ) {
1230 char addr[INET6_ADDRSTRLEN];
1231 print_sockaddr(addr, sizeof(addr),
1232 &ip_list[i].ss);
1233 add_one_dc_unique(mem_ctx,
1234 domain->name,
1235 addr,
1236 &ip_list[i].ss,
1237 dcs,
1238 num_dcs);
1241 SAFE_FREE(ip_list);
1242 iplist_size = 0;
1245 /* Try standard netbios queries if no ADS */
1246 if (*num_dcs == 0) {
1247 get_sorted_dc_list(domain->name, NULL, &ip_list, &iplist_size,
1248 False);
1250 for ( i=0; i<iplist_size; i++ ) {
1251 char addr[INET6_ADDRSTRLEN];
1252 print_sockaddr(addr, sizeof(addr),
1253 &ip_list[i].ss);
1254 add_one_dc_unique(mem_ctx,
1255 domain->name,
1256 addr,
1257 &ip_list[i].ss,
1258 dcs,
1259 num_dcs);
1262 SAFE_FREE(ip_list);
1263 iplist_size = 0;
1266 return True;
1269 /*******************************************************************
1270 Find and make a connection to a DC in the given domain.
1272 @param[in] mem_ctx talloc memory context to allocate from
1273 @param[in] domain domain to find a dc in
1274 @param[out] dcname NetBIOS or FQDN of DC that's connected to
1275 @param[out] pss DC Internet address and port
1276 @param[out] fd fd of the open socket connected to the newly found dc
1277 @return true when a DC connection is made, false otherwise
1278 *******************************************************************/
1280 static bool find_new_dc(TALLOC_CTX *mem_ctx,
1281 struct winbindd_domain *domain,
1282 fstring dcname, struct sockaddr_storage *pss, int *fd)
1284 struct dc_name_ip *dcs = NULL;
1285 int num_dcs = 0;
1287 const char **dcnames = NULL;
1288 int num_dcnames = 0;
1290 struct sockaddr_storage *addrs = NULL;
1291 int num_addrs = 0;
1293 int i, fd_index;
1295 *fd = -1;
1297 again:
1298 if (!get_dcs(mem_ctx, domain, &dcs, &num_dcs) || (num_dcs == 0))
1299 return False;
1301 for (i=0; i<num_dcs; i++) {
1303 if (!add_string_to_array(mem_ctx, dcs[i].name,
1304 &dcnames, &num_dcnames)) {
1305 return False;
1307 if (!add_sockaddr_to_array(mem_ctx, &dcs[i].ss, 445,
1308 &addrs, &num_addrs)) {
1309 return False;
1312 if (!add_string_to_array(mem_ctx, dcs[i].name,
1313 &dcnames, &num_dcnames)) {
1314 return False;
1316 if (!add_sockaddr_to_array(mem_ctx, &dcs[i].ss, 139,
1317 &addrs, &num_addrs)) {
1318 return False;
1322 if ((num_dcnames == 0) || (num_dcnames != num_addrs))
1323 return False;
1325 if ((addrs == NULL) || (dcnames == NULL))
1326 return False;
1328 /* 5 second timeout. */
1329 if (!open_any_socket_out(addrs, num_addrs, 5000, &fd_index, fd) ) {
1330 for (i=0; i<num_dcs; i++) {
1331 char ab[INET6_ADDRSTRLEN];
1332 print_sockaddr(ab, sizeof(ab), &dcs[i].ss);
1333 DEBUG(10, ("find_new_dc: open_any_socket_out failed for "
1334 "domain %s address %s. Error was %s\n",
1335 domain->name, ab, strerror(errno) ));
1336 winbind_add_failed_connection_entry(domain,
1337 dcs[i].name, NT_STATUS_UNSUCCESSFUL);
1339 return False;
1342 *pss = addrs[fd_index];
1344 if (*dcnames[fd_index] != '\0' && !is_ipaddress(dcnames[fd_index])) {
1345 /* Ok, we've got a name for the DC */
1346 fstrcpy(dcname, dcnames[fd_index]);
1347 return True;
1350 /* Try to figure out the name */
1351 if (dcip_to_name(mem_ctx, domain, pss, dcname)) {
1352 return True;
1355 /* We can not continue without the DC's name */
1356 winbind_add_failed_connection_entry(domain, dcs[fd_index].name,
1357 NT_STATUS_UNSUCCESSFUL);
1359 /* Throw away all arrays as we're doing this again. */
1360 TALLOC_FREE(dcs);
1361 num_dcs = 0;
1363 TALLOC_FREE(dcnames);
1364 num_dcnames = 0;
1366 TALLOC_FREE(addrs);
1367 num_addrs = 0;
1369 close(*fd);
1370 *fd = -1;
1372 goto again;
1375 static NTSTATUS cm_open_connection(struct winbindd_domain *domain,
1376 struct winbindd_cm_conn *new_conn)
1378 TALLOC_CTX *mem_ctx;
1379 NTSTATUS result;
1380 char *saf_servername = saf_fetch( domain->name );
1381 int retries;
1383 if ((mem_ctx = talloc_init("cm_open_connection")) == NULL) {
1384 SAFE_FREE(saf_servername);
1385 set_domain_offline(domain);
1386 return NT_STATUS_NO_MEMORY;
1389 /* we have to check the server affinity cache here since
1390 later we selecte a DC based on response time and not preference */
1392 /* Check the negative connection cache
1393 before talking to it. It going down may have
1394 triggered the reconnection. */
1396 if ( saf_servername && NT_STATUS_IS_OK(check_negative_conn_cache( domain->name, saf_servername))) {
1398 DEBUG(10,("cm_open_connection: saf_servername is '%s' for domain %s\n",
1399 saf_servername, domain->name ));
1401 /* convert an ip address to a name */
1402 if (is_ipaddress( saf_servername ) ) {
1403 fstring saf_name;
1404 struct sockaddr_storage ss;
1406 if (!interpret_string_addr(&ss, saf_servername,
1407 AI_NUMERICHOST)) {
1408 return NT_STATUS_UNSUCCESSFUL;
1410 if (dcip_to_name(mem_ctx, domain, &ss, saf_name )) {
1411 fstrcpy( domain->dcname, saf_name );
1412 } else {
1413 winbind_add_failed_connection_entry(
1414 domain, saf_servername,
1415 NT_STATUS_UNSUCCESSFUL);
1417 } else {
1418 fstrcpy( domain->dcname, saf_servername );
1421 SAFE_FREE( saf_servername );
1424 for (retries = 0; retries < 3; retries++) {
1425 int fd = -1;
1426 bool retry = False;
1428 result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
1430 DEBUG(10,("cm_open_connection: dcname is '%s' for domain %s\n",
1431 domain->dcname, domain->name ));
1433 if (*domain->dcname
1434 && NT_STATUS_IS_OK(check_negative_conn_cache( domain->name, domain->dcname))
1435 && (resolve_name(domain->dcname, &domain->dcaddr, 0x20)))
1437 struct sockaddr_storage *addrs = NULL;
1438 int num_addrs = 0;
1439 int dummy = 0;
1441 if (!add_sockaddr_to_array(mem_ctx, &domain->dcaddr, 445, &addrs, &num_addrs)) {
1442 set_domain_offline(domain);
1443 talloc_destroy(mem_ctx);
1444 return NT_STATUS_NO_MEMORY;
1446 if (!add_sockaddr_to_array(mem_ctx, &domain->dcaddr, 139, &addrs, &num_addrs)) {
1447 set_domain_offline(domain);
1448 talloc_destroy(mem_ctx);
1449 return NT_STATUS_NO_MEMORY;
1452 /* 5 second timeout. */
1453 if (!open_any_socket_out(addrs, num_addrs, 5000, &dummy, &fd)) {
1454 fd = -1;
1458 if ((fd == -1)
1459 && !find_new_dc(mem_ctx, domain, domain->dcname, &domain->dcaddr, &fd))
1461 /* This is the one place where we will
1462 set the global winbindd offline state
1463 to true, if a "WINBINDD_OFFLINE" entry
1464 is found in the winbindd cache. */
1465 set_global_winbindd_state_offline();
1466 break;
1469 new_conn->cli = NULL;
1471 result = cm_prepare_connection(domain, fd, domain->dcname,
1472 &new_conn->cli, &retry);
1474 if (!retry)
1475 break;
1478 if (NT_STATUS_IS_OK(result)) {
1480 winbindd_set_locator_kdc_envs(domain);
1482 if (domain->online == False) {
1483 /* We're changing state from offline to online. */
1484 set_global_winbindd_state_online();
1486 set_domain_online(domain);
1487 } else {
1488 /* Ensure we setup the retry handler. */
1489 set_domain_offline(domain);
1492 talloc_destroy(mem_ctx);
1493 return result;
1496 /* Close down all open pipes on a connection. */
1498 void invalidate_cm_connection(struct winbindd_cm_conn *conn)
1500 /* We're closing down a possibly dead
1501 connection. Don't have impossibly long (10s) timeouts. */
1503 if (conn->cli) {
1504 cli_set_timeout(conn->cli, 1000); /* 1 second. */
1507 if (conn->samr_pipe != NULL) {
1508 if (!cli_rpc_pipe_close(conn->samr_pipe)) {
1509 /* Ok, it must be dead. Drop timeout to 0.5 sec. */
1510 if (conn->cli) {
1511 cli_set_timeout(conn->cli, 500);
1514 conn->samr_pipe = NULL;
1517 if (conn->lsa_pipe != NULL) {
1518 if (!cli_rpc_pipe_close(conn->lsa_pipe)) {
1519 /* Ok, it must be dead. Drop timeout to 0.5 sec. */
1520 if (conn->cli) {
1521 cli_set_timeout(conn->cli, 500);
1524 conn->lsa_pipe = NULL;
1527 if (conn->netlogon_pipe != NULL) {
1528 if (!cli_rpc_pipe_close(conn->netlogon_pipe)) {
1529 /* Ok, it must be dead. Drop timeout to 0.5 sec. */
1530 if (conn->cli) {
1531 cli_set_timeout(conn->cli, 500);
1534 conn->netlogon_pipe = NULL;
1537 if (conn->cli) {
1538 cli_shutdown(conn->cli);
1541 conn->cli = NULL;
1544 void close_conns_after_fork(void)
1546 struct winbindd_domain *domain;
1548 for (domain = domain_list(); domain; domain = domain->next) {
1549 if (domain->conn.cli == NULL)
1550 continue;
1552 if (domain->conn.cli->fd == -1)
1553 continue;
1555 close(domain->conn.cli->fd);
1556 domain->conn.cli->fd = -1;
1560 static bool connection_ok(struct winbindd_domain *domain)
1562 if (domain->conn.cli == NULL) {
1563 DEBUG(8, ("connection_ok: Connection to %s for domain %s has NULL "
1564 "cli!\n", domain->dcname, domain->name));
1565 return False;
1568 if (!domain->conn.cli->initialised) {
1569 DEBUG(3, ("connection_ok: Connection to %s for domain %s was never "
1570 "initialised!\n", domain->dcname, domain->name));
1571 return False;
1574 if (domain->conn.cli->fd == -1) {
1575 DEBUG(3, ("connection_ok: Connection to %s for domain %s has died or was "
1576 "never started (fd == -1)\n",
1577 domain->dcname, domain->name));
1578 return False;
1581 if (domain->online == False) {
1582 DEBUG(3, ("connection_ok: Domain %s is offline\n", domain->name));
1583 return False;
1586 return True;
1589 /* Initialize a new connection up to the RPC BIND.
1590 Bypass online status check so always does network calls. */
1592 static NTSTATUS init_dc_connection_network(struct winbindd_domain *domain)
1594 NTSTATUS result;
1596 /* Internal connections never use the network. */
1597 if (domain->internal) {
1598 domain->initialized = True;
1599 return NT_STATUS_OK;
1602 if (connection_ok(domain)) {
1603 if (!domain->initialized) {
1604 set_dc_type_and_flags(domain);
1606 return NT_STATUS_OK;
1609 invalidate_cm_connection(&domain->conn);
1611 result = cm_open_connection(domain, &domain->conn);
1613 if (NT_STATUS_IS_OK(result) && !domain->initialized) {
1614 set_dc_type_and_flags(domain);
1617 return result;
1620 NTSTATUS init_dc_connection(struct winbindd_domain *domain)
1622 if (domain->initialized && !domain->online) {
1623 /* We check for online status elsewhere. */
1624 return NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
1627 return init_dc_connection_network(domain);
1630 /******************************************************************************
1631 Set the trust flags (direction and forest location) for a domain
1632 ******************************************************************************/
1634 static bool set_dc_type_and_flags_trustinfo( struct winbindd_domain *domain )
1636 struct winbindd_domain *our_domain;
1637 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1638 struct netr_DomainTrustList trusts;
1639 int i;
1640 uint32 flags = (NETR_TRUST_FLAG_IN_FOREST |
1641 NETR_TRUST_FLAG_OUTBOUND |
1642 NETR_TRUST_FLAG_INBOUND);
1643 struct rpc_pipe_client *cli;
1644 TALLOC_CTX *mem_ctx = NULL;
1646 DEBUG(5, ("set_dc_type_and_flags_trustinfo: domain %s\n", domain->name ));
1648 /* Our primary domain doesn't need to worry about trust flags.
1649 Force it to go through the network setup */
1650 if ( domain->primary ) {
1651 return False;
1654 our_domain = find_our_domain();
1656 if ( !connection_ok(our_domain) ) {
1657 DEBUG(3,("set_dc_type_and_flags_trustinfo: No connection to our domain!\n"));
1658 return False;
1661 /* This won't work unless our domain is AD */
1663 if ( !our_domain->active_directory ) {
1664 return False;
1667 /* Use DsEnumerateDomainTrusts to get us the trust direction
1668 and type */
1670 result = cm_connect_netlogon(our_domain, &cli);
1672 if (!NT_STATUS_IS_OK(result)) {
1673 DEBUG(5, ("set_dc_type_and_flags_trustinfo: Could not open "
1674 "a connection to %s for PIPE_NETLOGON (%s)\n",
1675 domain->name, nt_errstr(result)));
1676 return False;
1679 if ( (mem_ctx = talloc_init("set_dc_type_and_flags_trustinfo")) == NULL ) {
1680 DEBUG(0,("set_dc_type_and_flags_trustinfo: talloc_init() failed!\n"));
1681 return False;
1684 result = rpccli_netr_DsrEnumerateDomainTrusts(cli, mem_ctx,
1685 cli->cli->desthost,
1686 flags,
1687 &trusts,
1688 NULL);
1689 if (!NT_STATUS_IS_OK(result)) {
1690 DEBUG(0,("set_dc_type_and_flags_trustinfo: "
1691 "failed to query trusted domain list: %s\n",
1692 nt_errstr(result)));
1693 talloc_destroy(mem_ctx);
1694 return false;
1697 /* Now find the domain name and get the flags */
1699 for ( i=0; i<trusts.count; i++ ) {
1700 if ( strequal( domain->name, trusts.array[i].netbios_name) ) {
1701 domain->domain_flags = trusts.array[i].trust_flags;
1702 domain->domain_type = trusts.array[i].trust_type;
1703 domain->domain_trust_attribs = trusts.array[i].trust_attributes;
1705 if ( domain->domain_type == NETR_TRUST_TYPE_UPLEVEL )
1706 domain->active_directory = True;
1708 /* This flag is only set if the domain is *our*
1709 primary domain and the primary domain is in
1710 native mode */
1712 domain->native_mode = (domain->domain_flags & NETR_TRUST_FLAG_NATIVE);
1714 DEBUG(5, ("set_dc_type_and_flags_trustinfo: domain %s is %sin "
1715 "native mode.\n", domain->name,
1716 domain->native_mode ? "" : "NOT "));
1718 DEBUG(5,("set_dc_type_and_flags_trustinfo: domain %s is %s"
1719 "running active directory.\n", domain->name,
1720 domain->active_directory ? "" : "NOT "));
1723 domain->initialized = True;
1725 if ( !winbindd_can_contact_domain( domain) )
1726 domain->internal = True;
1728 break;
1732 talloc_destroy( mem_ctx );
1734 return domain->initialized;
1737 /******************************************************************************
1738 We can 'sense' certain things about the DC by it's replies to certain
1739 questions.
1741 This tells us if this particular remote server is Active Directory, and if it
1742 is native mode.
1743 ******************************************************************************/
1745 static void set_dc_type_and_flags_connect( struct winbindd_domain *domain )
1747 NTSTATUS result;
1748 WERROR werr;
1749 TALLOC_CTX *mem_ctx = NULL;
1750 struct rpc_pipe_client *cli;
1751 POLICY_HND pol;
1752 union dssetup_DsRoleInfo info;
1753 union lsa_PolicyInformation *lsa_info = NULL;
1755 if (!connection_ok(domain)) {
1756 return;
1759 mem_ctx = talloc_init("set_dc_type_and_flags on domain %s\n",
1760 domain->name);
1761 if (!mem_ctx) {
1762 DEBUG(1, ("set_dc_type_and_flags_connect: talloc_init() failed\n"));
1763 return;
1766 DEBUG(5, ("set_dc_type_and_flags_connect: domain %s\n", domain->name ));
1768 cli = cli_rpc_pipe_open_noauth(domain->conn.cli, PI_DSSETUP,
1769 &result);
1771 if (cli == NULL) {
1772 DEBUG(5, ("set_dc_type_and_flags_connect: Could not bind to "
1773 "PI_DSSETUP on domain %s: (%s)\n",
1774 domain->name, nt_errstr(result)));
1776 /* if this is just a non-AD domain we need to continue
1777 * identifying so that we can in the end return with
1778 * domain->initialized = True - gd */
1780 goto no_dssetup;
1783 result = rpccli_dssetup_DsRoleGetPrimaryDomainInformation(cli, mem_ctx,
1784 DS_ROLE_BASIC_INFORMATION,
1785 &info,
1786 &werr);
1787 cli_rpc_pipe_close(cli);
1789 if (!NT_STATUS_IS_OK(result)) {
1790 DEBUG(5, ("set_dc_type_and_flags_connect: rpccli_ds_getprimarydominfo "
1791 "on domain %s failed: (%s)\n",
1792 domain->name, nt_errstr(result)));
1794 /* older samba3 DCs will return DCERPC_FAULT_OP_RNG_ERROR for
1795 * every opcode on the DSSETUP pipe, continue with
1796 * no_dssetup mode here as well to get domain->initialized
1797 * set - gd */
1799 if (NT_STATUS_V(result) == DCERPC_FAULT_OP_RNG_ERROR) {
1800 goto no_dssetup;
1803 TALLOC_FREE(mem_ctx);
1804 return;
1807 if ((info.basic.flags & DS_ROLE_PRIMARY_DS_RUNNING) &&
1808 !(info.basic.flags & DS_ROLE_PRIMARY_DS_MIXED_MODE)) {
1809 domain->native_mode = True;
1810 } else {
1811 domain->native_mode = False;
1814 no_dssetup:
1815 cli = cli_rpc_pipe_open_noauth(domain->conn.cli, PI_LSARPC, &result);
1817 if (cli == NULL) {
1818 DEBUG(5, ("set_dc_type_and_flags_connect: Could not bind to "
1819 "PI_LSARPC on domain %s: (%s)\n",
1820 domain->name, nt_errstr(result)));
1821 cli_rpc_pipe_close(cli);
1822 TALLOC_FREE(mem_ctx);
1823 return;
1826 result = rpccli_lsa_open_policy2(cli, mem_ctx, True,
1827 SEC_RIGHTS_MAXIMUM_ALLOWED, &pol);
1829 if (NT_STATUS_IS_OK(result)) {
1830 /* This particular query is exactly what Win2k clients use
1831 to determine that the DC is active directory */
1832 result = rpccli_lsa_QueryInfoPolicy2(cli, mem_ctx,
1833 &pol,
1834 LSA_POLICY_INFO_DNS,
1835 &lsa_info);
1838 if (NT_STATUS_IS_OK(result)) {
1839 domain->active_directory = True;
1841 if (lsa_info->dns.name.string) {
1842 fstrcpy(domain->name, lsa_info->dns.name.string);
1845 if (lsa_info->dns.dns_domain.string) {
1846 fstrcpy(domain->alt_name,
1847 lsa_info->dns.dns_domain.string);
1850 /* See if we can set some domain trust flags about
1851 ourself */
1853 if (lsa_info->dns.dns_forest.string) {
1854 fstrcpy(domain->forest_name,
1855 lsa_info->dns.dns_forest.string);
1857 if (strequal(domain->forest_name, domain->alt_name)) {
1858 domain->domain_flags |= NETR_TRUST_FLAG_TREEROOT;
1862 if (lsa_info->dns.sid) {
1863 sid_copy(&domain->sid, lsa_info->dns.sid);
1865 } else {
1866 domain->active_directory = False;
1868 result = rpccli_lsa_open_policy(cli, mem_ctx, True,
1869 SEC_RIGHTS_MAXIMUM_ALLOWED,
1870 &pol);
1872 if (!NT_STATUS_IS_OK(result)) {
1873 goto done;
1876 result = rpccli_lsa_QueryInfoPolicy(cli, mem_ctx,
1877 &pol,
1878 LSA_POLICY_INFO_ACCOUNT_DOMAIN,
1879 &lsa_info);
1881 if (NT_STATUS_IS_OK(result)) {
1883 if (lsa_info->account_domain.name.string) {
1884 fstrcpy(domain->name,
1885 lsa_info->account_domain.name.string);
1888 if (lsa_info->account_domain.sid) {
1889 sid_copy(&domain->sid, lsa_info->account_domain.sid);
1893 done:
1895 DEBUG(5, ("set_dc_type_and_flags_connect: domain %s is %sin native mode.\n",
1896 domain->name, domain->native_mode ? "" : "NOT "));
1898 DEBUG(5,("set_dc_type_and_flags_connect: domain %s is %srunning active directory.\n",
1899 domain->name, domain->active_directory ? "" : "NOT "));
1901 cli_rpc_pipe_close(cli);
1903 TALLOC_FREE(mem_ctx);
1905 domain->initialized = True;
1908 /**********************************************************************
1909 Set the domain_flags (trust attributes, domain operating modes, etc...
1910 ***********************************************************************/
1912 static void set_dc_type_and_flags( struct winbindd_domain *domain )
1914 /* we always have to contact our primary domain */
1916 if ( domain->primary ) {
1917 DEBUG(10,("set_dc_type_and_flags: setting up flags for "
1918 "primary domain\n"));
1919 set_dc_type_and_flags_connect( domain );
1920 return;
1923 /* Use our DC to get the information if possible */
1925 if ( !set_dc_type_and_flags_trustinfo( domain ) ) {
1926 /* Otherwise, fallback to contacting the
1927 domain directly */
1928 set_dc_type_and_flags_connect( domain );
1931 return;
1936 /**********************************************************************
1937 ***********************************************************************/
1939 static bool cm_get_schannel_dcinfo(struct winbindd_domain *domain,
1940 struct dcinfo **ppdc)
1942 NTSTATUS result;
1943 struct rpc_pipe_client *netlogon_pipe;
1945 if (lp_client_schannel() == False) {
1946 return False;
1949 result = cm_connect_netlogon(domain, &netlogon_pipe);
1950 if (!NT_STATUS_IS_OK(result)) {
1951 return False;
1954 /* Return a pointer to the struct dcinfo from the
1955 netlogon pipe. */
1957 if (!domain->conn.netlogon_pipe->dc) {
1958 return false;
1961 *ppdc = domain->conn.netlogon_pipe->dc;
1962 return True;
1965 NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
1966 struct rpc_pipe_client **cli, POLICY_HND *sam_handle)
1968 struct winbindd_cm_conn *conn;
1969 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1970 fstring conn_pwd;
1971 struct dcinfo *p_dcinfo;
1972 char *machine_password = NULL;
1973 char *machine_account = NULL;
1974 char *domain_name = NULL;
1976 result = init_dc_connection(domain);
1977 if (!NT_STATUS_IS_OK(result)) {
1978 return result;
1981 conn = &domain->conn;
1983 if (conn->samr_pipe != NULL) {
1984 goto done;
1989 * No SAMR pipe yet. Attempt to get an NTLMSSP SPNEGO authenticated
1990 * sign and sealed pipe using the machine account password by
1991 * preference. If we can't - try schannel, if that fails, try
1992 * anonymous.
1995 pwd_get_cleartext(&conn->cli->pwd, conn_pwd);
1996 if ((conn->cli->user_name[0] == '\0') ||
1997 (conn->cli->domain[0] == '\0') ||
1998 (conn_pwd[0] == '\0'))
2000 result = get_trust_creds(domain, &machine_password,
2001 &machine_account, NULL);
2002 if (!NT_STATUS_IS_OK(result)) {
2003 DEBUG(10, ("cm_connect_sam: No no user available for "
2004 "domain %s, trying schannel\n", conn->cli->domain));
2005 goto schannel;
2007 domain_name = domain->name;
2008 } else {
2009 machine_password = SMB_STRDUP(conn_pwd);
2010 machine_account = SMB_STRDUP(conn->cli->user_name);
2011 domain_name = conn->cli->domain;
2014 if (!machine_password || !machine_account) {
2015 result = NT_STATUS_NO_MEMORY;
2016 goto done;
2019 /* We have an authenticated connection. Use a NTLMSSP SPNEGO
2020 authenticated SAMR pipe with sign & seal. */
2021 conn->samr_pipe =
2022 cli_rpc_pipe_open_spnego_ntlmssp(conn->cli, PI_SAMR,
2023 PIPE_AUTH_LEVEL_PRIVACY,
2024 domain_name,
2025 machine_account,
2026 machine_password, &result);
2028 if (conn->samr_pipe == NULL) {
2029 DEBUG(10,("cm_connect_sam: failed to connect to SAMR "
2030 "pipe for domain %s using NTLMSSP "
2031 "authenticated pipe: user %s\\%s. Error was "
2032 "%s\n", domain->name, domain_name,
2033 machine_account, nt_errstr(result)));
2034 goto schannel;
2037 DEBUG(10,("cm_connect_sam: connected to SAMR pipe for "
2038 "domain %s using NTLMSSP authenticated "
2039 "pipe: user %s\\%s\n", domain->name,
2040 domain_name, machine_account));
2042 result = rpccli_samr_Connect2(conn->samr_pipe, mem_ctx,
2043 conn->samr_pipe->cli->desthost,
2044 SEC_RIGHTS_MAXIMUM_ALLOWED,
2045 &conn->sam_connect_handle);
2046 if (NT_STATUS_IS_OK(result)) {
2047 goto open_domain;
2049 DEBUG(10,("cm_connect_sam: ntlmssp-sealed rpccli_samr_Connect2 "
2050 "failed for domain %s, error was %s. Trying schannel\n",
2051 domain->name, nt_errstr(result) ));
2052 cli_rpc_pipe_close(conn->samr_pipe);
2054 schannel:
2056 /* Fall back to schannel if it's a W2K pre-SP1 box. */
2058 if (!cm_get_schannel_dcinfo(domain, &p_dcinfo)) {
2059 /* If this call fails - conn->cli can now be NULL ! */
2060 DEBUG(10, ("cm_connect_sam: Could not get schannel auth info "
2061 "for domain %s, trying anon\n", domain->name));
2062 goto anonymous;
2064 conn->samr_pipe = cli_rpc_pipe_open_schannel_with_key
2065 (conn->cli, PI_SAMR, PIPE_AUTH_LEVEL_PRIVACY,
2066 domain->name, p_dcinfo, &result);
2068 if (conn->samr_pipe == NULL) {
2069 DEBUG(10,("cm_connect_sam: failed to connect to SAMR pipe for "
2070 "domain %s using schannel. Error was %s\n",
2071 domain->name, nt_errstr(result) ));
2072 goto anonymous;
2074 DEBUG(10,("cm_connect_sam: connected to SAMR pipe for domain %s using "
2075 "schannel.\n", domain->name ));
2077 result = rpccli_samr_Connect2(conn->samr_pipe, mem_ctx,
2078 conn->samr_pipe->cli->desthost,
2079 SEC_RIGHTS_MAXIMUM_ALLOWED,
2080 &conn->sam_connect_handle);
2081 if (NT_STATUS_IS_OK(result)) {
2082 goto open_domain;
2084 DEBUG(10,("cm_connect_sam: schannel-sealed rpccli_samr_Connect2 failed "
2085 "for domain %s, error was %s. Trying anonymous\n",
2086 domain->name, nt_errstr(result) ));
2087 cli_rpc_pipe_close(conn->samr_pipe);
2089 anonymous:
2091 /* Finally fall back to anonymous. */
2092 conn->samr_pipe = cli_rpc_pipe_open_noauth(conn->cli, PI_SAMR,
2093 &result);
2095 if (conn->samr_pipe == NULL) {
2096 result = NT_STATUS_PIPE_NOT_AVAILABLE;
2097 goto done;
2100 result = rpccli_samr_Connect2(conn->samr_pipe, mem_ctx,
2101 conn->samr_pipe->cli->desthost,
2102 SEC_RIGHTS_MAXIMUM_ALLOWED,
2103 &conn->sam_connect_handle);
2104 if (!NT_STATUS_IS_OK(result)) {
2105 DEBUG(10,("cm_connect_sam: rpccli_samr_Connect2 failed "
2106 "for domain %s Error was %s\n",
2107 domain->name, nt_errstr(result) ));
2108 goto done;
2111 open_domain:
2112 result = rpccli_samr_OpenDomain(conn->samr_pipe,
2113 mem_ctx,
2114 &conn->sam_connect_handle,
2115 SEC_RIGHTS_MAXIMUM_ALLOWED,
2116 &domain->sid,
2117 &conn->sam_domain_handle);
2119 done:
2121 if (!NT_STATUS_IS_OK(result)) {
2122 invalidate_cm_connection(conn);
2123 return result;
2126 *cli = conn->samr_pipe;
2127 *sam_handle = conn->sam_domain_handle;
2128 SAFE_FREE(machine_password);
2129 SAFE_FREE(machine_account);
2130 return result;
2133 NTSTATUS cm_connect_lsa(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
2134 struct rpc_pipe_client **cli, POLICY_HND *lsa_policy)
2136 struct winbindd_cm_conn *conn;
2137 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
2138 fstring conn_pwd;
2139 struct dcinfo *p_dcinfo;
2141 result = init_dc_connection(domain);
2142 if (!NT_STATUS_IS_OK(result))
2143 return result;
2145 conn = &domain->conn;
2147 if (conn->lsa_pipe != NULL) {
2148 goto done;
2151 pwd_get_cleartext(&conn->cli->pwd, conn_pwd);
2152 if ((conn->cli->user_name[0] == '\0') ||
2153 (conn->cli->domain[0] == '\0') ||
2154 (conn_pwd[0] == '\0')) {
2155 DEBUG(10, ("cm_connect_lsa: No no user available for "
2156 "domain %s, trying schannel\n", conn->cli->domain));
2157 goto schannel;
2160 /* We have an authenticated connection. Use a NTLMSSP SPNEGO
2161 * authenticated LSA pipe with sign & seal. */
2162 conn->lsa_pipe = cli_rpc_pipe_open_spnego_ntlmssp
2163 (conn->cli, PI_LSARPC, PIPE_AUTH_LEVEL_PRIVACY,
2164 conn->cli->domain, conn->cli->user_name, conn_pwd, &result);
2166 if (conn->lsa_pipe == NULL) {
2167 DEBUG(10,("cm_connect_lsa: failed to connect to LSA pipe for "
2168 "domain %s using NTLMSSP authenticated pipe: user "
2169 "%s\\%s. Error was %s. Trying schannel.\n",
2170 domain->name, conn->cli->domain,
2171 conn->cli->user_name, nt_errstr(result)));
2172 goto schannel;
2175 DEBUG(10,("cm_connect_lsa: connected to LSA pipe for domain %s using "
2176 "NTLMSSP authenticated pipe: user %s\\%s\n",
2177 domain->name, conn->cli->domain, conn->cli->user_name ));
2179 result = rpccli_lsa_open_policy(conn->lsa_pipe, mem_ctx, True,
2180 SEC_RIGHTS_MAXIMUM_ALLOWED,
2181 &conn->lsa_policy);
2182 if (NT_STATUS_IS_OK(result)) {
2183 goto done;
2186 DEBUG(10,("cm_connect_lsa: rpccli_lsa_open_policy failed, trying "
2187 "schannel\n"));
2189 cli_rpc_pipe_close(conn->lsa_pipe);
2191 schannel:
2193 /* Fall back to schannel if it's a W2K pre-SP1 box. */
2195 if (!cm_get_schannel_dcinfo(domain, &p_dcinfo)) {
2196 /* If this call fails - conn->cli can now be NULL ! */
2197 DEBUG(10, ("cm_connect_lsa: Could not get schannel auth info "
2198 "for domain %s, trying anon\n", domain->name));
2199 goto anonymous;
2201 conn->lsa_pipe = cli_rpc_pipe_open_schannel_with_key
2202 (conn->cli, PI_LSARPC, PIPE_AUTH_LEVEL_PRIVACY,
2203 domain->name, p_dcinfo, &result);
2205 if (conn->lsa_pipe == NULL) {
2206 DEBUG(10,("cm_connect_lsa: failed to connect to LSA pipe for "
2207 "domain %s using schannel. Error was %s\n",
2208 domain->name, nt_errstr(result) ));
2209 goto anonymous;
2211 DEBUG(10,("cm_connect_lsa: connected to LSA pipe for domain %s using "
2212 "schannel.\n", domain->name ));
2214 result = rpccli_lsa_open_policy(conn->lsa_pipe, mem_ctx, True,
2215 SEC_RIGHTS_MAXIMUM_ALLOWED,
2216 &conn->lsa_policy);
2217 if (NT_STATUS_IS_OK(result)) {
2218 goto done;
2221 DEBUG(10,("cm_connect_lsa: rpccli_lsa_open_policy failed, trying "
2222 "anonymous\n"));
2224 cli_rpc_pipe_close(conn->lsa_pipe);
2226 anonymous:
2228 conn->lsa_pipe = cli_rpc_pipe_open_noauth(conn->cli, PI_LSARPC,
2229 &result);
2230 if (conn->lsa_pipe == NULL) {
2231 result = NT_STATUS_PIPE_NOT_AVAILABLE;
2232 goto done;
2235 result = rpccli_lsa_open_policy(conn->lsa_pipe, mem_ctx, True,
2236 SEC_RIGHTS_MAXIMUM_ALLOWED,
2237 &conn->lsa_policy);
2238 done:
2239 if (!NT_STATUS_IS_OK(result)) {
2240 invalidate_cm_connection(conn);
2241 return result;
2244 *cli = conn->lsa_pipe;
2245 *lsa_policy = conn->lsa_policy;
2246 return result;
2249 /****************************************************************************
2250 Open the netlogon pipe to this DC. Use schannel if specified in client conf.
2251 session key stored in conn->netlogon_pipe->dc->sess_key.
2252 ****************************************************************************/
2254 NTSTATUS cm_connect_netlogon(struct winbindd_domain *domain,
2255 struct rpc_pipe_client **cli)
2257 struct winbindd_cm_conn *conn;
2258 NTSTATUS result;
2260 uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
2261 uint8 mach_pwd[16];
2262 uint32 sec_chan_type;
2263 const char *account_name;
2264 struct rpc_pipe_client *netlogon_pipe = NULL;
2266 *cli = NULL;
2268 result = init_dc_connection(domain);
2269 if (!NT_STATUS_IS_OK(result)) {
2270 return result;
2273 conn = &domain->conn;
2275 if (conn->netlogon_pipe != NULL) {
2276 *cli = conn->netlogon_pipe;
2277 return NT_STATUS_OK;
2280 netlogon_pipe = cli_rpc_pipe_open_noauth(conn->cli, PI_NETLOGON,
2281 &result);
2282 if (netlogon_pipe == NULL) {
2283 return result;
2286 if ((!IS_DC) && (!domain->primary)) {
2287 /* Clear the schannel request bit and drop down */
2288 neg_flags &= ~NETLOGON_NEG_SCHANNEL;
2289 goto no_schannel;
2292 if (lp_client_schannel() != False) {
2293 neg_flags |= NETLOGON_NEG_SCHANNEL;
2296 if (!get_trust_pw_hash(domain->name, mach_pwd, &account_name,
2297 &sec_chan_type))
2299 cli_rpc_pipe_close(netlogon_pipe);
2300 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
2303 result = rpccli_netlogon_setup_creds(
2304 netlogon_pipe,
2305 domain->dcname, /* server name. */
2306 domain->name, /* domain name */
2307 global_myname(), /* client name */
2308 account_name, /* machine account */
2309 mach_pwd, /* machine password */
2310 sec_chan_type, /* from get_trust_pw */
2311 &neg_flags);
2313 if (!NT_STATUS_IS_OK(result)) {
2314 cli_rpc_pipe_close(netlogon_pipe);
2315 return result;
2318 if ((lp_client_schannel() == True) &&
2319 ((neg_flags & NETLOGON_NEG_SCHANNEL) == 0)) {
2320 DEBUG(3, ("Server did not offer schannel\n"));
2321 cli_rpc_pipe_close(netlogon_pipe);
2322 return NT_STATUS_ACCESS_DENIED;
2325 no_schannel:
2326 if ((lp_client_schannel() == False) ||
2327 ((neg_flags & NETLOGON_NEG_SCHANNEL) == 0)) {
2329 * NetSamLogonEx only works for schannel
2331 domain->can_do_samlogon_ex = False;
2333 /* We're done - just keep the existing connection to NETLOGON
2334 * open */
2335 conn->netlogon_pipe = netlogon_pipe;
2336 *cli = conn->netlogon_pipe;
2337 return NT_STATUS_OK;
2340 /* Using the credentials from the first pipe, open a signed and sealed
2341 second netlogon pipe. The session key is stored in the schannel
2342 part of the new pipe auth struct.
2345 conn->netlogon_pipe =
2346 cli_rpc_pipe_open_schannel_with_key(conn->cli,
2347 PI_NETLOGON,
2348 PIPE_AUTH_LEVEL_PRIVACY,
2349 domain->name,
2350 netlogon_pipe->dc,
2351 &result);
2353 /* We can now close the initial netlogon pipe. */
2354 cli_rpc_pipe_close(netlogon_pipe);
2356 if (conn->netlogon_pipe == NULL) {
2357 DEBUG(3, ("Could not open schannel'ed NETLOGON pipe. Error "
2358 "was %s\n", nt_errstr(result)));
2360 /* make sure we return something besides OK */
2361 return !NT_STATUS_IS_OK(result) ? result : NT_STATUS_PIPE_NOT_AVAILABLE;
2365 * Try NetSamLogonEx for AD domains
2367 domain->can_do_samlogon_ex = domain->active_directory;
2369 *cli = conn->netlogon_pipe;
2370 return NT_STATUS_OK;