Index: libabac/abac_attribute.c
===================================================================
--- libabac/abac_attribute.c	(revision f89b991618ca86176d8d202d7c2b370ac8246c38)
+++ libabac/abac_attribute.c	(revision 461541aae6382bb58dfb3c4a1679d2d48e8f9e64)
@@ -1,6 +1,7 @@
-/**
-**  abac_attribute.c
-**/
-
+
+/* abac_attribute.c */
+
+#define _GNU_SOURCE
+#include <stdio.h>
 #include <assert.h>
 #include <ctype.h>
@@ -8,619 +9,410 @@
 #include <time.h>
 
-#include <credentials/certificates/x509.h>
-#include <credentials/certificates/certificate.h>
-#include <credentials/certificates/ac.h>
-
+#include "libabac_common.h"
 #include "abac_util.h"
-#include "abac_aspect.h"
-#include "abac_m64.h"
-#include "abac_id.h"
-#include "abac_pl_yy.h"
-#include "rt2_yy.h"
-#include "abac_verifier.h"
-#include "abac_util_cert.h"
-#include "abac_id.h"
-
-/*****************************************************************/
+#include "abac_xml.h"
+
+#define ROLE_SEPARATOR " <- "
+#define INTERSECTION_SEP " & "
+#define SHA1_LENGTH 40
+
 static int debug=0;
 
-/* the correct setting of using_this depends on user if the attribute is
-   not generate from yyparse call */
+// a GENI XML attribute chunk might contain multiple 
+// attribute rules. It will be translate into multiple
+// abac_attribute structures but with cert ptr pointing
+// to the same xml chunk
+// issuer can be missing but then it won't be bakable
+// unless it is baked just for creddy's roles call
 struct _abac_attribute_t {
     abac_id_t *issuer_id; 
-    abac_aspect_t *head;
-    abac_aspect_t *tail;
-    int validity;
-    int using_this; /* tracking use of (?This) */
-    certificate_t *cert; // NULL until baked
-    certificate_t *issuer_cert;
-
-    int refcount;
+    char *role;
+    long validity;
+
+    char *head_string;
+    char *tail_string;
+
+    abac_chunk_t cert; // the XML chunk
 };
 
