1/* Copyright (C) 2005 Red Hat, Inc. */ 2 3/* Object: dbase_policydb_t (Policy) 4 * Implements: dbase_t (Database) 5 */ 6 7struct dbase_policydb; 8typedef 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 */ 26struct 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 44static 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 54static 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 68static 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 89static 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 157static 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 */ 172static int dbase_policydb_is_modified(dbase_policydb_t * dbase) 173{ 174 175 return dbase->modified; 176} 177 178int 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 */ 212void 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. */ 223void 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. */ 234void dbase_policydb_detach(dbase_policydb_t * dbase) 235{ 236 237 dbase->attached = 0; 238 dbase->modified = 0; 239} 240 241static 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 257static 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 273static 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 291static 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 303static 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 313static 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 329static 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 345static 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 361static 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 378struct list_handler_arg { 379 semanage_handle_t *handle; 380 record_table_t *rtable; 381 record_t **records; 382 int pos; 383}; 384 385static 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 397static 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 447static 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 */ 454dbase_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