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