268 lines
9.2 KiB
C
268 lines
9.2 KiB
C
/*
|
|
* objectaccess.h
|
|
*
|
|
* Object access hooks.
|
|
*
|
|
* Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
*/
|
|
|
|
#ifndef OBJECTACCESS_H
|
|
#define OBJECTACCESS_H
|
|
|
|
/*
|
|
* Object access hooks are intended to be called just before or just after
|
|
* performing certain actions on a SQL object. This is intended as
|
|
* infrastructure for security or logging plugins.
|
|
*
|
|
* OAT_POST_CREATE should be invoked just after the object is created.
|
|
* Typically, this is done after inserting the primary catalog records and
|
|
* associated dependencies. The command counter may or may not be incremented
|
|
* at the time the hook is invoked; if not, the extension can use SnapshotSelf
|
|
* to get the new version of the tuple.
|
|
*
|
|
* OAT_DROP should be invoked just before deletion of objects; typically
|
|
* deleteOneObject(). Its arguments are packed within ObjectAccessDrop.
|
|
*
|
|
* OAT_POST_ALTER should be invoked just after the object is altered,
|
|
* but before the command counter is incremented. An extension using the
|
|
* hook can use a current MVCC snapshot to get the old version of the tuple,
|
|
* and can use SnapshotSelf to get the new version of the tuple.
|
|
*
|
|
* OAT_NAMESPACE_SEARCH should be invoked prior to object name lookup under
|
|
* a particular namespace. This event is equivalent to usage permission
|
|
* on a schema under the default access control mechanism.
|
|
*
|
|
* OAT_FUNCTION_EXECUTE should be invoked prior to function execution.
|
|
* This event is almost equivalent to execute permission on functions,
|
|
* except for the case when execute permission is checked during object
|
|
* creation or altering, because OAT_POST_CREATE or OAT_POST_ALTER are
|
|
* sufficient for extensions to track these kind of checks.
|
|
*
|
|
* OAT_TRUNCATE should be invoked just before truncation of objects. This
|
|
* event is equivalent to truncate permission on a relation under the
|
|
* default access control mechanism.
|
|
*
|
|
* Other types may be added in the future.
|
|
*/
|
|
typedef enum ObjectAccessType
|
|
{
|
|
OAT_POST_CREATE,
|
|
OAT_DROP,
|
|
OAT_POST_ALTER,
|
|
OAT_NAMESPACE_SEARCH,
|
|
OAT_FUNCTION_EXECUTE,
|
|
OAT_TRUNCATE,
|
|
} ObjectAccessType;
|
|
|
|
/*
|
|
* Arguments of OAT_POST_CREATE event
|
|
*/
|
|
typedef struct
|
|
{
|
|
/*
|
|
* This flag informs extensions whether the context of this creation is
|
|
* invoked by user's operations, or not. E.g, it shall be dealt as
|
|
* internal stuff on toast tables or indexes due to type changes.
|
|
*/
|
|
bool is_internal;
|
|
} ObjectAccessPostCreate;
|
|
|
|
/*
|
|
* 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;
|
|
|
|
/*
|
|
* Arguments of OAT_POST_ALTER event
|
|
*/
|
|
typedef struct
|
|
{
|
|
/*
|
|
* This identifier is used when system catalog takes two IDs to identify a
|
|
* particular tuple of the catalog. It is only used when the caller want
|
|
* to identify an entry of pg_inherits, pg_db_role_setting or
|
|
* pg_user_mapping. Elsewhere, InvalidOid should be set.
|
|
*/
|
|
Oid auxiliary_id;
|
|
|
|
/*
|
|
* If this flag is set, the user hasn't requested that the object be
|
|
* altered, but we're doing it anyway for some internal reason.
|
|
* Permissions-checking hooks may want to skip checks if, say, we're alter
|
|
* the constraints of a temporary heap during CLUSTER.
|
|
*/
|
|
bool is_internal;
|
|
} ObjectAccessPostAlter;
|
|
|
|
/*
|
|
* Arguments of OAT_NAMESPACE_SEARCH
|
|
*/
|
|
typedef struct
|
|
{
|
|
/*
|
|
* If true, hook should report an error when permission to search this
|
|
* schema is denied.
|
|
*/
|
|
bool ereport_on_violation;
|
|
|
|
/*
|
|
* This is, in essence, an out parameter. Core code should initialize
|
|
* this to true, and any extension that wants to deny access should reset
|
|
* it to false. But an extension should be careful never to store a true
|
|
* value here, so that in case there are multiple extensions access is
|
|
* only allowed if all extensions agree.
|
|
*/
|
|
bool result;
|
|
} ObjectAccessNamespaceSearch;
|
|
|
|
/* Plugin provides a hook function matching one or both of these signatures. */
|
|
typedef void (*object_access_hook_type) (ObjectAccessType access,
|
|
Oid classId,
|
|
Oid objectId,
|
|
int subId,
|
|
void *arg);
|
|
|
|
typedef void (*object_access_hook_type_str) (ObjectAccessType access,
|
|
Oid classId,
|
|
const char *objectStr,
|
|
int subId,
|
|
void *arg);
|
|
|
|
/* Plugin sets this variable to a suitable hook function. */
|
|
extern PGDLLIMPORT object_access_hook_type object_access_hook;
|
|
extern PGDLLIMPORT object_access_hook_type_str object_access_hook_str;
|
|
|
|
|
|
/* Core code uses these functions to call the hook (see macros below). */
|
|
extern void RunObjectPostCreateHook(Oid classId, Oid objectId, int subId,
|
|
bool is_internal);
|
|
extern void RunObjectDropHook(Oid classId, Oid objectId, int subId,
|
|
int dropflags);
|
|
extern void RunObjectTruncateHook(Oid objectId);
|
|
extern void RunObjectPostAlterHook(Oid classId, Oid objectId, int subId,
|
|
Oid auxiliaryId, bool is_internal);
|
|
extern bool RunNamespaceSearchHook(Oid objectId, bool ereport_on_violation);
|
|
extern void RunFunctionExecuteHook(Oid objectId);
|
|
|
|
/* String versions */
|
|
extern void RunObjectPostCreateHookStr(Oid classId, const char *objectName, int subId,
|
|
bool is_internal);
|
|
extern void RunObjectDropHookStr(Oid classId, const char *objectName, int subId,
|
|
int dropflags);
|
|
extern void RunObjectTruncateHookStr(const char *objectName);
|
|
extern void RunObjectPostAlterHookStr(Oid classId, const char *objectName, int subId,
|
|
Oid auxiliaryId, bool is_internal);
|
|
extern bool RunNamespaceSearchHookStr(const char *objectName, bool ereport_on_violation);
|
|
extern void RunFunctionExecuteHookStr(const char *objectName);
|
|
|
|
|
|
/*
|
|
* The following macros are wrappers around the functions above; these should
|
|
* normally be used to invoke the hook in lieu of calling the above functions
|
|
* directly.
|
|
*/
|
|
|
|
#define InvokeObjectPostCreateHook(classId,objectId,subId) \
|
|
InvokeObjectPostCreateHookArg((classId),(objectId),(subId),false)
|
|
#define InvokeObjectPostCreateHookArg(classId,objectId,subId,is_internal) \
|
|
do { \
|
|
if (object_access_hook) \
|
|
RunObjectPostCreateHook((classId),(objectId),(subId), \
|
|
(is_internal)); \
|
|
} while(0)
|
|
|
|
#define InvokeObjectDropHook(classId,objectId,subId) \
|
|
InvokeObjectDropHookArg((classId),(objectId),(subId),0)
|
|
#define InvokeObjectDropHookArg(classId,objectId,subId,dropflags) \
|
|
do { \
|
|
if (object_access_hook) \
|
|
RunObjectDropHook((classId),(objectId),(subId), \
|
|
(dropflags)); \
|
|
} while(0)
|
|
|
|
#define InvokeObjectTruncateHook(objectId) \
|
|
do { \
|
|
if (object_access_hook) \
|
|
RunObjectTruncateHook(objectId); \
|
|
} while(0)
|
|
|
|
#define InvokeObjectPostAlterHook(classId,objectId,subId) \
|
|
InvokeObjectPostAlterHookArg((classId),(objectId),(subId), \
|
|
InvalidOid,false)
|
|
#define InvokeObjectPostAlterHookArg(classId,objectId,subId, \
|
|
auxiliaryId,is_internal) \
|
|
do { \
|
|
if (object_access_hook) \
|
|
RunObjectPostAlterHook((classId),(objectId),(subId), \
|
|
(auxiliaryId),(is_internal)); \
|
|
} while(0)
|
|
|
|
#define InvokeNamespaceSearchHook(objectId, ereport_on_violation) \
|
|
(!object_access_hook \
|
|
? true \
|
|
: RunNamespaceSearchHook((objectId), (ereport_on_violation)))
|
|
|
|
#define InvokeFunctionExecuteHook(objectId) \
|
|
do { \
|
|
if (object_access_hook) \
|
|
RunFunctionExecuteHook(objectId); \
|
|
} while(0)
|
|
|
|
|
|
#define InvokeObjectPostCreateHookStr(classId,objectName,subId) \
|
|
InvokeObjectPostCreateHookArgStr((classId),(objectName),(subId),false)
|
|
#define InvokeObjectPostCreateHookArgStr(classId,objectName,subId,is_internal) \
|
|
do { \
|
|
if (object_access_hook_str) \
|
|
RunObjectPostCreateHookStr((classId),(objectName),(subId), \
|
|
(is_internal)); \
|
|
} while(0)
|
|
|
|
#define InvokeObjectDropHookStr(classId,objectName,subId) \
|
|
InvokeObjectDropHookArgStr((classId),(objectName),(subId),0)
|
|
#define InvokeObjectDropHookArgStr(classId,objectName,subId,dropflags) \
|
|
do { \
|
|
if (object_access_hook_str) \
|
|
RunObjectDropHookStr((classId),(objectName),(subId), \
|
|
(dropflags)); \
|
|
} while(0)
|
|
|
|
#define InvokeObjectTruncateHookStr(objectName) \
|
|
do { \
|
|
if (object_access_hook_str) \
|
|
RunObjectTruncateHookStr(objectName); \
|
|
} while(0)
|
|
|
|
#define InvokeObjectPostAlterHookStr(classId,objectName,subId) \
|
|
InvokeObjectPostAlterHookArgStr((classId),(objectName),(subId), \
|
|
InvalidOid,false)
|
|
#define InvokeObjectPostAlterHookArgStr(classId,objectName,subId, \
|
|
auxiliaryId,is_internal) \
|
|
do { \
|
|
if (object_access_hook_str) \
|
|
RunObjectPostAlterHookStr((classId),(objectName),(subId), \
|
|
(auxiliaryId),(is_internal)); \
|
|
} while(0)
|
|
|
|
#define InvokeNamespaceSearchHookStr(objectName, ereport_on_violation) \
|
|
(!object_access_hook_str \
|
|
? true \
|
|
: RunNamespaceSearchHookStr((objectName), (ereport_on_violation)))
|
|
|
|
#define InvokeFunctionExecuteHookStr(objectName) \
|
|
do { \
|
|
if (object_access_hook_str) \
|
|
RunFunctionExecuteHookStr(objectName); \
|
|
} while(0)
|
|
|
|
|
|
#endif /* OBJECTACCESS_H */
|