From ad237aebef1a3b605413bca8bc31ebf362db9e90 Mon Sep 17 00:00:00 2001
From: Ilya <markovilya197@gmail.com>
Date: Wed, 13 Dec 2017 18:47:36 +0300
Subject: [PATCH] security: add object name to "access denied" error messages

Delete specifc access denied error code (ER_FUNCTION_ACCESS_DENIED,
ER_SPACE_ACCESS_DENIED, ER_FUNC_ACCESS_DENIED) and always
ER_ACCESS_DENIED code, which now contains object name and type

Pass operation type (create, drop, grant, revoke) to ER_ACCESS_DENIED.
Add a helper function schema_find_name() to schema.[h,cc].

In scope of gh-2911 "add triggers for audit log".

Heavily edited by @kostja
---
 src/box/alter.cc                  | 92 +++++++++++++++++++++----------
 src/box/call.cc                   | 11 ++--
 src/box/errcode.h                 |  8 +--
 src/box/schema.cc                 | 44 +++++++++++++++
 src/box/schema.h                  |  8 +++
 src/box/schema_def.c              |  1 +
 src/box/sequence.c                |  9 +--
 src/box/session.cc                |  5 +-
 src/box/space.c                   |  9 +--
 src/box/user_def.c                | 46 +++++++---------
 src/box/user_def.h                |  6 +-
 src/box/wal.cc                    |  2 +-
 src/trivia/util.h                 |  2 -
 test/box-py/iproto.result         |  2 +-
 test/box/access.result            | 36 ++++++------
 test/box/access_bin.result        | 16 +++---
 test/box/access_escalation.result |  2 +-
 test/box/access_misc.result       | 54 +++++++++---------
 test/box/access_sysview.result    | 10 ++--
 test/box/misc.result              | 65 +++++++++++-----------
 test/box/net.box.result           |  6 +-
 test/box/role.result              | 40 +++++++-------
 test/box/sequence.result          | 38 ++++++-------
 test/engine/truncate.result       |  2 +-
 test/replication/wal_off.result   |  4 +-
 test/replication/wal_off.test.lua |  4 +-
 test/unit/column_mask.c           |  8 +--
 27 files changed, 307 insertions(+), 223 deletions(-)

diff --git a/src/box/alter.cc b/src/box/alter.cc
index 16c1bcda53..5b3f734820 100644
--- a/src/box/alter.cc
+++ b/src/box/alter.cc
@@ -61,7 +61,9 @@
 /* {{{ Auxiliary functions and methods. */
 
 static void
-access_check_ddl(uint32_t owner_uid, enum schema_object_type type)
+access_check_ddl(const char *name, uint32_t owner_uid,
+		 enum schema_object_type type,
+		 enum priv_type priv_type)
 {
 	struct credentials *cr = effective_user();
 	/*
@@ -79,11 +81,13 @@ access_check_ddl(uint32_t owner_uid, enum schema_object_type type)
 			tnt_raise(ClientError, ER_ACCESS_DENIED,
 				  priv_name(PRIV_U),
 				  schema_object_name(SC_UNIVERSE),
+				  "",
 				  user->def->name);
 		} else {
 			tnt_raise(ClientError, ER_ACCESS_DENIED,
-				  "Create, drop or alter",
+				  priv_name(priv_type),
 				  schema_object_name(type),
+				  name,
 				  user->def->name);
 		}
 	}
@@ -1366,7 +1370,7 @@ on_replace_dd_space(struct trigger * /* trigger */, void *event)
 		struct space_def *def =
 			space_def_new_from_tuple(new_tuple, ER_CREATE_SPACE,
 						 region);
-		access_check_ddl(def->uid, SC_SPACE);
+		access_check_ddl(def->name, def->uid, SC_SPACE, PRIV_C);
 		auto def_guard =
 			make_scoped_guard([=] { space_def_delete(def); });
 		RLIST_HEAD(empty_list);
