1 /* $OpenBSD: parse.y,v 1.26 2017/01/02 01:40:20 tedu 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.
19 #include <sys/types.h>
46 #define YYSTYPE yystype
56 static void yyerror(const char *, ...
);
57 static int yylex(void);
60 arraylen
(const char **arr
)
73 %token TPERMIT TDENY TAS TCMD TARGS
74 %token TNOPASS TPERSIST TKEEPENV TSETENV
85 rule: action ident target cmd
{
87 r
= calloc
(1, sizeof
(*r
));
89 errx
(1, "can't allocate rule");
90 r
->action
= $1.action
;
91 r
->options
= $1.options
;
92 r
->envlist
= $1.envlist
;
96 r
->cmdargs
= $4.cmdargs
;
97 if
(nrules
== maxrules
) {
102 if
(!(rules
= reallocarray
(rules
, maxrules
,
104 errx
(1, "can't allocate rules");
109 action: TPERMIT options
{
111 $$.options
= $2.options
;
112 $$.envlist
= $2.envlist
;
119 options: /* none */ {
123 $$.options
= $1.options |
$2.options
;
124 $$.envlist
= $1.envlist
;
125 if
(($$.options
& (NOPASS|PERSIST
)) == (NOPASS|PERSIST
)) {
126 yyerror("can't combine nopass and persist");
131 yyerror("can't have two setenv sections");
134 $$.envlist
= $2.envlist
;
141 $$.options
= PERSIST
;
144 $$.options
= KEEPENV
;
146 } | TSETENV
'{' strlist
'}' {
148 $$.envlist
= $3.strlist
;
151 strlist: /* empty */ {
152 if
(!($$.strlist
= calloc
(1, sizeof
(char *))))
153 errx
(1, "can't allocate strlist");
154 } | strlist TSTRING
{
155 int nstr
= arraylen
($1.strlist
);
156 if
(!($$.strlist
= reallocarray
($1.strlist
, nstr
+ 2,
158 errx
(1, "can't allocate strlist");
159 $$.strlist
[nstr
] = $2.str
;
160 $$.strlist
[nstr
+ 1] = NULL
;
168 target: /* optional */ {
174 cmd: /* optional */ {
177 } | TCMD TSTRING args
{
179 $$.cmdargs
= $3.cmdargs
;
185 $$.cmdargs
= $2.strlist
;
191 yyerror(const char *fmt
, ...
)
195 fprintf
(stderr
, "doas: ");
197 vfprintf
(stderr
, fmt
, va
);
199 fprintf
(stderr
, " at line %d\n", yylval.lineno
+ 1);
203 static struct keyword
{
208 { "permit", TPERMIT
},
212 { "nopass", TNOPASS
},
213 { "persist", TPERSIST
},
214 { "keepenv", TKEEPENV
},
215 { "setenv", TSETENV
},
221 char buf
[1024], *ebuf
, *p
, *str
;
222 int i
, c
, quotes
= 0, escape
= 0, qpos
= -1, nonkw
= 0;
225 ebuf
= buf
+ sizeof
(buf
);
228 /* skip whitespace first */
229 for
(c
= getc
(yyfp
); c
== ' ' || c
== '\t'; c
= getc
(yyfp
))
232 /* check for special one-character constructions */
242 /* skip comments; NUL is allowed; no continuation */
243 while
((c
= getc
(yyfp
)) != '\n')
253 /* parsing next word */
254 for
(;; c
= getc
(yyfp
), yylval.colno
++) {
257 yyerror("unallowed character NUL in column %d",
268 yyerror("unterminated quotes in column %d",
280 yyerror("unterminated escape in column %d",
283 yyerror("unterminated quotes in column %d",
292 if
(!escape
&& !quotes
)
307 yyerror("too long line");
319 * There could be a number of reasons for empty buffer,
320 * and we handle all of them here, to avoid cluttering
325 else if
(qpos
== -1) /* accept, e.g., empty args: cmd foo args "" */
329 for
(i
= 0; i
< sizeof
(keywords
) / sizeof
(keywords
[0]); i
++) {
330 if
(strcmp
(buf
, keywords
[i
].word
) == 0)
331 return keywords
[i
].token
;
334 if
((str
= strdup
(buf
)) == NULL
)
341 yyerror("input error reading config");