New `parse' interface to configuration file parser; informs caller
[become] / src / parser.y
CommitLineData
c4f2d992 1/* -*-c-*-
2 *
082ddb26 3 * $Id: parser.y,v 1.6 1998/04/23 13:26:49 mdw Exp $
c4f2d992 4 *
5 * Parser for `become.conf' files
6 *
c758e654 7 * (c) 1998 EBI
c4f2d992 8 */
9
03f996bd 10/*----- Licensing notice --------------------------------------------------*
c4f2d992 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
03f996bd 25 * along with `become'; if not, write to the Free Software Foundation,
26 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
c4f2d992 27 */
28
29/*----- Revision history --------------------------------------------------*
30 *
31 * $Log: parser.y,v $
082ddb26 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 *
c758e654 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
c327f3bc 41 * Use rewritten class handler. Makes the expression parsers considerably
42 * simpler.
43 *
f3debbd8 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 *
03f996bd 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
c4f2d992 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>
f3debbd8 67#include <sys/socket.h>
68
69#include <netinet/in.h>
c4f2d992 70
f3debbd8 71#include <arpa/inet.h>
72
73#include <netdb.h>
c4f2d992 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"
c4f2d992 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;
c327f3bc 95 class_node *c;
c4f2d992 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
144static 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
166static 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
177file : /* empty */
178 | file statement
179 ;
180
181statement : 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
192user_spec : USER name '=' user_class ';' {
193 if ($2->c)
194 class_dec($2->c);
195 $2->c = $4;
196 }
197 ;
198
199command_spec : COMMAND name '=' command_class ';' {
200 if ($2->c)
201 class_dec($2->c);
202 $2->c = $4;
203 }
204 ;
205
206host_spec : HOST name '=' host_class ';' {
207 if ($2->c)
208 class_dec($2->c);
209 $2->c = $4;
210 }
211 ;
212
f3debbd8 213port_spec : PORT STRING ';' {
082ddb26 214#ifndef NONETWORK
f3debbd8 215 struct servent *s = getservbyname($2, "udp");
216 if (!s) {
217 moan("unknown service `%s' at line %i",
218 $2, lex_line);
082ddb26 219 yynerrs++; YYERROR;
f3debbd8 220 }
221 daemon_usePort(s->s_port);
082ddb26 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
f3debbd8 234 }
c4f2d992 235 ;
236
082ddb26 237key_spec : KEYFILE STRING ';' {
238#ifndef NONETWORK
239 daemon_readKey($2);
240#else
241 yyerror("`keyfile' command unsupported");
242 yynerrs++; YYERROR;
243#endif
244 }
c4f2d992 245
246/* --- Parsing allow specifications --- */
247
248allow_spec : ALLOW host_class_opt user_class ARROW
249 user_class_opt command_class_opt ';' {
250 rule_add($2, $3, $5, $6);
251 }
252
253host_class_opt : /* empty */ { $$ = class_all; }
254 | '[' host_class ']' { $$ = $2; }
255 ;
256
257user_class_opt : /* empty */ { $$ = class_all; }
258 | user_class { $$ = $1; }
259 ;
260
261command_class_opt : /* empty */ { $$ = class_all; }
262 | ':' command_class { $$ = $2; }
263 ;
264
265/* --- Names get translated into symbols quickly --- */
266
267name : 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
283user_class : user_class ',' user_class {
c327f3bc 284 if (($$ = class_union($1, $3)) == 0) {
c4f2d992 285 yyerror("type mismatch");
082ddb26 286 yynerrs++; YYERROR;
c4f2d992 287 }
288 }
289 | user_class '-' user_class {
c327f3bc 290 if (($$ = class_diff($1, $3)) == 0) {
c4f2d992 291 yyerror("type mismatch");
082ddb26 292 yynerrs++; YYERROR;
c4f2d992 293 }
294 }
295 | user_class '&' user_class {
c327f3bc 296 if (($$ = class_isect($1, $3)) == 0) {
c4f2d992 297 yyerror("type mismatch");
082ddb26 298 yynerrs++; YYERROR;
c4f2d992 299 }
300 }
301 | user_class '|' user_class {
c327f3bc 302 if (($$ = class_union($1, $3)) == 0) {
c4f2d992 303 yyerror("type mismatch");
082ddb26 304 yynerrs++; YYERROR;
c4f2d992 305 }
306 }
c327f3bc 307 | INT { $$ = class_fromUser(clType_user, $1); }
c4f2d992 308 | STRING {
309 struct passwd *pw;
c4f2d992 310 if ((pw = userdb_userByName($1)) == 0) {
311 moan("user `%s' not known at line %i",
312 $1, lex_line);
082ddb26 313 yynerrs++; YYERROR;
c327f3bc 314 } else
315 $$ = class_fromUser(clType_user, pw->pw_uid);
c4f2d992 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);
082ddb26 322 yynerrs++; YYERROR;
c4f2d992 323 } else if (~n->c->type & clType_user) {
082ddb26 324 yynerrs++; yyerror("type mismatch");
325 yynerrs++; YYERROR;
c4f2d992 326 } else {
327 $$ = n->c;
328 class_inc(n->c);
329 }
330 }
331 | '(' user_class ')' { $$ = $2; }
332 ;
333
334/* --- Command class expressions --- */
335
336command_class : command_class ',' command_class {
c327f3bc 337 if (($$ = class_union($1, $3)) == 0) {
c4f2d992 338 yyerror("type mismatch");
082ddb26 339 yynerrs++; YYERROR;
c4f2d992 340 }
341 }
342 | command_class '-' command_class {
c327f3bc 343 if (($$ = class_diff($1, $3)) == 0) {
c4f2d992 344 yyerror("type mismatch");
082ddb26 345 yynerrs++; YYERROR;
c4f2d992 346 }
347 }
348 | command_class '&' command_class {
c327f3bc 349 if (($$ = class_isect($1, $3)) == 0) {
c4f2d992 350 yyerror("type mismatch");
082ddb26 351 yynerrs++; YYERROR;
c4f2d992 352 }
353 }
354 | command_class '|' command_class {
c327f3bc 355 if (($$ = class_union($1, $3)) == 0) {
c4f2d992 356 yyerror("type mismatch");
082ddb26 357 yynerrs++; YYERROR;
c4f2d992 358 }
359 }
c327f3bc 360 | STRING { $$ = class_fromString(clType_command, $1); }
c4f2d992 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);
082ddb26 366 yynerrs++; YYERROR;
c4f2d992 367 } else if (~n->c->type & clType_command) {
368 yyerror("type mismatch");
082ddb26 369 yynerrs++; YYERROR;
c4f2d992 370 } else {
371 $$ = n->c;
372 class_inc(n->c);
373 }
374 }
375 | '(' command_class ')' { $$ = $2; }
376 ;
377
378/* --- Host class expressions --- */
379
c327f3bc 380host_class : host_class ',' host_class {
381 if (($$ = class_union($1, $3)) == 0) {
c4f2d992 382 yyerror("type mismatch");
082ddb26 383 yynerrs++; YYERROR;
c4f2d992 384 }
385 }
386 | host_class '-' host_class {
c327f3bc 387 if (($$ = class_diff($1, $3)) == 0) {
c4f2d992 388 yyerror("type mismatch");
082ddb26 389 yynerrs++; YYERROR;
c4f2d992 390 }
391 }
392 | host_class '&' host_class {
c327f3bc 393 if (($$ = class_isect($1, $3)) == 0) {
c4f2d992 394 yyerror("type mismatch");
082ddb26 395 yynerrs++; YYERROR;
c4f2d992 396 }
397 }
398 | host_class '|' host_class {
c327f3bc 399 if (($$ = class_union($1, $3)) == 0) {
c4f2d992 400 yyerror("type mismatch");
082ddb26 401 yynerrs++; YYERROR;
c4f2d992 402 }
403 }
c327f3bc 404 | STRING { $$ = class_fromString(clType_host, $1); }
c4f2d992 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);
082ddb26 410 yynerrs++; YYERROR;
c4f2d992 411 } else if (~n->c->type & clType_host) {
412 yyerror("type mismatch");
082ddb26 413 yynerrs++; YYERROR;
c4f2d992 414 } else {
415 $$ = n->c;
416 class_inc(n->c);
417 }
418 }
419 | '(' host_class ')' { $$ = $2; }
420 ;
421
082ddb26 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
433int parse(void)
434{
435 yynerrs = 0;
436 return (yyparse() || yynerrs);
437}
438
c4f2d992 439/*----- That's all, folks -------------------------------------------------*/