summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorantirez <antirez@gmail.com>2020-01-27 18:37:52 +0100
committerantirez <antirez@gmail.com>2020-01-27 18:37:52 +0100
commit3e9e27e98fa7ecdbb5a34676e51cda54de671d8a (patch)
tree130fefddb0528822ecfabc42642526f79c74b00d
parent7ef2270ee73e75b00b0c1bde40fb1df55c7ec6ff (diff)
downloadredis-3e9e27e98fa7ecdbb5a34676e51cda54de671d8a.tar.gz
ACL LOG: data structures and initial functions.
-rw-r--r--src/acl.c51
-rw-r--r--src/multi.c2
-rw-r--r--src/scripting.c2
-rw-r--r--src/server.c2
-rw-r--r--src/server.h2
5 files changed, 54 insertions, 5 deletions
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;
}
@@ -1455,6 +1459,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);