diff options
Diffstat (limited to 'src/postscreen/postscreen.c')
-rw-r--r-- | src/postscreen/postscreen.c | 1252 |
1 files changed, 1252 insertions, 0 deletions
diff --git a/src/postscreen/postscreen.c b/src/postscreen/postscreen.c new file mode 100644 index 0000000..67716cb --- /dev/null +++ b/src/postscreen/postscreen.c @@ -0,0 +1,1252 @@ +/*++ +/* NAME +/* postscreen 8 +/* SUMMARY +/* Postfix zombie blocker +/* SYNOPSIS +/* \fBpostscreen\fR [generic Postfix daemon options] +/* DESCRIPTION +/* The Postfix \fBpostscreen\fR(8) server provides additional +/* protection against mail server overload. One \fBpostscreen\fR(8) +/* process handles multiple inbound SMTP connections, and decides +/* which clients may talk to a Postfix SMTP server process. +/* By keeping spambots away, \fBpostscreen\fR(8) leaves more +/* SMTP server processes available for legitimate clients, and +/* delays the onset of server overload conditions. +/* +/* This program should not be used on SMTP ports that receive +/* mail from end-user clients (MUAs). In a typical deployment, +/* \fBpostscreen\fR(8) handles the MX service on TCP port 25, and +/* \fBsmtpd\fR(8) receives mail from MUAs on the \fBsubmission\fR +/* service (TCP port 587) which requires client authentication. +/* Alternatively, a site could set up a dedicated, non-postscreen, +/* "port 25" server that provides \fBsubmission\fR service and +/* client authentication, but no MX service. +/* +/* \fBpostscreen\fR(8) maintains a temporary allowlist for +/* clients that have passed a number of tests. When an SMTP +/* client IP address is allowlisted, \fBpostscreen\fR(8) hands +/* off the connection immediately to a Postfix SMTP server +/* process. This minimizes the overhead for legitimate mail. +/* +/* By default, \fBpostscreen\fR(8) logs statistics and hands +/* off each connection to a Postfix SMTP server process, while +/* excluding clients in mynetworks from all tests (primarily, +/* to avoid problems with non-standard SMTP implementations +/* in network appliances). This default mode blocks no clients, +/* and is useful for non-destructive testing. +/* +/* In a typical production setting, \fBpostscreen\fR(8) is +/* configured to reject mail from clients that fail one or +/* more tests. \fBpostscreen\fR(8) logs rejected mail with the +/* client address, helo, sender and recipient information. +/* +/* \fBpostscreen\fR(8) is not an SMTP proxy; this is intentional. +/* The purpose is to keep spambots away from Postfix SMTP +/* server processes, while minimizing overhead for legitimate +/* traffic. +/* SECURITY +/* .ad +/* .fi +/* The \fBpostscreen\fR(8) server is moderately security-sensitive. +/* It talks to untrusted clients on the network. The process +/* can be run chrooted at fixed low privilege. +/* STANDARDS +/* RFC 821 (SMTP protocol) +/* RFC 1123 (Host requirements) +/* RFC 1652 (8bit-MIME transport) +/* RFC 1869 (SMTP service extensions) +/* RFC 1870 (Message Size Declaration) +/* RFC 1985 (ETRN command) +/* RFC 2034 (SMTP Enhanced Status Codes) +/* RFC 2821 (SMTP protocol) +/* Not: RFC 2920 (SMTP Pipelining) +/* RFC 3030 (CHUNKING without BINARYMIME) +/* RFC 3207 (STARTTLS command) +/* RFC 3461 (SMTP DSN Extension) +/* RFC 3463 (Enhanced Status Codes) +/* RFC 5321 (SMTP protocol, including multi-line 220 banners) +/* DIAGNOSTICS +/* Problems and transactions are logged to \fBsyslogd\fR(8) +/* or \fBpostlogd\fR(8). +/* BUGS +/* The \fBpostscreen\fR(8) built-in SMTP protocol engine +/* currently does not announce support for AUTH, XCLIENT or +/* XFORWARD. +/* If you need to make these services available +/* on port 25, then do not enable the optional "after 220 +/* server greeting" tests. +/* +/* The optional "after 220 server greeting" tests may result in +/* unexpected delivery delays from senders that retry email delivery +/* from a different IP address. Reason: after passing these tests a +/* new client must disconnect, and reconnect from the same IP +/* address before it can deliver mail. See POSTSCREEN_README, section +/* "Tests after the 220 SMTP server greeting", for a discussion. +/* CONFIGURATION PARAMETERS +/* .ad +/* .fi +/* Changes to main.cf are not picked up automatically, as +/* \fBpostscreen\fR(8) processes may run for several hours. +/* Use the command "postfix reload" after a configuration +/* change. +/* +/* The text below provides only a parameter summary. See +/* \fBpostconf\fR(5) for more details including examples. +/* +/* NOTE: Some \fBpostscreen\fR(8) parameters implement +/* stress-dependent behavior. This is supported only when the +/* default parameter value is stress-dependent (that is, it +/* looks like ${stress?{X}:{Y}}, or it is the $\fIname\fR +/* of an smtpd parameter with a stress-dependent default). +/* Other parameters always evaluate as if the \fBstress\fR +/* parameter value is the empty string. +/* COMPATIBILITY CONTROLS +/* .ad +/* .fi +/* .IP "\fBpostscreen_command_filter ($smtpd_command_filter)\fR" +/* A mechanism to transform commands from remote SMTP clients. +/* .IP "\fBpostscreen_discard_ehlo_keyword_address_maps ($smtpd_discard_ehlo_keyword_address_maps)\fR" +/* Lookup tables, indexed by the remote SMTP client address, with +/* case insensitive lists of EHLO keywords (pipelining, starttls, auth, +/* etc.) that the \fBpostscreen\fR(8) server will not send in the EHLO response +/* to a remote SMTP client. +/* .IP "\fBpostscreen_discard_ehlo_keywords ($smtpd_discard_ehlo_keywords)\fR" +/* A case insensitive list of EHLO keywords (pipelining, starttls, +/* auth, etc.) that the \fBpostscreen\fR(8) server will not send in the EHLO +/* response to a remote SMTP client. +/* .PP +/* Available in Postfix version 3.1 and later: +/* .IP "\fBdns_ncache_ttl_fix_enable (no)\fR" +/* Enable a workaround for future libc incompatibility. +/* .PP +/* Available in Postfix version 3.4 and later: +/* .IP "\fBpostscreen_reject_footer_maps ($smtpd_reject_footer_maps)\fR" +/* Optional lookup table for information that is appended after a 4XX +/* or 5XX \fBpostscreen\fR(8) server response. +/* .PP +/* Available in Postfix 3.6 and later: +/* .IP "\fBrespectful_logging (see 'postconf -d' output)\fR" +/* Avoid logging that implies white is better than black. +/* TROUBLE SHOOTING CONTROLS +/* .ad +/* .fi +/* .IP "\fBpostscreen_expansion_filter (see 'postconf -d' output)\fR" +/* List of characters that are permitted in postscreen_reject_footer +/* attribute expansions. +/* .IP "\fBpostscreen_reject_footer ($smtpd_reject_footer)\fR" +/* Optional information that is appended after a 4XX or 5XX +/* \fBpostscreen\fR(8) server +/* response. +/* .IP "\fBsoft_bounce (no)\fR" +/* Safety net to keep mail queued that would otherwise be returned to +/* the sender. +/* BEFORE-POSTSCREEN PROXY AGENT +/* .ad +/* .fi +/* Available in Postfix version 2.10 and later: +/* .IP "\fBpostscreen_upstream_proxy_protocol (empty)\fR" +/* The name of the proxy protocol used by an optional before-postscreen +/* proxy agent. +/* .IP "\fBpostscreen_upstream_proxy_timeout (5s)\fR" +/* The time limit for the proxy protocol specified with the +/* postscreen_upstream_proxy_protocol parameter. +/* PERMANENT ALLOW/DENYLIST TEST +/* .ad +/* .fi +/* This test is executed immediately after a remote SMTP client +/* connects. If a client is permanently allowlisted, the client +/* will be handed off immediately to a Postfix SMTP server +/* process. +/* .IP "\fBpostscreen_access_list (permit_mynetworks)\fR" +/* Permanent allow/denylist for remote SMTP client IP addresses. +/* .IP "\fBpostscreen_blacklist_action (ignore)\fR" +/* Renamed to postscreen_denylist_action in Postfix 3.6. +/* MAIL EXCHANGER POLICY TESTS +/* .ad +/* .fi +/* When \fBpostscreen\fR(8) is configured to monitor all primary +/* and backup MX addresses, it can refuse to allowlist clients +/* that connect to a backup MX address only. For small sites, +/* this requires configuring primary and backup MX addresses +/* on the same MTA. Larger sites would have to share the +/* \fBpostscreen\fR(8) cache between primary and backup MTAs, +/* which would introduce a common point of failure. +/* .IP "\fBpostscreen_whitelist_interfaces (static:all)\fR" +/* Renamed to postscreen_allowlist_interfaces in Postfix 3.6. +/* BEFORE 220 GREETING TESTS +/* .ad +/* .fi +/* These tests are executed before the remote SMTP client +/* receives the "220 servername" greeting. If no tests remain +/* after the successful completion of this phase, the client +/* will be handed off immediately to a Postfix SMTP server +/* process. +/* .IP "\fBdnsblog_service_name (dnsblog)\fR" +/* The name of the \fBdnsblog\fR(8) service entry in master.cf. +/* .IP "\fBpostscreen_dnsbl_action (ignore)\fR" +/* The action that \fBpostscreen\fR(8) takes when a remote SMTP client's combined +/* DNSBL score is equal to or greater than a threshold (as defined +/* with the postscreen_dnsbl_sites and postscreen_dnsbl_threshold +/* parameters). +/* .IP "\fBpostscreen_dnsbl_reply_map (empty)\fR" +/* A mapping from actual DNSBL domain name which includes a secret +/* password, to the DNSBL domain name that postscreen will reply with +/* when it rejects mail. +/* .IP "\fBpostscreen_dnsbl_sites (empty)\fR" +/* Optional list of DNS allow/denylist domains, filters and weight +/* factors. +/* .IP "\fBpostscreen_dnsbl_threshold (1)\fR" +/* The inclusive lower bound for blocking a remote SMTP client, based on +/* its combined DNSBL score as defined with the postscreen_dnsbl_sites +/* parameter. +/* .IP "\fBpostscreen_greet_action (ignore)\fR" +/* The action that \fBpostscreen\fR(8) takes when a remote SMTP client speaks +/* before its turn within the time specified with the postscreen_greet_wait +/* parameter. +/* .IP "\fBpostscreen_greet_banner ($smtpd_banner)\fR" +/* The \fItext\fR in the optional "220-\fItext\fR..." server +/* response that +/* \fBpostscreen\fR(8) sends ahead of the real Postfix SMTP server's "220 +/* text..." response, in an attempt to confuse bad SMTP clients so +/* that they speak before their turn (pre-greet). +/* .IP "\fBpostscreen_greet_wait (normal: 6s, overload: 2s)\fR" +/* The amount of time that \fBpostscreen\fR(8) will wait for an SMTP +/* client to send a command before its turn, and for DNS blocklist +/* lookup results to arrive (default: up to 2 seconds under stress, +/* up to 6 seconds otherwise). +/* .IP "\fBsmtpd_service_name (smtpd)\fR" +/* The internal service that \fBpostscreen\fR(8) hands off allowed +/* connections to. +/* .PP +/* Available in Postfix version 2.11 and later: +/* .IP "\fBpostscreen_dnsbl_whitelist_threshold (0)\fR" +/* Renamed to postscreen_dnsbl_allowlist_threshold in Postfix 3.6. +/* .PP +/* Available in Postfix version 3.0 and later: +/* .IP "\fBpostscreen_dnsbl_timeout (10s)\fR" +/* The time limit for DNSBL or DNSWL lookups. +/* .PP +/* Available in Postfix version 3.6 and later: +/* .IP "\fBpostscreen_denylist_action (ignore)\fR" +/* The action that \fBpostscreen\fR(8) takes when a remote SMTP client is +/* permanently denylisted with the postscreen_access_list parameter. +/* .IP "\fBpostscreen_allowlist_interfaces (static:all)\fR" +/* A list of local \fBpostscreen\fR(8) server IP addresses where a +/* non-allowlisted remote SMTP client can obtain \fBpostscreen\fR(8)'s temporary +/* allowlist status. +/* .IP "\fBpostscreen_dnsbl_allowlist_threshold (0)\fR" +/* Allow a remote SMTP client to skip "before" and "after 220 +/* greeting" protocol tests, based on its combined DNSBL score as +/* defined with the postscreen_dnsbl_sites parameter. +/* AFTER 220 GREETING TESTS +/* .ad +/* .fi +/* These tests are executed after the remote SMTP client +/* receives the "220 servername" greeting. If a client passes +/* all tests during this phase, it will receive a 4XX response +/* to all RCPT TO commands. After the client reconnects, it +/* will be allowed to talk directly to a Postfix SMTP server +/* process. +/* .IP "\fBpostscreen_bare_newline_action (ignore)\fR" +/* The action that \fBpostscreen\fR(8) takes when a remote SMTP client sends +/* a bare newline character, that is, a newline not preceded by carriage +/* return. +/* .IP "\fBpostscreen_bare_newline_enable (no)\fR" +/* Enable "bare newline" SMTP protocol tests in the \fBpostscreen\fR(8) +/* server. +/* .IP "\fBpostscreen_disable_vrfy_command ($disable_vrfy_command)\fR" +/* Disable the SMTP VRFY command in the \fBpostscreen\fR(8) daemon. +/* .IP "\fBpostscreen_forbidden_commands ($smtpd_forbidden_commands)\fR" +/* List of commands that the \fBpostscreen\fR(8) server considers in +/* violation of the SMTP protocol. +/* .IP "\fBpostscreen_helo_required ($smtpd_helo_required)\fR" +/* Require that a remote SMTP client sends HELO or EHLO before +/* commencing a MAIL transaction. +/* .IP "\fBpostscreen_non_smtp_command_action (drop)\fR" +/* The action that \fBpostscreen\fR(8) takes when a remote SMTP client sends +/* non-SMTP commands as specified with the postscreen_forbidden_commands +/* parameter. +/* .IP "\fBpostscreen_non_smtp_command_enable (no)\fR" +/* Enable "non-SMTP command" tests in the \fBpostscreen\fR(8) server. +/* .IP "\fBpostscreen_pipelining_action (enforce)\fR" +/* The action that \fBpostscreen\fR(8) takes when a remote SMTP client +/* sends +/* multiple commands instead of sending one command and waiting for +/* the server to respond. +/* .IP "\fBpostscreen_pipelining_enable (no)\fR" +/* Enable "pipelining" SMTP protocol tests in the \fBpostscreen\fR(8) +/* server. +/* CACHE CONTROLS +/* .ad +/* .fi +/* .IP "\fBpostscreen_cache_cleanup_interval (12h)\fR" +/* The amount of time between \fBpostscreen\fR(8) cache cleanup runs. +/* .IP "\fBpostscreen_cache_map (btree:$data_directory/postscreen_cache)\fR" +/* Persistent storage for the \fBpostscreen\fR(8) server decisions. +/* .IP "\fBpostscreen_cache_retention_time (7d)\fR" +/* The amount of time that \fBpostscreen\fR(8) will cache an expired +/* temporary allowlist entry before it is removed. +/* .IP "\fBpostscreen_bare_newline_ttl (30d)\fR" +/* The amount of time that \fBpostscreen\fR(8) will use the result from +/* a successful "bare newline" SMTP protocol test. +/* .IP "\fBpostscreen_dnsbl_max_ttl (${postscreen_dnsbl_ttl?{$postscreen_dnsbl_ttl}:{1}}h)\fR" +/* The maximum amount of time that \fBpostscreen\fR(8) will use the +/* result from a successful DNS-based reputation test before a +/* client IP address is required to pass that test again. +/* .IP "\fBpostscreen_dnsbl_min_ttl (60s)\fR" +/* The minimum amount of time that \fBpostscreen\fR(8) will use the +/* result from a successful DNS-based reputation test before a +/* client IP address is required to pass that test again. +/* .IP "\fBpostscreen_greet_ttl (1d)\fR" +/* The amount of time that \fBpostscreen\fR(8) will use the result from +/* a successful PREGREET test. +/* .IP "\fBpostscreen_non_smtp_command_ttl (30d)\fR" +/* The amount of time that \fBpostscreen\fR(8) will use the result from +/* a successful "non_smtp_command" SMTP protocol test. +/* .IP "\fBpostscreen_pipelining_ttl (30d)\fR" +/* The amount of time that \fBpostscreen\fR(8) will use the result from +/* a successful "pipelining" SMTP protocol test. +/* RESOURCE CONTROLS +/* .ad +/* .fi +/* .IP "\fBline_length_limit (2048)\fR" +/* Upon input, long lines are chopped up into pieces of at most +/* this length; upon delivery, long lines are reconstructed. +/* .IP "\fBpostscreen_client_connection_count_limit ($smtpd_client_connection_count_limit)\fR" +/* How many simultaneous connections any remote SMTP client is +/* allowed to have +/* with the \fBpostscreen\fR(8) daemon. +/* .IP "\fBpostscreen_command_count_limit (20)\fR" +/* The limit on the total number of commands per SMTP session for +/* \fBpostscreen\fR(8)'s built-in SMTP protocol engine. +/* .IP "\fBpostscreen_command_time_limit (normal: 300s, overload: 10s)\fR" +/* The time limit to read an entire command line with \fBpostscreen\fR(8)'s +/* built-in SMTP protocol engine. +/* .IP "\fBpostscreen_post_queue_limit ($default_process_limit)\fR" +/* The number of clients that can be waiting for service from a +/* real Postfix SMTP server process. +/* .IP "\fBpostscreen_pre_queue_limit ($default_process_limit)\fR" +/* The number of non-allowlisted clients that can be waiting for +/* a decision whether they will receive service from a real Postfix +/* SMTP server +/* process. +/* .IP "\fBpostscreen_watchdog_timeout (10s)\fR" +/* How much time a \fBpostscreen\fR(8) process may take to respond to +/* a remote SMTP client command or to perform a cache operation before it +/* is terminated by a built-in watchdog timer. +/* STARTTLS CONTROLS +/* .ad +/* .fi +/* .IP "\fBpostscreen_tls_security_level ($smtpd_tls_security_level)\fR" +/* The SMTP TLS security level for the \fBpostscreen\fR(8) server; when +/* a non-empty value is specified, this overrides the obsolete parameters +/* postscreen_use_tls and postscreen_enforce_tls. +/* .IP "\fBtlsproxy_service_name (tlsproxy)\fR" +/* The name of the \fBtlsproxy\fR(8) service entry in master.cf. +/* OBSOLETE STARTTLS SUPPORT CONTROLS +/* .ad +/* .fi +/* These parameters are supported for compatibility with +/* \fBsmtpd\fR(8) legacy parameters. +/* .IP "\fBpostscreen_use_tls ($smtpd_use_tls)\fR" +/* Opportunistic TLS: announce STARTTLS support to remote SMTP clients, +/* but do not require that clients use TLS encryption. +/* .IP "\fBpostscreen_enforce_tls ($smtpd_enforce_tls)\fR" +/* Mandatory TLS: announce STARTTLS support to remote SMTP clients, and +/* require that clients use TLS encryption. +/* MISCELLANEOUS CONTROLS +/* .ad +/* .fi +/* .IP "\fBconfig_directory (see 'postconf -d' output)\fR" +/* The default location of the Postfix main.cf and master.cf +/* configuration files. +/* .IP "\fBdelay_logging_resolution_limit (2)\fR" +/* The maximal number of digits after the decimal point when logging +/* sub-second delay values. +/* .IP "\fBcommand_directory (see 'postconf -d' output)\fR" +/* The location of all postfix administrative commands. +/* .IP "\fBmax_idle (100s)\fR" +/* The maximum amount of time that an idle Postfix daemon process waits +/* for an incoming connection before terminating voluntarily. +/* .IP "\fBprocess_id (read-only)\fR" +/* The process ID of a Postfix command or daemon process. +/* .IP "\fBprocess_name (read-only)\fR" +/* The process name of a Postfix command or daemon process. +/* .IP "\fBsyslog_facility (mail)\fR" +/* The syslog facility of Postfix logging. +/* .IP "\fBsyslog_name (see 'postconf -d' output)\fR" +/* A prefix that is prepended to the process name in syslog +/* records, so that, for example, "smtpd" becomes "prefix/smtpd". +/* .PP +/* Available in Postfix 3.3 and later: +/* .IP "\fBservice_name (read-only)\fR" +/* The master.cf service name of a Postfix daemon process. +/* .PP +/* Available in Postfix 3.5 and later: +/* .IP "\fBinfo_log_address_format (external)\fR" +/* The email address form that will be used in non-debug logging +/* (info, warning, etc.). +/* SEE ALSO +/* smtpd(8), Postfix SMTP server +/* tlsproxy(8), Postfix TLS proxy server +/* dnsblog(8), DNS allow/denylist logger +/* postlogd(8), Postfix logging +/* syslogd(8), system logging +/* README FILES +/* .ad +/* .fi +/* Use "\fBpostconf readme_directory\fR" or "\fBpostconf +/* html_directory\fR" to locate this information. +/* .nf +/* .na +/* POSTSCREEN_README, Postfix Postscreen Howto +/* LICENSE +/* .ad +/* .fi +/* The Secure Mailer license must be distributed with this software. +/* HISTORY +/* .ad +/* .fi +/* This service was introduced with Postfix version 2.8. +/* +/* Many ideas in \fBpostscreen\fR(8) were explored in earlier +/* work by Michael Tokarev, in OpenBSD spamd, and in MailChannels +/* Traffic Control. +/* AUTHOR(S) +/* Wietse Venema +/* IBM T.J. Watson Research +/* P.O. Box 704 +/* Yorktown Heights, NY 10598, USA +/* +/* Wietse Venema +/* Google, Inc. +/* 111 8th Avenue +/* New York, NY 10011, USA +/*--*/ + +/* System library. */ + +#include <sys_defs.h> +#include <sys/stat.h> +#include <stdlib.h> + +/* Utility library. */ + +#include <msg.h> +#include <mymalloc.h> +#include <events.h> +#include <myaddrinfo.h> +#include <dict_cache.h> +#include <set_eugid.h> +#include <vstream.h> +#include <name_code.h> +#include <inet_proto.h> + +/* Global library. */ + +#include <mail_conf.h> +#include <mail_params.h> +#include <mail_version.h> +#include <mail_proto.h> +#include <data_redirect.h> +#include <string_list.h> + +/* Master server protocols. */ + +#include <mail_server.h> + +/* Application-specific. */ + +#include <postscreen.h> + + /* + * Configuration parameters. + */ +char *var_smtpd_service; +char *var_smtpd_banner; +bool var_disable_vrfy_cmd; +bool var_helo_required; + +char *var_smtpd_cmd_filter; +char *var_psc_cmd_filter; + +char *var_smtpd_forbid_cmds; +char *var_psc_forbid_cmds; + +char *var_smtpd_ehlo_dis_words; +char *var_smtpd_ehlo_dis_maps; +char *var_psc_ehlo_dis_words; +char *var_psc_ehlo_dis_maps; + +char *var_smtpd_tls_level; +bool var_smtpd_use_tls; +bool var_smtpd_enforce_tls; +char *var_psc_tls_level; +bool var_psc_use_tls; +bool var_psc_enforce_tls; + +bool var_psc_disable_vrfy; +bool var_psc_helo_required; + +char *var_psc_cache_map; +int var_psc_cache_scan; +int var_psc_cache_ret; +int var_psc_post_queue_limit; +int var_psc_pre_queue_limit; +int var_psc_watchdog; + +char *var_psc_acl; +char *var_psc_dnlist_action; + +char *var_psc_greet_ttl; +int var_psc_greet_wait; + +char *var_psc_pregr_banner; +char *var_psc_pregr_action; +int var_psc_pregr_ttl; + +char *var_psc_dnsbl_sites; +char *var_psc_dnsbl_reply; +int var_psc_dnsbl_thresh; +int var_psc_dnsbl_althresh; +char *var_psc_dnsbl_action; +int var_psc_dnsbl_min_ttl; +int var_psc_dnsbl_max_ttl; +int var_psc_dnsbl_tmout; + +bool var_psc_pipel_enable; +char *var_psc_pipel_action; +int var_psc_pipel_ttl; + +bool var_psc_nsmtp_enable; +char *var_psc_nsmtp_action; +int var_psc_nsmtp_ttl; + +bool var_psc_barlf_enable; +char *var_psc_barlf_action; +int var_psc_barlf_ttl; + +int var_psc_cmd_count; +int var_psc_cmd_time; + +char *var_dnsblog_service; +char *var_tlsproxy_service; + +char *var_smtpd_rej_footer; +char *var_psc_rej_footer; +char *var_psc_rej_ftr_maps; + +int var_smtpd_cconn_limit; +int var_psc_cconn_limit; + +char *var_smtpd_exp_filter; +char *var_psc_exp_filter; + +char *var_psc_allist_if; +char *var_psc_uproxy_proto; +int var_psc_uproxy_tmout; + + /* + * Global variables. + */ +int psc_check_queue_length; /* connections being checked */ +int psc_post_queue_length; /* being sent to real SMTPD */ +DICT_CACHE *psc_cache_map; /* cache table handle */ +VSTRING *psc_temp; /* scratchpad */ +char *psc_smtpd_service_name; /* path to real SMTPD */ +int psc_pregr_action; /* PSC_ACT_DROP/ENFORCE/etc */ +int psc_dnsbl_action; /* PSC_ACT_DROP/ENFORCE/etc */ +int psc_pipel_action; /* PSC_ACT_DROP/ENFORCE/etc */ +int psc_nsmtp_action; /* PSC_ACT_DROP/ENFORCE/etc */ +int psc_barlf_action; /* PSC_ACT_DROP/ENFORCE/etc */ +int psc_min_ttl; /* Update with new tests! */ +STRING_LIST *psc_forbid_cmds; /* CONNECT GET POST */ +int psc_stress_greet_wait; /* stressed greet wait */ +int psc_normal_greet_wait; /* stressed greet wait */ +int psc_stress_cmd_time_limit; /* stressed command limit */ +int psc_normal_cmd_time_limit; /* normal command time limit */ +int psc_stress; /* stress level */ +int psc_lowat_check_queue_length; /* stress low-water mark */ +int psc_hiwat_check_queue_length; /* stress high-water mark */ +DICT *psc_dnsbl_reply; /* DNSBL name mapper */ +HTABLE *psc_client_concurrency; /* per-client concurrency */ + + /* + * Local variables and functions. + */ +static ARGV *psc_acl; /* permanent allow/denylist */ +static int psc_dnlist_action; /* PSC_ACT_DROP/ENFORCE/etc */ +static ADDR_MATCH_LIST *psc_allist_if; /* allowlist interfaces */ + +static void psc_endpt_lookup_done(int, VSTREAM *, + MAI_HOSTADDR_STR *, MAI_SERVPORT_STR *, + MAI_HOSTADDR_STR *, MAI_SERVPORT_STR *); + +/* psc_dump - dump some statistics before exit */ + +static void psc_dump(char *unused_service, char **unused_argv) +{ + + /* + * Dump preliminary cache cleanup statistics when the process commits + * suicide while a cache cleanup run is in progress. We can't currently + * distinguish between "postfix reload" (we should restart) or "maximal + * idle time reached" (we could finish the cache cleanup first). + */ + if (psc_cache_map) { + dict_cache_close(psc_cache_map); + psc_cache_map = 0; + } +} + +/* psc_drain - delayed exit after "postfix reload" */ + +static void psc_drain(char *unused_service, char **unused_argv) +{ + int count; + + /* + * After "postfix reload", complete work-in-progress in the background, + * instead of dropping already-accepted connections on the floor. + * + * Unfortunately we must close all writable tables, so we can't store or + * look up reputation information. The reason is that we don't have any + * multi-writer safety guarantees. We also can't use the single-writer + * proxywrite service, because its latency guarantees are too weak. + * + * All error retry counts shall be limited. Instead of blocking here, we + * could retry failed fork() operations in the event call-back routines, + * but we don't need perfection. The host system is severely overloaded + * and service levels are already way down. + * + * XXX Some Berkeley DB versions break with close-after-fork. Every new + * version is an improvement over its predecessor. + * + * XXX Don't assume that it is OK to share the same LMDB lockfile descriptor + * between different processes. + */ + if (psc_cache_map != 0 /* XXX && psc_cache_map + requires locking */ ) { + dict_cache_close(psc_cache_map); + psc_cache_map = 0; + } + for (count = 0; /* see below */ ; count++) { + if (count >= 5) { + msg_fatal("fork: %m"); + } else if (event_server_drain() != 0) { + msg_warn("fork: %m"); + sleep(1); + continue; + } else { + return; + } + } +} + +/* psc_service - handle new client connection */ + +static void psc_service(VSTREAM *smtp_client_stream, + char *unused_service, + char **unused_argv) +{ + + /* + * For sanity, require that at least one of INET or INET6 is enabled. + * Otherwise, we can't look up interface information, and we can't + * convert names or addresses. + */ + if (inet_proto_info()->ai_family_list[0] == 0) + msg_fatal("all network protocols are disabled (%s = %s)", + VAR_INET_PROTOCOLS, var_inet_protocols); + + /* + * This program handles all incoming connections, so it must not block. + * We use event-driven code for all operations that introduce latency. + * + * Note: instead of using VSTREAM-level timeouts, we enforce limits on the + * total amount of time to receive a complete SMTP command line. + */ + non_blocking(vstream_fileno(smtp_client_stream), NON_BLOCKING); + + /* + * Look up the remote SMTP client address and port. + */ + psc_endpt_lookup(smtp_client_stream, psc_endpt_lookup_done); +} + +/* psc_warn_compat_respectful_logging - compatibility warning */ + +static void psc_warn_compat_respectful_logging(PSC_STATE *state) +{ + msg_info("using backwards-compatible default setting " + VAR_RESPECTFUL_LOGGING "=no for client [%s]:%s", + PSC_CLIENT_ADDR_PORT(state)); + warn_compat_respectful_logging = 0; +} + +/* psc_endpt_lookup_done - endpoint lookup completed */ + +static void psc_endpt_lookup_done(int endpt_status, + VSTREAM *smtp_client_stream, + MAI_HOSTADDR_STR *smtp_client_addr, + MAI_SERVPORT_STR *smtp_client_port, + MAI_HOSTADDR_STR *smtp_server_addr, + MAI_SERVPORT_STR *smtp_server_port) +{ + const char *myname = "psc_endpt_lookup_done"; + PSC_STATE *state; + const char *stamp_str; + int saved_flags; + + /* + * Best effort - if this non-blocking write(2) fails, so be it. + */ + if (endpt_status < 0) { + (void) write(vstream_fileno(smtp_client_stream), + "421 4.3.2 No system resources\r\n", + sizeof("421 4.3.2 No system resources\r\n") - 1); + event_server_disconnect(smtp_client_stream); + return; + } + if (msg_verbose > 1) + msg_info("%s: sq=%d cq=%d connect from [%s]:%s", + myname, psc_post_queue_length, psc_check_queue_length, + smtp_client_addr->buf, smtp_client_port->buf); + + msg_info("CONNECT from [%s]:%s to [%s]:%s", + smtp_client_addr->buf, smtp_client_port->buf, + smtp_server_addr->buf, smtp_server_port->buf); + + /* + * Bundle up all the loose session pieces. This zeroes all flags and time + * stamps. + */ + state = psc_new_session_state(smtp_client_stream, smtp_client_addr->buf, + smtp_client_port->buf, + smtp_server_addr->buf, + smtp_server_port->buf); + + /* + * Reply with 421 when the client has too many open connections. + */ + if (var_psc_cconn_limit > 0 + && state->client_info->concurrency > var_psc_cconn_limit) { + msg_info("NOQUEUE: reject: CONNECT from [%s]:%s: too many connections", + state->smtp_client_addr, state->smtp_client_port); + PSC_DROP_SESSION_STATE(state, + "421 4.7.0 Error: too many connections\r\n"); + return; + } + + /* + * Reply with 421 when we can't forward more connections. + */ + if (var_psc_post_queue_limit > 0 + && psc_post_queue_length >= var_psc_post_queue_limit) { + msg_info("NOQUEUE: reject: CONNECT from [%s]:%s: all server ports busy", + state->smtp_client_addr, state->smtp_client_port); + PSC_DROP_SESSION_STATE(state, + "421 4.3.2 All server ports are busy\r\n"); + return; + } + + /* + * The permanent allow/denylist has highest precedence. + */ + if (psc_acl != 0) { + switch (psc_acl_eval(state, psc_acl, VAR_PSC_ACL)) { + + /* + * Permanently denylisted. + */ + case PSC_ACL_ACT_DENYLIST: + msg_info("%sLISTED [%s]:%s", + var_respectful_logging ? "DENY" : "BLACK", + PSC_CLIENT_ADDR_PORT(state)); + if (warn_compat_respectful_logging) + psc_warn_compat_respectful_logging(state); + PSC_FAIL_SESSION_STATE(state, PSC_STATE_FLAG_DNLIST_FAIL); + switch (psc_dnlist_action) { + case PSC_ACT_DROP: + PSC_DROP_SESSION_STATE(state, + "521 5.3.2 Service currently unavailable\r\n"); + return; + case PSC_ACT_ENFORCE: + PSC_ENFORCE_SESSION_STATE(state, + "550 5.3.2 Service currently unavailable\r\n"); + break; + case PSC_ACT_IGNORE: + PSC_UNFAIL_SESSION_STATE(state, PSC_STATE_FLAG_DNLIST_FAIL); + + /* + * Not: PSC_PASS_SESSION_STATE. Repeat this test the next + * time. + */ + break; + default: + msg_panic("%s: unknown denylist action value %d", + myname, psc_dnlist_action); + } + break; + + /* + * Permanently allowlisted. + */ + case PSC_ACL_ACT_ALLOWLIST: + msg_info("%sLISTED [%s]:%s", + var_respectful_logging ? "ALLOW" : "WHITE", + PSC_CLIENT_ADDR_PORT(state)); + if (warn_compat_respectful_logging) + psc_warn_compat_respectful_logging(state); + psc_conclude(state); + return; + + /* + * Other: dunno (don't know) or error. + */ + default: + break; + } + } + + /* + * The temporary allowlist (i.e. the postscreen cache) has the lowest + * precedence. This cache contains information about the results of prior + * tests. Allowlist the client when all enabled test results are still + * valid. + */ + if ((state->flags & PSC_STATE_MASK_ANY_FAIL) == 0 + && state->client_info->concurrency == 1 + && psc_cache_map != 0 + && (stamp_str = psc_cache_lookup(psc_cache_map, state->smtp_client_addr)) != 0) { + saved_flags = state->flags; + psc_parse_tests(state, stamp_str, event_time()); + state->flags |= saved_flags; + if (msg_verbose) + msg_info("%s: cached + recent flags: %s", + myname, psc_print_state_flags(state->flags, myname)); + if ((state->flags & PSC_STATE_MASK_ANY_TODO_FAIL) == 0) { + msg_info("PASS OLD [%s]:%s", PSC_CLIENT_ADDR_PORT(state)); + psc_conclude(state); + return; + } + } else if (state->client_info->concurrency > 1) { + saved_flags = state->flags; + psc_todo_tests(state, event_time()); + state->flags |= saved_flags; + if (msg_verbose) + msg_info("%s: new + recent flags: %s", + myname, psc_print_state_flags(state->flags, myname)); + } else { + saved_flags = state->flags; + psc_new_tests(state); + state->flags |= saved_flags; + if (msg_verbose) + msg_info("%s: new + recent flags: %s", + myname, psc_print_state_flags(state->flags, myname)); + } + + /* + * Don't allowlist clients that connect to backup MX addresses. Fail + * "closed" on error. + */ + if (addr_match_list_match(psc_allist_if, smtp_server_addr->buf) == 0) { + state->flags |= (PSC_STATE_FLAG_ALLIST_FAIL | PSC_STATE_FLAG_NOFORWARD); + msg_info("%sLIST VETO [%s]:%s", var_respectful_logging ? + "ALLOW" : "WHITE", PSC_CLIENT_ADDR_PORT(state)); + if (warn_compat_respectful_logging) + psc_warn_compat_respectful_logging(state); + } + + /* + * Reply with 421 when we can't analyze more connections. That also means + * no deep protocol tests when the noforward flag is raised. + */ + if (var_psc_pre_queue_limit > 0 + && psc_check_queue_length - psc_post_queue_length + >= var_psc_pre_queue_limit) { + msg_info("reject: connect from [%s]:%s: all screening ports busy", + state->smtp_client_addr, state->smtp_client_port); + PSC_DROP_SESSION_STATE(state, + "421 4.3.2 All screening ports are busy\r\n"); + return; + } + + /* + * If the client has no up-to-date results for some tests, do those tests + * first. Otherwise, skip the tests and hand off the connection. + */ + if (state->flags & PSC_STATE_MASK_EARLY_TODO) + psc_early_tests(state); + else if (state->flags & (PSC_STATE_MASK_SMTPD_TODO | PSC_STATE_FLAG_NOFORWARD)) + psc_smtpd_tests(state); + else + psc_conclude(state); +} + +/* psc_cache_validator - validate one cache entry */ + +static int psc_cache_validator(const char *client_addr, + const char *stamp_str, + void *unused_context) +{ + PSC_STATE dummy_state; + PSC_CLIENT_INFO dummy_client_info; + + /* + * This function is called by the cache cleanup pseudo thread. + * + * When an entry is removed from the cache, the client will be reported as + * "NEW" in the next session where it passes all tests again. To avoid + * silly logging we remove the cache entry only after all tests have + * expired longer ago than the cache retention time. + */ + dummy_state.client_info = &dummy_client_info; + psc_parse_tests(&dummy_state, stamp_str, event_time() - var_psc_cache_ret); + return ((dummy_state.flags & PSC_STATE_MASK_ANY_TODO) == 0); +} + +/* pre_jail_init - pre-jail initialization */ + +static void pre_jail_init(char *unused_name, char **unused_argv) +{ + VSTRING *redirect; + + /* + * Open read-only maps before dropping privilege, for consistency with + * other Postfix daemons. + */ + psc_acl_pre_jail_init(var_mynetworks, VAR_PSC_ACL); + if (*var_psc_acl) + psc_acl = psc_acl_parse(var_psc_acl, VAR_PSC_ACL); + /* Ignore smtpd_forbid_cmds lookup errors. Non-critical feature. */ + if (*var_psc_forbid_cmds) + psc_forbid_cmds = string_list_init(VAR_PSC_FORBID_CMDS, + MATCH_FLAG_RETURN, + var_psc_forbid_cmds); + if (*var_psc_dnsbl_reply) + psc_dnsbl_reply = dict_open(var_psc_dnsbl_reply, O_RDONLY, + DICT_FLAG_DUP_WARN); + + /* + * Never, ever, get killed by a master signal, as that would corrupt the + * database when we're in the middle of an update. + */ + if (setsid() < 0) + msg_warn("setsid: %m"); + + /* + * Security: don't create root-owned files that contain untrusted data. + * And don't create Postfix-owned files in root-owned directories, + * either. We want a correct relationship between (file or directory) + * ownership and (file or directory) content. To open files before going + * to jail, temporarily drop root privileges. + */ + SAVE_AND_SET_EUGID(var_owner_uid, var_owner_gid); + redirect = vstring_alloc(100); + + /* + * Keep state in persistent external map. As a safety measure we sync the + * database on each update. This hurts on LINUX file systems that sync + * all dirty disk blocks whenever any application invokes fsync(). + * + * Start the cache maintenance pseudo thread after dropping privileges. + */ +#define PSC_DICT_OPEN_FLAGS (DICT_FLAG_DUP_REPLACE | DICT_FLAG_SYNC_UPDATE | \ + DICT_FLAG_OPEN_LOCK) + + if (*var_psc_cache_map) + psc_cache_map = + dict_cache_open(data_redirect_map(redirect, var_psc_cache_map), + O_CREAT | O_RDWR, PSC_DICT_OPEN_FLAGS); + + /* + * Clean up and restore privilege. + */ + vstring_free(redirect); + RESTORE_SAVED_EUGID(); + + /* + * Initialize the dummy SMTP engine. + */ + psc_smtpd_pre_jail_init(); +} + +/* pre_accept - see if tables have changed */ + +static void pre_accept(char *unused_name, char **unused_argv) +{ + static time_t last_event_time; + time_t new_event_time; + const char *name; + + /* + * If some table has changed then stop accepting new connections. Don't + * check the tables more than once a second. + */ + new_event_time = event_time(); + if (new_event_time >= last_event_time + 1 + && (name = dict_changed_name()) != 0) { + msg_info("table %s has changed - finishing in the background", name); + event_server_drain(); + } else { + last_event_time = new_event_time; + } +} + +/* post_jail_init - post-jail initialization */ + +static void post_jail_init(char *unused_name, char **unused_argv) +{ + const NAME_CODE actions[] = { + PSC_NAME_ACT_DROP, PSC_ACT_DROP, + PSC_NAME_ACT_ENFORCE, PSC_ACT_ENFORCE, + PSC_NAME_ACT_IGNORE, PSC_ACT_IGNORE, + PSC_NAME_ACT_CONT, PSC_ACT_IGNORE, /* compatibility */ + 0, -1, + }; + int cache_flags; + const char *tmp; + + /* + * This routine runs after the skeleton code has entered the chroot jail. + * Prevent automatic process suicide after a limited number of client + * requests. It is OK to terminate after a limited amount of idle time. + */ + var_use_limit = 0; + + /* + * Workaround for parameters whose values may contain "$", and that have + * a default of "$parametername". Not sure if it would be a good idea to + * always to this in the mail_conf_raw(3) module. + */ + if (*var_psc_rej_footer == '$' + && mail_conf_lookup(var_psc_rej_footer + 1)) { + tmp = mail_conf_eval_once(var_psc_rej_footer); + myfree(var_psc_rej_footer); + var_psc_rej_footer = mystrdup(tmp); + } + if (*var_psc_exp_filter == '$' + && mail_conf_lookup(var_psc_exp_filter + 1)) { + tmp = mail_conf_eval_once(var_psc_exp_filter); + myfree(var_psc_exp_filter); + var_psc_exp_filter = mystrdup(tmp); + } + + /* + * Other one-time initialization. + */ + psc_temp = vstring_alloc(10); + vstring_sprintf(psc_temp, "%s/%s", MAIL_CLASS_PRIVATE, var_smtpd_service); + psc_smtpd_service_name = mystrdup(STR(psc_temp)); + psc_dnsbl_init(); + psc_early_init(); + psc_smtpd_init(); + + if ((psc_dnlist_action = name_code(actions, NAME_CODE_FLAG_NONE, + var_psc_dnlist_action)) < 0) + msg_fatal("bad %s value: %s", VAR_PSC_DNLIST_ACTION, + var_psc_dnlist_action); + if ((psc_dnsbl_action = name_code(actions, NAME_CODE_FLAG_NONE, + var_psc_dnsbl_action)) < 0) + msg_fatal("bad %s value: %s", VAR_PSC_DNSBL_ACTION, + var_psc_dnsbl_action); + if ((psc_pregr_action = name_code(actions, NAME_CODE_FLAG_NONE, + var_psc_pregr_action)) < 0) + msg_fatal("bad %s value: %s", VAR_PSC_PREGR_ACTION, + var_psc_pregr_action); + if ((psc_pipel_action = name_code(actions, NAME_CODE_FLAG_NONE, + var_psc_pipel_action)) < 0) + msg_fatal("bad %s value: %s", VAR_PSC_PIPEL_ACTION, + var_psc_pipel_action); + if ((psc_nsmtp_action = name_code(actions, NAME_CODE_FLAG_NONE, + var_psc_nsmtp_action)) < 0) + msg_fatal("bad %s value: %s", VAR_PSC_NSMTP_ACTION, + var_psc_nsmtp_action); + if ((psc_barlf_action = name_code(actions, NAME_CODE_FLAG_NONE, + var_psc_barlf_action)) < 0) + msg_fatal("bad %s value: %s", VAR_PSC_BARLF_ACTION, + var_psc_barlf_action); + /* Fail "closed" on error. */ + psc_allist_if = addr_match_list_init(VAR_PSC_ALLIST_IF, MATCH_FLAG_RETURN, + var_psc_allist_if); + + /* + * Start the cache maintenance pseudo thread last. Early cleanup makes + * verbose logging more informative (we get positive confirmation that + * the cleanup thread runs). + */ + cache_flags = DICT_CACHE_FLAG_STATISTICS; + if (msg_verbose > 1) + cache_flags |= DICT_CACHE_FLAG_VERBOSE; + if (psc_cache_map != 0 && var_psc_cache_scan > 0) + dict_cache_control(psc_cache_map, + CA_DICT_CACHE_CTL_FLAGS(cache_flags), + CA_DICT_CACHE_CTL_INTERVAL(var_psc_cache_scan), + CA_DICT_CACHE_CTL_VALIDATOR(psc_cache_validator), + CA_DICT_CACHE_CTL_CONTEXT((void *) 0), + CA_DICT_CACHE_CTL_END); + + /* + * Pre-compute the minimal and maximal TTL. + */ + psc_min_ttl = + PSC_MIN(PSC_MIN(var_psc_pregr_ttl, var_psc_dnsbl_min_ttl), + PSC_MIN(PSC_MIN(var_psc_pipel_ttl, var_psc_nsmtp_ttl), + var_psc_barlf_ttl)); + + /* + * Pre-compute the stress and normal command time limits. + */ + mail_conf_update(VAR_STRESS, "yes"); + psc_stress_cmd_time_limit = + get_mail_conf_time(VAR_PSC_CMD_TIME, DEF_PSC_CMD_TIME, 1, 0); + psc_stress_greet_wait = + get_mail_conf_time(VAR_PSC_GREET_WAIT, DEF_PSC_GREET_WAIT, 1, 0); + + mail_conf_update(VAR_STRESS, ""); + psc_normal_cmd_time_limit = + get_mail_conf_time(VAR_PSC_CMD_TIME, DEF_PSC_CMD_TIME, 1, 0); + psc_normal_greet_wait = + get_mail_conf_time(VAR_PSC_GREET_WAIT, DEF_PSC_GREET_WAIT, 1, 0); + + psc_lowat_check_queue_length = .7 * var_psc_pre_queue_limit; + psc_hiwat_check_queue_length = .9 * var_psc_pre_queue_limit; + if (msg_verbose) + msg_info(VAR_PSC_CMD_TIME ": stress=%d normal=%d lowat=%d hiwat=%d", + psc_stress_cmd_time_limit, psc_normal_cmd_time_limit, + psc_lowat_check_queue_length, psc_hiwat_check_queue_length); + + if (psc_lowat_check_queue_length == 0) + msg_panic("compiler error: 0.7 * %d = %d", var_psc_pre_queue_limit, + psc_lowat_check_queue_length); + if (psc_hiwat_check_queue_length == 0) + msg_panic("compiler error: 0.9 * %d = %d", var_psc_pre_queue_limit, + psc_hiwat_check_queue_length); + + /* + * Per-client concurrency. + */ + psc_client_concurrency = htable_create(var_psc_pre_queue_limit); +} + +MAIL_VERSION_STAMP_DECLARE; + +/* main - pass control to the multi-threaded skeleton */ + +int main(int argc, char **argv) +{ + + /* + * List smtpd(8) parameters before any postscreen(8) parameters that have + * defaults dependencies on them. + */ + static const CONFIG_STR_TABLE str_table[] = { + VAR_SMTPD_SERVICE, DEF_SMTPD_SERVICE, &var_smtpd_service, 1, 0, + VAR_SMTPD_BANNER, DEF_SMTPD_BANNER, &var_smtpd_banner, 1, 0, + VAR_SMTPD_FORBID_CMDS, DEF_SMTPD_FORBID_CMDS, &var_smtpd_forbid_cmds, 0, 0, + VAR_SMTPD_EHLO_DIS_WORDS, DEF_SMTPD_EHLO_DIS_WORDS, &var_smtpd_ehlo_dis_words, 0, 0, + VAR_SMTPD_EHLO_DIS_MAPS, DEF_SMTPD_EHLO_DIS_MAPS, &var_smtpd_ehlo_dis_maps, 0, 0, + VAR_SMTPD_TLS_LEVEL, DEF_SMTPD_TLS_LEVEL, &var_smtpd_tls_level, 0, 0, + VAR_SMTPD_CMD_FILTER, DEF_SMTPD_CMD_FILTER, &var_smtpd_cmd_filter, 0, 0, + VAR_PSC_CACHE_MAP, DEF_PSC_CACHE_MAP, &var_psc_cache_map, 0, 0, + VAR_PSC_PREGR_BANNER, DEF_PSC_PREGR_BANNER, &var_psc_pregr_banner, 0, 0, + VAR_PSC_PREGR_ACTION, DEF_PSC_PREGR_ACTION, &var_psc_pregr_action, 1, 0, + VAR_PSC_DNSBL_SITES, DEF_PSC_DNSBL_SITES, &var_psc_dnsbl_sites, 0, 0, + VAR_PSC_DNSBL_ACTION, DEF_PSC_DNSBL_ACTION, &var_psc_dnsbl_action, 1, 0, + VAR_PSC_PIPEL_ACTION, DEF_PSC_PIPEL_ACTION, &var_psc_pipel_action, 1, 0, + VAR_PSC_NSMTP_ACTION, DEF_PSC_NSMTP_ACTION, &var_psc_nsmtp_action, 1, 0, + VAR_PSC_BARLF_ACTION, DEF_PSC_BARLF_ACTION, &var_psc_barlf_action, 1, 0, + VAR_PSC_ACL, DEF_PSC_ACL, &var_psc_acl, 0, 0, + VAR_PSC_DNLIST_ACTION, DEF_PSC_DNLIST_ACTION, &var_psc_dnlist_action, 1, 0, + VAR_PSC_FORBID_CMDS, DEF_PSC_FORBID_CMDS, &var_psc_forbid_cmds, 0, 0, + VAR_PSC_EHLO_DIS_WORDS, DEF_PSC_EHLO_DIS_WORDS, &var_psc_ehlo_dis_words, 0, 0, + VAR_PSC_EHLO_DIS_MAPS, DEF_PSC_EHLO_DIS_MAPS, &var_psc_ehlo_dis_maps, 0, 0, + VAR_PSC_DNSBL_REPLY, DEF_PSC_DNSBL_REPLY, &var_psc_dnsbl_reply, 0, 0, + VAR_PSC_TLS_LEVEL, DEF_PSC_TLS_LEVEL, &var_psc_tls_level, 0, 0, + VAR_PSC_CMD_FILTER, DEF_PSC_CMD_FILTER, &var_psc_cmd_filter, 0, 0, + VAR_DNSBLOG_SERVICE, DEF_DNSBLOG_SERVICE, &var_dnsblog_service, 1, 0, + VAR_TLSPROXY_SERVICE, DEF_TLSPROXY_SERVICE, &var_tlsproxy_service, 1, 0, + VAR_PSC_ALLIST_IF, DEF_PSC_ALLIST_IF, &var_psc_allist_if, 0, 0, + VAR_PSC_UPROXY_PROTO, DEF_PSC_UPROXY_PROTO, &var_psc_uproxy_proto, 0, 0, + VAR_PSC_REJ_FTR_MAPS, DEF_PSC_REJ_FTR_MAPS, &var_psc_rej_ftr_maps, 0, 0, + 0, + }; + static const CONFIG_INT_TABLE int_table[] = { + VAR_PSC_DNSBL_THRESH, DEF_PSC_DNSBL_THRESH, &var_psc_dnsbl_thresh, 1, 0, + VAR_PSC_CMD_COUNT, DEF_PSC_CMD_COUNT, &var_psc_cmd_count, 1, 0, + VAR_SMTPD_CCONN_LIMIT, DEF_SMTPD_CCONN_LIMIT, &var_smtpd_cconn_limit, 0, 0, + 0, + }; + static const CONFIG_NINT_TABLE nint_table[] = { + VAR_PSC_POST_QLIMIT, DEF_PSC_POST_QLIMIT, &var_psc_post_queue_limit, 5, 0, + VAR_PSC_PRE_QLIMIT, DEF_PSC_PRE_QLIMIT, &var_psc_pre_queue_limit, 10, 0, + VAR_PSC_CCONN_LIMIT, DEF_PSC_CCONN_LIMIT, &var_psc_cconn_limit, 0, 0, + VAR_PSC_DNSBL_ALTHRESH, DEF_PSC_DNSBL_ALTHRESH, &var_psc_dnsbl_althresh, 0, 0, + 0, + }; + static const CONFIG_TIME_TABLE time_table[] = { + VAR_PSC_CMD_TIME, DEF_PSC_CMD_TIME, &var_psc_cmd_time, 1, 0, + VAR_PSC_GREET_WAIT, DEF_PSC_GREET_WAIT, &var_psc_greet_wait, 1, 0, + VAR_PSC_PREGR_TTL, DEF_PSC_PREGR_TTL, &var_psc_pregr_ttl, 1, 0, + VAR_PSC_DNSBL_MIN_TTL, DEF_PSC_DNSBL_MIN_TTL, &var_psc_dnsbl_min_ttl, 1, 0, + VAR_PSC_DNSBL_MAX_TTL, DEF_PSC_DNSBL_MAX_TTL, &var_psc_dnsbl_max_ttl, 1, 0, + VAR_PSC_PIPEL_TTL, DEF_PSC_PIPEL_TTL, &var_psc_pipel_ttl, 1, 0, + VAR_PSC_NSMTP_TTL, DEF_PSC_NSMTP_TTL, &var_psc_nsmtp_ttl, 1, 0, + VAR_PSC_BARLF_TTL, DEF_PSC_BARLF_TTL, &var_psc_barlf_ttl, 1, 0, + VAR_PSC_CACHE_RET, DEF_PSC_CACHE_RET, &var_psc_cache_ret, 1, 0, + VAR_PSC_CACHE_SCAN, DEF_PSC_CACHE_SCAN, &var_psc_cache_scan, 0, 0, + VAR_PSC_WATCHDOG, DEF_PSC_WATCHDOG, &var_psc_watchdog, 10, 0, + VAR_PSC_UPROXY_TMOUT, DEF_PSC_UPROXY_TMOUT, &var_psc_uproxy_tmout, 1, 0, + VAR_PSC_DNSBL_TMOUT, DEF_PSC_DNSBL_TMOUT, &var_psc_dnsbl_tmout, 1, 0, + + 0, + }; + static const CONFIG_BOOL_TABLE bool_table[] = { + VAR_HELO_REQUIRED, DEF_HELO_REQUIRED, &var_helo_required, + VAR_DISABLE_VRFY_CMD, DEF_DISABLE_VRFY_CMD, &var_disable_vrfy_cmd, + VAR_SMTPD_USE_TLS, DEF_SMTPD_USE_TLS, &var_smtpd_use_tls, + VAR_SMTPD_ENFORCE_TLS, DEF_SMTPD_ENFORCE_TLS, &var_smtpd_enforce_tls, + VAR_PSC_PIPEL_ENABLE, DEF_PSC_PIPEL_ENABLE, &var_psc_pipel_enable, + VAR_PSC_NSMTP_ENABLE, DEF_PSC_NSMTP_ENABLE, &var_psc_nsmtp_enable, + VAR_PSC_BARLF_ENABLE, DEF_PSC_BARLF_ENABLE, &var_psc_barlf_enable, + 0, + }; + static const CONFIG_RAW_TABLE raw_table[] = { + VAR_SMTPD_REJ_FOOTER, DEF_SMTPD_REJ_FOOTER, &var_smtpd_rej_footer, 0, 0, + VAR_PSC_REJ_FOOTER, DEF_PSC_REJ_FOOTER, &var_psc_rej_footer, 0, 0, + VAR_SMTPD_EXP_FILTER, DEF_SMTPD_EXP_FILTER, &var_smtpd_exp_filter, 1, 0, + VAR_PSC_EXP_FILTER, DEF_PSC_EXP_FILTER, &var_psc_exp_filter, 1, 0, + 0, + }; + static const CONFIG_NBOOL_TABLE nbool_table[] = { + VAR_PSC_HELO_REQUIRED, DEF_PSC_HELO_REQUIRED, &var_psc_helo_required, + VAR_PSC_DISABLE_VRFY, DEF_PSC_DISABLE_VRFY, &var_psc_disable_vrfy, + VAR_PSC_USE_TLS, DEF_PSC_USE_TLS, &var_psc_use_tls, + VAR_PSC_ENFORCE_TLS, DEF_PSC_ENFORCE_TLS, &var_psc_enforce_tls, + 0, + }; + + /* + * Fingerprint executables and core dumps. + */ + MAIL_VERSION_STAMP_ALLOCATE; + + event_server_main(argc, argv, psc_service, + CA_MAIL_SERVER_STR_TABLE(str_table), + CA_MAIL_SERVER_INT_TABLE(int_table), + CA_MAIL_SERVER_NINT_TABLE(nint_table), + CA_MAIL_SERVER_TIME_TABLE(time_table), + CA_MAIL_SERVER_BOOL_TABLE(bool_table), + CA_MAIL_SERVER_RAW_TABLE(raw_table), + CA_MAIL_SERVER_NBOOL_TABLE(nbool_table), + CA_MAIL_SERVER_PRE_INIT(pre_jail_init), + CA_MAIL_SERVER_POST_INIT(post_jail_init), + CA_MAIL_SERVER_PRE_ACCEPT(pre_accept), + CA_MAIL_SERVER_SOLITARY, + CA_MAIL_SERVER_SLOW_EXIT(psc_drain), + CA_MAIL_SERVER_EXIT(psc_dump), + CA_MAIL_SERVER_WATCHDOG(&var_psc_watchdog), + 0); +} |