@@ -1392,7 +1396,8 @@ on_replace_dd_space(struct trigger * /* trigger */, void *event)
 			txn_alter_trigger_new(on_create_space_rollback, space);
 		txn_on_rollback(txn, on_rollback);
 	} else if (new_tuple == NULL) { /* DELETE */
-		access_check_ddl(old_space->def->uid, SC_SPACE);
+		access_check_ddl(old_space->def->name, old_space->def->uid,
+				 SC_SPACE, PRIV_D);
 		/* Verify that the space is empty (has no indexes) */
 		if (old_space->index_count) {
 			tnt_raise(ClientError, ER_DROP_SPACE,
@@ -1431,7 +1436,7 @@ on_replace_dd_space(struct trigger * /* trigger */, void *event)
 		struct space_def *def =
 			space_def_new_from_tuple(new_tuple, ER_ALTER_SPACE,
 						 region);
-		access_check_ddl(def->uid, SC_SPACE);
+		access_check_ddl(def->name, def->uid, SC_SPACE, PRIV_A);
 		auto def_guard =
 			make_scoped_guard([=] { space_def_delete(def); });
 		/*
@@ -1505,7 +1510,11 @@ on_replace_dd_index(struct trigger * /* trigger */, void *event)
 	uint32_t iid = tuple_field_u32_xc(old_tuple ? old_tuple : new_tuple,
 					  BOX_INDEX_FIELD_ID);
 	struct space *old_space = space_cache_find_xc(id);
-	access_check_ddl(old_space->def->uid, SC_SPACE);
+	enum priv_type priv_type = new_tuple ? PRIV_C : PRIV_D;
+	if (old_tuple && new_tuple)
+		priv_type = PRIV_A;
+	access_check_ddl(old_space->def->name, old_space->def->uid, SC_SPACE,
+			 priv_type);
 	struct index *old_index = space_index(old_space, iid);
 
 	/*
@@ -1937,7 +1946,7 @@ on_replace_dd_user(struct trigger * /* trigger */, void *event)
 	struct user *old_user = user_by_id(uid);
 	if (new_tuple != NULL && old_user == NULL) { /* INSERT */
 		struct user_def *user = user_def_new_from_tuple(new_tuple);
-		access_check_ddl(user->owner, SC_USER);
+		access_check_ddl(user->name, user->owner, SC_USER, PRIV_C);
 		auto def_guard = make_scoped_guard([=] { free(user); });
 		(void) user_cache_replace(user);
 		def_guard.is_active = false;
@@ -1945,7 +1954,8 @@ on_replace_dd_user(struct trigger * /* trigger */, void *event)
 			txn_alter_trigger_new(user_cache_remove_user, NULL);
 		txn_on_rollback(txn, on_rollback);
 	} else if (new_tuple == NULL) { /* DELETE */
-		access_check_ddl(old_user->def->owner, SC_USER);
+		access_check_ddl(old_user->def->name, old_user->def->owner,
+				 SC_USER, PRIV_D);
 		/* Can't drop guest or super user */
 		if (uid <= (uint32_t) BOX_SYSTEM_USER_ID_MAX) {
 			tnt_raise(ClientError, ER_DROP_USER,
@@ -1971,7 +1981,7 @@ on_replace_dd_user(struct trigger * /* trigger */, void *event)
 		 * correct.
 		 */
 		struct user_def *user = user_def_new_from_tuple(new_tuple);
-		access_check_ddl(user->uid, SC_USER);
+		access_check_ddl(user->name, user->uid, SC_USER, PRIV_A);
 		auto def_guard = make_scoped_guard([=] { free(user); });
 		struct trigger *on_commit =
 			txn_alter_trigger_new(user_cache_alter_user, NULL);
@@ -2085,7 +2095,8 @@ on_replace_dd_func(struct trigger * /* trigger */, void *event)
 		 * Can only delete func if you're the one
 		 * who created it or a superuser.
 		 */
-		access_check_ddl(uid, SC_FUNCTION);
+		access_check_ddl(old_func->def->name, uid, SC_FUNCTION,
+				 PRIV_D);
 		/* Can only delete func if it has no grants. */
 		if (schema_find_grants("function", old_func->def->fid)) {
 			tnt_raise(ClientError, ER_DROP_FUNCTION,
@@ -2098,7 +2109,7 @@ on_replace_dd_func(struct trigger * /* trigger */, void *event)
 	} else {                                /* UPDATE, REPLACE */
 		struct func_def *def = func_def_new_from_tuple(new_tuple);
 		auto def_guard = make_scoped_guard([=] { free(def); });
-		access_check_ddl(def->uid, SC_FUNCTION);
+		access_check_ddl(def->name, def->uid, SC_FUNCTION, PRIV_A);
 		struct trigger *on_commit =
 			txn_alter_trigger_new(func_cache_replace_func, NULL);
 		txn_on_commit(txn, on_commit);
@@ -2236,7 +2247,9 @@ on_replace_dd_collation(struct trigger * /* trigger */, void *event)
 						     BOX_COLLATION_FIELD_ID);
 		old_coll = coll_by_id(old_id);
 		assert(old_coll != NULL);
-		access_check_ddl(old_coll->owner_id, SC_COLLATION);
+		access_check_ddl(old_coll->name, old_coll->owner_id,
+				 SC_COLLATION,
+				 new_tuple == NULL ? PRIV_D: PRIV_A);
 
 		struct trigger *on_commit =
 			txn_alter_trigger_new(coll_cache_delete_coll, old_coll);
@@ -2256,7 +2269,8 @@ on_replace_dd_collation(struct trigger * /* trigger */, void *event)
 
 	struct coll_def new_def;
 	coll_def_new_from_tuple(new_tuple, &new_def);
-	access_check_ddl(new_def.owner_id, SC_COLLATION);
+	access_check_ddl(new_def.name, new_def.owner_id, SC_COLLATION,
+			 old_tuple == NULL ? PRIV_C : PRIV_A);
 	struct coll *new_coll = coll_new(&new_def);
 	if (new_coll == NULL)
 		diag_raise();
@@ -2310,7 +2324,7 @@ priv_def_create_from_tuple(struct priv_def *priv, struct tuple *tuple)
  * In the future we must protect grant/revoke with a logical lock.
  */
 static void
-priv_def_check(struct priv_def *priv)
+priv_def_check(struct priv_def *priv, enum priv_type priv_type)
 {
 	struct user *grantor = user_find_xc(priv->grantor_id);
 	/* May be a role */
@@ -2319,12 +2333,15 @@ priv_def_check(struct priv_def *priv)
 		tnt_raise(ClientError, ER_NO_SUCH_USER,
 			  int2str(priv->grantee_id));
 	}
-	access_check_ddl(grantor->def->uid, priv->object_type);
+	const char *name = schema_find_name(priv->object_type, priv->object_id);
+	access_check_ddl(name, grantor->def->uid, priv->object_type, priv_type);
 	switch (priv->object_type) {
 	case SC_UNIVERSE:
 		if (grantor->def->uid != ADMIN) {
 			tnt_raise(ClientError, ER_ACCESS_DENIED,
-				  "Grant", schema_object_name(priv->object_type),
+				  priv_name(priv_type),
+				  schema_object_name(SC_UNIVERSE),
+				  name,
 				  grantor->def->name);
 		}
 		break;
@@ -2334,7 +2351,8 @@ priv_def_check(struct priv_def *priv)
 		if (space->def->uid != grantor->def->uid &&
 		    grantor->def->uid != ADMIN) {
 			tnt_raise(ClientError, ER_ACCESS_DENIED,
-				  "Grant", schema_object_name(priv->object_type),
+				  priv_name(priv_type),
+				  schema_object_name(SC_SPACE), name,
 				  grantor->def->name);
 		}
 		break;
@@ -2345,7 +2363,8 @@ priv_def_check(struct priv_def *priv)
 		if (func->def->uid != grantor->def->uid &&
 		    grantor->def->uid != ADMIN) {
 			tnt_raise(ClientError, ER_ACCESS_DENIED,
-				  "Grant", schema_object_name(priv->object_type),
+				  priv_name(priv_type),
+				  schema_object_name(SC_FUNCTION), name,
 				  grantor->def->name);
 		}
 		break;
@@ -2356,7 +2375,8 @@ priv_def_check(struct priv_def *priv)
 		if (seq->def->uid != grantor->def->uid &&
 		    grantor->def->uid != ADMIN) {
 			tnt_raise(ClientError, ER_ACCESS_DENIED,
-				  "Grant", schema_object_name(priv->object_type),
+				  priv_name(priv_type),
+				  schema_object_name(SC_SEQUENCE), name,
 				  grantor->def->name);
 		}
 		break;
@@ -2377,7 +2397,9 @@ priv_def_check(struct priv_def *priv)
 		    grantor->def->uid != ADMIN &&
 		    (role->def->uid != PUBLIC || priv->access < PRIV_X)) {
 			tnt_raise(ClientError, ER_ACCESS_DENIED,
-				  "Grant", role->def->name, grantor->def->name);
+				  priv_name(priv_type),
+				  schema_object_name(SC_ROLE), name,
+				  grantor->def->name);;
 		}
 		/* Not necessary to do during revoke, but who cares. */
 		role_check(grantee, role);
@@ -2471,7 +2493,7 @@ on_replace_dd_priv(struct trigger * /* trigger */, void *event)
 			priv.access |= PRIV_S;
 			priv.access |= PRIV_U;
 		}
-		priv_def_check(&priv);
+		priv_def_check(&priv, PRIV_GRANT);
 		grant_or_revoke(&priv);
 		struct trigger *on_rollback =
 			txn_alter_trigger_new(revoke_priv, NULL);
@@ -2479,13 +2501,16 @@ on_replace_dd_priv(struct trigger * /* trigger */, void *event)
 	} else if (new_tuple == NULL) {                /* revoke */
 		assert(old_tuple);
 		priv_def_create_from_tuple(&priv, old_tuple);
-		access_check_ddl(priv.grantor_id, priv.object_type);
+		const char *name = schema_find_name(priv.object_type,
+						    priv.object_id);
+		access_check_ddl(name, priv.grantor_id, priv.object_type,
+				 PRIV_REVOKE);
 		struct trigger *on_commit =
 			txn_alter_trigger_new(revoke_priv, NULL);
 		txn_on_commit(txn, on_commit);
 	} else {                                       /* modify */
 		priv_def_create_from_tuple(&priv, new_tuple);
-		priv_def_check(&priv);
+		priv_def_check(&priv, PRIV_GRANT);
 		struct trigger *on_commit =
 			txn_alter_trigger_new(modify_priv, NULL);
 		txn_on_commit(txn, on_commit);
@@ -2772,7 +2797,8 @@ on_replace_dd_sequence(struct trigger * /* trigger */, void *event)
 						 BOX_SEQUENCE_DATA_FIELD_ID);
 		struct sequence *seq = sequence_by_id(id);
 		assert(seq != NULL);
-		access_check_ddl(seq->def->uid, SC_SEQUENCE);
+		access_check_ddl(seq->def->name, seq->def->uid, SC_SEQUENCE,
+				 PRIV_D);
 		if (space_has_data(BOX_SEQUENCE_DATA_ID, 0, id))
 			tnt_raise(ClientError, ER_DROP_SEQUENCE,
 				  seq->def->name, "the sequence has data");
@@ -2788,7 +2814,8 @@ on_replace_dd_sequence(struct trigger * /* trigger */, void *event)
 						      ER_ALTER_SEQUENCE);
 		struct sequence *seq = sequence_by_id(new_def->id);
 		assert(seq != NULL);
-		access_check_ddl(seq->def->uid, SC_SEQUENCE);
+		access_check_ddl(seq->def->name, seq->def->uid, SC_SEQUENCE,
+				 PRIV_A);
 		alter->old_def = seq->def;
 		alter->new_def = new_def;
 	}
@@ -2850,10 +2877,10 @@ on_replace_dd_space_sequence(struct trigger * /* trigger */, void *event)
 	struct txn *txn = (struct txn *) event;
 	txn_check_singlestatement_xc(txn, "Space _space_sequence");
 	struct txn_stmt *stmt = txn_current_stmt(txn);
-	struct tuple *tuple = stmt->new_tuple ?: stmt->old_tuple;
+	struct tuple *tuple = stmt->new_tuple ? stmt->new_tuple : stmt->old_tuple;
 
 	uint32_t space_id = tuple_field_u32_xc(tuple,
-				BOX_SPACE_SEQUENCE_FIELD_ID);
+					       BOX_SPACE_SEQUENCE_FIELD_ID);
 	uint32_t sequence_id = tuple_field_u32_xc(tuple,
 				BOX_SPACE_SEQUENCE_FIELD_SEQUENCE_ID);
 	bool is_generated = tuple_field_bool_xc(tuple,
@@ -2862,8 +2889,15 @@ on_replace_dd_space_sequence(struct trigger * /* trigger */, void *event)
 	struct space *space = space_cache_find_xc(space_id);
 	struct sequence *seq = sequence_cache_find(sequence_id);
 
-	access_check_ddl(space->def->uid, SC_SPACE);
-	access_check_ddl(seq->def->uid, SC_SEQUENCE);
+	/** Check we have alter access on space. */
+	access_check_ddl(space->def->name, space->def->uid, SC_SPACE, PRIV_A);
+	/* Check we have the correct access type on the sequence.  * */
+
+	enum priv_type priv_type = stmt->new_tuple ? PRIV_C : PRIV_D;
+	if (stmt->new_tuple && stmt->old_tuple)
+		priv_type = PRIV_A;
+
+	access_check_ddl(seq->def->name, seq->def->uid, SC_SEQUENCE, priv_type);
 
 	struct trigger *on_commit =
 		txn_alter_trigger_new(on_commit_dd_space_sequence, space);
diff --git a/src/box/call.cc b/src/box/call.cc
index 70eee018e4..aca8714674 100644
--- a/src/box/call.cc
+++ b/src/box/call.cc
@@ -81,13 +81,14 @@ access_check_func(const char *name, uint32_t name_len, struct func **funcp)
 			if (!(access & credentials->universal_access)) {
 				diag_set(ClientError, ER_ACCESS_DENIED,
 					 priv_name(PRIV_U),
-					 schema_object_name(SC_UNIVERSE),
+					 schema_object_name(SC_UNIVERSE), "",
 					 user->def->name);
 			} else {
-				diag_set(ClientError,
-					 ER_FUNCTION_ACCESS_DENIED,
-					 priv_name(PRIV_X), user->def->name,
-					 tt_cstr(name, name_len));
+				diag_set(ClientError, ER_ACCESS_DENIED,
+					 priv_name(PRIV_X),
+					 schema_object_name(SC_FUNCTION),
+					 tt_cstr(name, name_len),
+					 user->def->name);
 			}
 		}
 		return -1;
