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