16cd6a6acSopenharmony_ci/* Authors: Joshua Brindle <jbrindle@tresys.com>
26cd6a6acSopenharmony_ci * 	    Jason Tang <jtang@tresys.com>
36cd6a6acSopenharmony_ci *
46cd6a6acSopenharmony_ci * Copyright (C) 2005-2006 Tresys Technology, LLC
56cd6a6acSopenharmony_ci *
66cd6a6acSopenharmony_ci *  This library is free software; you can redistribute it and/or
76cd6a6acSopenharmony_ci *  modify it under the terms of the GNU Lesser General Public
86cd6a6acSopenharmony_ci *  License as published by the Free Software Foundation; either
96cd6a6acSopenharmony_ci *  version 2.1 of the License, or (at your option) any later version.
106cd6a6acSopenharmony_ci *
116cd6a6acSopenharmony_ci *  This library is distributed in the hope that it will be useful,
126cd6a6acSopenharmony_ci *  but WITHOUT ANY WARRANTY; without even the implied warranty of
136cd6a6acSopenharmony_ci *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
146cd6a6acSopenharmony_ci *  Lesser General Public License for more details.
156cd6a6acSopenharmony_ci *
166cd6a6acSopenharmony_ci *  You should have received a copy of the GNU Lesser General Public
176cd6a6acSopenharmony_ci *  License along with this library; if not, write to the Free Software
186cd6a6acSopenharmony_ci *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
196cd6a6acSopenharmony_ci */
206cd6a6acSopenharmony_ci
216cd6a6acSopenharmony_ci#include <assert.h>
226cd6a6acSopenharmony_ci#include <ctype.h>
236cd6a6acSopenharmony_ci#include <stdarg.h>
246cd6a6acSopenharmony_ci#include <stdio.h>
256cd6a6acSopenharmony_ci#include <stdlib.h>
266cd6a6acSopenharmony_ci
276cd6a6acSopenharmony_ci#include <sepol/policydb/flask_types.h>
286cd6a6acSopenharmony_ci#include <sepol/policydb/policydb.h>
296cd6a6acSopenharmony_ci#include <sepol/policydb/util.h>
306cd6a6acSopenharmony_ci
316cd6a6acSopenharmony_ci#include "private.h"
326cd6a6acSopenharmony_ci
336cd6a6acSopenharmony_cistruct val_to_name {
346cd6a6acSopenharmony_ci	unsigned int val;
356cd6a6acSopenharmony_ci	char *name;
366cd6a6acSopenharmony_ci};
376cd6a6acSopenharmony_ci
386cd6a6acSopenharmony_ci/* Add an unsigned integer to a dynamically reallocated array.  *cnt
396cd6a6acSopenharmony_ci * is a reference pointer to the number of values already within array
406cd6a6acSopenharmony_ci * *a; it will be incremented upon successfully appending i.  If *a is
416cd6a6acSopenharmony_ci * NULL then this function will create a new array (*cnt is reset to
426cd6a6acSopenharmony_ci * 0).  Return 0 on success, -1 on out of memory. */
436cd6a6acSopenharmony_ciint add_i_to_a(uint32_t i, uint32_t * cnt, uint32_t ** a)
446cd6a6acSopenharmony_ci{
456cd6a6acSopenharmony_ci	uint32_t *new;
466cd6a6acSopenharmony_ci
476cd6a6acSopenharmony_ci	if (cnt == NULL || a == NULL)
486cd6a6acSopenharmony_ci		return -1;
496cd6a6acSopenharmony_ci
506cd6a6acSopenharmony_ci	/* FIX ME: This is not very elegant! We use an array that we
516cd6a6acSopenharmony_ci	 * grow as new uint32_t are added to an array.  But rather
526cd6a6acSopenharmony_ci	 * than be smart about it, for now we realloc() the array each
536cd6a6acSopenharmony_ci	 * time a new uint32_t is added! */
546cd6a6acSopenharmony_ci	if (*a != NULL)
556cd6a6acSopenharmony_ci		new = (uint32_t *) reallocarray(*a, *cnt + 1, sizeof(uint32_t));
566cd6a6acSopenharmony_ci	else {			/* empty list */
576cd6a6acSopenharmony_ci
586cd6a6acSopenharmony_ci		*cnt = 0;
596cd6a6acSopenharmony_ci		new = (uint32_t *) malloc(sizeof(uint32_t));
606cd6a6acSopenharmony_ci	}
616cd6a6acSopenharmony_ci	if (new == NULL) {
626cd6a6acSopenharmony_ci		return -1;
636cd6a6acSopenharmony_ci	}
646cd6a6acSopenharmony_ci	new[*cnt] = i;
656cd6a6acSopenharmony_ci	(*cnt)++;
666cd6a6acSopenharmony_ci	*a = new;
676cd6a6acSopenharmony_ci	return 0;
686cd6a6acSopenharmony_ci}
696cd6a6acSopenharmony_ci
706cd6a6acSopenharmony_cistatic int perm_name(hashtab_key_t key, hashtab_datum_t datum, void *data)
716cd6a6acSopenharmony_ci{
726cd6a6acSopenharmony_ci	struct val_to_name *v = data;
736cd6a6acSopenharmony_ci	perm_datum_t *perdatum;
746cd6a6acSopenharmony_ci
756cd6a6acSopenharmony_ci	perdatum = (perm_datum_t *) datum;
766cd6a6acSopenharmony_ci
776cd6a6acSopenharmony_ci	if (v->val == perdatum->s.value) {
786cd6a6acSopenharmony_ci		v->name = key;
796cd6a6acSopenharmony_ci		return 1;
806cd6a6acSopenharmony_ci	}
816cd6a6acSopenharmony_ci
826cd6a6acSopenharmony_ci	return 0;
836cd6a6acSopenharmony_ci}
846cd6a6acSopenharmony_ci
856cd6a6acSopenharmony_cichar *sepol_av_to_string(policydb_t * policydbp, uint32_t tclass,
866cd6a6acSopenharmony_ci			 sepol_access_vector_t av)
876cd6a6acSopenharmony_ci{
886cd6a6acSopenharmony_ci	struct val_to_name v;
896cd6a6acSopenharmony_ci	static char avbuf[1024];
906cd6a6acSopenharmony_ci	class_datum_t *cladatum;
916cd6a6acSopenharmony_ci	char *perm = NULL, *p;
926cd6a6acSopenharmony_ci	unsigned int i;
936cd6a6acSopenharmony_ci	int rc;
946cd6a6acSopenharmony_ci	int avlen = 0, len;
956cd6a6acSopenharmony_ci
966cd6a6acSopenharmony_ci	memset(avbuf, 0, sizeof avbuf);
976cd6a6acSopenharmony_ci	cladatum = policydbp->class_val_to_struct[tclass - 1];
986cd6a6acSopenharmony_ci	p = avbuf;
996cd6a6acSopenharmony_ci	for (i = 0; i < cladatum->permissions.nprim; i++) {
1006cd6a6acSopenharmony_ci		if (av & (UINT32_C(1) << i)) {
1016cd6a6acSopenharmony_ci			v.val = i + 1;
1026cd6a6acSopenharmony_ci			rc = hashtab_map(cladatum->permissions.table,
1036cd6a6acSopenharmony_ci					 perm_name, &v);
1046cd6a6acSopenharmony_ci			if (!rc && cladatum->comdatum) {
1056cd6a6acSopenharmony_ci				rc = hashtab_map(cladatum->comdatum->
1066cd6a6acSopenharmony_ci						 permissions.table, perm_name,
1076cd6a6acSopenharmony_ci						 &v);
1086cd6a6acSopenharmony_ci			}
1096cd6a6acSopenharmony_ci			if (rc)
1106cd6a6acSopenharmony_ci				perm = v.name;
1116cd6a6acSopenharmony_ci			if (perm) {
1126cd6a6acSopenharmony_ci				len =
1136cd6a6acSopenharmony_ci				    snprintf(p, sizeof(avbuf) - avlen, " %s",
1146cd6a6acSopenharmony_ci					     perm);
1156cd6a6acSopenharmony_ci				if (len < 0
1166cd6a6acSopenharmony_ci				    || (size_t) len >= (sizeof(avbuf) - avlen))
1176cd6a6acSopenharmony_ci					return NULL;
1186cd6a6acSopenharmony_ci				p += len;
1196cd6a6acSopenharmony_ci				avlen += len;
1206cd6a6acSopenharmony_ci			}
1216cd6a6acSopenharmony_ci		}
1226cd6a6acSopenharmony_ci	}
1236cd6a6acSopenharmony_ci
1246cd6a6acSopenharmony_ci	return avbuf;
1256cd6a6acSopenharmony_ci}
1266cd6a6acSopenharmony_ci
1276cd6a6acSopenharmony_ci#define next_bit_in_range(i, p) (((i) + 1 < sizeof(p)*8) && xperm_test(((i) + 1), p))
1286cd6a6acSopenharmony_ci
1296cd6a6acSopenharmony_cichar *sepol_extended_perms_to_string(avtab_extended_perms_t *xperms)
1306cd6a6acSopenharmony_ci{
1316cd6a6acSopenharmony_ci	uint16_t value;
1326cd6a6acSopenharmony_ci	uint16_t low_bit;
1336cd6a6acSopenharmony_ci	uint16_t low_value;
1346cd6a6acSopenharmony_ci	unsigned int bit;
1356cd6a6acSopenharmony_ci	unsigned int in_range = 0;
1366cd6a6acSopenharmony_ci	static char xpermsbuf[2048];
1376cd6a6acSopenharmony_ci	char *p;
1386cd6a6acSopenharmony_ci	int len, xpermslen = 0;
1396cd6a6acSopenharmony_ci	xpermsbuf[0] = '\0';
1406cd6a6acSopenharmony_ci	p = xpermsbuf;
1416cd6a6acSopenharmony_ci
1426cd6a6acSopenharmony_ci	if ((xperms->specified != AVTAB_XPERMS_IOCTLFUNCTION)
1436cd6a6acSopenharmony_ci		&& (xperms->specified != AVTAB_XPERMS_IOCTLDRIVER))
1446cd6a6acSopenharmony_ci		return NULL;
1456cd6a6acSopenharmony_ci
1466cd6a6acSopenharmony_ci	len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "ioctl { ");
1476cd6a6acSopenharmony_ci	p += len;
1486cd6a6acSopenharmony_ci	xpermslen += len;
1496cd6a6acSopenharmony_ci
1506cd6a6acSopenharmony_ci	for (bit = 0; bit < sizeof(xperms->perms)*8; bit++) {
1516cd6a6acSopenharmony_ci		if (!xperm_test(bit, xperms->perms))
1526cd6a6acSopenharmony_ci			continue;
1536cd6a6acSopenharmony_ci
1546cd6a6acSopenharmony_ci		if (in_range && next_bit_in_range(bit, xperms->perms)) {
1556cd6a6acSopenharmony_ci			/* continue until high value found */
1566cd6a6acSopenharmony_ci			continue;
1576cd6a6acSopenharmony_ci		} else if (next_bit_in_range(bit, xperms->perms)) {
1586cd6a6acSopenharmony_ci			/* low value */
1596cd6a6acSopenharmony_ci			low_bit = bit;
1606cd6a6acSopenharmony_ci			in_range = 1;
1616cd6a6acSopenharmony_ci			continue;
1626cd6a6acSopenharmony_ci		}
1636cd6a6acSopenharmony_ci
1646cd6a6acSopenharmony_ci		if (xperms->specified & AVTAB_XPERMS_IOCTLFUNCTION) {
1656cd6a6acSopenharmony_ci			value = xperms->driver<<8 | bit;
1666cd6a6acSopenharmony_ci			if (in_range) {
1676cd6a6acSopenharmony_ci				low_value = xperms->driver<<8 | low_bit;
1686cd6a6acSopenharmony_ci				len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "0x%hx-0x%hx ", low_value, value);
1696cd6a6acSopenharmony_ci			} else {
1706cd6a6acSopenharmony_ci				len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "0x%hx ", value);
1716cd6a6acSopenharmony_ci			}
1726cd6a6acSopenharmony_ci		} else if (xperms->specified & AVTAB_XPERMS_IOCTLDRIVER) {
1736cd6a6acSopenharmony_ci			value = bit << 8;
1746cd6a6acSopenharmony_ci			if (in_range) {
1756cd6a6acSopenharmony_ci				low_value = low_bit << 8;
1766cd6a6acSopenharmony_ci				len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "0x%hx-0x%hx ", low_value, (uint16_t) (value|0xff));
1776cd6a6acSopenharmony_ci			} else {
1786cd6a6acSopenharmony_ci				len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "0x%hx-0x%hx ", value, (uint16_t) (value|0xff));
1796cd6a6acSopenharmony_ci			}
1806cd6a6acSopenharmony_ci
1816cd6a6acSopenharmony_ci		}
1826cd6a6acSopenharmony_ci
1836cd6a6acSopenharmony_ci		if (len < 0 || (size_t) len >= (sizeof(xpermsbuf) - xpermslen))
1846cd6a6acSopenharmony_ci			return NULL;
1856cd6a6acSopenharmony_ci
1866cd6a6acSopenharmony_ci		p += len;
1876cd6a6acSopenharmony_ci		xpermslen += len;
1886cd6a6acSopenharmony_ci		if (in_range)
1896cd6a6acSopenharmony_ci			in_range = 0;
1906cd6a6acSopenharmony_ci	}
1916cd6a6acSopenharmony_ci
1926cd6a6acSopenharmony_ci	len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "}");
1936cd6a6acSopenharmony_ci	if (len < 0 || (size_t) len >= (sizeof(xpermsbuf) - xpermslen))
1946cd6a6acSopenharmony_ci		return NULL;
1956cd6a6acSopenharmony_ci
1966cd6a6acSopenharmony_ci	return xpermsbuf;
1976cd6a6acSopenharmony_ci}
1986cd6a6acSopenharmony_ci
1996cd6a6acSopenharmony_ci/*
2006cd6a6acSopenharmony_ci * The tokenize and tokenize_str functions may be used to
2016cd6a6acSopenharmony_ci * replace sscanf to read tokens from buffers.
2026cd6a6acSopenharmony_ci */
2036cd6a6acSopenharmony_ci
2046cd6a6acSopenharmony_ci/* Read a token from a buffer */
2056cd6a6acSopenharmony_cistatic inline int tokenize_str(char delim, char **str, char **ptr, size_t *len)
2066cd6a6acSopenharmony_ci{
2076cd6a6acSopenharmony_ci	char *tmp_buf = *ptr;
2086cd6a6acSopenharmony_ci	*str = NULL;
2096cd6a6acSopenharmony_ci
2106cd6a6acSopenharmony_ci	while (**ptr != '\0') {
2116cd6a6acSopenharmony_ci		if (isspace(delim) && isspace(**ptr)) {
2126cd6a6acSopenharmony_ci			(*ptr)++;
2136cd6a6acSopenharmony_ci			break;
2146cd6a6acSopenharmony_ci		} else if (!isspace(delim) && **ptr == delim) {
2156cd6a6acSopenharmony_ci			(*ptr)++;
2166cd6a6acSopenharmony_ci			break;
2176cd6a6acSopenharmony_ci		}
2186cd6a6acSopenharmony_ci
2196cd6a6acSopenharmony_ci		(*ptr)++;
2206cd6a6acSopenharmony_ci	}
2216cd6a6acSopenharmony_ci
2226cd6a6acSopenharmony_ci	*len = *ptr - tmp_buf;
2236cd6a6acSopenharmony_ci	/* If the end of the string has not been reached, this will ensure the
2246cd6a6acSopenharmony_ci	 * delimiter is not included when returning the token.
2256cd6a6acSopenharmony_ci	 */
2266cd6a6acSopenharmony_ci	if (**ptr != '\0') {
2276cd6a6acSopenharmony_ci		(*len)--;
2286cd6a6acSopenharmony_ci	}
2296cd6a6acSopenharmony_ci
2306cd6a6acSopenharmony_ci	*str = strndup(tmp_buf, *len);
2316cd6a6acSopenharmony_ci	if (!*str) {
2326cd6a6acSopenharmony_ci		return -1;
2336cd6a6acSopenharmony_ci	}
2346cd6a6acSopenharmony_ci
2356cd6a6acSopenharmony_ci	/* Squash spaces if the delimiter is a whitespace character */
2366cd6a6acSopenharmony_ci	while (**ptr != '\0' && isspace(delim) && isspace(**ptr)) {
2376cd6a6acSopenharmony_ci		(*ptr)++;
2386cd6a6acSopenharmony_ci	}
2396cd6a6acSopenharmony_ci
2406cd6a6acSopenharmony_ci	return 0;
2416cd6a6acSopenharmony_ci}
2426cd6a6acSopenharmony_ci
2436cd6a6acSopenharmony_ci/*
2446cd6a6acSopenharmony_ci * line_buf - Buffer containing string to tokenize.
2456cd6a6acSopenharmony_ci * delim - The delimiter used to tokenize line_buf. A whitespace delimiter will
2466cd6a6acSopenharmony_ci *	    be tokenized using isspace().
2476cd6a6acSopenharmony_ci * num_args - The number of parameter entries to process.
2486cd6a6acSopenharmony_ci * ...      - A 'char **' for each parameter.
2496cd6a6acSopenharmony_ci * returns  - The number of items processed.
2506cd6a6acSopenharmony_ci *
2516cd6a6acSopenharmony_ci * This function calls tokenize_str() to do the actual string processing. The
2526cd6a6acSopenharmony_ci * caller is responsible for calling free() on each additional argument. The
2536cd6a6acSopenharmony_ci * function will not tokenize more than num_args and the last argument will
2546cd6a6acSopenharmony_ci * contain the remaining content of line_buf. If the delimiter is any whitespace
2556cd6a6acSopenharmony_ci * character, then all whitespace will be squashed.
2566cd6a6acSopenharmony_ci */
2576cd6a6acSopenharmony_ciint tokenize(char *line_buf, char delim, int num_args, ...)
2586cd6a6acSopenharmony_ci{
2596cd6a6acSopenharmony_ci	char **arg, *buf_p;
2606cd6a6acSopenharmony_ci	int rc, items;
2616cd6a6acSopenharmony_ci	size_t arg_len = 0;
2626cd6a6acSopenharmony_ci	va_list ap;
2636cd6a6acSopenharmony_ci
2646cd6a6acSopenharmony_ci	buf_p = line_buf;
2656cd6a6acSopenharmony_ci
2666cd6a6acSopenharmony_ci	/* Process the arguments */
2676cd6a6acSopenharmony_ci	va_start(ap, num_args);
2686cd6a6acSopenharmony_ci
2696cd6a6acSopenharmony_ci	for (items = 0; items < num_args && *buf_p != '\0'; items++) {
2706cd6a6acSopenharmony_ci		arg = va_arg(ap, char **);
2716cd6a6acSopenharmony_ci
2726cd6a6acSopenharmony_ci		/* Save the remainder of the string in arg */
2736cd6a6acSopenharmony_ci		if (items == num_args - 1) {
2746cd6a6acSopenharmony_ci			*arg = strdup(buf_p);
2756cd6a6acSopenharmony_ci			if (*arg == NULL) {
2766cd6a6acSopenharmony_ci				goto exit;
2776cd6a6acSopenharmony_ci			}
2786cd6a6acSopenharmony_ci
2796cd6a6acSopenharmony_ci			continue;
2806cd6a6acSopenharmony_ci		}
2816cd6a6acSopenharmony_ci
2826cd6a6acSopenharmony_ci		rc = tokenize_str(delim, arg, &buf_p, &arg_len);
2836cd6a6acSopenharmony_ci		if (rc < 0) {
2846cd6a6acSopenharmony_ci			goto exit;
2856cd6a6acSopenharmony_ci		}
2866cd6a6acSopenharmony_ci	}
2876cd6a6acSopenharmony_ci
2886cd6a6acSopenharmony_ciexit:
2896cd6a6acSopenharmony_ci	va_end(ap);
2906cd6a6acSopenharmony_ci	return items;
2916cd6a6acSopenharmony_ci}
292