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