Home | History | Annotate | Download | only in semodule
      1 /* Authors: Karl MacMillan <kmacmillan (at) tresys.com>
      2  *          Joshua Brindle <jbrindle (at) tresys.com>
      3  *          Jason Tang <jtang (at) 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 
     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. */
     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 
     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 
     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. */
    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 
    121 static void usage(char *progname)
    122 {
    123 	printf("usage:  %s [options]... MODE [MODES]...\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("  -i,--install=MODULE_PKG   install a new module\n");
    129 	printf("  -r,--remove=MODULE_NAME   remove existing module\n");
    130 	printf("  -l,--list-modules=[KIND]  display list of installed modules\n");
    131 	printf("     KIND:  standard  list highest priority, enabled modules\n");
    132 	printf("            full      list all modules\n");
    133 	printf("  -X,--priority=PRIORITY    set priority for following operations (1-999)\n");
    134 	printf("  -e,--enable=MODULE_NAME   enable module\n");
    135 	printf("  -d,--disable=MODULE_NAME  disable module\n");
    136 	printf("  -E,--extract=MODULE_NAME  extract module\n");
    137 	printf("Other options:\n");
    138 	printf("  -s,--store	   name of the store to operate on\n");
    139 	printf("  -N,-n,--noreload do not reload policy after commit\n");
    140 	printf("  -h,--help        print this message and quit\n");
    141 	printf("  -v,--verbose     be verbose\n");
    142 	printf("  -D,--disable_dontaudit	Remove dontaudits from policy\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. */
    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. */
    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::vqr: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;
    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 		if (commands && commands[num_commands - 1].mode == INSTALL_M) {
    321 			mode = INSTALL_M;
    322 		} else if (commands && commands[num_commands - 1].mode == REMOVE_M) {
    323 			mode = REMOVE_M;
    324 		} else if (commands && commands[num_commands - 1].mode == EXTRACT_M) {
    325 			mode = EXTRACT_M;
    326 		} else {
    327 			fprintf(stderr, "unknown additional arguments:\n");
    328 			while (optind < argc)
    329 				fprintf(stderr, " %s", argv[optind++]);
    330 			fprintf(stderr, "\n\n");
    331 			usage(argv[0]);
    332 			exit(1);
    333 		}
    334 		while (optind < argc)
    335 			set_mode(mode, argv[optind++]);
    336 	}
    337 }
    338 
    339 int main(int argc, char *argv[])
    340 {
    341 	int i, commit = 0;
    342 	int result;
    343 	int status = EXIT_FAILURE;
    344 	char *genhomedirconargv[] = { "genhomedircon", "-B", "-n" };
    345 	create_signal_handlers();
    346 	if (strcmp(basename(argv[0]), "genhomedircon") == 0) {
    347 		argc = 3;
    348 		argv=genhomedirconargv;
    349 	}
    350 	parse_command_line(argc, argv);
    351 
    352 	if (build)
    353 		commit = 1;
    354 
    355 	sh = semanage_handle_create();
    356 	if (!sh) {
    357 		fprintf(stderr, "%s:  Could not create semanage handle\n",
    358 			argv[0]);
    359 		goto cleanup_nohandle;
    360 	}
    361 
    362 	if (store) {
    363 		/* Set the store we want to connect to, before connecting.
    364 		 * this will always set a direct connection now, an additional
    365 		 * option will need to be used later to specify a policy server
    366 		 * location */
    367 		semanage_select_store(sh, store, SEMANAGE_CON_DIRECT);
    368 	}
    369 
    370 	if (store_root) {
    371 		semanage_set_store_root(sh, store_root);
    372 	}
    373 
    374 	/* create store if necessary, for bootstrapping */
    375 	semanage_set_create_store(sh, 1);
    376 
    377 	if ((result = semanage_connect(sh)) < 0) {
    378 		fprintf(stderr, "%s:  Could not connect to policy handler\n",
    379 			argv[0]);
    380 		goto cleanup;
    381 	}
    382 
    383 	if (reload) {
    384 		if ((result = semanage_reload_policy(sh)) < 0) {
    385 			fprintf(stderr, "%s:  Could not reload policy\n",
    386 				argv[0]);
    387 			goto cleanup;
    388 		}
    389 	}
    390 
    391 	if (build) {
    392 		if ((result = semanage_begin_transaction(sh)) < 0) {
    393 			fprintf(stderr, "%s:  Could not begin transaction:  %s\n",
    394 				argv[0], errno ? strerror(errno) : "");
    395 			goto cleanup;
    396 		}
    397 	}
    398 
    399 	if ((result = semanage_set_default_priority(sh, priority)) != 0) {
    400 		fprintf(stderr,
    401 			"%s: Invalid priority %d (needs to be between 1 and 999)\n",
    402 			argv[0],
    403 			priority);
    404 		goto cleanup;
    405 	}
    406 
    407 	for (i = 0; i < num_commands; i++) {
    408 		enum client_modes mode = commands[i].mode;
    409 		char *mode_arg = commands[i].arg;
    410 
    411 		switch (mode) {
    412 		case INSTALL_M:{
    413 				if (verbose) {
    414 					printf
    415 					    ("Attempting to install module '%s':\n",
    416 					     mode_arg);
    417 				}
    418 				result =
    419 				    semanage_module_install_file(sh, mode_arg);
    420 				break;
    421 			}
    422 		case EXTRACT_M:{
    423 				semanage_module_info_t *extract_info = NULL;
    424 				semanage_module_key_t *modkey = NULL;
    425 				uint16_t curr_priority;
    426 				void *data = NULL;
    427 				size_t data_len = 0;
    428 				char output_path[PATH_MAX];
    429 				const char *output_name = NULL;
    430 				const char *lang_ext = NULL;
    431 				int rlen;
    432 				FILE *output_fd = NULL;
    433 
    434 				result = semanage_module_key_create(sh, &modkey);
    435 				if (result != 0) {
    436 					goto cleanup_extract;
    437 				}
    438 
    439 				result = semanage_module_key_set_name(sh, modkey, mode_arg);
    440 				if (result != 0) {
    441 					goto cleanup_extract;
    442 				}
    443 
    444 				if (priority_set == 0) {
    445 					result = semanage_module_get_module_info(sh, modkey, &extract_info);
    446 					if (result != 0) {
    447 						goto cleanup_extract;
    448 					}
    449 
    450 					semanage_module_info_get_priority(sh, extract_info, &curr_priority);
    451 					printf("Module '%s' does not exist at the default priority '%d'. "
    452 							"Extracting at highest existing priority '%d'.\n", mode_arg, priority, curr_priority);
    453 					priority = curr_priority;
    454 				}
    455 
    456 				result  = semanage_module_key_set_priority(sh, modkey, priority);
    457 				if (result != 0) {
    458 					goto cleanup_extract;
    459 				}
    460 
    461 				if (verbose) {
    462 					printf
    463 						("Attempting to extract module '%s':\n",
    464 							mode_arg);
    465 				}
    466 				result = semanage_module_extract(sh, modkey, extract_cil, &data, &data_len, &extract_info);
    467 				if (result != 0) {
    468 					goto cleanup_extract;
    469 				}
    470 
    471 				if (extract_cil) {
    472 					lang_ext = "cil";
    473 				} else {
    474 					result = semanage_module_info_get_lang_ext(sh, extract_info, &lang_ext);
    475 					if (result != 0) {
    476 						goto cleanup_extract;
    477 					}
    478 				}
    479 
    480 				result = semanage_module_info_get_name(sh, extract_info, &output_name);
    481 				if (result != 0) {
    482 					goto cleanup_extract;
    483 				}
    484 
    485 				rlen = snprintf(output_path, PATH_MAX, "%s.%s", output_name, lang_ext);
    486 				if (rlen < 0 || rlen >= PATH_MAX) {
    487 					fprintf(stderr, "%s: Failed to generate output path.\n", argv[0]);
    488 					result = -1;
    489 					goto cleanup_extract;
    490 				}
    491 
    492 				if (access(output_path, F_OK) == 0) {
    493 					fprintf(stderr, "%s: %s is already extracted with extension %s.\n", argv[0], mode_arg, lang_ext);
    494 					result = -1;
    495 					goto cleanup_extract;
    496 				}
    497 
    498 				output_fd = fopen(output_path, "w");
    499 				if (output_fd == NULL) {
    500 					fprintf(stderr, "%s: Unable to open %s\n", argv[0], output_path);
    501 					result = -1;
    502 					goto cleanup_extract;
    503 				}
    504 
    505 				if (fwrite(data, 1, data_len, output_fd) < data_len) {
    506 					fprintf(stderr, "%s: Unable to write to %s\n", argv[0], output_path);
    507 					result = -1;
    508 					goto cleanup_extract;
    509 				}
    510 cleanup_extract:
    511 				if (output_fd != NULL) {
    512 					fclose(output_fd);
    513 				}
    514 				if (data_len > 0) {
    515 					munmap(data, data_len);
    516 				}
    517 				semanage_module_info_destroy(sh, extract_info);
    518 				free(extract_info);
    519 				semanage_module_key_destroy(sh, modkey);
    520 				free(modkey);
    521 				break;
    522 			}
    523 		case CIL_M:
    524 				extract_cil = 1;
    525 				break;
    526 		case HLL_M:
    527 				extract_cil = 0;
    528 				break;
    529 		case REMOVE_M:{
    530 				if (verbose) {
    531 					printf
    532 					    ("Attempting to remove module '%s':\n",
    533 					     mode_arg);
    534 				}
    535 				result = semanage_module_remove(sh, mode_arg);
    536 				if ( result == -2 ) {
    537 					continue;
    538 				}
    539 				break;
    540 			}
    541 		case LIST_M:{
    542 				semanage_module_info_t *modinfos = NULL;
    543 				int modinfos_len = 0;
    544 				semanage_module_info_t *m = NULL;
    545 				int j = 0;
    546 
    547 				if (verbose) {
    548 					printf
    549 					    ("Attempting to list active modules:\n");
    550 				}
    551 
    552 				if (mode_arg == NULL || strcmp(mode_arg, "standard") == 0) {
    553 					result = semanage_module_list(sh,
    554 								      &modinfos,
    555 								      &modinfos_len);
    556 					if (result < 0) goto cleanup_list;
    557 
    558 					if (modinfos_len == 0) {
    559 						printf("No modules.\n");
    560 					}
    561 
    562 					const char *name = NULL;
    563 
    564 					for (j = 0; j < modinfos_len; j++) {
    565 						m = semanage_module_list_nth(modinfos, j);
    566 
    567 						result = semanage_module_info_get_name(sh, m, &name);
    568 						if (result != 0) goto cleanup_list;
    569 
    570 						printf("%s\n", name);
    571 					}
    572 				}
    573 				else if (strcmp(mode_arg, "full") == 0) {
    574 					/* get the modules */
    575 					result = semanage_module_list_all(sh,
    576 									  &modinfos,
    577 									  &modinfos_len);
    578 					if (result != 0) goto cleanup_list;
    579 
    580 					if (modinfos_len == 0) {
    581 						printf("No modules.\n");
    582 					}
    583 
    584 					/* calculate column widths */
    585 					size_t column[4] = { 0, 0, 0, 0 };
    586 
    587 					/* fixed width columns */
    588 					column[0] = sizeof("000") - 1;
    589 					column[3] = sizeof("disabled") - 1;
    590 
    591 					/* variable width columns */
    592 					const char *tmp = NULL;
    593 					size_t size;
    594 					for (j = 0; j < modinfos_len; j++) {
    595 						m = semanage_module_list_nth(modinfos, j);
    596 
    597 						result = semanage_module_info_get_name(sh, m, &tmp);
    598 						if (result != 0) goto cleanup_list;
    599 
    600 						size = strlen(tmp);
    601 						if (size > column[1]) column[1] = size;
    602 
    603 						result = semanage_module_info_get_lang_ext(sh, m, &tmp);
    604 						if (result != 0) goto cleanup_list;
    605 
    606 						size = strlen(tmp);
    607 						if (size > column[3]) column[3] = size;
    608 					}
    609 
    610 					/* print out each module */
    611 					for (j = 0; j < modinfos_len; j++) {
    612 						uint16_t pri = 0;
    613 						const char *name = NULL;
    614 						int enabled = 0;
    615 						const char *lang_ext = NULL;
    616 
    617 						m = semanage_module_list_nth(modinfos, j);
    618 
    619 						result = semanage_module_info_get_priority(sh, m, &pri);
    620 						if (result != 0) goto cleanup_list;
    621 
    622 						result = semanage_module_info_get_name(sh, m, &name);
    623 						if (result != 0) goto cleanup_list;
    624 
    625 						result = semanage_module_info_get_enabled(sh, m, &enabled);
    626 						if (result != 0) goto cleanup_list;
    627 
    628 						result = semanage_module_info_get_lang_ext(sh, m, &lang_ext);
    629 						if (result != 0) goto cleanup_list;
    630 
    631 						printf("%0*u %-*s %-*s %-*s\n",
    632 							(int)column[0], pri,
    633 							(int)column[1], name,
    634 							(int)column[2], lang_ext,
    635 							(int)column[3], enabled ? "" : "disabled");
    636 					}
    637 				}
    638 				else {
    639 					result = -1;
    640 				}
    641 
    642 cleanup_list:
    643 				for (j = 0; j < modinfos_len; j++) {
    644 					m = semanage_module_list_nth(modinfos, j);
    645 					semanage_module_info_destroy(sh, m);
    646 				}
    647 
    648 				free(modinfos);
    649 
    650 				break;
    651 			}
    652 		case PRIORITY_M:{
    653 				char *endptr = NULL;
    654 				priority = (uint16_t)strtoul(mode_arg, &endptr, 10);
    655 				priority_set = 1;
    656 
    657 				if ((result = semanage_set_default_priority(sh, priority)) != 0) {
    658 					fprintf(stderr,
    659 						"%s: Invalid priority %d (needs to be between 1 and 999)\n",
    660 						argv[0],
    661 						priority);
    662 					goto cleanup;
    663 				}
    664 
    665 				break;
    666 			}
    667 		case ENABLE_M:{
    668 				if (verbose) {
    669 					printf
    670 					    ("Attempting to enable module '%s':\n",
    671 					     mode_arg);
    672 				}
    673 
    674 				semanage_module_key_t *modkey = NULL;
    675 
    676 				result = semanage_module_key_create(sh, &modkey);
    677 				if (result != 0) goto cleanup_enable;
    678 
    679 				result = semanage_module_key_set_name(sh, modkey, mode_arg);
    680 				if (result != 0) goto cleanup_enable;
    681 
    682 				result = semanage_module_set_enabled(sh, modkey, 1);
    683 				if (result != 0) goto cleanup_enable;
    684 
    685 cleanup_enable:
    686 				semanage_module_key_destroy(sh, modkey);
    687 				free(modkey);
    688 
    689 				break;
    690 			}
    691 		case DISABLE_M:{
    692 				if (verbose) {
    693 					printf
    694 					    ("Attempting to disable module '%s':\n",
    695 					     mode_arg);
    696 				}
    697 
    698 				semanage_module_key_t *modkey = NULL;
    699 
    700 				result = semanage_module_key_create(sh, &modkey);
    701 				if (result != 0) goto cleanup_disable;
    702 
    703 				result = semanage_module_key_set_name(sh, modkey, mode_arg);
    704 				if (result != 0) goto cleanup_disable;
    705 
    706 				result = semanage_module_set_enabled(sh, modkey, 0);
    707 				if (result != 0) goto cleanup_disable;
    708 
    709 cleanup_disable:
    710 				semanage_module_key_destroy(sh, modkey);
    711 				free(modkey);
    712 
    713 				break;
    714 			}
    715 		default:{
    716 				fprintf(stderr,
    717 					"%s:  Unknown mode specified.\n",
    718 					argv[0]);
    719 				usage(argv[0]);
    720 				goto cleanup;
    721 			}
    722 		}
    723 		commit += do_commit[mode];
    724 		if (result < 0) {
    725 			fprintf(stderr, "%s:  Failed on %s!\n", argv[0],
    726 				mode_arg ? : "list");
    727 			goto cleanup;
    728 		} else if (verbose) {
    729 			printf("Ok: return value of %d.\n", result);
    730 		}
    731 	}
    732 
    733 	if (commit) {
    734 		if (verbose)
    735 			printf("Committing changes:\n");
    736 		if (no_reload)
    737 			semanage_set_reload(sh, 0);
    738 		if (build)
    739 			semanage_set_rebuild(sh, 1);
    740 		if (disable_dontaudit)
    741 			semanage_set_disable_dontaudit(sh, 1);
    742 		else if (build)
    743 			semanage_set_disable_dontaudit(sh, 0);
    744 		if (preserve_tunables)
    745 			semanage_set_preserve_tunables(sh, 1);
    746 		if (ignore_module_cache)
    747 			semanage_set_ignore_module_cache(sh, 1);
    748 
    749 		result = semanage_commit(sh);
    750 	}
    751 
    752 	if (result < 0) {
    753 		fprintf(stderr, "%s:  Failed!\n", argv[0]);
    754 		goto cleanup;
    755 	} else if (commit && verbose) {
    756 		printf("Ok: transaction number %d.\n", result);
    757 	}
    758 
    759 	if (semanage_disconnect(sh) < 0) {
    760 		fprintf(stderr, "%s:  Error disconnecting\n", argv[0]);
    761 		goto cleanup;
    762 	}
    763 	status = EXIT_SUCCESS;
    764 
    765       cleanup:
    766 	if (semanage_is_connected(sh)) {
    767 		if (semanage_disconnect(sh) < 0) {
    768 			fprintf(stderr, "%s:  Error disconnecting\n", argv[0]);
    769 		}
    770 	}
    771 	semanage_handle_destroy(sh);
    772 
    773       cleanup_nohandle:
    774 	cleanup();
    775 	exit(status);
    776 }
    777