diff options
Diffstat (limited to 'libsemanage/src/database_policydb.c')
-rw-r--r-- | libsemanage/src/database_policydb.c | 495 |
1 files changed, 495 insertions, 0 deletions
diff --git a/libsemanage/src/database_policydb.c b/libsemanage/src/database_policydb.c new file mode 100644 index 00000000..839dcbe3 --- /dev/null +++ b/libsemanage/src/database_policydb.c @@ -0,0 +1,495 @@ +/* Copyright (C) 2005 Red Hat, Inc. */ + +/* Object: dbase_policydb_t (Policy) + * Implements: dbase_t (Database) + */ + +struct dbase_policydb; +typedef struct dbase_policydb dbase_t; +#define DBASE_DEFINED + +#include <stdlib.h> +#include <stddef.h> +#include <string.h> +#include <stdio.h> +#include <stdio_ext.h> +#include <errno.h> + +#include <sepol/policydb.h> + +#include "database_policydb.h" +#include "semanage_store.h" +#include "handle.h" +#include "debug.h" + +/* POLICYDB dbase */ +struct dbase_policydb { + + /* Backing file suffix */ + const char *suffix; + + /* Base record table */ + record_table_t *rtable; + + /* Policy extensions */ + record_policydb_table_t *rptable; + + sepol_policydb_t *policydb; + + int cache_serial; + int modified; + int attached; +}; + +static void dbase_policydb_drop_cache(dbase_policydb_t * dbase) +{ + + if (dbase->cache_serial >= 0) { + sepol_policydb_free(dbase->policydb); + dbase->cache_serial = -1; + dbase->modified = 0; + } +} + +static int dbase_policydb_set_serial(semanage_handle_t * handle, + dbase_policydb_t * dbase) +{ + + int cache_serial = handle->funcs->get_serial(handle); + if (cache_serial < 0) { + ERR(handle, "could not update cache serial"); + return STATUS_ERR; + } + + dbase->cache_serial = cache_serial; + return STATUS_SUCCESS; +} + +static int dbase_policydb_needs_resync(semanage_handle_t * handle, + dbase_policydb_t * dbase) +{ + + int cache_serial; + + if (dbase->cache_serial < 0) + return 1; + + cache_serial = handle->funcs->get_serial(handle); + if (cache_serial < 0) + return 1; + + if (cache_serial != dbase->cache_serial) { + dbase_policydb_drop_cache(dbase); + dbase->cache_serial = -1; + return 1; + } + return 0; +} + +static int construct_filename(semanage_handle_t * handle, + dbase_policydb_t * dbase, char **filename) +{ + + const char *path = (handle->is_in_transaction) ? + semanage_path(SEMANAGE_TMP, SEMANAGE_TOPLEVEL) : + semanage_path(SEMANAGE_ACTIVE, SEMANAGE_TOPLEVEL); + size_t fname_length = strlen(path) + strlen(dbase->suffix) + 2; + + char *fname = malloc(fname_length); + if (!fname) { + ERR(handle, "out of memory, could not construct database name"); + return STATUS_ERR; + } + snprintf(fname, fname_length, "%s/%s", path, dbase->suffix); + + *filename = fname; + return STATUS_SUCCESS; +} + +static int dbase_policydb_cache(semanage_handle_t * handle, + dbase_policydb_t * dbase) +{ + + FILE *fp = NULL; + sepol_policydb_t *policydb = NULL; + sepol_policy_file_t *pf = NULL; + char *fname = NULL; + + /* Check if cache is needed */ + if (dbase->attached) + return STATUS_SUCCESS; + + if (!dbase_policydb_needs_resync(handle, dbase)) + return STATUS_SUCCESS; + + if (construct_filename(handle, dbase, &fname) < 0) + goto err; + + if (sepol_policydb_create(&policydb) < 0) { + ERR(handle, "could not create policydb object"); + goto err; + } + + /* Try opening file + * ENOENT is not fatal - we just create an empty policydb */ + fp = fopen(fname, "rb"); + if (fp == NULL && errno != ENOENT) { + ERR(handle, "could not open %s for reading: %s", + fname, strerror(errno)); + goto err; + } + + /* If the file was opened successfully, read a policydb */ + if (fp != NULL) { + __fsetlocking(fp, FSETLOCKING_BYCALLER); + if (sepol_policy_file_create(&pf) < 0) { + ERR(handle, "could not create policy file object"); + goto err; + } + + sepol_policy_file_set_fp(pf, fp); + sepol_policy_file_set_handle(pf, handle->sepolh); + + if (sepol_policydb_read(policydb, pf) < 0) + goto err; + + sepol_policy_file_free(pf); + fclose(fp); + fp = NULL; + } + + /* Update cache serial */ + if (dbase_policydb_set_serial(handle, dbase) < 0) + goto err; + + /* Update the database policydb */ + dbase->policydb = policydb; + free(fname); + return STATUS_SUCCESS; + + err: + ERR(handle, "could not cache policy database"); + if (fp) + fclose(fp); + sepol_policydb_free(policydb); + sepol_policy_file_free(pf); + free(fname); + return STATUS_ERR; +} + +static int dbase_policydb_flush(semanage_handle_t * handle, + dbase_policydb_t * dbase) +{ + + if (!dbase->modified) + return STATUS_SUCCESS; + + dbase->modified = 0; + + /* Stub */ + handle = NULL; + return STATUS_ERR; +} + +/* Check if modified */ +static int dbase_policydb_is_modified(dbase_policydb_t * dbase) +{ + + return dbase->modified; +} + +int dbase_policydb_init(semanage_handle_t * handle, + const char *suffix, + record_table_t * rtable, + record_policydb_table_t * rptable, + dbase_policydb_t ** dbase) +{ + + dbase_policydb_t *tmp_dbase = + (dbase_policydb_t *) malloc(sizeof(dbase_policydb_t)); + + if (!tmp_dbase) + goto omem; + + tmp_dbase->suffix = suffix; + tmp_dbase->rtable = rtable; + tmp_dbase->rptable = rptable; + tmp_dbase->policydb = NULL; + tmp_dbase->cache_serial = -1; + tmp_dbase->modified = 0; + tmp_dbase->attached = 0; + *dbase = tmp_dbase; + + return STATUS_SUCCESS; + + omem: + ERR(handle, "out of memory, could not initialize policy database"); + free(tmp_dbase); + + return STATUS_ERR; +} + +/* Release dbase resources */ +void dbase_policydb_release(dbase_policydb_t * dbase) +{ + + dbase_policydb_drop_cache(dbase); + free(dbase); +} + +/* Attach to a shared policydb. + * This implies drop_cache(), + * and prevents flush() and drop_cache() + * until detached. */ +void dbase_policydb_attach(dbase_policydb_t * dbase, + sepol_policydb_t * policydb) +{ + + dbase->attached = 1; + dbase_policydb_drop_cache(dbase); + dbase->policydb = policydb; +} + +/* Detach from a shared policdb. + * This implies drop_cache. */ +void dbase_policydb_detach(dbase_policydb_t * dbase) +{ + + dbase->attached = 0; + dbase->modified = 0; +} + +static int dbase_policydb_add(semanage_handle_t * handle, + dbase_policydb_t * dbase, + const record_key_t * key, const record_t * data) +{ + + if (dbase->rptable->add(handle->sepolh, dbase->policydb, key, data) < 0) + goto err; + + dbase->modified = 1; + return STATUS_SUCCESS; + + err: + ERR(handle, "could not add record to the database"); + return STATUS_ERR; +} + +static int dbase_policydb_set(semanage_handle_t * handle, + dbase_policydb_t * dbase, + const record_key_t * key, const record_t * data) +{ + + if (dbase->rptable->set(handle->sepolh, dbase->policydb, key, data) < 0) + goto err; + + dbase->modified = 1; + return STATUS_SUCCESS; + + err: + ERR(handle, "could not set record value"); + return STATUS_ERR; +} + +static int dbase_policydb_modify(semanage_handle_t * handle, + dbase_policydb_t * dbase, + const record_key_t * key, + const record_t * data) +{ + + if (dbase->rptable->modify(handle->sepolh, + dbase->policydb, key, data) < 0) + goto err; + + dbase->modified = 1; + return STATUS_SUCCESS; + + err: + ERR(handle, "could not modify record value"); + return STATUS_ERR; +} + +static int dbase_policydb_del(semanage_handle_t * handle, + dbase_policydb_t * dbase, + const record_key_t * key) +{ + + /* Stub */ + key = NULL; + handle = NULL; + dbase = NULL; + return STATUS_ERR; +} + +static int dbase_policydb_clear(semanage_handle_t * handle, + dbase_policydb_t * dbase) +{ + + /* Stub */ + handle = NULL; + dbase = NULL; + return STATUS_ERR; +} + +static int dbase_policydb_query(semanage_handle_t * handle, + dbase_policydb_t * dbase, + const record_key_t * key, record_t ** response) +{ + + if (dbase->rptable->query(handle->sepolh, + dbase->policydb, key, response) < 0) + goto err; + + return STATUS_SUCCESS; + + err: + ERR(handle, "could not query record value"); + return STATUS_ERR; +} + +static int dbase_policydb_exists(semanage_handle_t * handle, + dbase_policydb_t * dbase, + const record_key_t * key, int *response) +{ + + if (dbase->rptable->exists(handle->sepolh, + dbase->policydb, key, response) < 0) + goto err; + + return STATUS_SUCCESS; + + err: + ERR(handle, "could not check if record exists"); + return STATUS_ERR; +} + +static int dbase_policydb_count(semanage_handle_t * handle, + dbase_policydb_t * dbase, + unsigned int *response) +{ + + if (dbase->rptable->count(handle->sepolh, + dbase->policydb, response) < 0) + goto err; + + return STATUS_SUCCESS; + + err: + ERR(handle, "could not count the database records"); + return STATUS_ERR; +} + +static int dbase_policydb_iterate(semanage_handle_t * handle, + dbase_policydb_t * dbase, + int (*fn) (const record_t * record, + void *fn_arg), void *arg) +{ + + if (dbase->rptable->iterate(handle->sepolh, + dbase->policydb, fn, arg) < 0) + goto err; + + return STATUS_SUCCESS; + + err: + ERR(handle, "could not iterate over records"); + return STATUS_ERR; +} + +struct list_handler_arg { + semanage_handle_t *handle; + record_table_t *rtable; + record_t **records; + int pos; +}; + +static int list_handler(const record_t * record, void *varg) +{ + + struct list_handler_arg *arg = (struct list_handler_arg *)varg; + + if (arg->rtable->clone(arg->handle, record, &arg->records[arg->pos]) < + 0) + return -1; + arg->pos++; + return 0; +} + +static int dbase_policydb_list(semanage_handle_t * handle, + dbase_t * dbase, + record_t *** records, unsigned int *count) +{ + + record_t **tmp_records = NULL; + unsigned int tmp_count; + struct list_handler_arg list_arg; + list_arg.pos = 0; + list_arg.rtable = dbase->rtable; + list_arg.handle = handle; + + if (dbase->rptable->count(handle->sepolh, + dbase->policydb, &tmp_count) < 0) + goto err; + + if (tmp_count > 0) { + tmp_records = (record_t **) + calloc(tmp_count, sizeof(record_t *)); + + if (tmp_records == NULL) + goto omem; + + list_arg.records = tmp_records; + + if (dbase->rptable->iterate(handle->sepolh, + dbase->policydb, list_handler, + &list_arg) < 0) { + ERR(handle, "list handler could not extract record"); + goto err; + } + } + + *records = tmp_records; + *count = tmp_count; + return STATUS_SUCCESS; + + omem: + ERR(handle, "out of memory"); + + err: + for (; list_arg.pos >= 0; list_arg.pos--) + dbase->rtable->free(tmp_records[list_arg.pos]); + free(tmp_records); + ERR(handle, "could not list records"); + return STATUS_ERR; +} + +static record_table_t *dbase_policydb_get_rtable(dbase_policydb_t * dbase) +{ + + return dbase->rtable; +} + +/* POLICYDB dbase - method table implementation */ +dbase_table_t SEMANAGE_POLICYDB_DTABLE = { + + /* Cache/Transactions */ + .cache = dbase_policydb_cache, + .drop_cache = dbase_policydb_drop_cache, + .flush = dbase_policydb_flush, + .is_modified = dbase_policydb_is_modified, + + /* Database Functionality */ + .iterate = dbase_policydb_iterate, + .exists = dbase_policydb_exists, + .list = dbase_policydb_list, + .add = dbase_policydb_add, + .set = dbase_policydb_set, + .del = dbase_policydb_del, + .clear = dbase_policydb_clear, + .modify = dbase_policydb_modify, + .query = dbase_policydb_query, + .count = dbase_policydb_count, + + /* Polymorphism */ + .get_rtable = dbase_policydb_get_rtable +}; |