Expunge revision histories in files.
[become] / src / parser.y
... / ...
CommitLineData
1/* -*-c-*-
2 *
3 * $Id: parser.y,v 1.9 2004/04/08 01:36:20 mdw Exp $
4 *
5 * Parser for `become.conf' files
6 *
7 * (c) 1998 EBI
8 */
9
10/*----- Licensing notice --------------------------------------------------*
11 *
12 * This file is part of `become'
13 *
14 * `Become' is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * `Become' is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with `become'; if not, write to the Free Software Foundation,
26 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 */
28
29/*----- Header files ------------------------------------------------------*/
30%{
31
32/* --- ANSI headers --- */
33
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37
38/* --- Unix headers --- */
39
40#include <sys/types.h>
41#include <sys/socket.h>
42
43#include <netinet/in.h>
44
45#include <arpa/inet.h>
46
47#include <netdb.h>
48#include <pwd.h>
49#include <unistd.h>
50
51/* --- mLib headers --- */
52
53#include <mLib/report.h>
54#include <mLib/sym.h>
55
56/* --- Local headers --- */
57
58#include "class.h"
59#include "daemon.h"
60#include "lexer.h"
61#include "name.h"
62#include "rule.h"
63#include "userdb.h"
64
65%}
66/*----- Stack type --------------------------------------------------------*/
67
68%union {
69 long i;
70 char *s;
71 name *n;
72 class_node *c;
73}
74
75/*----- Token and rule declarations ---------------------------------------*/
76
77/* --- Tokens --- */
78
79%token BADTOKEN
80%token USER
81%token COMMAND
82%token HOST
83%token ALLOW
84%token PORT
85%token KEYFILE
86%token <i> INT
87%token <s> WORD
88%token <s> STRING
89%token ARROW
90
91%left ','
92%left '-'
93%left '|'
94%left '&'
95
96/* --- Rules --- */
97
98%type <c> user_class command_class host_class
99%type <c> user_class_opt command_class_opt host_class_opt
100%type <n> name
101
102/*----- Error reporting ---------------------------------------------------*/
103%{
104
105#define YYDEBUG 1
106#define YYERROR_VERBOSE
107
108/* --- @yyprint@ --- *
109 *
110 * Arguments: @FILE *fp@ = pointer to stream to write on
111 * @int type@ = pointer to token type
112 * @YYSTYPE v@ = token value
113 *
114 * Returns: ---
115 *
116 * Use: Displays the semantic value of a token.
117 */
118
119#define YYPRINT(fp, type, value) yyprint(fp, type, value)
120
121static void yyprint(FILE *fp, int type, YYSTYPE v)
122{
123 switch (type) {
124 case INT:
125 fprintf(fp, " %li", v.i);
126 break;
127 case WORD:
128 case STRING:
129 fprintf(fp, " `%s'", v.s);
130 break;
131 }
132}
133
134/* --- @yyerror@ --- *
135 *
136 * Arguments: @const char *msg@ = pointer to error message
137 *
138 * Returns: ---
139 *
140 * Use: Reports parse errors.
141 */
142
143static void yyerror(const char *msg)
144{
145 moan("%s at line %i", msg, lex_line);
146}
147
148%}
149%%
150/*----- The actual grammar ------------------------------------------------*/
151
152/* --- Simple driver things --- */
153
154file : /* empty */
155 | file statement
156 ;
157
158statement : user_spec
159 | command_spec
160 | host_spec
161 | allow_spec
162 | port_spec
163 | key_spec
164 | error ';'
165 ;
166
167/* --- Main statement types --- */
168
169user_spec : USER name '=' user_class ';' {
170 if ($2->c)
171 class_dec($2->c);
172 $2->c = $4;
173 }
174 ;
175
176command_spec : COMMAND name '=' command_class ';' {
177 if ($2->c)
178 class_dec($2->c);
179 $2->c = $4;
180 }
181 ;
182
183host_spec : HOST name '=' host_class ';' {
184 if ($2->c)
185 class_dec($2->c);
186 $2->c = $4;
187 }
188 ;
189
190port_spec : PORT STRING ';' {
191#ifndef NONETWORK
192 struct servent *s = getservbyname($2, "udp");
193 if (!s) {
194 moan("unknown service `%s' at line %i",
195 $2, lex_line);
196 yynerrs++; YYERROR;
197 }
198 daemon_usePort(s->s_port);
199#else
200 yyerror("`port' command unsupported");
201 yynerrs++; YYERROR;
202#endif
203 }
204 | PORT INT ';' {
205#ifndef NONETWORK
206 daemon_usePort(htons($2));
207#else
208 yyerror("`port' command unsupported");
209 yynerrs++; YYERROR;
210#endif
211 }
212 ;
213
214key_spec : KEYFILE STRING ';' {
215#ifndef NONETWORK
216 daemon_readKey($2);
217#else
218 yyerror("`keyfile' command unsupported");
219 yynerrs++; YYERROR;
220#endif
221 }
222 ;
223
224/* --- Parsing allow specifications --- */
225
226allow_spec : ALLOW host_class_opt user_class ARROW
227 user_class_opt command_class_opt ';' {
228 rule_add($2, $3, $5, $6);
229 }
230 ;
231
232host_class_opt : /* empty */ { $$ = class_all; }
233 | '[' host_class ']' { $$ = $2; }
234 ;
235
236user_class_opt : /* empty */ { $$ = class_all; }
237 | user_class { $$ = $1; }
238 ;
239
240command_class_opt : /* empty */ { $$ = class_all; }
241 | ':' command_class { $$ = $2; }
242 ;
243
244/* --- Names get translated into symbols quickly --- */
245
246name : WORD {
247 unsigned f;
248 name *n = name_find($1, 1, &f);
249 if (!f)
250 n->c = 0;
251 $$ = n;
252 }
253 ;
254
255/*----- Various class expression types ------------------------------------*
256 *
257 * Unfortunately, all these need to handle token types slightly differently
258 * and I can't be bothered to remember the current state.
259 */
260
261/* --- User class expressions --- */
262
263user_class : user_class ',' user_class {
264 if (($$ = class_union($1, $3)) == 0) {
265 yyerror("type mismatch");
266 yynerrs++; YYERROR;
267 }
268 }
269 | user_class '-' user_class {
270 if (($$ = class_diff($1, $3)) == 0) {
271 yyerror("type mismatch");
272 yynerrs++; YYERROR;
273 }
274 }
275 | user_class '&' user_class {
276 if (($$ = class_isect($1, $3)) == 0) {
277 yyerror("type mismatch");
278 yynerrs++; YYERROR;
279 }
280 }
281 | user_class '|' user_class {
282 if (($$ = class_union($1, $3)) == 0) {
283 yyerror("type mismatch");
284 yynerrs++; YYERROR;
285 }
286 }
287 | INT { $$ = class_fromUser(clType_user, $1); }
288 | STRING {
289 struct passwd *pw;
290 if ((pw = userdb_userByName($1)) == 0) {
291 moan("user `%s' not known at line %i",
292 $1, lex_line);
293 yynerrs++; YYERROR;
294 } else
295 $$ = class_fromUser(clType_user, pw->pw_uid);
296 }
297 | WORD {
298 name *n = name_find($1, 0, 0);
299 if (!n || !n->c) {
300 moan("class `%s' not found at line %i",
301 $1, lex_line);
302 yynerrs++; YYERROR;
303 } else if (~n->c->type & clType_user) {
304 yynerrs++; yyerror("type mismatch");
305 yynerrs++; YYERROR;
306 } else {
307 $$ = n->c;
308 class_inc(n->c);
309 }
310 }
311 | '(' user_class ')' { $$ = $2; }
312 ;
313
314/* --- Command class expressions --- */
315
316command_class : command_class ',' command_class {
317 if (($$ = class_union($1, $3)) == 0) {
318 yyerror("type mismatch");
319 yynerrs++; YYERROR;
320 }
321 }
322 | command_class '-' command_class {
323 if (($$ = class_diff($1, $3)) == 0) {
324 yyerror("type mismatch");
325 yynerrs++; YYERROR;
326 }
327 }
328 | command_class '&' command_class {
329 if (($$ = class_isect($1, $3)) == 0) {
330 yyerror("type mismatch");
331 yynerrs++; YYERROR;
332 }
333 }
334 | command_class '|' command_class {
335 if (($$ = class_union($1, $3)) == 0) {
336 yyerror("type mismatch");
337 yynerrs++; YYERROR;
338 }
339 }
340 | STRING { $$ = class_fromString(clType_command, $1); }
341 | WORD {
342 name *n = name_find($1, 0, 0);
343 if (!n || !n->c) {
344 moan("class `%s' not found at line %i",
345 $1, lex_line);
346 yynerrs++; YYERROR;
347 } else if (~n->c->type & clType_command) {
348 yyerror("type mismatch");
349 yynerrs++; YYERROR;
350 } else {
351 $$ = n->c;
352 class_inc(n->c);
353 }
354 }
355 | '(' command_class ')' { $$ = $2; }
356 ;
357
358/* --- Host class expressions --- */
359
360host_class : host_class ',' host_class {
361 if (($$ = class_union($1, $3)) == 0) {
362 yyerror("type mismatch");
363 yynerrs++; YYERROR;
364 }
365 }
366 | host_class '-' host_class {
367 if (($$ = class_diff($1, $3)) == 0) {
368 yyerror("type mismatch");
369 yynerrs++; YYERROR;
370 }
371 }
372 | host_class '&' host_class {
373 if (($$ = class_isect($1, $3)) == 0) {
374 yyerror("type mismatch");
375 yynerrs++; YYERROR;
376 }
377 }
378 | host_class '|' host_class {
379 if (($$ = class_union($1, $3)) == 0) {
380 yyerror("type mismatch");
381 yynerrs++; YYERROR;
382 }
383 }
384 | STRING { $$ = class_fromString(clType_host, $1); }
385 | WORD {
386 name *n = name_find($1, 0, 0);
387 if (!n || !n->c) {
388 moan("class `%s' not found at line %i",
389 $1, lex_line);
390 yynerrs++; YYERROR;
391 } else if (~n->c->type & clType_host) {
392 yyerror("type mismatch");
393 yynerrs++; YYERROR;
394 } else {
395 $$ = n->c;
396 class_inc(n->c);
397 }
398 }
399 | '(' host_class ')' { $$ = $2; }
400 ;
401
402/*----- Helper functions --------------------------------------------------*/
403%%
404/* --- @parse@ --- *
405 *
406 * Arguments: ---
407 *
408 * Returns: Zero if it worked, nonzero if it didn't.
409 *
410 * Use: Parses configuration files.
411 */
412
413int parse(void)
414{
415 yynerrs = 0;
416 return (yyparse() || yynerrs);
417}
418
419/*----- That's all, folks -------------------------------------------------*/