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