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
20int permanent = 0;
21int reload = 1;
22int verbose = 0;
23
24int setbool(char **list, size_t start, size_t end);
25
26void usage(void)
27{
28	fputs
29	    ("\nUsage:  setsebool [ -NPV ] boolean value | bool1=val1 bool2=val2...\n\n",
30	     stderr);
31	exit(1);
32}
33
34int 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 */
100static 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 */
123static 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. */
222int 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