1*08f6ba19Snaddy /* $OpenBSD: parse.y,v 1.78 2021/10/15 15:01:28 naddy Exp $ */
2f64d3c3cShenning
3f64d3c3cShenning /*
4f64d3c3cShenning * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
5f64d3c3cShenning * Copyright (c) 2001 Markus Friedl. All rights reserved.
6f64d3c3cShenning * Copyright (c) 2001 Daniel Hartmeier. All rights reserved.
7f64d3c3cShenning * Copyright (c) 2001 Theo de Raadt. All rights reserved.
8f64d3c3cShenning *
9f64d3c3cShenning * Permission to use, copy, modify, and distribute this software for any
10f64d3c3cShenning * purpose with or without fee is hereby granted, provided that the above
11f64d3c3cShenning * copyright notice and this permission notice appear in all copies.
12f64d3c3cShenning *
13f64d3c3cShenning * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14f64d3c3cShenning * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15f64d3c3cShenning * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16f64d3c3cShenning * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17f64d3c3cShenning * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18f64d3c3cShenning * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19f64d3c3cShenning * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20f64d3c3cShenning */
21f64d3c3cShenning
22f64d3c3cShenning %{
23f64d3c3cShenning #include <sys/types.h>
24f64d3c3cShenning #include <sys/socket.h>
25f64d3c3cShenning #include <netinet/in.h>
26f64d3c3cShenning #include <arpa/inet.h>
27f64d3c3cShenning
28f64d3c3cShenning #include <ctype.h>
29f64d3c3cShenning #include <errno.h>
30f64d3c3cShenning #include <limits.h>
31f64d3c3cShenning #include <stdarg.h>
32f64d3c3cShenning #include <stdio.h>
3379b7b712Sotto #include <stdlib.h>
34f64d3c3cShenning #include <string.h>
35f64d3c3cShenning #include <syslog.h>
36f64d3c3cShenning
37f64d3c3cShenning #include "ntpd.h"
38f64d3c3cShenning
3920741916Sderaadt TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files);
4020741916Sderaadt static struct file {
4120741916Sderaadt TAILQ_ENTRY(file) entry;
4220741916Sderaadt FILE *stream;
4320741916Sderaadt char *name;
4420741916Sderaadt int lineno;
4520741916Sderaadt int errors;
46c6004ab9Smpf } *file, *topfile;
4720741916Sderaadt struct file *pushfile(const char *);
4820741916Sderaadt int popfile(void);
49f64d3c3cShenning int yyparse(void);
5020741916Sderaadt int yylex(void);
510f79392cSdoug int yyerror(const char *, ...)
520f79392cSdoug __attribute__((__format__ (printf, 1, 2)))
530f79392cSdoug __attribute__((__nonnull__ (1)));
54f64d3c3cShenning int kw_cmp(const void *, const void *);
55f64d3c3cShenning int lookup(char *);
56d5d66eaeSderaadt int lgetc(int);
57f64d3c3cShenning int lungetc(int);
58f64d3c3cShenning int findeol(void);
5920741916Sderaadt
603e0a6a28Sbenno struct sockaddr_in query_addr4;
613e0a6a28Sbenno struct sockaddr_in6 query_addr6;
62c7e8e3a2Sotto int poolseqnum;
63f64d3c3cShenning
64c82b5dedSderaadt struct opts {
65c82b5dedSderaadt int weight;
66c8ddfef5Sckuethe int correction;
677d8d1c3fSpatrick int stratum;
6802d74365Sphessler int rtable;
69eb7f225fSotto int trusted;
70c45e6fdaSckuethe char *refstr;
71c82b5dedSderaadt } opts;
72b85c043bSderaadt void opts_default(void);
73c82b5dedSderaadt
74f64d3c3cShenning typedef struct {
75f64d3c3cShenning union {
76c82b5dedSderaadt int64_t number;
77f64d3c3cShenning char *string;
78e35d9b5eShenning struct ntp_addr_wrap *addr;
79c82b5dedSderaadt struct opts opts;
80f64d3c3cShenning } v;
81f64d3c3cShenning int lineno;
82f64d3c3cShenning } YYSTYPE;
83f64d3c3cShenning
84f64d3c3cShenning %}
85f64d3c3cShenning
86eb7f225fSotto %token LISTEN ON CONSTRAINT CONSTRAINTS FROM QUERY TRUSTED
877d8d1c3fSpatrick %token SERVER SERVERS SENSOR CORRECTION RTABLE REFID STRATUM WEIGHT
88f64d3c3cShenning %token ERROR
89f64d3c3cShenning %token <v.string> STRING
90c82b5dedSderaadt %token <v.number> NUMBER
91a7894e87Sotto %type <v.addr> address url urllist
9202d74365Sphessler %type <v.opts> listen_opts listen_opts_l listen_opt
93c82b5dedSderaadt %type <v.opts> server_opts server_opts_l server_opt
94c82b5dedSderaadt %type <v.opts> sensor_opts sensor_opts_l sensor_opt
95c8ddfef5Sckuethe %type <v.opts> correction
9602d74365Sphessler %type <v.opts> rtable
97c45e6fdaSckuethe %type <v.opts> refid
987d8d1c3fSpatrick %type <v.opts> stratum
99c82b5dedSderaadt %type <v.opts> weight
100eb7f225fSotto %type <v.opts> trusted
101f64d3c3cShenning %%
102f64d3c3cShenning
103f64d3c3cShenning grammar : /* empty */
104f64d3c3cShenning | grammar '\n'
10520741916Sderaadt | grammar main '\n'
10620741916Sderaadt | grammar error '\n' { file->errors++; }
107f64d3c3cShenning ;
108f64d3c3cShenning
10902d74365Sphessler main : LISTEN ON address listen_opts {
110f64d3c3cShenning struct listen_addr *la;
111204af22aShenning struct ntp_addr *h, *next;
112f64d3c3cShenning
11379668879Sphessler if ((h = $3->a) == NULL &&
114c9addb91Sotto (host_dns($3->name, 0, &h) == -1 || !h)) {
11540b0cbdaShenning yyerror("could not resolve \"%s\"", $3->name);
1161008f341Shenning free($3->name);
1171008f341Shenning free($3);
1181008f341Shenning YYERROR;
1191008f341Shenning }
1201008f341Shenning
12140b0cbdaShenning for (; h != NULL; h = next) {
122204af22aShenning next = h->next;
123204af22aShenning la = calloc(1, sizeof(struct listen_addr));
124204af22aShenning if (la == NULL)
125204af22aShenning fatal("listen on calloc");
1269096d664Shenning la->fd = -1;
12702d74365Sphessler la->rtable = $4.rtable;
128204af22aShenning memcpy(&la->sa, &h->ss,
129204af22aShenning sizeof(struct sockaddr_storage));
130204af22aShenning TAILQ_INSERT_TAIL(&conf->listen_addrs, la,
131204af22aShenning entry);
132204af22aShenning free(h);
133204af22aShenning }
134e35d9b5eShenning free($3->name);
135e35d9b5eShenning free($3);
136f64d3c3cShenning }
1373e0a6a28Sbenno | QUERY FROM STRING {
1383e0a6a28Sbenno struct sockaddr_in sin4;
1393e0a6a28Sbenno struct sockaddr_in6 sin6;
1403e0a6a28Sbenno
141f41a09e2Snaddy memset(&sin4, 0, sizeof(sin4));
1423e0a6a28Sbenno sin4.sin_family = AF_INET;
1433e0a6a28Sbenno sin4.sin_len = sizeof(struct sockaddr_in);
144f41a09e2Snaddy memset(&sin6, 0, sizeof(sin6));
1453e0a6a28Sbenno sin6.sin6_family = AF_INET6;
1463e0a6a28Sbenno sin6.sin6_len = sizeof(struct sockaddr_in6);
1473e0a6a28Sbenno
1483e0a6a28Sbenno if (inet_pton(AF_INET, $3, &sin4.sin_addr) == 1)
1493e0a6a28Sbenno memcpy(&query_addr4, &sin4, sin4.sin_len);
1503e0a6a28Sbenno else if (inet_pton(AF_INET6, $3, &sin6.sin6_addr) == 1)
1513e0a6a28Sbenno memcpy(&query_addr6, &sin6, sin6.sin6_len);
1523e0a6a28Sbenno else {
1533e0a6a28Sbenno yyerror("invalid IPv4 or IPv6 address: %s\n",
1543e0a6a28Sbenno $3);
1553e0a6a28Sbenno free($3);
1563e0a6a28Sbenno YYERROR;
1573e0a6a28Sbenno }
1583e0a6a28Sbenno
1593e0a6a28Sbenno free($3);
1603e0a6a28Sbenno }
161c82b5dedSderaadt | SERVERS address server_opts {
1629096d664Shenning struct ntp_peer *p;
163204af22aShenning struct ntp_addr *h, *next;
1649096d664Shenning
165a3c37861Shenning h = $2->a;
166a3c37861Shenning do {
167a3c37861Shenning if (h != NULL) {
168204af22aShenning next = h->next;
169005baf58Shenning if (h->ss.ss_family != AF_INET &&
170005baf58Shenning h->ss.ss_family != AF_INET6) {
171005baf58Shenning yyerror("IPv4 or IPv6 address "
172005baf58Shenning "or hostname expected");
17371184721Shenning free(h);
174e35d9b5eShenning free($2->name);
175e35d9b5eShenning free($2);
176005baf58Shenning YYERROR;
177005baf58Shenning }
1783801c0acShenning h->next = NULL;
179a3c37861Shenning } else
180a3c37861Shenning next = NULL;
181a3c37861Shenning
182a3c37861Shenning p = new_peer();
183c82b5dedSderaadt p->weight = $3.weight;
184eb7f225fSotto p->trusted = $3.trusted;
1851511e2d1Sotto conf->trusted_peers = conf->trusted_peers ||
1861511e2d1Sotto $3.trusted;
1873e0a6a28Sbenno p->query_addr4 = query_addr4;
1883e0a6a28Sbenno p->query_addr6 = query_addr6;
1893801c0acShenning p->addr = h;
190e35d9b5eShenning p->addr_head.a = h;
191c7e8e3a2Sotto p->addr_head.pool = ++poolseqnum;
192e35d9b5eShenning p->addr_head.name = strdup($2->name);
193e35d9b5eShenning if (p->addr_head.name == NULL)
194e35d9b5eShenning fatal(NULL);
1956be00f15Shenning if (p->addr != NULL)
1966be00f15Shenning p->state = STATE_DNS_DONE;
197f51e26d3Snaddy TAILQ_INSERT_TAIL(&conf->ntp_peers, p, entry);
198a3c37861Shenning h = next;
199a3c37861Shenning } while (h != NULL);
200a3c37861Shenning
201e35d9b5eShenning free($2->name);
202e35d9b5eShenning free($2);
203204af22aShenning }
204c82b5dedSderaadt | SERVER address server_opts {
2053801c0acShenning struct ntp_peer *p;
2063801c0acShenning struct ntp_addr *h, *next;
2073801c0acShenning
20897c9f460Shenning p = new_peer();
209e35d9b5eShenning for (h = $2->a; h != NULL; h = next) {
2103801c0acShenning next = h->next;
2113801c0acShenning if (h->ss.ss_family != AF_INET &&
2123801c0acShenning h->ss.ss_family != AF_INET6) {
2133801c0acShenning yyerror("IPv4 or IPv6 address "
2143801c0acShenning "or hostname expected");
21571184721Shenning free(h);
21671184721Shenning free(p);
217e35d9b5eShenning free($2->name);
218e35d9b5eShenning free($2);
2193801c0acShenning YYERROR;
2203801c0acShenning }
2213801c0acShenning h->next = p->addr;
2223801c0acShenning p->addr = h;
2233801c0acShenning }
2243801c0acShenning
225c82b5dedSderaadt p->weight = $3.weight;
226eb7f225fSotto p->trusted = $3.trusted;
2271511e2d1Sotto conf->trusted_peers = conf->trusted_peers ||
2281511e2d1Sotto $3.trusted;
2293e0a6a28Sbenno p->query_addr4 = query_addr4;
2303e0a6a28Sbenno p->query_addr6 = query_addr6;
231e35d9b5eShenning p->addr_head.a = p->addr;
232e35d9b5eShenning p->addr_head.pool = 0;
233e35d9b5eShenning p->addr_head.name = strdup($2->name);
234e35d9b5eShenning if (p->addr_head.name == NULL)
235e35d9b5eShenning fatal(NULL);
2366be00f15Shenning if (p->addr != NULL)
2376be00f15Shenning p->state = STATE_DNS_DONE;
2383801c0acShenning TAILQ_INSERT_TAIL(&conf->ntp_peers, p, entry);
239e35d9b5eShenning free($2->name);
240e35d9b5eShenning free($2);
2413801c0acShenning }
242bc58a738Sreyk | CONSTRAINTS FROM url {
243bc58a738Sreyk struct constraint *p;
244bc58a738Sreyk struct ntp_addr *h, *next;
245bc58a738Sreyk
246bc58a738Sreyk h = $3->a;
247bc58a738Sreyk do {
248bc58a738Sreyk if (h != NULL) {
249bc58a738Sreyk next = h->next;
250bc58a738Sreyk if (h->ss.ss_family != AF_INET &&
251bc58a738Sreyk h->ss.ss_family != AF_INET6) {
252bc58a738Sreyk yyerror("IPv4 or IPv6 address "
253bc58a738Sreyk "or hostname expected");
254bc58a738Sreyk free(h);
255bc58a738Sreyk free($3->name);
256bc58a738Sreyk free($3->path);
257bc58a738Sreyk free($3);
258bc58a738Sreyk YYERROR;
259bc58a738Sreyk }
260bc58a738Sreyk h->next = NULL;
261bc58a738Sreyk } else
262bc58a738Sreyk next = NULL;
263bc58a738Sreyk
264bc58a738Sreyk p = new_constraint();
265bc58a738Sreyk p->addr = h;
266bc58a738Sreyk p->addr_head.a = h;
267c7e8e3a2Sotto p->addr_head.pool = ++poolseqnum;
268bc58a738Sreyk p->addr_head.name = strdup($3->name);
269bc58a738Sreyk p->addr_head.path = strdup($3->path);
270bc58a738Sreyk if (p->addr_head.name == NULL ||
271bc58a738Sreyk p->addr_head.path == NULL)
272bc58a738Sreyk fatal(NULL);
273bc58a738Sreyk if (p->addr != NULL)
274bc58a738Sreyk p->state = STATE_DNS_DONE;
2753303745eSreyk constraint_add(p);
276bc58a738Sreyk h = next;
277bc58a738Sreyk } while (h != NULL);
278bc58a738Sreyk
279bc58a738Sreyk free($3->name);
280bc58a738Sreyk free($3);
281bc58a738Sreyk }
282a7894e87Sotto | CONSTRAINT FROM urllist {
283bc58a738Sreyk struct constraint *p;
2843303745eSreyk struct ntp_addr *h, *next;
285bc58a738Sreyk
286bc58a738Sreyk p = new_constraint();
2873303745eSreyk for (h = $3->a; h != NULL; h = next) {
2883303745eSreyk next = h->next;
289bc58a738Sreyk if (h->ss.ss_family != AF_INET &&
290bc58a738Sreyk h->ss.ss_family != AF_INET6) {
291bc58a738Sreyk yyerror("IPv4 or IPv6 address "
292bc58a738Sreyk "or hostname expected");
293bc58a738Sreyk free(h);
294bc58a738Sreyk free(p);
295bc58a738Sreyk free($3->name);
296bc58a738Sreyk free($3->path);
297bc58a738Sreyk free($3);
298bc58a738Sreyk YYERROR;
299bc58a738Sreyk }
3003303745eSreyk h->next = p->addr;
301bc58a738Sreyk p->addr = h;
302bc58a738Sreyk }
303bc58a738Sreyk
304bc58a738Sreyk p->addr_head.a = p->addr;
305bc58a738Sreyk p->addr_head.pool = 0;
306bc58a738Sreyk p->addr_head.name = strdup($3->name);
307bc58a738Sreyk p->addr_head.path = strdup($3->path);
308bc58a738Sreyk if (p->addr_head.name == NULL ||
309bc58a738Sreyk p->addr_head.path == NULL)
310bc58a738Sreyk fatal(NULL);
311bc58a738Sreyk if (p->addr != NULL)
312bc58a738Sreyk p->state = STATE_DNS_DONE;
3133303745eSreyk constraint_add(p);
314bc58a738Sreyk free($3->name);
315bc58a738Sreyk free($3);
316bc58a738Sreyk }
317c82b5dedSderaadt | SENSOR STRING sensor_opts {
318009f3548Shenning struct ntp_conf_sensor *s;
319009f3548Shenning
320009f3548Shenning s = new_sensor($2);
321c82b5dedSderaadt s->weight = $3.weight;
322c8ddfef5Sckuethe s->correction = $3.correction;
323c45e6fdaSckuethe s->refstr = $3.refstr;
3247d8d1c3fSpatrick s->stratum = $3.stratum;
3251511e2d1Sotto s->trusted = $3.trusted;
3261511e2d1Sotto conf->trusted_sensors = conf->trusted_sensors ||
3271511e2d1Sotto $3.trusted;
328009f3548Shenning free($2);
329009f3548Shenning TAILQ_INSERT_TAIL(&conf->ntp_conf_sensors, s, entry);
330009f3548Shenning }
331f64d3c3cShenning ;
332f64d3c3cShenning
333f64d3c3cShenning address : STRING {
334e35d9b5eShenning if (($$ = calloc(1, sizeof(struct ntp_addr_wrap))) ==
335e35d9b5eShenning NULL)
336e35d9b5eShenning fatal(NULL);
3372388a8b4Stedu host($1, &$$->a);
338e35d9b5eShenning $$->name = $1;
339f64d3c3cShenning }
340f64d3c3cShenning ;
341f64d3c3cShenning
342a7894e87Sotto urllist : urllist address {
343a7894e87Sotto struct ntp_addr *p, *q = NULL;
344a7894e87Sotto struct in_addr ina;
345a7894e87Sotto struct in6_addr in6a;
346a7894e87Sotto
347a7894e87Sotto if (inet_pton(AF_INET, $2->name, &ina) != 1 &&
348a7894e87Sotto inet_pton(AF_INET6, $2->name, &in6a) != 1) {
349a7894e87Sotto yyerror("url can only be followed by IP "
350a7894e87Sotto "addresses");
351a7894e87Sotto free($2->name);
352a7894e87Sotto free($2);
353a7894e87Sotto YYERROR;
354a7894e87Sotto }
355a7894e87Sotto p = $2->a;
356a7894e87Sotto while (p != NULL) {
357a7894e87Sotto q = p;
358a7894e87Sotto p = p->next;
359a7894e87Sotto }
360a7894e87Sotto if (q != NULL) {
361a7894e87Sotto q->next = $1->a;
362a7894e87Sotto $1->a = $2->a;
363a7894e87Sotto free($2);
364a7894e87Sotto }
365a7894e87Sotto $$ = $1;
366a7894e87Sotto }
367a7894e87Sotto | url {
368a7894e87Sotto $$ = $1;
369a7894e87Sotto }
370a7894e87Sotto ;
371a7894e87Sotto
372bc58a738Sreyk url : STRING {
373bc58a738Sreyk char *hname, *path;
374bc58a738Sreyk
375bc58a738Sreyk if (($$ = calloc(1, sizeof(struct ntp_addr_wrap))) ==
376bc58a738Sreyk NULL)
377bc58a738Sreyk fatal("calloc");
378bc58a738Sreyk
379bc58a738Sreyk if (strncmp("https://", $1,
380bc58a738Sreyk strlen("https://")) != 0) {
381bc58a738Sreyk host($1, &$$->a);
382bc58a738Sreyk $$->name = $1;
383bc58a738Sreyk } else {
384bc58a738Sreyk hname = $1 + strlen("https://");
385bc58a738Sreyk
386bc58a738Sreyk path = hname + strcspn(hname, "/\\");
387ae231988Sreyk if (*path != '\0') {
388bc58a738Sreyk if (($$->path = strdup(path)) == NULL)
389bc58a738Sreyk fatal("strdup");
390bc58a738Sreyk *path = '\0';
391ae231988Sreyk }
392bc58a738Sreyk host(hname, &$$->a);
393bc58a738Sreyk if (($$->name = strdup(hname)) == NULL)
394bc58a738Sreyk fatal("strdup");
395bc58a738Sreyk }
396ae231988Sreyk if ($$->path == NULL &&
397ae231988Sreyk ($$->path = strdup("/")) == NULL)
398ae231988Sreyk fatal("strdup");
399bc58a738Sreyk }
400bc58a738Sreyk ;
401bc58a738Sreyk
40202d74365Sphessler listen_opts : { opts_default(); }
40302d74365Sphessler listen_opts_l
40402d74365Sphessler { $$ = opts; }
40502d74365Sphessler | { opts_default(); $$ = opts; }
40602d74365Sphessler ;
40702d74365Sphessler listen_opts_l : listen_opts_l listen_opt
40802d74365Sphessler | listen_opt
40902d74365Sphessler ;
41002d74365Sphessler listen_opt : rtable
41102d74365Sphessler ;
41202d74365Sphessler
413b85c043bSderaadt server_opts : { opts_default(); }
414c82b5dedSderaadt server_opts_l
415c82b5dedSderaadt { $$ = opts; }
416b85c043bSderaadt | { opts_default(); $$ = opts; }
417c82b5dedSderaadt ;
418c82b5dedSderaadt server_opts_l : server_opts_l server_opt
419c82b5dedSderaadt | server_opt
420c82b5dedSderaadt ;
421c82b5dedSderaadt server_opt : weight
422eb7f225fSotto | trusted
42349532891Shenning ;
42449532891Shenning
425b85c043bSderaadt sensor_opts : { opts_default(); }
426c82b5dedSderaadt sensor_opts_l
427c82b5dedSderaadt { $$ = opts; }
428b85c043bSderaadt | { opts_default(); $$ = opts; }
429c82b5dedSderaadt ;
430c82b5dedSderaadt sensor_opts_l : sensor_opts_l sensor_opt
431c82b5dedSderaadt | sensor_opt
432c82b5dedSderaadt ;
433c8ddfef5Sckuethe sensor_opt : correction
434c45e6fdaSckuethe | refid
4357d8d1c3fSpatrick | stratum
436c8ddfef5Sckuethe | weight
4371511e2d1Sotto | trusted
438c8ddfef5Sckuethe ;
439c8ddfef5Sckuethe
440c8ddfef5Sckuethe correction : CORRECTION NUMBER {
441c8ddfef5Sckuethe if ($2 < -127000000 || $2 > 127000000) {
442c8ddfef5Sckuethe yyerror("correction must be between "
443c8ddfef5Sckuethe "-127000000 and 127000000 microseconds");
444c8ddfef5Sckuethe YYERROR;
445c8ddfef5Sckuethe }
446c8ddfef5Sckuethe opts.correction = $2;
447c8ddfef5Sckuethe }
448c82b5dedSderaadt ;
449c82b5dedSderaadt
450c45e6fdaSckuethe refid : REFID STRING {
45135757d17Sderaadt size_t l = strlen($2);
45235757d17Sderaadt
453c45e6fdaSckuethe if (l < 1 || l > 4) {
45435757d17Sderaadt yyerror("refid must be 1 to 4 characters");
45535757d17Sderaadt free($2);
456c45e6fdaSckuethe YYERROR;
457c45e6fdaSckuethe }
458c45e6fdaSckuethe opts.refstr = $2;
459c45e6fdaSckuethe }
460c45e6fdaSckuethe ;
461c45e6fdaSckuethe
4627d8d1c3fSpatrick stratum : STRATUM NUMBER {
4637d8d1c3fSpatrick if ($2 < 1 || $2 > 15) {
4647d8d1c3fSpatrick yyerror("stratum must be between "
4657d8d1c3fSpatrick "1 and 15");
4667d8d1c3fSpatrick YYERROR;
4677d8d1c3fSpatrick }
4687d8d1c3fSpatrick opts.stratum = $2;
4697d8d1c3fSpatrick }
4707d8d1c3fSpatrick ;
4717d8d1c3fSpatrick
472c82b5dedSderaadt weight : WEIGHT NUMBER {
47349532891Shenning if ($2 < 1 || $2 > 10) {
47449532891Shenning yyerror("weight must be between 1 and 10");
47549532891Shenning YYERROR;
47649532891Shenning }
477c82b5dedSderaadt opts.weight = $2;
47849532891Shenning }
47902d74365Sphessler rtable : RTABLE NUMBER {
48002d74365Sphessler if ($2 < 0 || $2 > RT_TABLEID_MAX) {
481a0ef9696Sreyk yyerror("rtable must be between 1"
482a0ef9696Sreyk " and RT_TABLEID_MAX");
48302d74365Sphessler YYERROR;
48402d74365Sphessler }
48502d74365Sphessler opts.rtable = $2;
48602d74365Sphessler }
48749532891Shenning ;
48849532891Shenning
489eb7f225fSotto trusted : TRUSTED {
490eb7f225fSotto opts.trusted = 1;
491eb7f225fSotto }
492eb7f225fSotto
493f64d3c3cShenning %%
494f64d3c3cShenning
495b85c043bSderaadt void
496b85c043bSderaadt opts_default(void)
497b85c043bSderaadt {
498842d7e97Sbcook memset(&opts, 0, sizeof opts);
499b85c043bSderaadt opts.weight = 1;
5007d8d1c3fSpatrick opts.stratum = 1;
501b85c043bSderaadt }
502b85c043bSderaadt
503f64d3c3cShenning struct keywords {
504f64d3c3cShenning const char *k_name;
505f64d3c3cShenning int k_val;
506f64d3c3cShenning };
507f64d3c3cShenning
508f64d3c3cShenning int
yyerror(const char * fmt,...)509f64d3c3cShenning yyerror(const char *fmt, ...)
510f64d3c3cShenning {
511f64d3c3cShenning va_list ap;
512cd8337bcSbluhm char *msg;
513f64d3c3cShenning
51420741916Sderaadt file->errors++;
515f64d3c3cShenning va_start(ap, fmt);
516cd8337bcSbluhm if (vasprintf(&msg, fmt, ap) == -1)
517cd8337bcSbluhm fatalx("yyerror vasprintf");
518f64d3c3cShenning va_end(ap);
51995ca2e79Sbcook log_warnx("%s:%d: %s", file->name, yylval.lineno, msg);
520cd8337bcSbluhm free(msg);
521f64d3c3cShenning return (0);
522f64d3c3cShenning }
523f64d3c3cShenning
524f64d3c3cShenning int
kw_cmp(const void * k,const void * e)525f64d3c3cShenning kw_cmp(const void *k, const void *e)
526f64d3c3cShenning {
527f64d3c3cShenning return (strcmp(k, ((const struct keywords *)e)->k_name));
528f64d3c3cShenning }
529f64d3c3cShenning
530f64d3c3cShenning int
lookup(char * s)531f64d3c3cShenning lookup(char *s)
532f64d3c3cShenning {
533f64d3c3cShenning /* this has to be sorted always */
534f64d3c3cShenning static const struct keywords keywords[] = {
535bc58a738Sreyk { "constraint", CONSTRAINT},
536bc58a738Sreyk { "constraints", CONSTRAINTS},
537c8ddfef5Sckuethe { "correction", CORRECTION},
538bc58a738Sreyk { "from", FROM},
539f64d3c3cShenning { "listen", LISTEN},
5409096d664Shenning { "on", ON},
5413e0a6a28Sbenno { "query", QUERY},
542c45e6fdaSckuethe { "refid", REFID},
54302d74365Sphessler { "rtable", RTABLE},
544009f3548Shenning { "sensor", SENSOR},
5453801c0acShenning { "server", SERVER},
54649532891Shenning { "servers", SERVERS},
5477d8d1c3fSpatrick { "stratum", STRATUM},
548eb7f225fSotto { "trusted", TRUSTED},
54949532891Shenning { "weight", WEIGHT}
550f64d3c3cShenning };
551f64d3c3cShenning const struct keywords *p;
552f64d3c3cShenning
553f64d3c3cShenning p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
554f64d3c3cShenning sizeof(keywords[0]), kw_cmp);
555f64d3c3cShenning
556361fcf82Shenning if (p)
557f64d3c3cShenning return (p->k_val);
558361fcf82Shenning else
559f64d3c3cShenning return (STRING);
560f64d3c3cShenning }
561f64d3c3cShenning
562f64d3c3cShenning #define MAXPUSHBACK 128
563f64d3c3cShenning
564*08f6ba19Snaddy char *parsebuf;
565f64d3c3cShenning int parseindex;
566*08f6ba19Snaddy char pushback_buffer[MAXPUSHBACK];
567f64d3c3cShenning int pushback_index = 0;
568f64d3c3cShenning
569f64d3c3cShenning int
lgetc(int quotec)57020741916Sderaadt lgetc(int quotec)
571f64d3c3cShenning {
572f64d3c3cShenning int c, next;
573f64d3c3cShenning
574f64d3c3cShenning if (parsebuf) {
575f64d3c3cShenning /* Read character from the parsebuffer instead of input. */
576f64d3c3cShenning if (parseindex >= 0) {
577*08f6ba19Snaddy c = (unsigned char)parsebuf[parseindex++];
578f64d3c3cShenning if (c != '\0')
579f64d3c3cShenning return (c);
580f64d3c3cShenning parsebuf = NULL;
581f64d3c3cShenning } else
582f64d3c3cShenning parseindex++;
583f64d3c3cShenning }
584f64d3c3cShenning
585f64d3c3cShenning if (pushback_index)
586*08f6ba19Snaddy return ((unsigned char)pushback_buffer[--pushback_index]);
587f64d3c3cShenning
58820741916Sderaadt if (quotec) {
58920741916Sderaadt if ((c = getc(file->stream)) == EOF) {
590c6004ab9Smpf yyerror("reached end of file while parsing "
591c6004ab9Smpf "quoted string");
592c6004ab9Smpf if (file == topfile || popfile() == EOF)
59320741916Sderaadt return (EOF);
59420741916Sderaadt return (quotec);
59520741916Sderaadt }
596d5d66eaeSderaadt return (c);
597d5d66eaeSderaadt }
598d5d66eaeSderaadt
59920741916Sderaadt while ((c = getc(file->stream)) == '\\') {
60020741916Sderaadt next = getc(file->stream);
601f64d3c3cShenning if (next != '\n') {
602e3bfd77aSderaadt c = next;
603f64d3c3cShenning break;
604f64d3c3cShenning }
60520741916Sderaadt yylval.lineno = file->lineno;
60620741916Sderaadt file->lineno++;
607f64d3c3cShenning }
608f64d3c3cShenning
60920741916Sderaadt while (c == EOF) {
610c6004ab9Smpf if (file == topfile || popfile() == EOF)
61120741916Sderaadt return (EOF);
61220741916Sderaadt c = getc(file->stream);
61320741916Sderaadt }
614f64d3c3cShenning return (c);
615f64d3c3cShenning }
616f64d3c3cShenning
617f64d3c3cShenning int
lungetc(int c)618f64d3c3cShenning lungetc(int c)
619f64d3c3cShenning {
620f64d3c3cShenning if (c == EOF)
621f64d3c3cShenning return (EOF);
622f64d3c3cShenning if (parsebuf) {
623f64d3c3cShenning parseindex--;
624f64d3c3cShenning if (parseindex >= 0)
625f64d3c3cShenning return (c);
626f64d3c3cShenning }
627*08f6ba19Snaddy if (pushback_index + 1 >= MAXPUSHBACK)
628f64d3c3cShenning return (EOF);
629*08f6ba19Snaddy pushback_buffer[pushback_index++] = c;
630*08f6ba19Snaddy return (c);
631f64d3c3cShenning }
632f64d3c3cShenning
633f64d3c3cShenning int
findeol(void)634f64d3c3cShenning findeol(void)
635f64d3c3cShenning {
636f64d3c3cShenning int c;
637f64d3c3cShenning
638f64d3c3cShenning parsebuf = NULL;
639f64d3c3cShenning
640f64d3c3cShenning /* skip to either EOF or the first real EOL */
641f64d3c3cShenning while (1) {
642e44efe63Shenning if (pushback_index)
643*08f6ba19Snaddy c = (unsigned char)pushback_buffer[--pushback_index];
644e44efe63Shenning else
645d5d66eaeSderaadt c = lgetc(0);
646f64d3c3cShenning if (c == '\n') {
64720741916Sderaadt file->lineno++;
648f64d3c3cShenning break;
649f64d3c3cShenning }
650f64d3c3cShenning if (c == EOF)
651f64d3c3cShenning break;
652f64d3c3cShenning }
653f64d3c3cShenning return (ERROR);
654f64d3c3cShenning }
655f64d3c3cShenning
656f64d3c3cShenning int
yylex(void)657f64d3c3cShenning yylex(void)
658f64d3c3cShenning {
659*08f6ba19Snaddy char buf[8096];
660*08f6ba19Snaddy char *p;
66120741916Sderaadt int quotec, next, c;
662f64d3c3cShenning int token;
663f64d3c3cShenning
664f64d3c3cShenning p = buf;
6652053f12aSmpf while ((c = lgetc(0)) == ' ' || c == '\t')
666f64d3c3cShenning ; /* nothing */
667f64d3c3cShenning
66820741916Sderaadt yylval.lineno = file->lineno;
669f64d3c3cShenning if (c == '#')
670d5d66eaeSderaadt while ((c = lgetc(0)) != '\n' && c != EOF)
671f64d3c3cShenning ; /* nothing */
672f64d3c3cShenning
673f64d3c3cShenning switch (c) {
674f64d3c3cShenning case '\'':
675f64d3c3cShenning case '"':
67620741916Sderaadt quotec = c;
677f64d3c3cShenning while (1) {
67820741916Sderaadt if ((c = lgetc(quotec)) == EOF)
679f64d3c3cShenning return (0);
680f64d3c3cShenning if (c == '\n') {
68120741916Sderaadt file->lineno++;
682f64d3c3cShenning continue;
683d5d66eaeSderaadt } else if (c == '\\') {
68420741916Sderaadt if ((next = lgetc(quotec)) == EOF)
685d5d66eaeSderaadt return (0);
686a1533359Ssashan if (next == quotec || next == ' ' ||
687a1533359Ssashan next == '\t')
688d5d66eaeSderaadt c = next;
689daf24110Shenning else if (next == '\n') {
690daf24110Shenning file->lineno++;
691ea014f46Sderaadt continue;
692daf24110Shenning } else
693d5d66eaeSderaadt lungetc(next);
69420741916Sderaadt } else if (c == quotec) {
695d5d66eaeSderaadt *p = '\0';
696d5d66eaeSderaadt break;
69741eef22fSjsg } else if (c == '\0') {
69841eef22fSjsg yyerror("syntax error");
69941eef22fSjsg return (findeol());
700f64d3c3cShenning }
701f64d3c3cShenning if (p + 1 >= buf + sizeof(buf) - 1) {
702f64d3c3cShenning yyerror("string too long");
703f64d3c3cShenning return (findeol());
704f64d3c3cShenning }
705015d7b4dSbenno *p++ = c;
706f64d3c3cShenning }
707f64d3c3cShenning yylval.v.string = strdup(buf);
708f64d3c3cShenning if (yylval.v.string == NULL)
709f64d3c3cShenning fatal("yylex: strdup");
710f64d3c3cShenning return (STRING);
711f64d3c3cShenning }
712f64d3c3cShenning
713c82b5dedSderaadt #define allowed_to_end_number(x) \
7140cf2c9c3Smpf (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
715c82b5dedSderaadt
716c82b5dedSderaadt if (c == '-' || isdigit(c)) {
717c82b5dedSderaadt do {
718c82b5dedSderaadt *p++ = c;
719915c3f33Sderaadt if ((size_t)(p-buf) >= sizeof(buf)) {
720c82b5dedSderaadt yyerror("string too long");
721c82b5dedSderaadt return (findeol());
722c82b5dedSderaadt }
723d5d66eaeSderaadt } while ((c = lgetc(0)) != EOF && isdigit(c));
724c82b5dedSderaadt lungetc(c);
725c82b5dedSderaadt if (p == buf + 1 && buf[0] == '-')
726c82b5dedSderaadt goto nodigits;
727c82b5dedSderaadt if (c == EOF || allowed_to_end_number(c)) {
728c82b5dedSderaadt const char *errstr = NULL;
729c82b5dedSderaadt
730c82b5dedSderaadt *p = '\0';
731c82b5dedSderaadt yylval.v.number = strtonum(buf, LLONG_MIN,
732c82b5dedSderaadt LLONG_MAX, &errstr);
733c82b5dedSderaadt if (errstr) {
734c82b5dedSderaadt yyerror("\"%s\" invalid number: %s",
735c82b5dedSderaadt buf, errstr);
736c82b5dedSderaadt return (findeol());
737c82b5dedSderaadt }
738c82b5dedSderaadt return (NUMBER);
739c82b5dedSderaadt } else {
740c82b5dedSderaadt nodigits:
741c82b5dedSderaadt while (p > buf + 1)
742*08f6ba19Snaddy lungetc((unsigned char)*--p);
743*08f6ba19Snaddy c = (unsigned char)*--p;
744c82b5dedSderaadt if (c == '-')
745c82b5dedSderaadt return (c);
746c82b5dedSderaadt }
747c82b5dedSderaadt }
748c82b5dedSderaadt
749f64d3c3cShenning #define allowed_in_string(x) \
750f64d3c3cShenning (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
751f64d3c3cShenning x != '{' && x != '}' && x != '<' && x != '>' && \
752f64d3c3cShenning x != '!' && x != '=' && x != '/' && x != '#' && \
753f64d3c3cShenning x != ','))
754f64d3c3cShenning
755f64d3c3cShenning if (isalnum(c) || c == ':' || c == '_' || c == '*') {
756f64d3c3cShenning do {
757f64d3c3cShenning *p++ = c;
758915c3f33Sderaadt if ((size_t)(p-buf) >= sizeof(buf)) {
759f64d3c3cShenning yyerror("string too long");
760f64d3c3cShenning return (findeol());
761f64d3c3cShenning }
762d5d66eaeSderaadt } while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
763f64d3c3cShenning lungetc(c);
764f64d3c3cShenning *p = '\0';
765f64d3c3cShenning if ((token = lookup(buf)) == STRING)
766f64d3c3cShenning if ((yylval.v.string = strdup(buf)) == NULL)
767f64d3c3cShenning fatal("yylex: strdup");
768f64d3c3cShenning return (token);
769f64d3c3cShenning }
770f64d3c3cShenning if (c == '\n') {
77120741916Sderaadt yylval.lineno = file->lineno;
77220741916Sderaadt file->lineno++;
773f64d3c3cShenning }
774f64d3c3cShenning if (c == EOF)
775f64d3c3cShenning return (0);
776f64d3c3cShenning return (c);
777f64d3c3cShenning }
778f64d3c3cShenning
77920741916Sderaadt struct file *
pushfile(const char * name)78020741916Sderaadt pushfile(const char *name)
78120741916Sderaadt {
78220741916Sderaadt struct file *nfile;
78320741916Sderaadt
7847fc93de0Stobias if ((nfile = calloc(1, sizeof(struct file))) == NULL) {
7856a3d55f9Skrw log_warn("%s", __func__);
78620741916Sderaadt return (NULL);
787d82aea89Spyr }
7887fc93de0Stobias if ((nfile->name = strdup(name)) == NULL) {
7896a3d55f9Skrw log_warn("%s", __func__);
7907fc93de0Stobias free(nfile);
7917fc93de0Stobias return (NULL);
7927fc93de0Stobias }
79320741916Sderaadt if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
7946a3d55f9Skrw log_warn("%s: %s", __func__, nfile->name);
79520741916Sderaadt free(nfile->name);
79620741916Sderaadt free(nfile);
79720741916Sderaadt return (NULL);
79820741916Sderaadt }
79920741916Sderaadt nfile->lineno = 1;
80020741916Sderaadt TAILQ_INSERT_TAIL(&files, nfile, entry);
80120741916Sderaadt return (nfile);
80220741916Sderaadt }
80320741916Sderaadt
80420741916Sderaadt int
popfile(void)80520741916Sderaadt popfile(void)
80620741916Sderaadt {
80720741916Sderaadt struct file *prev;
80820741916Sderaadt
809c6004ab9Smpf if ((prev = TAILQ_PREV(file, files, entry)) != NULL)
81020741916Sderaadt prev->errors += file->errors;
811c6004ab9Smpf
81220741916Sderaadt TAILQ_REMOVE(&files, file, entry);
81320741916Sderaadt fclose(file->stream);
81420741916Sderaadt free(file->name);
81520741916Sderaadt free(file);
81620741916Sderaadt file = prev;
817c6004ab9Smpf return (file ? 0 : EOF);
81820741916Sderaadt }
81920741916Sderaadt
820f64d3c3cShenning int
parse_config(const char * filename,struct ntpd_conf * xconf)8212db3fbc0Shenning parse_config(const char *filename, struct ntpd_conf *xconf)
822f64d3c3cShenning {
82320741916Sderaadt int errors = 0;
82420741916Sderaadt
8257be04f00Shenning conf = xconf;
826f64d3c3cShenning TAILQ_INIT(&conf->listen_addrs);
8279096d664Shenning TAILQ_INIT(&conf->ntp_peers);
828009f3548Shenning TAILQ_INIT(&conf->ntp_conf_sensors);
829bc58a738Sreyk TAILQ_INIT(&conf->constraints);
830f64d3c3cShenning
83120741916Sderaadt if ((file = pushfile(filename)) == NULL) {
832f64d3c3cShenning return (-1);
833f64d3c3cShenning }
834c6004ab9Smpf topfile = file;
835f64d3c3cShenning
836f64d3c3cShenning yyparse();
83720741916Sderaadt errors = file->errors;
83820741916Sderaadt popfile();
839f64d3c3cShenning
840f64d3c3cShenning return (errors ? -1 : 0);
841f64d3c3cShenning }
842