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 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