1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-25 01:02:05 +03:00

Revert "Use a bitmask to represent role attributes"

This reverts commit 1826987a46.

The overall design was deemed unacceptable, in discussion following the
previous commit message; we might find some parts of it still
salvageable, but I don't want to be on the hook for fixing it, so let's
wait until we have a new patch.
This commit is contained in:
Alvaro Herrera
2014-12-23 15:35:49 -03:00
parent d7ee82e50f
commit a609d96778
30 changed files with 380 additions and 806 deletions

View File

@ -27,7 +27,6 @@
#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"
@ -55,7 +54,7 @@ pg_start_backup(PG_FUNCTION_ARGS)
backupidstr = text_to_cstring(backupid);
if (!have_role_attribute(ROLE_ATTR_REPLICATION))
if (!superuser() && !has_rolreplication(GetUserId()))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser or replication role to run a backup")));
@ -83,7 +82,7 @@ pg_stop_backup(PG_FUNCTION_ARGS)
{
XLogRecPtr stoppoint;
if (!have_role_attribute(ROLE_ATTR_REPLICATION))
if (!superuser() && !has_rolreplication(GetUserId()))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
(errmsg("must be superuser or replication role to run a backup"))));

View File

@ -176,7 +176,7 @@ sub Catalogs
}
}
}
$catalogs{$catname} = \%catalog if defined $catname;
$catalogs{$catname} = \%catalog;
close INPUT_FILE;
}
return \%catalogs;

View File

@ -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/,\
acldefs.h pg_proc.h pg_type.h pg_attribute.h pg_class.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 \

View File

@ -3423,6 +3423,26 @@ 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
*/
@ -3610,7 +3630,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_role_attribute(roleid, ROLE_ATTR_CATUPDATE) &&
!has_rolcatupdate(roleid) &&
!allowSystemTableMods)
{
#ifdef ACLDEBUG
@ -5031,87 +5051,52 @@ pg_extension_ownercheck(Oid ext_oid, Oid roleid)
}
/*
* has_role_attribute
* Check if the role with the specified id has been assigned a specific role
* attribute.
* Check whether specified role has CREATEROLE privilege (or is a superuser)
*
* 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.)
* 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_role_attribute(Oid roleid, RoleAttr attribute)
has_createrole_privilege(Oid roleid)
{
/*
* Superusers bypass all permission checking except in the case of CATUPDATE
*/
if (!(attribute & ROLE_ATTR_CATUPDATE) && superuser_arg(roleid))
bool result = false;
HeapTuple utup;
/* Superusers bypass all permission checking. */
if (superuser_arg(roleid))
return true;
return check_role_attribute(roleid, attribute);
utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
if (HeapTupleIsValid(utup))
{
result = ((Form_pg_authid) GETSTRUCT(utup))->rolcreaterole;
ReleaseSysCache(utup);
}
return result;
}
/*
* 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
have_role_attribute(RoleAttr attribute)
has_bypassrls_privilege(Oid roleid)
{
return has_role_attribute(GetUserId(), attribute);
}
bool result = false;
HeapTuple utup;
/*
* 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;
/* Superusers bypass all permission checking. */
if (superuser_arg(roleid))
return true;
/* 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);
utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
if (HeapTupleIsValid(utup))
{
result = ((Form_pg_authid) GETSTRUCT(utup))->rolbypassrls;
ReleaseSysCache(utup);
}
return result;
}
/*

View File

@ -90,8 +90,6 @@ 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);
@ -146,7 +144,6 @@ 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')

View File

@ -2884,12 +2884,7 @@ 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 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
OR (SELECT 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;

View File

@ -1738,7 +1738,7 @@ check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address,
}
else
{
if (!has_role_attribute(roleid, ROLE_ATTR_CREATEROLE))
if (!has_createrole_privilege(roleid))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must have CREATEROLE privilege")));

View File

@ -9,17 +9,17 @@
CREATE VIEW pg_roles AS
SELECT
rolname,
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,
rolsuper,
rolinherit,
rolcreaterole,
rolcreatedb,
rolcatupdate,
rolcanlogin,
rolreplication,
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,
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,
rolcreatedb AS usecreatedb,
rolsuper AS usesuper,
rolcatupdate AS usecatupd,
rolreplication 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 pg_check_role_attribute(pg_authid.rolattr, 'CANLOGIN');
WHERE rolcanlogin;
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 pg_check_role_attribute(pg_authid.rolattr, 'CANLOGIN');
WHERE NOT rolcanlogin;
CREATE VIEW pg_user AS
SELECT

View File

@ -85,6 +85,7 @@ 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);
@ -290,7 +291,7 @@ createdb(const CreatedbStmt *stmt)
* "giveaway" attacks. Note that a superuser will always have both of
* these privileges a fortiori.
*/
if (!have_role_attribute(ROLE_ATTR_CREATEDB))
if (!have_createdb_privilege())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to create database")));
@ -964,7 +965,7 @@ RenameDatabase(const char *oldname, const char *newname)
oldname);
/* must have createdb rights */
if (!have_role_attribute(ROLE_ATTR_CREATEDB))
if (!have_createdb_privilege())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to rename database")));
@ -1622,7 +1623,7 @@ AlterDatabaseOwner(const char *dbname, Oid newOwnerId)
* databases. Because superusers will always have this right, we need
* no special case for them.
*/
if (!have_role_attribute(ROLE_ATTR_CREATEDB))
if (!have_createdb_privilege())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to change owner of database")));
@ -1801,6 +1802,26 @@ 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
*

