2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-08-30 21:55:20 +00:00

snapshot-20000507

This commit is contained in:
Wietse Venema
2000-05-07 00:00:00 +00:00
parent f1faee7672
commit 27b4bead1d
43 changed files with 1106 additions and 716 deletions

View File

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

View File

@@ -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

View File

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

View File

@@ -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

View File

@@ -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

View File

@@ -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:
===========================================

View File

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

View File

@@ -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] ?

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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 */

View File

@@ -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 *);

View File

@@ -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",

View File

@@ -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

View File

@@ -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

View File

@@ -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);

View File

@@ -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>

View File

@@ -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 &lt;<b>sysexits.h</b>&gt;.
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)

View File

@@ -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>

View File

@@ -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

View File

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

View File

@@ -1,6 +0,0 @@
# script to compare common code between smtp and lmtp
sed '
s/SMTP/LMTP/g
s/smtp/lmtp/g
' $*

View File

@@ -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

View File

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

View File

@@ -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).

View File

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

View File

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

View File

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

View File

@@ -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);
}
/*

View File

@@ -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[] = {

View File

@@ -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)

View File

@@ -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);
}

View File

@@ -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,

View File

@@ -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);
}

View File

@@ -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;
/*

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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)

View File

@@ -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 *);