When granting or revoking a privilege on an entire entity, id 0 was used to indicate the fact that we don't grant a privilege on a single object, but on a whole entity. This caused confusion, because for entity USER, for example, id 0 is a valid object id (user 'guest' uses it). Any non-zero id dedicated to this cause obviously may be confused as well. Fix this by creating separate schema_object_types for entities: SC_ENTITY_SPACE, SC_ENTITY_USER, etc. Also now granting privileges on an entity (e.g. space) may be done in 2 ways: the old one: box.schema.user.grant('user', 'privilege', 'space') the new one: box.schema.user.grant('user', 'privilege', 'all spaces') The same applies to all entities. Closes: #3574 Prerequisite: #3524 --- https://github.com/tarantool/tarantool/tree/sergepetrenko/gh-3574-whole-entity-types https://github.com/tarantool/tarantool/issues/3574 src/box/lua/schema.lua | 87 ++++++++++++++++++++++++++++++++++++++------------ src/box/schema.cc | 16 ++++++---- src/box/schema.h | 23 +++++++------ src/box/schema_def.c | 22 ++++++++----- src/box/schema_def.h | 18 +++++++---- src/box/user.cc | 27 +++++++++------- test/box/access.result | 8 ++--- 7 files changed, 134 insertions(+), 67 deletions(-) diff --git a/src/box/lua/schema.lua b/src/box/lua/schema.lua index b9b8c9004..eb984b1de 100644 --- a/src/box/lua/schema.lua +++ b/src/box/lua/schema.lua @@ -1731,14 +1731,21 @@ local priv_object_combo = { ["universe"] = box.priv.ALL, -- sic: we allow to grant 'execute' on space. This is a legacy -- bug, please fix it in 2.0 - ["space"] = bit.bxor(box.priv.ALL, box.priv.S, - box.priv.REVOKE, box.priv.GRANT), - ["sequence"] = bit.bor(box.priv.R, box.priv.W, box.priv.U, - box.priv.C, box.priv.A, box.priv.D), - ["function"] = bit.bor(box.priv.X, box.priv.U, - box.priv.C, box.priv.D), - ["role"] = bit.bor(box.priv.X, box.priv.U, - box.priv.C, box.priv.D), + ["space"] = bit.bxor(box.priv.ALL, box.priv.S, box.priv.C, + box.priv.REVOKE, box.priv.GRANT), + ["all spaces"] = bit.bxor(box.priv.ALL, box.priv.S, + box.priv.REVOKE, box.priv.GRANT), + ["sequence"] = bit.bor(box.priv.R, box.priv.W, box.priv.U, + box.priv.A, box.priv.D), + ["all sequences"] = bit.bor(box.priv.R, box.priv.W, + box.priv.C, box.priv.A, box.priv.D), + ["function"] = bit.bor(box.priv.X, box.priv.U, + box.priv.D), + ["all functions"] = bit.bor(box.priv.X, + box.priv.C, box.priv.D), + ["role"] = bit.bor(box.priv.X, box.priv.U, + box.priv.D), + ["all roles"] = bit.bor(box.priv.C, box.priv.D), } -- @@ -1808,10 +1815,34 @@ local function object_resolve(object_type, object_name) end return 0 end - if object_type == 'space' then - if object_name == nil or object_name == 0 then - return 0 + if object_type == 'all spaces' then + if object_name ~= nil and object_name ~= 0 then + box.error(box.error.ILLEGAL_PARAMS, "no object name allowed") + end + return 0 + end + if object_type == 'all sequences' then + if object_name ~= nil and object_name ~= 0 then + box.error(box.error.ILLEGAL_PARAMS, "no object name allowed") end + return 0 + end + if object_type == 'all functions' then + if object_name ~= nil and object_name ~= 0 then + box.error(box.error.ILLEGAL_PARAMS, "no object name allowed") + end + return 0 + end + if object_type == 'all roles' then + if object_name ~= nil and object_name ~= 0 then + box.error(box.error.ILLEGAL_PARAMS, "no object name allowed") + end + return 0 + end + if object_type == 'space' then + if object_name == nil then + return nil + end local space = box.space[object_name] if space == nil then box.error(box.error.NO_SUCH_SPACE, object_name) @@ -1819,9 +1850,9 @@ local function object_resolve(object_type, object_name) return space.id end if object_type == 'function' then - if object_name == nil or object_name == 0 then - return 0 - end + if object_name == nil then + return nil + end local _vfunc = box.space[box.schema.VFUNC_ID] local func if type(object_name) == 'string' then @@ -1836,16 +1867,19 @@ local function object_resolve(object_type, object_name) end end if object_type == 'sequence' then - if object_name == nil or object_name == 0 then - return 0 - end - local seq = sequence_resolve(object_name) + if object_name == nil then + return nil + end + local seq = sequence_resolve(object_name) if seq == nil then box.error(box.error.NO_SUCH_SEQUENCE, object_name) end return seq end if object_type == 'role' then + if object_name == nil then + return nil + end local _vuser = box.space[box.schema.VUSER_ID] local role if type(object_name) == 'string' then @@ -1864,7 +1898,9 @@ local function object_resolve(object_type, object_name) end local function object_name(object_type, object_id) - if object_type == 'universe' then + if object_type == 'universe' or object_type == 'all spaces' or + object_type == 'all sequences' or object_type == 'all functions' or + object_type == 'all roles' or object_type == 'all users' then return "" end local space @@ -2079,9 +2115,14 @@ local function grant(uid, name, privilege, object_type, object_name = privilege privilege = 'execute' end - local privilege_hex = privilege_check(privilege, object_type) local oid = object_resolve(object_type, object_name) + -- allow for old syntax to grant privileges on an entity + if oid == nil then + oid = 0 + object_type = 'all ' .. object_type .. 's' + end + local privilege_hex = privilege_check(privilege, object_type) options = options or {} if options.grantor == nil then options.grantor = session.euid() @@ -2122,9 +2163,13 @@ local function revoke(uid, name, privilege, object_type, object_name, options) object_name = privilege privilege = 'execute' end - local privilege_hex = privilege_check(privilege, object_type) options = options or {} local oid = object_resolve(object_type, object_name) + if oid == nil then + oid = 0 + object_type = 'all ' .. object_type .. 's' + end + local privilege_hex = privilege_check(privilege, object_type) local _priv = box.space[box.schema.PRIV_ID] local _vpriv = box.space[box.schema.VPRIV_ID] local tuple = _vpriv:get{uid, object_type, oid} diff --git a/src/box/schema.cc b/src/box/schema.cc index 433f52c08..b81d2cd8a 100644 --- a/src/box/schema.cc +++ b/src/box/schema.cc @@ -536,10 +536,18 @@ schema_find_name(enum schema_object_type type, uint32_t object_id) switch (type) { case SC_UNIVERSE: return ""; + case SC_ENTITY_SPACE: + return "SPACE"; + case SC_ENTITY_FUNCTION: + return "FUNCTION"; + case SC_ENTITY_SEQUENCE: + return "SEQUENCE"; + case SC_ENTITY_ROLE: + return "ROLE"; + case SC_ENTITY_USER: + return "USER"; case SC_SPACE: { - if (object_id == 0) - return "SPACE"; struct space *space = space_by_id(object_id); if (space == NULL) break; @@ -547,8 +555,6 @@ schema_find_name(enum schema_object_type type, uint32_t object_id) } case SC_FUNCTION: { - if (object_id == 0) - return "FUNCTION"; struct func *func = func_by_id(object_id); if (func == NULL) break; @@ -556,8 +562,6 @@ schema_find_name(enum schema_object_type type, uint32_t object_id) } case SC_SEQUENCE: { - if (object_id == 0) - return "SEQUENCE"; struct sequence *seq = sequence_by_id(object_id); if (seq == NULL) break; diff --git a/src/box/schema.h b/src/box/schema.h index 0822262d0..f1735ff34 100644 --- a/src/box/schema.h +++ b/src/box/schema.h @@ -250,16 +250,19 @@ static inline struct access * entity_access_get(enum schema_object_type type) { - switch (type) { - case SC_SPACE: - return entity_access.space; - case SC_FUNCTION: - return entity_access.function; - case SC_SEQUENCE: - return entity_access.sequence; - default: - return NULL; - } + switch (type) { + case SC_SPACE: + case SC_ENTITY_SPACE: + return entity_access.space; + case SC_FUNCTION: + case SC_ENTITY_FUNCTION: + return entity_access.function; + case SC_SEQUENCE: + case SC_ENTITY_SEQUENCE: + return entity_access.sequence; + default: + return NULL; + } } #endif /* INCLUDES_TARANTOOL_BOX_SCHEMA_H */ diff --git a/src/box/schema_def.c b/src/box/schema_def.c index 97c074ab2..caec2e00d 100644 --- a/src/box/schema_def.c +++ b/src/box/schema_def.c @@ -31,14 +31,20 @@ #include "schema_def.h" static const char *object_type_strs[] = { - /* [SC_UKNNOWN] = */ "unknown", - /* [SC_UNIVERSE] = */ "universe", - /* [SC_SPACE] = */ "space", - /* [SC_FUNCTION] = */ "function", - /* [SC_USER] = */ "user", - /* [SC_ROLE] = */ "role", - /* [SC_SEQUENCE] = */ "sequence", - /* [SC_COLLATION] = */ "collation", + /* [SC_UKNNOWN] = */ "unknown", + /* [SC_UNIVERSE] = */ "universe", + /* [SC_SPACE] = */ "space", + /* [SC_ENTITY_SPACE] = */ "all spaces", + /* [SC_FUNCTION] = */ "function", + /* [SC_ENTITY_FUNCTION] = */ "all functions", + /* [SC_USER] = */ "user", + /* [SC_ENTITY_USER] = */ "all users", + /* [SC_ROLE] = */ "role", + /* [SC_ENTITY_ROLE] = */ "all roles", + /* [SC_SEQUENCE] = */ "sequence", + /* [SC_ENTITY_SEQUENCE] = */ "all sequences", + /* [SC_COLLATION] = */ "collation", + /* [SC_ENTITY_COLLATION] = */ "all collations", }; enum schema_object_type diff --git a/src/box/schema_def.h b/src/box/schema_def.h index 2edb8d37f..0c917094c 100644 --- a/src/box/schema_def.h +++ b/src/box/schema_def.h @@ -223,12 +223,18 @@ enum schema_object_type { SC_UNKNOWN = 0, SC_UNIVERSE = 1, SC_SPACE = 2, - SC_FUNCTION = 3, - SC_USER = 4, - SC_ROLE = 5, - SC_SEQUENCE = 6, - SC_COLLATION = 7, - schema_object_type_MAX = 8 + SC_ENTITY_SPACE = 3, + SC_FUNCTION = 4, + SC_ENTITY_FUNCTION = 5, + SC_USER = 6, + SC_ENTITY_USER = 7, + SC_ROLE = 8, + SC_ENTITY_ROLE = 9, + SC_SEQUENCE = 10, + SC_ENTITY_SEQUENCE = 11, + SC_COLLATION = 12, + SC_ENTITY_COLLATION = 13, + schema_object_type_MAX = 13 }; enum schema_object_type diff --git a/src/box/user.cc b/src/box/user.cc index fbf06566a..eec785652 100644 --- a/src/box/user.cc +++ b/src/box/user.cc @@ -207,12 +207,23 @@ access_find(struct priv_def *priv) access = universe.access; break; } + case SC_ENTITY_SPACE: + { + access = entity_access.space; + break; + } + case SC_ENTITY_FUNCTION: + { + access = entity_access.function; + break; + } + case SC_ENTITY_SEQUENCE: + { + access = entity_access.sequence; + break; + } case SC_SPACE: { - if (priv->object_id == 0) { - access = entity_access.space; - break; - } struct space *space = space_by_id(priv->object_id); if (space) access = space->access; @@ -220,10 +231,6 @@ access_find(struct priv_def *priv) } case SC_FUNCTION: { - if (priv->object_id == 0) { - access = entity_access.function; - break; - } struct func *func = func_by_id(priv->object_id); if (func) access = func->access; @@ -231,10 +238,6 @@ access_find(struct priv_def *priv) } case SC_SEQUENCE: { - if (priv->object_id == 0) { - access = entity_access.sequence; - break; - } struct sequence *seq = sequence_by_id(priv->object_id); if (seq) access = seq->access; diff --git a/test/box/access.result b/test/box/access.result index f4669a4a3..30fcb6455 100644 --- a/test/box/access.result +++ b/test/box/access.result @@ -1733,19 +1733,19 @@ box.session.su('admin') -- prerequisite gh-945 box.schema.user.grant("guest", "alter", "function") --- -- error: Unsupported function privilege 'alter' +- error: Unsupported all functions privilege 'alter' ... box.schema.user.grant("guest", "execute", "sequence") --- -- error: Unsupported sequence privilege 'execute' +- error: Unsupported all sequences privilege 'execute' ... box.schema.user.grant("guest", "read,execute", "sequence") --- -- error: Unsupported sequence privilege 'read,execute' +- error: Unsupported all sequences privilege 'read,execute' ... box.schema.user.grant("guest", "read,write,execute", "role") --- -- error: Unsupported role privilege 'read,write,execute' +- error: Unsupported all roles privilege 'read,write,execute' ... -- Check entities DML box.schema.user.create("tester", { password = '123' }) -- 2.15.2 (Apple Git-101.1)