aboutsummaryrefslogtreecommitdiff
path: root/examples/redis-unstable/src/acl.c
diff options
context:
space:
mode:
Diffstat (limited to 'examples/redis-unstable/src/acl.c')
-rw-r--r--examples/redis-unstable/src/acl.c3313
1 files changed, 3313 insertions, 0 deletions
diff --git a/examples/redis-unstable/src/acl.c b/examples/redis-unstable/src/acl.c
new file mode 100644
index 0000000..37d504d
--- /dev/null
+++ b/examples/redis-unstable/src/acl.c
@@ -0,0 +1,3313 @@
1/*
2 * Copyright (c) 2018-Present, Redis Ltd.
3 * All rights reserved.
4 *
5 * Copyright (c) 2024-present, Valkey contributors.
6 * All rights reserved.
7 *
8 * Licensed under your choice of (a) the Redis Source Available License 2.0
9 * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the
10 * GNU Affero General Public License v3 (AGPLv3).
11 */
12
13#include "server.h"
14#include "cluster.h"
15#include "sha256.h"
16#include <fcntl.h>
17#include <ctype.h>
18
19/* =============================================================================
20 * Global state for ACLs
21 * ==========================================================================*/
22
23rax *Users; /* Table mapping usernames to user structures. */
24
25user *DefaultUser; /* Global reference to the default user.
26 Every new connection is associated to it, if no
27 AUTH or HELLO is used to authenticate with a
28 different user. */
29
30list *UsersToLoad; /* This is a list of users found in the configuration file
31 that we'll need to load in the final stage of Redis
32 initialization, after all the modules are already
33 loaded. Every list element is a NULL terminated
34 array of SDS pointers: the first is the user name,
35 all the remaining pointers are ACL rules in the same
36 format as ACLSetUser(). */
37list *ACLLog; /* Our security log, the user is able to inspect that
38 using the ACL LOG command .*/
39
40long long ACLLogEntryCount = 0; /* Number of ACL log entries created */
41
42static rax *commandId = NULL; /* Command name to id mapping */
43
44static unsigned long nextid = 0; /* Next command id that has not been assigned */
45
46#define ACL_MAX_CATEGORIES 64 /* Maximum number of command categories */
47
48struct ACLCategoryItem {
49 char *name;
50 uint64_t flag;
51} ACLDefaultCommandCategories[] = { /* See redis.conf for details on each category. */
52 {"keyspace", ACL_CATEGORY_KEYSPACE},
53 {"read", ACL_CATEGORY_READ},
54 {"write", ACL_CATEGORY_WRITE},
55 {"set", ACL_CATEGORY_SET},
56 {"sortedset", ACL_CATEGORY_SORTEDSET},
57 {"list", ACL_CATEGORY_LIST},
58 {"hash", ACL_CATEGORY_HASH},
59 {"string", ACL_CATEGORY_STRING},
60 {"bitmap", ACL_CATEGORY_BITMAP},
61 {"hyperloglog", ACL_CATEGORY_HYPERLOGLOG},
62 {"geo", ACL_CATEGORY_GEO},
63 {"stream", ACL_CATEGORY_STREAM},
64 {"pubsub", ACL_CATEGORY_PUBSUB},
65 {"admin", ACL_CATEGORY_ADMIN},
66 {"fast", ACL_CATEGORY_FAST},
67 {"slow", ACL_CATEGORY_SLOW},
68 {"blocking", ACL_CATEGORY_BLOCKING},
69 {"dangerous", ACL_CATEGORY_DANGEROUS},
70 {"connection", ACL_CATEGORY_CONNECTION},
71 {"transaction", ACL_CATEGORY_TRANSACTION},
72 {"scripting", ACL_CATEGORY_SCRIPTING},
73 {NULL,0} /* Terminator. */
74};
75
76static struct ACLCategoryItem *ACLCommandCategories = NULL;
77static size_t nextCommandCategory = 0; /* Index of the next command category to be added */
78
79/* Implements the ability to add to the list of ACL categories at runtime. Since each ACL category
80 * also requires a bit in the acl_categories flag, there is a limit to the number that can be added.
81 * The new ACL categories occupy the remaining bits of acl_categories flag, other than the bits
82 * occupied by the default ACL command categories.
83 *
84 * The optional `flag` argument allows the assignment of the `acl_categories` flag bit to the ACL category.
85 * When adding a new category, except for the default ACL command categories, this arguments should be `0`
86 * to allow the function to assign the next available `acl_categories` flag bit to the new ACL category.
87 *
88 * returns 1 -> Added, 0 -> Failed (out of space)
89 *
90 * This function is present here to gain access to the ACLCommandCategories array and add a new ACL category.
91 */
92int ACLAddCommandCategory(const char *name, uint64_t flag) {
93 if (nextCommandCategory >= ACL_MAX_CATEGORIES) return 0;
94 ACLCommandCategories[nextCommandCategory].name = zstrdup(name);
95 ACLCommandCategories[nextCommandCategory].flag = flag != 0 ? flag : (1ULL<<nextCommandCategory);
96 nextCommandCategory++;
97 return 1;
98}
99
100/* Initializes ACLCommandCategories with default ACL categories and allocates space for
101 * new ACL categories.
102 */
103void ACLInitCommandCategories(void) {
104 ACLCommandCategories = zcalloc(sizeof(struct ACLCategoryItem) * (ACL_MAX_CATEGORIES + 1));
105 for (int j = 0; ACLDefaultCommandCategories[j].flag; j++) {
106 serverAssert(ACLAddCommandCategory(ACLDefaultCommandCategories[j].name, ACLDefaultCommandCategories[j].flag));
107 }
108}
109
110/* This function removes the specified number of categories from the trailing end of
111 * the `ACLCommandCategories` array.
112 * The purpose of this is to remove the categories added by modules that fail
113 * during the onload function.
114 */
115void ACLCleanupCategoriesOnFailure(size_t num_acl_categories_added) {
116 for (size_t j = nextCommandCategory - num_acl_categories_added; j < nextCommandCategory; j++) {
117 zfree(ACLCommandCategories[j].name);
118 ACLCommandCategories[j].name = NULL;
119 ACLCommandCategories[j].flag = 0;
120 }
121 nextCommandCategory -= num_acl_categories_added;
122}
123
124struct ACLUserFlag {
125 const char *name;
126 uint64_t flag;
127} ACLUserFlags[] = {
128 /* Note: the order here dictates the emitted order at ACLDescribeUser */
129 {"on", USER_FLAG_ENABLED},
130 {"off", USER_FLAG_DISABLED},
131 {"nopass", USER_FLAG_NOPASS},
132 {"skip-sanitize-payload", USER_FLAG_SANITIZE_PAYLOAD_SKIP},
133 {"sanitize-payload", USER_FLAG_SANITIZE_PAYLOAD},
134 {NULL,0} /* Terminator. */
135};
136
137struct ACLSelectorFlags {
138 const char *name;
139 uint64_t flag;
140} ACLSelectorFlags[] = {
141 /* Note: the order here dictates the emitted order at ACLDescribeUser */
142 {"allkeys", SELECTOR_FLAG_ALLKEYS},
143 {"allchannels", SELECTOR_FLAG_ALLCHANNELS},
144 {"allcommands", SELECTOR_FLAG_ALLCOMMANDS},
145 {NULL,0} /* Terminator. */
146};
147
148/* ACL selectors are private and not exposed outside of acl.c. */
149typedef struct {
150 uint32_t flags; /* See SELECTOR_FLAG_* */
151 /* The bit in allowed_commands is set if this user has the right to
152 * execute this command.
153 *
154 * If the bit for a given command is NOT set and the command has
155 * allowed first-args, Redis will also check allowed_firstargs in order to
156 * understand if the command can be executed. */
157 uint64_t allowed_commands[USER_COMMAND_BITS_COUNT/64];
158 /* allowed_firstargs is used by ACL rules to block access to a command unless a
159 * specific argv[1] is given.
160 *
161 * For each command ID (corresponding to the command bit set in allowed_commands),
162 * This array points to an array of SDS strings, terminated by a NULL pointer,
163 * with all the first-args that are allowed for this command. When no first-arg
164 * matching is used, the field is just set to NULL to avoid allocating
165 * USER_COMMAND_BITS_COUNT pointers. */
166 sds **allowed_firstargs;
167 list *patterns; /* A list of allowed key patterns. If this field is NULL
168 the user cannot mention any key in a command, unless
169 the flag ALLKEYS is set in the user. */
170 list *channels; /* A list of allowed Pub/Sub channel patterns. If this
171 field is NULL the user cannot mention any channel in a
172 `PUBLISH` or [P][UNSUBSCRIBE] command, unless the flag
173 ALLCHANNELS is set in the user. */
174 sds command_rules; /* A string representation of the ordered categories and commands, this
175 * is used to regenerate the original ACL string for display. */
176} aclSelector;
177
178void ACLResetFirstArgsForCommand(aclSelector *selector, unsigned long id);
179void ACLResetFirstArgs(aclSelector *selector);
180void ACLAddAllowedFirstArg(aclSelector *selector, unsigned long id, const char *sub);
181void ACLFreeLogEntry(void *le);
182int ACLSetSelector(aclSelector *selector, const char *op, size_t oplen);
183
184/* The length of the string representation of a hashed password. */
185#define HASH_PASSWORD_LEN (SHA256_BLOCK_SIZE*2)
186
187/* =============================================================================
188 * Helper functions for the rest of the ACL implementation
189 * ==========================================================================*/
190
191/* Return zero if strings are the same, non-zero if they are not.
192 * The comparison is performed in a way that prevents an attacker to obtain
193 * information about the nature of the strings just monitoring the execution
194 * time of the function. Note: The two strings must be the same length.
195 */
196int time_independent_strcmp(char *a, char *b, int len) {
197 int diff = 0;
198 for (int j = 0; j < len; j++) {
199 diff |= (a[j] ^ b[j]);
200 }
201 return diff; /* If zero strings are the same. */
202}
203
204/* Given an SDS string, returns the SHA256 hex representation as a
205 * new SDS string. */
206sds ACLHashPassword(unsigned char *cleartext, size_t len) {
207 SHA256_CTX ctx;
208 unsigned char hash[SHA256_BLOCK_SIZE];
209 char hex[HASH_PASSWORD_LEN];
210 char *cset = "0123456789abcdef";
211
212 sha256_init(&ctx);
213 sha256_update(&ctx,(unsigned char*)cleartext,len);
214 sha256_final(&ctx,hash);
215
216 for (int j = 0; j < SHA256_BLOCK_SIZE; j++) {
217 hex[j*2] = cset[((hash[j]&0xF0)>>4)];
218 hex[j*2+1] = cset[(hash[j]&0xF)];
219 }
220 return sdsnewlen(hex,HASH_PASSWORD_LEN);
221}
222
223/* Given a hash and the hash length, returns C_OK if it is a valid password
224 * hash, or C_ERR otherwise. */
225int ACLCheckPasswordHash(unsigned char *hash, int hashlen) {
226 if (hashlen != HASH_PASSWORD_LEN) {
227 return C_ERR;
228 }
229
230 /* Password hashes can only be characters that represent
231 * hexadecimal values, which are numbers and lowercase
232 * characters 'a' through 'f'. */
233 for(int i = 0; i < HASH_PASSWORD_LEN; i++) {
234 char c = hash[i];
235 if ((c < 'a' || c > 'f') && (c < '0' || c > '9')) {
236 return C_ERR;
237 }
238 }
239 return C_OK;
240}
241
242/* =============================================================================
243 * Low level ACL API
244 * ==========================================================================*/
245
246/* Return 1 if the specified string contains spaces or null characters.
247 * We do this for usernames and key patterns for simpler rewriting of
248 * ACL rules, presentation on ACL list, and to avoid subtle security bugs
249 * that may arise from parsing the rules in presence of escapes.
250 * The function returns 0 if the string has no spaces. */
251int ACLStringHasSpaces(const char *s, size_t len) {
252 for (size_t i = 0; i < len; i++) {
253 if (isspace(s[i]) || s[i] == 0) return 1;
254 }
255 return 0;
256}
257
258/* Given the category name the command returns the corresponding flag, or
259 * zero if there is no match. */
260uint64_t ACLGetCommandCategoryFlagByName(const char *name) {
261 for (int j = 0; ACLCommandCategories[j].flag != 0; j++) {
262 if (!strcasecmp(name,ACLCommandCategories[j].name)) {
263 return ACLCommandCategories[j].flag;
264 }
265 }
266 return 0; /* No match. */
267}
268
269/* Method for searching for a user within a list of user definitions. The
270 * list contains an array of user arguments, and we are only
271 * searching the first argument, the username, for a match. */
272int ACLListMatchLoadedUser(void *definition, void *user) {
273 sds *user_definition = definition;
274 return sdscmp(user_definition[0], user) == 0;
275}
276
277/* Method for passwords/pattern comparison used for the user->passwords list
278 * so that we can search for items with listSearchKey(). */
279int ACLListMatchSds(void *a, void *b) {
280 return sdscmp(a,b) == 0;
281}
282
283/* Method to free list elements from ACL users password/patterns lists. */
284void ACLListFreeSds(void *item) {
285 sdsfreegeneric(item);
286}
287
288/* Method to duplicate list elements from ACL users password/patterns lists. */
289void *ACLListDupSds(void *item) {
290 return sdsdup(item);
291}
292
293/* Structure used for handling key patterns with different key
294 * based permissions. */
295typedef struct {
296 int flags; /* The ACL key permission types for this key pattern */
297 sds pattern; /* The pattern to match keys against */
298} keyPattern;
299
300/* Create a new key pattern. */
301keyPattern *ACLKeyPatternCreate(sds pattern, int flags) {
302 keyPattern *new = (keyPattern *) zmalloc(sizeof(keyPattern));
303 new->pattern = pattern;
304 new->flags = flags;
305 return new;
306}
307
308/* Free a key pattern and internal structures. */
309void ACLKeyPatternFree(keyPattern *pattern) {
310 sdsfree(pattern->pattern);
311 zfree(pattern);
312}
313
314/* Method for passwords/pattern comparison used for the user->passwords list
315 * so that we can search for items with listSearchKey(). */
316int ACLListMatchKeyPattern(void *a, void *b) {
317 return sdscmp(((keyPattern *) a)->pattern,((keyPattern *) b)->pattern) == 0;
318}
319
320/* Method to free list elements from ACL users password/patterns lists. */
321void ACLListFreeKeyPattern(void *item) {
322 ACLKeyPatternFree(item);
323}
324
325/* Method to duplicate list elements from ACL users password/patterns lists. */
326void *ACLListDupKeyPattern(void *item) {
327 keyPattern *old = (keyPattern *) item;
328 return ACLKeyPatternCreate(sdsdup(old->pattern), old->flags);
329}
330
331/* Append the string representation of a key pattern onto the
332 * provided base string. */
333sds sdsCatPatternString(sds base, keyPattern *pat) {
334 if (pat->flags == ACL_ALL_PERMISSION) {
335 base = sdscatlen(base,"~",1);
336 } else if (pat->flags == ACL_READ_PERMISSION) {
337 base = sdscatlen(base,"%R~",3);
338 } else if (pat->flags == ACL_WRITE_PERMISSION) {
339 base = sdscatlen(base,"%W~",3);
340 } else {
341 serverPanic("Invalid key pattern flag detected");
342 }
343 return sdscatsds(base, pat->pattern);
344}
345
346/* Create an empty selector with the provided set of initial
347 * flags. The selector will be default have no permissions. */
348aclSelector *ACLCreateSelector(int flags) {
349 aclSelector *selector = zmalloc(sizeof(aclSelector));
350 selector->flags = flags | server.acl_pubsub_default;
351 selector->patterns = listCreate();
352 selector->channels = listCreate();
353 selector->allowed_firstargs = NULL;
354 selector->command_rules = sdsempty();
355
356 listSetMatchMethod(selector->patterns,ACLListMatchKeyPattern);
357 listSetFreeMethod(selector->patterns,ACLListFreeKeyPattern);
358 listSetDupMethod(selector->patterns,ACLListDupKeyPattern);
359 listSetMatchMethod(selector->channels,ACLListMatchSds);
360 listSetFreeMethod(selector->channels,ACLListFreeSds);
361 listSetDupMethod(selector->channels,ACLListDupSds);
362 memset(selector->allowed_commands,0,sizeof(selector->allowed_commands));
363
364 return selector;
365}
366
367/* Cleanup the provided selector, including all interior structures. */
368void ACLFreeSelector(aclSelector *selector) {
369 listRelease(selector->patterns);
370 listRelease(selector->channels);
371 sdsfree(selector->command_rules);
372 ACLResetFirstArgs(selector);
373 zfree(selector);
374}
375
376/* Create an exact copy of the provided selector. */
377aclSelector *ACLCopySelector(aclSelector *src) {
378 aclSelector *dst = zmalloc(sizeof(aclSelector));
379 dst->flags = src->flags;
380 dst->patterns = listDup(src->patterns);
381 dst->channels = listDup(src->channels);
382 dst->command_rules = sdsdup(src->command_rules);
383 memcpy(dst->allowed_commands,src->allowed_commands,
384 sizeof(dst->allowed_commands));
385 dst->allowed_firstargs = NULL;
386 /* Copy the allowed first-args array of array of SDS strings. */
387 if (src->allowed_firstargs) {
388 for (int j = 0; j < USER_COMMAND_BITS_COUNT; j++) {
389 if (!(src->allowed_firstargs[j])) continue;
390 for (int i = 0; src->allowed_firstargs[j][i]; i++) {
391 ACLAddAllowedFirstArg(dst, j, src->allowed_firstargs[j][i]);
392 }
393 }
394 }
395 return dst;
396}
397
398/* List method for freeing a selector */
399void ACLListFreeSelector(void *a) {
400 ACLFreeSelector((aclSelector *) a);
401}
402
403/* List method for duplicating a selector */
404void *ACLListDuplicateSelector(void *src) {
405 return ACLCopySelector((aclSelector *)src);
406}
407
408/* All users have an implicit root selector which
409 * provides backwards compatibility to the old ACLs-
410 * permissions. */
411aclSelector *ACLUserGetRootSelector(user *u) {
412 serverAssert(listLength(u->selectors));
413 aclSelector *s = (aclSelector *) listNodeValue(listFirst(u->selectors));
414 serverAssert(s->flags & SELECTOR_FLAG_ROOT);
415 return s;
416}
417
418/* Create a new user with the specified name, store it in the list
419 * of users (the Users global radix tree), and returns a reference to
420 * the structure representing the user.
421 *
422 * If the user with such name already exists NULL is returned. */
423user *ACLCreateUser(const char *name, size_t namelen) {
424 if (raxFind(Users,(unsigned char*)name,namelen,NULL)) return NULL;
425 user *u = zmalloc(sizeof(*u));
426 u->name = sdsnewlen(name,namelen);
427 atomicSet(u->flags, USER_FLAG_DISABLED | USER_FLAG_SANITIZE_PAYLOAD);
428 u->passwords = listCreate();
429 u->acl_string = NULL;
430 listSetMatchMethod(u->passwords,ACLListMatchSds);
431 listSetFreeMethod(u->passwords,ACLListFreeSds);
432 listSetDupMethod(u->passwords,ACLListDupSds);
433
434 u->selectors = listCreate();
435 listSetFreeMethod(u->selectors,ACLListFreeSelector);
436 listSetDupMethod(u->selectors,ACLListDuplicateSelector);
437
438 /* Add the initial root selector */
439 aclSelector *s = ACLCreateSelector(SELECTOR_FLAG_ROOT);
440 listAddNodeHead(u->selectors, s);
441
442 raxInsert(Users,(unsigned char*)name,namelen,u,NULL);
443 return u;
444}
445
446/* This function should be called when we need an unlinked "fake" user
447 * we can use in order to validate ACL rules or for other similar reasons.
448 * The user will not get linked to the Users radix tree. The returned
449 * user should be released with ACLFreeUser() as usually. */
450user *ACLCreateUnlinkedUser(void) {
451 char username[64];
452 for (int j = 0; ; j++) {
453 snprintf(username,sizeof(username),"__fakeuser:%d__",j);
454 user *fakeuser = ACLCreateUser(username,strlen(username));
455 if (fakeuser == NULL) continue;
456 int retval = raxRemove(Users,(unsigned char*) username,
457 strlen(username),NULL);
458 serverAssert(retval != 0);
459 return fakeuser;
460 }
461}
462
463/* Release the memory used by the user structure. Note that this function
464 * will not remove the user from the Users global radix tree. */
465void ACLFreeUser(user *u) {
466 sdsfree(u->name);
467 if (u->acl_string) {
468 decrRefCount(u->acl_string);
469 u->acl_string = NULL;
470 }
471 listRelease(u->passwords);
472 listRelease(u->selectors);
473 zfree(u);
474}
475
476/* Generic version of ACLFreeUser. */
477void ACLFreeUserGeneric(void *u) {
478 ACLFreeUser((user *)u);
479}
480
481/* When a user is deleted we need to cycle the active
482 * connections in order to kill all the pending ones that
483 * are authenticated with such user. */
484void ACLFreeUserAndKillClients(user *u) {
485 listIter li;
486 listNode *ln;
487 listRewind(server.clients,&li);
488 while ((ln = listNext(&li)) != NULL) {
489 client *c = listNodeValue(ln);
490 if (c->user == u) {
491 /* We'll free the connection asynchronously, so
492 * in theory to set a different user is not needed.
493 * However if there are bugs in Redis, soon or later
494 * this may result in some security hole: it's much
495 * more defensive to set the default user and put
496 * it in non authenticated mode. */
497 deauthenticateAndCloseClient(c);
498 }
499 }
500 ACLFreeUser(u);
501}
502
503/* Copy the user ACL rules from the source user 'src' to the destination
504 * user 'dst' so that at the end of the process they'll have exactly the
505 * same rules (but the names will continue to be the original ones). */
506void ACLCopyUser(user *dst, user *src) {
507 listRelease(dst->passwords);
508 listRelease(dst->selectors);
509 dst->passwords = listDup(src->passwords);
510 dst->selectors = listDup(src->selectors);
511 dst->flags = src->flags;
512 if (dst->acl_string) {
513 decrRefCount(dst->acl_string);
514 }
515 dst->acl_string = src->acl_string;
516 if (dst->acl_string) {
517 /* if src is NULL, we set it to NULL, if not, need to increment reference count */
518 incrRefCount(dst->acl_string);
519 }
520}
521
522/* Given a command ID, this function set by reference 'word' and 'bit'
523 * so that user->allowed_commands[word] will address the right word
524 * where the corresponding bit for the provided ID is stored, and
525 * so that user->allowed_commands[word]&bit will identify that specific
526 * bit. The function returns C_ERR in case the specified ID overflows
527 * the bitmap in the user representation. */
528int ACLGetCommandBitCoordinates(uint64_t id, uint64_t *word, uint64_t *bit) {
529 if (id >= USER_COMMAND_BITS_COUNT) return C_ERR;
530 *word = id / sizeof(uint64_t) / 8;
531 *bit = 1ULL << (id % (sizeof(uint64_t) * 8));
532 return C_OK;
533}
534
535/* Check if the specified command bit is set for the specified user.
536 * The function returns 1 is the bit is set or 0 if it is not.
537 * Note that this function does not check the ALLCOMMANDS flag of the user
538 * but just the lowlevel bitmask.
539 *
540 * If the bit overflows the user internal representation, zero is returned
541 * in order to disallow the execution of the command in such edge case. */
542int ACLGetSelectorCommandBit(const aclSelector *selector, unsigned long id) {
543 uint64_t word, bit;
544 if (ACLGetCommandBitCoordinates(id,&word,&bit) == C_ERR) return 0;
545 return (selector->allowed_commands[word] & bit) != 0;
546}
547
548/* When +@all or allcommands is given, we set a reserved bit as well that we
549 * can later test, to see if the user has the right to execute "future commands",
550 * that is, commands loaded later via modules. */
551int ACLSelectorCanExecuteFutureCommands(aclSelector *selector) {
552 return ACLGetSelectorCommandBit(selector,USER_COMMAND_BITS_COUNT-1);
553}
554
555/* Set the specified command bit for the specified user to 'value' (0 or 1).
556 * If the bit overflows the user internal representation, no operation
557 * is performed. As a side effect of calling this function with a value of
558 * zero, the user flag ALLCOMMANDS is cleared since it is no longer possible
559 * to skip the command bit explicit test. */
560void ACLSetSelectorCommandBit(aclSelector *selector, unsigned long id, int value) {
561 uint64_t word, bit;
562 if (ACLGetCommandBitCoordinates(id,&word,&bit) == C_ERR) return;
563 if (value) {
564 selector->allowed_commands[word] |= bit;
565 } else {
566 selector->allowed_commands[word] &= ~bit;
567 selector->flags &= ~SELECTOR_FLAG_ALLCOMMANDS;
568 }
569}
570
571/* Remove a rule from the retained command rules. Always match rules
572 * verbatim, but also remove subcommand rules if we are adding or removing the
573 * entire command. */
574void ACLSelectorRemoveCommandRule(aclSelector *selector, sds new_rule) {
575 size_t new_len = sdslen(new_rule);
576 char *existing_rule = selector->command_rules;
577
578 /* Loop over the existing rules, trying to find a rule that "matches"
579 * the new rule. If we find a match, then remove the command from the string by
580 * copying the later rules over it. */
581 while(existing_rule[0]) {
582 /* The first character of the rule is +/-, which we don't need to compare. */
583 char *copy_position = existing_rule;
584 existing_rule += 1;
585
586 /* Assume a trailing space after a command is part of the command, like '+get ', so trim it
587 * as well if the command is removed. */
588 char *rule_end = strchr(existing_rule, ' ');
589 if (!rule_end) {
590 /* This is the last rule, so move it to the end of the string. */
591 rule_end = existing_rule + strlen(existing_rule);
592
593 /* This approach can leave a trailing space if the last rule is removed,
594 * but only if it's not the first rule, so handle that case. */
595 if (copy_position != selector->command_rules) copy_position -= 1;
596 }
597 char *copy_end = rule_end;
598 if (*copy_end == ' ') copy_end++;
599
600 /* Exact match or the rule we are comparing is a subcommand denoted by '|' */
601 size_t existing_len = rule_end - existing_rule;
602 if (!memcmp(existing_rule, new_rule, min(existing_len, new_len))) {
603 if ((existing_len == new_len) || (existing_len > new_len && (existing_rule[new_len]) == '|')) {
604 /* Copy the remaining rules starting at the next rule to replace the rule to be
605 * deleted, including the terminating NULL character. */
606 memmove(copy_position, copy_end, strlen(copy_end) + 1);
607 existing_rule = copy_position;
608 continue;
609 }
610 }
611 existing_rule = copy_end;
612 }
613
614 /* There is now extra padding at the end of the rules, so clean that up. */
615 sdsupdatelen(selector->command_rules);
616}
617
618/* This function is resopnsible for updating the command_rules struct so that relative ordering of
619 * commands and categories is maintained and can be reproduced without loss. */
620void ACLUpdateCommandRules(aclSelector *selector, const char *rule, int allow) {
621 sds new_rule = sdsnew(rule);
622 sdstolower(new_rule);
623
624 ACLSelectorRemoveCommandRule(selector, new_rule);
625 if (sdslen(selector->command_rules)) selector->command_rules = sdscat(selector->command_rules, " ");
626 selector->command_rules = sdscatfmt(selector->command_rules, allow ? "+%S" : "-%S", new_rule);
627 sdsfree(new_rule);
628}
629
630/* This function is used to allow/block a specific command.
631 * Allowing/blocking a container command also applies for its subcommands */
632void ACLChangeSelectorPerm(aclSelector *selector, struct redisCommand *cmd, int allow) {
633 unsigned long id = cmd->id;
634 ACLSetSelectorCommandBit(selector,id,allow);
635 ACLResetFirstArgsForCommand(selector,id);
636 if (cmd->subcommands_dict) {
637 dictEntry *de;
638 dictIterator di;
639 dictInitSafeIterator(&di, cmd->subcommands_dict);
640 while((de = dictNext(&di)) != NULL) {
641 struct redisCommand *sub = (struct redisCommand *)dictGetVal(de);
642 ACLSetSelectorCommandBit(selector,sub->id,allow);
643 }
644 dictResetIterator(&di);
645 }
646}
647
648/* This is like ACLSetSelectorCommandBit(), but instead of setting the specified
649 * ID, it will check all the commands in the category specified as argument,
650 * and will set all the bits corresponding to such commands to the specified
651 * value. Since the category passed by the user may be non existing, the
652 * function returns C_ERR if the category was not found, or C_OK if it was
653 * found and the operation was performed. */
654void ACLSetSelectorCommandBitsForCategory(dict *commands, aclSelector *selector, uint64_t cflag, int value) {
655 dictIterator di;
656 dictEntry *de;
657 dictInitIterator(&di, commands);
658 while ((de = dictNext(&di)) != NULL) {
659 struct redisCommand *cmd = dictGetVal(de);
660 if (cmd->acl_categories & cflag) {
661 ACLChangeSelectorPerm(selector,cmd,value);
662 }
663 if (cmd->subcommands_dict) {
664 ACLSetSelectorCommandBitsForCategory(cmd->subcommands_dict, selector, cflag, value);
665 }
666 }
667 dictResetIterator(&di);
668}
669
670/* This function is responsible for recomputing the command bits for all selectors of the existing users.
671 * It uses the 'command_rules', a string representation of the ordered categories and commands,
672 * to recompute the command bits. */
673void ACLRecomputeCommandBitsFromCommandRulesAllUsers(void) {
674 raxIterator ri;
675 raxStart(&ri,Users);
676 raxSeek(&ri,"^",NULL,0);
677 while(raxNext(&ri)) {
678 user *u = ri.data;
679 listIter li;
680 listNode *ln;
681 listRewind(u->selectors,&li);
682 while((ln = listNext(&li))) {
683 aclSelector *selector = (aclSelector *) listNodeValue(ln);
684 int argc = 0;
685 sds *argv = sdssplitargs(selector->command_rules, &argc);
686 serverAssert(argv != NULL);
687 /* Checking selector's permissions for all commands to start with a clean state. */
688 if (ACLSelectorCanExecuteFutureCommands(selector)) {
689 int res = ACLSetSelector(selector,"+@all",-1);
690 serverAssert(res == C_OK);
691 } else {
692 int res = ACLSetSelector(selector,"-@all",-1);
693 serverAssert(res == C_OK);
694 }
695
696 /* Apply all of the commands and categories to this selector. */
697 for(int i = 0; i < argc; i++) {
698 int res = ACLSetSelector(selector, argv[i], sdslen(argv[i]));
699 serverAssert(res == C_OK);
700 }
701 sdsfreesplitres(argv, argc);
702 }
703 }
704 raxStop(&ri);
705
706}
707
708int ACLSetSelectorCategory(aclSelector *selector, const char *category, int allow) {
709 uint64_t cflag = ACLGetCommandCategoryFlagByName(category + 1);
710 if (!cflag) return C_ERR;
711
712 ACLUpdateCommandRules(selector, category, allow);
713
714 /* Set the actual command bits on the selector. */
715 ACLSetSelectorCommandBitsForCategory(server.orig_commands, selector, cflag, allow);
716 return C_OK;
717}
718
719void ACLCountCategoryBitsForCommands(dict *commands, aclSelector *selector, unsigned long *on, unsigned long *off, uint64_t cflag) {
720 dictIterator di;
721 dictEntry *de;
722 dictInitIterator(&di, commands);
723 while ((de = dictNext(&di)) != NULL) {
724 struct redisCommand *cmd = dictGetVal(de);
725 if (cmd->acl_categories & cflag) {
726 if (ACLGetSelectorCommandBit(selector,cmd->id))
727 (*on)++;
728 else
729 (*off)++;
730 }
731 if (cmd->subcommands_dict) {
732 ACLCountCategoryBitsForCommands(cmd->subcommands_dict, selector, on, off, cflag);
733 }
734 }
735 dictResetIterator(&di);
736}
737
738/* Return the number of commands allowed (on) and denied (off) for the user 'u'
739 * in the subset of commands flagged with the specified category name.
740 * If the category name is not valid, C_ERR is returned, otherwise C_OK is
741 * returned and on and off are populated by reference. */
742int ACLCountCategoryBitsForSelector(aclSelector *selector, unsigned long *on, unsigned long *off,
743 const char *category)
744{
745 uint64_t cflag = ACLGetCommandCategoryFlagByName(category);
746 if (!cflag) return C_ERR;
747
748 *on = *off = 0;
749 ACLCountCategoryBitsForCommands(server.orig_commands, selector, on, off, cflag);
750 return C_OK;
751}
752
753/* This function returns an SDS string representing the specified selector ACL
754 * rules related to command execution, in the same format you could set them
755 * back using ACL SETUSER. The function will return just the set of rules needed
756 * to recreate the user commands bitmap, without including other user flags such
757 * as on/off, passwords and so forth. The returned string always starts with
758 * the +@all or -@all rule, depending on the user bitmap, and is followed, if
759 * needed, by the other rules needed to narrow or extend what the user can do. */
760sds ACLDescribeSelectorCommandRules(aclSelector *selector) {
761 sds rules = sdsempty();
762
763 /* We use this fake selector as a "sanity" check to make sure the rules
764 * we generate have the same bitmap as those on the current selector. */
765 aclSelector *fake_selector = ACLCreateSelector(0);
766
767 /* Here we want to understand if we should start with +@all or -@all.
768 * Note that when starting with +@all and subtracting, the user
769 * will be able to execute future commands, while -@all and adding will just
770 * allow the user the run the selected commands and/or categories.
771 * How do we test for that? We use the trick of a reserved command ID bit
772 * that is set only by +@all (and its alias "allcommands"). */
773 if (ACLSelectorCanExecuteFutureCommands(selector)) {
774 rules = sdscat(rules,"+@all ");
775 ACLSetSelector(fake_selector,"+@all",-1);
776 } else {
777 rules = sdscat(rules,"-@all ");
778 ACLSetSelector(fake_selector,"-@all",-1);
779 }
780
781 /* Apply all of the commands and categories to the fake selector. */
782 int argc = 0;
783 sds *argv = sdssplitargs(selector->command_rules, &argc);
784 serverAssert(argv != NULL);
785
786 for(int i = 0; i < argc; i++) {
787 int res = ACLSetSelector(fake_selector, argv[i], -1);
788 serverAssert(res == C_OK);
789 }
790 if (sdslen(selector->command_rules)) {
791 rules = sdscatfmt(rules, "%S ", selector->command_rules);
792 }
793 sdsfreesplitres(argv, argc);
794
795 /* Trim the final useless space. */
796 sdsrange(rules,0,-2);
797
798 /* This is technically not needed, but we want to verify that now the
799 * predicted bitmap is exactly the same as the user bitmap, and abort
800 * otherwise, because aborting is better than a security risk in this
801 * code path. */
802 if (memcmp(fake_selector->allowed_commands,
803 selector->allowed_commands,
804 sizeof(selector->allowed_commands)) != 0)
805 {
806 serverLog(LL_WARNING,
807 "CRITICAL ERROR: User ACLs don't match final bitmap: '%s'",
808 redactLogCstr(rules));
809 serverPanic("No bitmap match in ACLDescribeSelectorCommandRules()");
810 }
811 ACLFreeSelector(fake_selector);
812 return rules;
813}
814
815sds ACLDescribeSelector(aclSelector *selector) {
816 listIter li;
817 listNode *ln;
818 sds res = sdsempty();
819 /* Key patterns. */
820 if (selector->flags & SELECTOR_FLAG_ALLKEYS) {
821 res = sdscatlen(res,"~* ",3);
822 } else {
823 listRewind(selector->patterns,&li);
824 while((ln = listNext(&li))) {
825 keyPattern *thispat = (keyPattern *)listNodeValue(ln);
826 res = sdsCatPatternString(res, thispat);
827 res = sdscatlen(res," ",1);
828 }
829 }
830
831 /* Pub/sub channel patterns. */
832 if (selector->flags & SELECTOR_FLAG_ALLCHANNELS) {
833 res = sdscatlen(res,"&* ",3);
834 } else {
835 res = sdscatlen(res,"resetchannels ",14);
836 listRewind(selector->channels,&li);
837 while((ln = listNext(&li))) {
838 sds thispat = listNodeValue(ln);
839 res = sdscatlen(res,"&",1);
840 res = sdscatsds(res,thispat);
841 res = sdscatlen(res," ",1);
842 }
843 }
844
845 /* Command rules. */
846 sds rules = ACLDescribeSelectorCommandRules(selector);
847 res = sdscatsds(res,rules);
848 sdsfree(rules);
849 return res;
850}
851
852/* This is similar to ACLDescribeSelectorCommandRules(), however instead of
853 * describing just the user command rules, everything is described: user
854 * flags, keys, passwords and finally the command rules obtained via
855 * the ACLDescribeSelectorCommandRules() function. This is the function we call
856 * when we want to rewrite the configuration files describing ACLs and
857 * in order to show users with ACL LIST. */
858robj *ACLDescribeUser(user *u) {
859 if (u->acl_string) {
860 incrRefCount(u->acl_string);
861 return u->acl_string;
862 }
863
864 sds res = sdsempty();
865
866 /* Flags. */
867 for (int j = 0; ACLUserFlags[j].flag; j++) {
868 if (u->flags & ACLUserFlags[j].flag) {
869 res = sdscat(res,ACLUserFlags[j].name);
870 res = sdscatlen(res," ",1);
871 }
872 }
873
874 /* Passwords. */
875 listIter li;
876 listNode *ln;
877 listRewind(u->passwords,&li);
878 while((ln = listNext(&li))) {
879 sds thispass = listNodeValue(ln);
880 res = sdscatlen(res,"#",1);
881 res = sdscatsds(res,thispass);
882 res = sdscatlen(res," ",1);
883 }
884
885 /* Selectors (Commands and keys) */
886 listRewind(u->selectors,&li);
887 while((ln = listNext(&li))) {
888 aclSelector *selector = (aclSelector *) listNodeValue(ln);
889 sds default_perm = ACLDescribeSelector(selector);
890 if (selector->flags & SELECTOR_FLAG_ROOT) {
891 res = sdscatfmt(res, "%s", default_perm);
892 } else {
893 res = sdscatfmt(res, " (%s)", default_perm);
894 }
895 sdsfree(default_perm);
896 }
897
898 u->acl_string = createObject(OBJ_STRING, res);
899 /* because we are returning it, have to increase count */
900 incrRefCount(u->acl_string);
901
902 return u->acl_string;
903}
904
905/* Get a command from the original command table, that is not affected
906 * by the command renaming operations: we base all the ACL work from that
907 * table, so that ACLs are valid regardless of command renaming. */
908struct redisCommand *ACLLookupCommand(const char *name) {
909 struct redisCommand *cmd;
910 sds sdsname = sdsnew(name);
911 cmd = lookupCommandBySdsLogic(server.orig_commands,sdsname);
912 sdsfree(sdsname);
913 return cmd;
914}
915
916/* Flush the array of allowed first-args for the specified user
917 * and command ID. */
918void ACLResetFirstArgsForCommand(aclSelector *selector, unsigned long id) {
919 if (selector->allowed_firstargs && selector->allowed_firstargs[id]) {
920 for (int i = 0; selector->allowed_firstargs[id][i]; i++)
921 sdsfree(selector->allowed_firstargs[id][i]);
922 zfree(selector->allowed_firstargs[id]);
923 selector->allowed_firstargs[id] = NULL;
924 }
925}
926
927/* Flush the entire table of first-args. This is useful on +@all, -@all
928 * or similar to return back to the minimal memory usage (and checks to do)
929 * for the user. */
930void ACLResetFirstArgs(aclSelector *selector) {
931 if (selector->allowed_firstargs == NULL) return;
932 for (int j = 0; j < USER_COMMAND_BITS_COUNT; j++) {
933 if (selector->allowed_firstargs[j]) {
934 for (int i = 0; selector->allowed_firstargs[j][i]; i++)
935 sdsfree(selector->allowed_firstargs[j][i]);
936 zfree(selector->allowed_firstargs[j]);
937 }
938 }
939 zfree(selector->allowed_firstargs);
940 selector->allowed_firstargs = NULL;
941}
942
943/* Add a first-arg to the list of subcommands for the user 'u' and
944 * the command id specified. */
945void ACLAddAllowedFirstArg(aclSelector *selector, unsigned long id, const char *sub) {
946 /* If this is the first first-arg to be configured for
947 * this user, we have to allocate the first-args array. */
948 if (selector->allowed_firstargs == NULL) {
949 selector->allowed_firstargs = zcalloc(USER_COMMAND_BITS_COUNT * sizeof(sds*));
950 }
951
952 /* We also need to enlarge the allocation pointing to the
953 * null terminated SDS array, to make space for this one.
954 * To start check the current size, and while we are here
955 * make sure the first-arg is not already specified inside. */
956 long items = 0;
957 if (selector->allowed_firstargs[id]) {
958 while(selector->allowed_firstargs[id][items]) {
959 /* If it's already here do not add it again. */
960 if (!strcasecmp(selector->allowed_firstargs[id][items],sub))
961 return;
962 items++;
963 }
964 }
965
966 /* Now we can make space for the new item (and the null term). */
967 items += 2;
968 selector->allowed_firstargs[id] = zrealloc(selector->allowed_firstargs[id], sizeof(sds)*items);
969 selector->allowed_firstargs[id][items-2] = sdsnew(sub);
970 selector->allowed_firstargs[id][items-1] = NULL;
971}
972
973/* Create an ACL selector from the given ACL operations, which should be
974 * a list of space separate ACL operations that starts and ends
975 * with parentheses.
976 *
977 * If any of the operations are invalid, NULL will be returned instead
978 * and errno will be set corresponding to the interior error. */
979aclSelector *aclCreateSelectorFromOpSet(const char *opset, size_t opsetlen) {
980 serverAssert(opset[0] == '(' && opset[opsetlen - 1] == ')');
981 aclSelector *s = ACLCreateSelector(0);
982
983 int argc = 0;
984 sds trimmed = sdsnewlen(opset + 1, opsetlen - 2);
985 sds *argv = sdssplitargs(trimmed, &argc);
986 for (int i = 0; i < argc; i++) {
987 if (ACLSetSelector(s, argv[i], sdslen(argv[i])) == C_ERR) {
988 ACLFreeSelector(s);
989 s = NULL;
990 goto cleanup;
991 }
992 }
993
994cleanup:
995 sdsfreesplitres(argv, argc);
996 sdsfree(trimmed);
997 return s;
998}
999
1000/* Set a selector's properties with the provided 'op'.
1001 *
1002 * +<command> Allow the execution of that command.
1003 * May be used with `|` for allowing subcommands (e.g "+config|get")
1004 * -<command> Disallow the execution of that command.
1005 * May be used with `|` for blocking subcommands (e.g "-config|set")
1006 * +@<category> Allow the execution of all the commands in such category
1007 * with valid categories are like @admin, @set, @sortedset, ...
1008 * and so forth, see the full list in the server.c file where
1009 * the Redis command table is described and defined.
1010 * The special category @all means all the commands, but currently
1011 * present in the server, and that will be loaded in the future
1012 * via modules.
1013 * +<command>|first-arg Allow a specific first argument of an otherwise
1014 * disabled command. Note that this form is not
1015 * allowed as negative like -SELECT|1, but
1016 * only additive starting with "+".
1017 * allcommands Alias for +@all. Note that it implies the ability to execute
1018 * all the future commands loaded via the modules system.
1019 * nocommands Alias for -@all.
1020 * ~<pattern> Add a pattern of keys that can be mentioned as part of
1021 * commands. For instance ~* allows all the keys. The pattern
1022 * is a glob-style pattern like the one of KEYS.
1023 * It is possible to specify multiple patterns.
1024 * %R~<pattern> Add key read pattern that specifies which keys can be read
1025 * from.
1026 * %W~<pattern> Add key write pattern that specifies which keys can be
1027 * written to.
1028 * allkeys Alias for ~*
1029 * resetkeys Flush the list of allowed keys patterns.
1030 * &<pattern> Add a pattern of channels that can be mentioned as part of
1031 * Pub/Sub commands. For instance &* allows all the channels. The
1032 * pattern is a glob-style pattern like the one of PSUBSCRIBE.
1033 * It is possible to specify multiple patterns.
1034 * allchannels Alias for &*
1035 * resetchannels Flush the list of allowed channel patterns.
1036 */
1037int ACLSetSelector(aclSelector *selector, const char* op, size_t oplen) {
1038 if (!strcasecmp(op,"allkeys") ||
1039 !strcasecmp(op,"~*"))
1040 {
1041 selector->flags |= SELECTOR_FLAG_ALLKEYS;
1042 listEmpty(selector->patterns);
1043 } else if (!strcasecmp(op,"resetkeys")) {
1044 selector->flags &= ~SELECTOR_FLAG_ALLKEYS;
1045 listEmpty(selector->patterns);
1046 } else if (!strcasecmp(op,"allchannels") ||
1047 !strcasecmp(op,"&*"))
1048 {
1049 selector->flags |= SELECTOR_FLAG_ALLCHANNELS;
1050 listEmpty(selector->channels);
1051 } else if (!strcasecmp(op,"resetchannels")) {
1052 selector->flags &= ~SELECTOR_FLAG_ALLCHANNELS;
1053 listEmpty(selector->channels);
1054 } else if (!strcasecmp(op,"allcommands") ||
1055 !strcasecmp(op,"+@all"))
1056 {
1057 memset(selector->allowed_commands,255,sizeof(selector->allowed_commands));
1058 selector->flags |= SELECTOR_FLAG_ALLCOMMANDS;
1059 sdsclear(selector->command_rules);
1060 ACLResetFirstArgs(selector);
1061 } else if (!strcasecmp(op,"nocommands") ||
1062 !strcasecmp(op,"-@all"))
1063 {
1064 memset(selector->allowed_commands,0,sizeof(selector->allowed_commands));
1065 selector->flags &= ~SELECTOR_FLAG_ALLCOMMANDS;
1066 sdsclear(selector->command_rules);
1067 ACLResetFirstArgs(selector);
1068 } else if (op[0] == '~' || op[0] == '%') {
1069 if (selector->flags & SELECTOR_FLAG_ALLKEYS) {
1070 errno = EEXIST;
1071 return C_ERR;
1072 }
1073 int flags = 0;
1074 size_t offset = 1;
1075 if (op[0] == '%') {
1076 int perm_ok = 1;
1077 for (; offset < oplen; offset++) {
1078 if (toupper(op[offset]) == 'R' && !(flags & ACL_READ_PERMISSION)) {
1079 flags |= ACL_READ_PERMISSION;
1080 } else if (toupper(op[offset]) == 'W' && !(flags & ACL_WRITE_PERMISSION)) {
1081 flags |= ACL_WRITE_PERMISSION;
1082 } else if (op[offset] == '~') {
1083 offset++;
1084 break;
1085 } else {
1086 perm_ok = 0;
1087 break;
1088 }
1089 }
1090 if (!flags || !perm_ok) {
1091 errno = EINVAL;
1092 return C_ERR;
1093 }
1094 } else {
1095 flags = ACL_ALL_PERMISSION;
1096 }
1097
1098 if (ACLStringHasSpaces(op+offset,oplen-offset)) {
1099 errno = EINVAL;
1100 return C_ERR;
1101 }
1102 keyPattern *newpat = ACLKeyPatternCreate(sdsnewlen(op+offset,oplen-offset), flags);
1103 listNode *ln = listSearchKey(selector->patterns,newpat);
1104 /* Avoid re-adding the same key pattern multiple times. */
1105 if (ln == NULL) {
1106 listAddNodeTail(selector->patterns,newpat);
1107 } else {
1108 ((keyPattern *)listNodeValue(ln))->flags |= flags;
1109 ACLKeyPatternFree(newpat);
1110 }
1111 selector->flags &= ~SELECTOR_FLAG_ALLKEYS;
1112 } else if (op[0] == '&') {
1113 if (selector->flags & SELECTOR_FLAG_ALLCHANNELS) {
1114 errno = EISDIR;
1115 return C_ERR;
1116 }
1117 if (ACLStringHasSpaces(op+1,oplen-1)) {
1118 errno = EINVAL;
1119 return C_ERR;
1120 }
1121 sds newpat = sdsnewlen(op+1,oplen-1);
1122 listNode *ln = listSearchKey(selector->channels,newpat);
1123 /* Avoid re-adding the same channel pattern multiple times. */
1124 if (ln == NULL)
1125 listAddNodeTail(selector->channels,newpat);
1126 else
1127 sdsfree(newpat);
1128 selector->flags &= ~SELECTOR_FLAG_ALLCHANNELS;
1129 } else if (op[0] == '+' && op[1] != '@') {
1130 if (strrchr(op,'|') == NULL) {
1131 struct redisCommand *cmd = ACLLookupCommand(op+1);
1132 if (cmd == NULL) {
1133 errno = ENOENT;
1134 return C_ERR;
1135 }
1136 ACLChangeSelectorPerm(selector,cmd,1);
1137 ACLUpdateCommandRules(selector,cmd->fullname,1);
1138 } else {
1139 /* Split the command and subcommand parts. */
1140 char *copy = zstrdup(op+1);
1141 char *sub = strrchr(copy,'|');
1142 sub[0] = '\0';
1143 sub++;
1144
1145 struct redisCommand *cmd = ACLLookupCommand(copy);
1146
1147 /* Check if the command exists. We can't check the
1148 * first-arg to see if it is valid. */
1149 if (cmd == NULL) {
1150 zfree(copy);
1151 errno = ENOENT;
1152 return C_ERR;
1153 }
1154
1155 /* We do not support allowing first-arg of a subcommand */
1156 if (cmd->parent) {
1157 zfree(copy);
1158 errno = ECHILD;
1159 return C_ERR;
1160 }
1161
1162 /* The subcommand cannot be empty, so things like DEBUG|
1163 * are syntax errors of course. */
1164 if (strlen(sub) == 0) {
1165 zfree(copy);
1166 errno = EINVAL;
1167 return C_ERR;
1168 }
1169
1170 if (cmd->subcommands_dict) {
1171 /* If user is trying to allow a valid subcommand we can just add its unique ID */
1172 cmd = ACLLookupCommand(op+1);
1173 if (cmd == NULL) {
1174 zfree(copy);
1175 errno = ENOENT;
1176 return C_ERR;
1177 }
1178 ACLChangeSelectorPerm(selector,cmd,1);
1179 } else {
1180 /* If user is trying to use the ACL mech to block SELECT except SELECT 0 or
1181 * block DEBUG except DEBUG OBJECT (DEBUG subcommands are not considered
1182 * subcommands for now) we use the allowed_firstargs mechanism. */
1183
1184 /* Add the first-arg to the list of valid ones. */
1185 serverLog(LL_WARNING, "Deprecation warning: Allowing a first arg of an otherwise "
1186 "blocked command is a misuse of ACL and may get disabled "
1187 "in the future (offender: +%s)", redactLogCstr(op+1));
1188 ACLAddAllowedFirstArg(selector,cmd->id,sub);
1189 }
1190 ACLUpdateCommandRules(selector,op+1,1);
1191 zfree(copy);
1192 }
1193 } else if (op[0] == '-' && op[1] != '@') {
1194 struct redisCommand *cmd = ACLLookupCommand(op+1);
1195 if (cmd == NULL) {
1196 errno = ENOENT;
1197 return C_ERR;
1198 }
1199 ACLChangeSelectorPerm(selector,cmd,0);
1200 ACLUpdateCommandRules(selector,cmd->fullname,0);
1201 } else if ((op[0] == '+' || op[0] == '-') && op[1] == '@') {
1202 int bitval = op[0] == '+' ? 1 : 0;
1203 if (ACLSetSelectorCategory(selector,op+1,bitval) == C_ERR) {
1204 errno = ENOENT;
1205 return C_ERR;
1206 }
1207 } else {
1208 errno = EINVAL;
1209 return C_ERR;
1210 }
1211 return C_OK;
1212}
1213
1214/* Set user properties according to the string "op". The following
1215 * is a description of what different strings will do:
1216 *
1217 * on Enable the user: it is possible to authenticate as this user.
1218 * off Disable the user: it's no longer possible to authenticate
1219 * with this user, however the already authenticated connections
1220 * will still work.
1221 * skip-sanitize-payload RESTORE dump-payload sanitization is skipped.
1222 * sanitize-payload RESTORE dump-payload is sanitized (default).
1223 * ><password> Add this password to the list of valid password for the user.
1224 * For example >mypass will add "mypass" to the list.
1225 * This directive clears the "nopass" flag (see later).
1226 * #<hash> Add this password hash to the list of valid hashes for
1227 * the user. This is useful if you have previously computed
1228 * the hash, and don't want to store it in plaintext.
1229 * This directive clears the "nopass" flag (see later).
1230 * <<password> Remove this password from the list of valid passwords.
1231 * !<hash> Remove this hashed password from the list of valid passwords.
1232 * This is useful when you want to remove a password just by
1233 * hash without knowing its plaintext version at all.
1234 * nopass All the set passwords of the user are removed, and the user
1235 * is flagged as requiring no password: it means that every
1236 * password will work against this user. If this directive is
1237 * used for the default user, every new connection will be
1238 * immediately authenticated with the default user without
1239 * any explicit AUTH command required. Note that the "resetpass"
1240 * directive will clear this condition.
1241 * resetpass Flush the list of allowed passwords. Moreover removes the
1242 * "nopass" status. After "resetpass" the user has no associated
1243 * passwords and there is no way to authenticate without adding
1244 * some password (or setting it as "nopass" later).
1245 * reset Performs the following actions: resetpass, resetkeys, resetchannels,
1246 * allchannels (if acl-pubsub-default is set), off, clearselectors, -@all.
1247 * The user returns to the same state it has immediately after its creation.
1248 * (<options>) Create a new selector with the options specified within the
1249 * parentheses and attach it to the user. Each option should be
1250 * space separated. The first character must be ( and the last
1251 * character must be ).
1252 * clearselectors Remove all of the currently attached selectors.
1253 * Note this does not change the "root" user permissions,
1254 * which are the permissions directly applied onto the
1255 * user (outside the parentheses).
1256 *
1257 * Selector options can also be specified by this function, in which case
1258 * they update the root selector for the user.
1259 *
1260 * The 'op' string must be null terminated. The 'oplen' argument should
1261 * specify the length of the 'op' string in case the caller requires to pass
1262 * binary data (for instance the >password form may use a binary password).
1263 * Otherwise the field can be set to -1 and the function will use strlen()
1264 * to determine the length.
1265 *
1266 * The function returns C_OK if the action to perform was understood because
1267 * the 'op' string made sense. Otherwise C_ERR is returned if the operation
1268 * is unknown or has some syntax error.
1269 *
1270 * When an error is returned, errno is set to the following values:
1271 *
1272 * EINVAL: The specified opcode is not understood or the key/channel pattern is
1273 * invalid (contains non allowed characters).
1274 * ENOENT: The command name or command category provided with + or - is not
1275 * known.
1276 * EEXIST: You are adding a key pattern after "*" was already added. This is
1277 * almost surely an error on the user side.
1278 * EISDIR: You are adding a channel pattern after "*" was already added. This is
1279 * almost surely an error on the user side.
1280 * ENODEV: The password you are trying to remove from the user does not exist.
1281 * EBADMSG: The hash you are trying to add is not a valid hash.
1282 * ECHILD: Attempt to allow a specific first argument of a subcommand
1283 */
1284int ACLSetUser(user *u, const char *op, ssize_t oplen) {
1285 /* as we are changing the ACL, the old generated string is now invalid */
1286 if (u->acl_string) {
1287 decrRefCount(u->acl_string);
1288 u->acl_string = NULL;
1289 }
1290
1291 if (oplen == -1) oplen = strlen(op);
1292 if (oplen == 0) return C_OK; /* Empty string is a no-operation. */
1293 if (!strcasecmp(op,"on")) {
1294 atomicSet(u->flags, (u->flags | USER_FLAG_ENABLED) & ~USER_FLAG_DISABLED);
1295 } else if (!strcasecmp(op,"off")) {
1296 atomicSet(u->flags, (u->flags | USER_FLAG_DISABLED) & ~USER_FLAG_ENABLED);
1297 } else if (!strcasecmp(op,"skip-sanitize-payload")) {
1298 atomicSet(u->flags, (u->flags | USER_FLAG_SANITIZE_PAYLOAD_SKIP) & ~USER_FLAG_SANITIZE_PAYLOAD);
1299 } else if (!strcasecmp(op,"sanitize-payload")) {
1300 atomicSet(u->flags, (u->flags | USER_FLAG_SANITIZE_PAYLOAD) & ~USER_FLAG_SANITIZE_PAYLOAD_SKIP);
1301 } else if (!strcasecmp(op,"nopass")) {
1302 atomicSet(u->flags, u->flags | USER_FLAG_NOPASS);
1303 listEmpty(u->passwords);
1304 } else if (!strcasecmp(op,"resetpass")) {
1305 atomicSet(u->flags, u->flags & ~USER_FLAG_NOPASS);
1306 listEmpty(u->passwords);
1307 } else if (op[0] == '>' || op[0] == '#') {
1308 sds newpass;
1309 if (op[0] == '>') {
1310 newpass = ACLHashPassword((unsigned char*)op+1,oplen-1);
1311 } else {
1312 if (ACLCheckPasswordHash((unsigned char*)op+1,oplen-1) == C_ERR) {
1313 errno = EBADMSG;
1314 return C_ERR;
1315 }
1316 newpass = sdsnewlen(op+1,oplen-1);
1317 }
1318
1319 listNode *ln = listSearchKey(u->passwords,newpass);
1320 /* Avoid re-adding the same password multiple times. */
1321 if (ln == NULL)
1322 listAddNodeTail(u->passwords,newpass);
1323 else
1324 sdsfree(newpass);
1325 atomicSet(u->flags, u->flags & ~USER_FLAG_NOPASS);
1326 } else if (op[0] == '<' || op[0] == '!') {
1327 sds delpass;
1328 if (op[0] == '<') {
1329 delpass = ACLHashPassword((unsigned char*)op+1,oplen-1);
1330 } else {
1331 if (ACLCheckPasswordHash((unsigned char*)op+1,oplen-1) == C_ERR) {
1332 errno = EBADMSG;
1333 return C_ERR;
1334 }
1335 delpass = sdsnewlen(op+1,oplen-1);
1336 }
1337 listNode *ln = listSearchKey(u->passwords,delpass);
1338 sdsfree(delpass);
1339 if (ln) {
1340 listDelNode(u->passwords,ln);
1341 } else {
1342 errno = ENODEV;
1343 return C_ERR;
1344 }
1345 } else if (op[0] == '(' && op[oplen - 1] == ')') {
1346 aclSelector *selector = aclCreateSelectorFromOpSet(op, oplen);
1347 if (!selector) {
1348 /* No errorno set, propagate it from interior error. */
1349 return C_ERR;
1350 }
1351 listAddNodeTail(u->selectors, selector);
1352 return C_OK;
1353 } else if (!strcasecmp(op,"clearselectors")) {
1354 listIter li;
1355 listNode *ln;
1356 listRewind(u->selectors,&li);
1357 /* There has to be a root selector */
1358 serverAssert(listNext(&li));
1359 while((ln = listNext(&li))) {
1360 listDelNode(u->selectors, ln);
1361 }
1362 return C_OK;
1363 } else if (!strcasecmp(op,"reset")) {
1364 serverAssert(ACLSetUser(u,"resetpass",-1) == C_OK);
1365 serverAssert(ACLSetUser(u,"resetkeys",-1) == C_OK);
1366 serverAssert(ACLSetUser(u,"resetchannels",-1) == C_OK);
1367 if (server.acl_pubsub_default & SELECTOR_FLAG_ALLCHANNELS)
1368 serverAssert(ACLSetUser(u,"allchannels",-1) == C_OK);
1369 serverAssert(ACLSetUser(u,"off",-1) == C_OK);
1370 serverAssert(ACLSetUser(u,"sanitize-payload",-1) == C_OK);
1371 serverAssert(ACLSetUser(u,"clearselectors",-1) == C_OK);
1372 serverAssert(ACLSetUser(u,"-@all",-1) == C_OK);
1373 } else {
1374 aclSelector *selector = ACLUserGetRootSelector(u);
1375 if (ACLSetSelector(selector, op, oplen) == C_ERR) {
1376 return C_ERR;
1377 }
1378 }
1379 return C_OK;
1380}
1381
1382/* Return a description of the error that occurred in ACLSetUser() according to
1383 * the errno value set by the function on error. */
1384const char *ACLSetUserStringError(void) {
1385 const char *errmsg = "Wrong format";
1386 if (errno == ENOENT)
1387 errmsg = "Unknown command or category name in ACL";
1388 else if (errno == EINVAL)
1389 errmsg = "Syntax error";
1390 else if (errno == EEXIST)
1391 errmsg = "Adding a pattern after the * pattern (or the "
1392 "'allkeys' flag) is not valid and does not have any "
1393 "effect. Try 'resetkeys' to start with an empty "
1394 "list of patterns";
1395 else if (errno == EISDIR)
1396 errmsg = "Adding a pattern after the * pattern (or the "
1397 "'allchannels' flag) is not valid and does not have any "
1398 "effect. Try 'resetchannels' to start with an empty "
1399 "list of channels";
1400 else if (errno == ENODEV)
1401 errmsg = "The password you are trying to remove from the user does "
1402 "not exist";
1403 else if (errno == EBADMSG)
1404 errmsg = "The password hash must be exactly 64 characters and contain "
1405 "only lowercase hexadecimal characters";
1406 else if (errno == EALREADY)
1407 errmsg = "Duplicate user found. A user can only be defined once in "
1408 "config files";
1409 else if (errno == ECHILD)
1410 errmsg = "Allowing first-arg of a subcommand is not supported";
1411 return errmsg;
1412}
1413
1414/* Create the default user, this has special permissions. */
1415user *ACLCreateDefaultUser(void) {
1416 user *new = ACLCreateUser("default",7);
1417 ACLSetUser(new,"+@all",-1);
1418 ACLSetUser(new,"~*",-1);
1419 ACLSetUser(new,"&*",-1);
1420 ACLSetUser(new,"on",-1);
1421 ACLSetUser(new,"nopass",-1);
1422 return new;
1423}
1424
1425/* Initialization of the ACL subsystem. */
1426void ACLInit(void) {
1427 Users = raxNew();
1428 UsersToLoad = listCreate();
1429 ACLInitCommandCategories();
1430 listSetMatchMethod(UsersToLoad, ACLListMatchLoadedUser);
1431 ACLLog = listCreate();
1432 DefaultUser = ACLCreateDefaultUser();
1433}
1434
1435/* Check the username and password pair and return C_OK if they are valid,
1436 * otherwise C_ERR is returned and errno is set to:
1437 *
1438 * EINVAL: if the username-password do not match.
1439 * ENOENT: if the specified user does not exist at all.
1440 */
1441int ACLCheckUserCredentials(robj *username, robj *password) {
1442 user *u = ACLGetUserByName(username->ptr,sdslen(username->ptr));
1443 if (u == NULL) {
1444 errno = ENOENT;
1445 return C_ERR;
1446 }
1447
1448 /* Disabled users can't login. */
1449 if (u->flags & USER_FLAG_DISABLED) {
1450 errno = EINVAL;
1451 return C_ERR;
1452 }
1453
1454 /* If the user is configured to don't require any password, we
1455 * are already fine here. */
1456 if (u->flags & USER_FLAG_NOPASS) return C_OK;
1457
1458 /* Check all the user passwords for at least one to match. */
1459 listIter li;
1460 listNode *ln;
1461 listRewind(u->passwords,&li);
1462 sds hashed = ACLHashPassword(password->ptr,sdslen(password->ptr));
1463 while((ln = listNext(&li))) {
1464 sds thispass = listNodeValue(ln);
1465 if (!time_independent_strcmp(hashed, thispass, HASH_PASSWORD_LEN)) {
1466 sdsfree(hashed);
1467 return C_OK;
1468 }
1469 }
1470 sdsfree(hashed);
1471
1472 /* If we reached this point, no password matched. */
1473 errno = EINVAL;
1474 return C_ERR;
1475}
1476
1477/* If `err` is provided, this is added as an error reply to the client.
1478 * Otherwise, the standard Auth error is added as a reply. */
1479void addAuthErrReply(client *c, robj *err) {
1480 if (clientHasPendingReplies(c)) return;
1481 if (!err) {
1482 addReplyError(c, "-WRONGPASS invalid username-password pair or user is disabled.");
1483 return;
1484 }
1485 addReplyError(c, err->ptr);
1486}
1487
1488/* This is like ACLCheckUserCredentials(), however if the user/pass
1489 * are correct, the connection is put in authenticated state and the
1490 * connection user reference is populated.
1491 *
1492 * The return value is AUTH_OK on success (valid username / password pair) & AUTH_ERR otherwise. */
1493int checkPasswordBasedAuth(client *c, robj *username, robj *password) {
1494 if (ACLCheckUserCredentials(username,password) == C_OK) {
1495 c->authenticated = 1;
1496 c->user = ACLGetUserByName(username->ptr,sdslen(username->ptr));
1497 moduleNotifyUserChanged(c);
1498 return AUTH_OK;
1499 } else {
1500 addACLLogEntry(c,ACL_DENIED_AUTH,(c->flags & CLIENT_MULTI) ? ACL_LOG_CTX_MULTI : ACL_LOG_CTX_TOPLEVEL,0,username->ptr,NULL);
1501 return AUTH_ERR;
1502 }
1503}
1504
1505/* Attempt authenticating the user - first through module based authentication,
1506 * and then, if needed, with normal password based authentication.
1507 * Returns one of the following codes:
1508 * AUTH_OK - Indicates that authentication succeeded.
1509 * AUTH_ERR - Indicates that authentication failed.
1510 * AUTH_BLOCKED - Indicates module authentication is in progress through a blocking implementation.
1511 */
1512int ACLAuthenticateUser(client *c, robj *username, robj *password, robj **err) {
1513 int result = checkModuleAuthentication(c, username, password, err);
1514 /* If authentication was not handled by any Module, attempt normal password based auth. */
1515 if (result == AUTH_NOT_HANDLED) {
1516 result = checkPasswordBasedAuth(c, username, password);
1517 }
1518 return result;
1519}
1520
1521/* For ACL purposes, every user has a bitmap with the commands that such
1522 * user is allowed to execute. In order to populate the bitmap, every command
1523 * should have an assigned ID (that is used to index the bitmap). This function
1524 * creates such an ID: it uses sequential IDs, reusing the same ID for the same
1525 * command name, so that a command retains the same ID in case of modules that
1526 * are unloaded and later reloaded.
1527 *
1528 * The function does not take ownership of the 'cmdname' SDS string.
1529 * */
1530unsigned long ACLGetCommandID(sds cmdname) {
1531 sds lowername = sdsdup(cmdname);
1532 sdstolower(lowername);
1533 if (commandId == NULL) commandId = raxNew();
1534 void *id;
1535 if (raxFind(commandId,(unsigned char*)lowername,sdslen(lowername),&id)) {
1536 sdsfree(lowername);
1537 return (unsigned long)id;
1538 }
1539 raxInsert(commandId,(unsigned char*)lowername,strlen(lowername),
1540 (void*)nextid,NULL);
1541 sdsfree(lowername);
1542 unsigned long thisid = nextid;
1543 nextid++;
1544
1545 /* We never assign the last bit in the user commands bitmap structure,
1546 * this way we can later check if this bit is set, understanding if the
1547 * current ACL for the user was created starting with a +@all to add all
1548 * the possible commands and just subtracting other single commands or
1549 * categories, or if, instead, the ACL was created just adding commands
1550 * and command categories from scratch, not allowing future commands by
1551 * default (loaded via modules). This is useful when rewriting the ACLs
1552 * with ACL SAVE. */
1553 if (nextid == USER_COMMAND_BITS_COUNT-1) nextid++;
1554 return thisid;
1555}
1556
1557/* Clear command id table and reset nextid to 0. */
1558void ACLClearCommandID(void) {
1559 if (commandId) raxFree(commandId);
1560 commandId = NULL;
1561 nextid = 0;
1562}
1563
1564/* Return an username by its name, or NULL if the user does not exist. */
1565user *ACLGetUserByName(const char *name, size_t namelen) {
1566 void *myuser = NULL;
1567 raxFind(Users,(unsigned char*)name,namelen,&myuser);
1568 return myuser;
1569}
1570
1571/* =============================================================================
1572 * ACL permission checks
1573 * ==========================================================================*/
1574
1575/* Check if the key can be accessed by the selector.
1576 *
1577 * If the selector can access the key, ACL_OK is returned, otherwise
1578 * ACL_DENIED_KEY is returned. */
1579static int ACLSelectorCheckKey(aclSelector *selector, const char *key, int keylen, int keyspec_flags) {
1580 /* The selector can access any key */
1581 if (selector->flags & SELECTOR_FLAG_ALLKEYS) return ACL_OK;
1582
1583 listIter li;
1584 listNode *ln;
1585 listRewind(selector->patterns,&li);
1586
1587 int key_flags = 0;
1588 if (keyspec_flags & CMD_KEY_ACCESS) key_flags |= ACL_READ_PERMISSION;
1589 if (keyspec_flags & CMD_KEY_INSERT) key_flags |= ACL_WRITE_PERMISSION;
1590 if (keyspec_flags & CMD_KEY_DELETE) key_flags |= ACL_WRITE_PERMISSION;
1591 if (keyspec_flags & CMD_KEY_UPDATE) key_flags |= ACL_WRITE_PERMISSION;
1592
1593 /* Is given key represent a prefix of a set of keys */
1594 int prefix = keyspec_flags & CMD_KEY_PREFIX;
1595
1596 /* Test this key against every pattern. */
1597 while((ln = listNext(&li))) {
1598 keyPattern *pattern = listNodeValue(ln);
1599 if ((pattern->flags & key_flags) != key_flags)
1600 continue;
1601 size_t plen = sdslen(pattern->pattern);
1602 if (prefix) {
1603 if (prefixmatch(pattern->pattern,plen,key,keylen,0))
1604 return ACL_OK;
1605 } else {
1606 if (stringmatchlen(pattern->pattern, plen, key, keylen, 0))
1607 return ACL_OK;
1608 }
1609 }
1610 return ACL_DENIED_KEY;
1611}
1612
1613/* Checks if the provided selector selector has access specified in flags
1614 * to all keys in the keyspace. For example, CMD_KEY_READ access requires either
1615 * '%R~*', '~*', or allkeys to be granted to the selector. Returns 1 if all
1616 * the access flags are satisfied with this selector or 0 otherwise.
1617 */
1618static int ACLSelectorHasUnrestrictedKeyAccess(aclSelector *selector, int flags) {
1619 /* The selector can access any key */
1620 if (selector->flags & SELECTOR_FLAG_ALLKEYS) return 1;
1621
1622 listIter li;
1623 listNode *ln;
1624 listRewind(selector->patterns,&li);
1625
1626 int access_flags = 0;
1627 if (flags & CMD_KEY_ACCESS) access_flags |= ACL_READ_PERMISSION;
1628 if (flags & CMD_KEY_INSERT) access_flags |= ACL_WRITE_PERMISSION;
1629 if (flags & CMD_KEY_DELETE) access_flags |= ACL_WRITE_PERMISSION;
1630 if (flags & CMD_KEY_UPDATE) access_flags |= ACL_WRITE_PERMISSION;
1631
1632 /* Test this key against every pattern. */
1633 while((ln = listNext(&li))) {
1634 keyPattern *pattern = listNodeValue(ln);
1635 if ((pattern->flags & access_flags) != access_flags)
1636 continue;
1637 if (!strcmp(pattern->pattern,"*")) {
1638 return 1;
1639 }
1640 }
1641 return 0;
1642}
1643
1644/* Checks a channel against a provided list of channels. The is_pattern
1645 * argument should only be used when subscribing (not when publishing)
1646 * and controls whether the input channel is evaluated as a channel pattern
1647 * (like in PSUBSCRIBE) or a plain channel name (like in SUBSCRIBE).
1648 *
1649 * Note that a plain channel name like in PUBLISH or SUBSCRIBE can be
1650 * matched against ACL channel patterns, but the pattern provided in PSUBSCRIBE
1651 * can only be matched as a literal against an ACL pattern (using plain string compare). */
1652static int ACLCheckChannelAgainstList(list *reference, const char *channel, int channellen, int is_pattern) {
1653 listIter li;
1654 listNode *ln;
1655
1656 listRewind(reference, &li);
1657 while((ln = listNext(&li))) {
1658 sds pattern = listNodeValue(ln);
1659 size_t plen = sdslen(pattern);
1660 /* Channel patterns are matched literally against the channels in
1661 * the list. Regular channels perform pattern matching. */
1662 if ((is_pattern && !strcmp(pattern,channel)) ||
1663 (!is_pattern && stringmatchlen(pattern,plen,channel,channellen,0)))
1664 {
1665 return ACL_OK;
1666 }
1667 }
1668 return ACL_DENIED_CHANNEL;
1669}
1670
1671/* To prevent duplicate calls to getKeysResult, a cache is maintained
1672 * in between calls to the various selectors. */
1673typedef struct {
1674 int keys_init;
1675 getKeysResult keys;
1676} aclKeyResultCache;
1677
1678void initACLKeyResultCache(aclKeyResultCache *cache) {
1679 cache->keys_init = 0;
1680}
1681
1682void cleanupACLKeyResultCache(aclKeyResultCache *cache) {
1683 if (cache->keys_init) getKeysFreeResult(&(cache->keys));
1684}
1685
1686/* Check if the command is ready to be executed according to the
1687 * ACLs associated with the specified selector.
1688 *
1689 * If the selector can execute the command ACL_OK is returned, otherwise
1690 * ACL_DENIED_CMD, ACL_DENIED_KEY, or ACL_DENIED_CHANNEL is returned: the first in case the
1691 * command cannot be executed because the selector is not allowed to run such
1692 * command, the second and third if the command is denied because the selector is trying
1693 * to access a key or channel that are not among the specified patterns. */
1694static int ACLSelectorCheckCmd(aclSelector *selector, struct redisCommand *cmd, robj **argv, int argc, int *keyidxptr, aclKeyResultCache *cache) {
1695 uint64_t id = cmd->id;
1696 int ret;
1697 if (!(selector->flags & SELECTOR_FLAG_ALLCOMMANDS) && !(cmd->flags & CMD_NO_AUTH)) {
1698 /* If the bit is not set we have to check further, in case the
1699 * command is allowed just with that specific first argument. */
1700 if (ACLGetSelectorCommandBit(selector,id) == 0) {
1701 /* Check if the first argument matches. */
1702 if (argc < 2 ||
1703 selector->allowed_firstargs == NULL ||
1704 selector->allowed_firstargs[id] == NULL)
1705 {
1706 return ACL_DENIED_CMD;
1707 }
1708
1709 long subid = 0;
1710 while (1) {
1711 if (selector->allowed_firstargs[id][subid] == NULL)
1712 return ACL_DENIED_CMD;
1713 int idx = cmd->parent ? 2 : 1;
1714 if (!strcasecmp(argv[idx]->ptr,selector->allowed_firstargs[id][subid]))
1715 break; /* First argument match found. Stop here. */
1716 subid++;
1717 }
1718 }
1719 }
1720
1721 /* Check if the user can execute commands explicitly touching the keys
1722 * mentioned in the command arguments. */
1723 if (!(selector->flags & SELECTOR_FLAG_ALLKEYS) && doesCommandHaveKeys(cmd)) {
1724 if (!(cache->keys_init)) {
1725 cache->keys = (getKeysResult) GETKEYS_RESULT_INIT;
1726 getKeysFromCommandWithSpecs(cmd, argv, argc, GET_KEYSPEC_DEFAULT, &(cache->keys));
1727 cache->keys_init = 1;
1728 }
1729 getKeysResult *result = &(cache->keys);
1730 keyReference *resultidx = result->keys;
1731 for (int j = 0; j < result->numkeys; j++) {
1732 int idx = resultidx[j].pos;
1733 ret = ACLSelectorCheckKey(selector, argv[idx]->ptr, sdslen(argv[idx]->ptr), resultidx[j].flags);
1734 if (ret != ACL_OK) {
1735 if (keyidxptr) *keyidxptr = resultidx[j].pos;
1736 return ret;
1737 }
1738 }
1739 }
1740
1741 /* Check if the user can execute commands explicitly touching the channels
1742 * mentioned in the command arguments */
1743 const int channel_flags = CMD_CHANNEL_PUBLISH | CMD_CHANNEL_SUBSCRIBE;
1744 if (!(selector->flags & SELECTOR_FLAG_ALLCHANNELS) && doesCommandHaveChannelsWithFlags(cmd, channel_flags)) {
1745 getKeysResult channels = (getKeysResult) GETKEYS_RESULT_INIT;
1746 getChannelsFromCommand(cmd, argv, argc, &channels);
1747 keyReference *channelref = channels.keys;
1748 for (int j = 0; j < channels.numkeys; j++) {
1749 int idx = channelref[j].pos;
1750 if (!(channelref[j].flags & channel_flags)) continue;
1751 int is_pattern = channelref[j].flags & CMD_CHANNEL_PATTERN;
1752 int ret = ACLCheckChannelAgainstList(selector->channels, argv[idx]->ptr, sdslen(argv[idx]->ptr), is_pattern);
1753 if (ret != ACL_OK) {
1754 if (keyidxptr) *keyidxptr = channelref[j].pos;
1755 getKeysFreeResult(&channels);
1756 return ret;
1757 }
1758 }
1759 getKeysFreeResult(&channels);
1760 }
1761 return ACL_OK;
1762}
1763
1764/* Check if the key can be accessed by the client according to
1765 * the ACLs associated with the specified user according to the
1766 * keyspec access flags.
1767 *
1768 * If the user can access the key, ACL_OK is returned, otherwise
1769 * ACL_DENIED_KEY is returned. */
1770int ACLUserCheckKeyPerm(user *u, const char *key, int keylen, int flags) {
1771 listIter li;
1772 listNode *ln;
1773
1774 /* If there is no associated user, the connection can run anything. */
1775 if (u == NULL) return ACL_OK;
1776
1777 /* Check all of the selectors */
1778 listRewind(u->selectors,&li);
1779 while((ln = listNext(&li))) {
1780 aclSelector *s = (aclSelector *) listNodeValue(ln);
1781 if (ACLSelectorCheckKey(s, key, keylen, flags) == ACL_OK) {
1782 return ACL_OK;
1783 }
1784 }
1785 return ACL_DENIED_KEY;
1786}
1787
1788/* Checks if the user can execute the given command with the added restriction
1789 * it must also have the access specified in flags to any key in the key space.
1790 * For example, CMD_KEY_READ access requires either '%R~*', '~*', or allkeys to be
1791 * granted in addition to the access required by the command. Returns 1
1792 * if the user has access or 0 otherwise.
1793 */
1794int ACLUserCheckCmdWithUnrestrictedKeyAccess(user *u, struct redisCommand *cmd, robj **argv, int argc, int flags) {
1795 listIter li;
1796 listNode *ln;
1797 int local_idxptr;
1798
1799 /* If there is no associated user, the connection can run anything. */
1800 if (u == NULL) return 1;
1801
1802 /* For multiple selectors, we cache the key result in between selector
1803 * calls to prevent duplicate lookups. */
1804 aclKeyResultCache cache;
1805 initACLKeyResultCache(&cache);
1806
1807 /* Check each selector sequentially */
1808 listRewind(u->selectors,&li);
1809 while((ln = listNext(&li))) {
1810 aclSelector *s = (aclSelector *) listNodeValue(ln);
1811 int acl_retval = ACLSelectorCheckCmd(s, cmd, argv, argc, &local_idxptr, &cache);
1812 if (acl_retval == ACL_OK && ACLSelectorHasUnrestrictedKeyAccess(s, flags)) {
1813 cleanupACLKeyResultCache(&cache);
1814 return 1;
1815 }
1816 }
1817 cleanupACLKeyResultCache(&cache);
1818 return 0;
1819}
1820
1821/* Check if the channel can be accessed by the client according to
1822 * the ACLs associated with the specified user.
1823 *
1824 * If the user can access the key, ACL_OK is returned, otherwise
1825 * ACL_DENIED_CHANNEL is returned. */
1826int ACLUserCheckChannelPerm(user *u, sds channel, int is_pattern) {
1827 listIter li;
1828 listNode *ln;
1829
1830 /* If there is no associated user, the connection can run anything. */
1831 if (u == NULL) return ACL_OK;
1832
1833 /* Check all of the selectors */
1834 listRewind(u->selectors,&li);
1835 while((ln = listNext(&li))) {
1836 aclSelector *s = (aclSelector *) listNodeValue(ln);
1837 /* The selector can run any keys */
1838 if (s->flags & SELECTOR_FLAG_ALLCHANNELS) return ACL_OK;
1839
1840 /* Otherwise, loop over the selectors list and check each channel */
1841 if (ACLCheckChannelAgainstList(s->channels, channel, sdslen(channel), is_pattern) == ACL_OK) {
1842 return ACL_OK;
1843 }
1844 }
1845 return ACL_DENIED_CHANNEL;
1846}
1847
1848/* Lower level API that checks if a specified user is able to execute a given command.
1849 *
1850 * If the command fails an ACL check, idxptr will be to set to the first argv entry that
1851 * causes the failure, either 0 if the command itself fails or the idx of the key/channel
1852 * that causes the failure */
1853int ACLCheckAllUserCommandPerm(user *u, struct redisCommand *cmd, robj **argv, int argc, getKeysResult *key_result, int *idxptr) {
1854 listIter li;
1855 listNode *ln;
1856
1857 /* If there is no associated user, the connection can run anything. */
1858 if (u == NULL) return ACL_OK;
1859
1860 /* Quick check if the user has all permissions, return early if so. */
1861 if (likely(listFirst(u->selectors) != NULL)) {
1862 aclSelector *s = listNodeValue(listFirst(u->selectors));
1863 const uint32_t all_perms = SELECTOR_FLAG_ALLCOMMANDS |
1864 SELECTOR_FLAG_ALLKEYS |
1865 SELECTOR_FLAG_ALLCHANNELS;
1866 if ((s->flags & all_perms) == all_perms) return ACL_OK;
1867 }
1868
1869 /* We have to pick a single error to log, the logic for picking is as follows:
1870 * 1) If no selector can execute the command, return the command.
1871 * 2) Return the last key or channel that no selector could match. */
1872 int relevant_error = ACL_DENIED_CMD;
1873 int local_idxptr = 0, last_idx = 0;
1874
1875 /* For multiple selectors, we cache the key result in between selector
1876 * calls to prevent duplicate lookups. */
1877 aclKeyResultCache cache;
1878 initACLKeyResultCache(&cache);
1879 if (key_result) {
1880 cache.keys = *key_result;
1881 cache.keys_init = 1;
1882 }
1883
1884 /* Check each selector sequentially */
1885 listRewind(u->selectors,&li);
1886 while((ln = listNext(&li))) {
1887 aclSelector *s = (aclSelector *) listNodeValue(ln);
1888 int acl_retval = ACLSelectorCheckCmd(s, cmd, argv, argc, &local_idxptr, &cache);
1889 if (acl_retval == ACL_OK) {
1890 if (!key_result) cleanupACLKeyResultCache(&cache);
1891 return ACL_OK;
1892 }
1893 if (acl_retval > relevant_error ||
1894 (acl_retval == relevant_error && local_idxptr > last_idx))
1895 {
1896 relevant_error = acl_retval;
1897 last_idx = local_idxptr;
1898 }
1899 }
1900
1901 *idxptr = last_idx;
1902 if (!key_result) cleanupACLKeyResultCache(&cache);
1903 return relevant_error;
1904}
1905
1906/* High level API for checking if a client can execute the queued up command */
1907int ACLCheckAllPerm(client *c, int *idxptr) {
1908 return ACLCheckAllUserCommandPerm(c->user, c->cmd, c->argv, c->argc, getClientCachedKeyResult(c), idxptr);
1909}
1910
1911/* If 'new' can access all channels 'original' could then return NULL;
1912 Otherwise return a list of channels that the new user can access */
1913list *getUpcomingChannelList(user *new, user *original) {
1914 listIter li, lpi;
1915 listNode *ln, *lpn;
1916
1917 /* Optimization: we check if any selector has all channel permissions. */
1918 listRewind(new->selectors,&li);
1919 while((ln = listNext(&li))) {
1920 aclSelector *s = (aclSelector *) listNodeValue(ln);
1921 if (s->flags & SELECTOR_FLAG_ALLCHANNELS) return NULL;
1922 }
1923
1924 /* Next, check if the new list of channels
1925 * is a strict superset of the original. This is done by
1926 * created an "upcoming" list of all channels that are in
1927 * the new user and checking each of the existing channels
1928 * against it. */
1929 list *upcoming = listCreate();
1930 listRewind(new->selectors,&li);
1931 while((ln = listNext(&li))) {
1932 aclSelector *s = (aclSelector *) listNodeValue(ln);
1933 listRewind(s->channels, &lpi);
1934 while((lpn = listNext(&lpi))) {
1935 listAddNodeTail(upcoming, listNodeValue(lpn));
1936 }
1937 }
1938
1939 int match = 1;
1940 listRewind(original->selectors,&li);
1941 while((ln = listNext(&li)) && match) {
1942 aclSelector *s = (aclSelector *) listNodeValue(ln);
1943 /* If any of the original selectors has the all-channels permission, but
1944 * the new ones don't (this is checked earlier in this function), then the
1945 * new list is not a strict superset of the original. */
1946 if (s->flags & SELECTOR_FLAG_ALLCHANNELS) {
1947 match = 0;
1948 break;
1949 }
1950 listRewind(s->channels, &lpi);
1951 while((lpn = listNext(&lpi)) && match) {
1952 if (!listSearchKey(upcoming, listNodeValue(lpn))) {
1953 match = 0;
1954 break;
1955 }
1956 }
1957 }
1958
1959 if (match) {
1960 /* All channels were matched, no need to kill clients. */
1961 listRelease(upcoming);
1962 return NULL;
1963 }
1964
1965 return upcoming;
1966}
1967
1968/* Check if the client should be killed because it is subscribed to channels that were
1969 * permitted in the past, are not in the `upcoming` channel list. */
1970int ACLShouldKillPubsubClient(client *c, list *upcoming) {
1971 robj *o;
1972 int kill = 0;
1973
1974 if (getClientType(c) == CLIENT_TYPE_PUBSUB) {
1975 /* Check for pattern violations. */
1976 dictIterator di;
1977 dictEntry *de;
1978 dictInitIterator(&di, c->pubsub_patterns);
1979 while (!kill && ((de = dictNext(&di)) != NULL)) {
1980 o = dictGetKey(de);
1981 int res = ACLCheckChannelAgainstList(upcoming, o->ptr, sdslen(o->ptr), 1);
1982 kill = (res == ACL_DENIED_CHANNEL);
1983 }
1984 dictResetIterator(&di);
1985
1986 /* Check for channel violations. */
1987 if (!kill) {
1988 /* Check for global channels violation. */
1989 dictInitIterator(&di, c->pubsub_channels);
1990
1991 while (!kill && ((de = dictNext(&di)) != NULL)) {
1992 o = dictGetKey(de);
1993 int res = ACLCheckChannelAgainstList(upcoming, o->ptr, sdslen(o->ptr), 0);
1994 kill = (res == ACL_DENIED_CHANNEL);
1995 }
1996 dictResetIterator(&di);
1997 }
1998 if (!kill) {
1999 /* Check for shard channels violation. */
2000 dictInitIterator(&di, c->pubsubshard_channels);
2001 while (!kill && ((de = dictNext(&di)) != NULL)) {
2002 o = dictGetKey(de);
2003 int res = ACLCheckChannelAgainstList(upcoming, o->ptr, sdslen(o->ptr), 0);
2004 kill = (res == ACL_DENIED_CHANNEL);
2005 }
2006 dictResetIterator(&di);
2007 }
2008
2009 if (kill) {
2010 return 1;
2011 }
2012 }
2013 return 0;
2014}
2015
2016/* Check if the user's existing pub/sub clients violate the ACL pub/sub
2017 * permissions specified via the upcoming argument, and kill them if so. */
2018void ACLKillPubsubClientsIfNeeded(user *new, user *original) {
2019 /* Do nothing if there are no subscribers. */
2020 if (pubsubTotalSubscriptions() == 0)
2021 return;
2022
2023 list *channels = getUpcomingChannelList(new, original);
2024 /* If the new user's pubsub permissions are a strict superset of the original, return early. */
2025 if (!channels)
2026 return;
2027
2028 listIter li;
2029 listNode *ln;
2030
2031 /* Permissions have changed, so we need to iterate through all
2032 * the clients and disconnect those that are no longer valid.
2033 * Scan all connected clients to find the user's pub/subs. */
2034 listRewind(server.clients,&li);
2035 while ((ln = listNext(&li)) != NULL) {
2036 client *c = listNodeValue(ln);
2037 if (c->user != original)
2038 continue;
2039 if (ACLShouldKillPubsubClient(c, channels))
2040 deauthenticateAndCloseClient(c);
2041 }
2042
2043 listRelease(channels);
2044}
2045
2046/* =============================================================================
2047 * ACL loading / saving functions
2048 * ==========================================================================*/
2049
2050
2051/* Selector definitions should be sent as a single argument, however
2052 * we will be lenient and try to find selector definitions spread
2053 * across multiple arguments since it makes for a simpler user experience
2054 * for ACL SETUSER as well as when loading from conf files.
2055 *
2056 * This function takes in an array of ACL operators, excluding the username,
2057 * and merges selector operations that are spread across multiple arguments. The return
2058 * value is a new SDS array, with length set to the passed in merged_argc. Arguments
2059 * that are untouched are still duplicated. If there is an unmatched parenthesis, NULL
2060 * is returned and invalid_idx is set to the argument with the start of the opening
2061 * parenthesis. */
2062sds *ACLMergeSelectorArguments(sds *argv, int argc, int *merged_argc, int *invalid_idx) {
2063 *merged_argc = 0;
2064 int open_bracket_start = -1;
2065
2066 sds *acl_args = (sds *) zmalloc(sizeof(sds) * argc);
2067
2068 sds selector = NULL;
2069 for (int j = 0; j < argc; j++) {
2070 char *op = argv[j];
2071
2072 if (open_bracket_start == -1 &&
2073 (op[0] == '(' && op[sdslen(op) - 1] != ')')) {
2074 selector = sdsdup(argv[j]);
2075 open_bracket_start = j;
2076 continue;
2077 }
2078
2079 if (open_bracket_start != -1) {
2080 selector = sdscatfmt(selector, " %s", op);
2081 if (op[sdslen(op) - 1] == ')') {
2082 open_bracket_start = -1;
2083 acl_args[*merged_argc] = selector;
2084 (*merged_argc)++;
2085 }
2086 continue;
2087 }
2088
2089 acl_args[*merged_argc] = sdsdup(argv[j]);
2090 (*merged_argc)++;
2091 }
2092
2093 if (open_bracket_start != -1) {
2094 for (int i = 0; i < *merged_argc; i++) sdsfree(acl_args[i]);
2095 zfree(acl_args);
2096 sdsfree(selector);
2097 if (invalid_idx) *invalid_idx = open_bracket_start;
2098 return NULL;
2099 }
2100
2101 return acl_args;
2102}
2103
2104/* takes an acl string already split on spaces and adds it to the given user
2105 * if the user object is NULL, will create a user with the given username
2106 *
2107 * Returns an error as an sds string if the ACL string is not parsable
2108 */
2109sds ACLStringSetUser(user *u, sds username, sds *argv, int argc) {
2110 serverAssert(u != NULL || username != NULL);
2111
2112 sds error = NULL;
2113
2114 int merged_argc = 0, invalid_idx = 0;
2115 sds *acl_args = ACLMergeSelectorArguments(argv, argc, &merged_argc, &invalid_idx);
2116
2117 if (!acl_args) {
2118 return sdscatfmt(sdsempty(),
2119 "Unmatched parenthesis in acl selector starting "
2120 "at '%s'.", (char *) argv[invalid_idx]);
2121 }
2122
2123 /* Create a temporary user to validate and stage all changes against
2124 * before applying to an existing user or creating a new user. If all
2125 * arguments are valid the user parameters will all be applied together.
2126 * If there are any errors then none of the changes will be applied. */
2127 user *tempu = ACLCreateUnlinkedUser();
2128 if (u) {
2129 ACLCopyUser(tempu, u);
2130 }
2131
2132 for (int j = 0; j < merged_argc; j++) {
2133 if (ACLSetUser(tempu,acl_args[j],(ssize_t) sdslen(acl_args[j])) != C_OK) {
2134 const char *errmsg = ACLSetUserStringError();
2135 error = sdscatfmt(sdsempty(),
2136 "Error in ACL SETUSER modifier '%s': %s",
2137 (char*)acl_args[j], errmsg);
2138 goto cleanup;
2139 }
2140 }
2141
2142 /* Existing pub/sub clients authenticated with the user may need to be
2143 * disconnected if (some of) their channel permissions were revoked. */
2144 if (u) {
2145 ACLKillPubsubClientsIfNeeded(tempu, u);
2146 }
2147
2148 /* Overwrite the user with the temporary user we modified above. */
2149 if (!u) {
2150 u = ACLCreateUser(username,sdslen(username));
2151 }
2152 serverAssert(u != NULL);
2153
2154 ACLCopyUser(u, tempu);
2155
2156cleanup:
2157 ACLFreeUser(tempu);
2158 for (int i = 0; i < merged_argc; i++) {
2159 sdsfree(acl_args[i]);
2160 }
2161 zfree(acl_args);
2162
2163 return error;
2164}
2165
2166/* Given an argument vector describing a user in the form:
2167 *
2168 * user <username> ... ACL rules and flags ...
2169 *
2170 * this function validates, and if the syntax is valid, appends
2171 * the user definition to a list for later loading.
2172 *
2173 * The rules are tested for validity and if there obvious syntax errors
2174 * the function returns C_ERR and does nothing, otherwise C_OK is returned
2175 * and the user is appended to the list.
2176 *
2177 * Note that this function cannot stop in case of commands that are not found
2178 * and, in that case, the error will be emitted later, because certain
2179 * commands may be defined later once modules are loaded.
2180 *
2181 * When an error is detected and C_ERR is returned, the function populates
2182 * by reference (if not set to NULL) the argc_err argument with the index
2183 * of the argv vector that caused the error. */
2184int ACLAppendUserForLoading(sds *argv, int argc, int *argc_err) {
2185 if (argc < 2 || strcasecmp(argv[0],"user")) {
2186 if (argc_err) *argc_err = 0;
2187 return C_ERR;
2188 }
2189
2190 if (listSearchKey(UsersToLoad, argv[1])) {
2191 if (argc_err) *argc_err = 1;
2192 errno = EALREADY;
2193 return C_ERR;
2194 }
2195
2196 /* Merged selectors before trying to process */
2197 int merged_argc;
2198 sds *acl_args = ACLMergeSelectorArguments(argv + 2, argc - 2, &merged_argc, argc_err);
2199
2200 if (!acl_args) {
2201 return C_ERR;
2202 }
2203
2204 /* Try to apply the user rules in a fake user to see if they
2205 * are actually valid. */
2206 user *fakeuser = ACLCreateUnlinkedUser();
2207
2208 for (int j = 0; j < merged_argc; j++) {
2209 if (ACLSetUser(fakeuser,acl_args[j],sdslen(acl_args[j])) == C_ERR) {
2210 if (errno != ENOENT) {
2211 ACLFreeUser(fakeuser);
2212 if (argc_err) *argc_err = j;
2213 for (int i = 0; i < merged_argc; i++) sdsfree(acl_args[i]);
2214 zfree(acl_args);
2215 return C_ERR;
2216 }
2217 }
2218 }
2219
2220 /* Rules look valid, let's append the user to the list. */
2221 sds *copy = zmalloc(sizeof(sds)*(merged_argc + 2));
2222 copy[0] = sdsdup(argv[1]);
2223 for (int j = 0; j < merged_argc; j++) copy[j+1] = sdsdup(acl_args[j]);
2224 copy[merged_argc + 1] = NULL;
2225 listAddNodeTail(UsersToLoad,copy);
2226 ACLFreeUser(fakeuser);
2227 for (int i = 0; i < merged_argc; i++) sdsfree(acl_args[i]);
2228 zfree(acl_args);
2229 return C_OK;
2230}
2231
2232/* This function will load the configured users appended to the server
2233 * configuration via ACLAppendUserForLoading(). On loading errors it will
2234 * log an error and return C_ERR, otherwise C_OK will be returned. */
2235int ACLLoadConfiguredUsers(void) {
2236 listIter li;
2237 listNode *ln;
2238 listRewind(UsersToLoad,&li);
2239 while ((ln = listNext(&li)) != NULL) {
2240 sds *aclrules = listNodeValue(ln);
2241 sds username = aclrules[0];
2242
2243 if (ACLStringHasSpaces(aclrules[0],sdslen(aclrules[0]))) {
2244 serverLog(LL_WARNING,"Spaces not allowed in ACL usernames");
2245 return C_ERR;
2246 }
2247
2248 user *u = ACLCreateUser(username,sdslen(username));
2249 if (!u) {
2250 /* Only valid duplicate user is the default one. */
2251 serverAssert(!strcmp(username, "default"));
2252 u = ACLGetUserByName("default",7);
2253 ACLSetUser(u,"reset",-1);
2254 }
2255
2256 /* Load every rule defined for this user. */
2257 for (int j = 1; aclrules[j]; j++) {
2258 if (ACLSetUser(u,aclrules[j],sdslen(aclrules[j])) != C_OK) {
2259 const char *errmsg = ACLSetUserStringError();
2260 serverLog(LL_WARNING,"Error loading ACL rule '%s' for "
2261 "the user named '%s': %s",
2262 redactLogCstr(aclrules[j]),redactLogCstr(aclrules[0]),errmsg);
2263 return C_ERR;
2264 }
2265 }
2266
2267 /* Having a disabled user in the configuration may be an error,
2268 * warn about it without returning any error to the caller. */
2269 if (u->flags & USER_FLAG_DISABLED) {
2270 serverLog(LL_NOTICE, "The user '%s' is disabled (there is no "
2271 "'on' modifier in the user description). Make "
2272 "sure this is not a configuration error.",
2273 redactLogCstr(aclrules[0]));
2274 }
2275 }
2276 return C_OK;
2277}
2278
2279/* This function loads the ACL from the specified filename: every line
2280 * is validated and should be either empty or in the format used to specify
2281 * users in the redis.conf configuration or in the ACL file, that is:
2282 *
2283 * user <username> ... rules ...
2284 *
2285 * Note that this function considers comments starting with '#' as errors
2286 * because the ACL file is meant to be rewritten, and comments would be
2287 * lost after the rewrite. Yet empty lines are allowed to avoid being too
2288 * strict.
2289 *
2290 * One important part of implementing ACL LOAD, that uses this function, is
2291 * to avoid ending with broken rules if the ACL file is invalid for some
2292 * reason, so the function will attempt to validate the rules before loading
2293 * each user. For every line that will be found broken the function will
2294 * collect an error message.
2295 *
2296 * IMPORTANT: If there is at least a single error, nothing will be loaded
2297 * and the rules will remain exactly as they were.
2298 *
2299 * At the end of the process, if no errors were found in the whole file then
2300 * NULL is returned. Otherwise an SDS string describing in a single line
2301 * a description of all the issues found is returned. */
2302sds ACLLoadFromFile(const char *filename) {
2303 FILE *fp;
2304 char buf[1024];
2305
2306 /* Open the ACL file. */
2307 if ((fp = fopen(filename,"r")) == NULL) {
2308 sds errors = sdscatprintf(sdsempty(),
2309 "Error loading ACLs, opening file '%s': %s",
2310 filename, strerror(errno));
2311 return errors;
2312 }
2313
2314 /* Load the whole file as a single string in memory. */
2315 sds acls = sdsempty();
2316 while(fgets(buf,sizeof(buf),fp) != NULL)
2317 acls = sdscat(acls,buf);
2318 fclose(fp);
2319
2320 /* Split the file into lines and attempt to load each line. */
2321 int totlines;
2322 sds *lines, errors = sdsempty();
2323 lines = sdssplitlen(acls,strlen(acls),"\n",1,&totlines);
2324 sdsfree(acls);
2325
2326 /* We do all the loading in a fresh instance of the Users radix tree,
2327 * so if there are errors loading the ACL file we can rollback to the
2328 * old version. */
2329 rax *old_users = Users;
2330 Users = raxNew();
2331
2332 /* Load each line of the file. */
2333 for (int i = 0; i < totlines; i++) {
2334 sds *argv;
2335 int argc;
2336 int linenum = i+1;
2337
2338 lines[i] = sdstrim(lines[i]," \t\r\n");
2339
2340 /* Skip blank lines */
2341 if (lines[i][0] == '\0') continue;
2342
2343 /* Split into arguments */
2344 argv = sdssplitlen(lines[i],sdslen(lines[i])," ",1,&argc);
2345 if (argv == NULL) {
2346 errors = sdscatprintf(errors,
2347 "%s:%d: unbalanced quotes in acl line. ",
2348 server.acl_filename, linenum);
2349 continue;
2350 }
2351
2352 /* Skip this line if the resulting command vector is empty. */
2353 if (argc == 0) {
2354 sdsfreesplitres(argv,argc);
2355 continue;
2356 }
2357
2358 /* The line should start with the "user" keyword. */
2359 if (strcmp(argv[0],"user") || argc < 2) {
2360 errors = sdscatprintf(errors,
2361 "%s:%d should start with user keyword followed "
2362 "by the username. ", server.acl_filename,
2363 linenum);
2364 sdsfreesplitres(argv,argc);
2365 continue;
2366 }
2367
2368 /* Spaces are not allowed in usernames. */
2369 if (ACLStringHasSpaces(argv[1],sdslen(argv[1]))) {
2370 errors = sdscatprintf(errors,
2371 "'%s:%d: username '%s' contains invalid characters. ",
2372 server.acl_filename, linenum, argv[1]);
2373 sdsfreesplitres(argv,argc);
2374 continue;
2375 }
2376
2377 user *u = ACLCreateUser(argv[1],sdslen(argv[1]));
2378
2379 /* If the user already exists we assume it's an error and abort. */
2380 if (!u) {
2381 errors = sdscatprintf(errors,"WARNING: Duplicate user '%s' found on line %d. ", argv[1], linenum);
2382 sdsfreesplitres(argv,argc);
2383 continue;
2384 }
2385
2386 /* Finally process the options and validate they can
2387 * be cleanly applied to the user. If any option fails
2388 * to apply, the other values won't be applied since
2389 * all the pending changes will get dropped. */
2390 int merged_argc;
2391 sds *acl_args = ACLMergeSelectorArguments(argv + 2, argc - 2, &merged_argc, NULL);
2392 if (!acl_args) {
2393 errors = sdscatprintf(errors,
2394 "%s:%d: Unmatched parenthesis in selector definition.",
2395 server.acl_filename, linenum);
2396 }
2397
2398 int syntax_error = 0;
2399 for (int j = 0; j < merged_argc; j++) {
2400 acl_args[j] = sdstrim(acl_args[j],"\t\r\n");
2401 if (ACLSetUser(u,acl_args[j],sdslen(acl_args[j])) != C_OK) {
2402 const char *errmsg = ACLSetUserStringError();
2403 if (errno == ENOENT) {
2404 /* For missing commands, we print out more information since
2405 * it shouldn't contain any sensitive information. */
2406 errors = sdscatprintf(errors,
2407 "%s:%d: Error in applying operation '%s': %s. ",
2408 server.acl_filename, linenum, acl_args[j], errmsg);
2409 } else if (syntax_error == 0) {
2410 /* For all other errors, only print out the first error encountered
2411 * since it might affect future operations. */
2412 errors = sdscatprintf(errors,
2413 "%s:%d: %s. ",
2414 server.acl_filename, linenum, errmsg);
2415 syntax_error = 1;
2416 }
2417 }
2418 }
2419
2420 for (int i = 0; i < merged_argc; i++) sdsfree(acl_args[i]);
2421 zfree(acl_args);
2422
2423 /* Apply the rule to the new users set only if so far there
2424 * are no errors, otherwise it's useless since we are going
2425 * to discard the new users set anyway. */
2426 if (sdslen(errors) != 0) {
2427 sdsfreesplitres(argv,argc);
2428 continue;
2429 }
2430
2431 sdsfreesplitres(argv,argc);
2432 }
2433
2434 sdsfreesplitres(lines,totlines);
2435
2436 /* Check if we found errors and react accordingly. */
2437 if (sdslen(errors) == 0) {
2438 /* The default user pointer is referenced in different places: instead
2439 * of replacing such occurrences it is much simpler to copy the new
2440 * default user configuration in the old one. */
2441 user *new_default = ACLGetUserByName("default",7);
2442 if (!new_default) {
2443 new_default = ACLCreateDefaultUser();
2444 }
2445
2446 ACLCopyUser(DefaultUser,new_default);
2447 ACLFreeUser(new_default);
2448 raxInsert(Users,(unsigned char*)"default",7,DefaultUser,NULL);
2449 raxRemove(old_users,(unsigned char*)"default",7,NULL);
2450
2451 /* If there are some subscribers, we need to check if we need to drop some clients. */
2452 rax *user_channels = NULL;
2453 if (pubsubTotalSubscriptions() > 0) {
2454 user_channels = raxNew();
2455 }
2456
2457 listIter li;
2458 listNode *ln;
2459
2460 listRewind(server.clients,&li);
2461 while ((ln = listNext(&li)) != NULL) {
2462 client *c = listNodeValue(ln);
2463 /* a MASTER client can do everything (and user = NULL) so we can skip it */
2464 if (c->flags & CLIENT_MASTER)
2465 continue;
2466 user *original = c->user;
2467 list *channels = NULL;
2468 user *new = ACLGetUserByName(c->user->name, sdslen(c->user->name));
2469 if (new && user_channels) {
2470 if (!raxFind(user_channels, (unsigned char*)(new->name), sdslen(new->name), (void**)&channels)) {
2471 channels = getUpcomingChannelList(new, original);
2472 raxInsert(user_channels, (unsigned char*)(new->name), sdslen(new->name), channels, NULL);
2473 }
2474 }
2475 /* When the new channel list is NULL, it means the new user's channel list is a superset of the old user's list. */
2476 if (!new || (channels && ACLShouldKillPubsubClient(c, channels))) {
2477 deauthenticateAndCloseClient(c);
2478 continue;
2479 }
2480 c->user = new;
2481 }
2482
2483 if (user_channels)
2484 raxFreeWithCallback(user_channels, listReleaseGeneric);
2485 raxFreeWithCallback(old_users, ACLFreeUserGeneric);
2486 sdsfree(errors);
2487 return NULL;
2488 } else {
2489 raxFreeWithCallback(Users, ACLFreeUserGeneric);
2490 Users = old_users;
2491 errors = sdscat(errors,"WARNING: ACL errors detected, no change to the previously active ACL rules was performed");
2492 return errors;
2493 }
2494}
2495
2496/* Generate a copy of the ACLs currently in memory in the specified filename.
2497 * Returns C_OK on success or C_ERR if there was an error during the I/O.
2498 * When C_ERR is returned a log is produced with hints about the issue. */
2499int ACLSaveToFile(const char *filename) {
2500 sds acl = sdsempty();
2501 int fd = -1;
2502 sds tmpfilename = NULL;
2503 int retval = C_ERR;
2504
2505 /* Let's generate an SDS string containing the new version of the
2506 * ACL file. */
2507 raxIterator ri;
2508 raxStart(&ri,Users);
2509 raxSeek(&ri,"^",NULL,0);
2510 while(raxNext(&ri)) {
2511 user *u = ri.data;
2512 /* Return information in the configuration file format. */
2513 sds user = sdsnew("user ");
2514 user = sdscatsds(user,u->name);
2515 user = sdscatlen(user," ",1);
2516 robj *descr = ACLDescribeUser(u);
2517 user = sdscatsds(user,descr->ptr);
2518 decrRefCount(descr);
2519 acl = sdscatsds(acl,user);
2520 acl = sdscatlen(acl,"\n",1);
2521 sdsfree(user);
2522 }
2523 raxStop(&ri);
2524
2525 /* Create a temp file with the new content. */
2526 tmpfilename = sdsnew(filename);
2527 tmpfilename = sdscatfmt(tmpfilename,".tmp-%i-%I",
2528 (int) getpid(),commandTimeSnapshot());
2529 if ((fd = open(tmpfilename,O_WRONLY|O_CREAT,0644)) == -1) {
2530 serverLog(LL_WARNING,"Opening temp ACL file for ACL SAVE: %s",
2531 strerror(errno));
2532 goto cleanup;
2533 }
2534
2535 /* Write it. */
2536 size_t offset = 0;
2537 while (offset < sdslen(acl)) {
2538 ssize_t written_bytes = write(fd,acl + offset,sdslen(acl) - offset);
2539 if (written_bytes <= 0) {
2540 if (errno == EINTR) continue;
2541 serverLog(LL_WARNING,"Writing ACL file for ACL SAVE: %s",
2542 strerror(errno));
2543 goto cleanup;
2544 }
2545 offset += written_bytes;
2546 }
2547 if (redis_fsync(fd) == -1) {
2548 serverLog(LL_WARNING,"Syncing ACL file for ACL SAVE: %s",
2549 strerror(errno));
2550 goto cleanup;
2551 }
2552 close(fd); fd = -1;
2553
2554 /* Let's replace the new file with the old one. */
2555 if (rename(tmpfilename,filename) == -1) {
2556 serverLog(LL_WARNING,"Renaming ACL file for ACL SAVE: %s",
2557 strerror(errno));
2558 goto cleanup;
2559 }
2560 if (fsyncFileDir(filename) == -1) {
2561 serverLog(LL_WARNING,"Syncing ACL directory for ACL SAVE: %s",
2562 strerror(errno));
2563 goto cleanup;
2564 }
2565 sdsfree(tmpfilename); tmpfilename = NULL;
2566 retval = C_OK; /* If we reached this point, everything is fine. */
2567
2568cleanup:
2569 if (fd != -1) close(fd);
2570 if (tmpfilename) unlink(tmpfilename);
2571 sdsfree(tmpfilename);
2572 sdsfree(acl);
2573 return retval;
2574}
2575
2576/* This function is called once the server is already running, modules are
2577 * loaded, and we are ready to start, in order to load the ACLs either from
2578 * the pending list of users defined in redis.conf, or from the ACL file.
2579 * The function will just exit with an error if the user is trying to mix
2580 * both the loading methods. */
2581void ACLLoadUsersAtStartup(void) {
2582 if (server.acl_filename[0] != '\0' && listLength(UsersToLoad) != 0) {
2583 serverLog(LL_WARNING,
2584 "Configuring Redis with users defined in redis.conf and at "
2585 "the same setting an ACL file path is invalid. This setup "
2586 "is very likely to lead to configuration errors and security "
2587 "holes, please define either an ACL file or declare users "
2588 "directly in your redis.conf, but not both.");
2589 exit(1);
2590 }
2591
2592 if (ACLLoadConfiguredUsers() == C_ERR) {
2593 serverLog(LL_WARNING,
2594 "Critical error while loading ACLs. Exiting.");
2595 exit(1);
2596 }
2597
2598 if (server.acl_filename[0] != '\0') {
2599 sds errors = ACLLoadFromFile(server.acl_filename);
2600 if (errors) {
2601 serverLog(LL_WARNING,
2602 "Aborting Redis startup because of ACL errors: %s", errors);
2603 sdsfree(errors);
2604 exit(1);
2605 }
2606 }
2607}
2608
2609/* =============================================================================
2610 * ACL log
2611 * ==========================================================================*/
2612
2613#define ACL_LOG_GROUPING_MAX_TIME_DELTA 60000
2614
2615/* This structure defines an entry inside the ACL log. */
2616typedef struct ACLLogEntry {
2617 uint64_t count; /* Number of times this happened recently. */
2618 int reason; /* Reason for denying the command. ACL_DENIED_*. */
2619 int context; /* Toplevel, Lua or MULTI/EXEC? ACL_LOG_CTX_*. */
2620 sds object; /* The key name or command name. */
2621 sds username; /* User the client is authenticated with. */
2622 mstime_t ctime; /* Milliseconds time of last update to this entry. */
2623 sds cinfo; /* Client info (last client if updated). */
2624 long long entry_id; /* The pair (entry_id, timestamp_created) is a unique identifier of this entry
2625 * in case the node dies and is restarted, it can detect that if it's a new series. */
2626 mstime_t timestamp_created; /* UNIX time in milliseconds at the time of this entry's creation. */
2627} ACLLogEntry;
2628
2629/* This function will check if ACL entries 'a' and 'b' are similar enough
2630 * that we should actually update the existing entry in our ACL log instead
2631 * of creating a new one. */
2632int ACLLogMatchEntry(ACLLogEntry *a, ACLLogEntry *b) {
2633 if (a->reason != b->reason) return 0;
2634 if (a->context != b->context) return 0;
2635 mstime_t delta = a->ctime - b->ctime;
2636 if (delta < 0) delta = -delta;
2637 if (delta > ACL_LOG_GROUPING_MAX_TIME_DELTA) return 0;
2638 if (sdscmp(a->object,b->object) != 0) return 0;
2639 if (sdscmp(a->username,b->username) != 0) return 0;
2640 return 1;
2641}
2642
2643/* Release an ACL log entry. */
2644void ACLFreeLogEntry(void *leptr) {
2645 ACLLogEntry *le = leptr;
2646 sdsfree(le->object);
2647 sdsfree(le->username);
2648 sdsfree(le->cinfo);
2649 zfree(le);
2650}
2651
2652/* Update the relevant counter by the reason */
2653void ACLUpdateInfoMetrics(int reason){
2654 if (reason == ACL_DENIED_AUTH) {
2655 server.acl_info.user_auth_failures++;
2656 } else if (reason == ACL_DENIED_CMD) {
2657 server.acl_info.invalid_cmd_accesses++;
2658 } else if (reason == ACL_DENIED_KEY) {
2659 server.acl_info.invalid_key_accesses++;
2660 } else if (reason == ACL_DENIED_CHANNEL) {
2661 server.acl_info.invalid_channel_accesses++;
2662 } else if (reason == ACL_INVALID_TLS_CERT_AUTH) {
2663 server.acl_info.acl_access_denied_tls_cert++;
2664 } else {
2665 serverPanic("Unknown ACL_DENIED encoding");
2666 }
2667}
2668
2669static void trimACLLogEntriesToMaxLen(void) {
2670 while(listLength(ACLLog) > server.acllog_max_len) {
2671 listNode *ln = listLast(ACLLog);
2672 ACLLogEntry *le = listNodeValue(ln);
2673 ACLFreeLogEntry(le);
2674 listDelNode(ACLLog,ln);
2675 }
2676}
2677
2678/* Adds a new entry in the ACL log, making sure to delete the old entry
2679 * if we reach the maximum length allowed for the log. This function attempts
2680 * to find similar entries in the current log in order to bump the counter of
2681 * the log entry instead of creating many entries for very similar ACL
2682 * rules issues.
2683 *
2684 * The argpos argument is used when the reason is ACL_DENIED_KEY or
2685 * ACL_DENIED_CHANNEL, since it allows the function to log the key or channel
2686 * name that caused the problem.
2687 *
2688 * The last 2 arguments are a manual override to be used, instead of any of the automatic
2689 * ones which depend on the client and reason arguments (use NULL for default).
2690 *
2691 * If `object` is not NULL, this functions takes over it.
2692 */
2693void addACLLogEntry(client *c, int reason, int context, int argpos, sds username, sds object) {
2694 /* Update ACL info metrics */
2695 ACLUpdateInfoMetrics(reason);
2696
2697 if (server.acllog_max_len == 0) {
2698 trimACLLogEntriesToMaxLen();
2699 return;
2700 }
2701
2702 /* Create a new entry. */
2703 struct ACLLogEntry *le = zmalloc(sizeof(*le));
2704 le->count = 1;
2705 le->reason = reason;
2706 le->username = sdsdup(username ? username : c->user->name);
2707 le->ctime = commandTimeSnapshot();
2708 le->entry_id = ACLLogEntryCount;
2709 le->timestamp_created = le->ctime;
2710
2711 if (object) {
2712 le->object = object;
2713 } else {
2714 switch(reason) {
2715 case ACL_DENIED_CMD: le->object = sdsdup(c->cmd->fullname); break;
2716 case ACL_DENIED_KEY: le->object = sdsdup(c->argv[argpos]->ptr); break;
2717 case ACL_DENIED_CHANNEL: le->object = sdsdup(c->argv[argpos]->ptr); break;
2718 case ACL_DENIED_AUTH: le->object = sdsdup(c->argv[0]->ptr); break;
2719 default: le->object = sdsempty();
2720 }
2721 }
2722
2723 /* if we have a real client from the network, use it (could be missing on module timers) */
2724 client *realclient = server.current_client? server.current_client : c;
2725
2726 le->cinfo = catClientInfoString(sdsempty(),realclient);
2727 le->context = context;
2728
2729 /* Try to match this entry with past ones, to see if we can just
2730 * update an existing entry instead of creating a new one. */
2731 long toscan = 10; /* Do a limited work trying to find duplicated. */
2732 listIter li;
2733 listNode *ln;
2734 listRewind(ACLLog,&li);
2735 ACLLogEntry *match = NULL;
2736 while (toscan-- && (ln = listNext(&li)) != NULL) {
2737 ACLLogEntry *current = listNodeValue(ln);
2738 if (ACLLogMatchEntry(current,le)) {
2739 match = current;
2740 listDelNode(ACLLog,ln);
2741 listAddNodeHead(ACLLog,current);
2742 break;
2743 }
2744 }
2745
2746 /* If there is a match update the entry, otherwise add it as a
2747 * new one. */
2748 if (match) {
2749 /* We update a few fields of the existing entry and bump the
2750 * counter of events for this entry. */
2751 sdsfree(match->cinfo);
2752 match->cinfo = le->cinfo;
2753 match->ctime = le->ctime;
2754 match->count++;
2755
2756 /* Release the old entry. */
2757 le->cinfo = NULL;
2758 ACLFreeLogEntry(le);
2759 } else {
2760 /* Add it to our list of entries. We'll have to trim the list
2761 * to its maximum size. */
2762 ACLLogEntryCount++; /* Incrementing the entry_id count to make each record in the log unique. */
2763 listAddNodeHead(ACLLog, le);
2764 trimACLLogEntriesToMaxLen();
2765 }
2766}
2767
2768sds getAclErrorMessage(int acl_res, user *user, struct redisCommand *cmd, sds errored_val, int verbose) {
2769 switch (acl_res) {
2770 case ACL_DENIED_CMD:
2771 return sdscatfmt(sdsempty(), "User %S has no permissions to run "
2772 "the '%S' command", user->name, cmd->fullname);
2773 case ACL_DENIED_KEY:
2774 if (verbose) {
2775 return sdscatfmt(sdsempty(), "User %S has no permissions to access "
2776 "the '%S' key", user->name, errored_val);
2777 } else {
2778 return sdsnew("No permissions to access a key");
2779 }
2780 case ACL_DENIED_CHANNEL:
2781 if (verbose) {
2782 return sdscatfmt(sdsempty(), "User %S has no permissions to access "
2783 "the '%S' channel", user->name, errored_val);
2784 } else {
2785 return sdsnew("No permissions to access a channel");
2786 }
2787 }
2788 serverPanic("Reached deadcode on getAclErrorMessage");
2789}
2790
2791/* =============================================================================
2792 * ACL related commands
2793 * ==========================================================================*/
2794
2795/* ACL CAT category */
2796void aclCatWithFlags(client *c, dict *commands, uint64_t cflag, int *arraylen) {
2797 dictEntry *de;
2798 dictIterator di;
2799 dictInitIterator(&di, commands);
2800 while ((de = dictNext(&di)) != NULL) {
2801 struct redisCommand *cmd = dictGetVal(de);
2802 if (cmd->acl_categories & cflag) {
2803 addReplyBulkCBuffer(c, cmd->fullname, sdslen(cmd->fullname));
2804 (*arraylen)++;
2805 }
2806
2807 if (cmd->subcommands_dict) {
2808 aclCatWithFlags(c, cmd->subcommands_dict, cflag, arraylen);
2809 }
2810 }
2811 dictResetIterator(&di);
2812}
2813
2814/* Add the formatted response from a single selector to the ACL GETUSER
2815 * response. This function returns the number of fields added.
2816 *
2817 * Setting verbose to 1 means that the full qualifier for key and channel
2818 * permissions are shown.
2819 */
2820int aclAddReplySelectorDescription(client *c, aclSelector *s) {
2821 listIter li;
2822 listNode *ln;
2823
2824 /* Commands */
2825 addReplyBulkCString(c,"commands");
2826 sds cmddescr = ACLDescribeSelectorCommandRules(s);
2827 addReplyBulkSds(c,cmddescr);
2828
2829 /* Key patterns */
2830 addReplyBulkCString(c,"keys");
2831 if (s->flags & SELECTOR_FLAG_ALLKEYS) {
2832 addReplyBulkCBuffer(c,"~*",2);
2833 } else {
2834 sds dsl = sdsempty();
2835 listRewind(s->patterns,&li);
2836 while((ln = listNext(&li))) {
2837 keyPattern *thispat = (keyPattern *) listNodeValue(ln);
2838 if (ln != listFirst(s->patterns)) dsl = sdscat(dsl, " ");
2839 dsl = sdsCatPatternString(dsl, thispat);
2840 }
2841 addReplyBulkSds(c, dsl);
2842 }
2843
2844 /* Pub/sub patterns */
2845 addReplyBulkCString(c,"channels");
2846 if (s->flags & SELECTOR_FLAG_ALLCHANNELS) {
2847 addReplyBulkCBuffer(c,"&*",2);
2848 } else {
2849 sds dsl = sdsempty();
2850 listRewind(s->channels,&li);
2851 while((ln = listNext(&li))) {
2852 sds thispat = listNodeValue(ln);
2853 if (ln != listFirst(s->channels)) dsl = sdscat(dsl, " ");
2854 dsl = sdscatfmt(dsl, "&%S", thispat);
2855 }
2856 addReplyBulkSds(c, dsl);
2857 }
2858 return 3;
2859}
2860
2861/* ACL -- show and modify the configuration of ACL users.
2862 * ACL HELP
2863 * ACL LOAD
2864 * ACL SAVE
2865 * ACL LIST
2866 * ACL USERS
2867 * ACL CAT [<category>]
2868 * ACL SETUSER <username> ... acl rules ...
2869 * ACL DELUSER <username> [...]
2870 * ACL GETUSER <username>
2871 * ACL GENPASS [<bits>]
2872 * ACL WHOAMI
2873 * ACL LOG [<count> | RESET]
2874 */
2875void aclCommand(client *c) {
2876 char *sub = c->argv[1]->ptr;
2877 if (!strcasecmp(sub,"setuser") && c->argc >= 3) {
2878 /* Initially redact all of the arguments to not leak any information
2879 * about the user. */
2880 for (int j = 2; j < c->argc; j++) {
2881 redactClientCommandArgument(c, j);
2882 }
2883
2884 sds username = c->argv[2]->ptr;
2885 /* Check username validity. */
2886 if (ACLStringHasSpaces(username,sdslen(username))) {
2887 addReplyError(c, "Usernames can't contain spaces or null characters");
2888 return;
2889 }
2890
2891 user *u = ACLGetUserByName(username,sdslen(username));
2892
2893 sds *temp_argv = zmalloc(c->argc * sizeof(sds));
2894 for (int i = 3; i < c->argc; i++) temp_argv[i-3] = c->argv[i]->ptr;
2895
2896 sds error = ACLStringSetUser(u, username, temp_argv, c->argc - 3);
2897 zfree(temp_argv);
2898 if (error == NULL) {
2899 addReply(c,shared.ok);
2900 } else {
2901 addReplyErrorSdsSafe(c, error);
2902 }
2903 return;
2904 } else if (!strcasecmp(sub,"deluser") && c->argc >= 3) {
2905 /* Initially redact all the arguments to not leak any information
2906 * about the users. */
2907 for (int j = 2; j < c->argc; j++) redactClientCommandArgument(c, j);
2908
2909 int deleted = 0;
2910 for (int j = 2; j < c->argc; j++) {
2911 sds username = c->argv[j]->ptr;
2912 if (!strcmp(username,"default")) {
2913 addReplyError(c,"The 'default' user cannot be removed");
2914 return;
2915 }
2916 }
2917
2918 for (int j = 2; j < c->argc; j++) {
2919 sds username = c->argv[j]->ptr;
2920 user *u;
2921 if (raxRemove(Users,(unsigned char*)username,
2922 sdslen(username),
2923 (void**)&u))
2924 {
2925 ACLFreeUserAndKillClients(u);
2926 deleted++;
2927 }
2928 }
2929 addReplyLongLong(c,deleted);
2930 } else if (!strcasecmp(sub,"getuser") && c->argc == 3) {
2931 /* Redact the username to not leak any information about the user. */
2932 redactClientCommandArgument(c, 2);
2933
2934 user *u = ACLGetUserByName(c->argv[2]->ptr,sdslen(c->argv[2]->ptr));
2935 if (u == NULL) {
2936 addReplyNull(c);
2937 return;
2938 }
2939
2940 void *ufields = addReplyDeferredLen(c);
2941 int fields = 3;
2942
2943 /* Flags */
2944 addReplyBulkCString(c,"flags");
2945 void *deflen = addReplyDeferredLen(c);
2946 int numflags = 0;
2947 for (int j = 0; ACLUserFlags[j].flag; j++) {
2948 if (u->flags & ACLUserFlags[j].flag) {
2949 addReplyBulkCString(c,ACLUserFlags[j].name);
2950 numflags++;
2951 }
2952 }
2953 setDeferredSetLen(c,deflen,numflags);
2954
2955 /* Passwords */
2956 addReplyBulkCString(c,"passwords");
2957 addReplyArrayLen(c,listLength(u->passwords));
2958 listIter li;
2959 listNode *ln;
2960 listRewind(u->passwords,&li);
2961 while((ln = listNext(&li))) {
2962 sds thispass = listNodeValue(ln);
2963 addReplyBulkCBuffer(c,thispass,sdslen(thispass));
2964 }
2965 /* Include the root selector at the top level for backwards compatibility */
2966 fields += aclAddReplySelectorDescription(c, ACLUserGetRootSelector(u));
2967
2968 /* Describe all of the selectors on this user, including duplicating the root selector */
2969 addReplyBulkCString(c,"selectors");
2970 addReplyArrayLen(c, listLength(u->selectors) - 1);
2971 listRewind(u->selectors,&li);
2972 serverAssert(listNext(&li));
2973 while((ln = listNext(&li))) {
2974 void *slen = addReplyDeferredLen(c);
2975 int sfields = aclAddReplySelectorDescription(c, (aclSelector *)listNodeValue(ln));
2976 setDeferredMapLen(c, slen, sfields);
2977 }
2978 setDeferredMapLen(c, ufields, fields);
2979 } else if ((!strcasecmp(sub,"list") || !strcasecmp(sub,"users")) &&
2980 c->argc == 2)
2981 {
2982 int justnames = !strcasecmp(sub,"users");
2983 addReplyArrayLen(c,raxSize(Users));
2984 raxIterator ri;
2985 raxStart(&ri,Users);
2986 raxSeek(&ri,"^",NULL,0);
2987 while(raxNext(&ri)) {
2988 user *u = ri.data;
2989 if (justnames) {
2990 addReplyBulkCBuffer(c,u->name,sdslen(u->name));
2991 } else {
2992 /* Return information in the configuration file format. */
2993 sds config = sdsnew("user ");
2994 config = sdscatsds(config,u->name);
2995 config = sdscatlen(config," ",1);
2996 robj *descr = ACLDescribeUser(u);
2997 config = sdscatsds(config,descr->ptr);
2998 decrRefCount(descr);
2999 addReplyBulkSds(c,config);
3000 }
3001 }
3002 raxStop(&ri);
3003 } else if (!strcasecmp(sub,"whoami") && c->argc == 2) {
3004 if (c->user != NULL) {
3005 addReplyBulkCBuffer(c,c->user->name,sdslen(c->user->name));
3006 } else {
3007 addReplyNull(c);
3008 }
3009 } else if (server.acl_filename[0] == '\0' &&
3010 (!strcasecmp(sub,"load") || !strcasecmp(sub,"save")))
3011 {
3012 addReplyError(c,"This Redis instance is not configured to use an ACL file. You may want to specify users via the ACL SETUSER command and then issue a CONFIG REWRITE (assuming you have a Redis configuration file set) in order to store users in the Redis configuration.");
3013 return;
3014 } else if (!strcasecmp(sub,"load") && c->argc == 2) {
3015 sds errors = ACLLoadFromFile(server.acl_filename);
3016 if (errors == NULL) {
3017 addReply(c,shared.ok);
3018 } else {
3019 addReplyError(c,errors);
3020 sdsfree(errors);
3021 }
3022 } else if (!strcasecmp(sub,"save") && c->argc == 2) {
3023 if (ACLSaveToFile(server.acl_filename) == C_OK) {
3024 addReply(c,shared.ok);
3025 } else {
3026 addReplyError(c,"There was an error trying to save the ACLs. "
3027 "Please check the server logs for more "
3028 "information");
3029 }
3030 } else if (!strcasecmp(sub,"cat") && c->argc == 2) {
3031 void *dl = addReplyDeferredLen(c);
3032 int j;
3033 for (j = 0; ACLCommandCategories[j].flag != 0; j++)
3034 addReplyBulkCString(c,ACLCommandCategories[j].name);
3035 setDeferredArrayLen(c,dl,j);
3036 } else if (!strcasecmp(sub,"cat") && c->argc == 3) {
3037 uint64_t cflag = ACLGetCommandCategoryFlagByName(c->argv[2]->ptr);
3038 if (cflag == 0) {
3039 addReplyErrorFormat(c, "Unknown category '%.128s'", (char*)c->argv[2]->ptr);
3040 return;
3041 }
3042 int arraylen = 0;
3043 void *dl = addReplyDeferredLen(c);
3044 aclCatWithFlags(c, server.orig_commands, cflag, &arraylen);
3045 setDeferredArrayLen(c,dl,arraylen);
3046 } else if (!strcasecmp(sub,"genpass") && (c->argc == 2 || c->argc == 3)) {
3047 #define GENPASS_MAX_BITS 4096
3048 char pass[GENPASS_MAX_BITS/8*2]; /* Hex representation. */
3049 long bits = 256; /* By default generate 256 bits passwords. */
3050
3051 if (c->argc == 3 && getLongFromObjectOrReply(c,c->argv[2],&bits,NULL)
3052 != C_OK) return;
3053
3054 if (bits <= 0 || bits > GENPASS_MAX_BITS) {
3055 addReplyErrorFormat(c,
3056 "ACL GENPASS argument must be the number of "
3057 "bits for the output password, a positive number "
3058 "up to %d",GENPASS_MAX_BITS);
3059 return;
3060 }
3061
3062 long chars = (bits+3)/4; /* Round to number of characters to emit. */
3063 getRandomHexChars(pass,chars);
3064 addReplyBulkCBuffer(c,pass,chars);
3065 } else if (!strcasecmp(sub,"log") && (c->argc == 2 || c->argc ==3)) {
3066 long count = 10; /* Number of entries to emit by default. */
3067
3068 /* Parse the only argument that LOG may have: it could be either
3069 * the number of entries the user wants to display, or alternatively
3070 * the "RESET" command in order to flush the old entries. */
3071 if (c->argc == 3) {
3072 if (!strcasecmp(c->argv[2]->ptr,"reset")) {
3073 listSetFreeMethod(ACLLog,ACLFreeLogEntry);
3074 listEmpty(ACLLog);
3075 listSetFreeMethod(ACLLog,NULL);
3076 addReply(c,shared.ok);
3077 return;
3078 } else if (getLongFromObjectOrReply(c,c->argv[2],&count,NULL)
3079 != C_OK)
3080 {
3081 return;
3082 }
3083 if (count < 0) count = 0;
3084 }
3085
3086 /* Fix the count according to the number of entries we got. */
3087 if ((size_t)count > listLength(ACLLog))
3088 count = listLength(ACLLog);
3089
3090 addReplyArrayLen(c,count);
3091 listIter li;
3092 listNode *ln;
3093 listRewind(ACLLog,&li);
3094 mstime_t now = commandTimeSnapshot();
3095 while (count-- && (ln = listNext(&li)) != NULL) {
3096 ACLLogEntry *le = listNodeValue(ln);
3097 addReplyMapLen(c,10);
3098 addReplyBulkCString(c,"count");
3099 addReplyLongLong(c,le->count);
3100
3101 addReplyBulkCString(c,"reason");
3102 char *reasonstr;
3103 switch(le->reason) {
3104 case ACL_DENIED_CMD: reasonstr="command"; break;
3105 case ACL_DENIED_KEY: reasonstr="key"; break;
3106 case ACL_DENIED_CHANNEL: reasonstr="channel"; break;
3107 case ACL_DENIED_AUTH: reasonstr="auth"; break;
3108 case ACL_INVALID_TLS_CERT_AUTH: reasonstr = "tls-cert"; break;
3109 default: reasonstr="unknown";
3110 }
3111 addReplyBulkCString(c,reasonstr);
3112
3113 addReplyBulkCString(c,"context");
3114 char *ctxstr;
3115 switch(le->context) {
3116 case ACL_LOG_CTX_TOPLEVEL: ctxstr="toplevel"; break;
3117 case ACL_LOG_CTX_MULTI: ctxstr="multi"; break;
3118 case ACL_LOG_CTX_LUA: ctxstr="lua"; break;
3119 case ACL_LOG_CTX_MODULE: ctxstr="module"; break;
3120 default: ctxstr="unknown";
3121 }
3122 addReplyBulkCString(c,ctxstr);
3123
3124 addReplyBulkCString(c,"object");
3125 addReplyBulkCBuffer(c,le->object,sdslen(le->object));
3126 addReplyBulkCString(c,"username");
3127 addReplyBulkCBuffer(c,le->username,sdslen(le->username));
3128 addReplyBulkCString(c,"age-seconds");
3129 double age = (double)(now - le->ctime)/1000;
3130 addReplyDouble(c,age);
3131 addReplyBulkCString(c,"client-info");
3132 addReplyBulkCBuffer(c,le->cinfo,sdslen(le->cinfo));
3133 addReplyBulkCString(c, "entry-id");
3134 addReplyLongLong(c, le->entry_id);
3135 addReplyBulkCString(c, "timestamp-created");
3136 addReplyLongLong(c, le->timestamp_created);
3137 addReplyBulkCString(c, "timestamp-last-updated");
3138 addReplyLongLong(c, le->ctime);
3139 }
3140 } else if (!strcasecmp(sub,"dryrun") && c->argc >= 4) {
3141 struct redisCommand *cmd;
3142 user *u = ACLGetUserByName(c->argv[2]->ptr,sdslen(c->argv[2]->ptr));
3143 if (u == NULL) {
3144 addReplyErrorFormat(c, "User '%s' not found", (char *)c->argv[2]->ptr);
3145 return;
3146 }
3147
3148 if ((cmd = lookupCommand(c->argv + 3, c->argc - 3)) == NULL) {
3149 addReplyErrorFormat(c, "Command '%s' not found", (char *)c->argv[3]->ptr);
3150 return;
3151 }
3152
3153 if ((cmd->arity > 0 && cmd->arity != c->argc-3) ||
3154 (c->argc-3 < -cmd->arity))
3155 {
3156 addReplyErrorFormat(c,"wrong number of arguments for '%s' command", cmd->fullname);
3157 return;
3158 }
3159
3160 int idx;
3161 int result = ACLCheckAllUserCommandPerm(u, cmd, c->argv + 3, c->argc - 3, NULL, &idx);
3162 if (result != ACL_OK) {
3163 sds err = getAclErrorMessage(result, u, cmd, c->argv[idx+3]->ptr, 1);
3164 addReplyBulkSds(c, err);
3165 return;
3166 }
3167
3168 addReply(c,shared.ok);
3169 } else if (c->argc == 2 && !strcasecmp(sub,"help")) {
3170 const char *help[] = {
3171"CAT [<category>]",
3172" List all commands that belong to <category>, or all command categories",
3173" when no category is specified.",
3174"DELUSER <username> [<username> ...]",
3175" Delete a list of users.",
3176"DRYRUN <username> <command> [<arg> ...]",
3177" Returns whether the user can execute the given command without executing the command.",
3178"GETUSER <username>",
3179" Get the user's details.",
3180"GENPASS [<bits>]",
3181" Generate a secure 256-bit user password. The optional `bits` argument can",
3182" be used to specify a different size.",
3183"LIST",
3184" Show users details in config file format.",
3185"LOAD",
3186" Reload users from the ACL file.",
3187"LOG [<count> | RESET]",
3188" Show the ACL log entries.",
3189"SAVE",
3190" Save the current config to the ACL file.",
3191"SETUSER <username> <attribute> [<attribute> ...]",
3192" Create or modify a user with the specified attributes.",
3193"USERS",
3194" List all the registered usernames.",
3195"WHOAMI",
3196" Return the current connection username.",
3197NULL
3198 };
3199 addReplyHelp(c,help);
3200 } else {
3201 addReplySubcommandSyntaxError(c);
3202 }
3203}
3204
3205void addReplyCommandCategories(client *c, struct redisCommand *cmd) {
3206 int flagcount = 0;
3207 void *flaglen = addReplyDeferredLen(c);
3208 for (int j = 0; ACLCommandCategories[j].flag != 0; j++) {
3209 if (cmd->acl_categories & ACLCommandCategories[j].flag) {
3210 addReplyStatusFormat(c, "@%s", ACLCommandCategories[j].name);
3211 flagcount++;
3212 }
3213 }
3214 setDeferredSetLen(c, flaglen, flagcount);
3215}
3216
3217/* When successful, initiates an internal connection, that is able to execute
3218 * internal commands (see CMD_INTERNAL). */
3219static void internalAuth(client *c) {
3220 if (!server.cluster_enabled) {
3221 addReplyError(c, "Cannot authenticate as an internal connection on non-cluster instances");
3222 return;
3223 }
3224
3225 sds password = c->argv[2]->ptr;
3226
3227 /* Get internal secret. */
3228 size_t len = -1;
3229 const char *internal_secret = clusterGetSecret(&len);
3230 if (sdslen(password) != len) {
3231 addReplyError(c, "-WRONGPASS invalid internal password");
3232 return;
3233 }
3234 if (!time_independent_strcmp((char *)internal_secret, (char *)password, len)) {
3235 c->flags |= CLIENT_INTERNAL;
3236 /* No further authentication is needed. */
3237 c->authenticated = 1;
3238 /* Set the user to the unrestricted user, if it is not already set (default). */
3239 if (c->user != NULL) {
3240 c->user = NULL;
3241 moduleNotifyUserChanged(c);
3242 }
3243 addReply(c, shared.ok);
3244 } else {
3245 addReplyError(c, "-WRONGPASS invalid internal password");
3246 }
3247}
3248
3249/* AUTH <password>
3250 * AUTH <username> <password> (Redis >= 6.0 form)
3251 *
3252 * When the user is omitted it means that we are trying to authenticate
3253 * against the default user. */
3254void authCommand(client *c) {
3255 /* Only two or three argument forms are allowed. */
3256 if (c->argc > 3) {
3257 addReplyErrorObject(c,shared.syntaxerr);
3258 return;
3259 }
3260 /* Always redact the second argument */
3261 redactClientCommandArgument(c, 1);
3262
3263 /* Handle the two different forms here. The form with two arguments
3264 * will just use "default" as username. */
3265 robj *username, *password;
3266 if (c->argc == 2) {
3267 /* Mimic the old behavior of giving an error for the two argument
3268 * form if no password is configured. */
3269 if (DefaultUser->flags & USER_FLAG_NOPASS) {
3270 addReplyError(c,"AUTH <password> called without any password "
3271 "configured for the default user. Are you sure "
3272 "your configuration is correct?");
3273 return;
3274 }
3275
3276 username = shared.default_username;
3277 password = c->argv[1];
3278 } else {
3279 username = c->argv[1];
3280 password = c->argv[2];
3281 redactClientCommandArgument(c, 2);
3282
3283 /* Handle internal authentication commands.
3284 * Note: No user-defined ACL user can have this username (no spaces
3285 * allowed), thus no conflicts with ACL possible. */
3286 if (!strcmp(username->ptr, "internal connection")) {
3287 internalAuth(c);
3288 return;
3289 }
3290 }
3291
3292 robj *err = NULL;
3293 int result = ACLAuthenticateUser(c, username, password, &err);
3294 if (result == AUTH_OK) {
3295 addReply(c, shared.ok);
3296 } else if (result == AUTH_ERR) {
3297 addAuthErrReply(c, err);
3298 }
3299 if (err) decrRefCount(err);
3300}
3301
3302/* Set the password for the "default" ACL user. This implements supports for
3303 * requirepass config, so passing in NULL will set the user to be nopass. */
3304void ACLUpdateDefaultUserPassword(sds password) {
3305 ACLSetUser(DefaultUser,"resetpass",-1);
3306 if (password) {
3307 sds aclop = sdscatlen(sdsnew(">"), password, sdslen(password));
3308 ACLSetUser(DefaultUser,aclop,sdslen(aclop));
3309 sdsfree(aclop);
3310 } else {
3311 ACLSetUser(DefaultUser,"nopass",-1);
3312 }
3313}