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 
12 typedef 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  */
context_new(const char * str)22 context_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 
hidden_def(context_new)85 hidden_def(context_new)
86 
87 static 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  */
context_free(context_t context)99 void 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 
hidden_def(context_free)116 hidden_def(context_free)
117 
118 /*
119  * Return a pointer to the string value of the context.
120  */
121 char *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 		cp = stpcpy(cp, n->component[0]);
137 		for (i = 1; i < 4; i++) {
138 			if (n->component[i]) {
139 				*cp++ = ':';
140 				cp = stpcpy(cp, n->component[i]);
141 			}
142 		}
143 	}
144 	return n->current_str;
145 }
146 
hidden_def(context_str)147 hidden_def(context_str)
148 
149 /* Returns nonzero iff failed */
150 static int set_comp(context_private_t * n, int idx, const char *str)
151 {
152 	char *t = NULL;
153 	const char *p;
154 	if (str) {
155 		t = (char *)malloc(strlen(str) + 1);
156 		if (!t) {
157 			return 1;
158 		}
159 		for (p = str; *p; p++) {
160 			if (*p == '\t' || *p == '\n' || *p == '\r' ||
161 			    ((*p == ':' || *p == ' ') && idx != COMP_RANGE)) {
162 				free(t);
163 				errno = EINVAL;
164 				return 1;
165 			}
166 		}
167 		strcpy(t, str);
168 	}
169 	conditional_free(&n->component[idx]);
170 	n->component[idx] = t;
171 	return 0;
172 }
173 
174 #define def_get(name,tag) \
175 const char * context_ ## name ## _get(context_t context) \
176 { \
177         context_private_t *n = context->ptr; \
178         return n->component[tag]; \
179 } \
180 hidden_def(context_ ## name ## _get)
181 
182 def_get(type, COMP_TYPE)
183     def_get(user, COMP_USER)
184     def_get(range, COMP_RANGE)
185     def_get(role, COMP_ROLE)
186 #define def_set(name,tag) \
187 int context_ ## name ## _set(context_t context, const char* str) \
188 { \
189         return set_comp(context->ptr,tag,str);\
190 } \
191 hidden_def(context_ ## name ## _set)
192     def_set(type, COMP_TYPE)
193     def_set(role, COMP_ROLE)
194     def_set(user, COMP_USER)
195     def_set(range, COMP_RANGE)
196