147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner/*
247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner * Property Service contexts backend for labeling Android
347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner * property keys
447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner */
547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include <stdarg.h>
747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include <string.h>
847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include <ctype.h>
947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include <errno.h>
1047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include <limits.h>
1147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include <sys/types.h>
1247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include <sys/stat.h>
1347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include "callbacks.h"
1447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include "label_internal.h"
1547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
1647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner/* A property security context specification. */
1747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnertypedef struct spec {
1847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	struct selabel_lookup_rec lr;	 /* holds contexts for lookup result */
1947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	char *property_key;	         /* property key string */
2047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner} spec_t;
2147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
2247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner/* Our stored configuration */
2347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerstruct saved_data {
2447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	/*
2547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	 * The array of specifications is sorted for longest
2647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	 * prefix match
2747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	 */
2847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	spec_t *spec_arr;
2947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	unsigned int nspec; /* total number of specifications */
3047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner};
3147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
3247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerstatic int cmp(const void *A, const void *B)
3347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner{
3447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	const struct spec *sp1 = A, *sp2 = B;
3547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
3647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (strncmp(sp1->property_key,"*",1) == 0)
3747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		return 1;
3847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (strncmp(sp2->property_key,"*",1) == 0)
3947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		return -1;
4047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
4147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	size_t L1 = strlen(sp1->property_key);
4247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	size_t L2 = strlen(sp2->property_key);
4347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
4447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	return (L1 < L2) - (L1 > L2);
4547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner}
4647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
4747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner/*
4847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner * Warn about duplicate specifications.
4947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner */
5047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerstatic int nodups_specs(struct saved_data *data, const char *path)
5147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner{
5247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	int rc = 0;
5347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	unsigned int ii, jj;
5447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	struct spec *curr_spec, *spec_arr = data->spec_arr;
5547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
5647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	for (ii = 0; ii < data->nspec; ii++) {
5747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		curr_spec = &spec_arr[ii];
5847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		for (jj = ii + 1; jj < data->nspec; jj++) {
5947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			if ((!strcmp(spec_arr[jj].property_key, curr_spec->property_key))) {
6047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				rc = -1;
6147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				errno = EINVAL;
6247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				if (strcmp
6347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				    (spec_arr[jj].lr.ctx_raw,
6447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				     curr_spec->lr.ctx_raw)) {
6547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner					selinux_log
6647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner						(SELINUX_ERROR,
6747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner						 "%s: Multiple different specifications for %s  (%s and %s).\n",
6847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner						 path, curr_spec->property_key,
6947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner						 spec_arr[jj].lr.ctx_raw,
7047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner						 curr_spec->lr.ctx_raw);
7147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				} else {
7247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner					selinux_log
7347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner						(SELINUX_ERROR,
7447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner						 "%s: Multiple same specifications for %s.\n",
7547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner						 path, curr_spec->property_key);
7647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				}
7747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			}
7847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		}
7947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
8047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	return rc;
8147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner}
8247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
8347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerstatic int process_line(struct selabel_handle *rec,
8447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			const char *path, char *line_buf,
8547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			int pass, unsigned lineno)
8647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner{
8747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	int items, len;
8847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	char buf1[BUFSIZ], buf2[BUFSIZ];
8947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	char *buf_p, *prop = buf1, *context = buf2;
9047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	struct saved_data *data = (struct saved_data *)rec->data;
9147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	spec_t *spec_arr = data->spec_arr;
9247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	unsigned int nspec = data->nspec;
9347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
9447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	len = strlen(line_buf);
9547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (line_buf[len - 1] == '\n')
9647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		line_buf[len - 1] = 0;
9747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	buf_p = line_buf;
9847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	while (isspace(*buf_p))
9947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		buf_p++;
10047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	/* Skip comment lines and empty lines. */
10147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (*buf_p == '#' || *buf_p == 0)
10247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		return 0;
10347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	items = sscanf(line_buf, "%255s %255s", prop, context);
10447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (items != 2) {
10547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		selinux_log(SELINUX_WARNING,
10647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			    "%s:  line %d is missing fields, skipping\n", path,
10747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			    lineno);
10847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		return 0;
10947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
11047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
11147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (pass == 1) {
11247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		/* On the second pass, process and store the specification in spec. */
11347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		spec_arr[nspec].property_key = strdup(prop);
11447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		if (!spec_arr[nspec].property_key) {
11547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			selinux_log(SELINUX_WARNING,
11647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				    "%s:  out of memory at line %d on prop %s\n",
11747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				    path, lineno, prop);
11847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		return -1;
11947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
12047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		}
12147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
12247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		spec_arr[nspec].lr.ctx_raw = strdup(context);
12347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		if (!spec_arr[nspec].lr.ctx_raw) {
12447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			selinux_log(SELINUX_WARNING,
12547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				    "%s:  out of memory at line %d on context %s\n",
12647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				    path, lineno, context);
12747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		return -1;
12847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		}
12947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
13047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		if (rec->validating) {
13147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		        if (selabel_validate(rec, &spec_arr[nspec].lr) < 0) {
13247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			        selinux_log(SELINUX_WARNING,
13347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner					    "%s:  line %d has invalid context %s\n",
13447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner					    path, lineno, spec_arr[nspec].lr.ctx_raw);
13547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			}
13647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		}
13747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner     	}
13847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
13947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	data->nspec = ++nspec;
14047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	return 0;
14147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner}
14247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
14347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerstatic int init(struct selabel_handle *rec, const struct selinux_opt *opts,
14447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		unsigned n)
14547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner{
14647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	struct saved_data *data = (struct saved_data *)rec->data;
14747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	const char *path = NULL;
14847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	FILE *fp;
14947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	char line_buf[BUFSIZ];
15047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	unsigned int lineno = 0, maxnspec, pass;
15147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	int status = -1;
15247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	struct stat sb;
15347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
15447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	/* Process arguments */
15547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	while (n--)
15647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		switch (opts[n].type) {
15747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		case SELABEL_OPT_PATH:
15847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			path = opts[n].value;
15947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			break;
16047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		}
16147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
16247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	/* Open the specification file. */
16347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if ((fp = fopen(path, "r")) == NULL)
16447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		return -1;
16547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
16647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (fstat(fileno(fp), &sb) < 0)
16747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		return -1;
16847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (!S_ISREG(sb.st_mode)) {
16947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		errno = EINVAL;
17047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		return -1;
17147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
17247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
17347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	/*
17447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	 * Two passes of the specification file. First is to get the size.
17547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	 * After the first pass, the spec array is malloced to the appropriate
17647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	 * size. Second pass is to populate the spec array and check for
17747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	 * dups.
17847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	 */
17947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	maxnspec = UINT_MAX / sizeof(spec_t);
18047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	for (pass = 0; pass < 2; pass++) {
18147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		data->nspec = 0;
18247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
18347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		while (fgets(line_buf, sizeof line_buf - 1, fp)
18447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		       && data->nspec < maxnspec) {
18547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			if (process_line(rec, path, line_buf, pass, ++lineno) != 0) {
18647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				goto finish;
18747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			}
18847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		}
18947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
19047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		if (pass == 1) {
19147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			status = nodups_specs(data, path);
19247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
19347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			if (status)
19447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				goto finish;
19547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		}
19647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
19747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		if (pass == 0) {
19847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
19947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			if (data->nspec == 0) {
20047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				status = 0;
20147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				goto finish;
20247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			}
20347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
20447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			if (NULL == (data->spec_arr =
20547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				     malloc(sizeof(spec_t) * data->nspec)))
20647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				goto finish;
20747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
20847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			memset(data->spec_arr, 0, sizeof(spec_t)*data->nspec);
20947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			maxnspec = data->nspec;
21047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			rewind(fp);
21147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		}
21247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
21347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
21447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	qsort(data->spec_arr, data->nspec, sizeof(struct spec), cmp);
21547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
21647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	status = 0;
21747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerfinish:
21847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	fclose(fp);
21947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	return status;
22047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner}
22147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
22247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner/*
22347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner * Backend interface routines
22447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner */
22547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerstatic void closef(struct selabel_handle *rec)
22647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner{
22747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	struct saved_data *data = (struct saved_data *)rec->data;
22847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	struct spec *spec;
22947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	unsigned int i;
23047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
23147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	for (i = 0; i < data->nspec; i++) {
23247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		spec = &data->spec_arr[i];
23347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		free(spec->property_key);
23447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		free(spec->lr.ctx_raw);
23547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		free(spec->lr.ctx_trans);
23647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
23747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
23847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (data->spec_arr)
23947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		free(data->spec_arr);
24047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
24147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	free(data);
24247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner}
24347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
24447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerstatic struct selabel_lookup_rec *lookup(struct selabel_handle *rec,
24547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner					 const char *key,
24647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner					 int __attribute__((unused)) type)
24747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner{
24847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	struct saved_data *data = (struct saved_data *)rec->data;
24947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	spec_t *spec_arr = data->spec_arr;
25047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	unsigned int i;
25147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	struct selabel_lookup_rec *ret = NULL;
25247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
25347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (!data->nspec) {
25447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		errno = ENOENT;
25547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		goto finish;
25647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
25747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
25847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	for (i = 0; i < data->nspec; i++) {
25947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		if (strncmp(spec_arr[i].property_key, key,
26047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		    strlen(spec_arr[i].property_key)) == 0) {
26147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			break;
26247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		}
26347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		if (strncmp(spec_arr[i].property_key, "*", 1) == 0)
26447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			break;
26547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
26647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
26747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (i >= data->nspec) {
26847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		/* No matching specification. */
26947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		errno = ENOENT;
27047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		goto finish;
27147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
27247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
27347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	ret = &spec_arr[i].lr;
27447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
27547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerfinish:
27647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	return ret;
27747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner}
27847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
27947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerstatic void stats(struct selabel_handle __attribute__((unused)) *rec)
28047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner{
28147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	selinux_log(SELINUX_WARNING, "'stats' functionality not implemented.\n");
28247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner}
28347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
28447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerint selabel_property_init(struct selabel_handle *rec,
28547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			  const struct selinux_opt *opts,
28647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			  unsigned nopts)
28747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner{
28847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	struct saved_data *data;
28947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
29047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	data = (struct saved_data *)malloc(sizeof(*data));
29147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (!data)
29247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		return -1;
29347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	memset(data, 0, sizeof(*data));
29447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
29547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	rec->data = data;
29647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	rec->func_close = &closef;
29747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	rec->func_stats = &stats;
29847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	rec->func_lookup = &lookup;
29947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
30047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	return init(rec, opts, nopts);
30147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner}
302