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 <[email protected]>
*** 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 ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers