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