Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions gpcontrib/gp_toolkit/Makefile
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
EXTENSION = gp_toolkit
DATA = gp_toolkit--1.1--1.2.sql gp_toolkit--1.0--1.1.sql gp_toolkit--1.0.sql \
gp_toolkit--1.2--1.3.sql gp_toolkit--1.3.sql gp_toolkit--1.3--1.4.sql \
gp_toolkit--1.4--1.5.sql gp_toolkit--1.5--1.6.sql
gp_toolkit--1.4--1.5.sql gp_toolkit--1.5--1.6.sql gp_toolkit--1.6--1.7.sql
MODULE_big = gp_toolkit
ifeq ($(shell uname -s), Linux)
OBJS = resgroup.o gp_partition_maint.o
OBJS = resgroup.o gp_partition_maint.o mdb_admin.o
else
OBJS = resgroup-dummy.o gp_partition_maint.o
OBJS = resgroup-dummy.o gp_partition_maint.o mdb_admin.o
endif

REGRESS = resource_manager_restore_to_none gp_toolkit resource_manager_switch_to_queue gp_toolkit_resqueue gp_toolkit_ao_funcs gp_partition_maint
REGRESS = resource_manager_restore_to_none gp_toolkit gp_toolkit_mdb_admin resource_manager_switch_to_queue gp_toolkit_resqueue gp_toolkit_ao_funcs gp_partition_maint
EXTRA_REGRESS_OPTS = --init-file=$(top_builddir)/src/test/regress/init_file

ifdef USE_PGXS
Expand Down
46 changes: 46 additions & 0 deletions gpcontrib/gp_toolkit/expected/gp_toolkit_mdb_admin.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
-- Tests for gp_toolkit.pg_create_mdb_admin_role(): creation of the
-- fixed-OID mdb_admin role and the resource-group permission gate it
-- enables. gp_toolkit is installed in template1 by gpinitsystem, so the
-- extension is already present in this database.
-- ---------------------------------------------------------------------
-- pg_create_mdb_admin_role() creates the mdb_admin role with its fixed OID.
-- ---------------------------------------------------------------------
SELECT gp_toolkit.pg_create_mdb_admin_role() AS mdb_admin_oid;
mdb_admin_oid
---------------
8067
(1 row)

-- The role exists with the fixed OID and is a non-login, non-superuser,
-- connection-limited role.
SELECT oid = 8067 AS has_fixed_oid, rolcanlogin, rolsuper,
rolcreaterole, rolcreatedb, rolconnlimit
FROM pg_authid WHERE rolname = 'mdb_admin';
has_fixed_oid | rolcanlogin | rolsuper | rolcreaterole | rolcreatedb | rolconnlimit
---------------+-------------+----------+---------------+-------------+--------------
t | f | f | f | f | 0
(1 row)

-- Creating it a second time is rejected.
SELECT gp_toolkit.pg_create_mdb_admin_role();
ERROR: role with OID 8067 already exists
-- ---------------------------------------------------------------------
-- Resource-group permission gate: a role that is not a member of mdb_admin
-- is rejected on every entry point. These checks run before the "resource
-- group is enabled" check, so they are deterministic regardless of the
-- resource manager in use.
-- ---------------------------------------------------------------------
CREATE ROLE regress_rg_noadmin;
SET ROLE regress_rg_noadmin;
CREATE RESOURCE GROUP regress_rg_x WITH (concurrency=1, cpu_max_percent=5);
ERROR: must be mdb_admin to create resource groups
ALTER RESOURCE GROUP regress_rg_x SET cpu_max_percent 6;
ERROR: must be mdb_admin to alter resource groups
DROP RESOURCE GROUP regress_rg_x;
ERROR: must be mdb_admin to drop resource groups
RESET ROLE;
DROP ROLE regress_rg_noadmin;
-- ---------------------------------------------------------------------
-- Cleanup.
-- ---------------------------------------------------------------------
DROP ROLE mdb_admin;
21 changes: 21 additions & 0 deletions gpcontrib/gp_toolkit/gp_toolkit--1.6--1.7.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/* gpcontrib/gp_toolkit/gp_toolkit--1.6--1.7.sql */

-- complain if script is sourced in psql, rather than via ALTER EXTENSION
\echo Use "ALTER EXTENSION gp_toolkit UPDATE TO '1.7'" to load this file. \quit

