xref: /aosp_15_r20/external/selinux/libsemanage/src/database_file.c (revision 2d543d20722ada2425b5bdab9d0d1d29470e7bba)
1*2d543d20SAndroid Build Coastguard Worker /* Copyright (C) 2005 Red Hat, Inc. */
2*2d543d20SAndroid Build Coastguard Worker 
3*2d543d20SAndroid Build Coastguard Worker /* Object: dbase_file_t (File)
4*2d543d20SAndroid Build Coastguard Worker  * Extends: dbase_llist_t (Linked List)
5*2d543d20SAndroid Build Coastguard Worker  * Implements: dbase_t (Database)
6*2d543d20SAndroid Build Coastguard Worker  */
7*2d543d20SAndroid Build Coastguard Worker 
8*2d543d20SAndroid Build Coastguard Worker struct dbase_file;
9*2d543d20SAndroid Build Coastguard Worker typedef struct dbase_file dbase_t;
10*2d543d20SAndroid Build Coastguard Worker #define DBASE_DEFINED
11*2d543d20SAndroid Build Coastguard Worker 
12*2d543d20SAndroid Build Coastguard Worker #include <stdlib.h>
13*2d543d20SAndroid Build Coastguard Worker #include <stddef.h>
14*2d543d20SAndroid Build Coastguard Worker #include <string.h>
15*2d543d20SAndroid Build Coastguard Worker #include <errno.h>
16*2d543d20SAndroid Build Coastguard Worker #include <stdio.h>
17*2d543d20SAndroid Build Coastguard Worker #include <stdio_ext.h>
18*2d543d20SAndroid Build Coastguard Worker #include "debug.h"
19*2d543d20SAndroid Build Coastguard Worker #include "handle.h"
20*2d543d20SAndroid Build Coastguard Worker #include "parse_utils.h"
21*2d543d20SAndroid Build Coastguard Worker #include "database_file.h"
22*2d543d20SAndroid Build Coastguard Worker #include "database_llist.h"
23*2d543d20SAndroid Build Coastguard Worker #include "semanage_store.h"
24*2d543d20SAndroid Build Coastguard Worker 
25*2d543d20SAndroid Build Coastguard Worker /* FILE dbase */
26*2d543d20SAndroid Build Coastguard Worker struct dbase_file {
27*2d543d20SAndroid Build Coastguard Worker 
28*2d543d20SAndroid Build Coastguard Worker 	/* Parent object - must always be
29*2d543d20SAndroid Build Coastguard Worker 	 * the first field - here we are using
30*2d543d20SAndroid Build Coastguard Worker 	 * a linked list to store the records */
31*2d543d20SAndroid Build Coastguard Worker 	dbase_llist_t llist;
32*2d543d20SAndroid Build Coastguard Worker 
33*2d543d20SAndroid Build Coastguard Worker 	/* Backing path for read-only[0] and transaction[1] */
34*2d543d20SAndroid Build Coastguard Worker 	const char *path[2];
35*2d543d20SAndroid Build Coastguard Worker 
36*2d543d20SAndroid Build Coastguard Worker 	/* FILE extension */
37*2d543d20SAndroid Build Coastguard Worker 	record_file_table_t *rftable;
38*2d543d20SAndroid Build Coastguard Worker };
39*2d543d20SAndroid Build Coastguard Worker 
dbase_file_cache(semanage_handle_t * handle,dbase_file_t * dbase)40*2d543d20SAndroid Build Coastguard Worker static int dbase_file_cache(semanage_handle_t * handle, dbase_file_t * dbase)
41*2d543d20SAndroid Build Coastguard Worker {
42*2d543d20SAndroid Build Coastguard Worker 
43*2d543d20SAndroid Build Coastguard Worker 	record_table_t *rtable = dbase_llist_get_rtable(&dbase->llist);
44*2d543d20SAndroid Build Coastguard Worker 	record_file_table_t *rftable = dbase->rftable;
45*2d543d20SAndroid Build Coastguard Worker 
46*2d543d20SAndroid Build Coastguard Worker 	record_t *process_record = NULL;
47*2d543d20SAndroid Build Coastguard Worker 	int pstatus = STATUS_SUCCESS;
48*2d543d20SAndroid Build Coastguard Worker 
49*2d543d20SAndroid Build Coastguard Worker 	parse_info_t *parse_info = NULL;
50*2d543d20SAndroid Build Coastguard Worker 	const char *fname = NULL;
51*2d543d20SAndroid Build Coastguard Worker 
52*2d543d20SAndroid Build Coastguard Worker 	/* Already cached */
53*2d543d20SAndroid Build Coastguard Worker 	if (!dbase_llist_needs_resync(handle, &dbase->llist))
54*2d543d20SAndroid Build Coastguard Worker 		return STATUS_SUCCESS;
55*2d543d20SAndroid Build Coastguard Worker 
56*2d543d20SAndroid Build Coastguard Worker 	/* Update cache serial */
57*2d543d20SAndroid Build Coastguard Worker 	dbase_llist_cache_init(&dbase->llist);
58*2d543d20SAndroid Build Coastguard Worker 	if (dbase_llist_set_serial(handle, &dbase->llist) < 0)
59*2d543d20SAndroid Build Coastguard Worker 		goto err;
60*2d543d20SAndroid Build Coastguard Worker 
61*2d543d20SAndroid Build Coastguard Worker 	fname = dbase->path[handle->is_in_transaction];
62*2d543d20SAndroid Build Coastguard Worker 
63*2d543d20SAndroid Build Coastguard Worker 	if (parse_init(handle, fname, NULL, &parse_info) < 0)
64*2d543d20SAndroid Build Coastguard Worker 		goto err;
65*2d543d20SAndroid Build Coastguard Worker 
66*2d543d20SAndroid Build Coastguard Worker 	if (parse_open(handle, parse_info) < 0)
67*2d543d20SAndroid Build Coastguard Worker 		goto err;
68*2d543d20SAndroid Build Coastguard Worker 
69*2d543d20SAndroid Build Coastguard Worker 	/* Main processing loop */
70*2d543d20SAndroid Build Coastguard Worker 	do {
71*2d543d20SAndroid Build Coastguard Worker 
72*2d543d20SAndroid Build Coastguard Worker 		/* Create record */
73*2d543d20SAndroid Build Coastguard Worker 		if (rtable->create(handle, &process_record) < 0)
74*2d543d20SAndroid Build Coastguard Worker 			goto err;
75*2d543d20SAndroid Build Coastguard Worker 
76*2d543d20SAndroid Build Coastguard Worker 		/* Parse record */
77*2d543d20SAndroid Build Coastguard Worker 		pstatus = rftable->parse(handle, parse_info, process_record);
78*2d543d20SAndroid Build Coastguard Worker 
79*2d543d20SAndroid Build Coastguard Worker 		/* Parse error */
80*2d543d20SAndroid Build Coastguard Worker 		if (pstatus < 0)
81*2d543d20SAndroid Build Coastguard Worker 			goto err;
82*2d543d20SAndroid Build Coastguard Worker 
83*2d543d20SAndroid Build Coastguard Worker 		/* End of file */
84*2d543d20SAndroid Build Coastguard Worker 		else if (pstatus == STATUS_NODATA)
85*2d543d20SAndroid Build Coastguard Worker 			break;
86*2d543d20SAndroid Build Coastguard Worker 
87*2d543d20SAndroid Build Coastguard Worker 		/* Prepend to cache */
88*2d543d20SAndroid Build Coastguard Worker 		if (dbase_llist_cache_prepend(handle, &dbase->llist,
89*2d543d20SAndroid Build Coastguard Worker 					      process_record) < 0)
90*2d543d20SAndroid Build Coastguard Worker 			goto err;
91*2d543d20SAndroid Build Coastguard Worker 
92*2d543d20SAndroid Build Coastguard Worker 		rtable->free(process_record);
93*2d543d20SAndroid Build Coastguard Worker 		process_record = NULL;
94*2d543d20SAndroid Build Coastguard Worker 
95*2d543d20SAndroid Build Coastguard Worker 	} while (pstatus != STATUS_NODATA);
96*2d543d20SAndroid Build Coastguard Worker 
97*2d543d20SAndroid Build Coastguard Worker 	rtable->free(process_record);
98*2d543d20SAndroid Build Coastguard Worker 	parse_close(parse_info);
99*2d543d20SAndroid Build Coastguard Worker 	parse_release(parse_info);
100*2d543d20SAndroid Build Coastguard Worker 	return STATUS_SUCCESS;
101*2d543d20SAndroid Build Coastguard Worker 
102*2d543d20SAndroid Build Coastguard Worker       err:
103*2d543d20SAndroid Build Coastguard Worker 	ERR(handle, "could not cache file database");
104*2d543d20SAndroid Build Coastguard Worker 	rtable->free(process_record);
105*2d543d20SAndroid Build Coastguard Worker 	if (parse_info) {
106*2d543d20SAndroid Build Coastguard Worker 		parse_close(parse_info);
107*2d543d20SAndroid Build Coastguard Worker 		parse_release(parse_info);
108*2d543d20SAndroid Build Coastguard Worker 	}
109*2d543d20SAndroid Build Coastguard Worker 	dbase_llist_drop_cache(&dbase->llist);
110*2d543d20SAndroid Build Coastguard Worker 	return STATUS_ERR;
111*2d543d20SAndroid Build Coastguard Worker }
112*2d543d20SAndroid Build Coastguard Worker 
113*2d543d20SAndroid Build Coastguard Worker /* Flush database to file */
dbase_file_flush(semanage_handle_t * handle,dbase_file_t * dbase)114*2d543d20SAndroid Build Coastguard Worker static int dbase_file_flush(semanage_handle_t * handle, dbase_file_t * dbase)
115*2d543d20SAndroid Build Coastguard Worker {
116*2d543d20SAndroid Build Coastguard Worker 
117*2d543d20SAndroid Build Coastguard Worker 	record_file_table_t *rftable = dbase->rftable;
118*2d543d20SAndroid Build Coastguard Worker 
119*2d543d20SAndroid Build Coastguard Worker 	cache_entry_t *ptr;
120*2d543d20SAndroid Build Coastguard Worker 	const char *fname = NULL;
121*2d543d20SAndroid Build Coastguard Worker 	FILE *str = NULL;
122*2d543d20SAndroid Build Coastguard Worker 	mode_t mask;
123*2d543d20SAndroid Build Coastguard Worker 
124*2d543d20SAndroid Build Coastguard Worker 	if (!dbase_llist_is_modified(&dbase->llist))
125*2d543d20SAndroid Build Coastguard Worker 		return STATUS_SUCCESS;
126*2d543d20SAndroid Build Coastguard Worker 
127*2d543d20SAndroid Build Coastguard Worker 	fname = dbase->path[handle->is_in_transaction];
128*2d543d20SAndroid Build Coastguard Worker 
129*2d543d20SAndroid Build Coastguard Worker 	mask = umask(0077);
130*2d543d20SAndroid Build Coastguard Worker 	str = fopen(fname, "w");
131*2d543d20SAndroid Build Coastguard Worker 	umask(mask);
132*2d543d20SAndroid Build Coastguard Worker 	if (!str) {
133*2d543d20SAndroid Build Coastguard Worker 		ERR(handle, "could not open %s for writing: %s",
134*2d543d20SAndroid Build Coastguard Worker 		    fname, strerror(errno));
135*2d543d20SAndroid Build Coastguard Worker 		goto err;
136*2d543d20SAndroid Build Coastguard Worker 	}
137*2d543d20SAndroid Build Coastguard Worker 	__fsetlocking(str, FSETLOCKING_BYCALLER);
138*2d543d20SAndroid Build Coastguard Worker 
139*2d543d20SAndroid Build Coastguard Worker 	if (fprintf(str, "# This file is auto-generated by libsemanage\n"
140*2d543d20SAndroid Build Coastguard Worker 		    "# Do not edit directly.\n\n") < 0) {
141*2d543d20SAndroid Build Coastguard Worker 
142*2d543d20SAndroid Build Coastguard Worker 		ERR(handle, "could not write file header for %s", fname);
143*2d543d20SAndroid Build Coastguard Worker 		goto err;
144*2d543d20SAndroid Build Coastguard Worker 	}
145*2d543d20SAndroid Build Coastguard Worker 
146*2d543d20SAndroid Build Coastguard Worker 	for (ptr = dbase->llist.cache_tail; ptr != NULL; ptr = ptr->prev) {
147*2d543d20SAndroid Build Coastguard Worker 		if (rftable->print(handle, ptr->data, str) < 0)
148*2d543d20SAndroid Build Coastguard Worker 			goto err;
149*2d543d20SAndroid Build Coastguard Worker 	}
150*2d543d20SAndroid Build Coastguard Worker 
151*2d543d20SAndroid Build Coastguard Worker 	dbase_llist_set_modified(&dbase->llist, 0);
152*2d543d20SAndroid Build Coastguard Worker 	fclose(str);
153*2d543d20SAndroid Build Coastguard Worker 	return STATUS_SUCCESS;
154*2d543d20SAndroid Build Coastguard Worker 
155*2d543d20SAndroid Build Coastguard Worker       err:
156*2d543d20SAndroid Build Coastguard Worker 	if (str != NULL)
157*2d543d20SAndroid Build Coastguard Worker 		fclose(str);
158*2d543d20SAndroid Build Coastguard Worker 
159*2d543d20SAndroid Build Coastguard Worker 	ERR(handle, "could not flush database to file");
160*2d543d20SAndroid Build Coastguard Worker 	return STATUS_ERR;
161*2d543d20SAndroid Build Coastguard Worker }
162*2d543d20SAndroid Build Coastguard Worker 
dbase_file_init(semanage_handle_t * handle,const char * path_ro,const char * path_rw,record_table_t * rtable,record_file_table_t * rftable,dbase_file_t ** dbase)163*2d543d20SAndroid Build Coastguard Worker int dbase_file_init(semanage_handle_t * handle,
164*2d543d20SAndroid Build Coastguard Worker 		    const char *path_ro,
165*2d543d20SAndroid Build Coastguard Worker 		    const char *path_rw,
166*2d543d20SAndroid Build Coastguard Worker 		    record_table_t * rtable,
167*2d543d20SAndroid Build Coastguard Worker 		    record_file_table_t * rftable, dbase_file_t ** dbase)
168*2d543d20SAndroid Build Coastguard Worker {
169*2d543d20SAndroid Build Coastguard Worker 
170*2d543d20SAndroid Build Coastguard Worker 	dbase_file_t *tmp_dbase = (dbase_file_t *) malloc(sizeof(dbase_file_t));
171*2d543d20SAndroid Build Coastguard Worker 
172*2d543d20SAndroid Build Coastguard Worker 	if (!tmp_dbase)
173*2d543d20SAndroid Build Coastguard Worker 		goto omem;
174*2d543d20SAndroid Build Coastguard Worker 
175*2d543d20SAndroid Build Coastguard Worker 	tmp_dbase->path[0] = path_ro;
176*2d543d20SAndroid Build Coastguard Worker 	tmp_dbase->path[1] = path_rw;
177*2d543d20SAndroid Build Coastguard Worker 	tmp_dbase->rftable = rftable;
178*2d543d20SAndroid Build Coastguard Worker 	dbase_llist_init(&tmp_dbase->llist, rtable, &SEMANAGE_FILE_DTABLE);
179*2d543d20SAndroid Build Coastguard Worker 
180*2d543d20SAndroid Build Coastguard Worker 	*dbase = tmp_dbase;
181*2d543d20SAndroid Build Coastguard Worker 
182*2d543d20SAndroid Build Coastguard Worker 	return STATUS_SUCCESS;
183*2d543d20SAndroid Build Coastguard Worker 
184*2d543d20SAndroid Build Coastguard Worker       omem:
185*2d543d20SAndroid Build Coastguard Worker 	ERR(handle, "out of memory, could not initialize file database");
186*2d543d20SAndroid Build Coastguard Worker 	free(tmp_dbase);
187*2d543d20SAndroid Build Coastguard Worker 	return STATUS_ERR;
188*2d543d20SAndroid Build Coastguard Worker }
189*2d543d20SAndroid Build Coastguard Worker 
190*2d543d20SAndroid Build Coastguard Worker /* Release dbase resources */
dbase_file_release(dbase_file_t * dbase)191*2d543d20SAndroid Build Coastguard Worker void dbase_file_release(dbase_file_t * dbase)
192*2d543d20SAndroid Build Coastguard Worker {
193*2d543d20SAndroid Build Coastguard Worker 
194*2d543d20SAndroid Build Coastguard Worker 	dbase_llist_drop_cache(&dbase->llist);
195*2d543d20SAndroid Build Coastguard Worker 	free(dbase);
196*2d543d20SAndroid Build Coastguard Worker }
197*2d543d20SAndroid Build Coastguard Worker 
198*2d543d20SAndroid Build Coastguard Worker /* FILE dbase - method table implementation */
199*2d543d20SAndroid Build Coastguard Worker dbase_table_t SEMANAGE_FILE_DTABLE = {
200*2d543d20SAndroid Build Coastguard Worker 
201*2d543d20SAndroid Build Coastguard Worker 	/* Cache/Transactions */
202*2d543d20SAndroid Build Coastguard Worker 	.cache = dbase_file_cache,
203*2d543d20SAndroid Build Coastguard Worker 	.drop_cache = (void *)dbase_llist_drop_cache,
204*2d543d20SAndroid Build Coastguard Worker 	.flush = dbase_file_flush,
205*2d543d20SAndroid Build Coastguard Worker 	.is_modified = (void *)dbase_llist_is_modified,
206*2d543d20SAndroid Build Coastguard Worker 
207*2d543d20SAndroid Build Coastguard Worker 	/* Database API */
208*2d543d20SAndroid Build Coastguard Worker 	.iterate = (void *)dbase_llist_iterate,
209*2d543d20SAndroid Build Coastguard Worker 	.exists = (void *)dbase_llist_exists,
210*2d543d20SAndroid Build Coastguard Worker 	.list = (void *)dbase_llist_list,
211*2d543d20SAndroid Build Coastguard Worker 	.add = (void *)dbase_llist_add,
212*2d543d20SAndroid Build Coastguard Worker 	.set = (void *)dbase_llist_set,
213*2d543d20SAndroid Build Coastguard Worker 	.del = (void *)dbase_llist_del,
214*2d543d20SAndroid Build Coastguard Worker 	.clear = (void *)dbase_llist_clear,
215*2d543d20SAndroid Build Coastguard Worker 	.modify = (void *)dbase_llist_modify,
216*2d543d20SAndroid Build Coastguard Worker 	.query = (void *)dbase_llist_query,
217*2d543d20SAndroid Build Coastguard Worker 	.count = (void *)dbase_llist_count,
218*2d543d20SAndroid Build Coastguard Worker 
219*2d543d20SAndroid Build Coastguard Worker 	/* Polymorphism */
220*2d543d20SAndroid Build Coastguard Worker 	.get_rtable = (void *)dbase_llist_get_rtable
221*2d543d20SAndroid Build Coastguard Worker };
222