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 - There needs to be a utility function in libsmb/namequery.c that does
57 - Take care when destroying cli_structs as they can be shared between
65 #define DBGC_CLASS DBGC_WINBIND
67 /* Global list of connections. Initially a DLIST but can become a hash
68 table or whatever later. */
70 struct winbindd_cm_conn
{
71 struct winbindd_cm_conn
*prev
, *next
;
75 struct cli_state
*cli
;
79 static struct winbindd_cm_conn
*cm_conns
= NULL
;
81 /* Get a domain controller name. Cache positive and negative lookups so we
82 don't go to the network too often when something is badly broken. */
84 #define GET_DC_NAME_CACHE_TIMEOUT 30 /* Seconds between dc lookups */
86 struct get_dc_name_cache
{
90 struct get_dc_name_cache
*prev
, *next
;
95 find the DC for a domain using methods appropriate for a ADS domain
97 static BOOL
cm_ads_find_dc(const char *domain
, struct in_addr
*dc_ip
, fstring srv_name
)
100 const char *realm
= domain
;
102 if (strcasecmp(realm
, lp_workgroup()) == 0) {
106 ads
= ads_init(realm
, domain
, NULL
);
111 /* we don't need to bind, just connect */
112 ads
->auth
.no_bind
= 1;
114 DEBUG(4,("cm_ads_find_dc: domain=%s\n", domain
));
117 /* a full ads_connect() is actually overkill, as we don't srictly need
118 to do the SASL auth in order to get the info we need, but libads
119 doesn't offer a better way right now */
123 if (!ads
->config
.realm
) {
127 fstrcpy(srv_name
, ads
->config
.ldap_server_name
);
129 *dc_ip
= ads
->ldap_ip
;
132 DEBUG(4,("cm_ads_find_dc: using server='%s' IP=%s\n",
133 srv_name
, inet_ntoa(*dc_ip
)));
139 find the DC for a domain using methods appropriate for a RPC domain
141 static BOOL
cm_rpc_find_dc(const char *domain
, struct in_addr
*dc_ip
, fstring srv_name
)
143 struct in_addr
*ip_list
= NULL
;
146 /* Lookup domain controller name. Try the real PDC first to avoid
148 if (get_dc_list(True
, domain
, &ip_list
, &count
) &&
149 name_status_find(domain
, 0x1c, 0x20, ip_list
[0], srv_name
)) {
155 if (!get_dc_list(True
, domain
, &ip_list
, &count
)) {
156 if (!get_dc_list(False
, domain
, &ip_list
, &count
)) {
157 DEBUG(3, ("Could not look up dc's for domain %s\n", domain
));
162 /* Pick a nice close server */
163 /* Look for DC on local net */
164 for (i
= 0; i
< count
; i
++) {
165 if (!is_local_net(ip_list
[i
]))
168 if (name_status_find(domain
, 0x1c, 0x20, ip_list
[i
], srv_name
)) {
173 zero_ip(&ip_list
[i
]);
177 * Secondly try and contact a random PDC/BDC.
180 i
= (sys_random() % count
);
182 if (!is_zero_ip(ip_list
[i
]) &&
183 name_status_find(domain
, 0x1c, 0x20,
184 ip_list
[i
], srv_name
)) {
189 zero_ip(&ip_list
[i
]); /* Tried and failed. */
191 /* Finally return first DC that we can contact using a node
193 for (i
= 0; i
< count
; i
++) {
194 if (is_zero_ip(ip_list
[i
]))
197 if (name_status_find(domain
, 0x1c, 0x20, ip_list
[i
], srv_name
)) {
210 static BOOL
cm_get_dc_name(const char *domain
, fstring srv_name
, struct in_addr
*ip_out
)
212 static struct get_dc_name_cache
*get_dc_name_cache
;
213 struct get_dc_name_cache
*dcc
;
214 struct in_addr dc_ip
;
217 /* Check the cache for previous lookups */
219 for (dcc
= get_dc_name_cache
; dcc
; dcc
= dcc
->next
) {
221 if (!strequal(domain
, dcc
->domain_name
))
222 continue; /* Not our domain */
224 if ((time(NULL
) - dcc
->lookup_time
) >
225 GET_DC_NAME_CACHE_TIMEOUT
) {
227 /* Cache entry has expired, delete it */
229 DEBUG(10, ("get_dc_name_cache entry expired for %s\n", domain
));
231 DLIST_REMOVE(get_dc_name_cache
, dcc
);
237 /* Return a positive or negative lookup for this domain */
239 if (dcc
->srv_name
[0]) {
240 DEBUG(10, ("returning positive get_dc_name_cache entry for %s\n", domain
));
241 fstrcpy(srv_name
, dcc
->srv_name
);
244 DEBUG(10, ("returning negative get_dc_name_cache entry for %s\n", domain
));
249 /* Add cache entry for this lookup. */
251 DEBUG(10, ("Creating get_dc_name_cache entry for %s\n", domain
));
253 if (!(dcc
= (struct get_dc_name_cache
*)
254 malloc(sizeof(struct get_dc_name_cache
))))
259 fstrcpy(dcc
->domain_name
, domain
);
260 dcc
->lookup_time
= time(NULL
);
262 DLIST_ADD(get_dc_name_cache
, dcc
);
267 if (lp_security() == SEC_ADS
) {
268 ret
= cm_ads_find_dc(domain
, &dc_ip
, srv_name
);
271 /* fall back on rpc methods if the ADS methods fail */
272 ret
= cm_rpc_find_dc(domain
, &dc_ip
, srv_name
);
279 /* We have a name so make the cache entry positive now */
280 fstrcpy(dcc
->srv_name
, srv_name
);
282 DEBUG(3, ("cm_get_dc_name: Returning DC %s (%s) for domain %s\n", srv_name
,
283 inet_ntoa(dc_ip
), domain
));
290 /* Choose between anonymous or authenticated connections. We need to use
291 an authenticated connection if DCs have the RestrictAnonymous registry
292 entry set > 0, or the "Additional restrictions for anonymous
293 connections" set in the win2k Local Security Policy.
295 Caller to free() result in domain, username, password
298 static void cm_get_ipc_userpass(char **username
, char **domain
, char **password
)
300 *username
= secrets_fetch(SECRETS_AUTH_USER
, NULL
);
301 *domain
= secrets_fetch(SECRETS_AUTH_DOMAIN
, NULL
);
302 *password
= secrets_fetch(SECRETS_AUTH_PASSWORD
, NULL
);
304 if (*username
&& **username
) {
305 if (!*domain
|| !**domain
) {
306 *domain
= smb_xstrdup(lp_workgroup());
309 DEBUG(3, ("IPC$ connections done by user %s\\%s\n", *domain
, *username
));
311 DEBUG(3, ("IPC$ connections done anonymously\n"));
312 *username
= smb_xstrdup("");
313 *domain
= smb_xstrdup("");
314 *password
= smb_xstrdup("");
318 /* Open a new smb pipe connection to a DC on a given domain. Cache
319 negative creation attempts so we don't try and connect to broken
320 machines too often. */
322 #define FAILED_CONNECTION_CACHE_TIMEOUT 30 /* Seconds between attempts */
324 struct failed_connection_cache
{
329 struct failed_connection_cache
*prev
, *next
;
332 static struct failed_connection_cache
*failed_connection_cache
;
334 /* Add an entry to the failed conneciton cache */
336 static void add_failed_connection_entry(struct winbindd_cm_conn
*new_conn
,
339 struct failed_connection_cache
*fcc
;
341 SMB_ASSERT(!NT_STATUS_IS_OK(result
));
343 /* Check we already aren't in the cache */
345 for (fcc
= failed_connection_cache
; fcc
; fcc
= fcc
->next
) {
346 if (strequal(fcc
->domain_name
, new_conn
->domain
)) {
347 DEBUG(10, ("domain %s already tried and failed\n",
353 /* Create negative lookup cache entry for this domain and controller */
355 if (!(fcc
= (struct failed_connection_cache
*)
356 malloc(sizeof(struct failed_connection_cache
)))) {
357 DEBUG(0, ("malloc failed in add_failed_connection_entry!\n"));
363 fstrcpy(fcc
->domain_name
, new_conn
->domain
);
364 fstrcpy(fcc
->controller
, new_conn
->controller
);
365 fcc
->lookup_time
= time(NULL
);
366 fcc
->nt_status
= result
;
368 DLIST_ADD(failed_connection_cache
, fcc
);
371 /* Open a connction to the remote server, cache failures for 30 seconds */
373 static NTSTATUS
cm_open_connection(const char *domain
,const char *pipe_name
,
374 struct winbindd_cm_conn
*new_conn
)
376 struct failed_connection_cache
*fcc
;
377 extern pstring global_myname
;
379 char *ipc_username
, *ipc_domain
, *ipc_password
;
380 struct in_addr dc_ip
;
384 fstrcpy(new_conn
->domain
, domain
);
385 fstrcpy(new_conn
->pipe_name
, pipe_name
);
387 /* Look for a domain controller for this domain. Negative results
388 are cached so don't bother applying the caching for this
389 function just yet. */
391 if (!cm_get_dc_name(domain
, new_conn
->controller
, &dc_ip
)) {
392 result
= NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
;
393 add_failed_connection_entry(new_conn
, result
);
397 /* Return false if we have tried to look up this domain and netbios
398 name before and failed. */
400 for (fcc
= failed_connection_cache
; fcc
; fcc
= fcc
->next
) {
402 if (!(strequal(domain
, fcc
->domain_name
) &&
403 strequal(new_conn
->controller
, fcc
->controller
)))
404 continue; /* Not our domain */
406 if ((time(NULL
) - fcc
->lookup_time
) >
407 FAILED_CONNECTION_CACHE_TIMEOUT
) {
409 /* Cache entry has expired, delete it */
411 DEBUG(10, ("cm_open_connection cache entry expired for %s, %s\n", domain
, new_conn
->controller
));
413 DLIST_REMOVE(failed_connection_cache
, fcc
);
419 /* The timeout hasn't expired yet so return false */
421 DEBUG(10, ("returning negative open_connection_cache entry for %s, %s\n", domain
, new_conn
->controller
));
423 result
= fcc
->nt_status
;
424 SMB_ASSERT(!NT_STATUS_IS_OK(result
));
428 /* Initialise SMB connection */
430 cm_get_ipc_userpass(&ipc_username
, &ipc_domain
, &ipc_password
);
432 DEBUG(5, ("connecting to %s from %s with username [%s]\\[%s]\n",
433 new_conn
->controller
, global_myname
, ipc_domain
, ipc_username
));
435 result
= cli_full_connection(&(new_conn
->cli
), global_myname
, new_conn
->controller
,
437 "IPC", ipc_username
, ipc_domain
,
440 SAFE_FREE(ipc_username
);
441 SAFE_FREE(ipc_domain
);
442 SAFE_FREE(ipc_password
);
444 if (!NT_STATUS_IS_OK(result
)) {
445 add_failed_connection_entry(new_conn
, result
);
449 if (!cli_nt_session_open (new_conn
->cli
, pipe_name
)) {
450 result
= NT_STATUS_PIPE_NOT_AVAILABLE
;
451 add_failed_connection_entry(new_conn
, result
);
452 cli_shutdown(new_conn
->cli
);
459 /* Return true if a connection is still alive */
461 static BOOL
connection_ok(struct winbindd_cm_conn
*conn
)
464 smb_panic("Invalid paramater passed to conneciton_ok(): conn was NULL!\n");
469 DEBUG(0, ("Connection to %s for domain %s (pipe %s) has NULL conn->cli!\n",
470 conn
->controller
, conn
->domain
, conn
->pipe_name
));
471 smb_panic("connection_ok: conn->cli was null!");
475 if (!conn
->cli
->initialised
) {
476 DEBUG(0, ("Connection to %s for domain %s (pipe %s) was never initialised!\n",
477 conn
->controller
, conn
->domain
, conn
->pipe_name
));
478 smb_panic("connection_ok: conn->cli->initialised is False!");
482 if (conn
->cli
->fd
== -1) {
483 DEBUG(3, ("Connection to %s for domain %s (pipe %s) has died or was never started (fd == -1)\n",
484 conn
->controller
, conn
->domain
, conn
->pipe_name
));
491 /* Get a connection to the remote DC and open the pipe. If there is already a connection, use that */
493 static NTSTATUS
get_connection_from_cache(const char *domain
, const char *pipe_name
, struct winbindd_cm_conn
**conn_out
)
495 struct winbindd_cm_conn
*conn
, conn_temp
;
498 for (conn
= cm_conns
; conn
; conn
= conn
->next
) {
499 if (strequal(conn
->domain
, domain
) &&
500 strequal(conn
->pipe_name
, pipe_name
)) {
501 if (!connection_ok(conn
)) {
503 cli_shutdown(conn
->cli
);
505 ZERO_STRUCT(conn_temp
);
506 conn_temp
.next
= conn
->next
;
507 DLIST_REMOVE(cm_conns
, conn
);
509 conn
= &conn_temp
; /* Just to keep the loop moving */
517 if (!(conn
= malloc(sizeof(*conn
))))
518 return NT_STATUS_NO_MEMORY
;
522 if (!NT_STATUS_IS_OK(result
= cm_open_connection(domain
, pipe_name
, conn
))) {
523 DEBUG(3, ("Could not open a connection to %s for %s (%s)\n",
524 domain
, pipe_name
, nt_errstr(result
)));
528 DLIST_ADD(cm_conns
, conn
);
535 /* Return a LSA policy handle on a domain */
537 CLI_POLICY_HND
*cm_get_lsa_handle(char *domain
)
539 struct winbindd_cm_conn
*conn
;
540 uint32 des_access
= SEC_RIGHTS_MAXIMUM_ALLOWED
;
542 static CLI_POLICY_HND hnd
;
544 /* Look for existing connections */
546 if (!NT_STATUS_IS_OK(result
= get_connection_from_cache(domain
, PIPE_LSARPC
, &conn
))) {
550 /* This *shitty* code needs scrapping ! JRA */
551 if (policy_handle_is_valid(&conn
->pol
)) {
557 result
= cli_lsa_open_policy(conn
->cli
, conn
->cli
->mem_ctx
, False
,
558 des_access
, &conn
->pol
);
560 if (!NT_STATUS_IS_OK(result
)) {
561 /* Hit the cache code again. This cleans out the old connection and gets a new one */
562 if (conn
->cli
->fd
== -1) { /* Try again, if the remote host disapeared */
563 if (!NT_STATUS_IS_OK(result
= get_connection_from_cache(domain
, PIPE_LSARPC
, &conn
))) {
567 result
= cli_lsa_open_policy(conn
->cli
, conn
->cli
->mem_ctx
, False
,
568 des_access
, &conn
->pol
);
571 if (!NT_STATUS_IS_OK(result
)) {
572 cli_shutdown(conn
->cli
);
573 DLIST_REMOVE(cm_conns
, conn
);
585 /* Return a SAM policy handle on a domain */
587 CLI_POLICY_HND
*cm_get_sam_handle(char *domain
)
589 struct winbindd_cm_conn
*conn
;
590 uint32 des_access
= SEC_RIGHTS_MAXIMUM_ALLOWED
;
592 static CLI_POLICY_HND hnd
;
594 /* Look for existing connections */
596 if (!NT_STATUS_IS_OK(result
= get_connection_from_cache(domain
, PIPE_SAMR
, &conn
))) {
600 /* This *shitty* code needs scrapping ! JRA */
601 if (policy_handle_is_valid(&conn
->pol
)) {
606 result
= cli_samr_connect(conn
->cli
, conn
->cli
->mem_ctx
,
607 des_access
, &conn
->pol
);
609 if (!NT_STATUS_IS_OK(result
)) {
610 /* Hit the cache code again. This cleans out the old connection and gets a new one */
611 if (conn
->cli
->fd
== -1) { /* Try again, if the remote host disapeared */
612 if (!NT_STATUS_IS_OK(result
= get_connection_from_cache(domain
, PIPE_SAMR
, &conn
))) {
616 result
= cli_samr_connect(conn
->cli
, conn
->cli
->mem_ctx
,
617 des_access
, &conn
->pol
);
620 if (!NT_STATUS_IS_OK(result
)) {
621 cli_shutdown(conn
->cli
);
622 DLIST_REMOVE(cm_conns
, conn
);
634 #if 0 /* This code now *well* out of date */
636 /* Return a SAM domain policy handle on a domain */
638 CLI_POLICY_HND
*cm_get_sam_dom_handle(char *domain
, DOM_SID
*domain_sid
)
640 struct winbindd_cm_conn
*conn
, *basic_conn
= NULL
;
641 static CLI_POLICY_HND hnd
;
643 uint32 des_access
= SEC_RIGHTS_MAXIMUM_ALLOWED
;
645 /* Look for existing connections */
647 for (conn
= cm_conns
; conn
; conn
= conn
->next
) {
648 if (strequal(conn
->domain
, domain
) &&
649 strequal(conn
->pipe_name
, PIPE_SAMR
) &&
650 conn
->pipe_data
.samr
.pipe_type
== SAM_PIPE_DOM
) {
652 if (!connection_ok(conn
)) {
653 /* Shutdown cli? Free conn? Allow retry of DC? */
654 DLIST_REMOVE(cm_conns
, conn
);
662 /* Create a basic handle to open a domain handle from */
664 if (!cm_get_sam_handle(domain
))
667 for (conn
= cm_conns
; conn
; conn
= conn
->next
) {
668 if (strequal(conn
->domain
, domain
) &&
669 strequal(conn
->pipe_name
, PIPE_SAMR
) &&
670 conn
->pipe_data
.samr
.pipe_type
== SAM_PIPE_BASIC
)
674 if (!(conn
= (struct winbindd_cm_conn
*)
675 malloc(sizeof(struct winbindd_cm_conn
))))
680 fstrcpy(conn
->domain
, basic_conn
->domain
);
681 fstrcpy(conn
->controller
, basic_conn
->controller
);
682 fstrcpy(conn
->pipe_name
, basic_conn
->pipe_name
);
684 conn
->pipe_data
.samr
.pipe_type
= SAM_PIPE_DOM
;
685 conn
->cli
= basic_conn
->cli
;
687 result
= cli_samr_open_domain(conn
->cli
, conn
->cli
->mem_ctx
,
688 &basic_conn
->pol
, des_access
,
689 domain_sid
, &conn
->pol
);
691 if (!NT_STATUS_IS_OK(result
))
696 DLIST_ADD(cm_conns
, conn
);
705 /* Return a SAM policy handle on a domain user */
707 CLI_POLICY_HND
*cm_get_sam_user_handle(char *domain
, DOM_SID
*domain_sid
,
710 struct winbindd_cm_conn
*conn
, *basic_conn
= NULL
;
711 static CLI_POLICY_HND hnd
;
713 uint32 des_access
= SEC_RIGHTS_MAXIMUM_ALLOWED
;
715 /* Look for existing connections */
717 for (conn
= cm_conns
; conn
; conn
= conn
->next
) {
718 if (strequal(conn
->domain
, domain
) &&
719 strequal(conn
->pipe_name
, PIPE_SAMR
) &&
720 conn
->pipe_data
.samr
.pipe_type
== SAM_PIPE_USER
&&
721 conn
->pipe_data
.samr
.rid
== user_rid
) {
723 if (!connection_ok(conn
)) {
724 /* Shutdown cli? Free conn? Allow retry of DC? */
725 DLIST_REMOVE(cm_conns
, conn
);
733 /* Create a domain handle to open a user handle from */
735 if (!cm_get_sam_dom_handle(domain
, domain_sid
))
738 for (conn
= cm_conns
; conn
; conn
= conn
->next
) {
739 if (strequal(conn
->domain
, domain
) &&
740 strequal(conn
->pipe_name
, PIPE_SAMR
) &&
741 conn
->pipe_data
.samr
.pipe_type
== SAM_PIPE_DOM
)
746 DEBUG(0, ("No domain sam handle was created!\n"));
750 if (!(conn
= (struct winbindd_cm_conn
*)
751 malloc(sizeof(struct winbindd_cm_conn
))))
756 fstrcpy(conn
->domain
, basic_conn
->domain
);
757 fstrcpy(conn
->controller
, basic_conn
->controller
);
758 fstrcpy(conn
->pipe_name
, basic_conn
->pipe_name
);
760 conn
->pipe_data
.samr
.pipe_type
= SAM_PIPE_USER
;
761 conn
->cli
= basic_conn
->cli
;
762 conn
->pipe_data
.samr
.rid
= user_rid
;
764 result
= cli_samr_open_user(conn
->cli
, conn
->cli
->mem_ctx
,
765 &basic_conn
->pol
, des_access
, user_rid
,
768 if (!NT_STATUS_IS_OK(result
))
773 DLIST_ADD(cm_conns
, conn
);
782 /* Return a SAM policy handle on a domain group */
784 CLI_POLICY_HND
*cm_get_sam_group_handle(char *domain
, DOM_SID
*domain_sid
,
787 struct winbindd_cm_conn
*conn
, *basic_conn
= NULL
;
788 static CLI_POLICY_HND hnd
;
790 uint32 des_access
= SEC_RIGHTS_MAXIMUM_ALLOWED
;
792 /* Look for existing connections */
794 for (conn
= cm_conns
; conn
; conn
= conn
->next
) {
795 if (strequal(conn
->domain
, domain
) &&
796 strequal(conn
->pipe_name
, PIPE_SAMR
) &&
797 conn
->pipe_data
.samr
.pipe_type
== SAM_PIPE_GROUP
&&
798 conn
->pipe_data
.samr
.rid
== group_rid
) {
800 if (!connection_ok(conn
)) {
801 /* Shutdown cli? Free conn? Allow retry of DC? */
802 DLIST_REMOVE(cm_conns
, conn
);
810 /* Create a domain handle to open a user handle from */
812 if (!cm_get_sam_dom_handle(domain
, domain_sid
))
815 for (conn
= cm_conns
; conn
; conn
= conn
->next
) {
816 if (strequal(conn
->domain
, domain
) &&
817 strequal(conn
->pipe_name
, PIPE_SAMR
) &&
818 conn
->pipe_data
.samr
.pipe_type
== SAM_PIPE_DOM
)
823 DEBUG(0, ("No domain sam handle was created!\n"));
827 if (!(conn
= (struct winbindd_cm_conn
*)
828 malloc(sizeof(struct winbindd_cm_conn
))))
833 fstrcpy(conn
->domain
, basic_conn
->domain
);
834 fstrcpy(conn
->controller
, basic_conn
->controller
);
835 fstrcpy(conn
->pipe_name
, basic_conn
->pipe_name
);
837 conn
->pipe_data
.samr
.pipe_type
= SAM_PIPE_GROUP
;
838 conn
->cli
= basic_conn
->cli
;
839 conn
->pipe_data
.samr
.rid
= group_rid
;
841 result
= cli_samr_open_group(conn
->cli
, conn
->cli
->mem_ctx
,
842 &basic_conn
->pol
, des_access
, group_rid
,
845 if (!NT_STATUS_IS_OK(result
))
850 DLIST_ADD(cm_conns
, conn
);
861 /* Get a handle on a netlogon pipe. This is a bit of a hack to re-use the
862 netlogon pipe as no handle is returned. */
864 NTSTATUS
cm_get_netlogon_cli(char *domain
, unsigned char *trust_passwd
,
865 struct cli_state
**cli
)
867 NTSTATUS result
= NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
;
868 struct winbindd_cm_conn
*conn
;
871 return NT_STATUS_INVALID_PARAMETER
;
874 /* Open an initial conection */
876 if (!NT_STATUS_IS_OK(result
= get_connection_from_cache(domain
, PIPE_NETLOGON
, &conn
))) {
880 result
= cli_nt_setup_creds(conn
->cli
, get_sec_chan(), trust_passwd
);
882 if (!NT_STATUS_IS_OK(result
)) {
883 DEBUG(0, ("error connecting to domain password server: %s\n",
886 /* Hit the cache code again. This cleans out the old connection and gets a new one */
887 if (conn
->cli
->fd
== -1) {
888 if (!NT_STATUS_IS_OK(result
= get_connection_from_cache(domain
, PIPE_NETLOGON
, &conn
))) {
893 result
= cli_nt_setup_creds(
894 conn
->cli
, get_sec_chan(),trust_passwd
);
897 if (!NT_STATUS_IS_OK(result
)) {
898 cli_shutdown(conn
->cli
);
899 DLIST_REMOVE(cm_conns
, conn
);
910 /* Dump the current connection status */
912 static void dump_conn_list(void)
914 struct winbindd_cm_conn
*con
;
916 DEBUG(0, ("\tDomain Controller Pipe\n"));
918 for(con
= cm_conns
; con
; con
= con
->next
) {
921 /* Display pipe info */
923 if (asprintf(&msg
, "\t%-15s %-15s %-16s", con
->domain
, con
->controller
, con
->pipe_name
) < 0) {
924 DEBUG(0, ("Error: not enough memory!\n"));
926 DEBUG(0, ("%s\n", msg
));
932 void winbindd_cm_status(void)
934 /* List open connections */
936 DEBUG(0, ("winbindd connection manager status:\n"));
941 DEBUG(0, ("\tNo active connections\n"));