summaryrefslogtreecommitdiff
path: root/src/acl.c
diff options
context:
space:
mode:
authorMadelyn Olson <madelyneolson@gmail.com>2020-10-26 21:23:30 -0700
committerMadelyn Olson <34459052+madolson@users.noreply.github.com>2020-10-28 10:01:20 -0700
commit411bcf1a41d2758823d17e0864ef45e5f3948b7a (patch)
tree3461741f1ca4694ca3af54d2c0d09bcb01e9249c /src/acl.c
parentefd17316ab122f5ddd9ecd89a98f30759b076a10 (diff)
downloadredis-411bcf1a41d2758823d17e0864ef45e5f3948b7a.tar.gz
Further improved ACL algorithm for picking categories
Diffstat (limited to 'src/acl.c')
-rw-r--r--src/acl.c69
1 files changed, 47 insertions, 22 deletions
diff --git a/src/acl.c b/src/acl.c
index d9ee774c8..6f28818a0 100644
--- a/src/acl.c
+++ b/src/acl.c
@@ -479,36 +479,61 @@ sds ACLDescribeUserCommandRules(user *u) {
ACLSetUser(fakeuser,"-@all",-1);
}
- /* Try to add or subtract each category one after the other. Often a
- * single category will not perfectly match the set of commands into
- * it, so at the end we do a final pass adding/removing the single commands
- * needed to make the bitmap exactly match. A temp user is maintained to
- * keep track of categories already applied. */
+ /* Attempt to find a good approximation for categories and commands
+ * based on the current bits used, by looping over the category list
+ * and applying the best fit each time. Often a set of categories will not
+ * perfectly match the set of commands into it, so at the end we do a
+ * final pass adding/removing the single commands needed to make the bitmap
+ * exactly match. A temp user is maintained to keep track of categories
+ * already applied. */
user tu = {0};
user *tempuser = &tu;
memcpy(tempuser->allowed_commands,
u->allowed_commands,
sizeof(u->allowed_commands));
-
- for (int j = 0; ACLCommandCategories[j].flag != 0; j++) {
- unsigned long on, off;
- ACLCountCategoryBitsForUser(tempuser,&on,&off,ACLCommandCategories[j].name);
- if ((additive && on > off) || (!additive && off > on)) {
- sds op = sdsnewlen(additive ? "+@" : "-@", 2);
- op = sdscat(op,ACLCommandCategories[j].name);
- ACLSetUser(fakeuser,op,-1);
-
- sds invop = sdsnewlen(additive ? "-@" : "+@", 2);
- invop = sdscat(invop,ACLCommandCategories[j].name);
- ACLSetUser(tempuser,invop,-1);
-
- rules = sdscatsds(rules,op);
- rules = sdscatlen(rules," ",1);
- sdsfree(op);
- sdsfree(invop);
+ while (1) {
+ int best = -1;
+ unsigned long mindiff = INT_MAX, maxsame = 0;
+ for (int j = 0; ACLCommandCategories[j].flag != 0; j++) {
+ unsigned long on, off, diff, same;
+ ACLCountCategoryBitsForUser(tempuser,&on,&off,ACLCommandCategories[j].name);
+
+ /* Check if the current category is the best this loop:
+ * * It has more commands in common with the user than commands
+ * that are different.
+ * AND EITHER
+ * * It has the fewest number of differences
+ * than the best match we have found so far.
+ * * OR it matches the fewest number of differences
+ * that we've seen but it has more in common. */
+ diff = additive ? off : on;
+ same = additive ? on : off;
+ if (same > diff &&
+ ((diff < mindiff) || (diff == mindiff && same > maxsame))) {
+ best = j;
+ mindiff = diff;
+ maxsame = same;
+ }
}
+
+ /* We didn't find a match */
+ if (best == -1) break;
+
+ sds op = sdsnewlen(additive ? "+@" : "-@", 2);
+ op = sdscat(op,ACLCommandCategories[best].name);
+ ACLSetUser(fakeuser,op,-1);
+
+ sds invop = sdsnewlen(additive ? "-@" : "+@", 2);
+ invop = sdscat(invop,ACLCommandCategories[best].name);
+ ACLSetUser(tempuser,invop,-1);
+
+ rules = sdscatsds(rules,op);
+ rules = sdscatlen(rules," ",1);
+ sdsfree(op);
+ sdsfree(invop);
}
+
/* Fix the final ACLs with single commands differences. */
dictIterator *di = dictGetIterator(server.orig_commands);
dictEntry *de;