On Tue, 2010-01-26 at 17:08 -0500, Caleb Case wrote: > This adds the ability to retrieve the module source using semodule. > > -g,--get=MODULE_NAME [-o FILE] [-c] get module source > > * More than one -g is allowed per command invocation. > > * If output_name is “-“ then output is sent to standard out. > > * If output is specified multiple times with oufile_name "-", then > append to stdout. > > * If -o is not specified then the module is output to > <module name>.<language ext> in the current directory. > > * If there is an existing file with the output file name (with or > without -o), then emit error and exit. > > * -c will output the CIL instead of the source format. > > Example: > > # semodule -g alsa > > This will retrieve the high level language source for the alsa module > and save it to alsa.ref in the current directory. > --- > policycoreutils/semodule/semodule.8 | 3 + > policycoreutils/semodule/semodule.c | 227 ++++++++++++++++++++++++++++++++++- > 2 files changed, 228 insertions(+), 2 deletions(-) > > diff --git a/policycoreutils/semodule/semodule.8 b/policycoreutils/semodule/semodule.8 > index 5fc10b3..bb6ae49 100644 > --- a/policycoreutils/semodule/semodule.8 > +++ b/policycoreutils/semodule/semodule.8 > @@ -55,6 +55,9 @@ enable module > .B \-d,\-\-disable=MODULE_NAME > disable module > .TP > +.B \-g,\-\-get=MODULE_NAME [-o,--output=FILE] [-c,--cil] > +Outputs module source to MODULE_NAME.ref. If output is set to '-' outputs on stdout, otherwise, outputs to the specified FILE. If cil is specified, then outputs the cil source instead of the original source. > +.TP > .B \-s,\-\-store > name of the store to operate on > .TP > diff --git a/policycoreutils/semodule/semodule.c b/policycoreutils/semodule/semodule.c > index c6b0d3c..0e3cc76 100644 > --- a/policycoreutils/semodule/semodule.c > +++ b/policycoreutils/semodule/semodule.c > @@ -20,6 +20,7 @@ > #include <sys/mman.h> > #include <sys/stat.h> > #include <sys/types.h> > +#include <limits.h> > > #include <semanage/modules.h> > > @@ -27,17 +28,22 @@ > > enum client_modes { > NO_MODE, INSTALL_M, UPGRADE_M, BASE_M, REMOVE_M, > - LIST_M, RELOAD, PRIORITY_M, ENABLE_M, DISABLE_M > + LIST_M, RELOAD, PRIORITY_M, ENABLE_M, DISABLE_M, > + GET_M, > }; > + > /* list of modes in which one ought to commit afterwards */ > static const int do_commit[] = { > 0, 1, 1, 1, 1, > 0, 0, 0, 1, 1, > + 0, > }; > > struct command { > enum client_modes mode; > char *arg; > + char *output; > + int cil; > }; > static struct command *commands = NULL; > static int num_commands = 0; > @@ -61,6 +67,7 @@ static void cleanup(void) > { > while (--num_commands >= 0) { > free(commands[num_commands].arg); > + free(commands[num_commands].output); > } > free(commands); > } > @@ -117,6 +124,7 @@ static void usage(char *progname) > printf(" -p,--priority=PRIORITY set priority for following operations (1-999)\n"); > printf(" -e,--enable=MODULE_NAME enable module\n"); > printf(" -d,--disable=MODULE_NAME disable module\n"); > + printf(" -g,--get=MODULE_NAME [-o FILE] [-c] get module source\n"); > printf("Other options:\n"); > printf(" -s,--store name of the store to operate on\n"); > printf(" -n,--noreload do not reload policy after commit\n"); > @@ -139,6 +147,8 @@ static void set_mode(enum client_modes new_mode, char *arg) > commands = c; > commands[num_commands].mode = new_mode; > commands[num_commands].arg = NULL; > + commands[num_commands].output = NULL; > + commands[num_commands].cil = 0; > num_commands++; > if (arg != NULL) { > if ((s = strdup(arg)) == NULL) { > @@ -169,6 +179,9 @@ static void parse_command_line(int argc, char **argv) > {"priority", required_argument, NULL, 'p'}, > {"enable", required_argument, NULL, 'e'}, > {"disable", required_argument, NULL, 'd'}, > + {"get", required_argument, NULL, 'g'}, > + {"output", required_argument, NULL, 'o'}, > + {"cil", 0, NULL, 'c'}, > {NULL, 0, NULL, 0} > }; > int i; > @@ -178,7 +191,7 @@ static void parse_command_line(int argc, char **argv) > create_store = 0; > priority = 400; > while ((i = > - getopt_long(argc, argv, "s:b:hi:l::vqr:u:RnBDp:e:d:", opts, > + getopt_long(argc, argv, "s:b:hi:l::vqr:u:RnBDp:e:d:g:o:c", opts, > NULL)) != -1) { > switch (i) { > case 'b': > @@ -227,6 +240,53 @@ static void parse_command_line(int argc, char **argv) > case 'd': > set_mode(DISABLE_M, optarg); > break; > + case 'g': > + set_mode(GET_M, optarg); > + break; > + case 'o':{ > + /* no mode specified?? */ > + if (num_commands == 0) { > + usage(argv[0]); > + exit(1); > + } > + > + struct command *last = &commands[num_commands - 1]; > + > + /* only GET_M mode valid with -o */ > + if (last->mode != GET_M) { > + usage(argv[0]); > + exit(1); > + } > + > + last->output = strdup(optarg); > + if (last->output == NULL) { > + fprintf(stderr, > + "%s: Out of memory!\n", > + argv[0]); > + exit(1); > + } > + > + break; > + } > + case 'c':{ > + /* no mode specified?? */ > + if (num_commands == 0) { > + usage(argv[0]); > + exit(1); > + } > + > + struct command *last = &commands[num_commands - 1]; > + > + /* only GET_M mode valid with -c */ > + if (last->mode != GET_M) { > + usage(argv[0]); > + exit(1); > + } > + > + last->cil = 1; > + > + break; > + } > case '?': > default:{ > usage(argv[0]); > @@ -350,6 +410,8 @@ int main(int argc, char *argv[]) > for (i = 0; i < num_commands; i++) { > enum client_modes mode = commands[i].mode; > char *mode_arg = commands[i].arg; > + char *mode_output = commands[i].output; > + int mode_cil = commands[i].cil; > > switch (mode) { > case INSTALL_M:{ > @@ -582,6 +644,167 @@ cleanup_disable: > > break; > } > + case GET_M:{ > + if (verbose) { > + printf("Attempting to get module '%s':\n", mode_arg); > + } > + > + semanage_module_key_t *modkey = NULL; > + semanage_module_info_t *modinfo = NULL; > + const char *lang_ext = NULL; > + char *data = NULL; > + size_t data_len = 0; > + > + int fd = -1; > + FILE *out = NULL; > + size_t nwrite = 0; > + > + result = semanage_module_key_create(sh, > + &modkey); > + if (result != 0) goto cleanup_get; > + > + result = semanage_module_key_set_priority( > + sh, > + modkey, > + priority); > + if (result != 0) goto cleanup_get; > + > + result = semanage_module_key_set_name( > + sh, > + modkey, > + mode_arg); > + if (result != 0) goto cleanup_get; > + > + if (mode_cil == 0) { > + result = semanage_module_get( > + sh, > + modkey, > + &data, > + &data_len); > + } > + else { > + result = semanage_module_get_cil( > + sh, > + modkey, > + &data, > + &data_len); > + } > + if (result != 0) goto cleanup_get; > + > + /* get language extension */ > + result = semanage_module_get_module_info( > + sh, > + modkey, > + &modinfo); > + if (result != 0) goto cleanup_get; > + > + if (mode_cil == 0) { > + result = semanage_module_info_get_lang_ext( > + sh, > + modinfo, > + &lang_ext); > + if (result != 0) goto cleanup_get; > + } > + else { > + /* current cil is refpol */ > + lang_ext = "ref"; > + } > + > + if (mode_output == NULL || > + strcmp(mode_output, "-") != 0) { > + char path[PATH_MAX]; > + > + if (mode_output == NULL) { > + /* by default write out to <name>.<lang> */ > + /* compose path */ > + > + result = snprintf(path, > + sizeof(path) - 1, > + "%s.%s", > + mode_arg, > + lang_ext); > + if (result < 0 || > + result >= (int)sizeof(path)) { > + fprintf(stderr, > + "%s: Unable to compose path for output file.\n", > + argv[0]); > + result = -1; > + goto cleanup_get; > + } > + result = 0; > + } > + else { > + if (strlen(mode_output) > sizeof(path) - 1) { > + fprintf(stderr, > + "%s: Path too long (%d > %d): '%s'\n", > + argv[0], > + strlen(mode_output), > + sizeof(path) - 1, > + mode_output); I get the following warnings at the fprintf line: cc -Werror -Wall -W -I/usr/include -c -o semodule.o semodule.c cc1: warnings being treated as errors semodule.c: In function ‘main’: semodule.c:772: error: format ‘%d’ expects type ‘int’, but argument 4 has type ‘size_t’ semodule.c:772: error: format ‘%d’ expects type ‘int’, but argument 5 has type ‘long unsigned int’ make[2]: *** [semodule.o] Error 1 > + result = -1; > + goto cleanup_get; > + } > + strcpy(path, mode_output); > + } > + > + /* open file iff it doesn't exist */ > + fd = open(path, > + O_WRONLY | O_CREAT | O_EXCL, > + S_IRUSR | S_IWUSR); > + if (fd < 0) { > + fprintf(stderr, > + "%s: Unable to open output '%s'. (%s)\n", > + argv[0], > + path, > + strerror(errno)); > + result = -1; > + goto cleanup_get; > + } > + > + out = fdopen(fd, "w"); > + if (out == NULL) { > + fprintf(stderr, > + "%s: Unable to open output '%s'. (%s)\n", > + argv[0], > + path, > + strerror(errno)); > + result = -1; > + goto cleanup_get; > + } > + } > + else { > + /* otherwise we must be special '-' */ > + out = stdout; > + } > + > + nwrite = fwrite(data, > + data_len, > + 1, > + out); > + if (nwrite != 1) { > + fprintf(stderr, > + "%s: Failed to write module to output.\n", > + argv[0]); > + result = -1; > + goto cleanup_get; > + } > + > +cleanup_get: > + if (out != NULL && out != stdout) { > + fclose(out); > + fd = -1; > + } > + if (fd >= 0) close(fd); > + free(data); > + > + semanage_module_info_destroy(sh, modinfo); > + free(modinfo); > + > + semanage_module_key_destroy(sh, modkey); > + free(modkey); > + > + break; > + } > default:{ > fprintf(stderr, > "%s: Unknown mode specified.\n", -- James Carter <jwcart2@xxxxxxxxxxxxx> National Security Agency -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to majordomo@xxxxxxxxxxxxx with the words "unsubscribe selinux" without quotes as the message.