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