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