OpenSolaris_b135/lib/libtsol/common/btos.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 2006 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#pragma ident	"%Z%%M%	%I%	%E% SMI"

/*
 *      Binary label to label string translations.
 */

#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <wchar.h>

#include <sys/mman.h>

#include <tsol/label.h>

#include "clnt.h"
#include "labeld.h"
#include <sys/tsol/label_macro.h>

#if	!defined(TEXT_DOMAIN)		/* should be defined by Makefiles */
#define	TEXT_DOMAIN "SYS_TEST"
#endif	/* TEXT_DOMAIN */

static bslabel_t slow;	/* static admin_low high sensitivity label */
static bslabel_t shigh;	/* static admin_high sensitivity label */
static bclear_t clrlow, clrhigh; /* static admin_low and admin_high Clearance */

static char	*sstring;	/* return string for sb*tos */
static size_t	ssize;		/* current size of return string */

static int
return_string(char **string, int str_len, char *val)
{
	char	*cpyptr;
	size_t	val_len = strlen(val) + 1;

	if (*string == NULL) {
		if ((*string = malloc(val_len)) == NULL)
			return (0);
	} else if (val_len > str_len) {
		**string = '\0';
		return (0);
	}

	cpyptr = *string;
	bcopy(val, cpyptr, val_len);

	return (val_len);
}

void
set_label_view(uint_t *callflags, uint_t flags)
{
	if (flags&VIEW_INTERNAL) {
		*callflags |= LABELS_VIEW_INTERNAL;
	} else if (flags&VIEW_EXTERNAL) {
		*callflags |= LABELS_VIEW_EXTERNAL;
	}
}

int
alloc_string(char **string, size_t size, char val)
{
	if (*string == NULL) {
		if ((*string = malloc(ALLOC_CHUNK)) == NULL)
			return (0);
	} else {
		if ((*string = realloc(*string, size + ALLOC_CHUNK)) == NULL) {
			**string = val;
			return (0);
		}
	}
	**string = val;
	return (ALLOC_CHUNK);
}

#define	slcall callp->param.acall.cargs.bsltos_arg
#define	slret callp->param.aret.rvals.bsltos_ret
/*
 *	bsltos - Convert Binary Sensitivity Label to Sensitivity Label string.
 *
 *	Entry	label = Binary Sensitivity Label to be converted.
 *		string = NULL ((char *) 0), if memory to be allocated,
 *			 otherwise, pointer to preallocated memory.
 *		str_len = Length of preallocated memory, else ignored.
 *		flags = Logical sum of:
 *				LONG_CLASSIFICATION or SHORT_CLASSIFICATION,
 *				LONG_WORDS or SHORT_WORDS,
 *				VIEW_INTERNAL or VIEW_EXTERNAL, and
 *				NO_CLASSIFICATION.
 *			LONG_CLASSIFICATION, use long classification names.
 *			SHORT_CLASSIFICATION, use short classification
 *						names (default).
 *			NO_CLASSIFICATION, don't translate classification.
 *			LONG_WORDS, use the long form of words (default).
 *			SHORTWORDS, use the short form of words where available.
 *			VIEW_INTERNAL, don't promote/demote admin low/high.
 *			VIEW_EXTERNAL, promote/demote admin low/high.
 *
 *	Exit	string = Sensitivity Label string, or empty string if
 *			 not enough preallocated memory.
 *
 *	Returns	-1, If unable to access label encodings database.
 *		 0, If unable to allocate string,
 *			or allocated string to short
 *			(and **string = '\0').
 *		length (including null) of Sensitivity Label string,
 *			If successful.
 *
 *	Calls	RPC - LABELS_BSLTOS, BCLHIGH, BCLLOW, BCLTOSL, BLEQUAL,
 *			BLTYPE, SETBSLABEL, UCLNT, memcpy, clnt_call,
 *			clnt_perror, malloc, strcat, strlen.
 *
 *	Uses	ADMIN_HIGH, ADMIN_LOW, shigh, slow.
 */

ssize_t
bsltos(const bslabel_t *label, char **string, size_t str_len,
    int flags)
{
	labeld_data_t	call;
	labeld_data_t	*callp = &call;
	size_t	bufsize = sizeof (labeld_data_t);
	size_t	datasize = CALL_SIZE(bsltos_call_t, 0);
	int	rval;

	if (!BLTYPE(label, SUN_SL_ID)) {
		return (-1);
	}

	call.callop = BSLTOS;
	slcall.label = *label;
	slcall.flags = (flags&NO_CLASSIFICATION) ? LABELS_NO_CLASS : 0;
	slcall.flags |= (flags&SHORT_CLASSIFICATION ||
	    !(flags&LONG_CLASSIFICATION)) ? LABELS_SHORT_CLASS : 0;
	slcall.flags |= (flags&SHORT_WORDS && !(flags&LONG_WORDS)) ?
	    LABELS_SHORT_WORDS : 0;
	set_label_view(&slcall.flags, flags);

	if ((rval = __call_labeld(&callp, &bufsize, &datasize)) == SUCCESS) {

		if (callp->reterr != 0)
			return (-1);

		/* unpack Sensitivity Label */

		rval = return_string(string, str_len, slret.slabel);

		if (callp != &call)
			(void) munmap((void *)callp, bufsize);
		return (rval);
	} else if (rval == NOSERVER) {
		/* server not present */
		/* special case admin_high and admin_low */

		if (!BLTYPE(&slow, SUN_SL_ID)) {
			/* initialize static labels */

			BSLLOW(&slow);
			BSLHIGH(&shigh);
		}

		if (BLEQUAL(label, &slow)) {
			return (return_string(string, str_len, ADMIN_LOW));
		} else if (BLEQUAL(label, &shigh)) {
			return (return_string(string, str_len, ADMIN_HIGH));
		}
	}
	return (-1);
}  /* bsltos */
#undef	slcall
#undef	slret

