Index: libabac/abac_role.c
===================================================================
--- libabac/abac_role.c	(revision 15200beba77a0ea12f6dcaabfa529d03962d71fc)
+++ libabac/abac_role.c	(revision 15200beba77a0ea12f6dcaabfa529d03962d71fc)
@@ -0,0 +1,289 @@
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "abac.h"
+#include "abac_util.h"
+
+// typedef'd in role.h
+struct _abac_role_t {
+    char *principal;
+    char *linked_role;
+    char *abac_role_name;
+
+    char *string;
+    char *linked;
+};
+
+/**
+ * Create a new principal and initialize it.
+ */
+abac_role_t *abac_role_principal_new(char *principal) {
+    assert(principal != NULL);
+
+    abac_role_t *role;
+
+    if (strlen(principal) == 0)
+        return NULL;
+
+    role = abac_xmalloc(sizeof(abac_role_t));
+
+    role->principal = abac_xstrdup(principal);
+    role->abac_role_name = NULL;
+    role->linked_role = NULL;
+
+    role->string = abac_xstrdup(principal);
+    role->linked = NULL;
+
+    return role;
+}
+
+/**
+ * Create a new role and initialize it.
+ */
+abac_role_t *abac_role_role_new(char *principal, char *abac_role_name) {
+    assert(principal != NULL);
+    assert(abac_role_name != NULL);
+
+    abac_role_t *role;
+
+    if (strlen(principal) == 0 || strlen(abac_role_name) == 0)
+        return NULL;
+
+    role = abac_xmalloc(sizeof(abac_role_t));
+
+    role->principal = abac_xstrdup(principal);
+    role->abac_role_name = abac_xstrdup(abac_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);
+    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;
+
+    role->linked = NULL;
+
+    return role;
+}
+
+/**
+ * Created a new linking role and initialize it.
+ */
+abac_role_t *abac_role_linking_new(char *principal, char *linked, char *abac_role_name) {
+    assert(principal != NULL);
+    assert(linked != NULL);
+    assert(abac_role_name != NULL);
+
+    abac_role_t *role;
+
+    if (strlen(principal) == 0 || strlen(linked) == 0 || strlen(abac_role_name) == 0)
+        return NULL;
+
+    role = abac_xmalloc(sizeof(abac_role_t));
+
+    role->principal = abac_xstrdup(principal);
+    role->linked_role = abac_xstrdup(linked);
+    role->abac_role_name = abac_xstrdup(abac_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);
+
+    memcpy(role->string, principal, prin_len);
+    role->string[prin_len] = '.';
+    memcpy(role->string + prin_len + 1, linked, link_len);
+    role->string[prin_len + 1 + link_len] = 0;
+
+    // hack: linked role is first two parts of full string
+    role->linked = abac_xstrdup(role->string);
+
+    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;
+
+    return role;
+}
+
+/**
+ * Free the memory used by a role.
+ */
+void abac_role_free(abac_role_t *role) {
+    if (role == NULL)
+        return;
+
+    free(role->principal);
+    free(role->linked_role);
+    free(role->abac_role_name);
+
+    free(role->string);
+    free(role->linked);
+
+    free(role);
+}
+
+/**
+ * Create a role from a string. Handles principals, roles, and linking roles.
+ */
+abac_role_t *abac_role_from_string(char *string) {
+    int num_dots = 0;
+    char *dot = string;
+
+    // count the dots
+    while ((dot = strchr(dot, '.')) != NULL) {
+        ++num_dots;
+        ++dot;
+    }
+
+    // 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);
+
+    // a role has exactly 1 dot
+    if (num_dots == 1) {
+        char *principal = string;
+
+        // terminate the principal part
+        dot = strchr(principal, '.');
+        *dot = 0;
+
+        // role name comes after the dot
+        char *abac_role_name = dot + 1;
+
+        // create the role (if possible)
+        ret = abac_role_role_new(string, abac_role_name);
+    }
+
+    // a linked role has 2 dots
+    else if (num_dots == 2) {
+        char *principal = string;
+
+        // terminate the principal part
+        dot = strchr(principal, '.');
+        *dot = 0;
+
+        // linked name is next, terminate it
+        char *linked = dot + 1;
+        dot = strchr(linked, '.');
+        *dot = 0;
+
+        // role name is last, already terminated
+        char *abac_role_name = dot + 1;
+
+        ret = abac_role_linking_new(principal, linked, abac_role_name);
+    }
+
+    // more than two dots: return NULL
+
+    free(string);
+
+    return ret;
+}
+
+/**
+ * Duplicate a role.
+ */
+abac_role_t *abac_role_dup(abac_role_t *role) {
+    abac_role_t *ret = abac_xmalloc(sizeof(abac_role_t));
+
+    ret->principal = abac_xstrdup(role->principal);
+    ret->linked_role = abac_xstrdup(role->linked_role);
+    ret->abac_role_name = abac_xstrdup(role->abac_role_name);
+
+    ret->string = abac_xstrdup(role->string);
+    ret->linked = abac_xstrdup(role->linked);
+
+    return ret;
+}
+
+/**
+ * True if a role is a principal.
+ */
+int abac_role_is_principal(abac_role_t *role) {
+    assert(role != NULL);
+    return role->abac_role_name == NULL && role->linked_role == NULL;
+}
+
+/**
+ * True if a role is a role.
+ */
+int abac_role_is_role(abac_role_t *role) {
+    assert(role != NULL);
+    return role->abac_role_name != NULL && role->linked_role == NULL; 
+}
+
+/**
+ * True if a role is a linked role.
+ */
+int abac_role_is_linking(abac_role_t *role) {
+    assert(role != NULL);
+    return role->linked_role != NULL;
+}
+
+/**
+ * Returns the string representation of the role.
+ */
+char *abac_role_string(abac_role_t *role) {
+    assert(role != NULL);
+    return role->string;
+}
+
+/**
+ * Returns the name of a role. If the role is A.r1 then return r1. If the role
+ * is A.r1.r2 then return r2.
+ */
+char *abac_role_role_name(abac_role_t *role) {
+    assert(role != NULL);
+    return role->abac_role_name;
+}
+
+/**
+ * Returns the linked part of a linking role. For instance, if the role is
+ * A.r1.r2, this returns A.r1.
+ */
+char *abac_role_linked_role(abac_role_t *role) {
+    assert(role != NULL);
+    return role->linked;
+}
+
+/**
+ * Returns the principal part of a role. The stuff before the first dot.
+ */
+char *abac_role_principal(abac_role_t *role) {
+    assert(role != NULL);
+    return role->principal;
+}
+
+/**
+ * Build an attribute key from head and tail roles. Static.
+ */
+#define ROLE_SEPARATOR " <- "
+char *abac_role_attr_key(abac_role_t *head_role, abac_role_t *tail_role) {
+    char *head = abac_role_string(head_role);
+    int head_len = strlen(head);
+
+    char *tail = abac_role_string(tail_role);
+    int tail_len = strlen(tail);
+
+    int sep_len = sizeof(ROLE_SEPARATOR) - 1;
+
+    // "head <- tail"
+    char *ret = abac_xmalloc(head_len + tail_len + sep_len + 1);
+    memcpy(ret, head, head_len);
+    memcpy(ret + head_len, ROLE_SEPARATOR, sep_len);
+    memcpy(ret + head_len + sep_len, tail, tail_len);
+    ret[head_len + sep_len + tail_len] = 0;
+
+    return ret;
+}
