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