1 | /* |
2 | * objectaccess.h |
3 | * |
4 | * Object access hooks. |
5 | * |
6 | * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group |
7 | * Portions Copyright (c) 1994, Regents of the University of California |
8 | */ |
9 | |
10 | #ifndef OBJECTACCESS_H |
11 | #define OBJECTACCESS_H |
12 | |
13 | /* |
14 | * Object access hooks are intended to be called just before or just after |
15 | * performing certain actions on a SQL object. This is intended as |
16 | * infrastructure for security or logging plugins. |
17 | * |
18 | * OAT_POST_CREATE should be invoked just after the object is created. |
19 | * Typically, this is done after inserting the primary catalog records and |
20 | * associated dependencies. |
21 | * |
22 | * OAT_DROP should be invoked just before deletion of objects; typically |
23 | * deleteOneObject(). Its arguments are packed within ObjectAccessDrop. |
24 | * |
25 | * OAT_POST_ALTER should be invoked just after the object is altered, |
26 | * but before the command counter is incremented. An extension using the |
27 | * hook can use a current MVCC snapshot to get the old version of the tuple, |
28 | * and can use SnapshotSelf to get the new version of the tuple. |
29 | * |
30 | * OAT_NAMESPACE_SEARCH should be invoked prior to object name lookup under |
31 | * a particular namespace. This event is equivalent to usage permission |
32 | * on a schema under the default access control mechanism. |
33 | * |
34 | * OAT_FUNCTION_EXECUTE should be invoked prior to function execution. |
35 | * This event is almost equivalent to execute permission on functions, |
36 | * except for the case when execute permission is checked during object |
37 | * creation or altering, because OAT_POST_CREATE or OAT_POST_ALTER are |
38 | * sufficient for extensions to track these kind of checks. |
39 | * |
40 | * Other types may be added in the future. |
41 | */ |
42 | typedef enum ObjectAccessType |
43 | { |
44 | OAT_POST_CREATE, |
45 | OAT_DROP, |
46 | OAT_POST_ALTER, |
47 | OAT_NAMESPACE_SEARCH, |
48 | OAT_FUNCTION_EXECUTE |
49 | } ObjectAccessType; |
50 | |
51 | /* |
52 | * Arguments of OAT_POST_CREATE event |
53 | */ |
54 | typedef struct |
55 | { |
56 | /* |
57 | * This flag informs extensions whether the context of this creation is |
58 | * invoked by user's operations, or not. E.g, it shall be dealt as |
59 | * internal stuff on toast tables or indexes due to type changes. |
60 | */ |
61 | bool is_internal; |
62 | } ObjectAccessPostCreate; |
63 | |
64 | /* |
65 | * Arguments of OAT_DROP event |
66 | */ |
67 | typedef struct |
68 | { |
69 | /* |
70 | * Flags to inform extensions the context of this deletion. Also see |
71 | * PERFORM_DELETION_* in dependency.h |
72 | */ |
73 | int dropflags; |
74 | } ObjectAccessDrop; |
75 | |
76 | /* |
77 | * Arguments of OAT_POST_ALTER event |
78 | */ |
79 | typedef struct |
80 | { |
81 | /* |
82 | * This identifier is used when system catalog takes two IDs to identify a |
83 | * particular tuple of the catalog. It is only used when the caller want |
84 | * to identify an entry of pg_inherits, pg_db_role_setting or |
85 | * pg_user_mapping. Elsewhere, InvalidOid should be set. |
86 | */ |
87 | Oid auxiliary_id; |
88 | |
89 | /* |
90 | * If this flag is set, the user hasn't requested that the object be |
91 | * altered, but we're doing it anyway for some internal reason. |
92 | * Permissions-checking hooks may want to skip checks if, say, we're alter |
93 | * the constraints of a temporary heap during CLUSTER. |
94 | */ |
95 | bool is_internal; |
96 | } ObjectAccessPostAlter; |
97 | |
98 | /* |
99 | * Arguments of OAT_NAMESPACE_SEARCH |
100 | */ |
101 | typedef struct |
102 | { |
103 | /* |
104 | * If true, hook should report an error when permission to search this |
105 | * schema is denied. |
106 | */ |
107 | bool ereport_on_violation; |
108 | |
109 | /* |
110 | * This is, in essence, an out parameter. Core code should initialize |
111 | * this to true, and any extension that wants to deny access should reset |
112 | * it to false. But an extension should be careful never to store a true |
113 | * value here, so that in case there are multiple extensions access is |
114 | * only allowed if all extensions agree. |
115 | */ |
116 | bool result; |
117 | } ObjectAccessNamespaceSearch; |
118 | |
119 | /* Plugin provides a hook function matching this signature. */ |
120 | typedef void (*object_access_hook_type) (ObjectAccessType access, |
121 | Oid classId, |
122 | Oid objectId, |
123 | int subId, |
124 | void *arg); |
125 | |
126 | /* Plugin sets this variable to a suitable hook function. */ |
127 | extern PGDLLIMPORT object_access_hook_type object_access_hook; |
128 | |
129 | /* Core code uses these functions to call the hook (see macros below). */ |
130 | extern void RunObjectPostCreateHook(Oid classId, Oid objectId, int subId, |
131 | bool is_internal); |
132 | extern void RunObjectDropHook(Oid classId, Oid objectId, int subId, |
133 | int dropflags); |
134 | extern void RunObjectPostAlterHook(Oid classId, Oid objectId, int subId, |
135 | Oid auxiliaryId, bool is_internal); |
136 | extern bool RunNamespaceSearchHook(Oid objectId, bool ereport_on_violation); |
137 | extern void RunFunctionExecuteHook(Oid objectId); |
138 | |
139 | /* |
140 | * The following macros are wrappers around the functions above; these should |
141 | * normally be used to invoke the hook in lieu of calling the above functions |
142 | * directly. |
143 | */ |
144 | |
145 | #define InvokeObjectPostCreateHook(classId,objectId,subId) \ |
146 | InvokeObjectPostCreateHookArg((classId),(objectId),(subId),false) |
147 | #define InvokeObjectPostCreateHookArg(classId,objectId,subId,is_internal) \ |
148 | do { \ |
149 | if (object_access_hook) \ |
150 | RunObjectPostCreateHook((classId),(objectId),(subId), \ |
151 | (is_internal)); \ |
152 | } while(0) |
153 | |
154 | #define InvokeObjectDropHook(classId,objectId,subId) \ |
155 | InvokeObjectDropHookArg((classId),(objectId),(subId),0) |
156 | #define InvokeObjectDropHookArg(classId,objectId,subId,dropflags) \ |
157 | do { \ |
158 | if (object_access_hook) \ |
159 | RunObjectDropHook((classId),(objectId),(subId), \ |
160 | (dropflags)); \ |
161 | } while(0) |
162 | |
163 | #define InvokeObjectPostAlterHook(classId,objectId,subId) \ |
164 | InvokeObjectPostAlterHookArg((classId),(objectId),(subId), \ |
165 | InvalidOid,false) |
166 | #define InvokeObjectPostAlterHookArg(classId,objectId,subId, \ |
167 | auxiliaryId,is_internal) \ |
168 | do { \ |
169 | if (object_access_hook) \ |
170 | RunObjectPostAlterHook((classId),(objectId),(subId), \ |
171 | (auxiliaryId),(is_internal)); \ |
172 | } while(0) |
173 | |
174 | #define InvokeNamespaceSearchHook(objectId, ereport_on_violation) \ |
175 | (!object_access_hook \ |
176 | ? true \ |
177 | : RunNamespaceSearchHook((objectId), (ereport_on_violation))) |
178 | |
179 | #define InvokeFunctionExecuteHook(objectId) \ |
180 | do { \ |
181 | if (object_access_hook) \ |
182 | RunFunctionExecuteHook(objectId); \ |
183 | } while(0) |
184 | |
185 | #endif /* OBJECTACCESS_H */ |
186 | |