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