Improve several permission-related error messages.
authorPeter Eisentraut <peter@eisentraut.org>
Fri, 17 Mar 2023 09:14:16 +0000 (10:14 +0100)
committerPeter Eisentraut <peter@eisentraut.org>
Fri, 17 Mar 2023 09:33:09 +0000 (10:33 +0100)
Mainly move some detail from errmsg to errdetail, remove explicit
mention of superuser where appropriate, since that is implied in most
permission checks, and make messages more uniform.

Author: Nathan Bossart <nathandbossart@gmail.com>
Discussion: https://www.postgresql.org/message-id/20230316234701.GA903298@nathanxps13

18 files changed:
contrib/file_fdw/expected/file_fdw.out
contrib/file_fdw/file_fdw.c
contrib/test_decoding/expected/permissions.out
src/backend/backup/basebackup_server.c
src/backend/catalog/objectaddress.c
src/backend/commands/copy.c
src/backend/commands/user.c
src/backend/replication/slot.c
src/backend/storage/ipc/procarray.c
src/backend/storage/ipc/signalfuncs.c
src/backend/tcop/utility.c
src/backend/utils/init/postinit.c
src/backend/utils/misc/guc.c
src/test/modules/dummy_seclabel/expected/dummy_seclabel.out
src/test/modules/unsafe_tests/expected/rolenames.out
src/test/regress/expected/create_role.out
src/test/regress/expected/dependency.out
src/test/regress/expected/privileges.out

index f5ae29732a2837ace705d8082af00de4c7bef50c..72304e0ff321ba2e2c29563162e23b2402f57908 100644 (file)
@@ -491,7 +491,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:  Only roles with privileges of the "pg_read_server_files" role may set this option.
 SET ROLE regress_file_fdw_superuser;
 -- cleanup
 RESET ROLE;
index 99b21e8316dfdea3237d177cf2b5b2bcac1e0c45..9e330b99347edceec65adae70a75f232dcd824e0 100644 (file)
@@ -279,13 +279,19 @@ 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 \"%s\" option of a file_fdw foreign table",
+                               "filename"),
+                        errdetail("Only roles with privileges of the \"%s\" role may 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 \"%s\" option of a file_fdw foreign table",
+                               "program"),
+                        errdetail("Only roles with privileges of the \"%s\" role may set this option.",
+                                  "pg_execute_server_program")));
 
            filename = defGetString(def);
        }
index ed97f81dda5b447fb42065de1cc09eba7ed01d40..d6eaba8c55d68a26975f30a7651bd06902f7dd62 100644 (file)
@@ -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:  Only roles with the REPLICATION attribute may 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:  Only roles with the REPLICATION attribute may 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:  Only roles with the REPLICATION attribute may 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:  Only roles with the REPLICATION attribute may use replication slots.
 RESET ROLE;
 -- all users can see existing slots
 SET ROLE regress_lr_superuser;
