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 fprintf(stderr, "Failed to commit changes to booleans: %m\n");
205 goto err;
206 }
207
208 semanage_disconnect(handle);
209 semanage_handle_destroy(handle);
210 return 0;
211
212 err:
213 semanage_bool_key_free(bool_key);
214 semanage_bool_free(boolean);
215 semanage_handle_destroy(handle);
216 return -1;
217 }
218
219 /* Given an array of strings in the form "boolname=value", a start index,
220 and a finish index...walk the list and set the bool. */
setbool(char ** list,size_t start,size_t end)221 int setbool(char **list, size_t start, size_t end)
222 {
223 char *name, *value_ptr;
224 int j = 0, value;
225 size_t i = start;
226 size_t boolcnt = end - start;
227 struct passwd *pwd;
228 SELboolean *vallist = calloc(boolcnt, sizeof(SELboolean));
229 if (!vallist)
230 goto omem;
231
232 while (i < end) {
233 name = list[i];
234 value_ptr = strchr(list[i], '=');
235 if (value_ptr == NULL) {
236 fprintf(stderr,
237 "setsebool: '=' not found in boolean expression %s\n",
238 list[i]);
239 goto err;
240 }
241 *value_ptr = '\0';
242 value_ptr++;
243 if (strcmp(value_ptr, "1") == 0 ||
244 strcasecmp(value_ptr, "true") == 0 ||
245 strcasecmp(value_ptr, "on") == 0)
246 value = 1;
247 else if (strcmp(value_ptr, "0") == 0 ||
248 strcasecmp(value_ptr, "false") == 0 ||
249 strcasecmp(value_ptr, "off") == 0)
250 value = 0;
251 else {
252 fprintf(stderr, "setsebool: illegal value "
253 "%s for boolean %s\n", value_ptr, name);
254 goto err;
255 }
256
257 vallist[j].value = value;
258 vallist[j].name = strdup(name);
259 if (!vallist[j].name)
260 goto omem;
261 i++;
262 j++;
263
264 /* Now put it back */
265 value_ptr--;
266 *value_ptr = '=';
267 }
268
269 if (permanent) {
270 if (semanage_set_boolean_list(boolcnt, vallist) < 0)
271 goto err;
272 } else {
273 if (selinux_set_boolean_list(boolcnt, vallist) < 0)
274 goto err;
275 }
276
277 /* Now log what was done */
278 pwd = getpwuid(getuid());
279 i = start;
280 while (i < end) {
281 name = list[i];
282 value_ptr = strchr(name, '=');
283 *value_ptr = '\0';
284 value_ptr++;
285 if (pwd && pwd->pw_name)
286 syslog(LOG_NOTICE,
287 "The %s policy boolean was changed to %s by %s",
288 name, value_ptr, pwd->pw_name);
289 else
290 syslog(LOG_NOTICE,
291 "The %s policy boolean was changed to %s by uid:%d",
292 name, value_ptr, getuid());
293 i++;
294 }
295
296 for (i = 0; i < boolcnt; i++)
297 free(vallist[i].name);
298 free(vallist);
299 return 0;
300
301 omem:
302 fprintf(stderr, "setsebool: out of memory");
303
304 err:
305 if (vallist) {
306 for (i = 0; i < boolcnt; i++)
307 free(vallist[i].name);
308 free(vallist);
309 }
310 return -1;
311 }
312