16cd6a6acSopenharmony_ci#include <errno.h>
26cd6a6acSopenharmony_ci#include <stdlib.h>
36cd6a6acSopenharmony_ci#include <string.h>
46cd6a6acSopenharmony_ci#include <stdio.h>
56cd6a6acSopenharmony_ci
66cd6a6acSopenharmony_ci#include "context_internal.h"
76cd6a6acSopenharmony_ci#include "debug.h"
86cd6a6acSopenharmony_ci#include "private.h"
96cd6a6acSopenharmony_ci
106cd6a6acSopenharmony_cistruct sepol_context {
116cd6a6acSopenharmony_ci
126cd6a6acSopenharmony_ci	/* Selinux user */
136cd6a6acSopenharmony_ci	char *user;
146cd6a6acSopenharmony_ci
156cd6a6acSopenharmony_ci	/* Selinux role */
166cd6a6acSopenharmony_ci	char *role;
176cd6a6acSopenharmony_ci
186cd6a6acSopenharmony_ci	/* Selinux type */
196cd6a6acSopenharmony_ci	char *type;
206cd6a6acSopenharmony_ci
216cd6a6acSopenharmony_ci	/* MLS */
226cd6a6acSopenharmony_ci	char *mls;
236cd6a6acSopenharmony_ci};
246cd6a6acSopenharmony_ci
256cd6a6acSopenharmony_ci/* User */
266cd6a6acSopenharmony_ciconst char *sepol_context_get_user(const sepol_context_t * con)
276cd6a6acSopenharmony_ci{
286cd6a6acSopenharmony_ci
296cd6a6acSopenharmony_ci	return con->user;
306cd6a6acSopenharmony_ci}
316cd6a6acSopenharmony_ci
326cd6a6acSopenharmony_ci
336cd6a6acSopenharmony_ciint sepol_context_set_user(sepol_handle_t * handle,
346cd6a6acSopenharmony_ci			   sepol_context_t * con, const char *user)
356cd6a6acSopenharmony_ci{
366cd6a6acSopenharmony_ci
376cd6a6acSopenharmony_ci	char *tmp_user = strdup(user);
386cd6a6acSopenharmony_ci	if (!tmp_user) {
396cd6a6acSopenharmony_ci		ERR(handle, "out of memory, could not set "
406cd6a6acSopenharmony_ci		    "context user to %s", user);
416cd6a6acSopenharmony_ci		return STATUS_ERR;
426cd6a6acSopenharmony_ci	}
436cd6a6acSopenharmony_ci
446cd6a6acSopenharmony_ci	free(con->user);
456cd6a6acSopenharmony_ci	con->user = tmp_user;
466cd6a6acSopenharmony_ci	return STATUS_SUCCESS;
476cd6a6acSopenharmony_ci}
486cd6a6acSopenharmony_ci
496cd6a6acSopenharmony_ci
506cd6a6acSopenharmony_ci/* Role */
516cd6a6acSopenharmony_ciconst char *sepol_context_get_role(const sepol_context_t * con)
526cd6a6acSopenharmony_ci{
536cd6a6acSopenharmony_ci
546cd6a6acSopenharmony_ci	return con->role;
556cd6a6acSopenharmony_ci}
566cd6a6acSopenharmony_ci
576cd6a6acSopenharmony_ci
586cd6a6acSopenharmony_ciint sepol_context_set_role(sepol_handle_t * handle,
596cd6a6acSopenharmony_ci			   sepol_context_t * con, const char *role)
606cd6a6acSopenharmony_ci{
616cd6a6acSopenharmony_ci
626cd6a6acSopenharmony_ci	char *tmp_role = strdup(role);
636cd6a6acSopenharmony_ci	if (!tmp_role) {
646cd6a6acSopenharmony_ci		ERR(handle, "out of memory, could not set "
656cd6a6acSopenharmony_ci		    "context role to %s", role);
666cd6a6acSopenharmony_ci		return STATUS_ERR;
676cd6a6acSopenharmony_ci	}
686cd6a6acSopenharmony_ci	free(con->role);
696cd6a6acSopenharmony_ci	con->role = tmp_role;
706cd6a6acSopenharmony_ci	return STATUS_SUCCESS;
716cd6a6acSopenharmony_ci}
726cd6a6acSopenharmony_ci
736cd6a6acSopenharmony_ci
746cd6a6acSopenharmony_ci/* Type */
756cd6a6acSopenharmony_ciconst char *sepol_context_get_type(const sepol_context_t * con)
766cd6a6acSopenharmony_ci{
776cd6a6acSopenharmony_ci
786cd6a6acSopenharmony_ci	return con->type;
796cd6a6acSopenharmony_ci}
806cd6a6acSopenharmony_ci
816cd6a6acSopenharmony_ci
826cd6a6acSopenharmony_ciint sepol_context_set_type(sepol_handle_t * handle,
836cd6a6acSopenharmony_ci			   sepol_context_t * con, const char *type)
846cd6a6acSopenharmony_ci{
856cd6a6acSopenharmony_ci
866cd6a6acSopenharmony_ci	char *tmp_type = strdup(type);
876cd6a6acSopenharmony_ci	if (!tmp_type) {
886cd6a6acSopenharmony_ci		ERR(handle, "out of memory, could not set "
896cd6a6acSopenharmony_ci		    "context type to %s", type);
906cd6a6acSopenharmony_ci		return STATUS_ERR;
916cd6a6acSopenharmony_ci	}
926cd6a6acSopenharmony_ci	free(con->type);
936cd6a6acSopenharmony_ci	con->type = tmp_type;
946cd6a6acSopenharmony_ci	return STATUS_SUCCESS;
956cd6a6acSopenharmony_ci}
966cd6a6acSopenharmony_ci
976cd6a6acSopenharmony_ci
986cd6a6acSopenharmony_ci/* MLS */
996cd6a6acSopenharmony_ciconst char *sepol_context_get_mls(const sepol_context_t * con)
1006cd6a6acSopenharmony_ci{
1016cd6a6acSopenharmony_ci
1026cd6a6acSopenharmony_ci	return con->mls;
1036cd6a6acSopenharmony_ci}
1046cd6a6acSopenharmony_ci
1056cd6a6acSopenharmony_ci
1066cd6a6acSopenharmony_ciint sepol_context_set_mls(sepol_handle_t * handle,
1076cd6a6acSopenharmony_ci			  sepol_context_t * con, const char *mls)
1086cd6a6acSopenharmony_ci{
1096cd6a6acSopenharmony_ci
1106cd6a6acSopenharmony_ci	char *tmp_mls = strdup(mls);
1116cd6a6acSopenharmony_ci	if (!tmp_mls) {
1126cd6a6acSopenharmony_ci		ERR(handle, "out of memory, could not set "
1136cd6a6acSopenharmony_ci		    "MLS fields to %s", mls);
1146cd6a6acSopenharmony_ci		return STATUS_ERR;
1156cd6a6acSopenharmony_ci	}
1166cd6a6acSopenharmony_ci	free(con->mls);
1176cd6a6acSopenharmony_ci	con->mls = tmp_mls;
1186cd6a6acSopenharmony_ci	return STATUS_SUCCESS;
1196cd6a6acSopenharmony_ci}
1206cd6a6acSopenharmony_ci
1216cd6a6acSopenharmony_ci
1226cd6a6acSopenharmony_ci/* Create */
1236cd6a6acSopenharmony_ciint sepol_context_create(sepol_handle_t * handle, sepol_context_t ** con_ptr)
1246cd6a6acSopenharmony_ci{
1256cd6a6acSopenharmony_ci
1266cd6a6acSopenharmony_ci	sepol_context_t *con =
1276cd6a6acSopenharmony_ci	    (sepol_context_t *) malloc(sizeof(sepol_context_t));
1286cd6a6acSopenharmony_ci
1296cd6a6acSopenharmony_ci	if (!con) {
1306cd6a6acSopenharmony_ci		ERR(handle, "out of memory, could not create context");
1316cd6a6acSopenharmony_ci		return STATUS_ERR;
1326cd6a6acSopenharmony_ci	}
1336cd6a6acSopenharmony_ci
1346cd6a6acSopenharmony_ci	con->user = NULL;
1356cd6a6acSopenharmony_ci	con->role = NULL;
1366cd6a6acSopenharmony_ci	con->type = NULL;
1376cd6a6acSopenharmony_ci	con->mls = NULL;
1386cd6a6acSopenharmony_ci	*con_ptr = con;
1396cd6a6acSopenharmony_ci	return STATUS_SUCCESS;
1406cd6a6acSopenharmony_ci}
1416cd6a6acSopenharmony_ci
1426cd6a6acSopenharmony_ci
1436cd6a6acSopenharmony_ci/* Deep copy clone */
1446cd6a6acSopenharmony_ciint sepol_context_clone(sepol_handle_t * handle,
1456cd6a6acSopenharmony_ci			const sepol_context_t * con, sepol_context_t ** con_ptr)
1466cd6a6acSopenharmony_ci{
1476cd6a6acSopenharmony_ci
1486cd6a6acSopenharmony_ci	sepol_context_t *new_con = NULL;
1496cd6a6acSopenharmony_ci
1506cd6a6acSopenharmony_ci	if (!con) {
1516cd6a6acSopenharmony_ci		*con_ptr = NULL;
1526cd6a6acSopenharmony_ci		return 0;
1536cd6a6acSopenharmony_ci	}
1546cd6a6acSopenharmony_ci
1556cd6a6acSopenharmony_ci	if (sepol_context_create(handle, &new_con) < 0)
1566cd6a6acSopenharmony_ci		goto err;
1576cd6a6acSopenharmony_ci
1586cd6a6acSopenharmony_ci	if (!(new_con->user = strdup(con->user)))
1596cd6a6acSopenharmony_ci		goto omem;
1606cd6a6acSopenharmony_ci
1616cd6a6acSopenharmony_ci	if (!(new_con->role = strdup(con->role)))
1626cd6a6acSopenharmony_ci		goto omem;
1636cd6a6acSopenharmony_ci
1646cd6a6acSopenharmony_ci	if (!(new_con->type = strdup(con->type)))
1656cd6a6acSopenharmony_ci		goto omem;
1666cd6a6acSopenharmony_ci
1676cd6a6acSopenharmony_ci	if (con->mls && !(new_con->mls = strdup(con->mls)))
1686cd6a6acSopenharmony_ci		goto omem;
1696cd6a6acSopenharmony_ci
1706cd6a6acSopenharmony_ci	*con_ptr = new_con;
1716cd6a6acSopenharmony_ci	return STATUS_SUCCESS;
1726cd6a6acSopenharmony_ci
1736cd6a6acSopenharmony_ci      omem:
1746cd6a6acSopenharmony_ci	ERR(handle, "out of memory");
1756cd6a6acSopenharmony_ci
1766cd6a6acSopenharmony_ci      err:
1776cd6a6acSopenharmony_ci	ERR(handle, "could not clone context record");
1786cd6a6acSopenharmony_ci	sepol_context_free(new_con);
1796cd6a6acSopenharmony_ci	return STATUS_ERR;
1806cd6a6acSopenharmony_ci}
1816cd6a6acSopenharmony_ci
1826cd6a6acSopenharmony_ci
1836cd6a6acSopenharmony_ci/* Destroy */
1846cd6a6acSopenharmony_civoid sepol_context_free(sepol_context_t * con)
1856cd6a6acSopenharmony_ci{
1866cd6a6acSopenharmony_ci
1876cd6a6acSopenharmony_ci	if (!con)
1886cd6a6acSopenharmony_ci		return;
1896cd6a6acSopenharmony_ci
1906cd6a6acSopenharmony_ci	free(con->user);
1916cd6a6acSopenharmony_ci	free(con->role);
1926cd6a6acSopenharmony_ci	free(con->type);
1936cd6a6acSopenharmony_ci	free(con->mls);
1946cd6a6acSopenharmony_ci	free(con);
1956cd6a6acSopenharmony_ci}
1966cd6a6acSopenharmony_ci
1976cd6a6acSopenharmony_ci
1986cd6a6acSopenharmony_ciint sepol_context_from_string(sepol_handle_t * handle,
1996cd6a6acSopenharmony_ci			      const char *str, sepol_context_t ** con)
2006cd6a6acSopenharmony_ci{
2016cd6a6acSopenharmony_ci
2026cd6a6acSopenharmony_ci	char *tmp = NULL, *low, *high;
2036cd6a6acSopenharmony_ci	sepol_context_t *tmp_con = NULL;
2046cd6a6acSopenharmony_ci
2056cd6a6acSopenharmony_ci	if (!strcmp(str, "<<none>>")) {
2066cd6a6acSopenharmony_ci		*con = NULL;
2076cd6a6acSopenharmony_ci		return STATUS_SUCCESS;
2086cd6a6acSopenharmony_ci	}
2096cd6a6acSopenharmony_ci
2106cd6a6acSopenharmony_ci	if (sepol_context_create(handle, &tmp_con) < 0)
2116cd6a6acSopenharmony_ci		goto err;
2126cd6a6acSopenharmony_ci
2136cd6a6acSopenharmony_ci	/* Working copy context */
2146cd6a6acSopenharmony_ci	tmp = strdup(str);
2156cd6a6acSopenharmony_ci	if (!tmp) {
2166cd6a6acSopenharmony_ci		ERR(handle, "out of memory");
2176cd6a6acSopenharmony_ci		goto err;
2186cd6a6acSopenharmony_ci	}
2196cd6a6acSopenharmony_ci	low = tmp;
2206cd6a6acSopenharmony_ci
2216cd6a6acSopenharmony_ci	/* Then, break it into its components */
2226cd6a6acSopenharmony_ci
2236cd6a6acSopenharmony_ci	/* User */
2246cd6a6acSopenharmony_ci	if (!(high = strchr(low, ':')))
2256cd6a6acSopenharmony_ci		goto mcontext;
2266cd6a6acSopenharmony_ci	else
2276cd6a6acSopenharmony_ci		*high++ = '\0';
2286cd6a6acSopenharmony_ci	if (sepol_context_set_user(handle, tmp_con, low) < 0)
2296cd6a6acSopenharmony_ci		goto err;
2306cd6a6acSopenharmony_ci	low = high;
2316cd6a6acSopenharmony_ci
2326cd6a6acSopenharmony_ci	/* Role */
2336cd6a6acSopenharmony_ci	if (!(high = strchr(low, ':')))
2346cd6a6acSopenharmony_ci		goto mcontext;
2356cd6a6acSopenharmony_ci	else
2366cd6a6acSopenharmony_ci		*high++ = '\0';
2376cd6a6acSopenharmony_ci	if (sepol_context_set_role(handle, tmp_con, low) < 0)
2386cd6a6acSopenharmony_ci		goto err;
2396cd6a6acSopenharmony_ci	low = high;
2406cd6a6acSopenharmony_ci
2416cd6a6acSopenharmony_ci	/* Type, and possibly MLS */
2426cd6a6acSopenharmony_ci	if (!(high = strchr(low, ':'))) {
2436cd6a6acSopenharmony_ci		if (sepol_context_set_type(handle, tmp_con, low) < 0)
2446cd6a6acSopenharmony_ci			goto err;
2456cd6a6acSopenharmony_ci	} else {
2466cd6a6acSopenharmony_ci		*high++ = '\0';
2476cd6a6acSopenharmony_ci		if (sepol_context_set_type(handle, tmp_con, low) < 0)
2486cd6a6acSopenharmony_ci			goto err;
2496cd6a6acSopenharmony_ci		low = high;
2506cd6a6acSopenharmony_ci		if (sepol_context_set_mls(handle, tmp_con, low) < 0)
2516cd6a6acSopenharmony_ci			goto err;
2526cd6a6acSopenharmony_ci	}
2536cd6a6acSopenharmony_ci
2546cd6a6acSopenharmony_ci	free(tmp);
2556cd6a6acSopenharmony_ci	*con = tmp_con;
2566cd6a6acSopenharmony_ci
2576cd6a6acSopenharmony_ci	return STATUS_SUCCESS;
2586cd6a6acSopenharmony_ci
2596cd6a6acSopenharmony_ci      mcontext:
2606cd6a6acSopenharmony_ci	errno = EINVAL;
2616cd6a6acSopenharmony_ci	ERR(handle, "malformed context \"%s\"", str);
2626cd6a6acSopenharmony_ci
2636cd6a6acSopenharmony_ci      err:
2646cd6a6acSopenharmony_ci	ERR(handle, "could not construct context from string");
2656cd6a6acSopenharmony_ci	free(tmp);
2666cd6a6acSopenharmony_ci	sepol_context_free(tmp_con);
2676cd6a6acSopenharmony_ci	return STATUS_ERR;
2686cd6a6acSopenharmony_ci}
2696cd6a6acSopenharmony_ci
2706cd6a6acSopenharmony_ciint sepol_context_to_string(sepol_handle_t * handle,
2716cd6a6acSopenharmony_ci			    const sepol_context_t * con, char **str_ptr)
2726cd6a6acSopenharmony_ci{
2736cd6a6acSopenharmony_ci
2746cd6a6acSopenharmony_ci	int rc;
2756cd6a6acSopenharmony_ci	char *str = NULL;
2766cd6a6acSopenharmony_ci	size_t total_sz = 0, i;
2776cd6a6acSopenharmony_ci	const size_t sizes[] = {
2786cd6a6acSopenharmony_ci			strlen(con->user),                 /* user length */
2796cd6a6acSopenharmony_ci			strlen(con->role),                 /* role length */
2806cd6a6acSopenharmony_ci			strlen(con->type),                 /* type length */
2816cd6a6acSopenharmony_ci			(con->mls) ? strlen(con->mls) : 0, /* mls length */
2826cd6a6acSopenharmony_ci			((con->mls) ? 3 : 2) + 1           /* mls has extra ":" also null byte */
2836cd6a6acSopenharmony_ci	};
2846cd6a6acSopenharmony_ci
2856cd6a6acSopenharmony_ci	for (i = 0; i < ARRAY_SIZE(sizes); i++) {
2866cd6a6acSopenharmony_ci		if (__builtin_add_overflow(total_sz, sizes[i], &total_sz)) {
2876cd6a6acSopenharmony_ci			ERR(handle, "invalid size, overflow at position: %zu", i);
2886cd6a6acSopenharmony_ci			goto err;
2896cd6a6acSopenharmony_ci		}
2906cd6a6acSopenharmony_ci	}
2916cd6a6acSopenharmony_ci
2926cd6a6acSopenharmony_ci	str = (char *)malloc(total_sz);
2936cd6a6acSopenharmony_ci	if (!str) {
2946cd6a6acSopenharmony_ci		ERR(handle, "out of memory");
2956cd6a6acSopenharmony_ci		goto err;
2966cd6a6acSopenharmony_ci	}
2976cd6a6acSopenharmony_ci	if (con->mls) {
2986cd6a6acSopenharmony_ci		rc = snprintf(str, total_sz, "%s:%s:%s:%s",
2996cd6a6acSopenharmony_ci			      con->user, con->role, con->type, con->mls);
3006cd6a6acSopenharmony_ci	} else {
3016cd6a6acSopenharmony_ci		rc = snprintf(str, total_sz, "%s:%s:%s",
3026cd6a6acSopenharmony_ci			      con->user, con->role, con->type);
3036cd6a6acSopenharmony_ci	}
3046cd6a6acSopenharmony_ci
3056cd6a6acSopenharmony_ci	/*
3066cd6a6acSopenharmony_ci	 * rc is >= 0 on the size_t cast and is safe to promote
3076cd6a6acSopenharmony_ci	 * to an unsigned value.
3086cd6a6acSopenharmony_ci	 */
3096cd6a6acSopenharmony_ci	if (rc < 0 || (size_t)rc >= total_sz) {
3106cd6a6acSopenharmony_ci		ERR(handle, "print error");
3116cd6a6acSopenharmony_ci		goto err;
3126cd6a6acSopenharmony_ci	}
3136cd6a6acSopenharmony_ci
3146cd6a6acSopenharmony_ci	*str_ptr = str;
3156cd6a6acSopenharmony_ci	return STATUS_SUCCESS;
3166cd6a6acSopenharmony_ci
3176cd6a6acSopenharmony_ci      err:
3186cd6a6acSopenharmony_ci	ERR(handle, "could not convert context to string");
3196cd6a6acSopenharmony_ci	free(str);
3206cd6a6acSopenharmony_ci	return STATUS_ERR;
3216cd6a6acSopenharmony_ci}
322