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