source: branches/samba-3.0/source/nsswitch/winbindd_cm.c@ 124

Last change on this file since 124 was 124, checked in by Paul Smedley, 18 years ago

Update source to 3.0.28a

File size: 57.5 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3
4 Winbind daemon connection manager
5
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
11
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 2 of the License, or
15 (at your option) any later version.
16
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.
21
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25*/
26
27/*
28 We need to manage connections to domain controllers without having to
29 mess up the main winbindd code with other issues. The aim of the
30 connection manager is to:
31
32 - make connections to domain controllers and cache them
33 - re-establish connections when networks or servers go down
34 - centralise the policy on connection timeouts, domain controller
35 selection etc
36 - manage re-entrancy for when winbindd becomes able to handle
37 multiple outstanding rpc requests
38
39 Why not have connection management as part of the rpc layer like tng?
40 Good question. This code may morph into libsmb/rpc_cache.c or something
41 like that but at the moment it's simply staying as part of winbind. I
42 think the TNG architecture of forcing every user of the rpc layer to use
43 the connection caching system is a bad idea. It should be an optional
44 method of using the routines.
45
46 The TNG design is quite good but I disagree with some aspects of the
47 implementation. -tpot
48
49 */
50
51/*
52 TODO:
53
54 - I'm pretty annoyed by all the make_nmb_name() stuff. It should be
55 moved down into another function.
56
57 - Take care when destroying cli_structs as they can be shared between
58 various sam handles.
59
60 */
61
62#include "includes.h"
63#include "winbindd.h"
64
65#undef DBGC_CLASS
66#define DBGC_CLASS DBGC_WINBIND
67
68struct dc_name_ip {
69 fstring name;
70 struct in_addr ip;
71};
72
73extern struct winbindd_methods reconnect_methods;
74extern BOOL override_logfile;
75
76static NTSTATUS init_dc_connection_network(struct winbindd_domain *domain);
77static void set_dc_type_and_flags( struct winbindd_domain *domain );
78static BOOL get_dcs(TALLOC_CTX *mem_ctx, const struct winbindd_domain *domain,
79 struct dc_name_ip **dcs, int *num_dcs);
80
81/****************************************************************
82 Child failed to find DC's. Reschedule check.
83****************************************************************/
84
85static void msg_failed_to_go_online(int msg_type, struct process_id src,
86 void *buf, size_t len, void *private_data)
87{
88 struct winbindd_domain *domain;
89 const char *domainname = (const char *)buf;
90
91 if (buf == NULL || len == 0) {
92 return;
93 }
94
95 DEBUG(5,("msg_fail_to_go_online: received for domain %s.\n", domainname));
96
97 for (domain = domain_list(); domain; domain = domain->next) {
98 if (domain->internal) {
99 continue;
100 }
101
102 if (strequal(domain->name, domainname)) {
103 if (domain->online) {
104 /* We're already online, ignore. */
105 DEBUG(5,("msg_fail_to_go_online: domain %s "
106 "already online.\n", domainname));
107 continue;
108 }
109
110 /* Reschedule the online check. */
111 set_domain_offline(domain);
112 break;
113 }
114 }
115}
116
117/****************************************************************
118 Actually cause a reconnect from a message.
119****************************************************************/
120
121static void msg_try_to_go_online(int msg_type, struct process_id src,
122 void *buf, size_t len, void *private_data)
123{
124 struct winbindd_domain *domain;
125 const char *domainname = (const char *)buf;
126
127 if (buf == NULL || len == 0) {
128 return;
129 }
130
131 DEBUG(5,("msg_try_to_go_online: received for domain %s.\n", domainname));
132
133 for (domain = domain_list(); domain; domain = domain->next) {
134 if (domain->internal) {
135 continue;
136 }
137
138 if (strequal(domain->name, domainname)) {
139
140 if (domain->online) {
141 /* We're already online, ignore. */
142 DEBUG(5,("msg_try_to_go_online: domain %s "
143 "already online.\n", domainname));
144 continue;
145 }
146
147 /* This call takes care of setting the online
148 flag to true if we connected, or re-adding
149 the offline handler if false. Bypasses online
150 check so always does network calls. */
151
152 init_dc_connection_network(domain);
153 break;
154 }
155 }
156}
157
158/****************************************************************
159 Fork a child to try and contact a DC. Do this as contacting a
160 DC requires blocking lookups and we don't want to block our
161 parent.
162****************************************************************/
163
164static BOOL fork_child_dc_connect(struct winbindd_domain *domain)
165{
166 struct dc_name_ip *dcs = NULL;
167 int num_dcs = 0;
168 TALLOC_CTX *mem_ctx = NULL;
169 pid_t child_pid;
170 pid_t parent_pid = sys_getpid();
171
172 /* Stop zombies */
173 CatchChild();
174
175 message_block();
176
177 child_pid = sys_fork();
178
179 if (child_pid == -1) {
180 DEBUG(0, ("fork_child_dc_connect: Could not fork: %s\n", strerror(errno)));
181 message_unblock();
182 return False;
183 }
184
185 if (child_pid != 0) {
186 /* Parent */
187 message_register(MSG_WINBIND_TRY_TO_GO_ONLINE,
188 msg_try_to_go_online, NULL);
189 message_register(MSG_WINBIND_FAILED_TO_GO_ONLINE,
190 msg_failed_to_go_online, NULL);
191 message_unblock();
192 return True;
193 }
194
195 /* Child. */
196
197 /* Leave messages blocked - we will never process one. */
198
199 /* tdb needs special fork handling */
200 if (tdb_reopen_all(1) == -1) {
201 DEBUG(0,("tdb_reopen_all failed.\n"));
202 _exit(0);
203 }
204
205 close_conns_after_fork();
206
207 if (!override_logfile) {
208 pstring logfile;
209 pstr_sprintf(logfile, "%s/log.winbindd-dc-connect", dyn_LOGFILEBASE);
210 lp_set_logfile(logfile);
211 reopen_logs();
212 }
213
214 mem_ctx = talloc_init("fork_child_dc_connect");
215 if (!mem_ctx) {
216 DEBUG(0,("talloc_init failed.\n"));
217 _exit(0);
218 }
219
220 if ((!get_dcs(mem_ctx, domain, &dcs, &num_dcs)) || (num_dcs == 0)) {
221 /* Still offline ? Can't find DC's. */
222 message_send_pid(pid_to_procid(parent_pid), MSG_WINBIND_FAILED_TO_GO_ONLINE,
223 domain->name,
224 strlen(domain->name)+1, False);
225 _exit(0);
226 }
227
228 /* We got a DC. Send a message to our parent to get it to
229 try and do the same. */
230
231 message_send_pid(pid_to_procid(parent_pid), MSG_WINBIND_TRY_TO_GO_ONLINE,
232 domain->name,
233 strlen(domain->name)+1, False);
234 _exit(0);
235}
236
237/****************************************************************
238 Handler triggered if we're offline to try and detect a DC.
239****************************************************************/
240
241static void check_domain_online_handler(struct event_context *ctx,
242 struct timed_event *te,
243 const struct timeval *now,
244 void *private_data)
245{
246 struct winbindd_domain *domain =
247 (struct winbindd_domain *)private_data;
248
249 DEBUG(10,("check_domain_online_handler: called for domain %s\n",
250 domain->name ));
251
252 TALLOC_FREE(domain->check_online_event);
253
254 /* Are we still in "startup" mode ? */
255
256 if (domain->startup && (now->tv_sec > domain->startup_time + 30)) {
257 /* No longer in "startup" mode. */
258 DEBUG(10,("check_domain_online_handler: domain %s no longer in 'startup' mode.\n",
259 domain->name ));
260 domain->startup = False;
261 }
262
263 /* We've been told to stay offline, so stay
264 that way. */
265
266 if (get_global_winbindd_state_offline()) {
267 DEBUG(10,("check_domain_online_handler: domain %s remaining globally offline\n",
268 domain->name ));
269 return;
270 }
271
272 /* Fork a child to test if it can contact a DC.
273 If it can then send ourselves a message to
274 cause a reconnect. */
275
276 fork_child_dc_connect(domain);
277}
278
279/****************************************************************
280 If we're still offline setup the timeout check.
281****************************************************************/
282
283static void calc_new_online_timeout_check(struct winbindd_domain *domain)
284{
285 int wbc = lp_winbind_cache_time();
286
287 if (domain->startup) {
288 domain->check_online_timeout = 10;
289 } else if (domain->check_online_timeout < wbc) {
290 domain->check_online_timeout = wbc;
291 }
292}
293
294/****************************************************************
295 Set domain offline and also add handler to put us back online
296 if we detect a DC.
297****************************************************************/
298
299void set_domain_offline(struct winbindd_domain *domain)
300{
301 DEBUG(10,("set_domain_offline: called for domain %s\n",
302 domain->name ));
303
304 TALLOC_FREE(domain->check_online_event);
305
306 if (domain->internal) {
307 DEBUG(3,("set_domain_offline: domain %s is internal - logic error.\n",
308 domain->name ));
309 return;
310 }
311
312 domain->online = False;
313
314 /* Offline domains are always initialized. They're
315 re-initialized when they go back online. */
316
317 domain->initialized = True;
318
319 /* We only add the timeout handler that checks and
320 allows us to go back online when we've not
321 been told to remain offline. */
322
323 if (get_global_winbindd_state_offline()) {
324 DEBUG(10,("set_domain_offline: domain %s remaining globally offline\n",
325 domain->name ));
326 return;
327 }
328
329 /* If we're in statup mode, check again in 10 seconds, not in
330 lp_winbind_cache_time() seconds (which is 5 mins by default). */
331
332 calc_new_online_timeout_check(domain);
333
334 domain->check_online_event = event_add_timed(winbind_event_context(),
335 NULL,
336 timeval_current_ofs(domain->check_online_timeout,0),
337 "check_domain_online_handler",
338 check_domain_online_handler,
339 domain);
340
341 /* The above *has* to succeed for winbindd to work. */
342 if (!domain->check_online_event) {
343 smb_panic("set_domain_offline: failed to add online handler.\n");
344 }
345
346 DEBUG(10,("set_domain_offline: added event handler for domain %s\n",
347 domain->name ));
348}
349
350/****************************************************************
351 Set domain online - if allowed.
352****************************************************************/
353
354static void set_domain_online(struct winbindd_domain *domain)
355{
356 struct timeval now;
357
358 DEBUG(10,("set_domain_online: called for domain %s\n",
359 domain->name ));
360
361 if (domain->internal) {
362 DEBUG(3,("set_domain_online: domain %s is internal - logic error.\n",
363 domain->name ));
364 return;
365 }
366
367 if (get_global_winbindd_state_offline()) {
368 DEBUG(10,("set_domain_online: domain %s remaining globally offline\n",
369 domain->name ));
370 return;
371 }
372
373 /* If we are waiting to get a krb5 ticket, trigger immediately. */
374 GetTimeOfDay(&now);
375 set_event_dispatch_time(winbind_event_context(),
376 "krb5_ticket_gain_handler", now);
377
378 /* Ok, we're out of any startup mode now... */
379 domain->startup = False;
380
381 if (domain->online == False) {
382 /* We were offline - now we're online. We default to
383 using the MS-RPC backend if we started offline,
384 and if we're going online for the first time we
385 should really re-initialize the backends and the
386 checks to see if we're talking to an AD or NT domain.
387 */
388
389 domain->initialized = False;
390
391 /* 'reconnect_methods' is the MS-RPC backend. */
392 if (domain->backend == &reconnect_methods) {
393 domain->backend = NULL;
394 }
395 }
396
397 /* Ensure we have no online timeout checks. */
398 domain->check_online_timeout = 0;
399 TALLOC_FREE(domain->check_online_event);
400
401 /* Ensure we ignore any pending child messages. */
402 message_deregister(MSG_WINBIND_TRY_TO_GO_ONLINE);
403 message_deregister(MSG_WINBIND_FAILED_TO_GO_ONLINE);
404
405 domain->online = True;
406}
407
408/****************************************************************
409 Requested to set a domain online.
410****************************************************************/
411
412void set_domain_online_request(struct winbindd_domain *domain)
413{
414 struct timeval tev;
415
416 DEBUG(10,("set_domain_online_request: called for domain %s\n",
417 domain->name ));
418
419 if (get_global_winbindd_state_offline()) {
420 DEBUG(10,("set_domain_online_request: domain %s remaining globally offline\n",
421 domain->name ));
422 return;
423 }
424
425 /* We've been told it's safe to go online and
426 try and connect to a DC. But I don't believe it
427 because network manager seems to lie.
428 Wait at least 5 seconds. Heuristics suck... */
429
430 if (!domain->check_online_event) {
431 /* If we've come from being globally offline we
432 don't have a check online event handler set.
433 We need to add one now we're trying to go
434 back online. */
435
436 DEBUG(10,("set_domain_online_request: domain %s was globally offline.\n",
437 domain->name ));
438
439 domain->check_online_event = event_add_timed(winbind_event_context(),
440 NULL,
441 timeval_current_ofs(5, 0),
442 "check_domain_online_handler",
443 check_domain_online_handler,
444 domain);
445
446 /* The above *has* to succeed for winbindd to work. */
447 if (!domain->check_online_event) {
448 smb_panic("set_domain_online_request: failed to add online handler.\n");
449 }
450 }
451
452 GetTimeOfDay(&tev);
453
454 /* Go into "startup" mode again. */
455 domain->startup_time = tev.tv_sec;
456 domain->startup = True;
457
458 tev.tv_sec += 5;
459
460 set_event_dispatch_time(winbind_event_context(), "check_domain_online_handler", tev);
461}
462
463/****************************************************************
464 Add -ve connection cache entries for domain and realm.
465****************************************************************/
466
467void winbind_add_failed_connection_entry(const struct winbindd_domain *domain,
468 const char *server,
469 NTSTATUS result)
470{
471 add_failed_connection_entry(domain->name, server, result);
472 /* If this was the saf name for the last thing we talked to,
473 remove it. */
474 saf_delete(domain->name);
475 if (*domain->alt_name) {
476 add_failed_connection_entry(domain->alt_name, server, result);
477 saf_delete(domain->alt_name);
478 }
479}
480
481/* Choose between anonymous or authenticated connections. We need to use
482 an authenticated connection if DCs have the RestrictAnonymous registry
483 entry set > 0, or the "Additional restrictions for anonymous
484 connections" set in the win2k Local Security Policy.
485
486 Caller to free() result in domain, username, password
487*/
488
489static void cm_get_ipc_userpass(char **username, char **domain, char **password)
490{
491 *username = (char *)secrets_fetch(SECRETS_AUTH_USER, NULL);
492 *domain = (char *)secrets_fetch(SECRETS_AUTH_DOMAIN, NULL);
493 *password = (char *)secrets_fetch(SECRETS_AUTH_PASSWORD, NULL);
494
495 if (*username && **username) {
496
497 if (!*domain || !**domain)
498 *domain = smb_xstrdup(lp_workgroup());
499
500 if (!*password || !**password)
501 *password = smb_xstrdup("");
502
503 DEBUG(3, ("cm_get_ipc_userpass: Retrieved auth-user from secrets.tdb [%s\\%s]\n",
504 *domain, *username));
505
506 } else {
507 DEBUG(3, ("cm_get_ipc_userpass: No auth-user defined\n"));
508 *username = smb_xstrdup("");
509 *domain = smb_xstrdup("");
510 *password = smb_xstrdup("");
511 }
512}
513
514static BOOL get_dc_name_via_netlogon(const struct winbindd_domain *domain,
515 fstring dcname, struct in_addr *dc_ip)
516{
517 struct winbindd_domain *our_domain = NULL;
518 struct rpc_pipe_client *netlogon_pipe = NULL;
519 NTSTATUS result;
520 WERROR werr;
521 TALLOC_CTX *mem_ctx;
522 unsigned int orig_timeout;
523 fstring tmp;
524 char *p;
525
526 /* Hmmmm. We can only open one connection to the NETLOGON pipe at the
527 * moment.... */
528
529 if (IS_DC) {
530 return False;
531 }
532
533 if (domain->primary) {
534 return False;
535 }
536
537 our_domain = find_our_domain();
538
539 if ((mem_ctx = talloc_init("get_dc_name_via_netlogon")) == NULL) {
540 return False;
541 }
542
543 result = cm_connect_netlogon(our_domain, &netlogon_pipe);
544 if (!NT_STATUS_IS_OK(result)) {
545 talloc_destroy(mem_ctx);
546 return False;
547 }
548
549 /* This call can take a long time - allow the server to time out.
550 35 seconds should do it. */
551
552 orig_timeout = cli_set_timeout(netlogon_pipe->cli, 35000);
553
554 werr = rpccli_netlogon_getanydcname(netlogon_pipe, mem_ctx, our_domain->dcname,
555 domain->name, tmp);
556
557 /* And restore our original timeout. */
558 cli_set_timeout(netlogon_pipe->cli, orig_timeout);
559
560 talloc_destroy(mem_ctx);
561
562 if (!W_ERROR_IS_OK(werr)) {
563 DEBUG(10, ("rpccli_netlogon_getanydcname failed: %s\n",
564 dos_errstr(werr)));
565 return False;
566 }
567
568 /* cli_netlogon_getanydcname gives us a name with \\ */
569 p = tmp;
570 if (*p == '\\') {
571 p+=1;
572 }
573 if (*p == '\\') {
574 p+=1;
575 }
576
577 fstrcpy(dcname, p);
578
579 DEBUG(10, ("rpccli_netlogon_getanydcname returned %s\n", dcname));
580
581 if (!resolve_name(dcname, dc_ip, 0x20)) {
582 return False;
583 }
584
585 return True;
586}
587
588/**
589 * Helper function to assemble trust password and account name
590 */
591static NTSTATUS get_trust_creds(const struct winbindd_domain *domain,
592 char **machine_password,
593 char **machine_account,
594 char **machine_krb5_principal)
595{
596 const char *account_name;
597
598 if (!get_trust_pw_clear(domain->name, machine_password,
599 &account_name, NULL))
600 {
601 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
602 }
603
604 if ((machine_account != NULL) &&
605 (asprintf(machine_account, "%s$", account_name) == -1))
606 {
607 return NT_STATUS_NO_MEMORY;
608 }
609
610 /* this is at least correct when domain is our domain,
611 * which is the only case, when this is currently used: */
612 if (machine_krb5_principal != NULL)
613 {
614 if (asprintf(machine_krb5_principal, "%s$@%s",
615 account_name, domain->alt_name) == -1)
616 {
617 return NT_STATUS_NO_MEMORY;
618 }
619
620 strupper_m(*machine_krb5_principal);
621 }
622
623 return NT_STATUS_OK;
624}
625
626/************************************************************************
627 Given a fd with a just-connected TCP connection to a DC, open a connection
628 to the pipe.
629************************************************************************/
630
631static NTSTATUS cm_prepare_connection(const struct winbindd_domain *domain,
632 const int sockfd,
633 const char *controller,
634 struct cli_state **cli,
635 BOOL *retry)
636{
637 char *machine_password = NULL;
638 char *machine_krb5_principal = NULL;
639 char *machine_account = NULL;
640 char *ipc_username = NULL;
641 char *ipc_domain = NULL;
642 char *ipc_password = NULL;
643
644 BOOL got_mutex;
645
646 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
647
648 struct sockaddr peeraddr;
649 socklen_t peeraddr_len;
650
651 struct sockaddr_in *peeraddr_in = (struct sockaddr_in *)&peeraddr;
652
653 DEBUG(10,("cm_prepare_connection: connecting to DC %s for domain %s\n",
654 controller, domain->name ));
655
656 *retry = True;
657
658 got_mutex = secrets_named_mutex(controller,
659 WINBIND_SERVER_MUTEX_WAIT_TIME);
660
661 if (!got_mutex) {
662 DEBUG(0,("cm_prepare_connection: mutex grab failed for %s\n",
663 controller));
664 result = NT_STATUS_POSSIBLE_DEADLOCK;
665 goto done;
666 }
667
668 if ((*cli = cli_initialise()) == NULL) {
669 DEBUG(1, ("Could not cli_initialize\n"));
670 result = NT_STATUS_NO_MEMORY;
671 goto done;
672 }
673
674 (*cli)->timeout = 10000; /* 10 seconds */
675 (*cli)->fd = sockfd;
676 fstrcpy((*cli)->desthost, controller);
677 (*cli)->use_kerberos = True;
678
679 peeraddr_len = sizeof(peeraddr);
680
681 if ((getpeername((*cli)->fd, &peeraddr, &peeraddr_len) != 0) ||
682 (peeraddr_len != sizeof(struct sockaddr_in)) ||
683 (peeraddr_in->sin_family != PF_INET))
684 {
685 DEBUG(0,("cm_prepare_connection: %s\n", strerror(errno)));
686 result = NT_STATUS_UNSUCCESSFUL;
687 goto done;
688 }
689
690 if (ntohs(peeraddr_in->sin_port) == 139) {
691 struct nmb_name calling;
692 struct nmb_name called;
693
694 make_nmb_name(&calling, global_myname(), 0x0);
695 make_nmb_name(&called, "*SMBSERVER", 0x20);
696
697 if (!cli_session_request(*cli, &calling, &called)) {
698 DEBUG(8, ("cli_session_request failed for %s\n",
699 controller));
700 result = NT_STATUS_UNSUCCESSFUL;
701 goto done;
702 }
703 }
704
705 cli_setup_signing_state(*cli, Undefined);
706
707 if (!cli_negprot(*cli)) {
708 DEBUG(1, ("cli_negprot failed\n"));
709 result = NT_STATUS_UNSUCCESSFUL;
710 goto done;
711 }
712
713 if (!is_trusted_domain_situation(domain->name) &&
714 (*cli)->protocol >= PROTOCOL_NT1 &&
715 (*cli)->capabilities & CAP_EXTENDED_SECURITY)
716 {
717 ADS_STATUS ads_status;
718
719 result = get_trust_creds(domain, &machine_password,
720 &machine_account,
721 &machine_krb5_principal);
722 if (!NT_STATUS_IS_OK(result)) {
723 goto done;
724 }
725
726 if (lp_security() == SEC_ADS) {
727
728 /* Try a krb5 session */
729
730 (*cli)->use_kerberos = True;
731 DEBUG(5, ("connecting to %s from %s with kerberos principal "
732 "[%s]\n", controller, global_myname(),
733 machine_krb5_principal));
734
735 ads_status = cli_session_setup_spnego(*cli,
736 machine_krb5_principal,
737 machine_password,
738 domain->name);
739
740 if (!ADS_ERR_OK(ads_status)) {
741 DEBUG(4,("failed kerberos session setup with %s\n",
742 ads_errstr(ads_status)));
743 }
744
745 result = ads_ntstatus(ads_status);
746 if (NT_STATUS_IS_OK(result)) {
747 /* Ensure creds are stored for NTLMSSP authenticated pipe access. */
748 cli_init_creds(*cli, machine_account, domain->name, machine_password);
749 goto session_setup_done;
750 }
751 }
752
753 /* Fall back to non-kerberos session setup using NTLMSSP SPNEGO with the machine account. */
754 (*cli)->use_kerberos = False;
755
756 DEBUG(5, ("connecting to %s from %s with username "
757 "[%s]\\[%s]\n", controller, global_myname(),
758 domain->name, machine_account));
759
760 ads_status = cli_session_setup_spnego(*cli,
761 machine_account,
762 machine_password,
763 domain->name);
764 if (!ADS_ERR_OK(ads_status)) {
765 DEBUG(4, ("authenticated session setup failed with %s\n",
766 ads_errstr(ads_status)));
767 }
768
769 result = ads_ntstatus(ads_status);
770 if (NT_STATUS_IS_OK(result)) {
771 /* Ensure creds are stored for NTLMSSP authenticated pipe access. */
772 cli_init_creds(*cli, machine_account, domain->name, machine_password);
773 goto session_setup_done;
774 }
775 }
776
777 /* Fall back to non-kerberos session setup with auth_user */
778
779 (*cli)->use_kerberos = False;
780
781 cm_get_ipc_userpass(&ipc_username, &ipc_domain, &ipc_password);
782
783 if ((((*cli)->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) != 0) &&
784 (strlen(ipc_username) > 0)) {
785
786 /* Only try authenticated if we have a username */
787
788 DEBUG(5, ("connecting to %s from %s with username "
789 "[%s]\\[%s]\n", controller, global_myname(),
790 ipc_domain, ipc_username));
791
792 if (NT_STATUS_IS_OK(cli_session_setup(
793 *cli, ipc_username,
794 ipc_password, strlen(ipc_password)+1,
795 ipc_password, strlen(ipc_password)+1,
796 ipc_domain))) {
797 /* Successful logon with given username. */
798 cli_init_creds(*cli, ipc_username, ipc_domain, ipc_password);
799 goto session_setup_done;
800 } else {
801 DEBUG(4, ("authenticated session setup with user %s\\%s failed.\n",
802 ipc_domain, ipc_username ));
803 }
804 }
805
806 /* Fall back to anonymous connection, this might fail later */
807
808 if (NT_STATUS_IS_OK(cli_session_setup(*cli, "", NULL, 0,
809 NULL, 0, ""))) {
810 DEBUG(5, ("Connected anonymously\n"));
811 cli_init_creds(*cli, "", "", "");
812 goto session_setup_done;
813 }
814
815 result = cli_nt_error(*cli);
816
817 if (NT_STATUS_IS_OK(result))
818 result = NT_STATUS_UNSUCCESSFUL;
819
820 /* We can't session setup */
821
822 goto done;
823
824 session_setup_done:
825
826 /* cache the server name for later connections */
827
828 saf_store( domain->name, (*cli)->desthost );
829 if (domain->alt_name && (*cli)->use_kerberos) {
830 saf_store( domain->alt_name, (*cli)->desthost );
831 }
832
833 if (!cli_send_tconX(*cli, "IPC$", "IPC", "", 0)) {
834
835 result = cli_nt_error(*cli);
836
837 DEBUG(1,("failed tcon_X with %s\n", nt_errstr(result)));
838
839 if (NT_STATUS_IS_OK(result))
840 result = NT_STATUS_UNSUCCESSFUL;
841
842 goto done;
843 }
844
845 secrets_named_mutex_release(controller);
846 got_mutex = False;
847 *retry = False;
848
849 /* set the domain if empty; needed for schannel connections */
850 if ( !*(*cli)->domain ) {
851 fstrcpy( (*cli)->domain, domain->name );
852 }
853
854 result = NT_STATUS_OK;
855
856 done:
857 if (got_mutex) {
858 secrets_named_mutex_release(controller);
859 }
860
861 SAFE_FREE(machine_account);
862 SAFE_FREE(machine_password);
863 SAFE_FREE(machine_krb5_principal);
864 SAFE_FREE(ipc_username);
865 SAFE_FREE(ipc_domain);
866 SAFE_FREE(ipc_password);
867
868 if (!NT_STATUS_IS_OK(result)) {
869 winbind_add_failed_connection_entry(domain, controller, result);
870 if ((*cli) != NULL) {
871 cli_shutdown(*cli);
872 *cli = NULL;
873 }
874 }
875
876 return result;
877}
878
879static BOOL add_one_dc_unique(TALLOC_CTX *mem_ctx, const char *domain_name,
880 const char *dcname, struct in_addr ip,
881 struct dc_name_ip **dcs, int *num)
882{
883 if (!NT_STATUS_IS_OK(check_negative_conn_cache(domain_name, dcname))) {
884 DEBUG(10, ("DC %s was in the negative conn cache\n", dcname));
885 return False;
886 }
887
888 *dcs = TALLOC_REALLOC_ARRAY(mem_ctx, *dcs, struct dc_name_ip, (*num)+1);
889
890 if (*dcs == NULL)
891 return False;
892
893 fstrcpy((*dcs)[*num].name, dcname);
894 (*dcs)[*num].ip = ip;
895 *num += 1;
896 return True;
897}
898
899static BOOL add_sockaddr_to_array(TALLOC_CTX *mem_ctx,
900 struct in_addr ip, uint16 port,
901 struct sockaddr_in **addrs, int *num)
902{
903 *addrs = TALLOC_REALLOC_ARRAY(mem_ctx, *addrs, struct sockaddr_in, (*num)+1);
904
905 if (*addrs == NULL) {
906 *num = 0;
907 return False;
908 }
909
910 (*addrs)[*num].sin_family = PF_INET;
911 putip((char *)&((*addrs)[*num].sin_addr), (char *)&ip);
912 (*addrs)[*num].sin_port = htons(port);
913
914 *num += 1;
915 return True;
916}
917
918static void mailslot_name(struct in_addr dc_ip, fstring name)
919{
920 fstr_sprintf(name, "\\MAILSLOT\\NET\\GETDC%X", dc_ip.s_addr);
921}
922
923static BOOL send_getdc_request(struct in_addr dc_ip,
924 const char *domain_name,
925 const DOM_SID *sid)
926{
927 pstring outbuf;
928 char *p;
929 fstring my_acct_name;
930 fstring my_mailslot;
931
932 mailslot_name(dc_ip, my_mailslot);
933
934 memset(outbuf, '\0', sizeof(outbuf));
935
936 p = outbuf;
937
938 SCVAL(p, 0, SAMLOGON);
939 p++;
940
941 SCVAL(p, 0, 0); /* Count pointer ... */
942 p++;
943
944 SIVAL(p, 0, 0); /* The sender's token ... */
945 p += 2;
946
947 p += dos_PutUniCode(p, global_myname(),
948 sizeof(outbuf) - PTR_DIFF(p, outbuf), True);
949 fstr_sprintf(my_acct_name, "%s$", global_myname());
950 p += dos_PutUniCode(p, my_acct_name,
951 sizeof(outbuf) - PTR_DIFF(p, outbuf), True);
952
953 if (strlen(my_mailslot)+1 > sizeof(outbuf) - PTR_DIFF(p, outbuf)) {
954 return False;
955 }
956
957 memcpy(p, my_mailslot, strlen(my_mailslot)+1);
958 p += strlen(my_mailslot)+1;
959
960 if (sizeof(outbuf) - PTR_DIFF(p, outbuf) < 8) {
961 return False;
962 }
963 SIVAL(p, 0, 0x80);
964 p+=4;
965
966 SIVAL(p, 0, sid_size(sid));
967 p+=4;
968
969 p = ALIGN4(p, outbuf);
970
971 if (PTR_DIFF(p, outbuf) > sizeof(outbuf)) {
972 return False;
973 }
974
975 if (sid_size(sid) + 8 > sizeof(outbuf) - PTR_DIFF(p, outbuf)) {
976 return False;
977 }
978
979 sid_linearize(p, sizeof(outbuf) - PTR_DIFF(p, outbuf), sid);
980 p += sid_size(sid);
981
982 SIVAL(p, 0, 1);
983 SSVAL(p, 4, 0xffff);
984 SSVAL(p, 6, 0xffff);
985 p+=8;
986
987 return cli_send_mailslot(False, "\\MAILSLOT\\NET\\NTLOGON", 0,
988 outbuf, PTR_DIFF(p, outbuf),
989 global_myname(), 0, domain_name, 0x1c,
990 dc_ip);
991}
992
993static BOOL receive_getdc_response(struct in_addr dc_ip,
994 const char *domain_name,
995 fstring dc_name)
996{
997 struct packet_struct *packet;
998 fstring my_mailslot;
999 char *buf, *p;
1000 fstring dcname, user, domain;
1001 int len;
1002
1003 mailslot_name(dc_ip, my_mailslot);
1004
1005 packet = receive_unexpected(DGRAM_PACKET, 0, my_mailslot);
1006
1007 if (packet == NULL) {
1008 DEBUG(5, ("Did not receive packet for %s\n", my_mailslot));
1009 return False;
1010 }
1011
1012 DEBUG(5, ("Received packet for %s\n", my_mailslot));
1013
1014 buf = packet->packet.dgram.data;
1015 len = packet->packet.dgram.datasize;
1016
1017 if (len < 70) {
1018 /* 70 is a completely arbitrary value to make sure
1019 the SVAL below does not read uninitialized memory */
1020 DEBUG(3, ("GetDC got short response\n"));
1021 return False;
1022 }
1023
1024 /* This should be (buf-4)+SVAL(buf-4, smb_vwv12)... */
1025 p = buf+SVAL(buf, smb_vwv10);
1026
1027 if (CVAL(p,0) != SAMLOGON_R) {
1028 DEBUG(8, ("GetDC got invalid response type %d\n", CVAL(p, 0)));
1029 return False;
1030 }
1031
1032 p+=2;
1033 pull_ucs2(buf, dcname, p, sizeof(dcname), PTR_DIFF(buf+len, p),
1034 STR_TERMINATE|STR_NOALIGN);
1035 p = skip_unibuf(p, PTR_DIFF(buf+len, p));
1036 pull_ucs2(buf, user, p, sizeof(dcname), PTR_DIFF(buf+len, p),
1037 STR_TERMINATE|STR_NOALIGN);
1038 p = skip_unibuf(p, PTR_DIFF(buf+len, p));
1039 pull_ucs2(buf, domain, p, sizeof(dcname), PTR_DIFF(buf+len, p),
1040 STR_TERMINATE|STR_NOALIGN);
1041 p = skip_unibuf(p, PTR_DIFF(buf+len, p));
1042
1043 if (!strequal(domain, domain_name)) {
1044 DEBUG(3, ("GetDC: Expected domain %s, got %s\n",
1045 domain_name, domain));
1046 return False;
1047 }
1048
1049 p = dcname;
1050 if (*p == '\\') p += 1;
1051 if (*p == '\\') p += 1;
1052
1053 fstrcpy(dc_name, p);
1054
1055 DEBUG(10, ("GetDC gave name %s for domain %s\n",
1056 dc_name, domain));
1057
1058 return True;
1059}
1060
1061/*******************************************************************
1062 convert an ip to a name
1063*******************************************************************/
1064
1065static BOOL dcip_to_name(const struct winbindd_domain *domain, struct in_addr ip, fstring name )
1066{
1067 struct ip_service ip_list;
1068
1069 ip_list.ip = ip;
1070 ip_list.port = 0;
1071
1072#ifdef WITH_ADS
1073 /* For active directory servers, try to get the ldap server name.
1074 None of these failures should be considered critical for now */
1075
1076 if (lp_security() == SEC_ADS) {
1077 ADS_STRUCT *ads;
1078
1079 ads = ads_init(domain->alt_name, domain->name, NULL);
1080 ads->auth.flags |= ADS_AUTH_NO_BIND;
1081
1082 if (ads_try_connect( ads, inet_ntoa(ip) ) ) {
1083 /* We got a cldap packet. */
1084 fstrcpy(name, ads->config.ldap_server_name);
1085 namecache_store(name, 0x20, 1, &ip_list);
1086
1087 DEBUG(10,("dcip_to_name: flags = 0x%x\n", (unsigned int)ads->config.flags));
1088
1089 if (domain->primary && (ads->config.flags & ADS_KDC)) {
1090 if (ads_closest_dc(ads)) {
1091 char *sitename = sitename_fetch(ads->config.realm);
1092
1093 /* We're going to use this KDC for this realm/domain.
1094 If we are using sites, then force the krb5 libs
1095 to use this KDC. */
1096
1097 create_local_private_krb5_conf_for_domain(domain->alt_name,
1098 domain->name,
1099 sitename,
1100 ip);
1101
1102 SAFE_FREE(sitename);
1103 } else {
1104 /* use an off site KDC */
1105 create_local_private_krb5_conf_for_domain(domain->alt_name,
1106 domain->name,
1107 NULL,
1108 ip);
1109 }
1110 /* Ensure we contact this DC also. */
1111 saf_store( domain->name, name);
1112 saf_store( domain->alt_name, name);
1113 }
1114
1115 ads_destroy( &ads );
1116 return True;
1117 }
1118
1119 ads_destroy( &ads );
1120 }
1121#endif
1122
1123 /* try GETDC requests next */
1124
1125 if (send_getdc_request(ip, domain->name, &domain->sid)) {
1126 int i;
1127 smb_msleep(100);
1128 for (i=0; i<5; i++) {
1129 if (receive_getdc_response(ip, domain->name, name)) {
1130 namecache_store(name, 0x20, 1, &ip_list);
1131 return True;
1132 }
1133 smb_msleep(500);
1134 }
1135 }
1136
1137 /* try node status request */
1138
1139 if ( name_status_find(domain->name, 0x1c, 0x20, ip, name) ) {
1140 namecache_store(name, 0x20, 1, &ip_list);
1141 return True;
1142 }
1143 return False;
1144}
1145
1146/*******************************************************************
1147 Retreive a list of IP address for domain controllers. Fill in
1148 the dcs[] with results.
1149*******************************************************************/
1150
1151static BOOL get_dcs(TALLOC_CTX *mem_ctx, const struct winbindd_domain *domain,
1152 struct dc_name_ip **dcs, int *num_dcs)
1153{
1154 fstring dcname;
1155 struct in_addr ip;
1156 struct ip_service *ip_list = NULL;
1157 int iplist_size = 0;
1158 int i;
1159 BOOL is_our_domain;
1160 enum security_types sec = (enum security_types)lp_security();
1161
1162 is_our_domain = strequal(domain->name, lp_workgroup());
1163
1164 if ( !is_our_domain
1165 && get_dc_name_via_netlogon(domain, dcname, &ip)
1166 && add_one_dc_unique(mem_ctx, domain->name, dcname, ip, dcs, num_dcs) )
1167 {
1168 DEBUG(10, ("Retrieved DC %s at %s via netlogon\n",
1169 dcname, inet_ntoa(ip)));
1170 return True;
1171 }
1172
1173 if (sec == SEC_ADS) {
1174 char *sitename = NULL;
1175
1176 /* We need to make sure we know the local site before
1177 doing any DNS queries, as this will restrict the
1178 get_sorted_dc_list() call below to only fetching
1179 DNS records for the correct site. */
1180
1181 /* Find any DC to get the site record.
1182 We deliberately don't care about the
1183 return here. */
1184
1185 get_dc_name(domain->name, domain->alt_name, dcname, &ip);
1186
1187 sitename = sitename_fetch(domain->alt_name);
1188 if (sitename) {
1189
1190 /* Do the site-specific AD dns lookup first. */
1191 get_sorted_dc_list(domain->alt_name, sitename, &ip_list, &iplist_size, True);
1192
1193 for ( i=0; i<iplist_size; i++ ) {
1194 add_one_dc_unique(mem_ctx, domain->name, inet_ntoa(ip_list[i].ip),
1195 ip_list[i].ip, dcs, num_dcs);
1196 }
1197
1198 SAFE_FREE(ip_list);
1199 SAFE_FREE(sitename);
1200 iplist_size = 0;
1201 }
1202
1203 /* Now we add DCs from the main AD dns lookup. */
1204 get_sorted_dc_list(domain->alt_name, NULL, &ip_list, &iplist_size, True);
1205
1206 for ( i=0; i<iplist_size; i++ ) {
1207 add_one_dc_unique(mem_ctx, domain->name, inet_ntoa(ip_list[i].ip),
1208 ip_list[i].ip, dcs, num_dcs);
1209 }
1210 }
1211
1212 /* try standard netbios queries if no ADS */
1213
1214 if (iplist_size==0) {
1215 get_sorted_dc_list(domain->name, NULL, &ip_list, &iplist_size, False);
1216 }
1217
1218 /* FIXME!! this is where we should re-insert the GETDC requests --jerry */
1219
1220 /* now add to the dc array. We'll wait until the last minute
1221 to look up the name of the DC. But we fill in the char* for
1222 the ip now in to make the failed connection cache work */
1223
1224 for ( i=0; i<iplist_size; i++ ) {
1225 add_one_dc_unique(mem_ctx, domain->name, inet_ntoa(ip_list[i].ip),
1226 ip_list[i].ip, dcs, num_dcs);
1227 }
1228
1229 SAFE_FREE( ip_list );
1230
1231 return True;
1232}
1233
1234static BOOL find_new_dc(TALLOC_CTX *mem_ctx,
1235 const struct winbindd_domain *domain,
1236 fstring dcname, struct sockaddr_in *addr, int *fd)
1237{
1238 struct dc_name_ip *dcs = NULL;
1239 int num_dcs = 0;
1240
1241 const char **dcnames = NULL;
1242 int num_dcnames = 0;
1243
1244 struct sockaddr_in *addrs = NULL;
1245 int num_addrs = 0;
1246
1247 int i, fd_index;
1248
1249 again:
1250 if (!get_dcs(mem_ctx, domain, &dcs, &num_dcs) || (num_dcs == 0))
1251 return False;
1252
1253 for (i=0; i<num_dcs; i++) {
1254
1255 if (!add_string_to_array(mem_ctx, dcs[i].name,
1256 &dcnames, &num_dcnames)) {
1257 return False;
1258 }
1259 if (!add_sockaddr_to_array(mem_ctx, dcs[i].ip, 445,
1260 &addrs, &num_addrs)) {
1261 return False;
1262 }
1263
1264 if (!add_string_to_array(mem_ctx, dcs[i].name,
1265 &dcnames, &num_dcnames)) {
1266 return False;
1267 }
1268 if (!add_sockaddr_to_array(mem_ctx, dcs[i].ip, 139,
1269 &addrs, &num_addrs)) {
1270 return False;
1271 }
1272 }
1273
1274 if ((num_dcnames == 0) || (num_dcnames != num_addrs))
1275 return False;
1276
1277 if ((addrs == NULL) || (dcnames == NULL))
1278 return False;
1279
1280 /* 5 second timeout. */
1281 if ( !open_any_socket_out(addrs, num_addrs, 5000, &fd_index, fd) )
1282 {
1283 for (i=0; i<num_dcs; i++) {
1284 DEBUG(10, ("find_new_dc: open_any_socket_out failed for "
1285 "domain %s address %s. Error was %s\n",
1286 domain->name, inet_ntoa(dcs[i].ip), strerror(errno) ));
1287 winbind_add_failed_connection_entry(domain,
1288 dcs[i].name, NT_STATUS_UNSUCCESSFUL);
1289 }
1290 return False;
1291 }
1292
1293 *addr = addrs[fd_index];
1294
1295 if (*dcnames[fd_index] != '\0' && !is_ipaddress(dcnames[fd_index])) {
1296 /* Ok, we've got a name for the DC */
1297 fstrcpy(dcname, dcnames[fd_index]);
1298 return True;
1299 }
1300
1301 /* Try to figure out the name */
1302 if (dcip_to_name( domain, addr->sin_addr, dcname )) {
1303 return True;
1304 }
1305
1306 /* We can not continue without the DC's name */
1307 winbind_add_failed_connection_entry(domain, dcs[fd_index].name,
1308 NT_STATUS_UNSUCCESSFUL);
1309 goto again;
1310}
1311
1312static NTSTATUS cm_open_connection(struct winbindd_domain *domain,
1313 struct winbindd_cm_conn *new_conn)
1314{
1315 TALLOC_CTX *mem_ctx;
1316 NTSTATUS result;
1317 char *saf_servername = saf_fetch( domain->name );
1318 int retries;
1319
1320 if ((mem_ctx = talloc_init("cm_open_connection")) == NULL) {
1321 SAFE_FREE(saf_servername);
1322 set_domain_offline(domain);
1323 return NT_STATUS_NO_MEMORY;
1324 }
1325
1326 /* we have to check the server affinity cache here since
1327 later we selecte a DC based on response time and not preference */
1328
1329 /* Check the negative connection cache
1330 before talking to it. It going down may have
1331 triggered the reconnection. */
1332
1333 if ( saf_servername && NT_STATUS_IS_OK(check_negative_conn_cache( domain->name, saf_servername))) {
1334
1335 DEBUG(10,("cm_open_connection: saf_servername is '%s' for domain %s\n",
1336 saf_servername, domain->name ));
1337
1338 /* convert an ip address to a name */
1339 if ( is_ipaddress( saf_servername ) ) {
1340 fstring saf_name;
1341 struct in_addr ip;
1342
1343 ip = *interpret_addr2( saf_servername );
1344 if (dcip_to_name( domain, ip, saf_name )) {
1345 fstrcpy( domain->dcname, saf_name );
1346 } else {
1347 winbind_add_failed_connection_entry(
1348 domain, saf_servername,
1349 NT_STATUS_UNSUCCESSFUL);
1350 }
1351 } else {
1352 fstrcpy( domain->dcname, saf_servername );
1353 }
1354
1355 SAFE_FREE( saf_servername );
1356 }
1357
1358 for (retries = 0; retries < 3; retries++) {
1359
1360 int fd = -1;
1361 BOOL retry = False;
1362
1363 result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
1364
1365 DEBUG(10,("cm_open_connection: dcname is '%s' for domain %s\n",
1366 domain->dcname, domain->name ));
1367
1368 if (*domain->dcname
1369 && NT_STATUS_IS_OK(check_negative_conn_cache( domain->name, domain->dcname))
1370 && (resolve_name(domain->dcname, &domain->dcaddr.sin_addr, 0x20)))
1371 {
1372 struct sockaddr_in *addrs = NULL;
1373 int num_addrs = 0;
1374 int dummy = 0;
1375
1376 if (!add_sockaddr_to_array(mem_ctx, domain->dcaddr.sin_addr, 445, &addrs, &num_addrs)) {
1377 set_domain_offline(domain);
1378 talloc_destroy(mem_ctx);
1379 return NT_STATUS_NO_MEMORY;
1380 }
1381 if (!add_sockaddr_to_array(mem_ctx, domain->dcaddr.sin_addr, 139, &addrs, &num_addrs)) {
1382 set_domain_offline(domain);
1383 talloc_destroy(mem_ctx);
1384 return NT_STATUS_NO_MEMORY;
1385 }
1386
1387 /* 5 second timeout. */
1388 if (!open_any_socket_out(addrs, num_addrs, 5000, &dummy, &fd)) {
1389 fd = -1;
1390 }
1391 }
1392
1393 if ((fd == -1)
1394 && !find_new_dc(mem_ctx, domain, domain->dcname, &domain->dcaddr, &fd))
1395 {
1396 /* This is the one place where we will
1397 set the global winbindd offline state
1398 to true, if a "WINBINDD_OFFLINE" entry
1399 is found in the winbindd cache. */
1400 set_global_winbindd_state_offline();
1401 break;
1402 }
1403
1404 new_conn->cli = NULL;
1405
1406 result = cm_prepare_connection(domain, fd, domain->dcname,
1407 &new_conn->cli, &retry);
1408
1409 if (!retry)
1410 break;
1411 }
1412
1413 if (NT_STATUS_IS_OK(result)) {
1414 if (domain->online == False) {
1415 /* We're changing state from offline to online. */
1416 set_global_winbindd_state_online();
1417 }
1418 set_domain_online(domain);
1419 } else {
1420 /* Ensure we setup the retry handler. */
1421 set_domain_offline(domain);
1422 }
1423
1424 talloc_destroy(mem_ctx);
1425 return result;
1426}
1427
1428/* Close down all open pipes on a connection. */
1429
1430void invalidate_cm_connection(struct winbindd_cm_conn *conn)
1431{
1432 /* We're closing down a possibly dead
1433 connection. Don't have impossibly long (10s) timeouts. */
1434
1435 if (conn->cli) {
1436 cli_set_timeout(conn->cli, 1000); /* 1 second. */
1437 }
1438
1439 if (conn->samr_pipe != NULL) {
1440 if (!cli_rpc_pipe_close(conn->samr_pipe)) {
1441 /* Ok, it must be dead. Drop timeout to 0.5 sec. */
1442 if (conn->cli) {
1443 cli_set_timeout(conn->cli, 500);
1444 }
1445 }
1446 conn->samr_pipe = NULL;
1447 }
1448
1449 if (conn->lsa_pipe != NULL) {
1450 if (!cli_rpc_pipe_close(conn->lsa_pipe)) {
1451 /* Ok, it must be dead. Drop timeout to 0.5 sec. */
1452 if (conn->cli) {
1453 cli_set_timeout(conn->cli, 500);
1454 }
1455 }
1456 conn->lsa_pipe = NULL;
1457 }
1458
1459 if (conn->netlogon_pipe != NULL) {
1460 if (!cli_rpc_pipe_close(conn->netlogon_pipe)) {
1461 /* Ok, it must be dead. Drop timeout to 0.5 sec. */
1462 if (conn->cli) {
1463 cli_set_timeout(conn->cli, 500);
1464 }
1465 }
1466 conn->netlogon_pipe = NULL;
1467 }
1468
1469 if (conn->cli) {
1470 cli_shutdown(conn->cli);
1471 }
1472
1473 conn->cli = NULL;
1474}
1475
1476void close_conns_after_fork(void)
1477{
1478 struct winbindd_domain *domain;
1479
1480 for (domain = domain_list(); domain; domain = domain->next) {
1481 if (domain->conn.cli == NULL)
1482 continue;
1483
1484 if (domain->conn.cli->fd == -1)
1485 continue;
1486
1487 close(domain->conn.cli->fd);
1488 domain->conn.cli->fd = -1;
1489 }
1490}
1491
1492static BOOL connection_ok(struct winbindd_domain *domain)
1493{
1494 if (domain->conn.cli == NULL) {
1495 DEBUG(8, ("connection_ok: Connection to %s for domain %s has NULL "
1496 "cli!\n", domain->dcname, domain->name));
1497 return False;
1498 }
1499
1500 if (!domain->conn.cli->initialised) {
1501 DEBUG(3, ("connection_ok: Connection to %s for domain %s was never "
1502 "initialised!\n", domain->dcname, domain->name));
1503 return False;
1504 }
1505
1506 if (domain->conn.cli->fd == -1) {
1507 DEBUG(3, ("connection_ok: Connection to %s for domain %s has died or was "
1508 "never started (fd == -1)\n",
1509 domain->dcname, domain->name));
1510 return False;
1511 }
1512
1513 if (domain->online == False) {
1514 DEBUG(3, ("connection_ok: Domain %s is offline\n", domain->name));
1515 return False;
1516 }
1517
1518 return True;
1519}
1520
1521/* Initialize a new connection up to the RPC BIND.
1522 Bypass online status check so always does network calls. */
1523
1524static NTSTATUS init_dc_connection_network(struct winbindd_domain *domain)
1525{
1526 NTSTATUS result;
1527
1528 /* Internal connections never use the network. */
1529 if (domain->internal) {
1530 domain->initialized = True;
1531 return NT_STATUS_OK;
1532 }
1533
1534 if (connection_ok(domain)) {
1535 if (!domain->initialized) {
1536 set_dc_type_and_flags(domain);
1537 }
1538 return NT_STATUS_OK;
1539 }
1540
1541 invalidate_cm_connection(&domain->conn);
1542
1543 result = cm_open_connection(domain, &domain->conn);
1544
1545 if (NT_STATUS_IS_OK(result) && !domain->initialized) {
1546 set_dc_type_and_flags(domain);
1547 }
1548
1549 return result;
1550}
1551
1552NTSTATUS init_dc_connection(struct winbindd_domain *domain)
1553{
1554 if (domain->initialized && !domain->online) {
1555 /* We check for online status elsewhere. */
1556 return NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
1557 }
1558
1559 return init_dc_connection_network(domain);
1560}
1561
1562/******************************************************************************
1563 We can 'sense' certain things about the DC by it's replies to certain
1564 questions.
1565
1566 This tells us if this particular remote server is Active Directory, and if it
1567 is native mode.
1568******************************************************************************/
1569
1570static void set_dc_type_and_flags( struct winbindd_domain *domain )
1571{
1572 NTSTATUS result;
1573 DS_DOMINFO_CTR ctr;
1574 TALLOC_CTX *mem_ctx = NULL;
1575 struct rpc_pipe_client *cli;
1576 POLICY_HND pol;
1577
1578 char *domain_name = NULL;
1579 char *dns_name = NULL;
1580 char *forest_name = NULL;
1581 DOM_SID *dom_sid = NULL;
1582
1583 ZERO_STRUCT( ctr );
1584
1585 if (!connection_ok(domain)) {
1586 return;
1587 }
1588
1589 DEBUG(5, ("set_dc_type_and_flags: domain %s\n", domain->name ));
1590
1591 cli = cli_rpc_pipe_open_noauth(domain->conn.cli, PI_LSARPC_DS,
1592 &result);
1593
1594 if (cli == NULL) {
1595 DEBUG(5, ("set_dc_type_and_flags: Could not bind to "
1596 "PI_LSARPC_DS on domain %s: (%s)\n",
1597 domain->name, nt_errstr(result)));
1598
1599 /* if this is just a non-AD domain we need to continue
1600 * identifying so that we can in the end return with
1601 * domain->initialized = True - gd */
1602
1603 goto no_lsarpc_ds;
1604 }
1605
1606 result = rpccli_ds_getprimarydominfo(cli, cli->cli->mem_ctx,
1607 DsRolePrimaryDomainInfoBasic,
1608 &ctr);
1609 cli_rpc_pipe_close(cli);
1610
1611 if (!NT_STATUS_IS_OK(result)) {
1612 DEBUG(5, ("set_dc_type_and_flags: rpccli_ds_getprimarydominfo "
1613 "on domain %s failed: (%s)\n",
1614 domain->name, nt_errstr(result)));
1615
1616 /* older samba3 DCs will return DCERPC_FAULT_OP_RNG_ERROR for
1617 * every opcode on the LSARPC_DS pipe, continue with
1618 * no_lsarpc_ds mode here as well to get domain->initialized
1619 * set - gd */
1620
1621 if (NT_STATUS_V(result) == DCERPC_FAULT_OP_RNG_ERROR) {
1622 goto no_lsarpc_ds;
1623 }
1624
1625 return;
1626 }
1627
1628 if ((ctr.basic->flags & DSROLE_PRIMARY_DS_RUNNING) &&
1629 !(ctr.basic->flags & DSROLE_PRIMARY_DS_MIXED_MODE)) {
1630 domain->native_mode = True;
1631 } else {
1632 domain->native_mode = False;
1633 }
1634
1635no_lsarpc_ds:
1636 cli = cli_rpc_pipe_open_noauth(domain->conn.cli, PI_LSARPC, &result);
1637
1638 if (cli == NULL) {
1639 DEBUG(5, ("set_dc_type_and_flags: Could not bind to "
1640 "PI_LSARPC on domain %s: (%s)\n",
1641 domain->name, nt_errstr(result)));
1642 cli_rpc_pipe_close(cli);
1643 return;
1644 }
1645
1646 mem_ctx = talloc_init("set_dc_type_and_flags on domain %s\n",
1647 domain->name);
1648 if (!mem_ctx) {
1649 DEBUG(1, ("set_dc_type_and_flags: talloc_init() failed\n"));
1650 cli_rpc_pipe_close(cli);
1651 return;
1652 }
1653
1654 result = rpccli_lsa_open_policy2(cli, mem_ctx, True,
1655 SEC_RIGHTS_MAXIMUM_ALLOWED, &pol);
1656
1657 if (NT_STATUS_IS_OK(result)) {
1658 /* This particular query is exactly what Win2k clients use
1659 to determine that the DC is active directory */
1660 result = rpccli_lsa_query_info_policy2(cli, mem_ctx, &pol,
1661 12, &domain_name,
1662 &dns_name, &forest_name,
1663 NULL, &dom_sid);
1664 }
1665
1666 if (NT_STATUS_IS_OK(result)) {
1667 domain->active_directory = True;
1668
1669 if (domain_name)
1670 fstrcpy(domain->name, domain_name);
1671
1672 if (dns_name)
1673 fstrcpy(domain->alt_name, dns_name);
1674
1675 if ( forest_name )
1676 fstrcpy(domain->forest_name, forest_name);
1677
1678 if (dom_sid)
1679 sid_copy(&domain->sid, dom_sid);
1680 } else {
1681 domain->active_directory = False;
1682
1683 result = rpccli_lsa_open_policy(cli, mem_ctx, True,
1684 SEC_RIGHTS_MAXIMUM_ALLOWED,
1685 &pol);
1686
1687 if (!NT_STATUS_IS_OK(result))
1688 goto done;
1689
1690 result = rpccli_lsa_query_info_policy(cli, mem_ctx,
1691 &pol, 5, &domain_name,
1692 &dom_sid);
1693
1694 if (NT_STATUS_IS_OK(result)) {
1695 if (domain_name)
1696 fstrcpy(domain->name, domain_name);
1697
1698 if (dom_sid)
1699 sid_copy(&domain->sid, dom_sid);
1700 }
1701 }
1702done:
1703
1704 DEBUG(5, ("set_dc_type_and_flags: domain %s is %sin native mode.\n",
1705 domain->name, domain->native_mode ? "" : "NOT "));
1706
1707 DEBUG(5,("set_dc_type_and_flags: domain %s is %srunning active directory.\n",
1708 domain->name, domain->active_directory ? "" : "NOT "));
1709
1710 cli_rpc_pipe_close(cli);
1711
1712 talloc_destroy(mem_ctx);
1713
1714 domain->initialized = True;
1715}
1716
1717static BOOL cm_get_schannel_dcinfo(struct winbindd_domain *domain,
1718 struct dcinfo **ppdc)
1719{
1720 NTSTATUS result;
1721 struct rpc_pipe_client *netlogon_pipe;
1722
1723 if (lp_client_schannel() == False) {
1724 return False;
1725 }
1726
1727 result = cm_connect_netlogon(domain, &netlogon_pipe);
1728 if (!NT_STATUS_IS_OK(result)) {
1729 return False;
1730 }
1731
1732 /* Return a pointer to the struct dcinfo from the
1733 netlogon pipe. */
1734
1735 *ppdc = domain->conn.netlogon_pipe->dc;
1736 return True;
1737}
1738
1739NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
1740 struct rpc_pipe_client **cli, POLICY_HND *sam_handle)
1741{
1742 struct winbindd_cm_conn *conn;
1743 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1744 fstring conn_pwd;
1745 struct dcinfo *p_dcinfo;
1746 char *machine_password = NULL;
1747 char *machine_account = NULL;
1748 char *domain_name = NULL;
1749
1750 result = init_dc_connection(domain);
1751 if (!NT_STATUS_IS_OK(result)) {
1752 return result;
1753 }
1754
1755 conn = &domain->conn;
1756
1757 if (conn->samr_pipe != NULL) {
1758 goto done;
1759 }
1760
1761 /*
1762 * No SAMR pipe yet. Attempt to get an NTLMSSP SPNEGO authenticated
1763 * sign and sealed pipe using the machine account password by
1764 * preference. If we can't - try schannel, if that fails, try
1765 * anonymous.
1766 */
1767
1768 pwd_get_cleartext(&conn->cli->pwd, conn_pwd);
1769 if ((conn->cli->user_name[0] == '\0') ||
1770 (conn->cli->domain[0] == '\0') ||
1771 (conn_pwd[0] == '\0'))
1772 {
1773 result = get_trust_creds(domain, &machine_password,
1774 &machine_account, NULL);
1775 if (!NT_STATUS_IS_OK(result)) {
1776 DEBUG(10, ("cm_connect_sam: No no user available for "
1777 "domain %s, trying schannel\n", conn->cli->domain));
1778 goto schannel;
1779 }
1780 domain_name = domain->name;
1781 } else {
1782 machine_password = SMB_STRDUP(conn_pwd);
1783 machine_account = SMB_STRDUP(conn->cli->user_name);
1784 domain_name = conn->cli->domain;
1785 }
1786
1787 if (!machine_password || !machine_account) {
1788 result = NT_STATUS_NO_MEMORY;
1789 goto done;
1790 }
1791
1792 /* We have an authenticated connection. Use a NTLMSSP SPNEGO
1793 authenticated SAMR pipe with sign & seal. */
1794 conn->samr_pipe =
1795 cli_rpc_pipe_open_spnego_ntlmssp(conn->cli, PI_SAMR,
1796 PIPE_AUTH_LEVEL_PRIVACY,
1797 domain_name,
1798 machine_account,
1799 machine_password, &result);
1800
1801 if (conn->samr_pipe == NULL) {
1802 DEBUG(10,("cm_connect_sam: failed to connect to SAMR "
1803 "pipe for domain %s using NTLMSSP "
1804 "authenticated pipe: user %s\\%s. Error was "
1805 "%s\n", domain->name, domain_name,
1806 machine_account, nt_errstr(result)));
1807 goto schannel;
1808 }
1809
1810 DEBUG(10,("cm_connect_sam: connected to SAMR pipe for "
1811 "domain %s using NTLMSSP authenticated "
1812 "pipe: user %s\\%s\n", domain->name,
1813 domain_name, machine_account));
1814
1815 result = rpccli_samr_connect(conn->samr_pipe, mem_ctx,
1816 SEC_RIGHTS_MAXIMUM_ALLOWED,
1817 &conn->sam_connect_handle);
1818 if (NT_STATUS_IS_OK(result)) {
1819 goto open_domain;
1820 }
1821 DEBUG(10,("cm_connect_sam: ntlmssp-sealed rpccli_samr_connect "
1822 "failed for domain %s, error was %s. Trying schannel\n",
1823 domain->name, nt_errstr(result) ));
1824 cli_rpc_pipe_close(conn->samr_pipe);
1825
1826 schannel:
1827
1828 /* Fall back to schannel if it's a W2K pre-SP1 box. */
1829
1830 if (!cm_get_schannel_dcinfo(domain, &p_dcinfo)) {
1831 /* If this call fails - conn->cli can now be NULL ! */
1832 DEBUG(10, ("cm_connect_sam: Could not get schannel auth info "
1833 "for domain %s, trying anon\n", domain->name));
1834 goto anonymous;
1835 }
1836 conn->samr_pipe = cli_rpc_pipe_open_schannel_with_key
1837 (conn->cli, PI_SAMR, PIPE_AUTH_LEVEL_PRIVACY,
1838 domain->name, p_dcinfo, &result);
1839
1840 if (conn->samr_pipe == NULL) {
1841 DEBUG(10,("cm_connect_sam: failed to connect to SAMR pipe for "
1842 "domain %s using schannel. Error was %s\n",
1843 domain->name, nt_errstr(result) ));
1844 goto anonymous;
1845 }
1846 DEBUG(10,("cm_connect_sam: connected to SAMR pipe for domain %s using "
1847 "schannel.\n", domain->name ));
1848
1849 result = rpccli_samr_connect(conn->samr_pipe, mem_ctx,
1850 SEC_RIGHTS_MAXIMUM_ALLOWED,
1851 &conn->sam_connect_handle);
1852 if (NT_STATUS_IS_OK(result)) {
1853 goto open_domain;
1854 }
1855 DEBUG(10,("cm_connect_sam: schannel-sealed rpccli_samr_connect failed "
1856 "for domain %s, error was %s. Trying anonymous\n",
1857 domain->name, nt_errstr(result) ));
1858 cli_rpc_pipe_close(conn->samr_pipe);
1859
1860 anonymous:
1861
1862 /* Finally fall back to anonymous. */
1863 conn->samr_pipe = cli_rpc_pipe_open_noauth(conn->cli, PI_SAMR,
1864 &result);
1865
1866 if (conn->samr_pipe == NULL) {
1867 result = NT_STATUS_PIPE_NOT_AVAILABLE;
1868 goto done;
1869 }
1870
1871 result = rpccli_samr_connect(conn->samr_pipe, mem_ctx,
1872 SEC_RIGHTS_MAXIMUM_ALLOWED,
1873 &conn->sam_connect_handle);
1874 if (!NT_STATUS_IS_OK(result)) {
1875 DEBUG(10,("cm_connect_sam: rpccli_samr_connect failed "
1876 "for domain %s Error was %s\n",
1877 domain->name, nt_errstr(result) ));
1878 goto done;
1879 }
1880
1881 open_domain:
1882 result = rpccli_samr_open_domain(conn->samr_pipe,
1883 mem_ctx,
1884 &conn->sam_connect_handle,
1885 SEC_RIGHTS_MAXIMUM_ALLOWED,
1886 &domain->sid,
1887 &conn->sam_domain_handle);
1888
1889 done:
1890
1891 if (!NT_STATUS_IS_OK(result)) {
1892 invalidate_cm_connection(conn);
1893 return result;
1894 }
1895
1896 *cli = conn->samr_pipe;
1897 *sam_handle = conn->sam_domain_handle;
1898 SAFE_FREE(machine_password);
1899 SAFE_FREE(machine_account);
1900 return result;
1901}
1902
1903NTSTATUS cm_connect_lsa(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
1904 struct rpc_pipe_client **cli, POLICY_HND *lsa_policy)
1905{
1906 struct winbindd_cm_conn *conn;
1907 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1908 fstring conn_pwd;
1909 struct dcinfo *p_dcinfo;
1910
1911 result = init_dc_connection(domain);
1912 if (!NT_STATUS_IS_OK(result))
1913 return result;
1914
1915 conn = &domain->conn;
1916
1917 if (conn->lsa_pipe != NULL) {
1918 goto done;
1919 }
1920
1921 pwd_get_cleartext(&conn->cli->pwd, conn_pwd);
1922 if ((conn->cli->user_name[0] == '\0') ||
1923 (conn->cli->domain[0] == '\0') ||
1924 (conn_pwd[0] == '\0')) {
1925 DEBUG(10, ("cm_connect_lsa: No no user available for "
1926 "domain %s, trying schannel\n", conn->cli->domain));
1927 goto schannel;
1928 }
1929
1930 /* We have an authenticated connection. Use a NTLMSSP SPNEGO
1931 * authenticated LSA pipe with sign & seal. */
1932 conn->lsa_pipe = cli_rpc_pipe_open_spnego_ntlmssp
1933 (conn->cli, PI_LSARPC, PIPE_AUTH_LEVEL_PRIVACY,
1934 conn->cli->domain, conn->cli->user_name, conn_pwd, &result);
1935
1936 if (conn->lsa_pipe == NULL) {
1937 DEBUG(10,("cm_connect_lsa: failed to connect to LSA pipe for "
1938 "domain %s using NTLMSSP authenticated pipe: user "
1939 "%s\\%s. Error was %s. Trying schannel.\n",
1940 domain->name, conn->cli->domain,
1941 conn->cli->user_name, nt_errstr(result)));
1942 goto schannel;
1943 }
1944
1945 DEBUG(10,("cm_connect_lsa: connected to LSA pipe for domain %s using "
1946 "NTLMSSP authenticated pipe: user %s\\%s\n",
1947 domain->name, conn->cli->domain, conn->cli->user_name ));
1948
1949 result = rpccli_lsa_open_policy(conn->lsa_pipe, mem_ctx, True,
1950 SEC_RIGHTS_MAXIMUM_ALLOWED,
1951 &conn->lsa_policy);
1952 if (NT_STATUS_IS_OK(result)) {
1953 goto done;
1954 }
1955
1956 DEBUG(10,("cm_connect_lsa: rpccli_lsa_open_policy failed, trying "
1957 "schannel\n"));
1958
1959 cli_rpc_pipe_close(conn->lsa_pipe);
1960
1961 schannel:
1962
1963 /* Fall back to schannel if it's a W2K pre-SP1 box. */
1964
1965 if (!cm_get_schannel_dcinfo(domain, &p_dcinfo)) {
1966 /* If this call fails - conn->cli can now be NULL ! */
1967 DEBUG(10, ("cm_connect_lsa: Could not get schannel auth info "
1968 "for domain %s, trying anon\n", domain->name));
1969 goto anonymous;
1970 }
1971 conn->lsa_pipe = cli_rpc_pipe_open_schannel_with_key
1972 (conn->cli, PI_LSARPC, PIPE_AUTH_LEVEL_PRIVACY,
1973 domain->name, p_dcinfo, &result);
1974
1975 if (conn->lsa_pipe == NULL) {
1976 DEBUG(10,("cm_connect_lsa: failed to connect to LSA pipe for "
1977 "domain %s using schannel. Error was %s\n",
1978 domain->name, nt_errstr(result) ));
1979 goto anonymous;
1980 }
1981 DEBUG(10,("cm_connect_lsa: connected to LSA pipe for domain %s using "
1982 "schannel.\n", domain->name ));
1983
1984 result = rpccli_lsa_open_policy(conn->lsa_pipe, mem_ctx, True,
1985 SEC_RIGHTS_MAXIMUM_ALLOWED,
1986 &conn->lsa_policy);
1987 if (NT_STATUS_IS_OK(result)) {
1988 goto done;
1989 }
1990
1991 DEBUG(10,("cm_connect_lsa: rpccli_lsa_open_policy failed, trying "
1992 "anonymous\n"));
1993
1994 cli_rpc_pipe_close(conn->lsa_pipe);
1995
1996 anonymous:
1997
1998 conn->lsa_pipe = cli_rpc_pipe_open_noauth(conn->cli, PI_LSARPC,
1999 &result);
2000 if (conn->lsa_pipe == NULL) {
2001 result = NT_STATUS_PIPE_NOT_AVAILABLE;
2002 goto done;
2003 }
2004
2005 result = rpccli_lsa_open_policy(conn->lsa_pipe, mem_ctx, True,
2006 SEC_RIGHTS_MAXIMUM_ALLOWED,
2007 &conn->lsa_policy);
2008 done:
2009 if (!NT_STATUS_IS_OK(result)) {
2010 invalidate_cm_connection(conn);
2011 return result;
2012 }
2013
2014 *cli = conn->lsa_pipe;
2015 *lsa_policy = conn->lsa_policy;
2016 return result;
2017}
2018
2019/****************************************************************************
2020 Open the netlogon pipe to this DC. Use schannel if specified in client conf.
2021 session key stored in conn->netlogon_pipe->dc->sess_key.
2022****************************************************************************/
2023
2024NTSTATUS cm_connect_netlogon(struct winbindd_domain *domain,
2025 struct rpc_pipe_client **cli)
2026{
2027 struct winbindd_cm_conn *conn;
2028 NTSTATUS result;
2029
2030 uint32 neg_flags = NETLOGON_NEG_SELECT_AUTH2_FLAGS;
2031 uint8 mach_pwd[16];
2032 uint32 sec_chan_type;
2033 const char *account_name;
2034 struct rpc_pipe_client *netlogon_pipe = NULL;
2035
2036 *cli = NULL;
2037
2038 result = init_dc_connection(domain);
2039 if (!NT_STATUS_IS_OK(result)) {
2040 return result;
2041 }
2042
2043 conn = &domain->conn;
2044
2045 if (conn->netlogon_pipe != NULL) {
2046 *cli = conn->netlogon_pipe;
2047 return NT_STATUS_OK;
2048 }
2049
2050 netlogon_pipe = cli_rpc_pipe_open_noauth(conn->cli, PI_NETLOGON,
2051 &result);
2052 if (netlogon_pipe == NULL) {
2053 return result;
2054 }
2055
2056 if ((!IS_DC) && (!domain->primary)) {
2057 /* Clear the schannel request bit and drop down */
2058 neg_flags &= ~NETLOGON_NEG_SCHANNEL;
2059 goto no_schannel;
2060 }
2061
2062 if (lp_client_schannel() != False) {
2063 neg_flags |= NETLOGON_NEG_SCHANNEL;
2064 }
2065
2066 if (!get_trust_pw_hash(domain->name, mach_pwd, &account_name,
2067 &sec_chan_type))
2068 {
2069 cli_rpc_pipe_close(netlogon_pipe);
2070 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
2071 }
2072
2073 result = rpccli_netlogon_setup_creds(
2074 netlogon_pipe,
2075 domain->dcname, /* server name. */
2076 domain->name, /* domain name */
2077 global_myname(), /* client name */
2078 account_name, /* machine account */
2079 mach_pwd, /* machine password */
2080 sec_chan_type, /* from get_trust_pw */
2081 &neg_flags);
2082
2083 if (!NT_STATUS_IS_OK(result)) {
2084 cli_rpc_pipe_close(netlogon_pipe);
2085 return result;
2086 }
2087
2088 if ((lp_client_schannel() == True) &&
2089 ((neg_flags & NETLOGON_NEG_SCHANNEL) == 0)) {
2090 DEBUG(3, ("Server did not offer schannel\n"));
2091 cli_rpc_pipe_close(netlogon_pipe);
2092 return NT_STATUS_ACCESS_DENIED;
2093 }
2094
2095 no_schannel:
2096 if ((lp_client_schannel() == False) ||
2097 ((neg_flags & NETLOGON_NEG_SCHANNEL) == 0)) {
2098 /* We're done - just keep the existing connection to NETLOGON
2099 * open */
2100 conn->netlogon_pipe = netlogon_pipe;
2101 *cli = conn->netlogon_pipe;
2102 return NT_STATUS_OK;
2103 }
2104
2105 /* Using the credentials from the first pipe, open a signed and sealed
2106 second netlogon pipe. The session key is stored in the schannel
2107 part of the new pipe auth struct.
2108 */
2109
2110 conn->netlogon_pipe =
2111 cli_rpc_pipe_open_schannel_with_key(conn->cli,
2112 PI_NETLOGON,
2113 PIPE_AUTH_LEVEL_PRIVACY,
2114 domain->name,
2115 netlogon_pipe->dc,
2116 &result);
2117
2118 /* We can now close the initial netlogon pipe. */
2119 cli_rpc_pipe_close(netlogon_pipe);
2120
2121 if (conn->netlogon_pipe == NULL) {
2122 DEBUG(3, ("Could not open schannel'ed NETLOGON pipe. Error "
2123 "was %s\n", nt_errstr(result)));
2124
2125 /* make sure we return something besides OK */
2126 return !NT_STATUS_IS_OK(result) ? result : NT_STATUS_PIPE_NOT_AVAILABLE;
2127 }
2128
2129 *cli = conn->netlogon_pipe;
2130 return NT_STATUS_OK;
2131}
Note: See TracBrowser for help on using the repository browser.