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 /************************************************************************
205 Given a fd with a just-connected TCP connection to a DC, open a connection
207 ************************************************************************/
209 static NTSTATUS
cm_prepare_connection(const struct winbindd_domain
*domain
,
211 const int pipe_index
,
212 const char *controller
,
213 struct cli_state
**cli
,
216 char *machine_password
, *machine_krb5_principal
;
217 char *ipc_username
, *ipc_domain
, *ipc_password
;
218 struct ntuser_creds creds
;
221 BOOL add_failed_connection
= True
;
223 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
225 struct sockaddr peeraddr
;
226 socklen_t peeraddr_len
;
228 struct sockaddr_in
*peeraddr_in
= (struct sockaddr_in
*)&peeraddr
;
230 machine_password
= secrets_fetch_machine_password(lp_workgroup(), NULL
,
233 if (asprintf(&machine_krb5_principal
, "%s$@%s", global_myname(),
235 SAFE_FREE(machine_password
);
236 return NT_STATUS_NO_MEMORY
;
239 cm_get_ipc_userpass(&ipc_username
, &ipc_domain
, &ipc_password
);
243 got_mutex
= secrets_named_mutex(controller
,
244 WINBIND_SERVER_MUTEX_WAIT_TIME
);
247 DEBUG(0,("cm_open_connection: mutex grab failed for %s\n",
249 result
= NT_STATUS_POSSIBLE_DEADLOCK
;
253 if ((*cli
= cli_initialise(NULL
)) == NULL
) {
254 DEBUG(1, ("Could not cli_initialize\n"));
255 result
= NT_STATUS_NO_MEMORY
;
259 (*cli
)->timeout
= 10000; /* 10 seconds */
261 fstrcpy((*cli
)->desthost
, controller
);
262 (*cli
)->use_kerberos
= True
;
264 peeraddr_len
= sizeof(peeraddr
);
266 if ((getpeername((*cli
)->fd
, &peeraddr
, &peeraddr_len
) != 0) ||
267 (peeraddr_len
!= sizeof(struct sockaddr_in
)) ||
268 (peeraddr_in
->sin_family
!= PF_INET
))
271 if (ntohs(peeraddr_in
->sin_port
) == 139) {
272 struct nmb_name calling
;
273 struct nmb_name called
;
275 make_nmb_name(&calling
, global_myname(), 0x0);
276 make_nmb_name(&called
, "*SMBSERVER", 0x20);
278 if (!cli_session_request(*cli
, &calling
, &called
)) {
279 DEBUG(8, ("cli_session_request failed for %s\n",
285 cli_setup_signing_state(*cli
, Undefined
);
287 if (!cli_negprot(*cli
)) {
288 DEBUG(1, ("cli_negprot failed\n"));
295 if ((lp_security() == SEC_ADS
)
296 && ((*cli
)->protocol
>= PROTOCOL_NT1
&&
297 (*cli
)->capabilities
& CAP_EXTENDED_SECURITY
)) {
299 ADS_STATUS ads_status
;
300 (*cli
)->use_kerberos
= True
;
301 DEBUG(5, ("connecting to %s from %s with kerberos principal "
302 "[%s]\n", controller
, global_myname(),
303 machine_krb5_principal
));
305 ads_status
= cli_session_setup_spnego(*cli
,
306 machine_krb5_principal
,
310 if (!ADS_ERR_OK(ads_status
))
311 DEBUG(4,("failed kerberos session setup with %s\n",
312 ads_errstr(ads_status
)));
314 result
= ads_ntstatus(ads_status
);
317 if (NT_STATUS_IS_OK(result
))
318 goto session_setup_done
;
320 /* Fall back to non-kerberos session setup */
322 (*cli
)->use_kerberos
= False
;
324 if ((((*cli
)->sec_mode
& NEGOTIATE_SECURITY_CHALLENGE_RESPONSE
) != 0) &&
325 (strlen(ipc_username
) > 0)) {
327 /* Only try authenticated if we have a username */
329 DEBUG(5, ("connecting to %s from %s with username "
330 "[%s]\\[%s]\n", controller
, global_myname(),
331 ipc_domain
, ipc_username
));
333 if (cli_session_setup(*cli
, ipc_username
,
334 ipc_password
, strlen(ipc_password
)+1,
335 ipc_password
, strlen(ipc_password
)+1,
337 DEBUG(5, ("authenticated session setup failed\n"));
338 goto session_setup_done
;
342 /* Fall back to anonymous connection, this might fail later */
344 if (cli_session_setup(*cli
, "", NULL
, 0, NULL
, 0, "")) {
345 DEBUG(5, ("Connected anonymously\n"));
346 goto session_setup_done
;
349 result
= cli_nt_error(*cli
);
351 if (NT_STATUS_IS_OK(result
))
352 result
= NT_STATUS_UNSUCCESSFUL
;
354 /* We can't session setup */
360 if (!cli_send_tconX(*cli
, "IPC$", "IPC", "", 0)) {
362 result
= cli_nt_error(*cli
);
364 DEBUG(1,("failed tcon_X with %s\n", nt_errstr(result
)));
366 if (NT_STATUS_IS_OK(result
))
367 result
= NT_STATUS_UNSUCCESSFUL
;
373 init_creds(&creds
, ipc_username
, ipc_domain
, ipc_password
);
374 cli_init_creds(*cli
, &creds
);
376 secrets_named_mutex_release(controller
);
380 if (domain
->primary
|| IS_DC
) {
381 NTSTATUS status
= setup_schannel( *cli
, domain
->name
);
382 if (!NT_STATUS_IS_OK(status
)) {
383 DEBUG(3,("schannel refused - continuing without "
384 "schannel (%s)\n", nt_errstr(status
)));
388 /* set the domain if empty; needed for schannel connections */
389 if ( !*(*cli
)->domain
)
390 fstrcpy( (*cli
)->domain
, domain
->name
);
392 if ( !cli_nt_session_open (*cli
, pipe_index
) ) {
394 result
= NT_STATUS_PIPE_NOT_AVAILABLE
;
396 /* This might be a NT4 DC */
397 if ( is_win2k_pipe(pipe_index
) )
398 add_failed_connection
= False
;
404 result
= NT_STATUS_OK
;
405 add_failed_connection
= False
;
409 secrets_named_mutex_release(controller
);
411 SAFE_FREE(machine_password
);
412 SAFE_FREE(machine_krb5_principal
);
413 SAFE_FREE(ipc_username
);
414 SAFE_FREE(ipc_domain
);
415 SAFE_FREE(ipc_password
);
417 if (add_failed_connection
)
418 add_failed_connection_entry(domain
->name
, controller
, result
);
428 static BOOL
add_one_dc_unique(TALLOC_CTX
*mem_ctx
, const char *domain_name
,
429 const char *dcname
, struct in_addr ip
,
430 struct dc_name_ip
**dcs
, int *num
)
432 if (!NT_STATUS_IS_OK(check_negative_conn_cache(domain_name
, dcname
)))
435 *dcs
= TALLOC_REALLOC_ARRAY(mem_ctx
, *dcs
, struct dc_name_ip
, (*num
)+1);
440 fstrcpy((*dcs
)[*num
].name
, dcname
);
441 (*dcs
)[*num
].ip
= ip
;
446 static BOOL
add_string_to_array(TALLOC_CTX
*mem_ctx
,
447 const char *str
, char ***array
, int *num
)
449 char *dup_str
= talloc_strdup(mem_ctx
, str
);
451 *array
= TALLOC_REALLOC_ARRAY(mem_ctx
, *array
, char *, (*num
)+1);
453 if ((*array
== NULL
) || (dup_str
== NULL
))
456 (*array
)[*num
] = dup_str
;
461 static BOOL
add_sockaddr_to_array(TALLOC_CTX
*mem_ctx
,
462 struct in_addr ip
, uint16 port
,
463 struct sockaddr_in
**addrs
, int *num
)
465 *addrs
= TALLOC_REALLOC_ARRAY(mem_ctx
, *addrs
, struct sockaddr_in
, (*num
)+1);
470 (*addrs
)[*num
].sin_family
= PF_INET
;
471 putip((char *)&((*addrs
)[*num
].sin_addr
), (char *)&ip
);
472 (*addrs
)[*num
].sin_port
= htons(port
);
478 static BOOL
get_dcs_1c(TALLOC_CTX
*mem_ctx
,
479 const struct winbindd_domain
*domain
,
480 struct dc_name_ip
**dcs
, int *num_dcs
)
482 struct ip_service
*iplist
= NULL
;
485 if (!internal_resolve_name(domain
->name
, 0x1c, &iplist
, &num
,
486 lp_name_resolve_order()))
489 /* Now try to find the server names of at least one IP address, hosts
490 * not replying are cached as such */
492 for (i
=0; i
<num
; i
++) {
496 if (!name_status_find(domain
->name
, 0x1c, 0x20, iplist
[i
].ip
,
500 if (add_one_dc_unique(mem_ctx
, domain
->name
, dcname
,
501 iplist
[i
].ip
, dcs
, num_dcs
)) {
502 /* One DC responded, so we assume that he will also
511 static BOOL
get_dcs(TALLOC_CTX
*mem_ctx
, const struct winbindd_domain
*domain
,
512 struct dc_name_ip
**dcs
, int *num_dcs
)
520 is_our_domain
= strequal(domain
->name
, lp_workgroup());
522 if (!is_our_domain
&& get_dc_name_via_netlogon(domain
, dcname
, &ip
) &&
523 add_one_dc_unique(mem_ctx
, domain
->name
, dcname
, ip
, dcs
, num_dcs
))
526 if (!is_our_domain
) {
527 /* NETLOGON to our own domain could not give us a DC name
528 * (which is an error), fall back to looking up domain#1c */
529 return get_dcs_1c(mem_ctx
, domain
, dcs
, num_dcs
);
532 if (must_use_pdc(domain
->name
) && get_pdc_ip(domain
->name
, &ip
)) {
534 if (!name_status_find(domain
->name
, 0x1b, 0x20, ip
, dcname
))
537 if (add_one_dc_unique(mem_ctx
, domain
->name
,
538 dcname
, ip
, dcs
, num_dcs
))
542 p
= lp_passwordserver();
545 return get_dcs_1c(mem_ctx
, domain
, dcs
, num_dcs
);
547 while (next_token(&p
, dcname
, LIST_SEP
, sizeof(dcname
))) {
549 if (strequal(dcname
, "*")) {
550 get_dcs_1c(mem_ctx
, domain
, dcs
, num_dcs
);
554 if (!resolve_name(dcname
, &ip
, 0x20))
557 add_one_dc_unique(mem_ctx
, domain
->name
, dcname
, ip
,
564 static BOOL
find_new_dc(TALLOC_CTX
*mem_ctx
,
565 const struct winbindd_domain
*domain
,
566 fstring dcname
, struct sockaddr_in
*addr
, int *fd
)
568 struct dc_name_ip
*dcs
= NULL
;
571 char **dcnames
= NULL
;
574 struct sockaddr_in
*addrs
= NULL
;
579 if (!get_dcs(mem_ctx
, domain
, &dcs
, &num_dcs
) || (num_dcs
== 0))
582 for (i
=0; i
<num_dcs
; i
++) {
584 add_string_to_array(mem_ctx
, dcs
[i
].name
,
585 &dcnames
, &num_dcnames
);
586 add_sockaddr_to_array(mem_ctx
, dcs
[i
].ip
, 445,
589 add_string_to_array(mem_ctx
, dcs
[i
].name
,
590 &dcnames
, &num_dcnames
);
591 add_sockaddr_to_array(mem_ctx
, dcs
[i
].ip
, 139,
595 if ((num_dcnames
== 0) || (num_dcnames
!= num_addrs
))
598 if (!open_any_socket_out(addrs
, num_addrs
, 10000, &fd_index
, fd
)) {
599 for (i
=0; i
<num_dcs
; i
++) {
600 add_failed_connection_entry(domain
->name
,
602 NT_STATUS_UNSUCCESSFUL
);
607 fstrcpy(dcname
, dcnames
[fd_index
]);
608 *addr
= addrs
[fd_index
];
613 static NTSTATUS
cm_open_connection(struct winbindd_domain
*domain
,
614 const int pipe_index
,
615 struct winbindd_cm_conn
*new_conn
)
622 if ((mem_ctx
= talloc_init("cm_open_connection")) == NULL
)
623 return NT_STATUS_NO_MEMORY
;
625 for (retries
= 0; retries
< 3; retries
++) {
630 result
= NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
;
632 if ((strlen(domain
->dcname
) > 0) &&
633 NT_STATUS_IS_OK(check_negative_conn_cache(domain
->name
,
636 if (!open_any_socket_out(&domain
->dcaddr
, 1, 10000,
643 !find_new_dc(mem_ctx
, domain
, domain
->dcname
,
644 &domain
->dcaddr
, &fd
))
647 new_conn
->cli
= NULL
;
649 result
= cm_prepare_connection(domain
, fd
, pipe_index
,
651 &new_conn
->cli
, &retry
);
653 if (NT_STATUS_IS_OK(result
)) {
654 fstrcpy(new_conn
->domain
, domain
->name
);
655 /* Initialise SMB connection */
656 fstrcpy(new_conn
->pipe_name
,
657 get_pipe_name_from_index(pipe_index
));
665 talloc_destroy(mem_ctx
);
669 /************************************************************************
670 Wrapper around statuc cm_open_connection to retreive a freshly
671 setup cli_state struct
672 ************************************************************************/
674 NTSTATUS
cm_fresh_connection(struct winbindd_domain
*domain
, const int pipe_index
,
675 struct cli_state
**cli
)
678 struct winbindd_cm_conn conn
;
680 result
= cm_open_connection( domain
, pipe_index
, &conn
);
682 if ( NT_STATUS_IS_OK(result
) )
688 /* Return true if a connection is still alive */
690 static BOOL
connection_ok(struct winbindd_cm_conn
*conn
)
693 smb_panic("Invalid parameter passed to connection_ok(): conn was NULL!\n");
698 DEBUG(3, ("Connection to %s for domain %s (pipe %s) has NULL conn->cli!\n",
699 conn
->controller
, conn
->domain
, conn
->pipe_name
));
703 if (!conn
->cli
->initialised
) {
704 DEBUG(3, ("Connection to %s for domain %s (pipe %s) was never initialised!\n",
705 conn
->controller
, conn
->domain
, conn
->pipe_name
));
709 if (conn
->cli
->fd
== -1) {
710 DEBUG(3, ("Connection to %s for domain %s (pipe %s) has died or was never started (fd == -1)\n",
711 conn
->controller
, conn
->domain
, conn
->pipe_name
));
718 /* Search the cache for a connection. If there is a broken one,
719 shut it down properly and return NULL. */
721 static void find_cm_connection(struct winbindd_domain
*domain
, const char *pipe_name
,
722 struct winbindd_cm_conn
**conn_out
)
724 struct winbindd_cm_conn
*conn
;
726 for (conn
= cm_conns
; conn
; ) {
727 if (strequal(conn
->domain
, domain
->name
) &&
728 strequal(conn
->pipe_name
, pipe_name
)) {
729 if (!connection_ok(conn
)) {
730 /* Dead connection - remove it. */
731 struct winbindd_cm_conn
*conn_temp
= conn
->next
;
733 cli_shutdown(conn
->cli
);
734 DLIST_REMOVE(cm_conns
, conn
);
736 conn
= conn_temp
; /* Keep the loop moving */
748 /* Initialize a new connection up to the RPC BIND. */
750 static NTSTATUS
new_cm_connection(struct winbindd_domain
*domain
, const char *pipe_name
,
751 struct winbindd_cm_conn
**conn_out
)
753 struct winbindd_cm_conn
*conn
;
756 if (!(conn
= SMB_MALLOC_P(struct winbindd_cm_conn
)))
757 return NT_STATUS_NO_MEMORY
;
761 if (!NT_STATUS_IS_OK(result
= cm_open_connection(domain
, get_pipe_index(pipe_name
), conn
))) {
762 DEBUG(3, ("Could not open a connection to %s for %s (%s)\n",
763 domain
->name
, pipe_name
, nt_errstr(result
)));
767 DLIST_ADD(cm_conns
, conn
);
773 /* Get a connection to the remote DC and open the pipe. If there is already a connection, use that */
775 static NTSTATUS
get_connection_from_cache(struct winbindd_domain
*domain
, const char *pipe_name
,
776 struct winbindd_cm_conn
**conn_out
)
778 find_cm_connection(domain
, pipe_name
, conn_out
);
780 if (*conn_out
!= NULL
)
783 return new_cm_connection(domain
, pipe_name
, conn_out
);
786 /**********************************************************************************
787 We can 'sense' certain things about the DC by it's replies to certain questions.
789 This tells us if this particular remote server is Active Directory, and if it is
791 **********************************************************************************/
793 void set_dc_type_and_flags( struct winbindd_domain
*domain
)
796 struct winbindd_cm_conn conn
;
798 TALLOC_CTX
*mem_ctx
= NULL
;
803 domain
->native_mode
= False
;
804 domain
->active_directory
= False
;
806 if (domain
->internal
) {
807 domain
->initialized
= True
;
811 if ( !NT_STATUS_IS_OK(result
= cm_open_connection(domain
, PI_LSARPC_DS
, &conn
)) ) {
812 DEBUG(5, ("set_dc_type_and_flags: Could not open a connection to %s for PIPE_LSARPC (%s)\n",
813 domain
->name
, nt_errstr(result
)));
814 domain
->initialized
= True
;
819 if ( !NT_STATUS_IS_OK(cli_ds_getprimarydominfo( conn
.cli
,
820 conn
.cli
->mem_ctx
, DsRolePrimaryDomainInfoBasic
, &ctr
)) ) {
825 if ( (ctr
.basic
->flags
& DSROLE_PRIMARY_DS_RUNNING
)
826 && !(ctr
.basic
->flags
& DSROLE_PRIMARY_DS_MIXED_MODE
) )
827 domain
->native_mode
= True
;
829 /* Cheat - shut down the DS pipe, and open LSA */
831 cli_nt_session_close(conn
.cli
);
833 if ( cli_nt_session_open (conn
.cli
, PI_LSARPC
) ) {
834 char *domain_name
= NULL
;
835 char *dns_name
= NULL
;
836 DOM_SID
*dom_sid
= NULL
;
838 mem_ctx
= talloc_init("set_dc_type_and_flags on domain %s\n", domain
->name
);
840 DEBUG(1, ("set_dc_type_and_flags: talloc_init() failed\n"));
844 result
= cli_lsa_open_policy2(conn
.cli
, mem_ctx
, True
,
845 SEC_RIGHTS_MAXIMUM_ALLOWED
,
848 if (NT_STATUS_IS_OK(result
)) {
849 /* This particular query is exactly what Win2k clients use
850 to determine that the DC is active directory */
851 result
= cli_lsa_query_info_policy2(conn
.cli
, mem_ctx
,
858 if (NT_STATUS_IS_OK(result
)) {
860 fstrcpy(domain
->name
, domain_name
);
863 fstrcpy(domain
->alt_name
, dns_name
);
866 sid_copy(&domain
->sid
, dom_sid
);
868 domain
->active_directory
= True
;
871 result
= cli_lsa_open_policy(conn
.cli
, mem_ctx
, True
,
872 SEC_RIGHTS_MAXIMUM_ALLOWED
,
875 if (!NT_STATUS_IS_OK(result
))
878 result
= cli_lsa_query_info_policy(conn
.cli
, mem_ctx
,
879 &conn
.pol
, 5, &domain_name
,
882 if (NT_STATUS_IS_OK(result
)) {
884 fstrcpy(domain
->name
, domain_name
);
887 sid_copy(&domain
->sid
, dom_sid
);
894 /* close the connection; no other calls use this pipe and it is called only
895 on reestablishing the domain list --jerry */
898 cli_shutdown( conn
.cli
);
900 talloc_destroy(mem_ctx
);
902 domain
->initialized
= True
;
909 /* Return a LSA policy handle on a domain */
911 NTSTATUS
cm_get_lsa_handle(struct winbindd_domain
*domain
, CLI_POLICY_HND
**return_hnd
)
913 struct winbindd_cm_conn
*conn
;
914 uint32 des_access
= SEC_RIGHTS_MAXIMUM_ALLOWED
;
916 static CLI_POLICY_HND hnd
;
918 /* Look for existing connections */
920 if (!NT_STATUS_IS_OK(result
= get_connection_from_cache(domain
, PIPE_LSARPC
, &conn
)))
923 /* This *shitty* code needs scrapping ! JRA */
925 if (policy_handle_is_valid(&conn
->pol
)) {
933 result
= cli_lsa_open_policy(conn
->cli
, conn
->cli
->mem_ctx
, False
,
934 des_access
, &conn
->pol
);
936 if (!NT_STATUS_IS_OK(result
)) {
937 /* Hit the cache code again. This cleans out the old connection and gets a new one */
938 if (conn
->cli
->fd
== -1) { /* Try again, if the remote host disapeared */
939 if (!NT_STATUS_IS_OK(result
= get_connection_from_cache(domain
, PIPE_LSARPC
, &conn
)))
942 result
= cli_lsa_open_policy(conn
->cli
, conn
->cli
->mem_ctx
, False
,
943 des_access
, &conn
->pol
);
946 if (!NT_STATUS_IS_OK(result
)) {
947 cli_shutdown(conn
->cli
);
948 DLIST_REMOVE(cm_conns
, conn
);
962 /* Return a SAM policy handle on a domain */
964 NTSTATUS
cm_get_sam_handle(struct winbindd_domain
*domain
, CLI_POLICY_HND
**return_hnd
)
966 struct winbindd_cm_conn
*conn
;
967 uint32 des_access
= SEC_RIGHTS_MAXIMUM_ALLOWED
;
969 static CLI_POLICY_HND hnd
;
971 /* Look for existing connections */
973 if (!NT_STATUS_IS_OK(result
= get_connection_from_cache(domain
, PIPE_SAMR
, &conn
)))
976 /* This *shitty* code needs scrapping ! JRA */
978 if (policy_handle_is_valid(&conn
->pol
)) {
987 result
= cli_samr_connect(conn
->cli
, conn
->cli
->mem_ctx
,
988 des_access
, &conn
->pol
);
990 if (!NT_STATUS_IS_OK(result
)) {
991 /* Hit the cache code again. This cleans out the old connection and gets a new one */
992 if (conn
->cli
->fd
== -1) { /* Try again, if the remote host disapeared */
994 if (!NT_STATUS_IS_OK(result
= get_connection_from_cache(domain
, PIPE_SAMR
, &conn
)))
997 result
= cli_samr_connect(conn
->cli
, conn
->cli
->mem_ctx
,
998 des_access
, &conn
->pol
);
1001 if (!NT_STATUS_IS_OK(result
)) {
1003 cli_shutdown(conn
->cli
);
1004 DLIST_REMOVE(cm_conns
, conn
);
1011 hnd
.pol
= conn
->pol
;
1012 hnd
.cli
= conn
->cli
;
1016 return NT_STATUS_OK
;
1019 /* Get a handle on a netlogon pipe. This is a bit of a hack to re-use the
1020 netlogon pipe as no handle is returned. */
1022 NTSTATUS
cm_get_netlogon_cli(struct winbindd_domain
*domain
,
1023 const unsigned char *trust_passwd
,
1024 uint32 sec_channel_type
,
1026 struct cli_state
**cli
)
1028 NTSTATUS result
= NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
;
1029 struct winbindd_cm_conn
*conn
;
1034 return NT_STATUS_INVALID_PARAMETER
;
1036 /* Open an initial conection - keep the mutex. */
1038 find_cm_connection(domain
, PIPE_NETLOGON
, &conn
);
1040 if ( fresh
&& (conn
!= NULL
) ) {
1041 cli_shutdown(conn
->cli
);
1046 /* purge connection from cache */
1047 find_cm_connection(domain
, PIPE_NETLOGON
, &conn
);
1049 DEBUG(0,("Could not purge connection\n"));
1050 return NT_STATUS_UNSUCCESSFUL
;
1056 return NT_STATUS_OK
;
1059 result
= new_cm_connection(domain
, PIPE_NETLOGON
, &conn
);
1061 if (!NT_STATUS_IS_OK(result
))
1064 fstr_sprintf(lock_name
, "NETLOGON\\%s", conn
->controller
);
1066 if (!(got_mutex
= secrets_named_mutex(lock_name
, WINBIND_SERVER_MUTEX_WAIT_TIME
))) {
1067 DEBUG(0,("cm_get_netlogon_cli: mutex grab failed for %s\n", conn
->controller
));
1070 if ( sec_channel_type
== SEC_CHAN_DOMAIN
)
1071 fstr_sprintf(conn
->cli
->mach_acct
, "%s$", lp_workgroup());
1073 /* This must be the remote domain (not ours) for schannel */
1075 fstrcpy( conn
->cli
->domain
, domain
->name
);
1077 result
= cli_nt_establish_netlogon(conn
->cli
, sec_channel_type
, trust_passwd
);
1080 secrets_named_mutex_release(lock_name
);
1082 if (!NT_STATUS_IS_OK(result
)) {
1083 cli_shutdown(conn
->cli
);
1084 DLIST_REMOVE(cm_conns
, conn
);
1094 /* Dump the current connection status */
1096 static void dump_conn_list(void)
1098 struct winbindd_cm_conn
*con
;
1100 DEBUG(0, ("\tDomain Controller Pipe\n"));
1102 for(con
= cm_conns
; con
; con
= con
->next
) {
1105 /* Display pipe info */
1107 if (asprintf(&msg
, "\t%-15s %-15s %-16s", con
->domain
, con
->controller
, con
->pipe_name
) < 0) {
1108 DEBUG(0, ("Error: not enough memory!\n"));
1110 DEBUG(0, ("%s\n", msg
));
1116 void winbindd_cm_status(void)
1118 /* List open connections */
1120 DEBUG(0, ("winbindd connection manager status:\n"));
1125 DEBUG(0, ("\tNo active connections\n"));
1128 /* Close all cached connections */
1130 void winbindd_cm_flush(void)
1132 struct winbindd_cm_conn
*conn
, tmp
;
1134 /* Flush connection cache */
1136 for (conn
= cm_conns
; conn
; conn
= conn
->next
) {
1138 if (!connection_ok(conn
))
1141 DEBUG(10, ("Closing connection to %s on %s\n",
1142 conn
->pipe_name
, conn
->controller
));
1145 cli_shutdown(conn
->cli
);
1147 tmp
.next
= conn
->next
;
1149 DLIST_REMOVE(cm_conns
, conn
);
1154 /* Flush failed connection cache */
1156 flush_negative_conn_cache();