-- Create the mdb_admin privilege role with its fixed OID (8067).
--
-- The server lets members of mdb_admin CREATE/ALTER/DROP resource groups and
-- run pg_resgroup_move_query() without superuser. The role is identified by
-- a fixed, well-known OID rather than by name, so it must be created through
-- this function (a plain CREATE ROLE would assign an ordinary OID and the
-- permission checks would not recognise its members). The OID assignment is
-- dispatched to the segments, so the role has the same OID cluster-wide.
--
-- Typical usage (once per cluster, as superuser):
-- SELECT gp_toolkit.pg_create_mdb_admin_role();
-- GRANT mdb_admin TO cloud_admin;
CREATE FUNCTION gp_toolkit.pg_create_mdb_admin_role()
RETURNS OID
AS 'gp_toolkit.so', 'pg_create_mdb_admin_role'
LANGUAGE C STRICT;
2 changes: 1 addition & 1 deletion gpcontrib/gp_toolkit/gp_toolkit.control
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# gp_toolkit extension

comment = 'various GPDB administrative views/functions'
default_version = '1.6'
default_version = '1.7'
schema = gp_toolkit
86 changes: 86 additions & 0 deletions gpcontrib/gp_toolkit/mdb_admin.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*-------------------------------------------------------------------------
*
* mdb_admin.c
* Provisioning of the mdb_admin privilege role
*
* gpcontrib/gp_toolkit/mdb_admin.c
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"

#include "catalog/oid_dispatch.h"
#include "catalog/pg_authid.h"
#include "commands/user.h"
#include "fmgr.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/parsenodes.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/syscache.h"

/* Name of the mdb_admin role; its OID is MDB_ADMIN_ROLEID (see acl.h). */
#define MDB_ADMIN_ROLE_NAME "mdb_admin"

PG_FUNCTION_INFO_V1(pg_create_mdb_admin_role);

/*
* Create the mdb_admin role with its fixed OID (MDB_ADMIN_ROLEID, 8067).
*
* The core privilege checks identify mdb_admin by this fixed OID (see acl.c
* and resgroupcmds.c), so the role must always be created with it. On a
* Cloudberry cluster the OID is dispatched to the segments so the role ends
* up with the same OID everywhere. Returns the new role's OID.
*/
Datum
pg_create_mdb_admin_role(PG_FUNCTION_ARGS)
{
CreateRoleStmt stmt;
List *options = NIL;
Oid roleid;

/*
* Only a superuser may establish the mdb_admin privilege role. Otherwise
* a CREATEROLE user could drop mdb_admin and re-create it (CreateRole only
* requires CREATEROLE), taking ownership of the fixed-OID role and
* granting the capability to itself.
*/
if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser to create the mdb_admin role")));

/* Check if a role with the fixed OID already exists. */
if (SearchSysCacheExists1(AUTHOID, ObjectIdGetDatum(MDB_ADMIN_ROLEID)))
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("role with OID %u already exists", MDB_ADMIN_ROLEID)));

/* Check if a role named "mdb_admin" already exists. */
if (SearchSysCacheExists1(AUTHNAME, CStringGetDatum(MDB_ADMIN_ROLE_NAME)))
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("role \"%s\" already exists", MDB_ADMIN_ROLE_NAME)));

/* Build options for CreateRole: connection limit = 0. */
options = list_make1(makeDefElem("connectionlimit",
(Node *) makeInteger(0), -1));

/* Prepare the CreateRoleStmt. */
memset(&stmt, 0, sizeof(stmt));
stmt.type = T_CreateRoleStmt;
stmt.stmt_type = ROLESTMT_ROLE;
stmt.role = MDB_ADMIN_ROLE_NAME;
stmt.options = options;

/*
* Request the fixed OID for the role. GetNewOidForAuthId() consumes and
* clears this override.
*/
next_aux_pg_authid_oid = MDB_ADMIN_ROLEID;

roleid = CreateRole(NULL, &stmt);

PG_RETURN_OID(roleid);
}
37 changes: 37 additions & 0 deletions gpcontrib/gp_toolkit/sql/gp_toolkit_mdb_admin.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
-- Tests for gp_toolkit.pg_create_mdb_admin_role(): creation of the
-- fixed-OID mdb_admin role and the resource-group permission gate it
-- enables. gp_toolkit is installed in template1 by gpinitsystem, so the
-- extension is already present in this database.

-- ---------------------------------------------------------------------
-- pg_create_mdb_admin_role() creates the mdb_admin role with its fixed OID.
-- ---------------------------------------------------------------------
SELECT gp_toolkit.pg_create_mdb_admin_role() AS mdb_admin_oid;

-- The role exists with the fixed OID and is a non-login, non-superuser,
-- connection-limited role.
SELECT oid = 8067 AS has_fixed_oid, rolcanlogin, rolsuper,
rolcreaterole, rolcreatedb, rolconnlimit
FROM pg_authid WHERE rolname = 'mdb_admin';

