From 07d1edb954bc8f5d0e2c010dec8482328af38cb8 Mon Sep 17 00:00:00 2001 From: Robert Haas Date: Fri, 9 Mar 2012 14:34:56 -0500 Subject: [PATCH] Extend object access hook framework to support arguments, and DROP. This allows loadable modules to get control at drop time, perhaps for the purpose of performing additional security checks or to log the event. The initial purpose of this code is to support sepgsql, but other applications should be possible as well. KaiGai Kohei, reviewed by me. --- src/backend/catalog/dependency.c | 10 ++++++++ src/backend/catalog/heap.c | 3 ++- src/backend/catalog/pg_collation.c | 2 +- src/backend/catalog/pg_constraint.c | 3 ++- src/backend/catalog/pg_conversion.c | 4 +-- src/backend/catalog/pg_namespace.c | 3 ++- src/backend/catalog/pg_operator.c | 4 +-- src/backend/catalog/pg_proc.c | 3 ++- src/backend/catalog/pg_type.c | 6 +++-- src/backend/commands/dbcommands.c | 12 ++++++++- src/backend/commands/extension.c | 2 +- src/backend/commands/foreigncmds.c | 8 +++--- src/backend/commands/functioncmds.c | 3 ++- src/backend/commands/opclasscmds.c | 4 +-- src/backend/commands/proclang.c | 2 +- src/backend/commands/tablecmds.c | 2 +- src/backend/commands/tablespace.c | 11 +++++++- src/backend/commands/trigger.c | 2 +- src/backend/commands/tsearchcmds.c | 11 +++++--- src/backend/commands/user.c | 12 ++++++++- src/backend/rewrite/rewriteDefine.c | 2 +- src/backend/storage/large_object/inv_api.c | 2 +- src/include/catalog/objectaccess.h | 29 +++++++++++++++++----- 23 files changed, 104 insertions(+), 36 deletions(-) diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c index eca064f0cd..1b92f5c38a 100644 --- a/src/backend/catalog/dependency.c +++ b/src/backend/catalog/dependency.c @@ -20,6 +20,7 @@ #include "catalog/heap.h" #include "catalog/index.h" #include "catalog/namespace.h" +#include "catalog/objectaccess.h" #include "catalog/pg_amop.h" #include "catalog/pg_amproc.h" #include "catalog/pg_attrdef.h" @@ -991,6 +992,15 @@ deleteOneObject(const ObjectAddress *object, Relation depRel, int flags) SysScanDesc scan; HeapTuple tup; + /* DROP hook of the objects being removed */ + if (object_access_hook) + { + ObjectAccessDrop drop_arg; + drop_arg.dropflags = flags; + InvokeObjectAccessHook(OAT_DROP, object->classId, object->objectId, + object->objectSubId, &drop_arg); + } + /* * First remove any pg_depend records that link from this object to * others. (Any records linking to this object should be gone already.) diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index d1d458d7fa..8bd5a9296e 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -1286,7 +1286,8 @@ heap_create_with_catalog(const char *relname, } /* Post creation hook for new relation */ - InvokeObjectAccessHook(OAT_POST_CREATE, RelationRelationId, relid, 0); + InvokeObjectAccessHook(OAT_POST_CREATE, + RelationRelationId, relid, 0, NULL); /* * Store any supplied constraints and defaults. diff --git a/src/backend/catalog/pg_collation.c b/src/backend/catalog/pg_collation.c index 511d70c044..18c7acf0e8 100644 --- a/src/backend/catalog/pg_collation.c +++ b/src/backend/catalog/pg_collation.c @@ -136,7 +136,7 @@ CollationCreate(const char *collname, Oid collnamespace, /* Post creation hook for new collation */ InvokeObjectAccessHook(OAT_POST_CREATE, - CollationRelationId, oid, 0); + CollationRelationId, oid, 0, NULL); heap_freetuple(tup); heap_close(rel, RowExclusiveLock); diff --git a/src/backend/catalog/pg_constraint.c b/src/backend/catalog/pg_constraint.c index 0bad4d99cb..342cf75270 100644 --- a/src/backend/catalog/pg_constraint.c +++ b/src/backend/catalog/pg_constraint.c @@ -366,7 +366,8 @@ CreateConstraintEntry(const char *constraintName, } /* Post creation hook for new constraint */ - InvokeObjectAccessHook(OAT_POST_CREATE, ConstraintRelationId, conOid, 0); + InvokeObjectAccessHook(OAT_POST_CREATE, + ConstraintRelationId, conOid, 0, NULL); return conOid; } diff --git a/src/backend/catalog/pg_conversion.c b/src/backend/catalog/pg_conversion.c index 8194cd6c26..f86c84fc4b 100644 --- a/src/backend/catalog/pg_conversion.c +++ b/src/backend/catalog/pg_conversion.c @@ -134,8 +134,8 @@ ConversionCreate(const char *conname, Oid connamespace, recordDependencyOnCurrentExtension(&myself, false); /* Post creation hook for new conversion */ - InvokeObjectAccessHook(OAT_POST_CREATE, - ConversionRelationId, HeapTupleGetOid(tup), 0); + InvokeObjectAccessHook(OAT_POST_CREATE, ConversionRelationId, + HeapTupleGetOid(tup), 0, NULL); heap_freetuple(tup); heap_close(rel, RowExclusiveLock); diff --git a/src/backend/catalog/pg_namespace.c b/src/backend/catalog/pg_namespace.c index be812a246c..de856760f0 100644 --- a/src/backend/catalog/pg_namespace.c +++ b/src/backend/catalog/pg_namespace.c @@ -95,7 +95,8 @@ NamespaceCreate(const char *nspName, Oid ownerId, bool isTemp) recordDependencyOnCurrentExtension(&myself, false); /* Post creation hook for new schema */ - InvokeObjectAccessHook(OAT_POST_CREATE, NamespaceRelationId, nspoid, 0); + InvokeObjectAccessHook(OAT_POST_CREATE, + NamespaceRelationId, nspoid, 0, NULL); return nspoid; } diff --git a/src/backend/catalog/pg_operator.c b/src/backend/catalog/pg_operator.c index 3b72722241..4fd55ae570 100644 --- a/src/backend/catalog/pg_operator.c +++ b/src/backend/catalog/pg_operator.c @@ -275,7 +275,7 @@ OperatorShellMake(const char *operatorName, /* Post creation hook for new shell operator */ InvokeObjectAccessHook(OAT_POST_CREATE, - OperatorRelationId, operatorObjectId, 0); + OperatorRelationId, operatorObjectId, 0, NULL); /* * Make sure the tuple is visible for subsequent lookups/updates. @@ -544,7 +544,7 @@ OperatorCreate(const char *operatorName, /* Post creation hook for new operator */ InvokeObjectAccessHook(OAT_POST_CREATE, - OperatorRelationId, operatorObjectId, 0); + OperatorRelationId, operatorObjectId, 0, NULL); heap_close(pg_operator_desc, RowExclusiveLock); diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c index 91ead4cb9d..1fffe1c6ac 100644 --- a/src/backend/catalog/pg_proc.c +++ b/src/backend/catalog/pg_proc.c @@ -655,7 +655,8 @@ ProcedureCreate(const char *procedureName, heap_freetuple(tup); /* Post creation hook for new function */ - InvokeObjectAccessHook(OAT_POST_CREATE, ProcedureRelationId, retval, 0); + InvokeObjectAccessHook(OAT_POST_CREATE, + ProcedureRelationId, retval, 0, NULL); heap_close(rel, RowExclusiveLock); diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c index 2c2e3b3e7c..5b2ad6bfe0 100644 --- a/src/backend/catalog/pg_type.c +++ b/src/backend/catalog/pg_type.c @@ -162,7 +162,8 @@ TypeShellMake(const char *typeName, Oid typeNamespace, Oid ownerId) false); /* Post creation hook for new shell type */ - InvokeObjectAccessHook(OAT_POST_CREATE, TypeRelationId, typoid, 0); + InvokeObjectAccessHook(OAT_POST_CREATE, + TypeRelationId, typoid, 0, NULL); /* * clean up and return the type-oid @@ -474,7 +475,8 @@ TypeCreate(Oid newTypeOid, rebuildDeps); /* Post creation hook for new type */ - InvokeObjectAccessHook(OAT_POST_CREATE, TypeRelationId, typeObjectId, 0); + InvokeObjectAccessHook(OAT_POST_CREATE, + TypeRelationId, typeObjectId, 0, NULL); /* * finish up diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c index 42a8b31b2a..91d7481528 100644 --- a/src/backend/commands/dbcommands.c +++ b/src/backend/commands/dbcommands.c @@ -515,7 +515,8 @@ createdb(const CreatedbStmt *stmt) copyTemplateDependencies(src_dboid, dboid); /* Post creation hook for new database */ - InvokeObjectAccessHook(OAT_POST_CREATE, DatabaseRelationId, dboid, 0); + InvokeObjectAccessHook(OAT_POST_CREATE, + DatabaseRelationId, dboid, 0, NULL); /* * Force a checkpoint before starting the copy. This will force dirty @@ -777,6 +778,15 @@ dropdb(const char *dbname, bool missing_ok) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE, dbname); + /* DROP hook for the database being removed */ + if (object_access_hook) + { + ObjectAccessDrop drop_arg; + memset(&drop_arg, 0, sizeof(ObjectAccessDrop)); + InvokeObjectAccessHook(OAT_DROP, + DatabaseRelationId, db_id, 0, &drop_arg); + } + /* * Disallow dropping a DB that is marked istemplate. This is just to * prevent people from accidentally dropping template0 or template1; they diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c index a9963ac93b..732791cc41 100644 --- a/src/backend/commands/extension.c +++ b/src/backend/commands/extension.c @@ -1558,7 +1558,7 @@ InsertExtensionTuple(const char *extName, Oid extOwner, } /* Post creation hook for new extension */ InvokeObjectAccessHook(OAT_POST_CREATE, - ExtensionRelationId, extensionOid, 0); + ExtensionRelationId, extensionOid, 0, NULL); return extensionOid; } diff --git a/src/backend/commands/foreigncmds.c b/src/backend/commands/foreigncmds.c index 5d18bdcf0a..30135e6de8 100644 --- a/src/backend/commands/foreigncmds.c +++ b/src/backend/commands/foreigncmds.c @@ -666,7 +666,7 @@ CreateForeignDataWrapper(CreateFdwStmt *stmt) /* Post creation hook for new foreign data wrapper */ InvokeObjectAccessHook(OAT_POST_CREATE, - ForeignDataWrapperRelationId, fdwId, 0); + ForeignDataWrapperRelationId, fdwId, 0, NULL); heap_close(rel, RowExclusiveLock); } @@ -962,7 +962,8 @@ CreateForeignServer(CreateForeignServerStmt *stmt) recordDependencyOnCurrentExtension(&myself, false); /* Post creation hook for new foreign server */ - InvokeObjectAccessHook(OAT_POST_CREATE, ForeignServerRelationId, srvId, 0); + InvokeObjectAccessHook(OAT_POST_CREATE, + ForeignServerRelationId, srvId, 0, NULL); heap_close(rel, RowExclusiveLock); } @@ -1202,7 +1203,8 @@ CreateUserMapping(CreateUserMappingStmt *stmt) recordDependencyOnCurrentExtension(&myself, false); /* Post creation hook for new user mapping */ - InvokeObjectAccessHook(OAT_POST_CREATE, UserMappingRelationId, umId, 0); + InvokeObjectAccessHook(OAT_POST_CREATE, + UserMappingRelationId, umId, 0, NULL); heap_close(rel, RowExclusiveLock); } diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c index ce866a20a9..4125b97e89 100644 --- a/src/backend/commands/functioncmds.c +++ b/src/backend/commands/functioncmds.c @@ -1759,7 +1759,8 @@ CreateCast(CreateCastStmt *stmt) recordDependencyOnCurrentExtension(&myself, false); /* Post creation hook for new cast */ - InvokeObjectAccessHook(OAT_POST_CREATE, CastRelationId, castid, 0); + InvokeObjectAccessHook(OAT_POST_CREATE, + CastRelationId, castid, 0, NULL); heap_freetuple(tuple); diff --git a/src/backend/commands/opclasscmds.c b/src/backend/commands/opclasscmds.c index 5dc131a50e..87c889604e 100644 --- a/src/backend/commands/opclasscmds.c +++ b/src/backend/commands/opclasscmds.c @@ -314,7 +314,7 @@ CreateOpFamily(char *amname, char *opfname, Oid namespaceoid, Oid amoid) /* Post creation hook for new operator family */ InvokeObjectAccessHook(OAT_POST_CREATE, - OperatorFamilyRelationId, opfamilyoid, 0); + OperatorFamilyRelationId, opfamilyoid, 0, NULL); heap_close(rel, RowExclusiveLock); @@ -717,7 +717,7 @@ DefineOpClass(CreateOpClassStmt *stmt) /* Post creation hook for new operator class */ InvokeObjectAccessHook(OAT_POST_CREATE, - OperatorClassRelationId, opclassoid, 0); + OperatorClassRelationId, opclassoid, 0, NULL); heap_close(rel, RowExclusiveLock); } diff --git a/src/backend/commands/proclang.c b/src/backend/commands/proclang.c index 8d6a0416d5..41775fd867 100644 --- a/src/backend/commands/proclang.c +++ b/src/backend/commands/proclang.c @@ -428,7 +428,7 @@ create_proc_lang(const char *languageName, bool replace, /* Post creation hook for new procedural language */ InvokeObjectAccessHook(OAT_POST_CREATE, - LanguageRelationId, myself.objectId, 0); + LanguageRelationId, myself.objectId, 0, NULL); heap_close(rel, RowExclusiveLock); } diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index cd4490a1c2..25ca356b86 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -4382,7 +4382,7 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel, /* Post creation hook for new attribute */ InvokeObjectAccessHook(OAT_POST_CREATE, - RelationRelationId, myrelid, newattnum); + RelationRelationId, myrelid, newattnum, NULL); heap_close(pgclass, RowExclusiveLock); diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c index 5e10f8c9a3..d66ea3b6c1 100644 --- a/src/backend/commands/tablespace.c +++ b/src/backend/commands/tablespace.c @@ -330,7 +330,7 @@ CreateTableSpace(CreateTableSpaceStmt *stmt) /* Post creation hook for new tablespace */ InvokeObjectAccessHook(OAT_POST_CREATE, - TableSpaceRelationId, tablespaceoid, 0); + TableSpaceRelationId, tablespaceoid, 0, NULL); create_tablespace_directories(location, tablespaceoid); @@ -434,6 +434,15 @@ DropTableSpace(DropTableSpaceStmt *stmt) aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_TABLESPACE, tablespacename); + /* DROP hook for the tablespace being removed */ + if (object_access_hook) + { + ObjectAccessDrop drop_arg; + memset(&drop_arg, 0, sizeof(ObjectAccessDrop)); + InvokeObjectAccessHook(OAT_DROP, TableSpaceRelationId, + tablespaceoid, 0, &drop_arg); + } + /* * Remove the pg_tablespace tuple (this will roll back if we fail below) */ diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index caae2dafab..a98d1b884e 100644 --- a/src/backend/commands/trigger.c +++ b/src/backend/commands/trigger.c @@ -756,7 +756,7 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString, /* Post creation hook for new trigger */ InvokeObjectAccessHook(OAT_POST_CREATE, - TriggerRelationId, trigoid, 0); + TriggerRelationId, trigoid, 0, NULL); /* Keep lock on target rel until end of xact */ heap_close(rel, NoLock); diff --git a/src/backend/commands/tsearchcmds.c b/src/backend/commands/tsearchcmds.c index fe500a6d7f..86cb8704da 100644 --- a/src/backend/commands/tsearchcmds.c +++ b/src/backend/commands/tsearchcmds.c @@ -271,7 +271,8 @@ DefineTSParser(List *names, List *parameters) makeParserDependencies(tup); /* Post creation hook for new text search parser */ - InvokeObjectAccessHook(OAT_POST_CREATE, TSParserRelationId, prsOid, 0); + InvokeObjectAccessHook(OAT_POST_CREATE, + TSParserRelationId, prsOid, 0, NULL); heap_freetuple(tup); @@ -565,7 +566,7 @@ DefineTSDictionary(List *names, List *parameters) /* Post creation hook for new text search dictionary */ InvokeObjectAccessHook(OAT_POST_CREATE, - TSDictionaryRelationId, dictOid, 0); + TSDictionaryRelationId, dictOid, 0, NULL); heap_freetuple(tup); @@ -1036,7 +1037,8 @@ DefineTSTemplate(List *names, List *parameters) makeTSTemplateDependencies(tup); /* Post creation hook for new text search template */ - InvokeObjectAccessHook(OAT_POST_CREATE, TSTemplateRelationId, dictOid, 0); + InvokeObjectAccessHook(OAT_POST_CREATE, + TSTemplateRelationId, dictOid, 0, NULL); heap_freetuple(tup); @@ -1419,7 +1421,8 @@ DefineTSConfiguration(List *names, List *parameters) makeConfigurationDependencies(tup, false, mapRel); /* Post creation hook for new text search configuration */ - InvokeObjectAccessHook(OAT_POST_CREATE, TSConfigRelationId, cfgOid, 0); + InvokeObjectAccessHook(OAT_POST_CREATE, + TSConfigRelationId, cfgOid, 0, NULL); heap_freetuple(tup); diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c index 9a88c90789..2edbabe754 100644 --- a/src/backend/commands/user.c +++ b/src/backend/commands/user.c @@ -425,7 +425,8 @@ CreateRole(CreateRoleStmt *stmt) GetUserId(), false); /* Post creation hook for new role */ - InvokeObjectAccessHook(OAT_POST_CREATE, AuthIdRelationId, roleid, 0); + InvokeObjectAccessHook(OAT_POST_CREATE, + AuthIdRelationId, roleid, 0, NULL); /* * Close pg_authid, but keep lock till commit. @@ -932,6 +933,15 @@ DropRole(DropRoleStmt *stmt) (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be superuser to drop superusers"))); + /* DROP hook for the role being removed */ + if (object_access_hook) + { + ObjectAccessDrop drop_arg; + memset(&drop_arg, 0, sizeof(ObjectAccessDrop)); + InvokeObjectAccessHook(OAT_DROP, + AuthIdRelationId, roleid, 0, &drop_arg); + } + /* * Lock the role, so nobody can add dependencies to her while we drop * her. We keep the lock until the end of transaction. diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c index 8c87ac599f..645182dbfa 100644 --- a/src/backend/rewrite/rewriteDefine.c +++ b/src/backend/rewrite/rewriteDefine.c @@ -178,7 +178,7 @@ InsertRule(char *rulname, /* Post creation hook for new rule */ InvokeObjectAccessHook(OAT_POST_CREATE, - RewriteRelationId, rewriteObjectId, 0); + RewriteRelationId, rewriteObjectId, 0, NULL); heap_close(pg_rewrite_desc, RowExclusiveLock); diff --git a/src/backend/storage/large_object/inv_api.c b/src/backend/storage/large_object/inv_api.c index a14ce442c1..3adfb159b8 100644 --- a/src/backend/storage/large_object/inv_api.c +++ b/src/backend/storage/large_object/inv_api.c @@ -217,7 +217,7 @@ inv_create(Oid lobjId) /* Post creation hook for new large object */ InvokeObjectAccessHook(OAT_POST_CREATE, - LargeObjectRelationId, lobjId_new, 0); + LargeObjectRelationId, lobjId_new, 0, NULL); /* * Advance command counter to make new tuple visible to later operations. diff --git a/src/include/catalog/objectaccess.h b/src/include/catalog/objectaccess.h index 5c7a40a31c..9763280177 100644 --- a/src/include/catalog/objectaccess.h +++ b/src/include/catalog/objectaccess.h @@ -19,28 +19,45 @@ * Typically, this is done after inserting the primary catalog records and * associated dependencies. * + * OAT_DROP should be invoked just before deletion of objects; typically + * deleteOneObject(). Its arguments are packed within ObjectAccessDrop. + * * Other types may be added in the future. */ typedef enum ObjectAccessType { OAT_POST_CREATE, + OAT_DROP, } ObjectAccessType; +/* + * Arguments of OAT_DROP event + */ +typedef struct +{ + /* + * Flags to inform extensions the context of this deletion. + * Also see PERFORM_DELETION_* in dependency.h + */ + int dropflags; +} ObjectAccessDrop; + /* * Hook, and a macro to invoke it. */ - typedef void (*object_access_hook_type) (ObjectAccessType access, Oid classId, Oid objectId, - int subId); + int subId, + void *arg); extern PGDLLIMPORT object_access_hook_type object_access_hook; -#define InvokeObjectAccessHook(access,classId,objectId,subId) \ - do { \ - if (object_access_hook) \ - (*object_access_hook)((access),(classId),(objectId),(subId)); \ +#define InvokeObjectAccessHook(access,classId,objectId,subId,arg) \ + do { \ + if (object_access_hook) \ + (*object_access_hook)((access),(classId), \ + (objectId),(subId),(arg)); \ } while(0) #endif /* OBJECTACCESS_H */