1 /* $OpenBSD: parse.y,v 1.10 2015/07/24 06:36:42 zhuk Exp $ */
3 * Copyright (c) 2015 Ted Unangst <tedu@openbsd.org>
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 #include <sys/types.h>
50 #define YYSTYPE yystype
56 static size_t maxrules;
60 static void yyerror(const char *, ...);
61 static int yylex(void);
64 arraylen(const char **arr)
77 %token TPERMIT TDENY TAS TCMD TARGS
78 %token TNOPASS TNOLOG TPERSIST TKEEPENV TSETENV TINSULT
89 rule: action ident target cmd {
91 r = calloc(1, sizeof(*r));
93 errx(1, "can't allocate rule");
94 r->action = $1.action;
95 r->options = $1.options;
96 r->envlist = $1.envlist;
100 r->cmdargs = $4.cmdargs;
101 if (nrules == maxrules) {
104 rules = reallocarray(rules, maxrules,
107 errx(1, "can't allocate rules");
113 action: TPERMIT options {
115 $$.options = $2.options;
116 $$.envlist = $2.envlist;
123 options: /* none */ {
127 $$.options = $1.options | $2.options;
128 $$.envlist = $1.envlist;
129 if (($$.options & (NOPASS|PERSIST)) == (NOPASS|PERSIST)) {
130 yyerror("can't combine nopass and persist");
135 yyerror("can't have two setenv sections");
138 $$.envlist = $2.envlist;
148 $$.options = PERSIST;
151 $$.options = KEEPENV;
156 } | TSETENV '{' strlist '}' {
158 $$.envlist = $3.strlist;
161 strlist: /* empty */ {
162 if (!($$.strlist = calloc(1, sizeof(char *))))
163 errx(1, "can't allocate strlist");
164 } | strlist TSTRING {
165 int nstr = arraylen($1.strlist);
166 if (!($$.strlist = reallocarray($1.strlist, nstr + 2,
168 errx(1, "can't allocate strlist");
169 $$.strlist[nstr] = $2.str;
170 $$.strlist[nstr + 1] = NULL;
178 target: /* optional */ {
184 cmd: /* optional */ {
187 } | TCMD TSTRING args {
189 $$.cmdargs = $3.cmdargs;
195 $$.cmdargs = $2.strlist;
201 yyerror(const char *fmt, ...)
205 fprintf(stderr, "doas: ");
207 vfprintf(stderr, fmt, va);
209 fprintf(stderr, " at line %d\n", yylval.lineno + 1);
213 static struct keyword {
218 { "permit", TPERMIT },
222 { "nopass", TNOPASS },
224 { "persist", TPERSIST },
225 { "keepenv", TKEEPENV },
226 { "setenv", TSETENV },
227 { "insult", TINSULT },
233 char buf[1024], *ebuf, *p, *str;
234 int c, quotes = 0, escape = 0, qpos = -1, nonkw = 0;
238 ebuf = buf + sizeof(buf);
241 /* skip whitespace first */
242 for (c = getc(yyfp); c == ' ' || c == '\t'; c = getc(yyfp))
245 /* check for special one-character constructions */
255 /* skip comments; NUL is allowed; no continuation */
256 while ((c = getc(yyfp)) != '\n')
266 /* parsing next word */
267 for (;; c = getc(yyfp), yylval.colno++) {
270 yyerror("unallowed character NUL in column %d",
281 yyerror("unterminated quotes in column %d",
293 yyerror("unterminated escape in column %d",
296 yyerror("unterminated quotes in column %d",
305 if (!escape && !quotes)
320 yyerror("too long line");
332 * There could be a number of reasons for empty buffer,
333 * and we handle all of them here, to avoid cluttering
338 else if (qpos == -1) /* accept, e.g., empty args: cmd foo args "" */
342 for (i = 0; i < sizeof(keywords) / sizeof(keywords[0]); i++) {
343 if (strcmp(buf, keywords[i].word) == 0)
344 return keywords[i].token;
347 if ((str = strdup(buf)) == NULL)
348 err(1, "%s", __func__);
354 yyerror("input error reading config");