xref: /openbsd/usr.sbin/smtpd/parse.y (revision 7e71987f)
1 /*	$OpenBSD: parse.y,v 1.292 2023/05/10 07:19:49 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		: ','
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
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
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 } '{' 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
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 } '{' 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 		} '{' 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 		| TAG STRING			{
2153 			if (listen_opts.options & LO_TAG) {
2154 				yyerror("tag already specified");
2155 				YYERROR;
2156 			}
2157 			listen_opts.options |= LO_TAG;
2158 
2159 			if (strlen($2) >= SMTPD_TAG_SIZE) {
2160 				yyerror("tag name too long");
2161 				free($2);
2162 				YYERROR;
2163 			}
2164 			listen_opts.tag = $2;
2165 		}
2166 		;
2167 
2168 opt_if_listen : INET4 {
2169 			if (listen_opts.options & LO_FAMILY) {
2170 				yyerror("address family already specified");
2171 				YYERROR;
2172 			}
2173 			listen_opts.options |= LO_FAMILY;
2174 			listen_opts.family = AF_INET;
2175 		}
2176 		| INET6			{
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_INET6;
2183 		}
2184 		| PORT STRING			{
2185 			struct servent	*servent;
2186 
2187 			if (listen_opts.options & LO_PORT) {
2188 				yyerror("port already specified");
2189 				YYERROR;
2190 			}
2191 			listen_opts.options |= LO_PORT;
2192 
2193 			servent = getservbyname($2, "tcp");
2194 			if (servent == NULL) {
2195 				yyerror("invalid port: %s", $2);
2196 				free($2);
2197 				YYERROR;
2198 			}
2199 			free($2);
2200 			listen_opts.port = ntohs(servent->s_port);
2201 		}
2202 		| PORT SMTP			{
2203 			struct servent *servent;
2204 
2205 			if (listen_opts.options & LO_PORT) {
2206 				yyerror("port already specified");
2207 				YYERROR;
2208 			}
2209 			listen_opts.options |= LO_PORT;
2210 
2211 			servent = getservbyname("smtp", "tcp");
2212 			if (servent == NULL) {
2213 				yyerror("invalid port: smtp");
2214 				YYERROR;
2215 			}
2216 			listen_opts.port = ntohs(servent->s_port);
2217 		}
2218 		| PORT SMTPS			{
2219 			struct servent *servent;
2220 
2221 			if (listen_opts.options & LO_PORT) {
2222 				yyerror("port already specified");
2223 				YYERROR;
2224 			}
2225 			listen_opts.options |= LO_PORT;
2226 
2227 			servent = getservbyname("smtps", "tcp");
2228 			if (servent == NULL) {
2229 				yyerror("invalid port: smtps");
2230 				YYERROR;
2231 			}
2232 			listen_opts.port = ntohs(servent->s_port);
2233 		}
2234 		| PORT NUMBER			{
2235 			if (listen_opts.options & LO_PORT) {
2236 				yyerror("port already specified");
2237 				YYERROR;
2238 			}
2239 			listen_opts.options |= LO_PORT;
2240 
2241 			if ($2 <= 0 || $2 > (int)USHRT_MAX) {
2242 				yyerror("invalid port: %" PRId64, $2);
2243 				YYERROR;
2244 			}
2245 			listen_opts.port = $2;
2246 		}
2247 		| FILTER STRING			{
2248 			struct filter_config *fc;
2249 
2250 			if (listen_opts.options & LO_FILTER) {
2251 				yyerror("filter already specified");
2252 				YYERROR;
2253 			}
2254 			if ((fc = dict_get(conf->sc_filters_dict, $2)) == NULL) {
2255 				yyerror("no filter exist with that name: %s", $2);
2256 				free($2);
2257 				YYERROR;
2258 			}
2259 			fc->filter_subsystem |= FILTER_SUBSYSTEM_SMTP_IN;
2260 			listen_opts.options |= LO_FILTER;
2261 			listen_opts.filtername = $2;
2262 		}
2263 		| FILTER {
2264 			char	buffer[128];
2265 
2266 			if (listen_opts.options & LO_FILTER) {
2267 				yyerror("filter already specified");
2268 				YYERROR;
2269 			}
2270 
2271 			do {
2272 				(void)snprintf(buffer, sizeof buffer, "<dynchain:%08x>", last_dynchain_id++);
2273 			} while (dict_check(conf->sc_filters_dict, buffer));
2274 
2275 			listen_opts.options |= LO_FILTER;
2276 			listen_opts.filtername = xstrdup(buffer);
2277 			filter_config = xcalloc(1, sizeof *filter_config);
2278 			filter_config->filter_type = FILTER_TYPE_CHAIN;
2279 			filter_config->filter_subsystem |= FILTER_SUBSYSTEM_SMTP_IN;
2280 			dict_init(&filter_config->chain_procs);
2281 		} '{' filter_list '}' {
2282 			dict_set(conf->sc_filters_dict, listen_opts.filtername, filter_config);
2283 			filter_config = NULL;
2284 		}
2285 		| SMTPS				{
2286 			if (listen_opts.options & LO_SSL) {
2287 				yyerror("TLS mode already specified");
2288 				YYERROR;
2289 			}
2290 			listen_opts.options |= LO_SSL;
2291 			listen_opts.ssl = F_SMTPS;
2292 		}
2293 		| SMTPS VERIFY 			{
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|F_TLS_VERIFY;
2300 		}
2301 		| TLS				{
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_STARTTLS;
2308 		}
2309 		| TLS_REQUIRE			{
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|F_STARTTLS_REQUIRE;
2316 		}
2317 		| TLS_REQUIRE VERIFY   		{
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|F_TLS_VERIFY;
2324 		}
2325 		| CIPHERS STRING {
2326 			if (listen_opts.tls_ciphers) {
2327 				yyerror("ciphers already specified");
2328 				YYERROR;
2329 			}
2330 			listen_opts.tls_ciphers = $2;
2331 		}
2332 		| PROTOCOLS STRING {
2333 			if (listen_opts.tls_protocols) {
2334 				yyerror("protocols already specified");
2335 				YYERROR;
2336 			}
2337 			listen_opts.tls_protocols = $2;
2338 		}
2339 		| PKI STRING			{
2340 			if (listen_opts.pkicount == PKI_MAX) {
2341 				yyerror("too many pki specified");
2342 				YYERROR;
2343 			}
2344 			listen_opts.pki[listen_opts.pkicount++] = $2;
2345 		}
2346 		| CA STRING			{
2347 			if (listen_opts.options & LO_CA) {
2348 				yyerror("ca already specified");
2349 				YYERROR;
2350 			}
2351 			listen_opts.options |= LO_CA;
2352 			listen_opts.ca = $2;
2353 		}
2354 		| AUTH				{
2355 			if (listen_opts.options & LO_AUTH) {
2356 				yyerror("auth already specified");
2357 				YYERROR;
2358 			}
2359 			listen_opts.options |= LO_AUTH;
2360 			listen_opts.auth = F_AUTH|F_AUTH_REQUIRE;
2361 		}
2362 		| AUTH_OPTIONAL			{
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;
2369 		}
2370 		| AUTH tables  			{
2371 			if (listen_opts.options & LO_AUTH) {
2372 				yyerror("auth already specified");
2373 				YYERROR;
2374 			}
2375 			listen_opts.options |= LO_AUTH;
2376 			listen_opts.authtable = $2;
2377 			listen_opts.auth = F_AUTH|F_AUTH_REQUIRE;
2378 		}
2379 		| AUTH_OPTIONAL tables 		{
2380 			if (listen_opts.options & LO_AUTH) {
2381 				yyerror("auth already specified");
2382 				YYERROR;
2383 			}
2384 			listen_opts.options |= LO_AUTH;
2385 			listen_opts.authtable = $2;
2386 			listen_opts.auth = F_AUTH;
2387 		}
2388 		| TAG STRING			{
2389 			if (listen_opts.options & LO_TAG) {
2390 				yyerror("tag already specified");
2391 				YYERROR;
2392 			}
2393 			listen_opts.options |= LO_TAG;
2394 
2395 			if (strlen($2) >= SMTPD_TAG_SIZE) {
2396        				yyerror("tag name too long");
2397 				free($2);
2398 				YYERROR;
2399 			}
2400 			listen_opts.tag = $2;
2401 		}
2402 		| HOSTNAME STRING	{
2403 			if (listen_opts.options & LO_HOSTNAME) {
2404 				yyerror("hostname already specified");
2405 				YYERROR;
2406 			}
2407 			listen_opts.options |= LO_HOSTNAME;
2408 
2409 			listen_opts.hostname = $2;
2410 		}
2411 		| HOSTNAMES tables	{
2412 			struct table	*t = $2;
2413 
2414 			if (listen_opts.options & LO_HOSTNAMES) {
2415 				yyerror("hostnames already specified");
2416 				YYERROR;
2417 			}
2418 			listen_opts.options |= LO_HOSTNAMES;
2419 
2420 			if (!table_check_use(t, T_DYNAMIC|T_HASH, K_ADDRNAME)) {
2421 				yyerror("invalid use of table \"%s\" as "
2422 				    "HOSTNAMES parameter", t->t_name);
2423 				YYERROR;
2424 			}
2425 			listen_opts.hostnametable = t;
2426 		}
2427 		| MASK_SRC	{
2428 			if (config_lo_mask_source(&listen_opts)) {
2429 				YYERROR;
2430 			}
2431 		}
2432 		| RECEIVEDAUTH	{
2433 			if (listen_opts.options & LO_RECEIVEDAUTH) {
2434 				yyerror("received-auth already specified");
2435 				YYERROR;
2436 			}
2437 			listen_opts.options |= LO_RECEIVEDAUTH;
2438 			listen_opts.flags |= F_RECEIVEDAUTH;
2439 		}
2440 		| NO_DSN	{
2441 			if (listen_opts.options & LO_NODSN) {
2442 				yyerror("no-dsn already specified");
2443 				YYERROR;
2444 			}
2445 			listen_opts.options |= LO_NODSN;
2446 			listen_opts.flags &= ~F_EXT_DSN;
2447 		}
2448 		| PROXY_V2	{
2449 			if (listen_opts.options & LO_PROXY) {
2450 				yyerror("proxy-v2 already specified");
2451 				YYERROR;
2452 			}
2453 			listen_opts.options |= LO_PROXY;
2454 			listen_opts.flags |= F_PROXY;
2455 		}
2456 		| SENDERS tables	{
2457 			struct table	*t = $2;
2458 
2459 			if (listen_opts.options & LO_SENDERS) {
2460 				yyerror("senders already specified");
2461 				YYERROR;
2462 			}
2463 			listen_opts.options |= LO_SENDERS;
2464 
2465 			if (!table_check_use(t, T_DYNAMIC|T_HASH, K_MAILADDRMAP)) {
2466 				yyerror("invalid use of table \"%s\" as "
2467 				    "SENDERS parameter", t->t_name);
2468 				YYERROR;
2469 			}
2470 			listen_opts.sendertable = t;
2471 		}
2472 		| SENDERS tables MASQUERADE	{
2473 			struct table	*t = $2;
2474 
2475 			if (listen_opts.options & LO_SENDERS) {
2476 				yyerror("senders already specified");
2477 				YYERROR;
2478 			}
2479 			listen_opts.options |= LO_SENDERS|LO_MASQUERADE;
2480 
2481 			if (!table_check_use(t, T_DYNAMIC|T_HASH, K_MAILADDRMAP)) {
2482 				yyerror("invalid use of table \"%s\" as "
2483 				    "SENDERS parameter", t->t_name);
2484 				YYERROR;
2485 			}
2486 			listen_opts.sendertable = t;
2487 		}
2488 		;
2489 
2490 listener_type	: socket_listener
2491 		| if_listener
2492 		;
2493 
2494 socket_listener	: SOCKET sock_listen {
2495 			if (conf->sc_sock_listener) {
2496 				yyerror("socket listener already configured");
2497 				YYERROR;
2498 			}
2499 			create_sock_listener(&listen_opts);
2500 		}
2501 		;
2502 
2503 if_listener	: STRING if_listen {
2504 			listen_opts.ifx = $1;
2505 			create_if_listener(&listen_opts);
2506 		}
2507 		;
2508 
2509 sock_listen	: opt_sock_listen sock_listen
2510 		| /* empty */
2511 		;
2512 
2513 if_listen	: opt_if_listen if_listen
2514 		| /* empty */
2515 		;
2516 
2517 
2518 listen		: LISTEN {
2519 			memset(&listen_opts, 0, sizeof listen_opts);
2520 			listen_opts.family = AF_UNSPEC;
2521 			listen_opts.flags |= F_EXT_DSN;
2522 		} ON listener_type {
2523 			free(listen_opts.tls_protocols);
2524 			free(listen_opts.tls_ciphers);
2525 			memset(&listen_opts, 0, sizeof listen_opts);
2526 		}
2527 		;
2528 
2529 table		: TABLE STRING STRING	{
2530 			char *p, *backend, *config;
2531 
2532 			p = $3;
2533 			if (*p == '/') {
2534 				backend = "static";
2535 				config = $3;
2536 			}
2537 			else {
2538 				backend = $3;
2539 				config = NULL;
2540 				for (p = $3; *p && *p != ':'; p++)
2541 					;
2542 				if (*p == ':') {
2543 					*p = '\0';
2544 					backend = $3;
2545 					config  = p+1;
2546 				}
2547 			}
2548 			if (config != NULL && *config != '/') {
2549 				yyerror("invalid backend parameter for table: %s",
2550 				    $2);
2551 				free($2);
2552 				free($3);
2553 				YYERROR;
2554 			}
2555 			table = table_create(conf, backend, $2, config);
2556 			if (!table_config(table)) {
2557 				yyerror("invalid configuration file %s for table %s",
2558 				    config, table->t_name);
2559 				free($2);
2560 				free($3);
2561 				YYERROR;
2562 			}
2563 			table = NULL;
2564 			free($2);
2565 			free($3);
2566 		}
2567 		| TABLE STRING {
2568 			table = table_create(conf, "static", $2, NULL);
2569 			free($2);
2570 		} '{' tableval_list '}' {
2571 			table = NULL;
2572 		}
2573 		;
2574 
2575 tablenew	: STRING			{
2576 			struct table	*t;
2577 
2578 			t = table_create(conf, "static", NULL, NULL);
2579 			table_add(t, $1, NULL);
2580 			free($1);
2581 			$$ = t;
2582 		}
2583 		| '{'				{
2584 			table = table_create(conf, "static", NULL, NULL);
2585 		} tableval_list '}'		{
2586 			$$ = table;
2587 			table = NULL;
2588 		}
2589 		;
2590 
2591 tableref       	: '<' STRING '>'       		{
2592 			struct table	*t;
2593 
2594 			if ((t = table_find(conf, $2)) == NULL) {
2595 				yyerror("no such table: %s", $2);
2596 				free($2);
2597 				YYERROR;
2598 			}
2599 			free($2);
2600 			$$ = t;
2601 		}
2602 		;
2603 
2604 tables		: tablenew			{ $$ = $1; }
2605 		| tableref			{ $$ = $1; }
2606 		;
2607 
2608 
2609 %%
2610 
2611 struct keywords {
2612 	const char	*k_name;
2613 	int		 k_val;
2614 };
2615 
2616 int
2617 yyerror(const char *fmt, ...)
2618 {
2619 	va_list		 ap;
2620 	char		*msg;
2621 
2622 	file->errors++;
2623 	va_start(ap, fmt);
2624 	if (vasprintf(&msg, fmt, ap) == -1)
2625 		fatalx("yyerror vasprintf");
2626 	va_end(ap);
2627 	logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg);
2628 	free(msg);
2629 	return (0);
2630 }
2631 
2632 int
2633 kw_cmp(const void *k, const void *e)
2634 {
2635 	return (strcmp(k, ((const struct keywords *)e)->k_name));
2636 }
2637 
2638 int
2639 lookup(char *s)
2640 {
2641 	/* this has to be sorted always */
2642 	static const struct keywords keywords[] = {
2643 		{ "action",		ACTION },
2644 		{ "admd",		ADMD },
2645 		{ "alias",		ALIAS },
2646 		{ "any",		ANY },
2647 		{ "auth",		AUTH },
2648 		{ "auth-optional",     	AUTH_OPTIONAL },
2649 		{ "backup",		BACKUP },
2650 		{ "bounce",		BOUNCE },
2651 		{ "bypass",		BYPASS },
2652 		{ "ca",			CA },
2653 		{ "cert",		CERT },
2654 		{ "chain",		CHAIN },
2655 		{ "chroot",		CHROOT },
2656 		{ "ciphers",		CIPHERS },
2657 		{ "commit",		COMMIT },
2658 		{ "compression",	COMPRESSION },
2659 		{ "connect",		CONNECT },
2660 		{ "data",		DATA },
2661 		{ "data-line",		DATA_LINE },
2662 		{ "dhe",		DHE },
2663 		{ "disconnect",		DISCONNECT },
2664 		{ "domain",		DOMAIN },
2665 		{ "ehlo",		EHLO },
2666 		{ "encryption",		ENCRYPTION },
2667 		{ "expand-only",      	EXPAND_ONLY },
2668 		{ "fcrdns",		FCRDNS },
2669 		{ "filter",		FILTER },
2670 		{ "for",		FOR },
2671 		{ "forward-only",      	FORWARD_ONLY },
2672 		{ "from",		FROM },
2673 		{ "group",		GROUP },
2674 		{ "helo",		HELO },
2675 		{ "helo-src",       	HELO_SRC },
2676 		{ "host",		HOST },
2677 		{ "hostname",		HOSTNAME },
2678 		{ "hostnames",		HOSTNAMES },
2679 		{ "include",		INCLUDE },
2680 		{ "inet4",		INET4 },
2681 		{ "inet6",		INET6 },
2682 		{ "junk",		JUNK },
2683 		{ "key",		KEY },
2684 		{ "limit",		LIMIT },
2685 		{ "listen",		LISTEN },
2686 		{ "lmtp",		LMTP },
2687 		{ "local",		LOCAL },
2688 		{ "mail-from",		MAIL_FROM },
2689 		{ "maildir",		MAILDIR },
2690 		{ "mask-src",		MASK_SRC },
2691 		{ "masquerade",		MASQUERADE },
2692 		{ "match",		MATCH },
2693 		{ "max-deferred",  	MAX_DEFERRED },
2694 		{ "max-message-size",  	MAX_MESSAGE_SIZE },
2695 		{ "mbox",		MBOX },
2696 		{ "mda",		MDA },
2697 		{ "mta",		MTA },
2698 		{ "mx",			MX },
2699 		{ "no-dsn",		NO_DSN },
2700 		{ "no-verify",		NO_VERIFY },
2701 		{ "noop",		NOOP },
2702 		{ "on",			ON },
2703 		{ "phase",		PHASE },
2704 		{ "pki",		PKI },
2705 		{ "port",		PORT },
2706 		{ "proc",		PROC },
2707 		{ "proc-exec",		PROC_EXEC },
2708 		{ "protocols",		PROTOCOLS },
2709 		{ "proxy-v2",		PROXY_V2 },
2710 		{ "queue",		QUEUE },
2711 		{ "quit",		QUIT },
2712 		{ "rcpt-to",		RCPT_TO },
2713 		{ "rdns",		RDNS },
2714 		{ "received-auth",     	RECEIVEDAUTH },
2715 		{ "recipient",		RECIPIENT },
2716 		{ "regex",		REGEX },
2717 		{ "reject",		REJECT },
2718 		{ "relay",		RELAY },
2719 		{ "report",		REPORT },
2720 		{ "rewrite",		REWRITE },
2721 		{ "rset",		RSET },
2722 		{ "scheduler",		SCHEDULER },
2723 		{ "senders",   		SENDERS },
2724 		{ "smtp",		SMTP },
2725 		{ "smtp-in",		SMTP_IN },
2726 		{ "smtp-out",		SMTP_OUT },
2727 		{ "smtps",		SMTPS },
2728 		{ "socket",		SOCKET },
2729 		{ "src",		SRC },
2730 		{ "srs",		SRS },
2731 		{ "sub-addr-delim",	SUB_ADDR_DELIM },
2732 		{ "table",		TABLE },
2733 		{ "tag",		TAG },
2734 		{ "tagged",		TAGGED },
2735 		{ "tls",		TLS },
2736 		{ "tls-require",       	TLS_REQUIRE },
2737 		{ "ttl",		TTL },
2738 		{ "user",		USER },
2739 		{ "userbase",		USERBASE },
2740 		{ "verify",		VERIFY },
2741 		{ "virtual",		VIRTUAL },
2742 		{ "warn-interval",	WARN_INTERVAL },
2743 		{ "wrapper",		WRAPPER },
2744 	};
2745 	const struct keywords	*p;
2746 
2747 	p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
2748 	    sizeof(keywords[0]), kw_cmp);
2749 
2750 	if (p)
2751 		return (p->k_val);
2752 	else
2753 		return (STRING);
2754 }
2755 
2756 #define START_EXPAND	1
2757 #define DONE_EXPAND	2
2758 
2759 static int	expanding;
2760 
2761 int
2762 igetc(void)
2763 {
2764 	int	c;
2765 
2766 	while (1) {
2767 		if (file->ungetpos > 0)
2768 			c = file->ungetbuf[--file->ungetpos];
2769 		else
2770 			c = getc(file->stream);
2771 
2772 		if (c == START_EXPAND)
2773 			expanding = 1;
2774 		else if (c == DONE_EXPAND)
2775 			expanding = 0;
2776 		else
2777 			break;
2778 	}
2779 	return (c);
2780 }
2781 
2782 int
2783 lgetc(int quotec)
2784 {
2785 	int		c, next;
2786 
2787 	if (quotec) {
2788 		if ((c = igetc()) == EOF) {
2789 			yyerror("reached end of file while parsing "
2790 			    "quoted string");
2791 			if (file == topfile || popfile() == EOF)
2792 				return (EOF);
2793 			return (quotec);
2794 		}
2795 		return (c);
2796 	}
2797 
2798 	while ((c = igetc()) == '\\') {
2799 		next = igetc();
2800 		if (next != '\n') {
2801 			c = next;
2802 			break;
2803 		}
2804 		yylval.lineno = file->lineno;
2805 		file->lineno++;
2806 	}
2807 
2808 	if (c == EOF) {
2809 		/*
2810 		 * Fake EOL when hit EOF for the first time. This gets line
2811 		 * count right if last line in included file is syntactically
2812 		 * invalid and has no newline.
2813 		 */
2814 		if (file->eof_reached == 0) {
2815 			file->eof_reached = 1;
2816 			return ('\n');
2817 		}
2818 		while (c == EOF) {
2819 			if (file == topfile || popfile() == EOF)
2820 				return (EOF);
2821 			c = igetc();
2822 		}
2823 	}
2824 	return (c);
2825 }
2826 
2827 void
2828 lungetc(int c)
2829 {
2830 	if (c == EOF)
2831 		return;
2832 
2833 	if (file->ungetpos >= file->ungetsize) {
2834 		void *p = reallocarray(file->ungetbuf, file->ungetsize, 2);
2835 		if (p == NULL)
2836 			fatal("%s", __func__);
2837 		file->ungetbuf = p;
2838 		file->ungetsize *= 2;
2839 	}
2840 	file->ungetbuf[file->ungetpos++] = c;
2841 }
2842 
2843 int
2844 findeol(void)
2845 {
2846 	int	c;
2847 
2848 	/* skip to either EOF or the first real EOL */
2849 	while (1) {
2850 		c = lgetc(0);
2851 		if (c == '\n') {
2852 			file->lineno++;
2853 			break;
2854 		}
2855 		if (c == EOF)
2856 			break;
2857 	}
2858 	return (ERROR);
2859 }
2860 
2861 int
2862 yylex(void)
2863 {
2864 	char	 buf[8096];
2865 	char	*p, *val;
2866 	int	 quotec, next, c;
2867 	int	 token;
2868 
2869 top:
2870 	p = buf;
2871 	while ((c = lgetc(0)) == ' ' || c == '\t')
2872 		; /* nothing */
2873 
2874 	yylval.lineno = file->lineno;
2875 	if (c == '#')
2876 		while ((c = lgetc(0)) != '\n' && c != EOF)
2877 			; /* nothing */
2878 	if (c == '$' && !expanding) {
2879 		while (1) {
2880 			if ((c = lgetc(0)) == EOF)
2881 				return (0);
2882 
2883 			if (p + 1 >= buf + sizeof(buf) - 1) {
2884 				yyerror("string too long");
2885 				return (findeol());
2886 			}
2887 			if (isalnum(c) || c == '_') {
2888 				*p++ = c;
2889 				continue;
2890 			}
2891 			*p = '\0';
2892 			lungetc(c);
2893 			break;
2894 		}
2895 		val = symget(buf);
2896 		if (val == NULL) {
2897 			yyerror("macro '%s' not defined", buf);
2898 			return (findeol());
2899 		}
2900 		p = val + strlen(val) - 1;
2901 		lungetc(DONE_EXPAND);
2902 		while (p >= val) {
2903 			lungetc((unsigned char)*p);
2904 			p--;
2905 		}
2906 		lungetc(START_EXPAND);
2907 		goto top;
2908 	}
2909 
2910 	switch (c) {
2911 	case '\'':
2912 	case '"':
2913 		quotec = c;
2914 		while (1) {
2915 			if ((c = lgetc(quotec)) == EOF)
2916 				return (0);
2917 			if (c == '\n') {
2918 				file->lineno++;
2919 				continue;
2920 			} else if (c == '\\') {
2921 				if ((next = lgetc(quotec)) == EOF)
2922 					return (0);
2923 				if (next == quotec || next == ' ' ||
2924 				    next == '\t')
2925 					c = next;
2926 				else if (next == '\n') {
2927 					file->lineno++;
2928 					continue;
2929 				} else
2930 					lungetc(next);
2931 			} else if (c == quotec) {
2932 				*p = '\0';
2933 				break;
2934 			} else if (c == '\0') {
2935 				yyerror("syntax error");
2936 				return (findeol());
2937 			}
2938 			if (p + 1 >= buf + sizeof(buf) - 1) {
2939 				yyerror("string too long");
2940 				return (findeol());
2941 			}
2942 			*p++ = c;
2943 		}
2944 		yylval.v.string = strdup(buf);
2945 		if (yylval.v.string == NULL)
2946 			fatal("%s", __func__);
2947 		return (STRING);
2948 	}
2949 
2950 #define allowed_to_end_number(x) \
2951 	(isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
2952 
2953 	if (c == '-' || isdigit(c)) {
2954 		do {
2955 			*p++ = c;
2956 			if ((size_t)(p-buf) >= sizeof(buf)) {
2957 				yyerror("string too long");
2958 				return (findeol());
2959 			}
2960 		} while ((c = lgetc(0)) != EOF && isdigit(c));
2961 		lungetc(c);
2962 		if (p == buf + 1 && buf[0] == '-')
2963 			goto nodigits;
2964 		if (c == EOF || allowed_to_end_number(c)) {
2965 			const char *errstr = NULL;
2966 
2967 			*p = '\0';
2968 			yylval.v.number = strtonum(buf, LLONG_MIN,
2969 			    LLONG_MAX, &errstr);
2970 			if (errstr) {
2971 				yyerror("\"%s\" invalid number: %s",
2972 				    buf, errstr);
2973 				return (findeol());
2974 			}
2975 			return (NUMBER);
2976 		} else {
2977 nodigits:
2978 			while (p > buf + 1)
2979 				lungetc((unsigned char)*--p);
2980 			c = (unsigned char)*--p;
2981 			if (c == '-')
2982 				return (c);
2983 		}
2984 	}
2985 
2986 	if (c == '=') {
2987 		if ((c = lgetc(0)) != EOF && c == '>')
2988 			return (ARROW);
2989 		lungetc(c);
2990 		c = '=';
2991 	}
2992 
2993 #define allowed_in_string(x) \
2994 	(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
2995 	x != '{' && x != '}' && x != '<' && x != '>' && \
2996 	x != '!' && x != '=' && x != '#' && \
2997 	x != ','))
2998 
2999 	if (isalnum(c) || c == ':' || c == '_') {
3000 		do {
3001 			*p++ = c;
3002 			if ((size_t)(p-buf) >= sizeof(buf)) {
3003 				yyerror("string too long");
3004 				return (findeol());
3005 			}
3006 		} while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
3007 		lungetc(c);
3008 		*p = '\0';
3009 		if ((token = lookup(buf)) == STRING)
3010 			if ((yylval.v.string = strdup(buf)) == NULL)
3011 				fatal("%s", __func__);
3012 		return (token);
3013 	}
3014 	if (c == '\n') {
3015 		yylval.lineno = file->lineno;
3016 		file->lineno++;
3017 	}
3018 	if (c == EOF)
3019 		return (0);
3020 	return (c);
3021 }
3022 
3023 int
3024 check_file_secrecy(int fd, const char *fname)
3025 {
3026 	struct stat	st;
3027 
3028 	if (fstat(fd, &st)) {
3029 		log_warn("warn: cannot stat %s", fname);
3030 		return (-1);
3031 	}
3032 	if (st.st_uid != 0 && st.st_uid != getuid()) {
3033 		log_warnx("warn: %s: owner not root or current user", fname);
3034 		return (-1);
3035 	}
3036 	if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) {
3037 		log_warnx("warn: %s: group/world readable/writeable", fname);
3038 		return (-1);
3039 	}
3040 	return (0);
3041 }
3042 
3043 struct file *
3044 pushfile(const char *name, int secret)
3045 {
3046 	struct file	*nfile;
3047 
3048 	if ((nfile = calloc(1, sizeof(struct file))) == NULL) {
3049 		log_warn("%s", __func__);
3050 		return (NULL);
3051 	}
3052 	if ((nfile->name = strdup(name)) == NULL) {
3053 		log_warn("%s", __func__);
3054 		free(nfile);
3055 		return (NULL);
3056 	}
3057 	if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
3058 		log_warn("%s: %s", __func__, nfile->name);
3059 		free(nfile->name);
3060 		free(nfile);
3061 		return (NULL);
3062 	} else if (secret &&
3063 	    check_file_secrecy(fileno(nfile->stream), nfile->name)) {
3064 		fclose(nfile->stream);
3065 		free(nfile->name);
3066 		free(nfile);
3067 		return (NULL);
3068 	}
3069 	nfile->lineno = TAILQ_EMPTY(&files) ? 1 : 0;
3070 	nfile->ungetsize = 16;
3071 	nfile->ungetbuf = malloc(nfile->ungetsize);
3072 	if (nfile->ungetbuf == NULL) {
3073 		log_warn("%s", __func__);
3074 		fclose(nfile->stream);
3075 		free(nfile->name);
3076 		free(nfile);
3077 		return (NULL);
3078 	}
3079 	TAILQ_INSERT_TAIL(&files, nfile, entry);
3080 	return (nfile);
3081 }
3082 
3083 int
3084 popfile(void)
3085 {
3086 	struct file	*prev;
3087 
3088 	if ((prev = TAILQ_PREV(file, files, entry)) != NULL)
3089 		prev->errors += file->errors;
3090 
3091 	TAILQ_REMOVE(&files, file, entry);
3092 	fclose(file->stream);
3093 	free(file->name);
3094 	free(file->ungetbuf);
3095 	free(file);
3096 	file = prev;
3097 	return (file ? 0 : EOF);
3098 }
3099 
3100 int
3101 parse_config(struct smtpd *x_conf, const char *filename, int opts)
3102 {
3103 	struct sym     *sym, *next;
3104 
3105 	conf = x_conf;
3106 	errors = 0;
3107 
3108 	if ((file = pushfile(filename, 0)) == NULL) {
3109 		purge_config(PURGE_EVERYTHING);
3110 		return (-1);
3111 	}
3112 	topfile = file;
3113 
3114 	/*
3115 	 * parse configuration
3116 	 */
3117 	setservent(1);
3118 	yyparse();
3119 	errors = file->errors;
3120 	popfile();
3121 	endservent();
3122 
3123 	/* If the socket listener was not configured, create a default one. */
3124 	if (!conf->sc_sock_listener) {
3125 		memset(&listen_opts, 0, sizeof listen_opts);
3126 		create_sock_listener(&listen_opts);
3127 	}
3128 
3129 	/* Free macros and check which have not been used. */
3130 	TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) {
3131 		if ((conf->sc_opts & SMTPD_OPT_VERBOSE) && !sym->used)
3132 			fprintf(stderr, "warning: macro '%s' not "
3133 			    "used\n", sym->nam);
3134 		if (!sym->persist) {
3135 			free(sym->nam);
3136 			free(sym->val);
3137 			TAILQ_REMOVE(&symhead, sym, entry);
3138 			free(sym);
3139 		}
3140 	}
3141 
3142 	if (TAILQ_EMPTY(conf->sc_rules)) {
3143 		log_warnx("warn: no rules, nothing to do");
3144 		errors++;
3145 	}
3146 
3147 	if (errors) {
3148 		purge_config(PURGE_EVERYTHING);
3149 		return (-1);
3150 	}
3151 
3152 	return (0);
3153 }
3154 
3155 int
3156 symset(const char *nam, const char *val, int persist)
3157 {
3158 	struct sym	*sym;
3159 
3160 	TAILQ_FOREACH(sym, &symhead, entry) {
3161 		if (strcmp(nam, sym->nam) == 0)
3162 			break;
3163 	}
3164 
3165 	if (sym != NULL) {
3166 		if (sym->persist == 1)
3167 			return (0);
3168 		else {
3169 			free(sym->nam);
3170 			free(sym->val);
3171 			TAILQ_REMOVE(&symhead, sym, entry);
3172 			free(sym);
3173 		}
3174 	}
3175 	if ((sym = calloc(1, sizeof(*sym))) == NULL)
3176 		return (-1);
3177 
3178 	sym->nam = strdup(nam);
3179 	if (sym->nam == NULL) {
3180 		free(sym);
3181 		return (-1);
3182 	}
3183 	sym->val = strdup(val);
3184 	if (sym->val == NULL) {
3185 		free(sym->nam);
3186 		free(sym);
3187 		return (-1);
3188 	}
3189 	sym->used = 0;
3190 	sym->persist = persist;
3191 	TAILQ_INSERT_TAIL(&symhead, sym, entry);
3192 	return (0);
3193 }
3194 
3195 int
3196 cmdline_symset(char *s)
3197 {
3198 	char	*sym, *val;
3199 	int	ret;
3200 
3201 	if ((val = strrchr(s, '=')) == NULL)
3202 		return (-1);
3203 	sym = strndup(s, val - s);
3204 	if (sym == NULL)
3205 		fatalx("%s: strndup", __func__);
3206 	ret = symset(sym, val + 1, 1);
3207 	free(sym);
3208 
3209 	return (ret);
3210 }
3211 
3212 char *
3213 symget(const char *nam)
3214 {
3215 	struct sym	*sym;
3216 
3217 	TAILQ_FOREACH(sym, &symhead, entry) {
3218 		if (strcmp(nam, sym->nam) == 0) {
3219 			sym->used = 1;
3220 			return (sym->val);
3221 		}
3222 	}
3223 	return (NULL);
3224 }
3225 
3226 static void
3227 create_sock_listener(struct listen_opts *lo)
3228 {
3229 	struct listener *l = xcalloc(1, sizeof(*l));
3230 	lo->hostname = conf->sc_hostname;
3231 	l->ss.ss_family = AF_LOCAL;
3232 	l->ss.ss_len = sizeof(struct sockaddr *);
3233 	l->local = 1;
3234 	conf->sc_sock_listener = l;
3235 	config_listener(l, lo);
3236 }
3237 
3238 static void
3239 create_if_listener(struct listen_opts *lo)
3240 {
3241 	uint16_t	flags;
3242 
3243 	if (lo->port != 0 && lo->ssl == F_SSL)
3244 		fatalx("invalid listen option: tls/smtps on same port");
3245 
3246 	if (lo->auth != 0 && !lo->ssl)
3247 		fatalx("invalid listen option: auth requires tls/smtps");
3248 
3249 	if (lo->pkicount && !lo->ssl)
3250 		fatalx("invalid listen option: pki requires tls/smtps");
3251 	if (lo->pkicount == 0 && lo->ssl)
3252 		fatalx("invalid listen option: pki required for tls/smtps");
3253 
3254 	flags = lo->flags;
3255 
3256 	if (lo->port) {
3257 		lo->flags = lo->ssl|lo->auth|flags;
3258 		lo->port = htons(lo->port);
3259 	}
3260 	else {
3261 		if (lo->ssl & F_SMTPS) {
3262 			lo->port = htons(465);
3263 			lo->flags = F_SMTPS|lo->auth|flags;
3264 		}
3265 
3266 		if (!lo->ssl || (lo->ssl & F_STARTTLS)) {
3267 			lo->port = htons(25);
3268 			lo->flags = lo->auth|flags;
3269 			if (lo->ssl & F_STARTTLS)
3270 				lo->flags |= F_STARTTLS;
3271 		}
3272 	}
3273 
3274 	if (interface(lo))
3275 		return;
3276 	if (host_v4(lo))
3277 		return;
3278 	if (host_v6(lo))
3279 		return;
3280 	if (host_dns(lo))
3281 		return;
3282 
3283 	fatalx("invalid virtual ip or interface: %s", lo->ifx);
3284 }
3285 
3286 static void
3287 config_listener(struct listener *h,  struct listen_opts *lo)
3288 {
3289 	int i;
3290 
3291 	h->fd = -1;
3292 	h->port = lo->port;
3293 	h->flags = lo->flags;
3294 
3295 	if (lo->hostname == NULL)
3296 		lo->hostname = conf->sc_hostname;
3297 
3298 	if (lo->options & LO_FILTER) {
3299 		h->flags |= F_FILTERED;
3300 		(void)strlcpy(h->filter_name,
3301 		    lo->filtername,
3302 		    sizeof(h->filter_name));
3303 	}
3304 
3305 	if (lo->authtable != NULL)
3306 		(void)strlcpy(h->authtable, lo->authtable->t_name, sizeof(h->authtable));
3307 
3308 	h->pkicount = lo->pkicount;
3309 	if (h->pkicount) {
3310 		h->pki = calloc(h->pkicount, sizeof(*h->pki));
3311 		if (h->pki == NULL)
3312 			fatal("calloc");
3313 	}
3314 	for (i = 0; i < lo->pkicount; i++) {
3315 		h->pki[i] = dict_get(conf->sc_pki_dict, lo->pki[i]);
3316 		if (h->pki[i] == NULL) {
3317 			log_warnx("pki name not found: %s", lo->pki[i]);
3318 			fatalx(NULL);
3319 		}
3320 	}
3321 
3322 	if (lo->tls_ciphers != NULL &&
3323 	    (h->tls_ciphers = strdup(lo->tls_ciphers)) == NULL) {
3324 		fatal("strdup");
3325 	}
3326 
3327 	if (lo->tls_protocols != NULL &&
3328 	    (h->tls_protocols = strdup(lo->tls_protocols)) == NULL) {
3329 		fatal("strdup");
3330 	}
3331 
3332 	if (lo->ca != NULL) {
3333 		if (!lowercase(h->ca_name, lo->ca, sizeof(h->ca_name))) {
3334 			log_warnx("ca name too long: %s", lo->ca);
3335 			fatalx(NULL);
3336 		}
3337 		if (dict_get(conf->sc_ca_dict, h->ca_name) == NULL) {
3338 			log_warnx("ca name not found: %s", lo->ca);
3339 			fatalx(NULL);
3340 		}
3341 	}
3342 	if (lo->tag != NULL)
3343 		(void)strlcpy(h->tag, lo->tag, sizeof(h->tag));
3344 
3345 	(void)strlcpy(h->hostname, lo->hostname, sizeof(h->hostname));
3346 	if (lo->hostnametable)
3347 		(void)strlcpy(h->hostnametable, lo->hostnametable->t_name, sizeof(h->hostnametable));
3348 	if (lo->sendertable) {
3349 		(void)strlcpy(h->sendertable, lo->sendertable->t_name, sizeof(h->sendertable));
3350 		if (lo->options & LO_MASQUERADE)
3351 			h->flags |= F_MASQUERADE;
3352 	}
3353 
3354 	if (lo->ssl & F_TLS_VERIFY)
3355 		h->flags |= F_TLS_VERIFY;
3356 
3357 	if (lo->ssl & F_STARTTLS_REQUIRE)
3358 		h->flags |= F_STARTTLS_REQUIRE;
3359 
3360 	if (h != conf->sc_sock_listener)
3361 		TAILQ_INSERT_TAIL(conf->sc_listeners, h, entry);
3362 }
3363 
3364 static int
3365 host_v4(struct listen_opts *lo)
3366 {
3367 	struct in_addr		 ina;
3368 	struct sockaddr_in	*sain;
3369 	struct listener		*h;
3370 
3371 	if (lo->family != AF_UNSPEC && lo->family != AF_INET)
3372 		return (0);
3373 
3374 	memset(&ina, 0, sizeof(ina));
3375 	if (inet_pton(AF_INET, lo->ifx, &ina) != 1)
3376 		return (0);
3377 
3378 	h = xcalloc(1, sizeof(*h));
3379 	sain = (struct sockaddr_in *)&h->ss;
3380 	sain->sin_len = sizeof(struct sockaddr_in);
3381 	sain->sin_family = AF_INET;
3382 	sain->sin_addr.s_addr = ina.s_addr;
3383 	sain->sin_port = lo->port;
3384 
3385 	if (sain->sin_addr.s_addr == htonl(INADDR_LOOPBACK))
3386 		h->local = 1;
3387 	config_listener(h,  lo);
3388 
3389 	return (1);
3390 }
3391 
3392 static int
3393 host_v6(struct listen_opts *lo)
3394 {
3395 	struct in6_addr		 ina6;
3396 	struct sockaddr_in6	*sin6;
3397 	struct listener		*h;
3398 
3399 	if (lo->family != AF_UNSPEC && lo->family != AF_INET6)
3400 		return (0);
3401 
3402 	memset(&ina6, 0, sizeof(ina6));
3403 	if (inet_pton(AF_INET6, lo->ifx, &ina6) != 1)
3404 		return (0);
3405 
3406 	h = xcalloc(1, sizeof(*h));
3407 	sin6 = (struct sockaddr_in6 *)&h->ss;
3408 	sin6->sin6_len = sizeof(struct sockaddr_in6);
3409 	sin6->sin6_family = AF_INET6;
3410 	sin6->sin6_port = lo->port;
3411 	memcpy(&sin6->sin6_addr, &ina6, sizeof(ina6));
3412 
3413 	if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr))
3414 		h->local = 1;
3415 	config_listener(h,  lo);
3416 
3417 	return (1);
3418 }
3419 
3420 static int
3421 host_dns(struct listen_opts *lo)
3422 {
3423 	struct addrinfo		 hints, *res0, *res;
3424 	int			 error, cnt = 0;
3425 	struct sockaddr_in	*sain;
3426 	struct sockaddr_in6	*sin6;
3427 	struct listener		*h;
3428 
3429 	memset(&hints, 0, sizeof(hints));
3430 	hints.ai_family = lo->family;
3431 	hints.ai_socktype = SOCK_STREAM;
3432 	hints.ai_flags = AI_ADDRCONFIG;
3433 	error = getaddrinfo(lo->ifx, NULL, &hints, &res0);
3434 	if (error == EAI_AGAIN || error == EAI_NODATA || error == EAI_NONAME)
3435 		return (0);
3436 	if (error) {
3437 		log_warnx("warn: host_dns: could not parse \"%s\": %s", lo->ifx,
3438 		    gai_strerror(error));
3439 		return (-1);
3440 	}
3441 
3442 	for (res = res0; res; res = res->ai_next) {
3443 		if (res->ai_family != AF_INET &&
3444 		    res->ai_family != AF_INET6)
3445 			continue;
3446 		h = xcalloc(1, sizeof(*h));
3447 
3448 		h->ss.ss_family = res->ai_family;
3449 		if (res->ai_family == AF_INET) {
3450 			sain = (struct sockaddr_in *)&h->ss;
3451 			sain->sin_len = sizeof(struct sockaddr_in);
3452 			sain->sin_addr.s_addr = ((struct sockaddr_in *)
3453 			    res->ai_addr)->sin_addr.s_addr;
3454 			sain->sin_port = lo->port;
3455 			if (sain->sin_addr.s_addr == htonl(INADDR_LOOPBACK))
3456 				h->local = 1;
3457 		} else {
3458 			sin6 = (struct sockaddr_in6 *)&h->ss;
3459 			sin6->sin6_len = sizeof(struct sockaddr_in6);
3460 			memcpy(&sin6->sin6_addr, &((struct sockaddr_in6 *)
3461 			    res->ai_addr)->sin6_addr, sizeof(struct in6_addr));
3462 			sin6->sin6_port = lo->port;
3463 			if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr))
3464 				h->local = 1;
3465 		}
3466 
3467 		config_listener(h, lo);
3468 
3469 		cnt++;
3470 	}
3471 
3472 	freeaddrinfo(res0);
3473 	return (cnt);
3474 }
3475 
3476 static int
3477 interface(struct listen_opts *lo)
3478 {
3479 	struct ifaddrs *ifap, *p;
3480 	struct sockaddr_in	*sain;
3481 	struct sockaddr_in6	*sin6;
3482 	struct listener		*h;
3483 	int			ret = 0;
3484 
3485 	if (getifaddrs(&ifap) == -1)
3486 		fatal("getifaddrs");
3487 
3488 	for (p = ifap; p != NULL; p = p->ifa_next) {
3489 		if (p->ifa_addr == NULL)
3490 			continue;
3491 		if (strcmp(p->ifa_name, lo->ifx) != 0 &&
3492 		    !is_if_in_group(p->ifa_name, lo->ifx))
3493 			continue;
3494 		if (lo->family != AF_UNSPEC && lo->family != p->ifa_addr->sa_family)
3495 			continue;
3496 
3497 		h = xcalloc(1, sizeof(*h));
3498 
3499 		switch (p->ifa_addr->sa_family) {
3500 		case AF_INET:
3501 			sain = (struct sockaddr_in *)&h->ss;
3502 			*sain = *(struct sockaddr_in *)p->ifa_addr;
3503 			sain->sin_len = sizeof(struct sockaddr_in);
3504 			sain->sin_port = lo->port;
3505 			if (sain->sin_addr.s_addr == htonl(INADDR_LOOPBACK))
3506 				h->local = 1;
3507 			break;
3508 
3509 		case AF_INET6:
3510 			sin6 = (struct sockaddr_in6 *)&h->ss;
3511 			*sin6 = *(struct sockaddr_in6 *)p->ifa_addr;
3512 			sin6->sin6_len = sizeof(struct sockaddr_in6);
3513 			sin6->sin6_port = lo->port;
3514 #ifdef __KAME__
3515 			if ((IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) ||
3516 			    IN6_IS_ADDR_MC_LINKLOCAL(&sin6->sin6_addr) ||
3517 			    IN6_IS_ADDR_MC_INTFACELOCAL(&sin6->sin6_addr)) &&
3518 			    sin6->sin6_scope_id == 0) {
3519 				sin6->sin6_scope_id = ntohs(
3520 				    *(u_int16_t *)&sin6->sin6_addr.s6_addr[2]);
3521 				sin6->sin6_addr.s6_addr[2] = 0;
3522 				sin6->sin6_addr.s6_addr[3] = 0;
3523 			}
3524 #endif
3525 			if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr))
3526 				h->local = 1;
3527 			break;
3528 
3529 		default:
3530 			free(h);
3531 			continue;
3532 		}
3533 
3534 		config_listener(h, lo);
3535 		ret = 1;
3536 	}
3537 
3538 	freeifaddrs(ifap);
3539 
3540 	return ret;
3541 }
3542 
3543 int
3544 delaytonum(char *str)
3545 {
3546 	unsigned int     factor;
3547 	size_t           len;
3548 	const char      *errstr = NULL;
3549 	int              delay;
3550 
3551 	/* we need at least 1 digit and 1 unit */
3552 	len = strlen(str);
3553 	if (len < 2)
3554 		goto bad;
3555 
3556 	switch(str[len - 1]) {
3557 
3558 	case 's':
3559 		factor = 1;
3560 		break;
3561 
3562 	case 'm':
3563 		factor = 60;
3564 		break;
3565 
3566 	case 'h':
3567 		factor = 60 * 60;
3568 		break;
3569 
3570 	case 'd':
3571 		factor = 24 * 60 * 60;
3572 		break;
3573 
3574 	default:
3575 		goto bad;
3576 	}
3577 
3578 	str[len - 1] = '\0';
3579 	delay = strtonum(str, 1, INT_MAX / factor, &errstr);
3580 	if (errstr)
3581 		goto bad;
3582 
3583 	return (delay * factor);
3584 
3585 bad:
3586 	return (-1);
3587 }
3588 
3589 int
3590 is_if_in_group(const char *ifname, const char *groupname)
3591 {
3592         unsigned int		 len;
3593         struct ifgroupreq        ifgr;
3594         struct ifg_req          *ifg;
3595 	int			 s;
3596 	int			 ret = 0;
3597 
3598 	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
3599 		fatal("socket");
3600 
3601         memset(&ifgr, 0, sizeof(ifgr));
3602         if (strlcpy(ifgr.ifgr_name, ifname, IFNAMSIZ) >= IFNAMSIZ)
3603 		fatalx("interface name too large");
3604 
3605         if (ioctl(s, SIOCGIFGROUP, (caddr_t)&ifgr) == -1) {
3606                 if (errno == EINVAL || errno == ENOTTY)
3607 			goto end;
3608 		fatal("SIOCGIFGROUP");
3609         }
3610 
3611         len = ifgr.ifgr_len;
3612         ifgr.ifgr_groups = xcalloc(len/sizeof(struct ifg_req),
3613 		sizeof(struct ifg_req));
3614         if (ioctl(s, SIOCGIFGROUP, (caddr_t)&ifgr) == -1)
3615                 fatal("SIOCGIFGROUP");
3616 
3617         ifg = ifgr.ifgr_groups;
3618         for (; ifg && len >= sizeof(struct ifg_req); ifg++) {
3619                 len -= sizeof(struct ifg_req);
3620 		if (strcmp(ifg->ifgrq_group, groupname) == 0) {
3621 			ret = 1;
3622 			break;
3623 		}
3624         }
3625         free(ifgr.ifgr_groups);
3626 
3627 end:
3628 	close(s);
3629 	return ret;
3630 }
3631 
3632 static int
3633 config_lo_mask_source(struct listen_opts *lo) {
3634 	if (lo->options & LO_MASKSOURCE) {
3635 		yyerror("mask-source already specified");
3636 		return -1;
3637 	}
3638 	lo->options |= LO_MASKSOURCE;
3639 	lo->flags |= F_MASK_SOURCE;
3640 
3641 	return 0;
3642 }
3643 
3644