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 22 struct discover_class_node { 23 char *name; 24 security_class_t value; 25 char **perms; 26 27 struct discover_class_node *next; 28 }; 29 30 static struct discover_class_node *discover_class_cache = NULL; 31 32 static 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 41 static 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 50 static 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 | O_CLOEXEC); 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 148 err4: 149 closedir(dir); 150 for (i=0; i<MAXVECTORS; i++) 151 free(node->perms[i]); 152 err3: 153 free(node->name); 154 err2: 155 free(node->perms); 156 err1: 157 free(node); 158 return NULL; 159 } 160 161 hidden void flush_class_cache(void) 162 { 163 struct discover_class_node *cur = discover_class_cache, *prev = NULL; 164 size_t i; 165 166 while (cur != NULL) { 167 free(cur->name); 168 169 for (i = 0; i < MAXVECTORS; i++) 170 free(cur->perms[i]); 171 172 free(cur->perms); 173 174 prev = cur; 175 cur = cur->next; 176 177 free(prev); 178 } 179 180 discover_class_cache = NULL; 181 } 182 183 security_class_t string_to_security_class(const char *s) 184 { 185 struct discover_class_node *node; 186 187 node = get_class_cache_entry_name(s); 188 if (node == NULL) { 189 node = discover_class(s); 190 191 if (node == NULL) { 192 errno = EINVAL; 193 return 0; 194 } 195 } 196 197 return map_class(node->value); 198 } 199 200 security_class_t mode_to_security_class(mode_t m) { 201 202 if (S_ISREG(m)) 203 return string_to_security_class("file"); 204 if (S_ISDIR(m)) 205 return string_to_security_class("dir"); 206 if (S_ISCHR(m)) 207 return string_to_security_class("chr_file"); 208 if (S_ISBLK(m)) 209 return string_to_security_class("blk_file"); 210 if (S_ISFIFO(m)) 211 return string_to_security_class("fifo_file"); 212 if (S_ISLNK(m)) 213 return string_to_security_class("lnk_file"); 214 if (S_ISSOCK(m)) 215 return string_to_security_class("sock_file"); 216 217 errno=EINVAL; 218 return 0; 219 } 220 221 access_vector_t string_to_av_perm(security_class_t tclass, const char *s) 222 { 223 struct discover_class_node *node; 224 security_class_t kclass = unmap_class(tclass); 225 226 node = get_class_cache_entry_value(kclass); 227 if (node != NULL) { 228 size_t i; 229 for (i=0; i<MAXVECTORS && node->perms[i] != NULL; i++) 230 if (strcmp(node->perms[i],s) == 0) 231 return map_perm(tclass, 1<<i); 232 } 233 234 errno = EINVAL; 235 return 0; 236 } 237 238 const char *security_class_to_string(security_class_t tclass) 239 { 240 struct discover_class_node *node; 241 242 tclass = unmap_class(tclass); 243 244 node = get_class_cache_entry_value(tclass); 245 if (node == NULL) 246 return NULL; 247 else 248 return node->name; 249 } 250 251 const char *security_av_perm_to_string(security_class_t tclass, 252 access_vector_t av) 253 { 254 struct discover_class_node *node; 255 size_t i; 256 257 av = unmap_perm(tclass, av); 258 tclass = unmap_class(tclass); 259 260 node = get_class_cache_entry_value(tclass); 261 if (av && node) 262 for (i = 0; i<MAXVECTORS; i++) 263 if ((1<<i) & av) 264 return node->perms[i]; 265 266 return NULL; 267 } 268 269 int security_av_string(security_class_t tclass, access_vector_t av, char **res) 270 { 271 unsigned int i = 0; 272 size_t len = 5; 273 access_vector_t tmp = av; 274 int rc = 0; 275 const char *str; 276 char *ptr; 277 278 /* first pass computes the required length */ 279 while (tmp) { 280 if (tmp & 1) { 281 str = security_av_perm_to_string(tclass, av & (1<<i)); 282 if (str) 283 len += strlen(str) + 1; 284 else { 285 rc = -1; 286 errno = EINVAL; 287 goto out; 288 } 289 } 290 tmp >>= 1; 291 i++; 292 } 293 294 *res = malloc(len); 295 if (!*res) { 296 rc = -1; 297 goto out; 298 } 299 300 /* second pass constructs the string */ 301 i = 0; 302 tmp = av; 303 ptr = *res; 304 305 if (!av) { 306 sprintf(ptr, "null"); 307 goto out; 308 } 309 310 ptr += sprintf(ptr, "{ "); 311 while (tmp) { 312 if (tmp & 1) 313 ptr += sprintf(ptr, "%s ", security_av_perm_to_string( 314 tclass, av & (1<<i))); 315 tmp >>= 1; 316 i++; 317 } 318 sprintf(ptr, "}"); 319 out: 320 return rc; 321 } 322 323 void print_access_vector(security_class_t tclass, access_vector_t av) 324 { 325 const char *permstr; 326 access_vector_t bit = 1; 327 328 if (av == 0) { 329 printf(" null"); 330 return; 331 } 332 333 printf(" {"); 334 335 while (av) { 336 if (av & bit) { 337 permstr = security_av_perm_to_string(tclass, bit); 338 if (!permstr) 339 break; 340 printf(" %s", permstr); 341 av &= ~bit; 342 } 343 bit <<= 1; 344 } 345 346 if (av) 347 printf(" 0x%x", av); 348 printf(" }"); 349 } 350