Index: libabac/abac.h
===================================================================
--- libabac/abac.h	(revision ebe824c83add4831fddaeae8b0101869d9d83fe4)
+++ libabac/abac.h	(revision 9a411d7accba6ff50666bab7e0bb3c3ac7a85172)
@@ -68,4 +68,5 @@
 int abac_role_is_role(abac_role_t *role);
 int abac_role_is_linking(abac_role_t *role);
+int abac_role_is_intersection(abac_role_t *role);
 
 char *abac_role_string(abac_role_t *role);
Index: libabac/abac_graph.c
===================================================================
--- libabac/abac_graph.c	(revision ebe824c83add4831fddaeae8b0101869d9d83fe4)
+++ libabac/abac_graph.c	(revision 9a411d7accba6ff50666bab7e0bb3c3ac7a85172)
@@ -47,12 +47,5 @@
 
 // ugghhhghhhghh need this for intersections
-abac_list_t *abac_credential_prereqs(abac_credential_t *);
-
-/**
- * True iff a vertex is linking.
- */
-static inline int _vertex_is_intersection(abac_vertex_t *vertex) {
-    return vertex->role == NULL;
-}
+abac_list_t *abac_role_prereqs(abac_role_t *);
 
 /**
@@ -109,5 +102,18 @@
 
         // for intersections, always NULL on normal vertices
-        vertex->prereqs = NULL;
+        if (abac_role_is_intersection(role)) {
+            abac_role_t *prereq;
+            vertex->prereqs = abac_list_new();
+
+            // add each prereq to the vertex
+            abac_list_foreach(abac_role_prereqs(role), prereq,
+                abac_vertex_t *tail_vertex = _get_vertex(graph, prereq);
+                abac_list_add(vertex->prereqs, tail_vertex);
+            );
+        }
+
+        // normal edges have no prereqs
+        else
+            vertex->prereqs = NULL;
 
         // add it to the vertices
@@ -116,73 +122,4 @@
 
     return vertex;
-}
-
-/**
- * convert a list of prereqs to a string suitable for use as a hash key
- * format: role & role & ... & role
- */
-static char *_prereq_key(abac_list_t *prereqs) {
-    abac_role_t *role;
-    char *string;
-    int i = 0, size;
-    size_t len = 0;
-
-    // find the required size
-    abac_list_foreach(prereqs, role,
-        len += strlen(abac_role_string(role)) + 3;
-    );
-
-    string = abac_xmalloc(len);
-    string[0] = '\0';
-
-    size = abac_list_size(prereqs);
-
-    // concat the names
-    abac_list_foreach(prereqs, role,
-        strcat(string, abac_role_string(role));
-        if (i++ < size - 1)
-            strcat(string, " & ");
-    );
-
-    return string;
-}
-
-/**
- * Find/create intersection vertex. Only called by abac_graph_add_credential.
- */
-static abac_vertex_t *_get_intersection_vertex(abac_graph_t *graph, abac_credential_t *cred) {
-    abac_role_t *role, *tail_role;
-    abac_vertex_t *vertex;
-
-    abac_list_t *prereqs = abac_credential_prereqs(cred);
-    char *string = _prereq_key(prereqs);
-    HASH_FIND_STR(graph->vertices, string, vertex);
-
-    // add the vertex if it doesn't exist
-    if (vertex == NULL) {
-        vertex = abac_xmalloc(sizeof(abac_vertex_t));
-        vertex->role = NULL;
-        vertex->name = string;
-
-        // create the list of edges
-        vertex->edges = abac_list_new();
-
-        // for intersections, will be populated first time it's created
-        vertex->prereqs = abac_list_new();
-
-        // add each prereq to the vertex
-        abac_list_foreach(prereqs, tail_role,
-            abac_vertex_t *tail_vertex = _get_vertex(graph, tail_role);
-            abac_list_add(vertex->prereqs, tail_vertex);
-        );
-
-        // add it to the vertices
-        HASH_ADD_KEYPTR(hh, graph->vertices, vertex->name, strlen(vertex->name), vertex);
-    }
-    else
-        free(string); // already exists, get rid of useless memory
-
-    return vertex;
-
 }
 
@@ -203,12 +140,5 @@
 
     head_vertex = _get_vertex(graph, head);
-
-    // tail is a normal role
-    if (tail != NULL)
-        tail_vertex = _get_vertex(graph, tail);
-
-    // intersection
-    else
-        tail_vertex = _get_intersection_vertex(graph, cred);
+    tail_vertex = _get_vertex(graph, tail);
 
     // make sure we don't insert the same edge twice (ugh)
