-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 07/03/2015 10:03 AM, Noah Misch wrote:
> (2) CreatePolicy() and AlterPolicy() omit to create a pg_shdepend
> entry for each role in the TO clause.  Test case:

Please see the attached patch. Note that I used SHARED_DEPENDENCY_ACL
for this. It seems appropriate, but possibly we should invent a new
shared dependency type for this use case? Comments?

Thanks,

Joe

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.22 (GNU/Linux)

iQIcBAEBAgAGBQJVtSlAAAoJEDfy90M199hlrkIP/0BqMj30JpJVj3H5pIopU0RZ
pesBzFzzsWmt2QmasX9hajRfo6eXQAWPmKQmw/NDTJvHHNACxLdo0MHE7A9y7No7
aZIFTm0KhnG4jpzxfzpGqQ4ron5Vsc2TlNQgCBYCtbEEtuD0mV2qmcuTkqGte7iB
7iqneRBhmTYBy63X7S0ir4AhDi+JJg8P4F7YuU/XMcha5v5CpNJAToPpW7mCoZ8O
9w/RbXCHso7p1DIxfx4tfxVwLQ7j7G2j0rXbuA2e6OKfwZWWrk5E8Wnvc3xy3yCY
J37fcjOxFdhU/j1j+Tr90LYOSuRu5fQ4z6PmmsPkBM3T0Vllz/nNP64aVKbmHzga
szrIBERRs2icKa4OI08qZF42ObIEv0/t/NuyrXpegY6awRNNNsjyZvwM+51zdjw1
fuWh+2rObzh3RDH8lPB0N0rVfDMM+wU85Vaekckv/7UQ/pbWcwsYD/tykA1engQ8
Ww8kBAEct4dWdqppTqvLLxLgo4d+vuiS1mJ7SRY2aZFRX8QQ8TfB3eObETUsU4/X
9UWyMn+E0Au9ICX+wfD4whaBKst8EuO36qOZx0oZt+++EMOlzypgkCCxDtZO0KWd
KZHbtmJXHFVH+ihbEGXAKMIx+gLqSDG3IKy9MIJxpB3JY3XSdBNqobL2hiQy36/w
svK7i+mEYmUCQ6pB1j8c
=P1AS
-----END PGP SIGNATURE-----
diff --git a/src/backend/commands/policy.c b/src/backend/commands/policy.c
index 17b48d4..20ac54e 100644
*** a/src/backend/commands/policy.c
--- b/src/backend/commands/policy.c
***************
*** 22,27 ****
--- 22,28 ----
  #include "catalog/indexing.h"
  #include "catalog/namespace.h"
  #include "catalog/objectaccess.h"
+ #include "catalog/pg_authid.h"
  #include "catalog/pg_policy.h"
  #include "catalog/pg_type.h"
  #include "commands/policy.h"
***************
*** 48,54 ****
  static void RangeVarCallbackForPolicy(const RangeVar *rv,
  						  Oid relid, Oid oldrelid, void *arg);
  static char parse_policy_command(const char *cmd_name);
! static ArrayType *policy_role_list_to_array(List *roles);
  
  /*
   * Callback to RangeVarGetRelidExtended().
--- 49,55 ----
  static void RangeVarCallbackForPolicy(const RangeVar *rv,
  						  Oid relid, Oid oldrelid, void *arg);
  static char parse_policy_command(const char *cmd_name);
! static Datum *policy_role_list_to_array(List *roles, int *num_roles);
  
  /*
   * Callback to RangeVarGetRelidExtended().
*************** parse_policy_command(const char *cmd_nam
*** 130,159 ****
  
  /*
   * policy_role_list_to_array
!  *	 helper function to convert a list of RoleSpecs to an array of role ids.
   */
