3333#include <fcntl.h>
3434#include <ctype.h>
3535
36+ #include "script.h"
37+
3638/* =============================================================================
3739 * Global state for ACLs
3840 * ==========================================================================*/
@@ -1541,11 +1543,25 @@ user *ACLGetUserByName(const char *name, size_t namelen) {
15411543 * ACL permission checks
15421544 * ==========================================================================*/
15431545
1544- /* Check if the key can be accessed by the selector.
1546+ /* Checks whether a given key is allowed for the specified ACL selector.
1547+ *
1548+ * The function evaluates the key against the selector's patterns, taking into account
1549+ * the requested key access flags (read/write) and whether the key should be
1550+ * treated as a prefix. If the selector has the SELECTOR_FLAG_ALLKEYS flag set,
1551+ * the check always succeeds.
15451552 *
1546- * If the selector can access the key, ACL_OK is returned, otherwise
1547- * ACL_DENIED_KEY is returned. */
1548- static int ACLSelectorCheckKey (aclSelector * selector , const char * key , int keylen , int keyspec_flags ) {
1553+ * - selector The ACL selector containing the allowed key patterns.
1554+ * - key Pointer to the key string to check.
1555+ * - keylen Length of the key in bytes.
1556+ * - keyspec_flags Bitmask of requested key operations (e.g., CMD_KEY_ACCESS,
1557+ * CMD_KEY_INSERT, CMD_KEY_DELETE, CMD_KEY_UPDATE).
1558+ * - is_prefix If true, the key is compared as a prefix against the selector's
1559+ * patterns using prefixmatchlen rather than a full string match.
1560+ *
1561+ * This function returns ACL_OK if the key matches at least one pattern that allows the requested
1562+ * operations; otherwise ACL_DENIED_KEY.
1563+ */
1564+ static int ACLSelectorCheckKey (aclSelector * selector , const char * key , int keylen , int keyspec_flags , bool is_prefix ) {
15491565 /* The selector can access any key */
15501566 if (selector -> flags & SELECTOR_FLAG_ALLKEYS ) return ACL_OK ;
15511567
@@ -1564,6 +1580,12 @@ static int ACLSelectorCheckKey(aclSelector *selector, const char *key, int keyle
15641580 keyPattern * pattern = listNodeValue (ln );
15651581 if ((pattern -> flags & key_flags ) != key_flags ) continue ;
15661582 size_t plen = sdslen (pattern -> pattern );
1583+ if (is_prefix ) {
1584+ if (prefixmatchlen (pattern -> pattern , plen , key , keylen , 0 ))
1585+ return ACL_OK ;
1586+ else
1587+ continue ;
1588+ }
15671589 if (stringmatchlen (pattern -> pattern , plen , key , keylen , 0 )) return ACL_OK ;
15681590 }
15691591 return ACL_DENIED_KEY ;
@@ -1688,7 +1710,7 @@ static int ACLSelectorCheckCmd(aclSelector *selector,
16881710 keyReference * resultidx = result -> keys ;
16891711 for (int j = 0 ; j < result -> numkeys ; j ++ ) {
16901712 int idx = resultidx [j ].pos ;
1691- ret = ACLSelectorCheckKey (selector , argv [idx ]-> ptr , sdslen (argv [idx ]-> ptr ), resultidx [j ].flags );
1713+ ret = ACLSelectorCheckKey (selector , argv [idx ]-> ptr , sdslen (argv [idx ]-> ptr ), resultidx [j ].flags , false );
16921714 if (ret != ACL_OK ) {
16931715 if (keyidxptr ) * keyidxptr = resultidx [j ].pos ;
16941716 return ret ;
@@ -1721,13 +1743,30 @@ static int ACLSelectorCheckCmd(aclSelector *selector,
17211743 return ACL_OK ;
17221744}
17231745
1724- /* Check if the key can be accessed by the client according to
1725- * the ACLs associated with the specified user according to the
1726- * keyspec access flags.
1746+ /* Checks whether the given user has permission to access a specified key.
17271747 *
1728- * If the user can access the key, ACL_OK is returned, otherwise
1729- * ACL_DENIED_KEY is returned. */
1730- int ACLUserCheckKeyPerm (user * u , const char * key , int keylen , int flags ) {
1748+ * This function verifies the access control list (ACL) permissions for a user on a key.
1749+ * If the user pointer is NULL, the connection is considered authorized to run any
1750+ * command and the function returns ACL_OK. Otherwise, the function iterates
1751+ * through the user's ACL selectors and returns ACL_OK as soon as any selector
1752+ * grants permission. If no selector grants permission, ACL_DENIED_KEY is returned.
1753+ *
1754+ * Input parameters:
1755+ *
1756+ * - u Pointer to a user structure. If NULL, the user is treated as
1757+ * having unrestricted access.
1758+ * - key Pointer to the key string to check.
1759+ * - keylen Length of the key string in bytes.
1760+ * - flags Flags that may influence selector checks (implementation-specific).
1761+ * - is_prefix true if key should be treated as a prefix in selector
1762+ * evaluation; false otherwise.
1763+ *
1764+ * Returns ACL_OK if access is granted, ACL_DENIED_KEY if access is denied.
1765+ *
1766+ * NOTE: The function performs no modification of the user structure or the key;
1767+ * it only evaluates read-only selectors.
1768+ */
1769+ int ACLUserCheckKeyPerm (user * u , const char * key , int keylen , int flags , bool is_prefix ) {
17311770 listIter li ;
17321771 listNode * ln ;
17331772
@@ -1738,7 +1777,7 @@ int ACLUserCheckKeyPerm(user *u, const char *key, int keylen, int flags) {
17381777 listRewind (u -> selectors , & li );
17391778 while ((ln = listNext (& li ))) {
17401779 aclSelector * s = (aclSelector * )listNodeValue (ln );
1741- if (ACLSelectorCheckKey (s , key , keylen , flags ) == ACL_OK ) {
1780+ if (ACLSelectorCheckKey (s , key , keylen , flags , is_prefix ) == ACL_OK ) {
17421781 return ACL_OK ;
17431782 }
17441783 }
@@ -2546,7 +2585,7 @@ void ACLLoadUsersAtStartup(void) {
25462585typedef struct ACLLogEntry {
25472586 uint64_t count ; /* Number of times this happened recently. */
25482587 int reason ; /* Reason for denying the command. ACL_DENIED_*. */
2549- int context ; /* Toplevel, Lua or MULTI/EXEC? ACL_LOG_CTX_*. */
2588+ int context ; /* Toplevel, Lua, Script or MULTI/EXEC? ACL_LOG_CTX_*. */
25502589 sds object ; /* The key name or command name. */
25512590 sds username ; /* User the client is authenticated with. */
25522591 mstime_t ctime ; /* Milliseconds time of last update to this entry. */
@@ -2654,6 +2693,15 @@ void addACLLogEntry(client *c, int reason, int context, int argpos, sds username
26542693 client * realclient = server .current_client ? server .current_client : c ;
26552694
26562695 le -> cinfo = catClientInfoString (sdsempty (), realclient , 0 );
2696+
2697+ if (context == ACL_LOG_CTX_SCRIPT &&
2698+ strcmp (scriptGetRunningEngineName (), "LUA" ) == 0 ) {
2699+ /* For backward compatibility, we track that it's Lua using a special
2700+ * lua ACL log context. Any other scripting language is just "script" in
2701+ * the ACL log. */
2702+ context = ACL_LOG_CTX_LUA ;
2703+ }
2704+
26572705 le -> context = context ;
26582706
26592707 /* Try to match this entry with past ones, to see if we can just
@@ -3044,6 +3092,7 @@ void aclCommand(client *c) {
30443092 case ACL_LOG_CTX_MULTI : ctxstr = "multi" ; break ;
30453093 case ACL_LOG_CTX_LUA : ctxstr = "lua" ; break ;
30463094 case ACL_LOG_CTX_MODULE : ctxstr = "module" ; break ;
3095+ case ACL_LOG_CTX_SCRIPT : ctxstr = "script" ; break ;
30473096 default : ctxstr = "unknown" ;
30483097 }
30493098 addReplyBulkCString (c , ctxstr );
0 commit comments