Fixing for new autotools.
[become] / src / parser.y
1 /* -*-c-*-
2 *
3 * $Id$
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 #define YYDEBUG 1
66 #define YYERROR_VERBOSE
67
68 %}
69 /*----- Stack type --------------------------------------------------------*/
70
71 %union {
72 long i;
73 char *s;
74 name *n;
75 class_node *c;
76 }
77
78 /*----- Token and rule declarations ---------------------------------------*/
79
80 /* --- Tokens --- */
81
82 %token BADTOKEN
83 %token USER
84 %token COMMAND
85 %token HOST
86 %token ALLOW
87 %token PORT
88 %token KEYFILE
89 %token <i> INT
90 %token <s> WORD
91 %token <s> STRING
92 %token ARROW
93
94 %left ','
95 %left '-'
96 %left '|'
97 %left '&'
98
99 /* --- Rules --- */
100
101 %type <c> user_class command_class host_class
102 %type <c> user_class_opt command_class_opt host_class_opt
103 %type <n> name
104
105 /*----- Error reporting ---------------------------------------------------*/
106 %{
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 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
214 key_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
226 allow_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
232 host_class_opt : /* empty */ { $$ = class_all; }
233 | '[' host_class ']' { $$ = $2; }
234 ;
235
236 user_class_opt : /* empty */ { $$ = class_all; }
237 | user_class { $$ = $1; }
238 ;
239
240 command_class_opt : /* empty */ { $$ = class_all; }
241 | ':' command_class { $$ = $2; }
242 ;
243
244 /* --- Names get translated into symbols quickly --- */
245
246 name : 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
263 user_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
316 command_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
360 host_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
413 int parse(void)
414 {
415 yynerrs = 0;
416 return (yyparse() || yynerrs);
417 }
418
419 /*----- That's all, folks -------------------------------------------------*/