xref: /openbsd/usr.sbin/smtpd/parse.y (revision a6445c1d)
1 /*	$OpenBSD: parse.y,v 1.149 2014/11/20 05:51:21 jsg Exp $	*/
2 
3 /*
4  * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org>
5  * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
6  * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
7  * Copyright (c) 2001 Markus Friedl.  All rights reserved.
8  * Copyright (c) 2001 Daniel Hartmeier.  All rights reserved.
9  * Copyright (c) 2001 Theo de Raadt.  All rights reserved.
10  *
11  * Permission to use, copy, modify, and distribute this software for any
12  * purpose with or without fee is hereby granted, provided that the above
13  * copyright notice and this permission notice appear in all copies.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
16  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
18  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
21  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22  */
23 
24 %{
25 #include <sys/types.h>
26 #include <sys/queue.h>
27 #include <sys/tree.h>
28 #include <sys/socket.h>
29 #include <sys/stat.h>
30 #include <sys/ioctl.h>
31 
32 #include <net/if.h>
33 #include <netinet/in.h>
34 #include <arpa/inet.h>
35 
36 #include <ctype.h>
37 #include <err.h>
38 #include <errno.h>
39 #include <event.h>
40 #include <ifaddrs.h>
41 #include <imsg.h>
42 #include <inttypes.h>
43 #include <netdb.h>
44 #include <paths.h>
45 #include <pwd.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <syslog.h>
50 #include <unistd.h>
51 #include <util.h>
52 
53 #include <openssl/ssl.h>
54 
55 #include "smtpd.h"
56 #include "ssl.h"
57 #include "log.h"
58 
59 TAILQ_HEAD(files, file)		 files = TAILQ_HEAD_INITIALIZER(files);
60 static struct file {
61 	TAILQ_ENTRY(file)	 entry;
62 	FILE			*stream;
63 	char			*name;
64 	int			 lineno;
65 	int			 errors;
66 } *file, *topfile;
67 struct file	*pushfile(const char *, int);
68 int		 popfile(void);
69 int		 check_file_secrecy(int, const char *);
70 int		 yyparse(void);
71 int		 yylex(void);
72 int		 kw_cmp(const void *, const void *);
73 int		 lookup(char *);
74 int		 lgetc(int);
75 int		 lungetc(int);
76 int		 findeol(void);
77 int		 yyerror(const char *, ...)
78     __attribute__((__format__ (printf, 1, 2)))
79     __attribute__((__nonnull__ (1)));
80 
81 TAILQ_HEAD(symhead, sym)	 symhead = TAILQ_HEAD_INITIALIZER(symhead);
82 struct sym {
83 	TAILQ_ENTRY(sym)	 entry;
84 	int			 used;
85 	int			 persist;
86 	char			*nam;
87 	char			*val;
88 };
89 int		 symset(const char *, const char *, int);
90 char		*symget(const char *);
91 
92 struct smtpd		*conf = NULL;
93 static int		 errors = 0;
94 
95 struct filter_conf	*filter = NULL;
96 struct table		*table = NULL;
97 struct rule		*rule = NULL;
98 struct listener		 l;
99 struct mta_limits	*limits;
100 static struct pki	*pki;
101 
102 enum listen_options {
103 	LO_FAMILY	= 0x01,
104 	LO_PORT		= 0x02,
105 	LO_SSL		= 0x04,
106 	LO_FILTER      	= 0x08,
107 	LO_PKI      	= 0x10,
108 	LO_AUTH      	= 0x20,
109 	LO_TAG      	= 0x40,
110 	LO_HOSTNAME   	= 0x80,
111 	LO_HOSTNAMES   	= 0x100,
112 	LO_MASKSOURCE  	= 0x200,
113 	LO_NODSN	= 0x400,
114 };
115 
116 static struct listen_opts {
117 	char	       *ifx;
118 	int		family;
119 	in_port_t	port;
120 	uint16_t	ssl;
121 	char	       *filtername;
122 	char	       *pki;
123 	uint16_t       	auth;
124 	struct table   *authtable;
125 	char	       *tag;
126 	char	       *hostname;
127 	struct table   *hostnametable;
128 	uint16_t	flags;
129 
130 	uint16_t       	options;
131 } listen_opts;
132 
133 static void	create_listener(struct listenerlist *,  struct listen_opts *);
134 static void	config_listener(struct listener *,  struct listen_opts *);
135 
136 struct listener	*host_v4(const char *, in_port_t);
137 struct listener	*host_v6(const char *, in_port_t);
138 int		 host_dns(struct listenerlist *, struct listen_opts *);
139 int		 host(struct listenerlist *, struct listen_opts *);
140 int		 interface(struct listenerlist *, struct listen_opts *);
141 void		 set_local(const char *);
142 void		 set_localaddrs(struct table *);
143 int		 delaytonum(char *);
144 int		 is_if_in_group(const char *, const char *);
145 
146 static struct filter_conf *create_filter_proc(char *, char *);
147 static struct filter_conf *create_filter_chain(char *);
148 static int add_filter_arg(struct filter_conf *, char *);
149 
150 typedef struct {
151 	union {
152 		int64_t		 number;
153 		struct table	*table;
154 		char		*string;
155 		struct host	*host;
156 		struct mailaddr	*maddr;
157 	} v;
158 	int lineno;
159 } YYSTYPE;
160 
161 %}
162 
163 %token	AS QUEUE COMPRESSION ENCRYPTION MAXMESSAGESIZE MAXMTADEFERRED LISTEN ON ANY PORT EXPIRE
164 %token	TABLE SECURE SMTPS CERTIFICATE DOMAIN BOUNCEWARN LIMIT INET4 INET6 NODSN
165 %token  RELAY BACKUP VIA DELIVER TO LMTP MAILDIR MBOX HOSTNAME HOSTNAMES
166 %token	ACCEPT REJECT INCLUDE ERROR MDA FROM FOR SOURCE MTA PKI SCHEDULER
167 %token	ARROW AUTH TLS LOCAL VIRTUAL TAG TAGGED ALIAS FILTER KEY CA DHPARAMS
168 %token	AUTH_OPTIONAL TLS_REQUIRE USERBASE SENDER MASK_SOURCE VERIFY FORWARDONLY RECIPIENT
169 %token	<v.string>	STRING
170 %token  <v.number>	NUMBER
171 %type	<v.table>	table
172 %type	<v.number>	size negation
173 %type	<v.table>	tables tablenew tableref alias virtual userbase
174 %type	<v.string>	tagged
175 %%
176 
177 grammar		: /* empty */
178 		| grammar '\n'
179 		| grammar include '\n'
180 		| grammar varset '\n'
181 		| grammar main '\n'
182 		| grammar table '\n'
183 		| grammar rule '\n'
184 		| grammar error '\n'		{ file->errors++; }
185 		;
186 
187 include		: INCLUDE STRING		{
188 			struct file	*nfile;
189 
190 			if ((nfile = pushfile($2, 0)) == NULL) {
191 				yyerror("failed to include file %s", $2);
192 				free($2);
193 				YYERROR;
194 			}
195 			free($2);
196 
197 			file = nfile;
198 			lungetc('\n');
199 		}
200 		;
201 
202 varset		: STRING '=' STRING		{
203 			if (symset($1, $3, 0) == -1)
204 				fatal("cannot store variable");
205 			free($1);
206 			free($3);
207 		}
208 		;
209 
210 comma		: ','
211 		| nl
212 		| /* empty */
213 		;
214 
215 optnl		: '\n' optnl
216 		|
217 		;
218 
219 nl		: '\n' optnl
220 		;
221 
222 size		: NUMBER		{
223 			if ($1 < 0) {
224 				yyerror("invalid size: %" PRId64, $1);
225 				YYERROR;
226 			}
227 			$$ = $1;
228 		}
229 		| STRING			{
230 			long long result;
231 
232 			if (scan_scaled($1, &result) == -1 || result < 0) {
233 				yyerror("invalid size: %s", $1);
234 				free($1);
235 				YYERROR;
236 			}
237 			free($1);
238 			$$ = result;
239 		}
240 		;
241 
242 tagged		: TAGGED negation STRING       		{
243 			if (strlcpy(rule->r_tag, $3, sizeof rule->r_tag)
244 			    >= sizeof rule->r_tag) {
245 				yyerror("tag name too long: %s", $3);
246 				free($3);
247 				YYERROR;
248 			}
249 			free($3);
250 			rule->r_nottag = $2;
251 		}
252 		;
253 
254 bouncedelay	: STRING {
255 			time_t	d;
256 			int	i;
257 
258 			d = delaytonum($1);
259 			if (d < 0) {
260 				yyerror("invalid bounce delay: %s", $1);
261 				free($1);
262 				YYERROR;
263 			}
264 			free($1);
265 			for (i = 0; i < MAX_BOUNCE_WARN; i++) {
266 				if (conf->sc_bounce_warn[i] != 0)
267 					continue;
268 				conf->sc_bounce_warn[i] = d;
269 				break;
270 			}
271 		}
272 
273 bouncedelays	: bouncedelays ',' bouncedelay
274 		| bouncedelay
275 		| /* EMPTY */
276 		;
277 
278 opt_limit_mda	: STRING NUMBER {
279 			if (!strcmp($1, "max-session")) {
280 				conf->sc_mda_max_session = $2;
281 			}
282 			else if (!strcmp($1, "max-session-per-user")) {
283 				conf->sc_mda_max_user_session = $2;
284 			}
285 			else if (!strcmp($1, "task-lowat")) {
286 				conf->sc_mda_task_lowat = $2;
287 			}
288 			else if (!strcmp($1, "task-hiwat")) {
289 				conf->sc_mda_task_hiwat = $2;
290 			}
291 			else if (!strcmp($1, "task-release")) {
292 				conf->sc_mda_task_release = $2;
293 			}
294 			else {
295 				yyerror("invalid scheduler limit keyword: %s", $1);
296 				free($1);
297 				YYERROR;
298 			}
299 			free($1);
300 		}
301 		;
302 
303 limits_mda	: opt_limit_mda limits_mda
304 		| /* empty */
305 		;
306 
307 opt_limit_mta	: INET4 {
308 			limits->family = AF_INET;
309 		}
310 		| INET6 {
311 			limits->family = AF_INET6;
312 		}
313 		| STRING NUMBER {
314 			if (!limit_mta_set(limits, $1, $2)) {
315 				yyerror("invalid mta limit keyword: %s", $1);
316 				free($1);
317 				YYERROR;
318 			}
319 			free($1);
320 		}
321 		;
322 
323 limits_mta	: opt_limit_mta limits_mta
324 		| /* empty */
325 		;
326 
327 opt_limit_scheduler : STRING NUMBER {
328 			if (!strcmp($1, "max-inflight")) {
329 				conf->sc_scheduler_max_inflight = $2;
330 			}
331 			else if (!strcmp($1, "max-evp-batch-size")) {
332 				conf->sc_scheduler_max_evp_batch_size = $2;
333 			}
334 			else if (!strcmp($1, "max-msg-batch-size")) {
335 				conf->sc_scheduler_max_msg_batch_size = $2;
336 			}
337 			else if (!strcmp($1, "max-schedule")) {
338 				conf->sc_scheduler_max_schedule = $2;
339 			}
340 			else {
341 				yyerror("invalid scheduler limit keyword: %s", $1);
342 				free($1);
343 				YYERROR;
344 			}
345 			free($1);
346 		}
347 		;
348 
349 limits_scheduler: opt_limit_scheduler limits_scheduler
350 		| /* empty */
351 		;
352 
353 opt_pki		: CERTIFICATE STRING {
354 			pki->pki_cert_file = $2;
355 		}
356 		| KEY STRING {
357 			pki->pki_key_file = $2;
358 		}
359 		| CA STRING {
360 			pki->pki_ca_file = $2;
361 		}
362 		| DHPARAMS STRING {
363 			pki->pki_dhparams_file = $2;
364 		}
365 		;
366 
367 pki		: opt_pki pki
368 		| /* empty */
369 		;
370 
371 opt_listen     	: INET4			{
372 			if (listen_opts.options & LO_FAMILY) {
373 				yyerror("address family already specified");
374 				YYERROR;
375 			}
376 			listen_opts.options |= LO_FAMILY;
377 			listen_opts.family = AF_INET;
378 		}
379 		| INET6			{
380 			if (listen_opts.options & LO_FAMILY) {
381 				yyerror("address family already specified");
382 				YYERROR;
383 			}
384 			listen_opts.options |= LO_FAMILY;
385 			listen_opts.family = AF_INET6;
386 		}
387 		| PORT STRING			{
388 			struct servent	*servent;
389 
390 			if (listen_opts.options & LO_PORT) {
391 				yyerror("port already specified");
392 				YYERROR;
393 			}
394 			listen_opts.options |= LO_PORT;
395 
396 			servent = getservbyname($2, "tcp");
397 			if (servent == NULL) {
398 				yyerror("invalid port: %s", $2);
399 				free($2);
400 				YYERROR;
401 			}
402 			free($2);
403 			listen_opts.port = ntohs(servent->s_port);
404 		}
405 		| PORT NUMBER			{
406 			if (listen_opts.options & LO_PORT) {
407 				yyerror("port already specified");
408 				YYERROR;
409 			}
410 			listen_opts.options |= LO_PORT;
411 
412 			if ($2 <= 0 || $2 >= (int)USHRT_MAX) {
413 				yyerror("invalid port: %" PRId64, $2);
414 				YYERROR;
415 			}
416 			listen_opts.port = $2;
417 		}
418 		| FILTER STRING			{
419 			if (listen_opts.options & LO_FILTER) {
420 				yyerror("filter already specified");
421 				YYERROR;
422 			}
423 			listen_opts.options |= LO_FILTER;
424 			listen_opts.filtername = $2;
425 		}
426 		| SMTPS				{
427 			if (listen_opts.options & LO_SSL) {
428 				yyerror("TLS mode already specified");
429 				YYERROR;
430 			}
431 			listen_opts.options |= LO_SSL;
432 			listen_opts.ssl = F_SMTPS;
433 		}
434 		| SMTPS VERIFY 			{
435 			if (listen_opts.options & LO_SSL) {
436 				yyerror("TLS mode already specified");
437 				YYERROR;
438 			}
439 			listen_opts.options |= LO_SSL;
440 			listen_opts.ssl = F_SMTPS|F_TLS_VERIFY;
441 		}
442 		| TLS				{
443 			if (listen_opts.options & LO_SSL) {
444 				yyerror("TLS mode already specified");
445 				YYERROR;
446 			}
447 			listen_opts.options |= LO_SSL;
448 			listen_opts.ssl = F_STARTTLS;
449 		}
450 		| SECURE       			{
451 			if (listen_opts.options & LO_SSL) {
452 				yyerror("TLS mode already specified");
453 				YYERROR;
454 			}
455 			listen_opts.options |= LO_SSL;
456 			listen_opts.ssl = F_SSL;
457 		}
458 		| TLS_REQUIRE			{
459 			if (listen_opts.options & LO_SSL) {
460 				yyerror("TLS mode already specified");
461 				YYERROR;
462 			}
463 			listen_opts.options |= LO_SSL;
464 			listen_opts.ssl = F_STARTTLS|F_STARTTLS_REQUIRE;
465 		}
466 		| TLS_REQUIRE VERIFY   		{
467 			if (listen_opts.options & LO_SSL) {
468 				yyerror("TLS mode already specified");
469 				YYERROR;
470 			}
471 			listen_opts.options |= LO_SSL;
472 			listen_opts.ssl = F_STARTTLS|F_STARTTLS_REQUIRE|F_TLS_VERIFY;
473 		}
474 		| PKI STRING			{
475 			if (listen_opts.options & LO_PKI) {
476 				yyerror("pki already specified");
477 				YYERROR;
478 			}
479 			listen_opts.options |= LO_PKI;
480 			listen_opts.pki = $2;
481 		}
482 		| AUTH				{
483 			if (listen_opts.options & LO_AUTH) {
484 				yyerror("auth already specified");
485 				YYERROR;
486 			}
487 			listen_opts.options |= LO_AUTH;
488 			listen_opts.auth = F_AUTH|F_AUTH_REQUIRE;
489 		}
490 		| AUTH_OPTIONAL			{
491 			if (listen_opts.options & LO_AUTH) {
492 				yyerror("auth already specified");
493 				YYERROR;
494 			}
495 			listen_opts.options |= LO_AUTH;
496 			listen_opts.auth = F_AUTH;
497 		}
498 		| AUTH tables  			{
499 			if (listen_opts.options & LO_AUTH) {
500 				yyerror("auth already specified");
501 				YYERROR;
502 			}
503 			listen_opts.options |= LO_AUTH;
504 			listen_opts.authtable = $2;
505 			listen_opts.auth = F_AUTH|F_AUTH_REQUIRE;
506 		}
507 		| AUTH_OPTIONAL tables 		{
508 			if (listen_opts.options & LO_AUTH) {
509 				yyerror("auth already specified");
510 				YYERROR;
511 			}
512 			listen_opts.options |= LO_AUTH;
513 			listen_opts.authtable = $2;
514 			listen_opts.auth = F_AUTH;
515 		}
516 		| TAG STRING			{
517 			if (listen_opts.options & LO_TAG) {
518 				yyerror("tag already specified");
519 				YYERROR;
520 			}
521 			listen_opts.options |= LO_TAG;
522 
523        			if (strlen($2) >= MAX_TAG_SIZE) {
524        				yyerror("tag name too long");
525 				free($2);
526 				YYERROR;
527 			}
528 			listen_opts.tag = $2;
529 		}
530 		| HOSTNAME STRING	{
531 			if (listen_opts.options & LO_HOSTNAME) {
532 				yyerror("hostname already specified");
533 				YYERROR;
534 			}
535 			listen_opts.options |= LO_HOSTNAME;
536 
537 			listen_opts.hostname = $2;
538 		}
539 		| HOSTNAMES tables	{
540 			struct table	*t = $2;
541 
542 			if (listen_opts.options & LO_HOSTNAMES) {
543 				yyerror("hostnames already specified");
544 				YYERROR;
545 			}
546 			listen_opts.options |= LO_HOSTNAMES;
547 
548 			if (! table_check_use(t, T_DYNAMIC|T_HASH, K_ADDRNAME)) {
549 				yyerror("invalid use of table \"%s\" as "
550 				    "HOSTNAMES parameter", t->t_name);
551 				YYERROR;
552 			}
553 			listen_opts.hostnametable = t;
554 		}
555 		| MASK_SOURCE	{
556 			if (listen_opts.options & LO_MASKSOURCE) {
557 				yyerror("mask-source already specified");
558 				YYERROR;
559 			}
560 			listen_opts.options |= LO_MASKSOURCE;
561 			listen_opts.flags |= F_MASK_SOURCE;
562 		}
563 		| NODSN	{
564 			if (listen_opts.options & LO_NODSN) {
565 				yyerror("no-dsn already specified");
566 				YYERROR;
567 			}
568 			listen_opts.options |= LO_NODSN;
569 			listen_opts.flags &= ~F_EXT_DSN;
570 		}
571 		;
572 
573 listen		: opt_listen listen
574 		| /* empty */
575 		;
576 
577 opt_relay_common: AS STRING	{
578 			struct mailaddr maddr, *maddrp;
579 
580 			if (! text_to_mailaddr(&maddr, $2)) {
581 				yyerror("invalid parameter to AS: %s", $2);
582 				free($2);
583 				YYERROR;
584 			}
585 			free($2);
586 
587 			if (maddr.user[0] == '\0' && maddr.domain[0] == '\0') {
588 				yyerror("invalid empty parameter to AS");
589 				YYERROR;
590 			}
591 			else if (maddr.domain[0] == '\0') {
592 				if (strlcpy(maddr.domain, conf->sc_hostname,
593 					sizeof (maddr.domain))
594 				    >= sizeof (maddr.domain)) {
595 					yyerror("hostname too long for AS parameter: %s",
596 					    conf->sc_hostname);
597 					YYERROR;
598 				}
599 			}
600 			rule->r_as = xmemdup(&maddr, sizeof (*maddrp), "parse relay_as: AS");
601 		}
602 		| SOURCE tables			{
603 			struct table	*t = $2;
604 			if (! table_check_use(t, T_DYNAMIC|T_LIST, K_SOURCE)) {
605 				yyerror("invalid use of table \"%s\" as "
606 				    "SOURCE parameter", t->t_name);
607 				YYERROR;
608 			}
609 			(void)strlcpy(rule->r_value.relayhost.sourcetable, t->t_name,
610 			    sizeof rule->r_value.relayhost.sourcetable);
611 		}
612 		| HOSTNAME STRING {
613 			(void)strlcpy(rule->r_value.relayhost.heloname, $2,
614 			    sizeof rule->r_value.relayhost.heloname);
615 			free($2);
616 		}
617 		| HOSTNAMES tables		{
618 			struct table	*t = $2;
619 			if (! table_check_use(t, T_DYNAMIC|T_HASH, K_ADDRNAME)) {
620 				yyerror("invalid use of table \"%s\" as "
621 				    "HOSTNAMES parameter", t->t_name);
622 				YYERROR;
623 			}
624 			(void)strlcpy(rule->r_value.relayhost.helotable, t->t_name,
625 			    sizeof rule->r_value.relayhost.helotable);
626 		}
627 		| PKI STRING {
628 			if (! lowercase(rule->r_value.relayhost.pki_name, $2,
629 				sizeof(rule->r_value.relayhost.pki_name))) {
630 				yyerror("pki name too long: %s", $2);
631 				free($2);
632 				YYERROR;
633 			}
634 			if (dict_get(conf->sc_pki_dict,
635 			    rule->r_value.relayhost.pki_name) == NULL) {
636 				log_warnx("pki name not found: %s", $2);
637 				free($2);
638 				YYERROR;
639 			}
640 			free($2);
641 		}
642 		;
643 
644 opt_relay	: BACKUP STRING			{
645 			rule->r_value.relayhost.flags |= F_BACKUP;
646 			if (strlcpy(rule->r_value.relayhost.hostname, $2,
647 				sizeof (rule->r_value.relayhost.hostname))
648 			    >= sizeof (rule->r_value.relayhost.hostname)) {
649 				log_warnx("hostname too long: %s", $2);
650 				free($2);
651 				YYERROR;
652 			}
653 			free($2);
654 		}
655 		| BACKUP       			{
656 			rule->r_value.relayhost.flags |= F_BACKUP;
657 			(void)strlcpy(rule->r_value.relayhost.hostname,
658 			    conf->sc_hostname,
659 			    sizeof (rule->r_value.relayhost.hostname));
660 		}
661 		| TLS       			{
662 			rule->r_value.relayhost.flags |= F_STARTTLS;
663 		}
664 		| TLS VERIFY			{
665 			rule->r_value.relayhost.flags |= F_STARTTLS|F_TLS_VERIFY;
666 		}
667 		;
668 
669 relay		: opt_relay_common relay
670 		| opt_relay relay
671 		| /* empty */
672 		;
673 
674 opt_relay_via	: AUTH tables {
675 			struct table   *t = $2;
676 
677 			if (! table_check_use(t, T_DYNAMIC|T_HASH, K_CREDENTIALS)) {
678 				yyerror("invalid use of table \"%s\" as AUTH parameter",
679 				    t->t_name);
680 				YYERROR;
681 			}
682 			(void)strlcpy(rule->r_value.relayhost.authtable, t->t_name,
683 			    sizeof(rule->r_value.relayhost.authtable));
684 		}
685 		| VERIFY {
686 			if (!(rule->r_value.relayhost.flags & F_SSL)) {
687 				yyerror("cannot \"verify\" with insecure protocol");
688 				YYERROR;
689 			}
690 			rule->r_value.relayhost.flags |= F_TLS_VERIFY;
691 		}
692 		;
693 
694 relay_via	: opt_relay_common relay_via
695 		| opt_relay_via relay_via
696 		| /* empty */
697 		;
698 
699 main		: BOUNCEWARN {
700 			memset(conf->sc_bounce_warn, 0, sizeof conf->sc_bounce_warn);
701 		} bouncedelays
702 		| QUEUE COMPRESSION {
703 			conf->sc_queue_flags |= QUEUE_COMPRESSION;
704 		}
705 		| QUEUE ENCRYPTION {
706 			conf->sc_queue_flags |= QUEUE_ENCRYPTION;
707 		}
708 		| QUEUE ENCRYPTION KEY STRING {
709 			if (strcasecmp($4, "stdin") == 0 || strcasecmp($4, "-") == 0) {
710 				conf->sc_queue_key = "stdin";
711 				free($4);
712 			}
713 			else
714 				conf->sc_queue_key = $4;
715 			conf->sc_queue_flags |= QUEUE_ENCRYPTION;
716 		}
717 		| EXPIRE STRING {
718 			conf->sc_qexpire = delaytonum($2);
719 			if (conf->sc_qexpire == -1) {
720 				yyerror("invalid expire delay: %s", $2);
721 				free($2);
722 				YYERROR;
723 			}
724 			free($2);
725 		}
726 		| MAXMESSAGESIZE size {
727 			conf->sc_maxsize = $2;
728 		}
729 		| MAXMTADEFERRED NUMBER  {
730 			conf->sc_mta_max_deferred = $2;
731 		}
732 		| LIMIT MDA limits_mda
733 		| LIMIT MTA FOR DOMAIN STRING {
734 			struct mta_limits	*d;
735 
736 			limits = dict_get(conf->sc_limits_dict, $5);
737 			if (limits == NULL) {
738 				limits = xcalloc(1, sizeof(*limits), "mta_limits");
739 				dict_xset(conf->sc_limits_dict, $5, limits);
740 				d = dict_xget(conf->sc_limits_dict, "default");
741 				memmove(limits, d, sizeof(*limits));
742 			}
743 			free($5);
744 		} limits_mta
745 		| LIMIT MTA {
746 			limits = dict_get(conf->sc_limits_dict, "default");
747 		} limits_mta
748 		| LIMIT SCHEDULER limits_scheduler
749 		| LISTEN {
750 			memset(&l, 0, sizeof l);
751 			memset(&listen_opts, 0, sizeof listen_opts);
752 			listen_opts.family = AF_UNSPEC;
753 			listen_opts.flags |= F_EXT_DSN;
754 		} ON STRING listen {
755 			listen_opts.ifx = $4;
756 			create_listener(conf->sc_listeners, &listen_opts);
757 		}
758 		| FILTER STRING STRING {
759 			if (!strcmp($3, "chain")) {
760 				free($3);
761 				if ((filter = create_filter_chain($2)) == NULL) {
762 					free($2);
763 					YYERROR;
764 				}
765 			}
766 			else {
767 				if ((filter = create_filter_proc($2, $3)) == NULL) {
768 					free($2);
769 					free($3);
770 					YYERROR;
771 				}
772 			}
773 		} filter_args;
774 		| PKI STRING	{
775 			char buf[MAXHOSTNAMELEN];
776 			xlowercase(buf, $2, sizeof(buf));
777 			free($2);
778 			pki = dict_get(conf->sc_pki_dict, buf);
779 			if (pki == NULL) {
780 				pki = xcalloc(1, sizeof *pki, "parse:pki");
781 				(void)strlcpy(pki->pki_name, buf, sizeof(pki->pki_name));
782 				dict_set(conf->sc_pki_dict, pki->pki_name, pki);
783 			}
784 		} pki
785 		;
786 
787 filter_args	:
788 		| STRING {
789 			if (!add_filter_arg(filter, $1)) {
790 				free($1);
791 				YYERROR;
792 			}
793 		} filter_args
794 		;
795 
796 table		: TABLE STRING STRING	{
797 			char *p, *backend, *config;
798 
799 			p = $3;
800 			if (*p == '/') {
801 				backend = "static";
802 				config = $3;
803 			}
804 			else {
805 				backend = $3;
806 				config = NULL;
807 				for (p = $3; *p && *p != ':'; p++)
808 					;
809 				if (*p == ':') {
810 					*p = '\0';
811 					backend = $3;
812 					config  = p+1;
813 				}
814 			}
815 			if (config != NULL && *config != '/') {
816 				yyerror("invalid backend parameter for table: %s",
817 				    $2);
818 				free($2);
819 				free($3);
820 				YYERROR;
821 			}
822 			table = table_create(backend, $2, NULL, config);
823 			if (!table_config(table)) {
824 				yyerror("invalid configuration file %s for table %s",
825 				    config, table->t_name);
826 				free($2);
827 				free($3);
828 				YYERROR;
829 			}
830 			free($2);
831 			free($3);
832 		}
833 		| TABLE STRING {
834 			table = table_create("static", $2, NULL, NULL);
835 			free($2);
836 		} '{' tableval_list '}' {
837 			table = NULL;
838 		}
839 		;
840 
841 assign		: '=' | ARROW;
842 
843 keyval		: STRING assign STRING		{
844 			table->t_type = T_HASH;
845 			table_add(table, $1, $3);
846 			free($1);
847 			free($3);
848 		}
849 		;
850 
851 keyval_list	: keyval
852 		| keyval comma keyval_list
853 		;
854 
855 stringel	: STRING			{
856 			table->t_type = T_LIST;
857 			table_add(table, $1, NULL);
858 			free($1);
859 		}
860 		;
861 
862 string_list	: stringel
863 		| stringel comma string_list
864 		;
865 
866 tableval_list	: string_list			{ }
867 		| keyval_list			{ }
868 		;
869 
870 tablenew	: STRING			{
871 			struct table	*t;
872 
873 			t = table_create("static", NULL, NULL, NULL);
874 			t->t_type = T_LIST;
875 			table_add(t, $1, NULL);
876 			free($1);
877 			$$ = t;
878 		}
879 		| '{'				{
880 			table = table_create("static", NULL, NULL, NULL);
881 		} tableval_list '}'		{
882 			$$ = table;
883 		}
884 		;
885 
886 tableref       	: '<' STRING '>'       		{
887 			struct table	*t;
888 
889 			if ((t = table_find($2, NULL)) == NULL) {
890 				yyerror("no such table: %s", $2);
891 				free($2);
892 				YYERROR;
893 			}
894 			free($2);
895 			$$ = t;
896 		}
897 		;
898 
899 tables		: tablenew			{ $$ = $1; }
900 		| tableref			{ $$ = $1; }
901 		;
902 
903 alias		: ALIAS tables			{
904 			struct table   *t = $2;
905 
906 			if (! table_check_use(t, T_DYNAMIC|T_HASH, K_ALIAS)) {
907 				yyerror("invalid use of table \"%s\" as ALIAS parameter",
908 				    t->t_name);
909 				YYERROR;
910 			}
911 
912 			$$ = t;
913 		}
914 		;
915 
916 virtual		: VIRTUAL tables		{
917 			struct table   *t = $2;
918 
919 			if (! table_check_use(t, T_DYNAMIC|T_HASH, K_ALIAS)) {
920 				yyerror("invalid use of table \"%s\" as VIRTUAL parameter",
921 				    t->t_name);
922 				YYERROR;
923 			}
924 			$$ = t;
925 		}
926 		;
927 
928 usermapping	: alias		{
929 			if (rule->r_mapping) {
930 				yyerror("alias specified multiple times");
931 				YYERROR;
932 			}
933 			rule->r_desttype = DEST_DOM;
934 			rule->r_mapping = $1;
935 		}
936 		| virtual	{
937 			if (rule->r_mapping) {
938 				yyerror("virtual specified multiple times");
939 				YYERROR;
940 			}
941 			rule->r_desttype = DEST_VDOM;
942 			rule->r_mapping = $1;
943 		}
944 		;
945 
946 userbase	: USERBASE tables	{
947 			struct table   *t = $2;
948 
949 			if (rule->r_userbase) {
950 				yyerror("userbase specified multiple times");
951 				YYERROR;
952 			}
953 			if (! table_check_use(t, T_DYNAMIC|T_HASH, K_USERINFO)) {
954 				yyerror("invalid use of table \"%s\" as USERBASE parameter",
955 				    t->t_name);
956 				YYERROR;
957 			}
958 			rule->r_userbase = t;
959 		}
960 		;
961 
962 deliver_action	: DELIVER TO MAILDIR			{
963 			rule->r_action = A_MAILDIR;
964 			if (strlcpy(rule->r_value.buffer, "~/Maildir",
965 			    sizeof(rule->r_value.buffer)) >=
966 			    sizeof(rule->r_value.buffer))
967 				fatal("pathname too long");
968 		}
969 		| DELIVER TO MAILDIR STRING		{
970 			rule->r_action = A_MAILDIR;
971 			if (strlcpy(rule->r_value.buffer, $4,
972 			    sizeof(rule->r_value.buffer)) >=
973 			    sizeof(rule->r_value.buffer))
974 				fatal("pathname too long");
975 			free($4);
976 		}
977 		| DELIVER TO MBOX			{
978 			rule->r_action = A_MBOX;
979 			if (strlcpy(rule->r_value.buffer, _PATH_MAILDIR "/%u",
980 			    sizeof(rule->r_value.buffer))
981 			    >= sizeof(rule->r_value.buffer))
982 				fatal("pathname too long");
983 		}
984 		| DELIVER TO LMTP STRING		{
985 			rule->r_action = A_LMTP;
986 			if (strchr($4, ':') || $4[0] == '/') {
987 				if (strlcpy(rule->r_value.buffer, $4,
988 					sizeof(rule->r_value.buffer))
989 					>= sizeof(rule->r_value.buffer))
990 					fatal("lmtp destination too long");
991 			} else
992 				fatal("invalid lmtp destination");
993 			free($4);
994 		}
995 		| DELIVER TO MDA STRING			{
996 			rule->r_action = A_MDA;
997 			if (strlcpy(rule->r_value.buffer, $4,
998 			    sizeof(rule->r_value.buffer))
999 			    >= sizeof(rule->r_value.buffer))
1000 				fatal("command too long");
1001 			free($4);
1002 		}
1003 		;
1004 
1005 relay_action   	: RELAY relay {
1006 			rule->r_action = A_RELAY;
1007 		}
1008 		| RELAY VIA STRING {
1009 			rule->r_action = A_RELAYVIA;
1010 			if (! text_to_relayhost(&rule->r_value.relayhost, $3)) {
1011 				yyerror("error: invalid url: %s", $3);
1012 				free($3);
1013 				YYERROR;
1014 			}
1015 			free($3);
1016 		} relay_via {
1017 			/* no worries, F_AUTH cant be set without SSL */
1018 			if (rule->r_value.relayhost.flags & F_AUTH) {
1019 				if (rule->r_value.relayhost.authtable[0] == '\0') {
1020 					yyerror("error: auth without auth table");
1021 					YYERROR;
1022 				}
1023 			}
1024 		}
1025 		;
1026 
1027 negation	: '!'		{ $$ = 1; }
1028 		| /* empty */	{ $$ = 0; }
1029 		;
1030 
1031 from		: FROM negation SOURCE tables       		{
1032 			struct table   *t = $4;
1033 
1034 			if (rule->r_sources) {
1035 				yyerror("from specified multiple times");
1036 				YYERROR;
1037 			}
1038 			if (! table_check_use(t, T_DYNAMIC|T_LIST, K_NETADDR)) {
1039 				yyerror("invalid use of table \"%s\" as FROM parameter",
1040 				    t->t_name);
1041 				YYERROR;
1042 			}
1043 			rule->r_notsources = $2;
1044 			rule->r_sources = t;
1045 		}
1046 		| FROM negation ANY    		{
1047 			if (rule->r_sources) {
1048 				yyerror("from specified multiple times");
1049 				YYERROR;
1050 			}
1051 			rule->r_sources = table_find("<anyhost>", NULL);
1052 			rule->r_notsources = $2;
1053 		}
1054 		| FROM negation LOCAL  		{
1055 			if (rule->r_sources) {
1056 				yyerror("from specified multiple times");
1057 				YYERROR;
1058 			}
1059 			rule->r_sources = table_find("<localhost>", NULL);
1060 			rule->r_notsources = $2;
1061 		}
1062 		;
1063 
1064 for		: FOR negation DOMAIN tables {
1065 			struct table   *t = $4;
1066 
1067 			if (rule->r_destination) {
1068 				yyerror("for specified multiple times");
1069 				YYERROR;
1070 			}
1071 			if (! table_check_use(t, T_DYNAMIC|T_LIST, K_DOMAIN)) {
1072 				yyerror("invalid use of table \"%s\" as DOMAIN parameter",
1073 				    t->t_name);
1074 				YYERROR;
1075 			}
1076 			rule->r_notdestination = $2;
1077 			rule->r_destination = t;
1078 		}
1079 		| FOR negation ANY    		{
1080 			if (rule->r_destination) {
1081 				yyerror("for specified multiple times");
1082 				YYERROR;
1083 			}
1084 			rule->r_notdestination = $2;
1085 			rule->r_destination = table_find("<anydestination>", NULL);
1086 		}
1087 		| FOR negation LOCAL  		{
1088 			if (rule->r_destination) {
1089 				yyerror("for specified multiple times");
1090 				YYERROR;
1091 			}
1092 			rule->r_notdestination = $2;
1093 			rule->r_destination = table_find("<localnames>", NULL);
1094 		}
1095 		;
1096 
1097 sender		: SENDER negation tables			{
1098 			struct table   *t = $3;
1099 
1100 			if (rule->r_senders) {
1101 				yyerror("sender specified multiple times");
1102 				YYERROR;
1103 			}
1104 
1105 			if (! table_check_use(t, T_DYNAMIC|T_LIST, K_MAILADDR)) {
1106 				yyerror("invalid use of table \"%s\" as SENDER parameter",
1107 				    t->t_name);
1108 				YYERROR;
1109 			}
1110 			rule->r_notsenders = $2;
1111 			rule->r_senders = t;
1112 		}
1113 		;
1114 
1115 recipient      	: RECIPIENT negation tables			{
1116 			struct table   *t = $3;
1117 
1118 			if (rule->r_recipients) {
1119 				yyerror("recipient specified multiple times");
1120 				YYERROR;
1121 			}
1122 
1123 			if (! table_check_use(t, T_DYNAMIC|T_LIST, K_MAILADDR)) {
1124 				yyerror("invalid use of table \"%s\" as RECIPIENT parameter",
1125 				    t->t_name);
1126 				YYERROR;
1127 			}
1128 			rule->r_notrecipients = $2;
1129 			rule->r_recipients = t;
1130 		}
1131 		;
1132 
1133 forwardonly	: FORWARDONLY {
1134 			if (rule->r_forwardonly) {
1135 				yyerror("forward-only specified multiple times");
1136 				YYERROR;
1137 			}
1138 			rule->r_forwardonly = 1;
1139 		}
1140 		;
1141 
1142 expire		: EXPIRE STRING {
1143 			if (rule->r_qexpire != -1) {
1144 				yyerror("expire specified multiple times");
1145 				YYERROR;
1146 			}
1147 			rule->r_qexpire = delaytonum($2);
1148 			if (rule->r_qexpire == -1) {
1149 				yyerror("invalid expire delay: %s", $2);
1150 				free($2);
1151 				YYERROR;
1152 			}
1153 			free($2);
1154 		}
1155 		;
1156 
1157 opt_decision	: sender
1158 		| recipient
1159 		| from
1160 		| for
1161 		| tagged
1162 		;
1163 decision	: opt_decision decision
1164 		|
1165 		;
1166 
1167 opt_lookup	: userbase
1168 		| usermapping
1169 		;
1170 lookup		: opt_lookup lookup
1171 		|
1172 		;
1173 
1174 action		: deliver_action
1175 		| relay_action
1176 		|
1177 		;
1178 
1179 opt_accept	: expire
1180 		| forwardonly
1181 		;
1182 
1183 accept_params	: opt_accept accept_params
1184 		|
1185 		;
1186 
1187 rule		: ACCEPT {
1188 			rule = xcalloc(1, sizeof(*rule), "parse rule: ACCEPT");
1189 			rule->r_action = A_NONE;
1190 			rule->r_decision = R_ACCEPT;
1191 			rule->r_desttype = DEST_DOM;
1192 			rule->r_qexpire = -1;
1193 		} decision lookup action accept_params {
1194 			if (! rule->r_sources)
1195 				rule->r_sources = table_find("<localhost>", NULL);
1196 			if (! rule->r_destination)
1197 			 	rule->r_destination = table_find("<localnames>", NULL);
1198 			if (! rule->r_userbase)
1199 				rule->r_userbase = table_find("<getpwnam>", NULL);
1200 			if (rule->r_qexpire == -1)
1201 				rule->r_qexpire = conf->sc_qexpire;
1202 			if (rule->r_action == A_RELAY || rule->r_action == A_RELAYVIA) {
1203 				if (rule->r_userbase != table_find("<getpwnam>", NULL)) {
1204 					yyerror("userbase may not be used with a relay rule");
1205 					YYERROR;
1206 				}
1207 				if (rule->r_mapping) {
1208 					yyerror("aliases/virtual may not be used with a relay rule");
1209 					YYERROR;
1210 				}
1211 			}
1212 			if (rule->r_forwardonly && rule->r_action != A_NONE) {
1213 				yyerror("forward-only may not be used with a default action");
1214 				YYERROR;
1215 			}
1216 			TAILQ_INSERT_TAIL(conf->sc_rules, rule, r_entry);
1217 			rule = NULL;
1218 		}
1219 		| REJECT {
1220 			rule = xcalloc(1, sizeof(*rule), "parse rule: REJECT");
1221 			rule->r_decision = R_REJECT;
1222 			rule->r_desttype = DEST_DOM;
1223 		} decision {
1224 			if (! rule->r_sources)
1225 				rule->r_sources = table_find("<localhost>", NULL);
1226 			if (! rule->r_destination)
1227 				rule->r_destination = table_find("<localnames>", NULL);
1228 			TAILQ_INSERT_TAIL(conf->sc_rules, rule, r_entry);
1229 			rule = NULL;
1230 		}
1231 		;
1232 %%
1233 
1234 struct keywords {
1235 	const char	*k_name;
1236 	int		 k_val;
1237 };
1238 
1239 int
1240 yyerror(const char *fmt, ...)
1241 {
1242 	va_list		 ap;
1243 	char		*msg;
1244 
1245 	file->errors++;
1246 	va_start(ap, fmt);
1247 	if (vasprintf(&msg, fmt, ap) == -1)
1248 		fatalx("yyerror vasprintf");
1249 	va_end(ap);
1250 	logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg);
1251 	free(msg);
1252 	return (0);
1253 }
1254 
1255 int
1256 kw_cmp(const void *k, const void *e)
1257 {
1258 	return (strcmp(k, ((const struct keywords *)e)->k_name));
1259 }
1260 
1261 int
1262 lookup(char *s)
1263 {
1264 	/* this has to be sorted always */
1265 	static const struct keywords keywords[] = {
1266 		{ "accept",		ACCEPT },
1267 		{ "alias",		ALIAS },
1268 		{ "any",		ANY },
1269 		{ "as",			AS },
1270 		{ "auth",		AUTH },
1271 		{ "auth-optional",     	AUTH_OPTIONAL },
1272 		{ "backup",		BACKUP },
1273 		{ "bounce-warn",	BOUNCEWARN },
1274 		{ "ca",			CA },
1275 		{ "certificate",	CERTIFICATE },
1276 		{ "compression",	COMPRESSION },
1277 		{ "deliver",		DELIVER },
1278 		{ "dhparams",		DHPARAMS },
1279 		{ "domain",		DOMAIN },
1280 		{ "encryption",		ENCRYPTION },
1281 		{ "expire",		EXPIRE },
1282 		{ "filter",		FILTER },
1283 		{ "for",		FOR },
1284 		{ "forward-only",      	FORWARDONLY },
1285 		{ "from",		FROM },
1286 		{ "hostname",		HOSTNAME },
1287 		{ "hostnames",		HOSTNAMES },
1288 		{ "include",		INCLUDE },
1289 		{ "inet4",		INET4 },
1290 		{ "inet6",		INET6 },
1291 		{ "key",		KEY },
1292 		{ "limit",		LIMIT },
1293 		{ "listen",		LISTEN },
1294 		{ "lmtp",		LMTP },
1295 		{ "local",		LOCAL },
1296 		{ "maildir",		MAILDIR },
1297 		{ "mask-source",	MASK_SOURCE },
1298 		{ "max-message-size",  	MAXMESSAGESIZE },
1299 		{ "max-mta-deferred",  	MAXMTADEFERRED },
1300 		{ "mbox",		MBOX },
1301 		{ "mda",		MDA },
1302 		{ "mta",		MTA },
1303 		{ "no-dsn",		NODSN },
1304 		{ "on",			ON },
1305 		{ "pki",		PKI },
1306 		{ "port",		PORT },
1307 		{ "queue",		QUEUE },
1308 		{ "recipient",		RECIPIENT },
1309 		{ "reject",		REJECT },
1310 		{ "relay",		RELAY },
1311 		{ "scheduler",		SCHEDULER },
1312 		{ "secure",		SECURE },
1313 		{ "sender",    		SENDER },
1314 		{ "smtps",		SMTPS },
1315 		{ "source",		SOURCE },
1316 		{ "table",		TABLE },
1317 		{ "tag",		TAG },
1318 		{ "tagged",		TAGGED },
1319 		{ "tls",		TLS },
1320 		{ "tls-require",       	TLS_REQUIRE },
1321 		{ "to",			TO },
1322 		{ "userbase",		USERBASE },
1323 		{ "verify",		VERIFY },
1324 		{ "via",		VIA },
1325 		{ "virtual",		VIRTUAL },
1326 	};
1327 	const struct keywords	*p;
1328 
1329 	p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
1330 	    sizeof(keywords[0]), kw_cmp);
1331 
1332 	if (p)
1333 		return (p->k_val);
1334 	else
1335 		return (STRING);
1336 }
1337 
1338 #define MAXPUSHBACK	128
1339 
1340 u_char	*parsebuf;
1341 int	 parseindex;
1342 u_char	 pushback_buffer[MAXPUSHBACK];
1343 int	 pushback_index = 0;
1344 
1345 int
1346 lgetc(int quotec)
1347 {
1348 	int		c, next;
1349 
1350 	if (parsebuf) {
1351 		/* Read character from the parsebuffer instead of input. */
1352 		if (parseindex >= 0) {
1353 			c = parsebuf[parseindex++];
1354 			if (c != '\0')
1355 				return (c);
1356 			parsebuf = NULL;
1357 		} else
1358 			parseindex++;
1359 	}
1360 
1361 	if (pushback_index)
1362 		return (pushback_buffer[--pushback_index]);
1363 
1364 	if (quotec) {
1365 		if ((c = getc(file->stream)) == EOF) {
1366 			yyerror("reached end of file while parsing "
1367 			    "quoted string");
1368 			if (file == topfile || popfile() == EOF)
1369 				return (EOF);
1370 			return (quotec);
1371 		}
1372 		return (c);
1373 	}
1374 
1375 	while ((c = getc(file->stream)) == '\\') {
1376 		next = getc(file->stream);
1377 		if (next != '\n') {
1378 			c = next;
1379 			break;
1380 		}
1381 		yylval.lineno = file->lineno;
1382 		file->lineno++;
1383 	}
1384 
1385 	while (c == EOF) {
1386 		if (file == topfile || popfile() == EOF)
1387 			return (EOF);
1388 		c = getc(file->stream);
1389 	}
1390 	return (c);
1391 }
1392 
1393 int
1394 lungetc(int c)
1395 {
1396 	if (c == EOF)
1397 		return (EOF);
1398 	if (parsebuf) {
1399 		parseindex--;
1400 		if (parseindex >= 0)
1401 			return (c);
1402 	}
1403 	if (pushback_index < MAXPUSHBACK-1)
1404 		return (pushback_buffer[pushback_index++] = c);
1405 	else
1406 		return (EOF);
1407 }
1408 
1409 int
1410 findeol(void)
1411 {
1412 	int	c;
1413 
1414 	parsebuf = NULL;
1415 	pushback_index = 0;
1416 
1417 	/* skip to either EOF or the first real EOL */
1418 	while (1) {
1419 		c = lgetc(0);
1420 		if (c == '\n') {
1421 			file->lineno++;
1422 			break;
1423 		}
1424 		if (c == EOF)
1425 			break;
1426 	}
1427 	return (ERROR);
1428 }
1429 
1430 int
1431 yylex(void)
1432 {
1433 	u_char	 buf[8096];
1434 	u_char	*p, *val;
1435 	int	 quotec, next, c;
1436 	int	 token;
1437 
1438 top:
1439 	p = buf;
1440 	while ((c = lgetc(0)) == ' ' || c == '\t')
1441 		; /* nothing */
1442 
1443 	yylval.lineno = file->lineno;
1444 	if (c == '#')
1445 		while ((c = lgetc(0)) != '\n' && c != EOF)
1446 			; /* nothing */
1447 	if (c == '$' && parsebuf == NULL) {
1448 		while (1) {
1449 			if ((c = lgetc(0)) == EOF)
1450 				return (0);
1451 
1452 			if (p + 1 >= buf + sizeof(buf) - 1) {
1453 				yyerror("string too long");
1454 				return (findeol());
1455 			}
1456 			if (isalnum(c) || c == '_') {
1457 				*p++ = c;
1458 				continue;
1459 			}
1460 			*p = '\0';
1461 			lungetc(c);
1462 			break;
1463 		}
1464 		val = symget(buf);
1465 		if (val == NULL) {
1466 			yyerror("macro '%s' not defined", buf);
1467 			return (findeol());
1468 		}
1469 		parsebuf = val;
1470 		parseindex = 0;
1471 		goto top;
1472 	}
1473 
1474 	switch (c) {
1475 	case '\'':
1476 	case '"':
1477 		quotec = c;
1478 		while (1) {
1479 			if ((c = lgetc(quotec)) == EOF)
1480 				return (0);
1481 			if (c == '\n') {
1482 				file->lineno++;
1483 				continue;
1484 			} else if (c == '\\') {
1485 				if ((next = lgetc(quotec)) == EOF)
1486 					return (0);
1487 				if (next == quotec || c == ' ' || c == '\t')
1488 					c = next;
1489 				else if (next == '\n') {
1490 					file->lineno++;
1491 					continue;
1492 				} else
1493 					lungetc(next);
1494 			} else if (c == quotec) {
1495 				*p = '\0';
1496 				break;
1497 			} else if (c == '\0') {
1498 				yyerror("syntax error");
1499 				return (findeol());
1500 			}
1501 			if (p + 1 >= buf + sizeof(buf) - 1) {
1502 				yyerror("string too long");
1503 				return (findeol());
1504 			}
1505 			*p++ = c;
1506 		}
1507 		yylval.v.string = strdup(buf);
1508 		if (yylval.v.string == NULL)
1509 			err(1, "yylex: strdup");
1510 		return (STRING);
1511 	}
1512 
1513 #define allowed_to_end_number(x) \
1514 	(isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
1515 
1516 	if (c == '-' || isdigit(c)) {
1517 		do {
1518 			*p++ = c;
1519 			if ((unsigned)(p-buf) >= sizeof(buf)) {
1520 				yyerror("string too long");
1521 				return (findeol());
1522 			}
1523 		} while ((c = lgetc(0)) != EOF && isdigit(c));
1524 		lungetc(c);
1525 		if (p == buf + 1 && buf[0] == '-')
1526 			goto nodigits;
1527 		if (c == EOF || allowed_to_end_number(c)) {
1528 			const char *errstr = NULL;
1529 
1530 			*p = '\0';
1531 			yylval.v.number = strtonum(buf, LLONG_MIN,
1532 			    LLONG_MAX, &errstr);
1533 			if (errstr) {
1534 				yyerror("\"%s\" invalid number: %s",
1535 				    buf, errstr);
1536 				return (findeol());
1537 			}
1538 			return (NUMBER);
1539 		} else {
1540 nodigits:
1541 			while (p > buf + 1)
1542 				lungetc(*--p);
1543 			c = *--p;
1544 			if (c == '-')
1545 				return (c);
1546 		}
1547 	}
1548 
1549 	if (c == '=') {
1550 		if ((c = lgetc(0)) != EOF && c == '>')
1551 			return (ARROW);
1552 		lungetc(c);
1553 		c = '=';
1554 	}
1555 
1556 #define allowed_in_string(x) \
1557 	(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
1558 	x != '{' && x != '}' && x != '<' && x != '>' && \
1559 	x != '!' && x != '=' && x != '#' && \
1560 	x != ','))
1561 
1562 	if (isalnum(c) || c == ':' || c == '_') {
1563 		do {
1564 			*p++ = c;
1565 			if ((unsigned)(p-buf) >= sizeof(buf)) {
1566 				yyerror("string too long");
1567 				return (findeol());
1568 			}
1569 		} while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
1570 		lungetc(c);
1571 		*p = '\0';
1572 		if ((token = lookup(buf)) == STRING)
1573 			if ((yylval.v.string = strdup(buf)) == NULL)
1574 				err(1, "yylex: strdup");
1575 		return (token);
1576 	}
1577 	if (c == '\n') {
1578 		yylval.lineno = file->lineno;
1579 		file->lineno++;
1580 	}
1581 	if (c == EOF)
1582 		return (0);
1583 	return (c);
1584 }
1585 
1586 int
1587 check_file_secrecy(int fd, const char *fname)
1588 {
1589 	struct stat	st;
1590 
1591 	if (fstat(fd, &st)) {
1592 		log_warn("warn: cannot stat %s", fname);
1593 		return (-1);
1594 	}
1595 	if (st.st_uid != 0 && st.st_uid != getuid()) {
1596 		log_warnx("warn: %s: owner not root or current user", fname);
1597 		return (-1);
1598 	}
1599 	if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) {
1600 		log_warnx("warn: %s: group/world readable/writeable", fname);
1601 		return (-1);
1602 	}
1603 	return (0);
1604 }
1605 
1606 struct file *
1607 pushfile(const char *name, int secret)
1608 {
1609 	struct file	*nfile;
1610 
1611 	if ((nfile = calloc(1, sizeof(struct file))) == NULL) {
1612 		log_warn("warn: malloc");
1613 		return (NULL);
1614 	}
1615 	if ((nfile->name = strdup(name)) == NULL) {
1616 		log_warn("warn: malloc");
1617 		free(nfile);
1618 		return (NULL);
1619 	}
1620 	if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
1621 		log_warn("warn: %s", nfile->name);
1622 		free(nfile->name);
1623 		free(nfile);
1624 		return (NULL);
1625 	} else if (secret &&
1626 	    check_file_secrecy(fileno(nfile->stream), nfile->name)) {
1627 		fclose(nfile->stream);
1628 		free(nfile->name);
1629 		free(nfile);
1630 		return (NULL);
1631 	}
1632 	nfile->lineno = 1;
1633 	TAILQ_INSERT_TAIL(&files, nfile, entry);
1634 	return (nfile);
1635 }
1636 
1637 int
1638 popfile(void)
1639 {
1640 	struct file	*prev;
1641 
1642 	if ((prev = TAILQ_PREV(file, files, entry)) != NULL)
1643 		prev->errors += file->errors;
1644 
1645 	TAILQ_REMOVE(&files, file, entry);
1646 	fclose(file->stream);
1647 	free(file->name);
1648 	free(file);
1649 	file = prev;
1650 	return (file ? 0 : EOF);
1651 }
1652 
1653 int
1654 parse_config(struct smtpd *x_conf, const char *filename, int opts)
1655 {
1656 	struct sym     *sym, *next;
1657 	struct table   *t;
1658 	char		hostname[SMTPD_MAXHOSTNAMELEN];
1659 	char		hostname_copy[SMTPD_MAXHOSTNAMELEN];
1660 
1661 	if (! getmailname(hostname, sizeof hostname))
1662 		return (-1);
1663 
1664 	conf = x_conf;
1665 	memset(conf, 0, sizeof(*conf));
1666 
1667 	(void)strlcpy(conf->sc_hostname, hostname, sizeof(conf->sc_hostname));
1668 
1669 	conf->sc_maxsize = DEFAULT_MAX_BODY_SIZE;
1670 
1671 	conf->sc_tables_dict = calloc(1, sizeof(*conf->sc_tables_dict));
1672 	conf->sc_rules = calloc(1, sizeof(*conf->sc_rules));
1673 	conf->sc_listeners = calloc(1, sizeof(*conf->sc_listeners));
1674 	conf->sc_pki_dict = calloc(1, sizeof(*conf->sc_pki_dict));
1675 	conf->sc_ssl_dict = calloc(1, sizeof(*conf->sc_ssl_dict));
1676 	conf->sc_limits_dict = calloc(1, sizeof(*conf->sc_limits_dict));
1677 
1678 	/* Report mails delayed for more than 4 hours */
1679 	conf->sc_bounce_warn[0] = 3600 * 4;
1680 
1681 	if (conf->sc_tables_dict == NULL	||
1682 	    conf->sc_rules == NULL		||
1683 	    conf->sc_listeners == NULL		||
1684 	    conf->sc_pki_dict == NULL		||
1685 	    conf->sc_limits_dict == NULL) {
1686 		log_warn("warn: cannot allocate memory");
1687 		free(conf->sc_tables_dict);
1688 		free(conf->sc_rules);
1689 		free(conf->sc_listeners);
1690 		free(conf->sc_pki_dict);
1691 		free(conf->sc_ssl_dict);
1692 		free(conf->sc_limits_dict);
1693 		return (-1);
1694 	}
1695 
1696 	errors = 0;
1697 
1698 	table = NULL;
1699 	rule = NULL;
1700 
1701 	dict_init(&conf->sc_filters);
1702 
1703 	dict_init(conf->sc_pki_dict);
1704 	dict_init(conf->sc_ssl_dict);
1705 	dict_init(conf->sc_tables_dict);
1706 
1707 	dict_init(conf->sc_limits_dict);
1708 	limits = xcalloc(1, sizeof(*limits), "mta_limits");
1709 	limit_mta_set_defaults(limits);
1710 	dict_xset(conf->sc_limits_dict, "default", limits);
1711 
1712 	TAILQ_INIT(conf->sc_listeners);
1713 	TAILQ_INIT(conf->sc_rules);
1714 
1715 	conf->sc_qexpire = SMTPD_QUEUE_EXPIRY;
1716 	conf->sc_opts = opts;
1717 
1718 	conf->sc_mta_max_deferred = 100;
1719 	conf->sc_scheduler_max_inflight = 5000;
1720 	conf->sc_scheduler_max_schedule = 10;
1721 	conf->sc_scheduler_max_evp_batch_size = 256;
1722 	conf->sc_scheduler_max_msg_batch_size = 1024;
1723 
1724 	conf->sc_mda_max_session = 50;
1725 	conf->sc_mda_max_user_session = 7;
1726 	conf->sc_mda_task_hiwat = 50;
1727 	conf->sc_mda_task_lowat = 30;
1728 	conf->sc_mda_task_release = 10;
1729 
1730 	if ((file = pushfile(filename, 0)) == NULL) {
1731 		purge_config(PURGE_EVERYTHING);
1732 		return (-1);
1733 	}
1734 	topfile = file;
1735 
1736 	/*
1737 	 * declare special "localhost", "anyhost" and "localnames" tables
1738 	 */
1739 	set_local(hostname);
1740 
1741 	t = table_create("static", "<anydestination>", NULL, NULL);
1742 	t->t_type = T_LIST;
1743 	table_add(t, "*", NULL);
1744 
1745 	/* can't truncate here */
1746 	(void)strlcpy(hostname_copy, hostname, sizeof hostname_copy);
1747 
1748 	hostname_copy[strcspn(hostname_copy, ".")] = '\0';
1749 	if (strcmp(hostname, hostname_copy) != 0)
1750 		table_add(t, hostname_copy, NULL);
1751 
1752 	table_create("getpwnam", "<getpwnam>", NULL, NULL);
1753 
1754 	/*
1755 	 * parse configuration
1756 	 */
1757 	setservent(1);
1758 	yyparse();
1759 	errors = file->errors;
1760 	popfile();
1761 	endservent();
1762 
1763 	/* Free macros and check which have not been used. */
1764 	for (sym = TAILQ_FIRST(&symhead); sym != NULL; sym = next) {
1765 		next = TAILQ_NEXT(sym, entry);
1766 		if ((conf->sc_opts & SMTPD_OPT_VERBOSE) && !sym->used)
1767 			fprintf(stderr, "warning: macro '%s' not "
1768 			    "used\n", sym->nam);
1769 		if (!sym->persist) {
1770 			free(sym->nam);
1771 			free(sym->val);
1772 			TAILQ_REMOVE(&symhead, sym, entry);
1773 			free(sym);
1774 		}
1775 	}
1776 
1777 	if (TAILQ_EMPTY(conf->sc_rules)) {
1778 		log_warnx("warn: no rules, nothing to do");
1779 		errors++;
1780 	}
1781 
1782 	if (errors) {
1783 		purge_config(PURGE_EVERYTHING);
1784 		return (-1);
1785 	}
1786 
1787 	return (0);
1788 }
1789 
1790 int
1791 symset(const char *nam, const char *val, int persist)
1792 {
1793 	struct sym	*sym;
1794 
1795 	for (sym = TAILQ_FIRST(&symhead); sym && strcmp(nam, sym->nam);
1796 	    sym = TAILQ_NEXT(sym, entry))
1797 		;	/* nothing */
1798 
1799 	if (sym != NULL) {
1800 		if (sym->persist == 1)
1801 			return (0);
1802 		else {
1803 			free(sym->nam);
1804 			free(sym->val);
1805 			TAILQ_REMOVE(&symhead, sym, entry);
1806 			free(sym);
1807 		}
1808 	}
1809 	if ((sym = calloc(1, sizeof(*sym))) == NULL)
1810 		return (-1);
1811 
1812 	sym->nam = strdup(nam);
1813 	if (sym->nam == NULL) {
1814 		free(sym);
1815 		return (-1);
1816 	}
1817 	sym->val = strdup(val);
1818 	if (sym->val == NULL) {
1819 		free(sym->nam);
1820 		free(sym);
1821 		return (-1);
1822 	}
1823 	sym->used = 0;
1824 	sym->persist = persist;
1825 	TAILQ_INSERT_TAIL(&symhead, sym, entry);
1826 	return (0);
1827 }
1828 
1829 int
1830 cmdline_symset(char *s)
1831 {
1832 	char	*sym, *val;
1833 	int	ret;
1834 	size_t	len;
1835 
1836 	if ((val = strrchr(s, '=')) == NULL)
1837 		return (-1);
1838 
1839 	len = strlen(s) - strlen(val) + 1;
1840 	if ((sym = malloc(len)) == NULL)
1841 		errx(1, "cmdline_symset: malloc");
1842 
1843 	(void)strlcpy(sym, s, len);
1844 
1845 	ret = symset(sym, val + 1, 1);
1846 	free(sym);
1847 
1848 	return (ret);
1849 }
1850 
1851 char *
1852 symget(const char *nam)
1853 {
1854 	struct sym	*sym;
1855 
1856 	TAILQ_FOREACH(sym, &symhead, entry)
1857 		if (strcmp(nam, sym->nam) == 0) {
1858 			sym->used = 1;
1859 			return (sym->val);
1860 		}
1861 	return (NULL);
1862 }
1863 
1864 static void
1865 create_listener(struct listenerlist *ll,  struct listen_opts *lo)
1866 {
1867 	uint16_t	flags;
1868 
1869 	if (lo->port != 0 && lo->ssl == F_SSL)
1870 		errx(1, "invalid listen option: tls/smtps on same port");
1871 
1872 	if (lo->auth != 0 && !lo->ssl)
1873 		errx(1, "invalid listen option: auth requires tls/smtps");
1874 
1875 	if (lo->pki && !lo->ssl)
1876 		errx(1, "invalid listen option: pki requires tls/smtps");
1877 
1878 	flags = lo->flags;
1879 
1880 	if (lo->port) {
1881 		lo->flags = lo->ssl|lo->auth|flags;
1882 		lo->port = htons(lo->port);
1883 		if (! interface(ll, lo))
1884 			if (host(ll, lo) <= 0)
1885 				errx(1, "invalid virtual ip or interface: %s", lo->ifx);
1886 	}
1887 	else {
1888 		if (lo->ssl & F_SMTPS) {
1889 			lo->port = htons(465);
1890 			lo->flags = F_SMTPS|lo->auth|flags;
1891 			if (! interface(ll, lo))
1892 				if (host(ll, lo) <= 0)
1893 					errx(1, "invalid virtual ip or interface: %s", lo->ifx);
1894 		}
1895 
1896 		if (! lo->ssl || (lo->ssl & F_STARTTLS)) {
1897 			lo->port = htons(25);
1898 			lo->flags = lo->auth|flags;
1899 			if (lo->ssl & F_STARTTLS)
1900 				lo->flags |= F_STARTTLS;
1901 			if (! interface(ll, lo))
1902 				if (host(ll, lo) <= 0)
1903 					errx(1, "invalid virtual ip or interface: %s", lo->ifx);
1904 		}
1905 	}
1906 }
1907 
1908 static void
1909 config_listener(struct listener *h,  struct listen_opts *lo)
1910 {
1911 	h->fd = -1;
1912 	h->port = lo->port;
1913 	h->flags = lo->flags;
1914 
1915 	if (lo->hostname == NULL)
1916 		lo->hostname = conf->sc_hostname;
1917 
1918 	if (lo->filtername) {
1919 		if (dict_get(&conf->sc_filters, lo->filtername) == NULL) {
1920 			log_warnx("undefined filter: %s", lo->filtername);
1921 			fatalx(NULL);
1922 		}
1923 		(void)strlcpy(h->filter, lo->filtername, sizeof(h->filter));
1924 	}
1925 
1926 	h->pki_name[0] = '\0';
1927 
1928 	if (lo->authtable != NULL)
1929 		(void)strlcpy(h->authtable, lo->authtable->t_name, sizeof(h->authtable));
1930 	if (lo->pki != NULL) {
1931 		if (! lowercase(h->pki_name, lo->pki, sizeof(h->pki_name))) {
1932 			log_warnx("pki name too long: %s", lo->pki);
1933 			fatalx(NULL);
1934 		}
1935 		if (dict_get(conf->sc_pki_dict, h->pki_name) == NULL) {
1936 			log_warnx("pki name not found: %s", lo->pki);
1937 			fatalx(NULL);
1938 		}
1939 	}
1940 	if (lo->tag != NULL)
1941 		(void)strlcpy(h->tag, lo->tag, sizeof(h->tag));
1942 
1943 	(void)strlcpy(h->hostname, lo->hostname, sizeof(h->hostname));
1944 	if (lo->hostnametable)
1945 		(void)strlcpy(h->hostnametable, lo->hostnametable->t_name, sizeof(h->hostnametable));
1946 
1947 	if (lo->ssl & F_TLS_VERIFY)
1948 		h->flags |= F_TLS_VERIFY;
1949 }
1950 
1951 struct listener *
1952 host_v4(const char *s, in_port_t port)
1953 {
1954 	struct in_addr		 ina;
1955 	struct sockaddr_in	*sain;
1956 	struct listener		*h;
1957 
1958 	memset(&ina, 0, sizeof(ina));
1959 	if (inet_pton(AF_INET, s, &ina) != 1)
1960 		return (NULL);
1961 
1962 	h = xcalloc(1, sizeof(*h), "host_v4");
1963 	sain = (struct sockaddr_in *)&h->ss;
1964 	sain->sin_len = sizeof(struct sockaddr_in);
1965 	sain->sin_family = AF_INET;
1966 	sain->sin_addr.s_addr = ina.s_addr;
1967 	sain->sin_port = port;
1968 
1969 	return (h);
1970 }
1971 
1972 struct listener *
1973 host_v6(const char *s, in_port_t port)
1974 {
1975 	struct in6_addr		 ina6;
1976 	struct sockaddr_in6	*sin6;
1977 	struct listener		*h;
1978 
1979 	memset(&ina6, 0, sizeof(ina6));
1980 	if (inet_pton(AF_INET6, s, &ina6) != 1)
1981 		return (NULL);
1982 
1983 	h = xcalloc(1, sizeof(*h), "host_v6");
1984 	sin6 = (struct sockaddr_in6 *)&h->ss;
1985 	sin6->sin6_len = sizeof(struct sockaddr_in6);
1986 	sin6->sin6_family = AF_INET6;
1987 	sin6->sin6_port = port;
1988 	memcpy(&sin6->sin6_addr, &ina6, sizeof(ina6));
1989 
1990 	return (h);
1991 }
1992 
1993 int
1994 host_dns(struct listenerlist *al, struct listen_opts *lo)
1995 {
1996 	struct addrinfo		 hints, *res0, *res;
1997 	int			 error, cnt = 0;
1998 	struct sockaddr_in	*sain;
1999 	struct sockaddr_in6	*sin6;
2000 	struct listener		*h;
2001 
2002 	memset(&hints, 0, sizeof(hints));
2003 	hints.ai_family = PF_UNSPEC;
2004 	hints.ai_socktype = SOCK_STREAM;
2005 	error = getaddrinfo(lo->ifx, NULL, &hints, &res0);
2006 	if (error == EAI_AGAIN || error == EAI_NODATA || error == EAI_NONAME)
2007 		return (0);
2008 	if (error) {
2009 		log_warnx("warn: host_dns: could not parse \"%s\": %s", lo->ifx,
2010 		    gai_strerror(error));
2011 		return (-1);
2012 	}
2013 
2014 	for (res = res0; res; res = res->ai_next) {
2015 		if (res->ai_family != AF_INET &&
2016 		    res->ai_family != AF_INET6)
2017 			continue;
2018 		h = xcalloc(1, sizeof(*h), "host_dns");
2019 
2020 		h->ss.ss_family = res->ai_family;
2021 		if (res->ai_family == AF_INET) {
2022 			sain = (struct sockaddr_in *)&h->ss;
2023 			sain->sin_len = sizeof(struct sockaddr_in);
2024 			sain->sin_addr.s_addr = ((struct sockaddr_in *)
2025 			    res->ai_addr)->sin_addr.s_addr;
2026 			sain->sin_port = lo->port;
2027 		} else {
2028 			sin6 = (struct sockaddr_in6 *)&h->ss;
2029 			sin6->sin6_len = sizeof(struct sockaddr_in6);
2030 			memcpy(&sin6->sin6_addr, &((struct sockaddr_in6 *)
2031 			    res->ai_addr)->sin6_addr, sizeof(struct in6_addr));
2032 			sin6->sin6_port = lo->port;
2033 		}
2034 
2035 		config_listener(h, lo);
2036 
2037 		TAILQ_INSERT_HEAD(al, h, entry);
2038 		cnt++;
2039 	}
2040 
2041 	freeaddrinfo(res0);
2042 	return (cnt);
2043 }
2044 
2045 int
2046 host(struct listenerlist *al, struct listen_opts *lo)
2047 {
2048 	struct listener *h;
2049 
2050 	h = host_v4(lo->ifx, lo->port);
2051 
2052 	/* IPv6 address? */
2053 	if (h == NULL)
2054 		h = host_v6(lo->ifx, lo->port);
2055 
2056 	if (h != NULL) {
2057 		config_listener(h, lo);
2058 		TAILQ_INSERT_HEAD(al, h, entry);
2059 		return (1);
2060 	}
2061 
2062 	return (host_dns(al, lo));
2063 }
2064 
2065 int
2066 interface(struct listenerlist *al, struct listen_opts *lo)
2067 {
2068 	struct ifaddrs *ifap, *p;
2069 	struct sockaddr_in	*sain;
2070 	struct sockaddr_in6	*sin6;
2071 	struct listener		*h;
2072 	int			ret = 0;
2073 
2074 	if (getifaddrs(&ifap) == -1)
2075 		fatal("getifaddrs");
2076 
2077 	for (p = ifap; p != NULL; p = p->ifa_next) {
2078 		if (p->ifa_addr == NULL)
2079 			continue;
2080 		if (strcmp(p->ifa_name, lo->ifx) != 0 &&
2081 		    ! is_if_in_group(p->ifa_name, lo->ifx))
2082 			continue;
2083 		if (lo->family != AF_UNSPEC && lo->family != p->ifa_addr->sa_family)
2084 			continue;
2085 
2086 		h = xcalloc(1, sizeof(*h), "interface");
2087 
2088 		switch (p->ifa_addr->sa_family) {
2089 		case AF_INET:
2090 			sain = (struct sockaddr_in *)&h->ss;
2091 			*sain = *(struct sockaddr_in *)p->ifa_addr;
2092 			sain->sin_len = sizeof(struct sockaddr_in);
2093 			sain->sin_port = lo->port;
2094 			break;
2095 
2096 		case AF_INET6:
2097 			sin6 = (struct sockaddr_in6 *)&h->ss;
2098 			*sin6 = *(struct sockaddr_in6 *)p->ifa_addr;
2099 			sin6->sin6_len = sizeof(struct sockaddr_in6);
2100 			sin6->sin6_port = lo->port;
2101 			break;
2102 
2103 		default:
2104 			free(h);
2105 			continue;
2106 		}
2107 
2108 		config_listener(h, lo);
2109 		ret = 1;
2110 		TAILQ_INSERT_HEAD(al, h, entry);
2111 	}
2112 
2113 	freeifaddrs(ifap);
2114 
2115 	return ret;
2116 }
2117 
2118 void
2119 set_local(const char *hostname)
2120 {
2121 	struct table	*t;
2122 
2123 	t = table_create("static", "<localnames>", NULL, NULL);
2124 	t->t_type = T_LIST;
2125 	table_add(t, "localhost", NULL);
2126 	table_add(t, hostname, NULL);
2127 
2128 	set_localaddrs(t);
2129 }
2130 
2131 void
2132 set_localaddrs(struct table *localnames)
2133 {
2134 	struct ifaddrs *ifap, *p;
2135 	struct sockaddr_storage ss;
2136 	struct sockaddr_in	*sain;
2137 	struct sockaddr_in6	*sin6;
2138 	struct table		*t;
2139 	char buf[NI_MAXHOST + 5];
2140 
2141 	t = table_create("static", "<anyhost>", NULL, NULL);
2142 	table_add(t, "local", NULL);
2143 	table_add(t, "0.0.0.0/0", NULL);
2144 	table_add(t, "::/0", NULL);
2145 
2146 	if (getifaddrs(&ifap) == -1)
2147 		fatal("getifaddrs");
2148 
2149 	t = table_create("static", "<localhost>", NULL, NULL);
2150 	table_add(t, "local", NULL);
2151 
2152 	for (p = ifap; p != NULL; p = p->ifa_next) {
2153 		if (p->ifa_addr == NULL)
2154 			continue;
2155 		switch (p->ifa_addr->sa_family) {
2156 		case AF_INET:
2157 			sain = (struct sockaddr_in *)&ss;
2158 			*sain = *(struct sockaddr_in *)p->ifa_addr;
2159 			sain->sin_len = sizeof(struct sockaddr_in);
2160 			table_add(t, ss_to_text(&ss), NULL);
2161 			table_add(localnames, ss_to_text(&ss), NULL);
2162 			(void)snprintf(buf, sizeof buf, "[%s]", ss_to_text(&ss));
2163 			table_add(localnames, buf, NULL);
2164 			break;
2165 
2166 		case AF_INET6:
2167 			sin6 = (struct sockaddr_in6 *)&ss;
2168 			*sin6 = *(struct sockaddr_in6 *)p->ifa_addr;
2169 			sin6->sin6_len = sizeof(struct sockaddr_in6);
2170 			table_add(t, ss_to_text(&ss), NULL);
2171 			table_add(localnames, ss_to_text(&ss), NULL);
2172 			(void)snprintf(buf, sizeof buf, "[%s]", ss_to_text(&ss));
2173 			table_add(localnames, buf, NULL);
2174 			(void)snprintf(buf, sizeof buf, "[ipv6:%s]", ss_to_text(&ss));
2175 			table_add(localnames, buf, NULL);
2176 			break;
2177 		}
2178 	}
2179 
2180 	freeifaddrs(ifap);
2181 }
2182 
2183 int
2184 delaytonum(char *str)
2185 {
2186 	unsigned int     factor;
2187 	size_t           len;
2188 	const char      *errstr = NULL;
2189 	int              delay;
2190 
2191 	/* we need at least 1 digit and 1 unit */
2192 	len = strlen(str);
2193 	if (len < 2)
2194 		goto bad;
2195 
2196 	switch(str[len - 1]) {
2197 
2198 	case 's':
2199 		factor = 1;
2200 		break;
2201 
2202 	case 'm':
2203 		factor = 60;
2204 		break;
2205 
2206 	case 'h':
2207 		factor = 60 * 60;
2208 		break;
2209 
2210 	case 'd':
2211 		factor = 24 * 60 * 60;
2212 		break;
2213 
2214 	default:
2215 		goto bad;
2216 	}
2217 
2218 	str[len - 1] = '\0';
2219 	delay = strtonum(str, 1, INT_MAX / factor, &errstr);
2220 	if (errstr)
2221 		goto bad;
2222 
2223 	return (delay * factor);
2224 
2225 bad:
2226 	return (-1);
2227 }
2228 
2229 int
2230 is_if_in_group(const char *ifname, const char *groupname)
2231 {
2232         unsigned int		 len;
2233         struct ifgroupreq        ifgr;
2234         struct ifg_req          *ifg;
2235 	int			 s;
2236 	int			 ret = 0;
2237 
2238 	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
2239 		err(1, "socket");
2240 
2241         memset(&ifgr, 0, sizeof(ifgr));
2242         if (strlcpy(ifgr.ifgr_name, ifname, IFNAMSIZ) >= IFNAMSIZ)
2243 		errx(1, "interface name too large");
2244 
2245         if (ioctl(s, SIOCGIFGROUP, (caddr_t)&ifgr) == -1) {
2246                 if (errno == EINVAL || errno == ENOTTY)
2247 			goto end;
2248 		err(1, "SIOCGIFGROUP");
2249         }
2250 
2251         len = ifgr.ifgr_len;
2252         ifgr.ifgr_groups =
2253             (struct ifg_req *)xcalloc(len/sizeof(struct ifg_req),
2254 		sizeof(struct ifg_req), "is_if_in_group");
2255         if (ioctl(s, SIOCGIFGROUP, (caddr_t)&ifgr) == -1)
2256                 err(1, "SIOCGIFGROUP");
2257 
2258         ifg = ifgr.ifgr_groups;
2259         for (; ifg && len >= sizeof(struct ifg_req); ifg++) {
2260                 len -= sizeof(struct ifg_req);
2261 		if (strcmp(ifg->ifgrq_group, groupname) == 0) {
2262 			ret = 1;
2263 			break;
2264 		}
2265         }
2266         free(ifgr.ifgr_groups);
2267 
2268 end:
2269 	close(s);
2270 	return ret;
2271 }
2272 
2273 static struct filter_conf *
2274 create_filter_proc(char *name, char *prog)
2275 {
2276 	struct filter_conf	*f;
2277 	char			*path;
2278 
2279 	if (dict_get(&conf->sc_filters, name)) {
2280 		yyerror("filter \"%s\" already defined", name);
2281 		return (NULL);
2282 	}
2283 
2284 	if (asprintf(&path, "%s/filter-%s", PATH_LIBEXEC, prog) == -1) {
2285 		yyerror("filter \"%s\" asprintf failed", name);
2286 		return (0);
2287 	}
2288 
2289 	f = xcalloc(1, sizeof(*f), "create_filter");
2290 	f->path = path;
2291 	f->name = name;
2292 	f->argv[f->argc++] = name;
2293 
2294 	dict_xset(&conf->sc_filters, name, f);
2295 
2296 	return (f);
2297 }
2298 
2299 static struct filter_conf *
2300 create_filter_chain(char *name)
2301 {
2302 	struct filter_conf	*f;
2303 
2304 	if (dict_get(&conf->sc_filters, name)) {
2305 		yyerror("filter \"%s\" already defined", name);
2306 		return (NULL);
2307 	}
2308 
2309 	f = xcalloc(1, sizeof(*f), "create_filter_chain");
2310 	f->chain = 1;
2311 	f->name = name;
2312 
2313 	dict_xset(&conf->sc_filters, name, f);
2314 
2315 	return (f);
2316 }
2317 
2318 static int
2319 add_filter_arg(struct filter_conf *f, char *arg)
2320 {
2321 	if (f->argc == MAX_FILTER_ARGS) {
2322 		yyerror("filter \"%s\" is full", f->name);
2323 		return (0);
2324 	}
2325 
2326 	if (f->chain) {
2327 		if (dict_get(&conf->sc_filters, arg) == NULL) {
2328 			yyerror("undefined filter \"%s\"", arg);
2329 			return (0);
2330 		}
2331 		if (dict_get(&conf->sc_filters, arg) == f) {
2332 			yyerror("filter chain cannot contain itself");
2333 			return (0);
2334 		}
2335 	}
2336 
2337 	f->argv[f->argc++] = arg;
2338 
2339 	return (1);
2340 }
2341