diff --git a/src/box/errcode.h b/src/box/errcode.h
index df4335e6a1..676bda2662 100644
--- a/src/box/errcode.h
+++ b/src/box/errcode.h
@@ -94,7 +94,7 @@ struct errcode_record {
 	/* 39 */_(ER_MIN_FIELD_COUNT,		"Tuple field count %u is less than required by space format or defined indexes (expected at least %u)") \
 	/* 40 */_(ER_WAL_IO,			"Failed to write to disk") \
 	/* 41 */_(ER_MORE_THAN_ONE_TUPLE,	"Get() doesn't support partial keys and non-unique indexes") \
-	/* 42 */_(ER_ACCESS_DENIED,		"%s access on %s is denied for user '%s'") \
+	/* 42 */_(ER_ACCESS_DENIED,		"%s access to %s '%s' is denied for user '%s'") \
 	/* 43 */_(ER_CREATE_USER,		"Failed to create user '%s': %s") \
 	/* 44 */_(ER_DROP_USER,			"Failed to drop user or role '%s': %s") \
 	/* 45 */_(ER_NO_SUCH_USER,		"User '%s' is not found") \
@@ -105,9 +105,9 @@ struct errcode_record {
 	/* 50 */_(ER_CREATE_FUNCTION,		"Failed to create function '%s': %s") \
 	/* 51 */_(ER_NO_SUCH_FUNCTION,		"Function '%s' does not exist") \
 	/* 52 */_(ER_FUNCTION_EXISTS,		"Function '%s' already exists") \
-	/* 53 */_(ER_FUNCTION_ACCESS_DENIED,	"%s access is denied for user '%s' to function '%s'") \
+	/* 53 */_(ER_UNUSED3,			"") \
 	/* 54 */_(ER_FUNCTION_MAX,		"A limit on the total number of functions has been reached: %u") \
-	/* 55 */_(ER_SPACE_ACCESS_DENIED,	"%s access is denied for user '%s' to space '%s'") \
+	/* 55 */_(ER_UNUSED4,			"") \
 	/* 56 */_(ER_USER_MAX,			"A limit on the total number of users has been reached: %u") \
 	/* 57 */_(ER_NO_SUCH_ENGINE,		"Space engine '%s' does not exist") \
 	/* 58 */_(ER_RELOAD_CFG,		"Can't set option '%s' dynamically") \
@@ -200,7 +200,7 @@ struct errcode_record {
 	/*145 */_(ER_NO_SUCH_SEQUENCE,		"Sequence '%s' does not exist") \
 	/*146 */_(ER_SEQUENCE_EXISTS,		"Sequence '%s' already exists") \
 	/*147 */_(ER_SEQUENCE_OVERFLOW,		"Sequence '%s' has overflowed") \
-	/*148 */_(ER_SEQUENCE_ACCESS_DENIED,	"%s access is denied for user '%s' to sequence '%s'") \
+	/*148 */_(ER_UNUSED5,			"") \
 	/*149 */_(ER_SPACE_FIELD_IS_DUPLICATE,	"Space field '%s' is duplicate") \
 	/*150 */_(ER_CANT_CREATE_COLLATION,	"Failed to initialize collation: %s.") \
 	/*151 */_(ER_WRONG_COLLATION_OPTIONS,	"Wrong collation options (field %u): %s") \
diff --git a/src/box/schema.cc b/src/box/schema.cc
index 8209f56532..2e8533b943 100644
--- a/src/box/schema.cc
+++ b/src/box/schema.cc
@@ -36,6 +36,7 @@
 #include "alter.h"
 #include "scoped_guard.h"
 #include "version.h"
+#include "user.h"
 #include <stdio.h>
 /**
  * @module Data Dictionary
@@ -518,3 +519,46 @@ sequence_cache_delete(uint32_t id)
 		free(seq);
 	}
 }
+
+const char *
+schema_find_name(enum schema_object_type type, uint32_t object_id)
+{
+	switch (type) {
+	case SC_UNIVERSE:
+		return "";
+	case SC_SPACE:
+		{
+			struct space *space = space_by_id(object_id);
+			if (space == NULL)
+				break;
+			return space->def->name;
+		}
+	case SC_FUNCTION:
+		{
+			struct func *func = func_by_id(object_id);
+			if (func == NULL)
+				break;
+			return func->def->name;
+		}
+	case SC_SEQUENCE:
+		{
+			struct sequence *seq = sequence_by_id(object_id);
+			if (seq == NULL)
+				break;
+			return seq->def->name;
+		}
+	case SC_ROLE:
+	case SC_USER:
+		{
+			struct user *role = user_by_id(object_id);
+			if (role == NULL)
+				break;
+			return role->def->name;
+		}
+	default:
+		break;
+	}
+	assert(false);
+	return "(nil)";
+}
+
diff --git a/src/box/schema.h b/src/box/schema.h
index 07ae503f46..7a1cbbf99b 100644
--- a/src/box/schema.h
+++ b/src/box/schema.h
@@ -89,6 +89,14 @@ func_by_name(const char *name, uint32_t name_len);
 int
 space_foreach(int (*func)(struct space *sp, void *udata), void *udata);
 
+/**
+ * Try to look up object name by id and type of object.
+ *
+ * @return NULL if object of type not found, otherwise name of object.
+ */
+const char *
+schema_find_name(enum schema_object_type type, uint32_t object_id);
+
 #if defined(__cplusplus)
 } /* extern "C" */
 
diff --git a/src/box/schema_def.c b/src/box/schema_def.c
index 492c593dba..d9f924d660 100644
--- a/src/box/schema_def.c
+++ b/src/box/schema_def.c
@@ -59,6 +59,7 @@ schema_object_type(const char *name)
 const char *
 schema_object_name(enum schema_object_type type)
 {
+	assert((int) type < (int) schema_object_type_MAX);
 	return object_type_strs[type];
 }
 
diff --git a/src/box/sequence.c b/src/box/sequence.c
index 881cf61ee9..b549e09d5a 100644
--- a/src/box/sequence.c
+++ b/src/box/sequence.c
@@ -258,13 +258,14 @@ access_check_sequence(struct sequence *seq)
 			if (!(cr->universal_access & PRIV_U)) {
 				diag_set(ClientError, ER_ACCESS_DENIED,
 					 priv_name(PRIV_U),
-					 schema_object_name(SC_UNIVERSE),
+					 schema_object_name(SC_UNIVERSE), "",
 					 user->def->name);
 			} else {
 				diag_set(ClientError,
-					 ER_SEQUENCE_ACCESS_DENIED,
-					 priv_name(access), user->def->name,
-					 seq->def->name);
+					 ER_ACCESS_DENIED,
+					 priv_name(access),
+					 schema_object_name(SC_SEQUENCE),
+					 seq->def->name, user->def->name);
 			}
 		}
 		return -1;
diff --git a/src/box/session.cc b/src/box/session.cc
index aff8657c78..b5d72ea700 100644
--- a/src/box/session.cc
+++ b/src/box/session.cc
@@ -242,7 +242,7 @@ access_check_session(struct user *user)
 	 */
 	if (!(universe.access[user->auth_token].effective & PRIV_S)) {
 		diag_set(ClientError, ER_ACCESS_DENIED, priv_name(PRIV_S),
-			 schema_object_name(SC_UNIVERSE),
+			 schema_object_name(SC_UNIVERSE), "",
 			 user->def->name);
 		return -1;
 	}
@@ -273,6 +273,7 @@ access_check_universe(user_access_t access)
 					       & access) ^ access);
 		tnt_raise(ClientError, ER_ACCESS_DENIED,
 			 priv_name(denied_access),
-			 schema_object_name(SC_UNIVERSE), user->def->name);
+			 schema_object_name(SC_UNIVERSE), "",
+			 user->def->name);
 	}
 }
