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