]> granicus.if.org Git - postgresql/blob - contrib/sepgsql/proc.c
9cc21f05b5bc10c8b2f871abd258c1d2453c9c7a
[postgresql] / contrib / sepgsql / proc.c
1 /* -------------------------------------------------------------------------
2  *
3  * contrib/sepgsql/proc.c
4  *
5  * Routines corresponding to procedure objects
6  *
7  * Copyright (c) 2010-2016, PostgreSQL Global Development Group
8  *
9  * -------------------------------------------------------------------------
10  */
11 #include "postgres.h"
12
13 #include "access/genam.h"
14 #include "access/heapam.h"
15 #include "access/htup_details.h"
16 #include "access/sysattr.h"
17 #include "catalog/dependency.h"
18 #include "catalog/indexing.h"
19 #include "catalog/pg_namespace.h"
20 #include "catalog/pg_proc.h"
21 #include "catalog/pg_type.h"
22 #include "commands/seclabel.h"
23 #include "lib/stringinfo.h"
24 #include "utils/builtins.h"
25 #include "utils/fmgroids.h"
26 #include "utils/lsyscache.h"
27 #include "utils/syscache.h"
28 #include "utils/tqual.h"
29
30 #include "sepgsql.h"
31
32 /*
33  * sepgsql_proc_post_create
34  *
35  * This routine assigns a default security label on a newly defined
36  * procedure.
37  */
38 void
39 sepgsql_proc_post_create(Oid functionId)
40 {
41         Relation        rel;
42         ScanKeyData skey;
43         SysScanDesc sscan;
44         HeapTuple       tuple;
45         char       *nsp_name;
46         char       *scontext;
47         char       *tcontext;
48         char       *ncontext;
49         uint32          required;
50         int                     i;
51         StringInfoData audit_name;
52         ObjectAddress object;
53         Form_pg_proc proForm;
54
55         /*
56          * Fetch namespace of the new procedure. Because pg_proc entry is not
57          * visible right now, we need to scan the catalog using SnapshotSelf.
58          */
59         rel = heap_open(ProcedureRelationId, AccessShareLock);
60
61         ScanKeyInit(&skey,
62                                 ObjectIdAttributeNumber,
63                                 BTEqualStrategyNumber, F_OIDEQ,
64                                 ObjectIdGetDatum(functionId));
65
66         sscan = systable_beginscan(rel, ProcedureOidIndexId, true,
67                                                            SnapshotSelf, 1, &skey);
68
69         tuple = systable_getnext(sscan);
70         if (!HeapTupleIsValid(tuple))
71                 elog(ERROR, "catalog lookup failed for proc %u", functionId);
72
73         proForm = (Form_pg_proc) GETSTRUCT(tuple);
74
75         /*
76          * check db_schema:{add_name} permission of the namespace
77          */
78         object.classId = NamespaceRelationId;
79         object.objectId = proForm->pronamespace;
80         object.objectSubId = 0;
81         sepgsql_avc_check_perms(&object,
82                                                         SEPG_CLASS_DB_SCHEMA,
83                                                         SEPG_DB_SCHEMA__ADD_NAME,
84                                                         getObjectIdentity(&object),
85                                                         true);
86
87         /*
88          * XXX - db_language:{implement} also should be checked here
89          */
90
91
92         /*
93          * Compute a default security label when we create a new procedure object
94          * under the specified namespace.
95          */
96         scontext = sepgsql_get_client_label();
97         tcontext = sepgsql_get_label(NamespaceRelationId,
98                                                                  proForm->pronamespace, 0);
99         ncontext = sepgsql_compute_create(scontext, tcontext,
100                                                                           SEPG_CLASS_DB_PROCEDURE,
101                                                                           NameStr(proForm->proname));
102
103         /*
104          * check db_procedure:{create (install)} permission
105          */
106         initStringInfo(&audit_name);
107         nsp_name = get_namespace_name(proForm->pronamespace);
108         appendStringInfo(&audit_name, "%s(",
109                         quote_qualified_identifier(nsp_name, NameStr(proForm->proname)));
110         for (i = 0; i < proForm->pronargs; i++)
111         {
112                 if (i > 0)
113                         appendStringInfoChar(&audit_name, ',');
114
115                 object.classId = TypeRelationId;
116                 object.objectId = proForm->proargtypes.values[i];
117                 object.objectSubId = 0;
118                 appendStringInfoString(&audit_name, getObjectIdentity(&object));
119         }
120         appendStringInfoChar(&audit_name, ')');
121
122         required = SEPG_DB_PROCEDURE__CREATE;
123         if (proForm->proleakproof)
124                 required |= SEPG_DB_PROCEDURE__INSTALL;
125
126         sepgsql_avc_check_perms_label(ncontext,
127                                                                   SEPG_CLASS_DB_PROCEDURE,
128                                                                   required,
129                                                                   audit_name.data,
130                                                                   true);
131
132         /*
133          * Assign the default security label on a new procedure
134          */
135         object.classId = ProcedureRelationId;
136         object.objectId = functionId;
137         object.objectSubId = 0;
138         SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, ncontext);
139
140         /*
141          * Cleanup
142          */
143         systable_endscan(sscan);
144         heap_close(rel, AccessShareLock);
145
146         pfree(audit_name.data);
147         pfree(tcontext);
148         pfree(ncontext);
149 }
150
151 /*
152  * sepgsql_proc_drop
153  *
154  * It checks privileges to drop the supplied function.
155  */
156 void
157 sepgsql_proc_drop(Oid functionId)
158 {
159         ObjectAddress object;
160         char       *audit_name;
161
162         /*
163          * check db_schema:{remove_name} permission
164          */
165         object.classId = NamespaceRelationId;
166         object.objectId = get_func_namespace(functionId);
167         object.objectSubId = 0;
168         audit_name = getObjectIdentity(&object);
169
170         sepgsql_avc_check_perms(&object,
171                                                         SEPG_CLASS_DB_SCHEMA,
172                                                         SEPG_DB_SCHEMA__REMOVE_NAME,
173                                                         audit_name,
174                                                         true);
175         pfree(audit_name);
176
177         /*
178          * check db_procedure:{drop} permission
179          */
180         object.classId = ProcedureRelationId;
181         object.objectId = functionId;
182         object.objectSubId = 0;
183         audit_name = getObjectIdentity(&object);
184
185         sepgsql_avc_check_perms(&object,
186                                                         SEPG_CLASS_DB_PROCEDURE,
187                                                         SEPG_DB_PROCEDURE__DROP,
188                                                         audit_name,
189                                                         true);
190         pfree(audit_name);
191 }
192
193 /*
194  * sepgsql_proc_relabel
195  *
196  * It checks privileges to relabel the supplied function
197  * by the `seclabel'.
198  */
199 void
200 sepgsql_proc_relabel(Oid functionId, const char *seclabel)
201 {
202         ObjectAddress object;
203         char       *audit_name;
204
205         object.classId = ProcedureRelationId;
206         object.objectId = functionId;
207         object.objectSubId = 0;
208         audit_name = getObjectIdentity(&object);
209
210         /*
211          * check db_procedure:{setattr relabelfrom} permission
212          */
213         sepgsql_avc_check_perms(&object,
214                                                         SEPG_CLASS_DB_PROCEDURE,
215                                                         SEPG_DB_PROCEDURE__SETATTR |
216                                                         SEPG_DB_PROCEDURE__RELABELFROM,
217                                                         audit_name,
218                                                         true);
219
220         /*
221          * check db_procedure:{relabelto} permission
222          */
223         sepgsql_avc_check_perms_label(seclabel,
224                                                                   SEPG_CLASS_DB_PROCEDURE,
225                                                                   SEPG_DB_PROCEDURE__RELABELTO,
226                                                                   audit_name,
227                                                                   true);
228         pfree(audit_name);
229 }
230
231 /*
232  * sepgsql_proc_setattr
233  *
234  * It checks privileges to alter the supplied function.
235  */
236 void
237 sepgsql_proc_setattr(Oid functionId)
238 {
239         Relation        rel;
240         ScanKeyData skey;
241         SysScanDesc sscan;
242         HeapTuple       oldtup;
243         HeapTuple       newtup;
244         Form_pg_proc oldform;
245         Form_pg_proc newform;
246         uint32          required;
247         ObjectAddress object;
248         char       *audit_name;
249
250         /*
251          * Fetch newer catalog
252          */
253         rel = heap_open(ProcedureRelationId, AccessShareLock);
254
255         ScanKeyInit(&skey,
256                                 ObjectIdAttributeNumber,
257                                 BTEqualStrategyNumber, F_OIDEQ,
258                                 ObjectIdGetDatum(functionId));
259
260         sscan = systable_beginscan(rel, ProcedureOidIndexId, true,
261                                                            SnapshotSelf, 1, &skey);
262         newtup = systable_getnext(sscan);
263         if (!HeapTupleIsValid(newtup))
264                 elog(ERROR, "catalog lookup failed for function %u", functionId);
265         newform = (Form_pg_proc) GETSTRUCT(newtup);
266
267         /*
268          * Fetch older catalog
269          */
270         oldtup = SearchSysCache1(PROCOID, ObjectIdGetDatum(functionId));
271         if (!HeapTupleIsValid(oldtup))
272                 elog(ERROR, "cache lookup failed for function %u", functionId);
273         oldform = (Form_pg_proc) GETSTRUCT(oldtup);
274
275         /*
276          * Does this ALTER command takes operation to namespace?
277          */
278         if (newform->pronamespace != oldform->pronamespace)
279         {
280                 sepgsql_schema_remove_name(oldform->pronamespace);
281                 sepgsql_schema_add_name(oldform->pronamespace);
282         }
283         if (strcmp(NameStr(newform->proname), NameStr(oldform->proname)) != 0)
284                 sepgsql_schema_rename(oldform->pronamespace);
285
286         /*
287          * check db_procedure:{setattr (install)} permission
288          */
289         required = SEPG_DB_PROCEDURE__SETATTR;
290         if (!oldform->proleakproof && newform->proleakproof)
291                 required |= SEPG_DB_PROCEDURE__INSTALL;
292
293         object.classId = ProcedureRelationId;
294         object.objectId = functionId;
295         object.objectSubId = 0;
296         audit_name = getObjectIdentity(&object);
297
298         sepgsql_avc_check_perms(&object,
299                                                         SEPG_CLASS_DB_PROCEDURE,
300                                                         required,
301                                                         audit_name,
302                                                         true);
303         /* cleanups */
304         pfree(audit_name);
305
306         ReleaseSysCache(oldtup);
307         systable_endscan(sscan);
308         heap_close(rel, AccessShareLock);
309 }
310
311 /*
312  * sepgsql_proc_execute
313  *
314  * It checks privileges to execute the supplied function
315  */
316 void
317 sepgsql_proc_execute(Oid functionId)
318 {
319         ObjectAddress object;
320         char       *audit_name;
321
322         /*
323          * check db_procedure:{execute} permission
324          */
325         object.classId = ProcedureRelationId;
326         object.objectId = functionId;
327         object.objectSubId = 0;
328         audit_name = getObjectIdentity(&object);
329         sepgsql_avc_check_perms(&object,
330                                                         SEPG_CLASS_DB_PROCEDURE,
331                                                         SEPG_DB_PROCEDURE__EXECUTE,
332                                                         audit_name,
333                                                         true);
334         pfree(audit_name);
335 }