Home | History | Annotate | Download | only in src
      1 /* Authors: Joshua Brindle <jbrindle (at) tresys.com>
      2  * 	    Jason Tang <jtang (at) tresys.com>
      3  *
      4  * Copyright (C) 2005-2006 Tresys Technology, LLC
      5  *
      6  *  This library is free software; you can redistribute it and/or
      7  *  modify it under the terms of the GNU Lesser General Public
      8  *  License as published by the Free Software Foundation; either
      9  *  version 2.1 of the License, or (at your option) any later version.
     10  *
     11  *  This library is distributed in the hope that it will be useful,
     12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14  *  Lesser General Public License for more details.
     15  *
     16  *  You should have received a copy of the GNU Lesser General Public
     17  *  License along with this library; if not, write to the Free Software
     18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     19  */
     20 
     21 #include <assert.h>
     22 #include <ctype.h>
     23 #include <stdarg.h>
     24 #include <stdio.h>
     25 #include <stdlib.h>
     26 
     27 #include <sepol/policydb/flask_types.h>
     28 #include <sepol/policydb/policydb.h>
     29 #include <sepol/policydb/util.h>
     30 #include <dso.h>
     31 
     32 struct val_to_name {
     33 	unsigned int val;
     34 	char *name;
     35 };
     36 
     37 /* Add an unsigned integer to a dynamically reallocated array.  *cnt
     38  * is a reference pointer to the number of values already within array
     39  * *a; it will be incremented upon successfully appending i.  If *a is
     40  * NULL then this function will create a new array (*cnt is reset to
     41  * 0).  Return 0 on success, -1 on out of memory. */
     42 int add_i_to_a(uint32_t i, uint32_t * cnt, uint32_t ** a)
     43 {
     44 	if (cnt == NULL || a == NULL)
     45 		return -1;
     46 
     47 	/* FIX ME: This is not very elegant! We use an array that we
     48 	 * grow as new uint32_t are added to an array.  But rather
     49 	 * than be smart about it, for now we realloc() the array each
     50 	 * time a new uint32_t is added! */
     51 	if (*a != NULL)
     52 		*a = (uint32_t *) realloc(*a, (*cnt + 1) * sizeof(uint32_t));
     53 	else {			/* empty list */
     54 
     55 		*cnt = 0;
     56 		*a = (uint32_t *) malloc(sizeof(uint32_t));
     57 	}
     58 	if (*a == NULL) {
     59 		return -1;
     60 	}
     61 	(*a)[*cnt] = i;
     62 	(*cnt)++;
     63 	return 0;
     64 }
     65 
     66 static int perm_name(hashtab_key_t key, hashtab_datum_t datum, void *data)
     67 {
     68 	struct val_to_name *v = data;
     69 	perm_datum_t *perdatum;
     70 
     71 	perdatum = (perm_datum_t *) datum;
     72 
     73 	if (v->val == perdatum->s.value) {
     74 		v->name = key;
     75 		return 1;
     76 	}
     77 
     78 	return 0;
     79 }
     80 
     81 char *sepol_av_to_string(policydb_t * policydbp, uint32_t tclass,
     82 			 sepol_access_vector_t av)
     83 {
     84 	struct val_to_name v;
     85 	static char avbuf[1024];
     86 	class_datum_t *cladatum;
     87 	char *perm = NULL, *p;
     88 	unsigned int i;
     89 	int rc;
     90 	int avlen = 0, len;
     91 
     92 	memset(avbuf, 0, sizeof avbuf);
     93 	cladatum = policydbp->class_val_to_struct[tclass - 1];
     94 	p = avbuf;
     95 	for (i = 0; i < cladatum->permissions.nprim; i++) {
     96 		if (av & (1 << i)) {
     97 			v.val = i + 1;
     98 			rc = hashtab_map(cladatum->permissions.table,
     99 					 perm_name, &v);
    100 			if (!rc && cladatum->comdatum) {
    101 				rc = hashtab_map(cladatum->comdatum->
    102 						 permissions.table, perm_name,
    103 						 &v);
    104 			}
    105 			if (rc)
    106 				perm = v.name;
    107 			if (perm) {
    108 				len =
    109 				    snprintf(p, sizeof(avbuf) - avlen, " %s",
    110 					     perm);
    111 				if (len < 0
    112 				    || (size_t) len >= (sizeof(avbuf) - avlen))
    113 					return NULL;
    114 				p += len;
    115 				avlen += len;
    116 			}
    117 		}
    118 	}
    119 
    120 	return avbuf;
    121 }
    122 
    123 #define next_bit_in_range(i, p) ((i + 1 < sizeof(p)*8) && xperm_test((i + 1), p))
    124 
    125 char *sepol_extended_perms_to_string(avtab_extended_perms_t *xperms)
    126 {
    127 	uint16_t value;
    128 	uint16_t low_bit;
    129 	uint16_t low_value;
    130 	unsigned int bit;
    131 	unsigned int in_range = 0;
    132 	static char xpermsbuf[2048];
    133 	xpermsbuf[0] = '\0';
    134 	char *p;
    135 	int len, xpermslen = 0;
    136 	p = xpermsbuf;
    137 
    138 	if ((xperms->specified != AVTAB_XPERMS_IOCTLFUNCTION)
    139 		&& (xperms->specified != AVTAB_XPERMS_IOCTLDRIVER))
    140 		return NULL;
    141 
    142 	len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "ioctl { ");
    143 	p += len;
    144 	xpermslen += len;
    145 
    146 	for (bit = 0; bit < sizeof(xperms->perms)*8; bit++) {
    147 		if (!xperm_test(bit, xperms->perms))
    148 			continue;
    149 
    150 		if (in_range && next_bit_in_range(bit, xperms->perms)) {
    151 			/* continue until high value found */
    152 			continue;
    153 		} else if (next_bit_in_range(bit, xperms->perms)) {
    154 			/* low value */
    155 			low_bit = bit;
    156 			in_range = 1;
    157 			continue;
    158 		}
    159 
    160 		if (xperms->specified & AVTAB_XPERMS_IOCTLFUNCTION) {
    161 			value = xperms->driver<<8 | bit;
    162 			if (in_range) {
    163 				low_value = xperms->driver<<8 | low_bit;
    164 				len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "0x%hx-0x%hx ", low_value, value);
    165 			} else {
    166 				len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "0x%hx ", value);
    167 			}
    168 		} else if (xperms->specified & AVTAB_XPERMS_IOCTLDRIVER) {
    169 			value = bit << 8;
    170 			if (in_range) {
    171 				low_value = low_bit << 8;
    172 				len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "0x%hx-0x%hx ", low_value, (uint16_t) (value|0xff));
    173 			} else {
    174 				len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "0x%hx-0x%hx ", value, (uint16_t) (value|0xff));
    175 			}
    176 
    177 		}
    178 
    179 		if (len < 0 || (size_t) len >= (sizeof(xpermsbuf) - xpermslen))
    180 			return NULL;
    181 
    182 		p += len;
    183 		xpermslen += len;
    184 		if (in_range)
    185 			in_range = 0;
    186 	}
    187 
    188 	len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "}");
    189 	if (len < 0 || (size_t) len >= (sizeof(xpermsbuf) - xpermslen))
    190 		return NULL;
    191 
    192 	return xpermsbuf;
    193 }
    194 
    195 /*
    196  * The tokenize and tokenize_str functions may be used to
    197  * replace sscanf to read tokens from buffers.
    198  */
    199 
    200 /* Read a token from a buffer */
    201 static inline int tokenize_str(char delim, char **str, char **ptr, size_t *len)
    202 {
    203 	char *tmp_buf = *ptr;
    204 	*str = NULL;
    205 
    206 	while (**ptr != '\0') {
    207 		if (isspace(delim) && isspace(**ptr)) {
    208 			(*ptr)++;
    209 			break;
    210 		} else if (!isspace(delim) && **ptr == delim) {
    211 			(*ptr)++;
    212 			break;
    213 		}
    214 
    215 		(*ptr)++;
    216 	}
    217 
    218 	*len = *ptr - tmp_buf;
    219 	/* If the end of the string has not been reached, this will ensure the
    220 	 * delimiter is not included when returning the token.
    221 	 */
    222 	if (**ptr != '\0') {
    223 		(*len)--;
    224 	}
    225 
    226 	*str = strndup(tmp_buf, *len);
    227 	if (!*str) {
    228 		return -1;
    229 	}
    230 
    231 	/* Squash spaces if the delimiter is a whitespace character */
    232 	while (**ptr != '\0' && isspace(delim) && isspace(**ptr)) {
    233 		(*ptr)++;
    234 	}
    235 
    236 	return 0;
    237 }
    238 
    239 /*
    240  * line_buf - Buffer containing string to tokenize.
    241  * delim - The delimiter used to tokenize line_buf. A whitespace delimiter will
    242  *	    be tokenized using isspace().
    243  * num_args - The number of parameter entries to process.
    244  * ...      - A 'char **' for each parameter.
    245  * returns  - The number of items processed.
    246  *
    247  * This function calls tokenize_str() to do the actual string processing. The
    248  * caller is responsible for calling free() on each additional argument. The
    249  * function will not tokenize more than num_args and the last argument will
    250  * contain the remaining content of line_buf. If the delimiter is any whitespace
    251  * character, then all whitespace will be squashed.
    252  */
    253 int hidden tokenize(char *line_buf, char delim, int num_args, ...)
    254 {
    255 	char **arg, *buf_p;
    256 	int rc, items;
    257 	size_t arg_len = 0;
    258 	va_list ap;
    259 
    260 	buf_p = line_buf;
    261 
    262 	/* Process the arguments */
    263 	va_start(ap, num_args);
    264 
    265 	for (items = 0; items < num_args && *buf_p != '\0'; items++) {
    266 		arg = va_arg(ap, char **);
    267 
    268 		/* Save the remainder of the string in arg */
    269 		if (items == num_args - 1) {
    270 			*arg = strdup(buf_p);
    271 			if (*arg == NULL) {
    272 				goto exit;
    273 			}
    274 
    275 			continue;
    276 		}
    277 
    278 		rc = tokenize_str(delim, arg, &buf_p, &arg_len);
    279 		if (rc < 0) {
    280 			goto exit;
    281 		}
    282 	}
    283 
    284 exit:
    285 	va_end(ap);
    286 	return items;
    287 }
    288