From 583a9d46f1f71a099dc2bec366be4012b89045a1 Mon Sep 17 00:00:00 2001 From: Wietse Venema Date: Thu, 8 Dec 2005 00:00:00 -0500 Subject: [PATCH] postfix-2.3-20051208 --- postfix/HISTORY | 51 ++ postfix/Makefile.in | 2 +- postfix/RELEASE_NOTES | 21 + postfix/conf/postfix-files | 3 +- postfix/html/Makefile.in | 7 +- postfix/html/lmtp.8.html | 306 +-------- postfix/html/postconf.5.html | 427 ++++++++++++- postfix/html/postfix-manuals.html | 4 +- postfix/html/postfix.1.html | 18 +- postfix/html/postsuper.1.html | 127 ++-- postfix/html/smtp.8.html | 287 ++++++--- postfix/makedefs | 2 +- postfix/man/Makefile.in | 6 +- postfix/man/man1/postfix.1 | 18 +- postfix/man/man1/postsuper.1 | 2 +- postfix/man/man5/postconf.5 | 230 ++++++- postfix/man/man8/lmtp.8 | 280 +-------- postfix/man/man8/smtp.8 | 105 +++- postfix/mantools/postlink | 1 + postfix/proto/postconf.proto | 297 ++++++++- postfix/src/global/Makefile.in | 3 +- postfix/src/global/deliver_pass.c | 30 +- postfix/src/global/deliver_request.c | 9 +- postfix/src/global/mail_params.h | 84 ++- postfix/src/global/mail_version.h | 2 +- postfix/src/global/scache.h | 2 +- postfix/src/global/scache_clnt.c | 317 +++++----- postfix/src/lmtp/.indent.pro | 1 - postfix/src/lmtp/.printfck | 25 - postfix/src/lmtp/Makefile.in | 330 ---------- postfix/src/lmtp/lmtp.c | 615 ------------------ postfix/src/lmtp/lmtp.h | 202 ------ postfix/src/lmtp/lmtp_addr.c | 235 ------- postfix/src/lmtp/lmtp_addr.h | 46 -- postfix/src/lmtp/lmtp_chat.c | 361 ----------- postfix/src/lmtp/lmtp_connect.c | 386 ------------ postfix/src/lmtp/lmtp_dsn.c | 144 ----- postfix/src/lmtp/lmtp_proto.c | 905 --------------------------- postfix/src/lmtp/lmtp_rcpt.c | 83 --- postfix/src/lmtp/lmtp_sasl.h | 39 -- postfix/src/lmtp/lmtp_sasl_glue.c | 638 ------------------- postfix/src/lmtp/lmtp_sasl_proto.c | 128 ---- postfix/src/lmtp/lmtp_session.c | 106 ---- postfix/src/lmtp/lmtp_state.c | 103 --- postfix/src/lmtp/lmtp_trouble.c | 405 ------------ postfix/src/postfix/postfix.c | 18 +- postfix/src/postsuper/postsuper.c | 2 +- postfix/src/scache/scache.c | 47 +- postfix/src/smtp/Makefile.in | 17 +- postfix/src/smtp/lmtp_params.c | 72 +++ postfix/src/smtp/smtp-only | 4 + postfix/src/smtp/smtp.c | 201 +++--- postfix/src/smtp/smtp.h | 6 +- postfix/src/smtp/smtp_connect.c | 416 ++++++++---- postfix/src/smtp/smtp_dsn.c | 5 +- postfix/src/smtp/smtp_params.c | 76 +++ postfix/src/smtp/smtp_proto.c | 133 ++-- postfix/src/smtp/smtp_reuse.c | 12 +- postfix/src/smtp/smtp_reuse.h | 7 +- postfix/src/smtp/smtp_sasl_glue.c | 5 +- postfix/src/smtp/smtp_state.c | 19 + postfix/src/smtpstone/qmqp-sink.c | 5 + postfix/src/smtpstone/smtp-sink.c | 5 + postfix/src/util/Makefile.in | 4 +- postfix/src/util/attr_clnt.c | 69 +- postfix/src/util/auto_clnt.c | 88 ++- postfix/src/util/auto_clnt.h | 2 +- postfix/src/util/unix_connect.c | 2 +- 68 files changed, 2497 insertions(+), 6111 deletions(-) mode change 100644 => 120000 postfix/html/lmtp.8.html delete mode 120000 postfix/src/lmtp/.indent.pro delete mode 100644 postfix/src/lmtp/.printfck delete mode 100644 postfix/src/lmtp/Makefile.in delete mode 100644 postfix/src/lmtp/lmtp.c delete mode 100644 postfix/src/lmtp/lmtp.h delete mode 100644 postfix/src/lmtp/lmtp_addr.c delete mode 100644 postfix/src/lmtp/lmtp_addr.h delete mode 100644 postfix/src/lmtp/lmtp_chat.c delete mode 100644 postfix/src/lmtp/lmtp_connect.c delete mode 100644 postfix/src/lmtp/lmtp_dsn.c delete mode 100644 postfix/src/lmtp/lmtp_proto.c delete mode 100644 postfix/src/lmtp/lmtp_rcpt.c delete mode 100644 postfix/src/lmtp/lmtp_sasl.h delete mode 100644 postfix/src/lmtp/lmtp_sasl_glue.c delete mode 100644 postfix/src/lmtp/lmtp_sasl_proto.c delete mode 100644 postfix/src/lmtp/lmtp_session.c delete mode 100644 postfix/src/lmtp/lmtp_state.c delete mode 100644 postfix/src/lmtp/lmtp_trouble.c create mode 100644 postfix/src/smtp/lmtp_params.c create mode 100644 postfix/src/smtp/smtp-only create mode 100644 postfix/src/smtp/smtp_params.c diff --git a/postfix/HISTORY b/postfix/HISTORY index 7966419ea..a80b68ad8 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -11492,6 +11492,57 @@ Apologies for any names omitted. 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, diff --git a/postfix/Makefile.in b/postfix/Makefile.in index 6ff54224d..a5a7ecdd4 100644 --- a/postfix/Makefile.in +++ b/postfix/Makefile.in @@ -3,7 +3,7 @@ WARN = -Wmissing-prototypes -Wformat 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 \ diff --git a/postfix/RELEASE_NOTES b/postfix/RELEASE_NOTES index d3ff5ff43..c479bb594 100644 --- a/postfix/RELEASE_NOTES +++ b/postfix/RELEASE_NOTES @@ -17,6 +17,27 @@ Incompatibility with Postfix 2.1 and earlier 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 ====================================== diff --git a/postfix/conf/postfix-files b/postfix/conf/postfix-files index ee99c10ee..118988a13 100644 --- a/postfix/conf/postfix-files +++ b/postfix/conf/postfix-files @@ -67,7 +67,7 @@ $daemon_directory/cleanup:f:root:-:755 $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 @@ -86,6 +86,7 @@ $daemon_directory/trivial-rewrite: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 diff --git a/postfix/html/Makefile.in b/postfix/html/Makefile.in index 2f8100480..777024146 100644 --- a/postfix/html/Makefile.in +++ b/postfix/html/Makefile.in @@ -68,9 +68,9 @@ scache.8.html: ../src/scache/scache.c 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; \ @@ -192,7 +192,6 @@ sendmail.1.html: ../src/sendmail/sendmail.c srctoman $? | $(AWK) | nroff -man | uniq | $(MAN2HTML) | postlink >$@ mailq.1.html: sendmail.1.html - PATH=../mantools:$$PATH; \ rm -f $@ ln -s $? $@ diff --git a/postfix/html/lmtp.8.html b/postfix/html/lmtp.8.html deleted file mode 100644 index a8b4ab2cd..000000000 --- a/postfix/html/lmtp.8.html +++ /dev/null @@ -1,305 +0,0 @@ - - - - Postfix manual - lmtp(8) -
-LMTP(8)                                                                LMTP(8)
-
-NAME
-       lmtp - Postfix local delivery via LMTP
-
-SYNOPSIS
-       lmtp [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 recip-
-       ient information.  This program expects to be run from the
-       master(8) 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  bounce(8),  defer(8)  or
-       trace(8) daemon as appropriate.
-
-       The  LMTP  client connects to the destination specified in
-       the message delivery  request.  The  destination,  usually
-       specified in the Postfix transport(5) table, has the form:
-
-       unix:pathname
-              Connect to the local  UNIX-domain  server  that  is
-              bound  to  the  specified  pathname. If the process
-              runs chrooted, an absolute pathname is  interpreted
-              relative to the changed root directory.
-
-       inet:host, inet:host:port (symbolic host)
-
-       inet:[addr], inet:[addr]:port (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 lmtp in ser-
-              vices(4).   If  no  such  service  is  found,   the
-              lmtp_tcp_port   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  unix:  nor  inet:  are  specified,  inet:  is
-       assumed.
-
-SECURITY
-       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 syslogd(8).  Cor-
-       rupted message files are marked so that the queue  manager
-       can move them to the corrupt queue for further inspection.
-
-       Depending on the setting of the notify_classes  parameter,
-       the  postmaster is notified of bounces, protocol problems,
-       and of other trouble.
-
-CONFIGURATION PARAMETERS
-       Changes to main.cf are picked up automatically, as lmtp(8)
-       processes  run  for only a limited amount of time. Use the
-       command "postfix reload" to speed up a change.
-
-       The text below provides  only  a  parameter  summary.  See
-       postconf(5) for more details including examples.
-
-COMPATIBILITY CONTROLS
-       lmtp_skip_quit_response (no)
-              Wait for the response to the LMTP QUIT command.
-
-TROUBLE SHOOTING CONTROLS
-       debug_peer_level (2)
-              The  increment  in  verbose  logging  level  when a
-              remote client or server matches a  pattern  in  the
-              debug_peer_list parameter.
-
-       debug_peer_list (empty)
-              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.
-
-       error_notice_recipient (postmaster)
-              The recipient  of  postmaster  notifications  about
-              mail  delivery  problems that are caused by policy,
-              resource, software or protocol errors.
-
-       notify_classes (resource, software)
-              The list of error classes that are reported to  the
-              postmaster.
-
-EXTERNAL CONTENT INSPECTION CONTROLS
-       Available in Postfix version 2.1 and later:
-
-       lmtp_send_xforward_command (no)
-              Send  an  XFORWARD  command to the LMTP server when
-              the LMTP LHLO server  response  announces  XFORWARD
-              support.
-
-SASL AUTHENTICATION CONTROLS
-       lmtp_sasl_auth_enable (no)
-              Enable  SASL  authentication  in  the  Postfix LMTP
-              client.
-
-       lmtp_sasl_password_maps (empty)
-              Optional LMTP client lookup tables with  one  user-
-              name:password entry per host or domain.
-
-       lmtp_sasl_security_options (noplaintext, noanonymous)
-              What  authentication  mechanisms  the  Postfix LMTP
-              client is allowed to use.
-
-RESOURCE AND RATE CONTROLS
-       In the text below, transport is the name of the service as
-       specified in the master.cf file.
-
-       lmtp_cache_connection (yes)
-              Keep Postfix LMTP client connections open for up to
-              $max_idle seconds.
-
-       transport_destination_concurrency_limit ($default_destina-
-       tion_concurrency_limit)
-              Limit the number of parallel deliveries to the same
-              destination via this mail delivery transport.
-
-       transport_destination_recipient_limit   ($default_destina-
-       tion_recipient_limit)
-              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.
-
-       lmtp_connect_timeout (0s)
-              The LMTP client time limit  for  completing  a  TCP
-              connection,  or  zero  (use  the  operating  system
-              built-in time limit).
-
-       lmtp_lhlo_timeout (300s)
-              The LMTP client time limit for receiving  the  LMTP
-              greeting banner.
-
-       lmtp_xforward_timeout (300s)
-              The LMTP client time limit for sending the XFORWARD
-              command, and for receiving the server response.
-
-       lmtp_mail_timeout (300s)
-              The LMTP client time limit  for  sending  the  MAIL
-              FROM   command,   and   for  receiving  the  server
-              response.
-
-       lmtp_rcpt_timeout (300s)
-              The LMTP client time limit for sending the RCPT  TO
-              command, and for receiving the server response.
-
-       lmtp_data_init_timeout (120s)
-              The  LMTP  client  time  limit for sending the LMTP
-              DATA  command,  and  for   receiving   the   server
-              response.
-
-       lmtp_data_xfer_timeout (180s)
-              The  LMTP  client  time  limit for sending the LMTP
-              message content.
-
-       lmtp_data_done_timeout (600s)
-              The LMTP client time limit  for  sending  the  LMTP
-              ".", and for receiving the server response.
-
-       lmtp_rset_timeout (20s)
-              The  LMTP  client  time  limit for sending the RSET
-              command, and for receiving the server response.
-
-       lmtp_quit_timeout (300s)
-              The LMTP client time limit  for  sending  the  QUIT
-              command, and for receiving the server response.
-
-MISCELLANEOUS CONTROLS
-       config_directory (see 'postconf -d' output)
-              The  default  location  of  the Postfix main.cf and
-              master.cf configuration files.
-
-       daemon_timeout (18000s)
-              How much time a Postfix daemon process may take  to
-              handle  a  request  before  it  is  terminated by a
-              built-in watchdog timer.
-
-       delay_logging_resolution_limit (2)
-              The maximal number  of  digits  after  the  decimal
-              point when logging sub-second delay values.
-
-       disable_dns_lookups (no)
-              Disable  DNS  lookups  in the Postfix SMTP and LMTP
-              clients.
-
-       ipc_timeout (3600s)
-              The time limit for sending or receiving information
-              over an internal communication channel.
-
-       lmtp_tcp_port (24)
-              The  default  TCP port that the Postfix LMTP client
-              connects to.
-
-       max_idle (100s)
-              The maximum amount of time  that  an  idle  Postfix
-              daemon  process  waits for the next service request
-              before exiting.
-
-       max_use (100)
-              The maximal number of connection requests before  a
-              Postfix daemon process terminates.
-
-       process_id (read-only)
-              The  process  ID  of  a  Postfix  command or daemon
-              process.
-
-       process_name (read-only)
-              The process name of a  Postfix  command  or  daemon
-              process.
-
-       queue_directory (see 'postconf -d' output)
-              The  location of the Postfix top-level queue direc-
-              tory.
-
-       syslog_facility (mail)
-              The syslog facility of Postfix logging.
-
-       syslog_name (postfix)
-              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
-       LMTP_README, Postfix LMTP client howto
-       VIRTUAL_README, virtual delivery agent howto
-
-LICENSE
-       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
-
-                                                                       LMTP(8)
-
diff --git a/postfix/html/lmtp.8.html b/postfix/html/lmtp.8.html new file mode 120000 index 000000000..6ec40f8f3 --- /dev/null +++ b/postfix/html/lmtp.8.html @@ -0,0 +1 @@ +smtp.8.html \ No newline at end of file diff --git a/postfix/html/postconf.5.html b/postfix/html/postconf.5.html index fa2eef1fd..6f314d737 100644 --- a/postfix/html/postconf.5.html +++ b/postfix/html/postconf.5.html @@ -893,6 +893,14 @@ a "type:table" lookup table is matched when a (the lookup result is ignored). Continue long lines by starting the next line with whitespace.

+

+Example: +

+ +
+authorized_submit_users = !www, static:all
+
+

This feature is available in Postfix 2.2 and later.

@@ -1366,6 +1374,17 @@ requires that the directory is listed with the connection_cache_protocol_timeout +(default: 5s)
+ +

Time limit for connection cache connect, send or receive +operations. The time limit is enforced in the client.

+ +

This feature is available in Postfix 2.3 and later.

+ +
connection_cache_service @@ -2299,11 +2318,12 @@ This feature was removed in Postfix version 2.1.

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.

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.

The fallback relays must be SMTP destinations. Specify a domain, @@ -2311,7 +2331,8 @@ 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.

-

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.

@@ -2328,7 +2349,8 @@ as the right-hand side for backup or primary MX domain entries. -

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.

@@ -2984,6 +3006,28 @@ This feature is available in Postfix 2.1 and later. this length; upon delivery, long lines are reconstructed.

+ + +
lmtp_bind_address +(default: empty)
+ +

The LMTP-specific version of the smtp_bind_address configuration +parameter. See there for details.

+ +

This feature is available in Postfix 2.3 and later.

+ + +
+ +
lmtp_bind_address6 +(default: empty)
+ +

The LMTP-specific version of the smtp_bind_address6 configuration +parameter. See there for details.

+ +

This feature is available in Postfix 2.3 and later.

+ +
lmtp_cache_connection @@ -3051,6 +3095,39 @@ Example: + + +
lmtp_connection_cache_destinations +(default: empty)
+ +

The LMTP-specific version of the smtp_connection_cache_destinations +configuration parameter. See there for details.

+ +

This feature is available in Postfix 2.3 and later.

+ + +
+ +
lmtp_connection_cache_on_demand +(default: yes)
+ +

The LMTP-specific version of the smtp_connection_cache_on_demand +configuration parameter. See there for details.

+ +

This feature is available in Postfix 2.3 and later.

+ + +
+ +
lmtp_connection_reuse_time_limit +(default: 300s)
+ +

The LMTP-specific version of the smtp_connection_reuse_time_limit +configuration parameter. See there for details.

+ +

This feature is available in Postfix 2.3 and later.

+ +
lmtp_data_done_timeout @@ -3100,6 +3177,17 @@ The default time unit is s (seconds).

+ + +
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.

+ +

This feature is available in Postfix 2.3 and later.

+ +
lmtp_destination_concurrency_limit @@ -3128,20 +3216,127 @@ concurrency per recipient.

-
lmtp_lhlo_timeout -(default: 300s)
+
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.

+ +

This feature is available in Postfix 2.3 and later.

-

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.

+ +
+ +
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.

+ +

This feature is available in Postfix 2.3 and later.

+ +

Notes:

+ +
    + +
  • Specify the silent-discard pseudo keyword to prevent +this action from being logged.

    + +
  • Use the lmtp_discard_lhlo_keyword_address_maps feature to +discard LHLO keywords selectively.

    + +
+ + +
+ +
lmtp_enforce_tls +(default: no)
+ +

The LMTP-specific version of the smtp_enforce_tls configuration +parameter. See there for details.

+ +

This feature is available in Postfix 2.3 and later.

+ + +
+ +
lmtp_generic_maps +(default: empty)
+ +

The LMTP-specific version of the smtp_generic_maps configuration +parameter. See there for details.

+ +

This feature is available in Postfix 2.3 and later.

+ + +
+ +
lmtp_host_lookup +(default: dns)
+ +

The LMTP-specific version of the smtp_host_lookup configuration +parameter. See there for details.

+ +

This feature is available in Postfix 2.3 and later.

+ + +
+ +
lmtp_lhlo_name +(default: $myhostname)

-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. +

+ +

+The default value is the machine hostname. Specify a hostname or +[ip.add.re.ss].

+

+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: +

+ +
+  /etc/postfix/master.cf:
+        mylmtp ... lmtp -o lmtp_lhlo_name=foo.bar.com
+
+ +

+This feature is available in Postfix 2.3 and later. +

+ + +
+ +
lmtp_lhlo_timeout +(default: 300s)
+ +

The LMTP client time limit for sending the LHLO command, and +for receiving the initial server response.

+ +

Time units: s (seconds), m (minutes), h (hours), d (days), w +(weeks). The default time unit is s (seconds).

+ + +
+ +
lmtp_line_length_limit +(default: 990)
+ +

The LMTP-specific version of the smtp_line_length_limit +configuration parameter. See there for details.

+ +

This feature is available in Postfix 2.3 and later.

+
@@ -3159,6 +3354,50 @@ The default time unit is s (seconds).

+ + +
lmtp_mx_address_limit +(default: 5)
+ +

The LMTP-specific version of the smtp_mx_address_limit configuration +parameter. See there for details.

+ +

This feature is available in Postfix 2.3 and later.

+ + +
+ +
lmtp_mx_session_limit +(default: 2)
+ +

The LMTP-specific version of the smtp_mx_session_limit configuration +parameter. See there for details.

+ +

This feature is available in Postfix 2.3 and later.

+ + +
+ +
lmtp_pix_workaround_delay_time +(default: 10s)
+ +

The LMTP-specific version of the smtp_pix_workaround_delay_time +configuration parameter. See there for details.

+ +

This feature is available in Postfix 2.3 and later.

+ + +
+ +
lmtp_pix_workaround_threshold_time +(default: 500s)
+ +

The LMTP-specific version of the smtp_pix_workaround_threshold_time +configuration parameter. See there for details.

+ +

This feature is available in Postfix 2.3 and later.

+ +
lmtp_quit_timeout @@ -3175,6 +3414,28 @@ The default time unit is s (seconds).

+ + +
lmtp_quote_rfc821_envelope +(default: yes)
+ +

The LMTP-specific version of the smtp_quote_rfc821_envelope +configuration parameter. See there for details.

+ +

This feature is available in Postfix 2.3 and later.

+ + +
+ +
lmtp_randomize_addresses +(default: yes)
+ +

The LMTP-specific version of the smtp_randomize_addresses +configuration parameter. See there for details.

+ +

This feature is available in Postfix 2.3 and later.

+ +
lmtp_rcpt_timeout @@ -3217,6 +3478,17 @@ Enable SASL authentication in the Postfix LMTP client.

+ + +
lmtp_sasl_mechanism_filter +(default: empty)
+ +

The LMTP-specific version of the smtp_sasl_mechanism_filter +configuration parameter. See there for details.

+ +

This feature is available in Postfix 2.3 and later.

+ +
lmtp_sasl_password_maps @@ -3272,6 +3544,17 @@ Example: + + +
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.

+ +

This feature is available in Postfix 2.3 and later.

+ +
lmtp_send_xforward_command @@ -3292,6 +3575,28 @@ This feature is available in Postfix 2.1 and later.

+ + +
lmtp_sender_dependent_authentication +(default: no)
+ +

The LMTP-specific version of the smtp_sender_dependent_authentication +configuration parameter. See there for details.

+ +

This feature is available in Postfix 2.3 and later.

+ + +
+ +
lmtp_skip_5xx_greeting +(default: yes)
+ +

The LMTP-specific version of the smtp_skip_5xx_greeting +configuration parameter. See there for details.

+ +

This feature is available in Postfix 2.3 and later.

+ +
lmtp_skip_quit_response @@ -3302,6 +3607,17 @@ Wait for the response to the LMTP QUIT command.

+ + +
lmtp_starttls_timeout +(default: 300s)
+ +

The LMTP-specific version of the smtp_starttls_timeout configuration +parameter. See there for details.

+ +

This feature is available in Postfix 2.3 and later.

+ +
lmtp_tcp_port @@ -3312,6 +3628,61 @@ The default TCP port that the Postfix LMTP client connects to.

+ + +
lmtp_tls_enforce_peername +(default: yes)
+ +

The LMTP-specific version of the smtp_tls_enforce_peername +configuration parameter. See there for details.

+ +

This feature is available in Postfix 2.3 and later.

+ + +
+ +
lmtp_tls_note_starttls_offer +(default: no)
+ +

The LMTP-specific version of the smtp_tls_note_starttls_offer +configuration parameter. See there for details.

+ +

This feature is available in Postfix 2.3 and later.

+ + +
+ +
lmtp_tls_per_site +(default: empty)
+ +

The LMTP-specific version of the smtp_tls_per_site configuration +parameter. See there for details.

+ +

This feature is available in Postfix 2.3 and later.

+ + +
+ +
lmtp_tls_scert_verifydepth +(default: 5)
+ +

The LMTP-specific version of the smtp_tls_scert_verifydepth +configuration parameter. See there for details.

+ +

This feature is available in Postfix 2.3 and later.

+ + +
+ +
lmtp_use_tls +(default: no)
+ +

The LMTP-specific version of the smtp_use_tls configuration +parameter. See there for details.

+ +

This feature is available in Postfix 2.3 and later.

+ +
lmtp_xforward_timeout @@ -5786,7 +6157,7 @@ Example:

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.

@@ -5994,6 +6365,9 @@ IP address), [] or non-default TCP port), as specified in main.cf or in the transport map, +

  • if mail is sent via a UNIX-domain socket: a pathname (without +the unix: prefix), +
  • a /file/name with domain names and/or relay host names as defined above, @@ -6267,6 +6641,31 @@ provide valid server certificates. Typical use is for clients that send all their email to a dedicated mailhub.

    + + +
    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.

    + +

    +By default, mail is returned to the sender when a destination is +not found, and delivery is deferred when a destination is unreachable. +

    + +

    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.

    + +

    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.

    + +
    smtp_generic_maps diff --git a/postfix/html/postfix-manuals.html b/postfix/html/postfix-manuals.html index ed013d06f..ac25aab95 100644 --- a/postfix/html/postfix-manuals.html +++ b/postfix/html/postfix-manuals.html @@ -182,8 +182,6 @@ the following convention:

  • flush(8), Postfix fast ETRN service -
  • lmtp(8), Postfix LMTP client -
  • local(8), Postfix local delivery agent
  • master(8), Postfix master daemon @@ -204,7 +202,7 @@ the following convention:

  • showq(8), list Postfix mail queue -
  • smtp(8), Postfix SMTP client +
  • smtp(8), lmtp(8), Postfix SMTP+LMTP client
  • smtpd(8), Postfix SMTP server diff --git a/postfix/html/postfix.1.html b/postfix/html/postfix.1.html index 7dbcdf40f..fb225222e 100644 --- a/postfix/html/postfix.1.html +++ b/postfix/html/postfix.1.html @@ -244,7 +244,6 @@ POSTFIX(1) POSTFIX(1) 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 @@ -255,7 +254,7 @@ POSTFIX(1) POSTFIX(1) 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 @@ -284,5 +283,20 @@ POSTFIX(1) POSTFIX(1) 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) diff --git a/postfix/html/postsuper.1.html b/postfix/html/postsuper.1.html index b0bfc5154..28e5cc5d9 100644 --- a/postfix/html/postsuper.1.html +++ b/postfix/html/postsuper.1.html @@ -45,136 +45,137 @@ POSTSUPER(1) POSTSUPER(1) delete all mail with exactly one recipient user@example.com: - 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 -d ALL to remove all messages; for example, - specify -d ALL deferred to delete mail in the - deferred queue. As a safety measure, the word ALL + specify -d ALL deferred to delete mail in the + deferred queue. As a safety measure, the word ALL 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 postsuper(1) is asked to delete, + 1) The Postfix queue manager deletes the mes- + sage that postsuper(1) 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 - postsuper(1) 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 + postsuper(1) 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) postsuper(1) deletes the new message, - instead of the old message that it should + 3) postsuper(1) deletes the new message, + instead of the old message that it should have deleted. -h queue_id - 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: incoming, active and deferred) to the hold queue. - If a queue_id of - is specified, the program reads + If a queue_id of - is specified, the program reads queue IDs from standard input. - Specify -h ALL to hold all messages; for example, + Specify -h ALL to hold all messages; for example, specify -h ALL deferred to hold mail in the - deferred queue. As a safety measure, the word ALL + deferred queue. As a safety measure, the word ALL must be specified in upper case. - Note: while mail is "on hold" it will not expire - when its time in the queue exceeds the maxi- + Note: while mail is "on hold" it will not expire + when its time in the queue exceeds the maxi- mal_queue_lifetime or bounce_queue_lifetime set- - ting. It becomes subject to expiration after it is + ting. It becomes subject to expiration after it is released from "hold". -H queue_id 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: hold) to the deferred queue. - If a queue_id of - is specified, the program reads + If a queue_id of - is specified, the program reads queue IDs from standard input. - Note: use "postsuper -r" to release mail that was - kept on hold for a significant fraction of $maxi- + Note: use "postsuper -r" to release mail that was + kept on hold for a significant fraction of $maxi- mal_queue_lifetime or $bounce_queue_lifetime, or longer. - Specify -H ALL to release all mail that is "on - hold". As a safety measure, the word ALL must be + Specify -H ALL to release all mail that is "on + hold". As a safety measure, the word ALL must be specified in upper case. - -p Purge old temporary files that are left over after + -p Purge old temporary files that are left over after system or software crashes. -r queue_id - Requeue the message with the named queue ID from - the named mail queue(s) (default: hold, incoming, - active and deferred). To requeue multiple mes- + Requeue the message with the named queue ID from + the named mail queue(s) (default: hold, incoming, + active and deferred). To requeue multiple mes- sages, specify multiple -r command-line options. Alternatively, if a queue_id of - is specified, the program reads queue IDs from standard input. Specify -r ALL to requeue all messages. As a safety - measure, the word ALL must be specified in upper + measure, the word ALL must be specified in upper case. - A requeued message is moved to the maildrop 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 maildrop 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 postsuper(1) 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 postsuper(1) requeues + the wrong message file when it is executed while + the Postfix mail system is running, but no harm should be done. - -s Structure check and structure repair. This should + -s Structure check and structure repair. This should be done once before Postfix startup. - o Rename files whose name does not match the + o 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. o 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 hash_queue_names and/or hash_queue_depth configuration parameters. -v Enable verbose logging for debugging purposes. Mul- - tiple -v options make the software increasingly + tiple -v options make the software increasingly verbose. DIAGNOSTICS - Problems are reported to the standard error stream and to + Problems are reported to the standard error stream and to syslogd(8). - postsuper(1) reports the number of messages deleted with - -d, the number of messages requeued with -r, and the num- - ber of messages whose queue file name was fixed with -s. - The report is written to the standard error stream and to + postsuper(1) reports the number of messages deleted with + -d, the number of messages requeued with -r, and the num- + ber of messages whose queue file name was fixed with -s. + The report is written to the standard error stream and to syslogd(8). ENVIRONMENT @@ -182,37 +183,37 @@ POSTSUPER(1) POSTSUPER(1) Directory with the main.cf file. BUGS - Mail that is not sanitized by Postfix (i.e. mail in the + Mail that is not sanitized by Postfix (i.e. mail in the maildrop queue) cannot be placed "on hold". CONFIGURATION PARAMETERS - The following main.cf parameters are especially relevant + The following main.cf parameters are especially relevant to this program. The text below provides only a parameter - summary. See postconf(5) for more details including exam- + summary. See postconf(5) for more details including exam- ples. config_directory (see 'postconf -d' output) - The default location of the Postfix main.cf and + The default location of the Postfix main.cf and master.cf configuration files. hash_queue_depth (1) - The number of subdirectory levels for queue direc- - tories listed with the hash_queue_names parameter. + The number of subdirectory levels for queue direc- + tories listed with the hash_queue_names parameter. hash_queue_names (deferred, defer) - The names of queue directories that are split + The names of queue directories that are split across multiple subdirectory levels. queue_directory (see 'postconf -d' output) - The location of the Postfix top-level queue direc- + The location of the Postfix top-level queue direc- tory. syslog_facility (mail) The syslog facility of Postfix logging. syslog_name (postfix) - 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". SEE ALSO @@ -220,7 +221,7 @@ POSTSUPER(1) POSTSUPER(1) postqueue(1), unprivileged queue operations LICENSE - The Secure Mailer license must be distributed with this + The Secure Mailer license must be distributed with this software. AUTHOR(S) diff --git a/postfix/html/smtp.8.html b/postfix/html/smtp.8.html index 65b2ff9db..78f1ca8b3 100644 --- a/postfix/html/smtp.8.html +++ b/postfix/html/smtp.8.html @@ -7,47 +7,85 @@ SMTP(8) SMTP(8) NAME - smtp - Postfix SMTP client + smtp - Postfix SMTP+LMTP client SYNOPSIS smtp [generic Postfix daemon options] DESCRIPTION - 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 master(8) 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 bounce(8), defer(8) or - trace(8) 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 bounce(8), + defer(8) or trace(8) 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 scache(8) 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. +SMTP DESTINATION SYNTAX + SMTP destinations have the following form: + + domainname, domainname:port + Look up the mail exchangers for the specified + domain. + + [hostname], [hostname]:port + Look up the address of the specified host. + + [address], [address]:port + Connect to the host at the specified address. An + IPv6 address must be formatted as [ipv6:address]. + + In all the above cases, when no port is specified, look up + the port defined as smtp in services(4). + +LMTP DESTINATION SYNTAX + LMTP destinations have the following form: + + unix:pathname + Connect to the local UNIX-domain server that is + bound to the specified pathname. If the process + runs chrooted, an absolute pathname is interpreted + relative to the Postfix queue directory. + + inet:hostname, inet:hostname:port + + inet:[address], inet:[address]:port + 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 lmtp in services(4). + If no such service is found, the lmtp_tcp_port con- + figuration parameter (default value of 24) will be + used. + SECURITY - 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) @@ -55,8 +93,9 @@ SMTP(8) SMTP(8) 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) @@ -65,25 +104,30 @@ SMTP(8) SMTP(8) RFC 3463 (Enhanced Status Codes) DIAGNOSTICS - Problems and transactions are logged to syslogd(8). Cor- - rupted message files are marked so that the queue manager + Problems and transactions are logged to syslogd(8). Cor- + rupted message files are marked so that the queue manager can move them to the corrupt queue for further inspection. - Depending on the setting of the notify_classes parameter, - the postmaster is notified of bounces, protocol problems, + Depending on the setting of the notify_classes parameter, + the postmaster is notified of bounces, protocol problems, and of other trouble. BUGS - 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. CONFIGURATION PARAMETERS + Most smtp_xxx configuration parameters have an lmtp_xxx + "ghost" parameter for the equivalent LMTP feature. This + document describes only those LMTP-related parameters that + aren't simply "ghost" parameters. + Changes to main.cf are picked up automatically, as smtp(8) processes run for only a limited amount of time. Use the command "postfix reload" to speed up a change. @@ -158,11 +202,26 @@ SMTP(8) SMTP(8) locally valid address into a globally valid address when sending mail across the Internet. + Available in Postfix version 2.3 and later: + + lmtp_discard_lhlo_keyword_address_maps (empty) + 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. + + lmtp_discard_lhlo_keywords ($myhostname) + 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. + MIME PROCESSING CONTROLS Available in Postfix version 2.0 and later: disable_mime_output_conversion (no) - Disable the conversion of 8BITMIME format to 7BIT + Disable the conversion of 8BITMIME format to 7BIT format. mime_boundary_length_limit (2048) @@ -177,121 +236,121 @@ SMTP(8) SMTP(8) Available in Postfix version 2.1 and later: smtp_send_xforward_command (no) - 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. SASL AUTHENTICATION CONTROLS smtp_sasl_auth_enable (no) - Enable SASL authentication in the Postfix SMTP + Enable SASL authentication in the Postfix SMTP client. smtp_sasl_password_maps (empty) - 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. smtp_sasl_security_options (noplaintext, noanonymous) - 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: smtp_sasl_mechanism_filter (empty) - 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: smtp_sender_dependent_authentication (no) - 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. STARTTLS SUPPORT CONTROLS - Detailed information about STARTTLS configuration may be + Detailed information about STARTTLS configuration may be found in the TLS_README document. smtp_use_tls (no) - 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. smtp_enforce_tls (no) - 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. smtp_sasl_tls_security_options ($smtp_sasl_secu- rity_options) - 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. smtp_starttls_timeout (300s) - 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. smtp_tls_CAfile (empty) - 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. smtp_tls_CApath (empty) - 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. smtp_tls_cert_file (empty) - File with the Postfix SMTP client RSA certificate + File with the Postfix SMTP client RSA certificate in PEM format. smtp_tls_cipherlist (empty) - Controls the Postfix SMTP client TLS cipher selec- + Controls the Postfix SMTP client TLS cipher selec- tion scheme. smtp_tls_dcert_file (empty) - File with the Postfix SMTP client DSA certificate + File with the Postfix SMTP client DSA certificate in PEM format. smtp_tls_dkey_file ($smtp_tls_dcert_file) - File with the Postfix SMTP client DSA private key + File with the Postfix SMTP client DSA private key in PEM format. smtp_tls_enforce_peername (yes) - 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. smtp_tls_key_file ($smtp_tls_cert_file) - File with the Postfix SMTP client RSA private key + File with the Postfix SMTP client RSA private key in PEM format. smtp_tls_loglevel (0) - Enable additional Postfix SMTP client logging of + Enable additional Postfix SMTP client logging of TLS activity. smtp_tls_note_starttls_offer (no) - 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. smtp_tls_per_site (empty) 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. smtp_tls_scert_verifydepth (5) - The verification depth for remote SMTP server cer- + The verification depth for remote SMTP server cer- tificates. smtp_tls_session_cache_database (empty) - Name of the file containing the optional Postfix + Name of the file containing the optional Postfix SMTP client TLS session cache. smtp_tls_session_cache_timeout (3600s) @@ -299,31 +358,36 @@ SMTP(8) SMTP(8) sion cache information. tls_daemon_random_bytes (32) - The number of pseudo-random bytes that an smtp(8) - or smtpd(8) process requests from the tlsmgr(8) - server in order to seed its internal pseudo random + The number of pseudo-random bytes that an smtp(8) + or smtpd(8) process requests from the tlsmgr(8) + server in order to seed its internal pseudo random number generator (PRNG). RESOURCE AND RATE CONTROLS smtp_destination_concurrency_limit ($default_destina- tion_concurrency_limit) - 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. smtp_destination_recipient_limit ($default_destina- tion_recipient_limit) - The maximal number of recipients per delivery via + The maximal number of recipients per delivery via the smtp message delivery transport. smtp_connect_timeout (30s) - 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). smtp_helo_timeout (300s) - 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. + + lmtp_lhlo_timeout (300s) + The LMTP client time limit for sending the LHLO + command, and for receiving the initial server response. smtp_xforward_timeout (300s) @@ -331,30 +395,30 @@ SMTP(8) SMTP(8) command, and for receiving the server response. smtp_mail_timeout (300s) - 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. smtp_rcpt_timeout (300s) - 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. smtp_data_init_timeout (120s) - 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. smtp_data_xfer_timeout (180s) - The SMTP client time limit for sending the SMTP + The SMTP client time limit for sending the SMTP message content. smtp_data_done_timeout (600s) - The SMTP client time limit for sending the SMTP + The SMTP client time limit for sending the SMTP ".", and for receiving the server response. smtp_quit_timeout (300s) - 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: @@ -365,22 +429,22 @@ SMTP(8) SMTP(8) lookups, or zero (no limit). smtp_mx_session_limit (2) - 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 relay host, or zero (no limit). smtp_rset_timeout (20s) - 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: smtp_connection_cache_destinations (empty) - Permanently enable SMTP connection caching for the + Permanently enable SMTP connection caching for the specified destinations. smtp_connection_cache_on_demand (yes) - 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. @@ -390,9 +454,15 @@ SMTP(8) SMTP(8) smtp_connection_cache_time_limit (2s) 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: + + connection_cache_protocol_timeout (5s) + Time limit for connection cache connect, send or + receive operations. + TROUBLE SHOOTING CONTROLS debug_peer_level (2) The increment in verbose logging level when a @@ -437,22 +507,22 @@ SMTP(8) SMTP(8) Disable DNS lookups in the Postfix SMTP and LMTP clients. - fallback_relay (empty) - Optional list of relay hosts for SMTP destinations - that can't be found or that are unreachable. - inet_interfaces (all) The network interface addresses that this mail sys- tem receives mail on. inet_protocols (ipv4) - The Internet protocols Postfix will attempt to use + The Internet protocols Postfix will attempt to use when making or accepting connections. ipc_timeout (3600s) The time limit for sending or receiving information over an internal communication channel. + lmtp_tcp_port (24) + The default TCP port that the Postfix LMTP client + connects to. + max_idle (100s) The maximum amount of time that an idle Postfix daemon process waits for the next service request @@ -489,6 +559,9 @@ SMTP(8) SMTP(8) The hostname to send in the SMTP EHLO or HELO com- mand. + lmtp_lhlo_name ($myhostname) + The hostname to send in the LMTP LHLO command. + smtp_host_lookup (dns) What mechanisms when the SMTP client uses to look up a host's IP address. @@ -505,6 +578,18 @@ SMTP(8) SMTP(8) process name in syslog records, so that "smtpd" becomes, for example, "postfix/smtpd". + Available with Postfix 2.2 and earlier: + + fallback_relay (empty) + Optional list of relay hosts for SMTP destinations + that can't be found or that are unreachable. + + Available with Postfix 2.3 and later: + + smtp_fallback_relay ($fallback_relay) + 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 diff --git a/postfix/makedefs b/postfix/makedefs index d8a3426fc..d60263612 100644 --- a/postfix/makedefs +++ b/postfix/makedefs @@ -401,7 +401,7 @@ CCARGS="$CCARGS -DSNAPSHOT" # Non-production: needs thorough testing, or major changes are still # needed before the code stabilizes. -#CCARGS="$CCARGS -DNONPROD" +CCARGS="$CCARGS -DNONPROD" sed 's/ / /g' <$@ -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 && \ diff --git a/postfix/man/man1/postfix.1 b/postfix/man/man1/postfix.1 index 80c23e5a3..e19443ea1 100644 --- a/postfix/man/man1/postfix.1 +++ b/postfix/man/man1/postfix.1 @@ -210,7 +210,6 @@ cleanup(8), canonicalize and enqueue message 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 @@ -221,7 +220,7 @@ qmgr(8), 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 @@ -259,3 +258,18 @@ Wietse Venema 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 diff --git a/postfix/man/man1/postsuper.1 b/postfix/man/man1/postsuper.1 index 710287b84..23347ef1f 100644 --- a/postfix/man/man1/postsuper.1 +++ b/postfix/man/man1/postsuper.1 @@ -42,7 +42,7 @@ If a \fIqueue_id\fR of \fB-\fR is specified, the program reads 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 diff --git a/postfix/man/man5/postconf.5 b/postfix/man/man5/postconf.5 index 468e5d4a2..7c56cf5ce 100644 --- a/postfix/man/man5/postconf.5 +++ b/postfix/man/man5/postconf.5 @@ -496,6 +496,16 @@ a "type:table" lookup table is matched when a name matches a lookup key (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. @@ -741,6 +751,11 @@ With Postfix command that run with set-gid privileges, a 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. @@ -1225,17 +1240,19 @@ from message headers when mail is submitted with "\fBsendmail -t\fR". 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. @@ -1248,7 +1265,8 @@ the end of the relay entry. 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) @@ -1595,6 +1613,16 @@ This feature is available in Postfix 2.1 and later. .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 @@ -1640,6 +1668,21 @@ lmtp_connect_timeout = 30s .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 @@ -1661,6 +1704,11 @@ the LMTP client terminates the transfer. .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 @@ -1675,27 +1723,116 @@ the entry in the master.cf file. 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. @@ -1712,6 +1849,11 @@ Time units: s (seconds), m (minutes), h (hours), d (days), w (weeks). 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 @@ -1741,6 +1883,11 @@ lmtp_sasl_security_options = noplaintext .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) @@ -1751,10 +1898,50 @@ Before you change the value to yes, it is best to make sure that 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. @@ -3240,7 +3427,7 @@ sender_canonical_maps = hash:/etc/postfix/sender_canonical .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. @@ -3358,6 +3545,9 @@ if mail is sent via a relay host: a relay host name (without [] 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 @@ -3520,6 +3710,22 @@ This option is useful only if you are definitely sure that you 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 diff --git a/postfix/man/man8/lmtp.8 b/postfix/man/man8/lmtp.8 index 09f8bde96..966d30199 100644 --- a/postfix/man/man8/lmtp.8 +++ b/postfix/man/man8/lmtp.8 @@ -1,279 +1 @@ -.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 diff --git a/postfix/man/man8/smtp.8 b/postfix/man/man8/smtp.8 index bce7bafc5..a7176c63b 100644 --- a/postfix/man/man8/smtp.8 +++ b/postfix/man/man8/smtp.8 @@ -4,7 +4,7 @@ .SH NAME smtp \- -Postfix SMTP client +Postfix SMTP+LMTP client .SH "SYNOPSIS" .na .nf @@ -12,42 +12,78 @@ Postfix SMTP client .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 @@ -56,8 +92,9 @@ 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) @@ -77,17 +114,23 @@ other trouble. .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. @@ -146,6 +189,17 @@ from a remote SMTP server. 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 @@ -270,6 +324,9 @@ zero (use the operating system built-in time limit). .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. @@ -316,6 +373,11 @@ connection repeatedly. .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 @@ -353,9 +415,6 @@ 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 "\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. @@ -365,6 +424,8 @@ or accepting connections. .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. @@ -386,6 +447,8 @@ An optional numerical network address that the SMTP client should 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. @@ -396,6 +459,16 @@ 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". +.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 diff --git a/postfix/mantools/postlink b/postfix/mantools/postlink index 00fb66a3a..eab0521be 100755 --- a/postfix/mantools/postlink +++ b/postfix/mantools/postlink @@ -313,6 +313,7 @@ while (<>) { s;\bconnection_cache_service\b;$&;g; s;\bconnection_cache_status_update_time\b;$&;g; + s;\bconnection_cache_protocol_timeout\b;$&;g; s;\bconnection_cache_ttl_limit\b;$&;g; s;\bshow_user_unknown_table_name\b;$&;g; diff --git a/postfix/proto/postconf.proto b/postfix/proto/postconf.proto index 9f61f108c..cf73234eb 100644 --- a/postfix/proto/postconf.proto +++ b/postfix/proto/postconf.proto @@ -1238,15 +1238,37 @@ Example: export_environment = TZ PATH=/bin:/usr/bin +%PARAM smtp_fallback_relay $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.

    + +

    +By default, mail is returned to the sender when a destination is +not found, and delivery is deferred when a destination is unreachable. +

    + +

    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.

    + +

    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.

    + %PARAM fallback_relay

    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.

    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.

    The fallback relays must be SMTP destinations. Specify a domain, @@ -1254,7 +1276,8 @@ 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.

    -

    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.

    @@ -1271,7 +1294,8 @@ as the right-hand side for backup or primary MX domain entries. -

    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.

    %PARAM fast_flush_domains $relay_domains @@ -3614,6 +3638,9 @@ IP address), [] or non-default TCP port), as specified in main.cf or in the transport map, +
  • if mail is sent via a UNIX-domain socket: a pathname (without +the unix: prefix), +
  • a /file/name with domain names and/or relay host names as defined above, @@ -6255,6 +6282,14 @@ a "type:table" lookup table is matched when a name matches a lookup key (the lookup result is ignored). Continue long lines by starting the next line with whitespace.

    +

    +Example: +

    + +
    +authorized_submit_users = !www, static:all
    +
    +

    This feature is available in Postfix 2.2 and later.

    @@ -8719,7 +8754,7 @@ is placed into the Postfix configuration directory.

    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.

    @@ -8749,3 +8784,255 @@ appropriate credentials.

    This feature is available in Postfix 2.3 and later.

    +%PARAM lmtp_lhlo_name $myhostname + +

    +The hostname to send in the LMTP LHLO command. +

    + +

    +The default value is the machine hostname. Specify a hostname or +[ip.add.re.ss]. +

    + +

    +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: +

    + +
    +  /etc/postfix/master.cf:
    +        mylmtp ... lmtp -o lmtp_lhlo_name=foo.bar.com
    +
    + +

    +This feature is available in Postfix 2.3 and later. +

    + +%PARAM lmtp_discard_lhlo_keyword_address_maps + +

    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.

    + +

    This feature is available in Postfix 2.3 and later.

    + +%PARAM lmtp_discard_lhlo_keywords $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.

    + +

    This feature is available in Postfix 2.3 and later.

    + +

    Notes:

    + +
      + +
    • Specify the silent-discard pseudo keyword to prevent +this action from being logged.

      + +
    • Use the lmtp_discard_lhlo_keyword_address_maps feature to +discard LHLO keywords selectively.

      + +
    + +%PARAM lmtp_lhlo_timeout 300s + +

    The LMTP client time limit for sending the LHLO command, and +for receiving the initial server response.

    + +

    Time units: s (seconds), m (minutes), h (hours), d (days), w +(weeks). The default time unit is s (seconds).

    + +%PARAM lmtp_sasl_tls_security_options $var_lmtp_sasl_opts + +

    The LMTP-specific version of the smtp_sasl_tls_security_options +configuration parameter. See there for details.

    + +

    This feature is available in Postfix 2.3 and later.

    + +%PARAM lmtp_sasl_mechanism_filter + +

    The LMTP-specific version of the smtp_sasl_mechanism_filter +configuration parameter. See there for details.

    + +

    This feature is available in Postfix 2.3 and later.

    + +%PARAM lmtp_bind_address + +

    The LMTP-specific version of the smtp_bind_address configuration +parameter. See there for details.

    + +

    This feature is available in Postfix 2.3 and later.

    + +%PARAM lmtp_bind_address6 + +

    The LMTP-specific version of the smtp_bind_address6 configuration +parameter. See there for details.

    + +

    This feature is available in Postfix 2.3 and later.

    + +%PARAM lmtp_host_lookup dns + +

    The LMTP-specific version of the smtp_host_lookup configuration +parameter. See there for details.

    + +

    This feature is available in Postfix 2.3 and later.

    + +%PARAM lmtp_connection_cache_destinations + +

    The LMTP-specific version of the smtp_connection_cache_destinations +configuration parameter. See there for details.

    + +

    This feature is available in Postfix 2.3 and later.

    + +%PARAM lmtp_tls_per_site + +

    The LMTP-specific version of the smtp_tls_per_site configuration +parameter. See there for details.

    + +

    This feature is available in Postfix 2.3 and later.

    + +%PARAM lmtp_generic_maps + +

    The LMTP-specific version of the smtp_generic_maps configuration +parameter. See there for details.

    + +

    This feature is available in Postfix 2.3 and later.

    + +%PARAM lmtp_pix_workaround_threshold_time 500s + +

    The LMTP-specific version of the smtp_pix_workaround_threshold_time +configuration parameter. See there for details.

    + +

    This feature is available in Postfix 2.3 and later.

    + +%PARAM lmtp_pix_workaround_delay_time 10s + +

    The LMTP-specific version of the smtp_pix_workaround_delay_time +configuration parameter. See there for details.

    + +

    This feature is available in Postfix 2.3 and later.

    + +%PARAM lmtp_connection_reuse_time_limit 300s + +

    The LMTP-specific version of the smtp_connection_reuse_time_limit +configuration parameter. See there for details.

    + +

    This feature is available in Postfix 2.3 and later.

    + +%PARAM lmtp_starttls_timeout 300s + +

    The LMTP-specific version of the smtp_starttls_timeout configuration +parameter. See there for details.

    + +

    This feature is available in Postfix 2.3 and later.

    + +%PARAM lmtp_line_length_limit 990 + +

    The LMTP-specific version of the smtp_line_length_limit +configuration parameter. See there for details.

    + +

    This feature is available in Postfix 2.3 and later.

    + +%PARAM lmtp_mx_address_limit 5 + +

    The LMTP-specific version of the smtp_mx_address_limit configuration +parameter. See there for details.

    + +

    This feature is available in Postfix 2.3 and later.

    + +%PARAM lmtp_mx_session_limit 2 + +

    The LMTP-specific version of the smtp_mx_session_limit configuration +parameter. See there for details.

    + +

    This feature is available in Postfix 2.3 and later.

    + +%PARAM lmtp_tls_scert_verifydepth 5 + +

    The LMTP-specific version of the smtp_tls_scert_verifydepth +configuration parameter. See there for details.

    + +

    This feature is available in Postfix 2.3 and later.

    + +%PARAM lmtp_skip_5xx_greeting yes + +

    The LMTP-specific version of the smtp_skip_5xx_greeting +configuration parameter. See there for details.

    + +

    This feature is available in Postfix 2.3 and later.

    + +%PARAM lmtp_randomize_addresses yes + +

    The LMTP-specific version of the smtp_randomize_addresses +configuration parameter. See there for details.

    + +

    This feature is available in Postfix 2.3 and later.

    + +%PARAM lmtp_quote_rfc821_envelope yes + +

    The LMTP-specific version of the smtp_quote_rfc821_envelope +configuration parameter. See there for details.

    + +

    This feature is available in Postfix 2.3 and later.

    + +%PARAM lmtp_defer_if_no_mx_address_found no + +

    The LMTP-specific version of the smtp_defer_if_no_mx_address_found +configuration parameter. See there for details.

    + +

    This feature is available in Postfix 2.3 and later.

    + +%PARAM lmtp_connection_cache_on_demand yes + +

    The LMTP-specific version of the smtp_connection_cache_on_demand +configuration parameter. See there for details.

    + +

    This feature is available in Postfix 2.3 and later.

    + +%PARAM lmtp_use_tls no + +

    The LMTP-specific version of the smtp_use_tls configuration +parameter. See there for details.

    + +

    This feature is available in Postfix 2.3 and later.

    + +%PARAM lmtp_enforce_tls no + +

    The LMTP-specific version of the smtp_enforce_tls configuration +parameter. See there for details.

    + +

    This feature is available in Postfix 2.3 and later.

    + +%PARAM lmtp_tls_enforce_peername yes + +

    The LMTP-specific version of the smtp_tls_enforce_peername +configuration parameter. See there for details.

    + +

    This feature is available in Postfix 2.3 and later.

    + +%PARAM lmtp_tls_note_starttls_offer no + +

    The LMTP-specific version of the smtp_tls_note_starttls_offer +configuration parameter. See there for details.

    + +

    This feature is available in Postfix 2.3 and later.

    + +%PARAM lmtp_sender_dependent_authentication no + +

    The LMTP-specific version of the smtp_sender_dependent_authentication +configuration parameter. See there for details.

    + +

    This feature is available in Postfix 2.3 and later.

    + +%PARAM connection_cache_protocol_timeout 5s + +

    Time limit for connection cache connect, send or receive +operations. The time limit is enforced in the client.

    + +

    This feature is available in Postfix 2.3 and later.

    diff --git a/postfix/src/global/Makefile.in b/postfix/src/global/Makefile.in index 9a9ad6104..590a02221 100644 --- a/postfix/src/global/Makefile.in +++ b/postfix/src/global/Makefile.in @@ -1559,14 +1559,15 @@ scache.o: ../../include/vstring_vstream.h 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 diff --git a/postfix/src/global/deliver_pass.c b/postfix/src/global/deliver_pass.c index 943a58c25..09403e820 100644 --- a/postfix/src/global/deliver_pass.c +++ b/postfix/src/global/deliver_pass.c @@ -69,6 +69,9 @@ #include #include +#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) @@ -140,9 +143,10 @@ static int deliver_pass_final_reply(VSTREAM *stream, DSN_BUF *dsb) 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 */ @@ -153,6 +157,7 @@ int deliver_pass(const char *class, const char *service, { VSTREAM *stream; DSN_BUF *dsb; + DSN dsn; int status; char *saved_service; char *transport; @@ -184,10 +189,23 @@ int deliver_pass(const char *class, const char *service, * 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. diff --git a/postfix/src/global/deliver_request.c b/postfix/src/global/deliver_request.c index fba702725..1391e5d7c 100644 --- a/postfix/src/global/deliver_request.c +++ b/postfix/src/global/deliver_request.c @@ -17,7 +17,7 @@ /* char *nexthop; /* char *encoding; /* char *sender; -/* MSG_STATS stats; +/* MSG_STATS msg_stats; /* RECIPIENT_LIST rcpt_list; /* DSN *hop_status; /* char *client_name; @@ -240,7 +240,7 @@ static int deliver_request_get(VSTREAM *stream, DELIVER_REQUEST *request) 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, @@ -304,6 +304,11 @@ static int deliver_request_get(VSTREAM *stream, DELIVER_REQUEST *request) 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 diff --git a/postfix/src/global/mail_params.h b/postfix/src/global/mail_params.h index fc513fe02..eff145f19 100644 --- a/postfix/src/global/mail_params.h +++ b/postfix/src/global/mail_params.h @@ -189,7 +189,9 @@ extern char *var_relayhost; #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; @@ -202,14 +204,20 @@ extern bool var_disable_dns; #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; /* @@ -848,22 +856,32 @@ extern char *var_inet_protocols; #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" @@ -872,6 +890,8 @@ extern int var_smtp_conn_tmout; #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" @@ -880,6 +900,8 @@ extern int var_smtp_xfwd_tmout; #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" @@ -912,10 +934,14 @@ extern int var_smtp_quit_tmout; #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" @@ -940,34 +966,50 @@ extern bool var_smtp_never_ehlo; #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" @@ -976,6 +1018,8 @@ extern bool var_smtp_send_xforward; #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; /* @@ -1113,22 +1157,32 @@ extern int var_smtpd_tls_scache_timeout; #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" @@ -1165,6 +1219,8 @@ extern int var_smtp_tls_loglevel; #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" @@ -1233,10 +1289,14 @@ extern char *var_smtp_sasl_opts; #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; /* @@ -1314,8 +1374,8 @@ extern char *var_lmtp_sasl_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 @@ -2081,10 +2141,14 @@ extern char *var_flush_service; /* * 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; @@ -2335,7 +2399,7 @@ extern int var_anvil_stat_time; #if 0 #include -#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; @@ -2367,10 +2431,14 @@ extern char *var_smtpd_ehlo_dis_maps; #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; /* @@ -2417,6 +2485,8 @@ extern char *var_bounce_tmpl; */ #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 diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index 08a7f541d..f1d12a758 100644 --- a/postfix/src/global/mail_version.h +++ b/postfix/src/global/mail_version.h @@ -20,7 +20,7 @@ * 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 diff --git a/postfix/src/global/scache.h b/postfix/src/global/scache.h index 1670546c5..836d76599 100644 --- a/postfix/src/global/scache.h +++ b/postfix/src/global/scache.h @@ -110,7 +110,7 @@ struct SCACHE { }; 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) \ diff --git a/postfix/src/global/scache_clnt.c b/postfix/src/global/scache_clnt.c index f8098eea3..c1d3a058b 100644 --- a/postfix/src/global/scache_clnt.c +++ b/postfix/src/global/scache_clnt.c @@ -6,8 +6,9 @@ /* SYNOPSIS /* #include /* 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 @@ -19,6 +20,8 @@ /* 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 @@ -49,6 +52,8 @@ #include #include +#include +#include /*#define msg_verbose 1*/ @@ -56,7 +61,6 @@ #include #include -#include #include /* Application-specific. */ @@ -66,7 +70,7 @@ */ 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 @@ -103,44 +107,45 @@ static void scache_clnt_save_endp(SCACHE *scache, int endp_ttl, * 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) @@ -164,61 +169,62 @@ static int scache_clnt_find_endp(SCACHE *scache, const char *endp_label, * 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); } @@ -251,39 +257,40 @@ static void scache_clnt_save_dest(SCACHE *scache, int dest_ttl, * 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); } } @@ -305,62 +312,63 @@ static int scache_clnt_find_dest(SCACHE *scache, const char *dest_label, * 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); } @@ -381,8 +389,8 @@ static void scache_clnt_free(SCACHE *scache) { 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 @@ -391,9 +399,11 @@ static void scache_clnt_free(SCACHE *scache) /* 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; @@ -402,9 +412,10 @@ SCACHE *scache_clnt_create(const char *server, int idle_limit, int ttl_limit) 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 diff --git a/postfix/src/lmtp/.indent.pro b/postfix/src/lmtp/.indent.pro deleted file mode 120000 index 5c837eca6..000000000 --- a/postfix/src/lmtp/.indent.pro +++ /dev/null @@ -1 +0,0 @@ -../../.indent.pro \ No newline at end of file diff --git a/postfix/src/lmtp/.printfck b/postfix/src/lmtp/.printfck deleted file mode 100644 index 66016ed45..000000000 --- a/postfix/src/lmtp/.printfck +++ /dev/null @@ -1,25 +0,0 @@ -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 diff --git a/postfix/src/lmtp/Makefile.in b/postfix/src/lmtp/Makefile.in deleted file mode 100644 index 10210d785..000000000 --- a/postfix/src/lmtp/Makefile.in +++ /dev/null @@ -1,330 +0,0 @@ -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 diff --git a/postfix/src/lmtp/lmtp.c b/postfix/src/lmtp/lmtp.c deleted file mode 100644 index 2af07f753..000000000 --- a/postfix/src/lmtp/lmtp.c +++ /dev/null @@ -1,615 +0,0 @@ -/*++ -/* 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 -#include -#include -#include -#include -#include - -/* Utility library. */ - -#include -#include -#include -#include -#include - -/* Global library. */ - -#include -#include -#include -#include -#include -#include -#include -#include - -/* Single server skeleton. */ - -#include - -/* 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); -} diff --git a/postfix/src/lmtp/lmtp.h b/postfix/src/lmtp/lmtp.h deleted file mode 100644 index aa4407220..000000000 --- a/postfix/src/lmtp/lmtp.h +++ /dev/null @@ -1,202 +0,0 @@ -/*++ -/* NAME -/* lmtp 3h -/* SUMMARY -/* lmtp client program -/* SYNOPSIS -/* #include "lmtp.h" -/* DESCRIPTION -/* .nf - - /* - * SASL library. - */ -#ifdef USE_SASL_AUTH -#include -#include -#endif - - /* - * Utility library. - */ -#include -#include -#include - - /* - * Global library. - */ -#include -#include - - /* - * 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 -/*--*/ diff --git a/postfix/src/lmtp/lmtp_addr.c b/postfix/src/lmtp/lmtp_addr.c deleted file mode 100644 index e23849b28..000000000 --- a/postfix/src/lmtp/lmtp_addr.c +++ /dev/null @@ -1,235 +0,0 @@ -/*++ -/* 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 -#include -#include -#include -#include -#include -#include -#include -#include - -/* Utility library. */ - -#include -#include -#include -#include -#include -#include -#include -#include - -/* Global library. */ - -#include -#include - -/* DNS library. */ - -#include - -/* 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); -} diff --git a/postfix/src/lmtp/lmtp_addr.h b/postfix/src/lmtp/lmtp_addr.h deleted file mode 100644 index a29dba0dd..000000000 --- a/postfix/src/lmtp/lmtp_addr.h +++ /dev/null @@ -1,46 +0,0 @@ -/*++ -/* NAME -/* lmtp_addr 3h -/* SUMMARY -/* LMTP server address lookup -/* SYNOPSIS -/* #include "lmtp_addr.h" -/* DESCRIPTION -/* .nf - - /* - * Global library. - */ -#include - - /* - * DNS library. - */ -#include - - /* - * 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 -/*--*/ diff --git a/postfix/src/lmtp/lmtp_chat.c b/postfix/src/lmtp/lmtp_chat.c deleted file mode 100644 index 4abb0d664..000000000 --- a/postfix/src/lmtp/lmtp_chat.c +++ /dev/null @@ -1,361 +0,0 @@ -/*++ -/* 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 -#include /* 44BSD stdarg.h uses abort() */ -#include -#include -#include -#include -#include - -/* Utility library. */ - -#include -#include -#include -#include -#include -#include -#include - -/* Global library. */ - -#include -#include -#include -#include -#include -#include -#include -#include - -/* 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 ".QUIT", 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); -} diff --git a/postfix/src/lmtp/lmtp_connect.c b/postfix/src/lmtp/lmtp_connect.c deleted file mode 100644 index b043257b3..000000000 --- a/postfix/src/lmtp/lmtp_connect.c +++ /dev/null @@ -1,386 +0,0 @@ -/*++ -/* 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef STRCASECMP_IN_STRINGS_H -#include -#endif - -/* Utility library. */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Global library. */ - -#include -#include -#include -#include - -/* DNS library. */ - -#include - -/* 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); -} diff --git a/postfix/src/lmtp/lmtp_dsn.c b/postfix/src/lmtp/lmtp_dsn.c deleted file mode 100644 index aba903583..000000000 --- a/postfix/src/lmtp/lmtp_dsn.c +++ /dev/null @@ -1,144 +0,0 @@ -/*++ -/* NAME -/* lmtp_dsn 3 -/* SUMMARY -/* application-specific wrappers -/* SYNOPSIS -/* #include -/* -/* 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 -#include /* 44BSD stdarg.h uses abort() */ -#include - -/* Utility library. */ - -#include - -/* Global library. */ - -#include - -/* Application-specific. */ - -#include - -/* 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); -} diff --git a/postfix/src/lmtp/lmtp_proto.c b/postfix/src/lmtp/lmtp_proto.c deleted file mode 100644 index d051c5331..000000000 --- a/postfix/src/lmtp/lmtp_proto.c +++ /dev/null @@ -1,905 +0,0 @@ -/*++ -/* 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 -#include -#include /* shutdown(2) */ -#include -#include -#include -#include /* 44BSD stdarg.h uses abort() */ -#include -#include - -#ifdef STRCASECMP_IN_STRINGS_H -#include -#endif - -/* Utility library. */ - -#include -#include -#include -#include -#include -#include -#include - -/* Global library. */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* 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)); -} diff --git a/postfix/src/lmtp/lmtp_rcpt.c b/postfix/src/lmtp/lmtp_rcpt.c deleted file mode 100644 index 8d2b3e010..000000000 --- a/postfix/src/lmtp/lmtp_rcpt.c +++ /dev/null @@ -1,83 +0,0 @@ -/*++ -/* NAME -/* lmtp_rcpt 3 -/* SUMMARY -/* application-specific recipient list operations -/* SYNOPSIS -/* #include -/* -/* 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 -#include /* lmtp_rcpt_cleanup */ -#include - -/* Utility library. */ - -#include - -/* Global library. */ - -#include -#include -#include -#include - -/* Application-specific. */ - -#include - -/* 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; -} diff --git a/postfix/src/lmtp/lmtp_sasl.h b/postfix/src/lmtp/lmtp_sasl.h deleted file mode 100644 index 4d05b1de7..000000000 --- a/postfix/src/lmtp/lmtp_sasl.h +++ /dev/null @@ -1,39 +0,0 @@ -/*++ -/* 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 -/*--*/ diff --git a/postfix/src/lmtp/lmtp_sasl_glue.c b/postfix/src/lmtp/lmtp_sasl_glue.c deleted file mode 100644 index 3c0a6f8ed..000000000 --- a/postfix/src/lmtp/lmtp_sasl_glue.c +++ /dev/null @@ -1,638 +0,0 @@ -/*++ -/* 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 -#include -#include -#ifdef STRCASECMP_IN_STRINGS_H -#include -#endif - - /* - * Utility library - */ -#include -#include -#include -#include -#include - - /* - * Global library - */ -#include -#include -#include - - /* - * 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 diff --git a/postfix/src/lmtp/lmtp_sasl_proto.c b/postfix/src/lmtp/lmtp_sasl_proto.c deleted file mode 100644 index 143711f67..000000000 --- a/postfix/src/lmtp/lmtp_sasl_proto.c +++ /dev/null @@ -1,128 +0,0 @@ -/*++ -/* 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 -#include -#ifdef STRCASECMP_IN_STRINGS_H -#include -#endif - -/* Utility library. */ - -#include -#include - -/* Global library. */ - -#include - -/* 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 diff --git a/postfix/src/lmtp/lmtp_session.c b/postfix/src/lmtp/lmtp_session.c deleted file mode 100644 index 411ee8172..000000000 --- a/postfix/src/lmtp/lmtp_session.c +++ /dev/null @@ -1,106 +0,0 @@ -/*++ -/* 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 - -/* Utility library. */ - -#include -#include -#include - -/* Global library. */ - -#include - -/* 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); -} diff --git a/postfix/src/lmtp/lmtp_state.c b/postfix/src/lmtp/lmtp_state.c deleted file mode 100644 index d514a87d3..000000000 --- a/postfix/src/lmtp/lmtp_state.c +++ /dev/null @@ -1,103 +0,0 @@ -/*++ -/* 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 - -/* Utility library. */ - -#include -#include -#include - -/* Global library. */ - -#include - -/* 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); -} diff --git a/postfix/src/lmtp/lmtp_trouble.c b/postfix/src/lmtp/lmtp_trouble.c deleted file mode 100644 index 5ef08f9a2..000000000 --- a/postfix/src/lmtp/lmtp_trouble.c +++ /dev/null @@ -1,405 +0,0 @@ -/*++ -/* 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 -#include /* 44BSD stdarg.h uses abort() */ -#include -#include - -/* Utility library. */ - -#include -#include -#include - -/* Global library. */ - -#include -#include -#include -#include -#include -#include -#include -#include - -/* 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)); -} diff --git a/postfix/src/postfix/postfix.c b/postfix/src/postfix/postfix.c index fded3afe8..bad094a78 100644 --- a/postfix/src/postfix/postfix.c +++ b/postfix/src/postfix/postfix.c @@ -196,7 +196,6 @@ /* 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 @@ -207,7 +206,7 @@ /* 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 @@ -239,6 +238,21 @@ /* 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. */ diff --git a/postfix/src/postsuper/postsuper.c b/postfix/src/postsuper/postsuper.c index 32b818d3b..94c55aa11 100644 --- a/postfix/src/postsuper/postsuper.c +++ b/postfix/src/postsuper/postsuper.c @@ -36,7 +36,7 @@ /* 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 diff --git a/postfix/src/scache/scache.c b/postfix/src/scache/scache.c index deb6f0dad..86e17f459 100644 --- a/postfix/src/scache/scache.c +++ b/postfix/src/scache/scache.c @@ -421,27 +421,36 @@ static void scache_service(VSTREAM *client_stream, char *unused_service, * 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); } diff --git a/postfix/src/smtp/Makefile.in b/postfix/src/smtp/Makefile.in index a67da3b55..b38447207 100644 --- a/postfix/src/smtp/Makefile.in +++ b/postfix/src/smtp/Makefile.in @@ -36,6 +36,12 @@ update: ../../libexec/$(PROG) ../../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 @@ -79,6 +85,7 @@ depend: $(MAKES) @$(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 @@ -103,14 +110,17 @@ smtp.o: ../../include/recipient_list.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 @@ -231,6 +241,7 @@ smtp_dsn.o: ../../include/dict.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 @@ -275,6 +286,7 @@ smtp_map11.o: ../../include/vstream.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 @@ -361,7 +373,6 @@ smtp_reuse.o: ../../include/argv.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 @@ -371,12 +382,10 @@ smtp_reuse.o: ../../include/match_list.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 @@ -395,6 +404,7 @@ smtp_sasl_glue.o: ../../include/dict.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 @@ -488,6 +498,7 @@ smtp_state.o: ../../include/mail_params.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 diff --git a/postfix/src/smtp/lmtp_params.c b/postfix/src/smtp/lmtp_params.c new file mode 100644 index 000000000..39f201872 --- /dev/null +++ b/postfix/src/smtp/lmtp_params.c @@ -0,0 +1,72 @@ + 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, + }; diff --git a/postfix/src/smtp/smtp-only b/postfix/src/smtp/smtp-only new file mode 100644 index 000000000..134dcd452 --- /dev/null +++ b/postfix/src/smtp/smtp-only @@ -0,0 +1,4 @@ +_ALWAYS_EHLO +_NEVER_EHLO +_SMTP_FALLBACK +_IGN_MX_LOOKUP_ERR diff --git a/postfix/src/smtp/smtp.c b/postfix/src/smtp/smtp.c index 0208d2749..ee1312b18 100644 --- a/postfix/src/smtp/smtp.c +++ b/postfix/src/smtp/smtp.c @@ -2,52 +2,85 @@ /* 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) @@ -63,15 +96,21 @@ /* 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. @@ -128,6 +167,17 @@ /* 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 @@ -242,6 +292,9 @@ /* .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. @@ -288,6 +341,11 @@ /* .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 @@ -321,9 +379,6 @@ /* 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. @@ -333,6 +388,8 @@ /* .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. @@ -354,6 +411,8 @@ /* 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. @@ -364,6 +423,16 @@ /* .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 @@ -425,6 +494,7 @@ #include #include #include +#include /* Utility library. */ @@ -518,6 +588,8 @@ bool var_smtp_tls_note_starttls_offer; 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 @@ -645,6 +717,7 @@ static void post_init(char *unused_name, char **unused_argv) 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 @@ -740,87 +813,27 @@ static void pre_exit(void) 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, diff --git a/postfix/src/smtp/smtp.h b/postfix/src/smtp/smtp.h index 681a7e05f..0448b8a63 100644 --- a/postfix/src/smtp/smtp.h +++ b/postfix/src/smtp/smtp.h @@ -46,6 +46,7 @@ * 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 */ @@ -139,8 +140,7 @@ typedef struct SMTP_STATE { */ #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 @@ -246,7 +246,7 @@ extern int smtp_connect(SMTP_STATE *); /* * 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 *); diff --git a/postfix/src/smtp/smtp_connect.c b/postfix/src/smtp/smtp_connect.c index 62fa9c53b..b9a4a7164 100644 --- a/postfix/src/smtp/smtp_connect.c +++ b/postfix/src/smtp/smtp_connect.c @@ -2,29 +2,31 @@ /* 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 @@ -55,6 +57,7 @@ #include #include #include +#include #include #include #include @@ -103,9 +106,70 @@ #include #include + /* + * 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) { @@ -115,13 +179,8 @@ static SMTP_SESSION *smtp_connect_addr(const char *dest, DNS_RR *addr, 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 */ @@ -207,12 +266,33 @@ static SMTP_SESSION *smtp_connect_addr(const char *dest, DNS_RR *addr, } /* - * 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); @@ -227,7 +307,7 @@ static SMTP_SESSION *smtp_connect_addr(const char *dest, DNS_RR *addr, 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); @@ -274,11 +354,11 @@ static SMTP_SESSION *smtp_connect_addr(const char *dest, DNS_RR *addr, /* * 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) @@ -304,7 +384,7 @@ static char *smtp_parse_destination(char *destination, char *def_service, * 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 { @@ -390,6 +470,62 @@ static void smtp_cleanup_session(SMTP_STATE *state) 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) @@ -474,6 +610,7 @@ static int smtp_reuse_session(SMTP_STATE *state, int lookup_mx, DNS_RR *addr; DNS_RR *next; int saved_final_server = state->final_server; + MAI_HOSTADDR_STR hostaddr; SMTP_SESSION *session; /* @@ -503,7 +640,8 @@ static int smtp_reuse_session(SMTP_STATE *state, int lookup_mx, 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); @@ -517,31 +655,19 @@ static int smtp_reuse_session(SMTP_STATE *state, int lookup_mx, 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 @@ -555,7 +681,12 @@ int smtp_connect(SMTP_STATE *state) 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 @@ -577,6 +708,20 @@ int smtp_connect(SMTP_STATE *state) (*(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 @@ -591,21 +736,39 @@ int smtp_connect(SMTP_STATE *state) */ 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 @@ -631,34 +794,16 @@ int smtp_connect(SMTP_STATE *state) * 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 @@ -667,6 +812,8 @@ int smtp_connect(SMTP_STATE *state) 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); @@ -674,7 +821,8 @@ int smtp_connect(SMTP_STATE *state) 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 @@ -696,7 +844,8 @@ int smtp_connect(SMTP_STATE *state) 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; @@ -705,7 +854,7 @@ int smtp_connect(SMTP_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); @@ -728,35 +877,35 @@ int smtp_connect(SMTP_STATE *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; @@ -781,36 +930,9 @@ int smtp_connect(SMTP_STATE *state) 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"); } } @@ -820,6 +942,78 @@ int smtp_connect(SMTP_STATE *state) 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); } diff --git a/postfix/src/smtp/smtp_dsn.c b/postfix/src/smtp/smtp_dsn.c index 9a880ab6a..a48701ec0 100644 --- a/postfix/src/smtp/smtp_dsn.c +++ b/postfix/src/smtp/smtp_dsn.c @@ -104,6 +104,7 @@ /* Global library. */ #include +#include /* Application-specific. */ @@ -132,7 +133,7 @@ void vsmtp_dsn_update(DSN_BUF *why, const char *mta_name, { 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); } @@ -144,5 +145,5 @@ void smtp_dsn_formal(DSN_BUF *why, const char *mta_name, { 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); } diff --git a/postfix/src/smtp/smtp_params.c b/postfix/src/smtp/smtp_params.c new file mode 100644 index 000000000..021229c43 --- /dev/null +++ b/postfix/src/smtp/smtp_params.c @@ -0,0 +1,76 @@ + 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, + }; diff --git a/postfix/src/smtp/smtp_proto.c b/postfix/src/smtp/smtp_proto.c index 56429fcc8..c8adb4c4c 100644 --- a/postfix/src/smtp/smtp_proto.c +++ b/postfix/src/smtp/smtp_proto.c @@ -2,13 +2,12 @@ /* 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; @@ -19,6 +18,7 @@ /* 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. @@ -230,11 +230,11 @@ char *xfer_request[SMTP_STATE_LAST] = { "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; @@ -267,7 +267,7 @@ int smtp_helo(SMTP_STATE *state, NOCLOBBER int misc_flags) * 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. @@ -275,7 +275,7 @@ int smtp_helo(SMTP_STATE *state, NOCLOBBER int misc_flags) 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. @@ -312,18 +312,22 @@ int smtp_helo(SMTP_STATE *state, NOCLOBBER int misc_flags) (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; + } } /* @@ -338,19 +342,28 @@ int smtp_helo(SMTP_STATE *state, NOCLOBBER int misc_flags) * 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); } /* @@ -382,7 +395,7 @@ int smtp_helo(SMTP_STATE *state, NOCLOBBER int misc_flags) 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) @@ -483,7 +496,7 @@ int smtp_helo(SMTP_STATE *state, NOCLOBBER int misc_flags) /* * 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. @@ -528,8 +541,8 @@ int smtp_helo(SMTP_STATE *state, NOCLOBBER int misc_flags) } #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)); } /* @@ -587,7 +600,7 @@ int smtp_helo(SMTP_STATE *state, NOCLOBBER int misc_flags) /* 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; @@ -644,7 +657,7 @@ static int smtp_start_tls(SMTP_STATE *state, int misc_flags) * 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 @@ -848,11 +861,13 @@ static int smtp_loop(SMTP_STATE *state, NOCLOBBER int send_state, 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; @@ -881,6 +896,8 @@ static int smtp_loop(SMTP_STATE *state, NOCLOBBER int send_state, #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); \ @@ -929,7 +946,7 @@ static int smtp_loop(SMTP_STATE *state, NOCLOBBER int send_state, * 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; /* @@ -1277,6 +1294,13 @@ static int smtp_loop(SMTP_STATE *state, NOCLOBBER int send_state, #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)) { @@ -1327,24 +1351,53 @@ static int smtp_loop(SMTP_STATE *state, NOCLOBBER int send_state, */ 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 diff --git a/postfix/src/smtp/smtp_reuse.c b/postfix/src/smtp/smtp_reuse.c index 6d122421d..3cb097495 100644 --- a/postfix/src/smtp/smtp_reuse.c +++ b/postfix/src/smtp/smtp_reuse.c @@ -18,7 +18,7 @@ /* /* 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 @@ -46,7 +46,7 @@ /* .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 @@ -221,9 +221,9 @@ SMTP_SESSION *smtp_reuse_domain(SMTP_STATE *state, int lookup_mx, /* 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; @@ -234,10 +234,8 @@ SMTP_SESSION *smtp_reuse_addr(SMTP_STATE *state, DNS_RR *addr, unsigned port) * 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); diff --git a/postfix/src/smtp/smtp_reuse.h b/postfix/src/smtp/smtp_reuse.h index 9018c9fc7..bf005c043 100644 --- a/postfix/src/smtp/smtp_reuse.h +++ b/postfix/src/smtp/smtp_reuse.h @@ -8,17 +8,12 @@ /* DESCRIPTION /* .nf - /* - * DNS library. - */ -#include - /* * 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 diff --git a/postfix/src/smtp/smtp_sasl_glue.c b/postfix/src/smtp/smtp_sasl_glue.c index 81a931d03..8e78942d2 100644 --- a/postfix/src/smtp/smtp_sasl_glue.c +++ b/postfix/src/smtp/smtp_sasl_glue.c @@ -331,7 +331,8 @@ int smtp_sasl_passwd_lookup(SMTP_SESSION *session) * 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 @@ -460,7 +461,7 @@ void smtp_sasl_start(SMTP_SESSION *session, const char *sasl_opts_name, #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) diff --git a/postfix/src/smtp/smtp_state.c b/postfix/src/smtp/smtp_state.c index bfcea3818..9f364b671 100644 --- a/postfix/src/smtp/smtp_state.c +++ b/postfix/src/smtp/smtp_state.c @@ -38,6 +38,7 @@ #include #include +#include /* Global library. */ @@ -54,6 +55,7 @@ SMTP_STATE *smtp_state_alloc(void) { SMTP_STATE *state = (SMTP_STATE *) mymalloc(sizeof(*state)); + state->misc_flags = 0; state->src = 0; state->service = 0; state->request = 0; @@ -76,6 +78,23 @@ SMTP_STATE *smtp_state_alloc(void) } 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); } diff --git a/postfix/src/smtpstone/qmqp-sink.c b/postfix/src/smtpstone/qmqp-sink.c index 6517698b8..55ee99b25 100644 --- a/postfix/src/smtpstone/qmqp-sink.c +++ b/postfix/src/smtpstone/qmqp-sink.c @@ -246,6 +246,11 @@ int main(int argc, char **argv) const char *protocols = INET_PROTO_NAME_ALL; INET_PROTO_INFO *proto_info; + /* + * Fix 20051207. + */ + signal(SIGPIPE, SIG_IGN); + /* * Initialize diagnostics. */ diff --git a/postfix/src/smtpstone/smtp-sink.c b/postfix/src/smtpstone/smtp-sink.c index 15140378c..b5f218874 100644 --- a/postfix/src/smtpstone/smtp-sink.c +++ b/postfix/src/smtpstone/smtp-sink.c @@ -790,6 +790,11 @@ int main(int argc, char **argv) const char *protocols = INET_PROTO_NAME_ALL; INET_PROTO_INFO *proto_info; + /* + * Fix 20051207. + */ + signal(SIGPIPE, SIG_IGN); + /* * Initialize diagnostics. */ diff --git a/postfix/src/util/Makefile.in b/postfix/src/util/Makefile.in index 153836e0d..8e3cb4e08 100644 --- a/postfix/src/util/Makefile.in +++ b/postfix/src/util/Makefile.in @@ -570,12 +570,10 @@ attr_clnt.o: attr.h 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 @@ -642,10 +640,12 @@ attr_scan_plain.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 diff --git a/postfix/src/util/attr_clnt.c b/postfix/src/util/attr_clnt.c index 130615b9b..87aac7574 100644 --- a/postfix/src/util/attr_clnt.c +++ b/postfix/src/util/attr_clnt.c @@ -36,15 +36,8 @@ /* 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. @@ -83,17 +76,15 @@ #include #include #include -#include /* Utility library. */ #include #include -#include #include -#include #include #include +#include #include #include @@ -101,42 +92,14 @@ 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); } @@ -146,34 +109,12 @@ void attr_clnt_free(ATTR_CLNT *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); } @@ -249,7 +190,7 @@ int attr_clnt_request(ATTR_CLNT *client, int send_flags,...) 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 */ diff --git a/postfix/src/util/auto_clnt.c b/postfix/src/util/auto_clnt.c index 6bd6e2eb8..c608c6c28 100644 --- a/postfix/src/util/auto_clnt.c +++ b/postfix/src/util/auto_clnt.c @@ -6,11 +6,11 @@ /* SYNOPSIS /* #include /* -/* 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; @@ -26,6 +26,11 @@ /* 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 @@ -38,9 +43,22 @@ /* 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. @@ -66,6 +84,7 @@ /* System library. */ #include +#include /* Utility library. */ @@ -74,6 +93,8 @@ #include #include #include +#include +#include #include /* Application-specific. */ @@ -84,10 +105,11 @@ */ 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 *); @@ -132,6 +154,8 @@ static void auto_clnt_ttl_event(int event, char *context) static void auto_clnt_open(AUTO_CLNT *auto_clnt) { + const char *myname = "auto_clnt_open"; + int fd; /* * Sanity check. @@ -148,8 +172,18 @@ static void auto_clnt_open(AUTO_CLNT *auto_clnt) * 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); @@ -168,18 +202,20 @@ static void auto_clnt_open(AUTO_CLNT *auto_clnt) 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); @@ -219,22 +255,41 @@ VSTREAM *auto_clnt_access(AUTO_CLNT *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); } @@ -244,5 +299,6 @@ void auto_clnt_free(AUTO_CLNT *auto_clnt) { if (auto_clnt->vstream) auto_clnt_close(auto_clnt); + myfree(auto_clnt->endpoint); myfree((char *) auto_clnt); } diff --git a/postfix/src/util/auto_clnt.h b/postfix/src/util/auto_clnt.h index a4aaec21d..458c5f937 100644 --- a/postfix/src/util/auto_clnt.h +++ b/postfix/src/util/auto_clnt.h @@ -21,7 +21,7 @@ */ 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 *); diff --git a/postfix/src/util/unix_connect.c b/postfix/src/util/unix_connect.c index 5ae452543..402befb90 100644 --- a/postfix/src/util/unix_connect.c +++ b/postfix/src/util/unix_connect.c @@ -4,7 +4,7 @@ /* SUMMARY /* connect to UNIX-domain listener /* SYNOPSIS -/* #include +/* #include /* /* int unix_connect(addr, block_mode, timeout) /* const char *addr; -- 2.47.3