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 
39 rax *Users; /* Table mapping usernames to user structures. */
40 
41 user *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 
46 list *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(). */
53 list *ACLLog;       /* Our security log, the user is able to inspect that
54                        using the ACL LOG command .*/
55 
56 static rax *commandId = NULL; /* Command name to id mapping */
57 
58 static unsigned long nextid = 0; /* Next command id that has not been assigned */
59 
60 struct ACLCategoryItem {
61     const char *name;
62     uint64_t flag;
63 } ACLCommandCategories[] = { /* See redis.conf for details on each category. */
64     {"keyspace", CMD_CATEGORY_KEYSPACE},
65     {"read", CMD_CATEGORY_READ},
66     {"write", CMD_CATEGORY_WRITE},
67     {"set", CMD_CATEGORY_SET},
68     {"sortedset", CMD_CATEGORY_SORTEDSET},
69     {"list", CMD_CATEGORY_LIST},
70     {"hash", CMD_CATEGORY_HASH},
71     {"string", CMD_CATEGORY_STRING},
72     {"bitmap", CMD_CATEGORY_BITMAP},
73     {"hyperloglog", CMD_CATEGORY_HYPERLOGLOG},
74     {"geo", CMD_CATEGORY_GEO},
75     {"stream", CMD_CATEGORY_STREAM},
76     {"pubsub", CMD_CATEGORY_PUBSUB},
77     {"admin", CMD_CATEGORY_ADMIN},
78     {"fast", CMD_CATEGORY_FAST},
79     {"slow", CMD_CATEGORY_SLOW},
80     {"blocking", CMD_CATEGORY_BLOCKING},
81     {"dangerous", CMD_CATEGORY_DANGEROUS},
82     {"connection", CMD_CATEGORY_CONNECTION},
83     {"transaction", CMD_CATEGORY_TRANSACTION},
84     {"scripting", CMD_CATEGORY_SCRIPTING},
85     {NULL,0} /* Terminator. */
86 };
87 
88 struct 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     {"allkeys", USER_FLAG_ALLKEYS},
96     {"allchannels", USER_FLAG_ALLCHANNELS},
97     {"allcommands", USER_FLAG_ALLCOMMANDS},
98     {"nopass", USER_FLAG_NOPASS},
99     {"skip-sanitize-payload", USER_FLAG_SANITIZE_PAYLOAD_SKIP},
100     {"sanitize-payload", USER_FLAG_SANITIZE_PAYLOAD},
101     {NULL,0} /* Terminator. */
102 };
103 
104 void ACLResetFirstArgsForCommand(user *u, unsigned long id);
105 void ACLResetFirstArgs(user *u);
106 void ACLAddAllowedFirstArg(user *u, unsigned long id, const char *sub);
107 void ACLFreeLogEntry(void *le);
108 
109 /* The length of the string representation of a hashed password. */
110 #define HASH_PASSWORD_LEN SHA256_BLOCK_SIZE*2
111 
112 /* =============================================================================
113  * Helper functions for the rest of the ACL implementation
114  * ==========================================================================*/
115 
116 /* Return zero if strings are the same, non-zero if they are not.
117  * The comparison is performed in a way that prevents an attacker to obtain
118  * information about the nature of the strings just monitoring the execution
119  * time of the function.
120  *
121  * Note that limiting the comparison length to strings up to 512 bytes we
122  * can avoid leaking any information about the password length and any
123  * possible branch misprediction related leak.
124  */
time_independent_strcmp(char * a,char * b)125 int time_independent_strcmp(char *a, char *b) {
126     char bufa[CONFIG_AUTHPASS_MAX_LEN], bufb[CONFIG_AUTHPASS_MAX_LEN];
127     /* The above two strlen perform len(a) + len(b) operations where either
128      * a or b are fixed (our password) length, and the difference is only
129      * relative to the length of the user provided string, so no information
130      * leak is possible in the following two lines of code. */
131     unsigned int alen = strlen(a);
132     unsigned int blen = strlen(b);
133     unsigned int j;
134     int diff = 0;
135 
136     /* We can't compare strings longer than our static buffers.
137      * Note that this will never pass the first test in practical circumstances
138      * so there is no info leak. */
139     if (alen > sizeof(bufa) || blen > sizeof(bufb)) return 1;
140 
141     memset(bufa,0,sizeof(bufa));        /* Constant time. */
142     memset(bufb,0,sizeof(bufb));        /* Constant time. */
143     /* Again the time of the following two copies is proportional to
144      * len(a) + len(b) so no info is leaked. */
145     memcpy(bufa,a,alen);
146     memcpy(bufb,b,blen);
147 
148     /* Always compare all the chars in the two buffers without
149      * conditional expressions. */
150     for (j = 0; j < sizeof(bufa); j++) {
151         diff |= (bufa[j] ^ bufb[j]);
152     }
153     /* Length must be equal as well. */
154     diff |= alen ^ blen;
155     return diff; /* If zero strings are the same. */
156 }
157 
158 /* Given an SDS string, returns the SHA256 hex representation as a
159  * new SDS string. */
ACLHashPassword(unsigned char * cleartext,size_t len)160 sds ACLHashPassword(unsigned char *cleartext, size_t len) {
161     SHA256_CTX ctx;
162     unsigned char hash[SHA256_BLOCK_SIZE];
163     char hex[HASH_PASSWORD_LEN];
164     char *cset = "0123456789abcdef";
165 
166     sha256_init(&ctx);
167     sha256_update(&ctx,(unsigned char*)cleartext,len);
168     sha256_final(&ctx,hash);
169 
170     for (int j = 0; j < SHA256_BLOCK_SIZE; j++) {
171         hex[j*2] = cset[((hash[j]&0xF0)>>4)];
172         hex[j*2+1] = cset[(hash[j]&0xF)];
173     }
174     return sdsnewlen(hex,HASH_PASSWORD_LEN);
175 }
176 
177 /* Given a hash and the hash length, returns C_OK if it is a valid password
178  * hash, or C_ERR otherwise. */
ACLCheckPasswordHash(unsigned char * hash,int hashlen)179 int ACLCheckPasswordHash(unsigned char *hash, int hashlen) {
180     if (hashlen != HASH_PASSWORD_LEN) {
181         return C_ERR;
182     }
183 
184     /* Password hashes can only be characters that represent
185      * hexadecimal values, which are numbers and lowercase
186      * characters 'a' through 'f'. */
187     for(int i = 0; i < HASH_PASSWORD_LEN; i++) {
188         char c = hash[i];
189         if ((c < 'a' || c > 'f') && (c < '0' || c > '9')) {
190             return C_ERR;
191         }
192     }
193     return C_OK;
194 }
195 
196 /* =============================================================================
197  * Low level ACL API
198  * ==========================================================================*/
199 
200 /* Return 1 if the specified string contains spaces or null characters.
201  * We do this for usernames and key patterns for simpler rewriting of
202  * ACL rules, presentation on ACL list, and to avoid subtle security bugs
203  * that may arise from parsing the rules in presence of escapes.
204  * The function returns 0 if the string has no spaces. */
ACLStringHasSpaces(const char * s,size_t len)205 int ACLStringHasSpaces(const char *s, size_t len) {
206     for (size_t i = 0; i < len; i++) {
207         if (isspace(s[i]) || s[i] == 0) return 1;
208     }
209     return 0;
210 }
211 
212 /* Given the category name the command returns the corresponding flag, or
213  * zero if there is no match. */
ACLGetCommandCategoryFlagByName(const char * name)214 uint64_t ACLGetCommandCategoryFlagByName(const char *name) {
215     for (int j = 0; ACLCommandCategories[j].flag != 0; j++) {
216         if (!strcasecmp(name,ACLCommandCategories[j].name)) {
217             return ACLCommandCategories[j].flag;
218         }
219     }
220     return 0; /* No match. */
221 }
222 
223 /* Method for searching for a user within a list of user definitions. The
224  * list contains an array of user arguments, and we are only
225  * searching the first argument, the username, for a match. */
ACLListMatchLoadedUser(void * definition,void * user)226 int ACLListMatchLoadedUser(void *definition, void *user) {
227     sds *user_definition = definition;
228     return sdscmp(user_definition[0], user) == 0;
229 }
230 
231 /* Method for passwords/pattern comparison used for the user->passwords list
232  * so that we can search for items with listSearchKey(). */
ACLListMatchSds(void * a,void * b)233 int ACLListMatchSds(void *a, void *b) {
234     return sdscmp(a,b) == 0;
235 }
236 
237 /* Method to free list elements from ACL users password/patterns lists. */
ACLListFreeSds(void * item)238 void ACLListFreeSds(void *item) {
239     sdsfree(item);
240 }
241 
242 /* Method to duplicate list elements from ACL users password/patterns lists. */
ACLListDupSds(void * item)243 void *ACLListDupSds(void *item) {
244     return sdsdup(item);
245 }
246 
247 /* Create a new user with the specified name, store it in the list
248  * of users (the Users global radix tree), and returns a reference to
249  * the structure representing the user.
250  *
251  * If the user with such name already exists NULL is returned. */
ACLCreateUser(const char * name,size_t namelen)252 user *ACLCreateUser(const char *name, size_t namelen) {
253     if (raxFind(Users,(unsigned char*)name,namelen) != raxNotFound) return NULL;
254     user *u = zmalloc(sizeof(*u));
255     u->name = sdsnewlen(name,namelen);
256     u->flags = USER_FLAG_DISABLED | server.acl_pubsub_default;
257     u->allowed_firstargs = NULL;
258     u->passwords = listCreate();
259     u->patterns = listCreate();
260     u->channels = listCreate();
261     listSetMatchMethod(u->passwords,ACLListMatchSds);
262     listSetFreeMethod(u->passwords,ACLListFreeSds);
263     listSetDupMethod(u->passwords,ACLListDupSds);
264     listSetMatchMethod(u->patterns,ACLListMatchSds);
265     listSetFreeMethod(u->patterns,ACLListFreeSds);
266     listSetDupMethod(u->patterns,ACLListDupSds);
267     listSetMatchMethod(u->channels,ACLListMatchSds);
268     listSetFreeMethod(u->channels,ACLListFreeSds);
269     listSetDupMethod(u->channels,ACLListDupSds);
270     memset(u->allowed_commands,0,sizeof(u->allowed_commands));
271     raxInsert(Users,(unsigned char*)name,namelen,u,NULL);
272     return u;
273 }
274 
275 /* This function should be called when we need an unlinked "fake" user
276  * we can use in order to validate ACL rules or for other similar reasons.
277  * The user will not get linked to the Users radix tree. The returned
278  * user should be released with ACLFreeUser() as usually. */
ACLCreateUnlinkedUser(void)279 user *ACLCreateUnlinkedUser(void) {
280     char username[64];
281     for (int j = 0; ; j++) {
282         snprintf(username,sizeof(username),"__fakeuser:%d__",j);
283         user *fakeuser = ACLCreateUser(username,strlen(username));
284         if (fakeuser == NULL) continue;
285         int retval = raxRemove(Users,(unsigned char*) username,
286                                strlen(username),NULL);
287         serverAssert(retval != 0);
288         return fakeuser;
289     }
290 }
291 
292 /* Release the memory used by the user structure. Note that this function
293  * will not remove the user from the Users global radix tree. */
ACLFreeUser(user * u)294 void ACLFreeUser(user *u) {
295     sdsfree(u->name);
296     listRelease(u->passwords);
297     listRelease(u->patterns);
298     listRelease(u->channels);
299     ACLResetFirstArgs(u);
300     zfree(u);
301 }
302 
303 /* When a user is deleted we need to cycle the active
304  * connections in order to kill all the pending ones that
305  * are authenticated with such user. */
ACLFreeUserAndKillClients(user * u)306 void ACLFreeUserAndKillClients(user *u) {
307     listIter li;
308     listNode *ln;
309     listRewind(server.clients,&li);
310     while ((ln = listNext(&li)) != NULL) {
311         client *c = listNodeValue(ln);
312         if (c->user == u) {
313             /* We'll free the connection asynchronously, so
314              * in theory to set a different user is not needed.
315              * However if there are bugs in Redis, soon or later
316              * this may result in some security hole: it's much
317              * more defensive to set the default user and put
318              * it in non authenticated mode. */
319             c->user = DefaultUser;
320             c->authenticated = 0;
321             /* We will write replies to this client later, so we can't
322              * close it directly even if async. */
323             if (c == server.current_client) {
324                 c->flags |= CLIENT_CLOSE_AFTER_COMMAND;
325             } else {
326                 freeClientAsync(c);
327             }
328         }
329     }
330     ACLFreeUser(u);
331 }
332 
333 /* Copy the user ACL rules from the source user 'src' to the destination
334  * user 'dst' so that at the end of the process they'll have exactly the
335  * same rules (but the names will continue to be the original ones). */
ACLCopyUser(user * dst,user * src)336 void ACLCopyUser(user *dst, user *src) {
337     listRelease(dst->passwords);
338     listRelease(dst->patterns);
339     listRelease(dst->channels);
340     dst->passwords = listDup(src->passwords);
341     dst->patterns = listDup(src->patterns);
342     dst->channels = listDup(src->channels);
343     memcpy(dst->allowed_commands,src->allowed_commands,
344            sizeof(dst->allowed_commands));
345     dst->flags = src->flags;
346     ACLResetFirstArgs(dst);
347     /* Copy the allowed first-args array of array of SDS strings. */
348     if (src->allowed_firstargs) {
349         for (int j = 0; j < USER_COMMAND_BITS_COUNT; j++) {
350             if (src->allowed_firstargs[j]) {
351                 for (int i = 0; src->allowed_firstargs[j][i]; i++)
352                 {
353                     ACLAddAllowedFirstArg(dst, j,
354                         src->allowed_firstargs[j][i]);
355                 }
356             }
357         }
358     }
359 }
360 
361 /* Free all the users registered in the radix tree 'users' and free the
362  * radix tree itself. */
ACLFreeUsersSet(rax * users)363 void ACLFreeUsersSet(rax *users) {
364     raxFreeWithCallback(users,(void(*)(void*))ACLFreeUserAndKillClients);
365 }
366 
367 /* Given a command ID, this function set by reference 'word' and 'bit'
368  * so that user->allowed_commands[word] will address the right word
369  * where the corresponding bit for the provided ID is stored, and
370  * so that user->allowed_commands[word]&bit will identify that specific
371  * bit. The function returns C_ERR in case the specified ID overflows
372  * the bitmap in the user representation. */
ACLGetCommandBitCoordinates(uint64_t id,uint64_t * word,uint64_t * bit)373 int ACLGetCommandBitCoordinates(uint64_t id, uint64_t *word, uint64_t *bit) {
374     if (id >= USER_COMMAND_BITS_COUNT) return C_ERR;
375     *word = id / sizeof(uint64_t) / 8;
376     *bit = 1ULL << (id % (sizeof(uint64_t) * 8));
377     return C_OK;
378 }
379 
380 /* Check if the specified command bit is set for the specified user.
381  * The function returns 1 is the bit is set or 0 if it is not.
382  * Note that this function does not check the ALLCOMMANDS flag of the user
383  * but just the lowlevel bitmask.
384  *
385  * If the bit overflows the user internal representation, zero is returned
386  * in order to disallow the execution of the command in such edge case. */
ACLGetUserCommandBit(const user * u,unsigned long id)387 int ACLGetUserCommandBit(const user *u, unsigned long id) {
388     uint64_t word, bit;
389     if (ACLGetCommandBitCoordinates(id,&word,&bit) == C_ERR) return 0;
390     return (u->allowed_commands[word] & bit) != 0;
391 }
392 
393 /* When +@all or allcommands is given, we set a reserved bit as well that we
394  * can later test, to see if the user has the right to execute "future commands",
395  * that is, commands loaded later via modules. */
ACLUserCanExecuteFutureCommands(user * u)396 int ACLUserCanExecuteFutureCommands(user *u) {
397     return ACLGetUserCommandBit(u,USER_COMMAND_BITS_COUNT-1);
398 }
399 
400 /* Set the specified command bit for the specified user to 'value' (0 or 1).
401  * If the bit overflows the user internal representation, no operation
402  * is performed. As a side effect of calling this function with a value of
403  * zero, the user flag ALLCOMMANDS is cleared since it is no longer possible
404  * to skip the command bit explicit test. */
ACLSetUserCommandBit(user * u,unsigned long id,int value)405 void ACLSetUserCommandBit(user *u, unsigned long id, int value) {
406     uint64_t word, bit;
407     if (ACLGetCommandBitCoordinates(id,&word,&bit) == C_ERR) return;
408     if (value) {
409         u->allowed_commands[word] |= bit;
410     } else {
411         u->allowed_commands[word] &= ~bit;
412         u->flags &= ~USER_FLAG_ALLCOMMANDS;
413     }
414 }
415 
416 /* This function is used to allow/block a specific command.
417  * Allowing/blocking a container command also applies for its subcommands */
ACLChangeCommandPerm(user * u,struct redisCommand * cmd,int allow)418 void ACLChangeCommandPerm(user *u, struct redisCommand *cmd, int allow) {
419     unsigned long id = cmd->id;
420     ACLSetUserCommandBit(u,id,allow);
421     ACLResetFirstArgsForCommand(u,id);
422     if (cmd->subcommands_dict) {
423         dictEntry *de;
424         dictIterator *di = dictGetSafeIterator(cmd->subcommands_dict);
425         while((de = dictNext(di)) != NULL) {
426             struct redisCommand *sub = (struct redisCommand *)dictGetVal(de);
427             ACLSetUserCommandBit(u,sub->id,allow);
428         }
429         dictReleaseIterator(di);
430     }
431 }
432 
ACLSetUserCommandBitsForCategoryLogic(dict * commands,user * u,uint64_t cflag,int value)433 void ACLSetUserCommandBitsForCategoryLogic(dict *commands, user *u, uint64_t cflag, int value) {
434     dictIterator *di = dictGetIterator(commands);
435     dictEntry *de;
436     while ((de = dictNext(di)) != NULL) {
437         struct redisCommand *cmd = dictGetVal(de);
438         if (cmd->flags & CMD_MODULE) continue; /* Ignore modules commands. */
439         if (cmd->flags & cflag) {
440             ACLChangeCommandPerm(u,cmd,value);
441         }
442         if (cmd->subcommands_dict) {
443             ACLSetUserCommandBitsForCategoryLogic(cmd->subcommands_dict, u, cflag, value);
444         }
445     }
446     dictReleaseIterator(di);
447 }
448 
449 /* This is like ACLSetUserCommandBit(), but instead of setting the specified
450  * ID, it will check all the commands in the category specified as argument,
451  * and will set all the bits corresponding to such commands to the specified
452  * value. Since the category passed by the user may be non existing, the
453  * function returns C_ERR if the category was not found, or C_OK if it was
454  * found and the operation was performed. */
ACLSetUserCommandBitsForCategory(user * u,const char * category,int value)455 int ACLSetUserCommandBitsForCategory(user *u, const char *category, int value) {
456     uint64_t cflag = ACLGetCommandCategoryFlagByName(category);
457     if (!cflag) return C_ERR;
458     ACLSetUserCommandBitsForCategoryLogic(server.orig_commands, u, cflag, value);
459     return C_OK;
460 }
461 
ACLCountCategoryBitsForCommands(dict * commands,user * u,unsigned long * on,unsigned long * off,uint64_t cflag)462 void ACLCountCategoryBitsForCommands(dict *commands, user *u, unsigned long *on, unsigned long *off, uint64_t cflag) {
463     dictIterator *di = dictGetIterator(commands);
464     dictEntry *de;
465     while ((de = dictNext(di)) != NULL) {
466         struct redisCommand *cmd = dictGetVal(de);
467         if (cmd->flags & cflag) {
468             if (ACLGetUserCommandBit(u,cmd->id))
469                 (*on)++;
470             else
471                 (*off)++;
472         }
473         if (cmd->subcommands_dict) {
474             ACLCountCategoryBitsForCommands(cmd->subcommands_dict, u, on, off, cflag);
475         }
476     }
477     dictReleaseIterator(di);
478 }
479 
480 /* Return the number of commands allowed (on) and denied (off) for the user 'u'
481  * in the subset of commands flagged with the specified category name.
482  * If the category name is not valid, C_ERR is returned, otherwise C_OK is
483  * returned and on and off are populated by reference. */
ACLCountCategoryBitsForUser(user * u,unsigned long * on,unsigned long * off,const char * category)484 int ACLCountCategoryBitsForUser(user *u, unsigned long *on, unsigned long *off,
485                                 const char *category)
486 {
487     uint64_t cflag = ACLGetCommandCategoryFlagByName(category);
488     if (!cflag) return C_ERR;
489 
490     *on = *off = 0;
491     ACLCountCategoryBitsForCommands(server.orig_commands, u, on, off, cflag);
492     return C_OK;
493 }
494 
ACLDescribeUserCommandRulesSingleCommands(user * u,user * fakeuser,sds rules,dict * commands)495 sds ACLDescribeUserCommandRulesSingleCommands(user *u, user *fakeuser, sds rules, dict *commands) {
496     dictIterator *di = dictGetIterator(commands);
497     dictEntry *de;
498     while ((de = dictNext(di)) != NULL) {
499         struct redisCommand *cmd = dictGetVal(de);
500         int userbit = ACLGetUserCommandBit(u,cmd->id);
501         int fakebit = ACLGetUserCommandBit(fakeuser,cmd->id);
502         if (userbit != fakebit) {
503             rules = sdscatlen(rules, userbit ? "+" : "-", 1);
504             sds fullname = getFullCommandName(cmd);
505             rules = sdscat(rules,fullname);
506             sdsfree(fullname);
507             rules = sdscatlen(rules," ",1);
508             ACLChangeCommandPerm(fakeuser,cmd,userbit);
509         }
510 
511         if (cmd->subcommands_dict)
512             rules = ACLDescribeUserCommandRulesSingleCommands(u,fakeuser,rules,cmd->subcommands_dict);
513 
514         /* Emit the first-args if there are any. */
515         if (userbit == 0 && u->allowed_firstargs &&
516             u->allowed_firstargs[cmd->id])
517         {
518             for (int j = 0; u->allowed_firstargs[cmd->id][j]; j++) {
519                 rules = sdscatlen(rules,"+",1);
520                 sds fullname = getFullCommandName(cmd);
521                 rules = sdscat(rules,fullname);
522                 sdsfree(fullname);
523                 rules = sdscatlen(rules,"|",1);
524                 rules = sdscatsds(rules,u->allowed_firstargs[cmd->id][j]);
525                 rules = sdscatlen(rules," ",1);
526             }
527         }
528     }
529     dictReleaseIterator(di);
530     return rules;
531 }
532 
533 /* This function returns an SDS string representing the specified user ACL
534  * rules related to command execution, in the same format you could set them
535  * back using ACL SETUSER. The function will return just the set of rules needed
536  * to recreate the user commands bitmap, without including other user flags such
537  * as on/off, passwords and so forth. The returned string always starts with
538  * the +@all or -@all rule, depending on the user bitmap, and is followed, if
539  * needed, by the other rules needed to narrow or extend what the user can do. */
ACLDescribeUserCommandRules(user * u)540 sds ACLDescribeUserCommandRules(user *u) {
541     sds rules = sdsempty();
542     int additive;   /* If true we start from -@all and add, otherwise if
543                        false we start from +@all and remove. */
544 
545     /* This code is based on a trick: as we generate the rules, we apply
546      * them to a fake user, so that as we go we still know what are the
547      * bit differences we should try to address by emitting more rules. */
548     user fu = {0};
549     user *fakeuser = &fu;
550 
551     /* Here we want to understand if we should start with +@all and remove
552      * the commands corresponding to the bits that are not set in the user
553      * commands bitmap, or the contrary. Note that semantically the two are
554      * different. For instance starting with +@all and subtracting, the user
555      * will be able to execute future commands, while -@all and adding will just
556      * allow the user the run the selected commands and/or categories.
557      * How do we test for that? We use the trick of a reserved command ID bit
558      * that is set only by +@all (and its alias "allcommands"). */
559     if (ACLUserCanExecuteFutureCommands(u)) {
560         additive = 0;
561         rules = sdscat(rules,"+@all ");
562         ACLSetUser(fakeuser,"+@all",-1);
563     } else {
564         additive = 1;
565         rules = sdscat(rules,"-@all ");
566         ACLSetUser(fakeuser,"-@all",-1);
567     }
568 
569     /* Attempt to find a good approximation for categories and commands
570      * based on the current bits used, by looping over the category list
571      * and applying the best fit each time. Often a set of categories will not
572      * perfectly match the set of commands into it, so at the end we do a
573      * final pass adding/removing the single commands needed to make the bitmap
574      * exactly match. A temp user is maintained to keep track of categories
575      * already applied. */
576     user tu = {0};
577     user *tempuser = &tu;
578 
579     /* Keep track of the categories that have been applied, to prevent
580      * applying them twice.  */
581     char applied[sizeof(ACLCommandCategories)/sizeof(ACLCommandCategories[0])];
582     memset(applied, 0, sizeof(applied));
583 
584     memcpy(tempuser->allowed_commands,
585         u->allowed_commands,
586         sizeof(u->allowed_commands));
587     while (1) {
588         int best = -1;
589         unsigned long mindiff = INT_MAX, maxsame = 0;
590         for (int j = 0; ACLCommandCategories[j].flag != 0; j++) {
591             if (applied[j]) continue;
592 
593             unsigned long on, off, diff, same;
594             ACLCountCategoryBitsForUser(tempuser,&on,&off,ACLCommandCategories[j].name);
595             /* Check if the current category is the best this loop:
596              * * It has more commands in common with the user than commands
597              *   that are different.
598              * AND EITHER
599              * * It has the fewest number of differences
600              *    than the best match we have found so far.
601              * * OR it matches the fewest number of differences
602              *   that we've seen but it has more in common. */
603             diff = additive ? off : on;
604             same = additive ? on : off;
605             if (same > diff &&
606                 ((diff < mindiff) || (diff == mindiff && same > maxsame)))
607             {
608                 best = j;
609                 mindiff = diff;
610                 maxsame = same;
611             }
612         }
613 
614         /* We didn't find a match */
615         if (best == -1) break;
616 
617         sds op = sdsnewlen(additive ? "+@" : "-@", 2);
618         op = sdscat(op,ACLCommandCategories[best].name);
619         ACLSetUser(fakeuser,op,-1);
620 
621         sds invop = sdsnewlen(additive ? "-@" : "+@", 2);
622         invop = sdscat(invop,ACLCommandCategories[best].name);
623         ACLSetUser(tempuser,invop,-1);
624 
625         rules = sdscatsds(rules,op);
626         rules = sdscatlen(rules," ",1);
627         sdsfree(op);
628         sdsfree(invop);
629 
630         applied[best] = 1;
631     }
632 
633     /* Fix the final ACLs with single commands differences. */
634     rules = ACLDescribeUserCommandRulesSingleCommands(u,fakeuser,rules,server.orig_commands);
635 
636     /* Trim the final useless space. */
637     sdsrange(rules,0,-2);
638 
639     /* This is technically not needed, but we want to verify that now the
640      * predicted bitmap is exactly the same as the user bitmap, and abort
641      * otherwise, because aborting is better than a security risk in this
642      * code path. */
643     if (memcmp(fakeuser->allowed_commands,
644                         u->allowed_commands,
645                         sizeof(u->allowed_commands)) != 0)
646     {
647         serverLog(LL_WARNING,
648             "CRITICAL ERROR: User ACLs don't match final bitmap: '%s'",
649             rules);
650         serverPanic("No bitmap match in ACLDescribeUserCommandRules()");
651     }
652     return rules;
653 }
654 
655 /* This is similar to ACLDescribeUserCommandRules(), however instead of
656  * describing just the user command rules, everything is described: user
657  * flags, keys, passwords and finally the command rules obtained via
658  * the ACLDescribeUserCommandRules() function. This is the function we call
659  * when we want to rewrite the configuration files describing ACLs and
660  * in order to show users with ACL LIST. */
ACLDescribeUser(user * u)661 sds ACLDescribeUser(user *u) {
662     sds res = sdsempty();
663 
664     /* Flags. */
665     for (int j = 0; ACLUserFlags[j].flag; j++) {
666         /* Skip the allcommands, allkeys and allchannels flags because they'll
667          * be emitted later as +@all, ~* and &*. */
668         if (ACLUserFlags[j].flag == USER_FLAG_ALLKEYS ||
669             ACLUserFlags[j].flag == USER_FLAG_ALLCHANNELS ||
670             ACLUserFlags[j].flag == USER_FLAG_ALLCOMMANDS) continue;
671         if (u->flags & ACLUserFlags[j].flag) {
672             res = sdscat(res,ACLUserFlags[j].name);
673             res = sdscatlen(res," ",1);
674         }
675     }
676 
677     /* Passwords. */
678     listIter li;
679     listNode *ln;
680     listRewind(u->passwords,&li);
681     while((ln = listNext(&li))) {
682         sds thispass = listNodeValue(ln);
683         res = sdscatlen(res,"#",1);
684         res = sdscatsds(res,thispass);
685         res = sdscatlen(res," ",1);
686     }
687 
688     /* Key patterns. */
689     if (u->flags & USER_FLAG_ALLKEYS) {
690         res = sdscatlen(res,"~* ",3);
691     } else {
692         listRewind(u->patterns,&li);
693         while((ln = listNext(&li))) {
694             sds thispat = listNodeValue(ln);
695             res = sdscatlen(res,"~",1);
696             res = sdscatsds(res,thispat);
697             res = sdscatlen(res," ",1);
698         }
699     }
700 
701     /* Pub/sub channel patterns. */
702     if (u->flags & USER_FLAG_ALLCHANNELS) {
703         res = sdscatlen(res,"&* ",3);
704     } else {
705         res = sdscatlen(res,"resetchannels ",14);
706         listRewind(u->channels,&li);
707         while((ln = listNext(&li))) {
708             sds thispat = listNodeValue(ln);
709             res = sdscatlen(res,"&",1);
710             res = sdscatsds(res,thispat);
711             res = sdscatlen(res," ",1);
712         }
713     }
714 
715     /* Command rules. */
716     sds rules = ACLDescribeUserCommandRules(u);
717     res = sdscatsds(res,rules);
718     sdsfree(rules);
719     return res;
720 }
721 
722 /* Get a command from the original command table, that is not affected
723  * by the command renaming operations: we base all the ACL work from that
724  * table, so that ACLs are valid regardless of command renaming. */
ACLLookupCommand(const char * name)725 struct redisCommand *ACLLookupCommand(const char *name) {
726     struct redisCommand *cmd;
727     sds sdsname = sdsnew(name);
728     cmd = lookupCommandBySdsLogic(server.orig_commands,sdsname);
729     sdsfree(sdsname);
730     return cmd;
731 }
732 
733 /* Flush the array of allowed first-args for the specified user
734  * and command ID. */
ACLResetFirstArgsForCommand(user * u,unsigned long id)735 void ACLResetFirstArgsForCommand(user *u, unsigned long id) {
736     if (u->allowed_firstargs && u->allowed_firstargs[id]) {
737         for (int i = 0; u->allowed_firstargs[id][i]; i++)
738             sdsfree(u->allowed_firstargs[id][i]);
739         zfree(u->allowed_firstargs[id]);
740         u->allowed_firstargs[id] = NULL;
741     }
742 }
743 
744 /* Flush the entire table of first-args. This is useful on +@all, -@all
745  * or similar to return back to the minimal memory usage (and checks to do)
746  * for the user. */
ACLResetFirstArgs(user * u)747 void ACLResetFirstArgs(user *u) {
748     if (u->allowed_firstargs == NULL) return;
749     for (int j = 0; j < USER_COMMAND_BITS_COUNT; j++) {
750         if (u->allowed_firstargs[j]) {
751             for (int i = 0; u->allowed_firstargs[j][i]; i++)
752                 sdsfree(u->allowed_firstargs[j][i]);
753             zfree(u->allowed_firstargs[j]);
754         }
755     }
756     zfree(u->allowed_firstargs);
757     u->allowed_firstargs = NULL;
758 }
759 
760 /* Add a first-arh to the list of subcommands for the user 'u' and
761  * the command id specified. */
ACLAddAllowedFirstArg(user * u,unsigned long id,const char * sub)762 void ACLAddAllowedFirstArg(user *u, unsigned long id, const char *sub) {
763     /* If this is the first first-arg to be configured for
764      * this user, we have to allocate the first-args array. */
765     if (u->allowed_firstargs == NULL) {
766         u->allowed_firstargs = zcalloc(USER_COMMAND_BITS_COUNT * sizeof(sds*));
767     }
768 
769     /* We also need to enlarge the allocation pointing to the
770      * null terminated SDS array, to make space for this one.
771      * To start check the current size, and while we are here
772      * make sure the first-arg is not already specified inside. */
773     long items = 0;
774     if (u->allowed_firstargs[id]) {
775         while(u->allowed_firstargs[id][items]) {
776             /* If it's already here do not add it again. */
777             if (!strcasecmp(u->allowed_firstargs[id][items],sub))
778                 return;
779             items++;
780         }
781     }
782 
783     /* Now we can make space for the new item (and the null term). */
784     items += 2;
785     u->allowed_firstargs[id] = zrealloc(u->allowed_firstargs[id], sizeof(sds)*items);
786     u->allowed_firstargs[id][items-2] = sdsnew(sub);
787     u->allowed_firstargs[id][items-1] = NULL;
788 }
789 
790 /* Set user properties according to the string "op". The following
791  * is a description of what different strings will do:
792  *
793  * on           Enable the user: it is possible to authenticate as this user.
794  * off          Disable the user: it's no longer possible to authenticate
795  *              with this user, however the already authenticated connections
796  *              will still work.
797  * +<command>   Allow the execution of that command.
798  *              May be used with `|` for allowing subcommands (e.g "+config|get")
799  * -<command>   Disallow the execution of that command.
800  *              May be used with `|` for blocking subcommands (e.g "-config|set")
801  * +@<category> Allow the execution of all the commands in such category
802  *              with valid categories are like @admin, @set, @sortedset, ...
803  *              and so forth, see the full list in the server.c file where
804  *              the Redis command table is described and defined.
805  *              The special category @all means all the commands, but currently
806  *              present in the server, and that will be loaded in the future
807  *              via modules.
808  * +<command>|first-arg    Allow a specific first argument of an otherwise
809  *                         disabled command. Note that this form is not
810  *                         allowed as negative like -SELECT|1, but
811  *                         only additive starting with "+".
812  * allcommands  Alias for +@all. Note that it implies the ability to execute
813  *              all the future commands loaded via the modules system.
814  * nocommands   Alias for -@all.
815  * ~<pattern>   Add a pattern of keys that can be mentioned as part of
816  *              commands. For instance ~* allows all the keys. The pattern
817  *              is a glob-style pattern like the one of KEYS.
818  *              It is possible to specify multiple patterns.
819  * allkeys      Alias for ~*
820  * resetkeys    Flush the list of allowed keys patterns.
821  * &<pattern>   Add a pattern of channels that can be mentioned as part of
822  *              Pub/Sub commands. For instance &* allows all the channels. The
823  *              pattern is a glob-style pattern like the one of PSUBSCRIBE.
824  *              It is possible to specify multiple patterns.
825  * allchannels              Alias for &*
826  * resetchannels            Flush the list of allowed keys patterns.
827  * ><password>  Add this password to the list of valid password for the user.
828  *              For example >mypass will add "mypass" to the list.
829  *              This directive clears the "nopass" flag (see later).
830  * #<hash>      Add this password hash to the list of valid hashes for
831  *              the user. This is useful if you have previously computed
832  *              the hash, and don't want to store it in plaintext.
833  *              This directive clears the "nopass" flag (see later).
834  * <<password>  Remove this password from the list of valid passwords.
835  * !<hash>      Remove this hashed password from the list of valid passwords.
836  *              This is useful when you want to remove a password just by
837  *              hash without knowing its plaintext version at all.
838  * nopass       All the set passwords of the user are removed, and the user
839  *              is flagged as requiring no password: it means that every
840  *              password will work against this user. If this directive is
841  *              used for the default user, every new connection will be
842  *              immediately authenticated with the default user without
843  *              any explicit AUTH command required. Note that the "resetpass"
844  *              directive will clear this condition.
845  * resetpass    Flush the list of allowed passwords. Moreover removes the
846  *              "nopass" status. After "resetpass" the user has no associated
847  *              passwords and there is no way to authenticate without adding
848  *              some password (or setting it as "nopass" later).
849  * reset        Performs the following actions: resetpass, resetkeys, off,
850  *              -@all. The user returns to the same state it has immediately
851  *              after its creation.
852  *
853  * The 'op' string must be null terminated. The 'oplen' argument should
854  * specify the length of the 'op' string in case the caller requires to pass
855  * binary data (for instance the >password form may use a binary password).
856  * Otherwise the field can be set to -1 and the function will use strlen()
857  * to determine the length.
858  *
859  * The function returns C_OK if the action to perform was understood because
860  * the 'op' string made sense. Otherwise C_ERR is returned if the operation
861  * is unknown or has some syntax error.
862  *
863  * When an error is returned, errno is set to the following values:
864  *
865  * EINVAL: The specified opcode is not understood or the key/channel pattern is
866  *         invalid (contains non allowed characters).
867  * ENOENT: The command name or command category provided with + or - is not
868  *         known.
869  * EEXIST: You are adding a key pattern after "*" was already added. This is
870  *         almost surely an error on the user side.
871  * EISDIR: You are adding a channel pattern after "*" was already added. This is
872  *         almost surely an error on the user side.
873  * ENODEV: The password you are trying to remove from the user does not exist.
874  * EBADMSG: The hash you are trying to add is not a valid hash.
875  */
ACLSetUser(user * u,const char * op,ssize_t oplen)876 int ACLSetUser(user *u, const char *op, ssize_t oplen) {
877     if (oplen == -1) oplen = strlen(op);
878     if (oplen == 0) return C_OK; /* Empty string is a no-operation. */
879     if (!strcasecmp(op,"on")) {
880         u->flags |= USER_FLAG_ENABLED;
881         u->flags &= ~USER_FLAG_DISABLED;
882     } else if (!strcasecmp(op,"off")) {
883         u->flags |= USER_FLAG_DISABLED;
884         u->flags &= ~USER_FLAG_ENABLED;
885     } else if (!strcasecmp(op,"skip-sanitize-payload")) {
886         u->flags |= USER_FLAG_SANITIZE_PAYLOAD_SKIP;
887         u->flags &= ~USER_FLAG_SANITIZE_PAYLOAD;
888     } else if (!strcasecmp(op,"sanitize-payload")) {
889         u->flags &= ~USER_FLAG_SANITIZE_PAYLOAD_SKIP;
890         u->flags |= USER_FLAG_SANITIZE_PAYLOAD;
891     } else if (!strcasecmp(op,"allkeys") ||
892                !strcasecmp(op,"~*"))
893     {
894         u->flags |= USER_FLAG_ALLKEYS;
895         listEmpty(u->patterns);
896     } else if (!strcasecmp(op,"resetkeys")) {
897         u->flags &= ~USER_FLAG_ALLKEYS;
898         listEmpty(u->patterns);
899     } else if (!strcasecmp(op,"allchannels") ||
900                !strcasecmp(op,"&*"))
901     {
902         u->flags |= USER_FLAG_ALLCHANNELS;
903         listEmpty(u->channels);
904     } else if (!strcasecmp(op,"resetchannels")) {
905         u->flags &= ~USER_FLAG_ALLCHANNELS;
906         listEmpty(u->channels);
907     } else if (!strcasecmp(op,"allcommands") ||
908                !strcasecmp(op,"+@all"))
909     {
910         memset(u->allowed_commands,255,sizeof(u->allowed_commands));
911         u->flags |= USER_FLAG_ALLCOMMANDS;
912         ACLResetFirstArgs(u);
913     } else if (!strcasecmp(op,"nocommands") ||
914                !strcasecmp(op,"-@all"))
915     {
916         memset(u->allowed_commands,0,sizeof(u->allowed_commands));
917         u->flags &= ~USER_FLAG_ALLCOMMANDS;
918         ACLResetFirstArgs(u);
919     } else if (!strcasecmp(op,"nopass")) {
920         u->flags |= USER_FLAG_NOPASS;
921         listEmpty(u->passwords);
922     } else if (!strcasecmp(op,"resetpass")) {
923         u->flags &= ~USER_FLAG_NOPASS;
924         listEmpty(u->passwords);
925     } else if (op[0] == '>' || op[0] == '#') {
926         sds newpass;
927         if (op[0] == '>') {
928             newpass = ACLHashPassword((unsigned char*)op+1,oplen-1);
929         } else {
930             if (ACLCheckPasswordHash((unsigned char*)op+1,oplen-1) == C_ERR) {
931                 errno = EBADMSG;
932                 return C_ERR;
933             }
934             newpass = sdsnewlen(op+1,oplen-1);
935         }
936 
937         listNode *ln = listSearchKey(u->passwords,newpass);
938         /* Avoid re-adding the same password multiple times. */
939         if (ln == NULL)
940             listAddNodeTail(u->passwords,newpass);
941         else
942             sdsfree(newpass);
943         u->flags &= ~USER_FLAG_NOPASS;
944     } else if (op[0] == '<' || op[0] == '!') {
945         sds delpass;
946         if (op[0] == '<') {
947             delpass = ACLHashPassword((unsigned char*)op+1,oplen-1);
948         } else {
949             if (ACLCheckPasswordHash((unsigned char*)op+1,oplen-1) == C_ERR) {
950                 errno = EBADMSG;
951                 return C_ERR;
952             }
953             delpass = sdsnewlen(op+1,oplen-1);
954         }
955         listNode *ln = listSearchKey(u->passwords,delpass);
956         sdsfree(delpass);
957         if (ln) {
958             listDelNode(u->passwords,ln);
959         } else {
960             errno = ENODEV;
961             return C_ERR;
962         }
963     } else if (op[0] == '~') {
964         if (u->flags & USER_FLAG_ALLKEYS) {
965             errno = EEXIST;
966             return C_ERR;
967         }
968         if (ACLStringHasSpaces(op+1,oplen-1)) {
969             errno = EINVAL;
970             return C_ERR;
971         }
972         sds newpat = sdsnewlen(op+1,oplen-1);
973         listNode *ln = listSearchKey(u->patterns,newpat);
974         /* Avoid re-adding the same key pattern multiple times. */
975         if (ln == NULL)
976             listAddNodeTail(u->patterns,newpat);
977         else
978             sdsfree(newpat);
979         u->flags &= ~USER_FLAG_ALLKEYS;
980     } else if (op[0] == '&') {
981         if (u->flags & USER_FLAG_ALLCHANNELS) {
982             errno = EISDIR;
983             return C_ERR;
984         }
985         if (ACLStringHasSpaces(op+1,oplen-1)) {
986             errno = EINVAL;
987             return C_ERR;
988         }
989         sds newpat = sdsnewlen(op+1,oplen-1);
990         listNode *ln = listSearchKey(u->channels,newpat);
991         /* Avoid re-adding the same channel pattern multiple times. */
992         if (ln == NULL)
993             listAddNodeTail(u->channels,newpat);
994         else
995             sdsfree(newpat);
996         u->flags &= ~USER_FLAG_ALLCHANNELS;
997     } else if (op[0] == '+' && op[1] != '@') {
998         if (strrchr(op,'|') == NULL) {
999             struct redisCommand *cmd = ACLLookupCommand(op+1);
1000             if (cmd == NULL) {
1001                 errno = ENOENT;
1002                 return C_ERR;
1003             }
1004             ACLChangeCommandPerm(u,cmd,1);
1005         } else {
1006             /* Split the command and subcommand parts. */
1007             char *copy = zstrdup(op+1);
1008             char *sub = strrchr(copy,'|');
1009             sub[0] = '\0';
1010             sub++;
1011 
1012             struct redisCommand *cmd = ACLLookupCommand(copy);
1013 
1014             /* Check if the command exists. We can't check the
1015              * subcommand to see if it is valid. */
1016             if (cmd == NULL) {
1017                 zfree(copy);
1018                 errno = ENOENT;
1019                 return C_ERR;
1020             }
1021 
1022             /* The subcommand cannot be empty, so things like DEBUG|
1023              * are syntax errors of course. */
1024             if (strlen(sub) == 0) {
1025                 zfree(copy);
1026                 errno = EINVAL;
1027                 return C_ERR;
1028             }
1029 
1030             if (cmd->subcommands_dict) {
1031                 /* If user is trying to allow a valid subcommand we can just add its unique ID */
1032                 struct redisCommand *cmd = ACLLookupCommand(op+1);
1033                 if (cmd == NULL) {
1034                     zfree(copy);
1035                     errno = ENOENT;
1036                     return C_ERR;
1037                 }
1038                 ACLChangeCommandPerm(u,cmd,1);
1039             } else {
1040                 /* If user is trying to use the ACL mech to block SELECT except SELECT 0 or
1041                  * block DEBUG except DEBUG OBJECT (DEBUG subcommands are not considered
1042                  * subcommands for now) we use the allowed_firstargs mechanism. */
1043                 struct redisCommand *cmd = ACLLookupCommand(copy);
1044                 if (cmd == NULL) {
1045                     zfree(copy);
1046                     errno = ENOENT;
1047                     return C_ERR;
1048                 }
1049                 /* Add the first-arg to the list of valid ones. */
1050                 ACLAddAllowedFirstArg(u,cmd->id,sub);
1051             }
1052 
1053             zfree(copy);
1054         }
1055     } else if (op[0] == '-' && op[1] != '@') {
1056         struct redisCommand *cmd = ACLLookupCommand(op+1);
1057         if (cmd == NULL) {
1058             errno = ENOENT;
1059             return C_ERR;
1060         }
1061         ACLChangeCommandPerm(u,cmd,0);
1062     } else if ((op[0] == '+' || op[0] == '-') && op[1] == '@') {
1063         int bitval = op[0] == '+' ? 1 : 0;
1064         if (ACLSetUserCommandBitsForCategory(u,op+2,bitval) == C_ERR) {
1065             errno = ENOENT;
1066             return C_ERR;
1067         }
1068     } else if (!strcasecmp(op,"reset")) {
1069         serverAssert(ACLSetUser(u,"resetpass",-1) == C_OK);
1070         serverAssert(ACLSetUser(u,"resetkeys",-1) == C_OK);
1071         serverAssert(ACLSetUser(u,"resetchannels",-1) == C_OK);
1072         if (server.acl_pubsub_default & USER_FLAG_ALLCHANNELS)
1073             serverAssert(ACLSetUser(u,"allchannels",-1) == C_OK);
1074         serverAssert(ACLSetUser(u,"off",-1) == C_OK);
1075         serverAssert(ACLSetUser(u,"sanitize-payload",-1) == C_OK);
1076         serverAssert(ACLSetUser(u,"-@all",-1) == C_OK);
1077     } else {
1078         errno = EINVAL;
1079         return C_ERR;
1080     }
1081     return C_OK;
1082 }
1083 
1084 /* Return a description of the error that occurred in ACLSetUser() according to
1085  * the errno value set by the function on error. */
ACLSetUserStringError(void)1086 const char *ACLSetUserStringError(void) {
1087     const char *errmsg = "Wrong format";
1088     if (errno == ENOENT)
1089         errmsg = "Unknown command or category name in ACL";
1090     else if (errno == EINVAL)
1091         errmsg = "Syntax error";
1092     else if (errno == EEXIST)
1093         errmsg = "Adding a pattern after the * pattern (or the "
1094                  "'allkeys' flag) is not valid and does not have any "
1095                  "effect. Try 'resetkeys' to start with an empty "
1096                  "list of patterns";
1097     else if (errno == EISDIR)
1098         errmsg = "Adding a pattern after the * pattern (or the "
1099                  "'allchannels' flag) is not valid and does not have any "
1100                  "effect. Try 'resetchannels' to start with an empty "
1101                  "list of channels";
1102     else if (errno == ENODEV)
1103         errmsg = "The password you are trying to remove from the user does "
1104                  "not exist";
1105     else if (errno == EBADMSG)
1106         errmsg = "The password hash must be exactly 64 characters and contain "
1107                  "only lowercase hexadecimal characters";
1108     else if (errno == EALREADY)
1109         errmsg = "Duplicate user found. A user can only be defined once in "
1110                  "config files";
1111     return errmsg;
1112 }
1113 
1114 /* Create the default user, this has special permissions. */
ACLCreateDefaultUser(void)1115 user *ACLCreateDefaultUser(void) {
1116     user *new = ACLCreateUser("default",7);
1117     ACLSetUser(new,"+@all",-1);
1118     ACLSetUser(new,"~*",-1);
1119     ACLSetUser(new,"&*",-1);
1120     ACLSetUser(new,"on",-1);
1121     ACLSetUser(new,"nopass",-1);
1122     return new;
1123 }
1124 
1125 /* Initialization of the ACL subsystem. */
ACLInit(void)1126 void ACLInit(void) {
1127     Users = raxNew();
1128     UsersToLoad = listCreate();
1129     listSetMatchMethod(UsersToLoad, ACLListMatchLoadedUser);
1130     ACLLog = listCreate();
1131     DefaultUser = ACLCreateDefaultUser();
1132 }
1133 
1134 /* Check the username and password pair and return C_OK if they are valid,
1135  * otherwise C_ERR is returned and errno is set to:
1136  *
1137  *  EINVAL: if the username-password do not match.
1138  *  ENONENT: if the specified user does not exist at all.
1139  */
ACLCheckUserCredentials(robj * username,robj * password)1140 int ACLCheckUserCredentials(robj *username, robj *password) {
1141     user *u = ACLGetUserByName(username->ptr,sdslen(username->ptr));
1142     if (u == NULL) {
1143         errno = ENOENT;
1144         return C_ERR;
1145     }
1146 
1147     /* Disabled users can't login. */
1148     if (u->flags & USER_FLAG_DISABLED) {
1149         errno = EINVAL;
1150         return C_ERR;
1151     }
1152 
1153     /* If the user is configured to don't require any password, we
1154      * are already fine here. */
1155     if (u->flags & USER_FLAG_NOPASS) return C_OK;
1156 
1157     /* Check all the user passwords for at least one to match. */
1158     listIter li;
1159     listNode *ln;
1160     listRewind(u->passwords,&li);
1161     sds hashed = ACLHashPassword(password->ptr,sdslen(password->ptr));
1162     while((ln = listNext(&li))) {
1163         sds thispass = listNodeValue(ln);
1164         if (!time_independent_strcmp(hashed, thispass)) {
1165             sdsfree(hashed);
1166             return C_OK;
1167         }
1168     }
1169     sdsfree(hashed);
1170 
1171     /* If we reached this point, no password matched. */
1172     errno = EINVAL;
1173     return C_ERR;
1174 }
1175 
1176 /* This is like ACLCheckUserCredentials(), however if the user/pass
1177  * are correct, the connection is put in authenticated state and the
1178  * connection user reference is populated.
1179  *
1180  * The return value is C_OK or C_ERR with the same meaning as
1181  * ACLCheckUserCredentials(). */
ACLAuthenticateUser(client * c,robj * username,robj * password)1182 int ACLAuthenticateUser(client *c, robj *username, robj *password) {
1183     if (ACLCheckUserCredentials(username,password) == C_OK) {
1184         c->authenticated = 1;
1185         c->user = ACLGetUserByName(username->ptr,sdslen(username->ptr));
1186         moduleNotifyUserChanged(c);
1187         return C_OK;
1188     } else {
1189         addACLLogEntry(c,ACL_DENIED_AUTH,(c->flags & CLIENT_MULTI) ? ACL_LOG_CTX_MULTI : ACL_LOG_CTX_TOPLEVEL,0,username->ptr,NULL);
1190         return C_ERR;
1191     }
1192 }
1193 
1194 /* For ACL purposes, every user has a bitmap with the commands that such
1195  * user is allowed to execute. In order to populate the bitmap, every command
1196  * should have an assigned ID (that is used to index the bitmap). This function
1197  * creates such an ID: it uses sequential IDs, reusing the same ID for the same
1198  * command name, so that a command retains the same ID in case of modules that
1199  * are unloaded and later reloaded. */
ACLGetCommandID(const char * cmdname)1200 unsigned long ACLGetCommandID(const char *cmdname) {
1201     sds lowername = sdsnew(cmdname);
1202     sdstolower(lowername);
1203     if (commandId == NULL) commandId = raxNew();
1204     void *id = raxFind(commandId,(unsigned char*)lowername,sdslen(lowername));
1205     if (id != raxNotFound) {
1206         sdsfree(lowername);
1207         return (unsigned long)id;
1208     }
1209     raxInsert(commandId,(unsigned char*)lowername,strlen(lowername),
1210               (void*)nextid,NULL);
1211     sdsfree(lowername);
1212     unsigned long thisid = nextid;
1213     nextid++;
1214 
1215     /* We never assign the last bit in the user commands bitmap structure,
1216      * this way we can later check if this bit is set, understanding if the
1217      * current ACL for the user was created starting with a +@all to add all
1218      * the possible commands and just subtracting other single commands or
1219      * categories, or if, instead, the ACL was created just adding commands
1220      * and command categories from scratch, not allowing future commands by
1221      * default (loaded via modules). This is useful when rewriting the ACLs
1222      * with ACL SAVE. */
1223     if (nextid == USER_COMMAND_BITS_COUNT-1) nextid++;
1224     return thisid;
1225 }
1226 
1227 /* Clear command id table and reset nextid to 0. */
ACLClearCommandID(void)1228 void ACLClearCommandID(void) {
1229     if (commandId) raxFree(commandId);
1230     commandId = NULL;
1231     nextid = 0;
1232 }
1233 
1234 /* Return an username by its name, or NULL if the user does not exist. */
ACLGetUserByName(const char * name,size_t namelen)1235 user *ACLGetUserByName(const char *name, size_t namelen) {
1236     void *myuser = raxFind(Users,(unsigned char*)name,namelen);
1237     if (myuser == raxNotFound) return NULL;
1238     return myuser;
1239 }
1240 
1241 /* Check if the key can be accessed by the client according to
1242  * the ACLs associated with the specified user.
1243  *
1244  * If the user can access the key, ACL_OK is returned, otherwise
1245  * ACL_DENIED_KEY is returned. */
ACLCheckKey(const user * u,const char * key,int keylen)1246 int ACLCheckKey(const user *u, const char *key, int keylen) {
1247     /* If there is no associated user, the connection can run anything. */
1248     if (u == NULL) return ACL_OK;
1249 
1250     /* The user can run any keys */
1251     if (u->flags & USER_FLAG_ALLKEYS) return ACL_OK;
1252 
1253     listIter li;
1254     listNode *ln;
1255     listRewind(u->patterns,&li);
1256 
1257     /* Test this key against every pattern. */
1258     while((ln = listNext(&li))) {
1259         sds pattern = listNodeValue(ln);
1260         size_t plen = sdslen(pattern);
1261         if (stringmatchlen(pattern,plen,key,keylen,0))
1262             return ACL_OK;
1263     }
1264     return ACL_DENIED_KEY;
1265 }
1266 
1267 /* Check if the command is ready to be executed according to the
1268  * ACLs associated with the specified user.
1269  *
1270  * If the user can execute the command ACL_OK is returned, otherwise
1271  * ACL_DENIED_CMD or ACL_DENIED_KEY is returned: the first in case the
1272  * command cannot be executed because the user is not allowed to run such
1273  * command, the second if the command is denied because the user is trying
1274  * to access keys that are not among the specified patterns. */
ACLCheckCommandPerm(const user * u,struct redisCommand * cmd,robj ** argv,int argc,int * keyidxptr)1275 int ACLCheckCommandPerm(const user *u, struct redisCommand *cmd, robj **argv, int argc, int *keyidxptr) {
1276     int ret;
1277     uint64_t id = cmd->id;
1278 
1279     /* If there is no associated user, the connection can run anything. */
1280     if (u == NULL) return ACL_OK;
1281 
1282     /* Check if the user can execute this command or if the command
1283      * doesn't need to be authenticated (hello, auth). */
1284     if (!(u->flags & USER_FLAG_ALLCOMMANDS) && !(cmd->flags & CMD_NO_AUTH))
1285     {
1286         /* If the bit is not set we have to check further, in case the
1287          * command is allowed just with that specific first argument. */
1288         if (ACLGetUserCommandBit(u,id) == 0) {
1289             /* Check if the first argument matches. */
1290             if (argc < 2 ||
1291                 u->allowed_firstargs == NULL ||
1292                 u->allowed_firstargs[id] == NULL)
1293             {
1294                 return ACL_DENIED_CMD;
1295             }
1296 
1297             long subid = 0;
1298             while (1) {
1299                 if (u->allowed_firstargs[id][subid] == NULL)
1300                     return ACL_DENIED_CMD;
1301                 int idx = cmd->parent ? 2 : 1;
1302                 if (!strcasecmp(argv[idx]->ptr,u->allowed_firstargs[id][subid]))
1303                     break; /* First argument match found. Stop here. */
1304                 subid++;
1305             }
1306         }
1307     }
1308 
1309     /* Check if the user can execute commands explicitly touching the keys
1310      * mentioned in the command arguments. */
1311     if (!(u->flags & USER_FLAG_ALLKEYS) &&
1312         (cmd->getkeys_proc || cmd->key_specs_num))
1313     {
1314         getKeysResult result = GETKEYS_RESULT_INIT;
1315         int numkeys = getKeysFromCommand(cmd,argv,argc,&result);
1316         int *keyidx = result.keys;
1317         for (int j = 0; j < numkeys; j++) {
1318             int idx = keyidx[j];
1319             ret = ACLCheckKey(u, argv[idx]->ptr, sdslen(argv[idx]->ptr));
1320             if (ret != ACL_OK) {
1321                 if (keyidxptr) *keyidxptr = keyidx[j];
1322                 getKeysFreeResult(&result);
1323                 return ret;
1324             }
1325         }
1326         getKeysFreeResult(&result);
1327     }
1328 
1329     /* If we survived all the above checks, the user can execute the
1330      * command. */
1331     return ACL_OK;
1332 }
1333 
1334 /* Check if the provided channel is whitelisted by the given allowed channels
1335  * list. Glob-style pattern matching is employed, unless the literal flag is
1336  * set. Returns ACL_OK if access is granted or ACL_DENIED_CHANNEL otherwise. */
ACLCheckPubsubChannelPerm(sds channel,list * allowed,int literal)1337 int ACLCheckPubsubChannelPerm(sds channel, list *allowed, int literal) {
1338     listIter li;
1339     listNode *ln;
1340     size_t clen = sdslen(channel);
1341     int match = 0;
1342 
1343     listRewind(allowed,&li);
1344     while((ln = listNext(&li))) {
1345         sds pattern = listNodeValue(ln);
1346         size_t plen = sdslen(pattern);
1347 
1348         if ((literal && !sdscmp(pattern,channel)) ||
1349             (!literal && stringmatchlen(pattern,plen,channel,clen,0)))
1350         {
1351             match = 1;
1352             break;
1353         }
1354     }
1355     if (!match) {
1356         return ACL_DENIED_CHANNEL;
1357     }
1358     return ACL_OK;
1359 }
1360 
1361 /* Check if the user's existing pub/sub clients violate the ACL pub/sub
1362  * permissions specified via the upcoming argument, and kill them if so. */
ACLKillPubsubClientsIfNeeded(user * u,list * upcoming)1363 void ACLKillPubsubClientsIfNeeded(user *u, list *upcoming) {
1364     listIter li, lpi;
1365     listNode *ln, *lpn;
1366     robj *o;
1367     int kill = 0;
1368 
1369     /* Nothing to kill when the upcoming are a literal super set of the original
1370      * permissions. */
1371     listRewind(u->channels,&li);
1372     while (!kill && ((ln = listNext(&li)) != NULL)) {
1373         sds pattern = listNodeValue(ln);
1374         kill = (ACLCheckPubsubChannelPerm(pattern,upcoming,1) ==
1375                 ACL_DENIED_CHANNEL);
1376     }
1377     if (!kill) return;
1378 
1379     /* Scan all connected clients to find the user's pub/subs. */
1380     listRewind(server.clients,&li);
1381     while ((ln = listNext(&li)) != NULL) {
1382         client *c = listNodeValue(ln);
1383         kill = 0;
1384 
1385         if (c->user == u && getClientType(c) == CLIENT_TYPE_PUBSUB) {
1386             /* Check for pattern violations. */
1387             listRewind(c->pubsub_patterns,&lpi);
1388             while (!kill && ((lpn = listNext(&lpi)) != NULL)) {
1389                 o = lpn->value;
1390                 kill = (ACLCheckPubsubChannelPerm(o->ptr,upcoming,1) ==
1391                         ACL_DENIED_CHANNEL);
1392             }
1393             /* Check for channel violations. */
1394             if (!kill) {
1395                 dictIterator *di = dictGetIterator(c->pubsub_channels);
1396                 dictEntry *de;
1397                 while (!kill && ((de = dictNext(di)) != NULL)) {
1398                     o = dictGetKey(de);
1399                     kill = (ACLCheckPubsubChannelPerm(o->ptr,upcoming,0) ==
1400                             ACL_DENIED_CHANNEL);
1401                 }
1402                 dictReleaseIterator(di);
1403             }
1404 
1405             /* Kill it. */
1406             if (kill) {
1407                 freeClient(c);
1408             }
1409         }
1410     }
1411 }
1412 
1413 /* Check if the pub/sub channels of the command, that's ready to be executed
1414  * according to the ACLs channels associated with the specified user.
1415  *
1416  * idx and count are the index and count of channel arguments from the
1417  * command. The literal argument controls whether the user's ACL channels are
1418  * evaluated as literal values or matched as glob-like patterns.
1419  *
1420  * If the user can execute the command ACL_OK is returned, otherwise
1421  * ACL_DENIED_CHANNEL. */
ACLCheckPubsubPerm(const user * u,robj ** argv,int idx,int count,int literal,int * idxptr)1422 int ACLCheckPubsubPerm(const user *u, robj **argv, int idx, int count, int literal, int *idxptr) {
1423     /* If there is no associated user, the connection can run anything. */
1424     if (u == NULL) return ACL_OK;
1425 
1426     /* Check if the user can access the channels mentioned in the command's
1427      * arguments. */
1428     if (!(u->flags & USER_FLAG_ALLCHANNELS)) {
1429         for (int j = idx; j < idx+count; j++) {
1430             if (ACLCheckPubsubChannelPerm(argv[j]->ptr,u->channels,literal)
1431                 != ACL_OK) {
1432                 if (idxptr) *idxptr = j;
1433                 return ACL_DENIED_CHANNEL;
1434             }
1435         }
1436     }
1437 
1438     /* If we survived all the above checks, the user can execute the
1439      * command. */
1440     return ACL_OK;
1441 
1442 }
1443 
1444 /* Check whether the command is ready to be executed by ACLCheckCommandPerm.
1445  * If check passes, then check whether pub/sub channels of the command is
1446  * ready to be executed by ACLCheckPubsubPerm */
ACLCheckAllUserCommandPerm(const user * u,struct redisCommand * cmd,robj ** argv,int argc,int * idxptr)1447 int ACLCheckAllUserCommandPerm(const user *u, struct redisCommand *cmd, robj **argv, int argc, int *idxptr) {
1448     int acl_retval = ACLCheckCommandPerm(u,cmd,argv,argc,idxptr);
1449     if (acl_retval != ACL_OK)
1450         return acl_retval;
1451     if (cmd->proc == publishCommand)
1452         acl_retval = ACLCheckPubsubPerm(u,argv,1,1,0,idxptr);
1453     else if (cmd->proc == subscribeCommand)
1454         acl_retval = ACLCheckPubsubPerm(u,argv,1,argc-1,0,idxptr);
1455     else if (cmd->proc == psubscribeCommand)
1456         acl_retval = ACLCheckPubsubPerm(u,argv,1,argc-1,1,idxptr);
1457     return acl_retval;
1458 }
1459 
ACLCheckAllPerm(client * c,int * idxptr)1460 int ACLCheckAllPerm(client *c, int *idxptr) {
1461     return ACLCheckAllUserCommandPerm(c->user, c->cmd, c->argv, c->argc, idxptr);
1462 }
1463 
1464 /* =============================================================================
1465  * ACL loading / saving functions
1466  * ==========================================================================*/
1467 
1468 /* Given an argument vector describing a user in the form:
1469  *
1470  *      user <username> ... ACL rules and flags ...
1471  *
1472  * this function validates, and if the syntax is valid, appends
1473  * the user definition to a list for later loading.
1474  *
1475  * The rules are tested for validity and if there obvious syntax errors
1476  * the function returns C_ERR and does nothing, otherwise C_OK is returned
1477  * and the user is appended to the list.
1478  *
1479  * Note that this function cannot stop in case of commands that are not found
1480  * and, in that case, the error will be emitted later, because certain
1481  * commands may be defined later once modules are loaded.
1482  *
1483  * When an error is detected and C_ERR is returned, the function populates
1484  * by reference (if not set to NULL) the argc_err argument with the index
1485  * of the argv vector that caused the error. */
ACLAppendUserForLoading(sds * argv,int argc,int * argc_err)1486 int ACLAppendUserForLoading(sds *argv, int argc, int *argc_err) {
1487     if (argc < 2 || strcasecmp(argv[0],"user")) {
1488         if (argc_err) *argc_err = 0;
1489         return C_ERR;
1490     }
1491 
1492     if (listSearchKey(UsersToLoad, argv[1])) {
1493         if (argc_err) *argc_err = 1;
1494         errno = EALREADY;
1495         return C_ERR;
1496     }
1497 
1498     /* Try to apply the user rules in a fake user to see if they
1499      * are actually valid. */
1500     user *fakeuser = ACLCreateUnlinkedUser();
1501 
1502     for (int j = 2; j < argc; j++) {
1503         if (ACLSetUser(fakeuser,argv[j],sdslen(argv[j])) == C_ERR) {
1504             if (errno != ENOENT) {
1505                 ACLFreeUser(fakeuser);
1506                 if (argc_err) *argc_err = j;
1507                 return C_ERR;
1508             }
1509         }
1510     }
1511 
1512     /* Rules look valid, let's append the user to the list. */
1513     sds *copy = zmalloc(sizeof(sds)*argc);
1514     for (int j = 1; j < argc; j++) copy[j-1] = sdsdup(argv[j]);
1515     copy[argc-1] = NULL;
1516     listAddNodeTail(UsersToLoad,copy);
1517     ACLFreeUser(fakeuser);
1518     return C_OK;
1519 }
1520 
1521 /* This function will load the configured users appended to the server
1522  * configuration via ACLAppendUserForLoading(). On loading errors it will
1523  * log an error and return C_ERR, otherwise C_OK will be returned. */
ACLLoadConfiguredUsers(void)1524 int ACLLoadConfiguredUsers(void) {
1525     listIter li;
1526     listNode *ln;
1527     listRewind(UsersToLoad,&li);
1528     while ((ln = listNext(&li)) != NULL) {
1529         sds *aclrules = listNodeValue(ln);
1530         sds username = aclrules[0];
1531 
1532         if (ACLStringHasSpaces(aclrules[0],sdslen(aclrules[0]))) {
1533             serverLog(LL_WARNING,"Spaces not allowed in ACL usernames");
1534             return C_ERR;
1535         }
1536 
1537         user *u = ACLCreateUser(username,sdslen(username));
1538         if (!u) {
1539             /* Only valid duplicate user is the default one. */
1540             serverAssert(!strcmp(username, "default"));
1541             u = ACLGetUserByName("default",7);
1542             ACLSetUser(u,"reset",-1);
1543         }
1544 
1545         /* Load every rule defined for this user. */
1546         for (int j = 1; aclrules[j]; j++) {
1547             if (ACLSetUser(u,aclrules[j],sdslen(aclrules[j])) != C_OK) {
1548                 const char *errmsg = ACLSetUserStringError();
1549                 serverLog(LL_WARNING,"Error loading ACL rule '%s' for "
1550                                      "the user named '%s': %s",
1551                           aclrules[j],aclrules[0],errmsg);
1552                 return C_ERR;
1553             }
1554         }
1555 
1556         /* Having a disabled user in the configuration may be an error,
1557          * warn about it without returning any error to the caller. */
1558         if (u->flags & USER_FLAG_DISABLED) {
1559             serverLog(LL_NOTICE, "The user '%s' is disabled (there is no "
1560                                  "'on' modifier in the user description). Make "
1561                                  "sure this is not a configuration error.",
1562                       aclrules[0]);
1563         }
1564     }
1565     return C_OK;
1566 }
1567 
1568 /* This function loads the ACL from the specified filename: every line
1569  * is validated and should be either empty or in the format used to specify
1570  * users in the redis.conf configuration or in the ACL file, that is:
1571  *
1572  *  user <username> ... rules ...
1573  *
1574  * Note that this function considers comments starting with '#' as errors
1575  * because the ACL file is meant to be rewritten, and comments would be
1576  * lost after the rewrite. Yet empty lines are allowed to avoid being too
1577  * strict.
1578  *
1579  * One important part of implementing ACL LOAD, that uses this function, is
1580  * to avoid ending with broken rules if the ACL file is invalid for some
1581  * reason, so the function will attempt to validate the rules before loading
1582  * each user. For every line that will be found broken the function will
1583  * collect an error message.
1584  *
1585  * IMPORTANT: If there is at least a single error, nothing will be loaded
1586  * and the rules will remain exactly as they were.
1587  *
1588  * At the end of the process, if no errors were found in the whole file then
1589  * NULL is returned. Otherwise an SDS string describing in a single line
1590  * a description of all the issues found is returned. */
ACLLoadFromFile(const char * filename)1591 sds ACLLoadFromFile(const char *filename) {
1592     FILE *fp;
1593     char buf[1024];
1594 
1595     /* Open the ACL file. */
1596     if ((fp = fopen(filename,"r")) == NULL) {
1597         sds errors = sdscatprintf(sdsempty(),
1598             "Error loading ACLs, opening file '%s': %s",
1599             filename, strerror(errno));
1600         return errors;
1601     }
1602 
1603     /* Load the whole file as a single string in memory. */
1604     sds acls = sdsempty();
1605     while(fgets(buf,sizeof(buf),fp) != NULL)
1606         acls = sdscat(acls,buf);
1607     fclose(fp);
1608 
1609     /* Split the file into lines and attempt to load each line. */
1610     int totlines;
1611     sds *lines, errors = sdsempty();
1612     lines = sdssplitlen(acls,strlen(acls),"\n",1,&totlines);
1613     sdsfree(acls);
1614 
1615     /* We do all the loading in a fresh instance of the Users radix tree,
1616      * so if there are errors loading the ACL file we can rollback to the
1617      * old version. */
1618     rax *old_users = Users;
1619     Users = raxNew();
1620 
1621     /* Load each line of the file. */
1622     for (int i = 0; i < totlines; i++) {
1623         sds *argv;
1624         int argc;
1625         int linenum = i+1;
1626 
1627         lines[i] = sdstrim(lines[i]," \t\r\n");
1628 
1629         /* Skip blank lines */
1630         if (lines[i][0] == '\0') continue;
1631 
1632         /* Split into arguments */
1633         argv = sdssplitlen(lines[i],sdslen(lines[i])," ",1,&argc);
1634         if (argv == NULL) {
1635             errors = sdscatprintf(errors,
1636                      "%s:%d: unbalanced quotes in acl line. ",
1637                      server.acl_filename, linenum);
1638             continue;
1639         }
1640 
1641         /* Skip this line if the resulting command vector is empty. */
1642         if (argc == 0) {
1643             sdsfreesplitres(argv,argc);
1644             continue;
1645         }
1646 
1647         /* The line should start with the "user" keyword. */
1648         if (strcmp(argv[0],"user") || argc < 2) {
1649             errors = sdscatprintf(errors,
1650                      "%s:%d should start with user keyword followed "
1651                      "by the username. ", server.acl_filename,
1652                      linenum);
1653             sdsfreesplitres(argv,argc);
1654             continue;
1655         }
1656 
1657         /* Spaces are not allowed in usernames. */
1658         if (ACLStringHasSpaces(argv[1],sdslen(argv[1]))) {
1659             errors = sdscatprintf(errors,
1660                      "'%s:%d: username '%s' contains invalid characters. ",
1661                      server.acl_filename, linenum, argv[1]);
1662             sdsfreesplitres(argv,argc);
1663             continue;
1664         }
1665 
1666         user *u = ACLCreateUser(argv[1],sdslen(argv[1]));
1667 
1668         /* If the user already exists we assume it's an error and abort. */
1669         if (!u) {
1670             errors = sdscatprintf(errors,"WARNING: Duplicate user '%s' found on line %d. ", argv[1], linenum);
1671             sdsfreesplitres(argv,argc);
1672             continue;
1673         }
1674 
1675         /* Finally process the options and validate they can
1676          * be cleanly applied to the user. If any option fails
1677          * to apply, the other values won't be applied since
1678          * all the pending changes will get dropped. */
1679         int j;
1680         for (j = 2; j < argc; j++) {
1681             argv[j] = sdstrim(argv[j],"\t\r\n");
1682             if (ACLSetUser(u,argv[j],sdslen(argv[j])) != C_OK) {
1683                 const char *errmsg = ACLSetUserStringError();
1684                 errors = sdscatprintf(errors,
1685                          "%s:%d: %s. ",
1686                          server.acl_filename, linenum, errmsg);
1687                 continue;
1688             }
1689         }
1690 
1691         /* Apply the rule to the new users set only if so far there
1692          * are no errors, otherwise it's useless since we are going
1693          * to discard the new users set anyway. */
1694         if (sdslen(errors) != 0) {
1695             sdsfreesplitres(argv,argc);
1696             continue;
1697         }
1698 
1699         sdsfreesplitres(argv,argc);
1700     }
1701 
1702     sdsfreesplitres(lines,totlines);
1703 
1704     /* Check if we found errors and react accordingly. */
1705     if (sdslen(errors) == 0) {
1706         /* The default user pointer is referenced in different places: instead
1707          * of replacing such occurrences it is much simpler to copy the new
1708          * default user configuration in the old one. */
1709         user *new_default = ACLGetUserByName("default",7);
1710         if (!new_default) {
1711             new_default = ACLCreateDefaultUser();
1712         }
1713 
1714         ACLCopyUser(DefaultUser,new_default);
1715         ACLFreeUser(new_default);
1716         raxInsert(Users,(unsigned char*)"default",7,DefaultUser,NULL);
1717         raxRemove(old_users,(unsigned char*)"default",7,NULL);
1718         ACLFreeUsersSet(old_users);
1719         sdsfree(errors);
1720         return NULL;
1721     } else {
1722         ACLFreeUsersSet(Users);
1723         Users = old_users;
1724         errors = sdscat(errors,"WARNING: ACL errors detected, no change to the previously active ACL rules was performed");
1725         return errors;
1726     }
1727 }
1728 
1729 /* Generate a copy of the ACLs currently in memory in the specified filename.
1730  * Returns C_OK on success or C_ERR if there was an error during the I/O.
1731  * When C_ERR is returned a log is produced with hints about the issue. */
ACLSaveToFile(const char * filename)1732 int ACLSaveToFile(const char *filename) {
1733     sds acl = sdsempty();
1734     int fd = -1;
1735     sds tmpfilename = NULL;
1736     int retval = C_ERR;
1737 
1738     /* Let's generate an SDS string containing the new version of the
1739      * ACL file. */
1740     raxIterator ri;
1741     raxStart(&ri,Users);
1742     raxSeek(&ri,"^",NULL,0);
1743     while(raxNext(&ri)) {
1744         user *u = ri.data;
1745         /* Return information in the configuration file format. */
1746         sds user = sdsnew("user ");
1747         user = sdscatsds(user,u->name);
1748         user = sdscatlen(user," ",1);
1749         sds descr = ACLDescribeUser(u);
1750         user = sdscatsds(user,descr);
1751         sdsfree(descr);
1752         acl = sdscatsds(acl,user);
1753         acl = sdscatlen(acl,"\n",1);
1754         sdsfree(user);
1755     }
1756     raxStop(&ri);
1757 
1758     /* Create a temp file with the new content. */
1759     tmpfilename = sdsnew(filename);
1760     tmpfilename = sdscatfmt(tmpfilename,".tmp-%i-%I",
1761         (int)getpid(),(int)mstime());
1762     if ((fd = open(tmpfilename,O_WRONLY|O_CREAT,0644)) == -1) {
1763         serverLog(LL_WARNING,"Opening temp ACL file for ACL SAVE: %s",
1764             strerror(errno));
1765         goto cleanup;
1766     }
1767 
1768     /* Write it. */
1769     if (write(fd,acl,sdslen(acl)) != (ssize_t)sdslen(acl)) {
1770         serverLog(LL_WARNING,"Writing ACL file for ACL SAVE: %s",
1771             strerror(errno));
1772         goto cleanup;
1773     }
1774     close(fd); fd = -1;
1775 
1776     /* Let's replace the new file with the old one. */
1777     if (rename(tmpfilename,filename) == -1) {
1778         serverLog(LL_WARNING,"Renaming ACL file for ACL SAVE: %s",
1779             strerror(errno));
1780         goto cleanup;
1781     }
1782     sdsfree(tmpfilename); tmpfilename = NULL;
1783     retval = C_OK; /* If we reached this point, everything is fine. */
1784 
1785 cleanup:
1786     if (fd != -1) close(fd);
1787     if (tmpfilename) unlink(tmpfilename);
1788     sdsfree(tmpfilename);
1789     sdsfree(acl);
1790     return retval;
1791 }
1792 
1793 /* This function is called once the server is already running, modules are
1794  * loaded, and we are ready to start, in order to load the ACLs either from
1795  * the pending list of users defined in redis.conf, or from the ACL file.
1796  * The function will just exit with an error if the user is trying to mix
1797  * both the loading methods. */
ACLLoadUsersAtStartup(void)1798 void ACLLoadUsersAtStartup(void) {
1799     if (server.acl_filename[0] != '\0' && listLength(UsersToLoad) != 0) {
1800         serverLog(LL_WARNING,
1801             "Configuring Redis with users defined in redis.conf and at "
1802             "the same setting an ACL file path is invalid. This setup "
1803             "is very likely to lead to configuration errors and security "
1804             "holes, please define either an ACL file or declare users "
1805             "directly in your redis.conf, but not both.");
1806         exit(1);
1807     }
1808 
1809     if (ACLLoadConfiguredUsers() == C_ERR) {
1810         serverLog(LL_WARNING,
1811             "Critical error while loading ACLs. Exiting.");
1812         exit(1);
1813     }
1814 
1815     if (server.acl_filename[0] != '\0') {
1816         sds errors = ACLLoadFromFile(server.acl_filename);
1817         if (errors) {
1818             serverLog(LL_WARNING,
1819                 "Aborting Redis startup because of ACL errors: %s", errors);
1820             sdsfree(errors);
1821             exit(1);
1822         }
1823     }
1824 }
1825 
1826 /* =============================================================================
1827  * ACL log
1828  * ==========================================================================*/
1829 
1830 #define ACL_LOG_GROUPING_MAX_TIME_DELTA 60000
1831 
1832 /* This structure defines an entry inside the ACL log. */
1833 typedef struct ACLLogEntry {
1834     uint64_t count;     /* Number of times this happened recently. */
1835     int reason;         /* Reason for denying the command. ACL_DENIED_*. */
1836     int context;        /* Toplevel, Lua or MULTI/EXEC? ACL_LOG_CTX_*. */
1837     sds object;         /* The key name or command name. */
1838     sds username;       /* User the client is authenticated with. */
1839     mstime_t ctime;     /* Milliseconds time of last update to this entry. */
1840     sds cinfo;          /* Client info (last client if updated). */
1841 } ACLLogEntry;
1842 
1843 /* This function will check if ACL entries 'a' and 'b' are similar enough
1844  * that we should actually update the existing entry in our ACL log instead
1845  * of creating a new one. */
ACLLogMatchEntry(ACLLogEntry * a,ACLLogEntry * b)1846 int ACLLogMatchEntry(ACLLogEntry *a, ACLLogEntry *b) {
1847     if (a->reason != b->reason) return 0;
1848     if (a->context != b->context) return 0;
1849     mstime_t delta = a->ctime - b->ctime;
1850     if (delta < 0) delta = -delta;
1851     if (delta > ACL_LOG_GROUPING_MAX_TIME_DELTA) return 0;
1852     if (sdscmp(a->object,b->object) != 0) return 0;
1853     if (sdscmp(a->username,b->username) != 0) return 0;
1854     return 1;
1855 }
1856 
1857 /* Release an ACL log entry. */
ACLFreeLogEntry(void * leptr)1858 void ACLFreeLogEntry(void *leptr) {
1859     ACLLogEntry *le = leptr;
1860     sdsfree(le->object);
1861     sdsfree(le->username);
1862     sdsfree(le->cinfo);
1863     zfree(le);
1864 }
1865 
1866 /* Adds a new entry in the ACL log, making sure to delete the old entry
1867  * if we reach the maximum length allowed for the log. This function attempts
1868  * to find similar entries in the current log in order to bump the counter of
1869  * the log entry instead of creating many entries for very similar ACL
1870  * rules issues.
1871  *
1872  * The argpos argument is used when the reason is ACL_DENIED_KEY or
1873  * ACL_DENIED_CHANNEL, since it allows the function to log the key or channel
1874  * name that caused the problem.
1875  *
1876  * The last 2 arguments are a manual override to be used, instead of any of the automatic
1877  * ones which depend on the client and reason arguments (use NULL for default).
1878  */
addACLLogEntry(client * c,int reason,int context,int argpos,sds username,sds object)1879 void addACLLogEntry(client *c, int reason, int context, int argpos, sds username, sds object) {
1880     /* Create a new entry. */
1881     struct ACLLogEntry *le = zmalloc(sizeof(*le));
1882     le->count = 1;
1883     le->reason = reason;
1884     le->username = sdsdup(username ? username : c->user->name);
1885     le->ctime = mstime();
1886 
1887     if (object) {
1888         le->object = sdsnew(object);
1889     } else {
1890         switch(reason) {
1891             case ACL_DENIED_CMD: le->object = sdsnew(c->cmd->name); break;
1892             case ACL_DENIED_KEY: le->object = sdsdup(c->argv[argpos]->ptr); break;
1893             case ACL_DENIED_CHANNEL: le->object = sdsdup(c->argv[argpos]->ptr); break;
1894             case ACL_DENIED_AUTH: le->object = sdsdup(c->argv[0]->ptr); break;
1895             default: le->object = sdsempty();
1896         }
1897     }
1898 
1899     client *realclient = c;
1900     if (realclient->flags & CLIENT_LUA) realclient = server.lua_caller;
1901 
1902     le->cinfo = catClientInfoString(sdsempty(),realclient);
1903     le->context = context;
1904 
1905     /* Try to match this entry with past ones, to see if we can just
1906      * update an existing entry instead of creating a new one. */
1907     long toscan = 10; /* Do a limited work trying to find duplicated. */
1908     listIter li;
1909     listNode *ln;
1910     listRewind(ACLLog,&li);
1911     ACLLogEntry *match = NULL;
1912     while (toscan-- && (ln = listNext(&li)) != NULL) {
1913         ACLLogEntry *current = listNodeValue(ln);
1914         if (ACLLogMatchEntry(current,le)) {
1915             match = current;
1916             listDelNode(ACLLog,ln);
1917             listAddNodeHead(ACLLog,current);
1918             break;
1919         }
1920     }
1921 
1922     /* If there is a match update the entry, otherwise add it as a
1923      * new one. */
1924     if (match) {
1925         /* We update a few fields of the existing entry and bump the
1926          * counter of events for this entry. */
1927         sdsfree(match->cinfo);
1928         match->cinfo = le->cinfo;
1929         match->ctime = le->ctime;
1930         match->count++;
1931 
1932         /* Release the old entry. */
1933         le->cinfo = NULL;
1934         ACLFreeLogEntry(le);
1935     } else {
1936         /* Add it to our list of entries. We'll have to trim the list
1937          * to its maximum size. */
1938         listAddNodeHead(ACLLog, le);
1939         while(listLength(ACLLog) > server.acllog_max_len) {
1940             listNode *ln = listLast(ACLLog);
1941             ACLLogEntry *le = listNodeValue(ln);
1942             ACLFreeLogEntry(le);
1943             listDelNode(ACLLog,ln);
1944         }
1945     }
1946 }
1947 
1948 /* =============================================================================
1949  * ACL related commands
1950  * ==========================================================================*/
1951 
1952 /* ACL -- show and modify the configuration of ACL users.
1953  * ACL HELP
1954  * ACL LOAD
1955  * ACL SAVE
1956  * ACL LIST
1957  * ACL USERS
1958  * ACL CAT [<category>]
1959  * ACL SETUSER <username> ... acl rules ...
1960  * ACL DELUSER <username> [...]
1961  * ACL GETUSER <username>
1962  * ACL GENPASS [<bits>]
1963  * ACL WHOAMI
1964  * ACL LOG [<count> | RESET]
1965  */
aclCommand(client * c)1966 void aclCommand(client *c) {
1967     char *sub = c->argv[1]->ptr;
1968     if (!strcasecmp(sub,"setuser") && c->argc >= 3) {
1969         sds username = c->argv[2]->ptr;
1970         /* Check username validity. */
1971         if (ACLStringHasSpaces(username,sdslen(username))) {
1972             addReplyErrorFormat(c,
1973                 "Usernames can't contain spaces or null characters");
1974             return;
1975         }
1976 
1977         /* Create a temporary user to validate and stage all changes against
1978          * before applying to an existing user or creating a new user. If all
1979          * arguments are valid the user parameters will all be applied together.
1980          * If there are any errors then none of the changes will be applied. */
1981         user *tempu = ACLCreateUnlinkedUser();
1982         user *u = ACLGetUserByName(username,sdslen(username));
1983         if (u) ACLCopyUser(tempu, u);
1984 
1985         /* Initially redact all of the arguments to not leak any information
1986          * about the user. */
1987         for (int j = 2; j < c->argc; j++) {
1988             redactClientCommandArgument(c, j);
1989         }
1990 
1991         for (int j = 3; j < c->argc; j++) {
1992             if (ACLSetUser(tempu,c->argv[j]->ptr,sdslen(c->argv[j]->ptr)) != C_OK) {
1993                 const char *errmsg = ACLSetUserStringError();
1994                 addReplyErrorFormat(c,
1995                     "Error in ACL SETUSER modifier '%s': %s",
1996                     (char*)c->argv[j]->ptr, errmsg);
1997 
1998                 ACLFreeUser(tempu);
1999                 return;
2000             }
2001         }
2002 
2003         /* Existing pub/sub clients authenticated with the user may need to be
2004          * disconnected if (some of) their channel permissions were revoked. */
2005         if (u && !(tempu->flags & USER_FLAG_ALLCHANNELS))
2006             ACLKillPubsubClientsIfNeeded(u,tempu->channels);
2007 
2008         /* Overwrite the user with the temporary user we modified above. */
2009         if (!u) u = ACLCreateUser(username,sdslen(username));
2010         serverAssert(u != NULL);
2011         ACLCopyUser(u, tempu);
2012         ACLFreeUser(tempu);
2013         addReply(c,shared.ok);
2014     } else if (!strcasecmp(sub,"deluser") && c->argc >= 3) {
2015         int deleted = 0;
2016         for (int j = 2; j < c->argc; j++) {
2017             sds username = c->argv[j]->ptr;
2018             if (!strcmp(username,"default")) {
2019                 addReplyError(c,"The 'default' user cannot be removed");
2020                 return;
2021             }
2022         }
2023 
2024         for (int j = 2; j < c->argc; j++) {
2025             sds username = c->argv[j]->ptr;
2026             user *u;
2027             if (raxRemove(Users,(unsigned char*)username,
2028                           sdslen(username),
2029                           (void**)&u))
2030             {
2031                 ACLFreeUserAndKillClients(u);
2032                 deleted++;
2033             }
2034         }
2035         addReplyLongLong(c,deleted);
2036     } else if (!strcasecmp(sub,"getuser") && c->argc == 3) {
2037         user *u = ACLGetUserByName(c->argv[2]->ptr,sdslen(c->argv[2]->ptr));
2038         if (u == NULL) {
2039             addReplyNull(c);
2040             return;
2041         }
2042 
2043         addReplyMapLen(c,5);
2044 
2045         /* Flags */
2046         addReplyBulkCString(c,"flags");
2047         void *deflen = addReplyDeferredLen(c);
2048         int numflags = 0;
2049         for (int j = 0; ACLUserFlags[j].flag; j++) {
2050             if (u->flags & ACLUserFlags[j].flag) {
2051                 addReplyBulkCString(c,ACLUserFlags[j].name);
2052                 numflags++;
2053             }
2054         }
2055         setDeferredSetLen(c,deflen,numflags);
2056 
2057         /* Passwords */
2058         addReplyBulkCString(c,"passwords");
2059         addReplyArrayLen(c,listLength(u->passwords));
2060         listIter li;
2061         listNode *ln;
2062         listRewind(u->passwords,&li);
2063         while((ln = listNext(&li))) {
2064             sds thispass = listNodeValue(ln);
2065             addReplyBulkCBuffer(c,thispass,sdslen(thispass));
2066         }
2067 
2068         /* Commands */
2069         addReplyBulkCString(c,"commands");
2070         sds cmddescr = ACLDescribeUserCommandRules(u);
2071         addReplyBulkSds(c,cmddescr);
2072 
2073         /* Key patterns */
2074         addReplyBulkCString(c,"keys");
2075         if (u->flags & USER_FLAG_ALLKEYS) {
2076             addReplyArrayLen(c,1);
2077             addReplyBulkCBuffer(c,"*",1);
2078         } else {
2079             addReplyArrayLen(c,listLength(u->patterns));
2080             listIter li;
2081             listNode *ln;
2082             listRewind(u->patterns,&li);
2083             while((ln = listNext(&li))) {
2084                 sds thispat = listNodeValue(ln);
2085                 addReplyBulkCBuffer(c,thispat,sdslen(thispat));
2086             }
2087         }
2088 
2089         /* Pub/sub patterns */
2090         addReplyBulkCString(c,"channels");
2091         if (u->flags & USER_FLAG_ALLCHANNELS) {
2092             addReplyArrayLen(c,1);
2093             addReplyBulkCBuffer(c,"*",1);
2094         } else {
2095             addReplyArrayLen(c,listLength(u->channels));
2096             listIter li;
2097             listNode *ln;
2098             listRewind(u->channels,&li);
2099             while((ln = listNext(&li))) {
2100                 sds thispat = listNodeValue(ln);
2101                 addReplyBulkCBuffer(c,thispat,sdslen(thispat));
2102             }
2103         }
2104     } else if ((!strcasecmp(sub,"list") || !strcasecmp(sub,"users")) &&
2105                c->argc == 2)
2106     {
2107         int justnames = !strcasecmp(sub,"users");
2108         addReplyArrayLen(c,raxSize(Users));
2109         raxIterator ri;
2110         raxStart(&ri,Users);
2111         raxSeek(&ri,"^",NULL,0);
2112         while(raxNext(&ri)) {
2113             user *u = ri.data;
2114             if (justnames) {
2115                 addReplyBulkCBuffer(c,u->name,sdslen(u->name));
2116             } else {
2117                 /* Return information in the configuration file format. */
2118                 sds config = sdsnew("user ");
2119                 config = sdscatsds(config,u->name);
2120                 config = sdscatlen(config," ",1);
2121                 sds descr = ACLDescribeUser(u);
2122                 config = sdscatsds(config,descr);
2123                 sdsfree(descr);
2124                 addReplyBulkSds(c,config);
2125             }
2126         }
2127         raxStop(&ri);
2128     } else if (!strcasecmp(sub,"whoami") && c->argc == 2) {
2129         if (c->user != NULL) {
2130             addReplyBulkCBuffer(c,c->user->name,sdslen(c->user->name));
2131         } else {
2132             addReplyNull(c);
2133         }
2134     } else if (server.acl_filename[0] == '\0' &&
2135                (!strcasecmp(sub,"load") || !strcasecmp(sub,"save")))
2136     {
2137         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.");
2138         return;
2139     } else if (!strcasecmp(sub,"load") && c->argc == 2) {
2140         sds errors = ACLLoadFromFile(server.acl_filename);
2141         if (errors == NULL) {
2142             addReply(c,shared.ok);
2143         } else {
2144             addReplyError(c,errors);
2145             sdsfree(errors);
2146         }
2147     } else if (!strcasecmp(sub,"save") && c->argc == 2) {
2148         if (ACLSaveToFile(server.acl_filename) == C_OK) {
2149             addReply(c,shared.ok);
2150         } else {
2151             addReplyError(c,"There was an error trying to save the ACLs. "
2152                             "Please check the server logs for more "
2153                             "information");
2154         }
2155     } else if (!strcasecmp(sub,"cat") && c->argc == 2) {
2156         void *dl = addReplyDeferredLen(c);
2157         int j;
2158         for (j = 0; ACLCommandCategories[j].flag != 0; j++)
2159             addReplyBulkCString(c,ACLCommandCategories[j].name);
2160         setDeferredArrayLen(c,dl,j);
2161     } else if (!strcasecmp(sub,"cat") && c->argc == 3) {
2162         uint64_t cflag = ACLGetCommandCategoryFlagByName(c->argv[2]->ptr);
2163         if (cflag == 0) {
2164             addReplyErrorFormat(c, "Unknown category '%s'", (char*)c->argv[2]->ptr);
2165             return;
2166         }
2167         int arraylen = 0;
2168         void *dl = addReplyDeferredLen(c);
2169         dictIterator *di = dictGetIterator(server.orig_commands);
2170         dictEntry *de;
2171         while ((de = dictNext(di)) != NULL) {
2172             struct redisCommand *cmd = dictGetVal(de);
2173             if (cmd->flags & CMD_MODULE) continue;
2174             if (cmd->flags & cflag) {
2175                 addReplyBulkCString(c,cmd->name);
2176                 arraylen++;
2177             }
2178         }
2179         dictReleaseIterator(di);
2180         setDeferredArrayLen(c,dl,arraylen);
2181     } else if (!strcasecmp(sub,"genpass") && (c->argc == 2 || c->argc == 3)) {
2182         #define GENPASS_MAX_BITS 4096
2183         char pass[GENPASS_MAX_BITS/8*2]; /* Hex representation. */
2184         long bits = 256; /* By default generate 256 bits passwords. */
2185 
2186         if (c->argc == 3 && getLongFromObjectOrReply(c,c->argv[2],&bits,NULL)
2187             != C_OK) return;
2188 
2189         if (bits <= 0 || bits > GENPASS_MAX_BITS) {
2190             addReplyErrorFormat(c,
2191                 "ACL GENPASS argument must be the number of "
2192                 "bits for the output password, a positive number "
2193                 "up to %d",GENPASS_MAX_BITS);
2194             return;
2195         }
2196 
2197         long chars = (bits+3)/4; /* Round to number of characters to emit. */
2198         getRandomHexChars(pass,chars);
2199         addReplyBulkCBuffer(c,pass,chars);
2200     } else if (!strcasecmp(sub,"log") && (c->argc == 2 || c->argc ==3)) {
2201         long count = 10; /* Number of entries to emit by default. */
2202 
2203         /* Parse the only argument that LOG may have: it could be either
2204          * the number of entries the user wants to display, or alternatively
2205          * the "RESET" command in order to flush the old entries. */
2206         if (c->argc == 3) {
2207             if (!strcasecmp(c->argv[2]->ptr,"reset")) {
2208                 listSetFreeMethod(ACLLog,ACLFreeLogEntry);
2209                 listEmpty(ACLLog);
2210                 listSetFreeMethod(ACLLog,NULL);
2211                 addReply(c,shared.ok);
2212                 return;
2213             } else if (getLongFromObjectOrReply(c,c->argv[2],&count,NULL)
2214                        != C_OK)
2215             {
2216                 return;
2217             }
2218             if (count < 0) count = 0;
2219         }
2220 
2221         /* Fix the count according to the number of entries we got. */
2222         if ((size_t)count > listLength(ACLLog))
2223             count = listLength(ACLLog);
2224 
2225         addReplyArrayLen(c,count);
2226         listIter li;
2227         listNode *ln;
2228         listRewind(ACLLog,&li);
2229         mstime_t now = mstime();
2230         while (count-- && (ln = listNext(&li)) != NULL) {
2231             ACLLogEntry *le = listNodeValue(ln);
2232             addReplyMapLen(c,7);
2233             addReplyBulkCString(c,"count");
2234             addReplyLongLong(c,le->count);
2235 
2236             addReplyBulkCString(c,"reason");
2237             char *reasonstr;
2238             switch(le->reason) {
2239             case ACL_DENIED_CMD: reasonstr="command"; break;
2240             case ACL_DENIED_KEY: reasonstr="key"; break;
2241             case ACL_DENIED_CHANNEL: reasonstr="channel"; break;
2242             case ACL_DENIED_AUTH: reasonstr="auth"; break;
2243             default: reasonstr="unknown";
2244             }
2245             addReplyBulkCString(c,reasonstr);
2246 
2247             addReplyBulkCString(c,"context");
2248             char *ctxstr;
2249             switch(le->context) {
2250             case ACL_LOG_CTX_TOPLEVEL: ctxstr="toplevel"; break;
2251             case ACL_LOG_CTX_MULTI: ctxstr="multi"; break;
2252             case ACL_LOG_CTX_LUA: ctxstr="lua"; break;
2253             case ACL_LOG_CTX_MODULE: ctxstr="module"; break;
2254             default: ctxstr="unknown";
2255             }
2256             addReplyBulkCString(c,ctxstr);
2257 
2258             addReplyBulkCString(c,"object");
2259             addReplyBulkCBuffer(c,le->object,sdslen(le->object));
2260             addReplyBulkCString(c,"username");
2261             addReplyBulkCBuffer(c,le->username,sdslen(le->username));
2262             addReplyBulkCString(c,"age-seconds");
2263             double age = (double)(now - le->ctime)/1000;
2264             addReplyDouble(c,age);
2265             addReplyBulkCString(c,"client-info");
2266             addReplyBulkCBuffer(c,le->cinfo,sdslen(le->cinfo));
2267         }
2268     } else if (c->argc == 2 && !strcasecmp(sub,"help")) {
2269         const char *help[] = {
2270 "CAT [<category>]",
2271 "    List all commands that belong to <category>, or all command categories",
2272 "    when no category is specified.",
2273 "DELUSER <username> [<username> ...]",
2274 "    Delete a list of users.",
2275 "GETUSER <username>",
2276 "    Get the user's details.",
2277 "GENPASS [<bits>]",
2278 "    Generate a secure 256-bit user password. The optional `bits` argument can",
2279 "    be used to specify a different size.",
2280 "LIST",
2281 "    Show users details in config file format.",
2282 "LOAD",
2283 "    Reload users from the ACL file.",
2284 "LOG [<count> | RESET]",
2285 "    Show the ACL log entries.",
2286 "SAVE",
2287 "    Save the current config to the ACL file.",
2288 "SETUSER <username> <attribute> [<attribute> ...]",
2289 "    Create or modify a user with the specified attributes.",
2290 "USERS",
2291 "    List all the registered usernames.",
2292 "WHOAMI",
2293 "    Return the current connection username.",
2294 NULL
2295         };
2296         addReplyHelp(c,help);
2297     } else {
2298         addReplySubcommandSyntaxError(c);
2299     }
2300 }
2301 
addReplyCommandCategories(client * c,struct redisCommand * cmd)2302 void addReplyCommandCategories(client *c, struct redisCommand *cmd) {
2303     int flagcount = 0;
2304     void *flaglen = addReplyDeferredLen(c);
2305     for (int j = 0; ACLCommandCategories[j].flag != 0; j++) {
2306         if (cmd->flags & ACLCommandCategories[j].flag) {
2307             addReplyStatusFormat(c, "@%s", ACLCommandCategories[j].name);
2308             flagcount++;
2309         }
2310     }
2311     setDeferredSetLen(c, flaglen, flagcount);
2312 }
2313 
2314 /* AUTH <password>
2315  * AUTH <username> <password> (Redis >= 6.0 form)
2316  *
2317  * When the user is omitted it means that we are trying to authenticate
2318  * against the default user. */
authCommand(client * c)2319 void authCommand(client *c) {
2320     /* Only two or three argument forms are allowed. */
2321     if (c->argc > 3) {
2322         addReplyErrorObject(c,shared.syntaxerr);
2323         return;
2324     }
2325     /* Always redact the second argument */
2326     redactClientCommandArgument(c, 1);
2327 
2328     /* Handle the two different forms here. The form with two arguments
2329      * will just use "default" as username. */
2330     robj *username, *password;
2331     if (c->argc == 2) {
2332         /* Mimic the old behavior of giving an error for the two argument
2333          * form if no password is configured. */
2334         if (DefaultUser->flags & USER_FLAG_NOPASS) {
2335             addReplyError(c,"AUTH <password> called without any password "
2336                             "configured for the default user. Are you sure "
2337                             "your configuration is correct?");
2338             return;
2339         }
2340 
2341         username = shared.default_username;
2342         password = c->argv[1];
2343     } else {
2344         username = c->argv[1];
2345         password = c->argv[2];
2346         redactClientCommandArgument(c, 2);
2347     }
2348 
2349     if (ACLAuthenticateUser(c,username,password) == C_OK) {
2350         addReply(c,shared.ok);
2351     } else {
2352         addReplyError(c,"-WRONGPASS invalid username-password pair or user is disabled.");
2353     }
2354 }
2355 
2356 /* Set the password for the "default" ACL user. This implements supports for
2357  * requirepass config, so passing in NULL will set the user to be nopass. */
ACLUpdateDefaultUserPassword(sds password)2358 void ACLUpdateDefaultUserPassword(sds password) {
2359     ACLSetUser(DefaultUser,"resetpass",-1);
2360     if (password) {
2361         sds aclop = sdscatlen(sdsnew(">"), password, sdslen(password));
2362         ACLSetUser(DefaultUser,aclop,sdslen(aclop));
2363         sdsfree(aclop);
2364     } else {
2365         ACLSetUser(DefaultUser,"nopass",-1);
2366     }
2367 }
2368