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, "re")) == NULL)
121 return -1;
122 __fsetlocking(fp, FSETLOCKING_BYCALLER);
123
124 if (fstat(fileno(fp), &sb) < 0)
125 goto finish;
126 if (!S_ISREG(sb.st_mode)) {
127 errno = EINVAL;
128 goto finish;
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
150 if (pass == 0) {
151 if (data->nspec == 0) {
152 status = 0;
153 goto finish;
154 }
155 data->spec_arr = malloc(sizeof(spec_t)*data->nspec);
156 if (data->spec_arr == NULL)
157 goto finish;
158 memset(data->spec_arr, 0, sizeof(spec_t)*data->nspec);
159 maxnspec = data->nspec;
160 rewind(fp);
161 }
162 }
163 free(line_buf);
164
165 status = digest_add_specfile(rec->digest, fp, NULL, sb.st_size, path);
166 if (status)
167 goto finish;
168
169 digest_gen_hash(rec->digest);
170
171 finish:
172 fclose(fp);
173 return status;
174 }
175
176 /*
177 * Backend interface routines
178 */
close(struct selabel_handle * rec)179 static void close(struct selabel_handle *rec)
180 {
181 struct saved_data *data = (struct saved_data *)rec->data;
182 struct spec *spec, *spec_arr = data->spec_arr;
183 unsigned int i;
184
185 for (i = 0; i < data->nspec; i++) {
186 spec = &spec_arr[i];
187 free(spec->key);
188 free(spec->lr.ctx_raw);
189 free(spec->lr.ctx_trans);
190 }
191
192 if (spec_arr)
193 free(spec_arr);
194
195 free(data);
196 }
197
lookup(struct selabel_handle * rec,const char * key,int type)198 static struct selabel_lookup_rec *lookup(struct selabel_handle *rec,
199 const char *key, int type)
200 {
201 struct saved_data *data = (struct saved_data *)rec->data;
202 spec_t *spec_arr = data->spec_arr;
203 unsigned int i;
204
205 for (i = 0; i < data->nspec; i++) {
206 if (spec_arr[i].type != type)
207 continue;
208 if (!fnmatch(spec_arr[i].key, key, 0))
209 break;
210 }
211
212 if (i >= data->nspec) {
213 /* No matching specification. */
214 errno = ENOENT;
215 return NULL;
216 }
217
218 spec_arr[i].matches++;
219 return &spec_arr[i].lr;
220 }
221
stats(struct selabel_handle * rec)222 static void stats(struct selabel_handle *rec)
223 {
224 struct saved_data *data = (struct saved_data *)rec->data;
225 unsigned int i, total = 0;
226
227 for (i = 0; i < data->nspec; i++)
228 total += data->spec_arr[i].matches;
229
230 selinux_log(SELINUX_INFO, "%u entries, %u matches made\n",
231 data->nspec, total);
232 }
233
selabel_x_init(struct selabel_handle * rec,const struct selinux_opt * opts,unsigned nopts)234 int selabel_x_init(struct selabel_handle *rec, const struct selinux_opt *opts,
235 unsigned nopts)
236 {
237 struct saved_data *data;
238
239 data = (struct saved_data *)malloc(sizeof(*data));
240 if (!data)
241 return -1;
242 memset(data, 0, sizeof(*data));
243
244 rec->data = data;
245 rec->func_close = &close;
246 rec->func_lookup = &lookup;
247 rec->func_stats = &stats;
248
249 return init(rec, opts, nopts);
250 }
251