1 #include <stdlib.h>
2 #include <stddef.h>
3 #include <string.h>
4
5 #include "private.h"
6 #include "debug.h"
7 #include "handle.h"
8
9 #include <sepol/policydb/policydb.h>
10 #include <sepol/policydb/hashtab.h>
11 #include <sepol/policydb/expand.h>
12 #include "user_internal.h"
13 #include "mls.h"
14
user_to_record(sepol_handle_t * handle,const policydb_t * policydb,int user_idx,sepol_user_t ** record)15 static int user_to_record(sepol_handle_t * handle,
16 const policydb_t * policydb,
17 int user_idx, sepol_user_t ** record)
18 {
19
20 const char *name = policydb->p_user_val_to_name[user_idx];
21 user_datum_t *usrdatum = policydb->user_val_to_struct[user_idx];
22 ebitmap_t *roles;
23 ebitmap_node_t *rnode;
24 unsigned bit;
25
26 sepol_user_t *tmp_record = NULL;
27
28 if (!usrdatum)
29 goto err;
30
31 roles = &(usrdatum->roles.roles);
32
33 if (sepol_user_create(handle, &tmp_record) < 0)
34 goto err;
35
36 if (sepol_user_set_name(handle, tmp_record, name) < 0)
37 goto err;
38
39 /* Extract roles */
40 ebitmap_for_each_positive_bit(roles, rnode, bit) {
41 char *role = policydb->p_role_val_to_name[bit];
42 if (sepol_user_add_role(handle, tmp_record, role) < 0)
43 goto err;
44 }
45
46 /* Extract MLS info */
47 if (policydb->mls) {
48 context_struct_t context;
49 char *str;
50
51 context_init(&context);
52 if (mls_level_cpy(&context.range.level[0],
53 &usrdatum->exp_dfltlevel) < 0) {
54 ERR(handle, "could not copy MLS level");
55 context_destroy(&context);
56 goto err;
57 }
58 if (mls_level_cpy(&context.range.level[1],
59 &usrdatum->exp_dfltlevel) < 0) {
60 ERR(handle, "could not copy MLS level");
61 context_destroy(&context);
62 goto err;
63 }
64 if (mls_to_string(handle, policydb, &context, &str) < 0) {
65 context_destroy(&context);
66 goto err;
67 }
68 context_destroy(&context);
69
70 if (sepol_user_set_mlslevel(handle, tmp_record, str) < 0) {
71 free(str);
72 goto err;
73 }
74 free(str);
75
76 context_init(&context);
77 if (mls_range_cpy(&context.range, &usrdatum->exp_range) < 0) {
78 ERR(handle, "could not copy MLS range");
79 context_destroy(&context);
80 goto err;
81 }
82 if (mls_to_string(handle, policydb, &context, &str) < 0) {
83 context_destroy(&context);
84 goto err;
85 }
86 context_destroy(&context);
87
88 if (sepol_user_set_mlsrange(handle, tmp_record, str) < 0) {
89 free(str);
90 goto err;
91 }
92 free(str);
93 }
94
95 *record = tmp_record;
96 return STATUS_SUCCESS;
97
98 err:
99 /* FIXME: handle error */
100 sepol_user_free(tmp_record);
101 return STATUS_ERR;
102 }
103
sepol_user_modify(sepol_handle_t * handle,sepol_policydb_t * p,const sepol_user_key_t * key,const sepol_user_t * user)104 int sepol_user_modify(sepol_handle_t * handle,
105 sepol_policydb_t * p,
106 const sepol_user_key_t * key, const sepol_user_t * user)
107 {
108
109 policydb_t *policydb = &p->p;
110
111 /* For user data */
112 const char *cname, *cmls_level, *cmls_range;
113 char *name = NULL;
114
115 const char **roles = NULL;
116 unsigned int num_roles = 0;
117
118 /* Low-level representation */
119 user_datum_t *usrdatum = NULL;
120 role_datum_t *roldatum;
121 unsigned int i;
122
123 context_struct_t context;
124 unsigned bit;
125 int new = 0;
126
127 ebitmap_node_t *rnode;
128
129 /* First, extract all the data */
130 sepol_user_key_unpack(key, &cname);
131
132 cmls_level = sepol_user_get_mlslevel(user);
133 cmls_range = sepol_user_get_mlsrange(user);
134
135 /* Make sure that worked properly */
136 if (sepol_user_get_roles(handle, user, &roles, &num_roles) < 0)
137 goto err;
138
139 /* Now, see if a user exists */
140 usrdatum = hashtab_search(policydb->p_users.table, cname);
141
142 /* If it does, we will modify it */
143 if (usrdatum) {
144
145 int value_cp = usrdatum->s.value;
146 user_datum_destroy(usrdatum);
147 user_datum_init(usrdatum);
148 usrdatum->s.value = value_cp;
149
150 /* Otherwise, create a new one */
151 } else {
152 usrdatum = (user_datum_t *) malloc(sizeof(user_datum_t));
153 if (!usrdatum)
154 goto omem;
155 user_datum_init(usrdatum);
156 new = 1;
157 }
158
159 /* For every role */
160 for (i = 0; i < num_roles; i++) {
161
162 /* Search for the role */
163 roldatum = hashtab_search(policydb->p_roles.table, roles[i]);
164 if (!roldatum) {
165 ERR(handle, "undefined role %s for user %s",
166 roles[i], cname);
167 goto err;
168 }
169
170 /* Set the role and every role it dominates */
171 ebitmap_for_each_positive_bit(&roldatum->dominates, rnode, bit) {
172 if (ebitmap_set_bit(&(usrdatum->roles.roles), bit, 1))
173 goto omem;
174 }
175 }
176
177 /* For MLS systems */
178 if (policydb->mls) {
179
180 /* MLS level */
181 if (cmls_level == NULL) {
182 ERR(handle, "MLS is enabled, but no MLS "
183 "default level was defined for user %s", cname);
184 goto err;
185 }
186
187 context_init(&context);
188 if (mls_from_string(handle, policydb, cmls_level, &context) < 0) {
189 context_destroy(&context);
190 goto err;
191 }
192 if (mls_level_cpy(&usrdatum->exp_dfltlevel,
193 &context.range.level[0]) < 0) {
194 ERR(handle, "could not copy MLS level %s", cmls_level);
195 context_destroy(&context);
196 goto err;
197 }
198 context_destroy(&context);
199
200 /* MLS range */
201 if (cmls_range == NULL) {
202 ERR(handle, "MLS is enabled, but no MLS"
203 "range was defined for user %s", cname);
204 goto err;
205 }
206
207 context_init(&context);
208 if (mls_from_string(handle, policydb, cmls_range, &context) < 0) {
209 context_destroy(&context);
210 goto err;
211 }
212 if (mls_range_cpy(&usrdatum->exp_range, &context.range) < 0) {
213 ERR(handle, "could not copy MLS range %s", cmls_range);
214 context_destroy(&context);
215 goto err;
216 }
217 context_destroy(&context);
218 } else if (cmls_level != NULL || cmls_range != NULL) {
219 ERR(handle, "MLS is disabled, but MLS level/range "
220 "was found for user %s", cname);
221 goto err;
222 }
223
224 /* If there are no errors, and this is a new user, add the user to policy */
225 if (new) {
226 void *tmp_ptr;
227
228 /* Ensure reverse lookup array has enough space */
229 tmp_ptr = reallocarray(policydb->user_val_to_struct,
230 policydb->p_users.nprim + 1,
231 sizeof(user_datum_t *));
232 if (!tmp_ptr)
233 goto omem;
234 policydb->user_val_to_struct = tmp_ptr;
235 policydb->user_val_to_struct[policydb->p_users.nprim] = NULL;
236
237 tmp_ptr = reallocarray(policydb->sym_val_to_name[SYM_USERS],
238 policydb->p_users.nprim + 1,
239 sizeof(char *));
240 if (!tmp_ptr)
241 goto omem;
242 policydb->sym_val_to_name[SYM_USERS] = tmp_ptr;
243 policydb->p_user_val_to_name[policydb->p_users.nprim] = NULL;
244
245 /* Need to copy the user name */
246 name = strdup(cname);
247 if (!name)
248 goto omem;
249
250 /* Store user */
251 usrdatum->s.value = ++policydb->p_users.nprim;
252 if (hashtab_insert(policydb->p_users.table, name,
253 (hashtab_datum_t) usrdatum) < 0)
254 goto omem;
255
256 /* Set up reverse entry */
257 policydb->p_user_val_to_name[usrdatum->s.value - 1] = name;
258 policydb->user_val_to_struct[usrdatum->s.value - 1] = usrdatum;
259 name = NULL;
260
261 /* Expand roles */
262 if (role_set_expand(&usrdatum->roles, &usrdatum->cache,
263 policydb, NULL, NULL)) {
264 ERR(handle, "unable to expand role set");
265 goto err;
266 }
267 }
268
269 free(roles);
270 return STATUS_SUCCESS;
271
272 omem:
273 ERR(handle, "out of memory");
274
275 err:
276 ERR(handle, "could not load %s into policy", name);
277
278 free(name);
279 free(roles);
280 if (new && usrdatum) {
281 role_set_destroy(&usrdatum->roles);
282 free(usrdatum);
283 }
284 return STATUS_ERR;
285 }
286
sepol_user_exists(sepol_handle_t * handle,const sepol_policydb_t * p,const sepol_user_key_t * key,int * response)287 int sepol_user_exists(sepol_handle_t * handle __attribute__ ((unused)),
288 const sepol_policydb_t * p,
289 const sepol_user_key_t * key, int *response)
290 {
291
292 const policydb_t *policydb = &p->p;
293
294 const char *cname;
295 sepol_user_key_unpack(key, &cname);
296
297 *response = (hashtab_search(policydb->p_users.table, cname) != NULL);
298
299 return STATUS_SUCCESS;
300 }
301
sepol_user_count(sepol_handle_t * handle,const sepol_policydb_t * p,unsigned int * response)302 int sepol_user_count(sepol_handle_t * handle __attribute__ ((unused)),
303 const sepol_policydb_t * p, unsigned int *response)
304 {
305
306 const policydb_t *policydb = &p->p;
307 *response = policydb->p_users.nprim;
308
309 return STATUS_SUCCESS;
310 }
311
sepol_user_query(sepol_handle_t * handle,const sepol_policydb_t * p,const sepol_user_key_t * key,sepol_user_t ** response)312 int sepol_user_query(sepol_handle_t * handle,
313 const sepol_policydb_t * p,
314 const sepol_user_key_t * key, sepol_user_t ** response)
315 {
316
317 const policydb_t *policydb = &p->p;
318 user_datum_t *usrdatum = NULL;
319
320 const char *cname;
321 sepol_user_key_unpack(key, &cname);
322
323 usrdatum = hashtab_search(policydb->p_users.table, cname);
324
325 if (!usrdatum) {
326 *response = NULL;
327 return STATUS_SUCCESS;
328 }
329
330 if (user_to_record(handle, policydb, usrdatum->s.value - 1, response) <
331 0)
332 goto err;
333
334 return STATUS_SUCCESS;
335
336 err:
337 ERR(handle, "could not query user %s", cname);
338 return STATUS_ERR;
339 }
340
sepol_user_iterate(sepol_handle_t * handle,const sepol_policydb_t * p,int (* fn)(const sepol_user_t * user,void * fn_arg),void * arg)341 int sepol_user_iterate(sepol_handle_t * handle,
342 const sepol_policydb_t * p,
343 int (*fn) (const sepol_user_t * user,
344 void *fn_arg), void *arg)
345 {
346
347 const policydb_t *policydb = &p->p;
348 unsigned int nusers = policydb->p_users.nprim;
349 sepol_user_t *user = NULL;
350 unsigned int i;
351
352 /* For each user */
353 for (i = 0; i < nusers; i++) {
354
355 int status;
356
357 if (user_to_record(handle, policydb, i, &user) < 0)
358 goto err;
359
360 /* Invoke handler */
361 status = fn(user, arg);
362 if (status < 0)
363 goto err;
364
365 sepol_user_free(user);
366 user = NULL;
367
368 /* Handler requested exit */
369 if (status > 0)
370 break;
371 }
372
373 return STATUS_SUCCESS;
374
375 err:
376 ERR(handle, "could not iterate over users");
377 sepol_user_free(user);
378 return STATUS_ERR;
379 }
380