aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands/indexcmds.c
diff options
context:
space:
mode:
authorJeff Davis <jdavis@postgresql.org>2022-12-13 17:33:28 -0800
committerJeff Davis <jdavis@postgresql.org>2022-12-13 17:33:28 -0800
commit60684dd834a222fefedd49b19d1f0a6189c1632e (patch)
treea7452cf4aec03f4bed616662832ebcb8caac11a6 /src/backend/commands/indexcmds.c
parentc6f6646bb0bef315c3836f3f6909c24a985a8621 (diff)
downloadpostgresql-60684dd834a222fefedd49b19d1f0a6189c1632e.tar.gz
postgresql-60684dd834a222fefedd49b19d1f0a6189c1632e.zip
Add grantable MAINTAIN privilege and pg_maintain role.
Allows VACUUM, ANALYZE, REINDEX, REFRESH MATERIALIZED VIEW, CLUSTER, and LOCK TABLE. Effectively reverts 4441fc704d. Instead of creating separate privileges for VACUUM, ANALYZE, and other maintenance commands, group them together under a single MAINTAIN privilege. Author: Nathan Bossart Discussion: https://postgr.es/m/20221212210136.GA449764@nathanxps13 Discussion: https://postgr.es/m/45224.1670476523@sss.pgh.pa.us
Diffstat (limited to 'src/backend/commands/indexcmds.c')
-rw-r--r--src/backend/commands/indexcmds.c36
1 files changed, 22 insertions, 14 deletions
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b5b860c3abf..7dc1aca8fe6 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -26,6 +26,7 @@
#include "catalog/index.h"
#include "catalog/indexing.h"
#include "catalog/pg_am.h"
+#include "catalog/pg_authid.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_database.h"
#include "catalog/pg_inherits.h"
@@ -2754,6 +2755,7 @@ RangeVarCallbackForReindexIndex(const RangeVar *relation,
char relkind;
struct ReindexIndexCallbackState *state = arg;
LOCKMODE table_lockmode;
+ Oid table_oid;
/*
* Lock level here should match table lock in reindex_index() for
@@ -2793,14 +2795,16 @@ RangeVarCallbackForReindexIndex(const RangeVar *relation,
errmsg("\"%s\" is not an index", relation->relname)));
/* Check permissions */
- if (!object_ownercheck(RelationRelationId, relId, GetUserId()))
- aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_INDEX, relation->relname);
+ table_oid = IndexGetRelation(relId, true);
+ if (!object_ownercheck(RelationRelationId, relId, GetUserId()) &&
+ OidIsValid(table_oid) &&
+ pg_class_aclcheck(table_oid, GetUserId(), ACL_MAINTAIN) != ACLCHECK_OK)
+ aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_INDEX,
+ relation->relname);
/* Lock heap before index to avoid deadlock. */
if (relId != oldRelId)
{
- Oid table_oid = IndexGetRelation(relId, true);
-
/*
* If the OID isn't valid, it means the index was concurrently
* dropped, which is not a problem for us; just return normally.
@@ -2835,7 +2839,7 @@ ReindexTable(RangeVar *relation, ReindexParams *params, bool isTopLevel)
(params->options & REINDEXOPT_CONCURRENTLY) != 0 ?
ShareUpdateExclusiveLock : ShareLock,
0,
- RangeVarCallbackOwnsTable, NULL);
+ RangeVarCallbackMaintainsTable, NULL);
if (get_rel_relkind(heapOid) == RELKIND_PARTITIONED_TABLE)
ReindexPartitions(heapOid, params, isTopLevel);
@@ -2917,7 +2921,8 @@ ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind,
{
objectOid = get_namespace_oid(objectName, false);
- if (!object_ownercheck(NamespaceRelationId, objectOid, GetUserId()))
+ if (!object_ownercheck(NamespaceRelationId, objectOid, GetUserId()) &&
+ !has_privs_of_role(GetUserId(), ROLE_PG_MAINTAIN))
aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_SCHEMA,
objectName);
}
@@ -2929,7 +2934,8 @@ ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind,
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("can only reindex the currently open database")));
- if (!object_ownercheck(DatabaseRelationId, objectOid, GetUserId()))
+ if (!object_ownercheck(DatabaseRelationId, objectOid, GetUserId()) &&
+ !has_privs_of_role(GetUserId(), ROLE_PG_MAINTAIN))
aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_DATABASE,
get_database_name(objectOid));
}
@@ -3001,15 +3007,17 @@ ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind,
continue;
/*
- * The table can be reindexed if the user is superuser, the table
- * owner, or the database/schema owner (but in the latter case, only
- * if it's not a shared relation). object_ownercheck includes the
- * superuser case, and depending on objectKind we already know that
- * the user has permission to run REINDEX on this database or schema
- * per the permission checks at the beginning of this routine.
+ * The table can be reindexed if the user has been granted MAINTAIN on
+ * the table or the user is a superuser, the table owner, or the
+ * database/schema owner (but in the latter case, only if it's not a
+ * shared relation). object_ownercheck includes the superuser case,
+ * and depending on objectKind we already know that the user has
+ * permission to run REINDEX on this database or schema per the
+ * permission checks at the beginning of this routine.
*/
if (classtuple->relisshared &&
- !object_ownercheck(RelationRelationId, relid, GetUserId()))
+ !object_ownercheck(RelationRelationId, relid, GetUserId()) &&
+ pg_class_aclcheck(relid, GetUserId(), ACL_MAINTAIN) != ACLCHECK_OK)
continue;
/*