r153: Fix memleak
[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         size_t mutex_ref_count;
74         struct cli_state *cli;
75         POLICY_HND pol;
76 };
77
78 static struct winbindd_cm_conn *cm_conns = NULL;
79
80
81 /* Choose between anonymous or authenticated connections.  We need to use
82    an authenticated connection if DCs have the RestrictAnonymous registry
83    entry set > 0, or the "Additional restrictions for anonymous
84    connections" set in the win2k Local Security Policy. 
85    
86    Caller to free() result in domain, username, password
87 */
88
89 static void cm_get_ipc_userpass(char **username, char **domain, char **password)
90 {
91         *username = secrets_fetch(SECRETS_AUTH_USER, NULL);
92         *domain = secrets_fetch(SECRETS_AUTH_DOMAIN, NULL);
93         *password = secrets_fetch(SECRETS_AUTH_PASSWORD, NULL);
94         
95         if (*username && **username) {
96
97                 if (!*domain || !**domain)
98                         *domain = smb_xstrdup(lp_workgroup());
99                 
100                 if (!*password || !**password)
101                         *password = smb_xstrdup("");
102
103                 DEBUG(3, ("IPC$ connections done by user %s\\%s\n", 
104                           *domain, *username));
105
106         } else {
107                 DEBUG(3, ("IPC$ connections done anonymously\n"));
108                 *username = smb_xstrdup("");
109                 *domain = smb_xstrdup("");
110                 *password = smb_xstrdup("");
111         }
112 }
113
114 /*
115   setup for schannel on any pipes opened on this connection
116 */
117 static NTSTATUS setup_schannel(struct cli_state *cli)
118 {
119         NTSTATUS ret;
120         uchar trust_password[16];
121         uint32 sec_channel_type;
122
123         if (!secrets_fetch_trust_account_password(lp_workgroup(),
124                                                   trust_password,
125                                                   NULL, &sec_channel_type)) {
126                 return NT_STATUS_UNSUCCESSFUL;
127         }
128
129         ret = cli_nt_setup_netsec(cli, sec_channel_type, 
130                                   AUTH_PIPE_NETSEC | AUTH_PIPE_SIGN, 
131                                   trust_password);
132
133         return ret;
134 }
135
136 /* Open a connction to the remote server, cache failures for 30 seconds */
137
138 static NTSTATUS cm_open_connection(const struct winbindd_domain *domain, const int pipe_index,
139                                    struct winbindd_cm_conn *new_conn)
140 {
141         NTSTATUS result;
142         char *machine_password; 
143         char *machine_krb5_principal, *ipc_username, *ipc_domain, *ipc_password;
144         struct in_addr dc_ip;
145         int i;
146         BOOL retry = True;
147
148         ZERO_STRUCT(dc_ip);
149
150         fstrcpy(new_conn->domain, domain->name);
151         
152         /* connection failure cache has been moved inside of get_dc_name
153            so we can deal with half dead DC's   --jerry */
154
155         if (!get_dc_name(domain->name, domain->alt_name[0] ? domain->alt_name : NULL, 
156                          new_conn->controller, &dc_ip)) {
157                 result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
158                 add_failed_connection_entry(domain->name, "", result);
159                 return result;
160         }
161                 
162         /* Initialise SMB connection */
163         fstrcpy(new_conn->pipe_name, get_pipe_name_from_index(pipe_index));
164
165 /* grab stored passwords */
166         machine_password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
167         
168         if (asprintf(&machine_krb5_principal, "%s$@%s", global_myname(), lp_realm()) == -1) {
169                 SAFE_FREE(machine_password);
170                 return NT_STATUS_NO_MEMORY;
171         }
172
173         cm_get_ipc_userpass(&ipc_username, &ipc_domain, &ipc_password);
174
175         for (i = 0; retry && (i < 3); i++) {
176                 BOOL got_mutex;
177                 if (!(got_mutex = secrets_named_mutex(new_conn->controller, WINBIND_SERVER_MUTEX_WAIT_TIME))) {
178                         DEBUG(0,("cm_open_connection: mutex grab failed for %s\n", new_conn->controller));
179                         result = NT_STATUS_POSSIBLE_DEADLOCK;
180                         continue;
181                 }
182                 
183                 new_conn->cli = NULL;
184                 result = cli_start_connection(&new_conn->cli, global_myname(), 
185                                               new_conn->controller, 
186                                               &dc_ip, 0, Undefined, 
187                                               CLI_FULL_CONNECTION_USE_KERBEROS, 
188                                               &retry);
189
190                 if (NT_STATUS_IS_OK(result)) {
191
192                         /* reset the error code */
193                         result = NT_STATUS_UNSUCCESSFUL; 
194
195                         /* Krb5 session */
196                         
197                         if ((lp_security() == SEC_ADS) 
198                                 && (new_conn->cli->protocol >= PROTOCOL_NT1 && new_conn->cli->capabilities & CAP_EXTENDED_SECURITY)) {
199                                 ADS_STATUS ads_status;
200                                 new_conn->cli->use_kerberos = True;
201                                 DEBUG(5, ("connecting to %s from %s with kerberos principal [%s]\n", 
202                                           new_conn->controller, global_myname(), machine_krb5_principal));
203
204                                 ads_status = cli_session_setup_spnego(new_conn->cli, machine_krb5_principal, 
205                                                                       machine_password, 
206                                                                       lp_workgroup());
207                                 if (!ADS_ERR_OK(ads_status)) {
208                                         DEBUG(4,("failed kerberos session setup with %s\n", ads_errstr(ads_status)));
209                                         result = ads_ntstatus(ads_status);
210                                 } else {
211                                         result = NT_STATUS_OK;
212                                 }
213                         }
214                         new_conn->cli->use_kerberos = False;
215                         
216                         /* only do this is we have a username/password for thr IPC$ connection */
217                         
218                         if ( !NT_STATUS_IS_OK(result) 
219                                 && new_conn->cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE
220                                 && strlen(ipc_username) )
221                         {       
222                                 DEBUG(5, ("connecting to %s from %s with username [%s]\\[%s]\n", 
223                                           new_conn->controller, global_myname(), ipc_domain, ipc_username));
224
225                                 result = NT_STATUS_OK;
226
227                                 if (!cli_session_setup(new_conn->cli, ipc_username, 
228                                                        ipc_password, strlen(ipc_password)+1, 
229                                                        ipc_password, strlen(ipc_password)+1, 
230                                                        ipc_domain)) {
231                                         result = cli_nt_error(new_conn->cli);
232                                         DEBUG(4,("failed authenticated session setup with %s\n", nt_errstr(result)));
233                                         if (NT_STATUS_IS_OK(result)) 
234                                                 result = NT_STATUS_UNSUCCESSFUL;
235                                 }
236                         }
237                         
238                         /* anonymous is all that is left if we get to here */
239                         
240                         if (!NT_STATUS_IS_OK(result)) { 
241                         
242                                 DEBUG(5, ("anonymous connection attempt to %s from %s\n", 
243                                           new_conn->controller, global_myname()));
244                                           
245                                 result = NT_STATUS_OK;
246
247                                 if (!cli_session_setup(new_conn->cli, "", NULL, 0, NULL, 0, "")) 
248                                 {
249                                         result = cli_nt_error(new_conn->cli);
250                                         DEBUG(4,("failed anonymous session setup with %s\n", nt_errstr(result)));
251                                         if (NT_STATUS_IS_OK(result)) 
252                                                 result = NT_STATUS_UNSUCCESSFUL;
253                                 } 
254                                 
255                         }
256
257                         if (NT_STATUS_IS_OK(result) && !cli_send_tconX(new_conn->cli, "IPC$", "IPC",
258                                                                        "", 0)) {
259                                 result = cli_nt_error(new_conn->cli);
260                                 DEBUG(1,("failed tcon_X with %s\n", nt_errstr(result)));
261                                 cli_shutdown(new_conn->cli);
262                                 if (NT_STATUS_IS_OK(result)) {
263                                         result = NT_STATUS_UNSUCCESSFUL;
264                                 }
265                         }
266                 }
267
268                 if (NT_STATUS_IS_OK(result)) {
269                         struct ntuser_creds creds;
270                         init_creds(&creds, ipc_username, ipc_domain, ipc_password);
271                         cli_init_creds(new_conn->cli, &creds);
272                 }
273
274                 if (got_mutex)
275                         secrets_named_mutex_release(new_conn->controller);
276
277                 if (NT_STATUS_IS_OK(result))
278                         break;
279         }
280
281         /* try and use schannel if possible, but continue anyway if it
282            failed. This allows existing setups to continue working,
283            while solving the win2003 '100 user' limit for systems that
284            are joined properly */
285         if (NT_STATUS_IS_OK(result)) {
286                 NTSTATUS status = setup_schannel(new_conn->cli);
287                 if (!NT_STATUS_IS_OK(status)) {
288                         DEBUG(3,("schannel refused - continuing without schannel (%s)\n", 
289                                  nt_errstr(status)));
290                 }
291         }
292
293         SAFE_FREE(ipc_username);
294         SAFE_FREE(ipc_domain);
295         SAFE_FREE(ipc_password);
296         SAFE_FREE(machine_password);
297         SAFE_FREE(machine_krb5_principal);
298
299         if (!NT_STATUS_IS_OK(result)) {
300                 add_failed_connection_entry(domain->name, new_conn->controller, result);
301                 return result;
302         }
303         
304         /* set the domain if empty; needed for schannel connections */
305         if ( !*new_conn->cli->domain )
306                 fstrcpy( new_conn->cli->domain, domain->name );
307                 
308         
309         if ( !cli_nt_session_open (new_conn->cli, pipe_index) ) {
310                 result = NT_STATUS_PIPE_NOT_AVAILABLE;
311                 /* 
312                  * only cache a failure if we are not trying to open the 
313                  * **win2k** specific lsarpc UUID.  This could be an NT PDC 
314                  * and therefore a failure is normal.  This should probably
315                  * be abstracted to a check for 2k specific pipes and wondering
316                  * if the PDC is an NT4 box.   but since there is only one 2k 
317                  * specific UUID right now, i'm not going to bother.  --jerry
318                  */
319                 if ( !is_win2k_pipe(pipe_index) )
320                         add_failed_connection_entry(domain->name, new_conn->controller, result);
321                 cli_shutdown(new_conn->cli);
322                 return result;
323         }
324
325         return NT_STATUS_OK;
326 }
327
328 /************************************************************************
329  Wrapper around statuc cm_open_connection to retreive a freshly
330  setup cli_state struct
331 ************************************************************************/
332
333 NTSTATUS cm_fresh_connection(struct winbindd_domain *domain, const int pipe_index,
334                                struct cli_state **cli)
335 {
336         NTSTATUS result;
337         struct winbindd_cm_conn conn;
338         
339         result = cm_open_connection( domain, pipe_index, &conn );
340         
341         if ( NT_STATUS_IS_OK(result) ) 
342                 *cli = conn.cli;
343
344         return result;
345 }
346
347 /* Return true if a connection is still alive */
348
349 static BOOL connection_ok(struct winbindd_cm_conn *conn)
350 {
351         if (!conn) {
352                 smb_panic("Invalid parameter passed to connection_ok():  conn was NULL!\n");
353                 return False;
354         }
355
356         if (!conn->cli) {
357                 DEBUG(3, ("Connection to %s for domain %s (pipe %s) has NULL conn->cli!\n", 
358                           conn->controller, conn->domain, conn->pipe_name));
359                 return False;
360         }
361
362         if (!conn->cli->initialised) {
363                 DEBUG(3, ("Connection to %s for domain %s (pipe %s) was never initialised!\n", 
364                           conn->controller, conn->domain, conn->pipe_name));
365                 return False;
366         }
367
368         if (conn->cli->fd == -1) {
369                 DEBUG(3, ("Connection to %s for domain %s (pipe %s) has died or was never started (fd == -1)\n", 
370                           conn->controller, conn->domain, conn->pipe_name));
371                 return False;
372         }
373         
374         return True;
375 }
376
377 /* Search the cache for a connection. If there is a broken one,
378    shut it down properly and return NULL. */
379
380 static void find_cm_connection(struct winbindd_domain *domain, const char *pipe_name,
381                                struct winbindd_cm_conn **conn_out) 
382 {
383         struct winbindd_cm_conn *conn;
384
385         for (conn = cm_conns; conn; ) {
386                 if (strequal(conn->domain, domain->name) && 
387                     strequal(conn->pipe_name, pipe_name)) {
388                         if (!connection_ok(conn)) {
389                                 /* Dead connection - remove it. */
390                                 struct winbindd_cm_conn *conn_temp = conn->next;
391                                 if (conn->cli)
392                                         cli_shutdown(conn->cli);
393                                 DLIST_REMOVE(cm_conns, conn);
394                                 SAFE_FREE(conn);
395                                 conn = conn_temp;  /* Keep the loop moving */
396                                 continue;
397                         } else {
398                                 break;
399                         }
400                 }
401                 conn = conn->next;
402         }
403
404         *conn_out = conn;
405 }
406
407 /* Initialize a new connection up to the RPC BIND. */
408
409 static NTSTATUS new_cm_connection(struct winbindd_domain *domain, const char *pipe_name,
410                                   struct winbindd_cm_conn **conn_out)
411 {
412         struct winbindd_cm_conn *conn;
413         NTSTATUS result;
414
415         if (!(conn = malloc(sizeof(*conn))))
416                 return NT_STATUS_NO_MEMORY;
417                 
418         ZERO_STRUCTP(conn);
419                 
420         if (!NT_STATUS_IS_OK(result = cm_open_connection(domain, get_pipe_index(pipe_name), conn))) {
421                 DEBUG(3, ("Could not open a connection to %s for %s (%s)\n", 
422                           domain->name, pipe_name, nt_errstr(result)));
423                 SAFE_FREE(conn);
424                 return result;
425         }
426         DLIST_ADD(cm_conns, conn);
427
428         *conn_out = conn;
429         return NT_STATUS_OK;
430 }
431
432 /* Get a connection to the remote DC and open the pipe.  If there is already a connection, use that */
433
434 static NTSTATUS get_connection_from_cache(struct winbindd_domain *domain, const char *pipe_name,
435                                           struct winbindd_cm_conn **conn_out)
436 {
437         find_cm_connection(domain, pipe_name, conn_out);
438
439         if (*conn_out != NULL)
440                 return NT_STATUS_OK;
441
442         return new_cm_connection(domain, pipe_name, conn_out);
443 }
444
445 /**********************************************************************************
446  We can 'sense' certain things about the DC by it's replies to certain questions.
447
448  This tells us if this particular remote server is Active Directory, and if it is
449  native mode.
450 **********************************************************************************/
451
452 void set_dc_type_and_flags( struct winbindd_domain *domain )
453 {
454         NTSTATUS                result;
455         struct winbindd_cm_conn conn;
456         DS_DOMINFO_CTR          ctr;
457         TALLOC_CTX              *mem_ctx = NULL;
458         
459         ZERO_STRUCT( conn );
460         ZERO_STRUCT( ctr );
461         
462         domain->native_mode = False;
463         domain->active_directory = False;
464         
465         if ( !NT_STATUS_IS_OK(result = cm_open_connection(domain, PI_LSARPC_DS, &conn)) ) {
466                 DEBUG(5, ("set_dc_type_and_flags: Could not open a connection to %s for PIPE_LSARPC (%s)\n", 
467                           domain->name, nt_errstr(result)));
468                 return;
469         }
470         
471         if ( conn.cli ) {
472                 if ( !NT_STATUS_IS_OK(cli_ds_getprimarydominfo( conn.cli, 
473                                 conn.cli->mem_ctx, DsRolePrimaryDomainInfoBasic, &ctr)) ) {
474                         goto done;
475                 }
476         }
477                                 
478         if ( (ctr.basic->flags & DSROLE_PRIMARY_DS_RUNNING) 
479                         && !(ctr.basic->flags & DSROLE_PRIMARY_DS_MIXED_MODE) )
480                 domain->native_mode = True;
481
482         /* Cheat - shut down the DS pipe, and open LSA */
483
484         cli_nt_session_close(conn.cli);
485
486         if ( cli_nt_session_open (conn.cli, PI_LSARPC) ) {
487                 char *domain_name = NULL;
488                 char *dns_name = NULL;
489                 DOM_SID *dom_sid = NULL;
490
491                 mem_ctx = talloc_init("set_dc_type_and_flags on domain %s\n", domain->name);
492                 if (!mem_ctx) {
493                         DEBUG(1, ("set_dc_type_and_flags: talloc_init() failed\n"));
494                         return;
495                 }
496
497                 result = cli_lsa_open_policy2(conn.cli, mem_ctx, True, 
498                                               SEC_RIGHTS_MAXIMUM_ALLOWED,
499                                               &conn.pol);
500                 
501                 if (NT_STATUS_IS_OK(result)) {
502                         /* This particular query is exactly what Win2k clients use 
503                            to determine that the DC is active directory */
504                         result = cli_lsa_query_info_policy2(conn.cli, mem_ctx, 
505                                                             &conn.pol,
506                                                             12, &domain_name,
507                                                             &dns_name, NULL,
508                                                             NULL, &dom_sid);
509                 }
510
511                 if (NT_STATUS_IS_OK(result)) {
512                         if (domain_name)
513                                 fstrcpy(domain->name, domain_name);
514                         
515                         if (dns_name)
516                                 fstrcpy(domain->alt_name, dns_name);
517
518                         if (dom_sid) 
519                                 sid_copy(&domain->sid, dom_sid);
520
521                         domain->active_directory = True;
522                 } else {
523                         
524                         result = cli_lsa_open_policy(conn.cli, mem_ctx, True, 
525                                                      SEC_RIGHTS_MAXIMUM_ALLOWED,
526                                                      &conn.pol);
527                         
528                         if (!NT_STATUS_IS_OK(result))
529                                 goto done;
530                         
531                         result = cli_lsa_query_info_policy(conn.cli, mem_ctx, 
532                                                            &conn.pol, 5, &domain_name, 
533                                                            &dom_sid);
534                         
535                         if (NT_STATUS_IS_OK(result)) {
536                                 if (domain_name)
537                                         fstrcpy(domain->name, domain_name);
538                                 
539                                 if (dom_sid) 
540                                         sid_copy(&domain->sid, dom_sid);
541                         }
542                 }
543         }
544         
545 done:
546         
547         /* close the connection;  no other calls use this pipe and it is called only
548            on reestablishing the domain list   --jerry */
549         
550         if ( conn.cli )
551                 cli_shutdown( conn.cli );
552         
553         talloc_destroy(mem_ctx);
554         
555         return;
556 }
557
558
559
560 /* Return a LSA policy handle on a domain */
561
562 NTSTATUS cm_get_lsa_handle(struct winbindd_domain *domain, CLI_POLICY_HND **return_hnd)
563 {
564         struct winbindd_cm_conn *conn;
565         uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
566         NTSTATUS result;
567         static CLI_POLICY_HND hnd;
568
569         /* Look for existing connections */
570
571         if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_LSARPC, &conn)))
572                 return result;
573
574         /* This *shitty* code needs scrapping ! JRA */
575         
576         if (policy_handle_is_valid(&conn->pol)) {
577                 hnd.pol = conn->pol;
578                 hnd.cli = conn->cli;
579                 *return_hnd = &hnd;
580
581                 return NT_STATUS_OK;
582         }
583         
584         result = cli_lsa_open_policy(conn->cli, conn->cli->mem_ctx, False, 
585                                      des_access, &conn->pol);
586
587         if (!NT_STATUS_IS_OK(result)) {
588                 /* Hit the cache code again.  This cleans out the old connection and gets a new one */
589                 if (conn->cli->fd == -1) { /* Try again, if the remote host disapeared */
590                         if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_LSARPC, &conn)))
591                                 return result;
592
593                         result = cli_lsa_open_policy(conn->cli, conn->cli->mem_ctx, False, 
594                                                      des_access, &conn->pol);
595                 }
596
597                 if (!NT_STATUS_IS_OK(result)) {
598                         cli_shutdown(conn->cli);
599                         DLIST_REMOVE(cm_conns, conn);
600                         SAFE_FREE(conn);
601                         return result;
602                 }
603         }       
604
605         hnd.pol = conn->pol;
606         hnd.cli = conn->cli;
607
608         *return_hnd = &hnd;
609
610         return NT_STATUS_OK;
611 }
612
613 /* Return a SAM policy handle on a domain */
614
615 NTSTATUS cm_get_sam_handle(struct winbindd_domain *domain, CLI_POLICY_HND **return_hnd)
616
617         struct winbindd_cm_conn *conn;
618         uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
619         NTSTATUS result;
620         static CLI_POLICY_HND hnd;
621
622         /* Look for existing connections */
623
624         if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_SAMR, &conn)))
625                 return result;
626         
627         /* This *shitty* code needs scrapping ! JRA */
628         
629         if (policy_handle_is_valid(&conn->pol)) {
630                 hnd.pol = conn->pol;
631                 hnd.cli = conn->cli;
632                 
633                 *return_hnd = &hnd;
634
635                 return NT_STATUS_OK;
636         }
637         
638         result = cli_samr_connect(conn->cli, conn->cli->mem_ctx,
639                                   des_access, &conn->pol);
640
641         if (!NT_STATUS_IS_OK(result)) {
642                 /* Hit the cache code again.  This cleans out the old connection and gets a new one */
643                 if (conn->cli->fd == -1) { /* Try again, if the remote host disapeared */
644                 
645                         if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_SAMR, &conn)))
646                                 return result;
647
648                         result = cli_samr_connect(conn->cli, conn->cli->mem_ctx,
649                                                   des_access, &conn->pol);
650                 }
651
652                 if (!NT_STATUS_IS_OK(result)) {
653                 
654                         cli_shutdown(conn->cli);
655                         DLIST_REMOVE(cm_conns, conn);
656                         SAFE_FREE(conn);
657                         
658                         return result;
659                 }
660         }       
661
662         hnd.pol = conn->pol;
663         hnd.cli = conn->cli;
664
665         *return_hnd = &hnd;
666
667         return NT_STATUS_OK;
668 }
669
670 /* Get a handle on a netlogon pipe.  This is a bit of a hack to re-use the
671    netlogon pipe as no handle is returned. */
672
673 NTSTATUS cm_get_netlogon_cli(struct winbindd_domain *domain, 
674                              const unsigned char *trust_passwd, 
675                              uint32 sec_channel_type,
676                              BOOL fresh,
677                              struct cli_state **cli)
678 {
679         NTSTATUS result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
680         struct winbindd_cm_conn *conn;
681         fstring lock_name;
682         BOOL got_mutex;
683
684         if (!cli)
685                 return NT_STATUS_INVALID_PARAMETER;
686
687         /* Open an initial conection - keep the mutex. */
688
689         find_cm_connection(domain, PIPE_NETLOGON, &conn);
690
691         if ( fresh && (conn != NULL) ) {
692                 cli_shutdown(conn->cli);
693                 conn->cli = NULL;
694
695                 conn = NULL;
696
697                 /* purge connection from cache */
698                 find_cm_connection(domain, PIPE_NETLOGON, &conn);
699                 if (conn != NULL) {
700                         DEBUG(0,("Could not purge connection\n"));
701                         return NT_STATUS_UNSUCCESSFUL;
702                 }
703         }
704
705         if (conn != NULL) {
706                 *cli = conn->cli;
707                 return NT_STATUS_OK;
708         }
709
710         result = new_cm_connection(domain, PIPE_NETLOGON, &conn);
711
712         if (!NT_STATUS_IS_OK(result))
713                 return result;
714         
715         fstr_sprintf(lock_name, "NETLOGON\\%s", conn->controller);
716
717         if (!(got_mutex = secrets_named_mutex(lock_name, WINBIND_SERVER_MUTEX_WAIT_TIME))) {
718                 DEBUG(0,("cm_get_netlogon_cli: mutex grab failed for %s\n", conn->controller));
719         }
720         
721         if ( sec_channel_type == SEC_CHAN_DOMAIN )
722                 fstr_sprintf(conn->cli->mach_acct, "%s$", lp_workgroup());
723                         
724         /* This must be the remote domain (not ours) for schannel */
725
726         fstrcpy( conn->cli->domain, domain->name);
727         
728         result = cli_nt_establish_netlogon(conn->cli, sec_channel_type, trust_passwd);
729         
730         if (got_mutex)
731                 secrets_named_mutex_release(lock_name);
732                                 
733         if (!NT_STATUS_IS_OK(result)) {
734                 cli_shutdown(conn->cli);
735                 DLIST_REMOVE(cm_conns, conn);
736                 SAFE_FREE(conn);
737                 return result;
738         }
739
740         *cli = conn->cli;
741
742         return result;
743 }
744
745 /* Dump the current connection status */
746
747 static void dump_conn_list(void)
748 {
749         struct winbindd_cm_conn *con;
750
751         DEBUG(0, ("\tDomain          Controller      Pipe\n"));
752
753         for(con = cm_conns; con; con = con->next) {
754                 char *msg;
755
756                 /* Display pipe info */
757                 
758                 if (asprintf(&msg, "\t%-15s %-15s %-16s", con->domain, con->controller, con->pipe_name) < 0) {
759                         DEBUG(0, ("Error: not enough memory!\n"));
760                 } else {
761                         DEBUG(0, ("%s\n", msg));
762                         SAFE_FREE(msg);
763                 }
764         }
765 }
766
767 void winbindd_cm_status(void)
768 {
769         /* List open connections */
770
771         DEBUG(0, ("winbindd connection manager status:\n"));
772
773         if (cm_conns)
774                 dump_conn_list();
775         else
776                 DEBUG(0, ("\tNo active connections\n"));
777 }
778
779 /* Close all cached connections */
780
781 void winbindd_cm_flush(void)
782 {
783         struct winbindd_cm_conn *conn, tmp;
784
785         /* Flush connection cache */
786
787         for (conn = cm_conns; conn; conn = conn->next) {
788
789                 if (!connection_ok(conn))
790                         continue;
791
792                 DEBUG(10, ("Closing connection to %s on %s\n",
793                         conn->pipe_name, conn->controller));
794
795                 if (conn->cli)
796                         cli_shutdown(conn->cli);
797
798                 tmp.next = conn->next;
799
800                 DLIST_REMOVE(cm_conns, conn);
801                 SAFE_FREE(conn);
802                 conn = &tmp;
803         }
804
805         /* Flush failed connection cache */
806
807         flush_negative_conn_cache();
808 }