src/lib/libkeynote/keynote.y

902 lines
20 KiB
Plaintext

/* $OpenBSD: keynote.y,v 1.19 2022/12/27 17:10:06 jmc Exp $ */
/*
* The author of this code is Angelos D. Keromytis (angelos@dsl.cis.upenn.edu)
*
* This code was written by Angelos D. Keromytis in Philadelphia, PA, USA,
* in April-May 1998
*
* Copyright (C) 1998, 1999 by Angelos D. Keromytis.
*
* Permission to use, copy, and modify this software with or without fee
* is hereby granted, provided that this entire notice is included in
* all copies of any software which is or includes a copy or
* modification of this software.
*
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTY. IN PARTICULAR, THE AUTHORS MAKES NO
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
* MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
* PURPOSE.
*/
%union {
char *string;
double doubval;
int intval;
int bool;
};
%type <bool> stringexp numexp expr floatexp
%type <intval> NUM KOF numex afterhint notemptyprog
%type <intval> notemptykeypredicate prog key keyexp keylist
%type <doubval> FLOAT floatex
%type <string> STRING VARIABLE str strnotconcat
%token TRUE FALSE NUM FLOAT STRING VARIABLE
%token OPENPAREN CLOSEPAREN EQQ COMMA ACTSTR LOCINI KOF KEYPRE KNVERSION
%token DOTT SIGNERKEY HINT OPENBLOCK CLOSEBLOCK SIGNATUREENTRY PRIVATEKEY
%token SEMICOLON TRUE FALSE
%nonassoc EQ NE LT GT LE GE REGEXP
%left OR
%left AND
%right NOT
%left PLUS MINUS DOTT
%left MULT DIV MOD
%left EXP
%nonassoc UNARYMINUS DEREF OPENNUM OPENFLT
%start grammarswitch
%{
#include <sys/types.h>
#include <ctype.h>
#include <math.h>
#include <regex.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "keynote.h"
#include "assertion.h"
static int *keynote_kth_array = NULL;
static int keylistcount = 0;
static int resolve_assertion(char *);
static int keynote_init_kth(void);
static int isfloatstring(char *);
static int checkexception(int);
static char *my_lookup(char *);
static int intpow(int, int);
static int get_kth(int);
%}
%%
grammarswitch: LOCINI { keynote_exceptionflag = keynote_donteval = 0; }
localinit
| ACTSTR { keynote_exceptionflag = keynote_donteval = 0; } program
| KEYPRE { keynote_exceptionflag = keynote_donteval = 0; }
keypredicate
| SIGNERKEY { keynote_exceptionflag = keynote_donteval = 0; } key
| SIGNATUREENTRY { keynote_exceptionflag = keynote_donteval = 0; }
key
| KNVERSION { keynote_exceptionflag = keynote_donteval = 0; }
STRING { keynote_lex_remove($3);
if (strcmp($3, KEYNOTE_VERSION_STRING))
keynote_errno = ERROR_SYNTAX;
free($3);
}
| PRIVATEKEY { keynote_exceptionflag = keynote_donteval = 0; }
STRING { keynote_lex_remove($3);
keynote_privkey = $3;
}
keypredicate: /* Nothing */ { keynote_returnvalue = 0;
return 0;
}
| notemptykeypredicate { keynote_returnvalue = $1;
return 0;
}
notemptykeypredicate: key { $$ = $1; }
| keyexp { $$ = $1; }
keyexp: notemptykeypredicate AND { if (($1 == 0) && !keynote_justrecord)
keynote_donteval = 1;
} notemptykeypredicate
{ if ($1 > $4)
$$ = $4;
else
$$ = $1;
keynote_donteval = 0;
} /* Min */
| notemptykeypredicate OR { if (($1 == (keynote_current_session->ks_values_num - 1)) && !keynote_justrecord)
keynote_donteval = 1;
} notemptykeypredicate
{ if ($1 >= $4)
$$ = $1;
else
$$ = $4;
keynote_donteval = 0;
} /* Max */
| OPENPAREN keyexp CLOSEPAREN { $$ = $2; }
| KOF { keylistcount = 0; } OPENPAREN {
if (!keynote_justrecord && !keynote_donteval)
if (keynote_init_kth() == -1)
return -1;
} keylist CLOSEPAREN
{
if (keylistcount < $1)
{
keynote_errno = ERROR_SYNTAX;
return -1;
}
if (!keynote_justrecord && !keynote_donteval)
$$ = get_kth($1);
else
$$ = 0;
} /* K-th */
keylist: key
{ /* Don't do anything if we're just recording */
if (!keynote_justrecord && !keynote_donteval)
if (($1 < keynote_current_session->ks_values_num) && ($1 >= 0))
keynote_kth_array[$1]++;
keylistcount++;
}
| key COMMA keylist
{ /* Don't do anything if we're just recording */
if (!keynote_justrecord && !keynote_donteval)
if (($1 < keynote_current_session->ks_values_num) && ($1 >= 0))
keynote_kth_array[$1]++;
keylistcount++;
}
key: str {
if (keynote_donteval)
$$ = 0;
else
{
keynote_lex_remove($1);
if (keynote_justrecord)
{
if (keynote_keylist_add(&keynote_keypred_keylist,
$1) == -1)
{
free($1);
return -1;
}
$$ = 0;
}
else
switch (keynote_in_action_authorizers($1, KEYNOTE_ALGORITHM_UNSPEC))
{
case -1:
free($1);
return -1;
case RESULT_TRUE:
free($1);
$$ = keynote_current_session->ks_values_num -
1;
break;
default:
$$ = resolve_assertion($1);
free($1);
break;
}
}
}
localinit: /* Nothing */
| localconstants
localconstants: VARIABLE EQQ STRING
{
int i;
keynote_lex_remove($1);
keynote_lex_remove($3);
/*
* Variable names starting with underscores are illegal here.
*/
if ($1[0] == '_')
{
free($1);
free($3);
keynote_errno = ERROR_SYNTAX;
return -1;
}
/* If the identifier already exists, report error. */
if (keynote_env_lookup($1, &keynote_init_list, 1) != NULL)
{
free($1);
free($3);
keynote_errno = ERROR_SYNTAX;
return -1;
}
i = keynote_env_add($1, $3, &keynote_init_list, 1, 0);
free($1);
free($3);
if (i != RESULT_TRUE)
return -1;
}
| VARIABLE EQQ STRING
{
int i;
keynote_lex_remove($1);
keynote_lex_remove($3);
/*
* Variable names starting with underscores are illegal here.
*/
if ($1[0] == '_')
{
free($1);
free($3);
keynote_errno = ERROR_SYNTAX;
return -1;
}
/* If the identifier already exists, report error. */
if (keynote_env_lookup($1, &keynote_init_list, 1) != NULL)
{
free($1);
free($3);
keynote_errno = ERROR_SYNTAX;
return -1;
}
i = keynote_env_add($1, $3, &keynote_init_list, 1, 0);
free($1);
free($3);
if (i != RESULT_TRUE)
return -1;
} localconstants
program: prog {
keynote_returnvalue = $1;
return 0;
}
prog: /* Nada */ { $$ = 0; }
| notemptyprog {
/*
* Cleanup envlist of additions such as
* regexp results
*/
keynote_env_cleanup(&keynote_temp_list, 1);
} SEMICOLON prog
{
if ($1 > $4)
$$ = $1;
else
$$ = $4;
}
notemptyprog: expr HINT afterhint
{
if (checkexception($1))
$$ = $3;
else
$$ = 0;
}
| expr
{
if (checkexception($1))
$$ = keynote_current_session->ks_values_num - 1;
else
$$ = 0;
}
afterhint: str { if (keynote_exceptionflag || keynote_donteval)
$$ = 0;
else
{
keynote_lex_remove($1);
$$ = keynote_retindex($1);
if ($$ == -1) /* Invalid return value */
$$ = 0;
free($1);
}
}
| OPENBLOCK prog CLOSEBLOCK { $$ = $2; }
expr: OPENPAREN expr CLOSEPAREN { $$ = $2; }
| expr AND { if ($1 == 0)
keynote_donteval = 1;
} expr { $$ = ($1 && $4);
keynote_donteval = 0;
}
| expr OR { if ($1)
keynote_donteval = 1;
} expr { $$ = ($1 || $4);
keynote_donteval = 0;
}
| NOT expr { $$ = !($2); }
| numexp { $$ = $1; }
| floatexp { $$ = $1; }
| stringexp { $$ = $1; }
| TRUE { $$ = 1; }
| FALSE { $$ = 0; }
numexp: numex LT numex { $$ = $1 < $3; }
| numex GT numex { $$ = $1 > $3; }
| numex EQ numex { $$ = $1 == $3; }
| numex LE numex { $$ = $1 <= $3; }
| numex GE numex { $$ = $1 >= $3; }
| numex NE numex { $$ = $1 != $3; }
floatexp: floatex LT floatex { $$ = $1 < $3; }
| floatex GT floatex { $$ = $1 > $3; }
| floatex LE floatex { $$ = $1 <= $3; }
| floatex GE floatex { $$ = $1 >= $3; }
numex: numex PLUS numex { $$ = $1 + $3; }
| numex MINUS numex { $$ = $1 - $3; }
| numex MULT numex { $$ = $1 * $3; }
| numex DIV numex { if ($3 == 0)
{
if (!keynote_donteval)
keynote_exceptionflag = 1;
}
else
$$ = ($1 / $3);
}
| numex MOD numex { if ($3 == 0)
{
if (!keynote_donteval)
keynote_exceptionflag = 1;
}
else
$$ = $1 % $3;
}
| numex EXP numex { $$ = intpow($1, $3); }
| MINUS numex %prec UNARYMINUS { $$ = -($2); }
| OPENPAREN numex CLOSEPAREN { $$ = $2; }
| NUM { $$ = $1; }
| OPENNUM strnotconcat { if (keynote_exceptionflag ||
keynote_donteval)
$$ = 0;
else
{
keynote_lex_remove($2);
if (!isfloatstring($2))
$$ = 0;
else
$$ = (int) floor(atof($2));
free($2);
}
}
floatex: floatex PLUS floatex { $$ = ($1 + $3); }
| floatex MINUS floatex { $$ = ($1 - $3); }
| floatex MULT floatex { $$ = ($1 * $3); }
| floatex DIV floatex { if ($3 == 0)
{
if (!keynote_donteval)
keynote_exceptionflag = 1;
}
else
$$ = ($1 / $3);
}
| floatex EXP floatex { if (!keynote_exceptionflag &&
!keynote_donteval)
$$ = pow($1, $3);
}
| MINUS floatex %prec UNARYMINUS { $$ = -($2); }
| OPENPAREN floatex CLOSEPAREN { $$ = $2; }
| FLOAT { $$ = $1; }
| OPENFLT strnotconcat {
if (keynote_exceptionflag ||
keynote_donteval)
$$ = 0.0;
else
{
keynote_lex_remove($2);
if (!isfloatstring($2))
$$ = 0.0;
else
$$ = atof($2);
free($2);
}
}
stringexp: str EQ str {
if (keynote_exceptionflag || keynote_donteval)
$$ = 0;
else
{
$$ = strcmp($1, $3) == 0 ? 1 : 0;
keynote_lex_remove($1);
keynote_lex_remove($3);
free($1);
free($3);
}
}
| str NE str {
if (keynote_exceptionflag || keynote_donteval)
$$ = 0;
else
{
$$ = strcmp($1, $3) != 0 ? 1 : 0;
keynote_lex_remove($1);
keynote_lex_remove($3);
free($1);
free($3);
}
}
| str LT str {
if (keynote_exceptionflag || keynote_donteval)
$$ = 0;
else
{
$$ = strcmp($1, $3) < 0 ? 1 : 0;
keynote_lex_remove($1);
keynote_lex_remove($3);
free($1);
free($3);
}
}
| str GT str {
if (keynote_exceptionflag || keynote_donteval)
$$ = 0;
else
{
$$ = strcmp($1, $3) > 0 ? 1 : 0;
keynote_lex_remove($1);
keynote_lex_remove($3);
free($1);
free($3);
}
}
| str LE str {
if (keynote_exceptionflag || keynote_donteval)
$$ = 0;
else
{
$$ = strcmp($1, $3) <= 0 ? 1 : 0;
keynote_lex_remove($1);
keynote_lex_remove($3);
free($1);
free($3);
}
}
| str GE str {
if (keynote_exceptionflag || keynote_donteval)
$$ = 0;
else
{
$$ = strcmp($1, $3) >= 0 ? 1 : 0;
keynote_lex_remove($1);
keynote_lex_remove($3);
free($1);
free($3);
}
}
| str REGEXP str
{
regmatch_t pmatch[32];
char grp[10], *gr;
regex_t preg;
int i;
if (keynote_exceptionflag || keynote_donteval)
$$ = 0;
else
{
keynote_lex_remove($1);
keynote_lex_remove($3);
memset(pmatch, 0, sizeof(pmatch));
memset(grp, 0, sizeof(grp));
if (regcomp(&preg, $3, REG_EXTENDED))
{
free($1);
free($3);
keynote_exceptionflag = 1;
}
else
{
/* Clean-up residuals from previous regexps */
keynote_env_cleanup(&keynote_temp_list, 1);
free($3);
i = regexec(&preg, $1, 32, pmatch, 0);
$$ = (i == 0 ? 1 : 0);
if (i == 0)
{
snprintf(grp, sizeof grp, "%lu",
(unsigned long)preg.re_nsub);
if (keynote_env_add("_0", grp, &keynote_temp_list,
1, 0) != RESULT_TRUE)
{
free($1);
regfree(&preg);
return -1;
}
for (i = 1; i < 32 && pmatch[i].rm_so != -1; i++)
{
gr = calloc(pmatch[i].rm_eo - pmatch[i].rm_so +
1, sizeof(char));
if (gr == NULL)
{
free($1);
regfree(&preg);
keynote_errno = ERROR_MEMORY;
return -1;
}
strncpy(gr, $1 + pmatch[i].rm_so,
pmatch[i].rm_eo - pmatch[i].rm_so);
gr[pmatch[i].rm_eo - pmatch[i].rm_so] = '\0';
snprintf(grp, sizeof grp, "_%d", i);
if (keynote_env_add(grp, gr, &keynote_temp_list,
1, 0) == -1)
{
free($1);
regfree(&preg);
free(gr);
return -1;
}
else
free(gr);
}
}
regfree(&preg);
free($1);
}
}
}
str: str DOTT str { if (keynote_exceptionflag || keynote_donteval)
$$ = NULL;
else
{
int len = strlen($1) + strlen($3) + 1;
$$ = calloc(len, sizeof(char));
keynote_lex_remove($1);
keynote_lex_remove($3);
if ($$ == NULL)
{
free($1);
free($3);
keynote_errno = ERROR_MEMORY;
return -1;
}
snprintf($$, len, "%s%s", $1, $3);
free($1);
free($3);
if (keynote_lex_add($$, LEXTYPE_CHAR) == -1)
return -1;
}
}
| strnotconcat { $$ = $1; }
strnotconcat: STRING { $$ = $1; }
| OPENPAREN str CLOSEPAREN { $$ = $2; }
| VARIABLE { if (keynote_exceptionflag || keynote_donteval)
$$ = NULL;
else
{
$$ = my_lookup($1);
keynote_lex_remove($1);
free($1);
if ($$ == NULL)
{
if (keynote_errno)
return -1;
$$ = strdup("");
}
else
$$ = strdup($$);
if ($$ == NULL)
{
keynote_errno = ERROR_MEMORY;
return -1;
}
if (keynote_lex_add($$, LEXTYPE_CHAR) == -1)
return -1;
}
}
| DEREF str { if (keynote_exceptionflag || keynote_donteval)
$$ = NULL;
else
{
$$ = my_lookup($2);
keynote_lex_remove($2);
free($2);
if ($$ == NULL)
{
if (keynote_errno)
return -1;
$$ = strdup("");
}
else
$$ = strdup($$);
if ($$ == NULL)
{
keynote_errno = ERROR_MEMORY;
return -1;
}
if (keynote_lex_add($$, LEXTYPE_CHAR) == -1)
return -1;
}
}
%%
/*
* Find all assertions signed by s and give us the one with the highest
* return value.
*/
static int
resolve_assertion(char *s)
{
int i, alg = KEYNOTE_ALGORITHM_NONE, p = 0;
void *key = (void *) s;
struct assertion *as;
struct keylist *kl;
kl = keynote_keylist_find(keynote_current_assertion->as_keylist, s);
if (kl != NULL)
{
alg = kl->key_alg;
key = kl->key_key;
}
for (i = 0;; i++)
{
as = keynote_find_assertion(key, i, alg);
if (as == NULL) /* Gone through all of them */
return p;
if (as->as_kresult == KRESULT_DONE)
if (p < as->as_result)
p = as->as_result;
/* Short circuit if we find an assertion with maximum return value */
if (p == (keynote_current_session->ks_values_num - 1))
return p;
}
return 0;
}
/*
* Environment variable lookup.
*/
static char *
my_lookup(char *s)
{
struct keynote_session *ks = keynote_current_session;
char *ret;
if (!strcmp(s, "_MIN_TRUST"))
{
keynote_used_variable = 1;
return ks->ks_values[0];
}
else
{
if (!strcmp(s, "_MAX_TRUST"))
{
keynote_used_variable = 1;
return ks->ks_values[ks->ks_values_num - 1];
}
else
{
if (!strcmp(s, "_VALUES"))
{
keynote_used_variable = 1;
return keynote_env_lookup("_VALUES", ks->ks_env_table,
HASHTABLESIZE);
}
else
{
if (!strcmp(s, "_ACTION_AUTHORIZERS"))
{
keynote_used_variable = 1;
return keynote_env_lookup("_ACTION_AUTHORIZERS",
ks->ks_env_table, HASHTABLESIZE);
}
}
}
}
/* Temporary list (regexp results) */
if (keynote_temp_list != NULL)
{
ret = keynote_env_lookup(s, &keynote_temp_list, 1);
if (ret != NULL)
return ret;
else
if (keynote_errno != 0)
return NULL;
}
/* Local-Constants */
if (keynote_init_list != NULL)
{
ret = keynote_env_lookup(s, &keynote_init_list, 1);
if (ret != NULL)
return ret;
else
if (keynote_errno != 0)
return NULL;
}
if (ks != NULL)
{
/* Action environment */
ret = keynote_env_lookup(s, ks->ks_env_table, HASHTABLESIZE);
if (ret != NULL)
{
keynote_used_variable = 1;
return ret;
}
else
if (keynote_errno != 0)
return NULL;
}
/* Regex table */
if ((ks != NULL) && (ks->ks_env_regex != NULL))
{
ret = keynote_env_lookup(s, &(ks->ks_env_regex), 1);
if (ret != NULL)
{
keynote_used_variable = 1;
return ret;
}
return NULL;
}
return NULL;
}
/*
* If we had an exception, the boolean expression should return false.
* Otherwise, return the result of the expression (the argument).
*/
static int
checkexception(int i)
{
if (keynote_exceptionflag)
{
keynote_exceptionflag = 0;
return 0;
}
else
return i;
}
/*
* Integer exponentiation -- copied from Schneier's AC2, page 244.
*/
static int
intpow(int x, int y)
{
int s = 1;
/*
* x^y with y < 0 is equivalent to 1/(x^y), which for
* integer arithmetic is 0.
*/
if (y < 0)
return 0;
while (y)
{
if (y & 1)
s *= x;
y >>= 1;
x *= x;
}
return s;
}
/*
* Check whether the string is a floating point number.
*/
static int
isfloatstring(char *s)
{
int i, point = 0;
for (i = strlen(s) - 1; i >= 0; i--)
if (!isdigit((unsigned char)s[i]))
{
if (s[i] == '.')
{
if (point == 1)
return 0;
else
point = 1;
}
else
return 0;
}
return 1;
}
/*
* Initialize array for threshold search.
*/
static int
keynote_init_kth(void)
{
int i = keynote_current_session->ks_values_num;
if (i == -1)
return -1;
keynote_kth_array = calloc(i, sizeof(int));
if (keynote_kth_array == NULL)
{
keynote_errno = ERROR_MEMORY;
return -1;
}
return RESULT_TRUE;
}
/*
* Get the k-th best return value.
*/
static int
get_kth(int k)
{
int i;
for (i = keynote_current_session->ks_values_num - 1; i >= 0; i--)
{
k -= keynote_kth_array[i];
if (k <= 0)
return i;
}
return 0;
}
/*
* Cleanup array.
*/
void
keynote_cleanup_kth(void)
{
if (keynote_kth_array != NULL)
{
free(keynote_kth_array);
keynote_kth_array = NULL;
}
}
void
knerror(char *s)
{}