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