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