xref: /openbsd/usr.sbin/smtpd/parse.y (revision 954e2a27)
1 /*	$OpenBSD: parse.y,v 1.297 2024/02/02 20:54:27 millert 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 <stdlib.h>
38 #include <string.h>
39 #include <syslog.h>
40 #include <unistd.h>
41 #include <util.h>
42 
43 #include "smtpd.h"
44 #include "ssl.h"
45 #include "log.h"
46 
47 TAILQ_HEAD(files, file)		 files = TAILQ_HEAD_INITIALIZER(files);
48 static struct file {
49 	TAILQ_ENTRY(file)	 entry;
50 	FILE			*stream;
51 	char			*name;
52 	size_t			 ungetpos;
53 	size_t			 ungetsize;
54 	u_char			*ungetbuf;
55 	int			 eof_reached;
56 	int			 lineno;
57 	int			 errors;
58 } *file, *topfile;
59 struct file	*pushfile(const char *, int);
60 int		 popfile(void);
61 int		 check_file_secrecy(int, const char *);
62 int		 yyparse(void);
63 int		 yylex(void);
64 int		 kw_cmp(const void *, const void *);
65 int		 lookup(char *);
66 int		 igetc(void);
67 int		 lgetc(int);
68 void		 lungetc(int);
69 int		 findeol(void);
70 int		 yyerror(const char *, ...)
71     __attribute__((__format__ (printf, 1, 2)))
72     __attribute__((__nonnull__ (1)));
73 
74 TAILQ_HEAD(symhead, sym)	 symhead = TAILQ_HEAD_INITIALIZER(symhead);
75 struct sym {
76 	TAILQ_ENTRY(sym)	 entry;
77 	int			 used;
78 	int			 persist;
79 	char			*nam;
80 	char			*val;
81 };
82 int		 symset(const char *, const char *, int);
83 char		*symget(const char *);
84 
85 struct smtpd		*conf = NULL;
86 static int		 errors = 0;
87 
88 struct table		*table = NULL;
89 struct mta_limits	*limits;
90 static struct pki	*pki;
91 static struct ca	*sca;
92 
93 struct dispatcher	*dsp;
94 struct rule		*rule;
95 struct filter_proc	*processor;
96 struct filter_config	*filter_config;
97 static uint32_t		 last_dynchain_id = 1;
98 
99 enum listen_options {
100 	LO_FAMILY	= 0x000001,
101 	LO_PORT		= 0x000002,
102 	LO_SSL		= 0x000004,
103 	LO_FILTER      	= 0x000008,
104 	LO_PKI      	= 0x000010,
105 	LO_AUTH      	= 0x000020,
106 	LO_TAG      	= 0x000040,
107 	LO_HOSTNAME   	= 0x000080,
108 	LO_HOSTNAMES   	= 0x000100,
109 	LO_MASKSOURCE  	= 0x000200,
110 	LO_NODSN	= 0x000400,
111 	LO_SENDERS	= 0x000800,
112 	LO_RECEIVEDAUTH = 0x001000,
113 	LO_MASQUERADE	= 0x002000,
114 	LO_CA		= 0x004000,
115 	LO_PROXY       	= 0x008000,
116 };
117 
118 #define PKI_MAX	32
119 static struct listen_opts {
120 	char	       *ifx;
121 	int		family;
122 	in_port_t	port;
123 	uint16_t	ssl;
124 	char	       *filtername;
125 	char	       *pki[PKI_MAX];
126 	int		pkicount;
127 	char	       *tls_ciphers;
128 	char	       *tls_protocols;
129 	char	       *ca;
130 	uint16_t       	auth;
131 	struct table   *authtable;
132 	char	       *tag;
133 	char	       *hostname;
134 	struct table   *hostnametable;
135 	struct table   *sendertable;
136 	uint16_t	flags;
137 
138 	uint32_t       	options;
139 } listen_opts;
140 
141 static void	create_sock_listener(struct listen_opts *);
142 static void	create_if_listener(struct listen_opts *);
143 static void	config_listener(struct listener *, struct listen_opts *);
144 static int	host_v4(struct listen_opts *);
145 static int	host_v6(struct listen_opts *);
146 static int	host_dns(struct listen_opts *);
147 static int	interface(struct listen_opts *);
148 
149 int		 delaytonum(char *);
150 int		 is_if_in_group(const char *, const char *);
151 
152 static int config_lo_mask_source(struct listen_opts *);
153 
154 typedef struct {
155 	union {
156 		int64_t		 number;
157 		struct table	*table;
158 		char		*string;
159 		struct host	*host;
160 		struct mailaddr	*maddr;
161 	} v;
162 	int lineno;
163 } YYSTYPE;
164 
165 %}
166 
167 %token	ACTION ADMD ALIAS ANY ARROW AUTH AUTH_OPTIONAL
168 %token	BACKUP BOUNCE BYPASS
169 %token	CA CERT CHAIN CHROOT CIPHERS COMMIT COMPRESSION CONNECT
170 %token	DATA DATA_LINE DHE DISCONNECT DOMAIN
171 %token	EHLO ENABLE ENCRYPTION ERROR EXPAND_ONLY
172 %token	FCRDNS FILTER FOR FORWARD_ONLY FROM
173 %token	GROUP
174 %token	HELO HELO_SRC HOST HOSTNAME HOSTNAMES
175 %token	INCLUDE INET4 INET6
176 %token	JUNK
177 %token	KEY
178 %token	LIMIT LISTEN LMTP LOCAL
179 %token	MAIL_FROM MAILDIR MASK_SRC MASQUERADE MATCH MAX_MESSAGE_SIZE MAX_DEFERRED MBOX MDA MTA MX
180 %token	NO_DSN NO_VERIFY NOOP
181 %token	ON
182 %token	PHASE PKI PORT PROC PROC_EXEC PROTOCOLS PROXY_V2
183 %token	QUEUE QUIT
184 %token	RCPT_TO RDNS RECIPIENT RECEIVEDAUTH REGEX RELAY REJECT REPORT REWRITE RSET
185 %token	SCHEDULER SENDER SENDERS SMTP SMTP_IN SMTP_OUT SMTPS SOCKET SRC SRS SUB_ADDR_DELIM
186 %token	TABLE TAG TAGGED TLS TLS_REQUIRE TTL
187 %token	USER USERBASE
188 %token	VERIFY VIRTUAL
189 %token	WARN_INTERVAL WRAPPER
190 
191 %token	<v.string>	STRING
192 %token  <v.number>	NUMBER
193 %type	<v.table>	table
194 %type	<v.number>	size negation
195 %type	<v.table>	tables tablenew tableref
196 %%
197 
198 grammar		: /* empty */
199 		| grammar '\n'
200 		| grammar include '\n'
201 		| grammar varset '\n'
202 		| grammar bounce '\n'
203 		| grammar admd '\n'
204 		| grammar ca '\n'
205 		| grammar mda '\n'
206 		| grammar mta '\n'
207 		| grammar pki '\n'
208 		| grammar proc '\n'
209 		| grammar queue '\n'
210 		| grammar scheduler '\n'
211 		| grammar smtp '\n'
212 		| grammar srs '\n'
213 		| grammar listen '\n'
214 		| grammar table '\n'
215 		| grammar dispatcher '\n'
216 		| grammar match '\n'
217 		| grammar filter '\n'
218 		| grammar error '\n'		{ file->errors++; }
219 		;
220 
221 include		: INCLUDE STRING		{
222 			struct file	*nfile;
223 
224 			if ((nfile = pushfile($2, 0)) == NULL) {
225 				yyerror("failed to include file %s", $2);
226 				free($2);
227 				YYERROR;
228 			}
229 			free($2);
230 
231 			file = nfile;
232 			lungetc('\n');
233 		}
234 		;
235 
236 varset		: STRING '=' STRING		{
237 			char *s = $1;
238 			while (*s++) {
239 				if (isspace((unsigned char)*s)) {
240 					yyerror("macro name cannot contain "
241 					    "whitespace");
242 					free($1);
243 					free($3);
244 					YYERROR;
245 				}
246 			}
247 			if (symset($1, $3, 0) == -1)
248 				fatal("cannot store variable");
249 			free($1);
250 			free($3);
251 		}
252 		;
253 
254 comma		: ',' optnl
255 		| nl
256 		| /* empty */
257 		;
258 
259 optnl		: '\n' optnl
260 		|
261 		;
262 
263 nl		: '\n' optnl
264 		;
265 
266 negation	: '!'		{ $$ = 1; }
267 		| /* empty */	{ $$ = 0; }
268 		;
269 
270 assign		: '=' | ARROW;
271 
272 
273 keyval		: STRING assign STRING		{
274 			table_add(table, $1, $3);
275 			free($1);
276 			free($3);
277 		}
278 		;
279 
280 keyval_list	: keyval optnl
281 		| keyval comma keyval_list
282 		;
283 
284 stringel	: STRING			{
285 			table_add(table, $1, NULL);
286 			free($1);
287 		}
288 		;
289 
290 string_list	: stringel optnl
291 		| stringel comma string_list
292 		;
293 
294 tableval_list	: string_list			{ }
295 		| keyval_list			{ }
296 		;
297 
298 bounce:
299 BOUNCE WARN_INTERVAL {
300 	memset(conf->sc_bounce_warn, 0, sizeof conf->sc_bounce_warn);
301 } bouncedelays
302 ;
303 
304 
305 admd:
306 ADMD STRING {
307 	size_t i;
308 
309 	for (i = 0; $2[i] != '\0'; i++) {
310 		if (!isprint($2[i])) {
311 			yyerror("not a valid admd");
312 			free($2);
313 			YYERROR;
314 		}
315 	}
316 	conf->sc_admd = $2;
317 };
318 
319 
320 ca:
321 CA STRING {
322 	char buf[HOST_NAME_MAX+1];
323 
324 	/* if not catchall, check that it is a valid domain */
325 	if (strcmp($2, "*") != 0) {
326 		if (!res_hnok($2)) {
327 			yyerror("not a valid domain name: %s", $2);
328 			free($2);
329 			YYERROR;
330 		}
331 	}
332 	xlowercase(buf, $2, sizeof(buf));
333 	free($2);
334 	sca = dict_get(conf->sc_ca_dict, buf);
335 	if (sca == NULL) {
336 		sca = xcalloc(1, sizeof *sca);
337 		(void)strlcpy(sca->ca_name, buf, sizeof(sca->ca_name));
338 		dict_set(conf->sc_ca_dict, sca->ca_name, sca);
339 	}
340 } ca_params
341 ;
342 
343 
344 ca_params_opt:
345 CERT STRING {
346 	sca->ca_cert_file = $2;
347 }
348 ;
349 
350 ca_params:
351 ca_params_opt
352 ;
353 
354 
355 mda:
356 MDA LIMIT limits_mda
357 | MDA WRAPPER STRING STRING {
358 	if (dict_get(conf->sc_mda_wrappers, $3)) {
359 		yyerror("mda wrapper already declared with that name: %s", $3);
360 		YYERROR;
361 	}
362 	dict_set(conf->sc_mda_wrappers, $3, $4);
363 }
364 ;
365 
366 
367 mta:
368 MTA MAX_DEFERRED NUMBER  {
369 	conf->sc_mta_max_deferred = $3;
370 }
371 | MTA LIMIT FOR DOMAIN STRING {
372 	struct mta_limits	*d;
373 
374 	limits = dict_get(conf->sc_limits_dict, $5);
375 	if (limits == NULL) {
376 		limits = xcalloc(1, sizeof(*limits));
377 		dict_xset(conf->sc_limits_dict, $5, limits);
378 		d = dict_xget(conf->sc_limits_dict, "default");
379 		memmove(limits, d, sizeof(*limits));
380 	}
381 	free($5);
382 } limits_mta
383 | MTA LIMIT {
384 	limits = dict_get(conf->sc_limits_dict, "default");
385 } limits_mta
386 ;
387 
388 
389 pki:
390 PKI STRING {
391 	char buf[HOST_NAME_MAX+1];
392 
393 	/* if not catchall, check that it is a valid domain */
394 	if (strcmp($2, "*") != 0) {
395 		if (!res_hnok($2)) {
396 			yyerror("not a valid domain name: %s", $2);
397 			free($2);
398 			YYERROR;
399 		}
400 	}
401 	xlowercase(buf, $2, sizeof(buf));
402 	free($2);
403 	pki = dict_get(conf->sc_pki_dict, buf);
404 	if (pki == NULL) {
405 		pki = xcalloc(1, sizeof *pki);
406 		(void)strlcpy(pki->pki_name, buf, sizeof(pki->pki_name));
407 		dict_set(conf->sc_pki_dict, pki->pki_name, pki);
408 	}
409 } pki_params
410 ;
411 
412 pki_params_opt:
413 CERT STRING {
414 	pki->pki_cert_file = $2;
415 }
416 | KEY STRING {
417 	pki->pki_key_file = $2;
418 }
419 | DHE STRING {
420 	if (strcasecmp($2, "none") == 0)
421 		pki->pki_dhe = 0;
422 	else if (strcasecmp($2, "auto") == 0)
423 		pki->pki_dhe = 1;
424 	else if (strcasecmp($2, "legacy") == 0)
425 		pki->pki_dhe = 2;
426 	else {
427 		yyerror("invalid DHE keyword: %s", $2);
428 		free($2);
429 		YYERROR;
430 	}
431 	free($2);
432 }
433 ;
434 
435 
436 pki_params:
437 pki_params_opt pki_params
438 | /* empty */
439 ;
440 
441 
442 proc:
443 PROC STRING STRING {
444 	if (dict_get(conf->sc_filter_processes_dict, $2)) {
445 		yyerror("processor already exists with that name: %s", $2);
446 		free($2);
447 		free($3);
448 		YYERROR;
449 	}
450 	processor = xcalloc(1, sizeof *processor);
451 	processor->command = $3;
452 } proc_params {
453 	dict_set(conf->sc_filter_processes_dict, $2, processor);
454 	processor = NULL;
455 }
456 ;
457 
458 
459 proc_params_opt:
460 USER STRING {
461 	if (processor->user) {
462 		yyerror("user already specified for this processor");
463 		free($2);
464 		YYERROR;
465 	}
466 	processor->user = $2;
467 }
468 | GROUP STRING {
469 	if (processor->group) {
470 		yyerror("group already specified for this processor");
471 		free($2);
472 		YYERROR;
473 	}
474 	processor->group = $2;
475 }
476 | CHROOT STRING {
477 	if (processor->chroot) {
478 		yyerror("chroot already specified for this processor");
479 		free($2);
480 		YYERROR;
481 	}
482 	processor->chroot = $2;
483 }
484 ;
485 
486 proc_params:
487 proc_params_opt proc_params
488 | /* empty */
489 ;
490 
491 
492 queue:
493 QUEUE COMPRESSION {
494 	conf->sc_queue_flags |= QUEUE_COMPRESSION;
495 }
496 | QUEUE ENCRYPTION {
497 	conf->sc_queue_flags |= QUEUE_ENCRYPTION;
498 }
499 | QUEUE ENCRYPTION STRING {
500 	if (strcasecmp($3, "stdin") == 0 || strcasecmp($3, "-") == 0) {
501 		conf->sc_queue_key = "stdin";
502 		free($3);
503 	}
504 	else
505 		conf->sc_queue_key = $3;
506 	conf->sc_queue_flags |= QUEUE_ENCRYPTION;
507 }
508 | QUEUE TTL STRING {
509 	conf->sc_ttl = delaytonum($3);
510 	if (conf->sc_ttl == -1) {
511 		yyerror("invalid ttl delay: %s", $3);
512 		free($3);
513 		YYERROR;
514 	}
515 	free($3);
516 }
517 ;
518 
519 
520 scheduler:
521 SCHEDULER LIMIT limits_scheduler
522 ;
523 
524 
525 smtp:
526 SMTP LIMIT limits_smtp
527 | SMTP CIPHERS STRING {
528 	conf->sc_tls_ciphers = $3;
529 }
530 | SMTP MAX_MESSAGE_SIZE size {
531 	conf->sc_maxsize = $3;
532 }
533 | SMTP SUB_ADDR_DELIM STRING {
534 	if (strlen($3) != 1) {
535 		yyerror("subaddressing-delimiter must be one character");
536 		free($3);
537 		YYERROR;
538 	}
539 	if (isspace((unsigned char)*$3) || !isprint((unsigned char)*$3) || *$3 == '@') {
540 		yyerror("sub-addr-delim uses invalid character");
541 		free($3);
542 		YYERROR;
543 	}
544 	conf->sc_subaddressing_delim = $3;
545 }
546 ;
547 
548 srs:
549 SRS KEY STRING {
550 	conf->sc_srs_key = $3;
551 }
552 | SRS KEY BACKUP STRING {
553 	conf->sc_srs_key_backup = $4;
554 }
555 | SRS TTL STRING {
556 	conf->sc_srs_ttl = delaytonum($3);
557 	if (conf->sc_srs_ttl == -1) {
558 		yyerror("ttl delay \"%s\" is invalid", $3);
559 		free($3);
560 		YYERROR;
561 	}
562 
563 	conf->sc_srs_ttl /= 86400;
564 	if (conf->sc_srs_ttl == 0) {
565 		yyerror("ttl delay \"%s\" is too short", $3);
566 		free($3);
567 		YYERROR;
568 	}
569 	free($3);
570 }
571 ;
572 
573 
574 dispatcher_local_option:
575 USER STRING {
576 	if (dsp->u.local.is_mbox) {
577 		yyerror("user may not be specified for this dispatcher");
578 		YYERROR;
579 	}
580 
581 	if (dsp->u.local.forward_only) {
582 		yyerror("user may not be specified for forward-only");
583 		YYERROR;
584 	}
585 
586 	if (dsp->u.local.expand_only) {
587 		yyerror("user may not be specified for expand-only");
588 		YYERROR;
589 	}
590 
591 	if (dsp->u.local.user) {
592 		yyerror("user already specified for this dispatcher");
593 		YYERROR;
594 	}
595 
596 	dsp->u.local.user = $2;
597 }
598 | ALIAS tables {
599 	struct table   *t = $2;
600 
601 	if (dsp->u.local.table_alias) {
602 		yyerror("alias mapping already specified for this dispatcher");
603 		YYERROR;
604 	}
605 
606 	if (dsp->u.local.table_virtual) {
607 		yyerror("virtual mapping already specified for this dispatcher");
608 		YYERROR;
609 	}
610 
611 	if (!table_check_use(t, T_DYNAMIC|T_HASH, K_ALIAS)) {
612 		yyerror("table \"%s\" may not be used for alias lookups",
613 		    t->t_name);
614 		YYERROR;
615 	}
616 
617 	dsp->u.local.table_alias = strdup(t->t_name);
618 }
619 | VIRTUAL tables {
620 	struct table   *t = $2;
621 
622 	if (dsp->u.local.table_virtual) {
623 		yyerror("virtual mapping already specified for this dispatcher");
624 		YYERROR;
625 	}
626 
627 	if (dsp->u.local.table_alias) {
628 		yyerror("alias mapping already specified for this dispatcher");
629 		YYERROR;
630 	}
631 
632 	if (!table_check_use(t, T_DYNAMIC|T_HASH, K_ALIAS)) {
633 		yyerror("table \"%s\" may not be used for virtual lookups",
634 		    t->t_name);
635 		YYERROR;
636 	}
637 
638 	dsp->u.local.table_virtual = strdup(t->t_name);
639 }
640 | USERBASE tables {
641 	struct table   *t = $2;
642 
643 	if (dsp->u.local.table_userbase) {
644 		yyerror("userbase mapping already specified for this dispatcher");
645 		YYERROR;
646 	}
647 
648 	if (!table_check_use(t, T_DYNAMIC|T_HASH, K_USERINFO)) {
649 		yyerror("table \"%s\" may not be used for userbase lookups",
650 		    t->t_name);
651 		YYERROR;
652 	}
653 
654 	dsp->u.local.table_userbase = strdup(t->t_name);
655 }
656 | WRAPPER STRING {
657 	if (! dict_get(conf->sc_mda_wrappers, $2)) {
658 		yyerror("no mda wrapper with that name: %s", $2);
659 		YYERROR;
660 	}
661 	dsp->u.local.mda_wrapper = $2;
662 }
663 ;
664 
665 dispatcher_local_options:
666 dispatcher_local_option dispatcher_local_options
667 | /* empty */
668 ;
669 
670 dispatcher_local:
671 MBOX {
672 	dsp->u.local.is_mbox = 1;
673 	asprintf(&dsp->u.local.command, "/usr/libexec/mail.local -f %%{mbox.from} -- %%{user.username}");
674 } dispatcher_local_options
675 | MAILDIR {
676 	asprintf(&dsp->u.local.command, "/usr/libexec/mail.maildir");
677 } dispatcher_local_options
678 | MAILDIR JUNK {
679 	asprintf(&dsp->u.local.command, "/usr/libexec/mail.maildir -j");
680 } dispatcher_local_options
681 | MAILDIR STRING {
682 	if (strncmp($2, "~/", 2) == 0)
683 		asprintf(&dsp->u.local.command,
684 		    "/usr/libexec/mail.maildir \"%%{user.directory}/%s\"", $2+2);
685 	else
686 		asprintf(&dsp->u.local.command,
687 		    "/usr/libexec/mail.maildir \"%s\"", $2);
688 } dispatcher_local_options
689 | MAILDIR STRING JUNK {
690 	if (strncmp($2, "~/", 2) == 0)
691 		asprintf(&dsp->u.local.command,
692 		    "/usr/libexec/mail.maildir -j \"%%{user.directory}/%s\"", $2+2);
693 	else
694 		asprintf(&dsp->u.local.command,
695 		    "/usr/libexec/mail.maildir -j \"%s\"", $2);
696 } dispatcher_local_options
697 | LMTP STRING {
698 	asprintf(&dsp->u.local.command,
699 	    "/usr/libexec/mail.lmtp -d %s -u", $2);
700 } dispatcher_local_options
701 | LMTP STRING RCPT_TO {
702 	asprintf(&dsp->u.local.command,
703 	    "/usr/libexec/mail.lmtp -d %s -r", $2);
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 	dsp->u.remote.tls_verify = 1;
872 }
873 | TLS NO_VERIFY {
874 	if (dsp->u.remote.tls_required == 1) {
875 		yyerror("tls already specified for this dispatcher");
876 		YYERROR;
877 	}
878 
879 	dsp->u.remote.tls_required = 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 } '{' optnl 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 optnl
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 } '{' optnl 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 		} '{' optnl 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 		| NO_DSN	{
2151 			if (listen_opts.options & LO_NODSN) {
2152 				yyerror("no-dsn already specified");
2153 				YYERROR;
2154 			}
2155 			listen_opts.options |= LO_NODSN;
2156 			listen_opts.flags &= ~F_EXT_DSN;
2157 		}
2158 		| TAG STRING			{
2159 			if (listen_opts.options & LO_TAG) {
2160 				yyerror("tag already specified");
2161 				YYERROR;
2162 			}
2163 			listen_opts.options |= LO_TAG;
2164 
2165 			if (strlen($2) >= SMTPD_TAG_SIZE) {
2166 				yyerror("tag name too long");
2167 				free($2);
2168 				YYERROR;
2169 			}
2170 			listen_opts.tag = $2;
2171 		}
2172 		;
2173 
2174 opt_if_listen : INET4 {
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_INET;
2181 		}
2182 		| INET6			{
2183 			if (listen_opts.options & LO_FAMILY) {
2184 				yyerror("address family already specified");
2185 				YYERROR;
2186 			}
2187 			listen_opts.options |= LO_FAMILY;
2188 			listen_opts.family = AF_INET6;
2189 		}
2190 		| PORT STRING			{
2191 			struct servent	*servent;
2192 
2193 			if (listen_opts.options & LO_PORT) {
2194 				yyerror("port already specified");
2195 				YYERROR;
2196 			}
2197 			listen_opts.options |= LO_PORT;
2198 
2199 			servent = getservbyname($2, "tcp");
2200 			if (servent == NULL) {
2201 				yyerror("invalid port: %s", $2);
2202 				free($2);
2203 				YYERROR;
2204 			}
2205 			free($2);
2206 			listen_opts.port = ntohs(servent->s_port);
2207 		}
2208 		| PORT SMTP			{
2209 			struct servent *servent;
2210 
2211 			if (listen_opts.options & LO_PORT) {
2212 				yyerror("port already specified");
2213 				YYERROR;
2214 			}
2215 			listen_opts.options |= LO_PORT;
2216 
2217 			servent = getservbyname("smtp", "tcp");
2218 			if (servent == NULL) {
2219 				yyerror("invalid port: smtp");
2220 				YYERROR;
2221 			}
2222 			listen_opts.port = ntohs(servent->s_port);
2223 		}
2224 		| PORT SMTPS			{
2225 			struct servent *servent;
2226 
2227 			if (listen_opts.options & LO_PORT) {
2228 				yyerror("port already specified");
2229 				YYERROR;
2230 			}
2231 			listen_opts.options |= LO_PORT;
2232 
2233 			servent = getservbyname("smtps", "tcp");
2234 			if (servent == NULL) {
2235 				yyerror("invalid port: smtps");
2236 				YYERROR;
2237 			}
2238 			listen_opts.port = ntohs(servent->s_port);
2239 		}
2240 		| PORT NUMBER			{
2241 			if (listen_opts.options & LO_PORT) {
2242 				yyerror("port already specified");
2243 				YYERROR;
2244 			}
2245 			listen_opts.options |= LO_PORT;
2246 
2247 			if ($2 <= 0 || $2 > (int)USHRT_MAX) {
2248 				yyerror("invalid port: %" PRId64, $2);
2249 				YYERROR;
2250 			}
2251 			listen_opts.port = $2;
2252 		}
2253 		| FILTER STRING			{
2254 			struct filter_config *fc;
2255 
2256 			if (listen_opts.options & LO_FILTER) {
2257 				yyerror("filter already specified");
2258 				YYERROR;
2259 			}
2260 			if ((fc = dict_get(conf->sc_filters_dict, $2)) == NULL) {
2261 				yyerror("no filter exist with that name: %s", $2);
2262 				free($2);
2263 				YYERROR;
2264 			}
2265 			fc->filter_subsystem |= FILTER_SUBSYSTEM_SMTP_IN;
2266 			listen_opts.options |= LO_FILTER;
2267 			listen_opts.filtername = $2;
2268 		}
2269 		| FILTER {
2270 			char	buffer[128];
2271 
2272 			if (listen_opts.options & LO_FILTER) {
2273 				yyerror("filter already specified");
2274 				YYERROR;
2275 			}
2276 
2277 			do {
2278 				(void)snprintf(buffer, sizeof buffer, "<dynchain:%08x>", last_dynchain_id++);
2279 			} while (dict_check(conf->sc_filters_dict, buffer));
2280 
2281 			listen_opts.options |= LO_FILTER;
2282 			listen_opts.filtername = xstrdup(buffer);
2283 			filter_config = xcalloc(1, sizeof *filter_config);
2284 			filter_config->filter_type = FILTER_TYPE_CHAIN;
2285 			filter_config->filter_subsystem |= FILTER_SUBSYSTEM_SMTP_IN;
2286 			dict_init(&filter_config->chain_procs);
2287 		} '{' optnl filter_list '}' {
2288 			dict_set(conf->sc_filters_dict, listen_opts.filtername, filter_config);
2289 			filter_config = NULL;
2290 		}
2291 		| SMTPS				{
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;
2298 		}
2299 		| SMTPS VERIFY 			{
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_SMTPS|F_TLS_VERIFY;
2306 		}
2307 		| TLS				{
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;
2314 		}
2315 		| TLS_REQUIRE			{
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;
2322 		}
2323 		| TLS_REQUIRE VERIFY   		{
2324 			if (listen_opts.options & LO_SSL) {
2325 				yyerror("TLS mode already specified");
2326 				YYERROR;
2327 			}
2328 			listen_opts.options |= LO_SSL;
2329 			listen_opts.ssl = F_STARTTLS|F_STARTTLS_REQUIRE|F_TLS_VERIFY;
2330 		}
2331 		| CIPHERS STRING {
2332 			if (listen_opts.tls_ciphers) {
2333 				yyerror("ciphers already specified");
2334 				YYERROR;
2335 			}
2336 			listen_opts.tls_ciphers = $2;
2337 		}
2338 		| PROTOCOLS STRING {
2339 			if (listen_opts.tls_protocols) {
2340 				yyerror("protocols already specified");
2341 				YYERROR;
2342 			}
2343 			listen_opts.tls_protocols = $2;
2344 		}
2345 		| PKI STRING			{
2346 			if (listen_opts.pkicount == PKI_MAX) {
2347 				yyerror("too many pki specified");
2348 				YYERROR;
2349 			}
2350 			listen_opts.pki[listen_opts.pkicount++] = $2;
2351 		}
2352 		| CA STRING			{
2353 			if (listen_opts.options & LO_CA) {
2354 				yyerror("ca already specified");
2355 				YYERROR;
2356 			}
2357 			listen_opts.options |= LO_CA;
2358 			listen_opts.ca = $2;
2359 		}
2360 		| AUTH				{
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|F_AUTH_REQUIRE;
2367 		}
2368 		| AUTH_OPTIONAL			{
2369 			if (listen_opts.options & LO_AUTH) {
2370 				yyerror("auth already specified");
2371 				YYERROR;
2372 			}
2373 			listen_opts.options |= LO_AUTH;
2374 			listen_opts.auth = F_AUTH;
2375 		}
2376 		| AUTH tables  			{
2377 			if (listen_opts.options & LO_AUTH) {
2378 				yyerror("auth already specified");
2379 				YYERROR;
2380 			}
2381 			listen_opts.options |= LO_AUTH;
2382 			listen_opts.authtable = $2;
2383 			listen_opts.auth = F_AUTH|F_AUTH_REQUIRE;
2384 		}
2385 		| AUTH_OPTIONAL tables 		{
2386 			if (listen_opts.options & LO_AUTH) {
2387 				yyerror("auth already specified");
2388 				YYERROR;
2389 			}
2390 			listen_opts.options |= LO_AUTH;
2391 			listen_opts.authtable = $2;
2392 			listen_opts.auth = F_AUTH;
2393 		}
2394 		| TAG STRING			{
2395 			if (listen_opts.options & LO_TAG) {
2396 				yyerror("tag already specified");
2397 				YYERROR;
2398 			}
2399 			listen_opts.options |= LO_TAG;
2400 
2401 			if (strlen($2) >= SMTPD_TAG_SIZE) {
2402        				yyerror("tag name too long");
2403 				free($2);
2404 				YYERROR;
2405 			}
2406 			listen_opts.tag = $2;
2407 		}
2408 		| HOSTNAME STRING	{
2409 			if (listen_opts.options & LO_HOSTNAME) {
2410 				yyerror("hostname already specified");
2411 				YYERROR;
2412 			}
2413 			listen_opts.options |= LO_HOSTNAME;
2414 
2415 			listen_opts.hostname = $2;
2416 		}
2417 		| HOSTNAMES tables	{
2418 			struct table	*t = $2;
2419 
2420 			if (listen_opts.options & LO_HOSTNAMES) {
2421 				yyerror("hostnames already specified");
2422 				YYERROR;
2423 			}
2424 			listen_opts.options |= LO_HOSTNAMES;
2425 
2426 			if (!table_check_use(t, T_DYNAMIC|T_HASH, K_ADDRNAME)) {
2427 				yyerror("invalid use of table \"%s\" as "
2428 				    "HOSTNAMES parameter", t->t_name);
2429 				YYERROR;
2430 			}
2431 			listen_opts.hostnametable = t;
2432 		}
2433 		| MASK_SRC	{
2434 			if (config_lo_mask_source(&listen_opts)) {
2435 				YYERROR;
2436 			}
2437 		}
2438 		| RECEIVEDAUTH	{
2439 			if (listen_opts.options & LO_RECEIVEDAUTH) {
2440 				yyerror("received-auth already specified");
2441 				YYERROR;
2442 			}
2443 			listen_opts.options |= LO_RECEIVEDAUTH;
2444 			listen_opts.flags |= F_RECEIVEDAUTH;
2445 		}
2446 		| NO_DSN	{
2447 			if (listen_opts.options & LO_NODSN) {
2448 				yyerror("no-dsn already specified");
2449 				YYERROR;
2450 			}
2451 			listen_opts.options |= LO_NODSN;
2452 			listen_opts.flags &= ~F_EXT_DSN;
2453 		}
2454 		| PROXY_V2	{
2455 			if (listen_opts.options & LO_PROXY) {
2456 				yyerror("proxy-v2 already specified");
2457 				YYERROR;
2458 			}
2459 			listen_opts.options |= LO_PROXY;
2460 			listen_opts.flags |= F_PROXY;
2461 		}
2462 		| SENDERS tables	{
2463 			struct table	*t = $2;
2464 
2465 			if (listen_opts.options & LO_SENDERS) {
2466 				yyerror("senders already specified");
2467 				YYERROR;
2468 			}
2469 			listen_opts.options |= LO_SENDERS;
2470 
2471 			if (!table_check_use(t, T_DYNAMIC|T_HASH, K_MAILADDRMAP)) {
2472 				yyerror("invalid use of table \"%s\" as "
2473 				    "SENDERS parameter", t->t_name);
2474 				YYERROR;
2475 			}
2476 			listen_opts.sendertable = t;
2477 		}
2478 		| SENDERS tables MASQUERADE	{
2479 			struct table	*t = $2;
2480 
2481 			if (listen_opts.options & LO_SENDERS) {
2482 				yyerror("senders already specified");
2483 				YYERROR;
2484 			}
2485 			listen_opts.options |= LO_SENDERS|LO_MASQUERADE;
2486 
2487 			if (!table_check_use(t, T_DYNAMIC|T_HASH, K_MAILADDRMAP)) {
2488 				yyerror("invalid use of table \"%s\" as "
2489 				    "SENDERS parameter", t->t_name);
2490 				YYERROR;
2491 			}
2492 			listen_opts.sendertable = t;
2493 		}
2494 		;
2495 
2496 listener_type	: socket_listener
2497 		| if_listener
2498 		;
2499 
2500 socket_listener	: SOCKET sock_listen {
2501 			if (conf->sc_sock_listener) {
2502 				yyerror("socket listener already configured");
2503 				YYERROR;
2504 			}
2505 			create_sock_listener(&listen_opts);
2506 		}
2507 		;
2508 
2509 if_listener	: STRING if_listen {
2510 			listen_opts.ifx = $1;
2511 			create_if_listener(&listen_opts);
2512 		}
2513 		;
2514 
2515 sock_listen	: opt_sock_listen sock_listen
2516 		| /* empty */
2517 		;
2518 
2519 if_listen	: opt_if_listen if_listen
2520 		| /* empty */
2521 		;
2522 
2523 
2524 listen		: LISTEN {
2525 			memset(&listen_opts, 0, sizeof listen_opts);
2526 			listen_opts.family = AF_UNSPEC;
2527 			listen_opts.flags |= F_EXT_DSN;
2528 		} ON listener_type {
2529 			free(listen_opts.tls_protocols);
2530 			free(listen_opts.tls_ciphers);
2531 			memset(&listen_opts, 0, sizeof listen_opts);
2532 		}
2533 		;
2534 
2535 table		: TABLE STRING STRING	{
2536 			char *p, *backend, *config;
2537 
2538 			p = $3;
2539 			if (*p == '/') {
2540 				backend = "static";
2541 				config = $3;
2542 			}
2543 			else {
2544 				backend = $3;
2545 				config = NULL;
2546 				for (p = $3; *p && *p != ':'; p++)
2547 					;
2548 				if (*p == ':') {
2549 					*p = '\0';
2550 					backend = $3;
2551 					config  = p+1;
2552 				}
2553 			}
2554 			if (config != NULL && *config != '/') {
2555 				yyerror("invalid backend parameter for table: %s",
2556 				    $2);
2557 				free($2);
2558 				free($3);
2559 				YYERROR;
2560 			}
2561 			table = table_create(conf, backend, $2, config);
2562 			if (!table_config(table)) {
2563 				yyerror("invalid configuration file %s for table %s",
2564 				    config, table->t_name);
2565 				free($2);
2566 				free($3);
2567 				YYERROR;
2568 			}
2569 			table = NULL;
2570 			free($2);
2571 			free($3);
2572 		}
2573 		| TABLE STRING {
2574 			table = table_create(conf, "static", $2, NULL);
2575 			free($2);
2576 		} '{' optnl tableval_list '}' {
2577 			table = NULL;
2578 		}
2579 		;
2580 
2581 tablenew	: STRING			{
2582 			struct table	*t;
2583 
2584 			t = table_create(conf, "static", NULL, NULL);
2585 			table_add(t, $1, NULL);
2586 			free($1);
2587 			$$ = t;
2588 		}
2589 		| '{' optnl			{
2590 			table = table_create(conf, "static", NULL, NULL);
2591 		} tableval_list '}'		{
2592 			$$ = table;
2593 			table = NULL;
2594 		}
2595 		;
2596 
2597 tableref       	: '<' STRING '>'       		{
2598 			struct table	*t;
2599 
2600 			if ((t = table_find(conf, $2)) == NULL) {
2601 				yyerror("no such table: %s", $2);
2602 				free($2);
2603 				YYERROR;
2604 			}
2605 			free($2);
2606 			$$ = t;
2607 		}
2608 		;
2609 
2610 tables		: tablenew			{ $$ = $1; }
2611 		| tableref			{ $$ = $1; }
2612 		;
2613 
2614 
2615 %%
2616 
2617 struct keywords {
2618 	const char	*k_name;
2619 	int		 k_val;
2620 };
2621 
2622 int
2623 yyerror(const char *fmt, ...)
2624 {
2625 	va_list		 ap;
2626 	char		*msg;
2627 
2628 	file->errors++;
2629 	va_start(ap, fmt);
2630 	if (vasprintf(&msg, fmt, ap) == -1)
2631 		fatalx("yyerror vasprintf");
2632 	va_end(ap);
2633 	logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg);
2634 	free(msg);
2635 	return (0);
2636 }
2637 
2638 int
2639 kw_cmp(const void *k, const void *e)
2640 {
2641 	return (strcmp(k, ((const struct keywords *)e)->k_name));
2642 }
2643 
2644 int
2645 lookup(char *s)
2646 {
2647 	/* this has to be sorted always */
2648 	static const struct keywords keywords[] = {
2649 		{ "action",		ACTION },
2650 		{ "admd",		ADMD },
2651 		{ "alias",		ALIAS },
2652 		{ "any",		ANY },
2653 		{ "auth",		AUTH },
2654 		{ "auth-optional",     	AUTH_OPTIONAL },
2655 		{ "backup",		BACKUP },
2656 		{ "bounce",		BOUNCE },
2657 		{ "bypass",		BYPASS },
2658 		{ "ca",			CA },
2659 		{ "cert",		CERT },
2660 		{ "chain",		CHAIN },
2661 		{ "chroot",		CHROOT },
2662 		{ "ciphers",		CIPHERS },
2663 		{ "commit",		COMMIT },
2664 		{ "compression",	COMPRESSION },
2665 		{ "connect",		CONNECT },
2666 		{ "data",		DATA },
2667 		{ "data-line",		DATA_LINE },
2668 		{ "dhe",		DHE },
2669 		{ "disconnect",		DISCONNECT },
2670 		{ "domain",		DOMAIN },
2671 		{ "ehlo",		EHLO },
2672 		{ "encryption",		ENCRYPTION },
2673 		{ "expand-only",      	EXPAND_ONLY },
2674 		{ "fcrdns",		FCRDNS },
2675 		{ "filter",		FILTER },
2676 		{ "for",		FOR },
2677 		{ "forward-only",      	FORWARD_ONLY },
2678 		{ "from",		FROM },
2679 		{ "group",		GROUP },
2680 		{ "helo",		HELO },
2681 		{ "helo-src",       	HELO_SRC },
2682 		{ "host",		HOST },
2683 		{ "hostname",		HOSTNAME },
2684 		{ "hostnames",		HOSTNAMES },
2685 		{ "include",		INCLUDE },
2686 		{ "inet4",		INET4 },
2687 		{ "inet6",		INET6 },
2688 		{ "junk",		JUNK },
2689 		{ "key",		KEY },
2690 		{ "limit",		LIMIT },
2691 		{ "listen",		LISTEN },
2692 		{ "lmtp",		LMTP },
2693 		{ "local",		LOCAL },
2694 		{ "mail-from",		MAIL_FROM },
2695 		{ "maildir",		MAILDIR },
2696 		{ "mask-src",		MASK_SRC },
2697 		{ "masquerade",		MASQUERADE },
2698 		{ "match",		MATCH },
2699 		{ "max-deferred",  	MAX_DEFERRED },
2700 		{ "max-message-size",  	MAX_MESSAGE_SIZE },
2701 		{ "mbox",		MBOX },
2702 		{ "mda",		MDA },
2703 		{ "mta",		MTA },
2704 		{ "mx",			MX },
2705 		{ "no-dsn",		NO_DSN },
2706 		{ "no-verify",		NO_VERIFY },
2707 		{ "noop",		NOOP },
2708 		{ "on",			ON },
2709 		{ "phase",		PHASE },
2710 		{ "pki",		PKI },
2711 		{ "port",		PORT },
2712 		{ "proc",		PROC },
2713 		{ "proc-exec",		PROC_EXEC },
2714 		{ "protocols",		PROTOCOLS },
2715 		{ "proxy-v2",		PROXY_V2 },
2716 		{ "queue",		QUEUE },
2717 		{ "quit",		QUIT },
2718 		{ "rcpt-to",		RCPT_TO },
2719 		{ "rdns",		RDNS },
2720 		{ "received-auth",     	RECEIVEDAUTH },
2721 		{ "recipient",		RECIPIENT },
2722 		{ "regex",		REGEX },
2723 		{ "reject",		REJECT },
2724 		{ "relay",		RELAY },
2725 		{ "report",		REPORT },
2726 		{ "rewrite",		REWRITE },
2727 		{ "rset",		RSET },
2728 		{ "scheduler",		SCHEDULER },
2729 		{ "senders",   		SENDERS },
2730 		{ "smtp",		SMTP },
2731 		{ "smtp-in",		SMTP_IN },
2732 		{ "smtp-out",		SMTP_OUT },
2733 		{ "smtps",		SMTPS },
2734 		{ "socket",		SOCKET },
2735 		{ "src",		SRC },
2736 		{ "srs",		SRS },
2737 		{ "sub-addr-delim",	SUB_ADDR_DELIM },
2738 		{ "table",		TABLE },
2739 		{ "tag",		TAG },
2740 		{ "tagged",		TAGGED },
2741 		{ "tls",		TLS },
2742 		{ "tls-require",       	TLS_REQUIRE },
2743 		{ "ttl",		TTL },
2744 		{ "user",		USER },
2745 		{ "userbase",		USERBASE },
2746 		{ "verify",		VERIFY },
2747 		{ "virtual",		VIRTUAL },
2748 		{ "warn-interval",	WARN_INTERVAL },
2749 		{ "wrapper",		WRAPPER },
2750 	};
2751 	const struct keywords	*p;
2752 
2753 	p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
2754 	    sizeof(keywords[0]), kw_cmp);
2755 
2756 	if (p)
2757 		return (p->k_val);
2758 	else
2759 		return (STRING);
2760 }
2761 
2762 #define START_EXPAND	1
2763 #define DONE_EXPAND	2
2764 
2765 static int	expanding;
2766 
2767 int
2768 igetc(void)
2769 {
2770 	int	c;
2771 
2772 	while (1) {
2773 		if (file->ungetpos > 0)
2774 			c = file->ungetbuf[--file->ungetpos];
2775 		else
2776 			c = getc(file->stream);
2777 
2778 		if (c == START_EXPAND)
2779 			expanding = 1;
2780 		else if (c == DONE_EXPAND)
2781 			expanding = 0;
2782 		else
2783 			break;
2784 	}
2785 	return (c);
2786 }
2787 
2788 int
2789 lgetc(int quotec)
2790 {
2791 	int		c, next;
2792 
2793 	if (quotec) {
2794 		if ((c = igetc()) == EOF) {
2795 			yyerror("reached end of file while parsing "
2796 			    "quoted string");
2797 			if (file == topfile || popfile() == EOF)
2798 				return (EOF);
2799 			return (quotec);
2800 		}
2801 		return (c);
2802 	}
2803 
2804 	while ((c = igetc()) == '\\') {
2805 		next = igetc();
2806 		if (next != '\n') {
2807 			c = next;
2808 			break;
2809 		}
2810 		yylval.lineno = file->lineno;
2811 		file->lineno++;
2812 	}
2813 
2814 	if (c == EOF) {
2815 		/*
2816 		 * Fake EOL when hit EOF for the first time. This gets line
2817 		 * count right if last line in included file is syntactically
2818 		 * invalid and has no newline.
2819 		 */
2820 		if (file->eof_reached == 0) {
2821 			file->eof_reached = 1;
2822 			return ('\n');
2823 		}
2824 		while (c == EOF) {
2825 			if (file == topfile || popfile() == EOF)
2826 				return (EOF);
2827 			c = igetc();
2828 		}
2829 	}
2830 	return (c);
2831 }
2832 
2833 void
2834 lungetc(int c)
2835 {
2836 	if (c == EOF)
2837 		return;
2838 
2839 	if (file->ungetpos >= file->ungetsize) {
2840 		void *p = reallocarray(file->ungetbuf, file->ungetsize, 2);
2841 		if (p == NULL)
2842 			fatal("%s", __func__);
2843 		file->ungetbuf = p;
2844 		file->ungetsize *= 2;
2845 	}
2846 	file->ungetbuf[file->ungetpos++] = c;
2847 }
2848 
2849 int
2850 findeol(void)
2851 {
2852 	int	c;
2853 
2854 	/* skip to either EOF or the first real EOL */
2855 	while (1) {
2856 		c = lgetc(0);
2857 		if (c == '\n') {
2858 			file->lineno++;
2859 			break;
2860 		}
2861 		if (c == EOF)
2862 			break;
2863 	}
2864 	return (ERROR);
2865 }
2866 
2867 int
2868 yylex(void)
2869 {
2870 	char	 buf[8096];
2871 	char	*p, *val;
2872 	int	 quotec, next, c;
2873 	int	 token;
2874 
2875 top:
2876 	p = buf;
2877 	while ((c = lgetc(0)) == ' ' || c == '\t')
2878 		; /* nothing */
2879 
2880 	yylval.lineno = file->lineno;
2881 	if (c == '#')
2882 		while ((c = lgetc(0)) != '\n' && c != EOF)
2883 			; /* nothing */
2884 	if (c == '$' && !expanding) {
2885 		while (1) {
2886 			if ((c = lgetc(0)) == EOF)
2887 				return (0);
2888 
2889 			if (p + 1 >= buf + sizeof(buf) - 1) {
2890 				yyerror("string too long");
2891 				return (findeol());
2892 			}
2893 			if (isalnum(c) || c == '_') {
2894 				*p++ = c;
2895 				continue;
2896 			}
2897 			*p = '\0';
2898 			lungetc(c);
2899 			break;
2900 		}
2901 		val = symget(buf);
2902 		if (val == NULL) {
2903 			yyerror("macro '%s' not defined", buf);
2904 			return (findeol());
2905 		}
2906 		p = val + strlen(val) - 1;
2907 		lungetc(DONE_EXPAND);
2908 		while (p >= val) {
2909 			lungetc((unsigned char)*p);
2910 			p--;
2911 		}
2912 		lungetc(START_EXPAND);
2913 		goto top;
2914 	}
2915 
2916 	switch (c) {
2917 	case '\'':
2918 	case '"':
2919 		quotec = c;
2920 		while (1) {
2921 			if ((c = lgetc(quotec)) == EOF)
2922 				return (0);
2923 			if (c == '\n') {
2924 				file->lineno++;
2925 				continue;
2926 			} else if (c == '\\') {
2927 				if ((next = lgetc(quotec)) == EOF)
2928 					return (0);
2929 				if (next == quotec || next == ' ' ||
2930 				    next == '\t')
2931 					c = next;
2932 				else if (next == '\n') {
2933 					file->lineno++;
2934 					continue;
2935 				} else
2936 					lungetc(next);
2937 			} else if (c == quotec) {
2938 				*p = '\0';
2939 				break;
2940 			} else if (c == '\0') {
2941 				yyerror("syntax error");
2942 				return (findeol());
2943 			}
2944 			if (p + 1 >= buf + sizeof(buf) - 1) {
2945 				yyerror("string too long");
2946 				return (findeol());
2947 			}
2948 			*p++ = c;
2949 		}
2950 		yylval.v.string = strdup(buf);
2951 		if (yylval.v.string == NULL)
2952 			fatal("%s", __func__);
2953 		return (STRING);
2954 	}
2955 
2956 #define allowed_to_end_number(x) \
2957 	(isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
2958 
2959 	if (c == '-' || isdigit(c)) {
2960 		do {
2961 			*p++ = c;
2962 			if ((size_t)(p-buf) >= sizeof(buf)) {
2963 				yyerror("string too long");
2964 				return (findeol());
2965 			}
2966 		} while ((c = lgetc(0)) != EOF && isdigit(c));
2967 		lungetc(c);
2968 		if (p == buf + 1 && buf[0] == '-')
2969 			goto nodigits;
2970 		if (c == EOF || allowed_to_end_number(c)) {
2971 			const char *errstr = NULL;
2972 
2973 			*p = '\0';
2974 			yylval.v.number = strtonum(buf, LLONG_MIN,
2975 			    LLONG_MAX, &errstr);
2976 			if (errstr) {
2977 				yyerror("\"%s\" invalid number: %s",
2978 				    buf, errstr);
2979 				return (findeol());
2980 			}
2981 			return (NUMBER);
2982 		} else {
2983 nodigits:
2984 			while (p > buf + 1)
2985 				lungetc((unsigned char)*--p);
2986 			c = (unsigned char)*--p;
2987 			if (c == '-')
2988 				return (c);
2989 		}
2990 	}
2991 
2992 	if (c == '=') {
2993 		if ((c = lgetc(0)) != EOF && c == '>')
2994 			return (ARROW);
2995 		lungetc(c);
2996 		c = '=';
2997 	}
2998 
2999 #define allowed_in_string(x) \
3000 	(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
3001 	x != '{' && x != '}' && x != '<' && x != '>' && \
3002 	x != '!' && x != '=' && x != '#' && \
3003 	x != ','))
3004 
3005 	if (isalnum(c) || c == ':' || c == '_') {
3006 		do {
3007 			*p++ = c;
3008 			if ((size_t)(p-buf) >= sizeof(buf)) {
3009 				yyerror("string too long");
3010 				return (findeol());
3011 			}
3012 		} while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
3013 		lungetc(c);
3014 		*p = '\0';
3015 		if ((token = lookup(buf)) == STRING)
3016 			if ((yylval.v.string = strdup(buf)) == NULL)
3017 				fatal("%s", __func__);
3018 		return (token);
3019 	}
3020 	if (c == '\n') {
3021 		yylval.lineno = file->lineno;
3022 		file->lineno++;
3023 	}
3024 	if (c == EOF)
3025 		return (0);
3026 	return (c);
3027 }
3028 
3029 int
3030 check_file_secrecy(int fd, const char *fname)
3031 {
3032 	struct stat	st;
3033 
3034 	if (fstat(fd, &st)) {
3035 		log_warn("warn: cannot stat %s", fname);
3036 		return (-1);
3037 	}
3038 	if (st.st_uid != 0 && st.st_uid != getuid()) {
3039 		log_warnx("warn: %s: owner not root or current user", fname);
3040 		return (-1);
3041 	}
3042 	if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) {
3043 		log_warnx("warn: %s: group/world readable/writeable", fname);
3044 		return (-1);
3045 	}
3046 	return (0);
3047 }
3048 
3049 struct file *
3050 pushfile(const char *name, int secret)
3051 {
3052 	struct file	*nfile;
3053 
3054 	if ((nfile = calloc(1, sizeof(struct file))) == NULL) {
3055 		log_warn("%s", __func__);
3056 		return (NULL);
3057 	}
3058 	if ((nfile->name = strdup(name)) == NULL) {
3059 		log_warn("%s", __func__);
3060 		free(nfile);
3061 		return (NULL);
3062 	}
3063 	if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
3064 		log_warn("%s: %s", __func__, nfile->name);
3065 		free(nfile->name);
3066 		free(nfile);
3067 		return (NULL);
3068 	} else if (secret &&
3069 	    check_file_secrecy(fileno(nfile->stream), nfile->name)) {
3070 		fclose(nfile->stream);
3071 		free(nfile->name);
3072 		free(nfile);
3073 		return (NULL);
3074 	}
3075 	nfile->lineno = TAILQ_EMPTY(&files) ? 1 : 0;
3076 	nfile->ungetsize = 16;
3077 	nfile->ungetbuf = malloc(nfile->ungetsize);
3078 	if (nfile->ungetbuf == NULL) {
3079 		log_warn("%s", __func__);
3080 		fclose(nfile->stream);
3081 		free(nfile->name);
3082 		free(nfile);
3083 		return (NULL);
3084 	}
3085 	TAILQ_INSERT_TAIL(&files, nfile, entry);
3086 	return (nfile);
3087 }
3088 
3089 int
3090 popfile(void)
3091 {
3092 	struct file	*prev;
3093 
3094 	if ((prev = TAILQ_PREV(file, files, entry)) != NULL)
3095 		prev->errors += file->errors;
3096 
3097 	TAILQ_REMOVE(&files, file, entry);
3098 	fclose(file->stream);
3099 	free(file->name);
3100 	free(file->ungetbuf);
3101 	free(file);
3102 	file = prev;
3103 	return (file ? 0 : EOF);
3104 }
3105 
3106 int
3107 parse_config(struct smtpd *x_conf, const char *filename, int opts)
3108 {
3109 	struct sym     *sym, *next;
3110 
3111 	conf = x_conf;
3112 	errors = 0;
3113 
3114 	if ((file = pushfile(filename, 0)) == NULL) {
3115 		purge_config(PURGE_EVERYTHING);
3116 		return (-1);
3117 	}
3118 	topfile = file;
3119 
3120 	/*
3121 	 * parse configuration
3122 	 */
3123 	setservent(1);
3124 	yyparse();
3125 	errors = file->errors;
3126 	popfile();
3127 	endservent();
3128 
3129 	/* If the socket listener was not configured, create a default one. */
3130 	if (!conf->sc_sock_listener) {
3131 		memset(&listen_opts, 0, sizeof listen_opts);
3132 		listen_opts.family = AF_UNSPEC;
3133 		listen_opts.flags |= F_EXT_DSN;
3134 		create_sock_listener(&listen_opts);
3135 	}
3136 
3137 	/* Free macros and check which have not been used. */
3138 	TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) {
3139 		if ((conf->sc_opts & SMTPD_OPT_VERBOSE) && !sym->used)
3140 			fprintf(stderr, "warning: macro '%s' not "
3141 			    "used\n", sym->nam);
3142 		if (!sym->persist) {
3143 			free(sym->nam);
3144 			free(sym->val);
3145 			TAILQ_REMOVE(&symhead, sym, entry);
3146 			free(sym);
3147 		}
3148 	}
3149 
3150 	if (TAILQ_EMPTY(conf->sc_rules)) {
3151 		log_warnx("warn: no rules, nothing to do");
3152 		errors++;
3153 	}
3154 
3155 	if (errors) {
3156 		purge_config(PURGE_EVERYTHING);
3157 		return (-1);
3158 	}
3159 
3160 	return (0);
3161 }
3162 
3163 int
3164 symset(const char *nam, const char *val, int persist)
3165 {
3166 	struct sym	*sym;
3167 
3168 	TAILQ_FOREACH(sym, &symhead, entry) {
3169 		if (strcmp(nam, sym->nam) == 0)
3170 			break;
3171 	}
3172 
3173 	if (sym != NULL) {
3174 		if (sym->persist == 1)
3175 			return (0);
3176 		else {
3177 			free(sym->nam);
3178 			free(sym->val);
3179 			TAILQ_REMOVE(&symhead, sym, entry);
3180 			free(sym);
3181 		}
3182 	}
3183 	if ((sym = calloc(1, sizeof(*sym))) == NULL)
3184 		return (-1);
3185 
3186 	sym->nam = strdup(nam);
3187 	if (sym->nam == NULL) {
3188 		free(sym);
3189 		return (-1);
3190 	}
3191 	sym->val = strdup(val);
3192 	if (sym->val == NULL) {
3193 		free(sym->nam);
3194 		free(sym);
3195 		return (-1);
3196 	}
3197 	sym->used = 0;
3198 	sym->persist = persist;
3199 	TAILQ_INSERT_TAIL(&symhead, sym, entry);
3200 	return (0);
3201 }
3202 
3203 int
3204 cmdline_symset(char *s)
3205 {
3206 	char	*sym, *val;
3207 	int	ret;
3208 
3209 	if ((val = strrchr(s, '=')) == NULL)
3210 		return (-1);
3211 	sym = strndup(s, val - s);
3212 	if (sym == NULL)
3213 		fatalx("%s: strndup", __func__);
3214 	ret = symset(sym, val + 1, 1);
3215 	free(sym);
3216 
3217 	return (ret);
3218 }
3219 
3220 char *
3221 symget(const char *nam)
3222 {
3223 	struct sym	*sym;
3224 
3225 	TAILQ_FOREACH(sym, &symhead, entry) {
3226 		if (strcmp(nam, sym->nam) == 0) {
3227 			sym->used = 1;
3228 			return (sym->val);
3229 		}
3230 	}
3231 	return (NULL);
3232 }
3233 
3234 static void
3235 create_sock_listener(struct listen_opts *lo)
3236 {
3237 	struct listener *l = xcalloc(1, sizeof(*l));
3238 	lo->hostname = conf->sc_hostname;
3239 	l->ss.ss_family = AF_LOCAL;
3240 	l->ss.ss_len = sizeof(struct sockaddr *);
3241 	l->local = 1;
3242 	conf->sc_sock_listener = l;
3243 	config_listener(l, lo);
3244 }
3245 
3246 static void
3247 create_if_listener(struct listen_opts *lo)
3248 {
3249 	uint16_t	flags;
3250 
3251 	if (lo->port != 0 && lo->ssl == F_SSL)
3252 		fatalx("invalid listen option: tls/smtps on same port");
3253 
3254 	if (lo->auth != 0 && !lo->ssl)
3255 		fatalx("invalid listen option: auth requires tls/smtps");
3256 
3257 	if (lo->pkicount && !lo->ssl)
3258 		fatalx("invalid listen option: pki requires tls/smtps");
3259 	if (lo->pkicount == 0 && lo->ssl)
3260 		fatalx("invalid listen option: pki required for tls/smtps");
3261 
3262 	flags = lo->flags;
3263 
3264 	if (lo->port) {
3265 		lo->flags = lo->ssl|lo->auth|flags;
3266 		lo->port = htons(lo->port);
3267 	}
3268 	else {
3269 		if (lo->ssl & F_SMTPS) {
3270 			lo->port = htons(465);
3271 			lo->flags = F_SMTPS|lo->auth|flags;
3272 		}
3273 
3274 		if (!lo->ssl || (lo->ssl & F_STARTTLS)) {
3275 			lo->port = htons(25);
3276 			lo->flags = lo->auth|flags;
3277 			if (lo->ssl & F_STARTTLS)
3278 				lo->flags |= F_STARTTLS;
3279 		}
3280 	}
3281 
3282 	if (interface(lo))
3283 		return;
3284 	if (host_v4(lo))
3285 		return;
3286 	if (host_v6(lo))
3287 		return;
3288 	if (host_dns(lo))
3289 		return;
3290 
3291 	fatalx("invalid virtual ip or interface: %s", lo->ifx);
3292 }
3293 
3294 static void
3295 config_listener(struct listener *h,  struct listen_opts *lo)
3296 {
3297 	int i;
3298 
3299 	h->fd = -1;
3300 	h->port = lo->port;
3301 	h->flags = lo->flags;
3302 
3303 	if (lo->hostname == NULL)
3304 		lo->hostname = conf->sc_hostname;
3305 
3306 	if (lo->options & LO_FILTER) {
3307 		h->flags |= F_FILTERED;
3308 		(void)strlcpy(h->filter_name,
3309 		    lo->filtername,
3310 		    sizeof(h->filter_name));
3311 	}
3312 
3313 	if (lo->authtable != NULL)
3314 		(void)strlcpy(h->authtable, lo->authtable->t_name, sizeof(h->authtable));
3315 
3316 	h->pkicount = lo->pkicount;
3317 	if (h->pkicount) {
3318 		h->pki = calloc(h->pkicount, sizeof(*h->pki));
3319 		if (h->pki == NULL)
3320 			fatal("calloc");
3321 	}
3322 	for (i = 0; i < lo->pkicount; i++) {
3323 		h->pki[i] = dict_get(conf->sc_pki_dict, lo->pki[i]);
3324 		if (h->pki[i] == NULL) {
3325 			log_warnx("pki name not found: %s", lo->pki[i]);
3326 			fatalx(NULL);
3327 		}
3328 	}
3329 
3330 	if (lo->tls_ciphers != NULL &&
3331 	    (h->tls_ciphers = strdup(lo->tls_ciphers)) == NULL) {
3332 		fatal("strdup");
3333 	}
3334 
3335 	if (lo->tls_protocols != NULL &&
3336 	    (h->tls_protocols = strdup(lo->tls_protocols)) == NULL) {
3337 		fatal("strdup");
3338 	}
3339 
3340 	if (lo->ca != NULL) {
3341 		if (!lowercase(h->ca_name, lo->ca, sizeof(h->ca_name))) {
3342 			log_warnx("ca name too long: %s", lo->ca);
3343 			fatalx(NULL);
3344 		}
3345 		if (dict_get(conf->sc_ca_dict, h->ca_name) == NULL) {
3346 			log_warnx("ca name not found: %s", lo->ca);
3347 			fatalx(NULL);
3348 		}
3349 	}
3350 	if (lo->tag != NULL)
3351 		(void)strlcpy(h->tag, lo->tag, sizeof(h->tag));
3352 
3353 	(void)strlcpy(h->hostname, lo->hostname, sizeof(h->hostname));
3354 	if (lo->hostnametable)
3355 		(void)strlcpy(h->hostnametable, lo->hostnametable->t_name, sizeof(h->hostnametable));
3356 	if (lo->sendertable) {
3357 		(void)strlcpy(h->sendertable, lo->sendertable->t_name, sizeof(h->sendertable));
3358 		if (lo->options & LO_MASQUERADE)
3359 			h->flags |= F_MASQUERADE;
3360 	}
3361 
3362 	if (lo->ssl & F_TLS_VERIFY)
3363 		h->flags |= F_TLS_VERIFY;
3364 
3365 	if (lo->ssl & F_STARTTLS_REQUIRE)
3366 		h->flags |= F_STARTTLS_REQUIRE;
3367 
3368 	if (h != conf->sc_sock_listener)
3369 		TAILQ_INSERT_TAIL(conf->sc_listeners, h, entry);
3370 }
3371 
3372 static int
3373 host_v4(struct listen_opts *lo)
3374 {
3375 	struct in_addr		 ina;
3376 	struct sockaddr_in	*sain;
3377 	struct listener		*h;
3378 
3379 	if (lo->family != AF_UNSPEC && lo->family != AF_INET)
3380 		return (0);
3381 
3382 	memset(&ina, 0, sizeof(ina));
3383 	if (inet_pton(AF_INET, lo->ifx, &ina) != 1)
3384 		return (0);
3385 
3386 	h = xcalloc(1, sizeof(*h));
3387 	sain = (struct sockaddr_in *)&h->ss;
3388 	sain->sin_len = sizeof(struct sockaddr_in);
3389 	sain->sin_family = AF_INET;
3390 	sain->sin_addr.s_addr = ina.s_addr;
3391 	sain->sin_port = lo->port;
3392 
3393 	if (sain->sin_addr.s_addr == htonl(INADDR_LOOPBACK))
3394 		h->local = 1;
3395 	config_listener(h,  lo);
3396 
3397 	return (1);
3398 }
3399 
3400 static int
3401 host_v6(struct listen_opts *lo)
3402 {
3403 	struct in6_addr		 ina6;
3404 	struct sockaddr_in6	*sin6;
3405 	struct listener		*h;
3406 
3407 	if (lo->family != AF_UNSPEC && lo->family != AF_INET6)
3408 		return (0);
3409 
3410 	memset(&ina6, 0, sizeof(ina6));
3411 	if (inet_pton(AF_INET6, lo->ifx, &ina6) != 1)
3412 		return (0);
3413 
3414 	h = xcalloc(1, sizeof(*h));
3415 	sin6 = (struct sockaddr_in6 *)&h->ss;
3416 	sin6->sin6_len = sizeof(struct sockaddr_in6);
3417 	sin6->sin6_family = AF_INET6;
3418 	sin6->sin6_port = lo->port;
3419 	memcpy(&sin6->sin6_addr, &ina6, sizeof(ina6));
3420 
3421 	if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr))
3422 		h->local = 1;
3423 	config_listener(h,  lo);
3424 
3425 	return (1);
3426 }
3427 
3428 static int
3429 host_dns(struct listen_opts *lo)
3430 {
3431 	struct addrinfo		 hints, *res0, *res;
3432 	int			 error, cnt = 0;
3433 	struct sockaddr_in	*sain;
3434 	struct sockaddr_in6	*sin6;
3435 	struct listener		*h;
3436 
3437 	memset(&hints, 0, sizeof(hints));
3438 	hints.ai_family = lo->family;
3439 	hints.ai_socktype = SOCK_STREAM;
3440 	hints.ai_flags = AI_ADDRCONFIG;
3441 	error = getaddrinfo(lo->ifx, NULL, &hints, &res0);
3442 	if (error == EAI_AGAIN || error == EAI_NODATA || error == EAI_NONAME)
3443 		return (0);
3444 	if (error) {
3445 		log_warnx("warn: host_dns: could not parse \"%s\": %s", lo->ifx,
3446 		    gai_strerror(error));
3447 		return (-1);
3448 	}
3449 
3450 	for (res = res0; res; res = res->ai_next) {
3451 		if (res->ai_family != AF_INET &&
3452 		    res->ai_family != AF_INET6)
3453 			continue;
3454 		h = xcalloc(1, sizeof(*h));
3455 
3456 		h->ss.ss_family = res->ai_family;
3457 		if (res->ai_family == AF_INET) {
3458 			sain = (struct sockaddr_in *)&h->ss;
3459 			sain->sin_len = sizeof(struct sockaddr_in);
3460 			sain->sin_addr.s_addr = ((struct sockaddr_in *)
3461 			    res->ai_addr)->sin_addr.s_addr;
3462 			sain->sin_port = lo->port;
3463 			if (sain->sin_addr.s_addr == htonl(INADDR_LOOPBACK))
3464 				h->local = 1;
3465 		} else {
3466 			sin6 = (struct sockaddr_in6 *)&h->ss;
3467 			sin6->sin6_len = sizeof(struct sockaddr_in6);
3468 			memcpy(&sin6->sin6_addr, &((struct sockaddr_in6 *)
3469 			    res->ai_addr)->sin6_addr, sizeof(struct in6_addr));
3470 			sin6->sin6_port = lo->port;
3471 			if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr))
3472 				h->local = 1;
3473 		}
3474 
3475 		config_listener(h, lo);
3476 
3477 		cnt++;
3478 	}
3479 
3480 	freeaddrinfo(res0);
3481 	return (cnt);
3482 }
3483 
3484 static int
3485 interface(struct listen_opts *lo)
3486 {
3487 	struct ifaddrs *ifap, *p;
3488 	struct sockaddr_in	*sain;
3489 	struct sockaddr_in6	*sin6;
3490 	struct listener		*h;
3491 	int			ret = 0;
3492 
3493 	if (getifaddrs(&ifap) == -1)
3494 		fatal("getifaddrs");
3495 
3496 	for (p = ifap; p != NULL; p = p->ifa_next) {
3497 		if (p->ifa_addr == NULL)
3498 			continue;
3499 		if (strcmp(p->ifa_name, lo->ifx) != 0 &&
3500 		    !is_if_in_group(p->ifa_name, lo->ifx))
3501 			continue;
3502 		if (lo->family != AF_UNSPEC && lo->family != p->ifa_addr->sa_family)
3503 			continue;
3504 
3505 		h = xcalloc(1, sizeof(*h));
3506 
3507 		switch (p->ifa_addr->sa_family) {
3508 		case AF_INET:
3509 			sain = (struct sockaddr_in *)&h->ss;
3510 			*sain = *(struct sockaddr_in *)p->ifa_addr;
3511 			sain->sin_len = sizeof(struct sockaddr_in);
3512 			sain->sin_port = lo->port;
3513 			if (sain->sin_addr.s_addr == htonl(INADDR_LOOPBACK))
3514 				h->local = 1;
3515 			break;
3516 
3517 		case AF_INET6:
3518 			sin6 = (struct sockaddr_in6 *)&h->ss;
3519 			*sin6 = *(struct sockaddr_in6 *)p->ifa_addr;
3520 			sin6->sin6_len = sizeof(struct sockaddr_in6);
3521 			sin6->sin6_port = lo->port;
3522 #ifdef __KAME__
3523 			if ((IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) ||
3524 			    IN6_IS_ADDR_MC_LINKLOCAL(&sin6->sin6_addr) ||
3525 			    IN6_IS_ADDR_MC_INTFACELOCAL(&sin6->sin6_addr)) &&
3526 			    sin6->sin6_scope_id == 0) {
3527 				sin6->sin6_scope_id = ntohs(
3528 				    *(u_int16_t *)&sin6->sin6_addr.s6_addr[2]);
3529 				sin6->sin6_addr.s6_addr[2] = 0;
3530 				sin6->sin6_addr.s6_addr[3] = 0;
3531 			}
3532 #endif
3533 			if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr))
3534 				h->local = 1;
3535 			break;
3536 
3537 		default:
3538 			free(h);
3539 			continue;
3540 		}
3541 
3542 		config_listener(h, lo);
3543 		ret = 1;
3544 	}
3545 
3546 	freeifaddrs(ifap);
3547 
3548 	return ret;
3549 }
3550 
3551 int
3552 delaytonum(char *str)
3553 {
3554 	unsigned int     factor;
3555 	size_t           len;
3556 	const char      *errstr = NULL;
3557 	int              delay;
3558 
3559 	/* we need at least 1 digit and 1 unit */
3560 	len = strlen(str);
3561 	if (len < 2)
3562 		goto bad;
3563 
3564 	switch(str[len - 1]) {
3565 
3566 	case 's':
3567 		factor = 1;
3568 		break;
3569 
3570 	case 'm':
3571 		factor = 60;
3572 		break;
3573 
3574 	case 'h':
3575 		factor = 60 * 60;
3576 		break;
3577 
3578 	case 'd':
3579 		factor = 24 * 60 * 60;
3580 		break;
3581 
3582 	default:
3583 		goto bad;
3584 	}
3585 
3586 	str[len - 1] = '\0';
3587 	delay = strtonum(str, 1, INT_MAX / factor, &errstr);
3588 	if (errstr)
3589 		goto bad;
3590 
3591 	return (delay * factor);
3592 
3593 bad:
3594 	return (-1);
3595 }
3596 
3597 int
3598 is_if_in_group(const char *ifname, const char *groupname)
3599 {
3600         unsigned int		 len;
3601         struct ifgroupreq        ifgr;
3602         struct ifg_req          *ifg;
3603 	int			 s;
3604 	int			 ret = 0;
3605 
3606 	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
3607 		fatal("socket");
3608 
3609         memset(&ifgr, 0, sizeof(ifgr));
3610         if (strlcpy(ifgr.ifgr_name, ifname, IFNAMSIZ) >= IFNAMSIZ)
3611 		fatalx("interface name too large");
3612 
3613         if (ioctl(s, SIOCGIFGROUP, (caddr_t)&ifgr) == -1) {
3614                 if (errno == EINVAL || errno == ENOTTY)
3615 			goto end;
3616 		fatal("SIOCGIFGROUP");
3617         }
3618 
3619         len = ifgr.ifgr_len;
3620         ifgr.ifgr_groups = xcalloc(len/sizeof(struct ifg_req),
3621 		sizeof(struct ifg_req));
3622         if (ioctl(s, SIOCGIFGROUP, (caddr_t)&ifgr) == -1)
3623                 fatal("SIOCGIFGROUP");
3624 
3625         ifg = ifgr.ifgr_groups;
3626         for (; ifg && len >= sizeof(struct ifg_req); ifg++) {
3627                 len -= sizeof(struct ifg_req);
3628 		if (strcmp(ifg->ifgrq_group, groupname) == 0) {
3629 			ret = 1;
3630 			break;
3631 		}
3632         }
3633         free(ifgr.ifgr_groups);
3634 
3635 end:
3636 	close(s);
3637 	return ret;
3638 }
3639 
3640 static int
3641 config_lo_mask_source(struct listen_opts *lo) {
3642 	if (lo->options & LO_MASKSOURCE) {
3643 		yyerror("mask-source already specified");
3644 		return -1;
3645 	}
3646 	lo->options |= LO_MASKSOURCE;
3647 	lo->flags |= F_MASK_SOURCE;
3648 
3649 	return 0;
3650 }
3651 
3652