• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 	return STATUS_ERR;
169 }
170 
171 /* Check if modified */
dbase_policydb_is_modified(dbase_policydb_t * dbase)172 static int dbase_policydb_is_modified(dbase_policydb_t * dbase)
173 {
174 
175 	return dbase->modified;
176 }
177 
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)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 */
dbase_policydb_release(dbase_policydb_t * dbase)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. */
dbase_policydb_attach(dbase_policydb_t * dbase,sepol_policydb_t * policydb)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. */
dbase_policydb_detach(dbase_policydb_t * dbase)234 void dbase_policydb_detach(dbase_policydb_t * dbase)
235 {
236 
237 	dbase->attached = 0;
238 	dbase->modified = 0;
239 }
240 
dbase_policydb_add(semanage_handle_t * handle,dbase_policydb_t * dbase,const record_key_t * key,const record_t * data)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 
dbase_policydb_set(semanage_handle_t * handle,dbase_policydb_t * dbase,const record_key_t * key,const record_t * data)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 
dbase_policydb_modify(semanage_handle_t * handle,dbase_policydb_t * dbase,const record_key_t * key,const record_t * data)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 
dbase_policydb_del(semanage_handle_t * handle,dbase_policydb_t * dbase,const record_key_t * key)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 
dbase_policydb_clear(semanage_handle_t * handle,dbase_policydb_t * dbase)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 
dbase_policydb_query(semanage_handle_t * handle,dbase_policydb_t * dbase,const record_key_t * key,record_t ** response)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 
dbase_policydb_exists(semanage_handle_t * handle,dbase_policydb_t * dbase,const record_key_t * key,int * response)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 
dbase_policydb_count(semanage_handle_t * handle,dbase_policydb_t * dbase,unsigned int * response)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 
dbase_policydb_iterate(semanage_handle_t * handle,dbase_policydb_t * dbase,int (* fn)(const record_t * record,void * fn_arg),void * arg)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 
list_handler(const record_t * record,void * varg)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 
dbase_policydb_list(semanage_handle_t * handle,dbase_t * dbase,record_t *** records,unsigned int * count)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 
dbase_policydb_get_rtable(dbase_policydb_t * dbase)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