• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Authors: Karl MacMillan <kmacmillan@tresys.com>
2  *          Joshua Brindle <jbrindle@tresys.com>
3  *          Jason Tang <jtang@tresys.com>
4  *
5  * Copyright (C) 2004-2005 Tresys Technology, LLC
6  *      This program is free software; you can redistribute it and/or
7  *      modify it under the terms of the GNU General Public License as
8  *      published by the Free Software Foundation, version 2.
9  */
10 
11 #include <fcntl.h>
12 #include <getopt.h>
13 #include <signal.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <errno.h>
17 #include <string.h>
18 #include <unistd.h>
19 #include <sys/mman.h>
20 #include <sys/stat.h>
21 #include <sys/types.h>
22 #include <libgen.h>
23 #include <limits.h>
24 
25 #include <semanage/modules.h>
26 
27 enum client_modes {
28 	NO_MODE, INSTALL_M, REMOVE_M, EXTRACT_M, CIL_M, HLL_M,
29 	LIST_M, RELOAD, PRIORITY_M, ENABLE_M, DISABLE_M
30 };
31 /* list of modes in which one ought to commit afterwards */
32 static const int do_commit[] = {
33 	0, 1, 1, 0, 0, 0,
34 	0, 0, 0, 1, 1,
35 };
36 
37 struct command {
38 	enum client_modes mode;
39 	char *arg;
40 };
41 static struct command *commands = NULL;
42 static int num_commands = 0;
43 
44 /* options given on command line */
45 static int verbose;
46 static int reload;
47 static int no_reload;
48 static int build;
49 static int disable_dontaudit;
50 static int preserve_tunables;
51 static int ignore_module_cache;
52 static uint16_t priority;
53 static int priority_set = 0;
54 
55 static semanage_handle_t *sh = NULL;
56 static char *store;
57 static char *store_root;
58 int extract_cil = 0;
59 
60 extern char *optarg;
61 extern int optind;
62 
cleanup(void)63 static void cleanup(void)
64 {
65 	while (--num_commands >= 0) {
66 		free(commands[num_commands].arg);
67 	}
68 	free(commands);
69 }
70 
71 /* Signal handlers. */
handle_signal(int sig_num)72 static void handle_signal(int sig_num)
73 {
74 	if (sig_num == SIGINT || sig_num == SIGQUIT || sig_num == SIGTERM) {
75 		/* catch these signals, and then drop them */
76 	}
77 }
78 
set_store(char * storename)79 static void set_store(char *storename)
80 {
81 	/* For now this only supports a store name, later on this
82 	 * should support an address for a remote connection */
83 
84 	if ((store = strdup(storename)) == NULL) {
85 		fprintf(stderr, "Out of memory!\n");
86 		goto bad;
87 	}
88 
89 	return;
90 
91       bad:
92 	cleanup();
93 	exit(1);
94 }
95 
set_store_root(char * path)96 static void set_store_root(char *path)
97 {
98 	if ((store_root = strdup(path)) == NULL) {
99 		fprintf(stderr, "Out of memory!\n");
100 		goto bad;
101 	}
102 
103 	return;
104 
105       bad:
106 	cleanup();
107 	exit(1);
108 }
109 
110 /* Establish signal handlers for the process. */
create_signal_handlers(void)111 static void create_signal_handlers(void)
112 {
113 	if (signal(SIGINT, handle_signal) == SIG_ERR ||
114 	    signal(SIGQUIT, handle_signal) == SIG_ERR ||
115 	    signal(SIGTERM, handle_signal) == SIG_ERR) {
116 		fprintf(stderr, "Could not set up signal handler.\n");
117 		exit(255);
118 	}
119 }
120 
usage(char * progname)121 static void usage(char *progname)
122 {
123 	printf("usage:  %s [option]... MODE...\n", progname);
124 	printf("Manage SELinux policy modules.\n");
125 	printf("MODES:\n");
126 	printf("  -R, --reload		    reload policy\n");
127 	printf("  -B, --build		    build and reload policy\n");
128 	printf("  -D,--disable_dontaudit    Remove dontaudits from policy\n");
129 	printf("  -i,--install=MODULE_PKG   install a new module\n");
130 	printf("  -r,--remove=MODULE_NAME   remove existing module at desired priority\n");
131 	printf("  -l[KIND],--list-modules[=KIND]  display list of installed modules\n");
132 	printf("     KIND:  standard  list highest priority, enabled modules\n");
133 	printf("            full      list all modules\n");
134 	printf("  -X,--priority=PRIORITY    set priority for following operations (1-999)\n");
135 	printf("  -e,--enable=MODULE_NAME   enable module\n");
136 	printf("  -d,--disable=MODULE_NAME  disable module\n");
137 	printf("  -E,--extract=MODULE_NAME  extract module\n");
138 	printf("Options:\n");
139 	printf("  -s,--store	   name of the store to operate on\n");
140 	printf("  -N,-n,--noreload do not reload policy after commit\n");
141 	printf("  -h,--help        print this message and quit\n");
142 	printf("  -v,--verbose     be verbose\n");
143 	printf("  -P,--preserve_tunables	Preserve tunables in policy\n");
144 	printf("  -C,--ignore-module-cache	Rebuild CIL modules compiled from HLL files\n");
145 	printf("  -p,--path        use an alternate path for the policy root\n");
146 	printf("  -S,--store-path  use an alternate path for the policy store root\n");
147 	printf("  -c, --cil extract module as cil. This only affects module extraction.\n");
148 	printf("  -H, --hll extract module as hll. This only affects module extraction.\n");
149 }
150 
151 /* Sets the global mode variable to new_mode, but only if no other
152  * mode has been given. */
set_mode(enum client_modes new_mode,char * arg)153 static void set_mode(enum client_modes new_mode, char *arg)
154 {
155 	struct command *c;
156 	char *s;
157 	if ((c = realloc(commands, sizeof(*c) * (num_commands + 1))) == NULL) {
158 		fprintf(stderr, "Out of memory!\n");
159 		cleanup();
160 		exit(1);
161 	}
162 	commands = c;
163 	commands[num_commands].mode = new_mode;
164 	commands[num_commands].arg = NULL;
165 	num_commands++;
166 	if (arg != NULL) {
167 		if ((s = strdup(arg)) == NULL) {
168 			fprintf(stderr, "Out of memory!\n");
169 			cleanup();
170 			exit(1);
171 		}
172 		commands[num_commands - 1].arg = s;
173 	}
174 }
175 
176 /* Parse command line and set global options. */
parse_command_line(int argc,char ** argv)177 static void parse_command_line(int argc, char **argv)
178 {
179 	static struct option opts[] = {
180 		{"store", required_argument, NULL, 's'},
181 		{"base", required_argument, NULL, 'b'},
182 		{"help", 0, NULL, 'h'},
183 		{"install", required_argument, NULL, 'i'},
184 		{"extract", required_argument, NULL, 'E'},
185 		{"cil", 0, NULL, 'c'},
186 		{"hll", 0, NULL, 'H'},
187 		{"list-modules", optional_argument, NULL, 'l'},
188 		{"verbose", 0, NULL, 'v'},
189 		{"remove", required_argument, NULL, 'r'},
190 		{"upgrade", required_argument, NULL, 'u'},
191 		{"reload", 0, NULL, 'R'},
192 		{"noreload", 0, NULL, 'n'},
193 		{"build", 0, NULL, 'B'},
194 		{"disable_dontaudit", 0, NULL, 'D'},
195 		{"preserve_tunables", 0, NULL, 'P'},
196 		{"ignore-module-cache", 0, NULL, 'C'},
197 		{"priority", required_argument, NULL, 'X'},
198 		{"enable", required_argument, NULL, 'e'},
199 		{"disable", required_argument, NULL, 'd'},
200 		{"path", required_argument, NULL, 'p'},
201 		{"store-path", required_argument, NULL, 'S'},
202 		{NULL, 0, NULL, 0}
203 	};
204 	int extract_selected = 0;
205 	int cil_hll_set = 0;
206 	int i;
207 	verbose = 0;
208 	reload = 0;
209 	no_reload = 0;
210 	priority = 400;
211 	while ((i =
212 		getopt_long(argc, argv, "s:b:hi:l::vr:u:RnNBDCPX:e:d:p:S:E:cH", opts,
213 			    NULL)) != -1) {
214 		switch (i) {
215 		case 'b':
216 			fprintf(stderr, "The --base option is deprecated. Use --install instead.\n");
217 			set_mode(INSTALL_M, optarg);
218 			break;
219 		case 'h':
220 			usage(argv[0]);
221 			exit(0);
222 		case 'i':
223 			set_mode(INSTALL_M, optarg);
224 			break;
225 		case 'E':
226 			set_mode(EXTRACT_M, optarg);
227 			extract_selected = 1;
228 			break;
229 		case 'c':
230 			set_mode(CIL_M, NULL);
231 			cil_hll_set = 1;
232 			break;
233 		case 'H':
234 			set_mode(HLL_M, NULL);
235 			cil_hll_set = 1;
236 			break;
237 		case 'l':
238 			set_mode(LIST_M, optarg);
239 			break;
240 		case 'v':
241 			verbose = 1;
242 			break;
243 		case 'r':
244 			set_mode(REMOVE_M, optarg);
245 			break;
246 		case 'u':
247 			fprintf(stderr, "The --upgrade option is deprecated. Use --install instead.\n");
248 			set_mode(INSTALL_M, optarg);
249 			break;
250 		case 's':
251 			set_store(optarg);
252 			break;
253 		case 'p':
254 			semanage_set_root(optarg);
255 			break;
256 		case 'S':
257 			set_store_root(optarg);
258 			break;
259 		case 'R':
260 			reload = 1;
261 			break;
262 		case 'n':
263 			no_reload = 1;
264 			break;
265 		case 'N':
266 			no_reload = 1;
267 			break;
268 		case 'B':
269 			build = 1;
270 			break;
271 		case 'D':
272 			disable_dontaudit = 1;
273 			break;
274 		case 'P':
275 			preserve_tunables = 1;
276 			break;
277 		case 'C':
278 			ignore_module_cache = 1;
279 			break;
280 		case 'X':
281 			set_mode(PRIORITY_M, optarg);
282 			break;
283 		case 'e':
284 			set_mode(ENABLE_M, optarg);
285 			break;
286 		case 'd':
287 			set_mode(DISABLE_M, optarg);
288 			break;
289 		case '?':
290 		default:{
291 				usage(argv[0]);
292 				exit(1);
293 			}
294 		}
295 	}
296 	if ((build || reload) && num_commands) {
297 		fprintf(stderr,
298 			"build or reload should not be used with other commands\n");
299 		usage(argv[0]);
300 		exit(1);
301 	}
302 	if (num_commands == 0 && reload == 0 && build == 0) {
303 		fprintf(stderr, "At least one mode must be specified.\n");
304 		usage(argv[0]);
305 		exit(1);
306 	}
307 	if (extract_selected == 0 && cil_hll_set == 1) {
308 		fprintf(stderr, "--cil and --hll require a module to export with the --extract option.\n");
309 		usage(argv[0]);
310 		exit(1);
311 	}
312 
313 	if (optind < argc) {
314 		int mode = commands ? (int) commands[num_commands - 1].mode : -1;
315 		/* if -i/u/r/E was the last command treat any remaining
316 		 * arguments as args. Will allow 'semodule -i *.pp' to
317 		 * work as expected.
318 		 */
319 
320 		switch (mode) {
321 			case INSTALL_M:
322 			case REMOVE_M:
323 			case EXTRACT_M:
324 			case ENABLE_M:
325 			case DISABLE_M:
326 				while (optind < argc)
327 					set_mode(mode, argv[optind++]);
328 				break;
329 			default:
330 				fprintf(stderr, "unknown additional arguments:\n");
331 				while (optind < argc)
332 					fprintf(stderr, " %s", argv[optind++]);
333 				fprintf(stderr, "\n\n");
334 				usage(argv[0]);
335 				exit(1);
336 		}
337 	}
338 }
339 
main(int argc,char * argv[])340 int main(int argc, char *argv[])
341 {
342 	int i, commit = 0;
343 	int result;
344 	int status = EXIT_FAILURE;
345 	const char *genhomedirconargv[] = { "genhomedircon", "-B", "-n" };
346 	create_signal_handlers();
347 	if (strcmp(basename(argv[0]), "genhomedircon") == 0) {
348 		argc = 3;
349 		argv = (char **)genhomedirconargv;
350 	}
351 	parse_command_line(argc, argv);
352 
353 	if (build)
354 		commit = 1;
355 
356 	sh = semanage_handle_create();
357 	if (!sh) {
358 		fprintf(stderr, "%s:  Could not create semanage handle\n",
359 			argv[0]);
360 		goto cleanup_nohandle;
361 	}
362 
363 	if (store) {
364 		/* Set the store we want to connect to, before connecting.
365 		 * this will always set a direct connection now, an additional
366 		 * option will need to be used later to specify a policy server
367 		 * location */
368 		semanage_select_store(sh, store, SEMANAGE_CON_DIRECT);
369 	}
370 
371 	if (store_root) {
372 		semanage_set_store_root(sh, store_root);
373 	}
374 
375 	/* create store if necessary, for bootstrapping */
376 	semanage_set_create_store(sh, 1);
377 
378 	if ((result = semanage_connect(sh)) < 0) {
379 		fprintf(stderr, "%s:  Could not connect to policy handler\n",
380 			argv[0]);
381 		goto cleanup;
382 	}
383 
384 	if (reload) {
385 		if ((result = semanage_reload_policy(sh)) < 0) {
386 			fprintf(stderr, "%s:  Could not reload policy\n",
387 				argv[0]);
388 			goto cleanup;
389 		}
390 	}
391 
392 	if (build) {
393 		if ((result = semanage_begin_transaction(sh)) < 0) {
394 			fprintf(stderr, "%s:  Could not begin transaction:  %s\n",
395 				argv[0], errno ? strerror(errno) : "");
396 			goto cleanup;
397 		}
398 	}
399 
400 	if ((result = semanage_set_default_priority(sh, priority)) != 0) {
401 		fprintf(stderr,
402 			"%s: Invalid priority %d (needs to be between 1 and 999)\n",
403 			argv[0],
404 			priority);
405 		goto cleanup;
406 	}
407 
408 	for (i = 0; i < num_commands; i++) {
409 		enum client_modes mode = commands[i].mode;
410 		char *mode_arg = commands[i].arg;
411 
412 		switch (mode) {
413 		case INSTALL_M:{
414 				if (verbose) {
415 					printf
416 					    ("Attempting to install module '%s':\n",
417 					     mode_arg);
418 				}
419 				result =
420 				    semanage_module_install_file(sh, mode_arg);
421 				break;
422 			}
423 		case EXTRACT_M:{
424 				semanage_module_info_t *extract_info = NULL;
425 				semanage_module_key_t *modkey = NULL;
426 				uint16_t curr_priority;
427 				void *data = NULL;
428 				size_t data_len = 0;
429 				char output_path[PATH_MAX];
430 				const char *output_name = NULL;
431 				const char *lang_ext = NULL;
432 				int rlen;
433 				FILE *output_fd = NULL;
434 
435 				result = semanage_module_key_create(sh, &modkey);
436 				if (result != 0) {
437 					goto cleanup_extract;
438 				}
439 
440 				result = semanage_module_key_set_name(sh, modkey, mode_arg);
441 				if (result != 0) {
442 					goto cleanup_extract;
443 				}
444 
445 				if (priority_set == 0) {
446 					result = semanage_module_get_module_info(sh, modkey, &extract_info);
447 					if (result != 0) {
448 						goto cleanup_extract;
449 					}
450 
451 					semanage_module_info_get_priority(sh, extract_info, &curr_priority);
452 					printf("Module '%s' does not exist at the default priority '%d'. "
453 							"Extracting at highest existing priority '%d'.\n", mode_arg, priority, curr_priority);
454 					priority = curr_priority;
455 				}
456 
457 				result  = semanage_module_key_set_priority(sh, modkey, priority);
458 				if (result != 0) {
459 					goto cleanup_extract;
460 				}
461 
462 				if (verbose) {
463 					printf
464 						("Attempting to extract module '%s':\n",
465 							mode_arg);
466 				}
467 				result = semanage_module_extract(sh, modkey, extract_cil, &data, &data_len, &extract_info);
468 				if (result != 0) {
469 					goto cleanup_extract;
470 				}
471 
472 				if (extract_cil) {
473 					lang_ext = "cil";
474 				} else {
475 					result = semanage_module_info_get_lang_ext(sh, extract_info, &lang_ext);
476 					if (result != 0) {
477 						goto cleanup_extract;
478 					}
479 				}
480 
481 				result = semanage_module_info_get_name(sh, extract_info, &output_name);
482 				if (result != 0) {
483 					goto cleanup_extract;
484 				}
485 
486 				rlen = snprintf(output_path, PATH_MAX, "%s.%s", output_name, lang_ext);
487 				if (rlen < 0 || rlen >= PATH_MAX) {
488 					fprintf(stderr, "%s: Failed to generate output path.\n", argv[0]);
489 					result = -1;
490 					goto cleanup_extract;
491 				}
492 
493 				if (access(output_path, F_OK) == 0) {
494 					fprintf(stderr, "%s: %s is already extracted with extension %s.\n", argv[0], mode_arg, lang_ext);
495 					result = -1;
496 					goto cleanup_extract;
497 				}
498 
499 				output_fd = fopen(output_path, "w");
500 				if (output_fd == NULL) {
501 					fprintf(stderr, "%s: Unable to open %s\n", argv[0], output_path);
502 					result = -1;
503 					goto cleanup_extract;
504 				}
505 
506 				if (fwrite(data, 1, data_len, output_fd) < data_len) {
507 					fprintf(stderr, "%s: Unable to write to %s\n", argv[0], output_path);
508 					result = -1;
509 					goto cleanup_extract;
510 				}
511 cleanup_extract:
512 				if (output_fd != NULL) {
513 					fclose(output_fd);
514 				}
515 				if (data_len > 0) {
516 					munmap(data, data_len);
517 				}
518 				semanage_module_info_destroy(sh, extract_info);
519 				free(extract_info);
520 				semanage_module_key_destroy(sh, modkey);
521 				free(modkey);
522 				break;
523 			}
524 		case CIL_M:
525 				extract_cil = 1;
526 				break;
527 		case HLL_M:
528 				extract_cil = 0;
529 				break;
530 		case REMOVE_M:{
531 				if (verbose) {
532 					printf
533 					    ("Attempting to remove module '%s':\n",
534 					     mode_arg);
535 				}
536 				result = semanage_module_remove(sh, mode_arg);
537 				if ( result == -2 ) {
538 					continue;
539 				}
540 				break;
541 			}
542 		case LIST_M:{
543 				semanage_module_info_t *modinfos = NULL;
544 				int modinfos_len = 0;
545 				semanage_module_info_t *m = NULL;
546 				int j = 0;
547 
548 				if (verbose) {
549 					printf
550 					    ("Attempting to list active modules:\n");
551 				}
552 
553 				if (mode_arg == NULL || strcmp(mode_arg, "standard") == 0) {
554 					result = semanage_module_list(sh,
555 								      &modinfos,
556 								      &modinfos_len);
557 					if (result < 0) goto cleanup_list;
558 
559 					if (modinfos_len == 0) {
560 						printf("No modules.\n");
561 					}
562 
563 					const char *name = NULL;
564 
565 					for (j = 0; j < modinfos_len; j++) {
566 						m = semanage_module_list_nth(modinfos, j);
567 
568 						result = semanage_module_info_get_name(sh, m, &name);
569 						if (result != 0) goto cleanup_list;
570 
571 						printf("%s\n", name);
572 					}
573 				}
574 				else if (strcmp(mode_arg, "full") == 0) {
575 					/* get the modules */
576 					result = semanage_module_list_all(sh,
577 									  &modinfos,
578 									  &modinfos_len);
579 					if (result != 0) goto cleanup_list;
580 
581 					if (modinfos_len == 0) {
582 						printf("No modules.\n");
583 					}
584 
585 					/* calculate column widths */
586 					size_t column[4] = { 0, 0, 0, 0 };
587 
588 					/* fixed width columns */
589 					column[0] = sizeof("000") - 1;
590 					column[3] = sizeof("disabled") - 1;
591 
592 					/* variable width columns */
593 					const char *tmp = NULL;
594 					size_t size;
595 					for (j = 0; j < modinfos_len; j++) {
596 						m = semanage_module_list_nth(modinfos, j);
597 
598 						result = semanage_module_info_get_name(sh, m, &tmp);
599 						if (result != 0) goto cleanup_list;
600 
601 						size = strlen(tmp);
602 						if (size > column[1]) column[1] = size;
603 
604 						result = semanage_module_info_get_lang_ext(sh, m, &tmp);
605 						if (result != 0) goto cleanup_list;
606 
607 						size = strlen(tmp);
608 						if (size > column[3]) column[3] = size;
609 					}
610 
611 					/* print out each module */
612 					for (j = 0; j < modinfos_len; j++) {
613 						uint16_t pri = 0;
614 						const char *name = NULL;
615 						int enabled = 0;
616 						const char *lang_ext = NULL;
617 
618 						m = semanage_module_list_nth(modinfos, j);
619 
620 						result = semanage_module_info_get_priority(sh, m, &pri);
621 						if (result != 0) goto cleanup_list;
622 
623 						result = semanage_module_info_get_name(sh, m, &name);
624 						if (result != 0) goto cleanup_list;
625 
626 						result = semanage_module_info_get_enabled(sh, m, &enabled);
627 						if (result != 0) goto cleanup_list;
628 
629 						result = semanage_module_info_get_lang_ext(sh, m, &lang_ext);
630 						if (result != 0) goto cleanup_list;
631 
632 						printf("%0*u %-*s %-*s %-*s\n",
633 							(int)column[0], pri,
634 							(int)column[1], name,
635 							(int)column[2], lang_ext,
636 							(int)column[3], enabled ? "" : "disabled");
637 					}
638 				}
639 				else {
640 					result = -1;
641 				}
642 
643 cleanup_list:
644 				for (j = 0; j < modinfos_len; j++) {
645 					m = semanage_module_list_nth(modinfos, j);
646 					semanage_module_info_destroy(sh, m);
647 				}
648 
649 				free(modinfos);
650 
651 				break;
652 			}
653 		case PRIORITY_M:{
654 				char *endptr = NULL;
655 				priority = (uint16_t)strtoul(mode_arg, &endptr, 10);
656 				priority_set = 1;
657 
658 				if ((result = semanage_set_default_priority(sh, priority)) != 0) {
659 					fprintf(stderr,
660 						"%s: Invalid priority %d (needs to be between 1 and 999)\n",
661 						argv[0],
662 						priority);
663 					goto cleanup;
664 				}
665 
666 				break;
667 			}
668 		case ENABLE_M:{
669 				if (verbose) {
670 					printf
671 					    ("Attempting to enable module '%s':\n",
672 					     mode_arg);
673 				}
674 
675 				semanage_module_key_t *modkey = NULL;
676 
677 				result = semanage_module_key_create(sh, &modkey);
678 				if (result != 0) goto cleanup_enable;
679 
680 				result = semanage_module_key_set_name(sh, modkey, mode_arg);
681 				if (result != 0) goto cleanup_enable;
682 
683 				result = semanage_module_set_enabled(sh, modkey, 1);
684 				if (result != 0) goto cleanup_enable;
685 
686 cleanup_enable:
687 				semanage_module_key_destroy(sh, modkey);
688 				free(modkey);
689 
690 				break;
691 			}
692 		case DISABLE_M:{
693 				if (verbose) {
694 					printf
695 					    ("Attempting to disable module '%s':\n",
696 					     mode_arg);
697 				}
698 
699 				semanage_module_key_t *modkey = NULL;
700 
701 				result = semanage_module_key_create(sh, &modkey);
702 				if (result != 0) goto cleanup_disable;
703 
704 				result = semanage_module_key_set_name(sh, modkey, mode_arg);
705 				if (result != 0) goto cleanup_disable;
706 
707 				result = semanage_module_set_enabled(sh, modkey, 0);
708 				if (result != 0) goto cleanup_disable;
709 
710 cleanup_disable:
711 				semanage_module_key_destroy(sh, modkey);
712 				free(modkey);
713 
714 				break;
715 			}
716 		default:{
717 				fprintf(stderr,
718 					"%s:  Unknown mode specified.\n",
719 					argv[0]);
720 				usage(argv[0]);
721 				goto cleanup;
722 			}
723 		}
724 		commit += do_commit[mode];
725 		if (result < 0) {
726 			fprintf(stderr, "%s:  Failed on %s!\n", argv[0],
727 				mode_arg ? : "list");
728 			goto cleanup;
729 		} else if (verbose) {
730 			printf("Ok: return value of %d.\n", result);
731 		}
732 	}
733 
734 	if (commit) {
735 		if (verbose)
736 			printf("Committing changes:\n");
737 		if (no_reload)
738 			semanage_set_reload(sh, 0);
739 		if (build)
740 			semanage_set_rebuild(sh, 1);
741 		if (disable_dontaudit)
742 			semanage_set_disable_dontaudit(sh, 1);
743 		else if (build)
744 			semanage_set_disable_dontaudit(sh, 0);
745 		if (preserve_tunables)
746 			semanage_set_preserve_tunables(sh, 1);
747 		if (ignore_module_cache)
748 			semanage_set_ignore_module_cache(sh, 1);
749 
750 		result = semanage_commit(sh);
751 	}
752 
753 	if (result < 0) {
754 		fprintf(stderr, "%s:  Failed!\n", argv[0]);
755 		goto cleanup;
756 	} else if (commit && verbose) {
757 		printf("Ok: transaction number %d.\n", result);
758 	}
759 
760 	if (semanage_disconnect(sh) < 0) {
761 		fprintf(stderr, "%s:  Error disconnecting\n", argv[0]);
762 		goto cleanup;
763 	}
764 	status = EXIT_SUCCESS;
765 
766       cleanup:
767 	if (semanage_is_connected(sh)) {
768 		if (semanage_disconnect(sh) < 0) {
769 			fprintf(stderr, "%s:  Error disconnecting\n", argv[0]);
770 		}
771 	}
772 	semanage_handle_destroy(sh);
773 
774       cleanup_nohandle:
775 	cleanup();
776 	exit(status);
777 }
778