This patch allows external security providers to check privileges
to create a new relation and to inform the security labels to be
assigned on the new one.

This hook is put on DefineRelation() and OpenIntoRel(), but isn't
put on Boot_CreateStmt, create_toast_table() and make_new_heap(),
although they actually create a relation, because I assume these
are the cases when we don't need individual checks and security
labels.

DefineIndex() also creates a new relation (RELKIND_INDEX), but
it seems to me the PG implementation considers indexes are a part
of properties of tables, because it always has same owner-id.
So, it shall be checked at the upcoming ALTER TABLE hook, instead.

The ESP plugins can return a list of security labels of the new
relation, columns and relation-type. If multiple ESPs are installed,
it shall append its security labels on the security labels of the
secondary plugin.
The list shall be a list of SecLabelItem as follows:
  typedef struct
  {
      ObjectAddress   object;
      const char     *tag;
      const char     *seclabel;
  } SecLabelItem;
OID of them are decided in heap_create_with_catalog(), so ESP cannot
know what OID shall be supplied at the point where it makes access
control decision.
So, the core routine fix up the SecLabelItem::object->objectId later,
if InvalidOid is given. I think it is a reasonable idea rather than
putting one more hook to store security labels after the table creation.

Please also note that this patch depends on the security label support
patch that I submitted before.

Thanks,
-- 
KaiGai Kohei <kai...@ak.jp.nec.com>
*** a/src/backend/bootstrap/bootparse.y
--- b/src/backend/bootstrap/bootparse.y
***************
*** 246,252 **** Boot_CreateStmt:
  													  (Datum) 0,
  													  false,
  													  true,
! 													  false);
  						elog(DEBUG4, "relation created with oid %u", id);
  					}
  					do_end();
--- 246,253 ----
  													  (Datum) 0,
  													  false,
  													  true,
! 													  false,
! 													  NIL);
  						elog(DEBUG4, "relation created with oid %u", id);
  					}
  					do_end();
*** a/src/backend/catalog/heap.c
--- b/src/backend/catalog/heap.c
***************
*** 49,54 ****
--- 49,55 ----
  #include "catalog/pg_type.h"
  #include "catalog/pg_type_fn.h"
  #include "catalog/storage.h"
+ #include "commands/seclabel.h"
  #include "commands/tablecmds.h"
  #include "commands/typecmds.h"
  #include "miscadmin.h"
