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