#include #include #include #include #include "abac_list.h" #include "abac_util.h" #include "abac_pl.h" static int debug=0; /* A.oset <- B A.oset <- Obj A.oset <- B.oset A.oset <- B.role.oset */ struct _abac_oset_t { int is_object; union { char *principal_name; abac_term_t *principal_object; }; char *linked_role_name; abac_param_list_t *linked_role_params; char *oset_name; abac_param_list_t *oset_params; char *string; char *linked; abac_list_t *prereqs; int refcount; }; int abac_oset_is_object(abac_oset_t *ptr) { return ptr->is_object; } /** * Create a new principal and initialize it. */ abac_oset_t *abac_oset_principal_new(char *principal) { assert(principal != NULL); if (strlen(principal) == 0) return NULL; abac_oset_t *oset = (abac_oset_t *) abac_xmalloc(sizeof(abac_oset_t)); oset->is_object =0; oset->principal_name = abac_xstrdup(principal); oset->oset_name = NULL; oset->oset_params = NULL; oset->linked_role_name = NULL; oset->linked_role_params = NULL; oset->string = abac_xstrdup(principal); oset->linked = NULL; oset->prereqs = NULL; oset->refcount = 1; return oset; } abac_oset_t *abac_oset_object_new(abac_term_t *object) { assert(object != NULL); abac_oset_t *oset = (abac_oset_t *) abac_xmalloc(sizeof(abac_oset_t)); oset->is_object =1; oset->principal_object = object; oset->oset_name = NULL; oset->oset_params = NULL; oset->linked_role_name = NULL; oset->linked_role_params = NULL; oset->string = strdup(abac_term_name(object)); oset->linked = NULL; oset->prereqs = NULL; oset->refcount = 1; return oset; } /** * Create a new oset and initialize it. */ abac_oset_t *abac_oset_oset_new(char *principal_name, char *oset_name) { assert(principal_name != NULL); assert(oset_name != NULL); abac_oset_t *oset; if (strlen(principal_name) == 0 || strlen(oset_name) == 0) return NULL; /* MEI */ if(debug) printf("DEBUG:adding a new oset (%s) to principal (%s)\n", oset_name, principal_name); oset = abac_xmalloc(sizeof(abac_oset_t)); oset->is_object=0; oset->principal_name = abac_xstrdup(principal_name); oset->oset_name = abac_xstrdup(oset_name); oset->oset_params = NULL; oset->linked_role_name = NULL; oset->linked_role_params = NULL; int prin_len = strlen(principal_name); int oset_len = strlen(oset_name); oset->string = abac_xmalloc(prin_len + 1 + oset_len + 1); memcpy(oset->string, principal_name, prin_len); oset->string[prin_len] = '.'; memcpy(oset->string + prin_len + 1, oset_name, oset_len); oset->string[prin_len + 1 + oset_len] = 0; oset->linked = NULL; oset->prereqs = NULL; oset->refcount = 1; return oset; } /** * Created a new linking oset and initialize it. */ abac_oset_t *abac_oset_linking_new(char *principal_name, char *linked_role_name, char *oset_name) { assert(principal_name != NULL); assert(linked_role_name != NULL); assert(oset_name != NULL); abac_oset_t *oset; if (strlen(principal_name) == 0 || strlen(linked_role_name) == 0 || strlen(oset_name) == 0) return NULL; /* MEI */ if(debug) printf("DEBUG:adding a new linked (%s) to oset(%s) for principal(%s)\n", linked_role_name, oset_name, principal_name); oset = abac_xmalloc(sizeof(abac_oset_t)); oset->is_object=0; oset->principal_name = abac_xstrdup(principal_name); oset->linked_role_name = abac_xstrdup(linked_role_name); oset->linked_role_params = NULL; oset->oset_name = abac_xstrdup(oset_name); oset->oset_params = NULL; int prin_len = strlen(principal_name); int link_len = strlen(linked_role_name); int oset_len = strlen(oset_name); oset->string = abac_xmalloc(prin_len + 1 + link_len + 1 + oset_len + 1); memcpy(oset->string, principal_name, prin_len); oset->string[prin_len] = '.'; memcpy(oset->string + prin_len + 1, linked_role_name, link_len); oset->string[prin_len + 1 + link_len] = 0; // hack: linked role is first two parts of full string oset->linked = abac_xstrdup(oset->string); oset->string[prin_len + 1 + link_len] = '.'; memcpy(oset->string + prin_len + 1 + link_len + 1, oset_name, oset_len); oset->string[prin_len + 1 + link_len + 1 + oset_len] = 0; oset->prereqs = NULL; oset->refcount = 1; return oset; } /** * Create an intersection oset. */ abac_oset_t *abac_oset_intersection_new(char *name, abac_list_t *prereqs) { abac_oset_t *oset = abac_xmalloc(sizeof(abac_oset_t)); oset->principal_name = oset->linked_role_name = oset->oset_name = NULL; oset->linked_role_params = NULL; oset->oset_params = NULL; oset->linked = NULL; oset->string = abac_xstrdup(name); oset->prereqs = prereqs; oset->refcount = 1; return oset; } /** * Decrease a oset's reference count, freeing it when it reaches 0. */ void abac_oset_free(abac_oset_t *oset) { if(debug) printf("DEBUG:trying to freeing a oset %d\n",(int)oset); if (oset == NULL) return; if(debug) printf("DEBUG:freeing a oset %d\n",(int)oset); --oset->refcount; if (oset->refcount > 0) return; if(oset->principal_name) free(oset->principal_name); if(oset->linked_role_name) free(oset->linked_role_name); if(oset->oset_name) free(oset->oset_name); if(oset->string) free(oset->string); if(oset->linked) free(oset->linked); if (oset->oset_params != NULL) { abac_param_list_free(oset->oset_params); } if (oset->linked_role_params != NULL) { abac_param_list_free(oset->linked_role_params); } if (oset->prereqs != NULL) { abac_oset_t *cur; abac_list_foreach(oset->prereqs, cur, abac_oset_free(cur); ); abac_list_free(oset->prereqs); } free(oset); } abac_oset_t *abac_oset_oset_add_param(abac_oset_t *oset, abac_term_t *param) { if(oset->oset_params == NULL) { oset->oset_params=abac_param_list_new(param); } else { abac_param_list_add_term(oset->oset_params, param); } return oset; } abac_oset_t *abac_oset_add_intersecting_oset(abac_oset_t *oset, abac_oset_t *noset) { abac_list_add(oset->prereqs, noset); return oset; } abac_oset_t *abac_oset_oset_add_linked_param(abac_oset_t *oset, abac_term_t *param) { if(oset->linked_role_params == NULL) { oset->linked_role_params=abac_param_list_new(param); } else { abac_param_list_add_term(oset->linked_role_params, param); } return oset; } /** * Create a non-intersecting oset from a string. Handles principals, osets, * and linking osets. */ static abac_oset_t *_abac_single_oset_from_string(char *string) { int num_dots = 0; char *dot = string; abac_oset_t *ret = NULL; // count the dots while ((dot = strchr(dot, '.')) != NULL) { ++num_dots; ++dot; } // no dots: easy case, principal if (num_dots == 0) ret = abac_oset_principal_new(string); // a oset has exactly 1 dot else if (num_dots == 1) { char *principal = string; // terminate the principal part dot = strchr(principal, '.'); *dot = 0; // oset name comes after the dot char *oset_name = dot + 1; // create the oset (if possible) ret = abac_oset_oset_new(string, oset_name); } // a linked oset has 2 dots else if (num_dots == 2) { char *principal = string; // terminate the principal part dot = strchr(principal, '.'); *dot = 0; // linked name is next, terminate it char *linked = dot + 1; dot = strchr(linked, '.'); *dot = 0; // oset name is last, already terminated char *oset_name = dot + 1; ret = abac_oset_linking_new(principal, linked, oset_name); } // more than two dots: return NULL return ret; } /** * Create a oset from a string. Handles intersecting and normal osets. */ abac_oset_t *abac_oset_from_string(char *string) { abac_list_t *prereqs = NULL; abac_oset_t *ret = NULL, *oset; char *osets[256]; int num_osets, i; char *original = string; // make a copy so we can mess with it string = abac_xstrdup(string); // split the string (in case of an intersection num_osets > 1) abac_split(string, " & ", osets, &num_osets); // normal oset: if (num_osets == 1) ret = _abac_single_oset_from_string(string); else { prereqs = abac_list_new(); for (i = 0; i < num_osets; ++i) { // make sure the tail oset is valid oset = abac_oset_from_string(osets[i]); if (oset == NULL) goto error; abac_list_add(prereqs, oset); } ret = abac_oset_intersection_new(original, prereqs); } free(string); return ret; error: if (prereqs != NULL) { abac_oset_t *cur; abac_list_foreach(prereqs, cur, abac_oset_free(cur); ); abac_list_free(prereqs); } free(string); return NULL; } /** * Increase a oset's reference count. */ abac_oset_t *abac_oset_dup(abac_oset_t *oset) { assert(oset != NULL); ++oset->refcount; return oset; } /** * True if a oset is a principal. */ int abac_oset_is_principal(abac_oset_t *oset) { assert(oset != NULL); return oset->oset_name == NULL && oset->linked_role_name == NULL && oset->prereqs == NULL; } /** * True if a oset is a oset. */ int abac_oset_is_oset(abac_oset_t *oset) { assert(oset != NULL); return oset->oset_name != NULL && oset->linked_role_name == NULL && oset->prereqs == NULL; } /** * True if a oset is a linked oset. */ int abac_oset_is_linking(abac_oset_t *oset) { assert(oset != NULL); return oset->linked_role_name != NULL; } /** * True if a oset is an intersection. */ int abac_oset_is_intersection(abac_oset_t *oset) { assert(oset != NULL); return oset->prereqs != NULL; } char *abac_oset_intersecting_string_with_condition(abac_oset_t *oset) { assert(oset != NULL); char *tmp=NULL; if (oset->prereqs != NULL) { abac_oset_t *cur; abac_list_foreach(oset->prereqs, cur, char *ntmp=abac_oset_string_with_condition(cur); if(tmp==NULL) { asprintf(&tmp,"%s",ntmp); } else { asprintf(&tmp,"%s & %s",tmp, ntmp); } ); } return tmp; } /** * Returns the string representation of the oset. * principal.oset(params..) */ char *abac_oset_string_with_condition(abac_oset_t *oset) { assert(oset != NULL); if(abac_oset_is_intersection(oset)) { return abac_oset_intersecting_string_with_condition(oset); } char *tmp=NULL; /* use cn for now, easy to debug XXX */ char *principal_name; if(abac_oset_is_object(oset)) { principal_name = abac_oset_object_cn(oset); } else principal_name = abac_oset_principal_cn(oset); char *oset_name= oset->oset_name; char *linked_role_name = oset->linked_role_name; char *params_string=NULL; char *linked_params_string=NULL; int len = 0; if(principal_name) len=len+strlen(principal_name)+1; if(oset_name) len = len+strlen(oset_name)+1; if(linked_role_name) len = len+strlen(linked_role_name)+1; if(oset->oset_params) { params_string=abac_param_list_string_with_condition(oset->oset_params); len = len+strlen(params_string)+3; } if(oset->linked_role_params) { linked_params_string=abac_param_list_string_with_condition(oset->linked_role_params); len = len+strlen(linked_params_string)+3; } /* principal */ /* principal.oset */ /* principal.oset(params_string) */ /* principal.linked_role(linked_params_string).oset(params_string) */ tmp = abac_xmalloc(len); if(principal_name) sprintf(tmp,"%s",principal_name); if(linked_role_name) { strcat(tmp,"."); strcat(tmp,linked_role_name); } if(linked_params_string) { strcat(tmp,"("); strcat(tmp,linked_params_string); strcat(tmp,")"); } if(oset_name) { strcat(tmp,"."); strcat(tmp,oset_name); } if(params_string) { strcat(tmp,"("); strcat(tmp,params_string); strcat(tmp,")"); } if(linked_params_string) free(linked_params_string); if(params_string) free(params_string); return tmp; } void abac_print_oset_string_with_condition(abac_oset_t *oset,FILE *fp) { char *string=abac_oset_string_with_condition(oset); if(fp==NULL) printf("%s",string); else fprintf(fp,"%s",string); } /** * Returns the name of a oset. If the oset is A.r1 then return r1. If the oset * is A.r1.r2 then return r2. */ char *abac_oset_oset_name(abac_oset_t *oset) { assert(oset != NULL); return oset->oset_name; } char *abac_oset_oset_param_string(abac_oset_t *oset) { assert(oset != NULL); if(oset->oset_params) { return abac_param_list_string(oset->oset_params); } return NULL; } /** * Returns the linked part of a linking oset. For instance, if the oset is * A.r1.r2, this returns A.r1. */ char *abac_oset_linked_role(abac_oset_t *oset) { assert(oset != NULL); return oset->linked_role_name; } /** * Returns the principal part of a oset. The stuff before the first dot. */ char *abac_oset_principal(abac_oset_t *oset) { assert(oset != NULL); return oset->principal_name; } char *abac_oset_principal_cn(abac_oset_t *oset) { assert(oset != NULL); return abac_cn_with_sha(oset->principal_name); } char *abac_oset_object_cn(abac_oset_t *oset) { assert(oset != NULL && oset->is_object); abac_term_t *obj=oset->principal_object; char *tmp=abac_term_name(obj); return abac_term_name(obj); } abac_condition_t *abac_oset_object_constraint(abac_oset_t *oset) { assert(oset != NULL && oset->is_object); abac_term_t *obj=oset->principal_object; return abac_term_constraint(obj); } /** * Returns the prereqs of an intersection. */ abac_list_t *abac_oset_prereqs(abac_oset_t *oset) { assert(oset != NULL); return oset->prereqs; } abac_param_list_t *abac_oset_linked_role_params(abac_oset_t *oset) { assert(oset != NULL); return oset->linked_role_params; } abac_param_list_t *abac_oset_oset_params(abac_oset_t *oset) { assert(oset != NULL); return oset->oset_params; } /** * Build an attribute key from head and tail osets. Static. */ #define ROLE_SEPARATOR " <- " char *abac_oset_attr_key(abac_oset_t *head_oset, abac_oset_t *tail_oset) { char *head = abac_oset_string_with_condition(head_oset); int head_len = strlen(head); char *tail = abac_oset_string_with_condition(tail_oset); int tail_len = strlen(tail); int sep_len = sizeof(ROLE_SEPARATOR) - 1; // "head <- tail" char *ret = abac_xmalloc(head_len + tail_len + sep_len + 1); memcpy(ret, head, head_len); memcpy(ret + head_len, ROLE_SEPARATOR, sep_len); memcpy(ret + head_len + sep_len, tail, tail_len); ret[head_len + sep_len + tail_len] = 0; return ret; }