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