[apparmor] [PATCH 9/9] Convert codomain to a class

John Johansen john.johansen at canonical.com
Wed Nov 7 20:00:55 UTC 2012


Conver the codomain to a class, and the policy lists that store
codomains to stl containers instead of glibc twalk.

Signed-off-by: John Johansen <john.johansen at canonical.com>
---
 parser/Makefile           |    7 +-
 parser/parser.h           |  144 +++--------
 parser/parser_alias.c     |   27 ++-
 parser/parser_interface.c |   95 ++++----
 parser/parser_lex.l       |    1 +
 parser/parser_merge.c     |   32 +--
 parser/parser_misc.c      |   70 +-----
 parser/parser_policy.c    |  578 +++++++++++----------------------------------
 parser/parser_regex.c     |  130 +++++-----
 parser/parser_symtab.c    |    3 +
 parser/parser_variable.c  |   67 +++---
 parser/parser_yacc.y      |  150 ++++++------
 parser/profile.cc         |   89 +++++++
 parser/profile.h          |  241 +++++++++++++++++++
 parser/unit_test.h        |   53 +++++
 15 files changed, 813 insertions(+), 874 deletions(-)
 create mode 100644 parser/profile.cc
 create mode 100644 parser/profile.h
 create mode 100644 parser/unit_test.h

diff --git a/parser/Makefile b/parser/Makefile
index 2f6bb2a..570aebe 100644
--- a/parser/Makefile
+++ b/parser/Makefile
@@ -76,8 +76,8 @@ EXTRA_CFLAGS+=-DSUBDOMAIN_CONFDIR=\"${CONFDIR}\"
 SRCS = parser_common.c parser_include.c parser_interface.c parser_lex.c \
        parser_main.c parser_misc.c parser_merge.c parser_symtab.c \
        parser_yacc.c parser_regex.c parser_variable.c parser_policy.c \
-       parser_alias.c mount.c lib.c
-HDRS = parser.h parser_include.h immunix.h mount.h lib.h
+       parser_alias.c mount.c lib.c profile.cc
+HDRS = parser.h parser_include.h immunix.h mount.h lib.h profile.h
 TOOLS = apparmor_parser
 
 OBJECTS = $(SRCS:.c=.o)
@@ -207,6 +207,9 @@ mount.o: mount.c mount.h parser.h immunix.h
 lib.o: lib.c lib.h parser.h
 	$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
 
+profile.o: profile.cc profile.h parser.h
+	$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
+
 parser_version.h: Makefile
 	@echo \#define PARSER_VERSION \"$(VERSION)\" > .ver
 	@mv -f .ver $@
diff --git a/parser/parser.h b/parser/parser.h
index 3642833..724cf04 100644
--- a/parser/parser.h
+++ b/parser/parser.h
@@ -22,12 +22,19 @@
 #ifndef __AA_PARSER_H
 #define __AA_PARSER_H
 
+
+#include <string.h>
 #include <netinet/in.h>
 #include <sys/resource.h>
 #include "immunix.h"
 #include "libapparmor_re/apparmor_re.h"
 #include "libapparmor_re/aare_rules.h"
 
+using namespace std;
+
+#include <set>
+class Profile;
+
 struct mnt_ent;
 
 /* Global variable to pass token to lexer.  Will be replaced by parameter
@@ -43,12 +50,6 @@ struct prefixes {
 	int owner;
 };
 
-struct flagval {
-  	int hat;
-  	int complain;
-  	int audit;
-	int path;
-};
 
 struct named_transition {
 	int present;
@@ -79,7 +80,7 @@ struct cod_entry {
 	char *name;
 	char *link_name;
 	char *nt_name;
-	struct codomain *codomain; 	/* Special codomain defined
+	Profile *prof;		 	/* Special profile defined
 					 * just for this executable */
 	int mode;			/* mode is 'or' of AA_* bits */
 	int audit;			/* audit flags for mode */
@@ -114,56 +115,6 @@ struct alt_name {
 	struct alt_name *next;
 };
 
