Bugfix: the 20051128 code move for "smtpd_end_of_data_restrictions"
broke "postsuper -r".
+20051202-3
+
+ Cleanup: the SMTP client now also implements the LMTP
+ protocol. Files: smtp/smtp.c, smtp/smtp_connect.c,
+ smtp/smtp_proto.c, smtp/smtp_dsn.c, smtp_state.c,
+ smtp_sasl_glue.c.
+
+ As before, the LMTP behavior is controlled with parameters
+ named lmtp_xxx instead of smtp_xxx. However there are now
+ a lot more lmtp_xxx parameters :-) With few exceptions, all
+ SMTP features are now also available with LMTP. The exceptions
+ are related to the HELO and EHLO commands, which exist in
+ SMTP only. There are equivalent LHLO command parameters
+ where it makes sense.
+
+20051206
+
+ SMTP+LMTP client connection management code rewritten to
+ support UNIX-domain socket connections.
+
+20051207
+
+ Bugfix: race condition in the connection caching protocol,
+ found while adding connection caching for UNIX-domain sockets
+ (used for LMTP delivery). This was introduced with the
+ 20050706 workaround, and may the same problem that Jussi
+ Silvennoinen experienced (in Postfix 2.2.6) with SMTP after
+ an upgrade. Files: scache/scache.c.
+
+ Bugfix: smtp-sink and qmqp-sink didn't ignore SIGPIPE.
+
+20051208
+
+ Robustness: reduced timeouts in the connection caching
+ client, so that a malfunctioning service does not prevent
+ mail delivery. This uses similar code that already exists
+ for the anvil(8) client and the tlsmgr(8) client. Files:
+ global/scache_clnt.c, smtp/smtp.c.
+
+ To make reduced connection caching client timeouts possible,
+ connection management was moved from the attr_clnt(3) module
+ to the auto_clnt(3) module where it belongs. The auto_clnt(3)
+ module is now a full alternative for the clnt_stream(3)
+ module. Files: util/auto_clnt.c, util/attr_clnt.c.
+
+ Bugfix: the best_mx_transport, mailbox_transport and
+ fallback_transport features did not write a per-recipient
+ defer logfile record when the target delivery agent was
+ broken. This the analog of queue manager bugfix 20051119.
+ Files: global/deliver_pass.c.
+
Open problems:
"postsuper -r" no longer resets the message arrival time,
OPTS = 'CC=$(CC)'
DIRS = src/util src/global src/dns src/tls src/master src/postfix src/smtpstone \
src/sendmail src/error src/pickup src/cleanup src/smtpd src/local \
- src/lmtp src/trivial-rewrite src/qmgr src/oqmgr src/smtp src/bounce \
+ src/trivial-rewrite src/qmgr src/oqmgr src/smtp src/bounce \
src/pipe src/showq src/postalias src/postcat src/postconf src/postdrop \
src/postkick src/postlock src/postlog src/postmap src/postqueue \
src/postsuper src/qmqpd src/spawn src/flush src/verify \
If you upgrade from Postfix 2.1 or earlier, read RELEASE_NOTES-2.2
before proceeding.
+Incompatibility with snapshot 20051208
+======================================
+
+The fallback_relay feature is renamed to smtp_fallback_relay, to
+make clear that the combined SMTP+LMTP client uses this setting
+only for SMTP deliveries. The old name still works.
+
+The LMTP client now reports the server as "myhostname[/path/name]".
+With the real server hostname in delivery status reports, the
+information will be more useful.
+
+Major changes with snapshot 20051208
+====================================
+
+The SMTP client now implements the LMTP protocol. Most but not all
+smtp_xxx parameters have an lmtp_xxx "ghost" parameter. This means
+there are lot of new LMTP features, including support for TLS and
+for the shared connection cache. There are no lmtp_xxx "ghost"
+parameters for the HELO or EHLO commands, because those commands
+exist only in SMTP.
+
Incompatibility with snapshot 20051202
======================================
$daemon_directory/discard:f:root:-:755
$daemon_directory/error:f:root:-:755
$daemon_directory/flush:f:root:-:755
-$daemon_directory/lmtp:f:root:-:755
+#$daemon_directory/lmtp:f:root:-:755
$daemon_directory/local:f:root:-:755
$daemon_directory/master:f:root:-:755
$daemon_directory/oqmgr:f:root:-:755
$daemon_directory/verify:f:root:-:755
$daemon_directory/virtual:f:root:-:755
$daemon_directory/nqmgr:h:$daemon_directory/qmgr
+$daemon_directory/lmtp:h:$daemon_directory/smtp
$command_directory/postalias:f:root:-:755
$command_directory/postcat:f:root:-:755
$command_directory/postconf:f:root:-:755
PATH=../mantools:$$PATH; \
srctoman $? | $(AWK) | nroff -man | uniq | $(MAN2HTML) | postlink >$@
-lmtp.8.html: ../src/lmtp/lmtp.c
- PATH=../mantools:$$PATH; \
- srctoman $? | $(AWK) | nroff -man | uniq | $(MAN2HTML) | postlink >$@
+lmtp.8.html: smtp.8.html
+ rm -f $@
+ ln -s $? $@
local.8.html: ../src/local/local.c
PATH=../mantools:$$PATH; \
srctoman $? | $(AWK) | nroff -man | uniq | $(MAN2HTML) | postlink >$@
mailq.1.html: sendmail.1.html
- PATH=../mantools:$$PATH; \
rm -f $@
ln -s $? $@
+++ /dev/null
-<!doctype html public "-//W3C//DTD HTML 4.01 Transitional//EN"
- "http://www.w3.org/TR/html4/loose.dtd">
-<html> <head>
-<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
-<title> Postfix manual - lmtp(8) </title>
-</head> <body> <pre>
-LMTP(8) LMTP(8)
-
-<b>NAME</b>
- lmtp - Postfix local delivery via LMTP
-
-<b>SYNOPSIS</b>
- <b>lmtp</b> [generic Postfix daemon options]
-
-<b>DESCRIPTION</b>
- The LMTP client processes message delivery requests from
- the queue manager. Each request specifies a queue file, a
- sender address, a domain or host to deliver to, and recip-
- ient information. This program expects to be run from the
- <a href="master.8.html"><b>master</b>(8)</a> process manager.
-
- The LMTP client updates the queue file and marks recipi-
- ents as finished, or it informs the queue manager that
- delivery should be tried again at a later time. Delivery
- status reports are sent to the <a href="bounce.8.html"><b>bounce</b>(8)</a>, <a href="defer.8.html"><b>defer</b>(8)</a> or
- <a href="trace.8.html"><b>trace</b>(8)</a> daemon as appropriate.
-
- The LMTP client connects to the destination specified in
- the message delivery request. The destination, usually
- specified in the Postfix <a href="transport.5.html"><b>transport</b>(5)</a> table, has the form:
-
- <b>unix</b>:<i>pathname</i>
- Connect to the local UNIX-domain server that is
- bound to the specified <i>pathname</i>. If the process
- runs chrooted, an absolute pathname is interpreted
- relative to the changed root directory.
-
- <b>inet</b>:<i>host</i>, <b>inet:</b><i>host</i>:<i>port</i> (symbolic host)
-
- <b>inet</b>:[<i>addr</i>], <b>inet</b>:[<i>addr</i>]:<i>port</i> (numeric host)
- Connect to the specified IPV4 TCP port on the spec-
- ified local or remote host. If no port is speci-
- fied, connect to the port defined as <b>lmtp</b> in <b>ser-</b>
- <b>vices</b>(4). If no such service is found, the
- <b><a href="postconf.5.html#lmtp_tcp_port">lmtp_tcp_port</a></b> configuration parameter (default
- value of 24) will be used.
-
- The LMTP client does not perform MX (mail
- exchanger) lookups since those are defined only for
- mail delivery via SMTP.
-
- If neither <b>unix:</b> nor <b>inet:</b> are specified, <b>inet:</b> is
- assumed.
-
-<b>SECURITY</b>
- The LMTP client is moderately security-sensitive. It talks
- to LMTP servers and to DNS servers on the network. The
- LMTP client can be run chrooted at fixed low privilege.
-
-<b>STANDARDS</b>
- <a href="http://www.faqs.org/rfcs/rfc821.html">RFC 821</a> (SMTP protocol)
- <a href="http://www.faqs.org/rfcs/rfc1651.html">RFC 1651</a> (SMTP service extensions)
- <a href="http://www.faqs.org/rfcs/rfc1652.html">RFC 1652</a> (8bit-MIME transport)
- <a href="http://www.faqs.org/rfcs/rfc1870.html">RFC 1870</a> (Message Size Declaration)
- <a href="http://www.faqs.org/rfcs/rfc2033.html">RFC 2033</a> (LMTP protocol)
- <a href="http://www.faqs.org/rfcs/rfc2034.html">RFC 2034</a> (Enhanced Status codes)
- <a href="http://www.faqs.org/rfcs/rfc2554.html">RFC 2554</a> (AUTH command)
- <a href="http://www.faqs.org/rfcs/rfc2821.html">RFC 2821</a> (SMTP protocol)
- <a href="http://www.faqs.org/rfcs/rfc2920.html">RFC 2920</a> (SMTP Pipelining)
- <a href="http://www.faqs.org/rfcs/rfc3463.html">RFC 3463</a> (Enhanced Status codes)
-
-<b>DIAGNOSTICS</b>
- Problems and transactions are logged to <b>syslogd</b>(8). Cor-
- rupted message files are marked so that the queue manager
- can move them to the <b>corrupt</b> queue for further inspection.
-
- Depending on the setting of the <b><a href="postconf.5.html#notify_classes">notify_classes</a></b> parameter,
- the postmaster is notified of bounces, protocol problems,
- and of other trouble.
-
-<b>CONFIGURATION PARAMETERS</b>
- Changes to <b>main.cf</b> are picked up automatically, as <a href="lmtp.8.html"><b>lmtp</b>(8)</a>
- processes run for only a limited amount of time. Use the
- command "<b>postfix reload</b>" to speed up a change.
-
- The text below provides only a parameter summary. See
- <a href="postconf.5.html"><b>postconf</b>(5)</a> for more details including examples.
-
-<b>COMPATIBILITY CONTROLS</b>
- <b><a href="postconf.5.html#lmtp_skip_quit_response">lmtp_skip_quit_response</a> (no)</b>
- Wait for the response to the LMTP QUIT command.
-
-<b>TROUBLE SHOOTING CONTROLS</b>
- <b><a href="postconf.5.html#debug_peer_level">debug_peer_level</a> (2)</b>
- The increment in verbose logging level when a
- remote client or server matches a pattern in the
- <a href="postconf.5.html#debug_peer_list">debug_peer_list</a> parameter.
-
- <b><a href="postconf.5.html#debug_peer_list">debug_peer_list</a> (empty)</b>
- 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 $<a href="postconf.5.html#debug_peer_level">debug_peer_level</a>.
-
- <b><a href="postconf.5.html#error_notice_recipient">error_notice_recipient</a> (postmaster)</b>
- The recipient of postmaster notifications about
- mail delivery problems that are caused by policy,
- resource, software or protocol errors.
-
- <b><a href="postconf.5.html#notify_classes">notify_classes</a> (resource, software)</b>
- The list of error classes that are reported to the
- postmaster.
-
-<b>EXTERNAL CONTENT INSPECTION CONTROLS</b>
- Available in Postfix version 2.1 and later:
-
- <b><a href="postconf.5.html#lmtp_send_xforward_command">lmtp_send_xforward_command</a> (no)</b>
- Send an XFORWARD command to the LMTP server when
- the LMTP LHLO server response announces XFORWARD
- support.
-
-<b>SASL AUTHENTICATION CONTROLS</b>
- <b><a href="postconf.5.html#lmtp_sasl_auth_enable">lmtp_sasl_auth_enable</a> (no)</b>
- Enable SASL authentication in the Postfix LMTP
- client.
-
- <b><a href="postconf.5.html#lmtp_sasl_password_maps">lmtp_sasl_password_maps</a> (empty)</b>
- Optional LMTP client lookup tables with one user-
- name:password entry per host or domain.
-
- <b><a href="postconf.5.html#lmtp_sasl_security_options">lmtp_sasl_security_options</a> (noplaintext, noanonymous)</b>
- What authentication mechanisms the Postfix LMTP
- client is allowed to use.
-
-<b>RESOURCE AND RATE CONTROLS</b>
- In the text below, <i>transport</i> is the name of the service as
- specified in the <b>master.cf</b> file.
-
- <b><a href="postconf.5.html#lmtp_cache_connection">lmtp_cache_connection</a> (yes)</b>
- Keep Postfix LMTP client connections open for up to
- $<a href="postconf.5.html#max_idle">max_idle</a> seconds.
-
- <i>transport</i><b>_destination_concurrency_limit ($<a href="postconf.5.html#default_destination_concurrency_limit">default_destina</a>-</b>
- <b><a href="postconf.5.html#default_destination_concurrency_limit">tion_concurrency_limit</a>)</b>
- Limit the number of parallel deliveries to the same
- destination via this mail delivery transport.
-
- <i>transport</i><b>_destination_recipient_limit ($<a href="postconf.5.html#default_destination_recipient_limit">default_destina</a>-</b>
- <b><a href="postconf.5.html#default_destination_recipient_limit">tion_recipient_limit</a>)</b>
- Limit the number of recipients per message delivery
- via this mail delivery transport.
-
- This parameter becomes significant if the LMTP
- client is used for local delivery. Some LMTP
- servers can optimize delivery of the same message
- to multiple recipients. The default limit for local
- mail delivery is 1.
-
- Setting this parameter to 0 will lead to an
- unbounded number of recipients per delivery. How-
- ever, this could be risky since it may make the
- machine vulnerable to running out of resources if
- messages are encountered with an inordinate number
- of recipients. Exercise care when setting this
- parameter.
-
- <b><a href="postconf.5.html#lmtp_connect_timeout">lmtp_connect_timeout</a> (0s)</b>
- The LMTP client time limit for completing a TCP
- connection, or zero (use the operating system
- built-in time limit).
-
- <b><a href="postconf.5.html#lmtp_lhlo_timeout">lmtp_lhlo_timeout</a> (300s)</b>
- The LMTP client time limit for receiving the LMTP
- greeting banner.
-
- <b><a href="postconf.5.html#lmtp_xforward_timeout">lmtp_xforward_timeout</a> (300s)</b>
- The LMTP client time limit for sending the XFORWARD
- command, and for receiving the server response.
-
- <b><a href="postconf.5.html#lmtp_mail_timeout">lmtp_mail_timeout</a> (300s)</b>
- The LMTP client time limit for sending the MAIL
- FROM command, and for receiving the server
- response.
-
- <b><a href="postconf.5.html#lmtp_rcpt_timeout">lmtp_rcpt_timeout</a> (300s)</b>
- The LMTP client time limit for sending the RCPT TO
- command, and for receiving the server response.
-
- <b><a href="postconf.5.html#lmtp_data_init_timeout">lmtp_data_init_timeout</a> (120s)</b>
- The LMTP client time limit for sending the LMTP
- DATA command, and for receiving the server
- response.
-
- <b><a href="postconf.5.html#lmtp_data_xfer_timeout">lmtp_data_xfer_timeout</a> (180s)</b>
- The LMTP client time limit for sending the LMTP
- message content.
-
- <b><a href="postconf.5.html#lmtp_data_done_timeout">lmtp_data_done_timeout</a> (600s)</b>
- The LMTP client time limit for sending the LMTP
- ".", and for receiving the server response.
-
- <b><a href="postconf.5.html#lmtp_rset_timeout">lmtp_rset_timeout</a> (20s)</b>
- The LMTP client time limit for sending the RSET
- command, and for receiving the server response.
-
- <b><a href="postconf.5.html#lmtp_quit_timeout">lmtp_quit_timeout</a> (300s)</b>
- The LMTP client time limit for sending the QUIT
- command, and for receiving the server response.
-
-<b>MISCELLANEOUS CONTROLS</b>
- <b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
- The default location of the Postfix main.cf and
- master.cf configuration files.
-
- <b><a href="postconf.5.html#daemon_timeout">daemon_timeout</a> (18000s)</b>
- How much time a Postfix daemon process may take to
- handle a request before it is terminated by a
- built-in watchdog timer.
-
- <b><a href="postconf.5.html#delay_logging_resolution_limit">delay_logging_resolution_limit</a> (2)</b>
- The maximal number of digits after the decimal
- point when logging sub-second delay values.
-
- <b><a href="postconf.5.html#disable_dns_lookups">disable_dns_lookups</a> (no)</b>
- Disable DNS lookups in the Postfix SMTP and LMTP
- clients.
-
- <b><a href="postconf.5.html#ipc_timeout">ipc_timeout</a> (3600s)</b>
- The time limit for sending or receiving information
- over an internal communication channel.
-
- <b><a href="postconf.5.html#lmtp_tcp_port">lmtp_tcp_port</a> (24)</b>
- The default TCP port that the Postfix LMTP client
- connects to.
-
- <b><a href="postconf.5.html#max_idle">max_idle</a> (100s)</b>
- The maximum amount of time that an idle Postfix
- daemon process waits for the next service request
- before exiting.
-
- <b><a href="postconf.5.html#max_use">max_use</a> (100)</b>
- The maximal number of connection requests before a
- Postfix daemon process terminates.
-
- <b><a href="postconf.5.html#process_id">process_id</a> (read-only)</b>
- The process ID of a Postfix command or daemon
- process.
-
- <b><a href="postconf.5.html#process_name">process_name</a> (read-only)</b>
- The process name of a Postfix command or daemon
- process.
-
- <b><a href="postconf.5.html#queue_directory">queue_directory</a> (see 'postconf -d' output)</b>
- The location of the Postfix top-level queue direc-
- tory.
-
- <b><a href="postconf.5.html#syslog_facility">syslog_facility</a> (mail)</b>
- The syslog facility of Postfix logging.
-
- <b><a href="postconf.5.html#syslog_name">syslog_name</a> (postfix)</b>
- The mail system name that is prepended to the
- process name in syslog records, so that "smtpd"
- becomes, for example, "postfix/smtpd".
-
-<b>SEE ALSO</b>
- <a href="bounce.8.html">bounce(8)</a>, delivery status reports
- <a href="qmgr.8.html">qmgr(8)</a>, queue manager
- <a href="postconf.5.html">postconf(5)</a>, configuration parameters
- <a href="master.5.html">master(5)</a>, generic daemon options
- services(4), Internet services and aliases
- <a href="master.8.html">master(8)</a>, process manager
- syslogd(8), system logging
-
-<b>README FILES</b>
- <a href="LMTP_README.html">LMTP_README</a>, Postfix LMTP client howto
- <a href="VIRTUAL_README.html">VIRTUAL_README</a>, virtual delivery agent howto
-
-<b>LICENSE</b>
- The Secure Mailer license must be distributed with this
- software.
-
-<b>AUTHOR(S)</b>
- Wietse Venema
- IBM T.J. Watson Research
- P.O. Box 704
- Yorktown Heights, NY 10598, USA
-
- Modifications for LMTP by:
- Philip A. Prindeville
- Mirapoint, Inc.
- USA.
-
- SASL support originally by:
- Till Franke
- SuSE Rhein/Main AG
- 65760 Eschborn, Germany
-
- Additional work on LMTP by:
- Amos Gouaux
- University of Texas at Dallas
- P.O. Box 830688, MC34
- Richardson, TX 75083, USA
-
- LMTP(8)
-</pre> </body> </html>
--- /dev/null
+smtp.8.html
\ No newline at end of file
(the lookup result is ignored). Continue long lines by starting the
next line with whitespace. </p>
+<p>
+Example:
+</p>
+
+<pre>
+<a href="postconf.5.html#authorized_submit_users">authorized_submit_users</a> = !www, static:all
+</pre>
+
<p>
This feature is available in Postfix 2.2 and later.
</p>
parameter in the default main.cf file. </p>
+</DD>
+
+<DT><b><a name="connection_cache_protocol_timeout">connection_cache_protocol_timeout</a>
+(default: 5s)</b></DT><DD>
+
+<p> Time limit for connection cache connect, send or receive
+operations. The time limit is enforced in the client. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+
</DD>
<DT><b><a name="connection_cache_service">connection_cache_service</a>
<p>
Optional list of relay hosts for SMTP destinations that can't be
-found or that are unreachable. </p>
+found or that are unreachable. With Postfix 2.3 this parameter
+is renamed to smtp_fallback_relay. </p>
<p>
By default, mail is returned to the sender when a destination is
-not found, and delivery is deferred if a destination is unreachable.
+not found, and delivery is deferred when a destination is unreachable.
</p>
<p> The fallback relays must be SMTP destinations. Specify a domain,
[host] turns off MX lookups. If you specify multiple SMTP
destinations, Postfix will try them in the specified order. </p>
-<p> Note: do not use the <a href="postconf.5.html#fallback_relay">fallback_relay</a> feature when relaying mail
+<p> Note: before Postfix 2.2, do not use the <a href="postconf.5.html#fallback_relay">fallback_relay</a> feature
+when relaying mail
for a backup or primary MX domain. Mail would loop between the
Postfix MX host and the <a href="postconf.5.html#fallback_relay">fallback_relay</a> host when the final destination
is unavailable. </p>
</ul>
-<p> These are default settings in Postfix version 2.2 and later.
+<p> Postfix version 2.2 and later will not use the <a href="postconf.5.html#fallback_relay">fallback_relay</a> feature
+for destinations that it is MX host for.
</p>
this length; upon delivery, long lines are reconstructed. </p>
+</DD>
+
+<DT><b><a name="lmtp_bind_address">lmtp_bind_address</a>
+(default: empty)</b></DT><DD>
+
+<p> The LMTP-specific version of the <a href="postconf.5.html#smtp_bind_address">smtp_bind_address</a> configuration
+parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+
+</DD>
+
+<DT><b><a name="lmtp_bind_address6">lmtp_bind_address6</a>
+(default: empty)</b></DT><DD>
+
+<p> The LMTP-specific version of the <a href="postconf.5.html#smtp_bind_address6">smtp_bind_address6</a> configuration
+parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+
</DD>
<DT><b><a name="lmtp_cache_connection">lmtp_cache_connection</a>
</pre>
+</DD>
+
+<DT><b><a name="lmtp_connection_cache_destinations">lmtp_connection_cache_destinations</a>
+(default: empty)</b></DT><DD>
+
+<p> The LMTP-specific version of the <a href="postconf.5.html#smtp_connection_cache_destinations">smtp_connection_cache_destinations</a>
+configuration parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+
+</DD>
+
+<DT><b><a name="lmtp_connection_cache_on_demand">lmtp_connection_cache_on_demand</a>
+(default: yes)</b></DT><DD>
+
+<p> The LMTP-specific version of the <a href="postconf.5.html#smtp_connection_cache_on_demand">smtp_connection_cache_on_demand</a>
+configuration parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+
+</DD>
+
+<DT><b><a name="lmtp_connection_reuse_time_limit">lmtp_connection_reuse_time_limit</a>
+(default: 300s)</b></DT><DD>
+
+<p> The LMTP-specific version of the <a href="postconf.5.html#smtp_connection_reuse_time_limit">smtp_connection_reuse_time_limit</a>
+configuration parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+
</DD>
<DT><b><a name="lmtp_data_done_timeout">lmtp_data_done_timeout</a>
</p>
+</DD>
+
+<DT><b><a name="lmtp_defer_if_no_mx_address_found">lmtp_defer_if_no_mx_address_found</a>
+(default: no)</b></DT><DD>
+
+<p> The LMTP-specific version of the <a href="postconf.5.html#smtp_defer_if_no_mx_address_found">smtp_defer_if_no_mx_address_found</a>
+configuration parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+
</DD>
<DT><b><a name="lmtp_destination_concurrency_limit">lmtp_destination_concurrency_limit</a>
</DD>
-<DT><b><a name="lmtp_lhlo_timeout">lmtp_lhlo_timeout</a>
-(default: 300s)</b></DT><DD>
+<DT><b><a name="lmtp_discard_lhlo_keyword_address_maps">lmtp_discard_lhlo_keyword_address_maps</a>
+(default: empty)</b></DT><DD>
+
+<p> Lookup tables, indexed by the remote LMTP server address, with
+case insensitive lists of LHLO keywords (pipelining, starttls,
+auth, etc.) that the LMTP client will ignore in the LHLO response
+from a remote LMTP server. See lmtp_discard_lhlo_keywords for
+details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
-<p> The LMTP client time limit for receiving the LMTP greeting
-banner. When the server drops the connection without sending a
-greeting banner, or when it sends no greeting banner within the
-deadline, the LMTP client tries the next address on the mail
-exchanger list. </p>
+
+</DD>
+
+<DT><b><a name="lmtp_discard_lhlo_keywords">lmtp_discard_lhlo_keywords</a>
+(default: $<a href="postconf.5.html#myhostname">myhostname</a>)</b></DT><DD>
+
+<p> A case insensitive list of LHLO keywords (pipelining, starttls,
+auth, etc.) that the LMTP client will ignore in the LHLO response
+from a remote LMTP server. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+<p> Notes: </p>
+
+<ul>
+
+<li> <p> Specify the <b>silent-discard</b> pseudo keyword to prevent
+this action from being logged. </p>
+
+<li> <p> Use the lmtp_discard_lhlo_keyword_address_maps feature to
+discard LHLO keywords selectively. </p>
+
+</ul>
+
+
+</DD>
+
+<DT><b><a name="lmtp_enforce_tls">lmtp_enforce_tls</a>
+(default: no)</b></DT><DD>
+
+<p> The LMTP-specific version of the <a href="postconf.5.html#smtp_enforce_tls">smtp_enforce_tls</a> configuration
+parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+
+</DD>
+
+<DT><b><a name="lmtp_generic_maps">lmtp_generic_maps</a>
+(default: empty)</b></DT><DD>
+
+<p> The LMTP-specific version of the <a href="postconf.5.html#smtp_generic_maps">smtp_generic_maps</a> configuration
+parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+
+</DD>
+
+<DT><b><a name="lmtp_host_lookup">lmtp_host_lookup</a>
+(default: dns)</b></DT><DD>
+
+<p> The LMTP-specific version of the <a href="postconf.5.html#smtp_host_lookup">smtp_host_lookup</a> configuration
+parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+
+</DD>
+
+<DT><b><a name="lmtp_lhlo_name">lmtp_lhlo_name</a>
+(default: $<a href="postconf.5.html#myhostname">myhostname</a>)</b></DT><DD>
<p>
-Time units: s (seconds), m (minutes), h (hours), d (days), w (weeks).
-The default time unit is s (seconds).
+The hostname to send in the LMTP LHLO command.
+</p>
+
+<p>
+The default value is the machine hostname. Specify a hostname or
+[ip.add.re.ss].
</p>
+<p>
+This information can be specified in the main.cf file for all LMTP
+clients, or it can be specified in the master.cf file for a specific
+client, for example:
+</p>
+
+<pre>
+ /etc/postfix/master.cf:
+ mylmtp ... lmtp -o lmtp_lhlo_name=foo.bar.com
+</pre>
+
+<p>
+This feature is available in Postfix 2.3 and later.
+</p>
+
+
+</DD>
+
+<DT><b><a name="lmtp_lhlo_timeout">lmtp_lhlo_timeout</a>
+(default: 300s)</b></DT><DD>
+
+<p> The LMTP client time limit for sending the LHLO command, and
+for receiving the initial server response. </p>
+
+<p> Time units: s (seconds), m (minutes), h (hours), d (days), w
+(weeks). The default time unit is s (seconds). </p>
+
+
+</DD>
+
+<DT><b><a name="lmtp_line_length_limit">lmtp_line_length_limit</a>
+(default: 990)</b></DT><DD>
+
+<p> The LMTP-specific version of the <a href="postconf.5.html#smtp_line_length_limit">smtp_line_length_limit</a>
+configuration parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
</DD>
</p>
+</DD>
+
+<DT><b><a name="lmtp_mx_address_limit">lmtp_mx_address_limit</a>
+(default: 5)</b></DT><DD>
+
+<p> The LMTP-specific version of the <a href="postconf.5.html#smtp_mx_address_limit">smtp_mx_address_limit</a> configuration
+parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+
+</DD>
+
+<DT><b><a name="lmtp_mx_session_limit">lmtp_mx_session_limit</a>
+(default: 2)</b></DT><DD>
+
+<p> The LMTP-specific version of the <a href="postconf.5.html#smtp_mx_session_limit">smtp_mx_session_limit</a> configuration
+parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+
+</DD>
+
+<DT><b><a name="lmtp_pix_workaround_delay_time">lmtp_pix_workaround_delay_time</a>
+(default: 10s)</b></DT><DD>
+
+<p> The LMTP-specific version of the <a href="postconf.5.html#smtp_pix_workaround_delay_time">smtp_pix_workaround_delay_time</a>
+configuration parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+
+</DD>
+
+<DT><b><a name="lmtp_pix_workaround_threshold_time">lmtp_pix_workaround_threshold_time</a>
+(default: 500s)</b></DT><DD>
+
+<p> The LMTP-specific version of the <a href="postconf.5.html#smtp_pix_workaround_threshold_time">smtp_pix_workaround_threshold_time</a>
+configuration parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+
</DD>
<DT><b><a name="lmtp_quit_timeout">lmtp_quit_timeout</a>
</p>
+</DD>
+
+<DT><b><a name="lmtp_quote_rfc821_envelope">lmtp_quote_rfc821_envelope</a>
+(default: yes)</b></DT><DD>
+
+<p> The LMTP-specific version of the <a href="postconf.5.html#smtp_quote_rfc821_envelope">smtp_quote_rfc821_envelope</a>
+configuration parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+
+</DD>
+
+<DT><b><a name="lmtp_randomize_addresses">lmtp_randomize_addresses</a>
+(default: yes)</b></DT><DD>
+
+<p> The LMTP-specific version of the <a href="postconf.5.html#smtp_randomize_addresses">smtp_randomize_addresses</a>
+configuration parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+
</DD>
<DT><b><a name="lmtp_rcpt_timeout">lmtp_rcpt_timeout</a>
</p>
+</DD>
+
+<DT><b><a name="lmtp_sasl_mechanism_filter">lmtp_sasl_mechanism_filter</a>
+(default: empty)</b></DT><DD>
+
+<p> The LMTP-specific version of the <a href="postconf.5.html#smtp_sasl_mechanism_filter">smtp_sasl_mechanism_filter</a>
+configuration parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+
</DD>
<DT><b><a name="lmtp_sasl_password_maps">lmtp_sasl_password_maps</a>
</pre>
+</DD>
+
+<DT><b><a name="lmtp_sasl_tls_security_options">lmtp_sasl_tls_security_options</a>
+(default: $var_lmtp_sasl_opts)</b></DT><DD>
+
+<p> The LMTP-specific version of the <a href="postconf.5.html#smtp_sasl_tls_security_options">smtp_sasl_tls_security_options</a>
+configuration parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+
</DD>
<DT><b><a name="lmtp_send_xforward_command">lmtp_send_xforward_command</a>
</p>
+</DD>
+
+<DT><b><a name="lmtp_sender_dependent_authentication">lmtp_sender_dependent_authentication</a>
+(default: no)</b></DT><DD>
+
+<p> The LMTP-specific version of the <a href="postconf.5.html#smtp_sender_dependent_authentication">smtp_sender_dependent_authentication</a>
+configuration parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+
+</DD>
+
+<DT><b><a name="lmtp_skip_5xx_greeting">lmtp_skip_5xx_greeting</a>
+(default: yes)</b></DT><DD>
+
+<p> The LMTP-specific version of the <a href="postconf.5.html#smtp_skip_5xx_greeting">smtp_skip_5xx_greeting</a>
+configuration parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+
</DD>
<DT><b><a name="lmtp_skip_quit_response">lmtp_skip_quit_response</a>
</p>
+</DD>
+
+<DT><b><a name="lmtp_starttls_timeout">lmtp_starttls_timeout</a>
+(default: 300s)</b></DT><DD>
+
+<p> The LMTP-specific version of the <a href="postconf.5.html#smtp_starttls_timeout">smtp_starttls_timeout</a> configuration
+parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+
</DD>
<DT><b><a name="lmtp_tcp_port">lmtp_tcp_port</a>
</p>
+</DD>
+
+<DT><b><a name="lmtp_tls_enforce_peername">lmtp_tls_enforce_peername</a>
+(default: yes)</b></DT><DD>
+
+<p> The LMTP-specific version of the <a href="postconf.5.html#smtp_tls_enforce_peername">smtp_tls_enforce_peername</a>
+configuration parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+
+</DD>
+
+<DT><b><a name="lmtp_tls_note_starttls_offer">lmtp_tls_note_starttls_offer</a>
+(default: no)</b></DT><DD>
+
+<p> The LMTP-specific version of the <a href="postconf.5.html#smtp_tls_note_starttls_offer">smtp_tls_note_starttls_offer</a>
+configuration parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+
+</DD>
+
+<DT><b><a name="lmtp_tls_per_site">lmtp_tls_per_site</a>
+(default: empty)</b></DT><DD>
+
+<p> The LMTP-specific version of the <a href="postconf.5.html#smtp_tls_per_site">smtp_tls_per_site</a> configuration
+parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+
+</DD>
+
+<DT><b><a name="lmtp_tls_scert_verifydepth">lmtp_tls_scert_verifydepth</a>
+(default: 5)</b></DT><DD>
+
+<p> The LMTP-specific version of the <a href="postconf.5.html#smtp_tls_scert_verifydepth">smtp_tls_scert_verifydepth</a>
+configuration parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+
+</DD>
+
+<DT><b><a name="lmtp_use_tls">lmtp_use_tls</a>
+(default: no)</b></DT><DD>
+
+<p> The LMTP-specific version of the <a href="postconf.5.html#smtp_use_tls">smtp_use_tls</a> configuration
+parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+
</DD>
<DT><b><a name="lmtp_xforward_timeout">lmtp_xforward_timeout</a>
<p> A sender-dependent override for the global <a href="postconf.5.html#relayhost">relayhost</a> parameter
setting. The tables are searched by the sender address and by the
-sender @domain. This information is overruled with <a href="postconf.5.html#relay_transport">relay_transport</a>,
+@domain. This information is overruled with <a href="postconf.5.html#relay_transport">relay_transport</a>,
<a href="postconf.5.html#default_transport">default_transport</a> and with the <a href="transport.5.html">transport(5)</a> table. </p>
<p>
[] or non-default TCP port), as specified in main.cf or in the
transport map,
+<li> if mail is sent via a UNIX-domain socket: a pathname (without
+the unix: prefix),
+
<li> a /file/name with domain names and/or <a href="postconf.5.html#relayhost">relay host</a> names as
defined above,
send all their email to a dedicated mailhub. </p>
+</DD>
+
+<DT><b><a name="smtp_fallback_relay">smtp_fallback_relay</a>
+(default: $<a href="postconf.5.html#fallback_relay">fallback_relay</a>)</b></DT><DD>
+
+<p>
+Optional list of relay hosts for SMTP destinations that can't be
+found or that are unreachable. With Postfix 2.2 and earlier this
+parameter is called <a href="postconf.5.html#fallback_relay">fallback_relay</a>. </p>
+
+<p>
+By default, mail is returned to the sender when a destination is
+not found, and delivery is deferred when a destination is unreachable.
+</p>
+
+<p> The fallback relays must be SMTP destinations. Specify a domain,
+host, host:port, [host]:port, [address] or [address]:port; the form
+[host] turns off MX lookups. If you specify multiple SMTP
+destinations, Postfix will try them in the specified order. </p>
+
+<p> To prevent mailer loops between MX hosts and fall-back hosts,
+Postfix version 2.3 and later will not use the smtp_fallback_relay
+feature for destinations that it is MX host for. </p>
+
+
</DD>
<DT><b><a name="smtp_generic_maps">smtp_generic_maps</a>
<li> <a href="flush.8.html">flush(8)</a>, Postfix fast ETRN service
-<li> <a href="lmtp.8.html">lmtp(8)</a>, Postfix LMTP client
-
<li> <a href="local.8.html">local(8)</a>, Postfix local delivery agent
<li> <a href="master.8.html">master(8)</a>, Postfix master daemon
<li> <a href="showq.8.html">showq(8)</a>, list Postfix mail queue
-<li> <a href="smtp.8.html">smtp(8)</a>, Postfix SMTP client
+<li> <a href="smtp.8.html">smtp(8)</a>, <a href="lmtp.8.html">lmtp(8)</a>, Postfix SMTP+LMTP client
<li> <a href="smtpd.8.html">smtpd(8)</a>, Postfix SMTP server
<a href="discard.8.html">discard(8)</a>, Postfix discard delivery agent
<a href="error.8.html">error(8)</a>, Postfix error delivery agent
<a href="flush.8.html">flush(8)</a>, Postfix fast ETRN service
- <a href="lmtp.8.html">lmtp(8)</a>, Postfix LMTP client
<a href="local.8.html">local(8)</a>, Postfix local delivery agent
<a href="master.8.html">master(8)</a>, Postfix master daemon
<a href="qmgr.8.html">oqmgr(8)</a>, old Postfix queue manager
<a href="qmqpd.8.html">qmqpd(8)</a>, Postfix QMQP server
<a href="scache.8.html">scache(8)</a>, Postfix connection cache manager
<a href="showq.8.html">showq(8)</a>, list Postfix mail queue
- <a href="smtp.8.html">smtp(8)</a>, Postfix SMTP client
+ <a href="smtp.8.html">smtp(8)</a>, <a href="lmtp.8.html">lmtp(8)</a>, Postfix SMTP+LMTP client
<a href="smtpd.8.html">smtpd(8)</a>, Postfix SMTP server
<a href="spawn.8.html">spawn(8)</a>, run non-Postfix server
<a href="tlsmgr.8.html">tlsmgr(8)</a>, Postfix TLS cache and randomness manager
P.O. Box 704
Yorktown Heights, NY 10598, USA
+ SASL support originally by:
+ Till Franke
+ SuSE Rhein/Main AG
+ 65760 Eschborn, Germany
+
+ LMTP support originally by:
+ Philip A. Prindeville
+ Mirapoint, Inc.
+ USA.
+
+ Amos Gouaux
+ University of Texas at Dallas
+ P.O. Box 830688, MC34
+ Richardson, TX 75083, USA
+
POSTFIX(1)
</pre> </body> </html>
delete all mail with exactly one recipient
<b>user@example.com</b>:
- mailq | tail +2 | awk 'BEGIN { RS = "" }
+ mailq | tail +2 | grep -v '^ *(' | awk 'BEGIN { RS
+ = "" }
# $7=sender, $8=recipient1, $9=recipient2
{ if ($8 == "user@example.com" && $9 == "")
print $1 }
' | tr -d '*!' | postsuper -d -
Specify <b>-d ALL</b> to remove all messages; for example,
- specify <b>-d ALL deferred</b> to delete mail in the
- <b>deferred</b> queue. As a safety measure, the word <b>ALL</b>
+ specify <b>-d ALL deferred</b> to delete mail in the
+ <b>deferred</b> queue. As a safety measure, the word <b>ALL</b>
must be specified in upper case.
- Warning: Postfix queue IDs are reused. There is a
- very small possibility that postsuper deletes the
- wrong message file when it is executed while the
+ Warning: Postfix queue IDs are reused. There is a
+ very small possibility that postsuper deletes the
+ wrong message file when it is executed while the
Postfix mail system is delivering mail.
The scenario is as follows:
- 1) The Postfix queue manager deletes the mes-
- sage that <a href="postsuper.1.html"><b>postsuper</b>(1)</a> is asked to delete,
+ 1) The Postfix queue manager deletes the mes-
+ sage that <a href="postsuper.1.html"><b>postsuper</b>(1)</a> is asked to delete,
because Postfix is finished with the message
- (it is delivered, or it is returned to the
+ (it is delivered, or it is returned to the
sender).
- 2) New mail arrives, and the new message is
- given the same queue ID as the message that
- <a href="postsuper.1.html"><b>postsuper</b>(1)</a> is supposed to delete. The
- probability for reusing a deleted queue ID
+ 2) New mail arrives, and the new message is
+ given the same queue ID as the message that
+ <a href="postsuper.1.html"><b>postsuper</b>(1)</a> is supposed to delete. The
+ probability for reusing a deleted queue ID
is about 1 in 2**15 (the number of different
microsecond values that the system clock can
distinguish within a second).
- 3) <a href="postsuper.1.html"><b>postsuper</b>(1)</a> deletes the new message,
- instead of the old message that it should
+ 3) <a href="postsuper.1.html"><b>postsuper</b>(1)</a> deletes the new message,
+ instead of the old message that it should
have deleted.
<b>-h</b> <i>queue</i><b>_</b><i>id</i>
- Put mail "on hold" so that no attempt is made to
- deliver it. Move one message with the named queue
+ Put mail "on hold" so that no attempt is made to
+ deliver it. Move one message with the named queue
ID from the named mail queue(s) (default: <b>incoming</b>,
<b>active</b> and <b>deferred</b>) to the <b>hold</b> queue.
- If a <i>queue</i><b>_</b><i>id</i> of <b>-</b> is specified, the program reads
+ If a <i>queue</i><b>_</b><i>id</i> of <b>-</b> is specified, the program reads
queue IDs from standard input.
- Specify <b>-h ALL</b> to hold all messages; for example,
+ Specify <b>-h ALL</b> to hold all messages; for example,
specify <b>-h ALL deferred</b> to hold mail in the
- <b>deferred</b> queue. As a safety measure, the word <b>ALL</b>
+ <b>deferred</b> queue. As a safety measure, the word <b>ALL</b>
must be specified in upper case.
- Note: while mail is "on hold" it will not expire
- when its time in the queue exceeds the <b><a href="postconf.5.html#maximal_queue_lifetime">maxi</a>-</b>
+ Note: while mail is "on hold" it will not expire
+ when its time in the queue exceeds the <b><a href="postconf.5.html#maximal_queue_lifetime">maxi</a>-</b>
<b><a href="postconf.5.html#maximal_queue_lifetime">mal_queue_lifetime</a></b> or <b><a href="postconf.5.html#bounce_queue_lifetime">bounce_queue_lifetime</a></b> set-
- ting. It becomes subject to expiration after it is
+ ting. It becomes subject to expiration after it is
released from "hold".
<b>-H</b> <i>queue</i><b>_</b><i>id</i>
Release mail that was put "on hold". Move one mes-
- sage with the named queue ID from the named mail
+ sage with the named queue ID from the named mail
queue(s) (default: <b>hold</b>) to the <b>deferred</b> queue.
- If a <i>queue</i><b>_</b><i>id</i> of <b>-</b> is specified, the program reads
+ If a <i>queue</i><b>_</b><i>id</i> of <b>-</b> is specified, the program reads
queue IDs from standard input.
- Note: use "<b>postsuper -r</b>" to release mail that was
- kept on hold for a significant fraction of <b>$<a href="postconf.5.html#maximal_queue_lifetime">maxi</a>-</b>
+ Note: use "<b>postsuper -r</b>" to release mail that was
+ kept on hold for a significant fraction of <b>$<a href="postconf.5.html#maximal_queue_lifetime">maxi</a>-</b>
<b><a href="postconf.5.html#maximal_queue_lifetime">mal_queue_lifetime</a></b> or <b>$<a href="postconf.5.html#bounce_queue_lifetime">bounce_queue_lifetime</a></b>, or
longer.
- Specify <b>-H ALL</b> to release all mail that is "on
- hold". As a safety measure, the word <b>ALL</b> must be
+ Specify <b>-H ALL</b> to release all mail that is "on
+ hold". As a safety measure, the word <b>ALL</b> must be
specified in upper case.
- <b>-p</b> Purge old temporary files that are left over after
+ <b>-p</b> Purge old temporary files that are left over after
system or software crashes.
<b>-r</b> <i>queue</i><b>_</b><i>id</i>
- Requeue the message with the named queue ID from
- the named mail queue(s) (default: <b>hold</b>, <b>incoming</b>,
- <b>active</b> and <b>deferred</b>). To requeue multiple mes-
+ Requeue the message with the named queue ID from
+ the named mail queue(s) (default: <b>hold</b>, <b>incoming</b>,
+ <b>active</b> and <b>deferred</b>). To requeue multiple mes-
sages, specify multiple <b>-r</b> command-line options.
Alternatively, if a <i>queue</i><b>_</b><i>id</i> of <b>-</b> is specified, the
program reads queue IDs from standard input.
Specify <b>-r ALL</b> to requeue all messages. As a safety
- measure, the word <b>ALL</b> must be specified in upper
+ measure, the word <b>ALL</b> must be specified in upper
case.
- A requeued message is moved to the <b>maildrop</b> queue,
- from where it is copied by the pickup daemon to a
- new file whose name is guaranteed to match the new
+ A requeued message is moved to the <b>maildrop</b> queue,
+ from where it is copied by the pickup daemon to a
+ new file whose name is guaranteed to match the new
queue file inode number. The new queue file is sub-
- jected again to mail address rewriting and substi-
+ jected again to mail address rewriting and substi-
tution. This is useful when rewriting rules or vir-
tual mappings have changed.
- Warning: Postfix queue IDs are reused. There is a
- very small possibility that <a href="postsuper.1.html"><b>postsuper</b>(1)</a> requeues
- the wrong message file when it is executed while
- the Postfix mail system is running, but no harm
+ Warning: Postfix queue IDs are reused. There is a
+ very small possibility that <a href="postsuper.1.html"><b>postsuper</b>(1)</a> requeues
+ the wrong message file when it is executed while
+ the Postfix mail system is running, but no harm
should be done.
- <b>-s</b> Structure check and structure repair. This should
+ <b>-s</b> Structure check and structure repair. This should
be done once before Postfix startup.
- <b>o</b> Rename files whose name does not match the
+ <b>o</b> Rename files whose name does not match the
message file inode number. This operation is
- necessary after restoring a mail queue from
+ necessary after restoring a mail queue from
a different machine, or from backup media.
<b>o</b> Move queue files that are in the wrong place
in the file system hierarchy and remove sub-
directories that are no longer needed. File
- position rearrangements are necessary after
+ position rearrangements are necessary after
a change in the <b><a href="postconf.5.html#hash_queue_names">hash_queue_names</a></b> and/or
<b><a href="postconf.5.html#hash_queue_depth">hash_queue_depth</a></b> configuration parameters.
<b>-v</b> Enable verbose logging for debugging purposes. Mul-
- tiple <b>-v</b> options make the software increasingly
+ tiple <b>-v</b> options make the software increasingly
verbose.
<b>DIAGNOSTICS</b>
- Problems are reported to the standard error stream and to
+ Problems are reported to the standard error stream and to
<b>syslogd</b>(8).
- <a href="postsuper.1.html"><b>postsuper</b>(1)</a> reports the number of messages deleted with
- <b>-d</b>, the number of messages requeued with <b>-r</b>, and the num-
- ber of messages whose queue file name was fixed with <b>-s</b>.
- The report is written to the standard error stream and to
+ <a href="postsuper.1.html"><b>postsuper</b>(1)</a> reports the number of messages deleted with
+ <b>-d</b>, the number of messages requeued with <b>-r</b>, and the num-
+ ber of messages whose queue file name was fixed with <b>-s</b>.
+ The report is written to the standard error stream and to
<b>syslogd</b>(8).
<b>ENVIRONMENT</b>
Directory with the <b>main.cf</b> file.
<b>BUGS</b>
- Mail that is not sanitized by Postfix (i.e. mail in the
+ Mail that is not sanitized by Postfix (i.e. mail in the
<b>maildrop</b> queue) cannot be placed "on hold".
<b>CONFIGURATION PARAMETERS</b>
- The following <b>main.cf</b> parameters are especially relevant
+ The following <b>main.cf</b> parameters are especially relevant
to this program. The text below provides only a parameter
- summary. See <a href="postconf.5.html"><b>postconf</b>(5)</a> for more details including exam-
+ summary. See <a href="postconf.5.html"><b>postconf</b>(5)</a> for more details including exam-
ples.
<b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
- The default location of the Postfix main.cf and
+ The default location of the Postfix main.cf and
master.cf configuration files.
<b><a href="postconf.5.html#hash_queue_depth">hash_queue_depth</a> (1)</b>
- The number of subdirectory levels for queue direc-
- tories listed with the <a href="postconf.5.html#hash_queue_names">hash_queue_names</a> parameter.
+ The number of subdirectory levels for queue direc-
+ tories listed with the <a href="postconf.5.html#hash_queue_names">hash_queue_names</a> parameter.
<b><a href="postconf.5.html#hash_queue_names">hash_queue_names</a> (deferred, defer)</b>
- The names of queue directories that are split
+ The names of queue directories that are split
across multiple subdirectory levels.
<b><a href="postconf.5.html#queue_directory">queue_directory</a> (see 'postconf -d' output)</b>
- The location of the Postfix top-level queue direc-
+ The location of the Postfix top-level queue direc-
tory.
<b><a href="postconf.5.html#syslog_facility">syslog_facility</a> (mail)</b>
The syslog facility of Postfix logging.
<b><a href="postconf.5.html#syslog_name">syslog_name</a> (postfix)</b>
- The mail system name that is prepended to the
- process name in syslog records, so that "smtpd"
+ The mail system name that is prepended to the
+ process name in syslog records, so that "smtpd"
becomes, for example, "postfix/smtpd".
<b>SEE ALSO</b>
<a href="postqueue.1.html">postqueue(1)</a>, unprivileged queue operations
<b>LICENSE</b>
- The Secure Mailer license must be distributed with this
+ The Secure Mailer license must be distributed with this
software.
<b>AUTHOR(S)</b>
SMTP(8) SMTP(8)
<b>NAME</b>
- smtp - Postfix SMTP client
+ smtp - Postfix SMTP+LMTP client
<b>SYNOPSIS</b>
<b>smtp</b> [generic Postfix daemon options]
<b>DESCRIPTION</b>
- The Postfix SMTP client processes message delivery
- requests from the queue manager. Each request specifies a
- queue file, a sender address, a domain or host to deliver
+ The Postfix SMTP+LMTP client implements the SMTP and LMTP
+ mail delivery protocols. It processes message delivery
+ requests from the queue manager. Each request specifies a
+ queue file, a sender address, a domain or host to deliver
to, and recipient information. This program expects to be
run from the <a href="master.8.html"><b>master</b>(8)</a> process manager.
- The SMTP client updates the queue file and marks recipi-
- ents as finished, or it informs the queue manager that
- delivery should be tried again at a later time. Delivery
- status reports are sent to the <a href="bounce.8.html"><b>bounce</b>(8)</a>, <a href="defer.8.html"><b>defer</b>(8)</a> or
- <a href="trace.8.html"><b>trace</b>(8)</a> daemon as appropriate.
+ The SMTP+LMTP client updates the queue file and marks
+ recipients as finished, or it informs the queue manager
+ that delivery should be tried again at a later time.
+ Delivery status reports are sent to the <a href="bounce.8.html"><b>bounce</b>(8)</a>,
+ <a href="defer.8.html"><b>defer</b>(8)</a> or <a href="trace.8.html"><b>trace</b>(8)</a> daemon as appropriate.
- The SMTP client looks up a list of mail exchanger
- addresses for the destination host, sorts the list by
- preference, and connects to each listed address until it
+ The SMTP+LMTP client looks up a list of mail exchanger
+ addresses for the destination host, sorts the list by
+ preference, and connects to each listed address until it
finds a server that responds.
- When a server is not reachable, or when mail delivery
- fails due to a recoverable error condition, the SMTP
- client will try to deliver the mail to an alternate host.
+ When a server is not reachable, or when mail delivery
+ fails due to a recoverable error condition, the SMTP+LMTP
+ client will try to deliver the mail to an alternate host.
- After a successful mail transaction, a connection may be
+ After a successful mail transaction, a connection may be
saved to the <a href="scache.8.html"><b>scache</b>(8)</a> connection cache server, so that it
- may be used by any SMTP client for a subsequent transac-
- tion.
+ may be used by any SMTP+LMTP client for a subsequent
+ transaction.
- By default, connection caching is enabled temporarily for
+ By default, connection caching is enabled temporarily for
destinations that have a high volume of mail in the active
queue. Session caching can be enabled permanently for spe-
cific destinations.
+<b>SMTP DESTINATION SYNTAX</b>
+ SMTP destinations have the following form:
+
+ <i>domainname</i>, <i>domainname</i>:<i>port</i>
+ Look up the mail exchangers for the specified
+ domain.
+
+ [<i>hostname</i>], [<i>hostname</i>]:<i>port</i>
+ Look up the address of the specified host.
+
+ [<i>address</i>], [<i>address</i>]:<i>port</i>
+ Connect to the host at the specified address. An
+ IPv6 address must be formatted as [<b>ipv6</b>:<i>address</i>].
+
+ In all the above cases, when no port is specified, look up
+ the port defined as <b>smtp</b> in <b>services</b>(4).
+
+<b>LMTP DESTINATION SYNTAX</b>
+ LMTP destinations have the following form:
+
+ <b>unix</b>:<i>pathname</i>
+ Connect to the local UNIX-domain server that is
+ bound to the specified <i>pathname</i>. If the process
+ runs chrooted, an absolute pathname is interpreted
+ relative to the Postfix queue directory.
+
+ <b>inet</b>:<i>hostname</i>, <b>inet:</b><i>hostname</i>:<i>port</i>
+
+ <b>inet</b>:[<i>address</i>], <b>inet</b>:[<i>address</i>]:<i>port</i>
+ Connect to the specified TCP port on the specified
+ local or remote host. If no port is specified, con-
+ nect to the port defined as <b>lmtp</b> in <b>services</b>(4).
+ If no such service is found, the <b><a href="postconf.5.html#lmtp_tcp_port">lmtp_tcp_port</a></b> con-
+ figuration parameter (default value of 24) will be
+ used.
+
<b>SECURITY</b>
- The SMTP client is moderately security-sensitive. It talks
- to SMTP servers and to DNS servers on the network. The
- SMTP client can be run chrooted at fixed low privilege.
+ The SMTP+LMTP client is moderately security-sensitive. It
+ talks to SMTP or LMTP servers and to DNS servers on the
+ network. The SMTP+LMTP client can be run chrooted at fixed
+ low privilege.
<b>STANDARDS</b>
<a href="http://www.faqs.org/rfcs/rfc821.html">RFC 821</a> (SMTP protocol)
<a href="http://www.faqs.org/rfcs/rfc1651.html">RFC 1651</a> (SMTP service extensions)
<a href="http://www.faqs.org/rfcs/rfc1652.html">RFC 1652</a> (8bit-MIME transport)
<a href="http://www.faqs.org/rfcs/rfc1870.html">RFC 1870</a> (Message Size Declaration)
- <a href="http://www.faqs.org/rfcs/rfc2045.html">RFC 2045</a> (MIME: Format of Internet Message Bodies)
+ <a href="http://www.faqs.org/rfcs/rfc2033.html">RFC 2033</a> (LMTP protocol)
<a href="http://www.faqs.org/rfcs/rfc2034.html">RFC 2034</a> (Enhanced Status Codes)
+ <a href="http://www.faqs.org/rfcs/rfc2045.html">RFC 2045</a> (MIME: Format of Internet Message Bodies)
<a href="http://www.faqs.org/rfcs/rfc2046.html">RFC 2046</a> (MIME: Media Types)
<a href="http://www.faqs.org/rfcs/rfc2554.html">RFC 2554</a> (AUTH command)
<a href="http://www.faqs.org/rfcs/rfc2821.html">RFC 2821</a> (SMTP protocol)
<a href="http://www.faqs.org/rfcs/rfc3463.html">RFC 3463</a> (Enhanced Status Codes)
<b>DIAGNOSTICS</b>
- Problems and transactions are logged to <b>syslogd</b>(8). Cor-
- rupted message files are marked so that the queue manager
+ Problems and transactions are logged to <b>syslogd</b>(8). Cor-
+ rupted message files are marked so that the queue manager
can move them to the <b>corrupt</b> queue for further inspection.
- Depending on the setting of the <b><a href="postconf.5.html#notify_classes">notify_classes</a></b> parameter,
- the postmaster is notified of bounces, protocol problems,
+ Depending on the setting of the <b><a href="postconf.5.html#notify_classes">notify_classes</a></b> parameter,
+ the postmaster is notified of bounces, protocol problems,
and of other trouble.
<b>BUGS</b>
- SMTP connection caching does not work with TLS. The neces-
- sary support for TLS object passivation and re-activation
- does not exist without closing the session, which defeats
- the purpose.
+ SMTP and LMTP connection caching does not work with TLS.
+ The necessary support for TLS object passivation and re-
+ activation does not exist without closing the session,
+ which defeats the purpose.
- SMTP connection caching assumes that SASL credentials are
- valid for all destinations that map onto the same IP
- address and TCP port.
+ SMTP and LMTP connection caching assumes that SASL creden-
+ tials are valid for all destinations that map onto the
+ same IP address and TCP port.
<b>CONFIGURATION PARAMETERS</b>
+ Most smtp_<i>xxx</i> configuration parameters have an lmtp_<i>xxx</i>
+ "ghost" parameter for the equivalent LMTP feature. This
+ document describes only those LMTP-related parameters that
+ aren't simply "ghost" parameters.
+
Changes to <b>main.cf</b> are picked up automatically, as <a href="smtp.8.html"><b>smtp</b>(8)</a>
processes run for only a limited amount of time. Use the
command "<b>postfix reload</b>" to speed up a change.
locally valid address into a globally valid address
when sending mail across the Internet.
+ Available in Postfix version 2.3 and later:
+
+ <b>lmtp_discard_lhlo_keyword_address_maps (empty)</b>
+ Lookup tables, indexed by the remote LMTP server
+ address, with case insensitive lists of LHLO key-
+ words (pipelining, starttls, auth, etc.) that the
+ LMTP client will ignore in the LHLO response from a
+ remote LMTP server.
+
+ <b>lmtp_discard_lhlo_keywords ($<a href="postconf.5.html#myhostname">myhostname</a>)</b>
+ A case insensitive list of LHLO keywords (pipelin-
+ ing, starttls, auth, etc.) that the LMTP client
+ will ignore in the LHLO response from a remote LMTP
+ server.
+
<b>MIME PROCESSING CONTROLS</b>
Available in Postfix version 2.0 and later:
<b><a href="postconf.5.html#disable_mime_output_conversion">disable_mime_output_conversion</a> (no)</b>
- Disable the conversion of 8BITMIME format to 7BIT
+ Disable the conversion of 8BITMIME format to 7BIT
format.
<b><a href="postconf.5.html#mime_boundary_length_limit">mime_boundary_length_limit</a> (2048)</b>
Available in Postfix version 2.1 and later:
<b><a href="postconf.5.html#smtp_send_xforward_command">smtp_send_xforward_command</a> (no)</b>
- Send the non-standard XFORWARD command when the
- Postfix SMTP server EHLO response announces XFOR-
+ Send the non-standard XFORWARD command when the
+ Postfix SMTP server EHLO response announces XFOR-
WARD support.
<b>SASL AUTHENTICATION CONTROLS</b>
<b><a href="postconf.5.html#smtp_sasl_auth_enable">smtp_sasl_auth_enable</a> (no)</b>
- Enable SASL authentication in the Postfix SMTP
+ Enable SASL authentication in the Postfix SMTP
client.
<b><a href="postconf.5.html#smtp_sasl_password_maps">smtp_sasl_password_maps</a> (empty)</b>
- Optional SMTP client lookup tables with one user-
- name:password entry per remote hostname or domain,
+ Optional SMTP client lookup tables with one user-
+ name:password entry per remote hostname or domain,
or sender address when sender-dependent authentica-
tion is enabled.
<b><a href="postconf.5.html#smtp_sasl_security_options">smtp_sasl_security_options</a> (noplaintext, noanonymous)</b>
- What authentication mechanisms the Postfix SMTP
+ What authentication mechanisms the Postfix SMTP
client is allowed to use.
Available in Postfix version 2.2 and later:
<b><a href="postconf.5.html#smtp_sasl_mechanism_filter">smtp_sasl_mechanism_filter</a> (empty)</b>
- If non-empty, a Postfix SMTP client filter for the
- remote SMTP server's list of offered SASL mecha-
+ If non-empty, a Postfix SMTP client filter for the
+ remote SMTP server's list of offered SASL mecha-
nisms.
Available in Postfix version 2.3 and later:
<b><a href="postconf.5.html#smtp_sender_dependent_authentication">smtp_sender_dependent_authentication</a> (no)</b>
- Enable sender-dependent authentication in the SMTP
- client; this is available only with SASL authenti-
- cation, and disables SMTP connection caching to
- ensure that mail from different senders will use
+ Enable sender-dependent authentication in the SMTP
+ client; this is available only with SASL authenti-
+ cation, and disables SMTP connection caching to
+ ensure that mail from different senders will use
the appropriate credentials.
<b>STARTTLS SUPPORT CONTROLS</b>
- Detailed information about STARTTLS configuration may be
+ Detailed information about STARTTLS configuration may be
found in the <a href="TLS_README.html">TLS_README</a> document.
<b><a href="postconf.5.html#smtp_use_tls">smtp_use_tls</a> (no)</b>
- Opportunistic mode: use TLS when a remote SMTP
- server announces STARTTLS support, otherwise send
+ Opportunistic mode: use TLS when a remote SMTP
+ server announces STARTTLS support, otherwise send
the mail in the clear.
<b><a href="postconf.5.html#smtp_enforce_tls">smtp_enforce_tls</a> (no)</b>
- Enforcement mode: require that remote SMTP servers
- use TLS encryption, and never send mail in the
+ Enforcement mode: require that remote SMTP servers
+ use TLS encryption, and never send mail in the
clear.
<b><a href="postconf.5.html#smtp_sasl_tls_security_options">smtp_sasl_tls_security_options</a> ($<a href="postconf.5.html#smtp_sasl_security_options">smtp_sasl_secu</a>-</b>
<b><a href="postconf.5.html#smtp_sasl_security_options">rity_options</a>)</b>
- The SASL authentication security options that the
- Postfix SMTP client uses for TLS encrypted SMTP
+ The SASL authentication security options that the
+ Postfix SMTP client uses for TLS encrypted SMTP
sessions.
<b><a href="postconf.5.html#smtp_starttls_timeout">smtp_starttls_timeout</a> (300s)</b>
- Time limit for Postfix SMTP client write and read
- operations during TLS startup and shutdown hand-
+ Time limit for Postfix SMTP client write and read
+ operations during TLS startup and shutdown hand-
shake procedures.
<b><a href="postconf.5.html#smtp_tls_CAfile">smtp_tls_CAfile</a> (empty)</b>
- The file with the certificate of the certification
- authority (CA) that issued the Postfix SMTP client
+ The file with the certificate of the certification
+ authority (CA) that issued the Postfix SMTP client
certificate.
<b><a href="postconf.5.html#smtp_tls_CApath">smtp_tls_CApath</a> (empty)</b>
- Directory with PEM format certificate authority
- certificates that the Postfix SMTP client uses to
+ Directory with PEM format certificate authority
+ certificates that the Postfix SMTP client uses to
verify a remote SMTP server certificate.
<b><a href="postconf.5.html#smtp_tls_cert_file">smtp_tls_cert_file</a> (empty)</b>
- File with the Postfix SMTP client RSA certificate
+ File with the Postfix SMTP client RSA certificate
in PEM format.
<b><a href="postconf.5.html#smtp_tls_cipherlist">smtp_tls_cipherlist</a> (empty)</b>
- Controls the Postfix SMTP client TLS cipher selec-
+ Controls the Postfix SMTP client TLS cipher selec-
tion scheme.
<b><a href="postconf.5.html#smtp_tls_dcert_file">smtp_tls_dcert_file</a> (empty)</b>
- File with the Postfix SMTP client DSA certificate
+ File with the Postfix SMTP client DSA certificate
in PEM format.
<b><a href="postconf.5.html#smtp_tls_dkey_file">smtp_tls_dkey_file</a> ($<a href="postconf.5.html#smtp_tls_dcert_file">smtp_tls_dcert_file</a>)</b>
- File with the Postfix SMTP client DSA private key
+ File with the Postfix SMTP client DSA private key
in PEM format.
<b><a href="postconf.5.html#smtp_tls_enforce_peername">smtp_tls_enforce_peername</a> (yes)</b>
- When TLS encryption is enforced, require that the
+ When TLS encryption is enforced, require that the
remote SMTP server hostname matches the information
in the remote SMTP server certificate.
<b><a href="postconf.5.html#smtp_tls_key_file">smtp_tls_key_file</a> ($<a href="postconf.5.html#smtp_tls_cert_file">smtp_tls_cert_file</a>)</b>
- File with the Postfix SMTP client RSA private key
+ File with the Postfix SMTP client RSA private key
in PEM format.
<b><a href="postconf.5.html#smtp_tls_loglevel">smtp_tls_loglevel</a> (0)</b>
- Enable additional Postfix SMTP client logging of
+ Enable additional Postfix SMTP client logging of
TLS activity.
<b><a href="postconf.5.html#smtp_tls_note_starttls_offer">smtp_tls_note_starttls_offer</a> (no)</b>
- Log the hostname of a remote SMTP server that
- offers STARTTLS, when TLS is not already enabled
+ Log the hostname of a remote SMTP server that
+ offers STARTTLS, when TLS is not already enabled
for that server.
<b><a href="postconf.5.html#smtp_tls_per_site">smtp_tls_per_site</a> (empty)</b>
Optional lookup tables with the Postfix SMTP client
- TLS usage policy by next-hop domain name and by
+ TLS usage policy by next-hop domain name and by
remote SMTP server hostname.
<b><a href="postconf.5.html#smtp_tls_scert_verifydepth">smtp_tls_scert_verifydepth</a> (5)</b>
- The verification depth for remote SMTP server cer-
+ The verification depth for remote SMTP server cer-
tificates.
<b><a href="postconf.5.html#smtp_tls_session_cache_database">smtp_tls_session_cache_database</a> (empty)</b>
- Name of the file containing the optional Postfix
+ Name of the file containing the optional Postfix
SMTP client TLS session cache.
<b><a href="postconf.5.html#smtp_tls_session_cache_timeout">smtp_tls_session_cache_timeout</a> (3600s)</b>
sion cache information.
<b><a href="postconf.5.html#tls_daemon_random_bytes">tls_daemon_random_bytes</a> (32)</b>
- The number of pseudo-random bytes that an <a href="smtp.8.html"><b>smtp</b>(8)</a>
- or <a href="smtpd.8.html"><b>smtpd</b>(8)</a> process requests from the <a href="tlsmgr.8.html"><b>tlsmgr</b>(8)</a>
- server in order to seed its internal pseudo random
+ The number of pseudo-random bytes that an <a href="smtp.8.html"><b>smtp</b>(8)</a>
+ or <a href="smtpd.8.html"><b>smtpd</b>(8)</a> process requests from the <a href="tlsmgr.8.html"><b>tlsmgr</b>(8)</a>
+ server in order to seed its internal pseudo random
number generator (PRNG).
<b>RESOURCE AND RATE CONTROLS</b>
<b><a href="postconf.5.html#smtp_destination_concurrency_limit">smtp_destination_concurrency_limit</a> ($<a href="postconf.5.html#default_destination_concurrency_limit">default_destina</a>-</b>
<b><a href="postconf.5.html#default_destination_concurrency_limit">tion_concurrency_limit</a>)</b>
- The maximal number of parallel deliveries to the
- same destination via the smtp message delivery
+ The maximal number of parallel deliveries to the
+ same destination via the smtp message delivery
transport.
<b><a href="postconf.5.html#smtp_destination_recipient_limit">smtp_destination_recipient_limit</a> ($<a href="postconf.5.html#default_destination_recipient_limit">default_destina</a>-</b>
<b><a href="postconf.5.html#default_destination_recipient_limit">tion_recipient_limit</a>)</b>
- The maximal number of recipients per delivery via
+ The maximal number of recipients per delivery via
the smtp message delivery transport.
<b><a href="postconf.5.html#smtp_connect_timeout">smtp_connect_timeout</a> (30s)</b>
- The SMTP client time limit for completing a TCP
+ The SMTP client time limit for completing a TCP
connection, or zero (use the operating system
built-in time limit).
<b><a href="postconf.5.html#smtp_helo_timeout">smtp_helo_timeout</a> (300s)</b>
- The SMTP client time limit for sending the HELO or
- EHLO command, and for receiving the initial server
+ The SMTP client time limit for sending the HELO or
+ EHLO command, and for receiving the initial server
+ response.
+
+ <b><a href="postconf.5.html#lmtp_lhlo_timeout">lmtp_lhlo_timeout</a> (300s)</b>
+ The LMTP client time limit for sending the LHLO
+ command, and for receiving the initial server
response.
<b><a href="postconf.5.html#smtp_xforward_timeout">smtp_xforward_timeout</a> (300s)</b>
command, and for receiving the server response.
<b><a href="postconf.5.html#smtp_mail_timeout">smtp_mail_timeout</a> (300s)</b>
- The SMTP client time limit for sending the MAIL
- FROM command, and for receiving the server
+ The SMTP client time limit for sending the MAIL
+ FROM command, and for receiving the server
response.
<b><a href="postconf.5.html#smtp_rcpt_timeout">smtp_rcpt_timeout</a> (300s)</b>
- The SMTP client time limit for sending the SMTP
- RCPT TO command, and for receiving the server
+ The SMTP client time limit for sending the SMTP
+ RCPT TO command, and for receiving the server
response.
<b><a href="postconf.5.html#smtp_data_init_timeout">smtp_data_init_timeout</a> (120s)</b>
- The SMTP client time limit for sending the SMTP
- DATA command, and for receiving the server
+ The SMTP client time limit for sending the SMTP
+ DATA command, and for receiving the server
response.
<b><a href="postconf.5.html#smtp_data_xfer_timeout">smtp_data_xfer_timeout</a> (180s)</b>
- The SMTP client time limit for sending the SMTP
+ The SMTP client time limit for sending the SMTP
message content.
<b><a href="postconf.5.html#smtp_data_done_timeout">smtp_data_done_timeout</a> (600s)</b>
- The SMTP client time limit for sending the SMTP
+ The SMTP client time limit for sending the SMTP
".", and for receiving the server response.
<b><a href="postconf.5.html#smtp_quit_timeout">smtp_quit_timeout</a> (300s)</b>
- The SMTP client time limit for sending the QUIT
+ The SMTP client time limit for sending the QUIT
command, and for receiving the server response.
Available in Postfix version 2.1 and later:
lookups, or zero (no limit).
<b><a href="postconf.5.html#smtp_mx_session_limit">smtp_mx_session_limit</a> (2)</b>
- The maximal number of SMTP sessions per delivery
- request before giving up or delivering to a fall-
+ The maximal number of SMTP sessions per delivery
+ request before giving up or delivering to a fall-
back <a href="postconf.5.html#relayhost">relay host</a>, or zero (no limit).
<b><a href="postconf.5.html#smtp_rset_timeout">smtp_rset_timeout</a> (20s)</b>
- The SMTP client time limit for sending the RSET
+ The SMTP client time limit for sending the RSET
command, and for receiving the server response.
Available in Postfix version 2.2 and later:
<b><a href="postconf.5.html#smtp_connection_cache_destinations">smtp_connection_cache_destinations</a> (empty)</b>
- Permanently enable SMTP connection caching for the
+ Permanently enable SMTP connection caching for the
specified destinations.
<b><a href="postconf.5.html#smtp_connection_cache_on_demand">smtp_connection_cache_on_demand</a> (yes)</b>
- Temporarily enable SMTP connection caching while a
+ Temporarily enable SMTP connection caching while a
destination has a high volume of mail in the active
queue.
<b><a href="postconf.5.html#smtp_connection_cache_time_limit">smtp_connection_cache_time_limit</a> (2s)</b>
When SMTP connection caching is enabled, the amount
- of time that an unused SMTP client socket is kept
+ of time that an unused SMTP client socket is kept
open before it is closed.
+ Available in Postfix version 2.3 and later:
+
+ <b><a href="postconf.5.html#connection_cache_protocol_timeout">connection_cache_protocol_timeout</a> (5s)</b>
+ Time limit for connection cache connect, send or
+ receive operations.
+
<b>TROUBLE SHOOTING CONTROLS</b>
<b><a href="postconf.5.html#debug_peer_level">debug_peer_level</a> (2)</b>
The increment in verbose logging level when a
Disable DNS lookups in the Postfix SMTP and LMTP
clients.
- <b><a href="postconf.5.html#fallback_relay">fallback_relay</a> (empty)</b>
- Optional list of relay hosts for SMTP destinations
- that can't be found or that are unreachable.
-
<b><a href="postconf.5.html#inet_interfaces">inet_interfaces</a> (all)</b>
The network interface addresses that this mail sys-
tem receives mail on.
<b><a href="postconf.5.html#inet_protocols">inet_protocols</a> (ipv4)</b>
- The Internet protocols Postfix will attempt to use
+ The Internet protocols Postfix will attempt to use
when making or accepting connections.
<b><a href="postconf.5.html#ipc_timeout">ipc_timeout</a> (3600s)</b>
The time limit for sending or receiving information
over an internal communication channel.
+ <b><a href="postconf.5.html#lmtp_tcp_port">lmtp_tcp_port</a> (24)</b>
+ The default TCP port that the Postfix LMTP client
+ connects to.
+
<b><a href="postconf.5.html#max_idle">max_idle</a> (100s)</b>
The maximum amount of time that an idle Postfix
daemon process waits for the next service request
The hostname to send in the SMTP EHLO or HELO com-
mand.
+ <b>lmtp_lhlo_name ($<a href="postconf.5.html#myhostname">myhostname</a>)</b>
+ The hostname to send in the LMTP LHLO command.
+
<b><a href="postconf.5.html#smtp_host_lookup">smtp_host_lookup</a> (dns)</b>
What mechanisms when the SMTP client uses to look
up a host's IP address.
process name in syslog records, so that "smtpd"
becomes, for example, "postfix/smtpd".
+ Available with Postfix 2.2 and earlier:
+
+ <b><a href="postconf.5.html#fallback_relay">fallback_relay</a> (empty)</b>
+ Optional list of relay hosts for SMTP destinations
+ that can't be found or that are unreachable.
+
+ Available with Postfix 2.3 and later:
+
+ <b>smtp_fallback_relay ($<a href="postconf.5.html#fallback_relay">fallback_relay</a>)</b>
+ Optional list of relay hosts for SMTP destinations
+ that can't be found or that are unreachable.
+
<b>SEE ALSO</b>
<a href="qmgr.8.html">qmgr(8)</a>, queue manager
<a href="bounce.8.html">bounce(8)</a>, delivery status reports
# Non-production: needs thorough testing, or major changes are still
# needed before the code stabilizes.
-#CCARGS="$CCARGS -DNONPROD"
+CCARGS="$CCARGS -DNONPROD"
sed 's/ / /g' <<EOF
SYSTYPE = $SYSTYPE
(cmp -s junk $? || mv junk $?)
../mantools/srctoman $? >$@
-man8/lmtp.8: ../src/lmtp/lmtp.c
- ../mantools/fixman ../proto/postconf.proto $? >junk && \
- (cmp -s junk $? || mv junk $?)
- ../mantools/srctoman $? >$@
+man8/lmtp.8:
+ echo .so man8/smtp.8 >$@
man8/master.8: ../src/master/master.c
../mantools/fixman ../proto/postconf.proto $? >junk && \
discard(8), Postfix discard delivery agent
error(8), Postfix error delivery agent
flush(8), Postfix fast ETRN service
-lmtp(8), Postfix LMTP client
local(8), Postfix local delivery agent
master(8), Postfix master daemon
oqmgr(8), old Postfix queue manager
qmqpd(8), Postfix QMQP server
scache(8), Postfix connection cache manager
showq(8), list Postfix mail queue
-smtp(8), Postfix SMTP client
+smtp(8), lmtp(8), Postfix SMTP+LMTP client
smtpd(8), Postfix SMTP server
spawn(8), run non-Postfix server
tlsmgr(8), Postfix TLS cache and randomness manager
IBM T.J. Watson Research
P.O. Box 704
Yorktown Heights, NY 10598, USA
+
+SASL support originally by:
+Till Franke
+SuSE Rhein/Main AG
+65760 Eschborn, Germany
+
+LMTP support originally by:
+Philip A. Prindeville
+Mirapoint, Inc.
+USA.
+
+Amos Gouaux
+University of Texas at Dallas
+P.O. Box 830688, MC34
+Richardson, TX 75083, USA
queue IDs from standard input. For example, to delete all mail
with exactly one recipient \fBuser@example.com\fR:
.sp
-mailq | tail +2 | awk \'BEGIN { RS = "" }
+mailq | tail +2 | grep -v '^ *(' | awk \'BEGIN { RS = "" }
.ti +4
# $7=sender, $8=recipient1, $9=recipient2
.ti +4
(the lookup result is ignored). Continue long lines by starting the
next line with whitespace.
.PP
+Example:
+.PP
+.nf
+.na
+.ft C
+authorized_submit_users = !www, static:all
+.fi
+.ad
+.ft R
+.PP
This feature is available in Postfix 2.2 and later.
.SH authorized_verp_clients (default: $mynetworks)
What SMTP clients are allowed to specify the XVERP command.
config_directory override requires either root privileges, or it
requires that the directory is listed with the alternate_config_directories
parameter in the default main.cf file.
+.SH connection_cache_protocol_timeout (default: 5s)
+Time limit for connection cache connect, send or receive
+operations. The time limit is enforced in the client.
+.PP
+This feature is available in Postfix 2.3 and later.
.SH connection_cache_service (default: scache)
The name of the \fBscache\fR(8) connection cache service. This service
maintains a limited pool of cached sessions.
This feature was removed in Postfix version 2.1.
.SH fallback_relay (default: empty)
Optional list of relay hosts for SMTP destinations that can't be
-found or that are unreachable.
+found or that are unreachable. With Postfix 2.3 this parameter
+is renamed to smtp_fallback_relay.
.PP
By default, mail is returned to the sender when a destination is
-not found, and delivery is deferred if a destination is unreachable.
+not found, and delivery is deferred when a destination is unreachable.
.PP
The fallback relays must be SMTP destinations. Specify a domain,
host, host:port, [host]:port, [address] or [address]:port; the form
[host] turns off MX lookups. If you specify multiple SMTP
destinations, Postfix will try them in the specified order.
.PP
-Note: do not use the fallback_relay feature when relaying mail
+Note: before Postfix 2.2, do not use the fallback_relay feature
+when relaying mail
for a backup or primary MX domain. Mail would loop between the
Postfix MX host and the fallback_relay host when the final destination
is unavailable.
In transport maps, specify "relay:\fInexthop...\fR"
as the right-hand side for backup or primary MX domain entries.
.PP
-These are default settings in Postfix version 2.2 and later.
+Postfix version 2.2 and later will not use the fallback_relay feature
+for destinations that it is MX host for.
.SH fallback_transport (default: empty)
Optional message delivery transport that the \fBlocal\fR(8) delivery
agent should use for names that are not found in the \fBaliases\fR(5)
.SH line_length_limit (default: 2048)
Upon input, long lines are chopped up into pieces of at most
this length; upon delivery, long lines are reconstructed.
+.SH lmtp_bind_address (default: empty)
+The LMTP-specific version of the smtp_bind_address configuration
+parameter. See there for details.
+.PP
+This feature is available in Postfix 2.3 and later.
+.SH lmtp_bind_address6 (default: empty)
+The LMTP-specific version of the smtp_bind_address6 configuration
+parameter. See there for details.
+.PP
+This feature is available in Postfix 2.3 and later.
.SH lmtp_cache_connection (default: yes)
Keep Postfix LMTP client connections open for up to $max_idle
seconds. When the LMTP client receives a request for the same
.fi
.ad
.ft R
+.SH lmtp_connection_cache_destinations (default: empty)
+The LMTP-specific version of the smtp_connection_cache_destinations
+configuration parameter. See there for details.
+.PP
+This feature is available in Postfix 2.3 and later.
+.SH lmtp_connection_cache_on_demand (default: yes)
+The LMTP-specific version of the smtp_connection_cache_on_demand
+configuration parameter. See there for details.
+.PP
+This feature is available in Postfix 2.3 and later.
+.SH lmtp_connection_reuse_time_limit (default: 300s)
+The LMTP-specific version of the smtp_connection_reuse_time_limit
+configuration parameter. See there for details.
+.PP
+This feature is available in Postfix 2.3 and later.
.SH lmtp_data_done_timeout (default: 600s)
The LMTP client time limit for sending the LMTP ".", and for
receiving the server response. When no response is received within
.PP
Time units: s (seconds), m (minutes), h (hours), d (days), w (weeks).
The default time unit is s (seconds).
+.SH lmtp_defer_if_no_mx_address_found (default: no)
+The LMTP-specific version of the smtp_defer_if_no_mx_address_found
+configuration parameter. See there for details.
+.PP
+This feature is available in Postfix 2.3 and later.
.SH lmtp_destination_concurrency_limit (default: $default_destination_concurrency_limit)
The maximal number of parallel deliveries to the same destination
via the lmtp message delivery transport. This limit is enforced by
Setting this parameter to a value of 1 changes the meaning of
lmtp_destination_concurrency_limit from concurrency per domain into
concurrency per recipient.
+.SH lmtp_discard_lhlo_keyword_address_maps (default: empty)
+Lookup tables, indexed by the remote LMTP server address, with
+case insensitive lists of LHLO keywords (pipelining, starttls,
+auth, etc.) that the LMTP client will ignore in the LHLO response
+from a remote LMTP server. See lmtp_discard_lhlo_keywords for
+details.
+.PP
+This feature is available in Postfix 2.3 and later.
+.SH lmtp_discard_lhlo_keywords (default: $myhostname)
+A case insensitive list of LHLO keywords (pipelining, starttls,
+auth, etc.) that the LMTP client will ignore in the LHLO response
+from a remote LMTP server.
+.PP
+This feature is available in Postfix 2.3 and later.
+.PP
+Notes:
+.IP \(bu
+Specify the \fBsilent-discard\fR pseudo keyword to prevent
+this action from being logged.
+.IP \(bu
+Use the lmtp_discard_lhlo_keyword_address_maps feature to
+discard LHLO keywords selectively.
+.SH lmtp_enforce_tls (default: no)
+The LMTP-specific version of the smtp_enforce_tls configuration
+parameter. See there for details.
+.PP
+This feature is available in Postfix 2.3 and later.
+.SH lmtp_generic_maps (default: empty)
+The LMTP-specific version of the smtp_generic_maps configuration
+parameter. See there for details.
+.PP
+This feature is available in Postfix 2.3 and later.
+.SH lmtp_host_lookup (default: dns)
+The LMTP-specific version of the smtp_host_lookup configuration
+parameter. See there for details.
+.PP
+This feature is available in Postfix 2.3 and later.
+.SH lmtp_lhlo_name (default: $myhostname)
+The hostname to send in the LMTP LHLO command.
+.PP
+The default value is the machine hostname. Specify a hostname or
+[ip.add.re.ss].
+.PP
+This information can be specified in the main.cf file for all LMTP
+clients, or it can be specified in the master.cf file for a specific
+client, for example:
+.PP
+.nf
+.na
+.ft C
+ /etc/postfix/master.cf:
+ mylmtp ... lmtp -o lmtp_lhlo_name=foo.bar.com
+.fi
+.ad
+.ft R
+.PP
+This feature is available in Postfix 2.3 and later.
.SH lmtp_lhlo_timeout (default: 300s)
-The LMTP client time limit for receiving the LMTP greeting
-banner. When the server drops the connection without sending a
-greeting banner, or when it sends no greeting banner within the
-deadline, the LMTP client tries the next address on the mail
-exchanger list.
+The LMTP client time limit for sending the LHLO command, and
+for receiving the initial server response.
.PP
-Time units: s (seconds), m (minutes), h (hours), d (days), w (weeks).
-The default time unit is s (seconds).
+Time units: s (seconds), m (minutes), h (hours), d (days), w
+(weeks). The default time unit is s (seconds).
+.SH lmtp_line_length_limit (default: 990)
+The LMTP-specific version of the smtp_line_length_limit
+configuration parameter. See there for details.
+.PP
+This feature is available in Postfix 2.3 and later.
.SH lmtp_mail_timeout (default: 300s)
The LMTP client time limit for sending the MAIL FROM command, and
for receiving the server response.
.PP
Time units: s (seconds), m (minutes), h (hours), d (days), w (weeks).
The default time unit is s (seconds).
+.SH lmtp_mx_address_limit (default: 5)
+The LMTP-specific version of the smtp_mx_address_limit configuration
+parameter. See there for details.
+.PP
+This feature is available in Postfix 2.3 and later.
+.SH lmtp_mx_session_limit (default: 2)
+The LMTP-specific version of the smtp_mx_session_limit configuration
+parameter. See there for details.
+.PP
+This feature is available in Postfix 2.3 and later.
+.SH lmtp_pix_workaround_delay_time (default: 10s)
+The LMTP-specific version of the smtp_pix_workaround_delay_time
+configuration parameter. See there for details.
+.PP
+This feature is available in Postfix 2.3 and later.
+.SH lmtp_pix_workaround_threshold_time (default: 500s)
+The LMTP-specific version of the smtp_pix_workaround_threshold_time
+configuration parameter. See there for details.
+.PP
+This feature is available in Postfix 2.3 and later.
.SH lmtp_quit_timeout (default: 300s)
The LMTP client time limit for sending the QUIT command, and for
receiving the server response.
.PP
Time units: s (seconds), m (minutes), h (hours), d (days), w (weeks).
The default time unit is s (seconds).
+.SH lmtp_quote_rfc821_envelope (default: yes)
+The LMTP-specific version of the smtp_quote_rfc821_envelope
+configuration parameter. See there for details.
+.PP
+This feature is available in Postfix 2.3 and later.
+.SH lmtp_randomize_addresses (default: yes)
+The LMTP-specific version of the smtp_randomize_addresses
+configuration parameter. See there for details.
+.PP
+This feature is available in Postfix 2.3 and later.
.SH lmtp_rcpt_timeout (default: 300s)
The LMTP client time limit for sending the RCPT TO command, and
for receiving the server response.
The default time unit is s (seconds).
.SH lmtp_sasl_auth_enable (default: no)
Enable SASL authentication in the Postfix LMTP client.
+.SH lmtp_sasl_mechanism_filter (default: empty)
+The LMTP-specific version of the smtp_sasl_mechanism_filter
+configuration parameter. See there for details.
+.PP
+This feature is available in Postfix 2.3 and later.
.SH lmtp_sasl_password_maps (default: empty)
Optional LMTP client lookup tables with one username:password entry
per host or domain. If a remote host or domain has no username:password
.fi
.ad
.ft R
+.SH lmtp_sasl_tls_security_options (default: $var_lmtp_sasl_opts)
+The LMTP-specific version of the smtp_sasl_tls_security_options
+configuration parameter. See there for details.
+.PP
+This feature is available in Postfix 2.3 and later.
.SH lmtp_send_xforward_command (default: no)
Send an XFORWARD command to the LMTP server when the LMTP LHLO
server response announces XFORWARD support. This allows an \fBlmtp\fR(8)
your content filter supports this command.
.PP
This feature is available in Postfix 2.1 and later.
+.SH lmtp_sender_dependent_authentication (default: no)
+The LMTP-specific version of the smtp_sender_dependent_authentication
+configuration parameter. See there for details.
+.PP
+This feature is available in Postfix 2.3 and later.
+.SH lmtp_skip_5xx_greeting (default: yes)
+The LMTP-specific version of the smtp_skip_5xx_greeting
+configuration parameter. See there for details.
+.PP
+This feature is available in Postfix 2.3 and later.
.SH lmtp_skip_quit_response (default: no)
Wait for the response to the LMTP QUIT command.
+.SH lmtp_starttls_timeout (default: 300s)
+The LMTP-specific version of the smtp_starttls_timeout configuration
+parameter. See there for details.
+.PP
+This feature is available in Postfix 2.3 and later.
.SH lmtp_tcp_port (default: 24)
The default TCP port that the Postfix LMTP client connects to.
+.SH lmtp_tls_enforce_peername (default: yes)
+The LMTP-specific version of the smtp_tls_enforce_peername
+configuration parameter. See there for details.
+.PP
+This feature is available in Postfix 2.3 and later.
+.SH lmtp_tls_note_starttls_offer (default: no)
+The LMTP-specific version of the smtp_tls_note_starttls_offer
+configuration parameter. See there for details.
+.PP
+This feature is available in Postfix 2.3 and later.
+.SH lmtp_tls_per_site (default: empty)
+The LMTP-specific version of the smtp_tls_per_site configuration
+parameter. See there for details.
+.PP
+This feature is available in Postfix 2.3 and later.
+.SH lmtp_tls_scert_verifydepth (default: 5)
+The LMTP-specific version of the smtp_tls_scert_verifydepth
+configuration parameter. See there for details.
+.PP
+This feature is available in Postfix 2.3 and later.
+.SH lmtp_use_tls (default: no)
+The LMTP-specific version of the smtp_use_tls configuration
+parameter. See there for details.
+.PP
+This feature is available in Postfix 2.3 and later.
.SH lmtp_xforward_timeout (default: 300s)
The LMTP client time limit for sending the XFORWARD command, and
for receiving the server response.
.SH sender_dependent_relayhost_maps (default: empty)
A sender-dependent override for the global relayhost parameter
setting. The tables are searched by the sender address and by the
-sender @domain. This information is overruled with relay_transport,
+@domain. This information is overruled with relay_transport,
default_transport and with the \fBtransport\fR(5) table.
.PP
This feature is available in Postfix 2.3 and later.
[] or non-default TCP port), as specified in main.cf or in the
transport map,
.IP \(bu
+if mail is sent via a UNIX-domain socket: a pathname (without
+the unix: prefix),
+.IP \(bu
a /file/name with domain names and/or relay host names as
defined above,
.IP \(bu
will only connect to servers that support RFC 2487 _and_ that
provide valid server certificates. Typical use is for clients that
send all their email to a dedicated mailhub.
+.SH smtp_fallback_relay (default: $fallback_relay)
+Optional list of relay hosts for SMTP destinations that can't be
+found or that are unreachable. With Postfix 2.2 and earlier this
+parameter is called fallback_relay.
+.PP
+By default, mail is returned to the sender when a destination is
+not found, and delivery is deferred when a destination is unreachable.
+.PP
+The fallback relays must be SMTP destinations. Specify a domain,
+host, host:port, [host]:port, [address] or [address]:port; the form
+[host] turns off MX lookups. If you specify multiple SMTP
+destinations, Postfix will try them in the specified order.
+.PP
+To prevent mailer loops between MX hosts and fall-back hosts,
+Postfix version 2.3 and later will not use the smtp_fallback_relay
+feature for destinations that it is MX host for.
.SH smtp_generic_maps (default: empty)
Optional lookup tables that perform address rewriting in the
SMTP client, typically to transform a locally valid address into
-.TH LMTP 8
-.ad
-.fi
-.SH NAME
-lmtp
-\-
-Postfix local delivery via LMTP
-.SH "SYNOPSIS"
-.na
-.nf
-\fBlmtp\fR [generic Postfix daemon options]
-.SH DESCRIPTION
-.ad
-.fi
-The LMTP client processes message delivery requests from
-the queue manager. Each request specifies a queue file, a sender
-address, a domain or host to deliver to, and recipient information.
-This program expects to be run from the \fBmaster\fR(8) process
-manager.
-
-The LMTP client updates the queue file and marks recipients
-as finished, or it informs the queue manager that delivery should
-be tried again at a later time. Delivery status reports are sent
-to the \fBbounce\fR(8), \fBdefer\fR(8) or \fBtrace\fR(8) daemon as
-appropriate.
-
-The LMTP client connects to the destination specified in the message
-delivery request. The destination, usually specified in the Postfix
-\fBtransport\fR(5) table, has the form:
-.IP \fBunix\fR:\fIpathname\fR
-Connect to the local UNIX-domain server that is bound to the specified
-\fIpathname\fR. If the process runs chrooted, an absolute pathname
-is interpreted relative to the changed root directory.
-.IP "\fBinet\fR:\fIhost\fR, \fBinet\fB:\fIhost\fR:\fIport\fR (symbolic host)"
-.IP "\fBinet\fR:[\fIaddr\fR], \fBinet\fR:[\fIaddr\fR]:\fIport\fR (numeric host)"
-Connect to the specified IPV4 TCP port on the specified local or
-remote host. If no port is specified, connect to the port defined as
-\fBlmtp\fR in \fBservices\fR(4).
-If no such service is found, the \fBlmtp_tcp_port\fR configuration
-parameter (default value of 24) will be used.
-
-The LMTP client does not perform MX (mail exchanger) lookups since
-those are defined only for mail delivery via SMTP.
-.PP
-If neither \fBunix:\fR nor \fBinet:\fR are specified, \fBinet:\fR
-is assumed.
-.SH "SECURITY"
-.na
-.nf
-.ad
-.fi
-The LMTP client is moderately security-sensitive. It talks to LMTP
-servers and to DNS servers on the network. The LMTP client can be
-run chrooted at fixed low privilege.
-.SH "STANDARDS"
-.na
-.nf
-RFC 821 (SMTP protocol)
-RFC 1651 (SMTP service extensions)
-RFC 1652 (8bit-MIME transport)
-RFC 1870 (Message Size Declaration)
-RFC 2033 (LMTP protocol)
-RFC 2034 (Enhanced Status codes)
-RFC 2554 (AUTH command)
-RFC 2821 (SMTP protocol)
-RFC 2920 (SMTP Pipelining)
-RFC 3463 (Enhanced Status codes)
-.SH DIAGNOSTICS
-.ad
-.fi
-Problems and transactions are logged to \fBsyslogd\fR(8).
-Corrupted message files are marked so that the queue manager can
-move them to the \fBcorrupt\fR queue for further inspection.
-
-Depending on the setting of the \fBnotify_classes\fR parameter,
-the postmaster is notified of bounces, protocol problems, and of
-other trouble.
-.SH "CONFIGURATION PARAMETERS"
-.na
-.nf
-.ad
-.fi
-Changes to \fBmain.cf\fR are picked up automatically, as \fBlmtp\fR(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
-\fBpostconf\fR(5) for more details including examples.
-.SH "COMPATIBILITY CONTROLS"
-.na
-.nf
-.ad
-.fi
-.IP "\fBlmtp_skip_quit_response (no)\fR"
-Wait for the response to the LMTP QUIT command.
-.SH "TROUBLE SHOOTING CONTROLS"
-.na
-.nf
-.ad
-.fi
-.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.
-.SH "EXTERNAL CONTENT INSPECTION CONTROLS"
-.na
-.nf
-.ad
-.fi
-Available in Postfix version 2.1 and later:
-.IP "\fBlmtp_send_xforward_command (no)\fR"
-Send an XFORWARD command to the LMTP server when the LMTP LHLO
-server response announces XFORWARD support.
-.SH "SASL AUTHENTICATION CONTROLS"
-.na
-.nf
-.ad
-.fi
-.IP "\fBlmtp_sasl_auth_enable (no)\fR"
-Enable SASL authentication in the Postfix LMTP client.
-.IP "\fBlmtp_sasl_password_maps (empty)\fR"
-Optional LMTP client lookup tables with one username:password entry
-per host or domain.
-.IP "\fBlmtp_sasl_security_options (noplaintext, noanonymous)\fR"
-What authentication mechanisms the Postfix LMTP client is allowed
-to use.
-.SH "RESOURCE AND RATE CONTROLS"
-.na
-.nf
-.ad
-.fi
-In the text below, \fItransport\fR is the name
-of the service as specified in the \fBmaster.cf\fR file.
-.IP "\fBlmtp_cache_connection (yes)\fR"
-Keep Postfix LMTP client connections open for up to $max_idle
-seconds.
-.IP "\fItransport_\fBdestination_concurrency_limit ($default_destination_concurrency_limit)\fR"
-Limit the number of parallel deliveries to the same destination
-via this mail delivery transport.
-.IP "\fItransport_\fBdestination_recipient_limit ($default_destination_recipient_limit)\fR"
-Limit the number of recipients per message delivery via this mail
-delivery transport.
-
-This parameter becomes significant if the LMTP client is used
-for local delivery. Some LMTP servers can optimize delivery of
-the same message to multiple recipients. The default limit for
-local mail delivery is 1.
-
-Setting this parameter to 0 will lead to an unbounded number of
-recipients per delivery. However, this could be risky since it may
-make the machine vulnerable to running out of resources if messages
-are encountered with an inordinate number of recipients. Exercise
-care when setting this parameter.
-.IP "\fBlmtp_connect_timeout (0s)\fR"
-The LMTP client time limit for completing a TCP connection, or
-zero (use the operating system built-in time limit).
-.IP "\fBlmtp_lhlo_timeout (300s)\fR"
-The LMTP client time limit for receiving the LMTP greeting
-banner.
-.IP "\fBlmtp_xforward_timeout (300s)\fR"
-The LMTP client time limit for sending the XFORWARD command, and
-for receiving the server response.
-.IP "\fBlmtp_mail_timeout (300s)\fR"
-The LMTP client time limit for sending the MAIL FROM command, and
-for receiving the server response.
-.IP "\fBlmtp_rcpt_timeout (300s)\fR"
-The LMTP client time limit for sending the RCPT TO command, and
-for receiving the server response.
-.IP "\fBlmtp_data_init_timeout (120s)\fR"
-The LMTP client time limit for sending the LMTP DATA command, and
-for receiving the server response.
-.IP "\fBlmtp_data_xfer_timeout (180s)\fR"
-The LMTP client time limit for sending the LMTP message content.
-.IP "\fBlmtp_data_done_timeout (600s)\fR"
-The LMTP client time limit for sending the LMTP ".", and for
-receiving the server response.
-.IP "\fBlmtp_rset_timeout (20s)\fR"
-The LMTP client time limit for sending the RSET command, and
-for receiving the server response.
-.IP "\fBlmtp_quit_timeout (300s)\fR"
-The LMTP client time limit for sending the QUIT command, and for
-receiving the server response.
-.SH "MISCELLANEOUS CONTROLS"
-.na
-.nf
-.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 "\fBdelay_logging_resolution_limit (2)\fR"
-The maximal number of digits after the decimal point when logging
-sub-second delay values.
-.IP "\fBdisable_dns_lookups (no)\fR"
-Disable DNS lookups in the Postfix SMTP and LMTP clients.
-.IP "\fBipc_timeout (3600s)\fR"
-The time limit for sending or receiving information over an internal
-communication channel.
-.IP "\fBlmtp_tcp_port (24)\fR"
-The default TCP port that the Postfix LMTP client connects to.
-.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 "\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 "\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".
-.SH "SEE ALSO"
-.na
-.nf
-bounce(8), delivery status reports
-qmgr(8), queue manager
-postconf(5), configuration parameters
-master(5), generic daemon options
-services(4), Internet services and aliases
-master(8), process manager
-syslogd(8), system logging
-.SH "README FILES"
-.na
-.nf
-.ad
-.fi
-Use "\fBpostconf readme_directory\fR" or
-"\fBpostconf html_directory\fR" to locate this information.
-.na
-.nf
-LMTP_README, Postfix LMTP client howto
-VIRTUAL_README, virtual delivery agent howto
-.SH "LICENSE"
-.na
-.nf
-.ad
-.fi
-The Secure Mailer license must be distributed with this software.
-.SH "AUTHOR(S)"
-.na
-.nf
-Wietse Venema
-IBM T.J. Watson Research
-P.O. Box 704
-Yorktown Heights, NY 10598, USA
-
-Modifications for LMTP by:
-Philip A. Prindeville
-Mirapoint, Inc.
-USA.
-
-SASL support originally by:
-Till Franke
-SuSE Rhein/Main AG
-65760 Eschborn, Germany
-
-Additional work on LMTP by:
-Amos Gouaux
-University of Texas at Dallas
-P.O. Box 830688, MC34
-Richardson, TX 75083, USA
+.so man8/smtp.8
.SH NAME
smtp
\-
-Postfix SMTP client
+Postfix SMTP+LMTP client
.SH "SYNOPSIS"
.na
.nf
.SH DESCRIPTION
.ad
.fi
-The Postfix SMTP client processes message delivery requests from
+The Postfix SMTP+LMTP client implements the SMTP and LMTP mail
+delivery protocols. It processes message delivery requests from
the queue manager. Each request specifies a queue file, a sender
address, a domain or host to deliver to, and recipient information.
This program expects to be run from the \fBmaster\fR(8) process
manager.
-The SMTP client updates the queue file and marks recipients
+The SMTP+LMTP client updates the queue file and marks recipients
as finished, or it informs the queue manager that delivery should
be tried again at a later time. Delivery status reports are sent
to the \fBbounce\fR(8), \fBdefer\fR(8) or \fBtrace\fR(8) daemon as
appropriate.
-The SMTP client looks up a list of mail exchanger addresses for
+The SMTP+LMTP client looks up a list of mail exchanger addresses for
the destination host, sorts the list by preference, and connects
to each listed address until it finds a server that responds.
When a server is not reachable, or when mail delivery fails due
-to a recoverable error condition, the SMTP client will try to
+to a recoverable error condition, the SMTP+LMTP client will try to
deliver the mail to an alternate host.
After a successful mail transaction, a connection may be saved
to the \fBscache\fR(8) connection cache server, so that it
-may be used by any SMTP client for a subsequent transaction.
+may be used by any SMTP+LMTP client for a subsequent transaction.
By default, connection caching is enabled temporarily for
destinations that have a high volume of mail in the active
queue. Session caching can be enabled permanently for
specific destinations.
+.SH "SMTP DESTINATION SYNTAX"
+.na
+.nf
+.ad
+.fi
+SMTP destinations have the following form:
+.IP "\fIdomainname\fR, \fIdomainname\fR:\fIport\fR"
+Look up the mail exchangers for the specified domain.
+.IP "[\fIhostname\fR], [\fIhostname\fR]:\fIport\fR"
+Look up the address of the specified host.
+.IP "[\fIaddress\fR], [\fIaddress\fR]:\fIport\fR"
+Connect to the host at the specified address. An IPv6
+address must be formatted as [\fBipv6\fR:\fIaddress\fR].
+.PP
+In all the above cases, when no port is specified, look up
+the port defined as \fBsmtp\fR in \fBservices\fR(4).
+.SH "LMTP DESTINATION SYNTAX"
+.na
+.nf
+.ad
+.fi
+LMTP destinations have the following form:
+.IP \fBunix\fR:\fIpathname\fR
+Connect to the local UNIX-domain server that is bound to the specified
+\fIpathname\fR. If the process runs chrooted, an absolute pathname
+is interpreted relative to the Postfix queue directory.
+.IP "\fBinet\fR:\fIhostname\fR, \fBinet\fB:\fIhostname\fR:\fIport\fR"
+.IP "\fBinet\fR:[\fIaddress\fR], \fBinet\fR:[\fIaddress\fR]:\fIport\fR"
+Connect to the specified TCP port on the specified local or
+remote host. If no port is specified, connect to the port defined as
+\fBlmtp\fR in \fBservices\fR(4).
+If no such service is found, the \fBlmtp_tcp_port\fR configuration
+parameter (default value of 24) will be used.
+.PP
.SH "SECURITY"
.na
.nf
.ad
.fi
-The SMTP client is moderately security-sensitive. It talks to SMTP
-servers and to DNS servers on the network. The SMTP client can be
-run chrooted at fixed low privilege.
+The SMTP+LMTP client is moderately security-sensitive. It
+talks to SMTP or LMTP servers and to DNS servers on the
+network. The SMTP+LMTP client can be run chrooted at fixed
+low privilege.
.SH "STANDARDS"
.na
.nf
RFC 1651 (SMTP service extensions)
RFC 1652 (8bit-MIME transport)
RFC 1870 (Message Size Declaration)
-RFC 2045 (MIME: Format of Internet Message Bodies)
+RFC 2033 (LMTP protocol)
RFC 2034 (Enhanced Status Codes)
+RFC 2045 (MIME: Format of Internet Message Bodies)
RFC 2046 (MIME: Media Types)
RFC 2554 (AUTH command)
RFC 2821 (SMTP protocol)
.SH BUGS
.ad
.fi
-SMTP connection caching does not work with TLS. The necessary
+SMTP and LMTP connection caching does not work with TLS. The necessary
support for TLS object passivation and re-activation does not
exist without closing the session, which defeats the purpose.
-SMTP connection caching assumes that SASL credentials are valid for
-all destinations that map onto the same IP address and TCP port.
+SMTP and LMTP connection caching assumes that SASL credentials
+are valid for all destinations that map onto the same IP
+address and TCP port.
.SH "CONFIGURATION PARAMETERS"
.na
.nf
.ad
.fi
+Most smtp_\fIxxx\fR configuration parameters have an
+lmtp_\fIxxx\fR "ghost" parameter for the equivalent LMTP
+feature. This document describes only those LMTP-related
+parameters that aren't simply "ghost" parameters.
+
Changes to \fBmain.cf\fR are picked up automatically, as \fBsmtp\fR(8)
processes run for only a limited amount of time. Use the command
"\fBpostfix reload\fR" to speed up a change.
Optional lookup tables that perform address rewriting in the
SMTP client, typically to transform a locally valid address into
a globally valid address when sending mail across the Internet.
+.PP
+Available in Postfix version 2.3 and later:
+.IP "\fBlmtp_discard_lhlo_keyword_address_maps (empty)\fR"
+Lookup tables, indexed by the remote LMTP server address, with
+case insensitive lists of LHLO keywords (pipelining, starttls,
+auth, etc.) that the LMTP client will ignore in the LHLO response
+from a remote LMTP server.
+.IP "\fBlmtp_discard_lhlo_keywords ($myhostname)\fR"
+A case insensitive list of LHLO keywords (pipelining, starttls,
+auth, etc.) that the LMTP client will ignore in the LHLO response
+from a remote LMTP server.
.SH "MIME PROCESSING CONTROLS"
.na
.nf
.IP "\fBsmtp_helo_timeout (300s)\fR"
The SMTP client time limit for sending the HELO or EHLO command,
and for receiving the initial server response.
+.IP "\fBlmtp_lhlo_timeout (300s)\fR"
+The LMTP client time limit for sending the LHLO command, and
+for receiving the initial server response.
.IP "\fBsmtp_xforward_timeout (300s)\fR"
The SMTP client time limit for sending the XFORWARD command, and
for receiving the server response.
.IP "\fBsmtp_connection_cache_time_limit (2s)\fR"
When SMTP connection caching is enabled, the amount of time that
an unused SMTP client socket is kept open before it is closed.
+.PP
+Available in Postfix version 2.3 and later:
+.IP "\fBconnection_cache_protocol_timeout (5s)\fR"
+Time limit for connection cache connect, send or receive
+operations.
.SH "TROUBLE SHOOTING CONTROLS"
.na
.nf
sub-second delay values.
.IP "\fBdisable_dns_lookups (no)\fR"
Disable DNS lookups in the Postfix SMTP and LMTP clients.
-.IP "\fBfallback_relay (empty)\fR"
-Optional list of relay hosts for SMTP destinations that can't be
-found or that are unreachable.
.IP "\fBinet_interfaces (all)\fR"
The network interface addresses that this mail system receives
mail on.
.IP "\fBipc_timeout (3600s)\fR"
The time limit for sending or receiving information over an internal
communication channel.
+.IP "\fBlmtp_tcp_port (24)\fR"
+The default TCP port that the Postfix LMTP client connects to.
.IP "\fBmax_idle (100s)\fR"
The maximum amount of time that an idle Postfix daemon process
waits for the next service request before exiting.
bind to when making an IPv6 connection.
.IP "\fBsmtp_helo_name ($myhostname)\fR"
The hostname to send in the SMTP EHLO or HELO command.
+.IP "\fBlmtp_lhlo_name ($myhostname)\fR"
+The hostname to send in the LMTP LHLO command.
.IP "\fBsmtp_host_lookup (dns)\fR"
What mechanisms when the SMTP client uses to look up a host's IP
address.
.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".
+.PP
+Available with Postfix 2.2 and earlier:
+.IP "\fBfallback_relay (empty)\fR"
+Optional list of relay hosts for SMTP destinations that can't be
+found or that are unreachable.
+.PP
+Available with Postfix 2.3 and later:
+.IP "\fBsmtp_fallback_relay ($fallback_relay)\fR"
+Optional list of relay hosts for SMTP destinations that can't be
+found or that are unreachable.
.SH "SEE ALSO"
.na
.nf
s;\bconnection_cache_service\b;<a href="postconf.5.html#connection_cache_service">$&</a>;g;
s;\bconnection_cache_status_update_time\b;<a href="postconf.5.html#connection_cache_status_update_time">$&</a>;g;
+ s;\bconnection_cache_protocol_timeout\b;<a href="postconf.5.html#connection_cache_protocol_timeout">$&</a>;g;
s;\bconnection_cache_ttl_limit\b;<a href="postconf.5.html#connection_cache_ttl_limit">$&</a>;g;
s;\bshow_user_unknown_table_name\b;<a href="postconf.5.html#show_user_unknown_table_name">$&</a>;g;
export_environment = TZ PATH=/bin:/usr/bin
</pre>
+%PARAM smtp_fallback_relay $fallback_relay
+
+<p>
+Optional list of relay hosts for SMTP destinations that can't be
+found or that are unreachable. With Postfix 2.2 and earlier this
+parameter is called fallback_relay. </p>
+
+<p>
+By default, mail is returned to the sender when a destination is
+not found, and delivery is deferred when a destination is unreachable.
+</p>
+
+<p> The fallback relays must be SMTP destinations. Specify a domain,
+host, host:port, [host]:port, [address] or [address]:port; the form
+[host] turns off MX lookups. If you specify multiple SMTP
+destinations, Postfix will try them in the specified order. </p>
+
+<p> To prevent mailer loops between MX hosts and fall-back hosts,
+Postfix version 2.3 and later will not use the smtp_fallback_relay
+feature for destinations that it is MX host for. </p>
+
%PARAM fallback_relay
<p>
Optional list of relay hosts for SMTP destinations that can't be
-found or that are unreachable. </p>
+found or that are unreachable. With Postfix 2.3 this parameter
+is renamed to smtp_fallback_relay. </p>
<p>
By default, mail is returned to the sender when a destination is
-not found, and delivery is deferred if a destination is unreachable.
+not found, and delivery is deferred when a destination is unreachable.
</p>
<p> The fallback relays must be SMTP destinations. Specify a domain,
[host] turns off MX lookups. If you specify multiple SMTP
destinations, Postfix will try them in the specified order. </p>
-<p> Note: do not use the fallback_relay feature when relaying mail
+<p> Note: before Postfix 2.2, do not use the fallback_relay feature
+when relaying mail
for a backup or primary MX domain. Mail would loop between the
Postfix MX host and the fallback_relay host when the final destination
is unavailable. </p>
</ul>
-<p> These are default settings in Postfix version 2.2 and later.
+<p> Postfix version 2.2 and later will not use the fallback_relay feature
+for destinations that it is MX host for.
</p>
%PARAM fast_flush_domains $relay_domains
[] or non-default TCP port), as specified in main.cf or in the
transport map,
+<li> if mail is sent via a UNIX-domain socket: a pathname (without
+the unix: prefix),
+
<li> a /file/name with domain names and/or relay host names as
defined above,
(the lookup result is ignored). Continue long lines by starting the
next line with whitespace. </p>
+<p>
+Example:
+</p>
+
+<pre>
+authorized_submit_users = !www, static:all
+</pre>
+
<p>
This feature is available in Postfix 2.2 and later.
</p>
<p> A sender-dependent override for the global relayhost parameter
setting. The tables are searched by the sender address and by the
-sender @domain. This information is overruled with relay_transport,
+@domain. This information is overruled with relay_transport,
default_transport and with the transport(5) table. </p>
<p>
This feature is available in Postfix 2.3 and later.
</p>
+%PARAM lmtp_lhlo_name $myhostname
+
+<p>
+The hostname to send in the LMTP LHLO command.
+</p>
+
+<p>
+The default value is the machine hostname. Specify a hostname or
+[ip.add.re.ss].
+</p>
+
+<p>
+This information can be specified in the main.cf file for all LMTP
+clients, or it can be specified in the master.cf file for a specific
+client, for example:
+</p>
+
+<pre>
+ /etc/postfix/master.cf:
+ mylmtp ... lmtp -o lmtp_lhlo_name=foo.bar.com
+</pre>
+
+<p>
+This feature is available in Postfix 2.3 and later.
+</p>
+
+%PARAM lmtp_discard_lhlo_keyword_address_maps
+
+<p> Lookup tables, indexed by the remote LMTP server address, with
+case insensitive lists of LHLO keywords (pipelining, starttls,
+auth, etc.) that the LMTP client will ignore in the LHLO response
+from a remote LMTP server. See lmtp_discard_lhlo_keywords for
+details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+%PARAM lmtp_discard_lhlo_keywords $myhostname
+
+<p> A case insensitive list of LHLO keywords (pipelining, starttls,
+auth, etc.) that the LMTP client will ignore in the LHLO response
+from a remote LMTP server. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+<p> Notes: </p>
+
+<ul>
+
+<li> <p> Specify the <b>silent-discard</b> pseudo keyword to prevent
+this action from being logged. </p>
+
+<li> <p> Use the lmtp_discard_lhlo_keyword_address_maps feature to
+discard LHLO keywords selectively. </p>
+
+</ul>
+
+%PARAM lmtp_lhlo_timeout 300s
+
+<p> The LMTP client time limit for sending the LHLO command, and
+for receiving the initial server response. </p>
+
+<p> Time units: s (seconds), m (minutes), h (hours), d (days), w
+(weeks). The default time unit is s (seconds). </p>
+
+%PARAM lmtp_sasl_tls_security_options $var_lmtp_sasl_opts
+
+<p> The LMTP-specific version of the smtp_sasl_tls_security_options
+configuration parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+%PARAM lmtp_sasl_mechanism_filter
+
+<p> The LMTP-specific version of the smtp_sasl_mechanism_filter
+configuration parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+%PARAM lmtp_bind_address
+
+<p> The LMTP-specific version of the smtp_bind_address configuration
+parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+%PARAM lmtp_bind_address6
+
+<p> The LMTP-specific version of the smtp_bind_address6 configuration
+parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+%PARAM lmtp_host_lookup dns
+
+<p> The LMTP-specific version of the smtp_host_lookup configuration
+parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+%PARAM lmtp_connection_cache_destinations
+
+<p> The LMTP-specific version of the smtp_connection_cache_destinations
+configuration parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+%PARAM lmtp_tls_per_site
+
+<p> The LMTP-specific version of the smtp_tls_per_site configuration
+parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+%PARAM lmtp_generic_maps
+
+<p> The LMTP-specific version of the smtp_generic_maps configuration
+parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+%PARAM lmtp_pix_workaround_threshold_time 500s
+
+<p> The LMTP-specific version of the smtp_pix_workaround_threshold_time
+configuration parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+%PARAM lmtp_pix_workaround_delay_time 10s
+
+<p> The LMTP-specific version of the smtp_pix_workaround_delay_time
+configuration parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+%PARAM lmtp_connection_reuse_time_limit 300s
+
+<p> The LMTP-specific version of the smtp_connection_reuse_time_limit
+configuration parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+%PARAM lmtp_starttls_timeout 300s
+
+<p> The LMTP-specific version of the smtp_starttls_timeout configuration
+parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+%PARAM lmtp_line_length_limit 990
+
+<p> The LMTP-specific version of the smtp_line_length_limit
+configuration parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+%PARAM lmtp_mx_address_limit 5
+
+<p> The LMTP-specific version of the smtp_mx_address_limit configuration
+parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+%PARAM lmtp_mx_session_limit 2
+
+<p> The LMTP-specific version of the smtp_mx_session_limit configuration
+parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+%PARAM lmtp_tls_scert_verifydepth 5
+
+<p> The LMTP-specific version of the smtp_tls_scert_verifydepth
+configuration parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+%PARAM lmtp_skip_5xx_greeting yes
+
+<p> The LMTP-specific version of the smtp_skip_5xx_greeting
+configuration parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+%PARAM lmtp_randomize_addresses yes
+
+<p> The LMTP-specific version of the smtp_randomize_addresses
+configuration parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+%PARAM lmtp_quote_rfc821_envelope yes
+
+<p> The LMTP-specific version of the smtp_quote_rfc821_envelope
+configuration parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+%PARAM lmtp_defer_if_no_mx_address_found no
+
+<p> The LMTP-specific version of the smtp_defer_if_no_mx_address_found
+configuration parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+%PARAM lmtp_connection_cache_on_demand yes
+
+<p> The LMTP-specific version of the smtp_connection_cache_on_demand
+configuration parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+%PARAM lmtp_use_tls no
+
+<p> The LMTP-specific version of the smtp_use_tls configuration
+parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+%PARAM lmtp_enforce_tls no
+
+<p> The LMTP-specific version of the smtp_enforce_tls configuration
+parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+%PARAM lmtp_tls_enforce_peername yes
+
+<p> The LMTP-specific version of the smtp_tls_enforce_peername
+configuration parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+%PARAM lmtp_tls_note_starttls_offer no
+
+<p> The LMTP-specific version of the smtp_tls_note_starttls_offer
+configuration parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+%PARAM lmtp_sender_dependent_authentication no
+
+<p> The LMTP-specific version of the smtp_sender_dependent_authentication
+configuration parameter. See there for details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+%PARAM connection_cache_protocol_timeout 5s
+
+<p> Time limit for connection cache connect, send or receive
+operations. The time limit is enforced in the client. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
scache.o: scache.c
scache.o: scache.h
scache_clnt.o: ../../include/attr.h
+scache_clnt.o: ../../include/auto_clnt.h
scache_clnt.o: ../../include/iostuff.h
scache_clnt.o: ../../include/msg.h
scache_clnt.o: ../../include/mymalloc.h
+scache_clnt.o: ../../include/stringops.h
scache_clnt.o: ../../include/sys_defs.h
scache_clnt.o: ../../include/vbuf.h
scache_clnt.o: ../../include/vstream.h
scache_clnt.o: ../../include/vstring.h
-scache_clnt.o: clnt_stream.h
scache_clnt.o: mail_params.h
scache_clnt.o: mail_proto.h
scache_clnt.o: scache.h
#include <deliver_pass.h>
#include <dsb_scan.h>
+#define DELIVER_PASS_DEFER 1
+#define DELIVER_PASS_UNKNOWN 2
+
/* deliver_pass_initial_reply - retrieve initial delivery process response */
static int deliver_pass_initial_reply(VSTREAM *stream)
ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &stat,
ATTR_TYPE_END) != 2) {
msg_warn("%s: malformed response", VSTREAM_PATH(stream));
- stat = -1;
+ return (DELIVER_PASS_UNKNOWN);
+ } else {
+ return (stat ? DELIVER_PASS_DEFER : 0);
}
- return (stat);
}
/* deliver_pass - deliver one per-site queue entry */
{
VSTREAM *stream;
DSN_BUF *dsb;
+ DSN dsn;
int status;
char *saved_service;
char *transport;
* XXX Can't pass back hop status info because the problem is with a
* different transport.
*/
- if ((status = deliver_pass_initial_reply(stream)) == 0
- && (status = deliver_pass_send_request(stream, request, nexthop,
- rcpt)) == 0)
- status = deliver_pass_final_reply(stream, dsb);
+ if (deliver_pass_initial_reply(stream) != 0
+ || deliver_pass_send_request(stream, request, nexthop, rcpt) != 0) {
+ DSN_SMTP(&dsn, "4.3.0",
+ "451 mail transport unavailable",
+ "mail transport unavailable");
+ status = defer_append(DEL_REQ_TRACE_FLAGS(request->flags),
+ request->queue_id, &request->msg_stats,
+ rcpt, "none", &dsn);
+ } else if ((status = deliver_pass_final_reply(stream, dsb))
+ == DELIVER_PASS_UNKNOWN) {
+ DSN_SMTP(&dsn, "4.3.0",
+ "451 unknown mail transport error",
+ "unknown mail transport error");
+ status = defer_append(DEL_REQ_TRACE_FLAGS(request->flags),
+ request->queue_id, &request->msg_stats,
+ rcpt, "none", &dsn);
+ }
/*
* Clean up.
/* char *nexthop;
/* char *encoding;
/* char *sender;
-/* MSG_STATS stats;
+/* MSG_STATS msg_stats;
/* RECIPIENT_LIST rcpt_list;
/* DSN *hop_status;
/* char *client_name;
ATTR_TYPE_STR, MAIL_ATTR_SENDER, address,
ATTR_TYPE_STR, MAIL_ATTR_DSN_ENVID, dsn_envid,
ATTR_TYPE_NUM, MAIL_ATTR_DSN_RET, &dsn_ret,
- ATTR_TYPE_FUNC, msg_stats_scan, (void *) &request->msg_stats,
+ ATTR_TYPE_FUNC, msg_stats_scan, (void *) &request->msg_stats,
ATTR_TYPE_STR, MAIL_ATTR_CLIENT_NAME, client_name,
ATTR_TYPE_STR, MAIL_ATTR_CLIENT_ADDR, client_addr,
ATTR_TYPE_STR, MAIL_ATTR_PROTO_NAME, client_proto,
vstring_str(orig_addr),
vstring_str(address));
}
+ if (request->rcpt_list.len <= 0) {
+ msg_warn("%s: no recipients in delivery request for destination %s",
+ request->queue_id, request->nexthop);
+ return (-1);
+ }
/*
* Open the queue file and set a shared lock, in order to prevent
#define DEF_SND_RELAY_MAPS ""
extern char *var_snd_relay_maps;
-#define VAR_FALLBACK_RELAY "fallback_relay"
+#define VAR_SMTP_FALLBACK "smtp_fallback_relay"
+#define DEF_SMTP_FALLBACK "$fallback_relay"
+#define VAR_LMTP_FALLBACK "smtp_fallback_relay"
#define DEF_FALLBACK_RELAY ""
extern char *var_fallback_relay;
#define VAR_SMTP_HOST_LOOKUP "smtp_host_lookup"
#define DEF_SMTP_HOST_LOOKUP SMTP_HOST_LOOKUP_DNS
+#define VAR_LMTP_HOST_LOOKUP "lmtp_host_lookup"
+#define DEF_LMTP_HOST_LOOKUP SMTP_HOST_LOOKUP_DNS
extern int var_smtp_dns_lookup;
#define VAR_SMTP_MXADDR_LIMIT "smtp_mx_address_limit"
#define DEF_SMTP_MXADDR_LIMIT 5
+#define VAR_LMTP_MXADDR_LIMIT "lmtp_mx_address_limit"
+#define DEF_LMTP_MXADDR_LIMIT 5
extern int var_smtp_mxaddr_limit;
#define VAR_SMTP_MXSESS_LIMIT "smtp_mx_session_limit"
#define DEF_SMTP_MXSESS_LIMIT 2
+#define VAR_LMTP_MXSESS_LIMIT "lmtp_mx_session_limit"
+#define DEF_LMTP_MXSESS_LIMIT 2
extern int var_smtp_mxsess_limit;
/*
#define DEF_BESTMX_TRANSP ""
extern char *var_bestmx_transp;
-#define VAR_SMTP_CACHE_CONN "smtp_connection_cache_time_limit"
-#define DEF_SMTP_CACHE_CONN "2s"
+#define VAR_SMTP_CACHE_CONNT "smtp_connection_cache_time_limit"
+#define DEF_SMTP_CACHE_CONNT "2s"
+#define VAR_LMTP_CACHE_CONNT "smtp_connection_cache_time_limit"
+#define DEF_LMTP_CACHE_CONNT "2s"
extern int var_smtp_cache_conn;
#define VAR_SMTP_REUSE_TIME "smtp_connection_reuse_time_limit"
#define DEF_SMTP_REUSE_TIME "300s"
+#define VAR_LMTP_REUSE_TIME "lmtp_connection_reuse_time_limit"
+#define DEF_LMTP_REUSE_TIME "300s"
extern int var_smtp_reuse_time;
#define VAR_SMTP_CACHE_DEST "smtp_connection_cache_destinations"
#define DEF_SMTP_CACHE_DEST ""
+#define VAR_LMTP_CACHE_DEST "lmtp_connection_cache_destinations"
+#define DEF_LMTP_CACHE_DEST ""
extern char *var_smtp_cache_dest;
#define VAR_SMTP_CACHE_DEMAND "smtp_connection_cache_on_demand"
#ifndef DEF_SMTP_CACHE_DEMAND
#define DEF_SMTP_CACHE_DEMAND 1
#endif
+#define VAR_LMTP_CACHE_DEMAND "lmtp_connection_cache_on_demand"
+#ifndef DEF_LMTP_CACHE_DEMAND
+#define DEF_LMTP_CACHE_DEMAND 1
+#endif
extern bool var_smtp_cache_demand;
#define VAR_SMTP_CONN_TMOUT "smtp_connect_timeout"
#define VAR_SMTP_HELO_TMOUT "smtp_helo_timeout"
#define DEF_SMTP_HELO_TMOUT "300s"
+#define VAR_LMTP_HELO_TMOUT "lmtp_lhlo_timeout"
+#define DEF_LMTP_HELO_TMOUT "300s"
extern int var_smtp_helo_tmout;
#define VAR_SMTP_XFWD_TMOUT "smtp_xforward_timeout"
#define VAR_SMTP_STARTTLS_TMOUT "smtp_starttls_timeout"
#define DEF_SMTP_STARTTLS_TMOUT "300s"
+#define VAR_LMTP_STARTTLS_TMOUT "lmtp_starttls_timeout"
+#define DEF_LMTP_STARTTLS_TMOUT "300s"
extern int var_smtp_starttls_tmout;
#define VAR_SMTP_MAIL_TMOUT "smtp_mail_timeout"
#define VAR_SMTP_QUOTE_821_ENV "smtp_quote_rfc821_envelope"
#define DEF_SMTP_QUOTE_821_ENV 1
+#define VAR_LMTP_QUOTE_821_ENV "lmtp_quote_rfc821_envelope"
+#define DEF_LMTP_QUOTE_821_ENV 1
extern int var_smtp_quote_821_env;
#define VAR_SMTP_SKIP_5XX "smtp_skip_5xx_greeting"
#define DEF_SMTP_SKIP_5XX 1
+#define VAR_LMTP_SKIP_5XX "lmtp_skip_5xx_greeting"
+#define DEF_LMTP_SKIP_5XX 1
extern bool var_smtp_skip_5xx_greeting;
#define VAR_IGN_MX_LOOKUP_ERR "ignore_mx_lookup_error"
#define VAR_SMTP_BIND_ADDR "smtp_bind_address"
#define DEF_SMTP_BIND_ADDR ""
+#define VAR_LMTP_BIND_ADDR "lmtp_bind_address"
+#define DEF_LMTP_BIND_ADDR ""
extern char *var_smtp_bind_addr;
#define VAR_SMTP_BIND_ADDR6 "smtp_bind_address6"
#define DEF_SMTP_BIND_ADDR6 ""
+#define VAR_LMTP_BIND_ADDR6 "lmtp_bind_address6"
+#define DEF_LMTP_BIND_ADDR6 ""
extern char *var_smtp_bind_addr6;
#define VAR_SMTP_HELO_NAME "smtp_helo_name"
#define DEF_SMTP_HELO_NAME "$myhostname"
+#define VAR_LMTP_HELO_NAME "lmtp_lhlo_name"
+#define DEF_LMTP_HELO_NAME "$myhostname"
extern char *var_smtp_helo_name;
#define VAR_SMTP_RAND_ADDR "smtp_randomize_addresses"
#define DEF_SMTP_RAND_ADDR 1
+#define VAR_LMTP_RAND_ADDR "lmtp_randomize_addresses"
+#define DEF_LMTP_RAND_ADDR 1
extern bool var_smtp_rand_addr;
#define VAR_SMTP_LINE_LIMIT "smtp_line_length_limit"
#define DEF_SMTP_LINE_LIMIT 990
+#define VAR_LMTP_LINE_LIMIT "lmtp_line_length_limit"
+#define DEF_LMTP_LINE_LIMIT 990
extern int var_smtp_line_limit;
#define VAR_SMTP_PIX_THRESH "smtp_pix_workaround_threshold_time"
#define DEF_SMTP_PIX_THRESH "500s"
+#define VAR_LMTP_PIX_THRESH "lmtp_pix_workaround_threshold_time"
+#define DEF_LMTP_PIX_THRESH "500s"
extern int var_smtp_pix_thresh;
#define VAR_SMTP_PIX_DELAY "smtp_pix_workaround_delay_time"
#define DEF_SMTP_PIX_DELAY "10s"
+#define VAR_LMTP_PIX_DELAY "lmtp_pix_workaround_delay_time"
+#define DEF_LMTP_PIX_DELAY "10s"
extern int var_smtp_pix_delay;
#define VAR_SMTP_DEFER_MXADDR "smtp_defer_if_no_mx_address_found"
#define DEF_SMTP_DEFER_MXADDR 0
+#define VAR_LMTP_DEFER_MXADDR "lmtp_defer_if_no_mx_address_found"
+#define DEF_LMTP_DEFER_MXADDR 0
extern bool var_smtp_defer_mxaddr;
#define VAR_SMTP_SEND_XFORWARD "smtp_send_xforward_command"
#define VAR_SMTP_GENERIC_MAPS "smtp_generic_maps"
#define DEF_SMTP_GENERIC_MAPS ""
+#define VAR_LMTP_GENERIC_MAPS "lmtp_generic_maps"
+#define DEF_LMTP_GENERIC_MAPS ""
extern char *var_smtp_generic_maps;
/*
#define VAR_SMTP_TLS_PER_SITE "smtp_tls_per_site"
#define DEF_SMTP_TLS_PER_SITE ""
+#define VAR_LMTP_TLS_PER_SITE "lmtp_tls_per_site"
+#define DEF_LMTP_TLS_PER_SITE ""
extern char *var_smtp_tls_per_site;
#define VAR_SMTP_USE_TLS "smtp_use_tls"
#define DEF_SMTP_USE_TLS 0
+#define VAR_LMTP_USE_TLS "lmtp_use_tls"
+#define DEF_LMTP_USE_TLS 0
extern bool var_smtp_use_tls;
#define VAR_SMTP_ENFORCE_TLS "smtp_enforce_tls"
#define DEF_SMTP_ENFORCE_TLS 0
+#define VAR_LMTP_ENFORCE_TLS "lmtp_enforce_tls"
+#define DEF_LMTP_ENFORCE_TLS 0
extern bool var_smtp_enforce_tls;
#define VAR_SMTP_TLS_ENFORCE_PN "smtp_tls_enforce_peername"
#define DEF_SMTP_TLS_ENFORCE_PN 1
+#define VAR_LMTP_TLS_ENFORCE_PN "lmtp_tls_enforce_peername"
+#define DEF_LMTP_TLS_ENFORCE_PN 1
extern bool var_smtp_tls_enforce_peername;
#define VAR_SMTP_TLS_SCERT_VD "smtp_tls_scert_verifydepth"
#define DEF_SMTP_TLS_SCERT_VD 5
+#define VAR_LMTP_TLS_SCERT_VD "lmtp_tls_scert_verifydepth"
+#define DEF_LMTP_TLS_SCERT_VD 5
extern int var_smtp_tls_scert_vd;
#define VAR_SMTP_TLS_CERT_FILE "smtp_tls_cert_file"
#define VAR_SMTP_TLS_NOTEOFFER "smtp_tls_note_starttls_offer"
#define DEF_SMTP_TLS_NOTEOFFER 0
+#define VAR_LMTP_TLS_NOTEOFFER "lmtp_tls_note_starttls_offer"
+#define DEF_LMTP_TLS_NOTEOFFER 0
extern bool var_smtp_tls_note_starttls_offer;
#define VAR_SMTP_TLS_SCACHE_DB "smtp_tls_session_cache_database"
#define VAR_SMTP_SASL_MECHS "smtp_sasl_mechanism_filter"
#define DEF_SMTP_SASL_MECHS ""
+#define VAR_LMTP_SASL_MECHS "lmtp_sasl_mechanism_filter"
+#define DEF_LMTP_SASL_MECHS ""
extern char *var_smtp_sasl_mechs;
#define VAR_SMTP_SASL_TLS_OPTS "smtp_sasl_tls_security_options"
#define DEF_SMTP_SASL_TLS_OPTS "$var_smtp_sasl_opts"
+#define VAR_LMTP_SASL_TLS_OPTS "lmtp_sasl_tls_security_options"
+#define DEF_LMTP_SASL_TLS_OPTS "$var_lmtp_sasl_opts"
extern char *var_smtp_sasl_tls_opts;
/*
* when given more recipients than they are willing to handle.
*/
#define VAR_LMTP_TCP_PORT "lmtp_tcp_port"
-#define DEF_LMTP_TCP_PORT 24
-extern int var_lmtp_tcp_port;
+#define DEF_LMTP_TCP_PORT "24"
+extern char *var_lmtp_tcp_port;
#define VAR_LMTP_CACHE_CONN "lmtp_cache_connection"
#define DEF_LMTP_CACHE_CONN 1
/*
* Session cache service.
*/
-#define VAR_SCACHE_SERVICE "connection_cache_service"
+#define VAR_SCACHE_SERVICE "connection_cache_service_name"
#define DEF_SCACHE_SERVICE "scache"
extern char *var_scache_service;
+#define VAR_SCACHE_PROTO_TMOUT "connection_cache_protocol_timeout"
+#define DEF_SCACHE_PROTO_TMOUT "5s"
+extern int var_scache_proto_tmout;
+
#define VAR_SCACHE_TTL_LIM "connection_cache_ttl_limit"
#define DEF_SCACHE_TTL_LIM "2s"
extern int var_scache_ttl_lim;
#if 0
#include <anvil_clnt.h>
-#define VAR_ANVIL_SERVICE "client_connection_rate_service"
+#define VAR_ANVIL_SERVICE "client_connection_rate_service_name"
#define DEF_ANVIL_SERVICE "local:" ANVIL_CLASS "/" ANVIL_SERVICE
extern char *var_anvil_service;
#define VAR_SMTP_EHLO_DIS_WORDS "smtp_discard_ehlo_keywords"
#define DEF_SMTP_EHLO_DIS_WORDS ""
+#define VAR_LMTP_EHLO_DIS_WORDS "lmtp_discard_lhlo_keywords"
+#define DEF_LMTP_EHLO_DIS_WORDS ""
extern char *var_smtp_ehlo_dis_words;
#define VAR_SMTP_EHLO_DIS_MAPS "smtp_discard_ehlo_keyword_address_maps"
#define DEF_SMTP_EHLO_DIS_MAPS ""
+#define VAR_LMTP_EHLO_DIS_MAPS "lmtp_discard_lhlo_keyword_address_maps"
+#define DEF_LMTP_EHLO_DIS_MAPS ""
extern char *var_smtp_ehlo_dis_maps;
/*
*/
#define VAR_SMTP_SENDER_AUTH "smtp_sender_dependent_authentication"
#define DEF_SMTP_SENDER_AUTH 0
+#define VAR_LMTP_SENDER_AUTH "lmtp_sender_dependent_authentication"
+#define DEF_LMTP_SENDER_AUTH 0
extern bool var_smtp_sender_auth;
/* LICENSE
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20051202"
+#define MAIL_RELEASE_DATE "20051208"
#define MAIL_VERSION_NUMBER "2.3"
#ifdef SNAPSHOT
};
extern SCACHE *scache_single_create(void);
-extern SCACHE *scache_clnt_create(const char *, int, int);
+extern SCACHE *scache_clnt_create(const char *, int, int, int);
extern SCACHE *scache_multi_create(void);
#define scache_save_endp(scache, ttl, endp_label, endp_prop, fd) \
/* SYNOPSIS
/* #include <scache.h>
/* DESCRIPTION
-/* SCACHE *scache_clnt_create(server, idle_limit, ttl_limit)
+/* SCACHE *scache_clnt_create(server, timeout, idle_limit, ttl_limit)
/* const char *server;
+/* int timeout;
/* int idle_limit;
/* int ttl_limit;
/* DESCRIPTION
/* Arguments:
/* .IP server
/* The session cache service name.
+/* .IP timeout
+/* Time limit for connect, send or receive operations.
/* .IP idle_limit
/* Idle time after which the client disconnects.
/* .IP ttl_limit
#include <msg.h>
#include <mymalloc.h>
+#include <auto_clnt.h>
+#include <stringops.h>
/*#define msg_verbose 1*/
#include <mail_proto.h>
#include <mail_params.h>
-#include <clnt_stream.h>
#include <scache.h>
/* Application-specific. */
*/
typedef struct {
SCACHE scache[1]; /* super-class */
- CLNT_STREAM *clnt_stream; /* client endpoint */
+ AUTO_CLNT *auto_clnt; /* client endpoint */
#ifdef CANT_WRITE_BEFORE_SENDING_FD
VSTRING *dummy; /* dummy buffer */
#endif
* the session cache service is CPU bound and making the client
* asynchronous would just complicate the code.
*/
- for (tries = 0; sp->clnt_stream != 0 ; tries++) {
- stream = clnt_stream_access(sp->clnt_stream);
- errno = 0;
- if (attr_print(stream, ATTR_FLAG_NONE,
- ATTR_TYPE_STR, MAIL_ATTR_REQ, SCACHE_REQ_SAVE_ENDP,
- ATTR_TYPE_NUM, MAIL_ATTR_TTL, endp_ttl,
- ATTR_TYPE_STR, MAIL_ATTR_LABEL, endp_label,
- ATTR_TYPE_STR, MAIL_ATTR_PROP, endp_prop,
- ATTR_TYPE_END) != 0
- || vstream_fflush(stream)
+ for (tries = 0; sp->auto_clnt != 0; tries++) {
+ if ((stream = auto_clnt_access(sp->auto_clnt)) != 0) {
+ errno = 0;
+ if (attr_print(stream, ATTR_FLAG_NONE,
+ ATTR_TYPE_STR, MAIL_ATTR_REQ, SCACHE_REQ_SAVE_ENDP,
+ ATTR_TYPE_NUM, MAIL_ATTR_TTL, endp_ttl,
+ ATTR_TYPE_STR, MAIL_ATTR_LABEL, endp_label,
+ ATTR_TYPE_STR, MAIL_ATTR_PROP, endp_prop,
+ ATTR_TYPE_END) != 0
+ || vstream_fflush(stream)
#ifdef CANT_WRITE_BEFORE_SENDING_FD
- || attr_scan(stream, ATTR_FLAG_STRICT,
- ATTR_TYPE_STR, MAIL_ATTR_DUMMY, sp->dummy,
- ATTR_TYPE_END) != 1
+ || attr_scan(stream, ATTR_FLAG_STRICT,
+ ATTR_TYPE_STR, MAIL_ATTR_DUMMY, sp->dummy,
+ ATTR_TYPE_END) != 1
#endif
- || LOCAL_SEND_FD(vstream_fileno(stream), fd) < 0
- || attr_scan(stream, ATTR_FLAG_STRICT,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &status,
- ATTR_TYPE_END) != 1) {
- if (msg_verbose || (errno != EPIPE && errno != ENOENT))
- msg_warn("problem talking to service %s: %m",
- VSTREAM_PATH(stream));
- /* Give up or recover. */
- } else {
- if (msg_verbose && status != 0)
- msg_warn("%s: descriptor save failed with status %d",
- myname, status);
- break;
+ || LOCAL_SEND_FD(vstream_fileno(stream), fd) < 0
+ || attr_scan(stream, ATTR_FLAG_STRICT,
+ ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &status,
+ ATTR_TYPE_END) != 1) {
+ if (msg_verbose || (errno != EPIPE && errno != ENOENT))
+ msg_warn("problem talking to service %s: %m",
+ VSTREAM_PATH(stream));
+ /* Give up or recover. */
+ } else {
+ if (msg_verbose && status != 0)
+ msg_warn("%s: descriptor save failed with status %d",
+ myname, status);
+ break;
+ }
}
/* Give up or recover. */
if (tries >= SCACHE_MAX_TRIES - 1) {
msg_warn("disabling connection caching");
- clnt_stream_free(sp->clnt_stream);
- sp->clnt_stream = 0;
+ auto_clnt_free(sp->auto_clnt);
+ sp->auto_clnt = 0;
break;
}
sleep(1); /* XXX make configurable */
- clnt_stream_recover(sp->clnt_stream);
+ auto_clnt_recover(sp->auto_clnt);
}
/* Always close the descriptor before returning. */
if (close(fd) < 0)
* the session cache service is CPU bound and making the client
* asynchronous would just complicate the code.
*/
- for (tries = 0; sp->clnt_stream != 0 ; tries++) {
- stream = clnt_stream_access(sp->clnt_stream);
- errno = 0;
- if (attr_print(stream, ATTR_FLAG_NONE,
- ATTR_TYPE_STR, MAIL_ATTR_REQ, SCACHE_REQ_FIND_ENDP,
- ATTR_TYPE_STR, MAIL_ATTR_LABEL, endp_label,
- ATTR_TYPE_END) != 0
- || vstream_fflush(stream)
- || attr_scan(stream, ATTR_FLAG_STRICT,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &status,
- ATTR_TYPE_STR, MAIL_ATTR_PROP, endp_prop,
- ATTR_TYPE_END) != 2) {
- if (msg_verbose || (errno != EPIPE && errno != ENOENT))
- msg_warn("problem talking to service %s: %m",
- VSTREAM_PATH(stream));
- /* Give up or recover. */
- } else if (status != 0) {
- if (msg_verbose)
- msg_info("%s: not found: %s", myname, endp_label);
- return (-1);
- } else if (
+ for (tries = 0; sp->auto_clnt != 0; tries++) {
+ if ((stream = auto_clnt_access(sp->auto_clnt)) != 0) {
+ errno = 0;
+ if (attr_print(stream, ATTR_FLAG_NONE,
+ ATTR_TYPE_STR, MAIL_ATTR_REQ, SCACHE_REQ_FIND_ENDP,
+ ATTR_TYPE_STR, MAIL_ATTR_LABEL, endp_label,
+ ATTR_TYPE_END) != 0
+ || vstream_fflush(stream)
+ || attr_scan(stream, ATTR_FLAG_STRICT,
+ ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &status,
+ ATTR_TYPE_STR, MAIL_ATTR_PROP, endp_prop,
+ ATTR_TYPE_END) != 2) {
+ if (msg_verbose || (errno != EPIPE && errno != ENOENT))
+ msg_warn("problem talking to service %s: %m",
+ VSTREAM_PATH(stream));
+ /* Give up or recover. */
+ } else if (status != 0) {
+ if (msg_verbose)
+ msg_info("%s: not found: %s", myname, endp_label);
+ return (-1);
+ } else if (
#ifdef CANT_WRITE_BEFORE_SENDING_FD
- attr_print(stream, ATTR_FLAG_NONE,
- ATTR_TYPE_STR, MAIL_ATTR_DUMMY, "",
- ATTR_TYPE_END) != 0
- || vstream_fflush(stream) != 0
- || read_wait(vstream_fileno(stream),
- stream->timeout) < 0 || /* XXX */
+ attr_print(stream, ATTR_FLAG_NONE,
+ ATTR_TYPE_STR, MAIL_ATTR_DUMMY, "",
+ ATTR_TYPE_END) != 0
+ || vstream_fflush(stream) != 0
+ || read_wait(vstream_fileno(stream),
+ stream->timeout) < 0 || /* XXX */
#endif
- (fd = LOCAL_RECV_FD(vstream_fileno(stream))) < 0) {
- if (msg_verbose || (errno != EPIPE && errno != ENOENT))
- msg_warn("problem talking to service %s: %m",
- VSTREAM_PATH(stream));
- /* Give up or recover. */
- } else {
+ (fd = LOCAL_RECV_FD(vstream_fileno(stream))) < 0) {
+ if (msg_verbose || (errno != EPIPE && errno != ENOENT))
+ msg_warn("problem talking to service %s: %m",
+ VSTREAM_PATH(stream));
+ /* Give up or recover. */
+ } else {
#ifdef MUST_READ_AFTER_SENDING_FD
- (void) attr_print(stream, ATTR_FLAG_NONE,
- ATTR_TYPE_STR, MAIL_ATTR_DUMMY, "",
- ATTR_TYPE_END);
- (void) vstream_fflush(stream);
+ (void) attr_print(stream, ATTR_FLAG_NONE,
+ ATTR_TYPE_STR, MAIL_ATTR_DUMMY, "",
+ ATTR_TYPE_END);
+ (void) vstream_fflush(stream);
#endif
- if (msg_verbose)
- msg_info("%s: endp=%s prop=%s fd=%d",
- myname, endp_label, STR(endp_prop), fd);
- return (fd);
+ if (msg_verbose)
+ msg_info("%s: endp=%s prop=%s fd=%d",
+ myname, endp_label, STR(endp_prop), fd);
+ return (fd);
+ }
}
/* Give up or recover. */
if (tries >= SCACHE_MAX_TRIES - 1) {
msg_warn("disabling connection caching");
- clnt_stream_free(sp->clnt_stream);
- sp->clnt_stream = 0;
+ auto_clnt_free(sp->auto_clnt);
+ sp->auto_clnt = 0;
return (-1);
}
sleep(1); /* XXX make configurable */
- clnt_stream_recover(sp->clnt_stream);
+ auto_clnt_recover(sp->auto_clnt);
}
return (-1);
}
* the session cache service is CPU bound and making the client
* asynchronous would just complicate the code.
*/
- for (tries = 0; sp->clnt_stream != 0 ; tries++) {
- stream = clnt_stream_access(sp->clnt_stream);
- errno = 0;
- if (attr_print(stream, ATTR_FLAG_NONE,
- ATTR_TYPE_STR, MAIL_ATTR_REQ, SCACHE_REQ_SAVE_DEST,
- ATTR_TYPE_NUM, MAIL_ATTR_TTL, dest_ttl,
- ATTR_TYPE_STR, MAIL_ATTR_LABEL, dest_label,
- ATTR_TYPE_STR, MAIL_ATTR_PROP, dest_prop,
- ATTR_TYPE_STR, MAIL_ATTR_LABEL, endp_label,
- ATTR_TYPE_END) != 0
- || vstream_fflush(stream)
- || attr_scan(stream, ATTR_FLAG_STRICT,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &status,
- ATTR_TYPE_END) != 1) {
- if (msg_verbose || (errno != EPIPE && errno != ENOENT))
- msg_warn("problem talking to service %s: %m",
- VSTREAM_PATH(stream));
- /* Give up or recover. */
- } else {
- if (msg_verbose && status != 0)
- msg_warn("%s: destination save failed with status %d",
- myname, status);
- break;
- }
+ for (tries = 0; sp->auto_clnt != 0; tries++) {
+ if ((stream = auto_clnt_access(sp->auto_clnt)) != 0) {
+ errno = 0;
+ if (attr_print(stream, ATTR_FLAG_NONE,
+ ATTR_TYPE_STR, MAIL_ATTR_REQ, SCACHE_REQ_SAVE_DEST,
+ ATTR_TYPE_NUM, MAIL_ATTR_TTL, dest_ttl,
+ ATTR_TYPE_STR, MAIL_ATTR_LABEL, dest_label,
+ ATTR_TYPE_STR, MAIL_ATTR_PROP, dest_prop,
+ ATTR_TYPE_STR, MAIL_ATTR_LABEL, endp_label,
+ ATTR_TYPE_END) != 0
+ || vstream_fflush(stream)
+ || attr_scan(stream, ATTR_FLAG_STRICT,
+ ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &status,
+ ATTR_TYPE_END) != 1) {
+ if (msg_verbose || (errno != EPIPE && errno != ENOENT))
+ msg_warn("problem talking to service %s: %m",
+ VSTREAM_PATH(stream));
+ /* Give up or recover. */
+ } else {
+ if (msg_verbose && status != 0)
+ msg_warn("%s: destination save failed with status %d",
+ myname, status);
+ break;
+ }
+ }
/* Give up or recover. */
if (tries >= SCACHE_MAX_TRIES - 1) {
msg_warn("disabling connection caching");
- clnt_stream_free(sp->clnt_stream);
- sp->clnt_stream = 0;
+ auto_clnt_free(sp->auto_clnt);
+ sp->auto_clnt = 0;
break;
}
sleep(1); /* XXX make configurable */
- clnt_stream_recover(sp->clnt_stream);
+ auto_clnt_recover(sp->auto_clnt);
}
}
* the session cache service is CPU bound and making the client
* asynchronous would just complicate the code.
*/
- for (tries = 0; sp->clnt_stream != 0 ; tries++) {
- stream = clnt_stream_access(sp->clnt_stream);
- errno = 0;
- if (attr_print(stream, ATTR_FLAG_NONE,
- ATTR_TYPE_STR, MAIL_ATTR_REQ, SCACHE_REQ_FIND_DEST,
- ATTR_TYPE_STR, MAIL_ATTR_LABEL, dest_label,
- ATTR_TYPE_END) != 0
- || vstream_fflush(stream)
- || attr_scan(stream, ATTR_FLAG_STRICT,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &status,
- ATTR_TYPE_STR, MAIL_ATTR_PROP, dest_prop,
- ATTR_TYPE_STR, MAIL_ATTR_PROP, endp_prop,
- ATTR_TYPE_END) != 3) {
- if (msg_verbose || (errno != EPIPE && errno != ENOENT))
- msg_warn("problem talking to service %s: %m",
- VSTREAM_PATH(stream));
- /* Give up or recover. */
- } else if (status != 0) {
- if (msg_verbose)
- msg_info("%s: not found: %s", myname, dest_label);
- return (-1);
- } else if (
+ for (tries = 0; sp->auto_clnt != 0; tries++) {
+ if ((stream = auto_clnt_access(sp->auto_clnt)) != 0) {
+ errno = 0;
+ if (attr_print(stream, ATTR_FLAG_NONE,
+ ATTR_TYPE_STR, MAIL_ATTR_REQ, SCACHE_REQ_FIND_DEST,
+ ATTR_TYPE_STR, MAIL_ATTR_LABEL, dest_label,
+ ATTR_TYPE_END) != 0
+ || vstream_fflush(stream)
+ || attr_scan(stream, ATTR_FLAG_STRICT,
+ ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &status,
+ ATTR_TYPE_STR, MAIL_ATTR_PROP, dest_prop,
+ ATTR_TYPE_STR, MAIL_ATTR_PROP, endp_prop,
+ ATTR_TYPE_END) != 3) {
+ if (msg_verbose || (errno != EPIPE && errno != ENOENT))
+ msg_warn("problem talking to service %s: %m",
+ VSTREAM_PATH(stream));
+ /* Give up or recover. */
+ } else if (status != 0) {
+ if (msg_verbose)
+ msg_info("%s: not found: %s", myname, dest_label);
+ return (-1);
+ } else if (
#ifdef CANT_WRITE_BEFORE_SENDING_FD
- attr_print(stream, ATTR_FLAG_NONE,
- ATTR_TYPE_STR, MAIL_ATTR_DUMMY, "",
- ATTR_TYPE_END) != 0
- || vstream_fflush(stream) != 0
- || read_wait(vstream_fileno(stream),
- stream->timeout) < 0 || /* XXX */
+ attr_print(stream, ATTR_FLAG_NONE,
+ ATTR_TYPE_STR, MAIL_ATTR_DUMMY, "",
+ ATTR_TYPE_END) != 0
+ || vstream_fflush(stream) != 0
+ || read_wait(vstream_fileno(stream),
+ stream->timeout) < 0 || /* XXX */
#endif
- (fd = LOCAL_RECV_FD(vstream_fileno(stream))) < 0) {
- if (msg_verbose || (errno != EPIPE && errno != ENOENT))
- msg_warn("problem talking to service %s: %m",
- VSTREAM_PATH(stream));
- /* Give up or recover. */
- } else {
+ (fd = LOCAL_RECV_FD(vstream_fileno(stream))) < 0) {
+ if (msg_verbose || (errno != EPIPE && errno != ENOENT))
+ msg_warn("problem talking to service %s: %m",
+ VSTREAM_PATH(stream));
+ /* Give up or recover. */
+ } else {
#ifdef MUST_READ_AFTER_SENDING_FD
- (void) attr_print(stream, ATTR_FLAG_NONE,
- ATTR_TYPE_STR, MAIL_ATTR_DUMMY, "",
- ATTR_TYPE_END);
- (void) vstream_fflush(stream);
+ (void) attr_print(stream, ATTR_FLAG_NONE,
+ ATTR_TYPE_STR, MAIL_ATTR_DUMMY, "",
+ ATTR_TYPE_END);
+ (void) vstream_fflush(stream);
#endif
- if (msg_verbose)
- msg_info("%s: dest=%s dest_prop=%s endp_prop=%s fd=%d",
+ if (msg_verbose)
+ msg_info("%s: dest=%s dest_prop=%s endp_prop=%s fd=%d",
myname, dest_label, STR(dest_prop), STR(endp_prop), fd);
- return (fd);
+ return (fd);
+ }
}
/* Give up or recover. */
if (tries >= SCACHE_MAX_TRIES - 1) {
msg_warn("disabling connection caching");
- clnt_stream_free(sp->clnt_stream);
- sp->clnt_stream = 0;
+ auto_clnt_free(sp->auto_clnt);
+ sp->auto_clnt = 0;
return (-1);
}
sleep(1); /* XXX make configurable */
- clnt_stream_recover(sp->clnt_stream);
+ auto_clnt_recover(sp->auto_clnt);
}
return (-1);
}
{
SCACHE_CLNT *sp = (SCACHE_CLNT *) scache;
- if (sp->clnt_stream)
- clnt_stream_free(sp->clnt_stream);
+ if (sp->auto_clnt)
+ auto_clnt_free(sp->auto_clnt);
#ifdef CANT_WRITE_BEFORE_SENDING_FD
vstring_free(sp->dummy);
#endif
/* scache_clnt_create - initialize */
-SCACHE *scache_clnt_create(const char *server, int idle_limit, int ttl_limit)
+SCACHE *scache_clnt_create(const char *server, int timeout,
+ int idle_limit, int ttl_limit)
{
SCACHE_CLNT *sp = (SCACHE_CLNT *) mymalloc(sizeof(*sp));
+ char *service;
sp->scache->save_endp = scache_clnt_save_endp;
sp->scache->find_endp = scache_clnt_find_endp;
sp->scache->size = scache_clnt_size;
sp->scache->free = scache_clnt_free;
- /* XXX Need flags to stop looping on ECONNREFUSED errors. */
- sp->clnt_stream = clnt_stream_create(MAIL_CLASS_PRIVATE, server,
- idle_limit, ttl_limit);
+ service = concatenate("local:private/", var_scache_service, (char *) 0);
+ sp->auto_clnt = auto_clnt_create(service, timeout, idle_limit, ttl_limit);
+ myfree(service);
+
#ifdef CANT_WRITE_BEFORE_SENDING_FD
sp->dummy = vstring_alloc(1);
#endif
+++ /dev/null
-../../.indent.pro
\ No newline at end of file
+++ /dev/null
-been_here_xt 2 0
-bounce_append 5 0
-cleanup_out_format 1 0
-defer_append 5 0
-mail_command 1 0
-mail_print 1 0
-msg_error 0 0
-msg_fatal 0 0
-msg_info 0 0
-msg_panic 0 0
-msg_warn 0 0
-opened 4 0
-post_mail_fprintf 1 0
-qmgr_message_bounce 2 0
-rec_fprintf 2 0
-sent 4 0
-smtp_cmd 1 0
-smtp_mesg_fail 2 0
-smtp_printf 1 0
-smtp_rcpt_fail 3 0
-smtp_site_fail 2 0
-udp_syslog 1 0
-vstream_fprintf 1 0
-vstream_printf 0 0
-vstring_sprintf 1 0
+++ /dev/null
-SHELL = /bin/sh
-SRCS = lmtp.c lmtp_connect.c lmtp_proto.c lmtp_chat.c lmtp_session.c \
- lmtp_addr.c lmtp_trouble.c lmtp_state.c lmtp_sasl_glue.c \
- lmtp_sasl_proto.c lmtp_rcpt.c lmtp_dsn.c
-OBJS = lmtp.o lmtp_connect.o lmtp_proto.o lmtp_chat.o lmtp_session.o \
- lmtp_addr.o lmtp_trouble.o lmtp_state.o lmtp_sasl_glue.o \
- lmtp_sasl_proto.o lmtp_rcpt.o lmtp_dsn.o
-HDRS = lmtp.h
-TESTSRC =
-DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE)
-CFLAGS = $(DEBUG) $(OPT) $(DEFS)
-TESTPROG=
-PROG = lmtp
-INC_DIR = ../../include
-LIBS = ../../lib/libmaster.a ../../lib/libglobal.a ../../lib/libdns.a ../../lib/libutil.a
-
-.c.o:; $(CC) $(CFLAGS) -c $*.c
-
-$(PROG): $(OBJS) $(LIBS)
- $(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS)
-
-$(OBJS): ../../conf/makedefs.out
-
-Makefile: Makefile.in
- (cat ../../conf/makedefs.out $?) >$@
-
-test: $(TESTPROG)
-
-tests: test
-
-update: ../../libexec/$(PROG)
-
-../../libexec/$(PROG): $(PROG)
- cp $(PROG) ../../libexec
-
-printfck: $(OBJS) $(PROG)
- rm -rf printfck
- mkdir printfck
- cp *.h printfck
- sed '1,/^# do not edit/!d' Makefile >printfck/Makefile
- set -e; for i in *.c; do printfck -f .printfck $$i >printfck/$$i; done
- cd printfck; make "INC_DIR=../../../include" `cd ..; ls *.o`
-
-lint:
- lint $(DEFS) $(SRCS) $(LINTFIX)
-
-clean:
- rm -f *.o *core $(PROG) $(TESTPROG) junk
- rm -rf printfck
-
-tidy: clean
-
-depend: $(MAKES)
- (sed '1,/^# do not edit/!d' Makefile.in; \
- set -e; for i in [a-z][a-z0-9]*.c; do \
- $(CC) -E $(DEFS) $(INCL) $$i | grep -v '[<>]' | sed -n -e '/^# *1 *"\([^"]*\)".*/{' \
- -e 's//'`echo $$i|sed 's/c$$/o/'`': \1/' \
- -e 's/o: \.\//o: /' -e p -e '}' ; \
- done | sort -u) | grep -v '[.][o][:][ ][/]' >$$$$ && mv $$$$ Makefile.in
- @$(EXPORT) make -f Makefile.in Makefile 1>&2
-
-# do not edit below this line - it is generated by 'make depend'
-lmtp.o: ../../include/argv.h
-lmtp.o: ../../include/attr.h
-lmtp.o: ../../include/debug_peer.h
-lmtp.o: ../../include/deliver_request.h
-lmtp.o: ../../include/dict.h
-lmtp.o: ../../include/dsn.h
-lmtp.o: ../../include/dsn_buf.h
-lmtp.o: ../../include/dsn_util.h
-lmtp.o: ../../include/flush_clnt.h
-lmtp.o: ../../include/mail_conf.h
-lmtp.o: ../../include/mail_error.h
-lmtp.o: ../../include/mail_params.h
-lmtp.o: ../../include/mail_queue.h
-lmtp.o: ../../include/mail_server.h
-lmtp.o: ../../include/msg.h
-lmtp.o: ../../include/msg_stats.h
-lmtp.o: ../../include/mymalloc.h
-lmtp.o: ../../include/name_mask.h
-lmtp.o: ../../include/recipient_list.h
-lmtp.o: ../../include/split_at.h
-lmtp.o: ../../include/sys_defs.h
-lmtp.o: ../../include/vbuf.h
-lmtp.o: ../../include/vstream.h
-lmtp.o: ../../include/vstring.h
-lmtp.o: lmtp.c
-lmtp.o: lmtp.h
-lmtp.o: lmtp_sasl.h
-lmtp_addr.o: ../../include/argv.h
-lmtp_addr.o: ../../include/attr.h
-lmtp_addr.o: ../../include/deliver_request.h
-lmtp_addr.o: ../../include/dns.h
-lmtp_addr.o: ../../include/dsn.h
-lmtp_addr.o: ../../include/dsn_buf.h
-lmtp_addr.o: ../../include/inet_addr_list.h
-lmtp_addr.o: ../../include/inet_proto.h
-lmtp_addr.o: ../../include/mail_params.h
-lmtp_addr.o: ../../include/msg.h
-lmtp_addr.o: ../../include/msg_stats.h
-lmtp_addr.o: ../../include/myaddrinfo.h
-lmtp_addr.o: ../../include/mymalloc.h
-lmtp_addr.o: ../../include/own_inet_addr.h
-lmtp_addr.o: ../../include/recipient_list.h
-lmtp_addr.o: ../../include/sock_addr.h
-lmtp_addr.o: ../../include/stringops.h
-lmtp_addr.o: ../../include/sys_defs.h
-lmtp_addr.o: ../../include/vbuf.h
-lmtp_addr.o: ../../include/vstream.h
-lmtp_addr.o: ../../include/vstring.h
-lmtp_addr.o: lmtp.h
-lmtp_addr.o: lmtp_addr.c
-lmtp_addr.o: lmtp_addr.h
-lmtp_chat.o: ../../include/argv.h
-lmtp_chat.o: ../../include/attr.h
-lmtp_chat.o: ../../include/cleanup_user.h
-lmtp_chat.o: ../../include/deliver_request.h
-lmtp_chat.o: ../../include/dsn.h
-lmtp_chat.o: ../../include/dsn_buf.h
-lmtp_chat.o: ../../include/dsn_util.h
-lmtp_chat.o: ../../include/line_wrap.h
-lmtp_chat.o: ../../include/mail_addr.h
-lmtp_chat.o: ../../include/mail_error.h
-lmtp_chat.o: ../../include/mail_params.h
-lmtp_chat.o: ../../include/msg.h
-lmtp_chat.o: ../../include/msg_stats.h
-lmtp_chat.o: ../../include/mymalloc.h
-lmtp_chat.o: ../../include/name_mask.h
-lmtp_chat.o: ../../include/post_mail.h
-lmtp_chat.o: ../../include/recipient_list.h
-lmtp_chat.o: ../../include/smtp_stream.h
-lmtp_chat.o: ../../include/stringops.h
-lmtp_chat.o: ../../include/sys_defs.h
-lmtp_chat.o: ../../include/vbuf.h
-lmtp_chat.o: ../../include/vstream.h
-lmtp_chat.o: ../../include/vstring.h
-lmtp_chat.o: lmtp.h
-lmtp_chat.o: lmtp_chat.c
-lmtp_connect.o: ../../include/argv.h
-lmtp_connect.o: ../../include/attr.h
-lmtp_connect.o: ../../include/deliver_request.h
-lmtp_connect.o: ../../include/dns.h
-lmtp_connect.o: ../../include/dsn.h
-lmtp_connect.o: ../../include/dsn_buf.h
-lmtp_connect.o: ../../include/host_port.h
-lmtp_connect.o: ../../include/inet_addr_list.h
-lmtp_connect.o: ../../include/iostuff.h
-lmtp_connect.o: ../../include/mail_params.h
-lmtp_connect.o: ../../include/mail_proto.h
-lmtp_connect.o: ../../include/msg.h
-lmtp_connect.o: ../../include/msg_stats.h
-lmtp_connect.o: ../../include/myaddrinfo.h
-lmtp_connect.o: ../../include/mymalloc.h
-lmtp_connect.o: ../../include/own_inet_addr.h
-lmtp_connect.o: ../../include/recipient_list.h
-lmtp_connect.o: ../../include/sane_connect.h
-lmtp_connect.o: ../../include/sock_addr.h
-lmtp_connect.o: ../../include/split_at.h
-lmtp_connect.o: ../../include/stringops.h
-lmtp_connect.o: ../../include/sys_defs.h
-lmtp_connect.o: ../../include/timed_connect.h
-lmtp_connect.o: ../../include/vbuf.h
-lmtp_connect.o: ../../include/vstream.h
-lmtp_connect.o: ../../include/vstring.h
-lmtp_connect.o: lmtp.h
-lmtp_connect.o: lmtp_addr.h
-lmtp_connect.o: lmtp_connect.c
-lmtp_dsn.o: ../../include/argv.h
-lmtp_dsn.o: ../../include/attr.h
-lmtp_dsn.o: ../../include/deliver_request.h
-lmtp_dsn.o: ../../include/dsn.h
-lmtp_dsn.o: ../../include/dsn_buf.h
-lmtp_dsn.o: ../../include/msg_stats.h
-lmtp_dsn.o: ../../include/recipient_list.h
-lmtp_dsn.o: ../../include/sys_defs.h
-lmtp_dsn.o: ../../include/vbuf.h
-lmtp_dsn.o: ../../include/vstream.h
-lmtp_dsn.o: ../../include/vstring.h
-lmtp_dsn.o: lmtp.h
-lmtp_dsn.o: lmtp_dsn.c
-lmtp_proto.o: ../../include/argv.h
-lmtp_proto.o: ../../include/attr.h
-lmtp_proto.o: ../../include/bounce.h
-lmtp_proto.o: ../../include/defer.h
-lmtp_proto.o: ../../include/deliver_completed.h
-lmtp_proto.o: ../../include/deliver_request.h
-lmtp_proto.o: ../../include/dsn.h
-lmtp_proto.o: ../../include/dsn_buf.h
-lmtp_proto.o: ../../include/dsn_mask.h
-lmtp_proto.o: ../../include/iostuff.h
-lmtp_proto.o: ../../include/mail_params.h
-lmtp_proto.o: ../../include/mail_proto.h
-lmtp_proto.o: ../../include/mail_queue.h
-lmtp_proto.o: ../../include/mark_corrupt.h
-lmtp_proto.o: ../../include/msg.h
-lmtp_proto.o: ../../include/msg_stats.h
-lmtp_proto.o: ../../include/mymalloc.h
-lmtp_proto.o: ../../include/name_code.h
-lmtp_proto.o: ../../include/off_cvt.h
-lmtp_proto.o: ../../include/quote_821_local.h
-lmtp_proto.o: ../../include/quote_822_local.h
-lmtp_proto.o: ../../include/quote_flags.h
-lmtp_proto.o: ../../include/rec_type.h
-lmtp_proto.o: ../../include/recipient_list.h
-lmtp_proto.o: ../../include/record.h
-lmtp_proto.o: ../../include/sent.h
-lmtp_proto.o: ../../include/smtp_stream.h
-lmtp_proto.o: ../../include/stringops.h
-lmtp_proto.o: ../../include/sys_defs.h
-lmtp_proto.o: ../../include/vbuf.h
-lmtp_proto.o: ../../include/vstream.h
-lmtp_proto.o: ../../include/vstring.h
-lmtp_proto.o: ../../include/vstring_vstream.h
-lmtp_proto.o: ../../include/xtext.h
-lmtp_proto.o: lmtp.h
-lmtp_proto.o: lmtp_proto.c
-lmtp_proto.o: lmtp_sasl.h
-lmtp_rcpt.o: ../../include/argv.h
-lmtp_rcpt.o: ../../include/attr.h
-lmtp_rcpt.o: ../../include/bounce.h
-lmtp_rcpt.o: ../../include/deliver_completed.h
-lmtp_rcpt.o: ../../include/deliver_request.h
-lmtp_rcpt.o: ../../include/dsn.h
-lmtp_rcpt.o: ../../include/dsn_buf.h
-lmtp_rcpt.o: ../../include/dsn_mask.h
-lmtp_rcpt.o: ../../include/msg.h
-lmtp_rcpt.o: ../../include/msg_stats.h
-lmtp_rcpt.o: ../../include/recipient_list.h
-lmtp_rcpt.o: ../../include/sent.h
-lmtp_rcpt.o: ../../include/sys_defs.h
-lmtp_rcpt.o: ../../include/vbuf.h
-lmtp_rcpt.o: ../../include/vstream.h
-lmtp_rcpt.o: ../../include/vstring.h
-lmtp_rcpt.o: lmtp.h
-lmtp_rcpt.o: lmtp_rcpt.c
-lmtp_sasl_glue.o: ../../include/argv.h
-lmtp_sasl_glue.o: ../../include/attr.h
-lmtp_sasl_glue.o: ../../include/deliver_request.h
-lmtp_sasl_glue.o: ../../include/dict.h
-lmtp_sasl_glue.o: ../../include/dsn.h
-lmtp_sasl_glue.o: ../../include/dsn_buf.h
-lmtp_sasl_glue.o: ../../include/mail_params.h
-lmtp_sasl_glue.o: ../../include/maps.h
-lmtp_sasl_glue.o: ../../include/match_list.h
-lmtp_sasl_glue.o: ../../include/match_ops.h
-lmtp_sasl_glue.o: ../../include/msg.h
-lmtp_sasl_glue.o: ../../include/msg_stats.h
-lmtp_sasl_glue.o: ../../include/mymalloc.h
-lmtp_sasl_glue.o: ../../include/name_mask.h
-lmtp_sasl_glue.o: ../../include/recipient_list.h
-lmtp_sasl_glue.o: ../../include/split_at.h
-lmtp_sasl_glue.o: ../../include/string_list.h
-lmtp_sasl_glue.o: ../../include/stringops.h
-lmtp_sasl_glue.o: ../../include/sys_defs.h
-lmtp_sasl_glue.o: ../../include/vbuf.h
-lmtp_sasl_glue.o: ../../include/vstream.h
-lmtp_sasl_glue.o: ../../include/vstring.h
-lmtp_sasl_glue.o: lmtp.h
-lmtp_sasl_glue.o: lmtp_sasl.h
-lmtp_sasl_glue.o: lmtp_sasl_glue.c
-lmtp_sasl_proto.o: ../../include/argv.h
-lmtp_sasl_proto.o: ../../include/attr.h
-lmtp_sasl_proto.o: ../../include/deliver_request.h
-lmtp_sasl_proto.o: ../../include/dsn.h
-lmtp_sasl_proto.o: ../../include/dsn_buf.h
-lmtp_sasl_proto.o: ../../include/mail_params.h
-lmtp_sasl_proto.o: ../../include/msg.h
-lmtp_sasl_proto.o: ../../include/msg_stats.h
-lmtp_sasl_proto.o: ../../include/mymalloc.h
-lmtp_sasl_proto.o: ../../include/recipient_list.h
-lmtp_sasl_proto.o: ../../include/sys_defs.h
-lmtp_sasl_proto.o: ../../include/vbuf.h
-lmtp_sasl_proto.o: ../../include/vstream.h
-lmtp_sasl_proto.o: ../../include/vstring.h
-lmtp_sasl_proto.o: lmtp.h
-lmtp_sasl_proto.o: lmtp_sasl.h
-lmtp_sasl_proto.o: lmtp_sasl_proto.c
-lmtp_session.o: ../../include/argv.h
-lmtp_session.o: ../../include/attr.h
-lmtp_session.o: ../../include/debug_peer.h
-lmtp_session.o: ../../include/deliver_request.h
-lmtp_session.o: ../../include/dsn.h
-lmtp_session.o: ../../include/dsn_buf.h
-lmtp_session.o: ../../include/msg_stats.h
-lmtp_session.o: ../../include/mymalloc.h
-lmtp_session.o: ../../include/recipient_list.h
-lmtp_session.o: ../../include/stringops.h
-lmtp_session.o: ../../include/sys_defs.h
-lmtp_session.o: ../../include/vbuf.h
-lmtp_session.o: ../../include/vstream.h
-lmtp_session.o: ../../include/vstring.h
-lmtp_session.o: lmtp.h
-lmtp_session.o: lmtp_session.c
-lmtp_state.o: ../../include/argv.h
-lmtp_state.o: ../../include/attr.h
-lmtp_state.o: ../../include/deliver_request.h
-lmtp_state.o: ../../include/dsn.h
-lmtp_state.o: ../../include/dsn_buf.h
-lmtp_state.o: ../../include/mail_conf.h
-lmtp_state.o: ../../include/msg_stats.h
-lmtp_state.o: ../../include/mymalloc.h
-lmtp_state.o: ../../include/recipient_list.h
-lmtp_state.o: ../../include/sys_defs.h
-lmtp_state.o: ../../include/vbuf.h
-lmtp_state.o: ../../include/vstream.h
-lmtp_state.o: ../../include/vstring.h
-lmtp_state.o: lmtp.h
-lmtp_state.o: lmtp_sasl.h
-lmtp_state.o: lmtp_state.c
-lmtp_trouble.o: ../../include/argv.h
-lmtp_trouble.o: ../../include/attr.h
-lmtp_trouble.o: ../../include/bounce.h
-lmtp_trouble.o: ../../include/defer.h
-lmtp_trouble.o: ../../include/deliver_completed.h
-lmtp_trouble.o: ../../include/deliver_request.h
-lmtp_trouble.o: ../../include/dsn.h
-lmtp_trouble.o: ../../include/dsn_buf.h
-lmtp_trouble.o: ../../include/mail_error.h
-lmtp_trouble.o: ../../include/msg.h
-lmtp_trouble.o: ../../include/msg_stats.h
-lmtp_trouble.o: ../../include/name_mask.h
-lmtp_trouble.o: ../../include/recipient_list.h
-lmtp_trouble.o: ../../include/smtp_stream.h
-lmtp_trouble.o: ../../include/stringops.h
-lmtp_trouble.o: ../../include/sys_defs.h
-lmtp_trouble.o: ../../include/vbuf.h
-lmtp_trouble.o: ../../include/vstream.h
-lmtp_trouble.o: ../../include/vstring.h
-lmtp_trouble.o: lmtp.h
-lmtp_trouble.o: lmtp_trouble.c
+++ /dev/null
-/*++
-/* NAME
-/* lmtp 8
-/* SUMMARY
-/* Postfix local delivery via LMTP
-/* SYNOPSIS
-/* \fBlmtp\fR [generic Postfix daemon options]
-/* DESCRIPTION
-/* The LMTP client processes message delivery requests from
-/* the queue manager. Each request specifies a queue file, a sender
-/* address, a domain or host to deliver to, and recipient information.
-/* This program expects to be run from the \fBmaster\fR(8) process
-/* manager.
-/*
-/* The LMTP client updates the queue file and marks recipients
-/* as finished, or it informs the queue manager that delivery should
-/* be tried again at a later time. Delivery status reports are sent
-/* to the \fBbounce\fR(8), \fBdefer\fR(8) or \fBtrace\fR(8) daemon as
-/* appropriate.
-/*
-/* The LMTP client connects to the destination specified in the message
-/* delivery request. The destination, usually specified in the Postfix
-/* \fBtransport\fR(5) table, has the form:
-/* .IP \fBunix\fR:\fIpathname\fR
-/* Connect to the local UNIX-domain server that is bound to the specified
-/* \fIpathname\fR. If the process runs chrooted, an absolute pathname
-/* is interpreted relative to the changed root directory.
-/* .IP "\fBinet\fR:\fIhost\fR, \fBinet\fB:\fIhost\fR:\fIport\fR (symbolic host)"
-/* .IP "\fBinet\fR:[\fIaddr\fR], \fBinet\fR:[\fIaddr\fR]:\fIport\fR (numeric host)"
-/* Connect to the specified IPV4 TCP port on the specified local or
-/* remote host. If no port is specified, connect to the port defined as
-/* \fBlmtp\fR in \fBservices\fR(4).
-/* If no such service is found, the \fBlmtp_tcp_port\fR configuration
-/* parameter (default value of 24) will be used.
-/*
-/* The LMTP client does not perform MX (mail exchanger) lookups since
-/* those are defined only for mail delivery via SMTP.
-/* .PP
-/* If neither \fBunix:\fR nor \fBinet:\fR are specified, \fBinet:\fR
-/* is assumed.
-/* SECURITY
-/* .ad
-/* .fi
-/* The LMTP client is moderately security-sensitive. It talks to LMTP
-/* servers and to DNS servers on the network. The LMTP client can be
-/* run chrooted at fixed low privilege.
-/* STANDARDS
-/* RFC 821 (SMTP protocol)
-/* RFC 1651 (SMTP service extensions)
-/* RFC 1652 (8bit-MIME transport)
-/* RFC 1870 (Message Size Declaration)
-/* RFC 2033 (LMTP protocol)
-/* RFC 2034 (Enhanced Status codes)
-/* RFC 2554 (AUTH command)
-/* RFC 2821 (SMTP protocol)
-/* RFC 2920 (SMTP Pipelining)
-/* RFC 3463 (Enhanced Status codes)
-/* DIAGNOSTICS
-/* Problems and transactions are logged to \fBsyslogd\fR(8).
-/* Corrupted message files are marked so that the queue manager can
-/* move them to the \fBcorrupt\fR queue for further inspection.
-/*
-/* Depending on the setting of the \fBnotify_classes\fR parameter,
-/* the postmaster is notified of bounces, protocol problems, and of
-/* other trouble.
-/* CONFIGURATION PARAMETERS
-/* .ad
-/* .fi
-/* Changes to \fBmain.cf\fR are picked up automatically, as \fBlmtp\fR(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
-/* \fBpostconf\fR(5) for more details including examples.
-/* COMPATIBILITY CONTROLS
-/* .ad
-/* .fi
-/* .IP "\fBlmtp_skip_quit_response (no)\fR"
-/* Wait for the response to the LMTP QUIT command.
-/* TROUBLE SHOOTING CONTROLS
-/* .ad
-/* .fi
-/* .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.
-/* EXTERNAL CONTENT INSPECTION CONTROLS
-/* .ad
-/* .fi
-/* Available in Postfix version 2.1 and later:
-/* .IP "\fBlmtp_send_xforward_command (no)\fR"
-/* Send an XFORWARD command to the LMTP server when the LMTP LHLO
-/* server response announces XFORWARD support.
-/* SASL AUTHENTICATION CONTROLS
-/* .ad
-/* .fi
-/* .IP "\fBlmtp_sasl_auth_enable (no)\fR"
-/* Enable SASL authentication in the Postfix LMTP client.
-/* .IP "\fBlmtp_sasl_password_maps (empty)\fR"
-/* Optional LMTP client lookup tables with one username:password entry
-/* per host or domain.
-/* .IP "\fBlmtp_sasl_security_options (noplaintext, noanonymous)\fR"
-/* What authentication mechanisms the Postfix LMTP client is allowed
-/* to use.
-/* RESOURCE AND RATE CONTROLS
-/* .ad
-/* .fi
-/* In the text below, \fItransport\fR is the name
-/* of the service as specified in the \fBmaster.cf\fR file.
-/* .IP "\fBlmtp_cache_connection (yes)\fR"
-/* Keep Postfix LMTP client connections open for up to $max_idle
-/* seconds.
-/* .IP "\fItransport_\fBdestination_concurrency_limit ($default_destination_concurrency_limit)\fR"
-/* Limit the number of parallel deliveries to the same destination
-/* via this mail delivery transport.
-/* .IP "\fItransport_\fBdestination_recipient_limit ($default_destination_recipient_limit)\fR"
-/* Limit the number of recipients per message delivery via this mail
-/* delivery transport.
-/*
-/* This parameter becomes significant if the LMTP client is used
-/* for local delivery. Some LMTP servers can optimize delivery of
-/* the same message to multiple recipients. The default limit for
-/* local mail delivery is 1.
-/*
-/* Setting this parameter to 0 will lead to an unbounded number of
-/* recipients per delivery. However, this could be risky since it may
-/* make the machine vulnerable to running out of resources if messages
-/* are encountered with an inordinate number of recipients. Exercise
-/* care when setting this parameter.
-/* .IP "\fBlmtp_connect_timeout (0s)\fR"
-/* The LMTP client time limit for completing a TCP connection, or
-/* zero (use the operating system built-in time limit).
-/* .IP "\fBlmtp_lhlo_timeout (300s)\fR"
-/* The LMTP client time limit for receiving the LMTP greeting
-/* banner.
-/* .IP "\fBlmtp_xforward_timeout (300s)\fR"
-/* The LMTP client time limit for sending the XFORWARD command, and
-/* for receiving the server response.
-/* .IP "\fBlmtp_mail_timeout (300s)\fR"
-/* The LMTP client time limit for sending the MAIL FROM command, and
-/* for receiving the server response.
-/* .IP "\fBlmtp_rcpt_timeout (300s)\fR"
-/* The LMTP client time limit for sending the RCPT TO command, and
-/* for receiving the server response.
-/* .IP "\fBlmtp_data_init_timeout (120s)\fR"
-/* The LMTP client time limit for sending the LMTP DATA command, and
-/* for receiving the server response.
-/* .IP "\fBlmtp_data_xfer_timeout (180s)\fR"
-/* The LMTP client time limit for sending the LMTP message content.
-/* .IP "\fBlmtp_data_done_timeout (600s)\fR"
-/* The LMTP client time limit for sending the LMTP ".", and for
-/* receiving the server response.
-/* .IP "\fBlmtp_rset_timeout (20s)\fR"
-/* The LMTP client time limit for sending the RSET command, and
-/* for receiving the server response.
-/* .IP "\fBlmtp_quit_timeout (300s)\fR"
-/* The LMTP client time limit for sending the QUIT command, and for
-/* receiving the server response.
-/* 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 "\fBdelay_logging_resolution_limit (2)\fR"
-/* The maximal number of digits after the decimal point when logging
-/* sub-second delay values.
-/* .IP "\fBdisable_dns_lookups (no)\fR"
-/* Disable DNS lookups in the Postfix SMTP and LMTP clients.
-/* .IP "\fBipc_timeout (3600s)\fR"
-/* The time limit for sending or receiving information over an internal
-/* communication channel.
-/* .IP "\fBlmtp_tcp_port (24)\fR"
-/* The default TCP port that the Postfix LMTP client connects to.
-/* .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 "\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 "\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
-/* bounce(8), delivery status reports
-/* qmgr(8), queue manager
-/* postconf(5), configuration parameters
-/* master(5), generic daemon options
-/* services(4), Internet services and aliases
-/* 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
-/* LMTP_README, Postfix LMTP client howto
-/* VIRTUAL_README, virtual delivery agent howto
-/* 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
-/*
-/* Modifications for LMTP by:
-/* Philip A. Prindeville
-/* Mirapoint, Inc.
-/* USA.
-/*
-/* SASL support originally by:
-/* Till Franke
-/* SuSE Rhein/Main AG
-/* 65760 Eschborn, Germany
-/*
-/* Additional work on LMTP by:
-/* Amos Gouaux
-/* University of Texas at Dallas
-/* P.O. Box 830688, MC34
-/* Richardson, TX 75083, USA
-/*--*/
-
-/* System library. */
-
-#include <sys_defs.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <fcntl.h>
-#include <dict.h>
-
-/* Utility library. */
-
-#include <msg.h>
-#include <argv.h>
-#include <mymalloc.h>
-#include <name_mask.h>
-#include <split_at.h>
-
-/* Global library. */
-
-#include <deliver_request.h>
-#include <mail_queue.h>
-#include <mail_params.h>
-#include <mail_conf.h>
-#include <debug_peer.h>
-#include <mail_error.h>
-#include <flush_clnt.h>
-#include <dsn_util.h>
-
-/* Single server skeleton. */
-
-#include <mail_server.h>
-
-/* Application-specific. */
-
-#include "lmtp.h"
-#include "lmtp_sasl.h"
-
- /*
- * Tunable parameters. These have compiled-in defaults that can be overruled
- * by settings in the global Postfix configuration file.
- */
-int var_lmtp_tcp_port;
-int var_lmtp_conn_tmout;
-int var_lmtp_rset_tmout;
-int var_lmtp_lhlo_tmout;
-int var_lmtp_xfwd_tmout;
-int var_lmtp_mail_tmout;
-int var_lmtp_rcpt_tmout;
-int var_lmtp_data0_tmout;
-int var_lmtp_data1_tmout;
-int var_lmtp_data2_tmout;
-int var_lmtp_quit_tmout;
-int var_lmtp_cache_conn;
-int var_lmtp_skip_quit_resp;
-char *var_notify_classes;
-char *var_error_rcpt;
-char *var_lmtp_sasl_opts;
-char *var_lmtp_sasl_passwd;
-bool var_lmtp_sasl_enable;
-bool var_lmtp_send_xforward;
-
- /*
- * Global variables.
- *
- * lmtp_errno is set by the address lookup routines and by the connection
- * management routines.
- *
- * state is global for the connection caching to work.
- */
-int lmtp_errno;
-static LMTP_STATE *state = 0;
-
-/* deliver_message - deliver message with extreme prejudice */
-
-static int deliver_message(DELIVER_REQUEST *request, char **unused_argv)
-{
- char *myname = "deliver_message";
- DSN_BUF *why;
- int result;
-
- if (msg_verbose)
- msg_info("%s: from %s", myname, request->sender);
-
- /*
- * Sanity checks.
- */
- if (request->rcpt_list.len <= 0)
- msg_fatal("%s: recipient count: %d", myname, request->rcpt_list.len);
-
- /*
- * Initialize. Bundle all information about the delivery request, so that
- * we can produce understandable diagnostics when something goes wrong
- * many levels below. The alternative would be to make everything global.
- *
- * Note: `state' was made global (to this file) so that we can cache
- * connections and so that we can close a cached connection via the
- * MAIL_SERVER_EXIT function (cleanup). The alloc for `state' is
- * performed in the MAIL_SERVER_POST_INIT function (post_init).
- *
- */
- why = dsb_create();
- state->request = request;
- state->src = request->fp;
-
- /*
- * See if we can reuse an existing connection.
- */
- if (state->session != 0) {
-
- /*
- * Disconnect if we're going to a different destination. Discard
- * transcript and status information for sending QUIT.
- *
- * XXX Should transform nexthop into canonical form (unix:/path or
- * inet:host:port) before doing connection cache lookup. See also the
- * connection cache updating code in lmtp_connect.c.
- */
- if (strcasecmp(state->session->dest, request->nexthop) != 0) {
- lmtp_quit(state);
- lmtp_chat_reset(state);
- state->session = lmtp_session_free(state->session);
-#ifdef USE_SASL_AUTH
- if (var_lmtp_sasl_enable)
- lmtp_sasl_cleanup(state);
-#endif
- }
-
- /*
- * Disconnect if RSET can't be sent over an existing connection.
- * Discard transcript and status information for sending RSET.
- */
- else if (lmtp_rset(state) != 0
- || (state->features & LMTP_FEATURE_RSET_REJECTED) != 0) {
- lmtp_chat_reset(state);
- state->session = lmtp_session_free(state->session);
-#ifdef USE_SASL_AUTH
- if (var_lmtp_sasl_enable)
- lmtp_sasl_cleanup(state);
-#endif
- }
-
- /*
- * Ready to go with another load. The reuse counter is logged for
- * statistical analysis purposes. Given the Postfix architecture,
- * connection cacheing makes sense only for dedicated transports.
- * Logging the reuse count can help to convince people.
- */
- else {
- ++state->reuse;
- if (msg_verbose)
- msg_info("%s: reusing (count %d) session with: %s",
- myname, state->reuse, state->session->host);
- }
- }
-
- /*
- * See if we need to establish an LMTP connection.
- */
- if (state->session == 0) {
-
- /*
- * Bounce or defer the recipients if no connection can be made.
- *
- * XXX Unlike enhanced status codes, changing a 4xx into 5xx LMTP code
- * is not simply a matter of changing the initial digit. What we're
- * doing here is correct only under specific conditions, such as
- * changing 450 into 550 or vice versa.
- */
- if ((state->session = lmtp_connect(request->nexthop, why)) == 0) {
- if (lmtp_errno == LMTP_RETRY)
- STR(why->status)[0] = STR(why->dtext)[0] = '4'; /* XXX */
- else
- STR(why->status)[0] = STR(why->dtext)[0] = '5'; /* XXX */
- lmtp_sess_fail(state, why);
- }
-
- /*
- * Bounce or defer the recipients if the LMTP handshake fails.
- */
- else if (lmtp_lhlo(state) != 0) {
- state->session = lmtp_session_free(state->session);
-#ifdef USE_SASL_AUTH
- if (var_lmtp_sasl_enable)
- lmtp_sasl_cleanup(state);
-#endif
- }
-
- /*
- * Congratulations. We just established a new LMTP connection.
- */
- else
- state->reuse = 0;
- }
-
- /*
- * If a session exists, deliver this message to all requested recipients.
- */
- if (state->session != 0)
- lmtp_xfer(state);
-
- /*
- * Optionally, notify the postmaster of problems with establishing a
- * session or with delivering mail.
- */
- if (state->history != 0
- && (state->error_mask & name_mask(VAR_NOTIFY_CLASSES, mail_error_masks,
- var_notify_classes)))
- lmtp_chat_notify(state);
-
- /*
- * Disconnect if we're not caching connections. The pipelined protocol
- * state machine knows if it should have sent a QUIT command. Do not
- * cache a broken connection.
- */
- if (state->session != 0
- && (!var_lmtp_cache_conn
- || vstream_ferror(state->session->stream)
- || vstream_feof(state->session->stream)))
- state->session = lmtp_session_free(state->session);
-
- /*
- * Clean up.
- */
- dsb_free(why);
- result = state->status;
- lmtp_chat_reset(state);
-
- /*
- * XXX State persists until idle timeout, but these fields will be
- * dangling pointers. Nuke them.
- */
- state->request = 0;
- state->src = 0;
-
- return (result);
-}
-
-/* lmtp_service - perform service for client */
-
-static void lmtp_service(VSTREAM *client_stream, char *unused_service, char **argv)
-{
- DELIVER_REQUEST *request;
- int status;
-
- /*
- * Sanity check. This service takes no command-line arguments.
- */
- if (argv[0])
- msg_fatal("unexpected command-line argument: %s", argv[0]);
-
- /*
- * This routine runs whenever a client connects to the UNIX-domain socket
- * dedicated to remote LMTP delivery service. What we see below is a
- * little protocol to (1) tell the queue manager that we are ready, (2)
- * read a request from the queue manager, and (3) report the completion
- * status of that request. All connection-management stuff is handled by
- * the common code in single_server.c.
- */
- if ((request = deliver_request_read(client_stream)) != 0) {
- status = deliver_message(request, argv);
- deliver_request_done(client_stream, request, status);
- }
-}
-
-/* post_init - post-jail initialization */
-
-static void post_init(char *unused_name, char **unused_argv)
-{
- state = lmtp_state_alloc();
-}
-
-/* pre_init - pre-jail initialization */
-
-static void pre_init(char *unused_name, char **unused_argv)
-{
- debug_peer_init();
- if (var_lmtp_sasl_enable)
-#ifdef USE_SASL_AUTH
- lmtp_sasl_initialize();
-#else
- msg_warn("%s is true, but SASL support is not compiled in",
- VAR_LMTP_SASL_ENABLE);
-#endif
-
- /*
- * flush client.
- */
- flush_init();
-}
-
-/* cleanup - close any open connections, etc. */
-
-static void cleanup(void)
-{
- if (state->session != 0) {
- lmtp_quit(state);
- lmtp_chat_reset(state);
- state->session = lmtp_session_free(state->session);
- if (msg_verbose)
- msg_info("cleanup: just closed down session");
- }
- lmtp_state_free(state);
-#ifdef USE_SASL_AUTH
- if (var_lmtp_sasl_enable)
- sasl_done();
-#endif
-}
-
-/* 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);
- cleanup();
- exit(0);
- }
-}
-
-/* main - pass control to the single-threaded skeleton */
-
-int main(int argc, char **argv)
-{
- static CONFIG_STR_TABLE str_table[] = {
- VAR_NOTIFY_CLASSES, DEF_NOTIFY_CLASSES, &var_notify_classes, 0, 0,
- VAR_ERROR_RCPT, DEF_ERROR_RCPT, &var_error_rcpt, 1, 0,
- VAR_LMTP_SASL_PASSWD, DEF_LMTP_SASL_PASSWD, &var_lmtp_sasl_passwd, 0, 0,
- VAR_LMTP_SASL_OPTS, DEF_LMTP_SASL_OPTS, &var_lmtp_sasl_opts, 0, 0,
- 0,
- };
- static CONFIG_INT_TABLE int_table[] = {
- VAR_LMTP_TCP_PORT, DEF_LMTP_TCP_PORT, &var_lmtp_tcp_port, 0, 0,
- 0,
- };
- static CONFIG_TIME_TABLE time_table[] = {
- VAR_LMTP_CONN_TMOUT, DEF_LMTP_CONN_TMOUT, &var_lmtp_conn_tmout, 0, 0,
- VAR_LMTP_RSET_TMOUT, DEF_LMTP_RSET_TMOUT, &var_lmtp_rset_tmout, 1, 0,
- VAR_LMTP_LHLO_TMOUT, DEF_LMTP_LHLO_TMOUT, &var_lmtp_lhlo_tmout, 1, 0,
- VAR_LMTP_XFWD_TMOUT, DEF_LMTP_XFWD_TMOUT, &var_lmtp_xfwd_tmout, 1, 0,
- VAR_LMTP_MAIL_TMOUT, DEF_LMTP_MAIL_TMOUT, &var_lmtp_mail_tmout, 1, 0,
- VAR_LMTP_RCPT_TMOUT, DEF_LMTP_RCPT_TMOUT, &var_lmtp_rcpt_tmout, 1, 0,
- VAR_LMTP_DATA0_TMOUT, DEF_LMTP_DATA0_TMOUT, &var_lmtp_data0_tmout, 1, 0,
- VAR_LMTP_DATA1_TMOUT, DEF_LMTP_DATA1_TMOUT, &var_lmtp_data1_tmout, 1, 0,
- VAR_LMTP_DATA2_TMOUT, DEF_LMTP_DATA2_TMOUT, &var_lmtp_data2_tmout, 1, 0,
- VAR_LMTP_QUIT_TMOUT, DEF_LMTP_QUIT_TMOUT, &var_lmtp_quit_tmout, 1, 0,
- 0,
- };
- static CONFIG_BOOL_TABLE bool_table[] = {
- VAR_LMTP_CACHE_CONN, DEF_LMTP_CACHE_CONN, &var_lmtp_cache_conn,
- VAR_LMTP_SKIP_QUIT_RESP, DEF_LMTP_SKIP_QUIT_RESP, &var_lmtp_skip_quit_resp,
- VAR_LMTP_SASL_ENABLE, DEF_LMTP_SASL_ENABLE, &var_lmtp_sasl_enable,
- VAR_LMTP_SEND_XFORWARD, DEF_LMTP_SEND_XFORWARD, &var_lmtp_send_xforward,
- 0,
- };
-
- single_server_main(argc, argv, lmtp_service,
- MAIL_SERVER_INT_TABLE, int_table,
- MAIL_SERVER_STR_TABLE, str_table,
- MAIL_SERVER_BOOL_TABLE, bool_table,
- MAIL_SERVER_TIME_TABLE, time_table,
- MAIL_SERVER_PRE_INIT, pre_init,
- MAIL_SERVER_POST_INIT, post_init,
- MAIL_SERVER_PRE_ACCEPT, pre_accept,
- MAIL_SERVER_EXIT, cleanup,
- 0);
-}
+++ /dev/null
-/*++
-/* NAME
-/* lmtp 3h
-/* SUMMARY
-/* lmtp client program
-/* SYNOPSIS
-/* #include "lmtp.h"
-/* DESCRIPTION
-/* .nf
-
- /*
- * SASL library.
- */
-#ifdef USE_SASL_AUTH
-#include <sasl.h>
-#include <saslutil.h>
-#endif
-
- /*
- * Utility library.
- */
-#include <vstream.h>
-#include <vstring.h>
-#include <argv.h>
-
- /*
- * Global library.
- */
-#include <deliver_request.h>
-#include <dsn_buf.h>
-
- /*
- * State information associated with each LMTP delivery. We're bundling the
- * state so that we can give meaningful diagnostics in case of problems.
- */
-typedef struct LMTP_STATE {
- VSTREAM *src; /* queue file stream */
- DELIVER_REQUEST *request; /* envelope info, offsets */
- struct LMTP_SESSION *session; /* network connection */
- VSTRING *buffer; /* I/O buffer */
- VSTRING *scratch; /* scratch buffer */
- VSTRING *scratch2; /* scratch buffer */
- int status; /* delivery status */
- int features; /* server features */
- ARGV *history; /* transaction log */
- int error_mask; /* error classes */
-#ifdef USE_SASL_AUTH
- char *sasl_mechanism_list; /* server mechanism list */
- char *sasl_username; /* client username */
- char *sasl_passwd; /* client password */
- sasl_conn_t *sasl_conn; /* SASL internal state */
- VSTRING *sasl_encoded; /* encoding buffer */
- VSTRING *sasl_decoded; /* decoding buffer */
- sasl_callback_t *sasl_callbacks; /* stateful callbacks */
-#endif
- int sndbufsize; /* total window size */
- int reuse; /* connection being reused */
- VSTRING *dsn_reason; /* human-readable, sort of */
-} LMTP_STATE;
-
-#define LMTP_FEATURE_ESMTP (1<<0)
-#define LMTP_FEATURE_8BITMIME (1<<1)
-#define LMTP_FEATURE_PIPELINING (1<<2)
-#define LMTP_FEATURE_SIZE (1<<3)
-#define LMTP_FEATURE_AUTH (1<<5)
-#define LMTP_FEATURE_XFORWARD_NAME (1<<6)
-#define LMTP_FEATURE_XFORWARD_ADDR (1<<7)
-#define LMTP_FEATURE_XFORWARD_PROTO (1<<8)
-#define LMTP_FEATURE_XFORWARD_HELO (1<<9)
-#define LMTP_FEATURE_XFORWARD_DOMAIN (1<<10)
-#define LMTP_FEATURE_DSN (1<<11)
-#define LMTP_FEATURE_RSET_REJECTED (1<<12)
-
- /*
- * lmtp.c
- */
-extern int lmtp_errno; /* XXX can we get rid of this? */
-
- /*
- * lmtp_session.c
- */
-typedef struct LMTP_SESSION {
- VSTREAM *stream; /* network connection */
- char *host; /* mail exchanger, name */
- char *addr; /* mail exchanger, address */
- char *namaddr; /* mail exchanger, for logging */
- char *dest; /* remote endpoint name */
-} LMTP_SESSION;
-
-extern LMTP_SESSION *lmtp_session_alloc(VSTREAM *, const char *, const char *, const char *);
-extern LMTP_SESSION *lmtp_session_free(LMTP_SESSION *);
-
- /*
- * lmtp_connect.c
- */
-extern LMTP_SESSION *lmtp_connect(const char *, DSN_BUF *);
-
- /*
- * lmtp_proto.c
- */
-extern int lmtp_lhlo(LMTP_STATE *);
-extern int lmtp_xfer(LMTP_STATE *);
-extern int lmtp_quit(LMTP_STATE *);
-extern int lmtp_rset(LMTP_STATE *);
-
- /*
- * lmtp_chat.c
- */
-typedef struct LMTP_RESP { /* server response */
- int code; /* LMTP code */
- char *dsn; /* enhanced status */
- char *str; /* full reply */
- VSTRING *dsn_buf; /* status buffer */
- VSTRING *str_buf; /* reply buffer */
-} LMTP_RESP;
-
-extern void PRINTFLIKE(2, 3) lmtp_chat_cmd(LMTP_STATE *, char *,...);
-extern LMTP_RESP *lmtp_chat_resp(LMTP_STATE *);
-extern void lmtp_chat_reset(LMTP_STATE *);
-extern void lmtp_chat_notify(LMTP_STATE *);
-
-#define LMTP_RESP_FAKE(resp, _code, _dsn, _str) \
- ((resp)->code = (_code), \
- (resp)->dsn = (_dsn), \
- (resp)->str = (_str), \
- (resp))
-
- /*
- * lmtp_trouble.c
- */
-extern int lmtp_sess_fail(LMTP_STATE *, DSN_BUF *);
-extern int PRINTFLIKE(4, 5) lmtp_site_fail(LMTP_STATE *, const char *,
- LMTP_RESP *, const char *,...);
-extern int PRINTFLIKE(4, 5) lmtp_mesg_fail(LMTP_STATE *, const char *,
- LMTP_RESP *, const char *,...);
-extern void PRINTFLIKE(5, 6) lmtp_rcpt_fail(LMTP_STATE *, const char *, LMTP_RESP *, RECIPIENT *, const char *,...);
-extern int lmtp_stream_except(LMTP_STATE *, int, const char *);
-
- /*
- * lmtp_state.c
- */
-extern LMTP_STATE *lmtp_state_alloc(void);
-extern void lmtp_state_free(LMTP_STATE *);
-
- /*
- * lmtp_rcpt.c
- */
-extern void lmtp_rcpt_done(LMTP_STATE *, LMTP_RESP *, RECIPIENT *);
-
- /*
- * Status codes. Errors must have negative codes so that they do not
- * interfere with useful counts of work done.
- */
-#define LMTP_OK 0 /* so far, so good */
-#define LMTP_RETRY (-1) /* transient error */
-#define LMTP_FAIL (-2) /* hard error */
-
- /*
- * lmtp_dsn.c
- */
-extern void PRINTFLIKE(6, 7) lmtp_dsn_update(DSN_BUF *, const char *,
- const char *,
- int, const char *,
- const char *,...);
-extern void vlmtp_dsn_update(DSN_BUF *, const char *, const char *,
- int, const char *,
- const char *, va_list);
-extern void lmtp_dsn_formal(DSN_BUF *, const char *, const char *,
- int, const char *);
-
-#define LMTP_DSN_ASSIGN(dsn, mta, stat, resp, why) \
- DSN_ASSIGN((dsn), (stat), DSB_DEF_ACTION, (why), DSB_DTYPE_SMTP, (resp), \
- (mta) ? DSB_MTYPE_DNS : DSB_MTYPE_NONE, (mta))
-
-#define DSN_BY_LOCAL_MTA ((char *) 0) /* DSN issued by local MTA */
-
- /*
- * Silly little macros.
- */
-#define STR(s) vstring_str(s)
-
-/* 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
-/*
-/* Alterations for LMTP by:
-/* Philip A. Prindeville
-/* Mirapoint, Inc.
-/* USA.
-/*
-/* Additional work on LMTP by:
-/* Amos Gouaux
-/* University of Texas at Dallas
-/* P.O. Box 830688, MC34
-/* Richardson, TX 75083, USA
-/*--*/
+++ /dev/null
-/*++
-/* NAME
-/* lmtp_addr 3
-/* SUMMARY
-/* LMTP server address lookup
-/* SYNOPSIS
-/* #include "lmtp_addr.h"
-/*
-/* DNS_RR *lmtp_host_addr(name, why)
-/* char *name;
-/* DSN_BUF *why;
-/* DESCRIPTION
-/* This module implements Internet address lookups. By default,
-/* lookups are done via the Internet domain name service (DNS).
-/* A reasonable number of CNAME indirections is permitted.
-/*
-/* lmtp_host_addr() looks up all addresses listed for the named
-/* host. The host can be specified as a numerical Internet network
-/* address, or as a symbolic host name.
-/*
-/* Fortunately, we don't have to worry about MX records because
-/* those are for SMTP servers, not LMTP servers.
-/*
-/* Results from lmtp_host_addr() are destroyed by dns_rr_free(),
-/* including null lists.
-/* DIAGNOSTICS
-/* This routine either returns a DNS_RR pointer, or return a null
-/* pointer and sets the \fIlmtp_errno\fR global variable accordingly:
-/* .IP LMTP_RETRY
-/* The request failed due to a soft error, and should be retried later.
-/* .IP LMTP_FAIL
-/* The request attempt failed due to a hard error.
-/* .PP
-/* In addition, a description of the problem is made available
-/* via the \fIwhy\fR argument.
-/* 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
-/*
-/* Alterations for LMTP by:
-/* Philip A. Prindeville
-/* Mirapoint, Inc.
-/* USA.
-/*
-/* Additional work on LMTP by:
-/* Amos Gouaux
-/* University of Texas at Dallas
-/* P.O. Box 830688, MC34
-/* Richardson, TX 75083, USA
-/*--*/
-
-/* System library. */
-
-#include <sys_defs.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <stdlib.h>
-#include <netdb.h>
-#include <ctype.h>
-#include <string.h>
-#include <unistd.h>
-
-/* Utility library. */
-
-#include <msg.h>
-#include <vstring.h>
-#include <mymalloc.h>
-#include <inet_addr_list.h>
-#include <stringops.h>
-#include <myaddrinfo.h>
-#include <sock_addr.h>
-#include <inet_proto.h>
-
-/* Global library. */
-
-#include <mail_params.h>
-#include <own_inet_addr.h>
-
-/* DNS library. */
-
-#include <dns.h>
-
-/* Application-specific. */
-
-#include "lmtp.h"
-#include "lmtp_addr.h"
-
-/* lmtp_print_addr - print address list */
-
-static void lmtp_print_addr(char *what, DNS_RR *addr_list)
-{
- DNS_RR *addr;
- MAI_HOSTADDR_STR hostaddr;
-
- msg_info("begin %s address list", what);
- for (addr = addr_list; addr; addr = addr->next) {
- if (dns_rr_to_pa(addr, &hostaddr) == 0) {
- msg_warn("skipping record type %s: %m", dns_strtype(addr->type));
- } else {
- msg_info("pref %4d host %s/%s",
- addr->pref, addr->name,
- hostaddr.buf);
- }
- }
- msg_info("end %s address list", what);
-}
-
-/* lmtp_addr_one - address lookup for one host name */
-
-static DNS_RR *lmtp_addr_one(DNS_RR *addr_list, char *host, unsigned pref,
- DSN_BUF *why)
-{
- char *myname = "lmtp_addr_one";
- DNS_RR *addr = 0;
- DNS_RR *rr;
- int aierr;
- struct addrinfo *res0;
- struct addrinfo *res;
- INET_PROTO_INFO *proto_info = inet_proto_info();
- int found;
-
- if (msg_verbose)
- msg_info("%s: host %s", myname, host);
-
- /*
- * Interpret a numerical name as an address.
- */
- if (hostaddr_to_sockaddr(host, (char *) 0, 0, &res0) == 0
- && strchr((char *) proto_info->sa_family_list, res0->ai_family) != 0) {
- if ((addr = dns_sa_to_rr(host, pref, res0->ai_addr)) == 0)
- msg_fatal("host %s: conversion error for address family %d: %m",
- host, ((struct sockaddr *) (res0->ai_addr))->sa_family);
- addr_list = dns_rr_append(addr_list, addr);
- freeaddrinfo(res0);
- return (addr_list);
- }
-
- /*
- * Use native name service when DNS is disabled.
- */
-#define RETRY_AI_ERROR(e) \
- ((e) == EAI_AGAIN || (e) == EAI_MEMORY || (e) == EAI_SYSTEM)
-#ifdef EAI_NODATA
-#define DSN_NOHOST(e) \
- ((e) == EAI_AGAIN || (e) == EAI_NODATA || (e) == EAI_NONAME)
-#else
-#define DSN_NOHOST(e) \
- ((e) == EAI_AGAIN || (e) == EAI_NONAME)
-#endif
-
- if (var_disable_dns) {
- if ((aierr = hostname_to_sockaddr(host, (char *) 0, 0, &res0)) != 0) {
- lmtp_dsn_update(why, DSN_BY_LOCAL_MTA,
- DSN_NOHOST(aierr) ? "4.4.4" : "4.3.0",
- 450, "450 Host not found",
- "unable to look up host %s: %s",
- host, MAI_STRERROR(aierr));
- lmtp_errno = (RETRY_AI_ERROR(aierr) ? LMTP_RETRY : LMTP_FAIL);
- } else {
- for (found = 0, res = res0; res != 0; res = res->ai_next) {
- if (strchr((char *) proto_info->sa_family_list, res->ai_family) == 0) {
- msg_info("skipping address family %d for host %s",
- res->ai_family, host);
- continue;
- }
- found++;
- if ((addr = dns_sa_to_rr(host, pref, res->ai_addr)) == 0)
- msg_fatal("host %s: conversion error for address family %d: %m",
- host, ((struct sockaddr *) (res0->ai_addr))->sa_family);
- addr_list = dns_rr_append(addr_list, addr);
- }
- freeaddrinfo(res0);
- if (found == 0) {
- lmtp_dsn_update(why, DSN_BY_LOCAL_MTA,
- "5.4.4", 550, "550 Host not found",
- "%s: host not found", host);
- lmtp_errno = LMTP_FAIL;
- }
- return (addr_list);
- }
- }
-
- /*
- * Append the addresses for this host to the address list.
- */
- switch (dns_lookup_v(host, RES_DEFNAMES, &addr, (VSTRING *) 0, why->reason,
- DNS_REQ_FLAG_NONE, proto_info->dns_atype_list)) {
- case DNS_OK:
- for (rr = addr; rr; rr = rr->next)
- rr->pref = pref;
- addr_list = dns_rr_append(addr_list, addr);
- break;
- default:
- lmtp_dsn_formal(why, DSN_BY_LOCAL_MTA,
- "4.4.3", 450, "450 Host not found");
- lmtp_errno = LMTP_RETRY;
- break;
- case DNS_FAIL:
- lmtp_dsn_formal(why, DSN_BY_LOCAL_MTA,
- "5.4.3", 550, "550 Name server failure");
- lmtp_errno = LMTP_FAIL;
- break;
- case DNS_INVAL:
- case DNS_NOTFOUND:
- lmtp_dsn_formal(why, DSN_BY_LOCAL_MTA,
- "5.4.4", 550, "550 Host not found");
- lmtp_errno = LMTP_FAIL;
- break;
- }
- return (addr_list);
-}
-
-/* lmtp_host_addr - direct host lookup */
-
-DNS_RR *lmtp_host_addr(char *host, DSN_BUF *why)
-{
- DNS_RR *addr_list;
-
- /*
- * If the host is specified by numerical address, just convert the
- * address to internal form. Otherwise, the host is specified by name.
- */
-#define PREF0 0
- addr_list = lmtp_addr_one((DNS_RR *) 0, host, PREF0, why);
- if (msg_verbose)
- lmtp_print_addr(host, addr_list);
- return (addr_list);
-}
+++ /dev/null
-/*++
-/* NAME
-/* lmtp_addr 3h
-/* SUMMARY
-/* LMTP server address lookup
-/* SYNOPSIS
-/* #include "lmtp_addr.h"
-/* DESCRIPTION
-/* .nf
-
- /*
- * Global library.
- */
-#include <dsn_buf.h>
-
- /*
- * DNS library.
- */
-#include <dns.h>
-
- /*
- * Internal interfaces.
- */
-extern DNS_RR *lmtp_host_addr(char *, DSN_BUF *);
-
-/* 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
-/*
-/* Alterations for LMTP by:
-/* Philip A. Prindeville
-/* Mirapoint, Inc.
-/* USA.
-/*
-/* Additional work on LMTP by:
-/* Amos Gouaux
-/* University of Texas at Dallas
-/* P.O. Box 830688, MC34
-/* Richardson, TX 75083, USA
-/*--*/
+++ /dev/null
-/*++
-/* NAME
-/* lmtp_chat 3
-/* SUMMARY
-/* LMTP client request/response support
-/* SYNOPSIS
-/* #include "lmtp.h"
-/*
-/* typedef struct {
-/* .in +4
-/* int code;
-/* char *dsn;
-/* char *str;
-/* VSTRING *dsn_buf;
-/* VSTRING *str_buf;
-/* .in -4
-/* } LMTP_RESP;
-/*
-/* void lmtp_chat_cmd(state, format, ...)
-/* LMTP_STATE *state;
-/* char *format;
-/*
-/* LMTP_RESP *lmtp_chat_resp(state)
-/* LMTP_STATE *state;
-/*
-/* void lmtp_chat_notify(state)
-/* LMTP_STATE *state;
-/*
-/* void lmtp_chat_reset(state)
-/* LMTP_STATE *state;
-/* DESCRIPTION
-/* This module implements LMTP client support for request/reply
-/* conversations, and maintains a limited LMTP transaction log.
-/*
-/* lmtp_chat_cmd() formats a command and sends it to an LMTP server.
-/* Optionally, the command is logged.
-/*
-/* lmtp_chat_resp() reads one LMTP server response. It separates the
-/* numerical status code from the text, and concatenates multi-line
-/* responses to one string, using a newline as separator.
-/* Optionally, the server response is logged.
-/*
-/* lmtp_chat_notify() sends a copy of the LMTP transaction log
-/* to the postmaster for review. The postmaster notice is sent only
-/* when delivery is possible immediately. It is an error to call
-/* lmtp_chat_notify() when no LMTP transaction log exists.
-/*
-/* lmtp_chat_reset() resets the transaction log. This is
-/* typically done at the beginning or end of an LMTP session,
-/* or within a session to discard non-error information.
-/* In addition, lmtp_chat_reset() resets the per-session error
-/* status bits and flags.
-/*
-/* lmtp_chat_fake() constructs a synthetic LMTP server response
-/* from its arguments.
-/* DIAGNOSTICS
-/* Fatal errors: memory allocation problem, server response exceeds
-/* configurable limit.
-/* All other exceptions are handled by long jumps (see smtp_stream(3)).
-/* SEE ALSO
-/* smtp_stream(3) LMTP session I/O support
-/* msg(3) generic logging interface
-/* 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
-/*
-/* Alterations for LMTP by:
-/* Philip A. Prindeville
-/* Mirapoint, Inc.
-/* USA.
-/*
-/* Additional work on LMTP by:
-/* Amos Gouaux
-/* University of Texas at Dallas
-/* P.O. Box 830688, MC34
-/* Richardson, TX 75083, USA
-/*--*/
-
-/* System library. */
-
-#include <sys_defs.h>
-#include <stdlib.h> /* 44BSD stdarg.h uses abort() */
-#include <stdarg.h>
-#include <ctype.h>
-#include <stdlib.h>
-#include <setjmp.h>
-#include <string.h>
-
-/* Utility library. */
-
-#include <msg.h>
-#include <vstring.h>
-#include <vstream.h>
-#include <argv.h>
-#include <stringops.h>
-#include <line_wrap.h>
-#include <mymalloc.h>
-
-/* Global library. */
-
-#include <recipient_list.h>
-#include <deliver_request.h>
-#include <smtp_stream.h>
-#include <mail_params.h>
-#include <mail_addr.h>
-#include <post_mail.h>
-#include <mail_error.h>
-#include <dsn_util.h>
-
-/* Application-specific. */
-
-#include "lmtp.h"
-
-#define LEN VSTRING_LEN
-
-/* lmtp_chat_reset - reset LMTP transaction log */
-
-void lmtp_chat_reset(LMTP_STATE *state)
-{
- if (state->history) {
- argv_free(state->history);
- state->history = 0;
- }
- /* What's status without history? */
- state->status = 0;
- state->error_mask = 0;
-}
-
-/* lmtp_chat_append - append record to LMTP transaction log */
-
-static void lmtp_chat_append(LMTP_STATE *state, char *direction, char *data)
-{
- char *line;
-
- if (state->history == 0)
- state->history = argv_alloc(10);
- line = concatenate(direction, data, (char *) 0);
- argv_add(state->history, line, (char *) 0);
- myfree(line);
-}
-
-/* lmtp_chat_cmd - send an LMTP command */
-
-void lmtp_chat_cmd(LMTP_STATE *state, char *fmt,...)
-{
- LMTP_SESSION *session = state->session;
- va_list ap;
-
- /*
- * Format the command, and update the transaction log.
- */
- va_start(ap, fmt);
- vstring_vsprintf(state->buffer, fmt, ap);
- va_end(ap);
- lmtp_chat_append(state, "Out: ", STR(state->buffer));
-
- /*
- * Optionally log the command first, so we can see in the log what the
- * program is trying to do.
- */
- if (msg_verbose)
- msg_info("> %s: %s", session->namaddr, STR(state->buffer));
-
- /*
- * Send the command to the LMTP server.
- */
- smtp_fputs(STR(state->buffer), LEN(state->buffer), session->stream);
-}
-
-/* lmtp_chat_resp - read and process LMTP server response */
-
-LMTP_RESP *lmtp_chat_resp(LMTP_STATE *state)
-{
- static LMTP_RESP rdata;
- LMTP_SESSION *session = state->session;
- char *cp;
- int last_char;
- int three_digs = 0;
- size_t len;
-
- /*
- * Initialize the response data buffer.
- */
- if (rdata.str_buf == 0) {
- rdata.dsn_buf = vstring_alloc(10);
- rdata.str_buf = vstring_alloc(100);
- }
-
- /*
- * Censor out non-printable characters in server responses. Concatenate
- * multi-line server responses. Separate the status code from the text.
- * Leave further parsing up to the application.
- */
- VSTRING_RESET(rdata.str_buf);
- for (;;) {
- last_char = smtp_get(state->buffer, session->stream, var_line_limit);
- printable(STR(state->buffer), '?');
- if (last_char != '\n')
- msg_warn("%s: response longer than %d: %.30s...",
- session->namaddr, var_line_limit, STR(state->buffer));
- if (msg_verbose)
- msg_info("< %s: %s", session->namaddr, STR(state->buffer));
-
- /*
- * Defend against a denial of service attack by limiting the amount
- * of multi-line text that we are willing to store.
- */
- if (LEN(rdata.str_buf) < var_line_limit) {
- if (VSTRING_LEN(rdata.str_buf))
- VSTRING_ADDCH(rdata.str_buf, '\n');
- vstring_strcat(rdata.str_buf, STR(state->buffer));
- lmtp_chat_append(state, "In: ", STR(state->buffer));
- }
-
- /*
- * Parse into code and text. Ignore unrecognized garbage. This means
- * that any character except space (or end of line) will have the
- * same effect as the '-' line continuation character.
- */
- for (cp = STR(state->buffer); *cp && ISDIGIT(*cp); cp++)
- /* void */ ;
- if ((three_digs = (cp - STR(state->buffer) == 3)) != 0) {
- if (*cp == '-')
- continue;
- if (*cp == ' ' || *cp == 0)
- break;
- }
-
- /*
- * XXX Do not ignore garbage when ESMTP command pipelining is turned
- * on. After sending ".<CR><LF>QUIT<CR><LF>", Postfix might recognize
- * the server's 2XX QUIT reply as a 2XX END-OF-DATA reply after
- * garbage, causing mail to be lost. Instead, make a long jump so
- * that all recipients of multi-recipient mail get consistent
- * treatment.
- */
- state->error_mask |= MAIL_ERROR_PROTOCOL;
- if (state->features & LMTP_FEATURE_PIPELINING) {
- msg_warn("non-LMTP response from %s: %.100s",
- session->namaddr, STR(state->buffer));
- vstream_longjmp(session->stream, SMTP_ERR_PROTO);
- }
- }
-
- /*
- * Extract RFC 821 reply code and RFC 2034 detail code. Use a default
- * detail code if none was given.
- *
- * Ignore out-of-protocol enhanced status codes: codes that accompany 3XX
- * replies, or codes whose initial digit is out of sync with the reply
- * code.
- *
- * XXX Potential stability problem. In order to save memory, the queue
- * manager stores DSNs in a compact manner:
- *
- * - empty strings are represented by null pointers,
- *
- * - the status and reason are required to be non-empty.
- *
- * Other Postfix daemons inherit this behavior, because they use the same
- * DSN support code. This means that everything that receives DSNs must
- * cope with null pointers for the optional DSN attributes, and that
- * everything that provides DSN information must provide a non-empty
- * status and reason, otherwise the DSN support code wil panic().
- *
- * Thus, when the remote server sends a malformed reply (or 3XX out of
- * context) we should not panic() in DSN_COPY() just because we don't
- * have a status. Robustness suggests that we supply a status here, and
- * that we leave it up to the down-stream code to override the
- * server-supplied status in case of an error we can't detect here, such
- * as an out-of-order server reply.
- */
- VSTRING_TERMINATE(rdata.str_buf);
- vstring_strcpy(rdata.dsn_buf, "5.5.0"); /* SAFETY! protocol error */
- if (three_digs != 0) {
- rdata.code = atoi(STR(state->buffer));
- if (strchr("245", STR(state->buffer)[0]) != 0) {
- for (cp = STR(state->buffer) + 4; *cp == ' '; cp++)
- /* void */ ;
- if ((len = dsn_valid(cp)) > 0 && *cp == *STR(state->buffer)) {
- vstring_strncpy(rdata.dsn_buf, cp, len);
- } else {
- vstring_strcpy(rdata.dsn_buf, "0.0.0");
- STR(rdata.dsn_buf)[0] = STR(state->buffer)[0];
- }
- }
- } else {
- rdata.code = 0;
- }
- rdata.dsn = STR(rdata.dsn_buf);
- rdata.str = STR(rdata.str_buf);
- return (&rdata);
-}
-
-/* print_line - line_wrap callback */
-
-static void print_line(const char *str, int len, int indent, char *context)
-{
- VSTREAM *notice = (VSTREAM *) context;
-
- post_mail_fprintf(notice, " %*s%.*s", indent, "", len, str);
-}
-
-/* lmtp_chat_notify - notify postmaster */
-
-void lmtp_chat_notify(LMTP_STATE *state)
-{
- char *myname = "lmtp_chat_notify";
- LMTP_SESSION *session = state->session;
- VSTREAM *notice;
- char **cpp;
-
- /*
- * Sanity checks.
- */
- if (state->history == 0)
- msg_panic("%s: no conversation history", myname);
- if (msg_verbose)
- msg_info("%s: notify postmaster", myname);
-
- /*
- * Construct a message for the postmaster, explaining what this is all
- * about. This is junk mail: don't send it when the mail posting service
- * is unavailable, and use the double bounce sender address, to prevent
- * mail bounce wars. Always prepend one space to message content that we
- * generate from untrusted data.
- */
-#define NULL_TRACE_FLAGS 0
-#define LENGTH 78
-#define INDENT 4
-
- notice = post_mail_fopen_nowait(mail_addr_double_bounce(),
- var_error_rcpt,
- CLEANUP_FLAG_MASK_INTERNAL,
- NULL_TRACE_FLAGS);
- if (notice == 0) {
- msg_warn("postmaster notify: %m");
- return;
- }
- post_mail_fprintf(notice, "From: %s (Mail Delivery System)",
- mail_addr_mail_daemon());
- post_mail_fprintf(notice, "To: %s (Postmaster)", var_error_rcpt);
- post_mail_fprintf(notice, "Subject: %s LMTP client: errors from %s",
- var_mail_name, session->namaddr);
- post_mail_fputs(notice, "");
- post_mail_fprintf(notice, "Unexpected response from %s.", session->namaddr);
- post_mail_fputs(notice, "");
- post_mail_fputs(notice, "Transcript of session follows.");
- post_mail_fputs(notice, "");
- argv_terminate(state->history);
- for (cpp = state->history->argv; *cpp; cpp++)
- line_wrap(printable(*cpp, '?'), LENGTH, INDENT, print_line,
- (char *) notice);
- (void) post_mail_fclose(notice);
-}
+++ /dev/null
-/*++
-/* NAME
-/* lmtp_connect 3
-/* SUMMARY
-/* connect to LMTP server
-/* SYNOPSIS
-/* #include "lmtp.h"
-/*
-/* LMTP_SESSION *lmtp_connect(destination, why)
-/* char *destination;
-/* DSN_BUF *why;
-/* DESCRIPTION
-/* This module implements LMTP connection management.
-/*
-/* lmtp_connect() attempts to establish an LMTP session.
-/*
-/* The destination is one of the following:
-/* .IP unix:address
-/* Connect to a UNIX-domain service. The destination is a pathname.
-/* Beware: UNIX-domain sockets are flakey on Solaris, at last up to
-/* and including Solaris 7.0.
-/* .IP inet:address
-/* Connect to an IPV4 service.
-/* The destination is either a host name or a numeric address.
-/* Symbolic or numeric service port information may be appended,
-/* separated by a colon (":").
-/*
-/* Numerical address information should always be quoted with `[]'.
-/* .PP
-/* When no transport is specified, "inet" is assumed.
-/* DIAGNOSTICS
-/* This routine either returns an LMTP_SESSION pointer, or
-/* returns a null pointer and set the \fIlmtp_errno\fR
-/* global variable accordingly:
-/* .IP LMTP_RETRY
-/* The connection attempt failed, but should be retried later.
-/* .IP LMTP_FAIL
-/* The connection attempt failed.
-/* .PP
-/* In addition, a description of the error is made available
-/* via the \fIwhy\fR argument.
-/* SEE ALSO
-/* lmtp_proto(3) LMTP client protocol
-/* 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
-/*
-/* Alterations for LMTP by:
-/* Philip A. Prindeville
-/* Mirapoint, Inc.
-/* USA.
-/*
-/* Additional work on LMTP by:
-/* Amos Gouaux
-/* University of Texas at Dallas
-/* P.O. Box 830688, MC34
-/* Richardson, TX 75083, USA
-/*--*/
-
-/* System library. */
-
-#include <sys_defs.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <errno.h>
-#include <netdb.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <ctype.h>
-
-#ifdef STRCASECMP_IN_STRINGS_H
-#include <strings.h>
-#endif
-
-/* Utility library. */
-
-#include <msg.h>
-#include <vstream.h>
-#include <vstring.h>
-#include <split_at.h>
-#include <mymalloc.h>
-#include <iostuff.h>
-#include <timed_connect.h>
-#include <stringops.h>
-#include <host_port.h>
-#include <sane_connect.h>
-#include <inet_addr_list.h>
-#include <myaddrinfo.h>
-#include <sock_addr.h>
-
-/* Global library. */
-
-#include <mail_params.h>
-#include <mail_proto.h>
-#include <own_inet_addr.h>
-#include <dsn_buf.h>
-
-/* DNS library. */
-
-#include <dns.h>
-
-/* Application-specific. */
-
-#include "lmtp.h"
-#include "lmtp_addr.h"
-
- /*
- * Forward declaration.
- */
-static LMTP_SESSION *lmtp_connect_sock(int, struct sockaddr *, int,
- const char *, const char *,
- const char *, DSN_BUF *);
-
-/* lmtp_connect_unix - connect to UNIX-domain address */
-
-static LMTP_SESSION *lmtp_connect_unix(const char *addr,
- const char *destination, DSN_BUF *why)
-{
-#undef sun
- char *myname = "lmtp_connect_unix";
- struct sockaddr_un sun;
- int len = strlen(addr);
- int sock;
-
- /*
- * Sanity checks.
- */
- if (len >= (int) sizeof(sun.sun_path)) {
- msg_warn("unix-domain name too long: %s", addr);
- lmtp_dsn_update(why, DSN_BY_LOCAL_MTA, "4.3.5",
- 450, "450 Mail server configuration error",
- "Server configuration error");
- lmtp_errno = LMTP_RETRY;
- return (0);
- }
-
- /*
- * Initialize.
- */
- memset((char *) &sun, 0, sizeof(sun));
- sun.sun_family = AF_UNIX;
-#ifdef HAS_SUN_LEN
- sun.sun_len = len + 1;
-#endif
- memcpy(sun.sun_path, addr, len + 1);
-
- /*
- * Create a client socket.
- */
- if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
- msg_fatal("%s: socket: %m", myname);
-
- /*
- * Connect to the LMTP server.
- */
- if (msg_verbose)
- msg_info("%s: trying: %s...", myname, addr);
-
- return (lmtp_connect_sock(sock, (struct sockaddr *) & sun, sizeof(sun),
- addr, addr, destination, why));
-}
-
-/* lmtp_connect_addr - connect to explicit address */
-
-static LMTP_SESSION *lmtp_connect_addr(DNS_RR *addr, unsigned port,
- const char *destination, DSN_BUF *why)
-{
- char *myname = "lmtp_connect_addr";
- struct sockaddr_storage ss;
- struct sockaddr *sa = SOCK_ADDR_PTR(&ss);
- SOCKADDR_SIZE salen = sizeof(ss);
- MAI_HOSTADDR_STR hostaddr;
- int sock;
-
- /*
- * Sanity checks.
- */
- if (dns_rr_to_sa(addr, port, sa, &salen) != 0) {
- msg_warn("%s: skip address type %s: %m",
- myname, dns_strtype(addr->type));
- lmtp_dsn_update(why, DSN_BY_LOCAL_MTA, "4.3.0",
- 450, "450 Network address conversion error",
- "network address conversion failed");
- lmtp_errno = LMTP_RETRY;
- return (0);
- }
-
- /*
- * Initialize.
- */
- if ((sock = socket(sa->sa_family, SOCK_STREAM, 0)) < 0)
- msg_fatal("%s: socket: %m", myname);
-
- /*
- * Connect to the LMTP server.
- */
- SOCKADDR_TO_HOSTADDR(sa, salen, &hostaddr, (MAI_SERVPORT_STR *) 0, 0);
- if (msg_verbose)
- msg_info("%s: trying: %s[%s] port %d...",
- myname, addr->name, hostaddr.buf, ntohs(port));
-
- return (lmtp_connect_sock(sock, sa, salen,
- addr->name, hostaddr.buf, destination, why));
-}
-
-/* lmtp_connect_sock - connect a socket over some transport */
-
-static LMTP_SESSION *lmtp_connect_sock(int sock, struct sockaddr * sa, int len,
- const char *name, const char *addr,
- const char *destination,
- DSN_BUF *why)
-{
- int conn_stat;
- int saved_errno;
- VSTREAM *stream;
- int ch;
-
- if (var_lmtp_conn_tmout > 0) {
- non_blocking(sock, NON_BLOCKING);
- conn_stat = timed_connect(sock, sa, len, var_lmtp_conn_tmout);
- saved_errno = errno;
- non_blocking(sock, BLOCKING);
- errno = saved_errno;
- } else {
- conn_stat = sane_connect(sock, sa, len);
- }
- if (conn_stat < 0) {
- lmtp_dsn_update(why, DSN_BY_LOCAL_MTA,
- "4.4.1", 420, "420 Unable to connect to server",
- "connect to %s[%s]: %m", name, addr);
- lmtp_errno = LMTP_RETRY;
- close(sock);
- return (0);
- }
-
- /*
- * Skip this host if it takes no action within some time limit.
- */
- if (read_wait(sock, var_lmtp_lhlo_tmout) < 0) {
- lmtp_dsn_update(why, DSN_BY_LOCAL_MTA,
- "4.4.2", 426, "426 No response from server",
- "connect to %s[%s]: read timeout", name, addr);
- lmtp_errno = LMTP_RETRY;
- close(sock);
- return (0);
- }
-
- /*
- * Skip this host if it disconnects without talking to us.
- */
- stream = vstream_fdopen(sock, O_RDWR);
- if ((ch = VSTREAM_GETC(stream)) == VSTREAM_EOF) {
- lmtp_dsn_update(why, DSN_BY_LOCAL_MTA,
- "4.4.0", 421, "421 Lost connection",
- "connect to %s[%s]: server dropped connection without sending the initial greeting",
- name, addr);
- lmtp_errno = LMTP_RETRY;
- vstream_fclose(stream);
- return (0);
- }
- vstream_ungetc(stream, ch);
-
- /*
- * Skip this host if it sends a 4xx or 5xx greeting.
- */
- if (ch == '4' || ch == '5') {
- lmtp_dsn_update(why, DSN_BY_LOCAL_MTA,
- "4.3.0", 420, "420 Connection rejected by server",
- "connect to %s[%s]: server refused mail service",
- name, addr);
- lmtp_errno = LMTP_RETRY;
- vstream_fclose(stream);
- return (0);
- }
- return (lmtp_session_alloc(stream, name, addr, destination));
-}
-
-/* lmtp_connect_host - direct connection to host */
-
-static LMTP_SESSION *lmtp_connect_host(char *host, unsigned port,
- const char *destination, DSN_BUF *why)
-{
- LMTP_SESSION *session = 0;
- DNS_RR *addr_list;
- DNS_RR *addr;
-
- /*
- * Try each address in the specified order until we find one that works.
- * The addresses belong to the same A record, so we have no information
- * on what address is "best".
- */
- addr_list = lmtp_host_addr(host, why);
- for (addr = addr_list; addr; addr = addr->next) {
- if ((session = lmtp_connect_addr(addr, port, destination, why)) != 0) {
- break;
- }
- }
- dns_rr_free(addr_list);
- return (session);
-}
-
-/* lmtp_parse_destination - parse destination */
-
-static char *lmtp_parse_destination(const char *destination, char *def_service,
- char **hostp, unsigned *portp)
-{
- char *myname = "lmtp_parse_destination";
- char *buf = mystrdup(destination);
- char *service;
- struct servent *sp;
- char *protocol = "tcp"; /* XXX configurable? */
- unsigned port;
- const char *err;
-
- if (msg_verbose)
- msg_info("%s: %s %s", myname, destination, def_service);
-
- /*
- * Parse the host/port information. We're working with a copy of the
- * destination argument so the parsing can be destructive.
- */
- if ((err = host_port(buf, hostp, (char *) 0, &service, def_service)) != 0)
- msg_fatal("%s in LMTP server description: %s", err, destination);
-
- /*
- * Convert service to port number, network byte order. Since most folks
- * aren't going to have lmtp defined as a service, use a default value
- * instead of just blowing up.
- */
- if (alldig(service)) {
- if ((port = atoi(service)) >= 65536)
- msg_fatal("bad numeric port in destination: %s", destination);
- *portp = htons(port);
- } else if ((sp = getservbyname(service, protocol)) != 0)
- *portp = sp->s_port;
- else
- *portp = htons(var_lmtp_tcp_port);
- return (buf);
-}
-
-/* lmtp_connect - establish LMTP connection */
-
-LMTP_SESSION *lmtp_connect(const char *destination, DSN_BUF *why)
-{
- char *myname = "lmtp_connect";
- LMTP_SESSION *session;
- char *dest_buf;
- char *host;
- unsigned port;
- char *def_service = "lmtp"; /* XXX configurable? */
-
- /*
- * Connect to the LMTP server.
- *
- * XXX Ad-hoc transport parsing and connection management. Some or all
- * should be moved away to a reusable library routine so that every
- * program benefits from it.
- *
- * XXX Should transform destination into canonical form (unix:/path or
- * inet:host:port before entering it into the connection cache. See also
- * the connection cache lookup code in lmtp.c.
- */
- if (strncmp(destination, "unix:", 5) == 0)
- return (lmtp_connect_unix(destination + 5, destination, why));
- if (strncmp(destination, "inet:", 5) == 0)
- dest_buf = lmtp_parse_destination(destination + 5, def_service,
- &host, &port);
- else
- dest_buf = lmtp_parse_destination(destination, def_service,
- &host, &port);
- if (msg_verbose)
- msg_info("%s: connecting to %s port %d", myname, host, ntohs(port));
- session = lmtp_connect_host(host, port, destination, why);
- myfree(dest_buf);
- return (session);
-}
+++ /dev/null
-/*++
-/* NAME
-/* lmtp_dsn 3
-/* SUMMARY
-/* application-specific wrappers
-/* SYNOPSIS
-/* #include <smtp.h>
-/*
-/* void lmtp_dsn_update(dsb, mta_name, status, code, reply,
-/* reason_fmt, ...)
-/* DSN_BUF *dsb;
-/* const char *mta_name;
-/* const char *status;
-/* const char *reply;
-/* const char *reason_fmt;
-/*
-/* void vlmtp_dsn_update(dsb, mta_name, status, code, reply,
-/* reason_fmt, ap)
-/* DSN_BUF *dsb;
-/* const char *mta_name;
-/* const char *status;
-/* const char *reply;
-/* const char *reason_fmt;
-/* va_list ap;
-/*
-/* void lmtp_dsn_formal(dsb, mta_name, status, code, reply)
-/* DSN_BUF *dsb;
-/* const char *mta_name;
-/* const char *status;
-/* const char *reply;
-/*
-/* DSN *LMTP_DSN_ASSIGN(dsn, mta_name, status, action, reply, reason)
-/* DSN *dsn;
-/* const char *mta_name;
-/* const char *status;
-/* const char *action;
-/* const char *reply;
-/* const char *reason;
-/* DESCRIPTION
-/* This module implements an application-specific wrapper for
-/* the dsbuf(3) delivery status information module. This
-/* eliminates clutter from the code.
-/*
-/* lmtp_dsn_update() updates the formal and informal delivery
-/* status attributes.
-/*
-/* vlmtp_dsn_update() implements an alternative interface.
-/*
-/* lmtp_dsn_formal() updates the formal delivery status
-/* attributes and leaves the informal reason attribute unmodified.
-/*
-/* LMTP_DSN_ASSIGN() is a wrapper around the DSN_ASSIGN macro.
-/*
-/* Arguments:
-/* .IP dsb
-/* Delivery status information. See dsbuf(3).
-/* .IP mta_name
-/* The name of the MTA that issued the response given with the
-/* status and reply arguments. Specify DSN_BY_LOCAL_MTA for
-/* status and "reply" information that was issued by the local
-/* MTA.
-/* .IP status
-/* RFC 3463 status code.
-/* .IP code
-/* LMTP reply code.
-/* .IP reply
-/* LMTP reply code followed by text. The bounce(8) server
-/* replaces non-printable characters by '?', so it is a good
-/* idea to replace embedded newline characters by spaces.
-/* .IP reason_fmt
-/* Format string for the informal reason attribute.
-/* .IP DIAGNOSTICS
-/* Fatal: out of memory. Panic: invalid arguments.
-/* BUGS
-/* It seems wasteful to copy mostly-constant information into
-/* VSTRING buffers, but it's unavoidable if one needs to
-/* delegate work to a subordinate routine, and report the error
-/* after the subordinate has terminated.
-/* 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 <sys_defs.h>
-#include <stdlib.h> /* 44BSD stdarg.h uses abort() */
-#include <stdarg.h>
-
-/* Utility library. */
-
-#include <vstring.h>
-
-/* Global library. */
-
-#include <dsn_buf.h>
-
-/* Application-specific. */
-
-#include <lmtp.h>
-
-/* lmtp_dsn_update - update formal and informal DSN attributes */
-
-void lmtp_dsn_update(DSN_BUF *why, const char *mta_name,
- const char *status, int code,
- const char *reply,
- const char *format,...)
-{
- va_list ap;
-
- va_start(ap, format);
- vlmtp_dsn_update(why, mta_name, status, code, reply, format, ap);
- va_end(ap);
-}
-
-/* vlmtp_dsn_update - update formal and informal DSN attributes */
-
-void vlmtp_dsn_update(DSN_BUF *why, const char *mta_name,
- const char *status, int code,
- const char *reply,
- const char *format, va_list ap)
-{
- dsb_formal(why, status, DSB_DEF_ACTION,
- mta_name ? DSB_MTYPE_DNS : DSB_MTYPE_NONE,
- mta_name, DSB_DTYPE_SMTP, code, reply);
- vstring_vsprintf(why->reason, format, ap);
-}
-
-/* lmtp_dsn_formal - update formal DSN attributes only */
-
-void lmtp_dsn_formal(DSN_BUF *why, const char *mta_name,
- const char *status, int code,
- const char *reply)
-{
- dsb_formal(why, status, DSB_DEF_ACTION,
- mta_name ? DSB_MTYPE_DNS : DSB_MTYPE_NONE,
- mta_name, DSB_DTYPE_SMTP, code, reply);
-}
+++ /dev/null
-/*++
-/* NAME
-/* lmtp_proto 3
-/* SUMMARY
-/* client LMTP protocol
-/* SYNOPSIS
-/* #include "lmtp.h"
-/*
-/* int lmtp_lhlo(state)
-/* LMTP_STATE *state;
-/*
-/* int lmtp_xfer(state)
-/* LMTP_STATE *state;
-/*
-/* int lmtp_rset(state)
-/* LMTP_STATE *state;
-/*
-/* int lmtp_quit(state)
-/* LMTP_STATE *state;
-/* DESCRIPTION
-/* This module implements the client side of the LMTP protocol.
-/*
-/* lmtp_lhlo() performs the initial handshake with the LMTP server.
-/*
-/* lmtp_xfer() sends message envelope information followed by the
-/* message data and sends QUIT when connection cacheing is disabled.
-/* These operations are combined in one function, in order to implement
-/* LMTP pipelining.
-/* Recipients are marked as "done" in the mail queue file when
-/* bounced or delivered. The message delivery status is updated
-/* accordingly.
-/*
-/* lmtp_rset() sends a lone RSET command and waits for the response.
-/* In case of a negative reply it sets the CANT_RSET_THIS_SESSION flag.
-/*
-/* lmtp_quit() sends a lone QUIT command and waits for the response
-/* only if waiting for QUIT replies is enabled.
-/* DIAGNOSTICS
-/* lmtp_lhlo(), lmtp_xfer(), lmtp_rset() and lmtp_quit() return 0 in
-/* case of success, -1 in case of failure. For lmtp_xfer(), lmtp_rset()
-/* and lmtp_quit(), success means the ability to perform an LMTP
-/* conversation, not necessarily OK replies from the server.
-/*
-/* Warnings: corrupt message file. A corrupt message is marked
-/* as "corrupt" by changing its queue file permissions.
-/* SEE ALSO
-/* lmtp(3h) internal data structures
-/* lmtp_chat(3) query/reply LMTP support
-/* lmtp_trouble(3) error handlers
-/* 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
-/*
-/* Pipelining code in cooperation with:
-/* Jon Ribbens
-/* Oaktree Internet Solutions Ltd.,
-/* Internet House,
-/* Canal Basin,
-/* Coventry,
-/* CV1 4LY, United Kingdom.
-/*
-/* Alterations for LMTP by:
-/* Philip A. Prindeville
-/* Mirapoint, Inc.
-/* USA.
-/*
-/* Additional work on LMTP by:
-/* Amos Gouaux
-/* University of Texas at Dallas
-/* P.O. Box 830688, MC34
-/* Richardson, TX 75083, USA
-/*--*/
-
-/* System library. */
-
-#include <sys_defs.h>
-#include <sys/stat.h>
-#include <sys/socket.h> /* shutdown(2) */
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-#include <stdlib.h> /* 44BSD stdarg.h uses abort() */
-#include <stdarg.h>
-#include <time.h>
-
-#ifdef STRCASECMP_IN_STRINGS_H
-#include <strings.h>
-#endif
-
-/* Utility library. */
-
-#include <msg.h>
-#include <vstring.h>
-#include <vstream.h>
-#include <vstring_vstream.h>
-#include <stringops.h>
-#include <mymalloc.h>
-#include <name_code.h>
-
-/* Global library. */
-
-#include <mail_params.h>
-#include <smtp_stream.h>
-#include <mail_queue.h>
-#include <recipient_list.h>
-#include <deliver_request.h>
-#include <deliver_completed.h>
-#include <defer.h>
-#include <bounce.h>
-#include <sent.h>
-#include <record.h>
-#include <rec_type.h>
-#include <off_cvt.h>
-#include <mark_corrupt.h>
-#include <quote_821_local.h>
-#include <quote_822_local.h>
-#include <mail_proto.h>
-#include <dsn_mask.h>
-#include <xtext.h>
-
-/* Application-specific. */
-
-#include "lmtp.h"
-#include "lmtp_sasl.h"
-
- /*
- * Sender and receiver state. A session does not necessarily go through a
- * linear progression, but states are guaranteed to not jump backwards.
- * Normal sessions go from MAIL->RCPT->DATA->DOT->QUIT->LAST. The states
- * MAIL, RCPT, and DATA may also be followed by ABORT->QUIT->LAST.
- *
- * When connection cacheing is turned on, the transition diagram changes as
- * follows. Before sending mail over an existing connection, the client
- * sends a lone RSET command to find out if the connection still works. The
- * client sends QUIT only when closing a connection. The respective state
- * transitions are RSET->LAST and QUIT->LAST.
- *
- * For the sake of code reuse, the non-pipelined RSET command is sent by the
- * same code that implements command pipelining, so that we can borrow from
- * the existing code for exception handling and error reporting.
- *
- * Client states that are associated with sending mail (up to and including
- * LMTP_STATE_DOT) must have smaller numerical values than the non-sending
- * states (LMTP_STATE_ABORT .. LMTP_STATE_LAST).
- */
-#define LMTP_STATE_XFORWARD_NAME_ADDR 0
-#define LMTP_STATE_XFORWARD_PROTO_HELO 1
-#define LMTP_STATE_MAIL 2
-#define LMTP_STATE_RCPT 3
-#define LMTP_STATE_DATA 4
-#define LMTP_STATE_DOT 5
-#define LMTP_STATE_ABORT 6
-#define LMTP_STATE_RSET 7
-#define LMTP_STATE_QUIT 8
-#define LMTP_STATE_LAST 9
-
-int *xfer_timeouts[LMTP_STATE_LAST] = {
- &var_lmtp_xfwd_tmout, /* name/addr */
- &var_lmtp_xfwd_tmout, /* helo/proto */
- &var_lmtp_mail_tmout,
- &var_lmtp_rcpt_tmout,
- &var_lmtp_data0_tmout,
- &var_lmtp_data2_tmout,
- &var_lmtp_rset_tmout, /* abort */
- &var_lmtp_rset_tmout, /* rset */
- &var_lmtp_quit_tmout,
-};
-
-char *xfer_states[LMTP_STATE_LAST] = {
- "sending XFORWARD name/address",
- "sending XFORWARD protocol/helo_name",
- "sending MAIL FROM",
- "sending RCPT TO",
- "sending DATA command",
- "sending end of data -- message may be sent more than once",
- "sending RSET", /* abort */
- "sending RSET", /* rset */
- "sending QUIT",
-};
-
-char *xfer_request[LMTP_STATE_LAST] = {
- "XFORWARD name/address command",
- "XFORWARD helo/protocol command",
- "MAIL FROM command",
- "RCPT TO command",
- "DATA command",
- "end of DATA command",
- "RSET command", /* abort */
- "RSET command", /* rset */
- "QUIT command",
-};
-
-static int lmtp_send_proto_helo;
-
-/* lmtp_lhlo - perform initial handshake with LMTP server */
-
-int lmtp_lhlo(LMTP_STATE *state)
-{
- LMTP_SESSION *session = state->session;
- LMTP_RESP *resp;
- int except;
- char *lines;
- char *words;
- char *word;
- static NAME_CODE xforward_features[] = {
- XFORWARD_NAME, LMTP_FEATURE_XFORWARD_NAME,
- XFORWARD_ADDR, LMTP_FEATURE_XFORWARD_ADDR,
- XFORWARD_PROTO, LMTP_FEATURE_XFORWARD_PROTO,
- XFORWARD_HELO, LMTP_FEATURE_XFORWARD_HELO,
- XFORWARD_DOMAIN, LMTP_FEATURE_XFORWARD_DOMAIN,
- 0, 0,
- };
-
- /*
- * Prepare for disaster.
- */
- smtp_timeout_setup(state->session->stream, var_lmtp_lhlo_tmout);
- if ((except = vstream_setjmp(state->session->stream)) != 0)
- return (lmtp_stream_except(state, except, "sending LHLO"));
-
- /*
- * Read and parse the server's LMTP greeting banner.
- */
- if (((resp = lmtp_chat_resp(state))->code / 100) != 2)
- return (lmtp_site_fail(state, session->host, resp,
- "host %s refused to talk to me: %s",
- session->namaddr, translit(resp->str, "\n", " ")));
-
- /*
- * Return the compliment.
- */
- lmtp_chat_cmd(state, "LHLO %s", var_myhostname);
- if ((resp = lmtp_chat_resp(state))->code / 100 != 2)
- return (lmtp_site_fail(state, session->host, resp,
- "host %s refused to talk to me: %s",
- session->namaddr,
- translit(resp->str, "\n", " ")));
-
- /*
- * Pick up some useful features offered by the LMTP server. XXX Until we
- * have a portable routine to convert from string to off_t with proper
- * overflow detection, ignore the message size limit advertised by the
- * LMTP server. Otherwise, we might do the wrong thing when the server
- * advertises a really huge message size limit.
- */
- state->features = 0;
- lines = resp->str;
- (void) mystrtok(&lines, "\n");
- while ((words = mystrtok(&lines, "\n")) != 0) {
- if (mystrtok(&words, "- ") && (word = mystrtok(&words, " \t=")) != 0) {
- if (strcasecmp(word, "8BITMIME") == 0)
- state->features |= LMTP_FEATURE_8BITMIME;
- else if (strcasecmp(word, "PIPELINING") == 0)
- state->features |= LMTP_FEATURE_PIPELINING;
- else if (strcasecmp(word, "XFORWARD") == 0)
- while ((word = mystrtok(&words, " \t")) != 0)
- state->features |= name_code(xforward_features,
- NAME_CODE_FLAG_NONE, word);
- else if (strcasecmp(word, "SIZE") == 0)
- state->features |= LMTP_FEATURE_SIZE;
-#ifdef USE_SASL_AUTH
- else if (var_lmtp_sasl_enable && strcasecmp(word, "AUTH") == 0)
- lmtp_sasl_helo_auth(state, words);
-#endif
- else if (strcasecmp(word, "DSN") == 0)
- state->features |= LMTP_FEATURE_DSN;
- }
- }
- if (msg_verbose)
- msg_info("server features: 0x%x", state->features);
-
- /*
- * We use LMTP command pipelining if the server said it supported it.
- * Since we use blocking I/O, RFC 2197 says that we should inspect the
- * TCP window size and not send more than this amount of information.
- * Unfortunately this information is not available using the sockets
- * interface. However, we *can* get the TCP send buffer size on the local
- * TCP/IP stack. We should be able to fill this buffer without being
- * blocked, and then the kernel will effectively do non-blocking I/O for
- * us by automatically writing out the contents of its send buffer while
- * we are reading in the responses. In addition to TCP buffering we have
- * to be aware of application-level buffering by the vstream module,
- * which is limited to a couple kbytes.
- *
- * XXX Apparently, the getsockopt() call causes trouble with UNIX-domain
- * sockets. Don't worry about command pipelining for local connections,
- * because they benefit little from pipelining.
- */
- if (state->features & LMTP_FEATURE_PIPELINING) {
- state->sndbufsize = 4 * 1024;
- if (msg_verbose)
- msg_info("Using LMTP PIPELINING, send buffer size is %d",
- state->sndbufsize);
- } else
- state->sndbufsize = 0;
-
-#ifdef USE_SASL_AUTH
- if (var_lmtp_sasl_enable && (state->features & LMTP_FEATURE_AUTH))
- return (lmtp_sasl_helo_login(state));
-#endif
-
- return (0);
-}
-
-/* lmtp_loop - the LMTP state machine */
-
-static int lmtp_loop(LMTP_STATE *state, NOCLOBBER int send_state,
- NOCLOBBER int recv_state)
-{
- char *myname = "lmtp_loop";
- DELIVER_REQUEST *request = state->request;
- LMTP_SESSION *session = state->session;
- LMTP_RESP *resp;
- RECIPIENT *rcpt;
- VSTRING *next_command = vstring_alloc(100);
- int *NOCLOBBER survivors = 0;
- NOCLOBBER int next_state;
- NOCLOBBER int next_rcpt;
- NOCLOBBER int send_rcpt;
- NOCLOBBER int recv_rcpt;
- NOCLOBBER int nrcpt;
- int except;
- int rec_type;
- NOCLOBBER int prev_type = 0;
- NOCLOBBER int sndbuffree;
- NOCLOBBER int mail_from_rejected;
- NOCLOBBER int recv_dot;
-
- /*
- * Macros for readability. XXX Aren't LMTP addresses supposed to be case
- * insensitive?
- */
-#define REWRITE_ADDRESS(dst, src) do { \
- if (*(src)) { \
- quote_821_local(dst, src); \
- } else { \
- vstring_strcpy(dst, src); \
- } \
- } while (0)
-
-#define RETURN(x) do { \
- vstring_free(next_command); \
- if (survivors) \
- myfree((char *) survivors); \
- return (x); \
- } while (0)
-
-#define SENDER_IS_AHEAD \
- (recv_state < send_state || recv_rcpt != send_rcpt)
-
-#define SENDER_IN_WAIT_STATE \
- (send_state == LMTP_STATE_DOT || send_state == LMTP_STATE_LAST)
-
-#define SENDING_MAIL \
- (recv_state <= LMTP_STATE_DOT)
-
-#define CANT_RSET_THIS_SESSION \
- (state->features |= LMTP_FEATURE_RSET_REJECTED)
-
- /*
- * Pipelining support requires two loops: one loop for sending and one
- * for receiving. Each loop has its own independent state. Most of the
- * time the sender can run ahead of the receiver by as much as the TCP
- * send buffer permits. There are only two places where the sender must
- * wait for status information from the receiver: once after sending DATA
- * and once after sending QUIT.
- *
- * The sender state advances until the TCP send buffer would overflow, or
- * until the sender needs status information from the receiver. At that
- * point the receiver starts processing responses. Once the receiver has
- * caught up with the sender, the sender resumes sending commands. If the
- * receiver detects a serious problem (MAIL FROM rejected, all RCPT TO
- * commands rejected, DATA rejected) it forces the sender to abort the
- * LMTP dialog with RSET.
- */
- nrcpt = 0;
- next_rcpt = send_rcpt = recv_rcpt = recv_dot = 0;
- mail_from_rejected = 0;
- sndbuffree = state->sndbufsize;
-
- while (recv_state != LMTP_STATE_LAST) {
-
- /*
- * Build the next command.
- */
- switch (send_state) {
-
- /*
- * Sanity check.
- */
- default:
- msg_panic("%s: bad sender state %d", myname, send_state);
-
- /*
- * Build the XFORWARD command. With properly sanitized
- * information, the command length stays within the 512 byte
- * command line length limit.
- */
- case LMTP_STATE_XFORWARD_NAME_ADDR:
- vstring_strcpy(next_command, XFORWARD_CMD);
- if (state->features & LMTP_FEATURE_XFORWARD_NAME)
- vstring_sprintf_append(next_command, " %s=%s",
- XFORWARD_NAME, DEL_REQ_ATTR_AVAIL(request->client_name) ?
- request->client_name : XFORWARD_UNAVAILABLE);
- if (state->features & LMTP_FEATURE_XFORWARD_ADDR)
- vstring_sprintf_append(next_command, " %s=%s",
- XFORWARD_ADDR, DEL_REQ_ATTR_AVAIL(request->client_addr) ?
- request->client_addr : XFORWARD_UNAVAILABLE);
- if (lmtp_send_proto_helo)
- next_state = LMTP_STATE_XFORWARD_PROTO_HELO;
- else
- next_state = LMTP_STATE_MAIL;
- break;
-
- case LMTP_STATE_XFORWARD_PROTO_HELO:
- vstring_strcpy(next_command, XFORWARD_CMD);
- if (state->features & LMTP_FEATURE_XFORWARD_PROTO)
- vstring_sprintf_append(next_command, " %s=%s",
- XFORWARD_PROTO, DEL_REQ_ATTR_AVAIL(request->client_proto) ?
- request->client_proto : XFORWARD_UNAVAILABLE);
- if (state->features & LMTP_FEATURE_XFORWARD_HELO)
- vstring_sprintf_append(next_command, " %s=%s",
- XFORWARD_HELO, DEL_REQ_ATTR_AVAIL(request->client_helo) ?
- request->client_helo : XFORWARD_UNAVAILABLE);
- if (state->features & LMTP_FEATURE_XFORWARD_DOMAIN)
- vstring_sprintf_append(next_command, " %s=%s", XFORWARD_DOMAIN,
- DEL_REQ_ATTR_AVAIL(request->rewrite_context) == 0 ?
- XFORWARD_UNAVAILABLE :
- strcmp(request->rewrite_context, MAIL_ATTR_RWR_LOCAL) ?
- XFORWARD_DOM_REMOTE : XFORWARD_DOM_LOCAL);
- next_state = LMTP_STATE_MAIL;
- break;
-
- /*
- * Build the MAIL FROM command.
- */
- case LMTP_STATE_MAIL:
- GETTIMEOFDAY(&request->msg_stats.conn_setup_done);
- REWRITE_ADDRESS(state->scratch, request->sender);
- vstring_sprintf(next_command, "MAIL FROM:<%s>",
- vstring_str(state->scratch));
- if (state->features & LMTP_FEATURE_SIZE) /* RFC 1652 */
- vstring_sprintf_append(next_command, " SIZE=%lu",
- request->data_size);
- if (state->features & LMTP_FEATURE_8BITMIME) {
- if (strcmp(request->encoding, MAIL_ATTR_ENC_8BIT) == 0)
- vstring_strcat(next_command, " BODY=8BITMIME");
- else if (strcmp(request->encoding, MAIL_ATTR_ENC_7BIT) == 0)
- vstring_strcat(next_command, " BODY=7BIT");
- else if (strcmp(request->encoding, MAIL_ATTR_ENC_NONE) != 0)
- msg_warn("%s: unknown content encoding: %s",
- request->queue_id, request->encoding);
- }
- if (state->features & LMTP_FEATURE_DSN) {
- if (request->dsn_envid[0]) {
- vstring_sprintf_append(next_command, " ENVID=");
- xtext_quote_append(next_command, request->dsn_envid, "+=");
- }
- if (request->dsn_ret)
- vstring_sprintf_append(next_command, " RET=%s",
- dsn_ret_str(request->dsn_ret));
- }
-
- /*
- * We authenticate the local MTA only, but not the sender.
- */
-#ifdef USE_SASL_AUTH
- if (var_lmtp_sasl_enable
- && (state->features & LMTP_FEATURE_AUTH)
- && state->sasl_passwd)
- vstring_strcat(next_command, " AUTH=<>");
-#endif
- next_state = LMTP_STATE_RCPT;
- break;
-
- /*
- * Build one RCPT TO command before we have seen the MAIL FROM
- * response.
- */
- case LMTP_STATE_RCPT:
- rcpt = request->rcpt_list.info + send_rcpt;
- REWRITE_ADDRESS(state->scratch, rcpt->address);
- vstring_sprintf(next_command, "RCPT TO:<%s>",
- vstring_str(state->scratch));
- if (state->features & LMTP_FEATURE_DSN) {
- /* XXX DSN xtext encode address value not type. */
- if (rcpt->dsn_orcpt[0]) {
- xtext_quote(state->scratch, rcpt->dsn_orcpt, "+=");
- vstring_sprintf_append(next_command, " ORCPT=%s",
- vstring_str(state->scratch));
- } else if (rcpt->orig_addr[0]) {
- quote_822_local(state->scratch, rcpt->orig_addr);
- vstring_sprintf(state->scratch2, "rfc822;%s",
- vstring_str(state->scratch));
- xtext_quote(state->scratch, vstring_str(state->scratch2), "+=");
- vstring_sprintf_append(next_command, " ORCPT=%s",
- vstring_str(state->scratch));
- }
- if (rcpt->dsn_notify)
- vstring_sprintf_append(next_command, " NOTIFY=%s",
- dsn_notify_str(rcpt->dsn_notify));
- }
- if ((next_rcpt = send_rcpt + 1) == request->rcpt_list.len)
- next_state = DEL_REQ_TRACE_ONLY(request->flags) ?
- LMTP_STATE_RSET : LMTP_STATE_DATA;
- break;
-
- /*
- * Build the DATA command before we have seen all the RCPT TO
- * responses.
- */
- case LMTP_STATE_DATA:
- vstring_strcpy(next_command, "DATA");
- next_state = LMTP_STATE_DOT;
- break;
-
- /*
- * Build the "." command before we have seen the DATA response.
- */
- case LMTP_STATE_DOT:
- vstring_strcpy(next_command, ".");
- next_state = var_lmtp_cache_conn ?
- LMTP_STATE_LAST : LMTP_STATE_QUIT;
- break;
-
- /*
- * Can't happen. The LMTP_STATE_ABORT sender state is entered by
- * the receiver and is left before the bottom of the main loop.
- */
- case LMTP_STATE_ABORT:
- msg_panic("%s: sender abort state", myname);
-
- /*
- * Build the RSET command. This is used between pipelined
- * deliveries, and to abort a trace-only delivery request.
- */
- case LMTP_STATE_RSET:
- vstring_strcpy(next_command, "RSET");
- next_state = LMTP_STATE_LAST;
- break;
-
- /*
- * Build the QUIT command.
- */
- case LMTP_STATE_QUIT:
- vstring_strcpy(next_command, "QUIT");
- next_state = LMTP_STATE_LAST;
- break;
-
- /*
- * The final sender state has no action associated with it.
- */
- case LMTP_STATE_LAST:
- VSTRING_RESET(next_command);
- break;
- }
- VSTRING_TERMINATE(next_command);
-
- /*
- * Process responses until the receiver has caught up. Vstreams
- * automatically flush buffered output when reading new data.
- *
- * Flush unsent output if command pipelining is off or if no I/O
- * happened for a while. This limits the accumulation of client-side
- * delays in pipelined sessions.
- */
- if (SENDER_IN_WAIT_STATE
- || (SENDER_IS_AHEAD
- && (VSTRING_LEN(next_command) + 2 > sndbuffree
- || time((time_t *) 0) - vstream_ftime(session->stream) > 10))) {
- while (SENDER_IS_AHEAD) {
-
- /*
- * Sanity check.
- */
- if (recv_state < LMTP_STATE_XFORWARD_NAME_ADDR
- || recv_state > LMTP_STATE_QUIT)
- msg_panic("%s: bad receiver state %d (sender state %d)",
- myname, recv_state, send_state);
-
- /*
- * Receive the next server response. Use the proper timeout,
- * and log the proper client state in case of trouble.
- */
- smtp_timeout_setup(state->session->stream,
- *xfer_timeouts[recv_state]);
- if ((except = vstream_setjmp(state->session->stream)) != 0)
- RETURN(SENDING_MAIL ? lmtp_stream_except(state, except,
- xfer_states[recv_state]) : -1);
- resp = lmtp_chat_resp(state);
-
- /*
- * Process the response.
- */
- switch (recv_state) {
-
- /*
- * Process the XFORWARD response.
- */
- case LMTP_STATE_XFORWARD_NAME_ADDR:
- if (resp->code / 100 != 2)
- msg_warn("host %s said: %s (in reply to %s)",
- session->namaddr,
- translit(resp->str, "\n", " "),
- xfer_request[LMTP_STATE_XFORWARD_NAME_ADDR]);
- if (lmtp_send_proto_helo)
- recv_state = LMTP_STATE_XFORWARD_PROTO_HELO;
- else
- recv_state = LMTP_STATE_MAIL;
- break;
-
- case LMTP_STATE_XFORWARD_PROTO_HELO:
- if (resp->code / 100 != 2)
- msg_warn("host %s said: %s (in reply to %s)",
- session->namaddr,
- translit(resp->str, "\n", " "),
- xfer_request[LMTP_STATE_XFORWARD_PROTO_HELO]);
- recv_state = LMTP_STATE_MAIL;
- break;
-
- /*
- * Process the MAIL FROM response. When the server
- * rejects the sender, set the mail_from_rejected flag so
- * that the receiver may apply a course correction.
- */
- case LMTP_STATE_MAIL:
- if (resp->code / 100 != 2) {
- lmtp_mesg_fail(state, session->host, resp,
- "host %s said: %s (in reply to %s)",
- session->namaddr,
- translit(resp->str, "\n", " "),
- xfer_request[LMTP_STATE_MAIL]);
- mail_from_rejected = 1;
- }
- recv_state = LMTP_STATE_RCPT;
- break;
-
- /*
- * Process one RCPT TO response. If MAIL FROM was
- * rejected, ignore RCPT TO responses: all recipients are
- * dead already. When all recipients are rejected the
- * receiver may apply a course correction.
- *
- * XXX 2821: Section 4.5.3.1 says that a 552 RCPT TO reply
- * must be treated as if the server replied with 452.
- * However, this causes "too much mail data" to be
- * treated as a recoverable error, which is wrong. I'll
- * stick with RFC 821.
- */
- case LMTP_STATE_RCPT:
- if (!mail_from_rejected) {
-#ifdef notdef
- if (resp->code == 552) {
- resp->code = 452;
- STR(resp->dsn_buf)[0] = '4';
- }
-#endif
- rcpt = request->rcpt_list.info + recv_rcpt;
- if (resp->code / 100 == 2) {
- if (survivors == 0)
- survivors = (int *)
- mymalloc(request->rcpt_list.len
- * sizeof(int));
- survivors[nrcpt++] = recv_rcpt;
- /* If trace-only, mark the recipient done. */
- if (DEL_REQ_TRACE_ONLY(request->flags)) {
- translit(resp->str, "\n", " ");
- lmtp_rcpt_done(state, resp, rcpt);
- }
- } else {
- lmtp_rcpt_fail(state, session->host, resp, rcpt,
- "host %s said: %s (in reply to %s)",
- session->namaddr,
- translit(resp->str, "\n", " "),
- xfer_request[LMTP_STATE_RCPT]);
- }
- }
- /* If trace-only, send RSET instead of DATA. */
- if (++recv_rcpt == request->rcpt_list.len)
- recv_state = DEL_REQ_TRACE_ONLY(request->flags) ?
- LMTP_STATE_ABORT : LMTP_STATE_DATA;
- break;
-
- /*
- * Process the DATA response. When the server rejects
- * DATA, set nrcpt to a negative value so that the
- * receiver can apply a course correction.
- */
- case LMTP_STATE_DATA:
- if (resp->code / 100 != 3) {
- if (nrcpt > 0)
- lmtp_mesg_fail(state, session->host, resp,
- "host %s said: %s (in reply to %s)",
- session->namaddr,
- translit(resp->str, "\n", " "),
- xfer_request[LMTP_STATE_DATA]);
- nrcpt = -1;
- }
- recv_state = LMTP_STATE_DOT;
- break;
-
- /*
- * Process the end of message response. Ignore the
- * response when no recipient was accepted: all
- * recipients are dead already, and the next receiver
- * state is LMTP_STATE_LAST regardless. Otherwise, if the
- * message transfer fails, bounce all remaining
- * recipients, else cross off the recipients that were
- * delivered.
- */
- case LMTP_STATE_DOT:
- GETTIMEOFDAY(&request->msg_stats.deliver_done);
- if (nrcpt > 0) {
- rcpt = request->rcpt_list.info + survivors[recv_dot];
- if (resp->code / 100 == 2) {
- if (rcpt->offset)
- lmtp_rcpt_done(state, resp, rcpt);
- } else {
- lmtp_rcpt_fail(state, session->host, resp, rcpt,
- "host %s said: %s (in reply to %s)",
- session->namaddr,
- translit(resp->str, "\n", " "),
- xfer_request[LMTP_STATE_DOT]);
- }
- }
-
- /*
- * We get one response per valid RCPT TO:
- */
- if (msg_verbose)
- msg_info("%s: recv_dot = %d", myname, recv_dot);
- if (++recv_dot >= nrcpt) {
- if (msg_verbose)
- msg_info("%s: finished . command", myname);
- recv_state = var_lmtp_skip_quit_resp || var_lmtp_cache_conn ?
- LMTP_STATE_LAST : LMTP_STATE_QUIT;
- }
- break;
-
- /*
- * Ignore the RSET response.
- */
- case LMTP_STATE_ABORT:
- recv_state = var_lmtp_skip_quit_resp || var_lmtp_cache_conn ?
- LMTP_STATE_LAST : LMTP_STATE_QUIT;
- break;
-
- /*
- * Ignore the RSET response.
- */
- case LMTP_STATE_RSET:
- if (resp->code / 100 != 2)
- CANT_RSET_THIS_SESSION;
- recv_state = LMTP_STATE_LAST;
- break;
-
- /*
- * Ignore the QUIT response.
- */
- case LMTP_STATE_QUIT:
- recv_state = LMTP_STATE_LAST;
- break;
- }
- }
-
- /*
- * At this point, the sender and receiver are fully synchronized,
- * so that the entire TCP send buffer becomes available again.
- */
- sndbuffree = state->sndbufsize;
-
- /*
- * We know the server response to every command that was sent.
- * Apply a course correction if necessary: the sender wants to
- * send RCPT TO but MAIL FROM was rejected; the sender wants to
- * send DATA but all recipients were rejected; the sender wants
- * to deliver the message but DATA was rejected.
- */
- if ((send_state == LMTP_STATE_RCPT && mail_from_rejected)
- || (send_state == LMTP_STATE_DATA && nrcpt == 0)
- || (send_state == LMTP_STATE_DOT && nrcpt < 0)) {
- send_state = recv_state = LMTP_STATE_ABORT;
- send_rcpt = recv_rcpt = 0;
- vstring_strcpy(next_command, "RSET");
- next_state = var_lmtp_cache_conn ?
- LMTP_STATE_LAST : LMTP_STATE_QUIT;
- next_rcpt = 0;
- }
- }
-
- /*
- * Make the next sender state the current sender state.
- */
- if (send_state == LMTP_STATE_LAST)
- continue;
-
- /*
- * Special case if the server accepted the DATA command. If the
- * server accepted at least one recipient send the entire message.
- * Otherwise, just send "." as per RFC 2197.
- */
- if (send_state == LMTP_STATE_DOT && nrcpt > 0) {
- smtp_timeout_setup(state->session->stream,
- var_lmtp_data1_tmout);
- if ((except = vstream_setjmp(state->session->stream)) != 0)
- RETURN(lmtp_stream_except(state, except,
- "sending message body"));
-
- if (vstream_fseek(state->src, request->data_offset, SEEK_SET) < 0)
- msg_fatal("seek queue file: %m");
-
- while ((rec_type = rec_get(state->src, state->scratch, 0)) > 0) {
- if (rec_type != REC_TYPE_NORM && rec_type != REC_TYPE_CONT)
- break;
- if (prev_type != REC_TYPE_CONT)
- if (vstring_str(state->scratch)[0] == '.')
- smtp_fputc('.', session->stream);
- if (rec_type == REC_TYPE_CONT)
- smtp_fwrite(vstring_str(state->scratch),
- VSTRING_LEN(state->scratch),
- session->stream);
- else
- smtp_fputs(vstring_str(state->scratch),
- VSTRING_LEN(state->scratch),
- session->stream);
- prev_type = rec_type;
- }
-
- if (prev_type == REC_TYPE_CONT) /* missing newline at end */
- smtp_fputs("", 0, session->stream);
- if (vstream_ferror(state->src))
- msg_fatal("queue file read error");
- if (rec_type != REC_TYPE_XTRA) {
- msg_warn("%s: bad record type: %d in message content",
- request->queue_id, rec_type);
- RETURN(mark_corrupt(state->src));
- }
- }
-
- /*
- * Copy the next command to the buffer and update the sender state.
- */
- if (sndbuffree > 0)
- sndbuffree -= VSTRING_LEN(next_command) + 2;
- lmtp_chat_cmd(state, "%s", vstring_str(next_command));
- send_state = next_state;
- send_rcpt = next_rcpt;
- }
-
- RETURN(0);
-}
-
-/* lmtp_xfer - send a batch of envelope information and the message data */
-
-int lmtp_xfer(LMTP_STATE *state)
-{
- DELIVER_REQUEST *request = state->request;
- int start;
- int send_name_addr;
-
- /*
- * Use the XFORWARD command to forward client attributes only when a
- * minimal amount of information is available.
- */
- send_name_addr =
- var_lmtp_send_xforward
- && (((state->features & LMTP_FEATURE_XFORWARD_NAME)
- && DEL_REQ_ATTR_AVAIL(request->client_name))
- || ((state->features & LMTP_FEATURE_XFORWARD_ADDR)
- && DEL_REQ_ATTR_AVAIL(request->client_addr)));
- lmtp_send_proto_helo =
- var_lmtp_send_xforward
- && (((state->features & LMTP_FEATURE_XFORWARD_PROTO)
- && DEL_REQ_ATTR_AVAIL(request->client_proto))
- || ((state->features & LMTP_FEATURE_XFORWARD_HELO)
- && DEL_REQ_ATTR_AVAIL(request->client_helo)));
- if (send_name_addr)
- start = LMTP_STATE_XFORWARD_NAME_ADDR;
- else if (lmtp_send_proto_helo)
- start = LMTP_STATE_XFORWARD_PROTO_HELO;
- else
- start = LMTP_STATE_MAIL;
- return (lmtp_loop(state, start, start));
-}
-
-/* lmtp_rset - send a lone RSET command and wait for response */
-
-int lmtp_rset(LMTP_STATE *state)
-{
- return (lmtp_loop(state, LMTP_STATE_RSET, LMTP_STATE_RSET));
-}
-
-/* lmtp_quit - send a lone QUIT command */
-
-int lmtp_quit(LMTP_STATE *state)
-{
- return (lmtp_loop(state, LMTP_STATE_QUIT, var_lmtp_skip_quit_resp ?
- LMTP_STATE_LAST : LMTP_STATE_QUIT));
-}
+++ /dev/null
-/*++
-/* NAME
-/* lmtp_rcpt 3
-/* SUMMARY
-/* application-specific recipient list operations
-/* SYNOPSIS
-/* #include <lmtp.h>
-/*
-/* void lmtp_rcpt_done(state, reply, rcpt)
-/* LMTP_STATE *state;
-/* LMTP_RESP *reply;
-/* RECIPIENT *rcpt;
-/* DESCRIPTION
-/* lmtp_rcpt_done() logs that a recipient is completed and upon
-/* success it marks the recipient as done in the queue file.
-/* DIAGNOSTICS
-/* Panic: interface violation.
-/*
-/* When a recipient can't be logged as completed, the recipient is
-/* logged as deferred instead.
-/* BUGS
-/* 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 <sys_defs.h>
-#include <stdlib.h> /* lmtp_rcpt_cleanup */
-#include <string.h>
-
-/* Utility library. */
-
-#include <msg.h>
-
-/* Global library. */
-
-#include <deliver_request.h>
-#include <deliver_completed.h>
-#include <sent.h>
-#include <dsn_mask.h>
-
-/* Application-specific. */
-
-#include <lmtp.h>
-
-/* lmtp_rcpt_done - mark recipient as done or else */
-
-void lmtp_rcpt_done(LMTP_STATE *state, LMTP_RESP *resp, RECIPIENT *rcpt)
-{
- DELIVER_REQUEST *request = state->request;
- LMTP_SESSION *session = state->session;
- DSN dsn;
- int status;
-
- /*
- * Report success and delete the recipient from the delivery request.
- * Don't send a DSN "SUCCESS" notification if the receiving site
- * announced DSN support (however unlikely that may be).
- */
- if (state->features & LMTP_FEATURE_DSN)
- rcpt->dsn_notify &= ~DSN_NOTIFY_SUCCESS;
-
- (void) LMTP_DSN_ASSIGN(&dsn, session->host, resp->dsn,
- resp->str, resp->str);
-
- status = sent(DEL_REQ_TRACE_FLAGS(request->flags),
- request->queue_id, &request->msg_stats, rcpt,
- session->namaddr, &dsn);
- if (status == 0) {
- if (request->flags & DEL_REQ_FLAG_SUCCESS)
- deliver_completed(state->src, rcpt->offset);
- rcpt->offset = 0; /* in case deferred */
- }
- state->status |= status;
-}
+++ /dev/null
-/*++
-/* NAME
-/* lmtp_sasl 3h
-/* SUMMARY
-/* Postfix SASL interface for LMTP client
-/* SYNOPSIS
-/* #include "lmtp_sasl.h"
-/* DESCRIPTION
-/* .nf
-
- /*
- * SASL protocol functions
- */
-extern void lmtp_sasl_initialize(void);
-extern void lmtp_sasl_connect(LMTP_STATE *);
-extern int lmtp_sasl_passwd_lookup(LMTP_STATE *);
-extern void lmtp_sasl_start(LMTP_STATE *, const char *, const char *);
-extern int lmtp_sasl_authenticate(LMTP_STATE *, DSN_BUF *);
-extern void lmtp_sasl_cleanup(LMTP_STATE *);
-
-extern void lmtp_sasl_helo_auth(LMTP_STATE *, const char *);
-extern int lmtp_sasl_helo_login(LMTP_STATE *);
-
-/* LICENSE
-/* .ad
-/* .fi
-/* The Secure Mailer license must be distributed with this software.
-/* AUTHOR(S)
-/* Initial implementation by:
-/* Till Franke
-/* SuSE Rhein/Main AG
-/* 65760 Eschborn, Germany
-/*
-/* Adopted by:
-/* Wietse Venema
-/* IBM T.J. Watson Research
-/* P.O. Box 704
-/* Yorktown Heights, NY 10598, USA
-/*--*/
+++ /dev/null
-/*++
-/* NAME
-/* lmtp_sasl 3
-/* SUMMARY
-/* Postfix SASL interface for LMTP client
-/* SYNOPSIS
-/* #include lmtp_sasl.h
-/*
-/* void lmtp_sasl_initialize()
-/*
-/* void lmtp_sasl_connect(state)
-/* LMTP_STATE *state;
-/*
-/* void lmtp_sasl_start(state, sasl_opts_name, sasl_opts_val)
-/* LMTP_STATE *state;
-/*
-/* int lmtp_sasl_passwd_lookup(state)
-/* LMTP_STATE *state;
-/*
-/* int lmtp_sasl_authenticate(state, why)
-/* LMTP_STATE *state;
-/* VSTRING *why;
-/*
-/* void lmtp_sasl_cleanup(state)
-/* LMTP_STATE *state;
-/* DESCRIPTION
-/* lmtp_sasl_initialize() initializes the SASL library. This
-/* routine must be called once at process startup, before any
-/* chroot operations.
-/*
-/* lmtp_sasl_connect() performs per-session initialization. This
-/* routine must be called once at the start of each connection.
-/*
-/* lmtp_sasl_start() performs per-session initialization. This
-/* routine must be called once per session before doing any SASL
-/* authentication. The sasl_opts_name and sasl_opts_val parameters are
-/* the postfix configuration parameters setting the security
-/* policy of the SASL authentication.
-/*
-/* lmtp_sasl_passwd_lookup() looks up the username/password
-/* for the current LMTP server. The result is zero in case
-/* of failure.
-/*
-/* lmtp_sasl_authenticate() implements the SASL authentication
-/* dialog. The result is < 0 in case of protocol failure, zero in
-/* case of unsuccessful authentication, > 0 in case of success.
-/* The why argument is updated with a reason for failure.
-/* This routine must be called only when lmtp_sasl_passwd_lookup()
-/* suceeds.
-/*
-/* lmtp_sasl_cleanup() cleans up. It must be called at the
-/* end of every LMTP session that uses SASL authentication.
-/* This routine is a noop for non-SASL sessions.
-/*
-/* Arguments:
-/* .IP state
-/* Session context.
-/* .IP mech_list
-/* String of SASL mechanisms (separated by blanks)
-/* DIAGNOSTICS
-/* All errors are fatal.
-/* LICENSE
-/* .ad
-/* .fi
-/* The Secure Mailer license must be distributed with this software.
-/* AUTHOR(S)
-/* Original author:
-/* Till Franke
-/* SuSE Rhein/Main AG
-/* 65760 Eschborn, Germany
-/*
-/* Adopted by:
-/* Wietse Venema
-/* IBM T.J. Watson Research
-/* P.O. Box 704
-/* Yorktown Heights, NY 10598, USA
-/*--*/
-
- /*
- * System library.
- */
-#include <sys_defs.h>
-#include <stdlib.h>
-#include <string.h>
-#ifdef STRCASECMP_IN_STRINGS_H
-#include <strings.h>
-#endif
-
- /*
- * Utility library
- */
-#include <msg.h>
-#include <mymalloc.h>
-#include <stringops.h>
-#include <split_at.h>
-#include <name_mask.h>
-
- /*
- * Global library
- */
-#include <mail_params.h>
-#include <string_list.h>
-#include <maps.h>
-
- /*
- * Application-specific
- */
-#include "lmtp.h"
-#include "lmtp_sasl.h"
-
-#ifdef USE_SASL_AUTH
-
- /*
- * Authentication security options.
- */
-static NAME_MASK lmtp_sasl_sec_mask[] = {
- "noplaintext", SASL_SEC_NOPLAINTEXT,
- "noactive", SASL_SEC_NOACTIVE,
- "nodictionary", SASL_SEC_NODICTIONARY,
- "noanonymous", SASL_SEC_NOANONYMOUS,
-#if SASL_VERSION_MAJOR >= 2
- "mutual_auth", SASL_SEC_MUTUAL_AUTH,
-#endif
- 0,
-};
-
- /*
- * Macros to handle API differences between SASLv1 and SASLv2. Specifics:
- *
- * The SASL_LOG_* constants were renamed in SASLv2.
- *
- * SASLv2's sasl_client_new takes two new parameters to specify local and
- * remote IP addresses for auth mechs that use them.
- *
- * SASLv2's sasl_client_start function no longer takes the secret parameter.
- *
- * SASLv2's sasl_decode64 function takes an extra parameter for the length of
- * the output buffer.
- *
- * The other major change is that SASLv2 now takes more responsibility for
- * deallocating memory that it allocates internally. Thus, some of the
- * function parameters are now 'const', to make sure we don't try to free
- * them too. This is dealt with in the code later on.
- */
-
-#if SASL_VERSION_MAJOR < 2
-/* SASL version 1.x */
-#define SASL_CLIENT_NEW(srv, fqdn, lport, rport, prompt, secflags, pconn) \
- sasl_client_new(srv, fqdn, prompt, secflags, pconn)
-#define SASL_CLIENT_START(conn, mechlst, secret, prompt, clout, cllen, mech) \
- sasl_client_start(conn, mechlst, secret, prompt, clout, cllen, mech)
-#define SASL_DECODE64(in, inlen, out, outmaxlen, outlen) \
- sasl_decode64(in, inlen, out, outlen)
-#endif
-
-#if SASL_VERSION_MAJOR >= 2
-/* SASL version > 2.x */
-#define SASL_CLIENT_NEW(srv, fqdn, lport, rport, prompt, secflags, pconn) \
- sasl_client_new(srv, fqdn, lport, rport, prompt, secflags, pconn)
-#define SASL_CLIENT_START(conn, mechlst, secret, prompt, clout, cllen, mech) \
- sasl_client_start(conn, mechlst, prompt, clout, cllen, mech)
-#define SASL_DECODE64(in, inlen, out, outmaxlen, outlen) \
- sasl_decode64(in, inlen, out, outmaxlen, outlen)
-#endif
-
- /*
- * Per-host login/password information.
- */
-static MAPS *lmtp_sasl_passwd_map;
-
-/* lmtp_sasl_log - logging call-back routine */
-
-static int lmtp_sasl_log(void *unused_context, int priority,
- const char *message)
-{
- switch (priority) {
- case SASL_LOG_ERR: /* unusual errors */
-#ifdef SASL_LOG_WARN /* non-fatal warnings (Cyrus-SASL v2) */
- case SASL_LOG_WARN:
-#endif
-#ifdef SASL_LOG_WARNING /* non-fatal warnings (Cyrus-SASL v1) */
- case SASL_LOG_WARNING:
-#endif
- msg_warn("SASL authentication problem: %s", message);
- break;
-#ifdef SASL_LOG_INFO
- case SASL_LOG_INFO: /* other info (Cyrus-SASL v1) */
- if (msg_verbose)
- msg_info("SASL authentication info: %s", message);
- break;
-#endif
-#ifdef SASL_LOG_NOTE
- case SASL_LOG_NOTE: /* other info (Cyrus-SASL v2) */
- if (msg_verbose)
- msg_info("SASL authentication info: %s", message);
- break;
-#endif
-#ifdef SASL_LOG_FAIL
- case SASL_LOG_FAIL: /* authentication failures
- * (Cyrus-SASL v2) */
- msg_warn("SASL authentication failure: %s", message);
- break;
-#endif
-#ifdef SASL_LOG_DEBUG
- case SASL_LOG_DEBUG: /* more verbose than LOG_NOTE
- * (Cyrus-SASL v2) */
- if (msg_verbose > 1)
- msg_info("SASL authentication debug: %s", message);
- break;
-#endif
-#ifdef SASL_LOG_TRACE
- case SASL_LOG_TRACE: /* traces of internal
- * protocols (Cyrus-SASL v2) */
- if (msg_verbose > 1)
- msg_info("SASL authentication trace: %s", message);
- break;
-#endif
-#ifdef SASL_LOG_PASS
- case SASL_LOG_PASS: /* traces of internal
- * protocols, including
- * passwords (Cyrus-SASL v2) */
- if (msg_verbose > 1)
- msg_info("SASL authentication pass: %s", message);
- break;
-#endif
- }
- return (SASL_OK);
-}
-
-/* lmtp_sasl_get_user - username lookup call-back routine */
-
-static int lmtp_sasl_get_user(void *context, int unused_id, const char **result,
- unsigned *len)
-{
- char *myname = "lmtp_sasl_get_user";
- LMTP_STATE *state = (LMTP_STATE *) context;
-
- if (msg_verbose)
- msg_info("%s: %s", myname, state->sasl_username);
-
- /*
- * Sanity check.
- */
- if (state->sasl_passwd == 0)
- msg_panic("%s: no username looked up", myname);
-
- *result = state->sasl_username;
- if (len)
- *len = strlen(state->sasl_username);
- return (SASL_OK);
-}
-
-/* lmtp_sasl_get_passwd - password lookup call-back routine */
-
-static int lmtp_sasl_get_passwd(sasl_conn_t *conn, void *context,
- int id, sasl_secret_t **psecret)
-{
- char *myname = "lmtp_sasl_get_passwd";
- LMTP_STATE *state = (LMTP_STATE *) context;
- int len;
-
- if (msg_verbose)
- msg_info("%s: %s", myname, state->sasl_passwd);
-
- /*
- * Sanity check.
- */
- if (!conn || !psecret || id != SASL_CB_PASS)
- return (SASL_BADPARAM);
- if (state->sasl_passwd == 0)
- msg_panic("%s: no password looked up", myname);
-
- /*
- * Convert the password into a counted string.
- */
- len = strlen(state->sasl_passwd);
- if ((*psecret = (sasl_secret_t *) malloc(sizeof(sasl_secret_t) + len)) == 0)
- return (SASL_NOMEM);
- (*psecret)->len = len;
- memcpy((*psecret)->data, state->sasl_passwd, len + 1);
-
- return (SASL_OK);
-}
-
-/* lmtp_sasl_passwd_lookup - password lookup routine */
-
-int lmtp_sasl_passwd_lookup(LMTP_STATE *state)
-{
- char *myname = "lmtp_sasl_passwd_lookup";
- const char *value;
- char *passwd;
-
- /*
- * Sanity check.
- */
- if (lmtp_sasl_passwd_map == 0)
- msg_panic("%s: passwd map not initialized", myname);
-
- /*
- * Look up the per-server password information. Try the hostname first,
- * then try the destination.
- */
- if ((value = maps_find(lmtp_sasl_passwd_map, state->session->host, 0)) != 0
- || (value = maps_find(lmtp_sasl_passwd_map, state->request->nexthop, 0)) != 0) {
- state->sasl_username = mystrdup(value);
- passwd = split_at(state->sasl_username, ':');
- state->sasl_passwd = mystrdup(passwd ? passwd : "");
- if (msg_verbose)
- msg_info("%s: host `%s' user `%s' pass `%s'",
- myname, state->session->host,
- state->sasl_username, state->sasl_passwd);
- return (1);
- } else {
- if (msg_verbose)
- msg_info("%s: host `%s' no auth info found",
- myname, state->session->host);
- return (0);
- }
-}
-
-/* lmtp_sasl_initialize - per-process initialization (pre jail) */
-
-void lmtp_sasl_initialize(void)
-{
-
- /*
- * Global callbacks. These have no per-session context.
- */
- static sasl_callback_t callbacks[] = {
- {SASL_CB_LOG, &lmtp_sasl_log, 0},
- {SASL_CB_LIST_END, 0, 0}
- };
-
-#if SASL_VERSION_MAJOR >= 2 && (SASL_VERSION_MINOR >= 2 \
- || (SASL_VERSION_MINOR == 1 && SASL_VERSION_STEP >= 19))
- int sasl_major;
- int sasl_minor;
- int sasl_step;
-
- /*
- * DLL hell guard.
- */
- sasl_version_info((const char **) 0, (const char **) 0,
- &sasl_major, &sasl_minor,
- &sasl_step, (int *) 0);
- if (sasl_major != SASL_VERSION_MAJOR
-#if 0
- || sasl_minor != SASL_VERSION_MINOR
- || sasl_step != SASL_VERSION_STEP
-#endif
- )
- msg_fatal("incorrect SASL library version. "
- "Postfix was built with include files from version %d.%d.%d, "
- "but the run-time library version is %d.%d.%d",
- SASL_VERSION_MAJOR, SASL_VERSION_MINOR, SASL_VERSION_STEP,
- sasl_major, sasl_minor, sasl_step);
-#endif
-
- /*
- * Sanity check.
- */
- if (lmtp_sasl_passwd_map)
- msg_panic("lmtp_sasl_initialize: repeated call");
- if (*var_lmtp_sasl_passwd == 0)
- msg_fatal("specify a password table via the `%s' configuration parameter",
- VAR_LMTP_SASL_PASSWD);
-
- /*
- * Open the per-host password table and initialize the SASL library. Use
- * shared locks for reading, just in case someone updates the table.
- */
- lmtp_sasl_passwd_map = maps_create("lmtp_sasl_passwd",
- var_lmtp_sasl_passwd, DICT_FLAG_LOCK);
- if (sasl_client_init(callbacks) != SASL_OK)
- msg_fatal("SASL library initialization");
-
-}
-
-/* lmtp_sasl_connect - per-session client initialization */
-
-void lmtp_sasl_connect(LMTP_STATE *state)
-{
- state->sasl_mechanism_list = 0;
- state->sasl_username = 0;
- state->sasl_passwd = 0;
- state->sasl_conn = 0;
- state->sasl_encoded = 0;
- state->sasl_decoded = 0;
- state->sasl_callbacks = 0;
-}
-
-/* lmtp_sasl_start - per-session SASL initialization */
-
-void lmtp_sasl_start(LMTP_STATE *state, const char *sasl_opts_name,
- const char *sasl_opts_val)
-{
- static sasl_callback_t callbacks[] = {
- {SASL_CB_USER, &lmtp_sasl_get_user, 0},
- {SASL_CB_AUTHNAME, &lmtp_sasl_get_user, 0},
- {SASL_CB_PASS, &lmtp_sasl_get_passwd, 0},
- {SASL_CB_LIST_END, 0, 0}
- };
- sasl_callback_t *cp;
- sasl_security_properties_t sec_props;
-
- if (msg_verbose)
- msg_info("starting new SASL client");
-
- /*
- * Per-session initialization. Provide each session with its own callback
- * context.
- */
-#define NULL_SECFLAGS 0
-
- state->sasl_callbacks = (sasl_callback_t *) mymalloc(sizeof(callbacks));
- memcpy((char *) state->sasl_callbacks, callbacks, sizeof(callbacks));
- for (cp = state->sasl_callbacks; cp->id != SASL_CB_LIST_END; cp++)
- cp->context = (void *) state;
-
-#define NULL_SERVER_ADDR ((char *) 0)
-#define NULL_CLIENT_ADDR ((char *) 0)
-
- if (SASL_CLIENT_NEW("lmtp", state->session->host,
- NULL_CLIENT_ADDR, NULL_SERVER_ADDR,
- state->sasl_callbacks, NULL_SECFLAGS,
- (sasl_conn_t **) &state->sasl_conn) != SASL_OK)
- msg_fatal("per-session SASL client initialization");
-
- /*
- * Per-session security properties. XXX This routine is not sufficiently
- * documented. What is the purpose of all this?
- */
- memset(&sec_props, 0L, sizeof(sec_props));
- sec_props.min_ssf = 0;
- sec_props.max_ssf = 0; /* don't allow real SASL
- * security layer */
- sec_props.security_flags = name_mask(sasl_opts_name, lmtp_sasl_sec_mask,
- sasl_opts_val);
- sec_props.maxbufsize = 0;
- sec_props.property_names = 0;
- sec_props.property_values = 0;
- if (sasl_setprop(state->sasl_conn, SASL_SEC_PROPS,
- &sec_props) != SASL_OK)
- msg_fatal("set per-session SASL security properties");
-
- /*
- * We use long-lived conversion buffers rather than local variables in
- * order to avoid memory leaks in case of read/write timeout or I/O
- * error.
- */
- state->sasl_encoded = vstring_alloc(10);
- state->sasl_decoded = vstring_alloc(10);
-}
-
-/* lmtp_sasl_authenticate - run authentication protocol */
-
-int lmtp_sasl_authenticate(LMTP_STATE *state, DSN_BUF *why)
-{
- char *myname = "lmtp_sasl_authenticate";
- LMTP_SESSION *session = state->session;
- unsigned enc_length;
- unsigned enc_length_out;
-
-#if SASL_VERSION_MAJOR >= 2
- const char *clientout;
-
-#else
- char *clientout;
-
-#endif
- unsigned clientoutlen;
- unsigned serverinlen;
- LMTP_RESP *resp;
- const char *mechanism;
- int result;
- char *line;
-
-#define NO_SASL_SECRET 0
-#define NO_SASL_INTERACTION 0
-#define NO_SASL_LANGLIST ((const char *) 0)
-#define NO_SASL_OUTLANG ((const char **) 0)
-
- if (msg_verbose)
- msg_info("%s: %s: SASL mechanisms %s",
- myname, session->namaddr, state->sasl_mechanism_list);
-
- /*
- * Start the client side authentication protocol.
- */
- result = SASL_CLIENT_START((sasl_conn_t *) state->sasl_conn,
- state->sasl_mechanism_list,
- NO_SASL_SECRET, NO_SASL_INTERACTION,
- &clientout, &clientoutlen, &mechanism);
- if (result != SASL_OK && result != SASL_CONTINUE) {
- dsb_update(why, "4.7.0", DSB_DEF_ACTION, DSB_SKIP_RMTA, DSB_DTYPE_SASL,
- 421, sasl_errstring(result, NO_SASL_LANGLIST,
- NO_SASL_OUTLANG),
- "cannot SASL authenticate to server %s: %s",
- session->namaddr,
- sasl_errstring(result, NO_SASL_LANGLIST,
- NO_SASL_OUTLANG));
- return (-1);
- }
-
- /*
- * Send the AUTH command and the optional initial client response.
- * sasl_encode64() produces four bytes for each complete or incomplete
- * triple of input bytes. Allocate an extra byte for string termination.
- */
-#define ENCODE64_LENGTH(n) ((((n) + 2) / 3) * 4)
-
- if (clientoutlen > 0) {
- if (msg_verbose)
- msg_info("%s: %s: uncoded initial reply: %.*s",
- myname, session->namaddr,
- (int) clientoutlen, clientout);
- enc_length = ENCODE64_LENGTH(clientoutlen) + 1;
- VSTRING_SPACE(state->sasl_encoded, enc_length);
- if (sasl_encode64(clientout, clientoutlen,
- STR(state->sasl_encoded), enc_length,
- &enc_length_out) != SASL_OK)
- msg_panic("%s: sasl_encode64 botch", myname);
-#if SASL_VERSION_MAJOR < 2
- /* SASL version 1 doesn't free memory that it allocates. */
- free(clientout);
-#endif
- lmtp_chat_cmd(state, "AUTH %s %s", mechanism, STR(state->sasl_encoded));
- } else {
- lmtp_chat_cmd(state, "AUTH %s", mechanism);
- }
-
- /*
- * Step through the authentication protocol until the server tells us
- * that we are done.
- */
- while ((resp = lmtp_chat_resp(state))->code / 100 == 3) {
-
- /*
- * Process a server challenge.
- */
- line = resp->str;
- (void) mystrtok(&line, "- \t\n"); /* skip over result code */
- serverinlen = strlen(line);
- VSTRING_SPACE(state->sasl_decoded, serverinlen);
- if (SASL_DECODE64(line, serverinlen, STR(state->sasl_decoded),
- serverinlen, &enc_length) != SASL_OK) {
- lmtp_dsn_update(why, "5.7.0", DSN_BY_LOCAL_MTA,
- 501, "501 malformed SASL challenge",
- "malformed SASL challenge from server %s",
- session->namaddr);
- return (-1);
- }
- if (msg_verbose)
- msg_info("%s: %s: decoded challenge: %.*s",
- myname, session->namaddr,
- (int) enc_length, STR(state->sasl_decoded));
- result = sasl_client_step((sasl_conn_t *) state->sasl_conn,
- STR(state->sasl_decoded), enc_length,
- NO_SASL_INTERACTION, &clientout, &clientoutlen);
- if (result != SASL_OK && result != SASL_CONTINUE)
- msg_warn("SASL authentication failed to server %s: %s",
- session->namaddr,
- sasl_errstring(result, NO_SASL_LANGLIST,
- NO_SASL_OUTLANG));
-
- /*
- * Send a client response.
- */
- if (clientoutlen > 0) {
- if (msg_verbose)
- msg_info("%s: %s: uncoded client response %.*s",
- myname, session->namaddr,
- (int) clientoutlen, clientout);
- enc_length = ENCODE64_LENGTH(clientoutlen) + 1;
- VSTRING_SPACE(state->sasl_encoded, enc_length);
- if (sasl_encode64(clientout, clientoutlen,
- STR(state->sasl_encoded), enc_length,
- &enc_length_out) != SASL_OK)
- msg_panic("%s: sasl_encode64 botch", myname);
-#if SASL_VERSION_MAJOR < 2
- /* SASL version 1 doesn't free memory that it allocates. */
- free(clientout);
-#endif
- } else {
- vstring_strcat(state->sasl_encoded, "");
- }
- lmtp_chat_cmd(state, "%s", STR(state->sasl_encoded));
- }
-
- /*
- * We completed the authentication protocol.
- */
- if (resp->code / 100 != 2) {
- lmtp_dsn_update(why, session->host, resp->dsn, resp->code, resp->str,
- "SASL authentication failed; server %s said: %s",
- session->namaddr, resp->str);
- return (0);
- }
- return (1);
-}
-
-/* lmtp_sasl_cleanup - per-session cleanup */
-
-void lmtp_sasl_cleanup(LMTP_STATE *state)
-{
- if (state->sasl_username) {
- myfree(state->sasl_username);
- state->sasl_username = 0;
- }
- if (state->sasl_passwd) {
- myfree(state->sasl_passwd);
- state->sasl_passwd = 0;
- }
- if (state->sasl_mechanism_list) {
- /* allocated in lmtp_sasl_helo_auth */
- myfree(state->sasl_mechanism_list);
- state->sasl_mechanism_list = 0;
- }
- if (state->sasl_conn) {
- if (msg_verbose)
- msg_info("disposing SASL state information");
- sasl_dispose(&state->sasl_conn);
- }
- if (state->sasl_callbacks) {
- myfree((char *) state->sasl_callbacks);
- state->sasl_callbacks = 0;
- }
- if (state->sasl_encoded) {
- vstring_free(state->sasl_encoded);
- state->sasl_encoded = 0;
- }
- if (state->sasl_decoded) {
- vstring_free(state->sasl_decoded);
- state->sasl_decoded = 0;
- }
-}
-
-#endif
+++ /dev/null
-/*++
-/* NAME
-/* lmtp_sasl_proto 3
-/* SUMMARY
-/* Postfix SASL interface for LMTP client
-/* SYNOPSIS
-/* #include lmtp_sasl.h
-/*
-/* void lmtp_sasl_helo_auth(state, words)
-/* LMTP_STATE *state;
-/* const char *words;
-/*
-/* int lmtp_sasl_helo_login(state)
-/* LMTP_STATE *state;
-/* DESCRIPTION
-/* This module contains random chunks of code that implement
-/* the LMTP protocol interface for SASL negotiation. The goal
-/* is to reduce clutter in the main LMTP client source code.
-/*
-/* lmtp_sasl_helo_auth() processes the AUTH option in the
-/* LMTP server's LHLO response.
-/*
-/* lmtp_sasl_helo_login() authenticates the LMTP client to the
-/* LMTP server, using the authentication mechanism information
-/* given by the server. The result is a Postfix delivery status
-/* code in case of trouble.
-/*
-/* Arguments:
-/* .IP state
-/* Session context.
-/* .IP words
-/* List of SASL authentication mechanisms (separated by blanks)
-/* DIAGNOSTICS
-/* All errors are fatal.
-/* LICENSE
-/* .ad
-/* .fi
-/* The Secure Mailer license must be distributed with this software.
-/* AUTHOR(S)
-/* Original author:
-/* Till Franke
-/* SuSE Rhein/Main AG
-/* 65760 Eschborn, Germany
-/*
-/* Adopted by:
-/* Wietse Venema
-/* IBM T.J. Watson Research
-/* P.O. Box 704
-/* Yorktown Heights, NY 10598, USA
-/*--*/
-
-/* System library. */
-
-#include <sys_defs.h>
-#include <string.h>
-#ifdef STRCASECMP_IN_STRINGS_H
-#include <strings.h>
-#endif
-
-/* Utility library. */
-
-#include <msg.h>
-#include <mymalloc.h>
-
-/* Global library. */
-
-#include <mail_params.h>
-
-/* Application-specific. */
-
-#include "lmtp.h"
-#include "lmtp_sasl.h"
-
-#ifdef USE_SASL_AUTH
-
-/* lmtp_sasl_helo_auth - handle AUTH option in EHLO reply */
-
-void lmtp_sasl_helo_auth(LMTP_STATE *state, const char *words)
-{
-
- /*
- * XXX If the server offers a null list of authentication mechanisms,
- * then pretend that the server doesn't support SASL authentication.
- */
- if (state->sasl_mechanism_list) {
- if (strcasecmp(state->sasl_mechanism_list, words) == 0)
- return;
- myfree(state->sasl_mechanism_list);
- msg_warn("%s offered AUTH option multiple times",
- state->session->namaddr);
- state->sasl_mechanism_list = 0;
- state->features &= ~LMTP_FEATURE_AUTH;
- }
- if (strlen(words) > 0) {
- state->sasl_mechanism_list = mystrdup(words);
- state->features |= LMTP_FEATURE_AUTH;
- } else {
- msg_warn("%s offered null AUTH mechanism list",
- state->session->namaddr);
- }
-}
-
-/* lmtp_sasl_helo_login - perform SASL login */
-
-int lmtp_sasl_helo_login(LMTP_STATE *state)
-{
- DSN_BUF *why = dsb_create();
- int ret = 0;
-
- /*
- * Skip authentication when no authentication info exists for this
- * server, so that we talk to each other like strangers. Otherwise, if
- * authentication information exists, assume that authentication is
- * required, and assume that an authentication error is recoverable.
- */
- if (lmtp_sasl_passwd_lookup(state) != 0) {
- lmtp_sasl_start(state, VAR_LMTP_SASL_OPTS, var_lmtp_sasl_opts);
- if (lmtp_sasl_authenticate(state, why) <= 0) {
- vstring_prepend(why->reason, "Authentication failed: ",
- sizeof("Authentication failed: ") - 1);
- ret = lmtp_sess_fail(state, why);
- }
- }
- dsb_free(why);
- return (ret);
-}
-
-#endif
+++ /dev/null
-/*++
-/* NAME
-/* lmtp_session 3
-/* SUMMARY
-/* LMTP_SESSION structure management
-/* SYNOPSIS
-/* #include "lmtp.h"
-/*
-/* LMTP_SESSION *lmtp_session_alloc(stream, host, addr, dest, type)
-/* VSTREAM *stream;
-/* const char *host;
-/* const char *addr;
-/* const char *dest;
-/* int type;
-/*
-/* LMTP_SESSION *lmtp_session_free(session)
-/* LMTP_SESSION *session;
-/* DESCRIPTION
-/* This module maintains information about connections, including
-/* per-peer debugging.
-/*
-/* lmtp_session_alloc() allocates memory for an LMTP_SESSION structure
-/* and initializes it with the given stream and host name and address
-/* information. The host name and address strings are copied.
-/* The type argument specifies the transport type. The dest argument
-/* specifies a string-valued name for the remote endpoint.
-/* If the peer name or address matches the debug-peer_list configuration
-/* parameter, the debugging level is incremented by the amount specified
-/* in the debug_peer_level parameter.
-/*
-/* lmtp_session_free() destroys an LMTP_SESSION structure and its
-/* members, making memory available for reuse. The result value is
-/* convenient null pointer. The debugging level is restored to the
-/* value prior to the lmtp_session_alloc() call.
-/* LICENSE
-/* .ad
-/* .fi
-/* The Secure Mailer license must be distributed with this software.
-/* SEE ALSO
-/* debug_peer(3), increase logging for selected peers
-/* AUTHOR(S)
-/* Wietse Venema
-/* IBM T.J. Watson Research
-/* P.O. Box 704
-/* Yorktown Heights, NY 10598, USA
-/*
-/* Alterations for LMTP by:
-/* Philip A. Prindeville
-/* Mirapoint, Inc.
-/* USA.
-/*
-/* Additional work on LMTP by:
-/* Amos Gouaux
-/* University of Texas at Dallas
-/* P.O. Box 830688, MC34
-/* Richardson, TX 75083, USA
-/*--*/
-
-/* System library. */
-
-#include <sys_defs.h>
-
-/* Utility library. */
-
-#include <mymalloc.h>
-#include <vstream.h>
-#include <stringops.h>
-
-/* Global library. */
-
-#include <debug_peer.h>
-
-/* Application-specific. */
-
-#include "lmtp.h"
-
-/* lmtp_session_alloc - allocate and initialize LMTP_SESSION structure */
-
-LMTP_SESSION *lmtp_session_alloc(VSTREAM *stream, const char *host,
- const char *addr, const char *dest)
-{
- LMTP_SESSION *session;
-
- session = (LMTP_SESSION *) mymalloc(sizeof(*session));
- session->stream = stream;
- session->host = mystrdup(host);
- session->addr = mystrdup(addr);
- session->namaddr = concatenate(host, "[", addr, "]", (char *) 0);
- session->dest = mystrdup(dest);
- debug_peer_check(host, addr);
- return (session);
-}
-
-/* lmtp_session_free - destroy LMTP_SESSION structure and contents */
-
-LMTP_SESSION *lmtp_session_free(LMTP_SESSION *session)
-{
- debug_peer_restore();
- vstream_fclose(session->stream);
- myfree(session->host);
- myfree(session->addr);
- myfree(session->namaddr);
- myfree(session->dest);
- myfree((char *) session);
- return (0);
-}
+++ /dev/null
-/*++
-/* NAME
-/* lmtp_state 8
-/* SUMMARY
-/* initialize/cleanup shared state
-/* SYNOPSIS
-/* #include "lmtp.h"
-/*
-/* LMTP_STATE *lmtp_state_alloc()
-/*
-/* void lmtp_state_free(state)
-/* LMTP_STATE *state;
-/* DESCRIPTION
-/* lmtp_state_init() initializes the shared state, and allocates
-/* memory for buffers etc.
-/*
-/* lmtp_cleanup() destroys memory allocated by lmtp_state_init().
-/* STANDARDS
-/* DIAGNOSTICS
-/* BUGS
-/* SEE ALSO
-/* 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
-/*
-/* Alterations for LMTP by:
-/* Philip A. Prindeville
-/* Mirapoint, Inc.
-/* USA.
-/*
-/* Additional work on LMTP by:
-/* Amos Gouaux
-/* University of Texas at Dallas
-/* P.O. Box 830688, MC34
-/* Richardson, TX 75083, USA
-/*--*/
-
-/* System library. */
-
-#include <sys_defs.h>
-
-/* Utility library. */
-
-#include <mymalloc.h>
-#include <vstring.h>
-#include <vstream.h>
-
-/* Global library. */
-
-#include <mail_conf.h>
-
-/* Application-specific. */
-
-#include "lmtp.h"
-#include "lmtp_sasl.h"
-
-/* lmtp_state_alloc - initialize */
-
-LMTP_STATE *lmtp_state_alloc(void)
-{
- LMTP_STATE *state = (LMTP_STATE *) mymalloc(sizeof(*state));
-
- state->src = 0;
- state->request = 0;
- state->session = 0;
- state->buffer = vstring_alloc(100);
- state->scratch = vstring_alloc(100);
- state->scratch2 = vstring_alloc(100);
- state->status = 0;
- state->features = 0;
- state->history = 0;
- state->error_mask = 0;
-#ifdef USE_SASL_AUTH
- lmtp_sasl_connect(state);
-#endif
- state->sndbufsize = 0;
- state->reuse = 0;
- state->dsn_reason = 0;
-
- return (state);
-}
-
-/* lmtp_state_free - destroy state */
-
-void lmtp_state_free(LMTP_STATE *state)
-{
- vstring_free(state->buffer);
- vstring_free(state->scratch);
- vstring_free(state->scratch2);
-#ifdef USE_SASL_AUTH
- lmtp_sasl_cleanup(state);
-#endif
- if (state->dsn_reason)
- vstring_free(state->dsn_reason);
-
- myfree((char *) state);
-}
+++ /dev/null
-/*++
-/* NAME
-/* lmtp_trouble 3
-/* SUMMARY
-/* error handler policies
-/* SYNOPSIS
-/* #include "lmtp.h"
-/*
-/* int lmtp_sess_fail(state, why)
-/* SMTP_STATE *state;
-/* DSN_BUF *why;
-/*
-/* int lmtp_site_fail(state, mta_name, resp, format, ...)
-/* LMTP_STATE *state;
-/* const char *mta_name;
-/* LMTP_RESP *resp;
-/* const char *format;
-/*
-/* int lmtp_mesg_fail(state, mta_name, resp, format, ...)
-/* LMTP_STATE *state;
-/* const char *mta_name;
-/* LMTP_RESP *resp;
-/* const char *format;
-/*
-/* void lmtp_rcpt_fail(state, mta_name, resp, recipient, format, ...)
-/* LMTP_STATE *state;
-/* const char *mta_name;
-/* LMTP_RESP *resp;
-/* RECIPIENT *recipient;
-/* const char *format;
-/*
-/* int lmtp_stream_except(state, exception, description)
-/* LMTP_STATE *state;
-/* int exception;
-/* const char *description;
-/* DESCRIPTION
-/* This module handles all non-fatal errors that can happen while
-/* attempting to deliver mail via LMTP, and implements the policy
-/* of how to deal with the error. Depending on the nature of
-/* the problem, delivery of a single message is deferred, delivery
-/* of all messages to the same domain is deferred, or one or more
-/* recipients are given up as non-deliverable and a bounce log is
-/* updated.
-/*
-/* In addition, when an unexpected response code is seen such
-/* as 3xx where only 4xx or 5xx are expected, or any error code
-/* that suggests a syntax error or something similar, the
-/* protocol error flag is set so that the postmaster receives
-/* a transcript of the session. No notification is generated for
-/* what appear to be configuration errors - very likely, they
-/* would suffer the same problem and just cause more trouble.
-/*
-/* lmtp_sess_fail() takes a pre-formatted error report after
-/* failure to complete some protocol handshake. The policy is
-/* as with lmtp_site_fail().
-/*
-/* lmtp_site_fail() handles the case where the program fails to
-/* complete some protocol handshake: the server is not reachable,
-/* is not running, does not want talk to us, or we talk to ourselves.
-/* The \fIcode\fR gives an error status code; the \fIformat\fR
-/* argument gives a textual description. The policy is: soft
-/* error: defer delivery of all messages to this domain; hard
-/* error: bounce all recipients of this message.
-/* The result is non-zero.
-/*
-/* lmtp_mesg_fail() handles the case where the lmtp server
-/* does not accept the sender address or the message data.
-/* The policy is: soft errors: defer delivery of this message;
-/* hard error: bounce all recipients of this message.
-/* The result is non-zero.
-/*
-/* lmtp_rcpt_fail() handles the case where a recipient is not
-/* accepted by the server for reasons other than that the server
-/* recipient limit is reached. The policy is: soft error: defer
-/* delivery to this recipient; hard error: bounce this recipient.
-/*
-/* lmtp_stream_except() handles the exceptions generated by
-/* the smtp_stream(3) module (i.e. timeouts and I/O errors).
-/* The \fIexception\fR argument specifies the type of problem.
-/* The \fIdescription\fR argument describes at what stage of
-/* the LMTP dialog the problem happened. The policy is to defer
-/* delivery of all messages to the same domain. The result is non-zero.
-/*
-/* Arguments:
-/* .IP state
-/* LMTP client state per delivery request.
-/* .IP resp
-/* Server response including reply code and text.
-/* .IP recipient
-/* Undeliverable recipient address information.
-/* .IP format
-/* Human-readable description of why mail is not deliverable.
-/* DIAGNOSTICS
-/* Panic: unknown exception code.
-/* SEE ALSO
-/* lmtp_proto(3) lmtp high-level protocol
-/* smtp_stream(3) lmtp low-level protocol
-/* defer(3) basic message defer interface
-/* bounce(3) basic message bounce interface
-/* 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
-/*
-/* Alterations for LMTP by:
-/* Philip A. Prindeville
-/* Mirapoint, Inc.
-/* USA.
-/*
-/* Additional work on LMTP by:
-/* Amos Gouaux
-/* University of Texas at Dallas
-/* P.O. Box 830688, MC34
-/* Richardson, TX 75083, USA
-/*--*/
-
-/* System library. */
-
-#include <sys_defs.h>
-#include <stdlib.h> /* 44BSD stdarg.h uses abort() */
-#include <stdarg.h>
-#include <string.h>
-
-/* Utility library. */
-
-#include <msg.h>
-#include <vstring.h>
-#include <stringops.h>
-
-/* Global library. */
-
-#include <smtp_stream.h>
-#include <deliver_request.h>
-#include <deliver_completed.h>
-#include <bounce.h>
-#include <defer.h>
-#include <mail_error.h>
-#include <dsn_buf.h>
-#include <dsn.h>
-
-/* Application-specific. */
-
-#include "lmtp.h"
-
-#define LMTP_THROTTLE 1
-#define LMTP_NOTHROTTLE 0
-
-/* lmtp_check_code - check response code */
-
-static void lmtp_check_code(LMTP_STATE *state, int code)
-{
-
- /*
- * The intention of this code is to alert the postmaster when the local
- * Postfix LMTP client screws up, protocol wise. RFC 821 says that x0z
- * replies "refer to syntax errors, syntactically correct commands that
- * don't fit any functional category, and unimplemented or superfluous
- * commands". Unfortunately, this also triggers postmaster notices when
- * remote servers screw up, protocol wise. This is becoming a common
- * problem now that response codes are configured manually as part of
- * anti-UCE systems, by people who aren't aware of RFC details.
- */
- if (code < 400 || code > 599
- || code == 555 /* RFC 1869, section 6.1. */
- || (code >= 500 && code < 510))
- state->error_mask |= MAIL_ERROR_PROTOCOL;
-}
-
-/* lmtp_bulk_fail - skip, defer or bounce recipients, maybe throttle queue */
-
-static int lmtp_bulk_fail(LMTP_STATE *state, DSN *dsn, int throttle_queue)
-{
- DELIVER_REQUEST *request = state->request;
- LMTP_SESSION *session = state->session;
- RECIPIENT *rcpt;
- int status;
- int soft_error = (dsn->dtext[0] == '4');
- int nrcpt;
-
- /*
- * If we are still in the connection set-up phase, update the set-up
- * completion time here, otherwise the time spent in set-up latency will
- * be attributed as message transfer latency.
- *
- * All remaining recipients failed at this point, so we update the delivery
- * completion time stamp so that multiple recipient status records show
- * the same delay values.
- */
- if (request->msg_stats.conn_setup_done.tv_sec == 0) {
- GETTIMEOFDAY(&request->msg_stats.conn_setup_done);
- request->msg_stats.deliver_done =
- request->msg_stats.conn_setup_done;
- } else
- GETTIMEOFDAY(&request->msg_stats.deliver_done);
-
- /*
- * If this is a soft error, postpone further deliveries to this domain.
- * Otherwise, generate a bounce record for each recipient.
- */
- for (nrcpt = 0; nrcpt < request->rcpt_list.len; nrcpt++) {
- rcpt = request->rcpt_list.info + nrcpt;
- if (rcpt->offset == 0)
- continue;
- status = (soft_error ? defer_append : bounce_append)
- (DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id,
- &request->msg_stats, rcpt,
- session ? session->namaddr : "none", dsn);
- if (status == 0) {
- deliver_completed(state->src, rcpt->offset);
- rcpt->offset = 0;
- }
- state->status |= status;
- }
- if (throttle_queue && soft_error && request->hop_status == 0)
- request->hop_status = DSN_COPY(dsn);
-
- return (-1);
-}
-
-/* lmtp_sess_fail - skip site, defer or bounce all recipients */
-
-int lmtp_sess_fail(LMTP_STATE *state, DSN_BUF *why)
-{
- DSN dsn;
-
- /*
- * We need to incur the expense of copying lots of strings into VSTRING
- * buffers when the error information is collected by a routine that
- * terminates BEFORE the error is reported. If no copies were made, the
- * information would not be frozen in time.
- */
- return (lmtp_bulk_fail(state, DSN_FROM_DSN_BUF(&dsn, why), LMTP_THROTTLE));
-}
-
-/* vlmtp_fill_dsn - fill in temporary DSN structure */
-
-static void vlmtp_fill_dsn(LMTP_STATE *state, DSN *dsn, const char *mta_name,
- const char *status, const char *reply,
- const char *format, va_list ap)
-{
-
- /*
- * We can avoid the cost of copying lots of strings into VSTRING buffers
- * when the error information is collected by the routine that terminates
- * AFTER the error is reported. In this case, the information is already
- * frozen in time, so we don't need to make copies.
- */
- if (state->dsn_reason == 0)
- state->dsn_reason = vstring_alloc(100);
- else
- VSTRING_RESET(state->dsn_reason);
- if (mta_name && reply[0] != '4' && reply[0] != '5') {
- vstring_strcpy(state->dsn_reason, "Protocol error: ");
- mta_name = DSN_BY_LOCAL_MTA;
- status = "5.5.0";
- reply = "501 Protocol error in server reply";
- }
- vstring_vsprintf_append(state->dsn_reason, format, ap);
- LMTP_DSN_ASSIGN(dsn, mta_name, status, reply, STR(state->dsn_reason));
-}
-
-/* lmtp_fill_dsn - fill in temporary DSN structure */
-
-static void lmtp_fill_dsn(LMTP_STATE *state, DSN *dsn, const char *mta_name,
- const char *status, const char *reply,
- const char *format,...)
-{
- va_list ap;
-
- va_start(ap, format);
- vlmtp_fill_dsn(state, dsn, mta_name, status, reply, format, ap);
- va_end(ap);
-}
-
-/* lmtp_site_fail - defer site or bounce recipients */
-
-int lmtp_site_fail(LMTP_STATE *state, const char *mta_name, LMTP_RESP *resp,
- const char *format,...)
-{
- DSN dsn;
- va_list ap;
-
- /*
- * Initialize.
- */
- va_start(ap, format);
- vlmtp_fill_dsn(state, &dsn, mta_name, resp->dsn, resp->str, format, ap);
- va_end(ap);
-
- if (state->session && mta_name)
- lmtp_check_code(state, resp->code);
-
- /*
- * Skip, defer or bounce recipients, and throttle this queue.
- */
- return (lmtp_bulk_fail(state, &dsn, LMTP_THROTTLE));
-}
-
-/* lmtp_mesg_fail - defer message or bounce all recipients */
-
-int lmtp_mesg_fail(LMTP_STATE *state, const char *mta_name, LMTP_RESP *resp,
- const char *format,...)
-{
- va_list ap;
- DSN dsn;
-
- /*
- * Initialize.
- */
- va_start(ap, format);
- vlmtp_fill_dsn(state, &dsn, mta_name, resp->dsn, resp->str, format, ap);
- va_end(ap);
-
- if (state->session && mta_name)
- lmtp_check_code(state, resp->code);
-
- /*
- * Skip, defer or bounce recipients, but don't throttle this queue.
- */
- return (lmtp_bulk_fail(state, &dsn, LMTP_NOTHROTTLE));
-}
-
-/* lmtp_rcpt_fail - defer or bounce recipient */
-
-void lmtp_rcpt_fail(LMTP_STATE *state, const char *mta_name, LMTP_RESP *resp,
- RECIPIENT *rcpt, const char *format,...)
-{
- DELIVER_REQUEST *request = state->request;
- LMTP_SESSION *session = state->session;
- int soft_error;
- int status;
- DSN dsn;
- va_list ap;
-
- /*
- * Initialize.
- */
- va_start(ap, format);
- vlmtp_fill_dsn(state, &dsn, mta_name, resp->dsn, resp->str, format, ap);
- va_end(ap);
- soft_error = dsn.dtext[0] == '4';
-
- if (state->session && mta_name)
- lmtp_check_code(state, resp->code);
-
- /*
- * If this is a soft error, postpone delivery to this recipient.
- * Otherwise, generate a bounce record for this recipient.
- */
- status = (soft_error ? defer_append : bounce_append)
- (DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id,
- &request->msg_stats, rcpt,
- session ? session->namaddr : "none", &dsn);
- if (status == 0) {
- deliver_completed(state->src, rcpt->offset);
- rcpt->offset = 0;
- }
- state->status |= status;
-}
-
-/* lmtp_stream_except - defer domain after I/O problem */
-
-int lmtp_stream_except(LMTP_STATE *state, int code, const char *description)
-{
- LMTP_SESSION *session = state->session;
- DSN dsn;
-
- /*
- * Sanity check.
- */
- if (session == 0)
- msg_panic("lmtp_stream_except: no session");
-
- /*
- * Initialize.
- */
- switch (code) {
- default:
- msg_panic("lmtp_stream_except: unknown exception %d", code);
- case SMTP_ERR_EOF:
- lmtp_fill_dsn(state, &dsn, DSN_BY_LOCAL_MTA,
- "4.4.2", "421 lost connection",
- "lost connection with %s while %s",
- session->namaddr, description);
- break;
- case SMTP_ERR_TIME:
- lmtp_fill_dsn(state, &dsn, DSN_BY_LOCAL_MTA,
- "4.4.2", "426 conversation timed out",
- "conversation with %s timed out while %s",
- session->namaddr, description);
- break;
- case SMTP_ERR_PROTO:
- lmtp_fill_dsn(state, &dsn, DSN_BY_LOCAL_MTA,
- "4.5.0", "403 remote protocol error",
- "remote protocol error in reply from %s while %s",
- session->namaddr, description);
- break;
- }
- return (lmtp_bulk_fail(state, &dsn, LMTP_THROTTLE));
-}
/* discard(8), Postfix discard delivery agent
/* error(8), Postfix error delivery agent
/* flush(8), Postfix fast ETRN service
-/* lmtp(8), Postfix LMTP client
/* local(8), Postfix local delivery agent
/* master(8), Postfix master daemon
/* oqmgr(8), old Postfix queue manager
/* qmqpd(8), Postfix QMQP server
/* scache(8), Postfix connection cache manager
/* showq(8), list Postfix mail queue
-/* smtp(8), Postfix SMTP client
+/* smtp(8), lmtp(8), Postfix SMTP+LMTP client
/* smtpd(8), Postfix SMTP server
/* spawn(8), run non-Postfix server
/* tlsmgr(8), Postfix TLS cache and randomness manager
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
+/*
+/* SASL support originally by:
+/* Till Franke
+/* SuSE Rhein/Main AG
+/* 65760 Eschborn, Germany
+/*
+/* LMTP support originally by:
+/* Philip A. Prindeville
+/* Mirapoint, Inc.
+/* USA.
+/*
+/* Amos Gouaux
+/* University of Texas at Dallas
+/* P.O. Box 830688, MC34
+/* Richardson, TX 75083, USA
/*--*/
/* System library. */
/* queue IDs from standard input. For example, to delete all mail
/* with exactly one recipient \fBuser@example.com\fR:
/* .sp
-/* mailq | tail +2 | awk \'BEGIN { RS = "" }
+/* mailq | tail +2 | grep -v '^ *(' | awk \'BEGIN { RS = "" }
/* .ti +4
/* # $7=sender, $8=recipient1, $9=recipient2
/* .ti +4
* This routine runs whenever a client connects to the UNIX-domain socket
* dedicated to the scache service. All connection-management stuff is
* handled by the common code in multi_server.c.
+ *
+ * XXX Workaround: with some requests, the client sends a dummy message
+ * after the server replies (yes that's a botch). When the scache server
+ * is slow, this dummy message may become concatenated with the next
+ * request from the same client. The do-while loop below will repeat
+ * instead of discarding the client request. We must process it now
+ * because there will be no select() notification.
*/
- if (attr_scan(client_stream,
- ATTR_FLAG_MORE | ATTR_FLAG_STRICT,
- ATTR_TYPE_STR, MAIL_ATTR_REQ, scache_request,
- ATTR_TYPE_END) == 1) {
- if (VSTREQ(scache_request, SCACHE_REQ_SAVE_DEST)) {
- scache_save_dest_service(client_stream);
- } else if (VSTREQ(scache_request, SCACHE_REQ_FIND_DEST)) {
- scache_find_dest_service(client_stream);
- } else if (VSTREQ(scache_request, SCACHE_REQ_SAVE_ENDP)) {
- scache_save_endp_service(client_stream);
- } else if (VSTREQ(scache_request, SCACHE_REQ_FIND_ENDP)) {
- scache_find_endp_service(client_stream);
- } else {
- msg_warn("unrecognized request: \"%s\", ignored",
- STR(scache_request));
- attr_print(client_stream, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, MAIL_ATTR_STATUS, SCACHE_STAT_BAD,
- ATTR_TYPE_END);
+ do {
+ if (attr_scan(client_stream,
+ ATTR_FLAG_MORE | ATTR_FLAG_STRICT,
+ ATTR_TYPE_STR, MAIL_ATTR_REQ, scache_request,
+ ATTR_TYPE_END) == 1) {
+ if (VSTREQ(scache_request, SCACHE_REQ_SAVE_DEST)) {
+ scache_save_dest_service(client_stream);
+ } else if (VSTREQ(scache_request, SCACHE_REQ_FIND_DEST)) {
+ scache_find_dest_service(client_stream);
+ } else if (VSTREQ(scache_request, SCACHE_REQ_SAVE_ENDP)) {
+ scache_save_endp_service(client_stream);
+ } else if (VSTREQ(scache_request, SCACHE_REQ_FIND_ENDP)) {
+ scache_find_endp_service(client_stream);
+ } else {
+ msg_warn("unrecognized request: \"%s\", ignored",
+ STR(scache_request));
+ attr_print(client_stream, ATTR_FLAG_NONE,
+ ATTR_TYPE_NUM, MAIL_ATTR_STATUS, SCACHE_STAT_BAD,
+ ATTR_TYPE_END);
+ }
}
- }
+ } while (vstream_peek(client_stream) > 0);
vstream_fflush(client_stream);
}
../../libexec/$(PROG): $(PROG)
cp $(PROG) ../../libexec
+smtp.o: smtp.c smtp_params.c lmtp_params.c
+
+lmtp_params.c: smtp_params.c $(INC_DIR)/mail_params.h
+ egrep -v -f smtp-only smtp_params.c | \
+ sed 's/SMTP/LMTP/g; s/smtp_\([a-z]*_table\)/lmtp_\1/' >$@
+
printfck: $(OBJS) $(PROG)
rm -rf printfck
mkdir printfck
@$(EXPORT) make -f Makefile.in Makefile 1>&2
# do not edit below this line - it is generated by 'make depend'
+lmtp_params.o: lmtp_params.c
smtp.o: ../../include/argv.h
smtp.o: ../../include/attr.h
smtp.o: ../../include/debug_peer.h
smtp.o: ../../include/resolve_clnt.h
smtp.o: ../../include/scache.h
smtp.o: ../../include/string_list.h
+smtp.o: ../../include/stringops.h
smtp.o: ../../include/sys_defs.h
smtp.o: ../../include/tls.h
smtp.o: ../../include/tok822.h
smtp.o: ../../include/vbuf.h
smtp.o: ../../include/vstream.h
smtp.o: ../../include/vstring.h
+smtp.o: lmtp_params.c
smtp.o: smtp.c
smtp.o: smtp.h
+smtp.o: smtp_params.c
smtp.o: smtp_sasl.h
smtp_addr.o: ../../include/argv.h
smtp_addr.o: ../../include/attr.h
smtp_dsn.o: ../../include/dsn.h
smtp_dsn.o: ../../include/dsn_buf.h
smtp_dsn.o: ../../include/htable.h
+smtp_dsn.o: ../../include/mail_params.h
smtp_dsn.o: ../../include/maps.h
smtp_dsn.o: ../../include/match_list.h
smtp_dsn.o: ../../include/match_ops.h
smtp_map11.o: ../../include/vstring.h
smtp_map11.o: smtp.h
smtp_map11.o: smtp_map11.c
+smtp_params.o: smtp_params.c
smtp_proto.o: ../../include/argv.h
smtp_proto.o: ../../include/attr.h
smtp_proto.o: ../../include/bounce.h
smtp_reuse.o: ../../include/attr.h
smtp_reuse.o: ../../include/deliver_request.h
smtp_reuse.o: ../../include/dict.h
-smtp_reuse.o: ../../include/dns.h
smtp_reuse.o: ../../include/dsn.h
smtp_reuse.o: ../../include/dsn_buf.h
smtp_reuse.o: ../../include/htable.h
smtp_reuse.o: ../../include/match_ops.h
smtp_reuse.o: ../../include/msg.h
smtp_reuse.o: ../../include/msg_stats.h
-smtp_reuse.o: ../../include/myaddrinfo.h
smtp_reuse.o: ../../include/mymalloc.h
smtp_reuse.o: ../../include/recipient_list.h
smtp_reuse.o: ../../include/resolve_clnt.h
smtp_reuse.o: ../../include/scache.h
-smtp_reuse.o: ../../include/sock_addr.h
smtp_reuse.o: ../../include/string_list.h
smtp_reuse.o: ../../include/stringops.h
smtp_reuse.o: ../../include/sys_defs.h
smtp_sasl_glue.o: ../../include/dsn.h
smtp_sasl_glue.o: ../../include/dsn_buf.h
smtp_sasl_glue.o: ../../include/htable.h
+smtp_sasl_glue.o: ../../include/mail_addr_find.h
smtp_sasl_glue.o: ../../include/mail_params.h
smtp_sasl_glue.o: ../../include/maps.h
smtp_sasl_glue.o: ../../include/match_list.h
smtp_state.o: ../../include/maps.h
smtp_state.o: ../../include/match_list.h
smtp_state.o: ../../include/match_ops.h
+smtp_state.o: ../../include/msg.h
smtp_state.o: ../../include/msg_stats.h
smtp_state.o: ../../include/mymalloc.h
smtp_state.o: ../../include/recipient_list.h
--- /dev/null
+ static CONFIG_STR_TABLE lmtp_str_table[] = {
+ VAR_NOTIFY_CLASSES, DEF_NOTIFY_CLASSES, &var_notify_classes, 0, 0,
+ VAR_BESTMX_TRANSP, DEF_BESTMX_TRANSP, &var_bestmx_transp, 0, 0,
+ VAR_ERROR_RCPT, DEF_ERROR_RCPT, &var_error_rcpt, 1, 0,
+ VAR_LMTP_SASL_PASSWD, DEF_LMTP_SASL_PASSWD, &var_smtp_sasl_passwd, 0, 0,
+ VAR_LMTP_SASL_OPTS, DEF_LMTP_SASL_OPTS, &var_smtp_sasl_opts, 0, 0,
+#ifdef USE_TLS
+ VAR_LMTP_SASL_TLS_OPTS, DEF_LMTP_SASL_TLS_OPTS, &var_smtp_sasl_tls_opts, 0, 0,
+#endif
+ VAR_LMTP_SASL_MECHS, DEF_LMTP_SASL_MECHS, &var_smtp_sasl_mechs, 0, 0,
+ VAR_LMTP_BIND_ADDR, DEF_LMTP_BIND_ADDR, &var_smtp_bind_addr, 0, 0,
+ VAR_LMTP_BIND_ADDR6, DEF_LMTP_BIND_ADDR6, &var_smtp_bind_addr6, 0, 0,
+ VAR_LMTP_HELO_NAME, DEF_LMTP_HELO_NAME, &var_smtp_helo_name, 1, 0,
+ VAR_LMTP_HOST_LOOKUP, DEF_LMTP_HOST_LOOKUP, &var_smtp_host_lookup, 1, 0,
+ VAR_LMTP_CACHE_DEST, DEF_LMTP_CACHE_DEST, &var_smtp_cache_dest, 0, 0,
+ VAR_SCACHE_SERVICE, DEF_SCACHE_SERVICE, &var_scache_service, 1, 0,
+ VAR_LMTP_EHLO_DIS_WORDS, DEF_LMTP_EHLO_DIS_WORDS, &var_smtp_ehlo_dis_words, 0, 0,
+ VAR_LMTP_EHLO_DIS_MAPS, DEF_LMTP_EHLO_DIS_MAPS, &var_smtp_ehlo_dis_maps, 0, 0,
+ VAR_LMTP_TLS_PER_SITE, DEF_LMTP_TLS_PER_SITE, &var_smtp_tls_per_site, 0, 0,
+ VAR_PROP_EXTENSION, DEF_PROP_EXTENSION, &var_prop_extension, 0, 0,
+ VAR_LMTP_GENERIC_MAPS, DEF_LMTP_GENERIC_MAPS, &var_smtp_generic_maps, 0, 0,
+ VAR_LMTP_TCP_PORT, DEF_LMTP_TCP_PORT, &var_lmtp_tcp_port, 0, 0,
+ 0,
+ };
+ static CONFIG_TIME_TABLE lmtp_time_table[] = {
+ VAR_LMTP_CONN_TMOUT, DEF_LMTP_CONN_TMOUT, &var_smtp_conn_tmout, 0, 0,
+ VAR_LMTP_HELO_TMOUT, DEF_LMTP_HELO_TMOUT, &var_smtp_helo_tmout, 1, 0,
+ VAR_LMTP_XFWD_TMOUT, DEF_LMTP_XFWD_TMOUT, &var_smtp_xfwd_tmout, 1, 0,
+ VAR_LMTP_MAIL_TMOUT, DEF_LMTP_MAIL_TMOUT, &var_smtp_mail_tmout, 1, 0,
+ VAR_LMTP_RCPT_TMOUT, DEF_LMTP_RCPT_TMOUT, &var_smtp_rcpt_tmout, 1, 0,
+ VAR_LMTP_DATA0_TMOUT, DEF_LMTP_DATA0_TMOUT, &var_smtp_data0_tmout, 1, 0,
+ VAR_LMTP_DATA1_TMOUT, DEF_LMTP_DATA1_TMOUT, &var_smtp_data1_tmout, 1, 0,
+ VAR_LMTP_DATA2_TMOUT, DEF_LMTP_DATA2_TMOUT, &var_smtp_data2_tmout, 1, 0,
+ VAR_LMTP_RSET_TMOUT, DEF_LMTP_RSET_TMOUT, &var_smtp_rset_tmout, 1, 0,
+ VAR_LMTP_QUIT_TMOUT, DEF_LMTP_QUIT_TMOUT, &var_smtp_quit_tmout, 1, 0,
+ VAR_LMTP_PIX_THRESH, DEF_LMTP_PIX_THRESH, &var_smtp_pix_thresh, 0, 0,
+ VAR_LMTP_PIX_DELAY, DEF_LMTP_PIX_DELAY, &var_smtp_pix_delay, 1, 0,
+ VAR_LMTP_CACHE_CONNT, DEF_LMTP_CACHE_CONNT, &var_smtp_cache_conn, 1, 0,
+ VAR_LMTP_REUSE_TIME, DEF_LMTP_REUSE_TIME, &var_smtp_reuse_time, 1, 0,
+#ifdef USE_TLS
+ VAR_LMTP_STARTTLS_TMOUT, DEF_LMTP_STARTTLS_TMOUT, &var_smtp_starttls_tmout, 1, 0,
+#endif
+ VAR_SCACHE_PROTO_TMOUT, DEF_SCACHE_PROTO_TMOUT, &var_scache_proto_tmout, 1, 0,
+ 0,
+ };
+ static CONFIG_INT_TABLE lmtp_int_table[] = {
+ VAR_LMTP_LINE_LIMIT, DEF_LMTP_LINE_LIMIT, &var_smtp_line_limit, 0, 0,
+ VAR_LMTP_MXADDR_LIMIT, DEF_LMTP_MXADDR_LIMIT, &var_smtp_mxaddr_limit, 0, 0,
+ VAR_LMTP_MXSESS_LIMIT, DEF_LMTP_MXSESS_LIMIT, &var_smtp_mxsess_limit, 0, 0,
+#ifdef USE_TLS
+ VAR_LMTP_TLS_SCERT_VD, DEF_LMTP_TLS_SCERT_VD, &var_smtp_tls_scert_vd, 0, 0,
+#endif
+ 0,
+ };
+ static CONFIG_BOOL_TABLE lmtp_bool_table[] = {
+ VAR_LMTP_SKIP_5XX, DEF_LMTP_SKIP_5XX, &var_smtp_skip_5xx_greeting,
+ VAR_SKIP_QUIT_RESP, DEF_SKIP_QUIT_RESP, &var_skip_quit_resp,
+ VAR_LMTP_SASL_ENABLE, DEF_LMTP_SASL_ENABLE, &var_smtp_sasl_enable,
+ VAR_LMTP_RAND_ADDR, DEF_LMTP_RAND_ADDR, &var_smtp_rand_addr,
+ VAR_LMTP_QUOTE_821_ENV, DEF_LMTP_QUOTE_821_ENV, &var_smtp_quote_821_env,
+ VAR_LMTP_DEFER_MXADDR, DEF_LMTP_DEFER_MXADDR, &var_smtp_defer_mxaddr,
+ VAR_LMTP_SEND_XFORWARD, DEF_LMTP_SEND_XFORWARD, &var_smtp_send_xforward,
+ VAR_LMTP_CACHE_DEMAND, DEF_LMTP_CACHE_DEMAND, &var_smtp_cache_demand,
+ VAR_LMTP_USE_TLS, DEF_LMTP_USE_TLS, &var_smtp_use_tls,
+ VAR_LMTP_ENFORCE_TLS, DEF_LMTP_ENFORCE_TLS, &var_smtp_enforce_tls,
+#ifdef USE_TLS
+ VAR_LMTP_TLS_ENFORCE_PN, DEF_LMTP_TLS_ENFORCE_PN, &var_smtp_tls_enforce_peername,
+ VAR_LMTP_TLS_NOTEOFFER, DEF_LMTP_TLS_NOTEOFFER, &var_smtp_tls_note_starttls_offer,
+#endif
+ VAR_LMTP_SENDER_AUTH, DEF_LMTP_SENDER_AUTH, &var_smtp_sender_auth,
+ 0,
+ };
--- /dev/null
+_ALWAYS_EHLO
+_NEVER_EHLO
+_SMTP_FALLBACK
+_IGN_MX_LOOKUP_ERR
/* NAME
/* smtp 8
/* SUMMARY
-/* Postfix SMTP client
+/* Postfix SMTP+LMTP client
/* SYNOPSIS
/* \fBsmtp\fR [generic Postfix daemon options]
/* DESCRIPTION
-/* The Postfix SMTP client processes message delivery requests from
+/* The Postfix SMTP+LMTP client implements the SMTP and LMTP mail
+/* delivery protocols. It processes message delivery requests from
/* the queue manager. Each request specifies a queue file, a sender
/* address, a domain or host to deliver to, and recipient information.
/* This program expects to be run from the \fBmaster\fR(8) process
/* manager.
/*
-/* The SMTP client updates the queue file and marks recipients
+/* The SMTP+LMTP client updates the queue file and marks recipients
/* as finished, or it informs the queue manager that delivery should
/* be tried again at a later time. Delivery status reports are sent
/* to the \fBbounce\fR(8), \fBdefer\fR(8) or \fBtrace\fR(8) daemon as
/* appropriate.
/*
-/* The SMTP client looks up a list of mail exchanger addresses for
+/* The SMTP+LMTP client looks up a list of mail exchanger addresses for
/* the destination host, sorts the list by preference, and connects
/* to each listed address until it finds a server that responds.
/*
/* When a server is not reachable, or when mail delivery fails due
-/* to a recoverable error condition, the SMTP client will try to
+/* to a recoverable error condition, the SMTP+LMTP client will try to
/* deliver the mail to an alternate host.
/*
/* After a successful mail transaction, a connection may be saved
/* to the \fBscache\fR(8) connection cache server, so that it
-/* may be used by any SMTP client for a subsequent transaction.
+/* may be used by any SMTP+LMTP client for a subsequent transaction.
/*
/* By default, connection caching is enabled temporarily for
/* destinations that have a high volume of mail in the active
/* queue. Session caching can be enabled permanently for
/* specific destinations.
+/* SMTP DESTINATION SYNTAX
+/* .ad
+/* .fi
+/* SMTP destinations have the following form:
+/* .IP "\fIdomainname\fR, \fIdomainname\fR:\fIport\fR"
+/* Look up the mail exchangers for the specified domain.
+/* .IP "[\fIhostname\fR], [\fIhostname\fR]:\fIport\fR"
+/* Look up the address of the specified host.
+/* .IP "[\fIaddress\fR], [\fIaddress\fR]:\fIport\fR"
+/* Connect to the host at the specified address. An IPv6
+/* address must be formatted as [\fBipv6\fR:\fIaddress\fR].
+/* .PP
+/* In all the above cases, when no port is specified, look up
+/* the port defined as \fBsmtp\fR in \fBservices\fR(4).
+/* LMTP DESTINATION SYNTAX
+/* .ad
+/* .fi
+/* LMTP destinations have the following form:
+/* .IP \fBunix\fR:\fIpathname\fR
+/* Connect to the local UNIX-domain server that is bound to the specified
+/* \fIpathname\fR. If the process runs chrooted, an absolute pathname
+/* is interpreted relative to the Postfix queue directory.
+/* .IP "\fBinet\fR:\fIhostname\fR, \fBinet\fB:\fIhostname\fR:\fIport\fR"
+/* .IP "\fBinet\fR:[\fIaddress\fR], \fBinet\fR:[\fIaddress\fR]:\fIport\fR"
+/* Connect to the specified TCP port on the specified local or
+/* remote host. If no port is specified, connect to the port defined as
+/* \fBlmtp\fR in \fBservices\fR(4).
+/* If no such service is found, the \fBlmtp_tcp_port\fR configuration
+/* parameter (default value of 24) will be used.
+/* .PP
/* SECURITY
/* .ad
/* .fi
-/* The SMTP client is moderately security-sensitive. It talks to SMTP
-/* servers and to DNS servers on the network. The SMTP client can be
-/* run chrooted at fixed low privilege.
+/* The SMTP+LMTP client is moderately security-sensitive. It
+/* talks to SMTP or LMTP servers and to DNS servers on the
+/* network. The SMTP+LMTP client can be run chrooted at fixed
+/* low privilege.
/* STANDARDS
/* RFC 821 (SMTP protocol)
/* RFC 822 (ARPA Internet Text Messages)
/* RFC 1651 (SMTP service extensions)
/* RFC 1652 (8bit-MIME transport)
/* RFC 1870 (Message Size Declaration)
-/* RFC 2045 (MIME: Format of Internet Message Bodies)
+/* RFC 2033 (LMTP protocol)
/* RFC 2034 (Enhanced Status Codes)
+/* RFC 2045 (MIME: Format of Internet Message Bodies)
/* RFC 2046 (MIME: Media Types)
/* RFC 2554 (AUTH command)
/* RFC 2821 (SMTP protocol)
/* the postmaster is notified of bounces, protocol problems, and of
/* other trouble.
/* BUGS
-/* SMTP connection caching does not work with TLS. The necessary
+/* SMTP and LMTP connection caching does not work with TLS. The necessary
/* support for TLS object passivation and re-activation does not
/* exist without closing the session, which defeats the purpose.
/*
-/* SMTP connection caching assumes that SASL credentials are valid for
-/* all destinations that map onto the same IP address and TCP port.
+/* SMTP and LMTP connection caching assumes that SASL credentials
+/* are valid for all destinations that map onto the same IP
+/* address and TCP port.
/* CONFIGURATION PARAMETERS
/* .ad
/* .fi
+/* Most smtp_\fIxxx\fR configuration parameters have an
+/* lmtp_\fIxxx\fR "ghost" parameter for the equivalent LMTP
+/* feature. This document describes only those LMTP-related
+/* parameters that aren't simply "ghost" parameters.
+/*
/* Changes to \fBmain.cf\fR are picked up automatically, as \fBsmtp\fR(8)
/* processes run for only a limited amount of time. Use the command
/* "\fBpostfix reload\fR" to speed up a change.
/* Optional lookup tables that perform address rewriting in the
/* SMTP client, typically to transform a locally valid address into
/* a globally valid address when sending mail across the Internet.
+/* .PP
+/* Available in Postfix version 2.3 and later:
+/* .IP "\fBlmtp_discard_lhlo_keyword_address_maps (empty)\fR"
+/* Lookup tables, indexed by the remote LMTP server address, with
+/* case insensitive lists of LHLO keywords (pipelining, starttls,
+/* auth, etc.) that the LMTP client will ignore in the LHLO response
+/* from a remote LMTP server.
+/* .IP "\fBlmtp_discard_lhlo_keywords ($myhostname)\fR"
+/* A case insensitive list of LHLO keywords (pipelining, starttls,
+/* auth, etc.) that the LMTP client will ignore in the LHLO response
+/* from a remote LMTP server.
/* MIME PROCESSING CONTROLS
/* .ad
/* .fi
/* .IP "\fBsmtp_helo_timeout (300s)\fR"
/* The SMTP client time limit for sending the HELO or EHLO command,
/* and for receiving the initial server response.
+/* .IP "\fBlmtp_lhlo_timeout (300s)\fR"
+/* The LMTP client time limit for sending the LHLO command, and
+/* for receiving the initial server response.
/* .IP "\fBsmtp_xforward_timeout (300s)\fR"
/* The SMTP client time limit for sending the XFORWARD command, and
/* for receiving the server response.
/* .IP "\fBsmtp_connection_cache_time_limit (2s)\fR"
/* When SMTP connection caching is enabled, the amount of time that
/* an unused SMTP client socket is kept open before it is closed.
+/* .PP
+/* Available in Postfix version 2.3 and later:
+/* .IP "\fBconnection_cache_protocol_timeout (5s)\fR"
+/* Time limit for connection cache connect, send or receive
+/* operations.
/* TROUBLE SHOOTING CONTROLS
/* .ad
/* .fi
/* sub-second delay values.
/* .IP "\fBdisable_dns_lookups (no)\fR"
/* Disable DNS lookups in the Postfix SMTP and LMTP clients.
-/* .IP "\fBfallback_relay (empty)\fR"
-/* Optional list of relay hosts for SMTP destinations that can't be
-/* found or that are unreachable.
/* .IP "\fBinet_interfaces (all)\fR"
/* The network interface addresses that this mail system receives
/* mail on.
/* .IP "\fBipc_timeout (3600s)\fR"
/* The time limit for sending or receiving information over an internal
/* communication channel.
+/* .IP "\fBlmtp_tcp_port (24)\fR"
+/* The default TCP port that the Postfix LMTP client connects to.
/* .IP "\fBmax_idle (100s)\fR"
/* The maximum amount of time that an idle Postfix daemon process
/* waits for the next service request before exiting.
/* bind to when making an IPv6 connection.
/* .IP "\fBsmtp_helo_name ($myhostname)\fR"
/* The hostname to send in the SMTP EHLO or HELO command.
+/* .IP "\fBlmtp_lhlo_name ($myhostname)\fR"
+/* The hostname to send in the LMTP LHLO command.
/* .IP "\fBsmtp_host_lookup (dns)\fR"
/* What mechanisms when the SMTP client uses to look up a host's IP
/* address.
/* .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".
+/* .PP
+/* Available with Postfix 2.2 and earlier:
+/* .IP "\fBfallback_relay (empty)\fR"
+/* Optional list of relay hosts for SMTP destinations that can't be
+/* found or that are unreachable.
+/* .PP
+/* Available with Postfix 2.3 and later:
+/* .IP "\fBsmtp_fallback_relay ($fallback_relay)\fR"
+/* Optional list of relay hosts for SMTP destinations that can't be
+/* found or that are unreachable.
/* SEE ALSO
/* qmgr(8), queue manager
/* bounce(8), delivery status reports
#include <string.h>
#include <fcntl.h>
#include <dict.h>
+#include <stringops.h>
/* Utility library. */
char *var_smtp_generic_maps;
char *var_prop_extension;
bool var_smtp_sender_auth;
+char *var_lmtp_tcp_port;
+int var_scache_proto_tmout;
/*
* Global variables. smtp_errno is set by the address lookup routines and by
smtp_scache = scache_multi_create();
#else
smtp_scache = scache_clnt_create(var_scache_service,
+ var_scache_proto_tmout,
var_ipc_idle_limit,
var_ipc_ttl_limit);
#endif
int main(int argc, char **argv)
{
- static CONFIG_STR_TABLE str_table[] = {
- VAR_NOTIFY_CLASSES, DEF_NOTIFY_CLASSES, &var_notify_classes, 0, 0,
- VAR_FALLBACK_RELAY, DEF_FALLBACK_RELAY, &var_fallback_relay, 0, 0,
- VAR_BESTMX_TRANSP, DEF_BESTMX_TRANSP, &var_bestmx_transp, 0, 0,
- VAR_ERROR_RCPT, DEF_ERROR_RCPT, &var_error_rcpt, 1, 0,
- VAR_SMTP_SASL_PASSWD, DEF_SMTP_SASL_PASSWD, &var_smtp_sasl_passwd, 0, 0,
- VAR_SMTP_SASL_OPTS, DEF_SMTP_SASL_OPTS, &var_smtp_sasl_opts, 0, 0,
-#ifdef USE_TLS
- VAR_SMTP_SASL_TLS_OPTS, DEF_SMTP_SASL_TLS_OPTS, &var_smtp_sasl_tls_opts, 0, 0,
-#endif
- VAR_SMTP_SASL_MECHS, DEF_SMTP_SASL_MECHS, &var_smtp_sasl_mechs, 0, 0,
- VAR_SMTP_BIND_ADDR, DEF_SMTP_BIND_ADDR, &var_smtp_bind_addr, 0, 0,
- VAR_SMTP_BIND_ADDR6, DEF_SMTP_BIND_ADDR6, &var_smtp_bind_addr6, 0, 0,
- VAR_SMTP_HELO_NAME, DEF_SMTP_HELO_NAME, &var_smtp_helo_name, 1, 0,
- VAR_SMTP_HOST_LOOKUP, DEF_SMTP_HOST_LOOKUP, &var_smtp_host_lookup, 1, 0,
- VAR_SMTP_CACHE_DEST, DEF_SMTP_CACHE_DEST, &var_smtp_cache_dest, 0, 0,
- VAR_SCACHE_SERVICE, DEF_SCACHE_SERVICE, &var_scache_service, 1, 0,
- VAR_SMTP_EHLO_DIS_WORDS, DEF_SMTP_EHLO_DIS_WORDS, &var_smtp_ehlo_dis_words, 0, 0,
- VAR_SMTP_EHLO_DIS_MAPS, DEF_SMTP_EHLO_DIS_MAPS, &var_smtp_ehlo_dis_maps, 0, 0,
- VAR_SMTP_TLS_PER_SITE, DEF_SMTP_TLS_PER_SITE, &var_smtp_tls_per_site, 0, 0,
- VAR_PROP_EXTENSION, DEF_PROP_EXTENSION, &var_prop_extension, 0, 0,
- VAR_SMTP_GENERIC_MAPS, DEF_SMTP_GENERIC_MAPS, &var_smtp_generic_maps, 0, 0,
- 0,
- };
- static CONFIG_TIME_TABLE time_table[] = {
- VAR_SMTP_CONN_TMOUT, DEF_SMTP_CONN_TMOUT, &var_smtp_conn_tmout, 0, 0,
- VAR_SMTP_HELO_TMOUT, DEF_SMTP_HELO_TMOUT, &var_smtp_helo_tmout, 1, 0,
- VAR_SMTP_XFWD_TMOUT, DEF_SMTP_XFWD_TMOUT, &var_smtp_xfwd_tmout, 1, 0,
- VAR_SMTP_MAIL_TMOUT, DEF_SMTP_MAIL_TMOUT, &var_smtp_mail_tmout, 1, 0,
- VAR_SMTP_RCPT_TMOUT, DEF_SMTP_RCPT_TMOUT, &var_smtp_rcpt_tmout, 1, 0,
- VAR_SMTP_DATA0_TMOUT, DEF_SMTP_DATA0_TMOUT, &var_smtp_data0_tmout, 1, 0,
- VAR_SMTP_DATA1_TMOUT, DEF_SMTP_DATA1_TMOUT, &var_smtp_data1_tmout, 1, 0,
- VAR_SMTP_DATA2_TMOUT, DEF_SMTP_DATA2_TMOUT, &var_smtp_data2_tmout, 1, 0,
- VAR_SMTP_RSET_TMOUT, DEF_SMTP_RSET_TMOUT, &var_smtp_rset_tmout, 1, 0,
- VAR_SMTP_QUIT_TMOUT, DEF_SMTP_QUIT_TMOUT, &var_smtp_quit_tmout, 1, 0,
- VAR_SMTP_PIX_THRESH, DEF_SMTP_PIX_THRESH, &var_smtp_pix_thresh, 0, 0,
- VAR_SMTP_PIX_DELAY, DEF_SMTP_PIX_DELAY, &var_smtp_pix_delay, 1, 0,
- VAR_SMTP_CACHE_CONN, DEF_SMTP_CACHE_CONN, &var_smtp_cache_conn, 1, 0,
- VAR_SMTP_REUSE_TIME, DEF_SMTP_REUSE_TIME, &var_smtp_reuse_time, 1, 0,
-#ifdef USE_TLS
- VAR_SMTP_STARTTLS_TMOUT, DEF_SMTP_STARTTLS_TMOUT, &var_smtp_starttls_tmout, 1, 0,
-#endif
- 0,
- };
- static CONFIG_INT_TABLE int_table[] = {
- VAR_SMTP_LINE_LIMIT, DEF_SMTP_LINE_LIMIT, &var_smtp_line_limit, 0, 0,
- VAR_SMTP_MXADDR_LIMIT, DEF_SMTP_MXADDR_LIMIT, &var_smtp_mxaddr_limit, 0, 0,
- VAR_SMTP_MXSESS_LIMIT, DEF_SMTP_MXSESS_LIMIT, &var_smtp_mxsess_limit, 0, 0,
-#ifdef USE_TLS
- VAR_SMTP_TLS_SCERT_VD, DEF_SMTP_TLS_SCERT_VD, &var_smtp_tls_scert_vd, 0, 0,
-#endif
- 0,
- };
- static CONFIG_BOOL_TABLE bool_table[] = {
- VAR_SMTP_SKIP_5XX, DEF_SMTP_SKIP_5XX, &var_smtp_skip_5xx_greeting,
- VAR_IGN_MX_LOOKUP_ERR, DEF_IGN_MX_LOOKUP_ERR, &var_ign_mx_lookup_err,
- VAR_SKIP_QUIT_RESP, DEF_SKIP_QUIT_RESP, &var_skip_quit_resp,
- VAR_SMTP_ALWAYS_EHLO, DEF_SMTP_ALWAYS_EHLO, &var_smtp_always_ehlo,
- VAR_SMTP_NEVER_EHLO, DEF_SMTP_NEVER_EHLO, &var_smtp_never_ehlo,
- VAR_SMTP_SASL_ENABLE, DEF_SMTP_SASL_ENABLE, &var_smtp_sasl_enable,
- VAR_SMTP_RAND_ADDR, DEF_SMTP_RAND_ADDR, &var_smtp_rand_addr,
- VAR_SMTP_QUOTE_821_ENV, DEF_SMTP_QUOTE_821_ENV, &var_smtp_quote_821_env,
- VAR_SMTP_DEFER_MXADDR, DEF_SMTP_DEFER_MXADDR, &var_smtp_defer_mxaddr,
- VAR_SMTP_SEND_XFORWARD, DEF_SMTP_SEND_XFORWARD, &var_smtp_send_xforward,
- VAR_SMTP_CACHE_DEMAND, DEF_SMTP_CACHE_DEMAND, &var_smtp_cache_demand,
- VAR_SMTP_USE_TLS, DEF_SMTP_USE_TLS, &var_smtp_use_tls,
- VAR_SMTP_ENFORCE_TLS, DEF_SMTP_ENFORCE_TLS, &var_smtp_enforce_tls,
-#ifdef USE_TLS
- VAR_SMTP_TLS_ENFORCE_PN, DEF_SMTP_TLS_ENFORCE_PN, &var_smtp_tls_enforce_peername,
- VAR_SMTP_TLS_NOTEOFFER, DEF_SMTP_TLS_NOTEOFFER, &var_smtp_tls_note_starttls_offer,
-#endif
- VAR_SMTP_SENDER_AUTH, DEF_SMTP_SENDER_AUTH, &var_smtp_sender_auth,
+#include "smtp_params.c"
+#include "lmtp_params.c"
+ int smtp_mode;
- 0,
- };
+ /*
+ * XXX At this point, var_procname etc. are not initialized.
+ */
+ smtp_mode = (strcmp(sane_basename((VSTRING *) 0, argv[0]), "smtp") == 0);
+ /*
+ * Initialize with the LMTP or SMTP parameter name space.
+ */
single_server_main(argc, argv, smtp_service,
- MAIL_SERVER_TIME_TABLE, time_table,
- MAIL_SERVER_INT_TABLE, int_table,
- MAIL_SERVER_STR_TABLE, str_table,
- MAIL_SERVER_BOOL_TABLE, bool_table,
+ MAIL_SERVER_TIME_TABLE, smtp_mode ?
+ smtp_time_table : lmtp_time_table,
+ MAIL_SERVER_INT_TABLE, smtp_mode ?
+ smtp_int_table : lmtp_int_table,
+ MAIL_SERVER_STR_TABLE, smtp_mode ?
+ smtp_str_table : lmtp_str_table,
+ MAIL_SERVER_BOOL_TABLE, smtp_mode ?
+ smtp_bool_table : lmtp_bool_table,
MAIL_SERVER_PRE_INIT, pre_init,
MAIL_SERVER_POST_INIT, post_init,
MAIL_SERVER_PRE_ACCEPT, pre_accept,
* Session-specific state is stored separately.
*/
typedef struct SMTP_STATE {
+ int misc_flags; /* processing flags, see below */
VSTREAM *src; /* queue file stream */
const char *service; /* transport name */
DELIVER_REQUEST *request; /* envelope info, offsets */
*/
#define SMTP_MISC_FLAG_LOOP_DETECT (1<<0)
#define SMTP_MISC_FLAG_IN_STARTTLS (1<<1)
-
-#define SMTP_MISC_FLAG_DEFAULT SMTP_MISC_FLAG_LOOP_DETECT
+#define SMTP_MISC_FLAG_USE_LMTP (1<<2)
/*
* smtp.c
/*
* smtp_proto.c
*/
-extern int smtp_helo(SMTP_STATE *, int);
+extern int smtp_helo(SMTP_STATE *);
extern int smtp_xfer(SMTP_STATE *);
extern int smtp_rset(SMTP_STATE *);
extern int smtp_quit(SMTP_STATE *);
/* NAME
/* smtp_connect 3
/* SUMMARY
-/* connect to SMTP server and deliver
+/* connect to SMTP/LMTP server and deliver
/* SYNOPSIS
/* #include "smtp.h"
/*
/* int smtp_connect(state)
/* SMTP_STATE *state;
/* DESCRIPTION
-/* This module implements SMTP connection management and controls
+/* This module implements SMTP/LMTP connection management and controls
/* mail delivery.
/*
-/* smtp_connect() attempts to establish an SMTP session with a host
+/* smtp_connect() attempts to establish an SMTP/LMTP session with a host
/* that represents the destination domain, or with an optional fallback
/* relay when the destination cannot be found, or when all the
/* destination servers are unavailable. It skips over IP addresses
-/* that fail to complete the SMTP handshake and tries to find
-/* an alternate server when an SMTP session fails to deliver.
+/* that fail to complete the SMTP/LMTP handshake and tries to find
+/* an alternate server when an SMTP/LMTP session fails to deliver.
/*
-/* This layer also controls what sessions are retrieved from
-/* the session cache, and what sessions are saved to the cache.
+/* This layer also controls what connections are retrieved from
+/* the connection cache, and what connections are saved to the cache.
/*
/* The destination is either a host (or domain) name or a numeric
/* address. Symbolic or numeric service port information may be
-/* appended, separated by a colon (":").
+/* appended, separated by a colon (":"). In the case of LMTP,
+/* destinations may be specified as "unix:pathname", "inet:host"
+/* or "inet:host:port".
/*
/* By default, the Internet domain name service is queried for mail
/* exchanger hosts. Quote the domain name with `[' and `]' to
#include <sys_defs.h>
#include <stdlib.h>
#include <sys/socket.h>
+#include <sys/un.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <smtp_addr.h>
#include <smtp_reuse.h>
+ /*
+ * Forward declaration.
+ */
+static SMTP_SESSION *smtp_connect_sock(int, struct sockaddr *, int,
+ const char *, const char *,
+ unsigned,
+ const char *, DSN_BUF *,
+ int);
+
+/* smtp_connect_unix - connect to UNIX-domain address */
+
+static SMTP_SESSION *smtp_connect_unix(const char *addr,
+ DSN_BUF *why,
+ int sess_flags)
+{
+ char *myname = "smtp_connect_unix";
+ struct sockaddr_un sock_un;
+ int len = strlen(addr);
+ int sock;
+
+ smtp_errno = SMTP_ERR_NONE; /* Paranoia */
+
+ /*
+ * Sanity checks.
+ */
+ if (len >= (int) sizeof(sock_un.sun_path)) {
+ msg_warn("unix-domain name too long: %s", addr);
+ smtp_dsn_update(why, DSN_BY_LOCAL_MTA, "4.3.5",
+ 450, "450 Mail server configuration error",
+ "Server configuration error");
+ smtp_errno = SMTP_ERR_RETRY;
+ return (0);
+ }
+
+ /*
+ * Initialize.
+ */
+ memset((char *) &sock_un, 0, sizeof(sock_un));
+ sock_un.sun_family = AF_UNIX;
+#ifdef HAS_SUN_LEN
+ sock_un.sun_len = len + 1;
+#endif
+ memcpy(sock_un.sun_path, addr, len + 1);
+
+ /*
+ * Create a client socket.
+ */
+ if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
+ msg_fatal("%s: socket: %m", myname);
+
+ /*
+ * Connect to the server.
+ */
+ if (msg_verbose)
+ msg_info("%s: trying: %s...", myname, addr);
+
+ return (smtp_connect_sock(sock, (struct sockaddr *) & sock_un,
+ sizeof(sock_un), var_myhostname, addr,
+ 0, addr, why, sess_flags));
+}
+
/* smtp_connect_addr - connect to explicit address */
-static SMTP_SESSION *smtp_connect_addr(const char *dest, DNS_RR *addr,
+static SMTP_SESSION *smtp_connect_addr(const char *destination, DNS_RR *addr,
unsigned port, DSN_BUF *why,
int sess_flags)
{
SOCKADDR_SIZE salen = sizeof(ss);
MAI_HOSTADDR_STR hostaddr;
int sock;
- int conn_stat;
- int saved_errno;
- VSTREAM *stream;
- int ch;
char *bind_addr;
char *bind_var;
- time_t start_time;
smtp_errno = SMTP_ERR_NONE; /* Paranoia */
}
/*
- * Connect to the SMTP server.
+ * Connect to the server.
*/
SOCKADDR_TO_HOSTADDR(sa, salen, &hostaddr, (MAI_SERVPORT_STR *) 0, 0);
if (msg_verbose)
msg_info("%s: trying: %s[%s] port %d...",
myname, addr->name, hostaddr.buf, ntohs(port));
+
+ return (smtp_connect_sock(sock, sa, salen, addr->name, hostaddr.buf,
+ port, destination, why, sess_flags));
+}
+
+/* smtp_connect_sock - connect a socket over some transport */
+
+static SMTP_SESSION *smtp_connect_sock(int sock, struct sockaddr * sa,
+ int salen, const char *name,
+ const char *addr,
+ unsigned port,
+ const char *destination,
+ DSN_BUF *why,
+ int sess_flags)
+{
+ int conn_stat;
+ int saved_errno;
+ VSTREAM *stream;
+ int ch;
+ time_t start_time;
+
start_time = time((time_t *) 0);
if (var_smtp_conn_tmout > 0) {
non_blocking(sock, NON_BLOCKING);
if (conn_stat < 0) {
smtp_dsn_update(why, DSN_BY_LOCAL_MTA,
"4.4.1", 420, "420 Unable to connect to server",
- "connect to %s[%s]: %m", addr->name, hostaddr.buf);
+ "connect to %s[%s]: %m", name, addr);
smtp_errno = SMTP_ERR_RETRY;
close(sock);
return (0);
/*
* Bundle up what we have into a nice SMTP_SESSION object.
*/
- return (smtp_session_alloc(stream, dest, addr->name, hostaddr.buf,
+ return (smtp_session_alloc(stream, destination, name, addr,
port, start_time, sess_flags));
}
-/* smtp_parse_destination - parse destination */
+/* smtp_parse_destination - parse host/port destination */
static char *smtp_parse_destination(char *destination, char *def_service,
char **hostp, unsigned *portp)
* Convert service to port number, network byte order.
*/
if (alldig(service)) {
- if ((port = atoi(service)) >= 65536)
+ if ((port = atoi(service)) >= 65536 || port == 0)
msg_fatal("bad network port in destination: %s", destination);
*portp = htons(port);
} else {
request->msg_stats.reuse_count = 0;
}
+/* smtp_connect_local - connect to local server */
+
+static void smtp_connect_local(SMTP_STATE *state, const char *path,
+ DSN_BUF *why)
+{
+ DELIVER_REQUEST *request = state->request;
+ int sess_flags = SMTP_SESS_FLAG_NONE;
+ SMTP_SESSION *session;
+
+ /*
+ * It's too painful to weave this code into the SMTP connection
+ * management routine.
+ *
+ * Connection cache management is based on the UNIX-domain pathname, without
+ * the "unix:" prefix.
+ *
+ * XXX Disable connection caching when sender-dependent authentication is
+ * enabled. We must not send someone elses mail over an authenticated
+ * connection, and we must not send mail that requires authentication
+ * over a connection that wasn't authenticated.
+ */
+#define CAN_ENABLE_CONN_CACHE(request, dest) \
+ (!var_smtp_sender_auth \
+ && ((var_smtp_cache_demand && (request->flags & DEL_REQ_FLAG_SCACHE)) \
+ || (smtp_cache_dest && string_list_match(smtp_cache_dest, dest))))
+
+ if (CAN_ENABLE_CONN_CACHE(request, path))
+ sess_flags |= SMTP_SESS_FLAG_CACHE;
+
+ /*
+ * XXX We assume that the session->addr member refers to a copy of the
+ * UNIX-domain pathname, so that smtp_save_session() will cache the
+ * connection using the pathname as the physical endpoint name.
+ */
+#define NO_MX 0
+#define NO_PORT 0
+
+ if ((sess_flags & SMTP_SESS_FLAG_CACHE) == 0
+ || (session = smtp_reuse_addr(state, path, NO_PORT)) == 0)
+ session = smtp_connect_unix(path, why, sess_flags);
+ if ((state->session = session) != 0) {
+ session->state = state;
+ /* All delivery errors bounce or defer. */
+ state->final_server = 1;
+ if ((session->features & SMTP_FEATURE_FROM_CACHE) == 0
+ && smtp_helo(state) != 0) {
+ if (vstream_ferror(session->stream) == 0
+ && vstream_feof(session->stream) == 0)
+ smtp_quit(state);
+ } else {
+ smtp_xfer(state);
+ }
+ smtp_cleanup_session(state);
+ }
+}
+
/* smtp_scrub_address_list - delete all cached addresses from list */
static void smtp_scrub_addr_list(HTABLE *cached_addr, DNS_RR **addr_list)
DNS_RR *addr;
DNS_RR *next;
int saved_final_server = state->final_server;
+ MAI_HOSTADDR_STR hostaddr;
SMTP_SESSION *session;
/*
if (addr->pref != domain_best_pref)
break;
next = addr->next;
- if ((session = smtp_reuse_addr(state, addr, port)) != 0) {
+ if (dns_rr_to_pa(addr, &hostaddr) != 0
+ && (session = smtp_reuse_addr(state, hostaddr.buf, port)) != 0) {
session->features |= SMTP_FEATURE_BEST_MX;
session_count += 1;
smtp_update_addr_list(addr_list, session->addr, session_count);
return (session_count);
}
-/* smtp_connect - establish SMTP connection */
+/* smtp_connect_remote - establish remote connection */
-int smtp_connect(SMTP_STATE *state)
+static void smtp_connect_remote(SMTP_STATE *state, const char *nexthop,
+ DSN_BUF *why)
{
DELIVER_REQUEST *request = state->request;
- DSN_BUF *why = dsb_create();
- char *dest_buf;
- char *domain;
- unsigned port;
- char *def_service = "smtp"; /* XXX ##IPPORT_SMTP? */
+ char *def_service;
ARGV *sites;
char *dest;
char **cpp;
- DNS_RR *addr_list;
- DNS_RR *addr;
- DNS_RR *next;
- int addr_count;
- int sess_count;
- int misc_flags = SMTP_MISC_FLAG_DEFAULT;
- SMTP_SESSION *session;
- int lookup_mx;
- unsigned domain_best_pref;
int sess_flags = SMTP_SESS_FLAG_NONE;
- int i_am_mx = 0;
int non_fallback_sites;
+ int saved_misc_flags = state->misc_flags;
/*
* First try to deliver to the indicated destination, then try to deliver
if (sites->argc == 0)
msg_panic("null destination: \"%s\"", request->nexthop);
non_fallback_sites = sites->argc;
- argv_split_append(sites, var_fallback_relay, ", \t\r\n");
+ if ((state->misc_flags & SMTP_MISC_FLAG_USE_LMTP) == 0) {
+ argv_split_append(sites, var_fallback_relay, ", \t\r\n");
+ def_service = "smtp"; /* XXX ##IPPORT_SMTP? */
+ } else {
+ def_service = var_lmtp_tcp_port;
+ }
/*
* Don't give up after a hard host lookup error until we have tried the
(*(cpp) && (cpp) >= (sites)->argv + (non_fallback_sites))
for (cpp = sites->argv; SMTP_RCPT_LEFT(state) > 0 && (dest = *cpp) != 0; cpp++) {
+ char *dest_buf;
+ char *domain;
+ unsigned port;
+ DNS_RR *addr_list;
+ DNS_RR *addr;
+ DNS_RR *next;
+ int addr_count;
+ int sess_count;
+ SMTP_SESSION *session;
+ int lookup_mx;
+ unsigned domain_best_pref;
+ MAI_HOSTADDR_STR hostaddr;
+
+ state->misc_flags = saved_misc_flags;
/*
* Parse the destination. Default is to use the SMTP port. Look up
*/
if (msg_verbose)
msg_info("connecting to %s port %d", domain, ntohs(port));
- if (ntohs(port) != IPPORT_SMTP)
- misc_flags &= ~SMTP_MISC_FLAG_LOOP_DETECT;
- else
- misc_flags |= SMTP_MISC_FLAG_LOOP_DETECT;
- lookup_mx = (var_disable_dns == 0 && *dest != '[');
+ if ((state->misc_flags & SMTP_MISC_FLAG_USE_LMTP) == 0) {
+ if (ntohs(port) == IPPORT_SMTP)
+ state->misc_flags |= SMTP_MISC_FLAG_LOOP_DETECT;
+ lookup_mx = (var_disable_dns == 0 && *dest != '[');
+ } else
+ lookup_mx = 0;
if (!lookup_mx) {
- addr_list = smtp_host_addr(domain, misc_flags, why);
+ addr_list = smtp_host_addr(domain, state->misc_flags, why);
/* XXX We could be an MX host for this destination... */
} else {
- addr_list = smtp_domain_addr(domain, misc_flags, why, &i_am_mx);
+ int i_am_mx = 0;
+
+ addr_list = smtp_domain_addr(domain, state->misc_flags,
+ why, &i_am_mx);
/* If we're MX host, don't connect to non-MX backups. */
if (i_am_mx)
argv_truncate(sites, cpp - sites->argv + 1);
}
- state->final_server = (cpp[1] == 0);
+
+ /*
+ * Don't try any backup host if mail loops to myself. That would just
+ * make the problem worse.
+ */
+ if (addr_list == 0 && smtp_errno == SMTP_ERR_LOOP) {
+ myfree(dest_buf);
+ break;
+ }
+
+ /*
+ * No early loop exit or we have a memory leak with dest_buf.
+ */
+ if (addr_list)
+ domain_best_pref = addr_list->pref;
/*
* When session caching is enabled, store the first good session for
* authenticated connection, and we must not send mail that requires
* authentication over a connection that wasn't authenticated.
*/
- if (cpp == sites->argv
- && !var_smtp_sender_auth
- && ((var_smtp_cache_demand && (request->flags & DEL_REQ_FLAG_SCACHE) != 0)
- || (smtp_cache_dest && string_list_match(smtp_cache_dest, domain)))) {
+ if (cpp == sites->argv && CAN_ENABLE_CONN_CACHE(request, domain)) {
sess_flags |= SMTP_SESS_FLAG_CACHE;
SET_NEXTHOP_STATE(state, lookup_mx, domain, port);
}
- /*
- * Don't try any backup host if mail loops to myself. That would just
- * make the problem worse.
- */
- if (addr_list == 0 && smtp_errno == SMTP_ERR_LOOP) {
- myfree(dest_buf);
- break;
- }
-
- /*
- * No early loop exit or we have a memory leak with dest_buf.
- */
- if (addr_list)
- domain_best_pref = addr_list->pref;
-
/*
* Delete visited cached hosts from the address list.
*
* Optionally search the connection cache by domain name or by primary
- * MX address.
+ * MX address before we try to create new connections.
*
* Enforce the MX session and MX address counts per next-hop or
* fall-back destination. smtp_reuse_session() will truncate the
if (addr_list && (sess_flags & SMTP_SESS_FLAG_CACHE) != 0) {
if (state->cache_used->used > 0)
smtp_scrub_addr_list(state->cache_used, &addr_list);
+ /* Count delivery errors towards the session limit. */
+ state->final_server = (cpp[1] == 0);
sess_count = addr_count =
smtp_reuse_session(state, lookup_mx, domain, port,
&addr_list, domain_best_pref);
sess_count = addr_count = 0;
/*
- * Connect to an SMTP server.
+ * Connect to an SMTP server: create primary MX connections, and
+ * reuse or create backup MX connections.
*
* At the start of an SMTP session, all recipients are unmarked. In the
* course of an SMTP session, recipients are marked as KEEP (deliver
next = 0;
if ((sess_flags & SMTP_SESS_FLAG_CACHE) == 0
|| addr->pref == domain_best_pref
- || (session = smtp_reuse_addr(state, addr, port)) == 0)
+ || dns_rr_to_pa(addr, &hostaddr) == 0
+ || !(session = smtp_reuse_addr(state, hostaddr.buf, port)))
session = smtp_connect_addr(dest, addr, port, why, sess_flags);
if ((state->session = session) != 0) {
session->state = state;
/* Don't count handshake errors towards the session limit. */
state->final_server = (cpp[1] == 0 && next == 0);
if ((session->features & SMTP_FEATURE_FROM_CACHE) == 0
- && smtp_helo(state, misc_flags) != 0) {
+ && smtp_helo(state) != 0) {
if (vstream_ferror(session->stream) == 0
&& vstream_feof(session->stream) == 0)
smtp_quit(state);
/*
* We still need to deliver, bounce or defer some left-over recipients:
* either mail loops or some backup mail server was unavailable.
- *
- * Pay attention to what could be configuration problems, and pretend that
- * these are recoverable rather than bouncing the mail.
- *
- * In case of a "no error" indication we make up an excuse; this can happen
- * when the fall-back relay was already tried via a cached connection, so
- * that the address list scrubber left behind an empty list.
*/
if (SMTP_RCPT_LEFT(state) > 0) {
+
+ /*
+ * In case of a "no error" indication we make up an excuse; this can
+ * happen when the fall-back relay was already tried via a cached
+ * connection, so that the address list scrubber left behind an empty
+ * list.
+ */
if (smtp_errno == SMTP_ERR_NONE) {
smtp_dsn_update(why, DSN_BY_LOCAL_MTA,
"4.3.0", 450, "450 Server unavailable",
"server unavailable or unable to receive mail");
smtp_errno = SMTP_ERR_RETRY;
}
- switch (smtp_errno) {
- default:
- msg_panic("smtp_connect: bad error indication %d", smtp_errno);
-
- case SMTP_ERR_LOOP:
- case SMTP_ERR_FAIL:
+ /*
+ * Pay attention to what could be configuration problems, and pretend
+ * that these are recoverable rather than bouncing the mail.
+ */
+ else if (smtp_errno != SMTP_ERR_RETRY
+ && (state->misc_flags & SMTP_MISC_FLAG_USE_LMTP) == 0) {
/*
* The fall-back destination did not resolve as expected, or it
* is refusing to talk to us, or mail for it loops back to us.
*/
if (IS_FALLBACK_RELAY(cpp, sites, non_fallback_sites)) {
- msg_warn("%s configuration problem", VAR_FALLBACK_RELAY);
+ msg_warn("%s configuration problem", VAR_SMTP_FALLBACK);
vstring_strcpy(why->status, "4.3.5");
/* XXX Keep the diagnostic code and MTA. */
smtp_errno = SMTP_ERR_RETRY;
state->status = deliver_pass_all(MAIL_CLASS_PRIVATE,
var_bestmx_transp,
request);
+ smtp_errno = 0; /* XXX */
SMTP_RCPT_LEFT(state) = 0; /* XXX */
- break;
}
- /* FALLTHROUGH */
-
- case SMTP_ERR_RETRY:
-
- /*
- * We still need to bounce or defer some left-over recipients:
- * either mail loops or some mail server was unavailable.
- *
- * XXX Unlike enhanced status codes, changing a 4xx into 5xx SMTP
- * code is not simply a matter of changing the initial digit.
- * What we're doing here is correct only under specific
- * conditions, such as changing 450 into 550 or vice versa.
- */
- state->final_server = 1; /* XXX */
- if (smtp_errno == SMTP_ERR_RETRY)
- STR(why->status)[0] = STR(why->dtext)[0] = '4'; /* XXX */
- else
- STR(why->status)[0] = STR(why->dtext)[0] = '5'; /* XXX */
- why->dcode = atoi(STR(why->dtext)); /* XXX */
- smtp_sess_fail(state, why);
-
- /*
- * Sanity check. Don't silently lose recipients.
- */
- smtp_rcpt_cleanup(state);
- if (SMTP_RCPT_LEFT(state) > 0)
- msg_panic("smtp_connect: left-over recipients");
}
}
if (HAVE_NEXTHOP_STATE(state))
FREE_NEXTHOP_STATE(state);
argv_free(sites);
+}
+
+/* smtp_connect - establish SMTP connection */
+
+int smtp_connect(SMTP_STATE *state)
+{
+ DELIVER_REQUEST *request = state->request;
+ DSN_BUF *why = dsb_create();
+ char *destination = request->nexthop;
+
+ /*
+ * All deliveries proceed along the same lines, whether they are over TCP
+ * or UNIX-domain sockets, and whether they use SMTP or LMTP: get a
+ * connection from the cache or create a new connection; deliver mail;
+ * update the connection cache or disconnect.
+ *
+ * The major differences appear at a higher level: the expansion from
+ * destination to address list, and whether to stop before we reach the
+ * end of that list.
+ */
+
+ /*
+ * With LMTP we have direct-to-host delivery only. The destination may
+ * have multiple IP addresses.
+ */
+ if (state->misc_flags & SMTP_MISC_FLAG_USE_LMTP) {
+ if (strncmp(destination, "unix:", 5) == 0) {
+ smtp_connect_local(state, destination + 5, why);
+ } else {
+ if (strncmp(destination, "inet:", 5) == 0)
+ destination += 5;
+ smtp_connect_remote(state, destination, why);
+ }
+ }
+
+ /*
+ * With SMTP we can have indirection via MX host lookup, as well as an
+ * optional fall-back relayhost that we must avoid when we are MX host.
+ *
+ * XXX We don't add support for "unix:" or "inet:" prefixes in SMTP
+ * destinations, because that would break compatibility with existing
+ * Postfix configurations that have a host with such a name.
+ */
+ else {
+ smtp_connect_remote(state, destination, why);
+ }
+
+ /*
+ * We still need to bounce or defer some left-over recipients: either
+ * (SMTP) mail loops or some server was unavailable.
+ *
+ * XXX Unlike enhanced status codes, changing a 4xx into 5xx SMTP code is
+ * not simply a matter of changing the initial digit. What we're doing
+ * here is correct only under specific conditions, such as changing 450
+ * into 550 or vice versa.
+ */
+ if (SMTP_RCPT_LEFT(state) > 0) {
+ state->final_server = 1; /* XXX */
+ if (smtp_errno == SMTP_ERR_RETRY)
+ STR(why->status)[0] = STR(why->dtext)[0] = '4'; /* XXX */
+ else
+ STR(why->status)[0] = STR(why->dtext)[0] = '5'; /* XXX */
+ why->dcode = atoi(STR(why->dtext)); /* XXX */
+ smtp_sess_fail(state, why);
+
+ /*
+ * Sanity check. Don't silently lose recipients.
+ */
+ smtp_rcpt_cleanup(state);
+ if (SMTP_RCPT_LEFT(state) > 0)
+ msg_panic("smtp_connect: left-over recipients");
+ }
dsb_free(why);
return (state->status);
}
/* Global library. */
#include <dsn_buf.h>
+#include <mail_params.h>
/* Application-specific. */
{
dsb_formal(why, status, DSB_DEF_ACTION,
mta_name ? DSB_MTYPE_DNS : DSB_MTYPE_NONE,
- mta_name, DSB_DTYPE_SMTP, code, reply);
+ mta_name, var_procname, code, reply);
vstring_vsprintf(why->reason, format, ap);
}
{
dsb_formal(why, status, DSB_DEF_ACTION,
mta_name ? DSB_MTYPE_DNS : DSB_MTYPE_NONE,
- mta_name, DSB_DTYPE_SMTP, code, reply);
+ mta_name, var_procname, code, reply);
}
--- /dev/null
+ static CONFIG_STR_TABLE smtp_str_table[] = {
+ VAR_NOTIFY_CLASSES, DEF_NOTIFY_CLASSES, &var_notify_classes, 0, 0,
+ VAR_SMTP_FALLBACK, DEF_SMTP_FALLBACK, &var_fallback_relay, 0, 0,
+ VAR_BESTMX_TRANSP, DEF_BESTMX_TRANSP, &var_bestmx_transp, 0, 0,
+ VAR_ERROR_RCPT, DEF_ERROR_RCPT, &var_error_rcpt, 1, 0,
+ VAR_SMTP_SASL_PASSWD, DEF_SMTP_SASL_PASSWD, &var_smtp_sasl_passwd, 0, 0,
+ VAR_SMTP_SASL_OPTS, DEF_SMTP_SASL_OPTS, &var_smtp_sasl_opts, 0, 0,
+#ifdef USE_TLS
+ VAR_SMTP_SASL_TLS_OPTS, DEF_SMTP_SASL_TLS_OPTS, &var_smtp_sasl_tls_opts, 0, 0,
+#endif
+ VAR_SMTP_SASL_MECHS, DEF_SMTP_SASL_MECHS, &var_smtp_sasl_mechs, 0, 0,
+ VAR_SMTP_BIND_ADDR, DEF_SMTP_BIND_ADDR, &var_smtp_bind_addr, 0, 0,
+ VAR_SMTP_BIND_ADDR6, DEF_SMTP_BIND_ADDR6, &var_smtp_bind_addr6, 0, 0,
+ VAR_SMTP_HELO_NAME, DEF_SMTP_HELO_NAME, &var_smtp_helo_name, 1, 0,
+ VAR_SMTP_HOST_LOOKUP, DEF_SMTP_HOST_LOOKUP, &var_smtp_host_lookup, 1, 0,
+ VAR_SMTP_CACHE_DEST, DEF_SMTP_CACHE_DEST, &var_smtp_cache_dest, 0, 0,
+ VAR_SCACHE_SERVICE, DEF_SCACHE_SERVICE, &var_scache_service, 1, 0,
+ VAR_SMTP_EHLO_DIS_WORDS, DEF_SMTP_EHLO_DIS_WORDS, &var_smtp_ehlo_dis_words, 0, 0,
+ VAR_SMTP_EHLO_DIS_MAPS, DEF_SMTP_EHLO_DIS_MAPS, &var_smtp_ehlo_dis_maps, 0, 0,
+ VAR_SMTP_TLS_PER_SITE, DEF_SMTP_TLS_PER_SITE, &var_smtp_tls_per_site, 0, 0,
+ VAR_PROP_EXTENSION, DEF_PROP_EXTENSION, &var_prop_extension, 0, 0,
+ VAR_SMTP_GENERIC_MAPS, DEF_SMTP_GENERIC_MAPS, &var_smtp_generic_maps, 0, 0,
+ VAR_LMTP_TCP_PORT, DEF_LMTP_TCP_PORT, &var_lmtp_tcp_port, 0, 0,
+ 0,
+ };
+ static CONFIG_TIME_TABLE smtp_time_table[] = {
+ VAR_SMTP_CONN_TMOUT, DEF_SMTP_CONN_TMOUT, &var_smtp_conn_tmout, 0, 0,
+ VAR_SMTP_HELO_TMOUT, DEF_SMTP_HELO_TMOUT, &var_smtp_helo_tmout, 1, 0,
+ VAR_SMTP_XFWD_TMOUT, DEF_SMTP_XFWD_TMOUT, &var_smtp_xfwd_tmout, 1, 0,
+ VAR_SMTP_MAIL_TMOUT, DEF_SMTP_MAIL_TMOUT, &var_smtp_mail_tmout, 1, 0,
+ VAR_SMTP_RCPT_TMOUT, DEF_SMTP_RCPT_TMOUT, &var_smtp_rcpt_tmout, 1, 0,
+ VAR_SMTP_DATA0_TMOUT, DEF_SMTP_DATA0_TMOUT, &var_smtp_data0_tmout, 1, 0,
+ VAR_SMTP_DATA1_TMOUT, DEF_SMTP_DATA1_TMOUT, &var_smtp_data1_tmout, 1, 0,
+ VAR_SMTP_DATA2_TMOUT, DEF_SMTP_DATA2_TMOUT, &var_smtp_data2_tmout, 1, 0,
+ VAR_SMTP_RSET_TMOUT, DEF_SMTP_RSET_TMOUT, &var_smtp_rset_tmout, 1, 0,
+ VAR_SMTP_QUIT_TMOUT, DEF_SMTP_QUIT_TMOUT, &var_smtp_quit_tmout, 1, 0,
+ VAR_SMTP_PIX_THRESH, DEF_SMTP_PIX_THRESH, &var_smtp_pix_thresh, 0, 0,
+ VAR_SMTP_PIX_DELAY, DEF_SMTP_PIX_DELAY, &var_smtp_pix_delay, 1, 0,
+ VAR_SMTP_CACHE_CONNT, DEF_SMTP_CACHE_CONNT, &var_smtp_cache_conn, 1, 0,
+ VAR_SMTP_REUSE_TIME, DEF_SMTP_REUSE_TIME, &var_smtp_reuse_time, 1, 0,
+#ifdef USE_TLS
+ VAR_SMTP_STARTTLS_TMOUT, DEF_SMTP_STARTTLS_TMOUT, &var_smtp_starttls_tmout, 1, 0,
+#endif
+ VAR_SCACHE_PROTO_TMOUT, DEF_SCACHE_PROTO_TMOUT, &var_scache_proto_tmout, 1, 0,
+ 0,
+ };
+ static CONFIG_INT_TABLE smtp_int_table[] = {
+ VAR_SMTP_LINE_LIMIT, DEF_SMTP_LINE_LIMIT, &var_smtp_line_limit, 0, 0,
+ VAR_SMTP_MXADDR_LIMIT, DEF_SMTP_MXADDR_LIMIT, &var_smtp_mxaddr_limit, 0, 0,
+ VAR_SMTP_MXSESS_LIMIT, DEF_SMTP_MXSESS_LIMIT, &var_smtp_mxsess_limit, 0, 0,
+#ifdef USE_TLS
+ VAR_SMTP_TLS_SCERT_VD, DEF_SMTP_TLS_SCERT_VD, &var_smtp_tls_scert_vd, 0, 0,
+#endif
+ 0,
+ };
+ static CONFIG_BOOL_TABLE smtp_bool_table[] = {
+ VAR_SMTP_SKIP_5XX, DEF_SMTP_SKIP_5XX, &var_smtp_skip_5xx_greeting,
+ VAR_IGN_MX_LOOKUP_ERR, DEF_IGN_MX_LOOKUP_ERR, &var_ign_mx_lookup_err,
+ VAR_SKIP_QUIT_RESP, DEF_SKIP_QUIT_RESP, &var_skip_quit_resp,
+ VAR_SMTP_ALWAYS_EHLO, DEF_SMTP_ALWAYS_EHLO, &var_smtp_always_ehlo,
+ VAR_SMTP_NEVER_EHLO, DEF_SMTP_NEVER_EHLO, &var_smtp_never_ehlo,
+ VAR_SMTP_SASL_ENABLE, DEF_SMTP_SASL_ENABLE, &var_smtp_sasl_enable,
+ VAR_SMTP_RAND_ADDR, DEF_SMTP_RAND_ADDR, &var_smtp_rand_addr,
+ VAR_SMTP_QUOTE_821_ENV, DEF_SMTP_QUOTE_821_ENV, &var_smtp_quote_821_env,
+ VAR_SMTP_DEFER_MXADDR, DEF_SMTP_DEFER_MXADDR, &var_smtp_defer_mxaddr,
+ VAR_SMTP_SEND_XFORWARD, DEF_SMTP_SEND_XFORWARD, &var_smtp_send_xforward,
+ VAR_SMTP_CACHE_DEMAND, DEF_SMTP_CACHE_DEMAND, &var_smtp_cache_demand,
+ VAR_SMTP_USE_TLS, DEF_SMTP_USE_TLS, &var_smtp_use_tls,
+ VAR_SMTP_ENFORCE_TLS, DEF_SMTP_ENFORCE_TLS, &var_smtp_enforce_tls,
+#ifdef USE_TLS
+ VAR_SMTP_TLS_ENFORCE_PN, DEF_SMTP_TLS_ENFORCE_PN, &var_smtp_tls_enforce_peername,
+ VAR_SMTP_TLS_NOTEOFFER, DEF_SMTP_TLS_NOTEOFFER, &var_smtp_tls_note_starttls_offer,
+#endif
+ VAR_SMTP_SENDER_AUTH, DEF_SMTP_SENDER_AUTH, &var_smtp_sender_auth,
+ 0,
+ };
/* NAME
/* smtp_proto 3
/* SUMMARY
-/* client SMTP protocol
+/* client SMTP/LMTP protocol
/* SYNOPSIS
/* #include "smtp.h"
/*
-/* int smtp_helo(state, misc_flags)
+/* int smtp_helo(state)
/* SMTP_STATE *state;
-/* int misc_flags;
/*
/* int smtp_xfer(state)
/* SMTP_STATE *state;
/* int smtp_quit(state)
/* SMTP_STATE *state;
/* DESCRIPTION
+/* In the subsequent text, SMTP implies LMTP.
/* This module implements the client side of the SMTP protocol.
/*
/* smtp_helo() performs the initial handshake with the SMTP server.
"QUIT command",
};
-static int smtp_start_tls(SMTP_STATE *, int);
+static int smtp_start_tls(SMTP_STATE *);
/* smtp_helo - perform initial handshake with SMTP server */
-int smtp_helo(SMTP_STATE *state, NOCLOBBER int misc_flags)
+int smtp_helo(SMTP_STATE *state)
{
char *myname = "smtp_helo";
SMTP_SESSION *session = state->session;
* If not recursing after STARTTLS, examine the server greeting banner
* and decide if we are going to send EHLO as the next command.
*/
- if ((misc_flags & SMTP_MISC_FLAG_IN_STARTTLS) == 0) {
+ if ((state->misc_flags & SMTP_MISC_FLAG_IN_STARTTLS) == 0) {
/*
* Prepare for disaster.
smtp_timeout_setup(state->session->stream, var_smtp_helo_tmout);
if ((except = vstream_setjmp(state->session->stream)) != 0)
return (smtp_stream_except(state, except,
- "receiving the initial SMTP greeting"));
+ "receiving the initial server greeting"));
/*
* Read and parse the server's SMTP greeting banner.
(void) mystrtok(&words, "- \t\n");
for (n = 0; (word = mystrtok(&words, " \t\n")) != 0; n++) {
if (n == 0 && strcasecmp(word, var_myhostname) == 0) {
- if (misc_flags & SMTP_MISC_FLAG_LOOP_DETECT)
+ if (state->misc_flags & SMTP_MISC_FLAG_LOOP_DETECT)
msg_warn("host %s greeted me with my own hostname %s",
session->namaddr, var_myhostname);
} else if (strcasecmp(word, "ESMTP") == 0)
session->features |= SMTP_FEATURE_ESMTP;
}
- if (var_smtp_always_ehlo
- && (session->features & SMTP_FEATURE_MAYBEPIX) == 0)
+ if ((state->misc_flags & SMTP_MISC_FLAG_USE_LMTP) == 0) {
+ if (var_smtp_always_ehlo
+ && (session->features & SMTP_FEATURE_MAYBEPIX) == 0)
+ session->features |= SMTP_FEATURE_ESMTP;
+ if (var_smtp_never_ehlo
+ || (session->features & SMTP_FEATURE_MAYBEPIX) != 0)
+ session->features &= ~SMTP_FEATURE_ESMTP;
+ } else {
session->features |= SMTP_FEATURE_ESMTP;
- if (var_smtp_never_ehlo
- || (session->features & SMTP_FEATURE_MAYBEPIX) != 0)
- session->features &= ~SMTP_FEATURE_ESMTP;
+ }
}
/*
* Return the compliment. Fall back to SMTP if our ESMTP recognition
* heuristic failed.
*/
- if (session->features & SMTP_FEATURE_ESMTP) {
- smtp_chat_cmd(session, "EHLO %s", var_smtp_helo_name);
- if ((resp = smtp_chat_resp(session))->code / 100 != 2)
- session->features &= ~SMTP_FEATURE_ESMTP;
- }
- if ((session->features & SMTP_FEATURE_ESMTP) == 0) {
- smtp_chat_cmd(session, "HELO %s", var_smtp_helo_name);
+ if ((state->misc_flags & SMTP_MISC_FLAG_USE_LMTP) == 0) {
+ if (session->features & SMTP_FEATURE_ESMTP) {
+ smtp_chat_cmd(session, "EHLO %s", var_smtp_helo_name);
+ if ((resp = smtp_chat_resp(session))->code / 100 != 2)
+ session->features &= ~SMTP_FEATURE_ESMTP;
+ }
+ if ((session->features & SMTP_FEATURE_ESMTP) == 0) {
+ smtp_chat_cmd(session, "HELO %s", var_smtp_helo_name);
+ if ((resp = smtp_chat_resp(session))->code / 100 != 2)
+ return (smtp_site_fail(state, session->host, resp,
+ "host %s refused to talk to me: %s",
+ session->namaddr,
+ translit(resp->str, "\n", " ")));
+ return (0);
+ }
+ } else {
+ smtp_chat_cmd(session, "LHLO %s", var_smtp_helo_name);
if ((resp = smtp_chat_resp(session))->code / 100 != 2)
return (smtp_site_fail(state, session->host, resp,
"host %s refused to talk to me: %s",
session->namaddr,
translit(resp->str, "\n", " ")));
- return (0);
}
/*
myfree(session->helo);
session->helo = lowercase(mystrdup(word));
if (strcasecmp(word, var_myhostname) == 0
- && (misc_flags & SMTP_MISC_FLAG_LOOP_DETECT) != 0) {
+ && (state->misc_flags & SMTP_MISC_FLAG_LOOP_DETECT) != 0) {
msg_warn("host %s replied to HELO/EHLO with my own hostname %s",
session->namaddrport, var_myhostname);
if (session->features & SMTP_FEATURE_BEST_MX)
/*
* Skip this part if we already sent STARTTLS.
*/
- if ((misc_flags & SMTP_MISC_FLAG_IN_STARTTLS) == 0) {
+ if ((state->misc_flags & SMTP_MISC_FLAG_IN_STARTTLS) == 0) {
/*
* Optionally log unused STARTTLS opportunities.
}
#endif
session->features = saved_features;
- misc_flags |= SMTP_MISC_FLAG_IN_STARTTLS;
- return (smtp_start_tls(state, misc_flags));
+ state->misc_flags |= SMTP_MISC_FLAG_IN_STARTTLS;
+ return (smtp_start_tls(state));
}
/*
/* smtp_start_tls - turn on TLS and recurse into the HELO dialog */
-static int smtp_start_tls(SMTP_STATE *state, int misc_flags)
+static int smtp_start_tls(SMTP_STATE *state)
{
SMTP_SESSION *session = state->session;
VSTRING *serverid;
* At this point we have to re-negotiate the "EHLO" to reget the
* feature-list.
*/
- return (smtp_helo(state, misc_flags));
+ return (smtp_helo(state));
}
#endif
SMTP_RESP *resp;
RECIPIENT *rcpt;
VSTRING *next_command = vstring_alloc(100);
+ int *NOCLOBBER survivors = 0;
NOCLOBBER int next_state;
NOCLOBBER int next_rcpt;
NOCLOBBER int send_rcpt;
NOCLOBBER int recv_rcpt;
NOCLOBBER int nrcpt;
+ NOCLOBBER int recv_done;
int except;
int rec_type;
NOCLOBBER int prev_type = 0;
#define RETURN(x) do { \
vstring_free(next_command); \
+ if (survivors) \
+ myfree((char *) survivors); \
if (session->mime_state) \
session->mime_state = mime_state_free(session->mime_state); \
return (x); \
* SMTP dialog with RSET and QUIT.
*/
nrcpt = 0;
- next_rcpt = send_rcpt = recv_rcpt = 0;
+ next_rcpt = send_rcpt = recv_rcpt = recv_done = 0;
mail_from_rejected = 0;
/*
#endif
rcpt = request->rcpt_list.info + recv_rcpt;
if (resp->code / 100 == 2) {
+ if (state->misc_flags & SMTP_MISC_FLAG_USE_LMTP) {
+ if (survivors == 0)
+ survivors = (int *)
+ mymalloc(request->rcpt_list.len
+ * sizeof(int));
+ survivors[nrcpt] = recv_rcpt;
+ }
++nrcpt;
/* If trace-only, mark the recipient done. */
if (DEL_REQ_TRACE_ONLY(request->flags)) {
*/
case SMTP_STATE_DOT:
GETTIMEOFDAY(&request->msg_stats.deliver_done);
- if (nrcpt > 0) {
- if (resp->code / 100 != 2) {
- smtp_mesg_fail(state, session->host, resp,
+ if ((state->misc_flags & SMTP_MISC_FLAG_USE_LMTP) == 0) {
+ if (nrcpt > 0) {
+ if (resp->code / 100 != 2) {
+ smtp_mesg_fail(state, session->host, resp,
"host %s said: %s (in reply to %s)",
- session->namaddr,
- translit(resp->str, "\n", " "),
- xfer_request[SMTP_STATE_DOT]);
- } else {
- for (nrcpt = 0; nrcpt < recv_rcpt; nrcpt++) {
- rcpt = request->rcpt_list.info + nrcpt;
- if (!SMTP_RCPT_ISMARKED(rcpt)) {
- translit(resp->str, "\n", " ");
- smtp_rcpt_done(state, resp, rcpt);
+ session->namaddr,
+ translit(resp->str, "\n", " "),
+ xfer_request[SMTP_STATE_DOT]);
+ } else {
+ for (nrcpt = 0; nrcpt < recv_rcpt; nrcpt++) {
+ rcpt = request->rcpt_list.info + nrcpt;
+ if (!SMTP_RCPT_ISMARKED(rcpt)) {
+ translit(resp->str, "\n", " ");
+ smtp_rcpt_done(state, resp, rcpt);
+ }
}
}
}
}
+ /*
+ * With LMTP we have one response per accepted RCPT TO
+ * command. Stay in the SMTP_STATE_DOT state until we
+ * have collected all responses.
+ */
+ else {
+ if (nrcpt > 0) {
+ rcpt = request->rcpt_list.info
+ + survivors[recv_done++];
+ if (resp->code / 100 != 2) {
+ smtp_rcpt_fail(state, rcpt, session->host, resp,
+ "host %s said: %s (in reply to %s)",
+ session->namaddr,
+ translit(resp->str, "\n", " "),
+ xfer_request[SMTP_STATE_DOT]);
+ } else {
+ translit(resp->str, "\n", " ");
+ smtp_rcpt_done(state, resp, rcpt);
+ }
+ }
+ if (msg_verbose)
+ msg_info("%s: got %d of %d end-of-data replies",
+ myname, recv_done, nrcpt);
+ if (recv_done < nrcpt)
+ break;
+ }
+
/*
* XXX Do not change the connection caching state here,
* even if the connection caching timer expired between
/*
/* SMTP_SESSION *smtp_reuse_addr(state, addr, port)
/* SMTP_STATE *state;
-/* DNS_RR *addr;
+/* const char *addr;
/* unsigned port;
/* DESCRIPTION
/* This module implements the SMTP client specific interface to
/* .IP domain
/* Domain name or bare numerical address.
/* .IP addr
-/* The remote server name and address.
+/* The remote server address as printable text.
/* .IP port
/* The remote server port, network byte order.
/* LICENSE
/* smtp_reuse_addr - reuse session cached under numerical address */
-SMTP_SESSION *smtp_reuse_addr(SMTP_STATE *state, DNS_RR *addr, unsigned port)
+SMTP_SESSION *smtp_reuse_addr(SMTP_STATE *state, const char *addr,
+ unsigned port)
{
- MAI_HOSTADDR_STR hostaddr;
SMTP_SESSION *session;
int fd;
* Note: if the label needs to be made more specific (with e.g., SASL login
* information), just append the text with vstring_sprintf_append().
*/
- if (dns_rr_to_pa(addr, &hostaddr) == 0)
- return (0);
vstring_sprintf(state->endp_label, SMTP_SCACHE_LABEL(NO_MX_LOOKUP),
- state->service, hostaddr.buf, ntohs(port));
+ state->service, addr, ntohs(port));
if ((fd = scache_find_endp(smtp_scache, STR(state->endp_label),
state->endp_prop)) < 0)
return (0);
/* DESCRIPTION
/* .nf
- /*
- * DNS library.
- */
-#include <dns.h>
-
/*
* Internal interfaces.
*/
extern void smtp_save_session(SMTP_STATE *);
extern SMTP_SESSION *smtp_reuse_domain(SMTP_STATE *, int, const char *, unsigned);
-extern SMTP_SESSION *smtp_reuse_addr(SMTP_STATE *, DNS_RR *, unsigned);
+extern SMTP_SESSION *smtp_reuse_addr(SMTP_STATE *, const char *, unsigned);
/* LICENSE
/* .ad
* but didn't canonicalize the TCP port, and did not append the port to
* the MX hostname.
*/
- if ((var_smtp_sender_auth && state->request->sender[0]
+ if (((state->misc_flags & SMTP_MISC_FLAG_USE_LMTP) == 0
+ && var_smtp_sender_auth && state->request->sender[0]
&& (value = mail_addr_find(smtp_sasl_passwd_map,
state->request->sender, (char **) 0)) != 0)
|| (value = maps_find(smtp_sasl_passwd_map, session->host, 0)) != 0
#define NULL_SERVER_ADDR ((char *) 0)
#define NULL_CLIENT_ADDR ((char *) 0)
- if (SASL_CLIENT_NEW("smtp", session->host,
+ if (SASL_CLIENT_NEW(var_procname, session->host,
NULL_CLIENT_ADDR, NULL_SERVER_ADDR,
session->sasl_callbacks, NULL_SECFLAGS,
(sasl_conn_t **) &session->sasl_conn) != SASL_OK)
#include <mymalloc.h>
#include <vstring.h>
+#include <msg.h>
/* Global library. */
{
SMTP_STATE *state = (SMTP_STATE *) mymalloc(sizeof(*state));
+ state->misc_flags = 0;
state->src = 0;
state->service = 0;
state->request = 0;
}
state->dsn_reason = 0;
+ /*
+ * The process name, "smtp" or "lmtp", is also used as the DSN server
+ * reply type and for SASL service information lookup. Since all three
+ * external representations are identical there is no reason to transform
+ * from some external form X to some Postfix-specific canonical internal
+ * form, and then to transform from the internal form to external forms Y
+ * and Z.
+ */
+ if (strcmp(var_procname, "lmtp") == 0) {
+ state->misc_flags |= SMTP_MISC_FLAG_USE_LMTP;
+ } else if (strcmp(var_procname, "smtp") == 0) {
+ /* void */
+ } else {
+ msg_fatal("unexpected process name \"%s\" - "
+ "specify \"smtp\" or \"lmtp\"",
+ var_procname);
+ }
return (state);
}
const char *protocols = INET_PROTO_NAME_ALL;
INET_PROTO_INFO *proto_info;
+ /*
+ * Fix 20051207.
+ */
+ signal(SIGPIPE, SIG_IGN);
+
/*
* Initialize diagnostics.
*/
const char *protocols = INET_PROTO_NAME_ALL;
INET_PROTO_INFO *proto_info;
+ /*
+ * Fix 20051207.
+ */
+ signal(SIGPIPE, SIG_IGN);
+
/*
* Initialize diagnostics.
*/
attr_clnt.o: attr_clnt.c
attr_clnt.o: attr_clnt.h
attr_clnt.o: auto_clnt.h
-attr_clnt.o: connect.h
attr_clnt.o: htable.h
attr_clnt.o: iostuff.h
attr_clnt.o: msg.h
attr_clnt.o: mymalloc.h
-attr_clnt.o: split_at.h
attr_clnt.o: sys_defs.h
attr_clnt.o: vbuf.h
attr_clnt.o: vstream.h
attr_scan_plain.o: vstring.h
auto_clnt.o: auto_clnt.c
auto_clnt.o: auto_clnt.h
+auto_clnt.o: connect.h
auto_clnt.o: events.h
auto_clnt.o: iostuff.h
auto_clnt.o: msg.h
auto_clnt.o: mymalloc.h
+auto_clnt.o: split_at.h
auto_clnt.o: sys_defs.h
auto_clnt.o: vbuf.h
auto_clnt.o: vstream.h
/* This module implements a client for a simple attribute-based
/* protocol. The default protocol is described in attr_scan_plain(3).
/*
-/* attr_clnt_create() creates a client handle. The server
-/* argument specifies "transport:servername" where transport is
-/* currently limited to "inet" or "unix", and servername has the
-/* form "host:port", "private/servicename" or "public/servicename".
-/* The timeout parameter limits the time for sending or receiving
-/* a reply, max_idle specifies how long an idle connection is
-/* kept open, and the max_ttl parameter bounds the time that a
-/* connection is kept open.
-/* Specify zero to disable a max_idle or max_ttl limit.
+/* attr_clnt_create() creates a client handle. See auto_clnt(3) for
+/* a description of the arguments.
/*
/* attr_clnt_request() sends the specified request attributes and
/* receives a reply. The reply argument specifies a name-value table.
#include <sys_defs.h>
#include <unistd.h>
#include <errno.h>
-#include <string.h>
/* Utility library. */
#include <msg.h>
#include <mymalloc.h>
-#include <split_at.h>
#include <vstream.h>
-#include <connect.h>
#include <htable.h>
#include <attr.h>
+#include <iostuff.h>
#include <auto_clnt.h>
#include <attr_clnt.h>
struct ATTR_CLNT {
AUTO_CLNT *auto_clnt;
- int (*connect) (const char *, int, int);
- char *endpoint;
- int timeout;
ATTR_CLNT_PRINT_FN print;
ATTR_CLNT_SCAN_FN scan;
};
-/* attr_clnt_connect - connect to server */
-
-static VSTREAM *attr_clnt_connect(void *context)
-{
- const char *myname = "attr_clnt_connect";
- ATTR_CLNT *client = (ATTR_CLNT *) context;
- VSTREAM *fp;
- int fd;
-
- fd = client->connect(client->endpoint, BLOCKING, client->timeout);
- if (fd < 0) {
- msg_warn("connect to %s: %m", client->endpoint);
- return (0);
- } else {
- if (msg_verbose)
- msg_info("%s: connected to %s", myname, client->endpoint);
- fp = vstream_fdopen(fd, O_RDWR);
- vstream_control(fp, VSTREAM_CTL_PATH, client->endpoint,
- VSTREAM_CTL_TIMEOUT, client->timeout,
- VSTREAM_CTL_END);
- return (fp);
- }
-}
-
/* attr_clnt_free - destroy attribute client */
void attr_clnt_free(ATTR_CLNT *client)
{
- myfree(client->endpoint);
auto_clnt_free(client->auto_clnt);
myfree((char *) client);
}
ATTR_CLNT *attr_clnt_create(const char *service, int timeout,
int max_idle, int max_ttl)
{
- const char *myname = "attr_clnt_create";
- char *transport = mystrdup(service);
- char *endpoint;
ATTR_CLNT *client;
- if ((endpoint = split_at(transport, ':')) == 0
- || *endpoint == 0 || *transport == 0)
- msg_fatal("need service transport:endpoint instead of \"%s\"", service);
- if (msg_verbose)
- msg_info("%s: transport=%s endpoint=%s", myname, transport, endpoint);
-
client = (ATTR_CLNT *) mymalloc(sizeof(*client));
+ client->auto_clnt = auto_clnt_create(service, timeout, max_idle, max_ttl);
client->scan = attr_vscan_plain;
client->print = attr_vprint_plain;
- client->endpoint = mystrdup(endpoint);
- client->timeout = timeout;
- if (strcmp(transport, "inet") == 0) {
- client->connect = inet_connect;
- } else if (strcmp(transport, "local") == 0) {
- client->connect = LOCAL_CONNECT;
- } else if (strcmp(transport, "unix") == 0) {
- client->connect = unix_connect;
- } else {
- msg_fatal("invalid attribute transport name: %s", service);
- }
- client->auto_clnt = auto_clnt_create(max_idle, max_ttl,
- attr_clnt_connect, (void *) client);
- myfree(transport);
return (client);
}
if (++count >= 2
|| msg_verbose
|| (errno && errno != EPIPE && errno != ENOENT && errno != ECONNRESET))
- msg_warn("problem talking to server %s: %m", client->endpoint);
+ msg_warn("problem talking to server %s: %m", VSTREAM_PATH(stream));
if (count >= 2)
return (-1);
sleep(1); /* XXX make configurable */
/* SYNOPSIS
/* #include <auto_clnt.h>
/*
-/* AUTO_CLNT *auto_clnt_create(max_idle, max_ttl, open_action, context)
+/* AUTO_CLNT *auto_clnt_create(service, timeout, max_idle, max_ttl)
+/* const char *service;
+/* int timeout;
/* int max_idle;
/* int max_ttl;
-/* VSTREAM *(open_action)(void *context)
-/* void *context;
/*
/* VSTREAM *auto_clnt_access(auto_clnt)
/* AUTO_CLNT *auto_clnt;
/* that disconnect after a configurable time to live,
/* and that transparently handle most server-initiated disconnects.
/*
+/* This module tries each operation only a limited number of
+/* times and then reports an error. This is unlike the
+/* clnt_stream(3) module which will retry forever, so that
+/* the application never experiences an error.
+/*
/* auto_clnt_create() instantiates a client endpoint.
/*
/* auto_clnt_access() returns an open stream to the service specified
/* auto_clnt_free() destroys of the specified client endpoint.
/*
/* Arguments:
+/* .IP service
+/* The service argument specifies "transport:servername" where
+/* transport is currently limited to one of the following:
+/* .RS
+/* .IP inet
+/* servername has the form "host:port".
+/* .IP unix
+/* servername has the form "private/servicename" or
+/* "public/servicename".
+/* .RE
+/* .IP timeout
+/* The time limit for sending, receiving, or for connecting
+/* to a server. Specify a value <=0 to disable the time limit.
/* .IP max_idle
-/* Idle time after which the client disconnects. Specify 0 to disable
-/* the limit.
+/* Idle time after which the client disconnects. Specify 0 to
+/* disable the limit.
/* .IP max_ttl
/* Upper bound on the time that a connection is allowed to persist.
/* Specify 0 to disable the limit.
/* System library. */
#include <sys_defs.h>
+#include <string.h>
/* Utility library. */
#include <vstream.h>
#include <events.h>
#include <iostuff.h>
+#include <connect.h>
+#include <split_at.h>
#include <auto_clnt.h>
/* Application-specific. */
*/
struct AUTO_CLNT {
VSTREAM *vstream; /* buffered I/O */
+ char *endpoint; /* host:port or pathname */
+ int timeout; /* I/O time limit */
int max_idle; /* time before client disconnect */
int max_ttl; /* time before client disconnect */
- VSTREAM *(*open_action) (void *); /* callback */
- void *context; /* callback context */
+ int (*connect) (const char *, int, int); /* unix, local, inet */
};
static void auto_clnt_close(AUTO_CLNT *);
static void auto_clnt_open(AUTO_CLNT *auto_clnt)
{
+ const char *myname = "auto_clnt_open";
+ int fd;
/*
* Sanity check.
* connection is not idle. This is to prevent one client from clinging on
* to a server forever.
*/
- auto_clnt->vstream =
- auto_clnt->open_action(auto_clnt->context);
+ fd = auto_clnt->connect(auto_clnt->endpoint, BLOCKING, auto_clnt->timeout);
+ if (fd < 0) {
+ msg_warn("connect to %s: %m", auto_clnt->endpoint);
+ } else {
+ if (msg_verbose)
+ msg_info("%s: connected to %s", myname, auto_clnt->endpoint);
+ auto_clnt->vstream = vstream_fdopen(fd, O_RDWR);
+ vstream_control(auto_clnt->vstream,
+ VSTREAM_CTL_PATH, auto_clnt->endpoint,
+ VSTREAM_CTL_TIMEOUT, auto_clnt->timeout,
+ VSTREAM_CTL_END);
+ }
if (auto_clnt->vstream != 0) {
close_on_exec(vstream_fileno(auto_clnt->vstream), CLOSE_ON_EXEC);
static void auto_clnt_close(AUTO_CLNT *auto_clnt)
{
+ const char *myname = "auto_clnt_close";
/*
* Sanity check.
*/
if (auto_clnt->vstream == 0)
- msg_panic("auto_clnt_close: stream is closed");
+ msg_panic("%s: stream is closed", myname);
/*
* Be sure to disable read and timer events.
*/
if (msg_verbose)
- msg_info("%s stream disconnect", VSTREAM_PATH(auto_clnt->vstream));
+ msg_info("%s: disconnect %s stream",
+ myname, VSTREAM_PATH(auto_clnt->vstream));
event_disable_readwrite(vstream_fileno(auto_clnt->vstream));
event_cancel_timer(auto_clnt_event, (char *) auto_clnt);
event_cancel_timer(auto_clnt_ttl_event, (char *) auto_clnt);
return (auto_clnt->vstream);
}
-/* auto_clnt_create - create client stream connection */
+/* auto_clnt_create - create client stream object */
-AUTO_CLNT *auto_clnt_create(int max_idle, int max_ttl,
- VSTREAM *(*open_action) (void *), void *context)
+AUTO_CLNT *auto_clnt_create(const char *service, int timeout,
+ int max_idle, int max_ttl)
{
+ const char *myname = "auto_clnt_create";
+ char *transport = mystrdup(service);
+ char *endpoint;
AUTO_CLNT *auto_clnt;
/*
* Don't open the stream until the caller needs it.
*/
+ if ((endpoint = split_at(transport, ':')) == 0
+ || *endpoint == 0 || *transport == 0)
+ msg_fatal("need service transport:endpoint instead of \"%s\"", service);
+ if (msg_verbose)
+ msg_info("%s: transport=%s endpoint=%s", myname, transport, endpoint);
auto_clnt = (AUTO_CLNT *) mymalloc(sizeof(*auto_clnt));
auto_clnt->vstream = 0;
+ auto_clnt->endpoint = mystrdup(endpoint);
+ auto_clnt->timeout = timeout;
auto_clnt->max_idle = max_idle;
auto_clnt->max_ttl = max_ttl;
- auto_clnt->open_action = open_action;
- auto_clnt->context = context;
+ if (strcmp(transport, "inet") == 0) {
+ auto_clnt->connect = inet_connect;
+ } else if (strcmp(transport, "local") == 0) {
+ auto_clnt->connect = LOCAL_CONNECT;
+ } else if (strcmp(transport, "unix") == 0) {
+ auto_clnt->connect = unix_connect;
+ } else {
+ msg_fatal("invalid transport name: %s in service: %s",
+ transport, service);
+ }
+ myfree(transport);
return (auto_clnt);
}
{
if (auto_clnt->vstream)
auto_clnt_close(auto_clnt);
+ myfree(auto_clnt->endpoint);
myfree((char *) auto_clnt);
}
*/
typedef struct AUTO_CLNT AUTO_CLNT;
-extern AUTO_CLNT *auto_clnt_create(int, int, VSTREAM *(*) (void *), void *);
+extern AUTO_CLNT *auto_clnt_create(const char *, int, int, int);
extern VSTREAM *auto_clnt_access(AUTO_CLNT *);
extern void auto_clnt_recover(AUTO_CLNT *);
extern void auto_clnt_free(AUTO_CLNT *);
/* SUMMARY
/* connect to UNIX-domain listener
/* SYNOPSIS
-/* #include <unix_connect.h>
+/* #include <connect.h>
/*
/* int unix_connect(addr, block_mode, timeout)
/* const char *addr;