Skip to content

Commit 1826987

Browse files
committed
Use a bitmask to represent role attributes
The previous representation using a boolean column for each attribute would not scale as well as we want to add further attributes. Extra auxilliary functions are added to go along with this change, to make up for the lost convenience of access of the old representation. Catalog version bumped due to change in catalogs and the new functions. Author: Adam Brightwell, minor tweaks by Álvaro Reviewed by: Stephen Frost, Andres Freund, Álvaro Herrera
1 parent 7eca575 commit 1826987

30 files changed

+798
-372
lines changed

doc/src/sgml/catalogs.sgml

Lines changed: 86 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1391,89 +1391,134 @@
13911391
</row>
13921392

13931393
<row>
1394-
<entry><structfield>rolsuper</structfield></entry>
1395-
<entry><type>bool</type></entry>
1394+
<entry><structfield>rolattr</structfield></entry>
1395+
<entry><type>bigint</type></entry>
1396+
<entry>
1397+
Role attributes; see <xref linkend="catalog-rolattr-bitmap-table"> and
1398+
<xref linkend="sql-createrole"> for details
1399+
</entry>
1400+
</row>
1401+
1402+
<row>
1403+
<entry><structfield>rolconnlimit</structfield></entry>
1404+
<entry><type>int4</type></entry>
1405+
<entry>
1406+
For roles that can log in, this sets maximum number of concurrent
1407+
connections this role can make. -1 means no limit.
1408+
</entry>
1409+
</row>
1410+
1411+
<row>
1412+
<entry><structfield>rolpassword</structfield></entry>
1413+
<entry><type>text</type></entry>
1414+
<entry>
1415+
Password (possibly encrypted); null if none. If the password
1416+
is encrypted, this column will begin with the string <literal>md5</>
1417+
followed by a 32-character hexadecimal MD5 hash. The MD5 hash
1418+
will be of the user's password concatenated to their user name.
1419+
For example, if user <literal>joe</> has password <literal>xyzzy</>,
1420+
<productname>PostgreSQL</> will store the md5 hash of
1421+
<literal>xyzzyjoe</>. A password that does not follow that
1422+
format is assumed to be unencrypted.
1423+
</entry>
1424+
</row>
1425+
1426+
<row>
1427+
<entry><structfield>rolvaliduntil</structfield></entry>
1428+
<entry><type>timestamptz</type></entry>
1429+
<entry>Password expiry time (only used for password authentication);
1430+
null if no expiration</entry>
1431+
</row>
1432+
</tbody>
1433+
</tgroup>
1434+
</table>
1435+
1436+
<table id="catalog-rolattr-bitmap-table">
1437+
<title>Attributes in <structfield>rolattr</></title>
1438+
1439+
<tgroup cols="4">
1440+
<thead>
1441+
<row>
1442+
<entry>Attribute</entry>
1443+
<entry>CREATE ROLE Option</entry>
1444+
<entry>Description</entry>
1445+
<entry>Position</entry>
1446+
</row>
1447+
</thead>
1448+
1449+
<tbody>
1450+
<row>
1451+
<entry>Superuser</entry>
1452+
<entry>SUPERUSER</entry>
13961453
<entry>Role has superuser privileges</entry>
1454+
<entry><literal>0</literal></entry>
13971455
</row>
13981456

13991457
<row>
1400-
<entry><structfield>rolinherit</structfield></entry>
1401-
<entry><type>bool</type></entry>
1402-
<entry>Role automatically inherits privileges of roles it is a
1403-
member of</entry>
1458+
<entry>Inherit</entry>
1459+
<entry>INHERIT</entry>
1460+
<entry>
1461+
Role automatically inherits privileges of roles it is a member of
1462+
</entry>
1463+
<entry><literal>1</literal></entry>
14041464
</row>
14051465

