From: Nathan Bossart <nathandbossart@gmail.com>
To: Peter Eisentraut <peter.eisentraut@enterprisedb.com>
Cc: Alvaro Herrera <alvherre@alvh.no-ip.org>
Cc: Tom Lane <tgl@sss.pgh.pa.us>
Cc: Robert Haas <robertmhaas@gmail.com>
Cc: pgsql-hackers@postgresql.org <pgsql-hackers@postgresql.org>
Subject: Re: improving user.c error messages
Date: Mon, 20 Feb 2023 14:58:52 -0800
Message-ID: <20230220225852.GA3940888@nathanxps13> (raw)
In-Reply-To: <20230220190210.GA3481922@nathanxps13>
References: <20230127000936.GA1998073@nathanxps13>
<20230127183119.e5jtyh4g2md57ctb@alvherre.pgsql>
<20230127231507.GA2221340@nathanxps13>
<20230207201009.GA450353@nathanxps13>
<e1bbef97-ed13-f6ad-8d21-b2ebc251394b@enterprisedb.com>
<20230220190210.GA3481922@nathanxps13>
On Mon, Feb 20, 2023 at 11:02:10AM -0800, Nathan Bossart wrote:
> On Mon, Feb 20, 2023 at 08:54:48AM +0100, Peter Eisentraut wrote:
>> I'm concerned about the loose use of "privilege" here. A privilege is
>> something I can grant. So if someone doesn't have the "REPLICATION
>> privilege", as in the above example, I would expect to be able to do "GRANT
>> REPLICATION TO someuser". Since that is not what is happening, we should
>> use some other term. The documentation around CREATE USER uses the terms
>> "attribute" and "option" (and also "privilege") for these things.
>
> Good point. I will adjust these to use "attribute" instead.
done in v6
>> Similarly -- this is an existing issue but we might as well look at it -- in
>> something like
>>
>> must be superuser or a role with privileges of the
>> pg_write_server_files role
>>
>> the phrase "a role with the privileges of that other role" seems ambiguous.
>> Doesn't it really mean you must be a member of that role?
>
> Membership alone is not sufficient. You must also inherit the privileges
> of the role via the INHERIT option. I thought about making this something
> like
>
> must have the INHERIT option on role %s
>
> but I'm not sure that's accurate either. That wording makes it sound lіke
> you need to be granted membership to the role directly WITH INHERIT OPTION,
> but what you really need is membership, direct or indirect, with an INHERIT
> chain up to the role in question. However, it looks like "must have the
> ADMIN option on role %s" is used to mean something similar, so perhaps I am
> overthinking it.
For now, I've reworded these as "must inherit privileges of".
--
Nathan Bossart
Amazon Web Services: https://aws.amazon.comAttachments:download all (2 files, .tar.gz)v6-0001-Improve-user.c-error-messages.patch (text/x-diff, 30.2K) download
From cc6131da14200f32778ca8ba9628f86dccdbd43d Mon Sep 17 00:00:00 2001
From: Nathan Bossart <nathandbossart@gmail.com>
Date: Thu, 26 Jan 2023 11:05:13 -0800
Subject: [PATCH v6 1/2] Improve user.c error messages.
---
src/backend/commands/user.c | 169 ++++++++++++++++------
src/test/regress/expected/create_role.out | 77 ++++++----
src/test/regress/expected/dependency.out | 4 +
src/test/regress/expected/privileges.out | 23 ++-
4 files changed, 198 insertions(+), 75 deletions(-)
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.cindex 3a92e930c0..e92bb656f9 100644--- a/src/backend/commands/user.c+++ b/src/backend/commands/user.c@@ -316,23 +316,33 @@ CreateRole(ParseState *pstate, CreateRoleStmt *stmt)
if (!has_createrole_privilege(currentUserId))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("permission denied to create role")));+ errmsg("permission denied to create role"),+ errdetail("You must have the %s attribute to create roles.",+ "CREATEROLE")));
if (issuper)
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("must be superuser to create superusers")));+ errmsg("permission denied to create role"),+ errdetail("You must have the %s attribute to create roles with %s.",+ "SUPERUSER", "SUPERUSER")));
if (createdb && !have_createdb_privilege())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("must have createdb permission to create createdb users")));+ errmsg("permission denied to create role"),+ errdetail("You must have the %s attribute to create roles with %s.",+ "CREATEDB", "CREATEDB")));
if (isreplication && !has_rolreplication(currentUserId))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("must have replication permission to create replication users")));+ errmsg("permission denied to create role"),+ errdetail("You must have the %s attribute to create roles with %s.",+ "REPLICATION", "REPLICATION")));
if (bypassrls && !has_bypassrls_privilege(currentUserId))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("must have bypassrls to create bypassrls users")));+ errmsg("permission denied to create role"),+ errdetail("You must have the %s attribute to create roles with %s.",+ "BYPASSRLS", "BYPASSRLS")));
}
/*
@@ -744,10 +754,18 @@ AlterRole(ParseState *pstate, AlterRoleStmt *stmt)
roleid = authform->oid;
/* To mess with a superuser in any way you gotta be superuser. */
- if (!superuser() && (authform->rolsuper || dissuper))+ if (!superuser() && authform->rolsuper)
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("must be superuser to alter superuser roles or change superuser attribute")));+ errmsg("permission denied to alter role"),+ errdetail("You must have the %s attribute to alter roles with %s.",+ "SUPERUSER", "SUPERUSER")));+ if (!superuser() && dissuper)+ ereport(ERROR,+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),+ errmsg("permission denied to alter role"),+ errdetail("You must have the %s attribute to change the %s attribute.",+ "SUPERUSER", "SUPERUSER")));
/*
* Most changes to a role require that you both have CREATEROLE privileges
@@ -761,13 +779,17 @@ AlterRole(ParseState *pstate, AlterRoleStmt *stmt)
dvalidUntil || disreplication || dbypassRLS)
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("permission denied")));+ errmsg("permission denied to alter role"),+ errdetail("You must have the %s attribute and the %s option on role \"%s\".",+ "CREATEROLE", "ADMIN", rolename)));
/* an unprivileged user can change their own password */
if (dpassword && roleid != currentUserId)
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("must have CREATEROLE privilege to change another user's password")));+ errmsg("permission denied to alter role"),+ errdetail("To change another role's password, you must have the %s attribute and the %s option on the role.",+ "CREATEROLE", "ADMIN")));
}
else if (!superuser())
{
@@ -779,23 +801,30 @@ AlterRole(ParseState *pstate, AlterRoleStmt *stmt)
if (dcreatedb && !have_createdb_privilege())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("must have createdb privilege to change createdb attribute")));+ errmsg("permission denied to alter role"),+ errdetail("You must have the %s attribute to change the %s attribute.",+ "CREATEDB", "CREATEDB")));
if (disreplication && !has_rolreplication(currentUserId))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("must have replication privilege to change replication attribute")));+ errmsg("permission denied to alter role"),+ errdetail("You must have the %s attribute to change the %s attribute.",+ "REPLICATION", "REPLICATION")));
if (dbypassRLS && !has_bypassrls_privilege(currentUserId))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("must have bypassrls privilege to change bypassrls attribute")));+ errmsg("permission denied to alter role"),+ errdetail("You must have the %s attribute to change the %s attribute.",+ "BYPASSRLS", "BYPASSRLS")));
}
/* To add members to a role, you need ADMIN OPTION. */
if (drolemembers && !is_admin_of_role(currentUserId, roleid))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("must have admin option on role \"%s\" to add members",- rolename)));+ errmsg("permission denied to alter role"),+ errdetail("You must have the %s option on role \"%s\" to add members.",+ "ADMIN", rolename)));
/* Convert validuntil to internal form */
if (dvalidUntil)
@@ -837,8 +866,10 @@ AlterRole(ParseState *pstate, AlterRoleStmt *stmt)
if (!should_be_super && roleid == BOOTSTRAP_SUPERUSERID)
ereport(ERROR,
- (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),- errmsg("permission denied: bootstrap user must be superuser")));+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),+ errmsg("permission denied to alter role"),+ errdetail("The bootstrap user must have the %s attribute.",+ "SUPERUSER")));
new_record[Anum_pg_authid_rolsuper - 1] = BoolGetDatum(should_be_super);
new_record_repl[Anum_pg_authid_rolsuper - 1] = true;
@@ -999,7 +1030,9 @@ AlterRoleSet(AlterRoleSetStmt *stmt)
if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("must be superuser to alter superusers")));+ errmsg("permission denied to alter role"),+ errdetail("You must have the %s attribute to alter roles with %s.",+ "SUPERUSER", "SUPERUSER")));
}
else
{
@@ -1008,7 +1041,9 @@ AlterRoleSet(AlterRoleSetStmt *stmt)
&& roleid != GetUserId())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("permission denied")));+ errmsg("permission denied to alter role"),+ errdetail("You must have the %s attribute and the %s option on role \"%s\".",+ "CREATROLE", "ADMIN", NameStr(roleform->rolname))));
}
ReleaseSysCache(roletuple);
@@ -1038,7 +1073,9 @@ AlterRoleSet(AlterRoleSetStmt *stmt)
if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("must be superuser to alter settings globally")));+ errmsg("permission denied to alter setting"),+ errdetail("You must have the %s attribute to alter settings globally.",+ "SUPERUSER")));
}
AlterSetting(databaseid, roleid, stmt->setstmt);
@@ -1061,7 +1098,9 @@ DropRole(DropRoleStmt *stmt)
if (!have_createrole_privilege())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("permission denied to drop role")));+ errmsg("permission denied to drop role"),+ errdetail("You must have the %s attribute and the %s option on the target roles.",+ "CREATEROLE", "ADMIN")));
/*
* Scan the pg_authid relation to find the Oid of the role(s) to be
@@ -1131,12 +1170,15 @@ DropRole(DropRoleStmt *stmt)
if (roleform->rolsuper && !superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("must be superuser to drop superusers")));+ errmsg("permission denied to drop role"),+ errdetail("You must have the %s attribute to drop roles with %s.",+ "SUPERUSER", "SUPERUSER")));
if (!is_admin_of_role(GetUserId(), roleid))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("must have admin option on role \"%s\"",- role)));+ errmsg("permission denied to drop role"),+ errdetail("You must have the %s attribute and the %s option on role \"%s\".",+ "CREATEROLE", "ADMIN", NameStr(roleform->rolname))));
/* DROP hook for the role being removed */
InvokeObjectDropHook(AuthIdRelationId, roleid, 0);
@@ -1378,12 +1420,14 @@ RenameRole(const char *oldname, const char *newname)
* Only superusers can mess with superusers. Otherwise, a user with
* CREATEROLE can rename a role for which they have ADMIN OPTION.
*/
- if (((Form_pg_authid) GETSTRUCT(oldtuple))->rolsuper)+ if (authform->rolsuper)
{
if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("must be superuser to rename superusers")));+ errmsg("permission denied to rename role"),+ errdetail("You must have the %s attribute to rename roles with %s.",+ "SUPERUSER", "SUPERUSER")));
}
else
{
@@ -1391,7 +1435,9 @@ RenameRole(const char *oldname, const char *newname)
!is_admin_of_role(GetUserId(), roleid))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("permission denied to rename role")));+ errmsg("permission denied to rename role"),+ errdetail("You must have the %s attribute and the %s option on role \"%s\".",+ "CREATEROLE", "ADMIN", NameStr(authform->rolname))));
}
/* OK, construct the modified tuple */
@@ -1554,7 +1600,9 @@ DropOwnedObjects(DropOwnedStmt *stmt)
if (!has_privs_of_role(GetUserId(), roleid))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("permission denied to drop objects")));+ errmsg("permission denied to drop objects"),+ errdetail("You must inherit privileges of role \"%s\".",+ GetUserNameFromId(roleid, false))));
}
/* Ok, do it */
@@ -1581,7 +1629,9 @@ ReassignOwnedObjects(ReassignOwnedStmt *stmt)
if (!has_privs_of_role(GetUserId(), roleid))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("permission denied to reassign objects")));+ errmsg("permission denied to reassign objects"),+ errdetail("You must inherit privileges of role \"%s\".",+ GetUserNameFromId(roleid, false))));
}
/* Must have privileges on the receiving side too */
@@ -1590,7 +1640,9 @@ ReassignOwnedObjects(ReassignOwnedStmt *stmt)
if (!has_privs_of_role(GetUserId(), newrole))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("permission denied to reassign objects")));+ errmsg("permission denied to reassign objects"),+ errdetail("You must inherit privileges role \"%s\".",+ GetUserNameFromId(newrole, false))));
/* Ok, do it */
shdepReassignOwned(role_ids, newrole);
@@ -1738,7 +1790,8 @@ AddRoleMems(Oid currentUserId, const char *rolename, Oid roleid,
if (memberid == BOOTSTRAP_SUPERUSERID)
ereport(ERROR,
(errcode(ERRCODE_INVALID_GRANT_OPERATION),
- errmsg("admin option cannot be granted back to your own grantor")));+ errmsg("%s option cannot be granted back to your own grantor",+ "ADMIN")));
plan_member_revoke(memlist, actions, memberid);
}
@@ -1763,7 +1816,8 @@ AddRoleMems(Oid currentUserId, const char *rolename, Oid roleid,
if (i >= memlist->n_members)
ereport(ERROR,
(errcode(ERRCODE_INVALID_GRANT_OPERATION),
- errmsg("admin option cannot be granted back to your own grantor")));+ errmsg("%s option cannot be granted back to your own grantor",+ "ADMIN")));
ReleaseSysCacheList(memlist);
}
@@ -2081,9 +2135,22 @@ check_role_membership_authorization(Oid currentUserId, Oid roleid,
if (superuser_arg(roleid))
{
if (!superuser_arg(currentUserId))
- ereport(ERROR,- (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),- errmsg("must be superuser to alter superusers")));+ {+ if (is_grant)+ ereport(ERROR,+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),+ errmsg("permission denied to grant role \"%s\"",+ GetUserNameFromId(roleid, false)),+ errdetail("You must have the %s attribute to grant roles with %s.",+ "SUPERUSER", "SUPERUSER")));+ else+ ereport(ERROR,+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),+ errmsg("permission denied to revoke role \"%s\"",+ GetUserNameFromId(roleid, false)),+ errdetail("You must have the %s attribute to revoke roles with %s.",+ "SUPERUSER", "SUPERUSER")));+ }
}
else
{
@@ -2091,10 +2158,22 @@ check_role_membership_authorization(Oid currentUserId, Oid roleid,
* Otherwise, must have admin option on the role to be changed.
*/
if (!is_admin_of_role(currentUserId, roleid))
- ereport(ERROR,- (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),- errmsg("must have admin option on role \"%s\"",- GetUserNameFromId(roleid, false))));+ {+ if (is_grant)+ ereport(ERROR,+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),+ errmsg("permission denied to grant role \"%s\"",+ GetUserNameFromId(roleid, false)),+ errdetail("You must have the %s option on role \"%s\".",+ "ADMIN", GetUserNameFromId(roleid, false))));+ else+ ereport(ERROR,+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),+ errmsg("permission denied to revoke role \"%s\"",+ GetUserNameFromId(roleid, false)),+ errdetail("You must have the %s option on role \"%s\".",+ "ADMIN", GetUserNameFromId(roleid, false))));+ }
}
}
@@ -2173,14 +2252,18 @@ check_role_grantor(Oid currentUserId, Oid roleid, Oid grantorId, bool is_grant)
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to grant privileges as role \"%s\"",
- GetUserNameFromId(grantorId, false))));+ GetUserNameFromId(grantorId, false)),+ errdetail("You must inherit privileges of role \"%s\".",+ GetUserNameFromId(grantorId, false))));
if (grantorId != BOOTSTRAP_SUPERUSERID &&
select_best_admin(grantorId, roleid) != grantorId)
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("grantor must have ADMIN OPTION on \"%s\"",- GetUserNameFromId(roleid, false))));+ errmsg("permission denied to grant privileges as role \"%s\"",+ GetUserNameFromId(grantorId, false)),+ errdetail("The grantor must have the %s option on role \"%s\".",+ "ADMIN", GetUserNameFromId(roleid, false))));
}
else
{
@@ -2188,7 +2271,9 @@ check_role_grantor(Oid currentUserId, Oid roleid, Oid grantorId, bool is_grant)
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to revoke privileges granted by role \"%s\"",
- GetUserNameFromId(grantorId, false))));+ GetUserNameFromId(grantorId, false)),+ errdetail("You must inherit privileges of role \"%s\".",+ GetUserNameFromId(grantorId, false))));
}
/*
diff --git a/src/test/regress/expected/create_role.out b/src/test/regress/expected/create_role.outindex 9f431bd4f5..7157d4c589 100644--- a/src/test/regress/expected/create_role.out+++ b/src/test/regress/expected/create_role.out@@ -7,26 +7,35 @@ CREATE ROLE regress_role_normal;
-- fail, CREATEROLE user can't give away role attributes without having them
SET SESSION AUTHORIZATION regress_role_limited_admin;
CREATE ROLE regress_nosuch_superuser SUPERUSER;
-ERROR: must be superuser to create superusers+ERROR: permission denied to create role+DETAIL: You must have the SUPERUSER attribute to create roles with SUPERUSER.
CREATE ROLE regress_nosuch_replication_bypassrls REPLICATION BYPASSRLS;
-ERROR: must have replication permission to create replication users+ERROR: permission denied to create role+DETAIL: You must have the REPLICATION attribute to create roles with REPLICATION.
CREATE ROLE regress_nosuch_replication REPLICATION;
-ERROR: must have replication permission to create replication users+ERROR: permission denied to create role+DETAIL: You must have the REPLICATION attribute to create roles with REPLICATION.
CREATE ROLE regress_nosuch_bypassrls BYPASSRLS;
-ERROR: must have bypassrls to create bypassrls users+ERROR: permission denied to create role+DETAIL: You must have the BYPASSRLS attribute to create roles with BYPASSRLS.
CREATE ROLE regress_nosuch_createdb CREATEDB;
-ERROR: must have createdb permission to create createdb users+ERROR: permission denied to create role+DETAIL: You must have the CREATEDB attribute to create roles with CREATEDB.
-- ok, can create a role without any special attributes
CREATE ROLE regress_role_limited;
-- fail, can't give it in any of the restricted attributes
ALTER ROLE regress_role_limited SUPERUSER;
-ERROR: must be superuser to alter superuser roles or change superuser attribute+ERROR: permission denied to alter role+DETAIL: You must have the SUPERUSER attribute to change the SUPERUSER attribute.
ALTER ROLE regress_role_limited REPLICATION;
-ERROR: must have replication privilege to change replication attribute+ERROR: permission denied to alter role+DETAIL: You must have the REPLICATION attribute to change the REPLICATION attribute.
ALTER ROLE regress_role_limited CREATEDB;
-ERROR: must have createdb privilege to change createdb attribute+ERROR: permission denied to alter role+DETAIL: You must have the CREATEDB attribute to change the CREATEDB attribute.
ALTER ROLE regress_role_limited BYPASSRLS;
-ERROR: must have bypassrls privilege to change bypassrls attribute+ERROR: permission denied to alter role+DETAIL: You must have the BYPASSRLS attribute to change the BYPASSRLS attribute.
DROP ROLE regress_role_limited;
-- ok, can give away these role attributes if you have them
SET SESSION AUTHORIZATION regress_role_admin;
@@ -43,9 +52,11 @@ ALTER ROLE regress_createdb NOCREATEDB;
ALTER ROLE regress_createdb CREATEDB;
-- fail, can't toggle SUPERUSER
ALTER ROLE regress_createdb SUPERUSER;
-ERROR: must be superuser to alter superuser roles or change superuser attribute+ERROR: permission denied to alter role+DETAIL: You must have the SUPERUSER attribute to change the SUPERUSER attribute.
ALTER ROLE regress_createdb NOSUPERUSER;
-ERROR: must be superuser to alter superuser roles or change superuser attribute+ERROR: permission denied to alter role+DETAIL: You must have the SUPERUSER attribute to change the SUPERUSER attribute.
-- ok, having CREATEROLE is enough to create users with these privileges
CREATE ROLE regress_createrole CREATEROLE NOINHERIT;
GRANT CREATE ON DATABASE regression TO regress_createrole WITH GRANT OPTION;
@@ -59,7 +70,8 @@ CREATE ROLE regress_noiseword SYSID 12345;
NOTICE: SYSID can no longer be specified
-- fail, cannot grant membership in superuser role
CREATE ROLE regress_nosuch_super IN ROLE regress_role_super;
-ERROR: must be superuser to alter superusers+ERROR: permission denied to grant role "regress_role_super"+DETAIL: You must have the SUPERUSER attribute to grant roles with SUPERUSER.
-- fail, database owner cannot have members
CREATE ROLE regress_nosuch_dbowner IN ROLE pg_database_owner;
ERROR: role "pg_database_owner" cannot have explicit members
@@ -97,8 +109,10 @@ COMMENT ON ROLE regress_role_normal IS 'some comment';
ERROR: must have admin option on role "regress_role_normal"
ALTER ROLE regress_role_normal RENAME TO regress_role_abnormal;
ERROR: permission denied to rename role
+DETAIL: You must have the CREATEROLE attribute and the ADMIN option on role "regress_role_normal".
ALTER ROLE regress_role_normal NOINHERIT NOLOGIN CONNECTION LIMIT 7;
-ERROR: permission denied+ERROR: permission denied to alter role+DETAIL: You must have the CREATEROLE attribute and the ADMIN option on role "regress_role_normal".
-- ok, regress_tenant can create objects within the database
SET SESSION AUTHORIZATION regress_tenant;
CREATE TABLE tenant_table (i integer);
@@ -123,6 +137,7 @@ ERROR: must be able to SET ROLE "regress_tenant"
-- fail, we don't inherit permissions from regress_tenant
REASSIGN OWNED BY regress_tenant TO regress_createrole;
ERROR: permission denied to reassign objects
+DETAIL: You must inherit privileges of role "regress_tenant".
-- ok, create a role with a value for createrole_self_grant
SET createrole_self_grant = 'set, inherit';
CREATE ROLE regress_tenant2;
@@ -150,25 +165,35 @@ ERROR: must be able to SET ROLE "regress_tenant2"
DROP TABLE tenant2_table;
-- fail, CREATEROLE is not enough to create roles in privileged roles
CREATE ROLE regress_read_all_data IN ROLE pg_read_all_data;
-ERROR: must have admin option on role "pg_read_all_data"+ERROR: permission denied to grant role "pg_read_all_data"+DETAIL: You must have the ADMIN option on role "pg_read_all_data".
CREATE ROLE regress_write_all_data IN ROLE pg_write_all_data;
-ERROR: must have admin option on role "pg_write_all_data"+ERROR: permission denied to grant role "pg_write_all_data"+DETAIL: You must have the ADMIN option on role "pg_write_all_data".
CREATE ROLE regress_monitor IN ROLE pg_monitor;
-ERROR: must have admin option on role "pg_monitor"+ERROR: permission denied to grant role "pg_monitor"+DETAIL: You must have the ADMIN option on role "pg_monitor".
CREATE ROLE regress_read_all_settings IN ROLE pg_read_all_settings;
-ERROR: must have admin option on role "pg_read_all_settings"+ERROR: permission denied to grant role "pg_read_all_settings"+DETAIL: You must have the ADMIN option on role "pg_read_all_settings".
CREATE ROLE regress_read_all_stats IN ROLE pg_read_all_stats;
-ERROR: must have admin option on role "pg_read_all_stats"+ERROR: permission denied to grant role "pg_read_all_stats"+DETAIL: You must have the ADMIN option on role "pg_read_all_stats".
CREATE ROLE regress_stat_scan_tables IN ROLE pg_stat_scan_tables;
-ERROR: must have admin option on role "pg_stat_scan_tables"+ERROR: permission denied to grant role "pg_stat_scan_tables"+DETAIL: You must have the ADMIN option on role "pg_stat_scan_tables".
CREATE ROLE regress_read_server_files IN ROLE pg_read_server_files;
-ERROR: must have admin option on role "pg_read_server_files"+ERROR: permission denied to grant role "pg_read_server_files"+DETAIL: You must have the ADMIN option on role "pg_read_server_files".
CREATE ROLE regress_write_server_files IN ROLE pg_write_server_files;
-ERROR: must have admin option on role "pg_write_server_files"+ERROR: permission denied to grant role "pg_write_server_files"+DETAIL: You must have the ADMIN option on role "pg_write_server_files".
CREATE ROLE regress_execute_server_program IN ROLE pg_execute_server_program;
-ERROR: must have admin option on role "pg_execute_server_program"+ERROR: permission denied to grant role "pg_execute_server_program"+DETAIL: You must have the ADMIN option on role "pg_execute_server_program".
CREATE ROLE regress_signal_backend IN ROLE pg_signal_backend;
-ERROR: must have admin option on role "pg_signal_backend"+ERROR: permission denied to grant role "pg_signal_backend"+DETAIL: You must have the ADMIN option on role "pg_signal_backend".
-- fail, role still owns database objects
DROP ROLE regress_tenant;
ERROR: role "regress_tenant" cannot be dropped because some objects depend on it
@@ -211,11 +236,13 @@ DROP ROLE regress_inroles;
DROP ROLE regress_adminroles;
-- fail, cannot drop ourself, nor superusers or roles we lack ADMIN for
DROP ROLE regress_role_super;
-ERROR: must be superuser to drop superusers+ERROR: permission denied to drop role+DETAIL: You must have the SUPERUSER attribute to drop roles with SUPERUSER.
DROP ROLE regress_role_admin;
ERROR: current user cannot be dropped
DROP ROLE regress_rolecreator;
-ERROR: must have admin option on role "regress_rolecreator"+ERROR: permission denied to drop role+DETAIL: You must have the CREATEROLE attribute and the ADMIN option on role "regress_rolecreator".
-- ok
RESET SESSION AUTHORIZATION;
REVOKE CREATE ON DATABASE regression FROM regress_role_admin CASCADE;
diff --git a/src/test/regress/expected/dependency.out b/src/test/regress/expected/dependency.outindex 520035f6a0..d1e8dcdf5c 100644--- a/src/test/regress/expected/dependency.out+++ b/src/test/regress/expected/dependency.out@@ -48,12 +48,16 @@ SET SESSION AUTHORIZATION regress_dep_user0;
-- permission denied
DROP OWNED BY regress_dep_user1;
ERROR: permission denied to drop objects
+DETAIL: You must inherit privileges of role "regress_dep_user1".
DROP OWNED BY regress_dep_user0, regress_dep_user2;
ERROR: permission denied to drop objects
+DETAIL: You must inherit privileges of role "regress_dep_user2".
REASSIGN OWNED BY regress_dep_user0 TO regress_dep_user1;
ERROR: permission denied to reassign objects
+DETAIL: You must inherit privileges role "regress_dep_user1".
REASSIGN OWNED BY regress_dep_user1 TO regress_dep_user0;
ERROR: permission denied to reassign objects
+DETAIL: You must inherit privileges of role "regress_dep_user1".
-- this one is allowed
DROP OWNED BY regress_dep_user0;
CREATE TABLE deptest1 (f1 int unique);
diff --git a/src/test/regress/expected/privileges.out b/src/test/regress/expected/privileges.outindex 95d1e5515f..72829ad764 100644--- a/src/test/regress/expected/privileges.out+++ b/src/test/regress/expected/privileges.out@@ -37,7 +37,7 @@ CREATE ROLE regress_priv_role;
GRANT regress_priv_user1 TO regress_priv_user2 WITH ADMIN OPTION;
GRANT regress_priv_user1 TO regress_priv_user3 WITH ADMIN OPTION GRANTED BY regress_priv_user2;
GRANT regress_priv_user1 TO regress_priv_user2 WITH ADMIN OPTION GRANTED BY regress_priv_user3;
-ERROR: admin option cannot be granted back to your own grantor+ERROR: ADMIN option cannot be granted back to your own grantor
-- need CASCADE to revoke grant or admin option if dependent grants exist
REVOKE ADMIN OPTION FOR regress_priv_user1 FROM regress_priv_user2; -- fail
ERROR: dependent privileges exist
@@ -156,7 +156,8 @@ ALTER GROUP regress_priv_group2 ADD USER regress_priv_user2; -- duplicate
NOTICE: role "regress_priv_user2" has already been granted membership in role "regress_priv_group2" by role "regress_priv_user1"
ALTER GROUP regress_priv_group2 DROP USER regress_priv_user2;
ALTER USER regress_priv_user2 PASSWORD 'verysecret'; -- not permitted
-ERROR: must have CREATEROLE privilege to change another user's password+ERROR: permission denied to alter role+DETAIL: To change another role's password, you must have the CREATEROLE attribute and the ADMIN option on the role.
RESET SESSION AUTHORIZATION;
ALTER GROUP regress_priv_group2 DROP USER regress_priv_user2;
REVOKE ADMIN OPTION FOR regress_priv_group2 FROM regress_priv_user1;
@@ -168,7 +169,8 @@ CREATE FUNCTION leak(integer,integer) RETURNS boolean
ALTER FUNCTION leak(integer,integer) OWNER TO regress_priv_user1;
-- test owner privileges
GRANT regress_priv_role TO regress_priv_user1 WITH ADMIN OPTION GRANTED BY regress_priv_role; -- error, doesn't have ADMIN OPTION
-ERROR: grantor must have ADMIN OPTION on "regress_priv_role"+ERROR: permission denied to grant privileges as role "regress_priv_role"+DETAIL: The grantor must have the ADMIN option on role "regress_priv_role".
GRANT regress_priv_role TO regress_priv_user1 WITH ADMIN OPTION GRANTED BY CURRENT_ROLE;
REVOKE ADMIN OPTION FOR regress_priv_role FROM regress_priv_user1 GRANTED BY foo; -- error
ERROR: role "foo" does not exist
@@ -1795,7 +1797,8 @@ REFRESH MATERIALIZED VIEW sro_mv;
ERROR: cannot fire deferred trigger within security-restricted operation
CONTEXT: SQL function "mv_action" statement 1
BEGIN; SET CONSTRAINTS ALL IMMEDIATE; REFRESH MATERIALIZED VIEW sro_mv; COMMIT;
-ERROR: must have admin option on role "regress_priv_group2"+ERROR: permission denied to grant role "regress_priv_group2"+DETAIL: You must have the ADMIN option on role "regress_priv_group2".
CONTEXT: SQL function "unwanted_grant" statement 1
SQL statement "SELECT unwanted_grant()"
PL/pgSQL function sro_trojan() line 1 at PERFORM
@@ -1825,10 +1828,12 @@ CREATE FUNCTION dogrant_ok() RETURNS void LANGUAGE sql SECURITY DEFINER AS
GRANT regress_priv_group2 TO regress_priv_user5; -- ok: had ADMIN OPTION
SET ROLE regress_priv_group2;
GRANT regress_priv_group2 TO regress_priv_user5; -- fails: SET ROLE suspended privilege
-ERROR: must have admin option on role "regress_priv_group2"+ERROR: permission denied to grant role "regress_priv_group2"+DETAIL: You must have the ADMIN option on role "regress_priv_group2".
SET SESSION AUTHORIZATION regress_priv_user1;
GRANT regress_priv_group2 TO regress_priv_user5; -- fails: no ADMIN OPTION
-ERROR: must have admin option on role "regress_priv_group2"+ERROR: permission denied to grant role "regress_priv_group2"+DETAIL: You must have the ADMIN option on role "regress_priv_group2".
SELECT dogrant_ok(); -- ok: SECURITY DEFINER conveys ADMIN
NOTICE: role "regress_priv_user5" has already been granted membership in role "regress_priv_group2" by role "regress_priv_user4"
dogrant_ok
@@ -1838,10 +1843,12 @@ NOTICE: role "regress_priv_user5" has already been granted membership in role "
SET ROLE regress_priv_group2;
GRANT regress_priv_group2 TO regress_priv_user5; -- fails: SET ROLE did not help
-ERROR: must have admin option on role "regress_priv_group2"+ERROR: permission denied to grant role "regress_priv_group2"+DETAIL: You must have the ADMIN option on role "regress_priv_group2".
SET SESSION AUTHORIZATION regress_priv_group2;
GRANT regress_priv_group2 TO regress_priv_user5; -- fails: no self-admin
-ERROR: must have admin option on role "regress_priv_group2"+ERROR: permission denied to grant role "regress_priv_group2"+DETAIL: You must have the ADMIN option on role "regress_priv_group2".
SET SESSION AUTHORIZATION regress_priv_user4;
DROP FUNCTION dogrant_ok();
REVOKE regress_priv_group2 FROM regress_priv_user5;
--
2.25.1
v6-0002-Improve-more-insufficient-privileges-error-messag.patch (text/x-diff, 19.7K) download
From 4664631c96a303d2066380966d31df113e1fea06 Mon Sep 17 00:00:00 2001
From: Nathan Bossart <nathandbossart@gmail.com>
Date: Fri, 27 Jan 2023 14:52:57 -0800
Subject: [PATCH v6 2/2] Improve more insufficient-privileges error messages.
---
contrib/file_fdw/expected/file_fdw.out | 3 ++-
contrib/file_fdw/file_fdw.c | 8 ++++++--
contrib/test_decoding/expected/permissions.out | 12 ++++++++----
src/backend/backup/basebackup_server.c | 4 +++-
src/backend/catalog/objectaddress.c | 16 +++++++++++-----
src/backend/commands/copy.c | 12 +++++++++---
src/backend/replication/slot.c | 6 ++++--
src/backend/storage/ipc/procarray.c | 4 +++-
src/backend/storage/ipc/signalfuncs.c | 16 ++++++++++++----
src/backend/tcop/utility.c | 5 ++++-
src/backend/utils/init/miscinit.c | 4 ++++
src/backend/utils/init/postinit.c | 12 ++++++++----
src/backend/utils/misc/guc.c | 15 +++++++++------
.../dummy_seclabel/expected/dummy_seclabel.out | 3 ++-
.../modules/unsafe_tests/expected/rolenames.out | 3 ++-
src/test/regress/expected/create_role.out | 3 ++-
16 files changed, 89 insertions(+), 37 deletions(-)
diff --git a/contrib/file_fdw/expected/file_fdw.out b/contrib/file_fdw/expected/file_fdw.outindex 36d76ba26c..ea7afd6fe8 100644--- a/contrib/file_fdw/expected/file_fdw.out+++ b/contrib/file_fdw/expected/file_fdw.out@@ -474,7 +474,8 @@ ALTER FOREIGN TABLE agg_text OWNER TO regress_file_fdw_user;
ALTER FOREIGN TABLE agg_text OPTIONS (SET format 'text');
SET ROLE regress_file_fdw_user;
ALTER FOREIGN TABLE agg_text OPTIONS (SET format 'text');
-ERROR: only superuser or a role with privileges of the pg_read_server_files role may specify the filename option of a file_fdw foreign table+ERROR: permission denied to set the "filename" option of a file_fdw foreign table+DETAIL: You must inherit privileges of the "pg_read_server_files" role to set this option.
SET ROLE regress_file_fdw_superuser;
-- cleanup
RESET ROLE;
diff --git a/contrib/file_fdw/file_fdw.c b/contrib/file_fdw/file_fdw.cindex 8ccc167548..8553d93b3f 100644--- a/contrib/file_fdw/file_fdw.c+++ b/contrib/file_fdw/file_fdw.c@@ -278,13 +278,17 @@ file_fdw_validator(PG_FUNCTION_ARGS)
!has_privs_of_role(GetUserId(), ROLE_PG_READ_SERVER_FILES))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("only superuser or a role with privileges of the pg_read_server_files role may specify the filename option of a file_fdw foreign table")));+ errmsg("permission denied to set the \"filename\" option of a file_fdw foreign table"),+ errdetail("You must inherit privileges of the \"%s\" role to set this option.",+ "pg_read_server_files")));
if (strcmp(def->defname, "program") == 0 &&
!has_privs_of_role(GetUserId(), ROLE_PG_EXECUTE_SERVER_PROGRAM))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("only superuser or a role with privileges of the pg_execute_server_program role may specify the program option of a file_fdw foreign table")));+ errmsg("permission denied to set the \"program\" option of a file_fdw foreign table"),+ errdetail("You must inherit privileges of the \"%s\" role to set this option.",+ "pg_execute_server_program")));
filename = defGetString(def);
}
diff --git a/contrib/test_decoding/expected/permissions.out b/contrib/test_decoding/expected/permissions.outindex ed97f81dda..b45f5cf0df 100644--- a/contrib/test_decoding/expected/permissions.out+++ b/contrib/test_decoding/expected/permissions.out@@ -54,13 +54,16 @@ RESET ROLE;
-- plain user *can't* can control replication
SET ROLE regress_lr_normal;
SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot', 'test_decoding');
-ERROR: must be superuser or replication role to use replication slots+ERROR: permission denied to use replication slots+DETAIL: You must have the REPLICATION attribute to use replication slots.
INSERT INTO lr_test VALUES('lr_superuser_init');
ERROR: permission denied for table lr_test
SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1');
-ERROR: must be superuser or replication role to use replication slots+ERROR: permission denied to use replication slots+DETAIL: You must have the REPLICATION attribute to use replication slots.
SELECT pg_drop_replication_slot('regression_slot');
-ERROR: must be superuser or replication role to use replication slots+ERROR: permission denied to use replication slots+DETAIL: You must have the REPLICATION attribute to use replication slots.
RESET ROLE;
-- replication users can drop superuser created slots
SET ROLE regress_lr_superuser;
@@ -90,7 +93,8 @@ SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot', 'test_d
RESET ROLE;
SET ROLE regress_lr_normal;
SELECT pg_drop_replication_slot('regression_slot');
-ERROR: must be superuser or replication role to use replication slots+ERROR: permission denied to use replication slots+DETAIL: You must have the REPLICATION attribute to use replication slots.
RESET ROLE;
-- all users can see existing slots
SET ROLE regress_lr_superuser;
diff --git a/src/backend/backup/basebackup_server.c b/src/backend/backup/basebackup_server.cindex 0258d7a03b..aac64408d1 100644--- a/src/backend/backup/basebackup_server.c+++ b/src/backend/backup/basebackup_server.c@@ -72,7 +72,9 @@ bbsink_server_new(bbsink *next, char *pathname)
if (!has_privs_of_role(GetUserId(), ROLE_PG_WRITE_SERVER_FILES))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("must be superuser or a role with privileges of the pg_write_server_files role to create backup stored on server")));+ errmsg("permission denied to create backup stored on server"),+ errdetail("You must inherit privileges of the \"%s\" role.",+ "pg_write_server_files")));
CommitTransactionCommand();
/*
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.cindex 2f688166e1..c1ab4ea161 100644--- a/src/backend/catalog/objectaddress.c+++ b/src/backend/catalog/objectaddress.c@@ -2547,20 +2547,26 @@ check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address,
if (!superuser_arg(roleid))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("must be superuser")));+ errmsg("permission denied"),+ errdetail("You must have the %s attribute.",+ "SUPERUSER")));
}
else
{
if (!has_createrole_privilege(roleid))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("must have CREATEROLE privilege")));+ errmsg("permission denied"),+ errdetail("You must have the %s attribute.",+ "CREATEROLE")));
if (!is_admin_of_role(roleid, address.objectId))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("must have admin option on role \"%s\"",- GetUserNameFromId(address.objectId,- true))));+ errmsg("permission denied"),+ errdetail("You must have the %s option on role \"%s\".",+ "ADMIN",+ GetUserNameFromId(address.objectId,+ true))));
}
break;
case OBJECT_TSPARSER:
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.cindex e34f583ea7..388cfd7cae 100644--- a/src/backend/commands/copy.c+++ b/src/backend/commands/copy.c@@ -83,7 +83,9 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
if (!has_privs_of_role(GetUserId(), ROLE_PG_EXECUTE_SERVER_PROGRAM))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("must be superuser or have privileges of the pg_execute_server_program role to COPY to or from an external program"),+ errmsg("permission denied to COPY to or from an external program"),+ errdetail("You must inherit privileges of the \"%s\" role.",+ "pg_execute_server_program"),
errhint("Anyone can COPY to stdout or from stdin. "
"psql's \\copy command also works for anyone.")));
}
@@ -92,14 +94,18 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
if (is_from && !has_privs_of_role(GetUserId(), ROLE_PG_READ_SERVER_FILES))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("must be superuser or have privileges of the pg_read_server_files role to COPY from a file"),+ errmsg("permission denied to COPY from a file"),+ errdetail("You must inherit privileges of the \"%s\" role.",+ "pg_read_server_files"),
errhint("Anyone can COPY to stdout or from stdin. "
"psql's \\copy command also works for anyone.")));
if (!is_from && !has_privs_of_role(GetUserId(), ROLE_PG_WRITE_SERVER_FILES))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("must be superuser or have privileges of the pg_write_server_files role to COPY to a file"),+ errmsg("permission denied to COPY to a file"),+ errdetail("You must inherit privileges of the \"%s\" role.",+ "pg_write_server_files"),
errhint("Anyone can COPY to stdout or from stdin. "
"psql's \\copy command also works for anyone.")));
}
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.cindex f286918f69..51adcd8418 100644--- a/src/backend/replication/slot.c+++ b/src/backend/replication/slot.c@@ -1140,10 +1140,12 @@ CheckSlotRequirements(void)
void
CheckSlotPermissions(void)
{
- if (!superuser() && !has_rolreplication(GetUserId()))+ if (!has_rolreplication(GetUserId()))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("must be superuser or replication role to use replication slots")));+ errmsg("permission denied to use replication slots"),+ errdetail("You must have the %s attribute to use replication slots.",+ "REPLICATION")));
}
/*
diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.cindex a7071b2fce..09a69f2c76 100644--- a/src/backend/storage/ipc/procarray.c+++ b/src/backend/storage/ipc/procarray.c@@ -3860,7 +3860,9 @@ TerminateOtherDBBackends(Oid databaseId)
!has_privs_of_role(GetUserId(), ROLE_PG_SIGNAL_BACKEND))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("must be a member of the role whose process is being terminated or member of pg_signal_backend")));+ errmsg("permission denied to terminate process"),+ errdetail("You must inherit privileges of the role whose process is being terminated or inherit privileges of the \"%s\" role.",+ "pg_signal_backend")));
}
}
diff --git a/src/backend/storage/ipc/signalfuncs.c b/src/backend/storage/ipc/signalfuncs.cindex bc93ab5b52..c1be67e7d0 100644--- a/src/backend/storage/ipc/signalfuncs.c+++ b/src/backend/storage/ipc/signalfuncs.c@@ -121,12 +121,16 @@ pg_cancel_backend(PG_FUNCTION_ARGS)
if (r == SIGNAL_BACKEND_NOSUPERUSER)
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("must be a superuser to cancel superuser query")));+ errmsg("permission denied to cancel query"),+ errdetail("You must have the %s attribute to cancel queries of roles with %s.",+ "SUPERUSER", "SUPERUSER")));
if (r == SIGNAL_BACKEND_NOPERMISSION)
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("must be a member of the role whose query is being canceled or member of pg_signal_backend")));+ errmsg("permission denied to cancel query"),+ errdetail("You must inherit privileges of the role whose query is being canceled or inherit privileges of the \"%s\" role.",+ "pg_signal_backend")));
PG_RETURN_BOOL(r == SIGNAL_BACKEND_SUCCESS);
}
@@ -223,12 +227,16 @@ pg_terminate_backend(PG_FUNCTION_ARGS)
if (r == SIGNAL_BACKEND_NOSUPERUSER)
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("must be a superuser to terminate superuser process")));+ errmsg("permission denied to terminate process"),+ errdetail("You must have the %s attribute to terminate processes of roles with %s.",+ "SUPERUSER", "SUPERUSER")));
if (r == SIGNAL_BACKEND_NOPERMISSION)
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("must be a member of the role whose process is being terminated or member of pg_signal_backend")));+ errmsg("permission denied to terminate process"),+ errdetail("You must inherit privileges of the role whose process is being terminated or inherit privileges of the \"%s\" role.",+ "pg_signal_backend")));
/* Wait only on success and if actually requested */
if (r == SIGNAL_BACKEND_SUCCESS && timeout > 0)
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.cindex c7d9d96b45..3fd9cfb842 100644--- a/src/backend/tcop/utility.c+++ b/src/backend/tcop/utility.c@@ -950,7 +950,10 @@ standard_ProcessUtility(PlannedStmt *pstmt,
if (!has_privs_of_role(GetUserId(), ROLE_PG_CHECKPOINT))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("must be superuser or have privileges of pg_checkpoint to do CHECKPOINT")));+ errmsg("permission denied to execute %s command",+ "CHECKPOINT"),+ errdetail("You must inherit privileges of the \"%s\" role to execute this command.",+ "pg_checkpoint")));
RequestCheckpoint(CHECKPOINT_IMMEDIATE | CHECKPOINT_WAIT |
(RecoveryInProgress() ? 0 : CHECKPOINT_FORCE));
diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.cindex 59532bbd80..b0cfbc742b 100644--- a/src/backend/utils/init/miscinit.c+++ b/src/backend/utils/init/miscinit.c@@ -701,6 +701,10 @@ has_rolreplication(Oid roleid)
bool result = false;
HeapTuple utup;
+ /* Superusers bypass all permission checking. */+ if (superuser_arg(roleid))+ return true;+
utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
if (HeapTupleIsValid(utup))
{
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.cindex 2f07ca7a0e..2b103586ab 100644--- a/src/backend/utils/init/postinit.c+++ b/src/backend/utils/init/postinit.c@@ -940,12 +940,14 @@ InitPostgres(const char *in_dbname, Oid dboid,
if (nfree < SuperuserReservedConnections)
ereport(FATAL,
(errcode(ERRCODE_TOO_MANY_CONNECTIONS),
- errmsg("remaining connection slots are reserved for superusers")));+ errmsg("remaining connection slots are reserved for roles with %s",+ "SUPERUSER")));
if (!has_privs_of_role(GetUserId(), ROLE_PG_USE_RESERVED_CONNECTIONS))
ereport(FATAL,
(errcode(ERRCODE_TOO_MANY_CONNECTIONS),
- errmsg("remaining connection slots are reserved for roles with privileges of pg_use_reserved_connections")));+ errmsg("remaining connection slots are reserved for roles that inherit privileges of the \"%s\" role",+ "pg_use_reserved_connections")));
}
/* Check replication permissions needed for walsender processes. */
@@ -953,10 +955,12 @@ InitPostgres(const char *in_dbname, Oid dboid,
{
Assert(!bootstrap);
- if (!superuser() && !has_rolreplication(GetUserId()))+ if (!has_rolreplication(GetUserId()))
ereport(FATAL,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("must be superuser or replication role to start walsender")));+ errmsg("permission denied to start WAL sender"),+ errdetail("You must have the %s attribute to start a WAL sender process.",+ "REPLICATION")));
}
/*
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.cindex 51e07d5582..7805a6015b 100644--- a/src/backend/utils/misc/guc.c+++ b/src/backend/utils/misc/guc.c@@ -4209,8 +4209,9 @@ GetConfigOption(const char *name, bool missing_ok, bool restrict_privileged)
!ConfigOptionIsVisible(record))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("must be superuser or have privileges of pg_read_all_settings to examine \"%s\"",- name)));+ errmsg("permission denied to examine \"%s\"", name),+ errdetail("You must inherit privileges of the \"%s\" role to examine this parameter.",+ "pg_read_all_settings")));
switch (record->vartype)
{
@@ -4255,8 +4256,9 @@ GetConfigOptionResetString(const char *name)
if (!ConfigOptionIsVisible(record))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("must be superuser or have privileges of pg_read_all_settings to examine \"%s\"",- name)));+ errmsg("permission denied to examine \"%s\"", name),+ errdetail("You must inherit privileges of the \"%s\" role to examine this parameter.",+ "pg_read_all_settings")));
switch (record->vartype)
{
@@ -5261,8 +5263,9 @@ GetConfigOptionByName(const char *name, const char **varname, bool missing_ok)
if (!ConfigOptionIsVisible(record))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("must be superuser or have privileges of pg_read_all_settings to examine \"%s\"",- name)));+ errmsg("permission denied to examine \"%s\"", name),+ errdetail("You must inherit privileges of the \"%s\" role to examine this parameter.",+ "pg_read_all_settings")));
if (varname)
*varname = record->name;
diff --git a/src/test/modules/dummy_seclabel/expected/dummy_seclabel.out b/src/test/modules/dummy_seclabel/expected/dummy_seclabel.outindex c57d4fd2df..18f8db0e39 100644--- a/src/test/modules/dummy_seclabel/expected/dummy_seclabel.out+++ b/src/test/modules/dummy_seclabel/expected/dummy_seclabel.out@@ -59,7 +59,8 @@ SECURITY LABEL ON ROLE regress_dummy_seclabel_user4 IS 'unclassified'; -- fail (
ERROR: role "regress_dummy_seclabel_user4" does not exist
SET SESSION AUTHORIZATION regress_dummy_seclabel_user2;
SECURITY LABEL ON ROLE regress_dummy_seclabel_user2 IS 'unclassified'; -- fail (not privileged)
-ERROR: must have CREATEROLE privilege+ERROR: permission denied+DETAIL: You must have the CREATEROLE attribute.
RESET SESSION AUTHORIZATION;
--
-- Test for various types of object
diff --git a/src/test/modules/unsafe_tests/expected/rolenames.out b/src/test/modules/unsafe_tests/expected/rolenames.outindex 88b1ff843b..6e55850705 100644--- a/src/test/modules/unsafe_tests/expected/rolenames.out+++ b/src/test/modules/unsafe_tests/expected/rolenames.out@@ -1077,7 +1077,8 @@ SHOW session_preload_libraries;
SET SESSION AUTHORIZATION regress_role_nopriv;
-- fails with role not member of pg_read_all_settings
SHOW session_preload_libraries;
-ERROR: must be superuser or have privileges of pg_read_all_settings to examine "session_preload_libraries"+ERROR: permission denied to examine "session_preload_libraries"+DETAIL: You must inherit privileges of the "pg_read_all_settings" role to examine this parameter.
RESET SESSION AUTHORIZATION;
ERROR: current transaction is aborted, commands ignored until end of transaction block
ROLLBACK;
diff --git a/src/test/regress/expected/create_role.out b/src/test/regress/expected/create_role.outindex 7157d4c589..e72eb91624 100644--- a/src/test/regress/expected/create_role.out+++ b/src/test/regress/expected/create_role.out@@ -106,7 +106,8 @@ ALTER ROLE regress_hasprivs RENAME TO regress_tenant;
ALTER ROLE regress_tenant NOINHERIT NOLOGIN CONNECTION LIMIT 7;
-- fail, we should be unable to modify a role we did not create
COMMENT ON ROLE regress_role_normal IS 'some comment';
-ERROR: must have admin option on role "regress_role_normal"+ERROR: permission denied+DETAIL: You must have the ADMIN option on role "regress_role_normal".
ALTER ROLE regress_role_normal RENAME TO regress_role_abnormal;
ERROR: permission denied to rename role
DETAIL: You must have the CREATEROLE attribute and the ADMIN option on role "regress_role_normal".
--
2.25.1
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Reply to all the recipients using the --to and --cc options:
reply via email
To: pgsql-hackers@postgresql.org
Cc: nathandbossart@gmail.com, peter.eisentraut@enterprisedb.com, alvherre@alvh.no-ip.org, tgl@sss.pgh.pa.us, robertmhaas@gmail.com
Subject: Re: improving user.c error messages
In-Reply-To: <20230220225852.GA3940888@nathanxps13>
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox