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