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