! static ArrayType *
! policy_role_list_to_array(List *roles)
  {
! 	ArrayType  *role_ids;
! 	Datum	   *temp_array;
  	ListCell   *cell;
- 	int			num_roles;
  	int			i = 0;
  
  	/* Handle no roles being passed in as being for public */
  	if (roles == NIL)
  	{
! 		temp_array = (Datum *) palloc(sizeof(Datum));
! 		temp_array[0] = ObjectIdGetDatum(ACL_ID_PUBLIC);
  
! 		role_ids = construct_array(temp_array, 1, OIDOID, sizeof(Oid), true,
! 								   'i');
! 		return role_ids;
  	}
  
! 	num_roles = list_length(roles);
! 	temp_array = (Datum *) palloc(num_roles * sizeof(Datum));
  
  	foreach(cell, roles)
  	{
--- 131,158 ----
  
  /*
   * policy_role_list_to_array
!  *	 helper function to convert a list of RoleSpecs to an array of
!  *	 role id Datums.
   */
! static Datum *
! policy_role_list_to_array(List *roles, int *num_roles)
  {
! 	Datum	   *role_oids;
  	ListCell   *cell;
  	int			i = 0;
  
  	/* Handle no roles being passed in as being for public */
  	if (roles == NIL)
  	{
! 	   *num_roles = 1;
! 		role_oids = (Datum *) palloc(*num_roles * sizeof(Datum));
! 		role_oids[0] = ObjectIdGetDatum(ACL_ID_PUBLIC);
  
! 		return role_oids;
  	}
  
!    *num_roles = list_length(roles);
! 	role_oids = (Datum *) palloc(*num_roles * sizeof(Datum));
  
  	foreach(cell, roles)
  	{
*************** policy_role_list_to_array(List *roles)
*** 164,187 ****
  		 */
  		if (spec->roletype == ROLESPEC_PUBLIC)
  		{
! 			if (num_roles != 1)
  				ereport(WARNING,
  						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
  						 errmsg("ignoring roles specified other than public"),
  					  errhint("All roles are members of the public role.")));
! 			temp_array[0] = ObjectIdGetDatum(ACL_ID_PUBLIC);
! 			num_roles = 1;
! 			break;
  		}
  		else
! 			temp_array[i++] =
  				ObjectIdGetDatum(get_rolespec_oid((Node *) spec, false));
  	}
  
! 	role_ids = construct_array(temp_array, num_roles, OIDOID, sizeof(Oid), true,
! 							   'i');
! 
! 	return role_ids;
  }
  
  /*
--- 163,187 ----
  		 */
  		if (spec->roletype == ROLESPEC_PUBLIC)
  		{
! 			Datum   *tmp_role_oids;
! 
! 			if (*num_roles != 1)
  				ereport(WARNING,
  						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
  						 errmsg("ignoring roles specified other than public"),
  					  errhint("All roles are members of the public role.")));
! 		   *num_roles = 1;
! 			tmp_role_oids = (Datum *) palloc(*num_roles * sizeof(Datum));
! 			tmp_role_oids[0] = ObjectIdGetDatum(ACL_ID_PUBLIC);
! 
! 			return tmp_role_oids;
  		}
  		else
! 			role_oids[i++] =
  				ObjectIdGetDatum(get_rolespec_oid((Node *) spec, false));
  	}
  
! 	return role_oids;
  }
  
  /*
*************** CreatePolicy(CreatePolicyStmt *stmt)
*** 463,468 ****
--- 463,470 ----
  	Relation	target_table;
  	Oid			table_id;
  	char		polcmd;
+ 	Datum	   *role_oids;
+ 	int			nitems = 0;
  	ArrayType  *role_ids;
  	ParseState *qual_pstate;
  	ParseState *with_check_pstate;
*************** CreatePolicy(CreatePolicyStmt *stmt)
*** 476,481 ****
--- 478,484 ----
  	bool		isnull[Natts_pg_policy];
  	ObjectAddress target;
  	ObjectAddress myself;
+ 	int			i;
  
  	/* Parse command */
  	polcmd = parse_policy_command(stmt->cmd);
*************** CreatePolicy(CreatePolicyStmt *stmt)
*** 498,506 ****
  				(errcode(ERRCODE_SYNTAX_ERROR),
  				 errmsg("only WITH CHECK expression allowed for INSERT")));
  
- 
  	/* Collect role ids */
! 	role_ids = policy_role_list_to_array(stmt->roles);
  
  	/* Parse the supplied clause */
  	qual_pstate = make_parsestate(NULL);
--- 501,510 ----
  				(errcode(ERRCODE_SYNTAX_ERROR),
  				 errmsg("only WITH CHECK expression allowed for INSERT")));
  
  	/* Collect role ids */
! 	role_oids = policy_role_list_to_array(stmt->roles, &nitems);
! 	role_ids = construct_array(role_oids, nitems, OIDOID,
! 							   sizeof(Oid), true, 'i');
  
  	/* Parse the supplied clause */
  	qual_pstate = make_parsestate(NULL);
*************** CreatePolicy(CreatePolicyStmt *stmt)
*** 614,619 ****
--- 618,635 ----
  	recordDependencyOnExpr(&myself, with_check_qual,
  						   with_check_pstate->p_rtable, DEPENDENCY_NORMAL);
  
