/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #if !defined(_KERNEL) #include #include #include #include #include #include #else /* !defined(_KERNEL) */ #include #endif /* !defined(_KERNEL) */ #include #include #include #if !defined(_KERNEL) #include "clnt.h" #include "labeld.h" #else /* !defined(_KERNEL) */ #include #define L_DEFAULT 0x0 #define L_NO_CORRECTION 0x2 #endif /* !defined(_KERNEL) */ #define IS_LOW(s) \ ((strncasecmp(s, ADMIN_LOW, (sizeof (ADMIN_LOW) - 1)) == 0) && \ (s[sizeof (ADMIN_LOW) - 1] == '\0')) #define IS_HIGH(s) \ ((strncasecmp(s, ADMIN_HIGH, (sizeof (ADMIN_HIGH) - 1)) == 0) && \ (s[sizeof (ADMIN_HIGH) - 1] == '\0')) #define IS_HEX(f, s) \ (((((f) == L_NO_CORRECTION)) || ((f) == L_DEFAULT)) && \ (((s)[0] == '0') && (((s)[1] == 'x') || ((s)[1] == 'X')))) static boolean_t unhex(const char **h, uchar_t *l, int len) { const char *hx = *h; char ch; uchar_t byte; for (; len--; ) { ch = *hx++; if (!isxdigit(ch)) return (B_FALSE); if (isdigit(ch)) byte = ch - '0'; else byte = ch - (isupper(ch) ? 'A' - 10 : 'a' - 10); byte <<= 4; ch = *hx++; if (!isxdigit(ch)) return (B_FALSE); if (isdigit(ch)) byte |= ch - '0'; else byte |= ch - (isupper(ch) ? 'A' - 10 : 'a' - 10); *l++ = byte; } *h = hx; return (B_TRUE); } /* * Formats accepted: * 0x + 4 class + 64 comps + end of string * 0x + 4 class + '-' + ll + '-' + comps + end of string * ll = number of words to fill out the entire comps field * presumes trailing zero for comps * * So in the case of 256 comps (i.e., 8 compartment words): * 0x0006-08-7ff3f * 0x + Classification + Compartments + end of string * 0[xX]hhh... */ static int htol(const char *s, m_label_t *l) { const char *h = &s[2]; /* skip 0[xX] */ uchar_t *lp = (uchar_t *)&(((_mac_label_impl_t *)l)->_lclass); size_t len = sizeof (_mac_label_impl_t) - 4; int bytes; /* unpack 16 bit signed classification */ if (!unhex(&h, lp, 2) || (LCLASS(l) < 0)) { return (-1); } lp = (uchar_t *)&(((_mac_label_impl_t *)l)->_comps); if (h[0] == '-' && h[3] == '-') { uchar_t size; /* length specified of internal text label */ h++; /* skip '-' */ if (!unhex(&h, &size, 1)) { return (-1); } /* convert size from words to bytes */ if ((size * sizeof (uint32_t)) > len) { /* * internal label greater than will fit in current * binary. */ return (-1); } bzero(lp, len); h++; /* skip '-' */ } bytes = strlen(h)/2; if ((bytes > len) || (bytes*2 != strlen(h)) || !unhex(&h, lp, bytes)) { return (-1); } return (0); } /* * hexstr_to_label -- parse a string representing a hex label into a * binary label. Only admin high/low and hex are * accepted. * * Returns 0, success. * -1, failure */ int hexstr_to_label(const char *s, m_label_t *l) { uint_t f = L_DEFAULT; /* translate hex, admin_low and admin_high */ if (IS_LOW(s)) { _LOW_LABEL(l, SUN_MAC_ID); return (0); } else if (IS_HIGH(s)) { _HIGH_LABEL(l, SUN_MAC_ID); return (0); } else if (IS_HEX(f, s)) { _LOW_LABEL(l, SUN_MAC_ID); if (htol(s, l) == 0) return (0); } return (-1); } #if !defined(_KERNEL) static int convert_id(m_label_type_t t) { switch (t) { case MAC_LABEL: return (SUN_MAC_ID); case USER_CLEAR: return (SUN_UCLR_ID); default: return (-1); } } /* * str_to_label -- parse a string into the requested label type. * * Entry s = string to parse. * l = label to create or modify. * t = label type (MAC_LABEL, USER_CLEAR). * f = flags * L_DEFAULT, * L_MODIFY_EXISTING, use the existing label as a basis for * the parse string. * L_NO_CORRECTION, s must be correct and full by the * label_encoding rules. * L_CHECK_AR, for non-hex s, MAC_LABEL, check the l_e AR * * Exit l = parsed label value. * e = index into string of error. * = M_BAD_STRING (-3 L_BAD_LABEL) or could be zero, * indicates entire string, * e = M_BAD_LABEL (-2 L_BAD_CLASSIFICATION), problems with l * e = M_OUTSIDE_AR (-4 unrelated to L_BAD_* return values) * * Returns 0, success. * -1, failure * errno = ENOTSUP, the underlying label mechanism * does not support label parsing. * ENOMEM, unable to allocate memory for l. * EINVAL, invalid argument, l != NULL or * invalid label type for the underlying * label mechanism. */ #define _M_GOOD_LABEL -1 /* gfi L_GOOD_LABEL */ int str_to_label(const char *str, m_label_t **l, const m_label_type_t t, uint_t f, int *e) { char *s = strdup(str); char *st = s; char *p; labeld_data_t call; labeld_data_t *callp = &call; size_t bufsize = sizeof (labeld_data_t); size_t datasize; int err = M_BAD_LABEL; int id = convert_id(t); boolean_t new = B_FALSE; uint_t lf = (f & ~L_CHECK_AR); /* because L_DEFAULT == 0 */ if (st == NULL) { errno = ENOMEM; return (-1); } if (*l == NULL) { if ((*l = m_label_alloc(t)) == NULL) { free(st); return (-1); } if (id == -1) { goto badlabel; } _LOW_LABEL(*l, id); new = B_TRUE; } else if (_MTYPE(*l, SUN_INVALID_ID) && ((lf == L_NO_CORRECTION) || (lf == L_DEFAULT))) { _LOW_LABEL(*l, id); new = B_TRUE; } else if (!(_MTYPE(*l, SUN_MAC_ID) || _MTYPE(*l, SUN_CLR_ID))) { goto badlabel; } if (new == B_FALSE && id == -1) { goto badlabel; } /* get to the beginning of the string to parse */ while (isspace(*s)) { s++; } /* accept a leading '[' and trailing ']' for old times sake */ if (*s == '[') { *s = ' '; s++; while (isspace(*s)) { s++; } } p = s; while (*p != '\0' && *p != ']') { p++; } /* strip trailing spaces */ while (p != s && isspace(*(p-1))) { --p; } *p = '\0'; /* end of string */ /* translate hex, admin_low and admin_high */ id = _MGETTYPE(*l); if (IS_LOW(s)) { _LOW_LABEL(*l, id); goto goodlabel; } else if (IS_HIGH(s)) { _HIGH_LABEL(*l, id); goto goodlabel; } else if (IS_HEX(lf, s)) { if (htol(s, *l) != 0) { /* whole string in error */ err = 0; goto badlabel; } goto goodlabel; } #define slcall callp->param.acall.cargs.sl_arg #define slret callp->param.aret.rvals.sl_ret /* now try label server */ datasize = CALL_SIZE_STR(sl_call_t, strlen(st) + 1); if (datasize > bufsize) { if ((callp = malloc(datasize)) == NULL) { free(st); return (-1); } bufsize = datasize; } callp->callop = STOL; slcall.label = **l; slcall.flags = f; if (new) slcall.flags |= L_NEW_LABEL; (void) strcpy(slcall.string, st); /* * callp->reterr = L_GOOD_LABEL (-1) == OK; * L_BAD_CLASSIFICATION (-2) == bad input * classification: class * L_BAD_LABEL (-3) == either string or input label bad * M_OUTSIDE_AR (-4) == resultant MAC_LABEL is out * l_e accreditation range * O'E == offset in string 0 == entire string. */ if (__call_labeld(&callp, &bufsize, &datasize) == SUCCESS) { err = callp->reterr; if (callp != &call) { /* free allocated buffer */ free(callp); } switch (err) { case _M_GOOD_LABEL: /* L_GOOD_LABEL */ **l = slret.label; goto goodlabel; case M_BAD_LABEL: /* L_BAD_CLASSIFICATION */ case M_BAD_STRING: /* L_BAD_LABEL */ default: goto badlabel; } } switch (callp->reterr) { case NOSERVER: errno = ENOTSUP; break; default: errno = EINVAL; break; } free(st); return (-1); badlabel: errno = EINVAL; free(st); if (e != NULL) *e = err; return (-1); goodlabel: free(st); return (0); } #undef slcall #undef slret /* * m_label_alloc -- allocate a label structure * * Entry t = label type (MAC_LABEL, USER_CLEAR). * * Exit If error, NULL, errno set to ENOMEM * Otherwise, pointer to m_label_t memory */ /* ARGUSED */ m_label_t * m_label_alloc(const m_label_type_t t) { m_label_t *l; switch (t) { case MAC_LABEL: case USER_CLEAR: if ((l = malloc(sizeof (_mac_label_impl_t))) == NULL) { return (NULL); } _MSETTYPE(l, SUN_INVALID_ID); break; default: errno = EINVAL; return (NULL); } return (l); } /* * m_label_dup -- make a duplicate copy of the given label. * * Entry l = label to duplicate. * * Exit d = duplicate copy of l. * * Returns 0, success * -1, if error. * errno = ENOTSUP, the underlying label mechanism * does not support label duplication. * ENOMEM, unable to allocate memory for d. * EINVAL, invalid argument, l == NULL or * invalid label type for the underlying * label mechanism. */ int m_label_dup(m_label_t **d, const m_label_t *l) { if (d == NULL || *d != NULL) { errno = EINVAL; return (-1); } if ((*d = malloc(sizeof (_mac_label_impl_t))) == NULL) { errno = ENOMEM; return (-1); } (void) memcpy(*d, l, sizeof (_mac_label_impl_t)); return (0); } /* * m_label_free -- free label structure * * Entry l = label to free. * * Exit memory freed. * */ void m_label_free(m_label_t *l) { if (l) free(l); } #endif /* !defined(_KERNEL) */