diff options
author | antirez <antirez@gmail.com> | 2019-01-31 18:33:14 +0100 |
---|---|---|
committer | antirez <antirez@gmail.com> | 2019-01-31 18:33:14 +0100 |
commit | ec1aee031c847dc3929b2556633ffa33eaf3a5e2 (patch) | |
tree | 913162eff898f8bc84abd466fe8245071c712a2f /src/acl.c | |
parent | 74b7afdf71e7e06f998e5955b4a088290534acb9 (diff) | |
download | redis-ec1aee031c847dc3929b2556633ffa33eaf3a5e2.tar.gz |
ACL: implement DELUSER.
Diffstat (limited to 'src/acl.c')
-rw-r--r-- | src/acl.c | 49 |
1 files changed, 49 insertions, 0 deletions
@@ -80,6 +80,7 @@ struct ACLUserFlag { }; void ACLResetSubcommandsForCommand(user *u, unsigned long id); +void ACLResetSubcommands(user *u); /* ============================================================================= * Helper functions for the rest of the ACL implementation @@ -175,6 +176,16 @@ user *ACLCreateUser(const char *name, size_t namelen) { return u; } +/* Release the memory used by the user structure. Note that this function + * will not remove the user from the Users global radix tree. */ +void ACLFreeUser(user *u) { + sdsfree(u->name); + listRelease(u->passwords); + listRelease(u->patterns); + ACLResetSubcommands(u); + zfree(u); +} + /* Given a command ID, this function set by reference 'word' and 'bit' * so that user->allowed_commands[word] will address the right word * where the corresponding bit for the provided ID is stored, and @@ -921,6 +932,44 @@ void aclCommand(client *c) { } } addReply(c,shared.ok); + } else if (!strcasecmp(sub,"deluser") && c->argc >= 3) { + int deleted = 0; + for (int j = 2; j < c->argc; j++) { + sds username = c->argv[j]->ptr; + if (!strcmp(username,"default")) { + addReplyError(c,"The 'default' user cannot be removed"); + return; + } + user *u; + if (raxRemove(Users,(unsigned char*)username, + sdslen(username), + (void**)&u)) + { + /* When a user is deleted we need to cycle the active + * connections in order to kill all the pending ones that + * are authenticated with such user. */ + ACLFreeUser(u); + listIter li; + listNode *ln; + listRewind(server.clients,&li); + while ((ln = listNext(&li)) != NULL) { + client *c = listNodeValue(ln); + if (c->user == u) { + /* We'll free the conenction asynchronously, so + * in theory to set a different user is not needed. + * However if there are bugs in Redis, soon or later + * this may result in some security hole: it's much + * more defensive to set the default user and put + * it in non authenticated mode. */ + c->user = DefaultUser; + c->authenticated = 0; + freeClientAsync(c); + } + } + deleted++; + } + } + addReplyLongLong(c,deleted); } else if (!strcasecmp(sub,"getuser") && c->argc == 3) { user *u = ACLGetUserByName(c->argv[2]->ptr,sdslen(c->argv[2]->ptr)); if (u == NULL) { |