chiark / gitweb /
f7ed0e3eb3ac26f8e38d0e1eccfd09b400f19f6d
[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 -------------------------------------------------*/