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