OpenSolaris_b135/common/tsol/stol.c

Compare this file to the similar file:
Show the results in this format:

/*
 * 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 <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <strings.h>
#else /* !defined(_KERNEL) */
#include <sys/systm.h>
#endif /* !defined(_KERNEL) */

#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 /* !defined(_KERNEL) */
#include <util/strtolctype.h>

#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) */