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