[tarantool-patches] [PATCH v2 1/2] access: rework struct credentials API

Vladislav Shpilevoy v.shpilevoy at tarantool.org
Sat Oct 5 01:25:59 MSK 2019


Struct credentials is a cache of user's universal privileges. It
is static and is never changed after creation. That is a problem.
If a user privileges are updated, it is not reflected in his
existing credentials caches.

This patch reworks credentials API so as now this struct is not
just a container for several numbers. It is an object with
standard methods like create(), destroy(). A credentials object
still is not updated together with its source user, but now at
least the API allows to fix that.

Next patch will add a trigger to struct credentials to catch user
privilege changes and update the cache.

Part of #2763
---
 src/box/authentication.cc |  3 +--
 src/box/func.c            |  9 ++++-----
 src/box/lua/session.c     |  6 +++---
 src/box/session.cc        | 10 +++++-----
 src/box/session.h         |  8 --------
 src/box/user.cc           | 22 ++++++++++++++++++++++
 src/box/user.h            | 27 +++++++++++++++++++++++++++
 7 files changed, 62 insertions(+), 23 deletions(-)

diff --git a/src/box/authentication.cc b/src/box/authentication.cc
index fdad7395a..a7a3587f7 100644
--- a/src/box/authentication.cc
+++ b/src/box/authentication.cc
@@ -100,6 +100,5 @@ ok:
 	if (! rlist_empty(&session_on_auth) &&
 	    session_run_on_auth_triggers(&auth_res) != 0)
 		diag_raise();
-	credentials_init(&session->credentials, user->auth_token,
-			 user->def->uid);
+	credentials_reset(&session->credentials, user);
 }
diff --git a/src/box/func.c b/src/box/func.c
index e8cc99081..c94ca4974 100644
--- a/src/box/func.c
+++ b/src/box/func.c
@@ -418,7 +418,7 @@ func_new(struct func_def *def)
 	 * Later on consistency of the cache is ensured by DDL
 	 * checks (see user_has_data()).
 	 */
-	func->owner_credentials.auth_token = BOX_USER_MAX; /* invalid value */
+	credentials_create_empty(&func->owner_credentials);
 	return func;
 }
 
@@ -549,6 +549,7 @@ func_delete(struct func *func)
 {
 	struct func_def *def = func->def;
 	func->vtab->destroy(func);
+	credentials_destroy(&func->owner_credentials);
 	free(def);
 }
 
