#include #include #include #include #include "abac_list.h" #include "abac_util.h" #include "abac_pl.h" static int debug=0; struct _abac_role_t { char *principal_name; char *linked_role_name; abac_param_list_t *linked_role_params; char *role_name; abac_param_list_t *role_params; char *string; char *linked; abac_list_t *prereqs; int refcount; }; /** * Create a new principal and initialize it. */ abac_role_t *abac_role_principal_new(char *principal) { assert(principal != NULL); abac_role_t *role; if (strlen(principal) == 0) return NULL; role = abac_xmalloc(sizeof(abac_role_t)); role->principal_name = abac_xstrdup(principal); role->role_name = NULL; role->role_params = NULL; role->linked_role_name = NULL; role->linked_role_params = NULL; role->string = abac_xstrdup(principal); role->linked = NULL; role->prereqs = NULL; role->refcount = 1; return role; } /** * Create a new role and initialize it. */ abac_role_t *abac_role_role_new(char *principal_name, char *role_name) { assert(principal_name != NULL); assert(role_name != NULL); abac_role_t *role; if (strlen(principal_name) == 0 || strlen(role_name) == 0) return NULL; /* MEI */ if(debug) printf("DEBUG:adding a new role (%s) to principal (%s)\n", role_name, principal_name); role = abac_xmalloc(sizeof(abac_role_t)); role->principal_name = abac_xstrdup(principal_name); role->role_name = abac_xstrdup(role_name); role->role_params = NULL; role->linked_role_name = NULL; role->linked_role_params = NULL; int prin_len = strlen(principal_name); int role_len = strlen(role_name); role->string = abac_xmalloc(prin_len + 1 + role_len + 1); memcpy(role->string, principal_name, prin_len); role->string[prin_len] = '.'; memcpy(role->string + prin_len + 1, role_name, role_len); role->string[prin_len + 1 + role_len] = 0; role->linked = NULL; role->prereqs = NULL; role->refcount = 1; return role; } /** * Created a new linking role and initialize it. */ abac_role_t *abac_role_linking_new(char *principal_name, char *linked_role_name, char *role_name) { assert(principal_name != NULL); assert(linked_role_name != NULL); assert(role_name != NULL); abac_role_t *role; if (strlen(principal_name) == 0 || strlen(linked_role_name) == 0 || strlen(role_name) == 0) return NULL; /* MEI */ if(debug) printf("DEBUG:adding a new linked (%s) to role(%s) for principal(%s)\n", linked_role_name, role_name, principal_name); role = abac_xmalloc(sizeof(abac_role_t)); role->principal_name = abac_xstrdup(principal_name); role->linked_role_name = abac_xstrdup(linked_role_name); role->linked_role_params = NULL; role->role_name = abac_xstrdup(role_name); role->role_params = NULL; int prin_len = strlen(principal_name); int link_len = strlen(linked_role_name); int role_len = strlen(role_name); role->string = abac_xmalloc(prin_len + 1 + link_len + 1 + role_len + 1); memcpy(role->string, principal_name, prin_len); role->string[prin_len] = '.'; memcpy(role->string + prin_len + 1, linked_role_name, link_len); role->string[prin_len + 1 + link_len] = 0; // hack: linked role is first two parts of full string role->linked = abac_xstrdup(role->string); role->string[prin_len + 1 + link_len] = '.'; memcpy(role->string + prin_len + 1 + link_len + 1, role_name, role_len); role->string[prin_len + 1 + link_len + 1 + role_len] = 0; role->prereqs = NULL; role->refcount = 1; return role; } /** * Create an intersection role. */ abac_role_t *abac_role_intersection_new(char *name, abac_list_t *prereqs) { abac_role_t *role = abac_xmalloc(sizeof(abac_role_t)); role->principal_name = role->linked_role_name = role->role_name = NULL; role->linked_role_params = NULL; role->role_params = NULL; role->linked = NULL; role->string = abac_xstrdup(name); role->prereqs = prereqs; role->refcount = 1; return role; } /** * Decrease a role's reference count, freeing it when it reaches 0. */ void abac_role_free(abac_role_t *role) { if(debug) printf("DEBUG:trying to freeing a role %d\n",(int)role); if (role == NULL) return; if(debug) printf("DEBUG:freeing a role %d\n",(int)role); --role->refcount; if (role->refcount > 0) return; if(role->principal_name) free(role->principal_name); if(role->linked_role_name) free(role->linked_role_name); if(role->role_name) free(role->role_name); if(role->string) free(role->string); if(role->linked) free(role->linked); if (role->role_params != NULL) { abac_param_list_free(role->role_params); } if (role->linked_role_params != NULL) { abac_param_list_free(role->linked_role_params); } if (role->prereqs != NULL) { abac_role_t *cur; abac_list_foreach(role->prereqs, cur, abac_role_free(cur); ); abac_list_free(role->prereqs); } free(role); } abac_role_t *abac_role_role_add_param(abac_role_t *role, abac_term_t *param) { if(role->role_params == NULL) { role->role_params=abac_param_list_new(param); } else { abac_param_list_add_term(role->role_params, param); } return role; } abac_role_t *abac_role_add_intersecting_role(abac_role_t *role, abac_role_t *nrole) { abac_list_add(role->prereqs, nrole); return role; } abac_role_t *abac_role_role_add_linked_param(abac_role_t *role, abac_term_t *param) { if(role->linked_role_params == NULL) { role->linked_role_params=abac_param_list_new(param); } else { abac_param_list_add_term(role->linked_role_params, param); } return role; } /** * Create a non-intersecting role from a string. Handles principals, roles, * and linking roles. */ static abac_role_t *_abac_single_role_from_string(char *string) { int num_dots = 0; char *dot = string; abac_role_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_role_principal_new(string); // a role has exactly 1 dot else if (num_dots == 1) { char *principal = string; // terminate the principal part dot = strchr(principal, '.'); *dot = 0; // role name comes after the dot char *role_name = dot + 1; // create the role (if possible) ret = abac_role_role_new(string, role_name); } // a linked role 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; // role name is last, already terminated char *role_name = dot + 1; ret = abac_role_linking_new(principal, linked, role_name); } // more than two dots: return NULL return ret; } /** * Create a role from a string. Handles intersecting and normal roles. */ abac_role_t *abac_role_from_string(char *string) { abac_list_t *prereqs = NULL; abac_role_t *ret = NULL, *role; char *roles[256]; int num_roles, 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_roles > 1) abac_split(string, " & ", roles, &num_roles); // normal role: if (num_roles == 1) ret = _abac_single_role_from_string(string); else { prereqs = abac_list_new(); for (i = 0; i < num_roles; ++i) { // make sure the tail role is valid role = abac_role_from_string(roles[i]); if (role == NULL) goto error; abac_list_add(prereqs, role); } ret = abac_role_intersection_new(original, prereqs); } free(string); return ret; error: if (prereqs != NULL) { abac_role_t *cur; abac_list_foreach(prereqs, cur, abac_role_free(cur); ); abac_list_free(prereqs); } free(string); return NULL; } /** * Increase a role's reference count. */ abac_role_t *abac_role_dup(abac_role_t *role) { assert(role != NULL); ++role->refcount; return role; } /** * True if a role is a principal. */ int abac_role_is_principal(abac_role_t *role) { assert(role != NULL); return role->role_name == NULL && role->linked_role_name == NULL && role->prereqs == NULL; } /** * True if a role is a role. */ int abac_role_is_role(abac_role_t *role) { assert(role != NULL); return role->role_name != NULL && role->linked_role_name == NULL && role->prereqs == NULL; } /** * True if a role is a linked role. */ int abac_role_is_linking(abac_role_t *role) { assert(role != NULL); return role->linked_role_name != NULL; } /** * True if a role is an intersection. */ int abac_role_is_intersection(abac_role_t *role) { assert(role != NULL); return role->prereqs != NULL; } char *abac_role_intersecting_string_with_condition(abac_role_t *role) { assert(role != NULL); char *tmp=NULL; if (role->prereqs != NULL) { abac_role_t *cur; abac_list_foreach(role->prereqs, cur, char *ntmp=abac_role_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 role. * principal.role(params..) */ char *abac_role_string_with_condition(abac_role_t *role) { assert(role != NULL); if(abac_role_is_intersection(role)) { return abac_role_intersecting_string_with_condition(role); } char *tmp=NULL; /* use cn for now, easy to debug XXX */ char *principal_name = abac_role_principal_cn(role); char *role_name= role->role_name; char *linked_role_name = role->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(role_name) len = len+strlen(role_name)+1; if(linked_role_name) len = len+strlen(linked_role_name)+1; if(role->role_params) { params_string=abac_param_list_string_with_condition(role->role_params); len = len+strlen(params_string)+3; } if(role->linked_role_params) { linked_params_string=abac_param_list_string_with_condition(role->linked_role_params); len = len+strlen(linked_params_string)+3; } /* principal */ /* principal.role */ /* principal.role(params_string) */ /* principal.linked_role(linked_params_string).role(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(role_name) { strcat(tmp,"."); strcat(tmp,role_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_role_string_with_condition(abac_role_t *role,FILE *fp) { char *string=abac_role_string_with_condition(role); if(fp==NULL) printf("%s",string); else fprintf(fp,"%s",string); } /** * Returns the name of a role. If the role is A.r1 then return r1. If the role * is A.r1.r2 then return r2. */ char *abac_role_role_name(abac_role_t *role) { assert(role != NULL); return role->role_name; } char *abac_role_role_param_string(abac_role_t *role) { assert(role != NULL); if(role->role_params) { return abac_param_list_string(role->role_params); } return NULL; } /** * Returns the linked part of a linking role. For instance, if the role is * A.r1.r2, this returns A.r1. */ char *abac_role_linked_role(abac_role_t *role) { assert(role != NULL); return role->linked_role_name; } /** * Returns the principal part of a role. The stuff before the first dot. */ char *abac_role_principal(abac_role_t *role) { assert(role != NULL); return role->principal_name; } char *abac_role_principal_cn(abac_role_t *role) { assert(role != NULL); return abac_cn_with_sha(role->principal_name); } /** * Returns the prereqs of an intersection. */ abac_list_t *abac_role_prereqs(abac_role_t *role) { assert(role != NULL); return role->prereqs; } abac_param_list_t *abac_role_linked_role_params(abac_role_t *role) { assert(role != NULL); return role->linked_role_params; } abac_param_list_t *abac_role_role_params(abac_role_t *role) { assert(role != NULL); return role->role_params; } /** * Build an attribute key from head and tail roles. Static. */ #define ROLE_SEPARATOR " <- " char *abac_role_attr_key(abac_role_t *head_role, abac_role_t *tail_role) { char *head = abac_role_string_with_condition(head_role); int head_len = strlen(head); char *tail = abac_role_string_with_condition(tail_role); 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; }