-/* local */
-abac_attribute_t *abac_attribute_set_head(abac_attribute_t *ptr, abac_aspect_t *head);
-abac_aspect_t *abac_attribute_head(abac_attribute_t *ptr);
-abac_aspect_t *abac_attribute_tail(abac_attribute_t *ptr);
-abac_attribute_t *abac_attribute_add_tail(abac_attribute_t *ptr, abac_aspect_t *tail);
-void abac_attribute_set_using_this(abac_attribute_t *ptr, int using_this);
-
-/********************************************************************/
-/* currently the hashkeyid is the uuencoded 'sha attribute string'  */
-char *get_cred_encoding(abac_attribute_t *ptr)
-{
-    char *encoding=NULL;
-  
-    /* must have a head aspect and tail aspect */
-    assert(ptr->head != NULL);
-    assert(ptr->tail != NULL);
-
-    if(ptr->cert != NULL) { /* already a baked one */
-        ac_t *ac = (ac_t *)ptr->cert;
-        ietf_attributes_t *attr_cert = ac->get_groups(ac);
-        char *encoded_attr_string=attr_cert->get_string(attr_cert);
-        return encoded_attr_string;
-    }
-
-    /* not a baked one should not be in ABAC_CN mode at all !!! */
-    /* needs to be the one with sha */
-    if(USE("ABAC_CN")) {
-        fprintf(stderr,"get_cred_encoding, MIGHT be BAD..\n");
-    } 
-    char *head_string=abac_aspect_typed_string_with_condition(ptr->head);
-    char *tail_string=abac_aspect_typed_string_with_condition(ptr->tail);
-
-    asprintf(&encoding,"%s<-%s", head_string,tail_string);
-    char* base64_encoding=abac_encode_string(encoding);
-
-    if(USE("ABAC_CN")) {
-        fprintf(stderr,"    --> (%s)\n", encoding);
-    }
-
-    free(encoding);
-    free(head_string);
-    free(tail_string);
-    return base64_encoding;
-}
-
-static abac_attribute_t *_abac_attribute_init()
-{
-    abac_attribute_t *ptr = abac_xmalloc(sizeof(abac_attribute_t));
-    ptr->issuer_id = NULL;
-    ptr->head = NULL;
-    ptr->tail = NULL;
-    ptr->validity= 365 * 86400; // default
-    // NULL until baked
-    ptr->using_this=0;
-    ptr->cert= NULL;
-    ptr->issuer_cert= NULL;
-    ptr->refcount=1;
-    return ptr;
-}
-
-/********************************************************************/
-abac_attribute_t *abac_attribute_new(abac_id_t *issuer, certificate_t *cert,
-certificate_t *issuer_cert)
-{
-    abac_attribute_t *ptr = _abac_attribute_init();
-    ptr->issuer_id = abac_id_dup(issuer);
-    ptr->cert=cert; // already baked..
-    ptr->issuer_cert=issuer_cert;
-    ptr->refcount=1;
-    return ptr;
+char *abac_attribute_role_string(abac_attribute_t *attr);
+extern abac_id_t *abac_verifier_lookup_id(char *keyid);
+static char *_validate_principal(char *keyid);
+
+/************************************************************/
+abac_chunk_t abac_attribute_cert(abac_attribute_t *ptr)
+{
+    assert(ptr);
+    return ptr->cert;
+}
+
+abac_id_t *abac_attribute_issuer_id(abac_attribute_t *ptr)
+{
+    assert(ptr);
+    return ptr->issuer_id;
 }
 
 // validity is measured in seconds (as of 0.2.0)
-// remember using_this,
-int abac_attribute_create(abac_attribute_t **ret, abac_aspect_t *head, 
-abac_aspect_t *tail, int validity)
-{
-    abac_id_t *issuer_id=abac_aspect_get_issuer_id(head);
-    if(debug)
-        print_abac_key("abac_attribute_create" , abac_id_keyptr(issuer_id));
-
-    char *name=abac_aspect_aspect_name(head);
-
+// Acme.customer
+int abac_attribute_create(abac_attribute_t **ret, abac_id_t *issuer_id, char *role, long validity) {
     if (!abac_id_has_privkey(issuer_id))
         return ABAC_ATTRIBUTE_ISSUER_NOKEY;
-    if (!abac_validate_clean_aspect_name(name))
+    if (!abac_clean_name(role))
         return ABAC_ATTRIBUTE_INVALID_ROLE;
     if (validity < 0)
         return ABAC_ATTRIBUTE_INVALID_VALIDITY;
-
-    abac_attribute_t *ptr = _abac_attribute_init();
-    ptr->issuer_id = abac_id_dup(issuer_id);
-    ptr->head = abac_aspect_dup(head);
-    if(tail)
-        ptr->tail = abac_aspect_dup(tail);
-    ptr->validity=(validity==0?(365 * 86400):validity);
-
-    *ret = ptr;
-    return ABAC_ATTRIBUTE_SUCCESS;
-}
-
-// validity is measured in seconds (as of 0.2.0)
-int abac_attribute_create_creddy(abac_attribute_t **ret, abac_id_t *issuer, 
-abac_aspect_t *head_aspect, abac_aspect_t *tail_aspect, char *name,
-int validity)
-{
-    if (!abac_id_has_privkey(issuer))
-        return ABAC_ATTRIBUTE_ISSUER_NOKEY;
-    if (!abac_validate_clean_aspect_name(name))
-        return ABAC_ATTRIBUTE_INVALID_ROLE;
-    if (validity < 0)
-        return ABAC_ATTRIBUTE_INVALID_VALIDITY;
-
-    abac_attribute_t *ptr = _abac_attribute_init();
-    ptr->issuer_id = abac_id_dup(issuer);
-    ptr->head=head_aspect;
-    ptr->tail=tail_aspect;
-    ptr->validity = validity;
-
-    *ret = ptr;
-    return ABAC_ATTRIBUTE_SUCCESS;
-}
-
-static void _check_cert_group(certificate_t *cert, char *estring)
-{
-    ietf_attributes_t *attr_cert = NULL;
-    int ret, i;
-
-    // get the attr
-    ac_t *ac = (ac_t *)cert;
-    attr_cert = ac->get_groups(ac);
-    if(attr_cert == NULL) {
-        fprintf(stderr,"BAD group from the cert !!!\n");
+    if (!abac_id_still_valid(issuer_id))
+        return ABAC_ATTRIBUTE_INVALID_ISSUER;
+
+    abac_attribute_t *attr = abac_xmalloc(sizeof(abac_attribute_t));
+    if(issuer_id) attr->issuer_id = abac_id_dup(issuer_id);
+        else attr->issuer_id = NULL;
+    attr->role = abac_xstrdup(role);
+    attr->validity = validity;
+
+    attr->head_string = NULL;
+    attr->tail_string = NULL;
+
+    // NULL until baked
+    attr->cert.ptr=NULL;
+    attr->cert.len=0;
+
+    *ret = attr;
+    return ABAC_SUCCESS;
+}
+
+/**
+ * Get the validity period.(xml module returns the diff from expire time - now()
+ */
+int abac_attribute_validity(abac_attribute_t *attr,struct tm *not_before,struct tm *not_after) {
+    assert(attr);
+    memset(not_before, 0, sizeof(struct tm));
+    memset(not_after, 0, sizeof(struct tm));
+
+    time_t now;
+    time(&now);
+    gmtime_r(&now, not_before);
+    char *xml=attr->cert.ptr;
+    long validity=get_validity_from_xml(xml);
+
+    time_t etime = now + validity;
+    gmtime_r(&etime, not_after);
+
+    fprintf(stderr,"validity from the xml blob is %ld\n",validity);
+    if(validity == 0)
+        return ABAC_FAILURE;
+    return ABAC_SUCCESS;
+}
+
+int abac_attribute_still_valid(abac_attribute_t *attr)
+{
+    assert(attr);
+    assert(attr->cert.ptr);
+    long v=get_validity_from_xml(attr->cert.ptr);
+    if (v > 0.0)
+        return 1;
+    else return 0;
+}
+
+void abac_attribute_set_head(abac_attribute_t *attr, char *string)
+{
+    assert(attr);
+    attr->head_string=string;
+}
+
+char *abac_attribute_get_head(abac_attribute_t *attr)
+{
+    assert(attr);
+    return attr->head_string;
+}
+
+void abac_attribute_set_tail(abac_attribute_t *attr, char *string)
+{
+    assert(attr);
+    attr->tail_string=string;
+}
+
+char *abac_attribute_get_tail(abac_attribute_t *attr)
+{
+    assert(attr);
+    return attr->tail_string;
+}
+
+/* A.b->C, return copy of a A */
+char *abac_attribute_get_principal(abac_attribute_t *attr)
+{
+    char *role_string=abac_attribute_role_string(attr);
+    /* make an copy */
+    char *tmp=strdup(role_string);
+    char *head_tail[2];
+    int ret;
+    abac_split(tmp, "<-", head_tail, &ret);
+    if (ret != 2) goto err;
+    abac_split(head_tail[0], ".", head_tail, &ret);
+    if (ret != 2) goto err;
+    char *prin=strdup(head_tail[0]);
+    free(tmp);
+    return prin;
+
+err:     
+     free(tmp);
+     return NULL;
+}
+
+int abac_attribute_principal(abac_attribute_t *attr, char *keyid) {
+    char *copy = _validate_principal(keyid);
+    if (copy == NULL)
+        return 0;
+
+    abac_attribute_set_tail(attr,copy);
+    return 1;
+}
+
+int abac_attribute_role(abac_attribute_t *attr, char *keyid, char *role) {
+    if (!abac_clean_name(role))
+        return 0;
+
+    char *copy = _validate_principal(keyid);
+    if (copy == NULL)
+        return 0;
+
+    int len = strlen(copy) + strlen(role) + strlen(ROLE_SEPARATOR) + 1;
+    copy = abac_xrealloc(copy, len);
+    strcat(copy, ".");
+    strcat(copy, role);
+
+    abac_attribute_set_tail(attr,copy);
+    return 1;
+}
+
+int abac_attribute_linking_role(abac_attribute_t *attr, char *keyid, char *role, char *linked) {
+    if (!abac_clean_name(role) || !abac_clean_name(linked))
+        return 0;
+
+    char *copy = _validate_principal(keyid);
+    if (copy == NULL)
+        return 0;
+
+    int len = strlen(copy) + strlen(role) + strlen(linked) + strlen(ROLE_SEPARATOR) + 2;
+    copy = abac_xrealloc(copy, len);
+    strcat(copy, ".");
+    strcat(copy, role);
+    strcat(copy, ".");
+    strcat(copy, linked);
+
+    abac_attribute_set_tail(attr,copy);
+    return 1;
+}
+
+
+
+// 0 for fail to bake, 1 is baked okay
+int abac_attribute_bake(abac_attribute_t *attr) {
+    assert(attr);
+    assert(attr->head_string);
+    assert(attr->tail_string);
+
+    abac_chunk_t id_chunk = { NULL, 0 };
+    int ret=abac_id_PEM(attr->issuer_id, &id_chunk);
+    if(ret != ABAC_CERT_SUCCESS)
+        return 0; 
+
+    char *role_string = abac_attribute_role_string(attr);
+
+/* Make an new GENI abac credential with the rt0 rule that expires secs from
+ * now.  cert is the PEM encoded X.509 of the issuer's certificate as a string.
+ * certlen is the length of cert.  Returns the XML. Caller is responsible for
+ * freeing it. */
+    char *attr_cert=my_make_credential(role_string, attr->validity, id_chunk.ptr, id_chunk.len);
+
+    if (attr_cert == NULL)
+        return 0;
+
+    attr->cert.ptr = (unsigned char *)attr_cert;
+    attr->cert.len = strlen(attr_cert);
+
+    free(role_string);
+    return 1;
+}
+
+// make an explicit copy
+int abac_attribute_cert_chunk(abac_attribute_t *attr, abac_chunk_t *chunk) {
+
+    chunk->ptr=NULL;
+    chunk->len=0;
+
+    if (attr->cert.ptr == NULL)
+        return 0;
+
+    /* return the xml chunk */
+    chunk->ptr= (unsigned char *)abac_xstrdup((char *)attr->cert.ptr);
+    chunk->len=attr->cert.len;
+    return chunk->len;
+}
+
+int abac_attribute_baked(abac_attribute_t *attr) {
+    return (attr->cert.ptr != NULL);
+}
+
+
+static abac_attribute_t *_load_attr(char *role_string, char *xml)
+{
+
+if(debug) fprintf(stderr,"loading -> %s \n", role_string);
+
+    char *head_tail[2];
+    int ret;
+    abac_split(role_string, "<-", head_tail, &ret);
+    if (ret != 2) return NULL; 
+
+    char *keyid=get_keyid_from_xml(xml);
+    abac_id_t *issuer_id=abac_verifier_lookup_id(keyid);
+
+    long validity=get_validity_from_xml(xml);
+    
+    abac_attribute_t *attr = abac_xmalloc(sizeof(abac_attribute_t));
+    if(issuer_id)
+        attr->issuer_id = abac_id_dup(issuer_id);
+        else attr->issuer_id=NULL;
+    attr->validity = validity;
+
+    attr->head_string = abac_xstrdup(head_tail[0]);
+    attr->tail_string = abac_xstrdup(head_tail[1]);
+    char *tmp=strstr(attr->head_string,".");
+    attr->role =abac_xstrdup(tmp+1);
+
+    attr->cert.ptr=(unsigned char *)xml;
+    attr->cert.len=strlen(xml);
+
+    return attr;
+}
+
+abac_list_t *abac_attribute_certs_from_file(char *filename)
+{
+    abac_list_t *alist=abac_list_new();
+    char *xml=NULL;
+    char *rt0=NULL;
+
+    char **rt0s=my_read_credential(filename, &xml);
+    if(xml == NULL) return alist;
+
+    int len=strlen(xml);
+    if(len==0) return alist;
+
+    abac_attribute_t *attr;
+
+    int i=0;
+    do {
+        rt0 = rt0s[i]; 
+        if(rt0 == NULL) break;
+        attr=_load_attr(rt0, xml);
+        if(attr)
+            abac_list_add(alist, attr);
+        free(rt0);
+        i++;
+    } while (rt0s[i] !=NULL);
+
+    free(rt0s);
+    free(xml);
+
+    return alist;
+}
+
+abac_list_t *abac_attribute_certs_from_chunk(abac_chunk_t chunk) {
+
+    abac_list_t *alist=abac_list_new();
+    char *xml=(char *)chunk.ptr;
+    char **rt0s=get_rt0_from_xml(xml);
+    char *rt0=NULL;
+    int len=strlen(xml);
+    if(len==0) return alist;
+
+    abac_attribute_t *attr;
+    int i=0;
+    do {
+        rt0 = rt0s[i]; 
+        if(rt0 == NULL) break;
+        attr=_load_attr(rt0, xml);
+        if(attr)
+            abac_list_add(alist, attr);
+        free(rt0);
+        i++;
+    } while (rt0s[i] !=NULL);
+
+    free(rt0s);
+    return alist;
+}
+
+// returns 0 if the cert hasn't been baked
+int abac_attribute_write(abac_attribute_t *attr, FILE *out) {
+    assert(attr != NULL);
+
+    if (attr->cert.ptr == NULL)
+        return 0;
+
+    // write to file
+    fwrite(attr->cert.ptr, attr->cert.len, 1, out);
+
+    return 1;
+}
+
+void abac_attribute_free(abac_attribute_t *attr) {
+
+if(debug) fprintf(stderr,"calling abac_attribute_free on %s\n", attr->head_string);
+
+    if (attr == NULL)
         return;
+
+    if(attr->issuer_id) abac_id_free(attr->issuer_id);
+
+    free(attr->role);
+    free(attr->head_string);
+    free(attr->tail_string);
+
+/* XXX this can not be free as if it is a char string
+    free(attr->cert.ptr);
+*/
+
+    free(attr);
+}
+
+//
+// Helper functions below
+//
+
+// validate a princpal's name
+// makes sure it's a valid SHA1 identifier
+// return values:
+//  success: malloc'd copy with all hex digits lowercase
+//  fail: NULL
+static char *_validate_principal(char *keyid) {
+    int i;
+    char *copy = NULL;
+
+    if (strlen(keyid) != SHA1_LENGTH)
+        return NULL;
+
+    copy = abac_xstrdup(keyid);
+    for (i = 0; i < SHA1_LENGTH; ++i) {
+        copy[i] = tolower(copy[i]);
+        if (!isxdigit(copy[i]))
+            goto error;
     }
-    char *encoded_attr_string=attr_cert->get_string(attr_cert);
-    if(encoded_attr_string==NULL) {
-        fprintf(stderr,"BAD empty, encoded attr string from the cert !!!\n");
-/*
-    chunk_t b64 = chunk_to_base64(chunk, NULL);
-    chunk_t chk = chunk_from_base64(base64, NULL);
-*/
-       int len = strlen(estring);
-       chunk_t b64 = { estring, len };
-       chunk_t chk= chunk_from_base64(b64, NULL);
-       chk.ptr[chk.len]='\0';
-       fprintf(stderr,"new convert: (%s)\n", chk.ptr);
-       chunk_t nb64 = chunk_to_base64(chk, NULL);
-       fprintf(stderr,"back again: (%d)(%s)\n", strlen(nb64.ptr), nb64.ptr);
-    }
-}
-
-int abac_attribute_bake(abac_attribute_t *ptr) {
-    assert(ptr);
-
-    char *cred_encoding = get_cred_encoding(ptr);
-
-    // create attribute cert
-    time_t not_before = time(NULL);
-    time_t not_after = not_before + ptr->validity;
-    chunk_t serial = abac_generate_serial();
-
-    private_key_t *private = abac_id_privkey(ptr->issuer_id);
-
-    if(private==NULL)
-        errx(1,"can not bake without a private key!!!"); 
-
-/**** XXX this needs to be removed !!!!! limitation from strongswan... ****/
-    if(strlen(cred_encoding) > 512) {
-        fprintf(stderr,"due to BUILD_IETF_GROUP_ATTR buffer size limit, can not bake this attribute (%d)!!\n", strlen(cred_encoding));
-        return 0;
-    }
-
-    certificate_t *attr_cert = lib->creds->create(lib->creds,
-        CRED_CERTIFICATE, CERT_X509_AC,
-        BUILD_CERT, abac_id_cert(ptr->issuer_id),
-        BUILD_NOT_BEFORE_TIME, not_before,
-        BUILD_NOT_AFTER_TIME, not_after,
-        BUILD_SERIAL, serial,
-        BUILD_IETF_GROUP_ATTR, cred_encoding,
-        BUILD_SIGNING_CERT, abac_id_cert(ptr->issuer_id),
-        BUILD_SIGNING_KEY, private,
-        BUILD_END
-    );
-
-    _check_cert_group(attr_cert, cred_encoding);
-
-    DESTROY_IF(private);
-
-    if (attr_cert == NULL)
-        return 0;
-
-    ptr->cert = attr_cert;
-// cert and issuer can be the same, in which case it is the self signing
-    ptr->issuer_cert= attr_cert->get_ref(attr_cert);
- 
-    free(cred_encoding);
-    free(serial.ptr);
-    return 1;
-}
-
-abac_chunk_t abac_attribute_cert_chunk(abac_attribute_t *ptr) {
-    assert(ptr->cert);
-    chunk_t encoding = chunk_empty;
-    int rc=ptr->cert->get_encoding(ptr->cert,CERT_ASN1_DER,&encoding);
-    abac_chunk_t ret = { encoding.ptr, encoding.len };
-    return ret;
-}
-
-/* just loading it without any verifying */
-certificate_t *abac_attribute_cert_from_file(char *filename) {
-
-    if(!file_exist(filename)) return NULL;
-
-    libabac_init();
-
-    certificate_t *cert = cert_get_attr_cert_from_file(filename);
-    if (cert == NULL)
-        errx(1, "Couldn't load attribute cert %s", filename);
-
-    return cert;
-}
-
-
-certificate_t *abac_attribute_cert_from_chunk(abac_chunk_t achunk) {
-
-    chunk_t chunk = { .ptr = achunk.ptr, .len = achunk.len };
-    if(achunk.len == 0) {
-        errx(1, "Couldn't load attribute chunk, size of 0");
-    }
-
-    libabac_init();
-    certificate_t *cert = cert_get_attr_cert_from_chunk(chunk);
-    if (cert == NULL)
-        errx(1, "Couldn't load attribute chunk");
-
-    return cert;
-}
-
-
-/**
- * Load an attribute cert with a cert.
- * Returns true only if the certificate is valid and is issued by the proper
- * authority.
- * attribute string is parsed via yyparse call
- */
-static abac_attribute_t *_load_attribute_from_cert(certificate_t *cert)
-{
-    ietf_attributes_t *attr_cert = NULL;
-    int ret, i;
-    int using_this=0;
-
-    // get the attr
-    ac_t *ac = (ac_t *)cert;
-    attr_cert = ac->get_groups(ac);
-    if (attr_cert == NULL) {
-        ret = ABAC_CERT_INVALID;
-        goto error;
-    }
-
-    char *encoded_attr_string=attr_cert->get_string(attr_cert);
-    char *attr_string = abac_decode_string(encoded_attr_string);
-    if(debug)
-         fprintf(stderr, "string to be yyparse..(%d)(%s)\n",strlen(attr_string),attr_string);
-
-    if (attr_string == NULL) {
-        ret = ABAC_CERT_INVALID;
-        goto error;
-    }
-
-    abac_id_credential_t *id_cred;
-    abac_id_t *issuer_id;
-
-    /* reset lex input line, call into yacc parser */
-    abac_aspect_t *head_aspect = NULL;
-    abac_aspect_t *tail_aspect = NULL;
-    int rc=abac_yy_parse(NULL, attr_string, &head_aspect, &tail_aspect, &using_this);
-    if (rc) {
-        ret = ABAC_CERT_INVALID;
-        goto error;
-    }
-
-    // get the issuer based on keyid
-    char *principalname = abac_aspect_principal_principalname(head_aspect);
-    if(debug) fprintf(stderr, "LOOKING for %s\n", principalname);
-   
-    id_cred = abac_id_credential_lookup(principalname);
-    if(id_cred == NULL) {
-        ret = ABAC_CERT_MISSING_ISSUER;
-        if(debug)
-             fprintf(stderr, "can not find %s in id_creds\n", principalname);
-        goto error;
-    }
-
-    issuer_id=abac_id_credential_id(id_cred);
-    if (issuer_id == NULL) {
-        ret = ABAC_CERT_MISSING_ISSUER;
-        if(debug)
-             fprintf(stderr, "can not find %s in id_creds\n", principalname);
-        goto error;
-    }
-   // make sure the issuer's signed it
-    ret = verify_signature(abac_id_cert(issuer_id), cert);
-    if (!ret) {
-        abac_yy_set_error_code(ABAC_RT_CERT_BAD_SIG);
-        ret=ABAC_CERT_BAD_SIG;
-        goto error;
-    }
-
-    // at this point we know we have a good attribute cert baked it in
-    abac_attribute_t *attr=abac_attribute_new(issuer_id, cert, cert->get_ref(cert));
-    abac_attribute_set_head(attr, head_aspect);
-    abac_attribute_add_tail(attr, tail_aspect);
-    abac_attribute_set_using_this(attr, using_this);
-
-    // free up some stuff
-    attr_cert->destroy(attr_cert);
-
-    return attr;
+
+    return copy;
 
 error:
-    if (cert) cert->destroy(cert);
-    errx(1, "fail to extract attribute from a cert properly\n");
-}
-
-abac_attribute_t *abac_attribute_from_chunk(abac_chunk_t achunk)
-{
-    certificate_t *cert=abac_attribute_cert_from_chunk(achunk);
-    abac_attribute_t *ret=_load_attribute_from_cert(cert);
-    return ret;
-}
-
-// returns 0 if the cert hasn't been baked
-int abac_attribute_baked(abac_attribute_t *ptr) {
-    return ptr->cert != NULL;
-}
-
-int abac_attribute_write_cert(abac_attribute_t *ptr, FILE *out) {
-    assert(ptr != NULL);
-
-    if (ptr->cert == NULL)
-        return 0;
-
-    // write to file
-    chunk_t encoding = chunk_empty;
-    int rc=ptr->cert->get_encoding(ptr->cert,CERT_ASN1_DER,&encoding);
-
-    if(rc) {
-        fwrite(encoding.ptr, encoding.len, 1, out);
-        free(encoding.ptr);
-        return 1;
-    }
-    return 0;
-}
-
-abac_attribute_t *abac_attribute_dup(abac_attribute_t *ptr)
-{
-    assert(ptr);
-    abac_id_dup(ptr->issuer_id);
-    ++ptr->refcount;
-    return ptr;
-}
-
-static certificate_t *_cert_copy(certificate_t *cert)
-{
-    if(cert==NULL) return NULL;
-    chunk_t encoding = chunk_empty;
-    int rc=cert->get_encoding(cert,CERT_ASN1_DER,&encoding);
-    certificate_t *ncert = cert_get_attr_cert_from_chunk(encoding);
-    return ncert;
-}
-
-/* deep copy of a attribute structure, this is used by libabac
-   api so that we can have a local control of the data within
-   libabac
-*/
-abac_attribute_t *abac_attribute_copy(abac_attribute_t *ptr)
-{
-    assert(ptr);
-    abac_aspect_t *tmp;
-    abac_attribute_t *nptr = _abac_attribute_init();
-    nptr->issuer_id = abac_id_copy(ptr->issuer_id);
-    nptr->head=abac_aspect_copy(abac_attribute_head(ptr));
-    nptr->tail=abac_aspect_copy(abac_attribute_tail(ptr));
-
-    nptr->validity= ptr->validity;
-    nptr->using_this = ptr->using_this;
-    certificate_t *attr_cert=_cert_copy(ptr->cert);
-    nptr->cert=attr_cert; // already baked..
-    if(attr_cert) 
-        nptr->issuer_cert= attr_cert->get_ref(attr_cert);
-    nptr->refcount=ptr->refcount+1;
-    return nptr;
-}
-
-void abac_attribute_free(abac_attribute_t *ptr) {
-    int i;
-
-    if (ptr == NULL)
-        return;
-
-    --ptr->refcount;
-    if (ptr->refcount > 0)
-        return;
-
-    if(ptr->issuer_id) abac_id_free(ptr->issuer_id);
-    if(ptr->head) abac_aspect_free(ptr->head);
-    if(ptr->tail) abac_aspect_free(ptr->tail);
-
-    if(ptr->cert) DESTROY_IF(ptr->cert);
-    if(ptr->issuer_cert) DESTROY_IF(ptr->issuer_cert);
-    free(ptr);
-}
-
-
-char *abac_attribute_string(abac_attribute_t *ptr) 
-{
-    char *head=abac_aspect_string_with_condition(ptr->head);
-    char *tail=abac_aspect_string_with_condition(ptr->tail);
-    if(head==NULL || tail==NULL)
-        errx(1, "attribute string, head and tail can not be NULL");
-    char *tmp=NULL;
-    asprintf(&tmp,"%s<-%s",head,tail);
-    return tmp;
-}
-char *abac_attribute_typed_string(abac_attribute_t *ptr) 
-{
-    char *head=abac_aspect_typed_string_with_condition(ptr->head);
-    char *tail=abac_aspect_typed_string_with_condition(ptr->tail);
-    if(head==NULL || tail==NULL)
-        errx(1, "attribute typed string, head and tail can not be NULL");
-    char *tmp=NULL;
-    asprintf(&tmp,"%s<-%s",head,tail);
-    return tmp;
-}
-
-/********************************************************************/
-certificate_t *abac_attribute_issuer_cert(abac_attribute_t *ptr)
-{
-   assert(ptr);
-   return ptr->issuer_cert;
-}
-
-abac_aspect_t *abac_attribute_head(abac_attribute_t *ptr)
-{
-    assert(ptr);
-    return ptr->head;
-}
-
-int abac_attribute_is_role(abac_attribute_t *ptr)
-{
-    assert(ptr);
-    assert(ptr->head);
-    return abac_aspect_is_role(ptr->head);
-}
-
-abac_attribute_t *abac_attribute_set_head(abac_attribute_t *ptr, abac_aspect_t *head)
-{
-    assert(ptr);
-    ptr->head=head;
-    return ptr;
-}
-
-void abac_attribute_set_using_this(abac_attribute_t *ptr, int using_this)
-{
-    assert(ptr);
-    ptr->using_this=using_this;
-}
-
-int abac_attribute_get_this(abac_attribute_t *ptr)
-{
-    assert(ptr);
-    return ptr->using_this;
-}
-
-abac_aspect_t *abac_attribute_tail(abac_attribute_t *ptr)
-{
-    assert(ptr);
-    return ptr->tail;
-}
-
-abac_attribute_t *abac_attribute_add_tail(abac_attribute_t *ptr, abac_aspect_t *tail)
-{
-    assert(ptr);
-    assert(tail);
-
-    /* type of head and tail has to match */
-    abac_aspect_t *head=abac_attribute_head(ptr);
-
-    if(debug) {
-        fprintf(stderr, "head->(%s)\n",abac_aspect_type_string(head));
-        fprintf(stderr, "tail->(%s)\n",abac_aspect_type_string(tail));
-    }
-    if(abac_aspect_is_intersecting(tail)) {
-        if(debug) {
-            fprintf(stderr, "tail is intersection \n");
-            fprintf(stderr, "tail is (%s)\n", abac_aspect_string_with_condition(tail));
-        }
-        if(abac_aspect_intersecting_aspect_type(tail) != abac_aspect_aspect_type(head))
-            errx(1, "head and intersecting tail's aspect type does not match");
-        } else {
-            if(abac_aspect_aspect_type(head) != abac_aspect_aspect_type(tail)) {
-                if(debug)
-                    fprintf(stderr, "tail is (%s)\n", abac_aspect_string_with_condition(tail));
-                errx(1, "head and tail's aspect type does not match");
-            }
-    }
-
-    if(ptr->tail == NULL) {
-        ptr->tail=abac_aspect_dup(tail);
-        } else {
-            if(abac_aspect_is_intersecting(ptr->tail)) {
-                abac_aspect_add_intersecting_aspect(ptr->tail, tail);
-                } else {
-    /* special case.. if there is a tail there already and it is not an intersecting 
-       tail, need to turn this into an intersecting tails */
-                    abac_aspect_t *nptr=abac_aspect_intersection_new(ptr->tail);
-                    abac_aspect_add_intersecting_aspect(nptr, tail);
-                    ptr->tail=nptr;
-            }
-    }
-    return ptr;
-}
-
-certificate_t *abac_attribute_cert(abac_attribute_t *ptr)
-{
-    assert(ptr);
-    return ptr->cert;
-}
-
-int abac_attribute_lastone(abac_attribute_t *ptr)
-{
-    assert(ptr);
-    if(ptr->refcount == 1)
-        return 1;
-    return 0;
-}
-
-
-abac_aspect_t **abac_attribute_tail_vectorized(abac_attribute_t *ptr)
-{
-    abac_aspect_t **tails=NULL;
-    abac_aspect_t *tail=ptr->tail;
-    abac_list_t *list=NULL;
-    int cnt=0;
-    if(tail != NULL) {
-        if(!abac_aspect_is_intersecting(tail)) {
-            tails = abac_xmalloc(sizeof(abac_aspect_t *) * 2);
-            tails[0] = abac_aspect_dup(tail);
-            tails[1] = NULL;
-            if(debug) {
-               fprintf(stderr, "abac_attribute_tail_vectorized, only 1 tail\n");
-            }
-            return tails;
-            } else {
-                abac_list_t *list=abac_aspect_prereqs(tail);
-                cnt=abac_list_size(list);
-        }
-    }
-    // make the array (leave space to NULL terminate it)
-    //      n.b., even if the list is empty, we still return an array that
-    //            only contains the NULL terminator
-    tails = abac_xmalloc(sizeof(abac_aspect_t *) * (cnt + 1));
-    abac_aspect_t  *cur;
-    int i = 0;
-    if(i<cnt) {
-        abac_list_foreach(list, cur,
-            tails[i++] = abac_aspect_dup(cur);
-        );
-    }
-    tails[i] = NULL;
-    if(debug)
-        fprintf(stderr, "abac_attribute_tail_vectorized, %d tails\n", cnt);
-    return tails;
-}
-
-void abac_aspects_free(abac_aspect_t **aspects)
-{
-    /* always null terminating */
-    assert(aspects);
-    int i;
-    for (i = 0; aspects[i] != NULL; ++i) {
-        abac_aspect_free(aspects[i]);
-    }
-    free(aspects);
-}
+    free(copy);
+    return NULL;
+}
+
+// combine up the attribute's rule string, explicit copy
+char *abac_attribute_role_string(abac_attribute_t *attr) {
+    assert(attr);
+
+    char *role_string=NULL;
+    asprintf(&role_string,"%s<-%s",attr->head_string,attr->tail_string);
+    return role_string;
+}
+
+
