1 /* Copyright (C) 2005 Red Hat, Inc. */
2
3 /* Object: dbase_policydb_t (Policy)
4 * Implements: dbase_t (Database)
5 */
6
7 struct dbase_policydb;
8 typedef struct dbase_policydb dbase_t;
9 #define DBASE_DEFINED
10
11 #include <stdlib.h>
12 #include <stddef.h>
13 #include <string.h>
14 #include <stdio.h>
15 #include <stdio_ext.h>
16 #include <errno.h>
17
18 #include <sepol/policydb.h>
19
20 #include "database_policydb.h"
21 #include "semanage_store.h"
22 #include "handle.h"
23 #include "debug.h"
24
25 /* POLICYDB dbase */
26 struct dbase_policydb {
27
28 /* Backing path for read-only[0] and transaction[1] */
29 const char *path[2];
30
31 /* Base record table */
32 record_table_t *rtable;
33
34 /* Policy extensions */
35 record_policydb_table_t *rptable;
36
37 sepol_policydb_t *policydb;
38
39 int cache_serial;
40 int modified;
41 int attached;
42 };
43
dbase_policydb_drop_cache(dbase_policydb_t * dbase)44 static void dbase_policydb_drop_cache(dbase_policydb_t * dbase)
45 {
46
47 if (dbase->cache_serial >= 0) {
48 sepol_policydb_free(dbase->policydb);
49 dbase->cache_serial = -1;
50 dbase->modified = 0;
51 }
52 }
53
dbase_policydb_set_serial(semanage_handle_t * handle,dbase_policydb_t * dbase)54 static int dbase_policydb_set_serial(semanage_handle_t * handle,
55 dbase_policydb_t * dbase)
56 {
57
58 int cache_serial = handle->funcs->get_serial(handle);
59 if (cache_serial < 0) {
60 ERR(handle, "could not update cache serial");
61 return STATUS_ERR;
62 }
63
64 dbase->cache_serial = cache_serial;
65 return STATUS_SUCCESS;
66 }
67
dbase_policydb_needs_resync(semanage_handle_t * handle,dbase_policydb_t * dbase)68 static int dbase_policydb_needs_resync(semanage_handle_t * handle,
69 dbase_policydb_t * dbase)
70 {
71
72 int cache_serial;
73
74 if (dbase->cache_serial < 0)
75 return 1;
76
77 cache_serial = handle->funcs->get_serial(handle);
78 if (cache_serial < 0)
79 return 1;
80
81 if (cache_serial != dbase->cache_serial) {
82 dbase_policydb_drop_cache(dbase);
83 dbase->cache_serial = -1;
84 return 1;
85 }
86 return 0;
87 }
88
dbase_policydb_cache(semanage_handle_t * handle,dbase_policydb_t * dbase)89 static int dbase_policydb_cache(semanage_handle_t * handle,
90 dbase_policydb_t * dbase)
91 {
92
93 FILE *fp = NULL;
94 sepol_policydb_t *policydb = NULL;
95 sepol_policy_file_t *pf = NULL;
96 const char *fname = NULL;
97
98 /* Check if cache is needed */
99 if (dbase->attached)
100 return STATUS_SUCCESS;
101
102 if (!dbase_policydb_needs_resync(handle, dbase))
103 return STATUS_SUCCESS;
104
105 fname = dbase->path[handle->is_in_transaction];
106
107 if (sepol_policydb_create(&policydb) < 0) {
108 ERR(handle, "could not create policydb object");
109 goto err;
110 }
111
112 /* Try opening file
113 * ENOENT is not fatal - we just create an empty policydb */
114 fp = fopen(fname, "rb");
115 if (fp == NULL && errno != ENOENT) {
116 ERR(handle, "could not open %s for reading: %s",
117 fname, strerror(errno));
118 goto err;
119 }
120
121 /* If the file was opened successfully, read a policydb */
122 if (fp != NULL) {
123 __fsetlocking(fp, FSETLOCKING_BYCALLER);
124 if (sepol_policy_file_create(&pf) < 0) {
125 ERR(handle, "could not create policy file object");
126 goto err;
127 }
128
129 sepol_policy_file_set_fp(pf, fp);
130 sepol_policy_file_set_handle(pf, handle->sepolh);
131
132 if (sepol_policydb_read(policydb, pf) < 0)
133 goto err;
134
135 sepol_policy_file_free(pf);
136 fclose(fp);
137 fp = NULL;
138 }
139
140 /* Update cache serial */
141 if (dbase_policydb_set_serial(handle, dbase) < 0)
142 goto err;
143
144 /* Update the database policydb */
145 dbase->policydb = policydb;
146 return STATUS_SUCCESS;
147
148 err:
149 ERR(handle, "could not cache policy database");
150 if (fp)
151 fclose(fp);
152 sepol_policydb_free(policydb);
153 sepol_policy_file_free(pf);
154 return STATUS_ERR;
155 }
156
dbase_policydb_flush(semanage_handle_t * handle,dbase_policydb_t * dbase)157 static int dbase_policydb_flush(semanage_handle_t * handle
158 __attribute__ ((unused)),
159 dbase_policydb_t * dbase)
160 {
161
162 if (!dbase->modified)
163 return STATUS_SUCCESS;
164
165 dbase->modified = 0;
166
167 /* Stub */
168 return STATUS_ERR;
169 }
170
171 /* Check if modified */
dbase_policydb_is_modified(dbase_policydb_t * dbase)172 static int dbase_policydb_is_modified(dbase_policydb_t * dbase)
173 {
174
175 return dbase->modified;
176 }
177
dbase_policydb_init(semanage_handle_t * handle,const char * path_ro,const char * path_rw,record_table_t * rtable,record_policydb_table_t * rptable,dbase_policydb_t ** dbase)178 int dbase_policydb_init(semanage_handle_t * handle,
179 const char *path_ro,
180 const char *path_rw,
181 record_table_t * rtable,
182 record_policydb_table_t * rptable,
183 dbase_policydb_t ** dbase)
184 {
185
186 dbase_policydb_t *tmp_dbase =
187 (dbase_policydb_t *) malloc(sizeof(dbase_policydb_t));
188
189 if (!tmp_dbase)
190 goto omem;
191
192 tmp_dbase->path[0] = path_ro;
193 tmp_dbase->path[1] = path_rw;
194 tmp_dbase->rtable = rtable;
195 tmp_dbase->rptable = rptable;
196 tmp_dbase->policydb = NULL;
197 tmp_dbase->cache_serial = -1;
198 tmp_dbase->modified = 0;
199 tmp_dbase->attached = 0;
200 *dbase = tmp_dbase;
201
202 return STATUS_SUCCESS;
203
204 omem:
205 ERR(handle, "out of memory, could not initialize policy database");
206 free(tmp_dbase);
207
208 return STATUS_ERR;
209 }
210
211 /* Release dbase resources */
dbase_policydb_release(dbase_policydb_t * dbase)212 void dbase_policydb_release(dbase_policydb_t * dbase)
213 {
214
215 dbase_policydb_drop_cache(dbase);
216 free(dbase);
217 }
218
219 /* Attach to a shared policydb.
220 * This implies drop_cache(),
221 * and prevents flush() and drop_cache()
222 * until detached. */
dbase_policydb_attach(dbase_policydb_t * dbase,sepol_policydb_t * policydb)223 void dbase_policydb_attach(dbase_policydb_t * dbase,
224 sepol_policydb_t * policydb)
225 {
226
227 dbase->attached = 1;
228 dbase_policydb_drop_cache(dbase);
229 dbase->policydb = policydb;
230 }
231
232 /* Detach from a shared policdb.
233 * This implies drop_cache. */
dbase_policydb_detach(dbase_policydb_t * dbase)234 void dbase_policydb_detach(dbase_policydb_t * dbase)
235 {
236
237 dbase->attached = 0;
238 dbase->modified = 0;
239 }
240
dbase_policydb_add(semanage_handle_t * handle,dbase_policydb_t * dbase,const record_key_t * key,const record_t * data)241 static int dbase_policydb_add(semanage_handle_t * handle,
242 dbase_policydb_t * dbase,
243 const record_key_t * key, const record_t * data)
244 {
245
246 if (dbase->rptable->add(handle->sepolh, dbase->policydb, key, data) < 0)
247 goto err;
248
249 dbase->modified = 1;
250 return STATUS_SUCCESS;
251
252 err:
253 ERR(handle, "could not add record to the database");
254 return STATUS_ERR;
255 }
256
dbase_policydb_set(semanage_handle_t * handle,dbase_policydb_t * dbase,const record_key_t * key,const record_t * data)257 static int dbase_policydb_set(semanage_handle_t * handle,
258 dbase_policydb_t * dbase,
259 const record_key_t * key, const record_t * data)
260 {
261
262 if (dbase->rptable->set(handle->sepolh, dbase->policydb, key, data) < 0)
263 goto err;
264
265 dbase->modified = 1;
266 return STATUS_SUCCESS;
267
268 err:
269 ERR(handle, "could not set record value");
270 return STATUS_ERR;
271 }
272
dbase_policydb_modify(semanage_handle_t * handle,dbase_policydb_t * dbase,const record_key_t * key,const record_t * data)273 static int dbase_policydb_modify(semanage_handle_t * handle,
274 dbase_policydb_t * dbase,
275 const record_key_t * key,
276 const record_t * data)
277 {
278
279 if (dbase->rptable->modify(handle->sepolh,
280 dbase->policydb, key, data) < 0)
281 goto err;
282
283 dbase->modified = 1;
284 return STATUS_SUCCESS;
285
286 err:
287 ERR(handle, "could not modify record value");
288 return STATUS_ERR;
289 }
290
dbase_policydb_del(semanage_handle_t * handle,dbase_policydb_t * dbase,const record_key_t * key)291 static int dbase_policydb_del(semanage_handle_t * handle
292 __attribute__ ((unused)),
293 dbase_policydb_t * dbase
294 __attribute__ ((unused)),
295 const record_key_t * key
296 __attribute__ ((unused)))
297 {
298
299 /* Stub */
300 return STATUS_ERR;
301 }
302
dbase_policydb_clear(semanage_handle_t * handle,dbase_policydb_t * dbase)303 static int dbase_policydb_clear(semanage_handle_t * handle
304 __attribute__ ((unused)),
305 dbase_policydb_t * dbase
306 __attribute__ ((unused)))
307 {
308
309 /* Stub */
310 return STATUS_ERR;
311 }
312
dbase_policydb_query(semanage_handle_t * handle,dbase_policydb_t * dbase,const record_key_t * key,record_t ** response)313 static int dbase_policydb_query(semanage_handle_t * handle,
314 dbase_policydb_t * dbase,
315 const record_key_t * key, record_t ** response)
316 {
317
318 if (dbase->rptable->query(handle->sepolh,
319 dbase->policydb, key, response) < 0)
320 goto err;
321
322 return STATUS_SUCCESS;
323
324 err:
325 ERR(handle, "could not query record value");
326 return STATUS_ERR;
327 }
328
dbase_policydb_exists(semanage_handle_t * handle,dbase_policydb_t * dbase,const record_key_t * key,int * response)329 static int dbase_policydb_exists(semanage_handle_t * handle,
330 dbase_policydb_t * dbase,
331 const record_key_t * key, int *response)
332 {
333
334 if (dbase->rptable->exists(handle->sepolh,
335 dbase->policydb, key, response) < 0)
336 goto err;
337
338 return STATUS_SUCCESS;
339
340 err:
341 ERR(handle, "could not check if record exists");
342 return STATUS_ERR;
343 }
344
dbase_policydb_count(semanage_handle_t * handle,dbase_policydb_t * dbase,unsigned int * response)345 static int dbase_policydb_count(semanage_handle_t * handle,
346 dbase_policydb_t * dbase,
347 unsigned int *response)
348 {
349
350 if (dbase->rptable->count(handle->sepolh,
351 dbase->policydb, response) < 0)
352 goto err;
353
354 return STATUS_SUCCESS;
355
356 err:
357 ERR(handle, "could not count the database records");
358 return STATUS_ERR;
359 }
360
dbase_policydb_iterate(semanage_handle_t * handle,dbase_policydb_t * dbase,int (* fn)(const record_t * record,void * fn_arg),void * arg)361 static int dbase_policydb_iterate(semanage_handle_t * handle,
362 dbase_policydb_t * dbase,
363 int (*fn) (const record_t * record,
364 void *fn_arg), void *arg)
365 {
366
367 if (dbase->rptable->iterate(handle->sepolh,
368 dbase->policydb, fn, arg) < 0)
369 goto err;
370
371 return STATUS_SUCCESS;
372
373 err:
374 ERR(handle, "could not iterate over records");
375 return STATUS_ERR;
376 }
377
378 struct list_handler_arg {
379 semanage_handle_t *handle;
380 record_table_t *rtable;
381 record_t **records;
382 int pos;
383 };
384
list_handler(const record_t * record,void * varg)385 static int list_handler(const record_t * record, void *varg)
386 {
387
388 struct list_handler_arg *arg = (struct list_handler_arg *)varg;
389
390 if (arg->rtable->clone(arg->handle, record, &arg->records[arg->pos]) <
391 0)
392 return -1;
393 arg->pos++;
394 return 0;
395 }
396
dbase_policydb_list(semanage_handle_t * handle,dbase_t * dbase,record_t *** records,unsigned int * count)397 static int dbase_policydb_list(semanage_handle_t * handle,
398 dbase_t * dbase,
399 record_t *** records, unsigned int *count)
400 {
401
402 record_t **tmp_records = NULL;
403 unsigned int tmp_count;
404 struct list_handler_arg list_arg;
405 list_arg.pos = 0;
406 list_arg.rtable = dbase->rtable;
407 list_arg.handle = handle;
408
409 if (dbase->rptable->count(handle->sepolh,
410 dbase->policydb, &tmp_count) < 0)
411 goto err;
412
413 if (tmp_count > 0) {
414 tmp_records = (record_t **)
415 calloc(tmp_count, sizeof(record_t *));
416
417 if (tmp_records == NULL)
418 goto omem;
419
420 list_arg.records = tmp_records;
421
422 if (dbase->rptable->iterate(handle->sepolh,
423 dbase->policydb, list_handler,
424 &list_arg) < 0) {
425 ERR(handle, "list handler could not extract record");
426 goto err;
427 }
428 }
429
430 *records = tmp_records;
431 *count = tmp_count;
432 return STATUS_SUCCESS;
433
434 omem:
435 ERR(handle, "out of memory");
436
437 err:
438 if (tmp_records) {
439 for (; list_arg.pos >= 0; list_arg.pos--)
440 dbase->rtable->free(tmp_records[list_arg.pos]);
441 free(tmp_records);
442 }
443 ERR(handle, "could not list records");
444 return STATUS_ERR;
445 }
446
dbase_policydb_get_rtable(dbase_policydb_t * dbase)447 static record_table_t *dbase_policydb_get_rtable(dbase_policydb_t * dbase)
448 {
449
450 return dbase->rtable;
451 }
452
453 /* POLICYDB dbase - method table implementation */
454 dbase_table_t SEMANAGE_POLICYDB_DTABLE = {
455
456 /* Cache/Transactions */
457 .cache = dbase_policydb_cache,
458 .drop_cache = dbase_policydb_drop_cache,
459 .flush = dbase_policydb_flush,
460 .is_modified = dbase_policydb_is_modified,
461
462 /* Database Functionality */
463 .iterate = dbase_policydb_iterate,
464 .exists = dbase_policydb_exists,
465 .list = dbase_policydb_list,
466 .add = dbase_policydb_add,
467 .set = dbase_policydb_set,
468 .del = dbase_policydb_del,
469 .clear = dbase_policydb_clear,
470 .modify = dbase_policydb_modify,
471 .query = dbase_policydb_query,
472 .count = dbase_policydb_count,
473
474 /* Polymorphism */
475 .get_rtable = dbase_policydb_get_rtable
476 };
477