r25407: Revert Longhorn join patch as it is not correct for the 3.2 tree.
[Samba/bb.git] / source3 / winbindd / winbindd_cm.c
blob9ffb3dfb239bb6dc028c6a1ae8737d62a6141495
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 in_addr ip;
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, const 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();
177 /* Stop zombies */
178 CatchChild();
180 child_pid = sys_fork();
182 if (child_pid == -1) {
183 DEBUG(0, ("fork_child_dc_connect: Could not fork: %s\n", strerror(errno)));
184 return False;
187 if (child_pid != 0) {
188 /* Parent */
189 messaging_register(winbind_messaging_context(), NULL,
190 MSG_WINBIND_TRY_TO_GO_ONLINE,
191 msg_try_to_go_online);
192 messaging_register(winbind_messaging_context(), NULL,
193 MSG_WINBIND_FAILED_TO_GO_ONLINE,
194 msg_failed_to_go_online);
195 return True;
198 /* Child. */
200 /* Leave messages blocked - we will never process one. */
202 /* tdb needs special fork handling */
203 if (tdb_reopen_all(1) == -1) {
204 DEBUG(0,("tdb_reopen_all failed.\n"));
205 _exit(0);
208 close_conns_after_fork();
210 if (!override_logfile) {
211 pstring logfile;
212 pstr_sprintf(logfile, "%s/log.winbindd-dc-connect", dyn_LOGFILEBASE);
213 lp_set_logfile(logfile);
214 reopen_logs();
217 mem_ctx = talloc_init("fork_child_dc_connect");
218 if (!mem_ctx) {
219 DEBUG(0,("talloc_init failed.\n"));
220 _exit(0);
223 if ((!get_dcs(mem_ctx, domain, &dcs, &num_dcs)) || (num_dcs == 0)) {
224 /* Still offline ? Can't find DC's. */
225 messaging_send_buf(winbind_messaging_context(),
226 pid_to_procid(parent_pid),
227 MSG_WINBIND_FAILED_TO_GO_ONLINE,
228 (uint8 *)domain->name,
229 strlen(domain->name)+1);
230 _exit(0);
233 /* We got a DC. Send a message to our parent to get it to
234 try and do the same. */
236 messaging_send_buf(winbind_messaging_context(),
237 pid_to_procid(parent_pid),
238 MSG_WINBIND_TRY_TO_GO_ONLINE,
239 (uint8 *)domain->name,
240 strlen(domain->name)+1);
241 _exit(0);
244 /****************************************************************
245 Handler triggered if we're offline to try and detect a DC.
246 ****************************************************************/
248 static void check_domain_online_handler(struct event_context *ctx,
249 struct timed_event *te,
250 const struct timeval *now,
251 void *private_data)
253 struct winbindd_domain *domain =
254 (struct winbindd_domain *)private_data;
256 DEBUG(10,("check_domain_online_handler: called for domain "
257 "%s (online = %s)\n", domain->name,
258 domain->online ? "True" : "False" ));
260 TALLOC_FREE(domain->check_online_event);
262 /* Are we still in "startup" mode ? */
264 if (domain->startup && (now->tv_sec > domain->startup_time + 30)) {
265 /* No longer in "startup" mode. */
266 DEBUG(10,("check_domain_online_handler: domain %s no longer in 'startup' mode.\n",
267 domain->name ));
268 domain->startup = False;
271 /* We've been told to stay offline, so stay
272 that way. */
274 if (get_global_winbindd_state_offline()) {
275 DEBUG(10,("check_domain_online_handler: domain %s remaining globally offline\n",
276 domain->name ));
277 return;
280 /* Fork a child to test if it can contact a DC.
281 If it can then send ourselves a message to
282 cause a reconnect. */
284 fork_child_dc_connect(domain);
287 /****************************************************************
288 If we're still offline setup the timeout check.
289 ****************************************************************/
291 static void calc_new_online_timeout_check(struct winbindd_domain *domain)
293 int wbc = lp_winbind_cache_time();
295 if (domain->startup) {
296 domain->check_online_timeout = 10;
297 } else if (domain->check_online_timeout < wbc) {
298 domain->check_online_timeout = wbc;
302 /****************************************************************
303 Set domain offline and also add handler to put us back online
304 if we detect a DC.
305 ****************************************************************/
307 void set_domain_offline(struct winbindd_domain *domain)
309 DEBUG(10,("set_domain_offline: called for domain %s\n",
310 domain->name ));
312 TALLOC_FREE(domain->check_online_event);
314 if (domain->internal) {
315 DEBUG(3,("set_domain_offline: domain %s is internal - logic error.\n",
316 domain->name ));
317 return;
320 domain->online = False;
322 /* Offline domains are always initialized. They're
323 re-initialized when they go back online. */
325 domain->initialized = True;
327 /* We only add the timeout handler that checks and
328 allows us to go back online when we've not
329 been told to remain offline. */
331 if (get_global_winbindd_state_offline()) {
332 DEBUG(10,("set_domain_offline: domain %s remaining globally offline\n",
333 domain->name ));
334 return;
337 /* If we're in statup mode, check again in 10 seconds, not in
338 lp_winbind_cache_time() seconds (which is 5 mins by default). */
340 calc_new_online_timeout_check(domain);
342 domain->check_online_event = event_add_timed(winbind_event_context(),
343 NULL,
344 timeval_current_ofs(domain->check_online_timeout,0),
345 "check_domain_online_handler",
346 check_domain_online_handler,
347 domain);
349 /* The above *has* to succeed for winbindd to work. */
350 if (!domain->check_online_event) {
351 smb_panic("set_domain_offline: failed to add online handler");
354 DEBUG(10,("set_domain_offline: added event handler for domain %s\n",
355 domain->name ));
357 /* Send an offline message to the idmap child when our
358 primary domain goes offline */
360 if ( domain->primary ) {
361 struct winbindd_child *idmap = idmap_child();
363 if ( idmap->pid != 0 ) {
364 messaging_send_buf(winbind_messaging_context(),
365 pid_to_procid(idmap->pid),
366 MSG_WINBIND_OFFLINE,
367 (uint8 *)domain->name,
368 strlen(domain->name)+1);
372 return;
375 /****************************************************************
376 Set domain online - if allowed.
377 ****************************************************************/
379 static void set_domain_online(struct winbindd_domain *domain)
381 struct timeval now;
383 DEBUG(10,("set_domain_online: called for domain %s\n",
384 domain->name ));
386 if (domain->internal) {
387 DEBUG(3,("set_domain_online: domain %s is internal - logic error.\n",
388 domain->name ));
389 return;
392 if (get_global_winbindd_state_offline()) {
393 DEBUG(10,("set_domain_online: domain %s remaining globally offline\n",
394 domain->name ));
395 return;
398 winbindd_set_locator_kdc_envs(domain);
400 /* If we are waiting to get a krb5 ticket, trigger immediately. */
401 GetTimeOfDay(&now);
402 set_event_dispatch_time(winbind_event_context(),
403 "krb5_ticket_gain_handler", now);
405 /* Ok, we're out of any startup mode now... */
406 domain->startup = False;
408 if (domain->online == False) {
409 /* We were offline - now we're online. We default to
410 using the MS-RPC backend if we started offline,
411 and if we're going online for the first time we
412 should really re-initialize the backends and the
413 checks to see if we're talking to an AD or NT domain.
416 domain->initialized = False;
418 /* 'reconnect_methods' is the MS-RPC backend. */
419 if (domain->backend == &reconnect_methods) {
420 domain->backend = NULL;
424 /* Ensure we have no online timeout checks. */
425 domain->check_online_timeout = 0;
426 TALLOC_FREE(domain->check_online_event);
428 /* Ensure we ignore any pending child messages. */
429 messaging_deregister(winbind_messaging_context(),
430 MSG_WINBIND_TRY_TO_GO_ONLINE, NULL);
431 messaging_deregister(winbind_messaging_context(),
432 MSG_WINBIND_FAILED_TO_GO_ONLINE, NULL);
434 domain->online = True;
436 /* Send an online message to the idmap child when our
437 primary domain comes online */
439 if ( domain->primary ) {
440 struct winbindd_child *idmap = idmap_child();
442 if ( idmap->pid != 0 ) {
443 messaging_send_buf(winbind_messaging_context(),
444 pid_to_procid(idmap->pid),
445 MSG_WINBIND_ONLINE,
446 (uint8 *)domain->name,
447 strlen(domain->name)+1);
451 return;
454 /****************************************************************
455 Requested to set a domain online.
456 ****************************************************************/
458 void set_domain_online_request(struct winbindd_domain *domain)
460 struct timeval tev;
462 DEBUG(10,("set_domain_online_request: called for domain %s\n",
463 domain->name ));
465 if (get_global_winbindd_state_offline()) {
466 DEBUG(10,("set_domain_online_request: domain %s remaining globally offline\n",
467 domain->name ));
468 return;
471 /* We've been told it's safe to go online and
472 try and connect to a DC. But I don't believe it
473 because network manager seems to lie.
474 Wait at least 5 seconds. Heuristics suck... */
476 if (!domain->check_online_event) {
477 /* If we've come from being globally offline we
478 don't have a check online event handler set.
479 We need to add one now we're trying to go
480 back online. */
482 DEBUG(10,("set_domain_online_request: domain %s was globally offline.\n",
483 domain->name ));
485 domain->check_online_event = event_add_timed(winbind_event_context(),
486 NULL,
487 timeval_current_ofs(5, 0),
488 "check_domain_online_handler",
489 check_domain_online_handler,
490 domain);
492 /* The above *has* to succeed for winbindd to work. */
493 if (!domain->check_online_event) {
494 smb_panic("set_domain_online_request: failed to add online handler");
498 GetTimeOfDay(&tev);
500 /* Go into "startup" mode again. */
501 domain->startup_time = tev.tv_sec;
502 domain->startup = True;
504 tev.tv_sec += 5;
506 set_event_dispatch_time(winbind_event_context(), "check_domain_online_handler", tev);
509 /****************************************************************
510 Add -ve connection cache entries for domain and realm.
511 ****************************************************************/
513 void winbind_add_failed_connection_entry(const struct winbindd_domain *domain,
514 const char *server,
515 NTSTATUS result)
517 add_failed_connection_entry(domain->name, server, result);
518 /* If this was the saf name for the last thing we talked to,
519 remove it. */
520 saf_delete(domain->name);
521 if (*domain->alt_name) {
522 add_failed_connection_entry(domain->alt_name, server, result);
523 saf_delete(domain->alt_name);
525 winbindd_unset_locator_kdc_env(domain);
528 /* Choose between anonymous or authenticated connections. We need to use
529 an authenticated connection if DCs have the RestrictAnonymous registry
530 entry set > 0, or the "Additional restrictions for anonymous
531 connections" set in the win2k Local Security Policy.
533 Caller to free() result in domain, username, password
536 static void cm_get_ipc_userpass(char **username, char **domain, char **password)
538 *username = (char *)secrets_fetch(SECRETS_AUTH_USER, NULL);
539 *domain = (char *)secrets_fetch(SECRETS_AUTH_DOMAIN, NULL);
540 *password = (char *)secrets_fetch(SECRETS_AUTH_PASSWORD, NULL);
542 if (*username && **username) {
544 if (!*domain || !**domain)
545 *domain = smb_xstrdup(lp_workgroup());
547 if (!*password || !**password)
548 *password = smb_xstrdup("");
550 DEBUG(3, ("cm_get_ipc_userpass: Retrieved auth-user from secrets.tdb [%s\\%s]\n",
551 *domain, *username));
553 } else {
554 DEBUG(3, ("cm_get_ipc_userpass: No auth-user defined\n"));
555 *username = smb_xstrdup("");
556 *domain = smb_xstrdup("");
557 *password = smb_xstrdup("");
561 static BOOL get_dc_name_via_netlogon(const struct winbindd_domain *domain,
562 fstring dcname, struct in_addr *dc_ip)
564 struct winbindd_domain *our_domain = NULL;
565 struct rpc_pipe_client *netlogon_pipe = NULL;
566 NTSTATUS result;
567 WERROR werr;
568 TALLOC_CTX *mem_ctx;
569 unsigned int orig_timeout;
570 fstring tmp;
571 char *p;
573 /* Hmmmm. We can only open one connection to the NETLOGON pipe at the
574 * moment.... */
576 if (IS_DC) {
577 return False;
580 if (domain->primary) {
581 return False;
584 our_domain = find_our_domain();
586 if ((mem_ctx = talloc_init("get_dc_name_via_netlogon")) == NULL) {
587 return False;
590 result = cm_connect_netlogon(our_domain, &netlogon_pipe);
591 if (!NT_STATUS_IS_OK(result)) {
592 talloc_destroy(mem_ctx);
593 return False;
596 /* This call can take a long time - allow the server to time out.
597 35 seconds should do it. */
599 orig_timeout = cli_set_timeout(netlogon_pipe->cli, 35000);
601 werr = rpccli_netlogon_getanydcname(netlogon_pipe, mem_ctx, our_domain->dcname,
602 domain->name, tmp);
604 /* And restore our original timeout. */
605 cli_set_timeout(netlogon_pipe->cli, orig_timeout);
607 talloc_destroy(mem_ctx);
609 if (!W_ERROR_IS_OK(werr)) {
610 DEBUG(10, ("rpccli_netlogon_getanydcname failed: %s\n",
611 dos_errstr(werr)));
612 return False;
615 /* cli_netlogon_getanydcname gives us a name with \\ */
616 p = tmp;
617 if (*p == '\\') {
618 p+=1;
620 if (*p == '\\') {
621 p+=1;
624 fstrcpy(dcname, p);
626 DEBUG(10, ("rpccli_netlogon_getanydcname returned %s\n", dcname));
628 if (!resolve_name(dcname, dc_ip, 0x20)) {
629 return False;
632 return True;
635 /************************************************************************
636 Given a fd with a just-connected TCP connection to a DC, open a connection
637 to the pipe.
638 ************************************************************************/
640 static NTSTATUS cm_prepare_connection(const struct winbindd_domain *domain,
641 const int sockfd,
642 const char *controller,
643 struct cli_state **cli,
644 BOOL *retry)
646 char *machine_password, *machine_krb5_principal, *machine_account;
647 char *ipc_username, *ipc_domain, *ipc_password;
649 BOOL got_mutex;
651 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
653 struct sockaddr peeraddr;
654 socklen_t peeraddr_len;
656 struct sockaddr_in *peeraddr_in = (struct sockaddr_in *)&peeraddr;
658 DEBUG(10,("cm_prepare_connection: connecting to DC %s for domain %s\n",
659 controller, domain->name ));
661 machine_password = secrets_fetch_machine_password(lp_workgroup(), NULL,
662 NULL);
664 if (asprintf(&machine_account, "%s$", global_myname()) == -1) {
665 SAFE_FREE(machine_password);
666 return NT_STATUS_NO_MEMORY;
669 if (asprintf(&machine_krb5_principal, "%s$@%s", global_myname(),
670 lp_realm()) == -1) {
671 SAFE_FREE(machine_account);
672 SAFE_FREE(machine_password);
673 return NT_STATUS_NO_MEMORY;
676 cm_get_ipc_userpass(&ipc_username, &ipc_domain, &ipc_password);
678 *retry = True;
680 got_mutex = secrets_named_mutex(controller,
681 WINBIND_SERVER_MUTEX_WAIT_TIME);
683 if (!got_mutex) {
684 DEBUG(0,("cm_prepare_connection: mutex grab failed for %s\n",
685 controller));
686 result = NT_STATUS_POSSIBLE_DEADLOCK;
687 goto done;
690 if ((*cli = cli_initialise()) == NULL) {
691 DEBUG(1, ("Could not cli_initialize\n"));
692 result = NT_STATUS_NO_MEMORY;
693 goto done;
696 (*cli)->timeout = 10000; /* 10 seconds */
697 (*cli)->fd = sockfd;
698 fstrcpy((*cli)->desthost, controller);
699 (*cli)->use_kerberos = True;
701 peeraddr_len = sizeof(peeraddr);
703 if ((getpeername((*cli)->fd, &peeraddr, &peeraddr_len) != 0) ||
704 (peeraddr_len != sizeof(struct sockaddr_in)) ||
705 (peeraddr_in->sin_family != PF_INET))
707 DEBUG(0,("cm_prepare_connection: %s\n", strerror(errno)));
708 result = NT_STATUS_UNSUCCESSFUL;
709 goto done;
712 if (ntohs(peeraddr_in->sin_port) == 139) {
713 struct nmb_name calling;
714 struct nmb_name called;
716 make_nmb_name(&calling, global_myname(), 0x0);
717 make_nmb_name(&called, "*SMBSERVER", 0x20);
719 if (!cli_session_request(*cli, &calling, &called)) {
720 DEBUG(8, ("cli_session_request failed for %s\n",
721 controller));
722 result = NT_STATUS_UNSUCCESSFUL;
723 goto done;
727 cli_setup_signing_state(*cli, Undefined);
729 if (!cli_negprot(*cli)) {
730 DEBUG(1, ("cli_negprot failed\n"));
731 result = NT_STATUS_UNSUCCESSFUL;
732 goto done;
735 if ((*cli)->protocol >= PROTOCOL_NT1 && (*cli)->capabilities & CAP_EXTENDED_SECURITY) {
736 ADS_STATUS ads_status;
738 if (lp_security() == SEC_ADS) {
740 /* Try a krb5 session */
742 (*cli)->use_kerberos = True;
743 DEBUG(5, ("connecting to %s from %s with kerberos principal "
744 "[%s]\n", controller, global_myname(),
745 machine_krb5_principal));
747 winbindd_set_locator_kdc_envs(domain);
749 ads_status = cli_session_setup_spnego(*cli,
750 machine_krb5_principal,
751 machine_password,
752 lp_workgroup());
754 if (!ADS_ERR_OK(ads_status)) {
755 DEBUG(4,("failed kerberos session setup with %s\n",
756 ads_errstr(ads_status)));
759 result = ads_ntstatus(ads_status);
760 if (NT_STATUS_IS_OK(result)) {
761 /* Ensure creds are stored for NTLMSSP authenticated pipe access. */
762 cli_init_creds(*cli, machine_account, lp_workgroup(), machine_password);
763 goto session_setup_done;
767 /* Fall back to non-kerberos session setup using NTLMSSP SPNEGO with the machine account. */
768 (*cli)->use_kerberos = False;
770 DEBUG(5, ("connecting to %s from %s with username "
771 "[%s]\\[%s]\n", controller, global_myname(),
772 lp_workgroup(), machine_account));
774 ads_status = cli_session_setup_spnego(*cli,
775 machine_account,
776 machine_password,
777 lp_workgroup());
778 if (!ADS_ERR_OK(ads_status)) {
779 DEBUG(4, ("authenticated session setup failed with %s\n",
780 ads_errstr(ads_status)));
783 result = ads_ntstatus(ads_status);
784 if (NT_STATUS_IS_OK(result)) {
785 /* Ensure creds are stored for NTLMSSP authenticated pipe access. */
786 cli_init_creds(*cli, machine_account, lp_workgroup(), machine_password);
787 goto session_setup_done;
791 /* Fall back to non-kerberos session setup */
793 (*cli)->use_kerberos = False;
795 if ((((*cli)->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) != 0) &&
796 (strlen(ipc_username) > 0)) {
798 /* Only try authenticated if we have a username */
800 DEBUG(5, ("connecting to %s from %s with username "
801 "[%s]\\[%s]\n", controller, global_myname(),
802 ipc_domain, ipc_username));
804 if (NT_STATUS_IS_OK(cli_session_setup(
805 *cli, ipc_username,
806 ipc_password, strlen(ipc_password)+1,
807 ipc_password, strlen(ipc_password)+1,
808 ipc_domain))) {
809 /* Successful logon with given username. */
810 cli_init_creds(*cli, ipc_username, ipc_domain, ipc_password);
811 goto session_setup_done;
812 } else {
813 DEBUG(4, ("authenticated session setup with user %s\\%s failed.\n",
814 ipc_domain, ipc_username ));
818 /* Fall back to anonymous connection, this might fail later */
820 if (NT_STATUS_IS_OK(cli_session_setup(*cli, "", NULL, 0,
821 NULL, 0, ""))) {
822 DEBUG(5, ("Connected anonymously\n"));
823 cli_init_creds(*cli, "", "", "");
824 goto session_setup_done;
827 result = cli_nt_error(*cli);
829 if (NT_STATUS_IS_OK(result))
830 result = NT_STATUS_UNSUCCESSFUL;
832 /* We can't session setup */
834 goto done;
836 session_setup_done:
838 /* cache the server name for later connections */
840 saf_store( domain->name, (*cli)->desthost );
841 if (domain->alt_name && (*cli)->use_kerberos) {
842 saf_store( domain->alt_name, (*cli)->desthost );
845 winbindd_set_locator_kdc_envs(domain);
847 if (!cli_send_tconX(*cli, "IPC$", "IPC", "", 0)) {
849 result = cli_nt_error(*cli);
851 DEBUG(1,("failed tcon_X with %s\n", nt_errstr(result)));
853 if (NT_STATUS_IS_OK(result))
854 result = NT_STATUS_UNSUCCESSFUL;
856 goto done;
859 secrets_named_mutex_release(controller);
860 got_mutex = False;
861 *retry = False;
863 /* set the domain if empty; needed for schannel connections */
864 if ( !*(*cli)->domain ) {
865 fstrcpy( (*cli)->domain, domain->name );
868 result = NT_STATUS_OK;
870 done:
871 if (got_mutex) {
872 secrets_named_mutex_release(controller);
875 SAFE_FREE(machine_account);
876 SAFE_FREE(machine_password);
877 SAFE_FREE(machine_krb5_principal);
878 SAFE_FREE(ipc_username);
879 SAFE_FREE(ipc_domain);
880 SAFE_FREE(ipc_password);
882 if (!NT_STATUS_IS_OK(result)) {
883 winbind_add_failed_connection_entry(domain, controller, result);
884 if ((*cli) != NULL) {
885 cli_shutdown(*cli);
886 *cli = NULL;
890 return result;
893 static BOOL add_one_dc_unique(TALLOC_CTX *mem_ctx, const char *domain_name,
894 const char *dcname, struct in_addr ip,
895 struct dc_name_ip **dcs, int *num)
897 if (!NT_STATUS_IS_OK(check_negative_conn_cache(domain_name, dcname))) {
898 DEBUG(10, ("DC %s was in the negative conn cache\n", dcname));
899 return False;
902 *dcs = TALLOC_REALLOC_ARRAY(mem_ctx, *dcs, struct dc_name_ip, (*num)+1);
904 if (*dcs == NULL)
905 return False;
907 fstrcpy((*dcs)[*num].name, dcname);
908 (*dcs)[*num].ip = ip;
909 *num += 1;
910 return True;
913 static BOOL add_sockaddr_to_array(TALLOC_CTX *mem_ctx,
914 struct in_addr ip, uint16 port,
915 struct sockaddr_in **addrs, int *num)
917 *addrs = TALLOC_REALLOC_ARRAY(mem_ctx, *addrs, struct sockaddr_in, (*num)+1);
919 if (*addrs == NULL) {
920 *num = 0;
921 return False;
924 (*addrs)[*num].sin_family = PF_INET;
925 putip((char *)&((*addrs)[*num].sin_addr), (char *)&ip);
926 (*addrs)[*num].sin_port = htons(port);
928 *num += 1;
929 return True;
932 static void mailslot_name(struct in_addr dc_ip, fstring name)
934 fstr_sprintf(name, "\\MAILSLOT\\NET\\GETDC%X", dc_ip.s_addr);
937 static BOOL send_getdc_request(struct in_addr dc_ip,
938 const char *domain_name,
939 const DOM_SID *sid)
941 pstring outbuf;
942 char *p;
943 fstring my_acct_name;
944 fstring my_mailslot;
946 mailslot_name(dc_ip, my_mailslot);
948 memset(outbuf, '\0', sizeof(outbuf));
950 p = outbuf;
952 SCVAL(p, 0, SAMLOGON);
953 p++;
955 SCVAL(p, 0, 0); /* Count pointer ... */
956 p++;
958 SIVAL(p, 0, 0); /* The sender's token ... */
959 p += 2;
961 p += dos_PutUniCode(p, global_myname(), sizeof(pstring), True);
962 fstr_sprintf(my_acct_name, "%s$", global_myname());
963 p += dos_PutUniCode(p, my_acct_name, sizeof(pstring), True);
965 memcpy(p, my_mailslot, strlen(my_mailslot)+1);
966 p += strlen(my_mailslot)+1;
968 SIVAL(p, 0, 0x80);
969 p+=4;
971 SIVAL(p, 0, sid_size(sid));
972 p+=4;
974 p = ALIGN4(p, outbuf);
976 sid_linearize(p, sid_size(sid), sid);
977 p += sid_size(sid);
979 SIVAL(p, 0, 1);
980 SSVAL(p, 4, 0xffff);
981 SSVAL(p, 6, 0xffff);
982 p+=8;
984 return cli_send_mailslot(winbind_messaging_context(),
985 False, "\\MAILSLOT\\NET\\NTLOGON", 0,
986 outbuf, PTR_DIFF(p, outbuf),
987 global_myname(), 0, domain_name, 0x1c,
988 dc_ip);
991 static BOOL receive_getdc_response(struct in_addr dc_ip,
992 const char *domain_name,
993 fstring dc_name)
995 struct packet_struct *packet;
996 fstring my_mailslot;
997 char *buf, *p;
998 fstring dcname, user, domain;
999 int len;
1001 mailslot_name(dc_ip, my_mailslot);
1003 packet = receive_unexpected(DGRAM_PACKET, 0, my_mailslot);
1005 if (packet == NULL) {
1006 DEBUG(5, ("Did not receive packet for %s\n", my_mailslot));
1007 return False;
1010 DEBUG(5, ("Received packet for %s\n", my_mailslot));
1012 buf = packet->packet.dgram.data;
1013 len = packet->packet.dgram.datasize;
1015 if (len < 70) {
1016 /* 70 is a completely arbitrary value to make sure
1017 the SVAL below does not read uninitialized memory */
1018 DEBUG(3, ("GetDC got short response\n"));
1019 return False;
1022 /* This should be (buf-4)+SVAL(buf-4, smb_vwv12)... */
1023 p = buf+SVAL(buf, smb_vwv10);
1025 if (CVAL(p,0) != SAMLOGON_R) {
1026 DEBUG(8, ("GetDC got invalid response type %d\n", CVAL(p, 0)));
1027 return False;
1030 p+=2;
1031 pull_ucs2(buf, dcname, p, sizeof(dcname), PTR_DIFF(buf+len, p),
1032 STR_TERMINATE|STR_NOALIGN);
1033 p = skip_unibuf(p, PTR_DIFF(buf+len, p));
1034 pull_ucs2(buf, user, p, sizeof(dcname), PTR_DIFF(buf+len, p),
1035 STR_TERMINATE|STR_NOALIGN);
1036 p = skip_unibuf(p, PTR_DIFF(buf+len, p));
1037 pull_ucs2(buf, domain, p, sizeof(dcname), PTR_DIFF(buf+len, p),
1038 STR_TERMINATE|STR_NOALIGN);
1039 p = skip_unibuf(p, PTR_DIFF(buf+len, p));
1041 if (!strequal(domain, domain_name)) {
1042 DEBUG(3, ("GetDC: Expected domain %s, got %s\n",
1043 domain_name, domain));
1044 return False;
1047 p = dcname;
1048 if (*p == '\\') p += 1;
1049 if (*p == '\\') p += 1;
1051 fstrcpy(dc_name, p);
1053 DEBUG(10, ("GetDC gave name %s for domain %s\n",
1054 dc_name, domain));
1056 return True;
1059 /*******************************************************************
1060 convert an ip to a name
1061 *******************************************************************/
1063 static BOOL dcip_to_name(const struct winbindd_domain *domain, struct in_addr ip, fstring name )
1065 struct ip_service ip_list;
1067 ip_list.ip = ip;
1068 ip_list.port = 0;
1070 #ifdef WITH_ADS
1071 /* For active directory servers, try to get the ldap server name.
1072 None of these failures should be considered critical for now */
1074 if (lp_security() == SEC_ADS) {
1075 ADS_STRUCT *ads;
1077 ads = ads_init(domain->alt_name, domain->name, NULL);
1078 ads->auth.flags |= ADS_AUTH_NO_BIND;
1080 if (ads_try_connect( ads, inet_ntoa(ip) ) ) {
1081 /* We got a cldap packet. */
1082 fstrcpy(name, ads->config.ldap_server_name);
1083 namecache_store(name, 0x20, 1, &ip_list);
1085 DEBUG(10,("dcip_to_name: flags = 0x%x\n", (unsigned int)ads->config.flags));
1087 if (domain->primary && (ads->config.flags & ADS_KDC)) {
1088 if (ads_closest_dc(ads)) {
1089 char *sitename = sitename_fetch(ads->config.realm);
1091 /* We're going to use this KDC for this realm/domain.
1092 If we are using sites, then force the krb5 libs
1093 to use this KDC. */
1095 create_local_private_krb5_conf_for_domain(domain->alt_name,
1096 domain->name,
1097 sitename,
1098 ip);
1100 SAFE_FREE(sitename);
1101 } else {
1102 /* use an off site KDC */
1103 create_local_private_krb5_conf_for_domain(domain->alt_name,
1104 domain->name,
1105 NULL,
1106 ip);
1108 winbindd_set_locator_kdc_envs(domain);
1110 /* Ensure we contact this DC also. */
1111 saf_store( domain->name, name);
1112 saf_store( domain->alt_name, name);
1115 ads_destroy( &ads );
1116 return True;
1119 ads_destroy( &ads );
1121 #endif
1123 /* try GETDC requests next */
1125 if (send_getdc_request(ip, domain->name, &domain->sid)) {
1126 int i;
1127 smb_msleep(100);
1128 for (i=0; i<5; i++) {
1129 if (receive_getdc_response(ip, domain->name, name)) {
1130 namecache_store(name, 0x20, 1, &ip_list);
1131 return True;
1133 smb_msleep(500);
1137 /* try node status request */
1139 if ( name_status_find(domain->name, 0x1c, 0x20, ip, name) ) {
1140 namecache_store(name, 0x20, 1, &ip_list);
1141 return True;
1143 return False;
1146 /*******************************************************************
1147 Retreive a list of IP address for domain controllers. Fill in
1148 the dcs[] with results.
1149 *******************************************************************/
1151 static BOOL get_dcs(TALLOC_CTX *mem_ctx, const struct winbindd_domain *domain,
1152 struct dc_name_ip **dcs, int *num_dcs)
1154 fstring dcname;
1155 struct in_addr ip;
1156 struct ip_service *ip_list = NULL;
1157 int iplist_size = 0;
1158 int i;
1159 BOOL is_our_domain;
1160 enum security_types sec = (enum security_types)lp_security();
1162 is_our_domain = strequal(domain->name, lp_workgroup());
1164 if ( !is_our_domain
1165 && get_dc_name_via_netlogon(domain, dcname, &ip)
1166 && add_one_dc_unique(mem_ctx, domain->name, dcname, ip, dcs, num_dcs) )
1168 DEBUG(10, ("Retrieved DC %s at %s via netlogon\n",
1169 dcname, inet_ntoa(ip)));
1170 return True;
1173 if (sec == SEC_ADS) {
1174 char *sitename = NULL;
1176 /* We need to make sure we know the local site before
1177 doing any DNS queries, as this will restrict the
1178 get_sorted_dc_list() call below to only fetching
1179 DNS records for the correct site. */
1181 /* Find any DC to get the site record.
1182 We deliberately don't care about the
1183 return here. */
1185 get_dc_name(domain->name, domain->alt_name, dcname, &ip);
1187 sitename = sitename_fetch(domain->alt_name);
1188 if (sitename) {
1190 /* Do the site-specific AD dns lookup first. */
1191 get_sorted_dc_list(domain->alt_name, sitename, &ip_list, &iplist_size, True);
1193 for ( i=0; i<iplist_size; i++ ) {
1194 add_one_dc_unique(mem_ctx, domain->name, inet_ntoa(ip_list[i].ip),
1195 ip_list[i].ip, dcs, num_dcs);
1198 SAFE_FREE(ip_list);
1199 SAFE_FREE(sitename);
1200 iplist_size = 0;
1203 /* Now we add DCs from the main AD dns lookup. */
1204 get_sorted_dc_list(domain->alt_name, NULL, &ip_list, &iplist_size, True);
1206 for ( i=0; i<iplist_size; i++ ) {
1207 add_one_dc_unique(mem_ctx, domain->name, inet_ntoa(ip_list[i].ip),
1208 ip_list[i].ip, dcs, num_dcs);
1212 /* try standard netbios queries if no ADS */
1214 if (iplist_size==0) {
1215 get_sorted_dc_list(domain->name, NULL, &ip_list, &iplist_size, False);
1218 /* FIXME!! this is where we should re-insert the GETDC requests --jerry */
1220 /* now add to the dc array. We'll wait until the last minute
1221 to look up the name of the DC. But we fill in the char* for
1222 the ip now in to make the failed connection cache work */
1224 for ( i=0; i<iplist_size; i++ ) {
1225 add_one_dc_unique(mem_ctx, domain->name, inet_ntoa(ip_list[i].ip),
1226 ip_list[i].ip, dcs, num_dcs);
1229 SAFE_FREE( ip_list );
1231 return True;
1234 static BOOL find_new_dc(TALLOC_CTX *mem_ctx,
1235 const struct winbindd_domain *domain,
1236 fstring dcname, struct sockaddr_in *addr, int *fd)
1238 struct dc_name_ip *dcs = NULL;
1239 int num_dcs = 0;
1241 const char **dcnames = NULL;
1242 int num_dcnames = 0;
1244 struct sockaddr_in *addrs = NULL;
1245 int num_addrs = 0;
1247 int i, fd_index;
1249 again:
1250 if (!get_dcs(mem_ctx, domain, &dcs, &num_dcs) || (num_dcs == 0))
1251 return False;
1253 for (i=0; i<num_dcs; i++) {
1255 if (!add_string_to_array(mem_ctx, dcs[i].name,
1256 &dcnames, &num_dcnames)) {
1257 return False;
1259 if (!add_sockaddr_to_array(mem_ctx, dcs[i].ip, 445,
1260 &addrs, &num_addrs)) {
1261 return False;
1264 if (!add_string_to_array(mem_ctx, dcs[i].name,
1265 &dcnames, &num_dcnames)) {
1266 return False;
1268 if (!add_sockaddr_to_array(mem_ctx, dcs[i].ip, 139,
1269 &addrs, &num_addrs)) {
1270 return False;
1274 if ((num_dcnames == 0) || (num_dcnames != num_addrs))
1275 return False;
1277 if ((addrs == NULL) || (dcnames == NULL))
1278 return False;
1280 /* 5 second timeout. */
1281 if ( !open_any_socket_out(addrs, num_addrs, 5000, &fd_index, fd) )
1283 for (i=0; i<num_dcs; i++) {
1284 DEBUG(10, ("find_new_dc: open_any_socket_out failed for "
1285 "domain %s address %s. Error was %s\n",
1286 domain->name, inet_ntoa(dcs[i].ip), strerror(errno) ));
1287 winbind_add_failed_connection_entry(domain,
1288 dcs[i].name, NT_STATUS_UNSUCCESSFUL);
1290 return False;
1293 *addr = addrs[fd_index];
1295 if (*dcnames[fd_index] != '\0' && !is_ipaddress(dcnames[fd_index])) {
1296 /* Ok, we've got a name for the DC */
1297 fstrcpy(dcname, dcnames[fd_index]);
1298 return True;
1301 /* Try to figure out the name */
1302 if (dcip_to_name( domain, addr->sin_addr, dcname )) {
1303 return True;
1306 /* We can not continue without the DC's name */
1307 winbind_add_failed_connection_entry(domain, dcs[fd_index].name,
1308 NT_STATUS_UNSUCCESSFUL);
1309 goto again;
1312 static NTSTATUS cm_open_connection(struct winbindd_domain *domain,
1313 struct winbindd_cm_conn *new_conn)
1315 TALLOC_CTX *mem_ctx;
1316 NTSTATUS result;
1317 char *saf_servername = saf_fetch( domain->name );
1318 int retries;
1320 if ((mem_ctx = talloc_init("cm_open_connection")) == NULL) {
1321 SAFE_FREE(saf_servername);
1322 set_domain_offline(domain);
1323 return NT_STATUS_NO_MEMORY;
1326 /* we have to check the server affinity cache here since
1327 later we selecte a DC based on response time and not preference */
1329 /* Check the negative connection cache
1330 before talking to it. It going down may have
1331 triggered the reconnection. */
1333 if ( saf_servername && NT_STATUS_IS_OK(check_negative_conn_cache( domain->name, saf_servername))) {
1335 DEBUG(10,("cm_open_connection: saf_servername is '%s' for domain %s\n",
1336 saf_servername, domain->name ));
1338 /* convert an ip address to a name */
1339 if ( is_ipaddress( saf_servername ) ) {
1340 fstring saf_name;
1341 struct in_addr ip;
1343 ip = *interpret_addr2( saf_servername );
1344 if (dcip_to_name( domain, ip, saf_name )) {
1345 fstrcpy( domain->dcname, saf_name );
1346 } else {
1347 winbind_add_failed_connection_entry(
1348 domain, saf_servername,
1349 NT_STATUS_UNSUCCESSFUL);
1351 } else {
1352 fstrcpy( domain->dcname, saf_servername );
1355 SAFE_FREE( saf_servername );
1358 for (retries = 0; retries < 3; retries++) {
1360 int fd = -1;
1361 BOOL retry = False;
1363 result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
1365 DEBUG(10,("cm_open_connection: dcname is '%s' for domain %s\n",
1366 domain->dcname, domain->name ));
1368 if (*domain->dcname
1369 && NT_STATUS_IS_OK(check_negative_conn_cache( domain->name, domain->dcname))
1370 && (resolve_name(domain->dcname, &domain->dcaddr.sin_addr, 0x20)))
1372 struct sockaddr_in *addrs = NULL;
1373 int num_addrs = 0;
1374 int dummy = 0;
1376 if (!add_sockaddr_to_array(mem_ctx, domain->dcaddr.sin_addr, 445, &addrs, &num_addrs)) {
1377 set_domain_offline(domain);
1378 talloc_destroy(mem_ctx);
1379 return NT_STATUS_NO_MEMORY;
1381 if (!add_sockaddr_to_array(mem_ctx, domain->dcaddr.sin_addr, 139, &addrs, &num_addrs)) {
1382 set_domain_offline(domain);
1383 talloc_destroy(mem_ctx);
1384 return NT_STATUS_NO_MEMORY;
1387 /* 5 second timeout. */
1388 if (!open_any_socket_out(addrs, num_addrs, 5000, &dummy, &fd)) {
1389 fd = -1;
1393 if ((fd == -1)
1394 && !find_new_dc(mem_ctx, domain, domain->dcname, &domain->dcaddr, &fd))
1396 /* This is the one place where we will
1397 set the global winbindd offline state
1398 to true, if a "WINBINDD_OFFLINE" entry
1399 is found in the winbindd cache. */
1400 set_global_winbindd_state_offline();
1401 break;
1404 new_conn->cli = NULL;
1406 result = cm_prepare_connection(domain, fd, domain->dcname,
1407 &new_conn->cli, &retry);
1409 if (!retry)
1410 break;
1413 if (NT_STATUS_IS_OK(result)) {
1415 winbindd_set_locator_kdc_envs(domain);
1417 if (domain->online == False) {
1418 /* We're changing state from offline to online. */
1419 set_global_winbindd_state_online();
1421 set_domain_online(domain);
1422 } else {
1423 /* Ensure we setup the retry handler. */
1424 set_domain_offline(domain);
1427 talloc_destroy(mem_ctx);
1428 return result;
1431 /* Close down all open pipes on a connection. */
1433 void invalidate_cm_connection(struct winbindd_cm_conn *conn)
1435 /* We're closing down a possibly dead
1436 connection. Don't have impossibly long (10s) timeouts. */
1438 if (conn->cli) {
1439 cli_set_timeout(conn->cli, 1000); /* 1 second. */
1442 if (conn->samr_pipe != NULL) {
1443 if (!cli_rpc_pipe_close(conn->samr_pipe)) {
1444 /* Ok, it must be dead. Drop timeout to 0.5 sec. */
1445 if (conn->cli) {
1446 cli_set_timeout(conn->cli, 500);
1449 conn->samr_pipe = NULL;
1452 if (conn->lsa_pipe != NULL) {
1453 if (!cli_rpc_pipe_close(conn->lsa_pipe)) {
1454 /* Ok, it must be dead. Drop timeout to 0.5 sec. */
1455 if (conn->cli) {
1456 cli_set_timeout(conn->cli, 500);
1459 conn->lsa_pipe = NULL;
1462 if (conn->netlogon_pipe != NULL) {
1463 if (!cli_rpc_pipe_close(conn->netlogon_pipe)) {
1464 /* Ok, it must be dead. Drop timeout to 0.5 sec. */
1465 if (conn->cli) {
1466 cli_set_timeout(conn->cli, 500);
1469 conn->netlogon_pipe = NULL;
1472 if (conn->cli) {
1473 cli_shutdown(conn->cli);
1476 conn->cli = NULL;
1479 void close_conns_after_fork(void)
1481 struct winbindd_domain *domain;
1483 for (domain = domain_list(); domain; domain = domain->next) {
1484 if (domain->conn.cli == NULL)
1485 continue;
1487 if (domain->conn.cli->fd == -1)
1488 continue;
1490 close(domain->conn.cli->fd);
1491 domain->conn.cli->fd = -1;
1495 static BOOL connection_ok(struct winbindd_domain *domain)
1497 if (domain->conn.cli == NULL) {
1498 DEBUG(8, ("connection_ok: Connection to %s for domain %s has NULL "
1499 "cli!\n", domain->dcname, domain->name));
1500 return False;
1503 if (!domain->conn.cli->initialised) {
1504 DEBUG(3, ("connection_ok: Connection to %s for domain %s was never "
1505 "initialised!\n", domain->dcname, domain->name));
1506 return False;
1509 if (domain->conn.cli->fd == -1) {
1510 DEBUG(3, ("connection_ok: Connection to %s for domain %s has died or was "
1511 "never started (fd == -1)\n",
1512 domain->dcname, domain->name));
1513 return False;
1516 if (domain->online == False) {
1517 DEBUG(3, ("connection_ok: Domain %s is offline\n", domain->name));
1518 return False;
1521 return True;
1524 /* Initialize a new connection up to the RPC BIND.
1525 Bypass online status check so always does network calls. */
1527 static NTSTATUS init_dc_connection_network(struct winbindd_domain *domain)
1529 NTSTATUS result;
1531 /* Internal connections never use the network. */
1532 if (domain->internal) {
1533 domain->initialized = True;
1534 return NT_STATUS_OK;
1537 if (connection_ok(domain)) {
1538 if (!domain->initialized) {
1539 set_dc_type_and_flags(domain);
1541 return NT_STATUS_OK;
1544 invalidate_cm_connection(&domain->conn);
1546 result = cm_open_connection(domain, &domain->conn);
1548 if (NT_STATUS_IS_OK(result) && !domain->initialized) {
1549 set_dc_type_and_flags(domain);
1552 return result;
1555 NTSTATUS init_dc_connection(struct winbindd_domain *domain)
1557 if (domain->initialized && !domain->online) {
1558 /* We check for online status elsewhere. */
1559 return NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
1562 return init_dc_connection_network(domain);
1565 /******************************************************************************
1566 Set the trust flags (direction and forest location) for a domain
1567 ******************************************************************************/
1569 static BOOL set_dc_type_and_flags_trustinfo( struct winbindd_domain *domain )
1571 struct winbindd_domain *our_domain;
1572 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1573 struct ds_domain_trust *domains = NULL;
1574 int count = 0;
1575 int i;
1576 uint32 flags = (DS_DOMAIN_IN_FOREST |
1577 DS_DOMAIN_DIRECT_OUTBOUND |
1578 DS_DOMAIN_DIRECT_INBOUND);
1579 struct rpc_pipe_client *cli;
1580 TALLOC_CTX *mem_ctx = NULL;
1582 DEBUG(5, ("set_dc_type_and_flags_trustinfo: domain %s\n", domain->name ));
1584 /* Our primary domain doesn't need to worry about trust flags.
1585 Force it to go through the network setup */
1586 if ( domain->primary ) {
1587 return False;
1590 our_domain = find_our_domain();
1592 if ( !connection_ok(our_domain) ) {
1593 DEBUG(3,("set_dc_type_and_flags_trustinfo: No connection to our domain!\n"));
1594 return False;
1597 /* This won't work unless our domain is AD */
1599 if ( !our_domain->active_directory ) {
1600 return False;
1603 /* Use DsEnumerateDomainTrusts to get us the trust direction
1604 and type */
1606 result = cm_connect_netlogon(our_domain, &cli);
1608 if (!NT_STATUS_IS_OK(result)) {
1609 DEBUG(5, ("set_dc_type_and_flags_trustinfo: Could not open "
1610 "a connection to %s for PIPE_NETLOGON (%s)\n",
1611 domain->name, nt_errstr(result)));
1612 return False;
1615 if ( (mem_ctx = talloc_init("set_dc_type_and_flags_trustinfo")) == NULL ) {
1616 DEBUG(0,("set_dc_type_and_flags_trustinfo: talloc_init() failed!\n"));
1617 return False;
1620 result = rpccli_ds_enum_domain_trusts(cli, mem_ctx,
1621 cli->cli->desthost,
1622 flags, &domains,
1623 (unsigned int *)&count);
1625 /* Now find the domain name and get the flags */
1627 for ( i=0; i<count; i++ ) {
1628 if ( strequal( domain->name, domains[i].netbios_domain ) ) {
1629 domain->domain_flags = domains[i].flags;
1630 domain->domain_type = domains[i].trust_type;
1631 domain->domain_trust_attribs = domains[i].trust_attributes;
1633 if ( domain->domain_type == DS_DOMAIN_TRUST_TYPE_UPLEVEL )
1634 domain->active_directory = True;
1636 /* This flag is only set if the domain is *our*
1637 primary domain and the primary domain is in
1638 native mode */
1640 domain->native_mode = (domain->domain_flags & DS_DOMAIN_NATIVE_MODE);
1642 DEBUG(5, ("set_dc_type_and_flags_trustinfo: domain %s is %sin "
1643 "native mode.\n", domain->name,
1644 domain->native_mode ? "" : "NOT "));
1646 DEBUG(5,("set_dc_type_and_flags_trustinfo: domain %s is %s"
1647 "running active directory.\n", domain->name,
1648 domain->active_directory ? "" : "NOT "));
1651 domain->initialized = True;
1653 if ( !winbindd_can_contact_domain( domain) )
1654 domain->internal = True;
1656 break;
1660 talloc_destroy( mem_ctx );
1662 return domain->initialized;
1665 /******************************************************************************
1666 We can 'sense' certain things about the DC by it's replies to certain
1667 questions.
1669 This tells us if this particular remote server is Active Directory, and if it
1670 is native mode.
1671 ******************************************************************************/
1673 static void set_dc_type_and_flags_connect( struct winbindd_domain *domain )
1675 NTSTATUS result;
1676 DS_DOMINFO_CTR ctr;
1677 TALLOC_CTX *mem_ctx = NULL;
1678 struct rpc_pipe_client *cli;
1679 POLICY_HND pol;
1681 char *domain_name = NULL;
1682 char *dns_name = NULL;
1683 char *forest_name = NULL;
1684 DOM_SID *dom_sid = NULL;
1686 ZERO_STRUCT( ctr );
1688 if (!connection_ok(domain)) {
1689 return;
1692 DEBUG(5, ("set_dc_type_and_flags_connect: domain %s\n", domain->name ));
1694 cli = cli_rpc_pipe_open_noauth(domain->conn.cli, PI_LSARPC_DS,
1695 &result);
1697 if (cli == NULL) {
1698 DEBUG(5, ("set_dc_type_and_flags_connect: Could not bind to "
1699 "PI_LSARPC_DS on domain %s: (%s)\n",
1700 domain->name, nt_errstr(result)));
1702 /* if this is just a non-AD domain we need to continue
1703 * identifying so that we can in the end return with
1704 * domain->initialized = True - gd */
1706 goto no_lsarpc_ds;
1709 result = rpccli_ds_getprimarydominfo(cli, cli->cli->mem_ctx,
1710 DsRolePrimaryDomainInfoBasic,
1711 &ctr);
1712 cli_rpc_pipe_close(cli);
1714 if (!NT_STATUS_IS_OK(result)) {
1715 DEBUG(5, ("set_dc_type_and_flags_connect: rpccli_ds_getprimarydominfo "
1716 "on domain %s failed: (%s)\n",
1717 domain->name, nt_errstr(result)));
1719 /* older samba3 DCs will return DCERPC_FAULT_OP_RNG_ERROR for
1720 * every opcode on the LSARPC_DS pipe, continue with
1721 * no_lsarpc_ds mode here as well to get domain->initialized
1722 * set - gd */
1724 if (NT_STATUS_V(result) == DCERPC_FAULT_OP_RNG_ERROR) {
1725 goto no_lsarpc_ds;
1728 return;
1731 if ((ctr.basic->flags & DSROLE_PRIMARY_DS_RUNNING) &&
1732 !(ctr.basic->flags & DSROLE_PRIMARY_DS_MIXED_MODE)) {
1733 domain->native_mode = True;
1734 } else {
1735 domain->native_mode = False;
1738 no_lsarpc_ds:
1739 cli = cli_rpc_pipe_open_noauth(domain->conn.cli, PI_LSARPC, &result);
1741 if (cli == NULL) {
1742 DEBUG(5, ("set_dc_type_and_flags_connect: Could not bind to "
1743 "PI_LSARPC on domain %s: (%s)\n",
1744 domain->name, nt_errstr(result)));
1745 cli_rpc_pipe_close(cli);
1746 return;
1749 mem_ctx = talloc_init("set_dc_type_and_flags on domain %s\n",
1750 domain->name);
1751 if (!mem_ctx) {
1752 DEBUG(1, ("set_dc_type_and_flags_connect: talloc_init() failed\n"));
1753 cli_rpc_pipe_close(cli);
1754 return;
1757 result = rpccli_lsa_open_policy2(cli, mem_ctx, True,
1758 SEC_RIGHTS_MAXIMUM_ALLOWED, &pol);
1760 if (NT_STATUS_IS_OK(result)) {
1761 /* This particular query is exactly what Win2k clients use
1762 to determine that the DC is active directory */
1763 result = rpccli_lsa_query_info_policy2(cli, mem_ctx, &pol,
1764 12, &domain_name,
1765 &dns_name, &forest_name,
1766 NULL, &dom_sid);
1769 if (NT_STATUS_IS_OK(result)) {
1770 domain->active_directory = True;
1772 if (domain_name)
1773 fstrcpy(domain->name, domain_name);
1775 if (dns_name)
1776 fstrcpy(domain->alt_name, dns_name);
1778 if ( forest_name )
1779 fstrcpy(domain->forest_name, forest_name);
1781 if (dom_sid)
1782 sid_copy(&domain->sid, dom_sid);
1783 } else {
1784 domain->active_directory = False;
1786 result = rpccli_lsa_open_policy(cli, mem_ctx, True,
1787 SEC_RIGHTS_MAXIMUM_ALLOWED,
1788 &pol);
1790 if (!NT_STATUS_IS_OK(result))
1791 goto done;
1793 result = rpccli_lsa_query_info_policy(cli, mem_ctx,
1794 &pol, 5, &domain_name,
1795 &dom_sid);
1797 if (NT_STATUS_IS_OK(result)) {
1798 if (domain_name)
1799 fstrcpy(domain->name, domain_name);
1801 if (dom_sid)
1802 sid_copy(&domain->sid, dom_sid);
1805 done:
1807 DEBUG(5, ("set_dc_type_and_flags_connect: domain %s is %sin native mode.\n",
1808 domain->name, domain->native_mode ? "" : "NOT "));
1810 DEBUG(5,("set_dc_type_and_flags_connect: domain %s is %srunning active directory.\n",
1811 domain->name, domain->active_directory ? "" : "NOT "));
1813 cli_rpc_pipe_close(cli);
1815 talloc_destroy(mem_ctx);
1817 domain->initialized = True;
1820 /**********************************************************************
1821 Set the domain_flags (trust attributes, domain operating modes, etc...
1822 ***********************************************************************/
1824 static void set_dc_type_and_flags( struct winbindd_domain *domain )
1826 /* we always have to contact our primary domain */
1828 if ( domain->primary ) {
1829 DEBUG(10,("set_dc_type_and_flags: setting up flags for "
1830 "primary domain\n"));
1831 set_dc_type_and_flags_connect( domain );
1832 return;
1835 /* Use our DC to get the information if possible */
1837 if ( !set_dc_type_and_flags_trustinfo( domain ) ) {
1838 /* Otherwise, fallback to contacting the
1839 domain directly */
1840 set_dc_type_and_flags_connect( domain );
1843 return;
1848 /**********************************************************************
1849 ***********************************************************************/
1851 static BOOL cm_get_schannel_dcinfo(struct winbindd_domain *domain,
1852 struct dcinfo **ppdc)
1854 NTSTATUS result;
1855 struct rpc_pipe_client *netlogon_pipe;
1857 if (lp_client_schannel() == False) {
1858 return False;
1861 result = cm_connect_netlogon(domain, &netlogon_pipe);
1862 if (!NT_STATUS_IS_OK(result)) {
1863 return False;
1866 /* Return a pointer to the struct dcinfo from the
1867 netlogon pipe. */
1869 *ppdc = domain->conn.netlogon_pipe->dc;
1870 return True;
1873 NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
1874 struct rpc_pipe_client **cli, POLICY_HND *sam_handle)
1876 struct winbindd_cm_conn *conn;
1877 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1878 fstring conn_pwd;
1879 struct dcinfo *p_dcinfo;
1881 result = init_dc_connection(domain);
1882 if (!NT_STATUS_IS_OK(result)) {
1883 return result;
1886 conn = &domain->conn;
1888 if (conn->samr_pipe != NULL) {
1889 goto done;
1893 * No SAMR pipe yet. Attempt to get an NTLMSSP SPNEGO authenticated
1894 * sign and sealed pipe using the machine account password by
1895 * preference. If we can't - try schannel, if that fails, try
1896 * anonymous.
1899 pwd_get_cleartext(&conn->cli->pwd, conn_pwd);
1900 if ((conn->cli->user_name[0] == '\0') ||
1901 (conn->cli->domain[0] == '\0') ||
1902 (conn_pwd[0] == '\0')) {
1903 DEBUG(10, ("cm_connect_sam: No no user available for "
1904 "domain %s, trying schannel\n", conn->cli->domain));
1905 goto schannel;
1908 /* We have an authenticated connection. Use a NTLMSSP SPNEGO
1909 authenticated SAMR pipe with sign & seal. */
1910 conn->samr_pipe =
1911 cli_rpc_pipe_open_spnego_ntlmssp(conn->cli, PI_SAMR,
1912 PIPE_AUTH_LEVEL_PRIVACY,
1913 conn->cli->domain,
1914 conn->cli->user_name,
1915 conn_pwd, &result);
1917 if (conn->samr_pipe == NULL) {
1918 DEBUG(10,("cm_connect_sam: failed to connect to SAMR "
1919 "pipe for domain %s using NTLMSSP "
1920 "authenticated pipe: user %s\\%s. Error was "
1921 "%s\n", domain->name, conn->cli->domain,
1922 conn->cli->user_name, nt_errstr(result)));
1923 goto schannel;
1926 DEBUG(10,("cm_connect_sam: connected to SAMR pipe for "
1927 "domain %s using NTLMSSP authenticated "
1928 "pipe: user %s\\%s\n", domain->name,
1929 conn->cli->domain, conn->cli->user_name ));
1931 result = rpccli_samr_connect(conn->samr_pipe, mem_ctx,
1932 SEC_RIGHTS_MAXIMUM_ALLOWED,
1933 &conn->sam_connect_handle);
1934 if (NT_STATUS_IS_OK(result)) {
1935 goto open_domain;
1937 DEBUG(10,("cm_connect_sam: ntlmssp-sealed rpccli_samr_connect "
1938 "failed for domain %s, error was %s. Trying schannel\n",
1939 domain->name, nt_errstr(result) ));
1940 cli_rpc_pipe_close(conn->samr_pipe);
1942 schannel:
1944 /* Fall back to schannel if it's a W2K pre-SP1 box. */
1946 if (!cm_get_schannel_dcinfo(domain, &p_dcinfo)) {
1947 /* If this call fails - conn->cli can now be NULL ! */
1948 DEBUG(10, ("cm_connect_sam: Could not get schannel auth info "
1949 "for domain %s, trying anon\n", domain->name));
1950 goto anonymous;
1952 conn->samr_pipe = cli_rpc_pipe_open_schannel_with_key
1953 (conn->cli, PI_SAMR, PIPE_AUTH_LEVEL_PRIVACY,
1954 domain->name, p_dcinfo, &result);
1956 if (conn->samr_pipe == NULL) {
1957 DEBUG(10,("cm_connect_sam: failed to connect to SAMR pipe for "
1958 "domain %s using schannel. Error was %s\n",
1959 domain->name, nt_errstr(result) ));
1960 goto anonymous;
1962 DEBUG(10,("cm_connect_sam: connected to SAMR pipe for domain %s using "
1963 "schannel.\n", domain->name ));
1965 result = rpccli_samr_connect(conn->samr_pipe, mem_ctx,
1966 SEC_RIGHTS_MAXIMUM_ALLOWED,
1967 &conn->sam_connect_handle);
1968 if (NT_STATUS_IS_OK(result)) {
1969 goto open_domain;
1971 DEBUG(10,("cm_connect_sam: schannel-sealed rpccli_samr_connect failed "
1972 "for domain %s, error was %s. Trying anonymous\n",
1973 domain->name, nt_errstr(result) ));
1974 cli_rpc_pipe_close(conn->samr_pipe);
1976 anonymous:
1978 /* Finally fall back to anonymous. */
1979 conn->samr_pipe = cli_rpc_pipe_open_noauth(conn->cli, PI_SAMR,
1980 &result);
1982 if (conn->samr_pipe == NULL) {
1983 result = NT_STATUS_PIPE_NOT_AVAILABLE;
1984 goto done;
1987 result = rpccli_samr_connect(conn->samr_pipe, mem_ctx,
1988 SEC_RIGHTS_MAXIMUM_ALLOWED,
1989 &conn->sam_connect_handle);
1990 if (!NT_STATUS_IS_OK(result)) {
1991 DEBUG(10,("cm_connect_sam: rpccli_samr_connect failed "
1992 "for domain %s Error was %s\n",
1993 domain->name, nt_errstr(result) ));
1994 goto done;
1997 open_domain:
1998 result = rpccli_samr_open_domain(conn->samr_pipe,
1999 mem_ctx,
2000 &conn->sam_connect_handle,
2001 SEC_RIGHTS_MAXIMUM_ALLOWED,
2002 &domain->sid,
2003 &conn->sam_domain_handle);
2005 done:
2007 if (!NT_STATUS_IS_OK(result)) {
2008 invalidate_cm_connection(conn);
2009 return result;
2012 *cli = conn->samr_pipe;
2013 *sam_handle = conn->sam_domain_handle;
2014 return result;
2017 NTSTATUS cm_connect_lsa(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
2018 struct rpc_pipe_client **cli, POLICY_HND *lsa_policy)
2020 struct winbindd_cm_conn *conn;
2021 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
2022 fstring conn_pwd;
2023 struct dcinfo *p_dcinfo;
2025 result = init_dc_connection(domain);
2026 if (!NT_STATUS_IS_OK(result))
2027 return result;
2029 conn = &domain->conn;
2031 if (conn->lsa_pipe != NULL) {
2032 goto done;
2035 pwd_get_cleartext(&conn->cli->pwd, conn_pwd);
2036 if ((conn->cli->user_name[0] == '\0') ||
2037 (conn->cli->domain[0] == '\0') ||
2038 (conn_pwd[0] == '\0')) {
2039 DEBUG(10, ("cm_connect_lsa: No no user available for "
2040 "domain %s, trying schannel\n", conn->cli->domain));
2041 goto schannel;
2044 /* We have an authenticated connection. Use a NTLMSSP SPNEGO
2045 * authenticated LSA pipe with sign & seal. */
2046 conn->lsa_pipe = cli_rpc_pipe_open_spnego_ntlmssp
2047 (conn->cli, PI_LSARPC, PIPE_AUTH_LEVEL_PRIVACY,
2048 conn->cli->domain, conn->cli->user_name, conn_pwd, &result);
2050 if (conn->lsa_pipe == NULL) {
2051 DEBUG(10,("cm_connect_lsa: failed to connect to LSA pipe for "
2052 "domain %s using NTLMSSP authenticated pipe: user "
2053 "%s\\%s. Error was %s. Trying schannel.\n",
2054 domain->name, conn->cli->domain,
2055 conn->cli->user_name, nt_errstr(result)));
2056 goto schannel;
2059 DEBUG(10,("cm_connect_lsa: connected to LSA pipe for domain %s using "
2060 "NTLMSSP authenticated pipe: user %s\\%s\n",
2061 domain->name, conn->cli->domain, conn->cli->user_name ));
2063 result = rpccli_lsa_open_policy(conn->lsa_pipe, mem_ctx, True,
2064 SEC_RIGHTS_MAXIMUM_ALLOWED,
2065 &conn->lsa_policy);
2066 if (NT_STATUS_IS_OK(result)) {
2067 goto done;
2070 DEBUG(10,("cm_connect_lsa: rpccli_lsa_open_policy failed, trying "
2071 "schannel\n"));
2073 cli_rpc_pipe_close(conn->lsa_pipe);
2075 schannel:
2077 /* Fall back to schannel if it's a W2K pre-SP1 box. */
2079 if (!cm_get_schannel_dcinfo(domain, &p_dcinfo)) {
2080 /* If this call fails - conn->cli can now be NULL ! */
2081 DEBUG(10, ("cm_connect_lsa: Could not get schannel auth info "
2082 "for domain %s, trying anon\n", domain->name));
2083 goto anonymous;
2085 conn->lsa_pipe = cli_rpc_pipe_open_schannel_with_key
2086 (conn->cli, PI_LSARPC, PIPE_AUTH_LEVEL_PRIVACY,
2087 domain->name, p_dcinfo, &result);
2089 if (conn->lsa_pipe == NULL) {
2090 DEBUG(10,("cm_connect_lsa: failed to connect to LSA pipe for "
2091 "domain %s using schannel. Error was %s\n",
2092 domain->name, nt_errstr(result) ));
2093 goto anonymous;
2095 DEBUG(10,("cm_connect_lsa: connected to LSA pipe for domain %s using "
2096 "schannel.\n", domain->name ));
2098 result = rpccli_lsa_open_policy(conn->lsa_pipe, mem_ctx, True,
2099 SEC_RIGHTS_MAXIMUM_ALLOWED,
2100 &conn->lsa_policy);
2101 if (NT_STATUS_IS_OK(result)) {
2102 goto done;
2105 DEBUG(10,("cm_connect_lsa: rpccli_lsa_open_policy failed, trying "
2106 "anonymous\n"));
2108 cli_rpc_pipe_close(conn->lsa_pipe);
2110 anonymous:
2112 conn->lsa_pipe = cli_rpc_pipe_open_noauth(conn->cli, PI_LSARPC,
2113 &result);
2114 if (conn->lsa_pipe == NULL) {
2115 result = NT_STATUS_PIPE_NOT_AVAILABLE;
2116 goto done;
2119 result = rpccli_lsa_open_policy(conn->lsa_pipe, mem_ctx, True,
2120 SEC_RIGHTS_MAXIMUM_ALLOWED,
2121 &conn->lsa_policy);
2122 done:
2123 if (!NT_STATUS_IS_OK(result)) {
2124 invalidate_cm_connection(conn);
2125 return result;
2128 *cli = conn->lsa_pipe;
2129 *lsa_policy = conn->lsa_policy;
2130 return result;
2133 /****************************************************************************
2134 Open the netlogon pipe to this DC. Use schannel if specified in client conf.
2135 session key stored in conn->netlogon_pipe->dc->sess_key.
2136 ****************************************************************************/
2138 NTSTATUS cm_connect_netlogon(struct winbindd_domain *domain,
2139 struct rpc_pipe_client **cli)
2141 struct winbindd_cm_conn *conn;
2142 NTSTATUS result;
2144 uint32 neg_flags = NETLOGON_NEG_AUTH2_FLAGS;
2145 uint8 mach_pwd[16];
2146 uint32 sec_chan_type;
2147 const char *account_name;
2148 struct rpc_pipe_client *netlogon_pipe = NULL;
2150 *cli = NULL;
2152 result = init_dc_connection(domain);
2153 if (!NT_STATUS_IS_OK(result)) {
2154 return result;
2157 conn = &domain->conn;
2159 if (conn->netlogon_pipe != NULL) {
2160 *cli = conn->netlogon_pipe;
2161 return NT_STATUS_OK;
2164 if ((IS_DC || domain->primary) && !get_trust_pw(domain->name, mach_pwd, &sec_chan_type)) {
2165 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
2168 netlogon_pipe = cli_rpc_pipe_open_noauth(conn->cli, PI_NETLOGON,
2169 &result);
2170 if (netlogon_pipe == NULL) {
2171 return result;
2174 if ((!IS_DC) && (!domain->primary)) {
2175 /* Clear the schannel request bit and drop down */
2176 neg_flags &= ~NETLOGON_NEG_SCHANNEL;
2177 goto no_schannel;
2180 if (lp_client_schannel() != False) {
2181 neg_flags |= NETLOGON_NEG_SCHANNEL;
2184 /* if we are a DC and this is a trusted domain, then we need to use our
2185 domain name in the net_req_auth2() request */
2187 if ( IS_DC
2188 && !strequal(domain->name, lp_workgroup())
2189 && lp_allow_trusted_domains() )
2191 account_name = lp_workgroup();
2192 } else {
2193 account_name = domain->primary ?
2194 global_myname() : domain->name;
2197 if (account_name == NULL) {
2198 cli_rpc_pipe_close(netlogon_pipe);
2199 return NT_STATUS_NO_MEMORY;
2202 result = rpccli_netlogon_setup_creds(
2203 netlogon_pipe,
2204 domain->dcname, /* server name. */
2205 domain->name, /* domain name */
2206 global_myname(), /* client name */
2207 account_name, /* machine account */
2208 mach_pwd, /* machine password */
2209 sec_chan_type, /* from get_trust_pw */
2210 &neg_flags);
2212 if (!NT_STATUS_IS_OK(result)) {
2213 cli_rpc_pipe_close(netlogon_pipe);
2214 return result;
2217 if ((lp_client_schannel() == True) &&
2218 ((neg_flags & NETLOGON_NEG_SCHANNEL) == 0)) {
2219 DEBUG(3, ("Server did not offer schannel\n"));
2220 cli_rpc_pipe_close(netlogon_pipe);
2221 return NT_STATUS_ACCESS_DENIED;
2224 no_schannel:
2225 if ((lp_client_schannel() == False) ||
2226 ((neg_flags & NETLOGON_NEG_SCHANNEL) == 0)) {
2229 * NetSamLogonEx only works for schannel
2231 domain->can_do_samlogon_ex = False;
2233 /* We're done - just keep the existing connection to NETLOGON
2234 * open */
2235 conn->netlogon_pipe = netlogon_pipe;
2236 *cli = conn->netlogon_pipe;
2237 return NT_STATUS_OK;
2240 /* Using the credentials from the first pipe, open a signed and sealed
2241 second netlogon pipe. The session key is stored in the schannel
2242 part of the new pipe auth struct.
2245 conn->netlogon_pipe =
2246 cli_rpc_pipe_open_schannel_with_key(conn->cli,
2247 PI_NETLOGON,
2248 PIPE_AUTH_LEVEL_PRIVACY,
2249 domain->name,
2250 netlogon_pipe->dc,
2251 &result);
2253 /* We can now close the initial netlogon pipe. */
2254 cli_rpc_pipe_close(netlogon_pipe);
2256 if (conn->netlogon_pipe == NULL) {
2257 DEBUG(3, ("Could not open schannel'ed NETLOGON pipe. Error "
2258 "was %s\n", nt_errstr(result)));
2260 /* make sure we return something besides OK */
2261 return !NT_STATUS_IS_OK(result) ? result : NT_STATUS_PIPE_NOT_AVAILABLE;
2265 * Try NetSamLogonEx for AD domains
2267 domain->can_do_samlogon_ex = domain->active_directory;
2269 *cli = conn->netlogon_pipe;
2270 return NT_STATUS_OK;