diff --git a/postfix/HISTORY b/postfix/HISTORY index 7c4a84d85..f3b1d1cbe 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -9351,3 +9351,8 @@ Apologies for any names omitted. overshoot limit (default: smtpd_recipient_overshoot_limit = 1000). Solution in cooperation with Victor Duchovni. Files: smtpd/smtpd.c, smtpd/smtpd_state.c, smtpd/smtpd.h. + +20040503 + + Bugfix: missing "sasl enabled" guard in the SMTPD policy + client. File: smtpd/smtpd_check.c. diff --git a/postfix/html/smtpd.8.html b/postfix/html/smtpd.8.html index 06309d26e..242c121c4 100644 --- a/postfix/html/smtpd.8.html +++ b/postfix/html/smtpd.8.html @@ -434,7 +434,7 @@ SMTPD(8) SMTPD(8) Postfix SMTP server starts to increment the error counter with each junk command. - smtpd_recipient_overshoot_limit (1000) + smtpd_recipient_overshoot_limit (1000) The number of recipients that a remote SMTP client can send in excess of the limit specified with $smtpd_recipient_limit, before the Postfix SMTP diff --git a/postfix/man/junk b/postfix/man/junk deleted file mode 100644 index c5f44b835..000000000 --- a/postfix/man/junk +++ /dev/null @@ -1,2796 +0,0 @@ -/*++ -/* NAME -/* smtpd 8 -/* SUMMARY -/* Postfix SMTP server -/* SYNOPSIS -/* \fBsmtpd\fR [generic Postfix daemon options] -/* DESCRIPTION -/* The SMTP server accepts network connection requests -/* and performs zero or more SMTP transactions per connection. -/* Each received message is piped through the \fBcleanup\fR(8) -/* daemon, and is placed into the \fBincoming\fR queue as one -/* single queue file. For this mode of operation, the program -/* expects to be run from the \fBmaster\fR(8) process manager. -/* -/* Alternatively, the SMTP server takes an established -/* connection on standard input and deposits messages directly -/* into the \fBmaildrop\fR queue. In this so-called stand-alone -/* mode, the SMTP server can accept mail even while the mail -/* system is not running. -/* -/* The SMTP server implements a variety of policies for connection -/* requests, and for parameters given to \fBHELO, ETRN, MAIL FROM, VRFY\fR -/* and \fBRCPT TO\fR commands. They are detailed below and in the -/* \fBmain.cf\fR configuration file. -/* SECURITY -/* .ad -/* .fi -/* The SMTP server is moderately security-sensitive. It talks to SMTP -/* clients and to DNS servers on the network. The SMTP server 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 2554 (AUTH command) -/* RFC 2821 (SMTP protocol) -/* RFC 2920 (SMTP Pipelining) -/* DIAGNOSTICS -/* Problems and transactions are logged to \fBsyslogd\fR(8). -/* -/* Depending on the setting of the \fBnotify_classes\fR parameter, -/* the postmaster is notified of bounces, protocol problems, -/* policy violations, and of other trouble. -/* CONFIGURATION PARAMETERS -/* .ad -/* .fi -/* Changes to \fBmain.cf\fR are picked up automatically, as smtpd(8) -/* processes run for only a limited amount of time. Use the command -/* "\fBpostfix reload\fR" to speed up a change. -/* -/* The text below provides only a parameter summary. See -/* postconf(5) for more details including examples. -/* COMPATIBILITY CONTROLS -/* .ad -/* .fi -/* The following parameters work around implementation errors in other -/* software, and/or allow you to override standards in order to prevent -/* undesirable use. -/* .ad -/* .fi -/* .IP "\fBbroken_sasl_auth_clients (no)\fR" -/* Enable inter-operability with SMTP clients that implement an obsolete -/* version of the AUTH command (RFC 2554). -/* .IP "\fBdisable_vrfy_command (no)\fR" -/* Disable the SMTP VRFY command. -/* .IP "\fBsmtpd_noop_commands (empty)\fR" -/* List of commands that the Postfix SMTP server replies to with "250 -/* Ok", without doing any syntax checks and without changing state. -/* .IP "\fBstrict_rfc821_envelopes (no)\fR" -/* Require that addresses received in SMTP MAIL FROM and RCPT TO -/* commands are enclosed with <>, and that those addresses do -/* not contain RFC 822 style comments or phrases. -/* .PP -/* Available in Postfix version 2.1 and later: -/* .IP "\fBresolve_null_domain (no)\fR" -/* Resolve an address that ends in the "@" null domain as if the -/* local hostname were specified, instead of rejecting the address as -/* invalid. -/* .IP "\fBsmtpd_reject_unlisted_sender (no)\fR" -/* Request that the Postfix SMTP server rejects mail from unknown -/* sender addresses, even when no explicit reject_unlisted_sender -/* access restriction is specified. -/* .IP "\fBsmtpd_sasl_exceptions_networks (empty)\fR" -/* What SMTP clients Postfix will not offer AUTH support to. -/* AFTER QUEUE EXTERNAL CONTENT INSPECTION CONTROLS -/* .ad -/* .fi -/* As of version 1.0, Postfix can be configured to send new mail to -/* an external content filter AFTER the mail is queued. This content -/* filter is expected to inject mail back into a (Postfix or other) -/* MTA for further delivery. See the FILTER_README document for details. -/* .IP "\fBcontent_filter (empty)\fR" -/* The name of a mail delivery transport that filters mail after -/* it is queued. -/* BEFORE QUEUE EXTERNAL CONTENT INSPECTION CONTROLS -/* .ad -/* .fi -/* As of version 2.1, the Postfix SMTP server can be configured -/* to send incoming mail to a real-time SMTP-based content filter -/* BEFORE mail is queued. This content filter is expected to inject -/* mail back into Postfix. See the SMTPD_PROXY_README document for -/* details on how to configure and operate this feature. -/* .IP "\fBsmtpd_proxy_filter (empty)\fR" -/* The hostname and TCP port of the mail filtering proxy server. -/* .IP "\fBsmtpd_proxy_ehlo ($myhostname)\fR" -/* How the Postfix SMTP server announces itself to the proxy filter. -/* .IP "\fBsmtpd_proxy_timeout (100s)\fR" -/* The time limit for connecting to a proxy filter and for sending or -/* receiving information. -/* GENERAL CONTENT INSPECTION CONTROLS -/* .ad -/* .fi -/* The following parameters are applicable for both built-in -/* and external content filters. -/* .PP -/* Available in Postfix version 2.1 and later: -/* .IP "\fBreceive_override_options (empty)\fR" -/* Enable or disable recipient validation, built-in content -/* filtering, or address rewriting. -/* EXTERNAL CONTENT INSPECTION CONTROLS -/* .ad -/* .fi -/* The following parameters are applicable for both before-queue -/* and after-queue content filtering. -/* .PP -/* Available in Postfix version 2.1 and later: -/* .IP "\fBsmtpd_authorized_xforward_hosts (empty)\fR" -/* What SMTP clients are allowed to use the XFORWARD feature. -/* SASL AUTHENTICATION CONTROLS -/* .ad -/* .fi -/* Postfix SASL support (RFC 2554) can be used to authenticate remote -/* SMTP clients to the Postfix SMTP server, and to authenticate the -/* Postfix SMTP client to a remote SMTP server. -/* See the SASL_README document for details. -/* .IP "\fBbroken_sasl_auth_clients (no)\fR" -/* Enable inter-operability with SMTP clients that implement an obsolete -/* version of the AUTH command (RFC 2554). -/* .IP "\fBsmtpd_sasl_auth_enable (no)\fR" -/* Enable SASL authentication in the Postfix SMTP server. -/* .IP "\fBsmtpd_sasl_application_name (smtpd)\fR" -/* The application name used for SASL server initialization. -/* .IP "\fBsmtpd_sasl_local_domain (empty)\fR" -/* The name of the local SASL authentication realm. -/* .IP "\fBsmtpd_sasl_security_options (noanonymous)\fR" -/* Restrict what authentication mechanisms the Postfix SMTP server -/* will offer to the client. -/* .IP "\fBsmtpd_sender_login_maps (empty)\fR" -/* Optional lookup table with the SASL login names that own sender -/* (MAIL FROM) addresses. -/* .PP -/* Available in Postfix version 2.1 and later: -/* .IP "\fBsmtpd_sasl_exceptions_networks (empty)\fR" -/* What SMTP clients Postfix will not offer AUTH support to. -/* VERP SUPPORT CONTROLS -/* .ad -/* .fi -/* With VERP style delivery, each recipient of a message receives a -/* customized copy of the message with his/her own recipient address -/* encoded in the envelope sender address. The VERP_README file -/* describes configuration and operation details of Postfix support -/* for variable envelope return path addresses. VERP style delivery -/* is requested with the SMTP XVERP command or with the "sendmail -/* -V" command-line option and is available in Postfix version 1.1 -/* and later. -/* .IP "\fBdefault_verp_delimiters (+=)\fR" -/* The two default VERP delimiter characters. -/* .IP "\fBverp_delimiter_filter (-=+)\fR" -/* The characters Postfix accepts as VERP delimiter characters on the -/* Postfix sendmail(1) command line and in SMTP commands. -/* .PP -/* Available in Postfix version 1.1 and 2.0: -/* .IP "\fBauthorized_verp_clients ($mynetworks)\fR" -/* What SMTP clients are allowed to specify the XVERP command. -/* .PP -/* Available in Postfix version 2.1 and later: -/* .IP "\fBsmtpd_authorized_verp_clients ($authorized_verp_clients)\fR" -/* What SMTP clients are allowed to specify the XVERP command. -/* TROUBLE SHOOTING CONTROLS -/* .ad -/* .fi -/* The DEBUG_README document describes how to debug parts of the -/* Postfix mail system. The methods vary from making the software log -/* a lot of detail, to running some daemon processes under control of -/* a call tracer or debugger. -/* .IP "\fBdebug_peer_level (2)\fR" -/* The increment in verbose logging level when a remote client or -/* server matches a pattern in the debug_peer_list parameter. -/* .IP "\fBdebug_peer_list (empty)\fR" -/* Optional list of remote client or server hostname or network -/* address patterns that cause the verbose logging level to increase -/* by the amount specified in $debug_peer_level. -/* .IP "\fBerror_notice_recipient (postmaster)\fR" -/* The recipient of postmaster notifications about mail delivery -/* problems that are caused by policy, resource, software or protocol -/* errors. -/* .IP "\fBnotify_classes (resource, software)\fR" -/* The list of error classes that are reported to the postmaster. -/* .IP "\fBsoft_bounce (no)\fR" -/* Safety net to keep mail queued that would otherwise be returned to -/* the sender. -/* .PP -/* Available in Postfix version 2.1 and later: -/* .IP "\fBsmtpd_authorized_xclient_hosts (empty)\fR" -/* What SMTP clients are allowed to use the XCLIENT feature. -/* KNOWN VERSUS UNKNOWN RECIPIENT CONTROLS -/* .ad -/* .fi -/* As of Postfix version 2.0, the SMTP server rejects mail for -/* unknown recipients. This prevents the mail queue from clogging up -/* with undeliverable MAILER-DAEMON messages. Additional information -/* on this topic is in the LOCAL_RECIPIENT_README and ADDRESS_CLASS_README -/* documents. -/* .IP "\fBshow_user_unknown_table_name (yes)\fR" -/* Display the name of the recipient table in the "User unknown" -/* responses. -/* .IP "\fBcanonical_maps (empty)\fR" -/* Optional address mapping lookup tables for message headers and -/* envelopes. -/* .IP "\fBrecipient_canonical_maps (empty)\fR" -/* Optional address mapping lookup tables for envelope and header -/* recipient addresses. -/* .PP -/* Parameters concerning known/unknown local recipients: -/* .IP "\fBmydestination ($myhostname, localhost.$mydomain, localhost)\fR" -/* The list of domains that are delivered via the $local_transport -/* mail delivery transport. -/* .IP "\fBinet_interfaces (all)\fR" -/* The network interface addresses that this mail system receives mail -/* on. -/* .IP "\fBproxy_interfaces (empty)\fR" -/* The network interface addresses that this mail system receives mail -/* on by way of a proxy or network address translation unit. -/* .IP "\fBlocal_recipient_maps (proxy:unix:passwd.byname $alias_maps)\fR" -/* Lookup tables with all names or addresses of local recipients: -/* a recipient address is local when its domain matches $mydestination, -/* $inet_interfaces or $proxy_interfaces. -/* .IP "\fBunknown_local_recipient_reject_code (550)\fR" -/* The numerical Postfix SMTP server response code when a recipient -/* address is local, and $local_recipient_maps specifies a list of -/* lookup tables that does not match the recipient. -/* .PP -/* Parameters concerning known/unknown recipients of relay destinations: -/* .IP "\fBrelay_domains ($mydestination)\fR" -/* What destination domains (and subdomains thereof) this system -/* will relay mail to. -/* .IP "\fBrelay_recipient_maps (empty)\fR" -/* Optional lookup tables with all valid addresses in the domains -/* that match $relay_domains. -/* .IP "\fBunknown_relay_recipient_reject_code (550)\fR" -/* The numerical Postfix SMTP server reply code when a recipient -/* address matches $relay_domains, and relay_recipient_maps specifies -/* a list of lookup tables that does not match the recipient address. -/* .PP -/* Parameters concerning known/unknown recipients in virtual alias -/* domains: -/* .IP "\fBvirtual_alias_domains ($virtual_alias_maps)\fR" -/* Optional list of names of virtual alias domains, that is, -/* domains for which all addresses are aliased to addresses in other -/* local or remote domains. -/* .IP "\fBvirtual_alias_maps ($virtual_maps)\fR" -/* Optional lookup tables that alias specific mail addresses or domains -/* to other local or remote address. -/* .IP "\fBunknown_virtual_alias_reject_code (550)\fR" -/* The SMTP server reply code when a recipient address matches -/* $virtual_alias_domains, and $virtual_alias_maps specifies a list -/* of lookup tables that does not match the recipient address. -/* .PP -/* Parameters concerning known/unknown recipients in virtual mailbox -/* domains: -/* .IP "\fBvirtual_mailbox_domains ($virtual_mailbox_maps)\fR" -/* The list of domains that are delivered via the $virtual_transport -/* mail delivery transport. -/* .IP "\fBvirtual_mailbox_maps (empty)\fR" -/* Optional lookup tables with all valid addresses in the domains that -/* match $virtual_mailbox_domains. -/* .IP "\fBunknown_virtual_mailbox_reject_code (550)\fR" -/* The SMTP server reply code when a recipient address matches -/* $virtual_mailbox_domains, and $virtual_mailbox_maps specifies a list -/* of lookup tables that does not match the recipient address. -/* RESOURCE AND RATE CONTROLS -/* .ad -/* .fi -/* The following parameters limit resource usage by the SMTP -/* server and/or control client request rates. -/* .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 "\fBqueue_minfree (0)\fR" -/* The minimal amount of free space in bytes in the queue file system -/* that is needed to receive mail. -/* .IP "\fBmessage_size_limit (10240000)\fR" -/* The maximal size in bytes of a message, including envelope information. -/* .IP "\fBsmtpd_recipient_limit (1000)\fR" -/* The maximal number of recipients that the Postfix SMTP server -/* accepts per message delivery request. -/* .IP "\fBsmtpd_timeout (300s)\fR" -/* The time limit for sending a Postfix SMTP server response and for -/* receiving a remote SMTP client request. -/* .IP "\fBsmtpd_history_flush_threshold (100)\fR" -/* The maximal number of lines in the Postfix SMTP server command history -/* before it is flushed upon receipt of EHLO, RSET, or end of DATA. -/* .PP -/* Not available in Postfix version 2.1: -/* .IP "\fBsmtpd_client_connection_count_limit (50)\fR" -/* How many simultaneous connections any SMTP client is allowed to -/* make to the SMTP service. -/* .IP "\fBsmtpd_client_connection_rate_limit (0)\fR" -/* The maximal number of connection attempts any client is allowed to -/* make to this service per time unit. -/* .IP "\fBsmtpd_client_connection_limit_exceptions ($mynetworks)\fR" -/* Clients that are excluded from connection count or connection rate -/* restrictions. -/* TARPIT CONTROLS -/* .ad -/* .fi -/* When a remote SMTP client makes errors, the Postfix SMTP server -/* can insert delays before responding. This can help to slow down -/* run-away software. The behavior is controlled by an error counter -/* that counts the number of errors within an SMTP session that a -/* client makes without delivering mail. -/* .IP "\fBsmtpd_error_sleep_time (1s)\fR" -/* With Postfix 2.1 and later: the SMTP server response delay after -/* a client has made more than $smtpd_soft_error_limit errors, and -/* fewer than $smtpd_hard_error_limit errors, without delivering mail. -/* .IP "\fBsmtpd_soft_error_limit (10)\fR" -/* The number of errors a remote SMTP client is allowed to make without -/* delivering mail before the Postfix SMTP server slows down all its -/* responses. -/* .IP "\fBsmtpd_hard_error_limit (20)\fR" -/* The maximal number of errors a remote SMTP client is allowed to -/* make without delivering mail. -/* .IP "\fBsmtpd_junk_command_limit (100)\fR" -/* The number of junk commands (NOOP, VRFY, ETRN or RSET) that a remote -/* SMTP client can send before the Postfix SMTP server starts to -/* increment the error counter with each junk command. -/* .IP "\fBsmtpd_recipient_overshoot_limit (1000)\fR" -/* The number of recipients that a remote SMTP client can send in -/* excess of the limit specified with $smtpd_recipient_limit, before -/* the Postfix SMTP server increments the per-session error count -/* for each excess recipient. -/* ACCESS POLICY DELEGATION CONTROLS -/* .ad -/* .fi -/* As of version 2.1, Postfix can be configured to delegate access -/* policy decisions to an external server that runs outside Postfix. -/* See the file SMTPD_POLICY_README for more information. -/* .IP "\fBsmtpd_policy_service_timeout (100s)\fR" -/* The time limit for connecting to, writing to or receiving from a -/* delegated SMTPD policy server. -/* .IP "\fBsmtpd_policy_service_max_idle (300s)\fR" -/* The time after which an idle SMTPD policy service connection is -/* closed. -/* .IP "\fBsmtpd_policy_service_max_ttl (1000s)\fR" -/* The time after which an active SMTPD policy service connection is -/* closed. -/* .IP "\fBsmtpd_policy_service_timeout (100s)\fR" -/* The time limit for connecting to, writing to or receiving from a -/* delegated SMTPD policy server. -/* ACCESS CONTROLS -/* .ad -/* .fi -/* The SMTPD_ACCESS_README document gives an introduction to all the -/* SMTP server access control features. -/* .IP "\fBsmtpd_delay_reject (yes)\fR" -/* Wait until the RCPT TO command before evaluating -/* $smtpd_client_restrictions, $smtpd_helo_restrictions and -/* $smtpd_sender_restrictions, or wait until the ETRN command before -/* evaluating $smtpd_client_restrictions and $smtpd_helo_restrictions. -/* .IP "\fBparent_domain_matches_subdomains (see 'postconf -d' output)\fR" -/* What Postfix features match subdomains of "domain.tld" automatically, -/* instead of requiring an explicit ".domain.tld" pattern. -/* .IP "\fBsmtpd_client_restrictions (empty)\fR" -/* Optional SMTP server access restrictions in the context of a client -/* SMTP connection request. -/* .IP "\fBsmtpd_helo_required (no)\fR" -/* Require that a remote SMTP client introduces itself at the beginning -/* of an SMTP session with the HELO or EHLO command. -/* .IP "\fBsmtpd_helo_restrictions (empty)\fR" -/* Optional restrictions that the Postfix SMTP server applies in the -/* context of the SMTP HELO command. -/* .IP "\fBsmtpd_sender_restrictions (empty)\fR" -/* Optional restrictions that the Postfix SMTP server applies in the -/* context of the MAIL FROM command. -/* .IP "\fBsmtpd_recipient_restrictions (permit_mynetworks, reject_unauth_destination)\fR" -/* The access restrictions that the Postfix SMTP server applies in -/* the context of the RCPT TO command. -/* .IP "\fBsmtpd_etrn_restrictions (empty)\fR" -/* Optional SMTP server access restrictions in the context of a client -/* ETRN request. -/* .IP "\fBallow_untrusted_routing (no)\fR" -/* Forward mail with sender-specified routing (user[@%!]remote[@%!]site) -/* from untrusted clients to destinations matching $relay_domains. -/* .IP "\fBsmtpd_restriction_classes (empty)\fR" -/* User-defined aliases for groups of access restrictions. -/* .IP "\fBsmtpd_null_access_lookup_key (<>)\fR" -/* The lookup key to be used in SMTP access(5) tables instead of the -/* null sender address. -/* .IP "\fBpermit_mx_backup_networks (empty)\fR" -/* Restrict the use of the permit_mx_backup SMTP access feature to -/* only domains whose primary MX hosts match the listed networks. -/* .PP -/* Available in Postfix version 2.0 and later: -/* .IP "\fBsmtpd_data_restrictions (empty)\fR" -/* Optional access restrictions that the Postfix SMTP server applies -/* in the context of the SMTP DATA command. -/* .IP "\fBsmtpd_expansion_filter (see 'postconf -d' output)\fR" -/* What characters are allowed in $name expansions of RBL reply -/* templates. -/* .PP -/* Available in Postfix version 2.1 and later: -/* .IP "\fBsmtpd_reject_unlisted_sender (no)\fR" -/* Request that the Postfix SMTP server rejects mail from unknown -/* sender addresses, even when no explicit reject_unlisted_sender -/* access restriction is specified. -/* .IP "\fBsmtpd_reject_unlisted_recipient (yes)\fR" -/* Request that the Postfix SMTP server rejects mail for unknown -/* recipient addresses, even when no explicit reject_unlisted_recipient -/* access restriction is specified. -/* SENDER AND RECIPIENT ADDRESS VERIFICATION CONTROLS -/* .ad -/* .fi -/* Postfix version 2.1 introduces sender and address verification. -/* This feature is implemented by sending probe email messages that -/* are not actually delivered. -/* This feature is requested via the reject_unverified_sender and -/* reject_unverified_recipient access restrictions. The status of -/* verification probes is maintained by the verify(8) server. -/* See the file ADDRESS_VERIFICATION_README for information -/* about how to configure and operate the Postfix sender/recipient -/* address verification service. -/* .IP "\fBaddress_verify_poll_count (3)\fR" -/* How many times to query the verify(8) service for the completion -/* of an address verification request in progress. -/* .IP "\fBaddress_verify_poll_delay (3s)\fR" -/* The delay between queries for the completion of an address -/* verification request in progress. -/* .IP "\fBaddress_verify_sender (postmaster)\fR" -/* The sender address to use in address verification probes. -/* .IP "\fBunverified_sender_reject_code (450)\fR" -/* The numerical Postfix SMTP server response code when a recipient -/* address is rejected by the reject_unverified_sender restriction. -/* .IP "\fBunverified_recipient_reject_code (450)\fR" -/* The numerical Postfix SMTP server response when a recipient address -/* is rejected by the reject_unverified_recipient restriction. -/* ACCESS CONTROL RESPONSES -/* .ad -/* .fi -/* The following parameters control numerical SMTP reply codes -/* and/or text responses. -/* .IP "\fBaccess_map_reject_code (554)\fR" -/* The numerical Postfix SMTP server response code when a client -/* is rejected by an access(5) map restriction. -/* .IP "\fBdefer_code (450)\fR" -/* The numerical Postfix SMTP server response code when a remote SMTP -/* client request is rejected by the "defer" restriction. -/* .IP "\fBinvalid_hostname_reject_code (501)\fR" -/* The numerical Postfix SMTP server response code when the client -/* HELO or EHLO command parameter is rejected by the reject_invalid_hostname -/* restriction. -/* .IP "\fBmaps_rbl_reject_code (554)\fR" -/* The numerical Postfix SMTP server response code when a remote SMTP -/* client request is blocked by the reject_rbl_client, reject_rhsbl_client, -/* reject_rhsbl_sender or reject_rhsbl_recipient restriction. -/* .IP "\fBnon_fqdn_reject_code (504)\fR" -/* The numerical Postfix SMTP server reply code when a client request -/* is rejected by the reject_non_fqdn_hostname, reject_non_fqdn_sender -/* or reject_non_fqdn_recipient restriction. -/* .IP "\fBreject_code (554)\fR" -/* The numerical Postfix SMTP server response code when a remote SMTP -/* client request is rejected by the "\fBreject\fR" restriction. -/* .IP "\fBrelay_domains_reject_code (554)\fR" -/* The numerical Postfix SMTP server response code when a client -/* request is rejected by the reject_unauth_destination recipient -/* restriction. -/* .IP "\fBunknown_address_reject_code (450)\fR" -/* The numerical Postfix SMTP server response code when a sender or -/* recipient address is rejected by the reject_unknown_sender_domain -/* or reject_unknown_recipient_domain restriction. -/* .IP "\fBunknown_client_reject_code (450)\fR" -/* The numerical Postfix SMTP server response code when a client -/* without valid address <=> name mapping is rejected by the -/* reject_unknown_client restriction. -/* .IP "\fBunknown_hostname_reject_code (450)\fR" -/* The numerical Postfix SMTP server response code when the hostname -/* specified with the HELO or EHLO command is rejected by the -/* reject_unknown_hostname restriction. -/* .PP -/* Available in Postfix version 2.0 and later: -/* .IP "\fBdefault_rbl_reply (see 'postconf -d' output)\fR" -/* The default SMTP server response template for a request that is -/* rejected by an RBL-based restriction. -/* .IP "\fBmulti_recipient_bounce_reject_code (550)\fR" -/* The numerical Postfix SMTP server response code when a remote SMTP -/* client request is blocked by the reject_multi_recipient_bounce -/* restriction. -/* .IP "\fBrbl_reply_maps (empty)\fR" -/* Optional lookup tables with RBL response templates. -/* 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 "\fBdaemon_timeout (18000s)\fR" -/* How much time a Postfix daemon process may take to handle a -/* request before it is terminated by a built-in watchdog timer. -/* .IP "\fBcommand_directory (see 'postconf -d' output)\fR" -/* The location of all postfix administrative commands. -/* .IP "\fBdouble_bounce_sender (double-bounce)\fR" -/* The sender address of postmaster notifications that are generated -/* by the mail system. -/* .IP "\fBipc_timeout (3600s)\fR" -/* The time limit for sending or receiving information over an internal -/* communication channel. -/* .IP "\fBmail_name (Postfix)\fR" -/* The mail system name that is displayed in Received: headers, in -/* the SMTP greeting banner, and in bounced mail. -/* .IP "\fBmail_owner (postfix)\fR" -/* The UNIX system account that owns the Postfix queue and most Postfix -/* daemon processes. -/* .IP "\fBmax_idle (100s)\fR" -/* The maximum amount of time that an idle Postfix daemon process -/* waits for the next service request before exiting. -/* .IP "\fBmax_use (100)\fR" -/* The maximal number of connection requests before a Postfix daemon -/* process terminates. -/* .IP "\fBmyhostname (see 'postconf -d' output)\fR" -/* The internet hostname of this mail system. -/* .IP "\fBmynetworks (see 'postconf -d' output)\fR" -/* The list of "trusted" SMTP clients that have more privileges than -/* "strangers". -/* .IP "\fBmyorigin ($myhostname)\fR" -/* The default domain name that locally-posted mail appears to come -/* from, and that locally posted mail is delivered to. -/* .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 "\fBqueue_directory (see 'postconf -d' output)\fR" -/* The location of the Postfix top-level queue directory. -/* .IP "\fBrecipient_delimiter (empty)\fR" -/* The separator between user names and address extensions (user+foo). -/* .IP "\fBsmtpd_banner ($myhostname ESMTP $mail_name)\fR" -/* The text that follows the 220 status code in the SMTP greeting -/* banner. -/* .IP "\fBsyslog_facility (mail)\fR" -/* The syslog facility of Postfix logging. -/* .IP "\fBsyslog_name (postfix)\fR" -/* The mail system name that is prepended to the process name in syslog -/* records, so that "smtpd" becomes, for example, "postfix/smtpd". -/* SEE ALSO -/* cleanup(8), message canonicalization -/* trivial-rewrite(8), address resolver -/* verify(8), address verification service -/* postconf(5), configuration parameters -/* master(8), process manager -/* syslogd(8), system logging -/* README FILES -/* .ad -/* .fi -/* Use "\fBpostconf readme_directory\fR" or -/* "\fBpostconf html_directory\fR" to locate this information. -/* .na -/* .nf -/* ADDRESS_CLASS_README, blocking unknown hosted or relay recipients -/* FILTER_README, external after-queue content filter -/* LOCAL_RECIPIENT_README, blocking unknown local recipients -/* SMTPD_ACCESS_README, built-in access policies -/* SMTPD_POLICY_README, external policy server -/* SMTPD_PROXY_README, external before-queue content filter -/* SASL_README, Postfix SASL howto -/* VERP_README, Postfix XVERP extension -/* XCLIENT_README, Postfix XCLIENT extension -/* XFORWARD_README, Postfix XFORWARD extension -/* LICENSE -/* .ad -/* .fi -/* The Secure Mailer license must be distributed with this software. -/* AUTHOR(S) -/* Wietse Venema -/* IBM T.J. Watson Research -/* P.O. Box 704 -/* Yorktown Heights, NY 10598, USA -/*--*/ - -/* System library. */ - -#include -#include -#include -#include -#include -#include -#include -#include /* remove() */ -#include -#include -#include -#include -#include -#include -#include /* offsetof() */ - -#ifdef STRCASECMP_IN_STRINGS_H -#include -#endif - -/* Utility library. */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Global library. */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef SNAPSHOT -#include -#endif -#include - -/* Single-threaded server skeleton. */ - -#include - -/* Application-specific */ - -#include -#include -#include -#include -#include -#include -#include - - /* - * Tunable parameters. Make sure that there is some bound on the length of - * an SMTP command, so that the mail system stays in control even when a - * malicious client sends commands of unreasonable length (qmail-dos-1). - * Make sure there is some bound on the number of recipients, so that the - * mail system stays in control even when a malicious client sends an - * unreasonable number of recipients (qmail-dos-2). - */ -int var_smtpd_rcpt_limit; -int var_smtpd_tmout; -int var_smtpd_soft_erlim; -int var_smtpd_hard_erlim; -int var_queue_minfree; /* XXX use off_t */ -char *var_smtpd_banner; -char *var_notify_classes; -char *var_client_checks; -char *var_helo_checks; -char *var_mail_checks; -char *var_rcpt_checks; -char *var_etrn_checks; -char *var_data_checks; -int var_unk_client_code; -int var_bad_name_code; -int var_unk_name_code; -int var_unk_addr_code; -int var_relay_code; -int var_maps_rbl_code; -int var_access_map_code; -char *var_maps_rbl_domains; -char *var_rbl_reply_maps; -int var_helo_required; -int var_reject_code; -int var_defer_code; -int var_smtpd_err_sleep; -int var_non_fqdn_code; -char *var_error_rcpt; -int var_smtpd_delay_reject; -char *var_rest_classes; -int var_strict_rfc821_env; -bool var_disable_vrfy_cmd; -char *var_canonical_maps; -char *var_rcpt_canon_maps; -char *var_virt_alias_maps; -char *var_virt_mailbox_maps; -char *var_alias_maps; -char *var_local_rcpt_maps; -bool var_allow_untrust_route; -int var_smtpd_junk_cmd_limit; -int var_smtpd_rcpt_overlim; -bool var_smtpd_sasl_enable; -char *var_smtpd_sasl_opts; -char *var_smtpd_sasl_appname; -char *var_smtpd_sasl_realm; -char *var_smtpd_sasl_exceptions_networks; -char *var_filter_xport; -bool var_broken_auth_clients; -char *var_perm_mx_networks; -char *var_smtpd_snd_auth_maps; -char *var_smtpd_noop_cmds; -char *var_smtpd_null_key; -int var_smtpd_hist_thrsh; -char *var_smtpd_exp_filter; -char *var_def_rbl_reply; -int var_unv_from_code; -int var_unv_rcpt_code; -int var_mul_rcpt_code; -char *var_relay_rcpt_maps; -char *var_verify_sender; -int var_local_rcpt_code; -int var_virt_alias_code; -int var_virt_mailbox_code; -int var_relay_rcpt_code; -char *var_verp_clients; -int var_show_unk_rcpt_table; -int var_verify_poll_count; -int var_verify_poll_delay; -char *var_smtpd_proxy_filt; -int var_smtpd_proxy_tmout; -char *var_smtpd_proxy_ehlo; -char *var_input_transp; -int var_smtpd_policy_tmout; -int var_smtpd_policy_idle; -int var_smtpd_policy_ttl; -char *var_xclient_hosts; -char *var_xforward_hosts; -bool var_smtpd_rej_unl_from; -bool var_smtpd_rej_unl_rcpt; - -#ifdef SNAPSHOT -int var_smtpd_crate_limit; -int var_smtpd_cconn_limit; -char *var_smtpd_hoggers; - -#endif - - /* - * Silly little macros. - */ -#define STR(x) vstring_str(x) -#define LEN(x) VSTRING_LEN(x) - - /* - * VERP command name. - */ -#define VERP_CMD "XVERP" -#define VERP_CMD_LEN 5 - -static NAMADR_LIST *verp_clients; - - /* - * XCLIENT command. Access control is cached, so that XCLIENT can't override - * its own access control. - */ -static NAMADR_LIST *xclient_hosts; -static int xclient_allowed; - - /* - * XFORWARD command. Access control is cached. - */ -static NAMADR_LIST *xforward_hosts; -static int xforward_allowed; - - /* - * Client connection and rate limiting. - */ -#ifdef SNAPSHOT -ANVIL_CLNT *anvil_clnt; -static NAMADR_LIST *hogger_list; - -#endif - - /* - * Other application-specific globals. - */ -int smtpd_input_transp_mask; - - /* - * Forward declarations. - */ -static void helo_reset(SMTPD_STATE *); -static void mail_reset(SMTPD_STATE *); -static void rcpt_reset(SMTPD_STATE *); -static void chat_reset(SMTPD_STATE *, int); - -#ifdef USE_SASL_AUTH - - /* - * SASL exceptions. - */ -static NAMADR_LIST *sasl_exceptions_networks; - -/* sasl_client_exception - can we offer AUTH for this client */ - -static int sasl_client_exception(SMTPD_STATE *state) -{ - int match; - - /* - * This is to work around a Netscape mail client bug where it tries to - * use AUTH if available, even if user has not configured it. Returns - * TRUE if AUTH should be offered in the EHLO. - */ - if (sasl_exceptions_networks == 0) - return (0); - - match = namadr_list_match(sasl_exceptions_networks, - state->name, state->addr); - - if (msg_verbose) - msg_info("sasl_exceptions: %s[%s], match=%d", - state->name, state->addr, match); - - return (match); -} - -#endif - -/* collapse_args - put arguments together again */ - -static void collapse_args(int argc, SMTPD_TOKEN *argv) -{ - int i; - - for (i = 1; i < argc; i++) { - vstring_strcat(argv[0].vstrval, " "); - vstring_strcat(argv[0].vstrval, argv[i].strval); - } - argv[0].strval = STR(argv[0].vstrval); -} - -/* helo_cmd - process HELO command */ - -static int helo_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) -{ - char *err; - - if (argc < 2) { - state->error_mask |= MAIL_ERROR_PROTOCOL; - smtpd_chat_reply(state, "501 Syntax: HELO hostname"); - return (-1); - } - if (argc > 2) - collapse_args(argc - 1, argv + 1); - if (SMTPD_STAND_ALONE(state) == 0 - && var_smtpd_delay_reject == 0 - && (err = smtpd_check_helo(state, argv[1].strval)) != 0) { - smtpd_chat_reply(state, "%s", err); - return (-1); - } - if (state->helo_name != 0) - helo_reset(state); - chat_reset(state, var_smtpd_hist_thrsh); - mail_reset(state); - rcpt_reset(state); - state->helo_name = mystrdup(printable(argv[1].strval, '?')); - neuter(state->helo_name, "<>()\\\";:@", '?'); - /* Downgrading the protocol name breaks the unauthorized pipelining test. */ - if (strcasecmp(state->protocol, MAIL_PROTO_ESMTP) != 0 - && strcasecmp(state->protocol, MAIL_PROTO_SMTP) != 0) { - myfree(state->protocol); - state->protocol = mystrdup(MAIL_PROTO_SMTP); - } - smtpd_chat_reply(state, "250 %s", var_myhostname); - return (0); -} - -/* ehlo_cmd - process EHLO command */ - -static int ehlo_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) -{ - char *err; - - /* - * XXX 2821 new feature: Section 4.1.4 specifies that a server must clear - * all buffers and reset the state exactly as if a RSET command had been - * issued. - */ - if (argc < 2) { - state->error_mask |= MAIL_ERROR_PROTOCOL; - smtpd_chat_reply(state, "501 Syntax: EHLO hostname"); - return (-1); - } - if (argc > 2) - collapse_args(argc - 1, argv + 1); - if (SMTPD_STAND_ALONE(state) == 0 - && var_smtpd_delay_reject == 0 - && (err = smtpd_check_helo(state, argv[1].strval)) != 0) { - smtpd_chat_reply(state, "%s", err); - return (-1); - } - if (state->helo_name != 0) - helo_reset(state); - chat_reset(state, var_smtpd_hist_thrsh); - mail_reset(state); - rcpt_reset(state); - state->helo_name = mystrdup(printable(argv[1].strval, '?')); - neuter(state->helo_name, "<>()\\\";:@", '?'); - if (strcasecmp(state->protocol, MAIL_PROTO_ESMTP) != 0) { - myfree(state->protocol); - state->protocol = mystrdup(MAIL_PROTO_ESMTP); - } - smtpd_chat_reply(state, "250-%s", var_myhostname); - smtpd_chat_reply(state, "250-PIPELINING"); - if (var_message_limit) - smtpd_chat_reply(state, "250-SIZE %lu", - (unsigned long) var_message_limit); /* XXX */ - else - smtpd_chat_reply(state, "250-SIZE"); - if (var_disable_vrfy_cmd == 0) - smtpd_chat_reply(state, "250-VRFY"); - smtpd_chat_reply(state, "250-ETRN"); -#ifdef USE_SASL_AUTH - if (var_smtpd_sasl_enable && !sasl_client_exception(state)) { - smtpd_chat_reply(state, "250-AUTH %s", state->sasl_mechanism_list); - if (var_broken_auth_clients) - smtpd_chat_reply(state, "250-AUTH=%s", state->sasl_mechanism_list); - } -#endif - if (namadr_list_match(verp_clients, state->name, state->addr)) - smtpd_chat_reply(state, "250-%s", VERP_CMD); - /* XCLIENT must not override its own access control. */ - if (xclient_allowed) - smtpd_chat_reply(state, "250-" XCLIENT_CMD - " " XCLIENT_NAME " " XCLIENT_ADDR - " " XCLIENT_PROTO " " XCLIENT_HELO); - if (xforward_allowed) - smtpd_chat_reply(state, "250-" XFORWARD_CMD - " " XFORWARD_NAME " " XFORWARD_ADDR - " " XFORWARD_PROTO " " XFORWARD_HELO); - smtpd_chat_reply(state, "250 8BITMIME"); - return (0); -} - -/* helo_reset - reset HELO/EHLO command stuff */ - -static void helo_reset(SMTPD_STATE *state) -{ - if (state->helo_name) - myfree(state->helo_name); - state->helo_name = 0; -} - -/* mail_open_stream - open mail queue file or IPC stream */ - -static void mail_open_stream(SMTPD_STATE *state) -{ - char *postdrop_command; - int cleanup_flags; - - /* - * XXX 2821: An SMTP server is not allowed to "clean up" mail except in - * the case of original submissions. Presently, Postfix always runs all - * mail through the cleanup server. - * - * We could approximate the RFC as follows: Postfix rewrites mail if it - * comes from a source that we are willing to relay for. This way, we - * avoid rewriting most mail that comes from elsewhere. However, that - * requires moving functionality away from the cleanup daemon elsewhere, - * such as virtual address expansion, and header/body pattern matching. - */ - - /* - * If running from the master or from inetd, connect to the cleanup - * service. - */ - cleanup_flags = CLEANUP_FLAG_MASK_EXTERNAL; - if (smtpd_input_transp_mask & INPUT_TRANSP_ADDRESS_MAPPING) - cleanup_flags &= ~(CLEANUP_FLAG_BCC_OK | CLEANUP_FLAG_MAP_OK); - if (smtpd_input_transp_mask & INPUT_TRANSP_HEADER_BODY) - cleanup_flags &= ~CLEANUP_FLAG_FILTER; - - if (SMTPD_STAND_ALONE(state) == 0) { - state->dest = mail_stream_service(MAIL_CLASS_PUBLIC, - var_cleanup_service); - if (state->dest == 0 - || attr_print(state->dest->stream, ATTR_FLAG_NONE, - ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, cleanup_flags, - ATTR_TYPE_END) != 0) - msg_fatal("unable to connect to the %s %s service", - MAIL_CLASS_PUBLIC, var_cleanup_service); - } - - /* - * Otherwise, pipe the message through the privileged postdrop helper. - * XXX Make postdrop a manifest constant. - */ - else { - postdrop_command = concatenate(var_command_dir, "/postdrop", - msg_verbose ? " -v" : (char *) 0, (char *) 0); - state->dest = mail_stream_command(postdrop_command); - if (state->dest == 0) - msg_fatal("unable to execute %s", postdrop_command); - myfree(postdrop_command); - } - state->cleanup = state->dest->stream; - state->queue_id = mystrdup(state->dest->id); - - /* - * Record the time of arrival, the sender envelope address, some session - * information, and some additional attributes. - */ - if (SMTPD_STAND_ALONE(state) == 0) { - rec_fprintf(state->cleanup, REC_TYPE_TIME, "%ld", state->time); - if (*var_filter_xport) - rec_fprintf(state->cleanup, REC_TYPE_FILT, "%s", var_filter_xport); - } - rec_fputs(state->cleanup, REC_TYPE_FROM, state->sender); - if (state->encoding != 0) - rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", - MAIL_ATTR_ENCODING, state->encoding); - - /* - * Store the client attributes for logging purposes. - */ - if (SMTPD_STAND_ALONE(state) == 0) { - if (IS_AVAIL_CLIENT_NAME(FORWARD_NAME(state))) - rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", - MAIL_ATTR_CLIENT_NAME, FORWARD_NAME(state)); - if (IS_AVAIL_CLIENT_ADDR(FORWARD_ADDR(state))) - rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", - MAIL_ATTR_CLIENT_ADDR, FORWARD_ADDR(state)); - if (IS_AVAIL_CLIENT_NAMADDR(FORWARD_NAMADDR(state))) - rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", - MAIL_ATTR_ORIGIN, FORWARD_NAMADDR(state)); - if (IS_AVAIL_CLIENT_HELO(FORWARD_HELO(state))) - rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", - MAIL_ATTR_HELO_NAME, FORWARD_HELO(state)); - if (IS_AVAIL_CLIENT_PROTO(FORWARD_PROTO(state))) - rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s", - MAIL_ATTR_PROTO_NAME, FORWARD_PROTO(state)); - } - if (state->verp_delims) - rec_fputs(state->cleanup, REC_TYPE_VERP, state->verp_delims); -} - -/* extract_addr - extract address from rubble */ - -static char *extract_addr(SMTPD_STATE *state, SMTPD_TOKEN *arg, - int allow_empty_addr, int strict_rfc821) -{ - char *myname = "extract_addr"; - TOK822 *tree; - TOK822 *tp; - TOK822 *addr = 0; - int naddr; - int non_addr; - char *err = 0; - char *junk = 0; - char *text; - char *colon; - - /* - * Special case. - */ -#define PERMIT_EMPTY_ADDR 1 -#define REJECT_EMPTY_ADDR 0 - - /* - * Some mailers send RFC822-style address forms (with comments and such) - * in SMTP envelopes. We cannot blame users for this: the blame is with - * programmers violating the RFC, and with sendmail for being permissive. - * - * XXX The SMTP command tokenizer must leave the address in externalized - * (quoted) form, so that the address parser can correctly extract the - * address from surrounding junk. - * - * XXX We have only one address parser, written according to the rules of - * RFC 822. That standard differs subtly from RFC 821. - */ - if (msg_verbose) - msg_info("%s: input: %s", myname, STR(arg->vstrval)); - if (STR(arg->vstrval)[0] == '<' - && STR(arg->vstrval)[LEN(arg->vstrval) - 1] == '>') { - junk = text = mystrndup(STR(arg->vstrval) + 1, LEN(arg->vstrval) - 2); - } else - text = STR(arg->vstrval); - - /* - * Truncate deprecated route address form. - */ - if (*text == '@' && (colon = strchr(text, ':')) != 0) - text = colon + 1; - tree = tok822_parse(text); - - if (junk) - myfree(junk); - - /* - * Find trouble. - */ - for (naddr = non_addr = 0, tp = tree; tp != 0; tp = tp->next) { - if (tp->type == TOK822_ADDR) { - addr = tp; - naddr += 1; /* count address forms */ - } else if (tp->type == '<' || tp->type == '>') { - /* void */ ; /* ignore brackets */ - } else { - non_addr += 1; /* count non-address forms */ - } - } - - /* - * Report trouble. Log a warning only if we are going to sleep+reject so - * that attackers can't flood our logfiles. - */ - if (naddr > 1 - || (strict_rfc821 && (non_addr || *STR(arg->vstrval) != '<'))) { - msg_warn("Illegal address syntax from %s in %s command: %s", - state->namaddr, state->where, STR(arg->vstrval)); - err = "501 Bad address syntax"; - } - - /* - * Overwrite the input with the extracted address. This seems bad design, - * but we really are not going to use the original data anymore. What we - * start with is quoted (external) form, and what we need is unquoted - * (internal form). - */ - if (addr) - tok822_internalize(arg->vstrval, addr->head, TOK822_STR_DEFL); - else - vstring_strcpy(arg->vstrval, ""); - arg->strval = STR(arg->vstrval); - - /* - * Report trouble. Log a warning only if we are going to sleep+reject so - * that attackers can't flood our logfiles. - */ - if (err == 0) - if ((arg->strval[0] == 0 && !allow_empty_addr) - || (strict_rfc821 && arg->strval[0] == '@') - || (SMTPD_STAND_ALONE(state) == 0 - && smtpd_check_addr(STR(arg->vstrval)) != 0)) { - msg_warn("Illegal address syntax from %s in %s command: %s", - state->namaddr, state->where, STR(arg->vstrval)); - err = "501 Bad address syntax"; - } - - /* - * Cleanup. - */ - tok822_free_tree(tree); - if (msg_verbose) - msg_info("%s: result: %s", myname, STR(arg->vstrval)); - return (err); -} - -/* mail_cmd - process MAIL command */ - -static int mail_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) -{ - char *err; - int narg; - char *arg; - char *verp_delims = 0; - - state->encoding = 0; - - /* - * Sanity checks. - * - * XXX 2821 pedantism: Section 4.1.2 says that SMTP servers that receive a - * command in which invalid character codes have been employed, and for - * which there are no other reasons for rejection, MUST reject that - * command with a 501 response. So much for the principle of "be liberal - * in what you accept, be strict in what you send". - */ - if (var_helo_required && state->helo_name == 0) { - state->error_mask |= MAIL_ERROR_POLICY; - smtpd_chat_reply(state, "503 Error: send HELO/EHLO first"); - return (-1); - } -#define IN_MAIL_TRANSACTION(state) ((state)->sender != 0) - - if (IN_MAIL_TRANSACTION(state)) { - state->error_mask |= MAIL_ERROR_PROTOCOL; - smtpd_chat_reply(state, "503 Error: nested MAIL command"); - return (-1); - } - if (argc < 3 - || strcasecmp(argv[1].strval, "from:") != 0) { - state->error_mask |= MAIL_ERROR_PROTOCOL; - smtpd_chat_reply(state, "501 Syntax: MAIL FROM:
"); - return (-1); - } - if (argv[2].tokval == SMTPD_TOK_ERROR) { - state->error_mask |= MAIL_ERROR_PROTOCOL; - smtpd_chat_reply(state, "501 Bad sender address syntax"); - return (-1); - } - if ((err = extract_addr(state, argv + 2, PERMIT_EMPTY_ADDR, var_strict_rfc821_env)) != 0) { - state->error_mask |= MAIL_ERROR_PROTOCOL; - smtpd_chat_reply(state, "%s", err); - return (-1); - } - for (narg = 3; narg < argc; narg++) { - arg = argv[narg].strval; - if (strcasecmp(arg, "BODY=8BITMIME") == 0) { /* RFC 1652 */ - state->encoding = MAIL_ATTR_ENC_8BIT; - } else if (strcasecmp(arg, "BODY=7BIT") == 0) { /* RFC 1652 */ - state->encoding = MAIL_ATTR_ENC_7BIT; - } else if (strncasecmp(arg, "SIZE=", 5) == 0) { /* RFC 1870 */ - /* Reject non-numeric size. */ - if (!alldig(arg + 5)) { - state->error_mask |= MAIL_ERROR_PROTOCOL; - smtpd_chat_reply(state, "501 Bad message size syntax"); - return (-1); - } - /* Reject size overflow. */ - if ((state->msg_size = off_cvt_string(arg + 5)) < 0) { - smtpd_chat_reply(state, "552 Message size exceeds file system imposed limit"); - state->error_mask |= MAIL_ERROR_POLICY; - return (-1); - } -#ifdef USE_SASL_AUTH - } else if (var_smtpd_sasl_enable && strncasecmp(arg, "AUTH=", 5) == 0) { - if ((err = smtpd_sasl_mail_opt(state, arg + 5)) != 0) { - smtpd_chat_reply(state, "%s", err); - return (-1); - } -#endif - } else if (namadr_list_match(verp_clients, state->name, state->addr) - && strncasecmp(arg, VERP_CMD, VERP_CMD_LEN) == 0 - && (arg[VERP_CMD_LEN] == '=' || arg[VERP_CMD_LEN] == 0)) { - if (arg[VERP_CMD_LEN] == 0) { - verp_delims = var_verp_delims; - } else { - verp_delims = arg + VERP_CMD_LEN + 1; - if (verp_delims_verify(verp_delims) != 0) { - state->error_mask |= MAIL_ERROR_PROTOCOL; - smtpd_chat_reply(state, "501 Error: %s needs two characters from %s", - VERP_CMD, var_verp_filter); - return (-1); - } - } - } else { - state->error_mask |= MAIL_ERROR_PROTOCOL; - smtpd_chat_reply(state, "555 Unsupported option: %s", arg); - return (-1); - } - } - if (verp_delims && argv[2].strval[0] == 0) { - smtpd_chat_reply(state, "503 Error: %s requires non-null sender", - VERP_CMD); - return (-1); - } - if (SMTPD_STAND_ALONE(state) == 0 - && var_smtpd_delay_reject == 0 - && (err = smtpd_check_mail(state, argv[2].strval)) != 0) { - smtpd_chat_reply(state, "%s", err); - /* XXX Reset access map side effects. */ - mail_reset(state); - return (-1); - } - - /* - * Check the queue file space, if applicable. - */ - if (!USE_SMTPD_PROXY(state)) { - if ((err = smtpd_check_size(state, state->msg_size)) != 0) { - smtpd_chat_reply(state, "%s", err); - return (-1); - } - } - - /* - * No more early returns. The mail transaction is in progress. - */ - state->time = time((time_t *) 0); - state->sender = mystrdup(argv[2].strval); - vstring_sprintf(state->instance, "%x.%lx.%x", - var_pid, (unsigned long) state->time, state->seqno++); - if (verp_delims) - state->verp_delims = mystrdup(verp_delims); - if (USE_SMTPD_PROXY(state)) - state->proxy_mail = mystrdup(STR(state->buffer)); - smtpd_chat_reply(state, "250 Ok"); - return (0); -} - -/* mail_reset - reset MAIL command stuff */ - -static void mail_reset(SMTPD_STATE *state) -{ - state->msg_size = 0; - - /* - * Unceremoniously close the pipe to the cleanup service. The cleanup - * service will delete the queue file when it detects a premature - * end-of-file condition on input. - */ - if (state->cleanup != 0) { - mail_stream_cleanup(state->dest); - state->dest = 0; - state->cleanup = 0; - } - state->err = 0; - if (state->queue_id != 0) { - myfree(state->queue_id); - state->queue_id = 0; - } - if (state->sender) { - myfree(state->sender); - state->sender = 0; - } - if (state->verp_delims) { - myfree(state->verp_delims); - state->verp_delims = 0; - } - if (state->proxy_mail) { - myfree(state->proxy_mail); - state->proxy_mail = 0; - } - if (state->saved_filter) { - myfree(state->saved_filter); - state->saved_filter = 0; - } - if (state->saved_redirect) { - myfree(state->saved_redirect); - state->saved_redirect = 0; - } - state->saved_flags = 0; -#ifdef USE_SASL_AUTH - if (var_smtpd_sasl_enable) - smtpd_sasl_mail_reset(state); -#endif - state->discard = 0; - VSTRING_RESET(state->instance); - VSTRING_TERMINATE(state->instance); - - /* - * Try to be nice. Don't bother when we lost the connection. Don't bother - * waiting for a reply, it just increases latency. - */ - if (state->proxy) { - (void) smtpd_proxy_cmd(state, SMTPD_PROX_WANT_NONE, "QUIT"); - smtpd_proxy_close(state); - } - if (state->xforward.flags) - smtpd_xforward_reset(state); - if (state->prepend) - state->prepend = argv_free(state->prepend); -} - -/* rcpt_cmd - process RCPT TO command */ - -static int rcpt_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) -{ - char *err; - int narg; - char *arg; - - /* - * Sanity checks. - * - * XXX 2821 pedantism: Section 4.1.2 says that SMTP servers that receive a - * command in which invalid character codes have been employed, and for - * which there are no other reasons for rejection, MUST reject that - * command with a 501 response. So much for the principle of "be liberal - * in what you accept, be strict in what you send". - */ - if (!IN_MAIL_TRANSACTION(state)) { - state->error_mask |= MAIL_ERROR_PROTOCOL; - smtpd_chat_reply(state, "503 Error: need MAIL command"); - return (-1); - } - if (argc < 3 - || strcasecmp(argv[1].strval, "to:") != 0) { - state->error_mask |= MAIL_ERROR_PROTOCOL; - smtpd_chat_reply(state, "501 Syntax: RCPT TO:
"); - return (-1); - } - if (argv[2].tokval == SMTPD_TOK_ERROR) { - state->error_mask |= MAIL_ERROR_PROTOCOL; - smtpd_chat_reply(state, "501 Bad recipient address syntax"); - return (-1); - } - if ((err = extract_addr(state, argv + 2, REJECT_EMPTY_ADDR, var_strict_rfc821_env)) != 0) { - state->error_mask |= MAIL_ERROR_PROTOCOL; - smtpd_chat_reply(state, "%s", err); - return (-1); - } - for (narg = 3; narg < argc; narg++) { - arg = argv[narg].strval; - if (1) { - state->error_mask |= MAIL_ERROR_PROTOCOL; - smtpd_chat_reply(state, "555 Unsupported option: %s", arg); - return (-1); - } - } - if (var_smtpd_rcpt_limit && state->rcpt_count >= var_smtpd_rcpt_limit) { - smtpd_chat_reply(state, "452 Error: too many recipients"); - if (state->rcpt_overshoot++ < var_smtpd_rcpt_overlim) - return (0); - state->error_mask |= MAIL_ERROR_POLICY; - return (-1); - } - if (SMTPD_STAND_ALONE(state) == 0) { - if ((err = smtpd_check_rcpt(state, argv[2].strval)) != 0) { - smtpd_chat_reply(state, "%s", err); - return (-1); - } - } - - /* - * Don't access the proxy, queue file, or queue file writer process until - * we have a valid recipient address. - */ - if (state->proxy == 0 && state->cleanup == 0) { - if (state->proxy_mail) { - if (smtpd_proxy_open(state, var_smtpd_proxy_filt, - var_smtpd_proxy_tmout, var_smtpd_proxy_ehlo, - state->proxy_mail) != 0) { - smtpd_chat_reply(state, "%s", STR(state->proxy_buffer)); - return (-1); - } - } else { - mail_open_stream(state); - } - - /* - * Log the queue ID with the message origin. - */ -#ifdef USE_SASL_AUTH - if (var_smtpd_sasl_enable) - smtpd_sasl_mail_log(state); - else -#endif - msg_info("%s: client=%s", state->queue_id ? - state->queue_id : "NOQUEUE", FORWARD_NAMADDR(state)); - } - - /* - * Proxy the recipient. OK, so we lied. If the real-time proxy rejects - * the recipient then we can have a proxy connection without having - * accepted a recipient. - */ - if (state->proxy && smtpd_proxy_cmd(state, SMTPD_PROX_WANT_OK, - "%s", STR(state->buffer)) != 0) { - smtpd_chat_reply(state, "%s", STR(state->proxy_buffer)); - return (-1); - } - - /* - * Store the recipient. Remember the first one. - * - * Flush recipients to maintain a stiffer coupling with the next stage and - * to better utilize parallelism. - */ - state->rcpt_count++; - if (state->recipient == 0) - state->recipient = mystrdup(argv[2].strval); - if (state->cleanup) { - rec_fputs(state->cleanup, REC_TYPE_RCPT, argv[2].strval); - vstream_fflush(state->cleanup); - } - smtpd_chat_reply(state, "250 Ok"); - return (0); -} - -/* rcpt_reset - reset RCPT stuff */ - -static void rcpt_reset(SMTPD_STATE *state) -{ - if (state->recipient) { - myfree(state->recipient); - state->recipient = 0; - } - state->rcpt_count = 0; - /* XXX Must flush the command history. */ - state->rcpt_overshoot = 0; -} - -/* data_cmd - process DATA command */ - -static int data_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv) -{ - char *err; - char *start; - int len; - int curr_rec_type; - int prev_rec_type; - int first = 1; - VSTRING *why = 0; - int saved_err; - int (*out_record) (VSTREAM *, int, const char *, int); - int (*out_fprintf) (VSTREAM *, int, const char *,...); - VSTREAM *out_stream; - int out_error; - char **cpp; - - /* - * Sanity checks. With ESMTP command pipelining the client can send DATA - * before all recipients are rejected, so don't report that as a protocol - * error. - */ - if (state->rcpt_count == 0) { - if (!IN_MAIL_TRANSACTION(state)) { - state->error_mask |= MAIL_ERROR_PROTOCOL; - smtpd_chat_reply(state, "503 Error: need RCPT command"); - } else { - smtpd_chat_reply(state, "554 Error: no valid recipients"); - } - return (-1); - } - if (argc != 1) { - state->error_mask |= MAIL_ERROR_PROTOCOL; - smtpd_chat_reply(state, "501 Syntax: DATA"); - return (-1); - } - if (SMTPD_STAND_ALONE(state) == 0 && (err = smtpd_check_data(state)) != 0) { - smtpd_chat_reply(state, "%s", err); - return (-1); - } - if (state->proxy && smtpd_proxy_cmd(state, SMTPD_PROX_WANT_MORE, - "%s", STR(state->buffer)) != 0) { - smtpd_chat_reply(state, "%s", STR(state->proxy_buffer)); - return (-1); - } - - /* - * One level of indirection to choose between normal or proxied - * operation. We want to avoid massive code duplication within tons of - * if-else clauses. - */ - if (state->proxy) { - out_stream = state->proxy; - out_record = smtpd_proxy_rec_put; - out_fprintf = smtpd_proxy_rec_fprintf; - out_error = CLEANUP_STAT_PROXY; - } else { - out_stream = state->cleanup; - out_record = rec_put; - out_fprintf = rec_fprintf; - out_error = CLEANUP_STAT_WRITE; - } - - /* - * Flush out any access table actions that are delegated to the cleanup - * server, and that may trigger before we accept the first valid - * recipient. - * - * Terminate the message envelope segment. Start the message content - * segment, and prepend our own Received: header. If there is only one - * recipient, list the recipient address. - */ - if (state->cleanup) { - if (state->saved_filter) - rec_fprintf(state->cleanup, REC_TYPE_FILT, "%s", state->saved_filter); - if (state->saved_redirect) - rec_fprintf(state->cleanup, REC_TYPE_RDR, "%s", state->saved_redirect); - if (state->saved_flags) - rec_fprintf(state->cleanup, REC_TYPE_FLGS, "%d", state->saved_flags); - rec_fputs(state->cleanup, REC_TYPE_MESG, ""); - } - - /* - * PREPEND message headers. - */ - if (state->prepend) - for (cpp = state->prepend->argv; *cpp; cpp++) - out_fprintf(out_stream, REC_TYPE_NORM, "%s", *cpp); - - /* - * Suppress our own Received: header in the unlikely case that we are an - * intermediate proxy. - */ - if (!state->proxy || state->xforward.flags == 0) { - out_fprintf(out_stream, REC_TYPE_NORM, - "Received: from %s (%s [%s])", - state->helo_name ? state->helo_name : state->name, - state->name, state->addr); - if (state->rcpt_count == 1 && state->recipient) { - out_fprintf(out_stream, REC_TYPE_NORM, - state->cleanup ? "\tby %s (%s) with %s id %s" : - "\tby %s (%s) with %s", - var_myhostname, var_mail_name, - state->protocol, state->queue_id); - quote_822_local(state->buffer, state->recipient); - out_fprintf(out_stream, REC_TYPE_NORM, - "\tfor <%s>; %s", STR(state->buffer), mail_date(state->time)); - } else { - out_fprintf(out_stream, REC_TYPE_NORM, - state->cleanup ? "\tby %s (%s) with %s id %s;" : - "\tby %s (%s) with %s;", - var_myhostname, var_mail_name, - state->protocol, state->queue_id); - out_fprintf(out_stream, REC_TYPE_NORM, - "\t%s", mail_date(state->time)); - } -#ifdef RECEIVED_ENVELOPE_FROM - quote_822_local(state->buffer, state->sender); - out_fprintf(out_stream, REC_TYPE_NORM, - "\t(envelope-from %s)", STR(state->buffer)); -#endif - } - smtpd_chat_reply(state, "354 End data with ."); - - /* - * Copy the message content. If the cleanup process has a problem, keep - * reading until the remote stops sending, then complain. Produce typed - * records from the SMTP stream so we can handle data that spans buffers. - * - * XXX Force an empty record when the queue file content begins with - * whitespace, so that it won't be considered as being part of our own - * Received: header. What an ugly Kluge. - * - * XXX Deal with UNIX-style From_ lines at the start of message content - * because sendmail permits it. - */ - for (prev_rec_type = 0; /* void */ ; prev_rec_type = curr_rec_type) { - if (smtp_get(state->buffer, state->client, var_line_limit) == '\n') - curr_rec_type = REC_TYPE_NORM; - else - curr_rec_type = REC_TYPE_CONT; - start = vstring_str(state->buffer); - len = VSTRING_LEN(state->buffer); - if (first) { - if (strncmp(start + strspn(start, ">"), "From ", 5) == 0) { - out_fprintf(out_stream, curr_rec_type, - "X-Mailbox-Line: %s", start); - continue; - } - first = 0; - if (len > 0 && IS_SPACE_TAB(start[0])) - out_record(out_stream, REC_TYPE_NORM, "", 0); - } - if (prev_rec_type != REC_TYPE_CONT && *start == '.' - && (state->proxy == 0 ? (++start, --len) == 0 : len == 1)) - break; - if (state->err == CLEANUP_STAT_OK - && out_record(out_stream, curr_rec_type, start, len) < 0) - state->err = out_error; - } - - /* - * Send the end of DATA and finish the proxy connection. Set the - * CLEANUP_STAT_PROXY error flag in case of trouble. - * - * XXX The low-level proxy output routines should set "state" error - * attributes. This requires making "state" a context attribute of the - * VSTREAM. - */ - if (state->proxy) { - if (state->err == CLEANUP_STAT_OK) { - (void) smtpd_proxy_cmd(state, SMTPD_PROX_WANT_ANY, "."); - if (state->err == CLEANUP_STAT_OK && - *STR(state->proxy_buffer) != '2') - state->err = CLEANUP_STAT_CONT; - } else { - state->error_mask |= MAIL_ERROR_SOFTWARE; - state->err |= CLEANUP_STAT_PROXY; - vstring_sprintf(state->proxy_buffer, - "451 Error: queue file write error"); - } - } - - /* - * Send the end-of-segment markers and finish the queue file record - * stream. - */ - else { - if (state->err == CLEANUP_STAT_OK) - if (rec_fputs(state->cleanup, REC_TYPE_XTRA, "") < 0 - || rec_fputs(state->cleanup, REC_TYPE_END, "") < 0 - || vstream_fflush(state->cleanup)) - state->err = CLEANUP_STAT_WRITE; - if (state->err == 0) { - why = vstring_alloc(10); - state->err = mail_stream_finish(state->dest, why); - } else - mail_stream_cleanup(state->dest); - state->dest = 0; - state->cleanup = 0; - } - - /* - * Handle any errors. One message may suffer from multiple errors, so - * complain only about the most severe error. Forgive any previous client - * errors when a message was received successfully. - * - * See also: qmqpd.c - */ - if (state->err == CLEANUP_STAT_OK) { - state->error_count = 0; - state->error_mask = 0; - state->junk_cmds = 0; - if (state->queue_id) - smtpd_chat_reply(state, "250 Ok: queued as %s", state->queue_id); - else - smtpd_chat_reply(state, "%s", STR(state->proxy_buffer)); - } else if ((state->err & CLEANUP_STAT_BAD) != 0) { - state->error_mask |= MAIL_ERROR_SOFTWARE; - smtpd_chat_reply(state, "451 Error: internal error %d", state->err); - } else if ((state->err & CLEANUP_STAT_SIZE) != 0) { - state->error_mask |= MAIL_ERROR_BOUNCE; - smtpd_chat_reply(state, "552 Error: message too large"); - } else if ((state->err & CLEANUP_STAT_HOPS) != 0) { - state->error_mask |= MAIL_ERROR_BOUNCE; - smtpd_chat_reply(state, "554 Error: too many hops"); - } else if ((state->err & CLEANUP_STAT_CONT) != 0) { - state->error_mask |= MAIL_ERROR_POLICY; - if (state->proxy_buffer) - smtpd_chat_reply(state, "%s", STR(state->proxy_buffer)); - else - smtpd_chat_reply(state, "550 Error: %s", LEN(why) ? - STR(why) : "content rejected"); - } else if ((state->err & CLEANUP_STAT_WRITE) != 0) { - state->error_mask |= MAIL_ERROR_RESOURCE; - smtpd_chat_reply(state, "451 Error: queue file write error"); - } else if ((state->err & CLEANUP_STAT_PROXY) != 0) { - state->error_mask |= MAIL_ERROR_SOFTWARE; - smtpd_chat_reply(state, "%s", STR(state->proxy_buffer)); - } else { - state->error_mask |= MAIL_ERROR_SOFTWARE; - smtpd_chat_reply(state, "451 Error: internal error %d", state->err); - } - - /* - * Disconnect after transmission must not be treated as "lost connection - * after DATA". - */ - state->where = SMTPD_AFTER_DOT; - - /* - * Cleanup. The client may send another MAIL command. - */ - saved_err = state->err; - chat_reset(state, var_smtpd_hist_thrsh); - mail_reset(state); - rcpt_reset(state); - if (why) - vstring_free(why); - return (saved_err); -} - -/* rset_cmd - process RSET */ - -static int rset_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv) -{ - - /* - * Sanity checks. - */ - if (argc != 1) { - state->error_mask |= MAIL_ERROR_PROTOCOL; - smtpd_chat_reply(state, "501 Syntax: RSET"); - return (-1); - } - - /* - * Restore state to right after HELO/EHLO command. - */ - chat_reset(state, var_smtpd_hist_thrsh); - mail_reset(state); - rcpt_reset(state); - smtpd_chat_reply(state, "250 Ok"); - return (0); -} - -/* noop_cmd - process NOOP */ - -static int noop_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv) -{ - - /* - * XXX 2821 incompatibility: Section 4.1.1.9 says that NOOP can have a - * parameter string which is to be ignored. NOOP instructions with - * parameters? Go figure. - * - * RFC 2821 violates RFC 821, which says that NOOP takes no parameters. - */ -#ifdef RFC821_SYNTAX - - /* - * Sanity checks. - */ - if (argc != 1) { - state->error_mask |= MAIL_ERROR_PROTOCOL; - smtpd_chat_reply(state, "501 Syntax: NOOP"); - return (-1); - } -#endif - smtpd_chat_reply(state, "250 Ok"); - return (0); -} - -/* vrfy_cmd - process VRFY */ - -static int vrfy_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) -{ - char *err = 0; - - /* - * The SMTP standard (RFC 821) disallows unquoted special characters in - * the VRFY argument. Common practice violates the standard, however. - * Postfix accomodates common practice where it violates the standard. - * - * XXX Impedance mismatch! The SMTP command tokenizer preserves quoting, - * whereas the recipient restrictions checks expect unquoted (internal) - * address forms. Therefore we must parse out the address, or we must - * stop doing recipient restriction checks and lose the opportunity to - * say "user unknown" at the SMTP port. - * - * XXX 2821 incompatibility and brain damage: Section 4.5.1 requires that - * VRFY is implemented. RFC 821 specifies that VRFY is optional. It gets - * even worse: section 3.5.3 says that a 502 (command recognized but not - * implemented) reply is not fully compliant. - * - * Thus, an RFC 2821 compliant implementation cannot refuse to supply - * information in reply to VRFY queries. That is simply bogus. The only - * reply we could supply is a generic 252 reply. This causes spammers to - * add tons of bogus addresses to their mailing lists (spam harvesting by - * trying out large lists of potential recipient names with VRFY). - */ -#define SLOPPY 0 - - if (var_disable_vrfy_cmd) { - state->error_mask |= MAIL_ERROR_POLICY; - smtpd_chat_reply(state, "502 VRFY command is disabled"); - return (-1); - } - if (argc < 2) { - state->error_mask |= MAIL_ERROR_PROTOCOL; - smtpd_chat_reply(state, "501 Syntax: VRFY address"); - return (-1); - } - if (argc > 2) - collapse_args(argc - 1, argv + 1); - if ((err = extract_addr(state, argv + 1, REJECT_EMPTY_ADDR, SLOPPY)) != 0) { - state->error_mask |= MAIL_ERROR_PROTOCOL; - smtpd_chat_reply(state, "%s", err); - return (-1); - } - if (SMTPD_STAND_ALONE(state) == 0 - && (err = smtpd_check_rcpt(state, argv[1].strval)) != 0) { - smtpd_chat_reply(state, "%s", err); - return (-1); - } - - /* - * XXX 2821 new feature: Section 3.5.1 requires that the VRFY response is - * either "full name " or "user@domain". Postfix replies - * with the address that was provided by the client, whether or not it is - * in fully qualified domain form or not. - * - * Reply code 250 is reserved for the case where the address is verified; - * reply code 252 should be used when no definitive certainty exists. - */ - smtpd_chat_reply(state, "252 %s", argv[1].strval); - return (0); -} - -/* etrn_cmd - process ETRN command */ - -static int etrn_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) -{ - char *err; - - /* - * Sanity checks. - */ - if (var_helo_required && state->helo_name == 0) { - state->error_mask |= MAIL_ERROR_POLICY; - smtpd_chat_reply(state, "503 Error: send HELO/EHLO first"); - return (-1); - } - if (IN_MAIL_TRANSACTION(state)) { - state->error_mask |= MAIL_ERROR_PROTOCOL; - smtpd_chat_reply(state, "503 Error: MAIL transaction in progress"); - return (-1); - } - if (argc != 2) { - state->error_mask |= MAIL_ERROR_PROTOCOL; - smtpd_chat_reply(state, "500 Syntax: ETRN domain"); - return (-1); - } - if (!ISALNUM(argv[1].strval[0])) - argv[1].strval++; - if (!valid_hostname(argv[1].strval, DONT_GRIPE)) { - state->error_mask |= MAIL_ERROR_PROTOCOL; - smtpd_chat_reply(state, "501 Error: invalid parameter syntax"); - return (-1); - } - - /* - * XXX The implementation borrows heavily from the code that implements - * UCE restrictions. These typically return 450 or 550 when a request is - * rejected. RFC 1985 requires that 459 be sent when the server refuses - * to perform the request. - */ - if (SMTPD_STAND_ALONE(state)) { - msg_warn("do not use ETRN in \"sendmail -bs\" mode"); - smtpd_chat_reply(state, "458 Unable to queue messages"); - return (-1); - } - if ((err = smtpd_check_etrn(state, argv[1].strval)) != 0) { - smtpd_chat_reply(state, "%s", err); - return (-1); - } - switch (flush_send(argv[1].strval)) { - case FLUSH_STAT_OK: - smtpd_chat_reply(state, "250 Queuing started"); - return (0); - case FLUSH_STAT_DENY: - msg_warn("reject: ETRN %.100s... from %s", - argv[1].strval, state->namaddr); - smtpd_chat_reply(state, "459 <%s>: service unavailable", - argv[1].strval); - return (-1); - case FLUSH_STAT_BAD: - msg_warn("bad ETRN %.100s... from %s", argv[1].strval, state->namaddr); - smtpd_chat_reply(state, "458 Unable to queue messages"); - return (-1); - default: - msg_warn("unable to talk to fast flush service"); - smtpd_chat_reply(state, "458 Unable to queue messages"); - return (-1); - } -} - -/* quit_cmd - process QUIT command */ - -static int quit_cmd(SMTPD_STATE *state, int unused_argc, SMTPD_TOKEN *unused_argv) -{ - - /* - * Don't bother checking the syntax. - */ - smtpd_chat_reply(state, "221 Bye"); - - /* - * When the "." and quit replies are pipelined, make sure they are - * flushed now, to avoid repeated mail deliveries in case of a crash in - * the "clean up before disconnect" code. - */ - vstream_fflush(state->client); - return (0); -} - -/* xclient_cmd - override SMTP client attributes */ - -static int xclient_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) -{ - SMTPD_TOKEN *argp; - char *attr_value; - char *attr_name; - int update_namaddr = 0; - int peer_code; - static NAME_CODE peer_codes[] = { - XCLIENT_UNAVAILABLE, SMTPD_PEER_CODE_PERM, - XCLIENT_TEMPORARY, SMTPD_PEER_CODE_TEMP, - 0, SMTPD_PEER_CODE_OK, - }; - static NAME_CODE proto_names[] = { - MAIL_PROTO_SMTP, 1, - MAIL_PROTO_ESMTP, 2, - 0, -1, - }; - - /* - * Sanity checks. The XCLIENT command does not override its own access - * control. - */ - if (IN_MAIL_TRANSACTION(state)) { - state->error_mask |= MAIL_ERROR_PROTOCOL; - smtpd_chat_reply(state, "503 Error: MAIL transaction in progress"); - return (-1); - } - if (argc < 2) { - state->error_mask |= MAIL_ERROR_PROTOCOL; - smtpd_chat_reply(state, "501 Syntax: %s attribute=value...", - XCLIENT_CMD); - return (-1); - } - if (!xclient_allowed) { - state->error_mask |= MAIL_ERROR_POLICY; - smtpd_chat_reply(state, "554 Error: insufficient authorization"); - return (-1); - } -#define STREQ(x,y) (strcasecmp((x), (y)) == 0) -#define UPDATE_STR(s, v) do { \ - if (s) myfree(s); \ - s = (v) ? mystrdup(v) : 0; \ - } while(0) -#define NEUTER_CHARACTERS "<>()\\\";:@" - - /* - * Iterate over all attribute=value elements. - */ - for (argp = argv + 1; argp < argv + argc; argp++) { - attr_name = argp->strval; - - /* - * For safety's sake mask non-printable characters. We'll do more - * specific censoring later. - */ - if ((attr_value = split_at(attr_name, '=')) == 0 || *attr_value == 0) { - state->error_mask |= MAIL_ERROR_PROTOCOL; - smtpd_chat_reply(state, "501 Error: attribute=value expected"); - return (-1); - } - printable(attr_value, '?'); - - /* - * NAME=substitute SMTP client hostname. Also updates the client - * hostname lookup status code. - */ - if (STREQ(attr_name, XCLIENT_NAME)) { - peer_code = name_code(peer_codes, NAME_CODE_FLAG_NONE, attr_value); - if (peer_code != SMTPD_PEER_CODE_OK) { - attr_value = CLIENT_NAME_UNKNOWN; - } else { - if (!valid_hostname(attr_value, DONT_GRIPE) - || valid_hostaddr(attr_value, DONT_GRIPE)) { - state->error_mask |= MAIL_ERROR_PROTOCOL; - smtpd_chat_reply(state, "501 Bad %s syntax: %s", - XCLIENT_NAME, attr_value); - return (-1); - } - } - state->peer_code = peer_code; - UPDATE_STR(state->name, attr_value); - update_namaddr = 1; - } - - /* - * ADDR=substitute SMTP client network address. - */ - else if (STREQ(attr_name, XCLIENT_ADDR)) { - if (STREQ(attr_value, XCLIENT_UNAVAILABLE)) { - attr_value = CLIENT_ADDR_UNKNOWN; - } else { - if (!valid_hostaddr(attr_value, DONT_GRIPE)) { - state->error_mask |= MAIL_ERROR_PROTOCOL; - smtpd_chat_reply(state, "501 Bad %s syntax: %s", - XCLIENT_ADDR, attr_value); - return (-1); - } - } - UPDATE_STR(state->addr, attr_value); - update_namaddr = 1; - } - - /* - * HELO=substitute SMTP client HELO parameter. Censor special - * characters that could mess up message headers. - */ - else if (STREQ(attr_name, XCLIENT_HELO)) { - if (STREQ(attr_value, XCLIENT_UNAVAILABLE)) { - attr_value = CLIENT_HELO_UNKNOWN; - } else { - if (strlen(attr_value) > VALID_HOSTNAME_LEN) { - state->error_mask |= MAIL_ERROR_PROTOCOL; - smtpd_chat_reply(state, "501 Bad %s syntax: %s", - XCLIENT_HELO, attr_value); - return (-1); - } - neuter(attr_value, NEUTER_CHARACTERS, '?'); - } - UPDATE_STR(state->helo_name, attr_value); - } - - /* - * PROTO=SMTP protocol name. - */ - else if (STREQ(attr_name, XCLIENT_PROTO)) { - if (name_code(proto_names, NAME_CODE_FLAG_NONE, attr_value) < 0) { - state->error_mask |= MAIL_ERROR_PROTOCOL; - smtpd_chat_reply(state, "501 Bad %s syntax: %s", - XCLIENT_PROTO, attr_value); - return (-1); - } - UPDATE_STR(state->protocol, uppercase(attr_value)); - } - - /* - * Unknown attribute name. Complain. - */ - else { - state->error_mask |= MAIL_ERROR_PROTOCOL; - smtpd_chat_reply(state, "501 Bad %s attribute name: %s", - XCLIENT_CMD, attr_name); - return (-1); - } - } - - /* - * Update the combined name and address when either has changed. - */ - if (update_namaddr) { - if (state->namaddr) - myfree(state->namaddr); - state->namaddr = - concatenate(state->name, "[", state->addr, "]", (char *) 0); - } - smtpd_chat_reply(state, "250 Ok"); - return (0); -} - -/* xforward_cmd - forward logging attributes */ - -static int xforward_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) -{ - SMTPD_TOKEN *argp; - char *attr_value; - char *attr_name; - int updated = 0; - static NAME_CODE xforward_flags[] = { - XFORWARD_NAME, SMTPD_STATE_XFORWARD_NAME, - XFORWARD_ADDR, SMTPD_STATE_XFORWARD_ADDR, - XFORWARD_PROTO, SMTPD_STATE_XFORWARD_PROTO, - XFORWARD_HELO, SMTPD_STATE_XFORWARD_HELO, - 0, 0, - }; - int flag; - - /* - * Sanity checks. - */ - if (IN_MAIL_TRANSACTION(state)) { - state->error_mask |= MAIL_ERROR_PROTOCOL; - smtpd_chat_reply(state, "503 Error: MAIL transaction in progress"); - return (-1); - } - if (argc < 2) { - state->error_mask |= MAIL_ERROR_PROTOCOL; - smtpd_chat_reply(state, "501 Syntax: %s attribute=value...", - XFORWARD_CMD); - return (-1); - } - if (!xforward_allowed) { - state->error_mask |= MAIL_ERROR_POLICY; - smtpd_chat_reply(state, "554 Error: insufficient authorization"); - return (-1); - } - - /* - * Initialize. - */ - if (state->xforward.flags == 0) - smtpd_xforward_preset(state); - - /* - * Iterate over all attribute=value elements. - */ - for (argp = argv + 1; argp < argv + argc; argp++) { - attr_name = argp->strval; - - /* - * For safety's sake mask non-printable characters. We'll do more - * specific censoring later. - */ - if ((attr_value = split_at(attr_name, '=')) == 0 || *attr_value == 0) { - state->error_mask |= MAIL_ERROR_PROTOCOL; - smtpd_chat_reply(state, "501 Error: attribute=value expected"); - return (-1); - } - if (strlen(attr_value) > 255) { - state->error_mask |= MAIL_ERROR_PROTOCOL; - smtpd_chat_reply(state, "501 Error: attribute value too long"); - return (-1); - } - printable(attr_value, '?'); - - flag = name_code(xforward_flags, NAME_CODE_FLAG_NONE, attr_name); - switch (flag) { - - /* - * NAME=up-stream host name, not necessarily in the DNS. Censor - * special characters that could mess up message headers. - */ - case SMTPD_STATE_XFORWARD_NAME: - if (STREQ(attr_value, XFORWARD_UNAVAILABLE)) { - attr_value = CLIENT_NAME_UNKNOWN; - } else { - neuter(attr_value, NEUTER_CHARACTERS, '?'); - } - UPDATE_STR(state->xforward.name, attr_value); - break; - - /* - * ADDR=up-stream host network address, not necessarily on the - * Internet. Censor special characters that could mess up message - * headers. - */ - case SMTPD_STATE_XFORWARD_ADDR: - if (STREQ(attr_value, XFORWARD_UNAVAILABLE)) { - attr_value = CLIENT_ADDR_UNKNOWN; - } else { - neuter(attr_value, NEUTER_CHARACTERS, '?'); - } - UPDATE_STR(state->xforward.addr, attr_value); - break; - - /* - * HELO=hostname that the up-stream MTA introduced itself with - * (not necessarily SMTP HELO). Censor special characters that - * could mess up message headers. - */ - case SMTPD_STATE_XFORWARD_HELO: - if (STREQ(attr_value, XFORWARD_UNAVAILABLE)) { - attr_value = CLIENT_HELO_UNKNOWN; - } else { - neuter(attr_value, NEUTER_CHARACTERS, '?'); - } - UPDATE_STR(state->xforward.helo_name, attr_value); - break; - - /* - * PROTO=up-stream protocol, not necessarily SMTP or ESMTP. - * Censor special characters that could mess up message headers. - */ - case SMTPD_STATE_XFORWARD_PROTO: - if (STREQ(attr_value, XFORWARD_UNAVAILABLE)) { - attr_value = CLIENT_PROTO_UNKNOWN; - } else { - if (strlen(attr_value) > 64) { - state->error_mask |= MAIL_ERROR_PROTOCOL; - smtpd_chat_reply(state, "501 Bad %s syntax: %s", - XFORWARD_PROTO, attr_value); - return (-1); - } - neuter(attr_value, NEUTER_CHARACTERS, '?'); - } - UPDATE_STR(state->xforward.protocol, attr_value); - break; - - /* - * Unknown attribute name. Complain. - */ - default: - state->error_mask |= MAIL_ERROR_PROTOCOL; - smtpd_chat_reply(state, "501 Bad %s attribute name: %s", - XFORWARD_CMD, attr_name); - return (-1); - } - updated |= flag; - } - state->xforward.flags |= updated; - - /* - * Update the combined name and address when either has changed. Use only - * the name when no address is available. - */ - if (updated & (SMTPD_STATE_XFORWARD_NAME | SMTPD_STATE_XFORWARD_ADDR)) { - if (state->xforward.namaddr) - myfree(state->xforward.namaddr); - state->xforward.namaddr = - IS_AVAIL_CLIENT_ADDR(state->xforward.addr) ? - concatenate(state->xforward.name, "[", - state->xforward.addr, "]", - (char *) 0) : mystrdup(state->xforward.name); - } - smtpd_chat_reply(state, "250 Ok"); - return (0); -} - -/* chat_reset - notify postmaster and reset conversation log */ - -static void chat_reset(SMTPD_STATE *state, int threshold) -{ - - /* - * Notify the postmaster if there were errors. This usually indicates a - * client configuration problem, or that someone is trying nasty things. - * Either is significant enough to bother the postmaster. XXX Can't - * report problems when running in stand-alone mode: postmaster notices - * require availability of the cleanup service. - */ - if (state->history != 0 && state->history->argc > threshold) { - if (SMTPD_STAND_ALONE(state) == 0 - && (state->error_mask & state->notify_mask)) - smtpd_chat_notify(state); - state->error_mask = 0; - smtpd_chat_reset(state); - } -} - - /* - * The table of all SMTP commands that we know. Set the junk limit flag on - * any command that can be repeated an arbitrary number of times without - * triggering a tarpit delay of some sort. - */ -typedef struct SMTPD_CMD { - char *name; - int (*action) (SMTPD_STATE *, int, SMTPD_TOKEN *); - int flags; -} SMTPD_CMD; - -#define SMTPD_CMD_FLAG_LIMIT (1<<0) /* limit usage */ -#define SMTPD_CMD_FLAG_FORBID (1<<1) /* RFC 2822 mail header */ - -static SMTPD_CMD smtpd_cmd_table[] = { - "HELO", helo_cmd, SMTPD_CMD_FLAG_LIMIT, - "EHLO", ehlo_cmd, SMTPD_CMD_FLAG_LIMIT, - -#ifdef USE_SASL_AUTH - "AUTH", smtpd_sasl_auth_cmd, 0, -#endif - - "MAIL", mail_cmd, 0, - "RCPT", rcpt_cmd, 0, - "DATA", data_cmd, 0, - "RSET", rset_cmd, SMTPD_CMD_FLAG_LIMIT, - "NOOP", noop_cmd, SMTPD_CMD_FLAG_LIMIT, - "VRFY", vrfy_cmd, SMTPD_CMD_FLAG_LIMIT, - "ETRN", etrn_cmd, SMTPD_CMD_FLAG_LIMIT, - "QUIT", quit_cmd, 0, - "XCLIENT", xclient_cmd, SMTPD_CMD_FLAG_LIMIT, - "XFORWARD", xforward_cmd, SMTPD_CMD_FLAG_LIMIT, - "Received:", 0, SMTPD_CMD_FLAG_FORBID, - "Reply-To:", 0, SMTPD_CMD_FLAG_FORBID, - "Message-ID:", 0, SMTPD_CMD_FLAG_FORBID, - "Subject:", 0, SMTPD_CMD_FLAG_FORBID, - "From:", 0, SMTPD_CMD_FLAG_FORBID, - "CONNECT", 0, SMTPD_CMD_FLAG_FORBID, - "User-Agent:", 0, SMTPD_CMD_FLAG_FORBID, - 0, -}; - -static STRING_LIST *smtpd_noop_cmds; - -/* smtpd_proto - talk the SMTP protocol */ - -static void smtpd_proto(SMTPD_STATE *state, const char *service) -{ - int argc; - SMTPD_TOKEN *argv; - SMTPD_CMD *cmdp; - int count; - int crate; - - /* - * Print a greeting banner and run the state machine. Read SMTP commands - * one line at a time. According to the standard, a sender or recipient - * address could contain an escaped newline. I think this is perverse, - * and anyone depending on this is really asking for trouble. - * - * In case of mail protocol trouble, the program jumps back to this place, - * so that it can perform the necessary cleanup before talking to the - * next client. The setjmp/longjmp primitives are like a sharp tool: use - * with care. I would certainly recommend against the use of - * setjmp/longjmp in programs that change privilege levels. - * - * In case of file system trouble the program terminates after logging the - * error and after informing the client. In all other cases (out of - * memory, panic) the error is logged, and the msg_cleanup() exit handler - * cleans up, but no attempt is made to inform the client of the nature - * of the problem. - */ - smtp_timeout_setup(state->client, var_smtpd_tmout); - - switch (vstream_setjmp(state->client)) { - - default: - msg_panic("smtpd_proto: unknown error reading from %s[%s]", - state->name, state->addr); - break; - - case SMTP_ERR_TIME: - state->reason = "timeout"; - smtpd_chat_reply(state, "421 %s Error: timeout exceeded", - var_myhostname); - break; - - case SMTP_ERR_EOF: - state->reason = "lost connection"; - break; - - case 0: - - /* - * XXX The client connection count/rate control must be consistent in - * its use of client address information in connect and disconnect - * events. For now we exclude xclient authorized hosts from - * connection count/rate control. - */ -#ifdef SNAPSHOT - if (SMTPD_STAND_ALONE(state) == 0 - && !xclient_allowed - && anvil_clnt - && !namadr_list_match(hogger_list, state->name, state->addr) - && anvil_clnt_connect(anvil_clnt, service, state->addr, - &count, &crate) == ANVIL_STAT_OK) { - if (var_smtpd_cconn_limit > 0 && count > var_smtpd_cconn_limit) { - smtpd_chat_reply(state, "421 %s Error: too many connections from %s", - var_myhostname, state->addr); - msg_warn("Too many connections: %d from %s for service %s", - count, state->namaddr, service); - break; - } - if (var_smtpd_crate_limit > 0 && crate > var_smtpd_crate_limit) { - smtpd_chat_reply(state, "421 %s Error: too many connections from %s", - var_myhostname, state->addr); - msg_warn("Too frequent connections: %d from %s for service %s", - crate, state->namaddr, service); - break; - } - } -#endif - /* XXX We use the real client for connect access control. */ - if (SMTPD_STAND_ALONE(state) == 0 - && var_smtpd_delay_reject == 0 - && (state->access_denied = smtpd_check_client(state)) != 0) { - smtpd_chat_reply(state, "%s", state->access_denied); - } else { - smtpd_chat_reply(state, "220 %s", var_smtpd_banner); - } - - for (;;) { - if (state->error_count >= var_smtpd_hard_erlim) { - state->reason = "too many errors"; - state->error_mask |= MAIL_ERROR_PROTOCOL; - smtpd_chat_reply(state, "421 %s Error: too many errors", - var_myhostname); - break; - } - watchdog_pat(); - smtpd_chat_query(state); - if ((argc = smtpd_token(vstring_str(state->buffer), &argv)) == 0) { - state->error_mask |= MAIL_ERROR_PROTOCOL; - smtpd_chat_reply(state, "500 Error: bad syntax"); - state->error_count++; - continue; - } - if (*var_smtpd_noop_cmds - && string_list_match(smtpd_noop_cmds, argv[0].strval)) { - smtpd_chat_reply(state, "250 Ok"); - if (state->junk_cmds++ > var_smtpd_junk_cmd_limit) - state->error_count++; - continue; - } - for (cmdp = smtpd_cmd_table; cmdp->name != 0; cmdp++) - if (strcasecmp(argv[0].strval, cmdp->name) == 0) - break; - if (cmdp->name == 0) { - smtpd_chat_reply(state, "502 Error: command not implemented"); - state->error_mask |= MAIL_ERROR_PROTOCOL; - state->error_count++; - continue; - } - if (cmdp->flags & SMTPD_CMD_FLAG_FORBID) { - msg_warn("%s sent non-SMTP command: %.100s", - state->namaddr, vstring_str(state->buffer)); - smtpd_chat_reply(state, "221 Error: I can break rules, too. Goodbye."); - break; - } - /* XXX We use the real client for connect access control. */ - if (state->access_denied && cmdp->action != quit_cmd) { - smtpd_chat_reply(state, "503 Error: access denied for %s", - state->namaddr); /* RFC 2821 Sec 3.1 */ - state->error_count++; - continue; - } - state->where = cmdp->name; - if (cmdp->action(state, argc, argv) != 0) - state->error_count++; - if ((cmdp->flags & SMTPD_CMD_FLAG_LIMIT) - && state->junk_cmds++ > var_smtpd_junk_cmd_limit) - state->error_count++; - if (cmdp->action == quit_cmd) - break; - } - break; - } - - /* - * XXX The client connection count/rate control must be consistent in its - * use of client address information in connect and disconnect events. - * For now we exclude xclient authorized hosts from connection count/rate - * control. - */ -#ifdef SNAPSHOT - if (SMTPD_STAND_ALONE(state) == 0 - && !xclient_allowed - && anvil_clnt - && !namadr_list_match(hogger_list, state->name, state->addr)) - anvil_clnt_disconnect(anvil_clnt, service, state->addr); -#endif - - /* - * Log abnormal session termination, in case postmaster notification has - * been turned off. In the log, indicate the last recognized state before - * things went wrong. Don't complain about clients that go away without - * sending QUIT. - */ - if (state->reason && state->where - && (strcmp(state->where, SMTPD_AFTER_DOT) - || strcmp(state->reason, "lost connection"))) - msg_info("%s after %s from %s[%s]", - state->reason, state->where, state->name, state->addr); - - /* - * Cleanup whatever information the client gave us during the SMTP - * dialog. - */ - helo_reset(state); -#ifdef USE_SASL_AUTH - if (var_smtpd_sasl_enable) - smtpd_sasl_auth_reset(state); -#endif - chat_reset(state, 0); - mail_reset(state); - rcpt_reset(state); -} - -/* smtpd_service - service one client */ - -static void smtpd_service(VSTREAM *stream, char *service, char **argv) -{ - SMTPD_STATE state; - - /* - * Sanity check. This service takes no command-line arguments. - */ - if (argv[0]) - msg_fatal("unexpected command-line argument: %s", argv[0]); - - /* - * This routine runs when a client has connected to our network port, or - * when the smtp server is run in stand-alone mode (input from pipe). - * - * Look up and sanitize the peer name, then initialize some connection- - * specific state. When the name service is hosed, hostname lookup will - * take a while. This is why I always run a local name server on critical - * machines. - */ - smtpd_state_init(&state, stream); - msg_info("connect from %s[%s]", state.name, state.addr); - - /* - * XCLIENT must not override its own access control. - */ - xclient_allowed = - namadr_list_match(xclient_hosts, state.name, state.addr); - - /* - * Overriding XFORWARD access control makes no sense, either. - */ - xforward_allowed = - namadr_list_match(xforward_hosts, state.name, state.addr); - - /* - * See if we need to turn on verbose logging for this client. - */ - debug_peer_check(state.name, state.addr); - - /* - * Provide the SMTP service. - */ - smtpd_proto(&state, service); - - /* - * After the client has gone away, clean up whatever we have set up at - * connection time. - */ - msg_info("disconnect from %s[%s]", state.name, state.addr); - smtpd_state_reset(&state); - debug_peer_restore(); -} - -/* pre_accept - see if tables have changed */ - -static void pre_accept(char *unused_name, char **unused_argv) -{ - const char *table; - - if ((table = dict_changed_name()) != 0) { - msg_info("table %s has changed -- restarting", table); - exit(0); - } -} - -/* pre_jail_init - pre-jail initialization */ - -static void pre_jail_init(char *unused_name, char **unused_argv) -{ - - /* - * Initialize blacklist/etc. patterns before entering the chroot jail, in - * case they specify a filename pattern. - */ - smtpd_noop_cmds = string_list_init(MATCH_FLAG_NONE, var_smtpd_noop_cmds); - verp_clients = namadr_list_init(MATCH_FLAG_NONE, var_verp_clients); - xclient_hosts = namadr_list_init(MATCH_FLAG_NONE, var_xclient_hosts); - xforward_hosts = namadr_list_init(MATCH_FLAG_NONE, var_xforward_hosts); -#ifdef SNAPSHOT - hogger_list = namadr_list_init(MATCH_FLAG_NONE, var_smtpd_hoggers); -#endif - if (getuid() == 0 || getuid() == var_owner_uid) - smtpd_check_init(); - debug_peer_init(); - - if (var_smtpd_sasl_enable) -#ifdef USE_SASL_AUTH - smtpd_sasl_initialize(); - - if (*var_smtpd_sasl_exceptions_networks) - sasl_exceptions_networks = - namadr_list_init(MATCH_FLAG_NONE, - var_smtpd_sasl_exceptions_networks); -#else - msg_warn("%s is true, but SASL support is not compiled in", - VAR_SMTPD_SASL_ENABLE); -#endif - - /* - * flush client. - */ - flush_init(); -} - -/* post_jail_init - post-jail initialization */ - -static void post_jail_init(char *unused_name, char **unused_argv) -{ - - /* - * Initialize the receive transparency options: do we want unknown - * recipient checks, address mapping, header_body_checks?. - */ - smtpd_input_transp_mask = - input_transp_mask(VAR_INPUT_TRANSP, var_input_transp); - - /* - * Sanity checks. The queue_minfree value should be at least as large as - * (process_limit * message_size_limit) but that is unpractical, so we - * arbitrarily pick a number and require twice the message size limit. - */ - if (var_queue_minfree > 0 - && var_message_limit > 0 - && var_queue_minfree / 1.5 < var_message_limit) - msg_warn("%s(%lu) should be at least 1.5*%s(%lu)", - VAR_QUEUE_MINFREE, (unsigned long) var_queue_minfree, - VAR_MESSAGE_LIMIT, (unsigned long) var_message_limit); - - /* - * Connection rate management. - */ -#ifdef SNAPSHOT - if (var_smtpd_crate_limit || var_smtpd_cconn_limit) - anvil_clnt = anvil_clnt_create(); -#endif -} - -/* main - the main program */ - -int main(int argc, char **argv) -{ - static CONFIG_INT_TABLE int_table[] = { - VAR_SMTPD_RCPT_LIMIT, DEF_SMTPD_RCPT_LIMIT, &var_smtpd_rcpt_limit, 1, 0, - VAR_SMTPD_SOFT_ERLIM, DEF_SMTPD_SOFT_ERLIM, &var_smtpd_soft_erlim, 1, 0, - VAR_SMTPD_HARD_ERLIM, DEF_SMTPD_HARD_ERLIM, &var_smtpd_hard_erlim, 1, 0, - VAR_QUEUE_MINFREE, DEF_QUEUE_MINFREE, &var_queue_minfree, 0, 0, - VAR_UNK_CLIENT_CODE, DEF_UNK_CLIENT_CODE, &var_unk_client_code, 0, 0, - VAR_BAD_NAME_CODE, DEF_BAD_NAME_CODE, &var_bad_name_code, 0, 0, - VAR_UNK_NAME_CODE, DEF_UNK_NAME_CODE, &var_unk_name_code, 0, 0, - VAR_UNK_ADDR_CODE, DEF_UNK_ADDR_CODE, &var_unk_addr_code, 0, 0, - VAR_RELAY_CODE, DEF_RELAY_CODE, &var_relay_code, 0, 0, - VAR_MAPS_RBL_CODE, DEF_MAPS_RBL_CODE, &var_maps_rbl_code, 0, 0, - VAR_ACCESS_MAP_CODE, DEF_ACCESS_MAP_CODE, &var_access_map_code, 0, 0, - VAR_REJECT_CODE, DEF_REJECT_CODE, &var_reject_code, 0, 0, - VAR_DEFER_CODE, DEF_DEFER_CODE, &var_defer_code, 0, 0, - VAR_NON_FQDN_CODE, DEF_NON_FQDN_CODE, &var_non_fqdn_code, 0, 0, - VAR_SMTPD_JUNK_CMD, DEF_SMTPD_JUNK_CMD, &var_smtpd_junk_cmd_limit, 1, 0, - VAR_SMTPD_RCPT_OVERLIM, DEF_SMTPD_RCPT_OVERLIM, &var_smtpd_rcpt_overlim, 1, 0, - VAR_SMTPD_HIST_THRSH, DEF_SMTPD_HIST_THRSH, &var_smtpd_hist_thrsh, 1, 0, - VAR_UNV_FROM_CODE, DEF_UNV_FROM_CODE, &var_unv_from_code, 0, 0, - VAR_UNV_RCPT_CODE, DEF_UNV_RCPT_CODE, &var_unv_rcpt_code, 0, 0, - VAR_MUL_RCPT_CODE, DEF_MUL_RCPT_CODE, &var_mul_rcpt_code, 0, 0, - VAR_LOCAL_RCPT_CODE, DEF_LOCAL_RCPT_CODE, &var_local_rcpt_code, 0, 0, - VAR_VIRT_ALIAS_CODE, DEF_VIRT_ALIAS_CODE, &var_virt_alias_code, 0, 0, - VAR_VIRT_MAILBOX_CODE, DEF_VIRT_MAILBOX_CODE, &var_virt_mailbox_code, 0, 0, - VAR_RELAY_RCPT_CODE, DEF_RELAY_RCPT_CODE, &var_relay_rcpt_code, 0, 0, - VAR_VERIFY_POLL_COUNT, DEF_VERIFY_POLL_COUNT, &var_verify_poll_count, 1, 0, -#ifdef SNAPSHOT - VAR_SMTPD_CRATE_LIMIT, DEF_SMTPD_CRATE_LIMIT, &var_smtpd_crate_limit, 0, 0, - VAR_SMTPD_CCONN_LIMIT, DEF_SMTPD_CCONN_LIMIT, &var_smtpd_cconn_limit, 0, 0, -#endif - 0, - }; - static CONFIG_TIME_TABLE time_table[] = { - VAR_SMTPD_TMOUT, DEF_SMTPD_TMOUT, &var_smtpd_tmout, 1, 0, - VAR_SMTPD_ERR_SLEEP, DEF_SMTPD_ERR_SLEEP, &var_smtpd_err_sleep, 0, 0, - VAR_SMTPD_PROXY_TMOUT, DEF_SMTPD_PROXY_TMOUT, &var_smtpd_proxy_tmout, 1, 0, - VAR_VERIFY_POLL_DELAY, DEF_VERIFY_POLL_DELAY, &var_verify_poll_delay, 1, 0, - VAR_SMTPD_POLICY_TMOUT, DEF_SMTPD_POLICY_TMOUT, &var_smtpd_policy_tmout, 1, 0, - VAR_SMTPD_POLICY_IDLE, DEF_SMTPD_POLICY_IDLE, &var_smtpd_policy_idle, 1, 0, - VAR_SMTPD_POLICY_TTL, DEF_SMTPD_POLICY_TTL, &var_smtpd_policy_ttl, 1, 0, - 0, - }; - static CONFIG_BOOL_TABLE bool_table[] = { - VAR_HELO_REQUIRED, DEF_HELO_REQUIRED, &var_helo_required, - VAR_SMTPD_DELAY_REJECT, DEF_SMTPD_DELAY_REJECT, &var_smtpd_delay_reject, - VAR_STRICT_RFC821_ENV, DEF_STRICT_RFC821_ENV, &var_strict_rfc821_env, - VAR_DISABLE_VRFY_CMD, DEF_DISABLE_VRFY_CMD, &var_disable_vrfy_cmd, - VAR_ALLOW_UNTRUST_ROUTE, DEF_ALLOW_UNTRUST_ROUTE, &var_allow_untrust_route, - VAR_SMTPD_SASL_ENABLE, DEF_SMTPD_SASL_ENABLE, &var_smtpd_sasl_enable, - VAR_BROKEN_AUTH_CLNTS, DEF_BROKEN_AUTH_CLNTS, &var_broken_auth_clients, - VAR_SHOW_UNK_RCPT_TABLE, DEF_SHOW_UNK_RCPT_TABLE, &var_show_unk_rcpt_table, - VAR_SMTPD_REJ_UNL_FROM, DEF_SMTPD_REJ_UNL_FROM, &var_smtpd_rej_unl_from, - VAR_SMTPD_REJ_UNL_RCPT, DEF_SMTPD_REJ_UNL_RCPT, &var_smtpd_rej_unl_rcpt, - 0, - }; - static CONFIG_STR_TABLE str_table[] = { - VAR_SMTPD_BANNER, DEF_SMTPD_BANNER, &var_smtpd_banner, 1, 0, - VAR_NOTIFY_CLASSES, DEF_NOTIFY_CLASSES, &var_notify_classes, 0, 0, - VAR_CLIENT_CHECKS, DEF_CLIENT_CHECKS, &var_client_checks, 0, 0, - VAR_HELO_CHECKS, DEF_HELO_CHECKS, &var_helo_checks, 0, 0, - VAR_MAIL_CHECKS, DEF_MAIL_CHECKS, &var_mail_checks, 0, 0, - VAR_RCPT_CHECKS, DEF_RCPT_CHECKS, &var_rcpt_checks, 0, 0, - VAR_ETRN_CHECKS, DEF_ETRN_CHECKS, &var_etrn_checks, 0, 0, - VAR_DATA_CHECKS, DEF_DATA_CHECKS, &var_data_checks, 0, 0, - VAR_MAPS_RBL_DOMAINS, DEF_MAPS_RBL_DOMAINS, &var_maps_rbl_domains, 0, 0, - VAR_RBL_REPLY_MAPS, DEF_RBL_REPLY_MAPS, &var_rbl_reply_maps, 0, 0, - VAR_ERROR_RCPT, DEF_ERROR_RCPT, &var_error_rcpt, 1, 0, - VAR_REST_CLASSES, DEF_REST_CLASSES, &var_rest_classes, 0, 0, - VAR_CANONICAL_MAPS, DEF_CANONICAL_MAPS, &var_canonical_maps, 0, 0, - VAR_RCPT_CANON_MAPS, DEF_RCPT_CANON_MAPS, &var_rcpt_canon_maps, 0, 0, - VAR_VIRT_ALIAS_MAPS, DEF_VIRT_ALIAS_MAPS, &var_virt_alias_maps, 0, 0, - VAR_VIRT_MAILBOX_MAPS, DEF_VIRT_MAILBOX_MAPS, &var_virt_mailbox_maps, 0, 0, - VAR_ALIAS_MAPS, DEF_ALIAS_MAPS, &var_alias_maps, 0, 0, - VAR_LOCAL_RCPT_MAPS, DEF_LOCAL_RCPT_MAPS, &var_local_rcpt_maps, 0, 0, - VAR_SMTPD_SASL_OPTS, DEF_SMTPD_SASL_OPTS, &var_smtpd_sasl_opts, 0, 0, - VAR_SMTPD_SASL_APPNAME, DEF_SMTPD_SASL_APPNAME, &var_smtpd_sasl_appname, 1, 0, - VAR_SMTPD_SASL_REALM, DEF_SMTPD_SASL_REALM, &var_smtpd_sasl_realm, 0, 0, - VAR_SMTPD_SASL_EXCEPTIONS_NETWORKS, DEF_SMTPD_SASL_EXCEPTIONS_NETWORKS, &var_smtpd_sasl_exceptions_networks, 0, 0, - VAR_FILTER_XPORT, DEF_FILTER_XPORT, &var_filter_xport, 0, 0, - VAR_PERM_MX_NETWORKS, DEF_PERM_MX_NETWORKS, &var_perm_mx_networks, 0, 0, - VAR_SMTPD_SND_AUTH_MAPS, DEF_SMTPD_SND_AUTH_MAPS, &var_smtpd_snd_auth_maps, 0, 0, - VAR_SMTPD_NOOP_CMDS, DEF_SMTPD_NOOP_CMDS, &var_smtpd_noop_cmds, 0, 0, - VAR_SMTPD_NULL_KEY, DEF_SMTPD_NULL_KEY, &var_smtpd_null_key, 0, 0, - VAR_RELAY_RCPT_MAPS, DEF_RELAY_RCPT_MAPS, &var_relay_rcpt_maps, 0, 0, - VAR_VERIFY_SENDER, DEF_VERIFY_SENDER, &var_verify_sender, 0, 0, - VAR_VERP_CLIENTS, DEF_VERP_CLIENTS, &var_verp_clients, 0, 0, - VAR_SMTPD_PROXY_FILT, DEF_SMTPD_PROXY_FILT, &var_smtpd_proxy_filt, 0, 0, - VAR_SMTPD_PROXY_EHLO, DEF_SMTPD_PROXY_EHLO, &var_smtpd_proxy_ehlo, 0, 0, - VAR_INPUT_TRANSP, DEF_INPUT_TRANSP, &var_input_transp, 0, 0, - VAR_XCLIENT_HOSTS, DEF_XCLIENT_HOSTS, &var_xclient_hosts, 0, 0, - VAR_XFORWARD_HOSTS, DEF_XFORWARD_HOSTS, &var_xforward_hosts, 0, 0, -#ifdef SNAPSHOT - VAR_SMTPD_HOGGERS, DEF_SMTPD_HOGGERS, &var_smtpd_hoggers, 0, 0, -#endif - 0, - }; - static CONFIG_RAW_TABLE raw_table[] = { - VAR_SMTPD_EXP_FILTER, DEF_SMTPD_EXP_FILTER, &var_smtpd_exp_filter, 1, 0, - VAR_DEF_RBL_REPLY, DEF_DEF_RBL_REPLY, &var_def_rbl_reply, 1, 0, - 0, - }; - - /* - * Pass control to the single-threaded service skeleton. - */ - single_server_main(argc, argv, smtpd_service, - MAIL_SERVER_INT_TABLE, int_table, - MAIL_SERVER_STR_TABLE, str_table, - MAIL_SERVER_RAW_TABLE, raw_table, - MAIL_SERVER_BOOL_TABLE, bool_table, - MAIL_SERVER_TIME_TABLE, time_table, - MAIL_SERVER_PRE_INIT, pre_jail_init, - MAIL_SERVER_PRE_ACCEPT, pre_accept, - MAIL_SERVER_POST_INIT, post_jail_init, - 0); -} diff --git a/postfix/mantools/postlink b/postfix/mantools/postlink index bb2d3c9de..6cda6a71a 100755 --- a/postfix/mantools/postlink +++ b/postfix/mantools/postlink @@ -340,6 +340,7 @@ exec sed ' s;[[:<:]]smtpd_junk_command_limit[[:>:]];&;g s;[[:<:]]smtpd_noop_commands[[:>:]];&;g s;[[:<:]]smtpd_null_access_lookup_key[[:>:]];&;g + s;[[:<:]]smtpd_recipient_overshoot_limit[[:>:]];&;g s;[[:<:]]smtpd_policy_service_max_idle[[:>:]];&;g s;[[:<:]]smtpd_policy_service_max_ttl[[:>:]];&;g s;[[:<:]]smtpd_policy_service_timeout[[:>:]];&;g diff --git a/postfix/proto/SMTPD_POLICY_README.html b/postfix/proto/SMTPD_POLICY_README.html index ed2c89269..d406984d2 100644 --- a/postfix/proto/SMTPD_POLICY_README.html +++ b/postfix/proto/SMTPD_POLICY_README.html @@ -216,7 +216,7 @@ TCP sockets instead:

  1 /etc/postfix/master.cf:
- 2     127.0.0.1:9998  unix  -       n       n       -       -       spawn
+ 2     127.0.0.1:9998  inet  n       n       n       -       -       spawn
  3       user=nobody argv=/some/where/policy-server
  4 
  5 /etc/postfix/main.cf:
@@ -340,7 +340,7 @@ client/server configuration" section above.  

 1 /etc/postfix/master.cf:
-2     127.0.0.1:9998  unix  -       n       n       -       -       spawn
+2     127.0.0.1:9998  inet  n       n       n       -       -       spawn
 3       user=nobody argv=/usr/bin/perl /usr/libexec/postfix/greylist.pl
 4 
 5 /etc/postfix/main.cf:
diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h
index d1763601c..61f1eecc2 100644
--- a/postfix/src/global/mail_version.h
+++ b/postfix/src/global/mail_version.h
@@ -20,8 +20,8 @@
   * Patches change the patchlevel and the release date. Snapshots change the
   * release date only.
   */
-#define MAIL_RELEASE_DATE	"20040422"
-#define MAIL_VERSION_NUMBER	"2.1.0"
+#define MAIL_RELEASE_DATE	"20040503"
+#define MAIL_VERSION_NUMBER	"2.1.1"
 
 #define VAR_MAIL_VERSION	"mail_version"
 #ifdef SNAPSHOT
diff --git a/postfix/src/smtpd/smtpd_check.c b/postfix/src/smtpd/smtpd_check.c
index 9c513f109..89b6f0558 100644
--- a/postfix/src/smtpd/smtpd_check.c
+++ b/postfix/src/smtpd/smtpd_check.c
@@ -2870,11 +2870,14 @@ static int check_policy_service(SMTPD_STATE *state, const char *server,
 			  (unsigned long) state->msg_size,
 #ifdef USE_SASL_AUTH
 			  ATTR_TYPE_STR, MAIL_ATTR_SASL_METHOD,
-			  state->sasl_method ? state->sasl_method : "",
+			  var_smtpd_sasl_enable && state->sasl_method ?
+			  state->sasl_method : "",
 			  ATTR_TYPE_STR, MAIL_ATTR_SASL_USERNAME,
-			  state->sasl_username ? state->sasl_username : "",
+			  var_smtpd_sasl_enable && state->sasl_username ?
+			  state->sasl_username : "",
 			  ATTR_TYPE_STR, MAIL_ATTR_SASL_SENDER,
-			  state->sasl_sender ? state->sasl_sender : "",
+			  var_smtpd_sasl_enable && state->sasl_sender ?
+			  state->sasl_sender : "",
 #endif
 			  ATTR_TYPE_END,
 			  ATTR_FLAG_MISSING,	/* Reply attributes. */