[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).

John Johansen john.johansen at canonical.com
Fri Jul 29 03:33:32 UTC 2011


On 07/28/2011 07:19 PM, Seth Arnold wrote:
> 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.
>
heh, its more complicated than that.  See the updated documentation


>>   =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. :)
>
doh, not sure why I put %p there?


Revised patch attached

---

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).

Signed-off-by: John Johansen <john.johansen at canonical.com>
---
  parser/apparmor_parser.pod |   32 ++++
  parser/parser_main.c       |  407 +++++++++++++++++++++++++++-----------------
  2 files changed, 286 insertions(+), 153 deletions(-)

diff --git a/parser/apparmor_parser.pod b/parser/apparmor_parser.pod
index a7e0add..cff59d6 100644
--- a/parser/apparmor_parser.pod
+++ b/parser/apparmor_parser.pod
@@ -199,6 +199,38 @@ 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 overridden using the command
+line options.
+
+The config file ignores leading whitespace and treats lines that begin with #
+as comments.  Config options are specified one per line using the same format
+as the longform command line options (without the preceding --).
+
+Eg.
+    #comment
+
+    optimize=no-expr-tree
+    optimize=compress-fast
+
+As with the command line some options accumulate and others override, ie. when
+there are conflicting versions of switch the last option is the one chosen.
+
+Eg.
+    Optimize=no-minimize
+    Optimize=minimize
+
+would result in Optimize=minimize being set.
+
+The Include, Dump, and Optimize options accululate except for the inversion
+option (no-X vs. X), and a couple options that work by setting/clearing
+multiple options (compress-small).  In that case the option will override
+the flags it sets but will may accumulate with others.
+
+All other options override previously set values.
+
  =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..a255bf5 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("%s: unknown option (%s) in config file.\n",
+			       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("%s: internal error bad longopt value\n", progname);
+		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, "");
-- 
1.7.5.4




More information about the AppArmor mailing list