r16945: Sync trunk -> 3.0 for 3.0.24 code. Still need
[tprouty/samba.git] / source / nsswitch / winbindd_cm.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    Winbind daemon connection manager
5
6    Copyright (C) Tim Potter                2001
7    Copyright (C) Andrew Bartlett           2002
8    Copyright (C) Gerald (Jerry) Carter     2003-2005.
9    Copyright (C) Volker Lendecke           2004-2005
10    
11    This program is free software; you can redistribute it and/or modify
12    it under the terms of the GNU General Public License as published by
13    the Free Software Foundation; either version 2 of the License, or
14    (at your option) any later version.
15    
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License for more details.
20    
21    You should have received a copy of the GNU General Public License
22    along with this program; if not, write to the Free Software
23    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
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
68 /* Choose between anonymous or authenticated connections.  We need to use
69    an authenticated connection if DCs have the RestrictAnonymous registry
70    entry set > 0, or the "Additional restrictions for anonymous
71    connections" set in the win2k Local Security Policy. 
72    
73    Caller to free() result in domain, username, password
74 */
75
76 static void cm_get_ipc_userpass(char **username, char **domain, char **password)
77 {
78         *username = secrets_fetch(SECRETS_AUTH_USER, NULL);
79         *domain = secrets_fetch(SECRETS_AUTH_DOMAIN, NULL);
80         *password = secrets_fetch(SECRETS_AUTH_PASSWORD, NULL);
81         
82         if (*username && **username) {
83
84                 if (!*domain || !**domain)
85                         *domain = smb_xstrdup(lp_workgroup());
86                 
87                 if (!*password || !**password)
88                         *password = smb_xstrdup("");
89
90                 DEBUG(3, ("cm_get_ipc_userpass: Retrieved auth-user from secrets.tdb [%s\\%s]\n", 
91                           *domain, *username));
92
93         } else {
94                 DEBUG(3, ("cm_get_ipc_userpass: No auth-user defined\n"));
95                 *username = smb_xstrdup("");
96                 *domain = smb_xstrdup("");
97                 *password = smb_xstrdup("");
98         }
99 }
100
101 static BOOL get_dc_name_via_netlogon(const struct winbindd_domain *domain,
102                                      fstring dcname, struct in_addr *dc_ip)
103 {
104         struct winbindd_domain *our_domain = NULL;
105         struct rpc_pipe_client *netlogon_pipe = NULL;
106         NTSTATUS result;
107         TALLOC_CTX *mem_ctx;
108
109         fstring tmp;
110         char *p;
111
112         /* Hmmmm. We can only open one connection to the NETLOGON pipe at the
113          * moment.... */
114
115         if (IS_DC) {
116                 return False;
117         }
118
119         if (domain->primary) {
120                 return False;
121         }
122
123         our_domain = find_our_domain();
124
125         if ((mem_ctx = talloc_init("get_dc_name_via_netlogon")) == NULL) {
126                 return False;
127         }
128
129         result = cm_connect_netlogon(our_domain, &netlogon_pipe);
130         if (!NT_STATUS_IS_OK(result)) {
131                 return False;
132         }
133
134         result = rpccli_netlogon_getdcname(netlogon_pipe, mem_ctx, our_domain->dcname,
135                                            domain->name, tmp);
136
137         talloc_destroy(mem_ctx);
138
139         if (!NT_STATUS_IS_OK(result)) {
140                 DEBUG(10, ("rpccli_netlogon_getdcname failed: %s\n",
141                            nt_errstr(result)));
142                 return False;
143         }
144
145         /* cli_netlogon_getdcname gives us a name with \\ */
146         p = tmp;
147         if (*p == '\\') {
148                 p+=1;
149         }
150         if (*p == '\\') {
151                 p+=1;
152         }
153
154         fstrcpy(dcname, p);
155
156         DEBUG(10, ("rpccli_netlogon_getdcname returned %s\n", dcname));
157
158         if (!resolve_name(dcname, dc_ip, 0x20)) {
159                 return False;
160         }
161
162         return True;
163 }
164
165 /************************************************************************
166  Given a fd with a just-connected TCP connection to a DC, open a connection
167  to the pipe.
168 ************************************************************************/
169
170 static NTSTATUS cm_prepare_connection(const struct winbindd_domain *domain,
171                                       const int sockfd,
172                                       const char *controller,
173                                       struct cli_state **cli,
174                                       BOOL *retry)
175 {
176         char *machine_password, *machine_krb5_principal, *machine_account;
177         char *ipc_username, *ipc_domain, *ipc_password;
178
179         BOOL got_mutex;
180
181         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
182
183         struct sockaddr peeraddr;
184         socklen_t peeraddr_len;
185
186         struct sockaddr_in *peeraddr_in = (struct sockaddr_in *)&peeraddr;
187
188         machine_password = secrets_fetch_machine_password(lp_workgroup(), NULL,
189                                                           NULL);
190         
191         if (asprintf(&machine_account, "%s$", global_myname()) == -1) {
192                 SAFE_FREE(machine_password);
193                 return NT_STATUS_NO_MEMORY;
194         }
195
196         if (asprintf(&machine_krb5_principal, "%s$@%s", global_myname(),
197                      lp_realm()) == -1) {
198                 SAFE_FREE(machine_account);
199                 SAFE_FREE(machine_password);
200                 return NT_STATUS_NO_MEMORY;
201         }
202
203         cm_get_ipc_userpass(&ipc_username, &ipc_domain, &ipc_password);
204
205         *retry = True;
206
207         got_mutex = secrets_named_mutex(controller,
208                                         WINBIND_SERVER_MUTEX_WAIT_TIME);
209
210         if (!got_mutex) {
211                 DEBUG(0,("cm_prepare_connection: mutex grab failed for %s\n",
212                          controller));
213                 result = NT_STATUS_POSSIBLE_DEADLOCK;
214                 goto done;
215         }
216
217         if ((*cli = cli_initialise()) == NULL) {
218                 DEBUG(1, ("Could not cli_initialize\n"));
219                 result = NT_STATUS_NO_MEMORY;
220                 goto done;
221         }
222
223         (*cli)->timeout = 10000;        /* 10 seconds */
224         (*cli)->fd = sockfd;
225         fstrcpy((*cli)->desthost, controller);
226         (*cli)->use_kerberos = True;
227
228         peeraddr_len = sizeof(peeraddr);
229
230         if ((getpeername((*cli)->fd, &peeraddr, &peeraddr_len) != 0) ||
231             (peeraddr_len != sizeof(struct sockaddr_in)) ||
232             (peeraddr_in->sin_family != PF_INET))
233         {
234                 DEBUG(0,("cm_prepare_connection: %s\n", strerror(errno)));
235                 result = NT_STATUS_UNSUCCESSFUL;
236                 goto done;
237         }
238
239         if (ntohs(peeraddr_in->sin_port) == 139) {
240                 struct nmb_name calling;
241                 struct nmb_name called;
242
243                 make_nmb_name(&calling, global_myname(), 0x0);
244                 make_nmb_name(&called, "*SMBSERVER", 0x20);
245
246                 if (!cli_session_request(*cli, &calling, &called)) {
247                         DEBUG(8, ("cli_session_request failed for %s\n",
248                                   controller));
249                         result = NT_STATUS_UNSUCCESSFUL;
250                         goto done;
251                 }
252         }
253
254         cli_setup_signing_state(*cli, Undefined);
255
256         if (!cli_negprot(*cli)) {
257                 DEBUG(1, ("cli_negprot failed\n"));
258                 result = NT_STATUS_UNSUCCESSFUL;
259                 goto done;
260         }
261                         
262         if ((*cli)->protocol >= PROTOCOL_NT1 && (*cli)->capabilities & CAP_EXTENDED_SECURITY) {
263                 ADS_STATUS ads_status;
264
265                 if (lp_security() == SEC_ADS) {
266
267                         /* Try a krb5 session */
268
269                         (*cli)->use_kerberos = True;
270                         DEBUG(5, ("connecting to %s from %s with kerberos principal "
271                                   "[%s]\n", controller, global_myname(),
272                                   machine_krb5_principal));
273
274                         ads_status = cli_session_setup_spnego(*cli,
275                                                               machine_krb5_principal, 
276                                                               machine_password, 
277                                                               lp_workgroup());
278
279                         if (!ADS_ERR_OK(ads_status)) {
280                                 DEBUG(4,("failed kerberos session setup with %s\n",
281                                          ads_errstr(ads_status)));
282                         }
283
284                         result = ads_ntstatus(ads_status);
285                         if (NT_STATUS_IS_OK(result)) {
286                                 /* Ensure creds are stored for NTLMSSP authenticated pipe access. */
287                                 cli_init_creds(*cli, machine_account, lp_workgroup(), machine_password);
288                                 goto session_setup_done;
289                         }
290                 }
291
292                 /* Fall back to non-kerberos session setup using NTLMSSP SPNEGO with the machine account. */
293                 (*cli)->use_kerberos = False;
294
295                 DEBUG(5, ("connecting to %s from %s with username "
296                           "[%s]\\[%s]\n",  controller, global_myname(),
297                           lp_workgroup(), machine_account));
298
299                 ads_status = cli_session_setup_spnego(*cli,
300                                                       machine_account, 
301                                                       machine_password, 
302                                                       lp_workgroup());
303                 if (!ADS_ERR_OK(ads_status)) {
304                         DEBUG(4, ("authenticated session setup failed with %s\n",
305                                 ads_errstr(ads_status)));
306                 }
307
308                 result = ads_ntstatus(ads_status);
309                 if (NT_STATUS_IS_OK(result)) {
310                         /* Ensure creds are stored for NTLMSSP authenticated pipe access. */
311                         cli_init_creds(*cli, machine_account, lp_workgroup(), machine_password);
312                         goto session_setup_done;
313                 }
314         }
315
316         /* Fall back to non-kerberos session setup */
317
318         (*cli)->use_kerberos = False;
319
320         if ((((*cli)->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) != 0) &&
321             (strlen(ipc_username) > 0)) {
322
323                 /* Only try authenticated if we have a username */
324
325                 DEBUG(5, ("connecting to %s from %s with username "
326                           "[%s]\\[%s]\n",  controller, global_myname(),
327                           ipc_domain, ipc_username));
328
329                 if (cli_session_setup(*cli, ipc_username,
330                                       ipc_password, strlen(ipc_password)+1,
331                                       ipc_password, strlen(ipc_password)+1,
332                                       ipc_domain)) {
333                         /* Successful logon with given username. */
334                         cli_init_creds(*cli, ipc_username, ipc_domain, ipc_password);
335                         goto session_setup_done;
336                 } else {
337                         DEBUG(4, ("authenticated session setup with user %s\\%s failed.\n",
338                                 ipc_domain, ipc_username ));
339                 }
340         }
341
342         /* Fall back to anonymous connection, this might fail later */
343
344         if (cli_session_setup(*cli, "", NULL, 0, NULL, 0, "")) {
345                 DEBUG(5, ("Connected anonymously\n"));
346                 cli_init_creds(*cli, "", "", "");
347                 goto session_setup_done;
348         }
349
350         result = cli_nt_error(*cli);
351
352         if (NT_STATUS_IS_OK(result))
353                 result = NT_STATUS_UNSUCCESSFUL;
354
355         /* We can't session setup */
356
357         goto done;
358
359  session_setup_done:
360
361         /* cache the server name for later connections */
362
363         saf_store( domain->name, (*cli)->desthost );
364
365         if (!cli_send_tconX(*cli, "IPC$", "IPC", "", 0)) {
366
367                 result = cli_nt_error(*cli);
368
369                 DEBUG(1,("failed tcon_X with %s\n", nt_errstr(result)));
370
371                 if (NT_STATUS_IS_OK(result))
372                         result = NT_STATUS_UNSUCCESSFUL;
373
374                 goto done;
375         }
376
377         secrets_named_mutex_release(controller);
378         got_mutex = False;
379         *retry = False;
380
381         /* set the domain if empty; needed for schannel connections */
382         if ( !*(*cli)->domain ) {
383                 fstrcpy( (*cli)->domain, domain->name );
384         }
385
386         result = NT_STATUS_OK;
387
388  done:
389         if (got_mutex) {
390                 secrets_named_mutex_release(controller);
391         }
392
393         SAFE_FREE(machine_account);
394         SAFE_FREE(machine_password);
395         SAFE_FREE(machine_krb5_principal);
396         SAFE_FREE(ipc_username);
397         SAFE_FREE(ipc_domain);
398         SAFE_FREE(ipc_password);
399
400         if (!NT_STATUS_IS_OK(result)) {
401                 add_failed_connection_entry(domain->name, controller, result);
402                 if ((*cli) != NULL) {
403                         cli_shutdown(*cli);
404                         *cli = NULL;
405                 }
406         }
407
408         return result;
409 }
410
411 struct dc_name_ip {
412         fstring name;
413         struct in_addr ip;
414 };
415
416 static BOOL add_one_dc_unique(TALLOC_CTX *mem_ctx, const char *domain_name,
417                               const char *dcname, struct in_addr ip,
418                               struct dc_name_ip **dcs, int *num)
419 {
420         if (!NT_STATUS_IS_OK(check_negative_conn_cache(domain_name, dcname))) {
421                 DEBUG(10, ("DC %s was in the negative conn cache\n", dcname));
422                 return False;
423         }
424
425         *dcs = TALLOC_REALLOC_ARRAY(mem_ctx, *dcs, struct dc_name_ip, (*num)+1);
426
427         if (*dcs == NULL)
428                 return False;
429
430         fstrcpy((*dcs)[*num].name, dcname);
431         (*dcs)[*num].ip = ip;
432         *num += 1;
433         return True;
434 }
435
436 static BOOL add_sockaddr_to_array(TALLOC_CTX *mem_ctx,
437                                   struct in_addr ip, uint16 port,
438                                   struct sockaddr_in **addrs, int *num)
439 {
440         *addrs = TALLOC_REALLOC_ARRAY(mem_ctx, *addrs, struct sockaddr_in, (*num)+1);
441
442         if (*addrs == NULL)
443                 return False;
444
445         (*addrs)[*num].sin_family = PF_INET;
446         putip((char *)&((*addrs)[*num].sin_addr), (char *)&ip);
447         (*addrs)[*num].sin_port = htons(port);
448
449         *num += 1;
450         return True;
451 }
452
453 static void mailslot_name(struct in_addr dc_ip, fstring name)
454 {
455         fstr_sprintf(name, "\\MAILSLOT\\NET\\GETDC%X", dc_ip.s_addr);
456 }
457
458 static BOOL send_getdc_request(struct in_addr dc_ip,
459                                const char *domain_name,
460                                const DOM_SID *sid)
461 {
462         pstring outbuf;
463         char *p;
464         fstring my_acct_name;
465         fstring my_mailslot;
466
467         mailslot_name(dc_ip, my_mailslot);
468
469         memset(outbuf, '\0', sizeof(outbuf));
470
471         p = outbuf;
472
473         SCVAL(p, 0, SAMLOGON);
474         p++;
475
476         SCVAL(p, 0, 0); /* Count pointer ... */
477         p++;
478
479         SIVAL(p, 0, 0); /* The sender's token ... */
480         p += 2;
481
482         p += dos_PutUniCode(p, global_myname(), sizeof(pstring), True);
483         fstr_sprintf(my_acct_name, "%s$", global_myname());
484         p += dos_PutUniCode(p, my_acct_name, sizeof(pstring), True);
485
486         memcpy(p, my_mailslot, strlen(my_mailslot)+1);
487         p += strlen(my_mailslot)+1;
488
489         SIVAL(p, 0, 0x80);
490         p+=4;
491
492         SIVAL(p, 0, sid_size(sid));
493         p+=4;
494
495         p = ALIGN4(p, outbuf);
496
497         sid_linearize(p, sid_size(sid), sid);
498         p += sid_size(sid);
499
500         SIVAL(p, 0, 1);
501         SSVAL(p, 4, 0xffff);
502         SSVAL(p, 6, 0xffff);
503         p+=8;
504
505         return cli_send_mailslot(False, "\\MAILSLOT\\NET\\NTLOGON", 0,
506                                  outbuf, PTR_DIFF(p, outbuf),
507                                  global_myname(), 0, domain_name, 0x1c,
508                                  dc_ip);
509 }
510
511 static BOOL receive_getdc_response(struct in_addr dc_ip,
512                                    const char *domain_name,
513                                    fstring dc_name)
514 {
515         struct packet_struct *packet;
516         fstring my_mailslot;
517         char *buf, *p;
518         fstring dcname, user, domain;
519         int len;
520
521         mailslot_name(dc_ip, my_mailslot);
522
523         packet = receive_unexpected(DGRAM_PACKET, 0, my_mailslot);
524
525         if (packet == NULL) {
526                 DEBUG(5, ("Did not receive packet for %s\n", my_mailslot));
527                 return False;
528         }
529
530         DEBUG(5, ("Received packet for %s\n", my_mailslot));
531
532         buf = packet->packet.dgram.data;
533         len = packet->packet.dgram.datasize;
534
535         if (len < 70) {
536                 /* 70 is a completely arbitrary value to make sure
537                    the SVAL below does not read uninitialized memory */
538                 DEBUG(3, ("GetDC got short response\n"));
539                 return False;
540         }
541
542         /* This should be (buf-4)+SVAL(buf-4, smb_vwv12)... */
543         p = buf+SVAL(buf, smb_vwv10);
544
545         if (CVAL(p,0) != SAMLOGON_R) {
546                 DEBUG(8, ("GetDC got invalid response type %d\n", CVAL(p, 0)));
547                 return False;
548         }
549
550         p+=2;
551         pull_ucs2(buf, dcname, p, sizeof(dcname), PTR_DIFF(buf+len, p),
552                   STR_TERMINATE|STR_NOALIGN);
553         p = skip_unibuf(p, PTR_DIFF(buf+len, p));
554         pull_ucs2(buf, user, p, sizeof(dcname), PTR_DIFF(buf+len, p),
555                   STR_TERMINATE|STR_NOALIGN);
556         p = skip_unibuf(p, PTR_DIFF(buf+len, p));
557         pull_ucs2(buf, domain, p, sizeof(dcname), PTR_DIFF(buf+len, p),
558                   STR_TERMINATE|STR_NOALIGN);
559         p = skip_unibuf(p, PTR_DIFF(buf+len, p));
560
561         if (!strequal(domain, domain_name)) {
562                 DEBUG(3, ("GetDC: Expected domain %s, got %s\n",
563                           domain_name, domain));
564                 return False;
565         }
566
567         p = dcname;
568         if (*p == '\\') p += 1;
569         if (*p == '\\') p += 1;
570
571         fstrcpy(dc_name, p);
572
573         DEBUG(10, ("GetDC gave name %s for domain %s\n",
574                    dc_name, domain));
575
576         return True;
577 }
578
579 /*******************************************************************
580  convert an ip to a name
581 *******************************************************************/
582
583 static BOOL dcip_to_name( const char *domainname, const char *realm, 
584                           const DOM_SID *sid, struct in_addr ip, fstring name )
585 {
586         struct ip_service ip_list;
587
588         ip_list.ip = ip;
589         ip_list.port = 0;
590
591         /* try GETDC requests first */
592         
593         if (send_getdc_request(ip, domainname, sid)) {
594                 int i;
595                 smb_msleep(100);
596                 for (i=0; i<5; i++) {
597                         if (receive_getdc_response(ip, domainname, name)) {
598                                 namecache_store(name, 0x20, 1, &ip_list);
599                                 return True;
600                         }
601                         smb_msleep(500);
602                 }
603         }
604
605         /* try node status request */
606
607         if ( name_status_find(domainname, 0x1c, 0x20, ip, name) ) {
608                 namecache_store(name, 0x20, 1, &ip_list);
609                 return True;
610         }
611
612 #ifdef WITH_ADS
613         /* for active directory servers, try to get the ldap server name.
614            None of these failure should be considered critical for now */
615
616         if ( lp_security() == SEC_ADS ) 
617         {
618                 ADS_STRUCT *ads;
619
620                 ads = ads_init( realm, domainname, NULL );
621                 ads->auth.flags |= ADS_AUTH_NO_BIND;
622
623                 if ( !ads_try_connect( ads, inet_ntoa(ip) ) )  {
624                         ads_destroy( &ads );
625                         return False;
626                 }
627
628                 fstrcpy(name, ads->config.ldap_server_name);
629                 namecache_store(name, 0x20, 1, &ip_list);
630
631                 ads_destroy( &ads );
632                 return True;
633         }
634 #endif
635
636         return False;
637 }
638
639 /*******************************************************************
640  Retreive a list of IP address for domain controllers.  Fill in 
641  the dcs[]  with results.
642 *******************************************************************/
643
644 static BOOL get_dcs(TALLOC_CTX *mem_ctx, const struct winbindd_domain *domain,
645                     struct dc_name_ip **dcs, int *num_dcs)
646 {
647         fstring dcname;
648         struct  in_addr ip;
649         struct  ip_service *ip_list = NULL;
650         int     iplist_size = 0;
651         int     i;
652         BOOL    is_our_domain;
653
654
655         is_our_domain = strequal(domain->name, lp_workgroup());
656
657         if ( !is_our_domain 
658                 && get_dc_name_via_netlogon(domain, dcname, &ip) 
659                 && add_one_dc_unique(mem_ctx, domain->name, dcname, ip, dcs, num_dcs) )
660         {
661                 DEBUG(10, ("Retrieved DC %s at %s via netlogon\n",
662                            dcname, inet_ntoa(ip)));
663                 return True;
664         }
665
666         /* try standard netbios queries first */
667
668         get_sorted_dc_list(domain->name, &ip_list, &iplist_size, False);
669
670         /* check for security = ads and use DNS if we can */
671
672         if ( iplist_size==0 && lp_security() == SEC_ADS ) 
673                 get_sorted_dc_list(domain->alt_name, &ip_list, &iplist_size, True);
674
675         /* FIXME!! this is where we should re-insert the GETDC requests --jerry */
676
677         /* now add to the dc array.  We'll wait until the last minute 
678            to look up the name of the DC.  But we fill in the char* for 
679            the ip now in to make the failed connection cache work */
680
681         for ( i=0; i<iplist_size; i++ ) {
682                 add_one_dc_unique(mem_ctx, domain->name, inet_ntoa(ip_list[i].ip), 
683                         ip_list[i].ip, dcs, num_dcs);
684         }
685
686         SAFE_FREE( ip_list );
687
688         return True;
689 }
690
691 static BOOL find_new_dc(TALLOC_CTX *mem_ctx,
692                         const struct winbindd_domain *domain,
693                         fstring dcname, struct sockaddr_in *addr, int *fd)
694 {
695         struct dc_name_ip *dcs = NULL;
696         int num_dcs = 0;
697
698         const char **dcnames = NULL;
699         int num_dcnames = 0;
700
701         struct sockaddr_in *addrs = NULL;
702         int num_addrs = 0;
703
704         int i, fd_index;
705
706  again:
707         if (!get_dcs(mem_ctx, domain, &dcs, &num_dcs) || (num_dcs == 0))
708                 return False;
709
710         for (i=0; i<num_dcs; i++) {
711
712                 add_string_to_array(mem_ctx, dcs[i].name,
713                                     &dcnames, &num_dcnames);
714                 add_sockaddr_to_array(mem_ctx, dcs[i].ip, 445,
715                                       &addrs, &num_addrs);
716
717                 add_string_to_array(mem_ctx, dcs[i].name,
718                                     &dcnames, &num_dcnames);
719                 add_sockaddr_to_array(mem_ctx, dcs[i].ip, 139,
720                                       &addrs, &num_addrs);
721         }
722
723         if ((num_dcnames == 0) || (num_dcnames != num_addrs))
724                 return False;
725
726         if ((addrs == NULL) || (dcnames == NULL))
727                 return False;
728
729         if ( !open_any_socket_out(addrs, num_addrs, 10000, &fd_index, fd) ) 
730         {
731                 for (i=0; i<num_dcs; i++) {
732                         add_failed_connection_entry(domain->name,
733                                 dcs[i].name, NT_STATUS_UNSUCCESSFUL);
734                 }
735                 return False;
736         }
737
738         *addr = addrs[fd_index];
739
740         if (*dcnames[fd_index] != '\0' && !is_ipaddress(dcnames[fd_index])) {
741                 /* Ok, we've got a name for the DC */
742                 fstrcpy(dcname, dcnames[fd_index]);
743                 return True;
744         }
745
746         /* Try to figure out the name */
747         if (dcip_to_name( domain->name, domain->alt_name, &domain->sid,
748                           addr->sin_addr, dcname )) {
749                 return True;
750         }
751
752         /* We can not continue without the DC's name */
753         add_failed_connection_entry(domain->name, dcs[fd_index].name,
754                                     NT_STATUS_UNSUCCESSFUL);
755         goto again;
756 }
757
758 static NTSTATUS cm_open_connection(struct winbindd_domain *domain,
759                                    struct winbindd_cm_conn *new_conn)
760 {
761         TALLOC_CTX *mem_ctx;
762         NTSTATUS result;
763         char *saf_servername = saf_fetch( domain->name );
764         int retries;
765
766         if ((mem_ctx = talloc_init("cm_open_connection")) == NULL)
767                 return NT_STATUS_NO_MEMORY;
768
769         /* we have to check the server affinity cache here since 
770            later we selecte a DC based on response time and not preference */
771            
772         if ( saf_servername ) 
773         {
774                 /* convert an ip address to a name */
775                 if ( is_ipaddress( saf_servername ) )
776                 {
777                         fstring saf_name;
778                         struct in_addr ip;
779
780                         ip = *interpret_addr2( saf_servername );
781                         if (dcip_to_name( domain->name, domain->alt_name,
782                                           &domain->sid, ip, saf_name )) {
783                                 fstrcpy( domain->dcname, saf_name );
784                         } else {
785                                 add_failed_connection_entry(
786                                         domain->name, saf_servername,
787                                         NT_STATUS_UNSUCCESSFUL);
788                         }
789                 } 
790                 else 
791                 {
792                         fstrcpy( domain->dcname, saf_servername );
793                 }
794
795                 SAFE_FREE( saf_servername );
796         }
797
798         for (retries = 0; retries < 3; retries++) {
799
800                 int fd = -1;
801                 BOOL retry = False;
802
803                 result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
804
805                 if ((strlen(domain->dcname) > 0)
806                         && NT_STATUS_IS_OK(check_negative_conn_cache( domain->name, domain->dcname))
807                         && (resolve_name(domain->dcname, &domain->dcaddr.sin_addr, 0x20)))
808                 {
809                         struct sockaddr_in *addrs = NULL;
810                         int num_addrs = 0;
811                         int dummy = 0;
812
813                         add_sockaddr_to_array(mem_ctx, domain->dcaddr.sin_addr, 445, &addrs, &num_addrs);
814                         add_sockaddr_to_array(mem_ctx, domain->dcaddr.sin_addr, 139, &addrs, &num_addrs);
815
816                         if (!open_any_socket_out(addrs, num_addrs, 10000, &dummy, &fd)) {
817                                 domain->online = False;
818                                 fd = -1;
819                         }
820                 }
821
822                 if ((fd == -1) 
823                         && !find_new_dc(mem_ctx, domain, domain->dcname, &domain->dcaddr, &fd))
824                 {
825                         /* This is the one place where we will
826                            set the global winbindd offline state
827                            to true, if a "WINBINDD_OFFLINE" entry
828                            is found in the winbindd cache. */
829                         set_global_winbindd_state_offline();
830                         domain->online = False;
831                         break;
832                 }
833
834                 new_conn->cli = NULL;
835
836                 result = cm_prepare_connection(domain, fd, domain->dcname,
837                         &new_conn->cli, &retry);
838
839                 if (!retry)
840                         break;
841         }
842
843         if (NT_STATUS_IS_OK(result)) {
844                 if (domain->online == False) {
845                         /* We're changing state from offline to online. */
846                         set_global_winbindd_state_online();
847                 }
848                 domain->online = True;
849         }
850
851         talloc_destroy(mem_ctx);
852         return result;
853 }
854
855 /* Close down all open pipes on a connection. */
856
857 void invalidate_cm_connection(struct winbindd_cm_conn *conn)
858 {
859         if (conn->samr_pipe != NULL) {
860                 cli_rpc_pipe_close(conn->samr_pipe);
861                 conn->samr_pipe = NULL;
862         }
863
864         if (conn->lsa_pipe != NULL) {
865                 cli_rpc_pipe_close(conn->lsa_pipe);
866                 conn->lsa_pipe = NULL;
867         }
868
869         if (conn->netlogon_pipe != NULL) {
870                 cli_rpc_pipe_close(conn->netlogon_pipe);
871                 conn->netlogon_pipe = NULL;
872         }
873
874         if (conn->cli) {
875                 cli_shutdown(conn->cli);
876         }
877
878         conn->cli = NULL;
879 }
880
881 void close_conns_after_fork(void)
882 {
883         struct winbindd_domain *domain;
884
885         for (domain = domain_list(); domain; domain = domain->next) {
886                 if (domain->conn.cli == NULL)
887                         continue;
888
889                 if (domain->conn.cli->fd == -1)
890                         continue;
891
892                 close(domain->conn.cli->fd);
893                 domain->conn.cli->fd = -1;
894         }
895 }
896
897 static BOOL connection_ok(struct winbindd_domain *domain)
898 {
899         if (domain->conn.cli == NULL) {
900                 DEBUG(8, ("Connection to %s for domain %s has NULL "
901                           "cli!\n", domain->dcname, domain->name));
902                 return False;
903         }
904
905         if (!domain->conn.cli->initialised) {
906                 DEBUG(3, ("Connection to %s for domain %s was never "
907                           "initialised!\n", domain->dcname, domain->name));
908                 return False;
909         }
910
911         if (domain->conn.cli->fd == -1) {
912                 DEBUG(3, ("Connection to %s for domain %s has died or was "
913                           "never started (fd == -1)\n", 
914                           domain->dcname, domain->name));
915                 return False;
916         }
917
918         return True;
919 }
920         
921 /* Initialize a new connection up to the RPC BIND. */
922
923 static NTSTATUS init_dc_connection(struct winbindd_domain *domain)
924 {
925         if (connection_ok(domain))
926                 return NT_STATUS_OK;
927
928         invalidate_cm_connection(&domain->conn);
929
930         return cm_open_connection(domain, &domain->conn);
931 }
932
933 /******************************************************************************
934  We can 'sense' certain things about the DC by it's replies to certain
935  questions.
936
937  This tells us if this particular remote server is Active Directory, and if it
938  is native mode.
939 ******************************************************************************/
940
941 void set_dc_type_and_flags( struct winbindd_domain *domain )
942 {
943         NTSTATUS                result;
944         DS_DOMINFO_CTR          ctr;
945         TALLOC_CTX              *mem_ctx = NULL;
946         struct rpc_pipe_client  *cli;
947         POLICY_HND pol;
948         
949         char *domain_name = NULL;
950         char *dns_name = NULL;
951         DOM_SID *dom_sid = NULL;
952
953         ZERO_STRUCT( ctr );
954         
955         domain->native_mode = False;
956         domain->active_directory = False;
957
958         if (domain->internal) {
959                 domain->initialized = True;
960                 return;
961         }
962
963         result = init_dc_connection(domain);
964         if (!NT_STATUS_IS_OK(result)) {
965                 DEBUG(5, ("set_dc_type_and_flags: Could not open a connection "
966                           "to %s: (%s)\n", domain->name, nt_errstr(result)));
967                 domain->initialized = True;
968                 return;
969         }
970
971         cli = cli_rpc_pipe_open_noauth(domain->conn.cli, PI_LSARPC_DS,
972                                        &result);
973
974         if (cli == NULL) {
975                 DEBUG(5, ("set_dc_type_and_flags: Could not bind to "
976                           "PI_LSARPC_DS on domain %s: (%s)\n",
977                           domain->name, nt_errstr(result)));
978                 domain->initialized = True;
979                 return;
980         }
981
982         result = rpccli_ds_getprimarydominfo(cli, cli->cli->mem_ctx,
983                                              DsRolePrimaryDomainInfoBasic,
984                                              &ctr);
985         cli_rpc_pipe_close(cli);
986
987         if (!NT_STATUS_IS_OK(result)) {
988                 domain->initialized = True;
989                 return;
990         }
991         
992         if ((ctr.basic->flags & DSROLE_PRIMARY_DS_RUNNING) &&
993             !(ctr.basic->flags & DSROLE_PRIMARY_DS_MIXED_MODE) )
994                 domain->native_mode = True;
995
996         cli = cli_rpc_pipe_open_noauth(domain->conn.cli, PI_LSARPC, &result);
997
998         if (cli == NULL) {
999                 domain->initialized = True;
1000                 return;
1001         }
1002
1003         mem_ctx = talloc_init("set_dc_type_and_flags on domain %s\n",
1004                               domain->name);
1005         if (!mem_ctx) {
1006                 DEBUG(1, ("set_dc_type_and_flags: talloc_init() failed\n"));
1007                 cli_rpc_pipe_close(cli);
1008                 return;
1009         }
1010
1011         result = rpccli_lsa_open_policy2(cli, mem_ctx, True, 
1012                                          SEC_RIGHTS_MAXIMUM_ALLOWED, &pol);
1013                 
1014         if (NT_STATUS_IS_OK(result)) {
1015                 /* This particular query is exactly what Win2k clients use 
1016                    to determine that the DC is active directory */
1017                 result = rpccli_lsa_query_info_policy2(cli, mem_ctx, &pol,
1018                                                        12, &domain_name,
1019                                                        &dns_name, NULL,
1020                                                        NULL, &dom_sid);
1021         }
1022
1023         if (NT_STATUS_IS_OK(result)) {
1024                 if (domain_name)
1025                         fstrcpy(domain->name, domain_name);
1026
1027                 if (dns_name)
1028                         fstrcpy(domain->alt_name, dns_name);
1029
1030                 if (dom_sid) 
1031                         sid_copy(&domain->sid, dom_sid);
1032
1033                 domain->active_directory = True;
1034         } else {
1035                 
1036                 result = rpccli_lsa_open_policy(cli, mem_ctx, True, 
1037                                                 SEC_RIGHTS_MAXIMUM_ALLOWED,
1038                                                 &pol);
1039                         
1040                 if (!NT_STATUS_IS_OK(result))
1041                         goto done;
1042                         
1043                 result = rpccli_lsa_query_info_policy(cli, mem_ctx, 
1044                                                       &pol, 5, &domain_name, 
1045                                                       &dom_sid);
1046                         
1047                 if (NT_STATUS_IS_OK(result)) {
1048                         if (domain_name)
1049                                 fstrcpy(domain->name, domain_name);
1050
1051                         if (dom_sid) 
1052                                 sid_copy(&domain->sid, dom_sid);
1053                 }
1054         }
1055 done:
1056
1057         cli_rpc_pipe_close(cli);
1058         
1059         talloc_destroy(mem_ctx);
1060
1061         domain->initialized = True;
1062         
1063         return;
1064 }
1065
1066 static BOOL cm_get_schannel_dcinfo(struct winbindd_domain *domain,
1067                                    struct dcinfo **ppdc)
1068 {
1069         NTSTATUS result;
1070         struct rpc_pipe_client *netlogon_pipe;
1071
1072         if (lp_client_schannel() == False) {
1073                 return False;
1074         }
1075
1076         result = cm_connect_netlogon(domain, &netlogon_pipe);
1077         if (!NT_STATUS_IS_OK(result)) {
1078                 return False;
1079         }
1080
1081         /* Return a pointer to the struct dcinfo from the
1082            netlogon pipe. */
1083
1084         *ppdc = domain->conn.netlogon_pipe->dc;
1085         return True;
1086 }
1087
1088 NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
1089                         struct rpc_pipe_client **cli, POLICY_HND *sam_handle)
1090 {
1091         struct winbindd_cm_conn *conn;
1092         NTSTATUS result;
1093         fstring conn_pwd;
1094         struct dcinfo *p_dcinfo;
1095
1096         result = init_dc_connection(domain);
1097         if (!NT_STATUS_IS_OK(result)) {
1098                 return result;
1099         }
1100
1101         conn = &domain->conn;
1102
1103         if (conn->samr_pipe != NULL) {
1104                 goto done;
1105         }
1106
1107         /*
1108          * No SAMR pipe yet. Attempt to get an NTLMSSP SPNEGO authenticated
1109          * sign and sealed pipe using the machine account password by
1110          * preference. If we can't - try schannel, if that fails, try
1111          * anonymous.
1112          */
1113
1114         pwd_get_cleartext(&conn->cli->pwd, conn_pwd);
1115         if ((conn->cli->user_name[0] == '\0') ||
1116             (conn->cli->domain[0] == '\0') || 
1117             (conn_pwd[0] == '\0')) {
1118                 DEBUG(10, ("cm_connect_sam: No no user available for "
1119                            "domain %s, trying schannel\n", conn->cli->domain));
1120                 goto schannel;
1121         }
1122
1123         /* We have an authenticated connection. Use a NTLMSSP SPNEGO
1124            authenticated SAMR pipe with sign & seal. */
1125         conn->samr_pipe =
1126                 cli_rpc_pipe_open_spnego_ntlmssp(conn->cli, PI_SAMR,
1127                                                  PIPE_AUTH_LEVEL_PRIVACY,
1128                                                  conn->cli->domain,
1129                                                  conn->cli->user_name,
1130                                                  conn_pwd, &result);
1131
1132         if (conn->samr_pipe == NULL) {
1133                 DEBUG(10,("cm_connect_sam: failed to connect to SAMR "
1134                           "pipe for domain %s using NTLMSSP "
1135                           "authenticated pipe: user %s\\%s. Error was "
1136                           "%s\n", domain->name, conn->cli->domain,
1137                           conn->cli->user_name, nt_errstr(result)));
1138                 goto schannel;
1139         }
1140
1141         DEBUG(10,("cm_connect_sam: connected to SAMR pipe for "
1142                   "domain %s using NTLMSSP authenticated "
1143                   "pipe: user %s\\%s\n", domain->name,
1144                   conn->cli->domain, conn->cli->user_name ));
1145
1146         result = rpccli_samr_connect(conn->samr_pipe, mem_ctx,
1147                                      SEC_RIGHTS_MAXIMUM_ALLOWED,
1148                                      &conn->sam_connect_handle);
1149         if (NT_STATUS_IS_OK(result)) {
1150                 goto open_domain;
1151         }
1152         DEBUG(10,("cm_connect_sam: ntlmssp-sealed rpccli_samr_connect "
1153                   "failed for domain %s, error was %s. Trying schannel\n",
1154                   domain->name, nt_errstr(result) ));
1155         cli_rpc_pipe_close(conn->samr_pipe);
1156
1157  schannel:
1158
1159         /* Fall back to schannel if it's a W2K pre-SP1 box. */
1160
1161         if (!cm_get_schannel_dcinfo(domain, &p_dcinfo)) {
1162                 DEBUG(10, ("cm_connect_sam: Could not get schannel auth info "
1163                            "for domain %s, trying anon\n", conn->cli->domain));
1164                 goto anonymous;
1165         }
1166         conn->samr_pipe = cli_rpc_pipe_open_schannel_with_key
1167                 (conn->cli, PI_SAMR, PIPE_AUTH_LEVEL_PRIVACY,
1168                  domain->name, p_dcinfo, &result);
1169
1170         if (conn->samr_pipe == NULL) {
1171                 DEBUG(10,("cm_connect_sam: failed to connect to SAMR pipe for "
1172                           "domain %s using schannel. Error was %s\n",
1173                           domain->name, nt_errstr(result) ));
1174                 goto anonymous;
1175         }
1176         DEBUG(10,("cm_connect_sam: connected to SAMR pipe for domain %s using "
1177                   "schannel.\n", domain->name ));
1178
1179         result = rpccli_samr_connect(conn->samr_pipe, mem_ctx,
1180                                      SEC_RIGHTS_MAXIMUM_ALLOWED,
1181                                      &conn->sam_connect_handle);
1182         if (NT_STATUS_IS_OK(result)) {
1183                 goto open_domain;
1184         }
1185         DEBUG(10,("cm_connect_sam: schannel-sealed rpccli_samr_connect failed "
1186                   "for domain %s, error was %s. Trying anonymous\n",
1187                   domain->name, nt_errstr(result) ));
1188         cli_rpc_pipe_close(conn->samr_pipe);
1189
1190  anonymous:
1191
1192         /* Finally fall back to anonymous. */
1193         conn->samr_pipe = cli_rpc_pipe_open_noauth(conn->cli, PI_SAMR,
1194                                                    &result);
1195
1196         if (conn->samr_pipe == NULL) {
1197                 result = NT_STATUS_PIPE_NOT_AVAILABLE;
1198                 goto done;
1199         }
1200
1201         result = rpccli_samr_connect(conn->samr_pipe, mem_ctx,
1202                                      SEC_RIGHTS_MAXIMUM_ALLOWED,
1203                                      &conn->sam_connect_handle);
1204         if (!NT_STATUS_IS_OK(result)) {
1205                 DEBUG(10,("cm_connect_sam: rpccli_samr_connect failed "
1206                           "for domain %s Error was %s\n",
1207                           domain->name, nt_errstr(result) ));
1208                 goto done;
1209         }
1210
1211  open_domain:
1212         result = rpccli_samr_open_domain(conn->samr_pipe,
1213                                          mem_ctx,
1214                                          &conn->sam_connect_handle,
1215                                          SEC_RIGHTS_MAXIMUM_ALLOWED,
1216                                          &domain->sid,
1217                                          &conn->sam_domain_handle);
1218
1219  done:
1220
1221         if (!NT_STATUS_IS_OK(result)) {
1222                 invalidate_cm_connection(conn);
1223                 return result;
1224         }
1225
1226         *cli = conn->samr_pipe;
1227         *sam_handle = conn->sam_domain_handle;
1228         return result;
1229 }
1230
1231 NTSTATUS cm_connect_lsa(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
1232                         struct rpc_pipe_client **cli, POLICY_HND *lsa_policy)
1233 {
1234         struct winbindd_cm_conn *conn;
1235         NTSTATUS result;
1236         fstring conn_pwd;
1237         struct dcinfo *p_dcinfo;
1238
1239         result = init_dc_connection(domain);
1240         if (!NT_STATUS_IS_OK(result))
1241                 return result;
1242
1243         conn = &domain->conn;
1244
1245         if (conn->lsa_pipe != NULL) {
1246                 goto done;
1247         }
1248
1249         pwd_get_cleartext(&conn->cli->pwd, conn_pwd);
1250         if ((conn->cli->user_name[0] == '\0') ||
1251             (conn->cli->domain[0] == '\0') || 
1252             (conn_pwd[0] == '\0')) {
1253                 DEBUG(10, ("cm_connect_lsa: No no user available for "
1254                            "domain %s, trying schannel\n", conn->cli->domain));
1255                 goto schannel;
1256         }
1257
1258         /* We have an authenticated connection. Use a NTLMSSP SPNEGO
1259          * authenticated LSA pipe with sign & seal. */
1260         conn->lsa_pipe = cli_rpc_pipe_open_spnego_ntlmssp
1261                 (conn->cli, PI_LSARPC, PIPE_AUTH_LEVEL_PRIVACY,
1262                  conn->cli->domain, conn->cli->user_name, conn_pwd, &result);
1263
1264         if (conn->lsa_pipe == NULL) {
1265                 DEBUG(10,("cm_connect_lsa: failed to connect to LSA pipe for "
1266                           "domain %s using NTLMSSP authenticated pipe: user "
1267                           "%s\\%s. Error was %s. Trying schannel.\n",
1268                           domain->name, conn->cli->domain,
1269                           conn->cli->user_name, nt_errstr(result)));
1270                 goto schannel;
1271         }
1272
1273         DEBUG(10,("cm_connect_lsa: connected to LSA pipe for domain %s using "
1274                   "NTLMSSP authenticated pipe: user %s\\%s\n",
1275                   domain->name, conn->cli->domain, conn->cli->user_name ));
1276
1277         result = rpccli_lsa_open_policy(conn->lsa_pipe, mem_ctx, True,
1278                                         SEC_RIGHTS_MAXIMUM_ALLOWED,
1279                                         &conn->lsa_policy);
1280         if (NT_STATUS_IS_OK(result)) {
1281                 goto done;
1282         }
1283
1284         DEBUG(10,("cm_connect_lsa: rpccli_lsa_open_policy failed, trying "
1285                   "schannel\n"));
1286
1287         cli_rpc_pipe_close(conn->lsa_pipe);
1288
1289  schannel:
1290
1291         /* Fall back to schannel if it's a W2K pre-SP1 box. */
1292
1293         if (!cm_get_schannel_dcinfo(domain, &p_dcinfo)) {
1294                 DEBUG(10, ("cm_connect_lsa: Could not get schannel auth info "
1295                            "for domain %s, trying anon\n", conn->cli->domain));
1296                 goto anonymous;
1297         }
1298         conn->lsa_pipe = cli_rpc_pipe_open_schannel_with_key
1299                 (conn->cli, PI_LSARPC, PIPE_AUTH_LEVEL_PRIVACY,
1300                  domain->name, p_dcinfo, &result);
1301
1302         if (conn->lsa_pipe == NULL) {
1303                 DEBUG(10,("cm_connect_lsa: failed to connect to LSA pipe for "
1304                           "domain %s using schannel. Error was %s\n",
1305                           domain->name, nt_errstr(result) ));
1306                 goto anonymous;
1307         }
1308         DEBUG(10,("cm_connect_lsa: connected to LSA pipe for domain %s using "
1309                   "schannel.\n", domain->name ));
1310
1311         result = rpccli_lsa_open_policy(conn->lsa_pipe, mem_ctx, True,
1312                                         SEC_RIGHTS_MAXIMUM_ALLOWED,
1313                                         &conn->lsa_policy);
1314         if (NT_STATUS_IS_OK(result)) {
1315                 goto done;
1316         }
1317
1318         DEBUG(10,("cm_connect_lsa: rpccli_lsa_open_policy failed, trying "
1319                   "anonymous\n"));
1320
1321         cli_rpc_pipe_close(conn->lsa_pipe);
1322
1323  anonymous:
1324
1325         conn->lsa_pipe = cli_rpc_pipe_open_noauth(conn->cli, PI_LSARPC,
1326                                                   &result);
1327         if (conn->lsa_pipe == NULL) {
1328                 result = NT_STATUS_PIPE_NOT_AVAILABLE;
1329                 goto done;
1330         }
1331
1332         result = rpccli_lsa_open_policy(conn->lsa_pipe, mem_ctx, True,
1333                                         SEC_RIGHTS_MAXIMUM_ALLOWED,
1334                                         &conn->lsa_policy);
1335  done:
1336         if (!NT_STATUS_IS_OK(result)) {
1337                 invalidate_cm_connection(conn);
1338                 return NT_STATUS_UNSUCCESSFUL;
1339         }
1340
1341         *cli = conn->lsa_pipe;
1342         *lsa_policy = conn->lsa_policy;
1343         return result;
1344 }
1345
1346 /****************************************************************************
1347  Open the netlogon pipe to this DC. Use schannel if specified in client conf.
1348  session key stored in conn->netlogon_pipe->dc->sess_key.
1349 ****************************************************************************/
1350
1351 NTSTATUS cm_connect_netlogon(struct winbindd_domain *domain,
1352                              struct rpc_pipe_client **cli)
1353 {
1354         struct winbindd_cm_conn *conn;
1355         NTSTATUS result;
1356
1357         uint32 neg_flags = NETLOGON_NEG_AUTH2_FLAGS;
1358         uint8  mach_pwd[16];
1359         uint32  sec_chan_type;
1360         const char *account_name;
1361         struct rpc_pipe_client *netlogon_pipe = NULL;
1362
1363         *cli = NULL;
1364
1365         result = init_dc_connection(domain);
1366         if (!NT_STATUS_IS_OK(result)) {
1367                 return result;
1368         }
1369
1370         conn = &domain->conn;
1371
1372         if (conn->netlogon_pipe != NULL) {
1373                 *cli = conn->netlogon_pipe;
1374                 return NT_STATUS_OK;
1375         }
1376
1377         if (!get_trust_pw(domain->name, mach_pwd, &sec_chan_type)) {
1378                 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1379         }
1380
1381         netlogon_pipe = cli_rpc_pipe_open_noauth(conn->cli, PI_NETLOGON,
1382                                                  &result);
1383         if (netlogon_pipe == NULL) {
1384                 return result;
1385         }
1386
1387         if (lp_client_schannel() != False) {
1388                 neg_flags |= NETLOGON_NEG_SCHANNEL;
1389         }
1390
1391         /* if we are a DC and this is a trusted domain, then we need to use our
1392            domain name in the net_req_auth2() request */
1393
1394         if ( IS_DC
1395                 && !strequal(domain->name, lp_workgroup())
1396                 && lp_allow_trusted_domains() ) 
1397         {
1398                 account_name = lp_workgroup();
1399         } else {
1400                 account_name = domain->primary ?
1401                         global_myname() : domain->name;
1402         }
1403
1404         if (account_name == NULL) {
1405                 cli_rpc_pipe_close(netlogon_pipe);
1406                 return NT_STATUS_NO_MEMORY;
1407         }
1408
1409         result = rpccli_netlogon_setup_creds(
1410                  netlogon_pipe,
1411                  domain->dcname, /* server name. */
1412                  domain->name,   /* domain name */
1413                  global_myname(), /* client name */
1414                  account_name,   /* machine account */
1415                  mach_pwd,       /* machine password */
1416                  sec_chan_type,  /* from get_trust_pw */
1417                  &neg_flags);
1418
1419         if (!NT_STATUS_IS_OK(result)) {
1420                 cli_rpc_pipe_close(netlogon_pipe);
1421                 return result;
1422         }
1423
1424         if ((lp_client_schannel() == True) &&
1425                         ((neg_flags & NETLOGON_NEG_SCHANNEL) == 0)) {
1426                 DEBUG(3, ("Server did not offer schannel\n"));
1427                 cli_rpc_pipe_close(netlogon_pipe);
1428                 return NT_STATUS_ACCESS_DENIED;
1429         }
1430
1431         if ((lp_client_schannel() == False) ||
1432                         ((neg_flags & NETLOGON_NEG_SCHANNEL) == 0)) {
1433                 /* We're done - just keep the existing connection to NETLOGON
1434                  * open */
1435                 conn->netlogon_pipe = netlogon_pipe;
1436                 *cli = conn->netlogon_pipe;
1437                 return NT_STATUS_OK;
1438         }
1439
1440         /* Using the credentials from the first pipe, open a signed and sealed
1441            second netlogon pipe. The session key is stored in the schannel
1442            part of the new pipe auth struct.
1443         */
1444
1445         conn->netlogon_pipe =
1446                 cli_rpc_pipe_open_schannel_with_key(conn->cli,
1447                                                     PI_NETLOGON,
1448                                                     PIPE_AUTH_LEVEL_PRIVACY,
1449                                                     domain->name,
1450                                                     netlogon_pipe->dc,
1451                                                     &result);
1452
1453         /* We can now close the initial netlogon pipe. */
1454         cli_rpc_pipe_close(netlogon_pipe);
1455
1456         if (conn->netlogon_pipe == NULL) {
1457                 DEBUG(3, ("Could not open schannel'ed NETLOGON pipe. Error "
1458                           "was %s\n", nt_errstr(result)));
1459                           
1460                 /* make sure we return something besides OK */
1461                 return !NT_STATUS_IS_OK(result) ? result : NT_STATUS_PIPE_NOT_AVAILABLE;
1462         }
1463
1464         *cli = conn->netlogon_pipe;
1465         return NT_STATUS_OK;
1466 }