Merge pull request '阅读acl对应的源码' (#5) from dev into master
Reviewed-on: zeekling/redis#5
This commit is contained in:
commit
6d671f58e0
@ -759,7 +759,7 @@ acllog-max-len 128
|
|||||||
# The format of the external ACL user file is exactly the same as the
|
# The format of the external ACL user file is exactly the same as the
|
||||||
# format that is used inside redis.conf to describe users.
|
# format that is used inside redis.conf to describe users.
|
||||||
#
|
#
|
||||||
# aclfile /etc/redis/users.acl
|
aclfile /tmp/users.acl
|
||||||
|
|
||||||
# IMPORTANT NOTE: starting with Redis 6 "requirepass" is just a compatiblity
|
# IMPORTANT NOTE: starting with Redis 6 "requirepass" is just a compatiblity
|
||||||
# layer on top of the new ACL system. The option effect will be just setting
|
# layer on top of the new ACL system. The option effect will be just setting
|
||||||
|
72
src/acl.c
72
src/acl.c
@ -148,7 +148,9 @@ int time_independent_strcmp(char *a, char *b) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Given an SDS string, returns the SHA256 hex representation as a
|
/* Given an SDS string, returns the SHA256 hex representation as a
|
||||||
* new SDS string. */
|
* new SDS string.
|
||||||
|
* 对密码进行加密
|
||||||
|
* * */
|
||||||
sds ACLHashPassword(unsigned char *cleartext, size_t len) {
|
sds ACLHashPassword(unsigned char *cleartext, size_t len) {
|
||||||
SHA256_CTX ctx;
|
SHA256_CTX ctx;
|
||||||
unsigned char hash[SHA256_BLOCK_SIZE];
|
unsigned char hash[SHA256_BLOCK_SIZE];
|
||||||
@ -232,7 +234,10 @@ void *ACLListDupSds(void *item) {
|
|||||||
* of users (the Users global radix tree), and returns a reference to
|
* of users (the Users global radix tree), and returns a reference to
|
||||||
* the structure representing the user.
|
* the structure representing the user.
|
||||||
*
|
*
|
||||||
* If the user with such name already exists NULL is returned. */
|
* If the user with such name already exists NULL is returned.
|
||||||
|
*
|
||||||
|
* 创建用户
|
||||||
|
* */
|
||||||
user *ACLCreateUser(const char *name, size_t namelen) {
|
user *ACLCreateUser(const char *name, size_t namelen) {
|
||||||
if (raxFind(Users,(unsigned char*)name,namelen) != raxNotFound) return NULL;
|
if (raxFind(Users,(unsigned char*)name,namelen) != raxNotFound) return NULL;
|
||||||
user *u = zmalloc(sizeof(*u));
|
user *u = zmalloc(sizeof(*u));
|
||||||
@ -255,7 +260,9 @@ user *ACLCreateUser(const char *name, size_t namelen) {
|
|||||||
/* This function should be called when we need an unlinked "fake" user
|
/* This function should be called when we need an unlinked "fake" user
|
||||||
* we can use in order to validate ACL rules or for other similar reasons.
|
* we can use in order to validate ACL rules or for other similar reasons.
|
||||||
* The user will not get linked to the Users radix tree. The returned
|
* The user will not get linked to the Users radix tree. The returned
|
||||||
* user should be released with ACLFreeUser() as usually. */
|
* user should be released with ACLFreeUser() as usually.
|
||||||
|
*
|
||||||
|
* * */
|
||||||
user *ACLCreateUnlinkedUser(void) {
|
user *ACLCreateUnlinkedUser(void) {
|
||||||
char username[64];
|
char username[64];
|
||||||
for (int j = 0; ; j++) {
|
for (int j = 0; ; j++) {
|
||||||
@ -354,9 +361,13 @@ int ACLGetCommandBitCoordinates(uint64_t id, uint64_t *word, uint64_t *bit) {
|
|||||||
* but just the lowlevel bitmask.
|
* but just the lowlevel bitmask.
|
||||||
*
|
*
|
||||||
* If the bit overflows the user internal representation, zero is returned
|
* If the bit overflows the user internal representation, zero is returned
|
||||||
* in order to disallow the execution of the command in such edge case. */
|
* in order to disallow the execution of the command in such edge case.
|
||||||
|
*
|
||||||
|
* 通过计算command对应的bit位,计算是否存在权限
|
||||||
|
* * */
|
||||||
int ACLGetUserCommandBit(user *u, unsigned long id) {
|
int ACLGetUserCommandBit(user *u, unsigned long id) {
|
||||||
uint64_t word, bit;
|
uint64_t word, bit;
|
||||||
|
// 计算命令在allowed_commands当中对应的bit位
|
||||||
if (ACLGetCommandBitCoordinates(id,&word,&bit) == C_ERR) return 0;
|
if (ACLGetCommandBitCoordinates(id,&word,&bit) == C_ERR) return 0;
|
||||||
return (u->allowed_commands[word] & bit) != 0;
|
return (u->allowed_commands[word] & bit) != 0;
|
||||||
}
|
}
|
||||||
@ -927,18 +938,22 @@ char *ACLSetUserStringError(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize the default user, that will always exist for all the process
|
/* Initialize the default user, that will always exist for all the process
|
||||||
* lifetime. */
|
* lifetime.
|
||||||
|
* 初始化默认用户
|
||||||
|
* */
|
||||||
void ACLInitDefaultUser(void) {
|
void ACLInitDefaultUser(void) {
|
||||||
DefaultUser = ACLCreateUser("default",7);
|
DefaultUser = ACLCreateUser("default",7);
|
||||||
ACLSetUser(DefaultUser,"+@all",-1);
|
ACLSetUser(DefaultUser,"+@all",-1); // 默认用户赋予所有命令的权限
|
||||||
ACLSetUser(DefaultUser,"~*",-1);
|
ACLSetUser(DefaultUser,"~*",-1); // 可以操作任何key
|
||||||
ACLSetUser(DefaultUser,"on",-1);
|
ACLSetUser(DefaultUser,"on",-1); // 默认开启
|
||||||
ACLSetUser(DefaultUser,"nopass",-1);
|
ACLSetUser(DefaultUser,"nopass",-1);// 默认不需要密码
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialization of the ACL subsystem. */
|
/* Initialization of the ACL subsystem.
|
||||||
|
* 初始化ACL子系统
|
||||||
|
* */
|
||||||
void ACLInit(void) {
|
void ACLInit(void) {
|
||||||
Users = raxNew();
|
Users = raxNew(); // 初始化用户信息
|
||||||
UsersToLoad = listCreate();
|
UsersToLoad = listCreate();
|
||||||
ACLLog = listCreate();
|
ACLLog = listCreate();
|
||||||
ACLInitDefaultUser();
|
ACLInitDefaultUser();
|
||||||
@ -1056,7 +1071,9 @@ user *ACLGetUserByName(const char *name, size_t namelen) {
|
|||||||
* ACL_DENIED_CMD or ACL_DENIED_KEY is returned: the first in case the
|
* 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 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
|
* command, the second if the command is denied because the user is trying
|
||||||
* to access keys that are not among the specified patterns. */
|
* to access keys that are not among the specified patterns.
|
||||||
|
* 检查当前用户是否拥有对当前命令的权限
|
||||||
|
* * */
|
||||||
int ACLCheckCommandPerm(client *c, int *keyidxptr) {
|
int ACLCheckCommandPerm(client *c, int *keyidxptr) {
|
||||||
user *u = c->user;
|
user *u = c->user;
|
||||||
uint64_t id = c->cmd->id;
|
uint64_t id = c->cmd->id;
|
||||||
@ -1069,7 +1086,9 @@ int ACLCheckCommandPerm(client *c, int *keyidxptr) {
|
|||||||
c->cmd->proc != authCommand)
|
c->cmd->proc != authCommand)
|
||||||
{
|
{
|
||||||
/* If the bit is not set we have to check further, in case the
|
/* If the bit is not set we have to check further, in case the
|
||||||
* command is allowed just with that specific subcommand. */
|
* command is allowed just with that specific subcommand.
|
||||||
|
*
|
||||||
|
* */
|
||||||
if (ACLGetUserCommandBit(u,id) == 0) {
|
if (ACLGetUserCommandBit(u,id) == 0) {
|
||||||
/* Check if the subcommand matches. */
|
/* Check if the subcommand matches. */
|
||||||
if (c->argc < 2 ||
|
if (c->argc < 2 ||
|
||||||
@ -1151,7 +1170,9 @@ int ACLCheckCommandPerm(client *c, int *keyidxptr) {
|
|||||||
*
|
*
|
||||||
* When an error is detected and C_ERR is returned, the function populates
|
* When an error is detected and C_ERR is returned, the function populates
|
||||||
* by reference (if not set to NULL) the argc_err argument with the index
|
* by reference (if not set to NULL) the argc_err argument with the index
|
||||||
* of the argv vector that caused the error. */
|
* of the argv vector that caused the error.
|
||||||
|
* 加载user配置的ACL信息
|
||||||
|
* * * */
|
||||||
int ACLAppendUserForLoading(sds *argv, int argc, int *argc_err) {
|
int ACLAppendUserForLoading(sds *argv, int argc, int *argc_err) {
|
||||||
if (argc < 2 || strcasecmp(argv[0],"user")) {
|
if (argc < 2 || strcasecmp(argv[0],"user")) {
|
||||||
if (argc_err) *argc_err = 0;
|
if (argc_err) *argc_err = 0;
|
||||||
@ -1183,7 +1204,9 @@ int ACLAppendUserForLoading(sds *argv, int argc, int *argc_err) {
|
|||||||
|
|
||||||
/* This function will load the configured users appended to the server
|
/* This function will load the configured users appended to the server
|
||||||
* configuration via ACLAppendUserForLoading(). On loading errors it will
|
* configuration via ACLAppendUserForLoading(). On loading errors it will
|
||||||
* log an error and return C_ERR, otherwise C_OK will be returned. */
|
* log an error and return C_ERR, otherwise C_OK will be returned.
|
||||||
|
* 从user配置项中读取ACl信息
|
||||||
|
* * */
|
||||||
int ACLLoadConfiguredUsers(void) {
|
int ACLLoadConfiguredUsers(void) {
|
||||||
listIter li;
|
listIter li;
|
||||||
listNode *ln;
|
listNode *ln;
|
||||||
@ -1192,11 +1215,12 @@ int ACLLoadConfiguredUsers(void) {
|
|||||||
sds *aclrules = listNodeValue(ln);
|
sds *aclrules = listNodeValue(ln);
|
||||||
sds username = aclrules[0];
|
sds username = aclrules[0];
|
||||||
|
|
||||||
|
// 检查ACL用户名当中是否存在空格
|
||||||
if (ACLStringHasSpaces(aclrules[0],sdslen(aclrules[0]))) {
|
if (ACLStringHasSpaces(aclrules[0],sdslen(aclrules[0]))) {
|
||||||
serverLog(LL_WARNING,"Spaces not allowed in ACL usernames");
|
serverLog(LL_WARNING,"Spaces not allowed in ACL usernames");
|
||||||
return C_ERR;
|
return C_ERR;
|
||||||
}
|
}
|
||||||
|
// 创建ACL用户
|
||||||
user *u = ACLCreateUser(username,sdslen(username));
|
user *u = ACLCreateUser(username,sdslen(username));
|
||||||
if (!u) {
|
if (!u) {
|
||||||
u = ACLGetUserByName(username,sdslen(username));
|
u = ACLGetUserByName(username,sdslen(username));
|
||||||
@ -1206,6 +1230,7 @@ int ACLLoadConfiguredUsers(void) {
|
|||||||
|
|
||||||
/* Load every rule defined for this user. */
|
/* Load every rule defined for this user. */
|
||||||
for (int j = 1; aclrules[j]; j++) {
|
for (int j = 1; aclrules[j]; j++) {
|
||||||
|
// 添加当前用户的所有属性
|
||||||
if (ACLSetUser(u,aclrules[j],sdslen(aclrules[j])) != C_OK) {
|
if (ACLSetUser(u,aclrules[j],sdslen(aclrules[j])) != C_OK) {
|
||||||
char *errmsg = ACLSetUserStringError();
|
char *errmsg = ACLSetUserStringError();
|
||||||
serverLog(LL_WARNING,"Error loading ACL rule '%s' for "
|
serverLog(LL_WARNING,"Error loading ACL rule '%s' for "
|
||||||
@ -1216,7 +1241,9 @@ int ACLLoadConfiguredUsers(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Having a disabled user in the configuration may be an error,
|
/* Having a disabled user in the configuration may be an error,
|
||||||
* warn about it without returning any error to the caller. */
|
* warn about it without returning any error to the caller.
|
||||||
|
* 用户没有开启的时候打印到日志里面
|
||||||
|
* */
|
||||||
if (u->flags & USER_FLAG_DISABLED) {
|
if (u->flags & USER_FLAG_DISABLED) {
|
||||||
serverLog(LL_NOTICE, "The user '%s' is disabled (there is no "
|
serverLog(LL_NOTICE, "The user '%s' is disabled (there is no "
|
||||||
"'on' modifier in the user description). Make "
|
"'on' modifier in the user description). Make "
|
||||||
@ -1249,7 +1276,10 @@ int ACLLoadConfiguredUsers(void) {
|
|||||||
*
|
*
|
||||||
* At the end of the process, if no errors were found in the whole file then
|
* At the end of the process, if no errors were found in the whole file then
|
||||||
* NULL is returned. Otherwise an SDS string describing in a single line
|
* NULL is returned. Otherwise an SDS string describing in a single line
|
||||||
* a description of all the issues found is returned. */
|
* a description of all the issues found is returned.
|
||||||
|
*
|
||||||
|
* 从aclfile配置的文件里面读取ACL信息
|
||||||
|
* */
|
||||||
sds ACLLoadFromFile(const char *filename) {
|
sds ACLLoadFromFile(const char *filename) {
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
@ -1466,7 +1496,9 @@ cleanup:
|
|||||||
* loaded, and we are ready to start, in order to load the ACLs either from
|
* loaded, and we are ready to start, in order to load the ACLs either from
|
||||||
* the pending list of users defined in redis.conf, or from the ACL file.
|
* the pending list of users defined in redis.conf, or from the ACL file.
|
||||||
* The function will just exit with an error if the user is trying to mix
|
* The function will just exit with an error if the user is trying to mix
|
||||||
* both the loading methods. */
|
* both the loading methods.
|
||||||
|
* 加载redis.conf配置项aclfile对应文件里面的ACL权限信息
|
||||||
|
* */
|
||||||
void ACLLoadUsersAtStartup(void) {
|
void ACLLoadUsersAtStartup(void) {
|
||||||
if (server.acl_filename[0] != '\0' && listLength(UsersToLoad) != 0) {
|
if (server.acl_filename[0] != '\0' && listLength(UsersToLoad) != 0) {
|
||||||
serverLog(LL_WARNING,
|
serverLog(LL_WARNING,
|
||||||
@ -1477,7 +1509,7 @@ void ACLLoadUsersAtStartup(void) {
|
|||||||
"directly in your redis.conf, but not both.");
|
"directly in your redis.conf, but not both.");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
// 加载user配置的ACL信息
|
||||||
if (ACLLoadConfiguredUsers() == C_ERR) {
|
if (ACLLoadConfiguredUsers() == C_ERR) {
|
||||||
serverLog(LL_WARNING,
|
serverLog(LL_WARNING,
|
||||||
"Critical error while loading ACLs. Exiting.");
|
"Critical error while loading ACLs. Exiting.");
|
||||||
|
@ -1872,7 +1872,9 @@ void processInputBuffer(client *c) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We are finally ready to execute the command. */
|
/* We are finally ready to execute the command.
|
||||||
|
* 真正执行代码的函数
|
||||||
|
* */
|
||||||
if (processCommandAndResetClient(c) == C_ERR) {
|
if (processCommandAndResetClient(c) == C_ERR) {
|
||||||
/* If the client is no longer valid, we avoid exiting this
|
/* If the client is no longer valid, we avoid exiting this
|
||||||
* loop and trimming the client buffer later. So we return
|
* loop and trimming the client buffer later. So we return
|
||||||
|
@ -3418,7 +3418,9 @@ int processCommand(client *c) {
|
|||||||
/* The QUIT command is handled separately. Normal command procs will
|
/* The QUIT command is handled separately. Normal command procs will
|
||||||
* go through checking for replication and QUIT will cause trouble
|
* go through checking for replication and QUIT will cause trouble
|
||||||
* when FORCE_REPLICATION is enabled and would be implemented in
|
* when FORCE_REPLICATION is enabled and would be implemented in
|
||||||
* a regular command proc. */
|
* a regular command proc.
|
||||||
|
* 首先處理quit命令
|
||||||
|
* * */
|
||||||
if (!strcasecmp(c->argv[0]->ptr,"quit")) {
|
if (!strcasecmp(c->argv[0]->ptr,"quit")) {
|
||||||
addReply(c,shared.ok);
|
addReply(c,shared.ok);
|
||||||
c->flags |= CLIENT_CLOSE_AFTER_REPLY;
|
c->flags |= CLIENT_CLOSE_AFTER_REPLY;
|
||||||
|
13
src/server.h
13
src/server.h
@ -153,7 +153,7 @@ typedef long long ustime_t; /* microsecond time type. */
|
|||||||
/* Hash table parameters */
|
/* Hash table parameters */
|
||||||
#define HASHTABLE_MIN_FILL 10 /* Minimal hash table fill 10% */
|
#define HASHTABLE_MIN_FILL 10 /* Minimal hash table fill 10% */
|
||||||
|
|
||||||
/* Command flags. Please check the command table defined in the redis.c file
|
/* Command flags. Please check the command table defined in the server.c file
|
||||||
* for more information about the meaning of every flag. */
|
* for more information about the meaning of every flag. */
|
||||||
#define CMD_WRITE (1ULL<<0) /* "write" flag */
|
#define CMD_WRITE (1ULL<<0) /* "write" flag */
|
||||||
#define CMD_READONLY (1ULL<<1) /* "read-only" flag */
|
#define CMD_READONLY (1ULL<<1) /* "read-only" flag */
|
||||||
@ -721,7 +721,9 @@ typedef struct readyList {
|
|||||||
|
|
||||||
/* This structure represents a Redis user. This is useful for ACLs, the
|
/* This structure represents a Redis user. This is useful for ACLs, the
|
||||||
* user is associated to the connection after the connection is authenticated.
|
* user is associated to the connection after the connection is authenticated.
|
||||||
* If there is no associated user, the connection uses the default user. */
|
* If there is no associated user, the connection uses the default user.
|
||||||
|
* 表示Redis ACL所有的用户不能超过1024个
|
||||||
|
* */
|
||||||
#define USER_COMMAND_BITS_COUNT 1024 /* The total number of command bits
|
#define USER_COMMAND_BITS_COUNT 1024 /* The total number of command bits
|
||||||
in the user structure. The last valid
|
in the user structure. The last valid
|
||||||
command ID we can set in the user
|
command ID we can set in the user
|
||||||
@ -736,6 +738,7 @@ typedef struct readyList {
|
|||||||
no AUTH is needed, and every
|
no AUTH is needed, and every
|
||||||
connection is immediately
|
connection is immediately
|
||||||
authenticated. */
|
authenticated. */
|
||||||
|
/* 用户信息 */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
sds name; /* The username as an SDS string. */
|
sds name; /* The username as an SDS string. */
|
||||||
uint64_t flags; /* See USER_FLAG_* */
|
uint64_t flags; /* See USER_FLAG_* */
|
||||||
@ -746,7 +749,9 @@ typedef struct {
|
|||||||
*
|
*
|
||||||
* If the bit for a given command is NOT set and the command has
|
* If the bit for a given command is NOT set and the command has
|
||||||
* subcommands, Redis will also check allowed_subcommands in order to
|
* subcommands, Redis will also check allowed_subcommands in order to
|
||||||
* understand if the command can be executed. */
|
* understand if the command can be executed.
|
||||||
|
*
|
||||||
|
* */
|
||||||
uint64_t allowed_commands[USER_COMMAND_BITS_COUNT/64];
|
uint64_t allowed_commands[USER_COMMAND_BITS_COUNT/64];
|
||||||
|
|
||||||
/* This array points, for each command ID (corresponding to the command
|
/* This array points, for each command ID (corresponding to the command
|
||||||
@ -1428,7 +1433,7 @@ struct redisServer {
|
|||||||
long long latency_monitor_threshold;
|
long long latency_monitor_threshold;
|
||||||
dict *latency_events;
|
dict *latency_events;
|
||||||
/* ACLs */
|
/* ACLs */
|
||||||
char *acl_filename; /* ACL Users file. NULL if not configured. */
|
char *acl_filename; /* ACL Users file. NULL if not configured.ACL文件路径,需要配置已经存在的文件,否则会报错启动失败 */
|
||||||
unsigned long acllog_max_len; /* Maximum length of the ACL LOG list. */
|
unsigned long acllog_max_len; /* Maximum length of the ACL LOG list. */
|
||||||
sds requirepass; /* Remember the cleartext password set with the
|
sds requirepass; /* Remember the cleartext password set with the
|
||||||
old "requirepass" directive for backward
|
old "requirepass" directive for backward
|
||||||
|
Loading…
Reference in New Issue
Block a user