From 0a906a1db423e1f9602e44451d92d6cf596d5e2e Mon Sep 17 00:00:00 2001 From: Wietse Venema Date: Sun, 29 Oct 2000 00:00:00 -0500 Subject: [PATCH] snapshot-20001029 --- postfix/DB_README | 71 ++++++-- postfix/HISTORY | 42 +++-- postfix/LDAP_README | 117 ++++++++----- postfix/RELEASE_NOTES | 38 ++++- postfix/conf/main.cf | 9 +- postfix/conf/sample-misc.cf | 9 +- postfix/conf/sample-smtp.cf | 5 + postfix/examples/chroot-setup/LINUX2 | 56 +++++- postfix/html/faq.html | 78 +-------- postfix/html/lmtp.8.html | 158 ++++++++++++----- postfix/html/smtp.8.html | 128 +++++++------- postfix/makedefs | 23 +-- postfix/man/man8/lmtp.8 | 26 ++- postfix/man/man8/smtp.8 | 4 + postfix/src/flush/flush.c | 11 +- postfix/src/fsstone/fsstone | Bin 80084 -> 0 bytes postfix/src/global/mail_version.h | 2 +- postfix/src/lmtp/lmtp.c | 26 ++- postfix/src/lmtp/lmtp_connect.c | 115 +++++++++++-- postfix/src/lmtp/lmtp_proto.c | 6 +- postfix/src/smtp/smtp.c | 4 + postfix/src/smtp/smtp_connect.c | 2 +- postfix/src/smtpd/smtpd.c | 23 ++- postfix/src/smtpstone/smtp-sink.c | 17 +- postfix/src/smtpstone/smtp-source.c | 51 ++++-- postfix/src/util/dict_db.c | 6 + postfix/src/util/dict_ldap.c | 247 ++++++++++++++++++++------- postfix/src/util/dict_open.c | 2 +- 28 files changed, 873 insertions(+), 403 deletions(-) delete mode 100755 postfix/src/fsstone/fsstone diff --git a/postfix/DB_README b/postfix/DB_README index 103fdc1cd..6f6b3dc2d 100644 --- a/postfix/DB_README +++ b/postfix/DB_README @@ -1,21 +1,68 @@ Purpose of this document ======================== -This document describes how to build Postfix with Berkeley DB -support on systems that ship without DB library. The canonical -third-party source for Berkeley DB is www.sleepycat.com. +This document describes how to build Postfix with third-party +Berkeley DB from www.sleepycat.com, or how to choose a specific +Berkeley DB version when your system provides multiple implementations. -The information can also be used to build Postfix with a non-default -Berkeley DB version. However, the file formats of Berkeley DB -version 2 and later are not compatible with the older Berkeley DB -version that ships with, for example, 4.4BSD. +Building Postfix with Sleepycat Berkeley DB +=========================================== -Building Postfix with third-party Berkeley DB support -===================================================== +Many commercial UNIXes ship without Berkeley DB support. Examples +are Solaris, HP-UX, IRIX, UNIXWARE. In order to build Postfix with +Berkeley DB support you need to download and install the source +code from www.sleepycat.com. -If you installed the Berkeley DB from Sleepycat, use something like: +To build Postfix after you installed the Berkeley DB from Sleepycat, +use something like: % make tidy - % make makefiles CCARGS="-DHAS_DB -I/usr/local/BerkeleyDB/include" \ - AUXLIBS=/usr/local/BerkeleyDB/lib/libdb.a + % make makefiles CCARGS="-DHAS_DB -I/usr/local/BerkeleyDB.3.1/include" \ + AUXLIBS=/usr/local/BerkeleyDB.3.1/lib/libdb.a % make + +The exact pathnames depend on the DB version that you installed. +For example, Berkeley DB version 2 installs in /usr/local/BerkeleyDB. + +Beware, the file format produced by Berkeley DB version 1 is not +compatible with that of versions 2 and 3 (versions 2 and 3 have +the same format). If you switch between DB versions, then you may +have to rebuild all your Postfix DB files. + +Building Postfix on BSD systems with a specific Berkeley DB version +=================================================================== + +Some BSD systems ship with multiple Berkeley DB implementations. +Normally, Postfix builds with the default DB version that ships +with the system. + +To build Postfix on BSD systems with a specific DB version, use a +variant of the following commands: + + % make tidy + % make makefiles CCARGS=-I/usr/include/db2 AUXLIBS=-ldb2 + % make + +Beware, the file format produced by Berkeley DB version 1 is not +compatible with that of versions 2 and 3 (versions 2 and 3 have +the same format). If you switch between DB versions, then you may +have to rebuild all your Postfix DB files. + +Building Postfix on Linux with a specific Berkeley DB version +============================================================= + +Some Linux systems systems ship with multiple Berkeley DB +implementations. Normally, Postfix builds with the default DB +version that ships with the system. + +On Linux, you need to edit the makedefs script in order to specify +a non-default DB library. + +The reason is that the location of the default db.h include file +changes randomly between vendors and between versions, so that +Postfix has to choose the file for you. + +Beware, the file format produced by Berkeley DB version 1 is not +compatible with that of versions 2 and 3 (versions 2 and 3 have +the same format). If you switch between DB versions, then you may +have to rebuild all your Postfix DB files. diff --git a/postfix/HISTORY b/postfix/HISTORY index f29bd449b..96dceb72f 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -4358,12 +4358,12 @@ Apologies for any names omitted. the [] or host:port syntax, and there was no way to suppress MX record lookups. Files: smtp/smtp_addr.c, smtp/smtp_connect.c. - Convenience: you can now specify multiple destinations in - the relayhost or fallback_relay configuration parameters. + Convenience: you can now specify multiple SMTP destinations + in the relayhost or fallback_relay configuration parameters. The specified destinations will be tried in the specified order. File: smtp/smtp_connect.c. - Typographical corrections by Matthias Andree. + Many typographical corrections by Matthias Andree. 20001024 @@ -4380,13 +4380,13 @@ Apologies for any names omitted. Horror: postmap and postalias (newaliases) silently lose the file lock while building a lookup table with Berkeley - DB 2.x and later on Solaris, HP-UX or IRIX. The result is - that table lookups fail while the table is being built, so - that mail is lost. In order to avoid this misbehavior one - has to use an undocumented feature that is NOT available - with the DB1.85 compatibility interface. Therefore, Postfix - now supports three Berkeley DB programming interfaces of - increasing complexity. File: util/dict_db.c. + DB 2.x and later on Solaris, HP-UX, IRIX, and UNIXWARE. + The result is that table lookups fail while the table is + being built, so that mail is lost. In order to avoid this + misbehavior one has to use an undocumented feature that is + NOT available with the DB1.85 compatibility interface. + Therefore, Postfix now supports three Berkeley DB programming + interfaces of increasing complexity. File: util/dict_db.c. Bugfix: some character manipulations were not portable for signed/unsigned characters. Files: global/quote_821_local.c, @@ -4396,3 +4396,25 @@ Apologies for any names omitted. begins with "From sender time-stamp". Sendmail silently ignores such RFC violating garbage, and therefore Postfix needs to jump another hoop. File: smtpd/smtpd.c. + +20001028 + + Bugfix: the flush server tried to access config files after + going to the chroot jail. Found by Lutz Jaenicke, TU-Cottbus.DE. + File: flush/flush.c. + + Update: revised LDAP module from primary maintainer John + Hensley, with contributions from many other people. Files: + util/dict_ldap.c, LDAP_README. + + Update: LINUX2 chroot setup script by Matthias Andree, + uni-dortmund.de. + + Feature: specify unix:/path/name for LMTP connections over + UNIX-domain sockets, and specify inet:host or inet:host:port + for IPV4. If no unix: or inet: is specified, IPV4 is assumed. + File: lmtp/lmtp_connect.c. + + Feature: added UNIX-domain support to the smtpstone test + programs in order to test the LMTP client UNIX-domain + support. diff --git a/postfix/LDAP_README b/postfix/LDAP_README index 50b020ed1..9dca5663c 100644 --- a/postfix/LDAP_README +++ b/postfix/LDAP_README @@ -82,10 +82,22 @@ parameter below, "server_host", would be defined in main.cf as substitute for the address Postfix is trying to resolve, e.g. ldapsource_query_filter = (&(mail=%s)(paid_up=true)) + domain (No default; you must configure this.) + This is a list of domain names, paths to files, or dictionaries. + If specified, only lookups ending in a domain on this list will + be searched. This can significantly reduce the query load on the + LDAP server. + ldapsource_domain = postfix.org, hash:/etc/postfix/searchdomains + result_attribute (maildrop) - The attribute Postfix will read from any directory entries + The attribute(s) Postfix will read from any directory entries returned by the lookup, to be resolved to an email address. - ldapsource_result_attribute = mailbox + ldapsource_result_attribute = mailbox,maildrop + + special_result_attribute (No default) + The attribute(s) of directory entries that can contain DNs or URLs. + If found, a recursive subsequent search is done using their values. + ldapsource_special_result_attribute = member scope (sub) The LDAP search scope: sub, base, or one. These translate into @@ -147,8 +159,11 @@ configuration routines understand how to deal with quoted strings. EXAMPLES ======== -Here's a basic example for using LDAP to look up aliases. In main.cf, -you have these configuration parameters defined: +ALIASES +------- + +Here's a basic example for using LDAP to look up aliases. Assume that in +main.cf, you have these configuration parameters defined: alias_maps = hash:/etc/aliases, ldap:ldapsource ldapsource_server_host = ldap.my.com @@ -162,39 +177,52 @@ read the "maildrop" attributes of those found, and build a list of their maildrops, which will be treated as RFC822 addresses to which the message will be delivered. +VIRTUAL DOMAINS/ADDRESSES +------------------------- + If you want to keep information for virtual lookups in your directory, -it's only a little more complicated. You'll want to make sure all of -your virtual mailacceptinggeneralid attributes are fully qualified with -their virtual domains. If you want to designate a directory entry as the +it's only a little more complicated. First you need to make sure Postfix +knows about the virtual domain. An easy way to do that is to add the +domain to the mailacceptinggeneralid attribute of some entry in the +directory. Next you'll want to make sure all of your virtual recipients' +mailacceptinggeneralid attributes are fully qualified with their virtual +domains. Finally, if you want to designate a directory entry as the default user for a virtual domain, just give it an additional mailacceptinggeneralid (or the equivalent in your directory) of -"@virtual.dom". That's right, no user part. +"@virtual.dom". That's right, no user part. If you don't want a catchall +user, omit this step and mail to unknown users in the domain will simply +bounce. -If you want to get information for relay_domains out of your directory, -the simplest way to get it is to add the domain name (without even the -'@') as a mailacceptinggeneralid to some recipient in each domain, then -add "$virtual_maps" to your relay_domains line. Then you can use the -same map you use to find virtual recipients to determine if a domain is -a valid virtual domain and should be allowed to relay. +If you're using a version of Postfix newer than 19991226, that should do +it. If not, you also need to add your virtual domains to relay_domains. +Simply add "$virtual_maps" to your relay_domains line. Then you can use +the same map you use to find virtual recipients to determine if a domain +is a valid virtual domain and should be allowed to relay. -For example, the catchall user for a virtual domain might look like -this: +In summary, you might have a catchall user for a virtual domain that +looks like this: - dn: cn=defaultrecipient, dc=fake, dc=dom - objectclass: top - objectclass: rfc822mailgroup - cn: defaultrecipient - owner: uid=root, dc=someserver, dc=isp, dc=dom - mailacceptinggeneralid: fake.dom - mailacceptinggeneralid: @fake.dom - maildrop: realuser@real.dom + dn: cn=defaultrecipient, dc=fake, dc=dom + objectclass: top + objectclass: virtualaccount + cn: defaultrecipient + owner: uid=root, dc=someserver, dc=isp, dc=dom + 1 -> mailacceptinggeneralid: fake.dom + 2 -> mailacceptinggeneralid: @fake.dom + 3 -> maildrop: realuser@real.dom -If you don't necessarily have a catchall user for the domain (i.e. you -want mail to unknown users in the domain to bounce), and don't want to -tag an arbitrary user in the virtual domain, you might define another -LDAP map that finds your virtual domain's domain object entry, and add -that map to relay_domains instead of "$virtual_maps". All that's -necessary is that a search for the domain name return something. +1: Postfix knows fake.dom is a valid virtual domain when it looks for + this and gets something (the maildrop) back. + +2: This causes any mail for unknown users in fake.dom to go to this entry ... + +3: ... and then to its maildrop. + +Normal users might simply have one mailacceptinggeneralid and maildrop, +e.g. "normaluser@fake.dom" and "normaluser@real.dom". + +OTHER USES +---------- Other common uses for LDAP lookups include rewriting senders and recipients with Postfix' canonical lookups, for example in order to make @@ -204,6 +232,11 @@ instead of "userid@site.dom". NOTES AND THINGS TO THINK ABOUT =============================== +- The bits of schema and attribute names used in this document are just + examples. There's nothing special about them, other than that some are + the defaults in the LDAP configuration parameters. You can use + whatever schema you like, and configure Postfix accordingly. + - You probably want to make sure that mailacceptinggeneralids are unique, and that not just anyone can specify theirs as postmaster or root, say. @@ -266,17 +299,17 @@ contents, please include the applicable bits of some directory entries. CREDITS ======= -Support for LDAP was initially written by Prabhat K Singh of VSNL, -Bombay, India, and then hideously bloated by John Hensley to support -multiple sources and more configurable attributes. The caching bits were -initially worked out by Prabhat, then munged to support the multiple -sources. - -Other contributors, of code or direction or dope slaps, include: - -Manuel Guesdon -Carsten Hoeger -Keith Stevenson -Samuel Tardieu +Manuel Guesdon: Spotted a bug with the ldapsource_timeout attribute. +John Hensley: Multiple LDAP sources with more configurable attributes. +Carsten Hoeger: Search scope handling. +LaMont Jones: Domain restriction, URL and DN searches, multiple result + attributes. +Mike Mattice: Alias dereferencing control. +Hery Rakotoarisoa: Patches for LDAPv3 updating. +Prabhat K Singh: Wrote the initial Postfix LDAP lookups and connection caching. +Keith Stevenson: RFC 2254 escaping in queries. +Samuel Tardieu: Noticed that searches could include wildcards, prompting + the work on RFC 2254 escaping in queries. Spotted a bug + in binding. And of course Wietse. diff --git a/postfix/RELEASE_NOTES b/postfix/RELEASE_NOTES index 2f4e9b7f8..7842ce4d2 100644 --- a/postfix/RELEASE_NOTES +++ b/postfix/RELEASE_NOTES @@ -1,17 +1,45 @@ -Incompatible changes with snapshot-20001027 +Incompatible changes with snapshot-20001029 =========================================== +If this release does not work for you, you can go back to a previous +Postfix version without losing your mail, subject to the "incompatible +changes" listed for previous Postfix releases below. + Berkeley DB support has changed for Solaris, HP-UX, UNIXWARE, IRIX. -You can no longer use the DB 1.85 compatibility interface, because -that interface loses the file lock while building a table, so that -table lookups fail and mail is lost. See the DB_README file for -instructions on how to build with third-party Berkeley DB support. +On these systems, Postfix must no longer use DB 1.85 compatibility +mode, because that mode loses the file lock while building a table, +so that table lookups fail and mail is lost. See the DB_README file +for instructions on how to build Postfix with third-party Berkeley +DB support. The "fast ETRN" policy configuration has changed. You now specify the list of eligible "fast ETRN" domains with the fast_flush_domains parameter (default: $relay_domains). In order to disable the feature, specify an empty value (fast_flush_domains =). +Major changes with snapshot-20001029 +==================================== + +This release ships with an updated LDAP client module that has better +group support by Lamont Jones, and that has several other enhancements. +Review the LDAP_README file for more information. + +The LMTP client can now make connections over UNIX-domain sockets +in addition to IPV4. For connections over UNIX-domain sockets, +specify a transport table entry like: + + domain.name lmtp:unix:/path/name + +IPV4-based servers are still the default. The LMTP_README file +still needs to be revised to account for this change. This is +best done by someone who actually uses the Postfix LMTP client. + +You can now specify multiple SMTP destinations in the relayhost +and fallback_relay configuration parameters. The destinations are +tried in the specified order. Specify host or host:port (perform +MX record lookups), [host] or [host]:port (no MX record lookups), +[address] or [address]:port (numerical IP address). + Incompatible changes with snapshot-20001005 =========================================== diff --git a/postfix/conf/main.cf b/postfix/conf/main.cf index e96e68d54..24274dd5c 100644 --- a/postfix/conf/main.cf +++ b/postfix/conf/main.cf @@ -122,9 +122,12 @@ mail_owner = postfix # internal DNS uses no MX records, specify the name of the intranet # gateway host instead. # -# Specify a domain, host, host:port, [host]:port, [address] or -# [address]:port. Use the form [name] to turn off MX lookups. See -# also the default_transport parameter if you're connected via UUCP. +# In the case of SMTP, 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. +# +# If you're connected via UUCP, see also the default_transport parameter. # # relayhost = $mydomain # relayhost = gateway.my.domain diff --git a/postfix/conf/sample-misc.cf b/postfix/conf/sample-misc.cf index e5b134b36..9efed230e 100644 --- a/postfix/conf/sample-misc.cf +++ b/postfix/conf/sample-misc.cf @@ -245,9 +245,12 @@ recipient_delimiter = # internal DNS uses no MX records, specify the name of the intranet # gateway host instead. # -# Specify a domain, host, host:port, [host]:port, [address] or -# [address]:port. Use the form [name] to turn off MX lookups. See -# also the default_transport parameter if you're connected via UUCP. +# In the case of SMTP, 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. +# +# If you're connected via UUCP, see also the default_transport parameter. # # relayhost = $mydomain # relayhost = gateway.my.domain diff --git a/postfix/conf/sample-smtp.cf b/postfix/conf/sample-smtp.cf index c0fea6563..2359377f8 100644 --- a/postfix/conf/sample-smtp.cf +++ b/postfix/conf/sample-smtp.cf @@ -24,6 +24,11 @@ # By default, mail is bounced when a destination is not found, and # delivery is deferred if a destination is unreachable. # +# In the case of SMTP, 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. +# fallback_relay = # The ignore_mx_lookup_error parameter controls what happens when a diff --git a/postfix/examples/chroot-setup/LINUX2 b/postfix/examples/chroot-setup/LINUX2 index 1d35e1c8e..78aaab251 100644 --- a/postfix/examples/chroot-setup/LINUX2 +++ b/postfix/examples/chroot-setup/LINUX2 @@ -1,16 +1,56 @@ -# Setup chroot jail for Linux +#! /bin/sh + +# LINUX2 - shell script to set up a Postfix chroot jail for Linux +# Tested on SuSE Linux 5.3 (libc5) and 6.4 (glibc2.1) + +# Copyright (c) 2000 by Matthias Andree +# Redistributable unter the MIT-style license that follows: +# Abstract: "do whatever you want except hold somebody liable or change +# the copyright information". + +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + +cond_copy() { + # find files as per pattern in $1 + # if any, copy to directory $2 + dir=`dirname "$1"` + pat=`basename "$1"` + lr=`find "$dir" -name "$pat"` + if test ! -d "$2" ; then exit 1 ; fi + if test "x$lr" != "x" ; then cp -p $1 "$2" ; fi +} set -e umask 022 POSTFIX_DIR=${POSTFIX_DIR-/var/spool/postfix} - cd ${POSTFIX_DIR} -mkdir etc -cp /etc/localtime /etc/services /etc/resolv.conf /etc/nsswitch.conf etc -mkdir -p usr/lib/zoneinfo -ln -s /etc/localtime usr/lib/zoneinfo +mkdir -p etc lib usr/lib/zoneinfo -mkdir lib -cp /lib/libnss_* lib +# find localtime (SuSE 5.3 does not have /etc/localtime) +lt=/etc/localtime +if test ! -f $lt ; then lt=/usr/lib/zoneinfo/localtime ; fi +if test ! -f $lt ; then echo "cannot find localtime" ; exit 1 ; fi +cp -p -f $lt /etc/services /etc/resolv.conf /etc/nsswitch.conf etc +cp -p -f /etc/host.conf /etc/hosts /etc/passwd etc +ln -s -f /etc/localtime usr/lib/zoneinfo + +cond_copy '/lib/libnss_*' lib +cond_copy '/lib/libresolv*' lib \ No newline at end of file diff --git a/postfix/html/faq.html b/postfix/html/faq.html index afaeaefe0..0d54625ab 100644 --- a/postfix/html/faq.html +++ b/postfix/html/faq.html @@ -2592,79 +2592,11 @@ systems.