14061466
<row>
1407-
<entry><structfield>rolcreaterole</structfield></entry>
1408-
<entry><type>bool</type></entry>
1467+
<entry>Create Role</entry>
1468+
<entry>CREATEROLE</entry>
14091469
<entry>Role can create more roles</entry>
1470+
<entry><literal>2</literal></entry>
14101471
</row>
14111472

14121473
<row>
1413-
<entry><structfield>rolcreatedb</structfield></entry>
1414-
<entry><type>bool</type></entry>
1474+
<entry>Create DB</entry>
1475+
<entry>CREATEDB</entry>
14151476
<entry>Role can create databases</entry>
1477+
<entry><literal>3</literal></entry>
14161478
</row>
14171479

14181480
<row>
1419-
<entry><structfield>rolcatupdate</structfield></entry>
1420-
<entry><type>bool</type></entry>
1481+
<entry>Catalog Update</entry>
1482+
<entry>CATUPDATE</entry>
14211483
<entry>
14221484
Role can update system catalogs directly. (Even a superuser cannot do
14231485
this unless this column is true)
14241486
</entry>
1487+
<entry><literal>4</literal></entry>
14251488
</row>
14261489

14271490
<row>
1428-
<entry><structfield>rolcanlogin</structfield></entry>
1429-
<entry><type>bool</type></entry>
1491+
<entry>Can Login</entry>
1492+
<entry>LOGIN</entry>
14301493
<entry>
14311494
Role can log in. That is, this role can be given as the initial
14321495
session authorization identifier
14331496
</entry>
1497+
<entry><literal>5</literal></entry>
14341498
</row>
14351499

14361500
<row>
1437-
<entry><structfield>rolreplication</structfield></entry>
1438-
<entry><type>bool</type></entry>
1501+
<entry>Replication</entry>
1502+
<entry>REPLICATION</entry>
14391503
<entry>
14401504
Role is a replication role. That is, this role can initiate streaming
14411505
replication (see <xref linkend="streaming-replication">) and set/unset
14421506
the system backup mode using <function>pg_start_backup</> and
14431507
<function>pg_stop_backup</>
14441508
</entry>
1509+
<entry><literal>6</literal></entry>
14451510
</row>
14461511

14471512
<row>
1448-
<entry><structfield>rolconnlimit</structfield></entry>
1449-
<entry><type>int4</type></entry>
1513+
<entry>Bypass Row Level Security</entry>
1514+
<entry>BYPASSRLS</entry>
14501515
<entry>
1451-
For roles that can log in, this sets maximum number of concurrent
1452-
connections this role can make. -1 means no limit.
1453-
</entry>
1454-
</row>
1455-
1456-
<row>
1457-
<entry><structfield>rolpassword</structfield></entry>
1458-
<entry><type>text</type></entry>
1459-
<entry>
1460-
Password (possibly encrypted); null if none. If the password
1461-
is encrypted, this column will begin with the string <literal>md5</>
1462-
followed by a 32-character hexadecimal MD5 hash. The MD5 hash
1463-
will be of the user's password concatenated to their user name.
1464-
For example, if user <literal>joe</> has password <literal>xyzzy</>,
1465-
<productname>PostgreSQL</> will store the md5 hash of
1466-
<literal>xyzzyjoe</>. A password that does not follow that
1467-
format is assumed to be unencrypted.
1516+
Role can bypass row level security policies when <literal>row_security</>
1517+
is set <literal>off</>
14681518
</entry>
1519+
<entry><literal>7</literal></entry>
14691520
</row>
14701521

1471-
<row>
1472-
<entry><structfield>rolvaliduntil</structfield></entry>
1473-
<entry><type>timestamptz</type></entry>
1474-
<entry>Password expiry time (only used for password authentication);
1475-
null if no expiration</entry>
1476-
</row>
14771522
</tbody>
14781523
</tgroup>
14791524
</table>

doc/src/sgml/func.sgml

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15139,6 +15139,133 @@ SELECT has_function_privilege('joeuser', 'myfunc(int, text)', 'execute');
1513915139
are immediately available without doing <command>SET ROLE</>.
1514015140
</para>
1514115141

