00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include "postgres.h"
00012
00013 #include "access/genam.h"
00014 #include "access/heapam.h"
00015 #include "access/htup_details.h"
00016 #include "access/sysattr.h"
00017 #include "catalog/indexing.h"
00018 #include "catalog/dependency.h"
00019 #include "catalog/pg_attribute.h"
00020 #include "catalog/pg_class.h"
00021 #include "catalog/pg_namespace.h"
00022 #include "commands/seclabel.h"
00023 #include "lib/stringinfo.h"
00024 #include "utils/builtins.h"
00025 #include "utils/fmgroids.h"
00026 #include "utils/catcache.h"
00027 #include "utils/lsyscache.h"
00028 #include "utils/rel.h"
00029 #include "utils/syscache.h"
00030 #include "utils/tqual.h"
00031
00032 #include "sepgsql.h"
00033
00034 static void sepgsql_index_modify(Oid indexOid);
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044 void
00045 sepgsql_attribute_post_create(Oid relOid, AttrNumber attnum)
00046 {
00047 Relation rel;
00048 ScanKeyData skey[2];
00049 SysScanDesc sscan;
00050 HeapTuple tuple;
00051 char *scontext;
00052 char *tcontext;
00053 char *ncontext;
00054 ObjectAddress object;
00055 Form_pg_attribute attForm;
00056 StringInfoData audit_name;
00057
00058
00059
00060
00061
00062 if (get_rel_relkind(relOid) != RELKIND_RELATION)
00063 return;
00064
00065
00066
00067
00068
00069 rel = heap_open(AttributeRelationId, AccessShareLock);
00070
00071 ScanKeyInit(&skey[0],
00072 Anum_pg_attribute_attrelid,
00073 BTEqualStrategyNumber, F_OIDEQ,
00074 ObjectIdGetDatum(relOid));
00075 ScanKeyInit(&skey[1],
00076 Anum_pg_attribute_attnum,
00077 BTEqualStrategyNumber, F_INT2EQ,
00078 Int16GetDatum(attnum));
00079
00080 sscan = systable_beginscan(rel, AttributeRelidNumIndexId, true,
00081 SnapshotSelf, 2, &skey[0]);
00082
00083 tuple = systable_getnext(sscan);
00084 if (!HeapTupleIsValid(tuple))
00085 elog(ERROR, "catalog lookup failed for column %d of relation %u",
00086 attnum, relOid);
00087
00088 attForm = (Form_pg_attribute) GETSTRUCT(tuple);
00089
00090 scontext = sepgsql_get_client_label();
00091 tcontext = sepgsql_get_label(RelationRelationId, relOid, 0);
00092 ncontext = sepgsql_compute_create(scontext, tcontext,
00093 SEPG_CLASS_DB_COLUMN,
00094 NameStr(attForm->attname));
00095
00096
00097
00098
00099 object.classId = RelationRelationId;
00100 object.objectId = relOid;
00101 object.objectSubId = 0;
00102
00103 initStringInfo(&audit_name);
00104 appendStringInfo(&audit_name, "%s.%s",
00105 getObjectIdentity(&object),
00106 quote_identifier(NameStr(attForm->attname)));
00107 sepgsql_avc_check_perms_label(ncontext,
00108 SEPG_CLASS_DB_COLUMN,
00109 SEPG_DB_COLUMN__CREATE,
00110 audit_name.data,
00111 true);
00112
00113
00114
00115
00116 object.classId = RelationRelationId;
00117 object.objectId = relOid;
00118 object.objectSubId = attnum;
00119 SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, ncontext);
00120
00121 systable_endscan(sscan);
00122 heap_close(rel, AccessShareLock);
00123
00124 pfree(tcontext);
00125 pfree(ncontext);
00126 }
00127
00128
00129
00130
00131
00132
00133 void
00134 sepgsql_attribute_drop(Oid relOid, AttrNumber attnum)
00135 {
00136 ObjectAddress object;
00137 char *audit_name;
00138
00139 if (get_rel_relkind(relOid) != RELKIND_RELATION)
00140 return;
00141
00142
00143
00144
00145 object.classId = RelationRelationId;
00146 object.objectId = relOid;
00147 object.objectSubId = attnum;
00148 audit_name = getObjectIdentity(&object);
00149
00150 sepgsql_avc_check_perms(&object,
00151 SEPG_CLASS_DB_COLUMN,
00152 SEPG_DB_COLUMN__DROP,
00153 audit_name,
00154 true);
00155 pfree(audit_name);
00156 }
00157
00158
00159
00160
00161
00162
00163
00164 void
00165 sepgsql_attribute_relabel(Oid relOid, AttrNumber attnum,
00166 const char *seclabel)
00167 {
00168 ObjectAddress object;
00169 char *audit_name;
00170
00171 if (get_rel_relkind(relOid) != RELKIND_RELATION)
00172 ereport(ERROR,
00173 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
00174 errmsg("cannot set security label on non-regular columns")));
00175
00176 object.classId = RelationRelationId;
00177 object.objectId = relOid;
00178 object.objectSubId = attnum;
00179 audit_name = getObjectIdentity(&object);
00180
00181
00182
00183
00184 sepgsql_avc_check_perms(&object,
00185 SEPG_CLASS_DB_COLUMN,
00186 SEPG_DB_COLUMN__SETATTR |
00187 SEPG_DB_COLUMN__RELABELFROM,
00188 audit_name,
00189 true);
00190
00191
00192
00193
00194 sepgsql_avc_check_perms_label(seclabel,
00195 SEPG_CLASS_DB_COLUMN,
00196 SEPG_DB_PROCEDURE__RELABELTO,
00197 audit_name,
00198 true);
00199 pfree(audit_name);
00200 }
00201
00202
00203
00204
00205
00206
00207 void
00208 sepgsql_attribute_setattr(Oid relOid, AttrNumber attnum)
00209 {
00210 ObjectAddress object;
00211 char *audit_name;
00212
00213 if (get_rel_relkind(relOid) != RELKIND_RELATION)
00214 return;
00215
00216
00217
00218
00219 object.classId = RelationRelationId;
00220 object.objectId = relOid;
00221 object.objectSubId = attnum;
00222 audit_name = getObjectIdentity(&object);
00223
00224 sepgsql_avc_check_perms(&object,
00225 SEPG_CLASS_DB_COLUMN,
00226 SEPG_DB_COLUMN__SETATTR,
00227 audit_name,
00228 true);
00229 pfree(audit_name);
00230 }
00231
00232
00233
00234
00235
00236
00237 void
00238 sepgsql_relation_post_create(Oid relOid)
00239 {
00240 Relation rel;
00241 ScanKeyData skey;
00242 SysScanDesc sscan;
00243 HeapTuple tuple;
00244 Form_pg_class classForm;
00245 ObjectAddress object;
00246 uint16 tclass;
00247 char *scontext;
00248 char *tcontext;
00249 char *rcontext;
00250 char *ccontext;
00251 char *nsp_name;
00252 StringInfoData audit_name;
00253
00254
00255
00256
00257
00258 rel = heap_open(RelationRelationId, AccessShareLock);
00259
00260 ScanKeyInit(&skey,
00261 ObjectIdAttributeNumber,
00262 BTEqualStrategyNumber, F_OIDEQ,
00263 ObjectIdGetDatum(relOid));
00264
00265 sscan = systable_beginscan(rel, ClassOidIndexId, true,
00266 SnapshotSelf, 1, &skey);
00267
00268 tuple = systable_getnext(sscan);
00269 if (!HeapTupleIsValid(tuple))
00270 elog(ERROR, "catalog lookup failed for relation %u", relOid);
00271
00272 classForm = (Form_pg_class) GETSTRUCT(tuple);
00273
00274
00275 if (classForm->relkind == RELKIND_INDEX &&
00276 classForm->relnamespace == PG_TOAST_NAMESPACE)
00277 goto out;
00278
00279
00280
00281
00282 object.classId = NamespaceRelationId;
00283 object.objectId = classForm->relnamespace;
00284 object.objectSubId = 0;
00285 sepgsql_avc_check_perms(&object,
00286 SEPG_CLASS_DB_SCHEMA,
00287 SEPG_DB_SCHEMA__ADD_NAME,
00288 getObjectIdentity(&object),
00289 true);
00290
00291 switch (classForm->relkind)
00292 {
00293 case RELKIND_RELATION:
00294 tclass = SEPG_CLASS_DB_TABLE;
00295 break;
00296 case RELKIND_SEQUENCE:
00297 tclass = SEPG_CLASS_DB_SEQUENCE;
00298 break;
00299 case RELKIND_VIEW:
00300 tclass = SEPG_CLASS_DB_VIEW;
00301 break;
00302 case RELKIND_INDEX:
00303
00304 sepgsql_index_modify(relOid);
00305 goto out;
00306 default:
00307
00308 goto out;
00309 }
00310
00311
00312
00313
00314
00315 scontext = sepgsql_get_client_label();
00316 tcontext = sepgsql_get_label(NamespaceRelationId,
00317 classForm->relnamespace, 0);
00318 rcontext = sepgsql_compute_create(scontext, tcontext, tclass,
00319 NameStr(classForm->relname));
00320
00321
00322
00323
00324 nsp_name = get_namespace_name(classForm->relnamespace);
00325 initStringInfo(&audit_name);
00326 appendStringInfo(&audit_name, "%s.%s",
00327 quote_identifier(nsp_name),
00328 quote_identifier(NameStr(classForm->relname)));
00329 sepgsql_avc_check_perms_label(rcontext,
00330 tclass,
00331 SEPG_DB_DATABASE__CREATE,
00332 audit_name.data,
00333 true);
00334
00335
00336
00337
00338 object.classId = RelationRelationId;
00339 object.objectId = relOid;
00340 object.objectSubId = 0;
00341 SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, rcontext);
00342
00343
00344
00345
00346
00347 if (classForm->relkind == RELKIND_RELATION)
00348 {
00349 Relation arel;
00350 ScanKeyData akey;
00351 SysScanDesc ascan;
00352 HeapTuple atup;
00353 Form_pg_attribute attForm;
00354
00355 arel = heap_open(AttributeRelationId, AccessShareLock);
00356
00357 ScanKeyInit(&akey,
00358 Anum_pg_attribute_attrelid,
00359 BTEqualStrategyNumber, F_OIDEQ,
00360 ObjectIdGetDatum(relOid));
00361
00362 ascan = systable_beginscan(arel, AttributeRelidNumIndexId, true,
00363 SnapshotSelf, 1, &akey);
00364
00365 while (HeapTupleIsValid(atup = systable_getnext(ascan)))
00366 {
00367 attForm = (Form_pg_attribute) GETSTRUCT(atup);
00368
00369 resetStringInfo(&audit_name);
00370 appendStringInfo(&audit_name, "%s.%s.%s",
00371 quote_identifier(nsp_name),
00372 quote_identifier(NameStr(classForm->relname)),
00373 quote_identifier(NameStr(attForm->attname)));
00374
00375 ccontext = sepgsql_compute_create(scontext,
00376 rcontext,
00377 SEPG_CLASS_DB_COLUMN,
00378 NameStr(attForm->attname));
00379
00380
00381
00382
00383 sepgsql_avc_check_perms_label(ccontext,
00384 SEPG_CLASS_DB_COLUMN,
00385 SEPG_DB_COLUMN__CREATE,
00386 audit_name.data,
00387 true);
00388
00389 object.classId = RelationRelationId;
00390 object.objectId = relOid;
00391 object.objectSubId = attForm->attnum;
00392 SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, ccontext);
00393
00394 pfree(ccontext);
00395 }
00396 systable_endscan(ascan);
00397 heap_close(arel, AccessShareLock);
00398 }
00399 pfree(rcontext);
00400
00401 out:
00402 systable_endscan(sscan);
00403 heap_close(rel, AccessShareLock);
00404 }
00405
00406
00407
00408
00409
00410
00411 void
00412 sepgsql_relation_drop(Oid relOid)
00413 {
00414 ObjectAddress object;
00415 char *audit_name;
00416 uint16_t tclass;
00417 char relkind;
00418
00419 relkind = get_rel_relkind(relOid);
00420 switch (relkind)
00421 {
00422 case RELKIND_RELATION:
00423 tclass = SEPG_CLASS_DB_TABLE;
00424 break;
00425 case RELKIND_SEQUENCE:
00426 tclass = SEPG_CLASS_DB_SEQUENCE;
00427 break;
00428 case RELKIND_VIEW:
00429 tclass = SEPG_CLASS_DB_VIEW;
00430 break;
00431 case RELKIND_INDEX:
00432
00433 if (get_rel_namespace(relOid) == PG_TOAST_NAMESPACE)
00434 return;
00435
00436 break;
00437 default:
00438
00439 return;
00440 }
00441
00442
00443
00444
00445 object.classId = NamespaceRelationId;
00446 object.objectId = get_rel_namespace(relOid);
00447 object.objectSubId = 0;
00448 audit_name = getObjectIdentity(&object);
00449
00450 sepgsql_avc_check_perms(&object,
00451 SEPG_CLASS_DB_SCHEMA,
00452 SEPG_DB_SCHEMA__REMOVE_NAME,
00453 audit_name,
00454 true);
00455 pfree(audit_name);
00456
00457
00458 if (relkind == RELKIND_INDEX)
00459 {
00460 sepgsql_index_modify(relOid);
00461 return;
00462 }
00463
00464
00465
00466
00467 object.classId = RelationRelationId;
00468 object.objectId = relOid;
00469 object.objectSubId = 0;
00470 audit_name = getObjectIdentity(&object);
00471
00472 sepgsql_avc_check_perms(&object,
00473 tclass,
00474 SEPG_DB_TABLE__DROP,
00475 audit_name,
00476 true);
00477 pfree(audit_name);
00478
00479
00480
00481
00482 if (relkind == RELKIND_RELATION)
00483 {
00484 Form_pg_attribute attForm;
00485 CatCList *attrList;
00486 HeapTuple atttup;
00487 int i;
00488
00489 attrList = SearchSysCacheList1(ATTNUM, ObjectIdGetDatum(relOid));
00490 for (i = 0; i < attrList->n_members; i++)
00491 {
00492 atttup = &attrList->members[i]->tuple;
00493 attForm = (Form_pg_attribute) GETSTRUCT(atttup);
00494
00495 if (attForm->attisdropped)
00496 continue;
00497
00498 object.classId = RelationRelationId;
00499 object.objectId = relOid;
00500 object.objectSubId = attForm->attnum;
00501 audit_name = getObjectIdentity(&object);
00502
00503 sepgsql_avc_check_perms(&object,
00504 SEPG_CLASS_DB_COLUMN,
00505 SEPG_DB_COLUMN__DROP,
00506 audit_name,
00507 true);
00508 pfree(audit_name);
00509 }
00510 ReleaseCatCacheList(attrList);
00511 }
00512 }
00513
00514
00515
00516
00517
00518
00519 void
00520 sepgsql_relation_relabel(Oid relOid, const char *seclabel)
00521 {
00522 ObjectAddress object;
00523 char *audit_name;
00524 char relkind;
00525 uint16_t tclass = 0;
00526
00527 relkind = get_rel_relkind(relOid);
00528 if (relkind == RELKIND_RELATION)
00529 tclass = SEPG_CLASS_DB_TABLE;
00530 else if (relkind == RELKIND_SEQUENCE)
00531 tclass = SEPG_CLASS_DB_SEQUENCE;
00532 else if (relkind == RELKIND_VIEW)
00533 tclass = SEPG_CLASS_DB_VIEW;
00534 else
00535 ereport(ERROR,
00536 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
00537 errmsg("cannot set security labels on relations except "
00538 "for tables, sequences or views")));
00539
00540 object.classId = RelationRelationId;
00541 object.objectId = relOid;
00542 object.objectSubId = 0;
00543 audit_name = getObjectIdentity(&object);
00544
00545
00546
00547
00548 sepgsql_avc_check_perms(&object,
00549 tclass,
00550 SEPG_DB_TABLE__SETATTR |
00551 SEPG_DB_TABLE__RELABELFROM,
00552 audit_name,
00553 true);
00554
00555
00556
00557
00558 sepgsql_avc_check_perms_label(seclabel,
00559 tclass,
00560 SEPG_DB_TABLE__RELABELTO,
00561 audit_name,
00562 true);
00563 pfree(audit_name);
00564 }
00565
00566
00567
00568
00569
00570
00571 void
00572 sepgsql_relation_setattr(Oid relOid)
00573 {
00574 Relation rel;
00575 ScanKeyData skey;
00576 SysScanDesc sscan;
00577 HeapTuple oldtup;
00578 HeapTuple newtup;
00579 Form_pg_class oldform;
00580 Form_pg_class newform;
00581 ObjectAddress object;
00582 char *audit_name;
00583 uint16_t tclass;
00584
00585 switch (get_rel_relkind(relOid))
00586 {
00587 case RELKIND_RELATION:
00588 tclass = SEPG_CLASS_DB_TABLE;
00589 break;
00590 case RELKIND_SEQUENCE:
00591 tclass = SEPG_CLASS_DB_SEQUENCE;
00592 break;
00593 case RELKIND_VIEW:
00594 tclass = SEPG_CLASS_DB_VIEW;
00595 break;
00596 case RELKIND_INDEX:
00597
00598 sepgsql_index_modify(relOid);
00599 return;
00600 default:
00601
00602 return;
00603 }
00604
00605
00606
00607
00608 rel = heap_open(RelationRelationId, AccessShareLock);
00609
00610 ScanKeyInit(&skey,
00611 ObjectIdAttributeNumber,
00612 BTEqualStrategyNumber, F_OIDEQ,
00613 ObjectIdGetDatum(relOid));
00614
00615 sscan = systable_beginscan(rel, ClassOidIndexId, true,
00616 SnapshotSelf, 1, &skey);
00617
00618 newtup = systable_getnext(sscan);
00619 if (!HeapTupleIsValid(newtup))
00620 elog(ERROR, "catalog lookup failed for relation %u", relOid);
00621 newform = (Form_pg_class) GETSTRUCT(newtup);
00622
00623
00624
00625
00626 oldtup = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid));
00627 if (!HeapTupleIsValid(oldtup))
00628 elog(ERROR, "cache lookup failed for relation %u", relOid);
00629 oldform = (Form_pg_class) GETSTRUCT(oldtup);
00630
00631
00632
00633
00634 if (newform->relnamespace != oldform->relnamespace)
00635 {
00636 sepgsql_schema_remove_name(oldform->relnamespace);
00637 sepgsql_schema_add_name(newform->relnamespace);
00638 }
00639 if (strcmp(NameStr(newform->relname), NameStr(oldform->relname)) != 0)
00640 sepgsql_schema_rename(oldform->relnamespace);
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650 object.classId = RelationRelationId;
00651 object.objectId = relOid;
00652 object.objectSubId = 0;
00653 audit_name = getObjectIdentity(&object);
00654
00655 sepgsql_avc_check_perms(&object,
00656 tclass,
00657 SEPG_DB_TABLE__SETATTR,
00658 audit_name,
00659 true);
00660 pfree(audit_name);
00661
00662 ReleaseSysCache(oldtup);
00663 systable_endscan(sscan);
00664 heap_close(rel, AccessShareLock);
00665 }
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676 static void
00677 sepgsql_relation_setattr_extra(Relation catalog,
00678 Oid catindex_id,
00679 Oid extra_oid,
00680 AttrNumber anum_relation_id,
00681 AttrNumber anum_extra_id)
00682 {
00683 ScanKeyData skey;
00684 SysScanDesc sscan;
00685 HeapTuple tuple;
00686 Datum datum;
00687 bool isnull;
00688
00689 ScanKeyInit(&skey, anum_extra_id,
00690 BTEqualStrategyNumber, F_OIDEQ,
00691 ObjectIdGetDatum(extra_oid));
00692
00693 sscan = systable_beginscan(catalog, catindex_id, true,
00694 SnapshotSelf, 1, &skey);
00695 tuple = systable_getnext(sscan);
00696 if (!HeapTupleIsValid(tuple))
00697 elog(ERROR, "catalog lookup failed for object %u in catalog \"%s\"",
00698 extra_oid, RelationGetRelationName(catalog));
00699
00700 datum = heap_getattr(tuple, anum_relation_id,
00701 RelationGetDescr(catalog), &isnull);
00702 Assert(!isnull);
00703
00704 sepgsql_relation_setattr(DatumGetObjectId(datum));
00705
00706 systable_endscan(sscan);
00707 }
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717 static void
00718 sepgsql_index_modify(Oid indexOid)
00719 {
00720 Relation catalog = heap_open(IndexRelationId, AccessShareLock);
00721
00722
00723 sepgsql_relation_setattr_extra(catalog,
00724 IndexRelidIndexId,
00725 indexOid,
00726 Anum_pg_index_indrelid,
00727 Anum_pg_index_indexrelid);
00728 heap_close(catalog, AccessShareLock);
00729 }