r8800: grr...get logic right when checking #define
[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 /****************************************************************** 
69    Disabling schannl on the LSA pipe for now since 
70    both Win2K-SP4 SR1 & Win2K3-SP1 fail the open_policy() 
71    call (return codes 0xc0020042 and 0xc0020041 respectively).
72    We really need to fix this soon.  Had to disable on the 
73    SAMR pipe as well for now.   --jerry
74 ******************************************************************/
75
76 #define DISABLE_SCHANNEL_WIN2K3_SP1     1
77
78
79 /* Choose between anonymous or authenticated connections.  We need to use
80    an authenticated connection if DCs have the RestrictAnonymous registry
81    entry set > 0, or the "Additional restrictions for anonymous
82    connections" set in the win2k Local Security Policy. 
83    
84    Caller to free() result in domain, username, password
85 */
86
87 static void cm_get_ipc_userpass(char **username, char **domain, char **password)
88 {
89         *username = secrets_fetch(SECRETS_AUTH_USER, NULL);
90         *domain = secrets_fetch(SECRETS_AUTH_DOMAIN, NULL);
91         *password = secrets_fetch(SECRETS_AUTH_PASSWORD, NULL);
92         
93         if (*username && **username) {
94
95                 if (!*domain || !**domain)
96                         *domain = smb_xstrdup(lp_workgroup());
97                 
98                 if (!*password || !**password)
99                         *password = smb_xstrdup("");
100
101                 DEBUG(3, ("cm_get_ipc_userpass: Retrieved auth-user from secrets.tdb [%s\\%s]\n", 
102                           *domain, *username));
103
104         } else {
105                 DEBUG(3, ("cm_get_ipc_userpass: No auth-user defined\n"));
106                 *username = smb_xstrdup("");
107                 *domain = smb_xstrdup("");
108                 *password = smb_xstrdup("");
109         }
110 }
111
112 static BOOL get_dc_name_via_netlogon(const struct winbindd_domain *domain,
113                                      fstring dcname, struct in_addr *dc_ip)
114 {
115         struct winbindd_domain *our_domain;
116         NTSTATUS result;
117         struct rpc_pipe_client *cli;
118         TALLOC_CTX *mem_ctx;
119
120         fstring tmp;
121         char *p;
122
123         /* Hmmmm. We can only open one connection to the NETLOGON pipe at the
124          * moment.... */
125
126         if (IS_DC)
127                 return False;
128
129         if (domain->primary)
130                 return False;
131
132         our_domain = find_our_domain();
133
134         if ((mem_ctx = talloc_init("get_dc_name_via_netlogon")) == NULL)
135                 return False;
136
137         {
138                 /* These var's can be ignored -- we're not requesting
139                    anything in the credential chain here */
140                 unsigned char *session_key;
141                 DOM_CRED *creds;
142                 result = cm_connect_netlogon(our_domain, mem_ctx, &cli,
143                                              &session_key, &creds);
144         }
145
146         if (!NT_STATUS_IS_OK(result))
147                 return False;
148
149         result = rpccli_netlogon_getdcname(cli, mem_ctx, domain->dcname,
150                                            domain->name, tmp);
151
152         talloc_destroy(mem_ctx);
153
154         if (!NT_STATUS_IS_OK(result))
155                 return False;
156
157         /* cli_netlogon_getdcname gives us a name with \\ */
158         p = tmp;
159         if (*p == '\\') p+=1;
160         if (*p == '\\') p+=1;
161
162         fstrcpy(dcname, p);
163
164         if (!resolve_name(dcname, dc_ip, 0x20))
165                 return False;
166
167         return True;
168 }
169
170 /************************************************************************
171  Given a fd with a just-connected TCP connection to a DC, open a connection
172  to the pipe.
173 ************************************************************************/
174
175 static NTSTATUS cm_prepare_connection(const struct winbindd_domain *domain,
176                                       const int sockfd,
177                                       const char *controller,
178                                       struct cli_state **cli,
179                                       BOOL *retry)
180 {
181         char *machine_password, *machine_krb5_principal;
182         char *ipc_username, *ipc_domain, *ipc_password;
183
184         BOOL got_mutex;
185         BOOL add_failed_connection = True;
186
187         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
188
189         struct sockaddr peeraddr;
190         socklen_t peeraddr_len;
191
192         struct sockaddr_in *peeraddr_in = (struct sockaddr_in *)&peeraddr;
193
194         machine_password = secrets_fetch_machine_password(lp_workgroup(), NULL,
195                                                           NULL);
196         
197         if (asprintf(&machine_krb5_principal, "%s$@%s", global_myname(),
198                      lp_realm()) == -1) {
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_open_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)) == 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                 goto done;
236         }
237
238         if (ntohs(peeraddr_in->sin_port) == 139) {
239                 struct nmb_name calling;
240                 struct nmb_name called;
241
242                 make_nmb_name(&calling, global_myname(), 0x0);
243                 make_nmb_name(&called, "*SMBSERVER", 0x20);
244
245                 if (!cli_session_request(*cli, &calling, &called)) {
246                         DEBUG(8, ("cli_session_request failed for %s\n",
247                                   controller));
248                         goto done;
249                 }
250         }
251
252         cli_setup_signing_state(*cli, Undefined);
253
254         if (!cli_negprot(*cli)) {
255                 DEBUG(1, ("cli_negprot failed\n"));
256                 cli_shutdown(*cli);
257                 goto done;
258         }
259
260         /* Krb5 session */
261                         
262         if ((lp_security() == SEC_ADS) 
263             && ((*cli)->protocol >= PROTOCOL_NT1 &&
264                 (*cli)->capabilities & CAP_EXTENDED_SECURITY)) {
265
266                 ADS_STATUS ads_status;
267                 (*cli)->use_kerberos = True;
268                 DEBUG(5, ("connecting to %s from %s with kerberos principal "
269                           "[%s]\n", controller, global_myname(),
270                           machine_krb5_principal));
271
272                 ads_status = cli_session_setup_spnego(*cli,
273                                                       machine_krb5_principal, 
274                                                       machine_password, 
275                                                       lp_workgroup());
276
277                 if (!ADS_ERR_OK(ads_status))
278                         DEBUG(4,("failed kerberos session setup with %s\n",
279                                  ads_errstr(ads_status)));
280
281                 result = ads_ntstatus(ads_status);
282         }
283
284         if (NT_STATUS_IS_OK(result))
285                 goto session_setup_done;
286
287         /* Fall back to non-kerberos session setup */
288
289         (*cli)->use_kerberos = False;
290
291         if ((((*cli)->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) != 0) &&
292             (strlen(ipc_username) > 0)) {
293
294                 /* Only try authenticated if we have a username */
295
296                 DEBUG(5, ("connecting to %s from %s with username "
297                           "[%s]\\[%s]\n",  controller, global_myname(),
298                           ipc_domain, ipc_username));
299
300                 if (cli_session_setup(*cli, ipc_username,
301                                       ipc_password, strlen(ipc_password)+1,
302                                       ipc_password, strlen(ipc_password)+1,
303                                       ipc_domain)) {
304                         DEBUG(5, ("authenticated session setup failed\n"));
305                         goto session_setup_done;
306                 }
307         }
308
309         /* Fall back to anonymous connection, this might fail later */
310
311         if (cli_session_setup(*cli, "", NULL, 0, NULL, 0, "")) {
312                 DEBUG(5, ("Connected anonymously\n"));
313                 goto session_setup_done;
314         }
315
316         result = cli_nt_error(*cli);
317
318         if (NT_STATUS_IS_OK(result))
319                 result = NT_STATUS_UNSUCCESSFUL;
320
321         /* We can't session setup */
322
323         goto done;
324
325  session_setup_done:
326
327         if (!cli_send_tconX(*cli, "IPC$", "IPC", "", 0)) {
328
329                 result = cli_nt_error(*cli);
330
331                 DEBUG(1,("failed tcon_X with %s\n", nt_errstr(result)));
332
333                 if (NT_STATUS_IS_OK(result))
334                         result = NT_STATUS_UNSUCCESSFUL;
335
336                 cli_shutdown(*cli);
337                 goto done;
338         }
339
340         secrets_named_mutex_release(controller);
341         got_mutex = False;
342         *retry = False;
343
344         /* set the domain if empty; needed for schannel connections */
345         if ( !*(*cli)->domain )
346                 fstrcpy( (*cli)->domain, domain->name );
347
348         (*cli)->pipe_auth_flags = 0;
349
350         result = NT_STATUS_OK;
351         add_failed_connection = False;
352
353  done:
354         if (got_mutex)
355                 secrets_named_mutex_release(controller);
356
357         SAFE_FREE(machine_password);
358         SAFE_FREE(machine_krb5_principal);
359         SAFE_FREE(ipc_username);
360         SAFE_FREE(ipc_domain);
361         SAFE_FREE(ipc_password);
362
363         if (add_failed_connection)
364                 add_failed_connection_entry(domain->name, controller, result);
365
366         return result;
367 }
368
369 struct dc_name_ip {
370         fstring name;
371         struct in_addr ip;
372 };
373
374 static BOOL add_one_dc_unique(TALLOC_CTX *mem_ctx, const char *domain_name,
375                               const char *dcname, struct in_addr ip,
376                               struct dc_name_ip **dcs, int *num)
377 {
378         if (!NT_STATUS_IS_OK(check_negative_conn_cache(domain_name, dcname)))
379                 return False;
380
381         *dcs = TALLOC_REALLOC_ARRAY(mem_ctx, *dcs, struct dc_name_ip, (*num)+1);
382
383         if (*dcs == NULL)
384                 return False;
385
386         fstrcpy((*dcs)[*num].name, dcname);
387         (*dcs)[*num].ip = ip;
388         *num += 1;
389         return True;
390 }
391
392 static BOOL add_sockaddr_to_array(TALLOC_CTX *mem_ctx,
393                                   struct in_addr ip, uint16 port,
394                                   struct sockaddr_in **addrs, int *num)
395 {
396         *addrs = TALLOC_REALLOC_ARRAY(mem_ctx, *addrs, struct sockaddr_in, (*num)+1);
397
398         if (*addrs == NULL)
399                 return False;
400
401         (*addrs)[*num].sin_family = PF_INET;
402         putip((char *)&((*addrs)[*num].sin_addr), (char *)&ip);
403         (*addrs)[*num].sin_port = htons(port);
404
405         *num += 1;
406         return True;
407 }
408
409 static void mailslot_name(struct in_addr dc_ip, fstring name)
410 {
411         fstr_sprintf(name, "\\MAILSLOT\\NET\\GETDC%X", dc_ip.s_addr);
412 }
413
414 static BOOL send_getdc_request(struct in_addr dc_ip,
415                                const char *domain_name,
416                                const DOM_SID *sid)
417 {
418         pstring outbuf;
419         char *p;
420         fstring my_acct_name;
421         fstring my_mailslot;
422
423         mailslot_name(dc_ip, my_mailslot);
424
425         memset(outbuf, '\0', sizeof(outbuf));
426
427         p = outbuf;
428
429         SCVAL(p, 0, SAMLOGON);
430         p++;
431
432         SCVAL(p, 0, 0); /* Count pointer ... */
433         p++;
434
435         SIVAL(p, 0, 0); /* The sender's token ... */
436         p += 2;
437
438         p += dos_PutUniCode(p, global_myname(), sizeof(pstring), True);
439         fstr_sprintf(my_acct_name, "%s$", global_myname());
440         p += dos_PutUniCode(p, my_acct_name, sizeof(pstring), True);
441
442         memcpy(p, my_mailslot, strlen(my_mailslot)+1);
443         p += strlen(my_mailslot)+1;
444
445         SIVAL(p, 0, 0x80);
446         p+=4;
447
448         SIVAL(p, 0, sid_size(sid));
449         p+=4;
450
451         p = ALIGN4(p, outbuf);
452
453         sid_linearize(p, sid_size(sid), sid);
454         p += sid_size(sid);
455
456         SIVAL(p, 0, 1);
457         SSVAL(p, 4, 0xffff);
458         SSVAL(p, 6, 0xffff);
459         p+=8;
460
461         return cli_send_mailslot(False, "\\MAILSLOT\\NET\\NTLOGON", 0,
462                                  outbuf, PTR_DIFF(p, outbuf),
463                                  global_myname(), 0, domain_name, 0x1c,
464                                  dc_ip);
465 }
466
467 static BOOL receive_getdc_response(struct in_addr dc_ip,
468                                    const char *domain_name,
469                                    fstring dc_name)
470 {
471         struct packet_struct *packet;
472         fstring my_mailslot;
473         char *buf, *p;
474         fstring dcname, user, domain;
475         int len;
476
477         mailslot_name(dc_ip, my_mailslot);
478
479         packet = receive_unexpected(DGRAM_PACKET, 0, my_mailslot);
480
481         if (packet == NULL) {
482                 DEBUG(5, ("Did not receive packet for %s\n", my_mailslot));
483                 return False;
484         }
485
486         DEBUG(5, ("Received packet for %s\n", my_mailslot));
487
488         buf = packet->packet.dgram.data;
489         len = packet->packet.dgram.datasize;
490
491         if (len < 70) {
492                 /* 70 is a completely arbitrary value to make sure
493                    the SVAL below does not read uninitialized memory */
494                 DEBUG(3, ("GetDC got short response\n"));
495                 return False;
496         }
497
498         /* This should be (buf-4)+SVAL(buf-4, smb_vwv12)... */
499         p = buf+SVAL(buf, smb_vwv10);
500
501         if (CVAL(p,0) != SAMLOGON_R) {
502                 DEBUG(8, ("GetDC got invalid response type %d\n", CVAL(p, 0)));
503                 return False;
504         }
505
506         p+=2;
507         pull_ucs2(buf, dcname, p, sizeof(dcname), PTR_DIFF(buf+len, p),
508                   STR_TERMINATE|STR_NOALIGN);
509         p = skip_unibuf(p, PTR_DIFF(buf+len, p));
510         pull_ucs2(buf, user, p, sizeof(dcname), PTR_DIFF(buf+len, p),
511                   STR_TERMINATE|STR_NOALIGN);
512         p = skip_unibuf(p, PTR_DIFF(buf+len, p));
513         pull_ucs2(buf, domain, p, sizeof(dcname), PTR_DIFF(buf+len, p),
514                   STR_TERMINATE|STR_NOALIGN);
515         p = skip_unibuf(p, PTR_DIFF(buf+len, p));
516
517         if (!strequal(domain, domain_name)) {
518                 DEBUG(3, ("GetDC: Expected domain %s, got %s\n",
519                           domain_name, domain));
520                 return False;
521         }
522
523         p = dcname;
524         if (*p == '\\') p += 1;
525         if (*p == '\\') p += 1;
526
527         fstrcpy(dc_name, p);
528
529         DEBUG(10, ("GetDC gave name %s for domain %s\n",
530                    dc_name, domain));
531
532         return True;
533 }
534
535 /*******************************************************************
536  convert an ip to a name
537 *******************************************************************/
538
539 static void dcip_to_name( const char *domainname, const char *realm, 
540                           const DOM_SID *sid, struct in_addr ip, fstring name )
541 {
542         int i;
543
544         /* try GETDC requests first */
545         
546         send_getdc_request(ip, domainname, sid);
547         smb_msleep(100);
548
549         for (i=0; i<5; i++) {
550                 if (receive_getdc_response(ip, domainname, name))
551                         return;
552                 smb_msleep(500);
553         }
554
555         /* try node status request */
556
557         if ( name_status_find(domainname, 0x1c, 0x20, ip, name) )
558                 return;
559
560         /* backup in case the netbios stuff fails */
561
562         fstrcpy( name, inet_ntoa(ip) );
563
564 #ifdef WITH_ADS
565         /* for active directory servers, try to get the ldap server name.
566            None of these failure should be considered critical for now */
567
568         if ( lp_security() == SEC_ADS ) 
569         {
570                 ADS_STRUCT *ads;
571                 ADS_STATUS status;
572
573                 ads = ads_init( realm, domainname, NULL );
574                 ads->auth.flags |= ADS_AUTH_NO_BIND;
575
576                 if ( !ads_try_connect( ads, inet_ntoa(ip), LDAP_PORT ) )  {
577                         ads_destroy( &ads );
578                         return;
579                 }
580
581                 status = ads_server_info(ads);
582                 if ( !ADS_ERR_OK(status) ) {
583                         ads_destroy( &ads );
584                         return;
585                 }
586
587                 fstrcpy(name, ads->config.ldap_server_name);
588
589                 ads_destroy( &ads );
590         }
591 #endif
592
593         return;
594 }
595
596 /*******************************************************************
597  Retreive a list of IP address for domain controllers.  Fill in 
598  the dcs[]  with results.
599 *******************************************************************/
600
601 static BOOL get_dcs(TALLOC_CTX *mem_ctx, const struct winbindd_domain *domain,
602                     struct dc_name_ip **dcs, int *num_dcs)
603 {
604         fstring dcname;
605         struct  in_addr ip;
606         struct  ip_service *ip_list = NULL;
607         int     iplist_size = 0;
608         int     i;
609         BOOL    is_our_domain;
610
611
612         is_our_domain = strequal(domain->name, lp_workgroup());
613
614         if ( !is_our_domain 
615                 && get_dc_name_via_netlogon(domain, dcname, &ip) 
616                 && add_one_dc_unique(mem_ctx, domain->name, dcname, ip, dcs, num_dcs) )
617         {
618                 return True;
619         }
620
621         if ( is_our_domain 
622                 && must_use_pdc(domain->name) 
623                 && get_pdc_ip(domain->name, &ip)) 
624         {
625                 if (add_one_dc_unique(mem_ctx, domain->name, inet_ntoa(ip), ip, dcs, num_dcs)) 
626                         return True;
627         }
628
629         /* try standard netbios queries first */
630
631         get_sorted_dc_list(domain->name, &ip_list, &iplist_size, False);
632
633         /* check for security = ads and use DNS if we can */
634
635         if ( iplist_size==0 && lp_security() == SEC_ADS ) 
636                 get_sorted_dc_list(domain->alt_name, &ip_list, &iplist_size, True);
637
638         /* FIXME!! this is where we should re-insert the GETDC requests --jerry */
639
640         /* now add to the dc array.  We'll wait until the last minute 
641            to look up the name of the DC.  But we fill in the char* for 
642            the ip now in to make the failed connection cache work */
643
644         for ( i=0; i<iplist_size; i++ ) {
645                 add_one_dc_unique(mem_ctx, domain->name, inet_ntoa(ip_list[i].ip), 
646                         ip_list[i].ip, dcs, num_dcs);
647         }
648
649         SAFE_FREE( ip_list );
650
651         return True;
652 }
653
654 static BOOL find_new_dc(TALLOC_CTX *mem_ctx,
655                         const struct winbindd_domain *domain,
656                         fstring dcname, struct sockaddr_in *addr, int *fd)
657 {
658         struct dc_name_ip *dcs = NULL;
659         int num_dcs = 0;
660
661         const char **dcnames = NULL;
662         int num_dcnames = 0;
663
664         struct sockaddr_in *addrs = NULL;
665         int num_addrs = 0;
666
667         int i, fd_index;
668
669         if (!get_dcs(mem_ctx, domain, &dcs, &num_dcs) || (num_dcs == 0))
670                 return False;
671
672         for (i=0; i<num_dcs; i++) {
673
674                 add_string_to_array(mem_ctx, dcs[i].name,
675                                     &dcnames, &num_dcnames);
676                 add_sockaddr_to_array(mem_ctx, dcs[i].ip, 445,
677                                       &addrs, &num_addrs);
678
679                 add_string_to_array(mem_ctx, dcs[i].name,
680                                     &dcnames, &num_dcnames);
681                 add_sockaddr_to_array(mem_ctx, dcs[i].ip, 139,
682                                       &addrs, &num_addrs);
683         }
684
685         if ((num_dcnames == 0) || (num_dcnames != num_addrs))
686                 return False;
687
688         if ( !open_any_socket_out(addrs, num_addrs, 10000, &fd_index, fd) ) 
689         {
690                 for (i=0; i<num_dcs; i++) {
691                         add_failed_connection_entry(domain->name,
692                                 dcs[i].name, NT_STATUS_UNSUCCESSFUL);
693                 }
694                 return False;
695         }
696
697         *addr = addrs[fd_index];
698
699         /* if we have no name on the server or just an IP address for 
700            the name, now try to get the name */
701
702         if ( is_ipaddress(dcnames[fd_index]) || *dcnames[fd_index] == '\0' )
703                 dcip_to_name( domain->name, domain->alt_name, &domain->sid, addr->sin_addr, dcname );
704         else
705                 fstrcpy(dcname, dcnames[fd_index]);
706
707         return True;
708 }
709
710 static NTSTATUS cm_open_connection(struct winbindd_domain *domain,
711                                    struct winbindd_cm_conn *new_conn)
712 {
713         TALLOC_CTX *mem_ctx;
714         NTSTATUS result;
715
716         int retries;
717
718         if ((mem_ctx = talloc_init("cm_open_connection")) == NULL)
719                 return NT_STATUS_NO_MEMORY;
720
721         for (retries = 0; retries < 3; retries++) {
722
723                 int fd = -1;
724                 BOOL retry;
725
726                 result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
727
728                 if ((strlen(domain->dcname) > 0) &&
729                     NT_STATUS_IS_OK(check_negative_conn_cache(domain->name,
730                                                               domain->dcname))) {
731                         int dummy;
732                         if (!open_any_socket_out(&domain->dcaddr, 1, 10000,
733                                                  &dummy, &fd)) {
734                                 fd = -1;
735                         }
736                 }
737
738                 if ((fd == -1) &&
739                     !find_new_dc(mem_ctx, domain, domain->dcname,
740                                  &domain->dcaddr, &fd))
741                         break;
742
743                 new_conn->cli = NULL;
744
745                 result = cm_prepare_connection(domain, fd, domain->dcname,
746                         &new_conn->cli, &retry);
747
748                 if (!retry)
749                         break;
750         }
751
752         talloc_destroy(mem_ctx);
753         return result;
754 }
755
756 /* Return true if a connection is still alive */
757
758 void invalidate_cm_connection(struct winbindd_cm_conn *conn)
759 {
760         if (conn->samr_pipe != NULL) {
761                 cli_rpc_close(conn->samr_pipe);
762                 conn->samr_pipe = NULL;
763         }
764
765         if (conn->lsa_pipe != NULL) {
766                 cli_rpc_close(conn->lsa_pipe);
767                 conn->lsa_pipe = NULL;
768         }
769
770         if (conn->netlogon_auth2_pipe != NULL) {
771                 cli_rpc_close(conn->netlogon_auth2_pipe);
772                 conn->netlogon_auth2_pipe = NULL;
773         }
774
775         if (conn->netlogon_pipe != NULL) {
776                 cli_rpc_close(conn->netlogon_pipe);
777                 conn->netlogon_pipe = NULL;
778         }
779
780         if (conn->cli)
781                 cli_shutdown(conn->cli);
782
783         conn->cli = NULL;
784 }
785
786 void close_conns_after_fork(void)
787 {
788         struct winbindd_domain *domain;
789
790         for (domain = domain_list(); domain; domain = domain->next) {
791                 if (domain->conn.cli == NULL)
792                         continue;
793
794                 if (domain->conn.cli->fd == -1)
795                         continue;
796
797                 close(domain->conn.cli->fd);
798                 domain->conn.cli->fd = -1;
799         }
800 }
801
802 static BOOL connection_ok(struct winbindd_domain *domain)
803 {
804         if (domain->conn.cli == NULL) {
805                 DEBUG(8, ("Connection to %s for domain %s has NULL "
806                           "cli!\n", domain->dcname, domain->name));
807                 return False;
808         }
809
810         if (!domain->conn.cli->initialised) {
811                 DEBUG(3, ("Connection to %s for domain %s was never "
812                           "initialised!\n", domain->dcname, domain->name));
813                 return False;
814         }
815
816         if (domain->conn.cli->fd == -1) {
817                 DEBUG(3, ("Connection to %s for domain %s has died or was "
818                           "never started (fd == -1)\n", 
819                           domain->dcname, domain->name));
820                 return False;
821         }
822
823         return True;
824 }
825         
826 /* Initialize a new connection up to the RPC BIND. */
827
828 static NTSTATUS init_dc_connection(struct winbindd_domain *domain)
829 {
830         if (connection_ok(domain))
831                 return NT_STATUS_OK;
832
833         invalidate_cm_connection(&domain->conn);
834
835         return cm_open_connection(domain, &domain->conn);
836 }
837
838 /**********************************************************************************
839  We can 'sense' certain things about the DC by it's replies to certain questions.
840
841  This tells us if this particular remote server is Active Directory, and if it is
842  native mode.
843 **********************************************************************************/
844
845 void set_dc_type_and_flags( struct winbindd_domain *domain )
846 {
847         NTSTATUS                result;
848         DS_DOMINFO_CTR          ctr;
849         TALLOC_CTX              *mem_ctx = NULL;
850         struct rpc_pipe_client  *cli;
851         POLICY_HND pol;
852         
853         char *domain_name = NULL;
854         char *dns_name = NULL;
855         DOM_SID *dom_sid = NULL;
856
857         ZERO_STRUCT( ctr );
858         
859         domain->native_mode = False;
860         domain->active_directory = False;
861
862         if (domain->internal) {
863                 domain->initialized = True;
864                 return;
865         }
866
867         result = init_dc_connection(domain);
868         if (!NT_STATUS_IS_OK(result)) {
869                 DEBUG(5, ("set_dc_type_and_flags: Could not open a connection "
870                           "to %s: (%s)\n", domain->name, nt_errstr(result)));
871                 domain->initialized = True;
872                 return;
873         }
874
875         cli = cli_rpc_open_noauth(domain->conn.cli, PI_LSARPC_DS);
876
877         if (cli == NULL) {
878                 DEBUG(5, ("set_dc_type_and_flags: Could not bind to "
879                           "PI_LSARPC_DS on domain %s: (%s)\n",
880                           domain->name, nt_errstr(result)));
881                 domain->initialized = True;
882                 return;
883         }
884
885         result = rpccli_ds_getprimarydominfo(cli, cli->cli->mem_ctx,
886                                              DsRolePrimaryDomainInfoBasic,
887                                              &ctr);
888         cli_rpc_close(cli);
889
890         if (!NT_STATUS_IS_OK(result)) {
891                 domain->initialized = True;
892                 return;
893         }
894         
895         if ((ctr.basic->flags & DSROLE_PRIMARY_DS_RUNNING) &&
896             !(ctr.basic->flags & DSROLE_PRIMARY_DS_MIXED_MODE) )
897                 domain->native_mode = True;
898
899         cli = cli_rpc_open_noauth(domain->conn.cli, PI_LSARPC);
900
901         if (cli == NULL) {
902                 domain->initialized = True;
903                 return;
904         }
905
906         mem_ctx = talloc_init("set_dc_type_and_flags on domain %s\n",
907                               domain->name);
908         if (!mem_ctx) {
909                 DEBUG(1, ("set_dc_type_and_flags: talloc_init() failed\n"));
910                 return;
911         }
912
913         result = rpccli_lsa_open_policy2(cli, mem_ctx, True, 
914                                          SEC_RIGHTS_MAXIMUM_ALLOWED, &pol);
915                 
916         if (NT_STATUS_IS_OK(result)) {
917                 /* This particular query is exactly what Win2k clients use 
918                    to determine that the DC is active directory */
919                 result = rpccli_lsa_query_info_policy2(cli, mem_ctx, &pol,
920                                                        12, &domain_name,
921                                                        &dns_name, NULL,
922                                                        NULL, &dom_sid);
923         }
924
925         if (NT_STATUS_IS_OK(result)) {
926                 if (domain_name)
927                         fstrcpy(domain->name, domain_name);
928
929                 if (dns_name)
930                         fstrcpy(domain->alt_name, dns_name);
931
932                 if (dom_sid) 
933                         sid_copy(&domain->sid, dom_sid);
934
935                 domain->active_directory = True;
936         } else {
937                 
938                 result = rpccli_lsa_open_policy(cli, mem_ctx, True, 
939                                                 SEC_RIGHTS_MAXIMUM_ALLOWED,
940                                                 &pol);
941                         
942                 if (!NT_STATUS_IS_OK(result))
943                         goto done;
944                         
945                 result = rpccli_lsa_query_info_policy(cli, mem_ctx, 
946                                                       &pol, 5, &domain_name, 
947                                                       &dom_sid);
948                         
949                 if (NT_STATUS_IS_OK(result)) {
950                         if (domain_name)
951                                 fstrcpy(domain->name, domain_name);
952
953                         if (dom_sid) 
954                                 sid_copy(&domain->sid, dom_sid);
955                 }
956         }
957 done:
958
959         cli_rpc_close(cli);
960         
961         talloc_destroy(mem_ctx);
962
963         domain->initialized = True;
964         
965         return;
966 }
967
968 static BOOL cm_get_schannel_key(struct winbindd_domain *domain,
969                                 TALLOC_CTX *mem_ctx,
970                                 unsigned char **session_key)
971 {
972         struct rpc_pipe_client *cli;
973         DOM_CRED *credentials;
974
975         if (lp_client_schannel() == False)
976                 return False;
977
978         return NT_STATUS_IS_OK(cm_connect_netlogon(domain, mem_ctx,
979                                                    &cli, session_key,
980                                                    &credentials));
981 }
982
983 NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
984                         struct rpc_pipe_client **cli, POLICY_HND *sam_handle)
985 {
986         struct winbindd_cm_conn *conn;
987         NTSTATUS result;
988
989         result = init_dc_connection(domain);
990         if (!NT_STATUS_IS_OK(result))
991                 return result;
992
993         conn = &domain->conn;
994
995         if (conn->samr_pipe == NULL) {
996 #ifndef DISABLE_SCHANNEL_WIN2K3_SP1
997                 unsigned char *session_key;
998
999                 if (cm_get_schannel_key(domain, mem_ctx, &session_key))
1000                         conn->samr_pipe = cli_rpc_open_schannel(conn->cli,
1001                                                                 PI_SAMR,
1002                                                                 session_key,
1003                                                                 domain->name);
1004                 else
1005 #endif  /* DISABLE_SCHANNEL_WIN2K3_SP1 */
1006                         conn->samr_pipe = cli_rpc_open_noauth(conn->cli,
1007                                                               PI_SAMR);
1008
1009                 if (conn->samr_pipe == NULL) {
1010                         result = NT_STATUS_PIPE_NOT_AVAILABLE;
1011                         goto done;
1012                 }
1013
1014                 result = rpccli_samr_connect(conn->samr_pipe, mem_ctx,
1015                                              SEC_RIGHTS_MAXIMUM_ALLOWED,
1016                                              &conn->sam_connect_handle);
1017                 if (!NT_STATUS_IS_OK(result))
1018                         goto done;
1019
1020                 result = rpccli_samr_open_domain(conn->samr_pipe,
1021                                                  mem_ctx,
1022                                                  &conn->sam_connect_handle,
1023                                                  SEC_RIGHTS_MAXIMUM_ALLOWED,
1024                                                  &domain->sid,
1025                                                  &conn->sam_domain_handle);
1026         }
1027
1028  done:
1029         if (!NT_STATUS_IS_OK(result)) {
1030                 invalidate_cm_connection(conn);
1031                 return NT_STATUS_UNSUCCESSFUL;
1032         }
1033
1034         *cli = conn->samr_pipe;
1035         *sam_handle = conn->sam_domain_handle;
1036         return result;
1037 }
1038
1039 NTSTATUS cm_connect_lsa(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
1040                         struct rpc_pipe_client **cli, POLICY_HND *lsa_policy)
1041 {
1042         struct winbindd_cm_conn *conn;
1043         NTSTATUS result;
1044
1045         result = init_dc_connection(domain);
1046         if (!NT_STATUS_IS_OK(result))
1047                 return result;
1048
1049         conn = &domain->conn;
1050
1051         if (conn->lsa_pipe == NULL) {
1052 #ifndef DISABLE_SCHANNEL_WIN2K3_SP1
1053                 unsigned char *session_key;
1054
1055                 if (cm_get_schannel_key(domain, mem_ctx, &session_key))
1056                         conn->lsa_pipe = cli_rpc_open_schannel(conn->cli,
1057                                                                PI_LSARPC,
1058                                                                session_key,
1059                                                                domain->name);
1060                 else
1061 #endif  /* DISABLE_SCHANNEL_WIN2K3_SP1 */
1062                         conn->lsa_pipe = cli_rpc_open_noauth(conn->cli,
1063                                                              PI_LSARPC);
1064
1065                 if (conn->lsa_pipe == NULL) {
1066                         result = NT_STATUS_PIPE_NOT_AVAILABLE;
1067                         goto done;
1068                 }
1069
1070                 result = rpccli_lsa_open_policy(conn->lsa_pipe, mem_ctx, True,
1071                                                 SEC_RIGHTS_MAXIMUM_ALLOWED,
1072                                                 &conn->lsa_policy);
1073         }
1074
1075  done:
1076         if (!NT_STATUS_IS_OK(result)) {
1077                 invalidate_cm_connection(conn);
1078                 return NT_STATUS_UNSUCCESSFUL;
1079         }
1080
1081         *cli = conn->lsa_pipe;
1082         *lsa_policy = conn->lsa_policy;
1083         return result;
1084 }
1085
1086 /*******************************************************************
1087  wrapper around retrieving the trust account password
1088 *******************************************************************/
1089
1090 static BOOL get_trust_pw(const char *domain, uint8 ret_pwd[16],
1091                          uint32 *channel)
1092 {
1093         DOM_SID sid;
1094         char *pwd;
1095         time_t last_set_time;
1096
1097         /* if we are a DC and this is not our domain, then lookup an account
1098            for the domain trust */
1099
1100         if ( IS_DC && !strequal(domain, lp_workgroup()) &&
1101              lp_allow_trusted_domains() ) {
1102
1103                 if (!secrets_fetch_trusted_domain_password(domain, &pwd, &sid,
1104                                                            &last_set_time)) {
1105                         DEBUG(0, ("get_trust_pw: could not fetch trust "
1106                                   "account password for trusted domain %s\n",
1107                                   domain));
1108                         return False;
1109                 }
1110
1111                 *channel = SEC_CHAN_DOMAIN;
1112                 E_md4hash(pwd, ret_pwd);
1113                 SAFE_FREE(pwd);
1114
1115                 return True;
1116         }
1117
1118         /* Just get the account for the requested domain. In the future this
1119          * might also cover to be member of more than one domain. */
1120
1121         if (secrets_fetch_trust_account_password(domain, ret_pwd,
1122                                                  &last_set_time, channel))
1123                 return True;
1124
1125         DEBUG(5, ("get_trust_pw: could not fetch trust account "
1126                   "password for domain %s\n", domain));
1127         return False;
1128 }
1129
1130 NTSTATUS cm_connect_netlogon(struct winbindd_domain *domain,
1131                              TALLOC_CTX *mem_ctx,
1132                              struct rpc_pipe_client **cli,
1133                              unsigned char **session_key,
1134                              DOM_CRED **credentials)
1135 {
1136         struct winbindd_cm_conn *conn;
1137         NTSTATUS result;
1138
1139         uint32 neg_flags = NETLOGON_NEG_AUTH2_FLAGS;
1140         uint8  mach_pwd[16];
1141         uint32  sec_chan_type;
1142         DOM_CHAL clnt_chal, srv_chal, rcv_chal;
1143         const char *server_name;
1144         const char *account_name;
1145         UTIME zerotime;
1146
1147         result = init_dc_connection(domain);
1148         if (!NT_STATUS_IS_OK(result))
1149                 return result;
1150
1151         conn = &domain->conn;
1152
1153         if (conn->netlogon_pipe != NULL) {
1154                 *cli = conn->netlogon_pipe;
1155                 *session_key = (unsigned char *)&conn->sess_key;
1156                 *credentials = &conn->clnt_cred;
1157                 return NT_STATUS_OK;
1158         }
1159
1160         if (!get_trust_pw(domain->name, mach_pwd, &sec_chan_type))
1161                 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1162
1163         conn->netlogon_auth2_pipe = cli_rpc_open_noauth(conn->cli,
1164                                                         PI_NETLOGON);
1165         if (conn->netlogon_auth2_pipe == NULL)
1166                 return NT_STATUS_UNSUCCESSFUL;
1167
1168         if (lp_client_schannel() != False)
1169                 neg_flags |= NETLOGON_NEG_SCHANNEL;
1170
1171         generate_random_buffer(clnt_chal.data, 8);
1172
1173         server_name = talloc_asprintf(mem_ctx, "\\\\%s", domain->dcname);
1174
1175         /* if we are a DC and this is a trusted domain, then we need to use our
1176            domain name in the net_req_auth2() request */
1177
1178         if ( IS_DC ) {
1179                 account_name = talloc_asprintf( mem_ctx, "%s$", lp_workgroup() );
1180         }
1181         else {
1182                 account_name = talloc_asprintf(mem_ctx, "%s$", 
1183                         domain->primary ?  global_myname() : domain->name);
1184         }
1185
1186         if ((server_name == NULL) || (account_name == NULL))
1187                 return NT_STATUS_NO_MEMORY;
1188
1189         result = rpccli_net_req_chal(conn->netlogon_auth2_pipe, server_name,
1190                                      global_myname(), &clnt_chal, &srv_chal);
1191         if (!NT_STATUS_IS_OK(result))
1192                 return result;
1193
1194         /**************** Long-term Session key **************/
1195
1196         /* calculate the session key */
1197         cred_session_key(&clnt_chal, &srv_chal, mach_pwd, conn->sess_key);
1198         memset((char *)conn->sess_key+8, '\0', 8);
1199
1200         /* calculate auth2 credentials */
1201         zerotime.time = 0;
1202         cred_create(conn->sess_key, &clnt_chal, zerotime,
1203                     &conn->clnt_cred.challenge);
1204
1205         result = rpccli_net_auth2(conn->netlogon_auth2_pipe, server_name,
1206                                   account_name, sec_chan_type, global_myname(),
1207                                   &conn->clnt_cred.challenge, &neg_flags,
1208                                   &rcv_chal);
1209
1210         if (!NT_STATUS_IS_OK(result))
1211                 return result;
1212
1213         zerotime.time = 0;
1214         if (!cred_assert(&rcv_chal, conn->sess_key, &srv_chal, zerotime)) {
1215                 DEBUG(0, ("Server replied with bad credential\n"));
1216                 return NT_STATUS_ACCESS_DENIED;
1217         }
1218
1219         if ((lp_client_schannel() == True) &&
1220             ((neg_flags & NETLOGON_NEG_SCHANNEL) == 0)) {
1221                 DEBUG(3, ("Server did not offer schannel\n"));
1222                 cli_rpc_close(conn->netlogon_auth2_pipe);
1223                 conn->netlogon_auth2_pipe = NULL;
1224                 return NT_STATUS_ACCESS_DENIED;
1225         }
1226
1227         if ((lp_client_schannel() == False) ||
1228             ((neg_flags & NETLOGON_NEG_SCHANNEL) == 0)) {
1229                 /* keep the existing connection to NETLOGON open */
1230                 conn->netlogon_pipe = conn->netlogon_auth2_pipe;
1231                 conn->netlogon_auth2_pipe = NULL;
1232                 *cli = conn->netlogon_pipe;
1233                 *session_key = (unsigned char *)&conn->sess_key;
1234                 *credentials = &conn->clnt_cred;
1235                 return NT_STATUS_OK;
1236         }
1237
1238         conn->netlogon_pipe = cli_rpc_open_schannel(conn->cli, PI_NETLOGON,
1239                                                     conn->sess_key,
1240                                                     domain->name);
1241
1242         if (conn->netlogon_pipe == NULL) {
1243                 DEBUG(3, ("Could not open schannel'ed NETLOGON pipe\n"));
1244                 cli_rpc_close(conn->netlogon_auth2_pipe);
1245                 conn->netlogon_auth2_pipe = NULL;
1246                 return NT_STATUS_ACCESS_DENIED;
1247         }
1248
1249         *cli = conn->netlogon_pipe;
1250         *session_key = (unsigned char *)&conn->sess_key;
1251         *credentials = &conn->clnt_cred;
1252                 
1253         return NT_STATUS_OK;
1254 }