1#include <stdlib.h>
2#include <string.h>
3#include <errno.h>
4
5#include <sepol/policydb/policydb.h>
6#include <sepol/policydb/services.h>
7#include "context_internal.h"
8
9#include "debug.h"
10#include "context.h"
11#include "handle.h"
12#include "mls.h"
13#include "private.h"
14
15/* ----- Compatibility ---- */
16int policydb_context_isvalid(const policydb_t * p, const context_struct_t * c)
17{
18
19	return context_is_valid(p, c);
20}
21
22int sepol_check_context(const char *context)
23{
24
25	return sepol_context_to_sid((const sepol_security_context_t)context,
26				    strlen(context) + 1, NULL);
27}
28
29/* ---- End compatibility --- */
30
31/*
32 * Return 1 if the fields in the security context
33 * structure `c' are valid.  Return 0 otherwise.
34 */
35int context_is_valid(const policydb_t * p, const context_struct_t * c)
36{
37
38	role_datum_t *role;
39	user_datum_t *usrdatum;
40	ebitmap_t types, roles;
41	int ret = 1;
42
43	ebitmap_init(&types);
44	ebitmap_init(&roles);
45	if (!c->role || c->role > p->p_roles.nprim)
46		return 0;
47
48	if (!c->user || c->user > p->p_users.nprim)
49		return 0;
50
51	if (!c->type || c->type > p->p_types.nprim)
52		return 0;
53
54	if (c->role != OBJECT_R_VAL) {
55		/*
56		 * Role must be authorized for the type.
57		 */
58		role = p->role_val_to_struct[c->role - 1];
59		if (!role || !ebitmap_get_bit(&role->cache, c->type - 1))
60			/* role may not be associated with type */
61			return 0;
62
63		/*
64		 * User must be authorized for the role.
65		 */
66		usrdatum = p->user_val_to_struct[c->user - 1];
67		if (!usrdatum)
68			return 0;
69
70		if (!ebitmap_get_bit(&usrdatum->cache, c->role - 1))
71			/* user may not be associated with role */
72			return 0;
73	}
74
75	if (!mls_context_isvalid(p, c))
76		return 0;
77
78	return ret;
79}
80
81/*
82 * Write the security context string representation of
83 * the context structure `context' into a dynamically
84 * allocated string of the correct size.  Set `*scontext'
85 * to point to this string and set `*scontext_len' to
86 * the length of the string.
87 */
88int context_to_string(sepol_handle_t * handle,
89		      const policydb_t * policydb,
90		      const context_struct_t * context,
91		      char **result, size_t * result_len)
92{
93
94	char *scontext = NULL;
95	size_t scontext_len = 0;
96	char *ptr;
97
98	/* Compute the size of the context. */
99	scontext_len +=
100	    strlen(policydb->p_user_val_to_name[context->user - 1]) + 1;
101	scontext_len +=
102	    strlen(policydb->p_role_val_to_name[context->role - 1]) + 1;
103	scontext_len += strlen(policydb->p_type_val_to_name[context->type - 1]);
104	scontext_len += mls_compute_context_len(policydb, context);
105
106	/* We must null terminate the string */
107	scontext_len += 1;
108
109	/* Allocate space for the context; caller must free this space. */
110	scontext = malloc(scontext_len);
111	if (!scontext)
112		goto omem;
113	scontext[scontext_len - 1] = '\0';
114
115	/*
116	 * Copy the user name, role name and type name into the context.
117	 */
118	ptr = scontext;
119	sprintf(ptr, "%s:%s:%s",
120		policydb->p_user_val_to_name[context->user - 1],
121		policydb->p_role_val_to_name[context->role - 1],
122		policydb->p_type_val_to_name[context->type - 1]);
123
124	ptr +=
125	    strlen(policydb->p_user_val_to_name[context->user - 1]) + 1 +
126	    strlen(policydb->p_role_val_to_name[context->role - 1]) + 1 +
127	    strlen(policydb->p_type_val_to_name[context->type - 1]);
128
129	mls_sid_to_context(policydb, context, &ptr);
130
131	*result = scontext;
132	*result_len = scontext_len;
133	return STATUS_SUCCESS;
134
135      omem:
136	ERR(handle, "out of memory, could not convert " "context to string");
137	free(scontext);
138	return STATUS_ERR;
139}
140
141/*
142 * Create a context structure from the given record
143 */
144int context_from_record(sepol_handle_t * handle,
145			const policydb_t * policydb,
146			context_struct_t ** cptr,
147			const sepol_context_t * record)
148{
149
150	context_struct_t *scontext = NULL;
151	user_datum_t *usrdatum;
152	role_datum_t *roldatum;
153	type_datum_t *typdatum;
154
155	/* Hashtab keys are not constant - suppress warnings */
156	char *user = strdup(sepol_context_get_user(record));
157	char *role = strdup(sepol_context_get_role(record));
158	char *type = strdup(sepol_context_get_type(record));
159	const char *mls = sepol_context_get_mls(record);
160
161	scontext = (context_struct_t *) malloc(sizeof(context_struct_t));
162	if (!user || !role || !type || !scontext) {
163		ERR(handle, "out of memory");
164		goto err;
165	}
166	context_init(scontext);
167
168	/* User */
169	usrdatum = (user_datum_t *) hashtab_search(policydb->p_users.table,
170						   (hashtab_key_t) user);
171	if (!usrdatum) {
172		ERR(handle, "user %s is not defined", user);
173		goto err_destroy;
174	}
175	scontext->user = usrdatum->s.value;
176
177	/* Role */
178	roldatum = (role_datum_t *) hashtab_search(policydb->p_roles.table,
179						   (hashtab_key_t) role);
180	if (!roldatum) {
181		ERR(handle, "role %s is not defined", role);
182		goto err_destroy;
183	}
184	scontext->role = roldatum->s.value;
185
186	/* Type */
187	typdatum = (type_datum_t *) hashtab_search(policydb->p_types.table,
188						   (hashtab_key_t) type);
189	if (!typdatum || typdatum->flavor == TYPE_ATTRIB) {
190		ERR(handle, "type %s is not defined", type);
191		goto err_destroy;
192	}
193	scontext->type = typdatum->s.value;
194
195	/* MLS */
196	if (mls && !policydb->mls) {
197		ERR(handle, "MLS is disabled, but MLS context \"%s\" found",
198		    mls);
199		goto err_destroy;
200	} else if (!mls && policydb->mls) {
201		ERR(handle, "MLS is enabled, but no MLS context found");
202		goto err_destroy;
203	}
204	if (mls && (mls_from_string(handle, policydb, mls, scontext) < 0))
205		goto err_destroy;
206
207	/* Validity check */
208	if (!context_is_valid(policydb, scontext)) {
209		if (mls) {
210			ERR(handle,
211			    "invalid security context: \"%s:%s:%s:%s\"",
212			    user, role, type, mls);
213		} else {
214			ERR(handle,
215			    "invalid security context: \"%s:%s:%s\"",
216			    user, role, type);
217		}
218		goto err_destroy;
219	}
220
221	*cptr = scontext;
222	free(user);
223	free(type);
224	free(role);
225	return STATUS_SUCCESS;
226
227      err_destroy:
228	errno = EINVAL;
229	context_destroy(scontext);
230
231      err:
232	free(scontext);
233	free(user);
234	free(type);
235	free(role);
236	ERR(handle, "could not create context structure");
237	return STATUS_ERR;
238}
239
240/*
241 * Create a record from the given context structure
242 */
243int context_to_record(sepol_handle_t * handle,
244		      const policydb_t * policydb,
245		      const context_struct_t * context,
246		      sepol_context_t ** record)
247{
248
249	sepol_context_t *tmp_record = NULL;
250	char *mls = NULL;
251
252	if (sepol_context_create(handle, &tmp_record) < 0)
253		goto err;
254
255	if (sepol_context_set_user(handle, tmp_record,
256				   policydb->p_user_val_to_name[context->user -
257								1]) < 0)
258		goto err;
259
260	if (sepol_context_set_role(handle, tmp_record,
261				   policydb->p_role_val_to_name[context->role -
262								1]) < 0)
263		goto err;
264
265	if (sepol_context_set_type(handle, tmp_record,
266				   policydb->p_type_val_to_name[context->type -
267								1]) < 0)
268		goto err;
269
270	if (policydb->mls) {
271		if (mls_to_string(handle, policydb, context, &mls) < 0)
272			goto err;
273
274		if (sepol_context_set_mls(handle, tmp_record, mls) < 0)
275			goto err;
276	}
277
278	free(mls);
279	*record = tmp_record;
280	return STATUS_SUCCESS;
281
282      err:
283	ERR(handle, "could not create context record");
284	sepol_context_free(tmp_record);
285	free(mls);
286	return STATUS_ERR;
287}
288
289/*
290 * Create a context structure from the provided string.
291 */
292int context_from_string(sepol_handle_t * handle,
293			const policydb_t * policydb,
294			context_struct_t ** cptr,
295			const char *con_str, size_t con_str_len)
296{
297
298	char *con_cpy = NULL;
299	sepol_context_t *ctx_record = NULL;
300
301	if (zero_or_saturated(con_str_len)) {
302		ERR(handle, "Invalid context length");
303		goto err;
304	}
305
306	/* sepol_context_from_string expects a NULL-terminated string */
307	con_cpy = malloc(con_str_len + 1);
308	if (!con_cpy) {
309		ERR(handle, "out of memory");
310		goto err;
311	}
312
313	memcpy(con_cpy, con_str, con_str_len);
314	con_cpy[con_str_len] = '\0';
315
316	if (sepol_context_from_string(handle, con_cpy, &ctx_record) < 0)
317		goto err;
318
319	/* Now create from the data structure */
320	if (context_from_record(handle, policydb, cptr, ctx_record) < 0)
321		goto err;
322
323	free(con_cpy);
324	sepol_context_free(ctx_record);
325	return STATUS_SUCCESS;
326
327      err:
328	ERR(handle, "could not create context structure");
329	free(con_cpy);
330	sepol_context_free(ctx_record);
331	return STATUS_ERR;
332}
333
334int sepol_context_check(sepol_handle_t * handle,
335			const sepol_policydb_t * policydb,
336			const sepol_context_t * context)
337{
338
339	context_struct_t *con = NULL;
340	int ret = context_from_record(handle, &policydb->p, &con, context);
341	context_destroy(con);
342	free(con);
343	return ret;
344}
345