Attached is two separate patches to address previous
comments/recommendations:
* superuser-cleanup-shortcuts_11-5-2014.patch
* has_privilege-cleanup_11-5-2014.patch
-Adam
--
Adam Brightwell - [email protected]
Database Engineer - www.crunchydatasolutions.com
diff --git a/contrib/test_decoding/expected/permissions.out b/contrib/test_decoding/expected/permissions.out
new file mode 100644
index 212fd1d..f011955
*** a/contrib/test_decoding/expected/permissions.out
--- b/contrib/test_decoding/expected/permissions.out
*************** RESET ROLE;
*** 54,66 ****
-- plain user *can't* can control replication
SET ROLE 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
INSERT INTO lr_test VALUES('lr_superuser_init');
ERROR: permission denied for relation 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
SELECT pg_drop_replication_slot('regression_slot');
! ERROR: must be superuser or replication role to use replication slots
RESET ROLE;
-- replication users can drop superuser created slots
SET ROLE lr_superuser;
--- 54,69 ----
-- plain user *can't* can control replication
SET ROLE lr_normal;
SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot', 'test_decoding');
! ERROR: permission denied to use replication slots
! HINT: You must be superuser or replication role to use replication slots.
INSERT INTO lr_test VALUES('lr_superuser_init');
ERROR: permission denied for relation lr_test
SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1');
! ERROR: permission denied to use replication slots
! HINT: You must be superuser or replication role to use replication slots.
SELECT pg_drop_replication_slot('regression_slot');
! ERROR: permission denied to use replication slots
! HINT: You must be superuser or replication role to use replication slots.
RESET ROLE;
-- replication users can drop superuser created slots
SET ROLE lr_superuser;
*************** SELECT 'init' FROM pg_create_logical_rep
*** 90,96 ****
RESET ROLE;
SET ROLE lr_normal;
SELECT pg_drop_replication_slot('regression_slot');
! ERROR: must be superuser or replication role to use replication slots
RESET ROLE;
-- all users can see existing slots
SET ROLE lr_superuser;
--- 93,100 ----
RESET ROLE;
SET ROLE lr_normal;
SELECT pg_drop_replication_slot('regression_slot');
! ERROR: permission denied to use replication slots
! HINT: You must be superuser or replication role to use replication slots.
RESET ROLE;
-- all users can see existing slots
SET ROLE lr_superuser;
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
new file mode 100644
index 133143d..52d8208
*** a/src/backend/access/transam/xlogfuncs.c
--- b/src/backend/access/transam/xlogfuncs.c
***************
*** 27,32 ****
--- 27,33 ----
#include "miscadmin.h"
#include "replication/walreceiver.h"
#include "storage/smgr.h"
+ #include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/numeric.h"
#include "utils/guc.h"
*************** pg_start_backup(PG_FUNCTION_ARGS)
*** 54,63 ****
backupidstr = text_to_cstring(backupid);
! if (!superuser() && !has_rolreplication(GetUserId()))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! errmsg("must be superuser or replication role to run a backup")));
startpoint = do_pg_start_backup(backupidstr, fast, NULL, NULL);
--- 55,65 ----
backupidstr = text_to_cstring(backupid);
! if (!has_replication_privilege(GetUserId()))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! errmsg("permission denied to run a backup"),
! errhint("You must be superuser or replication role to run a backup.")));
startpoint = do_pg_start_backup(backupidstr, fast, NULL, NULL);
*************** pg_stop_backup(PG_FUNCTION_ARGS)
*** 82,91 ****
{
XLogRecPtr stoppoint;
! if (!superuser() && !has_rolreplication(GetUserId()))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! (errmsg("must be superuser or replication role to run a backup"))));
stoppoint = do_pg_stop_backup(NULL, true, NULL);
--- 84,94 ----
{
XLogRecPtr stoppoint;
! if (!has_replication_privilege(GetUserId()))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! errmsg("permission denied to run a backup"),
! errhint("You must be superuser or replication role to run a backup.")));
stoppoint = do_pg_stop_backup(NULL, true, NULL);
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
new file mode 100644
index d30612c..4d26b02
*** a/src/backend/catalog/aclchk.c
--- b/src/backend/catalog/aclchk.c
*************** static AclMode restrict_and_check_grant(
*** 143,148 ****
--- 143,149 ----
AttrNumber att_number, const char *colname);
static AclMode pg_aclmask(AclObjectKind objkind, Oid table_oid, AttrNumber attnum,
Oid roleid, AclMode mask, AclMaskHow how);
+ static bool has_catupdate_privilege(Oid roleid);
#ifdef ACLDEBUG
*************** aclcheck_error_type(AclResult aclerr, Oi
*** 3425,3431 ****
/* Check if given user has rolcatupdate privilege according to pg_authid */
static bool
! has_rolcatupdate(Oid roleid)
{
bool rolcatupdate;
HeapTuple tuple;
--- 3426,3432 ----
/* Check if given user has rolcatupdate privilege according to pg_authid */
static bool
! has_catupdate_privilege(Oid roleid)
{
bool rolcatupdate;
HeapTuple tuple;
*************** pg_class_aclmask(Oid table_oid, Oid role
*** 3630,3636 ****
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
--- 3631,3637 ----
if ((mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE | ACL_USAGE)) &&
IsSystemClass(table_oid, classForm) &&
classForm->relkind != RELKIND_VIEW &&
! !has_catupdate_privilege(roleid) &&
!allowSystemTableMods)
{
#ifdef ACLDEBUG
*************** has_createrole_privilege(Oid roleid)
*** 5078,5083 ****
--- 5079,5106 ----
ReleaseSysCache(utup);
}
return result;
+ }
+
+ /*
+ * Check whether specified role has REPLICATION priviledge (or is a superuser)
+ */
+ bool
+ has_replication_privilege(Oid roleid)
+ {
+ bool result = false;
+ HeapTuple utup;
+
+ /* Superusers bypass all permission checking. */
+ if (superuser_arg(roleid))
+ return true;
+
+ utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
+ if (HeapTupleIsValid(utup))
+ {
+ result = ((Form_pg_authid) GETSTRUCT(utup))->rolreplication;
+ ReleaseSysCache(utup);
+ }
+ return result;
}
bool
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c
new file mode 100644
index 1a73fd8..fd9a4ba
*** a/src/backend/commands/user.c
--- b/src/backend/commands/user.c
*************** static void DelRoleMems(const char *role
*** 55,69 ****
List *memberNames, List *memberIds,
bool admin_opt);
-
- /* Check if current user has createrole privileges */
- static bool
- have_createrole_privilege(void)
- {
- return has_createrole_privilege(GetUserId());
- }
-
-
/*
* CREATE ROLE
*/
--- 55,60 ----
*************** CreateRole(CreateRoleStmt *stmt)
*** 304,310 ****
}
else
{
! if (!have_createrole_privilege())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to create role")));
--- 295,301 ----
}
else
{
! if (!has_createrole_privilege(GetUserId()))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to create role")));
*************** AlterRole(AlterRoleStmt *stmt)
*** 682,688 ****
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser to change bypassrls attribute")));
}
! else if (!have_createrole_privilege())
{
if (!(inherit < 0 &&
createrole < 0 &&
--- 673,679 ----
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser to change bypassrls attribute")));
}
! else if (!has_createrole_privilege(GetUserId()))
{
if (!(inherit < 0 &&
createrole < 0 &&
*************** AlterRoleSet(AlterRoleSetStmt *stmt)
*** 898,904 ****
}
else
{
! if (!have_createrole_privilege() &&
HeapTupleGetOid(roletuple) != GetUserId())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
--- 889,895 ----
}
else
{
! if (!has_createrole_privilege(GetUserId()) &&
HeapTupleGetOid(roletuple) != GetUserId())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
*************** DropRole(DropRoleStmt *stmt)
*** 951,957 ****
pg_auth_members_rel;
ListCell *item;
! if (!have_createrole_privilege())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to drop role")));
--- 942,948 ----
pg_auth_members_rel;
ListCell *item;
! if (!has_createrole_privilege(GetUserId()))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to drop role")));
*************** RenameRole(const char *oldname, const ch
*** 1182,1188 ****
}
else
{
! if (!have_createrole_privilege())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to rename role")));
--- 1173,1179 ----
}
else
{
! if (!has_createrole_privilege(GetUserId()))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to rename role")));
*************** AddRoleMems(const char *rolename, Oid ro
*** 1409,1415 ****
}
else
{
! if (!have_createrole_privilege() &&
!is_admin_of_role(grantorId, roleid))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
--- 1400,1406 ----
}
else
{
! if (!has_createrole_privilege(GetUserId()) &&
!is_admin_of_role(grantorId, roleid))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
*************** DelRoleMems(const char *rolename, Oid ro
*** 1555,1561 ****
}
else
{
! if (!have_createrole_privilege() &&
!is_admin_of_role(GetUserId(), roleid))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
--- 1546,1552 ----
}
else
{
! if (!has_createrole_privilege(GetUserId()) &&
!is_admin_of_role(GetUserId(), roleid))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
diff --git a/src/backend/replication/logical/logicalfuncs.c b/src/backend/replication/logical/logicalfuncs.c
new file mode 100644
index 3a5ec2f..1b40f7e
*** a/src/backend/replication/logical/logicalfuncs.c
--- b/src/backend/replication/logical/logicalfuncs.c
***************
*** 27,32 ****
--- 27,33 ----
#include "mb/pg_wchar.h"
+ #include "utils/acl.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/inval.h"
*************** XLogRead(char *buf, TimeLineID tli, XLog
*** 200,214 ****
}
}
- static void
- check_permissions(void)
- {
- if (!superuser() && !has_rolreplication(GetUserId()))
- ereport(ERROR,
- (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- (errmsg("must be superuser or replication role to use replication slots"))));
- }
-
/*
* read_page callback for logical decoding contexts.
*
--- 201,206 ----
*************** pg_logical_slot_get_changes_guts(Functio
*** 322,328 ****
if (get_call_result_type(fcinfo, NULL, &p->tupdesc) != TYPEFUNC_COMPOSITE)
elog(ERROR, "return type must be a row type");
! check_permissions();
CheckLogicalDecodingRequirements();
--- 314,324 ----
if (get_call_result_type(fcinfo, NULL, &p->tupdesc) != TYPEFUNC_COMPOSITE)
elog(ERROR, "return type must be a row type");
! if (!has_replication_privilege(GetUserId()))
! ereport(ERROR,
! (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! errmsg("permission denied to use replication slots"),
! errhint("You must be superuser or replication role to use replication slots.")));
CheckLogicalDecodingRequirements();
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
new file mode 100644
index bd4701f..4cb82d0
*** a/src/backend/replication/slotfuncs.c
--- b/src/backend/replication/slotfuncs.c
***************
*** 20,37 ****
#include "replication/slot.h"
#include "replication/logical.h"
#include "replication/logicalfuncs.h"
#include "utils/builtins.h"
#include "utils/pg_lsn.h"
- static void
- check_permissions(void)
- {
- if (!superuser() && !has_rolreplication(GetUserId()))
- ereport(ERROR,
- (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- (errmsg("must be superuser or replication role to use replication slots"))));
- }
-
/*
* SQL function for creating a new physical (streaming replication)
* replication slot.
--- 20,29 ----
#include "replication/slot.h"
#include "replication/logical.h"
#include "replication/logicalfuncs.h"
+ #include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/pg_lsn.h"
/*
* SQL function for creating a new physical (streaming replication)
* replication slot.
*************** pg_create_physical_replication_slot(PG_F
*** 51,57 ****
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
elog(ERROR, "return type must be a row type");
! check_permissions();
CheckSlotRequirements();
--- 43,53 ----
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
elog(ERROR, "return type must be a row type");
! if (!has_replication_privilege(GetUserId()))
! ereport(ERROR,
! (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! errmsg("permission denied to use replication slots"),
! errhint("You must be superuser or replication role to use replication slots.")));
CheckSlotRequirements();
*************** pg_create_logical_replication_slot(PG_FU
*** 94,100 ****
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
elog(ERROR, "return type must be a row type");
! check_permissions();
CheckLogicalDecodingRequirements();
--- 90,100 ----
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
elog(ERROR, "return type must be a row type");
! if (!has_replication_privilege(GetUserId()))
! ereport(ERROR,
! (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! errmsg("permission denied to use replication slots"),
! errhint("You must be superuser or replication role to use replication slots.")));
CheckLogicalDecodingRequirements();
*************** pg_drop_replication_slot(PG_FUNCTION_ARG
*** 143,149 ****
{
Name name = PG_GETARG_NAME(0);
! check_permissions();
CheckSlotRequirements();
--- 143,153 ----
{
Name name = PG_GETARG_NAME(0);
! if (!has_replication_privilege(GetUserId()))
! ereport(ERROR,
! (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! errmsg("permission denied to use replication slots"),
! errhint("You must be superuser or replication role to use replication slots.")));
CheckSlotRequirements();
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
new file mode 100644
index dc6eb2c..4f9ffe5
*** a/src/backend/utils/adt/acl.c
--- b/src/backend/utils/adt/acl.c
*************** static AclMode convert_role_priv_string(
*** 117,122 ****
--- 117,123 ----
static AclResult pg_role_aclcheck(Oid role_oid, Oid roleid, AclMode mode);
static void RoleMembershipCacheCallback(Datum arg, int cacheid, uint32 hashvalue);
+ static bool has_inherit_privilege(Oid roleid);
/*
*************** RoleMembershipCacheCallback(Datum arg, i
*** 4636,4642 ****
/* Check if specified role has rolinherit set */
static bool
! has_rolinherit(Oid roleid)
{
bool result = false;
HeapTuple utup;
--- 4637,4643 ----
/* Check if specified role has rolinherit set */
static bool
! has_inherit_privilege(Oid roleid)
{
bool result = false;
HeapTuple utup;
*************** roles_has_privs_of(Oid roleid)
*** 4697,4703 ****
int i;
/* Ignore non-inheriting roles */
! if (!has_rolinherit(memberid))
continue;
/* Find roles that memberid is directly a member of */
--- 4698,4704 ----
int i;
/* Ignore non-inheriting roles */
! if (!has_inherit_privilege(memberid))
continue;
/* Find roles that memberid is directly a member of */
diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c
new file mode 100644
index 8fccb4c..73d5cd2
*** a/src/backend/utils/init/miscinit.c
--- b/src/backend/utils/init/miscinit.c
*************** SetUserIdAndContext(Oid userid, bool sec
*** 327,351 ****
SecurityRestrictionContext &= ~SECURITY_LOCAL_USERID_CHANGE;
}
-
- /*
- * Check whether specified role has explicit REPLICATION privilege
- */
- bool
- has_rolreplication(Oid roleid)
- {
- bool result = false;
- HeapTuple utup;
-
- utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
- if (HeapTupleIsValid(utup))
- {
- result = ((Form_pg_authid) GETSTRUCT(utup))->rolreplication;
- ReleaseSysCache(utup);
- }
- return result;
- }
-
/*
* Initialize user identity during normal backend startup
*/
--- 327,332 ----
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c
new file mode 100644
index 6a6a445..35f80fb
*** a/src/backend/utils/init/postinit.c
--- b/src/backend/utils/init/postinit.c
*************** InitPostgres(const char *in_dbname, Oid
*** 761,770 ****
{
Assert(!bootstrap);
! if (!superuser() && !has_rolreplication(GetUserId()))
ereport(FATAL,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! errmsg("must be superuser or replication role to start walsender")));
}
/*
--- 761,771 ----
{
Assert(!bootstrap);
! if (!has_replication_privilege(GetUserId()))
ereport(FATAL,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! errmsg("permission denied to use replication slots"),
! errhint("You must be superuser or replication role to use replication slots.")));
}
/*
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
new file mode 100644
index 1558a75..0cbc917
*** a/src/include/miscadmin.h
--- b/src/include/miscadmin.h
*************** extern void ValidatePgVersion(const char
*** 435,441 ****
extern void process_shared_preload_libraries(void);
extern void process_session_preload_libraries(void);
extern void pg_bindtextdomain(const char *domain);
- extern bool has_rolreplication(Oid roleid);
/* in access/transam/xlog.c */
extern bool BackupInProgress(void);
--- 435,440 ----
diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h
new file mode 100644
index a8e3164..1c52fdc
*** a/src/include/utils/acl.h
--- b/src/include/utils/acl.h
*************** extern bool pg_event_trigger_ownercheck(
*** 328,332 ****
--- 328,333 ----
extern bool pg_extension_ownercheck(Oid ext_oid, Oid roleid);
extern bool has_createrole_privilege(Oid roleid);
extern bool has_bypassrls_privilege(Oid roleid);
+ extern bool has_replication_privilege(Oid roleid);
#endif /* ACL_H */
diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c
new file mode 100644
index c9a9baf..73bdd0f
*** a/src/backend/commands/alter.c
--- b/src/backend/commands/alter.c
*************** AlterObjectOwner_internal(Relation rel,
*** 806,852 ****
Datum *values;
bool *nulls;
bool *replaces;
! /* Superusers can bypass permission checks */
! if (!superuser())
{
! AclObjectKind aclkind = get_object_aclkind(classId);
! /* must be owner */
! if (!has_privs_of_role(GetUserId(), old_ownerId))
{
! char *objname;
! char namebuf[NAMEDATALEN];
!
! if (Anum_name != InvalidAttrNumber)
! {
! datum = heap_getattr(oldtup, Anum_name,
! RelationGetDescr(rel), &isnull);
! Assert(!isnull);
! objname = NameStr(*DatumGetName(datum));
! }
! else
! {
! snprintf(namebuf, sizeof(namebuf), "%u",
! HeapTupleGetOid(oldtup));
! objname = namebuf;
! }
! aclcheck_error(ACLCHECK_NOT_OWNER, aclkind, objname);
}
! /* Must be able to become new owner */
! check_is_member_of_role(GetUserId(), new_ownerId);
!
! /* New owner must have CREATE privilege on namespace */
! if (OidIsValid(namespaceId))
{
! AclResult aclresult;
!
! aclresult = pg_namespace_aclcheck(namespaceId, new_ownerId,
! ACL_CREATE);
! if (aclresult != ACLCHECK_OK)
! aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
! get_namespace_name(namespaceId));
}
}
/* Build a modified tuple */
--- 806,849 ----
Datum *values;
bool *nulls;
bool *replaces;
+ AclObjectKind aclkind;
! aclkind = get_object_aclkind(classId);
!
! /* must be owner */
! if (!has_privs_of_role(GetUserId(), old_ownerId))
{
! char *objname;
! char namebuf[NAMEDATALEN];
! if (Anum_name != InvalidAttrNumber)
{
! datum = heap_getattr(oldtup, Anum_name,
! RelationGetDescr(rel), &isnull);
! Assert(!isnull);
! objname = NameStr(*DatumGetName(datum));
}
! else
{
! snprintf(namebuf, sizeof(namebuf), "%u",
! HeapTupleGetOid(oldtup));
! objname = namebuf;
}
+ aclcheck_error(ACLCHECK_NOT_OWNER, aclkind, objname);
+ }
+ /* Must be able to become new owner */
+ check_is_member_of_role(GetUserId(), new_ownerId);
+
+ /* New owner must have CREATE privilege on namespace */
+ if (OidIsValid(namespaceId))
+ {
+ AclResult aclresult;
+
+ aclresult = pg_namespace_aclcheck(namespaceId, new_ownerId,
+ ACL_CREATE);
+ if (aclresult != ACLCHECK_OK)
+ aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
+ get_namespace_name(namespaceId));
}
/* Build a modified tuple */
diff --git a/src/backend/commands/foreigncmds.c b/src/backend/commands/foreigncmds.c
new file mode 100644
index ab4ed6c..aad6ae4
*** a/src/backend/commands/foreigncmds.c
--- b/src/backend/commands/foreigncmds.c
*************** AlterForeignServerOwner_internal(Relatio
*** 332,361 ****
if (form->srvowner != newOwnerId)
{
! /* Superusers can always do it */
! if (!superuser())
! {
! Oid srvId;
! AclResult aclresult;
! srvId = HeapTupleGetOid(tup);
! /* Must be owner */
! if (!pg_foreign_server_ownercheck(srvId, GetUserId()))
! aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_FOREIGN_SERVER,
! NameStr(form->srvname));
! /* Must be able to become new owner */
! check_is_member_of_role(GetUserId(), newOwnerId);
! /* New owner must have USAGE privilege on foreign-data wrapper */
! aclresult = pg_foreign_data_wrapper_aclcheck(form->srvfdw, newOwnerId, ACL_USAGE);
! if (aclresult != ACLCHECK_OK)
! {
! ForeignDataWrapper *fdw = GetForeignDataWrapper(form->srvfdw);
! aclcheck_error(aclresult, ACL_KIND_FDW, fdw->fdwname);
! }
}
form->srvowner = newOwnerId;
--- 332,359 ----
if (form->srvowner != newOwnerId)
{
! Oid srvId;
! AclResult aclresult;
! srvId = HeapTupleGetOid(tup);
! /* Must be owner */
! if (!pg_foreign_server_ownercheck(srvId, GetUserId()))
! aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_FOREIGN_SERVER,
! NameStr(form->srvname));
! /* Must be able to become new owner */
! check_is_member_of_role(GetUserId(), newOwnerId);
! /* New owner must have USAGE privilege on foreign-data wrapper */
! aclresult = pg_foreign_data_wrapper_aclcheck(form->srvfdw, newOwnerId,
! ACL_USAGE);
! if (aclresult != ACLCHECK_OK)
! {
! ForeignDataWrapper *fdw = GetForeignDataWrapper(form->srvfdw);
!
! aclcheck_error(aclresult, ACL_KIND_FDW, fdw->fdwname);
}
form->srvowner = newOwnerId;
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
new file mode 100644
index ecdff1e..5fb470f
*** a/src/backend/commands/tablecmds.c
--- b/src/backend/commands/tablecmds.c
*************** ATExecChangeOwner(Oid relationOid, Oid n
*** 8625,8651 ****
/* skip permission checks when recursing to index or toast table */
if (!recursing)
{
! /* Superusers can always do it */
! if (!superuser())
! {
! Oid namespaceOid = tuple_class->relnamespace;
! AclResult aclresult;
! /* Otherwise, must be owner of the existing object */
! if (!pg_class_ownercheck(relationOid, GetUserId()))
! aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
! RelationGetRelationName(target_rel));
! /* Must be able to become new owner */
! check_is_member_of_role(GetUserId(), newOwnerId);
! /* New owner must have CREATE privilege on namespace */
! aclresult = pg_namespace_aclcheck(namespaceOid, newOwnerId,
! ACL_CREATE);
! if (aclresult != ACLCHECK_OK)
! aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
! get_namespace_name(namespaceOid));
! }
}
memset(repl_null, false, sizeof(repl_null));
--- 8625,8647 ----
/* skip permission checks when recursing to index or toast table */
if (!recursing)
{
! Oid namespaceOid = tuple_class->relnamespace;
! AclResult aclresult;
! /* Must be owner of the existing object */
! if (!pg_class_ownercheck(relationOid, GetUserId()))
! aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
! RelationGetRelationName(target_rel));
! /* Must be able to become new owner */
! check_is_member_of_role(GetUserId(), newOwnerId);
! /* New owner must have CREATE privilege on namespace */
! aclresult = pg_namespace_aclcheck(namespaceOid, newOwnerId,
! ACL_CREATE);
! if (aclresult != ACLCHECK_OK)
! aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
! get_namespace_name(namespaceOid));
}
memset(repl_null, false, sizeof(repl_null));
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
new file mode 100644
index 55a6881..c25e237
*** a/src/backend/commands/typecmds.c
--- b/src/backend/commands/typecmds.c
*************** AlterTypeOwner(List *names, Oid newOwner
*** 3302,3325 ****
*/
if (typTup->typowner != newOwnerId)
{
! /* Superusers can always do it */
! if (!superuser())
! {
! /* Otherwise, must be owner of the existing object */
! if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
! aclcheck_error_type(ACLCHECK_NOT_OWNER, HeapTupleGetOid(tup));
! /* Must be able to become new owner */
! check_is_member_of_role(GetUserId(), newOwnerId);
! /* New owner must have CREATE privilege on namespace */
! aclresult = pg_namespace_aclcheck(typTup->typnamespace,
! newOwnerId,
! ACL_CREATE);
! if (aclresult != ACLCHECK_OK)
! aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
! get_namespace_name(typTup->typnamespace));
! }
/*
* If it's a composite type, invoke ATExecChangeOwner so that we fix
--- 3302,3321 ----
*/
if (typTup->typowner != newOwnerId)
{
! /* Must be owner of the existing object */
! if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
! aclcheck_error_type(ACLCHECK_NOT_OWNER, HeapTupleGetOid(tup));
! /* Must be able to become new owner */
! check_is_member_of_role(GetUserId(), newOwnerId);
! /* New owner must have CREATE privilege on namespace */
! aclresult = pg_namespace_aclcheck(typTup->typnamespace,
! newOwnerId,
! ACL_CREATE);
! if (aclresult != ACLCHECK_OK)
! aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
! get_namespace_name(typTup->typnamespace));
/*
* If it's a composite type, invoke ATExecChangeOwner so that we fix
diff --git a/src/test/regress/expected/foreign_data.out b/src/test/regress/expected/foreign_data.out
new file mode 100644
index e4dedb0..b3b5cd0
*** a/src/test/regress/expected/foreign_data.out
--- b/src/test/regress/expected/foreign_data.out
*************** ERROR: must be owner of foreign server
*** 394,399 ****
--- 394,400 ----
ALTER SERVER s1 OWNER TO regress_test_role; -- ERROR
ERROR: must be owner of foreign server s1
RESET ROLE;
+ GRANT USAGE ON FOREIGN DATA WRAPPER foo TO regress_test_role;
ALTER SERVER s1 OWNER TO regress_test_role;
GRANT regress_test_role2 TO regress_test_role;
SET ROLE regress_test_role;
*************** GRANT USAGE ON FOREIGN DATA WRAPPER foo
*** 417,422 ****
--- 418,424 ----
SET ROLE regress_test_role;
ALTER SERVER s1 OWNER TO regress_test_indirect;
RESET ROLE;
+ REVOKE USAGE ON FOREIGN DATA WRAPPER foo FROM regress_test_role;
DROP ROLE regress_test_indirect; -- ERROR
ERROR: role "regress_test_indirect" cannot be dropped because some objects depend on it
DETAIL: owner of server s1
diff --git a/src/test/regress/sql/foreign_data.sql b/src/test/regress/sql/foreign_data.sql
new file mode 100644
index de9dbc8..91d51c9
*** a/src/test/regress/sql/foreign_data.sql
--- b/src/test/regress/sql/foreign_data.sql
*************** SET ROLE regress_test_role;
*** 164,169 ****
--- 164,170 ----
ALTER SERVER s1 VERSION '1.1'; -- ERROR
ALTER SERVER s1 OWNER TO regress_test_role; -- ERROR
RESET ROLE;
+ GRANT USAGE ON FOREIGN DATA WRAPPER foo TO regress_test_role;
ALTER SERVER s1 OWNER TO regress_test_role;
GRANT regress_test_role2 TO regress_test_role;
SET ROLE regress_test_role;
*************** GRANT USAGE ON FOREIGN DATA WRAPPER foo
*** 183,188 ****
--- 184,190 ----
SET ROLE regress_test_role;
ALTER SERVER s1 OWNER TO regress_test_indirect;
RESET ROLE;
+ REVOKE USAGE ON FOREIGN DATA WRAPPER foo FROM regress_test_role;
DROP ROLE regress_test_indirect; -- ERROR
\des+
--
Sent via pgsql-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers