xref: /openbsd-src/usr.sbin/ntpd/parse.y (revision 08f6ba1906d01c4a24fa700d568400f71bcf9611)
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