From f94a63cd8f94490780ad9331da229c0bcb2ca5d6 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Mon, 10 Mar 2008 21:08:29 +0100 Subject: [PATCH] Use a separate tdb for mutexes Another preparation to convert secrets.c to dbwrap: The dbwrap API does not provide a sane tdb_lock_with_timeout abstraction. In the clustered case the DC mutex is needed per-node anyway, so it is perfectly fine to use a local mutex only. --- source/auth/auth_domain.c | 16 +++++---- source/auth/auth_server.c | 16 +++++---- source/include/smb.h | 1 + source/lib/server_mutex.c | 57 +++++++++++++++++++++++---------- source/libads/kerberos_verify.c | 15 ++++----- source/passdb/secrets.c | 31 ------------------ source/winbindd/winbindd_cm.c | 17 ++++------ 7 files changed, 71 insertions(+), 82 deletions(-) diff --git a/source/auth/auth_domain.c b/source/auth/auth_domain.c index df51966f4c1..26474089fb9 100644 --- a/source/auth/auth_domain.c +++ b/source/auth/auth_domain.c @@ -24,6 +24,7 @@ #define DBGC_CLASS DBGC_AUTH extern bool global_machine_password_needs_changing; +static struct named_mutex *mutex; /** * Connect to a remote server for (inter)domain security authenticaion. @@ -67,7 +68,8 @@ static NTSTATUS connect_to_domain_password_server(struct cli_state **cli, * ACCESS_DENIED errors if 2 auths are done from the same machine. JRA. */ - if (!grab_server_mutex(dc_name)) { + mutex = grab_named_mutex(NULL, dc_name, 10); + if (mutex == NULL) { return NT_STATUS_NO_LOGON_SERVERS; } @@ -87,7 +89,7 @@ static NTSTATUS connect_to_domain_password_server(struct cli_state **cli, *cli = NULL; } - release_server_mutex(); + TALLOC_FREE(mutex); return result; } @@ -118,7 +120,7 @@ static NTSTATUS connect_to_domain_password_server(struct cli_state **cli, machine %s. Error was : %s.\n", dc_name, nt_errstr(result))); cli_shutdown(*cli); *cli = NULL; - release_server_mutex(); + TALLOC_FREE(mutex); return result; } @@ -137,7 +139,7 @@ machine %s. Error was : %s.\n", dc_name, nt_errstr(result))); domain)); cli_shutdown(*cli); *cli = NULL; - release_server_mutex(); + TALLOC_FREE(mutex); return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; } @@ -153,7 +155,7 @@ machine %s. Error was : %s.\n", dc_name, nt_errstr(result))); if (!NT_STATUS_IS_OK(result)) { cli_shutdown(*cli); *cli = NULL; - release_server_mutex(); + TALLOC_FREE(mutex); return result; } } @@ -163,7 +165,7 @@ machine %s. Error was : %s.\n", dc_name, nt_errstr(result))); machine %s. Error was : %s.\n", dc_name, cli_errstr(*cli))); cli_shutdown(*cli); *cli = NULL; - release_server_mutex(); + TALLOC_FREE(mutex); return NT_STATUS_NO_LOGON_SERVERS; } @@ -247,7 +249,7 @@ static NTSTATUS domain_client_validate(TALLOC_CTX *mem_ctx, /* Let go as soon as possible so we avoid any potential deadlocks with winbind lookup up users or groups. */ - release_server_mutex(); + TALLOC_FREE(mutex); if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(0,("domain_client_validate: unable to validate password " diff --git a/source/auth/auth_server.c b/source/auth/auth_server.c index 095f0b9fb83..b07884c49b6 100644 --- a/source/auth/auth_server.c +++ b/source/auth/auth_server.c @@ -37,6 +37,7 @@ static struct cli_state *server_cryptkey(TALLOC_CTX *mem_ctx) const char *p; char *pserver = NULL; bool connected_ok = False; + struct named_mutex *mutex; if (!(cli = cli_initialise())) return NULL; @@ -74,7 +75,8 @@ static struct cli_state *server_cryptkey(TALLOC_CTX *mem_ctx) session setup yet it will send a TCP reset to the first connection (tridge) */ - if (!grab_server_mutex(desthost)) { + mutex = grab_named_mutex(talloc_tos(), desthost, 10); + if (mutex == NULL) { cli_shutdown(cli); return NULL; } @@ -87,7 +89,7 @@ static struct cli_state *server_cryptkey(TALLOC_CTX *mem_ctx) } DEBUG(10,("server_cryptkey: failed to connect to server %s. Error %s\n", desthost, nt_errstr(status) )); - release_server_mutex(); + TALLOC_FREE(mutex); } if (!connected_ok) { @@ -98,7 +100,7 @@ static struct cli_state *server_cryptkey(TALLOC_CTX *mem_ctx) if (!attempt_netbios_session_request(&cli, global_myname(), desthost, &dest_ss)) { - release_server_mutex(); + TALLOC_FREE(mutex); DEBUG(1,("password server fails session request\n")); cli_shutdown(cli); return NULL; @@ -111,16 +113,16 @@ static struct cli_state *server_cryptkey(TALLOC_CTX *mem_ctx) DEBUG(3,("got session\n")); if (!cli_negprot(cli)) { + TALLOC_FREE(mutex); DEBUG(1,("%s rejected the negprot\n",desthost)); - release_server_mutex(); cli_shutdown(cli); return NULL; } if (cli->protocol < PROTOCOL_LANMAN2 || !(cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL)) { + TALLOC_FREE(mutex); DEBUG(1,("%s isn't in user level security mode\n",desthost)); - release_server_mutex(); cli_shutdown(cli); return NULL; } @@ -132,14 +134,14 @@ static struct cli_state *server_cryptkey(TALLOC_CTX *mem_ctx) if (!NT_STATUS_IS_OK(cli_session_setup(cli, "", "", 0, "", 0, ""))) { + TALLOC_FREE(mutex); DEBUG(0,("%s rejected the initial session setup (%s)\n", desthost, cli_errstr(cli))); - release_server_mutex(); cli_shutdown(cli); return NULL; } - release_server_mutex(); + TALLOC_FREE(mutex); DEBUG(3,("password server OK\n")); diff --git a/source/include/smb.h b/source/include/smb.h index c582a97e5c1..bf9ca6b92ca 100644 --- a/source/include/smb.h +++ b/source/include/smb.h @@ -420,6 +420,7 @@ struct timed_event; struct idle_event; struct share_mode_entry; struct uuid; +struct named_mutex; struct vfs_fsp_data { struct vfs_fsp_data *next; diff --git a/source/lib/server_mutex.c b/source/lib/server_mutex.c index 2700aa103b1..43c0de1975f 100644 --- a/source/lib/server_mutex.c +++ b/source/lib/server_mutex.c @@ -28,28 +28,51 @@ This locking allows smbd's mutlithread architecture to look like the single-connection that NT makes. */ -static char *mutex_server_name; +struct named_mutex { + struct tdb_wrap *tdb; + char *name; +}; -bool grab_server_mutex(const char *name) +static int unlock_named_mutex(struct named_mutex *mutex) { - mutex_server_name = SMB_STRDUP(name); - if (!mutex_server_name) { - DEBUG(0,("grab_server_mutex: malloc failed for %s\n", name)); - return False; + tdb_unlock_bystring(mutex->tdb->tdb, mutex->name); + return 0; +} + +struct named_mutex *grab_named_mutex(TALLOC_CTX *mem_ctx, const char *name, + int timeout) +{ + struct named_mutex *result; + + result = talloc(mem_ctx, struct named_mutex); + if (result == NULL) { + DEBUG(0, ("talloc failed\n")); + return NULL; } - if (!secrets_named_mutex(mutex_server_name, 10)) { - DEBUG(10,("grab_server_mutex: failed for %s\n", name)); - SAFE_FREE(mutex_server_name); - return False; + + result->name = talloc_strdup(result, name); + if (result->name == NULL) { + DEBUG(0, ("talloc failed\n")); + TALLOC_FREE(result); + return NULL; } - return True; -} + result->tdb = tdb_wrap_open(result, lock_path("mutex.tdb"), 0, + TDB_DEFAULT, O_RDWR|O_CREAT, 0600); + if (result->tdb == NULL) { + DEBUG(1, ("Could not open mutex.tdb: %s\n", + strerror(errno))); + TALLOC_FREE(result); + return NULL; + } -void release_server_mutex(void) -{ - if (mutex_server_name) { - secrets_named_mutex_release(mutex_server_name); - SAFE_FREE(mutex_server_name); + if (tdb_lock_bystring_with_timeout(result->tdb->tdb, name, + timeout) == -1) { + DEBUG(1, ("Could not get the lock for %s\n", name)); + TALLOC_FREE(result); + return NULL; } + + talloc_set_destructor(result, unlock_named_mutex); + return result; } diff --git a/source/libads/kerberos_verify.c b/source/libads/kerberos_verify.c index f112dd34e37..6b482ecd20b 100644 --- a/source/libads/kerberos_verify.c +++ b/source/libads/kerberos_verify.c @@ -330,8 +330,8 @@ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx, krb5_const_principal client_principal = NULL; char *host_princ_s = NULL; bool auth_ok = False; - bool got_replay_mutex = False; bool got_auth_data = False; + struct named_mutex *mutex = NULL; ZERO_STRUCT(packet); ZERO_STRUCT(auth_data); @@ -395,15 +395,15 @@ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx, locking in the MIT krb5 code surrounding the replay cache... */ - if (!grab_server_mutex("replay cache mutex")) { + mutex = grab_named_mutex(talloc_tos(), "replay cache mutex", + 10); + if (mutex == NULL) { DEBUG(1,("ads_verify_ticket: unable to protect " "replay cache with mutex.\n")); ret = KRB5_CC_IO; goto out; } - got_replay_mutex = True; - /* JRA. We must set the rcache here. This will prevent replay attacks. */ @@ -443,8 +443,7 @@ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx, } if ( use_replay_cache ) { - release_server_mutex(); - got_replay_mutex = False; + TALLOC_FREE(mutex); #if 0 /* Heimdal leaks here, if we fix the leak, MIT crashes */ if (rcache) { @@ -539,9 +538,7 @@ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx, out: - if (got_replay_mutex) { - release_server_mutex(); - } + TALLOC_FREE(mutex); if (!NT_STATUS_IS_OK(sret)) { data_blob_free(&auth_data); diff --git a/source/passdb/secrets.c b/source/passdb/secrets.c index 2c0d6487165..8448f795b49 100644 --- a/source/passdb/secrets.c +++ b/source/passdb/secrets.c @@ -1028,37 +1028,6 @@ NTSTATUS secrets_trusted_domains(TALLOC_CTX *mem_ctx, uint32 *num_domains, return NT_STATUS_OK; } -/******************************************************************************* - Lock the secrets tdb based on a string - this is used as a primitive form of mutex - between smbd instances. -*******************************************************************************/ - -bool secrets_named_mutex(const char *name, unsigned int timeout) -{ - int ret = 0; - - if (!secrets_init()) { - return false; - } - - ret = tdb_lock_bystring_with_timeout(tdb, name, timeout); - if (ret == 0) { - DEBUG(10,("secrets_named_mutex: got mutex for %s\n", name )); - } - - return (ret == 0); -} - -/******************************************************************************* - Unlock a named mutex. -*******************************************************************************/ - -void secrets_named_mutex_release(const char *name) -{ - tdb_unlock_bystring(tdb, name); - DEBUG(10,("secrets_named_mutex: released mutex for %s\n", name )); -} - /******************************************************************************* Store a complete AFS keyfile into secrets.tdb. *******************************************************************************/ diff --git a/source/winbindd/winbindd_cm.c b/source/winbindd/winbindd_cm.c index 0f536cdfb8d..072b4ee98f6 100644 --- a/source/winbindd/winbindd_cm.c +++ b/source/winbindd/winbindd_cm.c @@ -747,7 +747,7 @@ static NTSTATUS cm_prepare_connection(const struct winbindd_domain *domain, char *ipc_domain = NULL; char *ipc_password = NULL; - bool got_mutex; + struct named_mutex *mutex; NTSTATUS result = NT_STATUS_UNSUCCESSFUL; @@ -761,10 +761,9 @@ static NTSTATUS cm_prepare_connection(const struct winbindd_domain *domain, *retry = True; - got_mutex = secrets_named_mutex(controller, - WINBIND_SERVER_MUTEX_WAIT_TIME); - - if (!got_mutex) { + mutex = grab_named_mutex(talloc_tos(), controller, + WINBIND_SERVER_MUTEX_WAIT_TIME); + if (mutex == NULL) { DEBUG(0,("cm_prepare_connection: mutex grab failed for %s\n", controller)); result = NT_STATUS_POSSIBLE_DEADLOCK; @@ -952,8 +951,7 @@ static NTSTATUS cm_prepare_connection(const struct winbindd_domain *domain, goto done; } - secrets_named_mutex_release(controller); - got_mutex = False; + TALLOC_FREE(mutex); *retry = False; /* set the domain if empty; needed for schannel connections */ @@ -964,10 +962,7 @@ static NTSTATUS cm_prepare_connection(const struct winbindd_domain *domain, result = NT_STATUS_OK; done: - if (got_mutex) { - secrets_named_mutex_release(controller); - } - + TALLOC_FREE(mutex); SAFE_FREE(machine_account); SAFE_FREE(machine_password); SAFE_FREE(machine_krb5_principal); -- 2.34.1