Index: libabac/abac_graph.c
===================================================================
--- libabac/abac_graph.c	(revision 0eb4a8e20d9a64cbbd60a78e405919407e895a6c)
+++ libabac/abac_graph.c	(revision e2a0f26146e938057d51fd1e8d948174467e6256)
@@ -239,6 +239,6 @@
 
     abac_list_foreach(traversal, vertex,
-        if (abac_role_is_principal(vertex->role))
-            abac_set_add(principals, abac_role_string(vertex->role));
+        if (vertex->role != NULL && abac_role_is_principal(vertex->role))
+            abac_set_add(principals, vertex->name);
     );
 
@@ -268,4 +268,25 @@
 }
 
+// add a derived edge
+static void _derived_edge(abac_graph_t *graph, abac_vertex_t *head, abac_vertex_t *tail) {
+    abac_edge_t *edge = abac_xmalloc(sizeof(abac_edge_t));
+    edge->vertex = tail;
+    edge->credential = NULL;
+    abac_list_add(head->edges, edge);
+
+    // add to list of derived edges
+    abac_derived_t *derived = abac_xmalloc(sizeof(abac_derived_t));
+    derived->key.head = head;
+    derived->key.tail = edge;
+    HASH_ADD(hh, graph->derived, key, sizeof(abac_derived_key_t), derived);
+}
+
+// find a vertex by name
+abac_vertex_t *_find_vertex(abac_graph_t *graph, char *name) {
+    abac_vertex_t *ret = NULL;
+    HASH_FIND_STR(graph->vertices, name, ret);
+    return ret;
+}
+
 void abac_graph_derive_links(abac_graph_t *graph) {
     abac_vertex_t *vertex;
@@ -277,5 +298,4 @@
         // intersection
         if (_vertex_is_intersection(vertex)) {
-            // TODO:
             // for each prereq edge:
             //     find principals that have the edge
@@ -283,4 +303,34 @@
             // for each principal B in intersection:
             //     add link
+
+            char *name;
+            abac_vertex_t *prereq;
+            abac_set_t *principals = NULL;
+
+            abac_list_foreach(vertex->prereqs, prereq,
+                abac_set_t *cur = _find_principals(graph, prereq);
+
+                if (principals == NULL)
+                    principals = cur;
+                else {
+                    abac_set_intersect(principals, cur);
+                    abac_set_free(cur);
+                }
+
+                if (abac_set_size(principals) == 0)
+                    goto isect_done;
+            );
+
+            abac_list_t *prin_names = abac_set_elements(principals);
+            abac_list_foreach(prin_names, name,
+                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);
+            );
+
+            abac_list_free(prin_names);
+isect_done:
+            abac_set_free(principals);
         }
 
@@ -315,20 +365,9 @@
                 B_r2[B_len + r2_len + 1] = 0;
 
-                abac_vertex_t *B_r2_vertex;
-                HASH_FIND_STR(graph->vertices, B_r2, B_r2_vertex);
-
                 // add an edge if the principal's granted it to someone
+                abac_vertex_t *B_r2_vertex = _find_vertex(graph, B_r2);
                 if (B_r2_vertex) {
                     debug_printf("adding edge from %s to %s\n", B_r2, abac_role_string(vertex->role));
-                    abac_edge_t *edge = abac_xmalloc(sizeof(abac_edge_t));
-                    edge->vertex = B_r2_vertex;
-                    edge->credential = NULL;
-                    abac_list_add(vertex->edges, edge);
-
-                    // add to list of derived edges
-                    abac_derived_t *derived = abac_xmalloc(sizeof(abac_derived_t));
-                    derived->key.head = vertex;
-                    derived->key.tail = edge;
-                    HASH_ADD(hh, graph->derived, key, sizeof(abac_derived_key_t), derived);
+                    _derived_edge(graph, vertex, B_r2_vertex);
                 }
 
@@ -356,5 +395,5 @@
 
     // don't revisit nodes
-    if (!abac_set_add(seen, abac_role_string(vertex->role)))
+    if (!abac_set_add(seen, vertex->name))
         return;
 
@@ -437,19 +476,21 @@
     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;
-
-            if (!abac_set_contains(on_path, abac_role_string(incoming_role)))
+            char *incoming_name = incoming->vertex->name;
+
+            if (!abac_set_contains(on_path, incoming_name))
                 continue;
 
-            abac_set_add(on_path, abac_role_string(role));
-
-            // add non-derived edges to the proof graph
-            if (!abac_role_is_linking(role))
-                abac_graph_add_credential(return_graph, incoming->credential);
+            abac_set_add(on_path, vertex_name);
+
+            // TODO: get implying edges for intersection vertices
+            if (_vertex_is_intersection(vertex)) {
+            }
 
             // recursively find linked roles
-            else {
+            else if (abac_role_is_linking(role)) {
                 char *linked_role = abac_role_linked_role(role);
                 char *principal = abac_role_principal(incoming_role);
@@ -457,4 +498,8 @@
                 _query(graph, linked_role, principal, return_graph);
             }
+
+            // add non-derived edges to the proof graph
+            else
+                abac_graph_add_credential(return_graph, incoming->credential);
         );
     );
