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