Index: libabac/abac_aspect.c
===================================================================
--- libabac/abac_aspect.c	(revision 8bd77b59df89993868555d3b87f91fc241b09228)
+++ libabac/abac_aspect.c	(revision 8bd77b59df89993868555d3b87f91fc241b09228)
@@ -0,0 +1,753 @@
+
+/**
+**  abac_aspect.c
+**/
+
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "abac_list.h"
+#include "abac_util.h"
+
+#include "abac_internal.h"
+
+static int debug=0;
+/*
+   A.role <- B
+   A.role <- B.role
+   A.role <- B.role.role
+
+   A.oset <- B
+   A.oset <- Obj
+   A.oset <- B.oset
+   A.oset <- B.role.oset
+*/
+
+/* can store either a role or oset */
+struct _abac_aspect_t {
+    int aspect_type;
+    int is_object;
+
+    char *principal_name;
+    abac_term_t *principal_object;
+
+    char *linked_role_name;
+    abac_param_list_t *linked_role_params;
+
+    char *aspect_name;
+    abac_param_list_t *aspect_params;
+
+    char *type_string; // "oset" or "role"
+
+    abac_list_t *prereqs;
+    int refcount;
+};
+
+/**************************************************************/
+bool abac_aspect_is_oset(abac_aspect_t *ptr)
+{
+    assert(ptr);
+    if(ptr->aspect_type==e_ASPECTTYPE_OSET)
+        return 1;
+    return 0;
+}
+
+
+bool abac_aspect_is_role(abac_aspect_t *ptr)
+{
+    assert(ptr);
+    if(ptr->aspect_type==e_ASPECTTYPE_ROLE)
+        return 1;
+    return 0;
+}
+
+bool abac_aspect_is_intersecting(abac_aspect_t *ptr)
+{
+    assert(ptr);
+    if(ptr->aspect_type==e_ASPECTTYPE_INTERSECTING)
+        return 1;
+    return 0;
+}
+
+/* A.role->B or A.oset->B */
+bool abac_aspect_is_principal(abac_aspect_t *ptr) {
+    assert(ptr != NULL);
+    return ptr->is_object == 0 &&
+             ptr->aspect_name == NULL && 
+               ptr->linked_role_name == NULL && 
+                 ptr->prereqs == NULL;
+}
+
+/* A.oset->O */
+bool abac_aspect_is_object(abac_aspect_t *ptr)
+{
+    assert(ptr);
+    if(ptr->aspect_type == e_ASPECTTYPE_OSET)
+        return ptr->is_object;
+    return 0;
+}
+
+/* A.role->B.role.role or A.oset->B.role.oset */
+bool abac_aspect_is_linking(abac_aspect_t *ptr) 
+{
+    assert(ptr);
+    return ptr->linked_role_name != NULL;
+}
+
+/**
+ * True if an aspect is an intersection.
+ */
+bool abac_aspect_is_intersection(abac_aspect_t *ptr)
+{
+    assert(ptr);
+    return ptr->prereqs != NULL;
+}
+
+/**
+ * return the type that is common to all the intersecting aspects 
+ */ 
+int abac_aspect_intersecting_aspect_type(abac_aspect_t *ptr)
+{
+    assert(ptr);
+    assert(ptr->prereqs);
+    abac_aspect_t *cur;
+    int first=1;
+    int type;
+    abac_list_foreach(ptr->prereqs, cur,
+            if(first) {
+               type=abac_aspect_aspect_type(cur);
+               first=0;
+               } else {
+                   if(abac_aspect_aspect_type(cur) != type)
+                       errx(1,"Intersecting tails are not of the same type");
+            }
+        );
+    return type;
+}
+
+/**
+ * Returns the prereqs of an intersection.
+ */
+abac_list_t *abac_aspect_prereqs(abac_aspect_t *ptr)
+{
+    assert(ptr);
+    return ptr->prereqs;
+}
+
+char* abac_aspect_type_string(abac_aspect_t *ptr)
+{
+    assert(ptr);
+    return ptr->type_string;
+}
+
+int abac_aspect_aspect_type(abac_aspect_t *ptr)
+{
+    assert(ptr);
+    return ptr->aspect_type;
+}
+
+/**
+ * Returns the linked part of a linking aspect. 
+ * For instance, if the aspect is A.r1.r2, this returns r1.
+ */
+char *abac_aspect_linked_role_name(abac_aspect_t *ptr)
+{
+    assert(ptr);
+    return ptr->linked_role_name;
+}
+
+/* A.r1 without params or constraints, callee needs to free it*/
+char *abac_aspect_linked_role_bare(abac_aspect_t *ptr)
+{
+    assert(ptr);
+    assert(ptr->principal_name);
+    assert(ptr->linked_role_name);
+    char *tmp=NULL;
+    asprintf(&tmp,"%s.%s",ptr->principal_name,ptr->linked_role_name);
+    return tmp;
+}
+
+abac_param_list_t *abac_aspect_linked_role_params(abac_aspect_t *ptr)
+{
+    assert(ptr);
+    return ptr->linked_role_params;
+}
+
+/**
+ * Returns the name of an aspect. If the aspect is A.r1 then return r1.
+ * If the aspect is A.r1.r2 then return r2.
+ */
+char *abac_aspect_aspect_name(abac_aspect_t *ptr) {
+    assert(ptr);
+    return ptr->aspect_name;
+}
+
+abac_param_list_t *abac_aspect_aspect_params(abac_aspect_t *ptr)
+{
+    assert(ptr);
+    return ptr->aspect_params;
+}
+
+/**
+ * Returns the principal part of an aspect. The stuff before the first dot.
+ */
+char *abac_aspect_principal_name(abac_aspect_t *ptr)
+{
+    assert(ptr);
+    if(USE("ABAC_CN"))
+        return abac_cn_with_sha(ptr->principal_name);
+    return ptr->principal_name;
+}
+
+char *abac_aspect_principal_principalname(abac_aspect_t *ptr)
+{
+    assert(ptr);
+    return ptr->principal_name;
+}
+
+char *abac_aspect_principal_cn(abac_aspect_t *ptr)
+{
+    assert(ptr);
+    return abac_cn_with_sha(ptr->principal_name);
+}
+
+char *abac_aspect_object_name(abac_aspect_t *ptr)
+{
+    assert(ptr);
+    assert(ptr->is_object);
+    abac_term_t *obj=ptr->principal_object;
+    char *tmp=abac_term_name(obj);
+    return abac_term_name(obj);
+}
+
+char *abac_aspect_object_type(abac_aspect_t *ptr)
+{
+    assert(ptr);
+    assert(ptr->is_object);
+    abac_term_t *obj=ptr->principal_object;
+    char *tmp=abac_term_type_name(obj);
+    return tmp;
+}
+
+abac_condition_t *abac_aspect_object_constraint(abac_aspect_t *ptr) 
+{
+    assert(ptr != NULL);
+    assert(ptr->is_object);
+    abac_term_t *obj=ptr->principal_object;
+    return abac_term_constraint(obj);
+}
+
+abac_id_t *abac_aspect_get_issuer_id(abac_aspect_t *ptr)
+{
+    abac_id_t *issuer_id;
+    char *principalname=abac_aspect_principal_principalname(ptr);
+    if(principalname) {
+        abac_id_credential_t *id_cred=abac_id_credential_lookup(principalname);
+        if(id_cred)
+            issuer_id=abac_id_credential_id(id_cred);
+    }
+    return issuer_id;
+}
+/**
+ * Increase a aspect's reference count.
+ */
+abac_aspect_t *abac_aspect_dup(abac_aspect_t *ptr)
+{
+    assert(ptr != NULL);
+    ++ptr->refcount;
+    return ptr;
+}
+
+/**
+ * Decrease an aspect's reference count, freeing it when it reaches 0.
+ */
+void abac_aspect_free(abac_aspect_t *ptr) {
+
+    if(debug)
+        printf("DEBUG:trying to freeing an aspect %d\n",(int)ptr);
+
+    assert(ptr);
+
+    --ptr->refcount;
+    if (ptr->refcount > 0)
+        return;
+
+    if(ptr->principal_name) free(ptr->principal_name);
+    if(ptr->linked_role_name) free(ptr->linked_role_name);
+    if(ptr->aspect_name) free(ptr->aspect_name);
+
+    if(ptr->type_string) free(ptr->type_string);
+
+    if (ptr->aspect_params != NULL) {
+        abac_param_list_free(ptr->aspect_params);
+    }
+
+    if (ptr->linked_role_params != NULL) {
+        abac_param_list_free(ptr->linked_role_params);
+    }
+
+    if (ptr->prereqs != NULL) {
+        abac_aspect_t *cur;
+        abac_list_foreach(ptr->prereqs, cur,
+            abac_aspect_free(cur);
+        );
+        abac_list_free(ptr->prereqs);
+    }
+
+    free(ptr);
+}
+
+/**********************************************************************/
+
+abac_aspect_t *abac_aspect_add_param(abac_aspect_t *ptr, abac_term_t *param)
+{
+     if(ptr->aspect_params == NULL) {
+        ptr->aspect_params=abac_param_list_new(param);
+        } else {
+            abac_param_list_add_term(ptr->aspect_params, param);
+     }
+     return ptr;
+}
+
+abac_aspect_t *abac_aspect_add_intersecting_aspect(abac_aspect_t *ptr, abac_aspect_t *aspect)
+{
+     abac_list_add(ptr->prereqs, abac_aspect_dup(aspect));
+     return ptr;
+}
+
+abac_aspect_t *abac_aspect_add_linked_param(abac_aspect_t *ptr, abac_term_t *param)
+{
+     if(ptr->linked_role_params == NULL) {
+        ptr->linked_role_params=abac_param_list_new(param);
+        } else {
+            abac_param_list_add_term(ptr->linked_role_params, param);
+     }
+     return ptr;
+}
+
+
+/**********************************************************************/
+
+/**
+ * Create a new principal and initialize it.
+ * always with the proper SHA string
+ */
+static abac_aspect_t *_abac_aspect_init()
+{
+    abac_aspect_t *ptr = (abac_aspect_t *) abac_xmalloc(sizeof(abac_aspect_t));
+
+    ptr->is_object=0;
+    ptr->principal_name = NULL;
+    ptr->aspect_type=e_ASPECTTYPE_NULL;
+
+    ptr->aspect_name = NULL;
+    ptr->aspect_params = NULL;
+
+    ptr->linked_role_name = NULL;
+    ptr->linked_role_params = NULL;
+
+    ptr->type_string=NULL;
+
+    ptr->prereqs = NULL;
+    ptr->refcount = 1;
+}
+
+abac_aspect_t *abac_aspect_principal_new(int type, char *principal_name)
+{
+    assert(principal_name != NULL);
+
+    if (strlen(principal_name) == 0)
+        return NULL;
+
+    abac_aspect_t *ptr = _abac_aspect_init();
+    ptr->aspect_type=type;
+    ptr->principal_name = strdup(principal_name);
+    if(type==e_ASPECTTYPE_ROLE)
+       ptr->type_string=abac_xstrdup("role");
+    if(type==e_ASPECTTYPE_OSET)
+       ptr->type_string=abac_xstrdup("oset");
+    return ptr;
+}
+
+abac_aspect_t *abac_aspect_role_principal_new(char *principal_name)
+{
+    return abac_aspect_principal_new(e_ASPECTTYPE_ROLE,principal_name);
+}
+
+abac_aspect_t *abac_aspect_role_principal_create(char *principal_name)
+{
+    char *tmp=NULL;
+    asprintf(&tmp,"p%s",principal_name);
+    return abac_aspect_principal_new(e_ASPECTTYPE_ROLE,tmp);
+}
+
+abac_aspect_t *abac_aspect_oset_principal_new(char *principal_name)
+{
+    return abac_aspect_principal_new(e_ASPECTTYPE_OSET,principal_name);
+}
+
+abac_aspect_t *abac_aspect_oset_principal_create(char *principal_name)
+{
+    char *tmp=NULL;
+    asprintf(&tmp,"p%s",principal_name);
+    return abac_aspect_principal_new(e_ASPECTTYPE_OSET,tmp);
+}
+
+
+abac_aspect_t *abac_aspect_object_new(int type, abac_term_t *object)
+{
+    assert(object != NULL);
+    abac_aspect_t *ptr = _abac_aspect_init();
+    ptr->aspect_type=type;
+    ptr->is_object =1;
+    ptr->principal_object = object;
+    /* can not be role type */
+    if(type==e_ASPECTTYPE_OSET)
+        ptr->type_string=abac_xstrdup("oset");
+
+    return ptr;
+}
+
+abac_aspect_t *abac_aspect_oset_object_new(abac_term_t *object)
+{
+    return abac_aspect_object_new(e_ASPECTTYPE_OSET, object);
+}
+
+abac_aspect_t *abac_aspect_new(int type, char *principal_name, char *aspect_name)
+{
+    assert(principal_name != NULL);
+    assert(aspect_name != NULL);
+
+    if (strlen(principal_name) == 0 || strlen(aspect_name) == 0)
+        return NULL;
+
+    abac_aspect_t *ptr = _abac_aspect_init();
+
+    ptr->principal_name = strdup(principal_name);
+    ptr->aspect_type=type;
+
+    ptr->aspect_name = abac_xstrdup(aspect_name);
+
+    if(type==e_ASPECTTYPE_OSET)
+        ptr->type_string= abac_xstrdup("oset");
+        else
+            ptr->type_string= abac_xstrdup("role");
+  
+    if(debug)
+        printf("DEBUG:adding a new aspect (%s) to principal (%s)\n",
+                  ptr->aspect_name, ptr->principal_name);
+    return ptr;
+}
+
+abac_aspect_t *abac_aspect_oset_new(char *principal_name, char *oset_name)
+{
+    return abac_aspect_new(e_ASPECTTYPE_OSET,principal_name, oset_name);
+}
+
+abac_aspect_t *abac_aspect_oset_create(char *principal_name, char *oset_name)
+{
+    char *tmp=NULL;
+    asprintf(&tmp,"p%s",principal_name);
+    return abac_aspect_new(e_ASPECTTYPE_OSET,tmp,oset_name);
+}
+
+abac_aspect_t *abac_aspect_role_new(char *principal_name, char *oset_name)
+{
+    return abac_aspect_new(e_ASPECTTYPE_ROLE,principal_name, oset_name);
+}
+
+abac_aspect_t *abac_aspect_role_create(char *principal_name, char *role_name)
+{
+    char *tmp=NULL;
+    asprintf(&tmp,"p%s",principal_name);
+    return abac_aspect_new(e_ASPECTTYPE_ROLE,tmp,role_name);
+}
+
+/**
+ * Created a new linking role/oset and initialize it.
+ */
+abac_aspect_t *abac_aspect_linking_new(int type, char *principal_name, 
+char *linked_role_name, char *aspect_name)
+{
+    assert(principal_name != NULL);
+    assert(linked_role_name != NULL);
+    assert(aspect_name != NULL);
+
+    if (strlen(principal_name) == 0 || 
+         strlen(linked_role_name) == 0 || strlen(aspect_name) == 0)
+        return NULL;
+
+    abac_aspect_t *ptr = _abac_aspect_init();
+
+    ptr->is_object=0;
+    ptr->aspect_type=type;
+    ptr->principal_name = strdup(principal_name);
+
+    ptr->linked_role_name = strdup(linked_role_name);
+    ptr->aspect_name = strdup(aspect_name);
+    ptr->aspect_params = NULL;
+
+    if(debug)
+        printf("DEBUG:adding a new linked (%s) to oset(%s) for principal(%s)\n",
+                  ptr->linked_role_name, ptr->aspect_name, ptr->principal_name);
+
+    if(type==e_ASPECTTYPE_OSET)
+        ptr->type_string=abac_xstrdup("oset");
+        else ptr->type_string=abac_xstrdup("role");
+
+    return ptr;
+}
+
+abac_aspect_t *abac_aspect_role_linking_new(char *principal_name, char *linked_role_name, 
+char *role_name)
+{
+    return abac_aspect_linking_new(e_ASPECTTYPE_ROLE,
+                      principal_name, linked_role_name, role_name);
+}
+
+abac_aspect_t *abac_aspect_oset_linking_new(char *principal_name, char *linked_role_name, 
+char *oset_name)
+{
+    return abac_aspect_linking_new(e_ASPECTTYPE_OSET,
+                      principal_name, linked_role_name, oset_name);
+}
+
+/**
+ * Create an intersection oset/role.
+ */
+abac_aspect_t *abac_aspect_intersection_new(abac_aspect_t *aspect)
+{
+    abac_aspect_t *ptr = _abac_aspect_init();
+    ptr->aspect_type=e_ASPECTTYPE_INTERSECTING;
+    abac_list_t *prereqs = abac_list_new();
+    abac_list_add(prereqs, abac_aspect_dup(aspect));
+    ptr->prereqs = prereqs;
+    ptr->refcount = 1;
+    return ptr;
+}
+
+/*******************************************************************/
+char *abac_aspect_intersecting_string_with_condition(int typed,abac_aspect_t *ptr)
+{
+    assert(ptr != NULL);
+    char *tmp=NULL;
+    if (ptr->prereqs != NULL) {
+        abac_aspect_t *cur;
+        abac_list_foreach(ptr->prereqs, cur,
+            char *ntmp=NULL;
+            if(typed)
+                ntmp=abac_aspect_typed_string_with_condition(cur);
+                else
+                    ntmp=abac_aspect_string_with_condition(cur);
+            if(tmp==NULL) {
+                asprintf(&tmp,"%s",ntmp);
+                } else {
+                    asprintf(&tmp,"%s & %s",tmp, ntmp);
+            }
+        );
+    }
+    return tmp;
+}
+
+/**
+ * Returns the string representation of the role/oset.
+ * principal.osetname(params..)
+ * principal.rolename(params..)
+ */
+char *abac_aspect_string_with_condition(abac_aspect_t *ptr)
+{
+    assert(ptr != NULL);
+
+    if(abac_aspect_is_intersection(ptr)) {
+        return abac_aspect_intersecting_string_with_condition(0,ptr);
+    }
+
+    char *tmp=NULL;
+    char *principal_name;
+    if(abac_aspect_is_object(ptr))
+        principal_name = abac_aspect_object_name(ptr);
+        else principal_name = abac_aspect_principal_name(ptr);
+    char *aspect_name= ptr->aspect_name;
+    char *linked_role_name = ptr->linked_role_name;
+    char *params_string=NULL;
+    char *linked_params_string=NULL;
+
+    int len = 0;
+    if(principal_name)
+        len=len+strlen(principal_name)+1;
+    if(aspect_name)
+        len = len+strlen(aspect_name)+1;
+    if(linked_role_name)
+        len = len+strlen(linked_role_name)+1;
+
+    if(ptr->aspect_params) {
+         params_string=abac_param_list_string_with_condition(ptr->aspect_params);
+         len = len+strlen(params_string)+3;
+    } 
+    if(ptr->linked_role_params) {
+         linked_params_string=abac_param_list_string_with_condition(ptr->linked_role_params);
+         len = len+strlen(linked_params_string)+3;
+    }
+
+    /* principal */
+    /* principal.oset/role */
+    /* principal.oset/role(params_string) */
+    /* principal.linked_role(linked_params_string).oset/role(params_string) */
+    tmp = abac_xmalloc(len);
+
+    if(principal_name)
+        sprintf(tmp,"%s",principal_name);
+
+    if(linked_role_name) {
+        strcat(tmp,".");
+        strcat(tmp,linked_role_name);
+    }
+    if(linked_params_string) {
+        strcat(tmp,"(");
+        strcat(tmp,linked_params_string);
+        strcat(tmp,")");
+    }
+    if(aspect_name) {
+        strcat(tmp,".");
+        strcat(tmp,aspect_name);
+    }
+    if(params_string) {
+        strcat(tmp,"(");
+        strcat(tmp,params_string);
+        strcat(tmp,")");
+    }
+
+    if(linked_params_string) free(linked_params_string);
+    if(params_string) free(params_string);
+    return tmp;
+}
+
+char *abac_aspect_string(abac_aspect_t *ptr) { 
+    return abac_aspect_string_with_condition(ptr);
+}
+char *abac_aspect_typed_string(abac_aspect_t *ptr) { 
+    return abac_aspect_typed_string_with_condition(ptr);
+}
+
+void abac_print_aspect_string_with_condition(abac_aspect_t *ptr,FILE *fp)
+{
+    char *string=abac_aspect_string_with_condition(ptr);
+    if(fp==NULL)
+        printf("%s ",string);
+        else fprintf(fp,"%s ",string);
+}
+
+char *abac_aspect_aspect_param_string(abac_aspect_t *ptr) {
+    assert(ptr != NULL);
+    if(ptr->aspect_params) {
+         return abac_param_list_string_with_condition(ptr->aspect_params);
+    }
+    return NULL;
+}
+
+char *abac_aspect_aspect_param_typed_string(abac_aspect_t *ptr) {
+    assert(ptr != NULL);
+    if(ptr->aspect_params) {
+         return abac_param_list_typed_string_with_condition(ptr->aspect_params);
+    }
+    return NULL;
+}
+
+/**
+ * Returns the typed string representation of the role/oset.
+ */
+char *abac_aspect_typed_string_with_condition(abac_aspect_t *ptr)
+{
+    assert(ptr != NULL);
+
+    if(abac_aspect_is_intersection(ptr)) {
+        return abac_aspect_intersecting_string_with_condition(1,ptr);
+    }
+
+    char *tmp=NULL, *final=NULL;
+    char *principal_name;
+    char *principal_name_type=NULL;
+    if(abac_aspect_is_object(ptr)) {
+        principal_name = abac_aspect_object_name(ptr);
+        principal_name_type = abac_aspect_object_type(ptr);
+        } else {
+            char *sha=NULL;
+            principal_name = abac_aspect_principal_name(ptr);
+            /* only if it is cn */
+            if(USE("ABAC_CN"))
+                sha=abac_aspect_principal_principalname(ptr);
+                else sha=principal_name;
+            principal_name_type = abac_idtype_with_sha(sha);
+            if(debug) {
+                printf("aspect's typed_string (%s)(%s)\n", principal_name_type, principal_name);
+            }
+    }
+    char *aspect_name=abac_aspect_aspect_name(ptr);
+    char *aspect_name_type=abac_aspect_type_string(ptr);
+    char *linked_role_name=abac_aspect_linked_role_name(ptr);
+    char *params_string=NULL;
+    char *linked_params_string=NULL;
+
+    if(ptr->aspect_params) {
+         params_string=abac_param_list_typed_string_with_condition(ptr->aspect_params);
+    } 
+    if(ptr->linked_role_params) {
+         linked_params_string=abac_param_list_typed_string_with_condition(ptr->linked_role_params);
+    }
+
+    asprintf(&final,"[%s:%s]",principal_name_type,principal_name);
+    if(linked_role_name) {
+        tmp=final;
+        final=NULL;
+        asprintf(&final,".role:%s",tmp,linked_role_name);
+        free(tmp);
+    }
+    if(linked_params_string) {
+        tmp=final;
+        final=NULL;
+        asprintf(&final,"%s(%s)",tmp,linked_params_string);
+        free(tmp);
+    }
+    if(aspect_name) {
+        tmp=final;
+        final=NULL;
+        asprintf(&final,"%s.%s:%s",tmp,aspect_name_type,aspect_name);
+        free(tmp);
+    }
+    if(params_string) {
+        tmp=final;
+        final=NULL;
+        asprintf(&final,"%s(%s)",tmp,params_string);
+        free(tmp);
+    }
+
+    if(linked_params_string) free(linked_params_string);
+    if(params_string) free(params_string);
+    return final;
+}
+
+/**
+ * Build an attribute key from head and tail osets/role. Static.
+ */
+#define ROLE_SEPARATOR " <- "
+char *abac_aspect_attr_key(abac_aspect_t *head_ptr, abac_aspect_t *tail_ptr) {
+    char *head = abac_aspect_string_with_condition(head_ptr);
+    int head_len = strlen(head);
+
+    char *tail = abac_aspect_string_with_condition(tail_ptr);
+    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;
+}
