All,
I have attached and updated patch for review.
Thanks,
Adam
--
Adam Brightwell - [email protected]
Database Engineer - www.crunchydatasolutions.com
diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
new file mode 100644
index 62305d2..fd4b9ab
*** a/doc/src/sgml/catalogs.sgml
--- b/doc/src/sgml/catalogs.sgml
***************
*** 1445,1450 ****
--- 1445,1486 ----
</row>
<row>
+ <entry><structfield>rolbypassrls</structfield></entry>
+ <entry><type>bool</type></entry>
+ <entry>Role can bypass row level security</entry>
+ </row>
+
+ <row>
+ <entry><structfield>rolexclbackup</structfield></entry>
+ <entry><type>bool</type></entry>
+ <entry>Role can perform on-line exclusive backup operations</entry>
+ </row>
+
+ <row>
+ <entry><structfield>rolxlogreplay</structfield></entry>
+ <entry><type>bool</type></entry>
+ <entry>Role can control xlog recovery replay operations</entry>
+ </row>
+
+ <row>
+ <entry><structfield>rollogfile</structfield></entry>
+ <entry><type>bool</type></entry>
+ <entry>Role can rotate log files</entry>
+ </row>
+
+ <row>
+ <entry><structfield>rolmonitor</structfield></entry>
+ <entry><type>bool</type></entry>
+ <entry>Role can view pg_stat_* details</entry>
+ </row>
+
+ <row>
+ <entry><structfield>rolsignal</structfield></entry>
+ <entry><type>bool</type></entry>
+ <entry>Role can signal backend processes</entry>
+ </row>
+
+ <row>
<entry><structfield>rolconnlimit</structfield></entry>
<entry><type>int4</type></entry>
<entry>
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
new file mode 100644
index d57243a..096c770
*** a/doc/src/sgml/func.sgml
--- b/doc/src/sgml/func.sgml
*************** SELECT set_config('log_statement_stats',
*** 16425,16438 ****
<literal><function>pg_start_backup(<parameter>label</> <type>text</> <optional>, <parameter>fast</> <type>boolean</> </optional>)</function></literal>
</entry>
<entry><type>pg_lsn</type></entry>
! <entry>Prepare for performing on-line backup (restricted to superusers or replication roles)</entry>
</row>
<row>
<entry>
<literal><function>pg_stop_backup()</function></literal>
</entry>
<entry><type>pg_lsn</type></entry>
! <entry>Finish performing on-line backup (restricted to superusers or replication roles)</entry>
</row>
<row>
<entry>
--- 16425,16438 ----
<literal><function>pg_start_backup(<parameter>label</> <type>text</> <optional>, <parameter>fast</> <type>boolean</> </optional>)</function></literal>
</entry>
<entry><type>pg_lsn</type></entry>
! <entry>Prepare for performing on-line exclusive backup (restricted to superusers or replication roles)</entry>
</row>
<row>
<entry>
<literal><function>pg_stop_backup()</function></literal>
</entry>
<entry><type>pg_lsn</type></entry>
! <entry>Finish performing on-line exclusive backup (restricted to superusers or replication roles)</entry>
</row>
<row>
<entry>
diff --git a/doc/src/sgml/ref/create_role.sgml b/doc/src/sgml/ref/create_role.sgml
new file mode 100644
index ea26027..0fc3b42
*** a/doc/src/sgml/ref/create_role.sgml
--- b/doc/src/sgml/ref/create_role.sgml
*************** CREATE ROLE <replaceable class="PARAMETE
*** 33,38 ****
--- 33,43 ----
| LOGIN | NOLOGIN
| REPLICATION | NOREPLICATION
| BYPASSRLS | NOBYPASSRLS
+ | EXCLUSIVEBACKUP | NOEXCLUSIVEBACKUP
+ | XLOGREPLAY | NOXLOGREPLAY
+ | LOGFILE | NOLOGFILE
+ | MONITOR | NOMONITOR
+ | SIGNAL | NOSIGNAL
| CONNECTION LIMIT <replaceable class="PARAMETER">connlimit</replaceable>
| [ ENCRYPTED | UNENCRYPTED ] PASSWORD '<replaceable class="PARAMETER">password</replaceable>'
| VALID UNTIL '<replaceable class="PARAMETER">timestamp</replaceable>'
*************** CREATE ROLE <replaceable class="PARAMETE
*** 209,214 ****
--- 214,283 ----
</para>
</listitem>
</varlistentry>
+
+ <varlistentry>
+ <term><literal>EXCLUSIVEBACKUP</literal></term>
+ <term><literal>NOEXCLUSIVEBACKUP</literal></term>
+ <listitem>
+ <para>
+ These clauses determine whether a role is allowed to start/stop an
+ on-line exclusive backup. An on-line exclusive backup is one that is
+ initiated by the low-level base backup api instead of through the
+ replication protocol, see <xref linkend=backup-lowlevel-base-backup>.
+ If not specified, <literal>NOEXCLUSIVEBACKUP</literal> is the default.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>XLOGREPLAY</literal></term>
+ <term><literal>NOXLOGREPLAY</literal></term>
+ <listitem>
+ <para>
+ These clauses determine whether a role is allowed to pause/resume xlog
+ recovery.
+ If not specified, <literal>NOXLOGREPLAY</literal> is the default.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>LOGFILE</literal></term>
+ <term><literal>NOLOGFILE</literal></term>
+ <listitem>
+ <para>
+ These clauses determine whether a role is allowed to rotate log files.
+ If not specified, <literal>NOLOGFILE</literal> is the default.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>MONITOR</literal></term>
+ <term><literal>NOMONITOR</literal></term>
+ <listitem>
+ <para>
+ These clauses determine whether a role is allowed to view details from
+ calling pg_stat_* functions.
+ If not specified, <literal>NOMONITOR</literal> is the default.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>SIGNAL</literal></term>
+ <term><literal>NOSIGNAL</literal></term>
+ <listitem>
+ <para>
+ These clauses determine whether a role is allowed to signal backend
+ processes. A role having the <literal>SIGNAL</literal> attribute will be
+ allowed to signal backend processes that it owns and those roles which it
+ is a member. Roles with this attribute cannot signal backend processes
+ that are owned by a superuser.
+ If not specified, <literal>NOSIGNAL</literal> is the default.
+ </para>
+ </listitem>
+ </varlistentry>
<varlistentry>
<term><literal>CONNECTION LIMIT</literal> <replaceable class="parameter">connlimit</replaceable></term>
diff --git a/doc/src/sgml/ref/create_user.sgml b/doc/src/sgml/ref/create_user.sgml
new file mode 100644
index 065999c..f7f10c7
*** a/doc/src/sgml/ref/create_user.sgml
--- b/doc/src/sgml/ref/create_user.sgml
*************** CREATE USER <replaceable class="PARAMETE
*** 32,37 ****
--- 32,43 ----
| INHERIT | NOINHERIT
| LOGIN | NOLOGIN
| REPLICATION | NOREPLICATION
+ | BYPASSRLS | NOBYPASSRLS
+ | EXCLUSIVEBACKUP | NOEXCLUSIVEBACKUP
+ | XLOGREPLAY | NOXLOGREPLAY
+ | LOGFILE | NOLOGFILE
+ | MONITOR | NOMONITOR
+ | SIGNAL | NOSIGNAL
| CONNECTION LIMIT <replaceable class="PARAMETER">connlimit</replaceable>
| [ ENCRYPTED | UNENCRYPTED ] PASSWORD '<replaceable class="PARAMETER">password</replaceable>'
| VALID UNTIL '<replaceable class="PARAMETER">timestamp</replaceable>'
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
new file mode 100644
index 2179bf7..12b8a17
*** a/src/backend/access/transam/xlogfuncs.c
--- b/src/backend/access/transam/xlogfuncs.c
***************
*** 27,32 ****
--- 27,33 ----
#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"
*************** pg_start_backup(PG_FUNCTION_ARGS)
*** 54,63 ****
backupidstr = text_to_cstring(backupid);
! if (!superuser() && !has_rolreplication(GetUserId()))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! errmsg("must be superuser or replication role to run a backup")));
startpoint = do_pg_start_backup(backupidstr, fast, NULL, NULL);
--- 55,65 ----
backupidstr = text_to_cstring(backupid);
! if (!has_replication_privilege(GetUserId())
! && !has_exclbackup_privilege(GetUserId()))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! errmsg("must be superuser, replication role or exclusive backup role to run a backup")));
startpoint = do_pg_start_backup(backupidstr, fast, NULL, NULL);
*************** pg_stop_backup(PG_FUNCTION_ARGS)
*** 82,91 ****
{
XLogRecPtr stoppoint;
! if (!superuser() && !has_rolreplication(GetUserId()))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! (errmsg("must be superuser or replication role to run a backup"))));
stoppoint = do_pg_stop_backup(NULL, true, NULL);
--- 84,94 ----
{
XLogRecPtr stoppoint;
! if (!has_replication_privilege(GetUserId())
! && !has_exclbackup_privilege(GetUserId()))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! errmsg("must be superuser, replication role or exclusive backup role to run a backup")));
stoppoint = do_pg_stop_backup(NULL, true, NULL);
*************** pg_switch_xlog(PG_FUNCTION_ARGS)
*** 100,109 ****
{
XLogRecPtr switchpoint;
! if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! (errmsg("must be superuser to switch transaction log files"))));
if (RecoveryInProgress())
ereport(ERROR,
--- 103,112 ----
{
XLogRecPtr switchpoint;
! if (!has_exclbackup_privilege(GetUserId()))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! errmsg("must be superuser or exclusive backup role to switch transaction log files")));
if (RecoveryInProgress())
ereport(ERROR,
*************** pg_create_restore_point(PG_FUNCTION_ARGS
*** 129,138 ****
char *restore_name_str;
XLogRecPtr restorepoint;
! if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! (errmsg("must be superuser to create a restore point"))));
if (RecoveryInProgress())
ereport(ERROR,
--- 132,141 ----
char *restore_name_str;
XLogRecPtr restorepoint;
! if (!has_exclbackup_privilege(GetUserId()))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! (errmsg("must be superuser or exclusive backup role to create a restore point"))));
if (RecoveryInProgress())
ereport(ERROR,
*************** pg_xlogfile_name(PG_FUNCTION_ARGS)
*** 338,347 ****
Datum
pg_xlog_replay_pause(PG_FUNCTION_ARGS)
{
! if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! (errmsg("must be superuser to control recovery"))));
if (!RecoveryInProgress())
ereport(ERROR,
--- 341,350 ----
Datum
pg_xlog_replay_pause(PG_FUNCTION_ARGS)
{
! if (!has_xlog_replay_privilege(GetUserId()))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! (errmsg("must be superuser or xlog replay role to control recovery"))));
if (!RecoveryInProgress())
ereport(ERROR,
*************** pg_xlog_replay_pause(PG_FUNCTION_ARGS)
*** 360,369 ****
Datum
pg_xlog_replay_resume(PG_FUNCTION_ARGS)
{
! if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! (errmsg("must be superuser to control recovery"))));
if (!RecoveryInProgress())
ereport(ERROR,
--- 363,372 ----
Datum
pg_xlog_replay_resume(PG_FUNCTION_ARGS)
{
! if (!has_xlog_replay_privilege(GetUserId()))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! (errmsg("must be superuser or xlog replay role to control recovery"))));
if (!RecoveryInProgress())
ereport(ERROR,
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
new file mode 100644
index 1e3888e..9ed5158
*** a/src/backend/catalog/aclchk.c
--- b/src/backend/catalog/aclchk.c
*************** has_createrole_privilege(Oid roleid)
*** 5080,5085 ****
--- 5080,5110 ----
return result;
}
+ /*
+ * Check whether specified role has REPLICATION privilege (or is a superuser)
+ */
+ bool
+ has_replication_privilege(Oid roleid)
+ {
+ bool result = false;
+ HeapTuple utup;
+
+ /* Superusers bypass all permission checking. */
+ if (superuser_arg(roleid))
+ return true;
+
+ utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
+ if (HeapTupleIsValid(utup))
+ {
+ result = ((Form_pg_authid) GETSTRUCT(utup))->rolreplication;
+ ReleaseSysCache(utup);
+ }
+ return result;
+ }
+
+ /*
+ * Check whether specified role has BYPASSRLS privilege (or is a superuser)
+ */
bool
has_bypassrls_privilege(Oid roleid)
{
*************** has_bypassrls_privilege(Oid roleid)
*** 5097,5102 ****
--- 5122,5239 ----
ReleaseSysCache(utup);
}
return result;
+ }
+
+ /*
+ * Check whether specified role has BACKUP privilege (or is a superuser)
+ */
+ bool
+ has_exclbackup_privilege(Oid roleid)
+ {
+ bool result = false;
+ HeapTuple utup;
+
+ /* Superusers bypass all permission checking. */
+ if (superuser_arg(roleid))
+ return true;
+
+ utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
+ if (HeapTupleIsValid(utup))
+ {
+ result = ((Form_pg_authid) GETSTRUCT(utup))->rolexclbackup;
+ ReleaseSysCache(utup);
+ }
+
+ return result;
+ }
+
+ /*
+ * Check whether specified role has XLOGREPLAY privilege (or is a superuser)
+ */
+ bool
+ has_xlog_replay_privilege(Oid roleid)
+ {
+ bool result = false;
+ HeapTuple utup;
+
+ /* Superusers bypass all permission checking. */
+ if (superuser_arg(roleid))
+ return true;
+
+ utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
+ if (HeapTupleIsValid(utup))
+ {
+ result = ((Form_pg_authid) GETSTRUCT(utup))->rolxlogreplay;
+ ReleaseSysCache(utup);
+ }
+
+ return result;
+ }
+
+ /*
+ * Check whether specified role has LOGFILE privilege (or is a superuser)
+ */
+ bool
+ has_logfile_privilege(Oid roleid)
+ {
+ bool result = false;
+ HeapTuple utup;
+
+ /* Superusers bypass all permission checking. */
+ if (superuser_arg(roleid))
+ return true;
+
+ utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
+ if (HeapTupleIsValid(utup))
+ {
+ result = ((Form_pg_authid) GETSTRUCT(utup))->rollogfile;
+ ReleaseSysCache(utup);
+ }
+ return result;
+ }
+
+ /*
+ * Check whether specified role has MONITOR privilege (or is a superuser)
+ */
+ bool
+ has_monitor_privilege(Oid roleid)
+ {
+ bool result = false;
+ HeapTuple utup;
+
+ /* Superusers bypass all permission checking. */
+ if (superuser_arg(roleid))
+ return true;
+
+ utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
+ if (HeapTupleIsValid(utup))
+ {
+ result = ((Form_pg_authid) GETSTRUCT(utup))->rolmonitor;
+ ReleaseSysCache(utup);
+ }
+ return result;
+ }
+
+ /*
+ * Check whether specified role has SIGNAL privilege (or is a superuser)
+ */
+ bool
+ has_signal_privilege(Oid roleid)
+ {
+ bool result = false;
+ HeapTuple utup;
+
+ /* Superusers bypass all permission checking. */
+ if (superuser_arg(roleid))
+ return true;
+
+ utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
+ if (HeapTupleIsValid(utup))
+ {
+ result = ((Form_pg_authid) GETSTRUCT(utup))->rolsignal;
+ ReleaseSysCache(utup);
+ }
+ return result;
}
/*
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c
new file mode 100644
index 2210eed..e0eb5c3
*** a/src/backend/commands/user.c
--- b/src/backend/commands/user.c
*************** static void DelRoleMems(const char *role
*** 55,69 ****
List *memberNames, List *memberIds,
bool admin_opt);
-
- /* Check if current user has createrole privileges */
- static bool
- have_createrole_privilege(void)
- {
- return has_createrole_privilege(GetUserId());
- }
-
-
/*
* CREATE ROLE
*/
--- 55,60 ----
*************** CreateRole(CreateRoleStmt *stmt)
*** 88,93 ****
--- 79,89 ----
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? */
+ bool exclbackup = false;
+ bool xlogreplay = false;
+ bool logfile = false;
+ bool monitor = false;
+ bool signal = false;
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 */
*************** CreateRole(CreateRoleStmt *stmt)
*** 108,113 ****
--- 104,114 ----
DefElem *dadminmembers = NULL;
DefElem *dvalidUntil = NULL;
DefElem *dbypassRLS = NULL;
+ DefElem *dexclbackup = NULL;
+ DefElem *dxlogreplay = NULL;
+ DefElem *dlogfile = NULL;
+ DefElem *dmonitor = NULL;
+ DefElem *dsignal = NULL;
/* The defaults can vary depending on the original statement type */
switch (stmt->stmt_type)
*************** CreateRole(CreateRoleStmt *stmt)
*** 242,247 ****
--- 243,288 ----
errmsg("conflicting or redundant options")));
dbypassRLS = defel;
}
+ else if (strcmp(defel->defname, "exclbackup") == 0)
+ {
+ if (dexclbackup)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("conflicting or redundant options")));
+ dexclbackup = defel;
+ }
+ else if (strcmp(defel->defname, "xlogreplay") == 0)
+ {
+ if (dxlogreplay)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("conflicting or redundant options")));
+ dxlogreplay = defel;
+ }
+ else if (strcmp(defel->defname, "logfile") == 0)
+ {
+ if (dlogfile)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("conflicting or redundant options")));
+ dlogfile = defel;
+ }
+ else if (strcmp(defel->defname, "monitor") == 0)
+ {
+ if (dmonitor)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("conflicting or redundant options")));
+ dmonitor = defel;
+ }
+ else if (strcmp(defel->defname, "signal") == 0)
+ {
+ if (dsignal)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("conflicting or redundant options")));
+ dsignal = defel;
+ }
else
elog(ERROR, "option \"%s\" not recognized",
defel->defname);
*************** CreateRole(CreateRoleStmt *stmt)
*** 279,284 ****
--- 320,335 ----
validUntil = strVal(dvalidUntil->arg);
if (dbypassRLS)
bypassrls = intVal(dbypassRLS->arg) != 0;
+ if (dexclbackup)
+ exclbackup = intVal(dexclbackup->arg) != 0;
+ if (dxlogreplay)
+ xlogreplay = intVal(dxlogreplay->arg) != 0;
+ if (dlogfile)
+ logfile = intVal(dlogfile->arg) != 0;
+ if (dmonitor)
+ monitor = intVal(dmonitor->arg) != 0;
+ if (dsignal)
+ signal = intVal(dsignal->arg) != 0;
/* Check some permissions first */
if (issuper)
*************** CreateRole(CreateRoleStmt *stmt)
*** 304,310 ****
}
else
{
! if (!have_createrole_privilege())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to create role")));
--- 355,361 ----
}
else
{
! if (!has_createrole_privilege(GetUserId()))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to create role")));
*************** CreateRole(CreateRoleStmt *stmt)
*** 395,400 ****
--- 446,456 ----
new_record_nulls[Anum_pg_authid_rolvaliduntil - 1] = validUntil_null;
new_record[Anum_pg_authid_rolbypassrls - 1] = BoolGetDatum(bypassrls);
+ new_record[Anum_pg_authid_rolexclbackup - 1] = BoolGetDatum(exclbackup);
+ new_record[Anum_pg_authid_rolxlogreplay - 1] = BoolGetDatum(xlogreplay);
+ new_record[Anum_pg_authid_rollogfile - 1] = BoolGetDatum(logfile);
+ new_record[Anum_pg_authid_rolmonitor - 1] = BoolGetDatum(monitor);
+ new_record[Anum_pg_authid_rolsignal - 1] = BoolGetDatum(signal);
tuple = heap_form_tuple(pg_authid_dsc, new_record, new_record_nulls);
*************** AlterRole(AlterRoleStmt *stmt)
*** 496,501 ****
--- 552,562 ----
Datum validUntil_datum; /* same, as timestamptz Datum */
bool validUntil_null;
bool bypassrls = -1;
+ bool exclbackup = -1;
+ bool xlogreplay = -1;
+ bool logfile = -1;
+ bool monitor = -1;
+ bool signal = -1;
DefElem *dpassword = NULL;
DefElem *dissuper = NULL;
DefElem *dinherit = NULL;
*************** AlterRole(AlterRoleStmt *stmt)
*** 507,512 ****
--- 568,578 ----
DefElem *drolemembers = NULL;
DefElem *dvalidUntil = NULL;
DefElem *dbypassRLS = NULL;
+ DefElem *dexclbackup = NULL;
+ DefElem *dxlogreplay = NULL;
+ DefElem *dlogfile = NULL;
+ DefElem *dmonitor = NULL;
+ DefElem *dsignal = NULL;
Oid roleid;
/* Extract options from the statement node tree */
*************** AlterRole(AlterRoleStmt *stmt)
*** 609,614 ****
--- 675,720 ----
errmsg("conflicting or redundant options")));
dbypassRLS = defel;
}
+ else if (strcmp(defel->defname, "exclbackup") == 0)
+ {
+ if (dexclbackup)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("conflicting or redundant options")));
+ dexclbackup = defel;
+ }
+ else if (strcmp(defel->defname, "xlogreplay") == 0)
+ {
+ if (dxlogreplay)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("conflicting or redundant options")));
+ dxlogreplay = defel;
+ }
+ else if (strcmp(defel->defname, "logfile") == 0)
+ {
+ if (dlogfile)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("conflicting or redundant options")));
+ dlogfile = defel;
+ }
+ else if (strcmp(defel->defname, "monitor") == 0)
+ {
+ if (dmonitor)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("conflicting or redundant options")));
+ dmonitor = defel;
+ }
+ else if (strcmp(defel->defname, "signal") == 0)
+ {
+ if (dsignal)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("conflicting or redundant options")));
+ dsignal = defel;
+ }
else
elog(ERROR, "option \"%s\" not recognized",
defel->defname);
*************** AlterRole(AlterRoleStmt *stmt)
*** 642,647 ****
--- 748,763 ----
validUntil = strVal(dvalidUntil->arg);
if (dbypassRLS)
bypassrls = intVal(dbypassRLS->arg);
+ if (dexclbackup)
+ exclbackup = intVal(dexclbackup->arg);
+ if (dxlogreplay)
+ xlogreplay = intVal(dxlogreplay->arg);
+ if (dlogfile)
+ logfile = intVal(dlogfile->arg);
+ if (dmonitor)
+ monitor = intVal(dmonitor->arg);
+ if (dsignal)
+ signal = intVal(dsignal->arg);
/*
* Scan the pg_authid relation to be certain the user exists.
*************** AlterRole(AlterRoleStmt *stmt)
*** 682,694 ****
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser to change bypassrls attribute")));
}
! else if (!have_createrole_privilege())
{
if (!(inherit < 0 &&
createrole < 0 &&
createdb < 0 &&
canlogin < 0 &&
isreplication < 0 &&
!dconnlimit &&
!rolemembers &&
!validUntil &&
--- 798,815 ----
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser to change bypassrls attribute")));
}
! else if (!has_createrole_privilege(GetUserId()))
{
if (!(inherit < 0 &&
createrole < 0 &&
createdb < 0 &&
canlogin < 0 &&
isreplication < 0 &&
+ exclbackup < 0 &&
+ xlogreplay < 0 &&
+ logfile < 0 &&
+ monitor < 0 &&
+ signal < 0 &&
!dconnlimit &&
!rolemembers &&
!validUntil &&
*************** AlterRole(AlterRoleStmt *stmt)
*** 821,826 ****
--- 942,977 ----
new_record_repl[Anum_pg_authid_rolbypassrls - 1] = true;
}
+ if (exclbackup >= 0)
+ {
+ new_record[Anum_pg_authid_rolexclbackup - 1] = BoolGetDatum(exclbackup > 0);
+ new_record_repl[Anum_pg_authid_rolexclbackup - 1] = true;
+ }
+
+ if (xlogreplay >= 0)
+ {
+ new_record[Anum_pg_authid_rolxlogreplay - 1] = BoolGetDatum(xlogreplay > 0);
+ new_record_repl[Anum_pg_authid_rolxlogreplay - 1] = true;
+ }
+
+ if (logfile >= 0)
+ {
+ new_record[Anum_pg_authid_rollogfile - 1] = BoolGetDatum(logfile > 0);
+ new_record_repl[Anum_pg_authid_rollogfile - 1] = true;
+ }
+
+ if (monitor >= 0)
+ {
+ new_record[Anum_pg_authid_rolmonitor - 1] = BoolGetDatum(monitor > 0);
+ new_record_repl[Anum_pg_authid_rolmonitor - 1] = true;
+ }
+
+ if (signal >= 0)
+ {
+ new_record[Anum_pg_authid_rolsignal - 1] = BoolGetDatum(signal > 0);
+ new_record_repl[Anum_pg_authid_rolsignal - 1] = true;
+ }
+
new_tuple = heap_modify_tuple(tuple, pg_authid_dsc, new_record,
new_record_nulls, new_record_repl);
simple_heap_update(pg_authid_rel, &tuple->t_self, new_tuple);
*************** AlterRoleSet(AlterRoleSetStmt *stmt)
*** 898,904 ****
}
else
{
! if (!have_createrole_privilege() &&
HeapTupleGetOid(roletuple) != GetUserId())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
--- 1049,1055 ----
}
else
{
! if (!has_createrole_privilege(GetUserId()) &&
HeapTupleGetOid(roletuple) != GetUserId())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
*************** DropRole(DropRoleStmt *stmt)
*** 951,957 ****
pg_auth_members_rel;
ListCell *item;
! if (!have_createrole_privilege())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to drop role")));
--- 1102,1108 ----
pg_auth_members_rel;
ListCell *item;
! if (!has_createrole_privilege(GetUserId()))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to drop role")));
*************** RenameRole(const char *oldname, const ch
*** 1182,1188 ****
}
else
{
! if (!have_createrole_privilege())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to rename role")));
--- 1333,1339 ----
}
else
{
! if (!has_createrole_privilege(GetUserId()))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to rename role")));
*************** AddRoleMems(const char *rolename, Oid ro
*** 1409,1415 ****
}
else
{
! if (!have_createrole_privilege() &&
!is_admin_of_role(grantorId, roleid))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
--- 1560,1566 ----
}
else
{
! if (!has_createrole_privilege(GetUserId()) &&
!is_admin_of_role(grantorId, roleid))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
*************** DelRoleMems(const char *rolename, Oid ro
*** 1555,1561 ****
}
else
{
! if (!have_createrole_privilege() &&
!is_admin_of_role(GetUserId(), roleid))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
--- 1706,1712 ----
}
else
{
! if (!has_createrole_privilege(GetUserId()) &&
!is_admin_of_role(GetUserId(), roleid))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
new file mode 100644
index 36dac29..5374437
*** a/src/backend/parser/gram.y
--- b/src/backend/parser/gram.y
*************** AlterOptRoleElem:
*** 977,982 ****
--- 977,1002 ----
*/
$$ = makeDefElem("inherit", (Node *)makeInteger(FALSE));
}
+ else if (strcmp($1, "exclusivebackup") == 0)
+ $$ = makeDefElem("exclbackup", (Node *)makeInteger(TRUE));
+ else if (strcmp($1, "noexclusivebackup") == 0)
+ $$ = makeDefElem("exclbackup", (Node *)makeInteger(FALSE));
+ else if (strcmp($1, "xlogreplay") == 0)
+ $$ = makeDefElem("xlogreplay", (Node *)makeInteger(TRUE));
+ else if (strcmp($1, "noxlogreplay") == 0)
+ $$ = makeDefElem("xlogreplay", (Node *)makeInteger(FALSE));
+ else if (strcmp($1, "logfile") == 0)
+ $$ = makeDefElem("logfile", (Node *)makeInteger(TRUE));
+ else if (strcmp($1, "nologfile") == 0)
+ $$ = makeDefElem("logfile", (Node *)makeInteger(FALSE));
+ else if (strcmp($1, "monitor") == 0)
+ $$ = makeDefElem("monitor", (Node *)makeInteger(TRUE));
+ else if (strcmp($1, "nomonitor") == 0)
+ $$ = makeDefElem("monitor", (Node *)makeInteger(FALSE));
+ else if (strcmp($1, "signal") == 0)
+ $$ = makeDefElem("signal", (Node *)makeInteger(TRUE));
+ else if (strcmp($1, "nosignal") == 0)
+ $$ = makeDefElem("signal", (Node *)makeInteger(FALSE));
else
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
diff --git a/src/backend/replication/logical/logicalfuncs.c b/src/backend/replication/logical/logicalfuncs.c
new file mode 100644
index 3be5263..b7e7947
*** a/src/backend/replication/logical/logicalfuncs.c
--- b/src/backend/replication/logical/logicalfuncs.c
***************
*** 29,34 ****
--- 29,35 ----
#include "mb/pg_wchar.h"
+ #include "utils/acl.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/inval.h"
*************** XLogRead(char *buf, TimeLineID tli, XLog
*** 202,216 ****
}
}
- static void
- check_permissions(void)
- {
- if (!superuser() && !has_rolreplication(GetUserId()))
- ereport(ERROR,
- (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- (errmsg("must be superuser or replication role to use replication slots"))));
- }
-
/*
* read_page callback for logical decoding contexts.
*
--- 203,208 ----
*************** pg_logical_slot_get_changes_guts(Functio
*** 324,330 ****
if (get_call_result_type(fcinfo, NULL, &p->tupdesc) != TYPEFUNC_COMPOSITE)
elog(ERROR, "return type must be a row type");
! check_permissions();
CheckLogicalDecodingRequirements();
--- 316,325 ----
if (get_call_result_type(fcinfo, NULL, &p->tupdesc) != TYPEFUNC_COMPOSITE)
elog(ERROR, "return type must be a row type");
! if (!has_replication_privilege(GetUserId()))
! ereport(ERROR,
! (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! errmsg("must be superuser or replication role to use replication slots")));
CheckLogicalDecodingRequirements();
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
new file mode 100644
index f31925d..35e1c11
*** a/src/backend/replication/slotfuncs.c
--- b/src/backend/replication/slotfuncs.c
***************
*** 20,37 ****
#include "replication/slot.h"
#include "replication/logical.h"
#include "replication/logicalfuncs.h"
#include "utils/builtins.h"
#include "utils/pg_lsn.h"
- static void
- check_permissions(void)
- {
- if (!superuser() && !has_rolreplication(GetUserId()))
- ereport(ERROR,
- (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- (errmsg("must be superuser or replication role to use replication slots"))));
- }
-
/*
* SQL function for creating a new physical (streaming replication)
* replication slot.
--- 20,29 ----
#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"
/*
* SQL function for creating a new physical (streaming replication)
* replication slot.
*************** pg_create_physical_replication_slot(PG_F
*** 51,57 ****
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
elog(ERROR, "return type must be a row type");
! check_permissions();
CheckSlotRequirements();
--- 43,52 ----
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
elog(ERROR, "return type must be a row type");
! if (!has_replication_privilege(GetUserId()))
! ereport(ERROR,
! (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! errmsg("must be superuser or replication role to use replication slots")));
CheckSlotRequirements();
*************** pg_create_logical_replication_slot(PG_FU
*** 94,100 ****
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
elog(ERROR, "return type must be a row type");
! check_permissions();
CheckLogicalDecodingRequirements();
--- 89,98 ----
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
elog(ERROR, "return type must be a row type");
! if (!has_replication_privilege(GetUserId()))
! ereport(ERROR,
! (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! errmsg("must be superuser or replication role to use replication slots")));
CheckLogicalDecodingRequirements();
*************** pg_drop_replication_slot(PG_FUNCTION_ARG
*** 143,149 ****
{
Name name = PG_GETARG_NAME(0);
! check_permissions();
CheckSlotRequirements();
--- 141,150 ----
{
Name name = PG_GETARG_NAME(0);
! if (!has_replication_privilege(GetUserId()))
! ereport(ERROR,
! (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! errmsg("must be superuser or replication role to use replication slots")));
CheckSlotRequirements();
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
new file mode 100644
index 05d2339..1ace6c0
*** a/src/backend/replication/walsender.c
--- b/src/backend/replication/walsender.c
***************
*** 71,76 ****
--- 71,77 ----
#include "storage/proc.h"
#include "storage/procarray.h"
#include "tcop/tcopprot.h"
+ #include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/guc.h"
#include "utils/memutils.h"
*************** pg_stat_get_wal_senders(PG_FUNCTION_ARGS
*** 2805,2815 ****
memset(nulls, 0, sizeof(nulls));
values[0] = Int32GetDatum(walsnd->pid);
! if (!superuser())
{
/*
! * Only superusers can see details. Other users only get the pid
! * value to know it's a walsender, but no details.
*/
MemSet(&nulls[1], true, PG_STAT_GET_WAL_SENDERS_COLS - 1);
}
--- 2806,2817 ----
memset(nulls, 0, sizeof(nulls));
values[0] = Int32GetDatum(walsnd->pid);
! if (!has_monitor_privilege(GetUserId()))
{
/*
! * Only users with the MONITOR attribute or superuser privileges can
! * see details. Other users only get the pid value to know it's a
! * walsender, but no details.
*/
MemSet(&nulls[1], true, PG_STAT_GET_WAL_SENDERS_COLS - 1);
}
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
new file mode 100644
index 29f7c3b..0c1c31a
*** a/src/backend/utils/adt/misc.c
--- b/src/backend/utils/adt/misc.c
***************
*** 37,42 ****
--- 37,43 ----
#include "utils/lsyscache.h"
#include "utils/ruleutils.h"
#include "tcop/tcopprot.h"
+ #include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/timestamp.h"
*************** pg_signal_backend(int pid, int sig)
*** 113,119 ****
return SIGNAL_BACKEND_ERROR;
}
! if (!(superuser() || proc->roleId == GetUserId()))
return SIGNAL_BACKEND_NOPERMISSION;
/*
--- 114,132 ----
return SIGNAL_BACKEND_ERROR;
}
! /*
! * If the current user is not a superuser, then they aren't allowed to
! * signal backends which are owned by a superuser.
! */
! if (!superuser() && superuser_arg(proc->roleId))
! return SIGNAL_BACKEND_NOPERMISSION;
!
! /*
! * If the current user is not a member of the role owning the process and
! * does not have the SIGNAL permission, then permission is denied.
! */
! if (!has_privs_of_role(GetUserId(), proc->roleId)
! && !has_signal_privilege(GetUserId()))
return SIGNAL_BACKEND_NOPERMISSION;
/*
*************** pg_reload_conf(PG_FUNCTION_ARGS)
*** 202,211 ****
Datum
pg_rotate_logfile(PG_FUNCTION_ARGS)
{
! if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! (errmsg("must be superuser to rotate log files"))));
if (!Logging_collector)
{
--- 215,224 ----
Datum
pg_rotate_logfile(PG_FUNCTION_ARGS)
{
! if (!has_logfile_privilege(GetUserId()))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! errmsg("must be superuser or have logfile permission to rotate log files")));
if (!Logging_collector)
{
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
new file mode 100644
index 389ea49..2107490
*** a/src/backend/utils/adt/pgstatfuncs.c
--- b/src/backend/utils/adt/pgstatfuncs.c
***************
*** 20,25 ****
--- 20,26 ----
#include "libpq/ip.h"
#include "miscadmin.h"
#include "pgstat.h"
+ #include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/inet.h"
#include "utils/timestamp.h"
*************** pg_stat_get_activity(PG_FUNCTION_ARGS)
*** 625,630 ****
--- 626,632 ----
HeapTuple tuple;
LocalPgBackendStatus *local_beentry;
PgBackendStatus *beentry;
+ Oid current_user_id;
MemSet(values, 0, sizeof(values));
MemSet(nulls, 0, sizeof(nulls));
*************** pg_stat_get_activity(PG_FUNCTION_ARGS)
*** 674,681 ****
else
nulls[15] = true;
! /* Values only available to same user or superuser */
! if (superuser() || beentry->st_userid == GetUserId())
{
SockAddr zero_clientaddr;
--- 676,689 ----
else
nulls[15] = true;
! /*
! * Values only available to roles which are members of this role,
! * or which have the MONITOR privilege.
! */
! current_user_id = GetUserId();
!
! if (has_monitor_privilege(current_user_id)
! || has_privs_of_role(current_user_id, beentry->st_userid))
{
SockAddr zero_clientaddr;
*************** pg_stat_get_backend_activity(PG_FUNCTION
*** 874,883 ****
int32 beid = PG_GETARG_INT32(0);
PgBackendStatus *beentry;
const char *activity;
if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
activity = "<backend information not available>";
! else if (!superuser() && beentry->st_userid != GetUserId())
activity = "<insufficient privilege>";
else if (*(beentry->st_activity) == '\0')
activity = "<command string not enabled>";
--- 882,895 ----
int32 beid = PG_GETARG_INT32(0);
PgBackendStatus *beentry;
const char *activity;
+ Oid current_user_id;
+
+ current_user_id = GetUserId();
if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
activity = "<backend information not available>";
! else if (!has_monitor_privilege(current_user_id)
! && !has_privs_of_role(current_user_id, beentry->st_userid))
activity = "<insufficient privilege>";
else if (*(beentry->st_activity) == '\0')
activity = "<command string not enabled>";
*************** pg_stat_get_backend_waiting(PG_FUNCTION_
*** 894,904 ****
int32 beid = PG_GETARG_INT32(0);
bool result;
PgBackendStatus *beentry;
if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
PG_RETURN_NULL();
! if (!superuser() && beentry->st_userid != GetUserId())
PG_RETURN_NULL();
result = beentry->st_waiting;
--- 906,920 ----
int32 beid = PG_GETARG_INT32(0);
bool result;
PgBackendStatus *beentry;
+ Oid current_user_id;
if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
PG_RETURN_NULL();
! current_user_id = GetUserId();
!
! if (!has_monitor_privilege(current_user_id)
! && !has_privs_of_role(current_user_id, beentry->st_userid))
PG_RETURN_NULL();
result = beentry->st_waiting;
*************** pg_stat_get_backend_activity_start(PG_FU
*** 913,923 ****
int32 beid = PG_GETARG_INT32(0);
TimestampTz result;
PgBackendStatus *beentry;
if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
PG_RETURN_NULL();
! if (!superuser() && beentry->st_userid != GetUserId())
PG_RETURN_NULL();
result = beentry->st_activity_start_timestamp;
--- 929,943 ----
int32 beid = PG_GETARG_INT32(0);
TimestampTz result;
PgBackendStatus *beentry;
+ Oid current_user_id;
if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
PG_RETURN_NULL();
! current_user_id = GetUserId();
!
! if (!has_monitor_privilege(current_user_id)
! && !has_privs_of_role(current_user_id, beentry->st_userid))
PG_RETURN_NULL();
result = beentry->st_activity_start_timestamp;
*************** pg_stat_get_backend_xact_start(PG_FUNCTI
*** 939,949 ****
int32 beid = PG_GETARG_INT32(0);
TimestampTz result;
PgBackendStatus *beentry;
if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
PG_RETURN_NULL();
! if (!superuser() && beentry->st_userid != GetUserId())
PG_RETURN_NULL();
result = beentry->st_xact_start_timestamp;
--- 959,973 ----
int32 beid = PG_GETARG_INT32(0);
TimestampTz result;
PgBackendStatus *beentry;
+ Oid current_user_id;
if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
PG_RETURN_NULL();
! current_user_id = GetUserId();
!
! if (!has_monitor_privilege(current_user_id)
! && !has_privs_of_role(current_user_id, beentry->st_userid))
PG_RETURN_NULL();
result = beentry->st_xact_start_timestamp;
*************** pg_stat_get_backend_start(PG_FUNCTION_AR
*** 961,971 ****
int32 beid = PG_GETARG_INT32(0);
TimestampTz result;
PgBackendStatus *beentry;
if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
PG_RETURN_NULL();
! if (!superuser() && beentry->st_userid != GetUserId())
PG_RETURN_NULL();
result = beentry->st_proc_start_timestamp;
--- 985,999 ----
int32 beid = PG_GETARG_INT32(0);
TimestampTz result;
PgBackendStatus *beentry;
+ Oid current_user_id;
if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
PG_RETURN_NULL();
! current_user_id = GetUserId();
!
! if (!has_monitor_privilege(current_user_id)
! && !has_privs_of_role(current_user_id, beentry->st_userid))
PG_RETURN_NULL();
result = beentry->st_proc_start_timestamp;
*************** pg_stat_get_backend_client_addr(PG_FUNCT
*** 985,995 ****
SockAddr zero_clientaddr;
char remote_host[NI_MAXHOST];
int ret;
if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
PG_RETURN_NULL();
! if (!superuser() && beentry->st_userid != GetUserId())
PG_RETURN_NULL();
/* A zeroed client addr means we don't know */
--- 1013,1027 ----
SockAddr zero_clientaddr;
char remote_host[NI_MAXHOST];
int ret;
+ Oid current_user_id;
if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
PG_RETURN_NULL();
! current_user_id = GetUserId();
!
! if (!has_monitor_privilege(current_user_id)
! && !has_privs_of_role(current_user_id, beentry->st_userid))
PG_RETURN_NULL();
/* A zeroed client addr means we don't know */
*************** pg_stat_get_backend_client_port(PG_FUNCT
*** 1032,1042 ****
SockAddr zero_clientaddr;
char remote_port[NI_MAXSERV];
int ret;
if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
PG_RETURN_NULL();
! if (!superuser() && beentry->st_userid != GetUserId())
PG_RETURN_NULL();
/* A zeroed client addr means we don't know */
--- 1064,1082 ----
SockAddr zero_clientaddr;
char remote_port[NI_MAXSERV];
int ret;
+ Oid current_user_id;
if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
PG_RETURN_NULL();
! /*
! * User must have MONITOR attribute, be superuser or be the same
! * backend user.
! */
! current_user_id = GetUserId();
!
! if (!has_monitor_privilege(current_user_id)
! && !has_privs_of_role(current_user_id, beentry->st_userid))
PG_RETURN_NULL();
/* A zeroed client addr means we don't know */
diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c
new file mode 100644
index 4646e09..4bac170
*** a/src/backend/utils/init/miscinit.c
--- b/src/backend/utils/init/miscinit.c
*************** SetUserIdAndContext(Oid userid, bool sec
*** 430,454 ****
SecurityRestrictionContext &= ~SECURITY_LOCAL_USERID_CHANGE;
}
-
- /*
- * 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
*/
--- 430,435 ----
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c
new file mode 100644
index 1f5cf06..df9f0b4
*** a/src/backend/utils/init/postinit.c
--- b/src/backend/utils/init/postinit.c
*************** InitPostgres(const char *in_dbname, Oid
*** 762,768 ****
{
Assert(!bootstrap);
! if (!superuser() && !has_rolreplication(GetUserId()))
ereport(FATAL,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser or replication role to start walsender")));
--- 762,768 ----
{
Assert(!bootstrap);
! if (!has_replication_privilege(GetUserId()))
ereport(FATAL,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser or replication role to start walsender")));
diff --git a/src/include/catalog/pg_authid.h b/src/include/catalog/pg_authid.h
new file mode 100644
index e01e6aa..dd1ed37
*** a/src/include/catalog/pg_authid.h
--- b/src/include/catalog/pg_authid.h
*************** CATALOG(pg_authid,1260) BKI_SHARED_RELAT
*** 53,58 ****
--- 53,63 ----
bool rolcanlogin; /* allowed to log in as session user? */
bool rolreplication; /* role used for streaming replication */
bool rolbypassrls; /* allowed to bypass row level security? */
+ bool rolexclbackup; /* allowed to peform backup operations? */
+ bool rolxlogreplay; /* allowed to control xlog replay */
+ bool rollogfile; /* allowed to rotate log files? */
+ bool rolmonitor; /* allowed to view pg_stat_* details? */
+ bool rolsignal; /* allowed to signal backed processes? */
int32 rolconnlimit; /* max connections allowed (-1=no limit) */
/* remaining fields may be null; use heap_getattr to read them! */
*************** typedef FormData_pg_authid *Form_pg_auth
*** 74,80 ****
* compiler constants for pg_authid
* ----------------
*/
! #define Natts_pg_authid 12
#define Anum_pg_authid_rolname 1
#define Anum_pg_authid_rolsuper 2
#define Anum_pg_authid_rolinherit 3
--- 79,85 ----
* compiler constants for pg_authid
* ----------------
*/
! #define Natts_pg_authid 17
#define Anum_pg_authid_rolname 1
#define Anum_pg_authid_rolsuper 2
#define Anum_pg_authid_rolinherit 3
*************** typedef FormData_pg_authid *Form_pg_auth
*** 84,92 ****
#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
--- 89,102 ----
#define Anum_pg_authid_rolcanlogin 7
#define Anum_pg_authid_rolreplication 8
#define Anum_pg_authid_rolbypassrls 9
! #define Anum_pg_authid_rolexclbackup 10
! #define Anum_pg_authid_rolxlogreplay 11
! #define Anum_pg_authid_rollogfile 12
! #define Anum_pg_authid_rolmonitor 13
! #define Anum_pg_authid_rolsignal 14
! #define Anum_pg_authid_rolconnlimit 15
! #define Anum_pg_authid_rolpassword 16
! #define Anum_pg_authid_rolvaliduntil 17
/* ----------------
* initial contents of pg_authid
*************** typedef FormData_pg_authid *Form_pg_auth
*** 95,101 ****
* user choices.
* ----------------
*/
! DATA(insert OID = 10 ( "POSTGRES" t t t t t t t t -1 _null_ _null_));
#define BOOTSTRAP_SUPERUSERID 10
--- 105,111 ----
* user choices.
* ----------------
*/
! DATA(insert OID = 10 ( "POSTGRES" t t t t t t t t t t t t t -1 _null_ _null_));
#define BOOTSTRAP_SUPERUSERID 10
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
new file mode 100644
index 6e33a17..595564f
*** a/src/include/miscadmin.h
--- b/src/include/miscadmin.h
*************** extern void ValidatePgVersion(const char
*** 442,448 ****
extern void process_shared_preload_libraries(void);
extern void process_session_preload_libraries(void);
extern void pg_bindtextdomain(const char *domain);
- extern bool has_rolreplication(Oid roleid);
/* in access/transam/xlog.c */
extern bool BackupInProgress(void);
--- 442,447 ----
diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h
new file mode 100644
index ab0df6c..63c702b
*** a/src/include/utils/acl.h
--- b/src/include/utils/acl.h
*************** extern bool pg_event_trigger_ownercheck(
*** 328,332 ****
--- 328,338 ----
extern bool pg_extension_ownercheck(Oid ext_oid, Oid roleid);
extern bool has_createrole_privilege(Oid roleid);
extern bool has_bypassrls_privilege(Oid roleid);
+ extern bool has_replication_privilege(Oid roleid);
+ extern bool has_exclbackup_privilege(Oid roleid);
+ extern bool has_xlog_replay_privilege(Oid roleid);
+ extern bool has_logfile_privilege(Oid roleid);
+ extern bool has_monitor_privilege(Oid roleid);
+ extern bool has_signal_privilege(Oid roleid);
#endif /* ACL_H */
--
Sent via pgsql-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers