Header And Logo

PostgreSQL
| The world's most advanced open source database.

seclabel.c

Go to the documentation of this file.
00001 /* -------------------------------------------------------------------------
00002  *
00003  * seclabel.c
00004  *    routines to support security label feature.
00005  *
00006  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00007  * Portions Copyright (c) 1994, Regents of the University of California
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 "catalog/catalog.h"
00017 #include "catalog/indexing.h"
00018 #include "catalog/pg_seclabel.h"
00019 #include "catalog/pg_shseclabel.h"
00020 #include "commands/seclabel.h"
00021 #include "miscadmin.h"
00022 #include "utils/builtins.h"
00023 #include "utils/fmgroids.h"
00024 #include "utils/memutils.h"
00025 #include "utils/rel.h"
00026 #include "utils/tqual.h"
00027 
00028 typedef struct
00029 {
00030     const char *provider_name;
00031     check_object_relabel_type hook;
00032 } LabelProvider;
00033 
00034 static List *label_provider_list = NIL;
00035 
00036 /*
00037  * ExecSecLabelStmt --
00038  *
00039  * Apply a security label to a database object.
00040  */
00041 Oid
00042 ExecSecLabelStmt(SecLabelStmt *stmt)
00043 {
00044     LabelProvider *provider = NULL;
00045     ObjectAddress address;
00046     Relation    relation;
00047     ListCell   *lc;
00048 
00049     /*
00050      * Find the named label provider, or if none specified, check whether
00051      * there's exactly one, and if so use it.
00052      */
00053     if (stmt->provider == NULL)
00054     {
00055         if (label_provider_list == NIL)
00056             ereport(ERROR,
00057                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00058                      errmsg("no security label providers have been loaded")));
00059         if (lnext(list_head(label_provider_list)) != NULL)
00060             ereport(ERROR,
00061                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00062                      errmsg("must specify provider when multiple security label providers have been loaded")));
00063         provider = (LabelProvider *) linitial(label_provider_list);
00064     }
00065     else
00066     {
00067         foreach(lc, label_provider_list)
00068         {
00069             LabelProvider *lp = lfirst(lc);
00070 
00071             if (strcmp(stmt->provider, lp->provider_name) == 0)
00072             {
00073                 provider = lp;
00074                 break;
00075             }
00076         }
00077         if (provider == NULL)
00078             ereport(ERROR,
00079                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00080                      errmsg("security label provider \"%s\" is not loaded",
00081                             stmt->provider)));
00082     }
00083 
00084     /*
00085      * Translate the parser representation which identifies this object into
00086      * an ObjectAddress. get_object_address() will throw an error if the
00087      * object does not exist, and will also acquire a lock on the target to
00088      * guard against concurrent modifications.
00089      */
00090     address = get_object_address(stmt->objtype, stmt->objname, stmt->objargs,
00091                                  &relation, ShareUpdateExclusiveLock, false);
00092 
00093     /* Require ownership of the target object. */
00094     check_object_ownership(GetUserId(), stmt->objtype, address,
00095                            stmt->objname, stmt->objargs, relation);
00096 
00097     /* Perform other integrity checks as needed. */
00098     switch (stmt->objtype)
00099     {
00100         case OBJECT_COLUMN:
00101 
00102             /*
00103              * Allow security labels only on columns of tables, views,
00104              * materialized views, composite types, and foreign tables (which
00105              * are the only relkinds for which pg_dump will dump labels).
00106              */
00107             if (relation->rd_rel->relkind != RELKIND_RELATION &&
00108                 relation->rd_rel->relkind != RELKIND_VIEW &&
00109                 relation->rd_rel->relkind != RELKIND_MATVIEW &&
00110                 relation->rd_rel->relkind != RELKIND_COMPOSITE_TYPE &&
00111                 relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE)
00112                 ereport(ERROR,
00113                         (errcode(ERRCODE_WRONG_OBJECT_TYPE),
00114                          errmsg("\"%s\" is not a table, view, composite type, or foreign table",
00115                                 RelationGetRelationName(relation))));
00116             break;
00117         default:
00118             break;
00119     }
00120 
00121     /* Provider gets control here, may throw ERROR to veto new label. */
00122     (*provider->hook) (&address, stmt->label);
00123 
00124     /* Apply new label. */
00125     SetSecurityLabel(&address, provider->provider_name, stmt->label);
00126 
00127     /*
00128      * If get_object_address() opened the relation for us, we close it to keep
00129      * the reference count correct - but we retain any locks acquired by
00130      * get_object_address() until commit time, to guard against concurrent
00131      * activity.
00132      */
00133     if (relation != NULL)
00134         relation_close(relation, NoLock);
00135 
00136     return address.objectId;
00137 }
00138 
00139 /*
00140  * GetSharedSecurityLabel returns the security label for a shared object for
00141  * a given provider, or NULL if there is no such label.
00142  */
00143 static char *
00144 GetSharedSecurityLabel(const ObjectAddress *object, const char *provider)
00145 {
00146     Relation    pg_shseclabel;
00147     ScanKeyData keys[3];
00148     SysScanDesc scan;
00149     HeapTuple   tuple;
00150     Datum       datum;
00151     bool        isnull;
00152     char       *seclabel = NULL;
00153 
00154     ScanKeyInit(&keys[0],
00155                 Anum_pg_shseclabel_objoid,
00156                 BTEqualStrategyNumber, F_OIDEQ,
00157                 ObjectIdGetDatum(object->objectId));
00158     ScanKeyInit(&keys[1],
00159                 Anum_pg_shseclabel_classoid,
00160                 BTEqualStrategyNumber, F_OIDEQ,
00161                 ObjectIdGetDatum(object->classId));
00162     ScanKeyInit(&keys[2],
00163                 Anum_pg_shseclabel_provider,
00164                 BTEqualStrategyNumber, F_TEXTEQ,
00165                 CStringGetTextDatum(provider));
00166 
00167     pg_shseclabel = heap_open(SharedSecLabelRelationId, AccessShareLock);
00168 
00169     scan = systable_beginscan(pg_shseclabel, SharedSecLabelObjectIndexId, true,
00170                               SnapshotNow, 3, keys);
00171 
00172     tuple = systable_getnext(scan);
00173     if (HeapTupleIsValid(tuple))
00174     {
00175         datum = heap_getattr(tuple, Anum_pg_shseclabel_label,
00176                              RelationGetDescr(pg_shseclabel), &isnull);
00177         if (!isnull)
00178             seclabel = TextDatumGetCString(datum);
00179     }
00180     systable_endscan(scan);
00181 
00182     heap_close(pg_shseclabel, AccessShareLock);
00183 
00184     return seclabel;
00185 }
00186 
00187 /*
00188  * GetSecurityLabel returns the security label for a shared or database object
00189  * for a given provider, or NULL if there is no such label.
00190  */
00191 char *
00192 GetSecurityLabel(const ObjectAddress *object, const char *provider)
00193 {
00194     Relation    pg_seclabel;
00195     ScanKeyData keys[4];
00196     SysScanDesc scan;
00197     HeapTuple   tuple;
00198     Datum       datum;
00199     bool        isnull;
00200     char       *seclabel = NULL;
00201 
00202     /* Shared objects have their own security label catalog. */
00203     if (IsSharedRelation(object->classId))
00204         return GetSharedSecurityLabel(object, provider);
00205 
00206     /* Must be an unshared object, so examine pg_seclabel. */
00207     ScanKeyInit(&keys[0],
00208                 Anum_pg_seclabel_objoid,
00209                 BTEqualStrategyNumber, F_OIDEQ,
00210                 ObjectIdGetDatum(object->objectId));
00211     ScanKeyInit(&keys[1],
00212                 Anum_pg_seclabel_classoid,
00213                 BTEqualStrategyNumber, F_OIDEQ,
00214                 ObjectIdGetDatum(object->classId));
00215     ScanKeyInit(&keys[2],
00216                 Anum_pg_seclabel_objsubid,
00217                 BTEqualStrategyNumber, F_INT4EQ,
00218                 Int32GetDatum(object->objectSubId));
00219     ScanKeyInit(&keys[3],
00220                 Anum_pg_seclabel_provider,
00221                 BTEqualStrategyNumber, F_TEXTEQ,
00222                 CStringGetTextDatum(provider));
00223 
00224     pg_seclabel = heap_open(SecLabelRelationId, AccessShareLock);
00225 
00226     scan = systable_beginscan(pg_seclabel, SecLabelObjectIndexId, true,
00227                               SnapshotNow, 4, keys);
00228 
00229     tuple = systable_getnext(scan);
00230     if (HeapTupleIsValid(tuple))
00231     {
00232         datum = heap_getattr(tuple, Anum_pg_seclabel_label,
00233                              RelationGetDescr(pg_seclabel), &isnull);
00234         if (!isnull)
00235             seclabel = TextDatumGetCString(datum);
00236     }
00237     systable_endscan(scan);
00238 
00239     heap_close(pg_seclabel, AccessShareLock);
00240 
00241     return seclabel;
00242 }
00243 
00244 /*
00245  * SetSharedSecurityLabel is a helper function of SetSecurityLabel to
00246  * handle shared database objects.
00247  */
00248 static void
00249 SetSharedSecurityLabel(const ObjectAddress *object,
00250                        const char *provider, const char *label)
00251 {
00252     Relation    pg_shseclabel;
00253     ScanKeyData keys[4];
00254     SysScanDesc scan;
00255     HeapTuple   oldtup;
00256     HeapTuple   newtup = NULL;
00257     Datum       values[Natts_pg_shseclabel];
00258     bool        nulls[Natts_pg_shseclabel];
00259     bool        replaces[Natts_pg_shseclabel];
00260 
00261     /* Prepare to form or update a tuple, if necessary. */
00262     memset(nulls, false, sizeof(nulls));
00263     memset(replaces, false, sizeof(replaces));
00264     values[Anum_pg_shseclabel_objoid - 1] = ObjectIdGetDatum(object->objectId);
00265     values[Anum_pg_shseclabel_classoid - 1] = ObjectIdGetDatum(object->classId);
00266     values[Anum_pg_shseclabel_provider - 1] = CStringGetTextDatum(provider);
00267     if (label != NULL)
00268         values[Anum_pg_shseclabel_label - 1] = CStringGetTextDatum(label);
00269 
00270     /* Use the index to search for a matching old tuple */
00271     ScanKeyInit(&keys[0],
00272                 Anum_pg_shseclabel_objoid,
00273                 BTEqualStrategyNumber, F_OIDEQ,
00274                 ObjectIdGetDatum(object->objectId));
00275     ScanKeyInit(&keys[1],
00276                 Anum_pg_shseclabel_classoid,
00277                 BTEqualStrategyNumber, F_OIDEQ,
00278                 ObjectIdGetDatum(object->classId));
00279     ScanKeyInit(&keys[2],
00280                 Anum_pg_shseclabel_provider,
00281                 BTEqualStrategyNumber, F_TEXTEQ,
00282                 CStringGetTextDatum(provider));
00283 
00284     pg_shseclabel = heap_open(SharedSecLabelRelationId, RowExclusiveLock);
00285 
00286     scan = systable_beginscan(pg_shseclabel, SharedSecLabelObjectIndexId, true,
00287                               SnapshotNow, 3, keys);
00288 
00289     oldtup = systable_getnext(scan);
00290     if (HeapTupleIsValid(oldtup))
00291     {
00292         if (label == NULL)
00293             simple_heap_delete(pg_shseclabel, &oldtup->t_self);
00294         else
00295         {
00296             replaces[Anum_pg_shseclabel_label - 1] = true;
00297             newtup = heap_modify_tuple(oldtup, RelationGetDescr(pg_shseclabel),
00298                                        values, nulls, replaces);
00299             simple_heap_update(pg_shseclabel, &oldtup->t_self, newtup);
00300         }
00301     }
00302     systable_endscan(scan);
00303 
00304     /* If we didn't find an old tuple, insert a new one */
00305     if (newtup == NULL && label != NULL)
00306     {
00307         newtup = heap_form_tuple(RelationGetDescr(pg_shseclabel),
00308                                  values, nulls);
00309         simple_heap_insert(pg_shseclabel, newtup);
00310     }
00311 
00312     /* Update indexes, if necessary */
00313     if (newtup != NULL)
00314     {
00315         CatalogUpdateIndexes(pg_shseclabel, newtup);
00316         heap_freetuple(newtup);
00317     }
00318 
00319     heap_close(pg_shseclabel, RowExclusiveLock);
00320 }
00321 
00322 /*
00323  * SetSecurityLabel attempts to set the security label for the specified
00324  * provider on the specified object to the given value.  NULL means that any
00325  * any existing label should be deleted.
00326  */
00327 void
00328 SetSecurityLabel(const ObjectAddress *object,
00329                  const char *provider, const char *label)
00330 {
00331     Relation    pg_seclabel;
00332     ScanKeyData keys[4];
00333     SysScanDesc scan;
00334     HeapTuple   oldtup;
00335     HeapTuple   newtup = NULL;
00336     Datum       values[Natts_pg_seclabel];
00337     bool        nulls[Natts_pg_seclabel];
00338     bool        replaces[Natts_pg_seclabel];
00339 
00340     /* Shared objects have their own security label catalog. */
00341     if (IsSharedRelation(object->classId))
00342     {
00343         SetSharedSecurityLabel(object, provider, label);
00344         return;
00345     }
00346 
00347     /* Prepare to form or update a tuple, if necessary. */
00348     memset(nulls, false, sizeof(nulls));
00349     memset(replaces, false, sizeof(replaces));
00350     values[Anum_pg_seclabel_objoid - 1] = ObjectIdGetDatum(object->objectId);
00351     values[Anum_pg_seclabel_classoid - 1] = ObjectIdGetDatum(object->classId);
00352     values[Anum_pg_seclabel_objsubid - 1] = Int32GetDatum(object->objectSubId);
00353     values[Anum_pg_seclabel_provider - 1] = CStringGetTextDatum(provider);
00354     if (label != NULL)
00355         values[Anum_pg_seclabel_label - 1] = CStringGetTextDatum(label);
00356 
00357     /* Use the index to search for a matching old tuple */
00358     ScanKeyInit(&keys[0],
00359                 Anum_pg_seclabel_objoid,
00360                 BTEqualStrategyNumber, F_OIDEQ,
00361                 ObjectIdGetDatum(object->objectId));
00362     ScanKeyInit(&keys[1],
00363                 Anum_pg_seclabel_classoid,
00364                 BTEqualStrategyNumber, F_OIDEQ,
00365                 ObjectIdGetDatum(object->classId));
00366     ScanKeyInit(&keys[2],
00367                 Anum_pg_seclabel_objsubid,
00368                 BTEqualStrategyNumber, F_INT4EQ,
00369                 Int32GetDatum(object->objectSubId));
00370     ScanKeyInit(&keys[3],
00371                 Anum_pg_seclabel_provider,
00372                 BTEqualStrategyNumber, F_TEXTEQ,
00373                 CStringGetTextDatum(provider));
00374 
00375     pg_seclabel = heap_open(SecLabelRelationId, RowExclusiveLock);
00376 
00377     scan = systable_beginscan(pg_seclabel, SecLabelObjectIndexId, true,
00378                               SnapshotNow, 4, keys);
00379 
00380     oldtup = systable_getnext(scan);
00381     if (HeapTupleIsValid(oldtup))
00382     {
00383         if (label == NULL)
00384             simple_heap_delete(pg_seclabel, &oldtup->t_self);
00385         else
00386         {
00387             replaces[Anum_pg_seclabel_label - 1] = true;
00388             newtup = heap_modify_tuple(oldtup, RelationGetDescr(pg_seclabel),
00389                                        values, nulls, replaces);
00390             simple_heap_update(pg_seclabel, &oldtup->t_self, newtup);
00391         }
00392     }
00393     systable_endscan(scan);
00394 
00395     /* If we didn't find an old tuple, insert a new one */
00396     if (newtup == NULL && label != NULL)
00397     {
00398         newtup = heap_form_tuple(RelationGetDescr(pg_seclabel),
00399                                  values, nulls);
00400         simple_heap_insert(pg_seclabel, newtup);
00401     }
00402 
00403     /* Update indexes, if necessary */
00404     if (newtup != NULL)
00405     {
00406         CatalogUpdateIndexes(pg_seclabel, newtup);
00407         heap_freetuple(newtup);
00408     }
00409 
00410     heap_close(pg_seclabel, RowExclusiveLock);
00411 }
00412 
00413 /*
00414  * DeleteSharedSecurityLabel is a helper function of DeleteSecurityLabel
00415  * to handle shared database objects.
00416  */
00417 void
00418 DeleteSharedSecurityLabel(Oid objectId, Oid classId)
00419 {
00420     Relation    pg_shseclabel;
00421     ScanKeyData skey[2];
00422     SysScanDesc scan;
00423     HeapTuple   oldtup;
00424 
00425     ScanKeyInit(&skey[0],
00426                 Anum_pg_shseclabel_objoid,
00427                 BTEqualStrategyNumber, F_OIDEQ,
00428                 ObjectIdGetDatum(objectId));
00429     ScanKeyInit(&skey[1],
00430                 Anum_pg_shseclabel_classoid,
00431                 BTEqualStrategyNumber, F_OIDEQ,
00432                 ObjectIdGetDatum(classId));
00433 
00434     pg_shseclabel = heap_open(SharedSecLabelRelationId, RowExclusiveLock);
00435 
00436     scan = systable_beginscan(pg_shseclabel, SharedSecLabelObjectIndexId, true,
00437                               SnapshotNow, 2, skey);
00438     while (HeapTupleIsValid(oldtup = systable_getnext(scan)))
00439         simple_heap_delete(pg_shseclabel, &oldtup->t_self);
00440     systable_endscan(scan);
00441 
00442     heap_close(pg_shseclabel, RowExclusiveLock);
00443 }
00444 
00445 /*
00446  * DeleteSecurityLabel removes all security labels for an object (and any
00447  * sub-objects, if applicable).
00448  */
00449 void
00450 DeleteSecurityLabel(const ObjectAddress *object)
00451 {
00452     Relation    pg_seclabel;
00453     ScanKeyData skey[3];
00454     SysScanDesc scan;
00455     HeapTuple   oldtup;
00456     int         nkeys;
00457 
00458     /* Shared objects have their own security label catalog. */
00459     if (IsSharedRelation(object->classId))
00460     {
00461         Assert(object->objectSubId == 0);
00462         DeleteSharedSecurityLabel(object->objectId, object->classId);
00463         return;
00464     }
00465 
00466     ScanKeyInit(&skey[0],
00467                 Anum_pg_seclabel_objoid,
00468                 BTEqualStrategyNumber, F_OIDEQ,
00469                 ObjectIdGetDatum(object->objectId));
00470     ScanKeyInit(&skey[1],
00471                 Anum_pg_seclabel_classoid,
00472                 BTEqualStrategyNumber, F_OIDEQ,
00473                 ObjectIdGetDatum(object->classId));
00474     if (object->objectSubId != 0)
00475     {
00476         ScanKeyInit(&skey[2],
00477                     Anum_pg_seclabel_objsubid,
00478                     BTEqualStrategyNumber, F_INT4EQ,
00479                     Int32GetDatum(object->objectSubId));
00480         nkeys = 3;
00481     }
00482     else
00483         nkeys = 2;
00484 
00485     pg_seclabel = heap_open(SecLabelRelationId, RowExclusiveLock);
00486 
00487     scan = systable_beginscan(pg_seclabel, SecLabelObjectIndexId, true,
00488                               SnapshotNow, nkeys, skey);
00489     while (HeapTupleIsValid(oldtup = systable_getnext(scan)))
00490         simple_heap_delete(pg_seclabel, &oldtup->t_self);
00491     systable_endscan(scan);
00492 
00493     heap_close(pg_seclabel, RowExclusiveLock);
00494 }
00495 
00496 void
00497 register_label_provider(const char *provider_name, check_object_relabel_type hook)
00498 {
00499     LabelProvider *provider;
00500     MemoryContext oldcxt;
00501 
00502     oldcxt = MemoryContextSwitchTo(TopMemoryContext);
00503     provider = palloc(sizeof(LabelProvider));
00504     provider->provider_name = pstrdup(provider_name);
00505     provider->hook = hook;
00506     label_provider_list = lappend(label_provider_list, provider);
00507     MemoryContextSwitchTo(oldcxt);
00508 }