Annotation of src/usr.bin/doas/parse.y, Revision 1.2
1.2 ! nicm 1: /* $OpenBSD: parse.y,v 1.1 2015/07/16 20:44:21 tedu Exp $ */
1.1 tedu 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));
1.2 ! nicm 63: if (!r)
! 64: errx(1, "can't allocate rule");
1.1 tedu 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: case ':':
189: *p++ = c;
190: c = getc(yyfp);
191: break;
192: default:
193: break;
194: }
195: while (isalnum(c)) {
196: *p++ = c;
197: if (p == ebuf)
198: yyerror("too much stuff");
199: c = getc(yyfp);
200: }
201: *p = 0;
202: if (c != EOF)
203: ungetc(c, yyfp);
204: for (i = 0; i < sizeof(keywords) / sizeof(keywords[0]); i++) {
205: if (strcmp(buf, keywords[i].word) == 0)
206: return keywords[i].token;
207: }
208: if ((str = strdup(buf)) == NULL)
209: err(1, "strdup");
210: yylval.str = str;
211: return TSTRING;
212: }