Home | History | Annotate | Download | only in src
      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 
     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 
     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 
     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 
     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 
    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 */
    172 static int dbase_policydb_is_modified(dbase_policydb_t * dbase)
    173 {
    174 
    175 	return dbase->modified;
    176 }
    177 
    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 */
    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. */
    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. */
    234 void dbase_policydb_detach(dbase_policydb_t * dbase)
    235 {
    236 
    237 	dbase->attached = 0;
    238 	dbase->modified = 0;
    239 }
    240 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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