@@ -598,7 +599,7 @@ func_call(struct func *base, struct port *args, struct port *ret)
 	if (base->def->setuid) {
 		orig_credentials = effective_user();
 		/* Remember and change the current user id. */
-		if (base->owner_credentials.auth_token >= BOX_USER_MAX) {
+		if (credentials_is_empty(&base->owner_credentials)) {
 			/*
 			 * Fill the cache upon first access, since
 			 * when func is created, no user may
@@ -608,9 +609,7 @@ func_call(struct func *base, struct port *args, struct port *ret)
 			struct user *owner = user_find(base->def->uid);
 			if (owner == NULL)
 				return -1;
-			credentials_init(&base->owner_credentials,
-					 owner->auth_token,
-					 owner->def->uid);
+			credentials_reset(&base->owner_credentials, owner);
 		}
 		fiber_set_user(fiber(), &base->owner_credentials);
 	}
diff --git a/src/box/lua/session.c b/src/box/lua/session.c
index b9495e7a6..de5eb9adc 100644
--- a/src/box/lua/session.c
+++ b/src/box/lua/session.c
@@ -185,15 +185,14 @@ lbox_session_su(struct lua_State *L)
 		luaT_error(L);
 
 	if (top == 1) {
-		credentials_init(&session->credentials, user->auth_token,
-				 user->def->uid);
+		credentials_reset(&session->credentials, user);
 		fiber_set_user(fiber(), &session->credentials);
 		return 0; /* su */
 	}
 
 	struct credentials su_credentials;
 	struct credentials *old_credentials = fiber()->storage.credentials;
-	credentials_init(&su_credentials, user->auth_token, user->def->uid);
+	credentials_create(&su_credentials, user);
 	fiber()->storage.credentials = &su_credentials;
 
 	/* sudo */
@@ -201,6 +200,7 @@ lbox_session_su(struct lua_State *L)
 	int error = lua_pcall(L, top - 2, LUA_MULTRET, 0);
 	/* Restore the original credentials. */
 	fiber_set_user(fiber(), old_credentials);
+	credentials_destroy(&su_credentials);
 
 	if (error)
 		lua_error(L);
diff --git a/src/box/session.cc b/src/box/session.cc
index 59bf226dd..93d4eb948 100644
--- a/src/box/session.cc
+++ b/src/box/session.cc
@@ -142,8 +142,7 @@ session_create(enum session_type type)
 	session->sql_default_engine = SQL_STORAGE_ENGINE_MEMTX;
 
 	/* For on_connect triggers. */
-	credentials_init(&session->credentials, guest_user->auth_token,
-			 guest_user->def->uid);
+	credentials_create(&session->credentials, guest_user);
 	struct mh_i64ptr_node_t node;
 	node.key = session->id;
 	node.val = session;
@@ -172,8 +171,7 @@ session_create_on_demand()
 	};
 	/* Add a trigger to destroy session on fiber stop */
 	trigger_add(&fiber()->on_stop, &s->fiber_on_stop);
-	credentials_init(&s->credentials, admin_user->auth_token,
-			 admin_user->def->uid);
+	credentials_reset(&s->credentials, admin_user);
 	/*
 	 * At bootstrap, admin user access is not loaded yet (is
 	 * 0), force global access. @sa comment in session_init()
@@ -232,6 +230,7 @@ session_destroy(struct session *session)
 	session_storage_cleanup(session->id);
 	struct mh_i64ptr_node_t node = { session->id, NULL };
 	mh_i64ptr_remove(session_registry, &node, NULL);
+	credentials_destroy(&session->credentials);
 	mempool_free(&session_pool, session);
 }
 
@@ -252,7 +251,7 @@ session_init()
 	if (session_registry == NULL)
 		panic("out of memory");
 	mempool_create(&session_pool, &cord()->slabc, sizeof(struct session));
-	credentials_init(&admin_credentials, ADMIN, ADMIN);
+	credentials_create(&admin_credentials, admin_user);
 	/*
 	 * For performance reasons, we do not always explicitly
 	 * look at user id in access checks, while still need to
@@ -278,6 +277,7 @@ session_free()
 {
 	if (session_registry)
 		mh_i64ptr_delete(session_registry);
+	credentials_destroy(&admin_credentials);
 }
 
 int
diff --git a/src/box/session.h b/src/box/session.h
index 85a2d940b..eff3d7a67 100644
--- a/src/box/session.h
+++ b/src/box/session.h
@@ -193,14 +193,6 @@ fiber_set_session(struct fiber *fiber, struct session *session)
 	fiber->storage.session = session;
 }
 
-static inline void
-credentials_init(struct credentials *cr, uint8_t auth_token, uint32_t uid)
-{
-	cr->auth_token = auth_token;
-	cr->universal_access = universe.access[cr->auth_token].effective;
-	cr->uid = uid;
-}
-
 /*
  * For use in local hot standby, which runs directly
  * from ev watchers (without current fiber), but needs
diff --git a/src/box/user.cc b/src/box/user.cc
index c46ff67d1..f12d65d27 100644
--- a/src/box/user.cc
+++ b/src/box/user.cc
@@ -714,3 +714,25 @@ priv_grant(struct user *grantee, struct priv_def *priv)
 }
 
 /** }}} */
+
+void
+credentials_create(struct credentials *cr, struct user *user)
+{
+	cr->auth_token = user->auth_token;
+	cr->universal_access = universe.access[user->auth_token].effective;
+	cr->uid = user->def->uid;
+}
+
+void
+credentials_create_empty(struct credentials *cr)
+{
+	cr->auth_token = BOX_USER_MAX;
+	cr->universal_access = 0;
+	cr->uid = BOX_USER_MAX;
+}
+
+void
+credentials_destroy(struct credentials *cr)
+{
+	(void) cr;
+}
diff --git a/src/box/user.h b/src/box/user.h
index 527fb2e7c..5f320f739 100644
--- a/src/box/user.h
+++ b/src/box/user.h
@@ -106,6 +106,33 @@ user_find_by_name(const char *name, uint32_t len);
 struct user *
 user_find(uint32_t uid);
 
+/** Create a cache of user's privileges in @a cr. */
+void
+credentials_create(struct credentials *cr, struct user *user);
+
+/** Create a dummy credentials cache without a user. */
+void
+credentials_create_empty(struct credentials *cr);
+
+/** Check if @a cr has a source user. */
+static inline bool
+credentials_is_empty(const struct credentials *cr)
+{
+	return cr->auth_token == BOX_USER_MAX;
+}
+
+/** Free credentials resources, invalidate the object. */
+void
+credentials_destroy(struct credentials *cr);
+
+/** Change source user of the credentials cache. */
+static inline void
+credentials_reset(struct credentials *cr, struct user *new_user)
+{
+	credentials_destroy(cr);
+	credentials_create(cr, new_user);
+}
+
 #if defined(__cplusplus)
 } /* extern "C" */
 
-- 
2.21.0 (Apple Git-122)





More information about the Tarantool-patches mailing list