• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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