Home | History | Annotate | Download | only in src
      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