1 /* -------------------------------------------------------------------------
3 * contrib/sepgsql/proc.c
5 * Routines corresponding to procedure objects
7 * Copyright (c) 2010-2017, PostgreSQL Global Development Group
9 * -------------------------------------------------------------------------
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"
33 * sepgsql_proc_post_create
35 * This routine assigns a default security label on a newly defined
39 sepgsql_proc_post_create(Oid functionId)
51 StringInfoData audit_name;
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.
59 rel = heap_open(ProcedureRelationId, AccessShareLock);
62 ObjectIdAttributeNumber,
63 BTEqualStrategyNumber, F_OIDEQ,
64 ObjectIdGetDatum(functionId));
66 sscan = systable_beginscan(rel, ProcedureOidIndexId, true,
67 SnapshotSelf, 1, &skey);
69 tuple = systable_getnext(sscan);
70 if (!HeapTupleIsValid(tuple))
71 elog(ERROR, "catalog lookup failed for proc %u", functionId);
73 proForm = (Form_pg_proc) GETSTRUCT(tuple);
76 * check db_schema:{add_name} permission of the namespace
78 object.classId = NamespaceRelationId;
79 object.objectId = proForm->pronamespace;
80 object.objectSubId = 0;
81 sepgsql_avc_check_perms(&object,
83 SEPG_DB_SCHEMA__ADD_NAME,
84 getObjectIdentity(&object),
88 * XXX - db_language:{implement} also should be checked here
93 * Compute a default security label when we create a new procedure object
94 * under the specified namespace.
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));
104 * check db_procedure:{create (install)} permission
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++)
113 appendStringInfoChar(&audit_name, ',');
115 object.classId = TypeRelationId;
116 object.objectId = proForm->proargtypes.values[i];
117 object.objectSubId = 0;
118 appendStringInfoString(&audit_name, getObjectIdentity(&object));
120 appendStringInfoChar(&audit_name, ')');
122 required = SEPG_DB_PROCEDURE__CREATE;
123 if (proForm->proleakproof)
124 required |= SEPG_DB_PROCEDURE__INSTALL;
126 sepgsql_avc_check_perms_label(ncontext,
127 SEPG_CLASS_DB_PROCEDURE,
133 * Assign the default security label on a new procedure
135 object.classId = ProcedureRelationId;
136 object.objectId = functionId;
137 object.objectSubId = 0;
138 SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, ncontext);
143 systable_endscan(sscan);
144 heap_close(rel, AccessShareLock);
146 pfree(audit_name.data);
154 * It checks privileges to drop the supplied function.
157 sepgsql_proc_drop(Oid functionId)
159 ObjectAddress object;
163 * check db_schema:{remove_name} permission
165 object.classId = NamespaceRelationId;
166 object.objectId = get_func_namespace(functionId);
167 object.objectSubId = 0;
168 audit_name = getObjectIdentity(&object);
170 sepgsql_avc_check_perms(&object,
171 SEPG_CLASS_DB_SCHEMA,
172 SEPG_DB_SCHEMA__REMOVE_NAME,
178 * check db_procedure:{drop} permission
180 object.classId = ProcedureRelationId;
181 object.objectId = functionId;
182 object.objectSubId = 0;
183 audit_name = getObjectIdentity(&object);
185 sepgsql_avc_check_perms(&object,
186 SEPG_CLASS_DB_PROCEDURE,
187 SEPG_DB_PROCEDURE__DROP,
194 * sepgsql_proc_relabel
196 * It checks privileges to relabel the supplied function
200 sepgsql_proc_relabel(Oid functionId, const char *seclabel)
202 ObjectAddress object;
205 object.classId = ProcedureRelationId;
206 object.objectId = functionId;
207 object.objectSubId = 0;
208 audit_name = getObjectIdentity(&object);
211 * check db_procedure:{setattr relabelfrom} permission
213 sepgsql_avc_check_perms(&object,
214 SEPG_CLASS_DB_PROCEDURE,
215 SEPG_DB_PROCEDURE__SETATTR |
216 SEPG_DB_PROCEDURE__RELABELFROM,
221 * check db_procedure:{relabelto} permission
223 sepgsql_avc_check_perms_label(seclabel,
224 SEPG_CLASS_DB_PROCEDURE,
225 SEPG_DB_PROCEDURE__RELABELTO,
232 * sepgsql_proc_setattr
234 * It checks privileges to alter the supplied function.
237 sepgsql_proc_setattr(Oid functionId)
244 Form_pg_proc oldform;
245 Form_pg_proc newform;
247 ObjectAddress object;
251 * Fetch newer catalog
253 rel = heap_open(ProcedureRelationId, AccessShareLock);
256 ObjectIdAttributeNumber,
257 BTEqualStrategyNumber, F_OIDEQ,
258 ObjectIdGetDatum(functionId));
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);
268 * Fetch older catalog
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);
276 * Does this ALTER command takes operation to namespace?
278 if (newform->pronamespace != oldform->pronamespace)
280 sepgsql_schema_remove_name(oldform->pronamespace);
281 sepgsql_schema_add_name(oldform->pronamespace);
283 if (strcmp(NameStr(newform->proname), NameStr(oldform->proname)) != 0)
284 sepgsql_schema_rename(oldform->pronamespace);
287 * check db_procedure:{setattr (install)} permission
289 required = SEPG_DB_PROCEDURE__SETATTR;
290 if (!oldform->proleakproof && newform->proleakproof)
291 required |= SEPG_DB_PROCEDURE__INSTALL;
293 object.classId = ProcedureRelationId;
294 object.objectId = functionId;
295 object.objectSubId = 0;
296 audit_name = getObjectIdentity(&object);
298 sepgsql_avc_check_perms(&object,
299 SEPG_CLASS_DB_PROCEDURE,
306 ReleaseSysCache(oldtup);
307 systable_endscan(sscan);
308 heap_close(rel, AccessShareLock);
312 * sepgsql_proc_execute
314 * It checks privileges to execute the supplied function
317 sepgsql_proc_execute(Oid functionId)
319 ObjectAddress object;
323 * check db_procedure:{execute} permission
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,