X-Git-Url: https://git.armaanb.net/?a=blobdiff_plain;f=parse.y;h=f4309a3d0db0b61b95542b6e2dd03e4c20e787d3;hb=b82ffa68a6436ce3f4c4b480bc9c12ac284b0d99;hp=bd7d7e61713008fa0b8ad604aeb2b02fbb2ebf72;hpb=2b0167bb7af792320ca8c2655297598891004633;p=opendoas.git diff --git a/parse.y b/parse.y index bd7d7e6..f4309a3 100644 --- a/parse.y +++ b/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.8 2015/07/21 16:12:04 tedu Exp $ */ +/* $OpenBSD: parse.y,v 1.10 2015/07/24 06:36:42 zhuk Exp $ */ /* * Copyright (c) 2015 Ted Unangst * @@ -16,14 +16,19 @@ */ %{ +#include "config.h" + #include #include -#include -#include +#include #include #include +#include +#include #include -#include +#include + +#include "openbsd.h" #include "doas.h" @@ -36,24 +41,41 @@ typedef struct { const char **cmdargs; const char **envlist; }; + const char **strlist; const char *str; }; + int lineno; + int colno; } yystype; #define YYSTYPE yystype FILE *yyfp; struct rule **rules; -int nrules, maxrules; +int nrules; +static int maxrules; + +int parse_errors = 0; -void yyerror(const char *, ...); -int yylex(void); -int yyparse(void); +static void yyerror(const char *, ...); +static int yylex(void); + +static size_t +arraylen(const char **arr) +{ + size_t cnt = 0; + + while (*arr) { + cnt++; + arr++; + } + return cnt; +} %} %token TPERMIT TDENY TAS TCMD TARGS -%token TNOPASS TKEEPENV +%token TNOPASS TNOLOG TPERSIST TKEEPENV TSETENV %token TSTRING %% @@ -61,6 +83,7 @@ int yyparse(void); grammar: /* empty */ | grammar '\n' | grammar rule '\n' + | error '\n' ; rule: action ident target cmd { @@ -93,39 +116,56 @@ action: TPERMIT options { $$.envlist = $2.envlist; } | TDENY { $$.action = DENY; + $$.options = 0; + $$.envlist = NULL; } ; -options: /* none */ - | options option { +options: /* none */ { + $$.options = 0; + $$.envlist = NULL; + } | options option { $$.options = $1.options | $2.options; $$.envlist = $1.envlist; + if (($$.options & (NOPASS|PERSIST)) == (NOPASS|PERSIST)) { + yyerror("can't combine nopass and persist"); + YYERROR; + } if ($2.envlist) { - if ($$.envlist) - errx(1, "can't have two keepenv sections"); - else + if ($$.envlist) { + yyerror("can't have two setenv sections"); + YYERROR; + } else $$.envlist = $2.envlist; } } ; option: TNOPASS { $$.options = NOPASS; + $$.envlist = NULL; + } | TNOLOG { + $$.options = NOLOG; + $$.envlist = NULL; + } | TPERSIST { + $$.options = PERSIST; + $$.envlist = NULL; } | TKEEPENV { $$.options = KEEPENV; - } | TKEEPENV '{' envlist '}' { - $$.options = KEEPENV; - $$.envlist = $3.envlist; + $$.envlist = NULL; + } | TSETENV '{' strlist '}' { + $$.options = 0; + $$.envlist = $3.strlist; } ; -envlist: /* empty */ { - if (!($$.envlist = calloc(1, sizeof(char *)))) - errx(1, "can't allocate envlist"); - } | envlist TSTRING { - int nenv = arraylen($1.envlist); - if (!($$.envlist = reallocarray($1.envlist, nenv + 2, +strlist: /* empty */ { + if (!($$.strlist = calloc(1, sizeof(char *)))) + errx(1, "can't allocate strlist"); + } | strlist TSTRING { + int nstr = arraylen($1.strlist); + if (!($$.strlist = reallocarray($1.strlist, nstr + 2, sizeof(char *)))) - errx(1, "can't allocate envlist"); - $$.envlist[nenv] = $2.str; - $$.envlist[nenv + 1] = NULL; - } + errx(1, "can't allocate strlist"); + $$.strlist[nstr] = $2.str; + $$.strlist[nstr + 1] = NULL; + } ; ident: TSTRING { @@ -148,19 +188,8 @@ cmd: /* optional */ { args: /* empty */ { $$.cmdargs = NULL; - } | TARGS argslist { - $$.cmdargs = $2.cmdargs; - } ; - -argslist: /* empty */ { - if (!($$.cmdargs = calloc(1, sizeof(char *)))) - errx(1, "can't allocate args"); - } | argslist TSTRING { - int nargs = arraylen($1.cmdargs); - if (!($$.cmdargs = reallocarray($1.cmdargs, nargs + 2, sizeof(char *)))) - errx(1, "can't allocate args"); - $$.cmdargs[nargs] = $2.str; - $$.cmdargs[nargs + 1] = NULL; + } | TARGS strlist { + $$.cmdargs = $2.strlist; } ; %% @@ -170,11 +199,15 @@ yyerror(const char *fmt, ...) { va_list va; + fprintf(stderr, "doas: "); va_start(va, fmt); - verrx(1, fmt, va); + vfprintf(stderr, fmt, va); + va_end(va); + fprintf(stderr, " at line %d\n", yylval.lineno + 1); + parse_errors++; } -struct keyword { +static struct keyword { const char *word; int token; } keywords[] = { @@ -184,16 +217,17 @@ struct keyword { { "cmd", TCMD }, { "args", TARGS }, { "nopass", TNOPASS }, + { "nolog", TNOLOG }, + { "persist", TPERSIST }, { "keepenv", TKEEPENV }, + { "setenv", TSETENV }, }; int yylex(void) { - static int colno = 1, lineno = 1; - char buf[1024], *ebuf, *p, *str; - int i, c, quotes = 0, escape = 0, qpos = 0, nonkw = 0; + int c, quotes = 0, escape = 0, qpos = -1, nonkw = 0; p = buf; ebuf = buf + sizeof(buf); @@ -201,13 +235,13 @@ yylex(void) repeat: /* skip whitespace first */ for (c = getc(yyfp); c == ' ' || c == '\t'; c = getc(yyfp)) - colno++; + yylval.colno++; /* check for special one-character constructions */ switch (c) { case '\n': - colno = 1; - lineno++; + yylval.colno = 0; + yylval.lineno++; /* FALLTHROUGH */ case '{': case '}': @@ -217,19 +251,19 @@ repeat: while ((c = getc(yyfp)) != '\n') if (c == EOF) return 0; - colno = 1; - lineno++; + yylval.colno = 0; + yylval.lineno++; return c; case EOF: return 0; } /* parsing next word */ - for (;; c = getc(yyfp), colno++) { + for (;; c = getc(yyfp), yylval.colno++) { switch (c) { case '\0': - yyerror("unallowed character NUL at " - "line %d, column %d", lineno, colno); + yyerror("unallowed character NUL in column %d", + yylval.colno + 1); escape = 0; continue; case '\\': @@ -239,8 +273,8 @@ repeat: break; case '\n': if (quotes) - yyerror("unterminated quotes at line %d, column %d", - lineno, qpos); + yyerror("unterminated quotes in column %d", + qpos + 1); if (escape) { nonkw = 1; escape = 0; @@ -249,11 +283,12 @@ repeat: goto eow; case EOF: if (escape) - yyerror("unterminated escape at line %d, column %d", - lineno, colno - 1); + yyerror("unterminated escape in column %d", + yylval.colno); if (quotes) - yyerror("unterminated quotes at line %d, column %d", - lineno, qpos); + yyerror("unterminated quotes in column %d", + qpos + 1); + goto eow; /* FALLTHROUGH */ case '{': case '}': @@ -268,14 +303,14 @@ repeat: quotes = !quotes; if (quotes) { nonkw = 1; - qpos = colno; + qpos = yylval.colno; } continue; } } *p++ = c; if (p == ebuf) - yyerror("too long line %d", lineno); + yyerror("too long line"); escape = 0; } @@ -285,22 +320,24 @@ eow: ungetc(c, yyfp); if (p == buf) { /* - * There could be a number of reasons for empty buffer, and we handle - * all of them here, to avoid cluttering the main loop. + * There could be a number of reasons for empty buffer, + * and we handle all of them here, to avoid cluttering + * the main loop. */ if (c == EOF) return 0; - else if (!qpos) /* accept, e.g., empty args: cmd foo args "" */ + else if (qpos == -1) /* accept, e.g., empty args: cmd foo args "" */ goto repeat; } if (!nonkw) { + size_t i; for (i = 0; i < sizeof(keywords) / sizeof(keywords[0]); i++) { if (strcmp(buf, keywords[i].word) == 0) return keywords[i].token; } } if ((str = strdup(buf)) == NULL) - err(1, "strdup"); + err(1, "%s", __func__); yylval.str = str; return TSTRING; }