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