index 0258d7a03b3ee8542bf8bce73b66468ad4b690d5..2b9d9d29324872cbb5ef184467c6cdf0d2beecdd 100644 (file)
@@ -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("Only roles with privileges of the \"%s\" role may create a backup stored on the server.",
+                          "pg_write_server_files")));
    CommitTransactionCommand();
 
    /*
index 2f688166e14c116703cbe8b052aecb5421b19fb5..d59492934cb60d0c91fdfc514267d9fbefb4a14d 100644 (file)
@@ -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("The current user 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("The current user 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("The current user must have the %s option on role \"%s\".",
+                                      "ADMIN",
+                                      GetUserNameFromId(address.objectId,
+                                                        true))));
            }
            break;
        case OBJECT_TSPARSER:
index 167d31a2d99d6cfb2a84efb58bc3e95965e329ca..f14fae330837c816ab9e4462e8f72caa2549b8f9 100644 (file)
@@ -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("Only roles with privileges of the \"%s\" role may COPY to or from an external program.",
+                                  "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("Only roles with privileges of the \"%s\" role may COPY from a file.",
+                                  "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("Only roles with privileges of the \"%s\" role may COPY to a file.",
+                                  "pg_write_server_files"),
                         errhint("Anyone can COPY to stdout or from stdin. "
                                 "psql's \\copy command also works for anyone.")));
        }
index 43fe530a96d3a0902f118710e23173ec43540f07..52796e95487771fada3f9d4546e5928ec1f17c35 100644 (file)
@@ -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("Only roles with the %s attribute may 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("Only roles with the %s attribute may 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("Only roles with the %s attribute may 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("Only roles with the %s attribute may 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("Only roles with the %s attribute may 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("Only roles with the %s attribute may alter roles with %s.",
+                          "SUPERUSER", "SUPERUSER")));
+   if (!superuser() && dissuper)
+       ereport(ERROR,
+               (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+                errmsg("permission denied to alter role"),
+                errdetail("Only roles with the %s attribute may 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("Only roles with the %s attribute and the %s option on role \"%s\" may alter this role.",
+                              "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, the current user 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("Only roles with the %s attribute may 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("Only roles with the %s attribute may 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("Only roles with the %s attribute may 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("Only roles with the %s option on role \"%s\" may 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("Only roles with the %s attribute may 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("Only roles with the %s attribute and the %s option on role \"%s\" may alter this role.",
+                                  "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("Only roles with the %s attribute may 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("Only roles with the %s attribute and the %s option on the target roles may drop 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("Only roles with the %s attribute may 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("Only roles with the %s attribute and the %s option on role \"%s\" may drop this role.",
+                              "CREATEROLE", "ADMIN", NameStr(roleform->rolname))));
 
        /* DROP hook for the role being removed */
        InvokeObjectDropHook(AuthIdRelationId, roleid, 0);
@@ -1383,7 +1425,9 @@ RenameRole(const char *oldname, const char *newname)
        if (!superuser())
            ereport(ERROR,
                    (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-                    errmsg("must be superuser to rename superusers")));
+                    errmsg("permission denied to rename role"),
+                    errdetail("Only roles with the %s attribute may 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("Only roles with the %s attribute and the %s option on role \"%s\" may rename this role.",
+                              "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("Only roles with privileges of role \"%s\" may drop objects owned by it.",
+                              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("Only roles with privileges of role \"%s\" may reassign objects owned by it.",
+                              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("Only roles with privileges of role \"%s\" may reassign objects to it.",
+                          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("Only roles with the %s attribute may grant roles with %s.",
+                                  "SUPERUSER", "SUPERUSER")));
+           else
+               ereport(ERROR,
+                       (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+                        errmsg("permission denied to revoke role \"%s\"",
+                               GetUserNameFromId(roleid, false)),
+                        errdetail("Only roles with the %s attribute may 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("Only roles with the %s option on role \"%s\" may grant this role.",
+                                  "ADMIN", GetUserNameFromId(roleid, false))));
+           else
+               ereport(ERROR,
+                       (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+                        errmsg("permission denied to revoke role \"%s\"",
+                               GetUserNameFromId(roleid, false)),
+                        errdetail("Only roles with the %s option on role \"%s\" may revoke this role.",
+                                  "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("Only roles with privileges of role \"%s\" may grant privileges as this role.",
+                              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("Only roles with privileges of role \"%s\" may revoke privileges granted by this role.",
+                              GetUserNameFromId(grantorId, false))));
    }
 
    /*
index 3506b77cc7c2b9b2cadb36f900f2a11274e418a8..2293c0c6fc348b0a1541c2ed666977b73fd67639 100644 (file)
@@ -1143,7 +1143,9 @@ CheckSlotPermissions(void)
    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("Only roles with the %s attribute may use replication slots.",
+                          "REPLICATION")));
 }
 
 /*
index a9fb97460d846580c13fb33c5ddfde968f62de61..ea91ce355f2bf2d428c3452334e46a97625cb111 100644 (file)
@@ -3883,7 +3883,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("Only roles with privileges of the role whose process is being terminated or with privileges of the \"%s\" role may terminate this process.",
+                                      "pg_signal_backend")));
            }
        }
 
index bc93ab5b520531ffbab016cf4145d24bf7ae223e..eabb68a9e17cd594467ce3a463b95b89ed7fa96e 100644 (file)
@@ -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("Only roles with the %s attribute may 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("Only roles with privileges of the role whose query is being canceled or with privileges of the \"%s\" role may cancel this query.",
+                          "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("Only roles with the %s attribute may 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("Only roles with privileges of the role whose process is being terminated or with privileges of the \"%s\" role may terminate this process.",
+                          "pg_signal_backend")));
 
    /* Wait only on success and if actually requested */
    if (r == SIGNAL_BACKEND_SUCCESS && timeout > 0)
index c7d9d96b45dd205e40fc1f44e2a655f059fc4470..eada735363931af7055aa67d3a8808b74df8d137 100644 (file)
@@ -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("Only roles with privileges of the \"%s\" role may execute this command.",
+                                  "pg_checkpoint")));
 
            RequestCheckpoint(CHECKPOINT_IMMEDIATE | CHECKPOINT_WAIT |
                              (RecoveryInProgress() ? 0 : CHECKPOINT_FORCE));
