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