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 size_t mutex_ref_count
;
74 struct cli_state
*cli
;
78 static struct winbindd_cm_conn
*cm_conns
= NULL
;
81 /* Choose between anonymous or authenticated connections. We need to use
82 an authenticated connection if DCs have the RestrictAnonymous registry
83 entry set > 0, or the "Additional restrictions for anonymous
84 connections" set in the win2k Local Security Policy.
86 Caller to free() result in domain, username, password
89 static void cm_get_ipc_userpass(char **username
, char **domain
, char **password
)
91 *username
= secrets_fetch(SECRETS_AUTH_USER
, NULL
);
92 *domain
= secrets_fetch(SECRETS_AUTH_DOMAIN
, NULL
);
93 *password
= secrets_fetch(SECRETS_AUTH_PASSWORD
, NULL
);
95 if (*username
&& **username
) {
97 if (!*domain
|| !**domain
)
98 *domain
= smb_xstrdup(lp_workgroup());
100 if (!*password
|| !**password
)
101 *password
= smb_xstrdup("");
103 DEBUG(3, ("IPC$ connections done by user %s\\%s\n",
104 *domain
, *username
));
107 DEBUG(3, ("IPC$ connections done anonymously\n"));
108 *username
= smb_xstrdup("");
109 *domain
= smb_xstrdup("");
110 *password
= smb_xstrdup("");
115 setup for schannel on any pipes opened on this connection
117 static NTSTATUS
setup_schannel(struct cli_state
*cli
)
120 uchar trust_password
[16];
121 uint32 sec_channel_type
;
123 if (!secrets_fetch_trust_account_password(lp_workgroup(),
125 NULL
, &sec_channel_type
)) {
126 return NT_STATUS_UNSUCCESSFUL
;
129 ret
= cli_nt_setup_netsec(cli
, sec_channel_type
,
130 AUTH_PIPE_NETSEC
| AUTH_PIPE_SIGN
,
136 /* Open a connction to the remote server, cache failures for 30 seconds */
138 static NTSTATUS
cm_open_connection(const struct winbindd_domain
*domain
, const int pipe_index
,
139 struct winbindd_cm_conn
*new_conn
)
142 char *machine_password
;
143 char *machine_krb5_principal
, *ipc_username
, *ipc_domain
, *ipc_password
;
144 struct in_addr dc_ip
;
150 fstrcpy(new_conn
->domain
, domain
->name
);
152 /* connection failure cache has been moved inside of get_dc_name
153 so we can deal with half dead DC's --jerry */
155 if (!get_dc_name(domain
->name
, domain
->alt_name
[0] ? domain
->alt_name
: NULL
,
156 new_conn
->controller
, &dc_ip
)) {
157 result
= NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
;
158 add_failed_connection_entry(domain
->name
, "", result
);
162 /* Initialise SMB connection */
163 fstrcpy(new_conn
->pipe_name
, get_pipe_name_from_index(pipe_index
));
165 /* grab stored passwords */
166 machine_password
= secrets_fetch_machine_password(lp_workgroup(), NULL
, NULL
);
168 if (asprintf(&machine_krb5_principal
, "%s$@%s", global_myname(), lp_realm()) == -1) {
169 SAFE_FREE(machine_password
);
170 return NT_STATUS_NO_MEMORY
;
173 cm_get_ipc_userpass(&ipc_username
, &ipc_domain
, &ipc_password
);
175 for (i
= 0; retry
&& (i
< 3); i
++) {
177 if (!(got_mutex
= secrets_named_mutex(new_conn
->controller
, WINBIND_SERVER_MUTEX_WAIT_TIME
))) {
178 DEBUG(0,("cm_open_connection: mutex grab failed for %s\n", new_conn
->controller
));
179 result
= NT_STATUS_POSSIBLE_DEADLOCK
;
183 new_conn
->cli
= NULL
;
184 result
= cli_start_connection(&new_conn
->cli
, global_myname(),
185 new_conn
->controller
,
186 &dc_ip
, 0, Undefined
,
187 CLI_FULL_CONNECTION_USE_KERBEROS
,
190 if (NT_STATUS_IS_OK(result
)) {
192 /* reset the error code */
193 result
= NT_STATUS_UNSUCCESSFUL
;
197 if ((lp_security() == SEC_ADS
)
198 && (new_conn
->cli
->protocol
>= PROTOCOL_NT1
&& new_conn
->cli
->capabilities
& CAP_EXTENDED_SECURITY
)) {
199 ADS_STATUS ads_status
;
200 new_conn
->cli
->use_kerberos
= True
;
201 DEBUG(5, ("connecting to %s from %s with kerberos principal [%s]\n",
202 new_conn
->controller
, global_myname(), machine_krb5_principal
));
204 ads_status
= cli_session_setup_spnego(new_conn
->cli
, machine_krb5_principal
,
207 if (!ADS_ERR_OK(ads_status
)) {
208 DEBUG(4,("failed kerberos session setup with %s\n", ads_errstr(ads_status
)));
209 result
= ads_ntstatus(ads_status
);
211 result
= NT_STATUS_OK
;
214 new_conn
->cli
->use_kerberos
= False
;
216 /* only do this is we have a username/password for thr IPC$ connection */
218 if ( !NT_STATUS_IS_OK(result
)
219 && new_conn
->cli
->sec_mode
& NEGOTIATE_SECURITY_CHALLENGE_RESPONSE
220 && strlen(ipc_username
) )
222 DEBUG(5, ("connecting to %s from %s with username [%s]\\[%s]\n",
223 new_conn
->controller
, global_myname(), ipc_domain
, ipc_username
));
225 result
= NT_STATUS_OK
;
227 if (!cli_session_setup(new_conn
->cli
, ipc_username
,
228 ipc_password
, strlen(ipc_password
)+1,
229 ipc_password
, strlen(ipc_password
)+1,
231 result
= cli_nt_error(new_conn
->cli
);
232 DEBUG(4,("failed authenticated session setup with %s\n", nt_errstr(result
)));
233 if (NT_STATUS_IS_OK(result
))
234 result
= NT_STATUS_UNSUCCESSFUL
;
238 /* anonymous is all that is left if we get to here */
240 if (!NT_STATUS_IS_OK(result
)) {
242 DEBUG(5, ("anonymous connection attempt to %s from %s\n",
243 new_conn
->controller
, global_myname()));
245 result
= NT_STATUS_OK
;
247 if (!cli_session_setup(new_conn
->cli
, "", NULL
, 0, NULL
, 0, ""))
249 result
= cli_nt_error(new_conn
->cli
);
250 DEBUG(4,("failed anonymous session setup with %s\n", nt_errstr(result
)));
251 if (NT_STATUS_IS_OK(result
))
252 result
= NT_STATUS_UNSUCCESSFUL
;
257 if (NT_STATUS_IS_OK(result
) && !cli_send_tconX(new_conn
->cli
, "IPC$", "IPC",
259 result
= cli_nt_error(new_conn
->cli
);
260 DEBUG(1,("failed tcon_X with %s\n", nt_errstr(result
)));
261 cli_shutdown(new_conn
->cli
);
262 if (NT_STATUS_IS_OK(result
)) {
263 result
= NT_STATUS_UNSUCCESSFUL
;
268 if (NT_STATUS_IS_OK(result
)) {
269 struct ntuser_creds creds
;
270 init_creds(&creds
, ipc_username
, ipc_domain
, ipc_password
);
271 cli_init_creds(new_conn
->cli
, &creds
);
275 secrets_named_mutex_release(new_conn
->controller
);
277 if (NT_STATUS_IS_OK(result
))
281 /* try and use schannel if possible, but continue anyway if it
282 failed. This allows existing setups to continue working,
283 while solving the win2003 '100 user' limit for systems that
284 are joined properly */
285 if (NT_STATUS_IS_OK(result
)) {
286 NTSTATUS status
= setup_schannel(new_conn
->cli
);
287 if (!NT_STATUS_IS_OK(status
)) {
288 DEBUG(3,("schannel refused - continuing without schannel (%s)\n",
293 SAFE_FREE(ipc_username
);
294 SAFE_FREE(ipc_domain
);
295 SAFE_FREE(ipc_password
);
296 SAFE_FREE(machine_password
);
298 if (!NT_STATUS_IS_OK(result
)) {
299 add_failed_connection_entry(domain
->name
, new_conn
->controller
, result
);
303 /* set the domain if empty; needed for schannel connections */
304 if ( !*new_conn
->cli
->domain
)
305 fstrcpy( new_conn
->cli
->domain
, domain
->name
);
308 if ( !cli_nt_session_open (new_conn
->cli
, pipe_index
) ) {
309 result
= NT_STATUS_PIPE_NOT_AVAILABLE
;
311 * only cache a failure if we are not trying to open the
312 * **win2k** specific lsarpc UUID. This could be an NT PDC
313 * and therefore a failure is normal. This should probably
314 * be abstracted to a check for 2k specific pipes and wondering
315 * if the PDC is an NT4 box. but since there is only one 2k
316 * specific UUID right now, i'm not going to bother. --jerry
318 if ( !is_win2k_pipe(pipe_index
) )
319 add_failed_connection_entry(domain
->name
, new_conn
->controller
, result
);
320 cli_shutdown(new_conn
->cli
);
327 /************************************************************************
328 Wrapper around statuc cm_open_connection to retreive a freshly
329 setup cli_state struct
330 ************************************************************************/
332 NTSTATUS
cm_fresh_connection(struct winbindd_domain
*domain
, const int pipe_index
,
333 struct cli_state
**cli
)
336 struct winbindd_cm_conn conn
;
338 result
= cm_open_connection( domain
, pipe_index
, &conn
);
340 if ( NT_STATUS_IS_OK(result
) )
346 /* Return true if a connection is still alive */
348 static BOOL
connection_ok(struct winbindd_cm_conn
*conn
)
351 smb_panic("Invalid parameter passed to connection_ok(): conn was NULL!\n");
356 DEBUG(3, ("Connection to %s for domain %s (pipe %s) has NULL conn->cli!\n",
357 conn
->controller
, conn
->domain
, conn
->pipe_name
));
361 if (!conn
->cli
->initialised
) {
362 DEBUG(3, ("Connection to %s for domain %s (pipe %s) was never initialised!\n",
363 conn
->controller
, conn
->domain
, conn
->pipe_name
));
367 if (conn
->cli
->fd
== -1) {
368 DEBUG(3, ("Connection to %s for domain %s (pipe %s) has died or was never started (fd == -1)\n",
369 conn
->controller
, conn
->domain
, conn
->pipe_name
));
376 /* Search the cache for a connection. If there is a broken one,
377 shut it down properly and return NULL. */
379 static void find_cm_connection(struct winbindd_domain
*domain
, const char *pipe_name
,
380 struct winbindd_cm_conn
**conn_out
)
382 struct winbindd_cm_conn
*conn
;
384 for (conn
= cm_conns
; conn
; ) {
385 if (strequal(conn
->domain
, domain
->name
) &&
386 strequal(conn
->pipe_name
, pipe_name
)) {
387 if (!connection_ok(conn
)) {
388 /* Dead connection - remove it. */
389 struct winbindd_cm_conn
*conn_temp
= conn
->next
;
391 cli_shutdown(conn
->cli
);
392 DLIST_REMOVE(cm_conns
, conn
);
394 conn
= conn_temp
; /* Keep the loop moving */
406 /* Initialize a new connection up to the RPC BIND. */
408 static NTSTATUS
new_cm_connection(struct winbindd_domain
*domain
, const char *pipe_name
,
409 struct winbindd_cm_conn
**conn_out
)
411 struct winbindd_cm_conn
*conn
;
414 if (!(conn
= malloc(sizeof(*conn
))))
415 return NT_STATUS_NO_MEMORY
;
419 if (!NT_STATUS_IS_OK(result
= cm_open_connection(domain
, get_pipe_index(pipe_name
), conn
))) {
420 DEBUG(3, ("Could not open a connection to %s for %s (%s)\n",
421 domain
->name
, pipe_name
, nt_errstr(result
)));
425 DLIST_ADD(cm_conns
, conn
);
431 /* Get a connection to the remote DC and open the pipe. If there is already a connection, use that */
433 static NTSTATUS
get_connection_from_cache(struct winbindd_domain
*domain
, const char *pipe_name
,
434 struct winbindd_cm_conn
**conn_out
)
436 find_cm_connection(domain
, pipe_name
, conn_out
);
438 if (*conn_out
!= NULL
)
441 return new_cm_connection(domain
, pipe_name
, conn_out
);
444 /**********************************************************************************
445 We can 'sense' certain things about the DC by it's replies to certain questions.
447 This tells us if this particular remote server is Active Directory, and if it is
449 **********************************************************************************/
451 void set_dc_type_and_flags( struct winbindd_domain
*domain
)
454 struct winbindd_cm_conn conn
;
456 TALLOC_CTX
*mem_ctx
= NULL
;
461 domain
->native_mode
= False
;
462 domain
->active_directory
= False
;
464 if ( !NT_STATUS_IS_OK(result
= cm_open_connection(domain
, PI_LSARPC_DS
, &conn
)) ) {
465 DEBUG(5, ("set_dc_type_and_flags: Could not open a connection to %s for PIPE_LSARPC (%s)\n",
466 domain
->name
, nt_errstr(result
)));
471 if ( !NT_STATUS_IS_OK(cli_ds_getprimarydominfo( conn
.cli
,
472 conn
.cli
->mem_ctx
, DsRolePrimaryDomainInfoBasic
, &ctr
)) ) {
477 if ( (ctr
.basic
->flags
& DSROLE_PRIMARY_DS_RUNNING
)
478 && !(ctr
.basic
->flags
& DSROLE_PRIMARY_DS_MIXED_MODE
) )
479 domain
->native_mode
= True
;
481 /* Cheat - shut down the DS pipe, and open LSA */
483 cli_nt_session_close(conn
.cli
);
485 if ( cli_nt_session_open (conn
.cli
, PI_LSARPC
) ) {
486 char *domain_name
= NULL
;
487 char *dns_name
= NULL
;
488 DOM_SID
*dom_sid
= NULL
;
490 mem_ctx
= talloc_init("set_dc_type_and_flags on domain %s\n", domain
->name
);
492 DEBUG(1, ("set_dc_type_and_flags: talloc_init() failed\n"));
496 result
= cli_lsa_open_policy2(conn
.cli
, mem_ctx
, True
,
497 SEC_RIGHTS_MAXIMUM_ALLOWED
,
500 if (NT_STATUS_IS_OK(result
)) {
501 /* This particular query is exactly what Win2k clients use
502 to determine that the DC is active directory */
503 result
= cli_lsa_query_info_policy2(conn
.cli
, mem_ctx
,
510 if (NT_STATUS_IS_OK(result
)) {
512 fstrcpy(domain
->name
, domain_name
);
515 fstrcpy(domain
->alt_name
, dns_name
);
518 sid_copy(&domain
->sid
, dom_sid
);
520 domain
->active_directory
= True
;
523 result
= cli_lsa_open_policy(conn
.cli
, mem_ctx
, True
,
524 SEC_RIGHTS_MAXIMUM_ALLOWED
,
527 if (!NT_STATUS_IS_OK(result
))
530 result
= cli_lsa_query_info_policy(conn
.cli
, mem_ctx
,
531 &conn
.pol
, 5, &domain_name
,
534 if (NT_STATUS_IS_OK(result
)) {
536 fstrcpy(domain
->name
, domain_name
);
539 sid_copy(&domain
->sid
, dom_sid
);
546 /* close the connection; no other calls use this pipe and it is called only
547 on reestablishing the domain list --jerry */
550 cli_shutdown( conn
.cli
);
552 talloc_destroy(mem_ctx
);
559 /* Return a LSA policy handle on a domain */
561 NTSTATUS
cm_get_lsa_handle(struct winbindd_domain
*domain
, CLI_POLICY_HND
**return_hnd
)
563 struct winbindd_cm_conn
*conn
;
564 uint32 des_access
= SEC_RIGHTS_MAXIMUM_ALLOWED
;
566 static CLI_POLICY_HND hnd
;
568 /* Look for existing connections */
570 if (!NT_STATUS_IS_OK(result
= get_connection_from_cache(domain
, PIPE_LSARPC
, &conn
)))
573 /* This *shitty* code needs scrapping ! JRA */
575 if (policy_handle_is_valid(&conn
->pol
)) {
583 result
= cli_lsa_open_policy(conn
->cli
, conn
->cli
->mem_ctx
, False
,
584 des_access
, &conn
->pol
);
586 if (!NT_STATUS_IS_OK(result
)) {
587 /* Hit the cache code again. This cleans out the old connection and gets a new one */
588 if (conn
->cli
->fd
== -1) { /* Try again, if the remote host disapeared */
589 if (!NT_STATUS_IS_OK(result
= get_connection_from_cache(domain
, PIPE_LSARPC
, &conn
)))
592 result
= cli_lsa_open_policy(conn
->cli
, conn
->cli
->mem_ctx
, False
,
593 des_access
, &conn
->pol
);
596 if (!NT_STATUS_IS_OK(result
)) {
597 cli_shutdown(conn
->cli
);
598 DLIST_REMOVE(cm_conns
, conn
);
612 /* Return a SAM policy handle on a domain */
614 NTSTATUS
cm_get_sam_handle(struct winbindd_domain
*domain
, CLI_POLICY_HND
**return_hnd
)
616 struct winbindd_cm_conn
*conn
;
617 uint32 des_access
= SEC_RIGHTS_MAXIMUM_ALLOWED
;
619 static CLI_POLICY_HND hnd
;
621 /* Look for existing connections */
623 if (!NT_STATUS_IS_OK(result
= get_connection_from_cache(domain
, PIPE_SAMR
, &conn
)))
626 /* This *shitty* code needs scrapping ! JRA */
628 if (policy_handle_is_valid(&conn
->pol
)) {
637 result
= cli_samr_connect(conn
->cli
, conn
->cli
->mem_ctx
,
638 des_access
, &conn
->pol
);
640 if (!NT_STATUS_IS_OK(result
)) {
641 /* Hit the cache code again. This cleans out the old connection and gets a new one */
642 if (conn
->cli
->fd
== -1) { /* Try again, if the remote host disapeared */
644 if (!NT_STATUS_IS_OK(result
= get_connection_from_cache(domain
, PIPE_SAMR
, &conn
)))
647 result
= cli_samr_connect(conn
->cli
, conn
->cli
->mem_ctx
,
648 des_access
, &conn
->pol
);
651 if (!NT_STATUS_IS_OK(result
)) {
653 cli_shutdown(conn
->cli
);
654 DLIST_REMOVE(cm_conns
, conn
);
669 /* Get a handle on a netlogon pipe. This is a bit of a hack to re-use the
670 netlogon pipe as no handle is returned. */
672 NTSTATUS
cm_get_netlogon_cli(struct winbindd_domain
*domain
,
673 const unsigned char *trust_passwd
,
674 uint32 sec_channel_type
,
676 struct cli_state
**cli
)
678 NTSTATUS result
= NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
;
679 struct winbindd_cm_conn
*conn
;
684 return NT_STATUS_INVALID_PARAMETER
;
686 /* Open an initial conection - keep the mutex. */
688 find_cm_connection(domain
, PIPE_NETLOGON
, &conn
);
690 if ( fresh
&& (conn
!= NULL
) ) {
691 cli_shutdown(conn
->cli
);
696 /* purge connection from cache */
697 find_cm_connection(domain
, PIPE_NETLOGON
, &conn
);
699 DEBUG(0,("Could not purge connection\n"));
700 return NT_STATUS_UNSUCCESSFUL
;
709 result
= new_cm_connection(domain
, PIPE_NETLOGON
, &conn
);
711 if (!NT_STATUS_IS_OK(result
))
714 fstr_sprintf(lock_name
, "NETLOGON\\%s", conn
->controller
);
716 if (!(got_mutex
= secrets_named_mutex(lock_name
, WINBIND_SERVER_MUTEX_WAIT_TIME
))) {
717 DEBUG(0,("cm_get_netlogon_cli: mutex grab failed for %s\n", conn
->controller
));
720 if ( sec_channel_type
== SEC_CHAN_DOMAIN
)
721 fstr_sprintf(conn
->cli
->mach_acct
, "%s$", lp_workgroup());
723 /* This must be the remote domain (not ours) for schannel */
725 fstrcpy( conn
->cli
->domain
, domain
->name
);
727 result
= cli_nt_establish_netlogon(conn
->cli
, sec_channel_type
, trust_passwd
);
730 secrets_named_mutex_release(lock_name
);
732 if (!NT_STATUS_IS_OK(result
)) {
733 cli_shutdown(conn
->cli
);
734 DLIST_REMOVE(cm_conns
, conn
);
744 /* Dump the current connection status */
746 static void dump_conn_list(void)
748 struct winbindd_cm_conn
*con
;
750 DEBUG(0, ("\tDomain Controller Pipe\n"));
752 for(con
= cm_conns
; con
; con
= con
->next
) {
755 /* Display pipe info */
757 if (asprintf(&msg
, "\t%-15s %-15s %-16s", con
->domain
, con
->controller
, con
->pipe_name
) < 0) {
758 DEBUG(0, ("Error: not enough memory!\n"));
760 DEBUG(0, ("%s\n", msg
));
766 void winbindd_cm_status(void)
768 /* List open connections */
770 DEBUG(0, ("winbindd connection manager status:\n"));
775 DEBUG(0, ("\tNo active connections\n"));
778 /* Close all cached connections */
780 void winbindd_cm_flush(void)
782 struct winbindd_cm_conn
*conn
, tmp
;
784 /* Flush connection cache */
786 for (conn
= cm_conns
; conn
; conn
= conn
->next
) {
788 if (!connection_ok(conn
))
791 DEBUG(10, ("Closing connection to %s on %s\n",
792 conn
->pipe_name
, conn
->controller
));
795 cli_shutdown(conn
->cli
);
797 tmp
.next
= conn
->next
;
799 DLIST_REMOVE(cm_conns
, conn
);
804 /* Flush failed connection cache */
806 flush_negative_conn_cache();