semodule.c revision e4bc1b223debcc6747fef4d7a2a0a320c0208a88
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 23#include <semanage/modules.h> 24 25enum client_modes { NO_MODE, INSTALL_M, UPGRADE_M, BASE_M, ENABLE_M, DISABLE_M, REMOVE_M, 26 LIST_M, RELOAD 27}; 28/* list of modes in which one ought to commit afterwards */ 29static const int do_commit[] = { 30 0, 1, 1, 1, 1, 1, 1, 31 0, 0 32}; 33 34struct command { 35 enum client_modes mode; 36 char *arg; 37}; 38static struct command *commands = NULL; 39static int num_commands = 0; 40 41/* options given on command line */ 42static int verbose; 43static int reload; 44static int no_reload; 45static int create_store; 46static int build; 47static int disable_dontaudit; 48static int preserve_tunables; 49 50static semanage_handle_t *sh = NULL; 51static char *store; 52 53extern char *optarg; 54extern int optind; 55 56static void cleanup(void) 57{ 58 while (--num_commands >= 0) { 59 free(commands[num_commands].arg); 60 } 61 free(commands); 62} 63 64/* Signal handlers. */ 65static void handle_signal(int sig_num) 66{ 67 if (sig_num == SIGINT || sig_num == SIGQUIT || sig_num == SIGTERM) { 68 /* catch these signals, and then drop them */ 69 } 70} 71 72static void set_store(char *storename) 73{ 74 /* For now this only supports a store name, later on this 75 * should support an address for a remote connection */ 76 77 if ((store = strdup(storename)) == NULL) { 78 fprintf(stderr, "Out of memory!\n"); 79 goto bad; 80 } 81 82 return; 83 84 bad: 85 cleanup(); 86 exit(1); 87} 88 89/* Establish signal handlers for the process. */ 90static void create_signal_handlers(void) 91{ 92 if (signal(SIGINT, handle_signal) == SIG_ERR || 93 signal(SIGQUIT, handle_signal) == SIG_ERR || 94 signal(SIGTERM, handle_signal) == SIG_ERR) { 95 fprintf(stderr, "Could not set up signal handler.\n"); 96 exit(255); 97 } 98} 99 100static void usage(char *progname) 101{ 102 printf("usage: %s [options]... MODE [MODES]...\n", progname); 103 printf("Manage SELinux policy modules.\n"); 104 printf("MODES:\n"); 105 printf(" -R, --reload reload policy\n"); 106 printf(" -B, --build build and reload policy\n"); 107 printf(" -i,--install=MODULE_PKG install a new module\n"); 108 printf(" -u,--upgrade=MODULE_PKG upgrade existing module\n"); 109 printf(" -b,--base=MODULE_PKG install new base module\n"); 110 printf(" -e,--enable=MODULE_PKG enable existing module\n"); 111 printf(" -d,--disable=MODULE_PKG disable existing module\n"); 112 printf(" -r,--remove=MODULE_NAME remove existing module\n"); 113 printf 114 (" -l,--list-modules display list of installed modules\n"); 115 printf("Other options:\n"); 116 printf(" -s,--store name of the store to operate on\n"); 117 printf(" -n,--noreload do not reload policy after commit\n"); 118 printf(" -h,--help print this message and quit\n"); 119 printf(" -v,--verbose be verbose\n"); 120 printf(" -D,--disable_dontaudit Remove dontaudits from policy\n"); 121 printf(" -P,--preserve_tunables Preserve tunables in policy\n"); 122} 123 124/* Sets the global mode variable to new_mode, but only if no other 125 * mode has been given. */ 126static void set_mode(enum client_modes new_mode, char *arg) 127{ 128 struct command *c; 129 char *s; 130 if ((c = realloc(commands, sizeof(*c) * (num_commands + 1))) == NULL) { 131 fprintf(stderr, "Out of memory!\n"); 132 cleanup(); 133 exit(1); 134 } 135 commands = c; 136 commands[num_commands].mode = new_mode; 137 commands[num_commands].arg = NULL; 138 num_commands++; 139 if (arg != NULL) { 140 if ((s = strdup(arg)) == NULL) { 141 fprintf(stderr, "Out of memory!\n"); 142 cleanup(); 143 exit(1); 144 } 145 commands[num_commands - 1].arg = s; 146 } 147} 148 149/* Parse command line and set global options. */ 150static void parse_command_line(int argc, char **argv) 151{ 152 static struct option opts[] = { 153 {"store", required_argument, NULL, 's'}, 154 {"base", required_argument, NULL, 'b'}, 155 {"help", 0, NULL, 'h'}, 156 {"install", required_argument, NULL, 'i'}, 157 {"list-modules", 0, NULL, 'l'}, 158 {"verbose", 0, NULL, 'v'}, 159 {"enable", required_argument, NULL, 'e'}, 160 {"disable", required_argument, NULL, 'd'}, 161 {"remove", required_argument, NULL, 'r'}, 162 {"upgrade", required_argument, NULL, 'u'}, 163 {"reload", 0, NULL, 'R'}, 164 {"noreload", 0, NULL, 'n'}, 165 {"build", 0, NULL, 'B'}, 166 {"disable_dontaudit", 0, NULL, 'D'}, 167 {"preserve_tunables", 0, NULL, 'P'}, 168 {"path", required_argument, NULL, 'p'}, 169 {NULL, 0, NULL, 0} 170 }; 171 int i; 172 verbose = 0; 173 reload = 0; 174 no_reload = 0; 175 create_store = 0; 176 while ((i = 177 getopt_long(argc, argv, "p:s:b:hi:lvqe:d:r:u:RnBDP", opts, 178 NULL)) != -1) { 179 switch (i) { 180 case 'b': 181 set_mode(BASE_M, optarg); 182 create_store = 1; 183 break; 184 case 'h': 185 usage(argv[0]); 186 exit(0); 187 case 'i': 188 set_mode(INSTALL_M, optarg); 189 break; 190 case 'l': 191 set_mode(LIST_M, NULL); 192 break; 193 case 'v': 194 verbose = 1; 195 break; 196 case 'e': 197 set_mode(ENABLE_M, optarg); 198 break; 199 case 'd': 200 set_mode(DISABLE_M, optarg); 201 break; 202 case 'r': 203 set_mode(REMOVE_M, optarg); 204 break; 205 case 'p': 206 semanage_set_root(optarg); 207 break; 208 case 'u': 209 set_mode(UPGRADE_M, optarg); 210 break; 211 case 's': 212 set_store(optarg); 213 break; 214 case 'R': 215 reload = 1; 216 break; 217 case 'n': 218 no_reload = 1; 219 break; 220 case 'B': 221 build = 1; 222 break; 223 case 'D': 224 disable_dontaudit = 1; 225 break; 226 case 'P': 227 preserve_tunables = 1; 228 break; 229 case '?': 230 default:{ 231 usage(argv[0]); 232 exit(1); 233 } 234 } 235 } 236 if ((build || reload) && num_commands) { 237 fprintf(stderr, 238 "build or reload should not be used with other commands\n"); 239 usage(argv[0]); 240 exit(1); 241 } 242 if (num_commands == 0 && reload == 0 && build == 0) { 243 fprintf(stderr, "At least one mode must be specified.\n"); 244 usage(argv[0]); 245 exit(1); 246 } 247 248 if (optind < argc) { 249 int mode; 250 /* if -i/u/r was the last command treat any remaining 251 * arguments as args. Will allow 'semodule -i *.pp' to 252 * work as expected. 253 */ 254 255 if (commands && commands[num_commands - 1].mode == INSTALL_M) { 256 mode = INSTALL_M; 257 } else if (commands && commands[num_commands - 1].mode == UPGRADE_M) { 258 mode = UPGRADE_M; 259 } else if (commands && commands[num_commands - 1].mode == REMOVE_M) { 260 mode = REMOVE_M; 261 } else if (commands && commands[num_commands - 1].mode == ENABLE_M) { 262 mode = ENABLE_M; 263 } else if (commands && commands[num_commands - 1].mode == DISABLE_M) { 264 mode = DISABLE_M; 265 } else { 266 fprintf(stderr, "unknown additional arguments:\n"); 267 while (optind < argc) 268 fprintf(stderr, " %s", argv[optind++]); 269 fprintf(stderr, "\n\n"); 270 usage(argv[0]); 271 exit(1); 272 } 273 while (optind < argc) 274 set_mode(mode, argv[optind++]); 275 } 276} 277 278int main(int argc, char *argv[]) 279{ 280 int i, commit = 0; 281 int result; 282 int status = EXIT_FAILURE; 283 284 create_signal_handlers(); 285 parse_command_line(argc, argv); 286 287 if (build) 288 commit = 1; 289 290 sh = semanage_handle_create(); 291 if (!sh) { 292 fprintf(stderr, "%s: Could not create semanage handle\n", 293 argv[0]); 294 goto cleanup_nohandle; 295 } 296 297 if (store) { 298 /* Set the store we want to connect to, before connecting. 299 * this will always set a direct connection now, an additional 300 * option will need to be used later to specify a policy server 301 * location */ 302 semanage_select_store(sh, store, SEMANAGE_CON_DIRECT); 303 } 304 305 /* if installing base module create store if necessary, for bootstrapping */ 306 semanage_set_create_store(sh, create_store); 307 308 if (!create_store) { 309 if (!semanage_is_managed(sh)) { 310 fprintf(stderr, 311 "%s: SELinux policy is not managed or store cannot be accessed.\n", 312 argv[0]); 313 goto cleanup; 314 } 315 316 if (semanage_access_check(sh) < SEMANAGE_CAN_READ) { 317 fprintf(stderr, "%s: Cannot read policy store.\n", 318 argv[0]); 319 goto cleanup; 320 } 321 } 322 323 if ((result = semanage_connect(sh)) < 0) { 324 fprintf(stderr, "%s: Could not connect to policy handler\n", 325 argv[0]); 326 goto cleanup; 327 } 328 329 if (reload) { 330 if ((result = semanage_reload_policy(sh)) < 0) { 331 fprintf(stderr, "%s: Could not reload policy\n", 332 argv[0]); 333 goto cleanup; 334 } 335 } 336 337 if (build) { 338 if ((result = semanage_begin_transaction(sh)) < 0) { 339 fprintf(stderr, "%s: Could not begin transaction: %s\n", 340 argv[0], errno ? strerror(errno) : ""); 341 goto cleanup; 342 } 343 } 344 345 for (i = 0; i < num_commands; i++) { 346 enum client_modes mode = commands[i].mode; 347 char *mode_arg = commands[i].arg; 348 switch (mode) { 349 case INSTALL_M:{ 350 if (verbose) { 351 printf 352 ("Attempting to install module '%s':\n", 353 mode_arg); 354 } 355 result = 356 semanage_module_install_file(sh, mode_arg); 357 break; 358 } 359 case UPGRADE_M:{ 360 if (verbose) { 361 printf 362 ("Attempting to upgrade module '%s':\n", 363 mode_arg); 364 } 365 result = 366 semanage_module_upgrade_file(sh, mode_arg); 367 break; 368 } 369 case BASE_M:{ 370 if (verbose) { 371 printf 372 ("Attempting to install base module '%s':\n", 373 mode_arg); 374 } 375 result = 376 semanage_module_install_base_file(sh, mode_arg); 377 break; 378 } 379 case ENABLE_M:{ 380 if (verbose) { 381 printf 382 ("Attempting to enable module '%s':\n", 383 mode_arg); 384 } 385 result = semanage_module_enable(sh, mode_arg); 386 if ( result == -2 ) { 387 continue; 388 } 389 break; 390 } 391 case DISABLE_M:{ 392 if (verbose) { 393 printf 394 ("Attempting to disable module '%s':\n", 395 mode_arg); 396 } 397 result = semanage_module_disable(sh, mode_arg); 398 if ( result == -2 ) { 399 continue; 400 } 401 break; 402 } 403 case REMOVE_M:{ 404 if (verbose) { 405 printf 406 ("Attempting to remove module '%s':\n", 407 mode_arg); 408 } 409 result = semanage_module_remove(sh, mode_arg); 410 if ( result == -2 ) { 411 continue; 412 } 413 break; 414 } 415 case LIST_M:{ 416 semanage_module_info_t *modinfo; 417 int num_modules; 418 if (verbose) { 419 printf 420 ("Attempting to list active modules:\n"); 421 } 422 if ((result = 423 semanage_module_list(sh, &modinfo, 424 &num_modules)) >= 0) { 425 int j; 426 if (num_modules == 0) { 427 printf("No modules.\n"); 428 } 429 for (j = 0; j < num_modules; j++) { 430 semanage_module_info_t *m = 431 semanage_module_list_nth 432 (modinfo, j); 433 printf("%s\t%s\t%s\n", 434 semanage_module_get_name 435 (m), 436 semanage_module_get_version 437 (m), 438 (semanage_module_get_enabled(m) ? "" : "Disabled")); 439 semanage_module_info_datum_destroy 440 (m); 441 } 442 free(modinfo); 443 } 444 break; 445 } 446 default:{ 447 fprintf(stderr, 448 "%s: Unknown mode specified.\n", 449 argv[0]); 450 usage(argv[0]); 451 goto cleanup; 452 } 453 } 454 commit += do_commit[mode]; 455 if (result < 0) { 456 fprintf(stderr, "%s: Failed on %s!\n", argv[0], 457 mode_arg ? : "list"); 458 goto cleanup; 459 } else if (verbose) { 460 printf("Ok: return value of %d.\n", result); 461 } 462 } 463 464 if (commit) { 465 if (verbose) 466 printf("Committing changes:\n"); 467 if (no_reload) 468 semanage_set_reload(sh, 0); 469 if (build) 470 semanage_set_rebuild(sh, 1); 471 if (disable_dontaudit) 472 semanage_set_disable_dontaudit(sh, 1); 473 else if (build) 474 semanage_set_disable_dontaudit(sh, 0); 475 if (preserve_tunables) 476 semanage_set_preserve_tunables(sh, 1); 477 478 result = semanage_commit(sh); 479 } 480 481 if (result < 0) { 482 fprintf(stderr, "%s: Failed!\n", argv[0]); 483 goto cleanup; 484 } else if (commit && verbose) { 485 printf("Ok: transaction number %d.\n", result); 486 } 487 488 if (semanage_disconnect(sh) < 0) { 489 fprintf(stderr, "%s: Error disconnecting\n", argv[0]); 490 goto cleanup; 491 } 492 status = EXIT_SUCCESS; 493 494 cleanup: 495 if (semanage_is_connected(sh)) { 496 if (semanage_disconnect(sh) < 0) { 497 fprintf(stderr, "%s: Error disconnecting\n", argv[0]); 498 } 499 } 500 semanage_handle_destroy(sh); 501 502 cleanup_nohandle: 503 cleanup(); 504 exit(status); 505} 506