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