/** ** abac_context.c **/ #include #include #include #include #include #include #include #include #include #include #include #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, %ld(%s)\n", (long)cur,cur); else printf ("a clause, %ld(%s)\n", (long)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(ipl); 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(ipl, 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(inamespace) 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