diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml index 947091627f..9ceb96b54c 100644 --- a/doc/src/sgml/catalogs.sgml +++ b/doc/src/sgml/catalogs.sgml @@ -1391,11 +1391,56 @@ - rolattr - bigint + rolsuper + bool + Role has superuser privileges + + + + rolinherit + bool + Role automatically inherits privileges of roles it is a + member of + + + + rolcreaterole + bool + Role can create more roles + + + + rolcreatedb + bool + Role can create databases + + + + rolcatupdate + bool - Role attributes; see and - for details + Role can update system catalogs directly. (Even a superuser cannot do + this unless this column is true) + + + + + rolcanlogin + bool + + Role can log in. That is, this role can be given as the initial + session authorization identifier + + + + + rolreplication + bool + + Role is a replication role. That is, this role can initiate streaming + replication (see ) and set/unset + the system backup mode using pg_start_backup and + pg_stop_backup @@ -1433,96 +1478,6 @@ - - Attributes in <structfield>rolattr</> - - - - - Attribute - CREATE ROLE Option - Description - Position - - - - - - Superuser - SUPERUSER - Role has superuser privileges - 0 - - - - Inherit - INHERIT - - Role automatically inherits privileges of roles it is a member of - - 1 - - - - Create Role - CREATEROLE - Role can create more roles - 2 - - - - Create DB - CREATEDB - Role can create databases - 3 - - - - Catalog Update - CATUPDATE - - Role can update system catalogs directly. (Even a superuser cannot do - this unless this column is true) - - 4 - - - - Can Login - LOGIN - - Role can log in. That is, this role can be given as the initial - session authorization identifier - - 5 - - - - Replication - REPLICATION - - Role is a replication role. That is, this role can initiate streaming - replication (see ) and set/unset - the system backup mode using pg_start_backup and - pg_stop_backup - - 6 - - - - Bypass Row Level Security - BYPASSRLS - - Role can bypass row level security policies when row_security - is set off - - 7 - - - - -
- diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index 2a37e65eb9..24c64b7187 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -15139,133 +15139,6 @@ SELECT has_function_privilege('joeuser', 'myfunc(int, text)', 'execute'); are immediately available without doing SET ROLE. - - lists functions that - allow the user to query role attribute information programmatically. - - - - Role Attribute Inquiry Functions - - - Name Return Type Description - - - - pg_has_role_attribute(role, attribute) - boolean - does role have the permissions allowed by named attribute - - - pg_check_role_attribute(role, attribute) - boolean - does role have the named attribute - - - pg_check_role_attribute(role_attributes, attribute) - boolean - is attribute set in bitmap of role attributes - - - pg_all_role_attributes(role_attributes) - text[] - convert bitmap of role attribute representation to text[] - - - -
- - - pg_has_role_attribute - - - pg_check_role_attribute - - - pg_all_role_attributes - - - - pg_has_role_attribute checks the attribute permissions - given to a role. It will always return true for roles - with superuser privileges unless the attribute being checked is - CATUPDATE (superuser cannot bypass - CATUPDATE permissions). The role can be specified by name - and by OID. The attribute is specified by a text string which must evaluate - to one of the following role attributes: - SUPERUSER, - INHERIT, - CREATEROLE, - CREATEDB, - CATUPDATE, - CANLOGIN, - REPLICATION, or - BYPASSRLS. See for more - information. For example: - -SELECT pg_has_role_attribute('joe', 'SUPERUSER'); - pg_has_role_attribute ------------------------ - f -(1 row) - -SELECT rolname, pg_has_role_attribute(oid, 'INHERIT') AS rolinherit FROM pg_roles; - rolname | rolinherit -----------+------------ - postgres | t - joe | t -(2 rows) - - - - - pg_check_role_attribute checks the attribute value given - to a role. The role can be specified by name and by OID. The attribute is - specified by a text string which must evaluate to a valid role attribute (see - pg_has_role_attribute). A third variant of this function - allows for a bitmap representation (bigint) of attributes - to be given instead of a role. - Example: - -SELECT pg_check_role_attribute('joe', 'SUPERUSER'); - pg_check_role_attribute -------------------------- - f -(1 row) - -SELECT rolname, pg_check_role_attribute(oid, 'INHERIT') as rolinherit FROM pg_roles; - rolname | rolinherit -----------+------------ - postgres | t - joe | t -(2 rows) - t -(1 row) - - -SELECT rolname, pg_check_role_attribute(rolattr, 'SUPERUSER') AS rolsuper FROM pg_authid; - rolname | rolsuper -----------+---------- - postgres | t - joe | f -(2 rows) - - - - - pg_all_role_attributes convert a set of role attributes - represented by an bigint bitmap to a text array. - Example: - -SELECT rolname, pg_all_role_attributes(rolattr) AS attributes FROM pg_authid; - rolname | attributes -----------+----------------------------------------------------------------------------------------------- - postgres | {Superuser,Inherit,"Create Role","Create DB","Catalog Update",Login,Replication,"Bypass RLS"} - joe | {Inherit,Login} -(2 rows) - - - shows functions that determine whether a certain object is visible in the diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c index 3181a79e3e..133143db92 100644 --- a/src/backend/access/transam/xlogfuncs.c +++ b/src/backend/access/transam/xlogfuncs.c @@ -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")))); diff --git a/src/backend/catalog/Catalog.pm b/src/backend/catalog/Catalog.pm index fd52f48f34..523b37995d 100644 --- a/src/backend/catalog/Catalog.pm +++ b/src/backend/catalog/Catalog.pm @@ -176,7 +176,7 @@ sub Catalogs } } } - $catalogs{$catname} = \%catalog if defined $catname; + $catalogs{$catname} = \%catalog; close INPUT_FILE; } return \%catalogs; diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile index a6de2ff054..a403c64360 100644 --- a/src/backend/catalog/Makefile +++ b/src/backend/catalog/Makefile @@ -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 \ diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c index cd60739352..d30612c4d9 100644 --- a/src/backend/catalog/aclchk.c +++ b/src/backend/catalog/aclchk.c @@ -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; } /* diff --git a/src/backend/catalog/genbki.pl b/src/backend/catalog/genbki.pl index 415ac17a7b..ca8987907c 100644 --- a/src/backend/catalog/genbki.pl +++ b/src/backend/catalog/genbki.pl @@ -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') diff --git a/src/backend/catalog/information_schema.sql b/src/backend/catalog/information_schema.sql index 87b6d8ce9c..a036c62a33 100644 --- a/src/backend/catalog/information_schema.sql +++ b/src/backend/catalog/information_schema.sql @@ -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; diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index 128863744c..1f80176cdd 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -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"))); diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index ae93832215..22b8ceef62 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -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 diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c index c079168c83..1a5244cade 100644 --- a/src/backend/commands/dbcommands.c +++ b/src/backend/commands/dbcommands.c @@ -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 * diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c index 564f77a869..1a73fd8558 100644 --- a/src/backend/commands/user.c +++ b/src/backend/commands/user.c @@ -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), diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 491dc38caf..6ce8daeb95 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -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); diff --git a/src/backend/replication/logical/logicalfuncs.c b/src/backend/replication/logical/logicalfuncs.c index 1a38f56a7c..1977f098c7 100644 --- a/src/backend/replication/logical/logicalfuncs.c +++ b/src/backend/replication/logical/logicalfuncs.c @@ -17,14 +17,18 @@ #include -#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")))); diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c index c113a0bbaa..bd4701f97d 100644 --- a/src/backend/replication/slotfuncs.c +++ b/src/backend/replication/slotfuncs.c @@ -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")))); diff --git a/src/backend/rewrite/rowsecurity.c b/src/backend/rewrite/rowsecurity.c index f41ad34744..6c232dcf9a 100644 --- a/src/backend/rewrite/rowsecurity.c +++ b/src/backend/rewrite/rowsecurity.c @@ -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 diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c index 4c03955799..dc6eb2c8aa 100644 --- a/src/backend/utils/adt/acl.c +++ b/src/backend/utils/adt/acl.c @@ -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 */ diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c index ccb1066732..5c75390ce4 100644 --- a/src/backend/utils/adt/ri_triggers.c +++ b/src/backend/utils/adt/ri_triggers.c @@ -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 && diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c index db2a0fb48e..8fccb4c826 100644 --- a/src/backend/utils/init/miscinit.c +++ b/src/backend/utils/init/miscinit.c @@ -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", diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c index 268001f58a..c34803437b 100644 --- a/src/backend/utils/init/postinit.c +++ b/src/backend/utils/init/postinit.c @@ -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"))); diff --git a/src/backend/utils/misc/superuser.c b/src/backend/utils/misc/superuser.c index 67d070ca25..ff0f94711d 100644 --- a/src/backend/utils/misc/superuser.c +++ b/src/backend/utils/misc/superuser.c @@ -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 diff --git a/src/bin/pg_dump/pg_dumpall.c b/src/bin/pg_dump/pg_dumpall.c index f638167d8f..eb633bc136 100644 --- a/src/bin/pg_dump/pg_dumpall.c +++ b/src/bin/pg_dump/pg_dumpall.c @@ -671,16 +671,10 @@ dumpRoles(PGconn *conn) /* note: rolconfig is dumped later */ if (server_version >= 90500) printfPQExpBuffer(buf, - "SELECT oid, rolname, " - "pg_check_role_attribute(oid, 'SUPERUSER') AS rolsuper, " - "pg_check_role_attribute(oid, 'INHERIT') AS rolinherit, " - "pg_check_role_attribute(oid, 'CREATEROLE') AS rolcreaterole, " - "pg_check_role_attribute(oid, 'CREATEDB') AS rolcreatedb, " - "pg_check_role_attribute(oid, 'CANLOGIN') AS rolcanlogin, " - "pg_check_role_attribute(oid, 'REPLICATION') AS rolreplication, " - "pg_check_role_attribute(oid, 'BYPASSRLS') AS rolbypassrls, " - "rolconnlimit, rolpassword, " - "rolvaliduntil, " + "SELECT oid, rolname, rolsuper, rolinherit, " + "rolcreaterole, rolcreatedb, " + "rolcanlogin, rolconnlimit, rolpassword, " + "rolvaliduntil, rolreplication, rolbypassrls, " "pg_catalog.shobj_description(oid, 'pg_authid') as rolcomment, " "rolname = current_user AS is_current_user " "FROM pg_authid " diff --git a/src/include/catalog/acldefs.h b/src/include/catalog/acldefs.h deleted file mode 100644 index 2dcc17495d..0000000000 --- a/src/include/catalog/acldefs.h +++ /dev/null @@ -1,72 +0,0 @@ -/*------------------------------------------------------------------------- - * - * acldefs.h - * base definitions for ACLs and role attributes - * - * Portions Copyright (c) 2014, PostgreSQL Global Development Group - * - * src/include/catalog/acldefs.h - * - *------------------------------------------------------------------------- - */ -#ifndef ACLDEFS_H -#define ACLDEFS_H - -/* - * Grantable rights are encoded so that we can OR them together in a bitmask. - * The present representation of AclItem limits us to 16 distinct rights, - * even though AclMode is defined as uint32. See utils/acl.h. - * - * Caution: changing these codes breaks stored ACLs, hence forces initdb. - */ -typedef uint32 AclMode; /* a bitmask of privilege bits */ - -#define ACL_INSERT (1<<0) /* for relations */ -#define ACL_SELECT (1<<1) -#define ACL_UPDATE (1<<2) -#define ACL_DELETE (1<<3) -#define ACL_TRUNCATE (1<<4) -#define ACL_REFERENCES (1<<5) -#define ACL_TRIGGER (1<<6) -#define ACL_EXECUTE (1<<7) /* for functions */ -#define ACL_USAGE (1<<8) /* for languages, namespaces, FDWs, and - * servers */ -#define ACL_CREATE (1<<9) /* for namespaces and databases */ -#define ACL_CREATE_TEMP (1<<10) /* for databases */ -#define ACL_CONNECT (1<<11) /* for databases */ -#define N_ACL_RIGHTS 12 /* 1 plus the last 1<