View File

@ -56,6 +56,14 @@ 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
*/
@ -73,7 +81,13 @@ CreateRole(CreateRoleStmt *stmt)
char *password = NULL; /* user password */
bool encrypt_password = Password_encryption; /* encrypt password? */
char encrypted_password[MD5_PASSWD_LEN + 1];
RoleAttr attributes;
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? */
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 */
@ -95,17 +109,13 @@ CreateRole(CreateRoleStmt *stmt)
DefElem *dvalidUntil = NULL;
DefElem *dbypassRLS = NULL;
/*
* Every role has INHERIT by default, and CANLOGIN depends on the statement
* type.
*/
attributes = ROLE_ATTR_INHERIT;
/* The defaults can vary depending on the original statement type */
switch (stmt->stmt_type)
{
case ROLESTMT_ROLE:
break;
case ROLESTMT_USER:
attributes |= ROLE_ATTR_CANLOGIN;
canlogin = true;
/* may eventually want inherit to default to false here */
break;
case ROLESTMT_GROUP:
@ -239,76 +249,18 @@ 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)
{
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;
}
issuper = intVal(dissuper->arg) != 0;
if (dinherit)
{
if (intVal(dinherit->arg) != 0)
attributes |= ROLE_ATTR_INHERIT;
else
attributes &= ~ROLE_ATTR_INHERIT;
}
inherit = intVal(dinherit->arg) != 0;
if (dcreaterole)
{
if (intVal(dcreaterole->arg) != 0)
attributes |= ROLE_ATTR_CREATEROLE;
else
attributes &= ~ROLE_ATTR_CREATEROLE;
}
createrole = intVal(dcreaterole->arg) != 0;
if (dcreatedb)
{
if (intVal(dcreatedb->arg) != 0)
attributes |= ROLE_ATTR_CREATEDB;
else
attributes &= ~ROLE_ATTR_CREATEDB;
}
createdb = intVal(dcreatedb->arg) != 0;
if (dcanlogin)
{
if (intVal(dcanlogin->arg) != 0)
attributes |= ROLE_ATTR_CANLOGIN;
else
attributes &= ~ROLE_ATTR_CANLOGIN;
}
canlogin = intVal(dcanlogin->arg) != 0;
if (disreplication)
{
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;
}
isreplication = intVal(disreplication->arg) != 0;
if (dconnlimit)
{
connlimit = intVal(dconnlimit->arg);
@ -325,12 +277,38 @@ CreateRole(CreateRoleStmt *stmt)
adminmembers = (List *) dadminmembers->arg;
if (dvalidUntil)
validUntil = strVal(dvalidUntil->arg);
if (dbypassRLS)
bypassrls = intVal(dbypassRLS->arg) != 0;
/* Check permissions */
if (!have_role_attribute(ROLE_ATTR_CREATEROLE))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to create role")));
/* 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")));
}
if (strcmp(stmt->role, "public") == 0 ||
strcmp(stmt->role, "none") == 0)
@ -386,8 +364,14 @@ CreateRole(CreateRoleStmt *stmt)
new_record[Anum_pg_authid_rolname - 1] =
DirectFunctionCall1(namein, CStringGetDatum(stmt->role));
new_record[Anum_pg_authid_rolattr - 1] = Int64GetDatum(attributes);
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_rolconnlimit - 1] = Int32GetDatum(connlimit);
if (password)
@ -410,6 +394,8 @@ 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);
/*
@ -522,7 +508,6 @@ AlterRole(AlterRoleStmt *stmt)
DefElem *dvalidUntil = NULL;
DefElem *dbypassRLS = NULL;
Oid roleid;
RoleAttr attributes;
/* Extract options from the statement node tree */
foreach(option, stmt->options)
@ -673,34 +658,31 @@ AlterRole(AlterRoleStmt *stmt)
roleid = HeapTupleGetOid(tuple);
/*
* 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
* To mess with a superuser you gotta be superuser; else you need
* createrole, or just want to change your own password
*/
attributes = ((Form_pg_authid) GETSTRUCT(tuple))->rolattr;
if ((attributes & ROLE_ATTR_SUPERUSER) || issuper >= 0)
if (((Form_pg_authid) GETSTRUCT(tuple))->rolsuper || issuper >= 0)
{
if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser to alter superusers")));
}
else if ((attributes & ROLE_ATTR_REPLICATION) || isreplication >= 0)
else if (((Form_pg_authid) GETSTRUCT(tuple))->rolreplication || isreplication >= 0)
{
if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser to alter replication users")));
}
else if ((attributes & ROLE_ATTR_BYPASSRLS) || bypassrls >= 0)
else if (((Form_pg_authid) GETSTRUCT(tuple))->rolbypassrls || bypassrls >= 0)
{
if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser to change bypassrls attribute")));
}
else if (!have_role_attribute(ROLE_ATTR_CREATEROLE))
else if (!have_createrole_privilege())
{
if (!(inherit < 0 &&
createrole < 0 &&
@ -761,71 +743,43 @@ AlterRole(AlterRoleStmt *stmt)
*/
if (issuper >= 0)
{
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;
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 (inherit >= 0)
{
if (inherit > 0)
attributes |= ROLE_ATTR_INHERIT;
else
attributes &= ~ROLE_ATTR_INHERIT;
new_record_repl[Anum_pg_authid_rolattr - 1] = true;
new_record[Anum_pg_authid_rolinherit - 1] = BoolGetDatum(inherit > 0);
new_record_repl[Anum_pg_authid_rolinherit - 1] = true;
}
if (createrole >= 0)
{
if (createrole > 0)
attributes |= ROLE_ATTR_CREATEROLE;
else
attributes &= ~ROLE_ATTR_CREATEROLE;
new_record_repl[Anum_pg_authid_rolattr - 1] = true;
new_record[Anum_pg_authid_rolcreaterole - 1] = BoolGetDatum(createrole > 0);
new_record_repl[Anum_pg_authid_rolcreaterole - 1] = true;
}
if (createdb >= 0)
{
if (createdb > 0)
attributes |= ROLE_ATTR_CREATEDB;
else
attributes &= ~ROLE_ATTR_CREATEDB;
new_record_repl[Anum_pg_authid_rolattr - 1] = true;
new_record[Anum_pg_authid_rolcreatedb - 1] = BoolGetDatum(createdb > 0);
new_record_repl[Anum_pg_authid_rolcreatedb - 1] = true;
}
if (canlogin >= 0)
{
if (canlogin > 0)
attributes |= ROLE_ATTR_CANLOGIN;
else
attributes &= ~ROLE_ATTR_CANLOGIN;
new_record_repl[Anum_pg_authid_rolattr - 1] = true;
new_record[Anum_pg_authid_rolcanlogin - 1] = BoolGetDatum(canlogin > 0);
new_record_repl[Anum_pg_authid_rolcanlogin - 1] = true;
}
if (isreplication >= 0)
{
if (isreplication > 0)
attributes |= ROLE_ATTR_REPLICATION;
else
attributes &= ~ROLE_ATTR_REPLICATION;
new_record_repl[Anum_pg_authid_rolattr - 1] = true;
new_record[Anum_pg_authid_rolreplication - 1] = BoolGetDatum(isreplication > 0);
new_record_repl[Anum_pg_authid_rolreplication - 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);
@ -861,6 +815,11 @@ 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);
@ -908,7 +867,6 @@ AlterRoleSet(AlterRoleSetStmt *stmt)
HeapTuple roletuple;
Oid databaseid = InvalidOid;
Oid roleid = InvalidOid;
RoleAttr attributes;
if (stmt->role)
{
@ -931,8 +889,7 @@ AlterRoleSet(AlterRoleSetStmt *stmt)
* To mess with a superuser you gotta be superuser; else you need
* createrole, or just want to change your own settings
*/
attributes = ((Form_pg_authid) GETSTRUCT(roletuple))->rolattr;
if (attributes & ROLE_ATTR_SUPERUSER)
if (((Form_pg_authid) GETSTRUCT(roletuple))->rolsuper)
{
if (!superuser())
ereport(ERROR,
@ -941,7 +898,7 @@ AlterRoleSet(AlterRoleSetStmt *stmt)
}
else
{
if (!have_role_attribute(ROLE_ATTR_CREATEROLE) &&
if (!have_createrole_privilege() &&
HeapTupleGetOid(roletuple) != GetUserId())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
@ -994,7 +951,7 @@ DropRole(DropRoleStmt *stmt)
pg_auth_members_rel;
ListCell *item;
if (!have_role_attribute(ROLE_ATTR_CREATEROLE))
if (!have_createrole_privilege())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to drop role")));
@ -1016,7 +973,6 @@ DropRole(DropRoleStmt *stmt)
char *detail_log;
SysScanDesc sscan;
Oid roleid;
RoleAttr attributes;
tuple = SearchSysCache1(AUTHNAME, PointerGetDatum(role));
if (!HeapTupleIsValid(tuple))
@ -1057,8 +1013,8 @@ DropRole(DropRoleStmt *stmt)
* roles but not superuser roles. This is mainly to avoid the
* scenario where you accidentally drop the last superuser.
*/
attributes = ((Form_pg_authid) GETSTRUCT(tuple))->rolattr;
if ((attributes & ROLE_ATTR_SUPERUSER) && !superuser())
if (((Form_pg_authid) GETSTRUCT(tuple))->rolsuper &&
!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser to drop superusers")));
@ -1172,7 +1128,6 @@ 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);
@ -1218,8 +1173,7 @@ RenameRole(const char *oldname, const char *newname)
/*
* createrole is enough privilege unless you want to mess with a superuser
*/
attributes = ((Form_pg_authid) GETSTRUCT(oldtuple))->rolattr;
if (attributes & ROLE_ATTR_SUPERUSER)
if (((Form_pg_authid) GETSTRUCT(oldtuple))->rolsuper)
{
if (!superuser())
ereport(ERROR,
@ -1228,7 +1182,7 @@ RenameRole(const char *oldname, const char *newname)
}
else
{
if (!have_role_attribute(ROLE_ATTR_CREATEROLE))
if (!have_createrole_privilege())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to rename role")));
@ -1455,7 +1409,7 @@ AddRoleMems(const char *rolename, Oid roleid,
}
else
{
if (!have_role_attribute(ROLE_ATTR_CREATEROLE) &&
if (!have_createrole_privilege() &&
!is_admin_of_role(grantorId, roleid))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
@ -1601,7 +1555,7 @@ DelRoleMems(const char *rolename, Oid roleid,
}
else
{
if (!have_role_attribute(ROLE_ATTR_CREATEROLE) &&
if (!have_createrole_privilege() &&
!is_admin_of_role(GetUserId(), roleid))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),

View File

@ -776,7 +776,6 @@ 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)
@ -801,8 +800,7 @@ check_session_authorization(char **newval, void **extra, GucSource source)
}
roleid = HeapTupleGetOid(roleTup);
attributes = ((Form_pg_authid) GETSTRUCT(roleTup))->rolattr;
is_superuser = (attributes & ROLE_ATTR_SUPERUSER);
is_superuser = ((Form_pg_authid) GETSTRUCT(roleTup))->rolsuper;
ReleaseSysCache(roleTup);
@ -846,7 +844,6 @@ check_role(char **newval, void **extra, GucSource source)
Oid roleid;
bool is_superuser;
role_auth_extra *myextra;
RoleAttr attributes;
if (strcmp(*newval, "none") == 0)
{
@ -875,8 +872,7 @@ check_role(char **newval, void **extra, GucSource source)
}
roleid = HeapTupleGetOid(roleTup);
attributes = ((Form_pg_authid) GETSTRUCT(roleTup))->rolattr;
is_superuser = (attributes & ROLE_ATTR_SUPERUSER);
is_superuser = ((Form_pg_authid) GETSTRUCT(roleTup))->rolsuper;
ReleaseSysCache(roleTup);

View File

@ -17,14 +17,18 @@
#include <unistd.h>
#include "access/xlog_internal.h"
#include "catalog/pg_type.h"
#include "fmgr.h"
#include "funcapi.h"
#include "mb/pg_wchar.h"
#include "miscadmin.h"
#include "access/xlog_internal.h"
#include "catalog/pg_type.h"
#include "nodes/makefuncs.h"
#include "utils/acl.h"
#include "mb/pg_wchar.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/inval.h"
@ -32,9 +36,11 @@
#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 */
@ -199,7 +205,7 @@ XLogRead(char *buf, TimeLineID tli, XLogRecPtr startptr, Size count)
static void
check_permissions(void)
{
if (!have_role_attribute(ROLE_ATTR_REPLICATION))
if (!superuser() && !has_rolreplication(GetUserId()))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
(errmsg("must be superuser or replication role to use replication slots"))));

View File

@ -20,14 +20,13 @@
#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 (!have_role_attribute(ROLE_ATTR_REPLICATION))
if (!superuser() && !has_rolreplication(GetUserId()))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
(errmsg("must be superuser or replication role to use replication slots"))));

View File

@ -521,7 +521,7 @@ check_enable_rls(Oid relid, Oid checkAsUser)
*/
if (!checkAsUser && row_security == ROW_SECURITY_OFF)
{
if (has_role_attribute(user_id, ROLE_ATTR_BYPASSRLS))
if (has_bypassrls_privilege(user_id))
/* OK to bypass */
return RLS_NONE_ENV;
else

View File

@ -115,7 +115,6 @@ 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);
@ -4603,186 +4602,6 @@ 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)
@ -4815,6 +4634,23 @@ 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
*
@ -4861,7 +4697,7 @@ roles_has_privs_of(Oid roleid)
int i;
/* Ignore non-inheriting roles */
if (!has_role_attribute(memberid, ROLE_ATTR_INHERIT))
if (!has_rolinherit(memberid))
continue;
/* Find roles that memberid is directly a member of */

View File

@ -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 (!have_role_attribute(ROLE_ATTR_BYPASSRLS) &&
if (!has_bypassrls_privilege(GetUserId()) &&
((pk_rel->rd_rel->relrowsecurity &&
!pg_class_ownercheck(pkrte->relid, GetUserId())) ||
(fk_rel->rd_rel->relrowsecurity &&

View File

@ -40,7 +40,6 @@
#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"
@ -329,6 +328,24 @@ 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
*/
@ -358,7 +375,7 @@ InitializeSessionUserId(const char *rolename)
roleid = HeapTupleGetOid(roleTup);
AuthenticatedUserId = roleid;
AuthenticatedUserIsSuperuser = (rform->rolattr & ROLE_ATTR_SUPERUSER);
AuthenticatedUserIsSuperuser = rform->rolsuper;
/* This sets OuterUserId/CurrentUserId too */
SetSessionUserId(roleid, AuthenticatedUserIsSuperuser);
@ -377,7 +394,7 @@ InitializeSessionUserId(const char *rolename)
/*
* Is role allowed to login at all?
*/
if (!(rform->rolattr & ROLE_ATTR_CANLOGIN))
if (!rform->rolcanlogin)
ereport(FATAL,
(errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
errmsg("role \"%s\" is not permitted to log in",

View File

@ -762,7 +762,7 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
{
Assert(!bootstrap);
if (!have_role_attribute(ROLE_ATTR_REPLICATION))
if (!superuser() && !has_rolreplication(GetUserId()))
ereport(FATAL,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser or replication role to start walsender")));

View File

@ -58,7 +58,6 @@ superuser_arg(Oid roleid)
{
bool result;
HeapTuple rtup;
RoleAttr attributes;
/* Quick out for cache hit */
if (OidIsValid(last_roleid) && last_roleid == roleid)
@ -72,8 +71,7 @@ superuser_arg(Oid roleid)
rtup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
if (HeapTupleIsValid(rtup))
{
attributes = ((Form_pg_authid) GETSTRUCT(rtup))->rolattr;
result = (attributes & ROLE_ATTR_SUPERUSER);
result = ((Form_pg_authid) GETSTRUCT(rtup))->rolsuper;
ReleaseSysCache(rtup);
}
else