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