135b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley/*
235b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley * Property Service contexts backend for labeling Android
335b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley * property keys
435b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley */
535b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley
635b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley#include <stdarg.h>
735b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley#include <string.h>
835b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley#include <ctype.h>
935b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley#include <errno.h>
1035b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley#include <limits.h>
1135b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley#include <sys/types.h>
1235b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley#include <sys/stat.h>
1335b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley#include "callbacks.h"
1435b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley#include "label_internal.h"
1535b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley
1635b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley/* A property security context specification. */
1735b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalleytypedef struct spec {
1835b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	struct selabel_lookup_rec lr;	 /* holds contexts for lookup result */
1935b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	char *property_key;	         /* property key string */
2035b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley} spec_t;
2135b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley
2235b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley/* Our stored configuration */
2335b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalleystruct saved_data {
2435b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	/*
2535b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	 * The array of specifications is sorted for longest
2635b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	 * prefix match
2735b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	 */
2835b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	spec_t *spec_arr;
2935b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	unsigned int nspec; /* total number of specifications */
3035b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley};
3135b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley
3235b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalleystatic int cmp(const void *A, const void *B)
3335b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley{
3435b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	const struct spec *sp1 = A, *sp2 = B;
3535b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley
3635b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	if (strncmp(sp1->property_key,"*",1) == 0)
3735b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley		return 1;
3835b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	if (strncmp(sp2->property_key,"*",1) == 0)
3935b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley		return -1;
4035b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley
4135b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	size_t L1 = strlen(sp1->property_key);
4235b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	size_t L2 = strlen(sp2->property_key);
4335b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley
4435b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	return (L1 < L2) - (L1 > L2);
4535b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley}
4635b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley
4735b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley/*
4835b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley * Warn about duplicate specifications.
4935b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley */
5035b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalleystatic int nodups_specs(struct saved_data *data, const char *path)
5135b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley{
5235b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	int rc = 0;
5335b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	unsigned int ii, jj;
5435b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	struct spec *curr_spec, *spec_arr = data->spec_arr;
5535b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley
5635b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	for (ii = 0; ii < data->nspec; ii++) {
5735b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley		curr_spec = &spec_arr[ii];
5835b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley		for (jj = ii + 1; jj < data->nspec; jj++) {
5935b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley			if ((!strcmp(spec_arr[jj].property_key, curr_spec->property_key))) {
6035b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley				rc = -1;
6135b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley				errno = EINVAL;
6235b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley				if (strcmp
6335b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley				    (spec_arr[jj].lr.ctx_raw,
6435b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley				     curr_spec->lr.ctx_raw)) {
6535b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley					selinux_log
6635b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley						(SELINUX_ERROR,
6735b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley						 "%s: Multiple different specifications for %s  (%s and %s).\n",
6835b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley						 path, curr_spec->property_key,
6935b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley						 spec_arr[jj].lr.ctx_raw,
7035b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley						 curr_spec->lr.ctx_raw);
7135b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley				} else {
7235b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley					selinux_log
7335b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley						(SELINUX_ERROR,
7435b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley						 "%s: Multiple same specifications for %s.\n",
7535b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley						 path, curr_spec->property_key);
7635b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley				}
7735b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley			}
7835b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley		}
7935b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	}
8035b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	return rc;
8135b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley}
8235b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley
8335b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalleystatic int process_line(struct selabel_handle *rec,
8435b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley			const char *path, char *line_buf,
8535b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley			int pass, unsigned lineno)
8635b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley{
8735b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	int items, len;
8835b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	char buf1[BUFSIZ], buf2[BUFSIZ];
8935b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	char *buf_p, *prop = buf1, *context = buf2;
9035b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	struct saved_data *data = (struct saved_data *)rec->data;
9135b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	spec_t *spec_arr = data->spec_arr;
9235b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	unsigned int nspec = data->nspec;
9335b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley
9435b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	len = strlen(line_buf);
9535b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	if (line_buf[len - 1] == '\n')
9635b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley		line_buf[len - 1] = 0;
9735b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	buf_p = line_buf;
9835b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	while (isspace(*buf_p))
9935b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley		buf_p++;
10035b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	/* Skip comment lines and empty lines. */
10135b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	if (*buf_p == '#' || *buf_p == 0)
10235b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley		return 0;
10335b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	items = sscanf(line_buf, "%255s %255s", prop, context);
10435b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	if (items != 2) {
10535b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley		selinux_log(SELINUX_WARNING,
10635b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley			    "%s:  line %d is missing fields, skipping\n", path,
10735b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley			    lineno);
10835b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley		return 0;
10935b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	}
11035b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley
11135b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	if (pass == 1) {
11235b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley		/* On the second pass, process and store the specification in spec. */
11335b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley		spec_arr[nspec].property_key = strdup(prop);
11435b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley		if (!spec_arr[nspec].property_key) {
11535b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley			selinux_log(SELINUX_WARNING,
11635b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley				    "%s:  out of memory at line %d on prop %s\n",
11735b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley				    path, lineno, prop);
11835b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley		return -1;
11935b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley
12035b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley		}
12135b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley
12235b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley		spec_arr[nspec].lr.ctx_raw = strdup(context);
12335b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley		if (!spec_arr[nspec].lr.ctx_raw) {
12435b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley			selinux_log(SELINUX_WARNING,
12535b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley				    "%s:  out of memory at line %d on context %s\n",
12635b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley				    path, lineno, context);
12735b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley		return -1;
12835b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley		}
12951c57096c8101ea13e51c296e4891ae84fc1c422Robert Craig
13051c57096c8101ea13e51c296e4891ae84fc1c422Robert Craig		if (rec->validating) {
13151c57096c8101ea13e51c296e4891ae84fc1c422Robert Craig		        if (selabel_validate(rec, &spec_arr[nspec].lr) < 0) {
13251c57096c8101ea13e51c296e4891ae84fc1c422Robert Craig			        selinux_log(SELINUX_WARNING,
13351c57096c8101ea13e51c296e4891ae84fc1c422Robert Craig					    "%s:  line %d has invalid context %s\n",
13451c57096c8101ea13e51c296e4891ae84fc1c422Robert Craig					    path, lineno, spec_arr[nspec].lr.ctx_raw);
13551c57096c8101ea13e51c296e4891ae84fc1c422Robert Craig			}
13651c57096c8101ea13e51c296e4891ae84fc1c422Robert Craig		}
13735b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley     	}
13835b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley
13935b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	data->nspec = ++nspec;
14035b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	return 0;
14135b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley}
14235b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley
143a2e47cd90d84d48cde19575d044577a3fc7a4000Stephen Smalleystatic int init(struct selabel_handle *rec, const struct selinux_opt *opts,
14435b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley		unsigned n)
14535b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley{
14635b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	struct saved_data *data = (struct saved_data *)rec->data;
14735b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	const char *path = NULL;
14835b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	FILE *fp;
14935b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	char line_buf[BUFSIZ];
15035b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	unsigned int lineno = 0, maxnspec, pass;
15135b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	int status = -1;
15235b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	struct stat sb;
15335b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley
15435b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	/* Process arguments */
15535b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	while (n--)
15635b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley		switch (opts[n].type) {
15735b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley		case SELABEL_OPT_PATH:
15835b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley			path = opts[n].value;
15935b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley			break;
16035b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley		}
16135b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley
16235b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	/* Open the specification file. */
16335b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	if ((fp = fopen(path, "r")) == NULL)
16435b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley		return -1;
16535b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley
16635b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	if (fstat(fileno(fp), &sb) < 0)
16735b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley		return -1;
16835b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	if (!S_ISREG(sb.st_mode)) {
16935b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley		errno = EINVAL;
17035b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley		return -1;
17135b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	}
17235b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley
17335b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	/*
17435b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	 * Two passes of the specification file. First is to get the size.
17535b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	 * After the first pass, the spec array is malloced to the appropriate
17635b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	 * size. Second pass is to populate the spec array and check for
17735b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	 * dups.
17835b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	 */
17935b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	maxnspec = UINT_MAX / sizeof(spec_t);
18035b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	for (pass = 0; pass < 2; pass++) {
18135b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley		data->nspec = 0;
18235b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley
18335b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley		while (fgets(line_buf, sizeof line_buf - 1, fp)
18435b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley		       && data->nspec < maxnspec) {
18535b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley			if (process_line(rec, path, line_buf, pass, ++lineno) != 0) {
18635b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley				goto finish;
18735b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley			}
18835b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley		}
18935b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley
19035b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley		if (pass == 1) {
19135b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley			status = nodups_specs(data, path);
19235b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley
19335b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley			if (status)
19435b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley				goto finish;
19535b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley		}
19635b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley
19735b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley		if (pass == 0) {
19835b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley
19935b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley			if (data->nspec == 0) {
20035b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley				status = 0;
20135b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley				goto finish;
20235b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley			}
20335b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley
20435b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley			if (NULL == (data->spec_arr =
20535b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley				     malloc(sizeof(spec_t) * data->nspec)))
20635b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley				goto finish;
20735b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley
20835b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley			memset(data->spec_arr, 0, sizeof(spec_t)*data->nspec);
20935b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley			maxnspec = data->nspec;
21035b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley			rewind(fp);
21135b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley		}
21235b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	}
21335b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley
21435b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	qsort(data->spec_arr, data->nspec, sizeof(struct spec), cmp);
21535b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley
21635b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	status = 0;
21735b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalleyfinish:
21835b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	fclose(fp);
21935b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	return status;
22035b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley}
22135b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley
22235b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley/*
22335b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley * Backend interface routines
22435b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley */
22535b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalleystatic void closef(struct selabel_handle *rec)
22635b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley{
22735b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	struct saved_data *data = (struct saved_data *)rec->data;
22835b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	struct spec *spec;
22935b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	unsigned int i;
23035b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley
23135b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	for (i = 0; i < data->nspec; i++) {
23235b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley		spec = &data->spec_arr[i];
23335b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley		free(spec->property_key);
23435b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley		free(spec->lr.ctx_raw);
23535b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley		free(spec->lr.ctx_trans);
23635b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	}
23735b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley
23835b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	if (data->spec_arr)
23935b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley		free(data->spec_arr);
24035b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley
24135b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	free(data);
24235b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley}
24335b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley
24435b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalleystatic struct selabel_lookup_rec *lookup(struct selabel_handle *rec,
24535b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley					 const char *key,
24635b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley					 int __attribute__((unused)) type)
24735b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley{
24835b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	struct saved_data *data = (struct saved_data *)rec->data;
24935b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	spec_t *spec_arr = data->spec_arr;
25035b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	unsigned int i;
25135b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	struct selabel_lookup_rec *ret = NULL;
25235b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley
25335b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	if (!data->nspec) {
25435b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley		errno = ENOENT;
25535b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley		goto finish;
25635b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	}
25735b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley
25835b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	for (i = 0; i < data->nspec; i++) {
25935b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley		if (strncmp(spec_arr[i].property_key, key,
26035b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley		    strlen(spec_arr[i].property_key)) == 0) {
26135b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley			break;
26235b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley		}
26335b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley		if (strncmp(spec_arr[i].property_key, "*", 1) == 0)
26435b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley			break;
26535b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	}
26635b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley
26735b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	if (i >= data->nspec) {
26835b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley		/* No matching specification. */
26935b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley		errno = ENOENT;
27035b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley		goto finish;
27135b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	}
27235b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley
27335b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	ret = &spec_arr[i].lr;
27435b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley
27535b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalleyfinish:
27635b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	return ret;
27735b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley}
27835b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley
27935b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalleystatic void stats(struct selabel_handle __attribute__((unused)) *rec)
28035b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley{
28135b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	selinux_log(SELINUX_WARNING, "'stats' functionality not implemented.\n");
28235b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley}
28335b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley
284a2e47cd90d84d48cde19575d044577a3fc7a4000Stephen Smalleyint selabel_property_init(struct selabel_handle *rec,
285a2e47cd90d84d48cde19575d044577a3fc7a4000Stephen Smalley			  const struct selinux_opt *opts,
286a2e47cd90d84d48cde19575d044577a3fc7a4000Stephen Smalley			  unsigned nopts)
28735b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley{
28835b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	struct saved_data *data;
28935b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley
29035b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	data = (struct saved_data *)malloc(sizeof(*data));
29135b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	if (!data)
29235b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley		return -1;
29335b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	memset(data, 0, sizeof(*data));
29435b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley
29535b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	rec->data = data;
29635b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	rec->func_close = &closef;
29735b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	rec->func_stats = &stats;
29835b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	rec->func_lookup = &lookup;
29935b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley
30035b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley	return init(rec, opts, nopts);
30135b01083fe5e34cbd318a78ef9b1a13432ae24d9Stephen Smalley}
302