From 3e9e27e98fa7ecdbb5a34676e51cda54de671d8a Mon Sep 17 00:00:00 2001 From: antirez Date: Mon, 27 Jan 2020 18:37:52 +0100 Subject: ACL LOG: data structures and initial functions. --- src/acl.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++- src/multi.c | 2 +- src/scripting.c | 2 +- src/server.c | 2 +- src/server.h | 2 +- 5 files changed, 54 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/acl.c b/src/acl.c index 1f395bd3f..4391382a6 100644 --- a/src/acl.c +++ b/src/acl.c @@ -49,6 +49,8 @@ list *UsersToLoad; /* This is a list of users found in the configuration file array of SDS pointers: the first is the user name, all the remaining pointers are ACL rules in the same format as ACLSetUser(). */ +list *ACLLog; /* Our security log, the user is able to inspect that + using the ACL LOG command .*/ struct ACLCategoryItem { const char *name; @@ -920,6 +922,7 @@ void ACLInitDefaultUser(void) { void ACLInit(void) { Users = raxNew(); UsersToLoad = listCreate(); + ACLLog = listCreate(); ACLInitDefaultUser(); } @@ -1034,7 +1037,7 @@ user *ACLGetUserByName(const char *name, size_t namelen) { * command cannot be executed because the user is not allowed to run such * command, the second if the command is denied because the user is trying * to access keys that are not among the specified patterns. */ -int ACLCheckCommandPerm(client *c) { +int ACLCheckCommandPerm(client *c, int *keyidxptr) { user *u = c->user; uint64_t id = c->cmd->id; @@ -1094,6 +1097,7 @@ int ACLCheckCommandPerm(client *c) { } } if (!match) { + if (keyidxptr) *keyidxptr = keyidx[j]; getKeysFreeResult(keyidx); return ACL_DENIED_KEY; } @@ -1454,6 +1458,51 @@ void ACLLoadUsersAtStartup(void) { } } +/* ============================================================================= + * ACL log + * ==========================================================================*/ + +#define ACL_LOG_CTX_TOPLEVEL 0 +#define ACL_LOG_CTX_LUA 1 +#define ACL_LOG_CTX_MULTI 2 + +/* This structure defines an entry inside the ACL log. */ +typedef struct aclLogEntry { + uint64_t count; /* Number of times this happened recently. */ + int reason; /* Reason for denying the command. ACL_DENIED_*. */ + int context; /* Toplevel, Lua or MULTI/EXEC? ACL_LOG_CTX_*. */ + sds object; /* The key name or command name. */ + sds username; /* User the client is authenticated with. */ + mstime_t ctime; /* Milliseconds time of last update to this entry. */ + sds cinfo; /* Client info (last client if updated). */ +} aclLogEntry; + +void addACLLogEntry(client *c, int reason, int keypos) { + /* Create a new entry. */ + struct aclLogEntry *le = zmalloc(sizeof(*le)); + le->count = 1; + le->object = (reason == ACL_DENIED_CMD) ? sdsnew(c->cmd->name) : + sdsdup(c->argv[keypos]->ptr); + le->username = sdsdup(c->user->name); + le->ctime = mstime(); + + client *realclient = c; + if (realclient->flags & CLIENT_LUA) realclient = server.lua_caller; + + le->cinfo = catClientInfoString(sdsempty(),realclient); + if (c->flags & CLIENT_MULTI) { + le->context = ACL_LOG_CTX_MULTI; + } else if (c->flags & CLIENT_LUA) { + le->context = ACL_LOG_CTX_LUA; + } else { + le->context = ACL_LOG_CTX_TOPLEVEL; + } + + /* Add it to our list of entires. We'll have to trim the list + * to its maximum size. */ + listAddNodeHead(ACLLog, le); +} + /* ============================================================================= * ACL related commands * ==========================================================================*/ diff --git a/src/multi.c b/src/multi.c index df11225bd..640149870 100644 --- a/src/multi.c +++ b/src/multi.c @@ -177,7 +177,7 @@ void execCommand(client *c) { must_propagate = 1; } - int acl_retval = ACLCheckCommandPerm(c); + int acl_retval = ACLCheckCommandPerm(c,NULL); if (acl_retval != ACL_OK) { addReplyErrorFormat(c, "-NOPERM ACLs rules changed between the moment the " diff --git a/src/scripting.c b/src/scripting.c index 9282b7fd9..0e47ebcb0 100644 --- a/src/scripting.c +++ b/src/scripting.c @@ -606,7 +606,7 @@ int luaRedisGenericCommand(lua_State *lua, int raise_error) { } /* Check the ACLs. */ - int acl_retval = ACLCheckCommandPerm(c); + int acl_retval = ACLCheckCommandPerm(c,NULL); if (acl_retval != ACL_OK) { if (acl_retval == ACL_DENIED_CMD) luaPushError(lua, "The user executing the script can't run this " diff --git a/src/server.c b/src/server.c index 2b226f568..b5e27e238 100644 --- a/src/server.c +++ b/src/server.c @@ -3377,7 +3377,7 @@ int processCommand(client *c) { /* Check if the user can run this command according to the current * ACLs. */ - int acl_retval = ACLCheckCommandPerm(c); + int acl_retval = ACLCheckCommandPerm(c,NULL); if (acl_retval != ACL_OK) { flagTransaction(c); if (acl_retval == ACL_DENIED_CMD) diff --git a/src/server.h b/src/server.h index 8e354c03d..6fd0ffc5b 100644 --- a/src/server.h +++ b/src/server.h @@ -1824,7 +1824,7 @@ int ACLCheckUserCredentials(robj *username, robj *password); int ACLAuthenticateUser(client *c, robj *username, robj *password); unsigned long ACLGetCommandID(const char *cmdname); user *ACLGetUserByName(const char *name, size_t namelen); -int ACLCheckCommandPerm(client *c); +int ACLCheckCommandPerm(client *c, int *keyidxptr); int ACLSetUser(user *u, const char *op, ssize_t oplen); sds ACLDefaultUserFirstPassword(void); uint64_t ACLGetCommandCategoryFlagByName(const char *name); -- cgit v1.2.1