summaryrefslogtreecommitdiffstats
path: root/src/include/catalog/objectaccess.h
blob: 896c3a0fdc5b0550cc9d9bca80d3b34d2261f85b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
/*
 * objectaccess.h
 *
 *		Object access hooks.
 *
 * Portions Copyright (c) 1996-2021, 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.
 *
 * 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 this signature. */
typedef void (*object_access_hook_type) (ObjectAccessType access,
										 Oid classId,
										 Oid objectId,
										 int subId,
										 void *arg);

/* Plugin sets this variable to a suitable hook function. */
extern PGDLLIMPORT object_access_hook_type object_access_hook;

/* 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);

/*
 * 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)

#endif							/* OBJECTACCESS_H */