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