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