xref: /third_party/selinux/libsepol/src/users.c (revision 6cd6a6ac)
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
15static 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
104int 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
287int 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
302int 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
312int 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
341int 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