1/* 2 * String representation support for classes and permissions. 3 */ 4#include <sys/stat.h> 5#include <dirent.h> 6#include <fcntl.h> 7#include <limits.h> 8#include <unistd.h> 9#include <errno.h> 10#include <stddef.h> 11#include <stdio.h> 12#include <stdlib.h> 13#include <string.h> 14#include <stdint.h> 15#include <ctype.h> 16#include "selinux_internal.h" 17#include "policy.h" 18#include "mapping.h" 19 20#define MAXVECTORS 8*sizeof(access_vector_t) 21 22struct discover_class_node { 23 char *name; 24 security_class_t value; 25 char **perms; 26 27 struct discover_class_node *next; 28}; 29 30static struct discover_class_node *discover_class_cache = NULL; 31 32static struct discover_class_node * get_class_cache_entry_name(const char *s) 33{ 34 struct discover_class_node *node = discover_class_cache; 35 36 for (; node != NULL && strcmp(s,node->name) != 0; node = node->next); 37 38 return node; 39} 40 41static struct discover_class_node * get_class_cache_entry_value(security_class_t c) 42{ 43 struct discover_class_node *node = discover_class_cache; 44 45 for (; node != NULL && c != node->value; node = node->next); 46 47 return node; 48} 49 50static struct discover_class_node * discover_class(const char *s) 51{ 52 int fd, ret; 53 char path[PATH_MAX]; 54 char buf[20]; 55 DIR *dir; 56 struct dirent *dentry; 57 size_t i; 58 59 struct discover_class_node *node; 60 61 if (!selinux_mnt) { 62 errno = ENOENT; 63 return NULL; 64 } 65 66 /* allocate a node */ 67 node = malloc(sizeof(struct discover_class_node)); 68 if (node == NULL) 69 return NULL; 70 71 /* allocate array for perms */ 72 node->perms = calloc(MAXVECTORS,sizeof(char*)); 73 if (node->perms == NULL) 74 goto err1; 75 76 /* load up the name */ 77 node->name = strdup(s); 78 if (node->name == NULL) 79 goto err2; 80 81 /* load up class index */ 82 snprintf(path, sizeof path, "%s/class/%s/index", selinux_mnt,s); 83 fd = open(path, O_RDONLY); 84 if (fd < 0) 85 goto err3; 86 87 memset(buf, 0, sizeof(buf)); 88 ret = read(fd, buf, sizeof(buf) - 1); 89 close(fd); 90 if (ret < 0) 91 goto err3; 92 93 if (sscanf(buf, "%hu", &node->value) != 1) 94 goto err3; 95 96 /* load up permission indicies */ 97 snprintf(path, sizeof path, "%s/class/%s/perms",selinux_mnt,s); 98 dir = opendir(path); 99 if (dir == NULL) 100 goto err3; 101 102 dentry = readdir(dir); 103 while (dentry != NULL) { 104 unsigned int value; 105 struct stat m; 106 107 snprintf(path, sizeof path, "%s/class/%s/perms/%s", selinux_mnt,s,dentry->d_name); 108 fd = open(path, O_RDONLY | O_CLOEXEC); 109 if (fd < 0) 110 goto err4; 111 112 if (fstat(fd, &m) < 0) { 113 close(fd); 114 goto err4; 115 } 116 117 if (m.st_mode & S_IFDIR) { 118 close(fd); 119 dentry = readdir(dir); 120 continue; 121 } 122 123 memset(buf, 0, sizeof(buf)); 124 ret = read(fd, buf, sizeof(buf) - 1); 125 close(fd); 126 if (ret < 0) 127 goto err4; 128 129 if (sscanf(buf, "%u", &value) != 1) 130 goto err4; 131 132 if (value == 0 || value > MAXVECTORS) 133 goto err4; 134 135 node->perms[value-1] = strdup(dentry->d_name); 136 if (node->perms[value-1] == NULL) 137 goto err4; 138 139 dentry = readdir(dir); 140 } 141 closedir(dir); 142 143 node->next = discover_class_cache; 144 discover_class_cache = node; 145 146 return node; 147 148err4: 149 closedir(dir); 150 for (i=0; i<MAXVECTORS; i++) 151 free(node->perms[i]); 152err3: 153 free(node->name); 154err2: 155 free(node->perms); 156err1: 157 free(node); 158 return NULL; 159} 160 161security_class_t string_to_security_class(const char *s) 162{ 163 struct discover_class_node *node; 164 165 node = get_class_cache_entry_name(s); 166 if (node == NULL) { 167 node = discover_class(s); 168 169 if (node == NULL) { 170 errno = EINVAL; 171 return 0; 172 } 173 } 174 175 return map_class(node->value); 176} 177 178access_vector_t string_to_av_perm(security_class_t tclass, const char *s) 179{ 180 struct discover_class_node *node; 181 security_class_t kclass = unmap_class(tclass); 182 183 node = get_class_cache_entry_value(kclass); 184 if (node != NULL) { 185 size_t i; 186 for (i=0; i<MAXVECTORS && node->perms[i] != NULL; i++) 187 if (strcmp(node->perms[i],s) == 0) 188 return map_perm(tclass, 1<<i); 189 } 190 191 errno = EINVAL; 192 return 0; 193} 194 195const char *security_class_to_string(security_class_t tclass) 196{ 197 struct discover_class_node *node; 198 199 tclass = unmap_class(tclass); 200 201 node = get_class_cache_entry_value(tclass); 202 if (node) 203 return node->name; 204 return NULL; 205} 206 207const char *security_av_perm_to_string(security_class_t tclass, 208 access_vector_t av) 209{ 210 struct discover_class_node *node; 211 size_t i; 212 213 av = unmap_perm(tclass, av); 214 tclass = unmap_class(tclass); 215 216 node = get_class_cache_entry_value(tclass); 217 if (av && node) 218 for (i = 0; i<MAXVECTORS; i++) 219 if ((1<<i) & av) 220 return node->perms[i]; 221 222 return NULL; 223} 224 225int security_av_string(security_class_t tclass, access_vector_t av, char **res) 226{ 227 unsigned int i = 0; 228 size_t len = 5; 229 access_vector_t tmp = av; 230 int rc = 0; 231 const char *str; 232 char *ptr; 233 234 /* first pass computes the required length */ 235 while (tmp) { 236 if (tmp & 1) { 237 str = security_av_perm_to_string(tclass, av & (1<<i)); 238 if (str) 239 len += strlen(str) + 1; 240 else { 241 rc = -1; 242 errno = EINVAL; 243 goto out; 244 } 245 } 246 tmp >>= 1; 247 i++; 248 } 249 250 *res = malloc(len); 251 if (!*res) { 252 rc = -1; 253 goto out; 254 } 255 256 /* second pass constructs the string */ 257 i = 0; 258 tmp = av; 259 ptr = *res; 260 261 if (!av) { 262 sprintf(ptr, "null"); 263 goto out; 264 } 265 266 ptr += sprintf(ptr, "{ "); 267 while (tmp) { 268 if (tmp & 1) 269 ptr += sprintf(ptr, "%s ", security_av_perm_to_string( 270 tclass, av & (1<<i))); 271 tmp >>= 1; 272 i++; 273 } 274 sprintf(ptr, "}"); 275out: 276 return rc; 277} 278