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