mirror of
https://github.com/postgres/postgres.git
synced 2025-06-22 02:52:08 +03:00
Revert MAINTAIN privilege and pg_maintain predefined role.
This reverts the following commits:4dbdb82513
,c2122aae63
,5b1a879943
,9e1e9d6560
,ff9618e82a
,60684dd834
,4441fc704d
, andb5d6382496
. A role with the MAINTAIN privilege may be able to use search_path tricks to escalate privileges to the table owner. Unfortunately, it is too late in the v16 development cycle to apply the proposed fix, i.e., restricting search_path when running maintenance commands. Bumps catversion. Reviewed-by: Jeff Davis Discussion: https://postgr.es/m/E1q7j7Y-000z1H-Hr%40gemulon.postgresql.org Backpatch-through: 16
This commit is contained in:
@ -26,7 +26,6 @@
|
||||
#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"
|
||||
@ -2829,7 +2828,6 @@ 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
|
||||
@ -2869,19 +2867,14 @@ RangeVarCallbackForReindexIndex(const RangeVar *relation,
|
||||
errmsg("\"%s\" is not an index", relation->relname)));
|
||||
|
||||
/* Check permissions */
|
||||
table_oid = IndexGetRelation(relId, true);
|
||||
if (OidIsValid(table_oid))
|
||||
{
|
||||
AclResult aclresult;
|
||||
|
||||
aclresult = pg_class_aclcheck(table_oid, GetUserId(), ACL_MAINTAIN);
|
||||
if (aclresult != ACLCHECK_OK)
|
||||
aclcheck_error(aclresult, OBJECT_INDEX, relation->relname);
|
||||
}
|
||||
if (!object_ownercheck(RelationRelationId, relId, GetUserId()))
|
||||
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.
|
||||
@ -2916,7 +2909,7 @@ ReindexTable(RangeVar *relation, ReindexParams *params, bool isTopLevel)
|
||||
(params->options & REINDEXOPT_CONCURRENTLY) != 0 ?
|
||||
ShareUpdateExclusiveLock : ShareLock,
|
||||
0,
|
||||
RangeVarCallbackMaintainsTable, NULL);
|
||||
RangeVarCallbackOwnsTable, NULL);
|
||||
|
||||
if (get_rel_relkind(heapOid) == RELKIND_PARTITIONED_TABLE)
|
||||
ReindexPartitions(heapOid, params, isTopLevel);
|
||||
@ -2998,8 +2991,7 @@ ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind,
|
||||
{
|
||||
objectOid = get_namespace_oid(objectName, false);
|
||||
|
||||
if (!object_ownercheck(NamespaceRelationId, objectOid, GetUserId()) &&
|
||||
!has_privs_of_role(GetUserId(), ROLE_PG_MAINTAIN))
|
||||
if (!object_ownercheck(NamespaceRelationId, objectOid, GetUserId()))
|
||||
aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_SCHEMA,
|
||||
objectName);
|
||||
}
|
||||
@ -3011,8 +3003,7 @@ 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()) &&
|
||||
!has_privs_of_role(GetUserId(), ROLE_PG_MAINTAIN))
|
||||
if (!object_ownercheck(DatabaseRelationId, objectOid, GetUserId()))
|
||||
aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_DATABASE,
|
||||
get_database_name(objectOid));
|
||||
}
|
||||
@ -3084,12 +3075,15 @@ ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind,
|
||||
continue;
|
||||
|
||||
/*
|
||||
* We already checked privileges on the database or schema, but we
|
||||
* further restrict reindexing shared catalogs to roles with the
|
||||
* MAINTAIN privilege on the relation.
|
||||
* 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.
|
||||
*/
|
||||
if (classtuple->relisshared &&
|
||||
pg_class_aclcheck(relid, GetUserId(), ACL_MAINTAIN) != ACLCHECK_OK)
|
||||
!object_ownercheck(RelationRelationId, relid, GetUserId()))
|
||||
continue;
|
||||
|
||||
/*
|
||||
|
Reference in New Issue
Block a user