Initial revision
[become] / src / parser.y
1 /* -*-c-*-
2 *
3 * $Id: parser.y,v 1.1 1997/07/21 13:47:45 mdw Exp $
4 *
5 * Parser for `become.conf' files
6 *
7 * (c) 1997 EBI
8 */
9
10 /*----- Licencing 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
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 */
28
29 /*----- Revision history --------------------------------------------------*
30 *
31 * $Log: parser.y,v $
32 * Revision 1.1 1997/07/21 13:47:45 mdw
33 * Initial revision
34 *
35 */
36
37 /*----- Header files ------------------------------------------------------*/
38 %{
39
40 /* --- ANSI headers --- */
41
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45
46 /* --- Unix headers --- */
47
48 #include <sys/types.h>
49
50 #include <pwd.h>
51 #include <unistd.h>
52
53 /* --- Local headers --- */
54
55 #include "class.h"
56 #include "daemon.h"
57 #include "lexer.h"
58 #include "name.h"
59 #include "rule.h"
60 #include "set.h"
61 #include "sym.h"
62 #include "userdb.h"
63 #include "utils.h"
64
65 %}
66 /*----- Stack type --------------------------------------------------------*/
67
68 %union {
69 long i;
70 char *s;
71 name *n;
72 classdef *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
121 static 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
143 static 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
154 file : /* empty */
155 | file statement
156 ;
157
158 statement : 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
169 user_spec : USER name '=' user_class ';' {
170 if ($2->c)
171 class_dec($2->c);
172 $2->c = $4;
173 }
174 ;
175
176 command_spec : COMMAND name '=' command_class ';' {
177 if ($2->c)
178 class_dec($2->c);
179 $2->c = $4;
180 }
181 ;
182
183 host_spec : HOST name '=' host_class ';' {
184 if ($2->c)
185 class_dec($2->c);
186 $2->c = $4;
187 }
188 ;
189
190 port_spec : PORT INT ';' { daemon_usePort($2); }
191 ;
192
193 key_spec : KEYFILE STRING ';' { daemon_readKey($2); }
194
195 /* --- Parsing allow specifications --- */
196
197 allow_spec : ALLOW host_class_opt user_class ARROW
198 user_class_opt command_class_opt ';' {
199 rule_add($2, $3, $5, $6);
200 }
201
202 host_class_opt : /* empty */ { $$ = class_all; }
203 | '[' host_class ']' { $$ = $2; }
204 ;
205
206 user_class_opt : /* empty */ { $$ = class_all; }
207 | user_class { $$ = $1; }
208 ;
209
210 command_class_opt : /* empty */ { $$ = class_all; }
211 | ':' command_class { $$ = $2; }
212 ;
213
214 /* --- Names get translated into symbols quickly --- */
215
216 name : WORD {
217 unsigned f;
218 name *n = name_find($1, 1, &f);
219 if (!f)
220 n->c = 0;
221 $$ = n;
222 }
223
224 /*----- Various class expression types ------------------------------------*
225 *
226 * Unfortunately, all these need to handle token types slightly differently
227 * and I can't be bothered to remember the current state.
228 */
229
230 /* --- User class expressions --- */
231
232 user_class : user_class ',' user_class {
233 if ($1->type != $3->type) {
234 yyerror("type mismatch");
235 class_dec($1);
236 class_dec($3);
237 YYERROR;
238 } else {
239 if ($1 == class_all)
240 $$ = class_all;
241 else
242 $$ = class_create($1->type,
243 set_union($1->t, $3->t));
244 class_dec($1);
245 class_dec($3);
246 }
247 }
248 | user_class '-' user_class {
249 if ($1->type != $3->type) {
250 yyerror("type mismatch");
251 class_dec($1);
252 class_dec($3);
253 YYERROR;
254 } else {
255 $$ = class_create($1->type,
256 set_subtract($1->t, $3->t));
257 class_dec($1);
258 class_dec($3);
259 }
260 }
261 | user_class '&' user_class {
262 if ($1->type != $3->type) {
263 yyerror("type mismatch");
264 class_dec($1);
265 class_dec($3);
266 YYERROR;
267 } else {
268 if ($1 == class_all)
269 $$ = class_all;
270 else
271 $$ = class_create($1->type,
272 set_intersect($1->t, $3->t));
273 class_dec($1);
274 class_dec($3);
275 }
276 }
277 | user_class '|' user_class {
278 if ($1->type != $3->type) {
279 yyerror("type mismatch");
280 class_dec($1);
281 class_dec($3);
282 YYERROR;
283 } else {
284 if ($1 == class_all)
285 $$ = class_all;
286 else
287 $$ = class_create($1->type,
288 set_union($1->t, $3->t));
289 class_dec($1);
290 class_dec($3);
291 }
292 }
293 | INT {
294 sym_table *t = xmalloc(sizeof(*t));
295 int u = $1;
296 sym_createTable(t);
297 sym_find(t, (char *)&u, sizeof(u),
298 sizeof(sym_base), 0);
299 $$ = class_create(clType_user, t);
300 }
301 | STRING {
302 struct passwd *pw;
303 sym_table *t;
304 int u;
305 if ((pw = userdb_userByName($1)) == 0) {
306 moan("user `%s' not known at line %i",
307 $1, lex_line);
308 YYERROR;
309 } else {
310 t = xmalloc(sizeof(*t));
311 u = pw->pw_uid;
312 sym_createTable(t);
313 sym_find(t, (char *)&u, sizeof(u),
314 sizeof(sym_base), 0);
315 $$ = class_create(clType_user, t);
316 }
317 }
318 | WORD {
319 name *n = name_find($1, 0, 0);
320 if (!n || !n->c) {
321 moan("class `%s' not found at line %i",
322 $1, lex_line);
323 YYERROR;
324 } else if (~n->c->type & clType_user) {
325 yyerror("type mismatch");
326 YYERROR;
327 } else {
328 $$ = n->c;
329 class_inc(n->c);
330 }
331 }
332 | '(' user_class ')' { $$ = $2; }
333 ;
334
335 /* --- Command class expressions --- */
336
337 command_class : command_class ',' command_class {
338 if ($1->type != $3->type) {
339 yyerror("type mismatch");
340 class_dec($1);
341 class_dec($3);
342 YYERROR;
343 } else {
344 if ($1 == class_all)
345 $$ = class_all;
346 else
347 $$ = class_create($1->type,
348 set_union($1->t, $3->t));
349 class_dec($1);
350 class_dec($3);
351 }
352 }
353 | command_class '-' command_class {
354 if ($1->type != $3->type) {
355 yyerror("type mismatch");
356 class_dec($1);
357 class_dec($3);
358 YYERROR;
359 } else {
360 $$ = class_create($1->type,
361 set_subtract($1->t, $3->t));
362 class_dec($1);
363 class_dec($3);
364 }
365 }
366 | command_class '&' command_class {
367 if ($1->type != $3->type) {
368 yyerror("type mismatch");
369 class_dec($1);
370 class_dec($3);
371 YYERROR;
372 } else {
373 if ($1 == class_all)
374 $$ = class_all;
375 else
376 $$ = class_create($1->type,
377 set_intersect($1->t, $3->t));
378 class_dec($1);
379 class_dec($3);
380 }
381 }
382 | command_class '|' command_class {
383 if ($1->type != $3->type) {
384 yyerror("type mismatch");
385 class_dec($1);
386 class_dec($3);
387 YYERROR;
388 } else {
389 if ($1 == class_all)
390 $$ = class_all;
391 else
392 $$ = class_create($1->type,
393 set_union($1->t, $3->t));
394 class_dec($1);
395 class_dec($3);
396 }
397 }
398 | STRING {
399 sym_table *t = xmalloc(sizeof(*t));
400 sym_createTable(t);
401 sym_find(t, $1, -1, sizeof(sym_base), 0);
402 $$ = class_create(clType_command, t);
403 }
404 | WORD {
405 name *n = name_find($1, 0, 0);
406 if (!n || !n->c) {
407 moan("class `%s' not found at line %i",
408 $1, lex_line);
409 YYERROR;
410 } else if (~n->c->type & clType_command) {
411 yyerror("type mismatch");
412 YYERROR;
413 } else {
414 $$ = n->c;
415 class_inc(n->c);
416 }
417 }
418 | '(' command_class ')' { $$ = $2; }
419 ;
420
421 /* --- Host class expressions --- */
422
423 host_class : host_class ',' host_class {
424 if ($1->type != $3->type) {
425 yyerror("type mismatch");
426 class_dec($1);
427 class_dec($3);
428 YYERROR;
429 } else {
430 if ($1 == class_all)
431 $$ = class_all;
432 else
433 $$ = class_create($1->type,
434 set_union($1->t, $3->t));
435 class_dec($1);
436 class_dec($3);
437 }
438 }
439 | host_class '-' host_class {
440 if ($1->type != $3->type) {
441 yyerror("type mismatch");
442 class_dec($1);
443 class_dec($3);
444 YYERROR;
445 } else {
446 $$ = class_create($1->type,
447 set_subtract($1->t, $3->t));
448 class_dec($1);
449 class_dec($3);
450 }
451 }
452 | host_class '&' host_class {
453 if ($1->type != $3->type) {
454 yyerror("type mismatch");
455 class_dec($1);
456 class_dec($3);
457 YYERROR;
458 } else {
459 if ($1 == class_all)
460 $$ = class_all;
461 else
462 $$ = class_create($1->type,
463 set_intersect($1->t, $3->t));
464 class_dec($1);
465 class_dec($3);
466 }
467 }
468 | host_class '|' host_class {
469 if ($1->type != $3->type) {
470 yyerror("type mismatch");
471 class_dec($1);
472 class_dec($3);
473 YYERROR;
474 } else {
475 if ($1 == class_all)
476 $$ = class_all;
477 else
478 $$ = class_create($1->type,
479 set_union($1->t, $3->t));
480 class_dec($1);
481 class_dec($3);
482 }
483 }
484 | STRING {
485 sym_table *t = xmalloc(sizeof(*t));
486 sym_createTable(t);
487 sym_find(t, $1, -1, sizeof(sym_base), 0);
488 $$ = class_create(clType_host, t);
489 }
490 | WORD {
491 name *n = name_find($1, 0, 0);
492 if (!n || !n->c) {
493 moan("class `%s' not found at line %i",
494 $1, lex_line);
495 YYERROR;
496 } else if (~n->c->type & clType_host) {
497 yyerror("type mismatch");
498 YYERROR;
499 } else {
500 $$ = n->c;
501 class_inc(n->c);
502 }
503 }
504 | '(' host_class ')' { $$ = $2; }
505 ;
506
507 /*----- That's all, folks -------------------------------------------------*/