1*292805c1Sflorian /* $OpenBSD: parse.y,v 1.9 2024/06/06 06:26:14 florian Exp $ */
2ad7c548dSflorian
3ad7c548dSflorian /*
4ad7c548dSflorian * Copyright (c) 2018, 2024 Florian Obser <florian@openbsd.org>
5ad7c548dSflorian * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
6ad7c548dSflorian * Copyright (c) 2004 Ryan McBride <mcbride@openbsd.org>
7ad7c548dSflorian * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
8ad7c548dSflorian * Copyright (c) 2001 Markus Friedl. All rights reserved.
9ad7c548dSflorian * Copyright (c) 2001 Daniel Hartmeier. All rights reserved.
10ad7c548dSflorian * Copyright (c) 2001 Theo de Raadt. All rights reserved.
11ad7c548dSflorian *
12ad7c548dSflorian * Permission to use, copy, modify, and distribute this software for any
13ad7c548dSflorian * purpose with or without fee is hereby granted, provided that the above
14ad7c548dSflorian * copyright notice and this permission notice appear in all copies.
15ad7c548dSflorian *
16ad7c548dSflorian * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
17ad7c548dSflorian * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
18ad7c548dSflorian * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
19ad7c548dSflorian * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20ad7c548dSflorian * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
21ad7c548dSflorian * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
22ad7c548dSflorian * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23ad7c548dSflorian */
24ad7c548dSflorian
25ad7c548dSflorian %{
26ad7c548dSflorian #include <sys/types.h>
27ad7c548dSflorian #include <sys/queue.h>
28ad7c548dSflorian #include <sys/socket.h>
29ad7c548dSflorian #include <sys/stat.h>
30ad7c548dSflorian
31ad7c548dSflorian #include <net/if.h>
32ad7c548dSflorian
33ad7c548dSflorian #include <netinet/in.h>
34ad7c548dSflorian
35ad7c548dSflorian #include <arpa/inet.h>
36ad7c548dSflorian
37ad7c548dSflorian #include <ctype.h>
38ad7c548dSflorian #include <err.h>
39ad7c548dSflorian #include <errno.h>
40ad7c548dSflorian #include <event.h>
41ad7c548dSflorian #include <imsg.h>
42ad7c548dSflorian #include <limits.h>
43ad7c548dSflorian #include <stdarg.h>
44ad7c548dSflorian #include <stdio.h>
45ad7c548dSflorian #include <string.h>
46ad7c548dSflorian #include <syslog.h>
47ad7c548dSflorian #include <unistd.h>
48ad7c548dSflorian #include <vis.h>
49ad7c548dSflorian
50ad7c548dSflorian #include "log.h"
51ad7c548dSflorian #include "dhcp6leased.h"
52ad7c548dSflorian #include "frontend.h"
53ad7c548dSflorian
54ad7c548dSflorian TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files);
55763cddbdSflorian struct file *file, *topfile;
56ad7c548dSflorian int check_file_secrecy(int, const char *);
57ad7c548dSflorian int yyparse(void);
58ad7c548dSflorian int yylex(void);
59ad7c548dSflorian int yyerror(const char *, ...)
60ad7c548dSflorian __attribute__((__format__ (printf, 1, 2)))
61ad7c548dSflorian __attribute__((__nonnull__ (1)));
62ad7c548dSflorian int lookup(char *);
63ad7c548dSflorian int igetc(void);
64ad7c548dSflorian
65ad7c548dSflorian TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead);
66ad7c548dSflorian struct sym {
67ad7c548dSflorian TAILQ_ENTRY(sym) entry;
68ad7c548dSflorian int used;
69ad7c548dSflorian int persist;
70ad7c548dSflorian char *nam;
71ad7c548dSflorian char *val;
72ad7c548dSflorian };
73ad7c548dSflorian
74ad7c548dSflorian int symset(const char *, const char *, int);
75ad7c548dSflorian char *symget(const char *);
76ad7c548dSflorian
77ad7c548dSflorian static struct dhcp6leased_conf *conf;
78ad7c548dSflorian static int errors;
79ad7c548dSflorian
80ad7c548dSflorian static struct iface_conf *iface_conf;
81ad7c548dSflorian static struct iface_ia_conf *iface_ia_conf;
82ad7c548dSflorian
83ad7c548dSflorian struct iface_conf *conf_get_iface(char *);
84ad7c548dSflorian struct iface_pd_conf *conf_get_pd_iface(char *, int);
85ad7c548dSflorian void addressing_plan(struct iface_ia_conf *);
86ad7c548dSflorian int fls64(uint64_t);
87ad7c548dSflorian
88ad7c548dSflorian typedef struct {
89ad7c548dSflorian union {
90ad7c548dSflorian int64_t number;
91ad7c548dSflorian char *string;
92ad7c548dSflorian } v;
93ad7c548dSflorian int lineno;
94ad7c548dSflorian } YYSTYPE;
95ad7c548dSflorian
96ad7c548dSflorian %}
97ad7c548dSflorian
983ae4b9dfSflorian %token ERROR DELEGATION FOR ON PREFIX REQUEST RAPID COMMIT
99ad7c548dSflorian
100ad7c548dSflorian %token <v.string> STRING
101ad7c548dSflorian %token <v.number> NUMBER
102ad7c548dSflorian %type <v.string> string
103ad7c548dSflorian
104ad7c548dSflorian %%
105ad7c548dSflorian
106ad7c548dSflorian grammar : /* empty */
107ad7c548dSflorian | grammar '\n'
108ad7c548dSflorian | grammar varset '\n'
1093ae4b9dfSflorian | grammar conf_main '\n'
110ad7c548dSflorian | grammar ia_pd '\n'
111ad7c548dSflorian | grammar error '\n' { file->errors++; }
112ad7c548dSflorian ;
113ad7c548dSflorian
114ad7c548dSflorian string : string STRING {
115ad7c548dSflorian if (asprintf(&$$, "%s %s", $1, $2) == -1) {
116ad7c548dSflorian free($1);
117ad7c548dSflorian free($2);
118ad7c548dSflorian yyerror("string: asprintf");
119ad7c548dSflorian YYERROR;
120ad7c548dSflorian }
121ad7c548dSflorian free($1);
122ad7c548dSflorian free($2);
123ad7c548dSflorian }
124ad7c548dSflorian | STRING
125ad7c548dSflorian ;
126ad7c548dSflorian
127ad7c548dSflorian varset : STRING '=' string {
128ad7c548dSflorian char *s = $1;
129ad7c548dSflorian if (log_getverbose() == 1)
130ad7c548dSflorian printf("%s = \"%s\"\n", $1, $3);
131ad7c548dSflorian while (*s++) {
132ad7c548dSflorian if (isspace((unsigned char)*s)) {
133ad7c548dSflorian yyerror("macro name cannot contain "
134ad7c548dSflorian "whitespace");
135ad7c548dSflorian free($1);
136ad7c548dSflorian free($3);
137ad7c548dSflorian YYERROR;
138ad7c548dSflorian }
139ad7c548dSflorian }
140ad7c548dSflorian if (symset($1, $3, 0) == -1)
141ad7c548dSflorian fatal("cannot store variable");
142ad7c548dSflorian free($1);
143ad7c548dSflorian free($3);
144ad7c548dSflorian }
145ad7c548dSflorian ;
146ad7c548dSflorian
147ad7c548dSflorian optnl : '\n' optnl /* zero or more newlines */
148ad7c548dSflorian | /*empty*/
149ad7c548dSflorian ;
150ad7c548dSflorian
151ad7c548dSflorian nl : '\n' optnl /* one or more newlines */
152ad7c548dSflorian ;
1533ae4b9dfSflorian conf_main : REQUEST RAPID COMMIT {
1543ae4b9dfSflorian conf->rapid_commit = 1;
1553ae4b9dfSflorian }
1563ae4b9dfSflorian ;
157ad7c548dSflorian
158ad7c548dSflorian ia_pd : REQUEST PREFIX DELEGATION ON STRING FOR {
159ad7c548dSflorian iface_conf = conf_get_iface($5);
160ad7c548dSflorian iface_ia_conf = calloc(1, sizeof(*iface_ia_conf));
161ad7c548dSflorian if (iface_ia_conf == NULL)
162ad7c548dSflorian err(1, "%s: calloc", __func__);
16392119d76Sflorian iface_ia_conf->id = iface_conf->ia_count++;
16492119d76Sflorian if (iface_conf->ia_count > MAX_IA) {
165ad7c548dSflorian yyerror("Too many prefix delegation requests");
166ad7c548dSflorian YYERROR;
167ad7c548dSflorian }
168ad7c548dSflorian SIMPLEQ_INIT(&iface_ia_conf->iface_pd_list);
169ad7c548dSflorian SIMPLEQ_INSERT_TAIL(&iface_conf->iface_ia_list,
170ad7c548dSflorian iface_ia_conf, entry);
171*292805c1Sflorian } iface_block {
172ad7c548dSflorian iface_conf = NULL;
173ad7c548dSflorian iface_ia_conf = NULL;
174ad7c548dSflorian }
175ad7c548dSflorian ;
176ad7c548dSflorian
177*292805c1Sflorian iface_block : '{' optnl ifaceopts_l '}'
178*292805c1Sflorian | ifaceoptsl
179ad7c548dSflorian ;
180ad7c548dSflorian
181*292805c1Sflorian ifaceopts_l : ifaceopts_l ifaceoptsl optnl
182ad7c548dSflorian | ifaceoptsl optnl
183ad7c548dSflorian ;
184ad7c548dSflorian
185ad7c548dSflorian ifaceoptsl : STRING {
186ad7c548dSflorian struct iface_pd_conf *iface_pd_conf;
187ad7c548dSflorian int prefixlen;
188ad7c548dSflorian char *p;
189ad7c548dSflorian const char *errstr;
190ad7c548dSflorian
191ad7c548dSflorian p = strchr($1, '/');
192ad7c548dSflorian if (p != NULL) {
193ad7c548dSflorian *p++ = '\0';
194ad7c548dSflorian prefixlen = strtonum(p, 0, 128, &errstr);
195ad7c548dSflorian if (errstr != NULL) {
196ad7c548dSflorian yyerror("error parsing interface "
197ad7c548dSflorian "\"%s/%s\"", $1, p);
198ad7c548dSflorian free($1);
199ad7c548dSflorian YYERROR;
200ad7c548dSflorian }
201ad7c548dSflorian } else
202ad7c548dSflorian prefixlen = 64;
203ad7c548dSflorian if ((iface_pd_conf = conf_get_pd_iface($1, prefixlen))
204ad7c548dSflorian == NULL) {
205ad7c548dSflorian yyerror("duplicate interface %s", $1);
206ad7c548dSflorian free($1);
207ad7c548dSflorian YYERROR;
208ad7c548dSflorian }
209ad7c548dSflorian }
210ad7c548dSflorian ;
211ad7c548dSflorian %%
212ad7c548dSflorian
213ad7c548dSflorian struct keywords {
214ad7c548dSflorian const char *k_name;
215ad7c548dSflorian int k_val;
216ad7c548dSflorian };
217ad7c548dSflorian
218ad7c548dSflorian int
yyerror(const char * fmt,...)219ad7c548dSflorian yyerror(const char *fmt, ...)
220ad7c548dSflorian {
221ad7c548dSflorian va_list ap;
222ad7c548dSflorian char *msg;
223ad7c548dSflorian
224ad7c548dSflorian file->errors++;
225ad7c548dSflorian va_start(ap, fmt);
226ad7c548dSflorian if (vasprintf(&msg, fmt, ap) == -1)
227ad7c548dSflorian fatalx("yyerror vasprintf");
228ad7c548dSflorian va_end(ap);
229ad7c548dSflorian logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg);
230ad7c548dSflorian free(msg);
231ad7c548dSflorian return (0);
232ad7c548dSflorian }
233ad7c548dSflorian
234ad7c548dSflorian int
kw_cmp(const void * k,const void * e)235ad7c548dSflorian kw_cmp(const void *k, const void *e)
236ad7c548dSflorian {
237ad7c548dSflorian return (strcmp(k, ((const struct keywords *)e)->k_name));
238ad7c548dSflorian }
239ad7c548dSflorian
240ad7c548dSflorian int
lookup(char * s)241ad7c548dSflorian lookup(char *s)
242ad7c548dSflorian {
243ad7c548dSflorian /* This has to be sorted always. */
244ad7c548dSflorian static const struct keywords keywords[] = {
2453ae4b9dfSflorian {"commit", COMMIT},
246ad7c548dSflorian {"delegation", DELEGATION},
247ad7c548dSflorian {"for", FOR},
248ad7c548dSflorian {"on", ON},
249ad7c548dSflorian {"prefix", PREFIX},
2503ae4b9dfSflorian {"rapid", RAPID},
251ad7c548dSflorian {"request", REQUEST},
252ad7c548dSflorian };
253ad7c548dSflorian const struct keywords *p;
254ad7c548dSflorian
255ad7c548dSflorian p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
256ad7c548dSflorian sizeof(keywords[0]), kw_cmp);
257ad7c548dSflorian
258ad7c548dSflorian if (p)
259ad7c548dSflorian return (p->k_val);
260ad7c548dSflorian else
261ad7c548dSflorian return (STRING);
262ad7c548dSflorian }
263ad7c548dSflorian
264ad7c548dSflorian #define START_EXPAND 1
265ad7c548dSflorian #define DONE_EXPAND 2
266ad7c548dSflorian
267ad7c548dSflorian static int expanding;
268ad7c548dSflorian
269ad7c548dSflorian int
igetc(void)270ad7c548dSflorian igetc(void)
271ad7c548dSflorian {
272ad7c548dSflorian int c;
273ad7c548dSflorian
274ad7c548dSflorian while (1) {
275ad7c548dSflorian if (file->ungetpos > 0)
276ad7c548dSflorian c = file->ungetbuf[--file->ungetpos];
277ad7c548dSflorian else
278ad7c548dSflorian c = getc(file->stream);
279ad7c548dSflorian
280ad7c548dSflorian if (c == START_EXPAND)
281ad7c548dSflorian expanding = 1;
282ad7c548dSflorian else if (c == DONE_EXPAND)
283ad7c548dSflorian expanding = 0;
284ad7c548dSflorian else
285ad7c548dSflorian break;
286ad7c548dSflorian }
287ad7c548dSflorian return (c);
288ad7c548dSflorian }
289ad7c548dSflorian
290ad7c548dSflorian int
lgetc(int quotec)291ad7c548dSflorian lgetc(int quotec)
292ad7c548dSflorian {
293ad7c548dSflorian int c, next;
294ad7c548dSflorian
295ad7c548dSflorian if (quotec) {
296ad7c548dSflorian if ((c = igetc()) == EOF) {
297ad7c548dSflorian yyerror("reached end of file while parsing "
298ad7c548dSflorian "quoted string");
299ad7c548dSflorian if (file == topfile || popfile() == EOF)
300ad7c548dSflorian return (EOF);
301ad7c548dSflorian return (quotec);
302ad7c548dSflorian }
303ad7c548dSflorian return (c);
304ad7c548dSflorian }
305ad7c548dSflorian
306ad7c548dSflorian while ((c = igetc()) == '\\') {
307ad7c548dSflorian next = igetc();
308ad7c548dSflorian if (next != '\n') {
309ad7c548dSflorian c = next;
310ad7c548dSflorian break;
311ad7c548dSflorian }
312ad7c548dSflorian yylval.lineno = file->lineno;
313ad7c548dSflorian file->lineno++;
314ad7c548dSflorian }
315ad7c548dSflorian
316ad7c548dSflorian if (c == EOF) {
317ad7c548dSflorian /*
318ad7c548dSflorian * Fake EOL when hit EOF for the first time. This gets line
319ad7c548dSflorian * count right if last line in included file is syntactically
320ad7c548dSflorian * invalid and has no newline.
321ad7c548dSflorian */
322ad7c548dSflorian if (file->eof_reached == 0) {
323ad7c548dSflorian file->eof_reached = 1;
324ad7c548dSflorian return ('\n');
325ad7c548dSflorian }
326ad7c548dSflorian while (c == EOF) {
327ad7c548dSflorian if (file == topfile || popfile() == EOF)
328ad7c548dSflorian return (EOF);
329ad7c548dSflorian c = igetc();
330ad7c548dSflorian }
331ad7c548dSflorian }
332ad7c548dSflorian return (c);
333ad7c548dSflorian }
334ad7c548dSflorian
335ad7c548dSflorian void
lungetc(int c)336ad7c548dSflorian lungetc(int c)
337ad7c548dSflorian {
338ad7c548dSflorian if (c == EOF)
339ad7c548dSflorian return;
340ad7c548dSflorian
341ad7c548dSflorian if (file->ungetpos >= file->ungetsize) {
342ad7c548dSflorian void *p = reallocarray(file->ungetbuf, file->ungetsize, 2);
343ad7c548dSflorian if (p == NULL)
344ad7c548dSflorian err(1, "lungetc");
345ad7c548dSflorian file->ungetbuf = p;
346ad7c548dSflorian file->ungetsize *= 2;
347ad7c548dSflorian }
348ad7c548dSflorian file->ungetbuf[file->ungetpos++] = c;
349ad7c548dSflorian }
350ad7c548dSflorian
351ad7c548dSflorian int
findeol(void)352ad7c548dSflorian findeol(void)
353ad7c548dSflorian {
354ad7c548dSflorian int c;
355ad7c548dSflorian
356ad7c548dSflorian /* Skip to either EOF or the first real EOL. */
357ad7c548dSflorian while (1) {
358ad7c548dSflorian c = lgetc(0);
359ad7c548dSflorian if (c == '\n') {
360ad7c548dSflorian file->lineno++;
361ad7c548dSflorian break;
362ad7c548dSflorian }
363ad7c548dSflorian if (c == EOF)
364ad7c548dSflorian break;
365ad7c548dSflorian }
366ad7c548dSflorian return (ERROR);
367ad7c548dSflorian }
368ad7c548dSflorian
369ad7c548dSflorian int
yylex(void)370ad7c548dSflorian yylex(void)
371ad7c548dSflorian {
372ad7c548dSflorian char buf[8096];
373ad7c548dSflorian char *p, *val;
374ad7c548dSflorian int quotec, next, c;
375ad7c548dSflorian int token;
376ad7c548dSflorian
377ad7c548dSflorian top:
378ad7c548dSflorian p = buf;
379ad7c548dSflorian while ((c = lgetc(0)) == ' ' || c == '\t')
380ad7c548dSflorian ; /* nothing */
381ad7c548dSflorian
382ad7c548dSflorian yylval.lineno = file->lineno;
383ad7c548dSflorian if (c == '#')
384ad7c548dSflorian while ((c = lgetc(0)) != '\n' && c != EOF)
385ad7c548dSflorian ; /* nothing */
386ad7c548dSflorian if (c == '$' && !expanding) {
387ad7c548dSflorian while (1) {
388ad7c548dSflorian if ((c = lgetc(0)) == EOF)
389ad7c548dSflorian return (0);
390ad7c548dSflorian
391ad7c548dSflorian if (p + 1 >= buf + sizeof(buf) - 1) {
392ad7c548dSflorian yyerror("string too long");
393ad7c548dSflorian return (findeol());
394ad7c548dSflorian }
395ad7c548dSflorian if (isalnum(c) || c == '_') {
396ad7c548dSflorian *p++ = c;
397ad7c548dSflorian continue;
398ad7c548dSflorian }
399ad7c548dSflorian *p = '\0';
400ad7c548dSflorian lungetc(c);
401ad7c548dSflorian break;
402ad7c548dSflorian }
403ad7c548dSflorian val = symget(buf);
404ad7c548dSflorian if (val == NULL) {
405ad7c548dSflorian yyerror("macro '%s' not defined", buf);
406ad7c548dSflorian return (findeol());
407ad7c548dSflorian }
408ad7c548dSflorian p = val + strlen(val) - 1;
409ad7c548dSflorian lungetc(DONE_EXPAND);
410ad7c548dSflorian while (p >= val) {
411ad7c548dSflorian lungetc((unsigned char)*p);
412ad7c548dSflorian p--;
413ad7c548dSflorian }
414ad7c548dSflorian lungetc(START_EXPAND);
415ad7c548dSflorian goto top;
416ad7c548dSflorian }
417ad7c548dSflorian
418ad7c548dSflorian switch (c) {
419ad7c548dSflorian case '\'':
420ad7c548dSflorian case '"':
421ad7c548dSflorian quotec = c;
422ad7c548dSflorian while (1) {
423ad7c548dSflorian if ((c = lgetc(quotec)) == EOF)
424ad7c548dSflorian return (0);
425ad7c548dSflorian if (c == '\n') {
426ad7c548dSflorian file->lineno++;
427ad7c548dSflorian continue;
428ad7c548dSflorian } else if (c == '\\') {
429ad7c548dSflorian if ((next = lgetc(quotec)) == EOF)
430ad7c548dSflorian return (0);
431ad7c548dSflorian if (next == quotec || next == ' ' ||
432ad7c548dSflorian next == '\t')
433ad7c548dSflorian c = next;
434ad7c548dSflorian else if (next == '\n') {
435ad7c548dSflorian file->lineno++;
436ad7c548dSflorian continue;
437ad7c548dSflorian } else
438ad7c548dSflorian lungetc(next);
439ad7c548dSflorian } else if (c == quotec) {
440ad7c548dSflorian *p = '\0';
441ad7c548dSflorian break;
442ad7c548dSflorian } else if (c == '\0') {
443ad7c548dSflorian yyerror("syntax error");
444ad7c548dSflorian return (findeol());
445ad7c548dSflorian }
446ad7c548dSflorian if (p + 1 >= buf + sizeof(buf) - 1) {
447ad7c548dSflorian yyerror("string too long");
448ad7c548dSflorian return (findeol());
449ad7c548dSflorian }
450ad7c548dSflorian *p++ = c;
451ad7c548dSflorian }
452ad7c548dSflorian yylval.v.string = strdup(buf);
453ad7c548dSflorian if (yylval.v.string == NULL)
454ad7c548dSflorian err(1, "yylex: strdup");
455ad7c548dSflorian return (STRING);
456ad7c548dSflorian }
457ad7c548dSflorian
458ad7c548dSflorian #define allowed_to_end_number(x) \
459ad7c548dSflorian (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
460ad7c548dSflorian
461ad7c548dSflorian if (c == '-' || isdigit(c)) {
462ad7c548dSflorian do {
463ad7c548dSflorian *p++ = c;
464ad7c548dSflorian if ((size_t)(p-buf) >= sizeof(buf)) {
465ad7c548dSflorian yyerror("string too long");
466ad7c548dSflorian return (findeol());
467ad7c548dSflorian }
468ad7c548dSflorian } while ((c = lgetc(0)) != EOF && isdigit(c));
469ad7c548dSflorian lungetc(c);
470ad7c548dSflorian if (p == buf + 1 && buf[0] == '-')
471ad7c548dSflorian goto nodigits;
472ad7c548dSflorian if (c == EOF || allowed_to_end_number(c)) {
473ad7c548dSflorian const char *errstr = NULL;
474ad7c548dSflorian
475ad7c548dSflorian *p = '\0';
476ad7c548dSflorian yylval.v.number = strtonum(buf, LLONG_MIN,
477ad7c548dSflorian LLONG_MAX, &errstr);
478ad7c548dSflorian if (errstr) {
479ad7c548dSflorian yyerror("\"%s\" invalid number: %s",
480ad7c548dSflorian buf, errstr);
481ad7c548dSflorian return (findeol());
482ad7c548dSflorian }
483ad7c548dSflorian return (NUMBER);
484ad7c548dSflorian } else {
485ad7c548dSflorian nodigits:
486ad7c548dSflorian while (p > buf + 1)
487ad7c548dSflorian lungetc((unsigned char)*--p);
488ad7c548dSflorian c = (unsigned char)*--p;
489ad7c548dSflorian if (c == '-')
490ad7c548dSflorian return (c);
491ad7c548dSflorian }
492ad7c548dSflorian }
493ad7c548dSflorian
494ad7c548dSflorian #define allowed_in_string(x) \
495ad7c548dSflorian (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
496ad7c548dSflorian x != '{' && x != '}' && \
497ad7c548dSflorian x != '!' && x != '=' && x != '#' && \
498ad7c548dSflorian x != ','))
499ad7c548dSflorian
500ad7c548dSflorian if (isalnum(c) || c == ':' || c == '_') {
501ad7c548dSflorian do {
502ad7c548dSflorian *p++ = c;
503ad7c548dSflorian if ((size_t)(p-buf) >= sizeof(buf)) {
504ad7c548dSflorian yyerror("string too long");
505ad7c548dSflorian return (findeol());
506ad7c548dSflorian }
507ad7c548dSflorian } while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
508ad7c548dSflorian lungetc(c);
509ad7c548dSflorian *p = '\0';
510ad7c548dSflorian if ((token = lookup(buf)) == STRING)
511ad7c548dSflorian if ((yylval.v.string = strdup(buf)) == NULL)
512ad7c548dSflorian err(1, "yylex: strdup");
513ad7c548dSflorian return (token);
514ad7c548dSflorian }
515ad7c548dSflorian if (c == '\n') {
516ad7c548dSflorian yylval.lineno = file->lineno;
517ad7c548dSflorian file->lineno++;
518ad7c548dSflorian }
519ad7c548dSflorian if (c == EOF)
520ad7c548dSflorian return (0);
521ad7c548dSflorian return (c);
522ad7c548dSflorian }
523ad7c548dSflorian
524ad7c548dSflorian int
check_file_secrecy(int fd,const char * fname)525ad7c548dSflorian check_file_secrecy(int fd, const char *fname)
526ad7c548dSflorian {
527ad7c548dSflorian struct stat st;
528ad7c548dSflorian
529ad7c548dSflorian if (fstat(fd, &st)) {
530ad7c548dSflorian log_warn("cannot stat %s", fname);
531ad7c548dSflorian return (-1);
532ad7c548dSflorian }
533ad7c548dSflorian if (st.st_uid != 0 && st.st_uid != getuid()) {
534ad7c548dSflorian log_warnx("%s: owner not root or current user", fname);
535ad7c548dSflorian return (-1);
536ad7c548dSflorian }
537ad7c548dSflorian if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) {
538ad7c548dSflorian log_warnx("%s: group writable or world read/writable", fname);
539ad7c548dSflorian return (-1);
540ad7c548dSflorian }
541ad7c548dSflorian return (0);
542ad7c548dSflorian }
543ad7c548dSflorian
544ad7c548dSflorian struct file *
pushfile(const char * name,int secret)545ad7c548dSflorian pushfile(const char *name, int secret)
546ad7c548dSflorian {
547ad7c548dSflorian struct file *nfile;
548ad7c548dSflorian
549ad7c548dSflorian if ((nfile = calloc(1, sizeof(struct file))) == NULL) {
550ad7c548dSflorian log_warn("calloc");
551ad7c548dSflorian return (NULL);
552ad7c548dSflorian }
553ad7c548dSflorian if ((nfile->name = strdup(name)) == NULL) {
554ad7c548dSflorian log_warn("strdup");
555ad7c548dSflorian free(nfile);
556ad7c548dSflorian return (NULL);
557ad7c548dSflorian }
558ad7c548dSflorian if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
559ad7c548dSflorian free(nfile->name);
560ad7c548dSflorian free(nfile);
561ad7c548dSflorian return (NULL);
562ad7c548dSflorian } else if (secret &&
563ad7c548dSflorian check_file_secrecy(fileno(nfile->stream), nfile->name)) {
564ad7c548dSflorian fclose(nfile->stream);
565ad7c548dSflorian free(nfile->name);
566ad7c548dSflorian free(nfile);
567ad7c548dSflorian return (NULL);
568ad7c548dSflorian }
569ad7c548dSflorian nfile->lineno = TAILQ_EMPTY(&files) ? 1 : 0;
570ad7c548dSflorian nfile->ungetsize = 16;
571ad7c548dSflorian nfile->ungetbuf = malloc(nfile->ungetsize);
572ad7c548dSflorian if (nfile->ungetbuf == NULL) {
573ad7c548dSflorian log_warn("malloc");
574ad7c548dSflorian fclose(nfile->stream);
575ad7c548dSflorian free(nfile->name);
576ad7c548dSflorian free(nfile);
577ad7c548dSflorian return (NULL);
578ad7c548dSflorian }
579ad7c548dSflorian TAILQ_INSERT_TAIL(&files, nfile, entry);
580ad7c548dSflorian return (nfile);
581ad7c548dSflorian }
582ad7c548dSflorian
583ad7c548dSflorian int
popfile(void)584ad7c548dSflorian popfile(void)
585ad7c548dSflorian {
586ad7c548dSflorian struct file *prev;
587ad7c548dSflorian
588ad7c548dSflorian if ((prev = TAILQ_PREV(file, files, entry)) != NULL)
589ad7c548dSflorian prev->errors += file->errors;
590ad7c548dSflorian
591ad7c548dSflorian TAILQ_REMOVE(&files, file, entry);
592ad7c548dSflorian fclose(file->stream);
593ad7c548dSflorian free(file->name);
594ad7c548dSflorian free(file->ungetbuf);
595ad7c548dSflorian free(file);
596ad7c548dSflorian file = prev;
597ad7c548dSflorian return (file ? 0 : EOF);
598ad7c548dSflorian }
599ad7c548dSflorian
600ad7c548dSflorian struct dhcp6leased_conf *
parse_config(const char * filename)601ad7c548dSflorian parse_config(const char *filename)
602ad7c548dSflorian {
603ad7c548dSflorian struct sym *sym, *next;
604ad7c548dSflorian struct iface_conf *iface;
605ad7c548dSflorian struct iface_ia_conf *ia_conf;
606ad7c548dSflorian
607ad7c548dSflorian conf = config_new_empty();
608ad7c548dSflorian
609ad7c548dSflorian file = pushfile(filename, 0);
610ad7c548dSflorian if (file == NULL) {
611ad7c548dSflorian free(conf);
612ad7c548dSflorian return (NULL);
613ad7c548dSflorian }
614ad7c548dSflorian topfile = file;
615ad7c548dSflorian
616ad7c548dSflorian yyparse();
617ad7c548dSflorian errors = file->errors;
618ad7c548dSflorian popfile();
619ad7c548dSflorian
620ad7c548dSflorian /* Free macros and check which have not been used. */
621ad7c548dSflorian TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) {
622ad7c548dSflorian if ((log_getverbose() == 2) && !sym->used)
623ad7c548dSflorian fprintf(stderr, "warning: macro '%s' not used\n",
624ad7c548dSflorian sym->nam);
625ad7c548dSflorian if (!sym->persist) {
626ad7c548dSflorian free(sym->nam);
627ad7c548dSflorian free(sym->val);
628ad7c548dSflorian TAILQ_REMOVE(&symhead, sym, entry);
629ad7c548dSflorian free(sym);
630ad7c548dSflorian }
631ad7c548dSflorian }
632ad7c548dSflorian
633ad7c548dSflorian if (errors) {
634ad7c548dSflorian config_clear(conf);
635ad7c548dSflorian return (NULL);
636ad7c548dSflorian }
637ad7c548dSflorian
638ad7c548dSflorian SIMPLEQ_FOREACH(iface, &conf->iface_list, entry) {
639ad7c548dSflorian SIMPLEQ_FOREACH(ia_conf, &iface->iface_ia_list, entry) {
640ad7c548dSflorian addressing_plan(ia_conf);
641ad7c548dSflorian }
642ad7c548dSflorian }
643ad7c548dSflorian return (conf);
644ad7c548dSflorian }
645ad7c548dSflorian
646ad7c548dSflorian int
symset(const char * nam,const char * val,int persist)647ad7c548dSflorian symset(const char *nam, const char *val, int persist)
648ad7c548dSflorian {
649ad7c548dSflorian struct sym *sym;
650ad7c548dSflorian
651ad7c548dSflorian TAILQ_FOREACH(sym, &symhead, entry) {
652ad7c548dSflorian if (strcmp(nam, sym->nam) == 0)
653ad7c548dSflorian break;
654ad7c548dSflorian }
655ad7c548dSflorian
656ad7c548dSflorian if (sym != NULL) {
657ad7c548dSflorian if (sym->persist == 1)
658ad7c548dSflorian return (0);
659ad7c548dSflorian else {
660ad7c548dSflorian free(sym->nam);
661ad7c548dSflorian free(sym->val);
662ad7c548dSflorian TAILQ_REMOVE(&symhead, sym, entry);
663ad7c548dSflorian free(sym);
664ad7c548dSflorian }
665ad7c548dSflorian }
666ad7c548dSflorian if ((sym = calloc(1, sizeof(*sym))) == NULL)
667ad7c548dSflorian return (-1);
668ad7c548dSflorian
669ad7c548dSflorian sym->nam = strdup(nam);
670ad7c548dSflorian if (sym->nam == NULL) {
671ad7c548dSflorian free(sym);
672ad7c548dSflorian return (-1);
673ad7c548dSflorian }
674ad7c548dSflorian sym->val = strdup(val);
675ad7c548dSflorian if (sym->val == NULL) {
676ad7c548dSflorian free(sym->nam);
677ad7c548dSflorian free(sym);
678ad7c548dSflorian return (-1);
679ad7c548dSflorian }
680ad7c548dSflorian sym->used = 0;
681ad7c548dSflorian sym->persist = persist;
682ad7c548dSflorian TAILQ_INSERT_TAIL(&symhead, sym, entry);
683ad7c548dSflorian return (0);
684ad7c548dSflorian }
685ad7c548dSflorian
686ad7c548dSflorian char *
symget(const char * nam)687ad7c548dSflorian symget(const char *nam)
688ad7c548dSflorian {
689ad7c548dSflorian struct sym *sym;
690ad7c548dSflorian
691ad7c548dSflorian TAILQ_FOREACH(sym, &symhead, entry) {
692ad7c548dSflorian if (strcmp(nam, sym->nam) == 0) {
693ad7c548dSflorian sym->used = 1;
694ad7c548dSflorian return (sym->val);
695ad7c548dSflorian }
696ad7c548dSflorian }
697ad7c548dSflorian return (NULL);
698ad7c548dSflorian }
699ad7c548dSflorian
700ad7c548dSflorian struct iface_conf *
conf_get_iface(char * name)701ad7c548dSflorian conf_get_iface(char *name)
702ad7c548dSflorian {
703ad7c548dSflorian struct iface_conf *iface;
704ad7c548dSflorian size_t n;
705ad7c548dSflorian
706ad7c548dSflorian SIMPLEQ_FOREACH(iface, &conf->iface_list, entry) {
707ad7c548dSflorian if (strcmp(name, iface->name) == 0)
708ad7c548dSflorian return (iface);
709ad7c548dSflorian }
710ad7c548dSflorian
711ad7c548dSflorian iface = calloc(1, sizeof(*iface));
712ad7c548dSflorian if (iface == NULL)
713ad7c548dSflorian errx(1, "%s: calloc", __func__);
714ad7c548dSflorian n = strlcpy(iface->name, name, sizeof(iface->name));
715ad7c548dSflorian if (n >= sizeof(iface->name))
716ad7c548dSflorian errx(1, "%s: name too long", __func__);
717ad7c548dSflorian SIMPLEQ_INIT(&iface->iface_ia_list);
718ad7c548dSflorian
719ad7c548dSflorian SIMPLEQ_INSERT_TAIL(&conf->iface_list, iface, entry);
720ad7c548dSflorian
721ad7c548dSflorian return (iface);
722ad7c548dSflorian }
723ad7c548dSflorian
724ad7c548dSflorian struct iface_pd_conf *
conf_get_pd_iface(char * name,int prefixlen)725ad7c548dSflorian conf_get_pd_iface(char *name, int prefixlen)
726ad7c548dSflorian {
727ad7c548dSflorian struct iface_ia_conf *iface_ia;
728ad7c548dSflorian struct iface_pd_conf *iface_pd;
729ad7c548dSflorian size_t n;
730ad7c548dSflorian
731ad7c548dSflorian if (strcmp(name, "reserve") != 0) {
732ad7c548dSflorian SIMPLEQ_FOREACH(iface_ia, &iface_conf->iface_ia_list,
733ad7c548dSflorian entry) {
734ad7c548dSflorian SIMPLEQ_FOREACH(iface_pd, &iface_ia->iface_pd_list,
735ad7c548dSflorian entry) {
736ad7c548dSflorian if (strcmp(name, iface_pd->name) == 0)
737ad7c548dSflorian return NULL;
738ad7c548dSflorian }
739ad7c548dSflorian }
740ad7c548dSflorian }
741ad7c548dSflorian
742ad7c548dSflorian iface_pd = calloc(1, sizeof(*iface_pd));
743ad7c548dSflorian if (iface_pd == NULL)
744ad7c548dSflorian err(1, "%s: calloc", __func__);
745ad7c548dSflorian n = strlcpy(iface_pd->name, name, sizeof(iface_pd->name));
746ad7c548dSflorian if (n >= sizeof(iface_pd->name))
747ad7c548dSflorian errx(1, "%s: name too long", __func__);
748ad7c548dSflorian iface_pd->prefix_len = prefixlen;
749ad7c548dSflorian
750ad7c548dSflorian SIMPLEQ_INSERT_TAIL(&iface_ia_conf->iface_pd_list, iface_pd, entry);
751ad7c548dSflorian
752ad7c548dSflorian return (iface_pd);
753ad7c548dSflorian }
754ad7c548dSflorian
755ad7c548dSflorian static inline uint64_t
get_shift(int plen)756ad7c548dSflorian get_shift(int plen)
757ad7c548dSflorian {
758ad7c548dSflorian if (plen > 64)
759ad7c548dSflorian plen -= 64;
760ad7c548dSflorian
761ad7c548dSflorian return 1ULL << (64 - plen);
762ad7c548dSflorian }
763ad7c548dSflorian
764ad7c548dSflorian void
addressing_plan(struct iface_ia_conf * ia_conf)765ad7c548dSflorian addressing_plan(struct iface_ia_conf *ia_conf)
766ad7c548dSflorian {
767ad7c548dSflorian struct iface_pd_conf *pd_conf;
768ad7c548dSflorian uint64_t *p, lo_counter, hi_counter, lo_shift, hi_shift;
769be6176a9Sflorian int prev_plen = -1;
770ad7c548dSflorian
771ad7c548dSflorian lo_counter = hi_counter = 0;
772ad7c548dSflorian
773ad7c548dSflorian SIMPLEQ_FOREACH(pd_conf, &ia_conf->iface_pd_list, entry) {
774ad7c548dSflorian /* not the first prefix */
775ad7c548dSflorian if (ia_conf->prefix_len != 0) {
776ad7c548dSflorian lo_shift = hi_shift = 0;
777ad7c548dSflorian if (prev_plen > pd_conf->prefix_len) {
778ad7c548dSflorian if (pd_conf->prefix_len > 64)
779ad7c548dSflorian lo_shift =
780ad7c548dSflorian get_shift(pd_conf->prefix_len);
781ad7c548dSflorian else
782ad7c548dSflorian hi_shift =
783ad7c548dSflorian get_shift(pd_conf->prefix_len);
784ad7c548dSflorian } else {
785ad7c548dSflorian if (prev_plen > 64)
786ad7c548dSflorian lo_shift = get_shift(prev_plen);
787ad7c548dSflorian else
788ad7c548dSflorian hi_shift = get_shift(prev_plen);
789ad7c548dSflorian }
790ad7c548dSflorian
791ad7c548dSflorian if (lo_shift != 0) {
792ad7c548dSflorian if (lo_counter > UINT64_MAX - lo_shift) {
793ad7c548dSflorian /* overflow */
794ad7c548dSflorian hi_counter++;
795ad7c548dSflorian lo_counter = 0;
796ad7c548dSflorian } else {
797ad7c548dSflorian lo_counter += lo_shift;
798ad7c548dSflorian /* remove all lower bits */
799ad7c548dSflorian lo_counter &= ~(lo_shift - 1);
800ad7c548dSflorian }
801ad7c548dSflorian } else {
802ad7c548dSflorian hi_counter += hi_shift;
803ad7c548dSflorian /* remove all lower bits */
804ad7c548dSflorian hi_counter &= ~(hi_shift - 1);
805ad7c548dSflorian lo_counter = 0;
806ad7c548dSflorian }
807ad7c548dSflorian
808ad7c548dSflorian } else
809ad7c548dSflorian ia_conf->prefix_len = pd_conf->prefix_len;
810ad7c548dSflorian
811ad7c548dSflorian p = (uint64_t *)&pd_conf->prefix_mask.s6_addr;
812ad7c548dSflorian *p |= htobe64(hi_counter);
813ad7c548dSflorian
814ad7c548dSflorian p = (uint64_t *)&pd_conf->prefix_mask.s6_addr[8];
815ad7c548dSflorian *p |= htobe64(lo_counter);
816ad7c548dSflorian
817ad7c548dSflorian prev_plen = pd_conf->prefix_len;
818ad7c548dSflorian }
819ad7c548dSflorian
820ad7c548dSflorian if (hi_counter != 0)
821ad7c548dSflorian ia_conf->prefix_len = 64 - fls64(hi_counter);
822ad7c548dSflorian else if (lo_counter != 0)
823ad7c548dSflorian ia_conf->prefix_len = 128 - fls64(lo_counter);
824ad7c548dSflorian }
825ad7c548dSflorian
826ad7c548dSflorian /* from NetBSD's sys/sys/bitops.h */
827ad7c548dSflorian /*-
828ad7c548dSflorian * Copyright (c) 2007, 2010 The NetBSD Foundation, Inc.
829ad7c548dSflorian * All rights reserved.
830ad7c548dSflorian *
831ad7c548dSflorian * This code is derived from software contributed to The NetBSD Foundation
832ad7c548dSflorian * by Christos Zoulas and Joerg Sonnenberger.
833ad7c548dSflorian *
834ad7c548dSflorian * Redistribution and use in source and binary forms, with or without
835ad7c548dSflorian * modification, are permitted provided that the following conditions
836ad7c548dSflorian * are met:
837ad7c548dSflorian * 1. Redistributions of source code must retain the above copyright
838ad7c548dSflorian * notice, this list of conditions and the following disclaimer.
839ad7c548dSflorian * 2. Redistributions in binary form must reproduce the above copyright
840ad7c548dSflorian * notice, this list of conditions and the following disclaimer in the
841ad7c548dSflorian * documentation and/or other materials provided with the distribution.
842ad7c548dSflorian *
843ad7c548dSflorian * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
844ad7c548dSflorian * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
845ad7c548dSflorian * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
846ad7c548dSflorian * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
847ad7c548dSflorian * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
848ad7c548dSflorian * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
849ad7c548dSflorian * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
850ad7c548dSflorian * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
851ad7c548dSflorian * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
852ad7c548dSflorian * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
853ad7c548dSflorian * POSSIBILITY OF SUCH DAMAGE.
854ad7c548dSflorian */
855ad7c548dSflorian int
fls64(uint64_t _n)856ad7c548dSflorian fls64(uint64_t _n)
857ad7c548dSflorian {
858ad7c548dSflorian int _v;
859ad7c548dSflorian
860ad7c548dSflorian if (!_n)
861ad7c548dSflorian return 0;
862ad7c548dSflorian
863ad7c548dSflorian _v = 64;
864ad7c548dSflorian if ((_n & 0xFFFFFFFF00000000ULL) == 0) {
865ad7c548dSflorian _n <<= 32;
866ad7c548dSflorian _v -= 32;
867ad7c548dSflorian }
868ad7c548dSflorian if ((_n & 0xFFFF000000000000ULL) == 0) {
869ad7c548dSflorian _n <<= 16;
870ad7c548dSflorian _v -= 16;
871ad7c548dSflorian }
872ad7c548dSflorian if ((_n & 0xFF00000000000000ULL) == 0) {
873ad7c548dSflorian _n <<= 8;
874ad7c548dSflorian _v -= 8;
875ad7c548dSflorian }
876ad7c548dSflorian if ((_n & 0xF000000000000000ULL) == 0) {
877ad7c548dSflorian _n <<= 4;
878ad7c548dSflorian _v -= 4;
879ad7c548dSflorian }
880ad7c548dSflorian if ((_n & 0xC000000000000000ULL) == 0) {
881ad7c548dSflorian _n <<= 2;
882ad7c548dSflorian _v -= 2;
883ad7c548dSflorian }
884ad7c548dSflorian if ((_n & 0x8000000000000000ULL) == 0) {
885ad7c548dSflorian //_n <<= 1;
886ad7c548dSflorian _v -= 1;
887ad7c548dSflorian }
888ad7c548dSflorian return _v;
889ad7c548dSflorian }
890