Age Owner Branch data TLA Line data Source code
1 : : /* -------------------------------------------------------------------------
2 : : *
3 : : * contrib/sepgsql/relation.c
4 : : *
5 : : * Routines corresponding to relation/attribute 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_attribute.h"
19 : : #include "catalog/pg_class.h"
20 : : #include "catalog/pg_namespace.h"
21 : : #include "commands/seclabel.h"
22 : : #include "lib/stringinfo.h"
23 : : #include "sepgsql.h"
24 : : #include "utils/builtins.h"
25 : : #include "utils/catcache.h"
26 : : #include "utils/fmgroids.h"
27 : : #include "utils/lsyscache.h"
28 : : #include "utils/rel.h"
29 : : #include "utils/snapmgr.h"
30 : : #include "utils/syscache.h"
31 : :
32 : : static void sepgsql_index_modify(Oid indexOid);
33 : :
34 : : /*
35 : : * sepgsql_attribute_post_create
36 : : *
37 : : * This routine assigns a default security label on a newly defined
38 : : * column, using ALTER TABLE ... ADD COLUMN.
39 : : * Note that this routine is not invoked in the case of CREATE TABLE,
40 : : * although it also defines columns in addition to table.
41 : : */
42 : : void
4830 rhaas@postgresql.org 43 :UBC 0 : sepgsql_attribute_post_create(Oid relOid, AttrNumber attnum)
44 : : {
45 : : Relation rel;
46 : : ScanKeyData skey[2];
47 : : SysScanDesc sscan;
48 : : HeapTuple tuple;
49 : : char *scontext;
50 : : char *tcontext;
51 : : char *ncontext;
52 : : ObjectAddress object;
53 : : Form_pg_attribute attForm;
54 : : StringInfoData audit_name;
2562 mail@joeconway.com 55 : 0 : char relkind = get_rel_relkind(relOid);
56 : :
57 : : /*
58 : : * Only attributes within regular relations or partition relations have
59 : : * individual security labels.
60 : : */
61 [ # # # # ]: 0 : if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE)
4830 rhaas@postgresql.org 62 : 0 : return;
63 : :
64 : : /*
65 : : * Compute a default security label of the new column underlying the
66 : : * specified relation, and check permission to create it.
67 : : */
1910 andres@anarazel.de 68 : 0 : rel = table_open(AttributeRelationId, AccessShareLock);
69 : :
4498 rhaas@postgresql.org 70 : 0 : ScanKeyInit(&skey[0],
71 : : Anum_pg_attribute_attrelid,
72 : : BTEqualStrategyNumber, F_OIDEQ,
73 : : ObjectIdGetDatum(relOid));
74 : 0 : ScanKeyInit(&skey[1],
75 : : Anum_pg_attribute_attnum,
76 : : BTEqualStrategyNumber, F_INT2EQ,
77 : : Int16GetDatum(attnum));
78 : :
79 : 0 : sscan = systable_beginscan(rel, AttributeRelidNumIndexId, true,
80 : : SnapshotSelf, 2, &skey[0]);
81 : :
82 : 0 : tuple = systable_getnext(sscan);
83 [ # # ]: 0 : if (!HeapTupleIsValid(tuple))
2506 tgl@sss.pgh.pa.us 84 [ # # ]: 0 : elog(ERROR, "could not find tuple for column %d of relation %u",
85 : : attnum, relOid);
86 : :
4498 rhaas@postgresql.org 87 : 0 : attForm = (Form_pg_attribute) GETSTRUCT(tuple);
88 : :
4830 89 : 0 : scontext = sepgsql_get_client_label();
90 : 0 : tcontext = sepgsql_get_label(RelationRelationId, relOid, 0);
91 : 0 : ncontext = sepgsql_compute_create(scontext, tcontext,
92 : : SEPG_CLASS_DB_COLUMN,
4035 93 : 0 : NameStr(attForm->attname));
94 : :
95 : : /*
96 : : * check db_column:{create} permission
97 : : */
4020 98 : 0 : object.classId = RelationRelationId;
99 : 0 : object.objectId = relOid;
100 : 0 : object.objectSubId = 0;
101 : :
102 : 0 : initStringInfo(&audit_name);
103 : 0 : appendStringInfo(&audit_name, "%s.%s",
104 : : getObjectIdentity(&object, false),
105 : 0 : quote_identifier(NameStr(attForm->attname)));
4498 106 : 0 : sepgsql_avc_check_perms_label(ncontext,
107 : : SEPG_CLASS_DB_COLUMN,
108 : : SEPG_DB_COLUMN__CREATE,
4020 109 : 0 : audit_name.data,
110 : : true);
111 : :
112 : : /*
113 : : * Assign the default security label on a new procedure
114 : : */
4830 115 : 0 : object.classId = RelationRelationId;
116 : 0 : object.objectId = relOid;
117 : 0 : object.objectSubId = attnum;
118 : 0 : SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, ncontext);
119 : :
4498 120 : 0 : systable_endscan(sscan);
1910 andres@anarazel.de 121 : 0 : table_close(rel, AccessShareLock);
122 : :
4830 rhaas@postgresql.org 123 : 0 : pfree(tcontext);
124 : 0 : pfree(ncontext);
125 : : }
126 : :
127 : : /*
128 : : * sepgsql_attribute_drop
129 : : *
130 : : * It checks privileges to drop the supplied column.
131 : : */
132 : : void
4419 133 : 0 : sepgsql_attribute_drop(Oid relOid, AttrNumber attnum)
134 : : {
135 : : ObjectAddress object;
136 : : char *audit_name;
2562 mail@joeconway.com 137 : 0 : char relkind = get_rel_relkind(relOid);
138 : :
139 [ # # # # ]: 0 : if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE)
4419 rhaas@postgresql.org 140 : 0 : return;
141 : :
142 : : /*
143 : : * check db_column:{drop} permission
144 : : */
145 : 0 : object.classId = RelationRelationId;
146 : 0 : object.objectId = relOid;
147 : 0 : object.objectSubId = attnum;
1369 michael@paquier.xyz 148 : 0 : audit_name = getObjectIdentity(&object, false);
149 : :
4419 rhaas@postgresql.org 150 : 0 : sepgsql_avc_check_perms(&object,
151 : : SEPG_CLASS_DB_COLUMN,
152 : : SEPG_DB_COLUMN__DROP,
153 : : audit_name,
154 : : true);
155 : 0 : pfree(audit_name);
156 : : }
157 : :
158 : : /*
159 : : * sepgsql_attribute_relabel
160 : : *
161 : : * It checks privileges to relabel the supplied column
162 : : * by the `seclabel'.
163 : : */
164 : : void
4830 165 : 0 : sepgsql_attribute_relabel(Oid relOid, AttrNumber attnum,
166 : : const char *seclabel)
167 : : {
168 : : ObjectAddress object;
169 : : char *audit_name;
2562 mail@joeconway.com 170 : 0 : char relkind = get_rel_relkind(relOid);
171 : :
172 [ # # # # ]: 0 : if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE)
4830 rhaas@postgresql.org 173 [ # # ]: 0 : ereport(ERROR,
174 : : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
175 : : errmsg("cannot set security label on non-regular columns")));
176 : :
4820 177 : 0 : object.classId = RelationRelationId;
178 : 0 : object.objectId = relOid;
179 : 0 : object.objectSubId = attnum;
1369 michael@paquier.xyz 180 : 0 : audit_name = getObjectIdentity(&object, false);
181 : :
182 : : /*
183 : : * check db_column:{setattr relabelfrom} permission
184 : : */
4609 rhaas@postgresql.org 185 : 0 : sepgsql_avc_check_perms(&object,
186 : : SEPG_CLASS_DB_COLUMN,
187 : : SEPG_DB_COLUMN__SETATTR |
188 : : SEPG_DB_COLUMN__RELABELFROM,
189 : : audit_name,
190 : : true);
191 : :
192 : : /*
193 : : * check db_column:{relabelto} permission
194 : : */
195 : 0 : sepgsql_avc_check_perms_label(seclabel,
196 : : SEPG_CLASS_DB_COLUMN,
197 : : SEPG_DB_PROCEDURE__RELABELTO,
198 : : audit_name,
199 : : true);
4820 200 : 0 : pfree(audit_name);
4830 201 : 0 : }
202 : :
203 : : /*
204 : : * sepgsql_attribute_setattr
205 : : *
206 : : * It checks privileges to alter the supplied column.
207 : : */
208 : : void
4036 209 : 0 : sepgsql_attribute_setattr(Oid relOid, AttrNumber attnum)
210 : : {
211 : : ObjectAddress object;
212 : : char *audit_name;
2562 mail@joeconway.com 213 : 0 : char relkind = get_rel_relkind(relOid);
214 : :
215 [ # # # # ]: 0 : if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE)
4036 rhaas@postgresql.org 216 : 0 : return;
217 : :
218 : : /*
219 : : * check db_column:{setattr} permission
220 : : */
221 : 0 : object.classId = RelationRelationId;
222 : 0 : object.objectId = relOid;
223 : 0 : object.objectSubId = attnum;
1369 michael@paquier.xyz 224 : 0 : audit_name = getObjectIdentity(&object, false);
225 : :
4036 rhaas@postgresql.org 226 : 0 : sepgsql_avc_check_perms(&object,
227 : : SEPG_CLASS_DB_COLUMN,
228 : : SEPG_DB_COLUMN__SETATTR,
229 : : audit_name,
230 : : true);
231 : 0 : pfree(audit_name);
232 : : }
233 : :
234 : : /*
235 : : * sepgsql_relation_post_create
236 : : *
237 : : * The post creation hook of relation/attribute
238 : : */
239 : : void
4830 240 : 0 : sepgsql_relation_post_create(Oid relOid)
241 : : {
242 : : Relation rel;
243 : : ScanKeyData skey;
244 : : SysScanDesc sscan;
245 : : HeapTuple tuple;
246 : : Form_pg_class classForm;
247 : : ObjectAddress object;
248 : : uint16_t tclass;
249 : : char *scontext; /* subject */
250 : : char *tcontext; /* schema */
251 : : char *rcontext; /* relation */
252 : : char *ccontext; /* column */
253 : : char *nsp_name;
254 : : StringInfoData audit_name;
255 : :
256 : : /*
257 : : * Fetch catalog record of the new relation. Because pg_class entry is not
258 : : * visible right now, we need to scan the catalog using SnapshotSelf.
259 : : */
1910 andres@anarazel.de 260 : 0 : rel = table_open(RelationRelationId, AccessShareLock);
261 : :
4830 rhaas@postgresql.org 262 : 0 : ScanKeyInit(&skey,
263 : : Anum_pg_class_oid,
264 : : BTEqualStrategyNumber, F_OIDEQ,
265 : : ObjectIdGetDatum(relOid));
266 : :
267 : 0 : sscan = systable_beginscan(rel, ClassOidIndexId, true,
268 : : SnapshotSelf, 1, &skey);
269 : :
270 : 0 : tuple = systable_getnext(sscan);
271 [ # # ]: 0 : if (!HeapTupleIsValid(tuple))
2506 tgl@sss.pgh.pa.us 272 [ # # ]: 0 : elog(ERROR, "could not find tuple for relation %u", relOid);
273 : :
4830 rhaas@postgresql.org 274 : 0 : classForm = (Form_pg_class) GETSTRUCT(tuple);
275 : :
276 : : /* ignore indexes on toast tables */
4191 alvherre@alvh.no-ip. 277 [ # # ]: 0 : if (classForm->relkind == RELKIND_INDEX &&
278 [ # # ]: 0 : classForm->relnamespace == PG_TOAST_NAMESPACE)
279 : 0 : goto out;
280 : :
281 : : /*
282 : : * check db_schema:{add_name} permission of the namespace
283 : : */
284 : 0 : object.classId = NamespaceRelationId;
285 : 0 : object.objectId = classForm->relnamespace;
286 : 0 : object.objectSubId = 0;
287 : 0 : sepgsql_avc_check_perms(&object,
288 : : SEPG_CLASS_DB_SCHEMA,
289 : : SEPG_DB_SCHEMA__ADD_NAME,
1369 michael@paquier.xyz 290 : 0 : getObjectIdentity(&object, false),
291 : : true);
292 : :
4498 rhaas@postgresql.org 293 [ # # # # : 0 : switch (classForm->relkind)
# ]
294 : : {
295 : 0 : case RELKIND_RELATION:
296 : : case RELKIND_PARTITIONED_TABLE:
297 : 0 : tclass = SEPG_CLASS_DB_TABLE;
298 : 0 : break;
299 : 0 : case RELKIND_SEQUENCE:
300 : 0 : tclass = SEPG_CLASS_DB_SEQUENCE;
301 : 0 : break;
302 : 0 : case RELKIND_VIEW:
303 : 0 : tclass = SEPG_CLASS_DB_VIEW;
304 : 0 : break;
4191 alvherre@alvh.no-ip. 305 : 0 : case RELKIND_INDEX:
306 : : /* deal with indexes specially; no need for tclass */
307 : 0 : sepgsql_index_modify(relOid);
308 : 0 : goto out;
4498 rhaas@postgresql.org 309 : 0 : default:
310 : : /* ignore other relkinds */
311 : 0 : goto out;
312 : : }
313 : :
314 : : /*
315 : : * Compute a default security label when we create a new relation object
316 : : * under the specified namespace.
317 : : */
4830 318 : 0 : scontext = sepgsql_get_client_label();
319 : 0 : tcontext = sepgsql_get_label(NamespaceRelationId,
320 : : classForm->relnamespace, 0);
4035 321 : 0 : rcontext = sepgsql_compute_create(scontext, tcontext, tclass,
322 : 0 : NameStr(classForm->relname));
323 : :
324 : : /*
325 : : * check db_xxx:{create} permission
326 : : */
4020 327 : 0 : nsp_name = get_namespace_name(classForm->relnamespace);
328 : 0 : initStringInfo(&audit_name);
329 : 0 : appendStringInfo(&audit_name, "%s.%s",
330 : : quote_identifier(nsp_name),
331 : 0 : quote_identifier(NameStr(classForm->relname)));
4498 332 : 0 : sepgsql_avc_check_perms_label(rcontext,
333 : : tclass,
334 : : SEPG_DB_DATABASE__CREATE,
4020 335 : 0 : audit_name.data,
336 : : true);
337 : :
338 : : /*
339 : : * Assign the default security label on the new regular or partitioned
340 : : * relation.
341 : : */
4830 342 : 0 : object.classId = RelationRelationId;
343 : 0 : object.objectId = relOid;
344 : 0 : object.objectSubId = 0;
345 : 0 : SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, rcontext);
346 : :
347 : : /*
348 : : * We also assign a default security label on columns of a new table.
349 : : */
2562 mail@joeconway.com 350 [ # # ]: 0 : if (classForm->relkind == RELKIND_RELATION ||
351 [ # # ]: 0 : classForm->relkind == RELKIND_PARTITIONED_TABLE)
352 : : {
353 : : Relation arel;
354 : : ScanKeyData akey;
355 : : SysScanDesc ascan;
356 : : HeapTuple atup;
357 : : Form_pg_attribute attForm;
358 : :
1910 andres@anarazel.de 359 : 0 : arel = table_open(AttributeRelationId, AccessShareLock);
360 : :
4498 rhaas@postgresql.org 361 : 0 : ScanKeyInit(&akey,
362 : : Anum_pg_attribute_attrelid,
363 : : BTEqualStrategyNumber, F_OIDEQ,
364 : : ObjectIdGetDatum(relOid));
365 : :
366 : 0 : ascan = systable_beginscan(arel, AttributeRelidNumIndexId, true,
367 : : SnapshotSelf, 1, &akey);
368 : :
369 [ # # ]: 0 : while (HeapTupleIsValid(atup = systable_getnext(ascan)))
370 : : {
371 : 0 : attForm = (Form_pg_attribute) GETSTRUCT(atup);
372 : :
4020 373 : 0 : resetStringInfo(&audit_name);
374 : 0 : appendStringInfo(&audit_name, "%s.%s.%s",
375 : : quote_identifier(nsp_name),
376 : 0 : quote_identifier(NameStr(classForm->relname)),
377 : 0 : quote_identifier(NameStr(attForm->attname)));
378 : :
4498 379 : 0 : ccontext = sepgsql_compute_create(scontext,
380 : : rcontext,
381 : : SEPG_CLASS_DB_COLUMN,
4035 382 : 0 : NameStr(attForm->attname));
383 : :
384 : : /*
385 : : * check db_column:{create} permission
386 : : */
4498 387 : 0 : sepgsql_avc_check_perms_label(ccontext,
388 : : SEPG_CLASS_DB_COLUMN,
389 : : SEPG_DB_COLUMN__CREATE,
4020 390 : 0 : audit_name.data,
391 : : true);
392 : :
4830 393 : 0 : object.classId = RelationRelationId;
394 : 0 : object.objectId = relOid;
4498 395 : 0 : object.objectSubId = attForm->attnum;
4830 396 : 0 : SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, ccontext);
397 : :
4498 398 : 0 : pfree(ccontext);
399 : : }
400 : 0 : systable_endscan(ascan);
1910 andres@anarazel.de 401 : 0 : table_close(arel, AccessShareLock);
402 : : }
4830 rhaas@postgresql.org 403 : 0 : pfree(rcontext);
404 : :
405 : 0 : out:
406 : 0 : systable_endscan(sscan);
1910 andres@anarazel.de 407 : 0 : table_close(rel, AccessShareLock);
4830 rhaas@postgresql.org 408 : 0 : }
409 : :
410 : : /*
411 : : * sepgsql_relation_drop
412 : : *
413 : : * It checks privileges to drop the supplied relation.
414 : : */
415 : : void
4419 416 : 0 : sepgsql_relation_drop(Oid relOid)
417 : : {
418 : : ObjectAddress object;
419 : : char *audit_name;
2565 mail@joeconway.com 420 : 0 : uint16_t tclass = 0;
2562 421 : 0 : char relkind = get_rel_relkind(relOid);
422 : :
4191 alvherre@alvh.no-ip. 423 [ # # # # : 0 : switch (relkind)
# ]
424 : : {
425 : 0 : case RELKIND_RELATION:
426 : : case RELKIND_PARTITIONED_TABLE:
427 : 0 : tclass = SEPG_CLASS_DB_TABLE;
428 : 0 : break;
429 : 0 : case RELKIND_SEQUENCE:
430 : 0 : tclass = SEPG_CLASS_DB_SEQUENCE;
431 : 0 : break;
432 : 0 : case RELKIND_VIEW:
433 : 0 : tclass = SEPG_CLASS_DB_VIEW;
434 : 0 : break;
435 : 0 : case RELKIND_INDEX:
436 : : /* ignore indexes on toast tables */
437 [ # # ]: 0 : if (get_rel_namespace(relOid) == PG_TOAST_NAMESPACE)
438 : 0 : return;
439 : : /* other indexes are handled specially below; no need for tclass */
440 : 0 : break;
441 : 0 : default:
442 : : /* ignore other relkinds */
443 : 0 : return;
444 : : }
445 : :
446 : : /*
447 : : * check db_schema:{remove_name} permission
448 : : */
4419 rhaas@postgresql.org 449 : 0 : object.classId = NamespaceRelationId;
450 : 0 : object.objectId = get_rel_namespace(relOid);
451 : 0 : object.objectSubId = 0;
1369 michael@paquier.xyz 452 : 0 : audit_name = getObjectIdentity(&object, false);
453 : :
4419 rhaas@postgresql.org 454 : 0 : sepgsql_avc_check_perms(&object,
455 : : SEPG_CLASS_DB_SCHEMA,
456 : : SEPG_DB_SCHEMA__REMOVE_NAME,
457 : : audit_name,
458 : : true);
459 : 0 : pfree(audit_name);
460 : :
461 : : /* deal with indexes specially */
4191 alvherre@alvh.no-ip. 462 [ # # ]: 0 : if (relkind == RELKIND_INDEX)
463 : : {
464 : 0 : sepgsql_index_modify(relOid);
465 : 0 : return;
466 : : }
467 : :
468 : : /*
469 : : * check db_table/sequence/view:{drop} permission
470 : : */
4419 rhaas@postgresql.org 471 : 0 : object.classId = RelationRelationId;
472 : 0 : object.objectId = relOid;
473 : 0 : object.objectSubId = 0;
1369 michael@paquier.xyz 474 : 0 : audit_name = getObjectIdentity(&object, false);
475 : :
4419 rhaas@postgresql.org 476 : 0 : sepgsql_avc_check_perms(&object,
477 : : tclass,
478 : : SEPG_DB_TABLE__DROP,
479 : : audit_name,
480 : : true);
481 : 0 : pfree(audit_name);
482 : :
483 : : /*
484 : : * check db_column:{drop} permission
485 : : */
2562 mail@joeconway.com 486 [ # # # # ]: 0 : if (relkind == RELKIND_RELATION || relkind == RELKIND_PARTITIONED_TABLE)
487 : : {
488 : : Form_pg_attribute attForm;
489 : : CatCList *attrList;
490 : : HeapTuple atttup;
491 : : int i;
492 : :
4419 rhaas@postgresql.org 493 : 0 : attrList = SearchSysCacheList1(ATTNUM, ObjectIdGetDatum(relOid));
4326 bruce@momjian.us 494 [ # # ]: 0 : for (i = 0; i < attrList->n_members; i++)
495 : : {
4419 rhaas@postgresql.org 496 : 0 : atttup = &attrList->members[i]->tuple;
497 : 0 : attForm = (Form_pg_attribute) GETSTRUCT(atttup);
498 : :
499 [ # # ]: 0 : if (attForm->attisdropped)
500 : 0 : continue;
501 : :
502 : 0 : object.classId = RelationRelationId;
503 : 0 : object.objectId = relOid;
504 : 0 : object.objectSubId = attForm->attnum;
1369 michael@paquier.xyz 505 : 0 : audit_name = getObjectIdentity(&object, false);
506 : :
4419 rhaas@postgresql.org 507 : 0 : sepgsql_avc_check_perms(&object,
508 : : SEPG_CLASS_DB_COLUMN,
509 : : SEPG_DB_COLUMN__DROP,
510 : : audit_name,
511 : : true);
512 : 0 : pfree(audit_name);
513 : : }
514 : 0 : ReleaseCatCacheList(attrList);
515 : : }
516 : : }
517 : :
518 : : /*
519 : : * sepgsql_relation_truncate
520 : : *
521 : : * Check privileges to TRUNCATE the supplied relation.
522 : : */
523 : : void
1604 mail@joeconway.com 524 : 0 : sepgsql_relation_truncate(Oid relOid)
525 : : {
526 : : ObjectAddress object;
527 : : char *audit_name;
528 : 0 : uint16_t tclass = 0;
529 : 0 : char relkind = get_rel_relkind(relOid);
530 : :
531 [ # # ]: 0 : switch (relkind)
532 : : {
533 : 0 : case RELKIND_RELATION:
534 : : case RELKIND_PARTITIONED_TABLE:
535 : 0 : tclass = SEPG_CLASS_DB_TABLE;
536 : 0 : break;
537 : 0 : default:
538 : : /* ignore other relkinds */
539 : 0 : return;
540 : : }
541 : :
542 : : /*
543 : : * check db_table:{truncate} permission
544 : : */
545 : 0 : object.classId = RelationRelationId;
546 : 0 : object.objectId = relOid;
547 : 0 : object.objectSubId = 0;
1369 michael@paquier.xyz 548 : 0 : audit_name = getObjectIdentity(&object, false);
549 : :
1604 mail@joeconway.com 550 : 0 : sepgsql_avc_check_perms(&object,
551 : : tclass,
552 : : SEPG_DB_TABLE__TRUNCATE,
553 : : audit_name,
554 : : true);
555 : 0 : pfree(audit_name);
556 : : }
557 : :
558 : : /*
559 : : * sepgsql_relation_relabel
560 : : *
561 : : * It checks privileges to relabel the supplied relation by the `seclabel'.
562 : : */
563 : : void
4830 rhaas@postgresql.org 564 : 0 : sepgsql_relation_relabel(Oid relOid, const char *seclabel)
565 : : {
566 : : ObjectAddress object;
567 : : char *audit_name;
2562 mail@joeconway.com 568 : 0 : char relkind = get_rel_relkind(relOid);
4830 rhaas@postgresql.org 569 : 0 : uint16_t tclass = 0;
570 : :
2562 mail@joeconway.com 571 [ # # # # ]: 0 : if (relkind == RELKIND_RELATION || relkind == RELKIND_PARTITIONED_TABLE)
4830 rhaas@postgresql.org 572 : 0 : tclass = SEPG_CLASS_DB_TABLE;
573 [ # # ]: 0 : else if (relkind == RELKIND_SEQUENCE)
574 : 0 : tclass = SEPG_CLASS_DB_SEQUENCE;
575 [ # # ]: 0 : else if (relkind == RELKIND_VIEW)
576 : 0 : tclass = SEPG_CLASS_DB_VIEW;
577 : : else
578 [ # # ]: 0 : ereport(ERROR,
579 : : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
580 : : errmsg("cannot set security labels on relations except "
581 : : "for tables, sequences or views")));
582 : :
4609 583 : 0 : object.classId = RelationRelationId;
584 : 0 : object.objectId = relOid;
585 : 0 : object.objectSubId = 0;
1369 michael@paquier.xyz 586 : 0 : audit_name = getObjectIdentity(&object, false);
587 : :
588 : : /*
589 : : * check db_xxx:{setattr relabelfrom} permission
590 : : */
4609 rhaas@postgresql.org 591 : 0 : sepgsql_avc_check_perms(&object,
592 : : tclass,
593 : : SEPG_DB_TABLE__SETATTR |
594 : : SEPG_DB_TABLE__RELABELFROM,
595 : : audit_name,
596 : : true);
597 : :
598 : : /*
599 : : * check db_xxx:{relabelto} permission
600 : : */
601 : 0 : sepgsql_avc_check_perms_label(seclabel,
602 : : tclass,
603 : : SEPG_DB_TABLE__RELABELTO,
604 : : audit_name,
605 : : true);
4820 606 : 0 : pfree(audit_name);
4830 607 : 0 : }
608 : :
609 : : /*
610 : : * sepgsql_relation_setattr
611 : : *
612 : : * It checks privileges to set attribute of the supplied relation
613 : : */
614 : : void
4191 alvherre@alvh.no-ip. 615 : 0 : sepgsql_relation_setattr(Oid relOid)
616 : : {
617 : : Relation rel;
618 : : ScanKeyData skey;
619 : : SysScanDesc sscan;
620 : : HeapTuple oldtup;
621 : : HeapTuple newtup;
622 : : Form_pg_class oldform;
623 : : Form_pg_class newform;
624 : : ObjectAddress object;
625 : : char *audit_name;
626 : : uint16_t tclass;
627 : :
628 [ # # # # : 0 : switch (get_rel_relkind(relOid))
# ]
629 : : {
630 : 0 : case RELKIND_RELATION:
631 : : case RELKIND_PARTITIONED_TABLE:
632 : 0 : tclass = SEPG_CLASS_DB_TABLE;
633 : 0 : break;
634 : 0 : case RELKIND_SEQUENCE:
635 : 0 : tclass = SEPG_CLASS_DB_SEQUENCE;
636 : 0 : break;
637 : 0 : case RELKIND_VIEW:
638 : 0 : tclass = SEPG_CLASS_DB_VIEW;
639 : 0 : break;
640 : 0 : case RELKIND_INDEX:
641 : : /* deal with indexes specially */
642 : 0 : sepgsql_index_modify(relOid);
643 : 0 : return;
644 : 0 : default:
645 : : /* other relkinds don't need additional work */
646 : 0 : return;
647 : : }
648 : :
649 : : /*
650 : : * Fetch newer catalog
651 : : */
1910 andres@anarazel.de 652 : 0 : rel = table_open(RelationRelationId, AccessShareLock);
653 : :
4036 rhaas@postgresql.org 654 : 0 : ScanKeyInit(&skey,
655 : : Anum_pg_class_oid,
656 : : BTEqualStrategyNumber, F_OIDEQ,
657 : : ObjectIdGetDatum(relOid));
658 : :
659 : 0 : sscan = systable_beginscan(rel, ClassOidIndexId, true,
660 : : SnapshotSelf, 1, &skey);
661 : :
662 : 0 : newtup = systable_getnext(sscan);
663 [ # # ]: 0 : if (!HeapTupleIsValid(newtup))
2506 tgl@sss.pgh.pa.us 664 [ # # ]: 0 : elog(ERROR, "could not find tuple for relation %u", relOid);
4036 rhaas@postgresql.org 665 : 0 : newform = (Form_pg_class) GETSTRUCT(newtup);
666 : :
667 : : /*
668 : : * Fetch older catalog
669 : : */
670 : 0 : oldtup = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid));
671 [ # # ]: 0 : if (!HeapTupleIsValid(oldtup))
672 [ # # ]: 0 : elog(ERROR, "cache lookup failed for relation %u", relOid);
673 : 0 : oldform = (Form_pg_class) GETSTRUCT(oldtup);
674 : :
675 : : /*
676 : : * Does this ALTER command takes operation to namespace?
677 : : */
678 [ # # ]: 0 : if (newform->relnamespace != oldform->relnamespace)
679 : : {
680 : 0 : sepgsql_schema_remove_name(oldform->relnamespace);
681 : 0 : sepgsql_schema_add_name(newform->relnamespace);
682 : : }
683 [ # # ]: 0 : if (strcmp(NameStr(newform->relname), NameStr(oldform->relname)) != 0)
684 : 0 : sepgsql_schema_rename(oldform->relnamespace);
685 : :
686 : : /*
687 : : * XXX - In the future version, db_tuple:{use} of system catalog entry
688 : : * shall be checked, if tablespace configuration is changed.
689 : : */
690 : :
691 : : /*
692 : : * check db_xxx:{setattr} permission
693 : : */
694 : 0 : object.classId = RelationRelationId;
695 : 0 : object.objectId = relOid;
696 : 0 : object.objectSubId = 0;
1369 michael@paquier.xyz 697 : 0 : audit_name = getObjectIdentity(&object, false);
698 : :
4191 alvherre@alvh.no-ip. 699 : 0 : sepgsql_avc_check_perms(&object,
700 : : tclass,
701 : : SEPG_DB_TABLE__SETATTR,
702 : : audit_name,
703 : : true);
704 : 0 : pfree(audit_name);
705 : :
4036 rhaas@postgresql.org 706 : 0 : ReleaseSysCache(oldtup);
707 : 0 : systable_endscan(sscan);
1910 andres@anarazel.de 708 : 0 : table_close(rel, AccessShareLock);
709 : : }
710 : :
711 : : /*
712 : : * sepgsql_relation_setattr_extra
713 : : *
714 : : * It checks permission of the relation being referenced by extra attributes,
715 : : * such as pg_index entries. Like core PostgreSQL, sepgsql also does not deal
716 : : * with such entries as individual "objects", thus, modification of these
717 : : * entries shall be considered as setting an attribute of the underlying
718 : : * relation.
719 : : */
720 : : static void
4191 alvherre@alvh.no-ip. 721 : 0 : sepgsql_relation_setattr_extra(Relation catalog,
722 : : Oid catindex_id,
723 : : Oid extra_oid,
724 : : AttrNumber anum_relation_id,
725 : : AttrNumber anum_extra_id)
726 : : {
727 : : ScanKeyData skey;
728 : : SysScanDesc sscan;
729 : : HeapTuple tuple;
730 : : Datum datum;
731 : : bool isnull;
732 : :
733 : 0 : ScanKeyInit(&skey, anum_extra_id,
734 : : BTEqualStrategyNumber, F_OIDEQ,
735 : : ObjectIdGetDatum(extra_oid));
736 : :
737 : 0 : sscan = systable_beginscan(catalog, catindex_id, true,
738 : : SnapshotSelf, 1, &skey);
739 : 0 : tuple = systable_getnext(sscan);
740 [ # # ]: 0 : if (!HeapTupleIsValid(tuple))
2506 tgl@sss.pgh.pa.us 741 [ # # ]: 0 : elog(ERROR, "could not find tuple for object %u in catalog \"%s\"",
742 : : extra_oid, RelationGetRelationName(catalog));
743 : :
4191 alvherre@alvh.no-ip. 744 : 0 : datum = heap_getattr(tuple, anum_relation_id,
745 : : RelationGetDescr(catalog), &isnull);
746 [ # # ]: 0 : Assert(!isnull);
747 : :
748 : 0 : sepgsql_relation_setattr(DatumGetObjectId(datum));
749 : :
750 : 0 : systable_endscan(sscan);
751 : 0 : }
752 : :
753 : : /*
754 : : * sepgsql_index_modify
755 : : * Handle index create, update, drop
756 : : *
757 : : * Unlike other relation kinds, indexes do not have their own security labels,
758 : : * so instead of doing checks directly, treat them as extra attributes of their
759 : : * owning tables; so check 'setattr' permissions on the table.
760 : : */
761 : : static void
762 : 0 : sepgsql_index_modify(Oid indexOid)
763 : : {
1910 andres@anarazel.de 764 : 0 : Relation catalog = table_open(IndexRelationId, AccessShareLock);
765 : :
766 : : /* check db_table:{setattr} permission of the table being indexed */
4191 alvherre@alvh.no-ip. 767 : 0 : sepgsql_relation_setattr_extra(catalog,
768 : : IndexRelidIndexId,
769 : : indexOid,
770 : : Anum_pg_index_indrelid,
771 : : Anum_pg_index_indexrelid);
1910 andres@anarazel.de 772 : 0 : table_close(catalog, AccessShareLock);
4191 alvherre@alvh.no-ip. 773 : 0 : }
|