FROM: or CC: by From: or Cc:. Files: cleanup/cleanup_message.c,
smtp/smtp_proto.c.
+20050228
+
+ Cleanup/portability: missing #includes and bad prototypes.
+ Matthias Andree, Carsten Hoeger, and others.
+
+20050302
+
+ Workaround: make TLS session caching work with perverse
+ sites that have multiple servers per hostname or even
+ multiple servers per IP address, but no shared TLS session
+ cache. The SMTP client TLS session cache is now indexed by
+ (server hostname, server address, server port, server helo
+ hostname). After an idea by Victor Duchovni. Files:
+ smtp/smtp_proto.c, tls/tls_client.c.
+
+20050303
+
+ Bugfix (bug inherited from Postfix/TLS patch): a rare 9kbyte
+ memory leak when in-memory TLS session information expires;
+ found by setting the expiry time shorter than the time to
+ deliver one or two messages with a very slow machine. This
+ was due to a missing SSL_SESSION_free() call in the "new
+ session" call-back routines. Found by Victor Duchovni.
+ Files: tls/tls_client.c, tls/tls_server.c.
+
+ Workaround: OpenSSL is overly agressive when purging a
+ not-yet expired entry from a full in-memory cache: it also
+ purges the entry from the on-disk server session cache.
+ Workaround is to let only the tlsmgr purge entries from the
+ on-disk server session cache. Found by Victor Duchovni.
+ File: tls/tls_server.c.
+
+20050304
+
+ Postfix releases are now signed with Wietse's new PGP key.
+ The old key was getting a bit short for today's standards.
+ The new public key can be found on the Postfix download
+ webpage. As proof of authenticity the new PGP key is signed
+ with Wietse's old PGP key.
+
Open problems:
Med: disable header address rewriting after XCLIENT?
Introduce a better concept of original submission?
- Low: 9kbyte memory leak when expired in-memory session
- information is removed by SSL_CTX_flush_sessions(); found
- by setting the expiry time shorter than the time to deliver
- one or two messages. Postfix processes are short-lived,
- and the occurrance of this leak is rare enough that it is
- a low priority.
-
Low: configurable order of local(8) delivery methods.
Med: local and remote source port and IP address for smtpd
-The official Postfix release is called 2.1.x where 2=major release
-number, 1=minor release number, x=patchlevel. Snapshot releases
-are now called 2.2-yyyymmdd where yyyymmdd is the release date
-(yyyy=year, mm=month, dd=day). The mail_release_date configuration
-parameter contains the release date (both for official release and
-snapshot release). Patches are issued for the official release
-and change the patchlevel and the release date. Patches are never
-issued for snapshot releases.
+The stable Postfix release is called postfix-2.2.x where 2=major
+release number, 2=minor release number, x=patchlevel. The stable
+release never changes except for patches that address bugs or
+emergencies. Patches change the patchlevel and the release date.
-Major changes with snapshot Postfix-2.2-20050212
-================================================
+New features are developed in snapshot releases. These are called
+postfix-2.3-yyyymmdd where yyyymmdd is the release date (yyyy=year,
+mm=month, dd=day). Patches are never issued for snapshot releases;
+instead, a new snapshot is released.
-When header address rewriting is enabled, Postfix now updates a
-message header only when at least one address in that header
-is modified. Older Postfix versions first parse and then unparse
-a header so that there may be subtle changes in formatting, such
-as the amount of whitespace between tokens, or in capitalization
-of header labels such as FROM:/CC: because they are not replaced
-by From:/Cc:.
+The mail_release_date configuration parameter (format: yyyymmdd)
+specifies the release date of a stable release or snapshot release.
-Major changes with snapshot Postfix-2.2-20050211
-================================================
-
-The "generics" table feature is renamed to "generic", for consistency
-with other Postfix table names which are also singular.
-
-Major changes with snapshot Postfix-2.2-20050209
-================================================
-
-The policy delegation protocol now supplies TLS client certificate
-information after successful verification. The new attribute names
-are ccert_subject, ccert_issuer and ccert_fingerprint.
-
-Major changes with snapshot Postfix-2.2-20050208
-================================================
-
-New "check_ccert_maps maptype:mapname" feature to enforce access
-control based on (hexadecimal) client certificate fingerprints.
-
-Major changes with snapshot Postfix-2.2-20050206
-================================================
-
-Support for address rewriting in outgoing SMTP mail. This is useful
-for sites that have no valid Internet domain name, and that use a
-domain name such as localdomain.local instead. Mail addresses that
-use such domain names are often rejected by mail servers.
-
-The new smtp_generic_maps feature allows you to replace local mail
-addresses by valid Internet addresses when mail is sent across the
-Internet. It has no effect on mail that is sent between accounts
-on the local machine. The syntax is described in generic(5) and
-a detailed example is in the STANDARD_CONFIGURATION_README file.
-
-Example:
-
-/etc/postfix/main.cf:
- smtp_generic_maps = hash:/etc/postfix/generic
-
-/etc/postfix/generic:
- you@localdomain.local youraccount@yourisp.net
- her@localdomain.local heraccount@herisp.net
- @localdomain.local youraccount+local@yourisp.net
-
-When mail is sent to a remote host via SMTP, this replaces your
-local mail address you@localdomain.local by your ISP mail address,
-replaces her@localdomain.local by her ISP mail address, and replaces
-all other local addresses by your ISP account, with an address
-extension of +local (this example assumes that the ISP supports
-"+" style address extensions).
-
-Major changes with snapshot Postfix-2.2-20050205
-================================================
-
-REPLACE action in header_checks and body_checks. See header_checks(5)
-for details.
-
-Incompatible changes with snapshot Postfix-2.2-20050203
-=======================================================
-
-Postfix rewrites message header addresses only in mail that originates
-from the local machine. Specify "local_header_rewrite_clients =
-static:all" to get the old behavior of Postfix 2.1 and earlier.
-
-All "postfix start" file permission checks are run in the foreground
-while Postfix is started.
-
-Major changes with snapshot Postfix-2.2-20050203
-================================================
-
-To create a ready-to-install package for distribution to other
-systems use "make package" or "make non-interactive-package",
-instead of invoking the postfix-install script by hand (which is
-deprecated). See the PACKAGE_README file for details.
-
-New "permit_inet_interfaces" access restriction to allow access
-from local IP addresses only. This is used for the default, purist,
-setting of local_header_rewrite_clients in the previous paragraph.
-
-New "sleep time-in-seconds" pseudo access restriction to block
-zombie clients with reject_unauthorized_pipelining before the
-Postfix SMTP server sends the SMTP greeting. See postconf(5)
-for example.
-
-Safety: Postfix no longer tries to send mail to the fallback_relay
-when the local machine is MX host for the mail destination. See
-the postconf(5) description of fallback_relay for details.
-
-Incompatible changes with snapshot Postfix-2.2-20050117
-=======================================================
-
-Only the deferred and defer queue directories are hashed by default,
-instead of eight queue directories. With modern file systems, this
-speeds up Postfix boot time without compromising performance under
-high load too much. Hashing is now turned on only for the defer and
-deferred queue directories, because those contain lots of mail when
-undeliverable mail is backing up.
-
-The SMTP server now requires that IPv6 addresses in SMTP commands
-are specified as [ipv6:ipv6address], as described in RFC 2821.
-
-Incompatible changes with snapshot Postfix-2.2-20050111+IPV6
-============================================================
-
-Postfix version 2.2 IP version 6 support is based on the Postfix/IPv6
-patch by Dean Strik, but differs in a few minor ways.
-
-- Network protocol support including DNS lookup is selected with
-the inet_protocols parameter instead of the inet_interfaces parameter.
-This is needed so that Postfix will not attempt to deliver mail
-via IPv6 when the system has no IPv6 connectivity.
-
-- The lmtp_bind_address6 feature was omitted. The Postfix LMTP
-client will be absorbed into the SMTP client, so there is no reason
-to keep adding features to the LMTP client.
-
-- The cidr-based address matching code was rewritten. The new
-behavior is believed to be closer to expectation. The results may
-be incompatible with that of the Postfix/IPv6 patch.
-
-Major changes with snapshot Postfix-2.2-20050111+IPV6
-=====================================================
-
-Postfix version 2.2 IP version 6 support based on the Postfix/IPv6
-patch by Dean Strik and others. IP version 6 support is selected
-in main.cf; it is not selected at compile time as with TLS or SASL.
-
-IP version 6 support is always compiled into Postfix on systems
-that have Postfix compatible IP version 6 support. On other systems
-Postfix will simply use IP version 4 just like it did before. See
-the IPV6_README document for what systems are supported, and how
-to turn on IPv6 in main.cf.
-
-Incompatible changes with snapshot Postfix-2.2-20041210+TLS
-===========================================================
-
-Postfix version 2.2 TLS support is based on the Postfix/TLS patch
-by Lutz Jaenicke, but differs in a few minor ways.
-
-- main.cf: Use btree instead of sdbm for TLS session cache databases.
-
- Session caches are now accessed only by the tlsmgr(8) process,
- so there are no more concurrency issues. Although Postfix still
- has an sdbm client, the sdbm library (1000 lines of code) is no
- longer included with Postfix/TLS.
-
- TLS session caches can use any database that can store objects
- of several kbytes or more, and that implements the sequence
- operation. In most cases, btree databases should be adequate.
-
- NOTE: You cannot use dbm databases. TLS session objects are too
- large.
-
-- master.cf: Specify unix instead of fifo as the tlsmgr service type.
-
- The smtp(8) and smtpd(8) processes now use a client-server protocol
- in order to access the tlsmgr(8)'s pseudo-random number generation
- (PRNG) pool, and in order to access the TLS session cache databases.
- Such a protocol cannot be run across fifos.
-
-Major changes with snapshot Postfix-2.2-20041210+TLS
-=====================================================
-
-TLS support based on the Postfix/TLS patch by Lutz Jaenicke. This
-is not compiled in by default. To build Postfix with TLS support,
-see the TLS_README document.
-
-Major changes with snapshot Postfix-2.2-20041218
-================================================
-
-Fine control for SMTP inter-operability problems, by discarding
-keywords sent or received with the EHLO handshake. Typically one
-would discard "pipelining", "starttls", or "auth". Specify a list
-of EHLO keywords with the smtp(d)_discard_ehlo_keywords parameters,
-or specify one or more lookup tables, indexed by remote network
-address, with the smtp(d)_discard_ehlo_keyword_address_maps
-parameters. Note: this only discards words from the EHLO conversation;
-it does not turn off the actual features in the SMTP server.
-
-More client attributes for delivery to command with the local(8)
-and pipe(8) delivery agents: client_hostname, client_address,
-client_protocol, client_helo, sasl_method, sasl_sender, and
-sasl_username. With local(8), attribute names must be specified
-in upper case.
-
-Major changes with snapshot Postfix-2.2-20041210
-================================================
-
-You can now dump an entire database with the new postmap/postalias
-"-s" option. This works only for database types with Postfix sequence
-operator support: hash, btree, dbm, and sdbm.
-
-Major changes with snapshot Postfix-2.2-20041208
-================================================
-
-Support for CDB databases by Michael Tokarev. This supports both
-Michael's tinycdb and Daniel Bernstein's cdb implementations, but
-neither of the two implementations is bundled with Postfix.
-
-Incompatible changes with snapshot Postfix-2.2-20041118
-=======================================================
-
-You must restart Postfix, because the master-child protocol has
-changed. Postfix will log warnings about partial status updates
-if you forget to restart the master.
-
-Major changes with snapshot Postfix-2.2-20041118
-================================================
-
-New "smtpd_end_of_data_restrictions" feature that is invoked after
-the client terminates the SMTP DATA command. The syntax is the same
-as with "smtpd_data_restrictions", but the message size is the
-actual byte count of the message content.
-
-Incompatible changes with snapshot Postfix-2.2-20041030
-=======================================================
-
-The SMTP session cache is renamed to connection cache, to avoid
-confusion with the TLS session cache. Thus, all session_cache_mumble
-parameters are now called connection_cache_mumble.
-
-Incompatible changes with snapshot Postfix-2.2-20041023
-=======================================================
-
-You must reload or stop/start Postfix, because the queue manager
-to delivery agent protocol has changed. If you forget this, mail
-will remain queued until the queue manager is restarted.
-
-Support for the non-standard Errors-To: return addresses is removed.
-It was already disabled by default with Postfix version 2.1. Since
-Errors-To: is non-standard, there was no guarantee that it would
-have effect with other MTAs.
-
-Major changes with snapshot Postfix-2.2-20041023
-================================================
-
-The NIS+ client by Geoff Gibbs is now part of the Postfix source
-tree. Details are given in the nisplus_table(5) manual page.
-
-By default, Postfix no longer appends its own domain to addresses
-in message headers from remote clients. Thus, spam from poorly
-written software no longer looks like it came from a local user.
-
-Postfix either does not rewrite remote message headers at all, or
-it rewrites headers and appends the domain name that is specified
-with the remote_header_rewrite_domain parameter (like "domain.invalid").
-
-To get the behavior of earlier Postfix versions (always append
-Postfix's own domain to incomplete addresses in message headers)
-specify:
-
-/etc/postfix/main.cf:
- local_header_rewrite_clients = static:all
-
-Postfix always appends its own domain information to addresses in
-message headers from Postfix sendmail and from local SMTP clients.
-
-By default, Postfix considers an SMTP client local (and thus updates
-message header addresses with the Postfix's own domain) when the
-client IP address matches mynetworks, or when the client is SASL
-or TLS authenticated.
-
-If you want to include other clients via a pop-before-smtp table,
-then you have to specify that via the new local_header_rewrite_clients
-parameter:
-
-/etc/postfix/main.cf:
- local_header_rewrite_clients = permit_mynetworks,
- permit_sasl_authenticated, permit_tls_clientcerts,
- check_address_map hash:/etc/postfix/pop-before-smtp
-
-As before, Postfix appends local domain information to envelope
-addresses (as opposed to header addresses), because an unqualified
-envelope address is effectively local for the purpose of delivery,
-and for the purpose of replying to it.
-
-Full details are given in ADDRESS_REWRITING_README, and in the
-postconf(5) manual. For best results, point your browser at the
-ADDRESS_REWRITING_README.html file and navigate to the section
-titled "To rewrite or not to rewrite, or to label as invalid".
-
-Incompatible changes with snapshot Postfix-2.2-20041009
-=======================================================
-
-You must reload or stop/start Postfix, because the queue manager
-to delivery agent protocol has changed. If you forget this, mail
-will remain queued until the queue manager is restarted.
-
-The smtpd_client_connection_limit_exceptions parameter is renamed
-to smtpd_client_event_limit_exceptions. Besides connections it now
-also applies to per-client message rate and recipient rate limits.
-
-Major changes with snapshot Postfix-2.2-20041009
-================================================
-
-Per SMTP client message rate and recipient rate limits. These limit
-the number of MAIL FROM or RCPT TO requests regardless of whether
-or not Postfix would have accepted them otherwise. The user interface
-(smtpd_client_message_rate_limit and smtpd_client_recipient_rate_limit)
-is similar to that of the existing per SMTP client connection rate
-limit, and the same warnings apply: these features are to be used
-to stop abuse, and must not be used to regulate legitimate mail.
-More details can be found in the postconf(5) manual.
-
-Incompatible changes with snapshot Postfix-2.2-20040919
-=======================================================
-
-This snapshot adds a discard service to the master.cf file.
-
-Major changes with snapshot Postfix-2.2-20040919
-================================================
-
-A new discard(8) mail delivery agent that makes throwing away mail
-easier and more efficient. It's the Postfix equivalent of /dev/null
-for deliveries. On the input side, Postfix already has a /dev/null
-equivalent in the form of the DISCARD action in access maps and
-header_body_checks.
-
-Access control for local mail submission, for listing the queue
-and for flushing the queue. These features are controlled with
-authorized_submit_users, authorized_mailq_users, and with
-authorized_flush_users, respectively. The last two controls are
-always permitted for the super-user and for the mail system owner.
-More information is in the postconf(5) manual.
-
-Incompatible changes with snapshot Postfix-2.2-20040829
-=======================================================
-
-When no recipients are specified on the command line or via the -t
-option, the Postfix sendmail command terminates with status EX_USAGE
-and produces an error message instead of accepting the mail first
-and bouncing it later. This gives more direct feedback in case of
-a common client configuration error.
-
-Major changes with snapshot Postfix-2.2-20040827
-================================================
-
-Easier use of the proxymap service with the virtual(8) delivery
-agent. As of now, the virtual(8) delivery agent will silently open
-maps directly when they can't be proxied. This means you can now
-specify "virtual_mailbox_maps = proxy:mysql:whatever" without
-triggering fatal errors in the virtual(8) delivery agent.
-
-Better SMTP client control over the use of SASL mechanisms. New
-smtp_sasl_mechanism_filter mechanism to shorten the list of SASL
-mechanisms from a remote server to just those that the local SASL
-library can actually use.
-
-Finer control over canonical mapping with canonical_classes,
-sender_canonical_classes and recipient_canonical_classes. These
-specify one or more of envelope_sender, header_sender, envelope_recipient
-or header_recipient. The default settings are backwards compatible.
-
-Incompatible changes with snapshot Postfix-2.2-20040729
-=======================================================
-
-SMTP session caching is enabled temporarily when a destination has
-a high volume of mail in the active queue. To disable, specify
-"smtp_connection_cache_on_demand = no".
-
-Major changes with snapshot Postfix-2.2-20040729
-================================================
-
-Opportunistic SMTP session caching. When a destination has a high
-volume of mail in the active queue, SMTP session caching is enabled
-temporarily. This is controlled with a new configuration parameter
-"smtp_connection_cache_on_demand" (default: yes).
-
-Incompatible changes with snapshot Postfix-2.2-20040723
-=======================================================
-
-Permanent SMTP session caching is now enabled with the
-smtp_session_cache_destinations parameter. This requires "bare"
-domain names without "[]" or TCP port. The change eliminates a
-syntax conflict between host:port and maptype:mapname, and simplifies
-the user interface, at the cost of a minor loss of control over
-what sessions are cached.
-
-Major changes with snapshot Postfix-2.2-20040721
-================================================
-
-The session cache manager now logs cache hit and miss statistics
-every $session_cache_status_update_time seconds (default: 600s).
-It reports the hit and miss rates for lookups by domain, as well
-as for lookups by network address.
-
-Hit rates for cache lookups by domain will tell you how useful
-session caching is.
-
-Cache lookups by network address will always fail, unless you're
-sending mail to different domains that share the same MX host.
-
-Incompatible changes with snapshot Postfix-2.2-20040720
-=======================================================
-
-The default SMTP/LMTP timeouts for sending RSET are reduced to 20s.
-
-Major changes with snapshot Postfix-2.2-20040720
-================================================
-
-Selective permanent SMTP session caching. Instead of disconnecting
-immediately after a mail transaction, the SMTP client can save the
-open session to a session cache daemon, so that any SMTP client
-process can use that session for another mail transaction.
-
-This feature introduces the scache (session cache) server, which
-is added to your master.cf file when you upgrade Postfix.
-
-*** You need to execute "postfix reload" when upgrading from Postfix
-*** version 2.1 or later.
-
-*** You need to execute "postfix stop" when upgrading from Postfix
-*** version 2.0 or earlier. Execute "postfix start" when done.
-
-Session caching is enabled with the new smtp_connection_cache_destinations
-parameter. Specify a list of destinations or lookup tables:
-
-- if mail is sent without relay host: a domain (the right-hand side
-of an email address),
-
-- if mail is sent via a relay host, the relay host (without [],
-and without non-default TCP port) that is specified in main.cf or
-in the transport map,
-
-- a /file/name with domains and/or relay hosts,
-
-- a type:table with domains and/or relay hosts on the left-hand
-side; the right-hand side result from type:table lookups is ignored.
-
-The following optimizes deliveries to hosts that your machine relays
-mail to:
-
- smtp_connection_cache_destinations = $relay_domains $relayhost
-
-A setting that tries to optimize deliveries to problem sites:
-
- smtp_connection_cache_destinations = hotmail.com...
-
-Cached SMTP sessions are allowed to remain unused for only a limited
-amount of time (smtp_connection_cache_time_limit, default: 2
-seconds). This limits the impact on remote server resources.
-Specify larger values only with permission from the remote sites.
-
-To avoid triggering remote problems, the same SMTP session is used
-only a limited number of times (smtp_connection_cache_reuse_limit,
-default: 10).
-
-Robustness note: to prevent mail from being delivered to the wrong
-server, the session caching feature explicitly labels each cached
-session with destination domain and IP address information. A
-session cache lookup succeeds only when the correct information is
-specified.
-
-Limitations:
-
-- SMTP session caching does not work with TLS (the necessary support
-for object passivation and re-activation does not exist without
-closing the connection).
-
-- SMTP session caching assumes that SASL credentials are valid for
-all hostnames or domain names that map onto the same IP address
-and TCP port.
-
-Major changes with snapshot Postfix-2.2-20040621
-================================================
-
-Control over the working directory when executing an external
-command. With the pipe(8) mailer, specify directory=pathname, and
-with local(8) specify "command_execution_directory = expression"
-where "expression" is subject to $home etc. macro expansion. The
-result of macro expansion is restricted by the set of characters
-specified with execution_directory_expansion_filter.
+See RELEASE_NOTES-2.2 for changes introduced during the development
+of Postfix version 2.2.
from third-party patches.
- SMTP client-side connection reuse. This can dramatically speed
-up deliveries to high-volume destinations that have good and
-non-responding mail servers.
+up deliveries to high-volume destinations that have some servers
+that respond, and some non-responding mail servers.
- By default, message header address rewriting is now disabled for
SMTP mail from other systems. Thus, spam from poorly written
[Feature 20040919] The upgrade procedure adds the discard service
to the master.cf file.
-[Feature 20040720] The upgrade procedure adds the scache (connection
-cache) service to the master.cf file.
+[Feature 20040720] The upgrade procedure adds the scache (shared
+connection cache) service to the master.cf file.
Major changes - IPv6 support
----------------------------
in by default. For more information about Postfix 2.2 TLS support,
see the TLS_README document.
-[Feature 20050209] The Postfix SMTP server policy delegation protocol
-now supplies TLS client certificate information after successful
-verification. The new policy delegation protocol attribute names
-are ccert_subject, ccert_issuer and ccert_fingerprint.
-
-[Feature 20050208] New "check_ccert_maps maptype:mapname" feature
-to enforce access control based on hexadecimal client certificate
-fingerprints.
-
[Incompat 20041210] Postfix version 2.2 TLS support differs from
the Postfix/TLS patch by Lutz Jaenicke in a few minor ways.
(PRNG) pool, and in order to access the TLS session cache databases.
Such a protocol cannot be run across fifos.
+[Feature 20050209] The Postfix SMTP server policy delegation protocol
+now supplies TLS client certificate information after successful
+verification. The new policy delegation protocol attribute names
+are ccert_subject, ccert_issuer and ccert_fingerprint.
+
+[Feature 20050208] New "check_ccert_maps maptype:mapname" feature
+to enforce access control based on hexadecimal client certificate
+fingerprints.
+
Major changes - SMTP client connection cache
--------------------------------------------
PATH=/bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin
xxgdb $daemon_directory/$process_name $process_id & sleep 5
-# If you don't have X installed on the Postfix machine, try:
+# If you can't use X, use this to capture the call stack when a
+# daemon crashes. The result is in a file in the configuration
+# directory, and is named after the process name and the process ID.
+#
# debugger_command =
# PATH=/bin:/usr/bin:/usr/local/bin; export PATH; (echo cont;
# echo where) | gdb $daemon_directory/$process_name $process_id 2>&1
# >$config_directory/$process_name.$process_id.log & sleep 5
+#
+# Another possibility is to run gdb under a detached screen session.
+# To attach to the screen sesssion, su root and run "screen -r
+# <id_string>" where <id_string> uniquely matches one of the detached
+# sessions (from "screen -list").
+#
+# debugger_command =
+# PATH=/bin:/usr/bin:/sbin:/usr/sbin; export PATH; screen
+# -dmS $process_name gdb $daemon_directory/$process_name
+# $process_id & sleep 1
# INSTALL-TIME CONFIGURATION INFORMATION
#
(remote)->rcpt = 0; \
(remote)->newtls = 1; \
(remote)->start = _now; \
- } else if ((remote)->rcpt < INT_MAX) { \
+ } else if ((remote)->newtls < INT_MAX) { \
(remote)->newtls += 1; \
} \
} while(0)
#include <bounce.h>
#include <deliver_completed.h>
#include <flush_clnt.h>
+#include <sent.h>
/* Single server skeleton. */
* Patches change the patchlevel and the release date. Snapshots change the
* release date only.
*/
-#define MAIL_RELEASE_DATE "20050227"
+#define MAIL_RELEASE_DATE "20050304"
#define MAIL_VERSION_NUMBER "2.2"
#define VAR_MAIL_VERSION "mail_version"
/* System library. */
#include <sys_defs.h>
+#include <string.h>
#include <unistd.h>
/* Utility library. */
/*
* Local mail submission access list.
*/
-static char *var_submit_acl;
+char *var_submit_acl;
static CONFIG_STR_TABLE str_table[] = {
VAR_SUBMIT_ACL, DEF_SUBMIT_ACL, &var_submit_acl, 0, 0,
/*
* Queue manipulation access lists.
*/
-static char *var_flush_acl;
-static char *var_showq_acl;
+char *var_flush_acl;
+char *var_showq_acl;
static CONFIG_STR_TABLE str_table[] = {
VAR_FLUSH_ACL, DEF_FLUSH_ACL, &var_flush_acl, 0, 0,
/*
* Mail submission ACL
*/
-static char *var_submit_acl;
+char *var_submit_acl;
static CONFIG_STR_TABLE str_table[] = {
VAR_SUBMIT_ACL, DEF_SUBMIT_ACL, &var_submit_acl, 0, 0,
char *host; /* mail exchanger */
char *addr; /* mail exchanger */
char *namaddr; /* mail exchanger */
+ char *helo; /* helo response */
unsigned port; /* network byte order */
VSTRING *buffer; /* I/O buffer */
"QUIT command",
};
+static int smtp_start_tls(SMTP_STATE *, int);
+
/* smtp_helo - perform initial handshake with SMTP server */
int smtp_helo(SMTP_STATE *state, NOCLOBBER int misc_flags)
int discard_mask;
#ifdef USE_TLS
- static int smtp_start_tls(SMTP_STATE *, int);
int saved_features = session->features;
#endif
* MicroSoft implemented AUTH based on an old draft.
*/
lines = resp->str;
- while ((words = mystrtok(&lines, "\n")) != 0) {
+ for (n = 0; (words = mystrtok(&lines, "\n")) != 0; /* see below */ ) {
if (mystrtok(&words, "- ") && (word = mystrtok(&words, " \t=")) != 0) {
- if (strcasecmp(word, "8BITMIME") == 0) {
+ if (n == 0) {
+ if (session->helo != 0)
+ myfree(session->helo);
+ session->helo = lowercase(mystrdup(word));
+ if (strcasecmp(word, var_myhostname) == 0
+ && (misc_flags & SMTP_MISC_FLAG_LOOP_DETECT) != 0) {
+ msg_warn("host %s replied to HELO/EHLO with my own hostname %s",
+ session->namaddr, var_myhostname);
+ return (smtp_site_fail(state,
+ (session->features & SMTP_FEATURE_BEST_MX) ? 550 : 450,
+ "mail for %s loops back to myself",
+ request->nexthop));
+ }
+ } else if (strcasecmp(word, "8BITMIME") == 0) {
if ((discard_mask & EHLO_MASK_8BITMIME) == 0)
session->features |= SMTP_FEATURE_8BITMIME;
} else if (strcasecmp(word, "PIPELINING") == 0) {
if ((discard_mask & EHLO_MASK_AUTH) == 0)
smtp_sasl_helo_auth(session, words);
#endif
- } else if (strcasecmp(word, var_myhostname) == 0) {
- if (misc_flags & SMTP_MISC_FLAG_LOOP_DETECT) {
- msg_warn("host %s replied to HELO/EHLO with my own hostname %s",
- session->namaddr, var_myhostname);
- return (smtp_site_fail(state,
- (session->features & SMTP_FEATURE_BEST_MX) ? 550 : 450,
- "mail for %s loops back to myself",
- request->nexthop));
- }
}
+ n++;
}
}
if (msg_verbose)
static int smtp_start_tls(SMTP_STATE *state, int misc_flags)
{
SMTP_SESSION *session = state->session;
+ VSTRING *serverid;
/*
* Turn off SMTP connection caching. When the TLS handshake succeeds, we
* follow below AFTER the tls_client_start() call. These tests should be
* done inside tls_client_start() or its call-backs, to keep the SMTP
* client code clean (as it is in the SMTP server).
+ *
+ * The following assumes sites that use TLS in a perverse configuration:
+ * multiple hosts per hostname, or even multiple hosts per IP address.
+ * All this without a shared TLS session cache, and they still want to
+ * use TLS session caching???
*/
+ serverid = vstring_alloc(10);
+ vstring_sprintf(serverid, "%s:%s:%u",
+ session->host, session->addr,
+ ntohs(session->port));
+ if (session->helo && strcasecmp(session->host, session->helo) != 0)
+ vstring_sprintf_append(serverid, ":%s", session->helo);
session->tls_context =
tls_client_start(smtp_tls_ctx, session->stream,
var_smtp_starttls_tmout,
session->tls_enforce_peername,
session->host,
+ lowercase(vstring_str(serverid)),
&(session->tls_info));
+ vstring_free(serverid);
if (session->tls_context == 0)
return (smtp_site_fail(state, 450,
"Cannot start TLS: handshake failure"));
char *end_line;
/*
- * Rewrite primary header addresses that match the smtp_generic_maps.
- * The cleanup server already enforces that all headers have proper
- * lengths and that all addresses are in proper form, so we don't have to
- * repeat that.
+ * Rewrite primary header addresses that match the smtp_generic_maps. The
+ * cleanup server already enforces that all headers have proper lengths
+ * and that all addresses are in proper form, so we don't have to repeat
+ * that.
*/
if (header_info && header_class == MIME_HDR_PRIMARY
&& (header_info->flags & (HDR_OPT_SENDER | HDR_OPT_RECIP)) != 0) {
save_mech = mech_list = mystrdup(words);
- while (mech = mystrtok(&mech_list, " \t")) {
- if (string_list_match(smtp_sasl_mechs, mech)) {
+ while ((mech = mystrtok(&mech_list, " \t")) != 0) {
+ if (string_list_match(smtp_sasl_mechs, mech)) {
if (VSTRING_LEN(buf) > 0)
VSTRING_ADDCH(buf, ' ');
vstring_strcat(buf, mech);
#include <sys_defs.h>
#include <stdlib.h>
#include <string.h>
+#include <netinet/in.h>
#ifdef STRCASECMP_IN_STRINGS_H
#include <strings.h>
/* Application-specific. */
#include "smtp.h"
+#include "smtp_sasl.h"
#define STR(x) vstring_str(x)
session->host = mystrdup(host);
session->addr = mystrdup(addr);
session->namaddr = concatenate(host, "[", addr, "]", (char *) 0);
+ session->helo = 0;
session->port = port;
session->features = 0;
myfree(session->host);
myfree(session->addr);
myfree(session->namaddr);
+ if (session->helo)
+ myfree(session->helo);
vstring_free(session->buffer);
vstring_free(session->scratch);
#include <mymalloc.h>
#include <namadr_list.h>
#include <name_mask.h>
+#include <stringops.h>
/* Global library. */
SSL *con;
BIO *internal_bio; /* postfix/TLS side of pair */
BIO *network_bio; /* network side of pair */
+ char *serverid; /* unique server identifier */
char peer_subject[CCERT_BUFSIZ];
char peer_issuer[CCERT_BUFSIZ];
char peer_CN[CCERT_BUFSIZ];
#define TLS_BIO_BUFSIZE 8192
+#define NEW_TLS_CONTEXT(p) do { \
+ p = (TLScontext_t *) mymalloc(sizeof(*p)); \
+ memset((char *) p, 0, sizeof(*p)); \
+ p->serverid = 0; \
+ } while (0)
+
+#define FREE_TLS_CONTEXT(p) do { \
+ if ((p)->serverid) \
+ myfree((p)->serverid); \
+ myfree((char *) (p)); \
+ } while (0)
+
typedef struct {
int peer_verified;
int hostname_matched;
*/
extern SSL_CTX *tls_client_init(int);
extern TLScontext_t *tls_client_start(SSL_CTX *, VSTREAM *, int, int,
- const char *, tls_info_t *);
+ const char *, const char *,
+ tls_info_t *);
#define tls_client_stop(ctx , stream, timeout, failure, tls_info) \
tls_session_stop((ctx), (stream), (timeout), (failure), (tls_info))
* tls_misc.c
*/
extern int TLScontext_index;
-extern int TLSpeername_index;
extern void tls_print_errors(void);
extern void tls_info_callback(const SSL *, int, int);
/* SSL_CTX *tls_client_init(verifydepth)
/* int verifydepth; /* unused */
/*
-/* TLScontext_t *tls_client_start(client_ctx, stream, timeout, peername,
-/* peeraddr, tls_info)
+/* TLScontext_t *tls_client_start(client_ctx, stream, timeout,
+/* enforce_peername, peername,
+/* serverid, tls_info)
/* SSL_CTX *client_ctx;
/* VSTREAM *stream;
/* int timeout;
+/* int enforce_peername;
/* const char *peername;
-/* const char *peeraddr;
+/* const char *serverid;
/* tls_info_t *tls_info;
/*
/* void tls_client_stop(client_ctx, stream, failure, tls_info)
/* passed as argument. We expect that network buffers are flushed and the
/* TLS handshake can begin immediately. Information about the peer
/* is stored into the tls_info structure passed as argument.
+/* The serverid argument specifies a string that hopefully
+/* uniquely identifies a server. It is used as the client
+/* session cache lookup key.
/*
/* tls_client_stop() sends the "close notify" alert via
/* SSL_shutdown() to the peer and resets all connection specific
/* load_clnt_session - load session from client cache (non-callback) */
-static SSL_SESSION *load_clnt_session(const char *hostname,
+static SSL_SESSION *load_clnt_session(const char *cache_id,
int enforce_peername)
{
SSL_SESSION *session = 0;
- char *cache_id;
- VSTRING *cache_id_buffer;
VSTRING *session_data = vstring_alloc(2048);
int flags = 0;
/*
* Prepare the query.
*/
- cache_id = lowercase(mystrdup(hostname));
if (var_smtp_tls_loglevel >= 3)
msg_info("looking for session %s in client cache", cache_id);
if (enforce_peername)
if (session) {
if (var_smtp_tls_loglevel >= 3)
msg_info("reloaded session %s from client cache", cache_id);
- cache_id_buffer =
- (VSTRING *) SSL_SESSION_get_ex_data(session, TLSpeername_index);
- vstring_strcpy(cache_id_buffer, cache_id);
}
}
/*
* Clean up.
*/
- myfree(cache_id);
vstring_free(session_data);
return (session);
}
- /*
- * The client session cache is indexed by peer name, not by session id. The
- * following routines maintain string storage for the peer name in an
- * SSL_SESSION object. We use VSTRING buffers so that we don't have to worry
- * about hostname length problems.
- */
-
-/* new_cache_id_func - create space for peer name in SSL_SESSION object */
-
-static int new_cache_id_func(void *unused_parent, void *unused_ptr,
- CRYPTO_EX_DATA *ad, int idx,
- long unused_argl, void *unused_argp)
-{
- VSTRING *cache_id_buffer;
-
- cache_id_buffer = vstring_alloc(32);
- return (CRYPTO_set_ex_data(ad, idx, (void *) cache_id_buffer));
-}
-
-/* free_cache_id_func - destroy space for peer name in SSL_SESSION object */
-
-static void free_cache_id_func(void *unused_parent, void *unused_ptr,
- CRYPTO_EX_DATA *ad, int idx,
- long unused_argl, void *unused_argp)
-{
- VSTRING *cache_id_buffer;
-
- cache_id_buffer = (VSTRING *) CRYPTO_get_ex_data(ad, idx);
- vstring_free(cache_id_buffer);
-}
-
-/* dup_cache_id_func - duplicate peer name when SSL_SESSION is duplicated */
-
-static int dup_cache_id_func(CRYPTO_EX_DATA *to, CRYPTO_EX_DATA *from,
- void *unused_from_d, int idx, long unused_argl, void *unused_argp)
-{
- const char *myname = "dup_cache_id_func";
- VSTRING *old_cache_id_buffer;
- VSTRING *new_cache_id_buffer;
-
- old_cache_id_buffer = (VSTRING *) CRYPTO_get_ex_data(from, idx);
- if (old_cache_id_buffer == 0) {
- msg_warn("%s: cannot get old SSL_SESSION peer name buffer", myname);
- return (0);
- }
- new_cache_id_buffer = (VSTRING *) CRYPTO_get_ex_data(to, idx);
- if (new_cache_id_buffer == 0) {
- msg_warn("%s: cannot get new SSL_SESSION peer name buffer", myname);
- return (0);
- }
- vstring_strcpy(new_cache_id_buffer, STR(old_cache_id_buffer));
- return (1);
-}
-
/* new_client_session_cb - name new session and save it to client cache */
static int new_client_session_cb(SSL *ssl, SSL_SESSION *session)
{
TLScontext_t *TLScontext;
VSTRING *session_data;
- VSTRING *cache_id_buffer;
+ const char *cache_id;
int flags = 0;
/*
- * Attach the cache ID string to the session object. Don't worry about
- * the length; that is the concern of the code that updates the session
- * cache.
+ * Look up the cache ID string for this session object.
*/
- cache_id_buffer =
- (VSTRING *) SSL_SESSION_get_ex_data(session, TLSpeername_index);
TLScontext = SSL_get_ex_data(ssl, TLScontext_index);
- vstring_strcpy(cache_id_buffer, TLScontext->peername_save);
- lowercase(STR(cache_id_buffer)); /* just in case */
+ cache_id = TLScontext->serverid;
if (var_smtp_tls_loglevel >= 3)
- msg_info("save session %s to client cache", STR(cache_id_buffer));
+ msg_info("save session %s to client cache", cache_id);
/*
* Remember whether peername matching was enforced when the session was
*/
session_data = tls_session_passivate(session);
if (session_data)
- tls_mgr_update(tls_client_cache, STR(cache_id_buffer),
+ tls_mgr_update(tls_client_cache, cache_id,
OPENSSL_VERSION_NUMBER, flags,
STR(session_data), LEN(session_data));
*/
if (session_data)
vstring_free(session_data);
+ SSL_SESSION_free(session); /* 200502 */
return (1);
}
if (TLScontext_index < 0)
TLScontext_index = SSL_get_ex_new_index(0, "TLScontext ex_data index",
NULL, NULL, NULL);
-
- /*
- * Create a global index so that we can attach peer name information to
- * SSL_SESSION objects; the client session cache manager uses this to
- * generate cache ID strings.
- */
- if (TLSpeername_index < 0)
- TLSpeername_index = SSL_SESSION_get_ex_new_index(0,
- "TLSpeername ex_data index",
- new_cache_id_func,
- dup_cache_id_func,
- free_cache_id_func);
-
return (client_ctx);
}
* buffers are flushed and the "220 Ready to start TLS" was received by us,
* so that we can immediately start the TLS handshake process.
*/
-TLScontext_t *tls_client_start(SSL_CTX *client_ctx, VSTREAM *stream, int timeout,
+TLScontext_t *tls_client_start(SSL_CTX *client_ctx, VSTREAM *stream,
+ int timeout,
int enforce_peername,
const char *peername,
+ const char *serverid,
tls_info_t *tls_info)
{
int sts;
- SSL_SESSION *session,
- *old_session;
+ SSL_SESSION *session, *old_session;
SSL_CIPHER *cipher;
X509 *peer;
int verify_flags;
*/
#define PEERNAME_SIZE sizeof(TLScontext->peername_save)
- TLScontext = (TLScontext_t *) mymalloc(sizeof(TLScontext_t));
- memset((char *) TLScontext, 0, sizeof(*TLScontext));
+ NEW_TLS_CONTEXT(TLScontext);
TLScontext->log_level = var_smtp_tls_loglevel;
strncpy(TLScontext->peername_save, peername, PEERNAME_SIZE - 1);
TLScontext->peername_save[PEERNAME_SIZE - 1] = 0;
(void) lowercase(TLScontext->peername_save);
+ TLScontext->serverid = mystrdup(serverid);
if ((TLScontext->con = (SSL *) SSL_new(client_ctx)) == NULL) {
msg_info("Could not allocate 'TLScontext->con' with SSL_new()");
tls_print_errors();
- myfree((char *) TLScontext);
+ FREE_TLS_CONTEXT(TLScontext);
return (0);
}
if (!SSL_set_ex_data(TLScontext->con, TLScontext_index, TLScontext)) {
msg_info("Could not set application data for 'TLScontext->con'");
tls_print_errors();
SSL_free(TLScontext->con);
- myfree((char *) TLScontext);
+ FREE_TLS_CONTEXT(TLScontext);
return (0);
}
msg_info("Could not obtain BIO_pair");
tls_print_errors();
SSL_free(TLScontext->con);
- myfree((char *) TLScontext);
+ FREE_TLS_CONTEXT(TLScontext);
return (0);
}
old_session = NULL;
* will be reused.
*/
if (tls_client_cache) {
- old_session = load_clnt_session(peername, enforce_peername);
+ old_session = load_clnt_session(serverid, enforce_peername);
if (old_session) {
SSL_set_session(TLScontext->con, old_session);
SSL_SESSION_free(old_session); /* 200411 */
}
SSL_free(TLScontext->con);
BIO_free(TLScontext->network_bio); /* 200411 */
- myfree((char *) TLScontext);
+ FREE_TLS_CONTEXT(TLScontext);
return (0);
}
if (var_smtp_tls_loglevel >= 3 && SSL_session_reused(TLScontext->con))
* so that it can be accessed by call-back routines.
*/
int TLScontext_index = -1;
-int TLSpeername_index = -1;
/* tls_print_errors - print and clear the error stack */
return (session);
}
-/* remove_server_session_cb - callback to remove session from server cache */
-
-static void remove_server_session_cb(SSL_CTX *unused_ctx, SSL_SESSION *session)
-{
- VSTRING *cache_id;
-
- /*
- * Encode the session ID.
- */
- cache_id =
- MAKE_SERVER_CACHE_ID(session->session_id, session->session_id_length);
- if (var_smtpd_tls_loglevel >= 3)
- msg_info("remove session %s from server cache", STR(cache_id));
-
- /*
- * Delete the session from cache.
- */
- tls_mgr_delete(tls_server_cache, STR(cache_id));
-
- vstring_free(cache_id);
-}
-
/* new_server_session_cb - callback to save session to server cache */
static int new_server_session_cb(SSL *unused_ssl, SSL_SESSION *session)
if (session_data)
vstring_free(session_data);
vstring_free(cache_id);
+ SSL_SESSION_free(session); /* 200502 */
return (1);
}
/*
* The session cache is implemented by the tlsmgr(8) server.
+ *
+ * XXX 200502 Surprise: when OpenSSL purges an entry from the in-memory
+ * cache, it also attempts to purge the entry from the on-disk cache.
+ * This is undesirable, especially when we set the in-memory cache size
+ * to 1. For this reason we don't allow OpenSSL to purge on-disk cache
+ * entries, and leave it up to the tlsmgr process instead. Found by
+ * Victor Duchovni.
*/
if (tls_mgr_policy(&cache_types) == TLS_MGR_STAT_OK
&& (tls_server_cache = (cache_types & TLS_MGR_SCACHE_SERVER)) != 0) {
SSL_SESS_CACHE_SERVER | SSL_SESS_CACHE_NO_AUTO_CLEAR);
SSL_CTX_sess_set_get_cb(server_ctx, get_server_session_cb);
SSL_CTX_sess_set_new_cb(server_ctx, new_server_session_cb);
- SSL_CTX_sess_set_remove_cb(server_ctx, remove_server_session_cb);
}
/*
* Allocate a new TLScontext for the new connection and get an SSL
* structure. Add the location of TLScontext to the SSL to later retrieve
* the information inside the tls_verify_certificate_callback().
- *
+ *
* XXX Need a dedicated procedure for consistent initialization of all the
* fields in this structure.
*/
#define PEERNAME_SIZE sizeof(TLScontext->peername_save)
- TLScontext = (TLScontext_t *) mymalloc(sizeof(TLScontext_t));
- memset((char *) TLScontext, 0, sizeof(*TLScontext));
+ NEW_TLS_CONTEXT(TLScontext);
TLScontext->log_level = var_smtpd_tls_loglevel;
strncpy(TLScontext->peername_save, peername, PEERNAME_SIZE - 1);
TLScontext->peername_save[PEERNAME_SIZE - 1] = 0;
if ((TLScontext->con = (SSL *) SSL_new(server_ctx)) == NULL) {
msg_info("Could not allocate 'TLScontext->con' with SSL_new()");
tls_print_errors();
- myfree((char *) TLScontext);
+ FREE_TLS_CONTEXT(TLScontext);
return (0);
}
if (!SSL_set_ex_data(TLScontext->con, TLScontext_index, TLScontext)) {
msg_info("Could not set application data for 'TLScontext->con'");
tls_print_errors();
SSL_free(TLScontext->con);
- myfree((char *) TLScontext);
+ FREE_TLS_CONTEXT(TLScontext);
return (0);
}
msg_info("Could not obtain BIO_pair");
tls_print_errors();
SSL_free(TLScontext->con);
- myfree((char *) TLScontext);
+ FREE_TLS_CONTEXT(TLScontext);
return (0);
}
tls_print_errors();
SSL_free(TLScontext->con);
BIO_free(TLScontext->network_bio); /* 200411 */
- myfree((char *) TLScontext);
+ FREE_TLS_CONTEXT(TLScontext);
return (0);
}
/* Only loglevel==4 dumps everything */
msg_info("fingerprint=%s", TLScontext->fingerprint);
tls_info->peer_fingerprint = TLScontext->fingerprint;
}
-
TLScontext->peer_CN[0] = '\0';
if (!X509_NAME_get_text_by_NID(X509_get_subject_name(peer),
NID_commonName, TLScontext->peer_CN,
SSL_CTX_remove_session(server_ctx, session);
SSL_free(TLScontext->con);
BIO_free(TLScontext->network_bio); /* 200411 */
- myfree((char *) TLScontext);
+ FREE_TLS_CONTEXT(TLScontext);
return (0);
}
}
SSL_free(TLScontext->con);
BIO_free(TLScontext->network_bio);
- myfree((char *) TLScontext);
+ FREE_TLS_CONTEXT(TLScontext);
tls_stream_stop(stream);
SSL_CTX_flush_sessions(ctx, time(NULL));