• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <errno.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <stdio.h>
5 
6 #include "context_internal.h"
7 #include "debug.h"
8 #include "private.h"
9 
10 struct sepol_context {
11 
12 	/* Selinux user */
13 	char *user;
14 
15 	/* Selinux role */
16 	char *role;
17 
18 	/* Selinux type */
19 	char *type;
20 
21 	/* MLS */
22 	char *mls;
23 };
24 
25 /* User */
sepol_context_get_user(const sepol_context_t * con)26 const char *sepol_context_get_user(const sepol_context_t * con)
27 {
28 
29 	return con->user;
30 }
31 
hidden_def(sepol_context_get_user)32 hidden_def(sepol_context_get_user)
33 
34 int sepol_context_set_user(sepol_handle_t * handle,
35 			   sepol_context_t * con, const char *user)
36 {
37 
38 	char *tmp_user = strdup(user);
39 	if (!tmp_user) {
40 		ERR(handle, "out of memory, could not set "
41 		    "context user to %s", user);
42 		return STATUS_ERR;
43 	}
44 
45 	free(con->user);
46 	con->user = tmp_user;
47 	return STATUS_SUCCESS;
48 }
49 
hidden_def(sepol_context_set_user)50 hidden_def(sepol_context_set_user)
51 
52 /* Role */
53 const char *sepol_context_get_role(const sepol_context_t * con)
54 {
55 
56 	return con->role;
57 }
58 
hidden_def(sepol_context_get_role)59 hidden_def(sepol_context_get_role)
60 
61 int sepol_context_set_role(sepol_handle_t * handle,
62 			   sepol_context_t * con, const char *role)
63 {
64 
65 	char *tmp_role = strdup(role);
66 	if (!tmp_role) {
67 		ERR(handle, "out of memory, could not set "
68 		    "context role to %s", role);
69 		return STATUS_ERR;
70 	}
71 	free(con->role);
72 	con->role = tmp_role;
73 	return STATUS_SUCCESS;
74 }
75 
hidden_def(sepol_context_set_role)76 hidden_def(sepol_context_set_role)
77 
78 /* Type */
79 const char *sepol_context_get_type(const sepol_context_t * con)
80 {
81 
82 	return con->type;
83 }
84 
hidden_def(sepol_context_get_type)85 hidden_def(sepol_context_get_type)
86 
87 int sepol_context_set_type(sepol_handle_t * handle,
88 			   sepol_context_t * con, const char *type)
89 {
90 
91 	char *tmp_type = strdup(type);
92 	if (!tmp_type) {
93 		ERR(handle, "out of memory, could not set "
94 		    "context type to %s", type);
95 		return STATUS_ERR;
96 	}
97 	free(con->type);
98 	con->type = tmp_type;
99 	return STATUS_SUCCESS;
100 }
101 
hidden_def(sepol_context_set_type)102 hidden_def(sepol_context_set_type)
103 
104 /* MLS */
105 const char *sepol_context_get_mls(const sepol_context_t * con)
106 {
107 
108 	return con->mls;
109 }
110 
hidden_def(sepol_context_get_mls)111 hidden_def(sepol_context_get_mls)
112 
113 int sepol_context_set_mls(sepol_handle_t * handle,
114 			  sepol_context_t * con, const char *mls)
115 {
116 
117 	char *tmp_mls = strdup(mls);
118 	if (!tmp_mls) {
119 		ERR(handle, "out of memory, could not set "
120 		    "MLS fields to %s", mls);
121 		return STATUS_ERR;
122 	}
123 	free(con->mls);
124 	con->mls = tmp_mls;
125 	return STATUS_SUCCESS;
126 }
127 
hidden_def(sepol_context_set_mls)128 hidden_def(sepol_context_set_mls)
129 
130 /* Create */
131 int sepol_context_create(sepol_handle_t * handle, sepol_context_t ** con_ptr)
132 {
133 
134 	sepol_context_t *con =
135 	    (sepol_context_t *) malloc(sizeof(sepol_context_t));
136 
137 	if (!con) {
138 		ERR(handle, "out of memory, could not " "create context\n");
139 		return STATUS_ERR;
140 	}
141 
142 	con->user = NULL;
143 	con->role = NULL;
144 	con->type = NULL;
145 	con->mls = NULL;
146 	*con_ptr = con;
147 	return STATUS_SUCCESS;
148 }
149 
hidden_def(sepol_context_create)150 hidden_def(sepol_context_create)
151 
152 /* Deep copy clone */
153 int sepol_context_clone(sepol_handle_t * handle,
154 			const sepol_context_t * con, sepol_context_t ** con_ptr)
155 {
156 
157 	sepol_context_t *new_con = NULL;
158 
159 	if (!con) {
160 		*con_ptr = NULL;
161 		return 0;
162 	}
163 
164 	if (sepol_context_create(handle, &new_con) < 0)
165 		goto err;
166 
167 	if (!(new_con->user = strdup(con->user)))
168 		goto omem;
169 
170 	if (!(new_con->role = strdup(con->role)))
171 		goto omem;
172 
173 	if (!(new_con->type = strdup(con->type)))
174 		goto omem;
175 
176 	if (con->mls && !(new_con->mls = strdup(con->mls)))
177 		goto omem;
178 
179 	*con_ptr = new_con;
180 	return STATUS_SUCCESS;
181 
182       omem:
183 	ERR(handle, "out of memory");
184 
185       err:
186 	ERR(handle, "could not clone context record");
187 	sepol_context_free(new_con);
188 	return STATUS_ERR;
189 }
190 
hidden_def(sepol_context_clone)191 hidden_def(sepol_context_clone)
192 
193 /* Destroy */
194 void sepol_context_free(sepol_context_t * con)
195 {
196 
197 	if (!con)
198 		return;
199 
200 	free(con->user);
201 	free(con->role);
202 	free(con->type);
203 	free(con->mls);
204 	free(con);
205 }
206 
hidden_def(sepol_context_free)207 hidden_def(sepol_context_free)
208 
209 int sepol_context_from_string(sepol_handle_t * handle,
210 			      const char *str, sepol_context_t ** con)
211 {
212 
213 	char *tmp = NULL, *low, *high;
214 	sepol_context_t *tmp_con = NULL;
215 
216 	if (!strcmp(str, "<<none>>")) {
217 		*con = NULL;
218 		return STATUS_SUCCESS;
219 	}
220 
221 	if (sepol_context_create(handle, &tmp_con) < 0)
222 		goto err;
223 
224 	/* Working copy context */
225 	tmp = strdup(str);
226 	if (!tmp) {
227 		ERR(handle, "out of memory");
228 		goto err;
229 	}
230 	low = tmp;
231 
232 	/* Then, break it into its components */
233 
234 	/* User */
235 	if (!(high = strchr(low, ':')))
236 		goto mcontext;
237 	else
238 		*high++ = '\0';
239 	if (sepol_context_set_user(handle, tmp_con, low) < 0)
240 		goto err;
241 	low = high;
242 
243 	/* Role */
244 	if (!(high = strchr(low, ':')))
245 		goto mcontext;
246 	else
247 		*high++ = '\0';
248 	if (sepol_context_set_role(handle, tmp_con, low) < 0)
249 		goto err;
250 	low = high;
251 
252 	/* Type, and possibly MLS */
253 	if (!(high = strchr(low, ':'))) {
254 		if (sepol_context_set_type(handle, tmp_con, low) < 0)
255 			goto err;
256 	} else {
257 		*high++ = '\0';
258 		if (sepol_context_set_type(handle, tmp_con, low) < 0)
259 			goto err;
260 		low = high;
261 		if (sepol_context_set_mls(handle, tmp_con, low) < 0)
262 			goto err;
263 	}
264 
265 	free(tmp);
266 	*con = tmp_con;
267 
268 	return STATUS_SUCCESS;
269 
270       mcontext:
271 	errno = EINVAL;
272 	ERR(handle, "malformed context \"%s\"", str);
273 
274       err:
275 	ERR(handle, "could not construct context from string");
276 	free(tmp);
277 	sepol_context_free(tmp_con);
278 	return STATUS_ERR;
279 }
280 
hidden_def(sepol_context_from_string)281 hidden_def(sepol_context_from_string)
282 
283 static inline int safe_sum(size_t *sum, const size_t augends[], const size_t cnt) {
284 
285 	size_t a, i;
286 
287 	*sum = 0;
288 	for(i=0; i < cnt; i++) {
289 		/* sum should not be smaller than the addend */
290 		a = augends[i];
291 		*sum += a;
292 		if (*sum < a) {
293 			return i;
294 		}
295 	}
296 
297 	return 0;
298 }
299 
sepol_context_to_string(sepol_handle_t * handle,const sepol_context_t * con,char ** str_ptr)300 int sepol_context_to_string(sepol_handle_t * handle,
301 			    const sepol_context_t * con, char **str_ptr)
302 {
303 
304 	int rc;
305 	char *str = NULL;
306 	size_t total_sz, err;
307 	const size_t sizes[] = {
308 			strlen(con->user),                 /* user length */
309 			strlen(con->role),                 /* role length */
310 			strlen(con->type),                 /* type length */
311 			(con->mls) ? strlen(con->mls) : 0, /* mls length */
312 			((con->mls) ? 3 : 2) + 1           /* mls has extra ":" also null byte */
313 	};
314 
315 	err = safe_sum(&total_sz, sizes, ARRAY_SIZE(sizes));
316 	if (err) {
317 		ERR(handle, "invalid size, overflow at position: %zu", err);
318 		goto err;
319 	}
320 
321 	str = (char *)malloc(total_sz);
322 	if (!str) {
323 		ERR(handle, "out of memory");
324 		goto err;
325 	}
326 	if (con->mls) {
327 		rc = snprintf(str, total_sz, "%s:%s:%s:%s",
328 			      con->user, con->role, con->type, con->mls);
329 	} else {
330 		rc = snprintf(str, total_sz, "%s:%s:%s",
331 			      con->user, con->role, con->type);
332 	}
333 
334 	/*
335 	 * rc is >= 0 on the size_t cast and is safe to promote
336 	 * to an unsigned value.
337 	 */
338 	if (rc < 0 || (size_t)rc >= total_sz) {
339 		ERR(handle, "print error");
340 		goto err;
341 	}
342 
343 	*str_ptr = str;
344 	return STATUS_SUCCESS;
345 
346       err:
347 	ERR(handle, "could not convert context to string");
348 	free(str);
349 	return STATUS_ERR;
350 }
351