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