r17571: Change the return code of cli_session_setup from BOOL to NTSTATUS
[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 = (char *)secrets_fetch(SECRETS_AUTH_USER, NULL);
79         *domain = (char *)secrets_fetch(SECRETS_AUTH_DOMAIN, NULL);
80         *password = (char *)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 (NT_STATUS_IS_OK(cli_session_setup(
330                                             *cli, ipc_username,
331                                             ipc_password, strlen(ipc_password)+1,
332                                             ipc_password, strlen(ipc_password)+1,
333                                             ipc_domain))) {
334                         /* Successful logon with given username. */
335                         cli_init_creds(*cli, ipc_username, ipc_domain, ipc_password);
336                         goto session_setup_done;
337                 } else {
338                         DEBUG(4, ("authenticated session setup with user %s\\%s failed.\n",
339                                 ipc_domain, ipc_username ));
340                 }
341         }
342
343         /* Fall back to anonymous connection, this might fail later */
344
345         if (NT_STATUS_IS_OK(cli_session_setup(*cli, "", NULL, 0,
346                                               NULL, 0, ""))) {
347                 DEBUG(5, ("Connected anonymously\n"));
348                 cli_init_creds(*cli, "", "", "");
349                 goto session_setup_done;
350         }
351
352         result = cli_nt_error(*cli);
353
354         if (NT_STATUS_IS_OK(result))
355                 result = NT_STATUS_UNSUCCESSFUL;
356
357         /* We can't session setup */
358
359         goto done;
360
361  session_setup_done:
362
363         /* cache the server name for later connections */
364
365         saf_store( domain->name, (*cli)->desthost );
366
367         if (!cli_send_tconX(*cli, "IPC$", "IPC", "", 0)) {
368
369                 result = cli_nt_error(*cli);
370
371                 DEBUG(1,("failed tcon_X with %s\n", nt_errstr(result)));
372
373                 if (NT_STATUS_IS_OK(result))
374                         result = NT_STATUS_UNSUCCESSFUL;
375
376                 goto done;
377         }
378
379         secrets_named_mutex_release(controller);
380         got_mutex = False;
381         *retry = False;
382
383         /* set the domain if empty; needed for schannel connections */
384         if ( !*(*cli)->domain ) {
385                 fstrcpy( (*cli)->domain, domain->name );
386         }
387
388         result = NT_STATUS_OK;
389
390  done:
391         if (got_mutex) {
392                 secrets_named_mutex_release(controller);
393         }
394
395         SAFE_FREE(machine_account);
396         SAFE_FREE(machine_password);
397         SAFE_FREE(machine_krb5_principal);
398         SAFE_FREE(ipc_username);
399         SAFE_FREE(ipc_domain);
400         SAFE_FREE(ipc_password);
401
402         if (!NT_STATUS_IS_OK(result)) {
403                 add_failed_connection_entry(domain->name, controller, result);
404                 if ((*cli) != NULL) {
405                         cli_shutdown(*cli);
406                         *cli = NULL;
407                 }
408         }
409
410         return result;
411 }
412
413 struct dc_name_ip {
414         fstring name;
415         struct in_addr ip;
416 };
417
418 static BOOL add_one_dc_unique(TALLOC_CTX *mem_ctx, const char *domain_name,
419                               const char *dcname, struct in_addr ip,
420                               struct dc_name_ip **dcs, int *num)
421 {
422         if (!NT_STATUS_IS_OK(check_negative_conn_cache(domain_name, dcname))) {
423                 DEBUG(10, ("DC %s was in the negative conn cache\n", dcname));
424                 return False;
425         }
426
427         *dcs = TALLOC_REALLOC_ARRAY(mem_ctx, *dcs, struct dc_name_ip, (*num)+1);
428
429         if (*dcs == NULL)
430                 return False;
431
432         fstrcpy((*dcs)[*num].name, dcname);
433         (*dcs)[*num].ip = ip;
434         *num += 1;
435         return True;
436 }
437
438 static BOOL add_sockaddr_to_array(TALLOC_CTX *mem_ctx,
439                                   struct in_addr ip, uint16 port,
440                                   struct sockaddr_in **addrs, int *num)
441 {
442         *addrs = TALLOC_REALLOC_ARRAY(mem_ctx, *addrs, struct sockaddr_in, (*num)+1);
443
444         if (*addrs == NULL)
445                 return False;
446
447         (*addrs)[*num].sin_family = PF_INET;
448         putip((char *)&((*addrs)[*num].sin_addr), (char *)&ip);
449         (*addrs)[*num].sin_port = htons(port);
450
451         *num += 1;
452         return True;
453 }
454
455 static void mailslot_name(struct in_addr dc_ip, fstring name)
456 {
457         fstr_sprintf(name, "\\MAILSLOT\\NET\\GETDC%X", dc_ip.s_addr);
458 }
459
460 static BOOL send_getdc_request(struct in_addr dc_ip,
461                                const char *domain_name,
462                                const DOM_SID *sid)
463 {
464         pstring outbuf;
465         char *p;
466         fstring my_acct_name;
467         fstring my_mailslot;
468
469         mailslot_name(dc_ip, my_mailslot);
470
471         memset(outbuf, '\0', sizeof(outbuf));
472
473         p = outbuf;
474
475         SCVAL(p, 0, SAMLOGON);
476         p++;
477
478         SCVAL(p, 0, 0); /* Count pointer ... */
479         p++;
480
481         SIVAL(p, 0, 0); /* The sender's token ... */
482         p += 2;
483
484         p += dos_PutUniCode(p, global_myname(), sizeof(pstring), True);
485         fstr_sprintf(my_acct_name, "%s$", global_myname());
486         p += dos_PutUniCode(p, my_acct_name, sizeof(pstring), True);
487
488         memcpy(p, my_mailslot, strlen(my_mailslot)+1);
489         p += strlen(my_mailslot)+1;
490
491         SIVAL(p, 0, 0x80);
492         p+=4;
493
494         SIVAL(p, 0, sid_size(sid));
495         p+=4;
496
497         p = ALIGN4(p, outbuf);
498
499         sid_linearize(p, sid_size(sid), sid);
500         p += sid_size(sid);
501
502         SIVAL(p, 0, 1);
503         SSVAL(p, 4, 0xffff);
504         SSVAL(p, 6, 0xffff);
505         p+=8;
506
507         return cli_send_mailslot(False, "\\MAILSLOT\\NET\\NTLOGON", 0,
508                                  outbuf, PTR_DIFF(p, outbuf),
509                                  global_myname(), 0, domain_name, 0x1c,
510                                  dc_ip);
511 }
512
513 static BOOL receive_getdc_response(struct in_addr dc_ip,
514                                    const char *domain_name,
515                                    fstring dc_name)
516 {
517         struct packet_struct *packet;
518         fstring my_mailslot;
519         char *buf, *p;
520         fstring dcname, user, domain;
521         int len;
522
523         mailslot_name(dc_ip, my_mailslot);
524
525         packet = receive_unexpected(DGRAM_PACKET, 0, my_mailslot);
526
527         if (packet == NULL) {
528                 DEBUG(5, ("Did not receive packet for %s\n", my_mailslot));
529                 return False;
530         }
531
532         DEBUG(5, ("Received packet for %s\n", my_mailslot));
533
534         buf = packet->packet.dgram.data;
535         len = packet->packet.dgram.datasize;
536
537         if (len < 70) {
538                 /* 70 is a completely arbitrary value to make sure
539                    the SVAL below does not read uninitialized memory */
540                 DEBUG(3, ("GetDC got short response\n"));
541                 return False;
542         }
543
544         /* This should be (buf-4)+SVAL(buf-4, smb_vwv12)... */
545         p = buf+SVAL(buf, smb_vwv10);
546
547         if (CVAL(p,0) != SAMLOGON_R) {
548                 DEBUG(8, ("GetDC got invalid response type %d\n", CVAL(p, 0)));
549                 return False;
550         }
551
552         p+=2;
553         pull_ucs2(buf, dcname, p, sizeof(dcname), PTR_DIFF(buf+len, p),
554                   STR_TERMINATE|STR_NOALIGN);
555         p = skip_unibuf(p, PTR_DIFF(buf+len, p));
556         pull_ucs2(buf, user, p, sizeof(dcname), PTR_DIFF(buf+len, p),
557                   STR_TERMINATE|STR_NOALIGN);
558         p = skip_unibuf(p, PTR_DIFF(buf+len, p));
559         pull_ucs2(buf, domain, p, sizeof(dcname), PTR_DIFF(buf+len, p),
560                   STR_TERMINATE|STR_NOALIGN);
561         p = skip_unibuf(p, PTR_DIFF(buf+len, p));
562
563         if (!strequal(domain, domain_name)) {
564                 DEBUG(3, ("GetDC: Expected domain %s, got %s\n",
565                           domain_name, domain));
566                 return False;
567         }
568
569         p = dcname;
570         if (*p == '\\') p += 1;
571         if (*p == '\\') p += 1;
572
573         fstrcpy(dc_name, p);
574
575         DEBUG(10, ("GetDC gave name %s for domain %s\n",
576                    dc_name, domain));
577
578         return True;
579 }
580
581 /*******************************************************************
582  convert an ip to a name
583 *******************************************************************/
584
585 static BOOL dcip_to_name( const char *domainname, const char *realm, 
586                           const DOM_SID *sid, struct in_addr ip, fstring name )
587 {
588         struct ip_service ip_list;
589
590         ip_list.ip = ip;
591         ip_list.port = 0;
592
593         /* try GETDC requests first */
594         
595         if (send_getdc_request(ip, domainname, sid)) {
596                 int i;
597                 smb_msleep(100);
598                 for (i=0; i<5; i++) {
599                         if (receive_getdc_response(ip, domainname, name)) {
600                                 namecache_store(name, 0x20, 1, &ip_list);
601                                 return True;
602                         }
603                         smb_msleep(500);
604                 }
605         }
606
607         /* try node status request */
608
609         if ( name_status_find(domainname, 0x1c, 0x20, ip, name) ) {
610                 namecache_store(name, 0x20, 1, &ip_list);
611                 return True;
612         }
613
614 #ifdef WITH_ADS
615         /* for active directory servers, try to get the ldap server name.
616            None of these failure should be considered critical for now */
617
618         if ( lp_security() == SEC_ADS ) 
619         {
620                 ADS_STRUCT *ads;
621
622                 ads = ads_init( realm, domainname, NULL );
623                 ads->auth.flags |= ADS_AUTH_NO_BIND;
624
625                 if ( !ads_try_connect( ads, inet_ntoa(ip) ) )  {
626                         ads_destroy( &ads );
627                         return False;
628                 }
629
630                 fstrcpy(name, ads->config.ldap_server_name);
631                 namecache_store(name, 0x20, 1, &ip_list);
632
633                 ads_destroy( &ads );
634                 return True;
635         }
636 #endif
637
638         return False;
639 }
640
641 /*******************************************************************
642  Retreive a list of IP address for domain controllers.  Fill in 
643  the dcs[]  with results.
644 *******************************************************************/
645
646 static BOOL get_dcs(TALLOC_CTX *mem_ctx, const struct winbindd_domain *domain,
647                     struct dc_name_ip **dcs, int *num_dcs)
648 {
649         fstring dcname;
650         struct  in_addr ip;
651         struct  ip_service *ip_list = NULL;
652         int     iplist_size = 0;
653         int     i;
654         BOOL    is_our_domain;
655
656
657         is_our_domain = strequal(domain->name, lp_workgroup());
658
659         if ( !is_our_domain 
660                 && get_dc_name_via_netlogon(domain, dcname, &ip) 
661                 && add_one_dc_unique(mem_ctx, domain->name, dcname, ip, dcs, num_dcs) )
662         {
663                 DEBUG(10, ("Retrieved DC %s at %s via netlogon\n",
664                            dcname, inet_ntoa(ip)));
665                 return True;
666         }
667
668         /* try standard netbios queries first */
669
670         get_sorted_dc_list(domain->name, &ip_list, &iplist_size, False);
671
672         /* check for security = ads and use DNS if we can */
673
674         if ( iplist_size==0 && lp_security() == SEC_ADS ) 
675                 get_sorted_dc_list(domain->alt_name, &ip_list, &iplist_size, True);
676
677         /* FIXME!! this is where we should re-insert the GETDC requests --jerry */
678
679         /* now add to the dc array.  We'll wait until the last minute 
680            to look up the name of the DC.  But we fill in the char* for 
681            the ip now in to make the failed connection cache work */
682
683         for ( i=0; i<iplist_size; i++ ) {
684                 add_one_dc_unique(mem_ctx, domain->name, inet_ntoa(ip_list[i].ip), 
685                         ip_list[i].ip, dcs, num_dcs);
686         }
687
688         SAFE_FREE( ip_list );
689
690         return True;
691 }
692
693 static BOOL find_new_dc(TALLOC_CTX *mem_ctx,
694                         const struct winbindd_domain *domain,
695                         fstring dcname, struct sockaddr_in *addr, int *fd)
696 {
697         struct dc_name_ip *dcs = NULL;
698         int num_dcs = 0;
699
700         const char **dcnames = NULL;
701         int num_dcnames = 0;
702
703         struct sockaddr_in *addrs = NULL;
704         int num_addrs = 0;
705
706         int i, fd_index;
707
708  again:
709         if (!get_dcs(mem_ctx, domain, &dcs, &num_dcs) || (num_dcs == 0))
710                 return False;
711
712         for (i=0; i<num_dcs; i++) {
713
714                 add_string_to_array(mem_ctx, dcs[i].name,
715                                     &dcnames, &num_dcnames);
716                 add_sockaddr_to_array(mem_ctx, dcs[i].ip, 445,
717                                       &addrs, &num_addrs);
718
719                 add_string_to_array(mem_ctx, dcs[i].name,
720                                     &dcnames, &num_dcnames);
721                 add_sockaddr_to_array(mem_ctx, dcs[i].ip, 139,
722                                       &addrs, &num_addrs);
723         }
724
725         if ((num_dcnames == 0) || (num_dcnames != num_addrs))
726                 return False;
727
728         if ((addrs == NULL) || (dcnames == NULL))
729                 return False;
730
731         if ( !open_any_socket_out(addrs, num_addrs, 10000, &fd_index, fd) ) 
732         {
733                 for (i=0; i<num_dcs; i++) {
734                         add_failed_connection_entry(domain->name,
735                                 dcs[i].name, NT_STATUS_UNSUCCESSFUL);
736                 }
737                 return False;
738         }
739
740         *addr = addrs[fd_index];
741
742         if (*dcnames[fd_index] != '\0' && !is_ipaddress(dcnames[fd_index])) {
743                 /* Ok, we've got a name for the DC */
744                 fstrcpy(dcname, dcnames[fd_index]);
745                 return True;
746         }
747
748         /* Try to figure out the name */
749         if (dcip_to_name( domain->name, domain->alt_name, &domain->sid,
750                           addr->sin_addr, dcname )) {
751                 return True;
752         }
753
754         /* We can not continue without the DC's name */
755         add_failed_connection_entry(domain->name, dcs[fd_index].name,
756                                     NT_STATUS_UNSUCCESSFUL);
757         goto again;
758 }
759
760 static NTSTATUS cm_open_connection(struct winbindd_domain *domain,
761                                    struct winbindd_cm_conn *new_conn)
762 {
763         TALLOC_CTX *mem_ctx;
764         NTSTATUS result;
765         char *saf_servername = saf_fetch( domain->name );
766         int retries;
767
768         if ((mem_ctx = talloc_init("cm_open_connection")) == NULL)
769                 return NT_STATUS_NO_MEMORY;
770
771         /* we have to check the server affinity cache here since 
772            later we selecte a DC based on response time and not preference */
773            
774         if ( saf_servername ) 
775         {
776                 /* convert an ip address to a name */
777                 if ( is_ipaddress( saf_servername ) )
778                 {
779                         fstring saf_name;
780                         struct in_addr ip;
781
782                         ip = *interpret_addr2( saf_servername );
783                         if (dcip_to_name( domain->name, domain->alt_name,
784                                           &domain->sid, ip, saf_name )) {
785                                 fstrcpy( domain->dcname, saf_name );
786                         } else {
787                                 add_failed_connection_entry(
788                                         domain->name, saf_servername,
789                                         NT_STATUS_UNSUCCESSFUL);
790                         }
791                 } 
792                 else 
793                 {
794                         fstrcpy( domain->dcname, saf_servername );
795                 }
796
797                 SAFE_FREE( saf_servername );
798         }
799
800         for (retries = 0; retries < 3; retries++) {
801
802                 int fd = -1;
803                 BOOL retry = False;
804
805                 result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
806
807                 if ((strlen(domain->dcname) > 0)
808                         && NT_STATUS_IS_OK(check_negative_conn_cache( domain->name, domain->dcname))
809                         && (resolve_name(domain->dcname, &domain->dcaddr.sin_addr, 0x20)))
810                 {
811                         struct sockaddr_in *addrs = NULL;
812                         int num_addrs = 0;
813                         int dummy = 0;
814
815                         add_sockaddr_to_array(mem_ctx, domain->dcaddr.sin_addr, 445, &addrs, &num_addrs);
816                         add_sockaddr_to_array(mem_ctx, domain->dcaddr.sin_addr, 139, &addrs, &num_addrs);
817
818                         if (!open_any_socket_out(addrs, num_addrs, 10000, &dummy, &fd)) {
819                                 domain->online = False;
820                                 fd = -1;
821                         }
822                 }
823
824                 if ((fd == -1) 
825                         && !find_new_dc(mem_ctx, domain, domain->dcname, &domain->dcaddr, &fd))
826                 {
827                         /* This is the one place where we will
828                            set the global winbindd offline state
829                            to true, if a "WINBINDD_OFFLINE" entry
830                            is found in the winbindd cache. */
831                         set_global_winbindd_state_offline();
832                         domain->online = False;
833                         break;
834                 }
835
836                 new_conn->cli = NULL;
837
838                 result = cm_prepare_connection(domain, fd, domain->dcname,
839                         &new_conn->cli, &retry);
840
841                 if (!retry)
842                         break;
843         }
844
845         if (NT_STATUS_IS_OK(result)) {
846                 if (domain->online == False) {
847                         /* We're changing state from offline to online. */
848                         set_global_winbindd_state_online();
849                 }
850                 domain->online = True;
851         }
852
853         talloc_destroy(mem_ctx);
854         return result;
855 }
856
857 /* Close down all open pipes on a connection. */
858
859 void invalidate_cm_connection(struct winbindd_cm_conn *conn)
860 {
861         if (conn->samr_pipe != NULL) {
862                 cli_rpc_pipe_close(conn->samr_pipe);
863                 conn->samr_pipe = NULL;
864         }
865
866         if (conn->lsa_pipe != NULL) {
867                 cli_rpc_pipe_close(conn->lsa_pipe);
868                 conn->lsa_pipe = NULL;
869         }
870
871         if (conn->netlogon_pipe != NULL) {
872                 cli_rpc_pipe_close(conn->netlogon_pipe);
873                 conn->netlogon_pipe = NULL;
874         }
875
876         if (conn->cli) {
877                 cli_shutdown(conn->cli);
878         }
879
880         conn->cli = NULL;
881 }
882
883 void close_conns_after_fork(void)
884 {
885         struct winbindd_domain *domain;
886
887         for (domain = domain_list(); domain; domain = domain->next) {
888                 if (domain->conn.cli == NULL)
889                         continue;
890
891                 if (domain->conn.cli->fd == -1)
892                         continue;
893
894                 close(domain->conn.cli->fd);
895                 domain->conn.cli->fd = -1;
896         }
897 }
898
899 static BOOL connection_ok(struct winbindd_domain *domain)
900 {
901         if (domain->conn.cli == NULL) {
902                 DEBUG(8, ("Connection to %s for domain %s has NULL "
903                           "cli!\n", domain->dcname, domain->name));
904                 return False;
905         }
906
907         if (!domain->conn.cli->initialised) {
908                 DEBUG(3, ("Connection to %s for domain %s was never "
909                           "initialised!\n", domain->dcname, domain->name));
910                 return False;
911         }
912
913         if (domain->conn.cli->fd == -1) {
914                 DEBUG(3, ("Connection to %s for domain %s has died or was "
915                           "never started (fd == -1)\n", 
916                           domain->dcname, domain->name));
917                 return False;
918         }
919
920         return True;
921 }
922         
923 /* Initialize a new connection up to the RPC BIND. */
924
925 static NTSTATUS init_dc_connection(struct winbindd_domain *domain)
926 {
927         if (connection_ok(domain))
928                 return NT_STATUS_OK;
929
930         invalidate_cm_connection(&domain->conn);
931
932         return cm_open_connection(domain, &domain->conn);
933 }
934
935 /******************************************************************************
936  We can 'sense' certain things about the DC by it's replies to certain
937  questions.
938
939  This tells us if this particular remote server is Active Directory, and if it
940  is native mode.
941 ******************************************************************************/
942
943 void set_dc_type_and_flags( struct winbindd_domain *domain )
944 {
945         NTSTATUS                result;
946         DS_DOMINFO_CTR          ctr;
947         TALLOC_CTX              *mem_ctx = NULL;
948         struct rpc_pipe_client  *cli;
949         POLICY_HND pol;
950         
951         char *domain_name = NULL;
952         char *dns_name = NULL;
953         DOM_SID *dom_sid = NULL;
954
955         ZERO_STRUCT( ctr );
956         
957         domain->native_mode = False;
958         domain->active_directory = False;
959
960         if (domain->internal) {
961                 domain->initialized = True;
962                 return;
963         }
964
965         result = init_dc_connection(domain);
966         if (!NT_STATUS_IS_OK(result)) {
967                 DEBUG(5, ("set_dc_type_and_flags: Could not open a connection "
968                           "to %s: (%s)\n", domain->name, nt_errstr(result)));
969                 domain->initialized = True;
970                 return;
971         }
972
973         cli = cli_rpc_pipe_open_noauth(domain->conn.cli, PI_LSARPC_DS,
974                                        &result);
975
976         if (cli == NULL) {
977                 DEBUG(5, ("set_dc_type_and_flags: Could not bind to "
978                           "PI_LSARPC_DS on domain %s: (%s)\n",
979                           domain->name, nt_errstr(result)));
980                 domain->initialized = True;
981                 return;
982         }
983
984         result = rpccli_ds_getprimarydominfo(cli, cli->cli->mem_ctx,
985                                              DsRolePrimaryDomainInfoBasic,
986                                              &ctr);
987         cli_rpc_pipe_close(cli);
988
989         if (!NT_STATUS_IS_OK(result)) {
990                 domain->initialized = True;
991                 return;
992         }
993         
994         if ((ctr.basic->flags & DSROLE_PRIMARY_DS_RUNNING) &&
995             !(ctr.basic->flags & DSROLE_PRIMARY_DS_MIXED_MODE) )
996                 domain->native_mode = True;
997
998         cli = cli_rpc_pipe_open_noauth(domain->conn.cli, PI_LSARPC, &result);
999
1000         if (cli == NULL) {
1001                 domain->initialized = True;
1002                 return;
1003         }
1004
1005         mem_ctx = talloc_init("set_dc_type_and_flags on domain %s\n",
1006                               domain->name);
1007         if (!mem_ctx) {
1008                 DEBUG(1, ("set_dc_type_and_flags: talloc_init() failed\n"));
1009                 cli_rpc_pipe_close(cli);
1010                 return;
1011         }
1012
1013         result = rpccli_lsa_open_policy2(cli, mem_ctx, True, 
1014                                          SEC_RIGHTS_MAXIMUM_ALLOWED, &pol);
1015                 
1016         if (NT_STATUS_IS_OK(result)) {
1017                 /* This particular query is exactly what Win2k clients use 
1018                    to determine that the DC is active directory */
1019                 result = rpccli_lsa_query_info_policy2(cli, mem_ctx, &pol,
1020                                                        12, &domain_name,
1021                                                        &dns_name, NULL,
1022                                                        NULL, &dom_sid);
1023         }
1024
1025         if (NT_STATUS_IS_OK(result)) {
1026                 if (domain_name)
1027                         fstrcpy(domain->name, domain_name);
1028
1029                 if (dns_name)
1030                         fstrcpy(domain->alt_name, dns_name);
1031
1032                 if (dom_sid) 
1033                         sid_copy(&domain->sid, dom_sid);
1034
1035                 domain->active_directory = True;
1036         } else {
1037                 
1038                 result = rpccli_lsa_open_policy(cli, mem_ctx, True, 
1039                                                 SEC_RIGHTS_MAXIMUM_ALLOWED,
1040                                                 &pol);
1041                         
1042                 if (!NT_STATUS_IS_OK(result))
1043                         goto done;
1044                         
1045                 result = rpccli_lsa_query_info_policy(cli, mem_ctx, 
1046                                                       &pol, 5, &domain_name, 
1047                                                       &dom_sid);
1048                         
1049                 if (NT_STATUS_IS_OK(result)) {
1050                         if (domain_name)
1051                                 fstrcpy(domain->name, domain_name);
1052
1053                         if (dom_sid) 
1054                                 sid_copy(&domain->sid, dom_sid);
1055                 }
1056         }
1057 done:
1058
1059         cli_rpc_pipe_close(cli);
1060         
1061         talloc_destroy(mem_ctx);
1062
1063         domain->initialized = True;
1064         
1065         return;
1066 }
1067
1068 static BOOL cm_get_schannel_dcinfo(struct winbindd_domain *domain,
1069                                    struct dcinfo **ppdc)
1070 {
1071         NTSTATUS result;
1072         struct rpc_pipe_client *netlogon_pipe;
1073
1074         if (lp_client_schannel() == False) {
1075                 return False;
1076         }
1077
1078         result = cm_connect_netlogon(domain, &netlogon_pipe);
1079         if (!NT_STATUS_IS_OK(result)) {
1080                 return False;
1081         }
1082
1083         /* Return a pointer to the struct dcinfo from the
1084            netlogon pipe. */
1085
1086         *ppdc = domain->conn.netlogon_pipe->dc;
1087         return True;
1088 }
1089
1090 NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
1091                         struct rpc_pipe_client **cli, POLICY_HND *sam_handle)
1092 {
1093         struct winbindd_cm_conn *conn;
1094         NTSTATUS result;
1095         fstring conn_pwd;
1096         struct dcinfo *p_dcinfo;
1097
1098         result = init_dc_connection(domain);
1099         if (!NT_STATUS_IS_OK(result)) {
1100                 return result;
1101         }
1102
1103         conn = &domain->conn;
1104
1105         if (conn->samr_pipe != NULL) {
1106                 goto done;
1107         }
1108
1109         /*
1110          * No SAMR pipe yet. Attempt to get an NTLMSSP SPNEGO authenticated
1111          * sign and sealed pipe using the machine account password by
1112          * preference. If we can't - try schannel, if that fails, try
1113          * anonymous.
1114          */
1115
1116         pwd_get_cleartext(&conn->cli->pwd, conn_pwd);
1117         if ((conn->cli->user_name[0] == '\0') ||
1118             (conn->cli->domain[0] == '\0') || 
1119             (conn_pwd[0] == '\0')) {
1120                 DEBUG(10, ("cm_connect_sam: No no user available for "
1121                            "domain %s, trying schannel\n", conn->cli->domain));
1122                 goto schannel;
1123         }
1124
1125         /* We have an authenticated connection. Use a NTLMSSP SPNEGO
1126            authenticated SAMR pipe with sign & seal. */
1127         conn->samr_pipe =
1128                 cli_rpc_pipe_open_spnego_ntlmssp(conn->cli, PI_SAMR,
1129                                                  PIPE_AUTH_LEVEL_PRIVACY,
1130                                                  conn->cli->domain,
1131                                                  conn->cli->user_name,
1132                                                  conn_pwd, &result);
1133
1134         if (conn->samr_pipe == NULL) {
1135                 DEBUG(10,("cm_connect_sam: failed to connect to SAMR "
1136                           "pipe for domain %s using NTLMSSP "
1137                           "authenticated pipe: user %s\\%s. Error was "
1138                           "%s\n", domain->name, conn->cli->domain,
1139                           conn->cli->user_name, nt_errstr(result)));
1140                 goto schannel;
1141         }
1142
1143         DEBUG(10,("cm_connect_sam: connected to SAMR pipe for "
1144                   "domain %s using NTLMSSP authenticated "
1145                   "pipe: user %s\\%s\n", domain->name,
1146                   conn->cli->domain, conn->cli->user_name ));
1147
1148         result = rpccli_samr_connect(conn->samr_pipe, mem_ctx,
1149                                      SEC_RIGHTS_MAXIMUM_ALLOWED,
1150                                      &conn->sam_connect_handle);
1151         if (NT_STATUS_IS_OK(result)) {
1152                 goto open_domain;
1153         }
1154         DEBUG(10,("cm_connect_sam: ntlmssp-sealed rpccli_samr_connect "
1155                   "failed for domain %s, error was %s. Trying schannel\n",
1156                   domain->name, nt_errstr(result) ));
1157         cli_rpc_pipe_close(conn->samr_pipe);
1158
1159  schannel:
1160
1161         /* Fall back to schannel if it's a W2K pre-SP1 box. */
1162
1163         if (!cm_get_schannel_dcinfo(domain, &p_dcinfo)) {
1164                 DEBUG(10, ("cm_connect_sam: Could not get schannel auth info "
1165                            "for domain %s, trying anon\n", conn->cli->domain));
1166                 goto anonymous;
1167         }
1168         conn->samr_pipe = cli_rpc_pipe_open_schannel_with_key
1169                 (conn->cli, PI_SAMR, PIPE_AUTH_LEVEL_PRIVACY,
1170                  domain->name, p_dcinfo, &result);
1171
1172         if (conn->samr_pipe == NULL) {
1173                 DEBUG(10,("cm_connect_sam: failed to connect to SAMR pipe for "
1174                           "domain %s using schannel. Error was %s\n",
1175                           domain->name, nt_errstr(result) ));
1176                 goto anonymous;
1177         }
1178         DEBUG(10,("cm_connect_sam: connected to SAMR pipe for domain %s using "
1179                   "schannel.\n", domain->name ));
1180
1181         result = rpccli_samr_connect(conn->samr_pipe, mem_ctx,
1182                                      SEC_RIGHTS_MAXIMUM_ALLOWED,
1183                                      &conn->sam_connect_handle);
1184         if (NT_STATUS_IS_OK(result)) {
1185                 goto open_domain;
1186         }
1187         DEBUG(10,("cm_connect_sam: schannel-sealed rpccli_samr_connect failed "
1188                   "for domain %s, error was %s. Trying anonymous\n",
1189                   domain->name, nt_errstr(result) ));
1190         cli_rpc_pipe_close(conn->samr_pipe);
1191
1192  anonymous:
1193
1194         /* Finally fall back to anonymous. */
1195         conn->samr_pipe = cli_rpc_pipe_open_noauth(conn->cli, PI_SAMR,
1196                                                    &result);
1197
1198         if (conn->samr_pipe == NULL) {
1199                 result = NT_STATUS_PIPE_NOT_AVAILABLE;
1200                 goto done;
1201         }
1202
1203         result = rpccli_samr_connect(conn->samr_pipe, mem_ctx,
1204                                      SEC_RIGHTS_MAXIMUM_ALLOWED,
1205                                      &conn->sam_connect_handle);
1206         if (!NT_STATUS_IS_OK(result)) {
1207                 DEBUG(10,("cm_connect_sam: rpccli_samr_connect failed "
1208                           "for domain %s Error was %s\n",
1209                           domain->name, nt_errstr(result) ));
1210                 goto done;
1211         }
1212
1213  open_domain:
1214         result = rpccli_samr_open_domain(conn->samr_pipe,
1215                                          mem_ctx,
1216                                          &conn->sam_connect_handle,
1217                                          SEC_RIGHTS_MAXIMUM_ALLOWED,
1218                                          &domain->sid,
1219                                          &conn->sam_domain_handle);
1220
1221  done:
1222
1223         if (!NT_STATUS_IS_OK(result)) {
1224                 invalidate_cm_connection(conn);
1225                 return result;
1226         }
1227
1228         *cli = conn->samr_pipe;
1229         *sam_handle = conn->sam_domain_handle;
1230         return result;
1231 }
1232
1233 NTSTATUS cm_connect_lsa(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
1234                         struct rpc_pipe_client **cli, POLICY_HND *lsa_policy)
1235 {
1236         struct winbindd_cm_conn *conn;
1237         NTSTATUS result;
1238         fstring conn_pwd;
1239         struct dcinfo *p_dcinfo;
1240
1241         result = init_dc_connection(domain);
1242         if (!NT_STATUS_IS_OK(result))
1243                 return result;
1244
1245         conn = &domain->conn;
1246
1247         if (conn->lsa_pipe != NULL) {
1248                 goto done;
1249         }
1250
1251         pwd_get_cleartext(&conn->cli->pwd, conn_pwd);
1252         if ((conn->cli->user_name[0] == '\0') ||
1253             (conn->cli->domain[0] == '\0') || 
1254             (conn_pwd[0] == '\0')) {
1255                 DEBUG(10, ("cm_connect_lsa: No no user available for "
1256                            "domain %s, trying schannel\n", conn->cli->domain));
1257                 goto schannel;
1258         }
1259
1260         /* We have an authenticated connection. Use a NTLMSSP SPNEGO
1261          * authenticated LSA pipe with sign & seal. */
1262         conn->lsa_pipe = cli_rpc_pipe_open_spnego_ntlmssp
1263                 (conn->cli, PI_LSARPC, PIPE_AUTH_LEVEL_PRIVACY,
1264                  conn->cli->domain, conn->cli->user_name, conn_pwd, &result);
1265
1266         if (conn->lsa_pipe == NULL) {
1267                 DEBUG(10,("cm_connect_lsa: failed to connect to LSA pipe for "
1268                           "domain %s using NTLMSSP authenticated pipe: user "
1269                           "%s\\%s. Error was %s. Trying schannel.\n",
1270                           domain->name, conn->cli->domain,
1271                           conn->cli->user_name, nt_errstr(result)));
1272                 goto schannel;
1273         }
1274
1275         DEBUG(10,("cm_connect_lsa: connected to LSA pipe for domain %s using "
1276                   "NTLMSSP authenticated pipe: user %s\\%s\n",
1277                   domain->name, conn->cli->domain, conn->cli->user_name ));
1278
1279         result = rpccli_lsa_open_policy(conn->lsa_pipe, mem_ctx, True,
1280                                         SEC_RIGHTS_MAXIMUM_ALLOWED,
1281                                         &conn->lsa_policy);
1282         if (NT_STATUS_IS_OK(result)) {
1283                 goto done;
1284         }
1285
1286         DEBUG(10,("cm_connect_lsa: rpccli_lsa_open_policy failed, trying "
1287                   "schannel\n"));
1288
1289         cli_rpc_pipe_close(conn->lsa_pipe);
1290
1291  schannel:
1292
1293         /* Fall back to schannel if it's a W2K pre-SP1 box. */
1294
1295         if (!cm_get_schannel_dcinfo(domain, &p_dcinfo)) {
1296                 DEBUG(10, ("cm_connect_lsa: Could not get schannel auth info "
1297                            "for domain %s, trying anon\n", conn->cli->domain));
1298                 goto anonymous;
1299         }
1300         conn->lsa_pipe = cli_rpc_pipe_open_schannel_with_key
1301                 (conn->cli, PI_LSARPC, PIPE_AUTH_LEVEL_PRIVACY,
1302                  domain->name, p_dcinfo, &result);
1303
1304         if (conn->lsa_pipe == NULL) {
1305                 DEBUG(10,("cm_connect_lsa: failed to connect to LSA pipe for "
1306                           "domain %s using schannel. Error was %s\n",
1307                           domain->name, nt_errstr(result) ));
1308                 goto anonymous;
1309         }
1310         DEBUG(10,("cm_connect_lsa: connected to LSA pipe for domain %s using "
1311                   "schannel.\n", domain->name ));
1312
1313         result = rpccli_lsa_open_policy(conn->lsa_pipe, mem_ctx, True,
1314                                         SEC_RIGHTS_MAXIMUM_ALLOWED,
1315                                         &conn->lsa_policy);
1316         if (NT_STATUS_IS_OK(result)) {
1317                 goto done;
1318         }
1319
1320         DEBUG(10,("cm_connect_lsa: rpccli_lsa_open_policy failed, trying "
1321                   "anonymous\n"));
1322
1323         cli_rpc_pipe_close(conn->lsa_pipe);
1324
1325  anonymous:
1326
1327         conn->lsa_pipe = cli_rpc_pipe_open_noauth(conn->cli, PI_LSARPC,
1328                                                   &result);
1329         if (conn->lsa_pipe == NULL) {
1330                 result = NT_STATUS_PIPE_NOT_AVAILABLE;
1331                 goto done;
1332         }
1333
1334         result = rpccli_lsa_open_policy(conn->lsa_pipe, mem_ctx, True,
1335                                         SEC_RIGHTS_MAXIMUM_ALLOWED,
1336                                         &conn->lsa_policy);
1337  done:
1338         if (!NT_STATUS_IS_OK(result)) {
1339                 invalidate_cm_connection(conn);
1340                 return NT_STATUS_UNSUCCESSFUL;
1341         }
1342
1343         *cli = conn->lsa_pipe;
1344         *lsa_policy = conn->lsa_policy;
1345         return result;
1346 }
1347
1348 /****************************************************************************
1349  Open the netlogon pipe to this DC. Use schannel if specified in client conf.
1350  session key stored in conn->netlogon_pipe->dc->sess_key.
1351 ****************************************************************************/
1352
1353 NTSTATUS cm_connect_netlogon(struct winbindd_domain *domain,
1354                              struct rpc_pipe_client **cli)
1355 {
1356         struct winbindd_cm_conn *conn;
1357         NTSTATUS result;
1358
1359         uint32 neg_flags = NETLOGON_NEG_AUTH2_FLAGS;
1360         uint8  mach_pwd[16];
1361         uint32  sec_chan_type;
1362         const char *account_name;
1363         struct rpc_pipe_client *netlogon_pipe = NULL;
1364
1365         *cli = NULL;
1366
1367         result = init_dc_connection(domain);
1368         if (!NT_STATUS_IS_OK(result)) {
1369                 return result;
1370         }
1371
1372         conn = &domain->conn;
1373
1374         if (conn->netlogon_pipe != NULL) {
1375                 *cli = conn->netlogon_pipe;
1376                 return NT_STATUS_OK;
1377         }
1378
1379         if (!get_trust_pw(domain->name, mach_pwd, &sec_chan_type)) {
1380                 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1381         }
1382
1383         netlogon_pipe = cli_rpc_pipe_open_noauth(conn->cli, PI_NETLOGON,
1384                                                  &result);
1385         if (netlogon_pipe == NULL) {
1386                 return result;
1387         }
1388
1389         if (lp_client_schannel() != False) {
1390                 neg_flags |= NETLOGON_NEG_SCHANNEL;
1391         }
1392
1393         /* if we are a DC and this is a trusted domain, then we need to use our
1394            domain name in the net_req_auth2() request */
1395
1396         if ( IS_DC
1397                 && !strequal(domain->name, lp_workgroup())
1398                 && lp_allow_trusted_domains() ) 
1399         {
1400                 account_name = lp_workgroup();
1401         } else {
1402                 account_name = domain->primary ?
1403                         global_myname() : domain->name;
1404         }
1405
1406         if (account_name == NULL) {
1407                 cli_rpc_pipe_close(netlogon_pipe);
1408                 return NT_STATUS_NO_MEMORY;
1409         }
1410
1411         result = rpccli_netlogon_setup_creds(
1412                  netlogon_pipe,
1413                  domain->dcname, /* server name. */
1414                  domain->name,   /* domain name */
1415                  global_myname(), /* client name */
1416                  account_name,   /* machine account */
1417                  mach_pwd,       /* machine password */
1418                  sec_chan_type,  /* from get_trust_pw */
1419                  &neg_flags);
1420
1421         if (!NT_STATUS_IS_OK(result)) {
1422                 cli_rpc_pipe_close(netlogon_pipe);
1423                 return result;
1424         }
1425
1426         if ((lp_client_schannel() == True) &&
1427                         ((neg_flags & NETLOGON_NEG_SCHANNEL) == 0)) {
1428                 DEBUG(3, ("Server did not offer schannel\n"));
1429                 cli_rpc_pipe_close(netlogon_pipe);
1430                 return NT_STATUS_ACCESS_DENIED;
1431         }
1432
1433         if ((lp_client_schannel() == False) ||
1434                         ((neg_flags & NETLOGON_NEG_SCHANNEL) == 0)) {
1435                 /* We're done - just keep the existing connection to NETLOGON
1436                  * open */
1437                 conn->netlogon_pipe = netlogon_pipe;
1438                 *cli = conn->netlogon_pipe;
1439                 return NT_STATUS_OK;
1440         }
1441
1442         /* Using the credentials from the first pipe, open a signed and sealed
1443            second netlogon pipe. The session key is stored in the schannel
1444            part of the new pipe auth struct.
1445         */
1446
1447         conn->netlogon_pipe =
1448                 cli_rpc_pipe_open_schannel_with_key(conn->cli,
1449                                                     PI_NETLOGON,
1450                                                     PIPE_AUTH_LEVEL_PRIVACY,
1451                                                     domain->name,
1452                                                     netlogon_pipe->dc,
1453                                                     &result);
1454
1455         /* We can now close the initial netlogon pipe. */
1456         cli_rpc_pipe_close(netlogon_pipe);
1457
1458         if (conn->netlogon_pipe == NULL) {
1459                 DEBUG(3, ("Could not open schannel'ed NETLOGON pipe. Error "
1460                           "was %s\n", nt_errstr(result)));
1461                           
1462                 /* make sure we return something besides OK */
1463                 return !NT_STATUS_IS_OK(result) ? result : NT_STATUS_PIPE_NOT_AVAILABLE;
1464         }
1465
1466         *cli = conn->netlogon_pipe;
1467         return NT_STATUS_OK;
1468 }