index 3026317bfc96e043064a43dc5d23c9cb1205b9a8..92bac8b63f544cf9c297c0c0ffca3ab410b24243 100644 (file)
@@ -949,12 +949,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 with privileges of the \"%s\" role",
+                           "pg_use_reserved_connections")));
    }
 
    /* Check replication permissions needed for walsender processes. */
@@ -965,7 +967,9 @@ InitPostgres(const char *in_dbname, Oid dboid,
        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("Only roles with the %s attribute may start a WAL sender process.",
+                              "REPLICATION")));
    }
 
    /*
index 51e07d55825c773396e7cce7d3cfa9a63b288840..ea67cfa5e514cda3731ac22f691bc318ffedbd2a 100644 (file)
@@ -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("Only roles with privileges of the \"%s\" role may 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("Only roles with privileges of the \"%s\" role may 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("Only roles with privileges of the \"%s\" role may examine this parameter.",
+                          "pg_read_all_settings")));
 
    if (varname)
        *varname = record->name;
index c57d4fd2df0887ea5aa678d553d79a188889a35f..de671e5a1707828c42a3abc137167e9d75a0a9f1 100644 (file)
@@ -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:  The current user must have the CREATEROLE attribute.
 RESET SESSION AUTHORIZATION;
 --
 -- Test for various types of object
index 88b1ff843be2f0dd8d38493ee0fe369d37824d11..61396b2a8054ae0b0ff8477ec287528570aaf1e0 100644 (file)
@@ -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:  Only roles with privileges of the "pg_read_all_settings" role may examine this parameter.
 RESET SESSION AUTHORIZATION;
 ERROR:  current transaction is aborted, commands ignored until end of transaction block
 ROLLBACK;
index 9f431bd4f569e4bd9d7dbedeb1b9a57070078db4..5526e34a7f446053b4c825c8cb59304fcbc8ed63 100644 (file)
@@ -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:  Only roles with the SUPERUSER attribute may 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:  Only roles with the REPLICATION attribute may 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:  Only roles with the REPLICATION attribute may 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:  Only roles with the BYPASSRLS attribute may 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:  Only roles with the CREATEDB attribute may 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:  Only roles with the SUPERUSER attribute may 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:  Only roles with the REPLICATION attribute may 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:  Only roles with the CREATEDB attribute may 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:  Only roles with the BYPASSRLS attribute may 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:  Only roles with the SUPERUSER attribute may 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:  Only roles with the SUPERUSER attribute may 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:  Only roles with the SUPERUSER attribute may 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
@@ -94,11 +106,14 @@ 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:  The current user 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:  Only roles with the CREATEROLE attribute and the ADMIN option on role "regress_role_normal" may rename this role.
 ALTER ROLE regress_role_normal NOINHERIT NOLOGIN CONNECTION LIMIT 7;
-ERROR:  permission denied
+ERROR:  permission denied to alter role
+DETAIL:  Only roles with the CREATEROLE attribute and the ADMIN option on role "regress_role_normal" may alter this role.
 -- ok, regress_tenant can create objects within the database
 SET SESSION AUTHORIZATION regress_tenant;
 CREATE TABLE tenant_table (i integer);
@@ -123,6 +138,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:  Only roles with privileges of role "regress_tenant" may reassign objects owned by it.
 -- ok, create a role with a value for createrole_self_grant
 SET createrole_self_grant = 'set, inherit';
 CREATE ROLE regress_tenant2;
@@ -150,25 +166,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:  Only roles with the ADMIN option on role "pg_read_all_data" may grant this role.
 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:  Only roles with the ADMIN option on role "pg_write_all_data" may grant this role.
 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:  Only roles with the ADMIN option on role "pg_monitor" may grant this role.
 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:  Only roles with the ADMIN option on role "pg_read_all_settings" may grant this role.
 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:  Only roles with the ADMIN option on role "pg_read_all_stats" may grant this role.
 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:  Only roles with the ADMIN option on role "pg_stat_scan_tables" may grant this role.
 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:  Only roles with the ADMIN option on role "pg_read_server_files" may grant this role.
 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:  Only roles with the ADMIN option on role "pg_write_server_files" may grant this role.
 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:  Only roles with the ADMIN option on role "pg_execute_server_program" may grant this role.
 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:  Only roles with the ADMIN option on role "pg_signal_backend" may grant this role.
 -- 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 +237,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:  Only roles with the SUPERUSER attribute may 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:  Only roles with the CREATEROLE attribute and the ADMIN option on role "regress_rolecreator" may drop this role.
 -- ok
 RESET SESSION AUTHORIZATION;
 REVOKE CREATE ON DATABASE regression FROM regress_role_admin CASCADE;
index 520035f6a0e877e6fd1f3df0d14898735e962d06..2b96720e29af12bb338ece2e521838c7a51afd1d 100644 (file)
@@ -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:  Only roles with privileges of role "regress_dep_user1" may drop objects owned by it.
 DROP OWNED BY regress_dep_user0, regress_dep_user2;
 ERROR:  permission denied to drop objects
+DETAIL:  Only roles with privileges of role "regress_dep_user2" may drop objects owned by it.
 REASSIGN OWNED BY regress_dep_user0 TO regress_dep_user1;
 ERROR:  permission denied to reassign objects
+DETAIL:  Only roles with privileges of role "regress_dep_user1" may reassign objects to it.
 REASSIGN OWNED BY regress_dep_user1 TO regress_dep_user0;
 ERROR:  permission denied to reassign objects
+DETAIL:  Only roles with privileges of role "regress_dep_user1" may reassign objects owned by it.
 -- this one is allowed
 DROP OWNED BY regress_dep_user0;
 CREATE TABLE deptest1 (f1 int unique);
index 5496ec8f55aa742c2e6c73f3b16bc71004f0a9d8..3cf4ac8c9ed257e7852ceb96b2caf015bacf28f2 100644 (file)
@@ -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, the current user 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:  Only roles with the ADMIN option on role "regress_priv_group2" may grant this role.
 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:  Only roles with the ADMIN option on role "regress_priv_group2" may grant this role.
 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:  Only roles with the ADMIN option on role "regress_priv_group2" may grant this role.
 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:  Only roles with the ADMIN option on role "regress_priv_group2" may grant this role.
 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:  Only roles with the ADMIN option on role "regress_priv_group2" may grant this role.
 SET SESSION AUTHORIZATION regress_priv_user4;
 DROP FUNCTION dogrant_ok();
 REVOKE regress_priv_group2 FROM regress_priv_user5;