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
10struct 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 */
26const char *sepol_context_get_user(const sepol_context_t * con)
27{
28
29	return con->user;
30}
31
32hidden_def(sepol_context_get_user)
33
34int 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
50hidden_def(sepol_context_set_user)
51
52/* Role */
53const char *sepol_context_get_role(const sepol_context_t * con)
54{
55
56	return con->role;
57}
58
59hidden_def(sepol_context_get_role)
60
61int 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
76hidden_def(sepol_context_set_role)
77
78/* Type */
79const char *sepol_context_get_type(const sepol_context_t * con)
80{
81
82	return con->type;
83}
84
85hidden_def(sepol_context_get_type)
86
87int 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
102hidden_def(sepol_context_set_type)
103
104/* MLS */
105const char *sepol_context_get_mls(const sepol_context_t * con)
106{
107
108	return con->mls;
109}
110
111hidden_def(sepol_context_get_mls)
112
113int 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
128hidden_def(sepol_context_set_mls)
129
130/* Create */
131int 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
150hidden_def(sepol_context_create)
151
152/* Deep copy clone */
153int 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
191hidden_def(sepol_context_clone)
192
193/* Destroy */
194void 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
207hidden_def(sepol_context_free)
208
209int 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
281hidden_def(sepol_context_from_string)
282
283static 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
300int 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