xref: /aosp_15_r20/external/selinux/libselinux/src/label_backends_android.c (revision 2d543d20722ada2425b5bdab9d0d1d29470e7bba)
1*2d543d20SAndroid Build Coastguard Worker /*
2*2d543d20SAndroid Build Coastguard Worker  * Property Service contexts backend for labeling Android
3*2d543d20SAndroid Build Coastguard Worker  * property keys
4*2d543d20SAndroid Build Coastguard Worker  */
5*2d543d20SAndroid Build Coastguard Worker 
6*2d543d20SAndroid Build Coastguard Worker #include <stdarg.h>
7*2d543d20SAndroid Build Coastguard Worker #include <string.h>
8*2d543d20SAndroid Build Coastguard Worker #include <ctype.h>
9*2d543d20SAndroid Build Coastguard Worker #include <errno.h>
10*2d543d20SAndroid Build Coastguard Worker #include <limits.h>
11*2d543d20SAndroid Build Coastguard Worker #include <sys/types.h>
12*2d543d20SAndroid Build Coastguard Worker #include <sys/stat.h>
13*2d543d20SAndroid Build Coastguard Worker #include "callbacks.h"
14*2d543d20SAndroid Build Coastguard Worker #include "label_internal.h"
15*2d543d20SAndroid Build Coastguard Worker 
16*2d543d20SAndroid Build Coastguard Worker /* A property security context specification. */
17*2d543d20SAndroid Build Coastguard Worker typedef struct spec {
18*2d543d20SAndroid Build Coastguard Worker 	struct selabel_lookup_rec lr;	/* holds contexts for lookup result */
19*2d543d20SAndroid Build Coastguard Worker 	char *property_key;		/* property key string */
20*2d543d20SAndroid Build Coastguard Worker } spec_t;
21*2d543d20SAndroid Build Coastguard Worker 
22*2d543d20SAndroid Build Coastguard Worker /* Our stored configuration */
23*2d543d20SAndroid Build Coastguard Worker struct saved_data {
24*2d543d20SAndroid Build Coastguard Worker 	/*
25*2d543d20SAndroid Build Coastguard Worker 	 * The array of specifications is sorted for longest
26*2d543d20SAndroid Build Coastguard Worker 	 * prefix match
27*2d543d20SAndroid Build Coastguard Worker 	 */
28*2d543d20SAndroid Build Coastguard Worker 	spec_t *spec_arr;
29*2d543d20SAndroid Build Coastguard Worker 	unsigned int nspec;	/* total number of specifications */
30*2d543d20SAndroid Build Coastguard Worker };
31*2d543d20SAndroid Build Coastguard Worker 
cmp(const void * A,const void * B)32*2d543d20SAndroid Build Coastguard Worker static int cmp(const void *A, const void *B)
33*2d543d20SAndroid Build Coastguard Worker {
34*2d543d20SAndroid Build Coastguard Worker 	const struct spec *sp1 = A, *sp2 = B;
35*2d543d20SAndroid Build Coastguard Worker 
36*2d543d20SAndroid Build Coastguard Worker 	if (strncmp(sp1->property_key, "*", 1) == 0)
37*2d543d20SAndroid Build Coastguard Worker 		return 1;
38*2d543d20SAndroid Build Coastguard Worker 	if (strncmp(sp2->property_key, "*", 1) == 0)
39*2d543d20SAndroid Build Coastguard Worker 		return -1;
40*2d543d20SAndroid Build Coastguard Worker 
41*2d543d20SAndroid Build Coastguard Worker 	size_t L1 = strlen(sp1->property_key);
42*2d543d20SAndroid Build Coastguard Worker 	size_t L2 = strlen(sp2->property_key);
43*2d543d20SAndroid Build Coastguard Worker 
44*2d543d20SAndroid Build Coastguard Worker 	return (L1 < L2) - (L1 > L2);
45*2d543d20SAndroid Build Coastguard Worker }
46*2d543d20SAndroid Build Coastguard Worker 
47*2d543d20SAndroid Build Coastguard Worker /*
48*2d543d20SAndroid Build Coastguard Worker  * Warn about duplicate specifications. Return error on different specifications.
49*2d543d20SAndroid Build Coastguard Worker  * TODO: Remove duplicate specifications. Move duplicate check to after sort
50*2d543d20SAndroid Build Coastguard Worker  * to improve performance.
51*2d543d20SAndroid Build Coastguard Worker  */
nodups_specs(struct saved_data * data)52*2d543d20SAndroid Build Coastguard Worker static int nodups_specs(struct saved_data *data)
53*2d543d20SAndroid Build Coastguard Worker {
54*2d543d20SAndroid Build Coastguard Worker 	int rc = 0;
55*2d543d20SAndroid Build Coastguard Worker 	unsigned int ii, jj;
56*2d543d20SAndroid Build Coastguard Worker 	struct spec *curr_spec, *spec_arr = data->spec_arr;
57*2d543d20SAndroid Build Coastguard Worker 
58*2d543d20SAndroid Build Coastguard Worker 	for (ii = 0; ii < data->nspec; ii++) {
59*2d543d20SAndroid Build Coastguard Worker 		curr_spec = &spec_arr[ii];
60*2d543d20SAndroid Build Coastguard Worker 		for (jj = ii + 1; jj < data->nspec; jj++) {
61*2d543d20SAndroid Build Coastguard Worker 			if (!strcmp(spec_arr[jj].property_key,
62*2d543d20SAndroid Build Coastguard Worker 					    curr_spec->property_key)) {
63*2d543d20SAndroid Build Coastguard Worker 				if (strcmp(spec_arr[jj].lr.ctx_raw,
64*2d543d20SAndroid Build Coastguard Worker 						    curr_spec->lr.ctx_raw)) {
65*2d543d20SAndroid Build Coastguard Worker 					rc = -1;
66*2d543d20SAndroid Build Coastguard Worker 					errno = EINVAL;
67*2d543d20SAndroid Build Coastguard Worker 					selinux_log
68*2d543d20SAndroid Build Coastguard Worker 						(SELINUX_ERROR,
69*2d543d20SAndroid Build Coastguard Worker 						 "Multiple different specifications for %s  (%s and %s).\n",
70*2d543d20SAndroid Build Coastguard Worker 						 curr_spec->property_key,
71*2d543d20SAndroid Build Coastguard Worker 						 spec_arr[jj].lr.ctx_raw,
72*2d543d20SAndroid Build Coastguard Worker 						 curr_spec->lr.ctx_raw);
73*2d543d20SAndroid Build Coastguard Worker 				} else {
74*2d543d20SAndroid Build Coastguard Worker 					selinux_log
75*2d543d20SAndroid Build Coastguard Worker 						(SELINUX_WARNING,
76*2d543d20SAndroid Build Coastguard Worker 						 "Multiple same specifications for %s.\n",
77*2d543d20SAndroid Build Coastguard Worker 						 curr_spec->property_key);
78*2d543d20SAndroid Build Coastguard Worker 				}
79*2d543d20SAndroid Build Coastguard Worker 			}
80*2d543d20SAndroid Build Coastguard Worker 		}
81*2d543d20SAndroid Build Coastguard Worker 	}
82*2d543d20SAndroid Build Coastguard Worker 	return rc;
83*2d543d20SAndroid Build Coastguard Worker }
84*2d543d20SAndroid Build Coastguard Worker 
process_line(struct selabel_handle * rec,const char * path,char * line_buf,int pass,unsigned lineno)85*2d543d20SAndroid Build Coastguard Worker static int process_line(struct selabel_handle *rec,
86*2d543d20SAndroid Build Coastguard Worker 			const char *path, char *line_buf,
87*2d543d20SAndroid Build Coastguard Worker 			int pass, unsigned lineno)
88*2d543d20SAndroid Build Coastguard Worker {
89*2d543d20SAndroid Build Coastguard Worker 	int items;
90*2d543d20SAndroid Build Coastguard Worker 	char *prop = NULL, *context = NULL;
91*2d543d20SAndroid Build Coastguard Worker 	struct saved_data *data = (struct saved_data *)rec->data;
92*2d543d20SAndroid Build Coastguard Worker 	spec_t *spec_arr = data->spec_arr;
93*2d543d20SAndroid Build Coastguard Worker 	unsigned int nspec = data->nspec;
94*2d543d20SAndroid Build Coastguard Worker 	const char *errbuf = NULL;
95*2d543d20SAndroid Build Coastguard Worker 
96*2d543d20SAndroid Build Coastguard Worker 	items = read_spec_entries(line_buf, &errbuf, 2, &prop, &context);
97*2d543d20SAndroid Build Coastguard Worker 	if (items < 0) {
98*2d543d20SAndroid Build Coastguard Worker 		if (errbuf) {
99*2d543d20SAndroid Build Coastguard Worker 			selinux_log(SELINUX_ERROR,
100*2d543d20SAndroid Build Coastguard Worker 				    "%s:  line %u error due to: %s\n", path,
101*2d543d20SAndroid Build Coastguard Worker 				    lineno, errbuf);
102*2d543d20SAndroid Build Coastguard Worker 		} else {
103*2d543d20SAndroid Build Coastguard Worker 			selinux_log(SELINUX_ERROR,
104*2d543d20SAndroid Build Coastguard Worker 				    "%s:  line %u error due to: %m\n", path,
105*2d543d20SAndroid Build Coastguard Worker 				    lineno);
106*2d543d20SAndroid Build Coastguard Worker 		}
107*2d543d20SAndroid Build Coastguard Worker 		return -1;
108*2d543d20SAndroid Build Coastguard Worker 	}
109*2d543d20SAndroid Build Coastguard Worker 
110*2d543d20SAndroid Build Coastguard Worker 	if (items == 0)
111*2d543d20SAndroid Build Coastguard Worker 		return items;
112*2d543d20SAndroid Build Coastguard Worker 
113*2d543d20SAndroid Build Coastguard Worker 	if (items != 2) {
114*2d543d20SAndroid Build Coastguard Worker 		selinux_log(SELINUX_ERROR,
115*2d543d20SAndroid Build Coastguard Worker 			    "%s:  line %u is missing fields\n", path,
116*2d543d20SAndroid Build Coastguard Worker 			    lineno);
117*2d543d20SAndroid Build Coastguard Worker 		free(prop);
118*2d543d20SAndroid Build Coastguard Worker 		errno = EINVAL;
119*2d543d20SAndroid Build Coastguard Worker 		return -1;
120*2d543d20SAndroid Build Coastguard Worker 	}
121*2d543d20SAndroid Build Coastguard Worker 
122*2d543d20SAndroid Build Coastguard Worker 	if (pass == 0) {
123*2d543d20SAndroid Build Coastguard Worker 		free(prop);
124*2d543d20SAndroid Build Coastguard Worker 		free(context);
125*2d543d20SAndroid Build Coastguard Worker 	} else if (pass == 1) {
126*2d543d20SAndroid Build Coastguard Worker 		/* On the second pass, process and store the specification in spec. */
127*2d543d20SAndroid Build Coastguard Worker 		spec_arr[nspec].property_key = prop;
128*2d543d20SAndroid Build Coastguard Worker 		spec_arr[nspec].lr.ctx_raw = context;
129*2d543d20SAndroid Build Coastguard Worker 
130*2d543d20SAndroid Build Coastguard Worker 		if (rec->validating) {
131*2d543d20SAndroid Build Coastguard Worker 			if (selabel_validate(&spec_arr[nspec].lr) < 0) {
132*2d543d20SAndroid Build Coastguard Worker 				selinux_log(SELINUX_ERROR,
133*2d543d20SAndroid Build Coastguard Worker 					    "%s:  line %u has invalid context %s\n",
134*2d543d20SAndroid Build Coastguard Worker 					    path, lineno, spec_arr[nspec].lr.ctx_raw);
135*2d543d20SAndroid Build Coastguard Worker 				errno = EINVAL;
136*2d543d20SAndroid Build Coastguard Worker 				return -1;
137*2d543d20SAndroid Build Coastguard Worker 			}
138*2d543d20SAndroid Build Coastguard Worker 		}
139*2d543d20SAndroid Build Coastguard Worker 
140*2d543d20SAndroid Build Coastguard Worker 		data->nspec = ++nspec;
141*2d543d20SAndroid Build Coastguard Worker 	}
142*2d543d20SAndroid Build Coastguard Worker 
143*2d543d20SAndroid Build Coastguard Worker 	return 0;
144*2d543d20SAndroid Build Coastguard Worker }
145*2d543d20SAndroid Build Coastguard Worker 
process_file(struct selabel_handle * rec,const char * path)146*2d543d20SAndroid Build Coastguard Worker static int process_file(struct selabel_handle *rec, const char *path)
147*2d543d20SAndroid Build Coastguard Worker {
148*2d543d20SAndroid Build Coastguard Worker 	struct saved_data *data = (struct saved_data *)rec->data;
149*2d543d20SAndroid Build Coastguard Worker 	char line_buf[BUFSIZ];
150*2d543d20SAndroid Build Coastguard Worker 	unsigned int lineno, maxnspec, pass;
151*2d543d20SAndroid Build Coastguard Worker 	struct stat sb;
152*2d543d20SAndroid Build Coastguard Worker 	FILE *fp;
153*2d543d20SAndroid Build Coastguard Worker 	int status = -1;
154*2d543d20SAndroid Build Coastguard Worker 	unsigned int nspec;
155*2d543d20SAndroid Build Coastguard Worker 	spec_t *spec_arr;
156*2d543d20SAndroid Build Coastguard Worker 
157*2d543d20SAndroid Build Coastguard Worker 	/* Open the specification file. */
158*2d543d20SAndroid Build Coastguard Worker 	if ((fp = fopen(path, "re")) == NULL)
159*2d543d20SAndroid Build Coastguard Worker 		return -1;
160*2d543d20SAndroid Build Coastguard Worker 
161*2d543d20SAndroid Build Coastguard Worker 	if (fstat(fileno(fp), &sb) < 0)
162*2d543d20SAndroid Build Coastguard Worker 		goto finish;
163*2d543d20SAndroid Build Coastguard Worker 
164*2d543d20SAndroid Build Coastguard Worker 	errno = EINVAL;
165*2d543d20SAndroid Build Coastguard Worker 
166*2d543d20SAndroid Build Coastguard Worker 	if (!S_ISREG(sb.st_mode))
167*2d543d20SAndroid Build Coastguard Worker 		goto finish;
168*2d543d20SAndroid Build Coastguard Worker 
169*2d543d20SAndroid Build Coastguard Worker 	/*
170*2d543d20SAndroid Build Coastguard Worker 	 * Two passes per specification file. First is to get the size.
171*2d543d20SAndroid Build Coastguard Worker 	 * After the first pass, the spec array is malloced / realloced to
172*2d543d20SAndroid Build Coastguard Worker 	 * the appropriate size. Second pass is to populate the spec array.
173*2d543d20SAndroid Build Coastguard Worker 	 */
174*2d543d20SAndroid Build Coastguard Worker 	maxnspec = UINT_MAX / sizeof(spec_t);
175*2d543d20SAndroid Build Coastguard Worker 	for (pass = 0; pass < 2; pass++) {
176*2d543d20SAndroid Build Coastguard Worker 		nspec = 0;
177*2d543d20SAndroid Build Coastguard Worker 		lineno = 0;
178*2d543d20SAndroid Build Coastguard Worker 
179*2d543d20SAndroid Build Coastguard Worker 		while (fgets(line_buf, sizeof(line_buf) - 1, fp) &&
180*2d543d20SAndroid Build Coastguard Worker 			nspec < maxnspec) {
181*2d543d20SAndroid Build Coastguard Worker 			if (process_line(rec, path, line_buf, pass, ++lineno))
182*2d543d20SAndroid Build Coastguard Worker 				goto finish;
183*2d543d20SAndroid Build Coastguard Worker 			nspec++;
184*2d543d20SAndroid Build Coastguard Worker 		}
185*2d543d20SAndroid Build Coastguard Worker 
186*2d543d20SAndroid Build Coastguard Worker 		if (pass == 0) {
187*2d543d20SAndroid Build Coastguard Worker 			if (nspec == 0) {
188*2d543d20SAndroid Build Coastguard Worker 				status = 0;
189*2d543d20SAndroid Build Coastguard Worker 				goto finish;
190*2d543d20SAndroid Build Coastguard Worker 			}
191*2d543d20SAndroid Build Coastguard Worker 
192*2d543d20SAndroid Build Coastguard Worker 			/* grow spec array if required */
193*2d543d20SAndroid Build Coastguard Worker 			spec_arr = realloc(data->spec_arr,
194*2d543d20SAndroid Build Coastguard Worker 					(data->nspec + nspec) * sizeof(spec_t));
195*2d543d20SAndroid Build Coastguard Worker 			if (spec_arr == NULL)
196*2d543d20SAndroid Build Coastguard Worker 				goto finish;
197*2d543d20SAndroid Build Coastguard Worker 
198*2d543d20SAndroid Build Coastguard Worker 			memset(&spec_arr[data->nspec], 0, nspec * sizeof(spec_t));
199*2d543d20SAndroid Build Coastguard Worker 			data->spec_arr = spec_arr;
200*2d543d20SAndroid Build Coastguard Worker 			maxnspec = nspec;
201*2d543d20SAndroid Build Coastguard Worker 			rewind(fp);
202*2d543d20SAndroid Build Coastguard Worker 		}
203*2d543d20SAndroid Build Coastguard Worker 	}
204*2d543d20SAndroid Build Coastguard Worker 
205*2d543d20SAndroid Build Coastguard Worker 	status = digest_add_specfile(rec->digest, fp, NULL, sb.st_size, path);
206*2d543d20SAndroid Build Coastguard Worker 
207*2d543d20SAndroid Build Coastguard Worker finish:
208*2d543d20SAndroid Build Coastguard Worker 	fclose(fp);
209*2d543d20SAndroid Build Coastguard Worker 	return status;
210*2d543d20SAndroid Build Coastguard Worker }
211*2d543d20SAndroid Build Coastguard Worker 
212*2d543d20SAndroid Build Coastguard Worker static void closef(struct selabel_handle *rec);
213*2d543d20SAndroid Build Coastguard Worker 
init(struct selabel_handle * rec,const struct selinux_opt * opts,unsigned n)214*2d543d20SAndroid Build Coastguard Worker static int init(struct selabel_handle *rec, const struct selinux_opt *opts,
215*2d543d20SAndroid Build Coastguard Worker 		unsigned n)
216*2d543d20SAndroid Build Coastguard Worker {
217*2d543d20SAndroid Build Coastguard Worker 	struct saved_data *data = (struct saved_data *)rec->data;
218*2d543d20SAndroid Build Coastguard Worker 	char **paths = NULL;
219*2d543d20SAndroid Build Coastguard Worker 	size_t num_paths = 0;
220*2d543d20SAndroid Build Coastguard Worker 	int status = -1;
221*2d543d20SAndroid Build Coastguard Worker 	size_t i;
222*2d543d20SAndroid Build Coastguard Worker 
223*2d543d20SAndroid Build Coastguard Worker 	/* Process arguments */
224*2d543d20SAndroid Build Coastguard Worker 	i = n;
225*2d543d20SAndroid Build Coastguard Worker 	while (i--) {
226*2d543d20SAndroid Build Coastguard Worker 		switch (opts[i].type) {
227*2d543d20SAndroid Build Coastguard Worker 		case SELABEL_OPT_PATH:
228*2d543d20SAndroid Build Coastguard Worker 			num_paths++;
229*2d543d20SAndroid Build Coastguard Worker 			break;
230*2d543d20SAndroid Build Coastguard Worker 		}
231*2d543d20SAndroid Build Coastguard Worker 	}
232*2d543d20SAndroid Build Coastguard Worker 
233*2d543d20SAndroid Build Coastguard Worker 	if (!num_paths)
234*2d543d20SAndroid Build Coastguard Worker 		return -1;
235*2d543d20SAndroid Build Coastguard Worker 
236*2d543d20SAndroid Build Coastguard Worker 	paths = calloc(num_paths, sizeof(*paths));
237*2d543d20SAndroid Build Coastguard Worker 	if (!paths)
238*2d543d20SAndroid Build Coastguard Worker 		return -1;
239*2d543d20SAndroid Build Coastguard Worker 
240*2d543d20SAndroid Build Coastguard Worker 	rec->spec_files = paths;
241*2d543d20SAndroid Build Coastguard Worker 	rec->spec_files_len = num_paths;
242*2d543d20SAndroid Build Coastguard Worker 
243*2d543d20SAndroid Build Coastguard Worker 	i = n;
244*2d543d20SAndroid Build Coastguard Worker 	while (i--) {
245*2d543d20SAndroid Build Coastguard Worker 		switch(opts[i].type) {
246*2d543d20SAndroid Build Coastguard Worker 		case SELABEL_OPT_PATH:
247*2d543d20SAndroid Build Coastguard Worker 			*paths = strdup(opts[i].value);
248*2d543d20SAndroid Build Coastguard Worker 			if (*paths == NULL)
249*2d543d20SAndroid Build Coastguard Worker 				goto finish;
250*2d543d20SAndroid Build Coastguard Worker 			paths++;
251*2d543d20SAndroid Build Coastguard Worker 		}
252*2d543d20SAndroid Build Coastguard Worker 	}
253*2d543d20SAndroid Build Coastguard Worker 
254*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < num_paths; i++) {
255*2d543d20SAndroid Build Coastguard Worker 		status = process_file(rec, rec->spec_files[i]);
256*2d543d20SAndroid Build Coastguard Worker 		if (status)
257*2d543d20SAndroid Build Coastguard Worker 			goto finish;
258*2d543d20SAndroid Build Coastguard Worker 	}
259*2d543d20SAndroid Build Coastguard Worker 
260*2d543d20SAndroid Build Coastguard Worker 	/* warn about duplicates after all files have been processed. */
261*2d543d20SAndroid Build Coastguard Worker 	status = nodups_specs(data);
262*2d543d20SAndroid Build Coastguard Worker 	if (status)
263*2d543d20SAndroid Build Coastguard Worker 		goto finish;
264*2d543d20SAndroid Build Coastguard Worker 
265*2d543d20SAndroid Build Coastguard Worker 	qsort(data->spec_arr, data->nspec, sizeof(struct spec), cmp);
266*2d543d20SAndroid Build Coastguard Worker 
267*2d543d20SAndroid Build Coastguard Worker 	digest_gen_hash(rec->digest);
268*2d543d20SAndroid Build Coastguard Worker 
269*2d543d20SAndroid Build Coastguard Worker finish:
270*2d543d20SAndroid Build Coastguard Worker 	if (status)
271*2d543d20SAndroid Build Coastguard Worker 		closef(rec);
272*2d543d20SAndroid Build Coastguard Worker 
273*2d543d20SAndroid Build Coastguard Worker 	return status;
274*2d543d20SAndroid Build Coastguard Worker }
275*2d543d20SAndroid Build Coastguard Worker 
276*2d543d20SAndroid Build Coastguard Worker /*
277*2d543d20SAndroid Build Coastguard Worker  * Backend interface routines
278*2d543d20SAndroid Build Coastguard Worker  */
closef(struct selabel_handle * rec)279*2d543d20SAndroid Build Coastguard Worker static void closef(struct selabel_handle *rec)
280*2d543d20SAndroid Build Coastguard Worker {
281*2d543d20SAndroid Build Coastguard Worker 	struct saved_data *data = (struct saved_data *)rec->data;
282*2d543d20SAndroid Build Coastguard Worker 	struct spec *spec;
283*2d543d20SAndroid Build Coastguard Worker 	unsigned int i;
284*2d543d20SAndroid Build Coastguard Worker 
285*2d543d20SAndroid Build Coastguard Worker 	if (!data)
286*2d543d20SAndroid Build Coastguard Worker 		return;
287*2d543d20SAndroid Build Coastguard Worker 
288*2d543d20SAndroid Build Coastguard Worker 	/* make sure successive ->func_close() calls are harmless */
289*2d543d20SAndroid Build Coastguard Worker 	rec->data = NULL;
290*2d543d20SAndroid Build Coastguard Worker 
291*2d543d20SAndroid Build Coastguard Worker 	if (data->spec_arr) {
292*2d543d20SAndroid Build Coastguard Worker 		for (i = 0; i < data->nspec; i++) {
293*2d543d20SAndroid Build Coastguard Worker 			spec = &data->spec_arr[i];
294*2d543d20SAndroid Build Coastguard Worker 			free(spec->property_key);
295*2d543d20SAndroid Build Coastguard Worker 			free(spec->lr.ctx_raw);
296*2d543d20SAndroid Build Coastguard Worker 			free(spec->lr.ctx_trans);
297*2d543d20SAndroid Build Coastguard Worker 		}
298*2d543d20SAndroid Build Coastguard Worker 		free(data->spec_arr);
299*2d543d20SAndroid Build Coastguard Worker 	}
300*2d543d20SAndroid Build Coastguard Worker 
301*2d543d20SAndroid Build Coastguard Worker 	free(data);
302*2d543d20SAndroid Build Coastguard Worker 	rec->data = NULL;
303*2d543d20SAndroid Build Coastguard Worker }
304*2d543d20SAndroid Build Coastguard Worker 
property_lookup(struct selabel_handle * rec,const char * key,int type)305*2d543d20SAndroid Build Coastguard Worker static struct selabel_lookup_rec *property_lookup(struct selabel_handle *rec,
306*2d543d20SAndroid Build Coastguard Worker 					 const char *key,
307*2d543d20SAndroid Build Coastguard Worker 					 int __attribute__((unused)) type)
308*2d543d20SAndroid Build Coastguard Worker {
309*2d543d20SAndroid Build Coastguard Worker 	struct saved_data *data = (struct saved_data *)rec->data;
310*2d543d20SAndroid Build Coastguard Worker 	spec_t *spec_arr = data->spec_arr;
311*2d543d20SAndroid Build Coastguard Worker 	unsigned int i;
312*2d543d20SAndroid Build Coastguard Worker 	struct selabel_lookup_rec *ret = NULL;
313*2d543d20SAndroid Build Coastguard Worker 
314*2d543d20SAndroid Build Coastguard Worker 	if (!data->nspec) {
315*2d543d20SAndroid Build Coastguard Worker 		errno = ENOENT;
316*2d543d20SAndroid Build Coastguard Worker 		goto finish;
317*2d543d20SAndroid Build Coastguard Worker 	}
318*2d543d20SAndroid Build Coastguard Worker 
319*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < data->nspec; i++) {
320*2d543d20SAndroid Build Coastguard Worker 		if (strncmp(spec_arr[i].property_key, key,
321*2d543d20SAndroid Build Coastguard Worker 			    strlen(spec_arr[i].property_key)) == 0) {
322*2d543d20SAndroid Build Coastguard Worker 			break;
323*2d543d20SAndroid Build Coastguard Worker 		}
324*2d543d20SAndroid Build Coastguard Worker 		if (strncmp(spec_arr[i].property_key, "*", 1) == 0)
325*2d543d20SAndroid Build Coastguard Worker 			break;
326*2d543d20SAndroid Build Coastguard Worker 	}
327*2d543d20SAndroid Build Coastguard Worker 
328*2d543d20SAndroid Build Coastguard Worker 	if (i >= data->nspec) {
329*2d543d20SAndroid Build Coastguard Worker 		/* No matching specification. */
330*2d543d20SAndroid Build Coastguard Worker 		errno = ENOENT;
331*2d543d20SAndroid Build Coastguard Worker 		goto finish;
332*2d543d20SAndroid Build Coastguard Worker 	}
333*2d543d20SAndroid Build Coastguard Worker 
334*2d543d20SAndroid Build Coastguard Worker 	ret = &spec_arr[i].lr;
335*2d543d20SAndroid Build Coastguard Worker 
336*2d543d20SAndroid Build Coastguard Worker finish:
337*2d543d20SAndroid Build Coastguard Worker 	return ret;
338*2d543d20SAndroid Build Coastguard Worker }
339*2d543d20SAndroid Build Coastguard Worker 
lookup_exact_match(struct selabel_handle * rec,const char * key,int type)340*2d543d20SAndroid Build Coastguard Worker static struct selabel_lookup_rec *lookup_exact_match(struct selabel_handle *rec,
341*2d543d20SAndroid Build Coastguard Worker 		const char *key, int __attribute__((unused)) type)
342*2d543d20SAndroid Build Coastguard Worker {
343*2d543d20SAndroid Build Coastguard Worker 	struct saved_data *data = (struct saved_data *)rec->data;
344*2d543d20SAndroid Build Coastguard Worker 	spec_t *spec_arr = data->spec_arr;
345*2d543d20SAndroid Build Coastguard Worker 	unsigned int i;
346*2d543d20SAndroid Build Coastguard Worker 	struct selabel_lookup_rec *ret = NULL;
347*2d543d20SAndroid Build Coastguard Worker 
348*2d543d20SAndroid Build Coastguard Worker 	if (!data->nspec) {
349*2d543d20SAndroid Build Coastguard Worker 		errno = ENOENT;
350*2d543d20SAndroid Build Coastguard Worker 		goto finish;
351*2d543d20SAndroid Build Coastguard Worker 	}
352*2d543d20SAndroid Build Coastguard Worker 
353*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < data->nspec; i++) {
354*2d543d20SAndroid Build Coastguard Worker 		if (strcmp(spec_arr[i].property_key, key) == 0)
355*2d543d20SAndroid Build Coastguard Worker 			break;
356*2d543d20SAndroid Build Coastguard Worker 		if (strcmp(spec_arr[i].property_key, "*") == 0)
357*2d543d20SAndroid Build Coastguard Worker 			break;
358*2d543d20SAndroid Build Coastguard Worker 	}
359*2d543d20SAndroid Build Coastguard Worker 
360*2d543d20SAndroid Build Coastguard Worker 	if (i >= data->nspec) {
361*2d543d20SAndroid Build Coastguard Worker 		/* No matching specification. */
362*2d543d20SAndroid Build Coastguard Worker 		errno = ENOENT;
363*2d543d20SAndroid Build Coastguard Worker 		goto finish;
364*2d543d20SAndroid Build Coastguard Worker 	}
365*2d543d20SAndroid Build Coastguard Worker 
366*2d543d20SAndroid Build Coastguard Worker 	ret = &spec_arr[i].lr;
367*2d543d20SAndroid Build Coastguard Worker 
368*2d543d20SAndroid Build Coastguard Worker finish:
369*2d543d20SAndroid Build Coastguard Worker 	return ret;
370*2d543d20SAndroid Build Coastguard Worker }
371*2d543d20SAndroid Build Coastguard Worker 
stats(struct selabel_handle * rec)372*2d543d20SAndroid Build Coastguard Worker static void stats(struct selabel_handle __attribute__((unused)) *rec)
373*2d543d20SAndroid Build Coastguard Worker {
374*2d543d20SAndroid Build Coastguard Worker 	selinux_log(SELINUX_WARNING, "'stats' functionality not implemented.\n");
375*2d543d20SAndroid Build Coastguard Worker }
376*2d543d20SAndroid Build Coastguard Worker 
selabel_property_init(struct selabel_handle * rec,const struct selinux_opt * opts,unsigned nopts)377*2d543d20SAndroid Build Coastguard Worker int selabel_property_init(struct selabel_handle *rec,
378*2d543d20SAndroid Build Coastguard Worker 			  const struct selinux_opt *opts,
379*2d543d20SAndroid Build Coastguard Worker 			  unsigned nopts)
380*2d543d20SAndroid Build Coastguard Worker {
381*2d543d20SAndroid Build Coastguard Worker 	struct saved_data *data;
382*2d543d20SAndroid Build Coastguard Worker 
383*2d543d20SAndroid Build Coastguard Worker 	data = (struct saved_data *)calloc(1, sizeof(*data));
384*2d543d20SAndroid Build Coastguard Worker 	if (!data)
385*2d543d20SAndroid Build Coastguard Worker 		return -1;
386*2d543d20SAndroid Build Coastguard Worker 
387*2d543d20SAndroid Build Coastguard Worker 	rec->data = data;
388*2d543d20SAndroid Build Coastguard Worker 	rec->func_close = &closef;
389*2d543d20SAndroid Build Coastguard Worker 	rec->func_stats = &stats;
390*2d543d20SAndroid Build Coastguard Worker 	rec->func_lookup = &property_lookup;
391*2d543d20SAndroid Build Coastguard Worker 
392*2d543d20SAndroid Build Coastguard Worker 	return init(rec, opts, nopts);
393*2d543d20SAndroid Build Coastguard Worker }
394*2d543d20SAndroid Build Coastguard Worker 
selabel_exact_match_init(struct selabel_handle * rec,const struct selinux_opt * opts,unsigned nopts)395*2d543d20SAndroid Build Coastguard Worker int selabel_exact_match_init(struct selabel_handle *rec,
396*2d543d20SAndroid Build Coastguard Worker 		const struct selinux_opt *opts, unsigned nopts)
397*2d543d20SAndroid Build Coastguard Worker {
398*2d543d20SAndroid Build Coastguard Worker 	struct saved_data *data;
399*2d543d20SAndroid Build Coastguard Worker 
400*2d543d20SAndroid Build Coastguard Worker 	data = (struct saved_data *)calloc(1, sizeof(*data));
401*2d543d20SAndroid Build Coastguard Worker 	if (!data)
402*2d543d20SAndroid Build Coastguard Worker 		return -1;
403*2d543d20SAndroid Build Coastguard Worker 
404*2d543d20SAndroid Build Coastguard Worker 	rec->data = data;
405*2d543d20SAndroid Build Coastguard Worker 	rec->func_close = &closef;
406*2d543d20SAndroid Build Coastguard Worker 	rec->func_stats = &stats;
407*2d543d20SAndroid Build Coastguard Worker 	rec->func_lookup = &lookup_exact_match;
408*2d543d20SAndroid Build Coastguard Worker 
409*2d543d20SAndroid Build Coastguard Worker 	return init(rec, opts, nopts);
410*2d543d20SAndroid Build Coastguard Worker }
411