1f074036424618c130dacb3464465a8b40bffef5Stephen Smalley/*
2f074036424618c130dacb3464465a8b40bffef5Stephen Smalley * File contexts backend for labeling system
3f074036424618c130dacb3464465a8b40bffef5Stephen Smalley *
4f074036424618c130dacb3464465a8b40bffef5Stephen Smalley * Author : Eamon Walsh <ewalsh@tycho.nsa.gov>
5f074036424618c130dacb3464465a8b40bffef5Stephen Smalley */
6f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
7f074036424618c130dacb3464465a8b40bffef5Stephen Smalley#include <fcntl.h>
8f074036424618c130dacb3464465a8b40bffef5Stephen Smalley#include <stdarg.h>
9f074036424618c130dacb3464465a8b40bffef5Stephen Smalley#include <string.h>
10f074036424618c130dacb3464465a8b40bffef5Stephen Smalley#include <stdio.h>
11f074036424618c130dacb3464465a8b40bffef5Stephen Smalley#include <ctype.h>
12f074036424618c130dacb3464465a8b40bffef5Stephen Smalley#include <errno.h>
13f074036424618c130dacb3464465a8b40bffef5Stephen Smalley#include <limits.h>
14f074036424618c130dacb3464465a8b40bffef5Stephen Smalley#include <sys/types.h>
15f074036424618c130dacb3464465a8b40bffef5Stephen Smalley#include <sys/stat.h>
16f074036424618c130dacb3464465a8b40bffef5Stephen Smalley#include <unistd.h>
17f074036424618c130dacb3464465a8b40bffef5Stephen Smalley#include "callbacks.h"
18f074036424618c130dacb3464465a8b40bffef5Stephen Smalley#include "label_internal.h"
19d0b768abcd2b4adb1853ac38e59aa80f09872ac3Nick Kralevich#include <pcre.h>
20f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
21f074036424618c130dacb3464465a8b40bffef5Stephen Smalley/*
22f074036424618c130dacb3464465a8b40bffef5Stephen Smalley * Internals, mostly moved over from matchpathcon.c
23f074036424618c130dacb3464465a8b40bffef5Stephen Smalley */
24f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
25f074036424618c130dacb3464465a8b40bffef5Stephen Smalley/* A file security context specification. */
26f074036424618c130dacb3464465a8b40bffef5Stephen Smalleytypedef struct spec {
27f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	struct selabel_lookup_rec lr;	/* holds contexts for lookup result */
28f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	char *regex_str;	/* regular expession string for diagnostics */
29f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	char *type_str;		/* type string for diagnostic messages */
30d0b768abcd2b4adb1853ac38e59aa80f09872ac3Nick Kralevich	pcre *regex;		/* compiled regular expression */
31d0b768abcd2b4adb1853ac38e59aa80f09872ac3Nick Kralevich	pcre_extra *sd;         /* pcre study result */
32f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	char regcomp;           /* regex_str has been compiled to regex */
33f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	mode_t mode;		/* mode format value */
34f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	int matches;		/* number of matching pathnames */
35f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	int hasMetaChars;	/* regular expression has meta-chars */
36f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	int stem_id;		/* indicates which stem-compression item */
370e7340fb99b931540e2baf4778abeb53d40084e7Stephen Smalley	size_t prefix_len;      /* length of fixed path prefix */
38f074036424618c130dacb3464465a8b40bffef5Stephen Smalley} spec_t;
39f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
40f074036424618c130dacb3464465a8b40bffef5Stephen Smalley/* A regular expression stem */
41f074036424618c130dacb3464465a8b40bffef5Stephen Smalleytypedef struct stem {
42f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	char *buf;
43f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	int len;
44f074036424618c130dacb3464465a8b40bffef5Stephen Smalley} stem_t;
45f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
46f074036424618c130dacb3464465a8b40bffef5Stephen Smalley/* Our stored configuration */
47f074036424618c130dacb3464465a8b40bffef5Stephen Smalleystruct saved_data {
48f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	/*
49f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	 * The array of specifications, initially in the same order as in
50f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	 * the specification file. Sorting occurs based on hasMetaChars.
51f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	 */
52f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	spec_t *spec_arr;
53f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	unsigned int nspec;
54f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	unsigned int ncomp;
55f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
56f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	/*
57f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	 * The array of regular expression stems.
58f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	 */
59f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	stem_t *stem_arr;
60f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	int num_stems;
61f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	int alloc_stems;
62f074036424618c130dacb3464465a8b40bffef5Stephen Smalley};
63f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
64f074036424618c130dacb3464465a8b40bffef5Stephen Smalley/* Return the length of the text that can be considered the stem, returns 0
65f074036424618c130dacb3464465a8b40bffef5Stephen Smalley * if there is no identifiable stem */
66f074036424618c130dacb3464465a8b40bffef5Stephen Smalleystatic int get_stem_from_spec(const char *const buf)
67f074036424618c130dacb3464465a8b40bffef5Stephen Smalley{
68f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	const char *tmp = strchr(buf + 1, '/');
69f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	const char *ind;
70f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
71f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	if (!tmp)
72f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		return 0;
73f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
74f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	for (ind = buf; ind < tmp; ind++) {
75f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		if (strchr(".^$?*+|[({", (int)*ind))
76f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			return 0;
77f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	}
78f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	return tmp - buf;
79f074036424618c130dacb3464465a8b40bffef5Stephen Smalley}
80f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
81f074036424618c130dacb3464465a8b40bffef5Stephen Smalley/* return the length of the text that is the stem of a file name */
82f074036424618c130dacb3464465a8b40bffef5Stephen Smalleystatic int get_stem_from_file_name(const char *const buf)
83f074036424618c130dacb3464465a8b40bffef5Stephen Smalley{
84f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	const char *tmp = strchr(buf + 1, '/');
85f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
86f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	if (!tmp)
87f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		return 0;
88f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	return tmp - buf;
89f074036424618c130dacb3464465a8b40bffef5Stephen Smalley}
90f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
91f074036424618c130dacb3464465a8b40bffef5Stephen Smalley/* find the stem of a file spec, returns the index into stem_arr for a new
92f074036424618c130dacb3464465a8b40bffef5Stephen Smalley * or existing stem, (or -1 if there is no possible stem - IE for a file in
93f074036424618c130dacb3464465a8b40bffef5Stephen Smalley * the root directory or a regex that is too complex for us). */
94f074036424618c130dacb3464465a8b40bffef5Stephen Smalleystatic int find_stem_from_spec(struct saved_data *data, const char *buf)
95f074036424618c130dacb3464465a8b40bffef5Stephen Smalley{
96f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	int i, num = data->num_stems;
97f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	int stem_len = get_stem_from_spec(buf);
98f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
99f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	if (!stem_len)
100f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		return -1;
101f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	for (i = 0; i < num; i++) {
102f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		if (stem_len == data->stem_arr[i].len
103f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		    && !strncmp(buf, data->stem_arr[i].buf, stem_len))
104f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			return i;
105f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	}
106f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	if (data->alloc_stems == num) {
107f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		stem_t *tmp_arr;
108f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		data->alloc_stems = data->alloc_stems * 2 + 16;
1095b91e6297719ee29fc4d3795a4bc9d7343b30fb0Nick Kralevich		tmp_arr = (stem_t *) realloc(data->stem_arr,
110f074036424618c130dacb3464465a8b40bffef5Stephen Smalley				  sizeof(stem_t) * data->alloc_stems);
111f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		if (!tmp_arr)
112f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			return -1;
113f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		data->stem_arr = tmp_arr;
114f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	}
115f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	data->stem_arr[num].len = stem_len;
1165b91e6297719ee29fc4d3795a4bc9d7343b30fb0Nick Kralevich	data->stem_arr[num].buf = (char *) malloc(stem_len + 1);
117f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	if (!data->stem_arr[num].buf)
118f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		return -1;
119f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	memcpy(data->stem_arr[num].buf, buf, stem_len);
120f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	data->stem_arr[num].buf[stem_len] = '\0';
121f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	data->num_stems++;
122f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	buf += stem_len;
123f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	return num;
124f074036424618c130dacb3464465a8b40bffef5Stephen Smalley}
125f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
126f074036424618c130dacb3464465a8b40bffef5Stephen Smalley/* find the stem of a file name, returns the index into stem_arr (or -1 if
127f074036424618c130dacb3464465a8b40bffef5Stephen Smalley * there is no match - IE for a file in the root directory or a regex that is
128f074036424618c130dacb3464465a8b40bffef5Stephen Smalley * too complex for us).  Makes buf point to the text AFTER the stem. */
129f074036424618c130dacb3464465a8b40bffef5Stephen Smalleystatic int find_stem_from_file(struct saved_data *data, const char **buf)
130f074036424618c130dacb3464465a8b40bffef5Stephen Smalley{
131f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	int i;
132f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	int stem_len = get_stem_from_file_name(*buf);
133f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
134f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	if (!stem_len)
135f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		return -1;
136f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	for (i = 0; i < data->num_stems; i++) {
137f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		if (stem_len == data->stem_arr[i].len
138f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		    && !strncmp(*buf, data->stem_arr[i].buf, stem_len)) {
139f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			*buf += stem_len;
140f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			return i;
141f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		}
142f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	}
143f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	return -1;
144f074036424618c130dacb3464465a8b40bffef5Stephen Smalley}
145f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
146f074036424618c130dacb3464465a8b40bffef5Stephen Smalley/*
147f074036424618c130dacb3464465a8b40bffef5Stephen Smalley * Warn about duplicate specifications.
148f074036424618c130dacb3464465a8b40bffef5Stephen Smalley */
149f074036424618c130dacb3464465a8b40bffef5Stephen Smalleystatic int nodups_specs(struct saved_data *data, const char *path)
150f074036424618c130dacb3464465a8b40bffef5Stephen Smalley{
151f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	int rc = 0;
152f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	unsigned int ii, jj;
153f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	struct spec *curr_spec, *spec_arr = data->spec_arr;
154f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
155f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	for (ii = 0; ii < data->nspec; ii++) {
156f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		curr_spec = &spec_arr[ii];
157f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		for (jj = ii + 1; jj < data->nspec; jj++) {
158f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			if ((!strcmp
159f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			     (spec_arr[jj].regex_str, curr_spec->regex_str))
160f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			    && (!spec_arr[jj].mode || !curr_spec->mode
161f074036424618c130dacb3464465a8b40bffef5Stephen Smalley				|| spec_arr[jj].mode == curr_spec->mode)) {
162f074036424618c130dacb3464465a8b40bffef5Stephen Smalley				rc = -1;
163f074036424618c130dacb3464465a8b40bffef5Stephen Smalley				errno = EINVAL;
164f074036424618c130dacb3464465a8b40bffef5Stephen Smalley				if (strcmp
165f074036424618c130dacb3464465a8b40bffef5Stephen Smalley				    (spec_arr[jj].lr.ctx_raw,
166f074036424618c130dacb3464465a8b40bffef5Stephen Smalley				     curr_spec->lr.ctx_raw)) {
167f074036424618c130dacb3464465a8b40bffef5Stephen Smalley					selinux_log
168f074036424618c130dacb3464465a8b40bffef5Stephen Smalley						(SELINUX_ERROR,
169f074036424618c130dacb3464465a8b40bffef5Stephen Smalley						 "%s: Multiple different specifications for %s  (%s and %s).\n",
170f074036424618c130dacb3464465a8b40bffef5Stephen Smalley						 path, curr_spec->regex_str,
171f074036424618c130dacb3464465a8b40bffef5Stephen Smalley						 spec_arr[jj].lr.ctx_raw,
172f074036424618c130dacb3464465a8b40bffef5Stephen Smalley						 curr_spec->lr.ctx_raw);
173f074036424618c130dacb3464465a8b40bffef5Stephen Smalley				} else {
174f074036424618c130dacb3464465a8b40bffef5Stephen Smalley					selinux_log
175f074036424618c130dacb3464465a8b40bffef5Stephen Smalley						(SELINUX_ERROR,
176f074036424618c130dacb3464465a8b40bffef5Stephen Smalley						 "%s: Multiple same specifications for %s.\n",
177f074036424618c130dacb3464465a8b40bffef5Stephen Smalley						 path, curr_spec->regex_str);
178f074036424618c130dacb3464465a8b40bffef5Stephen Smalley				}
179f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			}
180f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		}
181f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	}
182f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	return rc;
183f074036424618c130dacb3464465a8b40bffef5Stephen Smalley}
184f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
185f074036424618c130dacb3464465a8b40bffef5Stephen Smalley/* Determine if the regular expression specification has any meta characters. */
186f074036424618c130dacb3464465a8b40bffef5Stephen Smalleystatic void spec_hasMetaChars(struct spec *spec)
187f074036424618c130dacb3464465a8b40bffef5Stephen Smalley{
188f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	char *c;
1890e7340fb99b931540e2baf4778abeb53d40084e7Stephen Smalley	size_t len;
190f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	char *end;
191f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
192f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	c = spec->regex_str;
193f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	len = strlen(spec->regex_str);
194f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	end = c + len;
195f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
196f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	spec->hasMetaChars = 0;
1970e7340fb99b931540e2baf4778abeb53d40084e7Stephen Smalley	spec->prefix_len = len;
198f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
199f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	/* Look at each character in the RE specification string for a
200f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	 * meta character. Return when any meta character reached. */
201f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	while (c != end) {
202f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		switch (*c) {
203f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		case '.':
204f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		case '^':
205f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		case '$':
206f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		case '?':
207f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		case '*':
208f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		case '+':
209f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		case '|':
210f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		case '[':
211f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		case '(':
212f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		case '{':
213f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			spec->hasMetaChars = 1;
2140e7340fb99b931540e2baf4778abeb53d40084e7Stephen Smalley			spec->prefix_len = c - spec->regex_str;
215f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			return;
216f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		case '\\':	/* skip the next character */
217f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			c++;
218f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			break;
219f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		default:
220f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			break;
221f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
222f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		}
223f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		c++;
224f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	}
225f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	return;
226f074036424618c130dacb3464465a8b40bffef5Stephen Smalley}
227f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
228d0b768abcd2b4adb1853ac38e59aa80f09872ac3Nick Kralevichstatic int compile_regex(struct saved_data *data, spec_t *spec, const char **errbuf)
229f074036424618c130dacb3464465a8b40bffef5Stephen Smalley{
230d0b768abcd2b4adb1853ac38e59aa80f09872ac3Nick Kralevich	const char *tmperrbuf;
231f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	char *reg_buf, *anchored_regex, *cp;
232f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	stem_t *stem_arr = data->stem_arr;
233f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	size_t len;
234d0b768abcd2b4adb1853ac38e59aa80f09872ac3Nick Kralevich	int erroff;
235f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
236f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	if (spec->regcomp)
237f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		return 0; /* already done */
238f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
239f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	data->ncomp++; /* how many compiled regexes required */
240f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
241f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	/* Skip the fixed stem. */
242f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	reg_buf = spec->regex_str;
243f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	if (spec->stem_id >= 0)
244f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		reg_buf += stem_arr[spec->stem_id].len;
245f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
246f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	/* Anchor the regular expression. */
247f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	len = strlen(reg_buf);
2485b91e6297719ee29fc4d3795a4bc9d7343b30fb0Nick Kralevich	cp = anchored_regex = (char *) malloc(len + 3);
249f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	if (!anchored_regex)
250f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		return -1;
251f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	/* Create ^...$ regexp.  */
252f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	*cp++ = '^';
253f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	memcpy(cp, reg_buf, len);
254f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	cp += len;
255f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	*cp++ = '$';
256f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	*cp = '\0';
257f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
258f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	/* Compile the regular expression. */
25951fc85bc845bf6c7de1962efe6458ec701051162Nick Kralevich	spec->regex = pcre_compile(anchored_regex, PCRE_DOTALL, &tmperrbuf, &erroff, NULL);
260d0b768abcd2b4adb1853ac38e59aa80f09872ac3Nick Kralevich	free(anchored_regex);
261d0b768abcd2b4adb1853ac38e59aa80f09872ac3Nick Kralevich	if (!spec->regex) {
262d0b768abcd2b4adb1853ac38e59aa80f09872ac3Nick Kralevich		if (errbuf)
263d0b768abcd2b4adb1853ac38e59aa80f09872ac3Nick Kralevich			*errbuf=tmperrbuf;
264d0b768abcd2b4adb1853ac38e59aa80f09872ac3Nick Kralevich		return -1;
265d0b768abcd2b4adb1853ac38e59aa80f09872ac3Nick Kralevich	}
266d0b768abcd2b4adb1853ac38e59aa80f09872ac3Nick Kralevich
267d0b768abcd2b4adb1853ac38e59aa80f09872ac3Nick Kralevich	spec->sd = pcre_study(spec->regex, 0, &tmperrbuf);
268f74bc4e9ae72f60e9d1173802fcc275a9339c261Stephen Smalley	if (!spec->sd && tmperrbuf) {
269d0b768abcd2b4adb1853ac38e59aa80f09872ac3Nick Kralevich		if (errbuf)
270d0b768abcd2b4adb1853ac38e59aa80f09872ac3Nick Kralevich			*errbuf=tmperrbuf;
271f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		return -1;
272f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	}
273f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
274f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	/* Done. */
275f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	spec->regcomp = 1;
276f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
277f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	return 0;
278f074036424618c130dacb3464465a8b40bffef5Stephen Smalley}
279f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
280f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
281f074036424618c130dacb3464465a8b40bffef5Stephen Smalleystatic int process_line(struct selabel_handle *rec,
282f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			const char *path, const char *prefix,
283f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			char *line_buf, int pass, unsigned lineno)
284f074036424618c130dacb3464465a8b40bffef5Stephen Smalley{
285f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	int items, len;
286f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	char buf1[BUFSIZ], buf2[BUFSIZ], buf3[BUFSIZ];
287f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	char *buf_p, *regex = buf1, *type = buf2, *context = buf3;
288f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	struct saved_data *data = (struct saved_data *)rec->data;
289f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	spec_t *spec_arr = data->spec_arr;
290f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	unsigned int nspec = data->nspec;
291f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
292f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	len = strlen(line_buf);
293f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	if (line_buf[len - 1] == '\n')
294f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		line_buf[len - 1] = 0;
295f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	buf_p = line_buf;
296f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	while (isspace(*buf_p))
297f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		buf_p++;
298f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	/* Skip comment lines and empty lines. */
299f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	if (*buf_p == '#' || *buf_p == 0)
300f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		return 0;
301f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	items = sscanf(line_buf, "%255s %255s %255s", regex, type, context);
302f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	if (items < 2) {
303f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		selinux_log(SELINUX_WARNING,
304f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			    "%s:  line %d is missing fields, skipping\n", path,
305f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			    lineno);
306f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		return 0;
307f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	} else if (items == 2) {
308f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		/* The type field is optional. */
309f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		context = type;
310f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		type = NULL;
311f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	}
312f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
313f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	len = get_stem_from_spec(regex);
314f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	if (len && prefix && strncmp(prefix, regex, len)) {
315f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		/* Stem of regex does not match requested prefix, discard. */
316f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		return 0;
317f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	}
318f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
319f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	if (pass == 1) {
320f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		/* On the second pass, process and store the specification in spec. */
321d0b768abcd2b4adb1853ac38e59aa80f09872ac3Nick Kralevich		const char *errbuf = NULL;
322f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		spec_arr[nspec].stem_id = find_stem_from_spec(data, regex);
323f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		spec_arr[nspec].regex_str = strdup(regex);
324f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		if (!spec_arr[nspec].regex_str) {
325f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			selinux_log(SELINUX_WARNING,
326f074036424618c130dacb3464465a8b40bffef5Stephen Smalley				   "%s:  out of memory at line %d on regex %s\n",
327f074036424618c130dacb3464465a8b40bffef5Stephen Smalley				   path, lineno, regex);
328f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			return -1;
329f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
330f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		}
331f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		if (rec->validating && compile_regex(data, &spec_arr[nspec], &errbuf)) {
332f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			selinux_log(SELINUX_WARNING,
333f074036424618c130dacb3464465a8b40bffef5Stephen Smalley				   "%s:  line %d has invalid regex %s:  %s\n",
334f074036424618c130dacb3464465a8b40bffef5Stephen Smalley				   path, lineno, regex,
335f074036424618c130dacb3464465a8b40bffef5Stephen Smalley				   (errbuf ? errbuf : "out of memory"));
336f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		}
337f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
338f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		/* Convert the type string to a mode format */
339f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		spec_arr[nspec].mode = 0;
340f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		if (!type)
341f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			goto skip_type;
342f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		spec_arr[nspec].type_str = strdup(type);
343f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		len = strlen(type);
344f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		if (type[0] != '-' || len != 2) {
345f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			selinux_log(SELINUX_WARNING,
346f074036424618c130dacb3464465a8b40bffef5Stephen Smalley				    "%s:  line %d has invalid file type %s\n",
347f074036424618c130dacb3464465a8b40bffef5Stephen Smalley				    path, lineno, type);
348f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			return 0;
349f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		}
350f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		switch (type[1]) {
351f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		case 'b':
352f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			spec_arr[nspec].mode = S_IFBLK;
353f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			break;
354f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		case 'c':
355f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			spec_arr[nspec].mode = S_IFCHR;
356f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			break;
357f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		case 'd':
358f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			spec_arr[nspec].mode = S_IFDIR;
359f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			break;
360f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		case 'p':
361f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			spec_arr[nspec].mode = S_IFIFO;
362f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			break;
363f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		case 'l':
364f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			spec_arr[nspec].mode = S_IFLNK;
365f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			break;
366f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		case 's':
367f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			spec_arr[nspec].mode = S_IFSOCK;
368f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			break;
369f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		case '-':
370f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			spec_arr[nspec].mode = S_IFREG;
371f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			break;
372f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		default:
373f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			selinux_log(SELINUX_WARNING,
374f074036424618c130dacb3464465a8b40bffef5Stephen Smalley				    "%s:  line %d has invalid file type %s\n",
375f074036424618c130dacb3464465a8b40bffef5Stephen Smalley				    path, lineno, type);
376f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			return 0;
377f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		}
378f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
379f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	skip_type:
380f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		spec_arr[nspec].lr.ctx_raw = strdup(context);
381f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
38261e917ad2f1fbf39b3205d7568fcd3684b0ccda6Stephen Smalley		if (strcmp(context, "<<none>>") && rec->validating) {
38361e917ad2f1fbf39b3205d7568fcd3684b0ccda6Stephen Smalley			if (selabel_validate(rec, &spec_arr[nspec].lr) < 0) {
38461e917ad2f1fbf39b3205d7568fcd3684b0ccda6Stephen Smalley				selinux_log(SELINUX_WARNING,
38561e917ad2f1fbf39b3205d7568fcd3684b0ccda6Stephen Smalley					    "%s:  line %d has invalid context %s\n",
38661e917ad2f1fbf39b3205d7568fcd3684b0ccda6Stephen Smalley					    path, lineno, spec_arr[nspec].lr.ctx_raw);
38761e917ad2f1fbf39b3205d7568fcd3684b0ccda6Stephen Smalley			}
38861e917ad2f1fbf39b3205d7568fcd3684b0ccda6Stephen Smalley		}
38961e917ad2f1fbf39b3205d7568fcd3684b0ccda6Stephen Smalley
390f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		/* Determine if specification has
391f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		 * any meta characters in the RE */
392f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		spec_hasMetaChars(&spec_arr[nspec]);
393f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	}
394f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
395f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	data->nspec = ++nspec;
396f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	return 0;
397f074036424618c130dacb3464465a8b40bffef5Stephen Smalley}
398f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
399a2e47cd90d84d48cde19575d044577a3fc7a4000Stephen Smalleystatic int init(struct selabel_handle *rec, const struct selinux_opt *opts,
400f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		unsigned n)
401f074036424618c130dacb3464465a8b40bffef5Stephen Smalley{
402f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	struct saved_data *data = (struct saved_data *)rec->data;
403f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	const char *path = NULL;
404f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	const char *prefix = NULL;
405f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	FILE *fp;
406f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	FILE *localfp = NULL;
407f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	FILE *homedirfp = NULL;
408f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	char local_path[PATH_MAX + 1];
409f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	char homedir_path[PATH_MAX + 1];
410f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	char line_buf[BUFSIZ];
411f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	unsigned int lineno, pass, i, j, maxnspec;
412f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	spec_t *spec_copy = NULL;
413f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	int status = -1, baseonly = 0;
414f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	struct stat sb;
415f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
416f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	/* Process arguments */
417f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	while (n--)
418f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		switch(opts[n].type) {
419f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		case SELABEL_OPT_PATH:
420f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			path = opts[n].value;
421f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			break;
422f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		case SELABEL_OPT_SUBSET:
423f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			prefix = opts[n].value;
424f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			break;
425f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		case SELABEL_OPT_BASEONLY:
426f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			baseonly = !!opts[n].value;
427f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			break;
428f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		}
429f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
430f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	/* Open the specification file. */
431f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	if ((fp = fopen(path, "r")) == NULL)
432f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		return -1;
433f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
434f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	if (fstat(fileno(fp), &sb) < 0)
435f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		return -1;
436f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	if (!S_ISREG(sb.st_mode)) {
437f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		errno = EINVAL;
438f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		return -1;
439f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	}
440f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
441f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	if (!baseonly) {
442f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		snprintf(homedir_path, sizeof(homedir_path), "%s.homedirs",
443f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			 path);
444f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		homedirfp = fopen(homedir_path, "r");
445f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
446f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		snprintf(local_path, sizeof(local_path), "%s.local", path);
447f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		localfp = fopen(local_path, "r");
448f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	}
449f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
450f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	/*
451f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	 * Perform two passes over the specification file.
452f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	 * The first pass counts the number of specifications and
453f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	 * performs simple validation of the input.  At the end
454f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	 * of the first pass, the spec array is allocated.
455f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	 * The second pass performs detailed validation of the input
456f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	 * and fills in the spec array.
457f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	 */
458f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	maxnspec = UINT_MAX / sizeof(spec_t);
459f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	for (pass = 0; pass < 2; pass++) {
460f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		lineno = 0;
461f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		data->nspec = 0;
462f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		data->ncomp = 0;
463f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		while (fgets(line_buf, sizeof line_buf - 1, fp)
464f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		       && data->nspec < maxnspec) {
465f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			if (process_line(rec, path, prefix, line_buf,
466f074036424618c130dacb3464465a8b40bffef5Stephen Smalley					 pass, ++lineno) != 0)
467f074036424618c130dacb3464465a8b40bffef5Stephen Smalley				goto finish;
468f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		}
469f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		if (pass == 1) {
470f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			status = nodups_specs(data, path);
471f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			if (status)
472f074036424618c130dacb3464465a8b40bffef5Stephen Smalley				goto finish;
473f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		}
474f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		lineno = 0;
475f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		if (homedirfp)
476f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			while (fgets(line_buf, sizeof line_buf - 1, homedirfp)
477f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			       && data->nspec < maxnspec) {
478f074036424618c130dacb3464465a8b40bffef5Stephen Smalley				if (process_line
479f074036424618c130dacb3464465a8b40bffef5Stephen Smalley				    (rec, homedir_path, prefix,
480f074036424618c130dacb3464465a8b40bffef5Stephen Smalley				     line_buf, pass, ++lineno) != 0)
481f074036424618c130dacb3464465a8b40bffef5Stephen Smalley					goto finish;
482f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			}
483f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
484f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		lineno = 0;
485f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		if (localfp)
486f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			while (fgets(line_buf, sizeof line_buf - 1, localfp)
487f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			       && data->nspec < maxnspec) {
488f074036424618c130dacb3464465a8b40bffef5Stephen Smalley				if (process_line
489f074036424618c130dacb3464465a8b40bffef5Stephen Smalley				    (rec, local_path, prefix, line_buf,
490f074036424618c130dacb3464465a8b40bffef5Stephen Smalley				     pass, ++lineno) != 0)
491f074036424618c130dacb3464465a8b40bffef5Stephen Smalley					goto finish;
492f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			}
493f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
494f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		if (pass == 0) {
495f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			if (data->nspec == 0) {
496f074036424618c130dacb3464465a8b40bffef5Stephen Smalley				status = 0;
497f074036424618c130dacb3464465a8b40bffef5Stephen Smalley				goto finish;
498f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			}
499f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			if (NULL == (data->spec_arr =
5005b91e6297719ee29fc4d3795a4bc9d7343b30fb0Nick Kralevich				     (spec_t *) malloc(sizeof(spec_t) * data->nspec)))
501f074036424618c130dacb3464465a8b40bffef5Stephen Smalley				goto finish;
502f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			memset(data->spec_arr, 0, sizeof(spec_t)*data->nspec);
503f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			maxnspec = data->nspec;
504f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			rewind(fp);
505f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			if (homedirfp)
506f074036424618c130dacb3464465a8b40bffef5Stephen Smalley				rewind(homedirfp);
507f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			if (localfp)
508f074036424618c130dacb3464465a8b40bffef5Stephen Smalley				rewind(localfp);
509f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		}
510f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	}
511f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
512f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	/* Move exact pathname specifications to the end. */
5135b91e6297719ee29fc4d3795a4bc9d7343b30fb0Nick Kralevich	spec_copy = (spec_t *) malloc(sizeof(spec_t) * data->nspec);
514f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	if (!spec_copy)
515f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		goto finish;
516f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	j = 0;
517f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	for (i = 0; i < data->nspec; i++)
518f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		if (data->spec_arr[i].hasMetaChars)
519f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			memcpy(&spec_copy[j++],
520f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			       &data->spec_arr[i], sizeof(spec_t));
521f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	for (i = 0; i < data->nspec; i++)
522f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		if (!data->spec_arr[i].hasMetaChars)
523f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			memcpy(&spec_copy[j++],
524f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			       &data->spec_arr[i], sizeof(spec_t));
525f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	free(data->spec_arr);
526f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	data->spec_arr = spec_copy;
527f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
528f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	status = 0;
529f074036424618c130dacb3464465a8b40bffef5Stephen Smalleyfinish:
530f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	fclose(fp);
531f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	if (data->spec_arr != spec_copy)
532f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		free(data->spec_arr);
533f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	if (homedirfp)
534f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		fclose(homedirfp);
535f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	if (localfp)
536f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		fclose(localfp);
537f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	return status;
538f074036424618c130dacb3464465a8b40bffef5Stephen Smalley}
539f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
540f074036424618c130dacb3464465a8b40bffef5Stephen Smalley/*
541f074036424618c130dacb3464465a8b40bffef5Stephen Smalley * Backend interface routines
542f074036424618c130dacb3464465a8b40bffef5Stephen Smalley */
543f074036424618c130dacb3464465a8b40bffef5Stephen Smalleystatic void closef(struct selabel_handle *rec)
544f074036424618c130dacb3464465a8b40bffef5Stephen Smalley{
545f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	struct saved_data *data = (struct saved_data *)rec->data;
546f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	struct spec *spec;
547f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	struct stem *stem;
548f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	unsigned int i;
549f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
550f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	for (i = 0; i < data->nspec; i++) {
551f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		spec = &data->spec_arr[i];
552f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		free(spec->regex_str);
553f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		free(spec->type_str);
554f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		free(spec->lr.ctx_raw);
555f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		free(spec->lr.ctx_trans);
556d0b768abcd2b4adb1853ac38e59aa80f09872ac3Nick Kralevich		if (spec->regcomp) {
557d0b768abcd2b4adb1853ac38e59aa80f09872ac3Nick Kralevich			pcre_free(spec->regex);
558d0b768abcd2b4adb1853ac38e59aa80f09872ac3Nick Kralevich			pcre_free_study(spec->sd);
559d0b768abcd2b4adb1853ac38e59aa80f09872ac3Nick Kralevich		}
560f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	}
561f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
562f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	for (i = 0; i < (unsigned int)data->num_stems; i++) {
563f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		stem = &data->stem_arr[i];
564f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		free(stem->buf);
565f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	}
566f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
567f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	if (data->spec_arr)
568f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		free(data->spec_arr);
569f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	if (data->stem_arr)
570f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		free(data->stem_arr);
571f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
572f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	free(data);
573f074036424618c130dacb3464465a8b40bffef5Stephen Smalley}
574f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
575be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalleystatic spec_t *lookup_common(struct selabel_handle *rec,
576be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley			     const char *key,
577be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley			     int type,
578be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley			     bool partial)
579f074036424618c130dacb3464465a8b40bffef5Stephen Smalley{
580f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	struct saved_data *data = (struct saved_data *)rec->data;
581f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	spec_t *spec_arr = data->spec_arr;
582d0b768abcd2b4adb1853ac38e59aa80f09872ac3Nick Kralevich	int i, rc, file_stem, pcre_options = 0;
583f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	mode_t mode = (mode_t)type;
584f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	const char *buf;
585be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley	spec_t *ret = NULL;
586f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	char *clean_key = NULL;
587f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	const char *prev_slash, *next_slash;
588f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	unsigned int sofar = 0;
589f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
590f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	if (!data->nspec) {
591f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		errno = ENOENT;
592f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		goto finish;
593f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	}
594f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
595f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	/* Remove duplicate slashes */
596f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	if ((next_slash = strstr(key, "//"))) {
5975b91e6297719ee29fc4d3795a4bc9d7343b30fb0Nick Kralevich		clean_key = (char *) malloc(strlen(key) + 1);
598f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		if (!clean_key)
599f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			goto finish;
600f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		prev_slash = key;
601f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		while (next_slash) {
602f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			memcpy(clean_key + sofar, prev_slash, next_slash - prev_slash);
603f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			sofar += next_slash - prev_slash;
604f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			prev_slash = next_slash + 1;
605f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			next_slash = strstr(prev_slash, "//");
606f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		}
607f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		strcpy(clean_key + sofar, prev_slash);
608f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		key = clean_key;
609f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	}
610f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
611f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	buf = key;
612f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	file_stem = find_stem_from_file(data, &buf);
613f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	mode &= S_IFMT;
614f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
615d0b768abcd2b4adb1853ac38e59aa80f09872ac3Nick Kralevich	if (partial)
616d0b768abcd2b4adb1853ac38e59aa80f09872ac3Nick Kralevich		pcre_options |= PCRE_PARTIAL_SOFT;
617d0b768abcd2b4adb1853ac38e59aa80f09872ac3Nick Kralevich
618f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	/*
619f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	 * Check for matching specifications in reverse order, so that
620f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	 * the last matching specification is used.
621f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	 */
622f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	for (i = data->nspec - 1; i >= 0; i--) {
623f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		/* if the spec in question matches no stem or has the same
624f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		 * stem as the file AND if the spec in question has no mode
625f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		 * specified or if the mode matches the file mode then we do
626f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		 * a regex check        */
627f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		if ((spec_arr[i].stem_id == -1
628f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		     || spec_arr[i].stem_id == file_stem)
629f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		    && (!mode || !spec_arr[i].mode
630f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			|| mode == spec_arr[i].mode)) {
631f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			if (compile_regex(data, &spec_arr[i], NULL) < 0)
632f074036424618c130dacb3464465a8b40bffef5Stephen Smalley				goto finish;
633f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			if (spec_arr[i].stem_id == -1)
634d0b768abcd2b4adb1853ac38e59aa80f09872ac3Nick Kralevich				rc = pcre_exec(spec_arr[i].regex, spec_arr[i].sd, key, strlen(key), 0, pcre_options, NULL, 0);
635f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			else
636d0b768abcd2b4adb1853ac38e59aa80f09872ac3Nick Kralevich				rc = pcre_exec(spec_arr[i].regex, spec_arr[i].sd, buf, strlen(buf), 0, pcre_options, NULL, 0);
637f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
638f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			if (rc == 0) {
639f074036424618c130dacb3464465a8b40bffef5Stephen Smalley				spec_arr[i].matches++;
640f074036424618c130dacb3464465a8b40bffef5Stephen Smalley				break;
641d0b768abcd2b4adb1853ac38e59aa80f09872ac3Nick Kralevich			} else if (partial && rc == PCRE_ERROR_PARTIAL)
642d0b768abcd2b4adb1853ac38e59aa80f09872ac3Nick Kralevich				break;
6430e7340fb99b931540e2baf4778abeb53d40084e7Stephen Smalley
644d0b768abcd2b4adb1853ac38e59aa80f09872ac3Nick Kralevich			if (rc == PCRE_ERROR_NOMATCH)
645f074036424618c130dacb3464465a8b40bffef5Stephen Smalley				continue;
646f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			/* else it's an error */
647f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			goto finish;
648f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		}
649f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	}
650f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
651f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	if (i < 0 || strcmp(spec_arr[i].lr.ctx_raw, "<<none>>") == 0) {
652f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		/* No matching specification. */
653f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		errno = ENOENT;
654f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		goto finish;
655f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	}
656f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
657be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley	ret = &spec_arr[i];
658f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
659f074036424618c130dacb3464465a8b40bffef5Stephen Smalleyfinish:
660f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	free(clean_key);
661f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	return ret;
662f074036424618c130dacb3464465a8b40bffef5Stephen Smalley}
663f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
6640e7340fb99b931540e2baf4778abeb53d40084e7Stephen Smalleystatic struct selabel_lookup_rec *lookup(struct selabel_handle *rec,
6650e7340fb99b931540e2baf4778abeb53d40084e7Stephen Smalley					 const char *key, int type)
6660e7340fb99b931540e2baf4778abeb53d40084e7Stephen Smalley{
667be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley	spec_t *spec;
668be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley	spec = lookup_common(rec, key, type, false);
669be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley	if (spec)
670be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley		return &spec->lr;
671be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley	return NULL;
6720e7340fb99b931540e2baf4778abeb53d40084e7Stephen Smalley}
6730e7340fb99b931540e2baf4778abeb53d40084e7Stephen Smalley
6740e7340fb99b931540e2baf4778abeb53d40084e7Stephen Smalleystatic bool partial_match(struct selabel_handle *rec, const char *key)
6750e7340fb99b931540e2baf4778abeb53d40084e7Stephen Smalley{
6760e7340fb99b931540e2baf4778abeb53d40084e7Stephen Smalley	return lookup_common(rec, key, 0, true) ? true : false;
6770e7340fb99b931540e2baf4778abeb53d40084e7Stephen Smalley}
6780e7340fb99b931540e2baf4778abeb53d40084e7Stephen Smalley
679be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalleystatic struct selabel_lookup_rec *lookup_best_match(struct selabel_handle *rec,
680be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley						    const char *key,
681be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley						    const char **aliases,
682be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley						    int type)
683be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley{
684be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley	size_t n, i;
685be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley	int best = -1;
686be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley	spec_t **specs;
687be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley	size_t prefix_len = 0;
688be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley	struct selabel_lookup_rec *lr = NULL;
689be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley
690be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley	if (!aliases || !aliases[0])
691be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley		return lookup(rec, key, type);
692be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley
693be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley	for (n = 0; aliases[n]; n++)
694be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley		;
695be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley
696be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley	specs = calloc(n+1, sizeof(spec_t *));
697be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley	if (!specs)
698be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley		return NULL;
699be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley	specs[0] = lookup_common(rec, key, type, false);
700be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley	if (specs[0]) {
701be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley		if (!specs[0]->hasMetaChars) {
702be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley			/* exact match on key */
703be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley			lr = &specs[0]->lr;
704be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley			goto out;
705be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley		}
706be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley		best = 0;
707be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley		prefix_len = specs[0]->prefix_len;
708be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley	}
709be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley	for (i = 1; i <= n; i++) {
710be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley		specs[i] = lookup_common(rec, aliases[i-1], type, false);
711be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley		if (specs[i]) {
712be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley			if (!specs[i]->hasMetaChars) {
713be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley				/* exact match on alias */
714be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley				lr = &specs[i]->lr;
715be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley				goto out;
716be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley			}
717be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley			if (specs[i]->prefix_len > prefix_len) {
718be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley				best = i;
719be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley				prefix_len = specs[i]->prefix_len;
720be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley			}
721be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley		}
722be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley	}
723be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley
724be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley	if (best >= 0) {
725be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley		/* longest fixed prefix match on key or alias */
726be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley		lr = &specs[best]->lr;
727be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley	}
728be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley
729be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalleyout:
730be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley	free(specs);
731be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley	return lr;
732be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley}
733be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley
734f074036424618c130dacb3464465a8b40bffef5Stephen Smalleystatic void stats(struct selabel_handle *rec)
735f074036424618c130dacb3464465a8b40bffef5Stephen Smalley{
736f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	struct saved_data *data = (struct saved_data *)rec->data;
737f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	unsigned int i, nspec = data->nspec;
738f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	spec_t *spec_arr = data->spec_arr;
739f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
740f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	for (i = 0; i < nspec; i++) {
741f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		if (spec_arr[i].matches == 0) {
742f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			if (spec_arr[i].type_str) {
743f074036424618c130dacb3464465a8b40bffef5Stephen Smalley				selinux_log(SELINUX_WARNING,
744f074036424618c130dacb3464465a8b40bffef5Stephen Smalley				    "Warning!  No matches for (%s, %s, %s)\n",
745f074036424618c130dacb3464465a8b40bffef5Stephen Smalley				    spec_arr[i].regex_str,
746f074036424618c130dacb3464465a8b40bffef5Stephen Smalley				    spec_arr[i].type_str,
747f074036424618c130dacb3464465a8b40bffef5Stephen Smalley				    spec_arr[i].lr.ctx_raw);
748f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			} else {
749f074036424618c130dacb3464465a8b40bffef5Stephen Smalley				selinux_log(SELINUX_WARNING,
750f074036424618c130dacb3464465a8b40bffef5Stephen Smalley				    "Warning!  No matches for (%s, %s)\n",
751f074036424618c130dacb3464465a8b40bffef5Stephen Smalley				    spec_arr[i].regex_str,
752f074036424618c130dacb3464465a8b40bffef5Stephen Smalley				    spec_arr[i].lr.ctx_raw);
753f074036424618c130dacb3464465a8b40bffef5Stephen Smalley			}
754f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		}
755f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	}
756f074036424618c130dacb3464465a8b40bffef5Stephen Smalley}
757f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
758a2e47cd90d84d48cde19575d044577a3fc7a4000Stephen Smalleyint selabel_file_init(struct selabel_handle *rec, const struct selinux_opt *opts,
759f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		      unsigned nopts)
760f074036424618c130dacb3464465a8b40bffef5Stephen Smalley{
761f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	struct saved_data *data;
762f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
763f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	data = (struct saved_data *)malloc(sizeof(*data));
764f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	if (!data)
765f074036424618c130dacb3464465a8b40bffef5Stephen Smalley		return -1;
766f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	memset(data, 0, sizeof(*data));
767f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
768f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	rec->data = data;
769f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	rec->func_close = &closef;
770f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	rec->func_stats = &stats;
771f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	rec->func_lookup = &lookup;
7720e7340fb99b931540e2baf4778abeb53d40084e7Stephen Smalley	rec->func_partial_match = &partial_match;
773be7f5e8814c4954aca51d3f95455c5d9d527658cStephen Smalley	rec->func_lookup_best_match = &lookup_best_match;
774f074036424618c130dacb3464465a8b40bffef5Stephen Smalley
775f074036424618c130dacb3464465a8b40bffef5Stephen Smalley	return init(rec, opts, nopts);
776f074036424618c130dacb3464465a8b40bffef5Stephen Smalley}
777