/* Authors: Joshua Brindle <jbrindle@tresys.com> * Jason Tang <jtang@tresys.com> * * Copyright (C) 2005-2006 Tresys Technology, LLC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include <assert.h> #include <ctype.h> #include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <sepol/policydb/flask_types.h> #include <sepol/policydb/policydb.h> #include <sepol/policydb/util.h> #include <dso.h> struct val_to_name { unsigned int val; char *name; }; /* Add an unsigned integer to a dynamically reallocated array. *cnt * is a reference pointer to the number of values already within array * *a; it will be incremented upon successfully appending i. If *a is * NULL then this function will create a new array (*cnt is reset to * 0). Return 0 on success, -1 on out of memory. */ int add_i_to_a(uint32_t i, uint32_t * cnt, uint32_t ** a) { if (cnt == NULL || a == NULL) return -1; /* FIX ME: This is not very elegant! We use an array that we * grow as new uint32_t are added to an array. But rather * than be smart about it, for now we realloc() the array each * time a new uint32_t is added! */ if (*a != NULL) *a = (uint32_t *) realloc(*a, (*cnt + 1) * sizeof(uint32_t)); else { /* empty list */ *cnt = 0; *a = (uint32_t *) malloc(sizeof(uint32_t)); } if (*a == NULL) { return -1; } (*a)[*cnt] = i; (*cnt)++; return 0; } static int perm_name(hashtab_key_t key, hashtab_datum_t datum, void *data) { struct val_to_name *v = data; perm_datum_t *perdatum; perdatum = (perm_datum_t *) datum; if (v->val == perdatum->s.value) { v->name = key; return 1; } return 0; } char *sepol_av_to_string(policydb_t * policydbp, uint32_t tclass, sepol_access_vector_t av) { struct val_to_name v; static char avbuf[1024]; class_datum_t *cladatum; char *perm = NULL, *p; unsigned int i; int rc; int avlen = 0, len; memset(avbuf, 0, sizeof avbuf); cladatum = policydbp->class_val_to_struct[tclass - 1]; p = avbuf; for (i = 0; i < cladatum->permissions.nprim; i++) { if (av & (1 << i)) { v.val = i + 1; rc = hashtab_map(cladatum->permissions.table, perm_name, &v); if (!rc && cladatum->comdatum) { rc = hashtab_map(cladatum->comdatum-> permissions.table, perm_name, &v); } if (rc) perm = v.name; if (perm) { len = snprintf(p, sizeof(avbuf) - avlen, " %s", perm); if (len < 0 || (size_t) len >= (sizeof(avbuf) - avlen)) return NULL; p += len; avlen += len; } } } return avbuf; } #define next_bit_in_range(i, p) ((i + 1 < sizeof(p)*8) && xperm_test((i + 1), p)) char *sepol_extended_perms_to_string(avtab_extended_perms_t *xperms) { uint16_t value; uint16_t low_bit; uint16_t low_value; unsigned int bit; unsigned int in_range = 0; static char xpermsbuf[2048]; xpermsbuf[0] = '\0'; char *p; int len, xpermslen = 0; p = xpermsbuf; if ((xperms->specified != AVTAB_XPERMS_IOCTLFUNCTION) && (xperms->specified != AVTAB_XPERMS_IOCTLDRIVER)) return NULL; len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "ioctl { "); p += len; xpermslen += len; for (bit = 0; bit < sizeof(xperms->perms)*8; bit++) { if (!xperm_test(bit, xperms->perms)) continue; if (in_range && next_bit_in_range(bit, xperms->perms)) { /* continue until high value found */ continue; } else if (next_bit_in_range(bit, xperms->perms)) { /* low value */ low_bit = bit; in_range = 1; continue; } if (xperms->specified & AVTAB_XPERMS_IOCTLFUNCTION) { value = xperms->driver<<8 | bit; if (in_range) { low_value = xperms->driver<<8 | low_bit; len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "0x%hx-0x%hx ", low_value, value); } else { len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "0x%hx ", value); } } else if (xperms->specified & AVTAB_XPERMS_IOCTLDRIVER) { value = bit << 8; if (in_range) { low_value = low_bit << 8; len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "0x%hx-0x%hx ", low_value, (uint16_t) (value|0xff)); } else { len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "0x%hx-0x%hx ", value, (uint16_t) (value|0xff)); } } if (len < 0 || (size_t) len >= (sizeof(xpermsbuf) - xpermslen)) return NULL; p += len; xpermslen += len; if (in_range) in_range = 0; } len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "}"); if (len < 0 || (size_t) len >= (sizeof(xpermsbuf) - xpermslen)) return NULL; return xpermsbuf; } /* * The tokenize and tokenize_str functions may be used to * replace sscanf to read tokens from buffers. */ /* Read a token from a buffer */ static inline int tokenize_str(char delim, char **str, char **ptr, size_t *len) { char *tmp_buf = *ptr; *str = NULL; while (**ptr != '\0') { if (isspace(delim) && isspace(**ptr)) { (*ptr)++; break; } else if (!isspace(delim) && **ptr == delim) { (*ptr)++; break; } (*ptr)++; } *len = *ptr - tmp_buf; /* If the end of the string has not been reached, this will ensure the * delimiter is not included when returning the token. */ if (**ptr != '\0') { (*len)--; } *str = strndup(tmp_buf, *len); if (!*str) { return -1; } /* Squash spaces if the delimiter is a whitespace character */ while (**ptr != '\0' && isspace(delim) && isspace(**ptr)) { (*ptr)++; } return 0; } /* * line_buf - Buffer containing string to tokenize. * delim - The delimiter used to tokenize line_buf. A whitespace delimiter will * be tokenized using isspace(). * num_args - The number of parameter entries to process. * ... - A 'char **' for each parameter. * returns - The number of items processed. * * This function calls tokenize_str() to do the actual string processing. The * caller is responsible for calling free() on each additional argument. The * function will not tokenize more than num_args and the last argument will * contain the remaining content of line_buf. If the delimiter is any whitespace * character, then all whitespace will be squashed. */ int hidden tokenize(char *line_buf, char delim, int num_args, ...) { char **arg, *buf_p; int rc, items; size_t arg_len = 0; va_list ap; buf_p = line_buf; /* Process the arguments */ va_start(ap, num_args); for (items = 0; items < num_args && *buf_p != '\0'; items++) { arg = va_arg(ap, char **); /* Save the remainder of the string in arg */ if (items == num_args - 1) { *arg = strdup(buf_p); if (*arg == NULL) { goto exit; } continue; } rc = tokenize_str(delim, arg, &buf_p, &arg_len); if (rc < 0) { goto exit; } } exit: va_end(ap); return items; }