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