/* copied from abac_graph.c implementation of the low level using yap prolog */ #include #include #include #include #include #include #include "abac_internal.h" #include "abac_pl_yap.h" #include "abac_util.h" #include "uthash.h" extern abac_list_t *abac_credential_clauses(abac_credential_t *); extern char *abac_id_clause(abac_id_credential_t *); extern abac_aspect_t *abac_yy_get_rule_tail_aspect(); extern abac_aspect_t *abac_yy_get_rule_head_aspect(); static int debug=0; /* track constraint's external clause's -unique name id */ static int constraint_label_count=0; static char *constraint_label="isABAC_constraint"; // pl -- place holder for now struct _abac_pl_t { /* a_term <- prin */ char *aspect_term; char *prin_term; int query_made; /* 1+ yes, 0 no, rc is valid only if a query is made */ int query_rc; /* rc of query call */ int next_rc; /* rc of next-last query */ /* proof count = abac_list_size(proof_list) */ abac_list_t *proof_list; /* list of list of cred_list */ long safe_t; /* holding the YAP slot for the goal */ }; /***********************************************************/ static int _get_next_constraint_label_idx() { constraint_label_count++; return constraint_label_count; } static int _get_constraint_label_idx() { return constraint_label_count; } /***********************************************************/ static int _insert_clause(char *str) { YAP_Term *eterm; YAP_Term goalArgs=YAP_ReadBuffer(str, eterm); char *tmp=YAP_CompileClause(goalArgs); if (tmp!=NULL) { /* something is wrong */ printf("error: result of compile clause (%s)\n", tmp); printf("error: str used (%s)\n", str); return 1; } return 0; } static int _insert_cred_clause(char *cstr) { int ret=ABAC_CERT_SUCCESS; int rc=_insert_clause(cstr); if (rc) return ABAC_CERT_BAD_YAP; return ABAC_CERT_SUCCESS; } void show_yap_db(const char *msg) { char lstr[]="listing"; YAP_Term *eterm; /* error term */ printf("\n\n========= yap db (%s)\n",msg); YAP_Term goal=YAP_ReadBuffer(lstr, eterm); int rc =YAP_RunGoal( goal ); if (rc) { printf("listing ok.. \n"); } else { printf("listing's rc is bad.. \n"); YAP_Exit(1); } printf("========= \n\n"); } /** * Include some utility routines */ abac_pl_t *abac_pl_utility(void) { /* append([],L,L). append([X|L1],L2,[X|L3]):-append(L1,L2,L3). appendL([],[]). appendL([H|T], L) :- appendL(T,L2), append(H,L2,L). */ if(_insert_clause("append([],L,L)")) YAP_Exit(1); if(_insert_clause("append([X|L1],L2,[X|L3]):-append(L1,L2,L3)")) YAP_Exit(1); if(_insert_clause("appendL([],[])")) YAP_Exit(1); if(_insert_clause("appendL([H|T], L) :- appendL(T,L2), append(H,L2,L)")) YAP_Exit(1); } /** * Create a new yap structure. */ abac_pl_t *abac_pl_new(void) { if (YAP_FastInit(NULL) == YAP_BOOT_ERROR) YAP_Exit(1); if (YAP_RunGoal(YAP_MkAtomTerm(YAP_LookupAtom("source")))) { if(debug) fprintf(stderr, "calling source..\n"); } else { if(debug) fprintf(stderr,"calling source failed..\n"); YAP_Exit(1); } abac_pl_utility(); abac_pl_t *pl = abac_xmalloc(sizeof(abac_pl_t)); pl->aspect_term=NULL; pl->prin_term=NULL; pl->query_made=0; pl->query_rc=0; pl->next_rc=0; /* proof count = abac_list_size(proof_list) */ pl->proof_list=NULL; pl->safe_t=0; return pl; } /* returns the number of solution so far */ int abac_pl_proof_cnt(abac_pl_t *pl) { if(pl->proof_list) return abac_list_size(pl->proof_list); return 0; } /* is this the conclusion of the query ? */ /* 1 is yes, 0 N/A */ int abac_pl_done_yet(abac_pl_t *pl) { if(pl->query_made) { if(pl->query_rc) { if(!pl->next_rc) return 1; return 0; } else return 1; /* even init query failed */ } return 0; } static void _free_p_list(abac_list_t *p) { if( p != NULL ) { if(abac_list_size(p) != 0) { abac_credential_t *cur=NULL; abac_list_foreach(p, cur, abac_credential_free(cur); ); } abac_list_free(p); } } static void _free_pf_list(abac_list_t *p) { if(p != NULL) { if(abac_list_size(p) != 0) { abac_list_t *cur=NULL; abac_list_foreach(p, cur, _free_p_list(cur); ); } abac_list_free(p); } } void abac_pl_free(abac_pl_t *pl) { if(pl->aspect_term) free(pl->aspect_term); if(pl->prin_term) free(pl->prin_term); _free_pf_list(pl->proof_list); free(pl); } /* this is done whenever a new query starts in */ static void _reset_pl(abac_pl_t *pl, char *aspect_term, char *prin_term) { if(pl->safe_t) { YAP_RecoverSlots(1); YAP_Reset(); } /* free the old ones */ if(pl->aspect_term) free(pl->aspect_term); if(pl->prin_term) free(pl->prin_term); pl->aspect_term = abac_xstrdup(aspect_term); pl->prin_term = abac_xstrdup(prin_term); pl->query_made=0; pl->query_rc=0; pl->next_rc=0; _free_pf_list(pl->proof_list); pl->proof_list=abac_list_new(); pl->safe_t=0; } /** * Add a credential to the db, not duplicating a copy and so * don't try to free it after this call. */ int abac_pl_add_credential(abac_pl_t *pl, abac_credential_t *cred) { int rc=0; abac_list_t *clauses=abac_credential_clauses(cred); if (clauses != NULL) { char *cur; abac_list_foreach(clauses, cur, if(cur) { if(debug) fprintf(stderr,"inserting =>%s\n",cur); rc=_insert_cred_clause(cur); } ); } return rc; } int abac_pl_add_type_credential(abac_pl_t *pl, abac_id_credential_t *id_cert) { char *clause=abac_id_clause(id_cert); if (clause != NULL) { int rc=_insert_cred_clause(clause); return rc; } return 0; } /* string1(S):- S="abc";S="efg";S="ijk" */ char *abac_pl_add_range_constraint_clause(char *var, char *tmplist) { int i=_get_next_constraint_label_idx(); char *tmp=NULL; asprintf(&tmp,"%s_%d(%s) :- %s", constraint_label, i, var, tmplist); int rc=_insert_cred_clause(tmp); free(tmp); if(rc) panic("abac_pl_add_range_constraint_clause, failed to insert"); asprintf(&tmp,"%s_%d(%s)", constraint_label, i, var); return tmp; } /* cases, ['str'] ['str1','str2'] ([] is not possible, and don't care) */ static void _credentials_from_string(abac_list_t *credentials,char *slist) { char *cptr=slist; /* current ptr */ char *sptr; /* string ptr */ char *ptr; int len=0; char *string; abac_credential_t *cred=NULL; int cnt=0; /* find first [' */ ptr=strstr(cptr,"['"); if(ptr == NULL) return; cptr=ptr+2; sptr=cptr; while (1) { /* find next ',' or '] */ ptr=strstr(cptr,"','"); if(ptr!=NULL) { cptr=ptr+3; len=(ptr-sptr); string=strndup(sptr,len); cred=abac_credential_lookup(string); free(string); if(cred) { int i=abac_list_unique_add(credentials, cred); if(i) cnt++; } else { printf("BAD BAD\n"); } sptr=cptr; } else { ptr=strstr(cptr,"']"); if(ptr!=NULL) { len=(ptr-sptr); string=strndup(sptr,len); cred=abac_credential_lookup(string); free(string); if(cred) { int i=abac_list_unique_add(credentials, cred); if(i) cnt++; } else { printf("BAD BAD BAD\n"); } break; } } } if(debug) fprintf(stderr,"DEBUG:total %d credentials\n", cnt); } /* MAX 1024x1024, double as it goes */ static int try_again(int sz, char **tptr) { int blk=1024*2; /* 2048 */ int max=1024*1024; int size; char *tmp = NULL; if(sz==0) { size = (sizeof(char) * (blk+1)); } else { if (sz>=max) { size=0; *tptr=tmp; return 0; } size=sz*2+1; if(size > max) size=max; } tmp = (char *) YAP_AllocSpaceFromYap(size); if(tmp==NULL) { fprintf(stderr,"ERROR: malloc failed !!!\n"); YAP_Exit(1); } *tptr=tmp; return size; } /* make a query and extract just first set of result */ static abac_list_t *_make_yap_query(abac_pl_t *pl, char *prin, char *nm, char* estring) { YAP_Term *eterm0; YAP_Term *eterm1; YAP_Term arg[3]; abac_list_t *cred_list = abac_list_new(); if(debug) { fprintf(stderr," the principal part(%s)\n", prin); fprintf(stderr," the role/oset part(%s)\n", estring); fprintf(stderr," nm part(%s)\n", nm); } if(prin[0]=='\'' || prin[0]=='"') { arg[0]=YAP_ReadBuffer(prin,eterm0); } else { arg[0]=YAP_MkAtomTerm(YAP_LookupAtom(prin)); } if(debug) fprintf(stderr," the role/oset part(%s)\n", estring); arg[1]=YAP_ReadBuffer(estring,eterm1); /* var for credential list */ arg[2]=YAP_MkVarTerm(); YAP_Atom f = YAP_LookupAtom("isMember"); YAP_Functor func = YAP_MkFunctor(f, 3); YAP_Term goal=YAP_MkApplTerm(func, 3, arg); pl->safe_t = YAP_InitSlot(goal); pl->query_rc =YAP_RunGoal(goal); pl->query_made=1; pl->next_rc=pl->query_rc; if (pl->query_rc) { printf("YAP query succeed\n"); char *tmp=NULL; int tmp_sz=try_again(0, &tmp); YAP_Term argterm=YAP_ArgOfTerm(3,YAP_GetFromSlot(pl->safe_t)); while(1) { /* int rc=YAP_WriteBuffer(argterm, tmp, tmp_sz,YAP_WRITE_HANDLE_VARS); */ YAP_WriteBuffer(argterm, tmp, tmp_sz,YAP_WRITE_HANDLE_VARS); /* if(debug) fprintf(stderr,"call YAP_WriteBuffer: rc(%d) tmp_sz(%d)\n", rc, tmp_sz); */ if(strlen(tmp) > 5 && tmp[0]=='\[') { if(debug) fprintf(stderr,"what came back .. (%s)\n", tmp); break; } tmp_sz=try_again(tmp_sz,&tmp); if(debug) fprintf(stderr,"try_again: tmp_sz(%d)\n", tmp_sz); if(tmp_sz==0) { fprintf(stderr," PANIC, run out of heap space..\n"); YAP_Exit(1); } } /* this is returned as ['string1','string2'] */ if(debug) fprintf(stderr," query answer : %s(%d)\n", tmp, strlen(tmp)); _credentials_from_string(cred_list,tmp); if(abac_list_size(cred_list)==0) { fprintf(stderr,"CAN NOT retrieve result properly from YAP!!!\n"); YAP_Exit(1); } abac_list_add(pl->proof_list, cred_list); YAP_FreeSpaceFromYap(tmp); } else { printf("YAP query failed\n"); /* YAP_Exit(1); */ } return cred_list; } /* make a query for next possible solution proof */ static abac_list_t *_query_again(abac_pl_t *pl) { abac_list_t *cred_list=abac_list_new(); pl->next_rc=YAP_RestartGoal(); pl->query_made++; if(debug) fprintf(stderr,"query_again: another success\n"); char *tmp=NULL; int tmp_sz=try_again(0, &tmp); YAP_Term argterm=YAP_ArgOfTerm(3,YAP_GetFromSlot(pl->safe_t)); if(pl->next_rc) { while(1) { YAP_WriteBuffer(argterm, tmp, tmp_sz,YAP_WRITE_HANDLE_VARS); if(strlen(tmp) > 5 && tmp[0]=='\[') break; tmp_sz=try_again(tmp_sz,&tmp); if(tmp_sz==0) { fprintf(stderr," PANIC, run out of heap space..\n"); YAP_Exit(1); } } /* this is returned as ['string1','string2'] */ if(debug) fprintf(stderr," query answer : %s(%d)\n", tmp, strlen(tmp)); _credentials_from_string(cred_list,tmp); if(abac_list_size(cred_list)==0) { fprintf(stderr,"CAN NOT retrieve result properly from YAP!!!\n"); YAP_Exit(1); } abac_list_add(pl->proof_list, cred_list); YAP_FreeSpaceFromYap(tmp); } return cred_list; } abac_stack_t *_make_cred_stack(abac_list_t *p) { abac_stack_t *ret=abac_stack_new(); if(abac_list_size(p) != 0) { abac_credential_t *cur=NULL; abac_list_foreach(p, cur, abac_stack_push(ret, (void *)abac_credential_dup(cur)); ); } return ret; } /* force a backtrack to get next solution proof */ abac_stack_t *abac_pl_query_again(abac_pl_t *pl) { abac_list_t *rlist=_query_again(pl); abac_stack_t *ret=_make_cred_stack(rlist); return ret; } /* 2 types acme.buys_rocket <- coyote (coyote=prin, acme.buys_rocket=role) ==> isMember(coyote,role(acme,buys_rocket), L) acme.buys_rocket <- acme.preferred_customer -- NOT valid */ static abac_stack_t *_query_with_aspect(abac_pl_t *pl, abac_aspect_t* head, abac_aspect_t* tail) { abac_stack_t *ret=NULL; char *tmp=NULL; if(0) show_yap_db("DEBUG:calling within _query_with_aspect"); char *nm; PROLOG(nm=abac_aspect_principal_name(head);); /* could be obj or principal */ char *prin_nm=NULL; if(abac_aspect_is_object(tail)) { prin_nm=abac_aspect_object_name(tail); } else { PROLOG(prin_nm=abac_aspect_principal_name(tail);); } if(abac_aspect_aspect_name(tail)!=NULL) { printf("fail, a.o <- b.o and a.r <- a.r query is not implemented yet !!!\n"); YAP_Exit(1); } if (prin_nm == NULL || nm == NULL) { printf("fail, query's call got bad aspect names .. \n"); YAP_Exit(1); } if(debug) fprintf(stderr,"printing up the yap query ..\n"); char *pstring; PROLOG(pstring=abac_aspect_aspect_param_string(head);); char *stub=abac_aspect_type_string(head); if(pstring) { asprintf(&tmp,"%s(%s,%s,%s)", stub, nm, abac_aspect_aspect_name(head),pstring); free(pstring); } else { asprintf(&tmp,"%s(%s,%s)", stub, nm, abac_aspect_aspect_name(head)); } _reset_pl(pl,tmp,prin_nm); abac_list_t *rlist=_make_yap_query(pl,prin_nm,nm,tmp); /* generate the resulting stack from a list */ ret=_make_cred_stack(rlist); return ret; } /** * Get all the credentials (attribute/issuer cert pairs) from prolog * (which returns in string form) */ abac_stack_t *abac_pl_credentials(abac_pl_t *pl) { abac_stack_t *ret=abac_verifier_dump_creds(); return ret; } abac_stack_t *abac_pl_principals(abac_pl_t *pl) { abac_stack_t *ret=abac_verifier_dump_principals(); return ret; } /** * Make a query into prolog db --role acme.preferred_customer --principal coyote --role acme.prefer_customer.buy_rockets --principlal coyote --oset acme.rockets -- object mrx-21 --oset acme.villans -- principal coyote */ abac_stack_t *abac_pl_query(abac_pl_t *pl, char *roleoset, char *prinobj) { abac_stack_t *ret=NULL; int len=strlen(roleoset)+strlen(prinobj)+5; char* attr_string=(char *) abac_xmalloc(sizeof(char)*len); sprintf(attr_string,"%s<-%s", roleoset, prinobj); if(debug) fprintf(stderr,"abac_pl_query, query string is (%s)\n",attr_string); /* call into yacc parser */ abac_reset_yyfptr(attr_string); abac_yy_init(); int rc=yyparse(); if (rc) { free(attr_string); return NULL; } abac_aspect_t *head_aspect = abac_yy_get_rule_head_aspect(); abac_aspect_t *tail_aspect = abac_yy_get_rule_tail_aspect(); ret=_query_with_aspect(pl,head_aspect,tail_aspect); return ret; } abac_stack_t *abac_pl_query_with_structure(abac_pl_t *pl, abac_aspect_t *head_aspect, abac_aspect_t *tail_aspect) { abac_stack_t *ret=NULL; ret=_query_with_aspect(pl,head_aspect,tail_aspect); return ret; }