From 11788c71e39ad18be122c80ecc9cb974d1fe1bd1 Mon Sep 17 00:00:00 2001 From: Mike Palmiotto <mike.palmiotto@crunchydata.com> Date: Fri, 15 Sep 2017 07:37:58 -0400 Subject: [PATCH] Add group role support to superuser whitelist This feature adds support for '+<group_role>' syntax in the superuser whitelist. This should allow users to be added to the whitelist by association with the specified "<group_role>". Resolves: #7 --- README.md | 12 ++++++++---- set_user.c | 22 ++++++++++++++++++---- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index e38e428..e898d68 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,11 @@ reset_user(text token) returns text * set_user.block_alter_system = off (defaults to "on") * set_user.block_copy_program = off (defaults to "on") * set_user.block_log_statement = off (defaults to "on") - * set_user.superuser_whitelist = '```<user1>```,```<user2>```,...,```<userN>```' (defaults to '*') + * set_user.superuser_whitelist = '```<role list>``` + * ```<role list>``` can contain any of the following: + * list of user roles (i.e. ```<role1>, <role2>,...,<roleN>```) + * Group roles may be indicated by ```+<roleN>``' + * The wildcard character ```*``` ## Description @@ -37,7 +41,7 @@ This PostgreSQL extension allows switching users and optionally privilege escala variations will be blocked. * If set_user.block_log_statement is set to "on" and ```rolename``` is a database superuser, the current log_statement setting is changed to "all", meaning every SQL statement executed -Only users with EXECUTE permission on ```set_user_u('rolename')``` may escalate to superuser. Additionally, only users explicitly listed in set_user.superuser_whitelist can escalate to superuser. If set_user.superuser_whitelist is explicitly set to the empty set, '', superuser escalation is blocked for all users. If the whitelist is equal to the wildcard character, '*', all users with EXECUTE permission on ```set_user_u()``` can escalate to superuser. The default value of set_user.superuser_whitelist is '*'. +Only users with EXECUTE permission on ```set_user_u('rolename')``` may escalate to superuser. Additionally, only roles explicitly listed or included by a group that is explicitly listed (e.g. '+admin') in set_user.superuser_whitelist can escalate to superuser. If set_user.superuser_whitelist is explicitly set to the empty set, '', superuser escalation is blocked for all users. If the whitelist is equal to the wildcard character, '*', all users with EXECUTE permission on ```set_user_u()``` can escalate to superuser. The default value of set_user.superuser_whitelist is '*'. Additionally, with ```set_user('rolename','token')``` the ```token``` is stored in session lifetime memory. @@ -203,8 +207,8 @@ CREATE EXTENSION set_user; * set_user.block_copy_program = on * Block SET log_statement commands * set_user.block_log_statement = on -* Allow list of users to escalate to superuser - * set_user.superuser_whitelist = '```<user1>,<user2>,...,<userN>```' +* Allow list of roles to escalate to superuser + * set_user.superuser_whitelist = '```<role1>,<role2>,...,<roleN>```' ## Examples diff --git a/set_user.c b/set_user.c index 7070c11..c976eb1 100644 --- a/set_user.c +++ b/set_user.c @@ -93,6 +93,7 @@ #include "catalog/pg_proc.h" #include "miscadmin.h" #include "tcop/utility.h" +#include "utils/acl.h" #include "utils/builtins.h" #include "utils/guc.h" #include "utils/memutils.h" @@ -208,9 +209,21 @@ check_user_whitelist(Oid userId, const char *whitelist) { char *elem = (char *) lfirst(l); - if (pg_strcasecmp(elem, GETUSERNAMEFROMID(userId)) == 0) - result = true; - else if (pg_strcasecmp(elem, WHITELIST_WILDCARD) == 0) + if (elem[0] == '+') + { + Oid roleId; + roleId = get_role_oid(elem + 1, false); + if (!OidIsValid(roleId)) + result = false; + + /* Check to see if userId is contained by group role in whitelist */ + result = has_privs_of_role(userId, roleId); + } + else + { + if (pg_strcasecmp(elem, GETUSERNAMEFROMID(userId)) == 0) + result = true; + else if(pg_strcasecmp(elem, WHITELIST_WILDCARD) == 0) /* No explicit usernames intermingled with wildcard. */ ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), @@ -219,8 +232,9 @@ check_user_whitelist(Oid userId, const char *whitelist) "or remove the wildcard character \"%s\". The whitelist " "cannot contain both.", WHITELIST_WILDCARD))); + result = true; + } } - return result; }