diff --git a/src/box/alter.cc b/src/box/alter.cc index d53a7c2fc490d17fd05019f142be016b3ea3faa8..c0d6312c3a5f220f36b211d8b42446e4102fe2bb 100644 --- a/src/box/alter.cc +++ b/src/box/alter.cc @@ -72,15 +72,15 @@ void access_check_ddl(uint32_t owner_uid) { - struct current_user *user = current_user(); + struct credentials *cr = current_user(); /* * Only the creator of the space or superuser can modify * the space, since we don't have ALTER privilege. */ - if (owner_uid != user->uid && user->uid != ADMIN) { - struct user_def *def = user_cache_find(user->uid); + if (owner_uid != cr->uid && cr->uid != ADMIN) { + struct user *user = user_cache_find(cr->uid); tnt_raise(ClientError, ER_ACCESS_DENIED, - "Create or drop", def->name); + "Create or drop", user->name); } } @@ -1334,7 +1334,7 @@ func_def_create_from_tuple(struct func_def *func, struct tuple *tuple) * Later on consistency of the cache is ensured by DDL * checks (see user_has_data()). */ - func->setuid_user.auth_token = BOX_USER_MAX; /* invalid value */ + func->owner_credentials.auth_token = BOX_USER_MAX; /* invalid value */ const char *name = tuple_field_cstr(tuple, NAME); uint32_t len = strlen(name); if (len >= sizeof(func->name)) { @@ -1493,7 +1493,7 @@ priv_def_check(struct priv_def *priv) static void grant_or_revoke(struct priv_def *priv) { - struct user_def *grantee = user_by_id(priv->grantee_id); + struct user *grantee = user_by_id(priv->grantee_id); if (grantee == NULL) return; struct access *access = NULL; @@ -1502,9 +1502,9 @@ grant_or_revoke(struct priv_def *priv) { access = &grantee->universal_access; /** Update cache at least in the current session. */ - struct current_user *user = current_user(); - if (grantee->uid == user->uid) - user->universal_access = priv->access; + struct credentials *cr = current_user(); + if (grantee->uid == cr->uid) + cr->universal_access = priv->access; break; } case SC_SPACE: diff --git a/src/box/authentication.cc b/src/box/authentication.cc index 553579b4e1526cc9eed356c0c404841a93bd5349..dfdf8aaf7b86610e0f6bf1eff6509d2e1da6149e 100644 --- a/src/box/authentication.cc +++ b/src/box/authentication.cc @@ -36,7 +36,7 @@ void authenticate(const char *user_name, uint32_t len, const char *tuple, const char * /* tuple_end */) { - struct user_def *user = user_cache_find_by_name(user_name, len); + struct user *user = user_cache_find_by_name(user_name, len); struct session *session = current_session(); uint32_t part_count; uint32_t scramble_len; @@ -70,6 +70,6 @@ authenticate(const char *user_name, uint32_t len, tnt_raise(ClientError, ER_PASSWORD_MISMATCH, user->name); ok: - current_user_init(&session->user, user); + credentials_init(&session->credentials, user); } diff --git a/src/box/iproto.cc b/src/box/iproto.cc index bce1016e6c2c27ffe470ed24f173ca4dcb6edf5a..b7a371d67ca258b902d6d417399599b54ffb9b8c 100644 --- a/src/box/iproto.cc +++ b/src/box/iproto.cc @@ -199,7 +199,7 @@ iproto_queue_handler(va_list ap) while ((request = iproto_queue_pop(i_queue))) { IprotoRequestGuard guard(request); fiber_set_session(fiber(), request->session); - fiber_set_user(fiber(), &request->session->user); + fiber_set_user(fiber(), &request->session->credentials); request->process(request); } /** Put the current fiber into a queue fiber cache. */ diff --git a/src/box/key_def.h b/src/box/key_def.h index 008db160fb2052361ddf93939e0596d33f30fe8b..e730735d3bf66026c1f89b290e32e31bea2cf26a 100644 --- a/src/box/key_def.h +++ b/src/box/key_def.h @@ -297,7 +297,7 @@ struct access { * Differs from the authenticated user when executing * setuid functions. */ -struct current_user { +struct credentials { /** A look up key to quickly find session user. */ uint8_t auth_token; /** @@ -327,7 +327,7 @@ struct func_def { * Authentication id of the owner of the function, * used for set-user-id functions. */ - struct current_user setuid_user; + struct credentials owner_credentials; /** Function name. */ char name[BOX_NAME_MAX + 1]; /** diff --git a/src/box/lua/call.cc b/src/box/lua/call.cc index ce34aaceee40585c07dc83f4cacf1d88f9d9ccfa..196eefdd85047893f2b49ee11865640739a62ba2 100644 --- a/src/box/lua/call.cc +++ b/src/box/lua/call.cc @@ -474,7 +474,7 @@ struct SetuidGuard { /** True if the function was set-user-id one. */ bool setuid; - struct current_user *orig_user; + struct credentials *orig_credentials; inline SetuidGuard(const char *name, uint32_t name_len, uint8_t access); @@ -484,7 +484,7 @@ struct SetuidGuard SetuidGuard::SetuidGuard(const char *name, uint32_t name_len, uint8_t access) :setuid(false) - ,orig_user(current_user()) + ,orig_credentials(current_user()) { /* @@ -492,9 +492,9 @@ SetuidGuard::SetuidGuard(const char *name, uint32_t name_len, * No special check for ADMIN user is necessary * since ADMIN has universal access. */ - if (orig_user->universal_access & PRIV_ALL) + if (orig_credentials->universal_access & PRIV_ALL) return; - access &= ~orig_user->universal_access; + access &= ~orig_credentials->universal_access; /* * We need to look up the function by name even if * the user has access to it, since it could require @@ -510,37 +510,37 @@ SetuidGuard::SetuidGuard(const char *name, uint32_t name_len, */ return; } - if (func == NULL || (func->uid != orig_user->uid && - access & ~func->access[orig_user->auth_token].effective)) { + if (func == NULL || (func->uid != orig_credentials->uid && + access & ~func->access[orig_credentials->auth_token].effective)) { /* Access violation, report error. */ char name_buf[BOX_NAME_MAX + 1]; snprintf(name_buf, sizeof(name_buf), "%.*s", name_len, name); - struct user_def *def = user_cache_find(orig_user->uid); + struct user *user = user_cache_find(orig_credentials->uid); tnt_raise(ClientError, ER_FUNCTION_ACCESS_DENIED, - priv_name(access), def->name, name_buf); + priv_name(access), user->name, name_buf); } if (func->setuid) { /** Remember and change the current user id. */ - if (unlikely(func->setuid_user.auth_token >= BOX_USER_MAX)) { + if (func->owner_credentials.auth_token >= BOX_USER_MAX) { /* * Fill the cache upon first access, since * when func_def is created, no user may * be around to fill it (recovery of * system spaces from a snapshot). */ - struct user_def *owner = user_cache_find(func->uid); - current_user_init(&func->setuid_user, owner); + struct user *owner = user_cache_find(func->uid); + credentials_init(&func->owner_credentials, owner); } setuid = true; - fiber_set_user(fiber(), &func->setuid_user); + fiber_set_user(fiber(), &func->owner_credentials); } } SetuidGuard::~SetuidGuard() { if (setuid) - fiber_set_user(fiber(), orig_user); + fiber_set_user(fiber(), orig_credentials); } /** diff --git a/src/box/lua/session.cc b/src/box/lua/session.cc index a558def7b58f8c68d8a6ad967dc6376938f0cad3..2193936ac806dc34e2e94aff828ce3dab5fdf7c9 100644 --- a/src/box/lua/session.cc +++ b/src/box/lua/session.cc @@ -30,7 +30,6 @@ #include "lua/utils.h" #include "lua/trigger.h" #include "box/user.h" -#include "box/user_def.h" extern "C" { #include <lua.h> @@ -68,7 +67,11 @@ lbox_session_id(struct lua_State *L) static int lbox_session_uid(struct lua_State *L) { - lua_pushnumber(L, current_session()->user.uid); + /* + * Sic: push session user, not the current user, + * which may differ inside a setuid function. + */ + lua_pushnumber(L, current_session()->credentials.uid); return 1; } @@ -80,7 +83,7 @@ lbox_session_uid(struct lua_State *L) static int lbox_session_user(struct lua_State *L) { - struct user_def *user = user_by_id(current_session()->user.uid); + struct user *user = user_by_id(current_session()->credentials.uid); if (user) lua_pushstring(L, user->name); else @@ -97,7 +100,7 @@ lbox_session_su(struct lua_State *L) struct session *session = current_session(); if (session == NULL) luaL_error(L, "session.su(): session does not exit"); - struct user_def *user; + struct user *user; if (lua_type(L, 1) == LUA_TSTRING) { size_t len; const char *name = lua_tolstring(L, 1, &len); @@ -105,7 +108,7 @@ lbox_session_su(struct lua_State *L) } else { user = user_cache_find(lua_tointeger(L, 1)); } - current_user_init(&session->user, user); + credentials_init(&session->credentials, user); return 0; } diff --git a/src/box/recovery.cc b/src/box/recovery.cc index cbfa110c2fbdac76f2c99454d1e66819b4b29fbe..de7e76240a651a75f8eb98f9755f65a1f3acb837 100644 --- a/src/box/recovery.cc +++ b/src/box/recovery.cc @@ -579,7 +579,7 @@ recovery_rescan_dir(ev_loop * loop, ev_timer *w, int /* revents */) * but to run queries we need at least a current * user. */ - fiber_set_user(fiber(), &admin_user); + fiber_set_user(fiber(), &admin_credentials); int result = recover_remaining_wals(r); fiber_set_user(fiber(), NULL); if (result < 0) @@ -597,7 +597,7 @@ recovery_rescan_file(ev_loop * loop, ev_stat *w, int /* revents */) { struct recovery_state *r = (struct recovery_state *) w->data; struct wal_watcher *watcher = r->watcher; - fiber_set_user(fiber(), &admin_user); + fiber_set_user(fiber(), &admin_credentials); int result = recover_wal(r, r->current_wal); fiber_set_user(fiber(), NULL); if (result < 0) diff --git a/src/box/session.cc b/src/box/session.cc index d274c05f9ed768da484c747fc3307d32a6aac45f..28df06060235b74e70302c242b68df984aa32f7c 100644 --- a/src/box/session.cc +++ b/src/box/session.cc @@ -78,7 +78,7 @@ session_create(int fd, uint64_t cookie) session->fd = fd; session->cookie = cookie; /* For on_connect triggers. */ - current_user_init(&session->user, user_by_token(GUEST)); + credentials_init(&session->credentials, guest_user); if (fd >= 0) random_bytes(session->salt, SESSION_SEED_SIZE); struct mh_i32ptr_node_t node; @@ -105,9 +105,9 @@ session_create_on_demand() }; /* Add a trigger to destroy session on fiber stop */ trigger_add(&fiber()->on_stop, &s->fiber_on_stop); - current_user_init(&s->user, user_by_token(ADMIN)); + credentials_init(&s->credentials, admin_user); fiber_set_session(fiber(), s); - fiber_set_user(fiber(), &s->user); + fiber_set_user(fiber(), &s->credentials); return s; } @@ -115,7 +115,7 @@ session_create_on_demand() * To quickly switch to admin user when executing * on_connect/on_disconnect triggers in iproto. */ -struct current_user admin_user; +struct credentials admin_credentials; void session_run_on_disconnect_triggers(struct session *session) @@ -123,7 +123,7 @@ session_run_on_disconnect_triggers(struct session *session) struct fiber *fiber = fiber(); /* For triggers. */ fiber_set_session(fiber, session); - fiber_set_user(fiber, &admin_user); + fiber_set_user(fiber, &admin_credentials); try { trigger_run(&session_on_disconnect, NULL); } catch (Exception *e) { @@ -139,7 +139,7 @@ session_run_on_connect_triggers(struct session *session) { struct fiber *fiber = fiber(); fiber_set_session(fiber, session); - fiber_set_user(fiber, &admin_user); + fiber_set_user(fiber, &admin_credentials); trigger_run(&session_on_connect, NULL); /* Set session user to guest, until it is authenticated. */ } @@ -169,7 +169,7 @@ session_init() if (session_registry == NULL) panic("out of memory"); mempool_create(&session_pool, &cord()->slabc, sizeof(struct session)); - current_user_init(&admin_user, user_by_token(ADMIN)); + credentials_init(&admin_credentials, admin_user); } void diff --git a/src/box/session.h b/src/box/session.h index ff0c1a16361f1edd8a6c959e994b2f6714f3c9ed..77d1fb5a128aec88db1c32419d8b5927221e2ad0 100644 --- a/src/box/session.h +++ b/src/box/session.h @@ -32,7 +32,7 @@ #include <stdbool.h> #include "trigger.h" #include "fiber.h" -#include "user_def.h" +#include "user.h" enum { SESSION_SEED_SIZE = 32, SESSION_DELIM_SIZE = 16 }; @@ -55,7 +55,7 @@ struct session { /** Authentication salt. */ char salt[SESSION_SEED_SIZE]; /** Cached user id and global grants */ - struct current_user user; + struct credentials credentials; /** Trigger for fiber on_stop to cleanup created on-demand session */ struct trigger fiber_on_stop; }; @@ -116,9 +116,9 @@ void session_storage_cleanup(int sid); static inline void -fiber_set_user(struct fiber *fiber, struct current_user *user) +fiber_set_user(struct fiber *fiber, struct credentials *cr) { - fiber_set_key(fiber, FIBER_KEY_USER, user); + fiber_set_key(fiber, FIBER_KEY_USER, cr); } static inline void @@ -139,7 +139,7 @@ session_create_on_demand(); * from ev watchers (without current fiber), but needs * to execute transactions. */ -extern struct current_user admin_user; +extern struct credentials admin_credentials; /* * When creating a new fiber, the database (box) @@ -165,18 +165,26 @@ current_session() * The same rationale for initializing the current * user on demand as in current_session() applies. */ -static inline struct current_user * +static inline struct credentials * current_user() { - struct current_user *u = - (struct current_user *) fiber_get_key(fiber(), + struct credentials *u = + (struct credentials *) fiber_get_key(fiber(), FIBER_KEY_USER); if (u == NULL) { session_create_on_demand(); - u = (struct current_user *) fiber_get_key(fiber(), + u = (struct credentials *) fiber_get_key(fiber(), FIBER_KEY_USER); } return u; } +static inline void +credentials_init(struct credentials *cr, struct user *user) +{ + cr->auth_token = user->auth_token; + cr->universal_access = user->universal_access.effective; + cr->uid = user->uid; +} + #endif /* INCLUDES_TARANTOOL_SESSION_H */ diff --git a/src/box/space.cc b/src/box/space.cc index f355f76fea4a1a39c686abc7b04f8f7527781cd4..8350b8cdd4bfb1fb9ff86abb26a7bf18c7e89542 100644 --- a/src/box/space.cc +++ b/src/box/space.cc @@ -40,7 +40,7 @@ void access_check_space(struct space *space, uint8_t access) { - struct current_user *user = current_user(); + struct credentials *cr = current_user(); /* * If a user has a global permission, clear the respective * privilege from the list of privileges required @@ -48,12 +48,12 @@ access_check_space(struct space *space, uint8_t access) * No special check for ADMIN user is necessary * since ADMIN has universal access. */ - access &= ~user->universal_access; - if (access && space->def.uid != user->uid && - access & ~space->access[user->auth_token].effective) { - struct user_def *def = user_cache_find(user->uid); + access &= ~cr->universal_access; + if (access && space->def.uid != cr->uid && + access & ~space->access[cr->auth_token].effective) { + struct user *user = user_cache_find(cr->uid); tnt_raise(ClientError, ER_SPACE_ACCESS_DENIED, - priv_name(access), def->name, space->def.name); + priv_name(access), user->name, space->def.name); } } diff --git a/src/box/user.cc b/src/box/user.cc index aab2bac5ce6d47a37c1cf3d7c6b56bcf80a6fdbc..8334b30c06e9571fa01dd448f6dcfa0c7f385e56 100644 --- a/src/box/user.cc +++ b/src/box/user.cc @@ -31,7 +31,10 @@ #include "assoc.h" #include "schema.h" -struct user_def users[BOX_USER_MAX]; +static struct user users[BOX_USER_MAX]; +struct user *guest_user = users; +struct user *admin_user = users + 1; + /** Bitmap type for used/unused authentication token map. */ typedef unsigned long user_map_t; @@ -78,61 +81,59 @@ user_map_put_slot(uint8_t auth_token) user_map_idx = auth_token; } -void -user_cache_replace(struct user_def *user) +struct user * +user_cache_replace(struct user_def *def) { - struct user_def *old = user_by_id(user->uid); - if (old == NULL) { + struct user *user = user_by_id(def->uid); + if (user == NULL) { uint8_t auth_token = user_map_get_slot(); - old = users + auth_token; - assert(old->auth_token == 0); - old->auth_token = auth_token; + user = users + auth_token; + assert(user->auth_token == 0); + user->auth_token = auth_token; + struct mh_i32ptr_node_t node = { def->uid, user }; + mh_i32ptr_put(user_registry, &node, NULL, NULL); } - user->auth_token = old->auth_token; - user->universal_access = old->universal_access; - *old = *user; - struct mh_i32ptr_node_t node = { old->uid, old }; - mh_i32ptr_put(user_registry, &node, NULL, NULL); + *(struct user_def *) user = *def; + return user; } void user_cache_delete(uint32_t uid) { - struct user_def *old = user_by_id(uid); + struct user *old = user_by_id(uid); if (old) { assert(old->auth_token > ADMIN); user_map_put_slot(old->auth_token); - old->auth_token = 0; - old->uid = 0; + memset(old, 0, sizeof(*old)); mh_i32ptr_del(user_registry, uid, NULL); } } /** Find user by id. */ -struct user_def * +struct user * user_by_id(uint32_t uid) { mh_int_t k = mh_i32ptr_find(user_registry, uid, NULL); if (k == mh_end(user_registry)) return NULL; - return (struct user_def *) mh_i32ptr_node(user_registry, k)->val; + return (struct user *) mh_i32ptr_node(user_registry, k)->val; } -struct user_def * +struct user * user_cache_find(uint32_t uid) { - struct user_def *user = user_by_id(uid); + struct user *user = user_by_id(uid); if (user) return user; tnt_raise(ClientError, ER_NO_SUCH_USER, int2str(uid)); } /** Find user by name. */ -struct user_def * +struct user * user_cache_find_by_name(const char *name, uint32_t len) { uint32_t uid = schema_find_id(SC_USER_ID, 2, name, len); - struct user_def *user = user_by_id(uid); + struct user *user = user_by_id(uid); if (user == NULL || user->type != SC_USER) { char name_buf[BOX_NAME_MAX + 1]; /* \0 - to correctly print user name the error message. */ @@ -155,26 +156,22 @@ user_cache_init() * for 'guest' and 'admin' users here, they will be * updated with snapshot contents during recovery. */ - struct user_def guest; - memset(&guest, 0, sizeof(guest)); - snprintf(guest.name, sizeof(guest.name), "guest"); - guest.owner = ADMIN; - guest.type = SC_USER; - user_cache_replace(&guest); + struct user_def def; + memset(&def, 0, sizeof(def)); + snprintf(def.name, sizeof(def.name), "guest"); + def.owner = ADMIN; + def.type = SC_USER; + struct user *user = user_cache_replace(&def); /* 0 is the auth token and user id by default. */ - assert(guest.auth_token == GUEST && - guest.uid == GUEST && - users[guest.auth_token].uid == guest.uid); + assert(user->uid == GUEST && user->auth_token == GUEST); - struct user_def admin; - memset(&admin, 0, sizeof(admin)); - snprintf(admin.name, sizeof(admin.name), "admin"); - admin.uid = admin.owner = ADMIN; - admin.type = SC_USER; - user_cache_replace(&admin); + memset(&def, 0, sizeof(def)); + snprintf(def.name, sizeof(def.name), "admin"); + def.uid = def.owner = ADMIN; + def.type = SC_USER; + user = user_cache_replace(&def); /* ADMIN is both the auth token and user id for 'admin' user. */ - assert(admin.auth_token == ADMIN && - users[admin.auth_token].uid == ADMIN); + assert(user->uid == ADMIN && user->auth_token == ADMIN); } void diff --git a/src/box/user.h b/src/box/user.h index f4ac406bbf1af43dfb8deb750f1a6079f4367214..2397639cdb8d392a31a31f0433d1bb92ee26d0ef 100644 --- a/src/box/user.h +++ b/src/box/user.h @@ -29,8 +29,19 @@ * SUCH DAMAGE. */ #include <stdint.h> +#include "user_def.h" + +struct user: public user_def +{ + /** Global privileges this user has on the universe. */ + struct access universal_access; + /** + * An id in privileges array to quickly find a + * respective privilege. + */ + uint8_t auth_token; +}; -struct user_def; /** * For best performance, all users are maintained in this array. @@ -43,7 +54,7 @@ struct user_def; * is also used to find out user privileges when accessing stored * objects, such as spaces and functions. */ -extern struct user_def users[]; +extern struct user *guest_user, *admin_user; /* * Insert or update user object (a cache entry @@ -57,7 +68,7 @@ extern struct user_def users[]; * user in it. Update user->auth_token * with an index in the users[] array. */ -void +struct user * user_cache_replace(struct user_def *user); /** @@ -68,16 +79,14 @@ void user_cache_delete(uint32_t uid); /** Find user by id. */ -struct user_def * +struct user * user_by_id(uint32_t uid); -#define user_by_token(token) (users + token) - /* Find a user by name. Used by authentication. */ -struct user_def * +struct user * user_cache_find(uint32_t uid); -struct user_def * +struct user * user_cache_find_by_name(const char *name, uint32_t len); /** Initialize the user cache and access control subsystem. */ diff --git a/src/box/user_def.h b/src/box/user_def.h index 26de9fa1adbfac9bb419e225cb794cbe34426e04..9bcf87dfe049df82dc40920baa4988cf529f01ff 100644 --- a/src/box/user_def.h +++ b/src/box/user_def.h @@ -64,21 +64,9 @@ struct user_def { char hash2[SCRAMBLE_SIZE]; /** User name - for error messages and debugging */ char name[BOX_NAME_MAX + 1]; - /** Global privileges this user has on the universe. */ - struct access universal_access; - /** An id in users[] array to quickly find user */ - uint8_t auth_token; }; /** Predefined user ids. */ enum { GUEST = 0, ADMIN = 1, PUBLIC = 2 /* role */ }; -static inline void -current_user_init(struct current_user *user, struct user_def *def) -{ - user->auth_token = def->auth_token; - user->universal_access = def->universal_access.effective; - user->uid = def->uid; -} - #endif /* TARANTOOL_BOX_USER_DEF_H_INCLUDED */