1cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig/*
2cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig * Property Service contexts backend for labeling Android
3cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig * property keys
4cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig */
5cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig
6cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig#include <stdarg.h>
7cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig#include <string.h>
8cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig#include <ctype.h>
9cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig#include <errno.h>
10cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig#include <limits.h>
11cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig#include <sys/types.h>
12cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig#include <sys/stat.h>
13cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig#include "callbacks.h"
14cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig#include "label_internal.h"
15cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig
16cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig/* A property security context specification. */
17cfc492cf11e1b641e2a0478907d56a17b771a067rpcraigtypedef struct spec {
1830900902b16c70fabe78a22aafb120443acdd53cEric Paris	struct selabel_lookup_rec lr;	/* holds contexts for lookup result */
1930900902b16c70fabe78a22aafb120443acdd53cEric Paris	char *property_key;	/* property key string */
20cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig} spec_t;
21cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig
22cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig/* Our stored configuration */
23cfc492cf11e1b641e2a0478907d56a17b771a067rpcraigstruct saved_data {
24cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	/*
25cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	 * The array of specifications is sorted for longest
26cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	 * prefix match
27cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	 */
28cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	spec_t *spec_arr;
2930900902b16c70fabe78a22aafb120443acdd53cEric Paris	unsigned int nspec;	/* total number of specifications */
30cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig};
31cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig
32cfc492cf11e1b641e2a0478907d56a17b771a067rpcraigstatic int cmp(const void *A, const void *B)
33cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig{
34cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	const struct spec *sp1 = A, *sp2 = B;
35cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig
3630900902b16c70fabe78a22aafb120443acdd53cEric Paris	if (strncmp(sp1->property_key, "*", 1) == 0)
37cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig		return 1;
3830900902b16c70fabe78a22aafb120443acdd53cEric Paris	if (strncmp(sp2->property_key, "*", 1) == 0)
39cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig		return -1;
40cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig
41cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	size_t L1 = strlen(sp1->property_key);
42cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	size_t L2 = strlen(sp2->property_key);
43cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig
44cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	return (L1 < L2) - (L1 > L2);
45cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig}
46cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig
47cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig/*
48cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig * Warn about duplicate specifications.
49cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig */
50cfc492cf11e1b641e2a0478907d56a17b771a067rpcraigstatic int nodups_specs(struct saved_data *data, const char *path)
51cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig{
52cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	int rc = 0;
53cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	unsigned int ii, jj;
54cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	struct spec *curr_spec, *spec_arr = data->spec_arr;
55cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig
56cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	for (ii = 0; ii < data->nspec; ii++) {
57cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig		curr_spec = &spec_arr[ii];
58cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig		for (jj = ii + 1; jj < data->nspec; jj++) {
5930900902b16c70fabe78a22aafb120443acdd53cEric Paris			if (!strcmp(spec_arr[jj].property_key, curr_spec->property_key)) {
60cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig				rc = -1;
61cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig				errno = EINVAL;
6230900902b16c70fabe78a22aafb120443acdd53cEric Paris				if (strcmp(spec_arr[jj].lr.ctx_raw, curr_spec->lr.ctx_raw)) {
6330900902b16c70fabe78a22aafb120443acdd53cEric Paris					selinux_log(SELINUX_ERROR,
6430900902b16c70fabe78a22aafb120443acdd53cEric Paris						    "%s: Multiple different specifications for %s  (%s and %s).\n",
6530900902b16c70fabe78a22aafb120443acdd53cEric Paris						    path,
6630900902b16c70fabe78a22aafb120443acdd53cEric Paris						    curr_spec->property_key,
6730900902b16c70fabe78a22aafb120443acdd53cEric Paris						    spec_arr[jj].lr.ctx_raw,
6830900902b16c70fabe78a22aafb120443acdd53cEric Paris						    curr_spec->lr.ctx_raw);
69cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig				} else {
7030900902b16c70fabe78a22aafb120443acdd53cEric Paris					selinux_log(SELINUX_ERROR,
7130900902b16c70fabe78a22aafb120443acdd53cEric Paris						    "%s: Multiple same specifications for %s.\n",
7230900902b16c70fabe78a22aafb120443acdd53cEric Paris						    path,
7330900902b16c70fabe78a22aafb120443acdd53cEric Paris						    curr_spec->property_key);
74cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig				}
75cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig			}
76cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig		}
77cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	}
78cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	return rc;
79cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig}
80cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig
81cfc492cf11e1b641e2a0478907d56a17b771a067rpcraigstatic int process_line(struct selabel_handle *rec,
8230900902b16c70fabe78a22aafb120443acdd53cEric Paris			const char *path, char *line_buf,
83cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig			int pass, unsigned lineno)
84cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig{
85cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	int items, len;
86cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	char buf1[BUFSIZ], buf2[BUFSIZ];
87cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	char *buf_p, *prop = buf1, *context = buf2;
88cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	struct saved_data *data = (struct saved_data *)rec->data;
89cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	spec_t *spec_arr = data->spec_arr;
90cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	unsigned int nspec = data->nspec;
91cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig
92cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	len = strlen(line_buf);
93cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	if (line_buf[len - 1] == '\n')
94cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig		line_buf[len - 1] = 0;
95cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	buf_p = line_buf;
96cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	while (isspace(*buf_p))
97cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig		buf_p++;
98cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	/* Skip comment lines and empty lines. */
99cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	if (*buf_p == '#' || *buf_p == 0)
100cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig		return 0;
101cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	items = sscanf(line_buf, "%255s %255s", prop, context);
102cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	if (items != 2) {
103cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig		selinux_log(SELINUX_WARNING,
104417cb8d076a31c57710429b255aebc595613eb6bPetr Lautrbach			    "%s:  line %u is missing fields, skipping\n", path,
105cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig			    lineno);
106cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig		return 0;
107cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	}
108cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig
109cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	if (pass == 1) {
110cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig		/* On the second pass, process and store the specification in spec. */
111cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig		spec_arr[nspec].property_key = strdup(prop);
112cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig		if (!spec_arr[nspec].property_key) {
113cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig			selinux_log(SELINUX_WARNING,
114417cb8d076a31c57710429b255aebc595613eb6bPetr Lautrbach				    "%s:  out of memory at line %u on prop %s\n",
115cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig				    path, lineno, prop);
11630900902b16c70fabe78a22aafb120443acdd53cEric Paris			return -1;
11730900902b16c70fabe78a22aafb120443acdd53cEric Paris
118cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig		}
119cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig
120cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig		spec_arr[nspec].lr.ctx_raw = strdup(context);
121cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig		if (!spec_arr[nspec].lr.ctx_raw) {
122cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig			selinux_log(SELINUX_WARNING,
123417cb8d076a31c57710429b255aebc595613eb6bPetr Lautrbach				    "%s:  out of memory at line %u on context %s\n",
124cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig				    path, lineno, context);
12530900902b16c70fabe78a22aafb120443acdd53cEric Paris			return -1;
126cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig		}
127eb0ba200b513d05d176e10a85061fdf01d0426f7Robert Craig
128eb0ba200b513d05d176e10a85061fdf01d0426f7Robert Craig		if (rec->validating) {
129eb0ba200b513d05d176e10a85061fdf01d0426f7Robert Craig			if (selabel_validate(rec, &spec_arr[nspec].lr) < 0) {
130eb0ba200b513d05d176e10a85061fdf01d0426f7Robert Craig				selinux_log(SELINUX_WARNING,
131417cb8d076a31c57710429b255aebc595613eb6bPetr Lautrbach					    "%s:  line %u has invalid context %s\n",
132eb0ba200b513d05d176e10a85061fdf01d0426f7Robert Craig					    path, lineno, spec_arr[nspec].lr.ctx_raw);
133eb0ba200b513d05d176e10a85061fdf01d0426f7Robert Craig			}
134eb0ba200b513d05d176e10a85061fdf01d0426f7Robert Craig		}
13530900902b16c70fabe78a22aafb120443acdd53cEric Paris	}
136cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig
137cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	data->nspec = ++nspec;
138cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	return 0;
139cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig}
140cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig
141cfc492cf11e1b641e2a0478907d56a17b771a067rpcraigstatic int init(struct selabel_handle *rec, struct selinux_opt *opts,
142cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig		unsigned n)
143cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig{
144cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	struct saved_data *data = (struct saved_data *)rec->data;
145cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	const char *path = NULL;
146cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	FILE *fp;
147cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	char line_buf[BUFSIZ];
148cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	unsigned int lineno = 0, maxnspec, pass;
149cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	int status = -1;
150cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	struct stat sb;
151cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig
152cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	/* Process arguments */
153cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	while (n--)
154cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig		switch (opts[n].type) {
155cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig		case SELABEL_OPT_PATH:
156cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig			path = opts[n].value;
157cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig			break;
158cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig		}
159cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig
160aa62cd60f7192123b509c2518e7a2083e34a65a2Eric Paris	if (!path)
161aa62cd60f7192123b509c2518e7a2083e34a65a2Eric Paris		return -1;
162aa62cd60f7192123b509c2518e7a2083e34a65a2Eric Paris
163cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	/* Open the specification file. */
164cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	if ((fp = fopen(path, "r")) == NULL)
165cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig		return -1;
166cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig
167cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	if (fstat(fileno(fp), &sb) < 0)
1681e8f102e8cec4ae84f09cc595013234398270366Eric Paris		goto finish;
1691e8f102e8cec4ae84f09cc595013234398270366Eric Paris	errno = EINVAL;
1701e8f102e8cec4ae84f09cc595013234398270366Eric Paris	if (!S_ISREG(sb.st_mode))
1711e8f102e8cec4ae84f09cc595013234398270366Eric Paris		goto finish;
172cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig
173cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	/*
174cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	 * Two passes of the specification file. First is to get the size.
175cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	 * After the first pass, the spec array is malloced to the appropriate
176cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	 * size. Second pass is to populate the spec array and check for
177cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	 * dups.
178cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	 */
179cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	maxnspec = UINT_MAX / sizeof(spec_t);
180cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	for (pass = 0; pass < 2; pass++) {
181cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig		data->nspec = 0;
182cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig
183cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig		while (fgets(line_buf, sizeof line_buf - 1, fp)
184cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig		       && data->nspec < maxnspec) {
18530900902b16c70fabe78a22aafb120443acdd53cEric Paris			if (process_line(rec, path, line_buf, pass, ++lineno) != 0)
186cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig				goto finish;
187cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig		}
188cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig
189cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig		if (pass == 1) {
190cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig			status = nodups_specs(data, path);
19130900902b16c70fabe78a22aafb120443acdd53cEric Paris
192cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig			if (status)
193cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig				goto finish;
194cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig		}
195cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig
196cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig		if (pass == 0) {
197cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig
198cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig			if (data->nspec == 0) {
199cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig				status = 0;
200cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig				goto finish;
201cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig			}
202cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig
203cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig			if (NULL == (data->spec_arr =
204cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig				     malloc(sizeof(spec_t) * data->nspec)))
205cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig				goto finish;
206cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig
20730900902b16c70fabe78a22aafb120443acdd53cEric Paris			memset(data->spec_arr, 0, sizeof(spec_t) * data->nspec);
208cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig			maxnspec = data->nspec;
209cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig			rewind(fp);
210cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig		}
211cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	}
212cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig
213cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	qsort(data->spec_arr, data->nspec, sizeof(struct spec), cmp);
214cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig
215cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	status = 0;
216cfc492cf11e1b641e2a0478907d56a17b771a067rpcraigfinish:
217cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	fclose(fp);
218cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	return status;
219cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig}
220cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig
221cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig/*
222cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig * Backend interface routines
223cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig */
224cfc492cf11e1b641e2a0478907d56a17b771a067rpcraigstatic void closef(struct selabel_handle *rec)
225cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig{
226cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	struct saved_data *data = (struct saved_data *)rec->data;
227cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	struct spec *spec;
228cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	unsigned int i;
229cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig
230cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	for (i = 0; i < data->nspec; i++) {
231cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig		spec = &data->spec_arr[i];
232cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig		free(spec->property_key);
233cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig		free(spec->lr.ctx_raw);
234cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig		free(spec->lr.ctx_trans);
235cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	}
236cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig
237cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	if (data->spec_arr)
238cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig		free(data->spec_arr);
23930900902b16c70fabe78a22aafb120443acdd53cEric Paris
240cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	free(data);
241cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig}
242cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig
24330900902b16c70fabe78a22aafb120443acdd53cEric Parisstatic struct selabel_lookup_rec *lookup(struct selabel_handle *rec,
24430900902b16c70fabe78a22aafb120443acdd53cEric Paris					 const char *key,
24530900902b16c70fabe78a22aafb120443acdd53cEric Paris					 int __attribute__ ((unused)) type)
246cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig{
247cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	struct saved_data *data = (struct saved_data *)rec->data;
248cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	spec_t *spec_arr = data->spec_arr;
249cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	unsigned int i;
250cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	struct selabel_lookup_rec *ret = NULL;
251cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig
252cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	if (!data->nspec) {
253cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig		errno = ENOENT;
254cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig		goto finish;
255cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	}
256cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig
257cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	for (i = 0; i < data->nspec; i++) {
25830900902b16c70fabe78a22aafb120443acdd53cEric Paris		if (strncmp(spec_arr[i].property_key, key,
25930900902b16c70fabe78a22aafb120443acdd53cEric Paris			    strlen(spec_arr[i].property_key)) == 0) {
260cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig			break;
261cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig		}
262cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig		if (strncmp(spec_arr[i].property_key, "*", 1) == 0)
263cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig			break;
264cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	}
265cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig
266cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	if (i >= data->nspec) {
267cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig		/* No matching specification. */
268cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig		errno = ENOENT;
269cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig		goto finish;
270cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	}
271cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig
272cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	ret = &spec_arr[i].lr;
273cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig
274cfc492cf11e1b641e2a0478907d56a17b771a067rpcraigfinish:
275cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	return ret;
276cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig}
277cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig
27830900902b16c70fabe78a22aafb120443acdd53cEric Parisstatic void stats(struct selabel_handle __attribute__ ((unused)) * rec)
279cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig{
280cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	selinux_log(SELINUX_WARNING, "'stats' functionality not implemented.\n");
281cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig}
282cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig
283cfc492cf11e1b641e2a0478907d56a17b771a067rpcraigint selabel_property_init(struct selabel_handle *rec, struct selinux_opt *opts,
28430900902b16c70fabe78a22aafb120443acdd53cEric Paris			  unsigned nopts)
285cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig{
286cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	struct saved_data *data;
287cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig
288cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	data = (struct saved_data *)malloc(sizeof(*data));
289cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	if (!data)
290cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig		return -1;
291cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	memset(data, 0, sizeof(*data));
292cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig
293cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	rec->data = data;
294cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	rec->func_close = &closef;
295cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	rec->func_stats = &stats;
296cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	rec->func_lookup = &lookup;
297cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig
298cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig	return init(rec, opts, nopts);
299cfc492cf11e1b641e2a0478907d56a17b771a067rpcraig}
300