#if !defined(_KERNEL)
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <strings.h>
#else
#include <sys/systm.h>
#endif
#include <sys/mman.h>
#include <sys/tsol/label_macro.h>
#include <sys/tsol/label.h>
#if !defined(_KERNEL)
#include "clnt.h"
#include "labeld.h"
#else
#include <util/strtolctype.h>
#define L_DEFAULT 0x0
#define L_NO_CORRECTION 0x2
#endif
#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);
}
static int
htol(const char *s, m_label_t *l)
{
const char *h = &s[2];
uchar_t *lp = (uchar_t *)&(((_mac_label_impl_t *)l)->_lclass);
size_t len = sizeof (_mac_label_impl_t) - 4;
int bytes;
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;
h++;
if (!unhex(&h, &size, 1)) {
return (-1);
}
if ((size * sizeof (uint32_t)) > len) {
return (-1);
}
bzero(lp, len);
h++;
}
bytes = strlen(h)/2;
if ((bytes > len) ||
(bytes*2 != strlen(h)) ||
!unhex(&h, lp, bytes)) {
return (-1);
}
return (0);
}
int
hexstr_to_label(const char *s, m_label_t *l)
{
uint_t f = L_DEFAULT;
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);
}
}
#define _M_GOOD_LABEL -1
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);
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;
}
while (isspace(*s)) {
s++;
}
if (*s == '[') {
*s = ' ';
s++;
while (isspace(*s)) {
s++;
}
}
p = s;
while (*p != '\0' && *p != ']') {
p++;
}
while (p != s && isspace(*(p-1))) {
--p;
}
*p = '\0';
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) {
err = 0;
goto badlabel;
}
goto goodlabel;
}
#define slcall callp->param.acall.cargs.sl_arg
#define slret callp->param.aret.rvals.sl_ret
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);
if (__call_labeld(&callp, &bufsize, &datasize) == SUCCESS) {
err = callp->reterr;
if (callp != &call) {
free(callp);
}
switch (err) {
case _M_GOOD_LABEL:
**l = slret.label;
goto goodlabel;
case M_BAD_LABEL:
case M_BAD_STRING:
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_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);
}
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);
}
void
m_label_free(m_label_t *l)
{
if (l)
free(l);
}
#endif