1 /*
2 * Generalized labeling frontend for userspace object managers.
3 *
4 * Author : Eamon Walsh <ewalsh@epoch.ncsc.mil>
5 */
6
7 #include <sys/types.h>
8 #include <ctype.h>
9 #include <errno.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <selinux/selinux.h>
14 #include "callbacks.h"
15 #include "label_internal.h"
16
17 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
18
19 typedef int (*selabel_initfunc)(struct selabel_handle *rec,
20 struct selinux_opt *opts, unsigned nopts);
21
22 static selabel_initfunc initfuncs[] = {
23 &selabel_file_init,
24 &selabel_media_init,
25 &selabel_x_init,
26 &selabel_db_init,
27 &selabel_property_init,
28 };
29
selabel_subs_fini(struct selabel_sub * ptr)30 static void selabel_subs_fini(struct selabel_sub *ptr)
31 {
32 struct selabel_sub *next;
33
34 while (ptr) {
35 next = ptr->next;
36 free(ptr->src);
37 free(ptr->dst);
38 free(ptr);
39 ptr = next;
40 }
41 }
42
selabel_sub(struct selabel_sub * ptr,const char * src)43 static char *selabel_sub(struct selabel_sub *ptr, const char *src)
44 {
45 char *dst = NULL;
46 int len;
47
48 while (ptr) {
49 if (strncmp(src, ptr->src, ptr->slen) == 0 ) {
50 if (src[ptr->slen] == '/' ||
51 src[ptr->slen] == 0) {
52 if ((src[ptr->slen] == '/') &&
53 (strcmp(ptr->dst, "/") == 0))
54 len = ptr->slen + 1;
55 else
56 len = ptr->slen;
57 if (asprintf(&dst, "%s%s", ptr->dst, &src[len]) < 0)
58 return NULL;
59 return dst;
60 }
61 }
62 ptr = ptr->next;
63 }
64 return NULL;
65 }
66
selabel_subs_init(const char * path,struct selabel_sub * list)67 struct selabel_sub *selabel_subs_init(const char *path, struct selabel_sub *list)
68 {
69 char buf[1024];
70 FILE *cfg = fopen(path, "r");
71 struct selabel_sub *sub;
72
73 if (!cfg)
74 return list;
75
76 while (fgets_unlocked(buf, sizeof(buf) - 1, cfg)) {
77 char *ptr = NULL;
78 char *src = buf;
79 char *dst = NULL;
80
81 while (*src && isspace(*src))
82 src++;
83 if (src[0] == '#') continue;
84 ptr = src;
85 while (*ptr && ! isspace(*ptr))
86 ptr++;
87 *ptr++ = '\0';
88 if (! *src) continue;
89
90 dst = ptr;
91 while (*dst && isspace(*dst))
92 dst++;
93 ptr=dst;
94 while (*ptr && ! isspace(*ptr))
95 ptr++;
96 *ptr='\0';
97 if (! *dst)
98 continue;
99
100 sub = malloc(sizeof(*sub));
101 if (! sub)
102 goto err;
103 memset(sub, 0, sizeof(*sub));
104
105 sub->src=strdup(src);
106 if (! sub->src)
107 goto err;
108
109 sub->dst=strdup(dst);
110 if (! sub->dst)
111 goto err;
112
113 sub->slen = strlen(src);
114 sub->next = list;
115 list = sub;
116 }
117 out:
118 fclose(cfg);
119 return list;
120 err:
121 if (sub)
122 free(sub->src);
123 free(sub);
124 goto out;
125 }
126
127 /*
128 * Validation functions
129 */
130
selabel_is_validate_set(struct selinux_opt * opts,unsigned n)131 static inline int selabel_is_validate_set(struct selinux_opt *opts, unsigned n)
132 {
133 while (n--)
134 if (opts[n].type == SELABEL_OPT_VALIDATE)
135 return !!opts[n].value;
136
137 return 0;
138 }
139
selabel_validate(struct selabel_handle * rec,struct selabel_lookup_rec * contexts)140 int selabel_validate(struct selabel_handle *rec,
141 struct selabel_lookup_rec *contexts)
142 {
143 int rc = 0;
144
145 if (!rec->validating || contexts->validated)
146 goto out;
147
148 rc = selinux_validate(&contexts->ctx_raw);
149 if (rc < 0)
150 goto out;
151
152 contexts->validated = 1;
153 out:
154 return rc;
155 }
156
157 /*
158 * Public API
159 */
160
selabel_open(unsigned int backend,struct selinux_opt * opts,unsigned nopts)161 struct selabel_handle *selabel_open(unsigned int backend,
162 struct selinux_opt *opts, unsigned nopts)
163 {
164 struct selabel_handle *rec = NULL;
165
166 if (backend >= ARRAY_SIZE(initfuncs)) {
167 errno = EINVAL;
168 goto out;
169 }
170
171 rec = (struct selabel_handle *)malloc(sizeof(*rec));
172 if (!rec)
173 goto out;
174
175 memset(rec, 0, sizeof(*rec));
176 rec->backend = backend;
177 rec->validating = selabel_is_validate_set(opts, nopts);
178
179 rec->subs = NULL;
180 rec->dist_subs = NULL;
181
182 if ((*initfuncs[backend])(rec, opts, nopts)) {
183 free(rec);
184 rec = NULL;
185 }
186
187 out:
188 return rec;
189 }
190
191 static struct selabel_lookup_rec *
selabel_lookup_common(struct selabel_handle * rec,int translating,const char * key,int type)192 selabel_lookup_common(struct selabel_handle *rec, int translating,
193 const char *key, int type)
194 {
195 struct selabel_lookup_rec *lr;
196 char *ptr = NULL;
197 char *dptr = NULL;
198
199 if (key == NULL) {
200 errno = EINVAL;
201 return NULL;
202 }
203
204 ptr = selabel_sub(rec->subs, key);
205 if (ptr) {
206 dptr = selabel_sub(rec->dist_subs, ptr);
207 if (dptr) {
208 free(ptr);
209 ptr = dptr;
210 }
211 } else {
212 ptr = selabel_sub(rec->dist_subs, key);
213 }
214 if (ptr) {
215 lr = rec->func_lookup(rec, ptr, type);
216 free(ptr);
217 } else {
218 lr = rec->func_lookup(rec, key, type);
219 }
220 if (!lr)
221 return NULL;
222
223 if (compat_validate(rec, lr, rec->spec_file, 0))
224 return NULL;
225
226 if (translating && !lr->ctx_trans &&
227 selinux_raw_to_trans_context(lr->ctx_raw, &lr->ctx_trans))
228 return NULL;
229
230 return lr;
231 }
232
selabel_lookup(struct selabel_handle * rec,char ** con,const char * key,int type)233 int selabel_lookup(struct selabel_handle *rec, char **con,
234 const char *key, int type)
235 {
236 struct selabel_lookup_rec *lr;
237
238 lr = selabel_lookup_common(rec, 1, key, type);
239 if (!lr)
240 return -1;
241
242 *con = strdup(lr->ctx_trans);
243 return *con ? 0 : -1;
244 }
245
selabel_lookup_raw(struct selabel_handle * rec,char ** con,const char * key,int type)246 int selabel_lookup_raw(struct selabel_handle *rec, char **con,
247 const char *key, int type)
248 {
249 struct selabel_lookup_rec *lr;
250
251 lr = selabel_lookup_common(rec, 0, key, type);
252 if (!lr)
253 return -1;
254
255 *con = strdup(lr->ctx_raw);
256 return *con ? 0 : -1;
257 }
258
selabel_close(struct selabel_handle * rec)259 void selabel_close(struct selabel_handle *rec)
260 {
261 selabel_subs_fini(rec->subs);
262 selabel_subs_fini(rec->dist_subs);
263 rec->func_close(rec);
264 free(rec->spec_file);
265 free(rec);
266 }
267
selabel_stats(struct selabel_handle * rec)268 void selabel_stats(struct selabel_handle *rec)
269 {
270 rec->func_stats(rec);
271 }
272