xref: /illumos-gate/usr/src/common/tsol/stol.c (revision 4201a95e)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #if !defined(_KERNEL)
27 #include <errno.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <ctype.h>
32 #include <strings.h>
33 #else /* !defined(_KERNEL) */
34 #include <sys/systm.h>
35 #endif /* !defined(_KERNEL) */
36 
37 #include <sys/mman.h>
38 #include <sys/tsol/label_macro.h>
39 
40 #include <sys/tsol/label.h>
41 
42 #if !defined(_KERNEL)
43 #include "clnt.h"
44 #include "labeld.h"
45 #else /* !defined(_KERNEL) */
46 #include <util/strtolctype.h>
47 
48 #define	L_DEFAULT	0x0
49 #define	L_NO_CORRECTION	0x2
50 #endif /* !defined(_KERNEL) */
51 
52 #define	IS_LOW(s) \
53 	((strncasecmp(s, ADMIN_LOW, (sizeof (ADMIN_LOW) - 1)) == 0) && \
54 	(s[sizeof (ADMIN_LOW) - 1] == '\0'))
55 #define	IS_HIGH(s) \
56 	((strncasecmp(s, ADMIN_HIGH, (sizeof (ADMIN_HIGH) - 1)) == 0) && \
57 	(s[sizeof (ADMIN_HIGH) - 1] == '\0'))
58 #define	IS_HEX(f, s) \
59 	(((((f) == L_NO_CORRECTION)) || ((f) == L_DEFAULT)) && \
60 	(((s)[0] == '0') && (((s)[1] == 'x') || ((s)[1] == 'X'))))
61 
62 static boolean_t
unhex(const char ** h,uchar_t * l,int len)63 unhex(const char **h, uchar_t *l, int len)
64 {
65 	const char	*hx = *h;
66 	char	ch;
67 	uchar_t	byte;
68 
69 	for (; len--; ) {
70 		ch = *hx++;
71 		if (!isxdigit(ch))
72 			return (B_FALSE);
73 		if (isdigit(ch))
74 			byte = ch - '0';
75 		else
76 			byte = ch - (isupper(ch) ? 'A' - 10 : 'a' - 10);
77 		byte <<= 4;
78 		ch = *hx++;
79 		if (!isxdigit(ch))
80 			return (B_FALSE);
81 		if (isdigit(ch))
82 			byte |= ch - '0';
83 		else
84 			byte |= ch - (isupper(ch) ? 'A' - 10 : 'a' - 10);
85 		*l++ = byte;
86 	}
87 	*h = hx;
88 	return (B_TRUE);
89 }
90 
91 /*
92  * Formats accepted:
93  * 0x + 4 class + 64 comps + end of string
94  * 0x + 4 class + '-' + ll + '-' + comps + end of string
95  * ll = number of words to fill out the entire comps field
96  *      presumes trailing zero for comps
97  *
98  * So in the case of 256 comps (i.e., 8 compartment words):
99  * 0x0006-08-7ff3f
100  * 0x + Classification + Compartments + end of string
101  * 0[xX]hhh...
102  */
103 
104 static int
htol(const char * s,m_label_t * l)105 htol(const char *s, m_label_t *l)
106 {
107 	const char	*h = &s[2];	/* skip 0[xX] */
108 	uchar_t *lp = (uchar_t *)&(((_mac_label_impl_t *)l)->_lclass);
109 	size_t	len = sizeof (_mac_label_impl_t) - 4;
110 	int	bytes;
111 
112 	/* unpack 16 bit signed classification */
113 	if (!unhex(&h, lp, 2) || (LCLASS(l) < 0)) {
114 		return (-1);
115 	}
116 	lp = (uchar_t *)&(((_mac_label_impl_t *)l)->_comps);
117 	if (h[0] == '-' && h[3] == '-') {
118 		uchar_t size;
119 
120 		/* length specified of internal text label */
121 		h++;	/* skip '-' */
122 		if (!unhex(&h, &size, 1)) {
123 			return (-1);
124 		}
125 		/* convert size from words to bytes */
126 		if ((size * sizeof (uint32_t)) > len) {
127 			/*
128 			 * internal label greater than will fit in current
129 			 * binary.
130 			 */
131 			return (-1);
132 		}
133 		bzero(lp, len);
134 		h++;	/* skip '-' */
135 	}
136 	bytes = strlen(h)/2;
137 	if ((bytes > len) ||
138 	    (bytes*2 != strlen(h)) ||
139 	    !unhex(&h, lp, bytes)) {
140 		return (-1);
141 	}
142 	return (0);
143 }
144 
145 /*
146  * hexstr_to_label -- parse a string representing a hex label into a
147  *			binary label.  Only admin high/low and hex are
148  *			accepted.
149  *
150  *	Returns	 0, success.
151  *		-1, failure
152  */
153 int
hexstr_to_label(const char * s,m_label_t * l)154 hexstr_to_label(const char *s, m_label_t *l)
155 {
156 	uint_t	f = L_DEFAULT;
157 
158 	/* translate hex, admin_low and admin_high */
159 	if (IS_LOW(s)) {
160 		_LOW_LABEL(l, SUN_MAC_ID);
161 		return (0);
162 	} else if (IS_HIGH(s)) {
163 		_HIGH_LABEL(l, SUN_MAC_ID);
164 		return (0);
165 	} else if (IS_HEX(f, s)) {
166 		_LOW_LABEL(l, SUN_MAC_ID);
167 		if (htol(s, l) == 0)
168 			return (0);
169 	}
170 
171 	return (-1);
172 }
173 
174 #if !defined(_KERNEL)
175 static int
convert_id(m_label_type_t t)176 convert_id(m_label_type_t t)
177 {
178 	switch (t) {
179 	case MAC_LABEL:
180 		return (SUN_MAC_ID);
181 	case USER_CLEAR:
182 		return (SUN_UCLR_ID);
183 	default:
184 		return (-1);
185 	}
186 }
187 
188 /*
189  * str_to_label -- parse a string into the requested label type.
190  *
191  *	Entry	s = string to parse.
192  *		l = label to create or modify.
193  *		t = label type (MAC_LABEL, USER_CLEAR).
194  *		f = flags
195  *			L_DEFAULT,
196  *			L_MODIFY_EXISTING, use the existing label as a basis for
197  *				the parse string.
198  *			L_NO_CORRECTION, s must be correct and full by the
199  *				label_encoding rules.
200  *			L_CHECK_AR, for non-hex s, MAC_LABEL, check the l_e AR
201  *
202  *	Exit	l = parsed label value.
203  *		e = index into string of error.
204  *		  = M_BAD_STRING (-3 L_BAD_LABEL) or could be zero,
205  *		    indicates entire string,
206  *	        e = M_BAD_LABEL (-2 L_BAD_CLASSIFICATION), problems with l
207  *		e = M_OUTSIDE_AR (-4 unrelated to L_BAD_* return values)
208  *
209  *	Returns	 0, success.
210  *		-1, failure
211  *			errno = ENOTSUP, the underlying label mechanism
212  *				does not support label parsing.
213  *				ENOMEM, unable to allocate memory for l.
214  *				EINVAL, invalid argument, l != NULL or
215  *				invalid label type for the underlying
216  *				label mechanism.
217  */
218 #define	_M_GOOD_LABEL	-1	/* gfi L_GOOD_LABEL */
219 int
str_to_label(const char * str,m_label_t ** l,const m_label_type_t t,uint_t f,int * e)220 str_to_label(const char *str, m_label_t **l, const m_label_type_t t, uint_t f,
221     int *e)
222 {
223 	char		*s = strdup(str);
224 	char		*st = s;
225 	char		*p;
226 	labeld_data_t	call;
227 	labeld_data_t	*callp = &call;
228 	size_t		bufsize = sizeof (labeld_data_t);
229 	size_t		datasize;
230 	int		err = M_BAD_LABEL;
231 	int		id = convert_id(t);
232 	boolean_t	new = B_FALSE;
233 	uint_t		lf = (f & ~L_CHECK_AR);	/* because L_DEFAULT == 0 */
234 
235 	if (st == NULL) {
236 		errno = ENOMEM;
237 		return (-1);
238 	}
239 	if (*l == NULL) {
240 		if ((*l = m_label_alloc(t)) == NULL) {
241 			free(st);
242 			return (-1);
243 		}
244 		if (id == -1) {
245 			goto badlabel;
246 		}
247 		_LOW_LABEL(*l, id);
248 		new = B_TRUE;
249 	} else if (_MTYPE(*l, SUN_INVALID_ID) &&
250 	    ((lf == L_NO_CORRECTION) || (lf == L_DEFAULT))) {
251 		_LOW_LABEL(*l, id);
252 		new = B_TRUE;
253 	} else if (!(_MTYPE(*l, SUN_MAC_ID) || _MTYPE(*l, SUN_CLR_ID))) {
254 		goto badlabel;
255 	}
256 
257 	if (new == B_FALSE && id == -1) {
258 		goto badlabel;
259 	}
260 
261 	/* get to the beginning of the string to parse */
262 	while (isspace(*s)) {
263 		s++;
264 	}
265 
266 	/* accept a leading '[' and trailing ']' for old times sake */
267 	if (*s == '[') {
268 		*s = ' ';
269 		s++;
270 		while (isspace(*s)) {
271 			s++;
272 		}
273 	}
274 	p = s;
275 	while (*p != '\0' && *p != ']') {
276 		p++;
277 	}
278 
279 	/* strip trailing spaces */
280 	while (p != s && isspace(*(p-1))) {
281 		--p;
282 	}
283 	*p = '\0';	/* end of string */
284 
285 	/* translate hex, admin_low and admin_high */
286 	id = _MGETTYPE(*l);
287 	if (IS_LOW(s)) {
288 		_LOW_LABEL(*l, id);
289 		goto goodlabel;
290 	} else if (IS_HIGH(s)) {
291 		_HIGH_LABEL(*l, id);
292 		goto goodlabel;
293 	} else if (IS_HEX(lf, s)) {
294 		if (htol(s, *l) != 0) {
295 			/* whole string in error */
296 			err = 0;
297 			goto badlabel;
298 		}
299 		goto goodlabel;
300 	}
301 #define	slcall callp->param.acall.cargs.sl_arg
302 #define	slret callp->param.aret.rvals.sl_ret
303 	/* now try label server */
304 
305 	datasize = CALL_SIZE_STR(sl_call_t, strlen(st) + 1);
306 	if (datasize > bufsize) {
307 		if ((callp = malloc(datasize)) == NULL) {
308 			free(st);
309 			return (-1);
310 		}
311 		bufsize = datasize;
312 	}
313 	callp->callop = STOL;
314 	slcall.label = **l;
315 	slcall.flags = f;
316 	if (new)
317 		slcall.flags |= L_NEW_LABEL;
318 	(void) strcpy(slcall.string, st);
319 	/*
320 	 * callp->reterr = L_GOOD_LABEL (-1) == OK;
321 	 *		   L_BAD_CLASSIFICATION (-2) == bad input
322 	 *			classification: class
323 	 *		   L_BAD_LABEL (-3) == either string or input label bad
324 	 *		   M_OUTSIDE_AR (-4) == resultant MAC_LABEL is out
325 	 *			l_e accreditation range
326 	 *		   O'E == offset in string 0 == entire string.
327 	 */
328 	if (__call_labeld(&callp, &bufsize, &datasize) == SUCCESS) {
329 
330 		err = callp->reterr;
331 		if (callp != &call) {
332 			/* free allocated buffer */
333 			free(callp);
334 		}
335 		switch (err) {
336 		case _M_GOOD_LABEL:	/* L_GOOD_LABEL */
337 			**l = slret.label;
338 			goto goodlabel;
339 		case M_BAD_LABEL:	/* L_BAD_CLASSIFICATION */
340 		case M_BAD_STRING:	/* L_BAD_LABEL */
341 		default:
342 			goto badlabel;
343 		}
344 	}
345 	switch (callp->reterr) {
346 	case NOSERVER:
347 		errno = ENOTSUP;
348 		break;
349 	default:
350 		errno = EINVAL;
351 		break;
352 	}
353 	free(st);
354 	return (-1);
355 
356 badlabel:
357 	errno = EINVAL;
358 	free(st);
359 	if (e != NULL)
360 		*e = err;
361 	return (-1);
362 
363 goodlabel:
364 	free(st);
365 	return (0);
366 }
367 #undef	slcall
368 #undef	slret
369 
370 /*
371  * m_label_alloc -- allocate a label structure
372  *
373  *	Entry	t = label type (MAC_LABEL, USER_CLEAR).
374  *
375  *	Exit	If error, NULL, errno set to ENOMEM
376  *		Otherwise, pointer to m_label_t memory
377  */
378 
379 /* ARGUSED */
380 m_label_t *
m_label_alloc(const m_label_type_t t)381 m_label_alloc(const m_label_type_t t)
382 {
383 	m_label_t *l;
384 
385 	switch (t) {
386 	case MAC_LABEL:
387 	case USER_CLEAR:
388 		if ((l = malloc(sizeof (_mac_label_impl_t))) == NULL) {
389 			return (NULL);
390 		}
391 		_MSETTYPE(l, SUN_INVALID_ID);
392 		break;
393 	default:
394 		errno = EINVAL;
395 		return (NULL);
396 	}
397 	return (l);
398 }
399 
400 /*
401  * m_label_dup -- make a duplicate copy of the given label.
402  *
403  *	Entry	l = label to duplicate.
404  *
405  *	Exit	d = duplicate copy of l.
406  *
407  *	Returns	 0, success
408  *		-1, if error.
409  *			errno = ENOTSUP, the underlying label mechanism
410  *				does not support label duplication.
411  *				ENOMEM, unable to allocate memory for d.
412  *				EINVAL, invalid argument, l == NULL or
413  *				invalid label type for the underlying
414  *				label mechanism.
415  */
416 
417 int
m_label_dup(m_label_t ** d,const m_label_t * l)418 m_label_dup(m_label_t **d, const m_label_t *l)
419 {
420 	if (d == NULL || *d != NULL) {
421 		errno = EINVAL;
422 		return (-1);
423 	}
424 	if ((*d = malloc(sizeof (_mac_label_impl_t))) == NULL) {
425 		errno = ENOMEM;
426 		return (-1);
427 	}
428 
429 	(void) memcpy(*d, l, sizeof (_mac_label_impl_t));
430 	return (0);
431 }
432 
433 /*
434  * m_label_free -- free label structure
435  *
436  *	Entry	l = label to free.
437  *
438  *	Exit	memory freed.
439  *
440  */
441 
442 void
m_label_free(m_label_t * l)443 m_label_free(m_label_t *l)
444 {
445 	if (l)
446 		free(l);
447 }
448 #endif /* !defined(_KERNEL) */
449