Changeset: 7b380d84f5ee for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB/rev/7b380d84f5ee
Modified Files:
        monetdb5/mal/mal_authorize.c
Branch: default
Log Message:

Use locks to protect concurrent access to remote table credentials bats.


diffs (truncated from 502 to 300 lines):

diff --git a/monetdb5/mal/mal_authorize.c b/monetdb5/mal/mal_authorize.c
--- a/monetdb5/mal/mal_authorize.c
+++ b/monetdb5/mal/mal_authorize.c
@@ -31,8 +31,6 @@
 #include <unistd.h>
 #endif
 
-static BUN lookupRemoteTableKey(const char *key);
-
 /* Remote table bats */
 static BAT *rt_key = NULL;
 static BAT *rt_uri = NULL;
@@ -42,16 +40,23 @@ static BAT *rt_deleted = NULL;
 /* yep, the vault key is just stored in memory */
 static str vaultKey = NULL;
 static str master_password = NULL;
+/* lock to protect the above */
+static MT_RWLock rt_lock = MT_RWLOCK_INITIALIZER(rt_lock);
 static AUTHCallbackCntx authCallbackCntx = {
        .get_user_name = NULL,
        .get_user_password = NULL,
        .get_user_oid = NULL
 };
 
+static str AUTHdeleteRemoteTableCredentialsLocked(const char *local_table);
+static str AUTHdecypherValueLocked(str *ret, const char *value);
+
 void AUTHreset(void)
 {
+       MT_rwlock_wrlock(&rt_lock);
        GDKfree(vaultKey);
        vaultKey = NULL;
+       MT_rwlock_wrunlock(&rt_lock);
 }
 
 /**
@@ -67,7 +72,7 @@ AUTHrequireAdmin(Client cntxt) {
        return(MAL_SUCCEED);
 }
 
-static void
+static str
 AUTHcommit(void)
 {
        bat blist[6];
@@ -104,9 +109,13 @@ AUTHinitTables(void) {
        int isNew = 1;
        str msg = MAL_SUCCEED;
 
+       MT_rwlock_wrlock(&rt_lock);
+
        /* skip loading if already loaded */
