Merge from vendor branch NTPD:
[dragonfly.git] / contrib / ntpd / parse.y
1 /*      $OpenBSD: parse.y,v 1.19 2004/08/10 12:45:27 henning Exp $ */
2
3 /*
4  * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
5  * Copyright (c) 2001 Markus Friedl.  All rights reserved.
6  * Copyright (c) 2001 Daniel Hartmeier.  All rights reserved.
7  * Copyright (c) 2001 Theo de Raadt.  All rights reserved.
8  *
9  * Permission to use, copy, modify, and distribute this software for any
10  * purpose with or without fee is hereby granted, provided that the above
11  * copyright notice and this permission notice appear in all copies.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20  */
21
22 %{
23 #include <sys/types.h>
24 #include <sys/socket.h>
25 #include <netinet/in.h>
26 #include <arpa/inet.h>
27
28 #include <ctype.h>
29 #include <errno.h>
30 #include <limits.h>
31 #include <stdarg.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <syslog.h>
35
36 #include "ntpd.h"
37
38 static struct ntpd_conf         *conf;
39 static FILE                     *fin = NULL;
40 static int                       lineno = 1;
41 static int                       errors = 0;
42 static int                       pdebug = 1;
43 char                            *infile;
44
45 int      yyerror(const char *, ...);
46 int      yyparse(void);
47 int      kw_cmp(const void *, const void *);
48 int      lookup(char *);
49 int      lgetc(FILE *);
50 int      lungetc(int);
51 int      findeol(void);
52 int      yylex(void);
53
54 TAILQ_HEAD(symhead, sym)         symhead = TAILQ_HEAD_INITIALIZER(symhead);
55 struct sym {
56         TAILQ_ENTRY(sym)         entries;
57         int                      used;
58         int                      persist;
59         char                    *nam;
60         char                    *val;
61 };
62
63 int      symset(const char *, const char *, int);
64 char    *symget(const char *);
65 int      atoul(char *, u_long *);
66
67 typedef struct {
68         union {
69                 u_int32_t                number;
70                 char                    *string;
71                 struct ntp_addr_wrap    *addr;
72         } v;
73         int lineno;
74 } YYSTYPE;
75
76 %}
77
78 %token  LISTEN ON
79 %token  SERVER SERVERS
80 %token  ERROR
81 %token  <v.string>              STRING
82 %type   <v.number>              number
83 %type   <v.string>              string
84 %type   <v.addr>                address
85 %%
86
87 grammar         : /* empty */
88                 | grammar '\n'
89                 | grammar conf_main '\n'
90                 | grammar varset '\n'
91                 | grammar error '\n'            { errors++; }
92                 ;
93
94 number          : STRING                        {
95                         u_long  ulval;
96
97                         if (atoul($1, &ulval) == -1) {
98                                 yyerror("\"%s\" is not a number", $1);
99                                 free($1);
100                                 YYERROR;
101                         } else
102                                 $$ = ulval;
103                         free($1);
104                 }
105                 ;
106
107 string          : string STRING                         {
108                         if (asprintf(&$$, "%s %s", $1, $2) == -1)
109                                 fatal("string: asprintf");
110                         free($1);
111                         free($2);
112                 }
113                 | STRING
114                 ;
115
116 varset          : STRING '=' string             {
117                         if (conf->opts & NTPD_OPT_VERBOSE)
118                                 printf("%s = \"%s\"\n", $1, $3);
119                         if (symset($1, $3, 0) == -1)
120                                 fatal("cannot store variable");
121                         free($1);
122                         free($3);
123                 }
124                 ;
125
126 conf_main       : LISTEN ON address     {
127                         struct listen_addr      *la;
128                         struct ntp_addr         *h, *next;
129
130                         if ($3->a == NULL) {
131                                 yyerror("cannot resolve \"%s\"", $3->name);
132                                 free($3->name);
133                                 free($3);
134                                 YYERROR;
135                         }
136
137                         for (h = $3->a; h != NULL; h = next) {
138                                 next = h->next;
139                                 if (h->ss.ss_family == AF_UNSPEC) {
140                                         conf->listen_all = 1;
141                                         free(h);
142                                         continue;
143                                 }
144                                 la = calloc(1, sizeof(struct listen_addr));
145                                 if (la == NULL)
146                                         fatal("listen on calloc");
147                                 la->fd = -1;
148                                 memcpy(&la->sa, &h->ss,
149                                     sizeof(struct sockaddr_storage));
150                                 TAILQ_INSERT_TAIL(&conf->listen_addrs, la,
151                                     entry);
152                                 free(h);
153                         }
154                         free($3->name);
155                         free($3);
156                 }
157                 | SERVERS address       {
158                         struct ntp_peer         *p;
159                         struct ntp_addr         *h, *next;
160
161                         h = $2->a;
162                         do {
163                                 if (h != NULL) {
164                                         next = h->next;
165                                         if (h->ss.ss_family != AF_INET &&
166                                             h->ss.ss_family != AF_INET6) {
167                                                 yyerror("IPv4 or IPv6 address "
168                                                     "or hostname expected");
169                                                 free($2->name);
170                                                 free($2);
171                                                 YYERROR;
172                                         }
173                                         h->next = NULL;
174                                 } else
175                                         next = NULL;
176
177                                 p = new_peer();
178                                 p->addr = h;
179                                 p->addr_head.a = h;
180                                 p->addr_head.pool = 1;
181                                 p->addr_head.name = strdup($2->name);
182                                 if (p->addr_head.name == NULL)
183                                         fatal(NULL);
184                                 TAILQ_INSERT_TAIL(&conf->ntp_peers, p, entry);
185
186                                 h = next;
187                         } while (h != NULL);
188
189                         free($2->name);
190                         free($2);
191                 }
192                 | SERVER address        {
193                         struct ntp_peer         *p;
194                         struct ntp_addr         *h, *next;
195
196                         p = new_peer();
197                         for (h = $2->a; h != NULL; h = next) {
198                                 next = h->next;
199                                 if (h->ss.ss_family != AF_INET &&
200                                     h->ss.ss_family != AF_INET6) {
201                                         yyerror("IPv4 or IPv6 address "
202                                             "or hostname expected");
203                                         free($2->name);
204                                         free($2);
205                                         YYERROR;
206                                 }
207                                 h->next = p->addr;
208                                 p->addr = h;
209                         }
210
211                         p->addr_head.a = p->addr;
212                         p->addr_head.pool = 0;
213                         p->addr_head.name = strdup($2->name);
214                         if (p->addr_head.name == NULL)
215                                 fatal(NULL);
216                         TAILQ_INSERT_TAIL(&conf->ntp_peers, p, entry);
217                         free($2->name);
218                         free($2);
219                 }
220                 ;
221
222 address         : STRING                {
223                         if (($$ = calloc(1, sizeof(struct ntp_addr_wrap))) ==
224                             NULL)
225                                 fatal(NULL);
226                         if (host($1, &$$->a) == -1) {
227                                 yyerror("could not parse address spec \"%s\"",
228                                     $1);
229                                 free($1);
230                                 YYERROR;
231                         }
232                         $$->name = $1;
233                 }
234                 ;
235
236 %%
237
238 struct keywords {
239         const char      *k_name;
240         int              k_val;
241 };
242
243 int
244 yyerror(const char *fmt, ...)
245 {
246         va_list          ap;
247         char            *nfmt;
248
249         errors = 1;
250         va_start(ap, fmt);
251         if (asprintf(&nfmt, "%s:%d: %s", infile, yylval.lineno, fmt) == -1)
252                 fatalx("yyerror asprintf");
253         vlog(LOG_CRIT, nfmt, ap);
254         va_end(ap);
255         free(nfmt);
256         return (0);
257 }
258
259 int
260 kw_cmp(const void *k, const void *e)
261 {
262         return (strcmp(k, ((const struct keywords *)e)->k_name));
263 }
264
265 int
266 lookup(char *s)
267 {
268         /* this has to be sorted always */
269         static const struct keywords keywords[] = {
270                 { "listen",             LISTEN},
271                 { "on",                 ON},
272                 { "server",             SERVER},
273                 { "servers",            SERVERS}
274         };
275         const struct keywords   *p;
276
277         p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
278             sizeof(keywords[0]), kw_cmp);
279
280         if (p) {
281                 if (pdebug > 1)
282                         fprintf(stderr, "%s: %d\n", s, p->k_val);
283                 return (p->k_val);
284         } else {
285                 if (pdebug > 1)
286                         fprintf(stderr, "string: %s\n", s);
287                 return (STRING);
288         }
289 }
290
291 #define MAXPUSHBACK     128
292
293 char    *parsebuf;
294 int      parseindex;
295 char     pushback_buffer[MAXPUSHBACK];
296 int      pushback_index = 0;
297
298 int
299 lgetc(FILE *f)
300 {
301         int     c, next;
302
303         if (parsebuf) {
304                 /* Read character from the parsebuffer instead of input. */
305                 if (parseindex >= 0) {
306                         c = parsebuf[parseindex++];
307                         if (c != '\0')
308                                 return (c);
309                         parsebuf = NULL;
310                 } else
311                         parseindex++;
312         }
313
314         if (pushback_index)
315                 return (pushback_buffer[--pushback_index]);
316
317         while ((c = getc(f)) == '\\') {
318                 next = getc(f);
319                 if (next != '\n') {
320                         if (isspace(next))
321                                 yyerror("whitespace after \\");
322                         ungetc(next, f);
323                         break;
324                 }
325                 yylval.lineno = lineno;
326                 lineno++;
327         }
328         if (c == '\t' || c == ' ') {
329                 /* Compress blanks to a single space. */
330                 do {
331                         c = getc(f);
332                 } while (c == '\t' || c == ' ');
333                 ungetc(c, f);
334                 c = ' ';
335         }
336
337         return (c);
338 }
339
340 int
341 lungetc(int c)
342 {
343         if (c == EOF)
344                 return (EOF);
345         if (parsebuf) {
346                 parseindex--;
347                 if (parseindex >= 0)
348                         return (c);
349         }
350         if (pushback_index < MAXPUSHBACK-1)
351                 return (pushback_buffer[pushback_index++] = c);
352         else
353                 return (EOF);
354 }
355
356 int
357 findeol(void)
358 {
359         int     c;
360
361         parsebuf = NULL;
362         pushback_index = 0;
363
364         /* skip to either EOF or the first real EOL */
365         while (1) {
366                 c = lgetc(fin);
367                 if (c == '\n') {
368                         lineno++;
369                         break;
370                 }
371                 if (c == EOF)
372                         break;
373         }
374         return (ERROR);
375 }
376
377 int
378 yylex(void)
379 {
380         char     buf[8096];
381         char    *p, *val;
382         int      endc, c;
383         int      token;
384
385 top:
386         p = buf;
387         while ((c = lgetc(fin)) == ' ')
388                 ; /* nothing */
389
390         yylval.lineno = lineno;
391         if (c == '#')
392                 while ((c = lgetc(fin)) != '\n' && c != EOF)
393                         ; /* nothing */
394         if (c == '$' && parsebuf == NULL) {
395                 while (1) {
396                         if ((c = lgetc(fin)) == EOF)
397                                 return (0);
398
399                         if (p + 1 >= buf + sizeof(buf) - 1) {
400                                 yyerror("string too long");
401                                 return (findeol());
402                         }
403                         if (isalnum(c) || c == '_') {
404                                 *p++ = (char)c;
405                                 continue;
406                         }
407                         *p = '\0';
408                         lungetc(c);
409                         break;
410                 }
411                 val = symget(buf);
412                 if (val == NULL) {
413                         yyerror("macro \"%s\" not defined", buf);
414                         return (findeol());
415                 }
416                 parsebuf = val;
417                 parseindex = 0;
418                 goto top;
419         }
420
421         switch (c) {
422         case '\'':
423         case '"':
424                 endc = c;
425                 while (1) {
426                         if ((c = lgetc(fin)) == EOF)
427                                 return (0);
428                         if (c == endc) {
429                                 *p = '\0';
430                                 break;
431                         }
432                         if (c == '\n') {
433                                 lineno++;
434                                 continue;
435                         }
436                         if (p + 1 >= buf + sizeof(buf) - 1) {
437                                 yyerror("string too long");
438                                 return (findeol());
439                         }
440                         *p++ = (char)c;
441                 }
442                 yylval.v.string = strdup(buf);
443                 if (yylval.v.string == NULL)
444                         fatal("yylex: strdup");
445                 return (STRING);
446         }
447
448 #define allowed_in_string(x) \
449         (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
450         x != '{' && x != '}' && x != '<' && x != '>' && \
451         x != '!' && x != '=' && x != '/' && x != '#' && \
452         x != ','))
453
454         if (isalnum(c) || c == ':' || c == '_' || c == '*') {
455                 do {
456                         *p++ = c;
457                         if ((unsigned)(p-buf) >= sizeof(buf)) {
458                                 yyerror("string too long");
459                                 return (findeol());
460                         }
461                 } while ((c = lgetc(fin)) != EOF && (allowed_in_string(c)));
462                 lungetc(c);
463                 *p = '\0';
464                 if ((token = lookup(buf)) == STRING)
465                         if ((yylval.v.string = strdup(buf)) == NULL)
466                                 fatal("yylex: strdup");
467                 return (token);
468         }
469         if (c == '\n') {
470                 yylval.lineno = lineno;
471                 lineno++;
472         }
473         if (c == EOF)
474                 return (0);
475         return (c);
476 }
477
478 int
479 parse_config(char *filename, struct ntpd_conf *xconf)
480 {
481         struct sym              *sym, *next;
482
483         conf = xconf;
484         lineno = 1;
485         errors = 0;
486         TAILQ_INIT(&conf->listen_addrs);
487         TAILQ_INIT(&conf->ntp_peers);
488
489         if ((fin = fopen(filename, "r")) == NULL) {
490                 log_warn("%s", filename);
491                 return (-1);
492         }
493         infile = filename;
494
495         yyparse();
496
497         fclose(fin);
498
499         /* Free macros and check which have not been used. */
500         for (sym = TAILQ_FIRST(&symhead); sym != NULL; sym = next) {
501                 next = TAILQ_NEXT(sym, entries);
502                 if ((conf->opts & NTPD_OPT_VERBOSE2) && !sym->used)
503                         fprintf(stderr, "warning: macro \"%s\" not "
504                             "used\n", sym->nam);
505                 if (!sym->persist) {
506                         free(sym->nam);
507                         free(sym->val);
508                         TAILQ_REMOVE(&symhead, sym, entries);
509                         free(sym);
510                 }
511         }
512
513         return (errors ? -1 : 0);
514 }
515
516 int
517 symset(const char *nam, const char *val, int persist)
518 {
519         struct sym      *sym;
520
521         for (sym = TAILQ_FIRST(&symhead); sym && strcmp(nam, sym->nam);
522             sym = TAILQ_NEXT(sym, entries))
523                 ;       /* nothing */
524
525         if (sym != NULL) {
526                 if (sym->persist == 1)
527                         return (0);
528                 else {
529                         free(sym->nam);
530                         free(sym->val);
531                         TAILQ_REMOVE(&symhead, sym, entries);
532                         free(sym);
533                 }
534         }
535         if ((sym = calloc(1, sizeof(*sym))) == NULL)
536                 return (-1);
537
538         sym->nam = strdup(nam);
539         if (sym->nam == NULL) {
540                 free(sym);
541                 return (-1);
542         }
543         sym->val = strdup(val);
544         if (sym->val == NULL) {
545                 free(sym->nam);
546                 free(sym);
547                 return (-1);
548         }
549         sym->used = 0;
550         sym->persist = persist;
551         TAILQ_INSERT_TAIL(&symhead, sym, entries);
552         return (0);
553 }
554
555 int
556 cmdline_symset(char *s)
557 {
558         char    *sym, *val;
559         int     ret;
560         size_t  len;
561
562         if ((val = strrchr(s, '=')) == NULL)
563                 return (-1);
564
565         len = strlen(s) - strlen(val) + 1;
566         if ((sym = malloc(len)) == NULL)
567                 fatal("cmdline_symset: malloc");
568
569         strlcpy(sym, s, len);
570
571         ret = symset(sym, val + 1, 1);
572         free(sym);
573
574         return (ret);
575 }
576
577 char *
578 symget(const char *nam)
579 {
580         struct sym      *sym;
581
582         TAILQ_FOREACH(sym, &symhead, entries)
583                 if (strcmp(nam, sym->nam) == 0) {
584                         sym->used = 1;
585                         return (sym->val);
586                 }
587         return (NULL);
588 }
589
590 int
591 atoul(char *s, u_long *ulvalp)
592 {
593         u_long   ulval;
594         char    *ep;
595
596         errno = 0;
597         ulval = strtoul(s, &ep, 0);
598         if (s[0] == '\0' || *ep != '\0')
599                 return (-1);
600         if (errno == ERANGE && ulval == ULONG_MAX)
601                 return (-1);
602         *ulvalp = ulval;
603         return (0);
604 }