[apparmor] [PATCH] Add the ability for the parser to have a basic conf file, that defaults to /etc/apparmor/parser.conf (NOTE option to allow changing this is not provided currently).
Seth Arnold
seth.arnold at gmail.com
Fri Jul 29 02:19:04 UTC 2011
Hey John, this looks like a good idea, a few comments inline:
On Thu, Jul 28, 2011 at 6:30 PM, John Johansen
<john.johansen at canonical.com> wrote:
> Signed-off-by: John Johansen <john.johansen at canonical.com>
> ---
> parser/apparmor_parser.pod | 16 ++
> parser/parser_main.c | 407 +++++++++++++++++++++++++++-----------------
> 2 files changed, 270 insertions(+), 153 deletions(-)
>
> diff --git a/parser/apparmor_parser.pod b/parser/apparmor_parser.pod
> index a7e0add..11d2355 100644
> --- a/parser/apparmor_parser.pod
> +++ b/parser/apparmor_parser.pod
> @@ -199,6 +199,22 @@ Give a quick reference guide.
>
> =back
>
> +=head1 CONFIG FILE
> +
> +An optional config file /etc/apparmor/parser.conf can be used to specify the
> +default options for the parser, which then can be overriden using the command
s/overriden/overridden/
> +line options.
> +
> +The config file ignores leading whitespace and treats lines that begin with #
> +as comments. Config options are specified one per line usign the same format
s/usign/using/
> +as the longform command line options (without the preceeding --).
s/preceeding/preceding/
> +
> +Eg.
> + #comment
> +
> + optimize=no-expr-tree
> + optimize=compress-fast
> +
This anticipates my next question, but doesn't quite answer it: are all the
multiple-element options such as --Include and --Dump _accumulate_ values in
successive lines, or overwrite the previous value in successive lines? It'd
be super if the documentation explicitly says which is the case.
> =head1 BUGS
>
> If you find any bugs, please report them at
> diff --git a/parser/parser_main.c b/parser/parser_main.c
> index e28b2e0..06d3bef 100644
> --- a/parser/parser_main.c
> +++ b/parser/parser_main.c
> @@ -19,6 +19,7 @@
> * Ltd.
> */
>
> +#include <ctype.h>
> #include <stdio.h>
> #include <string.h>
> #include <stdlib.h>
> @@ -304,6 +305,242 @@ static void display_optimize(char *command)
> print_flag_table(optflag_table);
> }
>
> +
> +/* Treat conf file like options passed on command line
> + */
> +static int getopt_long_file(FILE *f, const struct option *longopts,
> + char **optarg, int *longindex)
> +{
> + static char line[256];
> + char *pos, *opt, *save;
> + int i;
> +
> + for (;;) {
> + if (!fgets(line, 256, f))
> + return -1;
> + pos = line;
> + while (isblank(*pos))
> + pos++;
> + if (*pos == '#')
> + continue;
> + opt = strtok_r(pos, " \t\r\n=", &save);
> + /* blank line */
> + if (!opt)
> + continue;
> +
> + for (i = 0; longopts[i].name &&
> + strcmp(longopts[i].name, opt) != 0; i++) ;
> + if (!longopts[i].name) {
> + PERROR("%p: unknown option (%s) in config file.\n",
The %p format specifier prints the void * value in hexadecimal. Probably %s
was meant. :)
> + progname, opt);
> + /* skip it */
> + continue;
> + }
> + break;
> + }
> +
> +
> + if (longindex)
> + *longindex = i;
> +
> + if (*save) {
> + int len;
> + while(isblank(*save))
> + save++;
> + len = strlen(save) - 1;
> + if (save[len] == '\n')
> + save[len] = 0;
> + }
> +
> + switch (longopts[i].has_arg) {
> + case 0:
> + *optarg = NULL;
> + break;
> + case 1:
> + if (!strlen(save)) {
> + *optarg = NULL;
> + return '?';
> + }
> + *optarg = save;
> + break;
> + case 2:
> + *optarg = save;
> + break;
> + default:
> + PERROR("%p: internal error bad longopt value\n", progname);
%p here, too.
> + exit(1);
> + }
> +
> + if (longopts[i].flag == NULL)
> + return longopts[i].val;
> + else
> + *longopts[i].flag = longopts[i].val;
> + return 0;
> +}
> +
> +/* process a single argment from getopt_long
> + * Returns: 1 if an action arg, else 0
> + */
> +static int process_arg(int c, char *optarg)
> +{
> + int count = 0;
> +
> + switch (c) {
> + case 0:
> + PERROR("Assert, in getopt_long handling\n");
> + display_usage(progname);
> + exit(0);
> + break;
> + case 'a':
> + count++;
> + option = OPTION_ADD;
> + break;
> + case 'd':
> + debug++;
> + skip_read_cache = 1;
> + break;
> + case 'h':
> + if (!optarg) {
> + display_usage(progname);
> + } else if (strcmp(optarg, "Dump") == 0 ||
> + strcmp(optarg, "dump") == 0 ||
> + strcmp(optarg, "D") == 0) {
> + display_dump(progname);
> + } else if (strcmp(optarg, "Optimize") == 0 ||
> + strcmp(optarg, "optimize") == 0 ||
> + strcmp(optarg, "O") == 0) {
> + display_optimize(progname);
> + } else {
> + PERROR("%s: Invalid --help option %s\n",
> + progname, optarg);
> + exit(1);
> + }
> + exit(0);
> + break;
> + case 'r':
> + count++;
> + option = OPTION_REPLACE;
> + break;
> + case 'R':
> + count++;
> + option = OPTION_REMOVE;
> + skip_cache = 1;
> + break;
> + case 'V':
> + display_version();
> + exit(0);
> + break;
> + case 'I':
> + add_search_dir(optarg);
> + break;
> + case 'b':
> + set_base_dir(optarg);
> + break;
> + case 'B':
> + binary_input = 1;
> + skip_cache = 1;
> + break;
> + case 'C':
> + opt_force_complain = 1;
> + skip_cache = 1;
> + break;
> + case 'N':
> + names_only = 1;
> + skip_cache = 1;
> + break;
> + case 'S':
> + count++;
> + option = OPTION_STDOUT;
> + skip_read_cache = 1;
> + kernel_load = 0;
> + break;
> + case 'o':
> + count++;
> + option = OPTION_OFILE;
> + skip_read_cache = 1;
> + kernel_load = 0;
> + ofile = fopen(optarg, "w");
> + if (!ofile) {
> + PERROR("%s: Could not open file %s\n",
> + progname, optarg);
> + exit(1);
> + }
> + break;
> + case 'f':
> + subdomainbase = strndup(optarg, PATH_MAX);
> + break;
> + case 'D':
> + skip_read_cache = 1;
> + if (!optarg) {
> + dump_vars = 1;
> + } else if (strcmp(optarg, "variables") == 0) {
> + dump_vars = 1;
> + } else if (strcmp(optarg, "expanded-variables") == 0) {
> + dump_expanded_vars = 1;
> + } else if (!handle_flag_table(dumpflag_table, optarg,
> + &dfaflags)) {
> + PERROR("%s: Invalid --Dump option %s\n",
> + progname, optarg);
> + exit(1);
> + }
> + break;
> + case 'O':
> + skip_read_cache = 1;
> +
> + if (!handle_flag_table(optflag_table, optarg,
> + &dfaflags)) {
> + PERROR("%s: Invalid --Optimize option %s\n",
> + progname, optarg);
> + exit(1);
> + }
> + break;
> + case 'm':
> + match_string = strdup(optarg);
> + break;
> + case 'q':
> + conf_verbose = 0;
> + conf_quiet = 1;
> + break;
> + case 'v':
> + conf_verbose = 1;
> + conf_quiet = 0;
> + break;
> + case 'n':
> + profile_namespace = strdup(optarg);
> + break;
> + case 'X':
> + read_implies_exec = 1;
> + break;
> + case 'K':
> + skip_cache = 1;
> + break;
> + case 'k':
> + show_cache = 1;
> + break;
> + case 'W':
> + write_cache = 1;
> + break;
> + case 'T':
> + skip_read_cache = 1;
> + break;
> + case 'Q':
> + kernel_load = 0;
> + break;
> + case 'p':
> + count++;
> + kernel_load = 0;
> + skip_cache = 1;
> + preprocess_only = 1;
> + skip_mode_force = 1;
> + break;
> + default:
> + display_usage(progname);
> + exit(0);
> + break;
> + }
> +
> + return count;
> +}
> +
> static int process_args(int argc, char *argv[])
> {
> int c, o;
> @@ -312,159 +549,7 @@ static int process_args(int argc, char *argv[])
>
> while ((c = getopt_long(argc, argv, "adf:h::rRVvI:b:BCD:NSm:qQn:XKTWkO:po:", long_options, &o)) != -1)
> {
> - switch (c) {
> - case 0:
> - PERROR("Assert, in getopt_long handling\n");
> - display_usage(progname);
> - exit(0);
> - break;
> - case 'a':
> - count++;
> - option = OPTION_ADD;
> - break;
> - case 'd':
> - debug++;
> - skip_read_cache = 1;
> - break;
> - case 'h':
> - if (!optarg) {
> - display_usage(progname);
> - } else if (strcmp(optarg, "Dump") == 0 ||
> - strcmp(optarg, "dump") == 0 ||
> - strcmp(optarg, "D") == 0) {
> - display_dump(progname);
> - } else if (strcmp(optarg, "Optimize") == 0 ||
> - strcmp(optarg, "optimize") == 0 ||
> - strcmp(optarg, "O") == 0) {
> - display_optimize(progname);
> - } else {
> - PERROR("%s: Invalid --help option %s\n",
> - progname, optarg);
> - exit(1);
> - }
> - exit(0);
> - break;
> - case 'r':
> - count++;
> - option = OPTION_REPLACE;
> - break;
> - case 'R':
> - count++;
> - option = OPTION_REMOVE;
> - skip_cache = 1;
> - break;
> - case 'V':
> - display_version();
> - exit(0);
> - break;
> - case 'I':
> - add_search_dir(optarg);
> - break;
> - case 'b':
> - set_base_dir(optarg);
> - break;
> - case 'B':
> - binary_input = 1;
> - skip_cache = 1;
> - break;
> - case 'C':
> - opt_force_complain = 1;
> - skip_cache = 1;
> - break;
> - case 'N':
> - names_only = 1;
> - skip_cache = 1;
> - break;
> - case 'S':
> - count++;
> - option = OPTION_STDOUT;
> - skip_read_cache = 1;
> - kernel_load = 0;
> - break;
> - case 'o':
> - count++;
> - option = OPTION_OFILE;
> - skip_read_cache = 1;
> - kernel_load = 0;
> - ofile = fopen(optarg, "w");
> - if (!ofile) {
> - PERROR("%s: Could not open file %s\n",
> - progname, optarg);
> - exit(1);
> - }
> - break;
> - case 'f':
> - subdomainbase = strndup(optarg, PATH_MAX);
> - break;
> - case 'D':
> - skip_read_cache = 1;
> - if (!optarg) {
> - dump_vars = 1;
> - } else if (strcmp(optarg, "variables") == 0) {
> - dump_vars = 1;
> - } else if (strcmp(optarg, "expanded-variables") == 0) {
> - dump_expanded_vars = 1;
> - } else if (!handle_flag_table(dumpflag_table, optarg,
> - &dfaflags)) {
> - PERROR("%s: Invalid --Dump option %s\n",
> - progname, optarg);
> - exit(1);
> - }
> - break;
> - case 'O':
> - skip_read_cache = 1;
> -
> - if (!handle_flag_table(optflag_table, optarg,
> - &dfaflags)) {
> - PERROR("%s: Invalid --Optimize option %s\n",
> - progname, optarg);
> - exit(1);
> - }
> - break;
> - case 'm':
> - match_string = strdup(optarg);
> - break;
> - case 'q':
> - conf_verbose = 0;
> - conf_quiet = 1;
> - break;
> - case 'v':
> - conf_verbose = 1;
> - conf_quiet = 0;
> - break;
> - case 'n':
> - profile_namespace = strdup(optarg);
> - break;
> - case 'X':
> - read_implies_exec = 1;
> - break;
> - case 'K':
> - skip_cache = 1;
> - break;
> - case 'k':
> - show_cache = 1;
> - break;
> - case 'W':
> - write_cache = 1;
> - break;
> - case 'T':
> - skip_read_cache = 1;
> - break;
> - case 'Q':
> - kernel_load = 0;
> - break;
> - case 'p':
> - count++;
> - kernel_load = 0;
> - skip_cache = 1;
> - preprocess_only = 1;
> - skip_mode_force = 1;
> - break;
> - default:
> - display_usage(progname);
> - exit(0);
> - break;
> - }
> + count += process_arg(c, optarg);
> }
>
> if (count > 1) {
> @@ -478,6 +563,21 @@ static int process_args(int argc, char *argv[])
> return optind;
> }
>
> +static int process_config_file(const char *name)
> +{
> + char *optarg;
> + FILE *f;
> + int c, o;
> +
> + f = fopen(name, "r");
> + if (!f)
> + return 0;
> +
> + while ((c = getopt_long_file(f, long_options, &optarg, &o)) != -1)
> + process_arg(c, optarg);
> + return 1;
> +}
> +
> static inline char *try_subdomainfs_mountpoint(const char *mntpnt,
> const char *path)
> {
> @@ -990,6 +1090,7 @@ int main(int argc, char *argv[])
>
> init_base_dir();
>
> + process_config_file("/etc/apparmor/parser.conf");
> optind = process_args(argc, argv);
>
> setlocale(LC_MESSAGES, "");
Thanks John!
More information about the AppArmor
mailing list