xref: /openbsd/usr.sbin/smtpd/parse.y (revision d3140113)
1 /*	$OpenBSD: parse.y,v 1.289 2021/06/14 17:58:15 eric 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/stat.h>
26 #include <sys/ioctl.h>
27 
28 #include <net/if.h>
29 #include <netinet/in.h>
30 
31 #include <arpa/inet.h>
32 #include <ctype.h>
33 #include <errno.h>
34 #include <ifaddrs.h>
35 #include <inttypes.h>
36 #include <resolv.h>
37 #include <syslog.h>
38 #include <unistd.h>
39 #include <util.h>
40 
41 #include "smtpd.h"
42 #include "ssl.h"
43 #include "log.h"
44 
45 TAILQ_HEAD(files, file)		 files = TAILQ_HEAD_INITIALIZER(files);
46 static struct file {
47 	TAILQ_ENTRY(file)	 entry;
48 	FILE			*stream;
49 	char			*name;
50 	size_t			 ungetpos;
51 	size_t			 ungetsize;
52 	u_char			*ungetbuf;
53 	int			 eof_reached;
54 	int			 lineno;
55 	int			 errors;
56 } *file, *topfile;
57 struct file	*pushfile(const char *, int);
58 int		 popfile(void);
59 int		 check_file_secrecy(int, const char *);
60 int		 yyparse(void);
61 int		 yylex(void);
62 int		 kw_cmp(const void *, const void *);
63 int		 lookup(char *);
64 int		 igetc(void);
65 int		 lgetc(int);
66 void		 lungetc(int);
67 int		 findeol(void);
68 int		 yyerror(const char *, ...)
69     __attribute__((__format__ (printf, 1, 2)))
70     __attribute__((__nonnull__ (1)));
71 
72 TAILQ_HEAD(symhead, sym)	 symhead = TAILQ_HEAD_INITIALIZER(symhead);
73 struct sym {
74 	TAILQ_ENTRY(sym)	 entry;
75 	int			 used;
76 	int			 persist;
77 	char			*nam;
78 	char			*val;
79 };
80 int		 symset(const char *, const char *, int);
81 char		*symget(const char *);
82 
83 struct smtpd		*conf = NULL;
84 static int		 errors = 0;
85 
86 struct table		*table = NULL;
87 struct mta_limits	*limits;
88 static struct pki	*pki;
89 static struct ca	*sca;
90 
91 struct dispatcher	*dsp;
92 struct rule		*rule;
93 struct filter_proc	*processor;
94 struct filter_config	*filter_config;
95 static uint32_t		 last_dynchain_id = 1;
96 
97 enum listen_options {
98 	LO_FAMILY	= 0x000001,
99 	LO_PORT		= 0x000002,
100 	LO_SSL		= 0x000004,
101 	LO_FILTER      	= 0x000008,
102 	LO_PKI      	= 0x000010,
103 	LO_AUTH      	= 0x000020,
104 	LO_TAG      	= 0x000040,
105 	LO_HOSTNAME   	= 0x000080,
106 	LO_HOSTNAMES   	= 0x000100,
107 	LO_MASKSOURCE  	= 0x000200,
108 	LO_NODSN	= 0x000400,
109 	LO_SENDERS	= 0x000800,
110 	LO_RECEIVEDAUTH = 0x001000,
111 	LO_MASQUERADE	= 0x002000,
112 	LO_CA		= 0x004000,
113 	LO_PROXY       	= 0x008000,
114 };
115 
116 #define PKI_MAX	32
117 static struct listen_opts {
118 	char	       *ifx;
119 	int		family;
120 	in_port_t	port;
121 	uint16_t	ssl;
122 	char	       *filtername;
123 	char	       *pki[PKI_MAX];
124 	int		pkicount;
125 	char	       *tls_ciphers;
126 	char	       *tls_protocols;
127 	char	       *ca;
128 	uint16_t       	auth;
129 	struct table   *authtable;
130 	char	       *tag;
131 	char	       *hostname;
132 	struct table   *hostnametable;
133 	struct table   *sendertable;
134 	uint16_t	flags;
135 
136 	uint32_t       	options;
137 } listen_opts;
138 
139 static void	create_sock_listener(struct listen_opts *);
140 static void	create_if_listener(struct listen_opts *);
141 static void	config_listener(struct listener *, struct listen_opts *);
142 static int	host_v4(struct listen_opts *);
143 static int	host_v6(struct listen_opts *);
144 static int	host_dns(struct listen_opts *);
145 static int	interface(struct listen_opts *);
146 
147 int		 delaytonum(char *);
148 int		 is_if_in_group(const char *, const char *);
149 
150 static int config_lo_mask_source(struct listen_opts *);
151 
152 typedef struct {
153 	union {
154 		int64_t		 number;
155 		struct table	*table;
156 		char		*string;
157 		struct host	*host;
158 		struct mailaddr	*maddr;
159 	} v;
160 	int lineno;
161 } YYSTYPE;
162 
163 %}
164 
165 %token	ACTION ADMD ALIAS ANY ARROW AUTH AUTH_OPTIONAL
166 %token	BACKUP BOUNCE BYPASS
167 %token	CA CERT CHAIN CHROOT CIPHERS COMMIT COMPRESSION CONNECT
168 %token	DATA DATA_LINE DHE DISCONNECT DOMAIN
169 %token	EHLO ENABLE ENCRYPTION ERROR EXPAND_ONLY
170 %token	FCRDNS FILTER FOR FORWARD_ONLY FROM
171 %token	GROUP
172 %token	HELO HELO_SRC HOST HOSTNAME HOSTNAMES
173 %token	INCLUDE INET4 INET6
174 %token	JUNK
175 %token	KEY
176 %token	LIMIT LISTEN LMTP LOCAL
177 %token	MAIL_FROM MAILDIR MASK_SRC MASQUERADE MATCH MAX_MESSAGE_SIZE MAX_DEFERRED MBOX MDA MTA MX
178 %token	NO_DSN NO_VERIFY NOOP
179 %token	ON
180 %token	PHASE PKI PORT PROC PROC_EXEC PROTOCOLS PROXY_V2
181 %token	QUEUE QUIT
182 %token	RCPT_TO RDNS RECIPIENT RECEIVEDAUTH REGEX RELAY REJECT REPORT REWRITE RSET
183 %token	SCHEDULER SENDER SENDERS SMTP SMTP_IN SMTP_OUT SMTPS SOCKET SRC SRS SUB_ADDR_DELIM
184 %token	TABLE TAG TAGGED TLS TLS_REQUIRE TTL
185 %token	USER USERBASE
186 %token	VERIFY VIRTUAL
187 %token	WARN_INTERVAL WRAPPER
188 
189 %token	<v.string>	STRING
190 %token  <v.number>	NUMBER
191 %type	<v.table>	table
192 %type	<v.number>	size negation
193 %type	<v.table>	tables tablenew tableref
194 %%
195 
196 grammar		: /* empty */
197 		| grammar '\n'
198 		| grammar include '\n'
199 		| grammar varset '\n'
200 		| grammar bounce '\n'
201 		| grammar admd '\n'
202 		| grammar ca '\n'
203 		| grammar mda '\n'
204 		| grammar mta '\n'
205 		| grammar pki '\n'
206 		| grammar proc '\n'
207 		| grammar queue '\n'
208 		| grammar scheduler '\n'
209 		| grammar smtp '\n'
210 		| grammar srs '\n'
211 		| grammar listen '\n'
212 		| grammar table '\n'
213 		| grammar dispatcher '\n'
214 		| grammar match '\n'
215 		| grammar filter '\n'
216 		| grammar error '\n'		{ file->errors++; }
217 		;
218 
219 include		: INCLUDE STRING		{
220 			struct file	*nfile;
221 
222 			if ((nfile = pushfile($2, 0)) == NULL) {
223 				yyerror("failed to include file %s", $2);
224 				free($2);
225 				YYERROR;
226 			}
227 			free($2);
228 
229 			file = nfile;
230 			lungetc('\n');
231 		}
232 		;
233 
234 varset		: STRING '=' STRING		{
235 			char *s = $1;
236 			while (*s++) {
237 				if (isspace((unsigned char)*s)) {
238 					yyerror("macro name cannot contain "
239 					    "whitespace");
240 					free($1);
241 					free($3);
242 					YYERROR;
243 				}
244 			}
245 			if (symset($1, $3, 0) == -1)
246 				fatal("cannot store variable");
247 			free($1);
248 			free($3);
249 		}
250 		;
251 
252 comma		: ','
253 		| nl
254 		| /* empty */
255 		;
256 
257 optnl		: '\n' optnl
258 		|
259 		;
260 
261 nl		: '\n' optnl
262 		;
263 
264 negation	: '!'		{ $$ = 1; }
265 		| /* empty */	{ $$ = 0; }
266 		;
267 
268 assign		: '=' | ARROW;
269 
270 
271 keyval		: STRING assign STRING		{
272 			table_add(table, $1, $3);
273 			free($1);
274 			free($3);
275 		}
276 		;
277 
278 keyval_list	: keyval
279 		| keyval comma keyval_list
280 		;
281 
282 stringel	: STRING			{
283 			table_add(table, $1, NULL);
284 			free($1);
285 		}
286 		;
287 
288 string_list	: stringel
289 		| stringel comma string_list
290 		;
291 
292 tableval_list	: string_list			{ }
293 		| keyval_list			{ }
294 		;
295 
296 bounce:
297 BOUNCE WARN_INTERVAL {
298 	memset(conf->sc_bounce_warn, 0, sizeof conf->sc_bounce_warn);
299 } bouncedelays
300 ;
301 
302 
303 admd:
304 ADMD STRING {
305 	size_t i;
306 
307 	for (i = 0; $2[i] != '\0'; i++) {
308 		if (!isprint($2[i])) {
309 			yyerror("not a valid admd");
310 			free($2);
311 			YYERROR;
312 		}
313 	}
314 	conf->sc_admd = $2;
315 };
316 
317 
318 ca:
319 CA STRING {
320 	char buf[HOST_NAME_MAX+1];
321 
322 	/* if not catchall, check that it is a valid domain */
323 	if (strcmp($2, "*") != 0) {
324 		if (!res_hnok($2)) {
325 			yyerror("not a valid domain name: %s", $2);
326 			free($2);
327 			YYERROR;
328 		}
329 	}
330 	xlowercase(buf, $2, sizeof(buf));
331 	free($2);
332 	sca = dict_get(conf->sc_ca_dict, buf);
333 	if (sca == NULL) {
334 		sca = xcalloc(1, sizeof *sca);
335 		(void)strlcpy(sca->ca_name, buf, sizeof(sca->ca_name));
336 		dict_set(conf->sc_ca_dict, sca->ca_name, sca);
337 	}
338 } ca_params
339 ;
340 
341 
342 ca_params_opt:
343 CERT STRING {
344 	sca->ca_cert_file = $2;
345 }
346 ;
347 
348 ca_params:
349 ca_params_opt
350 ;
351 
352 
353 mda:
354 MDA LIMIT limits_mda
355 | MDA WRAPPER STRING STRING {
356 	if (dict_get(conf->sc_mda_wrappers, $3)) {
357 		yyerror("mda wrapper already declared with that name: %s", $3);
358 		YYERROR;
359 	}
360 	dict_set(conf->sc_mda_wrappers, $3, $4);
361 }
362 ;
363 
364 
365 mta:
366 MTA MAX_DEFERRED NUMBER  {
367 	conf->sc_mta_max_deferred = $3;
368 }
369 | MTA LIMIT FOR DOMAIN STRING {
370 	struct mta_limits	*d;
371 
372 	limits = dict_get(conf->sc_limits_dict, $5);
373 	if (limits == NULL) {
374 		limits = xcalloc(1, sizeof(*limits));
375 		dict_xset(conf->sc_limits_dict, $5, limits);
376 		d = dict_xget(conf->sc_limits_dict, "default");
377 		memmove(limits, d, sizeof(*limits));
378 	}
379 	free($5);
380 } limits_mta
381 | MTA LIMIT {
382 	limits = dict_get(conf->sc_limits_dict, "default");
383 } limits_mta
384 ;
385 
386 
387 pki:
388 PKI STRING {
389 	char buf[HOST_NAME_MAX+1];
390 
391 	/* if not catchall, check that it is a valid domain */
392 	if (strcmp($2, "*") != 0) {
393 		if (!res_hnok($2)) {
394 			yyerror("not a valid domain name: %s", $2);
395 			free($2);
396 			YYERROR;
397 		}
398 	}
399 	xlowercase(buf, $2, sizeof(buf));
400 	free($2);
401 	pki = dict_get(conf->sc_pki_dict, buf);
402 	if (pki == NULL) {
403 		pki = xcalloc(1, sizeof *pki);
404 		(void)strlcpy(pki->pki_name, buf, sizeof(pki->pki_name));
405 		dict_set(conf->sc_pki_dict, pki->pki_name, pki);
406 	}
407 } pki_params
408 ;
409 
410 pki_params_opt:
411 CERT STRING {
412 	pki->pki_cert_file = $2;
413 }
414 | KEY STRING {
415 	pki->pki_key_file = $2;
416 }
417 | DHE STRING {
418 	if (strcasecmp($2, "none") == 0)
419 		pki->pki_dhe = 0;
420 	else if (strcasecmp($2, "auto") == 0)
421 		pki->pki_dhe = 1;
422 	else if (strcasecmp($2, "legacy") == 0)
423 		pki->pki_dhe = 2;
424 	else {
425 		yyerror("invalid DHE keyword: %s", $2);
426 		free($2);
427 		YYERROR;
428 	}
429 	free($2);
430 }
431 ;
432 
433 
434 pki_params:
435 pki_params_opt pki_params
436 | /* empty */
437 ;
438 
439 
440 proc:
441 PROC STRING STRING {
442 	if (dict_get(conf->sc_filter_processes_dict, $2)) {
443 		yyerror("processor already exists with that name: %s", $2);
444 		free($2);
445 		free($3);
446 		YYERROR;
447 	}
448 	processor = xcalloc(1, sizeof *processor);
449 	processor->command = $3;
450 } proc_params {
451 	dict_set(conf->sc_filter_processes_dict, $2, processor);
452 	processor = NULL;
453 }
454 ;
455 
456 
457 proc_params_opt:
458 USER STRING {
459 	if (processor->user) {
460 		yyerror("user already specified for this processor");
461 		free($2);
462 		YYERROR;
463 	}
464 	processor->user = $2;
465 }
466 | GROUP STRING {
467 	if (processor->group) {
468 		yyerror("group already specified for this processor");
469 		free($2);
470 		YYERROR;
471 	}
472 	processor->group = $2;
473 }
474 | CHROOT STRING {
475 	if (processor->chroot) {
476 		yyerror("chroot already specified for this processor");
477 		free($2);
478 		YYERROR;
479 	}
480 	processor->chroot = $2;
481 }
482 ;
483 
484 proc_params:
485 proc_params_opt proc_params
486 | /* empty */
487 ;
488 
489 
490 queue:
491 QUEUE COMPRESSION {
492 	conf->sc_queue_flags |= QUEUE_COMPRESSION;
493 }
494 | QUEUE ENCRYPTION {
495 	conf->sc_queue_flags |= QUEUE_ENCRYPTION;
496 }
497 | QUEUE ENCRYPTION STRING {
498 	if (strcasecmp($3, "stdin") == 0 || strcasecmp($3, "-") == 0) {
499 		conf->sc_queue_key = "stdin";
500 		free($3);
501 	}
502 	else
503 		conf->sc_queue_key = $3;
504 	conf->sc_queue_flags |= QUEUE_ENCRYPTION;
505 }
506 | QUEUE TTL STRING {
507 	conf->sc_ttl = delaytonum($3);
508 	if (conf->sc_ttl == -1) {
509 		yyerror("invalid ttl delay: %s", $3);
510 		free($3);
511 		YYERROR;
512 	}
513 	free($3);
514 }
515 ;
516 
517 
518 scheduler:
519 SCHEDULER LIMIT limits_scheduler
520 ;
521 
522 
523 smtp:
524 SMTP LIMIT limits_smtp
525 | SMTP CIPHERS STRING {
526 	conf->sc_tls_ciphers = $3;
527 }
528 | SMTP MAX_MESSAGE_SIZE size {
529 	conf->sc_maxsize = $3;
530 }
531 | SMTP SUB_ADDR_DELIM STRING {
532 	if (strlen($3) != 1) {
533 		yyerror("subaddressing-delimiter must be one character");
534 		free($3);
535 		YYERROR;
536 	}
537 	if (isspace((unsigned char)*$3) || !isprint((unsigned char)*$3) || *$3 == '@') {
538 		yyerror("sub-addr-delim uses invalid character");
539 		free($3);
540 		YYERROR;
541 	}
542 	conf->sc_subaddressing_delim = $3;
543 }
544 ;
545 
546 srs:
547 SRS KEY STRING {
548 	conf->sc_srs_key = $3;
549 }
550 | SRS KEY BACKUP STRING {
551 	conf->sc_srs_key_backup = $4;
552 }
553 | SRS TTL STRING {
554 	conf->sc_srs_ttl = delaytonum($3);
555 	if (conf->sc_srs_ttl == -1) {
556 		yyerror("ttl delay \"%s\" is invalid", $3);
557 		free($3);
558 		YYERROR;
559 	}
560 
561 	conf->sc_srs_ttl /= 86400;
562 	if (conf->sc_srs_ttl == 0) {
563 		yyerror("ttl delay \"%s\" is too short", $3);
564 		free($3);
565 		YYERROR;
566 	}
567 	free($3);
568 }
569 ;
570 
571 
572 dispatcher_local_option:
573 USER STRING {
574 	if (dsp->u.local.is_mbox) {
575 		yyerror("user may not be specified for this dispatcher");
576 		YYERROR;
577 	}
578 
579 	if (dsp->u.local.forward_only) {
580 		yyerror("user may not be specified for forward-only");
581 		YYERROR;
582 	}
583 
584 	if (dsp->u.local.expand_only) {
585 		yyerror("user may not be specified for expand-only");
586 		YYERROR;
587 	}
588 
589 	if (dsp->u.local.user) {
590 		yyerror("user already specified for this dispatcher");
591 		YYERROR;
592 	}
593 
594 	dsp->u.local.user = $2;
595 }
596 | ALIAS tables {
597 	struct table   *t = $2;
598 
599 	if (dsp->u.local.table_alias) {
600 		yyerror("alias mapping already specified for this dispatcher");
601 		YYERROR;
602 	}
603 
604 	if (dsp->u.local.table_virtual) {
605 		yyerror("virtual mapping already specified for this dispatcher");
606 		YYERROR;
607 	}
608 
609 	if (!table_check_use(t, T_DYNAMIC|T_HASH, K_ALIAS)) {
610 		yyerror("table \"%s\" may not be used for alias lookups",
611 		    t->t_name);
612 		YYERROR;
613 	}
614 
615 	dsp->u.local.table_alias = strdup(t->t_name);
616 }
617 | VIRTUAL tables {
618 	struct table   *t = $2;
619 
620 	if (dsp->u.local.table_virtual) {
621 		yyerror("virtual mapping already specified for this dispatcher");
622 		YYERROR;
623 	}
624 
625 	if (dsp->u.local.table_alias) {
626 		yyerror("alias mapping already specified for this dispatcher");
627 		YYERROR;
628 	}
629 
630 	if (!table_check_use(t, T_DYNAMIC|T_HASH, K_ALIAS)) {
631 		yyerror("table \"%s\" may not be used for virtual lookups",
632 		    t->t_name);
633 		YYERROR;
634 	}
635 
636 	dsp->u.local.table_virtual = strdup(t->t_name);
637 }
638 | USERBASE tables {
639 	struct table   *t = $2;
640 
641 	if (dsp->u.local.table_userbase) {
642 		yyerror("userbase mapping already specified for this dispatcher");
643 		YYERROR;
644 	}
645 
646 	if (!table_check_use(t, T_DYNAMIC|T_HASH, K_USERINFO)) {
647 		yyerror("table \"%s\" may not be used for userbase lookups",
648 		    t->t_name);
649 		YYERROR;
650 	}
651 
652 	dsp->u.local.table_userbase = strdup(t->t_name);
653 }
654 | WRAPPER STRING {
655 	if (! dict_get(conf->sc_mda_wrappers, $2)) {
656 		yyerror("no mda wrapper with that name: %s", $2);
657 		YYERROR;
658 	}
659 	dsp->u.local.mda_wrapper = $2;
660 }
661 ;
662 
663 dispatcher_local_options:
664 dispatcher_local_option dispatcher_local_options
665 | /* empty */
666 ;
667 
668 dispatcher_local:
669 MBOX {
670 	dsp->u.local.is_mbox = 1;
671 	asprintf(&dsp->u.local.command, "/usr/libexec/mail.local -f %%{mbox.from} -- %%{user.username}");
672 } dispatcher_local_options
673 | MAILDIR {
674 	asprintf(&dsp->u.local.command, "/usr/libexec/mail.maildir");
675 } dispatcher_local_options
676 | MAILDIR JUNK {
677 	asprintf(&dsp->u.local.command, "/usr/libexec/mail.maildir -j");
678 } dispatcher_local_options
679 | MAILDIR STRING {
680 	if (strncmp($2, "~/", 2) == 0)
681 		asprintf(&dsp->u.local.command,
682 		    "/usr/libexec/mail.maildir \"%%{user.directory}/%s\"", $2+2);
683 	else
684 		asprintf(&dsp->u.local.command,
685 		    "/usr/libexec/mail.maildir \"%s\"", $2);
686 } dispatcher_local_options
687 | MAILDIR STRING JUNK {
688 	if (strncmp($2, "~/", 2) == 0)
689 		asprintf(&dsp->u.local.command,
690 		    "/usr/libexec/mail.maildir -j \"%%{user.directory}/%s\"", $2+2);
691 	else
692 		asprintf(&dsp->u.local.command,
693 		    "/usr/libexec/mail.maildir -j \"%s\"", $2);
694 } dispatcher_local_options
695 | LMTP STRING {
696 	asprintf(&dsp->u.local.command,
697 	    "/usr/libexec/mail.lmtp -d %s -u", $2);
698 	dsp->u.local.user = SMTPD_USER;
699 } dispatcher_local_options
700 | LMTP STRING RCPT_TO {
701 	asprintf(&dsp->u.local.command,
702 	    "/usr/libexec/mail.lmtp -d %s -r", $2);
703 	dsp->u.local.user = SMTPD_USER;
704 } dispatcher_local_options
705 | MDA STRING {
706 	asprintf(&dsp->u.local.command,
707 	    "/usr/libexec/mail.mda \"%s\"", $2);
708 } dispatcher_local_options
709 | FORWARD_ONLY {
710 	dsp->u.local.forward_only = 1;
711 } dispatcher_local_options
712 | EXPAND_ONLY {
713 	dsp->u.local.expand_only = 1;
714 } dispatcher_local_options
715 
716 ;
717 
718 dispatcher_remote_option:
719 HELO STRING {
720 	if (dsp->u.remote.helo) {
721 		yyerror("helo already specified for this dispatcher");
722 		YYERROR;
723 	}
724 
725 	dsp->u.remote.helo = $2;
726 }
727 | HELO_SRC tables {
728 	struct table   *t = $2;
729 
730 	if (dsp->u.remote.helo_source) {
731 		yyerror("helo-source mapping already specified for this dispatcher");
732 		YYERROR;
733 	}
734 	if (!table_check_use(t, T_DYNAMIC|T_HASH, K_ADDRNAME)) {
735 		yyerror("table \"%s\" may not be used for helo-source lookups",
736 		    t->t_name);
737 		YYERROR;
738 	}
739 
740 	dsp->u.remote.helo_source = strdup(t->t_name);
741 }
742 | PKI STRING {
743 	if (dsp->u.remote.pki) {
744 		yyerror("pki already specified for this dispatcher");
745 		YYERROR;
746 	}
747 
748 	dsp->u.remote.pki = $2;
749 }
750 | CA STRING {
751 	if (dsp->u.remote.ca) {
752 		yyerror("ca already specified for this dispatcher");
753 		YYERROR;
754 	}
755 
756 	dsp->u.remote.ca = $2;
757 }
758 | CIPHERS STRING {
759 	if (dsp->u.remote.tls_ciphers) {
760 		yyerror("ciphers already specified for this dispatcher");
761 		YYERROR;
762 	}
763 
764 	dsp->u.remote.tls_ciphers = $2;
765 }
766 | PROTOCOLS STRING {
767 	if (dsp->u.remote.tls_protocols) {
768 		yyerror("protocols already specified for this dispatcher");
769 		YYERROR;
770 	}
771 
772 	dsp->u.remote.tls_protocols = $2;
773 }
774 | SRC tables {
775 	struct table   *t = $2;
776 
777 	if (dsp->u.remote.source) {
778 		yyerror("source mapping already specified for this dispatcher");
779 		YYERROR;
780 	}
781 
782 	if (!table_check_use(t, T_DYNAMIC|T_LIST, K_SOURCE)) {
783 		yyerror("table \"%s\" may not be used for source lookups",
784 		    t->t_name);
785 		YYERROR;
786 	}
787 
788 	dsp->u.remote.source = strdup(t->t_name);
789 }
790 | MAIL_FROM STRING {
791 	if (dsp->u.remote.mail_from) {
792 		yyerror("mail-from already specified for this dispatcher");
793 		YYERROR;
794 	}
795 
796 	dsp->u.remote.mail_from = $2;
797 }
798 | BACKUP MX STRING {
799 	if (dsp->u.remote.backup) {
800 		yyerror("backup already specified for this dispatcher");
801 		YYERROR;
802 	}
803 	if (dsp->u.remote.smarthost) {
804 		yyerror("backup and host are mutually exclusive");
805 		YYERROR;
806 	}
807 
808 	dsp->u.remote.backup = 1;
809 	dsp->u.remote.backupmx = $3;
810 }
811 | BACKUP {
812 	if (dsp->u.remote.backup) {
813 		yyerror("backup already specified for this dispatcher");
814 		YYERROR;
815 	}
816 	if (dsp->u.remote.smarthost) {
817 		yyerror("backup and host are mutually exclusive");
818 		YYERROR;
819 	}
820 
821 	dsp->u.remote.backup = 1;
822 }
823 | HOST tables {
824 	struct table   *t = $2;
825 
826 	if (dsp->u.remote.smarthost) {
827 		yyerror("host mapping already specified for this dispatcher");
828 		YYERROR;
829 	}
830 	if (dsp->u.remote.backup) {
831 		yyerror("backup and host are mutually exclusive");
832 		YYERROR;
833 	}
834 
835 	if (!table_check_use(t, T_DYNAMIC|T_LIST, K_RELAYHOST)) {
836 		yyerror("table \"%s\" may not be used for host lookups",
837 		    t->t_name);
838 		YYERROR;
839 	}
840 
841 	dsp->u.remote.smarthost = strdup(t->t_name);
842 }
843 | DOMAIN tables {
844 	struct table   *t = $2;
845 
846 	if (dsp->u.remote.smarthost) {
847 		yyerror("host mapping already specified for this dispatcher");
848 		YYERROR;
849 	}
850 	if (dsp->u.remote.backup) {
851 		yyerror("backup and domain are mutually exclusive");
852 		YYERROR;
853 	}
854 
855 	if (!table_check_use(t, T_DYNAMIC|T_HASH, K_RELAYHOST)) {
856 		yyerror("table \"%s\" may not be used for host lookups",
857 		    t->t_name);
858 		YYERROR;
859 	}
860 
861 	dsp->u.remote.smarthost = strdup(t->t_name);
862 	dsp->u.remote.smarthost_domain = 1;
863 }
864 | TLS {
865 	if (dsp->u.remote.tls_required == 1) {
866 		yyerror("tls already specified for this dispatcher");
867 		YYERROR;
868 	}
869 
870 	dsp->u.remote.tls_required = 1;
871 }
872 | TLS NO_VERIFY {
873 	if (dsp->u.remote.tls_required == 1) {
874 		yyerror("tls already specified for this dispatcher");
875 		YYERROR;
876 	}
877 
878 	dsp->u.remote.tls_required = 1;
879 	dsp->u.remote.tls_noverify = 1;
880 }
881 | AUTH tables {
882 	struct table   *t = $2;
883 
884 	if (dsp->u.remote.smarthost == NULL) {
885 		yyerror("auth may not be specified without host on a dispatcher");
886 		YYERROR;
887 	}
888 
889 	if (dsp->u.remote.auth) {
890 		yyerror("auth mapping already specified for this dispatcher");
891 		YYERROR;
892 	}
893 
894 	if (!table_check_use(t, T_DYNAMIC|T_HASH, K_CREDENTIALS)) {
895 		yyerror("table \"%s\" may not be used for auth lookups",
896 		    t->t_name);
897 		YYERROR;
898 	}
899 
900 	dsp->u.remote.auth = strdup(t->t_name);
901 }
902 | FILTER STRING {
903 	struct filter_config *fc;
904 
905 	if (dsp->u.remote.filtername) {
906 		yyerror("filter already specified for this dispatcher");
907 		YYERROR;
908 	}
909 
910 	if ((fc = dict_get(conf->sc_filters_dict, $2)) == NULL) {
911 		yyerror("no filter exist with that name: %s", $2);
912 		free($2);
913 		YYERROR;
914 	}
915 	fc->filter_subsystem |= FILTER_SUBSYSTEM_SMTP_OUT;
916 	dsp->u.remote.filtername = $2;
917 }
918 | FILTER {
919 	char	buffer[128];
920 	char	*filtername;
921 
922 	if (dsp->u.remote.filtername) {
923 		yyerror("filter already specified for this dispatcher");
924 		YYERROR;
925 	}
926 
927 	do {
928 		(void)snprintf(buffer, sizeof buffer, "<dynchain:%08x>", last_dynchain_id++);
929 	} while (dict_check(conf->sc_filters_dict, buffer));
930 
931 	filtername = xstrdup(buffer);
932 	filter_config = xcalloc(1, sizeof *filter_config);
933 	filter_config->filter_type = FILTER_TYPE_CHAIN;
934 	filter_config->filter_subsystem |= FILTER_SUBSYSTEM_SMTP_OUT;
935 	dict_init(&filter_config->chain_procs);
936 	dsp->u.remote.filtername = filtername;
937 } '{' filter_list '}' {
938 	dict_set(conf->sc_filters_dict, dsp->u.remote.filtername, filter_config);
939 	filter_config = NULL;
940 }
941 | SRS {
942 	if (conf->sc_srs_key == NULL) {
943 		yyerror("an srs key is required for srs to be specified in an action");
944 		YYERROR;
945 	}
946 	if (dsp->u.remote.srs == 1) {
947 		yyerror("srs already specified for this dispatcher");
948 		YYERROR;
949 	}
950 
951 	dsp->u.remote.srs = 1;
952 }
953 ;
954 
955 dispatcher_remote_options:
956 dispatcher_remote_option dispatcher_remote_options
957 | /* empty */
958 ;
959 
960 dispatcher_remote :
961 RELAY dispatcher_remote_options
962 ;
963 
964 dispatcher_type:
965 dispatcher_local {
966 	dsp->type = DISPATCHER_LOCAL;
967 }
968 | dispatcher_remote {
969 	dsp->type = DISPATCHER_REMOTE;
970 }
971 ;
972 
973 dispatcher_option:
974 TTL STRING {
975 	if (dsp->ttl) {
976 		yyerror("ttl already specified for this dispatcher");
977 		YYERROR;
978 	}
979 
980 	dsp->ttl = delaytonum($2);
981 	if (dsp->ttl == -1) {
982 		yyerror("ttl delay \"%s\" is invalid", $2);
983 		free($2);
984 		YYERROR;
985 	}
986 	free($2);
987 }
988 ;
989 
990 dispatcher_options:
991 dispatcher_option dispatcher_options
992 | /* empty */
993 ;
994 
995 dispatcher:
996 ACTION STRING {
997 	if (dict_get(conf->sc_dispatchers, $2)) {
998 		yyerror("dispatcher already declared with that name: %s", $2);
999 		YYERROR;
1000 	}
1001 	dsp = xcalloc(1, sizeof *dsp);
1002 } dispatcher_type dispatcher_options {
1003 	if (dsp->type == DISPATCHER_LOCAL)
1004 		if (dsp->u.local.table_userbase == NULL)
1005 			dsp->u.local.table_userbase = "<getpwnam>";
1006 	dict_set(conf->sc_dispatchers, $2, dsp);
1007 	dsp = NULL;
1008 }
1009 ;
1010 
1011 match_option:
1012 negation TAG tables {
1013 	struct table   *t = $3;
1014 
1015 	if (rule->flag_tag) {
1016 		yyerror("tag already specified for this rule");
1017 		YYERROR;
1018 	}
1019 
1020 	if (!table_check_use(t, T_DYNAMIC|T_LIST, K_STRING)) {
1021 		yyerror("table \"%s\" may not be used for tag lookups",
1022 		    t->t_name);
1023 		YYERROR;
1024 	}
1025 
1026 	rule->flag_tag = $1 ? -1 : 1;
1027 	rule->table_tag = strdup(t->t_name);
1028 }
1029 |
1030 negation TAG REGEX tables {
1031 	struct table   *t = $4;
1032 
1033 	if (rule->flag_tag) {
1034 		yyerror("tag already specified for this rule");
1035 		YYERROR;
1036 	}
1037 
1038 	if (!table_check_use(t, T_DYNAMIC|T_LIST, K_REGEX)) {
1039 		yyerror("table \"%s\" may not be used for tag lookups",
1040 		    t->t_name);
1041 		YYERROR;
1042 	}
1043 
1044 	rule->flag_tag = $1 ? -1 : 1;
1045 	rule->flag_tag_regex = 1;
1046 	rule->table_tag = strdup(t->t_name);
1047 }
1048 
1049 | negation HELO tables {
1050 	struct table   *t = $3;
1051 
1052 	if (rule->flag_smtp_helo) {
1053 		yyerror("helo already specified for this rule");
1054 		YYERROR;
1055 	}
1056 
1057 	if (!table_check_use(t, T_DYNAMIC|T_LIST, K_DOMAIN)) {
1058 		yyerror("table \"%s\" may not be used for helo lookups",
1059 		    t->t_name);
1060 		YYERROR;
1061 	}
1062 
1063 	rule->flag_smtp_helo = $1 ? -1 : 1;
1064 	rule->table_smtp_helo = strdup(t->t_name);
1065 }
1066 | negation HELO REGEX tables {
1067 	struct table   *t = $4;
1068 
1069 	if (rule->flag_smtp_helo) {
1070 		yyerror("helo already specified for this rule");
1071 		YYERROR;
1072 	}
1073 
1074 	if (!table_check_use(t, T_DYNAMIC|T_LIST, K_REGEX)) {
1075 		yyerror("table \"%s\" may not be used for helo lookups",
1076 		    t->t_name);
1077 		YYERROR;
1078 	}
1079 
1080 	rule->flag_smtp_helo = $1 ? -1 : 1;
1081 	rule->flag_smtp_helo_regex = 1;
1082 	rule->table_smtp_helo = strdup(t->t_name);
1083 }
1084 | negation TLS {
1085 	if (rule->flag_smtp_starttls) {
1086 		yyerror("tls already specified for this rule");
1087 		YYERROR;
1088 	}
1089 	rule->flag_smtp_starttls = $1 ? -1 : 1;
1090 }
1091 | negation AUTH {
1092 	if (rule->flag_smtp_auth) {
1093 		yyerror("auth already specified for this rule");
1094 		YYERROR;
1095 	}
1096 	rule->flag_smtp_auth = $1 ? -1 : 1;
1097 }
1098 | negation AUTH tables {
1099 	struct table   *t = $3;
1100 
1101 	if (rule->flag_smtp_auth) {
1102 		yyerror("auth already specified for this rule");
1103 		YYERROR;
1104 	}
1105 
1106        	if (!table_check_use(t, T_DYNAMIC|T_LIST, K_STRING|K_CREDENTIALS)) {
1107 		yyerror("table \"%s\" may not be used for auth lookups",
1108 		    t->t_name);
1109 		YYERROR;
1110 	}
1111 
1112 	rule->flag_smtp_auth = $1 ? -1 : 1;
1113 	rule->table_smtp_auth = strdup(t->t_name);
1114 }
1115 | negation AUTH REGEX tables {
1116 	struct table   *t = $4;
1117 
1118 	if (rule->flag_smtp_auth) {
1119 		yyerror("auth already specified for this rule");
1120 		YYERROR;
1121 	}
1122 
1123 	if (!table_check_use(t, T_DYNAMIC|T_LIST, K_REGEX)) {
1124 		yyerror("table \"%s\" may not be used for auth lookups",
1125 		    t->t_name);
1126 		YYERROR;
1127 	}
1128 
1129 	rule->flag_smtp_auth = $1 ? -1 : 1;
1130 	rule->flag_smtp_auth_regex = 1;
1131 	rule->table_smtp_auth = strdup(t->t_name);
1132 }
1133 | negation MAIL_FROM tables {
1134 	struct table   *t = $3;
1135 
1136 	if (rule->flag_smtp_mail_from) {
1137 		yyerror("mail-from already specified for this rule");
1138 		YYERROR;
1139 	}
1140 
1141 	if (!table_check_use(t, T_DYNAMIC|T_LIST, K_MAILADDR)) {
1142 		yyerror("table \"%s\" may not be used for mail-from lookups",
1143 		    t->t_name);
1144 		YYERROR;
1145 	}
1146 
1147 	rule->flag_smtp_mail_from = $1 ? -1 : 1;
1148 	rule->table_smtp_mail_from = strdup(t->t_name);
1149 }
1150 | negation MAIL_FROM REGEX tables {
1151 	struct table   *t = $4;
1152 
1153 	if (rule->flag_smtp_mail_from) {
1154 		yyerror("mail-from already specified for this rule");
1155 		YYERROR;
1156 	}
1157 
1158 	if (!table_check_use(t, T_DYNAMIC|T_LIST, K_REGEX)) {
1159 		yyerror("table \"%s\" may not be used for mail-from lookups",
1160 		    t->t_name);
1161 		YYERROR;
1162 	}
1163 
1164 	rule->flag_smtp_mail_from = $1 ? -1 : 1;
1165 	rule->flag_smtp_mail_from_regex = 1;
1166 	rule->table_smtp_mail_from = strdup(t->t_name);
1167 }
1168 | negation RCPT_TO tables {
1169 	struct table   *t = $3;
1170 
1171 	if (rule->flag_smtp_rcpt_to) {
1172 		yyerror("rcpt-to already specified for this rule");
1173 		YYERROR;
1174 	}
1175 
1176 	if (!table_check_use(t, T_DYNAMIC|T_LIST, K_MAILADDR)) {
1177 		yyerror("table \"%s\" may not be used for rcpt-to lookups",
1178 		    t->t_name);
1179 		YYERROR;
1180 	}
1181 
1182 	rule->flag_smtp_rcpt_to = $1 ? -1 : 1;
1183 	rule->table_smtp_rcpt_to = strdup(t->t_name);
1184 }
1185 | negation RCPT_TO REGEX tables {
1186 	struct table   *t = $4;
1187 
1188 	if (rule->flag_smtp_rcpt_to) {
1189 		yyerror("rcpt-to already specified for this rule");
1190 		YYERROR;
1191 	}
1192 
1193 	if (!table_check_use(t, T_DYNAMIC|T_LIST, K_REGEX)) {
1194 		yyerror("table \"%s\" may not be used for rcpt-to lookups",
1195 		    t->t_name);
1196 		YYERROR;
1197 	}
1198 
1199 	rule->flag_smtp_rcpt_to = $1 ? -1 : 1;
1200 	rule->flag_smtp_rcpt_to_regex = 1;
1201 	rule->table_smtp_rcpt_to = strdup(t->t_name);
1202 }
1203 
1204 | negation FROM SOCKET {
1205 	if (rule->flag_from) {
1206 		yyerror("from already specified for this rule");
1207 		YYERROR;
1208 	}
1209 	rule->flag_from = $1 ? -1 : 1;
1210 	rule->flag_from_socket = 1;
1211 }
1212 | negation FROM LOCAL {
1213 	struct table	*t = table_find(conf, "<localhost>");
1214 
1215 	if (rule->flag_from) {
1216 		yyerror("from already specified for this rule");
1217 		YYERROR;
1218 	}
1219 	rule->flag_from = $1 ? -1 : 1;
1220 	rule->table_from = strdup(t->t_name);
1221 }
1222 | negation FROM ANY {
1223 	struct table	*t = table_find(conf, "<anyhost>");
1224 
1225 	if (rule->flag_from) {
1226 		yyerror("from already specified for this rule");
1227 		YYERROR;
1228 	}
1229 	rule->flag_from = $1 ? -1 : 1;
1230 	rule->table_from = strdup(t->t_name);
1231 }
1232 | negation FROM SRC tables {
1233 	struct table   *t = $4;
1234 
1235 	if (rule->flag_from) {
1236 		yyerror("from already specified for this rule");
1237 		YYERROR;
1238 	}
1239 
1240 	if (!table_check_use(t, T_DYNAMIC|T_LIST, K_NETADDR)) {
1241 		yyerror("table \"%s\" may not be used for from lookups",
1242 		    t->t_name);
1243 		YYERROR;
1244 	}
1245 
1246 	rule->flag_from = $1 ? -1 : 1;
1247 	rule->table_from = strdup(t->t_name);
1248 }
1249 | negation FROM SRC REGEX tables {
1250 	struct table   *t = $5;
1251 
1252 	if (rule->flag_from) {
1253 		yyerror("from already specified for this rule");
1254 		YYERROR;
1255 	}
1256 
1257 	if (!table_check_use(t, T_DYNAMIC|T_LIST, K_REGEX)) {
1258 		yyerror("table \"%s\" may not be used for from lookups",
1259 		    t->t_name);
1260 		YYERROR;
1261 	}
1262 
1263 	rule->flag_from = $1 ? -1 : 1;
1264 	rule->flag_from_regex = 1;
1265 	rule->table_from = strdup(t->t_name);
1266 }
1267 | negation FROM RDNS {
1268 	if (rule->flag_from) {
1269 		yyerror("from already specified for this rule");
1270 		YYERROR;
1271 	}
1272 	rule->flag_from = $1 ? -1 : 1;
1273 	rule->flag_from_rdns = 1;
1274 }
1275 | negation FROM RDNS tables {
1276 	struct table   *t = $4;
1277 
1278 	if (rule->flag_from) {
1279 		yyerror("from already specified for this rule");
1280 		YYERROR;
1281 	}
1282 
1283 	if (!table_check_use(t, T_DYNAMIC|T_LIST, K_DOMAIN)) {
1284 		yyerror("table \"%s\" may not be used for rdns lookups",
1285 		    t->t_name);
1286 		YYERROR;
1287 	}
1288 
1289 	rule->flag_from = $1 ? -1 : 1;
1290 	rule->flag_from_rdns = 1;
1291 	rule->table_from = strdup(t->t_name);
1292 }
1293 | negation FROM RDNS REGEX tables {
1294 	struct table   *t = $5;
1295 
1296 	if (rule->flag_from) {
1297 		yyerror("from already specified for this rule");
1298 		YYERROR;
1299 	}
1300 
1301 	if (!table_check_use(t, T_DYNAMIC|T_LIST, K_DOMAIN)) {
1302 		yyerror("table \"%s\" may not be used for rdns lookups",
1303 		    t->t_name);
1304 		YYERROR;
1305 	}
1306 
1307 	rule->flag_from = $1 ? -1 : 1;
1308 	rule->flag_from_regex = 1;
1309 	rule->flag_from_rdns = 1;
1310 	rule->table_from = strdup(t->t_name);
1311 }
1312 
1313 | negation FROM AUTH {
1314 	struct table	*anyhost = table_find(conf, "<anyhost>");
1315 
1316 	if (rule->flag_from) {
1317 		yyerror("from already specified for this rule");
1318 		YYERROR;
1319 	}
1320 
1321 	rule->flag_from = 1;
1322 	rule->table_from = strdup(anyhost->t_name);
1323 	rule->flag_smtp_auth = $1 ? -1 : 1;
1324 }
1325 | negation FROM AUTH tables {
1326 	struct table	*anyhost = table_find(conf, "<anyhost>");
1327 	struct table	*t = $4;
1328 
1329 	if (rule->flag_from) {
1330 		yyerror("from already specified for this rule");
1331 		YYERROR;
1332 	}
1333 
1334        	if (!table_check_use(t, T_DYNAMIC|T_LIST, K_STRING|K_CREDENTIALS)) {
1335 		yyerror("table \"%s\" may not be used for from lookups",
1336 		    t->t_name);
1337 		YYERROR;
1338 	}
1339 
1340 	rule->flag_from = 1;
1341 	rule->table_from = strdup(anyhost->t_name);
1342 	rule->flag_smtp_auth = $1 ? -1 : 1;
1343 	rule->table_smtp_auth = strdup(t->t_name);
1344 }
1345 | negation FROM AUTH REGEX tables {
1346 	struct table	*anyhost = table_find(conf, "<anyhost>");
1347 	struct table	*t = $5;
1348 
1349 	if (rule->flag_from) {
1350 		yyerror("from already specified for this rule");
1351 		YYERROR;
1352 	}
1353 
1354 	if (!table_check_use(t, T_DYNAMIC|T_LIST, K_REGEX)) {
1355         	yyerror("table \"%s\" may not be used for from lookups",
1356 		    t->t_name);
1357 		YYERROR;
1358 	}
1359 
1360 	rule->flag_from = 1;
1361 	rule->table_from = strdup(anyhost->t_name);
1362 	rule->flag_smtp_auth = $1 ? -1 : 1;
1363 	rule->flag_smtp_auth_regex = 1;
1364 	rule->table_smtp_auth = strdup(t->t_name);
1365 }
1366 
1367 | negation FROM MAIL_FROM tables {
1368 	struct table	*anyhost = table_find(conf, "<anyhost>");
1369 	struct table	*t = $4;
1370 
1371 	if (rule->flag_from) {
1372 		yyerror("from already specified for this rule");
1373 		YYERROR;
1374 	}
1375 
1376 	if (!table_check_use(t, T_DYNAMIC|T_LIST, K_MAILADDR)) {
1377 		yyerror("table \"%s\" may not be used for from lookups",
1378 		    t->t_name);
1379 		YYERROR;
1380 	}
1381 
1382 	rule->flag_from = 1;
1383 	rule->table_from = strdup(anyhost->t_name);
1384 	rule->flag_smtp_mail_from = $1 ? -1 : 1;
1385 	rule->table_smtp_mail_from = strdup(t->t_name);
1386 }
1387 | negation FROM MAIL_FROM REGEX tables {
1388 	struct table	*anyhost = table_find(conf, "<anyhost>");
1389 	struct table	*t = $5;
1390 
1391 	if (rule->flag_from) {
1392 		yyerror("from already specified for this rule");
1393 		YYERROR;
1394 	}
1395 
1396 	if (!table_check_use(t, T_DYNAMIC|T_LIST, K_REGEX)) {
1397 		yyerror("table \"%s\" may not be used for from lookups",
1398 		    t->t_name);
1399 		YYERROR;
1400 	}
1401 
1402 	rule->flag_from = 1;
1403 	rule->table_from = strdup(anyhost->t_name);
1404 	rule->flag_smtp_mail_from = $1 ? -1 : 1;
1405 	rule->flag_smtp_mail_from_regex = 1;
1406 	rule->table_smtp_mail_from = strdup(t->t_name);
1407 }
1408 
1409 | negation FOR LOCAL {
1410 	struct table   *t = table_find(conf, "<localnames>");
1411 
1412 	if (rule->flag_for) {
1413 		yyerror("for already specified for this rule");
1414 		YYERROR;
1415 	}
1416 	rule->flag_for = $1 ? -1 : 1;
1417 	rule->table_for = strdup(t->t_name);
1418 }
1419 | negation FOR ANY {
1420 	struct table   *t = table_find(conf, "<anydestination>");
1421 
1422 	if (rule->flag_for) {
1423 		yyerror("for already specified for this rule");
1424 		YYERROR;
1425 	}
1426 	rule->flag_for = $1 ? -1 : 1;
1427 	rule->table_for = strdup(t->t_name);
1428 }
1429 | negation FOR DOMAIN tables {
1430 	struct table   *t = $4;
1431 
1432 	if (rule->flag_for) {
1433 		yyerror("for already specified for this rule");
1434 		YYERROR;
1435 	}
1436 
1437 	if (!table_check_use(t, T_DYNAMIC|T_LIST, K_DOMAIN)) {
1438 		yyerror("table \"%s\" may not be used for 'for' lookups",
1439 		    t->t_name);
1440 		YYERROR;
1441 	}
1442 
1443 	rule->flag_for = $1 ? -1 : 1;
1444 	rule->table_for = strdup(t->t_name);
1445 }
1446 | negation FOR DOMAIN REGEX tables {
1447 	struct table   *t = $5;
1448 
1449 	if (rule->flag_for) {
1450 		yyerror("for already specified for this rule");
1451 		YYERROR;
1452 	}
1453 
1454 	if (!table_check_use(t, T_DYNAMIC|T_LIST, K_REGEX)) {
1455 		yyerror("table \"%s\" may not be used for 'for' lookups",
1456 		    t->t_name);
1457 		YYERROR;
1458 	}
1459 
1460 	rule->flag_for = $1 ? -1 : 1;
1461 	rule->flag_for_regex = 1;
1462 	rule->table_for = strdup(t->t_name);
1463 }
1464 | negation FOR RCPT_TO tables {
1465 	struct table	*anyhost = table_find(conf, "<anydestination>");
1466 	struct table	*t = $4;
1467 
1468 	if (rule->flag_for) {
1469 		yyerror("for already specified for this rule");
1470 		YYERROR;
1471 	}
1472 
1473 	if (!table_check_use(t, T_DYNAMIC|T_LIST, K_MAILADDR)) {
1474 		yyerror("table \"%s\" may not be used for for lookups",
1475 		    t->t_name);
1476 		YYERROR;
1477 	}
1478 
1479 	rule->flag_for = 1;
1480 	rule->table_for = strdup(anyhost->t_name);
1481 	rule->flag_smtp_rcpt_to = $1 ? -1 : 1;
1482 	rule->table_smtp_rcpt_to = strdup(t->t_name);
1483 }
1484 | negation FOR RCPT_TO REGEX tables {
1485 	struct table	*anyhost = table_find(conf, "<anydestination>");
1486 	struct table	*t = $5;
1487 
1488 	if (rule->flag_for) {
1489 		yyerror("for already specified for this rule");
1490 		YYERROR;
1491 	}
1492 
1493 	if (!table_check_use(t, T_DYNAMIC|T_LIST, K_REGEX)) {
1494 		yyerror("table \"%s\" may not be used for for lookups",
1495 		    t->t_name);
1496 		YYERROR;
1497 	}
1498 
1499 	rule->flag_for = 1;
1500 	rule->table_for = strdup(anyhost->t_name);
1501 	rule->flag_smtp_rcpt_to = $1 ? -1 : 1;
1502 	rule->flag_smtp_rcpt_to_regex = 1;
1503 	rule->table_smtp_rcpt_to = strdup(t->t_name);
1504 }
1505 ;
1506 
1507 match_options:
1508 match_option match_options
1509 | /* empty */
1510 ;
1511 
1512 match_dispatcher:
1513 STRING {
1514 	if (dict_get(conf->sc_dispatchers, $1) == NULL) {
1515 		yyerror("no such dispatcher: %s", $1);
1516 		YYERROR;
1517 	}
1518 	rule->dispatcher = $1;
1519 }
1520 ;
1521 
1522 action:
1523 REJECT {
1524 	rule->reject = 1;
1525 }
1526 | ACTION match_dispatcher
1527 ;
1528 
1529 match:
1530 MATCH {
1531 	rule = xcalloc(1, sizeof *rule);
1532 } match_options action {
1533 	if (!rule->flag_from) {
1534 		rule->table_from = strdup("<localhost>");
1535 		rule->flag_from = 1;
1536 	}
1537 	if (!rule->flag_for) {
1538 		rule->table_for = strdup("<localnames>");
1539 		rule->flag_for = 1;
1540 	}
1541 	TAILQ_INSERT_TAIL(conf->sc_rules, rule, r_entry);
1542 	rule = NULL;
1543 }
1544 ;
1545 
1546 filter_action_builtin:
1547 filter_action_builtin_nojunk
1548 | JUNK {
1549 	filter_config->junk = 1;
1550 }
1551 | BYPASS {
1552 	filter_config->bypass = 1;
1553 }
1554 ;
1555 
1556 filter_action_builtin_nojunk:
1557 REJECT STRING {
1558 	filter_config->reject = $2;
1559 }
1560 | DISCONNECT STRING {
1561 	filter_config->disconnect = $2;
1562 }
1563 | REWRITE STRING {
1564 	filter_config->rewrite = $2;
1565 }
1566 | REPORT STRING {
1567 	filter_config->report = $2;
1568 }
1569 ;
1570 
1571 filter_phase_check_fcrdns:
1572 negation FCRDNS {
1573 	filter_config->not_fcrdns = $1 ? -1 : 1;
1574 	filter_config->fcrdns = 1;
1575 }
1576 ;
1577 
1578 filter_phase_check_rdns:
1579 negation RDNS {
1580 	filter_config->not_rdns = $1 ? -1 : 1;
1581 	filter_config->rdns = 1;
1582 }
1583 ;
1584 
1585 filter_phase_check_rdns_table:
1586 negation RDNS tables {
1587 	filter_config->not_rdns_table = $1 ? -1 : 1;
1588 	filter_config->rdns_table = $3;
1589 }
1590 ;
1591 filter_phase_check_rdns_regex:
1592 negation RDNS REGEX tables {
1593 	filter_config->not_rdns_regex = $1 ? -1 : 1;
1594 	filter_config->rdns_regex = $4;
1595 }
1596 ;
1597 
1598 filter_phase_check_src_table:
1599 negation SRC tables {
1600 	filter_config->not_src_table = $1 ? -1 : 1;
1601 	filter_config->src_table = $3;
1602 }
1603 ;
1604 filter_phase_check_src_regex:
1605 negation SRC REGEX tables {
1606 	filter_config->not_src_regex = $1 ? -1 : 1;
1607 	filter_config->src_regex = $4;
1608 }
1609 ;
1610 
1611 filter_phase_check_helo_table:
1612 negation HELO tables {
1613 	filter_config->not_helo_table = $1 ? -1 : 1;
1614 	filter_config->helo_table = $3;
1615 }
1616 ;
1617 filter_phase_check_helo_regex:
1618 negation HELO REGEX tables {
1619 	filter_config->not_helo_regex = $1 ? -1 : 1;
1620 	filter_config->helo_regex = $4;
1621 }
1622 ;
1623 
1624 filter_phase_check_auth:
1625 negation AUTH {
1626 	filter_config->not_auth = $1 ? -1 : 1;
1627 	filter_config->auth = 1;
1628 }
1629 ;
1630 filter_phase_check_auth_table:
1631 negation AUTH tables {
1632 	filter_config->not_auth_table = $1 ? -1 : 1;
1633 	filter_config->auth_table = $3;
1634 }
1635 ;
1636 filter_phase_check_auth_regex:
1637 negation AUTH REGEX tables {
1638 	filter_config->not_auth_regex = $1 ? -1 : 1;
1639 	filter_config->auth_regex = $4;
1640 }
1641 ;
1642 
1643 filter_phase_check_mail_from_table:
1644 negation MAIL_FROM tables {
1645 	filter_config->not_mail_from_table = $1 ? -1 : 1;
1646 	filter_config->mail_from_table = $3;
1647 }
1648 ;
1649 filter_phase_check_mail_from_regex:
1650 negation MAIL_FROM REGEX tables {
1651 	filter_config->not_mail_from_regex = $1 ? -1 : 1;
1652 	filter_config->mail_from_regex = $4;
1653 }
1654 ;
1655 
1656 filter_phase_check_rcpt_to_table:
1657 negation RCPT_TO tables {
1658 	filter_config->not_rcpt_to_table = $1 ? -1 : 1;
1659 	filter_config->rcpt_to_table = $3;
1660 }
1661 ;
1662 filter_phase_check_rcpt_to_regex:
1663 negation RCPT_TO REGEX tables {
1664 	filter_config->not_rcpt_to_regex = $1 ? -1 : 1;
1665 	filter_config->rcpt_to_regex = $4;
1666 }
1667 ;
1668 
1669 filter_phase_global_options:
1670 filter_phase_check_fcrdns |
1671 filter_phase_check_rdns |
1672 filter_phase_check_rdns_regex |
1673 filter_phase_check_rdns_table |
1674 filter_phase_check_src_regex |
1675 filter_phase_check_src_table;
1676 
1677 filter_phase_connect_options:
1678 filter_phase_global_options;
1679 
1680 filter_phase_helo_options:
1681 filter_phase_check_helo_table |
1682 filter_phase_check_helo_regex |
1683 filter_phase_global_options;
1684 
1685 filter_phase_auth_options:
1686 filter_phase_check_helo_table |
1687 filter_phase_check_helo_regex |
1688 filter_phase_check_auth |
1689 filter_phase_check_auth_table |
1690 filter_phase_check_auth_regex |
1691 filter_phase_global_options;
1692 
1693 filter_phase_mail_from_options:
1694 filter_phase_check_helo_table |
1695 filter_phase_check_helo_regex |
1696 filter_phase_check_auth |
1697 filter_phase_check_auth_table |
1698 filter_phase_check_auth_regex |
1699 filter_phase_check_mail_from_table |
1700 filter_phase_check_mail_from_regex |
1701 filter_phase_global_options;
1702 
1703 filter_phase_rcpt_to_options:
1704 filter_phase_check_helo_table |
1705 filter_phase_check_helo_regex |
1706 filter_phase_check_auth |
1707 filter_phase_check_auth_table |
1708 filter_phase_check_auth_regex |
1709 filter_phase_check_mail_from_table |
1710 filter_phase_check_mail_from_regex |
1711 filter_phase_check_rcpt_to_table |
1712 filter_phase_check_rcpt_to_regex |
1713 filter_phase_global_options;
1714 
1715 filter_phase_data_options:
1716 filter_phase_check_helo_table |
1717 filter_phase_check_helo_regex |
1718 filter_phase_check_auth |
1719 filter_phase_check_auth_table |
1720 filter_phase_check_auth_regex |
1721 filter_phase_check_mail_from_table |
1722 filter_phase_check_mail_from_regex |
1723 filter_phase_global_options;
1724 
1725 /*
1726 filter_phase_quit_options:
1727 filter_phase_check_helo_table |
1728 filter_phase_check_helo_regex |
1729 filter_phase_global_options;
1730 
1731 filter_phase_rset_options:
1732 filter_phase_check_helo_table |
1733 filter_phase_check_helo_regex |
1734 filter_phase_global_options;
1735 
1736 filter_phase_noop_options:
1737 filter_phase_check_helo_table |
1738 filter_phase_check_helo_regex |
1739 filter_phase_global_options;
1740 */
1741 
1742 filter_phase_commit_options:
1743 filter_phase_check_helo_table |
1744 filter_phase_check_helo_regex |
1745 filter_phase_check_auth |
1746 filter_phase_check_auth_table |
1747 filter_phase_check_auth_regex |
1748 filter_phase_check_mail_from_table |
1749 filter_phase_check_mail_from_regex |
1750 filter_phase_global_options;
1751 
1752 
1753 filter_phase_connect:
1754 CONNECT {
1755 	filter_config->phase = FILTER_CONNECT;
1756 } MATCH filter_phase_connect_options filter_action_builtin
1757 ;
1758 
1759 
1760 filter_phase_helo:
1761 HELO {
1762 	filter_config->phase = FILTER_HELO;
1763 } MATCH filter_phase_helo_options filter_action_builtin
1764 ;
1765 
1766 filter_phase_ehlo:
1767 EHLO {
1768 	filter_config->phase = FILTER_EHLO;
1769 } MATCH filter_phase_helo_options filter_action_builtin
1770 ;
1771 
1772 filter_phase_auth:
1773 AUTH {
1774 } MATCH filter_phase_auth_options filter_action_builtin
1775 ;
1776 
1777 filter_phase_mail_from:
1778 MAIL_FROM {
1779 	filter_config->phase = FILTER_MAIL_FROM;
1780 } MATCH filter_phase_mail_from_options filter_action_builtin
1781 ;
1782 
1783 filter_phase_rcpt_to:
1784 RCPT_TO {
1785 	filter_config->phase = FILTER_RCPT_TO;
1786 } MATCH filter_phase_rcpt_to_options filter_action_builtin
1787 ;
1788 
1789 filter_phase_data:
1790 DATA {
1791 	filter_config->phase = FILTER_DATA;
1792 } MATCH filter_phase_data_options filter_action_builtin
1793 ;
1794 
1795 /*
1796 filter_phase_data_line:
1797 DATA_LINE {
1798 	filter_config->phase = FILTER_DATA_LINE;
1799 } MATCH filter_action_builtin
1800 ;
1801 
1802 filter_phase_quit:
1803 QUIT {
1804 	filter_config->phase = FILTER_QUIT;
1805 } filter_phase_quit_options filter_action_builtin
1806 ;
1807 
1808 filter_phase_rset:
1809 RSET {
1810 	filter_config->phase = FILTER_RSET;
1811 } MATCH filter_phase_rset_options filter_action_builtin
1812 ;
1813 
1814 filter_phase_noop:
1815 NOOP {
1816 	filter_config->phase = FILTER_NOOP;
1817 } MATCH filter_phase_noop_options filter_action_builtin
1818 ;
1819 */
1820 
1821 filter_phase_commit:
1822 COMMIT {
1823 	filter_config->phase = FILTER_COMMIT;
1824 } MATCH filter_phase_commit_options filter_action_builtin_nojunk
1825 ;
1826 
1827 
1828 
1829 filter_phase:
1830 filter_phase_connect
1831 | filter_phase_helo
1832 | filter_phase_ehlo
1833 | filter_phase_auth
1834 | filter_phase_mail_from
1835 | filter_phase_rcpt_to
1836 | filter_phase_data
1837 /*| filter_phase_data_line*/
1838 /*| filter_phase_quit*/
1839 /*| filter_phase_noop*/
1840 /*| filter_phase_rset*/
1841 | filter_phase_commit
1842 ;
1843 
1844 
1845 filterel:
1846 STRING	{
1847 	struct filter_config   *fr;
1848 	size_t			i;
1849 
1850 	if ((fr = dict_get(conf->sc_filters_dict, $1)) == NULL) {
1851 		yyerror("no filter exist with that name: %s", $1);
1852 		free($1);
1853 		YYERROR;
1854 	}
1855 	if (fr->filter_type == FILTER_TYPE_CHAIN) {
1856 		yyerror("no filter chain allowed within a filter chain: %s", $1);
1857 		free($1);
1858 		YYERROR;
1859 	}
1860 
1861 	for (i = 0; i < filter_config->chain_size; i++) {
1862 		if (strcmp(filter_config->chain[i], $1) == 0) {
1863 			yyerror("no filter allowed twice within a filter chain: %s", $1);
1864 			free($1);
1865 			YYERROR;
1866 		}
1867 	}
1868 
1869 	if (fr->proc) {
1870 		if (dict_get(&filter_config->chain_procs, fr->proc)) {
1871 			yyerror("no proc allowed twice within a filter chain: %s", fr->proc);
1872 			free($1);
1873 			YYERROR;
1874 		}
1875 		dict_set(&filter_config->chain_procs, fr->proc, NULL);
1876 	}
1877 
1878 	fr->filter_subsystem |= filter_config->filter_subsystem;
1879 	filter_config->chain_size += 1;
1880 	filter_config->chain = reallocarray(filter_config->chain, filter_config->chain_size, sizeof(char *));
1881 	if (filter_config->chain == NULL)
1882 		fatal("reallocarray");
1883 	filter_config->chain[filter_config->chain_size - 1] = $1;
1884 }
1885 ;
1886 
1887 filter_list:
1888 filterel
1889 | filterel comma filter_list
1890 ;
1891 
1892 filter:
1893 FILTER STRING PROC STRING {
1894 
1895 	if (dict_get(conf->sc_filters_dict, $2)) {
1896 		yyerror("filter already exists with that name: %s", $2);
1897 		free($2);
1898 		free($4);
1899 		YYERROR;
1900 	}
1901 	if (dict_get(conf->sc_filter_processes_dict, $4) == NULL) {
1902 		yyerror("no processor exist with that name: %s", $4);
1903 		free($4);
1904 		YYERROR;
1905 	}
1906 
1907 	filter_config = xcalloc(1, sizeof *filter_config);
1908 	filter_config->filter_type = FILTER_TYPE_PROC;
1909 	filter_config->name = $2;
1910 	filter_config->proc = $4;
1911 	dict_set(conf->sc_filters_dict, $2, filter_config);
1912 	filter_config = NULL;
1913 }
1914 |
1915 FILTER STRING PROC_EXEC STRING {
1916 	if (dict_get(conf->sc_filters_dict, $2)) {
1917 		yyerror("filter already exists with that name: %s", $2);
1918 		free($2);
1919 		free($4);
1920 		YYERROR;
1921 	}
1922 
1923 	processor = xcalloc(1, sizeof *processor);
1924 	processor->command = $4;
1925 
1926 	filter_config = xcalloc(1, sizeof *filter_config);
1927 	filter_config->filter_type = FILTER_TYPE_PROC;
1928 	filter_config->name = $2;
1929 	filter_config->proc = xstrdup($2);
1930 	dict_set(conf->sc_filters_dict, $2, filter_config);
1931 } proc_params {
1932 	dict_set(conf->sc_filter_processes_dict, filter_config->proc, processor);
1933 	processor = NULL;
1934 	filter_config = NULL;
1935 }
1936 |
1937 FILTER STRING PHASE {
1938 	if (dict_get(conf->sc_filters_dict, $2)) {
1939 		yyerror("filter already exists with that name: %s", $2);
1940 		free($2);
1941 		YYERROR;
1942 	}
1943 	filter_config = xcalloc(1, sizeof *filter_config);
1944 	filter_config->name = $2;
1945 	filter_config->filter_type = FILTER_TYPE_BUILTIN;
1946 	dict_set(conf->sc_filters_dict, $2, filter_config);
1947 } filter_phase {
1948 	filter_config = NULL;
1949 }
1950 |
1951 FILTER STRING CHAIN {
1952 	if (dict_get(conf->sc_filters_dict, $2)) {
1953 		yyerror("filter already exists with that name: %s", $2);
1954 		free($2);
1955 		YYERROR;
1956 	}
1957 	filter_config = xcalloc(1, sizeof *filter_config);
1958 	filter_config->filter_type = FILTER_TYPE_CHAIN;
1959 	dict_init(&filter_config->chain_procs);
1960 } '{' filter_list '}' {
1961 	dict_set(conf->sc_filters_dict, $2, filter_config);
1962 	filter_config = NULL;
1963 }
1964 ;
1965 
1966 size		: NUMBER		{
1967 			if ($1 < 0) {
1968 				yyerror("invalid size: %" PRId64, $1);
1969 				YYERROR;
1970 			}
1971 			$$ = $1;
1972 		}
1973 		| STRING			{
1974 			long long result;
1975 
1976 			if (scan_scaled($1, &result) == -1 || result < 0) {
1977 				yyerror("invalid size: %s", $1);
1978 				free($1);
1979 				YYERROR;
1980 			}
1981 			free($1);
1982 			$$ = result;
1983 		}
1984 		;
1985 
1986 bouncedelay	: STRING {
1987 			time_t	d;
1988 			int	i;
1989 
1990 			d = delaytonum($1);
1991 			if (d < 0) {
1992 				yyerror("invalid bounce delay: %s", $1);
1993 				free($1);
1994 				YYERROR;
1995 			}
1996 			free($1);
1997 			for (i = 0; i < MAX_BOUNCE_WARN; i++) {
1998 				if (conf->sc_bounce_warn[i] != 0)
1999 					continue;
2000 				conf->sc_bounce_warn[i] = d;
2001 				break;
2002 			}
2003 		}
2004 		;
2005 
2006 bouncedelays	: bouncedelays ',' bouncedelay
2007 		| bouncedelay
2008 		;
2009 
2010 opt_limit_mda	: STRING NUMBER {
2011 			if (!strcmp($1, "max-session")) {
2012 				conf->sc_mda_max_session = $2;
2013 			}
2014 			else if (!strcmp($1, "max-session-per-user")) {
2015 				conf->sc_mda_max_user_session = $2;
2016 			}
2017 			else if (!strcmp($1, "task-lowat")) {
2018 				conf->sc_mda_task_lowat = $2;
2019 			}
2020 			else if (!strcmp($1, "task-hiwat")) {
2021 				conf->sc_mda_task_hiwat = $2;
2022 			}
2023 			else if (!strcmp($1, "task-release")) {
2024 				conf->sc_mda_task_release = $2;
2025 			}
2026 			else {
2027 				yyerror("invalid scheduler limit keyword: %s", $1);
2028 				free($1);
2029 				YYERROR;
2030 			}
2031 			free($1);
2032 		}
2033 		;
2034 
2035 limits_smtp	: opt_limit_smtp limits_smtp
2036 		| /* empty */
2037 		;
2038 
2039 opt_limit_smtp : STRING NUMBER {
2040 			if (!strcmp($1, "max-rcpt")) {
2041 				conf->sc_session_max_rcpt = $2;
2042 			}
2043 			else if (!strcmp($1, "max-mails")) {
2044 				conf->sc_session_max_mails = $2;
2045 			}
2046 			else {
2047 				yyerror("invalid session limit keyword: %s", $1);
2048 				free($1);
2049 				YYERROR;
2050 			}
2051 			free($1);
2052 		}
2053 		;
2054 
2055 limits_mda	: opt_limit_mda limits_mda
2056 		| /* empty */
2057 		;
2058 
2059 opt_limit_mta	: INET4 {
2060 			limits->family = AF_INET;
2061 		}
2062 		| INET6 {
2063 			limits->family = AF_INET6;
2064 		}
2065 		| STRING NUMBER {
2066 			if (!limit_mta_set(limits, $1, $2)) {
2067 				yyerror("invalid mta limit keyword: %s", $1);
2068 				free($1);
2069 				YYERROR;
2070 			}
2071 			free($1);
2072 		}
2073 		;
2074 
2075 limits_mta	: opt_limit_mta limits_mta
2076 		| /* empty */
2077 		;
2078 
2079 opt_limit_scheduler : STRING NUMBER {
2080 			if (!strcmp($1, "max-inflight")) {
2081 				conf->sc_scheduler_max_inflight = $2;
2082 			}
2083 			else if (!strcmp($1, "max-evp-batch-size")) {
2084 				conf->sc_scheduler_max_evp_batch_size = $2;
2085 			}
2086 			else if (!strcmp($1, "max-msg-batch-size")) {
2087 				conf->sc_scheduler_max_msg_batch_size = $2;
2088 			}
2089 			else if (!strcmp($1, "max-schedule")) {
2090 				conf->sc_scheduler_max_schedule = $2;
2091 			}
2092 			else {
2093 				yyerror("invalid scheduler limit keyword: %s", $1);
2094 				free($1);
2095 				YYERROR;
2096 			}
2097 			free($1);
2098 		}
2099 		;
2100 
2101 limits_scheduler: opt_limit_scheduler limits_scheduler
2102 		| /* empty */
2103 		;
2104 
2105 
2106 opt_sock_listen : FILTER STRING {
2107 			struct filter_config *fc;
2108 
2109 			if (listen_opts.options & LO_FILTER) {
2110 				yyerror("filter already specified");
2111 				free($2);
2112 				YYERROR;
2113 			}
2114 			if ((fc = dict_get(conf->sc_filters_dict, $2)) == NULL) {
2115 				yyerror("no filter exist with that name: %s", $2);
2116 				free($2);
2117 				YYERROR;
2118 			}
2119 			fc->filter_subsystem |= FILTER_SUBSYSTEM_SMTP_IN;
2120 			listen_opts.options |= LO_FILTER;
2121 			listen_opts.filtername = $2;
2122 		}
2123 		| FILTER {
2124 			char	buffer[128];
2125 
2126 			if (listen_opts.options & LO_FILTER) {
2127 				yyerror("filter already specified");
2128 				YYERROR;
2129 			}
2130 
2131 			do {
2132 				(void)snprintf(buffer, sizeof buffer, "<dynchain:%08x>", last_dynchain_id++);
2133 			} while (dict_check(conf->sc_filters_dict, buffer));
2134 
2135 			listen_opts.options |= LO_FILTER;
2136 			listen_opts.filtername = xstrdup(buffer);
2137 			filter_config = xcalloc(1, sizeof *filter_config);
2138 			filter_config->filter_type = FILTER_TYPE_CHAIN;
2139 			filter_config->filter_subsystem |= FILTER_SUBSYSTEM_SMTP_IN;
2140 			dict_init(&filter_config->chain_procs);
2141 		} '{' filter_list '}' {
2142 			dict_set(conf->sc_filters_dict, listen_opts.filtername, filter_config);
2143 			filter_config = NULL;
2144 		}
2145 		| MASK_SRC {
2146 			if (config_lo_mask_source(&listen_opts)) {
2147 				YYERROR;
2148 			}
2149 		}
2150 		| TAG STRING			{
2151 			if (listen_opts.options & LO_TAG) {
2152 				yyerror("tag already specified");
2153 				YYERROR;
2154 			}
2155 			listen_opts.options |= LO_TAG;
2156 
2157 			if (strlen($2) >= SMTPD_TAG_SIZE) {
2158 				yyerror("tag name too long");
2159 				free($2);
2160 				YYERROR;
2161 			}
2162 			listen_opts.tag = $2;
2163 		}
2164 		;
2165 
2166 opt_if_listen : INET4 {
2167 			if (listen_opts.options & LO_FAMILY) {
2168 				yyerror("address family already specified");
2169 				YYERROR;
2170 			}
2171 			listen_opts.options |= LO_FAMILY;
2172 			listen_opts.family = AF_INET;
2173 		}
2174 		| INET6			{
2175 			if (listen_opts.options & LO_FAMILY) {
2176 				yyerror("address family already specified");
2177 				YYERROR;
2178 			}
2179 			listen_opts.options |= LO_FAMILY;
2180 			listen_opts.family = AF_INET6;
2181 		}
2182 		| PORT STRING			{
2183 			struct servent	*servent;
2184 
2185 			if (listen_opts.options & LO_PORT) {
2186 				yyerror("port already specified");
2187 				YYERROR;
2188 			}
2189 			listen_opts.options |= LO_PORT;
2190 
2191 			servent = getservbyname($2, "tcp");
2192 			if (servent == NULL) {
2193 				yyerror("invalid port: %s", $2);
2194 				free($2);
2195 				YYERROR;
2196 			}
2197 			free($2);
2198 			listen_opts.port = ntohs(servent->s_port);
2199 		}
2200 		| PORT SMTP			{
2201 			struct servent *servent;
2202 
2203 			if (listen_opts.options & LO_PORT) {
2204 				yyerror("port already specified");
2205 				YYERROR;
2206 			}
2207 			listen_opts.options |= LO_PORT;
2208 
2209 			servent = getservbyname("smtp", "tcp");
2210 			if (servent == NULL) {
2211 				yyerror("invalid port: smtp");
2212 				YYERROR;
2213 			}
2214 			listen_opts.port = ntohs(servent->s_port);
2215 		}
2216 		| PORT SMTPS			{
2217 			struct servent *servent;
2218 
2219 			if (listen_opts.options & LO_PORT) {
2220 				yyerror("port already specified");
2221 				YYERROR;
2222 			}
2223 			listen_opts.options |= LO_PORT;
2224 
2225 			servent = getservbyname("smtps", "tcp");
2226 			if (servent == NULL) {
2227 				yyerror("invalid port: smtps");
2228 				YYERROR;
2229 			}
2230 			listen_opts.port = ntohs(servent->s_port);
2231 		}
2232 		| PORT NUMBER			{
2233 			if (listen_opts.options & LO_PORT) {
2234 				yyerror("port already specified");
2235 				YYERROR;
2236 			}
2237 			listen_opts.options |= LO_PORT;
2238 
2239 			if ($2 <= 0 || $2 > (int)USHRT_MAX) {
2240 				yyerror("invalid port: %" PRId64, $2);
2241 				YYERROR;
2242 			}
2243 			listen_opts.port = $2;
2244 		}
2245 		| FILTER STRING			{
2246 			struct filter_config *fc;
2247 
2248 			if (listen_opts.options & LO_FILTER) {
2249 				yyerror("filter already specified");
2250 				YYERROR;
2251 			}
2252 			if ((fc = dict_get(conf->sc_filters_dict, $2)) == NULL) {
2253 				yyerror("no filter exist with that name: %s", $2);
2254 				free($2);
2255 				YYERROR;
2256 			}
2257 			fc->filter_subsystem |= FILTER_SUBSYSTEM_SMTP_IN;
2258 			listen_opts.options |= LO_FILTER;
2259 			listen_opts.filtername = $2;
2260 		}
2261 		| FILTER {
2262 			char	buffer[128];
2263 
2264 			if (listen_opts.options & LO_FILTER) {
2265 				yyerror("filter already specified");
2266 				YYERROR;
2267 			}
2268 
2269 			do {
2270 				(void)snprintf(buffer, sizeof buffer, "<dynchain:%08x>", last_dynchain_id++);
2271 			} while (dict_check(conf->sc_filters_dict, buffer));
2272 
2273 			listen_opts.options |= LO_FILTER;
2274 			listen_opts.filtername = xstrdup(buffer);
2275 			filter_config = xcalloc(1, sizeof *filter_config);
2276 			filter_config->filter_type = FILTER_TYPE_CHAIN;
2277 			filter_config->filter_subsystem |= FILTER_SUBSYSTEM_SMTP_IN;
2278 			dict_init(&filter_config->chain_procs);
2279 		} '{' filter_list '}' {
2280 			dict_set(conf->sc_filters_dict, listen_opts.filtername, filter_config);
2281 			filter_config = NULL;
2282 		}
2283 		| SMTPS				{
2284 			if (listen_opts.options & LO_SSL) {
2285 				yyerror("TLS mode already specified");
2286 				YYERROR;
2287 			}
2288 			listen_opts.options |= LO_SSL;
2289 			listen_opts.ssl = F_SMTPS;
2290 		}
2291 		| SMTPS VERIFY 			{
2292 			if (listen_opts.options & LO_SSL) {
2293 				yyerror("TLS mode already specified");
2294 				YYERROR;
2295 			}
2296 			listen_opts.options |= LO_SSL;
2297 			listen_opts.ssl = F_SMTPS|F_TLS_VERIFY;
2298 		}
2299 		| TLS				{
2300 			if (listen_opts.options & LO_SSL) {
2301 				yyerror("TLS mode already specified");
2302 				YYERROR;
2303 			}
2304 			listen_opts.options |= LO_SSL;
2305 			listen_opts.ssl = F_STARTTLS;
2306 		}
2307 		| TLS_REQUIRE			{
2308 			if (listen_opts.options & LO_SSL) {
2309 				yyerror("TLS mode already specified");
2310 				YYERROR;
2311 			}
2312 			listen_opts.options |= LO_SSL;
2313 			listen_opts.ssl = F_STARTTLS|F_STARTTLS_REQUIRE;
2314 		}
2315 		| TLS_REQUIRE VERIFY   		{
2316 			if (listen_opts.options & LO_SSL) {
2317 				yyerror("TLS mode already specified");
2318 				YYERROR;
2319 			}
2320 			listen_opts.options |= LO_SSL;
2321 			listen_opts.ssl = F_STARTTLS|F_STARTTLS_REQUIRE|F_TLS_VERIFY;
2322 		}
2323 		| CIPHERS STRING {
2324 			if (listen_opts.tls_ciphers) {
2325 				yyerror("ciphers already specified");
2326 				YYERROR;
2327 			}
2328 			listen_opts.tls_ciphers = $2;
2329 		}
2330 		| PROTOCOLS STRING {
2331 			if (listen_opts.tls_protocols) {
2332 				yyerror("protocols already specified");
2333 				YYERROR;
2334 			}
2335 			listen_opts.tls_protocols = $2;
2336 		}
2337 		| PKI STRING			{
2338 			if (listen_opts.pkicount == PKI_MAX) {
2339 				yyerror("too many pki specified");
2340 				YYERROR;
2341 			}
2342 			listen_opts.pki[listen_opts.pkicount++] = $2;
2343 		}
2344 		| CA STRING			{
2345 			if (listen_opts.options & LO_CA) {
2346 				yyerror("ca already specified");
2347 				YYERROR;
2348 			}
2349 			listen_opts.options |= LO_CA;
2350 			listen_opts.ca = $2;
2351 		}
2352 		| AUTH				{
2353 			if (listen_opts.options & LO_AUTH) {
2354 				yyerror("auth already specified");
2355 				YYERROR;
2356 			}
2357 			listen_opts.options |= LO_AUTH;
2358 			listen_opts.auth = F_AUTH|F_AUTH_REQUIRE;
2359 		}
2360 		| AUTH_OPTIONAL			{
2361 			if (listen_opts.options & LO_AUTH) {
2362 				yyerror("auth already specified");
2363 				YYERROR;
2364 			}
2365 			listen_opts.options |= LO_AUTH;
2366 			listen_opts.auth = F_AUTH;
2367 		}
2368 		| AUTH tables  			{
2369 			if (listen_opts.options & LO_AUTH) {
2370 				yyerror("auth already specified");
2371 				YYERROR;
2372 			}
2373 			listen_opts.options |= LO_AUTH;
2374 			listen_opts.authtable = $2;
2375 			listen_opts.auth = F_AUTH|F_AUTH_REQUIRE;
2376 		}
2377 		| AUTH_OPTIONAL tables 		{
2378 			if (listen_opts.options & LO_AUTH) {
2379 				yyerror("auth already specified");
2380 				YYERROR;
2381 			}
2382 			listen_opts.options |= LO_AUTH;
2383 			listen_opts.authtable = $2;
2384 			listen_opts.auth = F_AUTH;
2385 		}
2386 		| TAG STRING			{
2387 			if (listen_opts.options & LO_TAG) {
2388 				yyerror("tag already specified");
2389 				YYERROR;
2390 			}
2391 			listen_opts.options |= LO_TAG;
2392 
2393 			if (strlen($2) >= SMTPD_TAG_SIZE) {
2394        				yyerror("tag name too long");
2395 				free($2);
2396 				YYERROR;
2397 			}
2398 			listen_opts.tag = $2;
2399 		}
2400 		| HOSTNAME STRING	{
2401 			if (listen_opts.options & LO_HOSTNAME) {
2402 				yyerror("hostname already specified");
2403 				YYERROR;
2404 			}
2405 			listen_opts.options |= LO_HOSTNAME;
2406 
2407 			listen_opts.hostname = $2;
2408 		}
2409 		| HOSTNAMES tables	{
2410 			struct table	*t = $2;
2411 
2412 			if (listen_opts.options & LO_HOSTNAMES) {
2413 				yyerror("hostnames already specified");
2414 				YYERROR;
2415 			}
2416 			listen_opts.options |= LO_HOSTNAMES;
2417 
2418 			if (!table_check_use(t, T_DYNAMIC|T_HASH, K_ADDRNAME)) {
2419 				yyerror("invalid use of table \"%s\" as "
2420 				    "HOSTNAMES parameter", t->t_name);
2421 				YYERROR;
2422 			}
2423 			listen_opts.hostnametable = t;
2424 		}
2425 		| MASK_SRC	{
2426 			if (config_lo_mask_source(&listen_opts)) {
2427 				YYERROR;
2428 			}
2429 		}
2430 		| RECEIVEDAUTH	{
2431 			if (listen_opts.options & LO_RECEIVEDAUTH) {
2432 				yyerror("received-auth already specified");
2433 				YYERROR;
2434 			}
2435 			listen_opts.options |= LO_RECEIVEDAUTH;
2436 			listen_opts.flags |= F_RECEIVEDAUTH;
2437 		}
2438 		| NO_DSN	{
2439 			if (listen_opts.options & LO_NODSN) {
2440 				yyerror("no-dsn already specified");
2441 				YYERROR;
2442 			}
2443 			listen_opts.options |= LO_NODSN;
2444 			listen_opts.flags &= ~F_EXT_DSN;
2445 		}
2446 		| PROXY_V2	{
2447 			if (listen_opts.options & LO_PROXY) {
2448 				yyerror("proxy-v2 already specified");
2449 				YYERROR;
2450 			}
2451 			listen_opts.options |= LO_PROXY;
2452 			listen_opts.flags |= F_PROXY;
2453 		}
2454 		| SENDERS tables	{
2455 			struct table	*t = $2;
2456 
2457 			if (listen_opts.options & LO_SENDERS) {
2458 				yyerror("senders already specified");
2459 				YYERROR;
2460 			}
2461 			listen_opts.options |= LO_SENDERS;
2462 
2463 			if (!table_check_use(t, T_DYNAMIC|T_HASH, K_MAILADDRMAP)) {
2464 				yyerror("invalid use of table \"%s\" as "
2465 				    "SENDERS parameter", t->t_name);
2466 				YYERROR;
2467 			}
2468 			listen_opts.sendertable = t;
2469 		}
2470 		| SENDERS tables MASQUERADE	{
2471 			struct table	*t = $2;
2472 
2473 			if (listen_opts.options & LO_SENDERS) {
2474 				yyerror("senders already specified");
2475 				YYERROR;
2476 			}
2477 			listen_opts.options |= LO_SENDERS|LO_MASQUERADE;
2478 
2479 			if (!table_check_use(t, T_DYNAMIC|T_HASH, K_MAILADDRMAP)) {
2480 				yyerror("invalid use of table \"%s\" as "
2481 				    "SENDERS parameter", t->t_name);
2482 				YYERROR;
2483 			}
2484 			listen_opts.sendertable = t;
2485 		}
2486 		;
2487 
2488 listener_type	: socket_listener
2489 		| if_listener
2490 		;
2491 
2492 socket_listener	: SOCKET sock_listen {
2493 			if (conf->sc_sock_listener) {
2494 				yyerror("socket listener already configured");
2495 				YYERROR;
2496 			}
2497 			create_sock_listener(&listen_opts);
2498 		}
2499 		;
2500 
2501 if_listener	: STRING if_listen {
2502 			listen_opts.ifx = $1;
2503 			create_if_listener(&listen_opts);
2504 		}
2505 		;
2506 
2507 sock_listen	: opt_sock_listen sock_listen
2508 		| /* empty */
2509 		;
2510 
2511 if_listen	: opt_if_listen if_listen
2512 		| /* empty */
2513 		;
2514 
2515 
2516 listen		: LISTEN {
2517 			memset(&listen_opts, 0, sizeof listen_opts);
2518 			listen_opts.family = AF_UNSPEC;
2519 			listen_opts.flags |= F_EXT_DSN;
2520 		} ON listener_type {
2521 			free(listen_opts.tls_protocols);
2522 			free(listen_opts.tls_ciphers);
2523 			memset(&listen_opts, 0, sizeof listen_opts);
2524 		}
2525 		;
2526 
2527 table		: TABLE STRING STRING	{
2528 			char *p, *backend, *config;
2529 
2530 			p = $3;
2531 			if (*p == '/') {
2532 				backend = "static";
2533 				config = $3;
2534 			}
2535 			else {
2536 				backend = $3;
2537 				config = NULL;
2538 				for (p = $3; *p && *p != ':'; p++)
2539 					;
2540 				if (*p == ':') {
2541 					*p = '\0';
2542 					backend = $3;
2543 					config  = p+1;
2544 				}
2545 			}
2546 			if (config != NULL && *config != '/') {
2547 				yyerror("invalid backend parameter for table: %s",
2548 				    $2);
2549 				free($2);
2550 				free($3);
2551 				YYERROR;
2552 			}
2553 			table = table_create(conf, backend, $2, config);
2554 			if (!table_config(table)) {
2555 				yyerror("invalid configuration file %s for table %s",
2556 				    config, table->t_name);
2557 				free($2);
2558 				free($3);
2559 				YYERROR;
2560 			}
2561 			table = NULL;
2562 			free($2);
2563 			free($3);
2564 		}
2565 		| TABLE STRING {
2566 			table = table_create(conf, "static", $2, NULL);
2567 			free($2);
2568 		} '{' tableval_list '}' {
2569 			table = NULL;
2570 		}
2571 		;
2572 
2573 tablenew	: STRING			{
2574 			struct table	*t;
2575 
2576 			t = table_create(conf, "static", NULL, NULL);
2577 			table_add(t, $1, NULL);
2578 			free($1);
2579 			$$ = t;
2580 		}
2581 		| '{'				{
2582 			table = table_create(conf, "static", NULL, NULL);
2583 		} tableval_list '}'		{
2584 			$$ = table;
2585 			table = NULL;
2586 		}
2587 		;
2588 
2589 tableref       	: '<' STRING '>'       		{
2590 			struct table	*t;
2591 
2592 			if ((t = table_find(conf, $2)) == NULL) {
2593 				yyerror("no such table: %s", $2);
2594 				free($2);
2595 				YYERROR;
2596 			}
2597 			free($2);
2598 			$$ = t;
2599 		}
2600 		;
2601 
2602 tables		: tablenew			{ $$ = $1; }
2603 		| tableref			{ $$ = $1; }
2604 		;
2605 
2606 
2607 %%
2608 
2609 struct keywords {
2610 	const char	*k_name;
2611 	int		 k_val;
2612 };
2613 
2614 int
2615 yyerror(const char *fmt, ...)
2616 {
2617 	va_list		 ap;
2618 	char		*msg;
2619 
2620 	file->errors++;
2621 	va_start(ap, fmt);
2622 	if (vasprintf(&msg, fmt, ap) == -1)
2623 		fatalx("yyerror vasprintf");
2624 	va_end(ap);
2625 	logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg);
2626 	free(msg);
2627 	return (0);
2628 }
2629 
2630 int
2631 kw_cmp(const void *k, const void *e)
2632 {
2633 	return (strcmp(k, ((const struct keywords *)e)->k_name));
2634 }
2635 
2636 int
2637 lookup(char *s)
2638 {
2639 	/* this has to be sorted always */
2640 	static const struct keywords keywords[] = {
2641 		{ "action",		ACTION },
2642 		{ "admd",		ADMD },
2643 		{ "alias",		ALIAS },
2644 		{ "any",		ANY },
2645 		{ "auth",		AUTH },
2646 		{ "auth-optional",     	AUTH_OPTIONAL },
2647 		{ "backup",		BACKUP },
2648 		{ "bounce",		BOUNCE },
2649 		{ "bypass",		BYPASS },
2650 		{ "ca",			CA },
2651 		{ "cert",		CERT },
2652 		{ "chain",		CHAIN },
2653 		{ "chroot",		CHROOT },
2654 		{ "ciphers",		CIPHERS },
2655 		{ "commit",		COMMIT },
2656 		{ "compression",	COMPRESSION },
2657 		{ "connect",		CONNECT },
2658 		{ "data",		DATA },
2659 		{ "data-line",		DATA_LINE },
2660 		{ "dhe",		DHE },
2661 		{ "disconnect",		DISCONNECT },
2662 		{ "domain",		DOMAIN },
2663 		{ "ehlo",		EHLO },
2664 		{ "encryption",		ENCRYPTION },
2665 		{ "expand-only",      	EXPAND_ONLY },
2666 		{ "fcrdns",		FCRDNS },
2667 		{ "filter",		FILTER },
2668 		{ "for",		FOR },
2669 		{ "forward-only",      	FORWARD_ONLY },
2670 		{ "from",		FROM },
2671 		{ "group",		GROUP },
2672 		{ "helo",		HELO },
2673 		{ "helo-src",       	HELO_SRC },
2674 		{ "host",		HOST },
2675 		{ "hostname",		HOSTNAME },
2676 		{ "hostnames",		HOSTNAMES },
2677 		{ "include",		INCLUDE },
2678 		{ "inet4",		INET4 },
2679 		{ "inet6",		INET6 },
2680 		{ "junk",		JUNK },
2681 		{ "key",		KEY },
2682 		{ "limit",		LIMIT },
2683 		{ "listen",		LISTEN },
2684 		{ "lmtp",		LMTP },
2685 		{ "local",		LOCAL },
2686 		{ "mail-from",		MAIL_FROM },
2687 		{ "maildir",		MAILDIR },
2688 		{ "mask-src",		MASK_SRC },
2689 		{ "masquerade",		MASQUERADE },
2690 		{ "match",		MATCH },
2691 		{ "max-deferred",  	MAX_DEFERRED },
2692 		{ "max-message-size",  	MAX_MESSAGE_SIZE },
2693 		{ "mbox",		MBOX },
2694 		{ "mda",		MDA },
2695 		{ "mta",		MTA },
2696 		{ "mx",			MX },
2697 		{ "no-dsn",		NO_DSN },
2698 		{ "no-verify",		NO_VERIFY },
2699 		{ "noop",		NOOP },
2700 		{ "on",			ON },
2701 		{ "phase",		PHASE },
2702 		{ "pki",		PKI },
2703 		{ "port",		PORT },
2704 		{ "proc",		PROC },
2705 		{ "proc-exec",		PROC_EXEC },
2706 		{ "protocols",		PROTOCOLS },
2707 		{ "proxy-v2",		PROXY_V2 },
2708 		{ "queue",		QUEUE },
2709 		{ "quit",		QUIT },
2710 		{ "rcpt-to",		RCPT_TO },
2711 		{ "rdns",		RDNS },
2712 		{ "received-auth",     	RECEIVEDAUTH },
2713 		{ "recipient",		RECIPIENT },
2714 		{ "regex",		REGEX },
2715 		{ "reject",		REJECT },
2716 		{ "relay",		RELAY },
2717 		{ "report",		REPORT },
2718 		{ "rewrite",		REWRITE },
2719 		{ "rset",		RSET },
2720 		{ "scheduler",		SCHEDULER },
2721 		{ "senders",   		SENDERS },
2722 		{ "smtp",		SMTP },
2723 		{ "smtp-in",		SMTP_IN },
2724 		{ "smtp-out",		SMTP_OUT },
2725 		{ "smtps",		SMTPS },
2726 		{ "socket",		SOCKET },
2727 		{ "src",		SRC },
2728 		{ "srs",		SRS },
2729 		{ "sub-addr-delim",	SUB_ADDR_DELIM },
2730 		{ "table",		TABLE },
2731 		{ "tag",		TAG },
2732 		{ "tagged",		TAGGED },
2733 		{ "tls",		TLS },
2734 		{ "tls-require",       	TLS_REQUIRE },
2735 		{ "ttl",		TTL },
2736 		{ "user",		USER },
2737 		{ "userbase",		USERBASE },
2738 		{ "verify",		VERIFY },
2739 		{ "virtual",		VIRTUAL },
2740 		{ "warn-interval",	WARN_INTERVAL },
2741 		{ "wrapper",		WRAPPER },
2742 	};
2743 	const struct keywords	*p;
2744 
2745 	p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
2746 	    sizeof(keywords[0]), kw_cmp);
2747 
2748 	if (p)
2749 		return (p->k_val);
2750 	else
2751 		return (STRING);
2752 }
2753 
2754 #define START_EXPAND	1
2755 #define DONE_EXPAND	2
2756 
2757 static int	expanding;
2758 
2759 int
2760 igetc(void)
2761 {
2762 	int	c;
2763 
2764 	while (1) {
2765 		if (file->ungetpos > 0)
2766 			c = file->ungetbuf[--file->ungetpos];
2767 		else
2768 			c = getc(file->stream);
2769 
2770 		if (c == START_EXPAND)
2771 			expanding = 1;
2772 		else if (c == DONE_EXPAND)
2773 			expanding = 0;
2774 		else
2775 			break;
2776 	}
2777 	return (c);
2778 }
2779 
2780 int
2781 lgetc(int quotec)
2782 {
2783 	int		c, next;
2784 
2785 	if (quotec) {
2786 		if ((c = igetc()) == EOF) {
2787 			yyerror("reached end of file while parsing "
2788 			    "quoted string");
2789 			if (file == topfile || popfile() == EOF)
2790 				return (EOF);
2791 			return (quotec);
2792 		}
2793 		return (c);
2794 	}
2795 
2796 	while ((c = igetc()) == '\\') {
2797 		next = igetc();
2798 		if (next != '\n') {
2799 			c = next;
2800 			break;
2801 		}
2802 		yylval.lineno = file->lineno;
2803 		file->lineno++;
2804 	}
2805 
2806 	if (c == EOF) {
2807 		/*
2808 		 * Fake EOL when hit EOF for the first time. This gets line
2809 		 * count right if last line in included file is syntactically
2810 		 * invalid and has no newline.
2811 		 */
2812 		if (file->eof_reached == 0) {
2813 			file->eof_reached = 1;
2814 			return ('\n');
2815 		}
2816 		while (c == EOF) {
2817 			if (file == topfile || popfile() == EOF)
2818 				return (EOF);
2819 			c = igetc();
2820 		}
2821 	}
2822 	return (c);
2823 }
2824 
2825 void
2826 lungetc(int c)
2827 {
2828 	if (c == EOF)
2829 		return;
2830 
2831 	if (file->ungetpos >= file->ungetsize) {
2832 		void *p = reallocarray(file->ungetbuf, file->ungetsize, 2);
2833 		if (p == NULL)
2834 			fatal("%s", __func__);
2835 		file->ungetbuf = p;
2836 		file->ungetsize *= 2;
2837 	}
2838 	file->ungetbuf[file->ungetpos++] = c;
2839 }
2840 
2841 int
2842 findeol(void)
2843 {
2844 	int	c;
2845 
2846 	/* skip to either EOF or the first real EOL */
2847 	while (1) {
2848 		c = lgetc(0);
2849 		if (c == '\n') {
2850 			file->lineno++;
2851 			break;
2852 		}
2853 		if (c == EOF)
2854 			break;
2855 	}
2856 	return (ERROR);
2857 }
2858 
2859 int
2860 yylex(void)
2861 {
2862 	unsigned char	 buf[8096];
2863 	unsigned char	*p, *val;
2864 	int		 quotec, next, c;
2865 	int		 token;
2866 
2867 top:
2868 	p = buf;
2869 	while ((c = lgetc(0)) == ' ' || c == '\t')
2870 		; /* nothing */
2871 
2872 	yylval.lineno = file->lineno;
2873 	if (c == '#')
2874 		while ((c = lgetc(0)) != '\n' && c != EOF)
2875 			; /* nothing */
2876 	if (c == '$' && !expanding) {
2877 		while (1) {
2878 			if ((c = lgetc(0)) == EOF)
2879 				return (0);
2880 
2881 			if (p + 1 >= buf + sizeof(buf) - 1) {
2882 				yyerror("string too long");
2883 				return (findeol());
2884 			}
2885 			if (isalnum(c) || c == '_') {
2886 				*p++ = c;
2887 				continue;
2888 			}
2889 			*p = '\0';
2890 			lungetc(c);
2891 			break;
2892 		}
2893 		val = symget(buf);
2894 		if (val == NULL) {
2895 			yyerror("macro '%s' not defined", buf);
2896 			return (findeol());
2897 		}
2898 		p = val + strlen(val) - 1;
2899 		lungetc(DONE_EXPAND);
2900 		while (p >= val) {
2901 			lungetc(*p);
2902 			p--;
2903 		}
2904 		lungetc(START_EXPAND);
2905 		goto top;
2906 	}
2907 
2908 	switch (c) {
2909 	case '\'':
2910 	case '"':
2911 		quotec = c;
2912 		while (1) {
2913 			if ((c = lgetc(quotec)) == EOF)
2914 				return (0);
2915 			if (c == '\n') {
2916 				file->lineno++;
2917 				continue;
2918 			} else if (c == '\\') {
2919 				if ((next = lgetc(quotec)) == EOF)
2920 					return (0);
2921 				if (next == quotec || next == ' ' ||
2922 				    next == '\t')
2923 					c = next;
2924 				else if (next == '\n') {
2925 					file->lineno++;
2926 					continue;
2927 				} else
2928 					lungetc(next);
2929 			} else if (c == quotec) {
2930 				*p = '\0';
2931 				break;
2932 			} else if (c == '\0') {
2933 				yyerror("syntax error");
2934 				return (findeol());
2935 			}
2936 			if (p + 1 >= buf + sizeof(buf) - 1) {
2937 				yyerror("string too long");
2938 				return (findeol());
2939 			}
2940 			*p++ = c;
2941 		}
2942 		yylval.v.string = strdup(buf);
2943 		if (yylval.v.string == NULL)
2944 			fatal("%s", __func__);
2945 		return (STRING);
2946 	}
2947 
2948 #define allowed_to_end_number(x) \
2949 	(isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
2950 
2951 	if (c == '-' || isdigit(c)) {
2952 		do {
2953 			*p++ = c;
2954 			if ((size_t)(p-buf) >= sizeof(buf)) {
2955 				yyerror("string too long");
2956 				return (findeol());
2957 			}
2958 		} while ((c = lgetc(0)) != EOF && isdigit(c));
2959 		lungetc(c);
2960 		if (p == buf + 1 && buf[0] == '-')
2961 			goto nodigits;
2962 		if (c == EOF || allowed_to_end_number(c)) {
2963 			const char *errstr = NULL;
2964 
2965 			*p = '\0';
2966 			yylval.v.number = strtonum(buf, LLONG_MIN,
2967 			    LLONG_MAX, &errstr);
2968 			if (errstr) {
2969 				yyerror("\"%s\" invalid number: %s",
2970 				    buf, errstr);
2971 				return (findeol());
2972 			}
2973 			return (NUMBER);
2974 		} else {
2975 nodigits:
2976 			while (p > buf + 1)
2977 				lungetc(*--p);
2978 			c = *--p;
2979 			if (c == '-')
2980 				return (c);
2981 		}
2982 	}
2983 
2984 	if (c == '=') {
2985 		if ((c = lgetc(0)) != EOF && c == '>')
2986 			return (ARROW);
2987 		lungetc(c);
2988 		c = '=';
2989 	}
2990 
2991 #define allowed_in_string(x) \
2992 	(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
2993 	x != '{' && x != '}' && x != '<' && x != '>' && \
2994 	x != '!' && x != '=' && x != '#' && \
2995 	x != ','))
2996 
2997 	if (isalnum(c) || c == ':' || c == '_') {
2998 		do {
2999 			*p++ = c;
3000 			if ((size_t)(p-buf) >= sizeof(buf)) {
3001 				yyerror("string too long");
3002 				return (findeol());
3003 			}
3004 		} while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
3005 		lungetc(c);
3006 		*p = '\0';
3007 		if ((token = lookup(buf)) == STRING)
3008 			if ((yylval.v.string = strdup(buf)) == NULL)
3009 				fatal("%s", __func__);
3010 		return (token);
3011 	}
3012 	if (c == '\n') {
3013 		yylval.lineno = file->lineno;
3014 		file->lineno++;
3015 	}
3016 	if (c == EOF)
3017 		return (0);
3018 	return (c);
3019 }
3020 
3021 int
3022 check_file_secrecy(int fd, const char *fname)
3023 {
3024 	struct stat	st;
3025 
3026 	if (fstat(fd, &st)) {
3027 		log_warn("warn: cannot stat %s", fname);
3028 		return (-1);
3029 	}
3030 	if (st.st_uid != 0 && st.st_uid != getuid()) {
3031 		log_warnx("warn: %s: owner not root or current user", fname);
3032 		return (-1);
3033 	}
3034 	if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) {
3035 		log_warnx("warn: %s: group/world readable/writeable", fname);
3036 		return (-1);
3037 	}
3038 	return (0);
3039 }
3040 
3041 struct file *
3042 pushfile(const char *name, int secret)
3043 {
3044 	struct file	*nfile;
3045 
3046 	if ((nfile = calloc(1, sizeof(struct file))) == NULL) {
3047 		log_warn("%s", __func__);
3048 		return (NULL);
3049 	}
3050 	if ((nfile->name = strdup(name)) == NULL) {
3051 		log_warn("%s", __func__);
3052 		free(nfile);
3053 		return (NULL);
3054 	}
3055 	if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
3056 		log_warn("%s: %s", __func__, nfile->name);
3057 		free(nfile->name);
3058 		free(nfile);
3059 		return (NULL);
3060 	} else if (secret &&
3061 	    check_file_secrecy(fileno(nfile->stream), nfile->name)) {
3062 		fclose(nfile->stream);
3063 		free(nfile->name);
3064 		free(nfile);
3065 		return (NULL);
3066 	}
3067 	nfile->lineno = TAILQ_EMPTY(&files) ? 1 : 0;
3068 	nfile->ungetsize = 16;
3069 	nfile->ungetbuf = malloc(nfile->ungetsize);
3070 	if (nfile->ungetbuf == NULL) {
3071 		log_warn("%s", __func__);
3072 		fclose(nfile->stream);
3073 		free(nfile->name);
3074 		free(nfile);
3075 		return (NULL);
3076 	}
3077 	TAILQ_INSERT_TAIL(&files, nfile, entry);
3078 	return (nfile);
3079 }
3080 
3081 int
3082 popfile(void)
3083 {
3084 	struct file	*prev;
3085 
3086 	if ((prev = TAILQ_PREV(file, files, entry)) != NULL)
3087 		prev->errors += file->errors;
3088 
3089 	TAILQ_REMOVE(&files, file, entry);
3090 	fclose(file->stream);
3091 	free(file->name);
3092 	free(file->ungetbuf);
3093 	free(file);
3094 	file = prev;
3095 	return (file ? 0 : EOF);
3096 }
3097 
3098 int
3099 parse_config(struct smtpd *x_conf, const char *filename, int opts)
3100 {
3101 	struct sym     *sym, *next;
3102 
3103 	conf = x_conf;
3104 	errors = 0;
3105 
3106 	if ((file = pushfile(filename, 0)) == NULL) {
3107 		purge_config(PURGE_EVERYTHING);
3108 		return (-1);
3109 	}
3110 	topfile = file;
3111 
3112 	/*
3113 	 * parse configuration
3114 	 */
3115 	setservent(1);
3116 	yyparse();
3117 	errors = file->errors;
3118 	popfile();
3119 	endservent();
3120 
3121 	/* If the socket listener was not configured, create a default one. */
3122 	if (!conf->sc_sock_listener) {
3123 		memset(&listen_opts, 0, sizeof listen_opts);
3124 		create_sock_listener(&listen_opts);
3125 	}
3126 
3127 	/* Free macros and check which have not been used. */
3128 	TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) {
3129 		if ((conf->sc_opts & SMTPD_OPT_VERBOSE) && !sym->used)
3130 			fprintf(stderr, "warning: macro '%s' not "
3131 			    "used\n", sym->nam);
3132 		if (!sym->persist) {
3133 			free(sym->nam);
3134 			free(sym->val);
3135 			TAILQ_REMOVE(&symhead, sym, entry);
3136 			free(sym);
3137 		}
3138 	}
3139 
3140 	if (TAILQ_EMPTY(conf->sc_rules)) {
3141 		log_warnx("warn: no rules, nothing to do");
3142 		errors++;
3143 	}
3144 
3145 	if (errors) {
3146 		purge_config(PURGE_EVERYTHING);
3147 		return (-1);
3148 	}
3149 
3150 	return (0);
3151 }
3152 
3153 int
3154 symset(const char *nam, const char *val, int persist)
3155 {
3156 	struct sym	*sym;
3157 
3158 	TAILQ_FOREACH(sym, &symhead, entry) {
3159 		if (strcmp(nam, sym->nam) == 0)
3160 			break;
3161 	}
3162 
3163 	if (sym != NULL) {
3164 		if (sym->persist == 1)
3165 			return (0);
3166 		else {
3167 			free(sym->nam);
3168 			free(sym->val);
3169 			TAILQ_REMOVE(&symhead, sym, entry);
3170 			free(sym);
3171 		}
3172 	}
3173 	if ((sym = calloc(1, sizeof(*sym))) == NULL)
3174 		return (-1);
3175 
3176 	sym->nam = strdup(nam);
3177 	if (sym->nam == NULL) {
3178 		free(sym);
3179 		return (-1);
3180 	}
3181 	sym->val = strdup(val);
3182 	if (sym->val == NULL) {
3183 		free(sym->nam);
3184 		free(sym);
3185 		return (-1);
3186 	}
3187 	sym->used = 0;
3188 	sym->persist = persist;
3189 	TAILQ_INSERT_TAIL(&symhead, sym, entry);
3190 	return (0);
3191 }
3192 
3193 int
3194 cmdline_symset(char *s)
3195 {
3196 	char	*sym, *val;
3197 	int	ret;
3198 
3199 	if ((val = strrchr(s, '=')) == NULL)
3200 		return (-1);
3201 	sym = strndup(s, val - s);
3202 	if (sym == NULL)
3203 		fatalx("%s: strndup", __func__);
3204 	ret = symset(sym, val + 1, 1);
3205 	free(sym);
3206 
3207 	return (ret);
3208 }
3209 
3210 char *
3211 symget(const char *nam)
3212 {
3213 	struct sym	*sym;
3214 
3215 	TAILQ_FOREACH(sym, &symhead, entry) {
3216 		if (strcmp(nam, sym->nam) == 0) {
3217 			sym->used = 1;
3218 			return (sym->val);
3219 		}
3220 	}
3221 	return (NULL);
3222 }
3223 
3224 static void
3225 create_sock_listener(struct listen_opts *lo)
3226 {
3227 	struct listener *l = xcalloc(1, sizeof(*l));
3228 	lo->hostname = conf->sc_hostname;
3229 	l->ss.ss_family = AF_LOCAL;
3230 	l->ss.ss_len = sizeof(struct sockaddr *);
3231 	l->local = 1;
3232 	conf->sc_sock_listener = l;
3233 	config_listener(l, lo);
3234 }
3235 
3236 static void
3237 create_if_listener(struct listen_opts *lo)
3238 {
3239 	uint16_t	flags;
3240 
3241 	if (lo->port != 0 && lo->ssl == F_SSL)
3242 		fatalx("invalid listen option: tls/smtps on same port");
3243 
3244 	if (lo->auth != 0 && !lo->ssl)
3245 		fatalx("invalid listen option: auth requires tls/smtps");
3246 
3247 	if (lo->pkicount && !lo->ssl)
3248 		fatalx("invalid listen option: pki requires tls/smtps");
3249 	if (lo->pkicount == 0 && lo->ssl)
3250 		fatalx("invalid listen option: pki required for tls/smtps");
3251 
3252 	flags = lo->flags;
3253 
3254 	if (lo->port) {
3255 		lo->flags = lo->ssl|lo->auth|flags;
3256 		lo->port = htons(lo->port);
3257 	}
3258 	else {
3259 		if (lo->ssl & F_SMTPS) {
3260 			lo->port = htons(465);
3261 			lo->flags = F_SMTPS|lo->auth|flags;
3262 		}
3263 
3264 		if (!lo->ssl || (lo->ssl & F_STARTTLS)) {
3265 			lo->port = htons(25);
3266 			lo->flags = lo->auth|flags;
3267 			if (lo->ssl & F_STARTTLS)
3268 				lo->flags |= F_STARTTLS;
3269 		}
3270 	}
3271 
3272 	if (interface(lo))
3273 		return;
3274 	if (host_v4(lo))
3275 		return;
3276 	if (host_v6(lo))
3277 		return;
3278 	if (host_dns(lo))
3279 		return;
3280 
3281 	fatalx("invalid virtual ip or interface: %s", lo->ifx);
3282 }
3283 
3284 static void
3285 config_listener(struct listener *h,  struct listen_opts *lo)
3286 {
3287 	int i;
3288 
3289 	h->fd = -1;
3290 	h->port = lo->port;
3291 	h->flags = lo->flags;
3292 
3293 	if (lo->hostname == NULL)
3294 		lo->hostname = conf->sc_hostname;
3295 
3296 	if (lo->options & LO_FILTER) {
3297 		h->flags |= F_FILTERED;
3298 		(void)strlcpy(h->filter_name,
3299 		    lo->filtername,
3300 		    sizeof(h->filter_name));
3301 	}
3302 
3303 	if (lo->authtable != NULL)
3304 		(void)strlcpy(h->authtable, lo->authtable->t_name, sizeof(h->authtable));
3305 
3306 	h->pkicount = lo->pkicount;
3307 	if (h->pkicount) {
3308 		h->pki = calloc(h->pkicount, sizeof(*h->pki));
3309 		if (h->pki == NULL)
3310 			fatal("calloc");
3311 	}
3312 	for (i = 0; i < lo->pkicount; i++) {
3313 		h->pki[i] = dict_get(conf->sc_pki_dict, lo->pki[i]);
3314 		if (h->pki[i] == NULL) {
3315 			log_warnx("pki name not found: %s", lo->pki[i]);
3316 			fatalx(NULL);
3317 		}
3318 	}
3319 
3320 	if (lo->tls_ciphers != NULL &&
3321 	    (h->tls_ciphers = strdup(lo->tls_ciphers)) == NULL) {
3322 		fatal("strdup");
3323 	}
3324 
3325 	if (lo->tls_protocols != NULL &&
3326 	    (h->tls_protocols = strdup(lo->tls_protocols)) == NULL) {
3327 		fatal("strdup");
3328 	}
3329 
3330 	if (lo->ca != NULL) {
3331 		if (!lowercase(h->ca_name, lo->ca, sizeof(h->ca_name))) {
3332 			log_warnx("ca name too long: %s", lo->ca);
3333 			fatalx(NULL);
3334 		}
3335 		if (dict_get(conf->sc_ca_dict, h->ca_name) == NULL) {
3336 			log_warnx("ca name not found: %s", lo->ca);
3337 			fatalx(NULL);
3338 		}
3339 	}
3340 	if (lo->tag != NULL)
3341 		(void)strlcpy(h->tag, lo->tag, sizeof(h->tag));
3342 
3343 	(void)strlcpy(h->hostname, lo->hostname, sizeof(h->hostname));
3344 	if (lo->hostnametable)
3345 		(void)strlcpy(h->hostnametable, lo->hostnametable->t_name, sizeof(h->hostnametable));
3346 	if (lo->sendertable) {
3347 		(void)strlcpy(h->sendertable, lo->sendertable->t_name, sizeof(h->sendertable));
3348 		if (lo->options & LO_MASQUERADE)
3349 			h->flags |= F_MASQUERADE;
3350 	}
3351 
3352 	if (lo->ssl & F_TLS_VERIFY)
3353 		h->flags |= F_TLS_VERIFY;
3354 
3355 	if (lo->ssl & F_STARTTLS_REQUIRE)
3356 		h->flags |= F_STARTTLS_REQUIRE;
3357 
3358 	if (h != conf->sc_sock_listener)
3359 		TAILQ_INSERT_TAIL(conf->sc_listeners, h, entry);
3360 }
3361 
3362 static int
3363 host_v4(struct listen_opts *lo)
3364 {
3365 	struct in_addr		 ina;
3366 	struct sockaddr_in	*sain;
3367 	struct listener		*h;
3368 
3369 	if (lo->family != AF_UNSPEC && lo->family != AF_INET)
3370 		return (0);
3371 
3372 	memset(&ina, 0, sizeof(ina));
3373 	if (inet_pton(AF_INET, lo->ifx, &ina) != 1)
3374 		return (0);
3375 
3376 	h = xcalloc(1, sizeof(*h));
3377 	sain = (struct sockaddr_in *)&h->ss;
3378 	sain->sin_len = sizeof(struct sockaddr_in);
3379 	sain->sin_family = AF_INET;
3380 	sain->sin_addr.s_addr = ina.s_addr;
3381 	sain->sin_port = lo->port;
3382 
3383 	if (sain->sin_addr.s_addr == htonl(INADDR_LOOPBACK))
3384 		h->local = 1;
3385 	config_listener(h,  lo);
3386 
3387 	return (1);
3388 }
3389 
3390 static int
3391 host_v6(struct listen_opts *lo)
3392 {
3393 	struct in6_addr		 ina6;
3394 	struct sockaddr_in6	*sin6;
3395 	struct listener		*h;
3396 
3397 	if (lo->family != AF_UNSPEC && lo->family != AF_INET6)
3398 		return (0);
3399 
3400 	memset(&ina6, 0, sizeof(ina6));
3401 	if (inet_pton(AF_INET6, lo->ifx, &ina6) != 1)
3402 		return (0);
3403 
3404 	h = xcalloc(1, sizeof(*h));
3405 	sin6 = (struct sockaddr_in6 *)&h->ss;
3406 	sin6->sin6_len = sizeof(struct sockaddr_in6);
3407 	sin6->sin6_family = AF_INET6;
3408 	sin6->sin6_port = lo->port;
3409 	memcpy(&sin6->sin6_addr, &ina6, sizeof(ina6));
3410 
3411 	if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr))
3412 		h->local = 1;
3413 	config_listener(h,  lo);
3414 
3415 	return (1);
3416 }
3417 
3418 static int
3419 host_dns(struct listen_opts *lo)
3420 {
3421 	struct addrinfo		 hints, *res0, *res;
3422 	int			 error, cnt = 0;
3423 	struct sockaddr_in	*sain;
3424 	struct sockaddr_in6	*sin6;
3425 	struct listener		*h;
3426 
3427 	memset(&hints, 0, sizeof(hints));
3428 	hints.ai_family = lo->family;
3429 	hints.ai_socktype = SOCK_STREAM;
3430 	hints.ai_flags = AI_ADDRCONFIG;
3431 	error = getaddrinfo(lo->ifx, NULL, &hints, &res0);
3432 	if (error == EAI_AGAIN || error == EAI_NODATA || error == EAI_NONAME)
3433 		return (0);
3434 	if (error) {
3435 		log_warnx("warn: host_dns: could not parse \"%s\": %s", lo->ifx,
3436 		    gai_strerror(error));
3437 		return (-1);
3438 	}
3439 
3440 	for (res = res0; res; res = res->ai_next) {
3441 		if (res->ai_family != AF_INET &&
3442 		    res->ai_family != AF_INET6)
3443 			continue;
3444 		h = xcalloc(1, sizeof(*h));
3445 
3446 		h->ss.ss_family = res->ai_family;
3447 		if (res->ai_family == AF_INET) {
3448 			sain = (struct sockaddr_in *)&h->ss;
3449 			sain->sin_len = sizeof(struct sockaddr_in);
3450 			sain->sin_addr.s_addr = ((struct sockaddr_in *)
3451 			    res->ai_addr)->sin_addr.s_addr;
3452 			sain->sin_port = lo->port;
3453 			if (sain->sin_addr.s_addr == htonl(INADDR_LOOPBACK))
3454 				h->local = 1;
3455 		} else {
3456 			sin6 = (struct sockaddr_in6 *)&h->ss;
3457 			sin6->sin6_len = sizeof(struct sockaddr_in6);
3458 			memcpy(&sin6->sin6_addr, &((struct sockaddr_in6 *)
3459 			    res->ai_addr)->sin6_addr, sizeof(struct in6_addr));
3460 			sin6->sin6_port = lo->port;
3461 			if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr))
3462 				h->local = 1;
3463 		}
3464 
3465 		config_listener(h, lo);
3466 
3467 		cnt++;
3468 	}
3469 
3470 	freeaddrinfo(res0);
3471 	return (cnt);
3472 }
3473 
3474 static int
3475 interface(struct listen_opts *lo)
3476 {
3477 	struct ifaddrs *ifap, *p;
3478 	struct sockaddr_in	*sain;
3479 	struct sockaddr_in6	*sin6;
3480 	struct listener		*h;
3481 	int			ret = 0;
3482 
3483 	if (getifaddrs(&ifap) == -1)
3484 		fatal("getifaddrs");
3485 
3486 	for (p = ifap; p != NULL; p = p->ifa_next) {
3487 		if (p->ifa_addr == NULL)
3488 			continue;
3489 		if (strcmp(p->ifa_name, lo->ifx) != 0 &&
3490 		    !is_if_in_group(p->ifa_name, lo->ifx))
3491 			continue;
3492 		if (lo->family != AF_UNSPEC && lo->family != p->ifa_addr->sa_family)
3493 			continue;
3494 
3495 		h = xcalloc(1, sizeof(*h));
3496 
3497 		switch (p->ifa_addr->sa_family) {
3498 		case AF_INET:
3499 			sain = (struct sockaddr_in *)&h->ss;
3500 			*sain = *(struct sockaddr_in *)p->ifa_addr;
3501 			sain->sin_len = sizeof(struct sockaddr_in);
3502 			sain->sin_port = lo->port;
3503 			if (sain->sin_addr.s_addr == htonl(INADDR_LOOPBACK))
3504 				h->local = 1;
3505 			break;
3506 
3507 		case AF_INET6:
3508 			sin6 = (struct sockaddr_in6 *)&h->ss;
3509 			*sin6 = *(struct sockaddr_in6 *)p->ifa_addr;
3510 			sin6->sin6_len = sizeof(struct sockaddr_in6);
3511 			sin6->sin6_port = lo->port;
3512 #ifdef __KAME__
3513 			if ((IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) ||
3514 			    IN6_IS_ADDR_MC_LINKLOCAL(&sin6->sin6_addr) ||
3515 			    IN6_IS_ADDR_MC_INTFACELOCAL(&sin6->sin6_addr)) &&
3516 			    sin6->sin6_scope_id == 0) {
3517 				sin6->sin6_scope_id = ntohs(
3518 				    *(u_int16_t *)&sin6->sin6_addr.s6_addr[2]);
3519 				sin6->sin6_addr.s6_addr[2] = 0;
3520 				sin6->sin6_addr.s6_addr[3] = 0;
3521 			}
3522 #endif
3523 			if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr))
3524 				h->local = 1;
3525 			break;
3526 
3527 		default:
3528 			free(h);
3529 			continue;
3530 		}
3531 
3532 		config_listener(h, lo);
3533 		ret = 1;
3534 	}
3535 
3536 	freeifaddrs(ifap);
3537 
3538 	return ret;
3539 }
3540 
3541 int
3542 delaytonum(char *str)
3543 {
3544 	unsigned int     factor;
3545 	size_t           len;
3546 	const char      *errstr = NULL;
3547 	int              delay;
3548 
3549 	/* we need at least 1 digit and 1 unit */
3550 	len = strlen(str);
3551 	if (len < 2)
3552 		goto bad;
3553 
3554 	switch(str[len - 1]) {
3555 
3556 	case 's':
3557 		factor = 1;
3558 		break;
3559 
3560 	case 'm':
3561 		factor = 60;
3562 		break;
3563 
3564 	case 'h':
3565 		factor = 60 * 60;
3566 		break;
3567 
3568 	case 'd':
3569 		factor = 24 * 60 * 60;
3570 		break;
3571 
3572 	default:
3573 		goto bad;
3574 	}
3575 
3576 	str[len - 1] = '\0';
3577 	delay = strtonum(str, 1, INT_MAX / factor, &errstr);
3578 	if (errstr)
3579 		goto bad;
3580 
3581 	return (delay * factor);
3582 
3583 bad:
3584 	return (-1);
3585 }
3586 
3587 int
3588 is_if_in_group(const char *ifname, const char *groupname)
3589 {
3590         unsigned int		 len;
3591         struct ifgroupreq        ifgr;
3592         struct ifg_req          *ifg;
3593 	int			 s;
3594 	int			 ret = 0;
3595 
3596 	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
3597 		fatal("socket");
3598 
3599         memset(&ifgr, 0, sizeof(ifgr));
3600         if (strlcpy(ifgr.ifgr_name, ifname, IFNAMSIZ) >= IFNAMSIZ)
3601 		fatalx("interface name too large");
3602 
3603         if (ioctl(s, SIOCGIFGROUP, (caddr_t)&ifgr) == -1) {
3604                 if (errno == EINVAL || errno == ENOTTY)
3605 			goto end;
3606 		fatal("SIOCGIFGROUP");
3607         }
3608 
3609         len = ifgr.ifgr_len;
3610         ifgr.ifgr_groups = xcalloc(len/sizeof(struct ifg_req),
3611 		sizeof(struct ifg_req));
3612         if (ioctl(s, SIOCGIFGROUP, (caddr_t)&ifgr) == -1)
3613                 fatal("SIOCGIFGROUP");
3614 
3615         ifg = ifgr.ifgr_groups;
3616         for (; ifg && len >= sizeof(struct ifg_req); ifg++) {
3617                 len -= sizeof(struct ifg_req);
3618 		if (strcmp(ifg->ifgrq_group, groupname) == 0) {
3619 			ret = 1;
3620 			break;
3621 		}
3622         }
3623         free(ifgr.ifgr_groups);
3624 
3625 end:
3626 	close(s);
3627 	return ret;
3628 }
3629 
3630 static int
3631 config_lo_mask_source(struct listen_opts *lo) {
3632 	if (lo->options & LO_MASKSOURCE) {
3633 		yyerror("mask-source already specified");
3634 		return -1;
3635 	}
3636 	lo->options |= LO_MASKSOURCE;
3637 	lo->flags |= F_MASK_SOURCE;
3638 
3639 	return 0;
3640 }
3641 
3642