147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner/*
247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner * File contexts backend for labeling system
347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner *
447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner * Author : Eamon Walsh <ewalsh@tycho.nsa.gov>
547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner */
647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include <fcntl.h>
847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include <stdarg.h>
947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include <string.h>
1047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include <stdio.h>
1147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include <ctype.h>
1247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include <errno.h>
1347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include <limits.h>
1447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include <regex.h>
1547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include <sys/types.h>
1647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include <sys/stat.h>
1747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include <unistd.h>
1847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include "callbacks.h"
1947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include "label_internal.h"
2047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
2147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner/*
2247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner * Internals, mostly moved over from matchpathcon.c
2347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner */
2447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
2547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner/* A file security context specification. */
2647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnertypedef struct spec {
2747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	struct selabel_lookup_rec lr;	/* holds contexts for lookup result */
2847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	char *regex_str;	/* regular expession string for diagnostics */
2947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	char *type_str;		/* type string for diagnostic messages */
3047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	regex_t regex;		/* compiled regular expression */
3147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	char regcomp;           /* regex_str has been compiled to regex */
3247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	mode_t mode;		/* mode format value */
3347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	int matches;		/* number of matching pathnames */
3447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	int hasMetaChars;	/* regular expression has meta-chars */
3547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	int stem_id;		/* indicates which stem-compression item */
3647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	size_t prefix_len;      /* length of fixed path prefix */
3747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner} spec_t;
3847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
3947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner/* A regular expression stem */
4047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnertypedef struct stem {
4147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	char *buf;
4247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	int len;
4347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner} stem_t;
4447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
4547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner/* Our stored configuration */
4647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerstruct saved_data {
4747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	/*
4847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	 * The array of specifications, initially in the same order as in
4947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	 * the specification file. Sorting occurs based on hasMetaChars.
5047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	 */
5147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	spec_t *spec_arr;
5247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	unsigned int nspec;
5347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	unsigned int ncomp;
5447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
5547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	/*
5647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	 * The array of regular expression stems.
5747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	 */
5847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	stem_t *stem_arr;
5947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	int num_stems;
6047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	int alloc_stems;
6147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner};
6247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
6347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner/* Return the length of the text that can be considered the stem, returns 0
6447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner * if there is no identifiable stem */
6547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerstatic int get_stem_from_spec(const char *const buf)
6647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner{
6747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	const char *tmp = strchr(buf + 1, '/');
6847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	const char *ind;
6947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
7047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (!tmp)
7147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		return 0;
7247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
7347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	for (ind = buf; ind < tmp; ind++) {
7447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		if (strchr(".^$?*+|[({", (int)*ind))
7547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			return 0;
7647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
7747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	return tmp - buf;
7847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner}
7947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
8047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner/* return the length of the text that is the stem of a file name */
8147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerstatic int get_stem_from_file_name(const char *const buf)
8247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner{
8347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	const char *tmp = strchr(buf + 1, '/');
8447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
8547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (!tmp)
8647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		return 0;
8747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	return tmp - buf;
8847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner}
8947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
9047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner/* find the stem of a file spec, returns the index into stem_arr for a new
9147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner * or existing stem, (or -1 if there is no possible stem - IE for a file in
9247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner * the root directory or a regex that is too complex for us). */
9347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerstatic int find_stem_from_spec(struct saved_data *data, const char *buf)
9447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner{
9547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	int i, num = data->num_stems;
9647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	int stem_len = get_stem_from_spec(buf);
9747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
9847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (!stem_len)
9947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		return -1;
10047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	for (i = 0; i < num; i++) {
10147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		if (stem_len == data->stem_arr[i].len
10247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		    && !strncmp(buf, data->stem_arr[i].buf, stem_len))
10347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			return i;
10447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
10547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (data->alloc_stems == num) {
10647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		stem_t *tmp_arr;
10747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		data->alloc_stems = data->alloc_stems * 2 + 16;
10847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		tmp_arr = (stem_t *) realloc(data->stem_arr,
10947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				  sizeof(stem_t) * data->alloc_stems);
11047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		if (!tmp_arr)
11147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			return -1;
11247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		data->stem_arr = tmp_arr;
11347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
11447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	data->stem_arr[num].len = stem_len;
11547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	data->stem_arr[num].buf = (char *) malloc(stem_len + 1);
11647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (!data->stem_arr[num].buf)
11747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		return -1;
11847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	memcpy(data->stem_arr[num].buf, buf, stem_len);
11947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	data->stem_arr[num].buf[stem_len] = '\0';
12047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	data->num_stems++;
12147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	buf += stem_len;
12247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	return num;
12347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner}
12447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
12547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner/* find the stem of a file name, returns the index into stem_arr (or -1 if
12647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner * there is no match - IE for a file in the root directory or a regex that is
12747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner * too complex for us).  Makes buf point to the text AFTER the stem. */
12847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerstatic int find_stem_from_file(struct saved_data *data, const char **buf)
12947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner{
13047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	int i;
13147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	int stem_len = get_stem_from_file_name(*buf);
13247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
13347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (!stem_len)
13447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		return -1;
13547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	for (i = 0; i < data->num_stems; i++) {
13647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		if (stem_len == data->stem_arr[i].len
13747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		    && !strncmp(*buf, data->stem_arr[i].buf, stem_len)) {
13847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			*buf += stem_len;
13947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			return i;
14047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		}
14147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
14247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	return -1;
14347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner}
14447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
14547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner/*
14647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner * Warn about duplicate specifications.
14747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner */
14847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerstatic int nodups_specs(struct saved_data *data, const char *path)
14947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner{
15047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	int rc = 0;
15147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	unsigned int ii, jj;
15247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	struct spec *curr_spec, *spec_arr = data->spec_arr;
15347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
15447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	for (ii = 0; ii < data->nspec; ii++) {
15547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		curr_spec = &spec_arr[ii];
15647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		for (jj = ii + 1; jj < data->nspec; jj++) {
15747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			if ((!strcmp
15847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			     (spec_arr[jj].regex_str, curr_spec->regex_str))
15947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			    && (!spec_arr[jj].mode || !curr_spec->mode
16047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				|| spec_arr[jj].mode == curr_spec->mode)) {
16147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				rc = -1;
16247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				errno = EINVAL;
16347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				if (strcmp
16447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				    (spec_arr[jj].lr.ctx_raw,
16547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				     curr_spec->lr.ctx_raw)) {
16647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner					selinux_log
16747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner						(SELINUX_ERROR,
16847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner						 "%s: Multiple different specifications for %s  (%s and %s).\n",
16947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner						 path, curr_spec->regex_str,
17047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner						 spec_arr[jj].lr.ctx_raw,
17147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner						 curr_spec->lr.ctx_raw);
17247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				} else {
17347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner					selinux_log
17447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner						(SELINUX_ERROR,
17547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner						 "%s: Multiple same specifications for %s.\n",
17647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner						 path, curr_spec->regex_str);
17747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				}
17847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			}
17947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		}
18047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
18147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	return rc;
18247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner}
18347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
18447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner/* Determine if the regular expression specification has any meta characters. */
18547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerstatic void spec_hasMetaChars(struct spec *spec)
18647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner{
18747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	char *c;
18847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	size_t len;
18947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	char *end;
19047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
19147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	c = spec->regex_str;
19247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	len = strlen(spec->regex_str);
19347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	end = c + len;
19447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
19547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	spec->hasMetaChars = 0;
19647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	spec->prefix_len = len;
19747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
19847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	/* Look at each character in the RE specification string for a
19947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	 * meta character. Return when any meta character reached. */
20047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	while (c != end) {
20147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		switch (*c) {
20247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		case '.':
20347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		case '^':
20447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		case '$':
20547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		case '?':
20647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		case '*':
20747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		case '+':
20847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		case '|':
20947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		case '[':
21047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		case '(':
21147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		case '{':
21247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			spec->hasMetaChars = 1;
21347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			spec->prefix_len = c - spec->regex_str;
21447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			return;
21547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		case '\\':	/* skip the next character */
21647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			c++;
21747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			break;
21847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		default:
21947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			break;
22047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
22147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		}
22247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		c++;
22347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
22447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	return;
22547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner}
22647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
22747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerstatic int compile_regex(struct saved_data *data, spec_t *spec, char **errbuf)
22847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner{
22947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	char *reg_buf, *anchored_regex, *cp;
23047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	stem_t *stem_arr = data->stem_arr;
23147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	size_t len;
23247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	int regerr;
23347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
23447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (spec->regcomp)
23547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		return 0; /* already done */
23647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
23747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	data->ncomp++; /* how many compiled regexes required */
23847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
23947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	/* Skip the fixed stem. */
24047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	reg_buf = spec->regex_str;
24147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (spec->stem_id >= 0)
24247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		reg_buf += stem_arr[spec->stem_id].len;
24347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
24447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	/* Anchor the regular expression. */
24547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	len = strlen(reg_buf);
24647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	cp = anchored_regex = (char *) malloc(len + 3);
24747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (!anchored_regex)
24847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		return -1;
24947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	/* Create ^...$ regexp.  */
25047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	*cp++ = '^';
25147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	memcpy(cp, reg_buf, len);
25247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	cp += len;
25347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	*cp++ = '$';
25447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	*cp = '\0';
25547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
25647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	/* Compile the regular expression. */
25747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	regerr = regcomp(&spec->regex, anchored_regex,
25847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			 REG_EXTENDED | REG_NOSUB);
25947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (regerr != 0) {
26047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		size_t errsz = 0;
26147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		errsz = regerror(regerr, &spec->regex, NULL, 0);
26247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		if (errsz && errbuf)
26347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			*errbuf = (char *) malloc(errsz);
26447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		if (errbuf && *errbuf)
26547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			(void)regerror(regerr, &spec->regex,
26647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				       *errbuf, errsz);
26747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
26847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		free(anchored_regex);
26947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		return -1;
27047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
27147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	free(anchored_regex);
27247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
27347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	/* Done. */
27447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	spec->regcomp = 1;
27547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
27647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	return 0;
27747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner}
27847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
27947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
28047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerstatic int process_line(struct selabel_handle *rec,
28147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			const char *path, const char *prefix,
28247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			char *line_buf, int pass, unsigned lineno)
28347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner{
28447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	int items, len;
28547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	char buf1[BUFSIZ], buf2[BUFSIZ], buf3[BUFSIZ];
28647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	char *buf_p, *regex = buf1, *type = buf2, *context = buf3;
28747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	struct saved_data *data = (struct saved_data *)rec->data;
28847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	spec_t *spec_arr = data->spec_arr;
28947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	unsigned int nspec = data->nspec;
29047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
29147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	len = strlen(line_buf);
29247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (line_buf[len - 1] == '\n')
29347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		line_buf[len - 1] = 0;
29447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	buf_p = line_buf;
29547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	while (isspace(*buf_p))
29647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		buf_p++;
29747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	/* Skip comment lines and empty lines. */
29847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (*buf_p == '#' || *buf_p == 0)
29947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		return 0;
30047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	items = sscanf(line_buf, "%255s %255s %255s", regex, type, context);
30147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (items < 2) {
30247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		selinux_log(SELINUX_WARNING,
30347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			    "%s:  line %d is missing fields, skipping\n", path,
30447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			    lineno);
30547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		return 0;
30647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	} else if (items == 2) {
30747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		/* The type field is optional. */
30847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		context = type;
30947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		type = NULL;
31047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
31147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
31247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	len = get_stem_from_spec(regex);
31347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (len && prefix && strncmp(prefix, regex, len)) {
31447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		/* Stem of regex does not match requested prefix, discard. */
31547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		return 0;
31647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
31747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
31847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (pass == 1) {
31947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		/* On the second pass, process and store the specification in spec. */
32047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		char *errbuf = NULL;
32147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		spec_arr[nspec].stem_id = find_stem_from_spec(data, regex);
32247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		spec_arr[nspec].regex_str = strdup(regex);
32347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		if (!spec_arr[nspec].regex_str) {
32447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			selinux_log(SELINUX_WARNING,
32547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				   "%s:  out of memory at line %d on regex %s\n",
32647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				   path, lineno, regex);
32747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			return -1;
32847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
32947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		}
33047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		if (rec->validating && compile_regex(data, &spec_arr[nspec], &errbuf)) {
33147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			selinux_log(SELINUX_WARNING,
33247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				   "%s:  line %d has invalid regex %s:  %s\n",
33347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				   path, lineno, regex,
33447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				   (errbuf ? errbuf : "out of memory"));
33547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		}
33647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
33747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		/* Convert the type string to a mode format */
33847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		spec_arr[nspec].mode = 0;
33947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		if (!type)
34047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			goto skip_type;
34147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		spec_arr[nspec].type_str = strdup(type);
34247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		len = strlen(type);
34347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		if (type[0] != '-' || len != 2) {
34447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			selinux_log(SELINUX_WARNING,
34547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				    "%s:  line %d has invalid file type %s\n",
34647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				    path, lineno, type);
34747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			return 0;
34847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		}
34947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		switch (type[1]) {
35047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		case 'b':
35147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			spec_arr[nspec].mode = S_IFBLK;
35247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			break;
35347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		case 'c':
35447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			spec_arr[nspec].mode = S_IFCHR;
35547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			break;
35647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		case 'd':
35747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			spec_arr[nspec].mode = S_IFDIR;
35847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			break;
35947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		case 'p':
36047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			spec_arr[nspec].mode = S_IFIFO;
36147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			break;
36247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		case 'l':
36347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			spec_arr[nspec].mode = S_IFLNK;
36447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			break;
36547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		case 's':
36647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			spec_arr[nspec].mode = S_IFSOCK;
36747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			break;
36847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		case '-':
36947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			spec_arr[nspec].mode = S_IFREG;
37047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			break;
37147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		default:
37247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			selinux_log(SELINUX_WARNING,
37347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				    "%s:  line %d has invalid file type %s\n",
37447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				    path, lineno, type);
37547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			return 0;
37647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		}
37747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
37847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	skip_type:
37947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		spec_arr[nspec].lr.ctx_raw = strdup(context);
38047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
38147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		if (strcmp(context, "<<none>>") && rec->validating) {
38247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			if (selabel_validate(rec, &spec_arr[nspec].lr) < 0) {
38347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				selinux_log(SELINUX_WARNING,
38447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner					    "%s:  line %d has invalid context %s\n",
38547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner					    path, lineno, spec_arr[nspec].lr.ctx_raw);
38647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			}
38747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		}
38847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
38947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		/* Determine if specification has
39047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		 * any meta characters in the RE */
39147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		spec_hasMetaChars(&spec_arr[nspec]);
39247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
39347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
39447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	data->nspec = ++nspec;
39547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	return 0;
39647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner}
39747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
39847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerstatic int init(struct selabel_handle *rec, const struct selinux_opt *opts,
39947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		unsigned n)
40047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner{
40147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	struct saved_data *data = (struct saved_data *)rec->data;
40247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	const char *path = NULL;
40347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	const char *prefix = NULL;
40447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	FILE *fp;
40547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	FILE *localfp = NULL;
40647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	FILE *homedirfp = NULL;
40747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	char local_path[PATH_MAX + 1];
40847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	char homedir_path[PATH_MAX + 1];
40947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	char line_buf[BUFSIZ];
41047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	unsigned int lineno, pass, i, j, maxnspec;
41147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	spec_t *spec_copy = NULL;
41247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	int status = -1, baseonly = 0;
41347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	struct stat sb;
41447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
41547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	/* Process arguments */
41647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	while (n--)
41747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		switch(opts[n].type) {
41847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		case SELABEL_OPT_PATH:
41947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			path = opts[n].value;
42047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			break;
42147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		case SELABEL_OPT_SUBSET:
42247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			prefix = opts[n].value;
42347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			break;
42447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		case SELABEL_OPT_BASEONLY:
42547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			baseonly = !!opts[n].value;
42647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			break;
42747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		}
42847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
42947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	/* Open the specification file. */
43047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if ((fp = fopen(path, "r")) == NULL)
43147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		return -1;
43247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
43347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (fstat(fileno(fp), &sb) < 0)
43447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		return -1;
43547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (!S_ISREG(sb.st_mode)) {
43647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		errno = EINVAL;
43747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		return -1;
43847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
43947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
44047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (!baseonly) {
44147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		snprintf(homedir_path, sizeof(homedir_path), "%s.homedirs",
44247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			 path);
44347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		homedirfp = fopen(homedir_path, "r");
44447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
44547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		snprintf(local_path, sizeof(local_path), "%s.local", path);
44647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		localfp = fopen(local_path, "r");
44747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
44847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
44947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	/*
45047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	 * Perform two passes over the specification file.
45147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	 * The first pass counts the number of specifications and
45247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	 * performs simple validation of the input.  At the end
45347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	 * of the first pass, the spec array is allocated.
45447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	 * The second pass performs detailed validation of the input
45547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	 * and fills in the spec array.
45647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	 */
45747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	maxnspec = UINT_MAX / sizeof(spec_t);
45847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	for (pass = 0; pass < 2; pass++) {
45947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		lineno = 0;
46047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		data->nspec = 0;
46147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		data->ncomp = 0;
46247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		while (fgets(line_buf, sizeof line_buf - 1, fp)
46347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		       && data->nspec < maxnspec) {
46447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			if (process_line(rec, path, prefix, line_buf,
46547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner					 pass, ++lineno) != 0)
46647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				goto finish;
46747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		}
46847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		if (pass == 1) {
46947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			status = nodups_specs(data, path);
47047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			if (status)
47147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				goto finish;
47247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		}
47347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		lineno = 0;
47447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		if (homedirfp)
47547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			while (fgets(line_buf, sizeof line_buf - 1, homedirfp)
47647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			       && data->nspec < maxnspec) {
47747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				if (process_line
47847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				    (rec, homedir_path, prefix,
47947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				     line_buf, pass, ++lineno) != 0)
48047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner					goto finish;
48147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			}
48247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
48347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		lineno = 0;
48447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		if (localfp)
48547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			while (fgets(line_buf, sizeof line_buf - 1, localfp)
48647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			       && data->nspec < maxnspec) {
48747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				if (process_line
48847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				    (rec, local_path, prefix, line_buf,
48947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				     pass, ++lineno) != 0)
49047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner					goto finish;
49147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			}
49247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
49347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		if (pass == 0) {
49447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			if (data->nspec == 0) {
49547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				status = 0;
49647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				goto finish;
49747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			}
49847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			if (NULL == (data->spec_arr =
49947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				     (spec_t *) malloc(sizeof(spec_t) * data->nspec)))
50047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				goto finish;
50147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			memset(data->spec_arr, 0, sizeof(spec_t)*data->nspec);
50247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			maxnspec = data->nspec;
50347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			rewind(fp);
50447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			if (homedirfp)
50547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				rewind(homedirfp);
50647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			if (localfp)
50747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				rewind(localfp);
50847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		}
50947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
51047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
51147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	/* Move exact pathname specifications to the end. */
51247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	spec_copy = (spec_t *) malloc(sizeof(spec_t) * data->nspec);
51347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (!spec_copy)
51447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		goto finish;
51547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	j = 0;
51647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	for (i = 0; i < data->nspec; i++)
51747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		if (data->spec_arr[i].hasMetaChars)
51847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			memcpy(&spec_copy[j++],
51947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			       &data->spec_arr[i], sizeof(spec_t));
52047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	for (i = 0; i < data->nspec; i++)
52147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		if (!data->spec_arr[i].hasMetaChars)
52247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			memcpy(&spec_copy[j++],
52347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			       &data->spec_arr[i], sizeof(spec_t));
52447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	free(data->spec_arr);
52547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	data->spec_arr = spec_copy;
52647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
52747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	status = 0;
52847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerfinish:
52947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	fclose(fp);
53047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (data->spec_arr != spec_copy)
53147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		free(data->spec_arr);
53247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (homedirfp)
53347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		fclose(homedirfp);
53447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (localfp)
53547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		fclose(localfp);
53647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	return status;
53747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner}
53847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
53947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner/*
54047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner * Backend interface routines
54147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner */
54247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerstatic void closef(struct selabel_handle *rec)
54347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner{
54447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	struct saved_data *data = (struct saved_data *)rec->data;
54547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	struct spec *spec;
54647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	struct stem *stem;
54747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	unsigned int i;
54847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
54947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	for (i = 0; i < data->nspec; i++) {
55047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		spec = &data->spec_arr[i];
55147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		free(spec->regex_str);
55247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		free(spec->type_str);
55347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		free(spec->lr.ctx_raw);
55447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		free(spec->lr.ctx_trans);
55547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		if (spec->regcomp)
55647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			regfree(&spec->regex);
55747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
55847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
55947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	for (i = 0; i < (unsigned int)data->num_stems; i++) {
56047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		stem = &data->stem_arr[i];
56147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		free(stem->buf);
56247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
56347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
56447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (data->spec_arr)
56547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		free(data->spec_arr);
56647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (data->stem_arr)
56747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		free(data->stem_arr);
56847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
56947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	free(data);
57047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner}
57147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
57247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerstatic struct selabel_lookup_rec *lookup_common(struct selabel_handle *rec,
57347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner						const char *key, int type,
57447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner						bool partial)
57547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner{
57647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	struct saved_data *data = (struct saved_data *)rec->data;
57747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	spec_t *spec_arr = data->spec_arr;
57847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	int i, rc, file_stem;
57947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	mode_t mode = (mode_t)type;
58047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	const char *buf;
58147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	struct selabel_lookup_rec *ret = NULL;
58247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	char *clean_key = NULL;
58347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	const char *prev_slash, *next_slash;
58447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	unsigned int sofar = 0;
58547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	size_t keylen = strlen(key);
58647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
58747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (!data->nspec) {
58847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		errno = ENOENT;
58947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		goto finish;
59047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
59147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
59247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	/* Remove duplicate slashes */
59347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if ((next_slash = strstr(key, "//"))) {
59447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		clean_key = (char *) malloc(strlen(key) + 1);
59547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		if (!clean_key)
59647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			goto finish;
59747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		prev_slash = key;
59847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		while (next_slash) {
59947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			memcpy(clean_key + sofar, prev_slash, next_slash - prev_slash);
60047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			sofar += next_slash - prev_slash;
60147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			prev_slash = next_slash + 1;
60247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			next_slash = strstr(prev_slash, "//");
60347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		}
60447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		strcpy(clean_key + sofar, prev_slash);
60547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		key = clean_key;
60647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
60747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
60847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	buf = key;
60947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	file_stem = find_stem_from_file(data, &buf);
61047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	mode &= S_IFMT;
61147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
61247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	/*
61347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	 * Check for matching specifications in reverse order, so that
61447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	 * the last matching specification is used.
61547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	 */
61647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	for (i = data->nspec - 1; i >= 0; i--) {
61747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		/* if the spec in question matches no stem or has the same
61847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		 * stem as the file AND if the spec in question has no mode
61947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		 * specified or if the mode matches the file mode then we do
62047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		 * a regex check        */
62147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		if ((spec_arr[i].stem_id == -1
62247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		     || spec_arr[i].stem_id == file_stem)
62347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		    && (!mode || !spec_arr[i].mode
62447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			|| mode == spec_arr[i].mode)) {
62547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			if (compile_regex(data, &spec_arr[i], NULL) < 0)
62647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				goto finish;
62747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			if (spec_arr[i].stem_id == -1)
62847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				rc = regexec(&spec_arr[i].regex, key, 0, 0, 0);
62947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			else
63047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				rc = regexec(&spec_arr[i].regex, buf, 0, 0, 0);
63147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
63247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			if (rc == 0) {
63347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				spec_arr[i].matches++;
63447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				break;
63547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			}
63647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
63747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			if (partial) {
63847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				/*
63947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				 * We already checked above to see if the
64047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				 * key has any direct match.  Now we just need
64147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				 * to check for partial matches.
64247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				 * Since POSIX regex functions do not support
64347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				 * partial match, we crudely approximate it
64447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				 * via a prefix match.
64547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				 * This is imprecise and could yield
64647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				 * false positives or negatives but
64747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				 * appears to work with our current set of
64847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				 * regex strings.
64947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				 * Convert to using pcre partial match
65047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				 * if/when pcre becomes available in Android.
65147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				 */
65247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				if (spec_arr[i].prefix_len > 1 &&
65347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				    !strncmp(key, spec_arr[i].regex_str,
65447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner					     keylen < spec_arr[i].prefix_len ?
65547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner					     keylen : spec_arr[i].prefix_len))
65647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner					break;
65747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			}
65847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
65947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			if (rc == REG_NOMATCH)
66047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				continue;
66147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			/* else it's an error */
66247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			goto finish;
66347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		}
66447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
66547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
66647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (i < 0 || strcmp(spec_arr[i].lr.ctx_raw, "<<none>>") == 0) {
66747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		/* No matching specification. */
66847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		errno = ENOENT;
66947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		goto finish;
67047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
67147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
67247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	ret = &spec_arr[i].lr;
67347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
67447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerfinish:
67547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	free(clean_key);
67647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	return ret;
67747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner}
67847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
67947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerstatic struct selabel_lookup_rec *lookup(struct selabel_handle *rec,
68047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner					 const char *key, int type)
68147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner{
68247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	return lookup_common(rec, key, type, false);
68347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner}
68447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
68547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerstatic bool partial_match(struct selabel_handle *rec, const char *key)
68647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner{
68747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	return lookup_common(rec, key, 0, true) ? true : false;
68847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner}
68947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
69047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerstatic void stats(struct selabel_handle *rec)
69147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner{
69247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	struct saved_data *data = (struct saved_data *)rec->data;
69347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	unsigned int i, nspec = data->nspec;
69447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	spec_t *spec_arr = data->spec_arr;
69547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
69647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	for (i = 0; i < nspec; i++) {
69747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		if (spec_arr[i].matches == 0) {
69847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			if (spec_arr[i].type_str) {
69947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				selinux_log(SELINUX_WARNING,
70047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				    "Warning!  No matches for (%s, %s, %s)\n",
70147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				    spec_arr[i].regex_str,
70247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				    spec_arr[i].type_str,
70347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				    spec_arr[i].lr.ctx_raw);
70447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			} else {
70547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				selinux_log(SELINUX_WARNING,
70647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				    "Warning!  No matches for (%s, %s)\n",
70747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				    spec_arr[i].regex_str,
70847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				    spec_arr[i].lr.ctx_raw);
70947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			}
71047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		}
71147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
71247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner}
71347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
71447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerint selabel_file_init(struct selabel_handle *rec, const struct selinux_opt *opts,
71547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		      unsigned nopts)
71647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner{
71747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	struct saved_data *data;
71847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
71947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	data = (struct saved_data *)malloc(sizeof(*data));
72047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (!data)
72147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		return -1;
72247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	memset(data, 0, sizeof(*data));
72347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
72447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	rec->data = data;
72547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	rec->func_close = &closef;
72647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	rec->func_stats = &stats;
72747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	rec->func_lookup = &lookup;
72847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	rec->func_partial_match = &partial_match;
72947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
73047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	return init(rec, opts, nopts);
73147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner}
732