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