+ 	/* Register role dependencies */
+ 	target.classId = AuthIdRelationId;
+ 	target.objectSubId = 0;
+ 	for (i = 0; i < nitems; i++)
+ 	{
+ 		target.objectId = DatumGetObjectId(role_oids[i]);
+ 		/* no dependency if public */
+ 		if (target.objectId != ACL_ID_PUBLIC)
+ 			recordSharedDependencyOn(&myself, &target,
+ 									 SHARED_DEPENDENCY_ACL);
+ 	}
+ 
  	/* Invalidate Relation Cache */
  	CacheInvalidateRelcache(target_table);
  
*************** AlterPolicy(AlterPolicyStmt *stmt)
*** 641,646 ****
--- 657,664 ----
  	Oid			policy_id;
  	Relation	target_table;
  	Oid			table_id;
+ 	Datum	   *role_oids;
+ 	int			nitems = 0;
  	ArrayType  *role_ids = NULL;
  	List	   *qual_parse_rtable = NIL;
  	List	   *with_check_parse_rtable = NIL;
*************** AlterPolicy(AlterPolicyStmt *stmt)
*** 658,667 ****
  	Datum		cmd_datum;
  	char		polcmd;
  	bool		polcmd_isnull;
  
  	/* Parse role_ids */
  	if (stmt->roles != NULL)
