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