In order to build Postfix with db support on UNIX systems -that do not have db support out of the box, you need the -db-1.85 release, or the current -version which has a db-1.85 compatible interface. - -

- -To build with a third-party DB library, use the following commands -in the Postfix top-level directory. -On Solaris, the LD_LIBRARY_PATH unset commands may be required to -avoid linking in the wrong libraries. - -

- -

-    % LD_LIBRARY_PATH=         (Bourne-shell syntax)
-    % unsetenv LD_LIBRARY_PATH (C-shell syntax)
-    % make tidy
-    % make makefiles CCARGS="-DHAS_DB -DPATH_DB_H='<db_185.h>' -I/some/where/include" AUXLIBS=/some/where/libdb.a
-    % make
-
- -

- -Of course you will have to specify the actual location of the -include directory and of the object library. - -

- -When building with a third-party DB library you may into one of the -following problems: - -

- -

+that do not have db support out of the box, you can use the +Berkeley DB source code from www.sleepycat.com. See the file +DB_README in the Postfix source code distribution for +instructions on how to build Postfix with Sleepycat's Berkeley DB.
diff --git a/postfix/html/lmtp.8.html b/postfix/html/lmtp.8.html index f25917afa..661e570fc 100644 --- a/postfix/html/lmtp.8.html +++ b/postfix/html/lmtp.8.html @@ -24,14 +24,31 @@ LMTP(8) LMTP(8) problem reports are sent to the bounce(8) or defer(8) dae- mon as appropriate. - If no server is given on the command line, the LMTP client - connects to the destination specified in the message - delivery request and to the TCP port defined as lmtp in - services(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 - SMTP. + 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 UNIX-domain server that is bound to + the specified pathname. If the process runs + chrooted, an absolute pathname is interpreted rela- + tive 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 host. If no port is specified, connect to the + port defined as lmtp in services(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 @@ -42,6 +59,18 @@ LMTP(8) LMTP(8) RFC 821 (SMTP protocol) RFC 1651 (SMTP service extensions) RFC 1870 (Message Size Declaration) + + + + 1 + + + + + +LMTP(8) LMTP(8) + + RFC 2033 (LMTP protocol) RFC 2197 (Pipelining) @@ -59,18 +88,6 @@ LMTP(8) LMTP(8) The following main.cf parameters are especially relevant to this program. See the Postfix main.cf file for syntax details and for default values. Use the postfix reload - - - - 1 - - - - - -LMTP(8) LMTP(8) - - command after a configuration change. Miscellaneous @@ -108,6 +125,18 @@ LMTP(8) LMTP(8) The effectiveness of cached connections will be determined by the number of LMTP servers in use, and the concurrency limit specified for the LMTP + + + + 2 + + + + + +LMTP(8) LMTP(8) + + client. Cached connections are closed under any of the following conditions: @@ -125,18 +154,6 @@ LMTP(8) LMTP(8) o Upon the onset of another delivery request, the LMTP server associated with the current - - - - 2 - - - - - -LMTP(8) LMTP(8) - - session does not respond to the RSET com- mand. @@ -175,6 +192,17 @@ LMTP(8) LMTP(8) LMTP server. If no connection can be made within the deadline, the message is deferred. + + + 3 + + + + + +LMTP(8) LMTP(8) + + lmtp_lhlo_timeout Timeout in seconds for sending the LHLO command, and for receiving the server response. @@ -191,18 +219,6 @@ LMTP(8) LMTP(8) Timeout in seconds for sending the DATA command, and for receiving the server response. - - - - 3 - - - - - -LMTP(8) LMTP(8) - - lmtp_data_xfer_timeout Timeout in seconds for sending the message content. @@ -226,7 +242,7 @@ LMTP(8) LMTP(8) master(8) process manager qmgr(8) queue manager services(4) Internet services and aliases - spawn(8) auxiliary command spawner + spawn(8) auxiliary command spawner syslogd(8) system logging LICENSE @@ -241,6 +257,18 @@ LMTP(8) LMTP(8) Alterations for LMTP by: Philip A. Prindeville + + + + 4 + + + + + +LMTP(8) LMTP(8) + + Mirapoint, Inc. USA. @@ -260,7 +288,45 @@ LMTP(8) LMTP(8) - 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 diff --git a/postfix/html/smtp.8.html b/postfix/html/smtp.8.html index 05e2d06e6..dc1ea633d 100644 --- a/postfix/html/smtp.8.html +++ b/postfix/html/smtp.8.html @@ -29,6 +29,11 @@ SMTP(8) SMTP(8) preference, and connects to each listed address until it finds a server that responds. + When the domain or host is specified as a comma/whitespace + separated list, the SMTP client repeats the above process + for all destinations until it finds a server that + responds. + Once the SMTP client has received the server greeting ban- ner, no error will cause it to proceed to the next address on the mail exchanger list. Instead, the message is either @@ -36,7 +41,7 @@ SMTP(8) SMTP(8) SECURITY The SMTP client is moderately security-sensitive. It talks - to SMTP servers and to DNS servers on the network. The + to SMTP servers and to DNS servers on the network. The SMTP client can be run chrooted at fixed low privilege. STANDARDS @@ -47,19 +52,14 @@ SMTP(8) SMTP(8) RFC 2554 (AUTH command) 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 -CONFIGURATION PARAMETERS - The following main.cf parameters are especially relevant - to this program. See the Postfix main.cf file for syntax - 1 @@ -71,36 +71,40 @@ SMTP(8) SMTP(8) SMTP(8) SMTP(8) - details and for default values. Use the postfix reload +BUGS +CONFIGURATION PARAMETERS + The following main.cf parameters are especially relevant + to this program. See the Postfix main.cf file for syntax + details and for default values. Use the postfix reload command after a configuration change. Miscellaneous best_mx_transport - Name of the delivery transport to use when the - local machine is the most-preferred mail exchanger - (by default, a mailer loop is reported, and the + Name of the delivery transport to use when the + local machine is the most-preferred mail exchanger + (by default, a mailer loop is reported, and the message is bounced). debug_peer_level - Verbose logging level increment for hosts that + Verbose logging level increment for hosts that match a pattern in the debug_peer_list parameter. debug_peer_list - List of domain or network patterns. When a remote - host matches a pattern, increase the verbose log- - ging level by the amount specified in the + List of domain or network patterns. When a remote + host matches a pattern, increase the verbose log- + ging level by the amount specified in the debug_peer_level parameter. disable_dns_lookups - Disable DNS lookups. This means that mail must be + Disable DNS lookups. This means that mail must be forwarded via a smart relay host. error_notice_recipient - Recipient of protocol/policy/resource/software + Recipient of protocol/policy/resource/software error notices. fallback_relay - Hosts to hand off mail to if a message destination + Hosts to hand off mail to if a message destination is not found or if a destination is unreachable. ignore_mx_lookup_error @@ -110,21 +114,17 @@ SMTP(8) SMTP(8) inet_interfaces The network interface addresses that this mail sys- - tem receives mail on. When any of those addresses + tem receives mail on. When any of those addresses appears in the list of mail exchangers for a remote - destination, the list is truncated to avoid mail + destination, the list is truncated to avoid mail delivery loops. notify_classes - When this parameter includes the protocol class, - send mail to the postmaster with transcripts of + When this parameter includes the protocol class, + send mail to the postmaster with transcripts of SMTP sessions with protocol errors. - smtp_always_send_ehlo - Always send EHLO at the start of a connection. - smtp_skip_4xx_greeting - Skip servers that greet us with a 4xx status code. @@ -137,26 +137,32 @@ SMTP(8) SMTP(8) SMTP(8) SMTP(8) + smtp_always_send_ehlo + Always send EHLO at the start of a connection. + + smtp_skip_4xx_greeting + Skip servers that greet us with a 4xx status code. + smtp_skip_5xx_greeting - Skip servers that greet us with a 5xx status code. + Skip servers that greet us with a 5xx status code. smtp_skip_quit_response - Do not wait for the server response after sending + Do not wait for the server response after sending QUIT. smtp_bind_address - Numerical network address to bind to when making a + Numerical network address to bind to when making a connection. Authentication controls smtp_enable_sasl_auth - Enable per-session authentication as per RFC 2554 - (SASL). By default, Postfix is built without SASL + Enable per-session authentication as per RFC 2554 + (SASL). By default, Postfix is built without SASL support. smtp_sasl_password_maps Lookup tables with per-host or domain name:password - entries. No entry for a host means no attempt to + entries. No entry for a host means no attempt to authenticate. smtp_sasl_security_options @@ -180,17 +186,11 @@ SMTP(8) SMTP(8) Resource controls smtp_destination_concurrency_limit Limit the number of parallel deliveries to the same - destination. The default limit is taken from the + destination. The default limit is taken from the default_destination_concurrency_limit parameter. smtp_destination_recipient_limit - Limit the number of recipients per message deliv- - ery. The default limit is taken from the - default_destination_recipient_limit parameter. - -Timeout controls - smtp_connect_timeout - Timeout in seconds for completing a TCP connection. + Limit the number of recipients per message @@ -203,24 +203,30 @@ SMTP(8) SMTP(8) SMTP(8) SMTP(8) + delivery. The default limit is taken from the + default_destination_recipient_limit parameter. + +Timeout controls + smtp_connect_timeout + Timeout in seconds for completing a TCP connection. When no connection can be made within the deadline, - the SMTP client tries the next address on the mail + the SMTP client tries the next address on the mail exchanger list. smtp_helo_timeout - Timeout in seconds for receiving the SMTP greeting + Timeout in seconds for receiving the SMTP greeting banner. When the server drops the connection with- - out sending a greeting banner, or when it sends no + out sending a greeting banner, or when it sends no greeting banner within the deadline, the SMTP client tries the next address on the mail exchanger list. smtp_helo_timeout - Timeout in seconds for sending the HELO command, + Timeout in seconds for sending the HELO command, and for receiving the server response. smtp_mail_timeout - Timeout in seconds for sending the MAIL FROM com- + Timeout in seconds for sending the MAIL FROM com- mand, and for receiving the server response. smtp_rcpt_timeout @@ -228,7 +234,7 @@ SMTP(8) SMTP(8) and for receiving the server response. smtp_data_init_timeout - Timeout in seconds for sending the DATA command, + Timeout in seconds for sending the DATA command, and for receiving the server response. smtp_data_xfer_timeout @@ -237,11 +243,11 @@ SMTP(8) SMTP(8) smtp_data_done_timeout Timeout in seconds for sending the "." command, and for receiving the server response. When no response - is received, a warning is logged that the mail may + is received, a warning is logged that the mail may be delivered multiple times. smtp_quit_timeout - Timeout in seconds for sending the QUIT command, + Timeout in seconds for sending the QUIT command, and for receiving the server response. SEE ALSO @@ -250,13 +256,7 @@ SMTP(8) SMTP(8) qmgr(8) queue manager syslogd(8) system logging -LICENSE - The Secure Mailer license must be distributed with this - software. -AUTHOR(S) - Wietse Venema - IBM T.J. Watson Research @@ -269,6 +269,13 @@ SMTP(8) SMTP(8) SMTP(8) SMTP(8) +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 @@ -311,13 +318,6 @@ SMTP(8) SMTP(8) - - - - - - - diff --git a/postfix/makedefs b/postfix/makedefs index baacc13c4..e8e5625c6 100644 --- a/postfix/makedefs +++ b/postfix/makedefs @@ -159,18 +159,12 @@ case "$SYSTEM.$RELEASE" in *) echo "Unknown AIX version: `uname -v`." 1>&2; exit 1;; esac;; Linux.2*) SYSTYPE=LINUX2 - if [ -f /usr/lib/libdb-3.1.a ] + # Postfix no longer needs DB 1.85 compatibility + if [ ! -f /usr/include/db.h -a -f /usr/include/db/db.h ] then - CCARGS="$CCARGS -I/usr/include/db3" - SYSLIBS="$SYSLIBS -ldb-3.1" - else - if [ -f /usr/include/db/db.h ] - then - CCARGS="$CCARGS -I/usr/include/db" - fi - test -f /usr/lib/libdb.a && SYSLIBS="$SYSLIBS -ldb" + CCARGS="$CCARGS -I/usr/include/db" fi - for name in nsl resolv + for name in db nsl resolv do test -f /usr/lib/lib$name.a && SYSLIBS="$SYSLIBS -l$name" done @@ -192,9 +186,6 @@ HP-UX.A.09.*) SYSTYPE=HPUX9 CCARGS="$CCARGS -DHAS_DB" SYSLIBS="$SYSLIBS -ldb" fi - if [ -f /usr/include/db_185.h ]; then - CCARGS="$CCARGS -DPATH_DB_H=''" - fi ;; HP-UX.B.10.*) SYSTYPE=HPUX10 CCARGS="$CCARGS `nm /usr/lib/libc.a 2>/dev/null | @@ -203,9 +194,6 @@ HP-UX.B.10.*) SYSTYPE=HPUX10 CCARGS="$CCARGS -DHAS_DB" SYSLIBS=-ldb fi - if [ -f /usr/include/db_185.h ]; then - CCARGS="$CCARGS -DPATH_DB_H=''" - fi ;; HP-UX.B.11.*) SYSTYPE=HPUX11 SYSLIBS=-lnsl @@ -213,9 +201,6 @@ HP-UX.B.11.*) SYSTYPE=HPUX11 CCARGS="$CCARGS -DHAS_DB" SYSLIBS="$SYSLIBS -ldb" fi - if [ -f /usr/include/db_185.h ]; then - CCARGS="$CCARGS -DPATH_DB_H=''" - fi ;; ReliantUNIX-?.5.43) SYSTYPE=ReliantUnix543 RANLIB=echo diff --git a/postfix/man/man8/lmtp.8 b/postfix/man/man8/lmtp.8 index 4d981bb9f..8af70aa52 100644 --- a/postfix/man/man8/lmtp.8 +++ b/postfix/man/man8/lmtp.8 @@ -23,12 +23,26 @@ as finished, or it informs the queue manager that delivery should be tried again at a later time. Delivery problem reports are sent to the \fBbounce\fR(8) or \fBdefer\fR(8) daemon as appropriate. -If no server is given on the command line, the LMTP client connects -to the destination specified in the message delivery request and to -the TCP 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 SMTP. +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 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 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 diff --git a/postfix/man/man8/smtp.8 b/postfix/man/man8/smtp.8 index bcf367a20..35553290a 100644 --- a/postfix/man/man8/smtp.8 +++ b/postfix/man/man8/smtp.8 @@ -27,6 +27,10 @@ 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 finds a server that responds. +When the domain or host is specified as a comma/whitespace +separated list, the SMTP client repeats the above process +for all destinations until it finds a server that responds. + Once the SMTP client has received the server greeting banner, no error will cause it to proceed to the next address on the mail exchanger list. Instead, the message is either bounced, or its diff --git a/postfix/src/flush/flush.c b/postfix/src/flush/flush.c index bbc2ff0e6..724341f46 100644 --- a/postfix/src/flush/flush.c +++ b/postfix/src/flush/flush.c @@ -189,9 +189,6 @@ static DOMAIN_LIST *flush_domains; static int flush_policy_ok(const char *site) { - if (flush_domains == 0) - flush_domains = domain_list_init(var_fflush_domains); - return (domain_list_match(flush_domains, site)); } @@ -497,6 +494,13 @@ static void flush_service(VSTREAM *client_stream, char *unused_service, vstring_free(queue_id); } +/* pre_jail_init - pre-jail initialization */ + +static void pre_jail_init(char *unused_name, char **unused_argv) +{ + flush_domains = domain_list_init(var_fflush_domains); +} + /* main - pass control to the single-threaded skeleton */ int main(int argc, char **argv) @@ -509,5 +513,6 @@ int main(int argc, char **argv) single_server_main(argc, argv, flush_service, MAIL_SERVER_TIME_TABLE, time_table, + MAIL_SERVER_PRE_INIT, pre_jail_init, 0); } diff --git a/postfix/src/fsstone/fsstone b/postfix/src/fsstone/fsstone deleted file mode 100755 index cd33f1c81508d5435353543b33d3b0deb3ea78be..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 80084 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 #include +#include #include #include #include @@ -97,6 +107,58 @@ #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 *, VSTRING *); + +/* lmtp_connect_unix - connect to UNIX-domain address */ + +static LMTP_SESSION *lmtp_connect_unix(const char *addr, VSTRING *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_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, addr, why)); +} + /* lmtp_connect_addr - connect to explicit address */ static LMTP_SESSION *lmtp_connect_addr(DNS_RR *addr, unsigned port, @@ -105,10 +167,6 @@ static LMTP_SESSION *lmtp_connect_addr(DNS_RR *addr, unsigned port, char *myname = "lmtp_connect_addr"; struct sockaddr_in sin; int sock; - int conn_stat; - int saved_errno; - VSTREAM *stream; - int ch; /* * Sanity checks. @@ -137,19 +195,35 @@ static LMTP_SESSION *lmtp_connect_addr(DNS_RR *addr, unsigned port, if (msg_verbose) msg_info("%s: trying: %s[%s] port %d...", myname, addr->name, inet_ntoa(sin.sin_addr), ntohs(port)); + + return (lmtp_connect_sock(sock, (struct sockaddr *) & sin, sizeof(sin), + addr->name, inet_ntoa(sin.sin_addr), + 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, VSTRING *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, (struct sockaddr *) & sin, - sizeof(sin), var_lmtp_conn_tmout); + conn_stat = timed_connect(sock, sa, len, var_lmtp_conn_tmout); saved_errno = errno; non_blocking(sock, BLOCKING); errno = saved_errno; } else { - conn_stat = connect(sock, (struct sockaddr *) & sin, sizeof(sin)); + conn_stat = connect(sock, sa, len); } if (conn_stat < 0) { vstring_sprintf(why, "connect to %s[%s]: %m", - addr->name, inet_ntoa(sin.sin_addr)); + name, addr); lmtp_errno = LMTP_RETRY; close(sock); return (0); @@ -160,7 +234,7 @@ static LMTP_SESSION *lmtp_connect_addr(DNS_RR *addr, unsigned port, */ if (read_wait(sock, var_lmtp_lhlo_tmout) < 0) { vstring_sprintf(why, "connect to %s[%s]: read timeout", - addr->name, inet_ntoa(sin.sin_addr)); + name, addr); lmtp_errno = LMTP_RETRY; close(sock); return (0); @@ -172,7 +246,7 @@ static LMTP_SESSION *lmtp_connect_addr(DNS_RR *addr, unsigned port, stream = vstream_fdopen(sock, O_RDWR); if ((ch = VSTREAM_GETC(stream)) == VSTREAM_EOF) { vstring_sprintf(why, "connect to %s[%s]: server dropped connection", - addr->name, inet_ntoa(sin.sin_addr)); + name, addr); lmtp_errno = LMTP_RETRY; vstream_fclose(stream); return (0); @@ -184,13 +258,12 @@ static LMTP_SESSION *lmtp_connect_addr(DNS_RR *addr, unsigned port, */ if (ch == '4' || ch == '5') { vstring_sprintf(why, "connect to %s[%s]: server refused mail service", - addr->name, inet_ntoa(sin.sin_addr)); + name, addr); lmtp_errno = LMTP_RETRY; vstream_fclose(stream); return (0); } - return (lmtp_session_alloc(stream, addr->name, inet_ntoa(sin.sin_addr), - destination)); + return (lmtp_session_alloc(stream, name, addr, destination)); } /* lmtp_connect_host - direct connection to host */ @@ -220,7 +293,7 @@ static LMTP_SESSION *lmtp_connect_host(char *host, unsigned port, /* lmtp_parse_destination - parse destination */ static char *lmtp_parse_destination(const char *destination, char *def_service, - char **hostp, unsigned *portp) + char **hostp, unsigned *portp) { char *myname = "lmtp_parse_destination"; char *buf = mystrdup(destination); @@ -272,7 +345,7 @@ static char *lmtp_parse_destination(const char *destination, char *def_service, LMTP_SESSION *lmtp_connect(const char *destination, VSTRING *why) { - char *myname = "lmtp_connect_inet"; + char *myname = "lmtp_connect"; LMTP_SESSION *session; char *dest_buf; char *host; @@ -281,7 +354,15 @@ LMTP_SESSION *lmtp_connect(const char *destination, VSTRING *why) /* * 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. */ + if (strncmp(destination, "unix:", 5) == 0) + return (lmtp_connect_unix(destination + 5, why)); + if (strncmp(destination, "inet:", 5) == 0) + destination += 5; dest_buf = lmtp_parse_destination(destination, def_service, &host, &port); if (msg_verbose) diff --git a/postfix/src/lmtp/lmtp_proto.c b/postfix/src/lmtp/lmtp_proto.c index ae16b0385..93ed07dd0 100644 --- a/postfix/src/lmtp/lmtp_proto.c +++ b/postfix/src/lmtp/lmtp_proto.c @@ -246,11 +246,9 @@ int lmtp_lhlo(LMTP_STATE *state) * because they benefit little from pipelining. */ if (state->features & LMTP_FEATURE_PIPELINING) { - if (getsockopt(vstream_fileno(state->session->stream), SOL_SOCKET, - SO_SNDBUF, (char *) &state->sndbufsize, &optlen) < 0) - msg_fatal("%s: getsockopt: %m", myname); + state->sndbufsize = 4 * 1024; if (msg_verbose) - msg_info("Using LMTP PIPELINING, TCP send buffer size is %d", + msg_info("Using LMTP PIPELINING, send buffer size is %d", state->sndbufsize); } else state->sndbufsize = 0; diff --git a/postfix/src/smtp/smtp.c b/postfix/src/smtp/smtp.c index d9d54357e..59017b1dc 100644 --- a/postfix/src/smtp/smtp.c +++ b/postfix/src/smtp/smtp.c @@ -21,6 +21,10 @@ /* the destination host, sorts the list by preference, and connects /* to each listed address until it finds a server that responds. /* +/* When the domain or host is specified as a comma/whitespace +/* separated list, the SMTP client repeats the above process +/* for all destinations until it finds a server that responds. +/* /* Once the SMTP client has received the server greeting banner, no /* error will cause it to proceed to the next address on the mail /* exchanger list. Instead, the message is either bounced, or its diff --git a/postfix/src/smtp/smtp_connect.c b/postfix/src/smtp/smtp_connect.c index f037c594d..d8017f230 100644 --- a/postfix/src/smtp/smtp_connect.c +++ b/postfix/src/smtp/smtp_connect.c @@ -401,7 +401,7 @@ SMTP_SESSION *smtp_connect(char *destination, VSTRING *why) */ cp = save = concatenate(destination, " ", var_fallback_relay, (char *) 0); - while ((dest = mystrtok(&cp, " \t\r\n")) != 0) { + while ((dest = mystrtok(&cp, ", \t\r\n")) != 0) { /* * Parse the destination. Default is to use the SMTP port. diff --git a/postfix/src/smtpd/smtpd.c b/postfix/src/smtpd/smtpd.c index aacdd5229..29e49cf86 100644 --- a/postfix/src/smtpd/smtpd.c +++ b/postfix/src/smtpd/smtpd.c @@ -353,6 +353,13 @@ char *smtpd_path; #define STR(x) vstring_str(x) #define LEN(x) VSTRING_LEN(x) + /* + * Forward declarations. + */ +static void helo_reset(SMTPD_STATE *); +static void mail_reset(SMTPD_STATE *); +static void rcpt_reset(SMTPD_STATE *); + /* collapse_args - put arguments together again */ static void collapse_args(int argc, SMTPD_TOKEN *argv) @@ -377,10 +384,8 @@ static int helo_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) smtpd_chat_reply(state, "501 Syntax: HELO hostname"); return (-1); } - if (state->helo_name != 0) { - myfree(state->helo_name); - state->helo_name = 0; - } + if (state->helo_name != 0) + helo_reset(state); if (argc > 2) collapse_args(argc - 1, argv + 1); if (SMTPD_STAND_ALONE(state) == 0 @@ -406,10 +411,12 @@ static int ehlo_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) smtpd_chat_reply(state, "501 Syntax: EHLO hostname"); return (-1); } - if (state->helo_name != 0) { - myfree(state->helo_name); - state->helo_name = 0; - } + if (state->helo_name != 0) + helo_reset(state); +#if 0 + mail_reset(state); + rcpt_reset(state); +#endif if (argc > 2) collapse_args(argc - 1, argv + 1); if (SMTPD_STAND_ALONE(state) == 0 diff --git a/postfix/src/smtpstone/smtp-sink.c b/postfix/src/smtpstone/smtp-sink.c index 701fdf05f..cac69ba83 100644 --- a/postfix/src/smtpstone/smtp-sink.c +++ b/postfix/src/smtpstone/smtp-sink.c @@ -4,12 +4,19 @@ /* SUMMARY /* multi-threaded SMTP/LMTP test server /* SYNOPSIS -/* smtp-sink [-cLpv] [-w delay] [host]:port backlog +/* .fi +/* \fBsmtp-sink\fR [\fB-cLpv\fR] [\fB-w \fIdelay\fR] +/* [\fBinet:\fR][\fIhost\fR]:\fIport\fR \fIbacklog\fR +/* +/* \fBsmtp-sink\fR [\fB-cLpv\fR] [\fB-w \fIdelay\fR] +/* \fBunix:\fR\fIpathname\fR \fIbacklog\fR /* DESCRIPTION /* \fIsmtp-sink\fR listens on the named host (or address) and port. /* It takes SMTP messages from the network and throws them away. /* The purpose is to measure SMTP client performance, not protocol /* compliance. +/* Connections can be accepted on IPV4 endpoints or UNIX-domain sockets. +/* IPV4 is the default. /* This program is the complement of the \fIsmtp-source\fR program. /* .IP -c /* Display a running counter that is updated whenever an SMTP @@ -392,7 +399,13 @@ int main(int argc, char **argv) */ buffer = vstring_alloc(1024); var_myhostname = "smtp-sink"; - sock = inet_listen(argv[optind], backlog, BLOCKING); + if (strncmp(argv[optind], "unix:", 5) == 0) { + sock = unix_listen(argv[optind] + 5, backlog, BLOCKING); + } else { + if (strncmp(argv[optind], "inet:", 5) == 0) + argv[optind] += 5; + sock = inet_listen(argv[optind], backlog, BLOCKING); + } /* * Start the event handler. diff --git a/postfix/src/smtpstone/smtp-source.c b/postfix/src/smtpstone/smtp-source.c index 0fc1ae8f3..c5d9dbcc7 100644 --- a/postfix/src/smtpstone/smtp-source.c +++ b/postfix/src/smtpstone/smtp-source.c @@ -4,12 +4,16 @@ /* SUMMARY /* multi-threaded SMTP test generator /* SYNOPSIS -/* smtp-source [options] host[:port] +/* .fi +/* \fBsmtp-source\fR [\fIoptions\fR] [\fBinet:\fR]\fIhost\fR[:\fIport\fR] +/* +/* \fBsmtp-source\fR [\fIoptions\fR] \fBunix:\fIpathname\fR /* DESCRIPTION /* smtp-source connects to the named host and port (default 25) /* and sends one or more little messages to it, either sequentially /* or in parallel. The program speaks either SMTP (default) or -/* LMTP. +/* LMTP. Connections can be made to UNIX-domain and IPV4 servers. +/* IPV4 is the default. /* /* Options: /* .IP -c @@ -64,6 +68,7 @@ #include #include #include +#include #include #include #include @@ -131,6 +136,10 @@ static const char *var_myhostname; static int session_count; static int message_count = 1; static struct sockaddr_in sin; +#undef sun +static struct sockaddr_un sun; +static struct sockaddr *sa; +static int sa_len; static int recipients = 1; static char *defaddr; static char *recipient; @@ -383,14 +392,13 @@ static void start_connect(SESSION *session) * retrieving it later with getsockopt(). We can't use MSG_PEEK to * distinguish between server disconnect and connection refused. */ - if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) + if ((fd = socket(sa->sa_family, SOCK_STREAM, 0)) < 0) msg_fatal("socket: %m"); (void) non_blocking(fd, NON_BLOCKING); session->stream = vstream_fdopen(fd, O_RDWR); event_enable_write(fd, connect_done, (char *) session); smtp_timeout_setup(session->stream, var_timeout); - if (connect(fd, (struct sockaddr *) & sin, sizeof(sin)) < 0 - && errno != EINPROGRESS) + if (connect(fd, sa, sa_len) < 0 && errno != EINPROGRESS) fail_connect(session); } @@ -739,6 +747,8 @@ int main(int argc, char **argv) SESSION *session; char *host; char *port; + char *path; + int path_len; int sessions = 1; int ch; int i; @@ -813,8 +823,6 @@ int main(int argc, char **argv) } if (argc - optind != 1) usage(argv[0]); - if ((port = split_at(host = argv[optind], ':')) == 0) - port = "smtp"; if (random_delay > 0) srand(getpid()); @@ -822,10 +830,31 @@ int main(int argc, char **argv) /* * Translate endpoint address to internal form. */ - memset((char *) &sin, 0, sizeof(sin)); - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = find_inet_addr(host); - sin.sin_port = find_inet_port(port, "tcp"); + if (strncmp(argv[optind], "unix:", 5) == 0) { + path = argv[optind] + 5; + path_len = strlen(path); + if (path_len >= (int) sizeof(sun.sun_path)) + msg_fatal("unix-domain name too long: %s", path); + memset((char *) &sun, 0, sizeof(sun)); + sun.sun_family = AF_UNIX; +#ifdef HAS_SUN_LEN + sun.sun_len = path_len + 1; +#endif + memcpy(sun.sun_path, path, path_len); + sa = (struct sockaddr *) & sun; + sa_len = sizeof(sun); + } else { + if (strncmp(argv[optind], "inet:", 5) == 0) + argv[optind] += 5; + if ((port = split_at(host = argv[optind], ':')) == 0) + port = "smtp"; + memset((char *) &sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = find_inet_addr(host); + sin.sin_port = find_inet_port(port, "tcp"); + sa = (struct sockaddr *) & sin; + sa_len = sizeof(sin); + } /* * Make sure the SMTP server cannot run us out of memory by sending diff --git a/postfix/src/util/dict_db.c b/postfix/src/util/dict_db.c index 1207402bc..904404575 100644 --- a/postfix/src/util/dict_db.c +++ b/postfix/src/util/dict_db.c @@ -82,6 +82,10 @@ #define DONT_CLOBBER DB_NOOVERWRITE #endif +#ifndef DB_FCNTL_LOCKING +#define DB_FCNTL_LOCKING 0 +#endif + /* Utility library. */ #include "msg.h" @@ -399,6 +403,8 @@ static void dict_db_close(DICT *dict) { DICT_DB *dict_db = (DICT_DB *) dict; + if (DICT_DB_SYNC(dict_db->db, 0) < 0) + msg_fatal("flush database %s: %m", dict_db->path); if (DICT_DB_CLOSE(dict_db->db) < 0) msg_fatal("close database %s: %m", dict_db->path); myfree(dict_db->path); diff --git a/postfix/src/util/dict_ldap.c b/postfix/src/util/dict_ldap.c index e0cf2440c..250a1e646 100644 --- a/postfix/src/util/dict_ldap.c +++ b/postfix/src/util/dict_ldap.c @@ -1,4 +1,3 @@ - /*++ /* NAME /* dict_ldap 3 @@ -32,14 +31,20 @@ /* The port the LDAP server listens on. /* .IP \fIldapsource_\fRsearch_base /* The LDAP search base, for example: \fIO=organization name, C=country\fR. +/* .IP \fIldapsource_\fRdomain +/* If specified, only lookups ending in this value will be queried. +/* This can significantly reduce the query load on the LDAP server. /* .IP \fIldapsource_\fRtimeout /* Deadline for LDAP open() and LDAP search() . /* .IP \fIldapsource_\fRquery_filter /* The filter used to search for directory entries, for example /* \fI(mailacceptinggeneralid=%s)\fR. /* .IP \fIldapsource_\fRresult_attribute -/* The attribute returned by the search, in which to find +/* The attribute(s) returned by the search, in which to find /* RFC822 addresses, for example \fImaildrop\fR. +/* .IP \fIldapsource_\fRspecial_result_attribute +/* The attribute(s) of directory entries that can contain DNs or URLs. +/* If found, a recursive subsequent search is done using their values. /* .IP \fIldapsource_\fRscope /* LDAP search scope: sub, base, or one. /* .IP \fIldapsource_\fRbind @@ -70,7 +75,7 @@ /* Yorktown Heights, NY 10532, USA /* /* John Hensley -/* roll@ic.net +/* john@sunislelodge.com /* /*--*/ @@ -90,6 +95,8 @@ /* Utility library. */ +#include "match_list.h" +#include "match_ops.h" #include "msg.h" #include "mymalloc.h" #include "vstring.h" @@ -107,8 +114,10 @@ typedef struct { int server_port; int scope; char *search_base; + MATCH_LIST *domain; char *query_filter; - char *result_attribute; + ARGV *result_attributes; + int num_attributes; /* rest of list is DN's. */ int bind; char *bind_dn; char *bind_pw; @@ -170,9 +179,13 @@ static int dict_ldap_connect(DICT_LDAP *dict_ldap) /* * Configure alias dereferencing for this connection. Thanks to Mike - * Mattice for this. + * Mattice for this, and to Hery Rakotoarisoa for the v3 update. */ +#if (LDAP_API_VERSION >= 2000) + ldap_set_option(dict_ldap->ld, LDAP_OPT_DEREF, &(dict_ldap->dereference)); +#else dict_ldap->ld->ld_deref = dict_ldap->dereference; +#endif /* * If this server requires a bind, do so. Thanks to Sam Tardieu for @@ -227,27 +240,138 @@ static int dict_ldap_connect(DICT_LDAP *dict_ldap) return (0); } +/* + * dict_ldap_get_values: for each entry returned by a search, get the values + * of all its attributes. Recurses to resolve any DN or URL values found. + * + * This and the rest of the handling of multiple attributes, DNs and URLs + * are thanks to LaMont Jones. + */ +static void dict_ldap_get_values(DICT_LDAP *dict_ldap, LDAPMessage * res, + VSTRING * result) +{ + long i = 0; + int rc = 0; + LDAPMessage *resloop = 0; + LDAPMessage *entry = 0; + BerElement *ber; + char **vals; + char *attr; + char *myname = "dict_ldap_get_values"; + struct timeval tv; + + tv.tv_sec = dict_ldap->timeout; + tv.tv_usec = 0; + + if (msg_verbose) + msg_info("%s: Search found %d match(es)", myname, + ldap_count_entries(dict_ldap->ld, res)); + + for (entry = ldap_first_entry(dict_ldap->ld, res); entry != NULL; + entry = ldap_next_entry(dict_ldap->ld, entry)) { + attr = ldap_first_attribute(dict_ldap->ld, entry, &ber); + if (attr == NULL) { + msg_warn("%s: no attributes found", myname); + continue; + } + for (; attr != NULL; + attr = ldap_next_attribute(dict_ldap->ld, entry, ber)) { + + vals = ldap_get_values(dict_ldap->ld, entry, attr); + if (vals == NULL) { + msg_warn("%s: Entry doesn't have any values for %s", + myname, attr); + continue; + } + for (i = 0; dict_ldap->result_attributes->argv[i]; i++) { + if (strcasecmp(dict_ldap->result_attributes->argv[i], + attr) == 0) { + if (msg_verbose) + msg_info("%s: search returned value(s) for requested result attribute %s", myname, attr); + break; + } + } + + /* + * Append each returned address to the result list, possibly + * recursing (for dn or url attributes). + */ + if (i < dict_ldap->num_attributes) { + for (i = 0; vals[i] != NULL; i++) { + if (VSTRING_LEN(result) > 0) + vstring_strcat(result, ","); + vstring_strcat(result, vals[i]); + } + } else if (dict_ldap->result_attributes->argv[i]) { + for (i = 0; vals[i] != NULL; i++) { + if (ldap_is_ldap_url(vals[i])) { + if (msg_verbose) + msg_info("%s: looking up URL %s", myname, + vals[i]); + rc = ldap_url_search_st(dict_ldap->ld, vals[i], + 0, &tv, &resloop); + } else { + if (msg_verbose) + msg_info("%s: looking up DN %s", myname, vals[i]); + rc = ldap_search_st(dict_ldap->ld, vals[i], + LDAP_SCOPE_BASE, "objectclass=*", + dict_ldap->result_attributes->argv, + 0, &tv, &resloop); + } + if (rc == LDAP_SUCCESS) + dict_ldap_get_values(dict_ldap, resloop, result); + else { + msg_warn("%s: search error %d: %s ", myname, rc, + ldap_err2string(rc)); + dict_errno = DICT_ERR_RETRY; + } + if (resloop != 0) + ldap_msgfree(resloop); + } + } + ldap_value_free(vals); + } + } + if (msg_verbose) + msg_info("%s: Leaving %s", myname, myname); +} + /* dict_ldap_lookup - find database entry */ static const char *dict_ldap_lookup(DICT *dict, const char *name) { char *myname = "dict_ldap_lookup"; DICT_LDAP *dict_ldap = (DICT_LDAP *) dict; - static VSTRING *result; LDAPMessage *res = 0; - LDAPMessage *entry = 0; + static VSTRING *result; struct timeval tv; VSTRING *escaped_name = 0, *filter_buf = 0; - char *result_attributes[1], - **attr_values; - long i = 0; int rc = 0; char *sub, *end; dict_errno = 0; + if (msg_verbose) + msg_info("%s: In dict_ldap_lookup", myname); + + /* + * If they specified a domain list for this map, then only search for + * addresses in domains on the list. This can significantly reduce the + * load on the LDAP server. + */ + if (dict_ldap->domain) { + if (strrchr(name, '@') != 0) { + if (match_list_match(dict_ldap->domain, (char *) strrchr(name, '@') + 1) == 0) { + if (msg_verbose) + msg_info("%s: domain of %s not found in domain list", myname, + name); + return (0); + } + } + } + /* * Initialize the result holder. */ @@ -255,9 +379,6 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name) result = vstring_alloc(2); vstring_strcpy(result, ""); - if (msg_verbose) - msg_info("%s: In dict_ldap_lookup", myname); - /* * Connect to the LDAP server, if necessary. */ @@ -371,56 +492,35 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name) msg_info("%s: Searching with filter %s", myname, vstring_str(filter_buf)); - /* - * Put result_attribute in an array, so the search can return only that - * attribute and not the entire entry. - */ - result_attributes[0] = dict_ldap->result_attribute; - if ((rc = ldap_search_st(dict_ldap->ld, dict_ldap->search_base, dict_ldap->scope, vstring_str(filter_buf), - result_attributes, + dict_ldap->result_attributes->argv, 0, &tv, &res)) == LDAP_SUCCESS) { /* * Search worked; extract the requested result_attribute. */ - if (msg_verbose) - msg_info("%s: Search found %d match(es)", myname, - ldap_count_entries(dict_ldap->ld, res)); + + dict_ldap_get_values(dict_ldap, res, result); /* - * There could have been lots of hits. + * OpenLDAP's ldap_next_attribute returns a bogus + * LDAP_DECODING_ERROR; I'm ignoring that for now. */ - for (entry = ldap_first_entry(dict_ldap->ld, res); entry != NULL; - entry = ldap_next_entry(dict_ldap->ld, entry)) { - /* - * And each entry could have multiple attributes. - */ - attr_values = ldap_get_values(dict_ldap->ld, entry, - dict_ldap->result_attribute); - if (attr_values == NULL) { - msg_warn("%s: Entry doesn't have any values for %s", - myname, dict_ldap->result_attribute); - continue; - } - - /* - * Append each returned address to the result list. - */ - for (i = 0; attr_values[i] != NULL; i++) { - if (VSTRING_LEN(result) > 0) - vstring_strcat(result, ","); - vstring_strcat(result, attr_values[i]); - } - ldap_value_free(attr_values); - } - if (dict_ldap->ld->ld_errno != LDAP_SUCCESS) +#if (LDAP_API_VERSION >= 2000) + ldap_get_option(dict_ldap->ld, LDAP_OPT_ERROR_NUMBER, &rc); + if (rc != LDAP_SUCCESS && rc != LDAP_DECODING_ERROR) + msg_warn("%s: Had some trouble with entries returned by search: %s", myname, ldap_err2string(rc)); +#else + if (dict_ldap->ld->ld_errno != LDAP_SUCCESS && + dict_ldap->ld->ld_errno != LDAP_DECODING_ERROR) msg_warn ("%s: Had some trouble with entries returned by search: %s", myname, ldap_err2string(dict_ldap->ld->ld_errno)); +#endif + if (msg_verbose) msg_info("%s: Search returned %s", myname, VSTRING_LEN(result) > @@ -454,7 +554,11 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name) if (filter_buf != 0) vstring_free(filter_buf); - return (VSTRING_LEN(result) > 0 ? vstring_str(result) : 0); + /* + * If we had an error, return nothing, Otherwise, return the result, if + * any. + */ + return (VSTRING_LEN(result) > 0 && !dict_errno ? vstring_str(result) : 0); } /* dict_ldap_update - add or update database entry */ @@ -478,8 +582,9 @@ static void dict_ldap_close(DICT *dict) myfree(dict_ldap->ldapsource); myfree(dict_ldap->server_host); myfree(dict_ldap->search_base); + match_list_free(dict_ldap->domain); myfree(dict_ldap->query_filter); - myfree(dict_ldap->result_attribute); + argv_free(dict_ldap->result_attributes); myfree(dict_ldap->bind_dn); myfree(dict_ldap->bind_pw); myfree((char *) dict_ldap); @@ -492,8 +597,9 @@ DICT *dict_ldap_open(const char *ldapsource, int dummy, int dict_flags) char *myname = "dict_ldap_open"; DICT_LDAP *dict_ldap; VSTRING *config_param; - int rc = 0; + char *domainlist; char *scope; + char *attr; dict_ldap = (DICT_LDAP *) mymalloc(sizeof(*dict_ldap)); dict_ldap->dict.lookup = dict_ldap_lookup; @@ -566,6 +672,20 @@ DICT *dict_ldap_open(const char *ldapsource, int dummy, int dict_flags) msg_info("%s: %s is %s", myname, vstring_str(config_param), dict_ldap->search_base); + vstring_sprintf(config_param, "%s_domain", ldapsource); + domainlist = + mystrdup((char *) get_mail_conf_str(vstring_str(config_param), + "", 0, 0)); + if (domainlist) { + dict_ldap->domain = match_list_init(domainlist, 1, match_string); + if (dict_ldap->domain == NULL) + msg_warn("%s: domain match list creation using \"%s\" failed, will continue without it", myname, domainlist); + if (msg_verbose) + msg_info("%s: domain list created using \"%s\"", myname, + domainlist); + myfree(domainlist); + } + /* * get configured value of "ldapsource_timeout"; default to 10 seconds * @@ -589,12 +709,22 @@ DICT *dict_ldap_open(const char *ldapsource, int dummy, int dict_flags) dict_ldap->query_filter); vstring_sprintf(config_param, "%s_result_attribute", ldapsource); - dict_ldap->result_attribute = - mystrdup((char *) get_mail_conf_str(vstring_str(config_param), - "maildrop", 0, 0)); + attr = mystrdup((char *) get_mail_conf_str(vstring_str(config_param), + "maildrop", 0, 0)); if (msg_verbose) - msg_info("%s: %s is %s", myname, vstring_str(config_param), - dict_ldap->result_attribute); + msg_info("%s: %s is %s", myname, vstring_str(config_param), attr);; + dict_ldap->result_attributes = argv_split(attr, " ,\t\r\n"); + dict_ldap->num_attributes = dict_ldap->result_attributes->argc; + + vstring_sprintf(config_param, "%s_special_result_attribute", ldapsource); + attr = mystrdup((char *) get_mail_conf_str(vstring_str(config_param), + "", 0, 0)); + if (msg_verbose) + msg_info("%s: %s is %s", myname, vstring_str(config_param), attr); + + if (*attr) { + argv_split_append(dict_ldap->result_attributes, attr, " ,\t\r\n"); + } /* * get configured value of "ldapsource_bind"; default to true @@ -646,7 +776,7 @@ DICT *dict_ldap_open(const char *ldapsource, int dummy, int dict_flags) dict_ldap->cache_expiry = get_mail_conf_int(vstring_str(config_param), 30, 0, 0); if (msg_verbose) - msg_info("%s: %s is %d", myname, vstring_str(config_param), + msg_info("%s: %s is %ld", myname, vstring_str(config_param), dict_ldap->cache_expiry); /* @@ -656,7 +786,7 @@ DICT *dict_ldap_open(const char *ldapsource, int dummy, int dict_flags) dict_ldap->cache_size = get_mail_conf_int(vstring_str(config_param), 32768, 0, 0); if (msg_verbose) - msg_info("%s: %s is %d", myname, vstring_str(config_param), + msg_info("%s: %s is %ld", myname, vstring_str(config_param), dict_ldap->cache_size); /* @@ -698,3 +828,4 @@ DICT *dict_ldap_open(const char *ldapsource, int dummy, int dict_flags) } #endif + diff --git a/postfix/src/util/dict_open.c b/postfix/src/util/dict_open.c index ff09aad7a..454b28719 100644 --- a/postfix/src/util/dict_open.c +++ b/postfix/src/util/dict_open.c @@ -181,7 +181,7 @@ typedef struct { static DICT_OPEN_INFO dict_open_info[] = { "environ", dict_env_open, "unix", dict_unix_open, -#if 1 +#if 0 "tcp", dict_tcp_open, #endif #ifdef HAS_DBM