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