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 
dbase_policydb_drop_cache(dbase_policydb_t * dbase)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 
dbase_policydb_set_serial(semanage_handle_t * handle,dbase_policydb_t * dbase)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 
dbase_policydb_needs_resync(semanage_handle_t * handle,dbase_policydb_t * dbase)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 
dbase_policydb_cache(semanage_handle_t * handle,dbase_policydb_t * dbase)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 
dbase_policydb_flush(semanage_handle_t * handle,dbase_policydb_t * dbase)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 */
dbase_policydb_is_modified(dbase_policydb_t * dbase)173 static int dbase_policydb_is_modified(dbase_policydb_t * dbase)
174 {
175 
176 	return dbase->modified;
177 }
178 
dbase_policydb_init(semanage_handle_t * handle,const char * path_ro,const char * path_rw,record_table_t * rtable,record_policydb_table_t * rptable,dbase_policydb_t ** dbase)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 */
dbase_policydb_release(dbase_policydb_t * dbase)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. */
dbase_policydb_attach(dbase_policydb_t * dbase,sepol_policydb_t * policydb)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. */
dbase_policydb_detach(dbase_policydb_t * dbase)235 void dbase_policydb_detach(dbase_policydb_t * dbase)
236 {
237 
238 	dbase->attached = 0;
239 	dbase->modified = 0;
240 }
241 
dbase_policydb_add(semanage_handle_t * handle,dbase_policydb_t * dbase,const record_key_t * key,const record_t * data)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 
dbase_policydb_set(semanage_handle_t * handle,dbase_policydb_t * dbase,const record_key_t * key,const record_t * data)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 
dbase_policydb_modify(semanage_handle_t * handle,dbase_policydb_t * dbase,const record_key_t * key,const record_t * data)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 
dbase_policydb_del(semanage_handle_t * handle,dbase_policydb_t * dbase,const record_key_t * key)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 
dbase_policydb_clear(semanage_handle_t * handle,dbase_policydb_t * dbase)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 
dbase_policydb_query(semanage_handle_t * handle,dbase_policydb_t * dbase,const record_key_t * key,record_t ** response)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 
dbase_policydb_exists(semanage_handle_t * handle,dbase_policydb_t * dbase,const record_key_t * key,int * response)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 
dbase_policydb_count(semanage_handle_t * handle,dbase_policydb_t * dbase,unsigned int * response)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 
dbase_policydb_iterate(semanage_handle_t * handle,dbase_policydb_t * dbase,int (* fn)(const record_t * record,void * fn_arg),void * arg)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 
list_handler(const record_t * record,void * varg)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 
dbase_policydb_list(semanage_handle_t * handle,dbase_t * dbase,record_t *** records,unsigned int * count)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 
dbase_policydb_get_rtable(dbase_policydb_t * dbase)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