aboutsummaryrefslogtreecommitdiffstats
path: root/libsemanage/src/database_policydb.c
diff options
context:
space:
mode:
Diffstat (limited to 'libsemanage/src/database_policydb.c')
-rw-r--r--libsemanage/src/database_policydb.c495
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
+};