chiark / gitweb /
Complete rewrite to support class trees. Makes the behaviour of the set
[become] / src / parser.y
1 /* -*-c-*-
2  *
3  * $Id: parser.y,v 1.3 1997/09/09 18:17:06 mdw Exp $
4  *
5  * Parser for `become.conf' files
6  *
7  * (c) 1997 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.3  1997/09/09 18:17:06  mdw
33  * Allow default port to be given as a service name or port number.
34  *
35  * Revision 1.2  1997/08/04 10:24:24  mdw
36  * Sources placed under CVS control.
37  *
38  * Revision 1.1  1997/07/21  13:47:45  mdw
39  * Initial revision
40  *
41  */
42
43 /*----- Header files ------------------------------------------------------*/
44 %{
45
46 /* --- ANSI headers --- */
47
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <string.h>
51
52 /* --- Unix headers --- */
53
54 #include <sys/types.h>
55 #include <sys/socket.h>
56
57 #include <netinet/in.h>
58
59 #include <arpa/inet.h>
60
61 #include <netdb.h>
62 #include <pwd.h>
63 #include <unistd.h>
64
65 /* --- Local headers --- */
66
67 #include "class.h"
68 #include "daemon.h"
69 #include "lexer.h"
70 #include "name.h"
71 #include "rule.h"
72 #include "set.h"
73 #include "sym.h"
74 #include "userdb.h"
75 #include "utils.h"
76
77 %}
78 /*----- Stack type --------------------------------------------------------*/
79
80 %union {
81   long i;
82   char *s;
83   name *n;
84   classdef *c;
85 }
86
87 /*----- Token and rule declarations ---------------------------------------*/
88
89 /* --- Tokens --- */
90
91 %token BADTOKEN
92 %token USER
93 %token COMMAND
94 %token HOST
95 %token ALLOW
96 %token PORT
97 %token KEYFILE
98 %token <i> INT
99 %token <s> WORD
100 %token <s> STRING
101 %token ARROW
102
103 %left ','
104 %left '-'
105 %left '|'
106 %left '&'
107
108 /* --- Rules --- */
109
110 %type <c> user_class command_class host_class
111 %type <c> user_class_opt command_class_opt host_class_opt
112 %type <n> name
113
114 /*----- Error reporting ---------------------------------------------------*/
115 %{
116
117 #define YYDEBUG 1
118 #define YYERROR_VERBOSE
119
120 /* --- @yyprint@ --- *
121  *
122  * Arguments:   @FILE *fp@ = pointer to stream to write on
123  *              @int type@ = pointer to token type
124  *              @YYSTYPE v@ = token value
125  *
126  * Returns:     ---
127  *
128  * Use:         Displays the semantic value of a token.
129  */
130
131 #define YYPRINT(fp, type, value) yyprint(fp, type, value)
132
133 static void yyprint(FILE *fp, int type, YYSTYPE v)
134 {
135   switch (type) {
136     case INT:
137       fprintf(fp, " %li", v.i);
138       break;
139     case WORD:
140     case STRING:
141       fprintf(fp, " `%s'", v.s);
142       break;
143   }
144 }
145
146 /* --- @yyerror@ --- *
147  *
148  * Arguments:   @const char *msg@ = pointer to error message
149  *
150  * Returns:     ---
151  *
152  * Use:         Reports parse errors.
153  */
154
155 static void yyerror(const char *msg)
156 {
157   moan("%s at line %i", msg, lex_line);
158 }
159
160 %}
161 %%
162 /*----- The actual grammar ------------------------------------------------*/
163
164 /* --- Simple driver things --- */
165
166 file            : /* empty */
167                 | file statement
168                 ;
169
170 statement       : user_spec
171                 | command_spec
172                 | host_spec
173                 | allow_spec
174                 | port_spec
175                 | key_spec
176                 | error ';'
177                 ;
178
179 /* --- Main statement types --- */
180
181 user_spec       : USER name '=' user_class ';' {
182                           if ($2->c)
183                             class_dec($2->c);
184                           $2->c = $4;
185                         }
186                 ;
187
188 command_spec    : COMMAND name '=' command_class ';' {
189                           if ($2->c)
190                             class_dec($2->c);
191                           $2->c = $4;
192                         }
193                 ;
194
195 host_spec       : HOST name '=' host_class ';' {
196                           if ($2->c)
197                             class_dec($2->c);
198                           $2->c = $4;
199                         }
200                 ;
201
202 port_spec       : PORT STRING ';' {
203                           struct servent *s = getservbyname($2, "udp");
204                           if (!s) {
205                             moan("unknown service `%s' at line %i",
206                                  $2, lex_line);
207                             YYERROR;
208                           }
209                           daemon_usePort(s->s_port);
210                         }
211                 | PORT INT ';' { daemon_usePort(htons($2)); }
212                 ;
213
214 key_spec        : KEYFILE STRING ';' { daemon_readKey($2); }
215
216 /* --- Parsing allow specifications --- */
217
218 allow_spec      : ALLOW host_class_opt user_class ARROW
219                    user_class_opt command_class_opt ';' {
220                           rule_add($2, $3, $5, $6);
221                         }
222
223 host_class_opt  : /* empty */ { $$ = class_all; }
224                 | '[' host_class ']' { $$ = $2; }
225                 ;
226
227 user_class_opt  : /* empty */ { $$ = class_all; }
228                 | user_class { $$ = $1; }
229                 ;
230
231 command_class_opt : /* empty */ { $$ = class_all; }
232                 | ':' command_class { $$ = $2; }
233                 ;
234
235 /* --- Names get translated into symbols quickly --- */
236
237 name            : WORD  {
238                           unsigned f;
239                           name *n = name_find($1, 1, &f);
240                           if (!f)
241                             n->c = 0;
242                           $$ = n;
243                         }
244
245 /*----- Various class expression types ------------------------------------*
246  *
247  * Unfortunately, all these need to handle token types slightly differently
248  * and I can't be bothered to remember the current state.
249  */
250
251 /* --- User class expressions --- */
252
253 user_class      : user_class ',' user_class {
254                           if ($1->type != $3->type) {
255                             yyerror("type mismatch");
256                             class_dec($1);
257                             class_dec($3);
258                             YYERROR;
259                           } else {
260                             if ($1 == class_all)
261                               $$ = class_all;
262                             else
263                               $$ = class_create($1->type,
264                                                 set_union($1->t, $3->t));
265                             class_dec($1);
266                             class_dec($3);
267                           }
268                         }
269                 | user_class '-' user_class {
270                           if ($1->type != $3->type) {
271                             yyerror("type mismatch");
272                             class_dec($1);
273                             class_dec($3);
274                             YYERROR;
275                           } else {
276                             $$ = class_create($1->type,
277                                               set_subtract($1->t, $3->t));
278                             class_dec($1);
279                             class_dec($3);
280                           }
281                         }
282                 | user_class '&' user_class {
283                           if ($1->type != $3->type) {
284                             yyerror("type mismatch");
285                             class_dec($1);
286                             class_dec($3);
287                             YYERROR;
288                           } else {
289                             if ($1 == class_all)
290                               $$ = class_all;
291                             else
292                               $$ = class_create($1->type,
293                                                 set_intersect($1->t, $3->t));
294                             class_dec($1);
295                             class_dec($3);
296                           }
297                         }
298                 | user_class '|' user_class {
299                           if ($1->type != $3->type) {
300                             yyerror("type mismatch");
301                             class_dec($1);
302                             class_dec($3);
303                             YYERROR;
304                           } else {
305                             if ($1 == class_all)
306                               $$ = class_all;
307                             else
308                               $$ = class_create($1->type,
309                                                 set_union($1->t, $3->t));
310                             class_dec($1);
311                             class_dec($3);
312                           }
313                         }
314                 | INT   {
315                           sym_table *t = xmalloc(sizeof(*t));
316                           int u = $1;
317                           sym_createTable(t);
318                           sym_find(t, (char *)&u, sizeof(u),
319                                    sizeof(sym_base), 0);
320                           $$ = class_create(clType_user, t);
321                         }
322                 | STRING {
323                           struct passwd *pw;
324                           sym_table *t;
325                           int u;
326                           if ((pw = userdb_userByName($1)) == 0) {
327                             moan("user `%s' not known at line %i",
328                                  $1, lex_line);
329                             YYERROR;
330                           } else {
331                             t = xmalloc(sizeof(*t));
332                             u = pw->pw_uid;
333                             sym_createTable(t);
334                             sym_find(t, (char *)&u, sizeof(u),
335                                      sizeof(sym_base), 0);
336                             $$ = class_create(clType_user, t);
337                           }
338                         }
339                 | WORD  {
340                           name *n = name_find($1, 0, 0);
341                           if (!n || !n->c) {
342                             moan("class `%s' not found at line %i",
343                                  $1, lex_line);
344                             YYERROR;
345                           } else if (~n->c->type & clType_user) {
346                             yyerror("type mismatch");
347                             YYERROR;
348                           } else {
349                             $$ = n->c;
350                             class_inc(n->c);
351                           }
352                         }
353                 | '(' user_class ')' { $$ = $2; }
354                 ;
355
356 /* --- Command class expressions --- */
357
358 command_class   : command_class ',' command_class {
359                           if ($1->type != $3->type) {
360                             yyerror("type mismatch");
361                             class_dec($1);
362                             class_dec($3);
363                             YYERROR;
364                           } else {
365                             if ($1 == class_all)
366                               $$ = class_all;
367                             else
368                               $$ = class_create($1->type,
369                                                 set_union($1->t, $3->t));
370                             class_dec($1);
371                             class_dec($3);
372                           }
373                         }
374                 | command_class '-' command_class {
375                           if ($1->type != $3->type) {
376                             yyerror("type mismatch");
377                             class_dec($1);
378                             class_dec($3);
379                             YYERROR;
380                           } else {
381                             $$ = class_create($1->type,
382                                               set_subtract($1->t, $3->t));
383                             class_dec($1);
384                             class_dec($3);
385                           }
386                         }
387                 | command_class '&' command_class {
388                           if ($1->type != $3->type) {
389                             yyerror("type mismatch");
390                             class_dec($1);
391                             class_dec($3);
392                             YYERROR;
393                           } else {
394                             if ($1 == class_all)
395                               $$ = class_all;
396                             else
397                               $$ = class_create($1->type,
398                                                 set_intersect($1->t, $3->t));
399                             class_dec($1);
400                             class_dec($3);
401                           }
402                         }
403                 | command_class '|' command_class {
404                           if ($1->type != $3->type) {
405                             yyerror("type mismatch");
406                             class_dec($1);
407                             class_dec($3);
408                             YYERROR;
409                           } else {
410                             if ($1 == class_all)
411                               $$ = class_all;
412                             else
413                               $$ = class_create($1->type,
414                                                 set_union($1->t, $3->t));
415                             class_dec($1);
416                             class_dec($3);
417                           }
418                         }
419                 | STRING {
420                           sym_table *t = xmalloc(sizeof(*t));
421                           sym_createTable(t);
422                           sym_find(t, $1, -1, sizeof(sym_base), 0);
423                           $$ = class_create(clType_command, t);
424                         }
425                 | WORD  {
426                           name *n = name_find($1, 0, 0);
427                           if (!n || !n->c) {
428                             moan("class `%s' not found at line %i",
429                                  $1, lex_line);
430                             YYERROR;
431                           } else if (~n->c->type & clType_command) {
432                             yyerror("type mismatch");
433                             YYERROR;
434                           } else {
435                             $$ = n->c;
436                             class_inc(n->c);
437                           }
438                         }
439                 | '(' command_class ')' { $$ = $2; }
440                 ;
441
442 /* --- Host class expressions --- */
443
444 host_class : host_class ',' host_class {
445                           if ($1->type != $3->type) {
446                             yyerror("type mismatch");
447                             class_dec($1);
448                             class_dec($3);
449                             YYERROR;
450                           } else {
451                             if ($1 == class_all)
452                               $$ = class_all;
453                             else
454                               $$ = class_create($1->type,
455                                                 set_union($1->t, $3->t));
456                             class_dec($1);
457                             class_dec($3);
458                           }
459                         }
460                 | host_class '-' host_class {
461                           if ($1->type != $3->type) {
462                             yyerror("type mismatch");
463                             class_dec($1);
464                             class_dec($3);
465                             YYERROR;
466                           } else {
467                             $$ = class_create($1->type,
468                                               set_subtract($1->t, $3->t));
469                             class_dec($1);
470                             class_dec($3);
471                           }
472                         }
473                 | host_class '&' host_class {
474                           if ($1->type != $3->type) {
475                             yyerror("type mismatch");
476                             class_dec($1);
477                             class_dec($3);
478                             YYERROR;
479                           } else {
480                             if ($1 == class_all)
481                               $$ = class_all;
482                             else
483                               $$ = class_create($1->type,
484                                                 set_intersect($1->t, $3->t));
485                             class_dec($1);
486                             class_dec($3);
487                           }
488                         }
489                 | host_class '|' host_class {
490                           if ($1->type != $3->type) {
491                             yyerror("type mismatch");
492                             class_dec($1);
493                             class_dec($3);
494                             YYERROR;
495                           } else {
496                             if ($1 == class_all)
497                               $$ = class_all;
498                             else
499                               $$ = class_create($1->type,
500                                                 set_union($1->t, $3->t));
501                             class_dec($1);
502                             class_dec($3);
503                           }
504                         }
505                 | STRING {
506                           sym_table *t = xmalloc(sizeof(*t));
507                           sym_createTable(t);
508                           sym_find(t, $1, -1, sizeof(sym_base), 0);
509                           $$ = class_create(clType_host, t);
510                         }
511                 | WORD  {
512                           name *n = name_find($1, 0, 0);
513                           if (!n || !n->c) {
514                             moan("class `%s' not found at line %i",
515                                  $1, lex_line);
516                             YYERROR;
517                           } else if (~n->c->type & clType_host) {
518                             yyerror("type mismatch");
519                             YYERROR;
520                           } else {
521                             $$ = n->c;
522                             class_inc(n->c);
523                           }
524                         }
525                 | '(' host_class ')' { $$ = $2; }
526                 ;
527
528 /*----- That's all, folks -------------------------------------------------*/