16cd6a6acSopenharmony_ci#include "context_internal.h"
26cd6a6acSopenharmony_ci#include <string.h>
36cd6a6acSopenharmony_ci#include <stdio.h>
46cd6a6acSopenharmony_ci#include <stdlib.h>
56cd6a6acSopenharmony_ci#include <errno.h>
66cd6a6acSopenharmony_ci
76cd6a6acSopenharmony_ci#define COMP_USER  0
86cd6a6acSopenharmony_ci#define COMP_ROLE  1
96cd6a6acSopenharmony_ci#define COMP_TYPE  2
106cd6a6acSopenharmony_ci#define COMP_RANGE 3
116cd6a6acSopenharmony_ci
126cd6a6acSopenharmony_citypedef struct {
136cd6a6acSopenharmony_ci	char *current_str;	/* This is made up-to-date only when needed */
146cd6a6acSopenharmony_ci	char *(component[4]);
156cd6a6acSopenharmony_ci} context_private_t;
166cd6a6acSopenharmony_ci
176cd6a6acSopenharmony_ci/*
186cd6a6acSopenharmony_ci * Allocate a new context, initialized from str.  There must be 3 or
196cd6a6acSopenharmony_ci * 4 colon-separated components and no whitespace in any component other
206cd6a6acSopenharmony_ci * than the MLS component.
216cd6a6acSopenharmony_ci */
226cd6a6acSopenharmony_cicontext_t context_new(const char *str)
236cd6a6acSopenharmony_ci{
246cd6a6acSopenharmony_ci	int i, count;
256cd6a6acSopenharmony_ci	errno = 0;
266cd6a6acSopenharmony_ci	context_private_t *n =
276cd6a6acSopenharmony_ci	    (context_private_t *) malloc(sizeof(context_private_t));
286cd6a6acSopenharmony_ci	context_t result = (context_t) malloc(sizeof(context_s_t));
296cd6a6acSopenharmony_ci	const char *p, *tok;
306cd6a6acSopenharmony_ci
316cd6a6acSopenharmony_ci	if (result)
326cd6a6acSopenharmony_ci		result->ptr = n;
336cd6a6acSopenharmony_ci	else
346cd6a6acSopenharmony_ci		free(n);
356cd6a6acSopenharmony_ci	if (n == 0 || result == 0) {
366cd6a6acSopenharmony_ci		goto err;
376cd6a6acSopenharmony_ci	}
386cd6a6acSopenharmony_ci	n->current_str = n->component[0] = n->component[1] = n->component[2] =
396cd6a6acSopenharmony_ci	    n->component[3] = 0;
406cd6a6acSopenharmony_ci	for (count = 0, p = str; *p; p++) {
416cd6a6acSopenharmony_ci		switch (*p) {
426cd6a6acSopenharmony_ci		case ':':
436cd6a6acSopenharmony_ci			count++;
446cd6a6acSopenharmony_ci			break;
456cd6a6acSopenharmony_ci		case '\n':
466cd6a6acSopenharmony_ci		case '\t':
476cd6a6acSopenharmony_ci		case '\r':
486cd6a6acSopenharmony_ci			goto err;	/* sanity check */
496cd6a6acSopenharmony_ci		case ' ':
506cd6a6acSopenharmony_ci			if (count < 3)
516cd6a6acSopenharmony_ci				goto err;	/* sanity check */
526cd6a6acSopenharmony_ci		}
536cd6a6acSopenharmony_ci	}
546cd6a6acSopenharmony_ci	/*
556cd6a6acSopenharmony_ci	 * Could be anywhere from 2 - 5
566cd6a6acSopenharmony_ci	 * e.g user:role:type to user:role:type:sens1:cata-sens2:catb
576cd6a6acSopenharmony_ci	 */
586cd6a6acSopenharmony_ci	if (count < 2 || count > 5) {	/* might not have a range */
596cd6a6acSopenharmony_ci		goto err;
606cd6a6acSopenharmony_ci	}
616cd6a6acSopenharmony_ci
626cd6a6acSopenharmony_ci	n->component[3] = 0;
636cd6a6acSopenharmony_ci	for (i = 0, tok = str; *tok; i++) {
646cd6a6acSopenharmony_ci		if (i < 3)
656cd6a6acSopenharmony_ci			for (p = tok; *p && *p != ':'; p++) {	/* empty */
666cd6a6acSopenharmony_ci		} else {
676cd6a6acSopenharmony_ci			/* MLS range is one component */
686cd6a6acSopenharmony_ci			for (p = tok; *p; p++) {	/* empty */
696cd6a6acSopenharmony_ci			}
706cd6a6acSopenharmony_ci		}
716cd6a6acSopenharmony_ci		n->component[i] = strndup(tok, p - tok);
726cd6a6acSopenharmony_ci		if (n->component[i] == 0)
736cd6a6acSopenharmony_ci			goto err;
746cd6a6acSopenharmony_ci		tok = *p ? p + 1 : p;
756cd6a6acSopenharmony_ci	}
766cd6a6acSopenharmony_ci	return result;
776cd6a6acSopenharmony_ci      err:
786cd6a6acSopenharmony_ci	if (errno == 0) errno = EINVAL;
796cd6a6acSopenharmony_ci	context_free(result);
806cd6a6acSopenharmony_ci	return 0;
816cd6a6acSopenharmony_ci}
826cd6a6acSopenharmony_ci
836cd6a6acSopenharmony_ci
846cd6a6acSopenharmony_cistatic void conditional_free(char **v)
856cd6a6acSopenharmony_ci{
866cd6a6acSopenharmony_ci	if (*v) {
876cd6a6acSopenharmony_ci		free(*v);
886cd6a6acSopenharmony_ci	}
896cd6a6acSopenharmony_ci	*v = 0;
906cd6a6acSopenharmony_ci}
916cd6a6acSopenharmony_ci
926cd6a6acSopenharmony_ci/*
936cd6a6acSopenharmony_ci * free all storage used by a context.  Safe to call with
946cd6a6acSopenharmony_ci * null pointer.
956cd6a6acSopenharmony_ci */
966cd6a6acSopenharmony_civoid context_free(context_t context)
976cd6a6acSopenharmony_ci{
986cd6a6acSopenharmony_ci	context_private_t *n;
996cd6a6acSopenharmony_ci	int i;
1006cd6a6acSopenharmony_ci	if (context) {
1016cd6a6acSopenharmony_ci		n = context->ptr;
1026cd6a6acSopenharmony_ci		if (n) {
1036cd6a6acSopenharmony_ci			conditional_free(&n->current_str);
1046cd6a6acSopenharmony_ci			for (i = 0; i < 4; i++) {
1056cd6a6acSopenharmony_ci				conditional_free(&n->component[i]);
1066cd6a6acSopenharmony_ci			}
1076cd6a6acSopenharmony_ci			free(n);
1086cd6a6acSopenharmony_ci		}
1096cd6a6acSopenharmony_ci		free(context);
1106cd6a6acSopenharmony_ci	}
1116cd6a6acSopenharmony_ci}
1126cd6a6acSopenharmony_ci
1136cd6a6acSopenharmony_ci
1146cd6a6acSopenharmony_ci/*
1156cd6a6acSopenharmony_ci * Return a pointer to the string value of the context.
1166cd6a6acSopenharmony_ci */
1176cd6a6acSopenharmony_ciconst char *context_str(context_t context)
1186cd6a6acSopenharmony_ci{
1196cd6a6acSopenharmony_ci	context_private_t *n = context->ptr;
1206cd6a6acSopenharmony_ci	int i;
1216cd6a6acSopenharmony_ci	size_t total = 0;
1226cd6a6acSopenharmony_ci	conditional_free(&n->current_str);
1236cd6a6acSopenharmony_ci	for (i = 0; i < 4; i++) {
1246cd6a6acSopenharmony_ci		if (n->component[i]) {
1256cd6a6acSopenharmony_ci			total += strlen(n->component[i]) + 1;
1266cd6a6acSopenharmony_ci		}
1276cd6a6acSopenharmony_ci	}
1286cd6a6acSopenharmony_ci	n->current_str = malloc(total);
1296cd6a6acSopenharmony_ci	if (n->current_str != 0) {
1306cd6a6acSopenharmony_ci		char *cp = n->current_str;
1316cd6a6acSopenharmony_ci
1326cd6a6acSopenharmony_ci		cp = stpcpy(cp, n->component[0]);
1336cd6a6acSopenharmony_ci		for (i = 1; i < 4; i++) {
1346cd6a6acSopenharmony_ci			if (n->component[i]) {
1356cd6a6acSopenharmony_ci				*cp++ = ':';
1366cd6a6acSopenharmony_ci				cp = stpcpy(cp, n->component[i]);
1376cd6a6acSopenharmony_ci			}
1386cd6a6acSopenharmony_ci		}
1396cd6a6acSopenharmony_ci	}
1406cd6a6acSopenharmony_ci	return n->current_str;
1416cd6a6acSopenharmony_ci}
1426cd6a6acSopenharmony_ci
1436cd6a6acSopenharmony_ci
1446cd6a6acSopenharmony_ci/* Returns nonzero iff failed */
1456cd6a6acSopenharmony_cistatic int set_comp(context_private_t * n, int idx, const char *str)
1466cd6a6acSopenharmony_ci{
1476cd6a6acSopenharmony_ci	char *t = NULL;
1486cd6a6acSopenharmony_ci	const char *p;
1496cd6a6acSopenharmony_ci	if (str) {
1506cd6a6acSopenharmony_ci		for (p = str; *p; p++) {
1516cd6a6acSopenharmony_ci			if (*p == '\t' || *p == '\n' || *p == '\r' ||
1526cd6a6acSopenharmony_ci			    ((*p == ':' || *p == ' ') && idx != COMP_RANGE)) {
1536cd6a6acSopenharmony_ci				errno = EINVAL;
1546cd6a6acSopenharmony_ci				return -1;
1556cd6a6acSopenharmony_ci			}
1566cd6a6acSopenharmony_ci		}
1576cd6a6acSopenharmony_ci
1586cd6a6acSopenharmony_ci		t = strdup(str);
1596cd6a6acSopenharmony_ci		if (!t) {
1606cd6a6acSopenharmony_ci			return -1;
1616cd6a6acSopenharmony_ci		}
1626cd6a6acSopenharmony_ci	}
1636cd6a6acSopenharmony_ci	conditional_free(&n->component[idx]);
1646cd6a6acSopenharmony_ci	n->component[idx] = t;
1656cd6a6acSopenharmony_ci	return 0;
1666cd6a6acSopenharmony_ci}
1676cd6a6acSopenharmony_ci
1686cd6a6acSopenharmony_ci#define def_get(name,tag) \
1696cd6a6acSopenharmony_ciconst char * context_ ## name ## _get(context_t context) \
1706cd6a6acSopenharmony_ci{ \
1716cd6a6acSopenharmony_ci        context_private_t *n = context->ptr; \
1726cd6a6acSopenharmony_ci        return n->component[tag]; \
1736cd6a6acSopenharmony_ci}
1746cd6a6acSopenharmony_ci
1756cd6a6acSopenharmony_cidef_get(type, COMP_TYPE)
1766cd6a6acSopenharmony_ci    def_get(user, COMP_USER)
1776cd6a6acSopenharmony_ci    def_get(range, COMP_RANGE)
1786cd6a6acSopenharmony_ci    def_get(role, COMP_ROLE)
1796cd6a6acSopenharmony_ci#define def_set(name,tag) \
1806cd6a6acSopenharmony_ciint context_ ## name ## _set(context_t context, const char* str) \
1816cd6a6acSopenharmony_ci{ \
1826cd6a6acSopenharmony_ci        return set_comp(context->ptr,tag,str);\
1836cd6a6acSopenharmony_ci}
1846cd6a6acSopenharmony_ci    def_set(type, COMP_TYPE)
1856cd6a6acSopenharmony_ci    def_set(role, COMP_ROLE)
1866cd6a6acSopenharmony_ci    def_set(user, COMP_USER)
1876cd6a6acSopenharmony_ci    def_set(range, COMP_RANGE)
188