diff -urNp gradm2/gradm_defs.h gradm2-new/gradm_defs.h
--- gradm2/gradm_defs.h	2010-11-24 09:22:08.000000000 -0500
+++ gradm2-new/gradm_defs.h	2010-12-04 15:59:35.000000000 -0500
@@ -361,6 +361,8 @@ struct proc_acl {
 };
 
 struct gr_learn_ip_node {
+	struct gr_learn_ip_node *prev;
+	struct gr_learn_ip_node *next;
 	u_int8_t ip_node;
 	u_int16_t **ports;
 	u_int32_t ip_proto[8];
@@ -369,10 +371,12 @@ struct gr_learn_ip_node {
 	unsigned char all_low_ports:1;
 	unsigned char all_high_ports:1;
 	struct gr_learn_ip_node *parent;
-	struct gr_learn_ip_node **leaves;
+	struct gr_learn_ip_node *leaves;
 };
 
 struct gr_learn_role_entry {
+	struct gr_learn_role_entry *prev;
+	struct gr_learn_role_entry *next;
 	char *rolename;
 	u_int16_t rolemode;
 	unsigned int id;
@@ -382,9 +386,11 @@ struct gr_learn_role_entry {
 };	
 
 struct gr_learn_group_node {
+	struct gr_learn_group_node *prev;
+	struct gr_learn_group_node *next;
 	char *rolename;
 	gid_t gid;
-	struct gr_learn_user_node **users;
+	struct gr_learn_user_node *users;
 	struct gr_hash_struct *hash;
 	struct gr_learn_file_node *subject_list;
 	struct gr_learn_ip_node *allowed_ips;
@@ -397,6 +403,8 @@ struct gr_learn_file_tmp_node {
 };
 
 struct gr_learn_user_node {
+	struct gr_learn_user_node *prev;
+	struct gr_learn_user_node *next;
 	char *rolename;
 	uid_t uid;
 	int multgroups;
@@ -416,9 +424,11 @@ struct gr_learn_subject_node {
 };
 
 struct gr_learn_file_node {
+	struct gr_learn_file_node *prev;
+	struct gr_learn_file_node *next;
 	char *filename;
 	u_int32_t mode;
-	struct gr_learn_file_node **leaves;
+	struct gr_learn_file_node *leaves;
 	struct gr_learn_file_node *parent;
 	struct gr_hash_struct *hash;
 	struct gr_learn_file_node *object_list;
diff -urNp gradm2/gradm_fulllearn.c gradm2-new/gradm_fulllearn.c
--- gradm2/gradm_fulllearn.c	2010-10-31 12:29:21.000000000 -0400
+++ gradm2-new/gradm_fulllearn.c	2010-12-05 12:11:06.000000000 -0500
@@ -3,7 +3,7 @@
 extern struct gr_learn_file_node **cachednode;
 extern unsigned int cachedlen;
 
-struct gr_learn_group_node **role_list = NULL;
+struct gr_learn_group_node *the_role_list = NULL;
 extern FILE *fulllearn_pass1in;
 extern FILE *fulllearn_pass2in;
 extern FILE *fulllearn_pass3in;
@@ -21,7 +21,7 @@ void fulllearn_pass1(FILE *stream)
 	fflush(stdout);
 	printf("Beginning full learning role reduction...");
 	fflush(stdout);
-	reduce_roles(&role_list);
+	reduce_roles(&the_role_list);
 	printf("done.\n");
 	fflush(stdout);
 
@@ -95,8 +95,8 @@ void fulllearn_pass2(FILE *stream)
 	printf("done.\n");
 	fflush(stdout);
 
-	traverse_roles(role_list, &full_reduce_subjects, NULL);
-	traverse_roles(role_list, &full_reduce_allowed_ips, NULL);
+	traverse_roles(the_role_list, &full_reduce_subjects, NULL);
+	traverse_roles(the_role_list, &full_reduce_allowed_ips, NULL);
 
 	return;
 }
@@ -217,23 +217,22 @@ int full_reduce_ips(struct gr_learn_grou
 
 void free_ip_ports(struct gr_learn_ip_node *node)
 {
-	struct gr_learn_ip_node **tmp;
+	struct gr_learn_ip_node *tmp, *tmp3;
 	u_int16_t **tmp2;
+	int removed = 0;
 
 	if (node == NULL)
 		return;
 
-	tmp = node->leaves;
-
-	while (tmp && *tmp) {
-		free_ip_ports(*tmp);
-		tmp++;
+	for_each_removable_list_entry(tmp, node->leaves) {
+		tmp3 = tmp->next;
+		free_ip_ports(tmp);
+		removed = 1;
+		tmp = tmp3;
+		for_each_removable_list_entry_end(tmp);
 	}
 	
-	if (node->leaves) {
-		gr_dyn_free(node->leaves);
-		node->leaves = NULL;
-	}
+	node->leaves = NULL;
 
 	tmp2 = node->ports;
 	while (tmp2 && *tmp2) {
@@ -243,30 +242,31 @@ void free_ip_ports(struct gr_learn_ip_no
 
 	if (node->ports)
 		gr_dyn_free(node->ports);
+
+	node->ports = NULL;
+
 	gr_stat_free(node);
-	node = NULL;
 
 	return;
 }
 
 void free_subject_objects(struct gr_learn_file_node *node)
 {
-	struct gr_learn_file_node **tmp;
+	struct gr_learn_file_node *tmp, *tmp2;
+	int removed = 0;
 
 	if (node == NULL)
 		return;
 
-	tmp = node->leaves;
-
-	while (tmp && *tmp) {
-		free_subject_objects(*tmp);
-		tmp++;
+	for_each_removable_list_entry(tmp, node->leaves) {
+		tmp2 = tmp->next;
+		free_subject_objects(tmp);
+		removed = 1;
+		tmp = tmp2;
+		for_each_removable_list_entry_end(tmp);
 	}
 
-	if (node->leaves) {
-		gr_dyn_free(node->leaves);
-		node->leaves = NULL;
-	}
+	node->leaves = NULL;
 
 	free_ip_ports(node->connect_list);
 	free_ip_ports(node->bind_list);
@@ -275,10 +275,9 @@ void free_subject_objects(struct gr_lear
 		free(node->subject);
 		node->subject = NULL;
 	}
+
 	free(node->filename);
 	gr_stat_free(node);
-	node = NULL;
-	
 
 	return;
 }
@@ -467,8 +466,9 @@ void output_role_info(struct gr_learn_gr
 
 void generate_full_learned_acls(FILE *learnlog, FILE *stream)
 {
-	struct gr_learn_group_node **group;
-	struct gr_learn_user_node **user;
+	struct gr_learn_group_node *group, *tmpgroup;
+	struct gr_learn_user_node *user, *tmpuser;
+	int removed = 0;
 
 	output_learn_header(stream);
 
@@ -477,32 +477,37 @@ void generate_full_learned_acls(FILE *le
 	fulllearn_pass2(learnlog);
 	
 	fulllearn_pass3in = learnlog;
-	group = role_list;
 
-	if (!group)
-		goto out;
-
-	while (*group) {
-		user = (*group)->users;
-		if (!user) {
-			current_learn_rolename = (*group)->rolename;
+	for_each_removable_list_entry(group, the_role_list) {
+		if (group->users == NULL) {
+			current_learn_rolename = group->rolename;
 			current_learn_rolemode = GR_ROLE_GROUP;
-			output_role_info((*group), NULL, stream);
-			traverse_file_tree((*group)->subject_list, &fulllearn_pass3, NULL, stream);
-		} else {	
-			while (*user) {
-				current_learn_rolename = (*user)->rolename;
+			output_role_info(group, NULL, stream);
+			if (group->subject_list)
+				sort_file_node_list(&group->subject_list->leaves);
+			traverse_file_tree(group->subject_list, &fulllearn_pass3, NULL, stream);
+		} else {
+			for_each_removable_list_entry(user, group->users) {
+				current_learn_rolename = user->rolename;
 				current_learn_rolemode = GR_ROLE_USER;
-				output_role_info(NULL, (*user), stream);
-				traverse_file_tree((*user)->subject_list, &fulllearn_pass3, NULL, stream);
-				free_role_user_full(*user);
-				user++;
+				output_role_info(NULL, user, stream);
+				if (user->subject_list)
+					sort_file_node_list(&user->subject_list->leaves);
+				traverse_file_tree(user->subject_list, &fulllearn_pass3, NULL, stream);
+				tmpuser = user->next;
+				free_role_user_full(user);
+				user = tmpuser;
+				removed = 1;
+				for_each_removable_list_entry_end(user);
 			}
 		}
-		free_role_group_full(*group);
-		group++;
+		tmpgroup = group->next;
+		free_role_group_full(group);
+		group = tmpgroup;
+		removed = 1;
+		for_each_removable_list_entry_end(group);
 	}
-out:
+
 	fprintf(stdout, "Full learning complete.\n");
 	fclose(learnlog);
 	return;
diff -urNp gradm2/gradm_fulllearn_pass1.y gradm2-new/gradm_fulllearn_pass1.y
--- gradm2/gradm_fulllearn_pass1.y	2005-01-22 21:25:58.000000000 -0500
+++ gradm2-new/gradm_fulllearn_pass1.y	2010-12-04 15:42:04.000000000 -0500
@@ -2,7 +2,7 @@
 #include "gradm.h"
 extern int fulllearn_pass1lex(void);
 
-extern struct gr_learn_group_node **role_list;
+extern struct gr_learn_group_node *the_role_list;
 %}
 
 %union {
@@ -43,7 +43,7 @@ learn_log:
 			group = gr_get_group_name(gid);
 
 			if (user && group)
-				insert_user(&role_list, user, group, uid, gid);
+				insert_user(&the_role_list, user, group, uid, gid);
 		}		
 	|	ROLENAME ':' NUM ':' NUM ':' NUM ':' filename ':' filename ':' IPADDR ':' NUM ':' NUM ':' NUM ':' NUM ':' IPADDR
 		{
@@ -59,7 +59,7 @@ learn_log:
 			group = gr_get_group_name(gid);
 
 			if (user && group)
-				insert_user(&role_list, user, group, uid, gid);
+				insert_user(&the_role_list, user, group, uid, gid);
 		}
 	|	ROLENAME ':' NUM ':' NUM ':' NUM ':' filename ':' filename ':' id_type ':' NUM ':' NUM ':' NUM ':' IPADDR
 		{
@@ -75,7 +75,7 @@ learn_log:
 			group = gr_get_group_name(gid);
 
 			if (user && group)
-				insert_user(&role_list, user, group, uid, gid);
+				insert_user(&the_role_list, user, group, uid, gid);
 		}
 	;
 %%
diff -urNp gradm2/gradm_fulllearn_pass2.y gradm2-new/gradm_fulllearn_pass2.y
--- gradm2/gradm_fulllearn_pass2.y	2005-03-22 10:09:24.000000000 -0500
+++ gradm2-new/gradm_fulllearn_pass2.y	2010-12-04 15:42:17.000000000 -0500
@@ -2,7 +2,7 @@
 #include "gradm.h"
 extern int fulllearn_pass2lex(void);
 
-extern struct gr_learn_group_node **role_list;
+extern struct gr_learn_group_node *the_role_list;
 %}
 
 %union {
@@ -59,7 +59,7 @@ learn_log:
 
 			addr = $21;
 
-			match_role(role_list, uid, gid, &group, &user);
+			match_role(the_role_list, uid, gid, &group, &user);
 	
 			if (user)
 				insert_ip(&(user->allowed_ips), addr, 0, 0, 0);
@@ -95,7 +95,7 @@ learn_log:
 
 			addr = $23;
 
-			match_role(role_list, uid, gid, &group, &user);
+			match_role(the_role_list, uid, gid, &group, &user);
 
 			if (user) {
 				insert_ip(&(user->allowed_ips), addr, 0, 0, 0);
diff -urNp gradm2/gradm_fulllearn_pass3.y gradm2-new/gradm_fulllearn_pass3.y
--- gradm2/gradm_fulllearn_pass3.y	2010-11-20 21:50:42.000000000 -0500
+++ gradm2-new/gradm_fulllearn_pass3.y	2010-12-04 15:42:28.000000000 -0500
@@ -2,7 +2,7 @@
 #include "gradm.h"
 extern int fulllearn_pass3lex(void);
 
-extern struct gr_learn_group_node **role_list;
+extern struct gr_learn_group_node *the_role_list;
 %}
 
 %union {
@@ -60,7 +60,7 @@ learn_log:
 			res1 = $13;
 			res2 = $15;
 
-			match_role(role_list, uid, gid, &group, &user);
+			match_role(the_role_list, uid, gid, &group, &user);
 			/* only add objects for the role currently in memory */
 			if ((current_learn_rolemode == GR_ROLE_GROUP && group && !strcmp(group->rolename, current_learn_rolename)) ||
 			    (current_learn_rolemode == GR_ROLE_USER && user && !strcmp(user->rolename, current_learn_rolename)))
@@ -120,7 +120,7 @@ learn_log:
 			proto = $19;
 			mode = $21;
 
-			match_role(role_list, uid, gid, &group, &user);
+			match_role(the_role_list, uid, gid, &group, &user);
 			/* only add objects for the role currently in memory */
 			if ((current_learn_rolemode == GR_ROLE_GROUP && group && !strcmp(group->rolename, current_learn_rolename)) ||
 			    (current_learn_rolemode == GR_ROLE_USER && user && !strcmp(user->rolename, current_learn_rolename)))
@@ -175,7 +175,7 @@ learn_log:
 			eff = $17;
 			fs = $19;
 
-			match_role(role_list, uid, gid, &group, &user);
+			match_role(the_role_list, uid, gid, &group, &user);
 			/* only add objects for the role currently in memory */
 			if ((current_learn_rolemode == GR_ROLE_GROUP && group && !strcmp(group->rolename, current_learn_rolename)) ||
 			    (current_learn_rolemode == GR_ROLE_USER && user && !strcmp(user->rolename, current_learn_rolename)))
diff -urNp gradm2/gradm_func.h gradm2-new/gradm_func.h
--- gradm2/gradm_func.h	2010-11-20 21:50:42.000000000 -0500
+++ gradm2-new/gradm_func.h	2010-12-05 12:09:30.000000000 -0500
@@ -71,17 +71,17 @@ struct var_object *differentiate_objects
 void sort_file_list(struct gr_hash_struct *hash);
 struct gr_learn_file_node *match_file_node(struct gr_learn_file_node *base, const char *filename);
 struct gr_learn_file_tmp_node *conv_filename_to_struct(char *filename, u_int32_t mode);
-void match_role(struct gr_learn_group_node **grouplist, uid_t uid, gid_t gid, struct gr_learn_group_node **group, struct gr_learn_user_node **user);
-struct gr_learn_ip_node ** find_insert_ip(struct gr_learn_ip_node **base, u_int32_t ip, struct gr_learn_ip_node **parent);
+void match_role(struct gr_learn_group_node *grouplist, uid_t uid, gid_t gid, struct gr_learn_group_node **group, struct gr_learn_user_node **user);
+struct gr_learn_ip_node * find_insert_ip(struct gr_learn_ip_node **base, u_int32_t ip);
 void conv_mode_to_str(u_int32_t mode, char *modestr, unsigned short len);
 void conv_subj_mode_to_str(u_int32_t mode, char *modestr, unsigned short len);
 void generate_full_learned_acls(FILE *learn_log, FILE *stream);
-void reduce_roles(struct gr_learn_group_node ***grouplist);
+void reduce_roles(struct gr_learn_group_node **grouplist);
 void insert_file(struct gr_learn_file_node **base, char *filename, u_int32_t mode, u_int8_t subj);
 void first_stage_reduce_tree(struct gr_learn_file_node *base);
 void second_stage_reduce_tree(struct gr_learn_file_node *base);
 void third_stage_reduce_tree(struct gr_learn_file_node *base);
-void traverse_roles(struct gr_learn_group_node **grouplist,
+void traverse_roles(struct gr_learn_group_node *grouplist,
 		int (*act)(struct gr_learn_group_node *group, struct gr_learn_user_node *user, FILE *stream),
 		FILE *stream);
 void traverse_file_tree(struct gr_learn_file_node *base,
@@ -89,7 +89,7 @@ void traverse_file_tree(struct gr_learn_
 		struct gr_learn_file_node *optarg, FILE *stream);
 void reduce_ip_tree(struct gr_learn_ip_node *base);
 void reduce_ports_tree(struct gr_learn_ip_node *base);
-void display_roles(struct gr_learn_group_node **grouplist, FILE *stream);
+void display_roles(struct gr_learn_group_node *grouplist, FILE *stream);
 void add_fulllearn_acl(void);
 void insert_ip(struct gr_learn_ip_node **base, u_int32_t ip, u_int16_t port, u_int8_t proto,
 		u_int8_t socktype);
@@ -97,13 +97,13 @@ int is_protected_path(char *filename, u_
 
 void add_grlearn_option(u_int32_t option);
 struct gr_learn_role_entry *
-insert_learn_role(struct gr_learn_role_entry ***role_list, char *rolename, u_int16_t rolemode);
+insert_learn_role(struct gr_learn_role_entry **role_list, char *rolename, u_int16_t rolemode);
 void insert_learn_object(struct gr_learn_file_node *subject, struct gr_learn_file_tmp_node *object);
 void insert_learn_role_subject(struct gr_learn_role_entry *role, struct gr_learn_file_tmp_node *subject);
 void insert_learn_group_subject(struct gr_learn_group_node *role, struct gr_learn_file_tmp_node *subject);
 void insert_learn_user_subject(struct gr_learn_user_node *role, struct gr_learn_file_tmp_node *subject);
 struct gr_learn_role_entry *
-find_learn_role(struct gr_learn_role_entry **role_list, char *rolename);
+find_learn_role(struct gr_learn_role_entry *role_list, char *rolename);
 int full_reduce_object_node(struct gr_learn_file_node *subject,
 			    struct gr_learn_file_node *unused1,
 			    FILE *unused2);
@@ -121,7 +121,7 @@ void traverse_ip_tree(struct gr_learn_ip
 			u_int8_t contype, FILE *stream);
 void display_tree(struct gr_learn_file_node *base, FILE *stream);
 void enforce_high_protected_paths(struct gr_learn_file_node *subject);
-void insert_user(struct gr_learn_group_node ***grouplist, char *username, char *groupname, uid_t uid, gid_t gid);
+void insert_user(struct gr_learn_group_node **grouplist, char *username, char *groupname, uid_t uid, gid_t gid);
 void add_rolelearn_acl(void);
 int ensure_subject_security(struct gr_learn_file_node *subject,
 			struct gr_learn_file_node *unused1,
@@ -163,6 +163,8 @@ void add_replace_string(char *name, char
 char *lookup_replace_string(char *name);
 char *process_string_replace(char *str);
 
+void sort_file_node_list(struct gr_learn_file_node **filelist);
+
 void add_sock_family(struct proc_acl *subject, char *family);
 
 #endif
diff -urNp gradm2/gradm.h gradm2-new/gradm.h
--- gradm2/gradm.h	2009-10-06 18:45:13.000000000 -0400
+++ gradm2-new/gradm.h	2010-12-05 02:09:27.000000000 -0500
@@ -58,6 +58,32 @@
 #define for_each_globbed(x, y) \
 	for(x = (y)->globbed; x; x = (x)->next)
 
+#define for_each_leaf(x, y) \
+	for (x = (y)->leaves; x; x = (x)->next)
+
+#define for_each_list_entry(x, y) \
+	for (x = (y); x; x = (x)->next)
+
+#define for_each_removable_list_entry(x, y) \
+	for (x = (y); x;)
+
+#define for_each_removable_list_entry_end(x) 	\
+		if (removed)			\
+			removed = 0;		\
+		else				\
+			x = (x)->next;		
+
+#define for_each_parent_entry(x, y) \
+	for (x = (y); x; x = (x)->parent)
+
+#define establish_new_head(list, head, tmp)	\
+	do {					\
+		(tmp) = (list);			\
+		(head)->next = (tmp);		\
+		if ((tmp))			\
+			(tmp)->prev = (head);	\
+		(list) = (head);		\
+	} while (0);
 
 #define MAJOR_26(dev)     ((unsigned int) ((dev)>>20))
 #define MINOR_26(dev)     ((unsigned int) ((dev) & ((1U << 20) - 1)))
diff -urNp gradm2/gradm_learn.c gradm2-new/gradm_learn.c
--- gradm2/gradm_learn.c	2010-11-20 21:50:42.000000000 -0500
+++ gradm2-new/gradm_learn.c	2010-12-05 12:03:12.000000000 -0500
@@ -1,9 +1,9 @@
 #include "gradm.h"
 
 struct gr_learn_role_entry *default_role_entry;
-struct gr_learn_role_entry **group_role_list;
-struct gr_learn_role_entry **user_role_list;
-struct gr_learn_role_entry **special_role_list;
+struct gr_learn_role_entry *group_role_list;
+struct gr_learn_role_entry *user_role_list;
+struct gr_learn_role_entry *special_role_list;
 
 extern FILE *learn_pass1in;
 extern FILE *learn_pass2in;
@@ -12,7 +12,7 @@ extern int learn_pass2parse(void);
 
 void learn_pass1(FILE *stream)
 {
-	struct gr_learn_role_entry **tmp;
+	struct gr_learn_role_entry *tmp;
 	struct gr_learn_file_tmp_node **tmptable;
 	unsigned long i;
 	u_int32_t table_size;
@@ -38,64 +38,58 @@ void learn_pass1(FILE *stream)
 			reduce_ip_tree(default_role_entry->allowed_ips);
 	}
 
-	tmp = group_role_list;
-	while (tmp && *tmp) {
-		if ((*tmp)->hash) {
-			tmptable = (struct gr_learn_file_tmp_node **)(*tmp)->hash->table;
-			table_size = (*tmp)->hash->table_size;
-			sort_file_list((*tmp)->hash);
+	for_each_list_entry(tmp, group_role_list) {
+		if (tmp->hash) {
+			tmptable = (struct gr_learn_file_tmp_node **)tmp->hash->table;
+			table_size = tmp->hash->table_size;
+			sort_file_list(tmp->hash);
 			for (i = 0; i < table_size; i++) {
 				if (tmptable[i] == NULL)
 					continue;
-				if ((*tmp)->rolemode & GR_ROLE_LEARN)
-					insert_file(&((*tmp)->subject_list), tmptable[i]->filename, tmptable[i]->mode, 1);
+				if (tmp->rolemode & GR_ROLE_LEARN)
+					insert_file(&(tmp->subject_list), tmptable[i]->filename, tmptable[i]->mode, 1);
 				else
-					insert_file(&((*tmp)->subject_list), tmptable[i]->filename, tmptable[i]->mode, 2);
+					insert_file(&(tmp->subject_list), tmptable[i]->filename, tmptable[i]->mode, 2);
 			}
 		}
-		if ((*tmp)->rolemode & GR_ROLE_LEARN)
-			reduce_ip_tree((*tmp)->allowed_ips);
-		tmp++;
+		if (tmp->rolemode & GR_ROLE_LEARN)
+			reduce_ip_tree(tmp->allowed_ips);
 	}
 
-	tmp = user_role_list;
-	while (tmp && *tmp) {
-		if ((*tmp)->hash) {
-			tmptable = (struct gr_learn_file_tmp_node **)(*tmp)->hash->table;
-			table_size = (*tmp)->hash->table_size;
-			sort_file_list((*tmp)->hash);
+	for_each_list_entry(tmp, user_role_list) {
+		if (tmp->hash) {
+			tmptable = (struct gr_learn_file_tmp_node **)tmp->hash->table;
+			table_size = tmp->hash->table_size;
+			sort_file_list(tmp->hash);
 			for (i = 0; i < table_size; i++) {
 				if (tmptable[i] == NULL)
 					continue;
-				if ((*tmp)->rolemode & GR_ROLE_LEARN)
-					insert_file(&((*tmp)->subject_list), tmptable[i]->filename, tmptable[i]->mode, 1);
+				if (tmp->rolemode & GR_ROLE_LEARN)
+					insert_file(&(tmp->subject_list), tmptable[i]->filename, tmptable[i]->mode, 1);
 				else
-					insert_file(&((*tmp)->subject_list), tmptable[i]->filename, tmptable[i]->mode, 2);
+					insert_file(&(tmp->subject_list), tmptable[i]->filename, tmptable[i]->mode, 2);
 			}
 		}
-		if ((*tmp)->rolemode & GR_ROLE_LEARN)
-			reduce_ip_tree((*tmp)->allowed_ips);
-		tmp++;
+		if (tmp->rolemode & GR_ROLE_LEARN)
+			reduce_ip_tree(tmp->allowed_ips);
 	}
 
-	tmp = special_role_list;
-	while (tmp && *tmp) {
-		if ((*tmp)->hash) {
-			tmptable = (struct gr_learn_file_tmp_node **)(*tmp)->hash->table;
-			table_size = (*tmp)->hash->table_size;
-			sort_file_list((*tmp)->hash);
+	for_each_list_entry(tmp, special_role_list) {
+		if (tmp->hash) {
+			tmptable = (struct gr_learn_file_tmp_node **)tmp->hash->table;
+			table_size = tmp->hash->table_size;
+			sort_file_list(tmp->hash);
 			for (i = 0; i < table_size; i++) {
 				if (tmptable[i] == NULL)
 					continue;
-				if ((*tmp)->rolemode & GR_ROLE_LEARN)
-					insert_file(&((*tmp)->subject_list), tmptable[i]->filename, tmptable[i]->mode, 1);
+				if (tmp->rolemode & GR_ROLE_LEARN)
+					insert_file(&(tmp->subject_list), tmptable[i]->filename, tmptable[i]->mode, 1);
 				else
-					insert_file(&((*tmp)->subject_list), tmptable[i]->filename, tmptable[i]->mode, 2);
+					insert_file(&(tmp->subject_list), tmptable[i]->filename, tmptable[i]->mode, 2);
 			}
 		}
-		if ((*tmp)->rolemode & GR_ROLE_LEARN)
-			reduce_ip_tree((*tmp)->allowed_ips);
-		tmp++;
+		if (tmp->rolemode & GR_ROLE_LEARN)
+			reduce_ip_tree(tmp->allowed_ips);
 	}
 
 	return;
@@ -190,7 +184,7 @@ void merge_acl_rules(void)
 
 void learn_pass2(FILE *stream)
 {
-	struct gr_learn_role_entry **tmp;
+	struct gr_learn_role_entry *tmp;
 	struct gr_learn_file_node *subjects;
 	
 	learn_pass2in = stream;
@@ -205,31 +199,25 @@ void learn_pass2(FILE *stream)
 		traverse_file_tree(subjects, &ensure_subject_security, NULL, NULL);
 	}
 
-	tmp = group_role_list;
-	while (tmp && *tmp) {
-		subjects = (*tmp)->subject_list;
+	for_each_list_entry(tmp, group_role_list) {
+		subjects = tmp->subject_list;
 		traverse_file_tree(subjects, &full_reduce_object_node, NULL, NULL);
 		traverse_file_tree(subjects, &full_reduce_ip_node, NULL, NULL);
 		traverse_file_tree(subjects, &ensure_subject_security, NULL, NULL);
-		tmp++;
 	}
 
-	tmp = user_role_list;
-	while (tmp && *tmp) {
-		subjects = (*tmp)->subject_list;
+	for_each_list_entry(tmp, user_role_list) {
+		subjects = tmp->subject_list;
 		traverse_file_tree(subjects, &full_reduce_object_node, NULL, NULL);
 		traverse_file_tree(subjects, &full_reduce_ip_node, NULL, NULL);
 		traverse_file_tree(subjects, &ensure_subject_security, NULL, NULL);
-		tmp++;
 	}
 
-	tmp = special_role_list;
-	while (tmp && *tmp) {
-		subjects = (*tmp)->subject_list;
+	for_each_list_entry(tmp, special_role_list) {
+		subjects = tmp->subject_list;
 		traverse_file_tree(subjects, &full_reduce_object_node, NULL, NULL);
 		traverse_file_tree(subjects, &full_reduce_ip_node, NULL, NULL);
 		traverse_file_tree(subjects, &ensure_subject_security, NULL, NULL);
-		tmp++;
 	}
 
 	return;
@@ -249,7 +237,7 @@ perform_parse_and_reduce(FILE *learnlog)
 
 void display_learn_logs(FILE *stream)
 {
-	struct gr_learn_role_entry **tmp;
+	struct gr_learn_role_entry *tmp;
 	struct gr_learn_file_node *subjects;
 	struct gr_learn_ip_node *allowed_ips;
 	char rolemode[17];
@@ -263,67 +251,69 @@ void display_learn_logs(FILE *stream)
 		allowed_ips = default_role_entry->allowed_ips;
 		if (allowed_ips && !(grlearn_options & GR_DONT_LEARN_ALLOWED_IPS))
 			traverse_ip_tree(allowed_ips, NULL, &display_only_ip, 0, stream);
-		if (subjects)
+		if (subjects) {
+			sort_file_node_list(&default_role_entry->subject_list->leaves);
 			display_tree(subjects, stream);
+		}
 
 		fprintf(stream, "\n");
 	}
 
-	tmp = group_role_list;
-	while (tmp && *tmp) {
-		if (!((*tmp)->rolemode & GR_ROLE_LEARN))
-			fprintf(stream, "###  THE BELOW SUBJECT(S) SHOULD BE ADDED TO THE GROUP ROLE \"%s\" ###\n", (*tmp)->rolename);
+	for_each_list_entry(tmp, group_role_list) {
+		if (!(tmp->rolemode & GR_ROLE_LEARN))
+			fprintf(stream, "###  THE BELOW SUBJECT(S) SHOULD BE ADDED TO THE GROUP ROLE \"%s\" ###\n", tmp->rolename);
 		else {
-			conv_role_mode_to_str((*tmp)->rolemode, rolemode, sizeof(rolemode));
-			fprintf(stream, "role %s %s\n", (*tmp)->rolename, rolemode);
+			conv_role_mode_to_str(tmp->rolemode, rolemode, sizeof(rolemode));
+			fprintf(stream, "role %s %s\n", tmp->rolename, rolemode);
 		}
-		subjects = (*tmp)->subject_list;
-		allowed_ips = (*tmp)->allowed_ips;
+		subjects = tmp->subject_list;
+		allowed_ips = tmp->allowed_ips;
 		if (allowed_ips && !(grlearn_options & GR_DONT_LEARN_ALLOWED_IPS))
 			traverse_ip_tree(allowed_ips, NULL, &display_only_ip, 0, stream);
-		if (subjects)
+		if (subjects) {
+			sort_file_node_list(&group_role_list->subject_list->leaves);
 			display_tree(subjects, stream);
+		}
 
 		fprintf(stream, "\n");
-		tmp++;
 	}
 
-	tmp = user_role_list;
-	while (tmp && *tmp) {
-		if (!((*tmp)->rolemode & GR_ROLE_LEARN))
-			fprintf(stream, "###  THE BELOW SUBJECT(S) SHOULD BE ADDED TO THE USER ROLE \"%s\" ###\n", (*tmp)->rolename);
+	for_each_list_entry(tmp, user_role_list) {
+		if (!(tmp->rolemode & GR_ROLE_LEARN))
+			fprintf(stream, "###  THE BELOW SUBJECT(S) SHOULD BE ADDED TO THE USER ROLE \"%s\" ###\n", tmp->rolename);
 		else {
-			conv_role_mode_to_str((*tmp)->rolemode, rolemode, sizeof(rolemode));
-			fprintf(stream, "role %s %s\n", (*tmp)->rolename, rolemode);
+			conv_role_mode_to_str(tmp->rolemode, rolemode, sizeof(rolemode));
+			fprintf(stream, "role %s %s\n", tmp->rolename, rolemode);
 		}
-		subjects = (*tmp)->subject_list;
-		allowed_ips = (*tmp)->allowed_ips;
+		subjects = tmp->subject_list;
+		allowed_ips = tmp->allowed_ips;
 		if (allowed_ips && !(grlearn_options & GR_DONT_LEARN_ALLOWED_IPS))
 			traverse_ip_tree(allowed_ips, NULL, &display_only_ip, 0, stream);
-		if (subjects)
+		if (subjects) {
+			sort_file_node_list(&user_role_list->subject_list->leaves);
 			display_tree(subjects, stream);
+		}
 
 		fprintf(stream, "\n");
-		tmp++;
 	}
 
-	tmp = special_role_list;
-	while (tmp && *tmp) {
-		if (!((*tmp)->rolemode & GR_ROLE_LEARN))
-			fprintf(stream, "###  THE BELOW SUBJECT(S) SHOULD BE ADDED TO THE SPECIAL ROLE \"%s\" ###\n", (*tmp)->rolename);
+	for_each_list_entry(tmp, special_role_list) {
+		if (!(tmp->rolemode & GR_ROLE_LEARN))
+			fprintf(stream, "###  THE BELOW SUBJECT(S) SHOULD BE ADDED TO THE SPECIAL ROLE \"%s\" ###\n", tmp->rolename);
 		else {
-			conv_role_mode_to_str((*tmp)->rolemode, rolemode, sizeof(rolemode));
-			fprintf(stream, "role %s %s\n", (*tmp)->rolename, rolemode);
+			conv_role_mode_to_str(tmp->rolemode, rolemode, sizeof(rolemode));
+			fprintf(stream, "role %s %s\n", tmp->rolename, rolemode);
 		}
-		subjects = (*tmp)->subject_list;
-		allowed_ips = (*tmp)->allowed_ips;
+		subjects = tmp->subject_list;
+		allowed_ips = tmp->allowed_ips;
 		if (allowed_ips && !(grlearn_options & GR_DONT_LEARN_ALLOWED_IPS))
 			traverse_ip_tree(allowed_ips, NULL, &display_only_ip, 0, stream);
-		if (subjects)
+		if (subjects) {
+			sort_file_node_list(&special_role_list->subject_list->leaves);
 			display_tree(subjects, stream);
+		}
 
 		fprintf(stream, "\n");
-		tmp++;
 	}
 
 	return;
diff -urNp gradm2/gradm_learn_pass1.y gradm2-new/gradm_learn_pass1.y
--- gradm2/gradm_learn_pass1.y	2005-03-22 10:09:24.000000000 -0500
+++ gradm2-new/gradm_learn_pass1.y	2010-12-04 15:39:38.000000000 -0500
@@ -3,9 +3,9 @@
 extern int learn_pass1lex(void);
 
 extern struct gr_learn_role_entry *default_role_entry;
-extern struct gr_learn_role_entry **group_role_list;
-extern struct gr_learn_role_entry **user_role_list;
-extern struct gr_learn_role_entry **special_role_list;
+extern struct gr_learn_role_entry *group_role_list;
+extern struct gr_learn_role_entry *user_role_list;
+extern struct gr_learn_role_entry *special_role_list;
 
 %}
 
diff -urNp gradm2/gradm_learn_pass2.y gradm2-new/gradm_learn_pass2.y
--- gradm2/gradm_learn_pass2.y	2010-11-20 21:50:42.000000000 -0500
+++ gradm2-new/gradm_learn_pass2.y	2010-12-04 15:39:45.000000000 -0500
@@ -3,9 +3,9 @@
 extern int learn_pass2lex(void);
 
 extern struct gr_learn_role_entry *default_role_entry;
-extern struct gr_learn_role_entry **group_role_list;
-extern struct gr_learn_role_entry **user_role_list;
-extern struct gr_learn_role_entry **special_role_list;
+extern struct gr_learn_role_entry *group_role_list;
+extern struct gr_learn_role_entry *user_role_list;
+extern struct gr_learn_role_entry *special_role_list;
 
 %}
 
diff -urNp gradm2/gradm_lib.c gradm2-new/gradm_lib.c
--- gradm2/gradm_lib.c	2006-01-06 19:16:50.000000000 -0500
+++ gradm2-new/gradm_lib.c	2010-12-05 03:29:04.000000000 -0500
@@ -524,11 +524,9 @@ char *gr_get_user_name(uid_t uid)
 	struct gr_user_map *tmpuser = user_list;
 	struct passwd *pwd;
 
-	if (tmpuser) {
-		do {
-			if (tmpuser->uid == uid)
-				return tmpuser->user;
-		} while ((tmpuser = tmpuser->next));
+	for_each_list_entry(tmpuser, user_list) {
+		if (tmpuser->uid == uid)
+			return tmpuser->user;
 	}
 
 	pwd = getpwuid(uid);
@@ -546,14 +544,12 @@ char *gr_get_user_name(uid_t uid)
 
 char *gr_get_group_name(gid_t gid)
 {
-	struct gr_group_map *tmpgroup = group_list;
+	struct gr_group_map *tmpgroup;
 	struct group *grp;
 
-	if (tmpgroup) {
-		do {
-			if (tmpgroup->gid == gid)
-				return tmpgroup->group;
-		} while ((tmpgroup = tmpgroup->next));
+	for_each_list_entry (tmpgroup, group_list) {
+		if (tmpgroup->gid == gid)
+			return tmpgroup->group;
 	}
 
 	grp = getgrgid(gid);
diff -urNp gradm2/gradm_newlearn.c gradm2-new/gradm_newlearn.c
--- gradm2/gradm_newlearn.c	2010-12-05 02:44:19.000000000 -0500
+++ gradm2-new/gradm_newlearn.c	2010-12-05 12:04:51.000000000 -0500
@@ -1,6 +1,6 @@
 #include "gradm.h"
 
-struct gr_learn_file_node **cachednode = NULL;
+struct gr_learn_file_node *cachednode = NULL;
 unsigned int cachedlen = 0;
 
 void add_grlearn_option(u_int32_t option)
@@ -66,68 +66,105 @@ next:
 	return;
 }
 
-void match_role(struct gr_learn_group_node **grouplist, uid_t uid, gid_t gid, struct gr_learn_group_node **group,
+void match_role(struct gr_learn_group_node *grouplist, uid_t uid, gid_t gid, struct gr_learn_group_node **group,
 		struct gr_learn_user_node **user)
 {
-	struct gr_learn_group_node **tmpgroup;
-	struct gr_learn_user_node **tmpuser;
+	struct gr_learn_group_node *tmpgroup;
+	struct gr_learn_user_node *tmpuser;
 
 	*group = NULL;
 	*user = NULL;
 
-	tmpgroup = grouplist;
-
-	if (!tmpgroup)
-		return;
-
-	while (*tmpgroup) {
-		tmpuser = (*tmpgroup)->users;
-		while (tmpuser && *tmpuser) {
-			if ((*tmpuser)->uid == uid) {
-				*user = *tmpuser;
+	for_each_list_entry(tmpgroup, grouplist) {
+		for_each_list_entry(tmpuser, tmpgroup->users) {
+			if (tmpuser->uid == uid) {
+				*user = tmpuser;
 				return;
 			}
-			tmpuser++;
 		}
-		tmpgroup++;
 	}
 
-	tmpgroup = grouplist;
 
-	while (*tmpgroup) {
-		if ((*tmpgroup)->gid == gid) {
-			*group = *tmpgroup;
+	for_each_list_entry(tmpgroup, grouplist) {
+		if (tmpgroup->gid == gid) {
+			*group = tmpgroup;
 			return;
 		}
-		tmpgroup++;
 	}
 				
 	return;
 }
 
-void traverse_roles(struct gr_learn_group_node **grouplist, 
+void traverse_roles(struct gr_learn_group_node *grouplist, 
 		    int (*act)(struct gr_learn_group_node *group, struct gr_learn_user_node *user, FILE *stream),
 		    FILE *stream)
 {
-	struct gr_learn_group_node **tmpgroup;
-	struct gr_learn_user_node **tmpuser;
+	struct gr_learn_group_node *tmpgroup;
+	struct gr_learn_user_node *tmpuser;
+
+	for_each_list_entry(tmpgroup, grouplist) {
+		if (tmpgroup->users == NULL)
+			act(tmpgroup, NULL, stream);
+		else {
+			for_each_list_entry(tmpuser, tmpgroup->users) {
+				act(tmpgroup, tmpuser, stream);
+			}
+		}
+	}
+
+	return;
+}
+
+/* this sort currently destroys ->prev pointers, so don't
+   use this for sorting for anything but the final printing of objects
+*/
+void sort_file_node_list(struct gr_learn_file_node **filelist)
+{
+	int count = 0;
+	int i, j;
+	struct gr_learn_file_node *cur, *next, *prev;
+	int cmp;
 
-	tmpgroup = grouplist;
+	if (*filelist == NULL)
+		return;
+
+	for_each_list_entry(cur, *filelist) {
+		sort_file_node_list(&cur->leaves);
+		count++;
+	}
 
-	if (!tmpgroup)
+	if (count < 2)
 		return;
 
-	while(*tmpgroup) {
-		tmpuser = (*tmpgroup)->users;
-		if (!tmpuser)
-			act(*tmpgroup, NULL, stream);
-		else {
-			while(*tmpuser) {
-				act(*tmpgroup, *tmpuser, stream);
-				tmpuser++;
+	cur = *filelist;
+	prev = cur;
+	next = cur->next;
+	
+	
+	for (i = 0; i < count - 1; i++) {
+		for (j = 0; j < count - i - 1; j++) {
+			cmp = strcmp(cur->filename, next->filename);
+			if (cmp > 0) {
+				cur->next = next->next;
+				next->next = cur;
+				if (cur == *filelist) {
+					*filelist = next;
+					prev = next;
+				} else {
+					prev->next = next;
+					prev = next;
+				}
+				if (next)
+					next = cur->next;
+			} else {
+				prev = cur;
+				cur = next;
+				next = cur->next;
 			}
 		}
-		tmpgroup++;
+		cur = *filelist;
+		prev = cur;
+		next = cur->next;
 	}
 
 	return;
@@ -139,10 +176,15 @@ int display_role(struct gr_learn_group_n
 
 	output_role_info(group, user, stream);
 
-	if (user)
+	if (user) {
+		if (user->subject_list)
+			sort_file_node_list(&user->subject_list->leaves);
 		subject = user->subject_list;
-	else
+	} else {
+		if (group->subject_list)
+			sort_file_node_list(&group->subject_list->leaves);
 		subject = group->subject_list;
+	}
 
 	if (subject)
 		display_tree(subject, stream);
@@ -152,199 +194,275 @@ int display_role(struct gr_learn_group_n
 	return 0;
 }
 
-void display_roles(struct gr_learn_group_node **grouplist, FILE *stream)
+void display_roles(struct gr_learn_group_node *grouplist, FILE *stream)
 {
 	output_learn_header(stream);
 	traverse_roles(grouplist, &display_role, stream);
 	return;
 }
 	
-struct gr_learn_group_node **find_insert_group(struct gr_learn_group_node ***grouplist, gid_t gid)
+struct gr_learn_group_node *find_insert_group(struct gr_learn_group_node *grouplist, gid_t gid)
 {
-	struct gr_learn_group_node **tmp = *grouplist;
-	unsigned long num = 0;
-
-	if (!tmp) {
-		*grouplist = (struct gr_learn_group_node **)gr_dyn_alloc(2 * sizeof(struct gr_learn_group_node *));
-		return (*grouplist);
-	}
+	struct gr_learn_group_node *tmp;
 
-	while(*tmp) {
-		if ((*tmp)->gid == gid)
+	for_each_list_entry(tmp, grouplist) {
+		if (tmp->gid == gid)
 			return tmp;
-		tmp++;
-		num++;
 	}
 
-	*grouplist = (struct gr_learn_group_node **)gr_dyn_realloc(*grouplist, (num + 2) * sizeof(struct gr_learn_group_node *));
-	memset(*grouplist + num, 0, 2 * sizeof(struct gr_learn_group_node *));
- 
-	return (*grouplist + num);
+	return NULL;
 }
 
 unsigned long count_users(struct gr_learn_group_node *group)
 {
-	struct gr_learn_user_node **tmp;
+	struct gr_learn_user_node *tmp;
 	unsigned long ret = 0;
 
-	tmp = group->users;
-
-	if (!tmp)
-		return 0;
-
-	while (*tmp) {
+	for_each_list_entry(tmp, group->users)
 		ret++;
-		tmp++;
-	}
 
 	return ret;
 }
 
 static unsigned long count_users_nomultgroups(struct gr_learn_group_node *group)
 {
-	struct gr_learn_user_node **tmp;
+	struct gr_learn_user_node *tmp;
 	unsigned long ret = 0;
 
-	tmp = group->users;
-
-	if (!tmp)
-		return 0;
-
-	while (*tmp) {
-		if (!(*tmp)->multgroups)
+	for_each_list_entry(tmp, group->users) {
+		if (!tmp->multgroups)
 			ret++;
-		tmp++;
 	}
 
 	return ret;
 }
 
-void insert_user(struct gr_learn_group_node ***grouplist, char *username, char *groupname, uid_t uid, gid_t gid)
+struct gr_learn_user_node * create_new_user(char *username, uid_t uid, struct gr_learn_group_node *group, int multgroups)
 {
-	struct gr_learn_group_node **group;
-	struct gr_learn_user_node **tmpuser;
-	unsigned long num;
+	struct gr_learn_user_node *user;
+
+	user = (struct gr_learn_user_node *)gr_stat_alloc(sizeof(struct gr_learn_user_node));
+	user->rolename = gr_strdup(username);
+	user->uid = uid;
+	user->group = group;
+	user->multgroups = multgroups;
+
+	return user;
+}
+
+struct gr_learn_group_node * create_new_group(char *groupname, gid_t gid)
+{
+	struct gr_learn_group_node *group;
+
+	group = (struct gr_learn_group_node *)gr_stat_alloc(sizeof(struct gr_learn_group_node));
+	group->rolename = gr_strdup(groupname);
+	group->gid = gid;
+
+	return group;
+}
+
+void insert_user(struct gr_learn_group_node **grouplist, char *username, char *groupname, uid_t uid, gid_t gid)
+{
+	struct gr_learn_group_node *group;
+	struct gr_learn_group_node *tmpgroup;
+	struct gr_learn_user_node *user;
+	struct gr_learn_user_node *tmpuser;
 	int multgroups = 0;
 
 	/* first check to see if the user exists in any group */
 
-	group = *grouplist;
-	while (group && *group) {
-		tmpuser = (*group)->users;
-		while (tmpuser && *tmpuser) {
+	for_each_list_entry(group, *grouplist) {
+		for_each_list_entry(user, group->users) {
 			/* found them, check if we've noted the group membership observed */
-			if ((*tmpuser)->uid == uid) {
+			if (user->uid == uid) {
 				/* user belongs to multiple groups, don't use them for reduction */
-				if ((*tmpuser)->group->gid != gid) {
-					(*tmpuser)->multgroups = 1;
+				if (user->group->gid != gid) {
+					user->multgroups = 1;
 					multgroups = 1;
 				} else /* this entry is a duplicate */
 					return;
 			}
-			tmpuser++;
 		}
-		group++;
 	}
 
-	group = find_insert_group(grouplist, gid);
+	group = find_insert_group(*grouplist, gid);
 
-	if (*group) {
-		num = count_users(*group);
+	if (group == NULL) {
+		group = create_new_group(groupname, gid);
+		establish_new_head(*grouplist, group, tmpgroup);
+	}
 
-		(*group)->users = (struct gr_learn_user_node **)gr_dyn_realloc((*group)->users, (num + 2) * sizeof(struct gr_learn_user_node *));
-		memset((*group)->users + num, 0, 2 * sizeof(struct gr_learn_user_node *));
+	user = create_new_user(username, uid, group, multgroups);
+	establish_new_head(group->users, user, tmpuser);
 
-		tmpuser = ((*group)->users + num);
-		*tmpuser = (struct gr_learn_user_node *)gr_stat_alloc(sizeof(struct gr_learn_user_node));
-		(*tmpuser)->rolename = gr_strdup(username);
-		(*tmpuser)->uid = uid;
-		(*tmpuser)->group = *group;
-		(*tmpuser)->multgroups = multgroups;
-	} else {
-		*group = (struct gr_learn_group_node *)gr_stat_alloc(sizeof(struct gr_learn_group_node));
-		(*group)->rolename = gr_strdup(groupname);
-		(*group)->gid = gid;
-		(*group)->users = (struct gr_learn_user_node **)gr_dyn_alloc(2 * sizeof(struct gr_learn_user_node *));
-		tmpuser = (*group)->users;
-		*tmpuser = (struct gr_learn_user_node *)gr_stat_alloc(sizeof(struct gr_learn_user_node));
-		(*tmpuser)->rolename = gr_strdup(username);
-		(*tmpuser)->uid = uid;
-		(*tmpuser)->group = *group;
-		(*tmpuser)->multgroups = multgroups;
+	return;
+}
+
+void free_entire_user_node_list(struct gr_learn_user_node **userlist)
+{
+	struct gr_learn_user_node *freeuser, *tmpuser;
+
+	for_each_list_entry(tmpuser, *userlist) {
+		freeuser = tmpuser;
+		tmpuser = tmpuser->next;
+		free(freeuser->rolename);
+		gr_stat_free(freeuser);
 	}
+		
+	*userlist = NULL;
 
 	return;
 }
 
-void reduce_roles(struct gr_learn_group_node ***grouplist)
+void unlink_and_free_user_node_entry(struct gr_learn_user_node *remove)
+{
+	if (remove->prev == NULL) {
+		remove->group->users = remove->next;
+		if (remove->next != NULL)
+			remove->next->prev = NULL;
+	} else {
+		remove->prev->next = remove->next;
+		if (remove->next != NULL)
+			remove->next->prev = remove->prev;
+	}
+	free(remove->rolename);
+	gr_stat_free(remove);
+		
+	return;
+}
+
+struct gr_learn_file_node * unlink_and_free_file_node_entry(struct gr_learn_file_node *remove, struct gr_learn_file_node **filelist)
+{
+	struct gr_learn_file_node *ret;
+
+	ret = remove->next;
+
+	if (remove->prev == NULL) {
+		*filelist = remove->next;
+		if (remove->next != NULL)
+			remove->next->prev = NULL;
+	} else {
+		remove->prev->next = remove->next;
+		if (remove->next != NULL)
+			remove->next->prev = remove->prev;
+	}
+	free(remove->filename);
+	gr_stat_free(remove);
+	
+	/* clear cache when removing a node */
+	cachednode = NULL;
+	cachedlen = 0;
+
+	return ret;
+}
+
+/* unlink a file node entry, return the next entry, and stuff the unlinked entry in the argument */
+struct gr_learn_file_node * unlink_file_node_entry(struct gr_learn_file_node *remove, struct gr_learn_file_node **filelist, struct gr_learn_file_node ** unlinked)
+{
+	struct gr_learn_file_node *ret;
+
+	ret = remove->next;
+
+	if (remove->prev == NULL) {
+		*filelist = remove->next;
+		if (remove->next != NULL)
+			remove->next->prev = NULL;
+	} else {
+		remove->prev->next = remove->next;
+		if (remove->next != NULL)
+			remove->next->prev = remove->prev;
+	}
+	
+	/* clear cache when removing a node */
+	cachednode = NULL;
+	cachedlen = 0;
+
+	*unlinked = remove;
+
+	return ret;
+}
+
+struct gr_learn_ip_node * unlink_and_free_ip_node_entry(struct gr_learn_ip_node *remove, struct gr_learn_ip_node **iplist)
+{
+	struct gr_learn_ip_node *ret;
+
+	ret = remove->next;
+
+	if (remove->prev == NULL) {
+		*iplist = remove->next;
+		if (remove->next != NULL)
+			remove->next->prev = NULL;
+	} else {
+		remove->prev->next = remove->next;
+		if (remove->next != NULL)
+			remove->next->prev = remove->prev;
+	}
+	gr_stat_free(remove);
+	
+	return ret;
+}
+
+struct gr_learn_group_node * unlink_and_free_group_node_entry(struct gr_learn_group_node *remove, struct gr_learn_group_node **grouplist)
+{
+	struct gr_learn_group_node *ret;
+
+	ret = remove->next;
+
+	if (remove->prev == NULL) {
+		*grouplist = remove->next;
+		if (remove->next != NULL)
+			remove->next->prev = NULL;
+	} else {
+		remove->prev->next = remove->next;
+		if (remove->next != NULL)
+			remove->next->prev = remove->prev;
+	}
+	free(remove->rolename);
+	gr_stat_free(remove);
+		
+	return ret;
+}
+
+void reduce_roles(struct gr_learn_group_node **grouplist)
 {
 	unsigned int thresh = 3;
-	struct gr_learn_group_node **group = *grouplist, **group2, **group3;
-	struct gr_learn_user_node **tmpuser, **tmpuser2;
+	struct gr_learn_group_node *group, *group2;
+	struct gr_learn_user_node *tmpuser, *tmpuser2;
 	unsigned long num;
+	int removed = 0;
 
-	while (group && *group) {
-		num = count_users_nomultgroups(*group);
-		if (num >= thresh) {
-			tmpuser = (*group)->users;
-			while(*tmpuser) {
-				free((*tmpuser)->rolename);
-				gr_stat_free(*tmpuser);
-				*tmpuser = NULL;
-				tmpuser++;
-			}
-			gr_dyn_free((*group)->users);
-			(*group)->users = NULL;
-		}
-		group++;
+	for_each_list_entry(group, *grouplist) {
+		num = count_users_nomultgroups(group);
+		if (num < thresh)
+			continue;
+		free_entire_user_node_list(&group->users);
 	}
 	
 	/* make sure only one role is created for each user */
-	group = *grouplist;
-	while (group && *group) {
-		tmpuser = (*group)->users;
-		while(tmpuser && *tmpuser) {
-			if ((*tmpuser)->multgroups) {
-				/* check to see if the user is in another group,
-				   and remove them from this group if so */
-				group2 = group + 1;
-				while (*group2) {
-					tmpuser2 = (*group2)->users;
-					while (tmpuser2 && *tmpuser2) {
-						if ((*tmpuser2)->uid == (*tmpuser)->uid) {
-							free((*tmpuser2)->rolename);
-							gr_stat_free(*tmpuser2);
-							while (*tmpuser2) {
-								*tmpuser2 = *(tmpuser2 + 1);
-								tmpuser2++;
-							}
-							/* we removed the only user in this group, so remove
-							   the group as well
-							*/
-							if (*((*group2)->users) == NULL) {
-								gr_dyn_free((*group2)->users);
-								free((*group2)->rolename);
-								gr_stat_free(*group2);
-								group3 = group2;
-								while (*group3) {
-									*group3 = *(group3 + 1);
-									group3++;
-								}
-								/* since we removed a group, the next group to check is the 
-								   one currently pointed to by group2 */
-								group2--;
-							}
-							goto done;
+	for_each_list_entry(group, *grouplist) {
+		for_each_list_entry(tmpuser, group->users) {
+			if (!tmpuser->multgroups)
+				continue;
+			/* check to see if the user is in another group,
+			   and remove them from this group if so */
+			for_each_removable_list_entry(group2, group->next) {
+				for_each_list_entry(tmpuser2, group2->users) {
+					if (tmpuser2->uid == tmpuser->uid) {
+						unlink_and_free_user_node_entry(tmpuser2);
+						/* we removed the only user in this group, so remove
+						   the group as well
+						*/
+						if (group2->users == NULL) {
+							group2 = unlink_and_free_group_node_entry(group2, grouplist);
+							removed = 1;
 						}
-						tmpuser2++;
+						goto done;
 					}
-done:
-					group2++;
 				}
+done:
+				for_each_removable_list_entry_end(group2);
 			}
-			tmpuser++;
 		}
-		group++;
 	}
 
 	return;
@@ -354,22 +472,15 @@ void traverse_file_tree(struct gr_learn_
 		   int (*act)(struct gr_learn_file_node *node, struct gr_learn_file_node *optarg, FILE *stream),
 		   struct gr_learn_file_node *optarg, FILE *stream)
 {
-	struct gr_learn_file_node **node;
+	struct gr_learn_file_node *node;
 
 	if (!base)
 		return;
 
 	act(base, optarg, stream);
 
-	node = base->leaves;
-
-	if (!node)
-		return;
-
-	while(*node) {
-		traverse_file_tree(*node, act, optarg, stream);
-		node++;
-	}
+	for_each_list_entry(node, base->leaves)
+		traverse_file_tree(node, act, optarg, stream);
 
 	return;
 }
@@ -377,12 +488,12 @@ void traverse_file_tree(struct gr_learn_
 struct gr_learn_file_node *match_file_node(struct gr_learn_file_node *base,
 					const char *filename)
 {
-	struct gr_learn_file_node **node, *ret;
+	struct gr_learn_file_node *node, *ret;
 	unsigned int baselen, filelen;
 
 	filelen = strlen(filename);
 
-	if (!base)
+	if (base == NULL)
 		return base;
 
 	baselen = strlen(base->filename);
@@ -393,46 +504,31 @@ struct gr_learn_file_node *match_file_no
 	    strncmp(base->filename, filename, baselen))
 		return NULL;
 
-	node = base->leaves;
-
-	if (!node)
-		return base;
-
-	while(*node) {
-		if ((ret = match_file_node(*node, filename)))
+	for_each_list_entry(node, base->leaves) {
+		if ((ret = match_file_node(node, filename)))
 			return ret;
-		node++;
 	}
 	
 	return base;
 }
 
-unsigned long count_nodes(struct gr_learn_file_node **node)
+unsigned long count_nodes(struct gr_learn_file_node *node)
 {
 	unsigned long ret = 0;
 
-	if (!node)
-		return 0;
-
-	while(*node) {
+	for_each_list_entry(node, node)
 		ret++;
-		node++;
-	}
 
 	return ret;
 }
 
-unsigned long count_leaf_nodes(struct gr_learn_file_node **node)
+unsigned long count_leaf_nodes(struct gr_learn_file_node *node)
 {
 	unsigned long ret = 0;
 
-	if (!node)
-		return 0;
-
-	while(*node) {
-		if (!((*node)->leaves))
+	for_each_list_entry(node, node) {
+		if (node->leaves == NULL)
 			ret++;
-		node++;
 	}
 
 	return ret;
@@ -441,16 +537,11 @@ unsigned long count_leaf_nodes(struct gr
 unsigned long count_total_leaves(struct gr_learn_file_node *node)
 {
 	unsigned long leaves = 0;
-	struct gr_learn_file_node **tmp;
-
-	tmp = node->leaves;
-	if (!tmp)
-		return 0;
+	struct gr_learn_file_node *tmp;
 
-	while(*tmp) {
+	for_each_list_entry(tmp, node->leaves) {
 		leaves++;
-		leaves += count_total_leaves(*tmp);
-		tmp++;
+		leaves += count_total_leaves(tmp);
 	}
 
 	return leaves;
@@ -459,18 +550,16 @@ unsigned long count_total_leaves(struct 
 unsigned long count_max_depth(struct gr_learn_file_node *node)
 {
 	unsigned long max = 0, tmpmax = 0;
-	struct gr_learn_file_node **tmp;
+	struct gr_learn_file_node *tmp;
 
-	tmp = node->leaves;
-	if (!tmp)
+	if (node->leaves == NULL)
 		return 0;
 
 	max++;
-	while(*tmp) {
-		tmpmax = count_max_depth(*tmp);
+	for_each_list_entry(tmp, node->leaves) {
+		tmpmax = count_max_depth(tmp);
 		if ((max + tmpmax) > max)
 			max = tmpmax + max;
-		tmp++;
 	}
 
 	return max;
@@ -481,112 +570,88 @@ unsigned long count_nested_depth(struct 
 	unsigned long depth = 0;
 	struct gr_learn_file_node *tmp;
 
-	tmp = node->parent;
-	if (!tmp)
-		return 0;
-
-	while(tmp) {
+	for_each_parent_entry(tmp, node->parent)
 		depth++;
-		tmp = tmp->parent;
-	}
 
 	return depth;
 }	
 
 int reduce_all_children(struct gr_learn_file_node *node)
 {
-	unsigned long num, not_leaf = 0;
-	unsigned long i, j;
-	struct gr_learn_file_node **tmp;
-	
-	tmp = node->leaves;
-	num = 0;
-	while (*tmp) {
-		if (!((*tmp)->leaves)) {
-			node->mode |= (*tmp)->mode;
-			if (node->subject && (*tmp)->subject) {
-				/* merge capabilities */
-				node->subject->cap_raise = cap_combine(node->subject->cap_raise, 
-								       (*tmp)->subject->cap_raise);
-				/* merge resources */
-				node->subject->resmask |= (*tmp)->subject->resmask;
-				for (i = 0; i < GR_NLIMITS; i++) {
-					if ((*tmp)->subject->res[i].rlim_cur > node->subject->res[i].rlim_cur)
-						node->subject->res[i].rlim_cur = (*tmp)->subject->res[i].rlim_cur;
-					if ((*tmp)->subject->res[i].rlim_max > node->subject->res[i].rlim_max)
-						node->subject->res[i].rlim_max = (*tmp)->subject->res[i].rlim_max;
-				}
-				/* merge socket families */
-				for (i = 0; i < SIZE(node->subject->sock_families); i++)
-					node->subject->sock_families[i] |= (*tmp)->subject->sock_families[i];
-			}
-		} else
-			not_leaf++;
-		tmp++;
-		num++;
-	}
+	unsigned long not_leaf = 0;
+	unsigned long i;
+	struct gr_learn_file_node *tmp;
+	int removed = 0;
 
-	tmp = node->leaves;
-	for (i = 0; i < num; i++) {
-		if (*(tmp + i) && !(*(tmp + i))->leaves) {
-			cachednode = NULL;
-			cachedlen = 0;
-			free((*(tmp + i))->filename);
-			gr_stat_free(*(tmp + i));
-			j = i;
-			while (*(tmp + j + 1)) {
-				*(tmp + j) = *(tmp + j + 1);
-				j++;
-			}
-			*(tmp + j) = NULL;			
+	for_each_list_entry(tmp, node->leaves) {
+		if (tmp->leaves != NULL) {
+			not_leaf++;
+			continue;
 		}
+		node->mode |= tmp->mode;
+		if (node->subject == NULL || tmp->subject == NULL)
+			continue;
+		/* merge capabilities */
+		node->subject->cap_raise = cap_combine(node->subject->cap_raise, tmp->subject->cap_raise);
+		/* merge resources */
+		node->subject->resmask |= tmp->subject->resmask;
+		for (i = 0; i < GR_NLIMITS; i++) {
+			if (tmp->subject->res[i].rlim_cur > node->subject->res[i].rlim_cur)
+				node->subject->res[i].rlim_cur = tmp->subject->res[i].rlim_cur;
+			if (tmp->subject->res[i].rlim_max > node->subject->res[i].rlim_max)
+				node->subject->res[i].rlim_max = tmp->subject->res[i].rlim_max;
+		}
+		/* merge socket families */
+		for (i = 0; i < SIZE(node->subject->sock_families); i++)
+			node->subject->sock_families[i] |= tmp->subject->sock_families[i];
+	}
+
+	for_each_removable_list_entry(tmp, node->leaves) {
+		if (tmp->leaves != NULL)
+			goto next_entry;
+		tmp = unlink_and_free_file_node_entry(tmp, &node->leaves);
+		removed = 1;
+next_entry:
+		for_each_removable_list_entry_end(tmp);
 	}
 
-	if (!not_leaf) {
-		gr_dyn_free(node->leaves);
+	if (!not_leaf)
 		node->leaves = NULL;
-		return 0;
-	}
 
 	return 0;
 }
 
 int reduce_all_leaves(struct gr_learn_file_node *node)
 {
-	struct gr_learn_file_node **tmp;
+	struct gr_learn_file_node *tmp;
 	unsigned int i;
+	int removed = 0;
 
-	tmp = node->leaves;
-	if (!tmp)
-		return 0;
-	while (*tmp) {
-		reduce_all_leaves(*tmp);
-		node->mode |= (*tmp)->mode;
-		if (node->subject && (*tmp)->subject) {
-			/* merge capabilities */
-			node->subject->cap_raise = cap_combine(node->subject->cap_raise,
-							       (*tmp)->subject->cap_raise);
-			/* merge resources */
-			node->subject->resmask |= (*tmp)->subject->resmask;
-			for (i = 0; i < GR_NLIMITS; i++) {
-				if ((*tmp)->subject->res[i].rlim_cur > node->subject->res[i].rlim_cur)
-					node->subject->res[i].rlim_cur = (*tmp)->subject->res[i].rlim_cur;
-				if ((*tmp)->subject->res[i].rlim_max > node->subject->res[i].rlim_max)
-					node->subject->res[i].rlim_max = (*tmp)->subject->res[i].rlim_max;
-			}
-			/* merge socket families */
-			for (i = 0; i < SIZE(node->subject->sock_families); i++)
-				node->subject->sock_families[i] |= (*tmp)->subject->sock_families[i];
-		}
-		cachednode = NULL;
-		cachedlen = 0;
-		free((*tmp)->filename);
-		gr_stat_free(*tmp);
-		*tmp = NULL;
-		tmp++;
+	for_each_removable_list_entry(tmp, node->leaves) {
+		reduce_all_leaves(tmp);
+		node->mode |= tmp->mode;
+		if (node->subject == NULL || tmp->subject == NULL)
+			goto remove_node;
+		/* merge capabilities */
+		node->subject->cap_raise = cap_combine(node->subject->cap_raise,
+						       tmp->subject->cap_raise);
+		/* merge resources */
+		node->subject->resmask |= tmp->subject->resmask;
+		for (i = 0; i < GR_NLIMITS; i++) {
+			if (tmp->subject->res[i].rlim_cur > node->subject->res[i].rlim_cur)
+				node->subject->res[i].rlim_cur = tmp->subject->res[i].rlim_cur;
+			if (tmp->subject->res[i].rlim_max > node->subject->res[i].rlim_max)
+				node->subject->res[i].rlim_max = tmp->subject->res[i].rlim_max;
+		}
+		/* merge socket families */
+		for (i = 0; i < SIZE(node->subject->sock_families); i++)
+			node->subject->sock_families[i] |= tmp->subject->sock_families[i];
+remove_node:
+		tmp = unlink_and_free_file_node_entry(tmp, &node->leaves);
+		removed = 1;
+		for_each_removable_list_entry_end(tmp);
 	}
 
-	gr_dyn_free(node->leaves);
 	node->leaves = NULL;
 
 	return 0;
@@ -594,7 +659,7 @@ int reduce_all_leaves(struct gr_learn_fi
 
 void greatest_occurring_modes(struct gr_learn_file_node *node, u_int32_t *modeary)
 {
-	struct gr_learn_file_node **tmp;
+	struct gr_learn_file_node *tmp;
 	u_int32_t modes[12] = { GR_FIND,
 			    GR_FIND | GR_READ,
 			    GR_FIND | GR_READ | GR_WRITE,
@@ -614,9 +679,9 @@ void greatest_occurring_modes(struct gr_
 
 	tmp = node->leaves;
 
-	while (*tmp) {
+	while (tmp) {
 		for (i = 0; i < 12; i++) {
-			if ((*tmp)->mode == modes[i])
+			if (tmp->mode == modes[i])
 				counts[i]++;
 		}
 
@@ -640,14 +705,13 @@ void greatest_occurring_modes(struct gr_
 
 int reduce_children_mode(struct gr_learn_file_node *node)
 {
-	struct gr_learn_file_node **tmp;
-	struct gr_learn_file_node **tmp2;
+	struct gr_learn_file_node *tmp;
 	u_int32_t modes[2];
 	int ret = 0;
 	int tmpdir = 0;
+	int removed = 0;
 
-	tmp = node->leaves;
-	if (!tmp)
+	if (node->leaves == NULL)
 		return 0;
 	
 	greatest_occurring_modes(node, (u_int32_t *)&modes);
@@ -658,23 +722,15 @@ int reduce_children_mode(struct gr_learn
 	if (node->mode == (GR_FIND | GR_READ | GR_WRITE | GR_CREATE | GR_DELETE))
 		tmpdir = 1;
 
-	while (*tmp) {
-		if (((tmpdir && !((*tmp)->mode & GR_EXEC)) ||
-		     ((*tmp)->mode == modes[0] || (*tmp)->mode == modes[1]))
-		    && !(*tmp)->leaves) {
-			tmp2 = tmp;
-			cachednode = NULL;
-			cachedlen = 0;
+	for_each_removable_list_entry(tmp, node->leaves) {
+		if (((tmpdir && !(tmp->mode & GR_EXEC)) ||
+		     (tmp->mode == modes[0] || tmp->mode == modes[1]))
+		    && tmp->leaves == NULL) {
 			ret++;
-			free((*tmp)->filename);
-			gr_stat_free(*tmp);
-			while (*(tmp2 + 1)) {
-				*(tmp2) = *(tmp2 + 1);
-				tmp2++;
-			}
-			*tmp2 = NULL;
-		} else
-			tmp++;
+			tmp = unlink_and_free_file_node_entry(tmp, &node->leaves);
+			removed = 1;
+		}
+		for_each_removable_list_entry_end(tmp);
 	}
 
 	return ret;
@@ -682,19 +738,13 @@ int reduce_children_mode(struct gr_learn
 
 int analyze_node_read_permissions(struct gr_learn_file_node *node)
 {
-	struct gr_learn_file_node **tmp;
-
-	if (!node->leaves)
-		return 1;
-
-	tmp = node->leaves;
+	struct gr_learn_file_node *tmp;
 
-	while (*tmp) {
-		if (((*tmp)->mode & GR_WRITE) && !((*tmp)->mode & GR_READ))
+	for_each_list_entry(tmp, node->leaves) {
+		if ((tmp->mode & GR_WRITE) && !(tmp->mode & GR_READ))
 			return 0;
-		if (!analyze_node_read_permissions(*tmp))
+		if (!analyze_node_read_permissions(tmp))
 			return 0;
-		tmp++;
 	}
 
 	return 1;
@@ -702,19 +752,13 @@ int analyze_node_read_permissions(struct
 
 int analyze_node_write_permissions(struct gr_learn_file_node *node)
 {
-	struct gr_learn_file_node **tmp;
-
-	if (!node->leaves)
-		return 1;
-
-	tmp = node->leaves;
+	struct gr_learn_file_node *tmp;
 
-	while (*tmp) {
-		if (!((*tmp)->mode & GR_WRITE) && ((*tmp)->mode & GR_READ))
+	for_each_list_entry(tmp, node->leaves) {
+		if (!(tmp->mode & GR_WRITE) && (tmp->mode & GR_READ))
 			return 0;
-		if (!analyze_node_write_permissions(*tmp))
+		if (!analyze_node_write_permissions(tmp))
 			return 0;
-		tmp++;
 	}
 
 	return 1;
@@ -722,21 +766,13 @@ int analyze_node_write_permissions(struc
 
 int analyze_child_read_permissions(struct gr_learn_file_node *node)
 {
-	struct gr_learn_file_node **tmp;
-
-	if (!node->leaves)
-		return 1;
-
-	tmp = node->leaves;
+	struct gr_learn_file_node *tmp;
 
-	while (*tmp) {
-		if ((*tmp)->leaves) {
-			tmp++;
+	for_each_list_entry(tmp, node->leaves) {
+		if (tmp->leaves)
 			continue;
-		}
-		if (((*tmp)->mode & GR_WRITE) && !((*tmp)->mode & GR_READ))
+		if ((tmp->mode & GR_WRITE) && !(tmp->mode & GR_READ))
 			return 0;
-		tmp++;
 	}
 
 	return 1;
@@ -744,21 +780,13 @@ int analyze_child_read_permissions(struc
 
 int analyze_child_write_permissions(struct gr_learn_file_node *node)
 {
-	struct gr_learn_file_node **tmp;
-
-	if (!node->leaves)
-		return 1;
-
-	tmp = node->leaves;
+	struct gr_learn_file_node *tmp;
 
-	while (*tmp) {
-		if ((*tmp)->leaves) {
-			tmp++;
+	for_each_list_entry(tmp, node->leaves) {
+		if (tmp->leaves)
 			continue;
-		}
-		if (!((*tmp)->mode & GR_WRITE) && ((*tmp)->mode & GR_READ))
+		if (!(tmp->mode & GR_WRITE) && (tmp->mode & GR_READ))
 			return 0;
-		tmp++;
 	}
 
 	return 1;
@@ -776,7 +804,8 @@ int *analyze_node_reduction(struct gr_le
 	int child_reduced = 0;
 	char **tmp;
 
-	if (!node->leaves)
+	/* revert all the changes i made to this function */
+	if (node->leaves == NULL)
 		return NULL;
 
 	tmp = dont_reduce_dirs;
@@ -887,34 +916,21 @@ void second_stage_reduce_tree(struct gr_
 int third_reduce_node(struct gr_learn_file_node *node,
 		       struct gr_learn_file_node *unused1, FILE *unused)
 {
-	struct gr_learn_file_node **tmp, **tmp2;
-
-	tmp = node->leaves;
-
-	if (!tmp)
-		return 0;
+	struct gr_learn_file_node *tmp;
+	int removed = 0;
 
-	while (*tmp) {
-		if ((*tmp)->leaves) {
-			tmp++;
-			continue;
-		}
-		if ((*tmp)->mode == node->mode ||
+	for_each_removable_list_entry(tmp, node->leaves) {
+		if (tmp->leaves)
+			goto next_entry;
+		if (tmp->mode == node->mode ||
 		    (((node->mode & (GR_WRITE | GR_CREATE)) == (GR_WRITE | GR_CREATE)) &&
-		    ((*tmp)->mode & GR_WRITE))) {
-			node->mode |= (*tmp)->mode;
-			tmp2 = tmp;
-			cachednode = NULL;
-			cachedlen = 0;
-			free((*tmp)->filename);
-			gr_stat_free(*tmp);
-			while(*(tmp2 + 1)) {
-				*tmp2 = *(tmp2 + 1);
-				tmp2++;
-			}
-			*tmp2 = NULL;
-		} else
-			tmp++;
+		    (tmp->mode & GR_WRITE))) {
+			node->mode |= tmp->mode;
+			tmp = unlink_and_free_file_node_entry(tmp, &node->leaves);
+			removed = 1;
+		}
+next_entry:
+		for_each_removable_list_entry_end(tmp);
 	}
 
 	return 0;
@@ -926,100 +942,92 @@ void third_stage_reduce_tree(struct gr_l
 	return traverse_file_tree(base, &third_reduce_node, NULL, NULL);
 }
 
-struct gr_learn_file_node **do_find_insert_file(struct gr_learn_file_node **base,
-					struct gr_learn_file_node *insert, unsigned int filelen,
+struct gr_learn_file_node *do_find_insert_file(struct gr_learn_file_node **base,
+					char *filename, unsigned int filelen,
 					struct gr_learn_file_node **parent)
 {
-	struct gr_learn_file_node **node, **tmpnode, **ret;
+	struct gr_learn_file_node *node, *tmpnode, *ret;
 	unsigned int baselen;
-	unsigned long num_leaves;
 
 	if (!*base) {
 		*parent = *base;
-		return base;
+		*base = (struct gr_learn_file_node *)gr_stat_alloc(sizeof(struct gr_learn_file_node));
+		return *base;
 	}
 
 	baselen = strlen((*base)->filename);
-	if ((filelen == baselen) && !strcmp((*base)->filename, insert->filename))
-		return base;
+	if ((filelen == baselen) && !strcmp((*base)->filename, filename))
+		return *base;
 
 	node = (*base)->leaves;
 
-	if (!node && (baselen < filelen) && (baselen == 1 || insert->filename[baselen] == '/') &&
-	    !strncmp((*base)->filename, insert->filename, baselen)) {
+	/* if there are no leaves for this base and the directory for the base matches
+	   the file we're inserting, add the first leaf
+	*/
+	if (!node && (baselen < filelen) && (baselen == 1 || filename[baselen] == '/') &&
+	    !strncmp((*base)->filename, filename, baselen)) {
 		*parent = *base;
-		(*base)->leaves = node = (struct gr_learn_file_node **)gr_dyn_alloc(2 * sizeof(struct gr_learn_file_node *));
-		cachednode = base;
+		(*base)->leaves = node = (struct gr_learn_file_node *)gr_stat_alloc(sizeof(struct gr_learn_file_node));
+		cachednode = *base;
 		cachedlen = baselen;
 		return node;
-	} else if (!node)
+	} else if (!node) {
 		return NULL;
+	}
 
-	tmpnode = node;
-
-	while(*tmpnode) {
-		ret = do_find_insert_file(tmpnode, insert, filelen, parent);
+	for_each_list_entry(tmpnode, node) {
+		ret = do_find_insert_file(&tmpnode, filename, filelen, parent);
 		if (ret)
 			return ret;
-		tmpnode++;
 	}
 	
-	if ((baselen >= filelen) || (baselen != 1 && insert->filename[baselen] != '/') ||
-	    strncmp((*base)->filename, insert->filename, baselen)) 
+	if ((baselen >= filelen) || (baselen != 1 && filename[baselen] != '/') ||
+	    strncmp((*base)->filename, filename, baselen)) {
 		return NULL;
+	}
 
-	*parent = *base;
-	num_leaves = count_nodes(node);
-	(*base)->leaves = node = (struct gr_learn_file_node **)gr_dyn_realloc((*base)->leaves, (num_leaves + 2) * sizeof(struct gr_learn_file_node *));
-	cachednode = base;
+	cachednode = *base;
 	cachedlen = baselen;
-	memset(node + num_leaves, 0, 2 * sizeof(struct gr_learn_file_node *));
-	return (node + num_leaves);
+	*parent = *base;
+	ret = (struct gr_learn_file_node *)gr_stat_alloc(sizeof(struct gr_learn_file_node));
+
+	establish_new_head((*base)->leaves, ret, tmpnode);
+
+	return ret;
 }
 
-struct gr_learn_file_node **find_insert_file(struct gr_learn_file_node **base,
-					struct gr_learn_file_node *insert, unsigned int filelen,
+struct gr_learn_file_node *find_insert_file(struct gr_learn_file_node **base,
+					char *filename, unsigned int filelen,
 					struct gr_learn_file_node **parent)
 {
-	if (cachednode && *cachednode && (cachedlen < filelen) && !strncmp((*cachednode)->filename, insert->filename, cachedlen)
-	    && insert->filename[cachedlen] == '/') {
-		return do_find_insert_file(cachednode, insert, filelen, parent);
-	} else if (cachednode && *cachednode && (cachedlen >= filelen)) {
+	if (cachednode && (cachedlen < filelen) && !strncmp(cachednode->filename, filename, cachedlen)
+	    && filename[cachedlen] == '/') {
+		return do_find_insert_file(&cachednode, filename, filelen, parent);
+	} else if (cachednode && (cachedlen >= filelen)) {
 		cachednode = NULL;
 		cachedlen = 0;
 	}
 
-	return do_find_insert_file(base, insert, filelen, parent);
+	return do_find_insert_file(base, filename, filelen, parent);
 }
 
 
 
 void do_insert_file(struct gr_learn_file_node **base, char *filename, u_int32_t mode, u_int8_t subj)
 {
-	struct gr_learn_file_node **node;
+	struct gr_learn_file_node *node;
 	struct gr_learn_file_node *parent = NULL;
-	struct gr_learn_file_node *insert;
 
-	insert = (struct gr_learn_file_node *)gr_stat_alloc(sizeof(struct gr_learn_file_node));
+	node = find_insert_file(base, filename, strlen(filename), &parent);
 
-	insert->filename = gr_strdup(filename);
-	insert->mode = mode;
+	node->mode |= mode;
+	node->dont_display = 0;
+	node->parent = parent;
+	if (node->filename == NULL)
+		node->filename = gr_strdup(filename);
 
 	if (subj)
-		insert_file(&(insert->object_list), "/", 0, 0);		
-
-	node = find_insert_file(base, insert, strlen(filename), &parent);
-
-	if (*node) {
-		(*node)->mode |= mode;
-		(*node)->dont_display = 0;
-		free(insert->filename);
-		gr_stat_free(insert);
-		return;
-	} else {
-		*node = insert;
-		(*node)->parent = parent;
-	}
+		insert_file(&(node->object_list), "/", 0, 0);		
 
 	return;
 }
@@ -1045,63 +1053,44 @@ int first_reduce_node(struct gr_learn_fi
 		       struct gr_learn_file_node *unused1, FILE *unused)
 {
 	unsigned long thresh = 5;	
-	unsigned long cnt = 0;
 	unsigned long num = count_nodes(node->leaves);
-	struct gr_learn_file_node **tmp, **tmp2, **tmp3, *tmp4;
+	struct gr_learn_file_node *tmp, *tmp2;
 	struct gr_learn_file_node *parent = NULL;
 	char *p, *p2;
 	unsigned int node_len = strlen(node->filename);
+	int removed = 0;
 
 	if (num < thresh)
 		return 0;
 
-	tmp = node->leaves;
-
-	while (*tmp) {
-		p = gr_strdup((*tmp)->filename);
+	for_each_list_entry(tmp, node->leaves) {
 		if (node_len == 1)
-			p2 = strchr(p + 1, '/');
+			p2 = strchr(tmp->filename + 1, '/');
 		else
-			p2 = strchr(p + node_len + 1, '/');
+			p2 = strchr(tmp->filename + node_len + 1, '/');
 
-		if (!p2) {
-			tmp++;
-			cnt++;
-			free(p);
+		if (p2 == NULL)
 			continue;
-		}
 
-		*p2 = '\0';
+		p = gr_strdup(tmp->filename);
+		*(p + (p2 - tmp->filename)) = '\0';
 		cachednode = NULL;
 		cachedlen = 0;
 		insert_file(&node, p, 0, 0);
 		free(p);
-		cnt++;
-		/* node->leaves might have been modified during insert */
-		tmp = node->leaves + cnt;
 	}
 
-	tmp = node->leaves;
 
-	while (*tmp && num) {
+	/* we're pulling out each leaf in this node and re-inserting it
+	*/
+	for_each_removable_list_entry(tmp, node->leaves) {
 		parent = NULL;
-		tmp4 = *tmp;
-		tmp2 = tmp;
-		while(*(tmp2 + 1)) {
-			*tmp2 = *(tmp2 + 1);
-			tmp2++;
-		}
-		*tmp2 = NULL;
-		/* cache not needed here */
-		cachednode = NULL;
-		cachedlen = 0;
-		tmp3 = find_insert_file(&node, tmp4, strlen(tmp4->filename), &parent);
-		tmp = node->leaves;
-		if (!(*tmp3)) {
-			*tmp3 = tmp4;
-			(*tmp3)->parent = parent;
-		}
-		num--;
+		tmp = unlink_file_node_entry(tmp, &node->leaves, &tmp2);
+		removed = 1;
+		do_insert_file(&node, tmp2->filename, tmp2->mode, 0);
+		free(tmp2->filename);
+		gr_stat_free(tmp2);
+		for_each_removable_list_entry_end(tmp);
 	}
 
 	return 0;
@@ -1176,8 +1165,10 @@ int display_leaf(struct gr_learn_file_no
 			fprintf(stream, "\n\n");
 		}
 
-		if (object)
+		if (object) {
+			sort_file_node_list(&object->leaves);
 			display_tree(object, stream);
+		}
 		if (!node->subject) {
 			fprintf(stream, "\t-CAP_ALL\n");
 			goto show_ips;
@@ -1286,19 +1277,15 @@ void traverse_ip_tree(struct gr_learn_ip
 		   int (*act)(struct gr_learn_ip_node *node, struct gr_learn_ip_node **optarg, u_int8_t contype, FILE *stream),
 		   u_int8_t contype, FILE *stream)
 {
-	struct gr_learn_ip_node **node;
+	struct gr_learn_ip_node *node;
 
 	if (!base)
 		return;
 
 	act(base, optarg, contype, stream);
 	
-	node = base->leaves;
-
-	while(node && *node) {
-		traverse_ip_tree(*node, optarg, act, contype, stream);
-		node++;
-	}
+	for_each_list_entry(node, base->leaves)
+		traverse_ip_tree(node, optarg, act, contype, stream);
 
 	return;
 }
@@ -1307,7 +1294,7 @@ int count_ip_depth(struct gr_learn_ip_no
 {
 	int depth = 0;
 
-	while ((node = node->parent))
+	for_each_parent_entry(node, node->parent)
 		depth++;
 
 	return depth;
@@ -1316,16 +1303,13 @@ int count_ip_depth(struct gr_learn_ip_no
 unsigned long count_total_ips(struct gr_learn_ip_node *node)
 {
 	unsigned long ips = 0;
-	struct gr_learn_ip_node **tmp;
+	struct gr_learn_ip_node *tmp;
 
-	tmp = node->leaves;
-	if (!tmp)
+	if (node->leaves == NULL)
 		return 1;
 
-	while(*tmp) {
-		ips += count_total_ips(*tmp);
-		tmp++;
-	}
+	for_each_list_entry(tmp, node->leaves)
+		ips += count_total_ips(tmp);
 
 	return ips;
 }
@@ -1476,17 +1460,13 @@ unsigned long count_ports(u_int16_t **po
 	return ret;
 }		
 		
-unsigned long count_ips(struct gr_learn_ip_node **ips)
+unsigned long count_ips(struct gr_learn_ip_node *ips)
 {
 	unsigned long ret = 0;
+	struct gr_learn_ip_node *tmp;
 
-	if (!ips)
-		return ret;
-
-	while (*ips) {
-		ips++;
+	for_each_list_entry(tmp, ips)
 		ret++;
-	}
 
 	return ret;
 }
@@ -1554,8 +1534,9 @@ void remove_port(struct gr_learn_ip_node
 void do_reduce_ip_node(struct gr_learn_ip_node *node, struct gr_learn_ip_node *actor)
 {
 	u_int16_t **tmpport = node->ports;
-	struct gr_learn_ip_node **tmpip;
+	struct gr_learn_ip_node *tmpip;
 	int i;
+	int removed = 0;
 
 	while (tmpport && *tmpport) {
 		insert_port(actor, **tmpport);
@@ -1572,20 +1553,13 @@ void do_reduce_ip_node(struct gr_learn_i
 		actor->ip_proto[i] |= node->ip_proto[i];
 	actor->ip_type |= node->ip_type;
 
-	if (!node->leaves) {
-		return;
-	}
-
-	tmpip = node->leaves;
-
-	while(*tmpip) {
-		do_reduce_ip_node(*tmpip, actor);
-		gr_stat_free(*tmpip);
-		*tmpip = NULL;
-		tmpip++;
+	for_each_removable_list_entry(tmpip, node->leaves) {
+		do_reduce_ip_node(tmpip, actor);
+		tmpip = unlink_and_free_ip_node_entry(tmpip, &node->leaves);
+		removed = 1;
+		for_each_removable_list_entry_end(tmpip);
 	}
 
-	gr_dyn_free(node->leaves);
 	node->leaves = NULL;
 
 	return;
@@ -1670,28 +1644,16 @@ u_int8_t extract_ip_field(u_int32_t ip, 
 
 	memcpy(ip_node, &ip, sizeof(ip));
 
-	switch(depth) {
-	case 3:
-		return ip_node[3];
-	case 2:
-		return ip_node[2];
-	case 1:
-		return ip_node[1];
-	case 0:
-		return ip_node[0];
-	default:
+	if (depth > 3)
 		return 0;
-	}
 
+	return ip_node[depth];
 }
 
-struct gr_learn_ip_node ** find_insert_ip(struct gr_learn_ip_node **base, u_int32_t ip,
-					  struct gr_learn_ip_node **parent)
+struct gr_learn_ip_node * find_insert_ip(struct gr_learn_ip_node **base, u_int32_t ip)
 {
-	struct gr_learn_ip_node *** node = NULL;
-	struct gr_learn_ip_node **tmpip = NULL;
+	struct gr_learn_ip_node *node, *tmpip, *newip;
 	int depth = 0;
-	unsigned long num_ips = 0;
 	int match = 0;
 
 	if (!(*base)) {
@@ -1700,68 +1662,49 @@ struct gr_learn_ip_node ** find_insert_i
 	}
 
 	depth = count_ip_depth(*base);
-	node = &((*base)->leaves);
+	node = (*base)->leaves;
 
-	tmpip = *node;
-	while (tmpip && *tmpip) {
-		if ((*tmpip)->ip_node == extract_ip_field(ip, depth)) {
+	for_each_list_entry(tmpip, node) {
+		if (tmpip->ip_node == extract_ip_field(ip, depth)) {
 			match = 1;
 			break;
 		}
-		tmpip++;
 	}
 
 	if (match && depth < 3) {
-		return find_insert_ip(tmpip, ip, parent);
-	} else if (match)
+		/* partial match, try to match at the next depth */
+		return find_insert_ip(&tmpip, ip);
+	} else if (match) {
+		/* complete match, return it */
 		return tmpip;
-	else {
-		num_ips = count_ips(*node);
-		(*node) = (struct gr_learn_ip_node **)gr_dyn_realloc((*node), (2 + num_ips) * sizeof(struct gr_learn_ip_node *));
-		memset((*node) + num_ips, 0, 2 * sizeof(struct gr_learn_ip_node *));
-
-		if (depth == 3) {
-			*parent = *base;
-			return ((*node) + num_ips);
-		} else {
-			(*((*node) + num_ips)) = (struct gr_learn_ip_node *)gr_stat_alloc(sizeof(struct gr_learn_ip_node));
-			(*((*node) + num_ips))->ip_node = extract_ip_field(ip, depth);
-			(*((*node) + num_ips))->parent = *base;
-			return find_insert_ip(((*node) + num_ips), ip, parent);
-		}
+	} else {
+		/* no match, need to allocate a new node */
+		newip = (struct gr_learn_ip_node *)gr_stat_alloc(sizeof(struct gr_learn_ip_node));
+		newip->parent = *base;
+		newip->ip_node = extract_ip_field(ip, depth);
+
+		establish_new_head((*base)->leaves, newip, tmpip);
+
+		if (depth < 3)
+			return find_insert_ip(&newip, ip);
+		else
+			return newip;
 	}
 }
 
 void insert_ip(struct gr_learn_ip_node **base, u_int32_t ip, u_int16_t port, u_int8_t proto,
 		u_int8_t socktype)
 {
-	struct gr_learn_ip_node **node;
-	struct gr_learn_ip_node *parent = NULL;
-	struct gr_learn_ip_node *insert;
-	u_int8_t ip_node[4];
+	struct gr_learn_ip_node *node;
 
-	insert = (struct gr_learn_ip_node *)gr_stat_alloc(sizeof(struct gr_learn_ip_node));
+	node = find_insert_ip(base, ip);
 
-	insert_port(insert, port);
-	insert->ip_proto[proto / 32] = (1 << (proto % 32));
-	insert->ip_type |= (1 << socktype);
-	memcpy(&ip_node, &ip, sizeof(ip));
-	insert->ip_node = ip_node[3];
-
-	node = find_insert_ip(base, ip, &parent);
-
-	if (*node) {
-		(*node)->ip_proto[proto / 32] |= (1 << (proto % 32));
-		(*node)->ip_type |= (1 << socktype);
-		insert_port(*node, port);
-		gr_stat_free(*(insert->ports));
-		gr_dyn_free(insert->ports);
-		gr_stat_free(insert);
-		return;
-	} else {
-		*node = insert;
-		(*node)->parent = parent;
-	}
+	/* the IP has already been added to the tree,
+	   so just OR in the information we've filled out in the
+	   insert structure */
+	node->ip_proto[proto / 32] |= (1 << (proto % 32));
+	node->ip_type |= (1 << socktype);
+	insert_port(node, port);
 
 	return;
 }
@@ -1806,47 +1749,40 @@ struct gr_learn_file_tmp_node *conv_file
 }
 
 struct gr_learn_role_entry *
-insert_learn_role(struct gr_learn_role_entry ***role_list, char *rolename, u_int16_t rolemode)
+insert_learn_role(struct gr_learn_role_entry **role_list, char *rolename, u_int16_t rolemode)
 {
-	unsigned long num = 0;
-	struct gr_learn_role_entry **tmp;
-
-	if ((*role_list) == NULL)
-		*role_list = (struct gr_learn_role_entry **)gr_dyn_alloc(2 * sizeof(struct gr_learn_role_entry *));
-
-	tmp = *role_list;
-	while(*tmp) {
-		if (!strcmp((*tmp)->rolename, rolename)) {
-			(*tmp)->rolemode |= rolemode;
-			return *tmp;
+	struct gr_learn_role_entry *tmp;
+	struct gr_learn_role_entry *newrole;
+	
+	for_each_list_entry(tmp, *role_list) {
+		if (!strcmp(tmp->rolename, rolename)) {
+			tmp->rolemode |= rolemode;
+			return tmp;
 		}
-		num++;
-		tmp++;
 	}
-	*role_list = (struct gr_learn_role_entry **)gr_dyn_realloc(*role_list, (2 + num) * sizeof(struct gr_learn_role_entry *));
-	memset(*role_list + num, 0, 2 * sizeof(struct gr_learn_role_entry *));
 
-	(*((*role_list) + num)) = (struct gr_learn_role_entry *)gr_stat_alloc(sizeof(struct gr_learn_role_entry));
-	(*((*role_list) + num))->rolename = gr_strdup(rolename);
-	(*((*role_list) + num))->rolemode = rolemode;
+	newrole = (struct gr_learn_role_entry *)gr_stat_alloc(sizeof(struct gr_learn_role_entry));
+	newrole->rolename = gr_strdup(rolename);
+	newrole->rolemode = rolemode;
+
+	establish_new_head(*role_list, newrole, tmp);
 
 	/* give every learned role a / subject */
-	insert_learn_role_subject(*((*role_list) + num), conv_filename_to_struct("/", GR_PROCFIND | GR_OVERRIDE));
+	insert_learn_role_subject(newrole, conv_filename_to_struct("/", GR_PROCFIND | GR_OVERRIDE));
 
-	return (*((*role_list) + num));
+	return newrole;
 }
 
 struct gr_learn_role_entry *
-find_learn_role(struct gr_learn_role_entry **role_list, char *rolename)
+find_learn_role(struct gr_learn_role_entry *role_list, char *rolename)
 {
-	struct gr_learn_role_entry **tmp;
+	struct gr_learn_role_entry *tmp;
 
-	tmp = role_list;
-	while(tmp && *tmp) {
-		if (!strcmp((*tmp)->rolename, rolename))
-			return *tmp;
-		tmp++;
+	for_each_list_entry(tmp, role_list) {
+		if (!strcmp(tmp->rolename, rolename))
+			return tmp;
 	}
+
 	return NULL;
 }
 
