mount.cifs: add support for sending IPv6 scope ID to kernel
[Samba/wip.git] / source3 / winbindd / winbindd_cm.c
blob396a30377fc7a1a37e6d36659516f869dbb67ae1
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"
63 #include "../libcli/auth/libcli_auth.h"
65 #undef DBGC_CLASS
66 #define DBGC_CLASS DBGC_WINBIND
68 struct dc_name_ip {
69 fstring name;
70 struct sockaddr_storage ss;
73 extern struct winbindd_methods reconnect_methods;
74 extern bool override_logfile;
76 static NTSTATUS init_dc_connection_network(struct winbindd_domain *domain);
77 static void set_dc_type_and_flags( struct winbindd_domain *domain );
78 static bool get_dcs(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
79 struct dc_name_ip **dcs, int *num_dcs);
81 /****************************************************************
82 Child failed to find DC's. Reschedule check.
83 ****************************************************************/
85 static void msg_failed_to_go_online(struct messaging_context *msg,
86 void *private_data,
87 uint32_t msg_type,
88 struct server_id server_id,
89 DATA_BLOB *data)
91 struct winbindd_domain *domain;
92 const char *domainname = (const char *)data->data;
94 if (data->data == NULL || data->length == 0) {
95 return;
98 DEBUG(5,("msg_fail_to_go_online: received for domain %s.\n", domainname));
100 for (domain = domain_list(); domain; domain = domain->next) {
101 if (domain->internal) {
102 continue;
105 if (strequal(domain->name, domainname)) {
106 if (domain->online) {
107 /* We're already online, ignore. */
108 DEBUG(5,("msg_fail_to_go_online: domain %s "
109 "already online.\n", domainname));
110 continue;
113 /* Reschedule the online check. */
114 set_domain_offline(domain);
115 break;
120 /****************************************************************
121 Actually cause a reconnect from a message.
122 ****************************************************************/
124 static void msg_try_to_go_online(struct messaging_context *msg,
125 void *private_data,
126 uint32_t msg_type,
127 struct server_id server_id,
128 DATA_BLOB *data)
130 struct winbindd_domain *domain;
131 const char *domainname = (const char *)data->data;
133 if (data->data == NULL || data->length == 0) {
134 return;
137 DEBUG(5,("msg_try_to_go_online: received for domain %s.\n", domainname));
139 for (domain = domain_list(); domain; domain = domain->next) {
140 if (domain->internal) {
141 continue;
144 if (strequal(domain->name, domainname)) {
146 if (domain->online) {
147 /* We're already online, ignore. */
148 DEBUG(5,("msg_try_to_go_online: domain %s "
149 "already online.\n", domainname));
150 continue;
153 /* This call takes care of setting the online
154 flag to true if we connected, or re-adding
155 the offline handler if false. Bypasses online
156 check so always does network calls. */
158 init_dc_connection_network(domain);
159 break;
164 /****************************************************************
165 Fork a child to try and contact a DC. Do this as contacting a
166 DC requires blocking lookups and we don't want to block our
167 parent.
168 ****************************************************************/
170 static bool fork_child_dc_connect(struct winbindd_domain *domain)
172 struct dc_name_ip *dcs = NULL;
173 int num_dcs = 0;
174 TALLOC_CTX *mem_ctx = NULL;
175 pid_t parent_pid = sys_getpid();
176 char *lfile = NULL;
178 /* Stop zombies */
179 CatchChild();
181 if (domain->dc_probe_pid != (pid_t)-1) {
183 * We might already have a DC probe
184 * child working, check.
186 if (process_exists_by_pid(domain->dc_probe_pid)) {
187 DEBUG(10,("fork_child_dc_connect: pid %u already "
188 "checking for DC's.\n",
189 (unsigned int)domain->dc_probe_pid));
190 return true;
192 domain->dc_probe_pid = (pid_t)-1;
195 domain->dc_probe_pid = sys_fork();
197 if (domain->dc_probe_pid == (pid_t)-1) {
198 DEBUG(0, ("fork_child_dc_connect: Could not fork: %s\n", strerror(errno)));
199 return False;
202 if (domain->dc_probe_pid != (pid_t)0) {
203 /* Parent */
204 messaging_register(winbind_messaging_context(), NULL,
205 MSG_WINBIND_TRY_TO_GO_ONLINE,
206 msg_try_to_go_online);
207 messaging_register(winbind_messaging_context(), NULL,
208 MSG_WINBIND_FAILED_TO_GO_ONLINE,
209 msg_failed_to_go_online);
210 return True;
213 /* Child. */
215 /* Leave messages blocked - we will never process one. */
217 if (!override_logfile) {
218 if (asprintf(&lfile, "%s/log.winbindd-dc-connect", get_dyn_LOGFILEBASE()) == -1) {
219 DEBUG(0, ("fork_child_dc_connect: out of memory.\n"));
220 _exit(1);
224 if (!winbindd_reinit_after_fork(lfile)) {
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(1);
232 SAFE_FREE(lfile);
234 mem_ctx = talloc_init("fork_child_dc_connect");
235 if (!mem_ctx) {
236 DEBUG(0,("talloc_init failed.\n"));
237 messaging_send_buf(winbind_messaging_context(),
238 pid_to_procid(parent_pid),
239 MSG_WINBIND_FAILED_TO_GO_ONLINE,
240 (uint8 *)domain->name,
241 strlen(domain->name)+1);
242 _exit(1);
245 if ((!get_dcs(mem_ctx, domain, &dcs, &num_dcs)) || (num_dcs == 0)) {
246 /* Still offline ? Can't find DC's. */
247 messaging_send_buf(winbind_messaging_context(),
248 pid_to_procid(parent_pid),
249 MSG_WINBIND_FAILED_TO_GO_ONLINE,
250 (uint8 *)domain->name,
251 strlen(domain->name)+1);
252 _exit(0);
255 /* We got a DC. Send a message to our parent to get it to
256 try and do the same. */
258 messaging_send_buf(winbind_messaging_context(),
259 pid_to_procid(parent_pid),
260 MSG_WINBIND_TRY_TO_GO_ONLINE,
261 (uint8 *)domain->name,
262 strlen(domain->name)+1);
263 _exit(0);
266 /****************************************************************
267 Handler triggered if we're offline to try and detect a DC.
268 ****************************************************************/
270 static void check_domain_online_handler(struct event_context *ctx,
271 struct timed_event *te,
272 struct timeval now,
273 void *private_data)
275 struct winbindd_domain *domain =
276 (struct winbindd_domain *)private_data;
278 DEBUG(10,("check_domain_online_handler: called for domain "
279 "%s (online = %s)\n", domain->name,
280 domain->online ? "True" : "False" ));
282 TALLOC_FREE(domain->check_online_event);
284 /* Are we still in "startup" mode ? */
286 if (domain->startup && (now.tv_sec > domain->startup_time + 30)) {
287 /* No longer in "startup" mode. */
288 DEBUG(10,("check_domain_online_handler: domain %s no longer in 'startup' mode.\n",
289 domain->name ));
290 domain->startup = False;
293 /* We've been told to stay offline, so stay
294 that way. */
296 if (get_global_winbindd_state_offline()) {
297 DEBUG(10,("check_domain_online_handler: domain %s remaining globally offline\n",
298 domain->name ));
299 return;
302 /* Fork a child to test if it can contact a DC.
303 If it can then send ourselves a message to
304 cause a reconnect. */
306 fork_child_dc_connect(domain);
309 /****************************************************************
310 If we're still offline setup the timeout check.
311 ****************************************************************/
313 static void calc_new_online_timeout_check(struct winbindd_domain *domain)
315 int wbr = lp_winbind_reconnect_delay();
317 if (domain->startup) {
318 domain->check_online_timeout = 10;
319 } else if (domain->check_online_timeout < wbr) {
320 domain->check_online_timeout = wbr;
324 /****************************************************************
325 Set domain offline and also add handler to put us back online
326 if we detect a DC.
327 ****************************************************************/
329 void set_domain_offline(struct winbindd_domain *domain)
331 DEBUG(10,("set_domain_offline: called for domain %s\n",
332 domain->name ));
334 TALLOC_FREE(domain->check_online_event);
336 if (domain->internal) {
337 DEBUG(3,("set_domain_offline: domain %s is internal - logic error.\n",
338 domain->name ));
339 return;
342 domain->online = False;
344 /* Offline domains are always initialized. They're
345 re-initialized when they go back online. */
347 domain->initialized = True;
349 /* We only add the timeout handler that checks and
350 allows us to go back online when we've not
351 been told to remain offline. */
353 if (get_global_winbindd_state_offline()) {
354 DEBUG(10,("set_domain_offline: domain %s remaining globally offline\n",
355 domain->name ));
356 return;
359 /* If we're in statup mode, check again in 10 seconds, not in
360 lp_winbind_reconnect_delay() seconds (which is 30 seconds by default). */
362 calc_new_online_timeout_check(domain);
364 domain->check_online_event = event_add_timed(winbind_event_context(),
365 NULL,
366 timeval_current_ofs(domain->check_online_timeout,0),
367 check_domain_online_handler,
368 domain);
370 /* The above *has* to succeed for winbindd to work. */
371 if (!domain->check_online_event) {
372 smb_panic("set_domain_offline: failed to add online handler");
375 DEBUG(10,("set_domain_offline: added event handler for domain %s\n",
376 domain->name ));
378 /* Send an offline message to the idmap child when our
379 primary domain goes offline */
381 if ( domain->primary ) {
382 struct winbindd_child *idmap = idmap_child();
384 if ( idmap->pid != 0 ) {
385 messaging_send_buf(winbind_messaging_context(),
386 pid_to_procid(idmap->pid),
387 MSG_WINBIND_OFFLINE,
388 (uint8 *)domain->name,
389 strlen(domain->name)+1);
393 return;
396 /****************************************************************
397 Set domain online - if allowed.
398 ****************************************************************/
400 static void set_domain_online(struct winbindd_domain *domain)
402 DEBUG(10,("set_domain_online: called for domain %s\n",
403 domain->name ));
405 if (domain->internal) {
406 DEBUG(3,("set_domain_online: domain %s is internal - logic error.\n",
407 domain->name ));
408 return;
411 if (get_global_winbindd_state_offline()) {
412 DEBUG(10,("set_domain_online: domain %s remaining globally offline\n",
413 domain->name ));
414 return;
417 winbindd_set_locator_kdc_envs(domain);
419 /* If we are waiting to get a krb5 ticket, trigger immediately. */
420 ccache_regain_all_now();
422 /* Ok, we're out of any startup mode now... */
423 domain->startup = False;
425 if (domain->online == False) {
426 /* We were offline - now we're online. We default to
427 using the MS-RPC backend if we started offline,
428 and if we're going online for the first time we
429 should really re-initialize the backends and the
430 checks to see if we're talking to an AD or NT domain.
433 domain->initialized = False;
435 /* 'reconnect_methods' is the MS-RPC backend. */
436 if (domain->backend == &reconnect_methods) {
437 domain->backend = NULL;
441 /* Ensure we have no online timeout checks. */
442 domain->check_online_timeout = 0;
443 TALLOC_FREE(domain->check_online_event);
445 /* Ensure we ignore any pending child messages. */
446 messaging_deregister(winbind_messaging_context(),
447 MSG_WINBIND_TRY_TO_GO_ONLINE, NULL);
448 messaging_deregister(winbind_messaging_context(),
449 MSG_WINBIND_FAILED_TO_GO_ONLINE, NULL);
451 domain->online = True;
453 /* Send an online message to the idmap child when our
454 primary domain comes online */
456 if ( domain->primary ) {
457 struct winbindd_child *idmap = idmap_child();
459 if ( idmap->pid != 0 ) {
460 messaging_send_buf(winbind_messaging_context(),
461 pid_to_procid(idmap->pid),
462 MSG_WINBIND_ONLINE,
463 (uint8 *)domain->name,
464 strlen(domain->name)+1);
468 return;
471 /****************************************************************
472 Requested to set a domain online.
473 ****************************************************************/
475 void set_domain_online_request(struct winbindd_domain *domain)
477 struct timeval tev;
479 DEBUG(10,("set_domain_online_request: called for domain %s\n",
480 domain->name ));
482 if (get_global_winbindd_state_offline()) {
483 DEBUG(10,("set_domain_online_request: domain %s remaining globally offline\n",
484 domain->name ));
485 return;
488 /* We've been told it's safe to go online and
489 try and connect to a DC. But I don't believe it
490 because network manager seems to lie.
491 Wait at least 5 seconds. Heuristics suck... */
494 GetTimeOfDay(&tev);
496 /* Go into "startup" mode again. */
497 domain->startup_time = tev.tv_sec;
498 domain->startup = True;
500 tev.tv_sec += 5;
502 if (!domain->check_online_event) {
503 /* If we've come from being globally offline we
504 don't have a check online event handler set.
505 We need to add one now we're trying to go
506 back online. */
508 DEBUG(10,("set_domain_online_request: domain %s was globally offline.\n",
509 domain->name ));
512 TALLOC_FREE(domain->check_online_event);
514 domain->check_online_event = event_add_timed(winbind_event_context(),
515 NULL,
516 tev,
517 check_domain_online_handler,
518 domain);
520 /* The above *has* to succeed for winbindd to work. */
521 if (!domain->check_online_event) {
522 smb_panic("set_domain_online_request: failed to add online handler");
526 /****************************************************************
527 Add -ve connection cache entries for domain and realm.
528 ****************************************************************/
530 void winbind_add_failed_connection_entry(const struct winbindd_domain *domain,
531 const char *server,
532 NTSTATUS result)
534 add_failed_connection_entry(domain->name, server, result);
535 /* If this was the saf name for the last thing we talked to,
536 remove it. */
537 saf_delete(domain->name);
538 if (*domain->alt_name) {
539 add_failed_connection_entry(domain->alt_name, server, result);
540 saf_delete(domain->alt_name);
542 winbindd_unset_locator_kdc_env(domain);
545 /* Choose between anonymous or authenticated connections. We need to use
546 an authenticated connection if DCs have the RestrictAnonymous registry
547 entry set > 0, or the "Additional restrictions for anonymous
548 connections" set in the win2k Local Security Policy.
550 Caller to free() result in domain, username, password
553 static void cm_get_ipc_userpass(char **username, char **domain, char **password)
555 *username = (char *)secrets_fetch(SECRETS_AUTH_USER, NULL);
556 *domain = (char *)secrets_fetch(SECRETS_AUTH_DOMAIN, NULL);
557 *password = (char *)secrets_fetch(SECRETS_AUTH_PASSWORD, NULL);
559 if (*username && **username) {
561 if (!*domain || !**domain)
562 *domain = smb_xstrdup(lp_workgroup());
564 if (!*password || !**password)
565 *password = smb_xstrdup("");
567 DEBUG(3, ("cm_get_ipc_userpass: Retrieved auth-user from secrets.tdb [%s\\%s]\n",
568 *domain, *username));
570 } else {
571 DEBUG(3, ("cm_get_ipc_userpass: No auth-user defined\n"));
572 *username = smb_xstrdup("");
573 *domain = smb_xstrdup("");
574 *password = smb_xstrdup("");
578 static bool get_dc_name_via_netlogon(struct winbindd_domain *domain,
579 fstring dcname,
580 struct sockaddr_storage *dc_ss)
582 struct winbindd_domain *our_domain = NULL;
583 struct rpc_pipe_client *netlogon_pipe = NULL;
584 NTSTATUS result;
585 WERROR werr;
586 TALLOC_CTX *mem_ctx;
587 unsigned int orig_timeout;
588 const char *tmp = NULL;
589 const char *p;
591 /* Hmmmm. We can only open one connection to the NETLOGON pipe at the
592 * moment.... */
594 if (IS_DC) {
595 return False;
598 if (domain->primary) {
599 return False;
602 our_domain = find_our_domain();
604 if ((mem_ctx = talloc_init("get_dc_name_via_netlogon")) == NULL) {
605 return False;
608 result = cm_connect_netlogon(our_domain, &netlogon_pipe);
609 if (!NT_STATUS_IS_OK(result)) {
610 talloc_destroy(mem_ctx);
611 return False;
614 /* This call can take a long time - allow the server to time out.
615 35 seconds should do it. */
617 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
619 if (our_domain->active_directory) {
620 struct netr_DsRGetDCNameInfo *domain_info = NULL;
622 result = rpccli_netr_DsRGetDCName(netlogon_pipe,
623 mem_ctx,
624 our_domain->dcname,
625 domain->name,
626 NULL,
627 NULL,
628 DS_RETURN_DNS_NAME,
629 &domain_info,
630 &werr);
631 if (NT_STATUS_IS_OK(result) && W_ERROR_IS_OK(werr)) {
632 tmp = talloc_strdup(
633 mem_ctx, domain_info->dc_unc);
634 if (tmp == NULL) {
635 DEBUG(0, ("talloc_strdup failed\n"));
636 talloc_destroy(mem_ctx);
637 return false;
639 if (strlen(domain->alt_name) == 0) {
640 fstrcpy(domain->alt_name,
641 domain_info->domain_name);
643 if (strlen(domain->forest_name) == 0) {
644 fstrcpy(domain->forest_name,
645 domain_info->forest_name);
648 } else {
649 result = rpccli_netr_GetAnyDCName(netlogon_pipe, mem_ctx,
650 our_domain->dcname,
651 domain->name,
652 &tmp,
653 &werr);
656 /* And restore our original timeout. */
657 rpccli_set_timeout(netlogon_pipe, orig_timeout);
659 if (!NT_STATUS_IS_OK(result)) {
660 DEBUG(10,("rpccli_netr_GetAnyDCName failed: %s\n",
661 nt_errstr(result)));
662 talloc_destroy(mem_ctx);
663 return false;
666 if (!W_ERROR_IS_OK(werr)) {
667 DEBUG(10,("rpccli_netr_GetAnyDCName failed: %s\n",
668 win_errstr(werr)));
669 talloc_destroy(mem_ctx);
670 return false;
673 /* rpccli_netr_GetAnyDCName gives us a name with \\ */
674 p = strip_hostname(tmp);
676 fstrcpy(dcname, p);
678 talloc_destroy(mem_ctx);
680 DEBUG(10,("rpccli_netr_GetAnyDCName returned %s\n", dcname));
682 if (!resolve_name(dcname, dc_ss, 0x20)) {
683 return False;
686 return True;
690 * Helper function to assemble trust password and account name
692 static NTSTATUS get_trust_creds(const struct winbindd_domain *domain,
693 char **machine_password,
694 char **machine_account,
695 char **machine_krb5_principal)
697 const char *account_name;
698 const char *name = NULL;
700 /* If we are a DC and this is not our own domain */
702 if (IS_DC) {
703 name = domain->name;
704 } else {
705 struct winbindd_domain *our_domain = find_our_domain();
707 if (!our_domain)
708 return NT_STATUS_INVALID_SERVER_STATE;
710 name = our_domain->name;
713 if (!get_trust_pw_clear(name, machine_password,
714 &account_name, NULL))
716 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
719 if ((machine_account != NULL) &&
720 (asprintf(machine_account, "%s$", account_name) == -1))
722 return NT_STATUS_NO_MEMORY;
725 /* For now assume our machine account only exists in our domain */
727 if (machine_krb5_principal != NULL)
729 struct winbindd_domain *our_domain = find_our_domain();
731 if (!our_domain) {
732 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
735 if (asprintf(machine_krb5_principal, "%s$@%s",
736 account_name, our_domain->alt_name) == -1)
738 return NT_STATUS_NO_MEMORY;
741 strupper_m(*machine_krb5_principal);
744 return NT_STATUS_OK;
747 /************************************************************************
748 Given a fd with a just-connected TCP connection to a DC, open a connection
749 to the pipe.
750 ************************************************************************/
752 static NTSTATUS cm_prepare_connection(const struct winbindd_domain *domain,
753 const int sockfd,
754 const char *controller,
755 struct cli_state **cli,
756 bool *retry)
758 char *machine_password = NULL;
759 char *machine_krb5_principal = NULL;
760 char *machine_account = NULL;
761 char *ipc_username = NULL;
762 char *ipc_domain = NULL;
763 char *ipc_password = NULL;
765 struct named_mutex *mutex;
767 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
769 struct sockaddr peeraddr;
770 socklen_t peeraddr_len;
772 struct sockaddr_in *peeraddr_in =
773 (struct sockaddr_in *)(void *)&peeraddr;
775 DEBUG(10,("cm_prepare_connection: connecting to DC %s for domain %s\n",
776 controller, domain->name ));
778 *retry = True;
780 mutex = grab_named_mutex(talloc_tos(), controller,
781 WINBIND_SERVER_MUTEX_WAIT_TIME);
782 if (mutex == NULL) {
783 DEBUG(0,("cm_prepare_connection: mutex grab failed for %s\n",
784 controller));
785 result = NT_STATUS_POSSIBLE_DEADLOCK;
786 goto done;
789 if ((*cli = cli_initialise()) == NULL) {
790 DEBUG(1, ("Could not cli_initialize\n"));
791 result = NT_STATUS_NO_MEMORY;
792 goto done;
795 (*cli)->timeout = 10000; /* 10 seconds */
796 (*cli)->fd = sockfd;
797 fstrcpy((*cli)->desthost, controller);
798 (*cli)->use_kerberos = True;
800 peeraddr_len = sizeof(peeraddr);
802 if ((getpeername((*cli)->fd, &peeraddr, &peeraddr_len) != 0) ||
803 (peeraddr_len != sizeof(struct sockaddr_in)) ||
804 (peeraddr_in->sin_family != PF_INET))
806 DEBUG(0,("cm_prepare_connection: %s\n", strerror(errno)));
807 result = NT_STATUS_UNSUCCESSFUL;
808 goto done;
811 if (ntohs(peeraddr_in->sin_port) == 139) {
812 struct nmb_name calling;
813 struct nmb_name called;
815 make_nmb_name(&calling, global_myname(), 0x0);
816 make_nmb_name(&called, "*SMBSERVER", 0x20);
818 if (!cli_session_request(*cli, &calling, &called)) {
819 DEBUG(8, ("cli_session_request failed for %s\n",
820 controller));
821 result = NT_STATUS_UNSUCCESSFUL;
822 goto done;
826 result = cli_negprot(*cli);
828 if (!NT_STATUS_IS_OK(result)) {
829 DEBUG(1, ("cli_negprot failed: %s\n", nt_errstr(result)));
830 goto done;
833 if (!is_dc_trusted_domain_situation(domain->name) &&
834 (*cli)->protocol >= PROTOCOL_NT1 &&
835 (*cli)->capabilities & CAP_EXTENDED_SECURITY)
837 ADS_STATUS ads_status;
839 result = get_trust_creds(domain, &machine_password,
840 &machine_account,
841 &machine_krb5_principal);
842 if (!NT_STATUS_IS_OK(result)) {
843 goto anon_fallback;
846 if (lp_security() == SEC_ADS) {
848 /* Try a krb5 session */
850 (*cli)->use_kerberos = True;
851 DEBUG(5, ("connecting to %s from %s with kerberos principal "
852 "[%s] and realm [%s]\n", controller, global_myname(),
853 machine_krb5_principal, domain->alt_name));
855 winbindd_set_locator_kdc_envs(domain);
857 ads_status = cli_session_setup_spnego(*cli,
858 machine_krb5_principal,
859 machine_password,
860 lp_workgroup(),
861 domain->name);
863 if (!ADS_ERR_OK(ads_status)) {
864 DEBUG(4,("failed kerberos session setup with %s\n",
865 ads_errstr(ads_status)));
868 result = ads_ntstatus(ads_status);
869 if (NT_STATUS_IS_OK(result)) {
870 /* Ensure creds are stored for NTLMSSP authenticated pipe access. */
871 result = cli_init_creds(*cli, machine_account, lp_workgroup(), machine_password);
872 if (!NT_STATUS_IS_OK(result)) {
873 goto done;
875 goto session_setup_done;
879 /* Fall back to non-kerberos session setup using NTLMSSP SPNEGO with the machine account. */
880 (*cli)->use_kerberos = False;
882 DEBUG(5, ("connecting to %s from %s with username "
883 "[%s]\\[%s]\n", controller, global_myname(),
884 lp_workgroup(), machine_account));
886 ads_status = cli_session_setup_spnego(*cli,
887 machine_account,
888 machine_password,
889 lp_workgroup(),
890 NULL);
891 if (!ADS_ERR_OK(ads_status)) {
892 DEBUG(4, ("authenticated session setup failed with %s\n",
893 ads_errstr(ads_status)));
896 result = ads_ntstatus(ads_status);
897 if (NT_STATUS_IS_OK(result)) {
898 /* Ensure creds are stored for NTLMSSP authenticated pipe access. */
899 result = cli_init_creds(*cli, machine_account, lp_workgroup(), machine_password);
900 if (!NT_STATUS_IS_OK(result)) {
901 goto done;
903 goto session_setup_done;
907 /* Fall back to non-kerberos session setup with auth_user */
909 (*cli)->use_kerberos = False;
911 cm_get_ipc_userpass(&ipc_username, &ipc_domain, &ipc_password);
913 if ((((*cli)->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) != 0) &&
914 (strlen(ipc_username) > 0)) {
916 /* Only try authenticated if we have a username */
918 DEBUG(5, ("connecting to %s from %s with username "
919 "[%s]\\[%s]\n", controller, global_myname(),
920 ipc_domain, ipc_username));
922 if (NT_STATUS_IS_OK(cli_session_setup(
923 *cli, ipc_username,
924 ipc_password, strlen(ipc_password)+1,
925 ipc_password, strlen(ipc_password)+1,
926 ipc_domain))) {
927 /* Successful logon with given username. */
928 result = cli_init_creds(*cli, ipc_username, ipc_domain, ipc_password);
929 if (!NT_STATUS_IS_OK(result)) {
930 goto done;
932 goto session_setup_done;
933 } else {
934 DEBUG(4, ("authenticated session setup with user %s\\%s failed.\n",
935 ipc_domain, ipc_username ));
939 anon_fallback:
941 /* Fall back to anonymous connection, this might fail later */
942 DEBUG(10,("cm_prepare_connection: falling back to anonymous "
943 "connection for DC %s\n",
944 controller ));
946 if (NT_STATUS_IS_OK(cli_session_setup(*cli, "", NULL, 0,
947 NULL, 0, ""))) {
948 DEBUG(5, ("Connected anonymously\n"));
949 result = cli_init_creds(*cli, "", "", "");
950 if (!NT_STATUS_IS_OK(result)) {
951 goto done;
953 goto session_setup_done;
956 result = cli_nt_error(*cli);
958 if (NT_STATUS_IS_OK(result))
959 result = NT_STATUS_UNSUCCESSFUL;
961 /* We can't session setup */
963 goto done;
965 session_setup_done:
967 /* cache the server name for later connections */
969 saf_store( domain->name, (*cli)->desthost );
970 if (domain->alt_name && (*cli)->use_kerberos) {
971 saf_store( domain->alt_name, (*cli)->desthost );
974 winbindd_set_locator_kdc_envs(domain);
976 result = cli_tcon_andx(*cli, "IPC$", "IPC", "", 0);
978 if (!NT_STATUS_IS_OK(result)) {
979 DEBUG(1,("failed tcon_X with %s\n", nt_errstr(result)));
980 goto done;
983 TALLOC_FREE(mutex);
984 *retry = False;
986 /* set the domain if empty; needed for schannel connections */
987 if ( !(*cli)->domain[0] ) {
988 result = cli_set_domain((*cli), domain->name);
989 if (!NT_STATUS_IS_OK(result)) {
990 return result;
994 result = NT_STATUS_OK;
996 done:
997 TALLOC_FREE(mutex);
998 SAFE_FREE(machine_account);
999 SAFE_FREE(machine_password);
1000 SAFE_FREE(machine_krb5_principal);
1001 SAFE_FREE(ipc_username);
1002 SAFE_FREE(ipc_domain);
1003 SAFE_FREE(ipc_password);
1005 if (!NT_STATUS_IS_OK(result)) {
1006 winbind_add_failed_connection_entry(domain, controller, result);
1007 if ((*cli) != NULL) {
1008 cli_shutdown(*cli);
1009 *cli = NULL;
1013 return result;
1016 /*******************************************************************
1017 Add a dcname and sockaddr_storage pair to the end of a dc_name_ip
1018 array.
1020 Keeps the list unique by not adding duplicate entries.
1022 @param[in] mem_ctx talloc memory context to allocate from
1023 @param[in] domain_name domain of the DC
1024 @param[in] dcname name of the DC to add to the list
1025 @param[in] pss Internet address and port pair to add to the list
1026 @param[in,out] dcs array of dc_name_ip structures to add to
1027 @param[in,out] num_dcs number of dcs returned in the dcs array
1028 @return true if the list was added to, false otherwise
1029 *******************************************************************/
1031 static bool add_one_dc_unique(TALLOC_CTX *mem_ctx, const char *domain_name,
1032 const char *dcname, struct sockaddr_storage *pss,
1033 struct dc_name_ip **dcs, int *num)
1035 int i = 0;
1037 if (!NT_STATUS_IS_OK(check_negative_conn_cache(domain_name, dcname))) {
1038 DEBUG(10, ("DC %s was in the negative conn cache\n", dcname));
1039 return False;
1042 /* Make sure there's no duplicates in the list */
1043 for (i=0; i<*num; i++)
1044 if (sockaddr_equal(
1045 (struct sockaddr *)(void *)&(*dcs)[i].ss,
1046 (struct sockaddr *)(void *)pss))
1047 return False;
1049 *dcs = TALLOC_REALLOC_ARRAY(mem_ctx, *dcs, struct dc_name_ip, (*num)+1);
1051 if (*dcs == NULL)
1052 return False;
1054 fstrcpy((*dcs)[*num].name, dcname);
1055 (*dcs)[*num].ss = *pss;
1056 *num += 1;
1057 return True;
1060 static bool add_sockaddr_to_array(TALLOC_CTX *mem_ctx,
1061 struct sockaddr_storage *pss, uint16 port,
1062 struct sockaddr_storage **addrs, int *num)
1064 *addrs = TALLOC_REALLOC_ARRAY(mem_ctx, *addrs, struct sockaddr_storage, (*num)+1);
1066 if (*addrs == NULL) {
1067 *num = 0;
1068 return False;
1071 (*addrs)[*num] = *pss;
1072 set_sockaddr_port((struct sockaddr *)&(*addrs)[*num], port);
1074 *num += 1;
1075 return True;
1078 /*******************************************************************
1079 convert an ip to a name
1080 *******************************************************************/
1082 static bool dcip_to_name(TALLOC_CTX *mem_ctx,
1083 const struct winbindd_domain *domain,
1084 struct sockaddr_storage *pss,
1085 fstring name )
1087 struct ip_service ip_list;
1088 uint32_t nt_version = NETLOGON_NT_VERSION_1;
1090 ip_list.ss = *pss;
1091 ip_list.port = 0;
1093 #ifdef WITH_ADS
1094 /* For active directory servers, try to get the ldap server name.
1095 None of these failures should be considered critical for now */
1097 if (lp_security() == SEC_ADS) {
1098 ADS_STRUCT *ads;
1099 ADS_STATUS ads_status;
1100 char addr[INET6_ADDRSTRLEN];
1102 print_sockaddr(addr, sizeof(addr), pss);
1104 ads = ads_init(domain->alt_name, domain->name, addr);
1105 ads->auth.flags |= ADS_AUTH_NO_BIND;
1107 ads_status = ads_connect(ads);
1108 if (ADS_ERR_OK(ads_status)) {
1109 /* We got a cldap packet. */
1110 fstrcpy(name, ads->config.ldap_server_name);
1111 namecache_store(name, 0x20, 1, &ip_list);
1113 DEBUG(10,("dcip_to_name: flags = 0x%x\n", (unsigned int)ads->config.flags));
1115 if (domain->primary && (ads->config.flags & NBT_SERVER_KDC)) {
1116 if (ads_closest_dc(ads)) {
1117 char *sitename = sitename_fetch(ads->config.realm);
1119 /* We're going to use this KDC for this realm/domain.
1120 If we are using sites, then force the krb5 libs
1121 to use this KDC. */
1123 create_local_private_krb5_conf_for_domain(domain->alt_name,
1124 domain->name,
1125 sitename,
1126 pss);
1128 SAFE_FREE(sitename);
1129 } else {
1130 /* use an off site KDC */
1131 create_local_private_krb5_conf_for_domain(domain->alt_name,
1132 domain->name,
1133 NULL,
1134 pss);
1136 winbindd_set_locator_kdc_envs(domain);
1138 /* Ensure we contact this DC also. */
1139 saf_store( domain->name, name);
1140 saf_store( domain->alt_name, name);
1143 ads_destroy( &ads );
1144 return True;
1147 ads_destroy( &ads );
1149 #endif
1151 /* try GETDC requests next */
1153 if (send_getdc_request(mem_ctx, winbind_messaging_context(),
1154 pss, domain->name, &domain->sid,
1155 nt_version)) {
1156 const char *dc_name = NULL;
1157 int i;
1158 smb_msleep(100);
1159 for (i=0; i<5; i++) {
1160 if (receive_getdc_response(mem_ctx, pss, domain->name,
1161 &nt_version,
1162 &dc_name, NULL)) {
1163 fstrcpy(name, dc_name);
1164 namecache_store(name, 0x20, 1, &ip_list);
1165 return True;
1167 smb_msleep(500);
1171 /* try node status request */
1173 if ( name_status_find(domain->name, 0x1c, 0x20, pss, name) ) {
1174 namecache_store(name, 0x20, 1, &ip_list);
1175 return True;
1177 return False;
1180 /*******************************************************************
1181 Retrieve a list of IP addresses for domain controllers.
1183 The array is sorted in the preferred connection order.
1185 @param[in] mem_ctx talloc memory context to allocate from
1186 @param[in] domain domain to retrieve DCs for
1187 @param[out] dcs array of dcs that will be returned
1188 @param[out] num_dcs number of dcs returned in the dcs array
1189 @return always true
1190 *******************************************************************/
1192 static bool get_dcs(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
1193 struct dc_name_ip **dcs, int *num_dcs)
1195 fstring dcname;
1196 struct sockaddr_storage ss;
1197 struct ip_service *ip_list = NULL;
1198 int iplist_size = 0;
1199 int i;
1200 bool is_our_domain;
1201 enum security_types sec = (enum security_types)lp_security();
1203 is_our_domain = strequal(domain->name, lp_workgroup());
1205 /* If not our domain, get the preferred DC, by asking our primary DC */
1206 if ( !is_our_domain
1207 && get_dc_name_via_netlogon(domain, dcname, &ss)
1208 && add_one_dc_unique(mem_ctx, domain->name, dcname, &ss, dcs,
1209 num_dcs) )
1211 char addr[INET6_ADDRSTRLEN];
1212 print_sockaddr(addr, sizeof(addr), &ss);
1213 DEBUG(10, ("Retrieved DC %s at %s via netlogon\n",
1214 dcname, addr));
1215 return True;
1218 if (sec == SEC_ADS) {
1219 char *sitename = NULL;
1221 /* We need to make sure we know the local site before
1222 doing any DNS queries, as this will restrict the
1223 get_sorted_dc_list() call below to only fetching
1224 DNS records for the correct site. */
1226 /* Find any DC to get the site record.
1227 We deliberately don't care about the
1228 return here. */
1230 get_dc_name(domain->name, domain->alt_name, dcname, &ss);
1232 sitename = sitename_fetch(domain->alt_name);
1233 if (sitename) {
1235 /* Do the site-specific AD dns lookup first. */
1236 get_sorted_dc_list(domain->alt_name, sitename, &ip_list,
1237 &iplist_size, True);
1239 /* Add ips to the DC array. We don't look up the name
1240 of the DC in this function, but we fill in the char*
1241 of the ip now to make the failed connection cache
1242 work */
1243 for ( i=0; i<iplist_size; i++ ) {
1244 char addr[INET6_ADDRSTRLEN];
1245 print_sockaddr(addr, sizeof(addr),
1246 &ip_list[i].ss);
1247 add_one_dc_unique(mem_ctx,
1248 domain->name,
1249 addr,
1250 &ip_list[i].ss,
1251 dcs,
1252 num_dcs);
1255 SAFE_FREE(ip_list);
1256 SAFE_FREE(sitename);
1257 iplist_size = 0;
1260 /* Now we add DCs from the main AD DNS lookup. */
1261 get_sorted_dc_list(domain->alt_name, NULL, &ip_list,
1262 &iplist_size, True);
1264 for ( i=0; i<iplist_size; i++ ) {
1265 char addr[INET6_ADDRSTRLEN];
1266 print_sockaddr(addr, sizeof(addr),
1267 &ip_list[i].ss);
1268 add_one_dc_unique(mem_ctx,
1269 domain->name,
1270 addr,
1271 &ip_list[i].ss,
1272 dcs,
1273 num_dcs);
1276 SAFE_FREE(ip_list);
1277 iplist_size = 0;
1280 /* Try standard netbios queries if no ADS */
1281 if (*num_dcs == 0) {
1282 get_sorted_dc_list(domain->name, NULL, &ip_list, &iplist_size,
1283 False);
1285 for ( i=0; i<iplist_size; i++ ) {
1286 char addr[INET6_ADDRSTRLEN];
1287 print_sockaddr(addr, sizeof(addr),
1288 &ip_list[i].ss);
1289 add_one_dc_unique(mem_ctx,
1290 domain->name,
1291 addr,
1292 &ip_list[i].ss,
1293 dcs,
1294 num_dcs);
1297 SAFE_FREE(ip_list);
1298 iplist_size = 0;
1301 return True;
1304 /*******************************************************************
1305 Find and make a connection to a DC in the given domain.
1307 @param[in] mem_ctx talloc memory context to allocate from
1308 @param[in] domain domain to find a dc in
1309 @param[out] dcname NetBIOS or FQDN of DC that's connected to
1310 @param[out] pss DC Internet address and port
1311 @param[out] fd fd of the open socket connected to the newly found dc
1312 @return true when a DC connection is made, false otherwise
1313 *******************************************************************/
1315 static bool find_new_dc(TALLOC_CTX *mem_ctx,
1316 struct winbindd_domain *domain,
1317 fstring dcname, struct sockaddr_storage *pss, int *fd)
1319 struct dc_name_ip *dcs = NULL;
1320 int num_dcs = 0;
1322 const char **dcnames = NULL;
1323 int num_dcnames = 0;
1325 struct sockaddr_storage *addrs = NULL;
1326 int num_addrs = 0;
1328 int i, fd_index;
1330 *fd = -1;
1332 again:
1333 if (!get_dcs(mem_ctx, domain, &dcs, &num_dcs) || (num_dcs == 0))
1334 return False;
1336 for (i=0; i<num_dcs; i++) {
1338 if (!add_string_to_array(mem_ctx, dcs[i].name,
1339 &dcnames, &num_dcnames)) {
1340 return False;
1342 if (!add_sockaddr_to_array(mem_ctx, &dcs[i].ss, 445,
1343 &addrs, &num_addrs)) {
1344 return False;
1347 if (!add_string_to_array(mem_ctx, dcs[i].name,
1348 &dcnames, &num_dcnames)) {
1349 return False;
1351 if (!add_sockaddr_to_array(mem_ctx, &dcs[i].ss, 139,
1352 &addrs, &num_addrs)) {
1353 return False;
1357 if ((num_dcnames == 0) || (num_dcnames != num_addrs))
1358 return False;
1360 if ((addrs == NULL) || (dcnames == NULL))
1361 return False;
1363 /* 5 second timeout. */
1364 if (!open_any_socket_out(addrs, num_addrs, 5000, &fd_index, fd) ) {
1365 for (i=0; i<num_dcs; i++) {
1366 char ab[INET6_ADDRSTRLEN];
1367 print_sockaddr(ab, sizeof(ab), &dcs[i].ss);
1368 DEBUG(10, ("find_new_dc: open_any_socket_out failed for "
1369 "domain %s address %s. Error was %s\n",
1370 domain->name, ab, strerror(errno) ));
1371 winbind_add_failed_connection_entry(domain,
1372 dcs[i].name, NT_STATUS_UNSUCCESSFUL);
1374 return False;
1377 *pss = addrs[fd_index];
1379 if (*dcnames[fd_index] != '\0' && !is_ipaddress(dcnames[fd_index])) {
1380 /* Ok, we've got a name for the DC */
1381 fstrcpy(dcname, dcnames[fd_index]);
1382 return True;
1385 /* Try to figure out the name */
1386 if (dcip_to_name(mem_ctx, domain, pss, dcname)) {
1387 return True;
1390 /* We can not continue without the DC's name */
1391 winbind_add_failed_connection_entry(domain, dcs[fd_index].name,
1392 NT_STATUS_UNSUCCESSFUL);
1394 /* Throw away all arrays as we're doing this again. */
1395 TALLOC_FREE(dcs);
1396 num_dcs = 0;
1398 TALLOC_FREE(dcnames);
1399 num_dcnames = 0;
1401 TALLOC_FREE(addrs);
1402 num_addrs = 0;
1404 close(*fd);
1405 *fd = -1;
1407 goto again;
1410 static NTSTATUS cm_open_connection(struct winbindd_domain *domain,
1411 struct winbindd_cm_conn *new_conn)
1413 TALLOC_CTX *mem_ctx;
1414 NTSTATUS result;
1415 char *saf_servername = saf_fetch( domain->name );
1416 int retries;
1418 if ((mem_ctx = talloc_init("cm_open_connection")) == NULL) {
1419 SAFE_FREE(saf_servername);
1420 set_domain_offline(domain);
1421 return NT_STATUS_NO_MEMORY;
1424 /* we have to check the server affinity cache here since
1425 later we selecte a DC based on response time and not preference */
1427 /* Check the negative connection cache
1428 before talking to it. It going down may have
1429 triggered the reconnection. */
1431 if ( saf_servername && NT_STATUS_IS_OK(check_negative_conn_cache( domain->name, saf_servername))) {
1433 DEBUG(10,("cm_open_connection: saf_servername is '%s' for domain %s\n",
1434 saf_servername, domain->name ));
1436 /* convert an ip address to a name */
1437 if (is_ipaddress( saf_servername ) ) {
1438 fstring saf_name;
1439 struct sockaddr_storage ss;
1441 if (!interpret_string_addr(&ss, saf_servername,
1442 AI_NUMERICHOST)) {
1443 return NT_STATUS_UNSUCCESSFUL;
1445 if (dcip_to_name(mem_ctx, domain, &ss, saf_name )) {
1446 fstrcpy( domain->dcname, saf_name );
1447 } else {
1448 winbind_add_failed_connection_entry(
1449 domain, saf_servername,
1450 NT_STATUS_UNSUCCESSFUL);
1452 } else {
1453 fstrcpy( domain->dcname, saf_servername );
1456 SAFE_FREE( saf_servername );
1459 for (retries = 0; retries < 3; retries++) {
1460 int fd = -1;
1461 bool retry = False;
1463 result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
1465 DEBUG(10,("cm_open_connection: dcname is '%s' for domain %s\n",
1466 domain->dcname, domain->name ));
1468 if (*domain->dcname
1469 && NT_STATUS_IS_OK(check_negative_conn_cache( domain->name, domain->dcname))
1470 && (resolve_name(domain->dcname, &domain->dcaddr, 0x20)))
1472 struct sockaddr_storage *addrs = NULL;
1473 int num_addrs = 0;
1474 int dummy = 0;
1476 if (!add_sockaddr_to_array(mem_ctx, &domain->dcaddr, 445, &addrs, &num_addrs)) {
1477 set_domain_offline(domain);
1478 talloc_destroy(mem_ctx);
1479 return NT_STATUS_NO_MEMORY;
1481 if (!add_sockaddr_to_array(mem_ctx, &domain->dcaddr, 139, &addrs, &num_addrs)) {
1482 set_domain_offline(domain);
1483 talloc_destroy(mem_ctx);
1484 return NT_STATUS_NO_MEMORY;
1487 /* 5 second timeout. */
1488 if (!open_any_socket_out(addrs, num_addrs, 5000, &dummy, &fd)) {
1489 fd = -1;
1493 if ((fd == -1)
1494 && !find_new_dc(mem_ctx, domain, domain->dcname, &domain->dcaddr, &fd))
1496 /* This is the one place where we will
1497 set the global winbindd offline state
1498 to true, if a "WINBINDD_OFFLINE" entry
1499 is found in the winbindd cache. */
1500 set_global_winbindd_state_offline();
1501 break;
1504 new_conn->cli = NULL;
1506 result = cm_prepare_connection(domain, fd, domain->dcname,
1507 &new_conn->cli, &retry);
1509 if (!retry)
1510 break;
1513 if (NT_STATUS_IS_OK(result)) {
1515 winbindd_set_locator_kdc_envs(domain);
1517 if (domain->online == False) {
1518 /* We're changing state from offline to online. */
1519 set_global_winbindd_state_online();
1521 set_domain_online(domain);
1522 } else {
1523 /* Ensure we setup the retry handler. */
1524 set_domain_offline(domain);
1527 talloc_destroy(mem_ctx);
1528 return result;
1531 /* Close down all open pipes on a connection. */
1533 void invalidate_cm_connection(struct winbindd_cm_conn *conn)
1535 /* We're closing down a possibly dead
1536 connection. Don't have impossibly long (10s) timeouts. */
1538 if (conn->cli) {
1539 cli_set_timeout(conn->cli, 1000); /* 1 second. */
1542 if (conn->samr_pipe != NULL) {
1543 TALLOC_FREE(conn->samr_pipe);
1544 /* Ok, it must be dead. Drop timeout to 0.5 sec. */
1545 if (conn->cli) {
1546 cli_set_timeout(conn->cli, 500);
1550 if (conn->lsa_pipe != NULL) {
1551 TALLOC_FREE(conn->lsa_pipe);
1552 /* Ok, it must be dead. Drop timeout to 0.5 sec. */
1553 if (conn->cli) {
1554 cli_set_timeout(conn->cli, 500);
1558 if (conn->netlogon_pipe != NULL) {
1559 TALLOC_FREE(conn->netlogon_pipe);
1560 /* Ok, it must be dead. Drop timeout to 0.5 sec. */
1561 if (conn->cli) {
1562 cli_set_timeout(conn->cli, 500);
1566 if (conn->cli) {
1567 cli_shutdown(conn->cli);
1570 conn->cli = NULL;
1573 void close_conns_after_fork(void)
1575 struct winbindd_domain *domain;
1577 for (domain = domain_list(); domain; domain = domain->next) {
1578 if (domain->conn.cli == NULL)
1579 continue;
1581 if (domain->conn.cli->fd == -1)
1582 continue;
1584 close(domain->conn.cli->fd);
1585 domain->conn.cli->fd = -1;
1589 static bool connection_ok(struct winbindd_domain *domain)
1591 if (domain->conn.cli == NULL) {
1592 DEBUG(8, ("connection_ok: Connection to %s for domain %s has NULL "
1593 "cli!\n", domain->dcname, domain->name));
1594 return False;
1597 if (!domain->conn.cli->initialised) {
1598 DEBUG(3, ("connection_ok: Connection to %s for domain %s was never "
1599 "initialised!\n", domain->dcname, domain->name));
1600 return False;
1603 if (domain->conn.cli->fd == -1) {
1604 DEBUG(3, ("connection_ok: Connection to %s for domain %s has died or was "
1605 "never started (fd == -1)\n",
1606 domain->dcname, domain->name));
1607 return False;
1610 if (domain->online == False) {
1611 DEBUG(3, ("connection_ok: Domain %s is offline\n", domain->name));
1612 return False;
1615 return True;
1618 /* Initialize a new connection up to the RPC BIND.
1619 Bypass online status check so always does network calls. */
1621 static NTSTATUS init_dc_connection_network(struct winbindd_domain *domain)
1623 NTSTATUS result;
1625 /* Internal connections never use the network. */
1626 if (domain->internal) {
1627 domain->initialized = True;
1628 return NT_STATUS_OK;
1631 if (connection_ok(domain)) {
1632 if (!domain->initialized) {
1633 set_dc_type_and_flags(domain);
1635 return NT_STATUS_OK;
1638 invalidate_cm_connection(&domain->conn);
1640 result = cm_open_connection(domain, &domain->conn);
1642 if (NT_STATUS_IS_OK(result) && !domain->initialized) {
1643 set_dc_type_and_flags(domain);
1646 return result;
1649 NTSTATUS init_dc_connection(struct winbindd_domain *domain)
1651 if (domain->initialized && !domain->online) {
1652 /* We check for online status elsewhere. */
1653 return NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
1656 return init_dc_connection_network(domain);
1659 /******************************************************************************
1660 Set the trust flags (direction and forest location) for a domain
1661 ******************************************************************************/
1663 static bool set_dc_type_and_flags_trustinfo( struct winbindd_domain *domain )
1665 struct winbindd_domain *our_domain;
1666 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1667 struct netr_DomainTrustList trusts;
1668 int i;
1669 uint32 flags = (NETR_TRUST_FLAG_IN_FOREST |
1670 NETR_TRUST_FLAG_OUTBOUND |
1671 NETR_TRUST_FLAG_INBOUND);
1672 struct rpc_pipe_client *cli;
1673 TALLOC_CTX *mem_ctx = NULL;
1675 DEBUG(5, ("set_dc_type_and_flags_trustinfo: domain %s\n", domain->name ));
1677 /* Our primary domain doesn't need to worry about trust flags.
1678 Force it to go through the network setup */
1679 if ( domain->primary ) {
1680 return False;
1683 our_domain = find_our_domain();
1685 if ( !connection_ok(our_domain) ) {
1686 DEBUG(3,("set_dc_type_and_flags_trustinfo: No connection to our domain!\n"));
1687 return False;
1690 /* This won't work unless our domain is AD */
1692 if ( !our_domain->active_directory ) {
1693 return False;
1696 /* Use DsEnumerateDomainTrusts to get us the trust direction
1697 and type */
1699 result = cm_connect_netlogon(our_domain, &cli);
1701 if (!NT_STATUS_IS_OK(result)) {
1702 DEBUG(5, ("set_dc_type_and_flags_trustinfo: Could not open "
1703 "a connection to %s for PIPE_NETLOGON (%s)\n",
1704 domain->name, nt_errstr(result)));
1705 return False;
1708 if ( (mem_ctx = talloc_init("set_dc_type_and_flags_trustinfo")) == NULL ) {
1709 DEBUG(0,("set_dc_type_and_flags_trustinfo: talloc_init() failed!\n"));
1710 return False;
1713 result = rpccli_netr_DsrEnumerateDomainTrusts(cli, mem_ctx,
1714 cli->desthost,
1715 flags,
1716 &trusts,
1717 NULL);
1718 if (!NT_STATUS_IS_OK(result)) {
1719 DEBUG(0,("set_dc_type_and_flags_trustinfo: "
1720 "failed to query trusted domain list: %s\n",
1721 nt_errstr(result)));
1722 talloc_destroy(mem_ctx);
1723 return false;
1726 /* Now find the domain name and get the flags */
1728 for ( i=0; i<trusts.count; i++ ) {
1729 if ( strequal( domain->name, trusts.array[i].netbios_name) ) {
1730 domain->domain_flags = trusts.array[i].trust_flags;
1731 domain->domain_type = trusts.array[i].trust_type;
1732 domain->domain_trust_attribs = trusts.array[i].trust_attributes;
1734 if ( domain->domain_type == NETR_TRUST_TYPE_UPLEVEL )
1735 domain->active_directory = True;
1737 /* This flag is only set if the domain is *our*
1738 primary domain and the primary domain is in
1739 native mode */
1741 domain->native_mode = (domain->domain_flags & NETR_TRUST_FLAG_NATIVE);
1743 DEBUG(5, ("set_dc_type_and_flags_trustinfo: domain %s is %sin "
1744 "native mode.\n", domain->name,
1745 domain->native_mode ? "" : "NOT "));
1747 DEBUG(5,("set_dc_type_and_flags_trustinfo: domain %s is %s"
1748 "running active directory.\n", domain->name,
1749 domain->active_directory ? "" : "NOT "));
1752 domain->initialized = True;
1754 if ( !winbindd_can_contact_domain( domain) )
1755 domain->internal = True;
1757 break;
1761 talloc_destroy( mem_ctx );
1763 return domain->initialized;
1766 /******************************************************************************
1767 We can 'sense' certain things about the DC by it's replies to certain
1768 questions.
1770 This tells us if this particular remote server is Active Directory, and if it
1771 is native mode.
1772 ******************************************************************************/
1774 static void set_dc_type_and_flags_connect( struct winbindd_domain *domain )
1776 NTSTATUS result;
1777 WERROR werr;
1778 TALLOC_CTX *mem_ctx = NULL;
1779 struct rpc_pipe_client *cli = NULL;
1780 struct policy_handle pol;
1781 union dssetup_DsRoleInfo info;
1782 union lsa_PolicyInformation *lsa_info = NULL;
1784 if (!connection_ok(domain)) {
1785 return;
1788 mem_ctx = talloc_init("set_dc_type_and_flags on domain %s\n",
1789 domain->name);
1790 if (!mem_ctx) {
1791 DEBUG(1, ("set_dc_type_and_flags_connect: talloc_init() failed\n"));
1792 return;
1795 DEBUG(5, ("set_dc_type_and_flags_connect: domain %s\n", domain->name ));
1797 result = cli_rpc_pipe_open_noauth(domain->conn.cli,
1798 &ndr_table_dssetup.syntax_id,
1799 &cli);
1801 if (!NT_STATUS_IS_OK(result)) {
1802 DEBUG(5, ("set_dc_type_and_flags_connect: Could not bind to "
1803 "PI_DSSETUP on domain %s: (%s)\n",
1804 domain->name, nt_errstr(result)));
1806 /* if this is just a non-AD domain we need to continue
1807 * identifying so that we can in the end return with
1808 * domain->initialized = True - gd */
1810 goto no_dssetup;
1813 result = rpccli_dssetup_DsRoleGetPrimaryDomainInformation(cli, mem_ctx,
1814 DS_ROLE_BASIC_INFORMATION,
1815 &info,
1816 &werr);
1817 TALLOC_FREE(cli);
1819 if (!NT_STATUS_IS_OK(result)) {
1820 DEBUG(5, ("set_dc_type_and_flags_connect: rpccli_ds_getprimarydominfo "
1821 "on domain %s failed: (%s)\n",
1822 domain->name, nt_errstr(result)));
1824 /* older samba3 DCs will return DCERPC_FAULT_OP_RNG_ERROR for
1825 * every opcode on the DSSETUP pipe, continue with
1826 * no_dssetup mode here as well to get domain->initialized
1827 * set - gd */
1829 if (NT_STATUS_V(result) == DCERPC_FAULT_OP_RNG_ERROR) {
1830 goto no_dssetup;
1833 TALLOC_FREE(mem_ctx);
1834 return;
1837 if ((info.basic.flags & DS_ROLE_PRIMARY_DS_RUNNING) &&
1838 !(info.basic.flags & DS_ROLE_PRIMARY_DS_MIXED_MODE)) {
1839 domain->native_mode = True;
1840 } else {
1841 domain->native_mode = False;
1844 no_dssetup:
1845 result = cli_rpc_pipe_open_noauth(domain->conn.cli,
1846 &ndr_table_lsarpc.syntax_id, &cli);
1848 if (!NT_STATUS_IS_OK(result)) {
1849 DEBUG(5, ("set_dc_type_and_flags_connect: Could not bind to "
1850 "PI_LSARPC on domain %s: (%s)\n",
1851 domain->name, nt_errstr(result)));
1852 TALLOC_FREE(cli);
1853 TALLOC_FREE(mem_ctx);
1854 return;
1857 result = rpccli_lsa_open_policy2(cli, mem_ctx, True,
1858 SEC_FLAG_MAXIMUM_ALLOWED, &pol);
1860 if (NT_STATUS_IS_OK(result)) {
1861 /* This particular query is exactly what Win2k clients use
1862 to determine that the DC is active directory */
1863 result = rpccli_lsa_QueryInfoPolicy2(cli, mem_ctx,
1864 &pol,
1865 LSA_POLICY_INFO_DNS,
1866 &lsa_info);
1869 if (NT_STATUS_IS_OK(result)) {
1870 domain->active_directory = True;
1872 if (lsa_info->dns.name.string) {
1873 fstrcpy(domain->name, lsa_info->dns.name.string);
1876 if (lsa_info->dns.dns_domain.string) {
1877 fstrcpy(domain->alt_name,
1878 lsa_info->dns.dns_domain.string);
1881 /* See if we can set some domain trust flags about
1882 ourself */
1884 if (lsa_info->dns.dns_forest.string) {
1885 fstrcpy(domain->forest_name,
1886 lsa_info->dns.dns_forest.string);
1888 if (strequal(domain->forest_name, domain->alt_name)) {
1889 domain->domain_flags |= NETR_TRUST_FLAG_TREEROOT;
1893 if (lsa_info->dns.sid) {
1894 sid_copy(&domain->sid, lsa_info->dns.sid);
1896 } else {
1897 domain->active_directory = False;
1899 result = rpccli_lsa_open_policy(cli, mem_ctx, True,
1900 SEC_FLAG_MAXIMUM_ALLOWED,
1901 &pol);
1903 if (!NT_STATUS_IS_OK(result)) {
1904 goto done;
1907 result = rpccli_lsa_QueryInfoPolicy(cli, mem_ctx,
1908 &pol,
1909 LSA_POLICY_INFO_ACCOUNT_DOMAIN,
1910 &lsa_info);
1912 if (NT_STATUS_IS_OK(result)) {
1914 if (lsa_info->account_domain.name.string) {
1915 fstrcpy(domain->name,
1916 lsa_info->account_domain.name.string);
1919 if (lsa_info->account_domain.sid) {
1920 sid_copy(&domain->sid, lsa_info->account_domain.sid);
1924 done:
1926 DEBUG(5, ("set_dc_type_and_flags_connect: domain %s is %sin native mode.\n",
1927 domain->name, domain->native_mode ? "" : "NOT "));
1929 DEBUG(5,("set_dc_type_and_flags_connect: domain %s is %srunning active directory.\n",
1930 domain->name, domain->active_directory ? "" : "NOT "));
1932 TALLOC_FREE(cli);
1934 TALLOC_FREE(mem_ctx);
1936 domain->initialized = True;
1939 /**********************************************************************
1940 Set the domain_flags (trust attributes, domain operating modes, etc...
1941 ***********************************************************************/
1943 static void set_dc_type_and_flags( struct winbindd_domain *domain )
1945 /* we always have to contact our primary domain */
1947 if ( domain->primary ) {
1948 DEBUG(10,("set_dc_type_and_flags: setting up flags for "
1949 "primary domain\n"));
1950 set_dc_type_and_flags_connect( domain );
1951 return;
1954 /* Use our DC to get the information if possible */
1956 if ( !set_dc_type_and_flags_trustinfo( domain ) ) {
1957 /* Otherwise, fallback to contacting the
1958 domain directly */
1959 set_dc_type_and_flags_connect( domain );
1962 return;
1967 /**********************************************************************
1968 ***********************************************************************/
1970 static bool cm_get_schannel_creds(struct winbindd_domain *domain,
1971 struct netlogon_creds_CredentialState **ppdc)
1973 NTSTATUS result;
1974 struct rpc_pipe_client *netlogon_pipe;
1976 if (lp_client_schannel() == False) {
1977 return False;
1980 result = cm_connect_netlogon(domain, &netlogon_pipe);
1981 if (!NT_STATUS_IS_OK(result)) {
1982 return False;
1985 /* Return a pointer to the struct netlogon_creds_CredentialState from the
1986 netlogon pipe. */
1988 if (!domain->conn.netlogon_pipe->dc) {
1989 return false;
1992 *ppdc = domain->conn.netlogon_pipe->dc;
1993 return True;
1996 NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
1997 struct rpc_pipe_client **cli, struct policy_handle *sam_handle)
1999 struct winbindd_cm_conn *conn;
2000 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
2001 struct netlogon_creds_CredentialState *p_creds;
2002 char *machine_password = NULL;
2003 char *machine_account = NULL;
2004 char *domain_name = NULL;
2006 result = init_dc_connection(domain);
2007 if (!NT_STATUS_IS_OK(result)) {
2008 return result;
2011 conn = &domain->conn;
2013 if (conn->samr_pipe != NULL) {
2014 goto done;
2019 * No SAMR pipe yet. Attempt to get an NTLMSSP SPNEGO authenticated
2020 * sign and sealed pipe using the machine account password by
2021 * preference. If we can't - try schannel, if that fails, try
2022 * anonymous.
2025 if ((conn->cli->user_name[0] == '\0') ||
2026 (conn->cli->domain[0] == '\0') ||
2027 (conn->cli->password == NULL || conn->cli->password[0] == '\0'))
2029 result = get_trust_creds(domain, &machine_password,
2030 &machine_account, NULL);
2031 if (!NT_STATUS_IS_OK(result)) {
2032 DEBUG(10, ("cm_connect_sam: No no user available for "
2033 "domain %s, trying schannel\n", conn->cli->domain));
2034 goto schannel;
2036 domain_name = domain->name;
2037 } else {
2038 machine_password = SMB_STRDUP(conn->cli->password);
2039 machine_account = SMB_STRDUP(conn->cli->user_name);
2040 domain_name = conn->cli->domain;
2043 if (!machine_password || !machine_account) {
2044 result = NT_STATUS_NO_MEMORY;
2045 goto done;
2048 /* We have an authenticated connection. Use a NTLMSSP SPNEGO
2049 authenticated SAMR pipe with sign & seal. */
2050 result = cli_rpc_pipe_open_spnego_ntlmssp(conn->cli,
2051 &ndr_table_samr.syntax_id,
2052 PIPE_AUTH_LEVEL_PRIVACY,
2053 domain_name,
2054 machine_account,
2055 machine_password,
2056 &conn->samr_pipe);
2058 if (!NT_STATUS_IS_OK(result)) {
2059 DEBUG(10,("cm_connect_sam: failed to connect to SAMR "
2060 "pipe for domain %s using NTLMSSP "
2061 "authenticated pipe: user %s\\%s. Error was "
2062 "%s\n", domain->name, domain_name,
2063 machine_account, nt_errstr(result)));
2064 goto schannel;
2067 DEBUG(10,("cm_connect_sam: connected to SAMR pipe for "
2068 "domain %s using NTLMSSP authenticated "
2069 "pipe: user %s\\%s\n", domain->name,
2070 domain_name, machine_account));
2072 result = rpccli_samr_Connect2(conn->samr_pipe, mem_ctx,
2073 conn->samr_pipe->desthost,
2074 SEC_FLAG_MAXIMUM_ALLOWED,
2075 &conn->sam_connect_handle);
2076 if (NT_STATUS_IS_OK(result)) {
2077 goto open_domain;
2079 DEBUG(10,("cm_connect_sam: ntlmssp-sealed rpccli_samr_Connect2 "
2080 "failed for domain %s, error was %s. Trying schannel\n",
2081 domain->name, nt_errstr(result) ));
2082 TALLOC_FREE(conn->samr_pipe);
2084 schannel:
2086 /* Fall back to schannel if it's a W2K pre-SP1 box. */
2088 if (!cm_get_schannel_creds(domain, &p_creds)) {
2089 /* If this call fails - conn->cli can now be NULL ! */
2090 DEBUG(10, ("cm_connect_sam: Could not get schannel auth info "
2091 "for domain %s, trying anon\n", domain->name));
2092 goto anonymous;
2094 result = cli_rpc_pipe_open_schannel_with_key
2095 (conn->cli, &ndr_table_samr.syntax_id, PIPE_AUTH_LEVEL_PRIVACY,
2096 domain->name, &p_creds, &conn->samr_pipe);
2098 if (!NT_STATUS_IS_OK(result)) {
2099 DEBUG(10,("cm_connect_sam: failed to connect to SAMR pipe for "
2100 "domain %s using schannel. Error was %s\n",
2101 domain->name, nt_errstr(result) ));
2102 goto anonymous;
2104 DEBUG(10,("cm_connect_sam: connected to SAMR pipe for domain %s using "
2105 "schannel.\n", domain->name ));
2107 result = rpccli_samr_Connect2(conn->samr_pipe, mem_ctx,
2108 conn->samr_pipe->desthost,
2109 SEC_FLAG_MAXIMUM_ALLOWED,
2110 &conn->sam_connect_handle);
2111 if (NT_STATUS_IS_OK(result)) {
2112 goto open_domain;
2114 DEBUG(10,("cm_connect_sam: schannel-sealed rpccli_samr_Connect2 failed "
2115 "for domain %s, error was %s. Trying anonymous\n",
2116 domain->name, nt_errstr(result) ));
2117 TALLOC_FREE(conn->samr_pipe);
2119 anonymous:
2121 /* Finally fall back to anonymous. */
2122 result = cli_rpc_pipe_open_noauth(conn->cli, &ndr_table_samr.syntax_id,
2123 &conn->samr_pipe);
2125 if (!NT_STATUS_IS_OK(result)) {
2126 goto done;
2129 result = rpccli_samr_Connect2(conn->samr_pipe, mem_ctx,
2130 conn->samr_pipe->desthost,
2131 SEC_FLAG_MAXIMUM_ALLOWED,
2132 &conn->sam_connect_handle);
2133 if (!NT_STATUS_IS_OK(result)) {
2134 DEBUG(10,("cm_connect_sam: rpccli_samr_Connect2 failed "
2135 "for domain %s Error was %s\n",
2136 domain->name, nt_errstr(result) ));
2137 goto done;
2140 open_domain:
2141 result = rpccli_samr_OpenDomain(conn->samr_pipe,
2142 mem_ctx,
2143 &conn->sam_connect_handle,
2144 SEC_FLAG_MAXIMUM_ALLOWED,
2145 &domain->sid,
2146 &conn->sam_domain_handle);
2148 done:
2150 if (!NT_STATUS_IS_OK(result)) {
2151 invalidate_cm_connection(conn);
2152 return result;
2155 *cli = conn->samr_pipe;
2156 *sam_handle = conn->sam_domain_handle;
2157 SAFE_FREE(machine_password);
2158 SAFE_FREE(machine_account);
2159 return result;
2162 NTSTATUS cm_connect_lsa(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
2163 struct rpc_pipe_client **cli, struct policy_handle *lsa_policy)
2165 struct winbindd_cm_conn *conn;
2166 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
2167 struct netlogon_creds_CredentialState *p_creds;
2169 result = init_dc_connection(domain);
2170 if (!NT_STATUS_IS_OK(result))
2171 return result;
2173 conn = &domain->conn;
2175 if (conn->lsa_pipe != NULL) {
2176 goto done;
2179 if ((conn->cli->user_name[0] == '\0') ||
2180 (conn->cli->domain[0] == '\0') ||
2181 (conn->cli->password == NULL || conn->cli->password[0] == '\0')) {
2182 DEBUG(10, ("cm_connect_lsa: No no user available for "
2183 "domain %s, trying schannel\n", conn->cli->domain));
2184 goto schannel;
2187 /* We have an authenticated connection. Use a NTLMSSP SPNEGO
2188 * authenticated LSA pipe with sign & seal. */
2189 result = cli_rpc_pipe_open_spnego_ntlmssp
2190 (conn->cli, &ndr_table_lsarpc.syntax_id,
2191 PIPE_AUTH_LEVEL_PRIVACY,
2192 conn->cli->domain, conn->cli->user_name, conn->cli->password,
2193 &conn->lsa_pipe);
2195 if (!NT_STATUS_IS_OK(result)) {
2196 DEBUG(10,("cm_connect_lsa: failed to connect to LSA pipe for "
2197 "domain %s using NTLMSSP authenticated pipe: user "
2198 "%s\\%s. Error was %s. Trying schannel.\n",
2199 domain->name, conn->cli->domain,
2200 conn->cli->user_name, nt_errstr(result)));
2201 goto schannel;
2204 DEBUG(10,("cm_connect_lsa: connected to LSA pipe for domain %s using "
2205 "NTLMSSP authenticated pipe: user %s\\%s\n",
2206 domain->name, conn->cli->domain, conn->cli->user_name ));
2208 result = rpccli_lsa_open_policy(conn->lsa_pipe, mem_ctx, True,
2209 SEC_FLAG_MAXIMUM_ALLOWED,
2210 &conn->lsa_policy);
2211 if (NT_STATUS_IS_OK(result)) {
2212 goto done;
2215 DEBUG(10,("cm_connect_lsa: rpccli_lsa_open_policy failed, trying "
2216 "schannel\n"));
2218 TALLOC_FREE(conn->lsa_pipe);
2220 schannel:
2222 /* Fall back to schannel if it's a W2K pre-SP1 box. */
2224 if (!cm_get_schannel_creds(domain, &p_creds)) {
2225 /* If this call fails - conn->cli can now be NULL ! */
2226 DEBUG(10, ("cm_connect_lsa: Could not get schannel auth info "
2227 "for domain %s, trying anon\n", domain->name));
2228 goto anonymous;
2230 result = cli_rpc_pipe_open_schannel_with_key
2231 (conn->cli, &ndr_table_lsarpc.syntax_id,
2232 PIPE_AUTH_LEVEL_PRIVACY,
2233 domain->name, &p_creds, &conn->lsa_pipe);
2235 if (!NT_STATUS_IS_OK(result)) {
2236 DEBUG(10,("cm_connect_lsa: failed to connect to LSA pipe for "
2237 "domain %s using schannel. Error was %s\n",
2238 domain->name, nt_errstr(result) ));
2239 goto anonymous;
2241 DEBUG(10,("cm_connect_lsa: connected to LSA pipe for domain %s using "
2242 "schannel.\n", domain->name ));
2244 result = rpccli_lsa_open_policy(conn->lsa_pipe, mem_ctx, True,
2245 SEC_FLAG_MAXIMUM_ALLOWED,
2246 &conn->lsa_policy);
2247 if (NT_STATUS_IS_OK(result)) {
2248 goto done;
2251 DEBUG(10,("cm_connect_lsa: rpccli_lsa_open_policy failed, trying "
2252 "anonymous\n"));
2254 TALLOC_FREE(conn->lsa_pipe);
2256 anonymous:
2258 result = cli_rpc_pipe_open_noauth(conn->cli,
2259 &ndr_table_lsarpc.syntax_id,
2260 &conn->lsa_pipe);
2261 if (!NT_STATUS_IS_OK(result)) {
2262 result = NT_STATUS_PIPE_NOT_AVAILABLE;
2263 goto done;
2266 result = rpccli_lsa_open_policy(conn->lsa_pipe, mem_ctx, True,
2267 SEC_FLAG_MAXIMUM_ALLOWED,
2268 &conn->lsa_policy);
2269 done:
2270 if (!NT_STATUS_IS_OK(result)) {
2271 invalidate_cm_connection(conn);
2272 return result;
2275 *cli = conn->lsa_pipe;
2276 *lsa_policy = conn->lsa_policy;
2277 return result;
2280 /****************************************************************************
2281 Open the netlogon pipe to this DC. Use schannel if specified in client conf.
2282 session key stored in conn->netlogon_pipe->dc->sess_key.
2283 ****************************************************************************/
2285 NTSTATUS cm_connect_netlogon(struct winbindd_domain *domain,
2286 struct rpc_pipe_client **cli)
2288 struct winbindd_cm_conn *conn;
2289 NTSTATUS result;
2291 uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
2292 uint8 mach_pwd[16];
2293 uint32 sec_chan_type;
2294 const char *account_name;
2295 struct rpc_pipe_client *netlogon_pipe = NULL;
2297 *cli = NULL;
2299 result = init_dc_connection(domain);
2300 if (!NT_STATUS_IS_OK(result)) {
2301 return result;
2304 conn = &domain->conn;
2306 if (conn->netlogon_pipe != NULL) {
2307 *cli = conn->netlogon_pipe;
2308 return NT_STATUS_OK;
2311 result = cli_rpc_pipe_open_noauth(conn->cli,
2312 &ndr_table_netlogon.syntax_id,
2313 &netlogon_pipe);
2314 if (!NT_STATUS_IS_OK(result)) {
2315 return result;
2318 if ((!IS_DC) && (!domain->primary)) {
2319 /* Clear the schannel request bit and drop down */
2320 neg_flags &= ~NETLOGON_NEG_SCHANNEL;
2321 goto no_schannel;
2324 if (lp_client_schannel() != False) {
2325 neg_flags |= NETLOGON_NEG_SCHANNEL;
2328 if (!get_trust_pw_hash(domain->name, mach_pwd, &account_name,
2329 &sec_chan_type))
2331 TALLOC_FREE(netlogon_pipe);
2332 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
2335 result = rpccli_netlogon_setup_creds(
2336 netlogon_pipe,
2337 domain->dcname, /* server name. */
2338 domain->name, /* domain name */
2339 global_myname(), /* client name */
2340 account_name, /* machine account */
2341 mach_pwd, /* machine password */
2342 sec_chan_type, /* from get_trust_pw */
2343 &neg_flags);
2345 if (!NT_STATUS_IS_OK(result)) {
2346 TALLOC_FREE(netlogon_pipe);
2347 return result;
2350 if ((lp_client_schannel() == True) &&
2351 ((neg_flags & NETLOGON_NEG_SCHANNEL) == 0)) {
2352 DEBUG(3, ("Server did not offer schannel\n"));
2353 TALLOC_FREE(netlogon_pipe);
2354 return NT_STATUS_ACCESS_DENIED;
2357 no_schannel:
2358 if ((lp_client_schannel() == False) ||
2359 ((neg_flags & NETLOGON_NEG_SCHANNEL) == 0)) {
2361 * NetSamLogonEx only works for schannel
2363 domain->can_do_samlogon_ex = False;
2365 /* We're done - just keep the existing connection to NETLOGON
2366 * open */
2367 conn->netlogon_pipe = netlogon_pipe;
2368 *cli = conn->netlogon_pipe;
2369 return NT_STATUS_OK;
2372 /* Using the credentials from the first pipe, open a signed and sealed
2373 second netlogon pipe. The session key is stored in the schannel
2374 part of the new pipe auth struct.
2377 result = cli_rpc_pipe_open_schannel_with_key(
2378 conn->cli, &ndr_table_netlogon.syntax_id,
2379 PIPE_AUTH_LEVEL_PRIVACY, domain->name, &netlogon_pipe->dc,
2380 &conn->netlogon_pipe);
2382 /* We can now close the initial netlogon pipe. */
2383 TALLOC_FREE(netlogon_pipe);
2385 if (!NT_STATUS_IS_OK(result)) {
2386 DEBUG(3, ("Could not open schannel'ed NETLOGON pipe. Error "
2387 "was %s\n", nt_errstr(result)));
2389 /* make sure we return something besides OK */
2390 return !NT_STATUS_IS_OK(result) ? result : NT_STATUS_PIPE_NOT_AVAILABLE;
2394 * Try NetSamLogonEx for AD domains
2396 domain->can_do_samlogon_ex = domain->active_directory;
2398 *cli = conn->netlogon_pipe;
2399 return NT_STATUS_OK;