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