***************
*** 94,99 **** static Oid AddNewRelationType(const char *typeName,
--- 95,101 ----
  static void RelationRemoveInheritance(Oid relid);
  static void StoreRelCheck(Relation rel, char *ccname, Node *expr,
  			  bool is_local, int inhcount);
+ static void StoreSecLabels(Relation rel, Oid typeId, List *seclabels);
  static void StoreConstraints(Relation rel, List *cooked_constraints);
  static bool MergeWithExistingConstraint(Relation rel, char *ccname, Node *expr,
  							bool allow_merge, bool is_local);
***************
*** 882,887 **** AddNewRelationType(const char *typeName,
--- 884,890 ----
   *	use_user_acl: TRUE if should look for user-defined default permissions;
   *		if FALSE, relacl is always set NULL
   *	allow_system_table_mods: TRUE to allow creation in system namespaces
+  *	seclabels : list of security labels to be assigned on, if exist
   *
   * Returns the OID of the new relation
   * --------------------------------
***************
*** 905,911 **** heap_create_with_catalog(const char *relname,
  						 Datum reloptions,
  						 bool use_user_acl,
  						 bool allow_system_table_mods,
! 						 bool if_not_exists)
  {
  	Relation	pg_class_desc;
  	Relation	new_rel_desc;
--- 908,915 ----
  						 Datum reloptions,
  						 bool use_user_acl,
  						 bool allow_system_table_mods,
! 						 bool if_not_exists,
! 						 List *seclabels)
  {
  	Relation	pg_class_desc;
  	Relation	new_rel_desc;
***************
*** 1189,1194 **** heap_create_with_catalog(const char *relname,
--- 1193,1203 ----
  	}
  
  	/*
+ 	 * Store any supplied security labels of the relation
+ 	 */
+ 	StoreSecLabels(new_rel_desc, new_type_oid, seclabels);
+ 
+ 	/*
  	 * Store any supplied constraints and defaults.
  	 *
  	 * NB: this may do a CommandCounterIncrement and rebuild the relcache
***************
*** 1808,1813 **** StoreRelCheck(Relation rel, char *ccname, Node *expr,
--- 1817,1861 ----
  }
  
  /*
+  * Store any supplied security labels of the new relation
+  */
+ static void
+ StoreSecLabels(Relation rel, Oid typeId, List *seclabels)
+ {
+ 	ListCell   *l;
+ 
+ 	foreach (l, seclabels)
+ 	{
+ 		SecLabelItem   *sl = lfirst(l);
+ 		ObjectAddress	object;
+ 
+ 		Assert(sl->tag != NULL && sl->seclabel != NULL);
+ 
+ 		memcpy(&object, &sl->object, sizeof(object));
+ 
+ 		/*
+ 		 * It fixes up OID of the new relation and type, because these IDs were
+ 		 * not decided at the point when external security provider made access
+ 		 * control decision and returns security label to be assigned on.
+ 		 *
+ 		 * If SecLabelItem::object->objectId is InvalidOid, this routine shall
+ 		 * set OID of the relation (when classId == RelationRelationId) or
+ 		 * OID of the relation-type (when classId == TypeRelationId).
+ 		 */
+ 		if (object.classId == RelationRelationId &&
+ 			!OidIsValid(object.objectId))
+ 			object.objectId = RelationGetRelid(rel);
+ 		if (object.classId == TypeRelationId &&
+ 			!OidIsValid(object.objectId))
+ 			object.objectId = typeId;
+ 		/*
+ 		 * set security label of the new relations
+ 		 */
+ 		SetSecurityLabel(&object, sl->tag, sl->seclabel);
+ 	}
+ }
+ 
+ /*
   * Store defaults and constraints (passed as a list of CookedConstraint).
   *
   * NOTE: only pre-cooked expressions will be passed this way, which is to
*** a/src/backend/catalog/toasting.c
--- b/src/backend/catalog/toasting.c
***************
*** 224,230 **** create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, Datum reloptio
  										   reloptions,
  										   false,
  										   true,
! 										   false);
  	Assert(toast_relid != InvalidOid);
  
  	/* make the toast relation visible, else index creation will fail */
--- 224,231 ----
  										   reloptions,
  										   false,
  										   true,
! 										   false,
! 										   NIL);
  	Assert(toast_relid != InvalidOid);
  
  	/* make the toast relation visible, else index creation will fail */
*** a/src/backend/commands/cluster.c
--- b/src/backend/commands/cluster.c
***************
*** 688,694 **** make_new_heap(Oid OIDOldHeap, Oid NewTableSpace)
  										  reloptions,
  										  false,
  										  true,
! 										  false);
  	Assert(OIDNewHeap != InvalidOid);
  
  	ReleaseSysCache(tuple);
--- 688,695 ----
  										  reloptions,
  										  false,
  										  true,
! 										  false,
! 										  NIL);
  	Assert(OIDNewHeap != InvalidOid);
  
  	ReleaseSysCache(tuple);
*** a/src/backend/commands/tablecmds.c
--- b/src/backend/commands/tablecmds.c
***************
*** 221,226 **** static const struct dropmsgstrings dropmsgstringarray[] = {
--- 221,234 ----
  	{'\0', 0, NULL, NULL, NULL, NULL}
  };
  
+ /*
+  * A security hook for plugins to check permissions on table creation.
+  * It also allows plugins to return security labels of new new relation,
+  * columns and relation-type, as a list of SecLabelItem.
+  * At this point, these OIDs are not decided, so it shall be fixed up
+  * later, if SecLabelItem::object.objectId is InvalidOid.
+  */
+ check_relation_create_type check_relation_create_hook = NULL;
  
  static void truncate_check_rel(Relation rel);
  static List *MergeAttributes(List *schema, List *supers, bool istemp,
***************
*** 366,371 **** DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId)
--- 374,380 ----
  	TupleDesc	descriptor;
  	List	   *inheritOids;
  	List	   *old_constraints;
+ 	List	   *seclabels = NIL;
  	bool		localHasOids;
  	int			parentOidCount;
  	List	   *rawDefaults;
