mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-02-23 19:39:53 +08:00
Allow granting SET and ALTER SYSTEM privileges on GUC parameters.
This patch allows "PGC_SUSET" parameters to be set by non-superusers if they have been explicitly granted the privilege to do so. The privilege to perform ALTER SYSTEM SET/RESET on a specific parameter can also be granted. Such privileges are cluster-wide, not per database. They are tracked in a new shared catalog, pg_parameter_acl. Granting and revoking these new privileges works as one would expect. One caveat is that PGC_USERSET GUCs are unaffected by the SET privilege --- one could wish that those were handled by a revocable grant to PUBLIC, but they are not, because we couldn't make it robust enough for GUCs defined by extensions. Mark Dilger, reviewed at various times by Andrew Dunstan, Robert Haas, Joshua Brindle, and myself Discussion: https://postgr.es/m/3D691E20-C1D5-4B80-8BA5-6BEB63AF3029@enterprisedb.com
This commit is contained in:
parent
2ef6f11b0c
commit
a0ffa885e4
@ -220,6 +220,11 @@
|
||||
<entry>access method operator families</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><link linkend="catalog-pg-parameter-acl"><structname>pg_parameter_acl</structname></link></entry>
|
||||
<entry>configuration parameters for which privileges have been granted</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><link linkend="catalog-pg-partitioned-table"><structname>pg_partitioned_table</structname></link></entry>
|
||||
<entry>information about partition key of tables</entry>
|
||||
@ -5450,6 +5455,74 @@ SCRAM-SHA-256$<replaceable><iteration count></replaceable>:<replaceable>&l
|
||||
</sect1>
|
||||
|
||||
|
||||
<sect1 id="catalog-pg-parameter-acl">
|
||||
<title><structname>pg_parameter_acl</structname></title>
|
||||
|
||||
<indexterm zone="catalog-pg-parameter-acl">
|
||||
<primary>pg_parameter_acl</primary>
|
||||
</indexterm>
|
||||
|
||||
<para>
|
||||
The catalog <structname>pg_parameter_acl</structname> records configuration
|
||||
parameters for which privileges have been granted to one or more roles.
|
||||
No entry is made for parameters that have default privileges.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Unlike most system catalogs, <structname>pg_parameter_acl</structname>
|
||||
is shared across all databases of a cluster: there is only one
|
||||
copy of <structname>pg_parameter_acl</structname> per cluster, not
|
||||
one per database.
|
||||
</para>
|
||||
|
||||
<table>
|
||||
<title><structname>pg_parameter_acl</structname> Columns</title>
|
||||
<tgroup cols="1">
|
||||
<thead>
|
||||
<row>
|
||||
<entry role="catalog_table_entry"><para role="column_definition">
|
||||
Column Type
|
||||
</para>
|
||||
<para>
|
||||
Description
|
||||
</para></entry>
|
||||
</row>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<row>
|
||||
<entry role="catalog_table_entry"><para role="column_definition">
|
||||
<structfield>oid</structfield> <type>oid</type>
|
||||
</para>
|
||||
<para>
|
||||
Row identifier
|
||||
</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry role="catalog_table_entry"><para role="column_definition">
|
||||
<structfield>parname</structfield> <type>text</type>
|
||||
</para>
|
||||
<para>
|
||||
The name of a configuration parameter for which privileges are granted
|
||||
</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry role="catalog_table_entry"><para role="column_definition">
|
||||
<structfield>paracl</structfield> <type>aclitem[]</type>
|
||||
</para>
|
||||
<para>
|
||||
Access privileges; see <xref linkend="ddl-priv"/> for details
|
||||
</para></entry>
|
||||
</row>
|
||||
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</sect1>
|
||||
|
||||
|
||||
<sect1 id="catalog-pg-partitioned-table">
|
||||
<title><structname>pg_partitioned_table</structname></title>
|
||||
|
||||
@ -12747,7 +12820,8 @@ SELECT * FROM pg_locks pl LEFT JOIN pg_prepared_xacts ppx
|
||||
<filename>postgresql.conf</filename> without restarting the server.
|
||||
They can also be set for a particular session in the connection request
|
||||
packet (for example, via <application>libpq</application>'s <literal>PGOPTIONS</literal>
|
||||
environment variable), but only if the connecting user is a superuser.
|
||||
environment variable), but only if the connecting user is a superuser
|
||||
or has been granted the appropriate <literal>SET</literal> privilege.
|
||||
However, these settings never change in a session after it is started.
|
||||
If you change them in <filename>postgresql.conf</filename>, send a
|
||||
<systemitem>SIGHUP</systemitem> signal to the postmaster to cause it to
|
||||
@ -12781,6 +12855,7 @@ SELECT * FROM pg_locks pl LEFT JOIN pg_prepared_xacts ppx
|
||||
<para>
|
||||
These settings can be set from <filename>postgresql.conf</filename>,
|
||||
or within a session via the <command>SET</command> command; but only superusers
|
||||
and users with the appropriate <literal>SET</literal> privilege
|
||||
can change them via <command>SET</command>. Changes in
|
||||
<filename>postgresql.conf</filename> will affect existing sessions
|
||||
only if no session-local value has been established with <command>SET</command>.
|
||||
|
@ -274,6 +274,9 @@ shared_buffers = 128MB
|
||||
The <link linkend="sql-set"><command>SET</command></link> command allows modification of the
|
||||
current value of those parameters that can be set locally to a
|
||||
session; it has no effect on other sessions.
|
||||
Many parameters can be set this way by any user, but some can
|
||||
only be set by superusers and users who have been
|
||||
granted <literal>SET</literal> privilege on that parameter.
|
||||
The corresponding SQL function is
|
||||
<function>set_config(setting_name, new_value, is_local)</function>
|
||||
(see <xref linkend="functions-admin-set"/>).
|
||||
@ -1976,7 +1979,8 @@ include_dir 'conf.d'
|
||||
The default setting is two megabytes (<literal>2MB</literal>), which
|
||||
is conservatively small and unlikely to risk crashes. However,
|
||||
it might be too small to allow execution of complex functions.
|
||||
Only superusers can change this setting.
|
||||
Only superusers and users with the appropriate <literal>SET</literal>
|
||||
privilege can change this setting.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
@ -2089,7 +2093,8 @@ include_dir 'conf.d'
|
||||
this limit will be canceled.
|
||||
If this value is specified without units, it is taken as kilobytes.
|
||||
<literal>-1</literal> (the default) means no limit.
|
||||
Only superusers can change this setting.
|
||||
Only superusers and users with the appropriate <literal>SET</literal>
|
||||
privilege can change this setting.
|
||||
</para>
|
||||
<para>
|
||||
This setting constrains the total space used at any instant by all
|
||||
@ -3166,7 +3171,8 @@ include_dir 'conf.d'
|
||||
<literal>zstd</literal> (if <productname>PostgreSQL</productname>
|
||||
was compiled with <option>--with-zstd</option>).
|
||||
The default value is <literal>off</literal>.
|
||||
Only superusers can change this setting.
|
||||
Only superusers and users with the appropriate <literal>SET</literal>
|
||||
privilege can change this setting.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
@ -3341,7 +3347,8 @@ include_dir 'conf.d'
|
||||
performed if <varname>fsync</varname> is disabled.
|
||||
If this value is specified without units, it is taken as microseconds.
|
||||
The default <varname>commit_delay</varname> is zero (no delay).
|
||||
Only superusers can change this setting.
|
||||
Only superusers and users with the appropriate <literal>SET</literal>
|
||||
privilege can change this setting.
|
||||
</para>
|
||||
<para>
|
||||
In <productname>PostgreSQL</productname> releases prior to 9.3,
|
||||
@ -6462,7 +6469,8 @@ local0.* /var/log/postgresql
|
||||
to the log. The default is <literal>WARNING</literal>. Note that
|
||||
<literal>LOG</literal> has a different rank here than in
|
||||
<xref linkend="guc-client-min-messages"/>.
|
||||
Only superusers can change this setting.
|
||||
Only superusers and users with the appropriate <literal>SET</literal>
|
||||
privilege can change this setting.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
@ -6492,7 +6500,8 @@ local0.* /var/log/postgresql
|
||||
causing errors, log messages, fatal errors, or panics will be logged.
|
||||
To effectively turn off logging of failing statements,
|
||||
set this parameter to <literal>PANIC</literal>.
|
||||
Only superusers can change this setting.
|
||||
Only superusers and users with the appropriate <literal>SET</literal>
|
||||
privilege can change this setting.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
@ -6514,7 +6523,9 @@ local0.* /var/log/postgresql
|
||||
If this value is specified without units, it is taken as milliseconds.
|
||||
Setting this to zero prints all statement durations.
|
||||
<literal>-1</literal> (the default) disables logging statement
|
||||
durations. Only superusers can change this setting.
|
||||
durations.
|
||||
Only superusers and users with the appropriate <literal>SET</literal>
|
||||
privilege can change this setting.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
@ -6566,7 +6577,9 @@ local0.* /var/log/postgresql
|
||||
If this value is specified without units, it is taken as milliseconds.
|
||||
Setting this to zero samples all statement durations.
|
||||
<literal>-1</literal> (the default) disables sampling statement
|
||||
durations. Only superusers can change this setting.
|
||||
durations.
|
||||
Only superusers and users with the appropriate <literal>SET</literal>
|
||||
privilege can change this setting.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
@ -6603,7 +6616,8 @@ local0.* /var/log/postgresql
|
||||
the same as setting
|
||||
<varname>log_min_duration_sample</varname> to
|
||||
<literal>-1</literal>.
|
||||
Only superusers can change this setting.
|
||||
Only superusers and users with the appropriate <literal>SET</literal>
|
||||
privilege can change this setting.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
@ -6627,7 +6641,8 @@ local0.* /var/log/postgresql
|
||||
The default is <literal>0</literal>, meaning not to log
|
||||
statements from any additional transactions. Setting this
|
||||
to <literal>1</literal> logs all statements of all transactions.
|
||||
Only superusers can change this setting.
|
||||
Only superusers and users with the appropriate <literal>SET</literal>
|
||||
privilege can change this setting.
|
||||
</para>
|
||||
<note>
|
||||
<para>
|
||||
@ -6892,7 +6907,8 @@ local0.* /var/log/postgresql
|
||||
Causes each attempted connection to the server to be logged,
|
||||
as well as successful completion of both client authentication (if
|
||||
necessary) and authorization.
|
||||
Only superusers can change this parameter at session start,
|
||||
Only superusers and users with the appropriate <literal>SET</literal>
|
||||
privilege can change this parameter at session start,
|
||||
and it cannot be changed at all within a session.
|
||||
The default is <literal>off</literal>.
|
||||
</para>
|
||||
@ -6919,7 +6935,8 @@ local0.* /var/log/postgresql
|
||||
Causes session terminations to be logged. The log output
|
||||
provides information similar to <varname>log_connections</varname>,
|
||||
plus the duration of the session.
|
||||
Only superusers can change this parameter at session start,
|
||||
Only superusers and users with the appropriate <literal>SET</literal>
|
||||
privilege can change this parameter at session start,
|
||||
and it cannot be changed at all within a session.
|
||||
The default is <literal>off</literal>.
|
||||
</para>
|
||||
@ -6937,7 +6954,8 @@ local0.* /var/log/postgresql
|
||||
<para>
|
||||
Causes the duration of every completed statement to be logged.
|
||||
The default is <literal>off</literal>.
|
||||
Only superusers can change this setting.
|
||||
Only superusers and users with the appropriate <literal>SET</literal>
|
||||
privilege can change this setting.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
@ -6978,7 +6996,8 @@ local0.* /var/log/postgresql
|
||||
<literal>VERBOSE</literal> output includes the <symbol>SQLSTATE</symbol> error
|
||||
code (see also <xref linkend="errcodes-appendix"/>) and the source code file name, function name,
|
||||
and line number that generated the error.
|
||||
Only superusers can change this setting.
|
||||
Only superusers and users with the appropriate <literal>SET</literal>
|
||||
privilege can change this setting.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
@ -7233,7 +7252,8 @@ log_line_prefix = '%m [%p] %q%u@%d/%a '
|
||||
longer than <xref linkend="guc-deadlock-timeout"/> to acquire a
|
||||
lock. This is useful in determining if lock waits are causing
|
||||
poor performance. The default is <literal>off</literal>.
|
||||
Only superusers can change this setting.
|
||||
Only superusers and users with the appropriate <literal>SET</literal>
|
||||
privilege can change this setting.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
@ -7274,7 +7294,8 @@ log_line_prefix = '%m [%p] %q%u@%d/%a '
|
||||
<literal>-1</literal> (the default) allows bind parameters to be
|
||||
logged in full.
|
||||
If this value is specified without units, it is taken as bytes.
|
||||
Only superusers can change this setting.
|
||||
Only superusers and users with the appropriate <literal>SET</literal>
|
||||
privilege can change this setting.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
@ -7341,8 +7362,9 @@ log_line_prefix = '%m [%p] %q%u@%d/%a '
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The default is <literal>none</literal>. Only superusers can change this
|
||||
setting.
|
||||
The default is <literal>none</literal>.
|
||||
Only superusers and users with the appropriate <literal>SET</literal>
|
||||
privilege can change this setting.
|
||||
</para>
|
||||
|
||||
<note>
|
||||
@ -7371,7 +7393,8 @@ log_line_prefix = '%m [%p] %q%u@%d/%a '
|
||||
Causes each replication command to be logged in the server log.
|
||||
See <xref linkend="protocol-replication"/> for more information about
|
||||
replication command. The default value is <literal>off</literal>.
|
||||
Only superusers can change this setting.
|
||||
Only superusers and users with the appropriate <literal>SET</literal>
|
||||
privilege can change this setting.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
@ -7394,7 +7417,8 @@ log_line_prefix = '%m [%p] %q%u@%d/%a '
|
||||
the specified amount of data.
|
||||
If this value is specified without units, it is taken as kilobytes.
|
||||
The default setting is -1, which disables such logging.
|
||||
Only superusers can change this setting.
|
||||
Only superusers and users with the appropriate <literal>SET</literal>
|
||||
privilege can change this setting.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
@ -7784,7 +7808,8 @@ COPY postgres_log FROM '/full/path/to/logfile.csv' WITH csv;
|
||||
This setting defaults to <literal>on</literal> on most platforms, but it
|
||||
defaults to <literal>off</literal> on Windows due to that platform's larger
|
||||
overhead for updating the process title.
|
||||
Only superusers can change this setting.
|
||||
Only superusers and users with the appropriate <literal>SET</literal>
|
||||
privilege can change this setting.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
@ -7823,7 +7848,8 @@ COPY postgres_log FROM '/full/path/to/logfile.csv' WITH csv;
|
||||
visible to all users, only to superusers and the user owning
|
||||
the session being reported on, so it should not represent a
|
||||
security risk.
|
||||
Only superusers can change this setting.
|
||||
Only superusers and users with the appropriate <literal>SET</literal>
|
||||
privilege can change this setting.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
@ -7857,7 +7883,8 @@ COPY postgres_log FROM '/full/path/to/logfile.csv' WITH csv;
|
||||
Enables collection of statistics on database activity.
|
||||
This parameter is on by default, because the autovacuum
|
||||
daemon needs the collected information.
|
||||
Only superusers can change this setting.
|
||||
Only superusers and users with the appropriate <literal>SET</literal>
|
||||
privilege can change this setting.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
@ -7882,9 +7909,10 @@ COPY postgres_log FROM '/full/path/to/logfile.csv' WITH csv;
|
||||
is used, in the output of <xref linkend="sql-vacuum"/> when
|
||||
the <literal>VERBOSE</literal> option is used, by autovacuum
|
||||
for auto-vacuums and auto-analyzes, when <xref
|
||||
linkend="guc-log-autovacuum-min-duration"/> is set and by
|
||||
<xref linkend="pgstatstatements"/>. Only superusers can
|
||||
change this setting.
|
||||
linkend="guc-log-autovacuum-min-duration"/> is set and by
|
||||
<xref linkend="pgstatstatements"/>.
|
||||
Only superusers and users with the appropriate <literal>SET</literal>
|
||||
privilege can change this setting.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
@ -7904,8 +7932,9 @@ COPY postgres_log FROM '/full/path/to/logfile.csv' WITH csv;
|
||||
measure the overhead of timing on your system.
|
||||
I/O timing information is
|
||||
displayed in <link linkend="monitoring-pg-stat-wal-view">
|
||||
<structname>pg_stat_wal</structname></link>. Only superusers can
|
||||
change this setting.
|
||||
<structname>pg_stat_wal</structname></link>.
|
||||
Only superusers and users with the appropriate <literal>SET</literal>
|
||||
privilege can change this setting.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
@ -7922,7 +7951,9 @@ COPY postgres_log FROM '/full/path/to/logfile.csv' WITH csv;
|
||||
<literal>pl</literal> to track only procedural-language functions,
|
||||
<literal>all</literal> to also track SQL and C language functions.
|
||||
The default is <literal>none</literal>, which disables function
|
||||
statistics tracking. Only superusers can change this setting.
|
||||
statistics tracking.
|
||||
Only superusers and users with the appropriate <literal>SET</literal>
|
||||
privilege can change this setting.
|
||||
</para>
|
||||
|
||||
<note>
|
||||
@ -8028,7 +8059,9 @@ COPY postgres_log FROM '/full/path/to/logfile.csv' WITH csv;
|
||||
statement statistics, while the others report per-module statistics.
|
||||
<varname>log_statement_stats</varname> cannot be enabled together with
|
||||
any of the per-module options. All of these options are disabled by
|
||||
default. Only superusers can change these settings.
|
||||
default.
|
||||
Only superusers and users with the appropriate <literal>SET</literal>
|
||||
privilege can change these settings.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
@ -8814,10 +8847,13 @@ COPY postgres_log FROM '/full/path/to/logfile.csv' WITH csv;
|
||||
<listitem>
|
||||
<para>
|
||||
Controls firing of replication-related triggers and rules for the
|
||||
current session. Setting this variable requires
|
||||
superuser privilege and results in discarding any previously cached
|
||||
query plans. Possible values are <literal>origin</literal> (the default),
|
||||
current session.
|
||||
Possible values are <literal>origin</literal> (the default),
|
||||
<literal>replica</literal> and <literal>local</literal>.
|
||||
Setting this parameter results in discarding any previously cached
|
||||
query plans.
|
||||
Only superusers and users with the appropriate <literal>SET</literal>
|
||||
privilege can change this setting.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
@ -9432,10 +9468,8 @@ SET XML OPTION { DOCUMENT | CONTENT };
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Only superusers can change this setting, because it affects the
|
||||
messages sent to the server log as well as to the client, and
|
||||
an improper value might obscure the readability of the server
|
||||
logs.
|
||||
Only superusers and users with the appropriate <literal>SET</literal>
|
||||
privilege can change this setting.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
@ -9630,7 +9664,8 @@ SET XML OPTION { DOCUMENT | CONTENT };
|
||||
The parameter value only takes effect at the start of the connection.
|
||||
Subsequent changes have no effect. If a specified library is not
|
||||
found, the connection attempt will fail.
|
||||
Only superusers can change this setting.
|
||||
Only superusers and users with the appropriate <literal>SET</literal>
|
||||
privilege can change this setting.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
@ -9780,7 +9815,8 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir'
|
||||
</para>
|
||||
|
||||
<para>
|
||||
This parameter can be changed at run time by superusers, but a
|
||||
This parameter can be changed at run time by superusers and users
|
||||
with the appropriate <literal>SET</literal> privilege, but a
|
||||
setting done that way will only persist until the end of the
|
||||
client connection, so this method should be reserved for
|
||||
development purposes. The recommended way to set this parameter
|
||||
@ -9844,8 +9880,9 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir'
|
||||
practice. On a heavily loaded server you might want to raise it.
|
||||
Ideally the setting should exceed your typical transaction time,
|
||||
so as to improve the odds that a lock will be released before
|
||||
the waiter decides to check for deadlock. Only superusers can change
|
||||
this setting.
|
||||
the waiter decides to check for deadlock.
|
||||
Only superusers and users with the appropriate <literal>SET</literal>
|
||||
privilege can change this setting.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
@ -10064,7 +10101,8 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir'
|
||||
and writable by all users. Setting this variable to <literal>on</literal>
|
||||
disables the new privilege checks, for compatibility with prior
|
||||
releases. The default is <literal>off</literal>.
|
||||
Only superusers can change this setting.
|
||||
Only superusers and users with the appropriate <literal>SET</literal>
|
||||
privilege can change this setting.
|
||||
</para>
|
||||
<para>
|
||||
Setting this variable does not disable all security checks related to
|
||||
@ -10717,7 +10755,9 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir'
|
||||
is intended to allow testing replication scenarios where primary and
|
||||
standby servers are running on the same machine. Such directories
|
||||
are likely to confuse backup tools that expect to find only symbolic
|
||||
links in that location. Only superusers can change this setting.
|
||||
links in that location.
|
||||
Only superusers and users with the appropriate <literal>SET</literal>
|
||||
privilege can change this setting.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
@ -10734,7 +10774,9 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir'
|
||||
certain other risky actions on system tables. This is otherwise not
|
||||
allowed even for superusers. Ill-advised use of this setting can
|
||||
cause irretrievable data loss or seriously corrupt the database
|
||||
system. Only superusers can change this setting.
|
||||
system.
|
||||
Only superusers and users with the appropriate <literal>SET</literal>
|
||||
privilege can change this setting.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
@ -10760,7 +10802,8 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir'
|
||||
</para>
|
||||
|
||||
<para>
|
||||
This parameter can only be set by superusers.
|
||||
Only superusers and users with the appropriate <literal>SET</literal>
|
||||
privilege can change this setting.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
@ -11145,8 +11188,9 @@ LOG: CleanUpLock: deleting: lock(0xb7acd844) id(24688,24696,0,0,0,1)
|
||||
the supported resource managers are <literal>heap</literal>,
|
||||
<literal>heap2</literal>, <literal>btree</literal>, <literal>hash</literal>,
|
||||
<literal>gin</literal>, <literal>gist</literal>, <literal>sequence</literal>,
|
||||
<literal>spgist</literal>, <literal>brin</literal>, and <literal>generic</literal>. Only
|
||||
superusers can change this setting.
|
||||
<literal>spgist</literal>, <literal>brin</literal>, and <literal>generic</literal>.
|
||||
Only superusers and users with the appropriate <literal>SET</literal>
|
||||
privilege can change this setting.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
@ -11187,7 +11231,9 @@ LOG: CleanUpLock: deleting: lock(0xb7acd844) id(24688,24696,0,0,0,1)
|
||||
you to get past the error and retrieve undamaged tuples that might still be
|
||||
present in the table if the block header is still sane. If the header is
|
||||
corrupt an error will be reported even if this option is enabled. The
|
||||
default setting is <literal>off</literal>, and it can only be changed by a superuser.
|
||||
default setting is <literal>off</literal>.
|
||||
Only superusers and users with the appropriate <literal>SET</literal>
|
||||
privilege can change this setting.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
@ -11213,8 +11259,9 @@ LOG: CleanUpLock: deleting: lock(0xb7acd844) id(24688,24696,0,0,0,1)
|
||||
data from the damaged pages of a table. Zeroed-out pages are not
|
||||
forced to disk so it is recommended to recreate the table or
|
||||
the index before turning this parameter off again. The
|
||||
default setting is <literal>off</literal>, and it can only be changed
|
||||
by a superuser.
|
||||
default setting is <literal>off</literal>.
|
||||
Only superusers and users with the appropriate <literal>SET</literal>
|
||||
privilege can change this setting.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
@ -11272,7 +11319,8 @@ LOG: CleanUpLock: deleting: lock(0xb7acd844) id(24688,24696,0,0,0,1)
|
||||
file system, inside <xref linkend="guc-data-directory"/>. This is only
|
||||
useful for working on the internals of the JIT implementation.
|
||||
The default setting is <literal>off</literal>.
|
||||
This parameter can only be changed by a superuser.
|
||||
Only superusers and users with the appropriate <literal>SET</literal>
|
||||
privilege can change this setting.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
@ -1691,7 +1691,8 @@ ALTER TABLE products RENAME TO items;
|
||||
<literal>INSERT</literal>, <literal>UPDATE</literal>, <literal>DELETE</literal>,
|
||||
<literal>TRUNCATE</literal>, <literal>REFERENCES</literal>, <literal>TRIGGER</literal>,
|
||||
<literal>CREATE</literal>, <literal>CONNECT</literal>, <literal>TEMPORARY</literal>,
|
||||
<literal>EXECUTE</literal>, and <literal>USAGE</literal>.
|
||||
<literal>EXECUTE</literal>, <literal>USAGE</literal>, <literal>SET</literal>
|
||||
and <literal>ALTER SYSTEM</literal>.
|
||||
The privileges applicable to a particular
|
||||
object vary depending on the object's type (table, function, etc).
|
||||
More detail about the meanings of these privileges appears below.
|
||||
@ -1959,6 +1960,28 @@ REVOKE ALL ON accounts FROM PUBLIC;
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><literal>SET</literal></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Allows a server configuration parameter to be set to a new value
|
||||
within the current session. (While this privilege can be granted
|
||||
on any parameter, it is meaningless except for parameters that would
|
||||
normally require superuser privilege to set.)
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><literal>ALTER SYSTEM</literal></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Allows a server configuration parameter to be configured to a new
|
||||
value using the <xref linkend="sql-altersystem"/> command.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
The privileges required by other commands are listed on the
|
||||
@ -1976,7 +1999,8 @@ REVOKE ALL ON accounts FROM PUBLIC;
|
||||
foreign servers,
|
||||
large objects,
|
||||
schemas,
|
||||
or tablespaces.
|
||||
tablespaces,
|
||||
or configuration parameters.
|
||||
For other types of objects, the default privileges
|
||||
granted to <literal>PUBLIC</literal> are as follows:
|
||||
<literal>CONNECT</literal> and <literal>TEMPORARY</literal> (create
|
||||
@ -2097,6 +2121,16 @@ REVOKE ALL ON accounts FROM PUBLIC;
|
||||
<literal>TYPE</literal>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>SET</literal></entry>
|
||||
<entry><literal>s</literal></entry>
|
||||
<entry><literal>PARAMETER</literal></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>ALTER SYSTEM</literal></entry>
|
||||
<entry><literal>A</literal></entry>
|
||||
<entry><literal>PARAMETER</literal></entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
@ -2167,6 +2201,12 @@ REVOKE ALL ON accounts FROM PUBLIC;
|
||||
<entry>none</entry>
|
||||
<entry><literal>\dl+</literal></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>PARAMETER</literal></entry>
|
||||
<entry><literal>sA</literal></entry>
|
||||
<entry>none</entry>
|
||||
<entry>none</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>SCHEMA</literal></entry>
|
||||
<entry><literal>UC</literal></entry>
|
||||
|
@ -22853,6 +22853,25 @@ SELECT has_function_privilege('joeuser', 'myfunc(int, text)', 'execute');
|
||||
</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry role="func_table_entry"><para role="func_signature">
|
||||
<indexterm>
|
||||
<primary>has_parameter_privilege</primary>
|
||||
</indexterm>
|
||||
<function>has_parameter_privilege</function> (
|
||||
<optional> <parameter>user</parameter> <type>name</type> or <type>oid</type>, </optional>
|
||||
<parameter>parameter</parameter> <type>text</type>,
|
||||
<parameter>privilege</parameter> <type>text</type> )
|
||||
<returnvalue>boolean</returnvalue>
|
||||
</para>
|
||||
<para>
|
||||
Does user have privilege for configuration parameter?
|
||||
The parameter name is case-insensitive.
|
||||
Allowable privilege types are <literal>SET</literal>
|
||||
and <literal>ALTER SYSTEM</literal>.
|
||||
</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry role="func_table_entry"><para role="func_signature">
|
||||
<indexterm>
|
||||
@ -23137,6 +23156,7 @@ SELECT has_function_privilege('joeuser', 'myfunc(int, text)', 'execute');
|
||||
'l' for <literal>LANGUAGE</literal>,
|
||||
'L' for <literal>LARGE OBJECT</literal>,
|
||||
'n' for <literal>SCHEMA</literal>,
|
||||
'p' for <literal>PARAMETER</literal>,
|
||||
't' for <literal>TABLESPACE</literal>,
|
||||
'F' for <literal>FOREIGN DATA WRAPPER</literal>,
|
||||
'S' for <literal>FOREIGN SERVER</literal>,
|
||||
@ -23905,7 +23925,7 @@ SELECT currval(pg_get_serial_sequence('sometable', 'id'));
|
||||
</simplelist>
|
||||
</para></entry>
|
||||
</row>
|
||||
|
||||
|
||||
<row>
|
||||
<entry role="func_table_entry"><para role="func_signature">
|
||||
<indexterm>
|
||||
@ -27427,7 +27447,7 @@ SELECT pg_size_pretty(sum(pg_relation_size(relid))) AS total_size
|
||||
are excluded.
|
||||
</para>
|
||||
<para>
|
||||
This function is restricted to superusers and roles with privileges of
|
||||
This function is restricted to superusers and roles with privileges of
|
||||
the <literal>pg_monitor</literal> role by default, but other users can
|
||||
be granted EXECUTE to run the function.
|
||||
</para></entry>
|
||||
|
@ -55,7 +55,8 @@ ALTER SYSTEM RESET ALL
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Only superusers can use <command>ALTER SYSTEM</command>. Also, since
|
||||
Only superusers and users granted <literal>ALTER SYSTEM</literal> privilege
|
||||
on a parameter can change it using <command>ALTER SYSTEM</command>. Also, since
|
||||
this command acts directly on the file system and cannot be rolled back,
|
||||
it is not allowed inside a transaction block or function.
|
||||
</para>
|
||||
|
@ -32,8 +32,8 @@ DROP OWNED BY { <replaceable class="parameter">name</replaceable> | CURRENT_ROLE
|
||||
<command>DROP OWNED</command> drops all the objects within the current
|
||||
database that are owned by one of the specified roles. Any
|
||||
privileges granted to the given roles on objects in the current
|
||||
database or on shared objects (databases, tablespaces) will also be
|
||||
revoked.
|
||||
database or on shared objects (databases, tablespaces, configuration
|
||||
parameters) will also be revoked.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
|
@ -77,6 +77,11 @@ GRANT { { SELECT | UPDATE } [, ...] | ALL [ PRIVILEGES ] }
|
||||
TO <replaceable class="parameter">role_specification</replaceable> [, ...] [ WITH GRANT OPTION ]
|
||||
[ GRANTED BY <replaceable class="parameter">role_specification</replaceable> ]
|
||||
|
||||
GRANT { { SET | ALTER SYSTEM } [, ... ] | ALL [ PRIVILEGES ] }
|
||||
ON PARAMETER <replaceable class="parameter">configuration_parameter</replaceable> [, ...]
|
||||
TO <replaceable class="parameter">role_specification</replaceable> [, ...] [ WITH GRANT OPTION ]
|
||||
[ GRANTED BY <replaceable class="parameter">role_specification</replaceable> ]
|
||||
|
||||
GRANT { { CREATE | USAGE } [, ...] | ALL [ PRIVILEGES ] }
|
||||
ON SCHEMA <replaceable>schema_name</replaceable> [, ...]
|
||||
TO <replaceable class="parameter">role_specification</replaceable> [, ...] [ WITH GRANT OPTION ]
|
||||
@ -111,9 +116,10 @@ GRANT <replaceable class="parameter">role_name</replaceable> [, ...] TO <replace
|
||||
|
||||
<para>
|
||||
The <command>GRANT</command> command has two basic variants: one
|
||||
that grants privileges on a database object (table, column, view, foreign
|
||||
table, sequence, database, foreign-data wrapper, foreign server, function, procedure,
|
||||
procedural language, schema, or tablespace), and one that grants
|
||||
that grants privileges on a database object (table, column, view,
|
||||
foreign table, sequence, database, foreign-data wrapper, foreign server,
|
||||
function, procedure, procedural language, large object, configuration
|
||||
parameter, schema, tablespace, or type), and one that grants
|
||||
membership in a role. These variants are similar in many ways, but
|
||||
they are different enough to be described separately.
|
||||
</para>
|
||||
@ -185,6 +191,8 @@ GRANT <replaceable class="parameter">role_name</replaceable> [, ...] TO <replace
|
||||
<term><literal>TEMPORARY</literal></term>
|
||||
<term><literal>EXECUTE</literal></term>
|
||||
<term><literal>USAGE</literal></term>
|
||||
<term><literal>SET</literal></term>
|
||||
<term><literal>ALTER SYSTEM</literal></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Specific types of privileges, as defined in <xref linkend="ddl-priv"/>.
|
||||
@ -452,7 +460,8 @@ GRANT admins TO joe;
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Privileges on databases, tablespaces, schemas, and languages are
|
||||
Privileges on databases, tablespaces, schemas, languages, and
|
||||
configuration parameters are
|
||||
<productname>PostgreSQL</productname> extensions.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
@ -38,7 +38,8 @@ PostgreSQL documentation
|
||||
linkend="app-psql"/> to restore the databases. It does this by
|
||||
calling <xref linkend="app-pgdump"/> for each database in the cluster.
|
||||
<application>pg_dumpall</application> also dumps global objects
|
||||
that are common to all databases, that is, database roles and tablespaces.
|
||||
that are common to all databases, namely database roles, tablespaces,
|
||||
and privilege grants for configuration parameters.
|
||||
(<application>pg_dump</application> does not save these objects.)
|
||||
</para>
|
||||
|
||||
|
@ -97,6 +97,13 @@ REVOKE [ GRANT OPTION FOR ]
|
||||
[ GRANTED BY <replaceable class="parameter">role_specification</replaceable> ]
|
||||
[ CASCADE | RESTRICT ]
|
||||
|
||||
REVOKE [ GRANT OPTION FOR ]
|
||||
{ { SET | ALTER SYSTEM } [, ...] | ALL [ PRIVILEGES ] }
|
||||
ON PARAMETER <replaceable class="parameter">configuration_parameter</replaceable> [, ...]
|
||||
FROM <replaceable class="parameter">role_specification</replaceable> [, ...]
|
||||
[ GRANTED BY <replaceable class="parameter">role_specification</replaceable> ]
|
||||
[ CASCADE | RESTRICT ]
|
||||
|
||||
REVOKE [ GRANT OPTION FOR ]
|
||||
{ { CREATE | USAGE } [, ...] | ALL [ PRIVILEGES ] }
|
||||
ON SCHEMA <replaceable>schema_name</replaceable> [, ...]
|
||||
|
@ -34,8 +34,10 @@ SET [ SESSION | LOCAL ] TIME ZONE { <replaceable class="parameter">timezone</rep
|
||||
parameters. Many of the run-time parameters listed in
|
||||
<xref linkend="runtime-config"/> can be changed on-the-fly with
|
||||
<command>SET</command>.
|
||||
(But some require superuser privileges to change, and others cannot
|
||||
be changed after server or session start.)
|
||||
(Some parameters can only be changed by superusers and users who
|
||||
have been granted <literal>SET</literal> privilege on that parameter.
|
||||
There are also parameters that cannot be changed after server or
|
||||
session start.)
|
||||
<command>SET</command> only affects the value used by the current
|
||||
session.
|
||||
</para>
|
||||
|
@ -38,6 +38,7 @@ OBJS = \
|
||||
pg_largeobject.o \
|
||||
pg_namespace.o \
|
||||
pg_operator.o \
|
||||
pg_parameter_acl.o \
|
||||
pg_proc.o \
|
||||
pg_publication.o \
|
||||
pg_range.o \
|
||||
@ -68,7 +69,8 @@ CATALOG_HEADERS := \
|
||||
pg_foreign_data_wrapper.h pg_foreign_server.h pg_user_mapping.h \
|
||||
pg_foreign_table.h pg_policy.h pg_replication_origin.h \
|
||||
pg_default_acl.h pg_init_privs.h pg_seclabel.h pg_shseclabel.h \
|
||||
pg_collation.h pg_partitioned_table.h pg_range.h pg_transform.h \
|
||||
pg_collation.h pg_parameter_acl.h pg_partitioned_table.h \
|
||||
pg_range.h pg_transform.h \
|
||||
pg_sequence.h pg_publication.h pg_publication_namespace.h \
|
||||
pg_publication_rel.h pg_subscription.h pg_subscription_rel.h
|
||||
|
||||
|
@ -48,6 +48,7 @@
|
||||
#include "catalog/pg_opclass.h"
|
||||
#include "catalog/pg_operator.h"
|
||||
#include "catalog/pg_opfamily.h"
|
||||
#include "catalog/pg_parameter_acl.h"
|
||||
#include "catalog/pg_proc.h"
|
||||
#include "catalog/pg_statistic_ext.h"
|
||||
#include "catalog/pg_subscription.h"
|
||||
@ -112,11 +113,13 @@ static void ExecGrant_Largeobject(InternalGrant *grantStmt);
|
||||
static void ExecGrant_Namespace(InternalGrant *grantStmt);
|
||||
static void ExecGrant_Tablespace(InternalGrant *grantStmt);
|
||||
static void ExecGrant_Type(InternalGrant *grantStmt);
|
||||
static void ExecGrant_Parameter(InternalGrant *grantStmt);
|
||||
|
||||
static void SetDefaultACLsInSchemas(InternalDefaultACL *iacls, List *nspnames);
|
||||
static void SetDefaultACL(InternalDefaultACL *iacls);
|
||||
|
||||
static List *objectNamesToOids(ObjectType objtype, List *objnames);
|
||||
static List *objectNamesToOids(ObjectType objtype, List *objnames,
|
||||
bool is_grant);
|
||||
static List *objectsInSchemaToOids(ObjectType objtype, List *nspnames);
|
||||
static List *getRelationsInNamespace(Oid namespaceId, char relkind);
|
||||
static void expand_col_privileges(List *colnames, Oid table_oid,
|
||||
@ -259,6 +262,9 @@ restrict_and_check_grant(bool is_grant, AclMode avail_goptions, bool all_privs,
|
||||
case OBJECT_TYPE:
|
||||
whole_mask = ACL_ALL_RIGHTS_TYPE;
|
||||
break;
|
||||
case OBJECT_PARAMETER_ACL:
|
||||
whole_mask = ACL_ALL_RIGHTS_PARAMETER_ACL;
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "unrecognized object type: %d", objtype);
|
||||
/* not reached, but keep compiler quiet */
|
||||
@ -390,7 +396,8 @@ ExecuteGrantStmt(GrantStmt *stmt)
|
||||
switch (stmt->targtype)
|
||||
{
|
||||
case ACL_TARGET_OBJECT:
|
||||
istmt.objects = objectNamesToOids(stmt->objtype, stmt->objects);
|
||||
istmt.objects = objectNamesToOids(stmt->objtype, stmt->objects,
|
||||
stmt->is_grant);
|
||||
break;
|
||||
case ACL_TARGET_ALL_IN_SCHEMA:
|
||||
istmt.objects = objectsInSchemaToOids(stmt->objtype, stmt->objects);
|
||||
@ -498,6 +505,10 @@ ExecuteGrantStmt(GrantStmt *stmt)
|
||||
all_privileges = ACL_ALL_RIGHTS_FOREIGN_SERVER;
|
||||
errormsg = gettext_noop("invalid privilege type %s for foreign server");
|
||||
break;
|
||||
case OBJECT_PARAMETER_ACL:
|
||||
all_privileges = ACL_ALL_RIGHTS_PARAMETER_ACL;
|
||||
errormsg = gettext_noop("invalid privilege type %s for parameter");
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "unrecognized GrantStmt.objtype: %d",
|
||||
(int) stmt->objtype);
|
||||
@ -600,6 +611,9 @@ ExecGrantStmt_oids(InternalGrant *istmt)
|
||||
case OBJECT_TABLESPACE:
|
||||
ExecGrant_Tablespace(istmt);
|
||||
break;
|
||||
case OBJECT_PARAMETER_ACL:
|
||||
ExecGrant_Parameter(istmt);
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "unrecognized GrantStmt.objtype: %d",
|
||||
(int) istmt->objtype);
|
||||
@ -626,7 +640,7 @@ ExecGrantStmt_oids(InternalGrant *istmt)
|
||||
* to fail.
|
||||
*/
|
||||
static List *
|
||||
objectNamesToOids(ObjectType objtype, List *objnames)
|
||||
objectNamesToOids(ObjectType objtype, List *objnames, bool is_grant)
|
||||
{
|
||||
List *objects = NIL;
|
||||
ListCell *cell;
|
||||
@ -759,6 +773,37 @@ objectNamesToOids(ObjectType objtype, List *objnames)
|
||||
objects = lappend_oid(objects, srvid);
|
||||
}
|
||||
break;
|
||||
case OBJECT_PARAMETER_ACL:
|
||||
foreach(cell, objnames)
|
||||
{
|
||||
/*
|
||||
* In this code we represent a GUC by the OID of its entry in
|
||||
* pg_parameter_acl, which we have to manufacture here if it
|
||||
* doesn't exist yet. (That's a hack for sure, but it avoids
|
||||
* messing with all the GRANT/REVOKE infrastructure that
|
||||
* expects to use OIDs for object identities.) However, if
|
||||
* this is a REVOKE, we can instead just ignore any GUCs that
|
||||
* don't have such an entry, as they must not have any
|
||||
* privileges needing removal.
|
||||
*/
|
||||
char *parameter = strVal(lfirst(cell));
|
||||
Oid parameterId = ParameterAclLookup(parameter, true);
|
||||
|
||||
if (!OidIsValid(parameterId) && is_grant)
|
||||
{
|
||||
parameterId = ParameterAclCreate(parameter);
|
||||
|
||||
/*
|
||||
* Prevent error when processing duplicate objects, and
|
||||
* make this new entry visible so that ExecGrant_Parameter
|
||||
* can update it.
|
||||
*/
|
||||
CommandCounterIncrement();
|
||||
}
|
||||
if (OidIsValid(parameterId))
|
||||
objects = lappend_oid(objects, parameterId);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "unrecognized GrantStmt.objtype: %d",
|
||||
(int) objtype);
|
||||
@ -1494,6 +1539,9 @@ RemoveRoleFromObjectACL(Oid roleid, Oid classid, Oid objid)
|
||||
case ForeignDataWrapperRelationId:
|
||||
istmt.objtype = OBJECT_FDW;
|
||||
break;
|
||||
case ParameterAclRelationId:
|
||||
istmt.objtype = OBJECT_PARAMETER_ACL;
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "unexpected object class %u", classid);
|
||||
break;
|
||||
@ -3225,6 +3273,154 @@ ExecGrant_Type(InternalGrant *istmt)
|
||||
table_close(relation, RowExclusiveLock);
|
||||
}
|
||||
|
||||
static void
|
||||
ExecGrant_Parameter(InternalGrant *istmt)
|
||||
{
|
||||
Relation relation;
|
||||
ListCell *cell;
|
||||
|
||||
if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
|
||||
istmt->privileges = ACL_ALL_RIGHTS_PARAMETER_ACL;
|
||||
|
||||
relation = table_open(ParameterAclRelationId, RowExclusiveLock);
|
||||
|
||||
foreach(cell, istmt->objects)
|
||||
{
|
||||
Oid parameterId = lfirst_oid(cell);
|
||||
Datum nameDatum;
|
||||
const char *parname;
|
||||
Datum aclDatum;
|
||||
bool isNull;
|
||||
AclMode avail_goptions;
|
||||
AclMode this_privileges;
|
||||
Acl *old_acl;
|
||||
Acl *new_acl;
|
||||
Oid grantorId;
|
||||
Oid ownerId;
|
||||
HeapTuple tuple;
|
||||
int noldmembers;
|
||||
int nnewmembers;
|
||||
Oid *oldmembers;
|
||||
Oid *newmembers;
|
||||
|
||||
tuple = SearchSysCache1(PARAMETERACLOID, ObjectIdGetDatum(parameterId));
|
||||
if (!HeapTupleIsValid(tuple))
|
||||
elog(ERROR, "cache lookup failed for parameter ACL %u",
|
||||
parameterId);
|
||||
|
||||
/* We'll need the GUC's name */
|
||||
nameDatum = SysCacheGetAttr(PARAMETERACLOID, tuple,
|
||||
Anum_pg_parameter_acl_parname,
|
||||
&isNull);
|
||||
Assert(!isNull);
|
||||
parname = TextDatumGetCString(nameDatum);
|
||||
|
||||
/* Treat all parameters as belonging to the bootstrap superuser. */
|
||||
ownerId = BOOTSTRAP_SUPERUSERID;
|
||||
|
||||
/*
|
||||
* Get working copy of existing ACL. If there's no ACL, substitute the
|
||||
* proper default.
|
||||
*/
|
||||
aclDatum = SysCacheGetAttr(PARAMETERACLOID, tuple,
|
||||
Anum_pg_parameter_acl_paracl,
|
||||
&isNull);
|
||||
|
||||
if (isNull)
|
||||
{
|
||||
old_acl = acldefault(istmt->objtype, ownerId);
|
||||
/* There are no old member roles according to the catalogs */
|
||||
noldmembers = 0;
|
||||
oldmembers = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
old_acl = DatumGetAclPCopy(aclDatum);
|
||||
/* Get the roles mentioned in the existing ACL */
|
||||
noldmembers = aclmembers(old_acl, &oldmembers);
|
||||
}
|
||||
|
||||
/* Determine ID to do the grant as, and available grant options */
|
||||
select_best_grantor(GetUserId(), istmt->privileges,
|
||||
old_acl, ownerId,
|
||||
&grantorId, &avail_goptions);
|
||||
|
||||
/*
|
||||
* Restrict the privileges to what we can actually grant, and emit the
|
||||
* standards-mandated warning and error messages.
|
||||
*/
|
||||
this_privileges =
|
||||
restrict_and_check_grant(istmt->is_grant, avail_goptions,
|
||||
istmt->all_privs, istmt->privileges,
|
||||
parameterId, grantorId,
|
||||
OBJECT_PARAMETER_ACL,
|
||||
parname,
|
||||
0, NULL);
|
||||
|
||||
/*
|
||||
* Generate new ACL.
|
||||
*/
|
||||
new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
|
||||
istmt->grant_option, istmt->behavior,
|
||||
istmt->grantees, this_privileges,
|
||||
grantorId, ownerId);
|
||||
|
||||
/*
|
||||
* We need the members of both old and new ACLs so we can correct the
|
||||
* shared dependency information.
|
||||
*/
|
||||
nnewmembers = aclmembers(new_acl, &newmembers);
|
||||
|
||||
/*
|
||||
* If the new ACL is equal to the default, we don't need the catalog
|
||||
* entry any longer. Delete it rather than updating it, to avoid
|
||||
* leaving a degenerate entry.
|
||||
*/
|
||||
if (aclequal(new_acl, acldefault(istmt->objtype, ownerId)))
|
||||
{
|
||||
CatalogTupleDelete(relation, &tuple->t_self);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* finished building new ACL value, now insert it */
|
||||
HeapTuple newtuple;
|
||||
Datum values[Natts_pg_parameter_acl];
|
||||
bool nulls[Natts_pg_parameter_acl];
|
||||
bool replaces[Natts_pg_parameter_acl];
|
||||
|
||||
MemSet(values, 0, sizeof(values));
|
||||
MemSet(nulls, false, sizeof(nulls));
|
||||
MemSet(replaces, false, sizeof(replaces));
|
||||
|
||||
replaces[Anum_pg_parameter_acl_paracl - 1] = true;
|
||||
values[Anum_pg_parameter_acl_paracl - 1] = PointerGetDatum(new_acl);
|
||||
|
||||
newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation),
|
||||
values, nulls, replaces);
|
||||
|
||||
CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
|
||||
}
|
||||
|
||||
/* Update initial privileges for extensions */
|
||||
recordExtensionInitPriv(parameterId, ParameterAclRelationId, 0,
|
||||
new_acl);
|
||||
|
||||
/* Update the shared dependency ACL info */
|
||||
updateAclDependencies(ParameterAclRelationId, parameterId, 0,
|
||||
ownerId,
|
||||
noldmembers, oldmembers,
|
||||
nnewmembers, newmembers);
|
||||
|
||||
ReleaseSysCache(tuple);
|
||||
pfree(new_acl);
|
||||
|
||||
/* prevent error when processing duplicate objects */
|
||||
CommandCounterIncrement();
|
||||
}
|
||||
|
||||
table_close(relation, RowExclusiveLock);
|
||||
}
|
||||
|
||||
|
||||
static AclMode
|
||||
string_to_privilege(const char *privname)
|
||||
@ -3255,6 +3451,10 @@ string_to_privilege(const char *privname)
|
||||
return ACL_CREATE_TEMP;
|
||||
if (strcmp(privname, "connect") == 0)
|
||||
return ACL_CONNECT;
|
||||
if (strcmp(privname, "set") == 0)
|
||||
return ACL_SET;
|
||||
if (strcmp(privname, "alter system") == 0)
|
||||
return ACL_ALTER_SYSTEM;
|
||||
if (strcmp(privname, "rule") == 0)
|
||||
return 0; /* ignore old RULE privileges */
|
||||
ereport(ERROR,
|
||||
@ -3292,6 +3492,10 @@ privilege_to_string(AclMode privilege)
|
||||
return "TEMP";
|
||||
case ACL_CONNECT:
|
||||
return "CONNECT";
|
||||
case ACL_SET:
|
||||
return "SET";
|
||||
case ACL_ALTER_SYSTEM:
|
||||
return "ALTER SYSTEM";
|
||||
default:
|
||||
elog(ERROR, "unrecognized privilege: %d", (int) privilege);
|
||||
}
|
||||
@ -3376,6 +3580,9 @@ aclcheck_error(AclResult aclerr, ObjectType objtype,
|
||||
case OBJECT_OPFAMILY:
|
||||
msg = gettext_noop("permission denied for operator family %s");
|
||||
break;
|
||||
case OBJECT_PARAMETER_ACL:
|
||||
msg = gettext_noop("permission denied for parameter %s");
|
||||
break;
|
||||
case OBJECT_POLICY:
|
||||
msg = gettext_noop("permission denied for policy %s");
|
||||
break;
|
||||
@ -3567,6 +3774,7 @@ aclcheck_error(AclResult aclerr, ObjectType objtype,
|
||||
case OBJECT_DEFAULT:
|
||||
case OBJECT_DEFACL:
|
||||
case OBJECT_DOMCONSTRAINT:
|
||||
case OBJECT_PARAMETER_ACL:
|
||||
case OBJECT_PUBLICATION_NAMESPACE:
|
||||
case OBJECT_PUBLICATION_REL:
|
||||
case OBJECT_ROLE:
|
||||
@ -3653,6 +3861,8 @@ pg_aclmask(ObjectType objtype, Oid table_oid, AttrNumber attnum, Oid roleid,
|
||||
case OBJECT_LARGEOBJECT:
|
||||
return pg_largeobject_aclmask_snapshot(table_oid, roleid,
|
||||
mask, how, NULL);
|
||||
case OBJECT_PARAMETER_ACL:
|
||||
return pg_parameter_acl_aclmask(table_oid, roleid, mask, how);
|
||||
case OBJECT_SCHEMA:
|
||||
return pg_namespace_aclmask(table_oid, roleid, mask, how);
|
||||
case OBJECT_STATISTIC_EXT:
|
||||
@ -4000,6 +4210,121 @@ pg_database_aclmask(Oid db_oid, Oid roleid,
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Exported routine for examining a user's privileges for a configuration
|
||||
* parameter (GUC), identified by GUC name.
|
||||
*/
|
||||
AclMode
|
||||
pg_parameter_aclmask(const char *name, Oid roleid, AclMode mask, AclMaskHow how)
|
||||
{
|
||||
AclMode result;
|
||||
char *parname;
|
||||
text *partext;
|
||||
HeapTuple tuple;
|
||||
|
||||
/* Superusers bypass all permission checking. */
|
||||
if (superuser_arg(roleid))
|
||||
return mask;
|
||||
|
||||
/* Convert name to the form it should have in pg_parameter_acl... */
|
||||
parname = convert_GUC_name_for_parameter_acl(name);
|
||||
partext = cstring_to_text(parname);
|
||||
|
||||
/* ... and look it up */
|
||||
tuple = SearchSysCache1(PARAMETERACLNAME, PointerGetDatum(partext));
|
||||
|
||||
if (!HeapTupleIsValid(tuple))
|
||||
{
|
||||
/* If no entry, GUC has no permissions for non-superusers */
|
||||
result = ACL_NO_RIGHTS;
|
||||
}
|
||||
else
|
||||
{
|
||||
Datum aclDatum;
|
||||
bool isNull;
|
||||
Acl *acl;
|
||||
|
||||
aclDatum = SysCacheGetAttr(PARAMETERACLNAME, tuple,
|
||||
Anum_pg_parameter_acl_paracl,
|
||||
&isNull);
|
||||
if (isNull)
|
||||
{
|
||||
/* No ACL, so build default ACL */
|
||||
acl = acldefault(OBJECT_PARAMETER_ACL, BOOTSTRAP_SUPERUSERID);
|
||||
aclDatum = (Datum) 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* detoast ACL if necessary */
|
||||
acl = DatumGetAclP(aclDatum);
|
||||
}
|
||||
|
||||
result = aclmask(acl, roleid, BOOTSTRAP_SUPERUSERID, mask, how);
|
||||
|
||||
/* if we have a detoasted copy, free it */
|
||||
if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
|
||||
pfree(acl);
|
||||
|
||||
ReleaseSysCache(tuple);
|
||||
}
|
||||
|
||||
pfree(parname);
|
||||
pfree(partext);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Exported routine for examining a user's privileges for a configuration
|
||||
* parameter (GUC), identified by the OID of its pg_parameter_acl entry.
|
||||
*/
|
||||
AclMode
|
||||
pg_parameter_acl_aclmask(Oid acl_oid, Oid roleid, AclMode mask, AclMaskHow how)
|
||||
{
|
||||
AclMode result;
|
||||
HeapTuple tuple;
|
||||
Datum aclDatum;
|
||||
bool isNull;
|
||||
Acl *acl;
|
||||
|
||||
/* Superusers bypass all permission checking. */
|
||||
if (superuser_arg(roleid))
|
||||
return mask;
|
||||
|
||||
/* Get the ACL from pg_parameter_acl */
|
||||
tuple = SearchSysCache1(PARAMETERACLOID, ObjectIdGetDatum(acl_oid));
|
||||
if (!HeapTupleIsValid(tuple))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
||||
errmsg("parameter ACL with OID %u does not exist",
|
||||
acl_oid)));
|
||||
|
||||
aclDatum = SysCacheGetAttr(PARAMETERACLOID, tuple,
|
||||
Anum_pg_parameter_acl_paracl,
|
||||
&isNull);
|
||||
if (isNull)
|
||||
{
|
||||
/* No ACL, so build default ACL */
|
||||
acl = acldefault(OBJECT_PARAMETER_ACL, BOOTSTRAP_SUPERUSERID);
|
||||
aclDatum = (Datum) 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* detoast ACL if necessary */
|
||||
acl = DatumGetAclP(aclDatum);
|
||||
}
|
||||
|
||||
result = aclmask(acl, roleid, BOOTSTRAP_SUPERUSERID, mask, how);
|
||||
|
||||
/* if we have a detoasted copy, free it */
|
||||
if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
|
||||
pfree(acl);
|
||||
|
||||
ReleaseSysCache(tuple);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Exported routine for examining a user's privileges for a function
|
||||
*/
|
||||
@ -4713,6 +5038,32 @@ pg_database_aclcheck(Oid db_oid, Oid roleid, AclMode mode)
|
||||
return ACLCHECK_NO_PRIV;
|
||||
}
|
||||
|
||||
/*
|
||||
* Exported routine for checking a user's access privileges to a configuration
|
||||
* parameter (GUC), identified by GUC name.
|
||||
*/
|
||||
AclResult
|
||||
pg_parameter_aclcheck(const char *name, Oid roleid, AclMode mode)
|
||||
{
|
||||
if (pg_parameter_aclmask(name, roleid, mode, ACLMASK_ANY) != 0)
|
||||
return ACLCHECK_OK;
|
||||
else
|
||||
return ACLCHECK_NO_PRIV;
|
||||
}
|
||||
|
||||
/*
|
||||
* Exported routine for checking a user's access privileges to a configuration
|
||||
* parameter (GUC), identified by the OID of its pg_parameter_acl entry.
|
||||
*/
|
||||
AclResult
|
||||
pg_parameter_acl_aclcheck(Oid acl_oid, Oid roleid, AclMode mode)
|
||||
{
|
||||
if (pg_parameter_acl_aclmask(acl_oid, roleid, mode, ACLMASK_ANY) != 0)
|
||||
return ACLCHECK_OK;
|
||||
else
|
||||
return ACLCHECK_NO_PRIV;
|
||||
}
|
||||
|
||||
/*
|
||||
* Exported routine for checking a user's access privileges to a function
|
||||
*/
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "catalog/pg_db_role_setting.h"
|
||||
#include "catalog/pg_largeobject.h"
|
||||
#include "catalog/pg_namespace.h"
|
||||
#include "catalog/pg_parameter_acl.h"
|
||||
#include "catalog/pg_replication_origin.h"
|
||||
#include "catalog/pg_shdepend.h"
|
||||
#include "catalog/pg_shdescription.h"
|
||||
@ -247,32 +248,35 @@ IsSharedRelation(Oid relationId)
|
||||
if (relationId == AuthIdRelationId ||
|
||||
relationId == AuthMemRelationId ||
|
||||
relationId == DatabaseRelationId ||
|
||||
relationId == SharedDescriptionRelationId ||
|
||||
relationId == SharedDependRelationId ||
|
||||
relationId == SharedSecLabelRelationId ||
|
||||
relationId == TableSpaceRelationId ||
|
||||
relationId == DbRoleSettingRelationId ||
|
||||
relationId == ParameterAclRelationId ||
|
||||
relationId == ReplicationOriginRelationId ||
|
||||
relationId == SubscriptionRelationId)
|
||||
relationId == SharedDependRelationId ||
|
||||
relationId == SharedDescriptionRelationId ||
|
||||
relationId == SharedSecLabelRelationId ||
|
||||
relationId == SubscriptionRelationId ||
|
||||
relationId == TableSpaceRelationId)
|
||||
return true;
|
||||
/* These are their indexes */
|
||||
if (relationId == AuthIdRolnameIndexId ||
|
||||
relationId == AuthIdOidIndexId ||
|
||||
relationId == AuthMemRoleMemIndexId ||
|
||||
if (relationId == AuthIdOidIndexId ||
|
||||
relationId == AuthIdRolnameIndexId ||
|
||||
relationId == AuthMemMemRoleIndexId ||
|
||||
relationId == AuthMemRoleMemIndexId ||
|
||||
relationId == DatabaseNameIndexId ||
|
||||
relationId == DatabaseOidIndexId ||
|
||||
relationId == SharedDescriptionObjIndexId ||
|
||||
relationId == SharedDependDependerIndexId ||
|
||||
relationId == SharedDependReferenceIndexId ||
|
||||
relationId == SharedSecLabelObjectIndexId ||
|
||||
relationId == TablespaceOidIndexId ||
|
||||
relationId == TablespaceNameIndexId ||
|
||||
relationId == DbRoleSettingDatidRolidIndexId ||
|
||||
relationId == ParameterAclOidIndexId ||
|
||||
relationId == ParameterAclParnameIndexId ||
|
||||
relationId == ReplicationOriginIdentIndex ||
|
||||
relationId == ReplicationOriginNameIndex ||
|
||||
relationId == SharedDependDependerIndexId ||
|
||||
relationId == SharedDependReferenceIndexId ||
|
||||
relationId == SharedDescriptionObjIndexId ||
|
||||
relationId == SharedSecLabelObjectIndexId ||
|
||||
relationId == SubscriptionNameIndexId ||
|
||||
relationId == SubscriptionObjectIndexId ||
|
||||
relationId == SubscriptionNameIndexId)
|
||||
relationId == TablespaceNameIndexId ||
|
||||
relationId == TablespaceOidIndexId)
|
||||
return true;
|
||||
/* These are their toast tables and toast indexes */
|
||||
if (relationId == PgAuthidToastTable ||
|
||||
@ -281,6 +285,8 @@ IsSharedRelation(Oid relationId)
|
||||
relationId == PgDatabaseToastIndex ||
|
||||
relationId == PgDbRoleSettingToastTable ||
|
||||
relationId == PgDbRoleSettingToastIndex ||
|
||||
relationId == PgParameterAclToastTable ||
|
||||
relationId == PgParameterAclToastIndex ||
|
||||
relationId == PgReplicationOriginToastTable ||
|
||||
relationId == PgReplicationOriginToastIndex ||
|
||||
relationId == PgShdescriptionToastTable ||
|
||||
|
@ -46,6 +46,7 @@
|
||||
#include "catalog/pg_opclass.h"
|
||||
#include "catalog/pg_operator.h"
|
||||
#include "catalog/pg_opfamily.h"
|
||||
#include "catalog/pg_parameter_acl.h"
|
||||
#include "catalog/pg_policy.h"
|
||||
#include "catalog/pg_proc.h"
|
||||
#include "catalog/pg_publication.h"
|
||||
@ -178,6 +179,7 @@ static const Oid object_classes[] = {
|
||||
DefaultAclRelationId, /* OCLASS_DEFACL */
|
||||
ExtensionRelationId, /* OCLASS_EXTENSION */
|
||||
EventTriggerRelationId, /* OCLASS_EVENT_TRIGGER */
|
||||
ParameterAclRelationId, /* OCLASS_PARAMETER_ACL */
|
||||
PolicyRelationId, /* OCLASS_POLICY */
|
||||
PublicationNamespaceRelationId, /* OCLASS_PUBLICATION_NAMESPACE */
|
||||
PublicationRelationId, /* OCLASS_PUBLICATION */
|
||||
@ -1507,6 +1509,7 @@ doDeletion(const ObjectAddress *object, int flags)
|
||||
case OCLASS_DATABASE:
|
||||
case OCLASS_TBLSPACE:
|
||||
case OCLASS_SUBSCRIPTION:
|
||||
case OCLASS_PARAMETER_ACL:
|
||||
elog(ERROR, "global objects cannot be deleted by doDeletion");
|
||||
break;
|
||||
|
||||
@ -2861,6 +2864,9 @@ getObjectClass(const ObjectAddress *object)
|
||||
case EventTriggerRelationId:
|
||||
return OCLASS_EVENT_TRIGGER;
|
||||
|
||||
case ParameterAclRelationId:
|
||||
return OCLASS_PARAMETER_ACL;
|
||||
|
||||
case PolicyRelationId:
|
||||
return OCLASS_POLICY;
|
||||
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include "catalog/pg_opclass.h"
|
||||
#include "catalog/pg_operator.h"
|
||||
#include "catalog/pg_opfamily.h"
|
||||
#include "catalog/pg_parameter_acl.h"
|
||||
#include "catalog/pg_policy.h"
|
||||
#include "catalog/pg_proc.h"
|
||||
#include "catalog/pg_publication.h"
|
||||
@ -818,6 +819,10 @@ static const struct object_type_map
|
||||
{
|
||||
"event trigger", OBJECT_EVENT_TRIGGER
|
||||
},
|
||||
/* OCLASS_PARAMETER_ACL */
|
||||
{
|
||||
"parameter ACL", OBJECT_PARAMETER_ACL
|
||||
},
|
||||
/* OCLASS_POLICY */
|
||||
{
|
||||
"policy", OBJECT_POLICY
|
||||
@ -1014,6 +1019,7 @@ get_object_address(ObjectType objtype, Node *object,
|
||||
case OBJECT_FDW:
|
||||
case OBJECT_FOREIGN_SERVER:
|
||||
case OBJECT_EVENT_TRIGGER:
|
||||
case OBJECT_PARAMETER_ACL:
|
||||
case OBJECT_ACCESS_METHOD:
|
||||
case OBJECT_PUBLICATION:
|
||||
case OBJECT_SUBSCRIPTION:
|
||||
@ -1315,6 +1321,11 @@ get_object_address_unqualified(ObjectType objtype,
|
||||
address.objectId = get_event_trigger_oid(name, missing_ok);
|
||||
address.objectSubId = 0;
|
||||
break;
|
||||
case OBJECT_PARAMETER_ACL:
|
||||
address.classId = ParameterAclRelationId;
|
||||
address.objectId = ParameterAclLookup(name, missing_ok);
|
||||
address.objectSubId = 0;
|
||||
break;
|
||||
case OBJECT_PUBLICATION:
|
||||
address.classId = PublicationRelationId;
|
||||
address.objectId = get_publication_oid(name, missing_ok);
|
||||
@ -2307,6 +2318,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
|
||||
case OBJECT_FDW:
|
||||
case OBJECT_FOREIGN_SERVER:
|
||||
case OBJECT_LANGUAGE:
|
||||
case OBJECT_PARAMETER_ACL:
|
||||
case OBJECT_PUBLICATION:
|
||||
case OBJECT_ROLE:
|
||||
case OBJECT_SCHEMA:
|
||||
@ -2597,6 +2609,7 @@ check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address,
|
||||
case OBJECT_TSPARSER:
|
||||
case OBJECT_TSTEMPLATE:
|
||||
case OBJECT_ACCESS_METHOD:
|
||||
case OBJECT_PARAMETER_ACL:
|
||||
/* We treat these object types as being owned by superusers */
|
||||
if (!superuser_arg(roleid))
|
||||
ereport(ERROR,
|
||||
@ -3880,6 +3893,32 @@ getObjectDescription(const ObjectAddress *object, bool missing_ok)
|
||||
break;
|
||||
}
|
||||
|
||||
case OCLASS_PARAMETER_ACL:
|
||||
{
|
||||
HeapTuple tup;
|
||||
Datum nameDatum;
|
||||
bool isNull;
|
||||
char *parname;
|
||||
|
||||
tup = SearchSysCache1(PARAMETERACLOID,
|
||||
ObjectIdGetDatum(object->objectId));
|
||||
if (!HeapTupleIsValid(tup))
|
||||
{
|
||||
if (!missing_ok)
|
||||
elog(ERROR, "cache lookup failed for parameter ACL %u",
|
||||
object->objectId);
|
||||
break;
|
||||
}
|
||||
nameDatum = SysCacheGetAttr(PARAMETERACLOID, tup,
|
||||
Anum_pg_parameter_acl_parname,
|
||||
&isNull);
|
||||
Assert(!isNull);
|
||||
parname = TextDatumGetCString(nameDatum);
|
||||
appendStringInfo(&buffer, _("parameter %s"), parname);
|
||||
ReleaseSysCache(tup);
|
||||
break;
|
||||
}
|
||||
|
||||
case OCLASS_POLICY:
|
||||
{
|
||||
Relation policy_rel;
|
||||
@ -4547,6 +4586,10 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
|
||||
appendStringInfoString(&buffer, "event trigger");
|
||||
break;
|
||||
|
||||
case OCLASS_PARAMETER_ACL:
|
||||
appendStringInfoString(&buffer, "parameter ACL");
|
||||
break;
|
||||
|
||||
case OCLASS_POLICY:
|
||||
appendStringInfoString(&buffer, "policy");
|
||||
break;
|
||||
@ -5693,6 +5736,34 @@ getObjectIdentityParts(const ObjectAddress *object,
|
||||
break;
|
||||
}
|
||||
|
||||
case OCLASS_PARAMETER_ACL:
|
||||
{
|
||||
HeapTuple tup;
|
||||
Datum nameDatum;
|
||||
bool isNull;
|
||||
char *parname;
|
||||
|
||||
tup = SearchSysCache1(PARAMETERACLOID,
|
||||
ObjectIdGetDatum(object->objectId));
|
||||
if (!HeapTupleIsValid(tup))
|
||||
{
|
||||
if (!missing_ok)
|
||||
elog(ERROR, "cache lookup failed for parameter ACL %u",
|
||||
object->objectId);
|
||||
break;
|
||||
}
|
||||
nameDatum = SysCacheGetAttr(PARAMETERACLOID, tup,
|
||||
Anum_pg_parameter_acl_parname,
|
||||
&isNull);
|
||||
Assert(!isNull);
|
||||
parname = TextDatumGetCString(nameDatum);
|
||||
appendStringInfoString(&buffer, parname);
|
||||
if (objname)
|
||||
*objname = list_make1(parname);
|
||||
ReleaseSysCache(tup);
|
||||
break;
|
||||
}
|
||||
|
||||
case OCLASS_POLICY:
|
||||
{
|
||||
Relation polDesc;
|
||||
|
118
src/backend/catalog/pg_parameter_acl.c
Normal file
118
src/backend/catalog/pg_parameter_acl.c
Normal file
@ -0,0 +1,118 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* pg_parameter_acl.c
|
||||
* routines to support manipulation of the pg_parameter_acl relation
|
||||
*
|
||||
* Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* src/backend/catalog/pg_parameter_acl.c
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include "postgres.h"
|
||||
|
||||
#include "access/table.h"
|
||||
#include "catalog/catalog.h"
|
||||
#include "catalog/indexing.h"
|
||||
#include "catalog/objectaccess.h"
|
||||
#include "catalog/pg_namespace.h"
|
||||
#include "catalog/pg_parameter_acl.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/pg_locale.h"
|
||||
#include "utils/rel.h"
|
||||
#include "utils/syscache.h"
|
||||
|
||||
|
||||
/*
|
||||
* ParameterAclLookup - Given a configuration parameter name,
|
||||
* look up the associated configuration parameter ACL's OID.
|
||||
*
|
||||
* If missing_ok is false, throw an error if ACL entry not found. If
|
||||
* true, just return InvalidOid.
|
||||
*/
|
||||
Oid
|
||||
ParameterAclLookup(const char *parameter, bool missing_ok)
|
||||
{
|
||||
Oid oid;
|
||||
char *parname;
|
||||
|
||||
/* Convert name to the form it should have in pg_parameter_acl... */
|
||||
parname = convert_GUC_name_for_parameter_acl(parameter);
|
||||
|
||||
/* ... and look it up */
|
||||
oid = GetSysCacheOid1(PARAMETERACLNAME, Anum_pg_parameter_acl_oid,
|
||||
PointerGetDatum(cstring_to_text(parname)));
|
||||
|
||||
if (!OidIsValid(oid) && !missing_ok)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
||||
errmsg("parameter ACL \"%s\" does not exist", parameter)));
|
||||
|
||||
pfree(parname);
|
||||
|
||||
return oid;
|
||||
}
|
||||
|
||||
/*
|
||||
* ParameterAclCreate
|
||||
*
|
||||
* Add a new tuple to pg_parameter_acl.
|
||||
*
|
||||
* parameter: the parameter name to create an entry for.
|
||||
* Caller should have verified that there's no such entry already.
|
||||
*
|
||||
* Returns the new entry's OID.
|
||||
*/
|
||||
Oid
|
||||
ParameterAclCreate(const char *parameter)
|
||||
{
|
||||
Oid parameterId;
|
||||
char *parname;
|
||||
Relation rel;
|
||||
TupleDesc tupDesc;
|
||||
HeapTuple tuple;
|
||||
Datum values[Natts_pg_parameter_acl];
|
||||
bool nulls[Natts_pg_parameter_acl];
|
||||
|
||||
/*
|
||||
* To prevent cluttering pg_parameter_acl with useless entries, insist
|
||||
* that the name be valid.
|
||||
*/
|
||||
if (!check_GUC_name_for_parameter_acl(parameter))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_NAME),
|
||||
errmsg("invalid parameter name \"%s\"",
|
||||
parameter)));
|
||||
|
||||
/* Convert name to the form it should have in pg_parameter_acl. */
|
||||
parname = convert_GUC_name_for_parameter_acl(parameter);
|
||||
|
||||
/*
|
||||
* Create and insert a new record containing a null ACL.
|
||||
*
|
||||
* We don't take a strong enough lock to prevent concurrent insertions,
|
||||
* relying instead on the unique index.
|
||||
*/
|
||||
rel = table_open(ParameterAclRelationId, RowExclusiveLock);
|
||||
tupDesc = RelationGetDescr(rel);
|
||||
MemSet(values, 0, sizeof(values));
|
||||
MemSet(nulls, false, sizeof(nulls));
|
||||
parameterId = GetNewOidWithIndex(rel,
|
||||
ParameterAclOidIndexId,
|
||||
Anum_pg_parameter_acl_oid);
|
||||
values[Anum_pg_parameter_acl_oid - 1] = ObjectIdGetDatum(parameterId);
|
||||
values[Anum_pg_parameter_acl_parname - 1] =
|
||||
PointerGetDatum(cstring_to_text(parname));
|
||||
nulls[Anum_pg_parameter_acl_paracl - 1] = true;
|
||||
tuple = heap_form_tuple(tupDesc, values, nulls);
|
||||
CatalogTupleInsert(rel, tuple);
|
||||
|
||||
/* Close pg_parameter_acl, but keep lock till commit. */
|
||||
heap_freetuple(tuple);
|
||||
table_close(rel, NoLock);
|
||||
|
||||
return parameterId;
|
||||
}
|
@ -658,6 +658,7 @@ AlterObjectNamespace_oid(Oid classId, Oid objid, Oid nspOid,
|
||||
case OCLASS_DEFACL:
|
||||
case OCLASS_EXTENSION:
|
||||
case OCLASS_EVENT_TRIGGER:
|
||||
case OCLASS_PARAMETER_ACL:
|
||||
case OCLASS_POLICY:
|
||||
case OCLASS_PUBLICATION:
|
||||
case OCLASS_PUBLICATION_NAMESPACE:
|
||||
|
@ -940,6 +940,7 @@ EventTriggerSupportsObjectType(ObjectType obtype)
|
||||
case OBJECT_DATABASE:
|
||||
case OBJECT_TABLESPACE:
|
||||
case OBJECT_ROLE:
|
||||
case OBJECT_PARAMETER_ACL:
|
||||
/* no support for global objects */
|
||||
return false;
|
||||
case OBJECT_EVENT_TRIGGER:
|
||||
@ -1015,6 +1016,7 @@ EventTriggerSupportsObjectClass(ObjectClass objclass)
|
||||
case OCLASS_DATABASE:
|
||||
case OCLASS_TBLSPACE:
|
||||
case OCLASS_ROLE:
|
||||
case OCLASS_PARAMETER_ACL:
|
||||
/* no support for global objects */
|
||||
return false;
|
||||
case OCLASS_EVENT_TRIGGER:
|
||||
@ -2042,6 +2044,8 @@ stringify_grant_objtype(ObjectType objtype)
|
||||
return "LARGE OBJECT";
|
||||
case OBJECT_SCHEMA:
|
||||
return "SCHEMA";
|
||||
case OBJECT_PARAMETER_ACL:
|
||||
return "PARAMETER";
|
||||
case OBJECT_PROCEDURE:
|
||||
return "PROCEDURE";
|
||||
case OBJECT_ROUTINE:
|
||||
@ -2153,6 +2157,7 @@ stringify_adefprivs_objtype(ObjectType objtype)
|
||||
case OBJECT_OPCLASS:
|
||||
case OBJECT_OPERATOR:
|
||||
case OBJECT_OPFAMILY:
|
||||
case OBJECT_PARAMETER_ACL:
|
||||
case OBJECT_POLICY:
|
||||
case OBJECT_PUBLICATION:
|
||||
case OBJECT_PUBLICATION_NAMESPACE:
|
||||
|
@ -78,6 +78,7 @@ SecLabelSupportsObjectType(ObjectType objtype)
|
||||
case OBJECT_OPCLASS:
|
||||
case OBJECT_OPERATOR:
|
||||
case OBJECT_OPFAMILY:
|
||||
case OBJECT_PARAMETER_ACL:
|
||||
case OBJECT_POLICY:
|
||||
case OBJECT_PUBLICATION_NAMESPACE:
|
||||
case OBJECT_PUBLICATION_REL:
|
||||
|
@ -12655,6 +12655,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
|
||||
case OCLASS_DEFACL:
|
||||
case OCLASS_EXTENSION:
|
||||
case OCLASS_EVENT_TRIGGER:
|
||||
case OCLASS_PARAMETER_ACL:
|
||||
case OCLASS_PUBLICATION:
|
||||
case OCLASS_PUBLICATION_NAMESPACE:
|
||||
case OCLASS_PUBLICATION_REL:
|
||||
|
@ -371,8 +371,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
|
||||
%type <str> foreign_server_version opt_foreign_server_version
|
||||
%type <str> opt_in_database
|
||||
|
||||
%type <str> OptSchemaName
|
||||
%type <list> OptSchemaEltList
|
||||
%type <str> OptSchemaName parameter_name
|
||||
%type <list> OptSchemaEltList parameter_name_list
|
||||
|
||||
%type <chr> am_type
|
||||
|
||||
@ -827,7 +827,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
|
||||
ORDER ORDINALITY OTHERS OUT_P OUTER_P
|
||||
OVER OVERLAPS OVERLAY OVERRIDING OWNED OWNER
|
||||
|
||||
PARALLEL PARSER PARTIAL PARTITION PASSING PASSWORD PATH PLACING PLAN PLANS POLICY
|
||||
PARALLEL PARAMETER PARSER PARTIAL PARTITION PASSING PASSWORD PATH
|
||||
PLACING PLAN PLANS POLICY
|
||||
POSITION PRECEDING PRECISION PRESERVE PREPARE PREPARED PRIMARY
|
||||
PRIOR PRIVILEGES PROCEDURAL PROCEDURE PROCEDURES PROGRAM PUBLICATION
|
||||
|
||||
@ -7197,6 +7198,13 @@ privilege: SELECT opt_column_list
|
||||
n->cols = $2;
|
||||
$$ = n;
|
||||
}
|
||||
| ALTER SYSTEM_P
|
||||
{
|
||||
AccessPriv *n = makeNode(AccessPriv);
|
||||
n->priv_name = pstrdup("alter system");
|
||||
n->cols = NIL;
|
||||
$$ = n;
|
||||
}
|
||||
| ColId opt_column_list
|
||||
{
|
||||
AccessPriv *n = makeNode(AccessPriv);
|
||||
@ -7206,6 +7214,28 @@ privilege: SELECT opt_column_list
|
||||
}
|
||||
;
|
||||
|
||||
parameter_name_list:
|
||||
parameter_name
|
||||
{
|
||||
$$ = list_make1(makeString($1));
|
||||
}
|
||||
| parameter_name_list ',' parameter_name
|
||||
{
|
||||
$$ = lappend($1, makeString($3));
|
||||
}
|
||||
;
|
||||
|
||||
parameter_name:
|
||||
ColId
|
||||
{
|
||||
$$ = $1;
|
||||
}
|
||||
| parameter_name '.' ColId
|
||||
{
|
||||
$$ = psprintf("%s.%s", $1, $3);
|
||||
}
|
||||
;
|
||||
|
||||
|
||||
/* Don't bother trying to fold the first two rules into one using
|
||||
* opt_table. You're going to get conflicts.
|
||||
@ -7307,6 +7337,14 @@ privilege_target:
|
||||
n->objs = $3;
|
||||
$$ = n;
|
||||
}
|
||||
| PARAMETER parameter_name_list
|
||||
{
|
||||
PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
|
||||
n->targtype = ACL_TARGET_OBJECT;
|
||||
n->objtype = OBJECT_PARAMETER_ACL;
|
||||
n->objs = $2;
|
||||
$$ = n;
|
||||
}
|
||||
| SCHEMA name_list
|
||||
{
|
||||
PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
|
||||
@ -17065,6 +17103,7 @@ unreserved_keyword:
|
||||
| OWNED
|
||||
| OWNER
|
||||
| PARALLEL
|
||||
| PARAMETER
|
||||
| PARSER
|
||||
| PARTIAL
|
||||
| PARTITION
|
||||
@ -17682,6 +17721,7 @@ bare_label_keyword:
|
||||
| OWNED
|
||||
| OWNER
|
||||
| PARALLEL
|
||||
| PARAMETER
|
||||
| PARSER
|
||||
| PARTIAL
|
||||
| PARTITION
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "catalog/pg_authid.h"
|
||||
#include "catalog/pg_class.h"
|
||||
#include "catalog/pg_database.h"
|
||||
#include "catalog/pg_parameter_acl.h"
|
||||
#include "catalog/pg_type.h"
|
||||
#include "commands/dbcommands.h"
|
||||
#include "commands/proclang.h"
|
||||
@ -36,6 +37,7 @@
|
||||
#include "utils/array.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/catcache.h"
|
||||
#include "utils/guc.h"
|
||||
#include "utils/inval.h"
|
||||
#include "utils/lsyscache.h"
|
||||
#include "utils/memutils.h"
|
||||
@ -109,6 +111,7 @@ static Oid convert_tablespace_name(text *tablespacename);
|
||||
static AclMode convert_tablespace_priv_string(text *priv_type_text);
|
||||
static Oid convert_type_name(text *typename);
|
||||
static AclMode convert_type_priv_string(text *priv_type_text);
|
||||
static AclMode convert_parameter_priv_string(text *priv_text);
|
||||
static AclMode convert_role_priv_string(text *priv_type_text);
|
||||
static AclResult pg_role_aclcheck(Oid role_oid, Oid roleid, AclMode mode);
|
||||
|
||||
@ -306,6 +309,12 @@ aclparse(const char *s, AclItem *aip)
|
||||
case ACL_CONNECT_CHR:
|
||||
read = ACL_CONNECT;
|
||||
break;
|
||||
case ACL_SET_CHR:
|
||||
read = ACL_SET;
|
||||
break;
|
||||
case ACL_ALTER_SYSTEM_CHR:
|
||||
read = ACL_ALTER_SYSTEM;
|
||||
break;
|
||||
case 'R': /* ignore old RULE privileges */
|
||||
read = 0;
|
||||
break;
|
||||
@ -794,6 +803,10 @@ acldefault(ObjectType objtype, Oid ownerId)
|
||||
world_default = ACL_USAGE;
|
||||
owner_default = ACL_ALL_RIGHTS_TYPE;
|
||||
break;
|
||||
case OBJECT_PARAMETER_ACL:
|
||||
world_default = ACL_NO_RIGHTS;
|
||||
owner_default = ACL_ALL_RIGHTS_PARAMETER_ACL;
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "unrecognized objtype: %d", (int) objtype);
|
||||
world_default = ACL_NO_RIGHTS; /* keep compiler quiet */
|
||||
@ -876,6 +889,9 @@ acldefault_sql(PG_FUNCTION_ARGS)
|
||||
case 'n':
|
||||
objtype = OBJECT_SCHEMA;
|
||||
break;
|
||||
case 'p':
|
||||
objtype = OBJECT_PARAMETER_ACL;
|
||||
break;
|
||||
case 't':
|
||||
objtype = OBJECT_TABLESPACE;
|
||||
break;
|
||||
@ -1602,6 +1618,10 @@ convert_priv_string(text *priv_type_text)
|
||||
return ACL_CREATE_TEMP;
|
||||
if (pg_strcasecmp(priv_type, "CONNECT") == 0)
|
||||
return ACL_CONNECT;
|
||||
if (pg_strcasecmp(priv_type, "SET") == 0)
|
||||
return ACL_SET;
|
||||
if (pg_strcasecmp(priv_type, "ALTER SYSTEM") == 0)
|
||||
return ACL_ALTER_SYSTEM;
|
||||
if (pg_strcasecmp(priv_type, "RULE") == 0)
|
||||
return 0; /* ignore old RULE privileges */
|
||||
|
||||
@ -1698,6 +1718,10 @@ convert_aclright_to_string(int aclright)
|
||||
return "TEMPORARY";
|
||||
case ACL_CONNECT:
|
||||
return "CONNECT";
|
||||
case ACL_SET:
|
||||
return "SET";
|
||||
case ACL_ALTER_SYSTEM:
|
||||
return "ALTER SYSTEM";
|
||||
default:
|
||||
elog(ERROR, "unrecognized aclright: %d", aclright);
|
||||
return NULL;
|
||||
@ -4429,6 +4453,96 @@ convert_type_priv_string(text *priv_type_text)
|
||||
return convert_any_priv_string(priv_type_text, type_priv_map);
|
||||
}
|
||||
|
||||
/*
|
||||
* has_parameter_privilege variants
|
||||
* These are all named "has_parameter_privilege" at the SQL level.
|
||||
* They take various combinations of parameter name with
|
||||
* user name, user OID, or implicit user = current_user.
|
||||
*
|
||||
* The result is a boolean value: true if user has been granted
|
||||
* the indicated privilege or false if not.
|
||||
*/
|
||||
|
||||
/*
|
||||
* has_param_priv_byname
|
||||
*
|
||||
* Helper function to check user privileges on a parameter given the
|
||||
* role by Oid, parameter by text name, and privileges as AclMode.
|
||||
*/
|
||||
static bool
|
||||
has_param_priv_byname(Oid roleid, const text *parameter, AclMode priv)
|
||||
{
|
||||
char *paramstr = text_to_cstring(parameter);
|
||||
|
||||
return pg_parameter_aclcheck(paramstr, roleid, priv) == ACLCHECK_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* has_parameter_privilege_name_name
|
||||
* Check user privileges on a parameter given name username, text
|
||||
* parameter, and text priv name.
|
||||
*/
|
||||
Datum
|
||||
has_parameter_privilege_name_name(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Name username = PG_GETARG_NAME(0);
|
||||
text *parameter = PG_GETARG_TEXT_PP(1);
|
||||
AclMode priv = convert_parameter_priv_string(PG_GETARG_TEXT_PP(2));
|
||||
Oid roleid = get_role_oid_or_public(NameStr(*username));
|
||||
|
||||
PG_RETURN_BOOL(has_param_priv_byname(roleid, parameter, priv));
|
||||
}
|
||||
|
||||
/*
|
||||
* has_parameter_privilege_name
|
||||
* Check user privileges on a parameter given text parameter and text priv
|
||||
* name. current_user is assumed
|
||||
*/
|
||||
Datum
|
||||
has_parameter_privilege_name(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *parameter = PG_GETARG_TEXT_PP(0);
|
||||
AclMode priv = convert_parameter_priv_string(PG_GETARG_TEXT_PP(1));
|
||||
|
||||
PG_RETURN_BOOL(has_param_priv_byname(GetUserId(), parameter, priv));
|
||||
}
|
||||
|
||||
/*
|
||||
* has_parameter_privilege_id_name
|
||||
* Check user privileges on a parameter given roleid, text parameter, and
|
||||
* text priv name.
|
||||
*/
|
||||
Datum
|
||||
has_parameter_privilege_id_name(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Oid roleid = PG_GETARG_OID(0);
|
||||
text *parameter = PG_GETARG_TEXT_PP(1);
|
||||
AclMode priv = convert_parameter_priv_string(PG_GETARG_TEXT_PP(2));
|
||||
|
||||
PG_RETURN_BOOL(has_param_priv_byname(roleid, parameter, priv));
|
||||
}
|
||||
|
||||
/*
|
||||
* Support routines for has_parameter_privilege family.
|
||||
*/
|
||||
|
||||
/*
|
||||
* convert_parameter_priv_string
|
||||
* Convert text string to AclMode value.
|
||||
*/
|
||||
static AclMode
|
||||
convert_parameter_priv_string(text *priv_text)
|
||||
{
|
||||
static const priv_map parameter_priv_map[] = {
|
||||
{"SET", ACL_SET},
|
||||
{"SET WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_SET)},
|
||||
{"ALTER SYSTEM", ACL_ALTER_SYSTEM},
|
||||
{"ALTER SYSTEM WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_ALTER_SYSTEM)},
|
||||
{NULL, 0}
|
||||
};
|
||||
|
||||
return convert_any_priv_string(priv_text, parameter_priv_map);
|
||||
}
|
||||
|
||||
/*
|
||||
* pg_has_role variants
|
||||
|
23
src/backend/utils/cache/syscache.c
vendored
23
src/backend/utils/cache/syscache.c
vendored
@ -47,6 +47,7 @@
|
||||
#include "catalog/pg_opclass.h"
|
||||
#include "catalog/pg_operator.h"
|
||||
#include "catalog/pg_opfamily.h"
|
||||
#include "catalog/pg_parameter_acl.h"
|
||||
#include "catalog/pg_partitioned_table.h"
|
||||
#include "catalog/pg_proc.h"
|
||||
#include "catalog/pg_publication.h"
|
||||
@ -574,6 +575,28 @@ static const struct cachedesc cacheinfo[] = {
|
||||
},
|
||||
8
|
||||
},
|
||||
{ParameterAclRelationId, /* PARAMETERACLNAME */
|
||||
ParameterAclParnameIndexId,
|
||||
1,
|
||||
{
|
||||
Anum_pg_parameter_acl_parname,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
},
|
||||
4
|
||||
},
|
||||
{ParameterAclRelationId, /* PARAMETERACLOID */
|
||||
ParameterAclOidIndexId,
|
||||
1,
|
||||
{
|
||||
Anum_pg_parameter_acl_oid,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
},
|
||||
4
|
||||
},
|
||||
{PartitionedRelationId, /* PARTRELID */
|
||||
PartitionedRelidIndexId,
|
||||
1,
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include "catalog/namespace.h"
|
||||
#include "catalog/objectaccess.h"
|
||||
#include "catalog/pg_authid.h"
|
||||
#include "catalog/pg_parameter_acl.h"
|
||||
#include "catalog/storage.h"
|
||||
#include "commands/async.h"
|
||||
#include "commands/prepare.h"
|
||||
@ -5713,6 +5714,65 @@ guc_name_compare(const char *namea, const char *nameb)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Convert a GUC name to the form that should be used in pg_parameter_acl.
|
||||
*
|
||||
* We need to canonicalize entries since, for example, case should not be
|
||||
* significant. In addition, we apply the map_old_guc_names[] mapping so that
|
||||
* any obsolete names will be converted when stored in a new PG version.
|
||||
* Note however that this function does not verify legality of the name.
|
||||
*
|
||||
* The result is a palloc'd string.
|
||||
*/
|
||||
char *
|
||||
convert_GUC_name_for_parameter_acl(const char *name)
|
||||
{
|
||||
char *result;
|
||||
|
||||
/* Apply old-GUC-name mapping. */
|
||||
for (int i = 0; map_old_guc_names[i] != NULL; i += 2)
|
||||
{
|
||||
if (guc_name_compare(name, map_old_guc_names[i]) == 0)
|
||||
{
|
||||
name = map_old_guc_names[i + 1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Apply case-folding that matches guc_name_compare(). */
|
||||
result = pstrdup(name);
|
||||
for (char *ptr = result; *ptr != '\0'; ptr++)
|
||||
{
|
||||
char ch = *ptr;
|
||||
|
||||
if (ch >= 'A' && ch <= 'Z')
|
||||
{
|
||||
ch += 'a' - 'A';
|
||||
*ptr = ch;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether we should allow creation of a pg_parameter_acl entry
|
||||
* for the given name. (This can be applied either before or after
|
||||
* canonicalizing it.)
|
||||
*/
|
||||
bool
|
||||
check_GUC_name_for_parameter_acl(const char *name)
|
||||
{
|
||||
/* OK if the GUC exists. */
|
||||
if (find_option(name, false, true, DEBUG1) != NULL)
|
||||
return true;
|
||||
/* Otherwise, it'd better be a valid custom GUC name. */
|
||||
if (valid_custom_variable_name(name))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Initialize GUC options during program startup.
|
||||
*
|
||||
@ -7518,14 +7578,24 @@ set_config_option(const char *name, const char *value,
|
||||
*/
|
||||
break;
|
||||
case PGC_SU_BACKEND:
|
||||
/* Reject if we're connecting but user is not superuser */
|
||||
if (context == PGC_BACKEND)
|
||||
{
|
||||
ereport(elevel,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
errmsg("permission denied to set parameter \"%s\"",
|
||||
name)));
|
||||
return 0;
|
||||
/*
|
||||
* Check whether the current user has been granted privilege
|
||||
* to set this GUC.
|
||||
*/
|
||||
AclResult aclresult;
|
||||
|
||||
aclresult = pg_parameter_aclcheck(name, GetUserId(), ACL_SET);
|
||||
if (aclresult != ACLCHECK_OK)
|
||||
{
|
||||
/* No granted privilege */
|
||||
ereport(elevel,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
errmsg("permission denied to set parameter \"%s\"",
|
||||
name)));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* fall through to process the same as PGC_BACKEND */
|
||||
/* FALLTHROUGH */
|
||||
@ -7568,11 +7638,22 @@ set_config_option(const char *name, const char *value,
|
||||
case PGC_SUSET:
|
||||
if (context == PGC_USERSET || context == PGC_BACKEND)
|
||||
{
|
||||
ereport(elevel,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
errmsg("permission denied to set parameter \"%s\"",
|
||||
name)));
|
||||
return 0;
|
||||
/*
|
||||
* Check whether the current user has been granted privilege
|
||||
* to set this GUC.
|
||||
*/
|
||||
AclResult aclresult;
|
||||
|
||||
aclresult = pg_parameter_aclcheck(name, GetUserId(), ACL_SET);
|
||||
if (aclresult != ACLCHECK_OK)
|
||||
{
|
||||
/* No granted privilege */
|
||||
ereport(elevel,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
errmsg("permission denied to set parameter \"%s\"",
|
||||
name)));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PGC_USERSET:
|
||||
@ -8617,11 +8698,6 @@ AlterSystemSetConfigFile(AlterSystemStmt *altersysstmt)
|
||||
char AutoConfFileName[MAXPGPATH];
|
||||
char AutoConfTmpFileName[MAXPGPATH];
|
||||
|
||||
if (!superuser())
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
errmsg("must be superuser to execute ALTER SYSTEM command")));
|
||||
|
||||
/*
|
||||
* Extract statement arguments
|
||||
*/
|
||||
@ -8649,6 +8725,29 @@ AlterSystemSetConfigFile(AlterSystemStmt *altersysstmt)
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check permission to run ALTER SYSTEM on the target variable
|
||||
*/
|
||||
if (!superuser())
|
||||
{
|
||||
if (resetall)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
errmsg("permission denied to perform ALTER SYSTEM RESET ALL")));
|
||||
else
|
||||
{
|
||||
AclResult aclresult;
|
||||
|
||||
aclresult = pg_parameter_aclcheck(name, GetUserId(),
|
||||
ACL_ALTER_SYSTEM);
|
||||
if (aclresult != ACLCHECK_OK)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
errmsg("permission denied to set parameter \"%s\"",
|
||||
name)));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Unless it's RESET_ALL, validate the target variable and value
|
||||
*/
|
||||
@ -8760,13 +8859,18 @@ AlterSystemSetConfigFile(AlterSystemStmt *altersysstmt)
|
||||
}
|
||||
|
||||
/*
|
||||
* Invoke the post-alter hook for altering this GUC variable.
|
||||
* Invoke the post-alter hook for setting this GUC variable. GUCs
|
||||
* typically do not have corresponding entries in pg_parameter_acl, so we
|
||||
* call the hook using the name rather than a potentially-non-existent
|
||||
* OID. Nonetheless, we pass ParameterAclRelationId so that this call
|
||||
* context can be distinguished from others. (Note that "name" will be
|
||||
* NULL in the RESET ALL case.)
|
||||
*
|
||||
* We do this here rather than at the end, because ALTER SYSTEM is not
|
||||
* transactional. If the hook aborts our transaction, it will be cleaner
|
||||
* to do so before we touch any files.
|
||||
*/
|
||||
InvokeObjectPostAlterHookArgStr(InvalidOid, name,
|
||||
InvokeObjectPostAlterHookArgStr(ParameterAclRelationId, name,
|
||||
ACL_ALTER_SYSTEM,
|
||||
altersysstmt->setstmt->kind,
|
||||
false);
|
||||
@ -8943,9 +9047,9 @@ ExecSetVariableStmt(VariableSetStmt *stmt, bool isTopLevel)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Invoke the post-alter hook for setting this GUC variable. */
|
||||
InvokeObjectPostAlterHookArgStr(InvalidOid, stmt->name,
|
||||
ACL_SET_VALUE, stmt->kind, false);
|
||||
/* Invoke the post-alter hook for setting this GUC variable, by name. */
|
||||
InvokeObjectPostAlterHookArgStr(ParameterAclRelationId, stmt->name,
|
||||
ACL_SET, stmt->kind, false);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -37,7 +37,7 @@ static void AddAcl(PQExpBuffer aclbuf, const char *keyword,
|
||||
* nspname: the namespace the object is in (NULL if none); not pre-quoted
|
||||
* type: the object type (as seen in GRANT command: must be one of
|
||||
* TABLE, SEQUENCE, FUNCTION, PROCEDURE, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
|
||||
* FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT)
|
||||
* FOREIGN DATA WRAPPER, SERVER, PARAMETER or LARGE OBJECT)
|
||||
* acls: the ACL string fetched from the database
|
||||
* baseacls: the initial ACL string for this object
|
||||
* owner: username of object owner (will be passed through fmtId); can be
|
||||
@ -501,6 +501,11 @@ do { \
|
||||
CONVERT_PRIV('U', "USAGE");
|
||||
else if (strcmp(type, "FOREIGN TABLE") == 0)
|
||||
CONVERT_PRIV('r', "SELECT");
|
||||
else if (strcmp(type, "PARAMETER") == 0)
|
||||
{
|
||||
CONVERT_PRIV('s', "SET");
|
||||
CONVERT_PRIV('A', "ALTER SYSTEM");
|
||||
}
|
||||
else if (strcmp(type, "LARGE OBJECT") == 0)
|
||||
{
|
||||
CONVERT_PRIV('r', "SELECT");
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "catalog/pg_authid_d.h"
|
||||
#include "common/connect.h"
|
||||
#include "common/file_utils.h"
|
||||
#include "common/logging.h"
|
||||
@ -36,6 +37,7 @@ static void help(void);
|
||||
static void dropRoles(PGconn *conn);
|
||||
static void dumpRoles(PGconn *conn);
|
||||
static void dumpRoleMembership(PGconn *conn);
|
||||
static void dumpRoleGUCPrivs(PGconn *conn);
|
||||
static void dropTablespaces(PGconn *conn);
|
||||
static void dumpTablespaces(PGconn *conn);
|
||||
static void dropDBs(PGconn *conn);
|
||||
@ -585,6 +587,10 @@ main(int argc, char *argv[])
|
||||
|
||||
/* Dump role memberships */
|
||||
dumpRoleMembership(conn);
|
||||
|
||||
/* Dump role GUC privileges */
|
||||
if (server_version >= 150000 && !skip_acls)
|
||||
dumpRoleGUCPrivs(conn);
|
||||
}
|
||||
|
||||
/* Dump tablespaces */
|
||||
@ -989,6 +995,65 @@ dumpRoleMembership(PGconn *conn)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Dump role configuration parameter privileges. This code is used for 15.0
|
||||
* and later servers.
|
||||
*
|
||||
* Note: we expect dumpRoles already created all the roles, but there are
|
||||
* no per-role configuration parameter privileges yet.
|
||||
*/
|
||||
static void
|
||||
dumpRoleGUCPrivs(PGconn *conn)
|
||||
{
|
||||
PGresult *res;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Get all parameters that have non-default acls defined.
|
||||
*/
|
||||
res = executeQuery(conn, "SELECT parname, "
|
||||
"pg_catalog.pg_get_userbyid(" CppAsString2(BOOTSTRAP_SUPERUSERID) ") AS parowner, "
|
||||
"paracl, "
|
||||
"pg_catalog.acldefault('p', " CppAsString2(BOOTSTRAP_SUPERUSERID) ") AS acldefault "
|
||||
"FROM pg_catalog.pg_parameter_acl "
|
||||
"ORDER BY 1");
|
||||
|
||||
if (PQntuples(res) > 0)
|
||||
fprintf(OPF, "--\n-- Role privileges on configuration parameters\n--\n\n");
|
||||
|
||||
for (i = 0; i < PQntuples(res); i++)
|
||||
{
|
||||
PQExpBuffer buf = createPQExpBuffer();
|
||||
char *parname = PQgetvalue(res, i, 0);
|
||||
char *parowner = PQgetvalue(res, i, 1);
|
||||
char *paracl = PQgetvalue(res, i, 2);
|
||||
char *acldefault = PQgetvalue(res, i, 3);
|
||||
char *fparname;
|
||||
|
||||
/* needed for buildACLCommands() */
|
||||
fparname = pg_strdup(fmtId(parname));
|
||||
|
||||
if (!buildACLCommands(fparname, NULL, NULL, "PARAMETER",
|
||||
paracl, acldefault,
|
||||
parowner, "", server_version, buf))
|
||||
{
|
||||
pg_log_error("could not parse ACL list (%s) for parameter \"%s\"",
|
||||
paracl, parname);
|
||||
PQfinish(conn);
|
||||
exit_nicely(1);
|
||||
}
|
||||
|
||||
fprintf(OPF, "%s", buf->data);
|
||||
|
||||
free(fparname);
|
||||
destroyPQExpBuffer(buf);
|
||||
}
|
||||
|
||||
PQclear(res);
|
||||
fprintf(OPF, "\n\n");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Drop tablespaces.
|
||||
*/
|
||||
|
@ -3737,7 +3737,8 @@ psql_completion(const char *text, int start, int end)
|
||||
* ALTER DEFAULT PRIVILEGES, so use TailMatches
|
||||
*/
|
||||
/* Complete GRANT/REVOKE with a list of roles and privileges */
|
||||
else if (TailMatches("GRANT|REVOKE"))
|
||||
else if (TailMatches("GRANT|REVOKE") ||
|
||||
TailMatches("REVOKE", "GRANT", "OPTION", "FOR"))
|
||||
{
|
||||
/*
|
||||
* With ALTER DEFAULT PRIVILEGES, restrict completion to grantable
|
||||
@ -3749,6 +3750,7 @@ psql_completion(const char *text, int start, int end)
|
||||
"EXECUTE", "USAGE", "ALL");
|
||||
else
|
||||
COMPLETE_WITH_QUERY_PLUS(Query_for_list_of_roles,
|
||||
"GRANT",
|
||||
"SELECT",
|
||||
"INSERT",
|
||||
"UPDATE",
|
||||
@ -3761,14 +3763,48 @@ psql_completion(const char *text, int start, int end)
|
||||
"TEMPORARY",
|
||||
"EXECUTE",
|
||||
"USAGE",
|
||||
"SET",
|
||||
"ALTER SYSTEM",
|
||||
"ALL");
|
||||
}
|
||||
|
||||
else if (TailMatches("REVOKE", "GRANT"))
|
||||
COMPLETE_WITH("OPTION FOR");
|
||||
else if (TailMatches("REVOKE", "GRANT", "OPTION"))
|
||||
COMPLETE_WITH("FOR");
|
||||
|
||||
else if (TailMatches("GRANT|REVOKE", "ALTER") ||
|
||||
TailMatches("REVOKE", "GRANT", "OPTION", "FOR", "ALTER"))
|
||||
COMPLETE_WITH("SYSTEM");
|
||||
|
||||
else if (TailMatches("GRANT|REVOKE", "SET") ||
|
||||
TailMatches("REVOKE", "GRANT", "OPTION", "FOR", "SET") ||
|
||||
TailMatches("GRANT|REVOKE", "ALTER", "SYSTEM") ||
|
||||
TailMatches("REVOKE", "GRANT", "OPTION", "FOR", "ALTER", "SYSTEM"))
|
||||
COMPLETE_WITH("ON PARAMETER");
|
||||
|
||||
else if (TailMatches("GRANT|REVOKE", MatchAny, "ON", "PARAMETER") ||
|
||||
TailMatches("GRANT|REVOKE", MatchAny, MatchAny, "ON", "PARAMETER") ||
|
||||
TailMatches("REVOKE", "GRANT", "OPTION", "FOR", MatchAny, "ON", "PARAMETER") ||
|
||||
TailMatches("REVOKE", "GRANT", "OPTION", "FOR", MatchAny, MatchAny, "ON", "PARAMETER"))
|
||||
COMPLETE_WITH_QUERY(Query_for_list_of_alter_system_set_vars);
|
||||
|
||||
else if (TailMatches("GRANT", MatchAny, "ON", "PARAMETER", MatchAny) ||
|
||||
TailMatches("GRANT", MatchAny, MatchAny, "ON", "PARAMETER", MatchAny))
|
||||
COMPLETE_WITH("TO");
|
||||
|
||||
else if (TailMatches("REVOKE", MatchAny, "ON", "PARAMETER", MatchAny) ||
|
||||
TailMatches("REVOKE", MatchAny, MatchAny, "ON", "PARAMETER", MatchAny) ||
|
||||
TailMatches("REVOKE", "GRANT", "OPTION", "FOR", MatchAny, "ON", "PARAMETER", MatchAny) ||
|
||||
TailMatches("REVOKE", "GRANT", "OPTION", "FOR", MatchAny, MatchAny, "ON", "PARAMETER", MatchAny))
|
||||
COMPLETE_WITH("FROM");
|
||||
|
||||
/*
|
||||
* Complete GRANT/REVOKE <privilege> with "ON", GRANT/REVOKE <role> with
|
||||
* TO/FROM
|
||||
*/
|
||||
else if (TailMatches("GRANT|REVOKE", MatchAny))
|
||||
else if (TailMatches("GRANT|REVOKE", MatchAny) ||
|
||||
TailMatches("REVOKE", "GRANT", "OPTION", "FOR", MatchAny))
|
||||
{
|
||||
if (TailMatches("SELECT|INSERT|UPDATE|DELETE|TRUNCATE|REFERENCES|TRIGGER|CREATE|CONNECT|TEMPORARY|TEMP|EXECUTE|USAGE|ALL"))
|
||||
COMPLETE_WITH("ON");
|
||||
@ -3785,7 +3821,8 @@ psql_completion(const char *text, int start, int end)
|
||||
* here will only work if the privilege list contains exactly one
|
||||
* privilege.
|
||||
*/
|
||||
else if (TailMatches("GRANT|REVOKE", MatchAny, "ON"))
|
||||
else if (TailMatches("GRANT|REVOKE", MatchAny, "ON") ||
|
||||
TailMatches("REVOKE", "GRANT", "OPTION", "FOR", MatchAny, "ON"))
|
||||
{
|
||||
/*
|
||||
* With ALTER DEFAULT PRIVILEGES, restrict completion to the kinds of
|
||||
@ -3807,6 +3844,7 @@ psql_completion(const char *text, int start, int end)
|
||||
"FUNCTION",
|
||||
"LANGUAGE",
|
||||
"LARGE OBJECT",
|
||||
"PARAMETER",
|
||||
"PROCEDURE",
|
||||
"ROUTINE",
|
||||
"SCHEMA",
|
||||
@ -3815,13 +3853,15 @@ psql_completion(const char *text, int start, int end)
|
||||
"TABLESPACE",
|
||||
"TYPE");
|
||||
}
|
||||
else if (TailMatches("GRANT|REVOKE", MatchAny, "ON", "ALL"))
|
||||
else if (TailMatches("GRANT|REVOKE", MatchAny, "ON", "ALL") ||
|
||||
TailMatches("REVOKE", "GRANT", "OPTION", "FOR", MatchAny, "ON", "ALL"))
|
||||
COMPLETE_WITH("FUNCTIONS IN SCHEMA",
|
||||
"PROCEDURES IN SCHEMA",
|
||||
"ROUTINES IN SCHEMA",
|
||||
"SEQUENCES IN SCHEMA",
|
||||
"TABLES IN SCHEMA");
|
||||
else if (TailMatches("GRANT|REVOKE", MatchAny, "ON", "FOREIGN"))
|
||||
else if (TailMatches("GRANT|REVOKE", MatchAny, "ON", "FOREIGN") ||
|
||||
TailMatches("REVOKE", "GRANT", "OPTION", "FOR", MatchAny, "ON", "FOREIGN"))
|
||||
COMPLETE_WITH("DATA WRAPPER", "SERVER");
|
||||
|
||||
/*
|
||||
@ -3830,7 +3870,8 @@ psql_completion(const char *text, int start, int end)
|
||||
*
|
||||
* Complete "GRANT/REVOKE * ON *" with "TO/FROM".
|
||||
*/
|
||||
else if (TailMatches("GRANT|REVOKE", MatchAny, "ON", MatchAny))
|
||||
else if (TailMatches("GRANT|REVOKE", MatchAny, "ON", MatchAny) ||
|
||||
TailMatches("REVOKE", "GRANT", "OPTION", "FOR", MatchAny, "ON", MatchAny))
|
||||
{
|
||||
if (TailMatches("DATABASE"))
|
||||
COMPLETE_WITH_QUERY(Query_for_list_of_databases);
|
||||
@ -3868,6 +3909,22 @@ psql_completion(const char *text, int start, int end)
|
||||
(HeadMatches("REVOKE") && TailMatches("FROM")))
|
||||
COMPLETE_WITH_QUERY_PLUS(Query_for_list_of_roles,
|
||||
Keywords_for_list_of_grant_roles);
|
||||
|
||||
/*
|
||||
* Offer grant options after that.
|
||||
*/
|
||||
else if (HeadMatches("GRANT") && TailMatches("TO", MatchAny))
|
||||
COMPLETE_WITH("WITH ADMIN OPTION",
|
||||
"WITH GRANT OPTION",
|
||||
"GRANTED BY");
|
||||
else if (HeadMatches("GRANT") && TailMatches("TO", MatchAny, "WITH"))
|
||||
COMPLETE_WITH("ADMIN OPTION",
|
||||
"GRANT OPTION");
|
||||
else if (HeadMatches("GRANT") && TailMatches("TO", MatchAny, "WITH", MatchAny, "OPTION"))
|
||||
COMPLETE_WITH("GRANTED BY");
|
||||
else if (HeadMatches("GRANT") && TailMatches("TO", MatchAny, "WITH", MatchAny, "OPTION", "GRANTED", "BY"))
|
||||
COMPLETE_WITH_QUERY_PLUS(Query_for_list_of_roles,
|
||||
Keywords_for_list_of_grant_roles);
|
||||
/* Complete "ALTER DEFAULT PRIVILEGES ... GRANT/REVOKE ... TO/FROM */
|
||||
else if (HeadMatches("ALTER", "DEFAULT", "PRIVILEGES") && TailMatches("TO|FROM"))
|
||||
COMPLETE_WITH_QUERY_PLUS(Query_for_list_of_roles,
|
||||
@ -3879,7 +3936,8 @@ psql_completion(const char *text, int start, int end)
|
||||
COMPLETE_WITH("FROM");
|
||||
|
||||
/* Complete "GRANT/REVOKE * ON ALL * IN SCHEMA *" with TO/FROM */
|
||||
else if (TailMatches("GRANT|REVOKE", MatchAny, "ON", "ALL", MatchAny, "IN", "SCHEMA", MatchAny))
|
||||
else if (TailMatches("GRANT|REVOKE", MatchAny, "ON", "ALL", MatchAny, "IN", "SCHEMA", MatchAny) ||
|
||||
TailMatches("REVOKE", "GRANT", "OPTION", "FOR", MatchAny, "ON", "ALL", MatchAny, "IN", "SCHEMA", MatchAny))
|
||||
{
|
||||
if (TailMatches("GRANT", MatchAny, MatchAny, MatchAny, MatchAny, MatchAny, MatchAny, MatchAny))
|
||||
COMPLETE_WITH("TO");
|
||||
@ -3888,7 +3946,8 @@ psql_completion(const char *text, int start, int end)
|
||||
}
|
||||
|
||||
/* Complete "GRANT/REVOKE * ON FOREIGN DATA WRAPPER *" with TO/FROM */
|
||||
else if (TailMatches("GRANT|REVOKE", MatchAny, "ON", "FOREIGN", "DATA", "WRAPPER", MatchAny))
|
||||
else if (TailMatches("GRANT|REVOKE", MatchAny, "ON", "FOREIGN", "DATA", "WRAPPER", MatchAny) ||
|
||||
TailMatches("REVOKE", "GRANT", "OPTION", "FOR", MatchAny, "ON", "FOREIGN", "DATA", "WRAPPER", MatchAny))
|
||||
{
|
||||
if (TailMatches("GRANT", MatchAny, MatchAny, MatchAny, MatchAny, MatchAny, MatchAny))
|
||||
COMPLETE_WITH("TO");
|
||||
@ -3897,7 +3956,8 @@ psql_completion(const char *text, int start, int end)
|
||||
}
|
||||
|
||||
/* Complete "GRANT/REVOKE * ON FOREIGN SERVER *" with TO/FROM */
|
||||
else if (TailMatches("GRANT|REVOKE", MatchAny, "ON", "FOREIGN", "SERVER", MatchAny))
|
||||
else if (TailMatches("GRANT|REVOKE", MatchAny, "ON", "FOREIGN", "SERVER", MatchAny) ||
|
||||
TailMatches("REVOKE", "GRANT", "OPTION", "FOR", MatchAny, "ON", "FOREIGN", "SERVER", MatchAny))
|
||||
{
|
||||
if (TailMatches("GRANT", MatchAny, MatchAny, MatchAny, MatchAny, MatchAny))
|
||||
COMPLETE_WITH("TO");
|
||||
|
@ -53,6 +53,6 @@
|
||||
*/
|
||||
|
||||
/* yyyymmddN */
|
||||
#define CATALOG_VERSION_NO 202203301
|
||||
#define CATALOG_VERSION_NO 202204061
|
||||
|
||||
#endif
|
||||
|
@ -120,6 +120,7 @@ typedef enum ObjectClass
|
||||
OCLASS_DEFACL, /* pg_default_acl */
|
||||
OCLASS_EXTENSION, /* pg_extension */
|
||||
OCLASS_EVENT_TRIGGER, /* pg_event_trigger */
|
||||
OCLASS_PARAMETER_ACL, /* pg_parameter_acl */
|
||||
OCLASS_POLICY, /* pg_policy */
|
||||
OCLASS_PUBLICATION, /* pg_publication */
|
||||
OCLASS_PUBLICATION_NAMESPACE, /* pg_publication_namespace */
|
||||
|
@ -239,7 +239,7 @@ extern void RunFunctionExecuteHookStr(const char *objectStr);
|
||||
RunObjectTruncateHookStr(objectName); \
|
||||
} while(0)
|
||||
|
||||
#define InvokeObjectPostAlterHookStr(className,objectName,subId) \
|
||||
#define InvokeObjectPostAlterHookStr(classId,objectName,subId) \
|
||||
InvokeObjectPostAlterHookArgStr((classId),(objectName),(subId), \
|
||||
InvalidOid,false)
|
||||
#define InvokeObjectPostAlterHookArgStr(classId,objectName,subId, \
|
||||
|
62
src/include/catalog/pg_parameter_acl.h
Normal file
62
src/include/catalog/pg_parameter_acl.h
Normal file
@ -0,0 +1,62 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* pg_parameter_acl.h
|
||||
* definition of the "configuration parameter ACL" system catalog
|
||||
* (pg_parameter_acl).
|
||||
*
|
||||
*
|
||||
* Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* src/include/catalog/pg_parameter_acl.h
|
||||
*
|
||||
* NOTES
|
||||
* The Catalog.pm module reads this file and derives schema
|
||||
* information.
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef PG_PARAMETER_ACL_H
|
||||
#define PG_PARAMETER_ACL_H
|
||||
|
||||
#include "catalog/genbki.h"
|
||||
#include "catalog/pg_parameter_acl_d.h"
|
||||
|
||||
/* ----------------
|
||||
* pg_parameter_acl definition. cpp turns this into
|
||||
* typedef struct FormData_pg_parameter_acl
|
||||
* ----------------
|
||||
*/
|
||||
CATALOG(pg_parameter_acl,8924,ParameterAclRelationId) BKI_SHARED_RELATION
|
||||
{
|
||||
Oid oid; /* oid */
|
||||
|
||||
#ifdef CATALOG_VARLEN /* variable-length fields start here */
|
||||
/* name of parameter */
|
||||
text parname BKI_FORCE_NOT_NULL;
|
||||
|
||||
/* access permissions */
|
||||
aclitem paracl[1] BKI_DEFAULT(_null_);
|
||||
#endif
|
||||
} FormData_pg_parameter_acl;
|
||||
|
||||
|
||||
/* ----------------
|
||||
* Form_pg_parameter_acl corresponds to a pointer to a tuple with
|
||||
* the format of pg_parameter_acl relation.
|
||||
* ----------------
|
||||
*/
|
||||
typedef FormData_pg_parameter_acl *Form_pg_parameter_acl;
|
||||
|
||||
DECLARE_TOAST(pg_parameter_acl, 8925, 8926);
|
||||
#define PgParameterAclToastTable 8925
|
||||
#define PgParameterAclToastIndex 8926
|
||||
|
||||
DECLARE_UNIQUE_INDEX(pg_parameter_acl_parname_index, 8927, ParameterAclParnameIndexId, on pg_parameter_acl using btree(parname text_ops));
|
||||
DECLARE_UNIQUE_INDEX_PKEY(pg_parameter_acl_oid_index, 8928, ParameterAclOidIndexId, on pg_parameter_acl using btree(oid oid_ops));
|
||||
|
||||
|
||||
extern Oid ParameterAclLookup(const char *parameter, bool missing_ok);
|
||||
extern Oid ParameterAclCreate(const char *parameter);
|
||||
|
||||
#endif /* PG_PARAMETER_ACL_H */
|
@ -7213,6 +7213,22 @@
|
||||
proname => 'has_type_privilege', provolatile => 's', prorettype => 'bool',
|
||||
proargtypes => 'oid text', prosrc => 'has_type_privilege_id' },
|
||||
|
||||
{ oid => '8050',
|
||||
descr => 'user privilege on parameter by username, parameter name',
|
||||
proname => 'has_parameter_privilege', provolatile => 's',
|
||||
prorettype => 'bool', proargtypes => 'name text text',
|
||||
prosrc => 'has_parameter_privilege_name_name' },
|
||||
{ oid => '8051',
|
||||
descr => 'user privilege on parameter by user oid, parameter name',
|
||||
proname => 'has_parameter_privilege', provolatile => 's',
|
||||
prorettype => 'bool', proargtypes => 'oid text text',
|
||||
prosrc => 'has_parameter_privilege_id_name' },
|
||||
{ oid => '8052',
|
||||
descr => 'current user privilege on parameter by parameter name',
|
||||
proname => 'has_parameter_privilege', provolatile => 's',
|
||||
prorettype => 'bool', proargtypes => 'text text',
|
||||
prosrc => 'has_parameter_privilege_name' },
|
||||
|
||||
{ oid => '2705', descr => 'user privilege on role by username, role name',
|
||||
proname => 'pg_has_role', provolatile => 's', prorettype => 'bool',
|
||||
proargtypes => 'name name text', prosrc => 'pg_has_role_name_name' },
|
||||
|
@ -92,8 +92,8 @@ typedef uint32 AclMode; /* a bitmask of privilege bits */
|
||||
#define ACL_CREATE (1<<9) /* for namespaces and databases */
|
||||
#define ACL_CREATE_TEMP (1<<10) /* for databases */
|
||||
#define ACL_CONNECT (1<<11) /* for databases */
|
||||
#define ACL_SET_VALUE (1<<12) /* for configuration parameters */
|
||||
#define ACL_ALTER_SYSTEM (1<<13) /* for configuration parameters */
|
||||
#define ACL_SET (1<<12) /* for configuration parameters */
|
||||
#define ACL_ALTER_SYSTEM (1<<13) /* for configuration parameters */
|
||||
#define N_ACL_RIGHTS 14 /* 1 plus the last 1<<x */
|
||||
#define ACL_NO_RIGHTS 0
|
||||
/* Currently, SELECT ... FOR [KEY] UPDATE/SHARE requires UPDATE privileges */
|
||||
@ -2162,6 +2162,7 @@ typedef enum ObjectType
|
||||
OBJECT_OPCLASS,
|
||||
OBJECT_OPERATOR,
|
||||
OBJECT_OPFAMILY,
|
||||
OBJECT_PARAMETER_ACL,
|
||||
OBJECT_POLICY,
|
||||
OBJECT_PROCEDURE,
|
||||
OBJECT_PUBLICATION,
|
||||
|
@ -329,6 +329,7 @@ PG_KEYWORD("overriding", OVERRIDING, UNRESERVED_KEYWORD, BARE_LABEL)
|
||||
PG_KEYWORD("owned", OWNED, UNRESERVED_KEYWORD, BARE_LABEL)
|
||||
PG_KEYWORD("owner", OWNER, UNRESERVED_KEYWORD, BARE_LABEL)
|
||||
PG_KEYWORD("parallel", PARALLEL, UNRESERVED_KEYWORD, BARE_LABEL)
|
||||
PG_KEYWORD("parameter", PARAMETER, UNRESERVED_KEYWORD, BARE_LABEL)
|
||||
PG_KEYWORD("parser", PARSER, UNRESERVED_KEYWORD, BARE_LABEL)
|
||||
PG_KEYWORD("partial", PARTIAL, UNRESERVED_KEYWORD, BARE_LABEL)
|
||||
PG_KEYWORD("partition", PARTITION, UNRESERVED_KEYWORD, BARE_LABEL)
|
||||
|
@ -146,7 +146,7 @@ typedef struct ArrayType Acl;
|
||||
#define ACL_CREATE_CHR 'C'
|
||||
#define ACL_CREATE_TEMP_CHR 'T'
|
||||
#define ACL_CONNECT_CHR 'c'
|
||||
#define ACL_SET_VALUE_CHR 's'
|
||||
#define ACL_SET_CHR 's'
|
||||
#define ACL_ALTER_SYSTEM_CHR 'A'
|
||||
|
||||
/* string holding all privilege code chars, in order by bitmask position */
|
||||
@ -164,6 +164,7 @@ typedef struct ArrayType Acl;
|
||||
#define ACL_ALL_RIGHTS_FUNCTION (ACL_EXECUTE)
|
||||
#define ACL_ALL_RIGHTS_LANGUAGE (ACL_USAGE)
|
||||
#define ACL_ALL_RIGHTS_LARGEOBJECT (ACL_SELECT|ACL_UPDATE)
|
||||
#define ACL_ALL_RIGHTS_PARAMETER_ACL (ACL_SET|ACL_ALTER_SYSTEM)
|
||||
#define ACL_ALL_RIGHTS_SCHEMA (ACL_USAGE|ACL_CREATE)
|
||||
#define ACL_ALL_RIGHTS_TABLESPACE (ACL_CREATE)
|
||||
#define ACL_ALL_RIGHTS_TYPE (ACL_USAGE)
|
||||
@ -245,6 +246,10 @@ extern AclMode pg_class_aclmask_ext(Oid table_oid, Oid roleid,
|
||||
bool *is_missing);
|
||||
extern AclMode pg_database_aclmask(Oid db_oid, Oid roleid,
|
||||
AclMode mask, AclMaskHow how);
|
||||
extern AclMode pg_parameter_aclmask(const char *name, Oid roleid,
|
||||
AclMode mask, AclMaskHow how);
|
||||
extern AclMode pg_parameter_acl_aclmask(Oid acl_oid, Oid roleid,
|
||||
AclMode mask, AclMaskHow how);
|
||||
extern AclMode pg_proc_aclmask(Oid proc_oid, Oid roleid,
|
||||
AclMode mask, AclMaskHow how);
|
||||
extern AclMode pg_language_aclmask(Oid lang_oid, Oid roleid,
|
||||
@ -273,6 +278,10 @@ extern AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode);
|
||||
extern AclResult pg_class_aclcheck_ext(Oid table_oid, Oid roleid,
|
||||
AclMode mode, bool *is_missing);
|
||||
extern AclResult pg_database_aclcheck(Oid db_oid, Oid roleid, AclMode mode);
|
||||
extern AclResult pg_parameter_aclcheck(const char *name, Oid roleid,
|
||||
AclMode mode);
|
||||
extern AclResult pg_parameter_acl_aclcheck(Oid acl_oid, Oid roleid,
|
||||
AclMode mode);
|
||||
extern AclResult pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode);
|
||||
extern AclResult pg_language_aclcheck(Oid lang_oid, Oid roleid, AclMode mode);
|
||||
extern AclResult pg_largeobject_aclcheck_snapshot(Oid lang_oid, Oid roleid,
|
||||
|
@ -364,6 +364,8 @@ extern const char *GetConfigOption(const char *name, bool missing_ok,
|
||||
extern const char *GetConfigOptionResetString(const char *name);
|
||||
extern int GetConfigOptionFlags(const char *name, bool missing_ok);
|
||||
extern void ProcessConfigFile(GucContext context);
|
||||
extern char *convert_GUC_name_for_parameter_acl(const char *name);
|
||||
extern bool check_GUC_name_for_parameter_acl(const char *name);
|
||||
extern void InitializeGUCOptions(void);
|
||||
extern bool SelectConfigFiles(const char *userDoption, const char *progname);
|
||||
extern void ResetAllOptions(void);
|
||||
|
@ -72,6 +72,8 @@ enum SysCacheIdentifier
|
||||
OPEROID,
|
||||
OPFAMILYAMNAMENSP,
|
||||
OPFAMILYOID,
|
||||
PARAMETERACLNAME,
|
||||
PARAMETERACLOID,
|
||||
PARTRELID,
|
||||
PROCNAMEARGSNSP,
|
||||
PROCOID,
|
||||
|
@ -1,36 +1,84 @@
|
||||
-- Creating privileges on a placeholder GUC should create entries in the
|
||||
-- pg_parameter_acl catalog which conservatively grant no privileges to public.
|
||||
CREATE ROLE regress_role_joe;
|
||||
GRANT SET ON PARAMETER test_oat_hooks.user_var1 TO regress_role_joe;
|
||||
GRANT SET ON PARAMETER test_oat_hooks.super_var1 TO regress_role_joe;
|
||||
-- SET commands fire both the ProcessUtility_hook and the
|
||||
-- object_access_hook_str. Since the auditing GUC starts out false, we miss the
|
||||
-- initial "attempting" audit message from the ProcessUtility_hook, but we
|
||||
-- should thereafter see the audit messages
|
||||
-- should thereafter see the audit messages.
|
||||
LOAD 'test_oat_hooks';
|
||||
SET test_oat_hooks.audit = true;
|
||||
NOTICE: in object_access_hook_str: superuser attempting alter (set) [test_oat_hooks.audit]
|
||||
NOTICE: in object_access_hook_str: superuser finished alter (set) [test_oat_hooks.audit]
|
||||
NOTICE: in object_access_hook_str: superuser attempting alter (subId=0x1000, set) [test_oat_hooks.audit]
|
||||
NOTICE: in object_access_hook_str: superuser finished alter (subId=0x1000, set) [test_oat_hooks.audit]
|
||||
NOTICE: in process utility: superuser finished set
|
||||
-- Creating privileges on an existent custom GUC should create precisely the
|
||||
-- right privileges, not overly conservative ones.
|
||||
GRANT SET ON PARAMETER test_oat_hooks.user_var2 TO regress_role_joe;
|
||||
NOTICE: in process utility: superuser attempting GrantStmt
|
||||
NOTICE: in process utility: superuser finished GrantStmt
|
||||
GRANT SET ON PARAMETER test_oat_hooks.super_var2 TO regress_role_joe;
|
||||
NOTICE: in process utility: superuser attempting GrantStmt
|
||||
NOTICE: in process utility: superuser finished GrantStmt
|
||||
-- Granting multiple privileges on a parameter should be reported correctly to
|
||||
-- the OAT hook, but beware that WITH GRANT OPTION is not represented.
|
||||
GRANT SET, ALTER SYSTEM ON PARAMETER none.such TO regress_role_joe;
|
||||
NOTICE: in process utility: superuser attempting GrantStmt
|
||||
NOTICE: in process utility: superuser finished GrantStmt
|
||||
GRANT SET, ALTER SYSTEM ON PARAMETER another.bogus TO regress_role_joe WITH GRANT OPTION;
|
||||
NOTICE: in process utility: superuser attempting GrantStmt
|
||||
NOTICE: in process utility: superuser finished GrantStmt
|
||||
-- Check when the hooks fire relative to dependency based abort of a drop
|
||||
DROP ROLE regress_role_joe;
|
||||
NOTICE: in process utility: superuser attempting DropRoleStmt
|
||||
NOTICE: in object access: superuser attempting drop (subId=0x0) []
|
||||
NOTICE: in object access: superuser finished drop (subId=0x0) []
|
||||
ERROR: role "regress_role_joe" cannot be dropped because some objects depend on it
|
||||
DETAIL: privileges for parameter test_oat_hooks.user_var1
|
||||
privileges for parameter test_oat_hooks.super_var1
|
||||
privileges for parameter test_oat_hooks.user_var2
|
||||
privileges for parameter test_oat_hooks.super_var2
|
||||
privileges for parameter none.such
|
||||
privileges for parameter another.bogus
|
||||
-- Check the behavior of the hooks relative to do-nothing grants and revokes
|
||||
GRANT SET ON PARAMETER work_mem TO PUBLIC;
|
||||
NOTICE: in process utility: superuser attempting GrantStmt
|
||||
NOTICE: in process utility: superuser finished GrantStmt
|
||||
REVOKE ALTER SYSTEM ON PARAMETER work_mem FROM PUBLIC;
|
||||
NOTICE: in process utility: superuser attempting GrantStmt
|
||||
NOTICE: in process utility: superuser finished GrantStmt
|
||||
-- Check the behavior of the hooks relative to unrecognized parameters
|
||||
GRANT ALL ON PARAMETER "none.such" TO PUBLIC;
|
||||
NOTICE: in process utility: superuser attempting GrantStmt
|
||||
NOTICE: in process utility: superuser finished GrantStmt
|
||||
-- Check relative to an operation that causes the catalog entry to be deleted
|
||||
REVOKE ALL ON PARAMETER "none.such" FROM PUBLIC;
|
||||
NOTICE: in process utility: superuser attempting GrantStmt
|
||||
NOTICE: in process utility: superuser finished GrantStmt
|
||||
-- Create objects for use in the test
|
||||
CREATE USER regress_test_user;
|
||||
NOTICE: in process utility: superuser attempting CreateRoleStmt
|
||||
NOTICE: in object access: superuser attempting create (subId=0) [explicit]
|
||||
NOTICE: in object access: superuser finished create (subId=0) [explicit]
|
||||
NOTICE: in object access: superuser attempting create (subId=0x0) [explicit]
|
||||
NOTICE: in object access: superuser finished create (subId=0x0) [explicit]
|
||||
NOTICE: in process utility: superuser finished CreateRoleStmt
|
||||
CREATE TABLE regress_test_table (t text);
|
||||
NOTICE: in process utility: superuser attempting CreateStmt
|
||||
NOTICE: in object access: superuser attempting namespace search (subId=0) [no report on violation, allowed]
|
||||
NOTICE: in object access: superuser attempting namespace search (subId=0x0) [no report on violation, allowed]
|
||||
LINE 1: CREATE TABLE regress_test_table (t text);
|
||||
^
|
||||
NOTICE: in object access: superuser finished namespace search (subId=0) [no report on violation, allowed]
|
||||
NOTICE: in object access: superuser finished namespace search (subId=0x0) [no report on violation, allowed]
|
||||
LINE 1: CREATE TABLE regress_test_table (t text);
|
||||
^
|
||||
NOTICE: in object access: superuser attempting create (subId=0) [explicit]
|
||||
NOTICE: in object access: superuser finished create (subId=0) [explicit]
|
||||
NOTICE: in object access: superuser attempting create (subId=0) [explicit]
|
||||
NOTICE: in object access: superuser finished create (subId=0) [explicit]
|
||||
NOTICE: in object access: superuser attempting create (subId=0) [explicit]
|
||||
NOTICE: in object access: superuser finished create (subId=0) [explicit]
|
||||
NOTICE: in object access: superuser attempting create (subId=0) [internal]
|
||||
NOTICE: in object access: superuser finished create (subId=0) [internal]
|
||||
NOTICE: in object access: superuser attempting create (subId=0) [internal]
|
||||
NOTICE: in object access: superuser finished create (subId=0) [internal]
|
||||
NOTICE: in object access: superuser attempting create (subId=0x0) [explicit]
|
||||
NOTICE: in object access: superuser finished create (subId=0x0) [explicit]
|
||||
NOTICE: in object access: superuser attempting create (subId=0x0) [explicit]
|
||||
NOTICE: in object access: superuser finished create (subId=0x0) [explicit]
|
||||
NOTICE: in object access: superuser attempting create (subId=0x0) [explicit]
|
||||
NOTICE: in object access: superuser finished create (subId=0x0) [explicit]
|
||||
NOTICE: in object access: superuser attempting create (subId=0x0) [internal]
|
||||
NOTICE: in object access: superuser finished create (subId=0x0) [internal]
|
||||
NOTICE: in object access: superuser attempting create (subId=0x0) [internal]
|
||||
NOTICE: in object access: superuser finished create (subId=0x0) [internal]
|
||||
NOTICE: in process utility: superuser finished CreateStmt
|
||||
GRANT SELECT ON Table regress_test_table TO public;
|
||||
NOTICE: in process utility: superuser attempting GrantStmt
|
||||
@ -39,8 +87,8 @@ CREATE FUNCTION regress_test_func (t text) RETURNS text AS $$
|
||||
SELECT $1;
|
||||
$$ LANGUAGE sql;
|
||||
NOTICE: in process utility: superuser attempting CreateFunctionStmt
|
||||
NOTICE: in object access: superuser attempting create (subId=0) [explicit]
|
||||
NOTICE: in object access: superuser finished create (subId=0) [explicit]
|
||||
NOTICE: in object access: superuser attempting create (subId=0x0) [explicit]
|
||||
NOTICE: in object access: superuser finished create (subId=0x0) [explicit]
|
||||
NOTICE: in process utility: superuser finished CreateFunctionStmt
|
||||
GRANT EXECUTE ON FUNCTION regress_test_func (text) TO public;
|
||||
NOTICE: in process utility: superuser attempting GrantStmt
|
||||
@ -63,35 +111,35 @@ NOTICE: in executor check perms: superuser finished execute
|
||||
|
||||
SET work_mem = 8192;
|
||||
NOTICE: in process utility: superuser attempting set
|
||||
NOTICE: in object_access_hook_str: superuser attempting alter (set) [work_mem]
|
||||
NOTICE: in object_access_hook_str: superuser finished alter (set) [work_mem]
|
||||
NOTICE: in object_access_hook_str: superuser attempting alter (subId=0x1000, set) [work_mem]
|
||||
NOTICE: in object_access_hook_str: superuser finished alter (subId=0x1000, set) [work_mem]
|
||||
NOTICE: in process utility: superuser finished set
|
||||
RESET work_mem;
|
||||
NOTICE: in process utility: superuser attempting set
|
||||
NOTICE: in object_access_hook_str: superuser attempting alter (set) [work_mem]
|
||||
NOTICE: in object_access_hook_str: superuser finished alter (set) [work_mem]
|
||||
NOTICE: in object_access_hook_str: superuser attempting alter (subId=0x1000, set) [work_mem]
|
||||
NOTICE: in object_access_hook_str: superuser finished alter (subId=0x1000, set) [work_mem]
|
||||
NOTICE: in process utility: superuser finished set
|
||||
ALTER SYSTEM SET work_mem = 8192;
|
||||
NOTICE: in process utility: superuser attempting alter system
|
||||
NOTICE: in object_access_hook_str: superuser attempting alter (alter system set) [work_mem]
|
||||
NOTICE: in object_access_hook_str: superuser finished alter (alter system set) [work_mem]
|
||||
NOTICE: in object_access_hook_str: superuser attempting alter (subId=0x2000, alter system) [work_mem]
|
||||
NOTICE: in object_access_hook_str: superuser finished alter (subId=0x2000, alter system) [work_mem]
|
||||
NOTICE: in process utility: superuser finished alter system
|
||||
ALTER SYSTEM RESET work_mem;
|
||||
NOTICE: in process utility: superuser attempting alter system
|
||||
NOTICE: in object_access_hook_str: superuser attempting alter (alter system set) [work_mem]
|
||||
NOTICE: in object_access_hook_str: superuser finished alter (alter system set) [work_mem]
|
||||
NOTICE: in object_access_hook_str: superuser attempting alter (subId=0x2000, alter system) [work_mem]
|
||||
NOTICE: in object_access_hook_str: superuser finished alter (subId=0x2000, alter system) [work_mem]
|
||||
NOTICE: in process utility: superuser finished alter system
|
||||
-- Do those same things as non-superuser
|
||||
SET SESSION AUTHORIZATION regress_test_user;
|
||||
NOTICE: in process utility: superuser attempting set
|
||||
NOTICE: in object_access_hook_str: non-superuser attempting alter (set) [session_authorization]
|
||||
NOTICE: in object_access_hook_str: non-superuser finished alter (set) [session_authorization]
|
||||
NOTICE: in object_access_hook_str: non-superuser attempting alter (subId=0x1000, set) [session_authorization]
|
||||
NOTICE: in object_access_hook_str: non-superuser finished alter (subId=0x1000, set) [session_authorization]
|
||||
NOTICE: in process utility: non-superuser finished set
|
||||
SELECT * FROM regress_test_table;
|
||||
NOTICE: in object access: non-superuser attempting namespace search (subId=0) [no report on violation, allowed]
|
||||
NOTICE: in object access: non-superuser attempting namespace search (subId=0x0) [no report on violation, allowed]
|
||||
LINE 1: SELECT * FROM regress_test_table;
|
||||
^
|
||||
NOTICE: in object access: non-superuser finished namespace search (subId=0) [no report on violation, allowed]
|
||||
NOTICE: in object access: non-superuser finished namespace search (subId=0x0) [no report on violation, allowed]
|
||||
LINE 1: SELECT * FROM regress_test_table;
|
||||
^
|
||||
NOTICE: in executor check perms: non-superuser attempting execute
|
||||
@ -110,61 +158,89 @@ NOTICE: in executor check perms: non-superuser finished execute
|
||||
|
||||
SET work_mem = 8192;
|
||||
NOTICE: in process utility: non-superuser attempting set
|
||||
NOTICE: in object_access_hook_str: non-superuser attempting alter (set) [work_mem]
|
||||
NOTICE: in object_access_hook_str: non-superuser finished alter (set) [work_mem]
|
||||
NOTICE: in object_access_hook_str: non-superuser attempting alter (subId=0x1000, set) [work_mem]
|
||||
NOTICE: in object_access_hook_str: non-superuser finished alter (subId=0x1000, set) [work_mem]
|
||||
NOTICE: in process utility: non-superuser finished set
|
||||
RESET work_mem;
|
||||
NOTICE: in process utility: non-superuser attempting set
|
||||
NOTICE: in object_access_hook_str: non-superuser attempting alter (set) [work_mem]
|
||||
NOTICE: in object_access_hook_str: non-superuser finished alter (set) [work_mem]
|
||||
NOTICE: in object_access_hook_str: non-superuser attempting alter (subId=0x1000, set) [work_mem]
|
||||
NOTICE: in object_access_hook_str: non-superuser finished alter (subId=0x1000, set) [work_mem]
|
||||
NOTICE: in process utility: non-superuser finished set
|
||||
ALTER SYSTEM SET work_mem = 8192;
|
||||
NOTICE: in process utility: non-superuser attempting alter system
|
||||
ERROR: must be superuser to execute ALTER SYSTEM command
|
||||
ERROR: permission denied to set parameter "work_mem"
|
||||
ALTER SYSTEM RESET work_mem;
|
||||
NOTICE: in process utility: non-superuser attempting alter system
|
||||
ERROR: must be superuser to execute ALTER SYSTEM command
|
||||
ERROR: permission denied to set parameter "work_mem"
|
||||
SET test_oat_hooks.user_var1 = true;
|
||||
NOTICE: in process utility: non-superuser attempting set
|
||||
NOTICE: in object_access_hook_str: non-superuser attempting alter (subId=0x1000, set) [test_oat_hooks.user_var1]
|
||||
NOTICE: in object_access_hook_str: non-superuser finished alter (subId=0x1000, set) [test_oat_hooks.user_var1]
|
||||
NOTICE: in process utility: non-superuser finished set
|
||||
SET test_oat_hooks.super_var1 = true;
|
||||
NOTICE: in process utility: non-superuser attempting set
|
||||
ERROR: permission denied to set parameter "test_oat_hooks.super_var1"
|
||||
ALTER SYSTEM SET test_oat_hooks.user_var1 = true;
|
||||
NOTICE: in process utility: non-superuser attempting alter system
|
||||
ERROR: permission denied to set parameter "test_oat_hooks.user_var1"
|
||||
ALTER SYSTEM SET test_oat_hooks.super_var1 = true;
|
||||
NOTICE: in process utility: non-superuser attempting alter system
|
||||
ERROR: permission denied to set parameter "test_oat_hooks.super_var1"
|
||||
SET test_oat_hooks.user_var2 = true;
|
||||
NOTICE: in process utility: non-superuser attempting set
|
||||
NOTICE: in object_access_hook_str: non-superuser attempting alter (subId=0x1000, set) [test_oat_hooks.user_var2]
|
||||
NOTICE: in object_access_hook_str: non-superuser finished alter (subId=0x1000, set) [test_oat_hooks.user_var2]
|
||||
NOTICE: in process utility: non-superuser finished set
|
||||
SET test_oat_hooks.super_var2 = true;
|
||||
NOTICE: in process utility: non-superuser attempting set
|
||||
ERROR: permission denied to set parameter "test_oat_hooks.super_var2"
|
||||
ALTER SYSTEM SET test_oat_hooks.user_var2 = true;
|
||||
NOTICE: in process utility: non-superuser attempting alter system
|
||||
ERROR: permission denied to set parameter "test_oat_hooks.user_var2"
|
||||
ALTER SYSTEM SET test_oat_hooks.super_var2 = true;
|
||||
NOTICE: in process utility: non-superuser attempting alter system
|
||||
ERROR: permission denied to set parameter "test_oat_hooks.super_var2"
|
||||
RESET SESSION AUTHORIZATION;
|
||||
NOTICE: in process utility: non-superuser attempting set
|
||||
NOTICE: in object_access_hook_str: superuser attempting alter (set) [session_authorization]
|
||||
NOTICE: in object_access_hook_str: superuser finished alter (set) [session_authorization]
|
||||
NOTICE: in object_access_hook_str: superuser attempting alter (subId=0x1000, set) [session_authorization]
|
||||
NOTICE: in object_access_hook_str: superuser finished alter (subId=0x1000, set) [session_authorization]
|
||||
NOTICE: in process utility: superuser finished set
|
||||
-- Turn off non-superuser permissions
|
||||
SET test_oat_hooks.deny_set_variable = true;
|
||||
NOTICE: in process utility: superuser attempting set
|
||||
NOTICE: in object_access_hook_str: superuser attempting alter (set) [test_oat_hooks.deny_set_variable]
|
||||
NOTICE: in object_access_hook_str: superuser finished alter (set) [test_oat_hooks.deny_set_variable]
|
||||
NOTICE: in object_access_hook_str: superuser attempting alter (subId=0x1000, set) [test_oat_hooks.deny_set_variable]
|
||||
NOTICE: in object_access_hook_str: superuser finished alter (subId=0x1000, set) [test_oat_hooks.deny_set_variable]
|
||||
NOTICE: in process utility: superuser finished set
|
||||
SET test_oat_hooks.deny_alter_system = true;
|
||||
NOTICE: in process utility: superuser attempting set
|
||||
NOTICE: in object_access_hook_str: superuser attempting alter (set) [test_oat_hooks.deny_alter_system]
|
||||
NOTICE: in object_access_hook_str: superuser finished alter (set) [test_oat_hooks.deny_alter_system]
|
||||
NOTICE: in object_access_hook_str: superuser attempting alter (subId=0x1000, set) [test_oat_hooks.deny_alter_system]
|
||||
NOTICE: in object_access_hook_str: superuser finished alter (subId=0x1000, set) [test_oat_hooks.deny_alter_system]
|
||||
NOTICE: in process utility: superuser finished set
|
||||
SET test_oat_hooks.deny_object_access = true;
|
||||
NOTICE: in process utility: superuser attempting set
|
||||
NOTICE: in object_access_hook_str: superuser attempting alter (set) [test_oat_hooks.deny_object_access]
|
||||
NOTICE: in object_access_hook_str: superuser finished alter (set) [test_oat_hooks.deny_object_access]
|
||||
NOTICE: in object_access_hook_str: superuser attempting alter (subId=0x1000, set) [test_oat_hooks.deny_object_access]
|
||||
NOTICE: in object_access_hook_str: superuser finished alter (subId=0x1000, set) [test_oat_hooks.deny_object_access]
|
||||
NOTICE: in process utility: superuser finished set
|
||||
SET test_oat_hooks.deny_exec_perms = true;
|
||||
NOTICE: in process utility: superuser attempting set
|
||||
NOTICE: in object_access_hook_str: superuser attempting alter (set) [test_oat_hooks.deny_exec_perms]
|
||||
NOTICE: in object_access_hook_str: superuser finished alter (set) [test_oat_hooks.deny_exec_perms]
|
||||
NOTICE: in object_access_hook_str: superuser attempting alter (subId=0x1000, set) [test_oat_hooks.deny_exec_perms]
|
||||
NOTICE: in object_access_hook_str: superuser finished alter (subId=0x1000, set) [test_oat_hooks.deny_exec_perms]
|
||||
NOTICE: in process utility: superuser finished set
|
||||
SET test_oat_hooks.deny_utility_commands = true;
|
||||
NOTICE: in process utility: superuser attempting set
|
||||
NOTICE: in object_access_hook_str: superuser attempting alter (set) [test_oat_hooks.deny_utility_commands]
|
||||
NOTICE: in object_access_hook_str: superuser finished alter (set) [test_oat_hooks.deny_utility_commands]
|
||||
NOTICE: in object_access_hook_str: superuser attempting alter (subId=0x1000, set) [test_oat_hooks.deny_utility_commands]
|
||||
NOTICE: in object_access_hook_str: superuser finished alter (subId=0x1000, set) [test_oat_hooks.deny_utility_commands]
|
||||
NOTICE: in process utility: superuser finished set
|
||||
-- Try again as non-superuser with permissions denied
|
||||
SET SESSION AUTHORIZATION regress_test_user;
|
||||
NOTICE: in process utility: superuser attempting set
|
||||
NOTICE: in object_access_hook_str: non-superuser attempting alter (set) [session_authorization]
|
||||
NOTICE: in object_access_hook_str: non-superuser attempting alter (subId=0x1000, set) [session_authorization]
|
||||
ERROR: permission denied: set session_authorization
|
||||
SELECT * FROM regress_test_table;
|
||||
NOTICE: in object access: superuser attempting namespace search (subId=0) [no report on violation, allowed]
|
||||
NOTICE: in object access: superuser attempting namespace search (subId=0x0) [no report on violation, allowed]
|
||||
LINE 1: SELECT * FROM regress_test_table;
|
||||
^
|
||||
NOTICE: in object access: superuser finished namespace search (subId=0) [no report on violation, allowed]
|
||||
NOTICE: in object access: superuser finished namespace search (subId=0x0) [no report on violation, allowed]
|
||||
LINE 1: SELECT * FROM regress_test_table;
|
||||
^
|
||||
NOTICE: in executor check perms: superuser attempting execute
|
||||
@ -183,28 +259,43 @@ NOTICE: in executor check perms: superuser finished execute
|
||||
|
||||
SET work_mem = 8192;
|
||||
NOTICE: in process utility: superuser attempting set
|
||||
NOTICE: in object_access_hook_str: superuser attempting alter (set) [work_mem]
|
||||
NOTICE: in object_access_hook_str: superuser finished alter (set) [work_mem]
|
||||
NOTICE: in object_access_hook_str: superuser attempting alter (subId=0x1000, set) [work_mem]
|
||||
NOTICE: in object_access_hook_str: superuser finished alter (subId=0x1000, set) [work_mem]
|
||||
NOTICE: in process utility: superuser finished set
|
||||
RESET work_mem;
|
||||
NOTICE: in process utility: superuser attempting set
|
||||
NOTICE: in object_access_hook_str: superuser attempting alter (set) [work_mem]
|
||||
NOTICE: in object_access_hook_str: superuser finished alter (set) [work_mem]
|
||||
NOTICE: in object_access_hook_str: superuser attempting alter (subId=0x1000, set) [work_mem]
|
||||
NOTICE: in object_access_hook_str: superuser finished alter (subId=0x1000, set) [work_mem]
|
||||
NOTICE: in process utility: superuser finished set
|
||||
ALTER SYSTEM SET work_mem = 8192;
|
||||
NOTICE: in process utility: superuser attempting alter system
|
||||
NOTICE: in object_access_hook_str: superuser attempting alter (alter system set) [work_mem]
|
||||
NOTICE: in object_access_hook_str: superuser finished alter (alter system set) [work_mem]
|
||||
NOTICE: in object_access_hook_str: superuser attempting alter (subId=0x2000, alter system) [work_mem]
|
||||
NOTICE: in object_access_hook_str: superuser finished alter (subId=0x2000, alter system) [work_mem]
|
||||
NOTICE: in process utility: superuser finished alter system
|
||||
ALTER SYSTEM RESET work_mem;
|
||||
NOTICE: in process utility: superuser attempting alter system
|
||||
NOTICE: in object_access_hook_str: superuser attempting alter (alter system set) [work_mem]
|
||||
NOTICE: in object_access_hook_str: superuser finished alter (alter system set) [work_mem]
|
||||
NOTICE: in object_access_hook_str: superuser attempting alter (subId=0x2000, alter system) [work_mem]
|
||||
NOTICE: in object_access_hook_str: superuser finished alter (subId=0x2000, alter system) [work_mem]
|
||||
NOTICE: in process utility: superuser finished alter system
|
||||
-- Clean up
|
||||
RESET SESSION AUTHORIZATION;
|
||||
NOTICE: in process utility: superuser attempting set
|
||||
NOTICE: in object_access_hook_str: superuser attempting alter (set) [session_authorization]
|
||||
NOTICE: in object_access_hook_str: superuser finished alter (set) [session_authorization]
|
||||
NOTICE: in object_access_hook_str: superuser attempting alter (subId=0x1000, set) [session_authorization]
|
||||
NOTICE: in object_access_hook_str: superuser finished alter (subId=0x1000, set) [session_authorization]
|
||||
NOTICE: in process utility: superuser finished set
|
||||
SET test_oat_hooks.audit = false;
|
||||
NOTICE: in process utility: superuser attempting set
|
||||
DROP ROLE regress_role_joe; -- fails
|
||||
ERROR: role "regress_role_joe" cannot be dropped because some objects depend on it
|
||||
DETAIL: privileges for parameter test_oat_hooks.user_var1
|
||||
privileges for parameter test_oat_hooks.super_var1
|
||||
privileges for parameter test_oat_hooks.user_var2
|
||||
privileges for parameter test_oat_hooks.super_var2
|
||||
privileges for parameter none.such
|
||||
privileges for parameter another.bogus
|
||||
REVOKE ALL PRIVILEGES ON PARAMETER
|
||||
none.such, another.bogus,
|
||||
test_oat_hooks.user_var1, test_oat_hooks.super_var1,
|
||||
test_oat_hooks.user_var2, test_oat_hooks.super_var2
|
||||
FROM regress_role_joe;
|
||||
DROP ROLE regress_role_joe;
|
||||
|
@ -1,10 +1,39 @@
|
||||
-- Creating privileges on a placeholder GUC should create entries in the
|
||||
-- pg_parameter_acl catalog which conservatively grant no privileges to public.
|
||||
CREATE ROLE regress_role_joe;
|
||||
GRANT SET ON PARAMETER test_oat_hooks.user_var1 TO regress_role_joe;
|
||||
GRANT SET ON PARAMETER test_oat_hooks.super_var1 TO regress_role_joe;
|
||||
|
||||
-- SET commands fire both the ProcessUtility_hook and the
|
||||
-- object_access_hook_str. Since the auditing GUC starts out false, we miss the
|
||||
-- initial "attempting" audit message from the ProcessUtility_hook, but we
|
||||
-- should thereafter see the audit messages
|
||||
-- should thereafter see the audit messages.
|
||||
LOAD 'test_oat_hooks';
|
||||
SET test_oat_hooks.audit = true;
|
||||
|
||||
-- Creating privileges on an existent custom GUC should create precisely the
|
||||
-- right privileges, not overly conservative ones.
|
||||
GRANT SET ON PARAMETER test_oat_hooks.user_var2 TO regress_role_joe;
|
||||
GRANT SET ON PARAMETER test_oat_hooks.super_var2 TO regress_role_joe;
|
||||
|
||||
-- Granting multiple privileges on a parameter should be reported correctly to
|
||||
-- the OAT hook, but beware that WITH GRANT OPTION is not represented.
|
||||
GRANT SET, ALTER SYSTEM ON PARAMETER none.such TO regress_role_joe;
|
||||
GRANT SET, ALTER SYSTEM ON PARAMETER another.bogus TO regress_role_joe WITH GRANT OPTION;
|
||||
|
||||
-- Check when the hooks fire relative to dependency based abort of a drop
|
||||
DROP ROLE regress_role_joe;
|
||||
|
||||
-- Check the behavior of the hooks relative to do-nothing grants and revokes
|
||||
GRANT SET ON PARAMETER work_mem TO PUBLIC;
|
||||
REVOKE ALTER SYSTEM ON PARAMETER work_mem FROM PUBLIC;
|
||||
|
||||
-- Check the behavior of the hooks relative to unrecognized parameters
|
||||
GRANT ALL ON PARAMETER "none.such" TO PUBLIC;
|
||||
|
||||
-- Check relative to an operation that causes the catalog entry to be deleted
|
||||
REVOKE ALL ON PARAMETER "none.such" FROM PUBLIC;
|
||||
|
||||
-- Create objects for use in the test
|
||||
CREATE USER regress_test_user;
|
||||
CREATE TABLE regress_test_table (t text);
|
||||
@ -30,6 +59,16 @@ SET work_mem = 8192;
|
||||
RESET work_mem;
|
||||
ALTER SYSTEM SET work_mem = 8192;
|
||||
ALTER SYSTEM RESET work_mem;
|
||||
|
||||
SET test_oat_hooks.user_var1 = true;
|
||||
SET test_oat_hooks.super_var1 = true;
|
||||
ALTER SYSTEM SET test_oat_hooks.user_var1 = true;
|
||||
ALTER SYSTEM SET test_oat_hooks.super_var1 = true;
|
||||
SET test_oat_hooks.user_var2 = true;
|
||||
SET test_oat_hooks.super_var2 = true;
|
||||
ALTER SYSTEM SET test_oat_hooks.user_var2 = true;
|
||||
ALTER SYSTEM SET test_oat_hooks.super_var2 = true;
|
||||
|
||||
RESET SESSION AUTHORIZATION;
|
||||
|
||||
-- Turn off non-superuser permissions
|
||||
@ -48,6 +87,14 @@ RESET work_mem;
|
||||
ALTER SYSTEM SET work_mem = 8192;
|
||||
ALTER SYSTEM RESET work_mem;
|
||||
|
||||
-- Clean up
|
||||
RESET SESSION AUTHORIZATION;
|
||||
|
||||
SET test_oat_hooks.audit = false;
|
||||
DROP ROLE regress_role_joe; -- fails
|
||||
REVOKE ALL PRIVILEGES ON PARAMETER
|
||||
none.such, another.bogus,
|
||||
test_oat_hooks.user_var1, test_oat_hooks.super_var1,
|
||||
test_oat_hooks.user_var2, test_oat_hooks.super_var2
|
||||
FROM regress_role_joe;
|
||||
DROP ROLE regress_role_joe;
|
||||
|
@ -34,6 +34,15 @@ static bool REGRESS_deny_exec_perms = false;
|
||||
static bool REGRESS_deny_utility_commands = false;
|
||||
static bool REGRESS_audit = false;
|
||||
|
||||
/*
|
||||
* GUCs for testing privileges on USERSET and SUSET variables,
|
||||
* with and without privileges granted prior to module load.
|
||||
*/
|
||||
static bool REGRESS_userset_variable1 = false;
|
||||
static bool REGRESS_userset_variable2 = false;
|
||||
static bool REGRESS_suset_variable1 = false;
|
||||
static bool REGRESS_suset_variable2 = false;
|
||||
|
||||
/* Saved hook values in case of unload */
|
||||
static object_access_hook_type next_object_access_hook = NULL;
|
||||
static object_access_hook_type_str next_object_access_hook_str = NULL;
|
||||
@ -153,6 +162,56 @@ _PG_init(void)
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
/*
|
||||
* test_oat_hooks.user_var{1,2} = (on|off)
|
||||
*/
|
||||
DefineCustomBoolVariable("test_oat_hooks.user_var1",
|
||||
"Dummy parameter settable by public",
|
||||
NULL,
|
||||
®RESS_userset_variable1,
|
||||
false,
|
||||
PGC_USERSET,
|
||||
GUC_NOT_IN_SAMPLE,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
DefineCustomBoolVariable("test_oat_hooks.user_var2",
|
||||
"Dummy parameter settable by public",
|
||||
NULL,
|
||||
®RESS_userset_variable2,
|
||||
false,
|
||||
PGC_USERSET,
|
||||
GUC_NOT_IN_SAMPLE,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
/*
|
||||
* test_oat_hooks.super_var{1,2} = (on|off)
|
||||
*/
|
||||
DefineCustomBoolVariable("test_oat_hooks.super_var1",
|
||||
"Dummy parameter settable by superuser",
|
||||
NULL,
|
||||
®RESS_suset_variable1,
|
||||
false,
|
||||
PGC_SUSET,
|
||||
GUC_NOT_IN_SAMPLE,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
DefineCustomBoolVariable("test_oat_hooks.super_var2",
|
||||
"Dummy parameter settable by superuser",
|
||||
NULL,
|
||||
®RESS_suset_variable2,
|
||||
false,
|
||||
PGC_SUSET,
|
||||
GUC_NOT_IN_SAMPLE,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
MarkGUCPrefixReserved("test_oat_hooks");
|
||||
|
||||
/* Object access hook */
|
||||
@ -250,7 +309,14 @@ REGRESS_object_access_hook_str(ObjectAccessType access, Oid classId, const char
|
||||
switch (access)
|
||||
{
|
||||
case OAT_POST_ALTER:
|
||||
if (subId & ACL_SET_VALUE)
|
||||
if ((subId & ACL_SET) && (subId & ACL_ALTER_SYSTEM))
|
||||
{
|
||||
if (REGRESS_deny_set_variable && !superuser_arg(GetUserId()))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
errmsg("permission denied: all privileges %s", objName)));
|
||||
}
|
||||
else if (subId & ACL_SET)
|
||||
{
|
||||
if (REGRESS_deny_set_variable && !superuser_arg(GetUserId()))
|
||||
ereport(ERROR,
|
||||
@ -265,7 +331,7 @@ REGRESS_object_access_hook_str(ObjectAccessType access, Oid classId, const char
|
||||
errmsg("permission denied: alter system set %s", objName)));
|
||||
}
|
||||
else
|
||||
elog(ERROR, "Unknown SettingAclRelationId subId: %d", subId);
|
||||
elog(ERROR, "Unknown ParameterAclRelationId subId: %d", subId);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -860,12 +926,14 @@ accesstype_to_string(ObjectAccessType access, int subId)
|
||||
type = "UNRECOGNIZED ObjectAccessType";
|
||||
}
|
||||
|
||||
if (subId & ACL_SET_VALUE)
|
||||
return psprintf("%s (set)", type);
|
||||
if ((subId & ACL_SET) && (subId & ACL_ALTER_SYSTEM))
|
||||
return psprintf("%s (subId=0x%x, all privileges)", type, subId);
|
||||
if (subId & ACL_SET)
|
||||
return psprintf("%s (subId=0x%x, set)", type, subId);
|
||||
if (subId & ACL_ALTER_SYSTEM)
|
||||
return psprintf("%s (alter system set)", type);
|
||||
return psprintf("%s (subId=0x%x, alter system)", type, subId);
|
||||
|
||||
return psprintf("%s (subId=%d)", type, subId);
|
||||
return psprintf("%s (subId=0x%x)", type, subId);
|
||||
}
|
||||
|
||||
static char *
|
||||
|
@ -316,6 +316,38 @@ my %tests = (
|
||||
like => { pg_dumpall_globals => 1, },
|
||||
},
|
||||
|
||||
'GRANT ALTER SYSTEM ON PARAMETER full_page_writes TO regress_dump_test_role'
|
||||
=> {
|
||||
create_order => 2,
|
||||
create_sql =>
|
||||
'GRANT ALTER SYSTEM ON PARAMETER full_page_writes TO regress_dump_test_role;',
|
||||
regexp =>
|
||||
|
||||
qr/^GRANT ALTER SYSTEM ON PARAMETER full_page_writes TO regress_dump_test_role;/m,
|
||||
like => { pg_dumpall_globals => 1, },
|
||||
},
|
||||
|
||||
'GRANT ALL ON PARAMETER Custom.Knob TO regress_dump_test_role WITH GRANT OPTION'
|
||||
=> {
|
||||
create_order => 2,
|
||||
create_sql =>
|
||||
'GRANT SET, ALTER SYSTEM ON PARAMETER Custom.Knob TO regress_dump_test_role WITH GRANT OPTION;',
|
||||
regexp =>
|
||||
# "set" plus "alter system" is "all" privileges on parameters
|
||||
qr/^GRANT ALL ON PARAMETER "custom.knob" TO regress_dump_test_role WITH GRANT OPTION;/m,
|
||||
like => { pg_dumpall_globals => 1, },
|
||||
},
|
||||
|
||||
'GRANT ALL ON PARAMETER DateStyle TO regress_dump_test_role' => {
|
||||
create_order => 2,
|
||||
create_sql =>
|
||||
'GRANT ALL ON PARAMETER "DateStyle" TO regress_dump_test_role WITH GRANT OPTION; REVOKE GRANT OPTION FOR ALL ON PARAMETER DateStyle FROM regress_dump_test_role;',
|
||||
regexp =>
|
||||
# The revoke simplifies the ultimate grant so as to not include "with grant option"
|
||||
qr/^GRANT ALL ON PARAMETER datestyle TO regress_dump_test_role;/m,
|
||||
like => { pg_dumpall_globals => 1, },
|
||||
},
|
||||
|
||||
'CREATE SCHEMA public' => {
|
||||
regexp => qr/^CREATE SCHEMA public;/m,
|
||||
like => {
|
||||
|
@ -1,6 +1,6 @@
|
||||
# src/test/modules/unsafe_tests/Makefile
|
||||
|
||||
REGRESS = rolenames alter_system_table
|
||||
REGRESS = rolenames alter_system_table guc_privs
|
||||
|
||||
ifdef USE_PGXS
|
||||
PG_CONFIG = pg_config
|
||||
|
526
src/test/modules/unsafe_tests/expected/guc_privs.out
Normal file
526
src/test/modules/unsafe_tests/expected/guc_privs.out
Normal file
@ -0,0 +1,526 @@
|
||||
--
|
||||
-- Tests for privileges on GUCs.
|
||||
-- This is unsafe because changes will affect other databases in the cluster.
|
||||
--
|
||||
-- Test with a superuser role.
|
||||
CREATE ROLE regress_admin SUPERUSER;
|
||||
-- Perform operations as user 'regress_admin'.
|
||||
SET SESSION AUTHORIZATION regress_admin;
|
||||
-- PGC_BACKEND
|
||||
SET ignore_system_indexes = OFF; -- fail, cannot be set after connection start
|
||||
ERROR: parameter "ignore_system_indexes" cannot be set after connection start
|
||||
RESET ignore_system_indexes; -- fail, cannot be set after connection start
|
||||
ERROR: parameter "ignore_system_indexes" cannot be set after connection start
|
||||
ALTER SYSTEM SET ignore_system_indexes = OFF; -- ok
|
||||
ALTER SYSTEM RESET ignore_system_indexes; -- ok
|
||||
-- PGC_INTERNAL
|
||||
SET block_size = 50; -- fail, cannot be changed
|
||||
ERROR: parameter "block_size" cannot be changed
|
||||
RESET block_size; -- fail, cannot be changed
|
||||
ERROR: parameter "block_size" cannot be changed
|
||||
ALTER SYSTEM SET block_size = 50; -- fail, cannot be changed
|
||||
ERROR: parameter "block_size" cannot be changed
|
||||
ALTER SYSTEM RESET block_size; -- fail, cannot be changed
|
||||
ERROR: parameter "block_size" cannot be changed
|
||||
-- PGC_POSTMASTER
|
||||
SET autovacuum_freeze_max_age = 1000050000; -- fail, requires restart
|
||||
ERROR: parameter "autovacuum_freeze_max_age" cannot be changed without restarting the server
|
||||
RESET autovacuum_freeze_max_age; -- fail, requires restart
|
||||
ERROR: parameter "autovacuum_freeze_max_age" cannot be changed without restarting the server
|
||||
ALTER SYSTEM SET autovacuum_freeze_max_age = 1000050000; -- ok
|
||||
ALTER SYSTEM RESET autovacuum_freeze_max_age; -- ok
|
||||
ALTER SYSTEM SET config_file = '/usr/local/data/postgresql.conf'; -- fail, cannot be changed
|
||||
ERROR: parameter "config_file" cannot be changed
|
||||
ALTER SYSTEM RESET config_file; -- fail, cannot be changed
|
||||
ERROR: parameter "config_file" cannot be changed
|
||||
-- PGC_SIGHUP
|
||||
SET autovacuum = OFF; -- fail, requires reload
|
||||
ERROR: parameter "autovacuum" cannot be changed now
|
||||
RESET autovacuum; -- fail, requires reload
|
||||
ERROR: parameter "autovacuum" cannot be changed now
|
||||
ALTER SYSTEM SET autovacuum = OFF; -- ok
|
||||
ALTER SYSTEM RESET autovacuum; -- ok
|
||||
-- PGC_SUSET
|
||||
SET lc_messages = 'C'; -- ok
|
||||
RESET lc_messages; -- ok
|
||||
ALTER SYSTEM SET lc_messages = 'C'; -- ok
|
||||
ALTER SYSTEM RESET lc_messages; -- ok
|
||||
-- PGC_SU_BACKEND
|
||||
SET jit_debugging_support = OFF; -- fail, cannot be set after connection start
|
||||
ERROR: parameter "jit_debugging_support" cannot be set after connection start
|
||||
RESET jit_debugging_support; -- fail, cannot be set after connection start
|
||||
ERROR: parameter "jit_debugging_support" cannot be set after connection start
|
||||
ALTER SYSTEM SET jit_debugging_support = OFF; -- ok
|
||||
ALTER SYSTEM RESET jit_debugging_support; -- ok
|
||||
-- PGC_USERSET
|
||||
SET DateStyle = 'ISO, MDY'; -- ok
|
||||
RESET DateStyle; -- ok
|
||||
ALTER SYSTEM SET DateStyle = 'ISO, MDY'; -- ok
|
||||
ALTER SYSTEM RESET DateStyle; -- ok
|
||||
ALTER SYSTEM SET ssl_renegotiation_limit = 0; -- fail, cannot be changed
|
||||
ERROR: parameter "ssl_renegotiation_limit" cannot be changed
|
||||
ALTER SYSTEM RESET ssl_renegotiation_limit; -- fail, cannot be changed
|
||||
ERROR: parameter "ssl_renegotiation_limit" cannot be changed
|
||||
-- Finished testing superuser
|
||||
-- Create non-superuser with privileges to configure host resource usage
|
||||
CREATE ROLE regress_host_resource_admin NOSUPERUSER;
|
||||
-- Revoke privileges not yet granted
|
||||
REVOKE SET, ALTER SYSTEM ON PARAMETER work_mem FROM regress_host_resource_admin;
|
||||
REVOKE SET, ALTER SYSTEM ON PARAMETER zero_damaged_pages FROM regress_host_resource_admin;
|
||||
-- Check the new role does not yet have privileges on parameters
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'work_mem', 'SET, ALTER SYSTEM');
|
||||
has_parameter_privilege
|
||||
-------------------------
|
||||
f
|
||||
(1 row)
|
||||
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'work_mem', 'SET');
|
||||
has_parameter_privilege
|
||||
-------------------------
|
||||
f
|
||||
(1 row)
|
||||
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'work_mem', 'ALTER SYSTEM');
|
||||
has_parameter_privilege
|
||||
-------------------------
|
||||
f
|
||||
(1 row)
|
||||
|
||||
-- Check inappropriate and nonsense privilege types
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'work_mem', 'SELECT, UPDATE, CREATE');
|
||||
ERROR: unrecognized privilege type: "SELECT"
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'work_mem', 'USAGE');
|
||||
ERROR: unrecognized privilege type: "USAGE"
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'work_mem', 'WHATEVER');
|
||||
ERROR: unrecognized privilege type: "WHATEVER"
|
||||
-- Revoke, grant, and revoke again a SUSET parameter not yet granted
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'zero_damaged_pages', 'SET');
|
||||
has_parameter_privilege
|
||||
-------------------------
|
||||
f
|
||||
(1 row)
|
||||
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'zero_damaged_pages', 'ALTER SYSTEM');
|
||||
has_parameter_privilege
|
||||
-------------------------
|
||||
f
|
||||
(1 row)
|
||||
|
||||
REVOKE SET ON PARAMETER zero_damaged_pages FROM regress_host_resource_admin;
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'zero_damaged_pages', 'SET');
|
||||
has_parameter_privilege
|
||||
-------------------------
|
||||
f
|
||||
(1 row)
|
||||
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'zero_damaged_pages', 'ALTER SYSTEM');
|
||||
has_parameter_privilege
|
||||
-------------------------
|
||||
f
|
||||
(1 row)
|
||||
|
||||
GRANT SET ON PARAMETER zero_damaged_pages TO regress_host_resource_admin;
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'zero_damaged_pages', 'SET');
|
||||
has_parameter_privilege
|
||||
-------------------------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'zero_damaged_pages', 'ALTER SYSTEM');
|
||||
has_parameter_privilege
|
||||
-------------------------
|
||||
f
|
||||
(1 row)
|
||||
|
||||
REVOKE SET ON PARAMETER zero_damaged_pages FROM regress_host_resource_admin;
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'zero_damaged_pages', 'SET');
|
||||
has_parameter_privilege
|
||||
-------------------------
|
||||
f
|
||||
(1 row)
|
||||
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'zero_damaged_pages', 'ALTER SYSTEM');
|
||||
has_parameter_privilege
|
||||
-------------------------
|
||||
f
|
||||
(1 row)
|
||||
|
||||
-- Revoke, grant, and revoke again a USERSET parameter not yet granted
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'work_mem', 'SET');
|
||||
has_parameter_privilege
|
||||
-------------------------
|
||||
f
|
||||
(1 row)
|
||||
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'work_mem', 'ALTER SYSTEM');
|
||||
has_parameter_privilege
|
||||
-------------------------
|
||||
f
|
||||
(1 row)
|
||||
|
||||
REVOKE SET ON PARAMETER work_mem FROM regress_host_resource_admin;
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'work_mem', 'SET');
|
||||
has_parameter_privilege
|
||||
-------------------------
|
||||
f
|
||||
(1 row)
|
||||
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'work_mem', 'ALTER SYSTEM');
|
||||
has_parameter_privilege
|
||||
-------------------------
|
||||
f
|
||||
(1 row)
|
||||
|
||||
GRANT SET ON PARAMETER work_mem TO regress_host_resource_admin;
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'work_mem', 'SET');
|
||||
has_parameter_privilege
|
||||
-------------------------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'work_mem', 'ALTER SYSTEM');
|
||||
has_parameter_privilege
|
||||
-------------------------
|
||||
f
|
||||
(1 row)
|
||||
|
||||
REVOKE SET ON PARAMETER work_mem FROM regress_host_resource_admin;
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'work_mem', 'SET');
|
||||
has_parameter_privilege
|
||||
-------------------------
|
||||
f
|
||||
(1 row)
|
||||
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'work_mem', 'ALTER SYSTEM');
|
||||
has_parameter_privilege
|
||||
-------------------------
|
||||
f
|
||||
(1 row)
|
||||
|
||||
-- Revoke privileges from a non-existent custom GUC. This should not create
|
||||
-- entries in the catalog.
|
||||
REVOKE ALL ON PARAMETER "none.such" FROM regress_host_resource_admin;
|
||||
SELECT 1 FROM pg_parameter_acl WHERE parname = 'none.such';
|
||||
?column?
|
||||
----------
|
||||
(0 rows)
|
||||
|
||||
-- Grant and then revoke privileges on the non-existent custom GUC. Check that
|
||||
-- a do-nothing entry is not left in the catalogs after the revoke.
|
||||
GRANT ALL ON PARAMETER none.such TO regress_host_resource_admin;
|
||||
SELECT 1 FROM pg_parameter_acl WHERE parname = 'none.such';
|
||||
?column?
|
||||
----------
|
||||
1
|
||||
(1 row)
|
||||
|
||||
REVOKE ALL ON PARAMETER "None.Such" FROM regress_host_resource_admin;
|
||||
SELECT 1 FROM pg_parameter_acl WHERE parname = 'none.such';
|
||||
?column?
|
||||
----------
|
||||
(0 rows)
|
||||
|
||||
-- Can't grant on a non-existent core GUC.
|
||||
GRANT ALL ON PARAMETER no_such_guc TO regress_host_resource_admin; -- fail
|
||||
ERROR: invalid parameter name "no_such_guc"
|
||||
-- Initially there are no privileges and no catalog entry for this GUC.
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'enable_material', 'SET');
|
||||
has_parameter_privilege
|
||||
-------------------------
|
||||
f
|
||||
(1 row)
|
||||
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'enable_material', 'ALTER SYSTEM');
|
||||
has_parameter_privilege
|
||||
-------------------------
|
||||
f
|
||||
(1 row)
|
||||
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'enable_material', 'SET, ALTER SYSTEM');
|
||||
has_parameter_privilege
|
||||
-------------------------
|
||||
f
|
||||
(1 row)
|
||||
|
||||
SELECT 1 FROM pg_parameter_acl WHERE parname = 'enable_material';
|
||||
?column?
|
||||
----------
|
||||
(0 rows)
|
||||
|
||||
-- GRANT SET creates an entry:
|
||||
GRANT SET ON PARAMETER enable_material TO PUBLIC;
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'enable_material', 'SET');
|
||||
has_parameter_privilege
|
||||
-------------------------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'enable_material', 'ALTER SYSTEM');
|
||||
has_parameter_privilege
|
||||
-------------------------
|
||||
f
|
||||
(1 row)
|
||||
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'enable_material', 'SET, ALTER SYSTEM');
|
||||
has_parameter_privilege
|
||||
-------------------------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
SELECT 1 FROM pg_parameter_acl WHERE parname = 'enable_material';
|
||||
?column?
|
||||
----------
|
||||
1
|
||||
(1 row)
|
||||
|
||||
-- Now grant ALTER SYSTEM:
|
||||
GRANT ALL ON PARAMETER enable_material TO PUBLIC;
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'enable_material', 'SET');
|
||||
has_parameter_privilege
|
||||
-------------------------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'enable_material', 'ALTER SYSTEM');
|
||||
has_parameter_privilege
|
||||
-------------------------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'enable_material', 'SET, ALTER SYSTEM');
|
||||
has_parameter_privilege
|
||||
-------------------------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
SELECT 1 FROM pg_parameter_acl WHERE parname = 'enable_material';
|
||||
?column?
|
||||
----------
|
||||
1
|
||||
(1 row)
|
||||
|
||||
-- REVOKE ALTER SYSTEM brings us back to just the SET privilege:
|
||||
REVOKE ALTER SYSTEM ON PARAMETER enable_material FROM PUBLIC;
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'enable_material', 'SET');
|
||||
has_parameter_privilege
|
||||
-------------------------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'enable_material', 'ALTER SYSTEM');
|
||||
has_parameter_privilege
|
||||
-------------------------
|
||||
f
|
||||
(1 row)
|
||||
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'enable_material', 'SET, ALTER SYSTEM');
|
||||
has_parameter_privilege
|
||||
-------------------------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
SELECT 1 FROM pg_parameter_acl WHERE parname = 'enable_material';
|
||||
?column?
|
||||
----------
|
||||
1
|
||||
(1 row)
|
||||
|
||||
-- And this should remove the entry altogether:
|
||||
REVOKE SET ON PARAMETER enable_material FROM PUBLIC;
|
||||
SELECT 1 FROM pg_parameter_acl WHERE parname = 'enable_material';
|
||||
?column?
|
||||
----------
|
||||
(0 rows)
|
||||
|
||||
-- Grant privileges on parameters to the new non-superuser role
|
||||
GRANT SET, ALTER SYSTEM ON PARAMETER
|
||||
autovacuum_work_mem, hash_mem_multiplier, max_stack_depth,
|
||||
shared_buffers, temp_file_limit, work_mem
|
||||
TO regress_host_resource_admin;
|
||||
-- Check the new role now has privilges on parameters
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'work_mem', 'SET, ALTER SYSTEM');
|
||||
has_parameter_privilege
|
||||
-------------------------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'work_mem', 'SET');
|
||||
has_parameter_privilege
|
||||
-------------------------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'work_mem', 'ALTER SYSTEM');
|
||||
has_parameter_privilege
|
||||
-------------------------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'work_mem', 'SET WITH GRANT OPTION, ALTER SYSTEM WITH GRANT OPTION');
|
||||
has_parameter_privilege
|
||||
-------------------------
|
||||
f
|
||||
(1 row)
|
||||
|
||||
-- Check again the inappropriate and nonsense privilege types. The prior
|
||||
-- similar check was performed before any entry for work_mem existed.
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'work_mem', 'SELECT, UPDATE, CREATE');
|
||||
ERROR: unrecognized privilege type: "SELECT"
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'work_mem', 'USAGE');
|
||||
ERROR: unrecognized privilege type: "USAGE"
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'work_mem', 'WHATEVER');
|
||||
ERROR: unrecognized privilege type: "WHATEVER"
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'work_mem', 'WHATEVER WITH GRANT OPTION');
|
||||
ERROR: unrecognized privilege type: "WHATEVER WITH GRANT OPTION"
|
||||
-- Check other function signatures
|
||||
SELECT has_parameter_privilege((SELECT oid FROM pg_catalog.pg_authid WHERE rolname = 'regress_host_resource_admin'),
|
||||
'max_stack_depth',
|
||||
'SET');
|
||||
has_parameter_privilege
|
||||
-------------------------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
SELECT has_parameter_privilege('hash_mem_multiplier', 'set');
|
||||
has_parameter_privilege
|
||||
-------------------------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
-- Check object identity functions
|
||||
SELECT pg_describe_object(tableoid, oid, 0)
|
||||
FROM pg_parameter_acl WHERE parname = 'work_mem';
|
||||
pg_describe_object
|
||||
--------------------
|
||||
parameter work_mem
|
||||
(1 row)
|
||||
|
||||
SELECT pg_identify_object(tableoid, oid, 0)
|
||||
FROM pg_parameter_acl WHERE parname = 'work_mem';
|
||||
pg_identify_object
|
||||
------------------------------
|
||||
("parameter ACL",,,work_mem)
|
||||
(1 row)
|
||||
|
||||
SELECT pg_identify_object_as_address(tableoid, oid, 0)
|
||||
FROM pg_parameter_acl WHERE parname = 'work_mem';
|
||||
pg_identify_object_as_address
|
||||
---------------------------------
|
||||
("parameter ACL",{work_mem},{})
|
||||
(1 row)
|
||||
|
||||
SELECT classid::regclass,
|
||||
(SELECT parname FROM pg_parameter_acl WHERE oid = goa.objid) AS parname,
|
||||
objsubid
|
||||
FROM pg_get_object_address('parameter ACL', '{work_mem}', '{}') goa;
|
||||
classid | parname | objsubid
|
||||
------------------+----------+----------
|
||||
pg_parameter_acl | work_mem | 0
|
||||
(1 row)
|
||||
|
||||
-- Perform some operations as user 'regress_host_resource_admin'
|
||||
SET SESSION AUTHORIZATION regress_host_resource_admin;
|
||||
ALTER SYSTEM SET autovacuum_work_mem = 32; -- ok, privileges have been granted
|
||||
ALTER SYSTEM SET ignore_system_indexes = OFF; -- fail, insufficient privileges
|
||||
ERROR: permission denied to set parameter "ignore_system_indexes"
|
||||
ALTER SYSTEM RESET autovacuum_multixact_freeze_max_age; -- fail, insufficient privileges
|
||||
ERROR: permission denied to set parameter "autovacuum_multixact_freeze_max_age"
|
||||
SET jit_provider = 'llvmjit'; -- fail, insufficient privileges
|
||||
ERROR: parameter "jit_provider" cannot be changed without restarting the server
|
||||
SELECT set_config ('jit_provider', 'llvmjit', true); -- fail, insufficient privileges
|
||||
ERROR: parameter "jit_provider" cannot be changed without restarting the server
|
||||
ALTER SYSTEM SET shared_buffers = 50; -- ok
|
||||
ALTER SYSTEM RESET shared_buffers; -- ok
|
||||
SET autovacuum_work_mem = 50; -- cannot be changed now
|
||||
ERROR: parameter "autovacuum_work_mem" cannot be changed now
|
||||
ALTER SYSTEM RESET temp_file_limit; -- ok
|
||||
SET TimeZone = 'Europe/Helsinki'; -- ok
|
||||
RESET TimeZone; -- ok
|
||||
SET max_stack_depth = 2048; -- ok, privileges have been granted
|
||||
RESET max_stack_depth; -- ok, privileges have been granted
|
||||
ALTER SYSTEM SET max_stack_depth = 2048; -- ok, privileges have been granted
|
||||
ALTER SYSTEM RESET max_stack_depth; -- ok, privileges have been granted
|
||||
SET lc_messages = 'C'; -- fail, insufficient privileges
|
||||
ERROR: permission denied to set parameter "lc_messages"
|
||||
RESET lc_messages; -- fail, insufficient privileges
|
||||
ERROR: permission denied to set parameter "lc_messages"
|
||||
ALTER SYSTEM SET lc_messages = 'C'; -- fail, insufficient privileges
|
||||
ERROR: permission denied to set parameter "lc_messages"
|
||||
ALTER SYSTEM RESET lc_messages; -- fail, insufficient privileges
|
||||
ERROR: permission denied to set parameter "lc_messages"
|
||||
SELECT set_config ('temp_buffers', '8192', false); -- ok
|
||||
set_config
|
||||
------------
|
||||
64MB
|
||||
(1 row)
|
||||
|
||||
ALTER SYSTEM RESET autovacuum_work_mem; -- ok, privileges have been granted
|
||||
ALTER SYSTEM RESET ALL; -- fail, insufficient privileges
|
||||
ERROR: permission denied to perform ALTER SYSTEM RESET ALL
|
||||
-- Check dropping/revoking behavior
|
||||
SET SESSION AUTHORIZATION regress_admin;
|
||||
DROP ROLE regress_host_resource_admin; -- fail, privileges remain
|
||||
ERROR: role "regress_host_resource_admin" cannot be dropped because some objects depend on it
|
||||
DETAIL: privileges for parameter autovacuum_work_mem
|
||||
privileges for parameter hash_mem_multiplier
|
||||
privileges for parameter max_stack_depth
|
||||
privileges for parameter shared_buffers
|
||||
privileges for parameter temp_file_limit
|
||||
privileges for parameter work_mem
|
||||
-- Use "revoke" to remove the privileges and allow the role to be dropped
|
||||
REVOKE SET, ALTER SYSTEM ON PARAMETER
|
||||
autovacuum_work_mem, hash_mem_multiplier, max_stack_depth,
|
||||
shared_buffers, temp_file_limit, work_mem
|
||||
FROM regress_host_resource_admin;
|
||||
DROP ROLE regress_host_resource_admin; -- ok
|
||||
-- Try that again, but use "drop owned by" instead of "revoke"
|
||||
CREATE ROLE regress_host_resource_admin NOSUPERUSER;
|
||||
SET SESSION AUTHORIZATION regress_host_resource_admin;
|
||||
ALTER SYSTEM SET autovacuum_work_mem = 32; -- fail, privileges not yet granted
|
||||
ERROR: permission denied to set parameter "autovacuum_work_mem"
|
||||
SET SESSION AUTHORIZATION regress_admin;
|
||||
GRANT SET, ALTER SYSTEM ON PARAMETER
|
||||
autovacuum_work_mem, hash_mem_multiplier, max_stack_depth,
|
||||
shared_buffers, temp_file_limit, work_mem
|
||||
TO regress_host_resource_admin;
|
||||
DROP ROLE regress_host_resource_admin; -- fail, privileges remain
|
||||
ERROR: role "regress_host_resource_admin" cannot be dropped because some objects depend on it
|
||||
DETAIL: privileges for parameter autovacuum_work_mem
|
||||
privileges for parameter hash_mem_multiplier
|
||||
privileges for parameter max_stack_depth
|
||||
privileges for parameter shared_buffers
|
||||
privileges for parameter temp_file_limit
|
||||
privileges for parameter work_mem
|
||||
DROP OWNED BY regress_host_resource_admin RESTRICT; -- cascade should not be needed
|
||||
SET SESSION AUTHORIZATION regress_host_resource_admin;
|
||||
ALTER SYSTEM SET autovacuum_work_mem = 32; -- fail, "drop owned" has dropped privileges
|
||||
ERROR: permission denied to set parameter "autovacuum_work_mem"
|
||||
SET SESSION AUTHORIZATION regress_admin;
|
||||
DROP ROLE regress_host_resource_admin; -- ok
|
||||
-- Check that "reassign owned" doesn't affect privileges
|
||||
CREATE ROLE regress_host_resource_admin NOSUPERUSER;
|
||||
CREATE ROLE regress_host_resource_newadmin NOSUPERUSER;
|
||||
GRANT SET, ALTER SYSTEM ON PARAMETER
|
||||
autovacuum_work_mem, hash_mem_multiplier, max_stack_depth,
|
||||
shared_buffers, temp_file_limit, work_mem
|
||||
TO regress_host_resource_admin;
|
||||
REASSIGN OWNED BY regress_host_resource_admin TO regress_host_resource_newadmin;
|
||||
SET SESSION AUTHORIZATION regress_host_resource_admin;
|
||||
ALTER SYSTEM SET autovacuum_work_mem = 32; -- ok, "reassign owned" did not change privileges
|
||||
ALTER SYSTEM RESET autovacuum_work_mem; -- ok
|
||||
SET SESSION AUTHORIZATION regress_admin;
|
||||
DROP ROLE regress_host_resource_admin; -- fail, privileges remain
|
||||
ERROR: role "regress_host_resource_admin" cannot be dropped because some objects depend on it
|
||||
DETAIL: privileges for parameter autovacuum_work_mem
|
||||
privileges for parameter hash_mem_multiplier
|
||||
privileges for parameter max_stack_depth
|
||||
privileges for parameter shared_buffers
|
||||
privileges for parameter temp_file_limit
|
||||
privileges for parameter work_mem
|
||||
DROP ROLE regress_host_resource_newadmin; -- ok, nothing was transferred
|
||||
-- Use "drop owned by" so we can drop the role
|
||||
DROP OWNED BY regress_host_resource_admin; -- ok
|
||||
DROP ROLE regress_host_resource_admin; -- ok
|
||||
-- Clean up
|
||||
RESET SESSION AUTHORIZATION;
|
||||
DROP ROLE regress_admin; -- ok
|
237
src/test/modules/unsafe_tests/sql/guc_privs.sql
Normal file
237
src/test/modules/unsafe_tests/sql/guc_privs.sql
Normal file
@ -0,0 +1,237 @@
|
||||
--
|
||||
-- Tests for privileges on GUCs.
|
||||
-- This is unsafe because changes will affect other databases in the cluster.
|
||||
--
|
||||
|
||||
-- Test with a superuser role.
|
||||
CREATE ROLE regress_admin SUPERUSER;
|
||||
|
||||
-- Perform operations as user 'regress_admin'.
|
||||
SET SESSION AUTHORIZATION regress_admin;
|
||||
|
||||
-- PGC_BACKEND
|
||||
SET ignore_system_indexes = OFF; -- fail, cannot be set after connection start
|
||||
RESET ignore_system_indexes; -- fail, cannot be set after connection start
|
||||
ALTER SYSTEM SET ignore_system_indexes = OFF; -- ok
|
||||
ALTER SYSTEM RESET ignore_system_indexes; -- ok
|
||||
-- PGC_INTERNAL
|
||||
SET block_size = 50; -- fail, cannot be changed
|
||||
RESET block_size; -- fail, cannot be changed
|
||||
ALTER SYSTEM SET block_size = 50; -- fail, cannot be changed
|
||||
ALTER SYSTEM RESET block_size; -- fail, cannot be changed
|
||||
-- PGC_POSTMASTER
|
||||
SET autovacuum_freeze_max_age = 1000050000; -- fail, requires restart
|
||||
RESET autovacuum_freeze_max_age; -- fail, requires restart
|
||||
ALTER SYSTEM SET autovacuum_freeze_max_age = 1000050000; -- ok
|
||||
ALTER SYSTEM RESET autovacuum_freeze_max_age; -- ok
|
||||
ALTER SYSTEM SET config_file = '/usr/local/data/postgresql.conf'; -- fail, cannot be changed
|
||||
ALTER SYSTEM RESET config_file; -- fail, cannot be changed
|
||||
-- PGC_SIGHUP
|
||||
SET autovacuum = OFF; -- fail, requires reload
|
||||
RESET autovacuum; -- fail, requires reload
|
||||
ALTER SYSTEM SET autovacuum = OFF; -- ok
|
||||
ALTER SYSTEM RESET autovacuum; -- ok
|
||||
-- PGC_SUSET
|
||||
SET lc_messages = 'C'; -- ok
|
||||
RESET lc_messages; -- ok
|
||||
ALTER SYSTEM SET lc_messages = 'C'; -- ok
|
||||
ALTER SYSTEM RESET lc_messages; -- ok
|
||||
-- PGC_SU_BACKEND
|
||||
SET jit_debugging_support = OFF; -- fail, cannot be set after connection start
|
||||
RESET jit_debugging_support; -- fail, cannot be set after connection start
|
||||
ALTER SYSTEM SET jit_debugging_support = OFF; -- ok
|
||||
ALTER SYSTEM RESET jit_debugging_support; -- ok
|
||||
-- PGC_USERSET
|
||||
SET DateStyle = 'ISO, MDY'; -- ok
|
||||
RESET DateStyle; -- ok
|
||||
ALTER SYSTEM SET DateStyle = 'ISO, MDY'; -- ok
|
||||
ALTER SYSTEM RESET DateStyle; -- ok
|
||||
ALTER SYSTEM SET ssl_renegotiation_limit = 0; -- fail, cannot be changed
|
||||
ALTER SYSTEM RESET ssl_renegotiation_limit; -- fail, cannot be changed
|
||||
-- Finished testing superuser
|
||||
|
||||
-- Create non-superuser with privileges to configure host resource usage
|
||||
CREATE ROLE regress_host_resource_admin NOSUPERUSER;
|
||||
-- Revoke privileges not yet granted
|
||||
REVOKE SET, ALTER SYSTEM ON PARAMETER work_mem FROM regress_host_resource_admin;
|
||||
REVOKE SET, ALTER SYSTEM ON PARAMETER zero_damaged_pages FROM regress_host_resource_admin;
|
||||
-- Check the new role does not yet have privileges on parameters
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'work_mem', 'SET, ALTER SYSTEM');
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'work_mem', 'SET');
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'work_mem', 'ALTER SYSTEM');
|
||||
-- Check inappropriate and nonsense privilege types
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'work_mem', 'SELECT, UPDATE, CREATE');
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'work_mem', 'USAGE');
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'work_mem', 'WHATEVER');
|
||||
-- Revoke, grant, and revoke again a SUSET parameter not yet granted
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'zero_damaged_pages', 'SET');
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'zero_damaged_pages', 'ALTER SYSTEM');
|
||||
REVOKE SET ON PARAMETER zero_damaged_pages FROM regress_host_resource_admin;
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'zero_damaged_pages', 'SET');
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'zero_damaged_pages', 'ALTER SYSTEM');
|
||||
GRANT SET ON PARAMETER zero_damaged_pages TO regress_host_resource_admin;
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'zero_damaged_pages', 'SET');
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'zero_damaged_pages', 'ALTER SYSTEM');
|
||||
REVOKE SET ON PARAMETER zero_damaged_pages FROM regress_host_resource_admin;
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'zero_damaged_pages', 'SET');
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'zero_damaged_pages', 'ALTER SYSTEM');
|
||||
-- Revoke, grant, and revoke again a USERSET parameter not yet granted
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'work_mem', 'SET');
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'work_mem', 'ALTER SYSTEM');
|
||||
REVOKE SET ON PARAMETER work_mem FROM regress_host_resource_admin;
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'work_mem', 'SET');
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'work_mem', 'ALTER SYSTEM');
|
||||
GRANT SET ON PARAMETER work_mem TO regress_host_resource_admin;
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'work_mem', 'SET');
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'work_mem', 'ALTER SYSTEM');
|
||||
REVOKE SET ON PARAMETER work_mem FROM regress_host_resource_admin;
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'work_mem', 'SET');
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'work_mem', 'ALTER SYSTEM');
|
||||
|
||||
-- Revoke privileges from a non-existent custom GUC. This should not create
|
||||
-- entries in the catalog.
|
||||
REVOKE ALL ON PARAMETER "none.such" FROM regress_host_resource_admin;
|
||||
SELECT 1 FROM pg_parameter_acl WHERE parname = 'none.such';
|
||||
-- Grant and then revoke privileges on the non-existent custom GUC. Check that
|
||||
-- a do-nothing entry is not left in the catalogs after the revoke.
|
||||
GRANT ALL ON PARAMETER none.such TO regress_host_resource_admin;
|
||||
SELECT 1 FROM pg_parameter_acl WHERE parname = 'none.such';
|
||||
REVOKE ALL ON PARAMETER "None.Such" FROM regress_host_resource_admin;
|
||||
SELECT 1 FROM pg_parameter_acl WHERE parname = 'none.such';
|
||||
-- Can't grant on a non-existent core GUC.
|
||||
GRANT ALL ON PARAMETER no_such_guc TO regress_host_resource_admin; -- fail
|
||||
|
||||
-- Initially there are no privileges and no catalog entry for this GUC.
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'enable_material', 'SET');
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'enable_material', 'ALTER SYSTEM');
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'enable_material', 'SET, ALTER SYSTEM');
|
||||
SELECT 1 FROM pg_parameter_acl WHERE parname = 'enable_material';
|
||||
-- GRANT SET creates an entry:
|
||||
GRANT SET ON PARAMETER enable_material TO PUBLIC;
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'enable_material', 'SET');
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'enable_material', 'ALTER SYSTEM');
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'enable_material', 'SET, ALTER SYSTEM');
|
||||
SELECT 1 FROM pg_parameter_acl WHERE parname = 'enable_material';
|
||||
-- Now grant ALTER SYSTEM:
|
||||
GRANT ALL ON PARAMETER enable_material TO PUBLIC;
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'enable_material', 'SET');
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'enable_material', 'ALTER SYSTEM');
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'enable_material', 'SET, ALTER SYSTEM');
|
||||
SELECT 1 FROM pg_parameter_acl WHERE parname = 'enable_material';
|
||||
-- REVOKE ALTER SYSTEM brings us back to just the SET privilege:
|
||||
REVOKE ALTER SYSTEM ON PARAMETER enable_material FROM PUBLIC;
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'enable_material', 'SET');
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'enable_material', 'ALTER SYSTEM');
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'enable_material', 'SET, ALTER SYSTEM');
|
||||
SELECT 1 FROM pg_parameter_acl WHERE parname = 'enable_material';
|
||||
-- And this should remove the entry altogether:
|
||||
REVOKE SET ON PARAMETER enable_material FROM PUBLIC;
|
||||
SELECT 1 FROM pg_parameter_acl WHERE parname = 'enable_material';
|
||||
|
||||
-- Grant privileges on parameters to the new non-superuser role
|
||||
GRANT SET, ALTER SYSTEM ON PARAMETER
|
||||
autovacuum_work_mem, hash_mem_multiplier, max_stack_depth,
|
||||
shared_buffers, temp_file_limit, work_mem
|
||||
TO regress_host_resource_admin;
|
||||
-- Check the new role now has privilges on parameters
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'work_mem', 'SET, ALTER SYSTEM');
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'work_mem', 'SET');
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'work_mem', 'ALTER SYSTEM');
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'work_mem', 'SET WITH GRANT OPTION, ALTER SYSTEM WITH GRANT OPTION');
|
||||
-- Check again the inappropriate and nonsense privilege types. The prior
|
||||
-- similar check was performed before any entry for work_mem existed.
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'work_mem', 'SELECT, UPDATE, CREATE');
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'work_mem', 'USAGE');
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'work_mem', 'WHATEVER');
|
||||
SELECT has_parameter_privilege('regress_host_resource_admin', 'work_mem', 'WHATEVER WITH GRANT OPTION');
|
||||
|
||||
-- Check other function signatures
|
||||
SELECT has_parameter_privilege((SELECT oid FROM pg_catalog.pg_authid WHERE rolname = 'regress_host_resource_admin'),
|
||||
'max_stack_depth',
|
||||
'SET');
|
||||
SELECT has_parameter_privilege('hash_mem_multiplier', 'set');
|
||||
|
||||
-- Check object identity functions
|
||||
SELECT pg_describe_object(tableoid, oid, 0)
|
||||
FROM pg_parameter_acl WHERE parname = 'work_mem';
|
||||
SELECT pg_identify_object(tableoid, oid, 0)
|
||||
FROM pg_parameter_acl WHERE parname = 'work_mem';
|
||||
SELECT pg_identify_object_as_address(tableoid, oid, 0)
|
||||
FROM pg_parameter_acl WHERE parname = 'work_mem';
|
||||
SELECT classid::regclass,
|
||||
(SELECT parname FROM pg_parameter_acl WHERE oid = goa.objid) AS parname,
|
||||
objsubid
|
||||
FROM pg_get_object_address('parameter ACL', '{work_mem}', '{}') goa;
|
||||
|
||||
-- Perform some operations as user 'regress_host_resource_admin'
|
||||
SET SESSION AUTHORIZATION regress_host_resource_admin;
|
||||
ALTER SYSTEM SET autovacuum_work_mem = 32; -- ok, privileges have been granted
|
||||
ALTER SYSTEM SET ignore_system_indexes = OFF; -- fail, insufficient privileges
|
||||
ALTER SYSTEM RESET autovacuum_multixact_freeze_max_age; -- fail, insufficient privileges
|
||||
SET jit_provider = 'llvmjit'; -- fail, insufficient privileges
|
||||
SELECT set_config ('jit_provider', 'llvmjit', true); -- fail, insufficient privileges
|
||||
ALTER SYSTEM SET shared_buffers = 50; -- ok
|
||||
ALTER SYSTEM RESET shared_buffers; -- ok
|
||||
SET autovacuum_work_mem = 50; -- cannot be changed now
|
||||
ALTER SYSTEM RESET temp_file_limit; -- ok
|
||||
SET TimeZone = 'Europe/Helsinki'; -- ok
|
||||
RESET TimeZone; -- ok
|
||||
SET max_stack_depth = 2048; -- ok, privileges have been granted
|
||||
RESET max_stack_depth; -- ok, privileges have been granted
|
||||
ALTER SYSTEM SET max_stack_depth = 2048; -- ok, privileges have been granted
|
||||
ALTER SYSTEM RESET max_stack_depth; -- ok, privileges have been granted
|
||||
SET lc_messages = 'C'; -- fail, insufficient privileges
|
||||
RESET lc_messages; -- fail, insufficient privileges
|
||||
ALTER SYSTEM SET lc_messages = 'C'; -- fail, insufficient privileges
|
||||
ALTER SYSTEM RESET lc_messages; -- fail, insufficient privileges
|
||||
SELECT set_config ('temp_buffers', '8192', false); -- ok
|
||||
ALTER SYSTEM RESET autovacuum_work_mem; -- ok, privileges have been granted
|
||||
ALTER SYSTEM RESET ALL; -- fail, insufficient privileges
|
||||
|
||||
-- Check dropping/revoking behavior
|
||||
SET SESSION AUTHORIZATION regress_admin;
|
||||
DROP ROLE regress_host_resource_admin; -- fail, privileges remain
|
||||
-- Use "revoke" to remove the privileges and allow the role to be dropped
|
||||
REVOKE SET, ALTER SYSTEM ON PARAMETER
|
||||
autovacuum_work_mem, hash_mem_multiplier, max_stack_depth,
|
||||
shared_buffers, temp_file_limit, work_mem
|
||||
FROM regress_host_resource_admin;
|
||||
DROP ROLE regress_host_resource_admin; -- ok
|
||||
|
||||
-- Try that again, but use "drop owned by" instead of "revoke"
|
||||
CREATE ROLE regress_host_resource_admin NOSUPERUSER;
|
||||
SET SESSION AUTHORIZATION regress_host_resource_admin;
|
||||
ALTER SYSTEM SET autovacuum_work_mem = 32; -- fail, privileges not yet granted
|
||||
SET SESSION AUTHORIZATION regress_admin;
|
||||
GRANT SET, ALTER SYSTEM ON PARAMETER
|
||||
autovacuum_work_mem, hash_mem_multiplier, max_stack_depth,
|
||||
shared_buffers, temp_file_limit, work_mem
|
||||
TO regress_host_resource_admin;
|
||||
DROP ROLE regress_host_resource_admin; -- fail, privileges remain
|
||||
DROP OWNED BY regress_host_resource_admin RESTRICT; -- cascade should not be needed
|
||||
SET SESSION AUTHORIZATION regress_host_resource_admin;
|
||||
ALTER SYSTEM SET autovacuum_work_mem = 32; -- fail, "drop owned" has dropped privileges
|
||||
SET SESSION AUTHORIZATION regress_admin;
|
||||
DROP ROLE regress_host_resource_admin; -- ok
|
||||
|
||||
-- Check that "reassign owned" doesn't affect privileges
|
||||
CREATE ROLE regress_host_resource_admin NOSUPERUSER;
|
||||
CREATE ROLE regress_host_resource_newadmin NOSUPERUSER;
|
||||
GRANT SET, ALTER SYSTEM ON PARAMETER
|
||||
autovacuum_work_mem, hash_mem_multiplier, max_stack_depth,
|
||||
shared_buffers, temp_file_limit, work_mem
|
||||
TO regress_host_resource_admin;
|
||||
REASSIGN OWNED BY regress_host_resource_admin TO regress_host_resource_newadmin;
|
||||
SET SESSION AUTHORIZATION regress_host_resource_admin;
|
||||
ALTER SYSTEM SET autovacuum_work_mem = 32; -- ok, "reassign owned" did not change privileges
|
||||
ALTER SYSTEM RESET autovacuum_work_mem; -- ok
|
||||
SET SESSION AUTHORIZATION regress_admin;
|
||||
DROP ROLE regress_host_resource_admin; -- fail, privileges remain
|
||||
DROP ROLE regress_host_resource_newadmin; -- ok, nothing was transferred
|
||||
-- Use "drop owned by" so we can drop the role
|
||||
DROP OWNED BY regress_host_resource_admin; -- ok
|
||||
DROP ROLE regress_host_resource_admin; -- ok
|
||||
|
||||
-- Clean up
|
||||
RESET SESSION AUTHORIZATION;
|
||||
DROP ROLE regress_admin; -- ok
|
Loading…
Reference in New Issue
Block a user