2 Unix SMB/CIFS implementation.
4 Winbind daemon connection manager
6 Copyright (C) Tim Potter 2001
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 We need to manage connections to domain controllers without having to
25 mess up the main winbindd code with other issues. The aim of the
26 connection manager is to:
28 - make connections to domain controllers and cache them
29 - re-establish connections when networks or servers go down
30 - centralise the policy on connection timeouts, domain controller
32 - manage re-entrancy for when winbindd becomes able to handle
33 multiple outstanding rpc requests
35 Why not have connection management as part of the rpc layer like tng?
36 Good question. This code may morph into libsmb/rpc_cache.c or something
37 like that but at the moment it's simply staying as part of winbind. I
38 think the TNG architecture of forcing every user of the rpc layer to use
39 the connection caching system is a bad idea. It should be an optional
40 method of using the routines.
42 The TNG design is quite good but I disagree with some aspects of the
50 - I'm pretty annoyed by all the make_nmb_name() stuff. It should be
51 moved down into another function.
53 - There needs to be a utility function in libsmb/namequery.c that does
56 - Take care when destroying cli_structs as they can be shared between
63 /* Global list of connections. Initially a DLIST but can become a hash
64 table or whatever later. */
66 struct winbindd_cm_conn
{
67 struct winbindd_cm_conn
*prev
, *next
;
71 struct cli_state
*cli
;
75 static struct winbindd_cm_conn
*cm_conns
= NULL
;
77 /* Get a domain controller name. Cache positive and negative lookups so we
78 don't go to the network too often when something is badly broken. */
80 #define GET_DC_NAME_CACHE_TIMEOUT 30 /* Seconds between dc lookups */
82 struct get_dc_name_cache
{
86 struct get_dc_name_cache
*prev
, *next
;
89 static BOOL
cm_get_dc_name(const char *domain
, fstring srv_name
, struct in_addr
*ip_out
)
91 static struct get_dc_name_cache
*get_dc_name_cache
;
92 struct get_dc_name_cache
*dcc
;
93 struct in_addr
*ip_list
, dc_ip
;
96 /* Check the cache for previous lookups */
98 for (dcc
= get_dc_name_cache
; dcc
; dcc
= dcc
->next
) {
100 if (!strequal(domain
, dcc
->domain_name
))
101 continue; /* Not our domain */
103 if ((time(NULL
) - dcc
->lookup_time
) >
104 GET_DC_NAME_CACHE_TIMEOUT
) {
106 /* Cache entry has expired, delete it */
108 DEBUG(10, ("get_dc_name_cache entry expired for %s\n", domain
));
110 DLIST_REMOVE(get_dc_name_cache
, dcc
);
116 /* Return a positive or negative lookup for this domain */
118 if (dcc
->srv_name
[0]) {
119 DEBUG(10, ("returning positive get_dc_name_cache entry for %s\n", domain
));
120 fstrcpy(srv_name
, dcc
->srv_name
);
123 DEBUG(10, ("returning negative get_dc_name_cache entry for %s\n", domain
));
128 /* Add cache entry for this lookup. */
130 DEBUG(10, ("Creating get_dc_name_cache entry for %s\n", domain
));
132 if (!(dcc
= (struct get_dc_name_cache
*)
133 malloc(sizeof(struct get_dc_name_cache
))))
138 fstrcpy(dcc
->domain_name
, domain
);
139 dcc
->lookup_time
= time(NULL
);
141 DLIST_ADD(get_dc_name_cache
, dcc
);
143 /* Lookup domain controller name. Try the real PDC first to avoid
145 if (!get_dc_list(True
, domain
, &ip_list
, &count
)) {
146 if (!get_dc_list(False
, domain
, &ip_list
, &count
)) {
147 DEBUG(3, ("Could not look up dc's for domain %s\n", domain
));
152 /* Pick a nice close server */
153 /* Look for DC on local net */
155 for (i
= 0; i
< count
; i
++) {
156 if (!is_local_net(ip_list
[i
]))
159 if (name_status_find(domain
, 0x1c, 0x20, ip_list
[i
], srv_name
)) {
163 zero_ip(&ip_list
[i
]);
167 * Secondly try and contact a random PDC/BDC.
170 i
= (sys_random() % count
);
172 if (!is_zero_ip(ip_list
[i
]) &&
173 name_status_find(domain
, 0x1c, 0x20,
174 ip_list
[i
], srv_name
)) {
178 zero_ip(&ip_list
[i
]); /* Tried and failed. */
180 /* Finally return first DC that we can contact */
182 for (i
= 0; i
< count
; i
++) {
183 if (is_zero_ip(ip_list
[i
]))
186 if (name_status_find(domain
, 0x1c, 0x20, ip_list
[i
], srv_name
)) {
192 /* No-one to talk to )-: */
193 return False
; /* Boo-hoo */
196 /* We have the netbios name and IP address of a domain controller.
197 Ideally we should sent a SAMLOGON request to determine whether
198 the DC is alive and kicking. If we can catch a dead DC before
199 performing a cli_connect() we can avoid a 30-second timeout. */
201 /* We have a name so make the cache entry positive now */
203 fstrcpy(dcc
->srv_name
, srv_name
);
205 DEBUG(3, ("cm_get_dc_name: Returning DC %s (%s) for domain %s\n", srv_name
,
206 inet_ntoa(dc_ip
), domain
));
215 /* Choose between anonymous or authenticated connections. We need to use
216 an authenticated connection if DCs have the RestrictAnonymous registry
217 entry set > 0, or the "Additional restrictions for anonymous
218 connections" set in the win2k Local Security Policy.
220 Caller to free() result in domain, username, password
223 static void cm_get_ipc_userpass(char **username
, char **domain
, char **password
)
225 *username
= secrets_fetch(SECRETS_AUTH_USER
, NULL
);
226 *domain
= secrets_fetch(SECRETS_AUTH_DOMAIN
, NULL
);
227 *password
= secrets_fetch(SECRETS_AUTH_PASSWORD
, NULL
);
229 if (*username
&& **username
) {
230 if (!*domain
|| !**domain
) {
231 *domain
= smb_xstrdup(lp_workgroup());
234 DEBUG(3, ("IPC$ connections done by user %s\\%s\n", *domain
, *username
));
236 DEBUG(3, ("IPC$ connections done anonymously\n"));
237 *username
= smb_xstrdup("");
238 *domain
= smb_xstrdup("");
239 *password
= smb_xstrdup("");
243 /* Open a new smb pipe connection to a DC on a given domain. Cache
244 negative creation attempts so we don't try and connect to broken
245 machines too often. */
247 #define FAILED_CONNECTION_CACHE_TIMEOUT 30 /* Seconds between attempts */
249 struct failed_connection_cache
{
254 struct failed_connection_cache
*prev
, *next
;
257 static struct failed_connection_cache
*failed_connection_cache
;
259 /* Add an entry to the failed conneciton cache */
261 static void add_failed_connection_entry(struct winbindd_cm_conn
*new_conn
, NTSTATUS result
) {
262 struct failed_connection_cache
*fcc
;
264 SMB_ASSERT(!NT_STATUS_IS_OK(result
));
266 /* Create negative lookup cache entry for this domain and controller */
268 if (!(fcc
= (struct failed_connection_cache
*)
269 malloc(sizeof(struct failed_connection_cache
)))) {
270 DEBUG(0, ("malloc failed in add_failed_connection_entry!\n"));
276 fstrcpy(fcc
->domain_name
, new_conn
->domain
);
277 fstrcpy(fcc
->controller
, new_conn
->controller
);
278 fcc
->lookup_time
= time(NULL
);
279 fcc
->nt_status
= result
;
281 DLIST_ADD(failed_connection_cache
, fcc
);
284 /* Open a connction to the remote server, cache failures for 30 seconds */
286 static NTSTATUS
cm_open_connection(const char *domain
,const char *pipe_name
,
287 struct winbindd_cm_conn
*new_conn
)
289 struct failed_connection_cache
*fcc
;
290 extern pstring global_myname
;
292 char *ipc_username
, *ipc_domain
, *ipc_password
;
293 struct in_addr dc_ip
;
297 fstrcpy(new_conn
->domain
, domain
);
298 fstrcpy(new_conn
->pipe_name
, pipe_name
);
300 /* Look for a domain controller for this domain. Negative results
301 are cached so don't bother applying the caching for this
302 function just yet. */
304 if (!cm_get_dc_name(domain
, new_conn
->controller
, &dc_ip
)) {
305 result
= NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
;
306 add_failed_connection_entry(new_conn
, result
);
310 /* Return false if we have tried to look up this domain and netbios
311 name before and failed. */
313 for (fcc
= failed_connection_cache
; fcc
; fcc
= fcc
->next
) {
315 if (!(strequal(domain
, fcc
->domain_name
) &&
316 strequal(new_conn
->controller
, fcc
->controller
)))
317 continue; /* Not our domain */
319 if ((time(NULL
) - fcc
->lookup_time
) >
320 FAILED_CONNECTION_CACHE_TIMEOUT
) {
322 /* Cache entry has expired, delete it */
324 DEBUG(10, ("cm_open_connection cache entry expired for %s, %s\n", domain
, new_conn
->controller
));
326 DLIST_REMOVE(failed_connection_cache
, fcc
);
332 /* The timeout hasn't expired yet so return false */
334 DEBUG(10, ("returning negative open_connection_cache entry for %s, %s\n", domain
, new_conn
->controller
));
336 result
= fcc
->nt_status
;
337 SMB_ASSERT(!NT_STATUS_IS_OK(result
));
341 /* Initialise SMB connection */
343 cm_get_ipc_userpass(&ipc_username
, &ipc_domain
, &ipc_password
);
345 DEBUG(5, ("connecting to %s from %s with username [%s]\\[%s]\n",
346 new_conn
->controller
, global_myname
, ipc_domain
, ipc_username
));
348 result
= cli_full_connection(&(new_conn
->cli
), global_myname
, new_conn
->controller
,
350 "IPC", ipc_username
, ipc_domain
,
351 ipc_password
, strlen(ipc_password
));
353 SAFE_FREE(ipc_username
);
354 SAFE_FREE(ipc_domain
);
355 SAFE_FREE(ipc_password
);
357 if (!NT_STATUS_IS_OK(result
)) {
358 add_failed_connection_entry(new_conn
, result
);
362 if (!cli_nt_session_open (new_conn
->cli
, pipe_name
)) {
363 result
= NT_STATUS_PIPE_NOT_AVAILABLE
;
364 add_failed_connection_entry(new_conn
, result
);
365 cli_shutdown(new_conn
->cli
);
372 /* Return true if a connection is still alive */
374 static BOOL
connection_ok(struct winbindd_cm_conn
*conn
)
377 smb_panic("Invalid paramater passed to conneciton_ok(): conn was NULL!\n");
382 DEBUG(0, ("Connection to %s for domain %s (pipe %s) has NULL conn->cli!\n",
383 conn
->controller
, conn
->domain
, conn
->pipe_name
));
384 smb_panic("connection_ok: conn->cli was null!");
388 if (!conn
->cli
->initialised
) {
389 DEBUG(0, ("Connection to %s for domain %s (pipe %s) was never initialised!\n",
390 conn
->controller
, conn
->domain
, conn
->pipe_name
));
391 smb_panic("connection_ok: conn->cli->initialised is False!");
395 if (conn
->cli
->fd
== -1) {
396 DEBUG(3, ("Connection to %s for domain %s (pipe %s) has died or was never started (fd == -1)\n",
397 conn
->controller
, conn
->domain
, conn
->pipe_name
));
404 /* Get a connection to the remote DC and open the pipe. If there is already a connection, use that */
406 static NTSTATUS
get_connection_from_cache(const char *domain
, const char *pipe_name
, struct winbindd_cm_conn
**conn_out
)
408 struct winbindd_cm_conn
*conn
, conn_temp
;
411 for (conn
= cm_conns
; conn
; conn
= conn
->next
) {
412 if (strequal(conn
->domain
, domain
) &&
413 strequal(conn
->pipe_name
, pipe_name
)) {
414 if (!connection_ok(conn
)) {
416 cli_shutdown(conn
->cli
);
418 conn_temp
.next
= conn
->next
;
419 DLIST_REMOVE(cm_conns
, conn
);
421 conn
= &conn_temp
; /* Just to keep the loop moving */
429 if (!(conn
= (struct winbindd_cm_conn
*) malloc(sizeof(struct winbindd_cm_conn
))))
430 return NT_STATUS_NO_MEMORY
;
434 if (!NT_STATUS_IS_OK(result
= cm_open_connection(domain
, pipe_name
, conn
))) {
435 DEBUG(3, ("Could not open a connection to %s for %s (%s)\n",
436 domain
, pipe_name
, nt_errstr(result
)));
440 DLIST_ADD(cm_conns
, conn
);
447 /* Return a LSA policy handle on a domain */
449 CLI_POLICY_HND
*cm_get_lsa_handle(char *domain
)
451 struct winbindd_cm_conn
*conn
;
452 uint32 des_access
= SEC_RIGHTS_MAXIMUM_ALLOWED
;
454 static CLI_POLICY_HND hnd
;
456 /* Look for existing connections */
458 if (!NT_STATUS_IS_OK(result
= get_connection_from_cache(domain
, PIPE_LSARPC
, &conn
))) {
462 /* This *shitty* code needs scrapping ! JRA */
463 if (policy_handle_is_valid(&conn
->pol
)) {
469 result
= cli_lsa_open_policy(conn
->cli
, conn
->cli
->mem_ctx
, False
,
470 des_access
, &conn
->pol
);
472 if (!NT_STATUS_IS_OK(result
)) {
473 /* Hit the cache code again. This cleans out the old connection and gets a new one */
474 if (conn
->cli
->fd
== -1) { /* Try again, if the remote host disapeared */
475 if (!NT_STATUS_IS_OK(result
= get_connection_from_cache(domain
, PIPE_LSARPC
, &conn
))) {
479 result
= cli_lsa_open_policy(conn
->cli
, conn
->cli
->mem_ctx
, False
,
480 des_access
, &conn
->pol
);
483 if (!NT_STATUS_IS_OK(result
)) {
484 cli_shutdown(conn
->cli
);
485 DLIST_REMOVE(cm_conns
, conn
);
497 /* Return a SAM policy handle on a domain */
499 CLI_POLICY_HND
*cm_get_sam_handle(char *domain
)
501 struct winbindd_cm_conn
*conn
;
502 uint32 des_access
= SEC_RIGHTS_MAXIMUM_ALLOWED
;
504 static CLI_POLICY_HND hnd
;
506 /* Look for existing connections */
508 if (!NT_STATUS_IS_OK(result
= get_connection_from_cache(domain
, PIPE_SAMR
, &conn
))) {
512 /* This *shitty* code needs scrapping ! JRA */
513 if (policy_handle_is_valid(&conn
->pol
)) {
518 result
= cli_samr_connect(conn
->cli
, conn
->cli
->mem_ctx
,
519 des_access
, &conn
->pol
);
521 if (!NT_STATUS_IS_OK(result
)) {
522 /* Hit the cache code again. This cleans out the old connection and gets a new one */
523 if (conn
->cli
->fd
== -1) { /* Try again, if the remote host disapeared */
524 if (!NT_STATUS_IS_OK(result
= get_connection_from_cache(domain
, PIPE_SAMR
, &conn
))) {
528 result
= cli_samr_connect(conn
->cli
, conn
->cli
->mem_ctx
,
529 des_access
, &conn
->pol
);
532 if (!NT_STATUS_IS_OK(result
)) {
533 cli_shutdown(conn
->cli
);
534 DLIST_REMOVE(cm_conns
, conn
);
546 #if 0 /* This code now *well* out of date */
548 /* Return a SAM domain policy handle on a domain */
550 CLI_POLICY_HND
*cm_get_sam_dom_handle(char *domain
, DOM_SID
*domain_sid
)
552 struct winbindd_cm_conn
*conn
, *basic_conn
= NULL
;
553 static CLI_POLICY_HND hnd
;
555 uint32 des_access
= SEC_RIGHTS_MAXIMUM_ALLOWED
;
557 /* Look for existing connections */
559 for (conn
= cm_conns
; conn
; conn
= conn
->next
) {
560 if (strequal(conn
->domain
, domain
) &&
561 strequal(conn
->pipe_name
, PIPE_SAMR
) &&
562 conn
->pipe_data
.samr
.pipe_type
== SAM_PIPE_DOM
) {
564 if (!connection_ok(conn
)) {
565 /* Shutdown cli? Free conn? Allow retry of DC? */
566 DLIST_REMOVE(cm_conns
, conn
);
574 /* Create a basic handle to open a domain handle from */
576 if (!cm_get_sam_handle(domain
))
579 for (conn
= cm_conns
; conn
; conn
= conn
->next
) {
580 if (strequal(conn
->domain
, domain
) &&
581 strequal(conn
->pipe_name
, PIPE_SAMR
) &&
582 conn
->pipe_data
.samr
.pipe_type
== SAM_PIPE_BASIC
)
586 if (!(conn
= (struct winbindd_cm_conn
*)
587 malloc(sizeof(struct winbindd_cm_conn
))))
592 fstrcpy(conn
->domain
, basic_conn
->domain
);
593 fstrcpy(conn
->controller
, basic_conn
->controller
);
594 fstrcpy(conn
->pipe_name
, basic_conn
->pipe_name
);
596 conn
->pipe_data
.samr
.pipe_type
= SAM_PIPE_DOM
;
597 conn
->cli
= basic_conn
->cli
;
599 result
= cli_samr_open_domain(conn
->cli
, conn
->cli
->mem_ctx
,
600 &basic_conn
->pol
, des_access
,
601 domain_sid
, &conn
->pol
);
603 if (!NT_STATUS_IS_OK(result
))
608 DLIST_ADD(cm_conns
, conn
);
617 /* Return a SAM policy handle on a domain user */
619 CLI_POLICY_HND
*cm_get_sam_user_handle(char *domain
, DOM_SID
*domain_sid
,
622 struct winbindd_cm_conn
*conn
, *basic_conn
= NULL
;
623 static CLI_POLICY_HND hnd
;
625 uint32 des_access
= SEC_RIGHTS_MAXIMUM_ALLOWED
;
627 /* Look for existing connections */
629 for (conn
= cm_conns
; conn
; conn
= conn
->next
) {
630 if (strequal(conn
->domain
, domain
) &&
631 strequal(conn
->pipe_name
, PIPE_SAMR
) &&
632 conn
->pipe_data
.samr
.pipe_type
== SAM_PIPE_USER
&&
633 conn
->pipe_data
.samr
.rid
== user_rid
) {
635 if (!connection_ok(conn
)) {
636 /* Shutdown cli? Free conn? Allow retry of DC? */
637 DLIST_REMOVE(cm_conns
, conn
);
645 /* Create a domain handle to open a user handle from */
647 if (!cm_get_sam_dom_handle(domain
, domain_sid
))
650 for (conn
= cm_conns
; conn
; conn
= conn
->next
) {
651 if (strequal(conn
->domain
, domain
) &&
652 strequal(conn
->pipe_name
, PIPE_SAMR
) &&
653 conn
->pipe_data
.samr
.pipe_type
== SAM_PIPE_DOM
)
658 DEBUG(0, ("No domain sam handle was created!\n"));
662 if (!(conn
= (struct winbindd_cm_conn
*)
663 malloc(sizeof(struct winbindd_cm_conn
))))
668 fstrcpy(conn
->domain
, basic_conn
->domain
);
669 fstrcpy(conn
->controller
, basic_conn
->controller
);
670 fstrcpy(conn
->pipe_name
, basic_conn
->pipe_name
);
672 conn
->pipe_data
.samr
.pipe_type
= SAM_PIPE_USER
;
673 conn
->cli
= basic_conn
->cli
;
674 conn
->pipe_data
.samr
.rid
= user_rid
;
676 result
= cli_samr_open_user(conn
->cli
, conn
->cli
->mem_ctx
,
677 &basic_conn
->pol
, des_access
, user_rid
,
680 if (!NT_STATUS_IS_OK(result
))
685 DLIST_ADD(cm_conns
, conn
);
694 /* Return a SAM policy handle on a domain group */
696 CLI_POLICY_HND
*cm_get_sam_group_handle(char *domain
, DOM_SID
*domain_sid
,
699 struct winbindd_cm_conn
*conn
, *basic_conn
= NULL
;
700 static CLI_POLICY_HND hnd
;
702 uint32 des_access
= SEC_RIGHTS_MAXIMUM_ALLOWED
;
704 /* Look for existing connections */
706 for (conn
= cm_conns
; conn
; conn
= conn
->next
) {
707 if (strequal(conn
->domain
, domain
) &&
708 strequal(conn
->pipe_name
, PIPE_SAMR
) &&
709 conn
->pipe_data
.samr
.pipe_type
== SAM_PIPE_GROUP
&&
710 conn
->pipe_data
.samr
.rid
== group_rid
) {
712 if (!connection_ok(conn
)) {
713 /* Shutdown cli? Free conn? Allow retry of DC? */
714 DLIST_REMOVE(cm_conns
, conn
);
722 /* Create a domain handle to open a user handle from */
724 if (!cm_get_sam_dom_handle(domain
, domain_sid
))
727 for (conn
= cm_conns
; conn
; conn
= conn
->next
) {
728 if (strequal(conn
->domain
, domain
) &&
729 strequal(conn
->pipe_name
, PIPE_SAMR
) &&
730 conn
->pipe_data
.samr
.pipe_type
== SAM_PIPE_DOM
)
735 DEBUG(0, ("No domain sam handle was created!\n"));
739 if (!(conn
= (struct winbindd_cm_conn
*)
740 malloc(sizeof(struct winbindd_cm_conn
))))
745 fstrcpy(conn
->domain
, basic_conn
->domain
);
746 fstrcpy(conn
->controller
, basic_conn
->controller
);
747 fstrcpy(conn
->pipe_name
, basic_conn
->pipe_name
);
749 conn
->pipe_data
.samr
.pipe_type
= SAM_PIPE_GROUP
;
750 conn
->cli
= basic_conn
->cli
;
751 conn
->pipe_data
.samr
.rid
= group_rid
;
753 result
= cli_samr_open_group(conn
->cli
, conn
->cli
->mem_ctx
,
754 &basic_conn
->pol
, des_access
, group_rid
,
757 if (!NT_STATUS_IS_OK(result
))
762 DLIST_ADD(cm_conns
, conn
);
773 /* Get a handle on a netlogon pipe. This is a bit of a hack to re-use the
774 netlogon pipe as no handle is returned. */
776 NTSTATUS
cm_get_netlogon_cli(char *domain
, unsigned char *trust_passwd
,
777 struct cli_state
**cli
)
779 NTSTATUS result
= NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
;
780 struct winbindd_cm_conn
*conn
;
783 return NT_STATUS_INVALID_PARAMETER
;
786 /* Open an initial conection */
788 if (!NT_STATUS_IS_OK(result
= get_connection_from_cache(domain
, PIPE_NETLOGON
, &conn
))) {
792 result
= new_cli_nt_setup_creds(conn
->cli
, (lp_server_role() == ROLE_DOMAIN_MEMBER
) ?
793 SEC_CHAN_WKSTA
: SEC_CHAN_BDC
, trust_passwd
);
795 if (!NT_STATUS_IS_OK(result
)) {
796 DEBUG(0, ("error connecting to domain password server: %s\n",
799 /* Hit the cache code again. This cleans out the old connection and gets a new one */
800 if (conn
->cli
->fd
== -1) {
801 if (!NT_STATUS_IS_OK(result
= get_connection_from_cache(domain
, PIPE_NETLOGON
, &conn
))) {
806 result
= new_cli_nt_setup_creds(conn
->cli
, (lp_server_role() == ROLE_DOMAIN_MEMBER
) ?
807 SEC_CHAN_WKSTA
: SEC_CHAN_BDC
, trust_passwd
);
810 if (!NT_STATUS_IS_OK(result
)) {
811 cli_shutdown(conn
->cli
);
812 DLIST_REMOVE(cm_conns
, conn
);
823 /* Dump the current connection status */
825 static void dump_conn_list(void)
827 struct winbindd_cm_conn
*con
;
829 DEBUG(0, ("\tDomain Controller Pipe\n"));
831 for(con
= cm_conns
; con
; con
= con
->next
) {
834 /* Display pipe info */
836 if (asprintf(&msg
, "\t%-15s %-15s %-16s", con
->domain
, con
->controller
, con
->pipe_name
) < 0) {
837 DEBUG(0, ("Error: not enough memory!\n"));
839 DEBUG(0, ("%s\n", msg
));
845 void winbindd_cm_status(void)
847 /* List open connections */
849 DEBUG(0, ("winbindd connection manager status:\n"));
854 DEBUG(0, ("\tNo active connections\n"));