#define	clrcall callp->param.acall.cargs.bcleartos_arg
#define	clrret callp->param.aret.rvals.bcleartos_ret
/*
 *	bcleartos - Convert Binary Clearance to Clearance string.
 *
 *	Entry	clearance = Binary Clearance to be converted.
 *		string = NULL ((char *) 0), if memory to be allocated,
 *			 otherwise, pointer to preallocated memory.
 *		str_len = Length of preallocated memory, else ignored.
 *		flags = Logical sum of:
 *				LONG_CLASSIFICATION or SHORT_CLASSIFICATION,
 *				LONG_WORDS or SHORT_WORDS,
 *				VIEW_INTERNAL or VIEW_EXTERNAL.
 *			LONG_CLASSIFICATION, use long classification names.
 *			SHORT_CLASSIFICATION, use short classification
 *						names (default).
 *			LONG_WORDS, use the long form of words (default).
 *			SHORTWORDS, use the short form of words where available.
 *			VIEW_INTERNAL, don't promote/demote admin low/high.
 *			VIEW_EXTERNAL, promote/demote admin low/high.
 *
 *	Exit	string = Clearance string, or empty string if not
 *			enough preallocated memory.
 *
 *	Returns	-1, If unable to access label encodings database.
 *		 0, If unable to allocate string,
 *			or allocated string to short
 *			(and **string = '\0').
 *		length (including null) of Clearance string,
 *			If successful.
 *
 *	Calls	RPC - LABELS_BSLTOS, BCLHIGH, BCLLOW, BCLTOSL, BLEQUAL,
 *			BLTYPE, SETBSLABEL, UCLNT, memcpy, clnt_call,
 *			clnt_perror, malloc, strcat, strlen.
 *
 *	Uses	ADMIN_HIGH, ADMIN_LOW, clrhigh, clrlow.
 */

ssize_t
bcleartos(const bclear_t *clearance, char **string, size_t str_len,
    int flags)
{
	labeld_data_t	call;
	labeld_data_t	*callp = &call;
	size_t	bufsize = sizeof (labeld_data_t);
	size_t	datasize = CALL_SIZE(bcleartos_call_t, 0);
	int	rval;

	if (!BLTYPE(clearance, SUN_CLR_ID)) {
		return (-1);
	}

	call.callop = BCLEARTOS;
	clrcall.clear = *clearance;
	clrcall.flags = (flags&SHORT_CLASSIFICATION ||
	    !(flags&LONG_CLASSIFICATION)) ? LABELS_SHORT_CLASS : 0;
	clrcall.flags |= (flags&SHORT_WORDS && !(flags&LONG_WORDS)) ?
	    LABELS_SHORT_WORDS : 0;
	set_label_view(&clrcall.flags, flags);

	if ((rval = __call_labeld(&callp, &bufsize, &datasize)) == SUCCESS) {

		if (callp->reterr != 0)
			return (-1);

		/* unpack Clearance */

		rval = return_string(string, str_len, clrret.cslabel);

		if (callp != &call)
			/* release return buffer */
			(void) munmap((void *)callp, bufsize);
		return (rval);
	} else if (rval == NOSERVER) {
		/* server not present */
		/* special case admin_high and admin_low */

		if (!BLTYPE(&clrlow, SUN_CLR_ID)) {
			/* initialize static labels */

			BCLEARLOW(&clrlow);
			BCLEARHIGH(&clrhigh);
		}
		if (BLEQUAL(clearance, &clrlow)) {
			return (return_string(string, str_len, ADMIN_LOW));
		} else if (BLEQUAL(clearance, &clrhigh)) {
			return (return_string(string, str_len, ADMIN_HIGH));
		}
	}
	return (-1);
}  /* bcleartos */
#undef	clrcall
#undef	clrret

/*
 *	sbsltos - Convert Sensitivity Label to canonical clipped form.
 *
 *	Entry	label = Sensitivity Label to be converted.
 *		len = Maximum length of translated string, excluding NULL.
 *		      0, full string.
 *		sstring = address of string to translate into.
 *		ssize = size of memory currently allocated to sstring.
 *
 *	Exit	sstring = Newly translated string.
 *		ssize = Updated if more memory pre-allocated.
 *
 *	Returns	NULL, If error, len too small, unable to translate, or get
 *		      memory for string.
 *		Address of string containing converted value.
 *
 *	Calls	alloc_string, bsltos, strcpy.
 *
 *	Uses	ssize, sstring.
 */

