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:
parent
d7ee82e50f
commit
a609d96778
|
@ -1391,11 +1391,56 @@
|
|||
</row>
|
||||
|
||||
<row>
|
||||
<entry><structfield>rolattr</structfield></entry>
|
||||
<entry><type>bigint</type></entry>
|
||||
<entry><structfield>rolsuper</structfield></entry>
|
||||
<entry><type>bool</type></entry>
|
||||
<entry>Role has superuser privileges</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><structfield>rolinherit</structfield></entry>
|
||||
<entry><type>bool</type></entry>
|
||||
<entry>Role automatically inherits privileges of roles it is a
|
||||
member of</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><structfield>rolcreaterole</structfield></entry>
|
||||
<entry><type>bool</type></entry>
|
||||
<entry>Role can create more roles</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><structfield>rolcreatedb</structfield></entry>
|
||||
<entry><type>bool</type></entry>
|
||||
<entry>Role can create databases</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><structfield>rolcatupdate</structfield></entry>
|
||||
<entry><type>bool</type></entry>
|
||||
<entry>
|
||||
Role attributes; see <xref linkend="catalog-rolattr-bitmap-table"> and
|
||||
<xref linkend="sql-createrole"> for details
|
||||
Role can update system catalogs directly. (Even a superuser cannot do
|
||||
this unless this column is true)
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><structfield>rolcanlogin</structfield></entry>
|
||||
<entry><type>bool</type></entry>
|
||||
<entry>
|
||||
Role can log in. That is, this role can be given as the initial
|
||||
session authorization identifier
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><structfield>rolreplication</structfield></entry>
|
||||
<entry><type>bool</type></entry>
|
||||
<entry>
|
||||
Role is a replication role. That is, this role can initiate streaming
|
||||
replication (see <xref linkend="streaming-replication">) and set/unset
|
||||
the system backup mode using <function>pg_start_backup</> and
|
||||
<function>pg_stop_backup</>
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
|
@ -1433,96 +1478,6 @@
|
|||
</tgroup>
|
||||
</table>
|
||||
|
||||
<table id="catalog-rolattr-bitmap-table">
|
||||
<title>Attributes in <structfield>rolattr</></title>
|
||||
|
||||
<tgroup cols="4">
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Attribute</entry>
|
||||
<entry>CREATE ROLE Option</entry>
|
||||
<entry>Description</entry>
|
||||
<entry>Position</entry>
|
||||
</row>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>Superuser</entry>
|
||||
<entry>SUPERUSER</entry>
|
||||
<entry>Role has superuser privileges</entry>
|
||||
<entry><literal>0</literal></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>Inherit</entry>
|
||||
<entry>INHERIT</entry>
|
||||
<entry>
|
||||
Role automatically inherits privileges of roles it is a member of
|
||||
</entry>
|
||||
<entry><literal>1</literal></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>Create Role</entry>
|
||||
<entry>CREATEROLE</entry>
|
||||
<entry>Role can create more roles</entry>
|
||||
<entry><literal>2</literal></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>Create DB</entry>
|
||||
<entry>CREATEDB</entry>
|
||||
<entry>Role can create databases</entry>
|
||||
<entry><literal>3</literal></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>Catalog Update</entry>
|
||||
<entry>CATUPDATE</entry>
|
||||
<entry>
|
||||
Role can update system catalogs directly. (Even a superuser cannot do
|
||||
this unless this column is true)
|
||||
</entry>
|
||||
<entry><literal>4</literal></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>Can Login</entry>
|
||||
<entry>LOGIN</entry>
|
||||
<entry>
|
||||
Role can log in. That is, this role can be given as the initial
|
||||
session authorization identifier
|
||||
</entry>
|
||||
<entry><literal>5</literal></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>Replication</entry>
|
||||
<entry>REPLICATION</entry>
|
||||
<entry>
|
||||
Role is a replication role. That is, this role can initiate streaming
|
||||
replication (see <xref linkend="streaming-replication">) and set/unset
|
||||
the system backup mode using <function>pg_start_backup</> and
|
||||
<function>pg_stop_backup</>
|
||||
</entry>
|
||||
<entry><literal>6</literal></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>Bypass Row Level Security</entry>
|
||||
<entry>BYPASSRLS</entry>
|
||||
<entry>
|
||||
Role can bypass row level security policies when <literal>row_security</>
|
||||
is set <literal>off</>
|
||||
</entry>
|
||||
<entry><literal>7</literal></entry>
|
||||
</row>
|
||||
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
|
||||
</sect1>
|
||||
|
||||
|
||||
|
|
|
@ -15139,133 +15139,6 @@ SELECT has_function_privilege('joeuser', 'myfunc(int, text)', 'execute');
|
|||
are immediately available without doing <command>SET ROLE</>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<xref linkend="functions-info-role-attribute-table"> lists functions that
|
||||
allow the user to query role attribute information programmatically.
|
||||
</para>
|
||||
|
||||
<table id="functions-info-role-attribute-table">
|
||||
<title>Role Attribute Inquiry Functions</title>
|
||||
<tgroup cols="3">
|
||||
<thead>
|
||||
<row><entry>Name</entry> <entry>Return Type</entry> <entry>Description</entry></row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry><literal><function>pg_has_role_attribute(role, attribute)</function></literal></entry>
|
||||
<entry><type>boolean</type></entry>
|
||||
<entry>does role have the permissions allowed by named attribute</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal><function>pg_check_role_attribute(role, attribute)</function></literal></entry>
|
||||
<entry><type>boolean</type></entry>
|
||||
<entry>does role have the named attribute</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal><function>pg_check_role_attribute(role_attributes, attribute)</function></literal></entry>
|
||||
<entry><type>boolean</type></entry>
|
||||
<entry>is attribute set in bitmap of role attributes</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal><function>pg_all_role_attributes(role_attributes)</function></literal></entry>
|
||||
<entry><type>text[]</type></entry>
|
||||
<entry>convert bitmap of role attribute representation to text[]</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
|
||||
<indexterm>
|
||||
<primary>pg_has_role_attribute</primary>
|
||||
</indexterm>
|
||||
<indexterm>
|
||||
<primary>pg_check_role_attribute</primary>
|
||||
</indexterm>
|
||||
<indexterm>
|
||||
<primary>pg_all_role_attributes</primary>
|
||||
</indexterm>
|
||||
|
||||
<para>
|
||||
<function>pg_has_role_attribute</function> checks the attribute permissions
|
||||
given to a role. It will always return <literal>true</literal> for roles
|
||||
with superuser privileges unless the attribute being checked is
|
||||
<literal>CATUPDATE</literal> (superuser cannot bypass
|
||||
<literal>CATUPDATE</literal> 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:
|
||||
<literal>SUPERUSER</literal>,
|
||||
<literal>INHERIT</literal>,
|
||||
<literal>CREATEROLE</literal>,
|
||||
<literal>CREATEDB</literal>,
|
||||
<literal>CATUPDATE</literal>,
|
||||
<literal>CANLOGIN</literal>,
|
||||
<literal>REPLICATION</literal>, or
|
||||
<literal>BYPASSRLS</literal>. See <xref linkend="sql-createrole"> for more
|
||||
information. For example:
|
||||
<programlisting>
|
||||
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)
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<function>pg_check_role_attribute</function> 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
|
||||
<function>pg_has_role_attribute</function>). A third variant of this function
|
||||
allows for a bitmap representation (<literal>bigint</literal>) of attributes
|
||||
to be given instead of a role.
|
||||
Example:
|
||||
<programlisting>
|
||||
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)
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<function>pg_all_role_attributes</function> convert a set of role attributes
|
||||
represented by an <literal>bigint</literal> bitmap to a text array.
|
||||
Example:
|
||||
<programlisting>
|
||||
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)
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<xref linkend="functions-info-schema-table"> shows functions that
|
||||
determine whether a certain object is <firstterm>visible</> in the
|
||||
|
|
|
@ -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"))));
|
||||
|
|
|
@ -176,7 +176,7 @@ sub Catalogs
|
|||
}
|
||||
}
|
||||
}
|
||||
$catalogs{$catname} = \%catalog if defined $catname;
|
||||
$catalogs{$catname} = \%catalog;
|
||||
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/,\
|
||||
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 \
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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")));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
*
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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"))));
|
||||
|
|
|
@ -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"))));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 &&
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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")));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 "
|
||||
|
|
|
@ -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<<x */
|
||||
#define ACL_NO_RIGHTS 0
|
||||
/* Currently, SELECT ... FOR [KEY] UPDATE/SHARE requires UPDATE privileges */
|
||||
#define ACL_SELECT_FOR_UPDATE ACL_UPDATE
|
||||
|
||||
#define ACL_ID_PUBLIC 0 /* placeholder for id in a PUBLIC acl item */
|
||||
|
||||
|
||||
/*
|
||||
* Role attributes are encoded so that we can OR them together in a bitmask.
|
||||
* The present representation of RoleAttr (defined in acl.h) limits us to 64
|
||||
* distinct rights.
|
||||
*
|
||||
* Note about ROLE_ATTR_ALL: This symbol is used verbatim by genbki.pl, which
|
||||
* means we need to hard-code its value instead of using a symbolic definition.
|
||||
* Therefore, whenever role attributes are changed, this value MUST be updated
|
||||
* manually.
|
||||
*/
|
||||
|
||||
/* A bitmask for role attributes */
|
||||
typedef uint64 RoleAttr;
|
||||
|
||||
#define ROLE_ATTR_NONE 0
|
||||
#define ROLE_ATTR_SUPERUSER (1<<0)
|
||||
#define ROLE_ATTR_INHERIT (1<<1)
|
||||
#define ROLE_ATTR_CREATEROLE (1<<2)
|
||||
#define ROLE_ATTR_CREATEDB (1<<3)
|
||||
#define ROLE_ATTR_CATUPDATE (1<<4)
|
||||
#define ROLE_ATTR_CANLOGIN (1<<5)
|
||||
#define ROLE_ATTR_REPLICATION (1<<6)
|
||||
#define ROLE_ATTR_BYPASSRLS (1<<7)
|
||||
#define N_ROLE_ATTRIBUTES 8 /* 1 plus the last 1<<x */
|
||||
#define ROLE_ATTR_ALL 255 /* (1 << N_ROLE_ATTRIBUTES) - 1 */
|
||||
|
||||
|
||||
#endif /* ACLDEFS_H */
|
|
@ -53,6 +53,6 @@
|
|||
*/
|
||||
|
||||
/* yyyymmddN */
|
||||
#define CATALOG_VERSION_NO 201412233
|
||||
#define CATALOG_VERSION_NO 201412234
|
||||
|
||||
#endif
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#ifndef PG_AUTHID_H
|
||||
#define PG_AUTHID_H
|
||||
|
||||
#include "catalog/acldefs.h"
|
||||
#include "catalog/genbki.h"
|
||||
|
||||
/*
|
||||
|
@ -46,8 +45,16 @@
|
|||
CATALOG(pg_authid,1260) BKI_SHARED_RELATION BKI_ROWTYPE_OID(2842) BKI_SCHEMA_MACRO
|
||||
{
|
||||
NameData rolname; /* name of role */
|
||||
int64 rolattr; /* role attribute bitmask */
|
||||
bool rolsuper; /* read this field via superuser() only! */
|
||||
bool rolinherit; /* inherit privileges from other roles? */
|
||||
bool rolcreaterole; /* allowed to create more roles? */
|
||||
bool rolcreatedb; /* allowed to create databases? */
|
||||
bool rolcatupdate; /* allowed to alter catalogs manually? */
|
||||
bool rolcanlogin; /* allowed to log in as session user? */
|
||||
bool rolreplication; /* role used for streaming replication */
|
||||
bool rolbypassrls; /* allowed to bypass row level security? */
|
||||
int32 rolconnlimit; /* max connections allowed (-1=no limit) */
|
||||
|
||||
/* remaining fields may be null; use heap_getattr to read them! */
|
||||
text rolpassword; /* password, if any */
|
||||
timestamptz rolvaliduntil; /* password expiration time, if any */
|
||||
|
@ -67,25 +74,28 @@ typedef FormData_pg_authid *Form_pg_authid;
|
|||
* compiler constants for pg_authid
|
||||
* ----------------
|
||||
*/
|
||||
#define Natts_pg_authid 5
|
||||
#define Natts_pg_authid 12
|
||||
#define Anum_pg_authid_rolname 1
|
||||
#define Anum_pg_authid_rolattr 2
|
||||
#define Anum_pg_authid_rolconnlimit 3
|
||||
#define Anum_pg_authid_rolpassword 4
|
||||
#define Anum_pg_authid_rolvaliduntil 5
|
||||
|
||||
#define Anum_pg_authid_rolsuper 2
|
||||
#define Anum_pg_authid_rolinherit 3
|
||||
#define Anum_pg_authid_rolcreaterole 4
|
||||
#define Anum_pg_authid_rolcreatedb 5
|
||||
#define Anum_pg_authid_rolcatupdate 6
|
||||
#define Anum_pg_authid_rolcanlogin 7
|
||||
#define Anum_pg_authid_rolreplication 8
|
||||
#define Anum_pg_authid_rolbypassrls 9
|
||||
#define Anum_pg_authid_rolconnlimit 10
|
||||
#define Anum_pg_authid_rolpassword 11
|
||||
#define Anum_pg_authid_rolvaliduntil 12
|
||||
|
||||
/* ----------------
|
||||
* initial contents of pg_authid
|
||||
*
|
||||
* The uppercase quantities will be replaced at initdb time with
|
||||
* user choices.
|
||||
*
|
||||
* PGROLATTRALL is substituted by genbki.pl to use the value defined by
|
||||
* ROLE_ATTR_ALL.
|
||||
* ----------------
|
||||
*/
|
||||
DATA(insert OID = 10 ( "POSTGRES" PGROLATTRALL -1 _null_ _null_));
|
||||
DATA(insert OID = 10 ( "POSTGRES" t t t t t t t t -1 _null_ _null_));
|
||||
|
||||
#define BOOTSTRAP_SUPERUSERID 10
|
||||
|
||||
|
|
|
@ -5139,19 +5139,6 @@ DESCR("rank of hypothetical row without gaps");
|
|||
DATA(insert OID = 3993 ( dense_rank_final PGNSP PGUID 12 1 0 2276 0 f f f f f f i 2 0 20 "2281 2276" "{2281,2276}" "{i,v}" _null_ _null_ hypothetical_dense_rank_final _null_ _null_ _null_ ));
|
||||
DESCR("aggregate final function");
|
||||
|
||||
/* role attribute support functions */
|
||||
DATA(insert OID = 3994 ( pg_has_role_attribute PGNSP PGUID 12 1 0 0 0 f f f f t f s 2 0 16 "26 25" _null_ _null_ _null_ _null_ pg_has_role_attribute_id _null_ _null_ _null_ ));
|
||||
DESCR("check role attribute by role oid with superuser bypass check");
|
||||
DATA(insert OID = 3995 ( pg_has_role_attribute PGNSP PGUID 12 1 0 0 0 f f f f t f s 2 0 16 "19 25" _null_ _null_ _null_ _null_ pg_has_role_attribute_name _null_ _null_ _null_ ));
|
||||
DESCR("check role attribute by role name with superuser bypass check");
|
||||
DATA(insert OID = 3996 ( pg_check_role_attribute PGNSP PGUID 12 1 0 0 0 f f f f t f s 2 0 16 "26 25" _null_ _null_ _null_ _null_ pg_check_role_attribute_id _null_ _null_ _null_ ));
|
||||
DESCR("check role attribute by role id");
|
||||
DATA(insert OID = 3997 ( pg_check_role_attribute PGNSP PGUID 12 1 0 0 0 f f f f t f s 2 0 16 "19 25" _null_ _null_ _null_ _null_ pg_check_role_attribute_name _null_ _null_ _null_ ));
|
||||
DESCR("check role attribute by role name");
|
||||
DATA(insert OID = 3998 ( pg_check_role_attribute PGNSP PGUID 12 1 0 0 0 f f f f t f s 2 0 16 "20 25" _null_ _null_ _null_ _null_ pg_check_role_attribute_attrs _null_ _null_ _null_ ));
|
||||
DESCR("check role attribute");
|
||||
DATA(insert OID = 3999 ( pg_all_role_attributes PGNSP PGUID 12 10 0 0 0 f f f f t f s 1 0 1009 "20" _null_ _null_ _null_ _null_ pg_all_role_attributes _null_ _null_ _null_));
|
||||
DESCR("convert role attributes to string array");
|
||||
|
||||
/*
|
||||
* Symbolic values for provolatile column: these indicate whether the result
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
#include "nodes/bitmapset.h"
|
||||
#include "nodes/primnodes.h"
|
||||
#include "nodes/value.h"
|
||||
#include "catalog/acldefs.h"
|
||||
#include "utils/lockwaitpolicy.h"
|
||||
|
||||
/* Possible sources of a Query */
|
||||
|
@ -52,6 +51,33 @@ typedef enum SortByNulls
|
|||
SORTBY_NULLS_LAST
|
||||
} SortByNulls;
|
||||
|
||||
/*
|
||||
* 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<<x */
|
||||
#define ACL_NO_RIGHTS 0
|
||||
/* Currently, SELECT ... FOR [KEY] UPDATE/SHARE requires UPDATE privileges */
|
||||
#define ACL_SELECT_FOR_UPDATE ACL_UPDATE
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* Query Tree
|
||||
|
|
|
@ -29,6 +29,13 @@
|
|||
#include "utils/snapshot.h"
|
||||
|
||||
|
||||
/*
|
||||
* typedef AclMode is declared in parsenodes.h, also the individual privilege
|
||||
* bit meanings are defined there
|
||||
*/
|
||||
|
||||
#define ACL_ID_PUBLIC 0 /* placeholder for id in a PUBLIC acl item */
|
||||
|
||||
/*
|
||||
* AclItem
|
||||
*
|
||||
|
@ -319,10 +326,7 @@ extern bool pg_foreign_data_wrapper_ownercheck(Oid srv_oid, Oid roleid);
|
|||
extern bool pg_foreign_server_ownercheck(Oid srv_oid, Oid roleid);
|
||||
extern bool pg_event_trigger_ownercheck(Oid et_oid, Oid roleid);
|
||||
extern bool pg_extension_ownercheck(Oid ext_oid, Oid roleid);
|
||||
|
||||
/* role attribute check routines */
|
||||
extern bool has_role_attribute(Oid roleid, RoleAttr attribute);
|
||||
extern bool have_role_attribute(RoleAttr attribute);
|
||||
extern bool check_role_attribute(Oid roleid, RoleAttr attribute);
|
||||
extern bool has_createrole_privilege(Oid roleid);
|
||||
extern bool has_bypassrls_privilege(Oid roleid);
|
||||
|
||||
#endif /* ACL_H */
|
||||
|
|
|
@ -106,12 +106,6 @@ extern Datum pg_has_role_id_name(PG_FUNCTION_ARGS);
|
|||
extern Datum pg_has_role_id_id(PG_FUNCTION_ARGS);
|
||||
extern Datum pg_has_role_name(PG_FUNCTION_ARGS);
|
||||
extern Datum pg_has_role_id(PG_FUNCTION_ARGS);
|
||||
extern Datum pg_has_role_attribute_id(PG_FUNCTION_ARGS);
|
||||
extern Datum pg_has_role_attribute_name(PG_FUNCTION_ARGS);
|
||||
extern Datum pg_check_role_attribute_id(PG_FUNCTION_ARGS);
|
||||
extern Datum pg_check_role_attribute_name(PG_FUNCTION_ARGS);
|
||||
extern Datum pg_check_role_attribute_attrs(PG_FUNCTION_ARGS);
|
||||
extern Datum pg_all_role_attributes(PG_FUNCTION_ARGS);
|
||||
|
||||
/* bool.c */
|
||||
extern Datum boolin(PG_FUNCTION_ARGS);
|
||||
|
|
|
@ -1314,7 +1314,7 @@ pg_group| SELECT pg_authid.rolname AS groname,
|
|||
FROM pg_auth_members
|
||||
WHERE (pg_auth_members.roleid = pg_authid.oid)) AS grolist
|
||||
FROM pg_authid
|
||||
WHERE (NOT pg_check_role_attribute(pg_authid.rolattr, 'CANLOGIN'::text));
|
||||
WHERE (NOT pg_authid.rolcanlogin);
|
||||
pg_indexes| SELECT n.nspname AS schemaname,
|
||||
c.relname AS tablename,
|
||||
i.relname AS indexname,
|
||||
|
@ -1405,17 +1405,17 @@ pg_replication_slots| SELECT l.slot_name,
|
|||
FROM (pg_get_replication_slots() l(slot_name, plugin, slot_type, datoid, active, xmin, catalog_xmin, restart_lsn)
|
||||
LEFT JOIN pg_database d ON ((l.datoid = d.oid)));
|
||||
pg_roles| SELECT pg_authid.rolname,
|
||||
pg_check_role_attribute(pg_authid.rolattr, 'SUPERUSER'::text) AS rolsuper,
|
||||
pg_check_role_attribute(pg_authid.rolattr, 'INHERIT'::text) AS rolinherit,
|
||||
pg_check_role_attribute(pg_authid.rolattr, 'CREATEROLE'::text) AS rolcreaterole,
|
||||
pg_check_role_attribute(pg_authid.rolattr, 'CREATEDB'::text) AS rolcreatedb,
|
||||
pg_check_role_attribute(pg_authid.rolattr, 'CATUPDATE'::text) AS rolcatupdate,
|
||||
pg_check_role_attribute(pg_authid.rolattr, 'CANLOGIN'::text) AS rolcanlogin,
|
||||
pg_check_role_attribute(pg_authid.rolattr, 'REPLICATION'::text) AS rolreplication,
|
||||
pg_check_role_attribute(pg_authid.rolattr, 'BYPASSRLS'::text) AS rolbypassrls,
|
||||
pg_authid.rolsuper,
|
||||
pg_authid.rolinherit,
|
||||
pg_authid.rolcreaterole,
|
||||
pg_authid.rolcreatedb,
|
||||
pg_authid.rolcatupdate,
|
||||
pg_authid.rolcanlogin,
|
||||
pg_authid.rolreplication,
|
||||
pg_authid.rolconnlimit,
|
||||
'********'::text AS rolpassword,
|
||||
pg_authid.rolvaliduntil,
|
||||
pg_authid.rolbypassrls,
|
||||
s.setconfig AS rolconfig,
|
||||
pg_authid.oid
|
||||
FROM (pg_authid
|
||||
|
@ -1608,16 +1608,16 @@ pg_settings| SELECT a.name,
|
|||
FROM pg_show_all_settings() a(name, setting, unit, category, short_desc, extra_desc, context, vartype, source, min_val, max_val, enumvals, boot_val, reset_val, sourcefile, sourceline);
|
||||
pg_shadow| SELECT pg_authid.rolname AS usename,
|
||||
pg_authid.oid AS usesysid,
|
||||
pg_check_role_attribute(pg_authid.rolattr, 'CREATEDB'::text) AS usecreatedb,
|
||||
pg_check_role_attribute(pg_authid.rolattr, 'SUPERUSER'::text) AS usesuper,
|
||||
pg_check_role_attribute(pg_authid.rolattr, 'CATUPDATE'::text) AS usecatupd,
|
||||
pg_check_role_attribute(pg_authid.rolattr, 'REPLICATION'::text) AS userepl,
|
||||
pg_authid.rolcreatedb AS usecreatedb,
|
||||
pg_authid.rolsuper AS usesuper,
|
||||
pg_authid.rolcatupdate AS usecatupd,
|
||||
pg_authid.rolreplication AS userepl,
|
||||
pg_authid.rolpassword AS passwd,
|
||||
(pg_authid.rolvaliduntil)::abstime AS valuntil,
|
||||
s.setconfig AS useconfig
|
||||
FROM (pg_authid
|
||||
LEFT JOIN pg_db_role_setting s ON (((pg_authid.oid = s.setrole) AND (s.setdatabase = (0)::oid))))
|
||||
WHERE pg_check_role_attribute(pg_authid.rolattr, 'CANLOGIN'::text);
|
||||
WHERE pg_authid.rolcanlogin;
|
||||
pg_stat_activity| SELECT s.datid,
|
||||
d.datname,
|
||||
s.pid,
|
||||
|
|
Loading…
Reference in New Issue