1 /* -------------------------------------------------------------------------
3 * contrib/sepgsql/proc.c
5 * Routines corresponding to procedure objects
7 * Copyright (c) 2010-2025, PostgreSQL Global Development Group
9 * -------------------------------------------------------------------------
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"
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"
31 * sepgsql_proc_post_create
33 * This routine assigns a default security label on a newly defined
37 sepgsql_proc_post_create(Oid functionId
)
49 StringInfoData audit_name
;
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.
57 rel
= table_open(ProcedureRelationId
, AccessShareLock
);
61 BTEqualStrategyNumber
, F_OIDEQ
,
62 ObjectIdGetDatum(functionId
));
64 sscan
= systable_beginscan(rel
, ProcedureOidIndexId
, true,
65 SnapshotSelf
, 1, &skey
);
67 tuple
= systable_getnext(sscan
);
68 if (!HeapTupleIsValid(tuple
))
69 elog(ERROR
, "could not find tuple for function %u", functionId
);
71 proForm
= (Form_pg_proc
) GETSTRUCT(tuple
);
74 * check db_schema:{add_name} permission of the namespace
76 object
.classId
= NamespaceRelationId
;
77 object
.objectId
= proForm
->pronamespace
;
78 object
.objectSubId
= 0;
79 sepgsql_avc_check_perms(&object
,
81 SEPG_DB_SCHEMA__ADD_NAME
,
82 getObjectIdentity(&object
, false),
86 * XXX - db_language:{implement} also should be checked here
91 * Compute a default security label when we create a new procedure object
92 * under the specified namespace.
94 scontext
= sepgsql_get_client_label();
95 tcontext
= sepgsql_get_label(NamespaceRelationId
,
96 proForm
->pronamespace
, 0);
97 ncontext
= sepgsql_compute_create(scontext
, tcontext
,
98 SEPG_CLASS_DB_PROCEDURE
,
99 NameStr(proForm
->proname
));
102 * check db_procedure:{create (install)} permission
104 initStringInfo(&audit_name
);
105 nsp_name
= get_namespace_name(proForm
->pronamespace
);
106 appendStringInfo(&audit_name
, "%s(",
107 quote_qualified_identifier(nsp_name
, NameStr(proForm
->proname
)));
108 for (i
= 0; i
< proForm
->pronargs
; i
++)
111 appendStringInfoChar(&audit_name
, ',');
113 object
.classId
= TypeRelationId
;
114 object
.objectId
= proForm
->proargtypes
.values
[i
];
115 object
.objectSubId
= 0;
116 appendStringInfoString(&audit_name
, getObjectIdentity(&object
, false));
118 appendStringInfoChar(&audit_name
, ')');
120 required
= SEPG_DB_PROCEDURE__CREATE
;
121 if (proForm
->proleakproof
)
122 required
|= SEPG_DB_PROCEDURE__INSTALL
;
124 sepgsql_avc_check_perms_label(ncontext
,
125 SEPG_CLASS_DB_PROCEDURE
,
131 * Assign the default security label on a new procedure
133 object
.classId
= ProcedureRelationId
;
134 object
.objectId
= functionId
;
135 object
.objectSubId
= 0;
136 SetSecurityLabel(&object
, SEPGSQL_LABEL_TAG
, ncontext
);
141 systable_endscan(sscan
);
142 table_close(rel
, AccessShareLock
);
144 pfree(audit_name
.data
);
152 * It checks privileges to drop the supplied function.
155 sepgsql_proc_drop(Oid functionId
)
157 ObjectAddress object
;
161 * check db_schema:{remove_name} permission
163 object
.classId
= NamespaceRelationId
;
164 object
.objectId
= get_func_namespace(functionId
);
165 object
.objectSubId
= 0;
166 audit_name
= getObjectIdentity(&object
, false);
168 sepgsql_avc_check_perms(&object
,
169 SEPG_CLASS_DB_SCHEMA
,
170 SEPG_DB_SCHEMA__REMOVE_NAME
,
176 * check db_procedure:{drop} permission
178 object
.classId
= ProcedureRelationId
;
179 object
.objectId
= functionId
;
180 object
.objectSubId
= 0;
181 audit_name
= getObjectIdentity(&object
, false);
183 sepgsql_avc_check_perms(&object
,
184 SEPG_CLASS_DB_PROCEDURE
,
185 SEPG_DB_PROCEDURE__DROP
,
192 * sepgsql_proc_relabel
194 * It checks privileges to relabel the supplied function
198 sepgsql_proc_relabel(Oid functionId
, const char *seclabel
)
200 ObjectAddress object
;
203 object
.classId
= ProcedureRelationId
;
204 object
.objectId
= functionId
;
205 object
.objectSubId
= 0;
206 audit_name
= getObjectIdentity(&object
, false);
209 * check db_procedure:{setattr relabelfrom} permission
211 sepgsql_avc_check_perms(&object
,
212 SEPG_CLASS_DB_PROCEDURE
,
213 SEPG_DB_PROCEDURE__SETATTR
|
214 SEPG_DB_PROCEDURE__RELABELFROM
,
219 * check db_procedure:{relabelto} permission
221 sepgsql_avc_check_perms_label(seclabel
,
222 SEPG_CLASS_DB_PROCEDURE
,
223 SEPG_DB_PROCEDURE__RELABELTO
,
230 * sepgsql_proc_setattr
232 * It checks privileges to alter the supplied function.
235 sepgsql_proc_setattr(Oid functionId
)
242 Form_pg_proc oldform
;
243 Form_pg_proc newform
;
245 ObjectAddress object
;
249 * Fetch newer catalog
251 rel
= table_open(ProcedureRelationId
, AccessShareLock
);
255 BTEqualStrategyNumber
, F_OIDEQ
,
256 ObjectIdGetDatum(functionId
));
258 sscan
= systable_beginscan(rel
, ProcedureOidIndexId
, true,
259 SnapshotSelf
, 1, &skey
);
260 newtup
= systable_getnext(sscan
);
261 if (!HeapTupleIsValid(newtup
))
262 elog(ERROR
, "could not find tuple for function %u", functionId
);
263 newform
= (Form_pg_proc
) GETSTRUCT(newtup
);
266 * Fetch older catalog
268 oldtup
= SearchSysCache1(PROCOID
, ObjectIdGetDatum(functionId
));
269 if (!HeapTupleIsValid(oldtup
))
270 elog(ERROR
, "cache lookup failed for function %u", functionId
);
271 oldform
= (Form_pg_proc
) GETSTRUCT(oldtup
);
274 * Does this ALTER command takes operation to namespace?
276 if (newform
->pronamespace
!= oldform
->pronamespace
)
278 sepgsql_schema_remove_name(oldform
->pronamespace
);
279 sepgsql_schema_add_name(oldform
->pronamespace
);
281 if (strcmp(NameStr(newform
->proname
), NameStr(oldform
->proname
)) != 0)
282 sepgsql_schema_rename(oldform
->pronamespace
);
285 * check db_procedure:{setattr (install)} permission
287 required
= SEPG_DB_PROCEDURE__SETATTR
;
288 if (!oldform
->proleakproof
&& newform
->proleakproof
)
289 required
|= SEPG_DB_PROCEDURE__INSTALL
;
291 object
.classId
= ProcedureRelationId
;
292 object
.objectId
= functionId
;
293 object
.objectSubId
= 0;
294 audit_name
= getObjectIdentity(&object
, false);
296 sepgsql_avc_check_perms(&object
,
297 SEPG_CLASS_DB_PROCEDURE
,
304 ReleaseSysCache(oldtup
);
305 systable_endscan(sscan
);
306 table_close(rel
, AccessShareLock
);
310 * sepgsql_proc_execute
312 * It checks privileges to execute the supplied function
315 sepgsql_proc_execute(Oid functionId
)
317 ObjectAddress object
;
321 * check db_procedure:{execute} permission
323 object
.classId
= ProcedureRelationId
;
324 object
.objectId
= functionId
;
325 object
.objectSubId
= 0;
326 audit_name
= getObjectIdentity(&object
, false);
327 sepgsql_avc_check_perms(&object
,
328 SEPG_CLASS_DB_PROCEDURE
,
329 SEPG_DB_PROCEDURE__EXECUTE
,