]> git.armaanb.net Git - opendoas.git/blob - parse.y
cases should line up with switch, from Dimitris Papastamos
[opendoas.git] / parse.y
1 /* $OpenBSD: parse.y,v 1.7 2015/07/21 11:04:06 zhuk Exp $ */
2 /*
3  * Copyright (c) 2015 Ted Unangst <tedu@openbsd.org>
4  *
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.
8  *
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.
16  */
17
18 %{
19 #include <sys/types.h>
20 #include <ctype.h>
21 #include <unistd.h>
22 #include <stdint.h>
23 #include <stdarg.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <err.h>
27
28 #include "doas.h"
29
30 typedef struct {
31         union {
32                 struct {
33                         int action;
34                         int options;
35                         const char *cmd;
36                         const char **cmdargs;
37                         const char **envlist;
38                 };
39                 const char *str;
40         };
41 } yystype;
42 #define YYSTYPE yystype
43
44 FILE *yyfp;
45
46 struct rule **rules;
47 int nrules, maxrules;
48
49 void yyerror(const char *, ...);
50 int yylex(void);
51 int yyparse(void);
52
53 %}
54
55 %token TPERMIT TDENY TAS TCMD TARGS
56 %token TNOPASS TKEEPENV
57 %token TSTRING
58
59 %%
60
61 grammar:        /* empty */
62                 | grammar '\n'
63                 | grammar rule '\n'
64                 ;
65
66 rule:           action ident target cmd {
67                         struct rule *r;
68                         r = calloc(1, sizeof(*r));
69                         if (!r)
70                                 errx(1, "can't allocate rule");
71                         r->action = $1.action;
72                         r->options = $1.options;
73                         r->envlist = $1.envlist;
74                         r->ident = $2.str;
75                         r->target = $3.str;
76                         r->cmd = $4.cmd;
77                         r->cmdargs = $4.cmdargs;
78                         if (nrules == maxrules) {
79                                 if (maxrules == 0)
80                                         maxrules = 63;
81                                 else
82                                         maxrules *= 2;
83                                 if (!(rules = reallocarray(rules, maxrules,
84                                     sizeof(*rules))))
85                                         errx(1, "can't allocate rules");
86                         }
87                         rules[nrules++] = r;
88                 } ;
89
90 action:         TPERMIT options {
91                         $$.action = PERMIT;
92                         $$.options = $2.options;
93                         $$.envlist = $2.envlist;
94                 } | TDENY {
95                         $$.action = DENY;
96                 } ;
97
98 options:        /* none */
99                 | options option {
100                         $$.options = $1.options | $2.options;
101                         $$.envlist = $1.envlist;
102                         if ($2.envlist) {
103                                 if ($$.envlist)
104                                         errx(1, "can't have two keepenv sections");
105                                 else
106                                         $$.envlist = $2.envlist;
107                         }
108                 } ;
109 option:         TNOPASS {
110                         $$.options = NOPASS;
111                 } | TKEEPENV {
112                         $$.options = KEEPENV;
113                 } | TKEEPENV '{' envlist '}' {
114                         $$.options = KEEPENV;
115                         $$.envlist = $3.envlist;
116                 } ;
117
118 envlist:        /* empty */ {
119                         if (!($$.envlist = calloc(1, sizeof(char *))))
120                                 errx(1, "can't allocate envlist");
121                 } | envlist TSTRING {
122                         int nenv = arraylen($1.envlist);
123                         if (!($$.envlist = reallocarray($1.envlist, nenv + 2,
124                             sizeof(char *))))
125                                 errx(1, "can't allocate envlist");
126                         $$.envlist[nenv] = $2.str;
127                         $$.envlist[nenv + 1] = NULL;
128                 }
129
130
131 ident:          TSTRING {
132                         $$.str = $1.str;
133                 } ;
134
135 target:         /* optional */ {
136                         $$.str = NULL;
137                 } | TAS TSTRING {
138                         $$.str = $2.str;
139                 } ;
140
141 cmd:            /* optional */ {
142                         $$.cmd = NULL;
143                         $$.cmdargs = NULL;
144                 } | TCMD TSTRING args {
145                         $$.cmd = $2.str;
146                         $$.cmdargs = $3.cmdargs;
147                 } ;
148
149 args:           /* empty */ {
150                         $$.cmdargs = NULL;
151                 } | TARGS argslist {
152                         $$.cmdargs = $2.cmdargs;
153                 } ;
154
155 argslist:       /* empty */ {
156                         if (!($$.cmdargs = calloc(1, sizeof(char *))))
157                                 errx(1, "can't allocate args");
158                 } | argslist TSTRING {
159                         int nargs = arraylen($1.cmdargs);
160                         if (!($$.cmdargs = reallocarray($1.cmdargs, nargs + 2, sizeof(char *))))
161                                 errx(1, "can't allocate args");
162                         $$.cmdargs[nargs] = $2.str;
163                         $$.cmdargs[nargs + 1] = NULL;
164                 } ;
165
166 %%
167
168 void
169 yyerror(const char *fmt, ...)
170 {
171         va_list va;
172
173         va_start(va, fmt);
174         verrx(1, fmt, va);
175 }
176
177 struct keyword {
178         const char *word;
179         int token;
180 } keywords[] = {
181         { "deny", TDENY },
182         { "permit", TPERMIT },
183         { "as", TAS },
184         { "cmd", TCMD },
185         { "args", TARGS },
186         { "nopass", TNOPASS },
187         { "keepenv", TKEEPENV },
188 };
189
190 int
191 yylex(void)
192 {
193         char buf[1024], *ebuf, *p, *str;
194         int i, c, next;
195
196         p = buf;
197         ebuf = buf + sizeof(buf);
198 repeat:
199         c = getc(yyfp);
200         switch (c) {
201         case ' ':
202         case '\t':
203                 goto repeat; /* skip spaces */
204         case '\\':
205                 next = getc(yyfp);
206                 if (next == '\n')
207                         goto repeat;
208                 else
209                         c = next;
210         case '\n':
211         case '{':
212         case '}':
213                 return c;
214         case '#':
215                 while ((c = getc(yyfp)) != '\n' && c != EOF)
216                         ; /* skip comments */
217                 if (c == EOF)
218                         return 0;
219                 return c;
220         case EOF:
221                 return 0;
222         }
223         while (1) {
224                 switch (c) {
225                 case '\n':
226                 case '{':
227                 case '}':
228                 case '#':
229                 case ' ':
230                 case '\t':
231                 case EOF:
232                         goto eow;
233                 }
234                 *p++ = c;
235                 if (p == ebuf)
236                         yyerror("too much stuff");
237                 c = getc(yyfp);
238         }
239 eow:
240         *p = 0;
241         if (c != EOF)
242                 ungetc(c, yyfp);
243         for (i = 0; i < sizeof(keywords) / sizeof(keywords[0]); i++) {
244                 if (strcmp(buf, keywords[i].word) == 0)
245                         return keywords[i].token;
246         }
247         if ((str = strdup(buf)) == NULL)
248                 err(1, "strdup");
249         yylval.str = str;
250         return TSTRING;
251 }