1 /* -------------------------------------------------------------------------
4 * routines to support security label feature.
6 * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
9 * -------------------------------------------------------------------------
13 #include "access/genam.h"
14 #include "access/heapam.h"
15 #include "catalog/catalog.h"
16 #include "catalog/indexing.h"
17 #include "catalog/namespace.h"
18 #include "catalog/pg_seclabel.h"
19 #include "commands/seclabel.h"
20 #include "miscadmin.h"
21 #include "utils/acl.h"
22 #include "utils/builtins.h"
23 #include "utils/fmgroids.h"
24 #include "utils/lsyscache.h"
25 #include "utils/memutils.h"
26 #include "utils/rel.h"
27 #include "utils/tqual.h"
31 const char *provider_name;
32 check_object_relabel_type hook;
35 static List *label_provider_list = NIL;
40 * Apply a security label to a database object.
43 ExecSecLabelStmt(SecLabelStmt *stmt)
45 LabelProvider *provider = NULL;
46 ObjectAddress address;
51 * Find the named label provider, or if none specified, check whether
52 * there's exactly one, and if so use it.
54 if (stmt->provider == NULL)
56 if (label_provider_list == NIL)
58 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
59 errmsg("no security label providers have been loaded")));
60 if (lnext(list_head(label_provider_list)) != NULL)
62 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
63 errmsg("must specify provider when multiple security label providers have been loaded")));
64 provider = (LabelProvider *) linitial(label_provider_list);
68 foreach(lc, label_provider_list)
70 LabelProvider *lp = lfirst(lc);
72 if (strcmp(stmt->provider, lp->provider_name) == 0)
80 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
81 errmsg("security label provider \"%s\" is not loaded",
86 * Translate the parser representation which identifies this object into
87 * an ObjectAddress. get_object_address() will throw an error if the
88 * object does not exist, and will also acquire a lock on the target to
89 * guard against concurrent modifications.
91 address = get_object_address(stmt->objtype, stmt->objname, stmt->objargs,
92 &relation, ShareUpdateExclusiveLock, false);
94 /* Require ownership of the target object. */
95 check_object_ownership(GetUserId(), stmt->objtype, address,
96 stmt->objname, stmt->objargs, relation);
98 /* Perform other integrity checks as needed. */
99 switch (stmt->objtype)
104 * Allow security labels only on columns of tables, views,
105 * composite types, and foreign tables (which are the only
106 * relkinds for which pg_dump will dump labels).
108 if (relation->rd_rel->relkind != RELKIND_RELATION &&
109 relation->rd_rel->relkind != RELKIND_VIEW &&
110 relation->rd_rel->relkind != RELKIND_COMPOSITE_TYPE &&
111 relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE)
113 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
114 errmsg("\"%s\" is not a table, view, composite type, or foreign table",
115 RelationGetRelationName(relation))));
121 /* Provider gets control here, may throw ERROR to veto new label. */
122 (*provider->hook) (&address, stmt->label);
124 /* Apply new label. */
125 SetSecurityLabel(&address, provider->provider_name, stmt->label);
128 * If get_object_address() opened the relation for us, we close it to keep
129 * the reference count correct - but we retain any locks acquired by
130 * get_object_address() until commit time, to guard against concurrent
133 if (relation != NULL)
134 relation_close(relation, NoLock);
138 * GetSecurityLabel returns the security label for a database object for a
139 * given provider, or NULL if there is no such label.
142 GetSecurityLabel(const ObjectAddress *object, const char *provider)
144 Relation pg_seclabel;
150 char *seclabel = NULL;
152 Assert(!IsSharedRelation(object->classId));
154 ScanKeyInit(&keys[0],
155 Anum_pg_seclabel_objoid,
156 BTEqualStrategyNumber, F_OIDEQ,
157 ObjectIdGetDatum(object->objectId));
158 ScanKeyInit(&keys[1],
159 Anum_pg_seclabel_classoid,
160 BTEqualStrategyNumber, F_OIDEQ,
161 ObjectIdGetDatum(object->classId));
162 ScanKeyInit(&keys[2],
163 Anum_pg_seclabel_objsubid,
164 BTEqualStrategyNumber, F_INT4EQ,
165 Int32GetDatum(object->objectSubId));
166 ScanKeyInit(&keys[3],
167 Anum_pg_seclabel_provider,
168 BTEqualStrategyNumber, F_TEXTEQ,
169 CStringGetTextDatum(provider));
171 pg_seclabel = heap_open(SecLabelRelationId, AccessShareLock);
173 scan = systable_beginscan(pg_seclabel, SecLabelObjectIndexId, true,
174 SnapshotNow, 4, keys);
176 tuple = systable_getnext(scan);
177 if (HeapTupleIsValid(tuple))
179 datum = heap_getattr(tuple, Anum_pg_seclabel_label,
180 RelationGetDescr(pg_seclabel), &isnull);
182 seclabel = TextDatumGetCString(datum);
184 systable_endscan(scan);
186 heap_close(pg_seclabel, AccessShareLock);
192 * SetSecurityLabel attempts to set the security label for the specified
193 * provider on the specified object to the given value. NULL means that any
194 * any existing label should be deleted.
197 SetSecurityLabel(const ObjectAddress *object,
198 const char *provider, const char *label)
200 Relation pg_seclabel;
204 HeapTuple newtup = NULL;
205 Datum values[Natts_pg_seclabel];
206 bool nulls[Natts_pg_seclabel];
207 bool replaces[Natts_pg_seclabel];
209 /* Security labels on shared objects are not supported. */
210 Assert(!IsSharedRelation(object->classId));
212 /* Prepare to form or update a tuple, if necessary. */
213 memset(nulls, false, sizeof(nulls));
214 memset(replaces, false, sizeof(replaces));
215 values[Anum_pg_seclabel_objoid - 1] = ObjectIdGetDatum(object->objectId);
216 values[Anum_pg_seclabel_classoid - 1] = ObjectIdGetDatum(object->classId);
217 values[Anum_pg_seclabel_objsubid - 1] = Int32GetDatum(object->objectSubId);
218 values[Anum_pg_seclabel_provider - 1] = CStringGetTextDatum(provider);
220 values[Anum_pg_seclabel_label - 1] = CStringGetTextDatum(label);
222 /* Use the index to search for a matching old tuple */
223 ScanKeyInit(&keys[0],
224 Anum_pg_seclabel_objoid,
225 BTEqualStrategyNumber, F_OIDEQ,
226 ObjectIdGetDatum(object->objectId));
227 ScanKeyInit(&keys[1],
228 Anum_pg_seclabel_classoid,
229 BTEqualStrategyNumber, F_OIDEQ,
230 ObjectIdGetDatum(object->classId));
231 ScanKeyInit(&keys[2],
232 Anum_pg_seclabel_objsubid,
233 BTEqualStrategyNumber, F_INT4EQ,
234 Int32GetDatum(object->objectSubId));
235 ScanKeyInit(&keys[3],
236 Anum_pg_seclabel_provider,
237 BTEqualStrategyNumber, F_TEXTEQ,
238 CStringGetTextDatum(provider));
240 pg_seclabel = heap_open(SecLabelRelationId, RowExclusiveLock);
242 scan = systable_beginscan(pg_seclabel, SecLabelObjectIndexId, true,
243 SnapshotNow, 4, keys);
245 oldtup = systable_getnext(scan);
246 if (HeapTupleIsValid(oldtup))
249 simple_heap_delete(pg_seclabel, &oldtup->t_self);
252 replaces[Anum_pg_seclabel_label - 1] = true;
253 newtup = heap_modify_tuple(oldtup, RelationGetDescr(pg_seclabel),
254 values, nulls, replaces);
255 simple_heap_update(pg_seclabel, &oldtup->t_self, newtup);
258 systable_endscan(scan);
260 /* If we didn't find an old tuple, insert a new one */
261 if (newtup == NULL && label != NULL)
263 newtup = heap_form_tuple(RelationGetDescr(pg_seclabel),
265 simple_heap_insert(pg_seclabel, newtup);
268 /* Update indexes, if necessary */
271 CatalogUpdateIndexes(pg_seclabel, newtup);
272 heap_freetuple(newtup);
275 heap_close(pg_seclabel, RowExclusiveLock);
279 * DeleteSecurityLabel removes all security labels for an object (and any
280 * sub-objects, if applicable).
283 DeleteSecurityLabel(const ObjectAddress *object)
285 Relation pg_seclabel;
291 /* Security labels on shared objects are not supported. */
292 if (IsSharedRelation(object->classId))
295 ScanKeyInit(&skey[0],
296 Anum_pg_seclabel_objoid,
297 BTEqualStrategyNumber, F_OIDEQ,
298 ObjectIdGetDatum(object->objectId));
299 ScanKeyInit(&skey[1],
300 Anum_pg_seclabel_classoid,
301 BTEqualStrategyNumber, F_OIDEQ,
302 ObjectIdGetDatum(object->classId));
303 if (object->objectSubId != 0)
305 ScanKeyInit(&skey[2],
306 Anum_pg_seclabel_objsubid,
307 BTEqualStrategyNumber, F_INT4EQ,
308 Int32GetDatum(object->objectSubId));
314 pg_seclabel = heap_open(SecLabelRelationId, RowExclusiveLock);
316 scan = systable_beginscan(pg_seclabel, SecLabelObjectIndexId, true,
317 SnapshotNow, nkeys, skey);
318 while (HeapTupleIsValid(oldtup = systable_getnext(scan)))
319 simple_heap_delete(pg_seclabel, &oldtup->t_self);
320 systable_endscan(scan);
322 heap_close(pg_seclabel, RowExclusiveLock);
326 register_label_provider(const char *provider_name, check_object_relabel_type hook)
328 LabelProvider *provider;
329 MemoryContext oldcxt;
331 oldcxt = MemoryContextSwitchTo(TopMemoryContext);
332 provider = palloc(sizeof(LabelProvider));
333 provider->provider_name = pstrdup(provider_name);
334 provider->hook = hook;
335 label_provider_list = lappend(label_provider_list, provider);
336 MemoryContextSwitchTo(oldcxt);