r4749: Fix memleak
[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    
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         struct ntuser_creds creds;
219
220         BOOL got_mutex;
221         BOOL add_failed_connection = True;
222
223         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
224
225         struct sockaddr peeraddr;
226         socklen_t peeraddr_len;
227
228         struct sockaddr_in *peeraddr_in = (struct sockaddr_in *)&peeraddr;
229
230         machine_password = secrets_fetch_machine_password(lp_workgroup(), NULL,
231                                                           NULL);
232         
233         if (asprintf(&machine_krb5_principal, "%s$@%s", global_myname(),
234                      lp_realm()) == -1) {
235                 SAFE_FREE(machine_password);
236                 return NT_STATUS_NO_MEMORY;
237         }
238
239         cm_get_ipc_userpass(&ipc_username, &ipc_domain, &ipc_password);
240
241         *retry = True;
242
243         got_mutex = secrets_named_mutex(controller,
244                                         WINBIND_SERVER_MUTEX_WAIT_TIME);
245
246         if (!got_mutex) {
247                 DEBUG(0,("cm_open_connection: mutex grab failed for %s\n",
248                          controller));
249                 result = NT_STATUS_POSSIBLE_DEADLOCK;
250                 goto done;
251         }
252
253         if ((*cli = cli_initialise(NULL)) == NULL) {
254                 DEBUG(1, ("Could not cli_initialize\n"));
255                 result = NT_STATUS_NO_MEMORY;
256                 goto done;
257         }
258
259         (*cli)->timeout = 10000;        /* 10 seconds */
260         (*cli)->fd = sockfd;
261         fstrcpy((*cli)->desthost, controller);
262         (*cli)->use_kerberos = True;
263
264         peeraddr_len = sizeof(peeraddr);
265
266         if ((getpeername((*cli)->fd, &peeraddr, &peeraddr_len) != 0) ||
267             (peeraddr_len != sizeof(struct sockaddr_in)) ||
268             (peeraddr_in->sin_family != PF_INET))
269         {
270                 DEBUG(0,("cm_prepare_connection: %s\n", strerror(errno)));
271                 goto done;
272         }
273
274         if (ntohs(peeraddr_in->sin_port) == 139) {
275                 struct nmb_name calling;
276                 struct nmb_name called;
277
278                 make_nmb_name(&calling, global_myname(), 0x0);
279                 make_nmb_name(&called, "*SMBSERVER", 0x20);
280
281                 if (!cli_session_request(*cli, &calling, &called)) {
282                         DEBUG(8, ("cli_session_request failed for %s\n",
283                                   controller));
284                         goto done;
285                 }
286         }
287
288         cli_setup_signing_state(*cli, Undefined);
289
290         if (!cli_negprot(*cli)) {
291                 DEBUG(1, ("cli_negprot failed\n"));
292                 cli_shutdown(*cli);
293                 goto done;
294         }
295
296         /* Krb5 session */
297                         
298         if ((lp_security() == SEC_ADS) 
299             && ((*cli)->protocol >= PROTOCOL_NT1 &&
300                 (*cli)->capabilities & CAP_EXTENDED_SECURITY)) {
301
302                 ADS_STATUS ads_status;
303                 (*cli)->use_kerberos = True;
304                 DEBUG(5, ("connecting to %s from %s with kerberos principal "
305                           "[%s]\n", controller, global_myname(),
306                           machine_krb5_principal));
307
308                 ads_status = cli_session_setup_spnego(*cli,
309                                                       machine_krb5_principal, 
310                                                       machine_password, 
311                                                       lp_workgroup());
312
313                 if (!ADS_ERR_OK(ads_status))
314                         DEBUG(4,("failed kerberos session setup with %s\n",
315                                  ads_errstr(ads_status)));
316
317                 result = ads_ntstatus(ads_status);
318         }
319
320         if (NT_STATUS_IS_OK(result))
321                 goto session_setup_done;
322
323         /* Fall back to non-kerberos session setup */
324
325         (*cli)->use_kerberos = False;
326
327         if ((((*cli)->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) != 0) &&
328             (strlen(ipc_username) > 0)) {
329
330                 /* Only try authenticated if we have a username */
331
332                 DEBUG(5, ("connecting to %s from %s with username "
333                           "[%s]\\[%s]\n",  controller, global_myname(),
334                           ipc_domain, ipc_username));
335
336                 if (cli_session_setup(*cli, ipc_username,
337                                       ipc_password, strlen(ipc_password)+1,
338                                       ipc_password, strlen(ipc_password)+1,
339                                       ipc_domain)) {
340                         DEBUG(5, ("authenticated session setup failed\n"));
341                         goto session_setup_done;
342                 }
343         }
344
345         /* Fall back to anonymous connection, this might fail later */
346
347         if (cli_session_setup(*cli, "", NULL, 0, NULL, 0, "")) {
348                 DEBUG(5, ("Connected anonymously\n"));
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         if (!cli_send_tconX(*cli, "IPC$", "IPC", "", 0)) {
364
365                 result = cli_nt_error(*cli);
366
367                 DEBUG(1,("failed tcon_X with %s\n", nt_errstr(result)));
368
369                 if (NT_STATUS_IS_OK(result))
370                         result = NT_STATUS_UNSUCCESSFUL;
371
372                 cli_shutdown(*cli);
373                 goto done;
374         }
375
376         init_creds(&creds, ipc_username, ipc_domain, ipc_password);
377         cli_init_creds(*cli, &creds);
378
379         secrets_named_mutex_release(controller);
380         got_mutex = False;
381         *retry = False;
382
383         if (domain->primary || IS_DC) {
384                 NTSTATUS status = setup_schannel( *cli, domain->name );
385                 if (!NT_STATUS_IS_OK(status)) {
386                         DEBUG(3,("schannel refused - continuing without "
387                                  "schannel (%s)\n", nt_errstr(status)));
388                 }
389         }
390
391         /* set the domain if empty; needed for schannel connections */
392         if ( !*(*cli)->domain )
393                 fstrcpy( (*cli)->domain, domain->name );
394
395         if ( !cli_nt_session_open (*cli, pipe_index) ) {
396
397                 result = NT_STATUS_PIPE_NOT_AVAILABLE;
398
399                 /* This might be a NT4 DC */
400                 if ( is_win2k_pipe(pipe_index) )
401                         add_failed_connection = False;
402
403                 cli_shutdown(*cli);
404                 goto done;
405         }
406
407         result = NT_STATUS_OK;
408         add_failed_connection = False;
409
410  done:
411         if (got_mutex)
412                 secrets_named_mutex_release(controller);
413
414         SAFE_FREE(machine_password);
415         SAFE_FREE(machine_krb5_principal);
416         SAFE_FREE(ipc_username);
417         SAFE_FREE(ipc_domain);
418         SAFE_FREE(ipc_password);
419
420         if (add_failed_connection)
421                 add_failed_connection_entry(domain->name, controller, result);
422
423         return result;
424 }
425
426 struct dc_name_ip {
427         fstring name;
428         struct in_addr ip;
429 };
430
431 static BOOL add_one_dc_unique(TALLOC_CTX *mem_ctx, const char *domain_name,
432                               const char *dcname, struct in_addr ip,
433                               struct dc_name_ip **dcs, int *num)
434 {
435         if (!NT_STATUS_IS_OK(check_negative_conn_cache(domain_name, dcname)))
436                 return False;
437
438         *dcs = TALLOC_REALLOC_ARRAY(mem_ctx, *dcs, struct dc_name_ip, (*num)+1);
439
440         if (*dcs == NULL)
441                 return False;
442
443         fstrcpy((*dcs)[*num].name, dcname);
444         (*dcs)[*num].ip = ip;
445         *num += 1;
446         return True;
447 }
448
449 static BOOL add_sockaddr_to_array(TALLOC_CTX *mem_ctx,
450                                   struct in_addr ip, uint16 port,
451                                   struct sockaddr_in **addrs, int *num)
452 {
453         *addrs = TALLOC_REALLOC_ARRAY(mem_ctx, *addrs, struct sockaddr_in, (*num)+1);
454
455         if (*addrs == NULL)
456                 return False;
457
458         (*addrs)[*num].sin_family = PF_INET;
459         putip((char *)&((*addrs)[*num].sin_addr), (char *)&ip);
460         (*addrs)[*num].sin_port = htons(port);
461
462         *num += 1;
463         return True;
464 }
465
466 static BOOL get_dcs_1c(TALLOC_CTX *mem_ctx,
467                        const struct winbindd_domain *domain,
468                        struct dc_name_ip **dcs, int *num_dcs)
469 {
470         struct ip_service *iplist = NULL;
471         int i, num = 0;
472
473         if (!internal_resolve_name(domain->name, 0x1c, &iplist, &num,
474                                    lp_name_resolve_order()))
475                 return False;
476
477         /* Now try to find the server names of at least one IP address, hosts
478          * not replying are cached as such */
479
480         for (i=0; i<num; i++) {
481
482                 fstring dcname;
483
484                 if (!name_status_find(domain->name, 0x1c, 0x20, iplist[i].ip,
485                                       dcname))
486                         continue;
487
488                 if (add_one_dc_unique(mem_ctx, domain->name, dcname,
489                                       iplist[i].ip, dcs, num_dcs)) {
490                         /* One DC responded, so we assume that he will also
491                            work on 139/445 */
492                         break;
493                 }
494         }
495
496         SAFE_FREE(iplist);
497
498         return True;
499 }
500
501 static BOOL get_dcs(TALLOC_CTX *mem_ctx, const struct winbindd_domain *domain,
502                     struct dc_name_ip **dcs, int *num_dcs)
503 {
504         fstring dcname;
505         struct in_addr ip;
506         BOOL is_our_domain;
507
508         const char *p;
509
510         is_our_domain = strequal(domain->name, lp_workgroup());
511
512         if (!is_our_domain && get_dc_name_via_netlogon(domain, dcname, &ip) &&
513             add_one_dc_unique(mem_ctx, domain->name, dcname, ip, dcs, num_dcs))
514                         return True;
515
516         if (!is_our_domain) {
517                 /* NETLOGON to our own domain could not give us a DC name
518                  * (which is an error), fall back to looking up domain#1c */
519                 return get_dcs_1c(mem_ctx, domain, dcs, num_dcs);
520         }
521
522         if (must_use_pdc(domain->name) && get_pdc_ip(domain->name, &ip)) {
523
524                 if (!name_status_find(domain->name, 0x1b, 0x20, ip, dcname))
525                         return False;
526
527                 if (add_one_dc_unique(mem_ctx, domain->name,
528                                       dcname, ip, dcs, num_dcs))
529                         return True;
530         }
531
532         p = lp_passwordserver();
533
534         if (*p == 0)
535                 return get_dcs_1c(mem_ctx, domain, dcs, num_dcs);
536
537         while (next_token(&p, dcname, LIST_SEP, sizeof(dcname))) {
538
539                 if (strequal(dcname, "*")) {
540                         get_dcs_1c(mem_ctx, domain, dcs, num_dcs);
541                         continue;
542                 }
543
544                 if (!resolve_name(dcname, &ip, 0x20))
545                         continue;
546
547                 /* Even if we got the dcname, double check the name to use for
548                  * the netlogon auth2 */
549
550                 if (!name_status_find(domain->name, 0x1c, 0x20, ip, dcname))
551                         continue;
552
553                 add_one_dc_unique(mem_ctx, domain->name, dcname, ip,
554                                   dcs, num_dcs);
555         }
556
557         return True;
558 }
559
560 static BOOL find_new_dc(TALLOC_CTX *mem_ctx,
561                         const struct winbindd_domain *domain,
562                         fstring dcname, struct sockaddr_in *addr, int *fd)
563 {
564         struct dc_name_ip *dcs = NULL;
565         int num_dcs = 0;
566
567         char **dcnames = NULL;
568         int num_dcnames = 0;
569
570         struct sockaddr_in *addrs = NULL;
571         int num_addrs = 0;
572
573         int i, fd_index;
574
575         if (!get_dcs(mem_ctx, domain, &dcs, &num_dcs) || (num_dcs == 0))
576                 return False;
577
578         for (i=0; i<num_dcs; i++) {
579
580                 add_string_to_array(mem_ctx, dcs[i].name,
581                                     &dcnames, &num_dcnames);
582                 add_sockaddr_to_array(mem_ctx, dcs[i].ip, 445,
583                                       &addrs, &num_addrs);
584
585                 add_string_to_array(mem_ctx, dcs[i].name,
586                                     &dcnames, &num_dcnames);
587                 add_sockaddr_to_array(mem_ctx, dcs[i].ip, 139,
588                                       &addrs, &num_addrs);
589         }
590
591         if ((num_dcnames == 0) || (num_dcnames != num_addrs))
592                 return False;
593
594         if (!open_any_socket_out(addrs, num_addrs, 10000, &fd_index, fd)) {
595                 for (i=0; i<num_dcs; i++) {
596                         add_failed_connection_entry(domain->name,
597                                                     dcs[i].name,
598                                                     NT_STATUS_UNSUCCESSFUL);
599                 }
600                 return False;
601         }
602
603         fstrcpy(dcname, dcnames[fd_index]);
604         *addr = addrs[fd_index];
605
606         return True;
607 }
608
609 static NTSTATUS cm_open_connection(struct winbindd_domain *domain,
610                                    const int pipe_index,
611                                    struct winbindd_cm_conn *new_conn)
612 {
613         TALLOC_CTX *mem_ctx;
614         NTSTATUS result;
615
616         int retries;
617
618         if ((mem_ctx = talloc_init("cm_open_connection")) == NULL)
619                 return NT_STATUS_NO_MEMORY;
620
621         for (retries = 0; retries < 3; retries++) {
622
623                 int fd = -1;
624                 BOOL retry;
625
626                 result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
627
628                 if ((strlen(domain->dcname) > 0) &&
629                     NT_STATUS_IS_OK(check_negative_conn_cache(domain->name,
630                                                               domain->dcname))) {
631                         int dummy;
632                         if (!open_any_socket_out(&domain->dcaddr, 1, 10000,
633                                                  &dummy, &fd)) {
634                                 fd = -1;
635                         }
636                 }
637
638                 if ((fd == -1) &&
639                     !find_new_dc(mem_ctx, domain, domain->dcname,
640                                  &domain->dcaddr, &fd))
641                         break;
642
643                 new_conn->cli = NULL;
644
645                 result = cm_prepare_connection(domain, fd, pipe_index,
646                                                domain->dcname,
647                                                &new_conn->cli, &retry);
648
649                 if (NT_STATUS_IS_OK(result)) {
650                         fstrcpy(new_conn->domain, domain->name);
651                         /* Initialise SMB connection */
652                         fstrcpy(new_conn->pipe_name,
653                                 get_pipe_name_from_index(pipe_index));
654                         break;
655                 }
656
657                 if (!retry)
658                         break;
659         }
660
661         talloc_destroy(mem_ctx);
662         return result;
663 }
664
665 /************************************************************************
666  Wrapper around statuc cm_open_connection to retreive a freshly
667  setup cli_state struct
668 ************************************************************************/
669
670 NTSTATUS cm_fresh_connection(struct winbindd_domain *domain, const int pipe_index,
671                                struct cli_state **cli)
672 {
673         NTSTATUS result;
674         struct winbindd_cm_conn conn;
675         
676         result = cm_open_connection( domain, pipe_index, &conn );
677         
678         if ( NT_STATUS_IS_OK(result) ) 
679                 *cli = conn.cli;
680
681         return result;
682 }
683
684 /* Return true if a connection is still alive */
685
686 static BOOL connection_ok(struct winbindd_cm_conn *conn)
687 {
688         if (!conn) {
689                 smb_panic("Invalid parameter passed to connection_ok():  conn was NULL!\n");
690                 return False;
691         }
692
693         if (!conn->cli) {
694                 DEBUG(3, ("Connection to %s for domain %s (pipe %s) has NULL conn->cli!\n", 
695                           conn->controller, conn->domain, conn->pipe_name));
696                 return False;
697         }
698
699         if (!conn->cli->initialised) {
700                 DEBUG(3, ("Connection to %s for domain %s (pipe %s) was never initialised!\n", 
701                           conn->controller, conn->domain, conn->pipe_name));
702                 return False;
703         }
704
705         if (conn->cli->fd == -1) {
706                 DEBUG(3, ("Connection to %s for domain %s (pipe %s) has died or was never started (fd == -1)\n", 
707                           conn->controller, conn->domain, conn->pipe_name));
708                 return False;
709         }
710         
711         return True;
712 }
713
714 /* Search the cache for a connection. If there is a broken one,
715    shut it down properly and return NULL. */
716
717 static void find_cm_connection(struct winbindd_domain *domain, const char *pipe_name,
718                                struct winbindd_cm_conn **conn_out) 
719 {
720         struct winbindd_cm_conn *conn;
721
722         for (conn = cm_conns; conn; ) {
723                 if (strequal(conn->domain, domain->name) && 
724                     strequal(conn->pipe_name, pipe_name)) {
725                         if (!connection_ok(conn)) {
726                                 /* Dead connection - remove it. */
727                                 struct winbindd_cm_conn *conn_temp = conn->next;
728                                 if (conn->cli)
729                                         cli_shutdown(conn->cli);
730                                 DLIST_REMOVE(cm_conns, conn);
731                                 SAFE_FREE(conn);
732                                 conn = conn_temp;  /* Keep the loop moving */
733                                 continue;
734                         } else {
735                                 break;
736                         }
737                 }
738                 conn = conn->next;
739         }
740
741         *conn_out = conn;
742 }
743
744 /* Initialize a new connection up to the RPC BIND. */
745
746 static NTSTATUS new_cm_connection(struct winbindd_domain *domain, const char *pipe_name,
747                                   struct winbindd_cm_conn **conn_out)
748 {
749         struct winbindd_cm_conn *conn;
750         NTSTATUS result;
751
752         if (!(conn = SMB_MALLOC_P(struct winbindd_cm_conn)))
753                 return NT_STATUS_NO_MEMORY;
754                 
755         ZERO_STRUCTP(conn);
756                 
757         if (!NT_STATUS_IS_OK(result = cm_open_connection(domain, get_pipe_index(pipe_name), conn))) {
758                 DEBUG(3, ("Could not open a connection to %s for %s (%s)\n", 
759                           domain->name, pipe_name, nt_errstr(result)));
760                 SAFE_FREE(conn);
761                 return result;
762         }
763         DLIST_ADD(cm_conns, conn);
764
765         *conn_out = conn;
766         return NT_STATUS_OK;
767 }
768
769 /* Get a connection to the remote DC and open the pipe.  If there is already a connection, use that */
770
771 static NTSTATUS get_connection_from_cache(struct winbindd_domain *domain, const char *pipe_name,
772                                           struct winbindd_cm_conn **conn_out)
773 {
774         find_cm_connection(domain, pipe_name, conn_out);
775
776         if (*conn_out != NULL)
777                 return NT_STATUS_OK;
778
779         return new_cm_connection(domain, pipe_name, conn_out);
780 }
781
782 /**********************************************************************************
783  We can 'sense' certain things about the DC by it's replies to certain questions.
784
785  This tells us if this particular remote server is Active Directory, and if it is
786  native mode.
787 **********************************************************************************/
788
789 void set_dc_type_and_flags( struct winbindd_domain *domain )
790 {
791         NTSTATUS                result;
792         struct winbindd_cm_conn conn;
793         DS_DOMINFO_CTR          ctr;
794         TALLOC_CTX              *mem_ctx = NULL;
795         
796         ZERO_STRUCT( conn );
797         ZERO_STRUCT( ctr );
798         
799         domain->native_mode = False;
800         domain->active_directory = False;
801
802         if (domain->internal) {
803                 domain->initialized = True;
804                 return;
805         }
806         
807         if ( !NT_STATUS_IS_OK(result = cm_open_connection(domain, PI_LSARPC_DS, &conn)) ) {
808                 DEBUG(5, ("set_dc_type_and_flags: Could not open a connection to %s for PIPE_LSARPC (%s)\n", 
809                           domain->name, nt_errstr(result)));
810                 domain->initialized = True;
811                 return;
812         }
813         
814         if ( conn.cli ) {
815                 if ( !NT_STATUS_IS_OK(cli_ds_getprimarydominfo( conn.cli, 
816                                 conn.cli->mem_ctx, DsRolePrimaryDomainInfoBasic, &ctr)) ) {
817                         goto done;
818                 }
819         }
820                                 
821         if ( (ctr.basic->flags & DSROLE_PRIMARY_DS_RUNNING) 
822                         && !(ctr.basic->flags & DSROLE_PRIMARY_DS_MIXED_MODE) )
823                 domain->native_mode = True;
824
825         /* Cheat - shut down the DS pipe, and open LSA */
826
827         cli_nt_session_close(conn.cli);
828
829         if ( cli_nt_session_open (conn.cli, PI_LSARPC) ) {
830                 char *domain_name = NULL;
831                 char *dns_name = NULL;
832                 DOM_SID *dom_sid = NULL;
833
834                 mem_ctx = talloc_init("set_dc_type_and_flags on domain %s\n", domain->name);
835                 if (!mem_ctx) {
836                         DEBUG(1, ("set_dc_type_and_flags: talloc_init() failed\n"));
837                         return;
838                 }
839
840                 result = cli_lsa_open_policy2(conn.cli, mem_ctx, True, 
841                                               SEC_RIGHTS_MAXIMUM_ALLOWED,
842                                               &conn.pol);
843                 
844                 if (NT_STATUS_IS_OK(result)) {
845                         /* This particular query is exactly what Win2k clients use 
846                            to determine that the DC is active directory */
847                         result = cli_lsa_query_info_policy2(conn.cli, mem_ctx, 
848                                                             &conn.pol,
849                                                             12, &domain_name,
850                                                             &dns_name, NULL,
851                                                             NULL, &dom_sid);
852                 }
853
854                 if (NT_STATUS_IS_OK(result)) {
855                         if (domain_name)
856                                 fstrcpy(domain->name, domain_name);
857                         
858                         if (dns_name)
859                                 fstrcpy(domain->alt_name, dns_name);
860
861                         if (dom_sid) 
862                                 sid_copy(&domain->sid, dom_sid);
863
864                         domain->active_directory = True;
865                 } else {
866                         
867                         result = cli_lsa_open_policy(conn.cli, mem_ctx, True, 
868                                                      SEC_RIGHTS_MAXIMUM_ALLOWED,
869                                                      &conn.pol);
870                         
871                         if (!NT_STATUS_IS_OK(result))
872                                 goto done;
873                         
874                         result = cli_lsa_query_info_policy(conn.cli, mem_ctx, 
875                                                            &conn.pol, 5, &domain_name, 
876                                                            &dom_sid);
877                         
878                         if (NT_STATUS_IS_OK(result)) {
879                                 if (domain_name)
880                                         fstrcpy(domain->name, domain_name);
881                                 
882                                 if (dom_sid) 
883                                         sid_copy(&domain->sid, dom_sid);
884                         }
885                 }
886         }
887         
888 done:
889         
890         /* close the connection;  no other calls use this pipe and it is called only
891            on reestablishing the domain list   --jerry */
892         
893         if ( conn.cli )
894                 cli_shutdown( conn.cli );
895         
896         talloc_destroy(mem_ctx);
897
898         domain->initialized = True;
899         
900         return;
901 }
902
903
904
905 /* Return a LSA policy handle on a domain */
906
907 NTSTATUS cm_get_lsa_handle(struct winbindd_domain *domain, CLI_POLICY_HND **return_hnd)
908 {
909         struct winbindd_cm_conn *conn;
910         uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
911         NTSTATUS result;
912         static CLI_POLICY_HND hnd;
913
914         /* Look for existing connections */
915
916         if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_LSARPC, &conn)))
917                 return result;
918
919         /* This *shitty* code needs scrapping ! JRA */
920         
921         if (policy_handle_is_valid(&conn->pol)) {
922                 hnd.pol = conn->pol;
923                 hnd.cli = conn->cli;
924                 *return_hnd = &hnd;
925
926                 return NT_STATUS_OK;
927         }
928         
929         result = cli_lsa_open_policy(conn->cli, conn->cli->mem_ctx, False, 
930                                      des_access, &conn->pol);
931
932         if (!NT_STATUS_IS_OK(result)) {
933                 /* Hit the cache code again.  This cleans out the old connection and gets a new one */
934                 if (conn->cli->fd == -1) { /* Try again, if the remote host disapeared */
935                         if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_LSARPC, &conn)))
936                                 return result;
937
938                         result = cli_lsa_open_policy(conn->cli, conn->cli->mem_ctx, False, 
939                                                      des_access, &conn->pol);
940                 }
941
942                 if (!NT_STATUS_IS_OK(result)) {
943                         cli_shutdown(conn->cli);
944                         DLIST_REMOVE(cm_conns, conn);
945                         SAFE_FREE(conn);
946                         return result;
947                 }
948         }       
949
950         hnd.pol = conn->pol;
951         hnd.cli = conn->cli;
952
953         *return_hnd = &hnd;
954
955         return NT_STATUS_OK;
956 }
957
958 /* Return a SAM policy handle on a domain */
959
960 NTSTATUS cm_get_sam_handle(struct winbindd_domain *domain, CLI_POLICY_HND **return_hnd)
961
962         struct winbindd_cm_conn *conn;
963         uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
964         NTSTATUS result;
965         static CLI_POLICY_HND hnd;
966
967         /* Look for existing connections */
968
969         if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_SAMR, &conn)))
970                 return result;
971         
972         /* This *shitty* code needs scrapping ! JRA */
973         
974         if (policy_handle_is_valid(&conn->pol)) {
975                 hnd.pol = conn->pol;
976                 hnd.cli = conn->cli;
977                 
978                 *return_hnd = &hnd;
979
980                 return NT_STATUS_OK;
981         }
982         
983         result = cli_samr_connect(conn->cli, conn->cli->mem_ctx,
984                                   des_access, &conn->pol);
985
986         if (!NT_STATUS_IS_OK(result)) {
987                 /* Hit the cache code again.  This cleans out the old connection and gets a new one */
988                 if (conn->cli->fd == -1) { /* Try again, if the remote host disapeared */
989                 
990                         if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_SAMR, &conn)))
991                                 return result;
992
993                         result = cli_samr_connect(conn->cli, conn->cli->mem_ctx,
994                                                   des_access, &conn->pol);
995                 }
996
997                 if (!NT_STATUS_IS_OK(result)) {
998                 
999                         cli_shutdown(conn->cli);
1000                         DLIST_REMOVE(cm_conns, conn);
1001                         SAFE_FREE(conn);
1002                         
1003                         return result;
1004                 }
1005         }       
1006
1007         hnd.pol = conn->pol;
1008         hnd.cli = conn->cli;
1009
1010         *return_hnd = &hnd;
1011
1012         return NT_STATUS_OK;
1013 }
1014
1015 /* Get a handle on a netlogon pipe.  This is a bit of a hack to re-use the
1016    netlogon pipe as no handle is returned. */
1017
1018 NTSTATUS cm_get_netlogon_cli(struct winbindd_domain *domain, 
1019                              const unsigned char *trust_passwd, 
1020                              uint32 sec_channel_type,
1021                              BOOL fresh,
1022                              struct cli_state **cli)
1023 {
1024         NTSTATUS result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
1025         struct winbindd_cm_conn *conn;
1026         fstring lock_name;
1027         BOOL got_mutex;
1028
1029         if (!cli)
1030                 return NT_STATUS_INVALID_PARAMETER;
1031
1032         /* Open an initial conection - keep the mutex. */
1033
1034         find_cm_connection(domain, PIPE_NETLOGON, &conn);
1035
1036         if ( fresh && (conn != NULL) ) {
1037                 cli_shutdown(conn->cli);
1038                 conn->cli = NULL;
1039
1040                 conn = NULL;
1041
1042                 /* purge connection from cache */
1043                 find_cm_connection(domain, PIPE_NETLOGON, &conn);
1044                 if (conn != NULL) {
1045                         DEBUG(0,("Could not purge connection\n"));
1046                         return NT_STATUS_UNSUCCESSFUL;
1047                 }
1048         }
1049
1050         if (conn != NULL) {
1051                 *cli = conn->cli;
1052                 return NT_STATUS_OK;
1053         }
1054
1055         result = new_cm_connection(domain, PIPE_NETLOGON, &conn);
1056
1057         if (!NT_STATUS_IS_OK(result))
1058                 return result;
1059         
1060         fstr_sprintf(lock_name, "NETLOGON\\%s", conn->controller);
1061
1062         if (!(got_mutex = secrets_named_mutex(lock_name, WINBIND_SERVER_MUTEX_WAIT_TIME))) {
1063                 DEBUG(0,("cm_get_netlogon_cli: mutex grab failed for %s\n", conn->controller));
1064         }
1065         
1066         if ( sec_channel_type == SEC_CHAN_DOMAIN )
1067                 fstr_sprintf(conn->cli->mach_acct, "%s$", lp_workgroup());
1068                         
1069         /* This must be the remote domain (not ours) for schannel */
1070
1071         fstrcpy( conn->cli->domain, domain->name);
1072         
1073         result = cli_nt_establish_netlogon(conn->cli, sec_channel_type, trust_passwd);
1074         
1075         if (got_mutex)
1076                 secrets_named_mutex_release(lock_name);
1077                                 
1078         if (!NT_STATUS_IS_OK(result)) {
1079                 cli_shutdown(conn->cli);
1080                 DLIST_REMOVE(cm_conns, conn);
1081                 SAFE_FREE(conn);
1082                 return result;
1083         }
1084
1085         *cli = conn->cli;
1086
1087         return result;
1088 }
1089
1090 /* Dump the current connection status */
1091
1092 static void dump_conn_list(void)
1093 {
1094         struct winbindd_cm_conn *con;
1095
1096         DEBUG(0, ("\tDomain          Controller      Pipe\n"));
1097
1098         for(con = cm_conns; con; con = con->next) {
1099                 char *msg;
1100
1101                 /* Display pipe info */
1102                 
1103                 if (asprintf(&msg, "\t%-15s %-15s %-16s", con->domain, con->controller, con->pipe_name) < 0) {
1104                         DEBUG(0, ("Error: not enough memory!\n"));
1105                 } else {
1106                         DEBUG(0, ("%s\n", msg));
1107                         SAFE_FREE(msg);
1108                 }
1109         }
1110 }
1111
1112 void winbindd_cm_status(void)
1113 {
1114         /* List open connections */
1115
1116         DEBUG(0, ("winbindd connection manager status:\n"));
1117
1118         if (cm_conns)
1119                 dump_conn_list();
1120         else
1121                 DEBUG(0, ("\tNo active connections\n"));
1122 }
1123
1124 /* Close all cached connections */
1125
1126 void winbindd_cm_flush(void)
1127 {
1128         struct winbindd_cm_conn *conn, tmp;
1129
1130         /* Flush connection cache */
1131
1132         for (conn = cm_conns; conn; conn = conn->next) {
1133
1134                 if (!connection_ok(conn))
1135                         continue;
1136
1137                 DEBUG(10, ("Closing connection to %s on %s\n",
1138                         conn->pipe_name, conn->controller));
1139
1140                 if (conn->cli)
1141                         cli_shutdown(conn->cli);
1142
1143                 tmp.next = conn->next;
1144
1145                 DLIST_REMOVE(cm_conns, conn);
1146                 SAFE_FREE(conn);
1147                 conn = &tmp;
1148         }
1149
1150         /* Flush failed connection cache */
1151
1152         flush_negative_conn_cache();
1153 }