%{ #include #include #include #include #include #include #include #include "common.h" #include "policy_lang.h" typedef struct { uint64_t value; int bits; /* zero if this is a flexint */ } sized_integer_t; typedef struct { int k; /* one if leaf, otherwise threshold */ char* attr; /* attribute string if leaf, otherwise null */ GPtrArray* children; /* pointers to bswabe_policy_t's, len == 0 for leaves */ } cpabe_policy_t; cpabe_policy_t* final_policy = 0; int yylex(); void yyerror( const char* s ); sized_integer_t* expint( uint64_t value, uint64_t bits ); sized_integer_t* flexint( uint64_t value ); cpabe_policy_t* leaf_policy( char* attr ); cpabe_policy_t* kof2_policy( int k, cpabe_policy_t* l, cpabe_policy_t* r ); cpabe_policy_t* kof_policy( int k, GPtrArray* list ); cpabe_policy_t* eq_policy( sized_integer_t* n, char* attr ); cpabe_policy_t* lt_policy( sized_integer_t* n, char* attr ); cpabe_policy_t* gt_policy( sized_integer_t* n, char* attr ); cpabe_policy_t* le_policy( sized_integer_t* n, char* attr ); cpabe_policy_t* ge_policy( sized_integer_t* n, char* attr ); %} %union { char* str; uint64_t nat; sized_integer_t* sint; cpabe_policy_t* tree; GPtrArray* list; } %token TAG %token INTLIT %type number %type policy %type arg_list %left OR %left AND %token OF %token LEQ %token GEQ %% result: policy { final_policy = $1; } number: INTLIT '#' INTLIT { $$ = expint($1, $3); } | INTLIT { $$ = flexint($1); } policy: TAG { $$ = leaf_policy($1); } | policy OR policy { $$ = kof2_policy(1, $1, $3); } | policy AND policy { $$ = kof2_policy(2, $1, $3); } | INTLIT OF '(' arg_list ')' { $$ = kof_policy($1, $4); } | TAG '=' number { $$ = eq_policy($3, $1); } | TAG '<' number { $$ = lt_policy($3, $1); } | TAG '>' number { $$ = gt_policy($3, $1); } | TAG LEQ number { $$ = le_policy($3, $1); } | TAG GEQ number { $$ = ge_policy($3, $1); } | number '=' TAG { $$ = eq_policy($1, $3); } | number '<' TAG { $$ = gt_policy($1, $3); } | number '>' TAG { $$ = lt_policy($1, $3); } | number LEQ TAG { $$ = ge_policy($1, $3); } | number GEQ TAG { $$ = le_policy($1, $3); } | '(' policy ')' { $$ = $2; } arg_list: policy { $$ = g_ptr_array_new(); g_ptr_array_add($$, $1); } | arg_list ',' policy { $$ = $1; g_ptr_array_add($$, $3); } ; %% sized_integer_t* expint( uint64_t value, uint64_t bits ) { sized_integer_t* s; if( bits == 0 ) die("error parsing policy: zero-length integer \"%llub%llu\"\n", value, bits); else if( bits > 64 ) die("error parsing policy: no more than 64 bits allowed \"%llub%llu\"\n", value, bits); s = malloc(sizeof(sized_integer_t)); s->value = value; s->bits = bits; return s; } sized_integer_t* flexint( uint64_t value ) { sized_integer_t* s; s = malloc(sizeof(sized_integer_t)); s->value = value; s->bits = 0; return s; } void policy_free( cpabe_policy_t* p ) { int i; if( p->attr ) free(p->attr); for( i = 0; i < p->children->len; i++ ) policy_free(g_ptr_array_index(p->children, i)); g_ptr_array_free(p->children, 1); free(p); } cpabe_policy_t* leaf_policy( char* attr ) { cpabe_policy_t* p; p = (cpabe_policy_t*) malloc(sizeof(cpabe_policy_t)); p->k = 1; p->attr = attr; p->children = g_ptr_array_new(); return p; } cpabe_policy_t* kof2_policy( int k, cpabe_policy_t* l, cpabe_policy_t* r ) { cpabe_policy_t* p; p = (cpabe_policy_t*) malloc(sizeof(cpabe_policy_t)); p->k = k; p->attr = 0; p->children = g_ptr_array_new(); g_ptr_array_add(p->children, l); g_ptr_array_add(p->children, r); return p; } cpabe_policy_t* kof_policy( int k, GPtrArray* list ) { cpabe_policy_t* p; if( k < 1 ) die("error parsing policy: trivially satisfied operator \"%dof\"\n", k); else if( k > list->len ) die("error parsing policy: unsatisfiable operator \"%dof\" (only %d operands)\n", k, list->len); else if( list->len == 1 ) die("error parsing policy: identity operator \"%dof\" (only one operand)\n", k); p = (cpabe_policy_t*) malloc(sizeof(cpabe_policy_t)); p->k = k; p->attr = 0; p->children = list; return p; } char* bit_marker( char* base, char* tplate, int bit, char val ) { char* lx; char* rx; char* s; lx = g_strnfill(64 - bit - 1, 'x'); rx = g_strnfill(bit, 'x'); s = g_strdup_printf(tplate, base, lx, !!val, rx); free(lx); free(rx); return s; } cpabe_policy_t* eq_policy( sized_integer_t* n, char* attr ) { if( n->bits == 0 ) return leaf_policy (g_strdup_printf("%s_flexint_%llu", attr, n->value)); else return leaf_policy (g_strdup_printf("%s_expint%02d_%llu", attr, n->bits, n->value)); return 0; } cpabe_policy_t* bit_marker_list( int gt, char* attr, char* tplate, int bits, uint64_t value ) { cpabe_policy_t* p; int i; i = 0; while( gt ? (((uint64_t)1)<attr = 0; p->children = g_ptr_array_new(); for( k = 2; k <= 32; k *= 2 ) if( ( gt && ((uint64_t)1< value) || (!gt && ((uint64_t)1<= value) ) g_ptr_array_add (p->children, leaf_policy (g_strdup_printf(gt ? "%s_ge_2^%02d" : "%s_lt_2^%02d", attr, k))); p->k = gt ? 1 : p->children->len; if( p->children->len == 0 ) { policy_free(p); p = 0; } else if( p->children->len == 1 ) { cpabe_policy_t* t; t = g_ptr_array_remove_index(p->children, 0); policy_free(p); p = t; } return p; } cpabe_policy_t* cmp_policy( sized_integer_t* n, int gt, char* attr ) { cpabe_policy_t* p; char* tplate; /* some error checking */ if( gt && n->value >= ((uint64_t)1<<(n->bits ? n->bits : 64)) - 1 ) die("error parsing policy: unsatisfiable integer comparison %s > %llu\n" "(%d-bits are insufficient to satisfy)\n", attr, n->value, n->bits ? n->bits : 64); else if( !gt && n->value == 0 ) die("error parsing policy: unsatisfiable integer comparison %s < 0\n" "(all numerical attributes are unsigned)\n", attr); else if( !gt && n->value > ((uint64_t)1<<(n->bits ? n->bits : 64)) - 1 ) die("error parsing policy: trivially satisfied integer comparison %s < %llu\n" "(any %d-bit number will satisfy)\n", attr, n->value, n->bits ? n->bits : 64); /* create it */ /* horrible */ tplate = n->bits ? g_strdup_printf("%%s_expint%02d_%%s%%d%%s", n->bits) : strdup("%s_flexint_%s%d%s"); p = bit_marker_list(gt, attr, tplate, n->bits ? n->bits : (n->value >= ((uint64_t)1<<32) ? 64 : n->value >= ((uint64_t)1<<16) ? 32 : n->value >= ((uint64_t)1<< 8) ? 16 : n->value >= ((uint64_t)1<< 4) ? 8 : n->value >= ((uint64_t)1<< 2) ? 4 : 2), n->value); free(tplate); if( !n->bits ) { cpabe_policy_t* l; l = flexint_leader(gt, attr, n->value); if( l ) p = kof2_policy(gt ? 1 : 2, l, p); } return p; } cpabe_policy_t* lt_policy( sized_integer_t* n, char* attr ) { return cmp_policy(n, 0, attr); } cpabe_policy_t* gt_policy( sized_integer_t* n, char* attr ) { return cmp_policy(n, 1, attr); } cpabe_policy_t* le_policy( sized_integer_t* n, char* attr ) { n->value++; return cmp_policy(n, 0, attr); } cpabe_policy_t* ge_policy( sized_integer_t* n, char* attr ) { n->value--; return cmp_policy(n, 1, attr); } char* cur_string = 0; #define PEEK_CHAR ( *cur_string ? *cur_string : EOF ) #define NEXT_CHAR ( *cur_string ? *(cur_string++) : EOF ) int yylex() { int c; int r; while( isspace(c = NEXT_CHAR) ); r = 0; if( c == EOF ) r = 0; else if( c == '&' ) r = AND; else if( c == '|' ) r = OR; else if( strchr("(),=#", c) || (strchr("<>", c) && PEEK_CHAR != '=') ) r = c; else if( c == '<' && PEEK_CHAR == '=' ) { NEXT_CHAR; r = LEQ; } else if( c == '>' && PEEK_CHAR == '=' ) { NEXT_CHAR; r = GEQ; } else if( isdigit(c) ) { GString* s; s = g_string_new(""); g_string_append_c(s, c); while( isdigit(PEEK_CHAR) ) g_string_append_c(s, NEXT_CHAR); sscanf(s->str, "%llu", &(yylval.nat)); g_string_free(s, 1); r = INTLIT; } else if( isalpha(c) ) { GString* s; s = g_string_new(""); g_string_append_c(s, c); while( isalnum(PEEK_CHAR) || PEEK_CHAR == '_' ) g_string_append_c(s, NEXT_CHAR); if( !strcmp(s->str, "and") ) { g_string_free(s, 1); r = AND; } else if( !strcmp(s->str, "or") ) { g_string_free(s, 1); r = OR; } else if( !strcmp(s->str, "of") ) { g_string_free(s, 1); r = OF; } else { yylval.str = s->str; g_string_free(s, 0); r = TAG; } } else die("syntax error at \"%c%s\"\n", c, cur_string); return r; } void yyerror( const char* s ) { die("error parsing policy: %s\n", s); } #define POLICY_IS_OR(p) (((cpabe_policy_t*)(p))->k == 1 && ((cpabe_policy_t*)(p))->children->len) #define POLICY_IS_AND(p) (((cpabe_policy_t*)(p))->k == ((cpabe_policy_t*)(p))->children->len) void merge_child( cpabe_policy_t* p, int i ) { int j; cpabe_policy_t* c; c = g_ptr_array_index(p->children, i); if( POLICY_IS_AND(p) ) { p->k += c->k; p->k--; } g_ptr_array_remove_index_fast(p->children, i); for( j = 0; j < c->children->len; j++ ) g_ptr_array_add(p->children, g_ptr_array_index(c->children, j)); g_ptr_array_free(c->children, 0); free(c); } void simplify( cpabe_policy_t* p ) { int i; for( i = 0; i < p->children->len; i++ ) simplify(g_ptr_array_index(p->children, i)); if( POLICY_IS_OR(p) ) for( i = 0; i < p->children->len; i++ ) if( POLICY_IS_OR(g_ptr_array_index(p->children, i)) ) merge_child(p, i); if( POLICY_IS_AND(p) ) for( i = 0; i < p->children->len; i++ ) if( POLICY_IS_AND(g_ptr_array_index(p->children, i)) ) merge_child(p, i); } int cmp_tidy( const void* a, const void* b ) { cpabe_policy_t* pa; cpabe_policy_t* pb; pa = *((cpabe_policy_t**) a); pb = *((cpabe_policy_t**) b); if( pa->children->len > 0 && pb->children->len == 0 ) return -1; else if( pa->children->len == 0 && pb->children->len > 0 ) return 1; else if( pa->children->len == 0 && pb->children->len == 0 ) return strcmp(pa->attr, pb->attr); else return 0; } void tidy( cpabe_policy_t* p ) { int i; for( i = 0; i < p->children->len; i++ ) tidy(g_ptr_array_index(p->children, i)); if( p->children->len > 0 ) qsort(p->children->pdata, p->children->len, sizeof(cpabe_policy_t*), cmp_tidy); } char* format_policy_postfix( cpabe_policy_t* p ) { int i; char* r; char* s; char* t; if( p->children->len == 0 ) return strdup(p->attr); r = format_policy_postfix(g_ptr_array_index(p->children, 0)); for( i = 1; i < p->children->len; i++ ) { s = format_policy_postfix(g_ptr_array_index(p->children, i)); t = g_strjoin(" ", r, s, (char*) 0); free(r); free(s); r = t; } t = g_strdup_printf("%s %dof%d", r, p->k, p->children->len); free(r); return t; } /* Crufty. */ int actual_bits( uint64_t value ) { int i; for( i = 32; i >= 1; i /= 2 ) if( value >= ((uint64_t)1<