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