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 size_t mutex_ref_count
;
76 struct cli_state
*cli
;
80 static struct winbindd_cm_conn
*cm_conns
= NULL
;
82 /* Get a domain controller name. Cache positive and negative lookups so we
83 don't go to the network too often when something is badly broken. */
85 #define GET_DC_NAME_CACHE_TIMEOUT 30 /* Seconds between dc lookups */
87 struct get_dc_name_cache
{
91 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)
105 ads
= ads_init(realm
, domain
, NULL
);
109 /* we don't need to bind, just connect */
110 ads
->auth
.flags
|= ADS_AUTH_NO_BIND
;
112 DEBUG(4,("cm_ads_find_dc: domain=%s\n", domain
));
115 /* a full ads_connect() is actually overkill, as we don't srictly need
116 to do the SASL auth in order to get the info we need, but libads
117 doesn't offer a better way right now */
121 if (!ads
->config
.realm
)
124 fstrcpy(srv_name
, ads
->config
.ldap_server_name
);
126 *dc_ip
= ads
->ldap_ip
;
129 DEBUG(4,("cm_ads_find_dc: using server='%s' IP=%s\n",
130 srv_name
, inet_ntoa(*dc_ip
)));
137 static BOOL
cm_get_dc_name(const char *domain
, fstring srv_name
, struct in_addr
*ip_out
)
139 static struct get_dc_name_cache
*get_dc_name_cache
;
140 struct get_dc_name_cache
*dcc
;
141 struct in_addr dc_ip
;
144 /* Check the cache for previous lookups */
146 for (dcc
= get_dc_name_cache
; dcc
; dcc
= dcc
->next
) {
148 if (!strequal(domain
, dcc
->domain_name
))
149 continue; /* Not our domain */
151 if ((time(NULL
) - dcc
->lookup_time
) >
152 GET_DC_NAME_CACHE_TIMEOUT
) {
154 /* Cache entry has expired, delete it */
156 DEBUG(10, ("get_dc_name_cache entry expired for %s\n", domain
));
158 DLIST_REMOVE(get_dc_name_cache
, dcc
);
164 /* Return a positive or negative lookup for this domain */
166 if (dcc
->srv_name
[0]) {
167 DEBUG(10, ("returning positive get_dc_name_cache entry for %s\n", domain
));
168 fstrcpy(srv_name
, dcc
->srv_name
);
171 DEBUG(10, ("returning negative get_dc_name_cache entry for %s\n", domain
));
176 /* Add cache entry for this lookup. */
178 DEBUG(10, ("Creating get_dc_name_cache entry for %s\n", domain
));
180 if (!(dcc
= (struct get_dc_name_cache
*)
181 malloc(sizeof(struct get_dc_name_cache
))))
186 fstrcpy(dcc
->domain_name
, domain
);
187 dcc
->lookup_time
= time(NULL
);
189 DLIST_ADD(get_dc_name_cache
, dcc
);
194 if (lp_security() == SEC_ADS
)
195 ret
= cm_ads_find_dc(domain
, &dc_ip
, srv_name
);
198 /* fall back on rpc methods if the ADS methods fail */
199 ret
= rpc_find_dc(domain
, srv_name
, &dc_ip
);
205 /* We have a name so make the cache entry positive now */
206 fstrcpy(dcc
->srv_name
, srv_name
);
208 DEBUG(3, ("cm_get_dc_name: Returning DC %s (%s) for domain %s\n", srv_name
,
209 inet_ntoa(dc_ip
), domain
));
216 /* Choose between anonymous or authenticated connections. We need to use
217 an authenticated connection if DCs have the RestrictAnonymous registry
218 entry set > 0, or the "Additional restrictions for anonymous
219 connections" set in the win2k Local Security Policy.
221 Caller to free() result in domain, username, password
224 static void cm_get_ipc_userpass(char **username
, char **domain
, char **password
)
226 *username
= secrets_fetch(SECRETS_AUTH_USER
, NULL
);
227 *domain
= secrets_fetch(SECRETS_AUTH_DOMAIN
, NULL
);
228 *password
= secrets_fetch(SECRETS_AUTH_PASSWORD
, NULL
);
230 if (*username
&& **username
) {
232 if (!*domain
|| !**domain
)
233 *domain
= smb_xstrdup(lp_workgroup());
235 if (!*password
|| !**password
)
236 *password
= smb_xstrdup("");
238 DEBUG(3, ("IPC$ connections done by user %s\\%s\n",
239 *domain
, *username
));
242 DEBUG(3, ("IPC$ connections done anonymously\n"));
243 *username
= smb_xstrdup("");
244 *domain
= smb_xstrdup("");
245 *password
= smb_xstrdup("");
249 /* Open a new smb pipe connection to a DC on a given domain. Cache
250 negative creation attempts so we don't try and connect to broken
251 machines too often. */
253 #define FAILED_CONNECTION_CACHE_TIMEOUT 30 /* Seconds between attempts */
255 struct failed_connection_cache
{
260 struct failed_connection_cache
*prev
, *next
;
263 static struct failed_connection_cache
*failed_connection_cache
;
265 /* Add an entry to the failed conneciton cache */
267 static void add_failed_connection_entry(struct winbindd_cm_conn
*new_conn
,
270 struct failed_connection_cache
*fcc
;
272 SMB_ASSERT(!NT_STATUS_IS_OK(result
));
274 /* Check we already aren't in the cache */
276 for (fcc
= failed_connection_cache
; fcc
; fcc
= fcc
->next
) {
277 if (strequal(fcc
->domain_name
, new_conn
->domain
)) {
278 DEBUG(10, ("domain %s already tried and failed\n",
284 /* Create negative lookup cache entry for this domain and controller */
286 if (!(fcc
= (struct failed_connection_cache
*)
287 malloc(sizeof(struct failed_connection_cache
)))) {
288 DEBUG(0, ("malloc failed in add_failed_connection_entry!\n"));
294 fstrcpy(fcc
->domain_name
, new_conn
->domain
);
295 fstrcpy(fcc
->controller
, new_conn
->controller
);
296 fcc
->lookup_time
= time(NULL
);
297 fcc
->nt_status
= result
;
299 DLIST_ADD(failed_connection_cache
, fcc
);
302 /* Open a connction to the remote server, cache failures for 30 seconds */
304 static NTSTATUS
cm_open_connection(const char *domain
, const int pipe_index
,
305 struct winbindd_cm_conn
*new_conn
, BOOL keep_mutex
)
307 struct failed_connection_cache
*fcc
;
309 char *ipc_username
, *ipc_domain
, *ipc_password
;
310 struct in_addr dc_ip
;
313 BOOL got_mutex
= False
;
317 fstrcpy(new_conn
->domain
, domain
);
318 fstrcpy(new_conn
->pipe_name
, get_pipe_name_from_index(pipe_index
));
320 /* Look for a domain controller for this domain. Negative results
321 are cached so don't bother applying the caching for this
322 function just yet. */
324 if (!cm_get_dc_name(domain
, new_conn
->controller
, &dc_ip
)) {
325 result
= NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
;
326 add_failed_connection_entry(new_conn
, result
);
330 /* Return false if we have tried to look up this domain and netbios
331 name before and failed. */
333 for (fcc
= failed_connection_cache
; fcc
; fcc
= fcc
->next
) {
335 if (!(strequal(domain
, fcc
->domain_name
) &&
336 strequal(new_conn
->controller
, fcc
->controller
)))
337 continue; /* Not our domain */
339 if ((time(NULL
) - fcc
->lookup_time
) >
340 FAILED_CONNECTION_CACHE_TIMEOUT
) {
342 /* Cache entry has expired, delete it */
344 DEBUG(10, ("cm_open_connection cache entry expired for %s, %s\n", domain
, new_conn
->controller
));
346 DLIST_REMOVE(failed_connection_cache
, fcc
);
352 /* The timeout hasn't expired yet so return false */
354 DEBUG(10, ("returning negative open_connection_cache entry for %s, %s\n", domain
, new_conn
->controller
));
356 result
= fcc
->nt_status
;
357 SMB_ASSERT(!NT_STATUS_IS_OK(result
));
361 /* Initialise SMB connection */
363 cm_get_ipc_userpass(&ipc_username
, &ipc_domain
, &ipc_password
);
365 DEBUG(5, ("connecting to %s from %s with username [%s]\\[%s]\n",
366 new_conn
->controller
, global_myname(), ipc_domain
, ipc_username
));
368 for (i
= 0; retry
&& (i
< 3); i
++) {
370 if (!secrets_named_mutex(new_conn
->controller
, WINBIND_SERVER_MUTEX_WAIT_TIME
, &new_conn
->mutex_ref_count
)) {
371 DEBUG(0,("cm_open_connection: mutex grab failed for %s\n", new_conn
->controller
));
372 result
= NT_STATUS_POSSIBLE_DEADLOCK
;
378 result
= cli_full_connection(&new_conn
->cli
, global_myname(), new_conn
->controller
,
379 &dc_ip
, 0, "IPC$", "IPC", ipc_username
, ipc_domain
,
380 ipc_password
, 0, &retry
);
382 if (NT_STATUS_IS_OK(result
))
385 secrets_named_mutex_release(new_conn
->controller
, &new_conn
->mutex_ref_count
);
389 SAFE_FREE(ipc_username
);
390 SAFE_FREE(ipc_domain
);
391 SAFE_FREE(ipc_password
);
393 if (!NT_STATUS_IS_OK(result
)) {
395 secrets_named_mutex_release(new_conn
->controller
, &new_conn
->mutex_ref_count
);
396 add_failed_connection_entry(new_conn
, result
);
400 if ( !cli_nt_session_open (new_conn
->cli
, pipe_index
) ) {
401 result
= NT_STATUS_PIPE_NOT_AVAILABLE
;
403 * only cache a failure if we are not trying to open the
404 * **win2k** specific lsarpc UUID. This could be an NT PDC
405 * and therefore a failure is normal. This should probably
406 * be abstracted to a check for 2k specific pipes and wondering
407 * if the PDC is an NT4 box. but since there is only one 2k
408 * specific UUID right now, i'm not going to bother. --jerry
411 secrets_named_mutex_release(new_conn
->controller
, &new_conn
->mutex_ref_count
);
412 if ( !is_win2k_pipe(pipe_index
) )
413 add_failed_connection_entry(new_conn
, result
);
414 cli_shutdown(new_conn
->cli
);
418 if ((got_mutex
) && !keep_mutex
)
419 secrets_named_mutex_release(new_conn
->controller
, &new_conn
->mutex_ref_count
);
423 /* Return true if a connection is still alive */
425 static BOOL
connection_ok(struct winbindd_cm_conn
*conn
)
428 smb_panic("Invalid paramater passed to conneciton_ok(): conn was NULL!\n");
433 DEBUG(0, ("Connection to %s for domain %s (pipe %s) has NULL conn->cli!\n",
434 conn
->controller
, conn
->domain
, conn
->pipe_name
));
435 smb_panic("connection_ok: conn->cli was null!");
439 if (!conn
->cli
->initialised
) {
440 DEBUG(0, ("Connection to %s for domain %s (pipe %s) was never initialised!\n",
441 conn
->controller
, conn
->domain
, conn
->pipe_name
));
442 smb_panic("connection_ok: conn->cli->initialised is False!");
446 if (conn
->cli
->fd
== -1) {
447 DEBUG(3, ("Connection to %s for domain %s (pipe %s) has died or was never started (fd == -1)\n",
448 conn
->controller
, conn
->domain
, conn
->pipe_name
));
455 /* Get a connection to the remote DC and open the pipe. If there is already a connection, use that */
457 static NTSTATUS
get_connection_from_cache(const char *domain
, const char *pipe_name
,
458 struct winbindd_cm_conn
**conn_out
, BOOL keep_mutex
)
460 struct winbindd_cm_conn
*conn
, conn_temp
;
463 for (conn
= cm_conns
; conn
; conn
= conn
->next
) {
464 if (strequal(conn
->domain
, domain
) &&
465 strequal(conn
->pipe_name
, pipe_name
)) {
466 if (!connection_ok(conn
)) {
468 cli_shutdown(conn
->cli
);
469 ZERO_STRUCT(conn_temp
);
470 conn_temp
.next
= conn
->next
;
471 DLIST_REMOVE(cm_conns
, conn
);
473 conn
= &conn_temp
; /* Just to keep the loop moving */
476 if (!secrets_named_mutex(conn
->controller
,
477 WINBIND_SERVER_MUTEX_WAIT_TIME
, &conn
->mutex_ref_count
))
478 DEBUG(0,("get_connection_from_cache: mutex grab failed for %s\n",
487 if (!(conn
= malloc(sizeof(*conn
))))
488 return NT_STATUS_NO_MEMORY
;
492 if (!NT_STATUS_IS_OK(result
= cm_open_connection(domain
, get_pipe_index(pipe_name
), conn
, keep_mutex
))) {
493 DEBUG(3, ("Could not open a connection to %s for %s (%s)\n",
494 domain
, pipe_name
, nt_errstr(result
)));
498 DLIST_ADD(cm_conns
, conn
);
506 /**********************************************************************************
507 **********************************************************************************/
509 BOOL
cm_check_for_native_mode_win2k( const char *domain
)
512 struct winbindd_cm_conn conn
;
520 if ( !NT_STATUS_IS_OK(result
= cm_open_connection(domain
, PI_LSARPC_DS
, &conn
, False
)) ) {
521 DEBUG(5, ("cm_check_for_native_mode_win2k: Could not open a connection to %s for PIPE_LSARPC (%s)\n",
522 domain
, nt_errstr(result
)));
527 if ( !NT_STATUS_IS_OK(cli_ds_getprimarydominfo( conn
.cli
,
528 conn
.cli
->mem_ctx
, DsRolePrimaryDomainInfoBasic
, &ctr
)) ) {
534 if ( (ctr
.basic
->flags
& DSROLE_PRIMARY_DS_RUNNING
)
535 && !(ctr
.basic
->flags
& DSROLE_PRIMARY_DS_MIXED_MODE
) )
540 cli_shutdown( conn
.cli
);
547 /* Return a LSA policy handle on a domain */
549 CLI_POLICY_HND
*cm_get_lsa_handle(const char *domain
)
551 struct winbindd_cm_conn
*conn
;
552 uint32 des_access
= SEC_RIGHTS_MAXIMUM_ALLOWED
;
554 static CLI_POLICY_HND hnd
;
556 /* Look for existing connections */
558 if (!NT_STATUS_IS_OK(result
= get_connection_from_cache(domain
, PIPE_LSARPC
, &conn
, False
)))
561 /* This *shitty* code needs scrapping ! JRA */
562 if (policy_handle_is_valid(&conn
->pol
)) {
568 result
= cli_lsa_open_policy(conn
->cli
, conn
->cli
->mem_ctx
, False
,
569 des_access
, &conn
->pol
);
571 if (!NT_STATUS_IS_OK(result
)) {
572 /* Hit the cache code again. This cleans out the old connection and gets a new one */
573 if (conn
->cli
->fd
== -1) { /* Try again, if the remote host disapeared */
574 if (!NT_STATUS_IS_OK(result
= get_connection_from_cache(domain
, PIPE_LSARPC
, &conn
, False
)))
577 result
= cli_lsa_open_policy(conn
->cli
, conn
->cli
->mem_ctx
, False
,
578 des_access
, &conn
->pol
);
581 if (!NT_STATUS_IS_OK(result
)) {
582 cli_shutdown(conn
->cli
);
583 DLIST_REMOVE(cm_conns
, conn
);
595 /* Return a SAM policy handle on a domain */
597 CLI_POLICY_HND
*cm_get_sam_handle(char *domain
)
599 struct winbindd_cm_conn
*conn
;
600 uint32 des_access
= SEC_RIGHTS_MAXIMUM_ALLOWED
;
602 static CLI_POLICY_HND hnd
;
604 /* Look for existing connections */
606 if (!NT_STATUS_IS_OK(result
= get_connection_from_cache(domain
, PIPE_SAMR
, &conn
, False
)))
609 /* This *shitty* code needs scrapping ! JRA */
610 if (policy_handle_is_valid(&conn
->pol
)) {
615 result
= cli_samr_connect(conn
->cli
, conn
->cli
->mem_ctx
,
616 des_access
, &conn
->pol
);
618 if (!NT_STATUS_IS_OK(result
)) {
619 /* Hit the cache code again. This cleans out the old connection and gets a new one */
620 if (conn
->cli
->fd
== -1) { /* Try again, if the remote host disapeared */
621 if (!NT_STATUS_IS_OK(result
= get_connection_from_cache(domain
, PIPE_SAMR
, &conn
, False
)))
624 result
= cli_samr_connect(conn
->cli
, conn
->cli
->mem_ctx
,
625 des_access
, &conn
->pol
);
628 if (!NT_STATUS_IS_OK(result
)) {
629 cli_shutdown(conn
->cli
);
630 DLIST_REMOVE(cm_conns
, conn
);
642 #if 0 /* This code now *well* out of date */
644 /* Return a SAM domain policy handle on a domain */
646 CLI_POLICY_HND
*cm_get_sam_dom_handle(char *domain
, DOM_SID
*domain_sid
)
648 struct winbindd_cm_conn
*conn
, *basic_conn
= NULL
;
649 static CLI_POLICY_HND hnd
;
651 uint32 des_access
= SEC_RIGHTS_MAXIMUM_ALLOWED
;
653 /* Look for existing connections */
655 for (conn
= cm_conns
; conn
; conn
= conn
->next
) {
656 if (strequal(conn
->domain
, domain
) &&
657 strequal(conn
->pipe_name
, PIPE_SAMR
) &&
658 conn
->pipe_data
.samr
.pipe_type
== SAM_PIPE_DOM
) {
660 if (!connection_ok(conn
)) {
661 /* Shutdown cli? Free conn? Allow retry of DC? */
662 DLIST_REMOVE(cm_conns
, conn
);
670 /* Create a basic handle to open a domain handle from */
672 if (!cm_get_sam_handle(domain
))
675 for (conn
= cm_conns
; conn
; conn
= conn
->next
) {
676 if (strequal(conn
->domain
, domain
) &&
677 strequal(conn
->pipe_name
, PIPE_SAMR
) &&
678 conn
->pipe_data
.samr
.pipe_type
== SAM_PIPE_BASIC
)
682 if (!(conn
= (struct winbindd_cm_conn
*)
683 malloc(sizeof(struct winbindd_cm_conn
))))
688 fstrcpy(conn
->domain
, basic_conn
->domain
);
689 fstrcpy(conn
->controller
, basic_conn
->controller
);
690 fstrcpy(conn
->pipe_name
, basic_conn
->pipe_name
);
692 conn
->pipe_data
.samr
.pipe_type
= SAM_PIPE_DOM
;
693 conn
->cli
= basic_conn
->cli
;
695 result
= cli_samr_open_domain(conn
->cli
, conn
->cli
->mem_ctx
,
696 &basic_conn
->pol
, des_access
,
697 domain_sid
, &conn
->pol
);
699 if (!NT_STATUS_IS_OK(result
))
704 DLIST_ADD(cm_conns
, conn
);
713 /* Return a SAM policy handle on a domain user */
715 CLI_POLICY_HND
*cm_get_sam_user_handle(char *domain
, DOM_SID
*domain_sid
,
718 struct winbindd_cm_conn
*conn
, *basic_conn
= NULL
;
719 static CLI_POLICY_HND hnd
;
721 uint32 des_access
= SEC_RIGHTS_MAXIMUM_ALLOWED
;
723 /* Look for existing connections */
725 for (conn
= cm_conns
; conn
; conn
= conn
->next
) {
726 if (strequal(conn
->domain
, domain
) &&
727 strequal(conn
->pipe_name
, PIPE_SAMR
) &&
728 conn
->pipe_data
.samr
.pipe_type
== SAM_PIPE_USER
&&
729 conn
->pipe_data
.samr
.rid
== user_rid
) {
731 if (!connection_ok(conn
)) {
732 /* Shutdown cli? Free conn? Allow retry of DC? */
733 DLIST_REMOVE(cm_conns
, conn
);
741 /* Create a domain handle to open a user handle from */
743 if (!cm_get_sam_dom_handle(domain
, domain_sid
))
746 for (conn
= cm_conns
; conn
; conn
= conn
->next
) {
747 if (strequal(conn
->domain
, domain
) &&
748 strequal(conn
->pipe_name
, PIPE_SAMR
) &&
749 conn
->pipe_data
.samr
.pipe_type
== SAM_PIPE_DOM
)
754 DEBUG(0, ("No domain sam handle was created!\n"));
758 if (!(conn
= (struct winbindd_cm_conn
*)
759 malloc(sizeof(struct winbindd_cm_conn
))))
764 fstrcpy(conn
->domain
, basic_conn
->domain
);
765 fstrcpy(conn
->controller
, basic_conn
->controller
);
766 fstrcpy(conn
->pipe_name
, basic_conn
->pipe_name
);
768 conn
->pipe_data
.samr
.pipe_type
= SAM_PIPE_USER
;
769 conn
->cli
= basic_conn
->cli
;
770 conn
->pipe_data
.samr
.rid
= user_rid
;
772 result
= cli_samr_open_user(conn
->cli
, conn
->cli
->mem_ctx
,
773 &basic_conn
->pol
, des_access
, user_rid
,
776 if (!NT_STATUS_IS_OK(result
))
781 DLIST_ADD(cm_conns
, conn
);
790 /* Return a SAM policy handle on a domain group */
792 CLI_POLICY_HND
*cm_get_sam_group_handle(char *domain
, DOM_SID
*domain_sid
,
795 struct winbindd_cm_conn
*conn
, *basic_conn
= NULL
;
796 static CLI_POLICY_HND hnd
;
798 uint32 des_access
= SEC_RIGHTS_MAXIMUM_ALLOWED
;
800 /* Look for existing connections */
802 for (conn
= cm_conns
; conn
; conn
= conn
->next
) {
803 if (strequal(conn
->domain
, domain
) &&
804 strequal(conn
->pipe_name
, PIPE_SAMR
) &&
805 conn
->pipe_data
.samr
.pipe_type
== SAM_PIPE_GROUP
&&
806 conn
->pipe_data
.samr
.rid
== group_rid
) {
808 if (!connection_ok(conn
)) {
809 /* Shutdown cli? Free conn? Allow retry of DC? */
810 DLIST_REMOVE(cm_conns
, conn
);
818 /* Create a domain handle to open a user handle from */
820 if (!cm_get_sam_dom_handle(domain
, domain_sid
))
823 for (conn
= cm_conns
; conn
; conn
= conn
->next
) {
824 if (strequal(conn
->domain
, domain
) &&
825 strequal(conn
->pipe_name
, PIPE_SAMR
) &&
826 conn
->pipe_data
.samr
.pipe_type
== SAM_PIPE_DOM
)
831 DEBUG(0, ("No domain sam handle was created!\n"));
835 if (!(conn
= (struct winbindd_cm_conn
*)
836 malloc(sizeof(struct winbindd_cm_conn
))))
841 fstrcpy(conn
->domain
, basic_conn
->domain
);
842 fstrcpy(conn
->controller
, basic_conn
->controller
);
843 fstrcpy(conn
->pipe_name
, basic_conn
->pipe_name
);
845 conn
->pipe_data
.samr
.pipe_type
= SAM_PIPE_GROUP
;
846 conn
->cli
= basic_conn
->cli
;
847 conn
->pipe_data
.samr
.rid
= group_rid
;
849 result
= cli_samr_open_group(conn
->cli
, conn
->cli
->mem_ctx
,
850 &basic_conn
->pol
, des_access
, group_rid
,
853 if (!NT_STATUS_IS_OK(result
))
858 DLIST_ADD(cm_conns
, conn
);
869 /* Get a handle on a netlogon pipe. This is a bit of a hack to re-use the
870 netlogon pipe as no handle is returned. */
872 NTSTATUS
cm_get_netlogon_cli(const char *domain
, const unsigned char *trust_passwd
,
873 struct cli_state
**cli
)
875 NTSTATUS result
= NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
;
876 struct winbindd_cm_conn
*conn
;
877 uint32 neg_flags
= 0x000001ff;
880 return NT_STATUS_INVALID_PARAMETER
;
882 /* Open an initial conection - keep the mutex. */
884 if (!NT_STATUS_IS_OK(result
= get_connection_from_cache(domain
, PIPE_NETLOGON
, &conn
, True
)))
887 result
= cli_nt_setup_creds(conn
->cli
, get_sec_chan(), trust_passwd
, &neg_flags
, 2);
889 if (conn
->mutex_ref_count
)
890 secrets_named_mutex_release(conn
->controller
, &conn
->mutex_ref_count
);
892 if (!NT_STATUS_IS_OK(result
)) {
893 DEBUG(0, ("error connecting to domain password server: %s\n",
896 /* Hit the cache code again. This cleans out the old connection and gets a new one */
897 if (conn
->cli
->fd
== -1) {
899 if (!NT_STATUS_IS_OK(result
= get_connection_from_cache(domain
, PIPE_NETLOGON
, &conn
, True
)))
903 result
= cli_nt_setup_creds( conn
->cli
, get_sec_chan(),trust_passwd
, &neg_flags
, 2);
905 if (conn
->mutex_ref_count
)
906 secrets_named_mutex_release(conn
->controller
, &conn
->mutex_ref_count
);
909 if (!NT_STATUS_IS_OK(result
)) {
910 cli_shutdown(conn
->cli
);
911 DLIST_REMOVE(cm_conns
, conn
);
922 /* Dump the current connection status */
924 static void dump_conn_list(void)
926 struct winbindd_cm_conn
*con
;
928 DEBUG(0, ("\tDomain Controller Pipe\n"));
930 for(con
= cm_conns
; con
; con
= con
->next
) {
933 /* Display pipe info */
935 if (asprintf(&msg
, "\t%-15s %-15s %-16s", con
->domain
, con
->controller
, con
->pipe_name
) < 0) {
936 DEBUG(0, ("Error: not enough memory!\n"));
938 DEBUG(0, ("%s\n", msg
));
944 void winbindd_cm_status(void)
946 /* List open connections */
948 DEBUG(0, ("winbindd connection manager status:\n"));
953 DEBUG(0, ("\tNo active connections\n"));