• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Media contexts backend for X contexts
3  *
4  * Author : Eamon Walsh <ewalsh@tycho.nsa.gov>
5  */
6 
7 #include <sys/stat.h>
8 #include <string.h>
9 #include <stdio.h>
10 #include <stdio_ext.h>
11 #include <ctype.h>
12 #include <errno.h>
13 #include <limits.h>
14 #include <fnmatch.h>
15 #include "callbacks.h"
16 #include "label_internal.h"
17 
18 /*
19  * Internals
20  */
21 
22 /* A context specification. */
23 typedef struct spec {
24 	struct selabel_lookup_rec lr;	/* holds contexts for lookup result */
25 	char *key;		/* key string */
26 	int type;		/* type of record (prop, ext, client) */
27 	int matches;		/* number of matches made during operation */
28 } spec_t;
29 
30 struct saved_data {
31 	unsigned int nspec;
32 	spec_t *spec_arr;
33 };
34 
process_line(const char * path,char * line_buf,int pass,unsigned lineno,struct selabel_handle * rec)35 static int process_line(const char *path, char *line_buf, int pass,
36 			unsigned lineno, struct selabel_handle *rec)
37 {
38 	struct saved_data *data = (struct saved_data *)rec->data;
39 	int items;
40 	char *buf_p;
41 	char *type, *key, *context;
42 
43 	buf_p = line_buf;
44 	while (isspace((unsigned char)*buf_p))
45 		buf_p++;
46 	/* Skip comment lines and empty lines. */
47 	if (*buf_p == '#' || *buf_p == 0)
48 		return 0;
49 	items = sscanf(line_buf, "%ms %ms %ms ", &type, &key, &context);
50 	if (items < 3) {
51 		selinux_log(SELINUX_WARNING,
52 			    "%s:  line %u is missing fields, skipping\n", path,
53 			    lineno);
54 		if (items > 0)
55 			free(type);
56 		if (items > 1)
57 			free(key);
58 		return 0;
59 	}
60 
61 	if (pass == 1) {
62 		/* Convert the type string to a mode format */
63 		if (!strcmp(type, "property"))
64 			data->spec_arr[data->nspec].type = SELABEL_X_PROP;
65 		else if (!strcmp(type, "extension"))
66 			data->spec_arr[data->nspec].type = SELABEL_X_EXT;
67 		else if (!strcmp(type, "client"))
68 			data->spec_arr[data->nspec].type = SELABEL_X_CLIENT;
69 		else if (!strcmp(type, "event"))
70 			data->spec_arr[data->nspec].type = SELABEL_X_EVENT;
71 		else if (!strcmp(type, "selection"))
72 			data->spec_arr[data->nspec].type = SELABEL_X_SELN;
73 		else if (!strcmp(type, "poly_property"))
74 			data->spec_arr[data->nspec].type = SELABEL_X_POLYPROP;
75 		else if (!strcmp(type, "poly_selection"))
76 			data->spec_arr[data->nspec].type = SELABEL_X_POLYSELN;
77 		else {
78 			selinux_log(SELINUX_WARNING,
79 				    "%s:  line %u has invalid object type %s\n",
80 				    path, lineno, type);
81 			return 0;
82 		}
83 		data->spec_arr[data->nspec].key = key;
84 		data->spec_arr[data->nspec].lr.ctx_raw = context;
85 		free(type);
86 	}
87 
88 	data->nspec++;
89 	if (pass == 0) {
90 		free(type);
91 		free(key);
92 		free(context);
93 	}
94 	return 0;
95 }
96 
init(struct selabel_handle * rec,const struct selinux_opt * opts,unsigned n)97 static int init(struct selabel_handle *rec, const struct selinux_opt *opts,
98 		unsigned n)
99 {
100 	FILE *fp;
101 	struct saved_data *data = (struct saved_data *)rec->data;
102 	const char *path = NULL;
103 	char *line_buf = NULL;
104 	size_t line_len = 0;
105 	int status = -1;
106 	unsigned int lineno, pass, maxnspec;
107 	struct stat sb;
108 
109 	/* Process arguments */
110 	while (n) {
111 		n--;
112 		switch(opts[n].type) {
113 		case SELABEL_OPT_PATH:
114 			path = opts[n].value;
115 			break;
116 		case SELABEL_OPT_UNUSED:
117 		case SELABEL_OPT_VALIDATE:
118 		case SELABEL_OPT_DIGEST:
119 			break;
120 		default:
121 			errno = EINVAL;
122 			return -1;
123 		}
124 	}
125 
126 	/* Open the specification file. */
127 	if (!path)
128 		path = selinux_x_context_path();
129 	if ((fp = fopen(path, "re")) == NULL)
130 		return -1;
131 	__fsetlocking(fp, FSETLOCKING_BYCALLER);
132 
133 	if (fstat(fileno(fp), &sb) < 0)
134 		goto finish;
135 	if (!S_ISREG(sb.st_mode)) {
136 		errno = EINVAL;
137 		goto finish;
138 	}
139 	rec->spec_file = strdup(path);
140 
141 	/*
142 	 * Perform two passes over the specification file.
143 	 * The first pass counts the number of specifications and
144 	 * performs simple validation of the input.  At the end
145 	 * of the first pass, the spec array is allocated.
146 	 * The second pass performs detailed validation of the input
147 	 * and fills in the spec array.
148 	 */
149 	maxnspec = UINT_MAX / sizeof(spec_t);
150 	for (pass = 0; pass < 2; pass++) {
151 		lineno = 0;
152 		data->nspec = 0;
153 		while (getline(&line_buf, &line_len, fp) > 0 &&
154 		       data->nspec < maxnspec) {
155 			if (process_line(path, line_buf, pass, ++lineno, rec))
156 				goto finish;
157 		}
158 
159 		if (pass == 0) {
160 			if (data->nspec == 0) {
161 				status = 0;
162 				goto finish;
163 			}
164 			data->spec_arr = malloc(sizeof(spec_t)*data->nspec);
165 			if (data->spec_arr == NULL)
166 				goto finish;
167 			memset(data->spec_arr, 0, sizeof(spec_t)*data->nspec);
168 			maxnspec = data->nspec;
169 
170 			status = fseek(fp, 0L, SEEK_SET);
171 			if (status == -1)
172 				goto finish;
173 		}
174 	}
175 	free(line_buf);
176 
177 	status = digest_add_specfile(rec->digest, fp, NULL, sb.st_size, path);
178 	if (status)
179 		goto finish;
180 
181 	digest_gen_hash(rec->digest);
182 
183 finish:
184 	fclose(fp);
185 	return status;
186 }
187 
188 /*
189  * Backend interface routines
190  */
close(struct selabel_handle * rec)191 static void close(struct selabel_handle *rec)
192 {
193 	struct saved_data *data = (struct saved_data *)rec->data;
194 	struct spec *spec, *spec_arr;
195 	unsigned int i;
196 
197 	if (!data)
198 		return;
199 
200 	spec_arr = data->spec_arr;
201 
202 	for (i = 0; i < data->nspec; i++) {
203 		spec = &spec_arr[i];
204 		free(spec->key);
205 		free(spec->lr.ctx_raw);
206 		free(spec->lr.ctx_trans);
207 	}
208 
209 	if (spec_arr)
210 	    free(spec_arr);
211 
212 	free(data);
213 }
214 
lookup(struct selabel_handle * rec,const char * key,int type)215 static struct selabel_lookup_rec *lookup(struct selabel_handle *rec,
216 					 const char *key, int type)
217 {
218 	struct saved_data *data = (struct saved_data *)rec->data;
219 	spec_t *spec_arr = data->spec_arr;
220 	unsigned int i;
221 
222 	for (i = 0; i < data->nspec; i++) {
223 		if (spec_arr[i].type != type)
224 			continue;
225 		if (!fnmatch(spec_arr[i].key, key, 0))
226 			break;
227 	}
228 
229 	if (i >= data->nspec) {
230 		/* No matching specification. */
231 		errno = ENOENT;
232 		return NULL;
233 	}
234 
235 	spec_arr[i].matches++;
236 	return &spec_arr[i].lr;
237 }
238 
stats(struct selabel_handle * rec)239 static void stats(struct selabel_handle *rec)
240 {
241 	struct saved_data *data = (struct saved_data *)rec->data;
242 	unsigned int i, total = 0;
243 
244 	for (i = 0; i < data->nspec; i++)
245 		total += data->spec_arr[i].matches;
246 
247 	selinux_log(SELINUX_INFO, "%u entries, %u matches made\n",
248 		  data->nspec, total);
249 }
250 
selabel_x_init(struct selabel_handle * rec,const struct selinux_opt * opts,unsigned nopts)251 int selabel_x_init(struct selabel_handle *rec, const struct selinux_opt *opts,
252 		   unsigned nopts)
253 {
254 	struct saved_data *data;
255 
256 	data = (struct saved_data *)malloc(sizeof(*data));
257 	if (!data)
258 		return -1;
259 	memset(data, 0, sizeof(*data));
260 
261 	rec->data = data;
262 	rec->func_close = &close;
263 	rec->func_lookup = &lookup;
264 	rec->func_stats = &stats;
265 
266 	return init(rec, opts, nopts);
267 }
268