mirror of
https://github.com/postgres/postgres.git
synced 2025-06-26 12:21:12 +03:00
Use a bitmask to represent role attributes
The previous representation using a boolean column for each attribute would not scale as well as we want to add further attributes. Extra auxilliary functions are added to go along with this change, to make up for the lost convenience of access of the old representation. Catalog version bumped due to change in catalogs and the new functions. Author: Adam Brightwell, minor tweaks by Álvaro Reviewed by: Stephen Frost, Andres Freund, Álvaro Herrera
This commit is contained in:
@ -27,6 +27,7 @@
|
||||
#include "miscadmin.h"
|
||||
#include "replication/walreceiver.h"
|
||||
#include "storage/smgr.h"
|
||||
#include "utils/acl.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/numeric.h"
|
||||
#include "utils/guc.h"
|
||||
@ -54,7 +55,7 @@ pg_start_backup(PG_FUNCTION_ARGS)
|
||||
|
||||
backupidstr = text_to_cstring(backupid);
|
||||
|
||||
if (!superuser() && !has_rolreplication(GetUserId()))
|
||||
if (!have_role_attribute(ROLE_ATTR_REPLICATION))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
errmsg("must be superuser or replication role to run a backup")));
|
||||
@ -82,7 +83,7 @@ pg_stop_backup(PG_FUNCTION_ARGS)
|
||||
{
|
||||
XLogRecPtr stoppoint;
|
||||
|
||||
if (!superuser() && !has_rolreplication(GetUserId()))
|
||||
if (!have_role_attribute(ROLE_ATTR_REPLICATION))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
(errmsg("must be superuser or replication role to run a backup"))));
|
||||
|
@ -176,7 +176,7 @@ sub Catalogs
|
||||
}
|
||||
}
|
||||
}
|
||||
$catalogs{$catname} = \%catalog;
|
||||
$catalogs{$catname} = \%catalog if defined $catname;
|
||||
close INPUT_FILE;
|
||||
}
|
||||
return \%catalogs;
|
||||
|
@ -28,7 +28,7 @@ all: $(BKIFILES) schemapg.h
|
||||
# indexing.h had better be last, and toasting.h just before it.
|
||||
|
||||
POSTGRES_BKI_SRCS = $(addprefix $(top_srcdir)/src/include/catalog/,\
|
||||
pg_proc.h pg_type.h pg_attribute.h pg_class.h \
|
||||
acldefs.h pg_proc.h pg_type.h pg_attribute.h pg_class.h \
|
||||
pg_attrdef.h pg_constraint.h pg_inherits.h pg_index.h pg_operator.h \
|
||||
pg_opfamily.h pg_opclass.h pg_am.h pg_amop.h pg_amproc.h \
|
||||
pg_language.h pg_largeobject_metadata.h pg_largeobject.h pg_aggregate.h \
|
||||
|
@ -3423,26 +3423,6 @@ aclcheck_error_type(AclResult aclerr, Oid typeOid)
|
||||
}
|
||||
|
||||
|
||||
/* Check if given user has rolcatupdate privilege according to pg_authid */
|
||||
static bool
|
||||
has_rolcatupdate(Oid roleid)
|
||||
{
|
||||
bool rolcatupdate;
|
||||
HeapTuple tuple;
|
||||
|
||||
tuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
|
||||
if (!HeapTupleIsValid(tuple))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
||||
errmsg("role with OID %u does not exist", roleid)));
|
||||
|
||||
rolcatupdate = ((Form_pg_authid) GETSTRUCT(tuple))->rolcatupdate;
|
||||
|
||||
ReleaseSysCache(tuple);
|
||||
|
||||
return rolcatupdate;
|
||||
}
|
||||
|
||||
/*
|
||||
* Relay for the various pg_*_mask routines depending on object kind
|
||||
*/
|
||||
@ -3630,7 +3610,7 @@ pg_class_aclmask(Oid table_oid, Oid roleid,
|
||||
if ((mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE | ACL_USAGE)) &&
|
||||
IsSystemClass(table_oid, classForm) &&
|
||||
classForm->relkind != RELKIND_VIEW &&
|
||||
!has_rolcatupdate(roleid) &&
|
||||
!has_role_attribute(roleid, ROLE_ATTR_CATUPDATE) &&
|
||||
!allowSystemTableMods)
|
||||
{
|
||||
#ifdef ACLDEBUG
|
||||
@ -5051,52 +5031,87 @@ pg_extension_ownercheck(Oid ext_oid, Oid roleid)
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether specified role has CREATEROLE privilege (or is a superuser)
|
||||
* has_role_attribute
|
||||
* Check if the role with the specified id has been assigned a specific role
|
||||
* attribute.
|
||||
*
|
||||
* Note: roles do not have owners per se; instead we use this test in
|
||||
* places where an ownership-like permissions test is needed for a role.
|
||||
* Be sure to apply it to the role trying to do the operation, not the
|
||||
* role being operated on! Also note that this generally should not be
|
||||
* considered enough privilege if the target role is a superuser.
|
||||
* (We don't handle that consideration here because we want to give a
|
||||
* separate error message for such cases, so the caller has to deal with it.)
|
||||
* roleid - the oid of the role to check.
|
||||
* attribute - the attribute to check.
|
||||
*
|
||||
* Note: Use this function for role attribute permission checking as it
|
||||
* accounts for superuser status. It will always return true for roles with
|
||||
* superuser privileges unless the attribute being checked is CATUPDATE
|
||||
* (superusers are not allowed to bypass CATUPDATE permissions).
|
||||
*
|
||||
* Note: roles do not have owners per se; instead we use this test in places
|
||||
* where an ownership-like permissions test is needed for a role. Be sure to
|
||||
* apply it to the role trying to do the operation, not the role being operated
|
||||
* on! Also note that this generally should not be considered enough privilege
|
||||
* if the target role is a superuser. (We don't handle that consideration here
|
||||
* because we want to give a separate error message for such cases, so the
|
||||
* caller has to deal with it.)
|
||||
*/
|
||||
bool
|
||||
has_createrole_privilege(Oid roleid)
|
||||
has_role_attribute(Oid roleid, RoleAttr attribute)
|
||||
{
|
||||
bool result = false;
|
||||
HeapTuple utup;
|
||||
|
||||
/* Superusers bypass all permission checking. */
|
||||
if (superuser_arg(roleid))
|
||||
/*
|
||||
* Superusers bypass all permission checking except in the case of CATUPDATE
|
||||
*/
|
||||
if (!(attribute & ROLE_ATTR_CATUPDATE) && superuser_arg(roleid))
|
||||
return true;
|
||||
|
||||
utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
|
||||
if (HeapTupleIsValid(utup))
|
||||
{
|
||||
result = ((Form_pg_authid) GETSTRUCT(utup))->rolcreaterole;
|
||||
ReleaseSysCache(utup);
|
||||
}
|
||||
return result;
|
||||
return check_role_attribute(roleid, attribute);
|
||||
}
|
||||
|
||||
/*
|
||||
* have_role_attribute
|
||||
* Convenience function for checking if the role id returned by GetUserId()
|
||||
* has been assigned a specific role attribute.
|
||||
*
|
||||
* attribute - the attribute to check.
|
||||
*/
|
||||
bool
|
||||
has_bypassrls_privilege(Oid roleid)
|
||||
have_role_attribute(RoleAttr attribute)
|
||||
{
|
||||
bool result = false;
|
||||
HeapTuple utup;
|
||||
return has_role_attribute(GetUserId(), attribute);
|
||||
}
|
||||
|
||||
/* Superusers bypass all permission checking. */
|
||||
if (superuser_arg(roleid))
|
||||
return true;
|
||||
/*
|
||||
* check_role_attribute
|
||||
* Check if the role with the specified id has been assigned a specific role
|
||||
* attribute.
|
||||
*
|
||||
* roleid - the oid of the role to check.
|
||||
* attribute - the attribute to check.
|
||||
*
|
||||
* Note: This function should only be used for checking the value of an
|
||||
* individual attribute in the rolattr bitmap and should *not* be used for
|
||||
* permission checking. For the purposes of permission checking use
|
||||
* 'has_role_attribute' instead.
|
||||
*/
|
||||
bool
|
||||
check_role_attribute(Oid roleid, RoleAttr attribute)
|
||||
{
|
||||
RoleAttr attributes;
|
||||
HeapTuple tuple;
|
||||
|
||||
utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
|
||||
if (HeapTupleIsValid(utup))
|
||||
{
|
||||
result = ((Form_pg_authid) GETSTRUCT(utup))->rolbypassrls;
|
||||
ReleaseSysCache(utup);
|
||||
}
|
||||
return result;
|
||||
/* ROLE_ATTR_NONE (zero) is not a valid attribute */
|
||||
Assert(attribute != ROLE_ATTR_NONE);
|
||||
|
||||
/* Check that only one bit is set in 'attribute' */
|
||||
Assert(!(attribute & (attribute - 1)));
|
||||
|
||||
tuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
|
||||
|
||||
if (!HeapTupleIsValid(tuple))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
||||
errmsg("role with OID %u does not exist", roleid)));
|
||||
|
||||
attributes = ((Form_pg_authid) GETSTRUCT(tuple))->rolattr;
|
||||
ReleaseSysCache(tuple);
|
||||
|
||||
return (attributes & attribute);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -90,6 +90,8 @@ my $BOOTSTRAP_SUPERUSERID =
|
||||
find_defined_symbol('pg_authid.h', 'BOOTSTRAP_SUPERUSERID');
|
||||
my $PG_CATALOG_NAMESPACE =
|
||||
find_defined_symbol('pg_namespace.h', 'PG_CATALOG_NAMESPACE');
|
||||
my $ROLE_ATTR_ALL =
|
||||
find_defined_symbol('acldefs.h', 'ROLE_ATTR_ALL');
|
||||
|
||||
# Read all the input header files into internal data structures
|
||||
my $catalogs = Catalog::Catalogs(@input_files);
|
||||
@ -144,6 +146,7 @@ foreach my $catname (@{ $catalogs->{names} })
|
||||
# substitute constant values we acquired above
|
||||
$row->{bki_values} =~ s/\bPGUID\b/$BOOTSTRAP_SUPERUSERID/g;
|
||||
$row->{bki_values} =~ s/\bPGNSP\b/$PG_CATALOG_NAMESPACE/g;
|
||||
$row->{bki_values} =~ s/\bPGROLATTRALL/$ROLE_ATTR_ALL/g;
|
||||
|
||||
# Save pg_type info for pg_attribute processing below
|
||||
if ($catname eq 'pg_type')
|
||||
|
@ -2884,7 +2884,12 @@ CREATE VIEW user_mapping_options AS
|
||||
CAST((pg_options_to_table(um.umoptions)).option_name AS sql_identifier) AS option_name,
|
||||
CAST(CASE WHEN (umuser <> 0 AND authorization_identifier = current_user)
|
||||
OR (umuser = 0 AND pg_has_role(srvowner, 'USAGE'))
|
||||
OR (SELECT rolsuper FROM pg_authid WHERE rolname = current_user) THEN (pg_options_to_table(um.umoptions)).option_value
|
||||
OR (
|
||||
SELECT pg_check_role_attribute(pg_authid.rolattr, 'SUPERUSER') AS rolsuper
|
||||
FROM pg_authid
|
||||
WHERE rolname = current_user
|
||||
)
|
||||
THEN (pg_options_to_table(um.umoptions)).option_value
|
||||
ELSE NULL END AS character_data) AS option_value
|
||||
FROM _pg_user_mappings um;
|
||||
|
||||
|
@ -1328,7 +1328,7 @@ check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address,
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!has_createrole_privilege(roleid))
|
||||
if (!has_role_attribute(roleid, ROLE_ATTR_CREATEROLE))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
errmsg("must have CREATEROLE privilege")));
|
||||
|
@ -9,17 +9,17 @@
|
||||
CREATE VIEW pg_roles AS
|
||||
SELECT
|
||||
rolname,
|
||||
rolsuper,
|
||||
rolinherit,
|
||||
rolcreaterole,
|
||||
rolcreatedb,
|
||||
rolcatupdate,
|
||||
rolcanlogin,
|
||||
rolreplication,
|
||||
pg_check_role_attribute(pg_authid.rolattr, 'SUPERUSER') AS rolsuper,
|
||||
pg_check_role_attribute(pg_authid.rolattr, 'INHERIT') AS rolinherit,
|
||||
pg_check_role_attribute(pg_authid.rolattr, 'CREATEROLE') AS rolcreaterole,
|
||||
pg_check_role_attribute(pg_authid.rolattr, 'CREATEDB') AS rolcreatedb,
|
||||
pg_check_role_attribute(pg_authid.rolattr, 'CATUPDATE') AS rolcatupdate,
|
||||
pg_check_role_attribute(pg_authid.rolattr, 'CANLOGIN') AS rolcanlogin,
|
||||
pg_check_role_attribute(pg_authid.rolattr, 'REPLICATION') AS rolreplication,
|
||||
pg_check_role_attribute(pg_authid.rolattr, 'BYPASSRLS') AS rolbypassrls,
|
||||
rolconnlimit,
|
||||
'********'::text as rolpassword,
|
||||
rolvaliduntil,
|
||||
rolbypassrls,
|
||||
setconfig as rolconfig,
|
||||
pg_authid.oid
|
||||
FROM pg_authid LEFT JOIN pg_db_role_setting s
|
||||
@ -29,16 +29,16 @@ CREATE VIEW pg_shadow AS
|
||||
SELECT
|
||||
rolname AS usename,
|
||||
pg_authid.oid AS usesysid,
|
||||
rolcreatedb AS usecreatedb,
|
||||
rolsuper AS usesuper,
|
||||
rolcatupdate AS usecatupd,
|
||||
rolreplication AS userepl,
|
||||
pg_check_role_attribute(pg_authid.rolattr, 'CREATEDB') AS usecreatedb,
|
||||
pg_check_role_attribute(pg_authid.rolattr, 'SUPERUSER') AS usesuper,
|
||||
pg_check_role_attribute(pg_authid.rolattr, 'CATUPDATE') AS usecatupd,
|
||||
pg_check_role_attribute(pg_authid.rolattr, 'REPLICATION') AS userepl,
|
||||
rolpassword AS passwd,
|
||||
rolvaliduntil::abstime AS valuntil,
|
||||
setconfig AS useconfig
|
||||
FROM pg_authid LEFT JOIN pg_db_role_setting s
|
||||
ON (pg_authid.oid = setrole AND setdatabase = 0)
|
||||
WHERE rolcanlogin;
|
||||
WHERE pg_check_role_attribute(pg_authid.rolattr, 'CANLOGIN');
|
||||
|
||||
REVOKE ALL on pg_shadow FROM public;
|
||||
|
||||
@ -48,7 +48,7 @@ CREATE VIEW pg_group AS
|
||||
oid AS grosysid,
|
||||
ARRAY(SELECT member FROM pg_auth_members WHERE roleid = oid) AS grolist
|
||||
FROM pg_authid
|
||||
WHERE NOT rolcanlogin;
|
||||
WHERE NOT pg_check_role_attribute(pg_authid.rolattr, 'CANLOGIN');
|
||||
|
||||
CREATE VIEW pg_user AS
|
||||
SELECT
|
||||
|
@ -85,7 +85,6 @@ static bool get_db_info(const char *name, LOCKMODE lockmode,
|
||||
Oid *dbLastSysOidP, TransactionId *dbFrozenXidP,
|
||||
MultiXactId *dbMinMultiP,
|
||||
Oid *dbTablespace, char **dbCollate, char **dbCtype);
|
||||
static bool have_createdb_privilege(void);
|
||||
static void remove_dbtablespaces(Oid db_id);
|
||||
static bool check_db_file_conflict(Oid db_id);
|
||||
static int errdetail_busy_db(int notherbackends, int npreparedxacts);
|
||||
@ -291,7 +290,7 @@ createdb(const CreatedbStmt *stmt)
|
||||
* "giveaway" attacks. Note that a superuser will always have both of
|
||||
* these privileges a fortiori.
|
||||
*/
|
||||
if (!have_createdb_privilege())
|
||||
if (!have_role_attribute(ROLE_ATTR_CREATEDB))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
errmsg("permission denied to create database")));
|
||||
@ -965,7 +964,7 @@ RenameDatabase(const char *oldname, const char *newname)
|
||||
oldname);
|
||||
|
||||
/* must have createdb rights */
|
||||
if (!have_createdb_privilege())
|
||||
if (!have_role_attribute(ROLE_ATTR_CREATEDB))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
errmsg("permission denied to rename database")));
|
||||
@ -1623,7 +1622,7 @@ AlterDatabaseOwner(const char *dbname, Oid newOwnerId)
|
||||
* databases. Because superusers will always have this right, we need
|
||||
* no special case for them.
|
||||
*/
|
||||
if (!have_createdb_privilege())
|
||||
if (!have_role_attribute(ROLE_ATTR_CREATEDB))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
errmsg("permission denied to change owner of database")));
|
||||
@ -1802,26 +1801,6 @@ get_db_info(const char *name, LOCKMODE lockmode,
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Check if current user has createdb privileges */
|
||||
static bool
|
||||
have_createdb_privilege(void)
|
||||
{
|
||||
bool result = false;
|
||||
HeapTuple utup;
|
||||
|
||||
/* Superusers can always do everything */
|
||||
if (superuser())
|
||||
return true;
|
||||
|
||||
utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(GetUserId()));
|
||||
if (HeapTupleIsValid(utup))
|
||||
{
|
||||
result = ((Form_pg_authid) GETSTRUCT(utup))->rolcreatedb;
|
||||
ReleaseSysCache(utup);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove tablespace directories
|
||||
*
|
||||
|
@ -56,14 +56,6 @@ static void DelRoleMems(const char *rolename, Oid roleid,
|
||||
bool admin_opt);
|
||||
|
||||
|
||||
/* Check if current user has createrole privileges */
|
||||
static bool
|
||||
have_createrole_privilege(void)
|
||||
{
|
||||
return has_createrole_privilege(GetUserId());
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* CREATE ROLE
|
||||
*/
|
||||
@ -81,13 +73,7 @@ CreateRole(CreateRoleStmt *stmt)
|
||||
char *password = NULL; /* user password */
|
||||
bool encrypt_password = Password_encryption; /* encrypt password? */
|
||||
char encrypted_password[MD5_PASSWD_LEN + 1];
|
||||
bool issuper = false; /* Make the user a superuser? */
|
||||
bool inherit = true; /* Auto inherit privileges? */
|
||||
bool createrole = false; /* Can this user create roles? */
|
||||
bool createdb = false; /* Can the user create databases? */
|
||||
bool canlogin = false; /* Can this user login? */
|
||||
bool isreplication = false; /* Is this a replication role? */
|
||||
bool bypassrls = false; /* Is this a row security enabled role? */
|
||||
RoleAttr attributes;
|
||||
int connlimit = -1; /* maximum connections allowed */
|
||||
List *addroleto = NIL; /* roles to make this a member of */
|
||||
List *rolemembers = NIL; /* roles to be members of this role */
|
||||
@ -109,13 +95,17 @@ CreateRole(CreateRoleStmt *stmt)
|
||||
DefElem *dvalidUntil = NULL;
|
||||
DefElem *dbypassRLS = NULL;
|
||||
|
||||
/* The defaults can vary depending on the original statement type */
|
||||
/*
|
||||
* Every role has INHERIT by default, and CANLOGIN depends on the statement
|
||||
* type.
|
||||
*/
|
||||
attributes = ROLE_ATTR_INHERIT;
|
||||
switch (stmt->stmt_type)
|
||||
{
|
||||
case ROLESTMT_ROLE:
|
||||
break;
|
||||
case ROLESTMT_USER:
|
||||
canlogin = true;
|
||||
attributes |= ROLE_ATTR_CANLOGIN;
|
||||
/* may eventually want inherit to default to false here */
|
||||
break;
|
||||
case ROLESTMT_GROUP:
|
||||
@ -249,18 +239,76 @@ CreateRole(CreateRoleStmt *stmt)
|
||||
|
||||
if (dpassword && dpassword->arg)
|
||||
password = strVal(dpassword->arg);
|
||||
|
||||
/* Set up role attributes and check permissions to set each of them */
|
||||
if (dissuper)
|
||||
issuper = intVal(dissuper->arg) != 0;
|
||||
{
|
||||
if (intVal(dissuper->arg) != 0)
|
||||
{
|
||||
if (!superuser())
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
errmsg("must be superuser to create superusers")));
|
||||
attributes |= ROLE_ATTR_SUPERUSER;
|
||||
}
|
||||
else
|
||||
attributes &= ~ROLE_ATTR_SUPERUSER;
|
||||
}
|
||||
if (dinherit)
|
||||
inherit = intVal(dinherit->arg) != 0;
|
||||
{
|
||||
if (intVal(dinherit->arg) != 0)
|
||||
attributes |= ROLE_ATTR_INHERIT;
|
||||
else
|
||||
attributes &= ~ROLE_ATTR_INHERIT;
|
||||
}
|
||||
if (dcreaterole)
|
||||
createrole = intVal(dcreaterole->arg) != 0;
|
||||
{
|
||||
if (intVal(dcreaterole->arg) != 0)
|
||||
attributes |= ROLE_ATTR_CREATEROLE;
|
||||
else
|
||||
attributes &= ~ROLE_ATTR_CREATEROLE;
|
||||
}
|
||||
if (dcreatedb)
|
||||
createdb = intVal(dcreatedb->arg) != 0;
|
||||
{
|
||||
if (intVal(dcreatedb->arg) != 0)
|
||||
attributes |= ROLE_ATTR_CREATEDB;
|
||||
else
|
||||
attributes &= ~ROLE_ATTR_CREATEDB;
|
||||
}
|
||||
if (dcanlogin)
|
||||
canlogin = intVal(dcanlogin->arg) != 0;
|
||||
{
|
||||
if (intVal(dcanlogin->arg) != 0)
|
||||
attributes |= ROLE_ATTR_CANLOGIN;
|
||||
else
|
||||
attributes &= ~ROLE_ATTR_CANLOGIN;
|
||||
}
|
||||
if (disreplication)
|
||||
isreplication = intVal(disreplication->arg) != 0;
|
||||
{
|
||||
if (intVal(disreplication->arg) != 0)
|
||||
{
|
||||
if (!superuser())
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
errmsg("must be superuser to create replication users")));
|
||||
attributes |= ROLE_ATTR_REPLICATION;
|
||||
}
|
||||
else
|
||||
attributes &= ~ROLE_ATTR_REPLICATION;
|
||||
}
|
||||
if (dbypassRLS)
|
||||
{
|
||||
if (intVal(dbypassRLS->arg) != 0)
|
||||
{
|
||||
if (!superuser())
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
errmsg("must be superuser to change bypassrls attribute")));
|
||||
attributes |= ROLE_ATTR_BYPASSRLS;
|
||||
}
|
||||
else
|
||||
attributes &= ~ROLE_ATTR_BYPASSRLS;
|
||||
}
|
||||
|
||||
if (dconnlimit)
|
||||
{
|
||||
connlimit = intVal(dconnlimit->arg);
|
||||
@ -277,38 +325,12 @@ CreateRole(CreateRoleStmt *stmt)
|
||||
adminmembers = (List *) dadminmembers->arg;
|
||||
if (dvalidUntil)
|
||||
validUntil = strVal(dvalidUntil->arg);
|
||||
if (dbypassRLS)
|
||||
bypassrls = intVal(dbypassRLS->arg) != 0;
|
||||
|
||||
/* Check some permissions first */
|
||||
if (issuper)
|
||||
{
|
||||
if (!superuser())
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
errmsg("must be superuser to create superusers")));
|
||||
}
|
||||
else if (isreplication)
|
||||
{
|
||||
if (!superuser())
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
errmsg("must be superuser to create replication users")));
|
||||
}
|
||||
else if (bypassrls)
|
||||
{
|
||||
if (!superuser())
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
errmsg("must be superuser to change bypassrls attribute.")));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!have_createrole_privilege())
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
errmsg("permission denied to create role")));
|
||||
}
|
||||
/* Check permissions */
|
||||
if (!have_role_attribute(ROLE_ATTR_CREATEROLE))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
errmsg("permission denied to create role")));
|
||||
|
||||
if (strcmp(stmt->role, "public") == 0 ||
|
||||
strcmp(stmt->role, "none") == 0)
|
||||
@ -364,14 +386,8 @@ CreateRole(CreateRoleStmt *stmt)
|
||||
new_record[Anum_pg_authid_rolname - 1] =
|
||||
DirectFunctionCall1(namein, CStringGetDatum(stmt->role));
|
||||
|
||||
new_record[Anum_pg_authid_rolsuper - 1] = BoolGetDatum(issuper);
|
||||
new_record[Anum_pg_authid_rolinherit - 1] = BoolGetDatum(inherit);
|
||||
new_record[Anum_pg_authid_rolcreaterole - 1] = BoolGetDatum(createrole);
|
||||
new_record[Anum_pg_authid_rolcreatedb - 1] = BoolGetDatum(createdb);
|
||||
/* superuser gets catupdate right by default */
|
||||
new_record[Anum_pg_authid_rolcatupdate - 1] = BoolGetDatum(issuper);
|
||||
new_record[Anum_pg_authid_rolcanlogin - 1] = BoolGetDatum(canlogin);
|
||||
new_record[Anum_pg_authid_rolreplication - 1] = BoolGetDatum(isreplication);
|
||||
new_record[Anum_pg_authid_rolattr - 1] = Int64GetDatum(attributes);
|
||||
|
||||
new_record[Anum_pg_authid_rolconnlimit - 1] = Int32GetDatum(connlimit);
|
||||
|
||||
if (password)
|
||||
@ -394,8 +410,6 @@ CreateRole(CreateRoleStmt *stmt)
|
||||
new_record[Anum_pg_authid_rolvaliduntil - 1] = validUntil_datum;
|
||||
new_record_nulls[Anum_pg_authid_rolvaliduntil - 1] = validUntil_null;
|
||||
|
||||
new_record[Anum_pg_authid_rolbypassrls - 1] = BoolGetDatum(bypassrls);
|
||||
|
||||
tuple = heap_form_tuple(pg_authid_dsc, new_record, new_record_nulls);
|
||||
|
||||
/*
|
||||
@ -508,6 +522,7 @@ AlterRole(AlterRoleStmt *stmt)
|
||||
DefElem *dvalidUntil = NULL;
|
||||
DefElem *dbypassRLS = NULL;
|
||||
Oid roleid;
|
||||
RoleAttr attributes;
|
||||
|
||||
/* Extract options from the statement node tree */
|
||||
foreach(option, stmt->options)
|
||||
@ -658,31 +673,34 @@ AlterRole(AlterRoleStmt *stmt)
|
||||
roleid = HeapTupleGetOid(tuple);
|
||||
|
||||
/*
|
||||
* To mess with a superuser you gotta be superuser; else you need
|
||||
* createrole, or just want to change your own password
|
||||
* To mess with a superuser or a replication user you gotta be superuser;
|
||||
* else you need createrole, or just want to change your own password
|
||||
*/
|
||||
if (((Form_pg_authid) GETSTRUCT(tuple))->rolsuper || issuper >= 0)
|
||||
|
||||
attributes = ((Form_pg_authid) GETSTRUCT(tuple))->rolattr;
|
||||
|
||||
if ((attributes & ROLE_ATTR_SUPERUSER) || issuper >= 0)
|
||||
{
|
||||
if (!superuser())
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
errmsg("must be superuser to alter superusers")));
|
||||
}
|
||||
else if (((Form_pg_authid) GETSTRUCT(tuple))->rolreplication || isreplication >= 0)
|
||||
else if ((attributes & ROLE_ATTR_REPLICATION) || isreplication >= 0)
|
||||
{
|
||||
if (!superuser())
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
errmsg("must be superuser to alter replication users")));
|
||||
}
|
||||
else if (((Form_pg_authid) GETSTRUCT(tuple))->rolbypassrls || bypassrls >= 0)
|
||||
else if ((attributes & ROLE_ATTR_BYPASSRLS) || bypassrls >= 0)
|
||||
{
|
||||
if (!superuser())
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
errmsg("must be superuser to change bypassrls attribute")));
|
||||
}
|
||||
else if (!have_createrole_privilege())
|
||||
else if (!have_role_attribute(ROLE_ATTR_CREATEROLE))
|
||||
{
|
||||
if (!(inherit < 0 &&
|
||||
createrole < 0 &&
|
||||
@ -743,43 +761,71 @@ AlterRole(AlterRoleStmt *stmt)
|
||||
*/
|
||||
if (issuper >= 0)
|
||||
{
|
||||
new_record[Anum_pg_authid_rolsuper - 1] = BoolGetDatum(issuper > 0);
|
||||
new_record_repl[Anum_pg_authid_rolsuper - 1] = true;
|
||||
|
||||
new_record[Anum_pg_authid_rolcatupdate - 1] = BoolGetDatum(issuper > 0);
|
||||
new_record_repl[Anum_pg_authid_rolcatupdate - 1] = true;
|
||||
if (issuper > 0)
|
||||
attributes |= ROLE_ATTR_SUPERUSER | ROLE_ATTR_CATUPDATE;
|
||||
else
|
||||
attributes &= ~(ROLE_ATTR_SUPERUSER | ROLE_ATTR_CATUPDATE);
|
||||
new_record_repl[Anum_pg_authid_rolattr - 1] = true;
|
||||
}
|
||||
|
||||
if (inherit >= 0)
|
||||
{
|
||||
new_record[Anum_pg_authid_rolinherit - 1] = BoolGetDatum(inherit > 0);
|
||||
new_record_repl[Anum_pg_authid_rolinherit - 1] = true;
|
||||
if (inherit > 0)
|
||||
attributes |= ROLE_ATTR_INHERIT;
|
||||
else
|
||||
attributes &= ~ROLE_ATTR_INHERIT;
|
||||
new_record_repl[Anum_pg_authid_rolattr - 1] = true;
|
||||
}
|
||||
|
||||
if (createrole >= 0)
|
||||
{
|
||||
new_record[Anum_pg_authid_rolcreaterole - 1] = BoolGetDatum(createrole > 0);
|
||||
new_record_repl[Anum_pg_authid_rolcreaterole - 1] = true;
|
||||
if (createrole > 0)
|
||||
attributes |= ROLE_ATTR_CREATEROLE;
|
||||
else
|
||||
attributes &= ~ROLE_ATTR_CREATEROLE;
|
||||
new_record_repl[Anum_pg_authid_rolattr - 1] = true;
|
||||
}
|
||||
|
||||
if (createdb >= 0)
|
||||
{
|
||||
new_record[Anum_pg_authid_rolcreatedb - 1] = BoolGetDatum(createdb > 0);
|
||||
new_record_repl[Anum_pg_authid_rolcreatedb - 1] = true;
|
||||
if (createdb > 0)
|
||||
attributes |= ROLE_ATTR_CREATEDB;
|
||||
else
|
||||
attributes &= ~ROLE_ATTR_CREATEDB;
|
||||
new_record_repl[Anum_pg_authid_rolattr - 1] = true;
|
||||
}
|
||||
|
||||
if (canlogin >= 0)
|
||||
{
|
||||
new_record[Anum_pg_authid_rolcanlogin - 1] = BoolGetDatum(canlogin > 0);
|
||||
new_record_repl[Anum_pg_authid_rolcanlogin - 1] = true;
|
||||
if (canlogin > 0)
|
||||
attributes |= ROLE_ATTR_CANLOGIN;
|
||||
else
|
||||
attributes &= ~ROLE_ATTR_CANLOGIN;
|
||||
new_record_repl[Anum_pg_authid_rolattr - 1] = true;
|
||||
}
|
||||
|
||||
if (isreplication >= 0)
|
||||
{
|
||||
new_record[Anum_pg_authid_rolreplication - 1] = BoolGetDatum(isreplication > 0);
|
||||
new_record_repl[Anum_pg_authid_rolreplication - 1] = true;
|
||||
if (isreplication > 0)
|
||||
attributes |= ROLE_ATTR_REPLICATION;
|
||||
else
|
||||
attributes &= ~ROLE_ATTR_REPLICATION;
|
||||
new_record_repl[Anum_pg_authid_rolattr - 1] = true;
|
||||
}
|
||||
|
||||
if (bypassrls >= 0)
|
||||
{
|
||||
if (bypassrls > 0)
|
||||
attributes |= ROLE_ATTR_BYPASSRLS;
|
||||
else
|
||||
attributes &= ~ROLE_ATTR_BYPASSRLS;
|
||||
new_record_repl[Anum_pg_authid_rolattr - 1] = true;
|
||||
}
|
||||
|
||||
/* If any role attributes were set, then update. */
|
||||
if (new_record_repl[Anum_pg_authid_rolattr - 1])
|
||||
new_record[Anum_pg_authid_rolattr - 1] = Int64GetDatum(attributes);
|
||||
|
||||
if (dconnlimit)
|
||||
{
|
||||
new_record[Anum_pg_authid_rolconnlimit - 1] = Int32GetDatum(connlimit);
|
||||
@ -815,11 +861,6 @@ AlterRole(AlterRoleStmt *stmt)
|
||||
new_record_nulls[Anum_pg_authid_rolvaliduntil - 1] = validUntil_null;
|
||||
new_record_repl[Anum_pg_authid_rolvaliduntil - 1] = true;
|
||||
|
||||
if (bypassrls >= 0)
|
||||
{
|
||||
new_record[Anum_pg_authid_rolbypassrls - 1] = BoolGetDatum(bypassrls > 0);
|
||||
new_record_repl[Anum_pg_authid_rolbypassrls - 1] = true;
|
||||
}
|
||||
|
||||
new_tuple = heap_modify_tuple(tuple, pg_authid_dsc, new_record,
|
||||
new_record_nulls, new_record_repl);
|
||||
@ -867,6 +908,7 @@ AlterRoleSet(AlterRoleSetStmt *stmt)
|
||||
HeapTuple roletuple;
|
||||
Oid databaseid = InvalidOid;
|
||||
Oid roleid = InvalidOid;
|
||||
RoleAttr attributes;
|
||||
|
||||
if (stmt->role)
|
||||
{
|
||||
@ -889,7 +931,8 @@ AlterRoleSet(AlterRoleSetStmt *stmt)
|
||||
* To mess with a superuser you gotta be superuser; else you need
|
||||
* createrole, or just want to change your own settings
|
||||
*/
|
||||
if (((Form_pg_authid) GETSTRUCT(roletuple))->rolsuper)
|
||||
attributes = ((Form_pg_authid) GETSTRUCT(roletuple))->rolattr;
|
||||
if (attributes & ROLE_ATTR_SUPERUSER)
|
||||
{
|
||||
if (!superuser())
|
||||
ereport(ERROR,
|
||||
@ -898,7 +941,7 @@ AlterRoleSet(AlterRoleSetStmt *stmt)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!have_createrole_privilege() &&
|
||||
if (!have_role_attribute(ROLE_ATTR_CREATEROLE) &&
|
||||
HeapTupleGetOid(roletuple) != GetUserId())
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
@ -951,7 +994,7 @@ DropRole(DropRoleStmt *stmt)
|
||||
pg_auth_members_rel;
|
||||
ListCell *item;
|
||||
|
||||
if (!have_createrole_privilege())
|
||||
if (!have_role_attribute(ROLE_ATTR_CREATEROLE))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
errmsg("permission denied to drop role")));
|
||||
@ -973,6 +1016,7 @@ DropRole(DropRoleStmt *stmt)
|
||||
char *detail_log;
|
||||
SysScanDesc sscan;
|
||||
Oid roleid;
|
||||
RoleAttr attributes;
|
||||
|
||||
tuple = SearchSysCache1(AUTHNAME, PointerGetDatum(role));
|
||||
if (!HeapTupleIsValid(tuple))
|
||||
@ -1013,8 +1057,8 @@ DropRole(DropRoleStmt *stmt)
|
||||
* roles but not superuser roles. This is mainly to avoid the
|
||||
* scenario where you accidentally drop the last superuser.
|
||||
*/
|
||||
if (((Form_pg_authid) GETSTRUCT(tuple))->rolsuper &&
|
||||
!superuser())
|
||||
attributes = ((Form_pg_authid) GETSTRUCT(tuple))->rolattr;
|
||||
if ((attributes & ROLE_ATTR_SUPERUSER) && !superuser())
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
errmsg("must be superuser to drop superusers")));
|
||||
@ -1128,6 +1172,7 @@ RenameRole(const char *oldname, const char *newname)
|
||||
bool repl_repl[Natts_pg_authid];
|
||||
int i;
|
||||
Oid roleid;
|
||||
RoleAttr attributes;
|
||||
|
||||
rel = heap_open(AuthIdRelationId, RowExclusiveLock);
|
||||
dsc = RelationGetDescr(rel);
|
||||
@ -1173,7 +1218,8 @@ RenameRole(const char *oldname, const char *newname)
|
||||
/*
|
||||
* createrole is enough privilege unless you want to mess with a superuser
|
||||
*/
|
||||
if (((Form_pg_authid) GETSTRUCT(oldtuple))->rolsuper)
|
||||
attributes = ((Form_pg_authid) GETSTRUCT(oldtuple))->rolattr;
|
||||
if (attributes & ROLE_ATTR_SUPERUSER)
|
||||
{
|
||||
if (!superuser())
|
||||
ereport(ERROR,
|
||||
@ -1182,7 +1228,7 @@ RenameRole(const char *oldname, const char *newname)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!have_createrole_privilege())
|
||||
if (!have_role_attribute(ROLE_ATTR_CREATEROLE))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
errmsg("permission denied to rename role")));
|
||||
@ -1409,7 +1455,7 @@ AddRoleMems(const char *rolename, Oid roleid,
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!have_createrole_privilege() &&
|
||||
if (!have_role_attribute(ROLE_ATTR_CREATEROLE) &&
|
||||
!is_admin_of_role(grantorId, roleid))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
@ -1555,7 +1601,7 @@ DelRoleMems(const char *rolename, Oid roleid,
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!have_createrole_privilege() &&
|
||||
if (!have_role_attribute(ROLE_ATTR_CREATEROLE) &&
|
||||
!is_admin_of_role(GetUserId(), roleid))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
|
@ -776,6 +776,7 @@ check_session_authorization(char **newval, void **extra, GucSource source)
|
||||
Oid roleid;
|
||||
bool is_superuser;
|
||||
role_auth_extra *myextra;
|
||||
RoleAttr attributes;
|
||||
|
||||
/* Do nothing for the boot_val default of NULL */
|
||||
if (*newval == NULL)
|
||||
@ -800,7 +801,8 @@ check_session_authorization(char **newval, void **extra, GucSource source)
|
||||
}
|
||||
|
||||
roleid = HeapTupleGetOid(roleTup);
|
||||
is_superuser = ((Form_pg_authid) GETSTRUCT(roleTup))->rolsuper;
|
||||
attributes = ((Form_pg_authid) GETSTRUCT(roleTup))->rolattr;
|
||||
is_superuser = (attributes & ROLE_ATTR_SUPERUSER);
|
||||
|
||||
ReleaseSysCache(roleTup);
|
||||
|
||||
@ -844,6 +846,7 @@ check_role(char **newval, void **extra, GucSource source)
|
||||
Oid roleid;
|
||||
bool is_superuser;
|
||||
role_auth_extra *myextra;
|
||||
RoleAttr attributes;
|
||||
|
||||
if (strcmp(*newval, "none") == 0)
|
||||
{
|
||||
@ -872,7 +875,8 @@ check_role(char **newval, void **extra, GucSource source)
|
||||
}
|
||||
|
||||
roleid = HeapTupleGetOid(roleTup);
|
||||
is_superuser = ((Form_pg_authid) GETSTRUCT(roleTup))->rolsuper;
|
||||
attributes = ((Form_pg_authid) GETSTRUCT(roleTup))->rolattr;
|
||||
is_superuser = (attributes & ROLE_ATTR_SUPERUSER);
|
||||
|
||||
ReleaseSysCache(roleTup);
|
||||
|
||||
|
@ -17,18 +17,14 @@
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include "access/xlog_internal.h"
|
||||
#include "catalog/pg_type.h"
|
||||
#include "fmgr.h"
|
||||
#include "funcapi.h"
|
||||
#include "miscadmin.h"
|
||||
|
||||
#include "access/xlog_internal.h"
|
||||
|
||||
#include "catalog/pg_type.h"
|
||||
|
||||
#include "nodes/makefuncs.h"
|
||||
|
||||
#include "mb/pg_wchar.h"
|
||||
|
||||
#include "miscadmin.h"
|
||||
#include "nodes/makefuncs.h"
|
||||
#include "utils/acl.h"
|
||||
#include "utils/array.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/inval.h"
|
||||
@ -36,11 +32,9 @@
|
||||
#include "utils/pg_lsn.h"
|
||||
#include "utils/resowner.h"
|
||||
#include "utils/lsyscache.h"
|
||||
|
||||
#include "replication/decode.h"
|
||||
#include "replication/logical.h"
|
||||
#include "replication/logicalfuncs.h"
|
||||
|
||||
#include "storage/fd.h"
|
||||
|
||||
/* private date for writing out data */
|
||||
@ -205,7 +199,7 @@ XLogRead(char *buf, TimeLineID tli, XLogRecPtr startptr, Size count)
|
||||
static void
|
||||
check_permissions(void)
|
||||
{
|
||||
if (!superuser() && !has_rolreplication(GetUserId()))
|
||||
if (!have_role_attribute(ROLE_ATTR_REPLICATION))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
(errmsg("must be superuser or replication role to use replication slots"))));
|
||||
|
@ -20,13 +20,14 @@
|
||||
#include "replication/slot.h"
|
||||
#include "replication/logical.h"
|
||||
#include "replication/logicalfuncs.h"
|
||||
#include "utils/acl.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/pg_lsn.h"
|
||||
|
||||
static void
|
||||
check_permissions(void)
|
||||
{
|
||||
if (!superuser() && !has_rolreplication(GetUserId()))
|
||||
if (!have_role_attribute(ROLE_ATTR_REPLICATION))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
(errmsg("must be superuser or replication role to use replication slots"))));
|
||||
|
@ -521,7 +521,7 @@ check_enable_rls(Oid relid, Oid checkAsUser)
|
||||
*/
|
||||
if (!checkAsUser && row_security == ROW_SECURITY_OFF)
|
||||
{
|
||||
if (has_bypassrls_privilege(user_id))
|
||||
if (has_role_attribute(user_id, ROLE_ATTR_BYPASSRLS))
|
||||
/* OK to bypass */
|
||||
return RLS_NONE_ENV;
|
||||
else
|
||||
|
@ -115,6 +115,7 @@ static Oid convert_type_name(text *typename);
|
||||
static AclMode convert_type_priv_string(text *priv_type_text);
|
||||
static AclMode convert_role_priv_string(text *priv_type_text);
|
||||
static AclResult pg_role_aclcheck(Oid role_oid, Oid roleid, AclMode mode);
|
||||
static RoleAttr convert_role_attr_string(text *attr_type_text);
|
||||
|
||||
static void RoleMembershipCacheCallback(Datum arg, int cacheid, uint32 hashvalue);
|
||||
|
||||
@ -4602,6 +4603,186 @@ pg_role_aclcheck(Oid role_oid, Oid roleid, AclMode mode)
|
||||
return ACLCHECK_NO_PRIV;
|
||||
}
|
||||
|
||||
/*
|
||||
* pg_has_role_attribute_id
|
||||
* Check that the role with the given oid has the given named role
|
||||
* attribute.
|
||||
*
|
||||
* Note: This function applies superuser checks. Therefore, if the provided
|
||||
* role is a superuser, then the result will always be true.
|
||||
*/
|
||||
Datum
|
||||
pg_has_role_attribute_id(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Oid roleoid = PG_GETARG_OID(0);
|
||||
text *attr_type_text = PG_GETARG_TEXT_P(1);
|
||||
RoleAttr attribute;
|
||||
|
||||
attribute = convert_role_attr_string(attr_type_text);
|
||||
|
||||
PG_RETURN_BOOL(has_role_attribute(roleoid, attribute));
|
||||
}
|
||||
|
||||
/*
|
||||
* pg_has_role_attribute_name
|
||||
* Check that the named role has the given named role attribute.
|
||||
*
|
||||
* Note: This function applies superuser checks. Therefore, if the provided
|
||||
* role is a superuser, then the result will always be true.
|
||||
*/
|
||||
Datum
|
||||
pg_has_role_attribute_name(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Name rolename = PG_GETARG_NAME(0);
|
||||
text *attr_type_text = PG_GETARG_TEXT_P(1);
|
||||
Oid roleoid;
|
||||
RoleAttr attribute;
|
||||
|
||||
roleoid = get_role_oid(NameStr(*rolename), false);
|
||||
attribute = convert_role_attr_string(attr_type_text);
|
||||
|
||||
PG_RETURN_BOOL(has_role_attribute(roleoid, attribute));
|
||||
}
|
||||
|
||||
/*
|
||||
* pg_check_role_attribute_id
|
||||
* Check that the role with the given oid has the given named role
|
||||
* attribute.
|
||||
*
|
||||
* Note: This function is different from 'pg_has_role_attribute_id_attr' in that
|
||||
* it does *not* apply any superuser checks. Therefore, this function will
|
||||
* always return the set value of the attribute, despite the superuser-ness of
|
||||
* the provided role.
|
||||
*/
|
||||
Datum
|
||||
pg_check_role_attribute_id(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Oid roleoid = PG_GETARG_OID(0);
|
||||
text *attr_type_text = PG_GETARG_TEXT_P(1);
|
||||
RoleAttr attribute;
|
||||
|
||||
attribute = convert_role_attr_string(attr_type_text);
|
||||
|
||||
PG_RETURN_BOOL(check_role_attribute(roleoid, attribute));
|
||||
}
|
||||
|
||||
/*
|
||||
* pg_check_role_attribute_name
|
||||
* Check that the named role has the given named role attribute.
|
||||
*
|
||||
* Note: This function is different from 'pg_has_role_attribute_name_attr' in
|
||||
* that it does *not* apply any superuser checks. Therefore, this function will
|
||||
* always return the set value of the attribute, despite the superuser-ness of
|
||||
* the provided role.
|
||||
*/
|
||||
Datum
|
||||
pg_check_role_attribute_name(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Name rolename = PG_GETARG_NAME(0);
|
||||
text *attr_type_text = PG_GETARG_TEXT_P(1);
|
||||
Oid roleoid;
|
||||
RoleAttr attribute;
|
||||
|
||||
roleoid = get_role_oid(NameStr(*rolename), false);
|
||||
attribute = convert_role_attr_string(attr_type_text);
|
||||
|
||||
PG_RETURN_BOOL(check_role_attribute(roleoid, attribute));
|
||||
}
|
||||
|
||||
/*
|
||||
* pg_check_role_attribute_attrs
|
||||
* Check that the named attribute is enabled in the given RoleAttr
|
||||
* representation of role attributes.
|
||||
*/
|
||||
Datum
|
||||
pg_check_role_attribute_attrs(PG_FUNCTION_ARGS)
|
||||
{
|
||||
RoleAttr attributes = PG_GETARG_INT64(0);
|
||||
text *attr_type_text = PG_GETARG_TEXT_P(1);
|
||||
RoleAttr attribute;
|
||||
|
||||
attribute = convert_role_attr_string(attr_type_text);
|
||||
|
||||
PG_RETURN_BOOL(attributes & attribute);
|
||||
}
|
||||
|
||||
/*
|
||||
* pg_all_role_attributes
|
||||
* Convert a RoleAttr representation of role attributes into an array of
|
||||
* corresponding text values.
|
||||
*
|
||||
* The first and only argument is a RoleAttr (int64) representation of the
|
||||
* role attributes.
|
||||
*/
|
||||
Datum
|
||||
pg_all_role_attributes(PG_FUNCTION_ARGS)
|
||||
{
|
||||
RoleAttr attributes = PG_GETARG_INT64(0);
|
||||
Datum *temp_array;
|
||||
ArrayType *result;
|
||||
int i = 0;
|
||||
|
||||
/*
|
||||
* Short-circuit the case for no attributes assigned.
|
||||
*/
|
||||
if (attributes == ROLE_ATTR_NONE)
|
||||
PG_RETURN_ARRAYTYPE_P(construct_empty_array(TEXTOID));
|
||||
|
||||
temp_array = (Datum *) palloc(N_ROLE_ATTRIBUTES * sizeof(Datum));
|
||||
|
||||
/* Determine which attributes are assigned. */
|
||||
if (attributes & ROLE_ATTR_SUPERUSER)
|
||||
temp_array[i++] = CStringGetTextDatum(_("Superuser"));
|
||||
if (attributes & ROLE_ATTR_INHERIT)
|
||||
temp_array[i++] = CStringGetTextDatum(_("Inherit"));
|
||||
if (attributes & ROLE_ATTR_CREATEROLE)
|
||||
temp_array[i++] = CStringGetTextDatum(_("Create Role"));
|
||||
if (attributes & ROLE_ATTR_CREATEDB)
|
||||
temp_array[i++] = CStringGetTextDatum(_("Create DB"));
|
||||
if (attributes & ROLE_ATTR_CATUPDATE)
|
||||
temp_array[i++] = CStringGetTextDatum(_("Catalog Update"));
|
||||
if (attributes & ROLE_ATTR_CANLOGIN)
|
||||
temp_array[i++] = CStringGetTextDatum(_("Login"));
|
||||
if (attributes & ROLE_ATTR_REPLICATION)
|
||||
temp_array[i++] = CStringGetTextDatum(_("Replication"));
|
||||
if (attributes & ROLE_ATTR_BYPASSRLS)
|
||||
temp_array[i++] = CStringGetTextDatum(_("Bypass RLS"));
|
||||
|
||||
result = construct_array(temp_array, i, TEXTOID, -1, false, 'i');
|
||||
|
||||
PG_RETURN_ARRAYTYPE_P(result);
|
||||
}
|
||||
|
||||
/*
|
||||
* convert_role_attr_string
|
||||
* Convert text string to RoleAttr value.
|
||||
*/
|
||||
static RoleAttr
|
||||
convert_role_attr_string(text *attr_type_text)
|
||||
{
|
||||
char *attr_type = text_to_cstring(attr_type_text);
|
||||
|
||||
if (pg_strcasecmp(attr_type, "SUPERUSER") == 0)
|
||||
return ROLE_ATTR_SUPERUSER;
|
||||
else if (pg_strcasecmp(attr_type, "INHERIT") == 0)
|
||||
return ROLE_ATTR_INHERIT;
|
||||
else if (pg_strcasecmp(attr_type, "CREATEROLE") == 0)
|
||||
return ROLE_ATTR_CREATEROLE;
|
||||
else if (pg_strcasecmp(attr_type, "CREATEDB") == 0)
|
||||
return ROLE_ATTR_CREATEDB;
|
||||
else if (pg_strcasecmp(attr_type, "CATUPDATE") == 0)
|
||||
return ROLE_ATTR_CATUPDATE;
|
||||
else if (pg_strcasecmp(attr_type, "CANLOGIN") == 0)
|
||||
return ROLE_ATTR_CANLOGIN;
|
||||
else if (pg_strcasecmp(attr_type, "REPLICATION") == 0)
|
||||
return ROLE_ATTR_REPLICATION;
|
||||
else if (pg_strcasecmp(attr_type, "BYPASSRLS") == 0)
|
||||
return ROLE_ATTR_BYPASSRLS;
|
||||
else
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("unrecognized role attribute: \"%s\"", attr_type)));
|
||||
}
|
||||
|
||||
/*
|
||||
* initialization function (called by InitPostgres)
|
||||
@ -4634,23 +4815,6 @@ RoleMembershipCacheCallback(Datum arg, int cacheid, uint32 hashvalue)
|
||||
}
|
||||
|
||||
|
||||
/* Check if specified role has rolinherit set */
|
||||
static bool
|
||||
has_rolinherit(Oid roleid)
|
||||
{
|
||||
bool result = false;
|
||||
HeapTuple utup;
|
||||
|
||||
utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
|
||||
if (HeapTupleIsValid(utup))
|
||||
{
|
||||
result = ((Form_pg_authid) GETSTRUCT(utup))->rolinherit;
|
||||
ReleaseSysCache(utup);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Get a list of roles that the specified roleid has the privileges of
|
||||
*
|
||||
@ -4697,7 +4861,7 @@ roles_has_privs_of(Oid roleid)
|
||||
int i;
|
||||
|
||||
/* Ignore non-inheriting roles */
|
||||
if (!has_rolinherit(memberid))
|
||||
if (!has_role_attribute(memberid, ROLE_ATTR_INHERIT))
|
||||
continue;
|
||||
|
||||
/* Find roles that memberid is directly a member of */
|
||||
|
@ -2308,7 +2308,7 @@ RI_Initial_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
|
||||
* bypassrls right or is the table owner of the table(s) involved which
|
||||
* have RLS enabled.
|
||||
*/
|
||||
if (!has_bypassrls_privilege(GetUserId()) &&
|
||||
if (!have_role_attribute(ROLE_ATTR_BYPASSRLS) &&
|
||||
((pk_rel->rd_rel->relrowsecurity &&
|
||||
!pg_class_ownercheck(pkrte->relid, GetUserId())) ||
|
||||
(fk_rel->rd_rel->relrowsecurity &&
|
||||
|
@ -40,6 +40,7 @@
|
||||
#include "storage/pg_shmem.h"
|
||||
#include "storage/proc.h"
|
||||
#include "storage/procarray.h"
|
||||
#include "utils/acl.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/guc.h"
|
||||
#include "utils/memutils.h"
|
||||
@ -328,24 +329,6 @@ SetUserIdAndContext(Oid userid, bool sec_def_context)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Check whether specified role has explicit REPLICATION privilege
|
||||
*/
|
||||
bool
|
||||
has_rolreplication(Oid roleid)
|
||||
{
|
||||
bool result = false;
|
||||
HeapTuple utup;
|
||||
|
||||
utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
|
||||
if (HeapTupleIsValid(utup))
|
||||
{
|
||||
result = ((Form_pg_authid) GETSTRUCT(utup))->rolreplication;
|
||||
ReleaseSysCache(utup);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize user identity during normal backend startup
|
||||
*/
|
||||
@ -375,7 +358,7 @@ InitializeSessionUserId(const char *rolename)
|
||||
roleid = HeapTupleGetOid(roleTup);
|
||||
|
||||
AuthenticatedUserId = roleid;
|
||||
AuthenticatedUserIsSuperuser = rform->rolsuper;
|
||||
AuthenticatedUserIsSuperuser = (rform->rolattr & ROLE_ATTR_SUPERUSER);
|
||||
|
||||
/* This sets OuterUserId/CurrentUserId too */
|
||||
SetSessionUserId(roleid, AuthenticatedUserIsSuperuser);
|
||||
@ -394,7 +377,7 @@ InitializeSessionUserId(const char *rolename)
|
||||
/*
|
||||
* Is role allowed to login at all?
|
||||
*/
|
||||
if (!rform->rolcanlogin)
|
||||
if (!(rform->rolattr & ROLE_ATTR_CANLOGIN))
|
||||
ereport(FATAL,
|
||||
(errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
|
||||
errmsg("role \"%s\" is not permitted to log in",
|
||||
|
@ -762,7 +762,7 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
|
||||
{
|
||||
Assert(!bootstrap);
|
||||
|
||||
if (!superuser() && !has_rolreplication(GetUserId()))
|
||||
if (!have_role_attribute(ROLE_ATTR_REPLICATION))
|
||||
ereport(FATAL,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
errmsg("must be superuser or replication role to start walsender")));
|
||||
|
@ -58,6 +58,7 @@ superuser_arg(Oid roleid)
|
||||
{
|
||||
bool result;
|
||||
HeapTuple rtup;
|
||||
RoleAttr attributes;
|
||||
|
||||
/* Quick out for cache hit */
|
||||
if (OidIsValid(last_roleid) && last_roleid == roleid)
|
||||
@ -71,7 +72,8 @@ superuser_arg(Oid roleid)
|
||||
rtup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
|
||||
if (HeapTupleIsValid(rtup))
|
||||
{
|
||||
result = ((Form_pg_authid) GETSTRUCT(rtup))->rolsuper;
|
||||
attributes = ((Form_pg_authid) GETSTRUCT(rtup))->rolattr;
|
||||
result = (attributes & ROLE_ATTR_SUPERUSER);
|
||||
ReleaseSysCache(rtup);
|
||||
}
|
||||
else
|
||||
|
Reference in New Issue
Block a user