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 handle = NULL;
169 return STATUS_ERR;
170 }
171
172 /* Check if modified */
dbase_policydb_is_modified(dbase_policydb_t * dbase)173 static int dbase_policydb_is_modified(dbase_policydb_t * dbase)
174 {
175
176 return dbase->modified;
177 }
178
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)179 int dbase_policydb_init(semanage_handle_t * handle,
180 const char *path_ro,
181 const char *path_rw,
182 record_table_t * rtable,
183 record_policydb_table_t * rptable,
184 dbase_policydb_t ** dbase)
185 {
186
187 dbase_policydb_t *tmp_dbase =
188 (dbase_policydb_t *) malloc(sizeof(dbase_policydb_t));
189
190 if (!tmp_dbase)
191 goto omem;
192
193 tmp_dbase->path[0] = path_ro;
194 tmp_dbase->path[1] = path_rw;
195 tmp_dbase->rtable = rtable;
196 tmp_dbase->rptable = rptable;
197 tmp_dbase->policydb = NULL;
198 tmp_dbase->cache_serial = -1;
199 tmp_dbase->modified = 0;
200 tmp_dbase->attached = 0;
201 *dbase = tmp_dbase;
202
203 return STATUS_SUCCESS;
204
205 omem:
206 ERR(handle, "out of memory, could not initialize policy database");
207 free(tmp_dbase);
208
209 return STATUS_ERR;
210 }
211
212 /* Release dbase resources */
dbase_policydb_release(dbase_policydb_t * dbase)213 void dbase_policydb_release(dbase_policydb_t * dbase)
214 {
215
216 dbase_policydb_drop_cache(dbase);
217 free(dbase);
218 }
219
220 /* Attach to a shared policydb.
221 * This implies drop_cache(),
222 * and prevents flush() and drop_cache()
223 * until detached. */
dbase_policydb_attach(dbase_policydb_t * dbase,sepol_policydb_t * policydb)224 void dbase_policydb_attach(dbase_policydb_t * dbase,
225 sepol_policydb_t * policydb)
226 {
227
228 dbase->attached = 1;
229 dbase_policydb_drop_cache(dbase);
230 dbase->policydb = policydb;
231 }
232
233 /* Detach from a shared policdb.
234 * This implies drop_cache. */
dbase_policydb_detach(dbase_policydb_t * dbase)235 void dbase_policydb_detach(dbase_policydb_t * dbase)
236 {
237
238 dbase->attached = 0;
239 dbase->modified = 0;
240 }
241
dbase_policydb_add(semanage_handle_t * handle,dbase_policydb_t * dbase,const record_key_t * key,const record_t * data)242 static int dbase_policydb_add(semanage_handle_t * handle,
243 dbase_policydb_t * dbase,
244 const record_key_t * key, const record_t * data)
245 {
246
247 if (dbase->rptable->add(handle->sepolh, dbase->policydb, key, data) < 0)
248 goto err;
249
250 dbase->modified = 1;
251 return STATUS_SUCCESS;
252
253 err:
254 ERR(handle, "could not add record to the database");
255 return STATUS_ERR;
256 }
257
dbase_policydb_set(semanage_handle_t * handle,dbase_policydb_t * dbase,const record_key_t * key,const record_t * data)258 static int dbase_policydb_set(semanage_handle_t * handle,
259 dbase_policydb_t * dbase,
260 const record_key_t * key, const record_t * data)
261 {
262
263 if (dbase->rptable->set(handle->sepolh, dbase->policydb, key, data) < 0)
264 goto err;
265
266 dbase->modified = 1;
267 return STATUS_SUCCESS;
268
269 err:
270 ERR(handle, "could not set record value");
271 return STATUS_ERR;
272 }
273
dbase_policydb_modify(semanage_handle_t * handle,dbase_policydb_t * dbase,const record_key_t * key,const record_t * data)274 static int dbase_policydb_modify(semanage_handle_t * handle,
275 dbase_policydb_t * dbase,
276 const record_key_t * key,
277 const record_t * data)
278 {
279
280 if (dbase->rptable->modify(handle->sepolh,
281 dbase->policydb, key, data) < 0)
282 goto err;
283
284 dbase->modified = 1;
285 return STATUS_SUCCESS;
286
287 err:
288 ERR(handle, "could not modify record value");
289 return STATUS_ERR;
290 }
291
dbase_policydb_del(semanage_handle_t * handle,dbase_policydb_t * dbase,const record_key_t * key)292 static int dbase_policydb_del(semanage_handle_t * handle
293 __attribute__ ((unused)),
294 dbase_policydb_t * dbase
295 __attribute__ ((unused)),
296 const record_key_t * key
297 __attribute__ ((unused)))
298 {
299
300 /* Stub */
301 key = NULL;
302 handle = NULL;
303 dbase = NULL;
304 return STATUS_ERR;
305 }
306
dbase_policydb_clear(semanage_handle_t * handle,dbase_policydb_t * dbase)307 static int dbase_policydb_clear(semanage_handle_t * handle
308 __attribute__ ((unused)),
309 dbase_policydb_t * dbase
310 __attribute__ ((unused)))
311 {
312
313 /* Stub */
314 handle = NULL;
315 dbase = NULL;
316 return STATUS_ERR;
317 }
318
dbase_policydb_query(semanage_handle_t * handle,dbase_policydb_t * dbase,const record_key_t * key,record_t ** response)319 static int dbase_policydb_query(semanage_handle_t * handle,
320 dbase_policydb_t * dbase,
321 const record_key_t * key, record_t ** response)
322 {
323
324 if (dbase->rptable->query(handle->sepolh,
325 dbase->policydb, key, response) < 0)
326 goto err;
327
328 return STATUS_SUCCESS;
329
330 err:
331 ERR(handle, "could not query record value");
332 return STATUS_ERR;
333 }
334
dbase_policydb_exists(semanage_handle_t * handle,dbase_policydb_t * dbase,const record_key_t * key,int * response)335 static int dbase_policydb_exists(semanage_handle_t * handle,
336 dbase_policydb_t * dbase,
337 const record_key_t * key, int *response)
338 {
339
340 if (dbase->rptable->exists(handle->sepolh,
341 dbase->policydb, key, response) < 0)
342 goto err;
343
344 return STATUS_SUCCESS;
345
346 err:
347 ERR(handle, "could not check if record exists");
348 return STATUS_ERR;
349 }
350
dbase_policydb_count(semanage_handle_t * handle,dbase_policydb_t * dbase,unsigned int * response)351 static int dbase_policydb_count(semanage_handle_t * handle,
352 dbase_policydb_t * dbase,
353 unsigned int *response)
354 {
355
356 if (dbase->rptable->count(handle->sepolh,
357 dbase->policydb, response) < 0)
358 goto err;
359
360 return STATUS_SUCCESS;
361
362 err:
363 ERR(handle, "could not count the database records");
364 return STATUS_ERR;
365 }
366
dbase_policydb_iterate(semanage_handle_t * handle,dbase_policydb_t * dbase,int (* fn)(const record_t * record,void * fn_arg),void * arg)367 static int dbase_policydb_iterate(semanage_handle_t * handle,
368 dbase_policydb_t * dbase,
369 int (*fn) (const record_t * record,
370 void *fn_arg), void *arg)
371 {
372
373 if (dbase->rptable->iterate(handle->sepolh,
374 dbase->policydb, fn, arg) < 0)
375 goto err;
376
377 return STATUS_SUCCESS;
378
379 err:
380 ERR(handle, "could not iterate over records");
381 return STATUS_ERR;
382 }
383
384 struct list_handler_arg {
385 semanage_handle_t *handle;
386 record_table_t *rtable;
387 record_t **records;
388 int pos;
389 };
390
list_handler(const record_t * record,void * varg)391 static int list_handler(const record_t * record, void *varg)
392 {
393
394 struct list_handler_arg *arg = (struct list_handler_arg *)varg;
395
396 if (arg->rtable->clone(arg->handle, record, &arg->records[arg->pos]) <
397 0)
398 return -1;
399 arg->pos++;
400 return 0;
401 }
402
dbase_policydb_list(semanage_handle_t * handle,dbase_t * dbase,record_t *** records,unsigned int * count)403 static int dbase_policydb_list(semanage_handle_t * handle,
404 dbase_t * dbase,
405 record_t *** records, unsigned int *count)
406 {
407
408 record_t **tmp_records = NULL;
409 unsigned int tmp_count;
410 struct list_handler_arg list_arg;
411 list_arg.pos = 0;
412 list_arg.rtable = dbase->rtable;
413 list_arg.handle = handle;
414
415 if (dbase->rptable->count(handle->sepolh,
416 dbase->policydb, &tmp_count) < 0)
417 goto err;
418
419 if (tmp_count > 0) {
420 tmp_records = (record_t **)
421 calloc(tmp_count, sizeof(record_t *));
422
423 if (tmp_records == NULL)
424 goto omem;
425
426 list_arg.records = tmp_records;
427
428 if (dbase->rptable->iterate(handle->sepolh,
429 dbase->policydb, list_handler,
430 &list_arg) < 0) {
431 ERR(handle, "list handler could not extract record");
432 goto err;
433 }
434 }
435
436 *records = tmp_records;
437 *count = tmp_count;
438 return STATUS_SUCCESS;
439
440 omem:
441 ERR(handle, "out of memory");
442
443 err:
444 if (tmp_records) {
445 for (; list_arg.pos >= 0; list_arg.pos--)
446 dbase->rtable->free(tmp_records[list_arg.pos]);
447 free(tmp_records);
448 }
449 ERR(handle, "could not list records");
450 return STATUS_ERR;
451 }
452
dbase_policydb_get_rtable(dbase_policydb_t * dbase)453 static record_table_t *dbase_policydb_get_rtable(dbase_policydb_t * dbase)
454 {
455
456 return dbase->rtable;
457 }
458
459 /* POLICYDB dbase - method table implementation */
460 dbase_table_t SEMANAGE_POLICYDB_DTABLE = {
461
462 /* Cache/Transactions */
463 .cache = dbase_policydb_cache,
464 .drop_cache = dbase_policydb_drop_cache,
465 .flush = dbase_policydb_flush,
466 .is_modified = dbase_policydb_is_modified,
467
468 /* Database Functionality */
469 .iterate = dbase_policydb_iterate,
470 .exists = dbase_policydb_exists,
471 .list = dbase_policydb_list,
472 .add = dbase_policydb_add,
473 .set = dbase_policydb_set,
474 .del = dbase_policydb_del,
475 .clear = dbase_policydb_clear,
476 .modify = dbase_policydb_modify,
477 .query = dbase_policydb_query,
478 .count = dbase_policydb_count,
479
480 /* Polymorphism */
481 .get_rtable = dbase_policydb_get_rtable
482 };
483