PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
seclabel.c
Go to the documentation of this file.
1 /* -------------------------------------------------------------------------
2  *
3  * seclabel.c
4  * routines to support security label feature.
5  *
6  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
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 "catalog/catalog.h"
17 #include "catalog/indexing.h"
18 #include "catalog/pg_seclabel.h"
19 #include "catalog/pg_shseclabel.h"
20 #include "commands/seclabel.h"
21 #include "miscadmin.h"
22 #include "utils/builtins.h"
23 #include "utils/fmgroids.h"
24 #include "utils/memutils.h"
25 #include "utils/rel.h"
26 #include "utils/tqual.h"
27 
28 typedef struct
29 {
30  const char *provider_name;
33 
35 
36 /*
37  * ExecSecLabelStmt --
38  *
39  * Apply a security label to a database object.
40  *
41  * Returns the ObjectAddress of the object to which the policy was applied.
42  */
45 {
46  LabelProvider *provider = NULL;
47  ObjectAddress address;
48  Relation relation;
49  ListCell *lc;
50 
51  /*
52  * Find the named label provider, or if none specified, check whether
53  * there's exactly one, and if so use it.
54  */
55  if (stmt->provider == NULL)
56  {
57  if (label_provider_list == NIL)
58  ereport(ERROR,
59  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
60  errmsg("no security label providers have been loaded")));
61  if (lnext(list_head(label_provider_list)) != NULL)
62  ereport(ERROR,
63  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
64  errmsg("must specify provider when multiple security label providers have been loaded")));
65  provider = (LabelProvider *) linitial(label_provider_list);
66  }
67  else
68  {
69  foreach(lc, label_provider_list)
70  {
71  LabelProvider *lp = lfirst(lc);
72 
73  if (strcmp(stmt->provider, lp->provider_name) == 0)
74  {
75  provider = lp;
76  break;
77  }
78  }
79  if (provider == NULL)
80  ereport(ERROR,
81  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
82  errmsg("security label provider \"%s\" is not loaded",
83  stmt->provider)));
84  }
85 
86  /*
87  * Translate the parser representation which identifies this object into
88  * an ObjectAddress. get_object_address() will throw an error if the
89  * object does not exist, and will also acquire a lock on the target to
90  * guard against concurrent modifications.
91  */
92  address = get_object_address(stmt->objtype, stmt->object,
93  &relation, ShareUpdateExclusiveLock, false);
94 
95  /* Require ownership of the target object. */
96  check_object_ownership(GetUserId(), stmt->objtype, address,
97  stmt->object, relation);
98 
99  /* Perform other integrity checks as needed. */
100  switch (stmt->objtype)
101  {
102  case OBJECT_COLUMN:
103 
104  /*
105  * Allow security labels only on columns of tables, views,
106  * materialized views, composite types, and foreign tables (which
107  * are the only relkinds for which pg_dump will dump labels).
108  */
109  if (relation->rd_rel->relkind != RELKIND_RELATION &&
110  relation->rd_rel->relkind != RELKIND_VIEW &&
111  relation->rd_rel->relkind != RELKIND_MATVIEW &&
112  relation->rd_rel->relkind != RELKIND_COMPOSITE_TYPE &&
113  relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
114  relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
115  ereport(ERROR,
116  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
117  errmsg("\"%s\" is not a table, view, materialized view, composite type, or foreign table",
118  RelationGetRelationName(relation))));
119  break;
120  default:
121  break;
122  }
123 
124  /* Provider gets control here, may throw ERROR to veto new label. */
125  (*provider->hook) (&address, stmt->label);
126 
127  /* Apply new label. */
128  SetSecurityLabel(&address, provider->provider_name, stmt->label);
129 
130  /*
131  * If get_object_address() opened the relation for us, we close it to keep
132  * the reference count correct - but we retain any locks acquired by
133  * get_object_address() until commit time, to guard against concurrent
134  * activity.
135  */
136  if (relation != NULL)
137  relation_close(relation, NoLock);
138 
139  return address;
140 }
141 
142 /*
143  * GetSharedSecurityLabel returns the security label for a shared object for
144  * a given provider, or NULL if there is no such label.
145  */
146 static char *
147 GetSharedSecurityLabel(const ObjectAddress *object, const char *provider)
148 {
149  Relation pg_shseclabel;
150  ScanKeyData keys[3];
151  SysScanDesc scan;
152  HeapTuple tuple;
153  Datum datum;
154  bool isnull;
155  char *seclabel = NULL;
156 
157  ScanKeyInit(&keys[0],
159  BTEqualStrategyNumber, F_OIDEQ,
160  ObjectIdGetDatum(object->objectId));
161  ScanKeyInit(&keys[1],
163  BTEqualStrategyNumber, F_OIDEQ,
164  ObjectIdGetDatum(object->classId));
165  ScanKeyInit(&keys[2],
167  BTEqualStrategyNumber, F_TEXTEQ,
168  CStringGetTextDatum(provider));
169 
171 
172  scan = systable_beginscan(pg_shseclabel, SharedSecLabelObjectIndexId, true,
173  NULL, 3, keys);
174 
175  tuple = systable_getnext(scan);
176  if (HeapTupleIsValid(tuple))
177  {
178  datum = heap_getattr(tuple, Anum_pg_shseclabel_label,
179  RelationGetDescr(pg_shseclabel), &isnull);
180  if (!isnull)
181  seclabel = TextDatumGetCString(datum);
182  }
183  systable_endscan(scan);
184 
185  heap_close(pg_shseclabel, AccessShareLock);
186 
187  return seclabel;
188 }
189 
190 /*
191  * GetSecurityLabel returns the security label for a shared or database object
192  * for a given provider, or NULL if there is no such label.
193  */
194 char *
195 GetSecurityLabel(const ObjectAddress *object, const char *provider)
196 {
197  Relation pg_seclabel;
198  ScanKeyData keys[4];
199  SysScanDesc scan;
200  HeapTuple tuple;
201  Datum datum;
202  bool isnull;
203  char *seclabel = NULL;
204 
205  /* Shared objects have their own security label catalog. */
206  if (IsSharedRelation(object->classId))
207  return GetSharedSecurityLabel(object, provider);
208 
209  /* Must be an unshared object, so examine pg_seclabel. */
210  ScanKeyInit(&keys[0],
212  BTEqualStrategyNumber, F_OIDEQ,
213  ObjectIdGetDatum(object->objectId));
214  ScanKeyInit(&keys[1],
216  BTEqualStrategyNumber, F_OIDEQ,
217  ObjectIdGetDatum(object->classId));
218  ScanKeyInit(&keys[2],
220  BTEqualStrategyNumber, F_INT4EQ,
221  Int32GetDatum(object->objectSubId));
222  ScanKeyInit(&keys[3],
224  BTEqualStrategyNumber, F_TEXTEQ,
225  CStringGetTextDatum(provider));
226 
228 
229  scan = systable_beginscan(pg_seclabel, SecLabelObjectIndexId, true,
230  NULL, 4, keys);
231 
232  tuple = systable_getnext(scan);
233  if (HeapTupleIsValid(tuple))
234  {
235  datum = heap_getattr(tuple, Anum_pg_seclabel_label,
236  RelationGetDescr(pg_seclabel), &isnull);
237  if (!isnull)
238  seclabel = TextDatumGetCString(datum);
239  }
240  systable_endscan(scan);
241 
242  heap_close(pg_seclabel, AccessShareLock);
243 
244  return seclabel;
245 }
246 
247 /*
248  * SetSharedSecurityLabel is a helper function of SetSecurityLabel to
249  * handle shared database objects.
250  */
251 static void
253  const char *provider, const char *label)
254 {
255  Relation pg_shseclabel;
256  ScanKeyData keys[4];
257  SysScanDesc scan;
258  HeapTuple oldtup;
259  HeapTuple newtup = NULL;
261  bool nulls[Natts_pg_shseclabel];
262  bool replaces[Natts_pg_shseclabel];
263 
264  /* Prepare to form or update a tuple, if necessary. */
265  memset(nulls, false, sizeof(nulls));
266  memset(replaces, false, sizeof(replaces));
267  values[Anum_pg_shseclabel_objoid - 1] = ObjectIdGetDatum(object->objectId);
269  values[Anum_pg_shseclabel_provider - 1] = CStringGetTextDatum(provider);
270  if (label != NULL)
271  values[Anum_pg_shseclabel_label - 1] = CStringGetTextDatum(label);
272 
273  /* Use the index to search for a matching old tuple */
274  ScanKeyInit(&keys[0],
276  BTEqualStrategyNumber, F_OIDEQ,
277  ObjectIdGetDatum(object->objectId));
278  ScanKeyInit(&keys[1],
280  BTEqualStrategyNumber, F_OIDEQ,
281  ObjectIdGetDatum(object->classId));
282  ScanKeyInit(&keys[2],
284  BTEqualStrategyNumber, F_TEXTEQ,
285  CStringGetTextDatum(provider));
286 
288 
289  scan = systable_beginscan(pg_shseclabel, SharedSecLabelObjectIndexId, true,
290  NULL, 3, keys);
291 
292  oldtup = systable_getnext(scan);
293  if (HeapTupleIsValid(oldtup))
294  {
295  if (label == NULL)
296  CatalogTupleDelete(pg_shseclabel, &oldtup->t_self);
297  else
298  {
299  replaces[Anum_pg_shseclabel_label - 1] = true;
300  newtup = heap_modify_tuple(oldtup, RelationGetDescr(pg_shseclabel),
301  values, nulls, replaces);
302  CatalogTupleUpdate(pg_shseclabel, &oldtup->t_self, newtup);
303  }
304  }
305  systable_endscan(scan);
306 
307  /* If we didn't find an old tuple, insert a new one */
308  if (newtup == NULL && label != NULL)
309  {
310  newtup = heap_form_tuple(RelationGetDescr(pg_shseclabel),
311  values, nulls);
312  CatalogTupleInsert(pg_shseclabel, newtup);
313  }
314 
315  if (newtup != NULL)
316  heap_freetuple(newtup);
317 
318  heap_close(pg_shseclabel, RowExclusiveLock);
319 }
320 
321 /*
322  * SetSecurityLabel attempts to set the security label for the specified
323  * provider on the specified object to the given value. NULL means that any
324  * any existing label should be deleted.
325  */
326 void
328  const char *provider, const char *label)
329 {
330  Relation pg_seclabel;
331  ScanKeyData keys[4];
332  SysScanDesc scan;
333  HeapTuple oldtup;
334  HeapTuple newtup = NULL;
336  bool nulls[Natts_pg_seclabel];
337  bool replaces[Natts_pg_seclabel];
338 
339  /* Shared objects have their own security label catalog. */
340  if (IsSharedRelation(object->classId))
341  {
342  SetSharedSecurityLabel(object, provider, label);
343  return;
344  }
345 
346  /* Prepare to form or update a tuple, if necessary. */
347  memset(nulls, false, sizeof(nulls));
348  memset(replaces, false, sizeof(replaces));
349  values[Anum_pg_seclabel_objoid - 1] = ObjectIdGetDatum(object->objectId);
350  values[Anum_pg_seclabel_classoid - 1] = ObjectIdGetDatum(object->classId);
351  values[Anum_pg_seclabel_objsubid - 1] = Int32GetDatum(object->objectSubId);
352  values[Anum_pg_seclabel_provider - 1] = CStringGetTextDatum(provider);
353  if (label != NULL)
354  values[Anum_pg_seclabel_label - 1] = CStringGetTextDatum(label);
355 
356  /* Use the index to search for a matching old tuple */
357  ScanKeyInit(&keys[0],
359  BTEqualStrategyNumber, F_OIDEQ,
360  ObjectIdGetDatum(object->objectId));
361  ScanKeyInit(&keys[1],
363  BTEqualStrategyNumber, F_OIDEQ,
364  ObjectIdGetDatum(object->classId));
365  ScanKeyInit(&keys[2],
367  BTEqualStrategyNumber, F_INT4EQ,
368  Int32GetDatum(object->objectSubId));
369  ScanKeyInit(&keys[3],
371  BTEqualStrategyNumber, F_TEXTEQ,
372  CStringGetTextDatum(provider));
373 
375 
376  scan = systable_beginscan(pg_seclabel, SecLabelObjectIndexId, true,
377  NULL, 4, keys);
378 
379  oldtup = systable_getnext(scan);
380  if (HeapTupleIsValid(oldtup))
381  {
382  if (label == NULL)
383  CatalogTupleDelete(pg_seclabel, &oldtup->t_self);
384  else
385  {
386  replaces[Anum_pg_seclabel_label - 1] = true;
387  newtup = heap_modify_tuple(oldtup, RelationGetDescr(pg_seclabel),
388  values, nulls, replaces);
389  CatalogTupleUpdate(pg_seclabel, &oldtup->t_self, newtup);
390  }
391  }
392  systable_endscan(scan);
393 
394  /* If we didn't find an old tuple, insert a new one */
395  if (newtup == NULL && label != NULL)
396  {
397  newtup = heap_form_tuple(RelationGetDescr(pg_seclabel),
398  values, nulls);
399  CatalogTupleInsert(pg_seclabel, newtup);
400  }
401 
402  /* Update indexes, if necessary */
403  if (newtup != NULL)
404  heap_freetuple(newtup);
405 
406  heap_close(pg_seclabel, RowExclusiveLock);
407 }
408 
409 /*
410  * DeleteSharedSecurityLabel is a helper function of DeleteSecurityLabel
411  * to handle shared database objects.
412  */
413 void
415 {
416  Relation pg_shseclabel;
417  ScanKeyData skey[2];
418  SysScanDesc scan;
419  HeapTuple oldtup;
420 
421  ScanKeyInit(&skey[0],
423  BTEqualStrategyNumber, F_OIDEQ,
424  ObjectIdGetDatum(objectId));
425  ScanKeyInit(&skey[1],
427  BTEqualStrategyNumber, F_OIDEQ,
428  ObjectIdGetDatum(classId));
429 
431 
432  scan = systable_beginscan(pg_shseclabel, SharedSecLabelObjectIndexId, true,
433  NULL, 2, skey);
434  while (HeapTupleIsValid(oldtup = systable_getnext(scan)))
435  CatalogTupleDelete(pg_shseclabel, &oldtup->t_self);
436  systable_endscan(scan);
437 
438  heap_close(pg_shseclabel, RowExclusiveLock);
439 }
440 
441 /*
442  * DeleteSecurityLabel removes all security labels for an object (and any
443  * sub-objects, if applicable).
444  */
445 void
447 {
448  Relation pg_seclabel;
449  ScanKeyData skey[3];
450  SysScanDesc scan;
451  HeapTuple oldtup;
452  int nkeys;
453 
454  /* Shared objects have their own security label catalog. */
455  if (IsSharedRelation(object->classId))
456  {
457  Assert(object->objectSubId == 0);
458  DeleteSharedSecurityLabel(object->objectId, object->classId);
459  return;
460  }
461 
462  ScanKeyInit(&skey[0],
464  BTEqualStrategyNumber, F_OIDEQ,
465  ObjectIdGetDatum(object->objectId));
466  ScanKeyInit(&skey[1],
468  BTEqualStrategyNumber, F_OIDEQ,
469  ObjectIdGetDatum(object->classId));
470  if (object->objectSubId != 0)
471  {
472  ScanKeyInit(&skey[2],
474  BTEqualStrategyNumber, F_INT4EQ,
475  Int32GetDatum(object->objectSubId));
476  nkeys = 3;
477  }
478  else
479  nkeys = 2;
480 
482 
483  scan = systable_beginscan(pg_seclabel, SecLabelObjectIndexId, true,
484  NULL, nkeys, skey);
485  while (HeapTupleIsValid(oldtup = systable_getnext(scan)))
486  CatalogTupleDelete(pg_seclabel, &oldtup->t_self);
487  systable_endscan(scan);
488 
489  heap_close(pg_seclabel, RowExclusiveLock);
490 }
491 
492 void
493 register_label_provider(const char *provider_name, check_object_relabel_type hook)
494 {
495  LabelProvider *provider;
496  MemoryContext oldcxt;
497 
499  provider = palloc(sizeof(LabelProvider));
500  provider->provider_name = pstrdup(provider_name);
501  provider->hook = hook;
502  label_provider_list = lappend(label_provider_list, provider);
503  MemoryContextSwitchTo(oldcxt);
504 }
#define NIL
Definition: pg_list.h:69
#define Anum_pg_shseclabel_label
Definition: pg_shseclabel.h:45
ObjectType objtype
Definition: parsenodes.h:2580
Node * object
Definition: parsenodes.h:2581
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:499
void SetSecurityLabel(const ObjectAddress *object, const char *provider, const char *label)
Definition: seclabel.c:327
#define RelationGetDescr(relation)
Definition: rel.h:429
ObjectAddress ExecSecLabelStmt(SecLabelStmt *stmt)
Definition: seclabel.c:44
Oid GetUserId(void)
Definition: miscinit.c:283
char * pstrdup(const char *in)
Definition: mcxt.c:1077
static char * GetSharedSecurityLabel(const ObjectAddress *object, const char *provider)
Definition: seclabel.c:147
void DeleteSecurityLabel(const ObjectAddress *object)
Definition: seclabel.c:446
#define RELKIND_MATVIEW
Definition: pg_class.h:165
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define AccessShareLock
Definition: lockdefs.h:36
char * provider
Definition: parsenodes.h:2582
int errcode(int sqlerrcode)
Definition: elog.c:575
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: heapam.c:1260
const char * provider_name
Definition: seclabel.c:30
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:255
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:692
#define heap_close(r, l)
Definition: heapam.h:97
Form_pg_class rd_rel
Definition: rel.h:114
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1374
unsigned int Oid
Definition: postgres_ext.h:31
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:328
#define RELKIND_COMPOSITE_TYPE
Definition: pg_class.h:166
static List * label_provider_list
Definition: seclabel.c:34
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:416
#define linitial(l)
Definition: pg_list.h:111
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
Oid CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:162
char * GetSecurityLabel(const ObjectAddress *object, const char *provider)
Definition: seclabel.c:195
char * label
Definition: parsenodes.h:2583
ItemPointerData t_self
Definition: htup.h:65
#define Anum_pg_seclabel_classoid
Definition: pg_seclabel.h:41
#define NoLock
Definition: lockdefs.h:34
#define Anum_pg_seclabel_objoid
Definition: pg_seclabel.h:40
#define RowExclusiveLock
Definition: lockdefs.h:38
struct statement * stmt
Definition: extern.h:74
#define RelationGetRelationName(relation)
Definition: rel.h:437
#define Anum_pg_seclabel_label
Definition: pg_seclabel.h:44
static ListCell * list_head(const List *l)
Definition: pg_list.h:77
#define RELKIND_FOREIGN_TABLE
Definition: pg_class.h:167
#define SecLabelObjectIndexId
Definition: indexing.h:313
#define lnext(lc)
Definition: pg_list.h:105
#define ereport(elevel, rest)
Definition: elog.h:122
void(* check_object_relabel_type)(const ObjectAddress *object, const char *seclabel)
Definition: seclabel.h:29
MemoryContext TopMemoryContext
Definition: mcxt.c:43
List * lappend(List *list, void *datum)
Definition: list.c:128
#define heap_getattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:769
#define SharedSecLabelRelationId
Definition: pg_shseclabel.h:21
#define RELKIND_PARTITIONED_TABLE
Definition: pg_class.h:168
#define TextDatumGetCString(d)
Definition: builtins.h:92
uintptr_t Datum
Definition: postgres.h:372
#define SecLabelRelationId
Definition: pg_seclabel.h:21
check_object_relabel_type hook
Definition: seclabel.c:31
static char * label
Definition: pg_basebackup.c:81
bool IsSharedRelation(Oid relationId)
Definition: catalog.c:219
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1284
#define Anum_pg_shseclabel_classoid
Definition: pg_shseclabel.h:43
void register_label_provider(const char *provider_name, check_object_relabel_type hook)
Definition: seclabel.c:493
#define Natts_pg_shseclabel
Definition: pg_shseclabel.h:41
static void SetSharedSecurityLabel(const ObjectAddress *object, const char *provider, const char *label)
Definition: seclabel.c:252
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
#define lfirst(lc)
Definition: pg_list.h:106
ObjectAddress get_object_address(ObjectType objtype, Node *object, Relation *relp, LOCKMODE lockmode, bool missing_ok)
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:210
#define Anum_pg_shseclabel_objoid
Definition: pg_shseclabel.h:42
#define SharedSecLabelObjectIndexId
Definition: indexing.h:316
void DeleteSharedSecurityLabel(Oid objectId, Oid classId)
Definition: seclabel.c:414
static Datum values[MAXATTR]
Definition: bootstrap.c:163
void check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address, Node *object, Relation relation)
#define Int32GetDatum(X)
Definition: postgres.h:485
void * palloc(Size size)
Definition: mcxt.c:849
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define RELKIND_VIEW
Definition: pg_class.h:164
#define Anum_pg_shseclabel_provider
Definition: pg_shseclabel.h:44
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define CStringGetTextDatum(s)
Definition: builtins.h:91
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:793
#define RELKIND_RELATION
Definition: pg_class.h:160
Definition: pg_list.h:45
#define Anum_pg_seclabel_provider
Definition: pg_seclabel.h:43
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define Anum_pg_seclabel_objsubid
Definition: pg_seclabel.h:42
#define Natts_pg_seclabel
Definition: pg_seclabel.h:39