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