summaryrefslogtreecommitdiff
path: root/src/acl.c
diff options
context:
space:
mode:
authorantirez <antirez@gmail.com>2019-01-31 18:33:14 +0100
committerantirez <antirez@gmail.com>2019-01-31 18:33:14 +0100
commitec1aee031c847dc3929b2556633ffa33eaf3a5e2 (patch)
tree913162eff898f8bc84abd466fe8245071c712a2f /src/acl.c
parent74b7afdf71e7e06f998e5955b4a088290534acb9 (diff)
downloadredis-ec1aee031c847dc3929b2556633ffa33eaf3a5e2.tar.gz
ACL: implement DELUSER.
Diffstat (limited to 'src/acl.c')
-rw-r--r--src/acl.c49
1 files changed, 49 insertions, 0 deletions
diff --git a/src/acl.c b/src/acl.c
index 58ffece34..1df511329 100644
--- a/src/acl.c
+++ b/src/acl.c
@@ -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) {