r148: Ensure we do not dereference a null pointer when we return the user
[Samba/gebeck_regimport.git] / source3 / nsswitch / winbindd_cm.c
blobb2d6e861a3d7197de2baeeb42bd58a0aff39f481
1 /*
2 Unix SMB/CIFS implementation.
4 Winbind daemon connection manager
6 Copyright (C) Tim Potter 2001
7 Copyright (C) Andrew Bartlett 2002
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.
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.
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.
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:
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
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.
43 The TNG design is quite good but I disagree with some aspects of the
44 implementation. -tpot
49 TODO:
51 - I'm pretty annoyed by all the make_nmb_name() stuff. It should be
52 moved down into another function.
54 - Take care when destroying cli_structs as they can be shared between
55 various sam handles.
59 #include "includes.h"
60 #include "winbindd.h"
62 #undef DBGC_CLASS
63 #define DBGC_CLASS DBGC_WINBIND
65 /* Global list of connections. Initially a DLIST but can become a hash
66 table or whatever later. */
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;
78 static struct winbindd_cm_conn *cm_conns = NULL;
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.
86 Caller to free() result in domain, username, password
89 static void cm_get_ipc_userpass(char **username, char **domain, char **password)
91 *username = secrets_fetch(SECRETS_AUTH_USER, NULL);
92 *domain = secrets_fetch(SECRETS_AUTH_DOMAIN, NULL);
93 *password = secrets_fetch(SECRETS_AUTH_PASSWORD, NULL);
95 if (*username && **username) {
97 if (!*domain || !**domain)
98 *domain = smb_xstrdup(lp_workgroup());
100 if (!*password || !**password)
101 *password = smb_xstrdup("");
103 DEBUG(3, ("IPC$ connections done by user %s\\%s\n",
104 *domain, *username));
106 } else {
107 DEBUG(3, ("IPC$ connections done anonymously\n"));
108 *username = smb_xstrdup("");
109 *domain = smb_xstrdup("");
110 *password = smb_xstrdup("");
115 setup for schannel on any pipes opened on this connection
117 static NTSTATUS setup_schannel(struct cli_state *cli)
119 NTSTATUS ret;
120 uchar trust_password[16];
121 uint32 sec_channel_type;
123 if (!secrets_fetch_trust_account_password(lp_workgroup(),
124 trust_password,
125 NULL, &sec_channel_type)) {
126 return NT_STATUS_UNSUCCESSFUL;
129 ret = cli_nt_setup_netsec(cli, sec_channel_type,
130 AUTH_PIPE_NETSEC | AUTH_PIPE_SIGN,
131 trust_password);
133 return ret;
136 /* Open a connction to the remote server, cache failures for 30 seconds */
138 static NTSTATUS cm_open_connection(const struct winbindd_domain *domain, const int pipe_index,
139 struct winbindd_cm_conn *new_conn)
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;
148 ZERO_STRUCT(dc_ip);
150 fstrcpy(new_conn->domain, domain->name);
152 /* connection failure cache has been moved inside of get_dc_name
153 so we can deal with half dead DC's --jerry */
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;
162 /* Initialise SMB connection */
163 fstrcpy(new_conn->pipe_name, get_pipe_name_from_index(pipe_index));
165 /* grab stored passwords */
166 machine_password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
168 if (asprintf(&machine_krb5_principal, "%s$@%s", global_myname(), lp_realm()) == -1) {
169 SAFE_FREE(machine_password);
170 return NT_STATUS_NO_MEMORY;
173 cm_get_ipc_userpass(&ipc_username, &ipc_domain, &ipc_password);
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;
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);
190 if (NT_STATUS_IS_OK(result)) {
192 /* reset the error code */
193 result = NT_STATUS_UNSUCCESSFUL;
195 /* Krb5 session */
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));
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;
214 new_conn->cli->use_kerberos = False;
216 /* only do this is we have a username/password for thr IPC$ connection */
218 if ( !NT_STATUS_IS_OK(result)
219 && new_conn->cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE
220 && strlen(ipc_username) )
222 DEBUG(5, ("connecting to %s from %s with username [%s]\\[%s]\n",
223 new_conn->controller, global_myname(), ipc_domain, ipc_username));
225 result = NT_STATUS_OK;
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;
238 /* anonymous is all that is left if we get to here */
240 if (!NT_STATUS_IS_OK(result)) {
242 DEBUG(5, ("anonymous connection attempt to %s from %s\n",
243 new_conn->controller, global_myname()));
245 result = NT_STATUS_OK;
247 if (!cli_session_setup(new_conn->cli, "", NULL, 0, NULL, 0, ""))
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;
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;
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);
274 if (got_mutex)
275 secrets_named_mutex_release(new_conn->controller);
277 if (NT_STATUS_IS_OK(result))
278 break;
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)));
293 SAFE_FREE(ipc_username);
294 SAFE_FREE(ipc_domain);
295 SAFE_FREE(ipc_password);
296 SAFE_FREE(machine_password);
298 if (!NT_STATUS_IS_OK(result)) {
299 add_failed_connection_entry(domain->name, new_conn->controller, result);
300 return result;
303 /* set the domain if empty; needed for schannel connections */
304 if ( !*new_conn->cli->domain )
305 fstrcpy( new_conn->cli->domain, domain->name );
308 if ( !cli_nt_session_open (new_conn->cli, pipe_index) ) {
309 result = NT_STATUS_PIPE_NOT_AVAILABLE;
311 * only cache a failure if we are not trying to open the
312 * **win2k** specific lsarpc UUID. This could be an NT PDC
313 * and therefore a failure is normal. This should probably
314 * be abstracted to a check for 2k specific pipes and wondering
315 * if the PDC is an NT4 box. but since there is only one 2k
316 * specific UUID right now, i'm not going to bother. --jerry
318 if ( !is_win2k_pipe(pipe_index) )
319 add_failed_connection_entry(domain->name, new_conn->controller, result);
320 cli_shutdown(new_conn->cli);
321 return result;
324 return NT_STATUS_OK;
327 /************************************************************************
328 Wrapper around statuc cm_open_connection to retreive a freshly
329 setup cli_state struct
330 ************************************************************************/
332 NTSTATUS cm_fresh_connection(struct winbindd_domain *domain, const int pipe_index,
333 struct cli_state **cli)
335 NTSTATUS result;
336 struct winbindd_cm_conn conn;
338 result = cm_open_connection( domain, pipe_index, &conn );
340 if ( NT_STATUS_IS_OK(result) )
341 *cli = conn.cli;
343 return result;
346 /* Return true if a connection is still alive */
348 static BOOL connection_ok(struct winbindd_cm_conn *conn)
350 if (!conn) {
351 smb_panic("Invalid parameter passed to connection_ok(): conn was NULL!\n");
352 return False;
355 if (!conn->cli) {
356 DEBUG(3, ("Connection to %s for domain %s (pipe %s) has NULL conn->cli!\n",
357 conn->controller, conn->domain, conn->pipe_name));
358 return False;
361 if (!conn->cli->initialised) {
362 DEBUG(3, ("Connection to %s for domain %s (pipe %s) was never initialised!\n",
363 conn->controller, conn->domain, conn->pipe_name));
364 return False;
367 if (conn->cli->fd == -1) {
368 DEBUG(3, ("Connection to %s for domain %s (pipe %s) has died or was never started (fd == -1)\n",
369 conn->controller, conn->domain, conn->pipe_name));
370 return False;
373 return True;
376 /* Search the cache for a connection. If there is a broken one,
377 shut it down properly and return NULL. */
379 static void find_cm_connection(struct winbindd_domain *domain, const char *pipe_name,
380 struct winbindd_cm_conn **conn_out)
382 struct winbindd_cm_conn *conn;
384 for (conn = cm_conns; conn; ) {
385 if (strequal(conn->domain, domain->name) &&
386 strequal(conn->pipe_name, pipe_name)) {
387 if (!connection_ok(conn)) {
388 /* Dead connection - remove it. */
389 struct winbindd_cm_conn *conn_temp = conn->next;
390 if (conn->cli)
391 cli_shutdown(conn->cli);
392 DLIST_REMOVE(cm_conns, conn);
393 SAFE_FREE(conn);
394 conn = conn_temp; /* Keep the loop moving */
395 continue;
396 } else {
397 break;
400 conn = conn->next;
403 *conn_out = conn;
406 /* Initialize a new connection up to the RPC BIND. */
408 static NTSTATUS new_cm_connection(struct winbindd_domain *domain, const char *pipe_name,
409 struct winbindd_cm_conn **conn_out)
411 struct winbindd_cm_conn *conn;
412 NTSTATUS result;
414 if (!(conn = malloc(sizeof(*conn))))
415 return NT_STATUS_NO_MEMORY;
417 ZERO_STRUCTP(conn);
419 if (!NT_STATUS_IS_OK(result = cm_open_connection(domain, get_pipe_index(pipe_name), conn))) {
420 DEBUG(3, ("Could not open a connection to %s for %s (%s)\n",
421 domain->name, pipe_name, nt_errstr(result)));
422 SAFE_FREE(conn);
423 return result;
425 DLIST_ADD(cm_conns, conn);
427 *conn_out = conn;
428 return NT_STATUS_OK;
431 /* Get a connection to the remote DC and open the pipe. If there is already a connection, use that */
433 static NTSTATUS get_connection_from_cache(struct winbindd_domain *domain, const char *pipe_name,
434 struct winbindd_cm_conn **conn_out)
436 find_cm_connection(domain, pipe_name, conn_out);
438 if (*conn_out != NULL)
439 return NT_STATUS_OK;
441 return new_cm_connection(domain, pipe_name, conn_out);
444 /**********************************************************************************
445 We can 'sense' certain things about the DC by it's replies to certain questions.
447 This tells us if this particular remote server is Active Directory, and if it is
448 native mode.
449 **********************************************************************************/
451 void set_dc_type_and_flags( struct winbindd_domain *domain )
453 NTSTATUS result;
454 struct winbindd_cm_conn conn;
455 DS_DOMINFO_CTR ctr;
456 TALLOC_CTX *mem_ctx = NULL;
458 ZERO_STRUCT( conn );
459 ZERO_STRUCT( ctr );
461 domain->native_mode = False;
462 domain->active_directory = False;
464 if ( !NT_STATUS_IS_OK(result = cm_open_connection(domain, PI_LSARPC_DS, &conn)) ) {
465 DEBUG(5, ("set_dc_type_and_flags: Could not open a connection to %s for PIPE_LSARPC (%s)\n",
466 domain->name, nt_errstr(result)));
467 return;
470 if ( conn.cli ) {
471 if ( !NT_STATUS_IS_OK(cli_ds_getprimarydominfo( conn.cli,
472 conn.cli->mem_ctx, DsRolePrimaryDomainInfoBasic, &ctr)) ) {
473 goto done;
477 if ( (ctr.basic->flags & DSROLE_PRIMARY_DS_RUNNING)
478 && !(ctr.basic->flags & DSROLE_PRIMARY_DS_MIXED_MODE) )
479 domain->native_mode = True;
481 /* Cheat - shut down the DS pipe, and open LSA */
483 cli_nt_session_close(conn.cli);
485 if ( cli_nt_session_open (conn.cli, PI_LSARPC) ) {
486 char *domain_name = NULL;
487 char *dns_name = NULL;
488 DOM_SID *dom_sid = NULL;
490 mem_ctx = talloc_init("set_dc_type_and_flags on domain %s\n", domain->name);
491 if (!mem_ctx) {
492 DEBUG(1, ("set_dc_type_and_flags: talloc_init() failed\n"));
493 return;
496 result = cli_lsa_open_policy2(conn.cli, mem_ctx, True,
497 SEC_RIGHTS_MAXIMUM_ALLOWED,
498 &conn.pol);
500 if (NT_STATUS_IS_OK(result)) {
501 /* This particular query is exactly what Win2k clients use
502 to determine that the DC is active directory */
503 result = cli_lsa_query_info_policy2(conn.cli, mem_ctx,
504 &conn.pol,
505 12, &domain_name,
506 &dns_name, NULL,
507 NULL, &dom_sid);
510 if (NT_STATUS_IS_OK(result)) {
511 if (domain_name)
512 fstrcpy(domain->name, domain_name);
514 if (dns_name)
515 fstrcpy(domain->alt_name, dns_name);
517 if (dom_sid)
518 sid_copy(&domain->sid, dom_sid);
520 domain->active_directory = True;
521 } else {
523 result = cli_lsa_open_policy(conn.cli, mem_ctx, True,
524 SEC_RIGHTS_MAXIMUM_ALLOWED,
525 &conn.pol);
527 if (!NT_STATUS_IS_OK(result))
528 goto done;
530 result = cli_lsa_query_info_policy(conn.cli, mem_ctx,
531 &conn.pol, 5, &domain_name,
532 &dom_sid);
534 if (NT_STATUS_IS_OK(result)) {
535 if (domain_name)
536 fstrcpy(domain->name, domain_name);
538 if (dom_sid)
539 sid_copy(&domain->sid, dom_sid);
544 done:
546 /* close the connection; no other calls use this pipe and it is called only
547 on reestablishing the domain list --jerry */
549 if ( conn.cli )
550 cli_shutdown( conn.cli );
552 talloc_destroy(mem_ctx);
554 return;
559 /* Return a LSA policy handle on a domain */
561 NTSTATUS cm_get_lsa_handle(struct winbindd_domain *domain, CLI_POLICY_HND **return_hnd)
563 struct winbindd_cm_conn *conn;
564 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
565 NTSTATUS result;
566 static CLI_POLICY_HND hnd;
568 /* Look for existing connections */
570 if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_LSARPC, &conn)))
571 return result;
573 /* This *shitty* code needs scrapping ! JRA */
575 if (policy_handle_is_valid(&conn->pol)) {
576 hnd.pol = conn->pol;
577 hnd.cli = conn->cli;
578 *return_hnd = &hnd;
580 return NT_STATUS_OK;
583 result = cli_lsa_open_policy(conn->cli, conn->cli->mem_ctx, False,
584 des_access, &conn->pol);
586 if (!NT_STATUS_IS_OK(result)) {
587 /* Hit the cache code again. This cleans out the old connection and gets a new one */
588 if (conn->cli->fd == -1) { /* Try again, if the remote host disapeared */
589 if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_LSARPC, &conn)))
590 return result;
592 result = cli_lsa_open_policy(conn->cli, conn->cli->mem_ctx, False,
593 des_access, &conn->pol);
596 if (!NT_STATUS_IS_OK(result)) {
597 cli_shutdown(conn->cli);
598 DLIST_REMOVE(cm_conns, conn);
599 SAFE_FREE(conn);
600 return result;
604 hnd.pol = conn->pol;
605 hnd.cli = conn->cli;
607 *return_hnd = &hnd;
609 return NT_STATUS_OK;
612 /* Return a SAM policy handle on a domain */
614 NTSTATUS cm_get_sam_handle(struct winbindd_domain *domain, CLI_POLICY_HND **return_hnd)
616 struct winbindd_cm_conn *conn;
617 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
618 NTSTATUS result;
619 static CLI_POLICY_HND hnd;
621 /* Look for existing connections */
623 if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_SAMR, &conn)))
624 return result;
626 /* This *shitty* code needs scrapping ! JRA */
628 if (policy_handle_is_valid(&conn->pol)) {
629 hnd.pol = conn->pol;
630 hnd.cli = conn->cli;
632 *return_hnd = &hnd;
634 return NT_STATUS_OK;
637 result = cli_samr_connect(conn->cli, conn->cli->mem_ctx,
638 des_access, &conn->pol);
640 if (!NT_STATUS_IS_OK(result)) {
641 /* Hit the cache code again. This cleans out the old connection and gets a new one */
642 if (conn->cli->fd == -1) { /* Try again, if the remote host disapeared */
644 if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_SAMR, &conn)))
645 return result;
647 result = cli_samr_connect(conn->cli, conn->cli->mem_ctx,
648 des_access, &conn->pol);
651 if (!NT_STATUS_IS_OK(result)) {
653 cli_shutdown(conn->cli);
654 DLIST_REMOVE(cm_conns, conn);
655 SAFE_FREE(conn);
657 return result;
661 hnd.pol = conn->pol;
662 hnd.cli = conn->cli;
664 *return_hnd = &hnd;
666 return NT_STATUS_OK;
669 /* Get a handle on a netlogon pipe. This is a bit of a hack to re-use the
670 netlogon pipe as no handle is returned. */
672 NTSTATUS cm_get_netlogon_cli(struct winbindd_domain *domain,
673 const unsigned char *trust_passwd,
674 uint32 sec_channel_type,
675 BOOL fresh,
676 struct cli_state **cli)
678 NTSTATUS result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
679 struct winbindd_cm_conn *conn;
680 fstring lock_name;
681 BOOL got_mutex;
683 if (!cli)
684 return NT_STATUS_INVALID_PARAMETER;
686 /* Open an initial conection - keep the mutex. */
688 find_cm_connection(domain, PIPE_NETLOGON, &conn);
690 if ( fresh && (conn != NULL) ) {
691 cli_shutdown(conn->cli);
692 conn->cli = NULL;
694 conn = NULL;
696 /* purge connection from cache */
697 find_cm_connection(domain, PIPE_NETLOGON, &conn);
698 if (conn != NULL) {
699 DEBUG(0,("Could not purge connection\n"));
700 return NT_STATUS_UNSUCCESSFUL;
704 if (conn != NULL) {
705 *cli = conn->cli;
706 return NT_STATUS_OK;
709 result = new_cm_connection(domain, PIPE_NETLOGON, &conn);
711 if (!NT_STATUS_IS_OK(result))
712 return result;
714 fstr_sprintf(lock_name, "NETLOGON\\%s", conn->controller);
716 if (!(got_mutex = secrets_named_mutex(lock_name, WINBIND_SERVER_MUTEX_WAIT_TIME))) {
717 DEBUG(0,("cm_get_netlogon_cli: mutex grab failed for %s\n", conn->controller));
720 if ( sec_channel_type == SEC_CHAN_DOMAIN )
721 fstr_sprintf(conn->cli->mach_acct, "%s$", lp_workgroup());
723 /* This must be the remote domain (not ours) for schannel */
725 fstrcpy( conn->cli->domain, domain->name);
727 result = cli_nt_establish_netlogon(conn->cli, sec_channel_type, trust_passwd);
729 if (got_mutex)
730 secrets_named_mutex_release(lock_name);
732 if (!NT_STATUS_IS_OK(result)) {
733 cli_shutdown(conn->cli);
734 DLIST_REMOVE(cm_conns, conn);
735 SAFE_FREE(conn);
736 return result;
739 *cli = conn->cli;
741 return result;
744 /* Dump the current connection status */
746 static void dump_conn_list(void)
748 struct winbindd_cm_conn *con;
750 DEBUG(0, ("\tDomain Controller Pipe\n"));
752 for(con = cm_conns; con; con = con->next) {
753 char *msg;
755 /* Display pipe info */
757 if (asprintf(&msg, "\t%-15s %-15s %-16s", con->domain, con->controller, con->pipe_name) < 0) {
758 DEBUG(0, ("Error: not enough memory!\n"));
759 } else {
760 DEBUG(0, ("%s\n", msg));
761 SAFE_FREE(msg);
766 void winbindd_cm_status(void)
768 /* List open connections */
770 DEBUG(0, ("winbindd connection manager status:\n"));
772 if (cm_conns)
773 dump_conn_list();
774 else
775 DEBUG(0, ("\tNo active connections\n"));
778 /* Close all cached connections */
780 void winbindd_cm_flush(void)
782 struct winbindd_cm_conn *conn, tmp;
784 /* Flush connection cache */
786 for (conn = cm_conns; conn; conn = conn->next) {
788 if (!connection_ok(conn))
789 continue;
791 DEBUG(10, ("Closing connection to %s on %s\n",
792 conn->pipe_name, conn->controller));
794 if (conn->cli)
795 cli_shutdown(conn->cli);
797 tmp.next = conn->next;
799 DLIST_REMOVE(cm_conns, conn);
800 SAFE_FREE(conn);
801 conn = &tmp;
804 /* Flush failed connection cache */
806 flush_negative_conn_cache();