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