From 7fc882c57854e952c866a7925e574dbf5db162bd Mon Sep 17 00:00:00 2001 From: antirez Date: Wed, 9 Jan 2019 21:31:29 +0100 Subject: [PATCH] ACL: use a fixed table for command IDs. --- src/acl.c | 17 +++++++++++++++++ src/server.c | 3 +-- src/server.h | 9 +++++++++ 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/acl.c b/src/acl.c index 5155f9471..dd21e2f03 100644 --- a/src/acl.c +++ b/src/acl.c @@ -93,3 +93,20 @@ int ACLCheckUserCredentials(robj *username, robj *password) { return C_ERR; } } + +/* For ACL purposes, every user has a bitmap with the commands that such + * user is allowed to execute. In order to populate the bitmap, every command + * should have an assigned ID (that is used to index the bitmap). This function + * creates such an ID: it uses sequential IDs, reusing the same ID for the same + * command name, so that a command retains the same ID in case of modules that + * are unloaded and later reloaded. */ +unsigned long ACLGetCommandID(const char *cmdname) { + static rax *map = NULL; + unsigned long nextid = 0; + + if (map == NULL) map = raxNew(); + void *id = raxFind(map,(unsigned char*)cmdname,strlen(cmdname)); + if (id != raxNotFound) return (unsigned long)id; + raxInsert(map,(unsigned char*)cmdname,strlen(cmdname),(void*)nextid,NULL); + return nextid++; +} diff --git a/src/server.c b/src/server.c index df9488873..c297e9122 100644 --- a/src/server.c +++ b/src/server.c @@ -2224,8 +2224,7 @@ void populateCommandTable(void) { f++; } - c->id = j; /* Sequential ID for each command. Used for ACLs. */ - + c->id = ACLGetCommandID(c->name); /* Assign the ID used for ACL. */ retval1 = dictAdd(server.commands, sdsnew(c->name), c); /* Populate an additional dictionary that will be unaffected * by rename-command statements in redis.conf. */ diff --git a/src/server.h b/src/server.h index a004acb25..1eb66e013 100644 --- a/src/server.h +++ b/src/server.h @@ -1352,6 +1352,14 @@ typedef struct { dictIterator *di; } setTypeIterator; +/* This structure represents a Redis user. This is useful for ACLs, the + * user is associated to the connection after the connection is authenticated. + * If there is no associated user, the connection uses the default user. */ +#define USER_MAX_COMMAND_BIT 1024 +typedef struct user { + uint64_t allowed_commands[USER_MAX_COMMAND_BIT/64]; +} user; + /* Structure to hold hash iteration abstraction. Note that iteration over * hashes involves both fields and values. Because it is possible that * not both are required, store pointers in the iterator to avoid @@ -1655,6 +1663,7 @@ void receiveChildInfo(void); /* acl.c -- Authentication related prototypes. */ int ACLCheckUserCredentials(robj *username, robj *password); +unsigned long ACLGetCommandID(const char *cmdname); /* Sorted sets data type */