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 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 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 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 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 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 * 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 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 443 m_label_free(m_label_t *l) 444 { 445 if (l) 446 free(l); 447 } 448 #endif /* !defined(_KERNEL) */ 449