Check if the command is ready to be executed in the client 'c', already * referenced by c->cmd, and can be executed by this client according to the * ACLs associated to the client user c->user. * * If the user can execute the command ACL_OK is returned, otherwise * ACL_DENIED_CMD or ACL_DENIED_KEY is returned: the first in case the * command cannot be executed because the user is not allowed
| 1186 | * command, the second if the command is denied because the user is trying |
| 1187 | * to access keys that are not among the specified patterns. */ |
| 1188 | int ACLCheckCommandPerm(client *c, int *keyidxptr) { |
| 1189 | user *u = c->user; |
| 1190 | uint64_t id = c->cmd->id; |
| 1191 | |
| 1192 | /* If there is no associated user, the connection can run anything. */ |
| 1193 | if (u == NULL) return ACL_OK; |
| 1194 | |
| 1195 | /* Check if the user can execute this command or if the command |
| 1196 | * doesn't need to be authenticated (hello, auth). */ |
| 1197 | if (!(u->flags & USER_FLAG_ALLCOMMANDS) && !(c->cmd->flags & CMD_NO_AUTH)) |
| 1198 | { |
| 1199 | /* If the bit is not set we have to check further, in case the |
| 1200 | * command is allowed just with that specific subcommand. */ |
| 1201 | if (ACLGetUserCommandBit(u,id) == 0) { |
| 1202 | /* Check if the subcommand matches. */ |
| 1203 | if (c->argc < 2 || |
| 1204 | u->allowed_subcommands == NULL || |
| 1205 | u->allowed_subcommands[id] == NULL) |
| 1206 | { |
| 1207 | return ACL_DENIED_CMD; |
| 1208 | } |
| 1209 | |
| 1210 | long subid = 0; |
| 1211 | while (1) { |
| 1212 | if (u->allowed_subcommands[id][subid] == NULL) |
| 1213 | return ACL_DENIED_CMD; |
| 1214 | if (!strcasecmp(szFromObj(c->argv[1]), |
| 1215 | u->allowed_subcommands[id][subid])) |
| 1216 | break; /* Subcommand match found. Stop here. */ |
| 1217 | subid++; |
| 1218 | } |
| 1219 | } |
| 1220 | } |
| 1221 | |
| 1222 | /* Check if the user can execute commands explicitly touching the keys |
| 1223 | * mentioned in the command arguments. */ |
| 1224 | if (!(c->user->flags & USER_FLAG_ALLKEYS) && |
| 1225 | (c->cmd->getkeys_proc || c->cmd->firstkey)) |
| 1226 | { |
| 1227 | getKeysResult result = GETKEYS_RESULT_INIT; |
| 1228 | int numkeys = getKeysFromCommand(c->cmd,c->argv,c->argc,&result); |
| 1229 | int *keyidx = result.keys; |
| 1230 | for (int j = 0; j < numkeys; j++) { |
| 1231 | listIter li; |
| 1232 | listNode *ln; |
| 1233 | listRewind(u->patterns,&li); |
| 1234 | |
| 1235 | /* Test this key against every pattern. */ |
| 1236 | int match = 0; |
| 1237 | while((ln = listNext(&li))) { |
| 1238 | sds pattern = (sds)listNodeValue(ln); |
| 1239 | size_t plen = sdslen(pattern); |
| 1240 | int idx = keyidx[j]; |
| 1241 | if (stringmatchlen(pattern,plen,szFromObj(c->argv[idx]), |
| 1242 | sdslen(szFromObj(c->argv[idx])),0)) |
| 1243 | { |
| 1244 | match = 1; |
| 1245 | break; |
no test coverage detected