16cd6a6acSopenharmony_ci#include <stdlib.h>
26cd6a6acSopenharmony_ci#include <string.h>
36cd6a6acSopenharmony_ci#include <errno.h>
46cd6a6acSopenharmony_ci
56cd6a6acSopenharmony_ci#include <sepol/policydb/policydb.h>
66cd6a6acSopenharmony_ci#include <sepol/policydb/services.h>
76cd6a6acSopenharmony_ci#include "context_internal.h"
86cd6a6acSopenharmony_ci
96cd6a6acSopenharmony_ci#include "debug.h"
106cd6a6acSopenharmony_ci#include "context.h"
116cd6a6acSopenharmony_ci#include "handle.h"
126cd6a6acSopenharmony_ci#include "mls.h"
136cd6a6acSopenharmony_ci#include "private.h"
146cd6a6acSopenharmony_ci
156cd6a6acSopenharmony_ci/* ----- Compatibility ---- */
166cd6a6acSopenharmony_ciint policydb_context_isvalid(const policydb_t * p, const context_struct_t * c)
176cd6a6acSopenharmony_ci{
186cd6a6acSopenharmony_ci
196cd6a6acSopenharmony_ci	return context_is_valid(p, c);
206cd6a6acSopenharmony_ci}
216cd6a6acSopenharmony_ci
226cd6a6acSopenharmony_ciint sepol_check_context(const char *context)
236cd6a6acSopenharmony_ci{
246cd6a6acSopenharmony_ci
256cd6a6acSopenharmony_ci	return sepol_context_to_sid(context,
266cd6a6acSopenharmony_ci				    strlen(context) + 1, NULL);
276cd6a6acSopenharmony_ci}
286cd6a6acSopenharmony_ci
296cd6a6acSopenharmony_ci/* ---- End compatibility --- */
306cd6a6acSopenharmony_ci
316cd6a6acSopenharmony_ci/*
326cd6a6acSopenharmony_ci * Return 1 if the fields in the security context
336cd6a6acSopenharmony_ci * structure `c' are valid.  Return 0 otherwise.
346cd6a6acSopenharmony_ci */
356cd6a6acSopenharmony_ciint context_is_valid(const policydb_t * p, const context_struct_t * c)
366cd6a6acSopenharmony_ci{
376cd6a6acSopenharmony_ci
386cd6a6acSopenharmony_ci	role_datum_t *role;
396cd6a6acSopenharmony_ci	user_datum_t *usrdatum;
406cd6a6acSopenharmony_ci	ebitmap_t types, roles;
416cd6a6acSopenharmony_ci
426cd6a6acSopenharmony_ci	ebitmap_init(&types);
436cd6a6acSopenharmony_ci	ebitmap_init(&roles);
446cd6a6acSopenharmony_ci	if (!c->role || c->role > p->p_roles.nprim)
456cd6a6acSopenharmony_ci		return 0;
466cd6a6acSopenharmony_ci
476cd6a6acSopenharmony_ci	if (!c->user || c->user > p->p_users.nprim)
486cd6a6acSopenharmony_ci		return 0;
496cd6a6acSopenharmony_ci
506cd6a6acSopenharmony_ci	if (!c->type || c->type > p->p_types.nprim)
516cd6a6acSopenharmony_ci		return 0;
526cd6a6acSopenharmony_ci
536cd6a6acSopenharmony_ci	if (c->role != OBJECT_R_VAL) {
546cd6a6acSopenharmony_ci		/*
556cd6a6acSopenharmony_ci		 * Role must be authorized for the type.
566cd6a6acSopenharmony_ci		 */
576cd6a6acSopenharmony_ci		role = p->role_val_to_struct[c->role - 1];
586cd6a6acSopenharmony_ci		if (!role || !ebitmap_get_bit(&role->cache, c->type - 1))
596cd6a6acSopenharmony_ci			/* role may not be associated with type */
606cd6a6acSopenharmony_ci			return 0;
616cd6a6acSopenharmony_ci
626cd6a6acSopenharmony_ci		/*
636cd6a6acSopenharmony_ci		 * User must be authorized for the role.
646cd6a6acSopenharmony_ci		 */
656cd6a6acSopenharmony_ci		usrdatum = p->user_val_to_struct[c->user - 1];
666cd6a6acSopenharmony_ci		if (!usrdatum)
676cd6a6acSopenharmony_ci			return 0;
686cd6a6acSopenharmony_ci
696cd6a6acSopenharmony_ci		if (!ebitmap_get_bit(&usrdatum->cache, c->role - 1))
706cd6a6acSopenharmony_ci			/* user may not be associated with role */
716cd6a6acSopenharmony_ci			return 0;
726cd6a6acSopenharmony_ci	}
736cd6a6acSopenharmony_ci
746cd6a6acSopenharmony_ci	if (!mls_context_isvalid(p, c))
756cd6a6acSopenharmony_ci		return 0;
766cd6a6acSopenharmony_ci
776cd6a6acSopenharmony_ci	return 1;
786cd6a6acSopenharmony_ci}
796cd6a6acSopenharmony_ci
806cd6a6acSopenharmony_ci/*
816cd6a6acSopenharmony_ci * Write the security context string representation of
826cd6a6acSopenharmony_ci * the context structure `context' into a dynamically
836cd6a6acSopenharmony_ci * allocated string of the correct size.  Set `*scontext'
846cd6a6acSopenharmony_ci * to point to this string and set `*scontext_len' to
856cd6a6acSopenharmony_ci * the length of the string.
866cd6a6acSopenharmony_ci */
876cd6a6acSopenharmony_ciint context_to_string(sepol_handle_t * handle,
886cd6a6acSopenharmony_ci		      const policydb_t * policydb,
896cd6a6acSopenharmony_ci		      const context_struct_t * context,
906cd6a6acSopenharmony_ci		      char **result, size_t * result_len)
916cd6a6acSopenharmony_ci{
926cd6a6acSopenharmony_ci
936cd6a6acSopenharmony_ci	char *scontext = NULL;
946cd6a6acSopenharmony_ci	size_t scontext_len = 0;
956cd6a6acSopenharmony_ci	char *ptr;
966cd6a6acSopenharmony_ci
976cd6a6acSopenharmony_ci	/* Compute the size of the context. */
986cd6a6acSopenharmony_ci	scontext_len +=
996cd6a6acSopenharmony_ci	    strlen(policydb->p_user_val_to_name[context->user - 1]) + 1;
1006cd6a6acSopenharmony_ci	scontext_len +=
1016cd6a6acSopenharmony_ci	    strlen(policydb->p_role_val_to_name[context->role - 1]) + 1;
1026cd6a6acSopenharmony_ci	scontext_len += strlen(policydb->p_type_val_to_name[context->type - 1]);
1036cd6a6acSopenharmony_ci	scontext_len += mls_compute_context_len(policydb, context);
1046cd6a6acSopenharmony_ci
1056cd6a6acSopenharmony_ci	/* We must null terminate the string */
1066cd6a6acSopenharmony_ci	scontext_len += 1;
1076cd6a6acSopenharmony_ci
1086cd6a6acSopenharmony_ci	/* Allocate space for the context; caller must free this space. */
1096cd6a6acSopenharmony_ci	scontext = malloc(scontext_len);
1106cd6a6acSopenharmony_ci	if (!scontext)
1116cd6a6acSopenharmony_ci		goto omem;
1126cd6a6acSopenharmony_ci	scontext[scontext_len - 1] = '\0';
1136cd6a6acSopenharmony_ci
1146cd6a6acSopenharmony_ci	/*
1156cd6a6acSopenharmony_ci	 * Copy the user name, role name and type name into the context.
1166cd6a6acSopenharmony_ci	 */
1176cd6a6acSopenharmony_ci	ptr = scontext;
1186cd6a6acSopenharmony_ci	sprintf(ptr, "%s:%s:%s",
1196cd6a6acSopenharmony_ci		policydb->p_user_val_to_name[context->user - 1],
1206cd6a6acSopenharmony_ci		policydb->p_role_val_to_name[context->role - 1],
1216cd6a6acSopenharmony_ci		policydb->p_type_val_to_name[context->type - 1]);
1226cd6a6acSopenharmony_ci
1236cd6a6acSopenharmony_ci	ptr +=
1246cd6a6acSopenharmony_ci	    strlen(policydb->p_user_val_to_name[context->user - 1]) + 1 +
1256cd6a6acSopenharmony_ci	    strlen(policydb->p_role_val_to_name[context->role - 1]) + 1 +
1266cd6a6acSopenharmony_ci	    strlen(policydb->p_type_val_to_name[context->type - 1]);
1276cd6a6acSopenharmony_ci
1286cd6a6acSopenharmony_ci	mls_sid_to_context(policydb, context, &ptr);
1296cd6a6acSopenharmony_ci
1306cd6a6acSopenharmony_ci	*result = scontext;
1316cd6a6acSopenharmony_ci	*result_len = scontext_len;
1326cd6a6acSopenharmony_ci	return STATUS_SUCCESS;
1336cd6a6acSopenharmony_ci
1346cd6a6acSopenharmony_ci      omem:
1356cd6a6acSopenharmony_ci	ERR(handle, "out of memory, could not convert " "context to string");
1366cd6a6acSopenharmony_ci	free(scontext);
1376cd6a6acSopenharmony_ci	return STATUS_ERR;
1386cd6a6acSopenharmony_ci}
1396cd6a6acSopenharmony_ci
1406cd6a6acSopenharmony_ci/*
1416cd6a6acSopenharmony_ci * Create a context structure from the given record
1426cd6a6acSopenharmony_ci */
1436cd6a6acSopenharmony_ciint context_from_record(sepol_handle_t * handle,
1446cd6a6acSopenharmony_ci			const policydb_t * policydb,
1456cd6a6acSopenharmony_ci			context_struct_t ** cptr,
1466cd6a6acSopenharmony_ci			const sepol_context_t * record)
1476cd6a6acSopenharmony_ci{
1486cd6a6acSopenharmony_ci
1496cd6a6acSopenharmony_ci	context_struct_t *scontext = NULL;
1506cd6a6acSopenharmony_ci	user_datum_t *usrdatum;
1516cd6a6acSopenharmony_ci	role_datum_t *roldatum;
1526cd6a6acSopenharmony_ci	type_datum_t *typdatum;
1536cd6a6acSopenharmony_ci
1546cd6a6acSopenharmony_ci	/* Hashtab keys are not constant - suppress warnings */
1556cd6a6acSopenharmony_ci	char *user = strdup(sepol_context_get_user(record));
1566cd6a6acSopenharmony_ci	char *role = strdup(sepol_context_get_role(record));
1576cd6a6acSopenharmony_ci	char *type = strdup(sepol_context_get_type(record));
1586cd6a6acSopenharmony_ci	const char *mls = sepol_context_get_mls(record);
1596cd6a6acSopenharmony_ci
1606cd6a6acSopenharmony_ci	scontext = (context_struct_t *) malloc(sizeof(context_struct_t));
1616cd6a6acSopenharmony_ci	if (!user || !role || !type || !scontext) {
1626cd6a6acSopenharmony_ci		ERR(handle, "out of memory");
1636cd6a6acSopenharmony_ci		goto err;
1646cd6a6acSopenharmony_ci	}
1656cd6a6acSopenharmony_ci	context_init(scontext);
1666cd6a6acSopenharmony_ci
1676cd6a6acSopenharmony_ci	/* User */
1686cd6a6acSopenharmony_ci	usrdatum = (user_datum_t *) hashtab_search(policydb->p_users.table,
1696cd6a6acSopenharmony_ci						   (hashtab_key_t) user);
1706cd6a6acSopenharmony_ci	if (!usrdatum) {
1716cd6a6acSopenharmony_ci		ERR(handle, "user %s is not defined", user);
1726cd6a6acSopenharmony_ci		goto err_destroy;
1736cd6a6acSopenharmony_ci	}
1746cd6a6acSopenharmony_ci	scontext->user = usrdatum->s.value;
1756cd6a6acSopenharmony_ci
1766cd6a6acSopenharmony_ci	/* Role */
1776cd6a6acSopenharmony_ci	roldatum = (role_datum_t *) hashtab_search(policydb->p_roles.table,
1786cd6a6acSopenharmony_ci						   (hashtab_key_t) role);
1796cd6a6acSopenharmony_ci	if (!roldatum) {
1806cd6a6acSopenharmony_ci		ERR(handle, "role %s is not defined", role);
1816cd6a6acSopenharmony_ci		goto err_destroy;
1826cd6a6acSopenharmony_ci	}
1836cd6a6acSopenharmony_ci	scontext->role = roldatum->s.value;
1846cd6a6acSopenharmony_ci
1856cd6a6acSopenharmony_ci	/* Type */
1866cd6a6acSopenharmony_ci	typdatum = (type_datum_t *) hashtab_search(policydb->p_types.table,
1876cd6a6acSopenharmony_ci						   (hashtab_key_t) type);
1886cd6a6acSopenharmony_ci	if (!typdatum || typdatum->flavor == TYPE_ATTRIB) {
1896cd6a6acSopenharmony_ci		ERR(handle, "type %s is not defined", type);
1906cd6a6acSopenharmony_ci		goto err_destroy;
1916cd6a6acSopenharmony_ci	}
1926cd6a6acSopenharmony_ci	scontext->type = typdatum->s.value;
1936cd6a6acSopenharmony_ci
1946cd6a6acSopenharmony_ci	/* MLS */
1956cd6a6acSopenharmony_ci	if (mls && !policydb->mls) {
1966cd6a6acSopenharmony_ci		ERR(handle, "MLS is disabled, but MLS context \"%s\" found",
1976cd6a6acSopenharmony_ci		    mls);
1986cd6a6acSopenharmony_ci		goto err_destroy;
1996cd6a6acSopenharmony_ci	} else if (!mls && policydb->mls) {
2006cd6a6acSopenharmony_ci		ERR(handle, "MLS is enabled, but no MLS context found");
2016cd6a6acSopenharmony_ci		goto err_destroy;
2026cd6a6acSopenharmony_ci	}
2036cd6a6acSopenharmony_ci	if (mls && (mls_from_string(handle, policydb, mls, scontext) < 0))
2046cd6a6acSopenharmony_ci		goto err_destroy;
2056cd6a6acSopenharmony_ci
2066cd6a6acSopenharmony_ci	/* Validity check */
2076cd6a6acSopenharmony_ci	if (!context_is_valid(policydb, scontext)) {
2086cd6a6acSopenharmony_ci		if (mls) {
2096cd6a6acSopenharmony_ci			ERR(handle,
2106cd6a6acSopenharmony_ci			    "invalid security context: \"%s:%s:%s:%s\"",
2116cd6a6acSopenharmony_ci			    user, role, type, mls);
2126cd6a6acSopenharmony_ci		} else {
2136cd6a6acSopenharmony_ci			ERR(handle,
2146cd6a6acSopenharmony_ci			    "invalid security context: \"%s:%s:%s\"",
2156cd6a6acSopenharmony_ci			    user, role, type);
2166cd6a6acSopenharmony_ci		}
2176cd6a6acSopenharmony_ci		goto err_destroy;
2186cd6a6acSopenharmony_ci	}
2196cd6a6acSopenharmony_ci
2206cd6a6acSopenharmony_ci	*cptr = scontext;
2216cd6a6acSopenharmony_ci	free(user);
2226cd6a6acSopenharmony_ci	free(type);
2236cd6a6acSopenharmony_ci	free(role);
2246cd6a6acSopenharmony_ci	return STATUS_SUCCESS;
2256cd6a6acSopenharmony_ci
2266cd6a6acSopenharmony_ci      err_destroy:
2276cd6a6acSopenharmony_ci	errno = EINVAL;
2286cd6a6acSopenharmony_ci	context_destroy(scontext);
2296cd6a6acSopenharmony_ci
2306cd6a6acSopenharmony_ci      err:
2316cd6a6acSopenharmony_ci	free(scontext);
2326cd6a6acSopenharmony_ci	free(user);
2336cd6a6acSopenharmony_ci	free(type);
2346cd6a6acSopenharmony_ci	free(role);
2356cd6a6acSopenharmony_ci	ERR(handle, "could not create context structure");
2366cd6a6acSopenharmony_ci	return STATUS_ERR;
2376cd6a6acSopenharmony_ci}
2386cd6a6acSopenharmony_ci
2396cd6a6acSopenharmony_ci/*
2406cd6a6acSopenharmony_ci * Create a record from the given context structure
2416cd6a6acSopenharmony_ci */
2426cd6a6acSopenharmony_ciint context_to_record(sepol_handle_t * handle,
2436cd6a6acSopenharmony_ci		      const policydb_t * policydb,
2446cd6a6acSopenharmony_ci		      const context_struct_t * context,
2456cd6a6acSopenharmony_ci		      sepol_context_t ** record)
2466cd6a6acSopenharmony_ci{
2476cd6a6acSopenharmony_ci
2486cd6a6acSopenharmony_ci	sepol_context_t *tmp_record = NULL;
2496cd6a6acSopenharmony_ci	char *mls = NULL;
2506cd6a6acSopenharmony_ci
2516cd6a6acSopenharmony_ci	if (sepol_context_create(handle, &tmp_record) < 0)
2526cd6a6acSopenharmony_ci		goto err;
2536cd6a6acSopenharmony_ci
2546cd6a6acSopenharmony_ci	if (sepol_context_set_user(handle, tmp_record,
2556cd6a6acSopenharmony_ci				   policydb->p_user_val_to_name[context->user -
2566cd6a6acSopenharmony_ci								1]) < 0)
2576cd6a6acSopenharmony_ci		goto err;
2586cd6a6acSopenharmony_ci
2596cd6a6acSopenharmony_ci	if (sepol_context_set_role(handle, tmp_record,
2606cd6a6acSopenharmony_ci				   policydb->p_role_val_to_name[context->role -
2616cd6a6acSopenharmony_ci								1]) < 0)
2626cd6a6acSopenharmony_ci		goto err;
2636cd6a6acSopenharmony_ci
2646cd6a6acSopenharmony_ci	if (sepol_context_set_type(handle, tmp_record,
2656cd6a6acSopenharmony_ci				   policydb->p_type_val_to_name[context->type -
2666cd6a6acSopenharmony_ci								1]) < 0)
2676cd6a6acSopenharmony_ci		goto err;
2686cd6a6acSopenharmony_ci
2696cd6a6acSopenharmony_ci	if (policydb->mls) {
2706cd6a6acSopenharmony_ci		if (mls_to_string(handle, policydb, context, &mls) < 0)
2716cd6a6acSopenharmony_ci			goto err;
2726cd6a6acSopenharmony_ci
2736cd6a6acSopenharmony_ci		if (sepol_context_set_mls(handle, tmp_record, mls) < 0)
2746cd6a6acSopenharmony_ci			goto err;
2756cd6a6acSopenharmony_ci	}
2766cd6a6acSopenharmony_ci
2776cd6a6acSopenharmony_ci	free(mls);
2786cd6a6acSopenharmony_ci	*record = tmp_record;
2796cd6a6acSopenharmony_ci	return STATUS_SUCCESS;
2806cd6a6acSopenharmony_ci
2816cd6a6acSopenharmony_ci      err:
2826cd6a6acSopenharmony_ci	ERR(handle, "could not create context record");
2836cd6a6acSopenharmony_ci	sepol_context_free(tmp_record);
2846cd6a6acSopenharmony_ci	free(mls);
2856cd6a6acSopenharmony_ci	return STATUS_ERR;
2866cd6a6acSopenharmony_ci}
2876cd6a6acSopenharmony_ci
2886cd6a6acSopenharmony_ci/*
2896cd6a6acSopenharmony_ci * Create a context structure from the provided string.
2906cd6a6acSopenharmony_ci */
2916cd6a6acSopenharmony_ciint context_from_string(sepol_handle_t * handle,
2926cd6a6acSopenharmony_ci			const policydb_t * policydb,
2936cd6a6acSopenharmony_ci			context_struct_t ** cptr,
2946cd6a6acSopenharmony_ci			const char *con_str, size_t con_str_len)
2956cd6a6acSopenharmony_ci{
2966cd6a6acSopenharmony_ci
2976cd6a6acSopenharmony_ci	char *con_cpy = NULL;
2986cd6a6acSopenharmony_ci	sepol_context_t *ctx_record = NULL;
2996cd6a6acSopenharmony_ci
3006cd6a6acSopenharmony_ci	if (zero_or_saturated(con_str_len)) {
3016cd6a6acSopenharmony_ci		ERR(handle, "Invalid context length");
3026cd6a6acSopenharmony_ci		goto err;
3036cd6a6acSopenharmony_ci	}
3046cd6a6acSopenharmony_ci
3056cd6a6acSopenharmony_ci	/* sepol_context_from_string expects a NULL-terminated string */
3066cd6a6acSopenharmony_ci	con_cpy = malloc(con_str_len + 1);
3076cd6a6acSopenharmony_ci	if (!con_cpy) {
3086cd6a6acSopenharmony_ci		ERR(handle, "out of memory");
3096cd6a6acSopenharmony_ci		goto err;
3106cd6a6acSopenharmony_ci	}
3116cd6a6acSopenharmony_ci
3126cd6a6acSopenharmony_ci	memcpy(con_cpy, con_str, con_str_len);
3136cd6a6acSopenharmony_ci	con_cpy[con_str_len] = '\0';
3146cd6a6acSopenharmony_ci
3156cd6a6acSopenharmony_ci	if (sepol_context_from_string(handle, con_cpy, &ctx_record) < 0)
3166cd6a6acSopenharmony_ci		goto err;
3176cd6a6acSopenharmony_ci
3186cd6a6acSopenharmony_ci	/* Now create from the data structure */
3196cd6a6acSopenharmony_ci	if (context_from_record(handle, policydb, cptr, ctx_record) < 0)
3206cd6a6acSopenharmony_ci		goto err;
3216cd6a6acSopenharmony_ci
3226cd6a6acSopenharmony_ci	free(con_cpy);
3236cd6a6acSopenharmony_ci	sepol_context_free(ctx_record);
3246cd6a6acSopenharmony_ci	return STATUS_SUCCESS;
3256cd6a6acSopenharmony_ci
3266cd6a6acSopenharmony_ci      err:
3276cd6a6acSopenharmony_ci	ERR(handle, "could not create context structure");
3286cd6a6acSopenharmony_ci	free(con_cpy);
3296cd6a6acSopenharmony_ci	sepol_context_free(ctx_record);
3306cd6a6acSopenharmony_ci	return STATUS_ERR;
3316cd6a6acSopenharmony_ci}
3326cd6a6acSopenharmony_ci
3336cd6a6acSopenharmony_ciint sepol_context_check(sepol_handle_t * handle,
3346cd6a6acSopenharmony_ci			const sepol_policydb_t * policydb,
3356cd6a6acSopenharmony_ci			const sepol_context_t * context)
3366cd6a6acSopenharmony_ci{
3376cd6a6acSopenharmony_ci
3386cd6a6acSopenharmony_ci	context_struct_t *con = NULL;
3396cd6a6acSopenharmony_ci	int ret = context_from_record(handle, &policydb->p, &con, context);
3406cd6a6acSopenharmony_ci	context_destroy(con);
3416cd6a6acSopenharmony_ci	free(con);
3426cd6a6acSopenharmony_ci	return ret;
3436cd6a6acSopenharmony_ci}
344