OSDN Git Service

Remove rel.h from objectaddress.h; only relcache.h is necessary.
[pg-rex/syncrep.git] / src / backend / commands / seclabel.c
1 /* -------------------------------------------------------------------------
2  *
3  * seclabel.c
4  *        routines to support security label feature.
5  *
6  * Portions Copyright (c) 1996-2011, 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 "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"
28
29 typedef struct
30 {
31         const char *provider_name;
32         check_object_relabel_type hook;
33 } LabelProvider;
34
35 static List *label_provider_list = NIL;
36
37 /*
38  * ExecSecLabelStmt --
39  *
40  * Apply a security label to a database object.
41  */
42 void
43 ExecSecLabelStmt(SecLabelStmt *stmt)
44 {
45         LabelProvider *provider = NULL;
46         ObjectAddress address;
47         Relation        relation;
48         ListCell   *lc;
49
50         /*
51          * Find the named label provider, or if none specified, check whether
52          * there's exactly one, and if so use it.
53          */
54         if (stmt->provider == NULL)
55         {
56                 if (label_provider_list == NIL)
57                         ereport(ERROR,
58                                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
59                                          errmsg("no security label providers have been loaded")));
60                 if (lnext(list_head(label_provider_list)) != NULL)
61                         ereport(ERROR,
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);
65         }
66         else
67         {
68                 foreach(lc, label_provider_list)
69                 {
70                         LabelProvider *lp = lfirst(lc);
71
72                         if (strcmp(stmt->provider, lp->provider_name) == 0)
73                         {
74                                 provider = lp;
75                                 break;
76                         }
77                 }
78                 if (provider == NULL)
79                         ereport(ERROR,
80                                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
81                                          errmsg("security label provider \"%s\" is not loaded",
82                                                         stmt->provider)));
83         }
84
85         /*
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.
90          */
91         address = get_object_address(stmt->objtype, stmt->objname, stmt->objargs,
92                                                                  &relation, ShareUpdateExclusiveLock, false);
93
94         /* Require ownership of the target object. */
95         check_object_ownership(GetUserId(), stmt->objtype, address,
96                                                    stmt->objname, stmt->objargs, relation);
97
98         /* Perform other integrity checks as needed. */
99         switch (stmt->objtype)
100         {
101                 case OBJECT_COLUMN:
102
103                         /*
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).
107                          */
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)
112                                 ereport(ERROR,
113                                                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
114                                                  errmsg("\"%s\" is not a table, view, composite type, or foreign table",
115                                                                 RelationGetRelationName(relation))));
116                         break;
117                 default:
118                         break;
119         }
120
121         /* Provider gets control here, may throw ERROR to veto new label. */
122         (*provider->hook) (&address, stmt->label);
123
124         /* Apply new label. */
125         SetSecurityLabel(&address, provider->provider_name, stmt->label);
126
127         /*
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
131          * activity.
132          */
133         if (relation != NULL)
134                 relation_close(relation, NoLock);
135 }
136
137 /*
138  * GetSecurityLabel returns the security label for a database object for a
139  * given provider, or NULL if there is no such label.
140  */
141 char *
142 GetSecurityLabel(const ObjectAddress *object, const char *provider)
143 {
144         Relation        pg_seclabel;
145         ScanKeyData keys[4];
146         SysScanDesc scan;
147         HeapTuple       tuple;
148         Datum           datum;
149         bool            isnull;
150         char       *seclabel = NULL;
151
152         Assert(!IsSharedRelation(object->classId));
153
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));
170
171         pg_seclabel = heap_open(SecLabelRelationId, AccessShareLock);
172
173         scan = systable_beginscan(pg_seclabel, SecLabelObjectIndexId, true,
174                                                           SnapshotNow, 4, keys);
175
176         tuple = systable_getnext(scan);
177         if (HeapTupleIsValid(tuple))
178         {
179                 datum = heap_getattr(tuple, Anum_pg_seclabel_label,
180                                                          RelationGetDescr(pg_seclabel), &isnull);
181                 if (!isnull)
182                         seclabel = TextDatumGetCString(datum);
183         }
184         systable_endscan(scan);
185
186         heap_close(pg_seclabel, AccessShareLock);
187
188         return seclabel;
189 }
190
191 /*
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.
195  */
196 void
197 SetSecurityLabel(const ObjectAddress *object,
198                                  const char *provider, const char *label)
199 {
200         Relation        pg_seclabel;
201         ScanKeyData keys[4];
202         SysScanDesc scan;
203         HeapTuple       oldtup;
204         HeapTuple       newtup = NULL;
205         Datum           values[Natts_pg_seclabel];
206         bool            nulls[Natts_pg_seclabel];
207         bool            replaces[Natts_pg_seclabel];
208
209         /* Security labels on shared objects are not supported. */
210         Assert(!IsSharedRelation(object->classId));
211
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);
219         if (label != NULL)
220                 values[Anum_pg_seclabel_label - 1] = CStringGetTextDatum(label);
221
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));
239
240         pg_seclabel = heap_open(SecLabelRelationId, RowExclusiveLock);
241
242         scan = systable_beginscan(pg_seclabel, SecLabelObjectIndexId, true,
243                                                           SnapshotNow, 4, keys);
244
245         oldtup = systable_getnext(scan);
246         if (HeapTupleIsValid(oldtup))
247         {
248                 if (label == NULL)
249                         simple_heap_delete(pg_seclabel, &oldtup->t_self);
250                 else
251                 {
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);
256                 }
257         }
258         systable_endscan(scan);
259
260         /* If we didn't find an old tuple, insert a new one */
261         if (newtup == NULL && label != NULL)
262         {
263                 newtup = heap_form_tuple(RelationGetDescr(pg_seclabel),
264                                                                  values, nulls);
265                 simple_heap_insert(pg_seclabel, newtup);
266         }
267
268         /* Update indexes, if necessary */
269         if (newtup != NULL)
270         {
271                 CatalogUpdateIndexes(pg_seclabel, newtup);
272                 heap_freetuple(newtup);
273         }
274
275         heap_close(pg_seclabel, RowExclusiveLock);
276 }
277
278 /*
279  * DeleteSecurityLabel removes all security labels for an object (and any
280  * sub-objects, if applicable).
281  */
282 void
283 DeleteSecurityLabel(const ObjectAddress *object)
284 {
285         Relation        pg_seclabel;
286         ScanKeyData skey[3];
287         SysScanDesc scan;
288         HeapTuple       oldtup;
289         int                     nkeys;
290
291         /* Security labels on shared objects are not supported. */
292         if (IsSharedRelation(object->classId))
293                 return;
294
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)
304         {
305                 ScanKeyInit(&skey[2],
306                                         Anum_pg_seclabel_objsubid,
307                                         BTEqualStrategyNumber, F_INT4EQ,
308                                         Int32GetDatum(object->objectSubId));
309                 nkeys = 3;
310         }
311         else
312                 nkeys = 2;
313
314         pg_seclabel = heap_open(SecLabelRelationId, RowExclusiveLock);
315
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);
321
322         heap_close(pg_seclabel, RowExclusiveLock);
323 }
324
325 void
326 register_label_provider(const char *provider_name, check_object_relabel_type hook)
327 {
328         LabelProvider *provider;
329         MemoryContext oldcxt;
330
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);
337 }