char *
sbsltos(const bslabel_t *label, size_t len)
{
	ssize_t	slen;		/* length including NULL */
	wchar_t *wstring;
	int	wccount;

	if (ssize == 0) {
		/* Allocate string memory. */
		if ((ssize = alloc_string(&sstring, ssize, 's')) == 0)
			/* can't get initial memory for string */
			return (NULL);
	}

again:
	if ((slen = bsltos(label, &sstring, ssize,
	    (SHORT_CLASSIFICATION | LONG_WORDS))) <= 0) {
		/* error in translation */
		if (slen == 0) {
			if (*sstring == '\0') {
				int newsize;
				/* sstring not long enough */
				if ((newsize = alloc_string(&sstring, ssize,
				    's')) == 0) {
					/* Can't get more memory */
					return (NULL);
				}
				ssize += newsize;
				goto again;
			}
		}
		return (NULL);
	}
	if (len == 0) {
		return (sstring);
	} else if (len < MIN_SL_LEN) {
		return (NULL);
	}
	if ((wstring = malloc(slen * sizeof (wchar_t))) == NULL)
		return (NULL);
	if ((wccount = mbstowcs(wstring, sstring, slen - 1)) == -1) {
		free(wstring);
		return (NULL);
	}
	if (wccount > len) {
		wchar_t *clipp = wstring + (len - 2);

		/* Adjust string size to desired length */

		clipp[0] = L'<';
		clipp[1] = L'-';
		clipp[2] = L'\0';

		while (wcstombs(NULL, wstring, 0) >= ssize) {
			int newsize;

			/* sstring not long enough */
			if ((newsize = alloc_string(&sstring, ssize, 's')) ==
			    0) {
				/* Can't get more memory */
				return (NULL);
			}
			ssize += newsize;
		}

		if ((wccount = wcstombs(sstring, wstring, ssize)) == -1) {
			free(wstring);
			return (NULL);
		}
	}
	free(wstring);

	return (sstring);
}  /* sbsltos */

/*
 *	sbcleartos - Convert Clearance to canonical clipped form.
 *
 *	Entry	clearance = Clearance to be converted.
 *		len = Maximum length of translated string, excluding NULL.
 *		      0, full string.
 *		sstring = address of string to translate into.
 *		ssize = size of memory currently allocated to sstring.
 *
 *	Exit	sstring = Newly translated string.
 *		ssize = Updated if more memory pre-allocated.
 *
 *	Returns	NULL, If error, len too small, unable to translate, or get
 *		      memory for string.
 *		Address of string containing converted value.
 *
 *	Calls	alloc_string, bcleartos, strcpy.
 *
 *	Uses	ssize, sstring.
 */

char *
sbcleartos(const bclear_t *clearance, size_t len)
{
	ssize_t	slen;		/* length including NULL */
	wchar_t *wstring;
	int	wccount;

	if (ssize == 0) {
		/* Allocate string memory. */
		if ((ssize = alloc_string(&sstring, ssize, 'c')) == 0)
			/* can't get initial memory for string */
			return (NULL);
	}

again:
	if ((slen = bcleartos(clearance, &sstring, ssize,
	    (SHORT_CLASSIFICATION | LONG_WORDS))) <= 0) {
		/* error in translation */
		if (slen == 0) {
			if (*sstring == '\0') {
				int newsize;
				/* sstring not long enough */
				if ((newsize = alloc_string(&sstring, ssize,
				    'c')) == 0) {
					/* Can't get more memory */
					return (NULL);
				}
				ssize += newsize;
				goto again;
			}
		}
		return (NULL);
	}
	if (len == 0) {
		return (sstring);
	} else if (len < MIN_CLR_LEN) {
		return (NULL);
	}
	if ((wstring = malloc(slen * sizeof (wchar_t))) == NULL)
		return (NULL);
	if ((wccount = mbstowcs(wstring, sstring, slen - 1)) == -1) {
		free(wstring);
		return (NULL);
	}
	if (wccount > len) {
		wchar_t *clipp = wstring + (len - 2);

		/* Adjust string size to desired length */

		clipp[0] = L'<';
		clipp[1] = L'-';
		clipp[2] = L'\0';

		while (wcstombs(NULL, wstring, 0) >= ssize) {
			int newsize;

			/* sstring not long enough */
			if ((newsize = alloc_string(&sstring, ssize, 'c')) ==
			    0) {
				/* Can't get more memory */
				free(wstring);
				return (NULL);
			}
			ssize += newsize;
		}
		if ((wccount = wcstombs(sstring, wstring, ssize)) == -1) {
			free(wstring);
			return (NULL);
		}
	}
	free(wstring);

	return (sstring);
}  /* sbcleartos */