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