diff options
| author | Tom Lane | 2022-04-06 17:24:33 +0000 |
|---|---|---|
| committer | Tom Lane | 2022-04-06 17:24:33 +0000 |
| commit | a0ffa885e478f5eeacc4e250e35ce25a4740c487 (patch) | |
| tree | 7ce236305d5eb50f34bfccaf9a662cf3f0b77adf /src/bin | |
| parent | 2ef6f11b0c77ec323c688ddfd98ffabddb72c11d (diff) | |
Allow granting SET and ALTER SYSTEM privileges on GUC parameters.
This patch allows "PGC_SUSET" parameters to be set by non-superusers
if they have been explicitly granted the privilege to do so.
The privilege to perform ALTER SYSTEM SET/RESET on a specific parameter
can also be granted.
Such privileges are cluster-wide, not per database. They are tracked
in a new shared catalog, pg_parameter_acl.
Granting and revoking these new privileges works as one would expect.
One caveat is that PGC_USERSET GUCs are unaffected by the SET privilege
--- one could wish that those were handled by a revocable grant to
PUBLIC, but they are not, because we couldn't make it robust enough
for GUCs defined by extensions.
Mark Dilger, reviewed at various times by Andrew Dunstan, Robert Haas,
Joshua Brindle, and myself
Discussion: https://postgr.es/m/3D691E20-C1D5-4B80-8BA5-6BEB63AF3029@enterprisedb.com
Diffstat (limited to 'src/bin')
| -rw-r--r-- | src/bin/pg_dump/dumputils.c | 7 | ||||
| -rw-r--r-- | src/bin/pg_dump/pg_dumpall.c | 65 | ||||
| -rw-r--r-- | src/bin/psql/tab-complete.c | 78 |
3 files changed, 140 insertions, 10 deletions
diff --git a/src/bin/pg_dump/dumputils.c b/src/bin/pg_dump/dumputils.c index 6086d57cf3a..3e68dfc78f9 100644 --- a/src/bin/pg_dump/dumputils.c +++ b/src/bin/pg_dump/dumputils.c @@ -37,7 +37,7 @@ static void AddAcl(PQExpBuffer aclbuf, const char *keyword, * nspname: the namespace the object is in (NULL if none); not pre-quoted * type: the object type (as seen in GRANT command: must be one of * TABLE, SEQUENCE, FUNCTION, PROCEDURE, LANGUAGE, SCHEMA, DATABASE, TABLESPACE, - * FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT) + * FOREIGN DATA WRAPPER, SERVER, PARAMETER or LARGE OBJECT) * acls: the ACL string fetched from the database * baseacls: the initial ACL string for this object * owner: username of object owner (will be passed through fmtId); can be @@ -501,6 +501,11 @@ do { \ CONVERT_PRIV('U', "USAGE"); else if (strcmp(type, "FOREIGN TABLE") == 0) CONVERT_PRIV('r', "SELECT"); + else if (strcmp(type, "PARAMETER") == 0) + { + CONVERT_PRIV('s', "SET"); + CONVERT_PRIV('A', "ALTER SYSTEM"); + } else if (strcmp(type, "LARGE OBJECT") == 0) { CONVERT_PRIV('r', "SELECT"); diff --git a/src/bin/pg_dump/pg_dumpall.c b/src/bin/pg_dump/pg_dumpall.c index 9c9f7c6d63c..2dc33627630 100644 --- a/src/bin/pg_dump/pg_dumpall.c +++ b/src/bin/pg_dump/pg_dumpall.c @@ -18,6 +18,7 @@ #include <time.h> #include <unistd.h> +#include "catalog/pg_authid_d.h" #include "common/connect.h" #include "common/file_utils.h" #include "common/logging.h" @@ -36,6 +37,7 @@ static void help(void); static void dropRoles(PGconn *conn); static void dumpRoles(PGconn *conn); static void dumpRoleMembership(PGconn *conn); +static void dumpRoleGUCPrivs(PGconn *conn); static void dropTablespaces(PGconn *conn); static void dumpTablespaces(PGconn *conn); static void dropDBs(PGconn *conn); @@ -585,6 +587,10 @@ main(int argc, char *argv[]) /* Dump role memberships */ dumpRoleMembership(conn); + + /* Dump role GUC privileges */ + if (server_version >= 150000 && !skip_acls) + dumpRoleGUCPrivs(conn); } /* Dump tablespaces */ @@ -990,6 +996,65 @@ dumpRoleMembership(PGconn *conn) /* + * Dump role configuration parameter privileges. This code is used for 15.0 + * and later servers. + * + * Note: we expect dumpRoles already created all the roles, but there are + * no per-role configuration parameter privileges yet. + */ +static void +dumpRoleGUCPrivs(PGconn *conn) +{ + PGresult *res; + int i; + + /* + * Get all parameters that have non-default acls defined. + */ + res = executeQuery(conn, "SELECT parname, " + "pg_catalog.pg_get_userbyid(" CppAsString2(BOOTSTRAP_SUPERUSERID) ") AS parowner, " + "paracl, " + "pg_catalog.acldefault('p', " CppAsString2(BOOTSTRAP_SUPERUSERID) ") AS acldefault " + "FROM pg_catalog.pg_parameter_acl " + "ORDER BY 1"); + + if (PQntuples(res) > 0) + fprintf(OPF, "--\n-- Role privileges on configuration parameters\n--\n\n"); + + for (i = 0; i < PQntuples(res); i++) + { + PQExpBuffer buf = createPQExpBuffer(); + char *parname = PQgetvalue(res, i, 0); + char *parowner = PQgetvalue(res, i, 1); + char *paracl = PQgetvalue(res, i, 2); + char *acldefault = PQgetvalue(res, i, 3); + char *fparname; + + /* needed for buildACLCommands() */ + fparname = pg_strdup(fmtId(parname)); + + if (!buildACLCommands(fparname, NULL, NULL, "PARAMETER", + paracl, acldefault, + parowner, "", server_version, buf)) + { + pg_log_error("could not parse ACL list (%s) for parameter \"%s\"", + paracl, parname); + PQfinish(conn); + exit_nicely(1); + } + + fprintf(OPF, "%s", buf->data); + + free(fparname); + destroyPQExpBuffer(buf); + } + + PQclear(res); + fprintf(OPF, "\n\n"); +} + + +/* * Drop tablespaces. */ static void diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c index 645d46ab75a..32d0b4855f5 100644 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@ -3737,7 +3737,8 @@ psql_completion(const char *text, int start, int end) * ALTER DEFAULT PRIVILEGES, so use TailMatches */ /* Complete GRANT/REVOKE with a list of roles and privileges */ - else if (TailMatches("GRANT|REVOKE")) + else if (TailMatches("GRANT|REVOKE") || + TailMatches("REVOKE", "GRANT", "OPTION", "FOR")) { /* * With ALTER DEFAULT PRIVILEGES, restrict completion to grantable @@ -3749,6 +3750,7 @@ psql_completion(const char *text, int start, int end) "EXECUTE", "USAGE", "ALL"); else COMPLETE_WITH_QUERY_PLUS(Query_for_list_of_roles, + "GRANT", "SELECT", "INSERT", "UPDATE", @@ -3761,14 +3763,48 @@ psql_completion(const char *text, int start, int end) "TEMPORARY", "EXECUTE", "USAGE", + "SET", + "ALTER SYSTEM", "ALL"); } + else if (TailMatches("REVOKE", "GRANT")) + COMPLETE_WITH("OPTION FOR"); + else if (TailMatches("REVOKE", "GRANT", "OPTION")) + COMPLETE_WITH("FOR"); + + else if (TailMatches("GRANT|REVOKE", "ALTER") || + TailMatches("REVOKE", "GRANT", "OPTION", "FOR", "ALTER")) + COMPLETE_WITH("SYSTEM"); + + else if (TailMatches("GRANT|REVOKE", "SET") || + TailMatches("REVOKE", "GRANT", "OPTION", "FOR", "SET") || + TailMatches("GRANT|REVOKE", "ALTER", "SYSTEM") || + TailMatches("REVOKE", "GRANT", "OPTION", "FOR", "ALTER", "SYSTEM")) + COMPLETE_WITH("ON PARAMETER"); + + else if (TailMatches("GRANT|REVOKE", MatchAny, "ON", "PARAMETER") || + TailMatches("GRANT|REVOKE", MatchAny, MatchAny, "ON", "PARAMETER") || + TailMatches("REVOKE", "GRANT", "OPTION", "FOR", MatchAny, "ON", "PARAMETER") || + TailMatches("REVOKE", "GRANT", "OPTION", "FOR", MatchAny, MatchAny, "ON", "PARAMETER")) + COMPLETE_WITH_QUERY(Query_for_list_of_alter_system_set_vars); + + else if (TailMatches("GRANT", MatchAny, "ON", "PARAMETER", MatchAny) || + TailMatches("GRANT", MatchAny, MatchAny, "ON", "PARAMETER", MatchAny)) + COMPLETE_WITH("TO"); + + else if (TailMatches("REVOKE", MatchAny, "ON", "PARAMETER", MatchAny) || + TailMatches("REVOKE", MatchAny, MatchAny, "ON", "PARAMETER", MatchAny) || + TailMatches("REVOKE", "GRANT", "OPTION", "FOR", MatchAny, "ON", "PARAMETER", MatchAny) || + TailMatches("REVOKE", "GRANT", "OPTION", "FOR", MatchAny, MatchAny, "ON", "PARAMETER", MatchAny)) + COMPLETE_WITH("FROM"); + /* * Complete GRANT/REVOKE <privilege> with "ON", GRANT/REVOKE <role> with * TO/FROM */ - else if (TailMatches("GRANT|REVOKE", MatchAny)) + else if (TailMatches("GRANT|REVOKE", MatchAny) || + TailMatches("REVOKE", "GRANT", "OPTION", "FOR", MatchAny)) { if (TailMatches("SELECT|INSERT|UPDATE|DELETE|TRUNCATE|REFERENCES|TRIGGER|CREATE|CONNECT|TEMPORARY|TEMP|EXECUTE|USAGE|ALL")) COMPLETE_WITH("ON"); @@ -3785,7 +3821,8 @@ psql_completion(const char *text, int start, int end) * here will only work if the privilege list contains exactly one * privilege. */ - else if (TailMatches("GRANT|REVOKE", MatchAny, "ON")) + else if (TailMatches("GRANT|REVOKE", MatchAny, "ON") || + TailMatches("REVOKE", "GRANT", "OPTION", "FOR", MatchAny, "ON")) { /* * With ALTER DEFAULT PRIVILEGES, restrict completion to the kinds of @@ -3807,6 +3844,7 @@ psql_completion(const char *text, int start, int end) "FUNCTION", "LANGUAGE", "LARGE OBJECT", + "PARAMETER", "PROCEDURE", "ROUTINE", "SCHEMA", @@ -3815,13 +3853,15 @@ psql_completion(const char *text, int start, int end) "TABLESPACE", "TYPE"); } - else if (TailMatches("GRANT|REVOKE", MatchAny, "ON", "ALL")) + else if (TailMatches("GRANT|REVOKE", MatchAny, "ON", "ALL") || + TailMatches("REVOKE", "GRANT", "OPTION", "FOR", MatchAny, "ON", "ALL")) COMPLETE_WITH("FUNCTIONS IN SCHEMA", "PROCEDURES IN SCHEMA", "ROUTINES IN SCHEMA", "SEQUENCES IN SCHEMA", "TABLES IN SCHEMA"); - else if (TailMatches("GRANT|REVOKE", MatchAny, "ON", "FOREIGN")) + else if (TailMatches("GRANT|REVOKE", MatchAny, "ON", "FOREIGN") || + TailMatches("REVOKE", "GRANT", "OPTION", "FOR", MatchAny, "ON", "FOREIGN")) COMPLETE_WITH("DATA WRAPPER", "SERVER"); /* @@ -3830,7 +3870,8 @@ psql_completion(const char *text, int start, int end) * * Complete "GRANT/REVOKE * ON *" with "TO/FROM". */ - else if (TailMatches("GRANT|REVOKE", MatchAny, "ON", MatchAny)) + else if (TailMatches("GRANT|REVOKE", MatchAny, "ON", MatchAny) || + TailMatches("REVOKE", "GRANT", "OPTION", "FOR", MatchAny, "ON", MatchAny)) { if (TailMatches("DATABASE")) COMPLETE_WITH_QUERY(Query_for_list_of_databases); @@ -3868,6 +3909,22 @@ psql_completion(const char *text, int start, int end) (HeadMatches("REVOKE") && TailMatches("FROM"))) COMPLETE_WITH_QUERY_PLUS(Query_for_list_of_roles, Keywords_for_list_of_grant_roles); + + /* + * Offer grant options after that. + */ + else if (HeadMatches("GRANT") && TailMatches("TO", MatchAny)) + COMPLETE_WITH("WITH ADMIN OPTION", + "WITH GRANT OPTION", + "GRANTED BY"); + else if (HeadMatches("GRANT") && TailMatches("TO", MatchAny, "WITH")) + COMPLETE_WITH("ADMIN OPTION", + "GRANT OPTION"); + else if (HeadMatches("GRANT") && TailMatches("TO", MatchAny, "WITH", MatchAny, "OPTION")) + COMPLETE_WITH("GRANTED BY"); + else if (HeadMatches("GRANT") && TailMatches("TO", MatchAny, "WITH", MatchAny, "OPTION", "GRANTED", "BY")) + COMPLETE_WITH_QUERY_PLUS(Query_for_list_of_roles, + Keywords_for_list_of_grant_roles); /* Complete "ALTER DEFAULT PRIVILEGES ... GRANT/REVOKE ... TO/FROM */ else if (HeadMatches("ALTER", "DEFAULT", "PRIVILEGES") && TailMatches("TO|FROM")) COMPLETE_WITH_QUERY_PLUS(Query_for_list_of_roles, @@ -3879,7 +3936,8 @@ psql_completion(const char *text, int start, int end) COMPLETE_WITH("FROM"); /* Complete "GRANT/REVOKE * ON ALL * IN SCHEMA *" with TO/FROM */ - else if (TailMatches("GRANT|REVOKE", MatchAny, "ON", "ALL", MatchAny, "IN", "SCHEMA", MatchAny)) + else if (TailMatches("GRANT|REVOKE", MatchAny, "ON", "ALL", MatchAny, "IN", "SCHEMA", MatchAny) || + TailMatches("REVOKE", "GRANT", "OPTION", "FOR", MatchAny, "ON", "ALL", MatchAny, "IN", "SCHEMA", MatchAny)) { if (TailMatches("GRANT", MatchAny, MatchAny, MatchAny, MatchAny, MatchAny, MatchAny, MatchAny)) COMPLETE_WITH("TO"); @@ -3888,7 +3946,8 @@ psql_completion(const char *text, int start, int end) } /* Complete "GRANT/REVOKE * ON FOREIGN DATA WRAPPER *" with TO/FROM */ - else if (TailMatches("GRANT|REVOKE", MatchAny, "ON", "FOREIGN", "DATA", "WRAPPER", MatchAny)) + else if (TailMatches("GRANT|REVOKE", MatchAny, "ON", "FOREIGN", "DATA", "WRAPPER", MatchAny) || + TailMatches("REVOKE", "GRANT", "OPTION", "FOR", MatchAny, "ON", "FOREIGN", "DATA", "WRAPPER", MatchAny)) { if (TailMatches("GRANT", MatchAny, MatchAny, MatchAny, MatchAny, MatchAny, MatchAny)) COMPLETE_WITH("TO"); @@ -3897,7 +3956,8 @@ psql_completion(const char *text, int start, int end) } /* Complete "GRANT/REVOKE * ON FOREIGN SERVER *" with TO/FROM */ - else if (TailMatches("GRANT|REVOKE", MatchAny, "ON", "FOREIGN", "SERVER", MatchAny)) + else if (TailMatches("GRANT|REVOKE", MatchAny, "ON", "FOREIGN", "SERVER", MatchAny) || + TailMatches("REVOKE", "GRANT", "OPTION", "FOR", MatchAny, "ON", "FOREIGN", "SERVER", MatchAny)) { if (TailMatches("GRANT", MatchAny, MatchAny, MatchAny, MatchAny, MatchAny)) COMPLETE_WITH("TO"); |
