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