15142+
<para>
15143+
<xref linkend="functions-info-role-attribute-table"> lists functions that
15144+
allow the user to query role attribute information programmatically.
15145+
</para>
15146+
15147+
<table id="functions-info-role-attribute-table">
15148+
<title>Role Attribute Inquiry Functions</title>
15149+
<tgroup cols="3">
15150+
<thead>
15151+
<row><entry>Name</entry> <entry>Return Type</entry> <entry>Description</entry></row>
15152+
</thead>
15153+
<tbody>
15154+
<row>
15155+
<entry><literal><function>pg_has_role_attribute(role, attribute)</function></literal></entry>
15156+
<entry><type>boolean</type></entry>
15157+
<entry>does role have the permissions allowed by named attribute</entry>
15158+
</row>
15159+
<row>
15160+
<entry><literal><function>pg_check_role_attribute(role, attribute)</function></literal></entry>
15161+
<entry><type>boolean</type></entry>
15162+
<entry>does role have the named attribute</entry>
15163+
</row>
15164+
<row>
15165+
<entry><literal><function>pg_check_role_attribute(role_attributes, attribute)</function></literal></entry>
15166+
<entry><type>boolean</type></entry>
15167+
<entry>is attribute set in bitmap of role attributes</entry>
15168+
</row>
15169+
<row>
15170+
<entry><literal><function>pg_all_role_attributes(role_attributes)</function></literal></entry>
15171+
<entry><type>text[]</type></entry>
15172+
<entry>convert bitmap of role attribute representation to text[]</entry>
15173+
</row>
15174+
</tbody>
15175+
</tgroup>
15176+
</table>
15177+
15178+
<indexterm>
15179+
<primary>pg_has_role_attribute</primary>
15180+
</indexterm>
15181+
<indexterm>
15182+
<primary>pg_check_role_attribute</primary>
15183+
</indexterm>
15184+
<indexterm>
15185+
<primary>pg_all_role_attributes</primary>
15186+
</indexterm>
15187+
15188+
<para>
15189+
<function>pg_has_role_attribute</function> checks the attribute permissions
15190+
given to a role. It will always return <literal>true</literal> for roles
15191+
with superuser privileges unless the attribute being checked is
15192+
<literal>CATUPDATE</literal> (superuser cannot bypass
15193+
<literal>CATUPDATE</literal> permissions). The role can be specified by name
15194+
and by OID. The attribute is specified by a text string which must evaluate
15195+
to one of the following role attributes:
15196+
<literal>SUPERUSER</literal>,
15197+
<literal>INHERIT</literal>,
15198+
<literal>CREATEROLE</literal>,
15199+
<literal>CREATEDB</literal>,
15200+
<literal>CATUPDATE</literal>,
15201+
<literal>CANLOGIN</literal>,
15202+
<literal>REPLICATION</literal>, or
15203+
<literal>BYPASSRLS</literal>. See <xref linkend="sql-createrole"> for more
15204+
information. For example:
15205+
<programlisting>
15206+
SELECT pg_has_role_attribute('joe', 'SUPERUSER');
15207+
pg_has_role_attribute
15208+
-----------------------
15209+
f
15210+
(1 row)
15211+
15212+
SELECT rolname, pg_has_role_attribute(oid, 'INHERIT') AS rolinherit FROM pg_roles;
15213+
rolname | rolinherit
15214+
----------+------------
15215+
postgres | t
15216+
joe | t
15217+
(2 rows)
15218+
</programlisting>
15219+
</para>
15220+
15221+
<para>
15222+
<function>pg_check_role_attribute</function> checks the attribute value given
15223+
to a role. The role can be specified by name and by OID. The attribute is
15224+
specified by a text string which must evaluate to a valid role attribute (see
15225+
<function>pg_has_role_attribute</function>). A third variant of this function
15226+
allows for a bitmap representation (<literal>bigint</literal>) of attributes
15227+
to be given instead of a role.
15228+
Example:
15229+
<programlisting>
15230+
SELECT pg_check_role_attribute('joe', 'SUPERUSER');
15231+
pg_check_role_attribute
15232+
-------------------------
15233+
f
15234+
(1 row)
15235+
15236+
SELECT rolname, pg_check_role_attribute(oid, 'INHERIT') as rolinherit FROM pg_roles;
15237+
rolname | rolinherit
15238+
----------+------------
15239+
postgres | t
15240+
joe | t
15241+
(2 rows)
15242+
t
15243+
(1 row)
15244+
15245+
15246+
SELECT rolname, pg_check_role_attribute(rolattr, 'SUPERUSER') AS rolsuper FROM pg_authid;
15247+
rolname | rolsuper
15248+
----------+----------
15249+
postgres | t
15250+
joe | f
15251+
(2 rows)
15252+
</programlisting>
15253+
</para>
15254+
15255+
<para>
15256+
<function>pg_all_role_attributes</function> convert a set of role attributes
15257+
represented by an <literal>bigint</literal> bitmap to a text array.
15258+
Example:
15259+
<programlisting>
15260+
SELECT rolname, pg_all_role_attributes(rolattr) AS attributes FROM pg_authid;
15261+
rolname | attributes
15262+
----------+-----------------------------------------------------------------------------------------------
15263+
postgres | {Superuser,Inherit,"Create Role","Create DB","Catalog Update",Login,Replication,"Bypass RLS"}
15264+
joe | {Inherit,Login}
15265+
(2 rows)
15266+
</programlisting>
15267+
</para>
15268+
1514215269
<para>
1514315270
<xref linkend="functions-info-schema-table"> shows functions that
1514415271
determine whether a certain object is <firstterm>visible</> in the

