| /* Authors: Joshua Brindle <[email protected]> |
| * Jason Tang <[email protected]> |
| * |
| * 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 "private.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) |
| { |
| uint32_t *new; |
| |
| 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) |
| new = (uint32_t *) reallocarray(*a, *cnt + 1, sizeof(uint32_t)); |
| else { /* empty list */ |
| |
| *cnt = 0; |
| new = (uint32_t *) malloc(sizeof(uint32_t)); |
| } |
| if (new == NULL) { |
| return -1; |
| } |
| new[*cnt] = i; |
| (*cnt)++; |
| *a = new; |
| 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 & (UINT32_C(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]; |
| char *p; |
| int len, xpermslen = 0; |
| xpermsbuf[0] = '\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 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; |
| } |