1 #include <unistd.h>
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <string.h>
5 #include <sys/stat.h>
6 #include <fcntl.h>
7 #include <errno.h>
8 #include <syslog.h>
9 #include <getopt.h>
10 #include <pwd.h>
11 #include <selinux/selinux.h>
12 #include <semanage/handle.h>
13 #include <semanage/debug.h>
14 #include <semanage/booleans_policy.h>
15 #include <semanage/booleans_local.h>
16 #include <semanage/booleans_active.h>
17 #include <semanage/boolean_record.h>
18 #include <errno.h>
19 
20 int permanent = 0;
21 int reload = 1;
22 int verbose = 0;
23 
24 int setbool(char **list, size_t start, size_t end);
25 
usage(void)26 void usage(void)
27 {
28 	fputs
29 	    ("\nUsage:  setsebool [ -NPV ] boolean value | bool1=val1 bool2=val2...\n\n",
30 	     stderr);
31 	exit(1);
32 }
33 
main(int argc,char ** argv)34 int main(int argc, char **argv)
35 {
36 	size_t rc;
37 	int clflag;		/* holds codes for command line flags */
38 	if (argc < 2)
39 		usage();
40 
41 	if (is_selinux_enabled() <= 0) {
42 		fputs("setsebool:  SELinux is disabled.\n", stderr);
43 		return 1;
44 	}
45 
46 	while (1) {
47 		clflag = getopt(argc, argv, "PNV");
48 		if (clflag == -1)
49 			break;
50 
51 		switch (clflag) {
52 		case 'P':
53 			permanent = 1;
54 			break;
55 		case 'N':
56 			reload = 0;
57 			break;
58 		case 'V':
59 			verbose = 1;
60 			break;
61 		default:
62 			usage();
63 			break;
64 		}
65 	}
66 
67 	if (argc - optind < 1) {
68 		fprintf(stderr, "Error: boolean name required\n");
69 		usage();
70 	}
71 
72 	/* Check to see which way we are being called. If a '=' is passed,
73 	   we'll enforce the list syntax. If not we'll enforce the original
74 	   syntax for backward compatibility. */
75 	if (strchr(argv[optind], '=') == 0) {
76 		int len;
77 		char *bool_list[1];
78 
79 		if ((argc - optind) != 2)
80 			usage();
81 
82 		/* Add 1 for the '=' */
83 		len = strlen(argv[optind]) + strlen(argv[optind + 1]) + 2;
84 		bool_list[0] = (char *)malloc(len);
85 		if (bool_list[0] == 0) {
86 			fputs("Out of memory - aborting\n", stderr);
87 			return 1;
88 		}
89 		snprintf(bool_list[0], len, "%s=%s", argv[optind],
90 			 argv[optind + 1]);
91 		rc = setbool(bool_list, 0, 1);
92 		free(bool_list[0]);
93 	} else
94 		rc = setbool(argv, optind, argc);
95 
96 	return rc;
97 }
98 
99 /* Apply temporal boolean changes to policy via libselinux */
selinux_set_boolean_list(size_t boolcnt,SELboolean * boollist)100 static int selinux_set_boolean_list(size_t boolcnt,
101 				    SELboolean * boollist)
102 {
103 
104 	if (security_set_boolean_list(boolcnt, boollist, 0)) {
105 		if (errno == ENOENT)
106 			fprintf(stderr, "Could not change active booleans: "
107 				"Invalid boolean\n");
108 		else if (errno) {
109 			if (getuid() == 0) {
110 				perror("Could not change active booleans");
111 			} else {
112 				perror("Could not change active booleans. Please try as root");
113 			}
114 		}
115 
116 		return -1;
117 	}
118 
119 	return 0;
120 }
121 
122 /* Apply permanent boolean changes to policy via libsemanage */
semanage_set_boolean_list(size_t boolcnt,SELboolean * boollist)123 static int semanage_set_boolean_list(size_t boolcnt,
124 				     SELboolean * boollist)
125 {
126 
127 	size_t j;
128 	semanage_handle_t *handle = NULL;
129 	semanage_bool_t *boolean = NULL;
130 	semanage_bool_key_t *bool_key = NULL;
131 	int managed;
132 	int result;
133 
134 	handle = semanage_handle_create();
135 	if (handle == NULL) {
136 		fprintf(stderr, "Could not create semanage library handle\n");
137 		goto err;
138 	}
139 
140 	if (! verbose) {
141 		semanage_msg_set_callback(handle,NULL, NULL);
142 	}
143 
144 	managed = semanage_is_managed(handle);
145 	if (managed < 0) {
146 		fprintf(stderr,
147 			"Error when checking whether policy is managed\n");
148 		goto err;
149 
150 	} else if (managed == 0) {
151 		if (getuid() == 0) {
152 			fprintf(stderr,
153 				"Cannot set persistent booleans without managed policy.\n");
154 		} else {
155 			fprintf(stderr,
156 				"Cannot set persistent booleans, please try as root.\n");
157 		}
158 		goto err;
159 	}
160 
161 	if (semanage_connect(handle) < 0)
162 		goto err;
163 
164 	if (semanage_begin_transaction(handle) < 0)
165 		goto err;
166 
167 	for (j = 0; j < boolcnt; j++) {
168 
169 		if (semanage_bool_create(handle, &boolean) < 0)
170 			goto err;
171 
172 		if (semanage_bool_set_name(handle, boolean, boollist[j].name) <
173 		    0)
174 			goto err;
175 
176 		semanage_bool_set_value(boolean, boollist[j].value);
177 
178 		if (semanage_bool_key_extract(handle, boolean, &bool_key) < 0)
179 			goto err;
180 
181 		semanage_bool_exists(handle, bool_key, &result);
182 		if ( !result ) {
183 			semanage_bool_exists_local(handle, bool_key, &result);
184 			if ( !result ) {
185 				fprintf(stderr, "Boolean %s is not defined\n", boollist[j].name);
186 				goto err;
187 			}
188 		}
189 
190 		if (semanage_bool_modify_local(handle, bool_key,
191 						  boolean) < 0)
192 			goto err;
193 
194 		if (semanage_bool_set_active(handle, bool_key, boolean) < 0) {
195 			fprintf(stderr, "Failed to change boolean %s: %m\n",
196 				boollist[j].name);
197 			goto err;
198 		}
199 		semanage_bool_key_free(bool_key);
200 		semanage_bool_free(boolean);
201 		bool_key = NULL;
202 		boolean = NULL;
203 	}
204 
205 	semanage_set_reload(handle, reload);
206 	if (semanage_commit(handle) < 0)
207 		goto err;
208 
209 	semanage_disconnect(handle);
210 	semanage_handle_destroy(handle);
211 	return 0;
212 
213       err:
214 	semanage_bool_key_free(bool_key);
215 	semanage_bool_free(boolean);
216 	semanage_handle_destroy(handle);
217 	return -1;
218 }
219 
220 /* Given an array of strings in the form "boolname=value", a start index,
221    and a finish index...walk the list and set the bool. */
setbool(char ** list,size_t start,size_t end)222 int setbool(char **list, size_t start, size_t end)
223 {
224 	char *name, *value_ptr;
225 	int j = 0, value;
226 	size_t i = start;
227 	size_t boolcnt = end - start;
228 	struct passwd *pwd;
229 	SELboolean *vallist = calloc(boolcnt, sizeof(SELboolean));
230 	if (!vallist)
231 		goto omem;
232 
233 	while (i < end) {
234 		name = list[i];
235 		value_ptr = strchr(list[i], '=');
236 		if (value_ptr == 0) {
237 			fprintf(stderr,
238 				"setsebool: '=' not found in boolean expression %s\n",
239 				list[i]);
240 			goto err;
241 		}
242 		*value_ptr = 0;
243 		value_ptr++;
244 		if (strcmp(value_ptr, "1") == 0 ||
245 		    strcasecmp(value_ptr, "true") == 0 ||
246 		    strcasecmp(value_ptr, "on") == 0)
247 			value = 1;
248 		else if (strcmp(value_ptr, "0") == 0 ||
249 			 strcasecmp(value_ptr, "false") == 0 ||
250 			 strcasecmp(value_ptr, "off") == 0)
251 			value = 0;
252 		else {
253 			fprintf(stderr, "setsebool: illegal value "
254 				"%s for boolean %s\n", value_ptr, name);
255 			goto err;
256 		}
257 
258 		vallist[j].value = value;
259 		vallist[j].name = strdup(name);
260 		if (!vallist[j].name)
261 			goto omem;
262 		i++;
263 		j++;
264 
265 		/* Now put it back */
266 		value_ptr--;
267 		*value_ptr = '=';
268 	}
269 
270 	if (permanent) {
271 		if (semanage_set_boolean_list(boolcnt, vallist) < 0)
272 			goto err;
273 	} else {
274 		if (selinux_set_boolean_list(boolcnt, vallist) < 0)
275 			goto err;
276 	}
277 
278 	/* Now log what was done */
279 	pwd = getpwuid(getuid());
280 	i = start;
281 	while (i < end) {
282 		name = list[i];
283 		value_ptr = strchr(name, '=');
284 		*value_ptr = 0;
285 		value_ptr++;
286 		if (pwd && pwd->pw_name)
287 			syslog(LOG_NOTICE,
288 			       "The %s policy boolean was changed to %s by %s",
289 			       name, value_ptr, pwd->pw_name);
290 		else
291 			syslog(LOG_NOTICE,
292 			       "The %s policy boolean was changed to %s by uid:%d",
293 			       name, value_ptr, getuid());
294 		i++;
295 	}
296 
297 	for (i = 0; i < boolcnt; i++)
298 		free(vallist[i].name);
299 	free(vallist);
300 	return 0;
301 
302       omem:
303 	fprintf(stderr, "setsebool: out of memory");
304 
305       err:
306 	if (vallist) {
307 		for (i = 0; i < boolcnt; i++)
308 			free(vallist[i].name);
309 		free(vallist);
310 	}
311 	return -1;
312 }
313