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(*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 switch(opts[n].type) {
112 case SELABEL_OPT_PATH:
113 path = opts[n].value;
114 break;
115 }
116
117 /* Open the specification file. */
118 if (!path)
119 path = selinux_x_context_path();
120 if ((fp = fopen(path, "r")) == NULL)
121 return -1;
122 __fsetlocking(fp, FSETLOCKING_BYCALLER);
123
124 if (fstat(fileno(fp), &sb) < 0)
125 return -1;
126 if (!S_ISREG(sb.st_mode)) {
127 errno = EINVAL;
128 return -1;
129 }
130 rec->spec_file = strdup(path);
131
132 /*
133 * Perform two passes over the specification file.
134 * The first pass counts the number of specifications and
135 * performs simple validation of the input. At the end
136 * of the first pass, the spec array is allocated.
137 * The second pass performs detailed validation of the input
138 * and fills in the spec array.
139 */
140 maxnspec = UINT_MAX / sizeof(spec_t);
141 for (pass = 0; pass < 2; pass++) {
142 lineno = 0;
143 data->nspec = 0;
144 while (getline(&line_buf, &line_len, fp) > 0 &&
145 data->nspec < maxnspec) {
146 if (process_line(path, line_buf, pass, ++lineno, rec))
147 goto finish;
148 }
149 lineno = 0;
150
151 if (pass == 0) {
152 if (data->nspec == 0) {
153 status = 0;
154 goto finish;
155 }
156 data->spec_arr = malloc(sizeof(spec_t)*data->nspec);
157 if (data->spec_arr == NULL)
158 goto finish;
159 memset(data->spec_arr, 0, sizeof(spec_t)*data->nspec);
160 maxnspec = data->nspec;
161 rewind(fp);
162 }
163 }
164 free(line_buf);
165
166 status = digest_add_specfile(rec->digest, fp, NULL, sb.st_size, path);
167 if (status)
168 goto finish;
169
170 digest_gen_hash(rec->digest);
171
172 finish:
173 fclose(fp);
174 return status;
175 }
176
177 /*
178 * Backend interface routines
179 */
close(struct selabel_handle * rec)180 static void close(struct selabel_handle *rec)
181 {
182 struct saved_data *data = (struct saved_data *)rec->data;
183 struct spec *spec, *spec_arr = data->spec_arr;
184 unsigned int i;
185
186 for (i = 0; i < data->nspec; i++) {
187 spec = &spec_arr[i];
188 free(spec->key);
189 free(spec->lr.ctx_raw);
190 free(spec->lr.ctx_trans);
191 }
192
193 if (spec_arr)
194 free(spec_arr);
195
196 free(data);
197 }
198
lookup(struct selabel_handle * rec,const char * key,int type)199 static struct selabel_lookup_rec *lookup(struct selabel_handle *rec,
200 const char *key, int type)
201 {
202 struct saved_data *data = (struct saved_data *)rec->data;
203 spec_t *spec_arr = data->spec_arr;
204 unsigned int i;
205
206 for (i = 0; i < data->nspec; i++) {
207 if (spec_arr[i].type != type)
208 continue;
209 if (!fnmatch(spec_arr[i].key, key, 0))
210 break;
211 }
212
213 if (i >= data->nspec) {
214 /* No matching specification. */
215 errno = ENOENT;
216 return NULL;
217 }
218
219 spec_arr[i].matches++;
220 return &spec_arr[i].lr;
221 }
222
stats(struct selabel_handle * rec)223 static void stats(struct selabel_handle *rec)
224 {
225 struct saved_data *data = (struct saved_data *)rec->data;
226 unsigned int i, total = 0;
227
228 for (i = 0; i < data->nspec; i++)
229 total += data->spec_arr[i].matches;
230
231 selinux_log(SELINUX_INFO, "%u entries, %u matches made\n",
232 data->nspec, total);
233 }
234
selabel_x_init(struct selabel_handle * rec,const struct selinux_opt * opts,unsigned nopts)235 int selabel_x_init(struct selabel_handle *rec, const struct selinux_opt *opts,
236 unsigned nopts)
237 {
238 struct saved_data *data;
239
240 data = (struct saved_data *)malloc(sizeof(*data));
241 if (!data)
242 return -1;
243 memset(data, 0, sizeof(*data));
244
245 rec->data = data;
246 rec->func_close = &close;
247 rec->func_lookup = &lookup;
248 rec->func_stats = &stats;
249
250 return init(rec, opts, nopts);
251 }
252