Add winbind:online check timeout parameter
[Samba.git] / source3 / winbindd / winbindd_cm.c
blobc6dab6f2e6e6ff4fc398bb0a5cd623447e5ab686
1 /*
2 Unix SMB/CIFS implementation.
4 Winbind daemon connection manager
6 Copyright (C) Tim Potter 2001
7 Copyright (C) Andrew Bartlett 2002
8 Copyright (C) Gerald (Jerry) Carter 2003-2005.
9 Copyright (C) Volker Lendecke 2004-2005
10 Copyright (C) Jeremy Allison 2006
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 3 of the License, or
15 (at your option) any later version.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program. If not, see <http://www.gnu.org/licenses/>.
27 We need to manage connections to domain controllers without having to
28 mess up the main winbindd code with other issues. The aim of the
29 connection manager is to:
31 - make connections to domain controllers and cache them
32 - re-establish connections when networks or servers go down
33 - centralise the policy on connection timeouts, domain controller
34 selection etc
35 - manage re-entrancy for when winbindd becomes able to handle
36 multiple outstanding rpc requests
38 Why not have connection management as part of the rpc layer like tng?
39 Good question. This code may morph into libsmb/rpc_cache.c or something
40 like that but at the moment it's simply staying as part of winbind. I
41 think the TNG architecture of forcing every user of the rpc layer to use
42 the connection caching system is a bad idea. It should be an optional
43 method of using the routines.
45 The TNG design is quite good but I disagree with some aspects of the
46 implementation. -tpot
51 TODO:
53 - I'm pretty annoyed by all the make_nmb_name() stuff. It should be
54 moved down into another function.
56 - Take care when destroying cli_structs as they can be shared between
57 various sam handles.
61 #include "includes.h"
62 #include "winbindd.h"
64 #undef DBGC_CLASS
65 #define DBGC_CLASS DBGC_WINBIND
67 struct dc_name_ip {
68 fstring name;
69 struct sockaddr_storage ss;
72 extern struct winbindd_methods reconnect_methods;
73 extern bool override_logfile;
75 static NTSTATUS init_dc_connection_network(struct winbindd_domain *domain);
76 static void set_dc_type_and_flags( struct winbindd_domain *domain );
77 static bool get_dcs(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
78 struct dc_name_ip **dcs, int *num_dcs);
80 /****************************************************************
81 Child failed to find DC's. Reschedule check.
82 ****************************************************************/
84 static void msg_failed_to_go_online(struct messaging_context *msg,
85 void *private_data,
86 uint32_t msg_type,
87 struct server_id server_id,
88 DATA_BLOB *data)
90 struct winbindd_domain *domain;
91 const char *domainname = (const char *)data->data;
93 if (data->data == NULL || data->length == 0) {
94 return;
97 DEBUG(5,("msg_fail_to_go_online: received for domain %s.\n", domainname));
99 for (domain = domain_list(); domain; domain = domain->next) {
100 if (domain->internal) {
101 continue;
104 if (strequal(domain->name, domainname)) {
105 if (domain->online) {
106 /* We're already online, ignore. */
107 DEBUG(5,("msg_fail_to_go_online: domain %s "
108 "already online.\n", domainname));
109 continue;
112 /* Reschedule the online check. */
113 set_domain_offline(domain);
114 break;
119 /****************************************************************
120 Actually cause a reconnect from a message.
121 ****************************************************************/
123 static void msg_try_to_go_online(struct messaging_context *msg,
124 void *private_data,
125 uint32_t msg_type,
126 struct server_id server_id,
127 DATA_BLOB *data)
129 struct winbindd_domain *domain;
130 const char *domainname = (const char *)data->data;
132 if (data->data == NULL || data->length == 0) {
133 return;
136 DEBUG(5,("msg_try_to_go_online: received for domain %s.\n", domainname));
138 for (domain = domain_list(); domain; domain = domain->next) {
139 if (domain->internal) {
140 continue;
143 if (strequal(domain->name, domainname)) {
145 if (domain->online) {
146 /* We're already online, ignore. */
147 DEBUG(5,("msg_try_to_go_online: domain %s "
148 "already online.\n", domainname));
149 continue;
152 /* This call takes care of setting the online
153 flag to true if we connected, or re-adding
154 the offline handler if false. Bypasses online
155 check so always does network calls. */
157 init_dc_connection_network(domain);
158 break;
163 /****************************************************************
164 Fork a child to try and contact a DC. Do this as contacting a
165 DC requires blocking lookups and we don't want to block our
166 parent.
167 ****************************************************************/
169 static bool fork_child_dc_connect(struct winbindd_domain *domain)
171 struct dc_name_ip *dcs = NULL;
172 int num_dcs = 0;
173 TALLOC_CTX *mem_ctx = NULL;
174 pid_t child_pid;
175 pid_t parent_pid = sys_getpid();
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 if (!reinit_after_fork(winbind_messaging_context(), true)) {
203 DEBUG(0,("reinit_after_fork() failed\n"));
204 _exit(0);
207 close_conns_after_fork();
209 if (!override_logfile) {
210 char *logfile;
211 if (asprintf(&logfile, "%s/log.winbindd-dc-connect", get_dyn_LOGFILEBASE()) > 0) {
212 lp_set_logfile(logfile);
213 SAFE_FREE(logfile);
214 reopen_logs();
218 mem_ctx = talloc_init("fork_child_dc_connect");
219 if (!mem_ctx) {
220 DEBUG(0,("talloc_init failed.\n"));
221 _exit(0);
224 if ((!get_dcs(mem_ctx, domain, &dcs, &num_dcs)) || (num_dcs == 0)) {
225 /* Still offline ? Can't find DC's. */
226 messaging_send_buf(winbind_messaging_context(),
227 pid_to_procid(parent_pid),
228 MSG_WINBIND_FAILED_TO_GO_ONLINE,
229 (uint8 *)domain->name,
230 strlen(domain->name)+1);
231 _exit(0);
234 /* We got a DC. Send a message to our parent to get it to
235 try and do the same. */
237 messaging_send_buf(winbind_messaging_context(),
238 pid_to_procid(parent_pid),
239 MSG_WINBIND_TRY_TO_GO_ONLINE,
240 (uint8 *)domain->name,
241 strlen(domain->name)+1);
242 _exit(0);
245 /****************************************************************
246 Handler triggered if we're offline to try and detect a DC.
247 ****************************************************************/
249 static void check_domain_online_handler(struct event_context *ctx,
250 struct timed_event *te,
251 const struct timeval *now,
252 void *private_data)
254 struct winbindd_domain *domain =
255 (struct winbindd_domain *)private_data;
257 DEBUG(10,("check_domain_online_handler: called for domain "
258 "%s (online = %s)\n", domain->name,
259 domain->online ? "True" : "False" ));
261 TALLOC_FREE(domain->check_online_event);
263 /* Are we still in "startup" mode ? */
265 if (domain->startup && (now->tv_sec > domain->startup_time + 30)) {
266 /* No longer in "startup" mode. */
267 DEBUG(10,("check_domain_online_handler: domain %s no longer in 'startup' mode.\n",
268 domain->name ));
269 domain->startup = False;
272 /* We've been told to stay offline, so stay
273 that way. */
275 if (get_global_winbindd_state_offline()) {
276 DEBUG(10,("check_domain_online_handler: domain %s remaining globally offline\n",
277 domain->name ));
278 return;
281 /* Fork a child to test if it can contact a DC.
282 If it can then send ourselves a message to
283 cause a reconnect. */
285 fork_child_dc_connect(domain);
288 /****************************************************************
289 If we're still offline setup the timeout check.
290 ****************************************************************/
292 static void calc_new_online_timeout_check(struct winbindd_domain *domain)
294 int wbc = lp_winbind_cache_time();
295 int domain_online_check;
298 * If "winbind:online check timeout" is set explicitly,
299 * override the default of "winbind cache timeout"
301 * Add this as a parametric option and don't document it. The
302 * whole offline abuse for non-reachable DCs needs
303 * fixing. Till then, use this hackish parameter.
306 domain_online_check = lp_parm_int(-1, "winbind",
307 "online check timeout", 0);
308 if (domain_online_check != 0) {
309 wbc = domain_online_check;
312 if (domain->startup) {
313 domain->check_online_timeout = 10;
314 } else if (domain->check_online_timeout < wbc) {
315 domain->check_online_timeout = wbc;
319 /****************************************************************
320 Set domain offline and also add handler to put us back online
321 if we detect a DC.
322 ****************************************************************/
324 void set_domain_offline(struct winbindd_domain *domain)
326 DEBUG(10,("set_domain_offline: called for domain %s\n",
327 domain->name ));
329 TALLOC_FREE(domain->check_online_event);
331 if (domain->internal) {
332 DEBUG(3,("set_domain_offline: domain %s is internal - logic error.\n",
333 domain->name ));
334 return;
337 domain->online = False;
339 /* Offline domains are always initialized. They're
340 re-initialized when they go back online. */
342 domain->initialized = True;
344 /* We only add the timeout handler that checks and
345 allows us to go back online when we've not
346 been told to remain offline. */
348 if (get_global_winbindd_state_offline()) {
349 DEBUG(10,("set_domain_offline: domain %s remaining globally offline\n",
350 domain->name ));
351 return;
354 /* If we're in statup mode, check again in 10 seconds, not in
355 lp_winbind_cache_time() seconds (which is 5 mins by default). */
357 calc_new_online_timeout_check(domain);
359 domain->check_online_event = event_add_timed(winbind_event_context(),
360 NULL,
361 timeval_current_ofs(domain->check_online_timeout,0),
362 "check_domain_online_handler",
363 check_domain_online_handler,
364 domain);
366 /* The above *has* to succeed for winbindd to work. */
367 if (!domain->check_online_event) {
368 smb_panic("set_domain_offline: failed to add online handler");
371 DEBUG(10,("set_domain_offline: added event handler for domain %s\n",
372 domain->name ));
374 /* Send an offline message to the idmap child when our
375 primary domain goes offline */
377 if ( domain->primary ) {
378 struct winbindd_child *idmap = idmap_child();
380 if ( idmap->pid != 0 ) {
381 messaging_send_buf(winbind_messaging_context(),
382 pid_to_procid(idmap->pid),
383 MSG_WINBIND_OFFLINE,
384 (uint8 *)domain->name,
385 strlen(domain->name)+1);
389 return;
392 /****************************************************************
393 Set domain online - if allowed.
394 ****************************************************************/
396 static void set_domain_online(struct winbindd_domain *domain)
398 struct timeval now;
400 DEBUG(10,("set_domain_online: called for domain %s\n",
401 domain->name ));
403 if (domain->internal) {
404 DEBUG(3,("set_domain_online: domain %s is internal - logic error.\n",
405 domain->name ));
406 return;
409 if (get_global_winbindd_state_offline()) {
410 DEBUG(10,("set_domain_online: domain %s remaining globally offline\n",
411 domain->name ));
412 return;
415 winbindd_set_locator_kdc_envs(domain);
417 /* If we are waiting to get a krb5 ticket, trigger immediately. */
418 GetTimeOfDay(&now);
419 set_event_dispatch_time(winbind_event_context(),
420 "krb5_ticket_gain_handler", 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... */
493 if (!domain->check_online_event) {
494 /* If we've come from being globally offline we
495 don't have a check online event handler set.
496 We need to add one now we're trying to go
497 back online. */
499 DEBUG(10,("set_domain_online_request: domain %s was globally offline.\n",
500 domain->name ));
502 domain->check_online_event = event_add_timed(winbind_event_context(),
503 NULL,
504 timeval_current_ofs(5, 0),
505 "check_domain_online_handler",
506 check_domain_online_handler,
507 domain);
509 /* The above *has* to succeed for winbindd to work. */
510 if (!domain->check_online_event) {
511 smb_panic("set_domain_online_request: failed to add online handler");
515 GetTimeOfDay(&tev);
517 /* Go into "startup" mode again. */
518 domain->startup_time = tev.tv_sec;
519 domain->startup = True;
521 tev.tv_sec += 5;
523 set_event_dispatch_time(winbind_event_context(), "check_domain_online_handler", tev);
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 (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 dos_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 = (struct sockaddr_in *)&peeraddr;
774 DEBUG(10,("cm_prepare_connection: connecting to DC %s for domain %s\n",
775 controller, domain->name ));
777 *retry = True;
779 mutex = grab_named_mutex(talloc_tos(), controller,
780 WINBIND_SERVER_MUTEX_WAIT_TIME);
781 if (mutex == NULL) {
782 DEBUG(0,("cm_prepare_connection: mutex grab failed for %s\n",
783 controller));
784 result = NT_STATUS_POSSIBLE_DEADLOCK;
785 goto done;
788 if ((*cli = cli_initialise()) == NULL) {
789 DEBUG(1, ("Could not cli_initialize\n"));
790 result = NT_STATUS_NO_MEMORY;
791 goto done;
794 (*cli)->timeout = 10000; /* 10 seconds */
795 (*cli)->fd = sockfd;
796 fstrcpy((*cli)->desthost, controller);
797 (*cli)->use_kerberos = True;
799 peeraddr_len = sizeof(peeraddr);
801 if ((getpeername((*cli)->fd, &peeraddr, &peeraddr_len) != 0) ||
802 (peeraddr_len != sizeof(struct sockaddr_in)) ||
803 (peeraddr_in->sin_family != PF_INET))
805 DEBUG(0,("cm_prepare_connection: %s\n", strerror(errno)));
806 result = NT_STATUS_UNSUCCESSFUL;
807 goto done;
810 if (ntohs(peeraddr_in->sin_port) == 139) {
811 struct nmb_name calling;
812 struct nmb_name called;
814 make_nmb_name(&calling, global_myname(), 0x0);
815 make_nmb_name(&called, "*SMBSERVER", 0x20);
817 if (!cli_session_request(*cli, &calling, &called)) {
818 DEBUG(8, ("cli_session_request failed for %s\n",
819 controller));
820 result = NT_STATUS_UNSUCCESSFUL;
821 goto done;
825 cli_setup_signing_state(*cli, Undefined);
827 if (!cli_negprot(*cli)) {
828 DEBUG(1, ("cli_negprot failed\n"));
829 result = NT_STATUS_UNSUCCESSFUL;
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 cli_init_creds(*cli, machine_account, domain->name, machine_password);
872 goto session_setup_done;
876 /* Fall back to non-kerberos session setup using NTLMSSP SPNEGO with the machine account. */
877 (*cli)->use_kerberos = False;
879 DEBUG(5, ("connecting to %s from %s with username "
880 "[%s]\\[%s]\n", controller, global_myname(),
881 lp_workgroup(), machine_account));
883 ads_status = cli_session_setup_spnego(*cli,
884 machine_account,
885 machine_password,
886 lp_workgroup(),
887 NULL);
888 if (!ADS_ERR_OK(ads_status)) {
889 DEBUG(4, ("authenticated session setup failed with %s\n",
890 ads_errstr(ads_status)));
893 result = ads_ntstatus(ads_status);
894 if (NT_STATUS_IS_OK(result)) {
895 /* Ensure creds are stored for NTLMSSP authenticated pipe access. */
896 cli_init_creds(*cli, machine_account, domain->name, machine_password);
897 goto session_setup_done;
901 /* Fall back to non-kerberos session setup with auth_user */
903 (*cli)->use_kerberos = False;
905 cm_get_ipc_userpass(&ipc_username, &ipc_domain, &ipc_password);
907 if ((((*cli)->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) != 0) &&
908 (strlen(ipc_username) > 0)) {
910 /* Only try authenticated if we have a username */
912 DEBUG(5, ("connecting to %s from %s with username "
913 "[%s]\\[%s]\n", controller, global_myname(),
914 ipc_domain, ipc_username));
916 if (NT_STATUS_IS_OK(cli_session_setup(
917 *cli, ipc_username,
918 ipc_password, strlen(ipc_password)+1,
919 ipc_password, strlen(ipc_password)+1,
920 ipc_domain))) {
921 /* Successful logon with given username. */
922 cli_init_creds(*cli, ipc_username, ipc_domain, ipc_password);
923 goto session_setup_done;
924 } else {
925 DEBUG(4, ("authenticated session setup with user %s\\%s failed.\n",
926 ipc_domain, ipc_username ));
930 anon_fallback:
932 /* Fall back to anonymous connection, this might fail later */
934 if (NT_STATUS_IS_OK(cli_session_setup(*cli, "", NULL, 0,
935 NULL, 0, ""))) {
936 DEBUG(5, ("Connected anonymously\n"));
937 cli_init_creds(*cli, "", "", "");
938 goto session_setup_done;
941 result = cli_nt_error(*cli);
943 if (NT_STATUS_IS_OK(result))
944 result = NT_STATUS_UNSUCCESSFUL;
946 /* We can't session setup */
948 goto done;
950 session_setup_done:
952 /* cache the server name for later connections */
954 saf_store( domain->name, (*cli)->desthost );
955 if (domain->alt_name && (*cli)->use_kerberos) {
956 saf_store( domain->alt_name, (*cli)->desthost );
959 winbindd_set_locator_kdc_envs(domain);
961 if (!cli_send_tconX(*cli, "IPC$", "IPC", "", 0)) {
963 result = cli_nt_error(*cli);
965 DEBUG(1,("failed tcon_X with %s\n", nt_errstr(result)));
967 if (NT_STATUS_IS_OK(result))
968 result = NT_STATUS_UNSUCCESSFUL;
970 goto done;
973 TALLOC_FREE(mutex);
974 *retry = False;
976 /* set the domain if empty; needed for schannel connections */
977 if ( !*(*cli)->domain ) {
978 fstrcpy( (*cli)->domain, domain->name );
981 result = NT_STATUS_OK;
983 done:
984 TALLOC_FREE(mutex);
985 SAFE_FREE(machine_account);
986 SAFE_FREE(machine_password);
987 SAFE_FREE(machine_krb5_principal);
988 SAFE_FREE(ipc_username);
989 SAFE_FREE(ipc_domain);
990 SAFE_FREE(ipc_password);
992 if (!NT_STATUS_IS_OK(result)) {
993 winbind_add_failed_connection_entry(domain, controller, result);
994 if ((*cli) != NULL) {
995 cli_shutdown(*cli);
996 *cli = NULL;
1000 return result;
1003 static bool add_one_dc_unique(TALLOC_CTX *mem_ctx, const char *domain_name,
1004 const char *dcname, struct sockaddr_storage *pss,
1005 struct dc_name_ip **dcs, int *num)
1007 if (!NT_STATUS_IS_OK(check_negative_conn_cache(domain_name, dcname))) {
1008 DEBUG(10, ("DC %s was in the negative conn cache\n", dcname));
1009 return False;
1012 *dcs = TALLOC_REALLOC_ARRAY(mem_ctx, *dcs, struct dc_name_ip, (*num)+1);
1014 if (*dcs == NULL)
1015 return False;
1017 fstrcpy((*dcs)[*num].name, dcname);
1018 (*dcs)[*num].ss = *pss;
1019 *num += 1;
1020 return True;
1023 static bool add_sockaddr_to_array(TALLOC_CTX *mem_ctx,
1024 struct sockaddr_storage *pss, uint16 port,
1025 struct sockaddr_storage **addrs, int *num)
1027 *addrs = TALLOC_REALLOC_ARRAY(mem_ctx, *addrs, struct sockaddr_storage, (*num)+1);
1029 if (*addrs == NULL) {
1030 *num = 0;
1031 return False;
1034 (*addrs)[*num] = *pss;
1035 set_sockaddr_port(&(*addrs)[*num], port);
1037 *num += 1;
1038 return True;
1041 /*******************************************************************
1042 convert an ip to a name
1043 *******************************************************************/
1045 static bool dcip_to_name(TALLOC_CTX *mem_ctx,
1046 const struct winbindd_domain *domain,
1047 struct sockaddr_storage *pss,
1048 fstring name )
1050 struct ip_service ip_list;
1051 uint32_t nt_version = NETLOGON_VERSION_1;
1053 ip_list.ss = *pss;
1054 ip_list.port = 0;
1056 #ifdef WITH_ADS
1057 /* For active directory servers, try to get the ldap server name.
1058 None of these failures should be considered critical for now */
1060 if (lp_security() == SEC_ADS) {
1061 ADS_STRUCT *ads;
1062 ADS_STATUS ads_status;
1063 char addr[INET6_ADDRSTRLEN];
1065 print_sockaddr(addr, sizeof(addr), pss);
1067 ads = ads_init(domain->alt_name, domain->name, addr);
1068 ads->auth.flags |= ADS_AUTH_NO_BIND;
1070 ads_status = ads_connect(ads);
1071 if (ADS_ERR_OK(ads_status)) {
1072 /* We got a cldap packet. */
1073 fstrcpy(name, ads->config.ldap_server_name);
1074 namecache_store(name, 0x20, 1, &ip_list);
1076 DEBUG(10,("dcip_to_name: flags = 0x%x\n", (unsigned int)ads->config.flags));
1078 if (domain->primary && (ads->config.flags & NBT_SERVER_KDC)) {
1079 if (ads_closest_dc(ads)) {
1080 char *sitename = sitename_fetch(ads->config.realm);
1082 /* We're going to use this KDC for this realm/domain.
1083 If we are using sites, then force the krb5 libs
1084 to use this KDC. */
1086 create_local_private_krb5_conf_for_domain(domain->alt_name,
1087 domain->name,
1088 sitename,
1089 pss);
1091 SAFE_FREE(sitename);
1092 } else {
1093 /* use an off site KDC */
1094 create_local_private_krb5_conf_for_domain(domain->alt_name,
1095 domain->name,
1096 NULL,
1097 pss);
1099 winbindd_set_locator_kdc_envs(domain);
1101 /* Ensure we contact this DC also. */
1102 saf_store( domain->name, name);
1103 saf_store( domain->alt_name, name);
1106 ads_destroy( &ads );
1107 return True;
1110 ads_destroy( &ads );
1112 #endif
1114 /* try GETDC requests next */
1116 if (send_getdc_request(mem_ctx, winbind_messaging_context(),
1117 pss, domain->name, &domain->sid,
1118 nt_version)) {
1119 const char *dc_name = NULL;
1120 int i;
1121 smb_msleep(100);
1122 for (i=0; i<5; i++) {
1123 if (receive_getdc_response(mem_ctx, pss, domain->name,
1124 &nt_version,
1125 &dc_name, NULL)) {
1126 fstrcpy(name, dc_name);
1127 namecache_store(name, 0x20, 1, &ip_list);
1128 return True;
1130 smb_msleep(500);
1134 /* try node status request */
1136 if ( name_status_find(domain->name, 0x1c, 0x20, pss, name) ) {
1137 namecache_store(name, 0x20, 1, &ip_list);
1138 return True;
1140 return False;
1143 /*******************************************************************
1144 Retreive a list of IP address for domain controllers. Fill in
1145 the dcs[] with results.
1146 *******************************************************************/
1148 static bool get_dcs(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
1149 struct dc_name_ip **dcs, int *num_dcs)
1151 fstring dcname;
1152 struct sockaddr_storage ss;
1153 struct ip_service *ip_list = NULL;
1154 int iplist_size = 0;
1155 int i;
1156 bool is_our_domain;
1157 enum security_types sec = (enum security_types)lp_security();
1159 is_our_domain = strequal(domain->name, lp_workgroup());
1161 if ( !is_our_domain
1162 && get_dc_name_via_netlogon(domain, dcname, &ss)
1163 && add_one_dc_unique(mem_ctx, domain->name, dcname, &ss, dcs, num_dcs) )
1165 char addr[INET6_ADDRSTRLEN];
1166 print_sockaddr(addr, sizeof(addr), &ss);
1167 DEBUG(10, ("Retrieved DC %s at %s via netlogon\n",
1168 dcname, addr));
1169 return True;
1172 if (sec == SEC_ADS) {
1173 char *sitename = NULL;
1175 /* We need to make sure we know the local site before
1176 doing any DNS queries, as this will restrict the
1177 get_sorted_dc_list() call below to only fetching
1178 DNS records for the correct site. */
1180 /* Find any DC to get the site record.
1181 We deliberately don't care about the
1182 return here. */
1184 get_dc_name(domain->name, domain->alt_name, dcname, &ss);
1186 sitename = sitename_fetch(domain->alt_name);
1187 if (sitename) {
1189 /* Do the site-specific AD dns lookup first. */
1190 get_sorted_dc_list(domain->alt_name, sitename, &ip_list, &iplist_size, True);
1192 for ( i=0; i<iplist_size; i++ ) {
1193 char addr[INET6_ADDRSTRLEN];
1194 print_sockaddr(addr, sizeof(addr),
1195 &ip_list[i].ss);
1196 add_one_dc_unique(mem_ctx,
1197 domain->name,
1198 addr,
1199 &ip_list[i].ss,
1200 dcs,
1201 num_dcs);
1204 SAFE_FREE(ip_list);
1205 SAFE_FREE(sitename);
1206 iplist_size = 0;
1209 /* Now we add DCs from the main AD dns lookup. */
1210 get_sorted_dc_list(domain->alt_name, NULL, &ip_list, &iplist_size, True);
1212 for ( i=0; i<iplist_size; i++ ) {
1213 char addr[INET6_ADDRSTRLEN];
1214 print_sockaddr(addr, sizeof(addr),
1215 &ip_list[i].ss);
1216 add_one_dc_unique(mem_ctx,
1217 domain->name,
1218 addr,
1219 &ip_list[i].ss,
1220 dcs,
1221 num_dcs);
1225 /* try standard netbios queries if no ADS */
1227 if (iplist_size==0) {
1228 get_sorted_dc_list(domain->name, NULL, &ip_list, &iplist_size, False);
1231 /* FIXME!! this is where we should re-insert the GETDC requests --jerry */
1233 /* now add to the dc array. We'll wait until the last minute
1234 to look up the name of the DC. But we fill in the char* for
1235 the ip now in to make the failed connection cache work */
1237 for ( i=0; i<iplist_size; i++ ) {
1238 char addr[INET6_ADDRSTRLEN];
1239 print_sockaddr(addr, sizeof(addr),
1240 &ip_list[i].ss);
1241 add_one_dc_unique(mem_ctx, domain->name, addr,
1242 &ip_list[i].ss, dcs, num_dcs);
1245 SAFE_FREE( ip_list );
1247 return True;
1250 static bool find_new_dc(TALLOC_CTX *mem_ctx,
1251 struct winbindd_domain *domain,
1252 fstring dcname, struct sockaddr_storage *pss, int *fd)
1254 struct dc_name_ip *dcs = NULL;
1255 int num_dcs = 0;
1257 const char **dcnames = NULL;
1258 int num_dcnames = 0;
1260 struct sockaddr_storage *addrs = NULL;
1261 int num_addrs = 0;
1263 int i, fd_index;
1265 *fd = -1;
1267 again:
1268 if (!get_dcs(mem_ctx, domain, &dcs, &num_dcs) || (num_dcs == 0))
1269 return False;
1271 for (i=0; i<num_dcs; i++) {
1273 if (!add_string_to_array(mem_ctx, dcs[i].name,
1274 &dcnames, &num_dcnames)) {
1275 return False;
1277 if (!add_sockaddr_to_array(mem_ctx, &dcs[i].ss, 445,
1278 &addrs, &num_addrs)) {
1279 return False;
1282 if (!add_string_to_array(mem_ctx, dcs[i].name,
1283 &dcnames, &num_dcnames)) {
1284 return False;
1286 if (!add_sockaddr_to_array(mem_ctx, &dcs[i].ss, 139,
1287 &addrs, &num_addrs)) {
1288 return False;
1292 if ((num_dcnames == 0) || (num_dcnames != num_addrs))
1293 return False;
1295 if ((addrs == NULL) || (dcnames == NULL))
1296 return False;
1298 /* 5 second timeout. */
1299 if (!open_any_socket_out(addrs, num_addrs, 5000, &fd_index, fd) ) {
1300 for (i=0; i<num_dcs; i++) {
1301 char ab[INET6_ADDRSTRLEN];
1302 print_sockaddr(ab, sizeof(ab), &dcs[i].ss);
1303 DEBUG(10, ("find_new_dc: open_any_socket_out failed for "
1304 "domain %s address %s. Error was %s\n",
1305 domain->name, ab, strerror(errno) ));
1306 winbind_add_failed_connection_entry(domain,
1307 dcs[i].name, NT_STATUS_UNSUCCESSFUL);
1309 return False;
1312 *pss = addrs[fd_index];
1314 if (*dcnames[fd_index] != '\0' && !is_ipaddress(dcnames[fd_index])) {
1315 /* Ok, we've got a name for the DC */
1316 fstrcpy(dcname, dcnames[fd_index]);
1317 return True;
1320 /* Try to figure out the name */
1321 if (dcip_to_name(mem_ctx, domain, pss, dcname)) {
1322 return True;
1325 /* We can not continue without the DC's name */
1326 winbind_add_failed_connection_entry(domain, dcs[fd_index].name,
1327 NT_STATUS_UNSUCCESSFUL);
1329 /* Throw away all arrays as we're doing this again. */
1330 TALLOC_FREE(dcs);
1331 num_dcs = 0;
1333 TALLOC_FREE(dcnames);
1334 num_dcnames = 0;
1336 TALLOC_FREE(addrs);
1337 num_addrs = 0;
1339 close(*fd);
1340 *fd = -1;
1342 goto again;
1345 static NTSTATUS cm_open_connection(struct winbindd_domain *domain,
1346 struct winbindd_cm_conn *new_conn)
1348 TALLOC_CTX *mem_ctx;
1349 NTSTATUS result;
1350 char *saf_servername = saf_fetch( domain->name );
1351 int retries;
1353 if ((mem_ctx = talloc_init("cm_open_connection")) == NULL) {
1354 SAFE_FREE(saf_servername);
1355 set_domain_offline(domain);
1356 return NT_STATUS_NO_MEMORY;
1359 /* we have to check the server affinity cache here since
1360 later we selecte a DC based on response time and not preference */
1362 /* Check the negative connection cache
1363 before talking to it. It going down may have
1364 triggered the reconnection. */
1366 if ( saf_servername && NT_STATUS_IS_OK(check_negative_conn_cache( domain->name, saf_servername))) {
1368 DEBUG(10,("cm_open_connection: saf_servername is '%s' for domain %s\n",
1369 saf_servername, domain->name ));
1371 /* convert an ip address to a name */
1372 if (is_ipaddress( saf_servername ) ) {
1373 fstring saf_name;
1374 struct sockaddr_storage ss;
1376 if (!interpret_string_addr(&ss, saf_servername,
1377 AI_NUMERICHOST)) {
1378 return NT_STATUS_UNSUCCESSFUL;
1380 if (dcip_to_name(mem_ctx, domain, &ss, saf_name )) {
1381 fstrcpy( domain->dcname, saf_name );
1382 } else {
1383 winbind_add_failed_connection_entry(
1384 domain, saf_servername,
1385 NT_STATUS_UNSUCCESSFUL);
1387 } else {
1388 fstrcpy( domain->dcname, saf_servername );
1391 SAFE_FREE( saf_servername );
1394 for (retries = 0; retries < 3; retries++) {
1395 int fd = -1;
1396 bool retry = False;
1398 result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
1400 DEBUG(10,("cm_open_connection: dcname is '%s' for domain %s\n",
1401 domain->dcname, domain->name ));
1403 if (*domain->dcname
1404 && NT_STATUS_IS_OK(check_negative_conn_cache( domain->name, domain->dcname))
1405 && (resolve_name(domain->dcname, &domain->dcaddr, 0x20)))
1407 struct sockaddr_storage *addrs = NULL;
1408 int num_addrs = 0;
1409 int dummy = 0;
1411 if (!add_sockaddr_to_array(mem_ctx, &domain->dcaddr, 445, &addrs, &num_addrs)) {
1412 set_domain_offline(domain);
1413 talloc_destroy(mem_ctx);
1414 return NT_STATUS_NO_MEMORY;
1416 if (!add_sockaddr_to_array(mem_ctx, &domain->dcaddr, 139, &addrs, &num_addrs)) {
1417 set_domain_offline(domain);
1418 talloc_destroy(mem_ctx);
1419 return NT_STATUS_NO_MEMORY;
1422 /* 5 second timeout. */
1423 if (!open_any_socket_out(addrs, num_addrs, 5000, &dummy, &fd)) {
1424 fd = -1;
1428 if ((fd == -1)
1429 && !find_new_dc(mem_ctx, domain, domain->dcname, &domain->dcaddr, &fd))
1431 /* This is the one place where we will
1432 set the global winbindd offline state
1433 to true, if a "WINBINDD_OFFLINE" entry
1434 is found in the winbindd cache. */
1435 set_global_winbindd_state_offline();
1436 break;
1439 new_conn->cli = NULL;
1441 result = cm_prepare_connection(domain, fd, domain->dcname,
1442 &new_conn->cli, &retry);
1444 if (!retry)
1445 break;
1448 if (NT_STATUS_IS_OK(result)) {
1450 winbindd_set_locator_kdc_envs(domain);
1452 if (domain->online == False) {
1453 /* We're changing state from offline to online. */
1454 set_global_winbindd_state_online();
1456 set_domain_online(domain);
1457 } else {
1458 /* Ensure we setup the retry handler. */
1459 set_domain_offline(domain);
1462 talloc_destroy(mem_ctx);
1463 return result;
1466 /* Close down all open pipes on a connection. */
1468 void invalidate_cm_connection(struct winbindd_cm_conn *conn)
1470 /* We're closing down a possibly dead
1471 connection. Don't have impossibly long (10s) timeouts. */
1473 if (conn->cli) {
1474 cli_set_timeout(conn->cli, 1000); /* 1 second. */
1477 if (conn->samr_pipe != NULL) {
1478 TALLOC_FREE(conn->samr_pipe);
1479 /* Ok, it must be dead. Drop timeout to 0.5 sec. */
1480 if (conn->cli) {
1481 cli_set_timeout(conn->cli, 500);
1485 if (conn->lsa_pipe != NULL) {
1486 TALLOC_FREE(conn->lsa_pipe);
1487 /* Ok, it must be dead. Drop timeout to 0.5 sec. */
1488 if (conn->cli) {
1489 cli_set_timeout(conn->cli, 500);
1493 if (conn->netlogon_pipe != NULL) {
1494 TALLOC_FREE(conn->netlogon_pipe);
1495 /* Ok, it must be dead. Drop timeout to 0.5 sec. */
1496 if (conn->cli) {
1497 cli_set_timeout(conn->cli, 500);
1501 if (conn->cli) {
1502 cli_shutdown(conn->cli);
1505 conn->cli = NULL;
1508 void close_conns_after_fork(void)
1510 struct winbindd_domain *domain;
1512 for (domain = domain_list(); domain; domain = domain->next) {
1513 if (domain->conn.cli == NULL)
1514 continue;
1516 if (domain->conn.cli->fd == -1)
1517 continue;
1519 close(domain->conn.cli->fd);
1520 domain->conn.cli->fd = -1;
1524 static bool connection_ok(struct winbindd_domain *domain)
1526 if (domain->conn.cli == NULL) {
1527 DEBUG(8, ("connection_ok: Connection to %s for domain %s has NULL "
1528 "cli!\n", domain->dcname, domain->name));
1529 return False;
1532 if (!domain->conn.cli->initialised) {
1533 DEBUG(3, ("connection_ok: Connection to %s for domain %s was never "
1534 "initialised!\n", domain->dcname, domain->name));
1535 return False;
1538 if (domain->conn.cli->fd == -1) {
1539 DEBUG(3, ("connection_ok: Connection to %s for domain %s has died or was "
1540 "never started (fd == -1)\n",
1541 domain->dcname, domain->name));
1542 return False;
1545 if (domain->online == False) {
1546 DEBUG(3, ("connection_ok: Domain %s is offline\n", domain->name));
1547 return False;
1550 return True;
1553 /* Initialize a new connection up to the RPC BIND.
1554 Bypass online status check so always does network calls. */
1556 static NTSTATUS init_dc_connection_network(struct winbindd_domain *domain)
1558 NTSTATUS result;
1560 /* Internal connections never use the network. */
1561 if (domain->internal) {
1562 domain->initialized = True;
1563 return NT_STATUS_OK;
1566 if (connection_ok(domain)) {
1567 if (!domain->initialized) {
1568 set_dc_type_and_flags(domain);
1570 return NT_STATUS_OK;
1573 invalidate_cm_connection(&domain->conn);
1575 result = cm_open_connection(domain, &domain->conn);
1577 if (NT_STATUS_IS_OK(result) && !domain->initialized) {
1578 set_dc_type_and_flags(domain);
1581 return result;
1584 NTSTATUS init_dc_connection(struct winbindd_domain *domain)
1586 if (domain->initialized && !domain->online) {
1587 /* We check for online status elsewhere. */
1588 return NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
1591 return init_dc_connection_network(domain);
1594 /******************************************************************************
1595 Set the trust flags (direction and forest location) for a domain
1596 ******************************************************************************/
1598 static bool set_dc_type_and_flags_trustinfo( struct winbindd_domain *domain )
1600 struct winbindd_domain *our_domain;
1601 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1602 struct netr_DomainTrustList trusts;
1603 int i;
1604 uint32 flags = (NETR_TRUST_FLAG_IN_FOREST |
1605 NETR_TRUST_FLAG_OUTBOUND |
1606 NETR_TRUST_FLAG_INBOUND);
1607 struct rpc_pipe_client *cli;
1608 TALLOC_CTX *mem_ctx = NULL;
1610 DEBUG(5, ("set_dc_type_and_flags_trustinfo: domain %s\n", domain->name ));
1612 /* Our primary domain doesn't need to worry about trust flags.
1613 Force it to go through the network setup */
1614 if ( domain->primary ) {
1615 return False;
1618 our_domain = find_our_domain();
1620 if ( !connection_ok(our_domain) ) {
1621 DEBUG(3,("set_dc_type_and_flags_trustinfo: No connection to our domain!\n"));
1622 return False;
1625 /* This won't work unless our domain is AD */
1627 if ( !our_domain->active_directory ) {
1628 return False;
1631 /* Use DsEnumerateDomainTrusts to get us the trust direction
1632 and type */
1634 result = cm_connect_netlogon(our_domain, &cli);
1636 if (!NT_STATUS_IS_OK(result)) {
1637 DEBUG(5, ("set_dc_type_and_flags_trustinfo: Could not open "
1638 "a connection to %s for PIPE_NETLOGON (%s)\n",
1639 domain->name, nt_errstr(result)));
1640 return False;
1643 if ( (mem_ctx = talloc_init("set_dc_type_and_flags_trustinfo")) == NULL ) {
1644 DEBUG(0,("set_dc_type_and_flags_trustinfo: talloc_init() failed!\n"));
1645 return False;
1648 result = rpccli_netr_DsrEnumerateDomainTrusts(cli, mem_ctx,
1649 cli->desthost,
1650 flags,
1651 &trusts,
1652 NULL);
1653 if (!NT_STATUS_IS_OK(result)) {
1654 DEBUG(0,("set_dc_type_and_flags_trustinfo: "
1655 "failed to query trusted domain list: %s\n",
1656 nt_errstr(result)));
1657 talloc_destroy(mem_ctx);
1658 return false;
1661 /* Now find the domain name and get the flags */
1663 for ( i=0; i<trusts.count; i++ ) {
1664 if ( strequal( domain->name, trusts.array[i].netbios_name) ) {
1665 domain->domain_flags = trusts.array[i].trust_flags;
1666 domain->domain_type = trusts.array[i].trust_type;
1667 domain->domain_trust_attribs = trusts.array[i].trust_attributes;
1669 if ( domain->domain_type == NETR_TRUST_TYPE_UPLEVEL )
1670 domain->active_directory = True;
1672 /* This flag is only set if the domain is *our*
1673 primary domain and the primary domain is in
1674 native mode */
1676 domain->native_mode = (domain->domain_flags & NETR_TRUST_FLAG_NATIVE);
1678 DEBUG(5, ("set_dc_type_and_flags_trustinfo: domain %s is %sin "
1679 "native mode.\n", domain->name,
1680 domain->native_mode ? "" : "NOT "));
1682 DEBUG(5,("set_dc_type_and_flags_trustinfo: domain %s is %s"
1683 "running active directory.\n", domain->name,
1684 domain->active_directory ? "" : "NOT "));
1687 domain->initialized = True;
1689 if ( !winbindd_can_contact_domain( domain) )
1690 domain->internal = True;
1692 break;
1696 talloc_destroy( mem_ctx );
1698 return domain->initialized;
1701 /******************************************************************************
1702 We can 'sense' certain things about the DC by it's replies to certain
1703 questions.
1705 This tells us if this particular remote server is Active Directory, and if it
1706 is native mode.
1707 ******************************************************************************/
1709 static void set_dc_type_and_flags_connect( struct winbindd_domain *domain )
1711 NTSTATUS result;
1712 WERROR werr;
1713 TALLOC_CTX *mem_ctx = NULL;
1714 struct rpc_pipe_client *cli;
1715 POLICY_HND pol;
1716 union dssetup_DsRoleInfo info;
1717 union lsa_PolicyInformation *lsa_info = NULL;
1719 if (!connection_ok(domain)) {
1720 return;
1723 mem_ctx = talloc_init("set_dc_type_and_flags on domain %s\n",
1724 domain->name);
1725 if (!mem_ctx) {
1726 DEBUG(1, ("set_dc_type_and_flags_connect: talloc_init() failed\n"));
1727 return;
1730 DEBUG(5, ("set_dc_type_and_flags_connect: domain %s\n", domain->name ));
1732 result = cli_rpc_pipe_open_noauth(domain->conn.cli,
1733 &ndr_table_dssetup.syntax_id,
1734 &cli);
1736 if (!NT_STATUS_IS_OK(result)) {
1737 DEBUG(5, ("set_dc_type_and_flags_connect: Could not bind to "
1738 "PI_DSSETUP on domain %s: (%s)\n",
1739 domain->name, nt_errstr(result)));
1741 /* if this is just a non-AD domain we need to continue
1742 * identifying so that we can in the end return with
1743 * domain->initialized = True - gd */
1745 goto no_dssetup;
1748 result = rpccli_dssetup_DsRoleGetPrimaryDomainInformation(cli, mem_ctx,
1749 DS_ROLE_BASIC_INFORMATION,
1750 &info,
1751 &werr);
1752 TALLOC_FREE(cli);
1754 if (!NT_STATUS_IS_OK(result)) {
1755 DEBUG(5, ("set_dc_type_and_flags_connect: rpccli_ds_getprimarydominfo "
1756 "on domain %s failed: (%s)\n",
1757 domain->name, nt_errstr(result)));
1759 /* older samba3 DCs will return DCERPC_FAULT_OP_RNG_ERROR for
1760 * every opcode on the DSSETUP pipe, continue with
1761 * no_dssetup mode here as well to get domain->initialized
1762 * set - gd */
1764 if (NT_STATUS_V(result) == DCERPC_FAULT_OP_RNG_ERROR) {
1765 goto no_dssetup;
1768 TALLOC_FREE(mem_ctx);
1769 return;
1772 if ((info.basic.flags & DS_ROLE_PRIMARY_DS_RUNNING) &&
1773 !(info.basic.flags & DS_ROLE_PRIMARY_DS_MIXED_MODE)) {
1774 domain->native_mode = True;
1775 } else {
1776 domain->native_mode = False;
1779 no_dssetup:
1780 result = cli_rpc_pipe_open_noauth(domain->conn.cli,
1781 &ndr_table_lsarpc.syntax_id, &cli);
1783 if (!NT_STATUS_IS_OK(result)) {
1784 DEBUG(5, ("set_dc_type_and_flags_connect: Could not bind to "
1785 "PI_LSARPC on domain %s: (%s)\n",
1786 domain->name, nt_errstr(result)));
1787 TALLOC_FREE(cli);
1788 TALLOC_FREE(mem_ctx);
1789 return;
1792 result = rpccli_lsa_open_policy2(cli, mem_ctx, True,
1793 SEC_RIGHTS_MAXIMUM_ALLOWED, &pol);
1795 if (NT_STATUS_IS_OK(result)) {
1796 /* This particular query is exactly what Win2k clients use
1797 to determine that the DC is active directory */
1798 result = rpccli_lsa_QueryInfoPolicy2(cli, mem_ctx,
1799 &pol,
1800 LSA_POLICY_INFO_DNS,
1801 &lsa_info);
1804 if (NT_STATUS_IS_OK(result)) {
1805 domain->active_directory = True;
1807 if (lsa_info->dns.name.string) {
1808 fstrcpy(domain->name, lsa_info->dns.name.string);
1811 if (lsa_info->dns.dns_domain.string) {
1812 fstrcpy(domain->alt_name,
1813 lsa_info->dns.dns_domain.string);
1816 /* See if we can set some domain trust flags about
1817 ourself */
1819 if (lsa_info->dns.dns_forest.string) {
1820 fstrcpy(domain->forest_name,
1821 lsa_info->dns.dns_forest.string);
1823 if (strequal(domain->forest_name, domain->alt_name)) {
1824 domain->domain_flags |= NETR_TRUST_FLAG_TREEROOT;
1828 if (lsa_info->dns.sid) {
1829 sid_copy(&domain->sid, lsa_info->dns.sid);
1831 } else {
1832 domain->active_directory = False;
1834 result = rpccli_lsa_open_policy(cli, mem_ctx, True,
1835 SEC_RIGHTS_MAXIMUM_ALLOWED,
1836 &pol);
1838 if (!NT_STATUS_IS_OK(result)) {
1839 goto done;
1842 result = rpccli_lsa_QueryInfoPolicy(cli, mem_ctx,
1843 &pol,
1844 LSA_POLICY_INFO_ACCOUNT_DOMAIN,
1845 &lsa_info);
1847 if (NT_STATUS_IS_OK(result)) {
1849 if (lsa_info->account_domain.name.string) {
1850 fstrcpy(domain->name,
1851 lsa_info->account_domain.name.string);
1854 if (lsa_info->account_domain.sid) {
1855 sid_copy(&domain->sid, lsa_info->account_domain.sid);
1859 done:
1861 DEBUG(5, ("set_dc_type_and_flags_connect: domain %s is %sin native mode.\n",
1862 domain->name, domain->native_mode ? "" : "NOT "));
1864 DEBUG(5,("set_dc_type_and_flags_connect: domain %s is %srunning active directory.\n",
1865 domain->name, domain->active_directory ? "" : "NOT "));
1867 TALLOC_FREE(cli);
1869 TALLOC_FREE(mem_ctx);
1871 domain->initialized = True;
1874 /**********************************************************************
1875 Set the domain_flags (trust attributes, domain operating modes, etc...
1876 ***********************************************************************/
1878 static void set_dc_type_and_flags( struct winbindd_domain *domain )
1880 /* we always have to contact our primary domain */
1882 if ( domain->primary ) {
1883 DEBUG(10,("set_dc_type_and_flags: setting up flags for "
1884 "primary domain\n"));
1885 set_dc_type_and_flags_connect( domain );
1886 return;
1889 /* Use our DC to get the information if possible */
1891 if ( !set_dc_type_and_flags_trustinfo( domain ) ) {
1892 /* Otherwise, fallback to contacting the
1893 domain directly */
1894 set_dc_type_and_flags_connect( domain );
1897 return;
1902 /**********************************************************************
1903 ***********************************************************************/
1905 static bool cm_get_schannel_dcinfo(struct winbindd_domain *domain,
1906 struct dcinfo **ppdc)
1908 NTSTATUS result;
1909 struct rpc_pipe_client *netlogon_pipe;
1911 if (lp_client_schannel() == False) {
1912 return False;
1915 result = cm_connect_netlogon(domain, &netlogon_pipe);
1916 if (!NT_STATUS_IS_OK(result)) {
1917 return False;
1920 /* Return a pointer to the struct dcinfo from the
1921 netlogon pipe. */
1923 *ppdc = domain->conn.netlogon_pipe->dc;
1924 return True;
1927 NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
1928 struct rpc_pipe_client **cli, POLICY_HND *sam_handle)
1930 struct winbindd_cm_conn *conn;
1931 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1932 fstring conn_pwd;
1933 struct dcinfo *p_dcinfo;
1934 char *machine_password = NULL;
1935 char *machine_account = NULL;
1936 char *domain_name = NULL;
1938 result = init_dc_connection(domain);
1939 if (!NT_STATUS_IS_OK(result)) {
1940 return result;
1943 conn = &domain->conn;
1945 if (conn->samr_pipe != NULL) {
1946 goto done;
1950 * No SAMR pipe yet. Attempt to get an NTLMSSP SPNEGO authenticated
1951 * sign and sealed pipe using the machine account password by
1952 * preference. If we can't - try schannel, if that fails, try
1953 * anonymous.
1956 pwd_get_cleartext(&conn->cli->pwd, conn_pwd);
1957 if ((conn->cli->user_name[0] == '\0') ||
1958 (conn->cli->domain[0] == '\0') ||
1959 (conn_pwd[0] == '\0'))
1961 result = get_trust_creds(domain, &machine_password,
1962 &machine_account, NULL);
1963 if (!NT_STATUS_IS_OK(result)) {
1964 DEBUG(10, ("cm_connect_sam: No no user available for "
1965 "domain %s, trying schannel\n", conn->cli->domain));
1966 goto schannel;
1968 domain_name = domain->name;
1969 } else {
1970 machine_password = SMB_STRDUP(conn_pwd);
1971 machine_account = SMB_STRDUP(conn->cli->user_name);
1972 domain_name = conn->cli->domain;
1975 if (!machine_password || !machine_account) {
1976 result = NT_STATUS_NO_MEMORY;
1977 goto done;
1980 /* We have an authenticated connection. Use a NTLMSSP SPNEGO
1981 authenticated SAMR pipe with sign & seal. */
1982 result = cli_rpc_pipe_open_spnego_ntlmssp(conn->cli,
1983 &ndr_table_samr.syntax_id,
1984 PIPE_AUTH_LEVEL_PRIVACY,
1985 domain_name,
1986 machine_account,
1987 machine_password,
1988 &conn->samr_pipe);
1990 if (!NT_STATUS_IS_OK(result)) {
1991 DEBUG(10,("cm_connect_sam: failed to connect to SAMR "
1992 "pipe for domain %s using NTLMSSP "
1993 "authenticated pipe: user %s\\%s. Error was "
1994 "%s\n", domain->name, domain_name,
1995 machine_account, nt_errstr(result)));
1996 goto schannel;
1999 DEBUG(10,("cm_connect_sam: connected to SAMR pipe for "
2000 "domain %s using NTLMSSP authenticated "
2001 "pipe: user %s\\%s\n", domain->name,
2002 domain_name, machine_account));
2004 result = rpccli_samr_Connect2(conn->samr_pipe, mem_ctx,
2005 conn->samr_pipe->desthost,
2006 SEC_RIGHTS_MAXIMUM_ALLOWED,
2007 &conn->sam_connect_handle);
2008 if (NT_STATUS_IS_OK(result)) {
2009 goto open_domain;
2011 DEBUG(10,("cm_connect_sam: ntlmssp-sealed rpccli_samr_Connect2 "
2012 "failed for domain %s, error was %s. Trying schannel\n",
2013 domain->name, nt_errstr(result) ));
2014 TALLOC_FREE(conn->samr_pipe);
2016 schannel:
2018 /* Fall back to schannel if it's a W2K pre-SP1 box. */
2020 if (!cm_get_schannel_dcinfo(domain, &p_dcinfo)) {
2021 /* If this call fails - conn->cli can now be NULL ! */
2022 DEBUG(10, ("cm_connect_sam: Could not get schannel auth info "
2023 "for domain %s, trying anon\n", domain->name));
2024 goto anonymous;
2026 result = cli_rpc_pipe_open_schannel_with_key
2027 (conn->cli, &ndr_table_samr.syntax_id, PIPE_AUTH_LEVEL_PRIVACY,
2028 domain->name, p_dcinfo, &conn->samr_pipe);
2030 if (!NT_STATUS_IS_OK(result)) {
2031 DEBUG(10,("cm_connect_sam: failed to connect to SAMR pipe for "
2032 "domain %s using schannel. Error was %s\n",
2033 domain->name, nt_errstr(result) ));
2034 goto anonymous;
2036 DEBUG(10,("cm_connect_sam: connected to SAMR pipe for domain %s using "
2037 "schannel.\n", domain->name ));
2039 result = rpccli_samr_Connect2(conn->samr_pipe, mem_ctx,
2040 conn->samr_pipe->desthost,
2041 SEC_RIGHTS_MAXIMUM_ALLOWED,
2042 &conn->sam_connect_handle);
2043 if (NT_STATUS_IS_OK(result)) {
2044 goto open_domain;
2046 DEBUG(10,("cm_connect_sam: schannel-sealed rpccli_samr_Connect2 failed "
2047 "for domain %s, error was %s. Trying anonymous\n",
2048 domain->name, nt_errstr(result) ));
2049 TALLOC_FREE(conn->samr_pipe);
2051 anonymous:
2053 /* Finally fall back to anonymous. */
2054 result = cli_rpc_pipe_open_noauth(conn->cli, &ndr_table_samr.syntax_id,
2055 &conn->samr_pipe);
2057 if (!NT_STATUS_IS_OK(result)) {
2058 goto done;
2061 result = rpccli_samr_Connect2(conn->samr_pipe, mem_ctx,
2062 conn->samr_pipe->desthost,
2063 SEC_RIGHTS_MAXIMUM_ALLOWED,
2064 &conn->sam_connect_handle);
2065 if (!NT_STATUS_IS_OK(result)) {
2066 DEBUG(10,("cm_connect_sam: rpccli_samr_Connect2 failed "
2067 "for domain %s Error was %s\n",
2068 domain->name, nt_errstr(result) ));
2069 goto done;
2072 open_domain:
2073 result = rpccli_samr_OpenDomain(conn->samr_pipe,
2074 mem_ctx,
2075 &conn->sam_connect_handle,
2076 SEC_RIGHTS_MAXIMUM_ALLOWED,
2077 &domain->sid,
2078 &conn->sam_domain_handle);
2080 done:
2082 if (!NT_STATUS_IS_OK(result)) {
2083 invalidate_cm_connection(conn);
2084 return result;
2087 *cli = conn->samr_pipe;
2088 *sam_handle = conn->sam_domain_handle;
2089 SAFE_FREE(machine_password);
2090 SAFE_FREE(machine_account);
2091 return result;
2094 NTSTATUS cm_connect_lsa(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
2095 struct rpc_pipe_client **cli, POLICY_HND *lsa_policy)
2097 struct winbindd_cm_conn *conn;
2098 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
2099 fstring conn_pwd;
2100 struct dcinfo *p_dcinfo;
2102 result = init_dc_connection(domain);
2103 if (!NT_STATUS_IS_OK(result))
2104 return result;
2106 conn = &domain->conn;
2108 if (conn->lsa_pipe != NULL) {
2109 goto done;
2112 pwd_get_cleartext(&conn->cli->pwd, conn_pwd);
2113 if ((conn->cli->user_name[0] == '\0') ||
2114 (conn->cli->domain[0] == '\0') ||
2115 (conn_pwd[0] == '\0')) {
2116 DEBUG(10, ("cm_connect_lsa: No no user available for "
2117 "domain %s, trying schannel\n", conn->cli->domain));
2118 goto schannel;
2121 /* We have an authenticated connection. Use a NTLMSSP SPNEGO
2122 * authenticated LSA pipe with sign & seal. */
2123 result = cli_rpc_pipe_open_spnego_ntlmssp
2124 (conn->cli, &ndr_table_lsarpc.syntax_id,
2125 PIPE_AUTH_LEVEL_PRIVACY,
2126 conn->cli->domain, conn->cli->user_name, conn_pwd,
2127 &conn->lsa_pipe);
2129 if (!NT_STATUS_IS_OK(result)) {
2130 DEBUG(10,("cm_connect_lsa: failed to connect to LSA pipe for "
2131 "domain %s using NTLMSSP authenticated pipe: user "
2132 "%s\\%s. Error was %s. Trying schannel.\n",
2133 domain->name, conn->cli->domain,
2134 conn->cli->user_name, nt_errstr(result)));
2135 goto schannel;
2138 DEBUG(10,("cm_connect_lsa: connected to LSA pipe for domain %s using "
2139 "NTLMSSP authenticated pipe: user %s\\%s\n",
2140 domain->name, conn->cli->domain, conn->cli->user_name ));
2142 result = rpccli_lsa_open_policy(conn->lsa_pipe, mem_ctx, True,
2143 SEC_RIGHTS_MAXIMUM_ALLOWED,
2144 &conn->lsa_policy);
2145 if (NT_STATUS_IS_OK(result)) {
2146 goto done;
2149 DEBUG(10,("cm_connect_lsa: rpccli_lsa_open_policy failed, trying "
2150 "schannel\n"));
2152 TALLOC_FREE(conn->lsa_pipe);
2154 schannel:
2156 /* Fall back to schannel if it's a W2K pre-SP1 box. */
2158 if (!cm_get_schannel_dcinfo(domain, &p_dcinfo)) {
2159 /* If this call fails - conn->cli can now be NULL ! */
2160 DEBUG(10, ("cm_connect_lsa: Could not get schannel auth info "
2161 "for domain %s, trying anon\n", domain->name));
2162 goto anonymous;
2164 result = cli_rpc_pipe_open_schannel_with_key
2165 (conn->cli, &ndr_table_lsarpc.syntax_id,
2166 PIPE_AUTH_LEVEL_PRIVACY,
2167 domain->name, p_dcinfo, &conn->lsa_pipe);
2169 if (!NT_STATUS_IS_OK(result)) {
2170 DEBUG(10,("cm_connect_lsa: failed to connect to LSA pipe for "
2171 "domain %s using schannel. Error was %s\n",
2172 domain->name, nt_errstr(result) ));
2173 goto anonymous;
2175 DEBUG(10,("cm_connect_lsa: connected to LSA pipe for domain %s using "
2176 "schannel.\n", domain->name ));
2178 result = rpccli_lsa_open_policy(conn->lsa_pipe, mem_ctx, True,
2179 SEC_RIGHTS_MAXIMUM_ALLOWED,
2180 &conn->lsa_policy);
2181 if (NT_STATUS_IS_OK(result)) {
2182 goto done;
2185 DEBUG(10,("cm_connect_lsa: rpccli_lsa_open_policy failed, trying "
2186 "anonymous\n"));
2188 TALLOC_FREE(conn->lsa_pipe);
2190 anonymous:
2192 result = cli_rpc_pipe_open_noauth(conn->cli,
2193 &ndr_table_lsarpc.syntax_id,
2194 &conn->lsa_pipe);
2195 if (!NT_STATUS_IS_OK(result)) {
2196 result = NT_STATUS_PIPE_NOT_AVAILABLE;
2197 goto done;
2200 result = rpccli_lsa_open_policy(conn->lsa_pipe, mem_ctx, True,
2201 SEC_RIGHTS_MAXIMUM_ALLOWED,
2202 &conn->lsa_policy);
2203 done:
2204 if (!NT_STATUS_IS_OK(result)) {
2205 invalidate_cm_connection(conn);
2206 return result;
2209 *cli = conn->lsa_pipe;
2210 *lsa_policy = conn->lsa_policy;
2211 return result;
2214 /****************************************************************************
2215 Open the netlogon pipe to this DC. Use schannel if specified in client conf.
2216 session key stored in conn->netlogon_pipe->dc->sess_key.
2217 ****************************************************************************/
2219 NTSTATUS cm_connect_netlogon(struct winbindd_domain *domain,
2220 struct rpc_pipe_client **cli)
2222 struct winbindd_cm_conn *conn;
2223 NTSTATUS result;
2225 uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
2226 uint8 mach_pwd[16];
2227 uint32 sec_chan_type;
2228 const char *account_name;
2229 struct rpc_pipe_client *netlogon_pipe = NULL;
2231 *cli = NULL;
2233 result = init_dc_connection(domain);
2234 if (!NT_STATUS_IS_OK(result)) {
2235 return result;
2238 conn = &domain->conn;
2240 if (conn->netlogon_pipe != NULL) {
2241 *cli = conn->netlogon_pipe;
2242 return NT_STATUS_OK;
2245 result = cli_rpc_pipe_open_noauth(conn->cli,
2246 &ndr_table_netlogon.syntax_id,
2247 &netlogon_pipe);
2248 if (!NT_STATUS_IS_OK(result)) {
2249 return result;
2252 if ((!IS_DC) && (!domain->primary)) {
2253 /* Clear the schannel request bit and drop down */
2254 neg_flags &= ~NETLOGON_NEG_SCHANNEL;
2255 goto no_schannel;
2258 if (lp_client_schannel() != False) {
2259 neg_flags |= NETLOGON_NEG_SCHANNEL;
2262 if (!get_trust_pw_hash(domain->name, mach_pwd, &account_name,
2263 &sec_chan_type))
2265 TALLOC_FREE(netlogon_pipe);
2266 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
2269 result = rpccli_netlogon_setup_creds(
2270 netlogon_pipe,
2271 domain->dcname, /* server name. */
2272 domain->name, /* domain name */
2273 global_myname(), /* client name */
2274 account_name, /* machine account */
2275 mach_pwd, /* machine password */
2276 sec_chan_type, /* from get_trust_pw */
2277 &neg_flags);
2279 if (!NT_STATUS_IS_OK(result)) {
2280 TALLOC_FREE(netlogon_pipe);
2281 return result;
2284 if ((lp_client_schannel() == True) &&
2285 ((neg_flags & NETLOGON_NEG_SCHANNEL) == 0)) {
2286 DEBUG(3, ("Server did not offer schannel\n"));
2287 TALLOC_FREE(netlogon_pipe);
2288 return NT_STATUS_ACCESS_DENIED;
2291 no_schannel:
2292 if ((lp_client_schannel() == False) ||
2293 ((neg_flags & NETLOGON_NEG_SCHANNEL) == 0)) {
2295 * NetSamLogonEx only works for schannel
2297 domain->can_do_samlogon_ex = False;
2299 /* We're done - just keep the existing connection to NETLOGON
2300 * open */
2301 conn->netlogon_pipe = netlogon_pipe;
2302 *cli = conn->netlogon_pipe;
2303 return NT_STATUS_OK;
2306 /* Using the credentials from the first pipe, open a signed and sealed
2307 second netlogon pipe. The session key is stored in the schannel
2308 part of the new pipe auth struct.
2311 result = cli_rpc_pipe_open_schannel_with_key(
2312 conn->cli, &ndr_table_netlogon.syntax_id,
2313 PIPE_AUTH_LEVEL_PRIVACY, domain->name, netlogon_pipe->dc,
2314 &conn->netlogon_pipe);
2316 /* We can now close the initial netlogon pipe. */
2317 TALLOC_FREE(netlogon_pipe);
2319 if (!NT_STATUS_IS_OK(result)) {
2320 DEBUG(3, ("Could not open schannel'ed NETLOGON pipe. Error "
2321 "was %s\n", nt_errstr(result)));
2323 /* make sure we return something besides OK */
2324 return !NT_STATUS_IS_OK(result) ? result : NT_STATUS_PIPE_NOT_AVAILABLE;
2328 * Try NetSamLogonEx for AD domains
2330 domain->can_do_samlogon_ex = domain->active_directory;
2332 *cli = conn->netlogon_pipe;
2333 return NT_STATUS_OK;