src/backend/access/transam/xlogfuncs.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "miscadmin.h"
2828
#include "replication/walreceiver.h"
2929
#include "storage/smgr.h"
30+
#include "utils/acl.h"
3031
#include "utils/builtins.h"
3132
#include "utils/numeric.h"
3233
#include "utils/guc.h"
@@ -54,7 +55,7 @@ pg_start_backup(PG_FUNCTION_ARGS)
5455

5556
backupidstr = text_to_cstring(backupid);
5657

57-
if (!superuser() && !has_rolreplication(GetUserId()))
58+
if (!have_role_attribute(ROLE_ATTR_REPLICATION))
5859
ereport(ERROR,
5960
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
6061
errmsg("must be superuser or replication role to run a backup")));
@@ -82,7 +83,7 @@ pg_stop_backup(PG_FUNCTION_ARGS)
8283
{
8384
XLogRecPtr stoppoint;
8485

85-
if (!superuser() && !has_rolreplication(GetUserId()))
86+
if (!have_role_attribute(ROLE_ATTR_REPLICATION))
8687
ereport(ERROR,
8788
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
8889
(errmsg("must be superuser or replication role to run a backup"))));

src/backend/catalog/Catalog.pm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ sub Catalogs
176176
}
177177
}
178178
}
179-
$catalogs{$catname} = \%catalog;
179+
$catalogs{$catname} = \%catalog if defined $catname;
180180
close INPUT_FILE;
181181
}
182182
return \%catalogs;

src/backend/catalog/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ all: $(BKIFILES) schemapg.h
2828
# indexing.h had better be last, and toasting.h just before it.
2929

3030
POSTGRES_BKI_SRCS = $(addprefix $(top_srcdir)/src/include/catalog/,\
31-
pg_proc.h pg_type.h pg_attribute.h pg_class.h \
31+
acldefs.h pg_proc.h pg_type.h pg_attribute.h pg_class.h \
3232
pg_attrdef.h pg_constraint.h pg_inherits.h pg_index.h pg_operator.h \
3333
pg_opfamily.h pg_opclass.h pg_am.h pg_amop.h pg_amproc.h \
3434
pg_language.h pg_largeobject_metadata.h pg_largeobject.h pg_aggregate.h \

0 commit comments

Comments
 (0)