1 /*
2 * Media contexts backend for X contexts
3 *
4 * Author : Eamon Walsh <[email protected]>
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,const char * line_buf,int pass,unsigned lineno,struct selabel_handle * rec)35 static int process_line(const char *path, const 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 const 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
176 status = digest_add_specfile(rec->digest, fp, NULL, sb.st_size, path);
177 if (status)
178 goto finish;
179
180 digest_gen_hash(rec->digest);
181
182 finish:
183 free(line_buf);
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 rec->data = NULL;
214 }
215
lookup(struct selabel_handle * rec,const char * key,int type)216 static struct selabel_lookup_rec *lookup(struct selabel_handle *rec,
217 const char *key, int type)
218 {
219 struct saved_data *data = (struct saved_data *)rec->data;
220 spec_t *spec_arr = data->spec_arr;
221 unsigned int i;
222
223 for (i = 0; i < data->nspec; i++) {
224 if (spec_arr[i].type != type)
225 continue;
226 if (!fnmatch(spec_arr[i].key, key, 0))
227 break;
228 }
229
230 if (i >= data->nspec) {
231 /* No matching specification. */
232 errno = ENOENT;
233 return NULL;
234 }
235
236 spec_arr[i].matches++;
237 return &spec_arr[i].lr;
238 }
239
stats(struct selabel_handle * rec)240 static void stats(struct selabel_handle *rec)
241 {
242 struct saved_data *data = (struct saved_data *)rec->data;
243 unsigned int i, total = 0;
244
245 for (i = 0; i < data->nspec; i++)
246 total += data->spec_arr[i].matches;
247
248 selinux_log(SELINUX_INFO, "%u entries, %u matches made\n",
249 data->nspec, total);
250 }
251
selabel_x_init(struct selabel_handle * rec,const struct selinux_opt * opts,unsigned nopts)252 int selabel_x_init(struct selabel_handle *rec, const struct selinux_opt *opts,
253 unsigned nopts)
254 {
255 struct saved_data *data;
256
257 data = (struct saved_data *)malloc(sizeof(*data));
258 if (!data)
259 return -1;
260 memset(data, 0, sizeof(*data));
261
262 rec->data = data;
263 rec->func_close = &close;
264 rec->func_lookup = &lookup;
265 rec->func_stats = &stats;
266
267 return init(rec, opts, nopts);
268 }
269