! 		role_ids = policy_role_list_to_array(stmt->roles);
  
  	/* Get id of table.  Also handles permissions checks. */
  	table_id = RangeVarGetRelidExtended(stmt->table, AccessExclusiveLock,
--- 676,690 ----
  	Datum		cmd_datum;
  	char		polcmd;
  	bool		polcmd_isnull;
+ 	int			i;
  
  	/* Parse role_ids */
  	if (stmt->roles != NULL)
! 	{
! 		role_oids = policy_role_list_to_array(stmt->roles, &nitems);
! 		role_ids = construct_array(role_oids, nitems, OIDOID,
! 								   sizeof(Oid), true, 'i');
! 	}
  
  	/* Get id of table.  Also handles permissions checks. */
  	table_id = RangeVarGetRelidExtended(stmt->table, AccessExclusiveLock,
*************** AlterPolicy(AlterPolicyStmt *stmt)
*** 825,830 ****
--- 848,866 ----
  	recordDependencyOnExpr(&myself, with_check_qual, with_check_parse_rtable,
  						   DEPENDENCY_NORMAL);
  
+ 	/* Register role dependencies */
+ 	deleteSharedDependencyRecordsFor(PolicyRelationId, policy_id, 0);
+ 	target.classId = AuthIdRelationId;
+ 	target.objectSubId = 0;
+ 	for (i = 0; i < nitems; i++)
+ 	{
+ 		target.objectId = DatumGetObjectId(role_oids[i]);
+ 		/* no dependency if public */
+ 		if (target.objectId != ACL_ID_PUBLIC)
+ 			recordSharedDependencyOn(&myself, &target,
+ 									 SHARED_DEPENDENCY_ACL);
+ 	}
+ 
  	heap_freetuple(new_tuple);
  
  	/* Invalidate Relation Cache */
diff --git a/src/test/regress/expected/rowsecurity.out b/src/test/regress/expected/rowsecurity.out
index e7c242c..48c85ca 100644
*** a/src/test/regress/expected/rowsecurity.out
--- b/src/test/regress/expected/rowsecurity.out
*************** SELECT * FROM coll_t;
*** 2860,2865 ****
--- 2860,2936 ----
  
  ROLLBACK;
  --
+ -- Shared Object Dependencies
+ --
+ RESET SESSION AUTHORIZATION;
+ BEGIN;
+ CREATE ROLE alice;
+ CREATE ROLE bob;
+ CREATE TABLE tbl1 (c) AS VALUES ('bar'::text);
+ GRANT SELECT ON TABLE tbl1 TO alice;
+ CREATE POLICY P ON tbl1 TO alice, bob USING (true);
+ SELECT refclassid::regclass, deptype
+   FROM pg_depend
+   WHERE classid = 'pg_policy'::regclass
+   AND refobjid = 'tbl1'::regclass;
+  refclassid | deptype 
+ ------------+---------
+  pg_class   | a
+ (1 row)
+ 
+ SELECT refclassid::regclass, deptype
+   FROM pg_shdepend
+   WHERE classid = 'pg_policy'::regclass
+   AND refobjid IN ('alice'::regrole, 'bob'::regrole);
+  refclassid | deptype 
+ ------------+---------
+  pg_authid  | a
+  pg_authid  | a
+ (2 rows)
+ 
+ SAVEPOINT q;
+ DROP ROLE alice; --fails due to dependency on POLICY p
+ ERROR:  role "alice" cannot be dropped because some objects depend on it
+ DETAIL:  privileges for policy p on table tbl1
+ privileges for table tbl1
+ ROLLBACK TO q;
+ ALTER POLICY p ON tbl1 TO bob USING (true);
+ SAVEPOINT q;
+ DROP ROLE alice; --fails due to dependency on GRANT SELECT
+ ERROR:  role "alice" cannot be dropped because some objects depend on it
+ DETAIL:  privileges for table tbl1
+ ROLLBACK TO q;
+ REVOKE ALL ON TABLE tbl1 FROM alice;
+ SAVEPOINT q;
+ DROP ROLE alice; --succeeds
+ ROLLBACK TO q;
+ SAVEPOINT q;
+ DROP ROLE bob; --fails due to dependency on POLICY p
+ ERROR:  role "bob" cannot be dropped because some objects depend on it
+ DETAIL:  privileges for policy p on table tbl1
+ ROLLBACK TO q;
+ DROP POLICY p ON tbl1;
+ SAVEPOINT q;
+ DROP ROLE bob; -- succeeds
+ ROLLBACK TO q;
+ SELECT refclassid::regclass, deptype
+   FROM pg_depend
+   WHERE classid = 'pg_policy'::regclass
+   AND refobjid = 'tbl1'::regclass;
+  refclassid | deptype 
+ ------------+---------
+ (0 rows)
+ 
+ SELECT refclassid::regclass, deptype
+   FROM pg_shdepend
+   WHERE classid = 'pg_policy'::regclass
+   AND refobjid IN ('alice'::regrole, 'bob'::regrole);
+  refclassid | deptype 
+ ------------+---------
+ (0 rows)
+ 
+ ROLLBACK; -- cleanup
+ --
  -- Clean up objects
  --
  RESET SESSION AUTHORIZATION;
diff --git a/src/test/regress/sql/rowsecurity.sql b/src/test/regress/sql/rowsecurity.sql
index e86f814..f1f1b6b 100644
*** a/src/test/regress/sql/rowsecurity.sql
--- b/src/test/regress/sql/rowsecurity.sql
*************** SELECT * FROM coll_t;
*** 1153,1158 ****
--- 1153,1211 ----
  ROLLBACK;
  
  --
+ -- Shared Object Dependencies
+ --
+ RESET SESSION AUTHORIZATION;
+ BEGIN;
+ CREATE ROLE alice;
+ CREATE ROLE bob;
+ CREATE TABLE tbl1 (c) AS VALUES ('bar'::text);
+ GRANT SELECT ON TABLE tbl1 TO alice;
+ CREATE POLICY P ON tbl1 TO alice, bob USING (true);
+ SELECT refclassid::regclass, deptype
+   FROM pg_depend
+   WHERE classid = 'pg_policy'::regclass
+   AND refobjid = 'tbl1'::regclass;
+ SELECT refclassid::regclass, deptype
+   FROM pg_shdepend
+   WHERE classid = 'pg_policy'::regclass
+   AND refobjid IN ('alice'::regrole, 'bob'::regrole);
+ 
+ SAVEPOINT q;
+ DROP ROLE alice; --fails due to dependency on POLICY p
+ ROLLBACK TO q;
+ 
+ ALTER POLICY p ON tbl1 TO bob USING (true);
+ SAVEPOINT q;
+ DROP ROLE alice; --fails due to dependency on GRANT SELECT
+ ROLLBACK TO q;
+ 
+ REVOKE ALL ON TABLE tbl1 FROM alice;
+ SAVEPOINT q;
+ DROP ROLE alice; --succeeds
+ ROLLBACK TO q;
+ 
+ SAVEPOINT q;
+ DROP ROLE bob; --fails due to dependency on POLICY p
+ ROLLBACK TO q;
+ 
+ DROP POLICY p ON tbl1;
+ SAVEPOINT q;
+ DROP ROLE bob; -- succeeds
+ ROLLBACK TO q;
+ 
+ SELECT refclassid::regclass, deptype
+   FROM pg_depend
+   WHERE classid = 'pg_policy'::regclass
+   AND refobjid = 'tbl1'::regclass;
+ SELECT refclassid::regclass, deptype
+   FROM pg_shdepend
+   WHERE classid = 'pg_policy'::regclass
+   AND refobjid IN ('alice'::regrole, 'bob'::regrole);
+ 
+ ROLLBACK; -- cleanup
+ 
+ --
  -- Clean up objects
  --
  RESET SESSION AUTHORIZATION;
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to