diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
new file mode 100644
index 515a40e..26bf35f
*** a/doc/src/sgml/catalogs.sgml
--- b/doc/src/sgml/catalogs.sgml
***************
*** 1416,1430 ****
- rolcatupdate
- bool
-
- Role can update system catalogs directly. (Even a superuser cannot do
- this unless this column is true)
-
-
-
-
rolcanlogin
bool
--- 1416,1421 ----
*************** SELECT * FROM pg_locks pl LEFT JOIN pg_p
*** 8492,8507 ****
- rolcatupdate
- bool
-
-
- Role can update system catalogs directly. (Even a superuser cannot do
- this unless this column is true)
-
-
-
-
rolcanlogin
bool
--- 8483,8488 ----
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
new file mode 100644
index 1e3888e..da4ba4e
*** a/src/backend/catalog/aclchk.c
--- b/src/backend/catalog/aclchk.c
*************** aclcheck_error_type(AclResult aclerr, Oi
*** 3423,3448 ****
}
- /* Check if given user has rolcatupdate privilege according to pg_authid */
- static bool
- has_rolcatupdate(Oid roleid)
- {
- bool rolcatupdate;
- HeapTuple tuple;
-
- tuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
- if (!HeapTupleIsValid(tuple))
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("role with OID %u does not exist", roleid)));
-
- rolcatupdate = ((Form_pg_authid) GETSTRUCT(tuple))->rolcatupdate;
-
- ReleaseSysCache(tuple);
-
- return rolcatupdate;
- }
-
/*
* Relay for the various pg_*_mask routines depending on object kind
*/
--- 3423,3428 ----
*************** pg_class_aclmask(Oid table_oid, Oid role
*** 3619,3646 ****
classForm = (Form_pg_class) GETSTRUCT(tuple);
/*
! * Deny anyone permission to update a system catalog unless
! * pg_authid.rolcatupdate is set. (This is to let superusers protect
! * themselves from themselves.) Also allow it if allowSystemTableMods.
! *
! * As of 7.4 we have some updatable system views; those shouldn't be
! * protected in this way. Assume the view rules can take care of
! * themselves. ACL_USAGE is if we ever have system sequences.
! */
! if ((mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE | ACL_USAGE)) &&
! IsSystemClass(table_oid, classForm) &&
! classForm->relkind != RELKIND_VIEW &&
! !has_rolcatupdate(roleid) &&
! !allowSystemTableMods)
! {
! #ifdef ACLDEBUG
! elog(DEBUG2, "permission denied for system catalog update");
! #endif
! mask &= ~(ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE | ACL_USAGE);
! }
!
! /*
! * Otherwise, superusers bypass all permission-checking.
*/
if (superuser_arg(roleid))
{
--- 3599,3605 ----
classForm = (Form_pg_class) GETSTRUCT(tuple);
/*
! * Superusers bypass all permission-checking.
*/
if (superuser_arg(roleid))
{
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
new file mode 100644
index 5e69e2b..2800f73
*** a/src/backend/catalog/system_views.sql
--- b/src/backend/catalog/system_views.sql
*************** CREATE VIEW pg_roles AS
*** 13,19 ****
rolinherit,
rolcreaterole,
rolcreatedb,
- rolcatupdate,
rolcanlogin,
rolreplication,
rolconnlimit,
--- 13,18 ----
*************** CREATE VIEW pg_shadow AS
*** 31,37 ****
pg_authid.oid AS usesysid,
rolcreatedb AS usecreatedb,
rolsuper AS usesuper,
- rolcatupdate AS usecatupd,
rolreplication AS userepl,
rolbypassrls AS usebypassrls,
rolpassword AS passwd,
--- 30,35 ----
*************** CREATE VIEW pg_user AS
*** 57,63 ****
usesysid,
usecreatedb,
usesuper,
- usecatupd,
userepl,
usebypassrls,
'********'::text as passwd,
--- 55,60 ----
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c
new file mode 100644
index 2210eed..1d3b658
*** a/src/backend/commands/user.c
--- b/src/backend/commands/user.c
*************** CreateRole(CreateRoleStmt *stmt)
*** 368,375 ****
new_record[Anum_pg_authid_rolinherit - 1] = BoolGetDatum(inherit);
new_record[Anum_pg_authid_rolcreaterole - 1] = BoolGetDatum(createrole);
new_record[Anum_pg_authid_rolcreatedb - 1] = BoolGetDatum(createdb);
- /* superuser gets catupdate right by default */
- new_record[Anum_pg_authid_rolcatupdate - 1] = BoolGetDatum(issuper);
new_record[Anum_pg_authid_rolcanlogin - 1] = BoolGetDatum(canlogin);
new_record[Anum_pg_authid_rolreplication - 1] = BoolGetDatum(isreplication);
new_record[Anum_pg_authid_rolconnlimit - 1] = Int32GetDatum(connlimit);
--- 368,373 ----
*************** AlterRole(AlterRoleStmt *stmt)
*** 734,753 ****
MemSet(new_record_repl, false, sizeof(new_record_repl));
/*
! * issuper/createrole/catupdate/etc
! *
! * XXX It's rather unclear how to handle catupdate. It's probably best to
! * keep it equal to the superuser status, otherwise you could end up with
! * a situation where no existing superuser can alter the catalogs,
! * including pg_authid!
*/
if (issuper >= 0)
{
new_record[Anum_pg_authid_rolsuper - 1] = BoolGetDatum(issuper > 0);
new_record_repl[Anum_pg_authid_rolsuper - 1] = true;
-
- new_record[Anum_pg_authid_rolcatupdate - 1] = BoolGetDatum(issuper > 0);
- new_record_repl[Anum_pg_authid_rolcatupdate - 1] = true;
}
if (inherit >= 0)
--- 732,743 ----
MemSet(new_record_repl, false, sizeof(new_record_repl));
/*
! * issuper/createrole/etc
*/
if (issuper >= 0)
{
new_record[Anum_pg_authid_rolsuper - 1] = BoolGetDatum(issuper > 0);
new_record_repl[Anum_pg_authid_rolsuper - 1] = true;
}
if (inherit >= 0)
diff --git a/src/include/catalog/pg_authid.h b/src/include/catalog/pg_authid.h
new file mode 100644
index e01e6aa..f60d08b
*** a/src/include/catalog/pg_authid.h
--- b/src/include/catalog/pg_authid.h
*************** CATALOG(pg_authid,1260) BKI_SHARED_RELAT
*** 49,55 ****
bool rolinherit; /* inherit privileges from other roles? */
bool rolcreaterole; /* allowed to create more roles? */
bool rolcreatedb; /* allowed to create databases? */
- bool rolcatupdate; /* allowed to alter catalogs manually? */
bool rolcanlogin; /* allowed to log in as session user? */
bool rolreplication; /* role used for streaming replication */
bool rolbypassrls; /* allowed to bypass row level security? */
--- 49,54 ----
*************** typedef FormData_pg_authid *Form_pg_auth
*** 74,92 ****
* compiler constants for pg_authid
* ----------------
*/
! #define Natts_pg_authid 12
#define Anum_pg_authid_rolname 1
#define Anum_pg_authid_rolsuper 2
#define Anum_pg_authid_rolinherit 3
#define Anum_pg_authid_rolcreaterole 4
#define Anum_pg_authid_rolcreatedb 5
! #define Anum_pg_authid_rolcatupdate 6
! #define Anum_pg_authid_rolcanlogin 7
! #define Anum_pg_authid_rolreplication 8
! #define Anum_pg_authid_rolbypassrls 9
! #define Anum_pg_authid_rolconnlimit 10
! #define Anum_pg_authid_rolpassword 11
! #define Anum_pg_authid_rolvaliduntil 12
/* ----------------
* initial contents of pg_authid
--- 73,90 ----
* compiler constants for pg_authid
* ----------------
*/
! #define Natts_pg_authid 11
#define Anum_pg_authid_rolname 1
#define Anum_pg_authid_rolsuper 2
#define Anum_pg_authid_rolinherit 3
#define Anum_pg_authid_rolcreaterole 4
#define Anum_pg_authid_rolcreatedb 5
! #define Anum_pg_authid_rolcanlogin 6
! #define Anum_pg_authid_rolreplication 7
! #define Anum_pg_authid_rolbypassrls 8
! #define Anum_pg_authid_rolconnlimit 9
! #define Anum_pg_authid_rolpassword 10
! #define Anum_pg_authid_rolvaliduntil 11
/* ----------------
* initial contents of pg_authid
*************** typedef FormData_pg_authid *Form_pg_auth
*** 95,101 ****
* user choices.
* ----------------
*/
! DATA(insert OID = 10 ( "POSTGRES" t t t t t t t t -1 _null_ _null_));
#define BOOTSTRAP_SUPERUSERID 10
--- 93,99 ----
* user choices.
* ----------------
*/
! DATA(insert OID = 10 ( "POSTGRES" t t t t t t t -1 _null_ _null_));
#define BOOTSTRAP_SUPERUSERID 10
diff --git a/src/test/regress/expected/privileges.out b/src/test/regress/expected/privileges.out
new file mode 100644
index 74b0450..0db1df3
*** a/src/test/regress/expected/privileges.out
--- b/src/test/regress/expected/privileges.out
*************** ERROR: role "nosuchuser" does not exist
*** 676,682 ****
select has_table_privilege('pg_authid','sel');
ERROR: unrecognized privilege type: "sel"
select has_table_privilege(-999999,'pg_authid','update');
! ERROR: role with OID 4293967297 does not exist
select has_table_privilege(1,'select');
has_table_privilege
---------------------
--- 676,686 ----
select has_table_privilege('pg_authid','sel');
ERROR: unrecognized privilege type: "sel"
select has_table_privilege(-999999,'pg_authid','update');
! has_table_privilege
! ---------------------
! f
! (1 row)
!
select has_table_privilege(1,'select');
has_table_privilege
---------------------
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
new file mode 100644
index d50b103..4af4e05
*** a/src/test/regress/expected/rules.out
--- b/src/test/regress/expected/rules.out
*************** pg_roles| SELECT pg_authid.rolname,
*** 1406,1412 ****
pg_authid.rolinherit,
pg_authid.rolcreaterole,
pg_authid.rolcreatedb,
- pg_authid.rolcatupdate,
pg_authid.rolcanlogin,
pg_authid.rolreplication,
pg_authid.rolconnlimit,
--- 1406,1411 ----
*************** pg_shadow| SELECT pg_authid.rolname AS u
*** 1607,1613 ****
pg_authid.oid AS usesysid,
pg_authid.rolcreatedb AS usecreatedb,
pg_authid.rolsuper AS usesuper,
- pg_authid.rolcatupdate AS usecatupd,
pg_authid.rolreplication AS userepl,
pg_authid.rolbypassrls AS usebypassrls,
pg_authid.rolpassword AS passwd,
--- 1606,1611 ----
*************** pg_user| SELECT pg_shadow.usename,
*** 2062,2068 ****
pg_shadow.usesysid,
pg_shadow.usecreatedb,
pg_shadow.usesuper,
- pg_shadow.usecatupd,
pg_shadow.userepl,
pg_shadow.usebypassrls,
'********'::text AS passwd,
--- 2060,2065 ----