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