diff options
author | Joe Conway <mail@joeconway.com> | 2022-03-28 15:10:04 -0400 |
---|---|---|
committer | Joe Conway <mail@joeconway.com> | 2022-03-28 15:10:04 -0400 |
commit | 6198420ad8a72e37f4fe4964616b17e0fd33b808 (patch) | |
tree | 48b9bf9c3997840958f3290ff8a1a2330a5b55b8 /src/backend | |
parent | 79de9842ab03259325ee4055fb0a7ebd2e4372ff (diff) | |
download | postgresql-6198420ad8a72e37f4fe4964616b17e0fd33b808.tar.gz postgresql-6198420ad8a72e37f4fe4964616b17e0fd33b808.zip |
Use has_privs_for_roles for predefined role checks
Generally if a role is granted membership to another role with NOINHERIT
they must use SET ROLE to access the privileges of that role, however
with predefined roles the membership and privilege is conflated. Fix that
by replacing is_member_of_role with has_privs_for_role for predefined
roles. Patch does not remove is_member_of_role from acl.h, but it does
add a warning not to use that function for privilege checking. Not
backpatched based on hackers list discussion.
Author: Joshua Brindle
Reviewed-by: Stephen Frost, Nathan Bossart, Joe Conway
Discussion: https://postgr.es/m/flat/CAGB+Vh4Zv_TvKt2tv3QNS6tUM_F_9icmuj0zjywwcgVi4PAhFA@mail.gmail.com
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/commands/copy.c | 12 | ||||
-rw-r--r-- | src/backend/replication/walreceiver.c | 8 | ||||
-rw-r--r-- | src/backend/replication/walsender.c | 8 | ||||
-rw-r--r-- | src/backend/utils/adt/acl.c | 4 | ||||
-rw-r--r-- | src/backend/utils/adt/dbsize.c | 8 | ||||
-rw-r--r-- | src/backend/utils/adt/genfile.c | 6 | ||||
-rw-r--r-- | src/backend/utils/adt/pgstatfuncs.c | 2 | ||||
-rw-r--r-- | src/backend/utils/misc/guc.c | 20 |
8 files changed, 36 insertions, 32 deletions
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index 7da7105d44b..7a0c897cc97 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -80,26 +80,26 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt, { if (stmt->is_program) { - if (!is_member_of_role(GetUserId(), ROLE_PG_EXECUTE_SERVER_PROGRAM)) + if (!has_privs_of_role(GetUserId(), ROLE_PG_EXECUTE_SERVER_PROGRAM)) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("must be superuser or a member of the pg_execute_server_program role to COPY to or from an external program"), + errmsg("must be superuser or have privileges of the pg_execute_server_program role to COPY to or from an external program"), errhint("Anyone can COPY to stdout or from stdin. " "psql's \\copy command also works for anyone."))); } else { - if (is_from && !is_member_of_role(GetUserId(), ROLE_PG_READ_SERVER_FILES)) + if (is_from && !has_privs_of_role(GetUserId(), ROLE_PG_READ_SERVER_FILES)) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("must be superuser or a member of the pg_read_server_files role to COPY from a file"), + errmsg("must be superuser or have privileges of the pg_read_server_files role to COPY from a file"), errhint("Anyone can COPY to stdout or from stdin. " "psql's \\copy command also works for anyone."))); - if (!is_from && !is_member_of_role(GetUserId(), ROLE_PG_WRITE_SERVER_FILES)) + if (!is_from && !has_privs_of_role(GetUserId(), ROLE_PG_WRITE_SERVER_FILES)) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("must be superuser or a member of the pg_write_server_files role to COPY to a file"), + errmsg("must be superuser or have privileges of the pg_write_server_files role to COPY to a file"), errhint("Anyone can COPY to stdout or from stdin. " "psql's \\copy command also works for anyone."))); } diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c index ceaff097b97..3c9411e2213 100644 --- a/src/backend/replication/walreceiver.c +++ b/src/backend/replication/walreceiver.c @@ -1403,12 +1403,12 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS) /* Fetch values */ values[0] = Int32GetDatum(pid); - if (!is_member_of_role(GetUserId(), ROLE_PG_READ_ALL_STATS)) + if (!has_privs_of_role(GetUserId(), ROLE_PG_READ_ALL_STATS)) { /* - * Only superusers and members of pg_read_all_stats can see details. - * Other users only get the pid value to know whether it is a WAL - * receiver, but no details. + * Only superusers and roles with privileges of pg_read_all_stats + * can see details. Other users only get the pid value to know whether + * it is a WAL receiver, but no details. */ MemSet(&nulls[1], true, sizeof(bool) * (tupdesc->natts - 1)); } diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c index 2d0292a092e..cffb3482adf 100644 --- a/src/backend/replication/walsender.c +++ b/src/backend/replication/walsender.c @@ -3473,12 +3473,12 @@ pg_stat_get_wal_senders(PG_FUNCTION_ARGS) memset(nulls, 0, sizeof(nulls)); values[0] = Int32GetDatum(pid); - if (!is_member_of_role(GetUserId(), ROLE_PG_READ_ALL_STATS)) + if (!has_privs_of_role(GetUserId(), ROLE_PG_READ_ALL_STATS)) { /* - * Only superusers and members of pg_read_all_stats can see - * details. Other users only get the pid value to know it's a - * walsender, but no details. + * Only superusers and roles with privileges of pg_read_all_stats + * can see details. Other users only get the pid value to know + * it's a walsender, but no details. */ MemSet(&nulls[1], true, PG_STAT_GET_WAL_SENDERS_COLS - 1); } diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c index 5d939de3da7..83cf7ac9ff9 100644 --- a/src/backend/utils/adt/acl.c +++ b/src/backend/utils/adt/acl.c @@ -4859,6 +4859,8 @@ has_privs_of_role(Oid member, Oid role) * Is member a member of role (directly or indirectly)? * * This is defined to recurse through roles regardless of rolinherit. + * + * Do not use this for privilege checking, instead use has_privs_of_role() */ bool is_member_of_role(Oid member, Oid role) @@ -4899,6 +4901,8 @@ check_is_member_of_role(Oid member, Oid role) * * This is identical to is_member_of_role except we ignore superuser * status. + * + * Do not use this for privilege checking, instead use has_privs_of_role() */ bool is_member_of_role_nosuper(Oid member, Oid role) diff --git a/src/backend/utils/adt/dbsize.c b/src/backend/utils/adt/dbsize.c index 3a2f2e1f99d..0576764ac4b 100644 --- a/src/backend/utils/adt/dbsize.c +++ b/src/backend/utils/adt/dbsize.c @@ -112,12 +112,12 @@ calculate_database_size(Oid dbOid) AclResult aclresult; /* - * User must have connect privilege for target database or be a member of + * User must have connect privilege for target database or have privileges of * pg_read_all_stats */ aclresult = pg_database_aclcheck(dbOid, GetUserId(), ACL_CONNECT); if (aclresult != ACLCHECK_OK && - !is_member_of_role(GetUserId(), ROLE_PG_READ_ALL_STATS)) + !has_privs_of_role(GetUserId(), ROLE_PG_READ_ALL_STATS)) { aclcheck_error(aclresult, OBJECT_DATABASE, get_database_name(dbOid)); @@ -196,12 +196,12 @@ calculate_tablespace_size(Oid tblspcOid) AclResult aclresult; /* - * User must be a member of pg_read_all_stats or have CREATE privilege for + * User must have privileges of pg_read_all_stats or have CREATE privilege for * target tablespace, either explicitly granted or implicitly because it * is default for current database. */ if (tblspcOid != MyDatabaseTableSpace && - !is_member_of_role(GetUserId(), ROLE_PG_READ_ALL_STATS)) + !has_privs_of_role(GetUserId(), ROLE_PG_READ_ALL_STATS)) { aclresult = pg_tablespace_aclcheck(tblspcOid, GetUserId(), ACL_CREATE); if (aclresult != ACLCHECK_OK) diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c index 1ed01620a1b..88f279d1b31 100644 --- a/src/backend/utils/adt/genfile.c +++ b/src/backend/utils/adt/genfile.c @@ -59,11 +59,11 @@ convert_and_check_filename(text *arg) canonicalize_path(filename); /* filename can change length here */ /* - * Members of the 'pg_read_server_files' role are allowed to access any - * files on the server as the PG user, so no need to do any further checks + * Roles with privleges of the 'pg_read_server_files' role are allowed to access + * any files on the server as the PG user, so no need to do any further checks * here. */ - if (is_member_of_role(GetUserId(), ROLE_PG_READ_SERVER_FILES)) + if (has_privs_of_role(GetUserId(), ROLE_PG_READ_SERVER_FILES)) return filename; /* diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c index eff45b16f2c..ce84525d402 100644 --- a/src/backend/utils/adt/pgstatfuncs.c +++ b/src/backend/utils/adt/pgstatfuncs.c @@ -34,7 +34,7 @@ #define UINT32_ACCESS_ONCE(var) ((uint32)(*((volatile uint32 *)&(var)))) -#define HAS_PGSTAT_PERMISSIONS(role) (is_member_of_role(GetUserId(), ROLE_PG_READ_ALL_STATS) || has_privs_of_role(GetUserId(), role)) +#define HAS_PGSTAT_PERMISSIONS(role) (has_privs_of_role(GetUserId(), ROLE_PG_READ_ALL_STATS) || has_privs_of_role(GetUserId(), role)) Datum pg_stat_get_numscans(PG_FUNCTION_ARGS) diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index b86137dc385..eb3a03b9762 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -8228,10 +8228,10 @@ GetConfigOption(const char *name, bool missing_ok, bool restrict_privileged) return NULL; if (restrict_privileged && (record->flags & GUC_SUPERUSER_ONLY) && - !is_member_of_role(GetUserId(), ROLE_PG_READ_ALL_SETTINGS)) + !has_privs_of_role(GetUserId(), ROLE_PG_READ_ALL_SETTINGS)) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("must be superuser or a member of pg_read_all_settings to examine \"%s\"", + errmsg("must be superuser or have privileges of pg_read_all_settings to examine \"%s\"", name))); switch (record->vartype) @@ -8275,10 +8275,10 @@ GetConfigOptionResetString(const char *name) record = find_option(name, false, false, ERROR); Assert(record != NULL); if ((record->flags & GUC_SUPERUSER_ONLY) && - !is_member_of_role(GetUserId(), ROLE_PG_READ_ALL_SETTINGS)) + !has_privs_of_role(GetUserId(), ROLE_PG_READ_ALL_SETTINGS)) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("must be superuser or a member of pg_read_all_settings to examine \"%s\"", + errmsg("must be superuser or have privileges of pg_read_all_settings to examine \"%s\"", name))); switch (record->vartype) @@ -9566,7 +9566,7 @@ ShowAllGUCConfig(DestReceiver *dest) if ((conf->flags & GUC_NO_SHOW_ALL) || ((conf->flags & GUC_SUPERUSER_ONLY) && - !is_member_of_role(GetUserId(), ROLE_PG_READ_ALL_SETTINGS))) + !has_privs_of_role(GetUserId(), ROLE_PG_READ_ALL_SETTINGS))) continue; /* assign to the values array */ @@ -9633,7 +9633,7 @@ get_explain_guc_options(int *num) /* return only options visible to the current user */ if ((conf->flags & GUC_NO_SHOW_ALL) || ((conf->flags & GUC_SUPERUSER_ONLY) && - !is_member_of_role(GetUserId(), ROLE_PG_READ_ALL_SETTINGS))) + !has_privs_of_role(GetUserId(), ROLE_PG_READ_ALL_SETTINGS))) continue; /* return only options that are different from their boot values */ @@ -9715,10 +9715,10 @@ GetConfigOptionByName(const char *name, const char **varname, bool missing_ok) } if ((record->flags & GUC_SUPERUSER_ONLY) && - !is_member_of_role(GetUserId(), ROLE_PG_READ_ALL_SETTINGS)) + !has_privs_of_role(GetUserId(), ROLE_PG_READ_ALL_SETTINGS)) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("must be superuser or a member of pg_read_all_settings to examine \"%s\"", + errmsg("must be superuser or have privileges of pg_read_all_settings to examine \"%s\"", name))); if (varname) @@ -9785,7 +9785,7 @@ GetConfigOptionByNum(int varnum, const char **values, bool *noshow) { if ((conf->flags & GUC_NO_SHOW_ALL) || ((conf->flags & GUC_SUPERUSER_ONLY) && - !is_member_of_role(GetUserId(), ROLE_PG_READ_ALL_SETTINGS))) + !has_privs_of_role(GetUserId(), ROLE_PG_READ_ALL_SETTINGS))) *noshow = true; else *noshow = false; @@ -9980,7 +9980,7 @@ GetConfigOptionByNum(int varnum, const char **values, bool *noshow) * insufficiently-privileged users. */ if (conf->source == PGC_S_FILE && - is_member_of_role(GetUserId(), ROLE_PG_READ_ALL_SETTINGS)) + has_privs_of_role(GetUserId(), ROLE_PG_READ_ALL_SETTINGS)) { values[14] = conf->sourcefile; snprintf(buffer, sizeof(buffer), "%d", conf->sourceline); |