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