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
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
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
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
;
73 struct cli_state
*cli
;
77 static struct winbindd_cm_conn
*cm_conns
= NULL
;
79 static NTSTATUS
get_connection_from_cache(struct winbindd_domain
*domain
,
80 const char *pipe_name
,
81 struct winbindd_cm_conn
**conn_out
);
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.
88 Caller to free() result in domain, username, password
91 static void cm_get_ipc_userpass(char **username
, char **domain
, char **password
)
93 *username
= secrets_fetch(SECRETS_AUTH_USER
, NULL
);
94 *domain
= secrets_fetch(SECRETS_AUTH_DOMAIN
, NULL
);
95 *password
= secrets_fetch(SECRETS_AUTH_PASSWORD
, NULL
);
97 if (*username
&& **username
) {
99 if (!*domain
|| !**domain
)
100 *domain
= smb_xstrdup(lp_workgroup());
102 if (!*password
|| !**password
)
103 *password
= smb_xstrdup("");
105 DEBUG(3, ("IPC$ connections done by user %s\\%s\n",
106 *domain
, *username
));
109 DEBUG(3, ("IPC$ connections done anonymously\n"));
110 *username
= smb_xstrdup("");
111 *domain
= smb_xstrdup("");
112 *password
= smb_xstrdup("");
117 setup for schannel on any pipes opened on this connection
119 static NTSTATUS
setup_schannel( struct cli_state
*cli
, const char *domain
)
122 uchar trust_password
[16];
123 uint32 sec_channel_type
;
127 /* use the domain trust password if we're on a DC
128 and this is not our domain */
130 if ( IS_DC
&& !strequal(domain
, lp_workgroup()) ) {
133 if ( !secrets_fetch_trusted_domain_password( domain
,
136 return NT_STATUS_UNSUCCESSFUL
;
139 sec_channel_type
= SEC_CHAN_DOMAIN
;
140 E_md4hash(pass
, trust_password
);
144 if (!secrets_fetch_trust_account_password(lp_workgroup(),
145 trust_password
, NULL
, &sec_channel_type
))
147 return NT_STATUS_UNSUCCESSFUL
;
151 ret
= cli_nt_setup_netsec(cli
, sec_channel_type
,
152 AUTH_PIPE_NETSEC
| AUTH_PIPE_SIGN
, trust_password
);
157 static BOOL
get_dc_name_via_netlogon(const struct winbindd_domain
*domain
,
158 fstring dcname
, struct in_addr
*dc_ip
)
160 struct winbindd_domain
*our_domain
;
162 struct winbindd_cm_conn
*conn
;
174 if ((our_domain
= find_our_domain()) == NULL
)
177 result
= get_connection_from_cache(our_domain
, PIPE_NETLOGON
, &conn
);
178 if (!NT_STATUS_IS_OK(result
))
181 if ((mem_ctx
= talloc_init("get_dc_name_via_netlogon")) == NULL
)
184 result
= cli_netlogon_getdcname(conn
->cli
, mem_ctx
, domain
->name
, tmp
);
186 talloc_destroy(mem_ctx
);
188 if (!NT_STATUS_IS_OK(result
))
191 /* cli_netlogon_getdcname gives us a name with \\ */
193 if (*p
== '\\') p
+=1;
194 if (*p
== '\\') p
+=1;
198 if (!resolve_name(dcname
, dc_ip
, 0x20))
204 /* Open a connction to the remote server, cache failures for 30 seconds */
206 static NTSTATUS
cm_open_connection(const struct winbindd_domain
*domain
, const int pipe_index
,
207 struct winbindd_cm_conn
*new_conn
)
210 char *machine_password
;
211 char *machine_krb5_principal
, *ipc_username
, *ipc_domain
, *ipc_password
;
212 struct in_addr dc_ip
;
218 fstrcpy(new_conn
->domain
, domain
->name
);
220 if (!get_dc_name_via_netlogon(domain
, new_conn
->controller
, &dc_ip
)) {
222 /* connection failure cache has been moved inside of
223 get_dc_name so we can deal with half dead DC's --jerry */
225 if (!get_dc_name(domain
->name
, domain
->alt_name
[0] ?
226 domain
->alt_name
: NULL
,
227 new_conn
->controller
, &dc_ip
)) {
228 result
= NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
;
229 add_failed_connection_entry(domain
->name
, "", result
);
234 /* Initialise SMB connection */
235 fstrcpy(new_conn
->pipe_name
, get_pipe_name_from_index(pipe_index
));
237 /* grab stored passwords */
239 machine_password
= secrets_fetch_machine_password(lp_workgroup(), NULL
, NULL
);
241 if (asprintf(&machine_krb5_principal
, "%s$@%s", global_myname(), lp_realm()) == -1) {
242 SAFE_FREE(machine_password
);
243 return NT_STATUS_NO_MEMORY
;
246 cm_get_ipc_userpass(&ipc_username
, &ipc_domain
, &ipc_password
);
248 for (i
= 0; retry
&& (i
< 3); i
++) {
250 if (!(got_mutex
= secrets_named_mutex(new_conn
->controller
, WINBIND_SERVER_MUTEX_WAIT_TIME
))) {
251 DEBUG(0,("cm_open_connection: mutex grab failed for %s\n", new_conn
->controller
));
252 result
= NT_STATUS_POSSIBLE_DEADLOCK
;
256 new_conn
->cli
= NULL
;
257 result
= cli_start_connection(&new_conn
->cli
, global_myname(),
258 new_conn
->controller
,
259 &dc_ip
, 0, Undefined
,
260 CLI_FULL_CONNECTION_USE_KERBEROS
,
263 if (NT_STATUS_IS_OK(result
)) {
265 /* reset the error code */
266 result
= NT_STATUS_UNSUCCESSFUL
;
270 if ((lp_security() == SEC_ADS
)
271 && (new_conn
->cli
->protocol
>= PROTOCOL_NT1
&& new_conn
->cli
->capabilities
& CAP_EXTENDED_SECURITY
)) {
272 ADS_STATUS ads_status
;
273 new_conn
->cli
->use_kerberos
= True
;
274 DEBUG(5, ("connecting to %s from %s with kerberos principal [%s]\n",
275 new_conn
->controller
, global_myname(), machine_krb5_principal
));
277 ads_status
= cli_session_setup_spnego(new_conn
->cli
, machine_krb5_principal
,
280 if (!ADS_ERR_OK(ads_status
)) {
281 DEBUG(4,("failed kerberos session setup with %s\n", ads_errstr(ads_status
)));
282 result
= ads_ntstatus(ads_status
);
284 result
= NT_STATUS_OK
;
287 new_conn
->cli
->use_kerberos
= False
;
289 /* only do this is we have a username/password for thr IPC$ connection */
291 if ( !NT_STATUS_IS_OK(result
)
292 && new_conn
->cli
->sec_mode
& NEGOTIATE_SECURITY_CHALLENGE_RESPONSE
293 && strlen(ipc_username
) )
295 DEBUG(5, ("connecting to %s from %s with username [%s]\\[%s]\n",
296 new_conn
->controller
, global_myname(), ipc_domain
, ipc_username
));
298 result
= NT_STATUS_OK
;
300 if (!cli_session_setup(new_conn
->cli
, ipc_username
,
301 ipc_password
, strlen(ipc_password
)+1,
302 ipc_password
, strlen(ipc_password
)+1,
304 result
= cli_nt_error(new_conn
->cli
);
305 DEBUG(4,("failed authenticated session setup with %s\n", nt_errstr(result
)));
306 if (NT_STATUS_IS_OK(result
))
307 result
= NT_STATUS_UNSUCCESSFUL
;
311 /* anonymous is all that is left if we get to here */
313 if (!NT_STATUS_IS_OK(result
)) {
315 DEBUG(5, ("anonymous connection attempt to %s from %s\n",
316 new_conn
->controller
, global_myname()));
318 result
= NT_STATUS_OK
;
320 if (!cli_session_setup(new_conn
->cli
, "", NULL
, 0, NULL
, 0, ""))
322 result
= cli_nt_error(new_conn
->cli
);
323 DEBUG(4,("failed anonymous session setup with %s\n", nt_errstr(result
)));
324 if (NT_STATUS_IS_OK(result
))
325 result
= NT_STATUS_UNSUCCESSFUL
;
330 if (NT_STATUS_IS_OK(result
) && !cli_send_tconX(new_conn
->cli
, "IPC$", "IPC",
332 result
= cli_nt_error(new_conn
->cli
);
333 DEBUG(1,("failed tcon_X with %s\n", nt_errstr(result
)));
334 cli_shutdown(new_conn
->cli
);
335 if (NT_STATUS_IS_OK(result
)) {
336 result
= NT_STATUS_UNSUCCESSFUL
;
341 if (NT_STATUS_IS_OK(result
)) {
342 struct ntuser_creds creds
;
343 init_creds(&creds
, ipc_username
, ipc_domain
, ipc_password
);
344 cli_init_creds(new_conn
->cli
, &creds
);
348 secrets_named_mutex_release(new_conn
->controller
);
350 if (NT_STATUS_IS_OK(result
))
354 /* try and use schannel if possible, but continue anyway if it
355 failed. This allows existing setups to continue working,
356 while solving the win2003 '100 user' limit for systems that
359 Only do this for our own domain or perhaps a trusted domain
360 if we are on a Samba DC */
362 if (NT_STATUS_IS_OK(result
) && (domain
->primary
|| IS_DC
) ) {
363 NTSTATUS status
= setup_schannel( new_conn
->cli
, domain
->name
);
364 if (!NT_STATUS_IS_OK(status
)) {
365 DEBUG(3,("schannel refused - continuing without schannel (%s)\n",
370 SAFE_FREE(ipc_username
);
371 SAFE_FREE(ipc_domain
);
372 SAFE_FREE(ipc_password
);
373 SAFE_FREE(machine_password
);
374 SAFE_FREE(machine_krb5_principal
);
376 if (!NT_STATUS_IS_OK(result
)) {
377 add_failed_connection_entry(domain
->name
, new_conn
->controller
, result
);
381 /* set the domain if empty; needed for schannel connections */
382 if ( !*new_conn
->cli
->domain
)
383 fstrcpy( new_conn
->cli
->domain
, domain
->name
);
386 if ( !cli_nt_session_open (new_conn
->cli
, pipe_index
) ) {
387 result
= NT_STATUS_PIPE_NOT_AVAILABLE
;
389 * only cache a failure if we are not trying to open the
390 * **win2k** specific lsarpc UUID. This could be an NT PDC
391 * and therefore a failure is normal. This should probably
392 * be abstracted to a check for 2k specific pipes and wondering
393 * if the PDC is an NT4 box. but since there is only one 2k
394 * specific UUID right now, i'm not going to bother. --jerry
396 if ( !is_win2k_pipe(pipe_index
) )
397 add_failed_connection_entry(domain
->name
, new_conn
->controller
, result
);
398 cli_shutdown(new_conn
->cli
);
405 /************************************************************************
406 Wrapper around statuc cm_open_connection to retreive a freshly
407 setup cli_state struct
408 ************************************************************************/
410 NTSTATUS
cm_fresh_connection(struct winbindd_domain
*domain
, const int pipe_index
,
411 struct cli_state
**cli
)
414 struct winbindd_cm_conn conn
;
416 result
= cm_open_connection( domain
, pipe_index
, &conn
);
418 if ( NT_STATUS_IS_OK(result
) )
424 /* Return true if a connection is still alive */
426 static BOOL
connection_ok(struct winbindd_cm_conn
*conn
)
429 smb_panic("Invalid parameter passed to connection_ok(): conn was NULL!\n");
434 DEBUG(3, ("Connection to %s for domain %s (pipe %s) has NULL conn->cli!\n",
435 conn
->controller
, conn
->domain
, conn
->pipe_name
));
439 if (!conn
->cli
->initialised
) {
440 DEBUG(3, ("Connection to %s for domain %s (pipe %s) was never initialised!\n",
441 conn
->controller
, conn
->domain
, conn
->pipe_name
));
445 if (conn
->cli
->fd
== -1) {
446 DEBUG(3, ("Connection to %s for domain %s (pipe %s) has died or was never started (fd == -1)\n",
447 conn
->controller
, conn
->domain
, conn
->pipe_name
));
454 /* Search the cache for a connection. If there is a broken one,
455 shut it down properly and return NULL. */
457 static void find_cm_connection(struct winbindd_domain
*domain
, const char *pipe_name
,
458 struct winbindd_cm_conn
**conn_out
)
460 struct winbindd_cm_conn
*conn
;
462 for (conn
= cm_conns
; conn
; ) {
463 if (strequal(conn
->domain
, domain
->name
) &&
464 strequal(conn
->pipe_name
, pipe_name
)) {
465 if (!connection_ok(conn
)) {
466 /* Dead connection - remove it. */
467 struct winbindd_cm_conn
*conn_temp
= conn
->next
;
469 cli_shutdown(conn
->cli
);
470 DLIST_REMOVE(cm_conns
, conn
);
472 conn
= conn_temp
; /* Keep the loop moving */
484 /* Initialize a new connection up to the RPC BIND. */
486 static NTSTATUS
new_cm_connection(struct winbindd_domain
*domain
, const char *pipe_name
,
487 struct winbindd_cm_conn
**conn_out
)
489 struct winbindd_cm_conn
*conn
;
492 if (!(conn
= malloc(sizeof(*conn
))))
493 return NT_STATUS_NO_MEMORY
;
497 if (!NT_STATUS_IS_OK(result
= cm_open_connection(domain
, get_pipe_index(pipe_name
), conn
))) {
498 DEBUG(3, ("Could not open a connection to %s for %s (%s)\n",
499 domain
->name
, pipe_name
, nt_errstr(result
)));
503 DLIST_ADD(cm_conns
, conn
);
509 /* Get a connection to the remote DC and open the pipe. If there is already a connection, use that */
511 static NTSTATUS
get_connection_from_cache(struct winbindd_domain
*domain
, const char *pipe_name
,
512 struct winbindd_cm_conn
**conn_out
)
514 find_cm_connection(domain
, pipe_name
, conn_out
);
516 if (*conn_out
!= NULL
)
519 return new_cm_connection(domain
, pipe_name
, conn_out
);
522 /**********************************************************************************
523 We can 'sense' certain things about the DC by it's replies to certain questions.
525 This tells us if this particular remote server is Active Directory, and if it is
527 **********************************************************************************/
529 void set_dc_type_and_flags( struct winbindd_domain
*domain
)
532 struct winbindd_cm_conn conn
;
534 TALLOC_CTX
*mem_ctx
= NULL
;
539 domain
->native_mode
= False
;
540 domain
->active_directory
= False
;
542 if (domain
->internal
) {
543 domain
->initialized
= True
;
547 if ( !NT_STATUS_IS_OK(result
= cm_open_connection(domain
, PI_LSARPC_DS
, &conn
)) ) {
548 DEBUG(5, ("set_dc_type_and_flags: Could not open a connection to %s for PIPE_LSARPC (%s)\n",
549 domain
->name
, nt_errstr(result
)));
550 domain
->initialized
= True
;
555 if ( !NT_STATUS_IS_OK(cli_ds_getprimarydominfo( conn
.cli
,
556 conn
.cli
->mem_ctx
, DsRolePrimaryDomainInfoBasic
, &ctr
)) ) {
561 if ( (ctr
.basic
->flags
& DSROLE_PRIMARY_DS_RUNNING
)
562 && !(ctr
.basic
->flags
& DSROLE_PRIMARY_DS_MIXED_MODE
) )
563 domain
->native_mode
= True
;
565 /* Cheat - shut down the DS pipe, and open LSA */
567 cli_nt_session_close(conn
.cli
);
569 if ( cli_nt_session_open (conn
.cli
, PI_LSARPC
) ) {
570 char *domain_name
= NULL
;
571 char *dns_name
= NULL
;
572 DOM_SID
*dom_sid
= NULL
;
574 mem_ctx
= talloc_init("set_dc_type_and_flags on domain %s\n", domain
->name
);
576 DEBUG(1, ("set_dc_type_and_flags: talloc_init() failed\n"));
580 result
= cli_lsa_open_policy2(conn
.cli
, mem_ctx
, True
,
581 SEC_RIGHTS_MAXIMUM_ALLOWED
,
584 if (NT_STATUS_IS_OK(result
)) {
585 /* This particular query is exactly what Win2k clients use
586 to determine that the DC is active directory */
587 result
= cli_lsa_query_info_policy2(conn
.cli
, mem_ctx
,
594 if (NT_STATUS_IS_OK(result
)) {
596 fstrcpy(domain
->name
, domain_name
);
599 fstrcpy(domain
->alt_name
, dns_name
);
602 sid_copy(&domain
->sid
, dom_sid
);
604 domain
->active_directory
= True
;
607 result
= cli_lsa_open_policy(conn
.cli
, mem_ctx
, True
,
608 SEC_RIGHTS_MAXIMUM_ALLOWED
,
611 if (!NT_STATUS_IS_OK(result
))
614 result
= cli_lsa_query_info_policy(conn
.cli
, mem_ctx
,
615 &conn
.pol
, 5, &domain_name
,
618 if (NT_STATUS_IS_OK(result
)) {
620 fstrcpy(domain
->name
, domain_name
);
623 sid_copy(&domain
->sid
, dom_sid
);
630 /* close the connection; no other calls use this pipe and it is called only
631 on reestablishing the domain list --jerry */
634 cli_shutdown( conn
.cli
);
636 talloc_destroy(mem_ctx
);
638 domain
->initialized
= True
;
645 /* Return a LSA policy handle on a domain */
647 NTSTATUS
cm_get_lsa_handle(struct winbindd_domain
*domain
, CLI_POLICY_HND
**return_hnd
)
649 struct winbindd_cm_conn
*conn
;
650 uint32 des_access
= SEC_RIGHTS_MAXIMUM_ALLOWED
;
652 static CLI_POLICY_HND hnd
;
654 /* Look for existing connections */
656 if (!NT_STATUS_IS_OK(result
= get_connection_from_cache(domain
, PIPE_LSARPC
, &conn
)))
659 /* This *shitty* code needs scrapping ! JRA */
661 if (policy_handle_is_valid(&conn
->pol
)) {
669 result
= cli_lsa_open_policy(conn
->cli
, conn
->cli
->mem_ctx
, False
,
670 des_access
, &conn
->pol
);
672 if (!NT_STATUS_IS_OK(result
)) {
673 /* Hit the cache code again. This cleans out the old connection and gets a new one */
674 if (conn
->cli
->fd
== -1) { /* Try again, if the remote host disapeared */
675 if (!NT_STATUS_IS_OK(result
= get_connection_from_cache(domain
, PIPE_LSARPC
, &conn
)))
678 result
= cli_lsa_open_policy(conn
->cli
, conn
->cli
->mem_ctx
, False
,
679 des_access
, &conn
->pol
);
682 if (!NT_STATUS_IS_OK(result
)) {
683 cli_shutdown(conn
->cli
);
684 DLIST_REMOVE(cm_conns
, conn
);
698 /* Return a SAM policy handle on a domain */
700 NTSTATUS
cm_get_sam_handle(struct winbindd_domain
*domain
, CLI_POLICY_HND
**return_hnd
)
702 struct winbindd_cm_conn
*conn
;
703 uint32 des_access
= SEC_RIGHTS_MAXIMUM_ALLOWED
;
705 static CLI_POLICY_HND hnd
;
707 /* Look for existing connections */
709 if (!NT_STATUS_IS_OK(result
= get_connection_from_cache(domain
, PIPE_SAMR
, &conn
)))
712 /* This *shitty* code needs scrapping ! JRA */
714 if (policy_handle_is_valid(&conn
->pol
)) {
723 result
= cli_samr_connect(conn
->cli
, conn
->cli
->mem_ctx
,
724 des_access
, &conn
->pol
);
726 if (!NT_STATUS_IS_OK(result
)) {
727 /* Hit the cache code again. This cleans out the old connection and gets a new one */
728 if (conn
->cli
->fd
== -1) { /* Try again, if the remote host disapeared */
730 if (!NT_STATUS_IS_OK(result
= get_connection_from_cache(domain
, PIPE_SAMR
, &conn
)))
733 result
= cli_samr_connect(conn
->cli
, conn
->cli
->mem_ctx
,
734 des_access
, &conn
->pol
);
737 if (!NT_STATUS_IS_OK(result
)) {
739 cli_shutdown(conn
->cli
);
740 DLIST_REMOVE(cm_conns
, conn
);
755 /* Get a handle on a netlogon pipe. This is a bit of a hack to re-use the
756 netlogon pipe as no handle is returned. */
758 NTSTATUS
cm_get_netlogon_cli(struct winbindd_domain
*domain
,
759 const unsigned char *trust_passwd
,
760 uint32 sec_channel_type
,
762 struct cli_state
**cli
)
764 NTSTATUS result
= NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
;
765 struct winbindd_cm_conn
*conn
;
770 return NT_STATUS_INVALID_PARAMETER
;
772 /* Open an initial conection - keep the mutex. */
774 find_cm_connection(domain
, PIPE_NETLOGON
, &conn
);
776 if ( fresh
&& (conn
!= NULL
) ) {
777 cli_shutdown(conn
->cli
);
782 /* purge connection from cache */
783 find_cm_connection(domain
, PIPE_NETLOGON
, &conn
);
785 DEBUG(0,("Could not purge connection\n"));
786 return NT_STATUS_UNSUCCESSFUL
;
795 result
= new_cm_connection(domain
, PIPE_NETLOGON
, &conn
);
797 if (!NT_STATUS_IS_OK(result
))
800 fstr_sprintf(lock_name
, "NETLOGON\\%s", conn
->controller
);
802 if (!(got_mutex
= secrets_named_mutex(lock_name
, WINBIND_SERVER_MUTEX_WAIT_TIME
))) {
803 DEBUG(0,("cm_get_netlogon_cli: mutex grab failed for %s\n", conn
->controller
));
806 if ( sec_channel_type
== SEC_CHAN_DOMAIN
)
807 fstr_sprintf(conn
->cli
->mach_acct
, "%s$", lp_workgroup());
809 /* This must be the remote domain (not ours) for schannel */
811 fstrcpy( conn
->cli
->domain
, domain
->name
);
813 result
= cli_nt_establish_netlogon(conn
->cli
, sec_channel_type
, trust_passwd
);
816 secrets_named_mutex_release(lock_name
);
818 if (!NT_STATUS_IS_OK(result
)) {
819 cli_shutdown(conn
->cli
);
820 DLIST_REMOVE(cm_conns
, conn
);
830 /* Dump the current connection status */
832 static void dump_conn_list(void)
834 struct winbindd_cm_conn
*con
;
836 DEBUG(0, ("\tDomain Controller Pipe\n"));
838 for(con
= cm_conns
; con
; con
= con
->next
) {
841 /* Display pipe info */
843 if (asprintf(&msg
, "\t%-15s %-15s %-16s", con
->domain
, con
->controller
, con
->pipe_name
) < 0) {
844 DEBUG(0, ("Error: not enough memory!\n"));
846 DEBUG(0, ("%s\n", msg
));
852 void winbindd_cm_status(void)
854 /* List open connections */
856 DEBUG(0, ("winbindd connection manager status:\n"));
861 DEBUG(0, ("\tNo active connections\n"));
864 /* Close all cached connections */
866 void winbindd_cm_flush(void)
868 struct winbindd_cm_conn
*conn
, tmp
;
870 /* Flush connection cache */
872 for (conn
= cm_conns
; conn
; conn
= conn
->next
) {
874 if (!connection_ok(conn
))
877 DEBUG(10, ("Closing connection to %s on %s\n",
878 conn
->pipe_name
, conn
->controller
));
881 cli_shutdown(conn
->cli
);
883 tmp
.next
= conn
->next
;
885 DLIST_REMOVE(cm_conns
, conn
);
890 /* Flush failed connection cache */
892 flush_negative_conn_cache();