diff --git a/src/box/space.c b/src/box/space.c
index d49538a50e..212aa1cd77 100644
--- a/src/box/space.c
+++ b/src/box/space.c
@@ -68,13 +68,14 @@ access_check_space(struct space *space, user_access_t access)
 			if (!(cr->universal_access & PRIV_U)) {
 				diag_set(ClientError, ER_ACCESS_DENIED,
 					 priv_name(PRIV_U),
-					 schema_object_name(SC_UNIVERSE),
+					 schema_object_name(SC_UNIVERSE), "",
 					 user->def->name);
 			} else {
 				diag_set(ClientError,
-					 ER_SPACE_ACCESS_DENIED,
-					 priv_name(access), user->def->name,
-					 space->def->name);
+					 ER_ACCESS_DENIED,
+					 priv_name(access),
+					 schema_object_name(SC_SPACE),
+					 space->def->name, user->def->name);
 			}
 		}
 		return -1;
diff --git a/src/box/user_def.c b/src/box/user_def.c
index def541fd0e..7d78377134 100644
--- a/src/box/user_def.c
+++ b/src/box/user_def.c
@@ -32,32 +32,26 @@
 const char *
 priv_name(user_access_t access)
 {
-	if (access & PRIV_R)
-		return "Read";
-	if (access & PRIV_W)
-		return "Write";
-	if (access & PRIV_X)
-		return "Execute";
-	if (access & PRIV_S)
-		return "Session";
-	if (access & PRIV_U)
-		return "Usage";
-	if (access & PRIV_C)
-		return "Create";
-	if (access & PRIV_D)
-		return "Drop";
-	if (access & PRIV_A)
-		return "Alter";
-	if (access & PRIV_REFERENCE)
-		return "Reference";
-	if (access & PRIV_TRIGGER)
-		return "Trigger";
-	if (access & PRIV_INSERT)
-		return "Insert";
-	if (access & PRIV_UPDATE)
-		return "Update";
-	if (access & PRIV_DELETE)
-		return "Delete";
+	static const char *priv_name_strs[] = {
+		"Read",
+		"Write",
+		"Execute",
+		"Session",
+		"Usage",
+		"Create",
+		"Drop",
+		"Alter",
+		"Reference",
+		"Trigger",
+		"Insert",
+		"Update",
+		"Delete",
+		"Grant",
+		"Revoke",
+	};
+	int bit_no = __builtin_ffs((int) access);
+	if (bit_no > 0 && bit_no <= (int) lengthof(priv_name_strs))
+		return priv_name_strs[bit_no - 1];
 	return "Any";
 }
 
diff --git a/src/box/user_def.h b/src/box/user_def.h
index f23fc3bb5a..1104ec634a 100644
--- a/src/box/user_def.h
+++ b/src/box/user_def.h
@@ -58,7 +58,7 @@ struct credentials {
 	uint32_t uid;
 };
 
