All, I have attached and updated patch for review.
Thanks, Adam -- Adam Brightwell - adam.brightw...@crunchydatasolutions.com 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 (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers