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 	handle = NULL;
    169 	return STATUS_ERR;
    170 }
    171 
    172 /* Check if modified */
    173 static int dbase_policydb_is_modified(dbase_policydb_t * dbase)
    174 {
    175 
    176 	return dbase->modified;
    177 }
    178 
    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 */
    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. */
    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. */
    235 void dbase_policydb_detach(dbase_policydb_t * dbase)
    236 {
    237 
    238 	dbase->attached = 0;
    239 	dbase->modified = 0;
    240 }
    241 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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