]> granicus.if.org Git - postgresql/blob - contrib/sepgsql/relation.c
sepgsql: Check CREATE permissions for some object types.
[postgresql] / contrib / sepgsql / relation.c
1 /* -------------------------------------------------------------------------
2  *
3  * contrib/sepgsql/label.c
4  *
5  * Routines corresponding to relation/attribute objects
6  *
7  * Copyright (c) 2010-2011, PostgreSQL Global Development Group
8  *
9  * -------------------------------------------------------------------------
10  */
11 #include "postgres.h"
12
13 #include "access/genam.h"
14 #include "access/heapam.h"
15 #include "access/sysattr.h"
16 #include "catalog/indexing.h"
17 #include "catalog/dependency.h"
18 #include "catalog/pg_attribute.h"
19 #include "catalog/pg_class.h"
20 #include "catalog/pg_namespace.h"
21 #include "commands/seclabel.h"
22 #include "utils/fmgroids.h"
23 #include "utils/lsyscache.h"
24 #include "utils/tqual.h"
25
26 #include "sepgsql.h"
27
28 /*
29  * sepgsql_attribute_post_create
30  *
31  * This routine assigns a default security label on a newly defined
32  * column, using ALTER TABLE ... ADD COLUMN.
33  * Note that this routine is not invoked in the case of CREATE TABLE,
34  * although it also defines columns in addition to table.
35  */
36 void
37 sepgsql_attribute_post_create(Oid relOid, AttrNumber attnum)
38 {
39         Relation        rel;
40         ScanKeyData skey[2];
41         SysScanDesc sscan;
42         HeapTuple       tuple;
43         char       *scontext;
44         char       *tcontext;
45         char       *ncontext;
46         char            audit_name[2*NAMEDATALEN + 20];
47         ObjectAddress object;
48         Form_pg_attribute       attForm;
49
50         /*
51          * Only attributes within regular relation have individual security
52          * labels.
53          */
54         if (get_rel_relkind(relOid) != RELKIND_RELATION)
55                 return;
56
57         /*
58          * Compute a default security label of the new column underlying the
59          * specified relation, and check permission to create it.
60          */
61         rel = heap_open(AttributeRelationId, AccessShareLock);
62
63         ScanKeyInit(&skey[0],
64                                 Anum_pg_attribute_attrelid,
65                                 BTEqualStrategyNumber, F_OIDEQ,
66                                 ObjectIdGetDatum(relOid));
67         ScanKeyInit(&skey[1],
68                                 Anum_pg_attribute_attnum,
69                                 BTEqualStrategyNumber, F_INT2EQ,
70                                 Int16GetDatum(attnum));
71
72         sscan = systable_beginscan(rel, AttributeRelidNumIndexId, true,
73                                                            SnapshotSelf, 2, &skey[0]);
74
75         tuple = systable_getnext(sscan);
76         if (!HeapTupleIsValid(tuple))
77                 elog(ERROR, "catalog lookup failed for column %d of relation %u",
78                          attnum, relOid);
79
80         attForm = (Form_pg_attribute) GETSTRUCT(tuple);
81
82         scontext = sepgsql_get_client_label();
83         tcontext = sepgsql_get_label(RelationRelationId, relOid, 0);
84         ncontext = sepgsql_compute_create(scontext, tcontext,
85                                                                           SEPG_CLASS_DB_COLUMN);
86         /*
87          * check db_column:{create} permission
88          */
89         snprintf(audit_name, sizeof(audit_name), "table %s column %s",
90                          get_rel_name(relOid), NameStr(attForm->attname));
91         sepgsql_avc_check_perms_label(ncontext,
92                                                                   SEPG_CLASS_DB_COLUMN,
93                                                                   SEPG_DB_COLUMN__CREATE,
94                                                                   audit_name,
95                                                                   true);
96
97         /*
98          * Assign the default security label on a new procedure
99          */
100         object.classId = RelationRelationId;
101         object.objectId = relOid;
102         object.objectSubId = attnum;
103         SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, ncontext);
104
105         systable_endscan(sscan);
106         heap_close(rel, AccessShareLock);
107
108         pfree(tcontext);
109         pfree(ncontext);
110 }
111
112 /*
113  * sepgsql_attribute_relabel
114  *
115  * It checks privileges to relabel the supplied column
116  * by the `seclabel'.
117  */
118 void
119 sepgsql_attribute_relabel(Oid relOid, AttrNumber attnum,
120                                                   const char *seclabel)
121 {
122         ObjectAddress object;
123         char             *audit_name;
124
125         if (get_rel_relkind(relOid) != RELKIND_RELATION)
126                 ereport(ERROR,
127                                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
128                                  errmsg("cannot set security label on non-regular columns")));
129
130         object.classId = RelationRelationId;
131         object.objectId = relOid;
132         object.objectSubId = attnum;
133         audit_name = getObjectDescription(&object);
134
135         /*
136          * check db_column:{setattr relabelfrom} permission
137          */
138         sepgsql_avc_check_perms(&object,
139                                                         SEPG_CLASS_DB_COLUMN,
140                                                         SEPG_DB_COLUMN__SETATTR |
141                                                         SEPG_DB_COLUMN__RELABELFROM,
142                                                         audit_name,
143                                                         true);
144         /*
145          * check db_column:{relabelto} permission
146          */
147         sepgsql_avc_check_perms_label(seclabel,
148                                                                   SEPG_CLASS_DB_COLUMN,
149                                                                   SEPG_DB_PROCEDURE__RELABELTO,
150                                                                   audit_name,
151                                                                   true);
152         pfree(audit_name);
153 }
154
155 /*
156  * sepgsql_relation_post_create
157  *
158  * The post creation hook of relation/attribute
159  */
160 void
161 sepgsql_relation_post_create(Oid relOid)
162 {
163         Relation        rel;
164         ScanKeyData skey;
165         SysScanDesc sscan;
166         HeapTuple       tuple;
167         Form_pg_class classForm;
168         ObjectAddress object;
169         uint16          tclass;
170         const char *tclass_text;
171         char       *scontext;           /* subject */
172         char       *tcontext;           /* schema */
173         char       *rcontext;           /* relation */
174         char       *ccontext;           /* column */
175         char            audit_name[2*NAMEDATALEN + 20];
176
177         /*
178          * Fetch catalog record of the new relation. Because pg_class entry is not
179          * visible right now, we need to scan the catalog using SnapshotSelf.
180          */
181         rel = heap_open(RelationRelationId, AccessShareLock);
182
183         ScanKeyInit(&skey,
184                                 ObjectIdAttributeNumber,
185                                 BTEqualStrategyNumber, F_OIDEQ,
186                                 ObjectIdGetDatum(relOid));
187
188         sscan = systable_beginscan(rel, ClassOidIndexId, true,
189                                                            SnapshotSelf, 1, &skey);
190
191         tuple = systable_getnext(sscan);
192         if (!HeapTupleIsValid(tuple))
193                 elog(ERROR, "catalog lookup failed for relation %u", relOid);
194
195         classForm = (Form_pg_class) GETSTRUCT(tuple);
196
197         switch (classForm->relkind)
198         {
199                 case RELKIND_RELATION:
200                         tclass = SEPG_CLASS_DB_TABLE;
201                         tclass_text = "table";
202                         break;
203                 case RELKIND_SEQUENCE:
204                         tclass = SEPG_CLASS_DB_SEQUENCE;
205                         tclass_text = "sequence";
206                         break;
207                 case RELKIND_VIEW:
208                         tclass = SEPG_CLASS_DB_VIEW;
209                         tclass_text = "view";
210                         break;
211                 default:
212                         goto out;
213         }
214
215         /*
216          * check db_schema:{add_name} permission of the namespace
217          */
218         object.classId = NamespaceRelationId;
219         object.objectId = classForm->relnamespace;
220         object.objectSubId = 0;
221         sepgsql_avc_check_perms(&object,
222                                                         SEPG_CLASS_DB_SCHEMA,
223                                                         SEPG_DB_SCHEMA__ADD_NAME,
224                                                         getObjectDescription(&object),
225                                                         true);
226         /*
227          * Compute a default security label when we create a new relation object
228          * under the specified namespace.
229          */
230         scontext = sepgsql_get_client_label();
231         tcontext = sepgsql_get_label(NamespaceRelationId,
232                                                                  classForm->relnamespace, 0);
233         rcontext = sepgsql_compute_create(scontext, tcontext, tclass);
234
235         /*
236          * check db_xxx:{create} permission
237          */
238         snprintf(audit_name, sizeof(audit_name), "%s %s",
239                          tclass_text, NameStr(classForm->relname));
240         sepgsql_avc_check_perms_label(rcontext,
241                                                                   tclass,
242                                                                   SEPG_DB_DATABASE__CREATE,
243                                                                   audit_name,
244                                                                   true);
245         /*
246          * Assign the default security label on the new relation
247          */
248         object.classId = RelationRelationId;
249         object.objectId = relOid;
250         object.objectSubId = 0;
251         SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, rcontext);
252
253         /*
254          * We also assigns a default security label on columns of the new regular
255          * tables.
256          */
257         if (classForm->relkind == RELKIND_RELATION)
258         {
259                 Relation        arel;
260                 ScanKeyData     akey;
261                 SysScanDesc     ascan;
262                 HeapTuple       atup;
263                 Form_pg_attribute       attForm;
264
265                 arel = heap_open(AttributeRelationId, AccessShareLock);
266
267                 ScanKeyInit(&akey,
268                                         Anum_pg_attribute_attrelid,
269                                         BTEqualStrategyNumber, F_OIDEQ,
270                                         ObjectIdGetDatum(relOid));
271
272                 ascan = systable_beginscan(arel, AttributeRelidNumIndexId, true,
273                                                                    SnapshotSelf, 1, &akey);
274
275                 while (HeapTupleIsValid(atup = systable_getnext(ascan)))
276                 {
277                         attForm = (Form_pg_attribute) GETSTRUCT(atup);
278
279                         snprintf(audit_name, sizeof(audit_name), "%s %s column %s",
280                                          tclass_text,
281                                          NameStr(classForm->relname),
282                                          NameStr(attForm->attname));
283
284                         ccontext = sepgsql_compute_create(scontext,
285                                                                                           rcontext,
286                                                                                           SEPG_CLASS_DB_COLUMN);
287                         /*
288                          * check db_column:{create} permission
289                          */
290                         sepgsql_avc_check_perms_label(ccontext,
291                                                                                   SEPG_CLASS_DB_COLUMN,
292                                                                                   SEPG_DB_COLUMN__CREATE,
293                                                                                   audit_name,
294                                                                                   true);
295
296                         object.classId = RelationRelationId;
297                         object.objectId = relOid;
298                         object.objectSubId = attForm->attnum;
299                         SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, ccontext);
300
301                         pfree(ccontext);
302                 }
303                 systable_endscan(ascan);
304                 heap_close(arel, AccessShareLock);
305         }
306         pfree(rcontext);
307 out:
308         systable_endscan(sscan);
309         heap_close(rel, AccessShareLock);
310 }
311
312 /*
313  * sepgsql_relation_relabel
314  *
315  * It checks privileges to relabel the supplied relation by the `seclabel'.
316  */
317 void
318 sepgsql_relation_relabel(Oid relOid, const char *seclabel)
319 {
320         ObjectAddress   object;
321         char       *audit_name;
322         char            relkind;
323         uint16_t        tclass = 0;
324
325         relkind = get_rel_relkind(relOid);
326         if (relkind == RELKIND_RELATION)
327                 tclass = SEPG_CLASS_DB_TABLE;
328         else if (relkind == RELKIND_SEQUENCE)
329                 tclass = SEPG_CLASS_DB_SEQUENCE;
330         else if (relkind == RELKIND_VIEW)
331                 tclass = SEPG_CLASS_DB_VIEW;
332         else
333                 ereport(ERROR,
334                                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
335                                  errmsg("cannot set security labels on relations except "
336                                                 "for tables, sequences or views")));
337
338         object.classId = RelationRelationId;
339         object.objectId = relOid;
340         object.objectSubId = 0;
341         audit_name = getObjectDescription(&object);
342
343         /*
344          * check db_xxx:{setattr relabelfrom} permission
345          */
346         sepgsql_avc_check_perms(&object,
347                                                         tclass,
348                                                         SEPG_DB_TABLE__SETATTR |
349                                                         SEPG_DB_TABLE__RELABELFROM,
350                                                         audit_name,
351                                                         true);
352         /*
353          * check db_xxx:{relabelto} permission
354          */
355         sepgsql_avc_check_perms_label(seclabel,
356                                                                   tclass,
357                                                                   SEPG_DB_TABLE__RELABELTO,
358                                                                   audit_name,
359                                                                   true);
360         pfree(audit_name);
361 }