/* Copyright (C) 2017 mod_auth_gssapi contributors - See COPYING for (C) terms * * Bison file for the GssapiRequiredNameAttributes option parser. * * Rule := (RequiredKV | "(" Rule ")"), { ' ', (AND|OR), ' ', Rule } ; * RequiredKV := (Key, "=", Value) | (Key, ":=" BinValue) ; * Key := ; * Value := | '*' ; * BinValue := ; * AND := "and" | "AND" ; * OR := "or" | "OR" ; * */ %{ #include #include #include #include int yylex(void); typedef struct yy_buffer_state * YY_BUFFER_STATE; extern void yyerror(const char **keys, const char **vals, int *status, const char *s); extern int yyparse(const char **keys, const char **vals, int *status); extern YY_BUFFER_STATE yy_scan_string(char * str); extern void yy_delete_buffer(YY_BUFFER_STATE buffer); static size_t b64_len(const char *val); static char *b64_enc(const char *val, size_t len); %} %union { char *sval; int ival; } %token LPAREN %token RPAREN %token SPACE %token OR %token AND %token EQUAL %token EQUALBIN %token AST %token STRING %token INT %type STRING %type INT rule rule_start requiredkv %parse-param {const char **keys} {const char **vals} {int *status} %% expr: rule { if (status != NULL) *status = $1; } ; rule: rule_start | rule_start SPACE AND SPACE rule { $$ = $1 && $5; } | rule_start SPACE OR SPACE rule { $$ = $1 || $5; } ; rule_start: LPAREN rule RPAREN { $$ = $2; } | requiredkv { $$ = $1; } ; requiredkv: STRING EQUAL STRING { int ret = 0; size_t sz; if (keys != NULL && vals != NULL) { for (int i = 0; keys[i] != NULL && vals[i] != NULL; i++) { if (strcmp($1, keys[i]) != 0) { continue; } sz = 0; memcpy(&sz, vals[i], sizeof(sz)); if (sz == 0) { continue; } if (!memcmp($3, vals[i] + sizeof(sz), sz)) { ret = 1; break; } } } $$ = ret; } | STRING EQUAL AST { int ret = 0; if (keys != NULL && vals != NULL) { for (int i = 0; keys[i] != NULL && vals[i] != NULL; i++) { if (strcmp($1, keys[i]) == 0) { ret = 1; break; } } } $$ = ret; } | STRING EQUALBIN STRING { int ret = 0; if (keys != NULL && vals != NULL) { for (int i = 0; keys[i] != NULL && vals[i] != NULL; i++) { if (strcmp($1, keys[i]) != 0) { continue; } size_t b64len = b64_len(vals[i]); /* b64len includes the NULL terminator. */ if (strlen($3) + 1 != b64len) { continue; } char *b64val = b64_enc(vals[i], b64len); if (!b64val) { continue; } if (strcmp($3, b64val) == 0) { ret = 1; } free(b64val); if (ret) { break; } } } $$ = ret; } ; %% static size_t b64_len(const char *val) { size_t sz = 0; memcpy(&sz, val, sizeof(sz)); if (sz == 0) return sz; return apr_base64_encode_len(sz); } static char *b64_enc(const char *val, size_t len) { size_t sz = 0; char *b64val; memcpy(&sz, val, sizeof(sz)); if (sz == 0) return NULL; b64val = calloc(1, len + 1); if (!b64val) return NULL; apr_base64_encode(b64val, val + sizeof(sz), sz); return b64val; } /* Return 1 if the given name attributes and values (NULL terminated arrays) * satisfy the expression. This does not handle parsing errors from yyparse, * so expr should be checked by required_name_attr_expr_check() first. */ int mag_verify_name_attributes(const char *expr, const char **attrs, const char **vals) { int ret = 0, status = 0; YY_BUFFER_STATE buffer; /* No name attribute requirements. Pass. */ if (expr == NULL) { return 1; } /* No name attributes but required attributes are specified. Fail. */ if (attrs == NULL || vals == NULL || attrs[0] == NULL || vals[0] == NULL) { return 0; } buffer = yy_scan_string((char *)expr); ret = yyparse(attrs, vals, &status); yy_delete_buffer(buffer); return ret == 0 && status; } /* Return 1 if the expression is provided and valid, else return 0. */ int mag_check_name_attr_expr(const char *expr) { int ret; YY_BUFFER_STATE buffer = yy_scan_string((char *)expr); /* Just verify the syntax. */ ret = yyparse(NULL, NULL, NULL); yy_delete_buffer(buffer); return ret == 0; } /* Define a no-op yyerror(). Syntax errors are logged outside of calling * required_name_attr_expr_check(). */ void yyerror(const char **keys, const char **vals, int *status, const char *s) { return; }