mirror of
https://github.com/samba-team/samba.git
synced 2024-12-24 21:34:56 +03:00
Fixed up mutex protection around winbindd logon code. Sync with APP-HEAD.
Jeremy.
This commit is contained in:
parent
f6121fb55b
commit
daf179bcd6
@ -216,4 +216,12 @@
|
|||||||
/* Max number of open RPC pipes. */
|
/* Max number of open RPC pipes. */
|
||||||
#define MAX_OPEN_PIPES 2048
|
#define MAX_OPEN_PIPES 2048
|
||||||
|
|
||||||
|
/* Tuning for server auth mutex. */
|
||||||
|
#define CLI_AUTH_TIMEOUT 5000 /* In milli-seconds. */
|
||||||
|
#define NUM_CLI_AUTH_CONNECT_RETRIES 3
|
||||||
|
/* Number in seconds to wait for the mutex. This must be less than 30 seconds. */
|
||||||
|
#define SERVER_MUTEX_WAIT_TIME ( ((NUM_CLI_AUTH_CONNECT_RETRIES) * ((CLI_AUTH_TIMEOUT)/1000)) + 5)
|
||||||
|
/* Number in seconds for winbindd to wait for the mutex. Make this 2 * smbd wait time. */
|
||||||
|
#define WINBIND_SERVER_MUTEX_WAIT_TIME (( ((NUM_CLI_AUTH_CONNECT_RETRIES) * ((CLI_AUTH_TIMEOUT)/1000)) + 5)*2)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -30,6 +30,8 @@
|
|||||||
like the single-connection that NT makes. */
|
like the single-connection that NT makes. */
|
||||||
|
|
||||||
static char *mutex_server_name;
|
static char *mutex_server_name;
|
||||||
|
/* FIXME. ref_count should be allocated per name... JRA. */
|
||||||
|
size_t ref_count;
|
||||||
|
|
||||||
BOOL grab_server_mutex(const char *name)
|
BOOL grab_server_mutex(const char *name)
|
||||||
{
|
{
|
||||||
@ -38,7 +40,7 @@ BOOL grab_server_mutex(const char *name)
|
|||||||
DEBUG(0,("grab_server_mutex: malloc failed for %s\n", name));
|
DEBUG(0,("grab_server_mutex: malloc failed for %s\n", name));
|
||||||
return False;
|
return False;
|
||||||
}
|
}
|
||||||
if (!secrets_named_mutex(mutex_server_name, 10)) {
|
if (!secrets_named_mutex(mutex_server_name, 10, &ref_count)) {
|
||||||
DEBUG(10,("grab_server_mutex: failed for %s\n", name));
|
DEBUG(10,("grab_server_mutex: failed for %s\n", name));
|
||||||
SAFE_FREE(mutex_server_name);
|
SAFE_FREE(mutex_server_name);
|
||||||
return False;
|
return False;
|
||||||
@ -50,7 +52,7 @@ BOOL grab_server_mutex(const char *name)
|
|||||||
void release_server_mutex(void)
|
void release_server_mutex(void)
|
||||||
{
|
{
|
||||||
if (mutex_server_name) {
|
if (mutex_server_name) {
|
||||||
secrets_named_mutex_release(mutex_server_name);
|
secrets_named_mutex_release(mutex_server_name, &ref_count);
|
||||||
SAFE_FREE(mutex_server_name);
|
SAFE_FREE(mutex_server_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -72,6 +72,7 @@ struct winbindd_cm_conn {
|
|||||||
fstring domain;
|
fstring domain;
|
||||||
fstring controller;
|
fstring controller;
|
||||||
fstring pipe_name;
|
fstring pipe_name;
|
||||||
|
size_t mutex_ref_count;
|
||||||
struct cli_state *cli;
|
struct cli_state *cli;
|
||||||
POLICY_HND pol;
|
POLICY_HND pol;
|
||||||
};
|
};
|
||||||
@ -301,7 +302,7 @@ static void add_failed_connection_entry(struct winbindd_cm_conn *new_conn,
|
|||||||
/* Open a connction to the remote server, cache failures for 30 seconds */
|
/* Open a connction to the remote server, cache failures for 30 seconds */
|
||||||
|
|
||||||
static NTSTATUS cm_open_connection(const char *domain, const int pipe_index,
|
static NTSTATUS cm_open_connection(const char *domain, const int pipe_index,
|
||||||
struct winbindd_cm_conn *new_conn)
|
struct winbindd_cm_conn *new_conn, BOOL keep_mutex)
|
||||||
{
|
{
|
||||||
struct failed_connection_cache *fcc;
|
struct failed_connection_cache *fcc;
|
||||||
NTSTATUS result;
|
NTSTATUS result;
|
||||||
@ -309,6 +310,7 @@ static NTSTATUS cm_open_connection(const char *domain, const int pipe_index,
|
|||||||
struct in_addr dc_ip;
|
struct in_addr dc_ip;
|
||||||
int i;
|
int i;
|
||||||
BOOL retry = True;
|
BOOL retry = True;
|
||||||
|
BOOL got_mutex = False;
|
||||||
|
|
||||||
ZERO_STRUCT(dc_ip);
|
ZERO_STRUCT(dc_ip);
|
||||||
|
|
||||||
@ -365,12 +367,23 @@ static NTSTATUS cm_open_connection(const char *domain, const int pipe_index,
|
|||||||
|
|
||||||
for (i = 0; retry && (i < 3); i++) {
|
for (i = 0; retry && (i < 3); i++) {
|
||||||
|
|
||||||
|
if (!secrets_named_mutex(new_conn->controller, WINBIND_SERVER_MUTEX_WAIT_TIME, &new_conn->mutex_ref_count)) {
|
||||||
|
DEBUG(0,("cm_open_connection: mutex grab failed for %s\n", new_conn->controller));
|
||||||
|
result = NT_STATUS_POSSIBLE_DEADLOCK;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
got_mutex = True;
|
||||||
|
|
||||||
result = cli_full_connection(&new_conn->cli, global_myname(), new_conn->controller,
|
result = cli_full_connection(&new_conn->cli, global_myname(), new_conn->controller,
|
||||||
&dc_ip, 0, "IPC$", "IPC", ipc_username, ipc_domain,
|
&dc_ip, 0, "IPC$", "IPC", ipc_username, ipc_domain,
|
||||||
ipc_password, 0, &retry);
|
ipc_password, 0, &retry);
|
||||||
|
|
||||||
if (NT_STATUS_IS_OK(result))
|
if (NT_STATUS_IS_OK(result))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
secrets_named_mutex_release(new_conn->controller, &new_conn->mutex_ref_count);
|
||||||
|
got_mutex = False;
|
||||||
}
|
}
|
||||||
|
|
||||||
SAFE_FREE(ipc_username);
|
SAFE_FREE(ipc_username);
|
||||||
@ -378,6 +391,8 @@ static NTSTATUS cm_open_connection(const char *domain, const int pipe_index,
|
|||||||
SAFE_FREE(ipc_password);
|
SAFE_FREE(ipc_password);
|
||||||
|
|
||||||
if (!NT_STATUS_IS_OK(result)) {
|
if (!NT_STATUS_IS_OK(result)) {
|
||||||
|
if (got_mutex)
|
||||||
|
secrets_named_mutex_release(new_conn->controller, &new_conn->mutex_ref_count);
|
||||||
add_failed_connection_entry(new_conn, result);
|
add_failed_connection_entry(new_conn, result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -392,12 +407,16 @@ static NTSTATUS cm_open_connection(const char *domain, const int pipe_index,
|
|||||||
* if the PDC is an NT4 box. but since there is only one 2k
|
* if the PDC is an NT4 box. but since there is only one 2k
|
||||||
* specific UUID right now, i'm not going to bother. --jerry
|
* specific UUID right now, i'm not going to bother. --jerry
|
||||||
*/
|
*/
|
||||||
|
if (got_mutex)
|
||||||
|
secrets_named_mutex_release(new_conn->controller, &new_conn->mutex_ref_count);
|
||||||
if ( !is_win2k_pipe(pipe_index) )
|
if ( !is_win2k_pipe(pipe_index) )
|
||||||
add_failed_connection_entry(new_conn, result);
|
add_failed_connection_entry(new_conn, result);
|
||||||
cli_shutdown(new_conn->cli);
|
cli_shutdown(new_conn->cli);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((got_mutex) && !keep_mutex)
|
||||||
|
secrets_named_mutex_release(new_conn->controller, &new_conn->mutex_ref_count);
|
||||||
return NT_STATUS_OK;
|
return NT_STATUS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -435,7 +454,8 @@ static BOOL connection_ok(struct winbindd_cm_conn *conn)
|
|||||||
|
|
||||||
/* Get a connection to the remote DC and open the pipe. If there is already a connection, use that */
|
/* Get a connection to the remote DC and open the pipe. If there is already a connection, use that */
|
||||||
|
|
||||||
static NTSTATUS get_connection_from_cache(const char *domain, const char *pipe_name, struct winbindd_cm_conn **conn_out)
|
static NTSTATUS get_connection_from_cache(const char *domain, const char *pipe_name,
|
||||||
|
struct winbindd_cm_conn **conn_out, BOOL keep_mutex)
|
||||||
{
|
{
|
||||||
struct winbindd_cm_conn *conn, conn_temp;
|
struct winbindd_cm_conn *conn, conn_temp;
|
||||||
NTSTATUS result;
|
NTSTATUS result;
|
||||||
@ -452,6 +472,12 @@ static NTSTATUS get_connection_from_cache(const char *domain, const char *pipe_n
|
|||||||
SAFE_FREE(conn);
|
SAFE_FREE(conn);
|
||||||
conn = &conn_temp; /* Just to keep the loop moving */
|
conn = &conn_temp; /* Just to keep the loop moving */
|
||||||
} else {
|
} else {
|
||||||
|
if (keep_mutex) {
|
||||||
|
if (!secrets_named_mutex(conn->controller,
|
||||||
|
WINBIND_SERVER_MUTEX_WAIT_TIME, &conn->mutex_ref_count))
|
||||||
|
DEBUG(0,("get_connection_from_cache: mutex grab failed for %s\n",
|
||||||
|
conn->controller));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -463,7 +489,7 @@ static NTSTATUS get_connection_from_cache(const char *domain, const char *pipe_n
|
|||||||
|
|
||||||
ZERO_STRUCTP(conn);
|
ZERO_STRUCTP(conn);
|
||||||
|
|
||||||
if (!NT_STATUS_IS_OK(result = cm_open_connection(domain, get_pipe_index(pipe_name), conn))) {
|
if (!NT_STATUS_IS_OK(result = cm_open_connection(domain, get_pipe_index(pipe_name), conn, keep_mutex))) {
|
||||||
DEBUG(3, ("Could not open a connection to %s for %s (%s)\n",
|
DEBUG(3, ("Could not open a connection to %s for %s (%s)\n",
|
||||||
domain, pipe_name, nt_errstr(result)));
|
domain, pipe_name, nt_errstr(result)));
|
||||||
SAFE_FREE(conn);
|
SAFE_FREE(conn);
|
||||||
@ -491,7 +517,7 @@ BOOL cm_check_for_native_mode_win2k( const char *domain )
|
|||||||
ZERO_STRUCT( ctr );
|
ZERO_STRUCT( ctr );
|
||||||
|
|
||||||
|
|
||||||
if ( !NT_STATUS_IS_OK(result = cm_open_connection(domain, PI_LSARPC_DS, &conn)) ) {
|
if ( !NT_STATUS_IS_OK(result = cm_open_connection(domain, PI_LSARPC_DS, &conn, False)) ) {
|
||||||
DEBUG(5, ("cm_check_for_native_mode_win2k: Could not open a connection to %s for PIPE_LSARPC (%s)\n",
|
DEBUG(5, ("cm_check_for_native_mode_win2k: Could not open a connection to %s for PIPE_LSARPC (%s)\n",
|
||||||
domain, nt_errstr(result)));
|
domain, nt_errstr(result)));
|
||||||
return False;
|
return False;
|
||||||
@ -529,7 +555,7 @@ CLI_POLICY_HND *cm_get_lsa_handle(const char *domain)
|
|||||||
|
|
||||||
/* Look for existing connections */
|
/* Look for existing connections */
|
||||||
|
|
||||||
if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_LSARPC, &conn)))
|
if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_LSARPC, &conn, False)))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* This *shitty* code needs scrapping ! JRA */
|
/* This *shitty* code needs scrapping ! JRA */
|
||||||
@ -545,7 +571,7 @@ CLI_POLICY_HND *cm_get_lsa_handle(const char *domain)
|
|||||||
if (!NT_STATUS_IS_OK(result)) {
|
if (!NT_STATUS_IS_OK(result)) {
|
||||||
/* Hit the cache code again. This cleans out the old connection and gets a new one */
|
/* Hit the cache code again. This cleans out the old connection and gets a new one */
|
||||||
if (conn->cli->fd == -1) { /* Try again, if the remote host disapeared */
|
if (conn->cli->fd == -1) { /* Try again, if the remote host disapeared */
|
||||||
if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_LSARPC, &conn)))
|
if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_LSARPC, &conn, False)))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
result = cli_lsa_open_policy(conn->cli, conn->cli->mem_ctx, False,
|
result = cli_lsa_open_policy(conn->cli, conn->cli->mem_ctx, False,
|
||||||
@ -577,7 +603,7 @@ CLI_POLICY_HND *cm_get_sam_handle(char *domain)
|
|||||||
|
|
||||||
/* Look for existing connections */
|
/* Look for existing connections */
|
||||||
|
|
||||||
if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_SAMR, &conn)))
|
if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_SAMR, &conn, False)))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* This *shitty* code needs scrapping ! JRA */
|
/* This *shitty* code needs scrapping ! JRA */
|
||||||
@ -592,7 +618,7 @@ CLI_POLICY_HND *cm_get_sam_handle(char *domain)
|
|||||||
if (!NT_STATUS_IS_OK(result)) {
|
if (!NT_STATUS_IS_OK(result)) {
|
||||||
/* Hit the cache code again. This cleans out the old connection and gets a new one */
|
/* Hit the cache code again. This cleans out the old connection and gets a new one */
|
||||||
if (conn->cli->fd == -1) { /* Try again, if the remote host disapeared */
|
if (conn->cli->fd == -1) { /* Try again, if the remote host disapeared */
|
||||||
if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_SAMR, &conn)))
|
if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_SAMR, &conn, False)))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
result = cli_samr_connect(conn->cli, conn->cli->mem_ctx,
|
result = cli_samr_connect(conn->cli, conn->cli->mem_ctx,
|
||||||
@ -849,28 +875,19 @@ NTSTATUS cm_get_netlogon_cli(const char *domain, const unsigned char *trust_pass
|
|||||||
NTSTATUS result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
|
NTSTATUS result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
|
||||||
struct winbindd_cm_conn *conn;
|
struct winbindd_cm_conn *conn;
|
||||||
uint32 neg_flags = 0x000001ff;
|
uint32 neg_flags = 0x000001ff;
|
||||||
fstring srv_name;
|
|
||||||
struct in_addr dc_ip;
|
|
||||||
|
|
||||||
if (!cli)
|
if (!cli)
|
||||||
return NT_STATUS_INVALID_PARAMETER;
|
return NT_STATUS_INVALID_PARAMETER;
|
||||||
|
|
||||||
if (!cm_get_dc_name(domain, srv_name, &dc_ip))
|
/* Open an initial conection - keep the mutex. */
|
||||||
return NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
|
|
||||||
|
|
||||||
if (!secrets_named_mutex(srv_name, 10)) {
|
if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_NETLOGON, &conn, True)))
|
||||||
DEBUG(0,("cm_get_netlogon_cli: mutex grab failed for %s\n", srv_name));
|
|
||||||
return NT_STATUS_POSSIBLE_DEADLOCK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Open an initial conection */
|
|
||||||
|
|
||||||
if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_NETLOGON, &conn)))
|
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
result = cli_nt_setup_creds(conn->cli, get_sec_chan(), trust_passwd, &neg_flags, 2);
|
result = cli_nt_setup_creds(conn->cli, get_sec_chan(), trust_passwd, &neg_flags, 2);
|
||||||
|
|
||||||
secrets_named_mutex_release(srv_name);
|
if (conn->mutex_ref_count)
|
||||||
|
secrets_named_mutex_release(conn->controller, &conn->mutex_ref_count);
|
||||||
|
|
||||||
if (!NT_STATUS_IS_OK(result)) {
|
if (!NT_STATUS_IS_OK(result)) {
|
||||||
DEBUG(0, ("error connecting to domain password server: %s\n",
|
DEBUG(0, ("error connecting to domain password server: %s\n",
|
||||||
@ -879,18 +896,14 @@ NTSTATUS cm_get_netlogon_cli(const char *domain, const unsigned char *trust_pass
|
|||||||
/* Hit the cache code again. This cleans out the old connection and gets a new one */
|
/* Hit the cache code again. This cleans out the old connection and gets a new one */
|
||||||
if (conn->cli->fd == -1) {
|
if (conn->cli->fd == -1) {
|
||||||
|
|
||||||
if (!secrets_named_mutex(srv_name, 10)) {
|
if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_NETLOGON, &conn, True)))
|
||||||
DEBUG(0,("cm_get_netlogon_cli: mutex grab failed for %s\n", srv_name));
|
|
||||||
return NT_STATUS_POSSIBLE_DEADLOCK;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_NETLOGON, &conn)))
|
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
/* Try again */
|
/* Try again */
|
||||||
result = cli_nt_setup_creds( conn->cli, get_sec_chan(),trust_passwd, &neg_flags, 2);
|
result = cli_nt_setup_creds( conn->cli, get_sec_chan(),trust_passwd, &neg_flags, 2);
|
||||||
|
|
||||||
secrets_named_mutex_release(srv_name);
|
if (conn->mutex_ref_count)
|
||||||
|
secrets_named_mutex_release(conn->controller, &conn->mutex_ref_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!NT_STATUS_IS_OK(result)) {
|
if (!NT_STATUS_IS_OK(result)) {
|
||||||
|
@ -588,17 +588,24 @@ NTSTATUS secrets_get_trusted_domains(TALLOC_CTX* ctx, int* enum_ctx, int max_num
|
|||||||
between smbd instances.
|
between smbd instances.
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
BOOL secrets_named_mutex(const char *name, unsigned int timeout)
|
BOOL secrets_named_mutex(const char *name, unsigned int timeout, size_t *p_ref_count)
|
||||||
{
|
{
|
||||||
int ret;
|
size_t ref_count = *p_ref_count;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
if (!message_init())
|
if (!message_init())
|
||||||
return False;
|
return False;
|
||||||
|
|
||||||
ret = tdb_lock_bystring(tdb, name, timeout);
|
if (ref_count == 0) {
|
||||||
if (ret == 0)
|
ret = tdb_lock_bystring(tdb, name, timeout);
|
||||||
DEBUG(10,("secrets_named_mutex: got mutex for %s\n", name ));
|
if (ret == 0)
|
||||||
|
DEBUG(10,("secrets_named_mutex: got mutex for %s\n", name ));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret == 0) {
|
||||||
|
*p_ref_count = ++ref_count;
|
||||||
|
DEBUG(10,("secrets_named_mutex: ref_count for mutex %s = %u\n", name, (unsigned int)ref_count ));
|
||||||
|
}
|
||||||
return (ret == 0);
|
return (ret == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -606,10 +613,19 @@ BOOL secrets_named_mutex(const char *name, unsigned int timeout)
|
|||||||
Unlock a named mutex.
|
Unlock a named mutex.
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
void secrets_named_mutex_release(const char *name)
|
void secrets_named_mutex_release(const char *name, size_t *p_ref_count)
|
||||||
{
|
{
|
||||||
tdb_unlock_bystring(tdb, name);
|
size_t ref_count = *p_ref_count;
|
||||||
DEBUG(10,("secrets_named_mutex: released mutex for %s\n", name ));
|
|
||||||
|
SMB_ASSERT(ref_count != 0);
|
||||||
|
|
||||||
|
if (ref_count == 1) {
|
||||||
|
tdb_unlock_bystring(tdb, name);
|
||||||
|
DEBUG(10,("secrets_named_mutex: released mutex for %s\n", name ));
|
||||||
|
}
|
||||||
|
|
||||||
|
*p_ref_count = --ref_count;
|
||||||
|
DEBUG(10,("secrets_named_mutex_release: ref_count for mutex %s = %u\n", name, (unsigned int)ref_count ));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*********************************************************
|
/*********************************************************
|
||||||
|
Loading…
Reference in New Issue
Block a user