-       if (rt_key != NULL && rt_deleted != NULL)
+       if (rt_key != NULL && rt_deleted != NULL) {
+               MT_rwlock_wrunlock(&rt_lock);
                return(MAL_SUCCEED);
+       }
 
        /* Remote table authorization table.
         *
@@ -117,12 +126,16 @@ AUTHinitTables(void) {
        bid = BBPindex("M5system_auth_rt_key");
        if (!bid) {
                rt_key = COLnew(0, TYPE_str, 256, PERSISTENT);
-               if (rt_key == NULL)
+               if (rt_key == NULL) {
+                       MT_rwlock_wrunlock(&rt_lock);
                        throw(MAL, "initTables.rt_key", SQLSTATE(HY013) 
MAL_MALLOC_FAIL " remote table key bat");
+               }
 
                if (BBPrename(rt_key, "M5system_auth_rt_key") != 0 ||
-                       BATmode(rt_key, false) != GDK_SUCCEED)
+                       BATmode(rt_key, false) != GDK_SUCCEED) {
+                       MT_rwlock_wrunlock(&rt_lock);
                        throw(MAL, "initTables.rt_key", GDK_EXCEPTION);
+               }
        }
        else {
                int dbg = GDKdebug;
@@ -131,6 +144,7 @@ AUTHinitTables(void) {
                rt_key = BATdescriptor(bid);
                GDKdebug = dbg;
                if (rt_key == NULL) {
+                       MT_rwlock_wrunlock(&rt_lock);
                        throw(MAL, "initTables.rt_key", SQLSTATE(HY002) 
RUNTIME_OBJECT_MISSING);
                }
                isNew = 0;
@@ -141,12 +155,16 @@ AUTHinitTables(void) {
        bid = BBPindex("M5system_auth_rt_uri");
        if (!bid) {
                rt_uri = COLnew(0, TYPE_str, 256, PERSISTENT);
-               if (rt_uri == NULL)
+               if (rt_uri == NULL) {
+                       MT_rwlock_wrunlock(&rt_lock);
                        throw(MAL, "initTables.rt_uri", SQLSTATE(HY013) 
MAL_MALLOC_FAIL " remote table uri bat");
+               }
 
                if (BBPrename(rt_uri, "M5system_auth_rt_uri") != 0 ||
-                       BATmode(rt_uri, false) != GDK_SUCCEED)
+                       BATmode(rt_uri, false) != GDK_SUCCEED) {
+                       MT_rwlock_wrunlock(&rt_lock);
                        throw(MAL, "initTables.rt_uri", GDK_EXCEPTION);
+               }
        }
        else {
                int dbg = GDKdebug;
@@ -155,6 +173,7 @@ AUTHinitTables(void) {
                rt_uri = BATdescriptor(bid);
                GDKdebug = dbg;
                if (rt_uri == NULL) {
+                       MT_rwlock_wrunlock(&rt_lock);
                        throw(MAL, "initTables.rt_uri", SQLSTATE(HY002) 
RUNTIME_OBJECT_MISSING);
                }
                isNew = 0;
@@ -165,12 +184,16 @@ AUTHinitTables(void) {
        bid = BBPindex("M5system_auth_rt_remoteuser");
        if (!bid) {
                rt_remoteuser = COLnew(0, TYPE_str, 256, PERSISTENT);
-               if (rt_remoteuser == NULL)
+               if (rt_remoteuser == NULL) {
+                       MT_rwlock_wrunlock(&rt_lock);
                        throw(MAL, "initTables.rt_remoteuser", SQLSTATE(HY013) 
MAL_MALLOC_FAIL " remote table local user bat");
+               }
 
                if (BBPrename(rt_remoteuser, "M5system_auth_rt_remoteuser") != 
0 ||
-                       BATmode(rt_remoteuser, false) != GDK_SUCCEED)
+                       BATmode(rt_remoteuser, false) != GDK_SUCCEED) {
+                       MT_rwlock_wrunlock(&rt_lock);
                        throw(MAL, "initTables.rt_remoteuser", GDK_EXCEPTION);
+               }
        }
        else {
                int dbg = GDKdebug;
@@ -179,6 +202,7 @@ AUTHinitTables(void) {
                rt_remoteuser = BATdescriptor(bid);
                GDKdebug = dbg;
                if (rt_remoteuser == NULL) {
+                       MT_rwlock_wrunlock(&rt_lock);
                        throw(MAL, "initTables.rt_remoteuser", SQLSTATE(HY002) 
RUNTIME_OBJECT_MISSING);
                }
                isNew = 0;
@@ -189,12 +213,16 @@ AUTHinitTables(void) {
        bid = BBPindex("M5system_auth_rt_hashedpwd");
        if (!bid) {
                rt_hashedpwd = COLnew(0, TYPE_str, 256, PERSISTENT);
-               if (rt_hashedpwd == NULL)
+               if (rt_hashedpwd == NULL) {
+                       MT_rwlock_wrunlock(&rt_lock);
                        throw(MAL, "initTables.rt_hashedpwd", SQLSTATE(HY013) 
MAL_MALLOC_FAIL " remote table local user bat");
+               }
 
                if (BBPrename(rt_hashedpwd, "M5system_auth_rt_hashedpwd") != 0 
||
-                       BATmode(rt_hashedpwd, false) != GDK_SUCCEED)
+                       BATmode(rt_hashedpwd, false) != GDK_SUCCEED) {
+                       MT_rwlock_wrunlock(&rt_lock);
                        throw(MAL, "initTables.rt_hashedpwd", GDK_EXCEPTION);
+               }
        }
        else {
                int dbg = GDKdebug;
@@ -203,6 +231,7 @@ AUTHinitTables(void) {
                rt_hashedpwd = BATdescriptor(bid);
                GDKdebug = dbg;
                if (rt_hashedpwd == NULL) {
+                       MT_rwlock_wrunlock(&rt_lock);
                        throw(MAL, "initTables.rt_hashedpwd", SQLSTATE(HY002) 
RUNTIME_OBJECT_MISSING);
                }
                isNew = 0;
@@ -213,22 +242,29 @@ AUTHinitTables(void) {
        bid = BBPindex("M5system_auth_rt_deleted");
        if (!bid) {
                rt_deleted = COLnew(0, TYPE_oid, 256, PERSISTENT);
-               if (rt_deleted == NULL)
+               if (rt_deleted == NULL) {
+                       MT_rwlock_wrunlock(&rt_lock);
                        throw(MAL, "initTables.rt_deleted", SQLSTATE(HY013) 
MAL_MALLOC_FAIL " remote table local user bat");
+               }
 
                if (BBPrename(rt_deleted, "M5system_auth_rt_deleted") != 0 ||
-                       BATmode(rt_deleted, false) != GDK_SUCCEED)
+                       BATmode(rt_deleted, false) != GDK_SUCCEED) {
+                       MT_rwlock_wrunlock(&rt_lock);
                        throw(MAL, "initTables.rt_deleted", GDK_EXCEPTION);
+               }
                /* If the database is not new, but we just created this BAT,
                 * write everything to disc. This needs to happen only after
                 * the last BAT of the vault has been created.
                 */
