1 /* $OpenBSD: parse.y,v 1.23 2024/05/17 06:50:14 florian Exp $ */
2
3 /*
4 * Copyright (c) 2018 Florian Obser <florian@openbsd.org>
5 * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
6 * Copyright (c) 2004 Ryan McBride <mcbride@openbsd.org>
7 * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
8 * Copyright (c) 2001 Markus Friedl. All rights reserved.
9 * Copyright (c) 2001 Daniel Hartmeier. All rights reserved.
10 * Copyright (c) 2001 Theo de Raadt. All rights reserved.
11 *
12 * Permission to use, copy, modify, and distribute this software for any
13 * purpose with or without fee is hereby granted, provided that the above
14 * copyright notice and this permission notice appear in all copies.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
17 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
19 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
21 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
22 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 */
24
25 %{
26 #include <sys/types.h>
27 #include <sys/queue.h>
28 #include <sys/socket.h>
29 #include <sys/stat.h>
30
31 #include <netinet/in.h>
32 #include <netinet/icmp6.h>
33 #include <net/if.h>
34
35 #include <arpa/inet.h>
36
37 #include <ctype.h>
38 #include <err.h>
39 #include <errno.h>
40 #include <event.h>
41 #include <imsg.h>
42 #include <limits.h>
43 #include <stdarg.h>
44 #include <stdio.h>
45 #include <string.h>
46 #include <syslog.h>
47 #include <unistd.h>
48
49 #include "log.h"
50 #include "rad.h"
51 #include "frontend.h"
52
53 TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files);
54 static struct file {
55 TAILQ_ENTRY(file) entry;
56 FILE *stream;
57 char *name;
58 size_t ungetpos;
59 size_t ungetsize;
60 u_char *ungetbuf;
61 int eof_reached;
62 int lineno;
63 int errors;
64 } *file, *topfile;
65 struct file *pushfile(const char *, int);
66 int popfile(void);
67 int check_file_secrecy(int, const char *);
68 int yyparse(void);
69 int yylex(void);
70 int yyerror(const char *, ...)
71 __attribute__((__format__ (printf, 1, 2)))
72 __attribute__((__nonnull__ (1)));
73 int kw_cmp(const void *, const void *);
74 int lookup(char *);
75 int igetc(void);
76 int lgetc(int);
77 void lungetc(int);
78 int findeol(void);
79
80 TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead);
81 struct sym {
82 TAILQ_ENTRY(sym) entry;
83 int used;
84 int persist;
85 char *nam;
86 char *val;
87 };
88
89 int symset(const char *, const char *, int);
90 char *symget(const char *);
91
92 void clear_config(struct rad_conf *xconf);
93
94 static struct rad_conf *conf;
95 static struct ra_options_conf *ra_options;
96 static int errors;
97
98 static struct ra_iface_conf *ra_iface_conf;
99 static struct ra_prefix_conf *ra_prefix_conf;
100 static struct ra_pref64_conf *ra_pref64_conf;
101
102 struct ra_prefix_conf *conf_get_ra_prefix(struct in6_addr*, int);
103 struct ra_pref64_conf *conf_get_ra_pref64(struct in6_addr*, int);
104 struct ra_iface_conf *conf_get_ra_iface(char *);
105 void copy_dns_options(const struct ra_options_conf *,
106 struct ra_options_conf *);
107 void copy_pref64_options(const struct ra_options_conf *,
108 struct ra_options_conf *);
109
110 typedef struct {
111 union {
112 int64_t number;
113 char *string;
114 } v;
115 int lineno;
116 } YYSTYPE;
117
118 %}
119
120 %token RA_IFACE YES NO INCLUDE ERROR
121 %token DEFAULT ROUTER HOP LIMIT MANAGED ADDRESS
122 %token CONFIGURATION OTHER LIFETIME REACHABLE TIME RETRANS TIMER
123 %token AUTO PREFIX VALID PREFERENCE PREFERRED LIFETIME ONLINK AUTONOMOUS
124 %token ADDRESS_CONFIGURATION DNS NAMESERVER SEARCH MTU NAT64 HIGH MEDIUM LOW
125 %token SOURCE LINK_LAYER
126
127 %token <v.string> STRING
128 %token <v.number> NUMBER
129 %type <v.number> yesno
130 %type <v.string> string
131
132 %%
133
134 grammar : /* empty */
135 | grammar include '\n'
136 | grammar '\n'
137 | grammar { ra_options = &conf->ra_options; } conf_main '\n'
138 | grammar varset '\n'
139 | grammar ra_iface '\n'
140 | grammar error '\n' { file->errors++; }
141 ;
142
143 include : INCLUDE STRING {
144 struct file *nfile;
145
146 if ((nfile = pushfile($2, 0)) == NULL) {
147 yyerror("failed to include file %s", $2);
148 free($2);
149 YYERROR;
150 }
151 free($2);
152
153 file = nfile;
154 lungetc('\n');
155 }
156 ;
157
158 string : string STRING {
159 if (asprintf(&$$, "%s %s", $1, $2) == -1) {
160 free($1);
161 free($2);
162 yyerror("string: asprintf");
163 YYERROR;
164 }
165 free($1);
166 free($2);
167 }
168 | STRING
169 ;
170
171 yesno : YES { $$ = 1; }
172 | NO { $$ = 0; }
173 ;
174
175 varset : STRING '=' string {
176 char *s = $1;
177 if (cmd_opts & OPT_VERBOSE)
178 printf("%s = \"%s\"\n", $1, $3);
179 while (*s++) {
180 if (isspace((unsigned char)*s)) {
181 yyerror("macro name cannot contain "
182 "whitespace");
183 free($1);
184 free($3);
185 YYERROR;
186 }
187 }
188 if (symset($1, $3, 0) == -1)
189 fatal("cannot store variable");
190 free($1);
191 free($3);
192 }
193 ;
194
195 conf_main : ra_opt_block {
196 ra_options = &conf->ra_options;
197 }
198 ;
199
200 ra_opt_block : DEFAULT ROUTER yesno {
201 ra_options->dfr = $3;
202 }
203 | HOP LIMIT NUMBER {
204 ra_options->cur_hl = $3;
205 }
206 | MANAGED ADDRESS CONFIGURATION yesno {
207 ra_options->m_flag = $4;
208 }
209 | OTHER CONFIGURATION yesno {
210 ra_options->o_flag = $3;
211 }
212 | ROUTER LIFETIME NUMBER {
213 ra_options->router_lifetime = $3;
214 }
215 | ROUTER PREFERENCE HIGH {
216 ra_options->rtpref = ND_RA_FLAG_RTPREF_HIGH;
217 }
218 | ROUTER PREFERENCE MEDIUM {
219 ra_options->rtpref = ND_RA_FLAG_RTPREF_MEDIUM;
220 }
221 | ROUTER PREFERENCE LOW {
222 ra_options->rtpref = ND_RA_FLAG_RTPREF_LOW;
223 }
224 | REACHABLE TIME NUMBER {
225 ra_options->reachable_time = $3;
226 }
227 | RETRANS TIMER NUMBER {
228 ra_options->retrans_timer = $3;
229 }
230 | SOURCE LINK_LAYER ADDRESS yesno {
231 ra_options->source_link_addr = $4;
232 }
233 | MTU NUMBER {
234 ra_options->mtu = $2;
235 }
236 | NAT64 PREFIX STRING {
237 struct in6_addr addr;
238 int prefixlen;
239 char *p;
240 const char *errstr;
241
242 memset(&addr, 0, sizeof(addr));
243 p = strchr($3, '/');
244 if (p != NULL) {
245 *p++ = '\0';
246 prefixlen = strtonum(p, 0, 128, &errstr);
247 if (errstr != NULL) {
248 yyerror("error parsing prefix "
249 "\"%s/%s\"", $3, p);
250 free($3);
251 YYERROR;
252 }
253 } else
254 prefixlen = 96;
255
256 switch (prefixlen) {
257 case 96:
258 case 64:
259 case 56:
260 case 48:
261 case 40:
262 case 32:
263 break;
264 default:
265 yyerror("invalid nat64 prefix length: %d",
266 prefixlen);
267 YYERROR;
268 break;
269 }
270 if(inet_pton(AF_INET6, $3, &addr) == 0) {
271 yyerror("error parsing prefix \"%s/%d\"", $3,
272 prefixlen);
273 free($3);
274 YYERROR;
275 }
276 mask_prefix(&addr, prefixlen);
277 ra_pref64_conf = conf_get_ra_pref64(&addr, prefixlen);
278 } ra_pref64_block {
279 ra_pref64_conf = NULL;
280 }
281 | DNS dns_block
282 ;
283
284 optnl : '\n' optnl /* zero or more newlines */
285 | /*empty*/
286 ;
287
288 nl : '\n' optnl /* one or more newlines */
289 ;
290
291 ra_iface : RA_IFACE STRING {
292 ra_iface_conf = conf_get_ra_iface($2);
293 /* set auto prefix defaults */
294 ra_iface_conf->autoprefix = conf_get_ra_prefix(NULL, 0);
295 ra_options = &ra_iface_conf->ra_options;
296 } ra_iface_block {
297 ra_iface_conf = NULL;
298 ra_options = &conf->ra_options;
299 }
300 ;
301
302 ra_iface_block : '{' optnl ra_ifaceopts_l '}'
303 | '{' optnl '}'
304 | /* empty */
305 ;
306
307 ra_ifaceopts_l : ra_ifaceopts_l ra_ifaceoptsl nl
308 | ra_ifaceoptsl optnl
309 ;
310
311 ra_ifaceoptsl : NO AUTO PREFIX {
312 free(ra_iface_conf->autoprefix);
313 ra_iface_conf->autoprefix = NULL;
314 }
315 | AUTO PREFIX {
316 if (ra_iface_conf->autoprefix == NULL)
317 ra_iface_conf->autoprefix =
318 conf_get_ra_prefix(NULL, 0);
319 ra_prefix_conf = ra_iface_conf->autoprefix;
320 } ra_prefix_block {
321 ra_prefix_conf = NULL;
322 }
323 | PREFIX STRING {
324 struct in6_addr addr;
325 int prefixlen;
326 char *p;
327 const char *errstr;
328
329 memset(&addr, 0, sizeof(addr));
330 p = strchr($2, '/');
331 if (p != NULL) {
332 *p++ = '\0';
333 prefixlen = strtonum(p, 0, 128, &errstr);
334 if (errstr != NULL) {
335 yyerror("error parsing prefix "
336 "\"%s/%s\"", $2, p);
337 free($2);
338 YYERROR;
339 }
340 } else
341 prefixlen = 64;
342 if(inet_pton(AF_INET6, $2, &addr) == 0) {
343 yyerror("error parsing prefix \"%s/%d\"", $2,
344 prefixlen);
345 free($2);
346 YYERROR;
347 }
348 mask_prefix(&addr, prefixlen);
349 ra_prefix_conf = conf_get_ra_prefix(&addr, prefixlen);
350 } ra_prefix_block {
351 ra_prefix_conf = NULL;
352 }
353 | ra_opt_block
354 ;
355
356 ra_prefix_block : '{' optnl ra_prefixopts_l '}'
357 | '{' optnl '}'
358 | /* empty */
359 ;
360
361 ra_prefixopts_l : ra_prefixopts_l ra_prefixoptsl nl
362 | ra_prefixoptsl optnl
363 ;
364
365 ra_prefixoptsl : VALID LIFETIME NUMBER {
366 ra_prefix_conf->vltime = $3;
367 }
368 | PREFERRED LIFETIME NUMBER {
369 ra_prefix_conf->pltime = $3;
370 }
371 | ONLINK yesno {
372 ra_prefix_conf->lflag = $2;
373 }
374 | AUTONOMOUS ADDRESS_CONFIGURATION yesno {
375 ra_prefix_conf->aflag = $3;
376 }
377 ;
378
379 ra_pref64_block : '{' optnl ra_pref64opts_l '}'
380 | '{' optnl '}'
381 | /* empty */
382 ;
383
384 ra_pref64opts_l : ra_pref64opts_l ra_pref64optsl nl
385 | ra_pref64optsl optnl
386 ;
387
388 ra_pref64optsl : LIFETIME NUMBER {
389 if ($2 < 0 || $2 > 65528) {
390 yyerror("Invalid nat64 prefix lifetime: %lld",
391 $2);
392 YYERROR;
393 }
394 ra_pref64_conf->ltime = $2;
395 }
396 ;
397
398 dns_block : '{' optnl dnsopts_l '}'
399 | '{' optnl '}'
400 | /* empty */
401 ;
402
403 dnsopts_l : dnsopts_l dnsoptsl nl
404 | dnsoptsl optnl
405 ;
406
407 dnsoptsl : LIFETIME NUMBER {
408 ra_options->rdns_lifetime = $2;
409 }
410 | NAMESERVER nserver_block
411 | SEARCH search_block
412 ;
413 nserver_block : '{' optnl nserveropts_l '}'
414 | '{' optnl '}'
415 | nserveroptsl
416 | /* empty */
417 ;
418
419 nserveropts_l : nserveropts_l nserveroptsl optnl
420 | nserveroptsl optnl
421 ;
422
423 nserveroptsl : STRING {
424 struct ra_rdnss_conf *ra_rdnss_conf;
425 struct in6_addr addr;
426
427 memset(&addr, 0, sizeof(addr));
428 if (inet_pton(AF_INET6, $1, &addr)
429 != 1) {
430 yyerror("error parsing nameserver address %s",
431 $1);
432 free($1);
433 YYERROR;
434 }
435 if ((ra_rdnss_conf = calloc(1, sizeof(*ra_rdnss_conf)))
436 == NULL)
437 err(1, "%s", __func__);
438 memcpy(&ra_rdnss_conf->rdnss, &addr, sizeof(addr));
439 SIMPLEQ_INSERT_TAIL(&ra_options->ra_rdnss_list,
440 ra_rdnss_conf, entry);
441 ra_options->rdnss_count++;
442 }
443 ;
444 search_block : '{' optnl searchopts_l '}'
445 | '{' optnl '}'
446 | searchoptsl
447 | /* empty */
448 ;
449
450 searchopts_l : searchopts_l searchoptsl optnl
451 | searchoptsl optnl
452 ;
453
454 searchoptsl : STRING {
455 struct ra_dnssl_conf *ra_dnssl_conf;
456 size_t len;
457
458 if ((ra_dnssl_conf = calloc(1,
459 sizeof(*ra_dnssl_conf))) == NULL)
460 err(1, "%s", __func__);
461
462 if ((len = strlcpy(ra_dnssl_conf->search, $1,
463 sizeof(ra_dnssl_conf->search))) >=
464 sizeof(ra_dnssl_conf->search)) {
465 yyerror("search string too long");
466 free($1);
467 YYERROR;
468 }
469 if (ra_dnssl_conf->search[len] != '.') {
470 if ((len = strlcat(ra_dnssl_conf->search, ".",
471 sizeof(ra_dnssl_conf->search))) >
472 sizeof(ra_dnssl_conf->search)) {
473 yyerror("search string too long");
474 free($1);
475 YYERROR;
476 }
477 }
478 SIMPLEQ_INSERT_TAIL(&ra_options->ra_dnssl_list,
479 ra_dnssl_conf, entry);
480 ra_options->dnssl_len += len + 1;
481 }
482 ;
483 %%
484
485 struct keywords {
486 const char *k_name;
487 int k_val;
488 };
489
490 int
yyerror(const char * fmt,...)491 yyerror(const char *fmt, ...)
492 {
493 va_list ap;
494 char *msg;
495
496 file->errors++;
497 va_start(ap, fmt);
498 if (vasprintf(&msg, fmt, ap) == -1)
499 fatalx("yyerror vasprintf");
500 va_end(ap);
501 logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg);
502 free(msg);
503 return (0);
504 }
505
506 int
kw_cmp(const void * k,const void * e)507 kw_cmp(const void *k, const void *e)
508 {
509 return (strcmp(k, ((const struct keywords *)e)->k_name));
510 }
511
512 int
lookup(char * s)513 lookup(char *s)
514 {
515 /* This has to be sorted always. */
516 static const struct keywords keywords[] = {
517 {"address", ADDRESS},
518 {"address-configuration", ADDRESS_CONFIGURATION},
519 {"auto", AUTO},
520 {"autonomous", AUTONOMOUS},
521 {"configuration", CONFIGURATION},
522 {"default", DEFAULT},
523 {"dns", DNS},
524 {"high", HIGH},
525 {"hop", HOP},
526 {"include", INCLUDE},
527 {"interface", RA_IFACE},
528 {"lifetime", LIFETIME},
529 {"limit", LIMIT},
530 {"link-layer", LINK_LAYER},
531 {"low", LOW},
532 {"managed", MANAGED},
533 {"medium", MEDIUM},
534 {"mtu", MTU},
535 {"nameserver", NAMESERVER},
536 {"nat64", NAT64},
537 {"no", NO},
538 {"on-link", ONLINK},
539 {"other", OTHER},
540 {"preference", PREFERENCE},
541 {"preferred", PREFERRED},
542 {"prefix", PREFIX},
543 {"reachable", REACHABLE},
544 {"retrans", RETRANS},
545 {"router", ROUTER},
546 {"search", SEARCH},
547 {"source", SOURCE},
548 {"time", TIME},
549 {"timer", TIMER},
550 {"valid", VALID},
551 {"yes", YES},
552 };
553 const struct keywords *p;
554
555 p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
556 sizeof(keywords[0]), kw_cmp);
557
558 if (p)
559 return (p->k_val);
560 else
561 return (STRING);
562 }
563
564 #define START_EXPAND 1
565 #define DONE_EXPAND 2
566
567 static int expanding;
568
569 int
igetc(void)570 igetc(void)
571 {
572 int c;
573
574 while (1) {
575 if (file->ungetpos > 0)
576 c = file->ungetbuf[--file->ungetpos];
577 else
578 c = getc(file->stream);
579
580 if (c == START_EXPAND)
581 expanding = 1;
582 else if (c == DONE_EXPAND)
583 expanding = 0;
584 else
585 break;
586 }
587 return (c);
588 }
589
590 int
lgetc(int quotec)591 lgetc(int quotec)
592 {
593 int c, next;
594
595 if (quotec) {
596 if ((c = igetc()) == EOF) {
597 yyerror("reached end of file while parsing "
598 "quoted string");
599 if (file == topfile || popfile() == EOF)
600 return (EOF);
601 return (quotec);
602 }
603 return (c);
604 }
605
606 while ((c = igetc()) == '\\') {
607 next = igetc();
608 if (next != '\n') {
609 c = next;
610 break;
611 }
612 yylval.lineno = file->lineno;
613 file->lineno++;
614 }
615
616 if (c == EOF) {
617 /*
618 * Fake EOL when hit EOF for the first time. This gets line
619 * count right if last line in included file is syntactically
620 * invalid and has no newline.
621 */
622 if (file->eof_reached == 0) {
623 file->eof_reached = 1;
624 return ('\n');
625 }
626 while (c == EOF) {
627 if (file == topfile || popfile() == EOF)
628 return (EOF);
629 c = igetc();
630 }
631 }
632 return (c);
633 }
634
635 void
lungetc(int c)636 lungetc(int c)
637 {
638 if (c == EOF)
639 return;
640
641 if (file->ungetpos >= file->ungetsize) {
642 void *p = reallocarray(file->ungetbuf, file->ungetsize, 2);
643 if (p == NULL)
644 err(1, "lungetc");
645 file->ungetbuf = p;
646 file->ungetsize *= 2;
647 }
648 file->ungetbuf[file->ungetpos++] = c;
649 }
650
651 int
findeol(void)652 findeol(void)
653 {
654 int c;
655
656 /* Skip to either EOF or the first real EOL. */
657 while (1) {
658 c = lgetc(0);
659 if (c == '\n') {
660 file->lineno++;
661 break;
662 }
663 if (c == EOF)
664 break;
665 }
666 return (ERROR);
667 }
668
669 int
yylex(void)670 yylex(void)
671 {
672 char buf[8096];
673 char *p, *val;
674 int quotec, next, c;
675 int token;
676
677 top:
678 p = buf;
679 while ((c = lgetc(0)) == ' ' || c == '\t')
680 ; /* nothing */
681
682 yylval.lineno = file->lineno;
683 if (c == '#')
684 while ((c = lgetc(0)) != '\n' && c != EOF)
685 ; /* nothing */
686 if (c == '$' && !expanding) {
687 while (1) {
688 if ((c = lgetc(0)) == EOF)
689 return (0);
690
691 if (p + 1 >= buf + sizeof(buf) - 1) {
692 yyerror("string too long");
693 return (findeol());
694 }
695 if (isalnum(c) || c == '_') {
696 *p++ = c;
697 continue;
698 }
699 *p = '\0';
700 lungetc(c);
701 break;
702 }
703 val = symget(buf);
704 if (val == NULL) {
705 yyerror("macro '%s' not defined", buf);
706 return (findeol());
707 }
708 p = val + strlen(val) - 1;
709 lungetc(DONE_EXPAND);
710 while (p >= val) {
711 lungetc((unsigned char)*p);
712 p--;
713 }
714 lungetc(START_EXPAND);
715 goto top;
716 }
717
718 switch (c) {
719 case '\'':
720 case '"':
721 quotec = c;
722 while (1) {
723 if ((c = lgetc(quotec)) == EOF)
724 return (0);
725 if (c == '\n') {
726 file->lineno++;
727 continue;
728 } else if (c == '\\') {
729 if ((next = lgetc(quotec)) == EOF)
730 return (0);
731 if (next == quotec || next == ' ' ||
732 next == '\t')
733 c = next;
734 else if (next == '\n') {
735 file->lineno++;
736 continue;
737 } else
738 lungetc(next);
739 } else if (c == quotec) {
740 *p = '\0';
741 break;
742 } else if (c == '\0') {
743 yyerror("syntax error");
744 return (findeol());
745 }
746 if (p + 1 >= buf + sizeof(buf) - 1) {
747 yyerror("string too long");
748 return (findeol());
749 }
750 *p++ = c;
751 }
752 yylval.v.string = strdup(buf);
753 if (yylval.v.string == NULL)
754 err(1, "yylex: strdup");
755 return (STRING);
756 }
757
758 #define allowed_to_end_number(x) \
759 (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
760
761 if (c == '-' || isdigit(c)) {
762 do {
763 *p++ = c;
764 if ((size_t)(p-buf) >= sizeof(buf)) {
765 yyerror("string too long");
766 return (findeol());
767 }
768 } while ((c = lgetc(0)) != EOF && isdigit(c));
769 lungetc(c);
770 if (p == buf + 1 && buf[0] == '-')
771 goto nodigits;
772 if (c == EOF || allowed_to_end_number(c)) {
773 const char *errstr = NULL;
774
775 *p = '\0';
776 yylval.v.number = strtonum(buf, LLONG_MIN,
777 LLONG_MAX, &errstr);
778 if (errstr) {
779 yyerror("\"%s\" invalid number: %s",
780 buf, errstr);
781 return (findeol());
782 }
783 return (NUMBER);
784 } else {
785 nodigits:
786 while (p > buf + 1)
787 lungetc((unsigned char)*--p);
788 c = (unsigned char)*--p;
789 if (c == '-')
790 return (c);
791 }
792 }
793
794 #define allowed_in_string(x) \
795 (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
796 x != '{' && x != '}' && \
797 x != '!' && x != '=' && x != '#' && \
798 x != ','))
799
800 if (isalnum(c) || c == ':' || c == '_') {
801 do {
802 *p++ = c;
803 if ((size_t)(p-buf) >= sizeof(buf)) {
804 yyerror("string too long");
805 return (findeol());
806 }
807 } while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
808 lungetc(c);
809 *p = '\0';
810 if ((token = lookup(buf)) == STRING)
811 if ((yylval.v.string = strdup(buf)) == NULL)
812 err(1, "yylex: strdup");
813 return (token);
814 }
815 if (c == '\n') {
816 yylval.lineno = file->lineno;
817 file->lineno++;
818 }
819 if (c == EOF)
820 return (0);
821 return (c);
822 }
823
824 int
check_file_secrecy(int fd,const char * fname)825 check_file_secrecy(int fd, const char *fname)
826 {
827 struct stat st;
828
829 if (fstat(fd, &st)) {
830 log_warn("cannot stat %s", fname);
831 return (-1);
832 }
833 if (st.st_uid != 0 && st.st_uid != getuid()) {
834 log_warnx("%s: owner not root or current user", fname);
835 return (-1);
836 }
837 if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) {
838 log_warnx("%s: group writable or world read/writable", fname);
839 return (-1);
840 }
841 return (0);
842 }
843
844 struct file *
pushfile(const char * name,int secret)845 pushfile(const char *name, int secret)
846 {
847 struct file *nfile;
848
849 if ((nfile = calloc(1, sizeof(struct file))) == NULL) {
850 log_warn("calloc");
851 return (NULL);
852 }
853 if ((nfile->name = strdup(name)) == NULL) {
854 log_warn("strdup");
855 free(nfile);
856 return (NULL);
857 }
858 if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
859 log_warn("%s", nfile->name);
860 free(nfile->name);
861 free(nfile);
862 return (NULL);
863 } else if (secret &&
864 check_file_secrecy(fileno(nfile->stream), nfile->name)) {
865 fclose(nfile->stream);
866 free(nfile->name);
867 free(nfile);
868 return (NULL);
869 }
870 nfile->lineno = TAILQ_EMPTY(&files) ? 1 : 0;
871 nfile->ungetsize = 16;
872 nfile->ungetbuf = malloc(nfile->ungetsize);
873 if (nfile->ungetbuf == NULL) {
874 log_warn("malloc");
875 fclose(nfile->stream);
876 free(nfile->name);
877 free(nfile);
878 return (NULL);
879 }
880 TAILQ_INSERT_TAIL(&files, nfile, entry);
881 return (nfile);
882 }
883
884 int
popfile(void)885 popfile(void)
886 {
887 struct file *prev;
888
889 if ((prev = TAILQ_PREV(file, files, entry)) != NULL)
890 prev->errors += file->errors;
891
892 TAILQ_REMOVE(&files, file, entry);
893 fclose(file->stream);
894 free(file->name);
895 free(file->ungetbuf);
896 free(file);
897 file = prev;
898 return (file ? 0 : EOF);
899 }
900
901 struct rad_conf *
parse_config(char * filename)902 parse_config(char *filename)
903 {
904 struct sym *sym, *next;
905 struct ra_iface_conf *iface;
906
907 conf = config_new_empty();
908 ra_options = NULL;
909
910 file = pushfile(filename, 0);
911 if (file == NULL) {
912 free(conf);
913 return (NULL);
914 }
915 topfile = file;
916
917 yyparse();
918 errors = file->errors;
919 popfile();
920
921 /* Free macros and check which have not been used. */
922 TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) {
923 if ((cmd_opts & OPT_VERBOSE2) && !sym->used)
924 fprintf(stderr, "warning: macro '%s' not used\n",
925 sym->nam);
926 if (!sym->persist) {
927 free(sym->nam);
928 free(sym->val);
929 TAILQ_REMOVE(&symhead, sym, entry);
930 free(sym);
931 }
932 }
933
934 if (errors) {
935 clear_config(conf);
936 return (NULL);
937 }
938
939 if (!SIMPLEQ_EMPTY(&conf->ra_options.ra_rdnss_list) ||
940 !SIMPLEQ_EMPTY(&conf->ra_options.ra_dnssl_list)) {
941 SIMPLEQ_FOREACH(iface, &conf->ra_iface_list, entry)
942 copy_dns_options(&conf->ra_options,
943 &iface->ra_options);
944 }
945
946 if (!SIMPLEQ_EMPTY(&conf->ra_options.ra_pref64_list)) {
947 SIMPLEQ_FOREACH(iface, &conf->ra_iface_list, entry)
948 copy_pref64_options(&conf->ra_options,
949 &iface->ra_options);
950 }
951
952 return (conf);
953 }
954
955 void
copy_dns_options(const struct ra_options_conf * src,struct ra_options_conf * dst)956 copy_dns_options(const struct ra_options_conf *src, struct ra_options_conf *dst)
957 {
958 struct ra_rdnss_conf *ra_rdnss, *nra_rdnss;
959 struct ra_dnssl_conf *ra_dnssl, *nra_dnssl;
960
961 if (SIMPLEQ_EMPTY(&dst->ra_rdnss_list)) {
962 SIMPLEQ_FOREACH(ra_rdnss, &src->ra_rdnss_list, entry) {
963 if ((nra_rdnss = calloc(1, sizeof(*nra_rdnss))) == NULL)
964 err(1, "%s", __func__);
965 memcpy(nra_rdnss, ra_rdnss, sizeof(*nra_rdnss));
966 SIMPLEQ_INSERT_TAIL(&dst->ra_rdnss_list, nra_rdnss,
967 entry);
968 }
969 dst->rdnss_count = src->rdnss_count;
970 }
971 if (SIMPLEQ_EMPTY(&dst->ra_dnssl_list)) {
972 SIMPLEQ_FOREACH(ra_dnssl, &src->ra_dnssl_list, entry) {
973 if ((nra_dnssl = calloc(1, sizeof(*nra_dnssl))) == NULL)
974 err(1, "%s", __func__);
975 memcpy(nra_dnssl, ra_dnssl, sizeof(*nra_dnssl));
976 SIMPLEQ_INSERT_TAIL(&dst->ra_dnssl_list, nra_dnssl,
977 entry);
978 }
979 dst->dnssl_len = src->dnssl_len;
980 }
981 }
982
983 void
copy_pref64_options(const struct ra_options_conf * src,struct ra_options_conf * dst)984 copy_pref64_options(const struct ra_options_conf *src, struct ra_options_conf
985 *dst)
986 {
987 struct ra_pref64_conf *pref64, *npref64;
988
989 SIMPLEQ_FOREACH(pref64, &src->ra_pref64_list, entry) {
990 if ((npref64 = calloc(1, sizeof(*npref64))) == NULL)
991 err(1, "%s", __func__);
992 memcpy(npref64, pref64, sizeof(*npref64));
993 SIMPLEQ_INSERT_TAIL(&dst->ra_pref64_list, npref64, entry);
994 }
995 }
996
997 int
symset(const char * nam,const char * val,int persist)998 symset(const char *nam, const char *val, int persist)
999 {
1000 struct sym *sym;
1001
1002 TAILQ_FOREACH(sym, &symhead, entry) {
1003 if (strcmp(nam, sym->nam) == 0)
1004 break;
1005 }
1006
1007 if (sym != NULL) {
1008 if (sym->persist == 1)
1009 return (0);
1010 else {
1011 free(sym->nam);
1012 free(sym->val);
1013 TAILQ_REMOVE(&symhead, sym, entry);
1014 free(sym);
1015 }
1016 }
1017 if ((sym = calloc(1, sizeof(*sym))) == NULL)
1018 return (-1);
1019
1020 sym->nam = strdup(nam);
1021 if (sym->nam == NULL) {
1022 free(sym);
1023 return (-1);
1024 }
1025 sym->val = strdup(val);
1026 if (sym->val == NULL) {
1027 free(sym->nam);
1028 free(sym);
1029 return (-1);
1030 }
1031 sym->used = 0;
1032 sym->persist = persist;
1033 TAILQ_INSERT_TAIL(&symhead, sym, entry);
1034 return (0);
1035 }
1036
1037 int
cmdline_symset(char * s)1038 cmdline_symset(char *s)
1039 {
1040 char *sym, *val;
1041 int ret;
1042
1043 if ((val = strrchr(s, '=')) == NULL)
1044 return (-1);
1045 sym = strndup(s, val - s);
1046 if (sym == NULL)
1047 errx(1, "%s: strndup", __func__);
1048 ret = symset(sym, val + 1, 1);
1049 free(sym);
1050
1051 return (ret);
1052 }
1053
1054 char *
symget(const char * nam)1055 symget(const char *nam)
1056 {
1057 struct sym *sym;
1058
1059 TAILQ_FOREACH(sym, &symhead, entry) {
1060 if (strcmp(nam, sym->nam) == 0) {
1061 sym->used = 1;
1062 return (sym->val);
1063 }
1064 }
1065 return (NULL);
1066 }
1067
1068 struct ra_prefix_conf *
conf_get_ra_prefix(struct in6_addr * addr,int prefixlen)1069 conf_get_ra_prefix(struct in6_addr *addr, int prefixlen)
1070 {
1071 struct ra_prefix_conf *prefix;
1072
1073 if (addr == NULL) {
1074 if (ra_iface_conf->autoprefix != NULL)
1075 return (ra_iface_conf->autoprefix);
1076 } else {
1077 SIMPLEQ_FOREACH(prefix, &ra_iface_conf->ra_prefix_list, entry) {
1078 if (prefix->prefixlen == prefixlen && memcmp(addr,
1079 &prefix->prefix, sizeof(*addr)) == 0)
1080 return (prefix);
1081 }
1082 }
1083
1084 prefix = calloc(1, sizeof(*prefix));
1085 if (prefix == NULL)
1086 err(1, "%s", __func__);
1087 prefix->prefixlen = prefixlen;
1088 prefix->vltime = ADV_VALID_LIFETIME;
1089 prefix->pltime = ADV_PREFERRED_LIFETIME;
1090 prefix->lflag = 1;
1091 prefix->aflag = 1;
1092
1093 if (addr == NULL)
1094 ra_iface_conf->autoprefix = prefix;
1095 else {
1096 prefix->prefix = *addr;
1097 SIMPLEQ_INSERT_TAIL(&ra_iface_conf->ra_prefix_list, prefix,
1098 entry);
1099 }
1100
1101 return (prefix);
1102 }
1103
1104 struct ra_pref64_conf *
conf_get_ra_pref64(struct in6_addr * addr,int prefixlen)1105 conf_get_ra_pref64(struct in6_addr *addr, int prefixlen)
1106 {
1107 struct ra_pref64_conf *pref64;
1108
1109 SIMPLEQ_FOREACH(pref64, &ra_options->ra_pref64_list, entry) {
1110 if (pref64->prefixlen == prefixlen && memcmp(addr,
1111 &pref64->prefix, sizeof(*addr)) == 0)
1112 return (pref64);
1113 }
1114
1115 pref64 = calloc(1, sizeof(*pref64));
1116 if (pref64 == NULL)
1117 err(1, "%s", __func__);
1118 pref64->prefixlen = prefixlen;
1119 pref64->ltime = ADV_DEFAULT_LIFETIME;
1120 pref64->prefix = *addr;
1121 SIMPLEQ_INSERT_TAIL(&ra_options->ra_pref64_list, pref64, entry);
1122
1123 return (pref64);
1124 }
1125
1126 struct ra_iface_conf *
conf_get_ra_iface(char * name)1127 conf_get_ra_iface(char *name)
1128 {
1129 struct ra_iface_conf *iface;
1130 size_t n;
1131
1132 SIMPLEQ_FOREACH(iface, &conf->ra_iface_list, entry) {
1133 if (strcmp(name, iface->name) == 0)
1134 return (iface);
1135 }
1136
1137 iface = calloc(1, sizeof(*iface));
1138 if (iface == NULL)
1139 errx(1, "%s: calloc", __func__);
1140 n = strlcpy(iface->name, name, sizeof(iface->name));
1141 if (n >= sizeof(iface->name))
1142 errx(1, "%s: name too long", __func__);
1143
1144 /* Inherit attributes set in global section. */
1145 iface->ra_options = conf->ra_options;
1146
1147 SIMPLEQ_INIT(&iface->ra_prefix_list);
1148 SIMPLEQ_INIT(&iface->ra_options.ra_rdnss_list);
1149 iface->ra_options.rdnss_count = 0;
1150 SIMPLEQ_INIT(&iface->ra_options.ra_dnssl_list);
1151 iface->ra_options.dnssl_len = 0;
1152 SIMPLEQ_INIT(&iface->ra_options.ra_pref64_list);
1153
1154 SIMPLEQ_INSERT_TAIL(&conf->ra_iface_list, iface, entry);
1155
1156 return (iface);
1157 }
1158
1159 void
clear_config(struct rad_conf * xconf)1160 clear_config(struct rad_conf *xconf)
1161 {
1162 struct ra_iface_conf *iface;
1163
1164 free_dns_options(&xconf->ra_options);
1165
1166 while((iface = SIMPLEQ_FIRST(&xconf->ra_iface_list)) != NULL) {
1167 SIMPLEQ_REMOVE_HEAD(&xconf->ra_iface_list, entry);
1168 free_ra_iface_conf(iface);
1169 }
1170
1171 free(xconf);
1172 }
1173