r5336: BUG 2329: fix to re-enable winbindd to locate DC's when 'disable netbios ...
[samba.git] / source3 / nsswitch / winbindd_cm.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    Winbind daemon connection manager
5
6    Copyright (C) Tim Potter 2001
7    Copyright (C) Andrew Bartlett 2002
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 /*
25    We need to manage connections to domain controllers without having to
26    mess up the main winbindd code with other issues.  The aim of the
27    connection manager is to:
28   
29        - make connections to domain controllers and cache them
30        - re-establish connections when networks or servers go down
31        - centralise the policy on connection timeouts, domain controller
32          selection etc
33        - manage re-entrancy for when winbindd becomes able to handle
34          multiple outstanding rpc requests
35   
36    Why not have connection management as part of the rpc layer like tng?
37    Good question.  This code may morph into libsmb/rpc_cache.c or something
38    like that but at the moment it's simply staying as part of winbind.  I
39    think the TNG architecture of forcing every user of the rpc layer to use
40    the connection caching system is a bad idea.  It should be an optional
41    method of using the routines.
42
43    The TNG design is quite good but I disagree with some aspects of the
44    implementation. -tpot
45
46  */
47
48 /*
49    TODO:
50
51      - I'm pretty annoyed by all the make_nmb_name() stuff.  It should be
52        moved down into another function.
53
54      - Take care when destroying cli_structs as they can be shared between
55        various sam handles.
56
57  */
58
59 #include "includes.h"
60 #include "winbindd.h"
61
62 #undef DBGC_CLASS
63 #define DBGC_CLASS DBGC_WINBIND
64
65 /* Global list of connections.  Initially a DLIST but can become a hash
66    table or whatever later. */
67
68 struct winbindd_cm_conn {
69         struct winbindd_cm_conn *prev, *next;
70         fstring domain;
71         fstring controller;
72         fstring pipe_name;
73         struct cli_state *cli;
74         POLICY_HND pol;
75 };
76
77 static struct winbindd_cm_conn *cm_conns = NULL;
78
79 static NTSTATUS get_connection_from_cache(struct winbindd_domain *domain,
80                                           const char *pipe_name,
81                                           struct winbindd_cm_conn **conn_out);
82
83 /* Choose between anonymous or authenticated connections.  We need to use
84    an authenticated connection if DCs have the RestrictAnonymous registry
85    entry set > 0, or the "Additional restrictions for anonymous
86    connections" set in the win2k Local Security Policy. 
87    
88    Caller to free() result in domain, username, password
89 */
90
91 static void cm_get_ipc_userpass(char **username, char **domain, char **password)
92 {
93         *username = secrets_fetch(SECRETS_AUTH_USER, NULL);
94         *domain = secrets_fetch(SECRETS_AUTH_DOMAIN, NULL);
95         *password = secrets_fetch(SECRETS_AUTH_PASSWORD, NULL);
96         
97         if (*username && **username) {
98
99                 if (!*domain || !**domain)
100                         *domain = smb_xstrdup(lp_workgroup());
101                 
102                 if (!*password || !**password)
103                         *password = smb_xstrdup("");
104
105                 DEBUG(3, ("IPC$ connections done by user %s\\%s\n", 
106                           *domain, *username));
107
108         } else {
109                 DEBUG(3, ("IPC$ connections done anonymously\n"));
110                 *username = smb_xstrdup("");
111                 *domain = smb_xstrdup("");
112                 *password = smb_xstrdup("");
113         }
114 }
115
116 /*
117   setup for schannel on any pipes opened on this connection
118 */
119 static NTSTATUS setup_schannel( struct cli_state *cli, const char *domain )
120 {
121         NTSTATUS ret;
122         uchar trust_password[16];
123         uint32 sec_channel_type;
124         DOM_SID sid;
125         time_t lct;
126
127         /* use the domain trust password if we're on a DC 
128            and this is not our domain */
129         
130         if ( IS_DC && !strequal(domain, lp_workgroup()) ) {
131                 char *pass = NULL;
132                 
133                 if ( !secrets_fetch_trusted_domain_password( domain, 
134                         &pass, &sid, &lct) )
135                 {
136                         return NT_STATUS_UNSUCCESSFUL;
137                 }       
138
139                 sec_channel_type = SEC_CHAN_DOMAIN;
140                 E_md4hash(pass, trust_password);
141                 SAFE_FREE( pass );
142                 
143         } else {
144                 if (!secrets_fetch_trust_account_password(lp_workgroup(),
145                         trust_password, NULL, &sec_channel_type)) 
146                 {
147                         return NT_STATUS_UNSUCCESSFUL;
148                 }
149         }
150
151         ret = cli_nt_setup_netsec(cli, sec_channel_type, 
152                 AUTH_PIPE_NETSEC | AUTH_PIPE_SIGN, trust_password);
153
154         return ret;
155 }
156
157 static BOOL get_dc_name_via_netlogon(const struct winbindd_domain *domain,
158                                      fstring dcname, struct in_addr *dc_ip)
159 {
160         struct winbindd_domain *our_domain;
161         NTSTATUS result;
162         struct winbindd_cm_conn *conn;
163         TALLOC_CTX *mem_ctx;
164
165         fstring tmp;
166         char *p;
167
168         if (IS_DC)
169                 return False;
170
171         if (domain->primary)
172                 return False;
173
174         if ((our_domain = find_our_domain()) == NULL)
175                 return False;
176
177         result = get_connection_from_cache(our_domain, PIPE_NETLOGON, &conn);
178         if (!NT_STATUS_IS_OK(result))
179                 return False;
180
181         if ((mem_ctx = talloc_init("get_dc_name_via_netlogon")) == NULL)
182                 return False;
183
184         result = cli_netlogon_getdcname(conn->cli, mem_ctx, domain->name, tmp);
185
186         talloc_destroy(mem_ctx);
187
188         if (!NT_STATUS_IS_OK(result))
189                 return False;
190
191         /* cli_netlogon_getdcname gives us a name with \\ */
192         p = tmp;
193         if (*p == '\\') p+=1;
194         if (*p == '\\') p+=1;
195
196         fstrcpy(dcname, p);
197
198         if (!resolve_name(dcname, dc_ip, 0x20))
199                 return False;
200
201         return True;
202 }
203
204 /************************************************************************
205  Given a fd with a just-connected TCP connection to a DC, open a connection
206  to the pipe.
207 ************************************************************************/
208
209 static NTSTATUS cm_prepare_connection(const struct winbindd_domain *domain,
210                                       const int sockfd,
211                                       const int pipe_index,
212                                       const char *controller,
213                                       struct cli_state **cli,
214                                       BOOL *retry)
215 {
216         char *machine_password, *machine_krb5_principal;
217         char *ipc_username, *ipc_domain, *ipc_password;
218
219         BOOL got_mutex;
220         BOOL add_failed_connection = True;
221
222         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
223
224         struct sockaddr peeraddr;
225         socklen_t peeraddr_len;
226
227         struct sockaddr_in *peeraddr_in = (struct sockaddr_in *)&peeraddr;
228
229         machine_password = secrets_fetch_machine_password(lp_workgroup(), NULL,
230                                                           NULL);
231         
232         if (asprintf(&machine_krb5_principal, "%s$@%s", global_myname(),
233                      lp_realm()) == -1) {
234                 SAFE_FREE(machine_password);
235                 return NT_STATUS_NO_MEMORY;
236         }
237
238         cm_get_ipc_userpass(&ipc_username, &ipc_domain, &ipc_password);
239
240         *retry = True;
241
242         got_mutex = secrets_named_mutex(controller,
243                                         WINBIND_SERVER_MUTEX_WAIT_TIME);
244
245         if (!got_mutex) {
246                 DEBUG(0,("cm_open_connection: mutex grab failed for %s\n",
247                          controller));
248                 result = NT_STATUS_POSSIBLE_DEADLOCK;
249                 goto done;
250         }
251
252         if ((*cli = cli_initialise(NULL)) == NULL) {
253                 DEBUG(1, ("Could not cli_initialize\n"));
254                 result = NT_STATUS_NO_MEMORY;
255                 goto done;
256         }
257
258         (*cli)->timeout = 10000;        /* 10 seconds */
259         (*cli)->fd = sockfd;
260         fstrcpy((*cli)->desthost, controller);
261         (*cli)->use_kerberos = True;
262
263         peeraddr_len = sizeof(peeraddr);
264
265         if ((getpeername((*cli)->fd, &peeraddr, &peeraddr_len) != 0) ||
266             (peeraddr_len != sizeof(struct sockaddr_in)) ||
267             (peeraddr_in->sin_family != PF_INET))
268         {
269                 DEBUG(0,("cm_prepare_connection: %s\n", strerror(errno)));
270                 goto done;
271         }
272
273         if (ntohs(peeraddr_in->sin_port) == 139) {
274                 struct nmb_name calling;
275                 struct nmb_name called;
276
277                 make_nmb_name(&calling, global_myname(), 0x0);
278                 make_nmb_name(&called, "*SMBSERVER", 0x20);
279
280                 if (!cli_session_request(*cli, &calling, &called)) {
281                         DEBUG(8, ("cli_session_request failed for %s\n",
282                                   controller));
283                         goto done;
284                 }
285         }
286
287         cli_setup_signing_state(*cli, Undefined);
288
289         if (!cli_negprot(*cli)) {
290                 DEBUG(1, ("cli_negprot failed\n"));
291                 cli_shutdown(*cli);
292                 goto done;
293         }
294
295         /* Krb5 session */
296                         
297         if ((lp_security() == SEC_ADS) 
298             && ((*cli)->protocol >= PROTOCOL_NT1 &&
299                 (*cli)->capabilities & CAP_EXTENDED_SECURITY)) {
300
301                 ADS_STATUS ads_status;
302                 (*cli)->use_kerberos = True;
303                 DEBUG(5, ("connecting to %s from %s with kerberos principal "
304                           "[%s]\n", controller, global_myname(),
305                           machine_krb5_principal));
306
307                 ads_status = cli_session_setup_spnego(*cli,
308                                                       machine_krb5_principal, 
309                                                       machine_password, 
310                                                       lp_workgroup());
311
312                 if (!ADS_ERR_OK(ads_status))
313                         DEBUG(4,("failed kerberos session setup with %s\n",
314                                  ads_errstr(ads_status)));
315
316                 result = ads_ntstatus(ads_status);
317         }
318
319         if (NT_STATUS_IS_OK(result))
320                 goto session_setup_done;
321
322         /* Fall back to non-kerberos session setup */
323
324         (*cli)->use_kerberos = False;
325
326         if ((((*cli)->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) != 0) &&
327             (strlen(ipc_username) > 0)) {
328
329                 /* Only try authenticated if we have a username */
330
331                 DEBUG(5, ("connecting to %s from %s with username "
332                           "[%s]\\[%s]\n",  controller, global_myname(),
333                           ipc_domain, ipc_username));
334
335                 if (cli_session_setup(*cli, ipc_username,
336                                       ipc_password, strlen(ipc_password)+1,
337                                       ipc_password, strlen(ipc_password)+1,
338                                       ipc_domain)) {
339                         DEBUG(5, ("authenticated session setup failed\n"));
340                         goto session_setup_done;
341                 }
342         }
343
344         /* Fall back to anonymous connection, this might fail later */
345
346         if (cli_session_setup(*cli, "", NULL, 0, NULL, 0, "")) {
347                 DEBUG(5, ("Connected anonymously\n"));
348                 goto session_setup_done;
349         }
350
351         result = cli_nt_error(*cli);
352
353         if (NT_STATUS_IS_OK(result))
354                 result = NT_STATUS_UNSUCCESSFUL;
355
356         /* We can't session setup */
357
358         goto done;
359
360  session_setup_done:
361
362         if (!cli_send_tconX(*cli, "IPC$", "IPC", "", 0)) {
363
364                 result = cli_nt_error(*cli);
365
366                 DEBUG(1,("failed tcon_X with %s\n", nt_errstr(result)));
367
368                 if (NT_STATUS_IS_OK(result))
369                         result = NT_STATUS_UNSUCCESSFUL;
370
371                 cli_shutdown(*cli);
372                 goto done;
373         }
374
375         secrets_named_mutex_release(controller);
376         got_mutex = False;
377         *retry = False;
378
379         if (domain->primary || IS_DC) {
380                 NTSTATUS status = setup_schannel( *cli, domain->name );
381                 if (!NT_STATUS_IS_OK(status)) {
382                         DEBUG(3,("schannel refused - continuing without "
383                                  "schannel (%s)\n", nt_errstr(status)));
384                 }
385         }
386
387         /* set the domain if empty; needed for schannel connections */
388         if ( !*(*cli)->domain )
389                 fstrcpy( (*cli)->domain, domain->name );
390
391         if ( !cli_nt_session_open (*cli, pipe_index) ) {
392
393                 result = NT_STATUS_PIPE_NOT_AVAILABLE;
394
395                 /* This might be a NT4 DC */
396                 if ( is_win2k_pipe(pipe_index) )
397                         add_failed_connection = False;
398
399                 cli_shutdown(*cli);
400                 goto done;
401         }
402
403         result = NT_STATUS_OK;
404         add_failed_connection = False;
405
406  done:
407         if (got_mutex)
408                 secrets_named_mutex_release(controller);
409
410         SAFE_FREE(machine_password);
411         SAFE_FREE(machine_krb5_principal);
412         SAFE_FREE(ipc_username);
413         SAFE_FREE(ipc_domain);
414         SAFE_FREE(ipc_password);
415
416         if (add_failed_connection)
417                 add_failed_connection_entry(domain->name, controller, result);
418
419         return result;
420 }
421
422 struct dc_name_ip {
423         fstring name;
424         struct in_addr ip;
425 };
426
427 static BOOL add_one_dc_unique(TALLOC_CTX *mem_ctx, const char *domain_name,
428                               const char *dcname, struct in_addr ip,
429                               struct dc_name_ip **dcs, int *num)
430 {
431         if (!NT_STATUS_IS_OK(check_negative_conn_cache(domain_name, dcname)))
432                 return False;
433
434         *dcs = TALLOC_REALLOC_ARRAY(mem_ctx, *dcs, struct dc_name_ip, (*num)+1);
435
436         if (*dcs == NULL)
437                 return False;
438
439         fstrcpy((*dcs)[*num].name, dcname);
440         (*dcs)[*num].ip = ip;
441         *num += 1;
442         return True;
443 }
444
445 static BOOL add_sockaddr_to_array(TALLOC_CTX *mem_ctx,
446                                   struct in_addr ip, uint16 port,
447                                   struct sockaddr_in **addrs, int *num)
448 {
449         *addrs = TALLOC_REALLOC_ARRAY(mem_ctx, *addrs, struct sockaddr_in, (*num)+1);
450
451         if (*addrs == NULL)
452                 return False;
453
454         (*addrs)[*num].sin_family = PF_INET;
455         putip((char *)&((*addrs)[*num].sin_addr), (char *)&ip);
456         (*addrs)[*num].sin_port = htons(port);
457
458         *num += 1;
459         return True;
460 }
461
462 /*******************************************************************
463  convert an ip to a name
464 *******************************************************************/
465
466 static void dcip_to_name( const char *domainname, const char *realm, struct in_addr ip, fstring name )
467 {
468         /* try node status request first */
469
470         if ( name_status_find(domainname, 0x1c, 0x20, ip, name) )
471                 return;
472
473         /* backup in case the ads stuff fails */
474
475         fstrcpy( name, inet_ntoa(ip) );
476
477 #ifdef WITH_ADS
478         /* for active directory servers, try to get the ldap server name.
479            None of these failure should be considered critical for now */
480
481         if ( lp_security() == SEC_ADS ) 
482         {
483                 ADS_STRUCT *ads;
484                 ADS_STATUS status;
485
486                 ads = ads_init( realm, domainname, NULL );
487                 ads->auth.flags |= ADS_AUTH_NO_BIND;
488
489                 if ( !ads_try_connect( ads, inet_ntoa(ip), LDAP_PORT ) )  {
490                         ads_destroy( &ads );
491                         return;
492                 }
493
494                 status = ads_server_info(ads);
495                 if ( !ADS_ERR_OK(status) ) {
496                         ads_destroy( &ads );
497                         return;
498                 }
499
500                 fstrcpy(name, ads->config.ldap_server_name);
501
502                 ads_destroy( &ads );
503         }
504 #endif
505
506         return;
507 }
508
509
510 /*******************************************************************
511  Retreive a list of IP address for domain controllers.  Fill in 
512  the dcs[]  with results.
513 *******************************************************************/
514
515 static BOOL get_dcs(TALLOC_CTX *mem_ctx, const struct winbindd_domain *domain,
516                     struct dc_name_ip **dcs, int *num_dcs)
517 {
518         fstring dcname;
519         struct  in_addr ip;
520         struct  ip_service *ip_list = NULL;
521         int     iplist_size = 0;
522         int     i;
523         BOOL    is_our_domain;
524
525
526         is_our_domain = strequal(domain->name, lp_workgroup());
527
528         if ( !is_our_domain 
529                 && get_dc_name_via_netlogon(domain, dcname, &ip) 
530                 && add_one_dc_unique(mem_ctx, domain->name, dcname, ip, dcs, num_dcs) )
531         {
532                 return True;
533         }
534
535         if ( is_our_domain 
536                 && must_use_pdc(domain->name) 
537                 && get_pdc_ip(domain->name, &ip)) 
538         {
539                 if (add_one_dc_unique(mem_ctx, domain->name, inet_ntoa(ip), ip, dcs, num_dcs)) 
540                         return True;
541         }
542
543         /* try standard netbios queries first */
544
545         get_sorted_dc_list(domain->name, &ip_list, &iplist_size, False);
546
547         /* check for security = ads and use DNS if we can */
548
549         if ( iplist_size==0 && lp_security() == SEC_ADS ) 
550                 get_sorted_dc_list(domain->alt_name, &ip_list, &iplist_size, True);
551
552         /* now add to the dc array.  We'll wait until the last minute 
553            to look up the name of the DC.  But we fill in the char* for 
554            the ip now in to make the failed connection cache work */
555
556         for ( i=0; i<iplist_size; i++ ) {
557                 add_one_dc_unique(mem_ctx, domain->name, inet_ntoa(ip_list[i].ip), 
558                         ip_list[i].ip, dcs, num_dcs);
559         }
560
561         SAFE_FREE( ip_list );
562
563         return True;
564 }
565
566 static BOOL find_new_dc(TALLOC_CTX *mem_ctx,
567                         const struct winbindd_domain *domain,
568                         fstring dcname, struct sockaddr_in *addr, int *fd)
569 {
570         struct dc_name_ip *dcs = NULL;
571         int num_dcs = 0;
572
573         const char **dcnames = NULL;
574         int num_dcnames = 0;
575
576         struct sockaddr_in *addrs = NULL;
577         int num_addrs = 0;
578
579         int i, fd_index;
580
581         if (!get_dcs(mem_ctx, domain, &dcs, &num_dcs) || (num_dcs == 0))
582                 return False;
583
584         for (i=0; i<num_dcs; i++) {
585
586                 add_string_to_array(mem_ctx, dcs[i].name,
587                                     &dcnames, &num_dcnames);
588                 add_sockaddr_to_array(mem_ctx, dcs[i].ip, 445,
589                                       &addrs, &num_addrs);
590
591                 add_string_to_array(mem_ctx, dcs[i].name,
592                                     &dcnames, &num_dcnames);
593                 add_sockaddr_to_array(mem_ctx, dcs[i].ip, 139,
594                                       &addrs, &num_addrs);
595         }
596
597         if ((num_dcnames == 0) || (num_dcnames != num_addrs))
598                 return False;
599
600         if ( !open_any_socket_out(addrs, num_addrs, 10000, &fd_index, fd) ) 
601         {
602                 for (i=0; i<num_dcs; i++) {
603                         add_failed_connection_entry(domain->name,
604                                 dcs[i].name, NT_STATUS_UNSUCCESSFUL);
605                 }
606                 return False;
607         }
608
609         *addr = addrs[fd_index];
610
611         /* if we have no name on the server or just an IP address for 
612            the name, now try to get the name */
613
614         if ( is_ipaddress(dcnames[fd_index]) || *dcnames[fd_index] == '\0' )
615                 dcip_to_name( domain->name, domain->alt_name, addr->sin_addr, dcname );
616         else
617                 fstrcpy(dcname, dcnames[fd_index]);
618
619         return True;
620 }
621
622 static NTSTATUS cm_open_connection(struct winbindd_domain *domain,
623                                    const int pipe_index,
624                                    struct winbindd_cm_conn *new_conn)
625 {
626         TALLOC_CTX *mem_ctx;
627         NTSTATUS result;
628
629         int retries;
630
631         if ((mem_ctx = talloc_init("cm_open_connection")) == NULL)
632                 return NT_STATUS_NO_MEMORY;
633
634         for (retries = 0; retries < 3; retries++) {
635
636                 int fd = -1;
637                 BOOL retry;
638
639                 result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
640
641                 if ((strlen(domain->dcname) > 0) &&
642                     NT_STATUS_IS_OK(check_negative_conn_cache(domain->name,
643                                                               domain->dcname))) {
644                         int dummy;
645                         if (!open_any_socket_out(&domain->dcaddr, 1, 10000,
646                                                  &dummy, &fd)) {
647                                 fd = -1;
648                         }
649                 }
650
651                 if ((fd == -1) &&
652                     !find_new_dc(mem_ctx, domain, domain->dcname,
653                                  &domain->dcaddr, &fd))
654                         break;
655
656                 new_conn->cli = NULL;
657
658                 result = cm_prepare_connection(domain, fd, pipe_index,
659                                                domain->dcname,
660                                                &new_conn->cli, &retry);
661
662                 if (NT_STATUS_IS_OK(result)) {
663                         fstrcpy(new_conn->domain, domain->name);
664                         /* Initialise SMB connection */
665                         fstrcpy(new_conn->pipe_name,
666                                 get_pipe_name_from_index(pipe_index));
667                         break;
668                 }
669
670                 if (!retry)
671                         break;
672         }
673
674         talloc_destroy(mem_ctx);
675         return result;
676 }
677
678 /************************************************************************
679  Wrapper around statuc cm_open_connection to retreive a freshly
680  setup cli_state struct
681 ************************************************************************/
682
683 NTSTATUS cm_fresh_connection(struct winbindd_domain *domain, const int pipe_index,
684                                struct cli_state **cli)
685 {
686         NTSTATUS result;
687         struct winbindd_cm_conn conn;
688         
689         result = cm_open_connection( domain, pipe_index, &conn );
690         
691         if ( NT_STATUS_IS_OK(result) ) 
692                 *cli = conn.cli;
693
694         return result;
695 }
696
697 /* Return true if a connection is still alive */
698
699 static BOOL connection_ok(struct winbindd_cm_conn *conn)
700 {
701         if (!conn) {
702                 smb_panic("Invalid parameter passed to connection_ok():  conn was NULL!\n");
703                 return False;
704         }
705
706         if (!conn->cli) {
707                 DEBUG(3, ("Connection to %s for domain %s (pipe %s) has NULL conn->cli!\n", 
708                           conn->controller, conn->domain, conn->pipe_name));
709                 return False;
710         }
711
712         if (!conn->cli->initialised) {
713                 DEBUG(3, ("Connection to %s for domain %s (pipe %s) was never initialised!\n", 
714                           conn->controller, conn->domain, conn->pipe_name));
715                 return False;
716         }
717
718         if (conn->cli->fd == -1) {
719                 DEBUG(3, ("Connection to %s for domain %s (pipe %s) has died or was never started (fd == -1)\n", 
720                           conn->controller, conn->domain, conn->pipe_name));
721                 return False;
722         }
723         
724         return True;
725 }
726
727 /* Search the cache for a connection. If there is a broken one,
728    shut it down properly and return NULL. */
729
730 static void find_cm_connection(struct winbindd_domain *domain, const char *pipe_name,
731                                struct winbindd_cm_conn **conn_out) 
732 {
733         struct winbindd_cm_conn *conn;
734
735         for (conn = cm_conns; conn; ) {
736                 if (strequal(conn->domain, domain->name) && 
737                     strequal(conn->pipe_name, pipe_name)) {
738                         if (!connection_ok(conn)) {
739                                 /* Dead connection - remove it. */
740                                 struct winbindd_cm_conn *conn_temp = conn->next;
741                                 if (conn->cli)
742                                         cli_shutdown(conn->cli);
743                                 DLIST_REMOVE(cm_conns, conn);
744                                 SAFE_FREE(conn);
745                                 conn = conn_temp;  /* Keep the loop moving */
746                                 continue;
747                         } else {
748                                 break;
749                         }
750                 }
751                 conn = conn->next;
752         }
753
754         *conn_out = conn;
755 }
756
757 /* Initialize a new connection up to the RPC BIND. */
758
759 static NTSTATUS new_cm_connection(struct winbindd_domain *domain, const char *pipe_name,
760                                   struct winbindd_cm_conn **conn_out)
761 {
762         struct winbindd_cm_conn *conn;
763         NTSTATUS result;
764
765         if (!(conn = SMB_MALLOC_P(struct winbindd_cm_conn)))
766                 return NT_STATUS_NO_MEMORY;
767                 
768         ZERO_STRUCTP(conn);
769                 
770         if (!NT_STATUS_IS_OK(result = cm_open_connection(domain, get_pipe_index(pipe_name), conn))) {
771                 DEBUG(3, ("Could not open a connection to %s for %s (%s)\n", 
772                           domain->name, pipe_name, nt_errstr(result)));
773                 SAFE_FREE(conn);
774                 return result;
775         }
776         DLIST_ADD(cm_conns, conn);
777
778         *conn_out = conn;
779         return NT_STATUS_OK;
780 }
781
782 /* Get a connection to the remote DC and open the pipe.  If there is already a connection, use that */
783
784 static NTSTATUS get_connection_from_cache(struct winbindd_domain *domain, const char *pipe_name,
785                                           struct winbindd_cm_conn **conn_out)
786 {
787         find_cm_connection(domain, pipe_name, conn_out);
788
789         if (*conn_out != NULL)
790                 return NT_STATUS_OK;
791
792         return new_cm_connection(domain, pipe_name, conn_out);
793 }
794
795 /**********************************************************************************
796  We can 'sense' certain things about the DC by it's replies to certain questions.
797
798  This tells us if this particular remote server is Active Directory, and if it is
799  native mode.
800 **********************************************************************************/
801
802 void set_dc_type_and_flags( struct winbindd_domain *domain )
803 {
804         NTSTATUS                result;
805         struct winbindd_cm_conn conn;
806         DS_DOMINFO_CTR          ctr;
807         TALLOC_CTX              *mem_ctx = NULL;
808         
809         ZERO_STRUCT( conn );
810         ZERO_STRUCT( ctr );
811         
812         domain->native_mode = False;
813         domain->active_directory = False;
814
815         if (domain->internal) {
816                 domain->initialized = True;
817                 return;
818         }
819         
820         if ( !NT_STATUS_IS_OK(result = cm_open_connection(domain, PI_LSARPC_DS, &conn)) ) {
821                 DEBUG(5, ("set_dc_type_and_flags: Could not open a connection to %s for PIPE_LSARPC (%s)\n", 
822                           domain->name, nt_errstr(result)));
823                 domain->initialized = True;
824                 return;
825         }
826         
827         if ( conn.cli ) {
828                 if ( !NT_STATUS_IS_OK(cli_ds_getprimarydominfo( conn.cli, 
829                                 conn.cli->mem_ctx, DsRolePrimaryDomainInfoBasic, &ctr)) ) {
830                         goto done;
831                 }
832         }
833                                 
834         if ( (ctr.basic->flags & DSROLE_PRIMARY_DS_RUNNING) 
835                         && !(ctr.basic->flags & DSROLE_PRIMARY_DS_MIXED_MODE) )
836                 domain->native_mode = True;
837
838         /* Cheat - shut down the DS pipe, and open LSA */
839
840         cli_nt_session_close(conn.cli);
841
842         if ( cli_nt_session_open (conn.cli, PI_LSARPC) ) {
843                 char *domain_name = NULL;
844                 char *dns_name = NULL;
845                 DOM_SID *dom_sid = NULL;
846
847                 mem_ctx = talloc_init("set_dc_type_and_flags on domain %s\n", domain->name);
848                 if (!mem_ctx) {
849                         DEBUG(1, ("set_dc_type_and_flags: talloc_init() failed\n"));
850                         return;
851                 }
852
853                 result = cli_lsa_open_policy2(conn.cli, mem_ctx, True, 
854                                               SEC_RIGHTS_MAXIMUM_ALLOWED,
855                                               &conn.pol);
856                 
857                 if (NT_STATUS_IS_OK(result)) {
858                         /* This particular query is exactly what Win2k clients use 
859                            to determine that the DC is active directory */
860                         result = cli_lsa_query_info_policy2(conn.cli, mem_ctx, 
861                                                             &conn.pol,
862                                                             12, &domain_name,
863                                                             &dns_name, NULL,
864                                                             NULL, &dom_sid);
865                 }
866
867                 if (NT_STATUS_IS_OK(result)) {
868                         if (domain_name)
869                                 fstrcpy(domain->name, domain_name);
870                         
871                         if (dns_name)
872                                 fstrcpy(domain->alt_name, dns_name);
873
874                         if (dom_sid) 
875                                 sid_copy(&domain->sid, dom_sid);
876
877                         domain->active_directory = True;
878                 } else {
879                         
880                         result = cli_lsa_open_policy(conn.cli, mem_ctx, True, 
881                                                      SEC_RIGHTS_MAXIMUM_ALLOWED,
882                                                      &conn.pol);
883                         
884                         if (!NT_STATUS_IS_OK(result))
885                                 goto done;
886                         
887                         result = cli_lsa_query_info_policy(conn.cli, mem_ctx, 
888                                                            &conn.pol, 5, &domain_name, 
889                                                            &dom_sid);
890                         
891                         if (NT_STATUS_IS_OK(result)) {
892                                 if (domain_name)
893                                         fstrcpy(domain->name, domain_name);
894                                 
895                                 if (dom_sid) 
896                                         sid_copy(&domain->sid, dom_sid);
897                         }
898                 }
899         }
900         
901 done:
902         
903         DEBUG(3,("add_trusted_domain: %s is an %s %s domain\n", domain->name,
904                 domain->active_directory ? "ADS" : "NT4",
905                 domain->native_mode ? "native mode" :
906                 ((domain->active_directory && !domain->native_mode) ? "mixed mode" : "")));
907
908         /* close the connection;  no other calls use this pipe and it is called only
909            on reestablishing the domain list   --jerry */
910         
911         if ( conn.cli )
912                 cli_shutdown( conn.cli );
913         
914         talloc_destroy(mem_ctx);
915
916         domain->initialized = True;
917         
918         return;
919 }
920
921
922
923 /* Return a LSA policy handle on a domain */
924
925 NTSTATUS cm_get_lsa_handle(struct winbindd_domain *domain, CLI_POLICY_HND **return_hnd)
926 {
927         struct winbindd_cm_conn *conn;
928         uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
929         NTSTATUS result;
930         static CLI_POLICY_HND hnd;
931
932         /* Look for existing connections */
933
934         if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_LSARPC, &conn)))
935                 return result;
936
937         /* This *shitty* code needs scrapping ! JRA */
938         
939         if (policy_handle_is_valid(&conn->pol)) {
940                 hnd.pol = conn->pol;
941                 hnd.cli = conn->cli;
942                 *return_hnd = &hnd;
943
944                 return NT_STATUS_OK;
945         }
946         
947         result = cli_lsa_open_policy(conn->cli, conn->cli->mem_ctx, False, 
948                                      des_access, &conn->pol);
949
950         if (!NT_STATUS_IS_OK(result)) {
951                 /* Hit the cache code again.  This cleans out the old connection and gets a new one */
952                 if (conn->cli->fd == -1) { /* Try again, if the remote host disapeared */
953                         if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_LSARPC, &conn)))
954                                 return result;
955
956                         result = cli_lsa_open_policy(conn->cli, conn->cli->mem_ctx, False, 
957                                                      des_access, &conn->pol);
958                 }
959
960                 if (!NT_STATUS_IS_OK(result)) {
961                         cli_shutdown(conn->cli);
962                         DLIST_REMOVE(cm_conns, conn);
963                         SAFE_FREE(conn);
964                         return result;
965                 }
966         }       
967
968         hnd.pol = conn->pol;
969         hnd.cli = conn->cli;
970
971         *return_hnd = &hnd;
972
973         return NT_STATUS_OK;
974 }
975
976 /* Return a SAM policy handle on a domain */
977
978 NTSTATUS cm_get_sam_handle(struct winbindd_domain *domain, CLI_POLICY_HND **return_hnd)
979
980         struct winbindd_cm_conn *conn;
981         uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
982         NTSTATUS result;
983         static CLI_POLICY_HND hnd;
984
985         /* Look for existing connections */
986
987         if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_SAMR, &conn)))
988                 return result;
989         
990         /* This *shitty* code needs scrapping ! JRA */
991         
992         if (policy_handle_is_valid(&conn->pol)) {
993                 hnd.pol = conn->pol;
994                 hnd.cli = conn->cli;
995                 
996                 *return_hnd = &hnd;
997
998                 return NT_STATUS_OK;
999         }
1000         
1001         result = cli_samr_connect(conn->cli, conn->cli->mem_ctx,
1002                                   des_access, &conn->pol);
1003
1004         if (!NT_STATUS_IS_OK(result)) {
1005                 /* Hit the cache code again.  This cleans out the old connection and gets a new one */
1006                 if (conn->cli->fd == -1) { /* Try again, if the remote host disapeared */
1007                 
1008                         if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_SAMR, &conn)))
1009                                 return result;
1010
1011                         result = cli_samr_connect(conn->cli, conn->cli->mem_ctx,
1012                                                   des_access, &conn->pol);
1013                 }
1014
1015                 if (!NT_STATUS_IS_OK(result)) {
1016                 
1017                         cli_shutdown(conn->cli);
1018                         DLIST_REMOVE(cm_conns, conn);
1019                         SAFE_FREE(conn);
1020                         
1021                         return result;
1022                 }
1023         }       
1024
1025         hnd.pol = conn->pol;
1026         hnd.cli = conn->cli;
1027
1028         *return_hnd = &hnd;
1029
1030         return NT_STATUS_OK;
1031 }
1032
1033 /* Get a handle on a netlogon pipe.  This is a bit of a hack to re-use the
1034    netlogon pipe as no handle is returned. */
1035
1036 NTSTATUS cm_get_netlogon_cli(struct winbindd_domain *domain, 
1037                              const unsigned char *trust_passwd, 
1038                              uint32 sec_channel_type,
1039                              BOOL fresh,
1040                              struct cli_state **cli)
1041 {
1042         NTSTATUS result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
1043         struct winbindd_cm_conn *conn;
1044         fstring lock_name;
1045         BOOL got_mutex;
1046
1047         if (!cli)
1048                 return NT_STATUS_INVALID_PARAMETER;
1049
1050         /* Open an initial conection - keep the mutex. */
1051
1052         find_cm_connection(domain, PIPE_NETLOGON, &conn);
1053
1054         if ( fresh && (conn != NULL) ) {
1055                 cli_shutdown(conn->cli);
1056                 conn->cli = NULL;
1057
1058                 conn = NULL;
1059
1060                 /* purge connection from cache */
1061                 find_cm_connection(domain, PIPE_NETLOGON, &conn);
1062                 if (conn != NULL) {
1063                         DEBUG(0,("Could not purge connection\n"));
1064                         return NT_STATUS_UNSUCCESSFUL;
1065                 }
1066         }
1067
1068         if (conn != NULL) {
1069                 *cli = conn->cli;
1070                 return NT_STATUS_OK;
1071         }
1072
1073         result = new_cm_connection(domain, PIPE_NETLOGON, &conn);
1074
1075         if (!NT_STATUS_IS_OK(result))
1076                 return result;
1077         
1078         fstr_sprintf(lock_name, "NETLOGON\\%s", conn->controller);
1079
1080         if (!(got_mutex = secrets_named_mutex(lock_name, WINBIND_SERVER_MUTEX_WAIT_TIME))) {
1081                 DEBUG(0,("cm_get_netlogon_cli: mutex grab failed for %s\n", conn->controller));
1082         }
1083         
1084         if ( sec_channel_type == SEC_CHAN_DOMAIN )
1085                 fstr_sprintf(conn->cli->mach_acct, "%s$", lp_workgroup());
1086                         
1087         /* This must be the remote domain (not ours) for schannel */
1088
1089         fstrcpy( conn->cli->domain, domain->name);
1090         
1091         result = cli_nt_establish_netlogon(conn->cli, sec_channel_type, trust_passwd);
1092         
1093         if (got_mutex)
1094                 secrets_named_mutex_release(lock_name);
1095                                 
1096         if (!NT_STATUS_IS_OK(result)) {
1097                 cli_shutdown(conn->cli);
1098                 DLIST_REMOVE(cm_conns, conn);
1099                 SAFE_FREE(conn);
1100                 return result;
1101         }
1102
1103         *cli = conn->cli;
1104
1105         return result;
1106 }
1107
1108 /* Dump the current connection status */
1109
1110 static void dump_conn_list(void)
1111 {
1112         struct winbindd_cm_conn *con;
1113
1114         DEBUG(0, ("\tDomain          Controller      Pipe\n"));
1115
1116         for(con = cm_conns; con; con = con->next) {
1117                 char *msg;
1118
1119                 /* Display pipe info */
1120                 
1121                 if (asprintf(&msg, "\t%-15s %-15s %-16s", con->domain, con->controller, con->pipe_name) < 0) {
1122                         DEBUG(0, ("Error: not enough memory!\n"));
1123                 } else {
1124                         DEBUG(0, ("%s\n", msg));
1125                         SAFE_FREE(msg);
1126                 }
1127         }
1128 }
1129
1130 void winbindd_cm_status(void)
1131 {
1132         /* List open connections */
1133
1134         DEBUG(0, ("winbindd connection manager status:\n"));
1135
1136         if (cm_conns)
1137                 dump_conn_list();
1138         else
1139                 DEBUG(0, ("\tNo active connections\n"));
1140 }
1141
1142 /* Close all cached connections */
1143
1144 void winbindd_cm_flush(void)
1145 {
1146         struct winbindd_cm_conn *conn, tmp;
1147
1148         /* Flush connection cache */
1149
1150         for (conn = cm_conns; conn; conn = conn->next) {
1151
1152                 if (!connection_ok(conn))
1153                         continue;
1154
1155                 DEBUG(10, ("Closing connection to %s on %s\n",
1156                         conn->pipe_name, conn->controller));
1157
1158                 if (conn->cli)
1159                         cli_shutdown(conn->cli);
1160
1161                 tmp.next = conn->next;
1162
1163                 DLIST_REMOVE(cm_conns, conn);
1164                 SAFE_FREE(conn);
1165                 conn = &tmp;
1166         }
1167
1168         /* Flush failed connection cache */
1169
1170         flush_negative_conn_cache();
1171 }