-               if (!isNew)
-                       AUTHcommit();
+               if (!isNew && (msg = AUTHcommit()) != MAL_SUCCEED) {
+                       MT_rwlock_wrunlock(&rt_lock);
+                       return msg;
+               }
        }
        else {
                rt_deleted = BATdescriptor(bid);
                if (rt_deleted == NULL) {
+                       MT_rwlock_wrunlock(&rt_lock);
                        throw(MAL, "initTables.rt_deleted", SQLSTATE(HY002) 
RUNTIME_OBJECT_MISSING);
                }
                isNew = 0;
@@ -242,10 +278,13 @@ AUTHinitTables(void) {
                if (msg != NULL) {
                        char *nmsg = createException(MAL, "initTables", "%s", 
msg);
                        free(msg);
+                       MT_rwlock_wrunlock(&rt_lock);
                        return nmsg;
                }
        }
 
+       MT_rwlock_wrunlock(&rt_lock);
+
        return(MAL_SUCCEED);
 }
 
@@ -321,7 +360,9 @@ AUTHcheckCredentials(
        /* special case: users whose name starts with '.' can authenticate using
         * the temporary master password.
         */
+       MT_rwlock_rdlock(&rt_lock);
        if (username[0] == '.' && master_password != NULL && master_password[0] 
!= '\0') {
+               MT_rwlock_rdunlock(&rt_lock);
                // first encrypt the master password as if we've just found it
                // in the password store
                str encrypted = mcrypt_BackendSum(master_password, 
strlen(master_password));
@@ -335,7 +376,8 @@ AUTHcheckCredentials(
                        return(MAL_SUCCEED);
                }
                free(hash);
-       }
+       } else
+               MT_rwlock_rdunlock(&rt_lock);
 
        /* of course we DO NOT print the password here */
        throw(INVCRED, "checkCredentials", INVCRED_INVALID_USER " '%s'", 
username);
@@ -363,14 +405,14 @@ AUTHgetUsername(str *username, Client cn
  * Returns the password hash as used by the backend for the given
  * username. Throws an exception if called by a non-superuser.
  */
-str
-AUTHgetPasswordHash(str *ret, Client cntxt, const char *username)
+static str
+AUTHgetPasswordHashLocked(str *ret, Client cntxt, const char *username)
 {
        str tmp;
        str msg;
        str passwd = NULL;
 
-       rethrow("getPasswordHash", tmp, AUTHrequireAdmin(cntxt));
+       rethrow("getPasswordHash", msg, AUTHrequireAdmin(cntxt));
 
        if (strNil(username))
                throw(ILLARG, "getPasswordHash", "username should not be nil");
@@ -383,18 +425,26 @@ AUTHgetPasswordHash(str *ret, Client cnt
                throw(MAL, "getPasswordHash", "user '%s' does not exist", 
username);
        }
        /* decypher the password */
-       if ((msg = AUTHdecypherValue(&passwd, tmp)) != MAL_SUCCEED) {
+       if ((msg = AUTHdecypherValueLocked(&passwd, tmp)) != MAL_SUCCEED) {
                GDKfree(tmp);
                return msg;
        }
 
-       if(tmp)
+       if (tmp)
                GDKfree(tmp);
 
        *ret = passwd;
        return(MAL_SUCCEED);
 }
 
+str
+AUTHgetPasswordHash(str *ret, Client cntxt, const char *username)
+{
+       MT_rwlock_rdlock(&rt_lock);
+       str err = AUTHgetPasswordHashLocked(ret, cntxt, username);
+       MT_rwlock_rdunlock(&rt_lock);
+       return err;
+}
 
 /*=== the vault ===*/
 
@@ -415,10 +465,15 @@ AUTHunlockVault(const char *password)
        /* even though I think this function should be called only once, it
         * is not of real extra efforts to avoid a mem-leak if it is used
         * multiple times */
+       MT_rwlock_wrlock(&rt_lock);
        GDKfree(vaultKey);
 
-       if ((vaultKey = GDKstrdup(password)) == NULL)
+       vaultKey = GDKstrdup(password);
+       if (vaultKey == NULL) {
+               MT_rwlock_wrunlock(&rt_lock);
                throw(MAL, "unlockVault", SQLSTATE(HY013) MAL_MALLOC_FAIL " 
vault key");
+       }
+       MT_rwlock_wrunlock(&rt_lock);
        return(MAL_SUCCEED);
 }
 
_______________________________________________
checkin-list mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to