mirror of
https://github.com/fluencelabs/redis
synced 2025-03-19 09:00:51 +00:00
ACL: fix and improve ACL key checking.
This commit is contained in:
parent
dbae371090
commit
4a3419acfc
22
src/acl.c
22
src/acl.c
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* =============================================================================
|
/* =============================================================================
|
||||||
|
12
src/server.c
12
src/server.c
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user