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