-struct codomain {
-	char *ns;
-	char *name;				/* codomain name */
-	char *attachment;
-	struct alt_name *altnames;
-	void *xmatch;
-	size_t xmatch_size;
-	int xmatch_len;
-
-	/* char *sub_name; */			/* subdomain name or NULL */
-	/* int default_deny; */			/* TRUE or FALSE */
-	int local;
-	int local_mode;				/* true if local, not hat */
-	int local_audit;
-
-	struct codomain *parent;
-
-	struct flagval flags;
-
-	uint64_t capabilities;
-	uint64_t audit_caps;
-	uint64_t deny_caps;
-	uint64_t quiet_caps;
-
-	unsigned int *network_allowed;		/* array of type masks
-						 * indexed by AF_FAMILY */
-	unsigned int *audit_network;
-	unsigned int *deny_network;
-	unsigned int *quiet_network;
-
-	struct aa_rlimits rlimits;
-
-	char *exec_table[AA_EXEC_COUNT];
-	struct cod_entry *entries;
-	struct mnt_entry *mnt_ents;
-
-	void *hat_table;
-	//struct codomain *next;
-
-	aare_ruleset_t *dfarules;
-	int dfarule_count;
-	void *dfa;
-	size_t dfa_size;
-
-	aare_ruleset_t *policy_rules;
-	int policy_rule_count;
-	void *policy_dfa;
-	size_t policy_dfa_size;
-};
-
 struct sd_hat {
 	char *hat_name;
 	unsigned int hat_magic;
@@ -301,16 +252,14 @@ extern int yylex(void);
 extern char *basedir;
 
 /* parser_regex.c */
-extern int process_regex(struct codomain *cod);
+extern int process_regex(Profile *prof);
 extern int post_process_entry(struct cod_entry *entry);
 extern void reset_regex(void);
 
-extern int process_policydb(struct codomain *cod);
-
-extern int process_policy_ents(struct codomain *cod);
+extern int process_policy_ents(Profile *prof);
 
 /* parser_variable.c */
-extern int process_variables(struct codomain *cod);
+extern int process_variables(Profile *prof);
 extern struct var_string *split_out_var(char *string);
 extern void free_var_string(struct var_string *var);
 
@@ -340,12 +289,15 @@ extern struct aa_network_entry *network_entry(const char *family,
 					      const char *protocol);
 extern size_t get_af_max(void);
 
-extern void debug_cod_list(struct codomain *list);
 /* returns -1 if value != true or false, otherwise 0 == false, 1 == true */
 extern int str_to_boolean(const char* str);
 extern struct cod_entry *copy_cod_entry(struct cod_entry *cod);
 extern void free_cod_entries(struct cod_entry *list);
 extern void free_mnt_entries(struct mnt_entry *list);
+extern void __debug_capabilities(uint64_t capset, const char *name);
+void __debug_network(unsigned int *array, const char *name);
+void debug_cod_entries(struct cod_entry *list);
+
 
 /* parser_symtab.c */
 struct set_value {;
@@ -364,71 +316,41 @@ void free_symtabs(void);
 
 /* parser_alias.c */
 extern int new_alias(const char *from, const char *to);
-extern void replace_aliases(struct codomain *cod);
+extern int replace_profile_aliases(Profile *prof);
 extern void free_aliases(void);
 
 /* parser_merge.c */
-extern int codomain_merge_rules(struct codomain *cod);
+extern int profile_merge_rules(Profile *prof);
 
 /* parser_interface.c */
 typedef struct __sdserialize sd_serialize;
-extern int load_codomain(int option, struct codomain *cod);
-extern int sd_serialize_profile(sd_serialize *p, struct codomain *cod,
+extern int load_profile(int option, Profile *prof);
+extern int sd_serialize_profile(sd_serialize *p, Profile *prof,
 				int flatten);
 extern int sd_load_buffer(int option, char *buffer, int size);
 extern int cache_fd;
 
 
 /* parser_policy.c */
-extern void add_to_list(struct codomain *codomain);
-extern void add_hat_to_policy(struct codomain *policy, struct codomain *hat);
-extern void add_entry_to_policy(struct codomain *policy, struct cod_entry *entry);
-extern void post_process_file_entries(struct codomain *cod);
-extern void post_process_mnt_entries(struct codomain *cod);
+extern void add_to_list(Profile *profile);
+extern void add_hat_to_policy(Profile *policy, Profile *hat);
+extern void add_entry_to_policy(Profile *policy, struct cod_entry *entry);
+extern void post_process_file_entries(Profile *prof);
+extern void post_process_mnt_entries(Profile *prof);
 extern int post_process_policy(int debug_only);
-extern int process_hat_regex(struct codomain *cod);
-extern int process_hat_variables(struct codomain *cod);
-extern int process_hat_policydb(struct codomain *cod);
+extern int process_profile_regex(Profile *prof);
+extern int process_profile_variables(Profile *prof);
+extern int process_profile_policydb(Profile *prof);
 extern int post_merge_rules(void);
-extern int merge_hat_rules(struct codomain *cod);
-extern struct codomain *merge_policy(struct codomain *a, struct codomain *b);
+extern int merge_hat_rules(Profile *prof);
+extern Profile *merge_policy(Profile *a, Profile *b);
 extern int load_policy(int option);
-extern int load_hats(sd_serialize *p, struct codomain *cod);
-extern int load_flattened_hats(struct codomain *cod);
-extern void free_policy(struct codomain *cod);
-extern void dump_policy(void);
-extern void dump_policy_hats(struct codomain *cod);
+extern int load_hats(sd_serialize *p, Profile *prof);
+extern int load_flattened_hats(Profile *prof, int option);
+extern void dump_policy_hats(Profile *prof);
 extern void dump_policy_names(void);
+void dump_policy(void);
 
 void free_policies(void);
 
-#ifdef UNIT_TEST
-/* For the unit-test builds, we must include function stubs for stuff that
- * only exists in the excluded object files; everything else should live
- * in parser_common.c.
- */
-
-/* parser_yacc.y */
-void yyerror(const char *msg, ...)
-{
-        va_list arg;
-        char buf[PATH_MAX];
-
-        va_start(arg, msg);
-        vsnprintf(buf, sizeof(buf), msg, arg);
-        va_end(arg);
-
-        PERROR(_("AppArmor parser error: %s\n"), buf);
-
-        exit(1);
-}
-
-#define MY_TEST(statement, error)               \
-        if (!(statement)) {                     \
-                PERROR("FAIL: %s\n", error);    \
-                rc = 1;                         \
-        }
-
-#endif
-
 #endif /** __AA_PARSER_H */
diff --git a/parser/parser_alias.c b/parser/parser_alias.c
index aee882e..aea9f1a 100644
--- a/parser/parser_alias.c
+++ b/parser/parser_alias.c
@@ -25,6 +25,7 @@
 
 #include "immunix.h"
 #include "parser.h"
+#include "profile.h"
 
 struct alias_rule {
 	char *from;
@@ -105,7 +106,7 @@ static char *do_alias(struct alias_rule *alias, const char *target)
 	return n;
 }
 
-static struct codomain *target_cod;
+static Profile *target_prof;
 static struct cod_entry *target_list;
 static void process_entries(const void *nodep, VISIT value, int __unused level)
 {
@@ -155,7 +156,7 @@ static void process_entries(const void *nodep, VISIT value, int __unused level)
 static void process_name(const void *nodep, VISIT value, int __unused level)
 {
 	struct alias_rule **t = (struct alias_rule **) nodep;
-	struct codomain *cod = target_cod;
+	Profile *prof = target_prof;
 	char *name;
 	int len;
 
@@ -164,10 +165,10 @@ static void process_name(const void *nodep, VISIT value, int __unused level)
 
 	len = strlen((*t)->from);
 
-	if (cod->attachment)
-		name = cod->attachment;
+	if (prof->attachment)
+		name = prof->attachment;
 	else
-		name = cod->name;
+		name = prof->name;
 
 	if (name && strncmp((*t)->from, name, len) == 0) {
 		struct alt_name *alt;
@@ -179,21 +180,23 @@ static void process_name(const void *nodep, VISIT value, int __unused level)
 		if (!alt)
 			return;
 		alt->name = n;
-		alt->next = cod->altnames;
-		cod->altnames = alt;
+		alt->next = prof->altnames;
+		prof->altnames = alt;
 	}
 }
 
-void replace_aliases(struct codomain *cod)
+int replace_profile_aliases(Profile *prof)
 {
-	target_cod = cod;
+	target_prof = prof;
 	twalk(alias_table, process_name);
 
-	if (cod->entries) {
-		target_list = cod->entries;
-		target_cod = cod;
+	if (prof->entries) {
+		target_list = prof->entries;
+		target_prof = prof;
 		twalk(alias_table, process_entries);
 	}
+
+	return 0;
 }
 
 static void free_alias(void *nodep)
diff --git a/parser/parser_interface.c b/parser/parser_interface.c
index 77f3d2e..d47cca2 100644
--- a/parser/parser_interface.c
+++ b/parser/parser_interface.c
@@ -25,6 +25,7 @@
 #define _(s) gettext(s)
 
 #include "parser.h"
+#include "profile.h"
 #include "libapparmor_re/apparmor_re.h"
 
 #include <unistd.h>
@@ -59,7 +60,7 @@
 
 #define SUBDOMAIN_INTERFACE_DFA_VERSION 5
 
-int sd_serialize_codomain(int option, struct codomain *cod);
+int sd_serialize_profile(int option, Profile *prof);
 
 static void print_error(int error)
 {
@@ -100,30 +101,30 @@ static void print_error(int error)
 	}
 }
 
-int load_codomain(int option, struct codomain *cod)
+int load_profile(int option, Profile *prof)
 {
 	int retval = 0;
 	int error = 0;
 
-	PDEBUG("Serializing policy for %s.\n", cod->name);
-	retval = sd_serialize_codomain(option, cod);
+	PDEBUG("Serializing policy for %s.\n", prof->name);
+	retval = sd_serialize_profile(option, prof);
 
 	if (retval < 0) {
 		error = retval;	/* yeah, we'll just report the last error */
 		switch (option) {
 		case OPTION_ADD:
 			PERROR(_("%s: Unable to add \"%s\".  "),
-			       progname, cod->name);
+			       progname, prof->name);
 			print_error(error);
 			break;
 		case OPTION_REPLACE:
 			PERROR(_("%s: Unable to replace \"%s\".  "),
-			       progname, cod->name);
+			       progname, prof->name);
 			print_error(error);
 			break;
 		case OPTION_REMOVE:
 			PERROR(_("%s: Unable to remove \"%s\".  "),
-			       progname, cod->name);
+			       progname, prof->name);
 			print_error(error);
 			break;
 		case OPTION_STDOUT:
@@ -144,15 +145,15 @@ int load_codomain(int option, struct codomain *cod)
 		switch (option) {
 		case OPTION_ADD:
 			printf(_("Addition succeeded for \"%s\".\n"),
-			       cod->name);
+			       prof->name);
 			break;
 		case OPTION_REPLACE:
 			printf(_("Replacement succeeded for \"%s\".\n"),
-			       cod->name);
+			       prof->name);
 			break;
 		case OPTION_REMOVE:
 			printf(_("Removal succeeded for \"%s\".\n"),
-			       cod->name);
+			       prof->name);
 			break;
 		case OPTION_STDOUT:
 		case OPTION_OFILE:
@@ -544,7 +545,7 @@ int count_tailglob_ents(struct cod_entry *list)
 	return count;
 }
 
-int sd_serialize_profile(sd_serialize *p, struct codomain *profile,
+int sd_serialize_profile(sd_serialize *p, Profile *profile,
 			 int flattened)
 {
 	uint64_t allowed_caps;
@@ -608,12 +609,12 @@ int sd_serialize_profile(sd_serialize *p, struct codomain *profile,
 
 #define low_caps(X) ((u32) ((X) & 0xffffffff))
 #define high_caps(X) ((u32) (((X) >> 32) & 0xffffffff))
-	allowed_caps = (profile->capabilities) & ~profile->deny_caps;
+	allowed_caps = (profile->caps.allow) & ~profile->caps.deny;
 	if (!sd_write32(p, low_caps(allowed_caps)))
 		return 0;
-	if (!sd_write32(p, low_caps(allowed_caps & profile->audit_caps)))
+	if (!sd_write32(p, low_caps(allowed_caps & profile->caps.audit)))
 		return 0;
-	if (!sd_write32(p, low_caps(profile->deny_caps & profile->quiet_caps)))
+	if (!sd_write32(p, low_caps(profile->caps.deny & profile->caps.quiet)))
 		return 0;
 	if (!sd_write32(p, 0))
 		return 0;
@@ -622,9 +623,9 @@ int sd_serialize_profile(sd_serialize *p, struct codomain *profile,
 		return 0;
 	if (!sd_write32(p, high_caps(allowed_caps)))
 		return 0;
-	if (!sd_write32(p, high_caps(allowed_caps & profile->audit_caps)))
+	if (!sd_write32(p, high_caps(allowed_caps & profile->caps.audit)))
 		return 0;
-	if (!sd_write32(p, high_caps(profile->deny_caps & profile->quiet_caps)))
+	if (!sd_write32(p, high_caps(profile->caps.deny & profile->caps.quiet)))
 		return 0;
 	if (!sd_write32(p, 0))
 		return 0;
@@ -634,42 +635,42 @@ int sd_serialize_profile(sd_serialize *p, struct codomain *profile,
 	if (!sd_serialize_rlimits(p, &profile->rlimits))
 		return 0;
 
-	if (profile->network_allowed && kernel_supports_network) {
+	if (profile->net.allow && kernel_supports_network) {
 		size_t i;
 		if (!sd_write_array(p, "net_allowed_af", get_af_max()))
 			return 0;
 		for (i = 0; i < get_af_max(); i++) {
-		    u16 allowed = profile->network_allowed[i] &
-			~profile->deny_network[i];
+		    u16 allowed = profile->net.allow[i] &
+			~profile->net.deny[i];
 			if (!sd_write16(p, allowed))
 				return 0;
-			if (!sd_write16(p, allowed & profile->audit_network[i]))
+			if (!sd_write16(p, allowed & profile->net.audit[i]))
 				return 0;
-			if (!sd_write16(p, profile->deny_network[i] & profile->quiet_network[i]))
+			if (!sd_write16(p, profile->net.deny[i] & profile->net.quiet[i]))
 				return 0;
 		}
 		if (!sd_write_arrayend(p))
 			return 0;
-	} else if (profile->network_allowed)
+	} else if (profile->net.allow)
 		pwarn(_("profile %s network rules not enforced\n"), profile->name);
 
-	if (profile->policy_dfa) {
+	if (profile->policy.dfa) {
 		if (!sd_write_struct(p, "policydb"))
 			return 0;
-		if (!sd_serialize_dfa(p, profile->policy_dfa, profile->policy_dfa_size))
+		if (!sd_serialize_dfa(p, profile->policy.dfa, profile->policy.size))
 			return 0;
 		if (!sd_write_structend(p))
 			return 0;
 	}
 
 	/* either have a single dfa or lists of different entry types */
-	if (!sd_serialize_dfa(p, profile->dfa, profile->dfa_size))
+	if (!sd_serialize_dfa(p, profile->dfa.dfa, profile->dfa.size))
 		return 0;
 
 	if (!sd_serialize_xtable(p, profile->exec_table))
 		return 0;
 
-	if (profile->hat_table) {
+	if (!profile->hat_table.empty()) {
 		if (!sd_write_list(p, "hats"))
 			return 0;
 		if (load_hats(p, profile) != 0)
@@ -684,7 +685,7 @@ int sd_serialize_profile(sd_serialize *p, struct codomain *profile,
 	return 1;
 }
 
-int sd_serialize_top_profile(sd_serialize *p, struct codomain *profile)
+int sd_serialize_top_profile(sd_serialize *p, Profile *profile)
 {
 	int version;
 
@@ -708,7 +709,7 @@ int sd_serialize_top_profile(sd_serialize *p, struct codomain *profile)
 }
 
 int cache_fd = -1;
-int sd_serialize_codomain(int option, struct codomain *cod)
+int sd_serialize_profile(int option, Profile *prof)
 {
 	int fd = -1;
 	int error = -ENOMEM, size, wsize;
@@ -763,34 +764,34 @@ int sd_serialize_codomain(int option, struct codomain *cod)
 		if (profile_ns) {
 			len += strlen(profile_ns) + 2;
 			ns = profile_ns;
-		} else if (cod->ns) {
-			len += strlen(cod->ns) + 2;
-			ns = cod->ns;
+		} else if (prof->ns) {
+			len += strlen(prof->ns) + 2;
+			ns = prof->ns;
 		}
-		if (cod->parent) {
-			name = (char *) malloc(strlen(cod->name) + 3 +
-				      strlen(cod->parent->name) + len);
+		if (prof->parent) {
+			name = (char *) malloc(strlen(prof->name) + 3 +
+				      strlen(prof->parent->name) + len);
 			if (!name) {
-				PERROR(_("Memory Allocation Error: Unable to remove ^%s\n"), cod->name);
+				PERROR(_("Memory Allocation Error: Unable to remove ^%s\n"), prof->name);
 				error = -errno;
 				goto exit;
 			}
 			if (ns)
 				sprintf(name, ":%s:%s//%s", ns,
-					cod->parent->name, cod->name);
+					prof->parent->name, prof->name);
 			else
-				sprintf(name, "%s//%s", cod->parent->name,
-					cod->name);
+				sprintf(name, "%s//%s", prof->parent->name,
+					prof->name);
 		} else if (ns) {
-			name = (char *) malloc(len + strlen(cod->name) + 1);
+			name = (char *) malloc(len + strlen(prof->name) + 1);
 			if (!name) {
-				PERROR(_("Memory Allocation Error: Unable to remove %s:%s."), ns, cod->name);
+				PERROR(_("Memory Allocation Error: Unable to remove %s:%s."), ns, prof->name);
 				error = -errno;
 				goto exit;
 			}
-			sprintf(name, ":%s:%s", ns, cod->name);
+			sprintf(name, ":%s:%s", ns, prof->name);
 		} else {
-			name = cod->name;
+			name = prof->name;
 		}
 		size = strlen(name) + 1;
 		if (kernel_load) {
@@ -798,7 +799,7 @@ int sd_serialize_codomain(int option, struct codomain *cod)
 			if (wsize < 0)
 				error = -errno;
 		}
-		if (cod->parent || ns)
+		if (prof->parent || ns)
 			free(name);
 	} else {
 
@@ -810,11 +811,11 @@ int sd_serialize_codomain(int option, struct codomain *cod)
 			goto exit;
 		}
 
-		if (!sd_serialize_top_profile(work_area, cod)) {
+		if (!sd_serialize_top_profile(work_area, prof)) {
 			close(fd);
 			free_sd_serial(work_area);
 			PERROR(_("unable to serialize profile %s\n"),
-			       cod->name);
+			       prof->name);
 			goto exit;
 		}
 
@@ -844,8 +845,8 @@ int sd_serialize_codomain(int option, struct codomain *cod)
 
 	close(fd);
 
-	if (cod->hat_table && option != OPTION_REMOVE) {
-		if (load_flattened_hats(cod) != 0)
+	if (!prof->hat_table.empty() && option != OPTION_REMOVE) {
+		if (load_flattened_hats(prof, option) != 0)
 			return 0;
 	}
 
diff --git a/parser/parser_lex.l b/parser/parser_lex.l
index d27afc7..8c613a1 100644
--- a/parser/parser_lex.l
+++ b/parser/parser_lex.l
@@ -37,6 +37,7 @@
 #define _(s) gettext(s)
 
 #include "parser.h"
+#include "profile.h"
 #include "parser_include.h"
 #include "parser_yacc.h"
 #include "lib.h"
diff --git a/parser/parser_merge.c b/parser/parser_merge.c
index 3b0baea..31d12dd 100644
--- a/parser/parser_merge.c
+++ b/parser/parser_merge.c
@@ -25,7 +25,7 @@
 #define _(s) gettext(s)
 
 #include "parser.h"
-
+#include "profile.h"
 
 static int file_comp(const void *c1, const void *c2)
 {
@@ -74,27 +74,27 @@ static int file_comp(const void *c1, const void *c2)
 	return strcmp((*e1)->name, (*e2)->name);
 }
 
-static int process_file_entries(struct codomain *cod)
+static int process_file_entries(Profile *prof)
 {
 	int n, count;
 	struct cod_entry *flist, *cur, *next;
 	struct cod_entry **table;
 
-	for (flist = cod->entries, n = 0; flist; flist = flist->next)
+	for (flist = prof->entries, n = 0; flist; flist = flist->next)
 		n++;
 
 	count = n;
 	if (count < 2)
-		return 1;
+		return 0;
 
 	table = (struct cod_entry **) malloc(sizeof(struct cod_entry *) * (count + 1));
 	if (!table) {
 		PERROR(_("Couldn't merge entries. Out of Memory\n"));
-		return 0;
+		return ENOMEM;
 	}
 
 	n = 0;
-	for (flist = cod->entries; flist; flist = flist->next) {
+	for (flist = prof->entries; flist; flist = flist->next) {
 		table[n] = flist;
 		n++;
 	}
@@ -110,8 +110,8 @@ static int process_file_entries(struct codomain *cod)
 			if (!is_merged_x_consistent(cur->mode, next->mode)) {
 				PERROR(_("profile %s: has merged rule %s with "
 					 "conflicting x modifiers\n"),
-					 cod->name, cur->name);
-				return 0;
+					 prof->name, cur->name);
+				return -1;
 			}
 //if (next->audit)
 //fprintf(stderr, "warning: merging rule 0x%x %s\n", next->audit, next->name);
@@ -136,22 +136,14 @@ static int process_file_entries(struct codomain *cod)
 		}
 	}
 	cur->next = NULL;
-	cod->entries = table[0];
+	prof->entries = table[0];
 
 	free(table);
 
-	return 1;
+	return 0;
 }
 
-int codomain_merge_rules(struct codomain *cod)
+int profile_merge_rules(Profile *prof)
 {
-	if (!process_file_entries(cod))
-		goto fail;
-
-	/* XXX  return error from this */
-	merge_hat_rules(cod);
-
-	return 1;
-fail:
-	return 0;
+  return process_file_entries(prof);
 }
diff --git a/parser/parser_misc.c b/parser/parser_misc.c
index 51a0768..1708ea3 100644
--- a/parser/parser_misc.c
+++ b/parser/parser_misc.c
@@ -36,6 +36,7 @@
 #include <unistd.h>
 
 #include "parser.h"
+#include "profile.h"
 #include "parser_yacc.h"
 #include "mount.h"
 
@@ -854,23 +855,6 @@ void debug_cod_entries(struct cod_entry *list)
 	}
 }
 
-void debug_flags(struct codomain *cod)
-{
-	printf("Profile Mode:\t");
-
-	if (cod->flags.complain)
-		printf("Complain");
-	else
-		printf("Enforce");
-
-	if (cod->flags.audit)
-		printf(", Audit");
-
-	if (cod->flags.hat)
-		printf(", Hat");
-
-	printf("\n");
-}
 
 static const char *capnames[] = {
 	"chown",
@@ -931,17 +915,6 @@ void __debug_capabilities(uint64_t capset, const char *name)
 	}
 	printf("\n");
 }
-void debug_capabilities(struct codomain *cod)
-{
-	if (cod->capabilities != 0ull)
-		__debug_capabilities(cod->capabilities, "Capabilities");
-	if (cod->audit_caps != 0ull)
-		__debug_capabilities(cod->audit_caps, "Audit Caps");
-	if (cod->deny_caps != 0ull)
-		__debug_capabilities(cod->deny_caps, "Deny Caps");
-	if (cod->quiet_caps != 0ull)
-		__debug_capabilities(cod->quiet_caps, "Quiet Caps");
-}
 
 /* Bleah C++ doesn't have non-trivial designated initializers so we just
  * have to make sure these are in order.  This means we are more brittle
@@ -1031,44 +1004,6 @@ void __debug_network(unsigned int *array, const char *name)
 	printf("\n");
 }
 
-void debug_network(struct codomain *cod)
-{
-	if (cod->network_allowed)
-		__debug_network(cod->network_allowed, "Network");
-	if (cod->audit_network)
-		__debug_network(cod->audit_network, "Audit Net");
-	if (cod->deny_network)
-		__debug_network(cod->deny_network, "Deny Net");
-	if (cod->quiet_network)
-		__debug_network(cod->quiet_network, "Quiet Net");
-
-}
-
-void debug_cod_list(struct codomain *cod)
-{
-	if (cod->ns)
-		printf("Ns:\t\t%s\n", cod->ns);
-
-	if (cod->name)
-		printf("Name:\t\t%s\n", cod->name);
-	else
-		printf("Name:\t\tNULL\n");
-
-	if (cod->local)
-		printf("Local To:\t%s\n", cod->parent->name);
-
-	debug_flags(cod);
-	
-	debug_capabilities(cod);
-
-	debug_network(cod);
-
-	if (cod->entries)
-		debug_cod_entries(cod->entries);
-
-	printf("\n");
-	dump_policy_hats(cod);
-}
 
 struct value_list *new_value_list(char *value)
 {
@@ -1167,6 +1102,9 @@ void print_cond_entry(struct cond_entry *ent)
 }
 
 #ifdef UNIT_TEST
+
+#include "unit_test.h"
+
 int test_str_to_boolean(void)
 {
 	int rc = 0;
diff --git a/parser/parser_policy.c b/parser/parser_policy.c
index 76a65c8..93c239c 100644
--- a/parser/parser_policy.c
+++ b/parser/parser_policy.c
@@ -19,6 +19,8 @@
  *   Ltd.
  */
 
+#include <algorithm>
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdarg.h>
@@ -29,6 +31,7 @@
 #define _(s) gettext(s)
 
 #include "parser.h"
+#include "profile.h"
 #include "mount.h"
 #include "parser_yacc.h"
 
@@ -40,70 +43,40 @@
 #endif
 #define NPDEBUG(fmt, args...)	/* Do nothing */
 
-void *policy_list = NULL;
 
-static int codomain_compare(const void *a, const void *b)
-{
-	struct codomain *A = (struct codomain *) a;
-	struct codomain *B = (struct codomain *) b;
+ProfileList policy_list;
 
-	int res = 0;
-	if (A->ns) {
-		if (B->ns)
-			res = strcmp(A->ns, B->ns);
-		else
-			res = -1;
-	} else if (B->ns)
-		res = 1;
-	if (res)
-		return res;
-	return strcmp(A->name, B->name);
-}
 
-void add_to_list(struct codomain *codomain)
+void add_to_list(Profile *prof)
 {
-	struct codomain **result;
-
-	result = (struct codomain **) tsearch(codomain, &policy_list, codomain_compare);
-	if (!result) {
-		PERROR("Memory allocation error\n");
-		exit(1);
-	}
-
-	if (*result != codomain) {
+	pair<ProfileList::iterator, bool> res = policy_list.insert(prof);
+	if (!res.second) {
 		PERROR("Multiple definitions for profile %s exist,"
-		       "bailing out.\n", codomain->name);
+		       "bailing out.\n", prof->name);
 		exit(1);
 	}
 }
 
-void add_hat_to_policy(struct codomain *cod, struct codomain *hat)
+void add_hat_to_policy(Profile *prof, Profile *hat)
 {
-	struct codomain **result;
-
-	hat->parent = cod;
+	hat->parent = prof;
 
-	result = (struct codomain **) tsearch(hat, &(cod->hat_table), codomain_compare);
-	if (!result) {
-		PERROR("Memory allocation error\n");
-		exit(1);
-	}
-
-	if (*result != hat) {
+	pair<ProfileList::iterator, bool> res = prof->hat_table.insert(hat);
+	if (!res.second) {
 		PERROR("Multiple definitions for hat %s in profile %s exist,"
-		       "bailing out.\n", hat->name, cod->name);
+		       "bailing out.\n", hat->name, prof->name);
 		exit(1);
 	}
 }
 
-static int add_entry_to_x_table(struct codomain *cod, char *name)
+static int add_entry_to_x_table(Profile *prof, char *name)
 {
 	int i;
 	for (i = (AA_EXEC_LOCAL >> 10) + 1; i < AA_EXEC_COUNT; i++) {
-		if (!cod->exec_table[i]) {
-			cod->exec_table[i] = name;
+		if (!prof->exec_table[i]) {
+			prof->exec_table[i] = name;
 			return i;
-		} else if (strcmp(cod->exec_table[i], name) == 0) {
+		} else if (strcmp(prof->exec_table[i], name) == 0) {
 			/* name already in table */
 			free(name);
 			return i;
@@ -113,7 +86,7 @@ static int add_entry_to_x_table(struct codomain *cod, char *name)
 	return 0;
 }
 
-static int add_named_transition(struct codomain *cod, struct cod_entry *entry)
+static int add_named_transition(Profile *prof, struct cod_entry *entry)
 {
 	char *name = NULL;
 
@@ -122,7 +95,7 @@ static int add_named_transition(struct codomain *cod, struct cod_entry *entry)
 		char *sub = strstr(entry->nt_name, "//");
 		/* does the subprofile name match the rule */
 
-		if (sub && strncmp(cod->name, sub, sub - entry->nt_name) &&
+		if (sub && strncmp(prof->name, sub, sub - entry->nt_name) &&
 		    strcmp(sub + 2, entry->name) == 0) {
 			free(entry->nt_name);
 			entry->nt_name = NULL;
@@ -137,13 +110,13 @@ static int add_named_transition(struct codomain *cod, struct cod_entry *entry)
 				return AA_EXEC_LOCAL >> 10;
 			}
 			/* specified as cix so profile name is implicit */
-			name = (char *) malloc(strlen(cod->name) + strlen(entry->nt_name)
+			name = (char *) malloc(strlen(prof->name) + strlen(entry->nt_name)
 				      + 3);
 			if (!name) {
 				PERROR("Memory allocation error\n");
 				exit(1);
 			}
-			sprintf(name, "%s//%s", cod->name, entry->nt_name);
+			sprintf(name, "%s//%s", prof->name, entry->nt_name);
 			free(entry->nt_name);
 			entry->nt_name = name;
 		}
@@ -163,26 +136,26 @@ static int add_named_transition(struct codomain *cod, struct cod_entry *entry)
 		name = entry->nt_name;
 	}
 
-	return add_entry_to_x_table(cod, name);
+	return add_entry_to_x_table(prof, name);
 }
 
-void add_entry_to_policy(struct codomain *cod, struct cod_entry *entry)
+void add_entry_to_policy(Profile *prof, struct cod_entry *entry)
 {
-	entry->next = cod->entries;
-	cod->entries = entry;
+	entry->next = prof->entries;
+	prof->entries = entry;
 }
 
-void post_process_file_entries(struct codomain *cod)
+void post_process_file_entries(Profile *prof)
 {
 	struct cod_entry *entry;
 	int cp_mode = 0;
 
-	list_for_each(cod->entries, entry) {
+	list_for_each(prof->entries, entry) {
 		if (entry->nt_name) {
 			int mode = 0;
-			int n = add_named_transition(cod, entry);
+			int n = add_named_transition(prof, entry);
 			if (!n) {
-				PERROR("Profile %s has too many specified profile transitions.\n", cod->name);
+				PERROR("Profile %s has too many specified profile transitions.\n", prof->name);
 				exit(1);
 			}
 			if (entry->mode & AA_USER_EXEC)
@@ -214,20 +187,20 @@ void post_process_file_entries(struct codomain *cod)
 			PERROR("Memory allocation error\n");
 			exit(1);
 		}
-		add_entry_to_policy(cod, new_ent);
+		add_entry_to_policy(prof, new_ent);
 	}
 }
 
-void post_process_mnt_entries(struct codomain *cod)
+void post_process_mnt_entries(Profile *prof)
 {
 	struct mnt_entry *entry;
 
-	list_for_each(cod->mnt_ents, entry) {
+	list_for_each(prof->mnt_ents, entry) {
 		if (entry->trans) {
 			unsigned int mode = 0;
-			int n = add_entry_to_x_table(cod, entry->trans);
+			int n = add_entry_to_x_table(prof, entry->trans);
 			if (!n) {
-				PERROR("Profile %s has too many specified profile transitions.\n", cod->name);
+				PERROR("Profile %s has too many specified profile transitions.\n", prof->name);
 				exit(1);
 			}
 
@@ -244,335 +217,90 @@ void post_process_mnt_entries(struct codomain *cod)
 }
 
 
-static void __merge_rules(const void *nodep, const VISIT value,
-			  const int __unused depth)
-{
-	struct codomain **t = (struct codomain **) nodep;
-
-	if (value == preorder || value == endorder)
-		return;
-
-	if (!codomain_merge_rules(*t)) {
-		PERROR(_("ERROR merging rules for profile %s, failed to load\n"),
-		       (*t)->name);
-		exit(1);
-	}
-}
-
-int post_merge_rules(void)
-{
-	twalk(policy_list, __merge_rules);
-	return 0;
-}
-
-int merge_hat_rules(struct codomain *cod)
-{
-	twalk(cod->hat_table, __merge_rules);
-	return 0;
-}
-
-static void __process_regex(const void *nodep, const VISIT value,
-			    const int __unused depth)
-{
-	struct codomain **t = (struct codomain **) nodep;
-
-	if (value == preorder || value == endorder)
-		return;
-
-	if (process_regex(*t) != 0) {
-		PERROR(_("ERROR processing regexs for profile %s, failed to load\n"),
-		       (*t)->name);
-		exit(1);
-	}
-}
-
-int post_process_regex(void)
-{
-	twalk(policy_list, __process_regex);
-	return 0;
-}
-
-int process_hat_regex(struct codomain *cod)
-{
-	twalk(cod->hat_table, __process_regex);
-	return 0;
-}
-
-static void __process_policydb(const void *nodep, const VISIT value,
-			       const int __unused depth)
-{
-	struct codomain **t = (struct codomain **) nodep;
-
-	if (value == preorder || value == endorder)
-		return;
-
-	if (process_policydb(*t) != 0) {
-		PERROR(_("ERROR processing policydb rules for profile %s, failed to load\n"),
-		       (*t)->name);
-		exit(1);
-	}
-}
-
-int post_process_policydb(void)
-{
-	twalk(policy_list, __process_policydb);
-	return 0;
-}
-
-int process_hat_policydb(struct codomain *cod)
-{
-	twalk(cod->hat_table, __process_policydb);
-	return 0;
-}
-
-static void __process_variables(const void *nodep, const VISIT value,
-				const int __unused depth)
-{
-	struct codomain **t = (struct codomain **) nodep;
-
-	if (value == preorder || value == endorder)
-		return;
-
-	if (process_variables(*t) != 0) {
-		PERROR(_("ERROR expanding variables for profile %s, failed to load\n"),
-		       (*t)->name);
-		exit(1);
-	}
-}
-
-int post_process_variables(void)
-{
-	twalk(policy_list, __process_variables);
-	return 0;
-}
-
-int process_hat_variables(struct codomain *cod)
-{
-	twalk(cod->hat_table, __process_variables);
-	return 0;
-}
-
-
-static void __process_alias(const void *nodep, const VISIT value,
-			    const int __unused depth)
-{
-	struct codomain **t = (struct codomain **) nodep;
-
-	if (value == preorder || value == endorder)
-		return;
-
-	replace_aliases((*t));
-
-	if ((*t)->hat_table)
-		twalk((*t)->hat_table, __process_alias);
-}
-
-int post_process_alias(void)
-{
-	twalk(policy_list, __process_alias);
-	return 0;
-}
-
 #define CHANGEHAT_PATH "/proc/[0-9]*/attr/current"
 
 /* add file rules to access /proc files to call change_hat()
  */
-static void __add_hat_rules_parent(const void *nodep, const VISIT value,
-				   const int __unused depth)
+static int profile_add_hat_rules(Profile *prof)
 {
-	struct codomain **t = (struct codomain **) nodep;
 	struct cod_entry *entry;
 
-	if (value == preorder || value == endorder)
-		return;
-
-	/* don't add hat rules if a parent profile with no hats */
-	if (!(*t)->hat_table && !(*t)->parent)
-		return;
-
-	/* don't add hat rules for local_profiles */
-	if ((*t)->local)
-		return;
+	/* TODO: ??? fix logic for when to add to hat/base vs. local */
+	/* don't add hat rules for local_profiles or base profiles */
+	if (prof->local || prof->hat_table.empty())
+		return 0;
 
+	/* add entry to hat */
 	entry = new_entry(NULL, strdup(CHANGEHAT_PATH), AA_MAY_WRITE, NULL);
-	if (!entry) {
-		PERROR(_("ERROR adding hat access rule for profile %s\n"),
-		       (*t)->name);
-		exit(1);
-	}
-	add_entry_to_policy(*t, entry);
+	if (!entry)
+		return ENOMEM;
 
-	twalk((*t)->hat_table, __add_hat_rules_parent);
-}
-
-static int add_hat_rules(void)
-{
-	twalk(policy_list, __add_hat_rules_parent);
+	add_entry_to_policy(prof, entry);
 
 	return 0;
 }
 
-/* Yuck, is their no other way to pass arguments to a twalk action */
-static int __load_option;
-static int __load_error;
-
-static void __load_policy(const void *nodep, const VISIT value,
-			  const int __unused depth)
+int load_policy_list(ProfileList &list, int option)
 {
-	struct codomain **t = (struct codomain **) nodep;
-
-	if (value == preorder || value == endorder || __load_error)
-		return;
+	int res = 0;
 
-	if (load_codomain(__load_option, *t) != 0) {
-		__load_error = -EINVAL;
+	for (ProfileList::iterator i = list.begin(); i != list.end(); i++) {
+		res = load_profile(option, *i);
+		if (!res)
+			break;
 	}
-}
 
-int load_policy(int option)
-{
-	__load_option = option;
-        __load_error = 0;
-	twalk(policy_list, __load_policy);
-	return __load_error;
+	return res;
 }
 
-/* Yuck, is their no other way to pass arguments to a twalk action */
-static sd_serialize *__p;
-
-static int __load_hat_error;
-static void __load_hat(const void *nodep, const VISIT value,
-		       const int __unused depth)
+int load_flattened_hats(Profile *prof, int option)
 {
-	struct codomain **t = (struct codomain **) nodep;
-
-	if (value == preorder || value == endorder || __load_hat_error)
-		return;
-
-	if (!sd_serialize_profile(__p, *t, 0)) {
-		PERROR(_("ERROR in profile %s, failed to load\n"),
-		       (*t)->name);
-		__load_hat_error = -EINVAL;
-	}
+	return load_policy_list(prof->hat_table, option);
 }
 
-static int __load_flattened_hat_error;
-static void __load_flattened_hat(const void *nodep, const VISIT value,
-				 const int __unused depth)
+int load_policy(int option)
 {
-	struct codomain **t = (struct codomain **) nodep;
-
-	if (value == preorder || value == endorder || __load_flattened_hat_error)
-		return;
-
-	if (load_codomain(__load_option, *t) != 0) {
-		__load_flattened_hat_error = -EINVAL;
-	}
+	return load_policy_list(policy_list, option);
 }
 
-int load_flattened_hats(struct codomain *cod)
+int load_hats(sd_serialize *p, Profile *prof)
 {
-	__load_flattened_hat_error = 0;
-	twalk(cod->hat_table, __load_flattened_hat);
-	return __load_flattened_hat_error;
-}
+	for (ProfileList::iterator i = prof->hat_table.begin(); i != prof->hat_table.end(); i++) {
+		if (!sd_serialize_profile(p, *i, 0)) {
+			PERROR(_("ERROR in profile %s, failed to load\n"),
+			       (*i)->name);
+			return -EINVAL;
+		}
+	}
 
-int load_hats(sd_serialize *p, struct codomain *cod)
-{
-	__p = p;
-	__load_hat_error = 0;
-	twalk(cod->hat_table, __load_hat);
-	return __load_hat_error;
+	return 0;
 }
 
-static void __dump_policy(const void *nodep, const VISIT value,
-			  const int __unused depth)
-{
-	struct codomain **t = (struct codomain **) nodep;
-
-	if (value == preorder || value == endorder)
-		return;
-
-	debug_cod_list(*t);
-}
 
 void dump_policy(void)
 {
-	twalk(policy_list, __dump_policy);
-}
-
-void dump_policy_hats(struct codomain *cod)
-{
-	twalk(cod->hat_table, __dump_policy);
-}
-
-/* Gar */
-static struct codomain *__dump_policy_name;
-
-static void __dump_policy_hatnames(const void *nodep, const VISIT value,
-				const int __unused depth)
-{
-	struct codomain **t = (struct codomain **) nodep;
-
-	if (value == preorder || value == endorder)
-		return;
-
-	printf("%s//%s\n", __dump_policy_name->name, (*t)->name);
-}
-
-void dump_policy_hatnames(struct codomain *cod)
-{
-	__dump_policy_name = cod;
-	twalk(cod->hat_table, __dump_policy_hatnames);
-}
-
-static void __dump_policy_names(const void *nodep, const VISIT value,
-				const int __unused depth)
-{
-	struct codomain **t = (struct codomain **) nodep;
-
-	if (value == preorder || value == endorder)
-		return;
-
-	printf("%s\n", (*t)->name);
-	dump_policy_hatnames(*t);
+	policy_list.dump();
 }
 
 void dump_policy_names(void)
 {
-	twalk(policy_list, __dump_policy_names);
-}
-
-/* gar, more global arguments */
-struct codomain *__hat_merge_policy;
-
-static void __merge_hat(const void *nodep, const VISIT value,
-			const int __unused depth)
-{
-	struct codomain **t = (struct codomain **) nodep;
-
-        if (value == preorder || value == endorder)
-		return;
-	add_hat_to_policy(__hat_merge_policy, (*t));
+	policy_list.dump_profile_names(true);
 }
 
-/* merge_hats: merges hat_table into hat_table owned by cod */
-static void merge_hats(struct codomain *cod, void *hats)
+/* merge_hats: merges hat_table into hat_table owned by prof */
+static void merge_hats(Profile *prof, ProfileList &hats)
 {
-	__hat_merge_policy = cod;
-	twalk(hats, __merge_hat);
-}
+	for (ProfileList::iterator i = hats.begin(); i != hats.end(); ) {
+		ProfileList::iterator cur = i++;
+		add_hat_to_policy(prof, *cur);
+		hats.erase(cur);
+	}
 
-/* don't want to free the hat entries in the table, as they were pushed
- * onto the other table. */
-static void empty_destroy(void __unused *nodep)
-{
-	return;
 }
 
-struct codomain *merge_policy(struct codomain *a, struct codomain *b)
+Profile *merge_policy(Profile *a, Profile *b)
 {
-	struct codomain *ret = a;
+	Profile *ret = a;
 	struct cod_entry *last;
 
 	if (!a) {
@@ -600,130 +328,112 @@ struct codomain *merge_policy(struct codomain *a, struct codomain *b)
 	a->flags.complain = a->flags.complain || b->flags.complain;
 	a->flags.audit = a->flags.audit || b->flags.audit;
 
-	a->capabilities |= b->capabilities;
-	a->audit_caps |= b->audit_caps;
-	a->deny_caps |= b->deny_caps;
-	a->quiet_caps |= b->quiet_caps;
+	a->caps.allow |= b->caps.allow;
+	a->caps.audit |= b->caps.audit;
+	a->caps.deny |= b->caps.deny;
+	a->caps.quiet |= b->caps.quiet;
 
-	if (a->network_allowed) {
+	if (a->net.allow) {
 		size_t i;
 		for (i = 0; i < get_af_max(); i++) {
-			a->network_allowed[i] |= b->network_allowed[i];
-			a->audit_network[i] |= b->audit_network[i];
-			a->deny_network[i] |= b->deny_network[i];
-			a->quiet_network[i] |= b->quiet_network[i];
+			a->net.allow[i] |= b->net.allow[i];
+			a->net.audit[i] |= b->net.audit[i];
+			a->net.deny[i] |= b->net.deny[i];
+			a->net.quiet[i] |= b->net.quiet[i];
 		}
 	}
 
 	merge_hats(a, b->hat_table);
-	tdestroy(b->hat_table, &empty_destroy);
-	b->hat_table = NULL;
 
-	free_policy(b);
+	delete b;
 out:
 	return ret;
 }
 
-int post_process_policy(int debug_only)
+
+int process_profile_rules(Profile *profile)
 {
-	int retval = 0;
+	int error;
+
+	error = process_profile_regex(profile);
+	if (error) {
+		PERROR(_("ERROR processing regexs for profile %s, failed to load\n"), profile->name);
+		exit(1);
+		return error;
+	}
 
-	retval = add_hat_rules();
-	if (retval != 0) {
-		PERROR(_("%s: Errors found during postprocessing.  Aborting.\n"),
-		       progname);
-		return retval;
+	error = process_profile_policydb(profile);
+	if (error) {
+		PERROR(_("ERROR processing policydb rules for profile %s, failed to load\n"),
+		       (profile)->name);
+		exit(1);
+		return error;
 	}
 
-	retval = post_process_variables();
-	if (retval != 0) {
-		PERROR(_("%s: Errors found during regex postprocess.  Aborting.\n"),
-		       progname);
-		return retval;
+	return 0;
+}
+
+int post_process_policy_list(ProfileList &list, int debug_only);
+int post_process_profile(Profile *profile, int debug_only)
+{
+	int error = 0;
+
+	error = profile_add_hat_rules(profile);
+	if (error) {
+		PERROR(_("ERROR adding hat access rule for profile %s\n"),
+		       profile->name);
+		return error;
 	}
 
-	retval = post_process_alias();
-	if (retval != 0) {
-		PERROR(_("%s: Errors found during postprocess.  Aborting.\n"),
-		       progname);
-		return retval;
+	error = process_profile_variables(profile);
+	if (error) {
+		PERROR(_("ERROR expanding variables for profile %s, failed to load\n"), profile->name);
+		exit(1);
+		return error;
 	}
 
-	retval = post_merge_rules();
-	if (retval != 0) {
-		PERROR(_("%s: Errors found in combining rules postprocessing. Aborting.\n"),
-		       progname);
-		return retval;
+	error = replace_profile_aliases(profile);
+	if (error) {
+		PERROR(_("ERROR replacing aliases for profile %s, failed to load\n"), profile->name);
+		return error;
 	}
 
-	if (!debug_only) {
-		retval = post_process_regex();
-		if (retval != 0) {
-			PERROR(_("%s: Errors found during regex postprocess.  Aborting.\n"),
-			       progname);
-			return retval;
-		}
+	error = profile_merge_rules(profile);
+	if (error) {
+		PERROR(_("ERROR merging rules for profile %s, failed to load\n"), profile->name);
+		exit(1);
+		return error;
 	}
 
 	if (!debug_only) {
-		retval = post_process_policydb();
-		if (retval != 0) {
-			PERROR(_("%s: Errors found during policydb postprocess.  Aborting.\n"),
-			       progname);
-			return retval;
-		}
+		error = process_profile_rules(profile);
+		if (error)
+			return error;
 	}
 
-	return retval;
-}
+	error = post_process_policy_list(profile->hat_table, debug_only);
 
-void free_hat_entry(void *nodep)
-{
-	struct codomain *t = (struct codomain *)nodep;
-	free_policy(t);
+	return error;
 }
 
-void free_hat_table(void *hat_table)
+int post_process_policy_list(ProfileList &list, int debug_only)
 {
-	if (hat_table)
-		tdestroy(hat_table, &free_hat_entry);
+	int error = 0;
+	for (ProfileList::iterator i = list.begin(); i != list.end(); i++) {
+		error = post_process_profile(*i, debug_only);
+		if (error)
+			break;
+	}
+
+	return error;
 }
 
-void free_policy(struct codomain *cod)
+int post_process_policy(int debug_only)
 {
-	if (!cod)
-		return;
-	free_hat_table(cod->hat_table);
-	free_cod_entries(cod->entries);
-	free_mnt_entries(cod->mnt_ents);
-	if (cod->dfarules)
-		aare_delete_ruleset(cod->dfarules);
-	if (cod->dfa)
-		free(cod->dfa);
-	if (cod->policy_rules)
-		aare_delete_ruleset(cod->policy_rules);
-	if (cod->policy_dfa)
-		free(cod->policy_dfa);
-	if (cod->name)
-		free(cod->name);
-	if (cod->attachment)
-		free(cod->attachment);
-	if (cod->ns)
-		free(cod->ns);
-	if (cod->network_allowed)
-		free(cod->network_allowed);
-	if (cod->audit_network)
-		free(cod->audit_network);
-	if (cod->deny_network)
-		free(cod->deny_network);
-	if (cod->quiet_network)
-		free(cod->quiet_network);
-	free(cod);
+	return post_process_policy_list(policy_list, debug_only);
 }
 
 void free_policies(void)
 {
-	if (policy_list)
-		tdestroy(policy_list, (__free_fn_t)&free_policy);
-	policy_list = NULL;
+	policy_list.clear();
 }
diff --git a/parser/parser_regex.c b/parser/parser_regex.c
index ce9d7a3..d65aa81 100644
--- a/parser/parser_regex.c
+++ b/parser/parser_regex.c
@@ -26,6 +26,7 @@
 /* #define DEBUG */
 
 #include "parser.h"
+#include "profile.h"
 #include "libapparmor_re/apparmor_re.h"
 #include "libapparmor_re/aare_rules.h"
 #include "mount.h"
@@ -383,30 +384,30 @@ static const char *local_name(const char *name)
 	return name;
 }
 
-static int process_profile_name_xmatch(struct codomain *cod)
+static int process_profile_name_xmatch(Profile *prof)
 {
 	char tbuf[PATH_MAX + 3];	/* +3 for ^, $ and \0 */
 	pattern_t ptype;
 	const char *name;
 
 	/* don't filter_slashes for profile names */
-	if (cod->attachment)
-		name = cod->attachment;
+	if (prof->attachment)
+		name = prof->attachment;
 	else
-		name = local_name(cod->name);
+		name = local_name(prof->name);
 	ptype = convert_aaregex_to_pcre(name, 0, tbuf, PATH_MAX + 3,
-					&cod->xmatch_len);
+					&prof->xmatch_len);
 	if (ptype == ePatternBasic)
-		cod->xmatch_len = strlen(name);
+		prof->xmatch_len = strlen(name);
 
 	if (ptype == ePatternInvalid) {
 		PERROR(_("%s: Invalid profile name '%s' - bad regular expression\n"), progname, name);
 		return FALSE;
-	} else if (ptype == ePatternBasic && !(cod->altnames || cod->attachment)) {
+	} else if (ptype == ePatternBasic && !(prof->altnames || prof->attachment)) {
 		/* no regex so do not set xmatch */
-		cod->xmatch = NULL;
-		cod->xmatch_len = 0;
-		cod->xmatch_size = 0;
+		prof->xmatch = NULL;
+		prof->xmatch_len = 0;
+		prof->xmatch_size = 0;
 	} else {
 		/* build a dfa */
 		aare_ruleset_t *rule = aare_new_ruleset(0);
@@ -416,9 +417,9 @@ static int process_profile_name_xmatch(struct codomain *cod)
 			aare_delete_ruleset(rule);
 			return FALSE;
 		}
-		if (cod->altnames) {
+		if (prof->altnames) {
 			struct alt_name *alt;
-			list_for_each(cod->altnames, alt) {
+			list_for_each(prof->altnames, alt) {
 				int len;
 				ptype = convert_aaregex_to_pcre(alt->name, 0,
 								tbuf,
@@ -426,18 +427,18 @@ static int process_profile_name_xmatch(struct codomain *cod)
 								&len);
 				if (ptype == ePatternBasic)
 					len = strlen(alt->name);
-				if (len < cod->xmatch_len)
-					cod->xmatch_len = len;
+				if (len < prof->xmatch_len)
+					prof->xmatch_len = len;
 				if (!aare_add_rule(rule, tbuf, 0, AA_MAY_EXEC, 0, dfaflags)) {
 					aare_delete_ruleset(rule);
 					return FALSE;
 				}
 			}
 		}
-		cod->xmatch = aare_create_dfa(rule, &cod->xmatch_size,
+		prof->xmatch = aare_create_dfa(rule, &prof->xmatch_size,
 					      dfaflags);
 		aare_delete_ruleset(rule);
-		if (!cod->xmatch)
+		if (!prof->xmatch)
 			return FALSE;
 	}
 
@@ -549,70 +550,54 @@ static int process_dfa_entry(aare_ruleset_t *dfarules, struct cod_entry *entry)
 	return TRUE;
 }
 
-int post_process_entries(struct codomain *cod)
+int post_process_entries(Profile *prof)
 {
 	int ret = TRUE;
 	struct cod_entry *entry;
 	int count = 0;
 
-	list_for_each(cod->entries, entry) {
-		if (!process_dfa_entry(cod->dfarules, entry))
+	list_for_each(prof->entries, entry) {
+		if (!process_dfa_entry(prof->dfa.rules, entry))
 			ret = FALSE;
 		count++;
 	}
 
-	cod->dfarule_count = count;
+	prof->dfa.count = count;
 	return ret;
 }
 
-int process_regex(struct codomain *cod)
+int process_profile_regex(Profile *prof)
 {
 	int error = -1;
 
-	if (!process_profile_name_xmatch(cod))
+	if (!process_profile_name_xmatch(prof))
 		goto out;
 
-	cod->dfarules = aare_new_ruleset(0);
-	if (!cod->dfarules)
+	prof->dfa.rules = aare_new_ruleset(0);
+	if (!prof->dfa.rules)
 		goto out;
 
-	if (!post_process_entries(cod))
+	if (!post_process_entries(prof))
 		goto out;
 
-	if (cod->dfarule_count > 0) {
-		cod->dfa = aare_create_dfa(cod->dfarules, &cod->dfa_size,
-					   dfaflags);
-		aare_delete_ruleset(cod->dfarules);
-		cod->dfarules = NULL;
- 		if (!cod->dfa)
+	if (prof->dfa.count > 0) {
+		prof->dfa.dfa = aare_create_dfa(prof->dfa.rules, &prof->dfa.size,
+						dfaflags);
+		aare_delete_ruleset(prof->dfa.rules);
+		prof->dfa.rules = NULL;
+ 		if (!prof->dfa.dfa)
 			goto out;
 /*
-		if (cod->dfa_size == 0) {
+		if (prof->dfa_size == 0) {
 			PERROR(_("profile %s: has merged rules (%s) with "
 				 "multiple x modifiers\n"),
-			       cod->name, (char *) cod->dfa);
-			free(cod->dfa);
-			cod->dfa = NULL;
+			       prof->name, (char *) prof->dfa);
+			free(prof->dfa);
+			prof->dfa = NULL;
 			goto out;
 		}
 */
 	}
-	/*
-	 * Post process subdomain(s):
-	 *
-	 * They are chained from the toplevel subdomain pointer
-	 * thru each <codomain> next pointer.
-
-	 * i.e first subdomain is list->subdomain
-	 *    second subdomain is list->subdomain->next
-	 *
-	 * N.B sub-subdomains are not valid so:
-	 * if (list->subdomain) {
-	 *    assert(list->subdomain->subdomain == NULL)
-	 * }
-	 */
-	if (process_hat_regex(cod) != 0)
-		goto out;
 
 	error = 0;
 
@@ -1039,59 +1024,57 @@ fail:
 }
 
 
-int post_process_mnt_ents(struct codomain *cod)
+int post_process_mnt_ents(Profile *prof)
 {
 	int ret = TRUE;
 	int count = 0;
 
 	/* Add fns for rules that should be added to policydb here */
-	if (cod->mnt_ents && kernel_supports_mount) {
+	if (prof->mnt_ents && kernel_supports_mount) {
 		struct mnt_entry *entry;
-		list_for_each(cod->mnt_ents, entry) {
-			if (!process_mnt_entry(cod->policy_rules, entry))
+		list_for_each(prof->mnt_ents, entry) {
+			if (!process_mnt_entry(prof->policy.rules, entry))
 				ret = FALSE;
 			count++;
 		}
-	} else if (cod->mnt_ents && !kernel_supports_mount)
-		pwarn("profile %s mount rules not enforced\n", cod->name);
+	} else if (prof->mnt_ents && !kernel_supports_mount)
+		pwarn("profile %s mount rules not enforced\n", prof->name);
 
-	cod->policy_rule_count += count;
+	prof->policy.count += count;
 
 	return ret;
 }
 
-int post_process_policydb_ents(struct codomain *cod)
+int post_process_policydb_ents(Profile *prof)
 {
-	if (!post_process_mnt_ents(cod))
+	if (!post_process_mnt_ents(prof))
 		return FALSE;
 
 	return TRUE;
 }
 
-int process_policydb(struct codomain *cod)
+int process_profile_policydb(Profile *prof)
 {
 	int error = -1;
 
-	cod->policy_rules = aare_new_ruleset(0);
-	if (!cod->policy_rules)
+	prof->policy.rules = aare_new_ruleset(0);
+	if (!prof->policy.rules)
 		goto out;
 
-	if (!post_process_policydb_ents(cod))
+	if (!post_process_policydb_ents(prof))
 		goto out;
 
-	if (cod->policy_rule_count > 0) {
-		cod->policy_dfa = aare_create_dfa(cod->policy_rules,
-						  &cod->policy_dfa_size,
+	if (prof->policy.count > 0) {
+		prof->policy.dfa = aare_create_dfa(prof->policy.rules,
+						  &prof->policy.size,
 						  dfaflags);
-		aare_delete_ruleset(cod->policy_rules);
-		cod->policy_rules = NULL;
-		if (!cod->policy_dfa)
+		aare_delete_ruleset(prof->policy.rules);
+		prof->policy.rules = NULL;
+		if (!prof->policy.dfa)
 			goto out;
 	}
 
 	aare_reset_matchflags();
-	if (process_hat_policydb(cod) != 0)
-		goto out;
 
 	error = 0;
 
@@ -1105,6 +1088,9 @@ void reset_regex(void)
 }
 
 #ifdef UNIT_TEST
+
+#include "unit_test.h"
+
 static int test_filter_slashes(void)
 {
 	int rc = 0;
diff --git a/parser/parser_symtab.c b/parser/parser_symtab.c
index 322551e..f10a264 100644
--- a/parser/parser_symtab.c
+++ b/parser/parser_symtab.c
@@ -539,6 +539,9 @@ void free_symtabs(void)
 }
 
 #ifdef UNIT_TEST
+
+#include "unit_test.h"
+
 int main(void)
 {
 	int rc = 0;
diff --git a/parser/parser_variable.c b/parser/parser_variable.c
index c17123a..460afbb 100644
--- a/parser/parser_variable.c
+++ b/parser/parser_variable.c
@@ -28,6 +28,7 @@
 /* #define DEBUG */
 
 #include "parser.h"
+#include "profile.h"
 #include "mount.h"
 
 static inline char *get_var_end(char *var)
@@ -136,12 +137,11 @@ static int expand_entry_variables(char **name, void *entry,
 				  int (dup_and_chain)(void *))
 {
 	struct set_value *valuelist;
-	int ret = TRUE;
 	char *value;
 	struct var_string *split_var;
 
 	if (!entry) 		/* can happen when entry is optional */
-		return ret;
+		return 0;
 
 	while ((split_var = split_out_var(*name))) {
 		valuelist = get_set_var(split_var->var);
@@ -167,7 +167,7 @@ static int expand_entry_variables(char **name, void *entry,
 			     split_var->prefix ? split_var->prefix : "",
 			     value,
 			     split_var->suffix ? split_var->suffix : "") == -1)
-			return FALSE;
+			return -1;
 
 		while ((value = get_next_set_value(&valuelist))) {
 			if (!dup_and_chain(entry)) {
@@ -180,12 +180,12 @@ static int expand_entry_variables(char **name, void *entry,
 			if (asprintf(name, "%s%s%s",
 			      split_var->prefix ? split_var->prefix : "", value,
 			      split_var->suffix ? split_var->suffix : "") == -1)
-				return FALSE;
+				return -1;
 		}
 
 		free_var_string(split_var);
 	}
-	return ret;
+	return 0;
 }
 
 int clone_and_chain_cod(void *v)
@@ -215,63 +215,60 @@ int clone_and_chain_mnt(void *v)
 
 static int process_variables_in_entries(struct cod_entry *entry_list)
 {
-	int ret = TRUE, rc;
+	int error = 0;
 	struct cod_entry *entry;
 
 	list_for_each(entry_list, entry) {
-		rc = expand_entry_variables(&entry->name, entry,
-					    clone_and_chain_cod);
-		if (!rc)
-			return FALSE;
+		error = expand_entry_variables(&entry->name, entry,
+					       clone_and_chain_cod);
+		if (error)
+			return error;
 	}
 
-	return ret;
+	return 0;
 }
 
 /* does not currently support expansion of vars in options */
 static int process_variables_in_mnt_entries(struct mnt_entry *entry_list)
 {
-	int ret = TRUE, rc;
+	int error = 0;
 	struct mnt_entry *entry;
 
 	list_for_each(entry_list, entry) {
-		rc = expand_entry_variables(&entry->mnt_point, entry,
-					    clone_and_chain_mnt);
-		if (!rc)
-			return FALSE;
-		rc = expand_entry_variables(&entry->device, entry,
-					    clone_and_chain_mnt);
-		if (!rc)
-			return FALSE;
-		rc = expand_entry_variables(&entry->trans, entry,
-					    clone_and_chain_mnt);
-		if (!rc)
-			return FALSE;
+		error = expand_entry_variables(&entry->mnt_point, entry,
+					       clone_and_chain_mnt);
+		if (error)
+			return error;
+		error = expand_entry_variables(&entry->device, entry,
+					       clone_and_chain_mnt);
+		if (error)
+			return error;
+		error = expand_entry_variables(&entry->trans, entry,
+					       clone_and_chain_mnt);
+		if (error)
+			return error;
 
 	}
 
-	return ret;
+	return 0;
 }
 
-int process_variables(struct codomain *cod)
+int process_profile_variables(Profile *prof)
 {
 	int error = 0;
 
-	if (!process_variables_in_entries(cod->entries)) {
-		error = -1;
-	}
+	error = process_variables_in_entries(prof->entries);
 
-	if (!process_variables_in_mnt_entries(cod->mnt_ents)) {
-		error = -1;
-	}
+	if (!error)
+		error = process_variables_in_mnt_entries(prof->mnt_ents);
 
-	if (process_hat_variables(cod) != 0) {
-			error = -1;
-	}
 	return error;
 }
 
 #ifdef UNIT_TEST
+
+#include "unit_test.h"
+
 int test_get_var_end(void)
 {
 	int rc = 0;
diff --git a/parser/parser_yacc.y b/parser/parser_yacc.y
index 4939d4f..8d4fb37 100644
--- a/parser/parser_yacc.y
+++ b/parser/parser_yacc.y
@@ -32,6 +32,7 @@
 /* #define DEBUG */
 
 #include "parser.h"
+#include "profile.h"
 #include "mount.h"
 #include "parser_include.h"
 #include <unistd.h>
@@ -75,7 +76,7 @@ struct mnt_entry *do_mnt_rule(struct cond_entry *src_conds, char *src,
 struct mnt_entry *do_pivot_rule(struct cond_entry *old, char *root,
 				char *transition);
 
-void add_local_entry(struct codomain *cod);
+void add_local_entry(Profile *prof);
 
 %}
 
@@ -156,12 +157,12 @@ void add_local_entry(struct codomain *cod);
 	char *flag_id;
 	char *mode;
 	struct aa_network_entry *network_entry;
-	struct codomain *cod;
+	Profile *prof;
 	struct cod_net_entry *net_entry;
 	struct cod_entry *user_entry;
 	struct mnt_entry *mnt_entry;
 
-	struct flagval flags;
+	flagvals flags;
 	int fmode;
 	uint64_t cap;
 	unsigned int allowed_protocol;
@@ -179,12 +180,12 @@ void add_local_entry(struct codomain *cod);
 %type <id>	TOK_CONDID
 %type <mode> 	TOK_MODE
 %type <fmode>   file_mode
-%type <cod>	profile_base
-%type <cod> 	profile
-%type <cod>	rules
-%type <cod>	hat
-%type <cod>	local_profile
-%type <cod>	cond_rule
+%type <prof>	profile_base
+%type <prof> 	profile
+%type <prof>	rules
+%type <prof>	hat
+%type <prof>	local_profile
+%type <prof>	cond_rule
 %type <network_entry> network_rule
 %type <user_entry> rule
 %type <user_entry> file_rule
@@ -245,37 +246,37 @@ opt_id: { /* nothing */ $$ = NULL; }
 
 profile_base: TOK_ID opt_id flags TOK_OPEN rules TOK_CLOSE
 	{
-		struct codomain *cod = $5;
+		Profile *prof = $5;
 
-		if (!cod) {
+		if (!prof) {
 			yyerror(_("Memory allocation error."));
 		}
 
-		cod->name = $1;
-		cod->attachment = $2;
+		prof->name = $1;
+		prof->attachment = $2;
 		if ($2 && $2[0] != '/')
 			/* we don't support variables as part of the profile
 			 * name or attachment atm
 			 */
 			yyerror(_("Profile attachment must begin with a '/'."));
-		cod->flags = $3;
+		prof->flags = $3;
 		if (force_complain)
-			cod->flags.complain = 1;
+			prof->flags.complain = 1;
 
-		post_process_file_entries(cod);
-		post_process_mnt_entries(cod);
+		post_process_file_entries(prof);
+		post_process_mnt_entries(prof);
 		PDEBUG("%s: flags='%s%s'\n",
 		       $2,
-		       cod->flags.complain ? "complain, " : "",
-		       cod->flags.audit ? "audit" : "");
+		       prof->flags.complain ? "complain, " : "",
+		       prof->flags.audit ? "audit" : "");
 
-		$$ = cod;
+		$$ = prof;
 
 	};
 
 profile:  opt_profile_flag opt_ns profile_base
 	{
-		struct codomain *cod = $3;
+		Profile *prof = $3;
 		if ($2)
 			PDEBUG("Matched: %s://%s { ... }\n", $2, $3->name);
 		else
@@ -284,31 +285,31 @@ profile:  opt_profile_flag opt_ns profile_base
 		if ($3->name[0] != '/' && !($1 || $2))
 			yyerror(_("Profile names must begin with a '/', namespace or keyword 'profile' or 'hat'."));
 
-		cod->ns = $2;
+		prof->ns = $2;
 		if ($1 == 2)
-			cod->flags.hat = 1;
-		$$ = cod;
+			prof->flags.hat = 1;
+		$$ = prof;
 	};
 
 local_profile:   TOK_PROFILE profile_base
 	{
 
-		struct codomain *cod = $2;
+		Profile *prof = $2;
 
 		if ($2)
-			PDEBUG("Matched: local profile %s { ... }\n", cod->name);
-		cod->local = 1;
-		$$ = cod;
+			PDEBUG("Matched: local profile %s { ... }\n", prof->name);
+		prof->local = 1;
+		$$ = prof;
 	};
 
 hat: hat_start profile_base
 	{
-		struct codomain *cod = $2;
+		Profile *prof = $2;
 		if ($2)
-			PDEBUG("Matched: hat %s { ... }\n", cod->name);
+			PDEBUG("Matched: hat %s { ... }\n", prof->name);
 
-		cod->flags.hat = 1;
-		$$ = cod;
+		prof->flags.hat = 1;
+		$$ = prof;
 	};
 
 preamble: { /* nothing */ }
@@ -414,7 +415,7 @@ valuelist:	valuelist TOK_VALUE
 	}
 
 flags:	{ /* nothing */
-	struct flagval fv = { 0, 0, 0, 0 };
+	struct flagvals fv = { 0, 0, 0, 0 };
 
 		$$ = fv;
 	};
@@ -461,7 +462,7 @@ flagvals:	flagval
 
 flagval:	TOK_VALUE
 	{
-		struct flagval fv = { 0, 0, 0, 0 };
+		struct flagvals fv = { 0, 0, 0, 0 };
 		if (strcmp($1, "debug") == 0) {
 			yyerror(_("Profile flag 'debug' is no longer valid."));
 		} else if (strcmp($1, "complain") == 0) {
@@ -514,13 +515,12 @@ opt_prefix: opt_audit_flag opt_deny opt_owner_flag
 	}
 
 rules:	{ /* nothing */ 
-		struct codomain *cod = NULL;
-		cod = (struct codomain *) calloc(1, sizeof(struct codomain));
-		if (!cod) {
+	Profile *prof = new Profile();
+		if (!prof) {
 			yyerror(_("Memory allocation error."));
 		}
 
-		$$ = cod;
+		$$ = prof;
 	};
 
 rules:  rules opt_prefix rule
@@ -580,8 +580,8 @@ rules: rules opt_prefix TOK_OPEN rules TOK_CLOSE
 			add_entry_to_policy($1, entry);
 		}
 		$4->entries = NULL;
-		// fix me transfer rules and free sub codomain
-		free_policy($4);
+		// fix me transfer rules and free sub profile
+		delete $4;
 		$$ = $1;
 	};
 
@@ -594,40 +594,40 @@ rules: rules opt_prefix network_rule
 			yyerror(_("owner prefix not allowed"));
 		if (!$3)
 			yyerror(_("Assert: `network_rule' return invalid protocol."));
-		if (!$1->network_allowed) {
-		  $1->network_allowed = (unsigned int *) calloc(get_af_max(),
+		if (!$1->net.allow) {
+		  $1->net.allow = (unsigned int *) calloc(get_af_max(),
 						     sizeof(unsigned int));
-			$1->audit_network = (unsigned int *)calloc(get_af_max(),
+			$1->net.audit = (unsigned int *)calloc(get_af_max(),
 						   sizeof(unsigned int));
-			$1->deny_network = (unsigned int *)calloc(get_af_max(),
+			$1->net.deny = (unsigned int *)calloc(get_af_max(),
 						     sizeof(unsigned int));
-			$1->quiet_network = (unsigned int *)calloc(get_af_max(),
+			$1->net.quiet = (unsigned int *)calloc(get_af_max(),
 						     sizeof(unsigned int));
-			if (!$1->network_allowed || !$1->audit_network ||
-			    !$1->deny_network || !$1->quiet_network)
+			if (!$1->net.allow || !$1->net.audit ||
+			    !$1->net.deny || !$1->net.quiet)
 				yyerror(_("Memory allocation error."));
 		}
 		list_for_each_safe($3, entry, tmp) {
 			if (entry->type > SOCK_PACKET) {
 				/* setting mask instead of a bit */
 				if ($2.deny) {
-					$1->deny_network[entry->family] |= entry->type;
+					$1->net.deny[entry->family] |= entry->type;
 					if (!$2.audit)
-						$1->quiet_network[entry->family] |= entry->type;
+						$1->net.quiet[entry->family] |= entry->type;
 				} else {
-					$1->network_allowed[entry->family] |= entry->type;
+					$1->net.allow[entry->family] |= entry->type;
 					if ($2.audit)
-						$1->audit_network[entry->family] |= entry->type;
+						$1->net.audit[entry->family] |= entry->type;
 				}
 			} else {
 				if ($2.deny) {
-					$1->deny_network[entry->family] |= 1 << entry->type;
+					$1->net.deny[entry->family] |= 1 << entry->type;
 					if (!$2.audit)
-						$1->quiet_network[entry->family] |= 1 << entry->type;
+						$1->net.quiet[entry->family] |= 1 << entry->type;
 				} else {
-					$1->network_allowed[entry->family] |= 1 << entry->type;
+					$1->net.allow[entry->family] |= 1 << entry->type;
 					if ($2.audit)
-						$1->audit_network[entry->family] |= 1 << entry->type;
+						$1->net.audit[entry->family] |= 1 << entry->type;
 				}
 			}
 			free(entry);
@@ -665,12 +665,12 @@ rules:	rules opt_prefix capability
 			yyerror(_("owner prefix not allow on mount rules"));
 
 		if ($2.deny)
-			$1->deny_caps |= $3;
+			$1->caps.deny |= $3;
 		else
-			$1->capabilities |= $3;
+			$1->caps.allow |= $3;
 
 		if (!$2.audit)
-			$1->quiet_caps |= $3;
+			$1->caps.quiet |= $3;
 		$$ = $1;
 	};
 
@@ -793,40 +793,40 @@ rules: rules TOK_SET TOK_RLIMIT TOK_ID TOK_LE TOK_VALUE TOK_END_OF_RULE
 
 cond_rule: TOK_IF expr TOK_OPEN rules TOK_CLOSE
 	{
-		struct codomain *ret = NULL;
+		Profile *ret = NULL;
 		PDEBUG("Matched: found conditional rules\n");
 		if ($2) {
 			ret = $4;
 		} else {
-			free_policy($4);
+			delete $4;
 		}
 		$$ = ret;
 	}
 
 cond_rule: TOK_IF expr TOK_OPEN rules TOK_CLOSE TOK_ELSE TOK_OPEN rules TOK_CLOSE
 	{
-		struct codomain *ret = NULL;
+		Profile *ret = NULL;
 		PDEBUG("Matched: found conditional else rules\n");
 		if ($2) {
 			ret = $4;
-			free_policy($8);
+			delete $8;
 		} else {
 			ret = $8;
-			free_policy($4);
+			delete $4;
 		}
 		$$ = ret;
 	}
 
 cond_rule: TOK_IF expr TOK_OPEN rules TOK_CLOSE TOK_ELSE cond_rule
 	{
-		struct codomain *ret = NULL;
+		Profile *ret = NULL;
 		PDEBUG("Matched: found conditional else-if rules\n");
 		if ($2) {
 			ret = $4;
-			free_policy($7);
+			delete $7;
 		} else {
 			ret = $7;
-			free_policy($4);
+			delete $4;
 		}
 		$$ = ret;
 	}
@@ -1222,25 +1222,25 @@ struct cod_entry *do_file_rule(char *ns, char *id, int mode,
 /* Note: NOT currently in use, used for 
  * /foo x -> { /bah, }   style transitions
  */
-void add_local_entry(struct codomain *cod)
+void add_local_entry(Profile *prof)
 {
 	/* ugh this has to be called after the hat is attached to its parent */
-	if (cod->local_mode) {
+	if (prof->local_mode) {
 		struct cod_entry *entry;
-		char *trans = (char *) malloc(strlen(cod->parent->name) +
-				    strlen(cod->name) + 3);
-		char *name = strdup(cod->name);
+		char *trans = (char *) malloc(strlen(prof->parent->name) +
+				    strlen(prof->name) + 3);
+		char *name = strdup(prof->name);
 		if (!trans)
 			yyerror(_("Memory allocation error."));
-		sprintf(name, "%s//%s", cod->parent->name, cod->name);
+		sprintf(name, "%s//%s", prof->parent->name, prof->name);
 
-		entry = new_entry(NULL, name, cod->local_mode, NULL);
-		entry->audit = cod->local_audit;
+		entry = new_entry(NULL, name, prof->local_mode, NULL);
+		entry->audit = prof->local_audit;
 		entry->nt_name = trans;
 		if (!entry)
 			yyerror(_("Memory allocation error."));
 
-		add_entry_to_policy(cod, entry);
+		add_entry_to_policy(prof, entry);
 	}
 }
 
diff --git a/parser/profile.cc b/parser/profile.cc
new file mode 100644
index 0000000..3033985
--- /dev/null
+++ b/parser/profile.cc
@@ -0,0 +1,89 @@
+/*
+ *   Copyright (c) 2012
+ *   Canonical, Ltd. (All rights reserved)
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ */
+
+#include "profile.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+bool deref_profileptr_lt::operator()(Profile * const &lhs, Profile * const &rhs) const
+{
+  return *lhs < *rhs;
+};
+
+pair<ProfileList::iterator,bool> ProfileList::insert(Profile *p)
+{
+	return list.insert(p);
+}
+
+void ProfileList::erase(ProfileList::iterator pos)
+{
+	list.erase(pos);
+}
+
+void ProfileList::clear(void)
+{
+	for(ProfileList::iterator i = list.begin(); i != list.end(); ) {
+		ProfileList::iterator k = i++;
+		delete *k;
+		list.erase(k);
+	}
+}
+
+void ProfileList::dump(void)
+{
+	for(ProfileList::iterator i = list.begin(); i != list.end(); i++) {
+		(*i)->dump();
+	}
+}
+
+void ProfileList::dump_profile_names(bool children)
+{
+	for (ProfileList::iterator i = list.begin(); i != list.end();i++) {
+		(*i)->dump_name(true);
+		printf("\n");
+		if (children && !(*i)->hat_table.empty())
+			(*i)->hat_table.dump_profile_names(children);
+	}
+}
+
+Profile::~Profile()
+{
+	hat_table.clear();
+	free_cod_entries(entries);
+	free_mnt_entries(mnt_ents);
+	if (dfa.rules)
+		aare_delete_ruleset(dfa.rules);
+	if (dfa.dfa)
+		free(dfa.dfa);
+	if (policy.rules)
+		aare_delete_ruleset(policy.rules);
+	if (policy.dfa)
+		free(policy.dfa);
+	if (name)
+		free(name);
+	if (attachment)
+		free(attachment);
+	if (ns)
+		free(ns);
+	if (net.allow)
+		free(net.allow);
+	if (net.audit)
+		free(net.audit);
+	if (net.deny)
+		free(net.deny);
+	if (net.quiet)
+		free(net.quiet);
+}
+
diff --git a/parser/profile.h b/parser/profile.h
new file mode 100644
index 0000000..67e1b60
--- /dev/null
+++ b/parser/profile.h
@@ -0,0 +1,241 @@
+/*
+ *   Copyright (c) 2012
+ *   Canonical, Ltd. (All rights reserved)
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ */
+#ifndef __AA_PROFILE_H
+#define __AA_PROFILE_H
+
+#include <set>
+
+#include "parser.h"
+
+class Profile;
+
+class block {
+public:
+
+};
+
+
+struct deref_profileptr_lt {
+	bool operator()(Profile * const &lhs, Profile * const &rhs) const;
+};
+
+class ProfileList {
+public:
+	set<Profile *, deref_profileptr_lt> list;
+
+	typedef set<Profile *, deref_profileptr_lt>::iterator iterator;
+	iterator begin() { return list.begin(); }
+	iterator end() { return list.end(); }
+
+	ProfileList() { };
+	virtual ~ProfileList() { clear(); }
+	virtual bool empty(void) { return list.empty(); }
+	virtual pair<ProfileList::iterator,bool> insert(Profile *);
+	virtual void erase(ProfileList::iterator pos);
+	void clear(void);
+	void dump(void);
+	void dump_profile_names(bool children);
+};
+
+
+
+class flagvals {
+public:
+	int hat;
+	int complain;
+	int audit;
+	int path;
+
+	void dump(void)
+	{
+		printf("Profile Mode:\t");
+
+		if (complain)
+			printf("Complain");
+		else
+			printf("Enforce");
+
+		if (audit)
+			printf(", Audit");
+
+		if (hat)
+			printf(", Hat");
+
+		printf("\n");
+	}
+};
+
+struct capabilities {
+	uint64_t allow;
+	uint64_t audit;
+	uint64_t deny;
+	uint64_t quiet;
+
+	capabilities(void) { allow = audit = deny = quiet; }
+
+	void dump()
+		{
+			if (allow != 0ull)
+				__debug_capabilities(allow, "Capabilities");
+			if (audit != 0ull)
+				__debug_capabilities(audit, "Audit Caps");
+			if (deny != 0ull)
+				__debug_capabilities(deny, "Deny Caps");
+			if (quiet != 0ull)
+				__debug_capabilities(quiet, "Quiet Caps");
+		};
+};
+
+struct network {
+	unsigned int *allow;		/* array of type masks
+						 * indexed by AF_FAMILY */
+	unsigned int *audit;
+	unsigned int *deny;
+	unsigned int *quiet;
+
+	network(void) { allow = audit = deny = quiet = NULL; }
+
+	void dump(void) {
+		if (allow)
+			__debug_network(allow, "Network");
+		if (audit)
+			__debug_network(audit, "Audit Net");
+		if (deny)
+			__debug_network(deny, "Deny Net");
+		if (quiet)
+			__debug_network(quiet, "Quiet Net");
+	}
+};
+
+struct dfa_stuff {
+	aare_ruleset_t *rules;
+	int count;
+	void *dfa;
+	size_t size;
+
+	dfa_stuff(void): rules(NULL), count(0), dfa(NULL), size(0) { } 
+};
+
+class Profile {
+public:
+	char *ns;
+	char *name;
+	char *attachment;
+	struct alt_name *altnames;
+	void *xmatch;
+	size_t xmatch_size;
+	int xmatch_len;
+
+	/* char *sub_name; */			/* subdomain name or NULL */
+	/* int default_deny; */			/* TRUE or FALSE */
+	int local;
+	int local_mode;				/* true if local, not hat */
+	int local_audit;
+
+	Profile *parent;
+
+	struct flagvals flags;
+	struct capabilities caps;
+	struct network net;
+
+	struct aa_rlimits rlimits;
+
+	char *exec_table[AA_EXEC_COUNT];
+	struct cod_entry *entries;
+	struct mnt_entry *mnt_ents;
+
+	ProfileList hat_table;
+
+	struct dfa_stuff dfa;
+	struct dfa_stuff policy;
+
+	Profile(void)
+	{
+		ns = name = attachment = NULL;
+		altnames = NULL;
+		xmatch = NULL;
+		xmatch_size = 0;
+		xmatch_len = 0;
+
+		local = local_mode = local_audit = 0;
+
+		parent = NULL;
+
+		flags = { 0, 0, 0, 0};
+		rlimits = { 0 };
+
+		std:fill(exec_table, exec_table + AA_EXEC_COUNT, (char *)NULL);
+
+		entries = NULL;
+		mnt_ents = NULL;
+
+		
+	};
+
+	virtual ~Profile();
+
+	bool operator<(Profile const &rhs)const
+	{
+		if (ns) {
+			if (rhs.ns) {
+				int res = strcmp(ns, rhs.ns);
+				if (res != 0)
+					return res < 0;
+			} else
+				return false;
+		} else if (rhs.ns)
+			return true;
+		return strcmp(name, rhs.name) < 0;
+	}
+
+	void dump(void)
+	{
+		if (ns)
+			printf("Ns:\t\t%s\n", ns);
+
+		if (name)
+			printf("Name:\t\t%s\n", name);
+		else
+			printf("Name:\t\t<NULL>\n");
+
+		if (local) {
+			if (parent)
+				printf("Local To:\t%s\n", parent->name);
+			else
+				printf("Local To:\t<NULL>\n");
+		}
+
+		flags.dump();
+		caps.dump();
+		net.dump();
+
+		if (entries)
+			debug_cod_entries(entries);
+
+		printf("\n");
+		hat_table.dump();
+	}
+
+	void dump_name(bool fqp)
+	{
+		if (fqp && parent) {
+			parent->dump_name(fqp);
+			printf("//%s", name);
+		} else
+			printf("%s", name);
+	}
+};
+
+
+#endif /* __AA_PROFILE_H */
diff --git a/parser/unit_test.h b/parser/unit_test.h
new file mode 100644
index 0000000..3b7cc5b
--- /dev/null
+++ b/parser/unit_test.h
@@ -0,0 +1,53 @@
+/*
+ *   Copyright (c) 2012
+ *   Canonical, Ltd. (All rights reserved)
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ */
+#ifndef __AA_UNIT_TEST_H
+#define __AA_UNIT_TEST_H
+
+#ifdef UNIT_TEST
+/* For the unit-test builds, we must include function stubs for stuff that
+ * only exists in the excluded object files; everything else should live
+ * in parser_common.c.
+ */
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <linux/limits.h>
+
+#undef _
+#define _(s) (s)
+
+/* parser_yacc.y */
+void yyerror(const char *msg, ...)
+{
+        va_list arg;
+        char buf[PATH_MAX];
+
+        va_start(arg, msg);
+        vsnprintf(buf, sizeof(buf), msg, arg);
+        va_end(arg);
+
+        PERROR(_("AppArmor parser error: %s\n"), buf);
+
+        exit(1);
+}
+
+#define MY_TEST(statement, error)               \
+        if (!(statement)) {                     \
+                PERROR("FAIL: %s\n", error);    \
+                rc = 1;                         \
+        }
+
+#endif
+
+#endif /* __AA_UNIT_TEST_H */
-- 
1.7.10.4




More information about the AppArmor mailing list