1 /*
2  * Author: Karl MacMillan <kmacmillan@tresys.com>
3  *
4  * Modified:
5  *   Dan Walsh <dwalsh@redhat.com> - Added security_load_booleans().
6  */
7 
8 #include <sys/types.h>
9 #include <sys/stat.h>
10 #include <fcntl.h>
11 #include <assert.h>
12 #include <stdlib.h>
13 #include <dirent.h>
14 #include <string.h>
15 #include <stdio.h>
16 #include <unistd.h>
17 #include <fnmatch.h>
18 #include <limits.h>
19 #include <ctype.h>
20 #include <errno.h>
21 
22 #include "selinux_internal.h"
23 #include "policy.h"
24 
25 #define SELINUX_BOOL_DIR "/booleans/"
26 
filename_select(const struct dirent * d)27 static int filename_select(const struct dirent *d)
28 {
29 	if (d->d_name[0] == '.'
30 	    && (d->d_name[1] == '\0'
31 		|| (d->d_name[1] == '.' && d->d_name[2] == '\0')))
32 		return 0;
33 	return 1;
34 }
35 
security_get_boolean_names(char *** names,int * len)36 int security_get_boolean_names(char ***names, int *len)
37 {
38 	char path[PATH_MAX];
39 	int i, rc;
40 	struct dirent **namelist;
41 	char **n;
42 
43 	assert(len);
44 	if (!selinux_mnt) {
45 		errno = ENOENT;
46 		return -1;
47 	}
48 
49 	snprintf(path, sizeof path, "%s%s", selinux_mnt, SELINUX_BOOL_DIR);
50 	*len = scandir(path, &namelist, &filename_select, alphasort);
51 	if (*len <= 0) {
52 		return -1;
53 	}
54 
55 	n = (char **)malloc(sizeof(char *) * *len);
56 	if (!n) {
57 		rc = -1;
58 		goto bad;
59 	}
60 
61 	for (i = 0; i < *len; i++) {
62 	        n[i] = strdup(namelist[i]->d_name);
63 		if (!n[i]) {
64 			rc = -1;
65 			goto bad_freen;
66 		}
67 	}
68 	rc = 0;
69 	*names = n;
70       out:
71 	for (i = 0; i < *len; i++) {
72 		free(namelist[i]);
73 	}
74 	free(namelist);
75 	return rc;
76       bad_freen:
77 	for (--i; i >= 0; --i)
78 		free(n[i]);
79 	free(n);
80       bad:
81 	goto out;
82 }
83 
hidden_def(security_get_boolean_names)84 hidden_def(security_get_boolean_names)
85 #define STRBUF_SIZE 3
86 static int get_bool_value(const char *name, char **buf)
87 {
88 	int fd, len;
89 	char *fname = NULL;
90 
91 	if (!selinux_mnt) {
92 		errno = ENOENT;
93 		return -1;
94 	}
95 
96 	*buf = (char *)malloc(sizeof(char) * (STRBUF_SIZE + 1));
97 	if (!*buf)
98 		goto out;
99 	(*buf)[STRBUF_SIZE] = 0;
100 
101 	len = strlen(name) + strlen(selinux_mnt) + sizeof(SELINUX_BOOL_DIR);
102 	fname = (char *)malloc(sizeof(char) * len);
103 	if (!fname)
104 		goto out;
105 	snprintf(fname, len, "%s%s%s", selinux_mnt, SELINUX_BOOL_DIR, name);
106 
107 	fd = open(fname, O_RDONLY);
108 	if (fd < 0)
109 		goto out;
110 
111 	len = read(fd, *buf, STRBUF_SIZE);
112 	close(fd);
113 	if (len != STRBUF_SIZE)
114 		goto out;
115 
116 	free(fname);
117 	return 0;
118       out:
119 	if (*buf)
120 		free(*buf);
121 	if (fname)
122 		free(fname);
123 	return -1;
124 }
125 
security_get_boolean_pending(const char * name)126 int security_get_boolean_pending(const char *name)
127 {
128 	char *buf;
129 	int val;
130 
131 	if (get_bool_value(name, &buf))
132 		return -1;
133 
134 	if (atoi(&buf[1]))
135 		val = 1;
136 	else
137 		val = 0;
138 	free(buf);
139 	return val;
140 }
141 
security_get_boolean_active(const char * name)142 int security_get_boolean_active(const char *name)
143 {
144 	char *buf;
145 	int val;
146 
147 	if (get_bool_value(name, &buf))
148 		return -1;
149 
150 	buf[1] = '\0';
151 	if (atoi(buf))
152 		val = 1;
153 	else
154 		val = 0;
155 	free(buf);
156 	return val;
157 }
158 
hidden_def(security_get_boolean_active)159 hidden_def(security_get_boolean_active)
160 
161 int security_set_boolean(const char *name, int value)
162 {
163 	int fd, ret, len;
164 	char buf[2], *fname;
165 
166 	if (!selinux_mnt) {
167 		errno = ENOENT;
168 		return -1;
169 	}
170 	if (value < 0 || value > 1) {
171 		errno = EINVAL;
172 		return -1;
173 	}
174 
175 	len = strlen(name) + strlen(selinux_mnt) + sizeof(SELINUX_BOOL_DIR);
176 	fname = (char *)malloc(sizeof(char) * len);
177 	if (!fname)
178 		return -1;
179 	snprintf(fname, len, "%s%s%s", selinux_mnt, SELINUX_BOOL_DIR, name);
180 
181 	fd = open(fname, O_WRONLY);
182 	if (fd < 0) {
183 		ret = -1;
184 		goto out;
185 	}
186 
187 	if (value)
188 		buf[0] = '1';
189 	else
190 		buf[0] = '0';
191 	buf[1] = '\0';
192 
193 	ret = write(fd, buf, 2);
194 	close(fd);
195       out:
196 	free(fname);
197 	if (ret > 0)
198 		return 0;
199 	else
200 		return -1;
201 }
202 
hidden_def(security_set_boolean)203 hidden_def(security_set_boolean)
204 
205 int security_commit_booleans(void)
206 {
207 	int fd, ret;
208 	char buf[2];
209 	char path[PATH_MAX];
210 
211 	if (!selinux_mnt) {
212 		errno = ENOENT;
213 		return -1;
214 	}
215 
216 	snprintf(path, sizeof path, "%s/commit_pending_bools", selinux_mnt);
217 	fd = open(path, O_WRONLY);
218 	if (fd < 0)
219 		return -1;
220 
221 	buf[0] = '1';
222 	buf[1] = '\0';
223 
224 	ret = write(fd, buf, 2);
225 	close(fd);
226 
227 	if (ret > 0)
228 		return 0;
229 	else
230 		return -1;
231 }
232 
hidden_def(security_commit_booleans)233 hidden_def(security_commit_booleans)
234 
235 static void rollback(SELboolean * boollist, int end)
236 {
237 	int i;
238 
239 	for (i = 0; i < end; i++)
240 		security_set_boolean(boollist[i].name,
241 				     security_get_boolean_active(boollist[i].
242 								 name));
243 }
244 
security_set_boolean_list(size_t boolcnt,SELboolean * const boollist,int permanent)245 int security_set_boolean_list(size_t boolcnt, SELboolean * const boollist,
246 			      int permanent __attribute__((unused)))
247 {
248 
249 	size_t i;
250 	for (i = 0; i < boolcnt; i++) {
251 		if (security_set_boolean(boollist[i].name, boollist[i].value)) {
252 			rollback(boollist, i);
253 			return -1;
254 		}
255 	}
256 
257 	/* OK, let's do the commit */
258 	if (security_commit_booleans()) {
259 		return -1;
260 	}
261 
262 	return 0;
263 }
264