@@ -239,6 +169,6 @@
 
     abac_list_foreach(traversal, vertex,
-        if (vertex->role != NULL && abac_role_is_principal(vertex->role))
-            abac_set_add(principals, vertex->name);
+        if (abac_role_is_principal(vertex->role))
+            abac_set_add(principals, abac_role_string(vertex->role));
     );
 
@@ -297,5 +227,5 @@
     for (vertex = graph->vertices; vertex != NULL; vertex = vertex->hh.next) {
         // intersection
-        if (_vertex_is_intersection(vertex)) {
+        if (abac_role_is_intersection(vertex->role)) {
             // for each prereq edge:
             //     find principals that have the edge
@@ -326,6 +256,4 @@
                 abac_vertex_t *principal = _find_vertex(graph, name);
                 _derived_edge(graph, vertex, principal);
-
-                printf("adding edge from %s to %s\n", principal->name, vertex->name);
             );
 
@@ -395,5 +323,5 @@
 
     // don't revisit nodes
-    if (!abac_set_add(seen, vertex->name))
+    if (!abac_set_add(seen, abac_role_string(vertex->role)))
         return;
 
@@ -476,17 +404,15 @@
     abac_list_foreach(traversal, vertex,
         abac_role_t *role = vertex->role;
-        char *vertex_name = vertex->name;
 
         abac_list_foreach(vertex->edges, incoming,
             abac_role_t *incoming_role = incoming->vertex->role;
-            char *incoming_name = incoming->vertex->name;
-
-            if (!abac_set_contains(on_path, incoming_name))
+
+            if (!abac_set_contains(on_path, abac_role_string(incoming_role)))
                 continue;
 
-            abac_set_add(on_path, vertex_name);
+            abac_set_add(on_path, abac_role_string(role));
 
             // get implying edges for intersection vertices
-            if (_vertex_is_intersection(vertex)) {
+            if (abac_role_is_intersection(role)) {
                 abac_vertex_t *prereq;
                 abac_list_foreach(vertex->prereqs, prereq,
Index: libabac/abac_role.c
===================================================================
--- libabac/abac_role.c	(revision ebe824c83add4831fddaeae8b0101869d9d83fe4)
+++ libabac/abac_role.c	(revision 9a411d7accba6ff50666bab7e0bb3c3ac7a85172)
@@ -5,4 +5,5 @@
 
 #include "abac.h"
+#include "abac_list.h"
 #include "abac_util.h"
 
@@ -11,9 +12,11 @@
     char *principal;
     char *linked_role;
-    char *abac_role_name;
+    char *role_name;
 
     char *string;
     char *linked;
 
+    abac_list_t *prereqs;
+
     int refcount;
 };
@@ -33,9 +36,10 @@
 
     role->principal = abac_xstrdup(principal);
-    role->abac_role_name = NULL;
+    role->role_name = NULL;
     role->linked_role = NULL;
 
     role->string = abac_xstrdup(principal);
     role->linked = NULL;
+    role->prereqs = NULL;
 
     role->refcount = 1;
@@ -47,11 +51,11 @@
  * Create a new role and initialize it.
  */
-abac_role_t *abac_role_role_new(char *principal, char *abac_role_name) {
+abac_role_t *abac_role_role_new(char *principal, char *role_name) {
     assert(principal != NULL);
-    assert(abac_role_name != NULL);
+    assert(role_name != NULL);
 
     abac_role_t *role;
 
-    if (strlen(principal) == 0 || strlen(abac_role_name) == 0)
+    if (strlen(principal) == 0 || strlen(role_name) == 0)
         return NULL;
 
@@ -59,17 +63,18 @@
 
     role->principal = abac_xstrdup(principal);
-    role->abac_role_name = abac_xstrdup(abac_role_name);
+    role->role_name = abac_xstrdup(role_name);
     role->linked_role = NULL;
 
     int prin_len = strlen(principal);
-    int abac_role_len = strlen(abac_role_name);
-
-    role->string = abac_xmalloc(prin_len + 1 + abac_role_len + 1);
+    int role_len = strlen(role_name);
+
+    role->string = abac_xmalloc(prin_len + 1 + role_len + 1);
     memcpy(role->string, principal, prin_len);
     role->string[prin_len] = '.';
-    memcpy(role->string + prin_len + 1, abac_role_name, abac_role_len);
-    role->string[prin_len + 1 + abac_role_len] = 0;
+    memcpy(role->string + prin_len + 1, role_name, role_len);
+    role->string[prin_len + 1 + role_len] = 0;
 
     role->linked = NULL;
+    role->prereqs = NULL;
 
     role->refcount = 1;
@@ -81,12 +86,12 @@
  * Created a new linking role and initialize it.
  */
-abac_role_t *abac_role_linking_new(char *principal, char *linked, char *abac_role_name) {
+abac_role_t *abac_role_linking_new(char *principal, char *linked, char *role_name) {
     assert(principal != NULL);
     assert(linked != NULL);
-    assert(abac_role_name != NULL);
+    assert(role_name != NULL);
 
     abac_role_t *role;
 
-    if (strlen(principal) == 0 || strlen(linked) == 0 || strlen(abac_role_name) == 0)
+    if (strlen(principal) == 0 || strlen(linked) == 0 || strlen(role_name) == 0)
         return NULL;
 
@@ -95,11 +100,11 @@
     role->principal = abac_xstrdup(principal);
     role->linked_role = abac_xstrdup(linked);
-    role->abac_role_name = abac_xstrdup(abac_role_name);
+    role->role_name = abac_xstrdup(role_name);
 
     int prin_len = strlen(principal);
     int link_len = strlen(linked);
-    int abac_role_len = strlen(abac_role_name);
-
-    role->string = abac_xmalloc(prin_len + 1 + link_len + 1 + abac_role_len + 1);
+    int role_len = strlen(role_name);
+
+    role->string = abac_xmalloc(prin_len + 1 + link_len + 1 + role_len + 1);
 
     memcpy(role->string, principal, prin_len);
@@ -112,6 +117,25 @@
 
     role->string[prin_len + 1 + link_len] = '.';
-    memcpy(role->string + prin_len + 1 + link_len + 1, abac_role_name, abac_role_len);
-    role->string[prin_len + 1 + link_len + 1 + abac_role_len] = 0;
+    memcpy(role->string + prin_len + 1 + link_len + 1, role_name, role_len);
+    role->string[prin_len + 1 + link_len + 1 + role_len] = 0;
+
+    role->prereqs = NULL;
+
+    role->refcount = 1;
+
+    return role;
+}
+
+/**
+ * Create an intersection role.
+ */
+abac_role_t *abac_role_intersection_new(char *name, abac_list_t *prereqs) {
+    abac_role_t *role = abac_xmalloc(sizeof(abac_role_t));
+
+    role->principal = role->linked_role = role->role_name = NULL;
+    role->linked = NULL;
+
+    role->string = abac_xstrdup(name);
+    role->prereqs = prereqs;
 
     role->refcount = 1;
@@ -133,18 +157,28 @@
     free(role->principal);
     free(role->linked_role);
-    free(role->abac_role_name);
+    free(role->role_name);
 
     free(role->string);
     free(role->linked);
 
+    if (role->prereqs != NULL) {
+        abac_role_t *cur;
+        abac_list_foreach(role->prereqs, cur,
+            abac_role_free(cur);
+        );
+        abac_list_free(role->prereqs);
+    }
+
     free(role);
 }
 
 /**
- * Create a role from a string. Handles principals, roles, and linking roles.
- */
-abac_role_t *abac_role_from_string(char *string) {
+ * Create a non-intersecting role from a string. Handles principals, roles,
+ * and linking roles.
+ */
+static abac_role_t *_abac_single_role_from_string(char *string) {
     int num_dots = 0;
     char *dot = string;
+    abac_role_t *ret = NULL;
 
     // count the dots
@@ -156,13 +190,8 @@
     // no dots: easy case, principal
     if (num_dots == 0)
-        return abac_role_principal_new(string);
-
-    abac_role_t *ret = NULL;
-
-    // make a copy so we can mess with it
-    string = abac_xstrdup(string);
+        ret = abac_role_principal_new(string);
 
     // a role has exactly 1 dot
-    if (num_dots == 1) {
+    else if (num_dots == 1) {
         char *principal = string;
 
@@ -172,8 +201,8 @@
 
         // role name comes after the dot
-        char *abac_role_name = dot + 1;
+        char *role_name = dot + 1;
 
         // create the role (if possible)
-        ret = abac_role_role_new(string, abac_role_name);
+        ret = abac_role_role_new(string, role_name);
     }
 
@@ -192,15 +221,65 @@
 
         // role name is last, already terminated
-        char *abac_role_name = dot + 1;
-
-        ret = abac_role_linking_new(principal, linked, abac_role_name);
+        char *role_name = dot + 1;
+
+        ret = abac_role_linking_new(principal, linked, role_name);
     }
 
     // more than two dots: return NULL
 
+    return ret;
+}
+
+/**
+ * Create a role from a string. Handles intersecting and normal roles.
+ */
+abac_role_t *abac_role_from_string(char *string) {
+    abac_list_t *prereqs = NULL;
+    abac_role_t *ret = NULL, *role;
+    char *roles[256];
+    int num_roles, i;
+
+    char *original = string;
+
+    // make a copy so we can mess with it
+    string = abac_xstrdup(string);
+
+    // split the string (in case of an intersection num_roles > 1)
+    abac_split(string, " & ", roles, &num_roles);
+
+    // normal role: 
+    if (num_roles == 1)
+        ret = _abac_single_role_from_string(string);
+
+    else {
+        prereqs = abac_list_new();
+
+        for (i = 0; i < num_roles; ++i) {
+            // make sure the tail role is valid
+            role = abac_role_from_string(roles[i]);
+            if (role == NULL)
+                goto error;
+
+            abac_list_add(prereqs, role);
+        }
+
+        ret = abac_role_intersection_new(original, prereqs);
+    }
+
     free(string);
-
     return ret;
-}
+
+error:
+    if (prereqs != NULL) {
+        abac_list_foreach(prereqs, role,
+            abac_role_free(role);
+        );
+        abac_list_free(prereqs);
+    }
+    free(string);
+
+    return NULL;
+}
+
 
 /**
@@ -219,5 +298,5 @@
 int abac_role_is_principal(abac_role_t *role) {
     assert(role != NULL);
-    return role->abac_role_name == NULL && role->linked_role == NULL;
+    return role->role_name == NULL && role->linked_role == NULL && role->prereqs == NULL;
 }
 
@@ -227,5 +306,5 @@
 int abac_role_is_role(abac_role_t *role) {
     assert(role != NULL);
-    return role->abac_role_name != NULL && role->linked_role == NULL; 
+    return role->role_name != NULL && role->linked_role == NULL && role->prereqs == NULL; 
 }
 
@@ -236,4 +315,12 @@
     assert(role != NULL);
     return role->linked_role != NULL;
+}
+
+/**
+ * True if a role is an intersection.
+ */
+int abac_role_is_intersection(abac_role_t *role) {
+    assert(role != NULL);
+    return role->prereqs != NULL;
 }
 
@@ -252,5 +339,5 @@
 char *abac_role_role_name(abac_role_t *role) {
     assert(role != NULL);
-    return role->abac_role_name;
+    return role->role_name;
 }
 
@@ -270,4 +357,12 @@
     assert(role != NULL);
     return role->principal;
+}
+
+/**
+ * Returns the prereqs of an intersection.
+ */
+abac_list_t *abac_role_prereqs(abac_role_t *role) {
+    assert(role != NULL);
+    return role->prereqs;
 }
 
Index: libabac/abac_util.c
===================================================================
--- libabac/abac_util.c	(revision ebe824c83add4831fddaeae8b0101869d9d83fe4)
+++ libabac/abac_util.c	(revision 9a411d7accba6ff50666bab7e0bb3c3ac7a85172)
@@ -31,2 +31,21 @@
     return ret;
 }
+
+/**
+ * Split a string based on the given delimiter.
+ */
+void abac_split(char *string, char *delim, char **ret, int *num) {
+    int len = strlen(delim);
+    char *start = string;
+    int count = 0;
+
+    // split the string by the delim
+    while ((start = strstr(string, delim)) != NULL) {
+        *start = 0;
+        ret[count++] = string;
+        string = start + len;
+    }
+    ret[count++] = string;
+
+    *num = count;
+}
Index: libabac/abac_util.h
===================================================================
--- libabac/abac_util.h	(revision ebe824c83add4831fddaeae8b0101869d9d83fe4)
+++ libabac/abac_util.h	(revision 9a411d7accba6ff50666bab7e0bb3c3ac7a85172)
@@ -6,4 +6,5 @@
 void *abac_xmalloc(size_t);
 char *abac_xstrdup(char *);
+void abac_split(char *string, char *delim, char **ret, int *num);
 
 #ifdef DEBUG
Index: libabac/abac_verifier.c
===================================================================
--- libabac/abac_verifier.c	(revision ebe824c83add4831fddaeae8b0101869d9d83fe4)
+++ libabac/abac_verifier.c	(revision 9a411d7accba6ff50666bab7e0bb3c3ac7a85172)
@@ -21,5 +21,4 @@
     abac_role_t *head;
     abac_role_t *tail;
-    abac_list_t *prereqs; // an intersecton has prereqs, not a tail
     certificate_t *cert;
     certificate_t *issuer;
@@ -164,23 +163,4 @@
 
 /**
- * Split a string based on the given delimiter.
- */
-static void _split(char *string, char *delim, char **ret, int *num) {
-    int len = strlen(delim);
-    char *start = string;
-    int count = 0;
-
-    // split the string by the delim
-    while ((start = strstr(string, delim)) != NULL) {
-        *start = 0;
-        ret[count++] = string;
-        string = start + len;
-    }
-    ret[count++] = string;
-
-    *num = count;
-}
-
-/**
  * Load an attribute cert.
  * Returns true only if the certificate is valid and is issued by the proper
@@ -192,5 +172,4 @@
     abac_role_t *tail_role = NULL;
     abac_id_cert_t *issuer;
-    abac_list_t *prereqs = NULL;
     int ret, i;
 
@@ -211,5 +190,5 @@
     // split into head/tail parts
     char *head_tail[2];
-    _split(attr_string, " <- ", head_tail, &ret);
+    abac_split(attr_string, " <- ", head_tail, &ret);
     if (ret != 2) {
         ret = ABAC_CERT_INVALID;
@@ -225,27 +204,10 @@
     }
 
-    // split the tail (in case of an intersection num_tails > 1)
-    char *tails[256];
-    int num_tails;
-    _split(head_tail[1], " & ", tails, &num_tails);
-
-    if (num_tails > 1)
-        prereqs = abac_list_new();
-
-    for (i = 0; i < num_tails; ++i) {
-        // make sure the tail role is valid
-        tail_role = abac_role_from_string(tails[i]);
-        if (tail_role == NULL) {
-            ret = ABAC_CERT_INVALID;
-            goto error;
-        }
-
-        // add to the list if intersection
-        if (num_tails > 1)
-            abac_list_add(prereqs, tail_role);
-    }
-
-    if (num_tails > 1)
-        tail_role = NULL;
+    // make sure the tail's valid too
+    tail_role = abac_role_from_string(head_tail[1]);
+    if (tail_role == NULL) {
+        ret = ABAC_CERT_INVALID;
+        goto error;
+    }
 
     // get the issuer based on keyid
@@ -268,5 +230,4 @@
     cred->head = head_role;
     cred->tail = tail_role;
-    cred->prereqs = prereqs;
     cred->cert = cert;
     cred->issuer = issuer->cert->get_ref(issuer->cert);
@@ -284,12 +245,4 @@
     if (head_role != NULL) abac_role_free(head_role);
     if (tail_role != NULL) abac_role_free(tail_role);
-
-    // free all the tail roles
-    if (prereqs != NULL) {
-        abac_list_foreach(prereqs, tail_role,
-            abac_role_free(tail_role);
-        );
-        abac_list_free(prereqs);
-    }
 
     return ret;
@@ -341,11 +294,4 @@
 
 /**
- * Return the prereqs. Non-NULL iff intersection.
- */
-abac_list_t *abac_credential_prereqs(abac_credential_t *cred) {
-    return cred->prereqs;
-}
-
-/**
  * Return the encoding of the attribute cert.
  */
@@ -391,12 +337,4 @@
     cred->issuer->destroy(cred->issuer); // reference counted
 
-    if (cred->prereqs != NULL) {
-        abac_role_t *tail;
-        abac_list_foreach(cred->prereqs, tail,
-            abac_role_free(tail);
-        );
-        abac_list_free(cred->prereqs);
-    }
-
     free(cred);
 }
Index: libabac/prover.c
===================================================================
--- libabac/prover.c	(revision ebe824c83add4831fddaeae8b0101869d9d83fe4)
+++ libabac/prover.c	(revision 9a411d7accba6ff50666bab7e0bb3c3ac7a85172)
@@ -29,8 +29,7 @@
         for (i = 0; credentials[i] != NULL; ++i) {
             cred = credentials[i];
-            abac_role_t *tail = abac_credential_tail(cred);
             printf("credential %s <- %s\n",
                     abac_role_string(abac_credential_head(cred)),
-                    tail != NULL ? abac_role_string(tail) : "(null)"
+                    abac_role_string(abac_credential_tail(cred))
                   );
         }
