Index: libabac/abac_role.c
===================================================================
--- libabac/abac_role.c	(revision fbb591ed7aab55768a5738344305ea21023f12e3)
+++ 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;
 }
 
