1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-28 23:42:10 +03:00

Add "pg_database_owner" default role.

Membership consists, implicitly, of the current database owner.  Expect
use in template databases.  Once pg_database_owner has rights within a
template, each owner of a database instantiated from that template will
exercise those rights.

Reviewed by John Naylor.

Discussion: https://postgr.es/m/20201228043148.GA1053024@rfd.leadboat.com
This commit is contained in:
Noah Misch
2021-03-26 10:42:17 -07:00
parent f687bf61ed
commit a14a0118a1
11 changed files with 207 additions and 6 deletions

View File

@ -22,6 +22,7 @@
#include "catalog/pg_auth_members.h"
#include "catalog/pg_authid.h"
#include "catalog/pg_class.h"
#include "catalog/pg_database.h"
#include "catalog/pg_type.h"
#include "commands/dbcommands.h"
#include "commands/proclang.h"
@ -68,6 +69,7 @@ enum RoleRecurseType
};
static Oid cached_role[] = {InvalidOid, InvalidOid};
static List *cached_roles[] = {NIL, NIL};
static uint32 cached_db_hash;
static const char *getid(const char *s, char *n);
@ -4665,10 +4667,14 @@ initialize_acl(void)
{
if (!IsBootstrapProcessingMode())
{
cached_db_hash =
GetSysCacheHashValue1(DATABASEOID,
ObjectIdGetDatum(MyDatabaseId));
/*
* In normal mode, set a callback on any syscache invalidation of rows
* of pg_auth_members (for roles_is_member_of()) or pg_authid (for
* has_rolinherit())
* of pg_auth_members (for roles_is_member_of()), pg_authid (for
* has_rolinherit()), or pg_database (for roles_is_member_of())
*/
CacheRegisterSyscacheCallback(AUTHMEMROLEMEM,
RoleMembershipCacheCallback,
@ -4676,6 +4682,9 @@ initialize_acl(void)
CacheRegisterSyscacheCallback(AUTHOID,
RoleMembershipCacheCallback,
(Datum) 0);
CacheRegisterSyscacheCallback(DATABASEOID,
RoleMembershipCacheCallback,
(Datum) 0);
}
}
@ -4686,6 +4695,13 @@ initialize_acl(void)
static void
RoleMembershipCacheCallback(Datum arg, int cacheid, uint32 hashvalue)
{
if (cacheid == DATABASEOID &&
hashvalue != cached_db_hash &&
hashvalue != 0)
{
return; /* ignore pg_database changes for other DBs */
}
/* Force membership caches to be recomputed on next use */
cached_role[ROLERECURSE_PRIVS] = InvalidOid;
cached_role[ROLERECURSE_MEMBERS] = InvalidOid;
@ -4728,6 +4744,7 @@ static List *
roles_is_member_of(Oid roleid, enum RoleRecurseType type,
Oid admin_of, bool *is_admin)
{
Oid dba;
List *roles_list;
ListCell *l;
List *new_cached_roles;
@ -4740,6 +4757,24 @@ roles_is_member_of(Oid roleid, enum RoleRecurseType type,
OidIsValid(cached_role[type]))
return cached_roles[type];
/*
* Role expansion happens in a non-database backend when guc.c checks
* DEFAULT_ROLE_READ_ALL_SETTINGS for a physical walsender SHOW command.
* In that case, no role gets pg_database_owner.
*/
if (!OidIsValid(MyDatabaseId))
dba = InvalidOid;
else
{
HeapTuple dbtup;
dbtup = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(MyDatabaseId));
if (!HeapTupleIsValid(dbtup))
elog(ERROR, "cache lookup failed for database %u", MyDatabaseId);
dba = ((Form_pg_database) GETSTRUCT(dbtup))->datdba;
ReleaseSysCache(dbtup);
}
/*
* Find all the roles that roleid is a member of, including multi-level
* recursion. The role itself will always be the first element of the
@ -4787,6 +4822,11 @@ roles_is_member_of(Oid roleid, enum RoleRecurseType type,
roles_list = list_append_unique_oid(roles_list, otherid);
}
ReleaseSysCacheList(memlist);
/* implement pg_database_owner implicit membership */
if (memberid == dba && OidIsValid(dba))
roles_list = list_append_unique_oid(roles_list,
DEFAULT_ROLE_DATABASE_OWNER);
}
/*