@@ -181,8 +181,8 @@ typedef struct {
181181 ALLCHANNELS is set in the user. */
182182 sds command_rules ; /* A string representation of the ordered categories and commands, this
183183 * is used to regenerate the original ACL string for display. */
184- intset * dbs ; /* Set of database ids, based on SELECTOR_FLAG_DBLIST_NEGATED
185- it is going to be allowed or disallowed database ids */
184+ intset * dbs ; /* Set of allowed database ids. If set is NULL or empty the user
185+ * cannot access any database, unless the flag ALLDBS is set. */
186186} aclSelector ;
187187
188188static void ACLResetFirstArgsForCommand (aclSelector * selector , unsigned long id );
@@ -821,12 +821,7 @@ static sds ACLDescribeSelector(aclSelector *selector) {
821821 if (selector -> flags & SELECTOR_FLAG_ALLDBS ) {
822822 res = sdscatlen (res , "alldbs " , 7 );
823823 } else {
824- if (selector -> flags & SELECTOR_FLAG_DBLIST_NEGATED ) {
825- res = sdscatlen (res , "db!=" , 4 );
826- } else {
827- res = sdscatlen (res , "db=" , 3 );
828- }
829-
824+ res = sdscatlen (res , "db=" , 3 );
830825 uint32_t len = intsetLen (selector -> dbs );
831826 for (uint32_t i = 0 ; i < len ; i ++ ) {
832827 int64_t dbid ;
@@ -965,7 +960,7 @@ static void ACLAddAllowedFirstArg(aclSelector *selector, unsigned long id, const
965960}
966961
967962/* Helper function to set database permissions for a selector */
968- static int ACLSetSelectorDatabasePermissions (aclSelector * selector , const char * dbs_str , int negated ) {
963+ static int ACLSetSelectorDatabasePermissions (aclSelector * selector , const char * dbs_str ) {
969964 selector -> flags &= ~SELECTOR_FLAG_ALLDBS ;
970965
971966 intset * new_dbs = intsetNew ();
@@ -974,20 +969,13 @@ static int ACLSetSelectorDatabasePermissions(aclSelector *selector, const char *
974969 return C_ERR ;
975970 }
976971
977- if (negated ) {
978- selector -> flags |= SELECTOR_FLAG_DBLIST_NEGATED ;
979- } else {
980- selector -> flags &= ~SELECTOR_FLAG_DBLIST_NEGATED ;
981- }
982-
983972 char * dblist = zstrdup (dbs_str );
984973 if (!dblist ) {
985974 intsetFree (new_dbs );
986975 errno = ENOMEM ;
987976 return C_ERR ;
988977 }
989978
990-
991979 // Reject empty list, trailing commas or more than 1 consecutive commas
992980 if (strlen (dblist ) == 0 || dblist [0 ] == ',' ||
993981 dblist [strlen (dblist ) - 1 ] == ',' || strstr (dblist , ",," )) {
@@ -1100,11 +1088,8 @@ static aclSelector *aclCreateSelectorFromOpSet(const char *opset, size_t opsetle
11001088 * db=<dbid> Add database ID to the set of allowed IDs, any other database ID
11011089 * will be disallowed. May be used with `,` for assingning multiple
11021090 * allowed IDs (e.g "db=1,2,3").
1103- * db!=<dbid> Add database ID to the set of disallowed IDs, any other database ID
1104- * will be disallowed. May be used with `,` for assingning multiple
1105- * disallowed IDs (e.g "db!=4,5,6").
11061091 * alldbs Allow access to all databases.
1107- * resetdbs Flush the set of allowed/disallowed database IDs, revert to default
1092+ * resetdbs Flush the set of allowed database IDs, revert to default
11081093 * behaviour (all databases are allowed).
11091094 */
11101095static int ACLSetSelector (aclSelector * selector , const char * op , size_t oplen ) {
@@ -1132,11 +1117,8 @@ static int ACLSetSelector(aclSelector *selector, const char *op, size_t oplen) {
11321117 intsetFree (selector -> dbs );
11331118 selector -> dbs = intsetNew ();
11341119 }
1135- } else if (strncmp (op , "db=" , 3 ) == 0 ) {
1136- int result = ACLSetSelectorDatabasePermissions (selector , op + 3 , 0 );
1137- if (result != C_OK ) return result ;
1138- } else if (strncmp (op , "db!=" , 4 ) == 0 ) {
1139- int result = ACLSetSelectorDatabasePermissions (selector , op + 4 , 1 );
1120+ } else if (strncmp (op , "db=" , 3 ) == 0 || strncmp (op , "DB=" , 3 ) == 0 ) {
1121+ int result = ACLSetSelectorDatabasePermissions (selector , op + 3 );
11401122 if (result != C_OK ) return result ;
11411123 } else if (!strcasecmp (op , "allcommands" ) || !strcasecmp (op , "+@all" )) {
11421124 memset (selector -> allowed_commands , 255 , sizeof (selector -> allowed_commands ));
@@ -1759,13 +1741,11 @@ int ACLSelectorCanAccessDb(aclSelector *selector, long long dbid) {
17591741 if (selector -> flags & SELECTOR_FLAG_ALLDBS )
17601742 return 1 ;
17611743
1762- if (dbid < 0 || dbid >= server .dbnum )
1744+ if (dbid < 0 || dbid >= server .dbnum || ! selector -> dbs )
17631745 return 0 ;
17641746
17651747 int found = intsetFind (selector -> dbs , (int64_t )dbid );
17661748
1767- if (selector -> flags & SELECTOR_FLAG_DBLIST_NEGATED )
1768- return !found ;
17691749 return found ;
17701750}
17711751
@@ -1801,41 +1781,43 @@ static int ACLSelectorCheckCmd(aclSelector *selector,
18011781 int dbid ) {
18021782 uint64_t id = cmd -> id ;
18031783 int ret ;
1784+
1785+ /* Check database level permissions based on command flags. */
18041786 if (cmd -> flags & CMD_CROSS_DB ) {
1805- if (cmd -> proc == selectCommand && argc > 1 ) {
1806- long long target_db ;
1807- if (getLongLongFromObject (argv [1 ], & target_db ) == C_OK ) {
1808- if (target_db >= 0 && target_db < server .dbnum ) {
1809- dbid = (int )target_db ;
1787+ if (cmd -> get_dbid_args ) {
1788+ int count = 0 ;
1789+ int * dbids = cmd -> get_dbid_args (argv , argc , & count );
1790+ if (dbids ) {
1791+ for (int i = 0 ; i < count ; i ++ ) {
1792+ if (!ACLSelectorCanAccessDb (selector , dbids [i ])) {
1793+ if (keyidxptr ) {
1794+ if (cmd -> proc == selectCommand )
1795+ * keyidxptr = 1 ;
1796+ else if (cmd -> proc == moveCommand )
1797+ * keyidxptr = 2 ;
1798+ else if (cmd -> proc == swapdbCommand )
1799+ * keyidxptr = (i == 0 ) ? 1 : 2 ;
1800+ else
1801+ * keyidxptr = 0 ;
1802+ }
1803+ zfree (dbids );
1804+ return ACL_DENIED_DB ;
1805+ }
18101806 }
1807+ zfree (dbids );
18111808 }
1812- } else if (cmd -> proc == swapdbCommand && argc > 2 ) {
1813- long long db1 , db2 ;
1814- if (getLongLongFromObject (argv [1 ], & db1 ) == C_OK && getLongLongFromObject (argv [2 ], & db2 ) == C_OK &&
1815- (!ACLSelectorCanAccessDb (selector , db1 ) || !ACLSelectorCanAccessDb (selector , db2 ))) {
1816- return ACL_DENIED_DB ;
1817- }
1818- } else if (cmd -> proc == moveCommand && argc > 2 ) {
1819- long long target_db ;
1820- if (getLongLongFromObject (argv [2 ], & target_db ) == C_OK &&
1821- !ACLSelectorCanAccessDb (selector , target_db )) {
1822- return ACL_DENIED_DB ;
1823- }
1809+ } else {
1810+ /* Command has flag CMD_CROSS_DB but has no function to get its db id args */
1811+ return ACL_NOT_IMPLEMENTED ;
18241812 }
1825- }
1826-
1827- if ((cmd -> flags & CMD_ALL_DBS ) && !(selector -> flags & SELECTOR_FLAG_ALLDBS )) {
1813+ } else if ((cmd -> flags & CMD_ALL_DBS ) && !(selector -> flags & SELECTOR_FLAG_ALLDBS )) {
18281814 for (int i = 0 ; i < server .dbnum ; i ++ ) {
18291815 if (!ACLSelectorCanAccessDb (selector , i )) {
18301816 return ACL_DENIED_DB ;
18311817 }
18321818 }
1833- }
1834-
1835- if (!ACLSelectorCanAccessDb (selector , dbid )) {
1836- if (keyidxptr ) {
1837- * keyidxptr = (cmd -> proc == selectCommand ) ? 1 : 0 ;
1838- }
1819+ } else if (!ACLSelectorCanAccessDb (selector , dbid )) {
1820+ if (keyidxptr ) * keyidxptr = 0 ;
18391821 return ACL_DENIED_DB ;
18401822 }
18411823
@@ -2778,6 +2760,7 @@ static void ACLUpdateInfoMetrics(int reason) {
27782760 server .acl_info .acl_access_denied_tls_cert ++ ;
27792761 } else if (reason == ACL_DENIED_DB ) {
27802762 server .acl_info .invalid_db_accesses ++ ;
2763+ } else if (reason == ACL_NOT_IMPLEMENTED ) {
27812764 } else {
27822765 serverPanic ("Unknown ACL_DENIED encoding" );
27832766 }
@@ -2915,8 +2898,14 @@ sds getAclErrorMessage(int acl_res, user *user, struct serverCommand *cmd, sds e
29152898 "database %s" ,
29162899 user -> name , errored_val );
29172900 } else {
2918- return sdsnew ("No permissions to access current database" );
2901+ return sdsnew ("No permissions to access database" );
29192902 }
2903+ case ACL_NOT_IMPLEMENTED :
2904+ return sdscatfmt (sdsempty (),
2905+ "Command '%S' has flag CMD_CROSS_DB "
2906+ "but has no function to get its database id args, "
2907+ "see serverCommand in server.h" ,
2908+ cmd -> fullname );
29202909 }
29212910 serverPanic ("Reached deadcode on getAclErrorMessage" );
29222911}
0 commit comments