-enum {
+enum priv_type {
 	/* SELECT */
 	PRIV_R = 1,
 	/* INSERT, UPDATE, UPSERT, DELETE, REPLACE */
@@ -85,6 +85,10 @@ enum {
 	PRIV_UPDATE = 2048,
 	/* DELETE - required by ANSI - not implemented */
 	PRIV_DELETE = 4096,
+	/* This is never granted, but used internally. */
+	PRIV_GRANT = 8192,
+	/* Never granted, but used internally. */
+	PRIV_REVOKE = 16384,
 	/* all bits */
 	PRIV_ALL  = ~((user_access_t) 0),
 };
diff --git a/src/box/wal.cc b/src/box/wal.cc
index 1e62564370..0c4dd3de2b 100644
--- a/src/box/wal.cc
+++ b/src/box/wal.cc
@@ -954,7 +954,7 @@ wal_set_watcher(struct wal_watcher *watcher, const char *name,
 	watcher->msg.cmsg.route = NULL;
 	watcher->events = 0;
 
-	assert(ARRAY_LENGTH(watcher->route) == 2);
+	assert(lengthof(watcher->route) == 2);
 	watcher->route[0] = {wal_watcher_notify_perform, &watcher->wal_pipe};
 	watcher->route[1] = {wal_watcher_notify_complete, NULL};
 
diff --git a/src/trivia/util.h b/src/trivia/util.h
index f87ad4c910..c6e8faa221 100644
--- a/src/trivia/util.h
+++ b/src/trivia/util.h
@@ -65,8 +65,6 @@ extern "C" {
 
 #define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
 
-#define ARRAY_LENGTH(arr) (sizeof(arr) / sizeof(arr[0]))
-
 /* Macros to define enum and corresponding strings. */
 #define ENUM0_MEMBER(s, ...) s,
 #define ENUM_MEMBER(s, v, ...) s = v,
diff --git a/test/box-py/iproto.result b/test/box-py/iproto.result
index 292aa83e93..6e1f37a00e 100644
--- a/test/box-py/iproto.result
+++ b/test/box-py/iproto.result
@@ -175,7 +175,7 @@ box.schema.user.revoke('guest', 'read,write,execute', 'universe')
 
 sync=0, {49: 'Invalid MsgPack - packet header'}
 sync=1234, {49: "Missing mandatory field 'space id' in request"}
-sync=5678, {49: "Read access is denied for user 'guest' to space '_user'"}
+sync=5678, {49: "Read access to space '_user' is denied for user 'guest'"}
 space = box.schema.space.create('test_index_base', { id = 568 })
 ---
 ...
diff --git a/test/box/access.result b/test/box/access.result
index afbed171d4..c8cc9f0923 100644
--- a/test/box/access.result
+++ b/test/box/access.result
@@ -56,7 +56,7 @@ session.su('test')
 -- in future we may  introduce a separate privilege
 box.schema.space.create('test')
 ---
-- error: Write access is denied for user 'test' to space '_schema'
+- error: Write access to space '_schema' is denied for user 'test'
 ...
 -- su() goes through because called from admin
 -- console, and it has no access checks
@@ -274,21 +274,21 @@ c = (require 'net.box').connect(LISTEN.host, LISTEN.service)
 ...
 c:call('nosuchfunction')
 ---
-- error: Execute access is denied for user 'guest' to function 'nosuchfunction'
+- error: Execute access to function 'nosuchfunction' is denied for user 'guest'
 ...
 function nosuchfunction() end
 ---
 ...
 c:call('nosuchfunction')
 ---
-- error: Execute access is denied for user 'guest' to function 'nosuchfunction'
+- error: Execute access to function 'nosuchfunction' is denied for user 'guest'
 ...
 nosuchfunction = nil
 ---
 ...
 c:call('nosuchfunction')
 ---
-- error: Execute access is denied for user 'guest' to function 'nosuchfunction'
+- error: Execute access to function 'nosuchfunction' is denied for user 'guest'
 ...
 c:close()
 ---
@@ -364,7 +364,7 @@ box.schema.user.create('grantee')
 ...
 box.schema.user.grant('grantee', 'read, write, execute', 'universe')  
 ---
-- error: Grant access on universe is denied for user 'grantor'
+- error: Grant access to universe '' is denied for user 'grantor'
 ...
 session.su('grantee')
 ---
@@ -372,7 +372,7 @@ session.su('grantee')
 -- fails - can't suicide - ask the creator to kill you
 box.schema.user.drop('grantee')
 ---
-- error: Read access is denied for user 'grantee' to space '_user'
+- error: Read access to space '_user' is denied for user 'grantee'
 ...
 session.su('grantor')
 ---
@@ -403,11 +403,11 @@ session.su('guest')
 ...
 box.space._user:select{0}
 ---
-- error: Read access is denied for user 'guest' to space '_user'
+- error: Read access to space '_user' is denied for user 'guest'
 ...
 box.space._user:select{1}
 ---
-- error: Read access is denied for user 'guest' to space '_user'
+- error: Read access to space '_user' is denied for user 'guest'
 ...
 session.su('admin')
 ---
@@ -457,7 +457,7 @@ session.su('user1')
 -- permission denied
 box.schema.user.passwd('admin', 'xxx')
 ---
-- error: Read access is denied for user 'user1' to space '_user'
+- error: Read access to space '_user' is denied for user 'user1'
 ...
 session.su('admin')
 ---
@@ -839,7 +839,7 @@ session.su('test')
 ...
 box.internal.collation.drop('test') -- fail
 ---
-- error: Create, drop or alter access on collation is denied for user 'test'
+- error: Drop access to collation 'test' is denied for user 'test'
 ...
 session.su('admin')
 ---
@@ -990,7 +990,7 @@ session.su("test1")
 ...
 box.schema.user.disable("test")
 ---
-- error: Read access is denied for user 'test1' to space '_user'
+- error: Read access to space '_user' is denied for user 'test1'
 ...
 session.su("admin")
 ---
@@ -1004,7 +1004,7 @@ box.schema.user.disable("test")
 ...
 session.su("test")
 ---
-- error: Session access on universe is denied for user 'test'
+- error: Session access to universe '' is denied for user 'test'
 ...
 c = (require 'net.box').connect(LISTEN.host, LISTEN.service, {user="test", password="pass"})
 ---
@@ -1015,14 +1015,14 @@ c.state
 ...
 c.error
 ---
-- Session access on universe is denied for user 'test'
+- Session access to universe '' is denied for user 'test'
 ...
 session.su("test1")
 ---
 ...
 box.schema.user.grant("test", "usage", "universe")
 ---
-- error: Read access is denied for user 'test1' to space '_user'
+- error: Read access to space '_user' is denied for user 'test1'
 ...
 session.su('admin')
 ---
@@ -1035,7 +1035,7 @@ session.su("test")
 ...
 s:select{}
 ---
-- error: Usage access on universe is denied for user 'test'
+- error: Usage access to universe '' is denied for user 'test'
 ...
 session.su('admin')
 ---
@@ -1104,15 +1104,15 @@ box.session.su('guest')
 ...
 box.schema.space.create('test')
 ---
-- error: Write access is denied for user 'guest' to space '_schema'
+- error: Write access to space '_schema' is denied for user 'guest'
 ...
 box.schema.user.create('test')
 ---
-- error: Read access is denied for user 'guest' to space '_user'
+- error: Read access to space '_user' is denied for user 'guest'
 ...
 box.schema.func.create('test')
 ---
-- error: Read access is denied for user 'guest' to space '_func'
+- error: Read access to space '_func' is denied for user 'guest'
 ...
 box.session.su('admin')
 ---
diff --git a/test/box/access_bin.result b/test/box/access_bin.result
index e3b5e3fdba..b81279cfe0 100644
--- a/test/box/access_bin.result
+++ b/test/box/access_bin.result
@@ -55,14 +55,14 @@ c = remote.connect(box.cfg.listen)
 ...
 c:call("setuid_func")
 ---
-- error: Read access is denied for user 'guest' to space 'setuid_space'
+- error: Read access to space 'setuid_space' is denied for user 'guest'
 ...
 session.su('guest')
 ---
 ...
 setuid_func()
 ---
-- error: Read access is denied for user 'guest' to space 'setuid_space'
+- error: Read access to space 'setuid_space' is denied for user 'guest'
 ...
 session.su('admin')
 ---
@@ -85,7 +85,7 @@ session.su('guest')
 ...
 setuid_func()
 ---
-- error: Read access is denied for user 'guest' to space 'setuid_space'
+- error: Read access to space 'setuid_space' is denied for user 'guest'
 ...
 session.su('admin')
 ---
@@ -122,7 +122,7 @@ session.su('guest')
 ...
 setuid_func()
 ---
-- error: Read access is denied for user 'guest' to space 'setuid_space'
+- error: Read access to space 'setuid_space' is denied for user 'guest'
 ...
 session.su('admin')
 ---
@@ -244,14 +244,14 @@ c = net.connect('test:test@'..box.cfg.listen)
 ...
 c.space.test:select{}
 ---
-- error: Read access is denied for user 'test' to space 'test'
+- error: Read access to space 'test' is denied for user 'test'
 ...
 box.schema.role.grant('public', 'read', 'universe')
 ---
 ...
 c.space.test:select{}
 ---
-- error: Read access is denied for user 'test' to space 'test'
+- error: Read access to space 'test' is denied for user 'test'
 ...
 c:close()
 ---
@@ -275,7 +275,7 @@ box.session.su('test')
 ...
 test:select{}
 ---
-- error: Read access is denied for user 'test' to space 'test'
+- error: Read access to space 'test' is denied for user 'test'
 ...
 box.session.su('admin')
 ---
@@ -314,7 +314,7 @@ c = net.connect(box.cfg.listen)
 -- should return access denied
 c:call('f1')
 ---
-- error: Read access is denied for user 'guest' to space '_func'
+- error: Read access to space '_func' is denied for user 'guest'
 ...
 -- should work (used to return access denied, because was not setuid
 c:call('f2')
diff --git a/test/box/access_escalation.result b/test/box/access_escalation.result
index 5d077d3763..9d6cb997ff 100644
--- a/test/box/access_escalation.result
+++ b/test/box/access_escalation.result
@@ -53,7 +53,7 @@ background = fiber.create(function() connection:call("setuid") end)
 ...
 connection:call("escalation")
 ---
-- error: Read access is denied for user 'guest' to space '_space'
+- error: Read access to space '_space' is denied for user 'guest'
 ...
 fiber.cancel(background)
 ---
diff --git a/test/box/access_misc.result b/test/box/access_misc.result
index 53e86a3359..67234ab243 100644
--- a/test/box/access_misc.result
+++ b/test/box/access_misc.result
@@ -70,15 +70,15 @@ s:select(1)
 ...
 s:insert({3})
 ---
-- error: Write access is denied for user 'testus' to space 'admin_space'
+- error: Write access to space 'admin_space' is denied for user 'testus'
 ...
 s:delete(1)
 ---
-- error: Write access is denied for user 'testus' to space 'admin_space'
+- error: Write access to space 'admin_space' is denied for user 'testus'
 ...
 s:drop()
 ---
-- error: Write access is denied for user 'testus' to space '_space_sequence'
+- error: Write access to space '_space_sequence' is denied for user 'testus'
 ...
 --
 -- Check double revoke
@@ -98,7 +98,7 @@ session.su('testus')
 ...
 s:select(1)
 ---
-- error: Read access is denied for user 'testus' to space 'admin_space'
+- error: Read access to space 'admin_space' is denied for user 'testus'
 ...
 session.su('admin')
 ---
@@ -114,7 +114,7 @@ session.su('testus')
 ...
 s:select(1)
 ---
-- error: Read access is denied for user 'testus' to space 'admin_space'
+- error: Read access to space 'admin_space' is denied for user 'testus'
 ...
 s:delete(1)
 ---
@@ -126,7 +126,7 @@ s:insert({3})
 ...
 s:drop()
 ---
-- error: Write access is denied for user 'testus' to space '_space_sequence'
+- error: Write access to space '_space_sequence' is denied for user 'testus'
 ...
 session.su('admin')
 ---
@@ -153,31 +153,31 @@ session.uid()
 ...
 box.space._user:select(1)
 ---
-- error: Read access is denied for user 'guest' to space '_user'
+- error: Read access to space '_user' is denied for user 'guest'
 ...
 s:select(1)
 ---
-- error: Read access is denied for user 'guest' to space 'admin_space'
+- error: Read access to space 'admin_space' is denied for user 'guest'
 ...
 s:insert({4})
 ---
-- error: Write access is denied for user 'guest' to space 'admin_space'
+- error: Write access to space 'admin_space' is denied for user 'guest'
 ...
 s:delete({3})
 ---
-- error: Write access is denied for user 'guest' to space 'admin_space'
+- error: Write access to space 'admin_space' is denied for user 'guest'
 ...
 s:drop()
 ---
-- error: Write access is denied for user 'guest' to space '_space_sequence'
+- error: Write access to space '_space_sequence' is denied for user 'guest'
 ...
 gs = box.schema.space.create('guest_space')
 ---
-- error: Write access is denied for user 'guest' to space '_schema'
+- error: Write access to space '_schema' is denied for user 'guest'
 ...
 box.schema.func.create('guest_func')
 ---
-- error: Read access is denied for user 'guest' to space '_func'
+- error: Read access to space '_func' is denied for user 'guest'
 ...
 session.su('admin')
 ---
@@ -288,15 +288,15 @@ session.su('someuser')
 --
 s:drop()
 ---
-- error: Create, drop or alter access on space is denied for user 'someuser'
+- error: Drop access to space 'admin_space' is denied for user 'someuser'
 ...
 us:drop()
 ---
-- error: Create, drop or alter access on space is denied for user 'someuser'
+- error: Drop access to space 'uniuser_space' is denied for user 'someuser'
 ...
 box.schema.func.drop('uniuser_func')
 ---
-- error: Create, drop or alter access on function is denied for user 'someuser'
+- error: Drop access to function 'uniuser_func' is denied for user 'someuser'
 ...
 box.schema.user.drop('uniuser_testus')
 ---
@@ -344,11 +344,11 @@ testuser_uid = session.uid()
 ...
 box.space._user:delete(2)
 ---
-- error: Create, drop or alter access on user is denied for user 'testuser'
+- error: Drop access to user 'public' is denied for user 'testuser'
 ...
 box.space._user:select(1)
 ---
-- error: Read access is denied for user 'testuser' to space '_user'
+- error: Read access to space '_user' is denied for user 'testuser'
 ...
 uid = box.space._user:insert{maxuid+1, session.uid(), 'someone', 'user', EMPTY_MAP}[1]
 ---
@@ -382,7 +382,7 @@ session.su('testuser')
 ...
 box.space._user:delete(2)
 ---
-- error: Write access is denied for user 'testuser' to space '_user'
+- error: Write access to space '_user' is denied for user 'testuser'
 ...
 box.space._user:select(1)
 ---
@@ -390,7 +390,7 @@ box.space._user:select(1)
 ...
 box.space._user:insert{uid, session.uid(), 'someone2', 'user'}
 ---
-- error: Write access is denied for user 'testuser' to space '_user'
+- error: Write access to space '_user' is denied for user 'testuser'
 ...
 session.su('admin')
 ---
@@ -410,7 +410,7 @@ box.space._index:select(272)
 ...
 box.space._index:insert{512, 1,'owner','tree', 1, 1, 0,'unsigned'}
 ---
-- error: Write access is denied for user 'testuser' to space '_index'
+- error: Write access to space '_index' is denied for user 'testuser'
 ...
 session.su('admin')
 ---
@@ -502,11 +502,11 @@ session.su('testuser')
 ...
 s:select()
 ---
-- error: Read access is denied for user 'testuser' to space 'glade'
+- error: Read access to space 'glade' is denied for user 'testuser'
 ...
 for key, v in s.index.primary:pairs(1, {iterator = 'GE'}) do table.insert (t, v) end 
 ---
-- error: Read access is denied for user 'testuser' to space 'glade'
+- error: Read access to space 'glade' is denied for user 'testuser'
 ...
 t
 ---
@@ -547,11 +547,11 @@ session.su('guest')
 ...
 s:select()
 ---
-- error: Read access is denied for user 'guest' to space 'glade'
+- error: Read access to space 'glade' is denied for user 'guest'
 ...
 for key, v in s.index.primary:pairs(3, {iterator = 'GE'}) do table.insert (t, v) end 
 ---
-- error: Read access is denied for user 'guest' to space 'glade'
+- error: Read access to space 'glade' is denied for user 'guest'
 ...
 t
 ---
@@ -565,11 +565,11 @@ session.su('guest')
 ...
 s:select()
 ---
-- error: Read access is denied for user 'guest' to space 'glade'
+- error: Read access to space 'glade' is denied for user 'guest'
 ...
 for key, v in s.index.primary:pairs(3, {iterator = 'GE'}) do table.insert (t, v) end 
 ---
-- error: Read access is denied for user 'guest' to space 'glade'
+- error: Read access to space 'glade' is denied for user 'guest'
 ...
 t
 ---
diff --git a/test/box/access_sysview.result b/test/box/access_sysview.result
index 5f16ed10bd..16aa8cb8b0 100644
--- a/test/box/access_sysview.result
+++ b/test/box/access_sysview.result
@@ -105,23 +105,23 @@ box.session.su('guest')
 ...
 #box.space._vspace:select{}
 ---
-- error: Read access is denied for user 'guest' to space '_vspace'
+- error: Read access to space '_vspace' is denied for user 'guest'
 ...
 #box.space._vindex:select{}
 ---
-- error: Read access is denied for user 'guest' to space '_vindex'
+- error: Read access to space '_vindex' is denied for user 'guest'
 ...
 #box.space._vuser:select{}
 ---
-- error: Read access is denied for user 'guest' to space '_vuser'
+- error: Read access to space '_vuser' is denied for user 'guest'
 ...
 #box.space._vpriv:select{}
 ---
-- error: Read access is denied for user 'guest' to space '_vpriv'
+- error: Read access to space '_vpriv' is denied for user 'guest'
 ...
 #box.space._vfunc:select{}
 ---
-- error: Read access is denied for user 'guest' to space '_vfunc'
+- error: Read access to space '_vfunc' is denied for user 'guest'
 ...
 box.session.su('admin')
 ---
diff --git a/test/box/misc.result b/test/box/misc.result
index 4d27653fa3..d35567e314 100644
--- a/test/box/misc.result
+++ b/test/box/misc.result
@@ -329,7 +329,7 @@ t;
   - 'box.error.MODIFY_INDEX : 14'
   - 'box.error.PASSWORD_MISMATCH : 47'
   - 'box.error.UNSUPPORTED_ROLE_PRIV : 98'
-  - 'box.error.SPLICE : 25'
+  - 'box.error.ACCESS_DENIED : 42'
   - 'box.error.CANT_CREATE_COLLATION : 150'
   - 'box.error.USER_EXISTS : 46'
   - 'box.error.WAL_IO : 40'
@@ -344,10 +344,9 @@ t;
   - 'box.error.VINYL_MAX_TUPLE_SIZE : 139'
   - 'box.error.LOAD_FUNCTION : 99'
   - 'box.error.INVALID_XLOG : 74'
-  - 'box.error.PRIV_NOT_GRANTED : 91'
+  - 'box.error.READ_VIEW_ABORTED : 130'
   - 'box.error.TRANSACTION_CONFLICT : 97'
   - 'box.error.GUEST_USER_PASSWORD : 96'
-  - 'box.error.SEQUENCE_ACCESS_DENIED : 148'
   - 'box.error.PROC_C : 102'
   - 'box.error.INVALID_RUN_FILE : 132'
   - 'box.error.NONMASTER : 6'
@@ -355,7 +354,7 @@ t;
   - 'box.error.DROP_FUNCTION : 71'
   - 'box.error.CFG : 59'
   - 'box.error.NO_SUCH_FIELD : 37'
-  - 'box.error.MORE_THAN_ONE_TUPLE : 41'
+  - 'box.error.CONNECTION_TO_SELF : 117'
   - 'box.error.FUNCTION_MAX : 54'
   - 'box.error.ILLEGAL_PARAMS : 1'
   - 'box.error.PARTIAL_KEY : 136'
@@ -383,82 +382,80 @@ t;
   - 'box.error.FUNCTION_EXISTS : 52'
   - 'box.error.UPDATE_ARG_TYPE : 26'
   - 'box.error.CROSS_ENGINE_TRANSACTION : 81'
-  - 'box.error.IDENTIFIER : 70'
-  - 'box.error.injection : table: <address>
+  - 'box.error.FORMAT_MISMATCH_INDEX_PART : 27'
   - 'box.error.NO_SUCH_ENGINE : 57'
   - 'box.error.COMMIT_IN_SUB_STMT : 122'
-  - 'box.error.NULLABLE_MISMATCH : 153'
-  - 'box.error.PROC_RET : 21'
+  - 'box.error.injection : table: <address>
   - 'box.error.LAST_DROP : 15'
-  - 'box.error.SPACE_FIELD_IS_DUPLICATE : 149'
+  - 'box.error.NULLABLE_MISMATCH : 153'
   - 'box.error.DECOMPRESSION : 124'
   - 'box.error.CREATE_SEQUENCE : 142'
   - 'box.error.CREATE_USER : 43'
-  - 'box.error.SEQUENCE_OVERFLOW : 147'
+  - 'box.error.ITERATOR_TYPE : 72'
   - 'box.error.INSTANCE_UUID_MISMATCH : 66'
-  - 'box.error.INJECTION : 8'
+  - 'box.error.SPACE_FIELD_IS_DUPLICATE : 149'
   - 'box.error.SYSTEM : 115'
   - 'box.error.KEY_PART_IS_TOO_LONG : 118'
-  - 'box.error.RELOAD_CFG : 58'
-  - 'box.error.TRUNCATE_SYSTEM_SPACE : 137'
+  - 'box.error.SEQUENCE_OVERFLOW : 147'
+  - 'box.error.INJECTION : 8'
   - 'box.error.NO_SUCH_SAVEPOINT : 61'
-  - 'box.error.VY_QUOTA_TIMEOUT : 135'
-  - 'box.error.READ_VIEW_ABORTED : 130'
+  - 'box.error.INVALID_XLOG_TYPE : 125'
+  - 'box.error.TRUNCATE_SYSTEM_SPACE : 137'
   - 'box.error.WRONG_INDEX_OPTIONS : 108'
   - 'box.error.INVALID_VYLOG_FILE : 133'
   - 'box.error.INDEX_FIELD_COUNT_LIMIT : 127'
-  - 'box.error.INVALID_XLOG_TYPE : 125'
+  - 'box.error.VY_QUOTA_TIMEOUT : 135'
   - 'box.error.USER_MAX : 56'
-  - 'box.error.PROTOCOL : 104'
+  - 'box.error.PROC_RET : 21'
   - 'box.error.TUPLE_NOT_ARRAY : 22'
   - 'box.error.KEY_PART_COUNT : 31'
   - 'box.error.ALTER_SPACE : 12'
   - 'box.error.ACTIVE_TRANSACTION : 79'
   - 'box.error.EXACT_FIELD_COUNT : 38'
   - 'box.error.DROP_SEQUENCE : 144'
-  - 'box.error.UNSUPPORTED : 5'
-  - 'box.error.UPSERT_UNIQUE_SECONDARY_KEY : 105'
-  - 'box.error.UNKNOWN_REQUEST_TYPE : 48'
+  - 'box.error.RELOAD_CFG : 58'
+  - 'box.error.PROC_LUA : 32'
+  - 'box.error.MORE_THAN_ONE_TUPLE : 41'
   - 'box.error.SUB_STMT_MAX : 121'
-  - 'box.error.FORMAT_MISMATCH_INDEX_PART : 27'
+  - 'box.error.UPSERT_UNIQUE_SECONDARY_KEY : 105'
   - 'box.error.SPACE_EXISTS : 10'
-  - 'box.error.ROLE_NOT_GRANTED : 92'
+  - 'box.error.UNKNOWN_REQUEST_TYPE : 48'
   - 'box.error.UNKNOWN : 0'
   - 'box.error.NO_SUCH_SPACE : 36'
   - 'box.error.WRONG_INDEX_PARTS : 107'
+  - 'box.error.ROLE_NOT_GRANTED : 92'
+  - 'box.error.SPLICE : 25'
   - 'box.error.MIN_FIELD_COUNT : 39'
   - 'box.error.REPLICASET_UUID_MISMATCH : 63'
+  - 'box.error.COMPRESSION : 119'
+  - 'box.error.INVALID_ORDER : 68'
   - 'box.error.UPDATE_FIELD : 29'
   - 'box.error.INDEX_EXISTS : 85'
-  - 'box.error.COMPRESSION : 119'
-  - 'box.error.SPACE_ACCESS_DENIED : 55'
-  - 'box.error.DROP_SPACE : 11'
-  - 'box.error.PROC_LUA : 32'
-  - 'box.error.REPLICA_MAX : 73'
+  - 'box.error.TUPLE_FORMAT_LIMIT : 16'
   - 'box.error.DROP_PRIMARY_KEY : 17'
   - 'box.error.NULLABLE_PRIMARY : 152'
   - 'box.error.NO_SUCH_SEQUENCE : 145'
-  - 'box.error.INVALID_ORDER : 68'
+  - 'box.error.UNSUPPORTED : 5'
   - 'box.error.INVALID_UUID : 64'
-  - 'box.error.ITERATOR_TYPE : 72'
+  - 'box.error.IDENTIFIER : 70'
   - 'box.error.TIMEOUT : 78'
-  - 'box.error.TUPLE_FORMAT_LIMIT : 16'
-  - 'box.error.NO_SUCH_ROLE : 82'
+  - 'box.error.REPLICA_MAX : 73'
+  - 'box.error.DROP_SPACE : 11'
   - 'box.error.INVALID_MSGPACK : 20'
   - 'box.error.MISSING_REQUEST_FIELD : 69'
   - 'box.error.MISSING_SNAPSHOT : 93'
   - 'box.error.WRONG_SPACE_OPTIONS : 111'
   - 'box.error.READONLY : 7'
   - 'box.error.UPDATE_INTEGER_OVERFLOW : 95'
-  - 'box.error.ACCESS_DENIED : 42'
+  - 'box.error.NO_SUCH_ROLE : 82'
   - 'box.error.NO_CONNECTION : 77'
   - 'box.error.INVALID_XLOG_ORDER : 76'
   - 'box.error.WRONG_SCHEMA_VERSION : 109'
   - 'box.error.ROLLBACK_IN_SUB_STMT : 123'
   - 'box.error.UNSUPPORTED_INDEX_FEATURE : 112'
-  - 'box.error.CONNECTION_TO_SELF : 117'
+  - 'box.error.PROTOCOL : 104'
   - 'box.error.INDEX_PART_TYPE_MISMATCH : 24'
-  - 'box.error.FUNCTION_ACCESS_DENIED : 53'
+  - 'box.error.PRIV_NOT_GRANTED : 91'
 ...
 test_run:cmd("setopt delimiter ''");
 ---
diff --git a/test/box/net.box.result b/test/box/net.box.result
index 894fb91a21..dcc1a2593e 100644
--- a/test/box/net.box.result
+++ b/test/box/net.box.result
@@ -72,18 +72,18 @@ cn:ping()
 -- check permissions
 cn:call('unexists_procedure')
 ---
-- error: Execute access is denied for user 'guest' to function 'unexists_procedure'
+- error: Execute access to function 'unexists_procedure' is denied for user 'guest'
 ...
 function test_foo(a,b,c) return { {{ [a] = 1 }}, {{ [b] = 2 }}, c } end
 ---
 ...
 cn:call('test_foo', {'a', 'b', 'c'})
 ---
-- error: Execute access is denied for user 'guest' to function 'test_foo'
+- error: Execute access to function 'test_foo' is denied for user 'guest'
 ...
 cn:eval('return 2+2')
 ---
-- error: Execute access on universe is denied for user 'guest'
+- error: Execute access to universe '' is denied for user 'guest'
 ...
 box.schema.user.grant('guest','execute','universe')
 ---
diff --git a/test/box/role.result b/test/box/role.result
index 8f6ff5d5ea..1c1bb21532 100644
--- a/test/box/role.result
+++ b/test/box/role.result
@@ -251,11 +251,11 @@ box.session.su('grantee')
 ...
 box.space.test:insert{1}
 ---
-- error: Write access is denied for user 'grantee' to space 'test'
+- error: Write access to space 'test' is denied for user 'grantee'
 ...
 box.space.test:select{1}
 ---
-- error: Read access is denied for user 'grantee' to space 'test'
+- error: Read access to space 'test' is denied for user 'grantee'
 ...
 box.session.su('admin')
 ---
@@ -380,7 +380,7 @@ box.session.su("user")
 ...
 box.space._space.index.name:get{"_space"}[3]
 ---
-- error: Read access is denied for user 'user' to space '_space'
+- error: Read access to space '_space' is denied for user 'user'
 ...
 box.session.su("admin")
 ---
@@ -396,7 +396,7 @@ box.session.su("user")
 ...
 box.space._space.index.name:get{"_space"}[3]
 ---
-- error: Read access is denied for user 'user' to space '_space'
+- error: Read access to space '_space' is denied for user 'user'
 ...
 box.space._index:get{288, 0}[3]
 ---
@@ -413,11 +413,11 @@ box.session.su("user")
 ...
 box.space._space.index.name:get{"_space"}[3]
 ---
-- error: Read access is denied for user 'user' to space '_space'
+- error: Read access to space '_space' is denied for user 'user'
 ...
 box.space._index:get{288, 0}[3]
 ---
-- error: Read access is denied for user 'user' to space '_index'
+- error: Read access to space '_index' is denied for user 'user'
 ...
 box.session.su("admin")
 ---
@@ -433,7 +433,7 @@ box.session.su("user")
 ...
 box.space._space.index.name:get{"_space"}[3]
 ---
-- error: Read access is denied for user 'user' to space '_space'
+- error: Read access to space '_space' is denied for user 'user'
 ...
 box.space._index:get{288, 0}[3]
 ---
@@ -450,11 +450,11 @@ box.session.su("user")
 ...
 box.space._space.index.name:get{"_space"}[3]
 ---
-- error: Read access is denied for user 'user' to space '_space'
+- error: Read access to space '_space' is denied for user 'user'
 ...
 box.space._index:get{288, 0}[3]
 ---
-- error: Read access is denied for user 'user' to space '_index'
+- error: Read access to space '_index' is denied for user 'user'
 ...
 box.session.su("admin")
 ---
@@ -523,7 +523,7 @@ box.session.su("user1")
 ...
 box.space._index:get{288, 0}[3]
 ---
-- error: Read access is denied for user 'user1' to space '_index'
+- error: Read access to space '_index' is denied for user 'user1'
 ...
 box.session.su("admin")
 ---
@@ -536,14 +536,14 @@ box.session.su("user")
 ...
 box.space._index:get{288, 0}[3]
 ---
-- error: Read access is denied for user 'user' to space '_index'
+- error: Read access to space '_index' is denied for user 'user'
 ...
 box.session.su("user1")
 ---
 ...
 box.space._index:get{288, 0}[3]
 ---
-- error: Read access is denied for user 'user1' to space '_index'
+- error: Read access to space '_index' is denied for user 'user1'
 ...
 box.session.su("admin")
 ---
@@ -579,14 +579,14 @@ box.session.su("user")
 ...
 box.space._space.index.name:get{"_space"}[3]
 ---
-- error: Read access is denied for user 'user' to space '_space'
+- error: Read access to space '_space' is denied for user 'user'
 ...
 box.session.su("user1")
 ---
 ...
 box.space._space.index.name:get{"_space"}[3]
 ---
-- error: Read access is denied for user 'user1' to space '_space'
+- error: Read access to space '_space' is denied for user 'user1'
 ...
 box.session.su("admin")
 ---
@@ -662,7 +662,7 @@ box.session.su('john')
 -- error
 box.schema.user.grant('grantee', 'role')
 ---
-- error: Read access is denied for user 'john' to space '_user'
+- error: Read access to space '_user' is denied for user 'john'
 ...
 --
 box.session.su('admin')
@@ -679,11 +679,11 @@ box.session.su('john')
 ...
 box.schema.user.grant('grantee', 'role')
 ---
-- error: Grant access on role is denied for user 'john'
+- error: Grant access to role 'role' is denied for user 'john'
 ...
 box.schema.user.grant('grantee', 'read', 'space', 'test')
 ---
-- error: Grant access on space is denied for user 'john'
+- error: Grant access to space 'test' is denied for user 'john'
 ...
 --
 -- granting 'public' is however an exception - everyone
@@ -701,7 +701,7 @@ box.schema.user.grant('grantee', 'public')
 --
 box.schema.user.revoke('grantee', 'public')
 ---
-- error: Create, drop or alter access on role is denied for user 'john'
+- error: Revoke access to role 'public' is denied for user 'john'
 ...
 box.session.su('admin')
 ---
@@ -749,7 +749,7 @@ box.space.test:select{}
 ...
 box.space.test:insert{1}
 ---
-- error: Write access is denied for user 'john' to space 'test'
+- error: Write access to space 'test' is denied for user 'john'
 ...
 box.session.su('admin')
 ---
@@ -783,7 +783,7 @@ box.space.test:select{}
 ...
 box.space.test:insert{1}
 ---
-- error: Write access is denied for user 'john' to space 'test'
+- error: Write access to space 'test' is denied for user 'john'
 ...
 box.session.su('admin')
 ---
diff --git a/test/box/sequence.result b/test/box/sequence.result
index 48669650e9..ac106be05a 100644
--- a/test/box/sequence.result
+++ b/test/box/sequence.result
@@ -1316,15 +1316,15 @@ box.session.su('user')
 ...
 sq:set(100) -- error
 ---
-- error: Write access is denied for user 'user' to sequence 'seq'
+- error: Write access to sequence 'seq' is denied for user 'user'
 ...
 sq:next() -- error
 ---
-- error: Write access is denied for user 'user' to sequence 'seq'
+- error: Write access to sequence 'seq' is denied for user 'user'
 ...
 sq:reset() -- error
 ---
-- error: Write access is denied for user 'user' to sequence 'seq'
+- error: Write access to sequence 'seq' is denied for user 'user'
 ...
 box.session.su('admin')
 ---
@@ -1433,15 +1433,15 @@ box.session.su('user')
 ...
 sq:set(100) -- error
 ---
-- error: Write access is denied for user 'user' to sequence 'seq'
+- error: Write access to sequence 'seq' is denied for user 'user'
 ...
 sq:next() -- error
 ---
-- error: Write access is denied for user 'user' to sequence 'seq'
+- error: Write access to sequence 'seq' is denied for user 'user'
 ...
 sq:reset() -- error
 ---
-- error: Write access is denied for user 'user' to sequence 'seq'
+- error: Write access to sequence 'seq' is denied for user 'user'
 ...
 box.session.su('admin')
 ---
@@ -1455,11 +1455,11 @@ box.session.su('user')
 ...
 sq:alter{step = 2} -- error
 ---
-- error: Create, drop or alter access on sequence is denied for user 'user'
+- error: Alter access to sequence 'seq' is denied for user 'user'
 ...
 sq:drop() -- error
 ---
-- error: Create, drop or alter access on sequence is denied for user 'user'
+- error: Drop access to sequence 'seq' is denied for user 'user'
 ...
 box.session.su('admin')
 ---
@@ -1532,23 +1532,23 @@ s2 = box.schema.space.create('space2')
 ...
 _ = s2:create_index('pk', {sequence = 'seq1'}) -- error
 ---
-- error: Create, drop or alter access on sequence is denied for user 'user'
+- error: Create access to sequence 'seq1' is denied for user 'user'
 ...
 s1.index.pk:alter({sequence = 'seq1'}) -- error
 ---
-- error: Create, drop or alter access on space is denied for user 'user'
+- error: Alter access to space 'space1' is denied for user 'user'
 ...
 box.space._space_sequence:replace{s1.id, sq1.id, false} -- error
 ---
-- error: Create, drop or alter access on space is denied for user 'user'
+- error: Alter access to space 'space1' is denied for user 'user'
 ...
 box.space._space_sequence:replace{s1.id, sq2.id, false} -- error
 ---
-- error: Create, drop or alter access on space is denied for user 'user'
+- error: Alter access to space 'space1' is denied for user 'user'
 ...
 box.space._space_sequence:replace{s2.id, sq1.id, false} -- error
 ---
-- error: Create, drop or alter access on sequence is denied for user 'user'
+- error: Create access to sequence 'seq1' is denied for user 'user'
 ...
 s2.index.pk:alter({sequence = 'seq2'}) -- ok
 ---
@@ -1580,11 +1580,11 @@ box.session.su('user')
 ...
 s2:insert{2, 2} -- error
 ---
-- error: Write access is denied for user 'user' to sequence 'seq1'
+- error: Write access to sequence 'seq1' is denied for user 'user'
 ...
 s2:insert{nil, 2} -- error
 ---
-- error: Write access is denied for user 'user' to sequence 'seq1'
+- error: Write access to sequence 'seq1' is denied for user 'user'
 ...
 s2:update(1, {{'+', 2, 1}}) -- ok
 ---
@@ -1650,15 +1650,15 @@ s:insert{nil, 11} -- ok: {11, 11}
 ...
 box.sequence.test_seq:set(100) -- error
 ---
-- error: Write access is denied for user 'user' to sequence 'test_seq'
+- error: Write access to sequence 'test_seq' is denied for user 'user'
 ...
 box.sequence.test_seq:next() -- error
 ---
-- error: Write access is denied for user 'user' to sequence 'test_seq'
+- error: Write access to sequence 'test_seq' is denied for user 'user'
 ...
 box.sequence.test_seq:reset() -- error
 ---
-- error: Write access is denied for user 'user' to sequence 'test_seq'
+- error: Write access to sequence 'test_seq' is denied for user 'user'
 ...
 box.session.su('admin')
 ---
@@ -1714,7 +1714,7 @@ box.session.su('user2')
 ...
 box.schema.user.grant('user2', 'write', 'sequence', 'test') -- error
 ---
-- error: Grant access on sequence is denied for user 'user2'
+- error: Grant access to sequence 'test' is denied for user 'user2'
 ...
 box.session.su('user1')
 ---
diff --git a/test/engine/truncate.result b/test/engine/truncate.result
index b9189649d5..2222804b5b 100644
--- a/test/engine/truncate.result
+++ b/test/engine/truncate.result
@@ -506,7 +506,7 @@ con = require('net.box').connect(box.cfg.listen)
 ...
 con:eval([[box.space.access_truncate:truncate()]])
 ---
-- error: Write access is denied for user 'guest' to space 'access_truncate'
+- error: Write access to space 'access_truncate' is denied for user 'guest'
 ...
 con.space.access_truncate:select()
 ---
diff --git a/test/replication/wal_off.result b/test/replication/wal_off.result
index 8bdb7c011f..f50bfc2f68 100644
--- a/test/replication/wal_off.result
+++ b/test/replication/wal_off.result
@@ -81,10 +81,10 @@ test_run:cmd('switch default')
 box.cfg { replication = wal_off_uri }
 ---
 ...
-check = "Read access on universe is denied for user 'guest'"
+check = "Read access to universe"
 ---
 ...
-while box.info.replication[wal_off_id].upstream.message ~= check do fiber.sleep(0) end
+while string.find(box.info.replication[wal_off_id].upstream.message, check) == nil do fiber.sleep(0.01) end
 ---
 ...
 box.cfg { replication = "" }
diff --git a/test/replication/wal_off.test.lua b/test/replication/wal_off.test.lua
index 060406c7a5..43cd0aed50 100644
--- a/test/replication/wal_off.test.lua
+++ b/test/replication/wal_off.test.lua
@@ -28,8 +28,8 @@ box.schema.user.revoke('guest', 'replication')
 test_run:cmd('switch default')
 
 box.cfg { replication = wal_off_uri }
-check = "Read access on universe is denied for user 'guest'"
-while box.info.replication[wal_off_id].upstream.message ~= check do fiber.sleep(0) end
+check = "Read access to universe"
+while string.find(box.info.replication[wal_off_id].upstream.message, check) == nil do fiber.sleep(0.01) end
 box.cfg { replication = "" }
 
 test_run:cmd("stop server wal_off")
diff --git a/test/unit/column_mask.c b/test/unit/column_mask.c
index 91bee94dbc..7859626f89 100644
--- a/test/unit/column_mask.c
+++ b/test/unit/column_mask.c
@@ -228,10 +228,10 @@ basic_test()
 		((uint64_t) 1) << 63 | ((uint64_t) 1) << 31,
 	};
 
-	assert(ARRAY_LENGTH(statements) == ARRAY_LENGTH(update_ops));
-	assert(ARRAY_LENGTH(statements) == ARRAY_LENGTH(results));
-	assert(ARRAY_LENGTH(statements) == ARRAY_LENGTH(column_masks));
-	for (size_t i = 0; i < ARRAY_LENGTH(statements); ++i)
+	assert(lengthof(statements) == lengthof(update_ops));
+	assert(lengthof(statements) == lengthof(results));
+	assert(lengthof(statements) == lengthof(column_masks));
+	for (size_t i = 0; i < lengthof(statements); ++i)
 		check_update_result(&statements[i], &update_ops[i], &results[i],
 				    column_masks[i]);
 }
-- 
GitLab