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