1#include "context_internal.h"
2#include <string.h>
3#include <stdio.h>
4#include <stdlib.h>
5#include <errno.h>
6
7#define COMP_USER  0
8#define COMP_ROLE  1
9#define COMP_TYPE  2
10#define COMP_RANGE 3
11
12typedef struct {
13	char *current_str;	/* This is made up-to-date only when needed */
14	char *(component[4]);
15} context_private_t;
16
17/*
18 * Allocate a new context, initialized from str.  There must be 3 or
19 * 4 colon-separated components and no whitespace in any component other
20 * than the MLS component.
21 */
22context_t context_new(const char *str)
23{
24	int i, count;
25	errno = 0;
26	context_private_t *n =
27	    (context_private_t *) malloc(sizeof(context_private_t));
28	context_t result = (context_t) malloc(sizeof(context_s_t));
29	const char *p, *tok;
30
31	if (result)
32		result->ptr = n;
33	else
34		free(n);
35	if (n == 0 || result == 0) {
36		goto err;
37	}
38	n->current_str = n->component[0] = n->component[1] = n->component[2] =
39	    n->component[3] = 0;
40	for (i = count = 0, p = str; *p; p++) {
41		switch (*p) {
42		case ':':
43			count++;
44			break;
45		case '\n':
46		case '\t':
47		case '\r':
48			goto err;	/* sanity check */
49		case ' ':
50			if (count < 3)
51				goto err;	/* sanity check */
52		}
53	}
54	/*
55	 * Could be anywhere from 2 - 5
56	 * e.g user:role:type to user:role:type:sens1:cata-sens2:catb
57	 */
58	if (count < 2 || count > 5) {	/* might not have a range */
59		goto err;
60	}
61
62	n->component[3] = 0;
63	for (i = 0, tok = str; *tok; i++) {
64		if (i < 3)
65			for (p = tok; *p && *p != ':'; p++) {	/* empty */
66		} else {
67			/* MLS range is one component */
68			for (p = tok; *p; p++) {	/* empty */
69			}
70		}
71		n->component[i] = (char *)malloc(p - tok + 1);
72		if (n->component[i] == 0)
73			goto err;
74		strncpy(n->component[i], tok, p - tok);
75		n->component[i][p - tok] = '\0';
76		tok = *p ? p + 1 : p;
77	}
78	return result;
79      err:
80	if (errno == 0) errno = EINVAL;
81	context_free(result);
82	return 0;
83}
84
85hidden_def(context_new)
86
87static void conditional_free(char **v)
88{
89	if (*v) {
90		free(*v);
91	}
92	*v = 0;
93}
94
95/*
96 * free all storage used by a context.  Safe to call with
97 * null pointer.
98 */
99void context_free(context_t context)
100{
101	context_private_t *n;
102	int i;
103	if (context) {
104		n = context->ptr;
105		if (n) {
106			conditional_free(&n->current_str);
107			for (i = 0; i < 4; i++) {
108				conditional_free(&n->component[i]);
109			}
110			free(n);
111		}
112		free(context);
113	}
114}
115
116hidden_def(context_free)
117
118/*
119 * Return a pointer to the string value of the context.
120 */
121char *context_str(context_t context)
122{
123	context_private_t *n = context->ptr;
124	int i;
125	size_t total = 0;
126	conditional_free(&n->current_str);
127	for (i = 0; i < 4; i++) {
128		if (n->component[i]) {
129			total += strlen(n->component[i]) + 1;
130		}
131	}
132	n->current_str = malloc(total);
133	if (n->current_str != 0) {
134		char *cp = n->current_str;
135
136		strcpy(cp, n->component[0]);
137		cp += strlen(cp);
138		for (i = 1; i < 4; i++) {
139			if (n->component[i]) {
140				*cp++ = ':';
141				strcpy(cp, n->component[i]);
142				cp += strlen(cp);
143			}
144		}
145	}
146	return n->current_str;
147}
148
149hidden_def(context_str)
150
151/* Returns nonzero iff failed */
152static int set_comp(context_private_t * n, int idx, const char *str)
153{
154	char *t = NULL;
155	const char *p;
156	if (str) {
157		t = (char *)malloc(strlen(str) + 1);
158		if (!t) {
159			return 1;
160		}
161		for (p = str; *p; p++) {
162			if (*p == '\t' || *p == '\n' || *p == '\r' ||
163			    ((*p == ':' || *p == ' ') && idx != COMP_RANGE)) {
164				free(t);
165				errno = EINVAL;
166				return 1;
167			}
168		}
169		strcpy(t, str);
170	}
171	conditional_free(&n->component[idx]);
172	n->component[idx] = t;
173	return 0;
174}
175
176#define def_get(name,tag) \
177const char * context_ ## name ## _get(context_t context) \
178{ \
179        context_private_t *n = context->ptr; \
180        return n->component[tag]; \
181} \
182hidden_def(context_ ## name ## _get)
183
184def_get(type, COMP_TYPE)
185    def_get(user, COMP_USER)
186    def_get(range, COMP_RANGE)
187    def_get(role, COMP_ROLE)
188#define def_set(name,tag) \
189int context_ ## name ## _set(context_t context, const char* str) \
190{ \
191        return set_comp(context->ptr,tag,str);\
192} \
193hidden_def(context_ ## name ## _set)
194    def_set(type, COMP_TYPE)
195    def_set(role, COMP_ROLE)
196    def_set(user, COMP_USER)
197    def_set(range, COMP_RANGE)
198