Use a separate tdb for mutexes
authorVolker Lendecke <vl@samba.org>
Mon, 10 Mar 2008 20:08:29 +0000 (21:08 +0100)
committerVolker Lendecke <vl@samba.org>
Mon, 10 Mar 2008 20:08:45 +0000 (21:08 +0100)
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
source/auth/auth_server.c
source/include/smb.h
source/lib/server_mutex.c
source/libads/kerberos_verify.c
source/passdb/secrets.c
source/winbindd/winbindd_cm.c

index df51966f4c155d34de3a60ec43b4b1edfc23f1fe..26474089fb987eb338d627be7b8eadfe585541d5 100644 (file)
@@ -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 "
index 095f0b9fb83b7d0a1453eed2212f2515a4eb3859..b07884c49b693b4e908bb02b380a4b029d471ca5 100644 (file)
@@ -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"));
 
index c582a97e5c1d078fcfd7429600974a51a5bd2d71..bf9ca6b92caf8339bb34769d1fd5762a64794b45 100644 (file)
@@ -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;
index 2700aa103b106fb5cd0b43cd9d2bdd2dae912239..43c0de1975f5d6d57415b93004b8f7924bb73833 100644 (file)
    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;
 }
index f112dd34e3709f6aef38b3fb37c856918d708b57..6b482ecd20bd23d17597ca010ca94c20f1c9e2c5 100644 (file)
@@ -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);
index 2c0d648716520ed0bc093a3f830796e91cba76d6..8448f795b49adf0ef0bee3eceda175a1bc4d4ff3 100644 (file)
@@ -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.
 *******************************************************************************/
index 0f536cdfb8dcd35cc215c49970545e8c0183c3a2..072b4ee98f6e62e3b7842aef91cd3cbdf659a430 100644 (file)
@@ -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);