]> git.armaanb.net Git - opendoas.git/blob - parse.y
wrap long lines and kill some whitespace
[opendoas.git] / parse.y
1 /* $OpenBSD: parse.y,v 1.5 2015/07/19 22:09:08 benno 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 **envlist;
36                 };
37                 const char *str;
38         };
39 } yystype;
40 #define YYSTYPE yystype
41
42 FILE *yyfp;
43
44 struct rule **rules;
45 int nrules, maxrules;
46
47 void yyerror(const char *, ...);
48 int yylex(void);
49 int yyparse(void);
50
51 %}
52
53 %token TPERMIT TDENY TAS TCMD
54 %token TNOPASS TKEEPENV
55 %token TSTRING
56
57 %%
58
59 grammar:        /* empty */
60                 | grammar '\n'
61                 | grammar rule '\n'
62                 ;
63
64 rule:           action ident target cmd {
65                         struct rule *r;
66                         r = calloc(1, sizeof(*r));
67                         if (!r)
68                                 errx(1, "can't allocate rule");
69                         r->action = $1.action;
70                         r->options = $1.options;
71                         r->envlist = $1.envlist;
72                         r->ident = $2.str;
73                         r->target = $3.str;
74                         r->cmd = $4.str;
75                         if (nrules == maxrules) {
76                                 if (maxrules == 0)
77                                         maxrules = 63;
78                                 else
79                                         maxrules *= 2;
80                                 if (!(rules = reallocarray(rules, maxrules,
81                                     sizeof(*rules))))
82                                         errx(1, "can't allocate rules");
83                         }
84                         rules[nrules++] = r;
85                 } ;
86
87 action:         TPERMIT options {
88                         $$.action = PERMIT;
89                         $$.options = $2.options;
90                         $$.envlist = $2.envlist;
91                 } | TDENY {
92                         $$.action = DENY;
93                 } ;
94
95 options:        /* none */
96                 | options option {
97                         $$.options = $1.options | $2.options;
98                         $$.envlist = $1.envlist;
99                         if ($2.envlist) {
100                                 if ($$.envlist)
101                                         errx(1, "can't have two keepenv sections");
102                                 else
103                                         $$.envlist = $2.envlist;
104                         }
105                 } ;
106 option:         TNOPASS {
107                         $$.options = NOPASS;
108                 } | TKEEPENV {
109                         $$.options = KEEPENV;
110                 } | TKEEPENV '{' envlist '}' {
111                         $$.options = KEEPENV;
112                         $$.envlist = $3.envlist;
113                 } ;
114
115 envlist:        /* empty */ {
116                         if (!($$.envlist = calloc(1, sizeof(char *))))
117                                 errx(1, "can't allocate envlist");
118                 } | envlist TSTRING {
119                         int nenv = arraylen($1.envlist);
120                         if (!($$.envlist = reallocarray($1.envlist, nenv + 2,
121                             sizeof(char *))))
122                                 errx(1, "can't allocate envlist");
123                         $$.envlist[nenv] = $2.str;
124                         $$.envlist[nenv + 1] = NULL;
125                 }
126
127
128 ident:          TSTRING {
129                         $$.str = $1.str;
130                 } ;
131
132 target:         /* optional */ {
133                         $$.str = NULL;
134                 } | TAS TSTRING {
135                         $$.str = $2.str;
136                 } ;
137
138 cmd:            /* optional */ {
139                         $$.str = NULL;
140                 } | TCMD TSTRING {
141                         $$.str = $2.str;
142                 } ;
143
144 %%
145
146 void
147 yyerror(const char *fmt, ...)
148 {
149         va_list va;
150
151         va_start(va, fmt);
152         verrx(1, fmt, va);
153 }
154
155 struct keyword {
156         const char *word;
157         int token;
158 } keywords[] = {
159         { "deny", TDENY },
160         { "permit", TPERMIT },
161         { "as", TAS },
162         { "cmd", TCMD },
163         { "nopass", TNOPASS },
164         { "keepenv", TKEEPENV },
165 };
166
167 int
168 yylex(void)
169 {
170         char buf[1024], *ebuf, *p, *str;
171         int i, c, next;
172
173         p = buf;
174         ebuf = buf + sizeof(buf);
175 repeat:
176         c = getc(yyfp);
177         switch (c) {
178                 case ' ':
179                 case '\t':
180                         goto repeat; /* skip spaces */
181                 case '\\':
182                         next = getc(yyfp);
183                         if (next == '\n')
184                                 goto repeat;
185                         else
186                                 c = next;
187                 case '\n':
188                 case '{':
189                 case '}':
190                         return c;
191                 case '#':
192                         while ((c = getc(yyfp)) != '\n' && c != EOF)
193                                 ; /* skip comments */
194                         if (c == EOF)
195                                 return 0;
196                         return c;
197                 case EOF:
198                         return 0;
199         }
200         while (1) {
201                 switch (c) {
202                 case '\n':
203                 case '{':
204                 case '}':
205                 case '#':
206                 case ' ':
207                 case '\t':
208                 case EOF:
209                         goto eow;
210                 }
211                 *p++ = c;
212                 if (p == ebuf)
213                         yyerror("too much stuff");
214                 c = getc(yyfp);
215         }
216 eow:
217         *p = 0;
218         if (c != EOF)
219                 ungetc(c, yyfp);
220         for (i = 0; i < sizeof(keywords) / sizeof(keywords[0]); i++) {
221                 if (strcmp(buf, keywords[i].word) == 0)
222                         return keywords[i].token;
223         }
224         if ((str = strdup(buf)) == NULL)
225                 err(1, "strdup");
226         yylval.str = str;
227         return TSTRING;
228 }