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