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.
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
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,
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.
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
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
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.
-
-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.
-
-For example, the catchall user for a virtual domain might look 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
-
-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.
+"@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'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.
+
+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: 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
+
+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
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.
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.
-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
===========================================
# 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
# 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
# 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
-# 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
+
+# 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
-mkdir lib
-cp /lib/libnss_* lib
+cond_copy '/lib/libnss_*' lib
+cond_copy '/lib/libresolv*' lib
\ No newline at end of file
<p>
In order to build Postfix with <b>db</b> support on UNIX systems
-that do not have <b>db</b> support out of the box, you need the
-db-1.85 release, or <a href="http://www.sleepycat.com">the current
-version</a> which has a db-1.85 compatible interface.
-
-<p>
-
-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.
-
-<p>
-
-<pre>
- % 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
-</pre>
-
-<p>
-
-Of course you will have to specify the actual location of the
-include directory and of the object library.
-
-<p>
-
-When building with a third-party DB library you may into one of the
-following problems:
-
-<p>
-
-<ul>
-
-<li> Older DB versions install a file
-<b>/usr/local/include/ndbm.h</b> that is incompatible with
-<b>/usr/include/ndbm.h</b>. Be sure to get rid of the bogus file.
-See the FAQ entry titled "<a href="#dbm_dirfno">Undefined symbols:
-dbm_pagfno, dbm_dirfno etc</a>".
-
-<p>
-
-<li>With Sleepcat DB 3.0.55, the linker will complain that dbopen()
-is not found. To fix, apply the following patch to the DB 3.0.55
-db_185.h include file:
-
-<p>
-<pre>
-*** db_185.h.orig Tue Mar 7 16:27:32 2000
---- db_185.h Tue Mar 7 16:27:44 2000
-***************
-*** 166,173 ****
- #if defined(__cplusplus)
- extern "C" {
- #endif
-- #ifdef DB_LIBRARY_COMPATIBILITY_API
- #define dbopen __db185_open
- DB *__db185_open __P((const char *, int, int, DBTYPE, const void *));
- #else
- DB *dbopen __P((const char *, int, int, DBTYPE, const void *));
---- 166,173 ----
- #if defined(__cplusplus)
- extern "C" {
- #endif
- #define dbopen __db185_open
-+ #ifdef DB_LIBRARY_COMPATIBILITY_API
- DB *__db185_open __P((const char *, int, int, DBTYPE, const void *));
- #else
- DB *dbopen __P((const char *, int, int, DBTYPE, const void *));
-</pre>
-
-</ul>
+that do not have <b>db</b> support out of the box, you can use the
+Berkeley DB source code from <a
+href="http://www.sleepycat.com">www.sleepycat.com</a>. See the file
+<b>DB_README</b> in the Postfix source code distribution for
+instructions on how to build Postfix with Sleepycat's Berkeley DB.
<hr>
problem reports are sent to the <a href="bounce.8.html"><b>bounce</b>(8)</a> or <a href="defer.8.html"><b>defer</b>(8)</a> 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 <b>lmtp</b> in
- <b>services</b>(4). If no such service is found, the
- <b>lmtp</b><i>_</i><b>tcp</b><i>_</i><b>port</b> configuration parameter (default value of
- 24) will be used. The LMTP client does not perform MX
- (mail exchanger) lookups since those are defined only for
- SMTP.
+ The LMTP client connects to the destination specified in
+ the message delivery request. The destination, usually
+ specified in the Postfix <a href="transport.5.html"><b>transport</b>(5)</a> table, has the form:
+
+ <b>unix</b>:<i>pathname</i>
+ Connect to the UNIX-domain server that is bound to
+ the specified <i>pathname</i>. If the process runs
+ chrooted, an absolute pathname is interpreted rela-
+ tive to the changed root directory.
+
+ <b>inet</b>:<i>host</i>, <b>inet:</b><i>host</i>:<i>port</i> (symbolic host)
+
+ <b>inet</b>:[<i>addr</i>], <b>inet</b>:[<i>addr</i>]:<i>port</i> (numeric host)
+ Connect to the specified IPV4 TCP port on the spec-
+ ified host. If no port is specified, connect to the
+ port defined as <b>lmtp</b> in <b>services</b>(4). If no such
+ service is found, the <b>lmtp</b><i>_</i><b>tcp</b><i>_</i><b>port</b> configuration
+ parameter (default value of 24) will be used.
+
+ The LMTP client does not perform MX (mail
+ exchanger) lookups since those are defined only for
+ mail delivery via SMTP.
+
+ If neither <b>unix:</b> nor <b>inet:</b> are specified, <b>inet:</b> is
+ assumed.
<b>SECURITY</b>
The LMTP client is moderately security-sensitive. It talks
<a href="http://www.faqs.org/rfcs/rfc821.html">RFC 821</a> (SMTP protocol)
<a href="http://www.faqs.org/rfcs/rfc1651.html">RFC 1651</a> (SMTP service extensions)
<a href="http://www.faqs.org/rfcs/rfc1870.html">RFC 1870</a> (Message Size Declaration)
+
+
+
+ 1
+
+
+
+
+
+LMTP(8) LMTP(8)
+
+
<a href="http://www.faqs.org/rfcs/rfc2033.html">RFC 2033</a> (LMTP protocol)
<a href="http://www.faqs.org/rfcs/rfc2197.html">RFC 2197</a> (Pipelining)
The following <b>main.cf</b> parameters are especially relevant
to this program. See the Postfix <b>main.cf</b> file for syntax
details and for default values. Use the <b>postfix</b> <b>reload</b>
-
-
-
- 1
-
-
-
-
-
-LMTP(8) LMTP(8)
-
-
command after a configuration change.
<b>Miscellaneous</b>
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:
<b>o</b> 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 <b>RSET</b> com-
mand.
LMTP server. If no connection can be made within
the deadline, the message is deferred.
+
+
+ 3
+
+
+
+
+
+LMTP(8) LMTP(8)
+
+
<b>lmtp</b><i>_</i><b>lhlo</b><i>_</i><b>timeout</b>
Timeout in seconds for sending the <b>LHLO</b> command,
and for receiving the server response.
Timeout in seconds for sending the <b>DATA</b> command,
and for receiving the server response.
-
-
-
- 3
-
-
-
-
-
-LMTP(8) LMTP(8)
-
-
<b>lmtp</b><i>_</i><b>data</b><i>_</i><b>xfer</b><i>_</i><b>timeout</b>
Timeout in seconds for sending the message content.
<a href="master.8.html">master(8)</a> process manager
<a href="qmgr.8.html">qmgr(8)</a> queue manager
services(4) Internet services and aliases
- spawn(8) auxiliary command spawner
+ <a href="spawn.8.html">spawn(8)</a> auxiliary command spawner
syslogd(8) system logging
<b>LICENSE</b>
Alterations for LMTP by:
Philip A. Prindeville
+
+
+
+ 4
+
+
+
+
+
+LMTP(8) LMTP(8)
+
+
Mirapoint, Inc.
USA.
- 4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 5
</pre> </body> </html>
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
<b>SECURITY</b>
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.
<b>STANDARDS</b>
<a href="http://www.faqs.org/rfcs/rfc2554.html">RFC 2554</a> (AUTH command)
<b>DIAGNOSTICS</b>
- Problems and transactions are logged to <b>syslogd</b>(8). Cor-
- rupted message files are marked so that the queue manager
+ Problems and transactions are logged to <b>syslogd</b>(8). Cor-
+ rupted message files are marked so that the queue manager
can move them to the <b>corrupt</b> queue for further inspection.
- Depending on the setting of the <b>notify</b><i>_</i><b>classes</b> parameter,
- the postmaster is notified of bounces, protocol problems,
+ Depending on the setting of the <b>notify</b><i>_</i><b>classes</b> parameter,
+ the postmaster is notified of bounces, protocol problems,
and of other trouble.
-<b>BUGS</b>
-<b>CONFIGURATION</b> <b>PARAMETERS</b>
- The following <b>main.cf</b> parameters are especially relevant
- to this program. See the Postfix <b>main.cf</b> file for syntax
-
1
SMTP(8) SMTP(8)
- details and for default values. Use the <b>postfix</b> <b>reload</b>
+<b>BUGS</b>
+<b>CONFIGURATION</b> <b>PARAMETERS</b>
+ The following <b>main.cf</b> parameters are especially relevant
+ to this program. See the Postfix <b>main.cf</b> file for syntax
+ details and for default values. Use the <b>postfix</b> <b>reload</b>
command after a configuration change.
<b>Miscellaneous</b>
<b>best</b><i>_</i><b>mx</b><i>_</i><b>transport</b>
- 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).
<b>debug</b><i>_</i><b>peer</b><i>_</i><b>level</b>
- Verbose logging level increment for hosts that
+ Verbose logging level increment for hosts that
match a pattern in the <b>debug</b><i>_</i><b>peer</b><i>_</i><b>list</b> parameter.
<b>debug</b><i>_</i><b>peer</b><i>_</i><b>list</b>
- 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
<b>debug</b><i>_</i><b>peer</b><i>_</i><b>level</b> parameter.
<b>disable</b><i>_</i><b>dns</b><i>_</i><b>lookups</b>
- Disable DNS lookups. This means that mail must be
+ Disable DNS lookups. This means that mail must be
forwarded via a smart relay host.
<b>error</b><i>_</i><b>notice</b><i>_</i><b>recipient</b>
- Recipient of protocol/policy/resource/software
+ Recipient of protocol/policy/resource/software
error notices.
<b>fallback</b><i>_</i><b>relay</b>
- 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.
<b>ignore</b><i>_</i><b>mx</b><i>_</i><b>lookup</b><i>_</i><b>error</b>
<b>inet</b><i>_</i><b>interfaces</b>
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.
<b>notify</b><i>_</i><b>classes</b>
- When this parameter includes the <b>protocol</b> class,
- send mail to the postmaster with transcripts of
+ When this parameter includes the <b>protocol</b> class,
+ send mail to the postmaster with transcripts of
SMTP sessions with protocol errors.
- <b>smtp</b><i>_</i><b>always</b><i>_</i><b>send</b><i>_</i><b>ehlo</b>
- Always send EHLO at the start of a connection.
- <b>smtp</b><i>_</i><b>skip</b><i>_</i><b>4xx</b><i>_</i><b>greeting</b>
- Skip servers that greet us with a 4xx status code.
SMTP(8) SMTP(8)
+ <b>smtp</b><i>_</i><b>always</b><i>_</i><b>send</b><i>_</i><b>ehlo</b>
+ Always send EHLO at the start of a connection.
+
+ <b>smtp</b><i>_</i><b>skip</b><i>_</i><b>4xx</b><i>_</i><b>greeting</b>
+ Skip servers that greet us with a 4xx status code.
+
<b>smtp</b><i>_</i><b>skip</b><i>_</i><b>5xx</b><i>_</i><b>greeting</b>
- Skip servers that greet us with a 5xx status code.
+ Skip servers that greet us with a 5xx status code.
<b>smtp</b><i>_</i><b>skip</b><i>_</i><b>quit</b><i>_</i><b>response</b>
- Do not wait for the server response after sending
+ Do not wait for the server response after sending
QUIT.
<b>smtp</b><i>_</i><b>bind</b><i>_</i><b>address</b>
- Numerical network address to bind to when making a
+ Numerical network address to bind to when making a
connection.
<b>Authentication</b> <b>controls</b>
<b>smtp</b><i>_</i><b>enable</b><i>_</i><b>sasl</b><i>_</i><b>auth</b>
- Enable per-session authentication as per <a href="http://www.faqs.org/rfcs/rfc2554.html">RFC 2554</a>
- (SASL). By default, Postfix is built without SASL
+ Enable per-session authentication as per <a href="http://www.faqs.org/rfcs/rfc2554.html">RFC 2554</a>
+ (SASL). By default, Postfix is built without SASL
support.
<b>smtp</b><i>_</i><b>sasl</b><i>_</i><b>password</b><i>_</i><b>maps</b>
Lookup tables with per-host or domain <i>name</i>:<i>password</i>
- entries. No entry for a host means no attempt to
+ entries. No entry for a host means no attempt to
authenticate.
<b>smtp</b><i>_</i><b>sasl</b><i>_</i><b>security</b><i>_</i><b>options</b>
<b>Resource</b> <b>controls</b>
<b>smtp</b><i>_</i><b>destination</b><i>_</i><b>concurrency</b><i>_</i><b>limit</b>
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
<b>default</b><i>_</i><b>destination</b><i>_</i><b>concurrency</b><i>_</i><b>limit</b> parameter.
<b>smtp</b><i>_</i><b>destination</b><i>_</i><b>recipient</b><i>_</i><b>limit</b>
- Limit the number of recipients per message deliv-
- ery. The default limit is taken from the
- <b>default</b><i>_</i><b>destination</b><i>_</i><b>recipient</b><i>_</i><b>limit</b> parameter.
-
-<b>Timeout</b> <b>controls</b>
- <b>smtp</b><i>_</i><b>connect</b><i>_</i><b>timeout</b>
- Timeout in seconds for completing a TCP connection.
+ Limit the number of recipients per message
SMTP(8) SMTP(8)
+ delivery. The default limit is taken from the
+ <b>default</b><i>_</i><b>destination</b><i>_</i><b>recipient</b><i>_</i><b>limit</b> parameter.
+
+<b>Timeout</b> <b>controls</b>
+ <b>smtp</b><i>_</i><b>connect</b><i>_</i><b>timeout</b>
+ 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.
<b>smtp</b><i>_</i><b>helo</b><i>_</i><b>timeout</b>
- 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.
<b>smtp</b><i>_</i><b>helo</b><i>_</i><b>timeout</b>
- Timeout in seconds for sending the <b>HELO</b> command,
+ Timeout in seconds for sending the <b>HELO</b> command,
and for receiving the server response.
<b>smtp</b><i>_</i><b>mail</b><i>_</i><b>timeout</b>
- Timeout in seconds for sending the <b>MAIL</b> <b>FROM</b> com-
+ Timeout in seconds for sending the <b>MAIL</b> <b>FROM</b> com-
mand, and for receiving the server response.
<b>smtp</b><i>_</i><b>rcpt</b><i>_</i><b>timeout</b>
and for receiving the server response.
<b>smtp</b><i>_</i><b>data</b><i>_</i><b>init</b><i>_</i><b>timeout</b>
- Timeout in seconds for sending the <b>DATA</b> command,
+ Timeout in seconds for sending the <b>DATA</b> command,
and for receiving the server response.
<b>smtp</b><i>_</i><b>data</b><i>_</i><b>xfer</b><i>_</i><b>timeout</b>
<b>smtp</b><i>_</i><b>data</b><i>_</i><b>done</b><i>_</i><b>timeout</b>
Timeout in seconds for sending the "<b>.</b>" 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.
<b>smtp</b><i>_</i><b>quit</b><i>_</i><b>timeout</b>
- Timeout in seconds for sending the <b>QUIT</b> command,
+ Timeout in seconds for sending the <b>QUIT</b> command,
and for receiving the server response.
<b>SEE</b> <b>ALSO</b>
<a href="qmgr.8.html">qmgr(8)</a> queue manager
syslogd(8) system logging
-<b>LICENSE</b>
- The Secure Mailer license must be distributed with this
- software.
-<b>AUTHOR(S)</b>
- Wietse Venema
- IBM T.J. Watson Research
SMTP(8) SMTP(8)
+<b>LICENSE</b>
+ The Secure Mailer license must be distributed with this
+ software.
+
+<b>AUTHOR(S)</b>
+ Wietse Venema
+ IBM T.J. Watson Research
P.O. Box 704
Yorktown Heights, NY 10598, USA
-
-
-
-
-
-
-
*) 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
CCARGS="$CCARGS -DHAS_DB"
SYSLIBS="$SYSLIBS -ldb"
fi
- if [ -f /usr/include/db_185.h ]; then
- CCARGS="$CCARGS -DPATH_DB_H='<db_185.h>'"
- fi
;;
HP-UX.B.10.*) SYSTYPE=HPUX10
CCARGS="$CCARGS `nm /usr/lib/libc.a 2>/dev/null |
CCARGS="$CCARGS -DHAS_DB"
SYSLIBS=-ldb
fi
- if [ -f /usr/include/db_185.h ]; then
- CCARGS="$CCARGS -DPATH_DB_H='<db_185.h>'"
- fi
;;
HP-UX.B.11.*) SYSTYPE=HPUX11
SYSLIBS=-lnsl
CCARGS="$CCARGS -DHAS_DB"
SYSLIBS="$SYSLIBS -ldb"
fi
- if [ -f /usr/include/db_185.h ]; then
- CCARGS="$CCARGS -DPATH_DB_H='<db_185.h>'"
- fi
;;
ReliantUNIX-?.5.43) SYSTYPE=ReliantUnix543
RANLIB=echo
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
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
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));
}
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)
single_server_main(argc, argv, flush_service,
MAIL_SERVER_TIME_TABLE, time_table,
+ MAIL_SERVER_PRE_INIT, pre_jail_init,
0);
}
* Version of this program.
*/
#define VAR_MAIL_VERSION "mail_version"
-#define DEF_MAIL_VERSION "Snapshot-20001028"
+#define DEF_MAIL_VERSION "Snapshot-20001029"
extern char *var_mail_version;
/* LICENSE
/* 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.
/* SECURITY
/* .ad
/* .fi
/*++
/* NAME
-/* lmtp_connect_inet 3
+/* lmtp_connect 3
/* SUMMARY
/* connect to LMTP server
/* SYNOPSIS
/* DESCRIPTION
/* This module implements LMTP connection management.
/*
-/* lmtp_connect() attempts to establish an LMTP session with a host.
+/* 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
#include <sys_defs.h>
#include <sys/socket.h>
+#include <sys/un.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#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,
char *myname = "lmtp_connect_addr";
struct sockaddr_in sin;
int sock;
- int conn_stat;
- int saved_errno;
- VSTREAM *stream;
- int ch;
/*
* Sanity checks.
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);
*/
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);
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);
*/
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 */
/* 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);
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;
/*
* 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)
* 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;
/* 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
*/
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.
#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)
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
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
/* 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
*/
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.
/* 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
#include <sys/socket.h>
#include <sys/wait.h>
#include <netinet/in.h>
+#include <sys/un.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
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;
* 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);
}
SESSION *session;
char *host;
char *port;
+ char *path;
+ int path_len;
int sessions = 1;
int ch;
int i;
}
if (argc - optind != 1)
usage(argv[0]);
- if ((port = split_at(host = argv[optind], ':')) == 0)
- port = "smtp";
if (random_delay > 0)
srand(getpid());
/*
* 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
#define DONT_CLOBBER DB_NOOVERWRITE
#endif
+#ifndef DB_FCNTL_LOCKING
+#define DB_FCNTL_LOCKING 0
+#endif
+
/* Utility library. */
#include "msg.h"
{
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);
-
/*++
/* NAME
/* dict_ldap 3
/* 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
/* Yorktown Heights, NY 10532, USA
/*
/* John Hensley
-/* roll@ic.net
+/* john@sunislelodge.com
/*
/*--*/
/* Utility library. */
+#include "match_list.h"
+#include "match_ops.h"
#include "msg.h"
#include "mymalloc.h"
#include "vstring.h"
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;
/*
* 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
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.
*/
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.
*/
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) >
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 */
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);
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;
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
*
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
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);
/*
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);
/*
}
#endif
+
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