Index: libabac/abac_context.c
===================================================================
--- libabac/abac_context.c	(revision 2e9455f11fea0205b8b4b1306b5d0804cda72e10)
+++ libabac/abac_context.c	(revision 2e9455f11fea0205b8b4b1306b5d0804cda72e10)
@@ -0,0 +1,1566 @@
+/**
+**  abac_context.c
+**/
+
+#include <assert.h>
+#include <err.h>
+#include <glob.h>
+#include <stdio.h>
+#include <regex.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <chunk.h>
+
+#include "abac_util.h"
+
+#include "abac_context.h"
+#include "abac_list.h"
+#include "abac_stack.h"
+#include "abac_pl_yap.h"
+#include "abac_pl_yy.h"
+#include "uthash.h"
+#include "abac_id.h"
+#include "abac_verifier.h"
+#include "abac_id.h"
+#include "abac_pl_gen.h"
+#include "abac_attribute.h"
+#include "abac_aspect.h"
+#include "abac_m64.h"
+#include "rt2_yy.h"
+#include "abac_util_cert.h"
+
+static int debug=0;
+
+#define KEY_PAT "/*_private.{der,pem}"
+#define ID_PAT "/*_ID.{der,pem}"
+#define ATTR_PAT "/*_attr.der"
+#define IDKEY_PAT "/*_IDKEY.{der,pem}"
+
+struct _abac_context_t {
+    char *namespace;
+    abac_pl_t *pl; /* prolog query structure */
+
+    abac_list_t *context_pl_clauses;
+
+/* linked list of all the ids's hashkeyid */
+    abac_list_t *context_id_hashkeyid_list;
+
+/* linked list of all the attr's hashkeyid */
+    abac_list_t *context_attr_hashkeyid_list;
+};
+
+/* local */
+int abac_context_load_id_id(abac_context_t *ctxt,abac_id_t *id);
+static chunk_t _extract_chunk(char *data, char* startline, char* endline);
+int abac_context_load_attribute_credential(abac_context_t *, abac_attribute_t *, abac_credential_t *);
+/****************************************************************/
+/**
+ * Create a new abac context.
+ */
+abac_context_t *abac_context_new(void)
+{
+    libabac_init();
+
+    DEBUG_PRINTF("creating a new context... \n");
+
+    abac_context_t *ctxt = abac_xmalloc(sizeof(abac_context_t));
+    ctxt->namespace=abac_verifier_session_next_namespace();
+    ctxt->pl = abac_pl_new(ctxt);
+    ctxt->context_attr_hashkeyid_list = abac_list_new();
+    ctxt->context_id_hashkeyid_list = abac_list_new();
+    ctxt->context_pl_clauses = abac_list_new();
+    abac_verifier_session_add_context(ctxt);
+    return ctxt;
+}
+
+/* create a new context with a specific namespace */
+abac_context_t *abac_context_named_new(char *namespace)
+{
+    assert(namespace!=NULL);
+    libabac_init();
+
+    abac_context_t *ctxt = abac_xmalloc(sizeof(abac_context_t));
+    ctxt->namespace=abac_xstrdup(namespace);
+    ctxt->pl = abac_pl_new(ctxt);
+    ctxt->context_attr_hashkeyid_list = abac_list_new();
+    ctxt->context_id_hashkeyid_list = abac_list_new();
+    ctxt->context_pl_clauses = abac_list_new();
+    abac_verifier_session_add_context(ctxt);
+    return ctxt;
+}
+
+char *abac_context_namespace(abac_context_t *ctxt)
+{
+    assert(ctxt!=NULL);
+    return abac_xstrdup(ctxt->namespace);
+}
+
+/**
+ * Deep copy an abac context. --
+ */
+abac_context_t *abac_context_dup(abac_context_t *ctxt)
+{
+    assert(ctxt!=NULL);
+    abac_context_t *dup = abac_xmalloc(sizeof(abac_context_t));
+    dup->namespace=abac_verifier_session_next_namespace();
+    dup->pl = abac_pl_new(dup);
+
+    dup->context_attr_hashkeyid_list = abac_list_new();
+    dup->context_id_hashkeyid_list = abac_list_new();
+    dup->context_pl_clauses = abac_list_new();
+
+/* copy over and build up the prolog */
+   if(ctxt->context_id_hashkeyid_list) {
+        abac_id_credential_t *id_cred;
+        abac_id_t *id;
+        char *cur;
+        abac_list_foreach(ctxt->context_id_hashkeyid_list, cur,
+            if(cur) {
+/* id_cred=abac_check_id_cred(cur); */
+                id_cred=abac_id_credential_lookup(cur);
+                id=abac_id_credential_id(id_cred);
+                assert(id!=NULL);
+                /* id=abac_id_dup(id); */
+                abac_context_load_id_id(dup,id);
+            }
+        );
+    }
+    if(ctxt->context_attr_hashkeyid_list) {
+        abac_credential_t *attr_cred;
+        abac_attribute_t *attr;
+        char *cur;
+        int sz=abac_list_size(ctxt->context_attr_hashkeyid_list);
+        abac_list_foreach(ctxt->context_attr_hashkeyid_list, cur,
+            if(cur) { /* cur is the hash key */
+/* attr_cred=abac_check_cred(cur); */
+                attr_cred=abac_credential_lookup(cur);
+                assert(attr_cred);
+                attr=abac_credential_attribute(attr_cred);
+                assert(attr);
+                /* attr=abac_attribute_dup(attr); 
+                abac_context_load_attribute_credential(dup,attr,attr_cred);
+                */
+                abac_context_load_attribute_attribute(dup,attr);
+            }
+        );
+    }
+    abac_verifier_session_add_context(dup);
+    return dup;
+}
+
+/**************************************************************/
+abac_id_credential_t *abac_context_add_id_credential(abac_context_t *ctxt, abac_id_t *a_id)
+{ 
+    char *cn=abac_id_cn(a_id);
+    char *keyid=abac_id_keyid(a_id);
+
+    /* see if it already exist */
+    abac_id_credential_t *id_cred;
+    id_cred=abac_id_credential_lookup(keyid);
+
+    /* add to master list if new */
+    if(id_cred == NULL) {
+        id_cred=abac_id_credential_new(a_id);
+        abac_add_id_cred(id_cred); 
+        } else { /* increment the reference count */
+            id_cred=abac_id_credential_dup(id_cred);
+    }
+
+    DEBUG_PRINTF("abac_context_add_id_credential, cn(%s)keyid(%s)\n",cn,keyid);
+    /* special handling here */
+    char *tmp;
+    if(USE("ABAC_CN")) {
+        tmp=generate_pl_type_clause(ctxt, cn, abac_id_idtype(a_id));
+        } else {
+           tmp=generate_pl_type_clause(ctxt, prologIt(keyid), abac_id_idtype(a_id));
+    }
+    abac_list_add(ctxt->context_pl_clauses,tmp);
+
+    /* insert into db */
+   int rc=abac_pl_add_type_credential(tmp);
+   
+    /* add to local hash list */
+    abac_list_add(ctxt->context_id_hashkeyid_list,
+                   abac_xstrdup(abac_id_credential_hashkey(id_cred)));
+
+    return id_cred;
+}
+
+/* have to find the last cn 
+   CN=test/emailAddress=abac.isi.edu, CN=12345678
+   CN=client
+   ..CN=255a03f3-ed30/emailAddress=..
+*/
+static char* _extract_cn(char *string)
+{
+    /* find the first CN= */
+    char *ptr=strstr(string,"CN=");
+    if(ptr == NULL) return NULL;
+
+    /* look for last CN= */
+    while(1) {
+       char *tptr=ptr+3;
+       char *p=strstr(tptr,"CN=");
+       if(p) ptr=p;
+           else break;
+    }
+
+    /* remove the possible additional stuff */
+    char *cn=abac_xstrdup(ptr); /* it would get write over */
+    char *nptr=strtok(cn,"/");
+    char *pcn=abac_xmalloc(sizeof(char) * strlen(nptr));
+    pcn[0]='p';
+    /* special case.. replace empty space with _ */
+    int i=strlen(nptr);
+    while(i--) 
+       if(nptr[i]==' ') nptr[i]='_';
+    sscanf(nptr,"CN=%s", &pcn[1]);
+    free(cn);
+    return pcn;
+}
+
+// convert a chunk to a lowercase binary string
+// malloc's the string
+static char *_chunk_to_string(chunk_t chunk) {
+    int i;
+
+    char *ret = abac_xmalloc(chunk.len * 2 + 1);
+
+    for (i = 0; i < chunk.len; ++i)
+        sprintf(ret + 2 * i, "%02x", chunk.ptr[i]);
+
+    return ret;
+}
+
+// verify that cert is still valid
+static int _verify_validity(certificate_t *cert) {
+    if (cert->get_validity(cert, NULL, NULL, NULL))
+        return 1;
+    return 0;
+}
+
+/**
+ * Load an ID 
+ */
+static int _load_id(abac_context_t *ctxt, abac_id_t **a_id,certificate_t *cert)
+{
+    int ret;
+    abac_id_credential_t *id_cred = NULL;
+
+    assert(cert != NULL);
+
+    // get the key ID, add p to keyid SHA here */
+    char *keyid =cert_get_keyid(cert);
+
+    /* Mike said this is the way it is */
+    char *str=NULL;
+    int rv = asprintf(&str, "%Y", cert->get_issuer(cert));
+
+    /* add p to cn name here, if there is no useable one
+       reuse keyid */
+    char *cn=_extract_cn(str);
+    if(cn == NULL) {
+        DEBUG_PRINTF("DEBUG:did not find usable cn, reuse keyid\n");
+        cn=abac_xstrdup(keyid);
+    }
+
+    DEBUG_PRINTF("DEBUG:keyid %s \n", keyid);
+    DEBUG_PRINTF("DEBUG:issuer '%s' \n", str);
+    DEBUG_PRINTF("DEBUG:cn %s \n", cn);
+    free(str);
+
+    // validate validity
+    ret = _verify_validity(cert);
+    if (!ret) {
+        ret = ABAC_CERT_INVALID;
+        goto error;
+    }
+
+    // validate sig
+    ret = verify_signature(cert, cert);
+    if (!ret) {
+        /* well.. this is not a self signed cert, don't fault it anymore */
+        DEBUG_PRINTF("This is not a self-signed cert \n");
+        } else {
+            DEBUG_PRINTF("This is a self-signed cert \n");
+    }
+
+    // if we already have this cert in the context, 'error' with success
+    id_cred=abac_context_id_credential_lookup(ctxt, keyid);
+    if (id_cred != NULL) {
+        DEBUG_PRINTF("existing cert \n");
+        /* needs to increment the ref count */
+        abac_id_credential_dup(id_cred);
+        ret = ABAC_CERT_EXISTS;
+        goto error;
+        } else {
+            // if we don't have it in context but in session, then
+            // we need to insert into the local context
+            abac_id_credential_t *icred=abac_id_credential_lookup(keyid);
+            if(icred!=NULL) {
+                *a_id=abac_id_credential_id(icred);
+                 DEBUG_PRINTF("_load_id:already exists in session.(%s)\n",abac_id_cn(*a_id));
+                } else  {
+                   // all else fail.. insert as a new id 
+                   if(*a_id==NULL) *a_id=abac_id_keyid_new(keyid,cn,cert);
+            }
+            id_cred=abac_context_add_id_credential(ctxt,*a_id);
+    }
+
+    if (keyid != NULL) free(keyid);
+    if (cn != NULL) free(cn);
+    return ABAC_CERT_SUCCESS;
+
+error:
+    if (keyid != NULL) free(keyid);
+    if (cn != NULL) free(cn);
+
+    return ret;
+}
+
+
+int abac_context_creds_count(abac_context_t *ctxt)
+{
+    int sz=abac_list_size(ctxt->context_attr_hashkeyid_list);
+    return sz;
+}
+
+int abac_context_id_creds_count(abac_context_t *ctxt)
+{
+    int sz=abac_list_size(ctxt->context_id_hashkeyid_list);
+    return sz;
+}
+
+/* collect all the creds for this context */
+abac_stack_t *abac_context_dump_creds(abac_context_t *ctxt)
+{
+    abac_stack_t *cred_list = abac_stack_new();
+
+    int cnt=0;
+    if(ctxt->context_attr_hashkeyid_list) {
+        char *keyid=NULL;
+        abac_credential_t *cred=NULL;
+        abac_list_foreach(ctxt->context_attr_hashkeyid_list, keyid,
+            cred=abac_credential_lookup(keyid);
+            if(cred!=NULL)
+                abac_stack_push(cred_list, abac_credential_dup(cred));
+                else {
+                    char *btmp=abac_decode_string(keyid);
+                    fprintf(stderr,"??? BADDD (%s)\n", btmp);
+                    assert(0);
+                }
+            cnt++;
+        );
+    }
+    DEBUG_PRINTF("abac_context_dump_creds: %d\n",cnt);
+    return cred_list;
+}
+
+/* collect all the id stored for this context */
+abac_stack_t *abac_context_dump_principals(abac_context_t *ctxt)
+{
+    abac_stack_t *id_list = abac_stack_new();
+
+    int cnt=0;
+    int sz=abac_list_size(ctxt->context_id_hashkeyid_list);
+
+    if(ctxt->context_id_hashkeyid_list) {
+        char *keyid;
+        abac_id_credential_t *id;
+        abac_list_foreach(ctxt->context_id_hashkeyid_list, keyid,
+            id=abac_id_credential_lookup(keyid);
+            abac_stack_push(id_list, abac_id_credential_dup(id));
+            cnt++;
+        );
+    }
+    DEBUG_PRINTF("abac_context_dump_principals: %d\n",cnt);
+    return id_list;
+}
+
+/**
+ * Load an attribute cert as string.
+ * have minimum syntax & validity check
+ */
+static int _load_attribute_string(abac_context_t *ctxt, char* attr_string) {
+    printf("NOT implemented yet!!!");
+    return ABAC_CERT_INVALID;
+}
+
+/**
+ * Load an ID cert from a file and key from a file.
+ */
+int abac_context_load_id_id_key_files(abac_context_t *ctxt, char *filename,
+char *keyfilename)
+{
+    struct stat sb;
+
+    assert(ctxt != NULL);
+    assert(filename != NULL);
+
+    abac_id_t *id=NULL;
+    if (lib == NULL)
+        errx(1, "looks like you didn't call libabac_init() (lib is NULL)");
+
+    DEBUG_PRINTF("loading id & key files... %s\n", filename);
+    certificate_t *cert = cert_get_id_cert_from_file(filename);
+
+    if (cert == NULL)
+        return ABAC_CERT_INVALID;
+
+    int rc=_load_id(ctxt,&id,cert);
+
+    if(rc==ABAC_CERT_EXISTS) {
+        DEBUG_PRINTF("abac_context_load_id_id_key_files: id already exists\n");
+        return ABAC_CERT_SUCCESS;
+    } 
+
+    /* try to load the private key if it is there */
+    if((rc==ABAC_CERT_SUCCESS) && keyfilename!=NULL && file_exist(keyfilename)) {
+        DEBUG_PRINTF("loading... %s\n", keyfilename);
+        int keyrc=abac_id_load_privkey_file(id, keyfilename);
+        if(keyrc == 1)
+            DEBUG_PRINTF("..load id: load(%s) with a private key\n",filename)
+
+            else DEBUG_PRINTF("..load id: load(%s) without a private key\n",filename)
+    }
+
+    return ABAC_CERT_SUCCESS;
+}
+
+/**
+ * Load an ID cert from files.
+ */
+int abac_context_load_id_enc_id_key_files(abac_context_t *ctxt, char *filename,
+char *keyfilename, char *pfile)
+{
+    abac_id_t *id=NULL;
+    assert(ctxt != NULL); assert(filename != NULL); assert(keyfilename!=NULL);
+
+    if (lib == NULL)
+        errx(1, "looks like you didn't call libabac_init() (lib is NULL)");
+
+    DEBUG_PRINTF("loading enc id & key files... %s\n", filename);
+
+    // load the cert, with public key
+    certificate_t *cert = cert_get_id_cert_from_file(filename);
+    if (cert == NULL) return ABAC_CERT_INVALID;
+
+    int rc=_load_id(ctxt,&id,cert);
+    if(rc==ABAC_CERT_EXISTS) {
+        DEBUG_PRINTF("abac_context_load_id_id_key_files: id already exists\n");
+        return ABAC_CERT_SUCCESS;
+    } 
+
+    /* try to load the private key if it is there */
+    if((rc==ABAC_CERT_SUCCESS) && keyfilename!=NULL && file_exist(keyfilename)) {
+        DEBUG_PRINTF("loading... %s\n", keyfilename);
+        int keyrc=abac_id_load_enc_privkey_file(id, keyfilename, pfile);
+        if(keyrc == 1) 
+            DEBUG_PRINTF("..load id: load(%s) with a private key\n",filename)
+           else DEBUG_PRINTF("..load id: load(%s) without a private key\n",filename)
+    }
+    return ABAC_CERT_SUCCESS;
+}
+
+/**
+ * Load an ID cert from a abac_id_t, used from abac.hh and actually
+ * makes a separate copy
+ */
+int abac_context_load_id(abac_context_t *ctxt,abac_id_t *id)
+{
+    assert(ctxt != NULL); assert(id);
+    abac_id_t *nid = abac_id_copy(id);
+    certificate_t *cert = abac_id_cert(nid);
+    int ret=_load_id(ctxt,&nid,cert);
+    return ret;
+}
+
+/**
+ * Load an ID cert from a abac_id_t 
+ */
+int abac_context_load_id_id(abac_context_t *ctxt,abac_id_t *id)
+{
+    assert(ctxt != NULL); assert(id);
+
+    certificate_t *cert = abac_id_cert(id);
+    int ret=_load_id(ctxt,&id,cert);
+    return ret;
+}
+
+/**
+ * Load an ID cert from a pem chunk.
+ */
+int abac_context_load_id_pem_chunk(abac_context_t *ctxt, chunk_t chunk)
+{
+    abac_id_t *id=NULL;
+
+    // load the cert
+    certificate_t *cert = cert_get_id_cert_from_pem_chunk(chunk);
+    if (cert == NULL) return ABAC_CERT_INVALID;
+
+    return _load_id(ctxt,&id,cert);
+}
+
+/* used locally */
+static int _abac_context_load_id_pem_chunk(abac_context_t *ctxt, abac_id_t **a_id, chunk_t chunk)
+{
+    // load the cert
+    certificate_t *cert = cert_get_id_cert_from_pem_chunk(chunk);
+    if (cert == NULL) return ABAC_CERT_INVALID;
+
+    return _load_id(ctxt,a_id,cert);
+}
+
+/**
+ * Load an ID cert from a chunk, Note, this only loads the id cert part
+ * and so it is not suitable for creating an attribute credential with. 
+ * Only a complete id cert + privkey could create attribute credential.
+ */
+int abac_context_load_id_chunk(abac_context_t *ctxt, abac_chunk_t ccert)
+{
+    assert(ctxt != NULL);
+
+    chunk_t cert_chunk = { ccert.ptr, ccert.len };
+    abac_id_t *id=NULL;
+
+    // load the cert
+    certificate_t *cert = cert_get_id_cert_from_chunk(cert_chunk);
+
+    if (cert == NULL) return ABAC_CERT_INVALID;
+
+    int ret=_load_id(ctxt,&id,cert);
+    return ret;
+}
+
+/**
+ * Load an ID cert from a cert chunk and a privkey chunk,
+ * this complete id cert + privkey could create attribute credential.
+ */
+int abac_context_load_id_privkey_chunk(abac_context_t *ctxt,abac_chunk_t ccert,
+abac_chunk_t privkey)
+{
+    assert(ctxt != NULL);
+    chunk_t cert_chunk = { ccert.ptr, ccert.len };
+/*A HACK/SWIG, this is to work around the swig's stub that seems to
+  mess up the transformation from abac_chunk_t to chunk_t and calling of
+  load_id_chunks to here */
+    chunk_t privkey_chunk = { strndup(privkey.ptr,privkey.len), privkey.len };
+
+    abac_id_t *id=NULL;
+
+    // load the cert
+    certificate_t *cert = cert_get_id_cert_from_chunk(cert_chunk);
+    if (cert == NULL) return ABAC_CERT_INVALID;
+
+    int rc=_load_id(ctxt,&id,cert);
+    if(rc == ABAC_CERT_SUCCESS) {
+        rc=abac_id_load_privkey_chunk(id, privkey_chunk);
+    }
+
+    return rc;
+}
+
+/**
+ * Load an ID cert and privkey from chunks.
+ */
+int 
+abac_context_load_id_enc_privkey_chunk(abac_context_t *ctxt, abac_chunk_t ccert,
+abac_chunk_t privkey, char* pfile) {
+
+    assert(ctxt != NULL);
+    chunk_t cert_chunk = { ccert.ptr, ccert.len };
+/*A HACK/SWIG, this is to work around the swig's stub that seems to
+  mess up the transformation from abac_chunk_t to chunk_t and calling of
+  load_id_chunks to here */
+    chunk_t privkey_chunk = { strndup(privkey.ptr,privkey.len), privkey.len };
+
+    abac_id_t *id=NULL;
+    certificate_t *cert = cert_get_id_cert_from_chunk(cert_chunk);
+    if (cert == NULL) return ABAC_CERT_INVALID;
+
+    int rc=_load_id(ctxt,&id,cert);
+    if(rc == ABAC_CERT_SUCCESS) {
+        rc=abac_id_load_enc_privkey_chunk(id, privkey_chunk, pfile);
+    }
+    return rc;
+}
+
+
+static int matchex(const char *subject, const char *pattern, int *so, int *eo)
+{
+    int rc; // Returned code
+    regmatch_t pmatch;
+
+    regex_t re; // Compiled regexp pattern
+
+    if (regcomp(&re, pattern, 0) != 0) return 0;
+
+    rc = regexec(&re, subject, 1 , &pmatch, 0);
+    regfree(&re); 
+
+    if (rc == REG_NOMATCH ) return 0; 
+
+    *so=pmatch.rm_so;
+    *eo=pmatch.rm_eo;
+
+    return 1;
+}
+
+
+static chunk_t _extract_chunk(char *data, char* startline, char* endline)
+{
+    int found=0;
+    int startos=0;
+    int endos=0;
+    regex_t re;
+    regmatch_t pm;
+    int rc;
+
+    int st;
+    int et;
+
+    rc=matchex(data, startline, &st, &et);
+    if(rc==0) return chunk_empty;
+    startos=st;
+
+    rc=matchex(data, endline, &st, &et);
+    if(rc==0) return chunk_empty;
+    endos=et;
+    
+    int len=endos - startos; 
+
+    DEBUG_PRINTF("making a chunk of size (%d) from %d and %d\n",len, startos,endos);
+    char *ptr=strndup(data+startos,len);
+
+    chunk_t ret = { ptr, len };
+    return ret;
+}
+
+/**
+ * Load an ID cert from a file, it may contain key part but not necessary.
+ */
+int abac_context_load_id_idkey_file(abac_context_t *ctxt, char *filename)
+{
+    struct stat sb;
+    int fd;
+    int rc;
+    assert(ctxt != NULL); assert(filename != NULL);
+    abac_id_t *id=NULL;
+
+    DEBUG_PRINTF("abac_context_load_id_idkey_file(%s)\n", filename);
+
+    fd = open(filename, O_RDONLY);
+    if (fd == -1) { return 1; }
+    if(stat(filename, &sb) == -1) {
+        close(fd);
+        return 1;
+    }
+    char* data = (char *)mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+    if(data == MAP_FAILED) {
+        close(fd);
+        return 1;
+    }
+    close(fd);
+
+    chunk_t key_pem_chunk=_extract_chunk(data,
+               "-----BEGIN RSA PRIVATE KEY-----","-----END RSA PRIVATE KEY-----");
+    chunk_t cert_pem_chunk=_extract_chunk(data,
+                   "-----BEGIN CERTIFICATE-----","-----END CERTIFICATE-----");
+
+    /* key=0, cert=0 */
+    if(key_pem_chunk.len==0 && cert_pem_chunk.len==0) {
+        DEBUG_PRINTF("abac_context_load_id_idkey_file: no key or id in idkey_file\n");
+        goto error;
+    }
+
+    /* key=0, cert=1 */
+    if(key_pem_chunk.len==0) {
+        DEBUG_PRINTF("abac_context_load_id_idkey_file: no key in idkey_file\n");
+        munmap(data, sb.st_size);
+        chunk_free(&key_pem_chunk);
+        return abac_context_load_id_id_key_files(ctxt,filename,NULL);
+    }
+
+    /* key=1, cert=1 */
+    if(cert_pem_chunk.len!=0) {
+        DEBUG_PRINTF("loading cert pem chunk len(%d)\n", cert_pem_chunk.len);
+        rc=_abac_context_load_id_pem_chunk(ctxt,&id,cert_pem_chunk);
+        if(rc != 0) {
+            DEBUG_PRINTF("abac_context_load_id_idkey_file: fail to load the id\n");
+            goto error;
+        }
+    /* key=1, cert=0 */
+        } else {
+            DEBUG_PRINTF("abac_context_load_id_idkey_file: there is no id info in there\n");
+            goto error;
+    }
+    
+    /* handle the key_pem_chunk */
+    DEBUG_PRINTF("loading key pem chunk len(%d)\n", key_pem_chunk.len);
+    rc=abac_id_load_privkey_chunk(id, key_pem_chunk);
+    if(rc==0) {
+        printf("abac_context_load_id_idkey_file:failed to load priv key!!!\n");
+        goto error;
+    }
+
+    munmap(data, sb.st_size);
+    return 0;
+
+error:
+    munmap(data, sb.st_size);
+    return 1;
+}
+
+/**
+ * Load an ID cert from a file, it may contain encrypted key part but not necessary.
+ */
+int abac_context_load_id_enc_idkey_file(abac_context_t *ctxt, char *filename, char *pfile)
+{
+    struct stat sb;
+    int fd;
+    int rc;
+    abac_id_t *id=NULL;
+
+    assert(ctxt != NULL); assert(filename != NULL);
+    abac_id_credential_t *id_cert=NULL;
+
+    fd = open(filename, O_RDONLY);
+    if (fd == -1) { return 1; }
+    if(stat(filename, &sb) == -1) {
+        close(fd);
+        return 1;
+    }
+    char* data = (char *)mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+    if(data == MAP_FAILED) {
+    
+        return 1;
+    }
+    close(fd);
+
+    chunk_t key_pem_chunk=_extract_chunk(data,
+               "-----BEGIN RSA PRIVATE KEY-----","-----END RSA PRIVATE KEY-----");
+    chunk_t cert_pem_chunk=_extract_chunk(data,
+                   "-----BEGIN CERTIFICATE-----","-----END CERTIFICATE-----");
+
+    /* key=0, cert=0 */
+    if(key_pem_chunk.len==0 && cert_pem_chunk.len==0) {
+        DEBUG_PRINTF("abac_context_load_id_idkey_file: no key or id in idkey_file\n");
+        goto error;
+    }
+
+    /* key=0, cert=1 */
+    if(key_pem_chunk.len==0) {
+        DEBUG_PRINTF("abac_context_load_id_idkey_file: no key in idkey_file\n");
+        munmap(data, sb.st_size);
+        chunk_free(&key_pem_chunk);
+        return abac_context_load_id_id_key_files(ctxt,filename,NULL);
+    }
+
+    /* key=1, cert=1 */
+    if(cert_pem_chunk.len!=0) {
+        DEBUG_PRINTF("loading cert pem chunk len(%d)\n", cert_pem_chunk.len);
+        rc=_abac_context_load_id_pem_chunk(ctxt,&id,cert_pem_chunk);
+        if(rc != 0) {
+            DEBUG_PRINTF("abac_context_load_id_idkey_file: fail to load the id\n");
+            goto error;
+        }
+    /* key=1, cert=0 */
+        } else {
+            DEBUG_PRINTF("abac_context_load_id_idkey_file: there is no id info in there\n");
+            goto error;
+    }
+    
+    /* handle the key_pem_chunk */
+    DEBUG_PRINTF("loading key pem chunk len(%d)\n", key_pem_chunk.len);
+
+    rc=abac_id_load_enc_privkey_chunk(id, key_pem_chunk, pfile);
+    if(rc==0) {
+        printf("abac_context_load_id_idkey_file:failed to load priv key!!!\n");
+        goto error;
+    }
+
+    munmap(data, sb.st_size);
+    return 0;
+
+error:
+    munmap(data, sb.st_size);
+    return 1;
+}
+
+/* not duplicated */
+abac_id_credential_t *abac_context_id_credential_lookup(abac_context_t *ctxt,char *pname)
+{
+    int cnt=0;
+    assert(pname);
+    if(ctxt->context_id_hashkeyid_list) {
+        char *keyid;
+        abac_id_credential_t *id_cred;
+        abac_list_foreach(ctxt->context_id_hashkeyid_list, keyid,
+            if(strcmp(keyid,pname)==0) {
+                id_cred=abac_id_credential_lookup(keyid);
+                return id_cred;
+            }
+        );
+    }
+    return NULL;
+}
+
+void abac_context_id_credential_free(abac_context_t *ctxt, abac_id_credential_t *ptr)
+{
+    if (ptr == NULL)
+        return;
+
+    char *keyid=abac_id_credential_hashkey(ptr);
+
+    /* make sure it belongs to this context */
+    char *cur=NULL;
+    abac_list_foreach(ctxt->context_id_hashkeyid_list, cur,
+        if(strcmp(cur,keyid)==0) 
+            break;
+    );
+    assert(cur!=NULL);
+    abac_list_remove(ctxt->context_id_hashkeyid_list, cur);
+    free(cur);
+
+    abac_id_credential_free(ptr);
+}
+
+/****************************************************************************/
+static char *_get_keyid_from_cert(certificate_t *cert)
+{
+    assert(cert);
+    ac_t *ac=(ac_t *)cert;
+    ietf_attributes_t *attr_cert=ac->get_groups(ac);
+    if(attr_cert == NULL) {
+        char *tmp=NULL;
+        asprintf(&tmp,"_get_keyid_from_cert: fail to get keyid from certificate_t");
+        panic(tmp);
+    }
+    char *encoded_attr_string=attr_cert->get_string(attr_cert);
+    attr_cert->destroy(attr_cert);
+    return encoded_attr_string;
+}
+
+static int _verify_valid_credential_issuer(abac_context_t *ctxt, char* keyid,
+certificate_t *cert, abac_id_t **issuer_id)
+{
+    abac_id_credential_t *id_cred;
+    int ret, i;
+
+    // get the issuer based on keyid
+    id_cred=abac_context_id_credential_lookup(ctxt,keyid);
+    if(id_cred == NULL) {
+        ret = ABAC_CERT_MISSING_ISSUER;
+        DEBUG_PRINTF("_verify_valid_credential_issuer:can not find %s in id_creds\n", keyid);
+        goto error;
+    }
+
+    *issuer_id=abac_id_credential_id(id_cred);
+    if (*issuer_id == NULL) {
+        ret = ABAC_CERT_MISSING_ISSUER;
+        DEBUG_PRINTF("_verify_valid_credential_issuer:can not find %s in id_creds\n", keyid);
+        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;
+        DEBUG_PRINTF("_verify_valid_credential_issuer:signing policy failed for %s \n", keyid);
+        goto error;
+    }
+
+    return ABAC_CERT_SUCCESS;
+
+error:
+    return ret;
+}
+
+/* at this point we know we have a good attribute cert baked it in */
+static int _insert_valid_cred(abac_context_t *ctxt, abac_id_t *issuer_id,
+abac_aspect_t *head_aspect, abac_aspect_t *tail_aspect, certificate_t *cert,
+abac_credential_t **cred_ret, char *encoded_attr_string, int using_this)
+{
+    abac_list_t *clauses=NULL;
+    abac_id_credential_t *id_cred;
+    int ret, i;
+
+    // generate prolog clauses from aspect structures
+    clauses = generate_pl_clauses(ctxt,head_aspect, tail_aspect, encoded_attr_string,using_this);
+
+    // make a new credential if only is first
+    if(*cred_ret == NULL) {
+        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);
+        if(using_this) abac_attribute_set_using_this(attr,using_this);
+        *cred_ret=abac_credential_new(abac_attribute_copy(attr),encoded_attr_string); /* need a deep copy ? */
+        abac_add_cred(*cred_ret);
+    }
+
+    // add clauses
+    char *cur=NULL;
+    abac_list_foreach(clauses, cur,
+        abac_list_add(ctxt->context_pl_clauses, abac_xstrdup(cur));
+    );
+
+    /* add locally */
+    abac_list_add(ctxt->context_attr_hashkeyid_list, abac_xstrdup(encoded_attr_string));
+    /* insert into db */
+    int add_ret=abac_pl_add_credential(clauses);
+
+    DEBUG_PRINTF("-->adding into context attr_creds, [%s]hashkey(%s)..cnt(%d)\n",
+       ctxt->namespace,
+       encoded_attr_string, abac_list_size(ctxt->context_attr_hashkeyid_list));
+
+    return ABAC_CERT_SUCCESS;
+
+error:
+    if(head_aspect) abac_aspect_free(head_aspect);
+    if(tail_aspect) abac_aspect_free(tail_aspect);
+    return ABAC_CERT_INVALID;
+}
+
+/**
+ * Load an attribute cert.
+ * Returns true only if the certificate is valid and is issued by the proper
+ * authority.
+ * attribute string is parsed via yyparse call
+ */
+static int _load_attribute_cert(abac_context_t *ctxt, certificate_t *cert,
+abac_credential_t **cred_ret)
+{
+    int ret, i;
+    abac_aspect_t *head_aspect = NULL;
+    abac_aspect_t *tail_aspect = NULL;
+    int using_this=0;
+    assert(cert);
+
+    char *encoded_attr_string=_get_keyid_from_cert(cert);
+    if(encoded_attr_string==NULL ) {
+       fprintf(stderr,"this is bad in loading the cert, empty encoded_attr_string\n");
+       goto error;
+    }
+    /* see if it already exists in context */
+    abac_credential_t *cred=abac_context_credential_lookup(ctxt,encoded_attr_string);
+    if(cred != NULL) {
+        if(debug) fprintf(stderr,"trying to insert identical attribute into a context\n");
+        ret = ABAC_CERT_INVALID;
+        goto error;
+    }
+
+    char *attr_string = abac_decode_string(encoded_attr_string);
+    if (attr_string == NULL) {
+        ret = ABAC_CERT_INVALID;
+        goto error;
+    }
+
+    /* see if it exist ... */
+    *cred_ret=abac_credential_lookup(encoded_attr_string);
+    if(*cred_ret != NULL ) {
+       //already exist in session
+       abac_attribute_t *attr=abac_credential_attribute(*cred_ret);
+       head_aspect=abac_attribute_head(attr);
+       tail_aspect=abac_attribute_tail(attr);
+       using_this=abac_attribute_get_this(attr);
+       } else {
+           /* call into yacc parser */
+           int rc=abac_yy_parse(ctxt, attr_string, &head_aspect, &tail_aspect, &using_this);
+           if(rc) {
+               ret = ABAC_CERT_INVALID;
+               goto error;
+           }
+    }
+
+    char *keyid=abac_aspect_principal_principalname(head_aspect);
+    abac_id_t *issuer_id=NULL;
+    ret= _verify_valid_credential_issuer(ctxt,keyid,cert,&issuer_id);
+    if(ret != ABAC_CERT_SUCCESS) {
+        char *tmp=NULL;
+        asprintf(&tmp,"_load_attribute_cert: fail to verify credential's issuer (%s)",attr_string);
+        panic(tmp);
+    }
+
+    ret=_insert_valid_cred(ctxt, issuer_id, head_aspect, tail_aspect,
+                                    cert,cred_ret,encoded_attr_string, using_this);
+
+    if(ret != ABAC_CERT_SUCCESS) {
+        char *tmp=NULL;
+        asprintf(&tmp,"_load_attribute_cert: fail to verify credential (%s)",attr_string);
+        panic(tmp);
+    }
+
+    return ABAC_CERT_SUCCESS;
+
+error:
+    return ret;
+}
+
+void abac_print_clauses(abac_list_t *clauses, FILE *fp)
+{
+    if (clauses != NULL) {
+        char *cur;
+        printf("total-- %d clauses\n", abac_list_size(clauses));
+        abac_list_foreach(clauses, cur,
+            if(cur) {
+                if(fp)
+                    fprintf (fp,"a clause, %d(%s)\n", (int)cur,cur);
+                    else printf ("a clause, %d(%s)\n", (int)cur,cur);
+            }
+        );
+    }
+}
+
+/**
+ * Load an attribute cert from a abac_attribute_t.
+ * attr should be all checked out before arriving here
+ * but because of preloading of id, need to check the issuer id's
+ * validity in this context
+ */
+int abac_context_load_attribute_attribute(abac_context_t *ctxt, abac_attribute_t *ptr)
+{
+    assert(ctxt != NULL);
+    abac_credential_t *cred=NULL;
+
+    certificate_t *cert=abac_attribute_cert(ptr);
+    return _load_attribute_cert(ctxt, cert, &cred);
+}
+
+/* this is especially made for abac_context_dup to avoid trying to do
+   yyparse again */
+int abac_context_load_attribute_credential(abac_context_t *ctxt, abac_attribute_t *ptr,
+abac_credential_t *cred)
+{
+    assert(ctxt != NULL);
+    certificate_t *cert=abac_attribute_cert(ptr);
+    return _load_attribute_cert(ctxt, cert, &cred);
+}
+
+
+/**
+ * Load an attribute cert from a abac_attribute_t.
+ * attr should be all checked out before arriving here
+ * this is called from abac.hh and so must make a 
+ * separate copy of attr 
+ */
+int abac_context_load_attribute(abac_context_t *ctxt, abac_attribute_t *ptr)
+{
+    assert(ctxt != NULL);
+    abac_attribute_t *nptr=abac_attribute_copy(ptr);
+    int ret= abac_context_load_attribute_attribute(ctxt, nptr);
+    return ret;
+}
+
+/**
+ * Load an attribute cert from a file.
+ */
+int abac_context_load_attribute_file(abac_context_t *ctxt, char *filename)
+{
+    abac_credential_t *cred=NULL;
+    assert(ctxt != NULL); assert(filename != NULL);
+
+    // load the cert
+    DEBUG_PRINTF("..loading attr file %s\n", filename);
+    certificate_t *cert = cert_get_attr_cert_from_file(filename);
+    if (cert == NULL) return ABAC_CERT_INVALID;
+
+    int ret=_load_attribute_cert(ctxt, cert, &cred);
+    return ret;
+}
+
+/**
+ * Load an attribute cert from a chunk.
+ */
+int abac_context_load_attribute_chunk(abac_context_t *ctxt, abac_chunk_t ccert)
+{
+    abac_credential_t *cred=NULL;
+    assert(ctxt != NULL);
+    chunk_t chunk = { ccert.ptr, ccert.len };
+
+    // load the cert
+    certificate_t *cert = cert_get_attr_cert_from_chunk(chunk);
+    if (cert == NULL) return ABAC_CERT_INVALID;
+
+    int ret=_load_attribute_cert(ctxt, cert, &cred);
+    return ret;
+}
+
+
+/**
+ *  lookup for a credential/duplicated.
+ */
+abac_credential_t *abac_context_credential_lookup(abac_context_t *ctxt, char* cred_string)
+{
+    assert(cred_string); 
+    abac_credential_t *attr_cred=NULL;
+    int sz=abac_list_size(ctxt->context_attr_hashkeyid_list);
+    if(ctxt->context_attr_hashkeyid_list) {
+        char *keyid;
+        abac_list_foreach(ctxt->context_attr_hashkeyid_list, keyid,
+            if(strcmp(keyid,cred_string)==0) {
+                attr_cred=abac_credential_lookup(keyid);
+                break;
+            }
+        );
+    }
+    if (attr_cred == NULL) {
+        DEBUG_PRINTF("DEBUG:credential_lookup, NOT FOUND..(%d)(%s)\n",sz,abac_decode_string(cred_string));
+        return NULL;
+    }
+    abac_credential_t *rt=abac_credential_dup(attr_cred);
+    DEBUG_PRINTF("DEBUG:crential_lookup, FOUND.. (%d)(%s) \n", sz,abac_decode_string(cred_string));
+    return rt;
+}
+
+void abac_context_credential_free(abac_context_t *ctxt, abac_credential_t *ptr)
+{
+    if (ptr == NULL)
+        return;
+
+    char *keyid=abac_credential_hashkey(ptr);
+
+    /* make sure it belongs to this context */
+    char *cur=NULL;
+    abac_list_foreach(ctxt->context_attr_hashkeyid_list, cur,
+        if(strcmp(cur,keyid)==0)
+            break;
+    );
+    assert(cur!=NULL);
+    abac_list_remove(ctxt->context_attr_hashkeyid_list, cur);
+    free(cur);
+
+    abac_credential_free(ptr);
+}
+
+/**************************************************************/
+char *_make_key_filename(char *cert_file)
+{
+    char *p=strstr(cert_file,"_ID.");
+    char *head=strndup(cert_file,p-cert_file);
+    char *tail=p+4;
+    char *keyfile=NULL;
+    asprintf(&keyfile,"%s_private.%s",head,tail);
+    free(head);
+    return keyfile;
+}
+
+/**
+ * Load a directory full of principal certs.
+ */
+void abac_context_load_principals(abac_context_t *ctxt, char *path) {
+    char *glob_pat, *key_pat;
+    glob_t glob_buf;
+    int i, ret;
+
+    assert(ctxt != NULL); assert(path != NULL);
+
+    int dirlen = strlen(path);
+
+    /* make sure pick the larger one */
+    glob_pat = abac_xmalloc(dirlen + sizeof(IDKEY_PAT));
+    memcpy(glob_pat, path, dirlen);
+
+    // load ID certs
+    memcpy(glob_pat + dirlen, ID_PAT, sizeof(ID_PAT));
+    glob(glob_pat, GLOB_BRACE, NULL, &glob_buf); // TODO check for error
+    for (i = 0; i < glob_buf.gl_pathc; ++i) {
+        /* blah_ID.pem */
+        char *cert_file = glob_buf.gl_pathv[i];
+        /* blah_private.pem */
+        char *key_file=_make_key_filename(cert_file);
+        DEBUG_PRINTF("--> ID cert... %s\n", cert_file);
+        DEBUG_PRINTF("--> KEY cert... %s\n", key_file);
+        ret = abac_context_load_id_id_key_files(ctxt, cert_file, key_file);
+        if (ret != ABAC_CERT_SUCCESS)
+            warnx("Couldn't load ID cert %s", cert_file);
+    }
+    globfree(&glob_buf);
+
+    // next load IDKEY certs
+    memcpy(glob_pat + dirlen, IDKEY_PAT, sizeof(IDKEY_PAT));
+    glob(glob_pat, GLOB_BRACE, NULL, &glob_buf); // TODO check for error
+    for (i = 0; i < glob_buf.gl_pathc; ++i) {
+        /* blah_IDKEY.pem */
+        char *certkey_file = glob_buf.gl_pathv[i];
+        DEBUG_PRINTF("--> IDKEY certkey... %s\n", certkey_file);
+        ret = abac_context_load_id_idkey_file(ctxt, certkey_file);
+        if (ret != ABAC_CERT_SUCCESS)
+            warnx("Couldn't load ID/KEY IDKEY cert %s", certkey_file);
+    }
+    globfree(&glob_buf);
+
+    free(glob_pat);
+}
+
+/**
+ * Load a directory full of certs.
+ */
+void abac_context_load_directory(abac_context_t *ctxt, char *path) {
+    char *glob_pat, *key_pat;
+    glob_t glob_buf;
+    int i, ret;
+
+    abac_context_load_principals(ctxt,path);
+    int dirlen = strlen(path);
+
+    /* make sure pick the larger one */
+    glob_pat = abac_xmalloc(dirlen + sizeof(IDKEY_PAT));
+    memcpy(glob_pat, path, dirlen);
+
+    memcpy(glob_pat + dirlen, ATTR_PAT, sizeof(ATTR_PAT));
+    glob(glob_pat, 0, NULL, &glob_buf); // TODO check for error
+    DEBUG_PRINTF("glob_pat is (%s)\n", glob_pat);
+    for (i = 0; i < glob_buf.gl_pathc; ++i) {
+        char *cert_file = glob_buf.gl_pathv[i];
+
+        DEBUG_PRINTF("--> attr file... (%s)\n", cert_file);
+        ret = abac_context_load_attribute_file(ctxt, cert_file);
+        if (ret != ABAC_CERT_SUCCESS)
+            warnx("Couldn't load attribute cert --(%d)%s", ret,cert_file);
+        DEBUG_PRINTF("Loaded.. (%s)\n", cert_file);
+    }
+    globfree(&glob_buf);
+
+    free(glob_pat);
+}
+
+/**
+ * Run a query on the data in an abac context. Returns a NULL-terminated array
+ * of abac_credential_t. Success/failure in *success.
+ * queryfor(either role or oset), with(either keyid or object type)
+ */
+abac_credential_t **abac_context_query(abac_context_t *ctxt, char *queryfor, char *with, int *success) {
+    DEBUG_PRINTF("abac_context_query about(%s) with(%s)\n", queryfor, with);
+    abac_credential_t **credentials = NULL, *cur;
+    assert(ctxt != NULL); assert(queryfor != NULL);
+    assert(with != NULL); assert(success != NULL);
+
+    abac_stack_t *result = abac_pl_query(ctxt->pl, queryfor, with);
+
+    int size = abac_stack_size(result);
+    if (size > 0) {
+       if(!abac_pl_returning_partial(ctxt->pl))
+            *success = 1;
+            else *success = 0;
+    } else {
+	*success = 0;
+    }
+
+    // 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
+    credentials = abac_xmalloc(sizeof(abac_credential_t *) * (size + 1));
+    int i = 0;
+    if(size) {
+        while(i<size) { 
+            cur=(abac_credential_t *) abac_stack_pop(result);
+            credentials[i++] = cur;
+        } 
+    }
+    credentials[i] = NULL;
+
+    if(result)
+        abac_stack_free(result);
+
+    return credentials;
+}
+
+/**
+ * Run a repeated query on the data in an abac context to get the next
+ * solution proof. Returns a NULL-terminated array
+ * of abac_credential_t. Success/failure in *success.
+ */
+abac_credential_t **abac_context_query_again(abac_context_t *ctxt, int *success)
+{
+    DEBUG_PRINTF("abac_context_query_again\n");
+    abac_credential_t **credentials = NULL, *cur;
+    assert(ctxt != NULL);
+    assert(success != NULL);
+
+    abac_stack_t *result = abac_pl_query_again(ctxt->pl);
+
+    int size = abac_stack_size(result);
+    if (size > 0) {
+        *success = 1;
+        } else {
+            *success = 0;
+    }
+
+    // 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
+    credentials = abac_xmalloc(sizeof(abac_credential_t *) * (size + 1));
+    int i = 0;
+    if(size) {
+        while(i<size) { 
+            cur=(abac_credential_t *) abac_stack_pop(result);
+            credentials[i++] = cur;
+        } 
+    }
+    credentials[i] = NULL;
+
+    if(result)
+        abac_stack_free(result);
+
+    return credentials;
+}
+
+
+abac_credential_t **abac_context_query_with_structure(abac_context_t *ctxt,
+abac_aspect_t *queryfor, abac_aspect_t *with, int *success)
+{
+    DEBUG_PRINTF("abac_context_query_with_structure\n");
+    abac_credential_t **credentials = NULL, *cur;
+    assert(ctxt != NULL); assert(queryfor != NULL);
+    assert(with != NULL); assert(success != NULL);
+
+    abac_stack_t *result = abac_pl_query_with_structure(ctxt->pl, queryfor, with);
+
+    int size = abac_stack_size(result);
+    if (size > 0) {
+        *success = 1;
+    } else {
+    // XXX NOT SURE YET..
+    // return partial proof
+	*success = 0;
+    }
+
+    // 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
+    credentials = abac_xmalloc(sizeof(abac_credential_t *) * (size + 1));
+    int i = 0;
+    if(size) {
+        while(i<size) { 
+            cur=(abac_credential_t *) abac_stack_pop(result);
+            credentials[i++] = cur;
+        } 
+    }
+    credentials[i] = NULL;
+
+    if(result)
+        abac_stack_free(result);
+
+    return credentials;
+}
+
+/**
+ * A NULL-terminated array of all the credentials in the context.
+ */
+abac_credential_t **abac_context_credentials(abac_context_t *ctxt) {
+    abac_credential_t **credentials = NULL, *cur;
+    assert(ctxt != NULL);
+
+    abac_stack_t *result = abac_context_dump_creds(ctxt);
+    int size = abac_stack_size(result);
+
+    // 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
+    credentials = abac_xmalloc(sizeof(abac_credential_t *) * (size + 1));
+    int i = 0;
+    if(size) {
+        while(i<size) { 
+            cur=(abac_credential_t *) abac_stack_pop(result);
+            /* if not in there yet, add into it */
+            credentials[i++] = cur;
+        } 
+    }
+    credentials[i] = NULL;
+
+    if(result)
+        abac_stack_free(result);
+    return credentials;
+}
+
+/**
+ * Frees a NULL-terminated list of credentials. context independent
+ */
+void abac_free_credentials(abac_credential_t **credentials) {
+    int i;
+
+    if (credentials == NULL)
+        return;
+
+    for (i = 0; credentials[i] != NULL; ++i)
+        abac_credential_free(credentials[i]);
+    free(credentials);
+}
+
+/**
+ * A NULL-terminated array of all the principals in the context.
+ */
+abac_id_credential_t **abac_context_principals(abac_context_t *ctxt)
+{
+    abac_id_credential_t **principals = NULL, *cur;
+    assert(ctxt != NULL);
+
+    abac_stack_t *result = abac_context_dump_principals(ctxt);
+
+    int size = abac_stack_size(result);
+
+    // 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
+    principals = abac_xmalloc(sizeof(abac_id_credential_t *) * (size + 1));
+    int i = 0;
+    if(size) {
+        while(i<size) {
+            cur=(abac_id_credential_t *) abac_stack_pop(result);
+            /* if not in there yet, add into it */
+            principals[i++] = cur;
+        }
+    }
+    principals[i] = NULL;
+
+    if(result)
+        abac_stack_free(result);
+    return principals;
+}
+
+/**
+ * Frees a NULL-terminated list of principals, context independent
+ */
+void abac_free_principals(abac_id_credential_t **principals)
+{
+    int i;
+
+    if (principals == NULL)
+        return;
+
+    for (i = 0; principals[i] != NULL; ++i)
+        abac_id_credential_free(principals[i]);
+    free(principals);
+}
+
+
+
+/**
+ * Free an abac context.
+ */
+void abac_context_free(abac_context_t *ctxt) 
+{
+    assert(ctxt != NULL);
+    DEBUG_PRINTF("abac_conext_free..\n");
+
+    abac_verifier_session_remove_context(ctxt);
+
+    if(ctxt->namespace) free(ctxt->namespace);
+    abac_pl_free(ctxt->pl);
+
+    DEBUG_PRINTF("looking to free context_attr_hashkeyid_list..\n");
+    if(ctxt->context_attr_hashkeyid_list) { 
+        if( abac_list_size(ctxt->context_attr_hashkeyid_list)>0) {
+           /* free all the keys */
+           char *cur;
+           abac_list_foreach(ctxt->context_attr_hashkeyid_list, cur,
+              if(cur) { 
+                 DEBUG_PRINTF("hum.. attr hashkey being freed.. %s\n", cur);
+                 abac_credential_t *attr=abac_credential_lookup(cur);
+/* XXX abac_check_cred(cur); */
+                 assert(attr!=NULL);
+                 abac_credential_free(attr);
+                 free(cur);
+              }
+           );
+        }
+        abac_list_free(ctxt->context_attr_hashkeyid_list);
+    }
+
+    DEBUG_PRINTF("looking to free context_id_hashkeyid_list..\n");
+    if(ctxt->context_id_hashkeyid_list) {
+ 
+        if(abac_list_size(ctxt->context_id_hashkeyid_list)) {
+            char *cur;
+            abac_list_foreach(ctxt->context_id_hashkeyid_list, cur,
+                if(cur) {
+                    DEBUG_PRINTF("hum.. id hashkey being freed.. %s\n", cur);
+/* abac_id_credential_t *id=abac_check_id_cred(cur); */
+                    abac_id_credential_t *id=abac_id_credential_lookup(cur);
+                    assert(id!=NULL);
+                    abac_id_credential_free(id);
+                    free(cur);
+                }
+            );
+        }
+        abac_list_free(ctxt->context_id_hashkeyid_list);
+    }
+
+    DEBUG_PRINTF("looking to free context_pl_clauses..\n");
+    if(ctxt->context_pl_clauses) {
+        if(abac_list_size(ctxt->context_pl_clauses)) {
+            abac_pl_remove_credential(ctxt->context_pl_clauses);
+            char *cur;
+            abac_list_foreach(ctxt->context_pl_clauses, cur,
+                if(cur) free(cur);
+            );
+        }
+        abac_list_free(ctxt->context_pl_clauses);
+    }
+    free(ctxt);
+}
+
+void abac_context_set_no_partial_proof(abac_context_t *ctxt)
+{ abac_pl_set_no_partial(ctxt->pl); }
+
+void abac_context_set_want_partial_proof(abac_context_t *ctxt)
+{ abac_pl_set_want_partial(ctxt->pl); }
+
+/****************************************************************************/
+void abac_context_dump_clauses(abac_context_t *ctxt)
+{
+    printf("===YAP clauses for [%s]===\n", ctxt->namespace);
+    if(ctxt->context_pl_clauses) {
+        char *cur;
+        abac_list_foreach(ctxt->context_pl_clauses, cur,
+            if(cur) {
+               printf("%s\n", cur);
+            }
+        );
+        } else {
+            DEBUG_PRINTF("abac_contxt_dump_clauses: no yap clauses!!!!\n");
+    }
+    printf("==========================\n");
+}
+
+
+void abac_context_dump(abac_context_t *ctxt)
+{
+    abac_stack_t *result = abac_context_dump_creds(ctxt);
+    int size = abac_stack_size(result);
+    int i=0;
+
+    printf("CONTEXT: [%s]\n", ctxt->namespace); 
+
+    if(size) {
+        abac_credential_t *cur;
+        while(i<size) {
+            cur=(abac_credential_t *) abac_stack_pop(result);
+            abac_print_typed_cred_info(cur,NULL);
+            abac_credential_free(cur);
+            i++; 
+        }
+    }
+    abac_stack_free(result);
+
+    result = abac_context_dump_principals(ctxt);
+    size = abac_stack_size(result);
+    i=0;
+    if(size) {
+        abac_id_credential_t *cur;
+        while(i<size) {
+            cur=(abac_id_credential_t *) abac_stack_pop(result);
+            abac_print_prin_info(cur,NULL);
+            abac_id_credential_free(cur);
+            i++; 
+        }
+    }
+    abac_stack_free(result);
+    abac_context_dump_clauses(ctxt);
+
+}
