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