Skip to content

Commit b2fd61a

Browse files
committed
Extend serverCommand with get_dbid_args, unify ACL checks
Signed-off-by: Daniil Kashapov <[email protected]>
1 parent 97a27c5 commit b2fd61a

File tree

11 files changed

+321
-295
lines changed

11 files changed

+321
-295
lines changed

src/acl.c

Lines changed: 44 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -181,8 +181,8 @@ typedef struct {
181181
ALLCHANNELS is set in the user. */
182182
sds command_rules; /* A string representation of the ordered categories and commands, this
183183
* is used to regenerate the original ACL string for display. */
184-
intset *dbs; /* Set of database ids, based on SELECTOR_FLAG_DBLIST_NEGATED
185-
it is going to be allowed or disallowed database ids */
184+
intset *dbs; /* Set of allowed database ids. If set is NULL or empty the user
185+
* cannot access any database, unless the flag ALLDBS is set. */
186186
} aclSelector;
187187

188188
static void ACLResetFirstArgsForCommand(aclSelector *selector, unsigned long id);
@@ -821,12 +821,7 @@ static sds ACLDescribeSelector(aclSelector *selector) {
821821
if (selector->flags & SELECTOR_FLAG_ALLDBS) {
822822
res = sdscatlen(res, "alldbs ", 7);
823823
} else {
824-
if (selector->flags & SELECTOR_FLAG_DBLIST_NEGATED) {
825-
res = sdscatlen(res, "db!=", 4);
826-
} else {
827-
res = sdscatlen(res, "db=", 3);
828-
}
829-
824+
res = sdscatlen(res, "db=", 3);
830825
uint32_t len = intsetLen(selector->dbs);
831826
for (uint32_t i = 0; i < len; i++) {
832827
int64_t dbid;
@@ -965,7 +960,7 @@ static void ACLAddAllowedFirstArg(aclSelector *selector, unsigned long id, const
965960
}
966961

967962
/* Helper function to set database permissions for a selector */
968-
static int ACLSetSelectorDatabasePermissions(aclSelector *selector, const char *dbs_str, int negated) {
963+
static int ACLSetSelectorDatabasePermissions(aclSelector *selector, const char *dbs_str) {
969964
selector->flags &= ~SELECTOR_FLAG_ALLDBS;
970965

971966
intset *new_dbs = intsetNew();
@@ -974,20 +969,13 @@ static int ACLSetSelectorDatabasePermissions(aclSelector *selector, const char *
974969
return C_ERR;
975970
}
976971

977-
if (negated) {
978-
selector->flags |= SELECTOR_FLAG_DBLIST_NEGATED;
979-
} else {
980-
selector->flags &= ~SELECTOR_FLAG_DBLIST_NEGATED;
981-
}
982-
983972
char *dblist = zstrdup(dbs_str);
984973
if (!dblist) {
985974
intsetFree(new_dbs);
986975
errno = ENOMEM;
987976
return C_ERR;
988977
}
989978

990-
991979
// Reject empty list, trailing commas or more than 1 consecutive commas
992980
if (strlen(dblist) == 0 || dblist[0] == ',' ||
993981
dblist[strlen(dblist) - 1] == ',' || strstr(dblist, ",,")) {
@@ -1100,11 +1088,8 @@ static aclSelector *aclCreateSelectorFromOpSet(const char *opset, size_t opsetle
11001088
* db=<dbid> Add database ID to the set of allowed IDs, any other database ID
11011089
* will be disallowed. May be used with `,` for assingning multiple
11021090
* allowed IDs (e.g "db=1,2,3").
1103-
* db!=<dbid> Add database ID to the set of disallowed IDs, any other database ID
1104-
* will be disallowed. May be used with `,` for assingning multiple
1105-
* disallowed IDs (e.g "db!=4,5,6").
11061091
* alldbs Allow access to all databases.
1107-
* resetdbs Flush the set of allowed/disallowed database IDs, revert to default
1092+
* resetdbs Flush the set of allowed database IDs, revert to default
11081093
* behaviour (all databases are allowed).
11091094
*/
11101095
static int ACLSetSelector(aclSelector *selector, const char *op, size_t oplen) {
@@ -1132,11 +1117,8 @@ static int ACLSetSelector(aclSelector *selector, const char *op, size_t oplen) {
11321117
intsetFree(selector->dbs);
11331118
selector->dbs = intsetNew();
11341119
}
1135-
} else if (strncmp(op, "db=", 3) == 0) {
1136-
int result = ACLSetSelectorDatabasePermissions(selector, op + 3, 0);
1137-
if (result != C_OK) return result;
1138-
} else if (strncmp(op, "db!=", 4) == 0) {
1139-
int result = ACLSetSelectorDatabasePermissions(selector, op + 4, 1);
1120+
} else if (strncmp(op, "db=", 3) == 0 || strncmp(op, "DB=", 3) == 0) {
1121+
int result = ACLSetSelectorDatabasePermissions(selector, op + 3);
11401122
if (result != C_OK) return result;
11411123
} else if (!strcasecmp(op, "allcommands") || !strcasecmp(op, "+@all")) {
11421124
memset(selector->allowed_commands, 255, sizeof(selector->allowed_commands));
@@ -1759,13 +1741,11 @@ int ACLSelectorCanAccessDb(aclSelector *selector, long long dbid) {
17591741
if (selector->flags & SELECTOR_FLAG_ALLDBS)
17601742
return 1;
17611743

1762-
if (dbid < 0 || dbid >= server.dbnum)
1744+
if (dbid < 0 || dbid >= server.dbnum || !selector->dbs)
17631745
return 0;
17641746

17651747
int found = intsetFind(selector->dbs, (int64_t)dbid);
17661748

1767-
if (selector->flags & SELECTOR_FLAG_DBLIST_NEGATED)
1768-
return !found;
17691749
return found;
17701750
}
17711751

@@ -1801,41 +1781,43 @@ static int ACLSelectorCheckCmd(aclSelector *selector,
18011781
int dbid) {
18021782
uint64_t id = cmd->id;
18031783
int ret;
1784+
1785+
/* Check database level permissions based on command flags. */
18041786
if (cmd->flags & CMD_CROSS_DB) {
1805-
if (cmd->proc == selectCommand && argc > 1) {
1806-
long long target_db;
1807-
if (getLongLongFromObject(argv[1], &target_db) == C_OK) {
1808-
if (target_db >= 0 && target_db < server.dbnum) {
1809-
dbid = (int)target_db;
1787+
if (cmd->get_dbid_args) {
1788+
int count = 0;
1789+
int *dbids = cmd->get_dbid_args(argv, argc, &count);
1790+
if (dbids) {
1791+
for (int i = 0; i < count; i++) {
1792+
if (!ACLSelectorCanAccessDb(selector, dbids[i])) {
1793+
if (keyidxptr) {
1794+
if (cmd->proc == selectCommand)
1795+
*keyidxptr = 1;
1796+
else if (cmd->proc == moveCommand)
1797+
*keyidxptr = 2;
1798+
else if (cmd->proc == swapdbCommand)
1799+
*keyidxptr = (i == 0) ? 1 : 2;
1800+
else
1801+
*keyidxptr = 0;
1802+
}
1803+
zfree(dbids);
1804+
return ACL_DENIED_DB;
1805+
}
18101806
}
1807+
zfree(dbids);
18111808
}
1812-
} else if (cmd->proc == swapdbCommand && argc > 2) {
1813-
long long db1, db2;
1814-
if (getLongLongFromObject(argv[1], &db1) == C_OK && getLongLongFromObject(argv[2], &db2) == C_OK &&
1815-
(!ACLSelectorCanAccessDb(selector, db1) || !ACLSelectorCanAccessDb(selector, db2))) {
1816-
return ACL_DENIED_DB;
1817-
}
1818-
} else if (cmd->proc == moveCommand && argc > 2) {
1819-
long long target_db;
1820-
if (getLongLongFromObject(argv[2], &target_db) == C_OK &&
1821-
!ACLSelectorCanAccessDb(selector, target_db)) {
1822-
return ACL_DENIED_DB;
1823-
}
1809+
} else {
1810+
/* Command has flag CMD_CROSS_DB but has no function to get its db id args */
1811+
return ACL_NOT_IMPLEMENTED;
18241812
}
1825-
}
1826-
1827-
if ((cmd->flags & CMD_ALL_DBS) && !(selector->flags & SELECTOR_FLAG_ALLDBS)) {
1813+
} else if ((cmd->flags & CMD_ALL_DBS) && !(selector->flags & SELECTOR_FLAG_ALLDBS)) {
18281814
for (int i = 0; i < server.dbnum; i++) {
18291815
if (!ACLSelectorCanAccessDb(selector, i)) {
18301816
return ACL_DENIED_DB;
18311817
}
18321818
}
1833-
}
1834-
1835-
if (!ACLSelectorCanAccessDb(selector, dbid)) {
1836-
if (keyidxptr) {
1837-
*keyidxptr = (cmd->proc == selectCommand) ? 1 : 0;
1838-
}
1819+
} else if (!ACLSelectorCanAccessDb(selector, dbid)) {
1820+
if (keyidxptr) *keyidxptr = 0;
18391821
return ACL_DENIED_DB;
18401822
}
18411823

@@ -2778,6 +2760,7 @@ static void ACLUpdateInfoMetrics(int reason) {
27782760
server.acl_info.acl_access_denied_tls_cert++;
27792761
} else if (reason == ACL_DENIED_DB) {
27802762
server.acl_info.invalid_db_accesses++;
2763+
} else if (reason == ACL_NOT_IMPLEMENTED) {
27812764
} else {
27822765
serverPanic("Unknown ACL_DENIED encoding");
27832766
}
@@ -2915,8 +2898,14 @@ sds getAclErrorMessage(int acl_res, user *user, struct serverCommand *cmd, sds e
29152898
"database %s",
29162899
user->name, errored_val);
29172900
} else {
2918-
return sdsnew("No permissions to access current database");
2901+
return sdsnew("No permissions to access database");
29192902
}
2903+
case ACL_NOT_IMPLEMENTED:
2904+
return sdscatfmt(sdsempty(),
2905+
"Command '%S' has flag CMD_CROSS_DB "
2906+
"but has no function to get its database id args, "
2907+
"see serverCommand in server.h",
2908+
cmd->fullname);
29202909
}
29212910
serverPanic("Reached deadcode on getAclErrorMessage");
29222911
}

src/cli_commands.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33

44
/* Definitions to configure commands.c to generate the above structs. */
55
#define MAKE_CMD(name, summary, complexity, since, doc_flags, replaced, deprecated, group, group_enum, history, \
6-
num_history, tips, num_tips, function, arity, flags, acl, key_specs, key_specs_num, get_keys, \
7-
numargs) \
6+
num_history, tips, num_tips, function, arity, flags, acl, get_dbid_args, key_specs, \
7+
key_specs_num, get_keys, numargs) \
88
name, summary, group, since, numargs
99
#define MAKE_ARG(name, type, key_spec_index, token, summary, since, flags, numsubargs, deprecated_since) \
1010
name, type, token, since, flags, numsubargs

src/commands.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22
#include "server.h"
33

44
#define MAKE_CMD(name, summary, complexity, since, doc_flags, replaced, deprecated, group, group_enum, history, \
5-
num_history, tips, num_tips, function, arity, flags, acl, key_specs, key_specs_num, get_keys, \
6-
numargs) \
5+
num_history, tips, num_tips, function, arity, flags, acl, get_dbid_args, key_specs, \
6+
key_specs_num, get_keys, numargs) \
77
name, summary, complexity, since, doc_flags, replaced, deprecated, group_enum, history, num_history, tips, \
8-
num_tips, function, arity, flags, acl, key_specs, key_specs_num, get_keys, numargs
8+
num_tips, function, arity, flags, acl, get_dbid_args, key_specs, key_specs_num, get_keys, numargs
99
#define MAKE_ARG(name, type, key_spec_index, token, summary, since, flags, numsubargs, deprecated_since) \
1010
name, type, key_spec_index, token, summary, since, flags, deprecated_since, numsubargs
1111
#define COMMAND_STRUCT serverCommand

0 commit comments

Comments
 (0)