• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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