mirror of
https://github.com/vdukhovni/postfix
synced 2025-08-30 21:55:20 +00:00
snapshot-20000507
This commit is contained in:
@@ -3618,7 +3618,7 @@ Apologies for any names omitted.
|
||||
field by the recipient localpart when a destination matches
|
||||
$mydestination/$inet_interfaces. The price is the introduction
|
||||
of a new parameter local_destination_recipient_limit which
|
||||
defaults to 1 i order to maintain backwards compatibility.
|
||||
defaults to 1 in order to maintain backwards compatibility.
|
||||
Files: qmgr/qmgr.c, qmgr/qmgr_message.c.
|
||||
|
||||
20000129
|
||||
@@ -3843,13 +3843,6 @@ Apologies for any names omitted.
|
||||
record delimiter (for example, eol=\r\n). This is necessary
|
||||
for transports that require CRLF instead of UNIX-style LF.
|
||||
|
||||
20000428
|
||||
|
||||
New code: added support to the vstring module for fixed-size
|
||||
buffers. This may help to avoid clumsy code that would have
|
||||
to prevent memory leaks. The buffers cause a fatal error
|
||||
when they turn out too small. File: util/vstring.[hc].
|
||||
|
||||
20000502
|
||||
|
||||
In order to support timeouts more conveniently, VSTREAMs
|
||||
@@ -3881,13 +3874,45 @@ Apologies for any names omitted.
|
||||
|
||||
20000505
|
||||
|
||||
Bugfix: the SMTP server now flushes output in-between tarpit
|
||||
delays, to avoid protocol timeouts when a client causes lots
|
||||
of errors. Found by Lamont Jones, HP. File: smtpd/smtpd_chat.c.
|
||||
Bugfix: the SMTP server now flushes unwritten output before
|
||||
tarpit delays, to avoid protocol timeouts in pipelined
|
||||
sessions when a client causes lots of errors. Found by
|
||||
Lamont Jones, HP. File: smtpd/smtpd_chat.c.
|
||||
|
||||
Finished the LMTP client, which is based on a modified
|
||||
version of the SMTP client by Philippe Prindeville, Mirapoint,
|
||||
Inc., later modified by Amos Gouaux, UTDallas, and then
|
||||
Wietse ripped it all up again. Currently this talks LMTP
|
||||
over TCP only.
|
||||
|
||||
Feature: override main.cf parameters in master.cf. Specify
|
||||
"-o parameter=value" after the program name. This allows
|
||||
you to selectively override myhostname etc. See also the
|
||||
new smtp_bind_address parameter below.
|
||||
|
||||
20000506
|
||||
|
||||
Convenience: the LMTP and SMTP clients now append the local
|
||||
domain to unqualified nexthop destinations. This makes it
|
||||
more convenient to set up transport maps. Files:
|
||||
more convenient to set up transport maps. Files:
|
||||
lmtp/lmtp_addr.c, smtp/smtp_addr.c.
|
||||
|
||||
Sendmail compatibility: the Postfix SMTP client now skips
|
||||
servers that greet the client with a 4xx or 5xx status
|
||||
code. To disable, set both smtp_skip_4xx_greeting and
|
||||
smtp_skip_5xx_greeting to "no".
|
||||
|
||||
20000507
|
||||
|
||||
Portability: NetBSD has migrated to /etc/mail/aliases. We
|
||||
can expect to see this happen more often when systems start
|
||||
shipping Sendmail 8.10. File: util/sys_defs.h
|
||||
|
||||
Updated LDAP code by John Hensley, with support for
|
||||
dereferencing of LDAP aliases, which have nothing to do
|
||||
with Postfix aliases.
|
||||
|
||||
Feature: "smtp_bind_address=x.x.x.x" specifies the source
|
||||
IP address for SMTP client connections. Specify in master.cf
|
||||
as "smtp -o smtp_bind_address=x.x.x.x" in order to give
|
||||
different delivery agents different source addresses.
|
||||
|
@@ -92,10 +92,8 @@ development are in /usr/ccs/bin, so you MUST have /usr/ccs/bin in
|
||||
your command search path.
|
||||
|
||||
If you need to build Postfix for multiple architectures, use the
|
||||
makelinks shell script to build a shadow tree with symbolic links
|
||||
to the source files.
|
||||
|
||||
% sh makelinks `pwd` /some/where/else
|
||||
lndir command to build a shadow tree with symbolic links to the
|
||||
source files. lndir is part of X11R6.
|
||||
|
||||
If at any time in the build process you get messages like: "make:
|
||||
don't know how to ..." you should be able to recover by running
|
||||
|
@@ -1,3 +1,15 @@
|
||||
LDAP SUPPORT IN POSTFIX
|
||||
=======================
|
||||
|
||||
Postfix can use an LDAP directory as a source for any of its lookups:
|
||||
aliases, virtual, canonical, etc. This allows you to keep information
|
||||
for your mail service in a replicated network database with fine-grained
|
||||
access controls. By not storing it locally on the mail server, the
|
||||
administrators can maintain it from anywhere, and the users can control
|
||||
whatever bits of it you think appropriate. You can have multiple mail
|
||||
servers using the same information, without the hassle and delay of
|
||||
having to copy it to each.
|
||||
|
||||
BUILDING WITH LDAP SUPPORT
|
||||
==========================
|
||||
|
||||
@@ -7,13 +19,14 @@ accordingly.
|
||||
|
||||
If you're using the libraries from the UM distribution
|
||||
(http://www.umich.edu/~dirsvcs/ldap/ldap.html) or OpenLDAP
|
||||
(http://www.openldap.org), something like this should work:
|
||||
(http://www.openldap.org), something like this in the top level of your
|
||||
Postfix source tree should work:
|
||||
|
||||
% make tidy
|
||||
% make makefiles CCARGS="-I/some/where/include -DHAS_LDAP" \
|
||||
AUXLIBS="/some/where/libldap.a /some/where/liblber.a"
|
||||
AUXLIBS="/some/where/lib/libldap.a /some/where/lib/liblber.a"
|
||||
|
||||
The `make tidy' command is needed only if you have previously built
|
||||
The 'make tidy' command is needed only if you have previously built
|
||||
Postfix without LDAP support.
|
||||
|
||||
If your LDAP libraries were built with Kerberos support, you'll also
|
||||
@@ -21,16 +34,16 @@ need to include your Kerberos libraries in this line. Note that the KTH
|
||||
Kerberos IV libraries might conflict with Postfix's lib/libdns.a, which
|
||||
defines dns_lookup. If that happens, you'll probably want to link with
|
||||
LDAP libraries that lack Kerberos support just to build Postfix, as it
|
||||
doesn't yet support Kerberos binds to the LDAP server anyway. Sorry
|
||||
about the bother.
|
||||
doesn't support Kerberos binds to the LDAP server anyway. Sorry about
|
||||
the bother.
|
||||
|
||||
If you're using one of the Netscape LDAP SDKs, you'll need to change the
|
||||
AUXLIBS line to point to libldap10.so or libldapssl30.so or whatever you
|
||||
have, and you may need to use the -R option so the executables can find
|
||||
it at runtime.
|
||||
have, and you may need to use the appropriate linker option (e.g. '-R')
|
||||
so the executables can find it at runtime.
|
||||
|
||||
USING LDAP LOOKUPS
|
||||
==================
|
||||
CONFIGURING LDAP LOOKUPS
|
||||
========================
|
||||
|
||||
In order to use LDAP lookups, define at least one LDAP source as a table
|
||||
lookup in main.cf, for example:
|
||||
@@ -39,22 +52,24 @@ lookup in main.cf, for example:
|
||||
|
||||
Each LDAP source can have the following parameters, which should be
|
||||
prefixed in main.cf with the name you've given the source in its
|
||||
definition. To continue the example, the first parameter below,
|
||||
"server_host", would be defined in main.cf as "ldapsource_server_host".
|
||||
Defaults are given in parentheses:
|
||||
definition and an underscore. To continue the example, the first
|
||||
parameter below, "server_host", would be defined in main.cf as
|
||||
"ldapsource_server_host". Defaults are given in parentheses:
|
||||
|
||||
server_host (localhost)
|
||||
The name of the host running the LDAP server, e.g.
|
||||
ldapsource_server_host = ldap.your.com
|
||||
It should be possible with all the libraries mentioned above to
|
||||
specify multiple servers separated by spaces, with the libraries
|
||||
trying them in order should the first one fail.
|
||||
trying them in order should the first one fail. It should also
|
||||
be possible to give each server in the list a different port, by
|
||||
naming them like "ldap.your.com:1444".
|
||||
|
||||
server_port (389)
|
||||
The port the LDAP server listens on, e.g.
|
||||
ldapsource_server_port = 778
|
||||
|
||||
search_base (no default)
|
||||
search_base (No default; you must configure this.)
|
||||
The base at which to conduct the search, e.g.
|
||||
ldapsource_search_base = dc=your, dc=com
|
||||
|
||||
@@ -72,12 +87,23 @@ Defaults are given in parentheses:
|
||||
returned by the lookup, to be resolved to an email address.
|
||||
ldapsource_result_attribute = mailbox
|
||||
|
||||
scope (sub)
|
||||
The LDAP search scope: sub, base, or one. These translate into
|
||||
LDAP_SCOPE_SUBTREE, LDAP_SCOPE_BASE, and LDAP_SCOPE_ONELEVEL.
|
||||
|
||||
bind (yes)
|
||||
Whether or not to bind to the LDAP server. Newer LDAP
|
||||
implementations don't require clients to bind, which saves
|
||||
time. Example:
|
||||
ldapsource_bind = no
|
||||
|
||||
If you do need to bind, you might consider configuring Postfix
|
||||
to connect to the local machine on a port that's an SSL tunnel
|
||||
to your LDAP server. If your LDAP server doesn't natively
|
||||
support SSL, put a tunnel (wrapper, proxy, whatever you want to
|
||||
call it) on that system too. This should prevent the password
|
||||
from traversing the network in the clear.
|
||||
|
||||
bind_dn ("")
|
||||
If you do have to bind, do it with this distinguished name.
|
||||
Example:
|
||||
@@ -85,18 +111,44 @@ Defaults are given in parentheses:
|
||||
|
||||
bind_pw ("")
|
||||
The password for the distinguished name above. If you have to
|
||||
have this, you probably want to make main.cf readable only by
|
||||
use this, you probably want to make main.cf readable only by
|
||||
the Postfix user. Example:
|
||||
ldapsource_bind_pw = postfixpw
|
||||
|
||||
cache (no)
|
||||
Whether to use a client-side cache for the LDAP connection. See
|
||||
ldap_enable_cache(3). It's off by default.
|
||||
|
||||
cache_expiry (30 seconds)
|
||||
If the client-side cache is enabled, cached results will expire
|
||||
after this many seconds.
|
||||
|
||||
cache_size (32768 bytes)
|
||||
If the client-side cache is enabled, this is its size in bytes.
|
||||
|
||||
dereference (0)
|
||||
When to dereference LDAP aliases. (Note that this has nothing
|
||||
do with Postfix aliases.) The permitted values are those
|
||||
legal for the OpenLDAP/UM LDAP implementations:
|
||||
|
||||
0 never
|
||||
1 when searching
|
||||
2 when locating the base object for the search
|
||||
3 always
|
||||
|
||||
See ldap.h or the ldap_open(3) or ldapsearch(1) man pages for
|
||||
more information. And if you're using an LDAP package that has
|
||||
other possible values, please bring it to the attention of the
|
||||
postfix-users@postfix.org mailing list.
|
||||
|
||||
Don't use quotes in these variables; at least, not until the Postfix
|
||||
configuration routines understand how to deal with quoted strings.
|
||||
|
||||
EXAMPLE
|
||||
=======
|
||||
EXAMPLES
|
||||
========
|
||||
|
||||
Here's a basic example. In main.cf, you have these configuration
|
||||
parameters defined:
|
||||
Here's a basic example for using LDAP to look up aliases. In main.cf,
|
||||
you have these configuration parameters defined:
|
||||
|
||||
alias_maps = hash:/etc/aliases, ldap:ldapsource
|
||||
ldapsource_server_host = ldap.my.com
|
||||
@@ -110,6 +162,45 @@ 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.
|
||||
|
||||
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
|
||||
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.
|
||||
|
||||
Other common uses for LDAP lookups include rewriting senders and
|
||||
recipients with Postfix' canonical lookups, for example in order to make
|
||||
mail leaving your site appear to be coming from "First.Last@site.dom"
|
||||
instead of "userid@site.dom".
|
||||
|
||||
NOTES AND THINGS TO THINK ABOUT
|
||||
===============================
|
||||
|
||||
@@ -117,10 +208,11 @@ NOTES AND THINGS TO THINK ABOUT
|
||||
unique, and that not just anyone can specify theirs as postmaster or
|
||||
root, say.
|
||||
|
||||
- An entry can have an arbitrary number of maildrops. Maildrops can also
|
||||
be comma-separated lists of addresses. For example, you could define
|
||||
an entry intended for use as a mailing list that looks like this
|
||||
(Warning! Schema made up just for this example):
|
||||
- An entry can have an arbitrary number of mailacceptinggeneralids or
|
||||
maildrops. Maildrops can also be comma-separated lists of addresses.
|
||||
They will all be found and returned by the lookups. For example, you
|
||||
could define an entry intended for use as a mailing list that looks
|
||||
like this (Warning! Schema made up just for this example):
|
||||
|
||||
dn: cn=Accounting Staff List, dc=my, dc=com
|
||||
cn: Accounting Staff List
|
||||
@@ -135,61 +227,41 @@ NOTES AND THINGS TO THINK ABOUT
|
||||
|
||||
- If you use an LDAP map for lookups other than aliases, you may have to
|
||||
make sure the lookup makes sense. In the case of virtual lookups,
|
||||
maildrops like "|/some/program" are pretty useless. Your query_filter
|
||||
should probably look something like this:
|
||||
maildrops other than mail addresses are pretty useless, because
|
||||
Postfix can't know how to set the ownership for program or file
|
||||
delivery. Your query_filter should probably look something like this:
|
||||
|
||||
virtual_query_filter =
|
||||
(&(mailacceptinggeneralid=%s)(!(|(maildrop="*|*")(maildrop="*:*"))))
|
||||
virtual_query_filter = (&(mailacceptinggeneralid=%s)(!(|(maildrop="*|*")(maildrop="*:*")(maildrop="*/*"))))
|
||||
|
||||
- And for that matter, you may not want users able to specify their
|
||||
maildrops as programs, particularly if they'd be executed on the
|
||||
server. A safer local query_filter could look something like:
|
||||
- And for that matter, even for aliases, you may not want users able to
|
||||
specify their maildrops as programs, includes, etc. This might be
|
||||
particularly pertinent on a "sealed" server where they don't have
|
||||
local UNIX accounts, but exist only in LDAP and Cyrus. You might allow
|
||||
the fun stuff only for directory entries owned by an administrative
|
||||
account:
|
||||
|
||||
local_query_filter = (&(mailacceptinggeneralid=%s)(|(!(maildrop="*|*"))(owner=cn=root, dc=your, dc=com)))
|
||||
local_query_filter = (&(mailacceptinggeneralid=%s)(|(!(maildrop="*|*")(maildrop="*:*")(maildrop="*/*"))(owner=cn=root, dc=your, dc=com)))
|
||||
|
||||
So that if the object had a program as its maildrop and weren't owned
|
||||
by "cn=root" it wouldn't be returned as a valid local user. This will
|
||||
probably require some thought on your part to implement safely,
|
||||
considering the ramifications of includes and programs. You may decide
|
||||
it's not worth the bother to allow any of that nonsense in LDAP
|
||||
lookups, ban it in the query_filter, and keep things like majordomo
|
||||
lists in local alias databases.
|
||||
require some thought on your part to implement safely, considering the
|
||||
ramifications of this type of delivery. You may decide it's not worth
|
||||
the bother to allow any of that nonsense in LDAP lookups, ban it in
|
||||
the query_filter, and keep things like majordomo lists in local alias
|
||||
databases.
|
||||
|
||||
- It's not yet known how all this scales, but LDAP lookups are much more
|
||||
expensive than checking a DB file. If you anticipate a lot of lookups,
|
||||
it may pay to plan your directory to reduce the number of lookups. For
|
||||
instance, rather than having a bunch of objects that serve as aliases
|
||||
to just one object, you could simply add their mailacceptinggeneralids
|
||||
to the target object. This:
|
||||
- LDAP lookups are slower than local DB or DBM lookups. For most sites
|
||||
they won't be a bottleneck, but it's a good idea to know how to tune
|
||||
your directory service.
|
||||
|
||||
dn: uid=firstlast, dc=your, dc=com
|
||||
maildrop: firstlast@mailbox.your.com
|
||||
mailacceptinggeneralid: firstlast
|
||||
mailacceptinggeneralid: First.Last
|
||||
mailacceptinggeneralid: F.Last
|
||||
FEEDBACK
|
||||
========
|
||||
|
||||
Not this:
|
||||
|
||||
dn: uid=firstlast, dc=your, dc=com
|
||||
maildrop: firstlast@mailbox.your.com
|
||||
mailacceptinggeneralid: firstlast
|
||||
|
||||
dn: cn=First.Last, dc=your, dc=com
|
||||
maildrop: firstlast
|
||||
mailacceptinggeneralid: First.Last
|
||||
|
||||
dn: cn=F.Last, dc=your, dc=com
|
||||
maildrop: firstlast
|
||||
mailacceptinggeneralid: F.Last
|
||||
|
||||
Any performance reports will be much appreciated on the postfix-users
|
||||
list.
|
||||
|
||||
UPDATE: At Merit, I've seen over 150000 deliveries per day with no
|
||||
noticeable delay from our OpenLDAP server. I'd now recommend not
|
||||
resorting to the above unless you anticipate much more traffic than
|
||||
that. It makes management of your directory less intuitive, which is
|
||||
probably not worth the reduction in lookups.
|
||||
If you have questions, send them to postfix-users@postfix.org. Please
|
||||
include relevant information about your Postfix setup: LDAP-related
|
||||
output from postconf, which LDAP libraries you built with, and which
|
||||
directory server you're using. If your question involves your directory
|
||||
contents, please include the applicable bits of some directory entries.
|
||||
|
||||
CREDITS
|
||||
=======
|
||||
@@ -198,6 +270,13 @@ 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 contributions have been submitted to move toward better
|
||||
support of Netscape/LDAPv3 libraries, and any other improvements are of
|
||||
course welcome.
|
||||
sources.
|
||||
|
||||
Other contributors, of code or direction or dope slaps, include:
|
||||
|
||||
Manuel Guesdon
|
||||
Carsten Hoeger
|
||||
Keith Stevenson
|
||||
Samuel Tardieu
|
||||
|
||||
And of course Wietse.
|
||||
|
@@ -1,10 +1,11 @@
|
||||
Postfix LMTP support
|
||||
====================
|
||||
|
||||
Postfix LMTP support was initially implemented by Philip A.
|
||||
Prindeville of Mirapoint, Inc., USA, and was modified further by
|
||||
Amos Gouaux of University of Texas at Dallas, Richardson, USA.
|
||||
Wietse then beat the code into its present shape.
|
||||
Postfix LMTP support is based on a modified version of the Postfix
|
||||
SMTP client. The initial version was by Philip A. Prindeville of
|
||||
Mirapoint, Inc., USA. This code was modified further by Amos Gouaux
|
||||
of University of Texas at Dallas, Richardson, USA. Wietse Venema
|
||||
reduced the code to its present shape.
|
||||
|
||||
Postfix can be configured to talk to a local or remote LMTP server.
|
||||
Most people will run the LMTP server on the same machine that runs
|
||||
@@ -27,10 +28,15 @@ Next, put the following in /etc/inetd.conf:
|
||||
|
||||
lmtp stream tcp nowait cyrus /usr/sbin/tcpd /usr/local/cyrus/bin/deliver -e -l
|
||||
|
||||
/usr/sbin/tcpd is from the tcp_wrappers package. You want this
|
||||
to make sure only your mail relay(s) can talk to the LMTP server.
|
||||
Postfix by default enables connection cacheing for delivery via
|
||||
LMTP, so do not worry about the load of wrapping the LMTP port.
|
||||
/usr/sbin/tcpd is from the tcp_wrappers package. You want this to
|
||||
make sure only your mail relay(s) can talk to the LMTP server.
|
||||
Postfix by default does multiple deliveries per LMTP session
|
||||
(connection cacheing), so do not worry about the overhead of
|
||||
tcp_wrapping the LMTP port.
|
||||
|
||||
On some systems, tcpd is built into inetd, so you do not have to
|
||||
specify tcpd in the inetd.conf file. Instead of tcpd/inetd, xinetd
|
||||
can do a similar job of logging and access control.
|
||||
|
||||
Configuring Postfix
|
||||
===================
|
||||
@@ -43,39 +49,45 @@ You may have to add the following entry to /etc/postfix/master.cf:
|
||||
|
||||
lmtp unix - - n - - lmtp
|
||||
|
||||
NOTES: Root privs are not necessary!
|
||||
NOTE: Root privileges are not necessary!
|
||||
|
||||
We put this in /etc/postfix/transport:
|
||||
Put this in /etc/postfix/transport:
|
||||
|
||||
inbox.domain.org lmtp:inbox.domain.org
|
||||
|
||||
Naturally, this means we also have to have in
|
||||
/etc/postfix/main.cf:
|
||||
Naturally, this means we also need in /etc/postfix/main.cf:
|
||||
|
||||
transport_maps = hash:/etc/postfix/transport
|
||||
|
||||
Use the map type of your choice. Use "postconf -m" to find out
|
||||
what map types are supported.
|
||||
Instead of "hash", use the map type of your choice. Some systems
|
||||
use "dbm" instead. Use "postconf -m" to find out what map types
|
||||
are supported.
|
||||
|
||||
Connection cacheing performance
|
||||
===============================
|
||||
Improving connection cacheing performance
|
||||
=========================================
|
||||
|
||||
After delivering a message via LMTP, Postfix will keep the connection
|
||||
open for a while, so that it can be reused for a subsequent delivery.
|
||||
This reduces overhead of LMTP servers that create one process per
|
||||
connection.
|
||||
|
||||
The Postfix LMTP client makes only one connection at a time. For
|
||||
connection cacheing to work well, the Postfix LMTP client has to
|
||||
avoid switching destination hosts. If you have multiple LMTP servers,
|
||||
configure separate master.cf entries for each LMTP server, and
|
||||
configure transport entries that distribute mail domains to the
|
||||
right LMTP servers.
|
||||
For LMTP connection cacheing to work, the Postfix LMTP client should
|
||||
not switch destination hosts. This is no problem when you run only
|
||||
one LMTP server. However, if you run multiple LMTP servers, this
|
||||
can be an issue.
|
||||
|
||||
/etc/postfix/transport:
|
||||
foo.com lmtp1:lmtp1host
|
||||
bar.com lmtp2:lmtp2host
|
||||
You can prevent the LMTP client from switching between servers by
|
||||
configuring a separate mail delivery transport for each LMTP server:
|
||||
|
||||
/etc/postfix/master.cf:
|
||||
lmtp1 unix - - n - - lmtp
|
||||
lmtp2 unix - - n - - lmtp
|
||||
. . . . . . . .
|
||||
|
||||
Configure transport table entries such that the lmtp1 mail delivery
|
||||
transport is used for all deliveries to the LMTP server #1, the
|
||||
mail lmtp2 transport for the LMTP server #2, and so on.
|
||||
|
||||
/etc/postfix/transport:
|
||||
foo.com lmtp1:lmtp1host
|
||||
bar.com lmtp2:lmtp2host
|
||||
|
@@ -4,7 +4,7 @@ OPTS = "CC=$(CC)"
|
||||
DIRS = util global dns master postfix smtpstone sendmail error \
|
||||
pickup cleanup smtpd local lmtp trivial-rewrite qmgr smtp bounce pipe \
|
||||
showq postalias postcat postconf postdrop postkick postlock postlog \
|
||||
postmap postsuper spawn # base64 proto man html
|
||||
postmap postsuper # spawn base64 proto man html
|
||||
|
||||
default: update
|
||||
|
||||
|
@@ -1,37 +1,64 @@
|
||||
Incompatible changes with snapshot-20000506
|
||||
Incompatible changes with snapshot-20000507
|
||||
===========================================
|
||||
|
||||
None.
|
||||
As required by RFC 822, Postfix now inserts a generic destination
|
||||
message header when no destination header is present. The text is
|
||||
specified via the undisclosed_recipients_header configuration
|
||||
parameter (default: "To: undisclosed-recipients:;").
|
||||
|
||||
Major changes with snapshot-20000506
|
||||
The Postfix sendmail command treats a line with only `.' as
|
||||
the end of input, for the sake of sendmail compatibility. To disable
|
||||
this feature, specify the sendmail-compatible `-i' or `-oi' flags
|
||||
on the sendmail command line.
|
||||
|
||||
For the sake of Sendmail compatibility, the Postfix SMTP client
|
||||
skips over SMTP servers that greet with a 4XX or 5XX reply code,
|
||||
treating them as unreachable servers. To obtain prior behavior
|
||||
(4XX=retry, 5XX=bounce), specify "smtp_skip_4xx_greeting = no" and
|
||||
"smtp_skip_5xx_greeting = no".
|
||||
|
||||
The read/write interface underneath VSTREAMs has been extended with
|
||||
parameters that specify a read/write timeout and application context.
|
||||
This should make it easier to plug in encryption modules such as TLS.
|
||||
|
||||
Major changes with snapshot-20000507
|
||||
====================================
|
||||
|
||||
Preliminary LMTP client support with connection cacheing, currently
|
||||
only over TCP sockets. Support for LMTP over UNIX-domain support
|
||||
will be added later. See the LMTP_README file for more details.
|
||||
Better documentation of Postfix lookup tables, including descriptions
|
||||
of how to use regular expressions in Postfix lookup tables.
|
||||
|
||||
Updated mysql and LDAP client code with fixes and improvements.
|
||||
|
||||
In master.cf you can selectively override main.cf configuration
|
||||
parameters, for example: "smtpd -o myhostname=foo.com".
|
||||
|
||||
In main.cf, specify "smtp_bind_address=x.x.x.x" to bind SMTP
|
||||
connections to a specific local interface. Or override the default
|
||||
setting in master.cf with "smtp -o smtp_bind_address=x.x.x.x".
|
||||
For now, you must specify a numeric IP address.
|
||||
|
||||
Preliminary LMTP client support over TCP with connection cacheing.
|
||||
Support for LMTP over UNIX-domain sockets will be added later as
|
||||
an enhancement to the transport table syntax. See the LMTP_README
|
||||
file for more details.
|
||||
|
||||
By the way, LMTP client-side connection cacheing is a good example
|
||||
for how to do the same in the SMTP client.
|
||||
|
||||
Preliminary support for SASL authentication, both in the SMTP server
|
||||
and in the SMTP client. See the SASL_README file for more details.
|
||||
|
||||
The pipe mailer now has a configurable end-of-line attribute.
|
||||
Specify, for example, "pipe ... eol=\r\n" for delivery mechanisms
|
||||
that require CRLF record delimiters.
|
||||
|
||||
The manual pages in sample configuration files now show plain text
|
||||
without TROFF escape sequences.
|
||||
The pipe delivery agent has a configurable end-of-line attribute.
|
||||
Specify "pipe ... eol=\r\n" for delivery mechanisms that require
|
||||
CRLF record delimiters. The eol attribute understands the following
|
||||
C-style escape sequences: \a \b \f \n \r \t \v \nnn \\.
|
||||
|
||||
Incompatible changes with snapshot-20000309
|
||||
===========================================
|
||||
|
||||
As required by RFC 822, Postfix now inserts a generic destination
|
||||
message header when no destination header is present. The text is
|
||||
specified via the undisclosed_recipients_header configuration
|
||||
parameter (default: "To: undisclosed-recipients:;").
|
||||
|
||||
The Postfix sendmail command now treats a line with only `.' as
|
||||
the end of input, for the sake of sendmail compatibility. To disable
|
||||
this feature, specify the sendmail-compatible `-i' or `-oi' flags
|
||||
on the sendmail command line.
|
||||
This release is mainly to have a reference point after reorganizing
|
||||
the cleanup daemon, and before adding some major contributions from
|
||||
other people.
|
||||
|
||||
Major changes with snapshot-20000309
|
||||
====================================
|
||||
@@ -50,7 +77,6 @@ read keys from stdin).
|
||||
The manual pages in Postfix configuration files no longer contain
|
||||
troff formatting codes. The text is now generated from prototype
|
||||
files in a new "proto" subdirectory.
|
||||
|
||||
|
||||
Incompatible changes with postfix-19991231:
|
||||
===========================================
|
||||
|
@@ -3,8 +3,8 @@ WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
|
||||
|
||||
Do not use this code. The Postfix SASL support is based on the
|
||||
Cyrus SASL library, which has not enough documentation about how
|
||||
the software is supposed to work, and it is not clear if the code
|
||||
is safe enough for security-critical applications.
|
||||
the software is supposed to work. It is not clear if the code is
|
||||
safe enough for security-critical applications.
|
||||
|
||||
Postfix+SASL 1.5.5 appears to work on RedHat 6.1 (pwcheck_method
|
||||
set to shadow or sasldb), Solaris 2.7 (pwcheck_method set to shadow
|
||||
@@ -53,19 +53,19 @@ and that the Cyrus SASL libraries are in /usr/local/lib.
|
||||
|
||||
On some systems this generates the necessary Makefile definitions:
|
||||
|
||||
% make tidy # if you have left-over files from a previus build
|
||||
% make tidy # if you have left-over files from a previous build
|
||||
% make makefiles CCARGS=-DUSE_SASL_AUTH" -I/usr/local/include" \
|
||||
AUXLIBS="-L/usr/local/lib -lsasl"
|
||||
|
||||
On Solaris 2.x you need to specify run-time link information,
|
||||
otherwise ld.so will not find the SASL shared library:
|
||||
|
||||
% make tidy # if you have left-over files from a previus build
|
||||
% make tidy # if you have left-over files from a previous build
|
||||
% make makefiles CCARGS=-DUSE_SASL_AUTH" -I/usr/local/include" \
|
||||
AUXLIBS="-L/usr/local/lib -R/usr/local/lib -lsasl"
|
||||
|
||||
Enabling SASL authentication in the SMTP server
|
||||
===============================================
|
||||
Enabling SASL authentication in the Postfix SMTP server
|
||||
=======================================================
|
||||
|
||||
If you installed the Cyrus SASL libraries as per the default, you
|
||||
will have to symlink /usr/lib/sasl -> /usr/local/lib/sasl.
|
||||
@@ -83,18 +83,34 @@ In order to allow mail relaying by authenticated clients:
|
||||
smtpd_recipient_restrictions =
|
||||
permit_mynetworks permit_sasl_authenticated ...
|
||||
|
||||
In /usr/local/lib/sasl/smtpd.conf you need to specify what authentication
|
||||
mechanism the server will support, for example:
|
||||
In /usr/local/lib/sasl/smtpd.conf you need to specify how the server
|
||||
should validate client passwords. For example:
|
||||
|
||||
pwcheck_method: sasldb
|
||||
/usr/local/lib/sasl/smtpd.conf:
|
||||
pwcheck_method: sasldb
|
||||
|
||||
This will use the SASL password file (default: /etc/sasldb), which
|
||||
is maintained with the saslpasswd command. On some systems the
|
||||
saslpasswd command needs to be run multiple times before it stops
|
||||
complaining. The Postfix SMTP server needs read access to the
|
||||
sasldb file - you have to play games with group access permissions.
|
||||
is maintained with the saslpasswd command (part of the Cyrus SASL
|
||||
software). On some poorly-supported systems the saslpasswd command
|
||||
needs to be run multiple times before it stops complaining. The
|
||||
Postfix SMTP server needs read access to the sasldb file - you may
|
||||
have to play games with group access permissions. On RedHat 6.1,
|
||||
SASL 1.5.5 insists on write access to /etc/sasldb.
|
||||
|
||||
To run chrooted with SASL support is an interesting exercise.
|
||||
Instead of the SASL-specific password file you can configure the
|
||||
Postfix SMTP server to validate client passwords against the UNIX
|
||||
shadow password file:
|
||||
|
||||
/usr/local/lib/sasl/smtpd.conf:
|
||||
pwcheck_method: shadow
|
||||
|
||||
However this requires that Postfix has read access to the UNIX shadow
|
||||
password file, which is normally readable only by root. Shadow
|
||||
password support has been found to work for Solaris 2.7 and RedHat
|
||||
6. 1 but not with freeBSD 3.4.
|
||||
|
||||
To run software chrooted with SASL support is an interesting exercise.
|
||||
This is one of the many problems with the present SASL support.
|
||||
|
||||
To test the whole mess, connect to the SMTP server, and you should
|
||||
be able to have a conversation like this:
|
||||
@@ -114,8 +130,8 @@ Instead of dGVzdAB0ZXN0AHRlc3RwYXNz, specify the base64 encoded
|
||||
form of username\0username\0password (the \0 is a null byte). The
|
||||
example above is for a user named `test' with password `testpass'.
|
||||
|
||||
Enabling SASL authentication in the SMTP client
|
||||
===============================================
|
||||
Enabling SASL authentication in the Postfix SMTP client
|
||||
=======================================================
|
||||
|
||||
Turn on client-side SASL authentication, and specify a table with
|
||||
per-host username and password information.
|
||||
@@ -128,6 +144,6 @@ per-host username and password information.
|
||||
foo.com username:password
|
||||
bar.com username
|
||||
|
||||
The SASL password file is opened before the SMTP server enters the
|
||||
optional chroot jail, so there is no need to copy the sasl_passwd
|
||||
DB or DBM file into /var/spool/postfix/etc/postfix.
|
||||
The SASL client password file is opened before the SMTP server
|
||||
enters the optional chroot jail, so you can keep the file in
|
||||
/etc/postfix.
|
||||
|
@@ -358,11 +358,11 @@ static void cleanup_missing_headers(CLEANUP_STATE *state)
|
||||
vstring_sprintf(state->temp2, "%sFrom: %s",
|
||||
state->resent, vstring_str(state->temp1));
|
||||
if (state->fullname && *state->fullname) {
|
||||
vstring_strcat(state->temp2, " (");
|
||||
token = tok822_alloc(TOK822_COMMENT_TEXT, state->fullname);
|
||||
vstring_sprintf(state->temp1, "(%s)", state->fullname);
|
||||
token = tok822_parse(vstring_str(state->temp1));
|
||||
vstring_strcat(state->temp2, " ");
|
||||
tok822_externalize(state->temp2, token, TOK822_STR_NONE);
|
||||
tok822_free(token);
|
||||
vstring_strcat(state->temp2, ")");
|
||||
tok822_free_tree(token);
|
||||
}
|
||||
CLEANUP_OUT_BUF(state, REC_TYPE_NORM, state->temp2);
|
||||
} else if ((state->headers_seen & (1 << (state->resent[0] ?
|
||||
|
@@ -70,7 +70,7 @@ smtp unix - - n - - smtp
|
||||
showq unix n - n - - showq
|
||||
error unix - - n - - error
|
||||
local unix - n n - - local
|
||||
lmtp unix - - n - - lmtp server=localhost
|
||||
lmtp unix - - n - - lmtp
|
||||
cyrus unix - n n - - pipe
|
||||
flags=R user=cyrus argv=/cyrus/bin/deliver -e -m ${extension} ${user}
|
||||
uucp unix - n n - - pipe
|
||||
|
@@ -2,15 +2,24 @@
|
||||
# HERE JUST SERVES AS AN EXAMPLE.
|
||||
#
|
||||
# This file contains example settings of Postfix configuration
|
||||
# parameters that control SASL authentication.
|
||||
# parameters that control SASL authentication for the Postfix
|
||||
# SMTP server and client programs.
|
||||
|
||||
# SMTP SERVER CONTROLS
|
||||
|
||||
# The smtpd_sasl_auth_enable parameter controls whether authentication
|
||||
# is enabled in the Postfix SMTP server.
|
||||
# The smtpd_sasl_auth_enable parameter controls whether SMTP client
|
||||
# authentication is enabled in the Postfix SMTP server. By default,
|
||||
# the Postfix SMTP server does not use authentication.
|
||||
#
|
||||
# If a client is authenticated, then the permit_sasl_authenticated
|
||||
# can be used to permit relay access.
|
||||
# If an SMTP client is authenticated, then the permit_sasl_authenticated
|
||||
# access restriction can be used to permit relay access, like this:
|
||||
#
|
||||
# smtpd_recipient_restrictions = permit_sasl_authenticated, ...
|
||||
#
|
||||
# To reject all SMTP connections from unauthenticated clients,
|
||||
# specify smtpd_delay_reject=yes (which is the default) and use:
|
||||
#
|
||||
# smtpd_client_restrictions = permit_sasl_authenticated
|
||||
#
|
||||
# In order to enable server-side authentication, build Postfix with
|
||||
# SASL support, and install a configuration file /usr/lib/sasl/smtpd.conf
|
||||
@@ -19,15 +28,17 @@
|
||||
# pwcheck_method: sasldb
|
||||
#
|
||||
# or whatever method is suitable for your environment: PAM, shadow,
|
||||
# whatever. If you use sasldb, you can add users with the "saslpasswd"
|
||||
# command that is part of the SASL library. If you use PAM, The PAM
|
||||
# service name for SASL authentication is "smtp", and adding users
|
||||
# depends entirely on how PAM is set up.
|
||||
# etc. If you use sasldb, you can add users with the "saslpasswd"
|
||||
# command that comes with the SASL library. If you configure Postfix
|
||||
# to use PAM, the PAM service name for SASL authentication is "smtp",
|
||||
# and adding users depends entirely on how PAM is set up.
|
||||
#
|
||||
# If you run your SMTP server chrooted, then you need to copy PAM
|
||||
# and/or SASL support libraries and data files into the chroot jail.
|
||||
# That's a lot of files, and it seems not very practical to do so.
|
||||
#
|
||||
smtpd_sasl_auth_enable = yes
|
||||
#smtpd_sasl_auth_enable = yes
|
||||
smtpd_sasl_auth_enable = no
|
||||
|
||||
# The smtpd_sasl_security_options parameter controls what authentication
|
||||
# mechanisms the Postfix SMTP server will offer to the client. The
|
||||
@@ -43,10 +54,10 @@ smtpd_sasl_auth_enable = yes
|
||||
# By default, the Postfix SMTP server accepts plaintext passwords but
|
||||
# not anonymous logins.
|
||||
#
|
||||
# Horror! It appears that clients try authentication methods in the
|
||||
# order as advertised by the server (PLAIN ANONYMOUS CRAM-MD5
|
||||
# ...) which means that if you disable plaintext passwords, clients
|
||||
# will log in anonymously even when they would be able to use CRAM-MD5.
|
||||
# HORROR! It appears that clients try authentication methods in the
|
||||
# order as advertised by the server (e.g., PLAIN ANONYMOUS CRAM-MD5)
|
||||
# which means that if you disable plaintext passwords, clients will
|
||||
# log in anonymously, even when they should be able to use CRAM-MD5.
|
||||
# So, if you disable plaintext logins, disable anonymous logins too.
|
||||
# Postfix treats anonymous login as no authentication.
|
||||
#
|
||||
@@ -56,9 +67,11 @@ smtpd_sasl_security_options = noanonymous
|
||||
# SMTP CLIENT CONTROLS
|
||||
|
||||
# The smtp_sasl_auth_enable parameter controls whether authentication
|
||||
# is enabled in the Postfix SMTP client.
|
||||
# is enabled in the Postfix SMTP client. By default, the Postfix SMTP
|
||||
# client uses no authentication.
|
||||
#
|
||||
smtp_sasl_auth_enable = yes
|
||||
#smtp_sasl_auth_enable = yes
|
||||
smtp_sasl_auth_enable = no
|
||||
|
||||
# The smtp_sasl_password_maps parameter specifies the names of lookup
|
||||
# tables with one username:password entry per remote hostname. If a
|
||||
@@ -66,7 +79,7 @@ smtp_sasl_auth_enable = yes
|
||||
# client will not attempt to authenticate to the remote host.
|
||||
#
|
||||
# The Postfix SMTP client opens the lookup table before going to
|
||||
# chroot jail, so you can keep the password file in /etc/postfix.
|
||||
# chroot jail, so you can leave the password file in /etc/postfix.
|
||||
#
|
||||
smtp_auth_passwd_map = hash:/etc/postfix/saslpass
|
||||
|
||||
|
@@ -33,6 +33,15 @@ fallback_relay =
|
||||
#
|
||||
ignore_mx_lookup_error = no
|
||||
|
||||
# The smtp_bind_address parameter specifies a numerical network
|
||||
# address that the client should bind to when making a connection.
|
||||
# This can be used in the main.cf file, or in the master.cf file,
|
||||
# for example:
|
||||
#
|
||||
# smtp ... smtp -o smtp_bind_address=111.222.333.444
|
||||
#
|
||||
#smtp_bind_address=111.222.333.444
|
||||
|
||||
# The smtp_skip_4xx_greeting parameter controls what happens when
|
||||
# an SMTP server greets us with a 4XX status code. By default, Postfix
|
||||
# backs off. Specify "smtp_skip_4xx_greeting = yes" to move on the
|
||||
|
@@ -8,6 +8,8 @@
|
||||
/*
|
||||
/* void mail_conf_read()
|
||||
/*
|
||||
/* void mail_conf_suck()
|
||||
/*
|
||||
/* void mail_conf_update(name, value)
|
||||
/* const char *name;
|
||||
/* const char *value;
|
||||
@@ -21,9 +23,12 @@
|
||||
/* const char *mail_conf_lookup_eval(name)
|
||||
/* const char *name;
|
||||
/* DESCRIPTION
|
||||
/* mail_conf_read() reads the global Postfix configuration file, and
|
||||
/* mail_conf_suck() reads the global Postfix configuration file, and
|
||||
/* stores its values into a global configuration dictionary.
|
||||
/*
|
||||
/* mail_conf_read() invokes mail_conf_suck() and assigns the values
|
||||
/* to global variables by calling mail_params_init().
|
||||
/*
|
||||
/* The following routines are wrappers around the generic dictionary
|
||||
/* access routines.
|
||||
/*
|
||||
@@ -88,6 +93,14 @@
|
||||
/* mail_conf_read - read global configuration file */
|
||||
|
||||
void mail_conf_read(void)
|
||||
{
|
||||
mail_conf_suck();
|
||||
mail_params_init();
|
||||
}
|
||||
|
||||
/* mail_conf_suck - suck in the global configuration file */
|
||||
|
||||
void mail_conf_suck(void)
|
||||
{
|
||||
char *config_dir;
|
||||
char *path;
|
||||
@@ -107,7 +120,6 @@ void mail_conf_read(void)
|
||||
path = concatenate(var_config_dir, "/", "main.cf", (char *) 0);
|
||||
dict_load_file(CONFIG_DICT, path);
|
||||
myfree(path);
|
||||
mail_params_init();
|
||||
}
|
||||
|
||||
/* mail_conf_eval - expand macros in string */
|
||||
|
@@ -33,6 +33,7 @@
|
||||
* Basic configuration management.
|
||||
*/
|
||||
extern void mail_conf_read(void);
|
||||
extern void mail_conf_suck(void);
|
||||
|
||||
extern void mail_conf_update(const char *, const char *);
|
||||
extern const char *mail_conf_lookup(const char *);
|
||||
|
@@ -136,10 +136,9 @@ int mail_copy(const char *sender, const char *delivered,
|
||||
quote_822_local(buf, sender);
|
||||
if (flags & MAIL_COPY_FROM) {
|
||||
time(&now);
|
||||
vstream_fprintf(dst, "From %s %s", *sender == 0 ?
|
||||
MAIL_ADDR_MAIL_DAEMON :
|
||||
vstring_str(buf),
|
||||
asctime(localtime(&now)));
|
||||
vstream_fprintf(dst, "From %s %.24s%s", *sender == 0 ?
|
||||
MAIL_ADDR_MAIL_DAEMON : vstring_str(buf),
|
||||
asctime(localtime(&now)), eol);
|
||||
}
|
||||
if (flags & MAIL_COPY_RETURN_PATH) {
|
||||
vstream_fprintf(dst, "Return-Path: <%s>%s",
|
||||
|
@@ -609,6 +609,10 @@ extern bool var_skip_quit_resp;
|
||||
#define DEF_SMTP_ALWAYS_EHLO 0
|
||||
extern bool var_smtp_always_ehlo;
|
||||
|
||||
#define VAR_SMTP_BIND_ADDR "smtp_bind_address"
|
||||
#define DEF_SMTP_BIND_ADDR ""
|
||||
extern char *var_smtp_bind_addr;
|
||||
|
||||
/*
|
||||
* SMTP server. The soft error limit determines how many errors an SMTP
|
||||
* client may make before we start to slow down; the hard error limit
|
||||
|
@@ -15,7 +15,7 @@
|
||||
* Version of this program.
|
||||
*/
|
||||
#define VAR_MAIL_VERSION "mail_version"
|
||||
#define DEF_MAIL_VERSION "Snapshot-20000506"
|
||||
#define DEF_MAIL_VERSION "Snapshot-20000507"
|
||||
extern char *var_mail_version;
|
||||
|
||||
/* LICENSE
|
||||
|
@@ -29,7 +29,6 @@
|
||||
#define SMTP_ERR_EOF 1 /* unexpected client disconnect */
|
||||
#define SMTP_ERR_TIME 2 /* time out */
|
||||
|
||||
extern void smtp_jump_setup(VSTREAM *, jmp_buf *);
|
||||
extern void smtp_timeout_setup(VSTREAM *, int);
|
||||
extern void smtp_printf(VSTREAM *, const char *,...);
|
||||
extern int smtp_get(VSTRING *, VSTREAM *, int);
|
||||
|
@@ -99,7 +99,7 @@ distribution list</a>
|
||||
|
||||
<ul>
|
||||
|
||||
<li><a href="#delay">Postfix responds slowly to SMTP connections</a>
|
||||
<li><a href="#delay">Postfix responds slowly to incoming SMTP connections</a>
|
||||
|
||||
<li><a href="#numerical_log">Postfix logs SMTP clients as IP
|
||||
addresses</a>
|
||||
@@ -779,7 +779,7 @@ delivery agent deals with undeliverable mail.
|
||||
|
||||
<hr>
|
||||
|
||||
<a name="delay"><h3>Postfix responds slowly to SMTP connections</h3></a>
|
||||
<a name="delay"><h3>Postfix responds slowly to incoming SMTP connections</h3></a>
|
||||
|
||||
<dl>
|
||||
|
||||
|
@@ -73,36 +73,37 @@ PIPE(8) PIPE(8)
|
||||
|
||||
<b>eol=string</b> (default: <b>\n</b>)
|
||||
The output record delimiter. Typically one would
|
||||
use either <b>\r\n</b> or <b>\n</b>. You can specify the usual C-
|
||||
style backslash escape sequences.
|
||||
use either <b>\r\n</b> or <b>\n</b>. The usual C-style backslash
|
||||
escape sequences are recognized: <b>\a</b> <b>\b</b> <b>\f</b> <b>\n</b> <b>\r</b> <b>\t</b>
|
||||
<b>\v</b> <b>\</b><i>octal</i> and <b>\\</b>.
|
||||
|
||||
<b>argv</b>=<i>command</i>... (required)
|
||||
The command to be executed. This must be specified
|
||||
The command to be executed. This must be specified
|
||||
as the last command attribute. The command is exe-
|
||||
cuted directly, i.e. without interpretation of
|
||||
shell meta characters by a shell command inter-
|
||||
shell meta characters by a shell command inter-
|
||||
preter.
|
||||
|
||||
In the command argument vector, the following
|
||||
macros are recognized and replaced with correspond-
|
||||
ing information from the Postfix queue manager
|
||||
ing information from the Postfix queue manager
|
||||
delivery request:
|
||||
|
||||
<b>${extension</b>}
|
||||
This macro expands to the extension part of
|
||||
a recipient address. For example, with an
|
||||
This macro expands to the extension part of
|
||||
a recipient address. For example, with an
|
||||
address <i>user+foo@domain</i> the extension is
|
||||
<i>foo</i>. A command-line argument that contains
|
||||
<b>${extension</b>} expands into as many command-
|
||||
<i>foo</i>. A command-line argument that contains
|
||||
<b>${extension</b>} expands into as many command-
|
||||
line arguments as there are recipients.
|
||||
|
||||
<b>${mailbox</b>}
|
||||
This macro expands to the complete local
|
||||
part of a recipient address. For example,
|
||||
with an address <i>user+foo@domain</i> the mailbox
|
||||
is <i>user+foo</i>. A command-line argument that
|
||||
contains <b>${mailbox</b>} expands into as many
|
||||
command-line arguments as there are recipi-
|
||||
This macro expands to the complete local
|
||||
part of a recipient address. For example,
|
||||
with an address <i>user+foo@domain</i> the mailbox
|
||||
is <i>user+foo</i>. A command-line argument that
|
||||
contains <b>${mailbox</b>} expands into as many
|
||||
command-line arguments as there are recipi-
|
||||
ents.
|
||||
|
||||
<b>${nexthop</b>}
|
||||
@@ -110,21 +111,20 @@ PIPE(8) PIPE(8)
|
||||
|
||||
<b>${recipient</b>}
|
||||
This macro expands to the complete recipient
|
||||
address. A command-line argument that con-
|
||||
address. A command-line argument that con-
|
||||
tains <b>${recipient</b>} expands into as many com-
|
||||
mand-line arguments as there are recipients.
|
||||
|
||||
<b>${sender</b>}
|
||||
This macro expands to the envelope sender
|
||||
This macro expands to the envelope sender
|
||||
address.
|
||||
|
||||
<b>${user</b>}
|
||||
This macro expands to the username part of a
|
||||
recipient address. For example, with an
|
||||
recipient address. For example, with an
|
||||
address <i>user+foo@domain</i> the username part is
|
||||
<i>user</i>. A command-line argument that contains
|
||||
<b>${user</b>} expands into as many command-line
|
||||
arguments as there are recipients.
|
||||
<b>${user</b>} expands into as many command-line
|
||||
|
||||
|
||||
|
||||
@@ -137,60 +137,60 @@ PIPE(8) PIPE(8)
|
||||
PIPE(8) PIPE(8)
|
||||
|
||||
|
||||
In addition to the form ${<i>name</i>}, the forms $<i>name</i> and
|
||||
$(<i>name</i>) are also recognized. Specify <b>$$</b> where a single <b>$</b>
|
||||
arguments as there are recipients.
|
||||
|
||||
In addition to the form ${<i>name</i>}, the forms $<i>name</i> and
|
||||
$(<i>name</i>) are also recognized. Specify <b>$$</b> where a single <b>$</b>
|
||||
is wanted.
|
||||
|
||||
<b>DIAGNOSTICS</b>
|
||||
Command exit status codes are expected to follow the con-
|
||||
Command exit status codes are expected to follow the con-
|
||||
ventions defined in <<b>sysexits.h</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.
|
||||
|
||||
<b>SECURITY</b>
|
||||
This program needs a dual personality 1) to access the
|
||||
private Postfix queue and IPC mechanisms, and 2) to exe-
|
||||
This program needs a dual personality 1) to access the
|
||||
private Postfix queue and IPC mechanisms, and 2) to exe-
|
||||
cute external commands as the specified user. It is there-
|
||||
fore security sensitive.
|
||||
|
||||
<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>
|
||||
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>mail</b><i>_</i><b>owner</b>
|
||||
The process privileges used while not running an
|
||||
The process privileges used while not running an
|
||||
external command.
|
||||
|
||||
<b>Resource</b> <b>controls</b>
|
||||
In the text below, <i>transport</i> is the first field in a <b>mas-</b>
|
||||
In the text below, <i>transport</i> is the first field in a <b>mas-</b>
|
||||
<b>ter.cf</b> entry.
|
||||
|
||||
<i>transport_</i><b>destination</b><i>_</i><b>concurrency</b><i>_</i><b>limit</b>
|
||||
Limit the number of parallel deliveries to the same
|
||||
destination, for delivery via the named <i>transport</i>.
|
||||
The default limit is taken from the <b>default</b><i>_</i><b>desti-</b>
|
||||
<b>nation</b><i>_</i><b>concurrency</b><i>_</i><b>limit</b> parameter. The limit is
|
||||
destination, for delivery via the named <i>transport</i>.
|
||||
The default limit is taken from the <b>default</b><i>_</i><b>desti-</b>
|
||||
<b>nation</b><i>_</i><b>concurrency</b><i>_</i><b>limit</b> parameter. The limit is
|
||||
enforced by the Postfix queue manager.
|
||||
|
||||
<i>transport_</i><b>destination</b><i>_</i><b>recipient</b><i>_</i><b>limit</b>
|
||||
Limit the number of recipients per message deliv-
|
||||
ery, for delivery via the named <i>transport</i>. The
|
||||
default limit is taken from the <b>default</b><i>_</i><b>destina-</b>
|
||||
<b>tion</b><i>_</i><b>recipient</b><i>_</i><b>limit</b> parameter. The limit is
|
||||
Limit the number of recipients per message deliv-
|
||||
ery, for delivery via the named <i>transport</i>. The
|
||||
default limit is taken from the <b>default</b><i>_</i><b>destina-</b>
|
||||
<b>tion</b><i>_</i><b>recipient</b><i>_</i><b>limit</b> parameter. The limit is
|
||||
enforced by the Postfix queue manager.
|
||||
|
||||
<i>transport_</i><b>time</b><i>_</i><b>limit</b>
|
||||
Limit the time for delivery to external command,
|
||||
for delivery via the named <b>transport</b>. The default
|
||||
limit is taken from the <b>command</b><i>_</i><b>time</b><i>_</i><b>limit</b> parame-
|
||||
ter. The limit is enforced by the Postfix queue
|
||||
manager.
|
||||
|
||||
Limit the time for delivery to external command,
|
||||
for delivery via the named <b>transport</b>. The default
|
||||
limit is taken from the <b>command</b><i>_</i><b>time</b><i>_</i><b>limit</b> parame-
|
||||
ter. The limit is enforced by the Postfix queue
|
||||
|
||||
|
||||
|
||||
@@ -203,6 +203,8 @@ PIPE(8) PIPE(8)
|
||||
PIPE(8) PIPE(8)
|
||||
|
||||
|
||||
manager.
|
||||
|
||||
<b>SEE</b> <b>ALSO</b>
|
||||
<a href="bounce.8.html">bounce(8)</a> non-delivery status reports
|
||||
<a href="master.8.html">master(8)</a> process manager
|
||||
@@ -210,7 +212,7 @@ PIPE(8) PIPE(8)
|
||||
syslogd(8) system logging
|
||||
|
||||
<b>LICENSE</b>
|
||||
The Secure Mailer license must be distributed with this
|
||||
The Secure Mailer license must be distributed with this
|
||||
software.
|
||||
|
||||
<b>AUTHOR(S)</b>
|
||||
@@ -255,8 +257,6 @@ PIPE(8) PIPE(8)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@@ -144,15 +144,19 @@ SMTP(8) SMTP(8)
|
||||
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
|
||||
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 <i>name</i>:<i>password</i> entries.
|
||||
No entry for a host means no attempt to authenti-
|
||||
Lookup tables with per-host <i>name</i>:<i>password</i> entries.
|
||||
No entry for a host means no attempt to authenti-
|
||||
cate.
|
||||
|
||||
<b>smtp</b><i>_</i><b>sasl</b><i>_</i><b>security</b><i>_</i><b>options</b>
|
||||
@@ -176,21 +180,17 @@ SMTP(8) SMTP(8)
|
||||
<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
|
||||
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.
|
||||
When no connection can be made within the deadline,
|
||||
the SMTP client tries the next address on the mail
|
||||
exchanger list.
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -203,20 +203,24 @@ SMTP(8) SMTP(8)
|
||||
SMTP(8) SMTP(8)
|
||||
|
||||
|
||||
When no connection can be made 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 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>
|
||||
@@ -224,7 +228,7 @@ SMTP(8) SMTP(8)
|
||||
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>
|
||||
@@ -233,11 +237,11 @@ SMTP(8) SMTP(8)
|
||||
<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>
|
||||
@@ -247,12 +251,24 @@ SMTP(8) SMTP(8)
|
||||
syslogd(8) system logging
|
||||
|
||||
<b>LICENSE</b>
|
||||
The Secure Mailer license must be distributed with this
|
||||
The Secure Mailer license must be distributed with this
|
||||
software.
|
||||
|
||||
<b>AUTHOR(S)</b>
|
||||
Wietse Venema
|
||||
IBM T.J. Watson Research
|
||||
|
||||
|
||||
|
||||
4
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
SMTP(8) SMTP(8)
|
||||
|
||||
|
||||
P.O. Box 704
|
||||
Yorktown Heights, NY 10598, USA
|
||||
|
||||
@@ -260,7 +276,57 @@ SMTP(8) SMTP(8)
|
||||
|
||||
|
||||
|
||||
4
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
5
|
||||
|
||||
|
||||
</pre> </body> </html>
|
||||
|
@@ -56,7 +56,7 @@ depend: $(MAKES)
|
||||
$(CC) -E $(DEFS) $(INCL) $$i | sed -n -e '/^# *1 *"\([^"]*\)".*/{' \
|
||||
-e 's//'`echo $$i|sed 's/c$$/o/'`': \1/' -e 'p' -e '}'; \
|
||||
done) | grep -v '[.][o][:][ ][/]' >$$$$ && mv $$$$ Makefile.in
|
||||
@make -f Makefile.in Makefile
|
||||
@$(EXPORT) make -f Makefile.in Makefile 1>&2
|
||||
|
||||
# do not edit below this line - it is generated by 'make depend'
|
||||
lmtp.o: lmtp.c
|
||||
|
@@ -1,50 +0,0 @@
|
||||
README.local
|
||||
|
||||
This file describes how to use the lmtp service for local delivery.
|
||||
You'll need postfix-19991231-pl04 or later for this to work because
|
||||
it relies on the "spawn" service.
|
||||
|
||||
Configure your Postfix as follows:
|
||||
|
||||
/etc/postfix/master.cf:
|
||||
|
||||
#local unix - n n - - local
|
||||
local unix - - n - - lmtp
|
||||
serv=unix:private/lmtpd
|
||||
lmtpd unix - n n - - spawn
|
||||
user=cyrus:cyrus argv=/usr/local/cyrus/bin/deliver -e -l
|
||||
|
||||
|
||||
First, we comment out the original "local" service and define
|
||||
a new one based on the "lmtp" client. The "serv=" argument says
|
||||
what LMTP server we're to talk to, in this case the "lmtpd"
|
||||
service.
|
||||
|
||||
The `-l' option to deliver tells it to go into LMTP mode, and the
|
||||
`-e' tells it to use the duplicate delivery database, which is
|
||||
required in order to use the vacation features of Sieve, the
|
||||
filtering language in Cyrus 1.6.X.
|
||||
|
||||
A note about spawn, this is a new experimental service. The
|
||||
makefile-patch included with this bundle will add spawn to the
|
||||
compile targets. However, you may need to check that it actually
|
||||
gets installed.
|
||||
|
||||
A note about local delivery and the number of recipients. Starting
|
||||
with postfix-19991231-pl04, it is now possible to specify the
|
||||
maximum number of recipients per message for local delivery. By
|
||||
default, this is set to 1 as follows:
|
||||
|
||||
local_destination_recipient_limit = 1
|
||||
|
||||
You can set it to zero (means no limit) or, safer, set it to some
|
||||
reasonable number so that your machine doesn't risk running out of
|
||||
resources on a message with an inordinate number of recipients.
|
||||
|
||||
Why is this of interest? Well, if a message contains multiple
|
||||
recipients, and all these recipients happen to be on the same Cyrus
|
||||
partition, then recent (1.6.X) releases of deliver will hard link
|
||||
the message to each recipient instead of each recipient getting a
|
||||
copy. So you'll probably want to set the above mail.cf value to
|
||||
something reasonable to take advantage of this feature in Cyrus.
|
||||
|
@@ -1,6 +0,0 @@
|
||||
# script to compare common code between smtp and lmtp
|
||||
|
||||
sed '
|
||||
s/SMTP/LMTP/g
|
||||
s/smtp/lmtp/g
|
||||
' $*
|
@@ -381,6 +381,12 @@ static void lmtp_service(VSTREAM *client_stream, char *unused_service, char **ar
|
||||
DELIVER_REQUEST *request;
|
||||
int status;
|
||||
|
||||
/*
|
||||
* Sanity check. This service takes no command-line arguments.
|
||||
*/
|
||||
if (argv[0])
|
||||
msg_fatal("unexpected command-line argument: %s", argv[0]);
|
||||
|
||||
/*
|
||||
* This routine runs whenever a client connects to the UNIX-domain socket
|
||||
* dedicated to remote LMTP delivery service. What we see below is a
|
||||
|
@@ -59,8 +59,9 @@ corresponding group ID is used instead of the group ID of
|
||||
\fIusername\fR.
|
||||
.IP "\fBeol=string\fR (default: \fB\en\fR)"
|
||||
The output record delimiter. Typically one would use either
|
||||
\fB\er\en\fR or \fB\en\fR. You can specify the usual C-style
|
||||
backslash escape sequences.
|
||||
\fB\er\en\fR or \fB\en\fR. The usual C-style backslash escape
|
||||
sequences are recognized: \fB\ea \eb \ef \en \er \et \ev
|
||||
\e\fIoctal\fR and \fB\e\e\fR.
|
||||
.IP "\fBargv\fR=\fIcommand\fR... (required)"
|
||||
The command to be executed. This must be specified as the
|
||||
last command attribute.
|
||||
|
@@ -110,6 +110,8 @@ Skip servers that greet us with a 4xx status code.
|
||||
Skip servers that greet us with a 5xx status code.
|
||||
.IP \fBsmtp_skip_quit_response\fR
|
||||
Do not wait for the server response after sending QUIT.
|
||||
.IP \fBsmtp_bind_address\fR
|
||||
Numerical network address to bind to when making a connection.
|
||||
.SH "Authentication controls"
|
||||
.IP \fBsmtp_enable_sasl_auth\fR
|
||||
Enable per-session authentication as per RFC 2554 (SASL).
|
||||
|
@@ -395,7 +395,68 @@ NORETURN multi_server_main(int argc, char **argv, MULTI_SERVER_FN service,...)
|
||||
* Initialize from the configuration file. Allow command-line options to
|
||||
* override compiled-in defaults or configured parameter values.
|
||||
*/
|
||||
mail_conf_read();
|
||||
mail_conf_suck();
|
||||
|
||||
/*
|
||||
* Pick up policy settings from master process. Shut up error messages to
|
||||
* stderr, because no-one is going to see them.
|
||||
*/
|
||||
opterr = 0;
|
||||
while ((c = GETOPT(argc, argv, "cDi:lm:n:o:s:St:uv")) > 0) {
|
||||
switch (c) {
|
||||
case 'c':
|
||||
root_dir = "setme";
|
||||
break;
|
||||
case 'D':
|
||||
debug_me = 1;
|
||||
break;
|
||||
case 'i':
|
||||
mail_conf_update(VAR_MAX_IDLE, optarg);
|
||||
break;
|
||||
case 'l':
|
||||
alone = 1;
|
||||
break;
|
||||
case 'm':
|
||||
mail_conf_update(VAR_MAX_USE, optarg);
|
||||
break;
|
||||
case 'n':
|
||||
service_name = optarg;
|
||||
break;
|
||||
case 'o':
|
||||
if ((oval = split_at(optarg, '=')) == 0)
|
||||
oval = "";
|
||||
mail_conf_update(optarg, oval);
|
||||
break;
|
||||
case 's':
|
||||
if ((socket_count = atoi(optarg)) <= 0)
|
||||
msg_fatal("invalid socket_count: %s", optarg);
|
||||
break;
|
||||
case 'S':
|
||||
stream = VSTREAM_IN;
|
||||
break;
|
||||
case 'u':
|
||||
user_name = "setme";
|
||||
break;
|
||||
case 't':
|
||||
transport = optarg;
|
||||
break;
|
||||
case 'v':
|
||||
msg_verbose++;
|
||||
break;
|
||||
default:
|
||||
msg_fatal("invalid option: %c", c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize generic parameters.
|
||||
*/
|
||||
mail_params_init();
|
||||
|
||||
/*
|
||||
* Application-specific initialization.
|
||||
*/
|
||||
va_start(ap, service);
|
||||
while ((key = va_arg(ap, int)) != 0) {
|
||||
switch (key) {
|
||||
@@ -432,59 +493,10 @@ NORETURN multi_server_main(int argc, char **argv, MULTI_SERVER_FN service,...)
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
/*
|
||||
* Pick up policy settings from master process. Shut up error messages to
|
||||
* stderr, because no-one is going to see them.
|
||||
*/
|
||||
opterr = 0;
|
||||
while ((c = GETOPT(argc, argv, "cDi:lm:n:o:s:St:uv")) > 0) {
|
||||
switch (c) {
|
||||
case 'c':
|
||||
root_dir = var_queue_dir;
|
||||
break;
|
||||
case 'D':
|
||||
debug_me = 1;
|
||||
break;
|
||||
case 'i':
|
||||
if ((var_idle_limit = atoi(optarg)) <= 0)
|
||||
msg_fatal("invalid max_idle time: %s", optarg);
|
||||
break;
|
||||
case 'l':
|
||||
alone = 1;
|
||||
break;
|
||||
case 'm':
|
||||
if ((var_use_limit = atoi(optarg)) <= 0)
|
||||
msg_fatal("invalid max_use: %s", optarg);
|
||||
break;
|
||||
case 'n':
|
||||
service_name = optarg;
|
||||
break;
|
||||
case 'o':
|
||||
mail_conf_update(optarg,
|
||||
(oval = split_at(optarg, '=')) ? oval : "");
|
||||
mail_params_init(); /* XXX */
|
||||
break;
|
||||
case 's':
|
||||
if ((socket_count = atoi(optarg)) <= 0)
|
||||
msg_fatal("invalid socket_count: %s", optarg);
|
||||
break;
|
||||
case 'S':
|
||||
stream = VSTREAM_IN;
|
||||
break;
|
||||
case 'u':
|
||||
user_name = var_mail_owner;
|
||||
break;
|
||||
case 't':
|
||||
transport = optarg;
|
||||
break;
|
||||
case 'v':
|
||||
msg_verbose++;
|
||||
break;
|
||||
default:
|
||||
msg_fatal("invalid option: %c", c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (root_dir)
|
||||
root_dir = var_queue_dir;
|
||||
if (user_name)
|
||||
user_name = var_mail_owner;
|
||||
|
||||
/*
|
||||
* If not connected to stdin, stdin must not be a terminal.
|
||||
|
@@ -367,7 +367,68 @@ NORETURN single_server_main(int argc, char **argv, SINGLE_SERVER_FN service,...)
|
||||
* Initialize from the configuration file. Allow command-line options to
|
||||
* override compiled-in defaults or configured parameter values.
|
||||
*/
|
||||
mail_conf_read();
|
||||
mail_conf_suck();
|
||||
|
||||
/*
|
||||
* Pick up policy settings from master process. Shut up error messages to
|
||||
* stderr, because no-one is going to see them.
|
||||
*/
|
||||
opterr = 0;
|
||||
while ((c = GETOPT(argc, argv, "cDi:lm:n:o:s:St:uv")) > 0) {
|
||||
switch (c) {
|
||||
case 'c':
|
||||
root_dir = "setme";
|
||||
break;
|
||||
case 'D':
|
||||
debug_me = 1;
|
||||
break;
|
||||
case 'i':
|
||||
mail_conf_update(VAR_MAX_IDLE, optarg);
|
||||
break;
|
||||
case 'l':
|
||||
alone = 1;
|
||||
break;
|
||||
case 'm':
|
||||
mail_conf_update(VAR_MAX_USE, optarg);
|
||||
break;
|
||||
case 'n':
|
||||
service_name = optarg;
|
||||
break;
|
||||
case 'o':
|
||||
if ((oval = split_at(optarg, '=')) == 0)
|
||||
oval = "";
|
||||
mail_conf_update(optarg, oval);
|
||||
break;
|
||||
case 's':
|
||||
if ((socket_count = atoi(optarg)) <= 0)
|
||||
msg_fatal("invalid socket_count: %s", optarg);
|
||||
break;
|
||||
case 'S':
|
||||
stream = VSTREAM_IN;
|
||||
break;
|
||||
case 'u':
|
||||
user_name = "setme";
|
||||
break;
|
||||
case 't':
|
||||
transport = optarg;
|
||||
break;
|
||||
case 'v':
|
||||
msg_verbose++;
|
||||
break;
|
||||
default:
|
||||
msg_fatal("invalid option: %c", c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize generic parameters.
|
||||
*/
|
||||
mail_params_init();
|
||||
|
||||
/*
|
||||
* Application-specific initialization.
|
||||
*/
|
||||
va_start(ap, service);
|
||||
while ((key = va_arg(ap, int)) != 0) {
|
||||
switch (key) {
|
||||
@@ -404,59 +465,10 @@ NORETURN single_server_main(int argc, char **argv, SINGLE_SERVER_FN service,...)
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
/*
|
||||
* Pick up policy settings from master process. Shut up error messages to
|
||||
* stderr, because no-one is going to see them.
|
||||
*/
|
||||
opterr = 0;
|
||||
while ((c = GETOPT(argc, argv, "cDi:lm:n:o:s:St:uv")) > 0) {
|
||||
switch (c) {
|
||||
case 'c':
|
||||
root_dir = var_queue_dir;
|
||||
break;
|
||||
case 'D':
|
||||
debug_me = 1;
|
||||
break;
|
||||
case 'i':
|
||||
if ((var_idle_limit = atoi(optarg)) <= 0)
|
||||
msg_fatal("invalid max_idle time: %s", optarg);
|
||||
break;
|
||||
case 'l':
|
||||
alone = 1;
|
||||
break;
|
||||
case 'm':
|
||||
if ((var_use_limit = atoi(optarg)) <= 0)
|
||||
msg_fatal("invalid max_use: %s", optarg);
|
||||
break;
|
||||
case 'n':
|
||||
service_name = optarg;
|
||||
break;
|
||||
case 'o':
|
||||
mail_conf_update(optarg,
|
||||
(oval = split_at(optarg, '=')) ? oval : "");
|
||||
mail_params_init(); /* XXX */
|
||||
break;
|
||||
case 's':
|
||||
if ((socket_count = atoi(optarg)) <= 0)
|
||||
msg_fatal("invalid socket_count: %s", optarg);
|
||||
break;
|
||||
case 'S':
|
||||
stream = VSTREAM_IN;
|
||||
break;
|
||||
case 'u':
|
||||
user_name = var_mail_owner;
|
||||
break;
|
||||
case 't':
|
||||
transport = optarg;
|
||||
break;
|
||||
case 'v':
|
||||
msg_verbose++;
|
||||
break;
|
||||
default:
|
||||
msg_fatal("invalid option: %c", c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (root_dir)
|
||||
root_dir = var_queue_dir;
|
||||
if (user_name)
|
||||
user_name = var_mail_owner;
|
||||
|
||||
/*
|
||||
* If not connected to stdin, stdin must not be a terminal.
|
||||
|
@@ -267,7 +267,6 @@ static void trigger_server_accept_local(int unused_event, char *context)
|
||||
int time_left = 0;
|
||||
int fd;
|
||||
|
||||
|
||||
if (msg_verbose)
|
||||
msg_info("%s: trigger arrived", myname);
|
||||
|
||||
@@ -368,7 +367,68 @@ NORETURN trigger_server_main(int argc, char **argv, TRIGGER_SERVER_FN service,..
|
||||
* Initialize from the configuration file. Allow command-line options to
|
||||
* override compiled-in defaults or configured parameter values.
|
||||
*/
|
||||
mail_conf_read();
|
||||
mail_conf_suck();
|
||||
|
||||
/*
|
||||
* Pick up policy settings from master process. Shut up error messages to
|
||||
* stderr, because no-one is going to see them.
|
||||
*/
|
||||
opterr = 0;
|
||||
while ((c = GETOPT(argc, argv, "cDi:lm:n:o:s:St:uv")) > 0) {
|
||||
switch (c) {
|
||||
case 'c':
|
||||
root_dir = "setme";
|
||||
break;
|
||||
case 'D':
|
||||
debug_me = 1;
|
||||
break;
|
||||
case 'i':
|
||||
mail_conf_update(VAR_MAX_IDLE, optarg);
|
||||
break;
|
||||
case 'l':
|
||||
alone = 1;
|
||||
break;
|
||||
case 'm':
|
||||
mail_conf_update(VAR_MAX_USE, optarg);
|
||||
break;
|
||||
case 'n':
|
||||
service_name = optarg;
|
||||
break;
|
||||
case 'o':
|
||||
if ((oval = split_at(optarg, '=')) == 0)
|
||||
oval = "";
|
||||
mail_conf_update(optarg, oval);
|
||||
break;
|
||||
case 's':
|
||||
if ((socket_count = atoi(optarg)) <= 0)
|
||||
msg_fatal("invalid socket_count: %s", optarg);
|
||||
break;
|
||||
case 'S':
|
||||
stream = VSTREAM_IN;
|
||||
break;
|
||||
case 't':
|
||||
transport = optarg;
|
||||
break;
|
||||
case 'u':
|
||||
user_name = "setme";
|
||||
break;
|
||||
case 'v':
|
||||
msg_verbose++;
|
||||
break;
|
||||
default:
|
||||
msg_fatal("invalid option: %c", c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize generic parameters.
|
||||
*/
|
||||
mail_params_init();
|
||||
|
||||
/*
|
||||
* Application-specific initialization.
|
||||
*/
|
||||
va_start(ap, service);
|
||||
while ((key = va_arg(ap, int)) != 0) {
|
||||
switch (key) {
|
||||
@@ -405,59 +465,10 @@ NORETURN trigger_server_main(int argc, char **argv, TRIGGER_SERVER_FN service,..
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
/*
|
||||
* Pick up policy settings from master process. Shut up error messages to
|
||||
* stderr, because no-one is going to see them.
|
||||
*/
|
||||
opterr = 0;
|
||||
while ((c = GETOPT(argc, argv, "cDi:lm:n:o:s:St:uv")) > 0) {
|
||||
switch (c) {
|
||||
case 'c':
|
||||
root_dir = var_queue_dir;
|
||||
break;
|
||||
case 'D':
|
||||
debug_me = 1;
|
||||
break;
|
||||
case 'i':
|
||||
if ((var_idle_limit = atoi(optarg)) <= 0)
|
||||
msg_fatal("invalid max_idle time: %s", optarg);
|
||||
break;
|
||||
case 'l':
|
||||
alone = 1;
|
||||
break;
|
||||
case 'm':
|
||||
if ((var_use_limit = atoi(optarg)) <= 0)
|
||||
msg_fatal("invalid max_use: %s", optarg);
|
||||
break;
|
||||
case 'n':
|
||||
service_name = optarg;
|
||||
break;
|
||||
case 'o':
|
||||
mail_conf_update(optarg,
|
||||
(oval = split_at(optarg, '=')) ? oval : "");
|
||||
mail_params_init(); /* XXX */
|
||||
break;
|
||||
case 's':
|
||||
if ((socket_count = atoi(optarg)) <= 0)
|
||||
msg_fatal("invalid socket_count: %s", optarg);
|
||||
break;
|
||||
case 'S':
|
||||
stream = VSTREAM_IN;
|
||||
break;
|
||||
case 't':
|
||||
transport = optarg;
|
||||
break;
|
||||
case 'u':
|
||||
user_name = var_mail_owner;
|
||||
break;
|
||||
case 'v':
|
||||
msg_verbose++;
|
||||
break;
|
||||
default:
|
||||
msg_fatal("invalid option: %c", c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (root_dir)
|
||||
root_dir = var_queue_dir;
|
||||
if (user_name)
|
||||
user_name = var_mail_owner;
|
||||
|
||||
/*
|
||||
* If not connected to stdin, stdin must not be a terminal.
|
||||
|
@@ -51,8 +51,9 @@
|
||||
/* \fIusername\fR.
|
||||
/* .IP "\fBeol=string\fR (default: \fB\en\fR)"
|
||||
/* The output record delimiter. Typically one would use either
|
||||
/* \fB\er\en\fR or \fB\en\fR. You can specify the usual C-style
|
||||
/* backslash escape sequences.
|
||||
/* \fB\er\en\fR or \fB\en\fR. The usual C-style backslash escape
|
||||
/* sequences are recognized: \fB\ea \eb \ef \en \er \et \ev
|
||||
/* \e\fIoctal\fR and \fB\e\e\fR.
|
||||
/* .IP "\fBargv\fR=\fIcommand\fR... (required)"
|
||||
/* The command to be executed. This must be specified as the
|
||||
/* last command attribute.
|
||||
@@ -479,7 +480,7 @@ static void get_service_attr(PIPE_ATTR *attr, char **argv)
|
||||
* eol=string
|
||||
*/
|
||||
else if (strncasecmp("eol=", *argv, sizeof("eol=") - 1) == 0) {
|
||||
unescape(attr->eol, *argv + sizeof("eol=") -1);
|
||||
unescape(attr->eol, *argv + sizeof("eol=") - 1);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@@ -94,6 +94,8 @@
|
||||
/* Skip servers that greet us with a 5xx status code.
|
||||
/* .IP \fBsmtp_skip_quit_response\fR
|
||||
/* Do not wait for the server response after sending QUIT.
|
||||
/* .IP \fBsmtp_bind_address\fR
|
||||
/* Numerical network address to bind to when making a connection.
|
||||
/* .SH "Authentication controls"
|
||||
/* .IP \fBsmtp_enable_sasl_auth\fR
|
||||
/* Enable per-session authentication as per RFC 2554 (SASL).
|
||||
@@ -236,6 +238,7 @@ int var_smtp_always_ehlo;
|
||||
char *var_smtp_sasl_opts;
|
||||
char *var_smtp_sasl_passwd;
|
||||
bool var_smtp_sasl_enable;
|
||||
char *var_smtp_bind_addr;
|
||||
|
||||
/*
|
||||
* Global variables. smtp_errno is set by the address lookup routines and by
|
||||
@@ -383,6 +386,7 @@ int main(int argc, char **argv)
|
||||
VAR_ERROR_RCPT, DEF_ERROR_RCPT, &var_error_rcpt, 1, 0,
|
||||
VAR_SMTP_SASL_PASSWD, DEF_SMTP_SASL_PASSWD, &var_smtp_sasl_passwd, 0, 0,
|
||||
VAR_SMTP_SASL_OPTS, DEF_SMTP_SASL_OPTS, &var_smtp_sasl_opts, 0, 0,
|
||||
VAR_SMTP_BIND_ADDR, DEF_SMTP_BIND_ADDR, &var_smtp_bind_addr, 0, 0,
|
||||
0,
|
||||
};
|
||||
static CONFIG_INT_TABLE int_table[] = {
|
||||
|
@@ -91,6 +91,10 @@
|
||||
#include <strings.h>
|
||||
#endif
|
||||
|
||||
#ifndef INADDR_NONE
|
||||
#define INADDR_NONE 0xffffff
|
||||
#endif
|
||||
|
||||
/* Utility library. */
|
||||
|
||||
#include <msg.h>
|
||||
@@ -149,13 +153,26 @@ static SMTP_SESSION *smtp_connect_addr(DNS_RR *addr, unsigned port,
|
||||
if ((sock = socket(sin.sin_family, SOCK_STREAM, 0)) < 0)
|
||||
msg_fatal("%s: socket: %m", myname);
|
||||
|
||||
/*
|
||||
* Allow the sysadmin to specify the source address, for example, as "-o
|
||||
* smtp_bind_address=x.x.x.x" in the master.cf file.
|
||||
*/
|
||||
if (*var_smtp_bind_addr) {
|
||||
sin.sin_addr.s_addr = inet_addr(var_smtp_bind_addr);
|
||||
if (sin.sin_addr.s_addr == INADDR_NONE)
|
||||
msg_fatal("%s: bad %s parameter: %s",
|
||||
myname, VAR_SMTP_BIND_ADDR, var_smtp_bind_addr);
|
||||
if (bind(sock, (struct sockaddr *) & sin, sizeof(sin)) < 0)
|
||||
msg_warn("%s: bind %s: %m", myname, inet_ntoa(sin.sin_addr));
|
||||
if (msg_verbose)
|
||||
msg_info("%s: bind %s", myname, inet_ntoa(sin.sin_addr));
|
||||
}
|
||||
|
||||
/*
|
||||
* When running as a virtual host, bind to the virtual interface so that
|
||||
* the mail appears to come from the "right" machine address.
|
||||
*/
|
||||
addr_list = own_inet_addr_list();
|
||||
if (addr_list->used == 1) {
|
||||
sin.sin_port = 0;
|
||||
else if ((addr_list = own_inet_addr_list())->used == 1) {
|
||||
memcpy((char *) &sin.sin_addr, addr_list->addrs, sizeof(sin.sin_addr));
|
||||
inaddr = ntohl(sin.sin_addr.s_addr);
|
||||
if (!IN_CLASSA(inaddr)
|
||||
|
@@ -201,7 +201,7 @@ static int smtp_sasl_get_passwd(sasl_conn_t *conn, void *context,
|
||||
if ((*psecret = (sasl_secret_t *) malloc(sizeof(sasl_secret_t) + len)) == 0)
|
||||
return (SASL_NOMEM);
|
||||
(*psecret)->len = len;
|
||||
strcpy((*psecret)->data, state->sasl_passwd);
|
||||
memcpy((*psecret)->data, state->sasl_passwd, len + 1);
|
||||
|
||||
return (SASL_OK);
|
||||
}
|
||||
|
@@ -423,7 +423,7 @@ static int ehlo_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
||||
smtpd_chat_reply(state, "250-SIZE");
|
||||
smtpd_chat_reply(state, "250-ETRN");
|
||||
#ifdef USE_SASL_AUTH
|
||||
if (var_smtpd_sasl_enable)
|
||||
if (SMTPD_STAND_ALONE(state) == 0 && var_smtpd_sasl_enable)
|
||||
smtpd_chat_reply(state, "250-AUTH %s", state->sasl_mechanism_list);
|
||||
#endif
|
||||
smtpd_chat_reply(state, "250 8BITMIME");
|
||||
@@ -535,7 +535,8 @@ static char *extract_addr(SMTPD_STATE *state, SMTPD_TOKEN *arg,
|
||||
}
|
||||
|
||||
/*
|
||||
* Report trouble. Log a warning only if we are going to sleep+reject.
|
||||
* Report trouble. Log a warning only if we are going to sleep+reject so
|
||||
* that attackers can't flood our logfiles.
|
||||
*/
|
||||
if ((naddr < 1 && !allow_empty_addr)
|
||||
|| naddr > 1
|
||||
@@ -615,7 +616,9 @@ static int mail_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
||||
if ((state->msg_size = off_cvt_string(arg + 5)) < 0)
|
||||
state->msg_size = 0;
|
||||
#ifdef USE_SASL_AUTH
|
||||
} else if (var_smtpd_sasl_enable && strncasecmp(arg, "AUTH=", 5) == 0) {
|
||||
} else if (SMTPD_STAND_ALONE(state) == 0
|
||||
&& var_smtpd_sasl_enable
|
||||
&& strncasecmp(arg, "AUTH=", 5) == 0) {
|
||||
if ((err = smtpd_sasl_mail_opt(state, arg + 5)) != 0) {
|
||||
smtpd_chat_reply(state, "%s", err);
|
||||
return (-1);
|
||||
@@ -1089,7 +1092,9 @@ static int quit_cmd(SMTPD_STATE *state, int unused_argc, SMTPD_TOKEN *unused_arg
|
||||
}
|
||||
|
||||
/*
|
||||
* The table of all SMTP commands that we know.
|
||||
* The table of all SMTP commands that we know. Set the junk limit flag on
|
||||
* any command that can be repeated an arbitrary number of times without
|
||||
* triggering a tarpit delay of some sort.
|
||||
*/
|
||||
typedef struct SMTPD_CMD {
|
||||
char *name;
|
||||
@@ -1100,8 +1105,8 @@ typedef struct SMTPD_CMD {
|
||||
#define SMTPD_CMD_FLAG_LIMIT (1<<0) /* limit usage */
|
||||
|
||||
static SMTPD_CMD smtpd_cmd_table[] = {
|
||||
"HELO", helo_cmd, 0,
|
||||
"EHLO", ehlo_cmd, 0,
|
||||
"HELO", helo_cmd, SMTPD_CMD_FLAG_LIMIT,
|
||||
"EHLO", ehlo_cmd, SMTPD_CMD_FLAG_LIMIT,
|
||||
|
||||
#ifdef USE_SASL_AUTH
|
||||
"AUTH", smtpd_sasl_auth_cmd, 0,
|
||||
|
@@ -147,11 +147,14 @@ void smtpd_chat_reply(SMTPD_STATE *state, char *format,...)
|
||||
* that abort the connection and go into a connect-error-disconnect loop;
|
||||
* sleep-on-anything slows down clients that make an excessive number of
|
||||
* errors within a session.
|
||||
*
|
||||
* Flush unsent output before sleeping. Pipelined error responses could
|
||||
* result in client-side timeouts.
|
||||
*/
|
||||
if (state->error_count > var_smtpd_soft_erlim)
|
||||
sleep(state->error_count), vstream_fflush(state->client);
|
||||
vstream_fflush(state->client), sleep(state->error_count);
|
||||
else if (STR(state->buffer)[0] == '4' || STR(state->buffer)[0] == '5')
|
||||
sleep(var_smtpd_err_sleep), vstream_fflush(state->client);
|
||||
vstream_fflush(state->client), sleep(var_smtpd_err_sleep);
|
||||
|
||||
smtp_fputs(STR(state->buffer), LEN(state->buffer), state->client);
|
||||
}
|
||||
|
@@ -173,7 +173,7 @@ void smtpd_sasl_initialize(void)
|
||||
|
||||
void smtpd_sasl_connect(SMTPD_STATE *state)
|
||||
{
|
||||
int sasl_mechanism_count;
|
||||
unsigned sasl_mechanism_count;
|
||||
sasl_security_properties_t sec_props;
|
||||
|
||||
/*
|
||||
|
@@ -123,7 +123,7 @@ int smtpd_sasl_auth_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
||||
smtpd_chat_reply(state, "503 Error: send HELO/EHLO first");
|
||||
return (-1);
|
||||
}
|
||||
if (!var_smtpd_sasl_enable) {
|
||||
if (SMTPD_STAND_ALONE(state) || !var_smtpd_sasl_enable) {
|
||||
state->error_mask |= MAIL_ERROR_PROTOCOL;
|
||||
smtpd_chat_reply(state, "503 Error: authentication not enabled");
|
||||
return (-1);
|
||||
|
@@ -1,3 +1,4 @@
|
||||
|
||||
/*++
|
||||
/* NAME
|
||||
/* dict_ldap 3
|
||||
@@ -39,6 +40,8 @@
|
||||
/* .IP \fIldapsource_\fRresult_attribute
|
||||
/* The attribute returned by the search, in which to find
|
||||
/* RFC822 addresses, for example \fImaildrop\fR.
|
||||
/* .IP \fIldapsource_\fRscope
|
||||
/* LDAP search scope: sub, base, or one.
|
||||
/* .IP \fIldapsource_\fRbind
|
||||
/* Whether or not to bind to the server -- LDAP v3 implementations don't
|
||||
/* require it, which saves some overhead.
|
||||
@@ -46,12 +49,16 @@
|
||||
/* If you must bind to the server, do it with this distinguished name ...
|
||||
/* .IP \fIldapsource_\fRbind_pw
|
||||
/* \&... and this password.
|
||||
/* BUGS
|
||||
/* Thrice a year, needed or not.
|
||||
/* .IP \fIldapsource_\fRcache
|
||||
/* Whether or not to turn on client-side caching.
|
||||
/* .IP \fIldapsource_\fRcache_expiry
|
||||
/* If you do cache results, expire them after this many seconds.
|
||||
/* .IP \fIldapsource_\fRcache_size
|
||||
/* The cache size in bytes. Does nothing if the cache is off, of course.
|
||||
/* .IP \fIldapsource_\fRdereference
|
||||
/* How to handle LDAP aliases. See ldap.h or ldap_open(3) man page.
|
||||
/* SEE ALSO
|
||||
/* dict(3) generic dictionary manager
|
||||
/* DIAGNOSTICS
|
||||
/* Warnings: unable to connect to server, unable to bind to server.
|
||||
/* AUTHOR(S)
|
||||
/* Prabhat K Singh
|
||||
/* VSNL, Bombay, India.
|
||||
@@ -63,7 +70,7 @@
|
||||
/* Yorktown Heights, NY 10532, USA
|
||||
/*
|
||||
/* John Hensley
|
||||
/* stormroll@yahoo.com
|
||||
/* roll@ic.net
|
||||
/*
|
||||
/*--*/
|
||||
|
||||
@@ -75,8 +82,6 @@
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <setjmp.h>
|
||||
#include <stdlib.h>
|
||||
@@ -91,19 +96,16 @@
|
||||
#include "dict.h"
|
||||
#include "dict_ldap.h"
|
||||
|
||||
/* Global library. */
|
||||
|
||||
#include "../global/mail_conf.h" /* XXX Fixme. */
|
||||
|
||||
/*
|
||||
* structure containing all the configuration parameters for a given
|
||||
* LDAP source, plus its connection handle
|
||||
* Structure containing all the configuration parameters for a given
|
||||
* LDAP source, plus its connection handle.
|
||||
*/
|
||||
typedef struct {
|
||||
DICT dict; /* generic member */
|
||||
char *ldapsource;
|
||||
char *server_host;
|
||||
int server_port;
|
||||
int scope;
|
||||
char *search_base;
|
||||
char *query_filter;
|
||||
char *result_attribute;
|
||||
@@ -111,12 +113,16 @@ typedef struct {
|
||||
char *bind_dn;
|
||||
char *bind_pw;
|
||||
int timeout;
|
||||
int cache;
|
||||
long cache_expiry;
|
||||
long cache_size;
|
||||
int dereference;
|
||||
LDAP *ld;
|
||||
} DICT_LDAP;
|
||||
|
||||
/*
|
||||
* LDAP connection timeout support.
|
||||
*/
|
||||
/*
|
||||
* LDAP connection timeout support.
|
||||
*/
|
||||
static jmp_buf env;
|
||||
|
||||
static void dict_ldap_timeout(int unused_sig)
|
||||
@@ -124,6 +130,103 @@ static void dict_ldap_timeout(int unused_sig)
|
||||
longjmp(env, 1);
|
||||
}
|
||||
|
||||
/* Establish a connection to the LDAP server. */
|
||||
static int dict_ldap_connect(DICT_LDAP *dict_ldap)
|
||||
{
|
||||
char *myname = "dict_ldap_connect";
|
||||
void (*saved_alarm) (int);
|
||||
int rc = 0;
|
||||
|
||||
dict_errno = 0;
|
||||
|
||||
if (msg_verbose)
|
||||
msg_info("%s: Connecting to server %s", myname,
|
||||
dict_ldap->server_host);
|
||||
|
||||
if ((saved_alarm = signal(SIGALRM, dict_ldap_timeout)) == SIG_ERR) {
|
||||
msg_warn("%s: Error setting signal handler for open timeout: %m",
|
||||
myname);
|
||||
dict_errno = DICT_ERR_RETRY;
|
||||
return (-1);
|
||||
}
|
||||
alarm(dict_ldap->timeout);
|
||||
if (setjmp(env) == 0)
|
||||
dict_ldap->ld = ldap_open(dict_ldap->server_host,
|
||||
(int) dict_ldap->server_port);
|
||||
alarm(0);
|
||||
|
||||
if (signal(SIGALRM, saved_alarm) == SIG_ERR) {
|
||||
msg_warn("%s: Error resetting signal handler after open: %m",
|
||||
myname);
|
||||
dict_errno = DICT_ERR_RETRY;
|
||||
return (-1);
|
||||
}
|
||||
if (dict_ldap->ld == NULL) {
|
||||
msg_warn("%s: Unable to connect to LDAP server %s",
|
||||
myname, dict_ldap->server_host);
|
||||
dict_errno = DICT_ERR_RETRY;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Configure alias dereferencing for this connection. Thanks to Mike
|
||||
* Mattice for this.
|
||||
*/
|
||||
dict_ldap->ld->ld_deref = dict_ldap->dereference;
|
||||
|
||||
/*
|
||||
* If this server requires a bind, do so. Thanks to Sam Tardieu for
|
||||
* noticing that the original bind call was broken.
|
||||
*/
|
||||
if (dict_ldap->bind) {
|
||||
if (msg_verbose)
|
||||
msg_info("%s: Binding to server %s as dn %s",
|
||||
myname, dict_ldap->server_host, dict_ldap->bind_dn);
|
||||
|
||||
rc = ldap_bind_s(dict_ldap->ld, dict_ldap->bind_dn,
|
||||
dict_ldap->bind_pw, LDAP_AUTH_SIMPLE);
|
||||
|
||||
if (rc != LDAP_SUCCESS) {
|
||||
msg_warn("%s: Unable to bind to server %s as %s: %d (%s)",
|
||||
myname, dict_ldap->server_host, dict_ldap->bind_dn,
|
||||
rc, ldap_err2string(rc));
|
||||
dict_errno = DICT_ERR_RETRY;
|
||||
return (-1);
|
||||
}
|
||||
if (msg_verbose)
|
||||
msg_info("%s: Successful bind to server %s as %s ",
|
||||
myname, dict_ldap->server_host, dict_ldap->bind_dn);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set up client-side caching if it's configured.
|
||||
*/
|
||||
if (dict_ldap->cache) {
|
||||
if (msg_verbose)
|
||||
msg_info
|
||||
("%s: Enabling %ld-byte cache for %s with %ld-second expiry",
|
||||
myname, dict_ldap->cache_size, dict_ldap->ldapsource,
|
||||
dict_ldap->cache_expiry);
|
||||
|
||||
rc = ldap_enable_cache(dict_ldap->ld, dict_ldap->cache_expiry,
|
||||
dict_ldap->cache_size);
|
||||
if (rc != LDAP_SUCCESS) {
|
||||
msg_warn
|
||||
("%s: Unable to configure cache for %s: %d (%s) -- continuing",
|
||||
myname, dict_ldap->ldapsource, rc, ldap_err2string(rc));
|
||||
} else {
|
||||
if (msg_verbose)
|
||||
msg_info("%s: Caching enabled for %s",
|
||||
myname, dict_ldap->ldapsource);
|
||||
}
|
||||
}
|
||||
if (msg_verbose)
|
||||
msg_info("%s: Cached connection handle for LDAP source %s",
|
||||
myname, dict_ldap->ldapsource);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* dict_ldap_lookup - find database entry */
|
||||
|
||||
static const char *dict_ldap_lookup(DICT *dict, const char *name)
|
||||
@@ -136,85 +239,45 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
|
||||
struct timeval tv;
|
||||
VSTRING *escaped_name = 0,
|
||||
*filter_buf = 0;
|
||||
char **attr_values;
|
||||
char *result_attributes[1],
|
||||
**attr_values;
|
||||
long i = 0;
|
||||
int rc = 0;
|
||||
void (*saved_alarm) (int);
|
||||
char *sub,
|
||||
*end;
|
||||
|
||||
dict_errno = 0;
|
||||
|
||||
/*
|
||||
* Initialize.
|
||||
* Initialize the result holder.
|
||||
*/
|
||||
if (result == 0)
|
||||
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.
|
||||
*/
|
||||
if (dict_ldap->ld == NULL) {
|
||||
if (msg_verbose)
|
||||
msg_info("%s: no existing connection for ldapsource %s, reopening",
|
||||
myname, dict_ldap->ldapsource);
|
||||
msg_info
|
||||
("%s: No existing connection for ldapsource %s, reopening",
|
||||
myname, dict_ldap->ldapsource);
|
||||
|
||||
if ((saved_alarm = signal(SIGALRM, dict_ldap_timeout)) == SIG_ERR) {
|
||||
msg_warn("%s: error setting signal handler for open timeout: %m", myname);
|
||||
dict_errno = DICT_ERR_RETRY;
|
||||
dict_ldap_connect(dict_ldap);
|
||||
|
||||
/*
|
||||
* if dict_ldap_connect() set dict_errno, abort.
|
||||
*/
|
||||
if (dict_errno)
|
||||
return (0);
|
||||
}
|
||||
if (msg_verbose)
|
||||
msg_info("%s: connecting to server %s", myname,
|
||||
dict_ldap->server_host);
|
||||
} else if (msg_verbose)
|
||||
msg_info("%s: Using existing connection for ldapsource %s",
|
||||
myname, dict_ldap->ldapsource);
|
||||
|
||||
alarm(dict_ldap->timeout);
|
||||
if (setjmp(env) == 0)
|
||||
dict_ldap->ld = ldap_open(dict_ldap->server_host,
|
||||
(int) dict_ldap->server_port);
|
||||
alarm(0);
|
||||
|
||||
if (signal(SIGALRM, saved_alarm) == SIG_ERR) {
|
||||
msg_warn("%s: error resetting signal handler after open: %m", myname);
|
||||
dict_errno = DICT_ERR_RETRY;
|
||||
return (0);
|
||||
}
|
||||
if (msg_verbose)
|
||||
msg_info("%s: after ldap_open", myname);
|
||||
|
||||
if (dict_ldap->ld == NULL) {
|
||||
msg_warn("%s: Unable to contact LDAP server %s",
|
||||
myname, dict_ldap->server_host);
|
||||
dict_errno = DICT_ERR_RETRY;
|
||||
return (0);
|
||||
} else {
|
||||
|
||||
/*
|
||||
* If this server requires a bind, do so.
|
||||
*/
|
||||
if (dict_ldap->bind) {
|
||||
if (msg_verbose)
|
||||
msg_info("%s: about to bind to server %s as dn %s", myname,
|
||||
dict_ldap->server_host, dict_ldap->bind_dn);
|
||||
|
||||
rc = ldap_bind_s(dict_ldap->ld, dict_ldap->bind_dn,
|
||||
dict_ldap->bind_pw, LDAP_AUTH_SIMPLE);
|
||||
if (rc != LDAP_SUCCESS) {
|
||||
msg_warn("%s: Unable to bind to server %s as %s (%d -- %s): ", myname, dict_ldap->server_host, dict_ldap->bind_dn, rc, ldap_err2string(rc));
|
||||
dict_errno = DICT_ERR_RETRY;
|
||||
return (0);
|
||||
} else {
|
||||
if (msg_verbose)
|
||||
msg_info("%s: Successful bind to server %s as %s (%d -- %s): ", myname, dict_ldap->server_host, dict_ldap->bind_dn, rc, ldap_err2string(rc));
|
||||
}
|
||||
}
|
||||
if (msg_verbose)
|
||||
msg_info("%s: cached connection handle for LDAP source %s",
|
||||
myname, dict_ldap->ldapsource);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Prepare the query.
|
||||
@@ -226,14 +289,17 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
|
||||
|
||||
/*
|
||||
* If any characters in the supplied address should be escaped per RFC
|
||||
* 2254, do so.
|
||||
* 2254, do so. Thanks to Keith Stevenson and Wietse. And thanks to
|
||||
* Samuel Tardieu for spotting that wildcard searches were being done in
|
||||
* the first place, which prompted the ill-conceived lookup_wildcards
|
||||
* parameter and then this more comprehensive mechanism.
|
||||
*/
|
||||
|
||||
end = (char *) name + strlen((char *) name);
|
||||
sub = (char *) strpbrk((char *) name, "*()\\\0");
|
||||
if (sub && sub != end) {
|
||||
if (msg_verbose)
|
||||
msg_info("%s: found character(s) in %s that must be escaped", myname, name);
|
||||
msg_info("%s: Found character(s) in %s that must be escaped",
|
||||
myname, name);
|
||||
for (sub = (char *) name; sub != end; sub++) {
|
||||
switch (*sub) {
|
||||
case '*':
|
||||
@@ -256,19 +322,27 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
|
||||
}
|
||||
}
|
||||
if (msg_verbose)
|
||||
msg_info("%s: after escaping, it's %s", myname, vstring_str(escaped_name));
|
||||
msg_info("%s: After escaping, it's %s", myname,
|
||||
vstring_str(escaped_name));
|
||||
} else
|
||||
vstring_strcpy(escaped_name, (char *) name);
|
||||
|
||||
/* Does the supplied query_filter even include a substitution? */
|
||||
if (strstr(dict_ldap->query_filter, "%s") == NULL) {
|
||||
/* No, log the fact and continue. */
|
||||
msg_warn("%s: fixed query_filter %s is probably useless", myname,
|
||||
/*
|
||||
* Does the supplied query_filter even include a substitution?
|
||||
*/
|
||||
if ((char *) strstr(dict_ldap->query_filter, "%s") == NULL) {
|
||||
|
||||
/*
|
||||
* No, log the fact and continue.
|
||||
*/
|
||||
msg_warn("%s: Fixed query_filter %s is probably useless", myname,
|
||||
dict_ldap->query_filter);
|
||||
vstring_strcpy(filter_buf, dict_ldap->query_filter);
|
||||
} else {
|
||||
|
||||
/* Yes, replace all instances of %s with the address to look up. */
|
||||
/*
|
||||
* Yes, replace all instances of %s with the address to look up.
|
||||
*/
|
||||
sub = dict_ldap->query_filter;
|
||||
end = sub + strlen(dict_ldap->query_filter);
|
||||
while (sub < end) {
|
||||
@@ -279,7 +353,9 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
|
||||
*/
|
||||
if (*(sub) == '%') {
|
||||
if ((sub + 1) != end && *(sub + 1) != 's')
|
||||
msg_warn("%s: invalid lookup substitution format '%%%c'!", myname, *(sub + 1));
|
||||
msg_warn
|
||||
("%s: Invalid lookup substitution format '%%%c'!",
|
||||
myname, *(sub + 1));
|
||||
vstring_strcat(filter_buf, vstring_str(escaped_name));
|
||||
sub++;
|
||||
} else
|
||||
@@ -288,31 +364,46 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
|
||||
}
|
||||
}
|
||||
|
||||
/* On to the search. */
|
||||
/*
|
||||
* On to the search.
|
||||
*/
|
||||
if (msg_verbose)
|
||||
msg_info("%s: searching with filter %s", myname,
|
||||
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,
|
||||
LDAP_SCOPE_SUBTREE,
|
||||
dict_ldap->scope,
|
||||
vstring_str(filter_buf),
|
||||
0, 0, &tv, &res)) == LDAP_SUCCESS) {
|
||||
result_attributes,
|
||||
0, &tv, &res)) == LDAP_SUCCESS) {
|
||||
|
||||
/*
|
||||
* Search worked; extract the requested result_attribute.
|
||||
*/
|
||||
if (msg_verbose)
|
||||
msg_info("%s: search found %d matches", myname,
|
||||
msg_info("%s: Search found %d match(es)", myname,
|
||||
ldap_count_entries(dict_ldap->ld, res));
|
||||
|
||||
/* There could have been lots of hits. */
|
||||
for (entry = ldap_first_entry(dict_ldap->ld, res); entry != NULL; entry = ldap_next_entry(dict_ldap->ld, entry)) {
|
||||
/*
|
||||
* There could have been lots of hits.
|
||||
*/
|
||||
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. */
|
||||
/*
|
||||
* 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);
|
||||
msg_warn("%s: Entry doesn't have any values for %s",
|
||||
myname, dict_ldap->result_attribute);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -326,11 +417,20 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
|
||||
}
|
||||
ldap_value_free(attr_values);
|
||||
}
|
||||
if (dict_ldap->ld->ld_errno != LDAP_SUCCESS)
|
||||
msg_warn
|
||||
("%s: Had some trouble with entries returned by search: %s",
|
||||
myname, ldap_err2string(dict_ldap->ld->ld_errno));
|
||||
if (msg_verbose)
|
||||
msg_info("%s: search returned: %s", myname, vstring_str(result));
|
||||
msg_info("%s: Search returned %s", myname,
|
||||
VSTRING_LEN(result) >
|
||||
0 ? vstring_str(result) : "nothing");
|
||||
} else {
|
||||
/* Rats. That didn't work. */
|
||||
msg_warn("%s: search error %d: %s ", myname, rc,
|
||||
|
||||
/*
|
||||
* Rats. The search didn't work.
|
||||
*/
|
||||
msg_warn("%s: Search error %d: %s ", myname, rc,
|
||||
ldap_err2string(rc));
|
||||
|
||||
/*
|
||||
@@ -340,11 +440,15 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
|
||||
ldap_unbind(dict_ldap->ld);
|
||||
dict_ldap->ld = NULL;
|
||||
|
||||
/* And tell the caller to try again later. */
|
||||
/*
|
||||
* And tell the caller to try again later.
|
||||
*/
|
||||
dict_errno = DICT_ERR_RETRY;
|
||||
}
|
||||
|
||||
/* Cleanup. */
|
||||
/*
|
||||
* Cleanup.
|
||||
*/
|
||||
if (res != 0)
|
||||
ldap_msgfree(res);
|
||||
if (filter_buf != 0)
|
||||
@@ -358,7 +462,7 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
|
||||
static void dict_ldap_update(DICT *dict, const char *unused_name,
|
||||
const char *unused_value)
|
||||
{
|
||||
msg_fatal("dict_ldap_update: operation not implemented");
|
||||
msg_fatal("dict_ldap_update: Operation not implemented");
|
||||
}
|
||||
|
||||
/* dict_ldap_close - disassociate from data base */
|
||||
@@ -389,7 +493,7 @@ DICT *dict_ldap_open(const char *ldapsource, int dummy, int dict_flags)
|
||||
DICT_LDAP *dict_ldap;
|
||||
VSTRING *config_param;
|
||||
int rc = 0;
|
||||
void (*saved_alarm) (int);
|
||||
char *scope;
|
||||
|
||||
dict_ldap = (DICT_LDAP *) mymalloc(sizeof(*dict_ldap));
|
||||
dict_ldap->dict.lookup = dict_ldap_lookup;
|
||||
@@ -399,7 +503,7 @@ DICT *dict_ldap_open(const char *ldapsource, int dummy, int dict_flags)
|
||||
dict_ldap->dict.flags = dict_flags | DICT_FLAG_FIXED;
|
||||
|
||||
if (msg_verbose)
|
||||
msg_info("%s: using LDAP source %s", myname, ldapsource);
|
||||
msg_info("%s: Using LDAP source %s", myname, ldapsource);
|
||||
|
||||
dict_ldap->ldapsource = mystrdup(ldapsource);
|
||||
|
||||
@@ -424,16 +528,53 @@ DICT *dict_ldap_open(const char *ldapsource, int dummy, int dict_flags)
|
||||
msg_info("%s: %s is %d", myname, vstring_str(config_param),
|
||||
dict_ldap->server_port);
|
||||
|
||||
/*
|
||||
* Scope handling thanks to Carsten Hoeger of SuSE.
|
||||
*/
|
||||
vstring_sprintf(config_param, "%s_scope", ldapsource);
|
||||
scope =
|
||||
(char *) get_mail_conf_str(vstring_str(config_param), "sub", 0, 0);
|
||||
|
||||
if (strcasecmp(scope, "one") == 0) {
|
||||
dict_ldap->scope = LDAP_SCOPE_ONELEVEL;
|
||||
if (msg_verbose)
|
||||
msg_info("%s: %s is LDAP_SCOPE_ONELEVEL", myname,
|
||||
vstring_str(config_param));
|
||||
|
||||
} else if (strcasecmp(scope, "base") == 0) {
|
||||
dict_ldap->scope = LDAP_SCOPE_BASE;
|
||||
if (msg_verbose)
|
||||
msg_info("%s: %s is LDAP_SCOPE_BASE", myname,
|
||||
vstring_str(config_param));
|
||||
|
||||
} else {
|
||||
dict_ldap->scope = LDAP_SCOPE_SUBTREE;
|
||||
if (msg_verbose)
|
||||
msg_info("%s: %s is LDAP_SCOPE_SUBTREE", myname,
|
||||
vstring_str(config_param));
|
||||
|
||||
}
|
||||
|
||||
myfree(scope);
|
||||
|
||||
vstring_sprintf(config_param, "%s_search_base", ldapsource);
|
||||
dict_ldap->search_base =
|
||||
mystrdup((char *) get_mail_conf_str(vstring_str(config_param), "", 0, 0));
|
||||
dict_ldap->search_base = 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),
|
||||
dict_ldap->search_base);
|
||||
|
||||
/* get configured value of "ldapsource_timeout"; default to 10 */
|
||||
/*
|
||||
* get configured value of "ldapsource_timeout"; default to 10 seconds
|
||||
*
|
||||
* Thanks to Manuel Guesdon for spotting that this wasn't really getting
|
||||
* set.
|
||||
*/
|
||||
vstring_sprintf(config_param, "%s_timeout", ldapsource);
|
||||
dict_ldap->timeout = get_mail_conf_int(vstring_str(config_param), 10, 0, 0);
|
||||
dict_ldap->timeout =
|
||||
get_mail_conf_int(vstring_str(config_param), 10, 0, 0);
|
||||
if (msg_verbose)
|
||||
msg_info("%s: %s is %d", myname, vstring_str(config_param),
|
||||
dict_ldap->timeout);
|
||||
@@ -441,7 +582,8 @@ DICT *dict_ldap_open(const char *ldapsource, int dummy, int dict_flags)
|
||||
vstring_sprintf(config_param, "%s_query_filter", ldapsource);
|
||||
dict_ldap->query_filter =
|
||||
mystrdup((char *) get_mail_conf_str(vstring_str(config_param),
|
||||
"(mailacceptinggeneralid=%s)", 0, 0));
|
||||
"(mailacceptinggeneralid=%s)",
|
||||
0, 0));
|
||||
if (msg_verbose)
|
||||
msg_info("%s: %s is %s", myname, vstring_str(config_param),
|
||||
dict_ldap->query_filter);
|
||||
@@ -454,87 +596,104 @@ 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->result_attribute);
|
||||
|
||||
/* get configured value of "ldapsource_bind"; default to true */
|
||||
/*
|
||||
* get configured value of "ldapsource_bind"; default to true
|
||||
*/
|
||||
vstring_sprintf(config_param, "%s_bind", ldapsource);
|
||||
dict_ldap->bind = get_mail_conf_bool(vstring_str(config_param), 1);
|
||||
if (msg_verbose)
|
||||
msg_info("%s: %s is %d", myname, vstring_str(config_param),
|
||||
dict_ldap->bind);
|
||||
|
||||
/* get configured value of "ldapsource_bind_dn"; default to "" */
|
||||
/*
|
||||
* get configured value of "ldapsource_bind_dn"; default to ""
|
||||
*/
|
||||
vstring_sprintf(config_param, "%s_bind_dn", ldapsource);
|
||||
dict_ldap->bind_dn =
|
||||
mystrdup((char *) get_mail_conf_str(vstring_str(config_param), "", 0, 0));
|
||||
dict_ldap->bind_dn = 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),
|
||||
dict_ldap->bind_dn);
|
||||
|
||||
/* get configured value of "ldapsource_bind_pw"; default to "" */
|
||||
/*
|
||||
* get configured value of "ldapsource_bind_pw"; default to ""
|
||||
*/
|
||||
vstring_sprintf(config_param, "%s_bind_pw", ldapsource);
|
||||
dict_ldap->bind_pw =
|
||||
mystrdup((char *) get_mail_conf_str(vstring_str(config_param), "", 0, 0));
|
||||
dict_ldap->bind_pw = 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),
|
||||
dict_ldap->bind_pw);
|
||||
|
||||
/*
|
||||
* establish the connection to the LDAP server
|
||||
* get configured value of "ldapsource_cache"; default to false
|
||||
*/
|
||||
|
||||
vstring_sprintf(config_param, "%s_cache", ldapsource);
|
||||
dict_ldap->cache = get_mail_conf_bool(vstring_str(config_param), 0);
|
||||
if (msg_verbose)
|
||||
msg_info("%s: connecting to server %s", myname,
|
||||
dict_ldap->server_host);
|
||||
msg_info("%s: %s is %d", myname, vstring_str(config_param),
|
||||
dict_ldap->cache);
|
||||
|
||||
if ((saved_alarm = signal(SIGALRM, dict_ldap_timeout)) == SIG_ERR) {
|
||||
msg_warn("%s: error setting signal handler for open timeout: %m", myname);
|
||||
dict_errno = DICT_ERR_RETRY;
|
||||
/*
|
||||
* get configured value of "ldapsource_cache_expiry"; default to 30
|
||||
* seconds
|
||||
*/
|
||||
vstring_sprintf(config_param, "%s_cache_expiry", ldapsource);
|
||||
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),
|
||||
dict_ldap->cache_expiry);
|
||||
|
||||
/*
|
||||
* get configured value of "ldapsource_cache_size"; default to 32k
|
||||
*/
|
||||
vstring_sprintf(config_param, "%s_cache_size", ldapsource);
|
||||
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),
|
||||
dict_ldap->cache_size);
|
||||
|
||||
/*
|
||||
* Alias dereferencing suggested by Mike Mattice.
|
||||
*/
|
||||
vstring_sprintf(config_param, "%s_dereference", ldapsource);
|
||||
dict_ldap->dereference = get_mail_conf_int(vstring_str(config_param), 0, 0,
|
||||
0);
|
||||
|
||||
/*
|
||||
* Make sure only valid options for alias dereferencing are used.
|
||||
*/
|
||||
if (dict_ldap->dereference < 0 || dict_ldap->dereference > 3) {
|
||||
msg_warn("%s: Unrecognized value %d specified for %s; using 0",
|
||||
myname, dict_ldap->dereference, vstring_str(config_param));
|
||||
dict_ldap->dereference = 0;
|
||||
}
|
||||
if (msg_verbose)
|
||||
msg_info("%s: %s is %d", myname, vstring_str(config_param),
|
||||
dict_ldap->dereference);
|
||||
|
||||
dict_ldap_connect(dict_ldap);
|
||||
|
||||
/*
|
||||
* if dict_ldap_connect() set dict_errno, free dict_ldap and abort.
|
||||
*/
|
||||
if (dict_errno) {
|
||||
if (dict_ldap->ld)
|
||||
ldap_unbind(dict_ldap->ld);
|
||||
|
||||
myfree((char *) dict_ldap);
|
||||
return (0);
|
||||
}
|
||||
alarm(dict_ldap->timeout);
|
||||
if (setjmp(env) == 0)
|
||||
dict_ldap->ld = ldap_open(dict_ldap->server_host,
|
||||
(int) dict_ldap->server_port);
|
||||
alarm(0);
|
||||
|
||||
if (signal(SIGALRM, saved_alarm) == SIG_ERR) {
|
||||
msg_warn("%s: error resetting signal handler after open: %m", myname);
|
||||
dict_errno = DICT_ERR_RETRY;
|
||||
return (0);
|
||||
}
|
||||
if (dict_ldap->ld == NULL) {
|
||||
msg_warn("%s: Unable to contact LDAP server %s",
|
||||
myname, dict_ldap->server_host);
|
||||
dict_errno = DICT_ERR_RETRY;
|
||||
return (0);
|
||||
} else {
|
||||
|
||||
if (msg_verbose)
|
||||
msg_info("%s: after ldap_open", myname);
|
||||
|
||||
/*
|
||||
* If this server requires a bind, do so.
|
||||
*/
|
||||
if (dict_ldap->bind) {
|
||||
if (msg_verbose)
|
||||
msg_info("%s: about to bind to server %s as dn %s", myname,
|
||||
dict_ldap->server_host, dict_ldap->bind_dn);
|
||||
|
||||
rc = ldap_bind_s(dict_ldap->ld, dict_ldap->bind_dn,
|
||||
dict_ldap->bind_pw, LDAP_AUTH_SIMPLE);
|
||||
if (rc != LDAP_SUCCESS) {
|
||||
msg_warn("%s: Unable to bind to server %s as %s (%d -- %s): ", myname, dict_ldap->server_host, dict_ldap->bind_dn, rc, ldap_err2string(rc));
|
||||
dict_errno = DICT_ERR_RETRY;
|
||||
return (0);
|
||||
} else {
|
||||
if (msg_verbose)
|
||||
msg_info("%s: Successful bind to server %s as %s (%d -- %s): ", myname, dict_ldap->server_host, dict_ldap->bind_dn, rc, ldap_err2string(rc));
|
||||
}
|
||||
}
|
||||
if (msg_verbose)
|
||||
msg_info("%s: cached connection handle for LDAP source %s",
|
||||
myname, dict_ldap->ldapsource);
|
||||
}
|
||||
|
||||
/*
|
||||
* Otherwise, we're all set. Return the new dict_ldap structure.
|
||||
*/
|
||||
return (&dict_ldap->dict);
|
||||
}
|
||||
|
||||
|
@@ -19,6 +19,10 @@
|
||||
* directory. Adding support for a new system type means updating the
|
||||
* makedefs script, and adding a section below for the new system.
|
||||
*/
|
||||
#if (defined(__NetBSD_Version__) && __NetBSD_Version__ >= 104250000)
|
||||
#define ALIAS_DB_MAP "hash:/etc/mail/aliases" /* sendmail 8.10 */
|
||||
#endif
|
||||
|
||||
#if defined(FREEBSD2) || defined(FREEBSD3) || defined(FREEBSD4) \
|
||||
|| defined(FREEBSD5) \
|
||||
|| defined(BSDI2) || defined(BSDI3) || defined(BSDI4) \
|
||||
@@ -32,7 +36,9 @@
|
||||
#define HAS_DB
|
||||
#define HAS_SA_LEN
|
||||
#define DEF_DB_TYPE "hash"
|
||||
#ifndef ALIAS_DB_MAP
|
||||
#define ALIAS_DB_MAP "hash:/etc/aliases"
|
||||
#endif
|
||||
#define GETTIMEOFDAY(t) gettimeofday(t,(struct timezone *) 0)
|
||||
#define ROOT_PATH "/bin:/usr/bin:/sbin:/usr/sbin"
|
||||
#define USE_STATFS
|
||||
|
@@ -31,9 +31,11 @@
|
||||
/* Vertical tab character.
|
||||
/* .IP \e\e
|
||||
/* Backslash character.
|
||||
/* .IP \enum
|
||||
/* .IP \e\fInum\fR
|
||||
/* 8-bit character whose ASCII value is the 1..3 digit
|
||||
/* octal number \fInum\fR.
|
||||
/* .IP \e\fIother\fR
|
||||
/* The backslash character is discarded.
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
/* .fi
|
||||
|
@@ -94,9 +94,8 @@
|
||||
/* int vstream_peek(stream)
|
||||
/* VSTREAM *stream;
|
||||
/*
|
||||
/* int vstream_setjmp(stream, buffer)
|
||||
/* int vstream_setjmp(stream)
|
||||
/* VSTREAM *stream;
|
||||
/* jmp_buf *buffer;
|
||||
/*
|
||||
/* void longjmp(stream, val)
|
||||
/* VSTREAM *stream;
|
||||
|
@@ -1,4 +1,4 @@
|
||||
/*++
|
||||
/*
|
||||
/* NAME
|
||||
/* vstring 3
|
||||
/* SUMMARY
|
||||
@@ -9,11 +9,6 @@
|
||||
/* VSTRING *vstring_alloc(len)
|
||||
/* int len;
|
||||
/*
|
||||
/* VSTRING *vstring_init(vp, buf, len)
|
||||
/* VSTRING *vp;
|
||||
/* char *buf;
|
||||
/* int len;
|
||||
/*
|
||||
/* vstring_ctl(vp, type, value, ..., VSTRING_CTL_END)
|
||||
/* VSTRING *vp;
|
||||
/* int type;
|
||||
@@ -106,10 +101,6 @@
|
||||
/* of at least "len" bytes. The minimal length is 1. The result
|
||||
/* is a null-terminated string of length zero.
|
||||
/*
|
||||
/* vstring_init() initializes a fixed-size buffer. Attempts to
|
||||
/* allocate space beyond the buffer end cause the process to
|
||||
/* terminate with a fatal run-time error.
|
||||
/*
|
||||
/* vstring_ctl() gives control over memory management policy.
|
||||
/* The function takes a VSTRING pointer and a list of zero
|
||||
/* or more (name,value) pairs. The expected valye type of the
|
||||
@@ -227,7 +218,7 @@
|
||||
|
||||
#include <sys_defs.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h> /* 44BSD stdarg.h uses abort() */
|
||||
#include <stdlib.h> /* 44BSD stdarg.h uses abort() */
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -306,49 +297,6 @@ VSTRING *vstring_alloc(int len)
|
||||
return (vp);
|
||||
}
|
||||
|
||||
/* vstring_fixed_get_ready - vbuf callback for read buffer empty condition */
|
||||
|
||||
static int vstring_fixed_get_ready(VBUF *unused_buf)
|
||||
{
|
||||
msg_panic("vstring_fixed_get: write-only buffer");
|
||||
}
|
||||
|
||||
/* vstring_fixed_put_ready - vbuf callback for write buffer full condition */
|
||||
|
||||
static int vstring_fixed_put_ready(VBUF *unused_bp)
|
||||
{
|
||||
msg_fatal("fixed-size string buffer full");
|
||||
}
|
||||
|
||||
/* vstring_fixed_space - vbuf callback to reserve space */
|
||||
|
||||
static int vstring_fixed_space(VBUF *bp, int len)
|
||||
{
|
||||
if (len < 0)
|
||||
msg_panic("vstring_fixed_space: bad length %d", len);
|
||||
if (len - bp->cnt > 0)
|
||||
msg_fatal("fixed-size string buffer full");
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* vstring_init - initialize fixed-length buffer */
|
||||
|
||||
VSTRING *vstring_init(VSTRING *vp, char *buf, int len)
|
||||
{
|
||||
if (len < 1)
|
||||
msg_panic("vstring_init: bad length %d", len);
|
||||
vp->vbuf.flags = 0;
|
||||
vp->vbuf.data = (unsigned char *) buf;
|
||||
vp->vbuf.len = len;
|
||||
VSTRING_RESET(vp);
|
||||
vp->vbuf.data[0] = 0;
|
||||
vp->vbuf.get_ready = vstring_fixed_get_ready;
|
||||
vp->vbuf.put_ready = vstring_fixed_put_ready;
|
||||
vp->vbuf.space = vstring_fixed_space;
|
||||
vp->maxlen = 0;
|
||||
return (vp);
|
||||
}
|
||||
|
||||
/* vstring_free - destroy variable-length string */
|
||||
|
||||
VSTRING *vstring_free(VSTRING *vp)
|
||||
|
@@ -31,7 +31,6 @@ typedef struct VSTRING {
|
||||
} VSTRING;
|
||||
|
||||
extern VSTRING *vstring_alloc(int);
|
||||
extern VSTRING *vstring_init(VSTRING *, char *, int);
|
||||
extern void vstring_ctl(VSTRING *,...);
|
||||
extern VSTRING *vstring_truncate(VSTRING *, int);
|
||||
extern VSTRING *vstring_free(VSTRING *);
|
||||
|
Reference in New Issue
Block a user