***************
*** 486,491 **** DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId)
--- 495,513 ----
  	descriptor->tdhasoid = (localHasOids || parentOidCount > 0);
  
  	/*
+ 	 * It allows external security providers to check permission to create
+ 	 * a new relation, and returns a list of security labels to be assigned
+ 	 * on the new relation.
+ 	 */
+ 	if (check_relation_create_hook)
+ 		seclabels = (*check_relation_create_hook)(relname,
+ 												  namespaceId,
+ 												  tablespaceId,
+ 												  relkind,
+ 												  descriptor,
+ 												  false);
+ 
+ 	/*
  	 * Find columns with default values and prepare for insertion of the
  	 * defaults.  Pre-cooked (that is, inherited) defaults go into a list of
  	 * CookedConstraint structs that we'll pass to heap_create_with_catalog,
***************
*** 559,565 **** DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId)
  										  reloptions,
  										  true,
  										  allowSystemTableMods,
! 										  stmt->if_not_exists);
  
  	/*
  	 * If heap_create_with_catalog returns InvalidOid, it means that the user
--- 581,588 ----
  										  reloptions,
  										  true,
  										  allowSystemTableMods,
! 										  stmt->if_not_exists,
! 										  seclabels);
  
  	/*
  	 * If heap_create_with_catalog returns InvalidOid, it means that the user
*** a/src/backend/executor/execMain.c
--- b/src/backend/executor/execMain.c
***************
*** 39,44 ****
--- 39,45 ----
  #include "catalog/heap.h"
  #include "catalog/namespace.h"
  #include "catalog/toasting.h"
+ #include "commands/tablecmds.h"
  #include "commands/tablespace.h"
  #include "commands/trigger.h"
  #include "executor/execdebug.h"
***************
*** 2086,2091 **** OpenIntoRel(QueryDesc *queryDesc)
--- 2087,2093 ----
  	Oid			tablespaceId;
  	Datum		reloptions;
  	AclResult	aclresult;
+ 	List	   *seclabels = NIL;
  	Oid			intoRelationId;
  	TupleDesc	tupdesc;
  	DR_intorel *myState;
***************
*** 2164,2169 **** OpenIntoRel(QueryDesc *queryDesc)
--- 2166,2180 ----
  									 false);
  	(void) heap_reloptions(RELKIND_RELATION, reloptions, true);
  
+ 	/* Check permission to create a new table */
+ 	if (check_relation_create_hook)
+ 		seclabels = (*check_relation_create_hook)(intoName,
+ 												  namespaceId,
+ 												  tablespaceId,
+ 												  RELKIND_RELATION,
+ 												  queryDesc->tupDesc,
+ 												  true);
+ 
  	/* Copy the tupdesc because heap_create_with_catalog modifies it */
  	tupdesc = CreateTupleDescCopy(queryDesc->tupDesc);
  
***************
*** 2186,2192 **** OpenIntoRel(QueryDesc *queryDesc)
  											  reloptions,
  											  true,
  											  allowSystemTableMods,
! 											  false);
  	Assert(intoRelationId != InvalidOid);
  
  	FreeTupleDesc(tupdesc);
--- 2197,2204 ----
  											  reloptions,
  											  true,
  											  allowSystemTableMods,
! 											  false,
! 											  seclabels);
  	Assert(intoRelationId != InvalidOid);
  
  	FreeTupleDesc(tupdesc);
*** a/src/include/catalog/heap.h
--- b/src/include/catalog/heap.h
***************
*** 62,68 **** extern Oid heap_create_with_catalog(const char *relname,
  						 Datum reloptions,
  						 bool use_user_acl,
  						 bool allow_system_table_mods,
! 						 bool if_not_exists);
  
  extern void heap_drop_with_catalog(Oid relid);
  
--- 62,69 ----
  						 Datum reloptions,
  						 bool use_user_acl,
  						 bool allow_system_table_mods,
! 						 bool if_not_exists,
! 						 List *seclabels);
  
  extern void heap_drop_with_catalog(Oid relid);
  
*** a/src/include/commands/seclabel.h
--- b/src/include/commands/seclabel.h
***************
*** 13,18 ****
--- 13,25 ----
  #include "nodes/primnodes.h"
  #include "nodes/parsenodes.h"
  
+ typedef struct
+ {
+ 	ObjectAddress	object;
+ 	const char	   *tag;
+ 	const char	   *seclabel;
+ } SecLabelItem;
+ 
  /*
   * Internal APIs
   */
*** a/src/include/commands/tablecmds.h
--- b/src/include/commands/tablecmds.h
***************
*** 73,76 **** extern void AtEOSubXact_on_commit_actions(bool isCommit,
--- 73,87 ----
  							  SubTransactionId mySubid,
  							  SubTransactionId parentSubid);
  
+ /*
+  * security hook on creation of a new relation
+  */
+ typedef List *(*check_relation_create_type)(const char *relname,
+ 											Oid namespaceId,
+ 											Oid tablespaceId,
+ 											char relkind,
+ 											TupleDesc tupdesc,
+ 											bool createAs);
+ extern check_relation_create_type check_relation_create_hook;
+ 
  #endif   /* TABLECMDS_H */
-- 
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