-- Creating it a second time is rejected.
SELECT gp_toolkit.pg_create_mdb_admin_role();

-- ---------------------------------------------------------------------
-- Resource-group permission gate: a role that is not a member of mdb_admin
-- is rejected on every entry point. These checks run before the "resource
-- group is enabled" check, so they are deterministic regardless of the
-- resource manager in use.
-- ---------------------------------------------------------------------
CREATE ROLE regress_rg_noadmin;
SET ROLE regress_rg_noadmin;
CREATE RESOURCE GROUP regress_rg_x WITH (concurrency=1, cpu_max_percent=5);
ALTER RESOURCE GROUP regress_rg_x SET cpu_max_percent 6;
DROP RESOURCE GROUP regress_rg_x;
RESET ROLE;
DROP ROLE regress_rg_noadmin;

-- ---------------------------------------------------------------------
-- Cleanup.
-- ---------------------------------------------------------------------
DROP ROLE mdb_admin;
50 changes: 47 additions & 3 deletions src/backend/catalog/oid_dispatch.c
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,18 @@ static MemoryContext oids_context = NULL;

static bool preserve_oids_on_commit = false;

/*
* OID to assign to the next auxiliary pg_authid role created through
* GetNewOidForAuthId(), or InvalidOid for the normal allocation path.
*
* This is the GPDB analogue of upstream PostgreSQL's
* binary_upgrade_next_pg_authid_oid (which is disabled here in favour of the
* generic OID pre-assignment machinery). It lets gp_toolkit
* create roles such as mdb_admin with a fixed, well-known OID. It is reset
* to InvalidOid as soon as it is consumed.
*/
Oid next_aux_pg_authid_oid = InvalidOid;

/*
* These will be used by the schema restoration process during binary upgrade,
* so any new object must not use any Oid in this structure or else there will
Expand Down Expand Up @@ -423,6 +435,7 @@ GetNewOrPreassignedOid(Relation relation, Oid indexId, AttrNumber oidcolumn,
OidAssignment *searchkey)
{
Oid oid;
Oid forcedOid = searchkey->oid;

searchkey->catalog = RelationGetRelid(relation);

Expand Down Expand Up @@ -461,8 +474,18 @@ GetNewOrPreassignedOid(Relation relation, Oid indexId, AttrNumber oidcolumn,
{
MemoryContext oldcontext;

/* Assign a new oid, and memorize it in the list of OIDs to dispatch */
oid = GetNewOidWithIndex(relation, indexId, oidcolumn);
/*
* Assign a new oid, and memorize it in the list of OIDs to dispatch.
*
* A caller may request a fixed, well-known OID by passing it in
* searchkey->oid (e.g. the mdb_admin auxiliary role, see
* GetNewOidForAuthId()). In that case use the requested OID instead
* of allocating a fresh one, but still record it for dispatch so the
* QEs end up with the same OID.
*/
oid = OidIsValid(forcedOid)
? forcedOid
: GetNewOidWithIndex(relation, indexId, oidcolumn);

oldcontext = MemoryContextSwitchTo(get_oids_context());
searchkey->oid = oid;
Expand All @@ -479,7 +502,9 @@ GetNewOrPreassignedOid(Relation relation, Oid indexId, AttrNumber oidcolumn,
}
else
{
oid = GetNewOidWithIndex(relation, indexId, oidcolumn);
oid = OidIsValid(forcedOid)
? forcedOid
: GetNewOidWithIndex(relation, indexId, oidcolumn);
}

return oid;
Expand Down Expand Up @@ -572,6 +597,25 @@ GetNewOidForAuthId(Relation relation, Oid indexId, AttrNumber oidcolumn,
memset(&key, 0, sizeof(OidAssignment));
key.type = T_OidAssignment;
key.objname = rolname;

/*
* Allow auxiliary roles (such as mdb_admin, see gpcontrib/gp_toolkit)
* to be created with a fixed, well-known OID. The OID is supplied through
* the next_aux_pg_authid_oid override, mirroring how upstream PostgreSQL
* assigns role OIDs during binary upgrade. We only honor it for OIDs in
* the auxiliary range to avoid clashing with normal OID allocation, and
* reset it immediately so it affects a single role only.
*/
if (OidIsValid(next_aux_pg_authid_oid))
{
if (!IsAuxOid(next_aux_pg_authid_oid))
elog(ERROR, "pre-assigned auxiliary role OID %u is out of the auxiliary OID range",
next_aux_pg_authid_oid);

key.oid = next_aux_pg_authid_oid;
next_aux_pg_authid_oid = InvalidOid;
}

return GetNewOrPreassignedOid(relation, indexId, oidcolumn, &key);
}

Expand Down
Loading
Loading