ACL: fix and improve ACL key checking.

This commit is contained in:
antirez 2019-01-16 18:31:05 +01:00
parent dbae371090
commit 4a3419acfc
3 changed files with 28 additions and 10 deletions

View File

@ -218,6 +218,7 @@ void ACLInit(void) {
Users = raxNew(); Users = raxNew();
DefaultUser = ACLCreateUser("default",7); DefaultUser = ACLCreateUser("default",7);
ACLSetUser(DefaultUser,"+@all",-1); ACLSetUser(DefaultUser,"+@all",-1);
ACLSetUser(DefaultUser,"~*",-1);
ACLSetUser(DefaultUser,"on",-1); ACLSetUser(DefaultUser,"on",-1);
ACLSetUser(DefaultUser,"nopass",-1); ACLSetUser(DefaultUser,"nopass",-1);
} }
@ -288,18 +289,21 @@ user *ACLGetUserByName(const char *name, size_t namelen) {
* referenced by c->cmd, can be executed by this client according to the * referenced by c->cmd, can be executed by this client according to the
* ACls associated to the client user c->user. * ACls associated to the client user c->user.
* *
* If the user can execute the command C_OK is returned, otherwise * If the user can execute the command ACL_OK is returned, otherwise
* C_ERR is returned. */ * ACL_DENIED_CMD or ACL_DENIED_KEY is returned: the first in case the
* command cannot be executed because the user is not allowed to run such
* command, the second if the command is denied because the user is trying
* to access keys that are not among the specified patterns. */
int ACLCheckCommandPerm(client *c) { int ACLCheckCommandPerm(client *c) {
user *u = c->user; user *u = c->user;
uint64_t id = c->cmd->id; uint64_t id = c->cmd->id;
/* If there is no associated user, the connection can run anything. */ /* If there is no associated user, the connection can run anything. */
if (u == NULL) return C_OK; if (u == NULL) return ACL_OK;
/* We have to deny every command with an ID that overflows the Redis /* We have to deny every command with an ID that overflows the Redis
* internal structures. Very unlikely to happen. */ * internal structures. Very unlikely to happen. */
if (c->cmd->id >= USER_MAX_COMMAND_BIT) return C_ERR; if (c->cmd->id >= USER_MAX_COMMAND_BIT) return ACL_DENIED_CMD;
/* Check if the user can execute this command. */ /* Check if the user can execute this command. */
if (!(u->flags & USER_FLAG_ALLCOMMANDS) && if (!(u->flags & USER_FLAG_ALLCOMMANDS) &&
@ -311,10 +315,12 @@ int ACLCheckCommandPerm(client *c) {
* command is allowed just with that specific subcommand. */ * command is allowed just with that specific subcommand. */
if (!(u->allowed_commands[wordid] & bit)) { if (!(u->allowed_commands[wordid] & bit)) {
/* Check if the subcommand matches. */ /* Check if the subcommand matches. */
if (u->allowed_subcommands == NULL || c->argc < 2) return C_ERR; if (u->allowed_subcommands == NULL || c->argc < 2)
return ACL_DENIED_CMD;
long subid = 0; long subid = 0;
while (1) { while (1) {
if (u->allowed_subcommands[id][subid] == NULL) return C_ERR; if (u->allowed_subcommands[id][subid] == NULL)
return ACL_DENIED_CMD;
if (!strcasecmp(c->argv[1]->ptr, if (!strcasecmp(c->argv[1]->ptr,
u->allowed_subcommands[id][subid])) u->allowed_subcommands[id][subid]))
break; /* Subcommand match found. Stop here. */ break; /* Subcommand match found. Stop here. */
@ -348,14 +354,14 @@ int ACLCheckCommandPerm(client *c) {
break; break;
} }
} }
if (!match) return C_ERR; if (!match) return ACL_DENIED_KEY;
} }
getKeysFreeResult(keyidx); getKeysFreeResult(keyidx);
} }
/* If we survived all the above checks, the user can execute the /* If we survived all the above checks, the user can execute the
* command. */ * command. */
return C_OK; return ACL_OK;
} }
/* ============================================================================= /* =============================================================================

View File

@ -2598,9 +2598,17 @@ int processCommand(client *c) {
/* Check if the user can run this command according to the current /* Check if the user can run this command according to the current
* ACLs. */ * ACLs. */
if (ACLCheckCommandPerm(c) == C_ERR) { int acl_retval = ACLCheckCommandPerm(c);
if (acl_retval != ACL_OK) {
flagTransaction(c); flagTransaction(c);
addReplyErrorFormat(c,"-NOPERM this user has no permissions to run the %s command", c->cmd->name); if (acl_retval == ACL_DENIED_CMD)
addReplyErrorFormat(c,
"-NOPERM this user has no permissions to run "
"the '%s' command", c->cmd->name);
else
addReplyErrorFormat(c,
"-NOPERM this user has no permissions to access "
"one of the keys used as arguments");
return C_OK; return C_OK;
} }

View File

@ -1698,6 +1698,10 @@ void receiveChildInfo(void);
/* acl.c -- Authentication related prototypes. */ /* acl.c -- Authentication related prototypes. */
extern user *DefaultUser; extern user *DefaultUser;
void ACLInit(void); void ACLInit(void);
/* Return values for ACLCheckUserCredentials(). */
#define ACL_OK 0
#define ACL_DENIED_CMD 1
#define ACL_DENIED_KEY 2
int ACLCheckUserCredentials(robj *username, robj *password); int ACLCheckUserCredentials(robj *username, robj *password);
unsigned long ACLGetCommandID(const char *cmdname); unsigned long ACLGetCommandID(const char *cmdname);
user *ACLGetUserByName(const char *name, size_t namelen); user *ACLGetUserByName(const char *name, size_t namelen);