-TDICT_ENV
-TDICT_HT
-TDICT_LDAP
+-TDICT_DEBUG
-TDICT_MYSQL
-TDICT_NI
-TDICT_NIS
========================
This document provides a road map of the Postfix mail system source
-code distribution. I suggest that you take a few minutes to read
-this file, and then proceed with the INSTALL instructions.
+code distribution. I suggest that you
+
+- take a few minutes to read this file,
+
+- review the RELEASE_NOTES file for incompatible changes,
+
+- and then proceed with the INSTALL instructions.
Introduction
============
==================================
Postfix aims to be an alternative to the widely-used sendmail
-program. Sendmail is responsible for 70% of all e-mail delivered
-on the Internet. With an estimated 100 million users, that's an
-estimated 10 billion (10^10) messages daily. A stunning number.
+program.
Although IBM supported the Postfix development, it abstains from
control over its evolution. The goal is to have Postfix installed
Web sites:
http://www.postfix.org/ current release information
- http://www.ibm.com/alphaworks/ original distribution site (obsolete)
Mail addresses (PLEASE send questions to the mailing list)
Roadmap of the Postfix source distribution
==========================================
-Point your browser at html/index.html for Postfix documentation,
-for manual pages, and for the unavoidable Postfix FAQ. Expect to
-see updated versions on-line at http://www.postfix.org/
-
-Point your MANPATH environment variable at the `man' directory (use
-an absolute path) for UNIX-style on-line manual pages. These pages
-are also available through the HTML interface, which allows you to
-navigate faster.
-
The RELEASE_NOTES file describes new features, and lists incompatible
changes with respect to previous Postfix versions.
The HISTORY file gives a detailed log of changes to the software.
+Point your browser at html/index.html for Postfix documentation,
+for manual pages, and for the unavoidable Postfix FAQ. Expect to
+see updated versions on-line at http://www.postfix.org/
+
+Point your MANPATH environment variable at the `man' directory (use
+an absolute path) for UNIX-style on-line manual pages. These pages
+are also available through the HTML interface, which allows you to
+navigate faster.
+
The PORTING file discusses how to go about porting Postfix to other
-UNIX platforms. Some people are looking into a port to Windows NT.
-We'll see. This software uses every trick in the book that I learned
-about UNIX.
+UNIX platforms.
The TODO file lists things that still need to be done. If you want
to set your teeth into one of those problems, drop me a note at
src/smtp/ SMTP client
src/smtpd/ SMTP server
src/trivial-rewrite/ Address rewriting and resolving
+ src/virtual/ virtual mailbox-only delivery agent
Test programs:
aliases yes (can enable/disable mail to /file or |command)
bare newlines yes (but will send CRLF)
blacklisting yes (client name/addr; helo hostname; mail from; rcpt to)
-content filter no
+content filter yes
db tables yes (compile time option)
dbm tables yes (compile time option)
delivered-to yes
-dsn not yet
+dsn not yet (bounces have DSN form)
errors-to: yes
esmtp yes
etrn support yes (uses per-destination log or flushes entire queue)
-fcntl locking yes (compile time)
-flock locking yes (compile time)
+fcntl locking yes (runtime configurable)
+flock locking yes (runtime configurable)
home mailbox yes
ident lookup no
ldap tables yes (contributed)
-luser relay not yet
+luser relay yes
+lmtp support yes (client)
m4 config no
mail to command yes (configurable for .forward, aliases, :include:)
mail to file yes (configurable for .forward, aliases, :include:)
majordomo yes (edit approve script to delete /delivered-to/i)
mime conversion not yet; postfix uses just-send-eight
missing <> yes (most common address forms)
+mysql tables yes (contributed)
netinfo tables yes (contributed)
newaliases yes (main alias database only)
nis tables yes
pop/imap yes (with third-party daemons that use /var[/spool]/mail)
rbl support yes
return-receipt: not yet
+sasl support yes (compile time option)
+sendmail -bt no
sendmail -q yes
-sendmail -qRxxx no
+sendmail -qRxxx yes
sendmail -qSxxx no
sendmail -qtime ignored
sendmail -v no
tcp wrapper no (use built-in blacklist facility)
user+extension yes (also: .forward+extension)
user-extension yes (also: .forward-extension)
-user.lock yes (compile time)
+user.lock yes (runtime configurable)
uucp support yes (sends user@domain recipients)
virtual domains yes
year 2000 safe yes
You can specify one or more hosts, domains, addresses or net/masks.
-3 - Making daemon programs more verbose
-=======================================
+2b - Record the SMTP connection with a sniffer
+==============================================
+
+This example uses tcpdump. In order to record a conversation you
+need to specify a large enough buffer or else you will miss some
+or all of the packet payload.
+
+ tcpdump -w /file/name -s 2000 host hostname and port 25
+
+Run this for a while, stop with Ctrl-C when done. To view the data
+use a binary viewer, or use my tcpdumpx utility that is available
+from ftp://ftp.porcupine.org/pub/debugging.
+
+3 - Making Postfix daemon programs more verbose
+===============================================
Append one or more -v options to selected daemon definitions in
/etc/postfix/master.cf and type "postfix reload". This will cause
This is a very first implementation of Postfix content filtering.
A Postfix content filter receives unfiltered mail from Postfix and
-re-injects filtered mail back into Postfix.
+either bounces the mail or re-injects filtered mail back into Postfix.
It involves an incompatible change to queue file formats. Older
Postfix versions will reject mail that needs to be content filtered,
content filtered.
..................................
- . Postfix .
- ------smtpd \ /local-----
- . -cleanup->queue- .
- -----pickup / \smtp------
- ^ . | .
- | . \pipe-----+
+ : Postfix :
+ ----->smtpd \ /local---->
+ : -cleanup->queue- :
+ ---->pickup / \smtp----->
+ ^ : | :
+ | : \pipe-----+
| .................................. |
| |
| |
+------sendmail<-------filter<---------+
-Create a dedicated local user account called "filter". The user
-will never log in, and can be given a "*" password and non-existent
-shell and home.
+1 - Create a dedicated local user account called "filter". The
+ user will never log in, and can be given a "*" password and
+ non-existent shell and home directory. This user handles all
+ potentially dangerous mail content - that is why it should be
+ a separate account.
-Create a directory /var/spool/filter that is accessible only to
-the "filter" user. This is where the content filtering will store
-its temporary files.
+2 - Create a directory /var/spool/filter that is accessible only
+ to the "filter" user. This is where the content filtering will
+ store its temporary files.
-Define a content filtering entry in the Postfix master file:
+3 - Define a content filtering entry in the Postfix master file:
/etc/postfix/master.cf:
- filter unix - n n - - pipe
- user=filter argv=/some/where/filter -f ${sender} -- ${recipient}
+ filter unix - n n - - pipe
+ flags=R user=filter argv=/some/where/filter -f ${sender} -- ${recipient}
-The filter program can start out as a simple shell script like this:
+The /some/where/filter program can be a simple shell script like this:
#!/bin/sh
exit status of the filter command is whatever exit status Postfix
sendmail produces.
-The problem with content filters like this is that they are not
-very robust, because the software does not talk a well-defined
-protocol with Postfix. If the filter shell script aborts because
-the shell runs into some memory allocation problem, the script will
-not produce a nice exit status as per /usr/include/sysexits.h and
-mail will probably bounce. The same lack of robustness is possible
-when the content filtering software itself runs into a resource
-problem.
-
I suggest that you play with this script for a while until you are
-satisfied with the results. Run it as root or as the filter user,
-with a real message (headers+body) as input:
+satisfied with the results. Run it as the filter user, with a real
+message (headers+body) as input:
- # /some/where/filter -f sender recipient... <message-file
+ % /some/where/filter -f sender recipient... <message-file
Turn on content filtering for mail arriving via SMTP only, by
appending "-o content_filter=filter:dummy" to the master.cf
The content_filter configuration parameter accepts the same
syntax as the right-hand side in a Postfix transport table.
-Postfix snapshot-20000529 requires that you specify a dummy
-destination as shown in the example. This is no longer necessary
-with later Postfix versions.
+Simple content filter limitations
+=================================
+
+The problem with content filters like the one above is that they
+are not very robust, because the software does not talk a well-defined
+protocol with Postfix. If the filter shell script aborts because
+the shell runs into some memory allocation problem, the script will
+not produce a nice exit status as per /usr/include/sysexits.h and
+mail will probably bounce. The same lack of robustness is possible
+when the content filtering software itself runs into a resource
+problem.
Advanced content filtering example
===================================
submits mail back into Postfix via localhost port 10026.
..................................
- . Postfix .
- ------smtpd \ /local-----
- . -cleanup->queue- .
- -----pickup / ^ | \smtp------
- . | v .
- . smtpd smtp .
- . 10026 | .
+ : Postfix :
+ ----->smtpd \ /local---->
+ : -cleanup->queue- :
+ ---->pickup / ^ | \smtp----->
+ : | v :
+ : smtpd smtp :
+ : 10026 | :
......................|...........
^ |
| v
....|............
- . | 10025 .
- . filtering .
- . .
+ : | 10025 :
+ : filter :
+ : :
.................
To enable content filtering in this manner, specify in main.cf a
"filter" is a dedicated local user account. The user will never
log in, and can be given a "*" password and non-existent shell and
-home.
+home directory. This user handles all potentially dangerous mail
+content - that is why it should be a separate account.
-The spawn server is part of Postfix but is not installed by default.
-Edit the top-level Makefile.in file, run "make makefiles", "make",
-and "make install". The manual page isn't installed by default,
-either. See the spawn.c source file.
+In the above example, Postfix listens on port localhost:10025. If
+you want to have your filter listening on port localhost:10025
+instead of Postfix, then you must run your filter as a stand-alone
+program.
The /some/where/filter command is most likely a PERL script. PERL
has modules that make talking SMTP easy. The command-line specifies
The simplest content filter just copies SMTP commands and data
between its inputs and outputs. If it has a problem, all it has to
do is to reply to an input of `.' with `550 content rejected', and
-to disconnect its output side instead of sending `.'.
+to disconnect without sending `.' on the connection that injects
+mail back into Postfix.
The job of the content filter is to either bounce mail with a
suitable diagnostic, or to feed the mail back into Postfix through
Bugfix: the code for masquerade_exceptions was case sensitive.
Reported by Eduard Vopicka. File: cleanup/cleanup_masquerade.c.
-20000526
-
- Feature: experimental queue manager by Patrik Rak with a
- fancy pre-emptive scheduling algorithm that improves delivery
- performance of mail with few recipients. This queue manager
- is made available as "nqmgr".
-
20000528
Feature: the SMTP client SASL password file can contain
Added a simple shell-script based content filtering example
to the FILTER_README file.
- Content filtering support for nqmgr by Patrik Rak. File:
- nqmgr/qmgr_message.c.
-
Renamed "content inspection" etc. to "content filtering"
in anticipation of a new hook for content inspection that
only inspects mail without re-injecting it into Postfix.
20000922
- nqmgr update from Patrik Rak for the changed queue manager
- to delivery agent protocol.
-
Lame feature: syslog_facility parameter to control where
syslogd sends Postfix logging (default: syslog_facility =
mail). However, errors during command-line parsing are
Bugfix: the recipient home directory test broke mailbox_transport
support for non-UNIX recipients. File: local/recipient.c.
-20001117
-
- Robustness: additional integrity tests for the nqmgr by
- Patrik Rak. File: nqmgr/qmgr_message.c.
-
20001118
Bugfix: the new LDAP client code did not work properly if
Feature: SASL support for the LMTP client. Recent CYRUS
software requires this for Postfix over TCP sockets.
- This was just a cloning operation.
20010120
20010121
+ Workaround: specify "broken_sasl_auth_clients = yes" in
+ order to support old Microsoft clients that implement
+ a non-standard version of RFC 2554 (AUTH command).
+
Workaround: Lotus Domino 5.0.4 violates RFC 2554 and replies
to EHLO with AUTH=LOGIN. File: smtp/smtp_proto.c.
+
+20010125
+
+ Code cleanup: wrote creator/destructor for dictionary
+ objects that provides default methods that trap all attempts
+ to perform an unimplemented operation. Based on an ansatz
+ by Laurent Wacrenier (teaser.fr). Files: util/dict*.[hc].
+
+ Code cleanup: INSTALL.sh does not ask questions when stdin
+ is not connected to a tty (as in: make install</dev/null).
+ To automate a customized install, the script imports
+ environment variables for install_root etc.
+
+20010127
+
+ Workaround: randomize the delay between attempts to lock
+ a file, so that multiple bounce or defer servers are less
+ likely to retry all at the same time. likely. File:
+ util/rand_sleep.c, global/deliver_flock.c, global/dot_lockfile.c.
+
+20010128
+
+ Code cleanup: complaints about invalid or numeric hostnames
+ either provide specific context or are removed as redundant.
+ Files: util/valid_hostname.c dns/dns_lookup.c.
+
+ Code cleanup: new mailbox_size_limit parameter (default:
+ 20MB). Until now, the mailbox size limit was the same as
+ the message size limit, due to artefact of implementation.
+ Files: global/mail_params.h, local/local.c.
+
+ Bugfix: fix for the ldap_domains parameter, both semantics
+ and documentation by LaMont Jones. Files: LDAP_README,
+ conf/sample-ldap.cf, util/dict_ldap.c.
+
+20010129
+
+ Cleanup: clarified documentation and boundary cases in the
+ random_sleep() routine.
+
+ Bugfix: the MISSING_USLEEP feature was used backwards.
+ Patrik Rak. File: util/random_sleep.c.
+
+20010130
+
+ Workaround: Linux usleep() is void, BSD/Solaris usleep()
+ returns int, don't use it. File util/random_sleep.c.
+
+ Made local maildir bounce/defer handling mode consistent
+ with local mailbox delivery. File local/maildir.c.
+
+ The smtp client now defers delivery when all MX hosts have
+ no A record. File: smtp/smtp_addr.c
+
+ Bundled the man2html and postlink quick hacks so people
+ can do their own manual page processing. See scripts in
+ the mantools directory.
+
+ Documentation: updated the reference to sendmail in the
+ html/index.html page.
+
+ Documentation: added note about the Cisco PIX "fixup smtp"
+ bug that causes mail delivery problems when "." and "CRLF"
+ arrive in separate packets. File: html/faq.html.
+
+20010201
+
+ Bugfix: another missing initialization in the mysql client.
+ File: util/dict_mysql.c.
+
+ Bumped the default mailbox file size limits to 50MB.
+
+20010202
+
+ Bugfix: fixed the way the master resets the file size limit
+ to avoid problems when a Postfix daemon updates a queue
+ file. The file size limit is now increased to INT_MAX if
+ it is smaller than INT_MAX, so that it is less likely to
+ interfere than the old setting of message_size_limit.
+
+ Feature: disable mailbox size limits for the local and
+ virtual delivery agents by setting mailbox_size_limit or
+ virtual_mailbox_limit to zero.
+
+20010203
+
+ Cleanup: added one gruesome command to the postlink script
+ for hyperlinking nroff manual page output. Word abbreviation
+ broke some <a href...> </a> instances across line boundaries.
+ sed(1) is an amazing tool. File: mantools/postlink.
+
+20010204
+
+ Laid the ground work for logging of table accesses. This
+ will give more insight into how Postfix uses its lookup
+ tables. User interface comes later. File: util/dict_debug.c.
+
+20010216
+
+ Bugfix: the pipe delivery agent expanded $size as if it
+ were a recipient, instead of expanding it as $nexthop or
+ as $sender. Reported by Michael Tokarev. File: pipe/pipe.c.
+
+20010221
+
+ Bugfix: poor LMTP performance for domains that are listed
+ in $mydestination, because Postfix would send one recipient
+ at a time, with multiple deliveries of recipients of the
+ same message in parallel; a similar problem could exist
+ with virus scanning and with firewall relay hosts that
+ forward mail for $mydestination to an inside machine. This
+ behavior is now changed to depend on the transport-specific
+ xxx_destination_recipient_limit parameter. This also means
+ that you can now get qmail behavior for SMTP deliveries by
+ setting smtp_destination_recipient_limit=1. File:
+ {qmgr,nqmgr}/qmgr_message.c.
+
+ Workaround: Solaris socketpair() can fail with EINTR. Added
+ a sane_socketpair.c module that joins the ranks of the other
+ sane_whatever workarounds. Reported by Andrew McNamara.
+ File: util/sane_socketpair.[hc]
+
+20010222
+
+ Documentation: the default main.cf file has a prominent
+ warning that mynetworks should be properly configured in
+ order to reject unauthorized mail relay requests from
+ strangers.
+
+ Documentation: the INSTALL document, section "mandatory
+ configuration file edits" has a section that explains that
+ mynetworks should be properly configured in order to reject
+ unauthorized mail relay requests from strangers.
+
+20010223
+
+ Documentation: the basic.html document has a section that
+ explains that mynetworks should be properly configured in
+ order to reject unauthorized mail relay requests from
+ strangers.
+
+ Feature: new "mynetworks_style" parameter that controls
+ how mynetworks (trusted networks) is derived from the
+ inet_interfaces (machine interfaces) setting. Specify
+ "class" for entire class A, B, C networks; "subnet" for
+ the local subnets only; or "host" for maximal privacy.
+ Files: util/inet_addr_local.[hc], global/own_inet_addr.[hc],
+ global/mynetworks.[hc], postconf/postconf.c.
+
+ Portability: MACOSX patches by Gerben Wierda.
+
+ Portability: Solaris /dev/null is a symlink, which tripped
+ up the code to safely open a file before local delivery. We now
+ grudgingly allow symlinks owned by root. File: util/safe_open.c.
+
+20010224
+
+ Bugfix: "postconf mynetworks" ignored the inet_interfaces
+ setting. That was a very old one. File: postconf/postconf.c.
+
+ INCOMPATIBLE CHANGE: POSTFIX NO LONGER RELAYS MAIL FOR
+ CLIENTS IN THE ENTIRE CLASS A/B/C NETWORK. POSTFIX BY
+ DEFAULT RELAYS MAIL FOR CLIENTS IN THE LOCAL SUBNETWORK.
+ Specify "mynetworks_style = class" to get the old behavior.
+
+20010225
+
+ Portability: master sigchld handler based on writing to a
+ pipe, so that the master wakes up from select(). Based on
+ code by Erik Forsberg, Linkoping University, Sweden. File:
+ master/master_sig.c. Disabled until after the major release.
+
+ Code cleanup: Postfix should now run with no alias database.
+
+ Code cleanup: local_destination_recipient_limit and
+ local_destination_concurrency_limit have become first-class
+ configuration parameters. Files: global/mail_params.h,
+ *qmgr/qmgr.c, postconf/postconf.c.
+
+20010226
+
+ Documentation suggestions by Lars Hecking and Richard
+ Huxton, Matthias Andree and many others.
+
+ Code cleanup: some queue/transport operations need to be
+ moved, after the code cleanup of the recipient/concurrency
+ limit handling. Patrik Rak. Files: *qmgr/qmgr_message.c.
Linux RedHat 4.x
Linux RedHat 5.x
Linux RedHat 6.x
+ Linux RedHat 7.x
Linux Slackware 3.5
Linux Slackware 4.0
Linux Slackware 7.0
Linux SuSE 5.x
Linux SuSE 6.x
+ Linux SuSE 7.x
Mac OS X server
+ Mac OS X Public Beta
NEXTSTEP 3.x
NetBSD 1.x
OPENSTEP 4.x
Rhapsody 5.x
SunOS 4.1.x
SunOS 5.4..5.8 (Solaris 2.4..8)
- Ultrix 4.x
+ Ultrix 4.x (well, that was long ago)
or something closely resemblant.
- Run the INSTALL.sh script as the super-user:
- # sh INSTALL.sh
+ # make install (interactive version, first time install)
+ # make install </dev/null (non-interactive version, for upgrades)
The INSTALL.sh script offers suggestions for pathnames that you
can override, either by editing INSTALL.sh or by specifying your
configuration language uses lazy evaluation, and does not look at
a parameter value until it is needed at runtime.
-First of all, you must specify what domain will be appended to a
-local address. The "myorigin" parameter defaults to the local
-hostname, but that is probably OK only for very small sites.
+First of all, you must specify what domain will be appended to an
+unqualified address (i.e. an address without @domain.name). The
+"myorigin" parameter defaults to the local hostname, but that is
+probably OK only for very small sites.
Some examples:
In the first case, local mail goes out as user@$myhostname, in
the second case the sender address is user@$mydomain.
-Next you need to specify what mail addresses are local to the
-Postfix system.
+Next you need to specify what mail addresses Postfix should deliver
+locally.
Some examples:
appropriate for the mailserver for an entire domain. The third
example should be used when running on a virtual host interface.
+If your machine is on an open network then you must specify what
+client IP addresses are authorized to relay their mail through your
+machine. The default setting includes all class A, B or C networks
+that the machine is attached to. Often, that gives relay permission
+to too many clients. My own settings are:
+
+ mynetworks = 168.100.189.0/28, 127.0.0.0/8
+
If you're behind a firewall, you should set up a relayhost. If
you can, specify the organizational domain name so that Postfix
can use DNS lookups, and so that it can fall back to a secondary
Finally, if you haven't used Sendmail prior to using Postfix, you
will have to build the alias database (with: sendmail -bi, or:
newaliases). Be sure to set up aliases for root and postmaster that
-forward mail to a real person.
+forward mail to a real person. Postfix has a sample aliases file
+conf/aliases that you can adapt to local conditions.
11 - To chroot or not to chroot
-==============================
+===============================
Postfix can run most daemon processes in a chroot jail, that is,
the processes run at a fixed low privilege and with access only to
With the exception of the Postfix local delivery and `pipe' daemons,
every Postfix daemon can run chrooted.
-By default, no Postfix daemon runs chrooted. In order to enable
-chroot operation, edit the file /etc/postfix/master.cf. It is
-highly recommended to chroot the daemons that talk to the network:
-the smtp and smtpd processes.
+Sites with high security requirements should consider to chroot
+all daemons that talk to the network: the smtp and smtpd processes,
+and perhaps also the lmtp client.
+
+The default /etc/postfix/master.cf file specifies that no Postfix
+daemon runs chrooted. In order to enable chroot operation, edit
+the file /etc/postfix/master.cf. Instructions are in the file.
Note that a chrooted daemon resolves all filenames relative to the
Postfix queue directory (/var/spool/postfix). For successful use
PATH=/bin:/usr/bin:/usr/sbin:/usr/etc:/sbin:/etc
umask 022
+test -t 0 &&
cat <<EOF
Warning: this script replaces existing sendmail or Postfix programs.
# Find out the location of configuration files.
+test -t 0 &&
for name in install_root tempdir config_directory
do
while :
# Override default settings.
+test -t 0 &&
for name in daemon_directory command_directory \
queue_directory sendmail_path newaliases_path mailq_path mail_owner\
setgid manpages
)
esac
-test "$need_config" = 1 && cat <<EOF 1>&2
+test "$need_config" = 1 || exit 0
+
+ALIASES=`bin/postconf -h alias_database | sed 's/^[^:]*://'`
+cat <<EOF 1>&2
- Warning: you still need to edit myorigin/mydestination in
- $CONFIG_DIRECTORY/main.cf. See also html/faq.html for dialup
+ Warning: you still need to edit myorigin/mydestination/mynetworks
+ in $CONFIG_DIRECTORY/main.cf. See also html/faq.html for dialup
sites or for sites inside a firewalled network.
- BTW: Edit your alias database and be sure to set up aliases
- for root and postmaster, then run $NEWALIASES_PATH.
+ BTW: Check your $ALIASES file and be sure to set up aliases
+ for root and postmaster that direct mail to a real person, then
+ run $NEWALIASES_PATH.
EOF
% make makefiles CCARGS="-I/usr/local/include -DHAS_LDAP" \
AUXLIBS="-L/usr/local/lib -lldap -L/usr/local/lib -llber"
+On Solaris 2.x you may have to specify run-time link information,
+otherwise ld.so will not find some of the shared libraries:
+
+ % make tidy
+ % make makefiles CCARGS="-I/usr/local/include -DHAS_LDAP" \
+ AUXLIBS="-L/usr/local/lib -R/usr/local/lib -lldap \
+ -L/usr/local/lib -R/usr/local/lib -llber"
+
The 'make tidy' command is needed only if you have previously built
Postfix without LDAP support.
substitute for the address Postfix is trying to resolve, e.g.
ldapsource_query_filter = (&(mail=%s)(paid_up=true))
- domain (No default; you must configure this.)
+ domain (Default is to ignore this.)
This is a list of domain names, paths to files, or dictionaries.
- If specified, only lookups ending in a domain on this list will
- be searched. This can significantly reduce the query load on the
- LDAP server.
+ If specified, only lookups for the domains on this list will be
+ performed. This means that the LDAP map won't get searched for
+ 'user', nor will it get searched for any domain not listed. This
+ can significantly reduce the query load on the LDAP server.
ldapsource_domain = postfix.org, hash:/etc/postfix/searchdomains
result_attribute (maildrop)
+LINUX PORTABILITY
+=================
+
+On RedHat Linux 7.0, you must install the db3-devel RPM before you
+can compile the Postfix source code.
+
LINUX SYSLOGD PERFORMANCE
=========================
-[Based on information that was provided by Amous Gouaux]
+[This file still needs to be updated - some information is obsolete]
-Postfix LMTP support
-====================
+1 - Postfix LMTP support
+========================
LMTP stands for Local Mail Transfer Protocol, and is detailed in
-RFC2033. This protocol is used to communicate with the final
-delivery agent, which may be on the local host or a remote host.
+RFC2033. Postfix uses this protocol to communicate with the final
+delivery agent, which may run on the local host or a remote host.
This protocol opens up interesting possibilities: one Postfix front
-end system can drive multiple mailbox back end systems over LMTP.
-As the mail load increases you add Postfix front end systems and
-LMTP mailbox back end systems. You can use LDAP or mysql to share
-the user database among the front end and back end systems.
+end machine can drive multiple mailbox back end machines over LMTP.
+As the mail load increases, you add more Postfix front end systems
+and more LMTP mailbox back end systems. This is the model that I
+had in mind when I began drafting the design for Postfix - a scalable
+architecture that allows you to keep adding SMTP servers and mailbox
+servers painlessly.
+
+Such a distributed architecture needs glue to keep things together.
+You can use a networked database LDAP or mysql to share the user
+database among the front end and back end systems. Use a replicated
+database so that no machine becomes a single point of failure for
+the entire mail infrastructure.
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.
+of University of Texas at Dallas, Richardson, USA, who also revised
+much of the documentation. Wietse Venema reduced the code to its
+present shape.
-Overview
-========
+2 - Overview
+============
Most of the examples in this document involve the CMU Cyrus IMAP/POP
server, available from:
http://asg.web.cmu.edu/cyrus/
-While certainly not the only application that could make use of LMTP,
-it tends to be the most discussed. These examples are based on the
-forthcoming Cyrus 2.0.10, at least at the time of writing. The 2.x
-branch of Cyrus places greater emphasis on LMTP delivery than the
-previous releases. Those using older releases of Cyrus can find a
-discussion in the appendix of this document.
+While certainly not the only application that could make use of
+LMTP, it tends to be the most discussed. These examples are based
+on the forthcoming Cyrus 2.0.10, at least at the time of writing.
+The 2.x branch of Cyrus places greater emphasis on LMTP delivery
+than the previous releases. Those using older releases of Cyrus
+can find a discussion in the appendix of this document.
There are a variety of ways LMTP delivery can be configured in
-Postfix. The two basic flavors are delivery over UNIX-domain sockets
-and delivery over TCP sockets. Both flavors can be specified in
-either the Postfix main.cf or in a transport map. The best approach
-to use depends upon the arrangement of your servers and the desired
-level of parallelization. Please be sure to study this entire
-document as there are trade-offs in convenience and performance with
-these different approaches.
-
-The precise syntax for UNIX-domain and TCP connection endpoints is
-given in the lmtp(8) manual page.
+Postfix. The two basic flavors are delivery over UNIX-domain
+sockets and delivery over TCP sockets.
+ o Connections over UNIX-domain sockets limit delivery to LMTP
+ servers running on the same machine.
-Using main.cf configuration
-===========================
+ o Connections over TCP sockets allow you to deliver to LMTP
+ servers across a local network.
-This is the simplest LMTP configuration. The settings
-local_transport, mailbox_transport, and fallback_transport can
-support the following connections:
-
-1. LMTP over TCP sockets.
+The precise syntax for UNIX-domain and TCP connection endpoints is
+given in the lmtp(8) manual page. Examples are also given in the
+text below.
- mailbox_transport = lmtp
+Both socket flavors can be specified in either the Postfix main.cf
+file (see section 5) or in a Postfix transport map (section 6).
+What is the best approach for you depends upon the arrangement of
+your servers and the desired level of parallelization.
- Instead of delivering local mail to a mail box such as
- /var/mail/$user, a connection will be made over TCP to an LMTP
- server. Currently the default port for this connection is 24,
- but this can be customized in the "/etc/services" file.
+Please be sure to study this entire document as there are trade-offs
+in convenience and in performance with these different approaches.
- NOTE:
+3 - LMTP over UNIX-domain sockets
+=================================
- With connections over TCP sockets, some Cyrus implementations
- insist on SASL-style authentication, which is not currently
- supported by the Postfix LMTP client. See the examples below
- for additional details.
+A UNIX-domain socket is specified as the socket type ("unix") and
+a name in the local file system:
+ unix:/path/name
-2. LMTP over UNIX-domain sockets.
+The "/path/name" part should be the name of a socket created by
+the LMTP server on the local machine. See the specific examples
+later in this document.
- mailbox_transport = lmtp:unix:/path/name
+NOTE:
- In this case the LMTP connection will be made over a UNIX-domain
- socket. This "/path/name" should be the socket created by the
- LMTP server on the local machine.
+ If you run the lmtp client chrooted, the interpretation of the
+ /path/name is relative to the Postfix queue directory (typically,
+ /var/spool/postfix).
- NOTE 1:
+ By default, the Postfix LMTP client does not run chrooted.
+ With LMTP delivery to the local machine there is no good reason
+ to run the Postfix LMTP client chrooted.
- If you configured Cyrus using the "--with-libwrap" option, be
- sure to allow access to the "lmtpd" service from "0.0.0.0".
- Otherwise LMTP deliveries over UNIX-domain sockets will be
- blocked. See the examples below for more on using libwrap.
+4 - LMTP over TCP sockets
+=========================
- NOTE 2:
+A TCP destination is specified as the socket type ("inet"), the
+destination hostname and the TCP port:
- If you run the lmtp client chrooted, the interpretation of
- the /path/name is relative to the Postfix queue directory
- (typically, /var/spool/postfix).
+ inet:hostname:port
- NOTE 3:
+The "inet:" part can be omitted, as it is the default socket type.
- By default, the Postfix LMTP client does not run chrooted.
- With LMTP delivery to the local machine there is no good
- reason to run the Postfix LMTP client chrooted.
+The destination port can be omitted as well. Currently the default
+TCP port number for this type of connection is 24, but this can be
+customized in the "/etc/services" file. Specific examples are
+given later in this document.
+NOTE:
-Examples:
+ With connections over TCP sockets, later Cyrus LMTP server
+ implementations insist on SASL-style authentication. This means
+ that Postfix must be built with SASL support (see SASL_README).
+ The examples below show how to enable this in the Postfix LMTP
+ client.
-1. LMTP over UNIX-domain sockets.
+ Some Cyrus LMTP server implementations do not allow SASL-style
+ authentication via plaintext passwords. You will have to jump
+ some extra hoops in order to enable MD5 password support, or
+ you will have to wait until this restriction is relaxed.
- To utilize UNIX-domain sockets for the communication between
- Postfix and Cyrus, the corresponding configuration files should
- look something like this:
- /etc/cyrus.conf:
+5 - Configuring LMTP using main.cf configuration
+================================================
- SERVICES {
- ...
- lmtpunix cmd="lmtpd" listen="/var/imap/socket/lmtp" prefork=1
- ...
- }
-
- /etc/postfix/main.cf:
+This is the simplest LMTP configuration.
- mailbox_transport = lmtp:unix:/var/imap/socket/lmtp
+5.1 - Delivery mechanisms
+-------------------------
- In this case, mail that is resolved to be local will be delivered
- to the Cyrus lmtpd server via the socket "/var/imap/socket/lmtp".
+Postfix main.cf supports three mechanisms to deliver mail over
+LMTP. Each method can use UNIX-domain or TCP sockets as described
+in a later section.
- If you configured Cyrus using the "--with-libwrap" option, you
- will need the following:
-
- /etc/hosts.allow:
-
- lmtpd : 0.0.0.0
-
-2. LMTP over TCP sockets.
-
- For this example, suppose the following files are configured
- thusly:
-
- /etc/cyrus.conf:
-
- SERVICES {
- ...
- lmtp cmd="lmtpd -a" listen="127.0.0.1:lmtp" prefork=0
- ...
- }
+main.cf mechanism 1
+-------------------
-XXX does this mean that connections will be accepted only on 127.0.0.1?
+mailbox_transport = lmtp:unix:/path/name (UNIX-domain socket example)
+mailbox_transport = lmtp:hostname:port (TCP socket example)
- /etc/services:
+Mail that resolves as local (domain is listed in $mydestination)
+is given to the Postfix local delivery agent. The Postfix local
+delivery agent expands aliases and .forward files, and delegates
+mailbox delivery to the LMTP server.
- lmtp 2003/tcp
+main.cf mechanism 2
+-------------------
- /etc/postfix/main.cf:
+local_transport = lmtp:unix:/path/name (UNIX-domain socket example)
+local_transport = lmtp:hostname:port (TCP socket example)
- mailbox_transport = lmtp
+Mail that resolves as local (domain is listed in $mydestination)
+is directly given to the LMTP server. The mail is not processed
+by the Postfix local delivery agent; therefore aliases and .forward
+files are not processed.
- /etc/postfix/master.cf:
+main.cf mechanism 3
+-------------------
- lmtp unix - - n - - lmtp
+fallback_transport = lmtp:unix:/path/name (UNIX-domain socket example)
+fallback_transport = lmtp:hostname:port (TCP socket example)
- Mail that Postfix resolves to be local will be delivered via TCP
- to the Cyrus LMTP server. Postfix will make a connection to port
- 2003 on the local host, subsequently transmitting the message to
- the lmtpd server managed by the Cyrus master process. Since
- Postfix does not currently support LMTP-AUTH, the "-a" lmtpd
- option is required.
+Mail that resolves as local (domain is listed in $mydestination)
+is given to the Postfix local delivery agent. The Postfix local
+delivery agent processes aliases and .forward files, and delivers
+to /var[/spool]/mail/$user for users that have a UNIX account.
+Mail for other local users is delegated to the LMTP server.
- CAUTION:
+5.2 - Examples
+--------------
- If you run lmtpd with the "-a" option, be certain that you
- restrict what systems can connect to this service. This can
- be done in either one of two ways:
+5.2.1 - LMTP over UNIX-domain sockets
+-------------------------------------
- a. Compile Cyrus with libwrap support, configuring
- "/etc/hosts.allow" to restrict access to this service to
- only your mail server.
+To utilize UNIX-domain sockets for the communication between
+Postfix and Cyrus, the corresponding configuration files should
+look something like this:
- b. In the cyrus.conf file, for the "listen" argument to the
- "lmtp" service, specify the address (in this case
- localhost), that the service should bind to. This can
- also be convenient if you have a private network between
- your Postfix server and your Cyrus server.
+/etc/cyrus.conf:
- If neither of these actions are taken, anybody will be able
- to drop junk into your Cyrus message store!
+ SERVICES {
+ ...
+ lmtpunix cmd="lmtpd" listen="/var/imap/socket/lmtp" prefork=1
+ ...
+ }
+/etc/postfix/main.cf:
-3. LMTP over TCP sockets, using hosts.allow.
+ mailbox_transport = lmtp:unix:/var/imap/socket/lmtp
- While similar to the previous example, this one varies in how the
- lmtpd service is protected from unauthorized use. Instead of
- binding the lmtpd service to a specific Internet address, access
- will be controlled using the "/etc/hosts.allow" tcp_wrappers
- configuration file. The tcp_wrappers package is available from:
+In this case, the Postfix local delivery agent expands aliases
+and .forward files, and delegates mailbox delivery to the Cyrus
+lmtpd server via the socket "/var/imap/socket/lmtp".
- ftp://ftp.porcupine.org/pub/security/index.html
+5.2.2 - LMTP over TCP sockets
+-----------------------------
- To take advantage of tcp_wrappers, Cyrus will need to be
- configured using the "--with-libwrap" option. See the Cyrus
- documentation for more details.
+For this example, suppose the following files are configured
+thusly:
- Here are excerpts of the pertinent files:
+/etc/cyrus.conf:
- /etc/hosts.allow:
+ SERVICES {
+ ...
+ lmtp cmd="lmtpd" listen="127.0.0.1:lmtp" prefork=0
+ ...
+ }
- lmtpd : localhost : ALLOW
- lmtpd : ALL@ALL : DENY
+/etc/services:
- /etc/cyrus.conf:
+ lmtp 24/tcp
- SERVICES {
- ...
- lmtp cmd="lmtpd -a" listen="lmtp" prefork=0
- ...
- }
+/etc/postfix/main.cf:
- /etc/services:
+ mailbox_transport = lmtp:localhost
+ lmtp_sasl_auth_enable = yes
+ lmtp_sasl_password_maps = hash:/etc/postfix/lmtp_sasl_pass
- lmtp 2003/tcp
+/etc/postfix/master.cf:
- /etc/postfix/main.cf:
+ lmtp unix - - n - - lmtp
- mailbox_transport = lmtp
+/etc/postfix/lmtp_sasl_pass:
+ localhost.my.domain username:password
- The syntax shown in the hosts.allow excerpt above is valid if
- tcp_wrappers is compiled using a "make" argument of:
+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.
- STYLE=-DPROCESS_OPTIONS
+With the above settings, the Postfix local delivery agent expands
+aliases and .forward files, and delegates mailbox delivery to the
+the Cyrus LMTP server. Postfix makes a connection to port 24 on
+the local host, subsequently transmitting the message to the lmtpd
+server managed by the Cyrus master process.
- See the tcp_wrappers hosts_options(5) man page for more details.
+6 - Configuring LMTP using transport map configuration
+======================================================
-Using transport map configuration
-=================================
+This approach is quite similar to specifying the LMTP service in
+the Postfix main.cf configuration file. However, now we will use
+a transport map to route mail to the appropriate LMTP server,
+instead of depending on delegation by the Postfix local delivery
+agent.
-This approach is quite similar to specifying the LMTP service in the
-Postfix main.cf configuration file. However, now we will use a
-transport map to route mail to the appropriate LMTP server. Why
-might this approach be useful? This could be handy if you wish to
-route mail for multiple domains to their respective mail retrieval
+Why might this approach be useful? This could be handy if you wish
+to route mail for multiple domains to their respective mail retrieval
(IMAP/POP) server. Example:
/etc/postfix/transport:
transport_maps = hash:/etc/postfix/transport
+For details of the Cyrus LMTP server configuration, see section 5.
+
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.
-Performance considerations
-==========================
+7 - Performance considerations
+==============================
Hopefully the preceding discussion has seemed pretty straight
forward. Now things get interesting. After reading the following
-you will see that there are more factors to consider when setting up
-LMTP services.
+you will see that there are more factors to consider when setting
+up LMTP services.
-Single instance message store
-=============================
+8 - Single instance message store
+=================================
Presently this topic is more pertinent to sites running Cyrus, but
may be a factor with other applications as well.
Since 1.6.22, Cyrus has had the feature that if a message containing
-multiple recipients is received via the LMTP protocol, and all these
-recipients were on the same Cyrus partition, only one instance of
-this message would be written to the file system. The other
+multiple recipients is received via the LMTP protocol, and all
+these recipients were on the same Cyrus partition, only one instance
+of this message would be written to the file system. The other
recipients would then see a hard link of this single instance.
-Depending on your user base, this can be considerable motivation to
-using LMTP.
-
-However, there is a catch: currently the Postfix local delivery
-mechanisms are only designed to handle one recipient at a time, which
-in most cases is more than adequate. So, if you wish to support
-single instance message store delivery, you will have to use a
-transport table to map these users to the appropriate LMTP
-destination.
-
-While the simplest thing to do would be to list the entire domain in
-the transport map for LMTP delivery, this by-passes alias expansion
-for otherwise local addresses. If the site is to run software via
-aliases, like most Mailing List Management (MLM) software, a more
-complex solution is required. Fortunately, a virtual table should do
-the trick.
+Depending on your user base, this can be considerable motivation
+to using LMTP.
+
+However, there is a catch: the Postfix local delivery agent is
+designed to deliver one recipient at a time, which in most cases
+is more than adequate. So, if you wish to support single instance
+message store delivery, you will have to use a virtual table to
+map these users to the appropriate LMTP destination (at the time
+of writing, the Postfix transport table supports only per-domain
+routing, and not per-recipient routing).
+
+While the simplest thing to do would be to list the entire domain
+in the transport map for LMTP delivery, this by-passes alias
+expansion for otherwise local addresses (see section 5.1, delivery
+mechanism 2). If the site is to run software via aliases, like
+most Mailing List Management (MLM) software, a more complex solution
+is required. A virtual table should do the trick.
As an example, suppose we wanted to support single instance message
-store delivery for the domain "example.org". The configuration files
-for this domain could look something like this:
+store delivery for the hosted (not local) domain "example.org".
+The configuration files for this domain could look something like
+this:
/etc/postfix/virtual:
Breaking things down, we begin with the address "mlist@example.org",
which represents a mailing list. By placing an entry in the virtual
map to direct this mail to "mlist@localhost", we can override the
-transport map that would by default route all "@example.org" mail to
-a LMTP server via a UNIX-domain socket.
+transport map that would by default route all "@example.org" mail
+to a LMTP server via a UNIX-domain socket.
-To summarize, all mail that is to be processed by an alias entry must
-first be diverted with a virtual table entry so that it does not fall
-into the more general routing established by the transport table.
+To summarize, all mail that is to be processed by an alias entry
+must first be diverted with a virtual table entry so that it does
+not fall into the more general routing established by the transport
+table.
-Improving connection caching performance
-========================================
+9 - Improving connection caching 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.
+connection.
For LMTP connection caching to work, the Postfix LMTP client should
not switch destination hosts. This is no problem when you run only
can be an issue.
You can prevent the LMTP client from switching between servers by
-configuring a separate mail delivery transport for each LMTP server:
+configuring a separate LMTP delivery transport for each LMTP server:
/etc/postfix/master.cf:
bar.com lmtp2:lmtp2host
-Appendix: Older Cyrus versions
-==============================
+10 - Appendix: Older Cyrus versions
+===================================
First of all, if you are using a Cyrus 2.x version prior to 2.0.10,
it would be good to upgrade. The previous 2.x releases were beta
/etc/services:
- lmtp 2003/tcp
+ lmtp 24/tcp
/etc/inetd.conf:
configuration is the lack of mention of the UNIX-domain sockets.
That is because delivery over UNIX-domain sockets is new with Cyrus
2.x, yet another reason to upgrade. :-)
-
-
-
-# Local Variables:
-# mode: text
-# mode: flyspell
-# fill-column: 69
-# End:
-
-
-
+++ /dev/null
-BEGIN WARNING
-=============
-
-The information in this file is outdated. The Postfix LMTP server
-can now make connections over UNIX-domain sockets.
-
-With connections over TCP sockets, some Cyrus implementations insist
-on SASL-style authentication, which is not supported by the Postfix
-LMTP client. In that case, use UNIX-domain sockets instead.
-
-The precise syntax for UNIX-domain and TCP connection endpoints is
-given in the lmtp(8) manual page.
-
-Examples:
-
- /etc/postfix/transport:
- domain1.name lmtp1:unix:/path/name
- domain2.name lmtp2:lmtp2host
-
- /etc/postfix/master.cf:
- lmtp1 unix - - n - - lmtp
- lmtp2 unix - - n - - lmtp
-
-The first example (domain1) uses UNIX-domain connections, the second
-example (domain2) uses TCP.
-
-For optimal use of connection caching, specify separate mail delivery
-transports for each domain that receives mail via LMTP:
-
-END WARNING
-===========
-
-Postfix LMTP support
-====================
-
-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
-Postfix. However, a remote LMTP server can be useful if Postfix
-runs on mail relay server(s) that feed incoming mail directly to
-the appropriate mailbox server(s). This way, mailbox servers do
-not need to run an SMTP server at all. Tidy all the way around.
-
-Configuring the mailbox server (local or remote)
-================================================
-
-On the mailbox server, in this case a CMU Cyrus imapd/popd server,
-add the following to /etc/services:
-
- pop3 110/tcp # Cyrus POP3
- imap 143/tcp # Cyrus IMAP4
- lmtp 24/tcp
-
-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 does multiple deliveries per LMTP session
-(connection caching), 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
-===================
-
-Similar changes to /etc/services:
-
- lmtp 24/tcp
-
-You may have to add the following entry to /etc/postfix/master.cf:
-
- lmtp unix - - n - - lmtp
-
-NOTE: Root privileges are not necessary!
-
-Put this in /etc/postfix/transport:
-
- inbox.domain.org lmtp:inbox.domain.org
-
-Naturally, this means we also need in /etc/postfix/main.cf:
-
- transport_maps = hash:/etc/postfix/transport
-
-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.
-
-Improving connection caching 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.
-
-For LMTP connection caching 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.
-
-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
You will need to add -DHAS_PCRE and a -I for the PCRE header to CCARGS,
and add the path to the PCRE library to AUXLIBS, for example:
- make -f Makefile.init makefiles 'CCARGS=-DHAS_PCRE -I../../pcre-2.08' \
- 'AUXLIBS=../../pcre-2.08/libpcre.a'
+ make -f Makefile.init makefiles 'CCARGS=-DHAS_PCRE -I../../../pcre-2.08' \
+ 'AUXLIBS=../../../pcre-2.08/libpcre.a'
[note: pcre versions before 2.06 are no longer compatible -- Wietse]
-REJECT by header/body_checks are now flagged as policy violations
-rather than bounces, for consistency in postmaster notifications.
+This is the first official Postfix release that is not called BETA.
+May it help the people who cannot get BETA software past their
+management.
-Major changes with snapshot-20001217
-====================================
+Release 20010228 differs from snapshot 20010228 in that the virtual
+delivery agent and nqmgr queue manager are left out. That software
+will become part of the official release when it has not changed
+in a while.
-This release involves little change in functionality and a lot of
-small changes to lots of files. The code is put out as a separate
-snapshot release so that I have a tested baseline for further work.
+In the text below, incompatible changes are labeled with the Postfix
+version that introduced the change. If you upgrade from a later
+Postfix version, then you do not have to worry about that particular
+incompatibility.
-All time-related configuration parameters now accept a one-letter
-suffix to indicate the time unit (s: second, m: minute, h: hour,
-d: day, w: week). The exceptions are the LDAP and MYSQL modules
-which are maintained separately.
+Major incompatible changes with release-20010228
+================================================
-The mysql client was partially rewritten in order to elimimate some
-memory allocation/deallocation problems. The code needs more work,
-and needs to be tested in a real production environment.
+[snapshot-20010225] POSTFIX NO LONGER RELAYS MAIL FOR CLIENTS IN
+THE ENTIRE CLASS A/B/C NETWORK. To get the old behavior, specify
+"mynetworks_style = class" in the main.cf file. The default
+(mynetworks_style = subnet) is to relay for clients in the local
+IP subnet. See conf/main.cf.
-The local_transport and default_transport configuration parameters
-can now be specified in transport:destination notation, just like
-the mailbox_transport and fallback_transport parameters. The
-:destination part is optional. However, these parameters take only
-one destination, unlike relayhost and fallback-relay which take
-any number of destinations.
+[snapshot-20001005, snapshot-20010225] You must execute "postfix
+stop" before installing this release. Some recommended parameter
+settings have changed, and a new entry must be added to the master.cf
+file before you can start Postfix again.
-Incompatible changes with snapshot-20001210
-===========================================
+1 - The recommended Postfix configuration no longer uses flat
+ directories for the "incoming" "active", "bounce", and "defer"
+ queue directories. The "flush" directory for the new "flush"
+ service directory should not be flat either.
-If this release does not work for you, you can go back to a previous
-Postfix version without losing your mail, subject to the "incompatible
-changes" listed for previous Postfix releases below.
-
-When delivering to /file/name (as directed in an alias or .forward
-file), the local delivery agent now logs a warning when it is unable
-to create a /file/name.lock file. Mail is still delivered as before.
-
-The "sun_mailtool_compatibility" feature is going away (a compatibility
-mode that turns off kernel locks on mailbox files). It still works,
-but a warning is logged. Instead of using "sun_mailtool_compatibility",
-specify the mailbox locking strategy as "mailbox_delivery_lock =
-dotlock".
-
-The Postfix SMTP client now skips SMTP server replies that do not
-start with "CODE SPACE" or with "CODE HYPHEN" and flags them as
-protocol errors. Older Postfix SMTP clients silently treated "CODE
-TEXT" as "CODE SPACE TEXT", i.e. as a valid SMTP reply.
-
-This snapshot does not yet change default relay settings. That
-change alone affects a dozen files, most of which documentation.
-This may be an incompatibility with some people's expectations,
-but such are my rules - between code freeze and release no major
-functionality changes are allowed.
-
-Several interfaces of libutil and libglobal routines have changed.
-This may break third-party code written for Postfix. In particular,
-the safe_open() routine has changed, the way the preferred locking
-method is specified in the sys_defs.h file, as well as all routines
-that perform file locking. When compiling third-party code written
-for Postfix, the incompatibilities will be detected by the compiler
-provided that #include file dependencies are properly maintained.
-
-Major changes with snapshot-20001210
-====================================
+ Upon start-up, Postfix checks if the hash_queue_names configuration
+ parameter is properly set up, and will add any queue directory
+ names that are missing.
+
+2 - In order to improve performance of one-to-one mail deliveries
+ the queue manager will now look at up to 10000 queue files
+ (was: 1000). The default qmgr_message_active_limit setting
+ was changed accordingly.
+
+ If you have a non-default qmgr_message_active_limit in main.cf,
+ you may want adjust it.
+
+3 - The new "flush" service needs to be configured in master.cf.
+
+ Upon start-up, Postfix checks if the new "flush" service is
+ configured in the master.cf file, and will add an entry if it
+ is missing.
+
+Should you wish to back out to a previous Postfix release there is
+no need to undo the above queue configuration changes.
+
+[snapshot-20000921] The protocol between queue manager and delivery
+agents has changed. This means that you cannot mix the Postfix
+queue manager or delivery agents with those of Postfix versions
+prior to 20000921. This change does not affect Postfix queue file
+formats.
+
+[snapshot-20000529] This release introduces an incompatible queue
+file format change ONLY when content filtering is enabled (see text
+in FILTER_README). Old Postfix queue files will work fine, but
+queue files with the new content filtering info will not work with
+Postfix versions before 20000529. Postfix logs a warning and moves
+incompatible queue files to the "corrupt" mail queue subdirectory.
+
+Minor incompatible changes with release-20010228
+================================================
+
+[snapshot-20010225] The incoming and deferred queue directories
+are now hashed by default. This improves the performance considerably
+under heavy load, at the cost of a small but noticeable slowdown
+when one runs "mailq" on an unloaded system.
+
+[snapshot-20010222] Postfix no longer automatically delivers
+recipients one at a time when their domain is listed in $mydestination.
+This change solves delivery performance problems with delivery via
+LMTP, with virus scanning, and with firewall relays that forward
+all mail for $mydestination to an inside host.
+
+The "one recipient at a time" delivery behavior is now controlled
+by the per-transport recipient limit (xxx_destination_recipient_limit,
+where xxx is the name of the delivery mechanism). This parameter
+controls the number of recipients that can be sent in one delivery
+(surprise).
+
+The setting of the per-transport recipient limit also controls the
+meaning of the per-transport destination concurrency limit (named
+xxx_destination_concurrency_limit, where xxx is again the name of
+the delivery mechanism):
+
+ 1) When the per-transport recipient limit is 1 (i.e., send one
+ recipient per delivery), the per-transport destination concurrency
+ limit controls the number of simultaneous deliveries to the
+ same recipient. This is the default behavior for delivery via
+ the Postfix local delivery agent.
+
+ 2) When the per-transport recipient limit is > 1 (i.e., send
+ multiple recipients per delivery), the per-transport destination
+ concurrency limit controls the number of simultaneous deliveries
+ to the same domain. This is the default behavior for all other
+ Postfix delivery agents.
+
+[snapshot-20010128] The Postfix local delivery agent now enforces
+mailbox file size limits (default: mailbox_size_limit = 51200000).
+This limit affects all file write access by the local delivery
+agent or by a process run by the local delivery agent. The purpose
+of this parameter is to act as a safety for run-away software. It
+cannot be a substitute for a file quota management system. Specify
+a limit of 0 to disable.
+
+[snapshot-20010128] REJECT in header/body_checks is now flagged as
+policy violation rather than bounce, for consistency in postmaster
+notifications.
+
+[snapshot-20010128] The default RBL (real-time blackhole lists)
+domain examples have been changed from *.vix.com to *.mail-abuse.org.
+
+[snapshot-20001210] Several interfaces of libutil and libglobal
+routines have changed. This may break third-party code written
+for Postfix. In particular, the safe_open() routine has changed,
+the way the preferred locking method is specified in the sys_defs.h
+file, as well as all routines that perform file locking. When
+compiling third-party code written for Postfix, the incompatibilities
+will be detected by the compiler provided that #include file
+dependencies are properly maintained.
+
+[snapshot-20001210] When delivering to /file/name (as directed in
+an alias or .forward file), the local delivery agent now logs a
+warning when it is unable to create a /file/name.lock file. Mail
+is still delivered as before.
+
+[snapshot-20001210] The "sun_mailtool_compatibility" feature is
+going away (a compatibility mode that turns off kernel locks on
+mailbox files). It still works, but a warning is logged. Instead
+of using "sun_mailtool_compatibility", specify the mailbox locking
+strategy as "mailbox_delivery_lock = dotlock".
+
+[snapshot-20001210] The Postfix SMTP client now skips SMTP server
+replies that do not start with "CODE SPACE" or with "CODE HYPHEN"
+and flags them as protocol errors. Older Postfix SMTP clients
+silently treated "CODE TEXT" as "CODE SPACE TEXT", i.e. as a valid
+SMTP reply.
+
+[snapshot-20001121] On RedHat Linux 7.0, you must install the
+db3-devel RPM before you can compile the Postfix source code.
+
+[snapshot-20000924] The postmaster address in the "sorry" text at
+the top of bounced mail is now just postmaster, not postmaster@machine.
+The idea is to refer users to their own postmaster.
+
+[snapshot-20000921] The notation of [host:port] in transport tables
+etc. is going away but it is still supported. The preferred form
+is now [host]:port. This change is necessary to support IPV6
+address forms which use ":" as part of a numeric IP address. In a
+future release, Postfix will log a warning when it encounters the
+[host:port] form.
+
+[snapshot-20000921] In mail headers, Errors-To:, Reply-To: and
+Return-Receipt: addresses are now rewritten as a sender address
+(was: recipient).
+
+[snapshot-20000921] Postfix no longer inserts Sender: message
+headers.
+
+[snapshot-20000921] The queue manager now logs the original number
+of recipients when opening a queue file (example: from=<>, size=3502,
+nrcpt=1).
+
+[snapshot-20000921] The local delivery agent no longer appends a
+blank line to mail that is delivered to external command.
+
+[snapshot-20000921] The pipe delivery agent no longer appends a
+blank line when the F flag is specified (in the master.cf file).
+Specify the B flag if you need that blank line.
+
+[snapshot-20000507] 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:;").
+
+[snapshot-20000507] 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.
+
+[snapshot-20000507] 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".
+
+Major changes with release-20010228
+===================================
+
+Postfix produces DSN formatted bounced/delayed mail notifications.
+The human-readable text still exists, so that users will not have
+to be unnecessarily confused by all the ugliness of RFC 1894. Full
+DSN support will be later.
+
+This release introduces full content filtering through an external
+process. This involves an incompatible change in queue file format.
+Mail is delivered to content filtering software via an existing
+mail delivery agent, and is re-injected into Postfix via an existing
+mail submission agent. See examples in the FILTER_README file.
+Depending on how the filter is implemented, you can expect to lose
+a factor of 2 to 4 in delivery performance of SMTP transit mail,
+more if the content filtering software needs lots of CPU or memory.
+
+Specify "body_checks = regexp:/etc/postfix/body_checks" for a quick
+and dirty emergency content filter that looks at non-header lines
+one line at a time (including MIME headers inside the message body).
+Details in conf/sample-filter.cf.
+
+The header_checks and body_checks features can be used to strip
+out unwanted data. Specify IGNORE on the right-hand side and the
+data will disappear from the mail.
-This snapshot includes bugfixes that were already released as
-patches 12 and 13 for the 19991231 "stable" release:
+Support for SASL (RFC 2554) authentication in the SMTP server and
+in the SMTP and LMTP clients. See the SASL_README file for more
+details. This file still needs better examples.
- - The queue manager could deadlock for 10 seconds when bouncing
- mail under extreme load from one-to-one mass mailings.
+Postfix now ships with an LMTP delivery agent that can deliver over
+local/remote TCP sockets and over local UNIX-domain sockets. The
+LMTP_README file gives example, but still needs to be revised.
- - Local delivery performance was substandard, because the per-user
- concurrency limit accidentally applied to the entire local
- domain.
+Fast "ETRN" and "sendmail -qR". Postfix maintains per-destination
+logfiles with information about what mail is queued for selected
+destinations. See the file ETRN_README for details.
The mailbox locking style is now fully configurable at runtime.
The new configuration parameter is called "mailbox_delivery_lock".
all mailbox and all "/file/name" deliveries by the Postfix local
delivery agent.
-The new "import_environment" and "export_environment" configuration
-parameters now provide explicit control over what environment
-variables Postfix will import, and what environment variables
-Postfix will pass on to a non-Postfix process. This is better than
-hard-coding my debugging environment into public releases.
+Minor changes with release-20010228
+===================================
+
+You can now specify multiple SMTP destinations in the relayhost
+and fallback_relay configuration parameters. The destinations are
+tried in the specified order. Specify host or host:port (perform
+MX record lookups), [host] or [host]:port (no MX record lookups),
+[address] or [address]:port (numerical IP address).
The "mailbox_transport" and "fallback_transport" parameters now
understand the form "transport:nexthop", with suitable defaults
Postfix transport map. This allows you to specify for example,
"mailbox_transport = lmtp:unix:/file/name".
-The MYSQL client now supports server connections over UNIX-domain
-sockets. Code provided by Piotr Klaban. See the file MYSQL_README
-for examples of "host" syntax.
-
-Incompatible changes with snapshot-20001121
-===========================================
-
-If this release does not work for you, you can go back to a previous
-Postfix version without losing your mail, subject to the "incompatible
-changes" listed for previous Postfix releases below.
-
-Major changes with snapshot-20001121
-====================================
-
-Support for RedHat Linux 7.0. On RedHat Linux 7.0, you must install
-the db3-devel RPM before you can compile the Postfix source code.
-
-The mailbox_transport feature works again. It was broken when the
-"require_home_directory" feature was added.
+The local_transport and default_transport configuration parameters
+can now be specified in transport:destination notation, just like
+the mailbox_transport and fallback_transport parameters. The
+:destination part is optional. However, these parameters take only
+one destination, unlike relayhost and fallback-relay which take
+any number of destinations.
More general virtual domain support. Postfix now supports both
Sendmail-style virtual domains and Postfix-style virtual domains.
are testing configurations. Until this release the SMTP server was
not aware of soft bounces.
-Incompatible changes with snapshot-20001029
-===========================================
-
-If this release does not work for you, you can go back to a previous
-Postfix version without losing your mail, subject to the "incompatible
-changes" listed for previous Postfix releases below.
-
-Berkeley DB support has changed for Solaris, HP-UX, UNIXWARE, IRIX.
-On these systems, Postfix must no longer use DB 1.85 compatibility
-mode, because that mode loses the file lock while building a table,
-so that table lookups fail and mail is lost. See the DB_README file
-for instructions on how to build Postfix with third-party Berkeley
-DB support.
-
-The "fast ETRN" policy configuration has changed. You now specify
-the list of eligible "fast ETRN" domains with the fast_flush_domains
-parameter (default: $relay_domains). In order to disable the feature,
-specify an empty value (fast_flush_domains =).
-
-Major changes with snapshot-20001029
-====================================
-
-This release ships with an updated LDAP client module that has better
-group support by Lamont Jones, and that has several other enhancements.
-Review the LDAP_README file for more information.
-
-The LMTP client can now make connections over UNIX-domain sockets
-in addition to IPV4. For connections over UNIX-domain sockets,
-specify a transport table entry like:
-
- domain.name lmtp:unix:/path/name
-
-IPV4-based servers are still the default. The LMTP_README file
-still needs to be revised to account for this change. This is
-best done by someone who actually uses the Postfix LMTP client.
-
-You can now specify multiple SMTP destinations in the relayhost
-and fallback_relay configuration parameters. The destinations are
-tried in the specified order. Specify host or host:port (perform
-MX record lookups), [host] or [host]:port (no MX record lookups),
-[address] or [address]:port (numerical IP address).
-
-Incompatible changes with snapshot-20001005
-===========================================
-
-If this release does not work for you, you can go back to a previous
-Postfix version without losing your mail, subject to the "incompatible
-changes" listed for previous Postfix releases below.
-
-You must execute "postfix stop" before installing this release.
-Some recommended parameter settings have changed, and a new entry
-must be added to the master.cf file before you can start Postfix
-again.
-
-1 - The recommended Postfix configuration no longer uses flat
- directories for the "active", "bounce", and "defer" queue
- directories. The "flush" directory for the new "flush" service
- directory should not be flat either.
-
- Upon start-up, Postfix checks if the hash_queue_names configuration
- parameter is properly set up, and will add any queue directory
- names that are missing.
-
-2 - In order to improve performance of one-to-one mail deliveries
- the queue manager will now look at up to 10000 queue files
- (was: 1000). The default qmgr_message_active_limit setting
- was changed accordingly.
-
- If you have a non-default qmgr_message_active_limit in main.cf,
- you may want adjust it.
-
-3 - The new "flush" service needs to be configured in master.cf.
+Workarounds for non-standard RFC 2554 (AUTH command) implementations.
+Specify "broken_sasl_auth_clients = yes" to enable SMTP server
+support for old Microsoft client applications. The Postfix SMTP
+client supports non-standard RFC 2554 servers by default.
- Upon start-up, Postfix checks if the new "flush" service is
- configured in the master.cf file, and will add an entry if it
- is missing.
-
-Should you wish to back out to a previous Postfix release there is
-no need to undo the above changes.
+All time-related configuration parameters now accept a one-letter
+suffix to indicate the time unit (s: second, m: minute, h: hour,
+d: day, w: week). The exceptions are the LDAP and MYSQL modules
+which are maintained separately.
-Major changes with snapshot-20001005
-====================================
+New "import_environment" and "export_environment" configuration
+parameters provide explicit control over what environment variables
+Postfix will import, and what environment variables Postfix will
+pass on to a non-Postfix process.
In order to improve performance of one-to-one deliveries, Postfix
by default now looks at up to 10000 messages at a time (was: 1000).
-Until now, Postfix did a rather lame effort at implementing the
-SMTP ETRN command - it attempted to deliver all mail in the queue,
-regardless of its destination. This is slow if your mail server
-queues mail for lots of different destinations.
-
-This release introduces fast "ETRN" and "sendmail -qR". These
-deliver only mail that is queued for the specified destination,
-without requiring Postfix to open every file in the mail queue.
-
-Postfix now maintains per-destination logfiles with information
-about what mail is queued for specific destinations. By default,
-these logfiles are maintained only for destinations that Postfix
-is willing to relay to (as controlled by the relay_domains parameter).
-
-The maintenance policy for deferred mail logfiles is selected with
-the "fast_flush_policy" configuration parameter. Possible values
-are: "all" (maintain logs for all destinations), "relay" (maintain
-logs for relay destinations) or "none" (maintain no logs).
-
-Postfix falls back to the old slow ETRN for destinations that are
-not eligible for the fast "ETRN" and "sendmail -qR" service.
-
-See the file ETRN_README for details.
-
-Incompatible changes with snapshot-20000924
-===========================================
-
-The postmaster address in the "sorry" text at the top of bounced
-mail is now just postmaster, not postmaster@sending.machine. The
-idea is to refer users to their own postmaster.
-
-Major changes with snapshot-20000924
-====================================
-
-DSN formatted bounced/delayed mail notifications, finally. The
-human-readable text still exists, so that users will not have to
-be unnecessarily confused by all the ugliness of RFC 1894.
-
-Major changes with snapshot-20000923
-====================================
-
-The nqmgr (experimental smarter queue manager) has been updated.
-It no longer worked after the change in queue manager to delivery
-agent protocol.
-
Specify "syslog_facility = log_local1" etc. to separate the logging
from multiple Postfix instances. However, a non-default logging
facility takes effect only after process initialization. Errors
during command-line parsing are still logged with the default syslog
facility, as are errors while processing the main.cf file.
-Incompatible changes with snapshot-20000921
-===========================================
-
-After "make install" you need to execute "postfix reload". The
-protocol between queue manager and delivery agents has changed.
-This does not affect the format of existing queue files. You just
-cannot mix this Postfix version's queue managers or delivery agents
-with older Postfix versions.
-
-The notation of [host:port] in transport tables etc. is going away
-but it is still supported. The preferred form is now [host]:port.
-This change is necessary to support IPV6 address forms which use
-":" as part of a numeric IP address. In a future release, Postfix
-will log a warning when it encounters the [host:port] form.
-
-In mail headers, Errors-To:, Reply-To: and Return-Receipt: addresses
-are now rewritten as a sender address (was: recipient).
-
-Postfix no longer inserts Sender: message headers.
-
-The queue manager now logs the original number of recipients when
-opening a queue file (example: from=<>, size=3502, nrcpt=1).
-
-The local delivery agent no longer appends a blank line to mail
-that is delivered to external command.
-
-The pipe delivery agent no longer appends a blank line when the F
-flag is specified (in the master.cf file). Specify the B flag if
-you need that blank line.
-
-Major changes with snapshot-20000921
-====================================
-
Postfix now strips out Content-Length: headers in incoming mail to
avoid confusion in mail user agents.
-The header_checks and body_checks features can now be used to strip
-out unwanted data. Specify IGNORE and the data will disappear.
-
Specify "require_home_directory = yes" to prevent mail from being
-delivered to a user whose home directory is not mounted.
+delivered to a user whose home directory is not mounted. This
+feature is implemented by the Postfix local delivery agent.
The pipe mailer has a size limit (size=nnn) command-line argument.
-Incompatible changes with snapshot-20000531
-===========================================
-
-All references to "content inspection" have been replaced by "content
-filtering", in anticipation of hooks for true content inspection
-that does not re-inject mail back into Postfix.
-
-Incompatible changes with snapshot-20000529
-===========================================
-
-This version introduces an incompatible queue file format change
-when content filtering is enabled. Old Postfix queue files will
-work fine, but new queue files with content filtering info will
-not work with old Postfix versions. They log a warning and move
-incompatible queue files to the "corrupt" mail queue subdirectory.
-
-Major changes with snapshot-20000529
-====================================
-
-This version introduces full content filtering through an external
-process. This involves an incompatible change in queue file format.
-Mail is delivered to content filtering software via an existing
-mail delivery agent, and is re-injected into Postfix via an existing
-mail submission agent. See examples in the FILTER_README file.
-Depending on how the filter is implemented, you can expect to lose
-a factor of 2 to 4 in delivery performance of SMTP transit mail,
-more if the content filtering software needs lots of CPU or memory.
-
-Major changes with snapshot-20000528
-====================================
-
-Specify "body_checks = regexp:/etc/postfix/body_checks" for a quick
-and dirty emergency content filter that looks at non-header lines
-one line at a time (including MIME headers inside the message body).
-Details in conf/sample-filter.cf.
-
-This version introduces a new queue manager with a clever scheduler
-by Patrik Rak that allow mailing list deliveries be pre-empted by
-non-list mail, while preserving correct average delivery delays.
-The queue manager is build as nqmgr. It needs further testing.
-
-Major changes with snapshot-20000514
-====================================
-
-LaMont Jones and Patrik Rak reported two different scenarios in
-which pipelined SMTP sessions could time out forever. Postfix now
-automatically flushes delayed SMTP commands/replies to prevent
-sender delays from accumulating too much. For example, client-side
-delays happen when a client does DNS lookups to replace hostname
-aliases in a MAIL FROM or RCPT TO commands; server-side delays
-happen when an UCE restriction involves DNS lookup, or when a server
-generates a tarpit delay.
-
-Incompatible changes with snapshot-20000507
-===========================================
-
-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 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
-====================================
-
-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.
+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 \\.
In master.cf you can selectively override main.cf configuration
parameters, for example: "smtpd -o myhostname=foo.com".
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 caching.
-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 caching 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 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
-===========================================
-
-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
-====================================
-
-Questionable feature: with "smtp_skip_5xx_greeting = yes", Postfix
-emulates behavior found in some other MTAs.
-
Questionable feature: with "smtp_always_send_ehlo = yes", the SMTP
client sends EHLO regardless of the content of the SMTP server's
greeting.
key. This still needs to be generalized to multi-key removal (e.g.,
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:
-===========================================
-
-- The SMTP server no longer forwards mail from untrusted clients
-with sender-specified routing (stuff[@%!]stuff[@%!]stuff) through
-destinations that are authorized by the relay_domains parameter.
-This closes a loophole that exploits trust relationships between
-hosts. Example: a trusted backup MX host forwards junk mail to
-a primary MX host which forwards the junk to the Internet. Specify
-"allow_untrusted_routing = yes" to restore the old behavior.
-
-- The SMTP server no longer forwards mail with sender-specified
-routing (stuff[@%!]stuff[@%!]stuff) through destinations that are
-authorized by the permit_mx_backup feature. This change is under
-control by the allow_untrusted_routing parameter discussed above.
-
-- In order to support the above, the data structure and protocol
-of the trivial-rewrite service was changed. This means you must
-re-compile and re-link existing software that uses the Postfix
-resolve_clnt interface.
-
-- As a side effect of the above, an address from an untrusted client
-with @ in the localpart (user@remote@here) no longer bounces with
-"user unknown" but instead is rejected with "relay access denied".
-
-- Incompatible SMTPD access map changes:
-
- An all-numeric right-hand side now means OK. This is for better
- cooperation with out-of-band authentication mechanisms such as
- POP before SMTP etc.
-
- An empty right-hand sides still mean OK, but Postfix will log a
- warning in order to discourage such usage.
-
- You can no longer use virtual, canonical or aliases tables as
- SMTPD access maps. Use the local_recipient_maps feature instead.
-
-- Recipient addresses may no longer begin with `-'. In order to
-get the old behavior, specify "allow_min_user = yes" in main.cf.
-
-- Incompatible transport map changes:
-
- Transport map entries override mydestination. If you use transport
- maps, it is better to always have explicit entries for all domain
- names you have in $mydestination. See the html/faq.html sections
- for firewalls and intranets.
-
- The nexthop information given to a local delivery agent may have
- changed. This information was never intended to be used as a
- next-hop destination.
+Comments in Postfix configuration files no longer contain troff
+formatting codes. The text is now generated from prototype files
+in a new "proto" subdirectory.
Major changes with postfix-19991231:
====================================
the right-hand side of SMTPD access tables, so that you can have
different UCE restrictions for different clients or users.
-The only anomalies in this scheme are that (1) message header checks
-are still the same for every message, and (2) you must use a
-restriction class name (see below) if you want to specify a lookup
-table on the right-hand side of an access table (this is because
-Postfix needs to open those tables ahead of time).
+The only anomalies in this scheme are that (1) message header_checks
+and body_checks are still the same for every message, and (2) you
+must use a restriction class name (see below) if you want to specify
+a lookup table on the right-hand side of an access table (this is
+because Postfix needs to open those tables ahead of time).
Restriction classes allow you to give easy-to-remember names to
groups of UCE restrictions (such as permissive, restrictive, and
non-standard SASL LOGIN authentication method. To enable this
authentication method, specify ``./configure --enable-login''.
-Reportedly, older Microsoft software mis-implements the AUTH
-protocol, and requires that the server replies to EHLO with
-"250-AUTH=stuff..." instead of "250-AUTH stuff...". To accomodate
-such clients, set "allow_broken_auth_clients = yes" in the main.cf
-file.
+Older Microsoft SMTP client software implements a non-standard
+version of the AUTH protocol syntax, and expects that the SMTP
+server replies to EHLO with "250 AUTH=stuff" instead of "250 AUTH
+stuff". To accomodate such clients in addition to conformant
+clients, set "broken_sasl_auth_clients = yes" in the main.cf file.
+
+The Postfix SMTP client is backwards compatible with SMTP servers
+that use the non-standard AUTH protocol syntax.
Building Postfix with SASL authentication support
=================================================
On some systems this generates the necessary Makefile definitions:
% make tidy # if you have left-over files from a previous build
- % make makefiles CCARGS=-DUSE_SASL_AUTH" -I/usr/local/include" \
+ % 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 previous build
- % make makefiles CCARGS=-DUSE_SASL_AUTH" -I/usr/local/include" \
+ % 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 Postfix SMTP server
postconf -f filename
-more general relocated feature - perhaps better to bounce recipients
+get rid of the relocated feature - perhaps better to bounce recipients
at the SMTP port.
-use $mydomain when hostname is not FQDN.
-
-generic daemon that listens on fifo and runs command
-
make sendmail/smtpd/cleanup output directory/fifo configurable
if postdrop scrutinizes input, skip the overhead in the pickup
daemon.
-luser relay
-
add a threshold to sendmail etc. stderr logging, so that class
"info" messages don't go to stderr.
-need a configurable mailbox locking method with system-specific
-default, so people don't have to recompile just to turn of fcntl()
-locks to work around SUN mailtool.
-
implement an UCE control to accept mail if the sender domain sender
lists us as MX host (rafal wiosna). By the same token, implement
a control to accept mail when the client hostname/parent domain
lists us as their MX host.
-with recipient delimiter enabled, append the unmatched recipient
-of @virtual.domain patterns as extension to right-hand recipient,
-for qmail-like virtual mapping.
-
received: headers should be generated by the cleanup daemon, and
client attributes ("with", "from", etc.) should be passed along
with the message. This guarantees that forwarded/aliased mail gets
stamped with the queue ID.
-trivial-rewrite etc.: after reload, close the listen socket and
-wait until all clients disconnect.
-
-In qmgr_entry.c, turn off random walk by default.
-
toss double-bounce mail even when mail for the local machine is
redirected to another box. See mail_addr_double_bounce().
-represent peer as object, not as name + addr arguments
-
-ignore sender: header when different from envelope?
-
-smtp client: optionally log every MX host contacted
-
remote showq access (cookie in maildrop or print some text to inform
the user)
multiple rewrite processes?
-log relay address in addition to host.
-
gethostbyaddr() uses native name services, which can be slow.
can we detect a client that ignores error responses?
way to block inbound mail based on recipient suffix?
-when client begins with non-SMTP data, log warning
-
-when non-SMTP follows ".", log warning.
-
-On linux syslogd needs -/file/name
-
can Postfix implement one switchboard instead of having all these
little lookup tables?
make canonical/virtual/etc. table lookup order configurable
-allow /file/name or maptype_mapname in $mydestination
-
-make protocol errors soft errore? There are a lot of broken mailers
-out there that sometimes croak and sometimes work.
-
-require @ in sender/rcpt (another restriction)
-
-figure out a way to pump recipients into qmgr before concurrency
-starts to drop.
-
pass on client etc/ attributes along with message to delivery agent
-pass on configurable info into external process environment
-
scrutinize file opens in delivery agents just like in qmgr (better:
open the file and see if someone compromised the vmailer account
and is racing against us).
-cleanup: don't run out of memory with large amounts of bcc addresses
-
-cleanup: permit non-empty extra segment, so that mail posting
-software can pass in bcc recipients.
-
suspend/resume signals + master status (suspended/running) in PID
file. Maybe use FIFO instead. But, that means requests do not
arrive when the master is stuck.
trivial-rewrite: optionally, use DNS to fully qualify hostnames.
-smtp: optionally deal with MX records containing an address instead
-of a name.
-
pickup/cleanup/qmgr/local: add options record to control internal
features such as canonical/virtual mapping, VERPs etcetera.
-smtpd: when deciding if a destination is local, also look at the
-virtual map. Perhaps we should move canonical and virtual lookups
-back into the rewrite service, but under a different name, so they
-do not get in the way if we do not want them.
-
-Queue manager: do not allocate queue slots when a destination
-already has more than some threshold. This is to prevent a dead or
-slow destination from filling up the queue manager's active queue,
-preventing delivery to other destinations. However, such `fairness'
-strategies should not cause Postfix to lose the benchmark race, so
-we must be fair and smart at the same time :-)
-
Add hook for (domain, user database) support. This is needed if
you have lots of real domains and can't afford a separate master.cf
delivery agent entry for each domain.
Add support for DBZ databases, using the code from INN. Reportedly,
GDB handles large numbers of keys poorly.
-Make the number of time bits in the queue ID configurable, or at
-least a little larger.
-
Change the front-end to cleanup protocol so that the front-end
sends the expected message size, and so that the cleanup service
can report if there is enough space. This is useful only for the
order to do this we must extract the alias_maps parameter from the
main.cf file, and create any missing files with the right ownerships.
-SunOS 5.4 sendmail seems to include the null byte in alias keys
-and values, like almost every UNIX system; SunOS 5.5 sendmail does
-not include these nulls. Need to add support for SunOS 5.4. NIS
-alias maps always include the null terminator...
-
implement the return-receipt-to notification service.
-Implement real address rewriting.
-
-default alias for mail to non-existent users. How useful is this
-when the postmaster already gets notices of mail that could not be
-delivered by the local mail system? And how do we pass around the
-original envelope recipient once it has been "aliased" to the
-address for non-existent users?
-
-owner-default alias to capture all mailing list errors. Or perhaps
-they should just set up the appropriate owner-foo aliases in their
-alias database?
-
-make mail_params module the main config interface; no calls from
-config.c to routines in mail_params.c
-
-resolve/rewrite clients should share connection
-
-postfix-script: make sure permissions of queue (and anything below)
-are sane.
-
bounce/defer: provide attribute-value interface, for better logging
(expanded-from etc.) and non-delivery reports.
-Postfix-Options: header, to turn on qmail-like VERPs. But, these
-must be accessible only for locally-posted mail (not mail that
-arrives via UUCP).
-
Maintain per-client short-term host status, so we can slow down
unreasonable clients
hosts" table & move mail from the "hold" queue for that site to
the incoming queue.
-Option to make a copy of all mail passing through the mail system.
-
-The message ID is built by concatenating the time of day in seconds
-with the queue id. We must ensure that a queue id is unique for at
-least one second, otherwise multiple messages will have the same
-message ID. Queue ids will always collide after a while. The NFS
-generation number for the queue file would be useful, but there is
-no portable interface to get it, and we cannot depend on the system
-having NFS support enabled. If a 1-microsecond resolution is
-sufficient, we could compose the queue ID from the inode number
-plus 6 decimal digits or 5 hex ones for the time in microseconds.
-Or, use a smarter encoding with more bits per character.
-
postfix-script: make sure that each queue file matches its file id
or we might lose mail.
postfix-script: do database fixups as the unprivileged user
-Put a version file in the conf directory or add option to vmail
-control command to print the version (requires vmconf tool that
-can query main.cf.).
-
Maintain a pool of pre-allocated queue files, to eliminate file
creation and deletion overhead.
rmail command installed. A minimal rmail command can be found in
the "auxiliary/rmail" directory. Install the command, mode 755, in
a place that can be found by the UUCP "uuxqt" command.
+
+In order to send mail via UUCP, see html/faq.html.
+++ /dev/null
-[Code contribued by Andrew McNamara ]
-
-Code created by Andrew McNamara <andrew@connect.com.au> and adapted to
-snapshot 20001121 by Xavier Beaudouin.
-
-Code is maintened now by Xavier Beaudouin <kiwi@oav.net>
-
-[Original Message]
-I've run out of time to fiddle further at the moment, so I've decided to
-post my virtual local delivery agent. Note that this is still a work in
-progress, so don't bet your business on it.
-
-I'll repeat what I said last time:
-
- This code is designed for ISP's who offer virtual mail hosting. It
- looks up the location, uid and gid of user mailboxes via separate maps,
- and the mailbox location map can specify either mailbox or maildir
- delivery (controlled by trailing slash on mailbox name).
-
- The agent does not support aliases or .forwards (use the virtual table
- instead), and therefore doesn't support file or program aliases. This
- choice was made to simplify and streamline the code (it allowed me to
- dispense with 70% of local's code - mostly the bits that are a security
- headache) - if you need this functionality, this agent isn't for you.
-
- It also doesn't support writing to a common spool as root and then
- chowning the mailbox to the user - I felt this functionality didn't fit
- with my overall aims.
-
-Some other notes:
-
-- It's still called "virtual" - I had some concerns that this would
- confuse people, but I'll leave that call up to Wietse - if he wants
- to integrate it, he can specify the name.
-
-- I've retained the three separate map lookups at this time. When
- postfix supports maps that return multiple values, we can consider
- changing it then.
-
-- Specify "virtual:" as the target in the transport table for domains
- for which you want this agent used.
-
-- The attached file is a gzipped tar that should be unpacked in the
- base postfix directory (where the INSTALL and HISTORY files live) -
- it adds a "virtual" subdirectory, and a "virtual.patch" file. The
- patch updates the top level Makefile.in to build the new agent, and
- global/mail_params.h to add the new config parameters.
-
-New config options are:
-
-virtual_mailbox_base
-
- Specifies a path that is prepended to all mailbox paths. This is
- a safety measure to ensure an out of control map doesn't litter the
- filesystem with mailboxes (or worse). While it could be set to "/",
- this isn't recommended.
-
-virtual_mailbox_maps
-
- Recipients are looked up in this map to determine the path to their
- mailbox. If the returned path ends in a slash ("/"), maildir-style
- delivery is carried out, otherwise the path is assumed to specify a
- mailbox file. Note that virtual_mailbox_base is unconditionally
- prepended to this path.
-
-virtual_minimum_uid
-
- Specifies a minimum uid that will be accepted as a return from a
- virtual_uid_maps lookup. Returned values less than this will be
- rejected, and the message will be deferred.
-
-virtual_uid_maps
-
- Recipients are looked up in this map to determine the UID to be
- used when writing to the target mailbox.
-
-virtual_gid_maps
-
- Recipients are looked up in this map to determine the GID to be
- used when writing to the target mailbox.
-
-virtual_usedotlock
-
- Use dot-locking when writing to mailboxes - defaults to off.
-
-[ - Exemple configuration - ]
-
-In main.cf file :
---/---
- virtual_mailbox_base = /var/mail/vhosts
- virtual_mailbox_maps = dbm:/etc/postfix/vmailbox
- virtual_minimum_uid = 100
- virtual_uid_maps = dbm:/etc/postfix/vuid
- virtual_gid_maps = dbm:/etc/postfix/vgid
- virtual_usedotlock = no
---/---
-
-In vmailbox file :
-
---/---
-testuser@fakedom.com testuser/
---/---
-
-In vuid file :
-
---/---
-testuser@fakedom.com 5000
---/---
-
-In vgid file :
-
---/---
-testuser@fakedom.com 5000
---/---
-
-Don't forget to add in master.cf the entry for the agent, that should be
-like :
-
---/---
-virtual unix - n n - - virtual
---/---
-
-NOTES :
--------
-
-1- Don't forget to add dbm:/etc/posfix/vmailbox into your
-local_recipent_maps in main.cf like :
-
---/---
-local_recipient_maps = $alias_maps dbm:/etc/posfix/vmailbox unix:passwd.byname
---/---
-
-2- If you use only the virtual localdelivery you can add the following line
-into main.cf
-
---/---
-mailbox_transport = virtual
---/---
-
-Otherwise you can use transport_maps :
-
-In main.cf file :
-
---/---
-transport_maps=dbm:/etc/postfix/transport
---/---
-
-In transport file :
-
---/---
-fakedom.com virtual:
---/---
-
-
# REJECT Reject the address etc. that matches the pattern. A
# generic error response message is generated.
#
-# OK
+# OK Accept the address etc. that matches the pattern.
#
-# Any other text
-# Accept the address etc. that matches the pattern.
+# restriction...
+# Apply the named UCE restriction (permit, reject,
+# reject_unauth_destination, and so on).
#
# REGULAR EXPRESSION TABLES
-# This section describes how the table lookups change when
+# This section describes how the table lookups change when
# the table is given in the form of regular expressions. For
-# a description of regular expression lookup table syntax,
+# a description of regular expression lookup table syntax,
# see regexp_table(5) or pcre_table(5).
#
-# Each pattern is a regular expression that is applied to
+# Each pattern is a regular expression that is applied to
# the entire string being looked up. Depending on the appli-
-# cation, that string is an entire client hostname, an
+# cation, that string is an entire client hostname, an
# entire client IP address, or an entire mail address. Thus,
-# no parent domain or parent network search is done, and
-# user@domain mail addresses are not broken up into their
+# no parent domain or parent network search is done, and
+# user@domain mail addresses are not broken up into their
# user@ and domain constituent parts.
#
-# Patterns are applied in the order as specified in the
-# table, until a pattern is found that matches the search
+# Patterns are applied in the order as specified in the
+# table, until a pattern is found that matches the search
# string.
#
-# Actions are the same as with normal indexed file lookups,
-# with the additional feature that parenthesized substrings
-# from the pattern can be interpolated as $1, $2 and so on.
+# Actions are the same as with normal indexed file lookups,
+# with the additional feature that parenthesized substrings
+# from the pattern can be interpolated as $1, $2 and so on.
#
# BUGS
-# The table format does not understand quoting conventions.
+# The table format does not understand quoting conventions.
#
# 2
#
# regexp_table(5) format of POSIX regular expression tables
#
# LICENSE
-# The Secure Mailer license must be distributed with this
+# The Secure Mailer license must be distributed with this
# software.
#
# AUTHOR(S)
# The general format is lines with parameter = value pairs. Lines
# that begin with whitespace continue the previous line. A value can
# contain references to other $names or ${name}s.
+#
+# NOTE - CHANGE NO MORE THAN 2-3 PARAMETERS AT A TIME, AND TEST IF
+# POSTFIX STILL WORKS AFTER EVERY CHANGE.
# SOFT BOUNCE
#
# a name matches a lookup key. Continue long lines by starting the
# next line with whitespace.
#
-# DO NOT LIST VIRTUAL DOMAINS HERE. LIST THEM IN THE VIRTUAL FILE
-# INSTEAD. BE SURE TO READ THE ENTIRE VIRTUAL MANUAL PAGE.
-#
#mydestination = $myhostname, localhost.$mydomain
#mydestination = $myhostname, localhost.$mydomain $mydomain
#mydestination = $myhostname, localhost.$mydomain, $mydomain,
# mail.$mydomain, www.$mydomain, ftp.$mydomain
+# TRUST AND RELAY CONTROL
+
+# The mynetworks parameter specifies the list of "trusted" SMTP
+# clients that have more privileges than "strangers".
+#
+# In particular, "trusted" SMTP clients are allowed to relay mail
+# through Postfix. See the smtpd_recipient_restrictions parameter
+# in file sample-smtpd.cf.
+#
+# You can specify the list of "trusted" network addresses by hand
+# or you can let Postfix do it for you (which is the default).
+#
+# By default (mynetworks_style = subnet), Postfix "trusts" SMTP
+# clients in the same IP subnetworks as the local machine.
+# On Linux, this does works correctly only with interfaces specified
+# with the "ifconfig" command.
+#
+# Specify "mynetworks_style = class" when Postfix should "trust" SMTP
+# clients in the same IP class A/B/C networks as the local machine.
+# Don't do this with a dialup site - it would cause Postfix to "trust"
+# your entire provider's network. Instead, specify an explicit
+# mynetworks list by hand, as described below.
+#
+# Specify "mynetworks_style = host" when Postfix should "trust"
+# only the local machine.
+#
+# mynetworks_style = class
+# mynetworks_style = subnet
+# mynetworks_style = host
+
+# Alternatively, you can specify the mynetworks list by hand, in
+# which case Postfix ignores the mynetworks_style setting.
+#
+# Specify an explicit list of network/netmask patterns, where the
+# mask specifies the number of bits in the network part of a host
+# address.
+#
+# You can also specify the absolute pathname of a pattern file instead
+# of listing the patterns here.
+#
+#mynetworks = 168.100.189.0/28, 127.0.0.0/8
+#mynetworks = $config_directory/mynetworks
+
+# The relay_domains parameter restricts what clients this mail system
+# will relay mail from, or what destinations this system will relay
+# mail to. See the smtpd_recipient_restrictions restriction in the
+# file sample-smtpd.cf for detailed information.
+#
+# By default, Postfix relays mail
+# - from "trusted" clients whose IP address matches $mynetworks,
+# - from "trusted" clients matching $relay_domains or subdomains thereof,
+# - from untrusted clients to destinations that match $relay_domains
+# or subdomains thereof, except addresses with sender-specified routing.
+# The default relay_domains value is $mydestination.
+#
+# In addition to the above, the Postfix SMTP server by default accepts mail
+# that Postfix is final destination for:
+# - destinations that match $inet_interfaces,
+# - destinations that match $mydestination
+# - destinations that match $virtual_maps.
+# These destinations do not need to be listed in $relay_domains.
+#
+# Specify a list of hosts or domains, /file/name patterns or type:name
+# lookup tables, separated by commas and/or whitespace. Continue
+# long lines by starting the next line with whitespace. A file name
+# is replaced by its contents; a type:name table is matched when a
+# (parent) domain appears as lookup key.
+#
+# NOTE: Postfix will not automatically forward mail for domains that
+# list this system as their primary or backup MX host. See the
+# permit_mx_backup restriction in the file sample-smtpd.cf.
+#
+#relay_domains = $mydestination
+
# INTERNET OR INTRANET
# The relayhost parameter specifies the default host to send mail to
#header_checks = regexp:/etc/postfix/filename
#header_checks = pcre:/etc/postfix/filename
-# The relay_domains parameter restricts what clients this mail system
-# will relay mail from, or what destinations this system will relay
-# mail to. See the smtpd_recipient_restrictions restriction in the
-# file sample-smtpd.cf.
-#
-# By default, Postfix relays mail
-# - from trusted clients whose IP address matches $mynetworks,
-# - from trusted clients matching $relay_domains or subdomains thereof,
-# - from untrusted clients to destinations that match $relay_domains
-# or subdomains thereof, except addresses with sender-specified routing.
-# The default relay_domains value is $mydestination.
-#
-# In addition to the above, the Postfix SMTP server by default accepts mail
-# that Postfix is final destination for:
-# - destinations that match $inet_interfaces,
-# - destinations that match $mydestination
-# - destinations that match $virtual_maps.
-# These destinations do not need to be listed in $relay_domains.
-#
-# Specify a list of hosts or domains, /file/name patterns or type:name
-# lookup tables, separated by commas and/or whitespace. Continue
-# long lines by starting the next line with whitespace. A file name
-# is replaced by its contents; a type:name table is matched when a
-# (parent) domain appears as lookup key.
-#
-# NOTE: Postfix will not automatically forward mail for domains that
-# list this system as their primary or backup MX host. See the
-# permit_mx_backup restriction in the file sample-smtpd.cf.
-#
-#relay_domains = $mydestination
-
-# The mynetworks parameter specifies the list of networks that are
-# local to this machine. The list is used by the anti-UCE software
-# to distinguish local clients from strangers. See permit_mynetworks
-# and smtpd_recipient_restrictions in the file sample-smtpd.cf file.
-#
-# The default is a list of all networks attached to the machine: a
-# complete class A network (X.0.0.0/8), a complete class B network
-# (X.X.0.0/16), and so on. If you want stricter control, specify a
-# list of network/mask patterns, where the mask specifies the number
-# of bits in the network part of a host address. You can also specify
-# the absolute pathname of a pattern file instead of listing the
-# patterns here.
-#
-#mynetworks = 168.100.189.0/28, 127.0.0.0/8
-#mynetworks = $config_directory/mynetworks
-
# FAST ETRN SERVICE
#
# Postfix maintains per-destination logfiles with information about
# raise eyebrows.
#
# Each message delivery transport has its XXX_destination_concurrency_limit
-# parameter. The default is $default_destination_concurrency_limit.
+# parameter. The default is $default_destination_concurrency_limit for
+# most delivery transports. For the local delivery agent the default is 2.
-local_destination_concurrency_limit = 2
-default_destination_concurrency_limit = 10
+#local_destination_concurrency_limit = 2
+#default_destination_concurrency_limit = 10
# DEBUGGING CONTROL
#
showq unix n - n - - showq
error unix - - n - - error
local unix - n n - - local
+virtual unix - n n - - virtual
lmtp unix - - n - - lmtp
cyrus unix - n n - - pipe
flags=R user=cyrus argv=/cyrus/bin/deliver -e -m ${extension} ${user}
exit 1
}
$INFO refreshing the Postfix mail system
+ $command_directory/postsuper active || exit 1
kill -HUP `sed 1q pid/master.pid`
+ $command_directory/postsuper &
;;
flush)
(echo "$found" | grep bounce >/dev/null) || missing="$missing bounce"
(echo "$found" | grep defer >/dev/null) || missing="$missing defer"
(echo "$found" | grep flush >/dev/null) || missing="$missing flush"
+ (echo "$found" | grep incoming>/dev/null)|| missing="$missing incoming"
+ (echo "$found" | grep deferred>/dev/null)|| missing="$missing deferred"
test -n "$missing" && {
$WARN fixing main.cf hash_queue_names for missing $missing
$command_directory/postconf -e hash_queue_names="$found$missing"
# See if all queue files are in the right place.
- $command_directory/postsuper || exit 1
+ $command_directory/postsuper active
+ $command_directory/postsuper &
find corrupt -type f -exec $WARN damaged message: {} \;
exit 1
}
$INFO refreshing the Postfix mail system
+ $command_directory/postsuper active || exit 1
kill -HUP `sed 1q pid/master.pid`
+ $command_directory/postsuper &
;;
flush)
(echo "$found" | grep bounce >/dev/null) || missing="$missing bounce"
(echo "$found" | grep defer >/dev/null) || missing="$missing defer"
(echo "$found" | grep flush >/dev/null) || missing="$missing flush"
+ (echo "$found" | grep incoming>/dev/null)|| missing="$missing incoming"
+ (echo "$found" | grep deferred>/dev/null)|| missing="$missing deferred"
test -n "$missing" && {
$WARN fixing main.cf hash_queue_names for missing $missing
$command_directory/postconf -e hash_queue_names="$found$missing"
# See if all queue files are in the right place.
-
- $command_directory/postsuper || exit 1
+ $command_directory/postsuper active
+ $command_directory/postsuper &
find corrupt -type f -exec $WARN damaged message: {} \;
# ldap_open(3) man page.
#
#ldap_dereference = 0
+
+# The ldap_domain parameter limits the LDAP searches to just things in
+# (exactly) the specified list of domains.
+#
+#ldap_domain =
fallback_transport =
#
-# RATE CONTROLS
+# RESOURCE CONTROLS
#
# The local_destination_concurrency_limit parameter limits the number
#
local_destination_concurrency_limit = 2
+# The mailbox_size_limit parameter controls the maximal size of a
+# mailbox or maildir file (in fact, it limits the size of any file
+# that is written to upon local delivery) The default is 50 MBytes.
+# This limit must not be set smaller than the message size limit.
+#
+mailbox_size_limit = 51200000
+
# The local_destination_recipient_limit parameter limits the number
# of recipients per local message delivery. The default limit is
# taken from the default_destination_recipient_limit parameter.
# myorigin = $mydomain
myorigin = $myhostname
-# The mynetworks parameter specifies the list of networks that are
-# local to this machine. The list is used by the anti-UCE software
-# to distinguish local clients from strangers. See permit_mynetworks
-# in the sample-smtpd.cf file.
-#
-# The mynetworks parameter specifies the list of networks that are
-# local to this machine. The list is used by the anti-UCE software
-# to distinguish local clients from strangers. See permit_mynetworks
-# and smtpd_recipient_restrictions in the file sample-smtpd.cf file.
-#
-# The default is a list of all networks attached to the machine: a
-# complete class A network (X.0.0.0/8), a complete class B network
-# (X.X.0.0/16), and so on. If you want stricter control, specify a
-# list of network/mask patterns, where the mask specifies the number
-# of bits in the network part of a host address. You can also specify
-# the absolute pathname of a pattern file instead of listing the
-# patterns here.
+# The mynetworks parameter specifies the list of "trusted" SMTP
+# clients that have more privileges than "strangers".
+#
+# In particular, "trusted" SMTP clients are allowed to relay mail
+# through Postfix. See the smtpd_recipient_restrictions parameter
+# in file sample-smtpd.cf.
+#
+# You can specify the list of "trusted" network addresses by hand
+# or you can let Postfix do it for you (which is the default).
+#
+# By default (mynetworks_style = subnet), Postfix "trusts" SMTP
+# clients in the same IP subnetworks as the local machine.
+#
+# Specify "mynetworks_style = class" when Postfix should "trust" SMTP
+# clients in the same IP class A/B/C networks as the local machine.
+# Don't do this with a dialup site - it would cause Postfix to "trust"
+# your entire provider's network. Instead, specify an explicit
+# mynetworks list by hand, as described below.
+#
+# Specify "mynetworks_style = host" when Postfix should "trust"
+# only the local machine.
+#
+# mynetworks_style = class
+# mynetworks_style = subnet
+# mynetworks_style = host
+
+# Alternatively, you can specify the mynetworks list by hand, in
+# which case Postfix ignores the mynetworks_style setting.
+#
+# Specify an explicit list of network/netmask patterns, where the
+# mask specifies the number of bits in the network part of a host
+# address.
+#
+# You can also specify the absolute pathname of a pattern file instead
+# of listing the patterns here.
#
#mynetworks = 168.100.189.0/28, 127.0.0.0/8
# UCE RESTRICTIONS
#
+# The mynetworks parameter specifies the list of "trusted" SMTP
+# clients that have more privileges than "strangers".
+#
+# In particular, "trusted" SMTP clients are allowed to relay mail
+# through Postfix. See the smtpd_recipient_restrictions parameter
+# in file sample-smtpd.cf.
+#
+# You can specify the list of "trusted" network addresses by hand
+# or you can let Postfix do it for you (which is the default).
+#
+# By default (mynetworks_style = subnet), Postfix "trusts" SMTP
+# clients in the same IP subnetworks as the local machine.
+#
+# Specify "mynetworks_style = class" when Postfix should "trust" SMTP
+# clients in the same IP class A/B/C networks as the local machine.
+# Don't do this with a dialup site - it would cause Postfix to "trust"
+# your entire provider's network. Instead, specify an explicit
+# mynetworks list by hand, as described below.
+#
+# Specify "mynetworks_style = host" when Postfix should "trust"
+# only the local machine.
+#
+# mynetworks_style = class
+mynetworks_style = subnet
+# mynetworks_style = host
+
+# Alternatively, you can specify the mynetworks list by hand, in
+# which case Postfix ignores the mynetworks_style setting.
+#
+# Specify an explicit list of network/netmask patterns, where the
+# mask specifies the number of bits in the network part of a host
+# address.
+#
+# You can also specify the absolute pathname of a pattern file instead
+# of listing the patterns here.
+#
+#mynetworks = 168.100.189.0/28, 127.0.0.0/8
+#mynetworks = $config_directory/mynetworks
+
# The smtpd_client_restrictions parameter specifies optional restrictions
# on SMTP client host names and addresses.
#
--- /dev/null
+# DO NOT EDIT THIS FILE. EDIT THE MAIN.CF FILE INSTEAD. THE STUFF
+# HERE JUST SERVES AS AN EXAMPLE.
+#
+# This file contains example settings of Postfix configuration
+# parameters that control virtual database lookups.
+
+# The virtual_maps parameter specifies optional lookup tables to
+# redirect specific addresses or even complete domains to another
+# address. This is typically used to implement virtual domain support.
+#
+# By default, no address redirection is done.
+#
+# If you use this feature, run "postmap /etc/postfix/virtual" to
+# build the necessary DBM or DB file after change.
+#
+# It may take a minute or so before the change becomes visible.
+# Use "postfix reload" to eliminate the delay.
+#
+# virtual_maps = dbm:/etc/postfix/virtual
+# virtual_maps = hash:/etc/postfix/virtual
+# virtual_maps = hash:/etc/postfix/virtual, nis:virtual
+# virtual_maps = hash:/etc/postfix/virtual, netinfo:/virtual
+virtual_maps =
DAEMONS = bounce.8.html cleanup.8.html defer.8.html error.8.html local.8.html \
lmtp.8.html master.8.html pickup.8.html pipe.8.html qmgr.8.html \
showq.8.html smtp.8.html smtpd.8.html trivial-rewrite.8.html \
- spawn.8.html flush.8.html
+ spawn.8.html flush.8.html # nqmgr.8.html virtual.8.html
COMMANDS= mailq.1.html newaliases.1.html postalias.1.html postcat.1.html \
postconf.1.html postfix.1.html postkick.1.html postlock.1.html \
postlog.1.html postdrop.1.html postmap.1.html sendmail.1.html \
master.8.html: ../src/master/master.c
srctoman $? | nroff -man | man2html | postlink >$@
+nqmgr.8.html: ../src/nqmgr/qmgr.c
+ srctoman $? | sed -e 's/qmgr[^_]/n&/' \
+ -e 's/qmgr$$/n&/' \
+ -e 's/QMGR[^_]/N&/' | \
+ nroff -man | man2html | postlink >$@
+
pickup.8.html: ../src/pickup/pickup.c
srctoman $? | nroff -man | man2html | postlink >$@
smtpd.8.html: ../src/smtpd/smtpd.c
srctoman $? | nroff -man | man2html | postlink >$@
+virtual.8.html: ../src/virtual/virtual.c
+ srctoman $? | nroff -man | man2html | postlink >$@
+
trivial-rewrite.8.html: ../src/trivial-rewrite/trivial-rewrite.c
srctoman $? | nroff -man | man2html | postlink >$@
<b>REJECT</b> Reject the address etc. that matches the pattern. A
generic error response message is generated.
- <b>OK</b>
+ <b>OK</b> Accept the address etc. that matches the pattern.
- <i>Any</i> <i>other</i> <i>text</i>
- Accept the address etc. that matches the pattern.
+ <i>restriction...</i>
+ Apply the named UCE restriction (<b>permit</b>, reject,
+ <b>reject</b><i>_</i><b>unauth</b><i>_</i><b>destination</b>, and so on).
<b>REGULAR</b> <b>EXPRESSION</b> <b>TABLES</b>
- This section describes how the table lookups change when
+ This section describes how the table lookups change when
the table is given in the form of regular expressions. For
- a description of regular expression lookup table syntax,
+ a description of regular expression lookup table syntax,
see <a href="regexp_table.5.html"><b>regexp</b><i>_</i><b>table</b>(5)</a> or <a href="pcre_table.5.html"><b>pcre</b><i>_</i><b>table</b>(5)</a>.
- Each pattern is a regular expression that is applied to
+ Each pattern is a regular expression that is applied to
the entire string being looked up. Depending on the appli-
- cation, that string is an entire client hostname, an
+ cation, that string is an entire client hostname, an
entire client IP address, or an entire mail address. Thus,
- no parent domain or parent network search is done, and
- <i>user@domain</i> mail addresses are not broken up into their
+ no parent domain or parent network search is done, and
+ <i>user@domain</i> mail addresses are not broken up into their
<i>user@</i> and <i>domain</i> constituent parts.
- Patterns are applied in the order as specified in the
- table, until a pattern is found that matches the search
+ Patterns are applied in the order as specified in the
+ table, until a pattern is found that matches the search
string.
- Actions are the same as with normal indexed file lookups,
- with the additional feature that parenthesized substrings
- from the pattern can be interpolated as <b>$1</b>, <b>$2</b> and so on.
+ Actions are the same as with normal indexed file lookups,
+ with the additional feature that parenthesized substrings
+ from the pattern can be interpolated as <b>$1</b>, <b>$2</b> and so on.
<b>BUGS</b>
- The table format does not understand quoting conventions.
-
+ The table format does not understand quoting conventions.
<a href="regexp_table.5.html">regexp_table(5)</a> format of POSIX regular expression tables
<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>
queue status. This is the program behind the <a
href="mailq.1.html">mailq</a> command.
+<p>
+
+<li>The <a href="flush.8.html">flush</a> daemon improves the
+performance of the SMTP <b>ETRN</b> request, and of its command-line
+equivalent, <b>sendmail -qR</b><i>destination</i>, for selected
+destinations. For other destinations, Postfix silently falls
+back to the equivalent of <b>sendmail -q</b>.
+
+<p>
+
+<li>The <a href="spawn.8.html">spawn</a> daemon listens on a TCP
+port, UNIX-domain socket or FIFO, and runs non-Postfix commands on
+request, with the socket or FIFO connected to the standard input,
+output and error streams. It is currently used only in an example
+of the Postfix external content filtering system.
+
</ul>
<hr>
<li> <a href="#mydestination"> What domains to receive mail for
</a>
+<p>
+
+<li> <a href="#relaying"> What clients to relay mail for </a>
</ul>
</dl>
+<a name="relaying"> <h2> What clients to relay mail for </h2> </a>
+
+By default, Postfix will relay mail for clients in authorized
+networks and in authorized domains.
+
+<p>
+
+Authorized client networks are defined by the <a
+href="#mynetworks">mynetworks</a> parameter. The default is to
+authorize all clients in the IP subnetworks that the local machine
+is attached to.
+
+<p>
+
+Authorized client domains are by defined by the <a
+href="uce.html#relay_domains"> relay_domains</a> configuration
+parameter. The default setting trusts clients with hostnames below
+the domain(s) listed in <a href="#mydestination">mydestination</a>.
+
<a name="notify"> <h2> What trouble to report to the postmaster
</h2> </a>
<a name="mynetworks"> <h2> My own networks </h2> </a>
The <b>mynetworks</b> parameter lists all networks that this machine
-is attached to. This information can be used by the <a href="uce.html">
-anti-UCE</a> features to distinguish between local systems and
-strangers.
+somehow trusts. This information can be used by the <a href="uce.html">
+anti-UCE</a> features to recognize trusted SMTP clients that are
+allowed to relay mail through Postfix.
+
+<p>
+
+You can specify the list of trusted networks in the <b>main.cf</b>
+file, or you can let Postfix deduce the list for you. The default
+is to let Postfix do the work for you.
+
+<p>
+
+<dl>
+
+<dt> Default:
+
+<dd> <b>mynetworks_style = subnet</b>
+
+<p>
+
+<dt>The meaning of the styles is as follows:
<p>
-By default, <b>mynetworks</b> is set to the class A, B or C networks
-that the machine is attached to. For example, for my machines at
-home, the result is: <b>168.100.0.0/16 127.0.0.0/8. </b> However,
-network <b>168.100</b> is owned by my ISP. Of course I do not want
-to consider all their customer systems as local, so I use instead:
+<dl>
+
+<dt> <b>class</b> <dd> Trust SMTP clients in the class A/B/C networks
+that Postfix is connected to. <b>Don't do this with a dialup site
+- it would cause Postfix to "trust" your entire provider's network.
+Instead, specify an explicit mynetworks list by hand, as described
+below</b>.
+
+<p>
+
+<dt> <b>subnet</b> (default) <dd> Trust SMTP clients in the IP
+subnetworks that Postfix is connected to.
+
+<p>
+
+<dt> <b>host</b> <dd> Trust only the local machine.
+
+</dl>
+
+</dl>
+
+<p>
+
+Alternatively, you can specify the <b>mynetworks</b> list by hand,
+in which case Postfix ignores the <b>mynetworks_style</b> setting.
+To specify the list of trusted networks by hand, specify network
+blocks in CIDR (network/mask) notation, for example:
+
+<p>
<dl>
</dl>
+<p>
+
+You can also specify the absolute pathname of a pattern file instead
+of listing the patterns in the <b>main.cf</b> file.
+
<a name="inet_interfaces"> <h2> My own network addresses </h2> </a>
The <b>inet_interfaces</b> parameter specifies all network interface
The default is to listen on all active interfaces. If you run
mailers on virtual interfaces, you will have to specify what
-interfaces to listen on. This includes the non-virtual mailer that
-receives mail for the machine itself as well: it should never listen
-on the virtual interfaces or you would have a mailer loop.
+interfaces to listen on.
+
+<p>
+
+You even have to specify explicit machine interfaces for the
+non-virtual mailer that receives mail for the machine itself: the
+non-virtual mailer should never listen on the virtual interfaces
+or you would have a mailer loop.
<dl>
<p>
+<li>The <a href="virtual.8.html">virtual</a> delivery agent is a
+very much stripped down version of the local delivery agent that
+delivers to mailboxes only. This is the most secure Postfix delivery
+agent, because it does not aliases expansions and no .forward file
+expansions.
+
+<p>
+
+This delivery agent can deliver mail for multiple domains, which
+makes it especially suitable for hosting lots of small domains on
+a single machine.
+
+<p>
+
<li>The <a href="smtp.8.html">SMTP client</a> looks up a list of
mail exchangers for the destination host, sorts the list by
preference, and tries each address in turn until it finds a server
<p>
+<li>The <a href="lmtp.8.html">LMTP client</a> speaks a protocol
+similar to SMTP. The client can connect to local or remote mailbox
+servers such as Cyrus. All the queue management is done by Postfix.
+The advantage of this setup is that one Postfix machine can feed
+multiple mailbox servers over LMTP. The opposite is true as well:
+one mailbox server can be fed over LMTP by multiple Postfix machines.
+
+<p>
+
<li>The <a href="pipe.8.html">pipe mailer</a> is the outbound
interface to other mail transports (the <a
href="sendmail.1.html">sendmail</a> program is the inbound interface).
requests from the queue manager. Each request specifies a
queue file, a sender address, a domain or host name that
is treated as the reason for non-delivery, and recipient
- information. This program expects to be run from the <a href="master.8.html"><b>mas-</b>
- <b>ter</b>(8)</a> process manager.
+ information. This program expects to be run from the <a href="master.8.html"><b>mas-</b></a>
+ <a href="master.8.html"><b>ter</b>(8)</a> process manager.
The error mailer client forces all recipients to bounce,
using the domain or host information as the reason for
<ul>
+<li><a href="#poppers">POP or IMAP problems</a>
+
+<li><a href="#warnings">Postfix warnings and error messages</a>
+
<li><a href="#example_config">Example configurations</a>
<li><a href="#sendmail_incompatibility">Sendmail incompatibility</a>
+<li><a href="#moby">Running hundreds of Postfix processes</a>
+
<li><a href="#performance">Postfix performance</a>
<li><a href="#receiving">Receiving mail via the network</a>
<p>
+<a name="warnings"><h3>Postfix warnings and error messages</h3>
+
+<ul>
+
+<li><a href="#biff">What does "biff_notify: Connection refused" mean?</a>
+
+<li><a href="#nisdom">What does "NIS domain name not set - NIS lookups disabled" mean?</a>
+
+<li><a href="#dns-again">Mail stays queued with: Host not found, try again</a>
+
+<li><a href="#timeouts">Mail fails consistently with timeout or lost connection</a>
+
+<li><a href="#noalias">What does "fatal: open database /etc/aliases.db" mean?</a>
+
+<li><a href="#nosuid">sendmail has set-uid root file permissions, or is run from a set-uid root process</a>
+
+</ul>
+
+<p>
+
<a name="example_config"><h3>Example configurations</h3>
<ul>
</ul>
+<p>
+
<a name="sendmail_incompatibility"><h3>Sendmail incompatibility</h3>
<ul>
</ul>
+<a name="moby"><h3>Running hundreds of Postfix processes</h3>
+
+<ul>
+
+<li><a href="#moby-freebsd">Running hundreds of Postfix processes on FreeBSD</a>
+
+<li><a href="#moby-linux">Running hundreds of Postfix processes on Linux</a>
+
+</ul>
+
+
<a name="performance"><h3>Postfix performance</h3>
<ul>
-<li><a href="#incoming">Too much mail in the incoming queue</a>
+<li><a href="#incoming">Mail stays queued in the incoming queue</a>
<li><a href="#delay">Postfix responds slowly to incoming SMTP connections</a>
<ul>
-<li><a href="#dns-again">All remote mail stays queued with: Host not found, try again</a>
+<li><a href="#dns-again">Mail stays queued with: Host not found, try again</a>
<li><a href="#timeouts">Mail fails consistently with timeout or lost connection</a>
<li><a href="#biff">What does "biff_notify: Connection refused" mean?</a>
+<li><a href="#nisdom">What does "NIS domain name not set - NIS lookups disabled" mean?</a>
+
<li><a href="#bogus">Postfix accepts mail for non-existing local users</a>
<li><a href="#some_local">Delivering some users locally while
<li><a href="#owner-foo">Postfix ignores the owner-list alias</a>
+<li><a href="#noalias">What does "fatal: open database /etc/aliases.db" mean?</a>
+
</ul>
<a name="mailing_lists"><h3>Mailing lists</h3>
<hr>
+<a name="poppers"><h3>POP or IMAP problems</h3>
+
+Postfix is a mail delivery system. Postfix does not implement
+services such as POP or IMAP to read mail. Several POP/IMAP
+implementations exist that can cooperate with software such as
+Postfix.
+
+<p>
+
+Examples of software that is used successfully with Postfix:
+
+<p>
+
+<ul>
+
+<li><a href="http://asg.web.cmu.edu/cyrus/">Cyrus IMAP</a> implements
+IMAP, POP3, and KPOP, later versions also support TLS. This software
+implements its own private mail database system. Not for beginners.
+
+<p>
+
+<li><a href="http://www.inter7.com/courierimap/">Courier-Imap</a>
+provides POP3, IMAP, POP3 and IMAP, and supports access over SSL.
+This software supports the maildir-style mailbox format only
+(one message per file, same format as qmail).
+
+<p>
+
+<li><a href="http://www.eudora.com/qpopper/">Qpopper</a> supports
+POP3, TLS (SSL), and uses the traditional UNIX-style mailbox format
+(multiple messages per file, each message starts with "From sender date...").
+
+</ul>
+
+<p>
+
+<hr>
+
<a name="stand_alone"><h3>Stand-alone machine</h3>
Out of the box, Postfix should work without change on a stand-alone
-machine that is has direct Internet access. At least, that is how
+machine that has direct Internet access. At least, that is how
Postfix installs when you download the Postfix source code. If you
are on a firewalled intranet, or if your machine is dial-up connected
only a small part of the time, see the respective sections.
<p>
How to set up Postfix on the firewall machine so that it relays
-mail for <i>my.domain</i> to a gateway machine on the inside, and
-so that it refuses mail for <i>*.my.domain</i>? The problem is that
-the standard <a href="uce.html#relay_domains">relay_domains</a>
-mail relaying restriction allows mail to <i>*.my.domain</i> when
-you specify <i>my.domain</i>.
+mail for <i>domain.com</i> to a gateway machine on the inside, and
+so that it refuses mail for <i>*.domain.com</i>? The problem is that
+the default <a href="uce.html#relay_domains">relay_domains</a>
+mail relaying restriction allows mail to <i>*.domain.com</i> when
+you specify <i>domain.com</i>.
<p>
<ul>
-<li>Specify a null <a href="uce.html#relay_domains">relay_domains</a>
-parameter plus a <a href="transport.5.html">transport</a> table to
-route mail for <i>my.domain</i> to the inside machine:
+<li>Specify a <a href="transport.5.html">transport</a> table to
+route mail for <i>domain.com</i> to the inside machine.
+
+<p>
+
+Specify explicit settings for <a
+href="uce.html#smtpd_recipient_restrictions">smtpd_recipient_restrictions</a>
+and for <a href="basic.html#mynetworks">mynetworks</a> that allow
+local systems to send mail anywhere, and that allow remote systems
+to send mail only to <i>user@domain.com</i>.
<p>
<pre>
/etc/postfix/main.cf:
- mydestination = $myhostname, my.domain, localhost.my.domain
- relay_domains =
+ myorigin = domain.com
+ mydestination = domain.com
transport_maps = hash:/etc/postfix/transport
+ mynetworks = 12.34.56.0/24
+ smtpd_recipient_restrictions = permit_mynetworks reject_unauth_destination
/etc/postfix/transport:
- my.domain smtp:inside-gateway.my.domain (forwards user@domain)
- .my.domain smtp:inside-gateway.my.domain (forwards user@firewall)
+ domain.com smtp:inside-gateway.domain.com (forwards user@domain)
/etc/postfix/master.cf:
Comment out the local delivery agent
<hr>
-<a name="incoming"><h3>Too much mail in the incoming queue</h3></a>
+<a name="noalias"><h3>What does "fatal: open database /etc/aliases.db" mean?</h3></a>
+
+Your aliases database is corrupt or it is missing. Execute the
+following command as root:
+
+<p>
+
+<pre>
+ # newaliases
+</pre>
+
+<hr>
+
+<a name="nosuid"><h1>sendmail has set-uid root file permissions, or is run from a
+set-uid root process</h3></a>
+
+Traditionally, the UNIX <b>sendmail</b> command is installed with
+set-uid root permissions. Even many MTAs other than Sendmail ship
+with a set-uid root <b>sendmail</b> command. This is not the case
+with Postfix. The Postfix <b>sendmail</b> command is designed not
+to be set-uid.
+
+<p>
+
+Unfortunately, some Linux systems have a helpful utility called
+<b>linuxconf</b> that automatically "fixes" file permissions to
+what they are supposed to be for Sendmail's <b>sendmail</b> command.
+Even when you reset the set-uid bit on the Postfix <b>sendmail</b>
+executable file, <b>linuxconf</b> will happily turn it on again
+for you.
+
+<p>
+
+On SuSE systems the file permission fixing utulity is called
+<b>SuSEconfig</b>. Other Linux systems may use different names.
+The usual disclaimers about mileages etc. apply.
+
+<p>
+
+<h4>Solutions</h4>
+
+<ul>
+
+<li>Rask Ingemann Lambertsen has a particularly effective
+solution :-)
+
+<blockquote>
+<pre>
+# /etc/rc.d/init.d/linuxconf stop && rpm --erase linuxconf
+</pre>
+</blockquote>
+
+<li>According to Matthias Andree, the band-aid fix for SuSE is to
+add to /etc/permissions.local the following line:
+
+<blockquote>
+<pre>
+/usr/sbin/sendmail root.root 755
+</pre>
+</blockquote>
+
+and to make sure that in /etc/rc.config,
+PERMISSIONS_SECURITY mentions local last, EXAMPLE:
+
+<blockquote>
+<pre>
+CHECK_PERMISSIONS=set
+PERMISSION_SECURITY="secure local"
+</pre>
+</blockquote>
+
+</ul>
+
+<hr>
+
+<a name="moby-freebsd"><h3>Running hundreds of Postfix processes on FreeBSD</h3></a>
+
+With hundreds of Postfix processes, the kernel will eventually
+run out of file handles; after that, it will run out of sockets.
+
+<p>
+
+To set kernel parameters at boot time, add the following lines to
+the <b>/boot/loader.conf</b> file (this is specific to FreeBSD 4.x):
+
+<p>
+
+<blockquote>
+<pre>
+kern.ipc.maxsockets="5000"
+kern.maxfiles="16384"
+kern.maxfilesperproc="16384"
+kern.ipc.nmbclusters="65536"
+</pre>
+</blockquote>
+
+<p>
+
+To set kernel parameters at run time execute the following commands
+as root (this is specific to FreeBSD 4.x):
+
+<p>
+
+<blockquote>
+<pre>
+# sysctl -w kern.ipc.maxsockets=5000
+# sysctl -w kern.maxfiles=16384
+# sysctl -w kern.maxfilesperproc=16384
+# sysctl -w kern.ipc.nmbclusters=65536
+</pre>
+</blockquote>
+
+<hr>
+
+<a name="moby-linux"><h3>Running hundreds of Postfix processes on Linux</h3></a>
+
+When you increase the number of Postfix processes into the hundreds,
+the kernel will eventually run out of file handles; after that it
+is likely to run out of process slots.
+
+<p>
+
+The following information is kernel version dependent.
+
+<p>
+
+To set parameters at boot time on Linux systems that have
+<b>/etc/sysctl.conf</b>, add the following lines:
+
+<p>
+
+<blockquote>
+<pre>
+fs.file-max = 16384
+kernel.threads-max = 2048
+</pre>
+</blockquote>
+
+<p>
+
+To set kernel parameters at run time, execute the following
+commands as <b>root</b>:
+
+<p>
+
+<blockquote>
+<pre>
+# echo 16384 > /proc/sys/fs/file-max
+# echo 2048 > /proc/sys/kernel/threads-max
+</pre>
+</blockquote>
+
+<hr>
+
+<a name="incoming"><h3>Mail stays queued in the incoming queue</h3></a>
<blockquote>
<p>
-I am still solving the scheduling problem from the software side.
+I am still solving the scheduling problem from the software side,
+but don't hold your breath.
<p>
Currently, the workaround is to configure multiple IP addresses
-per machine, and to run one Postfix instance per IP address. The
-Postfix instances can't share queue directories, but sharing mailbox
-directories is OK.
+per machine, and to run one Postfix instance per IP address, each
+instance preferably on a different disk. The Postfix instances
+can't share queue directories, but sharing mailbox directories is
+OK.
<p>
<p>
<pre>
- queue_directory = /my/own/queue/directory
- myhostname = foo1.my.domain
- inet_interfaces = $myhostname
+ /my/own/main.cf:
+ queue_directory = /my/own/queue/directory
+ myhostname = foo1.my.domain
+ inet_interfaces = $myhostname
</pre>
<hr>
<a name="backup"><h3>Configuring Postfix as backup MX host</h3></a>
-When you are SECONDARY MX for some other domain this is all you need:
+When you are <b>secondary mx</b> for a <b>remote site</b> this is
+all you need:
<p>
the.backed-up.domain.name IN MX 100 your.machine.name
/etc/postfix/main.cf:
- relay_domains = the.backed-up.domain.name
+ relay_domains = $mydestination the.backed-up.domain.name
+ smtpd_recipient_restrictions = permit_mynetworks check_relay_domains
</pre>
<p>
-When you are PRIMARY MX for some other domain you also need:
+When you are <b>primary mx</b> for a <b>remote site</b> you also
+need:
<p>
<hr>
-<a name="dns-again"><h3>All remote mail stays queued with: Host not found, try again</h3></a>
+<a name="dns-again"><h3>Mail stays queued with: Host not found, try again</h3></a>
<blockquote>
-When I connect send mail to a remote address, the following happens:
+When I send mail to a remote address, the following happens:
<p>
service error for domain recip.domain: Host not found, try again)
</pre>
+<p>
+
+However, I can nslookup the hostname just fine.
+
</blockquote>
<p>
+There can be several different problems.
+
+<p>
+
+<ul>
+
+<li> First of all, the result of nslookup for the hostname may be
+irrelevant. Postfix is required to look up the MX record first. So
+your nslookup test should begin with asking for the MX record. Some
+DNS servers are broken and produce no reply when asked for a
+non-existent MX record.
+
+<p> <li>
+
Check out your Postfix <b>master.cf</b> file. If the SMTP client
runs chrooted, then it needs a bunch of files inside the Postfix
queue directory. Examples are in the source distribution in the
<b>examples</b> subdirectory.
+</ul>
+
<hr>
<a name="timeouts"><h3>Mail fails consistently with timeout or lost connection</h3></a>
<p>
However, when you see mail deliveries fail consistently, you may
-have a different problem: broken path MTU discovery.
+have a different problem: broken path MTU discovery. Or it could
+be a broken PIX firewall.
+
+<h4>Cisco PIX "fixup protocol smtp" bug</h4>
+
+The Cisco PIX firewall has a bug when running software older than
+version 5.2(4) or 6.0(1).
+
+<p>
+
+The bug ID is CSCds90792. The "fixup protocol smtp" feature does
+not correctly handle the case where the "." and the "CRLF" at the
+end of mail are sent in separate packets.
+
+<p>
+
+How does one recognize a mailer behind a Cisco PIX with "fixup
+protocol smtp" enabled? As of version 5.1 and later, the fixup
+protocol smtp command changes the characters in the SMTP banner to
+asterisks except for the "2", "0" and "0 SPACE" characters.
<p>
+When you connect to a mailer behind such a filter you see something
+like:
+
+<blockquote>
+<pre>
+220 **************************************0******0*********20 ****200**0*********0*00
+</pre>
+</blockquote>
+
+<h4>IP path MTU discovery</h4>
+
A little background is in order. With the SMTP protocol, the HELO,
MAIL FROM and RCPT TO commands and responses are relatively short.
When you're talking to sendmail, every command and every response
<p>
To enable the <b>comsat</b> network service, uncomment the
-corresponding entry in the <b>inetd.conf</b> file.
+corresponding entry in the <b>inetd.conf</b> file, and <b>kill -HUP</b>
+the <b>inetd</b> process.
+
+<hr>
+
+<a name="nisdom"><h3>What does "NIS domain name not set - NIS lookups disabled" mean?</h3>
+
+<p>
+
+The warning message means that NIS (Network Information Service)
+is not enabled on your machine. That is perfectly OK. It's just
+hard for Postfix to find out about these things ahead of time.
+
+<p>
+
+To disable the <b>NIS</b> client code in the Postfix local delivery agent,
+update the corresponding section in the <b>main.cf</b> file and specify
+one of the following, depending on the type of aliases file:
+
+<p>
+
+<pre>
+/etc/postfix/main.cf:
+ alias_maps = $alias_database
+</pre>
+
+<p>
+
+This forces Postfix to use only the local aliases database, if one
+is defined.
<hr>
<pre>
/etc/postfix/master.cf:
- fax unix - n n - - pipe
+ fax unix - n n - 1 pipe
flags= user=fax argv=/usr/bin/faxmail -d -n ${user}
/etc/postfix/transport:
<p>
+The process limit of 1 in the <b>master.cf</b> file is necessary
+with fax software that cannot handle multiple requests at the same
+time. It won't hurt otherwise.
+
+<p>
+
The <b>fax_destination_recipient_limit</b> entry (by Simon, Mr.
Simix) is necessary with fax software that can't have more than
one destination on its command line. It won't hurt otherwise.
<p>
-Note: be sure to not advertise <b>fax.your.domain</b> in the DNS...
+Note: be sure to not advertise <b>fax.your.domain</b> in the DNS :-)
<hr>
<a name="deleting"><h3>Deleting a message from the Postfix queue</h3></a>
-To delete ONE message with queue id ABCDEF from the Postfix queue,
-it is not necessary to stop Postfix.
+To delete ONE message with queue id ABCDEF (e.g., from <b>mailq</b>
+output) from the Postfix queue, it is not necessary to stop Postfix.
<p>
<p>
-If you have to delete a large amount of mail, it is safer to stop
-Postfix first.
+If you have to delete a large amount of mail, you must stop Postfix
+first.
<p>
<pre>
<p>
-Do not use the above command on a running Postfix system, because
-it can delete files that belong to new mail that arrives while you
-are deleting queue files.
+Do not use the above <b>find</b> command on a running Postfix
+system, because it can delete files that belong to new mail that
+arrives while you are deleting queue files.
<hr>
<p>
What is Postfix? It is <a href="http://www.porcupine.org/wietse/">Wietse
-Venema's</a> attempt to provide an alternative to the widely-used
-<a href="http://www.sendmail.org/">Sendmail</a> program. Sendmail
-is responsible for most of the e-mail delivered on the Internet.
-With an estimated 100 million users, that's billions of messages
-daily. A stunning number.
+Venema's</a> mailer that started life as an alternative to the
+widely-used <a href="http://www.sendmail.org/">Sendmail</a> program.
<p>
Postfix attempts to be fast, easy to administer, and secure, while
at the same time being sendmail compatible enough to not upset
-existing users.
+existing users. Thus, the outside has a sendmail-ish flavor, but
+the inside is completely different.
<hr>
specified in the Postfix <a href="transport.5.html"><b>transport</b>(5)</a> table, has the form:
<b>unix</b>:<i>pathname</i>
- Connect to the UNIX-domain server that is bound to
- the specified <i>pathname</i>. If the process runs
- chrooted, an absolute pathname is interpreted rela-
- tive to the changed root directory.
+ Connect to the local UNIX-domain server that is
+ bound to the specified <i>pathname</i>. If the process
+ runs chrooted, an absolute pathname is interpreted
+ relative to the changed root directory.
<b>inet</b>:<i>host</i>, <b>inet:</b><i>host</i>:<i>port</i> (symbolic host)
<b>inet</b>:[<i>addr</i>], <b>inet</b>:[<i>addr</i>]:<i>port</i> (numeric host)
Connect to the specified IPV4 TCP port on the spec-
- ified host. If no port is specified, connect to the
- port defined as <b>lmtp</b> in <b>services</b>(4). If no such
- service is found, the <b>lmtp</b><i>_</i><b>tcp</b><i>_</i><b>port</b> configuration
- parameter (default value of 24) will be used.
+ ified local or remote host. If no port is speci-
+ fied, connect to the port defined as <b>lmtp</b> in <b>ser-</b>
+ <b>vices</b>(4). If no such service is found, the
+ <b>lmtp</b><i>_</i><b>tcp</b><i>_</i><b>port</b> configuration parameter (default
+ value of 24) will be used.
- The LMTP client does not perform MX (mail
+ The LMTP client does not perform MX (mail
exchanger) lookups since those are defined only for
mail delivery via SMTP.
<b>SECURITY</b>
The LMTP client is moderately security-sensitive. It talks
- to LMTP servers and to DNS servers on the network. The
+ to LMTP servers and to DNS servers on the network. The
LMTP client can be run chrooted at fixed low privilege.
<b>STANDARDS</b>
<a href="http://www.faqs.org/rfcs/rfc821.html">RFC 821</a> (SMTP protocol)
<a href="http://www.faqs.org/rfcs/rfc1651.html">RFC 1651</a> (SMTP service extensions)
- <a href="http://www.faqs.org/rfcs/rfc1870.html">RFC 1870</a> (Message Size Declaration)
LMTP(8) LMTP(8)
+ <a href="http://www.faqs.org/rfcs/rfc1870.html">RFC 1870</a> (Message Size Declaration)
<a href="http://www.faqs.org/rfcs/rfc2033.html">RFC 2033</a> (LMTP protocol)
<a href="http://www.faqs.org/rfcs/rfc2197.html">RFC 2197</a> (Pipelining)
+ <a href="http://www.faqs.org/rfcs/rfc2554.html">RFC 2554</a> (AUTH command)
<b>DIAGNOSTICS</b>
- Problems and transactions are logged to <b>syslogd</b>(8). Cor-
- rupted message files are marked so that the queue manager
+ Problems and transactions are logged to <b>syslogd</b>(8). Cor-
+ rupted message files are marked so that the queue manager
can move them to the <b>corrupt</b> queue for further inspection.
- Depending on the setting of the <b>notify</b><i>_</i><b>classes</b> parameter,
- the postmaster is notified of bounces, protocol problems,
+ Depending on the setting of the <b>notify</b><i>_</i><b>classes</b> parameter,
+ the postmaster is notified of bounces, protocol problems,
and of other trouble.
<b>BUGS</b>
<b>CONFIGURATION</b> <b>PARAMETERS</b>
- The following <b>main.cf</b> parameters are especially relevant
- to this program. See the Postfix <b>main.cf</b> file for syntax
- 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>debug</b><i>_</i><b>peer</b><i>_</i><b>level</b>
- Verbose logging level increment for hosts that
+ Verbose logging level increment for hosts that
match a pattern in the <b>debug</b><i>_</i><b>peer</b><i>_</i><b>list</b> parameter.
<b>debug</b><i>_</i><b>peer</b><i>_</i><b>list</b>
- List of domain or network patterns. When a remote
- host matches a pattern, increase the verbose log-
- ging level by the amount specified in the
+ List of domain or network patterns. When a remote
+ host matches a pattern, increase the verbose log-
+ ging level by the amount specified in the
<b>debug</b><i>_</i><b>peer</b><i>_</i><b>level</b> parameter.
<b>error</b><i>_</i><b>notice</b><i>_</i><b>recipient</b>
- Recipient of protocol/policy/resource/software
+ Recipient of protocol/policy/resource/software
error notices.
<b>notify</b><i>_</i><b>classes</b>
- When this parameter includes the <b>protocol</b> class,
- send mail to the postmaster with transcripts of
+ When this parameter includes the <b>protocol</b> class,
+ send mail to the postmaster with transcripts of
LMTP sessions with protocol errors.
<b>lmtp</b><i>_</i><b>skip</b><i>_</i><b>quit</b><i>_</i><b>response</b>
- Do not wait for the server response after sending
+ Do not wait for the server response after sending
QUIT.
<b>lmtp</b><i>_</i><b>tcp</b><i>_</i><b>port</b>
- The TCP port to be used when connecting to a LMTP
- server. Used as backup if the <b>lmtp</b> service is not
+ The TCP port to be used when connecting to a LMTP
+ server. Used as backup if the <b>lmtp</b> service is not
found in <b>services</b>(4).
-<b>Resource</b> <b>controls</b>
- <b>lmtp</b><i>_</i><b>cache</b><i>_</i><b>connection</b>
- Should we cache the connection to the LMTP server?
- The effectiveness of cached connections will be
- determined by the number of LMTP servers in use,
- and the concurrency limit specified for the LMTP
+<b>Authentication</b> <b>controls</b>
+ <b>lmtp</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
LMTP(8) LMTP(8)
+ support.
+
+ <b>lmtp</b><i>_</i><b>sasl</b><i>_</i><b>password</b><i>_</i><b>maps</b>
+ Lookup tables with per-host or domain <i>name</i>:<i>password</i>
+ entries. No entry for a host means no attempt to
+ authenticate.
+
+ <b>lmtp</b><i>_</i><b>sasl</b><i>_</i><b>security</b><i>_</i><b>options</b>
+ Zero or more of the following.
+
+ <b>noplaintext</b>
+ Disallow authentication methods that use
+ plaintext passwords.
+
+ <b>noactive</b>
+ Disallow authentication methods that are
+ vulnerable to non-dictionary active attacks.
+
+ <b>nodictionary</b>
+ Disallow authentication methods that are
+ vulnerable to passive dictionary attack.
+
+ <b>noanonymous</b>
+ Disallow anonymous logins.
+
+<b>Resource</b> <b>controls</b>
+ <b>lmtp</b><i>_</i><b>cache</b><i>_</i><b>connection</b>
+ Should we cache the connection to the LMTP server?
+ The effectiveness of cached connections will be
+ determined by the number of LMTP servers in use,
+ and the concurrency limit specified for the LMTP
client. Cached connections are closed under any of
the following conditions:
- <b>o</b> The LMTP client idle time limit is reached.
- This limit is specified with the Postfix
+ <b>o</b> The LMTP client idle time limit is reached.
+ This limit is specified with the Postfix
<b>max</b><i>_</i><b>idle</b> configuration parameter.
- <b>o</b> A delivery request specifies a different
+ <b>o</b> A delivery request specifies a different
destination than the one currently cached.
<b>o</b> The per-process limit on the number of
delivery requests is reached. This limit is
- specified with the Postfix <b>max</b><i>_</i><b>use</b> configu-
+ specified with the Postfix <b>max</b><i>_</i><b>use</b> configu-
ration parameter.
- <b>o</b> Upon the onset of another delivery request,
- the LMTP server associated with the current
- session does not respond to the <b>RSET</b> com-
+ <b>o</b> Upon the onset of another delivery request,
+ the LMTP server associated with the current
+ session does not respond to the <b>RSET</b> com-
mand.
<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 via this mail delivery transport.
- <i>transport</i> is the name of the service as specified
- in the <b>master.cf</b> file. 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>
+ destination via this mail delivery transport.
+
+
+
+ 3
+
+
+
+
+
+LMTP(8) LMTP(8)
+
+
+ <i>transport</i> is the name of the service as specified
+ in the <b>master.cf</b> file. 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.
<i>transport_</i><b>destination</b><i>_</i><b>recipient</b><i>_</i><b>limit</b>
Limit the number of recipients per message delivery
- via this mail delivery transport. <i>transport</i> is the
- name of the service as specified in the <b>master.cf</b>
- file. The default limit is taken from the
+ via this mail delivery transport. <i>transport</i> is the
+ name of the service as specified in the <b>master.cf</b>
+ file. 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.
- This parameter becomes significant if the LMTP
- client is used for local delivery. Some LMTP
- servers can optimize delivery of the same message
+ This parameter becomes significant if the LMTP
+ client is used for local delivery. Some LMTP
+ servers can optimize delivery of the same message
to multiple recipients. The default limit for local
mail delivery is 1.
Setting this parameter to 0 will lead to an
- unbounded number of recipients per delivery. How-
- ever, this could be risky since it may make the
- machine vulnerable to running out of resources if
- messages are encountered with an inordinate number
- of recipients. Exercise care when setting this
+ unbounded number of recipients per delivery. How-
+ ever, this could be risky since it may make the
+ machine vulnerable to running out of resources if
+ messages are encountered with an inordinate number
+ of recipients. Exercise care when setting this
parameter.
<b>Timeout</b> <b>controls</b>
- The default time unit is seconds; an explicit time unit
- can be specified by appending a one-letter suffix to the
- value: s (seconds), m (minutes), h (hours), d (days) or w
+ The default time unit is seconds; an explicit time unit
+ can be specified by appending a one-letter suffix to the
+ value: s (seconds), m (minutes), h (hours), d (days) or w
(weeks).
-
-
- 3
-
-
-
-
-
-LMTP(8) LMTP(8)
-
-
<b>lmtp</b><i>_</i><b>connect</b><i>_</i><b>timeout</b>
Timeout for opening a connection to the LMTP
- server. If no connection can be made within the
+ server. If no connection can be made within the
deadline, the message is deferred.
<b>lmtp</b><i>_</i><b>lhlo</b><i>_</i><b>timeout</b>
- Timeout for sending the <b>LHLO</b> command, and for
+ Timeout for sending the <b>LHLO</b> command, and for
receiving the server response.
<b>lmtp</b><i>_</i><b>mail</b><i>_</i><b>timeout</b>
- Timeout for sending the <b>MAIL</b> <b>FROM</b> command, and for
+ Timeout for sending the <b>MAIL</b> <b>FROM</b> command, and for
receiving the server response.
<b>lmtp</b><i>_</i><b>rcpt</b><i>_</i><b>timeout</b>
- Timeout for sending the <b>RCPT</b> <b>TO</b> command, and for
+ Timeout for sending the <b>RCPT</b> <b>TO</b> command, and for
receiving the server response.
<b>lmtp</b><i>_</i><b>data</b><i>_</i><b>init</b><i>_</i><b>timeout</b>
- Timeout for sending the <b>DATA</b> command, and for
+ Timeout for sending the <b>DATA</b> command, and for
receiving the server response.
+
+
+
+
+ 4
+
+
+
+
+
+LMTP(8) LMTP(8)
+
+
<b>lmtp</b><i>_</i><b>data</b><i>_</i><b>xfer</b><i>_</i><b>timeout</b>
Timeout for sending the message content.
<b>lmtp</b><i>_</i><b>data</b><i>_</i><b>done</b><i>_</i><b>timeout</b>
Timeout 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 be
+ receiving the server response. When no response is
+ received, a warning is logged that the mail may be
delivered multiple times.
<b>lmtp</b><i>_</i><b>rset</b><i>_</i><b>timeout</b>
- Timeout for sending the <b>RSET</b> command, and for
+ Timeout for sending the <b>RSET</b> command, and for
receiving the server response.
<b>lmtp</b><i>_</i><b>quit</b><i>_</i><b>timeout</b>
- Timeout for sending the <b>QUIT</b> command, and for
+ Timeout for sending the <b>QUIT</b> command, and for
receiving the server response.
<b>SEE</b> <b>ALSO</b>
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
-
-
-
-
-
-LMTP(8) LMTP(8)
-
-
P.O. Box 704
Yorktown Heights, NY 10598, USA
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
5
Postfix queue manager to deliver mail to local recipients.
Each delivery request specifies a queue file, a sender
address, a domain or host to deliver to, and one or more
- recipients. This program expects to be run from the <a href="master.8.html"><b>mas-</b>
- <b>ter</b>(8)</a> process manager.
+ recipients. This program expects to be run from the <a href="master.8.html"><b>mas-</b></a>
+ <a href="master.8.html"><b>ter</b>(8)</a> process manager.
The <b>local</b> daemon updates queue files and marks recipients
as finished, or it informs the queue manager that delivery
<b>recipient</b><i>_</i><b>delimiter</b>
Separator between username and address extension.
- <b>test</b><i>_</i><b>home</b><i>_</i><b>directory</b>
+ <b>require</b><i>_</i><b>home</b><i>_</i><b>directory</b>
Require that a recipient's home directory is acces-
sible by the recipient before attempting delivery.
+ Defer delivery otherwise.
<b>Mailbox</b> <b>delivery</b>
<b>fallback</b><i>_</i><b>transport</b>
External command to use for mailbox delivery. The
command executes with the recipient privileges
(exception: root). The string is subject to $name
- expansions.
LOCAL(8) LOCAL(8)
+ expansions.
+
<b>mailbox</b><i>_</i><b>transport</b>
Message transport to use for mailbox delivery to
all local recipients, whether or not they are found
<b>stale</b><i>_</i><b>lock</b><i>_</i><b>time</b>
Limit the time after which a stale lock is removed.
- <b>mailbox</b><i>__</i><b>delivery</b><i>_</i><b>lock</b>
+ <b>mailbox</b><i>_</i><b>delivery</b><i>_</i><b>lock</b>
What file locking method(s) to use when delivering
to a UNIX-style mailbox. The default setting is
system dependent. For a list of available file
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>Security</b> <b>controls</b>
- <b>allow</b><i>_</i><b>mail</b><i>_</i><b>to</b><i>_</i><b>commands</b>
- Restrict the usage of mail delivery to external
- command.
-
-
+ <b>mailbox</b><i>_</i><b>size</b><i>_</i><b>limit</b>
+ Limit the size of a mailbox etc. file (any file
+ that is written to upon delivery). Set to zero to
+ disable the limit.
LOCAL(8) LOCAL(8)
+<b>Security</b> <b>controls</b>
+ <b>allow</b><i>_</i><b>mail</b><i>_</i><b>to</b><i>_</i><b>commands</b>
+ Restrict the usage of mail delivery to external
+ command. Specify zero or more of: <b>alias</b>, <b>forward</b>,
+ <b>include</b>.
+
<b>allow</b><i>_</i><b>mail</b><i>_</i><b>to</b><i>_</i><b>files</b>
- Restrict the usage of mail delivery to external
- file.
+ Restrict the usage of mail delivery to external
+ file. Specify zero or more of: <b>alias</b>, <b>forward</b>,
+ <b>include</b>.
<b>command</b><i>_</i><b>expansion</b><i>_</i><b>filter</b>
What characters are allowed to appear in $name
-
-
-
-
-
-
-
8
and with group write permission to the <b>maildrop</b> queue
directory.
- The <b>postdrop</b> command is automatically invoked by the <a href="sendmail.1.html"><b>send-</b>
- <b>mail</b>(1)</a> mail posting agent when the <b>maildrop</b> queue direc-
+ The <b>postdrop</b> command is automatically invoked by the <a href="sendmail.1.html"><b>send-</b></a>
+ <a href="sendmail.1.html"><b>mail</b>(1)</a> mail posting agent when the <b>maildrop</b> queue direc-
tory is not world-writable.
Options:
<b>DESCRIPTION</b>
The <b>qmgr</b> daemon awaits the arrival of incoming mail and
arranges for its delivery via Postfix delivery processes.
- The actual mail routing strategy is delegated to the <a href="trivial-rewrite.8.html"><b>triv-</b>
- <b>ial-rewrite</b>(8)</a> daemon. This program expects to be run
+ The actual mail routing strategy is delegated to the <a href="trivial-rewrite.8.html"><b>triv-</b></a>
+ <a href="trivial-rewrite.8.html"><b>ial-rewrite</b>(8)</a> daemon. This program expects to be run
from the <a href="master.8.html"><b>master</b>(8)</a> process manager.
Mail addressed to the local <b>double-bounce</b> address is
For example, allow <a href="http://www.faqs.org/rfcs/rfc822.html">RFC822</a>-style address forms with
comments, like Sendmail does.
- <b>allow</b><i>_</i><b>broken</b><i>_</i><b>auth</b><i>_</i><b>clients</b>
+ <b>broken</b><i>_</i><b>sasl</b><i>_</i><b>auth</b><i>_</i><b>clients</b>
Support older Microsoft clients that mis-implement
the AUTH protocol, and that expect an EHLO response
of "250 AUTH=list" instead of "250 AUTH list".
same syntax as the right-hand side of a Postfix
transport table.
-<b>Authenication</b> <b>controls</b>
+<b>Authentication</b> <b>controls</b>
<b>enable</b><i>_</i><b>sasl</b><i>_</i><b>authentication</b>
Enable per-session authentication as per <a href="http://www.faqs.org/rfcs/rfc2554.html">RFC 2554</a>
(SASL). This functionality is available only when
explicitly selected at program build time and
explicitly enabled at runtime.
+ <b>smtpd</b><i>_</i><b>sasl</b><i>_</i><b>local</b><i>_</i><b>domain</b>
+ The name of the local authentication realm.
+
<b>smtpd</b><i>_</i><b>sasl</b><i>_</i><b>security</b><i>_</i><b>options</b>
Zero or more of the following.
<b>command</b><i>_</i><b>directory</b>
Location of Postfix support commands (default:
- <b>$program</b><i>_</i><b>directory</b>).
-
-
SMTPD(8) SMTPD(8)
+ <b>$program</b><i>_</i><b>directory</b>).
+
<b>debug</b><i>_</i><b>peer</b><i>_</i><b>level</b>
Increment in verbose logging level when a remote
host matches a pattern in the <b>debug</b><i>_</i><b>peer</b><i>_</i><b>list</b>
<b>soft</b><i>_</i><b>bounce</b>
Change hard (5xx) reject responses into soft (4xx)
reject responses. This can be useful for testing
- purposes.
-
SMTPD(8) SMTPD(8)
+ purposes.
+
<b>Resource</b> <b>controls</b>
<b>line</b><i>_</i><b>length</b><i>_</i><b>limit</b>
Limit the amount of memory in bytes used for the
Restrict what sender addresses are allowed in <b>MAIL</b>
<b>FROM</b> commands.
- <b>smtpd</b><i>_</i><b>recipient</b><i>_</i><b>restrictions</b>
- Restrict what recipient addresses are allowed in
- <b>RCPT</b> <b>TO</b> commands.
+
SMTPD(8) SMTPD(8)
+ <b>smtpd</b><i>_</i><b>recipient</b><i>_</i><b>restrictions</b>
+ Restrict what recipient addresses are allowed in
+ <b>RCPT</b> <b>TO</b> commands.
+
<b>smtpd</b><i>_</i><b>etrn</b><i>_</i><b>restrictions</b>
Restrict what domain names can be used in <b>ETRN</b> com-
mands, and what clients may issue <b>ETRN</b> commands.
Server response when a client violates the
<b>reject</b><i>_</i><b>unknown</b><i>_</i><b>address</b> restriction.
- <b>unknown</b><i>_</i><b>client</b><i>_</i><b>reject</b><i>_</i><b>code</b>
- Server response when a client without address to
- name mapping violates the <b>reject</b><i>_</i><b>unknown</b><i>_</i><b>clients</b>
- restriction.
SMTPD(8) SMTPD(8)
+ <b>unknown</b><i>_</i><b>client</b><i>_</i><b>reject</b><i>_</i><b>code</b>
+ Server response when a client without address to
+ name mapping violates the <b>reject</b><i>_</i><b>unknown</b><i>_</i><b>clients</b>
+ restriction.
+
<b>unknown</b><i>_</i><b>hostname</b><i>_</i><b>reject</b><i>_</i><b>code</b>
Server response when a client violates the
<b>reject</b><i>_</i><b>unknown</b><i>_</i><b>hostname</b> restriction.
-
-
-
-
-
The <b>trivial-rewrite</b> daemon by default only distin-
guishes between local and non-local mail. For finer
- control over mail routing, use the optional <a href="transport.5.html"><b>trans-</b>
- <b>port</b>(5)</a> lookup table.
+ control over mail routing, use the optional <a href="transport.5.html"><b>trans-</b></a>
+ <a href="transport.5.html"><b>port</b>(5)</a> lookup table.
This program expects to be run from the <a href="master.8.html"><b>master</b>(8)</a> process
manager.
<dt>Syntax:
<dd>Specify a list of zero or more lookup tables. Whenever a header
-matches a table, a REJECT result means reject the message.
+matches a table, a REJECT result means reject the message, and a
+SKIP result means delete the header from the message.
<p>
<dt>Default:
-<dd><b>maps_rbl_domains = rbl.maps.vix.com, dul.maps.vix.com</b>
+<dd><b>maps_rbl_domains = blackholes.mail-abuse.org</b>
<p>
RANLIB=echo
SYSLIBS="-lresolv -lsocket -lnsl"
;;
-Rhapsody.5*|Darwin.1.2*)
+Rhapsody.5*|Darwin.1.*)
SYSTYPE=RHAPSODY5
# Use the native compiler by default
: ${CC=cc}
DAEMONS = man8/bounce.8 man8/defer.8 man8/cleanup.8 man8/error.8 man8/local.8 \
man8/lmtp.8 man8/master.8 man8/pickup.8 man8/pipe.8 man8/qmgr.8 \
man8/showq.8 man8/smtp.8 man8/smtpd.8 man8/trivial-rewrite.8 \
- man8/spawn.8 man8/flush.8
+ man8/spawn.8 man8/flush.8 # man8/nqmgr.8 man8/virtual.8
COMMANDS= man1/postalias.1 man1/postcat.1 man1/postconf.1 man1/postfix.1 \
man1/postkick.1 man1/postlock.1 man1/postlog.1 man1/postdrop.1 \
man1/postmap.1 man1/sendmail.1 man1/mailq.1 man1/newaliases.1 \
man8/master.8: ../src/master/master.c
../mantools/srctoman $? >$@
+man8/nqmgr.8: ../src/nqmgr/qmgr.c
+ ../mantools/srctoman $? | \
+ sed -e 's/qmgr[^_]/n&/' \
+ -e 's/qmgr$$/n&/' \
+ -e 's/QMGR[^_]/N&/' >$@
+
man8/pickup.8: ../src/pickup/pickup.c
../mantools/srctoman $? >$@
man8/smtpd.8: ../src/smtpd/smtpd.c
../mantools/srctoman $? >$@
+man8/virtual.8: ../src/virtual/virtual.c
+ ../mantools/srctoman $? >$@
+
man8/trivial-rewrite.8: ../src/trivial-rewrite/trivial-rewrite.c
../mantools/srctoman $? >$@
Reject the address etc. that matches the pattern. A generic
error response message is generated.
.IP \fBOK\fR
-.IP "\fIAny other text\fR"
Accept the address etc. that matches the pattern.
+.IP \fIrestriction...\fR
+Apply the named UCE restriction (\fBpermit\fR, \fRreject\fR,
+\fBreject_unauth_destination\fR, and so on).
.SH REGULAR EXPRESSION TABLES
.na
.nf
delivery request. The destination, usually specified in the Postfix
\fBtransport\fR(5) table, has the form:
.IP \fBunix\fR:\fIpathname\fR
-Connect to the UNIX-domain server that is bound to the specified
+Connect to the local UNIX-domain server that is bound to the specified
\fIpathname\fR. If the process runs chrooted, an absolute pathname
is interpreted relative to the changed root directory.
.IP "\fBinet\fR:\fIhost\fR, \fBinet\fB:\fIhost\fR:\fIport\fR (symbolic host)"
.IP "\fBinet\fR:[\fIaddr\fR], \fBinet\fR:[\fIaddr\fR]:\fIport\fR (numeric host)"
-Connect to the specified IPV4 TCP port on the specified host. If no
-port is specified, connect to the port defined as \fBlmtp\fR in
-\fBservices\fR(4).
+Connect to the specified IPV4 TCP port on the specified local or
+remote host. If no port is specified, connect to the port defined as
+\fBlmtp\fR in \fBservices\fR(4).
If no such service is found, the \fBlmtp_tcp_port\fR configuration
parameter (default value of 24) will be used.
RFC 1870 (Message Size Declaration)
RFC 2033 (LMTP protocol)
RFC 2197 (Pipelining)
+RFC 2554 (AUTH command)
.SH DIAGNOSTICS
.ad
.fi
.IP \fBlmtp_tcp_port\fR
The TCP port to be used when connecting to a LMTP server. Used as
backup if the \fBlmtp\fR service is not found in \fBservices\fR(4).
+.SH "Authentication controls"
+.IP \fBlmtp_enable_sasl_auth\fR
+Enable per-session authentication as per RFC 2554 (SASL).
+By default, Postfix is built without SASL support.
+.IP \fBlmtp_sasl_password_maps\fR
+Lookup tables with per-host or domain \fIname\fR:\fIpassword\fR entries.
+No entry for a host means no attempt to authenticate.
+.IP \fBlmtp_sasl_security_options\fR
+Zero or more of the following.
+.RS
+.IP \fBnoplaintext\fR
+Disallow authentication methods that use plaintext passwords.
+.IP \fBnoactive\fR
+Disallow authentication methods that are vulnerable to non-dictionary
+active attacks.
+.IP \fBnodictionary\fR
+Disallow authentication methods that are vulnerable to passive
+dictionary attack.
+.IP \fBnoanonymous\fR
+Disallow anonymous logins.
+.RE
.SH "Resource controls"
.ad
.fi
forwarding mail is not recommended.
.IP \fBrecipient_delimiter\fR
Separator between username and address extension.
-.IP \fBtest_home_directory\fR
+.IP \fBrequire_home_directory\fR
Require that a recipient's home directory is accessible by the
-recipient before attempting delivery.
+recipient before attempting delivery. Defer delivery otherwise.
.SH Mailbox delivery
.ad
.fi
an exclusive lock.
.IP \fBstale_lock_time\fR
Limit the time after which a stale lock is removed.
-.IP \fBmailbox__delivery_lock\fR
+.IP \fBmailbox_delivery_lock\fR
What file locking method(s) to use when delivering to a UNIX-style
mailbox.
The default setting is system dependent. For a list of available
Limit the number of recipients per message delivery.
The default limit is taken from the
\fBdefault_destination_recipient_limit\fR parameter.
+.IP \fBmailbox_size_limit\fR
+Limit the size of a mailbox etc. file (any file that is
+written to upon delivery).
+Set to zero to disable the limit.
.SH "Security controls"
.ad
.fi
.IP \fBallow_mail_to_commands\fR
Restrict the usage of mail delivery to external command.
+Specify zero or more of: \fBalias\fR, \fBforward\fR, \fBinclude\fR.
.IP \fBallow_mail_to_files\fR
Restrict the usage of mail delivery to external file.
+Specify zero or more of: \fBalias\fR, \fBforward\fR, \fBinclude\fR.
.IP \fBcommand_expansion_filter\fR
What characters are allowed to appear in $name expansions of
mailbox_command. Illegal characters are replaced by underscores.
.IP \fBstrict_rfc821_envelopes\fR
Disallow non-RFC 821 style addresses in envelopes. For example,
allow RFC822-style address forms with comments, like Sendmail does.
-.IP \fBallow_broken_auth_clients\fR
+.IP \fBbroken_sasl_auth_clients\fR
Support older Microsoft clients that mis-implement the AUTH
protocol, and that expect an EHLO response of "250 AUTH=list"
instead of "250 AUTH list".
either bounces mail or re-injects the result back into Postfix.
This parameter uses the same syntax as the right-hand side of
a Postfix transport table.
-.SH "Authenication controls"
+.SH "Authentication controls"
.IP \fBenable_sasl_authentication\fR
Enable per-session authentication as per RFC 2554 (SASL).
This functionality is available only when explicitly selected
at program build time and explicitly enabled at runtime.
+.IP \fBsmtpd_sasl_local_domain\fR
+The name of the local authentication realm.
.IP \fBsmtpd_sasl_security_options\fR
Zero or more of the following.
.RS
srctoman extract man page from source file
usage: srctoman file.suffix
usage: srctoman -type file
+
+man2html quick script to htmlize nroff -man output
+
+postlink quick script to hyperlink man2html output
--- /dev/null
+#!/bin/sh
+
+# Crude script to convert formatted manual pages to HTML
+
+echo '<html> <head> </head> <body> <pre>'
+
+sed '
+ s/\([<>&]\)\b\1/\1/g
+ s/&/\&/g
+ s/</\</g
+ s/>/\>/g
+ s;_\b\(.\);<i>\1</i>;g
+ s;.\b\(.\);<b>\1</b>;g
+ s;</i><i>;;g
+ s;</b><b>;;g
+' "$@"
+
+echo '</pre> </body> </html>'
--- /dev/null
+#!/bin/sh
+
+# Crude script to make formatted Postfix man pages clickable.
+# RFC links by Ralf Hildebrandt.
+
+exec sed '
+ :again
+ /-[</bB>]*$/{
+ N
+ b again
+ }
+ s/[<bB>]*bounce[</bB>]*(8)/<a href="bounce.8.html">&<\/a>/
+ s/[<bB>]*cleanup[</bB>]*(8)/<a href="cleanup.8.html">&<\/a>/
+ s/[<bB>]*defer[</bB>]*(8)/<a href="defer.8.html">&<\/a>/
+ s/[<bB>]*error[</bB>]*(8)/<a href="error.8.html">&<\/a>/
+ s/[<bB>]*flush[</bB>]*(8)/<a href="flushd.8.html">&<\/a>/
+ s/[<bB>]*local[</bB>]*(8)/<a href="local.8.html">&<\/a>/
+ s/[<bB>]*mas[-</bB>]*\n*[ <bB>]*ter[</bB>]*(8)/<a href="master.8.html">&<\/a>/
+ s/[<bB>]*pickup[</bB>]*(8)/<a href="pickup.8.html">&<\/a>/
+ s/[<bB>]*pipe[</bB>]*(8)/<a href="pipe.8.html">&<\/a>/
+ s/[<bB>]*qmgr[</bB>]*(8)/<a href="qmgr.8.html">&<\/a>/
+ s/[<bB>]*showq[</bB>]*(8)/<a href="showq.8.html">&<\/a>/
+ s/[<bB>]*smtp[</bB>]*(8)/<a href="smtp.8.html">&<\/a>/
+ s/[<bB>]*smtpd[</bB>]*(8)/<a href="smtpd.8.html">&<\/a>/
+ s/[<bB>]*spawn[</bB>]*(8)/<a href="spawn.8.html">&<\/a>/
+ s/[<bB>]*triv[-</bB>]*\n*[ <bB>]*ial[-</bB>]*\n*[ <bB>]*rewrite[</bB>]*(8)/<a href="trivial-rewrite.8.html">&<\/a>/
+ s/[<bB>]*mailq[</bB>]*(1)/<a href="mailq.1.html">&<\/a>/
+ s/[<bB>]*newaliases[</bB>]*(1)/<a href="newaliases.1.html">&<\/a>/
+ s/[<bB>]*postalias[</bB>]*(1)/<a href="postalias.1.html">&<\/a>/
+ s/[<bB>]*postcat[</bB>]*(1)/<a href="postcat.1.html">&<\/a>/
+ s/[<bB>]*postconf[</bB>]*(1)/<a href="postconf.1.html">&<\/a>/
+ s/[<bB>]*postdrop[</bB>]*(1)/<a href="postdrop.1.html">&<\/a>/
+ s/[<bB>]*postfix[</bB>]*(1)/<a href="postfix.1.html">&<\/a>/
+ s/[<bB>]*postkick[</bB>]*(1)/<a href="postkick.1.html">&<\/a>/
+ s/[<bB>]*postlock[</bB>]*(1)/<a href="postlock.1.html">&<\/a>/
+ s/[<bB>]*postlog[</bB>]*(1)/<a href="postlog.1.html">&<\/a>/
+ s/[<bB>]*postmap[</bB>]*(1)/<a href="postmap.1.html">&<\/a>/
+ s/[<bB>]*send[-</bB>]*\n*[ <bB>]*mail[</bB>]*(1)/<a href="sendmail.1.html">&<\/a>/
+ s/[<bB>]*access[</bB>]*(5)/<a href="access.5.html">&<\/a>/
+ s/[<bB>]*aliases[</bB>]*(5)/<a href="aliases.5.html">&<\/a>/
+ s/[<bB>]*canonical[</bB>]*(5)/<a href="canonical.5.html">&<\/a>/
+ s/[<bB>]*etrn[</bB>]*(5)/<a href="etrn.5.html">&<\/a>/
+ s/[<bB>]*pcre[</bBiI>]*_[</iIbB>]*table[</bB>]*(5)/<a href="pcre_table.5.html">&<\/a>/
+ s/[<bB>]*regexp[</bBiI>]*_[</iIbB>]*table[</bB>]*(5)/<a href="regexp_table.5.html">&<\/a>/
+ s/[<bB>]*relocated[</bB>]*(5)/<a href="relocated.5.html">&<\/a>/
+ s/[<bB>]*trans[-</bB>]*\n*[ <bB>]*port[</bB>]*(5)/<a href="transport.5.html">&<\/a>/
+ s/[<bB>]*virtual[</bB>]*(5)/<a href="virtual.5.html">&<\/a>/
+ s/[<bB>]*virtual[</bB>]*(8)/<a href="virtual.8.html">&<\/a>/
+ s/\(<a href="[^"]*">\)\([<bB>]*[a-z0-9-]*[-</bB>]*\)\(\n *\)\([<bB>]*[a-z0-9-]*[</bB>]*([0-9])\)\(<\/a>\)/\1\2\5\3\1\4\5/
+ s/RFC *\([0-9]*\)/<a href="http:\/\/www.faqs.org\/rfcs\/rfc\1.html">&<\/a>/
+' "$@"
# Reject the address etc. that matches the pattern. A generic
# error response message is generated.
# .IP \fBOK\fR
-# .IP "\fIAny other text\fR"
# Accept the address etc. that matches the pattern.
+# .IP \fIrestriction...\fR
+# Apply the named UCE restriction (\fBpermit\fR, \fRreject\fR,
+# \fBreject_unauth_destination\fR, and so on).
# REGULAR EXPRESSION TABLES
# .ad
# .fi
len = res_search((char *) name, C_IN, type, reply->buf, sizeof(reply->buf));
if (len < 0) {
if (why)
- vstring_sprintf(why, "Name service error for domain %s: %s",
+ vstring_sprintf(why, "Name service error for %s: %s",
name, dns_strerror(h_errno));
if (msg_verbose)
msg_info("dns_query: %s (%s): %s",
return (DNS_OK);
}
+/* valid_rr_name - validate hostname in resource record */
+
+static int valid_rr_name(const char *name, const char *location,
+ unsigned type, DNS_REPLY *reply)
+{
+ char temp[DNS_NAME_LEN];
+ char *query_name;
+ int len;
+ char *gripe;
+ int result;
+
+ /*
+ * People aren't supposed to specify numeric names where domain names are
+ * required, but it "works" with some mailers anyway, so people complain
+ * when software doesn't bend over backwards.
+ */
+#define PASS_NAME 1
+#define REJECT_NAME 0
+
+ if (valid_hostaddr(name, DONT_GRIPE)) {
+ result = PASS_NAME;
+ gripe = "numeric domain name";
+ } else if (!valid_hostname(name, DO_GRIPE)) {
+ result = REJECT_NAME;
+ gripe = "malformed domain name";
+ } else {
+ result = PASS_NAME;
+ gripe = 0;
+ }
+
+ /*
+ * If we have a gripe, show some context, including the name used in the
+ * query and the type of reply that we're looking at.
+ */
+ if (gripe) {
+ len = dn_expand(reply->buf, reply->end, reply->query_start,
+ temp, DNS_NAME_LEN);
+ query_name = (len < 0 ? "*unparsable*" : temp);
+ msg_warn("%s in %s of %s record for %s: %.100s",
+ gripe, location, dns_strtype(type), query_name, name);
+ }
+ return (result);
+}
+
/* dns_get_rr - extract resource record from name server reply */
static DNS_RR *dns_get_rr(DNS_REPLY *reply, unsigned char *pos,
case T_PTR:
if (dn_expand(reply->buf, reply->end, pos, temp, sizeof(temp)) < 0)
return (0);
- if (!valid_hostname(temp))
+ if (!valid_rr_name(temp, "resource data", fixed->type, reply))
return (0);
data_len = strlen(temp) + 1;
break;
GETSHORT(pref, pos);
if (dn_expand(reply->buf, reply->end, pos, temp, sizeof(temp)) < 0)
return (0);
- if (!valid_hostname(temp))
+ if (!valid_rr_name(temp, "resource data", fixed->type, reply))
return (0);
data_len = strlen(temp) + 1;
break;
msg_panic("dns_get_alias: bad type %s", dns_strtype(fixed->type));
if (dn_expand(reply->buf, reply->end, pos, cname, c_len) < 0)
return (DNS_RETRY);
- if (!valid_hostname(cname))
+ if (!valid_rr_name(cname, "resource data", fixed->type, reply))
return (DNS_RETRY);
return (DNS_OK);
}
len = dn_expand(reply->buf, reply->end, pos, rr_name, DNS_NAME_LEN);
if (len < 0)
CORRUPT;
- if (!valid_hostname(rr_name))
- CORRUPT;
- if (fqdn)
- vstring_strcpy(fqdn, rr_name);
pos += len;
/*
CORRUPT;
if (dns_get_fixed(pos, &fixed) != DNS_OK)
CORRUPT;
+ if (!valid_rr_name(rr_name, "resource name", fixed.type, reply))
+ CORRUPT;
+ if (fqdn)
+ vstring_strcpy(fqdn, rr_name);
if (msg_verbose)
msg_info("dns_get_answer: type %s for %s",
dns_strtype(fixed.type), rr_name);
/*
* The Linux resolver misbehaves when given an invalid domain name.
*/
- if (!valid_hostname(name)) {
+ if (!valid_hostname(name, DONT_GRIPE)) {
if (why)
vstring_sprintf(why, "Name service error for %s: invalid name",
name);
#ifdef T_A
T_A, "A",
#endif
+#ifdef T_AAAA
+ T_AAAA, "AAAA",
+#endif
#ifdef T_NS
T_NS, "NS",
#endif
site = vstring_alloc(10);
queue_id = vstring_alloc(10);
if (mail_command_read(client_stream, "%s %s", site, queue_id) == 2
- && valid_hostname(STR(site))
+ && valid_hostname(STR(site), DONT_GRIPE)
&& mail_queue_id_ok(STR(queue_id)))
status = flush_add_service(lowercase(STR(site)), STR(queue_id));
mail_print(client_stream, "%d", status);
} else if (STREQ(STR(request), FLUSH_REQ_SEND)) {
site = vstring_alloc(10);
if (mail_command_read(client_stream, "%s", site) == 1
- && valid_hostname(STR(site)))
+ && valid_hostname(STR(site), DONT_GRIPE))
status = flush_send_service(lowercase(STR(site)));
mail_print(client_stream, "%d", status);
} else if (STREQ(STR(request), FLUSH_REQ_REFRESH)
deliver_flock.o: ../../include/vstring.h
deliver_flock.o: ../../include/vbuf.h
deliver_flock.o: ../../include/myflock.h
+deliver_flock.o: ../../include/iostuff.h
deliver_flock.o: mail_params.h
deliver_flock.o: deliver_flock.h
deliver_pass.o: deliver_pass.c
dot_lockfile.o: ../../include/vbuf.h
dot_lockfile.o: ../../include/stringops.h
dot_lockfile.o: ../../include/mymalloc.h
+dot_lockfile.o: ../../include/iostuff.h
dot_lockfile.o: mail_params.h
dot_lockfile.o: dot_lockfile.h
dot_lockfile_as.o: dot_lockfile_as.c
is_header.o: is_header.c
is_header.o: ../../include/sys_defs.h
is_header.o: is_header.h
-local_transport.o: local_transport.c
-local_transport.o: ../../include/sys_defs.h
-local_transport.o: ../../include/msg.h
-local_transport.o: ../../include/mymalloc.h
-local_transport.o: string_list.h
-local_transport.o: mail_params.h
-local_transport.o: local_transport.h
mail_addr.o: mail_addr.c
mail_addr.o: ../../include/sys_defs.h
mail_addr.o: ../../include/stringops.h
mkmap_open.o: ../../include/vstream.h
mkmap_open.o: ../../include/vbuf.h
mkmap_open.o: ../../include/argv.h
+mkmap_open.o: ../../include/dict_db.h
+mkmap_open.o: ../../include/dict_dbm.h
mkmap_open.o: ../../include/sigdelay.h
mkmap_open.o: ../../include/mymalloc.h
mkmap_open.o: ../../include/myflock.h
mynetworks.o: ../../include/vstring.h
mynetworks.o: ../../include/vbuf.h
mynetworks.o: ../../include/inet_addr_list.h
+mynetworks.o: ../../include/name_mask.h
mynetworks.o: own_inet_addr.h
+mynetworks.o: mail_params.h
mynetworks.o: mynetworks.h
mypwd.o: mypwd.c
mypwd.o: ../../include/sys_defs.h
#include <vstring.h>
#include <myflock.h>
+#include <iostuff.h>
/* Global library. */
#include "mail_params.h"
#include "deliver_flock.h"
+/* Application-specific. */
+
+#define MILLION 1000000
+
/* deliver_flock - lock open file for mail delivery */
int deliver_flock(int fd, int lock_style, VSTRING *why)
return (0);
if (i >= var_flock_tries)
break;
- sleep(var_flock_delay);
+ rand_sleep(var_flock_delay * MILLION, var_flock_delay * MILLION / 2);
}
if (why)
vstring_sprintf(why, "unable to lock for exclusive access: %m");
/* DIAGNOSTICS
/* dot_lockfile() returns 0 upon success. In case of failure, the
/* result is -1, and the errno variable is set appropriately:
-/* EEXIST when a "fresh" lock file already exists; other values as
+/* EEXIST when a "fresh" lock file already exists; other values as
/* appropriate.
/* CONFIGURATION PARAMETERS
/* deliver_lock_attempts, how many times to try to create a lock
#include <vstring.h>
#include <stringops.h>
#include <mymalloc.h>
+#include <iostuff.h>
/* Global library. */
#include "mail_params.h"
#include "dot_lockfile.h"
+/* Application-specific. */
+
+#define MILLION 1000000
+
/* dot_lockfile - create user.lock file */
int dot_lockfile(const char *path, VSTRING *why)
if (errno != ENOENT)
break;
- sleep(var_flock_delay);
+ rand_sleep(var_flock_delay * MILLION, var_flock_delay * MILLION / 2);
}
if (status && why)
vstring_sprintf(why, "unable to create lock file %s: %m", lock_file);
/* char *var_relay_domains;
/* char *var_fflush_domains;
/* char *var_def_transport;
+/* char *var_mynetworks_style;
/*
/* char *var_import_environ;
/* char *var_export_environ;
char *var_relay_domains;
char *var_fflush_domains;
char *var_def_transport;
+char *var_mynetworks_style;
char *var_import_environ;
char *var_export_environ;
VAR_INET_INTERFACES, DEF_INET_INTERFACES, &var_inet_interfaces, 1, 0,
VAR_DOUBLE_BOUNCE, DEF_DOUBLE_BOUNCE, &var_double_bounce_sender, 1, 0,
VAR_DEFAULT_PRIVS, DEF_DEFAULT_PRIVS, &var_default_privs, 1, 0,
- VAR_ALIAS_DB_MAP, DEF_ALIAS_DB_MAP, &var_alias_db_map, 1, 0,
+ VAR_ALIAS_DB_MAP, DEF_ALIAS_DB_MAP, &var_alias_db_map, 0, 0,
VAR_MAIL_VERSION, DEF_MAIL_VERSION, &var_mail_version, 1, 0,
VAR_DB_TYPE, DEF_DB_TYPE, &var_db_type, 1, 0,
VAR_HASH_QUEUE_NAMES, DEF_HASH_QUEUE_NAMES, &var_hash_queue_names, 1, 0,
VAR_EXPORT_ENVIRON, DEF_EXPORT_ENVIRON, &var_export_environ, 0, 0,
VAR_IMPORT_ENVIRON, DEF_IMPORT_ENVIRON, &var_import_environ, 0, 0,
VAR_DEF_TRANSPORT, DEF_DEF_TRANSPORT, &var_def_transport, 0, 0,
+ VAR_MYNETWORKS_STYLE, DEF_MYNETWORKS_STYLE, &var_mynetworks_style, 1, 0,
0,
};
static CONFIG_STR_FN_TABLE function_str_defaults_2[] = {
* the domain.
*/
get_mail_conf_str_fn_table(function_str_defaults);
- if (!valid_hostname(var_myhostname) || !valid_hostname(var_mydomain))
- msg_fatal("host or domain name configuration error");
+ if (!valid_hostname(var_myhostname, DO_GRIPE)
+ || !valid_hostname(var_mydomain, DO_GRIPE))
+ msg_fatal("main.cf configuration error: bad %s or %s parameter value",
+ VAR_MYHOSTNAME, VAR_MYDOMAIN);
/*
* Variables that are needed by almost every program.
* Standards violation: send "250 AUTH=list" in order to accomodate broken
* Microsoft clients.
*/
-#define VAR_BROKEN_AUTH_CLNTS "allow_broken_auth_clients"
+#define VAR_BROKEN_AUTH_CLNTS "broken_sasl_auth_clients"
#define DEF_BROKEN_AUTH_CLNTS 0
extern bool var_broken_auth_clients;
#define VAR_MAILBOX_LOCK "mailbox_delivery_lock"
extern char *var_mailbox_lock;
+ /*
+ * Mailbox size limit. This used to be enforced as a side effect of the way
+ * the message size limit is implemented, but that is not clean.
+ */
+#define VAR_MAILBOX_LIMIT "mailbox_size_limit"
+#define DEF_MAILBOX_LIMIT (DEF_MESSAGE_LIMIT * 5)
+extern int var_mailbox_limit;
+
/*
* Miscellaneous.
*/
*/
#define VAR_DELIVERY_SLOT_COST "default_delivery_slot_cost"
#define _DELIVERY_SLOT_COST "_delivery_slot_cost"
-#define DEF_DELIVERY_SLOT_COST 10
+#define DEF_DELIVERY_SLOT_COST 5
extern int var_delivery_slot_cost;
#define VAR_DELIVERY_SLOT_LOAN "default_delivery_slot_loan"
#define _DELIVERY_SLOT_LOAN "_delivery_slot_loan"
-#define DEF_DELIVERY_SLOT_LOAN 5
+#define DEF_DELIVERY_SLOT_LOAN 3
extern int var_delivery_slot_loan;
#define VAR_DELIVERY_SLOT_DISCOUNT "default_delivery_slot_discount"
#define DEF_DEST_CON_LIMIT 10
extern int var_dest_con_limit;
+#define VAR_LOCAL_CON_LIMIT "local" _DEST_CON_LIMIT
+#define DEF_LOCAL_CON_LIMIT 2
+extern int var_local_con_lim;
+
/*
* Queue manager: default number of recipients per transaction.
*/
#define VAR_LOCAL_RCPT_LIMIT "local" _DEST_RCPT_LIMIT /* XXX */
#define DEF_LOCAL_RCPT_LIMIT 1 /* XXX */
+extern int var_local_rcpt_lim;
/*
* Queue manager: default delay before retrying a dead transport.
* subdirectories, and how deep the forest is.
*/
#define VAR_HASH_QUEUE_NAMES "hash_queue_names"
-#define DEF_HASH_QUEUE_NAMES "active,bounce,defer,flush"
+#define DEF_HASH_QUEUE_NAMES "incoming,active,deferred,bounce,defer,flush"
extern char *var_hash_queue_names;
#define VAR_HASH_QUEUE_DEPTH "hash_queue_depth"
#define DEF_SMTP_SASL_OPTS "noplaintext, noanonymous"
extern char *var_smtp_sasl_opts;
+ /*
+ * LMTP server. The soft error limit determines how many errors an LMTP
+ * client may make before we start to slow down; the hard error limit
+ * determines after how many client errors we disconnect.
+ */
+#define VAR_LMTPD_BANNER "lmtpd_banner"
+#define DEF_LMTPD_BANNER "$myhostname $mail_name"
+extern char *var_lmtpd_banner;
+
+#define VAR_LMTPD_TMOUT "lmtpd_timeout"
+#define DEF_LMTPD_TMOUT "300s"
+extern int var_lmtpd_tmout;
+
+#define VAR_LMTPD_RCPT_LIMIT "lmtpd_recipient_limit"
+#define DEF_LMTPD_RCPT_LIMIT 1000
+extern int var_lmtpd_rcpt_limit;
+
+#define VAR_LMTPD_SOFT_ERLIM "lmtpd_soft_error_limit"
+#define DEF_LMTPD_SOFT_ERLIM 10
+extern int var_lmtpd_soft_erlim;
+
+#define VAR_LMTPD_HARD_ERLIM "lmtpd_hard_error_limit"
+#define DEF_LMTPD_HARD_ERLIM 100
+extern int var_lmtpd_hard_erlim;
+
+#define VAR_LMTPD_ERR_SLEEP "lmtpd_error_sleep_time"
+#define DEF_LMTPD_ERR_SLEEP "5s"
+extern int var_lmtpd_err_sleep;
+
+#define VAR_LMTPD_JUNK_CMD "lmtpd_junk_command_limit"
+#define DEF_LMTPD_JUNK_CMD 1000
+extern int var_lmtpd_junk_cmd_limit;
+
+ /*
+ * SASL authentication support, LMTP server side.
+ */
+#define VAR_LMTPD_SASL_ENABLE "lmtpd_sasl_auth_enable"
+#define DEF_LMTPD_SASL_ENABLE 0
+extern bool var_lmtpd_sasl_enable;
+
+#define VAR_LMTPD_SASL_OPTS "lmtpd_sasl_security_options"
+#define DEF_LMTPD_SASL_OPTS "noanonymous"
+extern char *var_lmtpd_sasl_opts;
+
+#define VAR_LMTPD_SASL_REALM "lmtpd_sasl_local_domain"
+#define DEF_LMTPD_SASL_REALM "$myhostname"
+extern char *var_lmtpd_sasl_realm;
+
/*
* SASL authentication support, LMTP client side.
*/
* When locking a mailbox, how often to try and how long to wait.
*/
#define VAR_FLOCK_TRIES "deliver_lock_attempts"
-#define DEF_FLOCK_TRIES 10
+#define DEF_FLOCK_TRIES 20
extern int var_flock_tries;
#define VAR_FLOCK_DELAY "deliver_lock_delay"
#define VAR_MYNETWORKS "mynetworks"
extern char *var_mynetworks;
+#define VAR_MYNETWORKS_STYLE "mynetworks_style"
+#define DEF_MYNETWORKS_STYLE MYNETWORKS_STYLE_SUBNET
+extern char *var_mynetworks_style;
+
+#define MYNETWORKS_STYLE_CLASS "class"
+#define MYNETWORKS_STYLE_SUBNET "subnet"
+#define MYNETWORKS_STYLE_HOST "host"
+
#define VAR_RELAY_DOMAINS "relay_domains"
#define DEF_RELAY_DOMAINS "$mydestination"
extern char *var_relay_domains;
#define REJECT_INVALID_HOSTNAME "reject_invalid_hostname"
#define VAR_BAD_NAME_CODE "invalid_hostname_reject_code"
-#define DEF_BAD_NAME_CODE 501
+#define DEF_BAD_NAME_CODE 501 /* SYNTAX */
extern int var_bad_name_code;
#define REJECT_UNKNOWN_HOSTNAME "reject_unknown_hostname"
#define REJECT_NON_FQDN_SENDER "reject_non_fqdn_sender"
#define REJECT_NON_FQDN_RCPT "reject_non_fqdn_recipient"
#define VAR_NON_FQDN_CODE "non_fqdn_reject_code"
-#define DEF_NON_FQDN_CODE 504
+#define DEF_NON_FQDN_CODE 504 /* POLICY */
extern int var_non_fqdn_code;
#define REJECT_UNKNOWN_SENDDOM "reject_unknown_sender_domain"
/*
* Tunables for the "virtual" local delivery agent
*/
-#define VAR_VIRT_MAILBOX_MAPS "virtual_mailbox_maps"
-#define DEF_VIRT_MAILBOX_MAPS ""
-extern char *var_mailbox_maps;
+#define VAR_VIRT_MAILBOX_MAPS "virtual_mailbox_maps"
+#define DEF_VIRT_MAILBOX_MAPS ""
+extern char *var_virt_mailbox_maps;
-#define VAR_VIRT_UID_MAPS "virtual_uid_maps"
-#define DEF_VIRT_UID_MAPS ""
-extern char *var_uid_maps;
+#define VAR_VIRT_UID_MAPS "virtual_uid_maps"
+#define DEF_VIRT_UID_MAPS ""
+extern char *var_virt_uid_maps;
-#define VAR_VIRT_GID_MAPS "virtual_gid_maps"
-#define DEF_VIRT_GID_MAPS ""
-extern char *var_gid_maps;
+#define VAR_VIRT_GID_MAPS "virtual_gid_maps"
+#define DEF_VIRT_GID_MAPS ""
+extern char *var_virt_gid_maps;
-#define VAR_VIRT_USEDOTLOCK "virtual_usedotlock"
-#define DEF_VIRT_USEDOTLOCK 0
-extern bool var_virt_usedotlock;
-
-#define VAR_VIRT_MINUID "virtual_minimum_uid"
-#define DEF_VIRT_MINUID 100
+#define VAR_VIRT_MINUID "virtual_minimum_uid"
+#define DEF_VIRT_MINUID 100
extern int var_virt_minimum_uid;
-#define VAR_VIRT_MAILBOX_BASE "virtual_mailbox_base"
-#define DEF_VIRT_MAILBOX_BASE ""
+#define VAR_VIRT_MAILBOX_BASE "virtual_mailbox_base"
+#define DEF_VIRT_MAILBOX_BASE ""
extern char *var_virt_mailbox_base;
+#define VAR_VIRT_MAILBOX_LIMIT "virtual_mailbox_limit"
+#define DEF_VIRT_MAILBOX_LIMIT (5 * DEF_MESSAGE_LIMIT)
+extern int var_virt_mailbox_limit;
+
+#define VAR_VIRT_MAILBOX_LOCK "virtual_mailbox_lock"
+#define DEF_VIRT_MAILBOX_LOCK "fcntl"
+extern char *var_virt_mailbox_lock;
+
/* LICENSE
/* .ad
/* .fi
/*
* OK if in valid hostname form.
*/
- return (valid_hostname(queue_id));
+ return (valid_hostname(queue_id, DO_GRIPE));
}
/* mail_queue_enter - make mail queue entry with locally-unique name */
*/
if ((fp = vstream_fopen(path, flags, mode)) == 0)
if (errno == ENOENT)
- if ((flags & O_CREAT) == O_CREAT && mail_queue_mkdirs(path) == 0)
- fp = vstream_fopen(path, flags, mode);
+ if ((flags & O_CREAT) == O_CREAT && mail_queue_mkdirs(path) == 0)
+ fp = vstream_fopen(path, flags, mode);
return (fp);
}
* Version of this program.
*/
#define VAR_MAIL_VERSION "mail_version"
-#define DEF_MAIL_VERSION "Release-20010120"
+#define DEF_MAIL_VERSION "Release-20010228"
extern char *var_mail_version;
/* LICENSE
#include <msg.h>
#include <dict.h>
+#include <dict_db.h>
+#include <dict_dbm.h>
#include <sigdelay.h>
#include <mymalloc.h>
#include <myflock.h>
MKMAP_OPEN_INFO mkmap_types[] = {
#ifdef HAS_DBM
- "dbm", mkmap_dbm_open,
+ DICT_TYPE_DBM, mkmap_dbm_open,
#endif
#ifdef HAS_DB
- "hash", mkmap_hash_open,
- "btree", mkmap_btree_open,
+ DICT_TYPE_HASH, mkmap_hash_open,
+ DICT_TYPE_BTREE, mkmap_btree_open,
#endif
0,
};
/* DESCRIPTION
/* This routine uses the address list built by own_inet_addr()
/* to produce a list of patterns that match the corresponding
-/* networks. The patterns are conservative: they match whole
-/* class A, B, C or D networks. This is usually sufficient to
-/* distinguish between organizations.
+/* networks.
+/*
+/* The interface list is specified with the "inet_interfaces"
+/* configuration parameter.
+/*
+/* The address to netblock conversion style is specified with
+/* the "mynetworks_style" parameter: one of "class" (match
+/* whole class A, B, C or D networks), "subnet" (match local
+/* subnets), or "host" (match local interfaces only).
/* LICENSE
/* .ad
/* .fi
#include <msg.h>
#include <vstring.h>
#include <inet_addr_list.h>
+#include <name_mask.h>
/* Global library. */
#include <own_inet_addr.h>
+#include <mail_params.h>
#include <mynetworks.h>
+/* Application-specific. */
+
+#define MASK_STYLE_CLASS (1 << 0)
+#define MASK_STYLE_SUBNET (1 << 1)
+#define MASK_STYLE_HOST (1 << 2)
+
+static NAME_MASK mask_styles[] = {
+ MYNETWORKS_STYLE_CLASS, MASK_STYLE_CLASS,
+ MYNETWORKS_STYLE_SUBNET, MASK_STYLE_SUBNET,
+ MYNETWORKS_STYLE_HOST, MASK_STYLE_HOST,
+ 0,
+};
+
/* mynetworks - return patterns that match my own networks */
const char *mynetworks(void)
if (result == 0) {
char *myname = "mynetworks";
INET_ADDR_LIST *my_addr_list;
+ INET_ADDR_LIST *my_mask_list;
unsigned long addr;
unsigned long mask;
struct in_addr net;
int shift;
+ int junk;
int i;
+ int mask_style;
+
+ mask_style = name_mask("mynetworks mask style", mask_styles,
+ var_mynetworks_style);
result = vstring_alloc(20);
my_addr_list = own_inet_addr_list();
+ my_mask_list = own_inet_mask_list();
for (i = 0; i < my_addr_list->used; i++) {
addr = ntohl(my_addr_list->addrs[i].s_addr);
- if (IN_CLASSA(addr)) {
- mask = IN_CLASSA_NET;
- shift = IN_CLASSA_NSHIFT;
- } else if (IN_CLASSB(addr)) {
- mask = IN_CLASSB_NET;
- shift = IN_CLASSB_NSHIFT;
- } else if (IN_CLASSC(addr)) {
- mask = IN_CLASSC_NET;
- shift = IN_CLASSC_NSHIFT;
- } else if (IN_CLASSD(addr)) {
- mask = IN_CLASSD_NET;
- shift = IN_CLASSD_NSHIFT;
- } else {
- msg_fatal("%s: bad address class: %s",
- myname, inet_ntoa(my_addr_list->addrs[i]));
+ mask = ntohl(my_mask_list->addrs[i].s_addr);
+
+ switch (mask_style) {
+
+ /*
+ * Natural mask. This is dangerous if you're customer of an
+ * ISP who gave you a small portion of their network.
+ */
+ case MASK_STYLE_CLASS:
+ if (IN_CLASSA(addr)) {
+ mask = IN_CLASSA_NET;
+ shift = IN_CLASSA_NSHIFT;
+ } else if (IN_CLASSB(addr)) {
+ mask = IN_CLASSB_NET;
+ shift = IN_CLASSB_NSHIFT;
+ } else if (IN_CLASSC(addr)) {
+ mask = IN_CLASSC_NET;
+ shift = IN_CLASSC_NSHIFT;
+ } else if (IN_CLASSD(addr)) {
+ mask = IN_CLASSD_NET;
+ shift = IN_CLASSD_NSHIFT;
+ } else {
+ msg_fatal("%s: bad address class: %s",
+ myname, inet_ntoa(my_addr_list->addrs[i]));
+ }
+ break;
+
+ /*
+ * Subnet mask. This is safe, but breaks backwards
+ * compatibility when used as default setting.
+ */
+ case MASK_STYLE_SUBNET:
+ for (junk = mask, shift = BITS_PER_ADDR; junk != 0; shift--, (junk <<= 1))
+ /* void */ ;
+ break;
+
+ /*
+ * Host only. Do not relay authorize other hosts.
+ */
+ case MASK_STYLE_HOST:
+ mask = ~0;
+ shift = 0;
+ break;
+
+ default:
+ msg_panic("unknown mynetworks mask style: %s",
+ var_mynetworks_style);
}
net.s_addr = htonl(addr & mask);
vstring_sprintf_append(result, "%s/%d ",
#ifdef TEST
char *var_inet_interfaces;
+char *var_mynetworks_style;
-main(int argc, char **argv)
+int main(int argc, char **argv)
{
- if (argc != 2)
- msg_fatal("usage: %s interface_list", argv[0]);
+ if (argc != 3)
+ msg_fatal("usage: %s mask_style interface_list", argv[0]);
msg_verbose = 10;
- var_inet_interfaces = argv[1];
+ var_inet_interfaces = argv[2];
+ var_mynetworks_style = argv[1];
mynetworks();
}
/* struct in_addr *addr;
/*
/* INET_ADDR_LIST *own_inet_addr_list()
+/*
+/* INET_ADDR_LIST *own_inet_mask_list()
/* DESCRIPTION
/* own_inet_addr() determines if the specified IP address belongs
/* to this mail system instance, i.e. if this mail system instance
/*
/* own_inet_addr_list() returns the list of all addresses that
/* belong to this mail system instance.
+/*
+/* own_inet_mask_list() returns the list of all corresponding
+/* netmasks.
/* LICENSE
/* .ad
/* .fi
/* Application-specific. */
static INET_ADDR_LIST addr_list;
+static INET_ADDR_LIST mask_list;
/* own_inet_addr_init - initialize my own address list */
-static void own_inet_addr_init(INET_ADDR_LIST *addr_list)
+static void own_inet_addr_init(INET_ADDR_LIST *addr_list,
+ INET_ADDR_LIST *mask_list)
{
+ INET_ADDR_LIST local_addrs;
+ INET_ADDR_LIST local_masks;
char *hosts;
char *host;
char *sep = " \t,";
char *bufp;
+ int nvirtual;
+ int nlocal;
inet_addr_list_init(addr_list);
+ inet_addr_list_init(mask_list);
/*
* If we are listening on all interfaces (default), ask the system what
* the interfaces are.
*/
if (strcasecmp(var_inet_interfaces, DEF_INET_INTERFACES) == 0) {
- if (inet_addr_local(addr_list) == 0)
+ if (inet_addr_local(addr_list, mask_list) == 0)
msg_fatal("could not find any active network interfaces");
#if 0
if (addr_list->used == 1)
msg_fatal("config variable %s: host not found: %s",
VAR_INET_INTERFACES, host);
myfree(hosts);
+
+ inet_addr_list_init(&local_addrs);
+ inet_addr_list_init(&local_masks);
+ if (inet_addr_local(&local_addrs, &local_masks) == 0)
+ msg_fatal("could not find any active network interfaces");
+ for (nvirtual = 0; nvirtual < addr_list->used; nvirtual++) {
+ for (nlocal = 0; /* see below */ ; nlocal++) {
+ if (nlocal >= local_addrs.used)
+ msg_fatal("parameter %s: no local interface found for %s",
+ VAR_INET_INTERFACES,
+ inet_ntoa(addr_list->addrs[nvirtual]));
+ if (addr_list->addrs[nvirtual].s_addr
+ == local_addrs.addrs[nlocal].s_addr) {
+ inet_addr_list_append(mask_list, &local_masks.addrs[nlocal]);
+ break;
+ }
+ }
+ }
+ inet_addr_list_free(&local_addrs);
+ inet_addr_list_free(&local_masks);
}
}
int i;
if (addr_list.used == 0)
- own_inet_addr_init(&addr_list);
+ own_inet_addr_init(&addr_list, &mask_list);
for (i = 0; i < addr_list.used; i++)
if (addr->s_addr == addr_list.addrs[i].s_addr)
INET_ADDR_LIST *own_inet_addr_list(void)
{
if (addr_list.used == 0)
- own_inet_addr_init(&addr_list);
+ own_inet_addr_init(&addr_list, &mask_list);
return (&addr_list);
}
+
+/* own_inet_mask_list - return list of addresses */
+
+INET_ADDR_LIST *own_inet_mask_list(void)
+{
+ if (addr_list.used == 0)
+ own_inet_addr_init(&addr_list, &mask_list);
+
+ return (&mask_list);
+}
*/
extern int own_inet_addr(struct in_addr *);
extern struct INET_ADDR_LIST *own_inet_addr_list(void);
+extern struct INET_ADDR_LIST *own_inet_mask_list(void);
/* LICENSE
/* .ad
peer.type = PEER_TYPE_INET;
hp = gethostbyaddr((char *) &(sin.sin_addr),
sizeof(sin.sin_addr), AF_INET);
- peer.name = (hp && valid_hostname(hp->h_name) ?
+ peer.name = (hp && valid_hostname(hp->h_name, DO_GRIPE) ?
hp->h_name : "unknown");
peer.addr = inet_ntoa(sin.sin_addr);
return (&peer);
lmtp_chat.o: ../../include/mail_addr.h
lmtp_chat.o: ../../include/post_mail.h
lmtp_chat.o: ../../include/cleanup_user.h
+lmtp_chat.o: ../../include/mail_error.h
+lmtp_chat.o: ../../include/name_mask.h
lmtp_chat.o: lmtp.h
lmtp_connect.o: lmtp_connect.c
lmtp_connect.o: ../../include/sys_defs.h
lmtp_proto.o: ../../include/rec_type.h
lmtp_proto.o: ../../include/off_cvt.h
lmtp_proto.o: ../../include/mark_corrupt.h
+lmtp_proto.o: ../../include/quote_821_local.h
lmtp_proto.o: lmtp.h
lmtp_proto.o: ../../include/argv.h
lmtp_proto.o: lmtp_sasl.h
-lmtp_proto.o: ../../include/quote_821_local.h
lmtp_sasl_glue.o: lmtp_sasl_glue.c
lmtp_sasl_glue.o: ../../include/sys_defs.h
lmtp_sasl_glue.o: ../../include/msg.h
lmtp_sasl_glue.o: ../../include/dict.h
lmtp_sasl_glue.o: ../../include/vstream.h
lmtp_sasl_glue.o: ../../include/argv.h
+lmtp_sasl_glue.o: lmtp.h
+lmtp_sasl_glue.o: ../../include/deliver_request.h
+lmtp_sasl_glue.o: ../../include/recipient_list.h
lmtp_sasl_glue.o: lmtp_sasl.h
lmtp_sasl_proto.o: lmtp_sasl_proto.c
lmtp_sasl_proto.o: ../../include/sys_defs.h
lmtp_sasl_proto.o: ../../include/msg.h
lmtp_sasl_proto.o: ../../include/mymalloc.h
lmtp_sasl_proto.o: ../../include/mail_params.h
+lmtp_sasl_proto.o: lmtp.h
+lmtp_sasl_proto.o: ../../include/vstream.h
+lmtp_sasl_proto.o: ../../include/vbuf.h
+lmtp_sasl_proto.o: ../../include/vstring.h
+lmtp_sasl_proto.o: ../../include/argv.h
+lmtp_sasl_proto.o: ../../include/deliver_request.h
+lmtp_sasl_proto.o: ../../include/recipient_list.h
lmtp_sasl_proto.o: lmtp_sasl.h
lmtp_session.o: lmtp_session.c
lmtp_session.o: ../../include/sys_defs.h
lmtp_state.o: ../../include/vstring.h
lmtp_state.o: ../../include/vbuf.h
lmtp_state.o: ../../include/vstream.h
-lmtp_state.o: ../../include/config.h
lmtp_state.o: ../../include/mail_conf.h
lmtp_state.o: lmtp.h
lmtp_state.o: ../../include/argv.h
/* delivery request. The destination, usually specified in the Postfix
/* \fBtransport\fR(5) table, has the form:
/* .IP \fBunix\fR:\fIpathname\fR
-/* Connect to the UNIX-domain server that is bound to the specified
+/* Connect to the local UNIX-domain server that is bound to the specified
/* \fIpathname\fR. If the process runs chrooted, an absolute pathname
/* is interpreted relative to the changed root directory.
/* .IP "\fBinet\fR:\fIhost\fR, \fBinet\fB:\fIhost\fR:\fIport\fR (symbolic host)"
/* .IP "\fBinet\fR:[\fIaddr\fR], \fBinet\fR:[\fIaddr\fR]:\fIport\fR (numeric host)"
-/* Connect to the specified IPV4 TCP port on the specified host. If no
-/* port is specified, connect to the port defined as \fBlmtp\fR in
-/* \fBservices\fR(4).
+/* Connect to the specified IPV4 TCP port on the specified local or
+/* remote host. If no port is specified, connect to the port defined as
+/* \fBlmtp\fR in \fBservices\fR(4).
/* If no such service is found, the \fBlmtp_tcp_port\fR configuration
/* parameter (default value of 24) will be used.
/*
static void pre_init(char *unused_name, char **unused_argv)
{
debug_peer_init();
-#ifdef USE_SASL_AUTH
if (var_lmtp_sasl_enable)
+#ifdef USE_SASL_AUTH
lmtp_sasl_initialize();
+#else
+ msg_warn("%s is true, but SASL support is not compiled in",
+ VAR_LMTP_SASL_ENABLE);
#endif
}
static CONFIG_BOOL_TABLE bool_table[] = {
VAR_LMTP_CACHE_CONN, DEF_LMTP_CACHE_CONN, &var_lmtp_cache_conn,
VAR_LMTP_SKIP_QUIT_RESP, DEF_LMTP_SKIP_QUIT_RESP, &var_lmtp_skip_quit_resp,
+ VAR_LMTP_SASL_ENABLE, DEF_LMTP_SASL_ENABLE, &var_lmtp_sasl_enable,
0,
};
*/
smtp_timeout_setup(state->session->stream, var_lmtp_lhlo_tmout);
if ((except = vstream_setjmp(state->session->stream)) != 0)
- return (smtp_stream_except(state, except, "sending LHLO"));
+ return (lmtp_stream_except(state, except, "sending LHLO"));
/*
* Read and parse the server's LMTP greeting banner.
smtp_timeout_setup(state->session->stream,
*xfer_timeouts[recv_state]);
if ((except = vstream_setjmp(state->session->stream)) != 0)
- RETURN(smtp_stream_except(state, except,
+ RETURN(lmtp_stream_except(state, except,
xfer_states[recv_state]));
resp = lmtp_chat_resp(state);
smtp_timeout_setup(state->session->stream,
var_lmtp_data1_tmout);
if ((except = vstream_setjmp(state->session->stream)) != 0)
- RETURN(smtp_stream_except(state, except,
+ RETURN(lmtp_stream_except(state, except,
"sending message body"));
if (vstream_fseek(state->src, request->data_offset, SEEK_SET) < 0)
/* RECIPIENT *recipient;
/* char *format;
/*
-/* int smtp_stream_except(state, exception, description)
+/* int lmtp_stream_except(state, exception, description)
/* LMTP_STATE *state;
/* int exception;
/* char *description;
/* recipient limit is reached. The policy is: soft error: defer
/* delivery to this recipient; hard error: bounce this recipient.
/*
-/* smtp_stream_except() handles the exceptions generated by
+/* lmtp_stream_except() handles the exceptions generated by
/* the smtp_stream(3) module (i.e. timeouts and I/O errors).
/* The \fIexception\fR argument specifies the type of problem.
/* The \fIdescription\fR argument describes at what stage of
state->status |= status;
}
-/* smtp_stream_except - defer domain after I/O problem */
+/* lmtp_stream_except - defer domain after I/O problem */
-int smtp_stream_except(LMTP_STATE *state, int code, char *description)
+int lmtp_stream_except(LMTP_STATE *state, int code, char *description)
{
DELIVER_REQUEST *request = state->request;
LMTP_SESSION *session = state->session;
*/
switch (code) {
default:
- msg_panic("smtp_stream_except: unknown exception %d", code);
+ msg_panic("lmtp_stream_except: unknown exception %d", code);
case SMTP_ERR_EOF:
vstring_sprintf(why, "lost connection with %s while %s",
session->namaddr, description);
maildir.o: ../../include/sane_fsops.h
maildir.o: ../../include/mail_copy.h
maildir.o: ../../include/bounce.h
+maildir.o: ../../include/defer.h
maildir.o: ../../include/sent.h
maildir.o: ../../include/mail_params.h
maildir.o: local.h
/* forwarding mail is not recommended.
/* .IP \fBrecipient_delimiter\fR
/* Separator between username and address extension.
-/* .IP \fBtest_home_directory\fR
+/* .IP \fBrequire_home_directory\fR
/* Require that a recipient's home directory is accessible by the
-/* recipient before attempting delivery.
+/* recipient before attempting delivery. Defer delivery otherwise.
/* .SH Mailbox delivery
/* .ad
/* .fi
/* an exclusive lock.
/* .IP \fBstale_lock_time\fR
/* Limit the time after which a stale lock is removed.
-/* .IP \fBmailbox__delivery_lock\fR
+/* .IP \fBmailbox_delivery_lock\fR
/* What file locking method(s) to use when delivering to a UNIX-style
/* mailbox.
/* The default setting is system dependent. For a list of available
/* Limit the number of recipients per message delivery.
/* The default limit is taken from the
/* \fBdefault_destination_recipient_limit\fR parameter.
+/* .IP \fBmailbox_size_limit\fR
+/* Limit the size of a mailbox etc. file (any file that is
+/* written to upon delivery).
+/* Set to zero to disable the limit.
/* .SH "Security controls"
/* .ad
/* .fi
/* .IP \fBallow_mail_to_commands\fR
/* Restrict the usage of mail delivery to external command.
+/* Specify zero or more of: \fBalias\fR, \fBforward\fR, \fBinclude\fR.
/* .IP \fBallow_mail_to_files\fR
/* Restrict the usage of mail delivery to external file.
+/* Specify zero or more of: \fBalias\fR, \fBforward\fR, \fBinclude\fR.
/* .IP \fBcommand_expansion_filter\fR
/* What characters are allowed to appear in $name expansions of
/* mailbox_command. Illegal characters are replaced by underscores.
int var_stat_home_dir;
int var_mailtool_compat;
char *var_mailbox_lock;
+int var_mailbox_limit;
int local_cmd_deliver_mask;
int local_file_deliver_mask;
local_mask_init();
}
+/* pre_init - pre-jail initialization */
+
+static void pre_init(char *unused_name, char **unused_argv)
+{
+
+ /*
+ * Reset the file size limit from the message size limit to the mailbox
+ * size limit. XXX This still isn't accurate because the file size limit
+ * also affects delivery to command.
+ *
+ * A file size limit protects the machine against runaway software errors.
+ * It is not suitable to enforce mail quota, because users can get around
+ * mail quota by delivering to /file/name or to |command.
+ *
+ * We can't have mailbox size limit smaller than the message size limit,
+ * because that prohibits the delivery agent from updating the queue
+ * file.
+ */
+ if (var_mailbox_limit) {
+ if (var_mailbox_limit < var_message_limit)
+ msg_fatal("main.cf configuration error: %s is smaller than %s",
+ VAR_MAILBOX_LIMIT, VAR_MESSAGE_LIMIT);
+ set_file_limit(var_mailbox_limit);
+ }
+}
+
/* main - pass control to the single-threaded skeleton */
int main(int argc, char **argv)
};
static CONFIG_INT_TABLE int_table[] = {
VAR_DUP_FILTER_LIMIT, DEF_DUP_FILTER_LIMIT, &var_dup_filter_limit, 0, 0,
+ VAR_MAILBOX_LIMIT, DEF_MAILBOX_LIMIT, &var_mailbox_limit, 0, 0,
0,
};
static CONFIG_STR_TABLE str_table[] = {
MAIL_SERVER_RAW_TABLE, raw_table,
MAIL_SERVER_BOOL_TABLE, bool_table,
MAIL_SERVER_TIME_TABLE, time_table,
+ MAIL_SERVER_PRE_INIT, pre_init,
MAIL_SERVER_POST_INIT, post_init,
MAIL_SERVER_PRE_ACCEPT, pre_accept,
0);
#include <mail_copy.h>
#include <bounce.h>
+#include <defer.h>
#include <sent.h>
#include <mail_params.h>
set_eugid(var_owner_uid, var_owner_gid);
if (status)
- bounce_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
- "maildir delivery failed: %s", vstring_str(why));
+ status = (errno == ENOSPC ? defer_append : bounce_append)
+ (BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
+ "maildir delivery failed: %s", vstring_str(why));
else
- sent(SENT_ATTR(state.msg_attr), "maildir");
+ status = sent(SENT_ATTR(state.msg_attr), "maildir");
vstring_free(buf);
vstring_free(why);
myfree(newdir);
myfree(curdir);
myfree(tmpfile);
myfree(newfile);
- return (0);
+ return (status);
}
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
+#include <limits.h>
/* Utility library. */
clean_env(import_env->argv);
argv_free(import_env);
- if ((inherited_limit = get_file_limit()) < (off_t) var_message_limit) {
- msg_warn("file size limit %lu < message_size_limit %lu -- reset",
- (unsigned long) inherited_limit, (unsigned long) var_message_limit);
- set_file_limit(var_message_limit);
- }
+ if ((inherited_limit = get_file_limit()) < (off_t) INT_MAX)
+ set_file_limit(INT_MAX);
+
if (chdir(var_queue_dir))
msg_fatal("chdir %s: %m", var_queue_dir);
/* Local stuff. */
+#ifdef USE_SIG_PIPE
+#include <errno.h>
+#include <fcntl.h>
+#include <iostuff.h>
+
+int master_sig_pipe[2];
+
+#define SIG_PIPE_WRITE_FD master_sig_pipe[1]
+#define SIG_PIPE_READ_FD master_sig_pipe[0]
+#endif
+
int master_gotsigchld;
int master_gotsighup;
#else
+#ifdef USE_SIG_PIPE
+
+/* master_sigchld - force wakeup from select() */
+
+static void master_sigchld(int sig)
+{
+ if (write(SIG_PIPE_WRITE_FD, "", 1) != 1)
+ msg_warn("write to SIG_PIPE_WRITE_FD failed: %m");
+}
+
+/* master_sig_event - called upon return from select() */
+
+static void master_sig_event(int unused_event, char *unused_context)
+{
+ char c[1];
+
+ while (read(SIG_PIPE_READ_FD, c, 1) > 0)
+ /* void */ ;
+ master_gotsigchld = 1;
+}
+
+#else
+
static void master_sigchld(int sig)
{
master_gotsigchld = sig;
}
+#endif
#endif
/* master_sigdeath - die, women and children first */
if (sigaction(sigs[i], &action, (struct sigaction *) 0) < 0)
msg_fatal("%s: sigaction(%d): %m", myname, sigs[i]);
+#ifdef USE_SIG_PIPE
+ if (pipe(master_sig_pipe))
+ msg_fatal("pipe: %m");
+ non_blocking(SIG_PIPE_WRITE_FD, NON_BLOCKING);
+ non_blocking(SIG_PIPE_READ_FD, NON_BLOCKING);
+ close_on_exec(SIG_PIPE_WRITE_FD, CLOSE_ON_EXEC);
+ close_on_exec(SIG_PIPE_READ_FD, CLOSE_ON_EXEC);
+ event_enable_read(SIG_PIPE_READ_FD, master_sig_event, (char *) 0);
+#endif
+
/*
* Intercept SIGHUP (re-read config file) and SIGCHLD (child exit).
*/
*expand_flag |= PIPE_FLAG_EXTENSION;
else if (strcmp(vstring_str(buf), PIPE_DICT_MAILBOX) == 0)
*expand_flag |= PIPE_FLAG_MAILBOX;
- else if (strcmp(vstring_str(buf), PIPE_DICT_SIZE) == 0)
- *expand_flag |= PIPE_FLAG_SIZE;
}
return (0);
}
dict_update(PIPE_DICT_TABLE, PIPE_DICT_MAILBOX, STR(buf));
}
- /*
- * This argument contains $size.
- */
- if (expand_flag & PIPE_FLAG_SIZE) {
- vstring_sprintf(buf, "%ld", data_size);
- dict_update(PIPE_DICT_TABLE, PIPE_DICT_SIZE, STR(buf));
- }
-
/*
* Done.
*/
dict_update(PIPE_DICT_TABLE, PIPE_DICT_SENDER, request->sender);
dict_update(PIPE_DICT_TABLE, PIPE_DICT_NEXTHOP, request->nexthop);
+ buf = vstring_alloc(10);
+ vstring_sprintf(buf, "%ld", (long) request->data_size);
+ dict_update(PIPE_DICT_TABLE, PIPE_DICT_SIZE, STR(buf));
+ vstring_free(buf);
expanded_argv = expand_argv(attr.command, rcpt_list, request->data_size);
export_env = argv_split(var_export_environ, ", \t\r\n");
postconf.o: bool_vars.h
postconf.o: int_vars.h
postconf.o: str_vars.h
-postconf.o: local_vars.h
+postconf.o: raw_vars.h
postconf.o: smtp_vars.h
postconf.o: time_table.h
postconf.o: bool_table.h
postconf.o: int_table.h
postconf.o: str_table.h
-postconf.o: local_table.h
postconf.o: smtp_table.h
+postconf.o: raw_table.h
+++ /dev/null
- "local_destination_concurrency_limit", "$default_destination_concurrency_limit", &var_local_destination_concurrency_limit, 0, 0,
+++ /dev/null
-char *var_local_destination_concurrency_limit;
/*
* Manually extracted.
*/
-#include "local_vars.h"
#include "smtp_vars.h"
/*
static CONFIG_STR_TABLE str_table[] = {
#include "str_table.h"
-#include "local_table.h" /* XXX */
#include "smtp_table.h" /* XXX */
0,
};
static const char *check_mynetworks(void)
{
- if (var_inet_interfaces == 0)
- var_inet_interfaces = mystrdup(DEF_INET_INTERFACES);
+ const char *junk;
+
+ if (var_inet_interfaces == 0) {
+ if ((mode & SHOW_DEFS)
+ || !(junk = mail_conf_lookup(VAR_INET_INTERFACES)))
+ junk = DEF_INET_INTERFACES;
+ var_inet_interfaces = mystrdup(junk);
+ }
+ if (var_mynetworks_style == 0) {
+ if ((mode & SHOW_DEFS)
+ || !(junk = mail_conf_lookup(VAR_MYNETWORKS_STYLE)))
+ junk = DEF_MYNETWORKS_STYLE;
+ var_mynetworks_style = mystrdup(junk);
+ }
return (mynetworks());
}
* bool_table, int_table, str_table, and raw_table. Look up each
* parameter name in the configuration parameter dictionary. If the
* parameter is not set, take the default value, or take the value from
- * in main.c, without doing $name expansions. This includes converting
+ * main.cf, without doing $name expansions. This includes converting
* default values from numeric/boolean internal forms to external string
* form.
*
#define INSIDE(p,t) (ptr >= (char *) t && ptr < ((char *) t) + sizeof(t))
/*
- * This is gross, but the best we can do on short notice. Instead of
- * guessing we should use a tagged union. This is what code looks like
- * when written under the pressure of a first public release.
+ * This is gross, but the best we can do on short notice.
*/
if (INSIDE(ptr, time_table))
print_time(mode, (CONFIG_TIME_TABLE *) ptr);
case 'd':
mode |= SHOW_DEFS;
break;
- case 'E':
- mode |= SHOW_EVAL;
- break;
case 'e':
mode |= EDIT_MAIN;
break;
argv_free(hash_queue_names);
}
-main(int argc, char **argv)
+int main(int argc, char **argv)
{
int fd;
struct stat st;
int var_qmgr_fudge;
int var_qmgr_hog;
int var_local_rcpt_lim; /* XXX */
+int var_local_con_lim; /* XXX */
static QMGR_SCAN *qmgr_incoming;
static QMGR_SCAN *qmgr_deferred;
VAR_QMGR_FUDGE, DEF_QMGR_FUDGE, &var_qmgr_fudge, 10, 100,
VAR_QMGR_HOG, DEF_QMGR_HOG, &var_qmgr_hog, 10, 100,
VAR_LOCAL_RCPT_LIMIT, DEF_LOCAL_RCPT_LIMIT, &var_local_rcpt_lim, 0, 0,
+ VAR_LOCAL_CON_LIMIT, DEF_LOCAL_CON_LIMIT, &var_local_con_lim, 0, 0,
0,
};
static CONFIG_BOOL_TABLE bool_table[] = {
/* qmgr_bounce_recipient - bounce one message recipient */
-void qmgr_bounce_recipient(QMGR_MESSAGE *message, QMGR_RCPT * recipient,
+void qmgr_bounce_recipient(QMGR_MESSAGE *message, QMGR_RCPT *recipient,
const char *format,...)
{
va_list ap;
char *cp;
/*
- * With local delivery, the queue name is user@nexthop, so that we can
- * implement per-recipient concurrency limits. The delivery agent
- * protocol expects nexthop only.
+ * With mail transports that accept only one recipient per delivery, the
+ * queue name is user@nexthop, so that we can implement per-recipient
+ * concurrency limits. However, the delivery agent protocol expects
+ * nexthop only, so we must strip off the recipient local part.
*/
mail_print(stream, "%d %s %s %ld %ld %s %s %s %s %ld",
message->inspect_xport ? DEL_REQ_FLAG_BOUNCE : DEL_REQ_FLAG_DEFLT,
/* the queue file to the deferred queue; send bounce reports to the
/* message originator (see qmgr_active_done()).
/*
-/* qmgr_entry_select() randomly selects one entry from the named
+/* qmgr_entry_select() selects the next entry from the named
/* per-site queue's `todo' list for actual delivery. The entry is
/* moved to the queue's `busy' list: the list of messages being
/* delivered.
*/
if ((at = strrchr(recipient->address, '@')) != 0
&& (at + 1)[strspn(at + 1, "[]0123456789.")] != 0
- && valid_hostname(at + 1) == 0) {
+ && valid_hostname(at + 1, DONT_GRIPE) == 0) {
qmgr_bounce_recipient(message, recipient,
"bad host/domain syntax: \"%s\"", at + 1);
continue;
/*
* Queues are identified by the transport name and by the next-hop
- * hostname. When the destination is local (no next hop), derive the
- * queue name from the recipient name. XXX Should split the address
+ * hostname. When the delivery agent accepts only one recipient per
+ * delivery, give each recipient its own queue, so that deliveries to
+ * different recipients of the same message can happen in parallel.
+ * This also has the benefit that one bad recipient cannot interfere
+ * with deliveries to other recipients. XXX Should split the address
* on the recipient delimiter if one is defined, but doing a proper
* job requires knowledge of local aliases. Yuck! I don't want to
* duplicate delivery-agent specific knowledge in the queue manager.
* queue name. Should have separate fields for queue name and for
* destination.
*/
- if ((at = strrchr(STR(reply.recipient), '@')) == 0
- || resolve_local(at + 1)) {
- len = (at != 0 ? (at - STR(reply.recipient))
- : strlen(STR(reply.recipient)));
+ at = strrchr(STR(reply.recipient), '@');
+ len = (at ? (at - STR(reply.recipient)) : strlen(STR(reply.recipient)));
+
+ /*
+ * Look up or instantiate the proper transport. We're working a
+ * little ahead, doing queue management stuff that used to be done
+ * way down.
+ */
+ if (transport == 0 || !STREQ(transport->name, STR(reply.transport))) {
+ if ((transport = qmgr_transport_find(STR(reply.transport))) == 0)
+ transport = qmgr_transport_create(STR(reply.transport));
+ queue = 0;
+ }
+ if (transport->recipient_limit == 1) {
VSTRING_SPACE(reply.nexthop, len + 1);
memmove(STR(reply.nexthop) + len + 1, STR(reply.nexthop),
LEN(reply.nexthop) + 1);
memcpy(STR(reply.nexthop), STR(reply.recipient), len);
STR(reply.nexthop)[len] = '@';
lowercase(STR(reply.nexthop));
+ }
- /*
- * Discard mail to the local double bounce address here, so this
- * system can run without a local delivery agent. They'd still
- * have to configure something for mail directed to the local
- * postmaster, though, but that is an RFC requirement anyway.
- */
+ /*
+ * Discard mail to the local double bounce address here, so this
+ * system can run without a local delivery agent. They'd still have
+ * to configure something for mail directed to the local postmaster,
+ * though, but that is an RFC requirement anyway.
+ */
+ if (at == 0 || resolve_local(at + 1)) {
if (strncasecmp(STR(reply.recipient), var_double_bounce_sender,
- at - STR(reply.recipient)) == 0
- && !var_double_bounce_sender[at - STR(reply.recipient)]) {
+ len) == 0
+ && !var_double_bounce_sender[len]) {
sent(message->queue_id, recipient->address,
"none", message->arrival_time, "discarded");
deliver_completed(message->fp, recipient->offset);
* bind each recipient to an in-core queue instance which is needed
* anyway. That gives all information needed for recipient grouping.
*/
+#if 0
/*
* Look up or instantiate the proper transport.
transport = qmgr_transport_create(STR(reply.transport));
queue = 0;
}
+#endif
/*
* This transport is dead. Defer delivery to this recipient.
* reset the saved set-userid, which would be a security vulnerability.
*/
if (geteuid() == 0 && getuid() != 0) {
- msg_warn("sendmail has set-uid root file permissions, or is run from a set-uid root process");
+ msg_warn("the Postfix sendmail command has set-uid root file permissions");
+ msg_warn("or the command is run from a set-uid root process");
msg_warn("the Postfix sendmail command must be installed without set-uid root file permissions");
set_ugid(getuid(), getgid());
}
msg_fatal("-t can be used only in delivery mode");
if (site_to_flush && mode != SM_MODE_ENQUEUE)
- msg_fatal("-t can be used only in delivery mode");
+ msg_fatal("-qR can be used only in delivery mode");
if (extract_recipients && argv[OPTIND])
msg_fatal("cannot handle command-line recipients with -t");
smtp_proto.o: ../../include/rec_type.h
smtp_proto.o: ../../include/off_cvt.h
smtp_proto.o: ../../include/mark_corrupt.h
+smtp_proto.o: ../../include/quote_821_local.h
smtp_proto.o: smtp.h
smtp_proto.o: ../../include/argv.h
-smtp_proto.o: ../../include/quote_821_local.h
smtp_proto.o: smtp_sasl.h
smtp_sasl_glue.o: smtp_sasl_glue.c
smtp_sasl_glue.o: ../../include/sys_defs.h
{
debug_peer_init();
-#ifdef USE_SASL_AUTH
if (var_smtp_sasl_enable)
+#ifdef USE_SASL_AUTH
smtp_sasl_initialize();
+#else
+ msg_warn("%s is true, but SASL support is not compiled in",
+ VAR_SMTP_SASL_ENABLE);
#endif
}
best_pref = (mx_names ? mx_names->pref : IMPOSSIBLE_PREFERENCE);
addr_list = smtp_addr_list(mx_names, why);
dns_rr_free(mx_names);
+ if (addr_list == 0) {
+ smtp_errno = SMTP_RETRY;
+ msg_warn("no MX host for %s has a valid A record", name);
+ break;
+ }
best_found = (addr_list ? addr_list->pref : IMPOSSIBLE_PREFERENCE);
if (msg_verbose)
smtp_print_addr(name, addr_list);
void smtp_sasl_helo_auth(SMTP_STATE *state, const char *words)
{
-msg_info("smtp_sasl_helo_auth: words=\"%s\"", words);
+
/*
* XXX If the server offers a null list of authentication mechanisms,
* then pretend that the server doesn't support SASL authentication.
smtpd_check.o: ../../include/mail_addr_find.h
smtpd_check.o: smtpd.h
smtpd_check.o: ../../include/mail_stream.h
+smtpd_check.o: smtpd_sasl_glue.h
smtpd_check.o: smtpd_check.h
smtpd_peer.o: smtpd_peer.c
smtpd_peer.o: ../../include/sys_defs.h
/* .IP \fBstrict_rfc821_envelopes\fR
/* Disallow non-RFC 821 style addresses in envelopes. For example,
/* allow RFC822-style address forms with comments, like Sendmail does.
-/* .IP \fBallow_broken_auth_clients\fR
+/* .IP \fBbroken_sasl_auth_clients\fR
/* Support older Microsoft clients that mis-implement the AUTH
-/* protocol, and that expect an EHLO response of "250 AUTH=list"
+/* protocol, and that expect an EHLO response of "250 AUTH=list"
/* instead of "250 AUTH list".
/* .SH "Content inspection controls"
/* .IP \fBcontent_filter\fR
/* either bounces mail or re-injects the result back into Postfix.
/* This parameter uses the same syntax as the right-hand side of
/* a Postfix transport table.
-/* .SH "Authenication controls"
+/* .SH "Authentication controls"
/* .IP \fBenable_sasl_authentication\fR
/* Enable per-session authentication as per RFC 2554 (SASL).
/* This functionality is available only when explicitly selected
/* at program build time and explicitly enabled at runtime.
+/* .IP \fBsmtpd_sasl_local_domain\fR
+/* The name of the local authentication realm.
/* .IP \fBsmtpd_sasl_security_options\fR
/* Zero or more of the following.
/* .RS
}
if (!ISALNUM(argv[1].strval[0]))
argv[1].strval++;
- if (!valid_hostname(argv[1].strval)) {
+ if (!valid_hostname(argv[1].strval, DONT_GRIPE)) {
state->error_mask |= MAIL_ERROR_PROTOCOL;
smtpd_chat_reply(state, "501 Error: invalid parameter syntax");
return (-1);
debug_peer_init();
msg_cleanup(smtpd_cleanup);
-#ifdef USE_SASL_AUTH
if (var_smtpd_sasl_enable)
+#ifdef USE_SASL_AUTH
smtpd_sasl_initialize();
+#else
+ msg_warn("%s is true, but SASL support is not compiled in",
+ VAR_SMTPD_SASL_ENABLE);
#endif
}
/* DESCRIPTION
/* .nf
+ /*
+ * System library.
+ */
+#include <unistd.h>
+
/*
* SASL library.
*/
/* Application-specific. */
#include "smtpd.h"
+#include "smtpd_sasl_glue.h"
#include "smtpd_check.h"
/*
/*
* Validate the address.
*/
- if (!valid_hostaddr(test_addr))
+ if (!valid_hostaddr(test_addr, DONT_GRIPE))
stat = smtpd_check_reject(state, MAIL_ERROR_POLICY,
"%d <%s>: %s rejected: invalid ip address",
var_bad_name_code, reply_name, reply_class);
/*
* Validate the hostname.
*/
- if (!valid_hostname(test_name))
+ if (!valid_hostname(test_name, DONT_GRIPE))
stat = smtpd_check_reject(state, MAIL_ERROR_POLICY,
"%d <%s>: %s rejected: Invalid name",
var_bad_name_code, reply_name, reply_class);
/*
* Validate the hostname.
*/
- if (!valid_hostname(test_name) || !strchr(test_name, '.'))
+ if (!valid_hostname(test_name, DONT_GRIPE) || !strchr(test_name, '.'))
stat = smtpd_check_reject(state, MAIL_ERROR_POLICY,
"%d <%s>: %s rejected: need fully-qualified hostname",
var_non_fqdn_code, reply_name, reply_class);
/*
* Validate the domain.
*/
- if (!*test_dom || !valid_hostname(test_dom) || !strchr(test_dom, '.'))
+ if (!*test_dom || !valid_hostname(test_dom, DONT_GRIPE) || !strchr(test_dom, '.'))
stat = smtpd_check_reject(state, MAIL_ERROR_POLICY,
"%d <%s>: %s rejected: need fully-qualified address",
var_non_fqdn_code, reply_name, reply_class);
if (hp == 0) {
state->name = mystrdup("unknown");
state->peer_code = (h_errno == TRY_AGAIN ? 4 : 5);
- } else if (!valid_hostname(hp->h_name)) {
+ } else if (!valid_hostname(hp->h_name, DONT_GRIPE)) {
state->name = mystrdup("unknown");
state->peer_code = 5;
} else {
if ((fd = accept(sock, &sa, &len)) >= 0) {
if (msg_verbose)
- msg_info("connect (%s)", sa.sa_family == AF_LOCAL ? "AF_LOCAL" :
+ msg_info("connect (%s)",
+#ifdef AF_LOCAL
+ sa.sa_family == AF_LOCAL ? "AF_LOCAL" :
+#else
+ sa.sa_family == AF_UNIX ? "AF_UNIX" :
+#endif
+ sa.sa_family == AF_INET ? "AF_INET" :
#ifdef AF_INET6
sa.sa_family == AF_INET6 ? "AF_INET6" :
#endif
- sa.sa_family == AF_INET ? "AF_INET" :
"unknown protocol family");
non_blocking(fd, NON_BLOCKING);
state = (SINK_STATE *) mymalloc(sizeof(*state));
stream_connect.c stream_trigger.c dict_regexp.c mac_expand.c \
clean_env.c watchdog.c spawn_command.c duplex_pipe.c sane_rename.c \
sane_link.c unescape.c timed_read.c timed_write.c dict_tcp.c \
- hex_quote.c
+ hex_quote.c dict_alloc.c rand_sleep.c sane_time.c dict_debug.c \
+ sane_socketpair.c
OBJS = argv.o argv_split.o attr.o basename.o binhash.o chroot_uid.o \
close_on_exec.o concatenate.o dict.o dict_db.o dict_dbm.o \
dict_env.o dict_ht.o dict_ldap.o dict_mysql.o dict_ni.o dict_nis.o \
stream_connect.o stream_trigger.o dict_regexp.o mac_expand.o \
clean_env.o watchdog.o spawn_command.o duplex_pipe.o sane_rename.o \
sane_link.o unescape.o timed_read.o timed_write.o dict_tcp.o \
- hex_quote.o
+ hex_quote.o dict_alloc.o rand_sleep.o sane_time.o dict_debug.o \
+ sane_socketpair.o
HDRS = argv.h attr.h binhash.h chroot_uid.h connect.h dict.h dict_db.h \
dict_dbm.h dict_env.h dict_ht.h dict_ldap.h dict_mysql.h \
dict_ni.h dict_nis.h dict_nisplus.h dir_forest.h events.h \
timed_connect.h timed_wait.h trigger.h username.h valid_hostname.h \
vbuf.h vbuf_print.h vstream.h vstring.h vstring_vstream.h \
dict_unix.h dict_pcre.h dict_regexp.h mac_expand.h clean_env.h \
- watchdog.h spawn_command.h sane_fsops.h dict_tcp.h hex_quote.h
+ watchdog.h spawn_command.h sane_fsops.h dict_tcp.h hex_quote.h \
+ sane_time.h sane_socketpair.h
TESTSRC = fifo_open.c fifo_rdwr_bug.c fifo_rdonly_bug.c select_bug.c \
stream_test.c dup2_pass_on_exec.c
WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \
inet_addr_host inet_addr_local mac_parse make_dirs msg_syslog \
mystrtok sigdelay translit valid_hostname vstream_popen \
vstring vstring_vstream doze select_bug stream_test mac_expand \
- watchdog unescape hex_quote name_mask
+ watchdog unescape hex_quote name_mask rand_sleep sane_time
LIB_DIR = ../../lib
INC_DIR = ../../include
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
mv junk $@.o
+rand_sleep: $(LIB)
+ mv $@.o junk
+ $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
+ mv junk $@.o
+
+sane_time: $(LIB)
+ mv $@.o junk
+ $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
+ mv junk $@.o
+
depend: $(MAKES)
(sed '1,/^# do not edit/!d' Makefile.in; \
set -e; for i in [a-z][a-z0-9]*.c; do \
dict.o: dict.h
dict.o: argv.h
dict.o: dict_ht.h
+dict_alloc.o: dict_alloc.c
+dict_alloc.o: sys_defs.h
+dict_alloc.o: msg.h
+dict_alloc.o: mymalloc.h
+dict_alloc.o: dict.h
+dict_alloc.o: vstream.h
+dict_alloc.o: vbuf.h
+dict_alloc.o: argv.h
dict_db.o: dict_db.c
dict_db.o: sys_defs.h
dict_db.o: msg.h
dict_db.o: dict_db.h
dict_dbm.o: dict_dbm.c
dict_dbm.o: sys_defs.h
-dict_dbm.o: msg.h
-dict_dbm.o: mymalloc.h
-dict_dbm.o: htable.h
-dict_dbm.o: iostuff.h
-dict_dbm.o: vstring.h
-dict_dbm.o: vbuf.h
-dict_dbm.o: myflock.h
-dict_dbm.o: stringops.h
-dict_dbm.o: dict.h
-dict_dbm.o: vstream.h
-dict_dbm.o: argv.h
-dict_dbm.o: dict_dbm.h
+dict_debug.o: dict_debug.c
+dict_debug.o: sys_defs.h
+dict_debug.o: msg.h
+dict_debug.o: mymalloc.h
+dict_debug.o: dict.h
+dict_debug.o: vstream.h
+dict_debug.o: vbuf.h
+dict_debug.o: argv.h
dict_env.o: dict_env.c
dict_env.o: sys_defs.h
dict_env.o: mymalloc.h
dict_ldap.o: sys_defs.h
dict_mysql.o: dict_mysql.c
dict_mysql.o: sys_defs.h
-dict_mysql.o: dict.h
-dict_mysql.o: vstream.h
-dict_mysql.o: vbuf.h
-dict_mysql.o: argv.h
-dict_mysql.o: msg.h
-dict_mysql.o: mymalloc.h
-dict_mysql.o: dict_mysql.h
-dict_mysql.o: vstring.h
dict_ni.o: dict_ni.c
dict_ni.o: sys_defs.h
dict_nis.o: dict_nis.c
duplex_pipe.o: duplex_pipe.c
duplex_pipe.o: sys_defs.h
duplex_pipe.o: iostuff.h
+duplex_pipe.o: sane_socketpair.h
environ.o: environ.c
environ.o: sys_defs.h
events.o: events.c
printable.o: stringops.h
printable.o: vstring.h
printable.o: vbuf.h
+rand_sleep.o: rand_sleep.c
+rand_sleep.o: sys_defs.h
+rand_sleep.o: msg.h
+rand_sleep.o: iostuff.h
read_wait.o: read_wait.c
read_wait.o: sys_defs.h
read_wait.o: msg.h
sane_rename.o: sys_defs.h
sane_rename.o: msg.h
sane_rename.o: sane_fsops.h
+sane_socketpair.o: sane_socketpair.c
+sane_socketpair.o: sys_defs.h
+sane_socketpair.o: msg.h
+sane_socketpair.o: sane_socketpair.h
+sane_time.o: sane_time.c
+sane_time.o: sys_defs.h
+sane_time.o: msg.h
+sane_time.o: sane_time.h
scan_dir.o: scan_dir.c
scan_dir.o: sys_defs.h
scan_dir.o: msg.h
/* dict_sequence() steps throuh the named dictionary and returns
/* keys and values in some implementation-defined order. The func
/* argument is DICT_SEQ_FUN_FIRST to set the cursor to the first
-/* entry or DICT_SEQ_FUN_NEXT so select the next entry. The result
+/* entry or DICT_SEQ_FUN_NEXT to select the next entry. The result
/* is owned by the underlying dictionary method. Make a copy if the
/* result is to be modified, or if the result is to survive multiple
/* dict_sequence() calls.
if ((node = dict_node(dict_name)) == 0) {
if (dict_unknown_allowed == 0)
msg_fatal("%s: unknown dictionary: %s", myname, dict_name);
- dict = dict_ht_open(htable_create(0), myfree);
+ dict = dict_ht_open(dict_name, htable_create(0), myfree);
dict_register(dict_name, dict);
} else
dict = node->dict;
if ((node = dict_node(dict_name)) == 0) {
if (dict_unknown_allowed == 0)
msg_fatal("%s: unknown dictionary: %s", myname, dict_name);
- dict = dict_ht_open(htable_create(0), myfree);
+ dict = dict_ht_open(dict_name, htable_create(0), myfree);
dict_register(dict_name, dict);
} else
dict = node->dict;
if ((node = dict_node(dict_name)) == 0) {
if (dict_unknown_allowed == 0)
msg_fatal("%s: unknown dictionary: %s", myname, dict_name);
- dict = dict_ht_open(htable_create(0), myfree);
+ dict = dict_ht_open(dict_name, htable_create(0), myfree);
dict_register(dict_name, dict);
} else
dict = node->dict;
* structure with private members to maintain internal state.
*/
typedef struct DICT {
+ char *type; /* for diagnostics */
+ char *name; /* for diagnostics */
int flags; /* see below */
const char *(*lookup) (struct DICT *, const char *);
void (*update) (struct DICT *, const char *, const char *);
time_t mtime; /* mod time at open */
} DICT;
+extern DICT *dict_alloc(const char *, const char *, int);
+extern void dict_free(DICT *);
+
+extern DICT *dict_debug(DICT *);
+#define DICT_DEBUG(d) ((d)->flags & DICT_FLAG_DEBUG ? dict_debug(d) : (d))
+
#define DICT_FLAG_DUP_WARN (1<<0) /* if file, warn about dups */
#define DICT_FLAG_DUP_IGNORE (1<<1) /* if file, ignore dups */
#define DICT_FLAG_TRY0NULL (1<<2) /* do not append 0 to key/value */
#define DICT_FLAG_LOCK (1<<6) /* lock before access */
#define DICT_FLAG_DUP_REPLACE (1<<7) /* if file, replace dups */
#define DICT_FLAG_SYNC_UPDATE (1<<8) /* if file, sync updates */
+#define DICT_FLAG_DEBUG (1<<9) /* log access */
extern int dict_unknown_allowed;
extern int dict_errno;
--- /dev/null
+/*++
+/* NAME
+/* dict_alloc 3
+/* SUMMARY
+/* dictionary memory manager
+/* SYNOPSIS
+/* #include <dict.h>
+/*
+/* DICT *dict_alloc(dict_type, dict_name, size)
+/* const char *dict_type;
+/* const char *dict_name;
+/* int size;
+/*
+/* void dict_free(dict)
+/* DICT *ptr;
+/* DESCRIPTION
+/* dict_alloc() allocates memory for a dictionary structure of
+/* \fIsize\fR bytes, initializes all properties to default settings,
+/* and installs default methods that do not support any operation.
+/* The caller is supposed to override the default methods with
+/* ones that it supports.
+/* The purpose of the default methods is to trap an attempt to
+/* invoke an unsupported method.
+/*
+/* dict_free() releases memory and cleans up after dict_alloc().
+/* It is up to the caller to dispose of any memory that was allocated
+/* by the caller.
+/*
+/* Arguments:
+/* .IP dict_type
+/* The official name for this type of dictionary, as used by
+/* dict_open(3) etc. This is stored under the \fBtype\fR
+/* member.
+/* .IP dict_name
+/* Dictionary name. This is stored as the \fBname\fR member.
+/* .IP size
+/* The size in bytes of the dictionary subclass structure instance.
+/* SEE ALSO
+/* dict(3)
+/* DIAGNOSTICS
+/* Fatal errors: the process invokes a default method.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System libraries. */
+
+#include "sys_defs.h"
+
+/* Utility library. */
+
+#include "msg.h"
+#include "mymalloc.h"
+#include "dict.h"
+
+/* dict_default_lookup - trap unimplemented operation */
+
+static const char *dict_default_lookup(DICT *dict, const char *unused_key)
+{
+ msg_fatal("%s table %s: lookup operation is not supported",
+ dict->type, dict->name);
+}
+
+/* dict_default_update - trap unimplemented operation */
+
+static void dict_default_update(DICT *dict, const char *unused_key,
+ const char *unused_value)
+{
+ msg_fatal("%s table %s: update operation is not supported",
+ dict->type, dict->name);
+}
+
+/* dict_default_delete - trap unimplemented operation */
+
+static int dict_default_delete(DICT *dict, const char *unused_key)
+{
+ msg_fatal("%s table %s: delete operation is not supported",
+ dict->type, dict->name);
+}
+
+/* dict_default_sequence - trap unimplemented operation */
+
+static int dict_default_sequence(DICT *dict, int function,
+ const char **unused_key, const char **unused_value)
+{
+ msg_fatal("%s table %s: sequence operation is not supported",
+ dict->type, dict->name);
+}
+
+/* dict_default_close - trap unimplemented operation */
+
+static void dict_default_close(DICT *dict)
+{
+ msg_fatal("%s table %s: close operation is not supported",
+ dict->type, dict->name);
+}
+
+/* dict_alloc - allocate dictionary object, initialize super-class */
+
+DICT *dict_alloc(const char *dict_type, const char *dict_name, int size)
+{
+ DICT *dict = (DICT *) mymalloc(size);
+
+ dict->type = mystrdup(dict_type);
+ dict->name = mystrdup(dict_name);
+ dict->flags = DICT_FLAG_FIXED;
+ dict->lookup = dict_default_lookup;
+ dict->update = dict_default_update;
+ dict->delete = dict_default_delete;
+ dict->sequence = dict_default_sequence;
+ dict->close = dict_default_close;
+ dict->fd = -1;
+ dict->mtime = 0;
+ return dict;
+}
+
+/* dict_free - super-class destructor */
+
+void dict_free(DICT *dict)
+{
+ myfree(dict->type);
+ myfree(dict->name);
+ myfree((char *) dict);
+}
typedef struct {
DICT dict; /* generic members */
DB *db; /* open db file */
- char *path; /* pathname */
} DICT_DB;
#define DICT_DB_CACHE_SIZE (1024 * 1024)
*/
if ((dict->flags & DICT_FLAG_LOCK)
&& myflock(dict->fd, INTERNAL_LOCK, MYFLOCK_OP_SHARED) < 0)
- msg_fatal("%s: lock dictionary: %m", dict_db->path);
+ msg_fatal("%s: lock dictionary: %m", dict_db->dict.name);
/*
* See if this DB file was written with one null byte appended to key and
db_key.data = (void *) name;
db_key.size = strlen(name) + 1;
if ((status = DICT_DB_GET(db, &db_key, &db_value, 0)) < 0)
- msg_fatal("error reading %s: %m", dict_db->path);
+ msg_fatal("error reading %s: %m", dict_db->dict.name);
if (status == 0) {
dict->flags &= ~DICT_FLAG_TRY0NULL;
result = db_value.data;
db_key.data = (void *) name;
db_key.size = strlen(name);
if ((status = DICT_DB_GET(db, &db_key, &db_value, 0)) < 0)
- msg_fatal("error reading %s: %m", dict_db->path);
+ msg_fatal("error reading %s: %m", dict_db->dict.name);
if (status == 0) {
if (buf == 0)
buf = vstring_alloc(10);
*/
if ((dict->flags & DICT_FLAG_LOCK)
&& myflock(dict->fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0)
- msg_fatal("%s: unlock dictionary: %m", dict_db->path);
+ msg_fatal("%s: unlock dictionary: %m", dict_db->dict.name);
return (result);
}
*/
if ((dict->flags & DICT_FLAG_LOCK)
&& myflock(dict->fd, INTERNAL_LOCK, MYFLOCK_OP_EXCLUSIVE) < 0)
- msg_fatal("%s: lock dictionary: %m", dict_db->path);
+ msg_fatal("%s: lock dictionary: %m", dict_db->dict.name);
/*
* Do the update.
*/
if ((status = DICT_DB_PUT(db, &db_key, &db_value,
(dict->flags & DICT_FLAG_DUP_REPLACE) ? 0 : DONT_CLOBBER)) < 0)
- msg_fatal("error writing %s: %m", dict_db->path);
+ msg_fatal("error writing %s: %m", dict_db->dict.name);
if (status) {
if (dict->flags & DICT_FLAG_DUP_IGNORE)
/* void */ ;
else if (dict->flags & DICT_FLAG_DUP_WARN)
- msg_warn("%s: duplicate entry: \"%s\"", dict_db->path, name);
+ msg_warn("%s: duplicate entry: \"%s\"", dict_db->dict.name, name);
else
- msg_fatal("%s: duplicate entry: \"%s\"", dict_db->path, name);
+ msg_fatal("%s: duplicate entry: \"%s\"", dict_db->dict.name, name);
}
if (dict->flags & DICT_FLAG_SYNC_UPDATE)
if (DICT_DB_SYNC(db, 0) < 0)
- msg_fatal("%s: flush dictionary: %m", dict_db->path);
+ msg_fatal("%s: flush dictionary: %m", dict_db->dict.name);
/*
* Release the exclusive lock.
*/
if ((dict->flags & DICT_FLAG_LOCK)
&& myflock(dict->fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0)
- msg_fatal("%s: unlock dictionary: %m", dict_db->path);
+ msg_fatal("%s: unlock dictionary: %m", dict_db->dict.name);
}
/* delete one entry from the dictionary */
*/
if ((dict->flags & DICT_FLAG_LOCK)
&& myflock(dict->fd, INTERNAL_LOCK, MYFLOCK_OP_EXCLUSIVE) < 0)
- msg_fatal("%s: lock dictionary: %m", dict_db->path);
+ msg_fatal("%s: lock dictionary: %m", dict_db->dict.name);
/*
* See if this DB file was written with one null byte appended to key and
db_key.data = (void *) name;
db_key.size = strlen(name) + 1;
if ((status = DICT_DB_DEL(db, &db_key, flags)) < 0)
- msg_fatal("error deleting from %s: %m", dict_db->path);
+ msg_fatal("error deleting from %s: %m", dict_db->dict.name);
if (status == 0)
dict->flags &= ~DICT_FLAG_TRY0NULL;
}
db_key.data = (void *) name;
db_key.size = strlen(name);
if ((status = DICT_DB_DEL(db, &db_key, flags)) < 0)
- msg_fatal("error deleting from %s: %m", dict_db->path);
+ msg_fatal("error deleting from %s: %m", dict_db->dict.name);
if (status == 0)
dict->flags &= ~DICT_FLAG_TRY1NULL;
}
if (dict->flags & DICT_FLAG_SYNC_UPDATE)
if (DICT_DB_SYNC(db, 0) < 0)
- msg_fatal("%s: flush dictionary: %m", dict_db->path);
+ msg_fatal("%s: flush dictionary: %m", dict_db->dict.name);
/*
* Release the exclusive lock.
*/
if ((dict->flags & DICT_FLAG_LOCK)
&& myflock(dict->fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0)
- msg_fatal("%s: unlock dictionary: %m", dict_db->path);
+ msg_fatal("%s: unlock dictionary: %m", dict_db->dict.name);
return status;
}
*/
if ((dict->flags & DICT_FLAG_LOCK)
&& myflock(dict->fd, INTERNAL_LOCK, MYFLOCK_OP_EXCLUSIVE) < 0)
- msg_fatal("%s: lock dictionary: %m", dict_db->path);
+ msg_fatal("%s: lock dictionary: %m", dict_db->dict.name);
if ((status = db->seq(db, &db_key, &db_value, db_function)) < 0)
- msg_fatal("error seeking %s: %m", dict_db->path);
+ msg_fatal("error seeking %s: %m", dict_db->dict.name);
/*
* Release the exclusive lock.
*/
if ((dict->flags & DICT_FLAG_LOCK)
&& myflock(dict->fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0)
- msg_fatal("%s: unlock dictionary: %m", dict_db->path);
+ msg_fatal("%s: unlock dictionary: %m", dict_db->dict.name);
if (status == 0) {
DICT_DB *dict_db = (DICT_DB *) dict;
if (DICT_DB_SYNC(dict_db->db, 0) < 0)
- msg_fatal("flush database %s: %m", dict_db->path);
+ msg_fatal("flush database %s: %m", dict_db->dict.name);
if (DICT_DB_CLOSE(dict_db->db) < 0)
- msg_fatal("close database %s: %m", dict_db->path);
- myfree(dict_db->path);
- myfree((char *) dict_db);
+ msg_fatal("close database %s: %m", dict_db->dict.name);
+ dict_free(dict);
}
/* dict_db_open - open data base */
-static DICT *dict_db_open(const char *path, int open_flags, int type,
- void *tweak, int dict_flags)
+static DICT *dict_db_open(const char *class, const char *path, int open_flags,
+ int type, void *tweak, int dict_flags)
{
DICT_DB *dict_db;
struct stat st;
if (close(lock_fd) < 0)
msg_fatal("close database %s: %m", db_path);
}
- dict_db = (DICT_DB *) mymalloc(sizeof(*dict_db));
+ dict_db = (DICT_DB *) dict_alloc(class, db_path, sizeof(*dict_db));
dict_db->dict.lookup = dict_db_lookup;
dict_db->dict.update = dict_db_update;
dict_db->dict.delete = dict_db_delete;
if ((dict_flags & (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL)) == 0)
dict_db->dict.flags |= (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL);
dict_db->db = db;
- dict_db->path = db_path;
- return (&dict_db->dict);
+ myfree(db_path);
+ return (DICT_DEBUG(&dict_db->dict));
}
/* dict_hash_open - create association with data base */
tweak = 0;
#endif
- return (dict_db_open(path, open_flags, DB_HASH, (void *) &tweak, dict_flags));
+ return (dict_db_open(DICT_TYPE_HASH, path, open_flags, DB_HASH,
+ (void *) &tweak, dict_flags));
}
/* dict_btree_open - create association with data base */
tweak = 0;
#endif
- return (dict_db_open(path, open_flags, DB_BTREE, (void *) &tweak, dict_flags));
+ return (dict_db_open(DICT_TYPE_BTREE, path, open_flags, DB_BTREE,
+ (void *) &tweak, dict_flags));
}
#endif
/*
* External interface.
*/
+#define DICT_TYPE_HASH "hash"
+#define DICT_TYPE_BTREE "btree"
+
extern DICT *dict_hash_open(const char *, int, int);
extern DICT *dict_btree_open(const char *, int, int);
typedef struct {
DICT dict; /* generic members */
DBM *dbm; /* open database */
- char *path; /* pathname */
} DICT_DBM;
/* dict_dbm_lookup - find database entry */
*/
if ((dict->flags & DICT_FLAG_LOCK)
&& myflock(dict->fd, INTERNAL_LOCK, MYFLOCK_OP_SHARED) < 0)
- msg_fatal("%s: lock dictionary: %m", dict_dbm->path);
+ msg_fatal("%s: lock dictionary: %m", dict_dbm->dict.name);
/*
* See if this DBM file was written with one null byte appended to key
*/
if ((dict->flags & DICT_FLAG_LOCK)
&& myflock(dict->fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0)
- msg_fatal("%s: unlock dictionary: %m", dict_dbm->path);
+ msg_fatal("%s: unlock dictionary: %m", dict_dbm->dict.name);
return (result);
}
*/
if ((dict->flags & DICT_FLAG_LOCK)
&& myflock(dict->fd, INTERNAL_LOCK, MYFLOCK_OP_EXCLUSIVE) < 0)
- msg_fatal("%s: lock dictionary: %m", dict_dbm->path);
+ msg_fatal("%s: lock dictionary: %m", dict_dbm->dict.name);
/*
* Do the update.
*/
if ((status = dbm_store(dict_dbm->dbm, dbm_key, dbm_value,
(dict->flags & DICT_FLAG_DUP_REPLACE) ? DBM_REPLACE : DBM_INSERT)) < 0)
- msg_fatal("error writing DBM database %s: %m", dict_dbm->path);
+ msg_fatal("error writing DBM database %s: %m", dict_dbm->dict.name);
if (status) {
if (dict->flags & DICT_FLAG_DUP_IGNORE)
/* void */ ;
else if (dict->flags & DICT_FLAG_DUP_WARN)
- msg_warn("%s: duplicate entry: \"%s\"", dict_dbm->path, name);
+ msg_warn("%s: duplicate entry: \"%s\"", dict_dbm->dict.name, name);
else
- msg_fatal("%s: duplicate entry: \"%s\"", dict_dbm->path, name);
+ msg_fatal("%s: duplicate entry: \"%s\"", dict_dbm->dict.name, name);
}
/*
*/
if ((dict->flags & DICT_FLAG_LOCK)
&& myflock(dict->fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0)
- msg_fatal("%s: unlock dictionary: %m", dict_dbm->path);
+ msg_fatal("%s: unlock dictionary: %m", dict_dbm->dict.name);
}
/* dict_dbm_delete - delete one entry from the dictionary */
*/
if ((dict->flags & DICT_FLAG_LOCK)
&& myflock(dict->fd, INTERNAL_LOCK, MYFLOCK_OP_EXCLUSIVE) < 0)
- msg_fatal("%s: lock dictionary: %m", dict_dbm->path);
+ msg_fatal("%s: lock dictionary: %m", dict_dbm->dict.name);
/*
* See if this DBM file was written with one null byte appended to key
dbm_clearerr(dict_dbm->dbm);
if ((status = dbm_delete(dict_dbm->dbm, dbm_key)) < 0) {
if (dbm_error(dict_dbm->dbm) != 0) /* fatal error */
- msg_fatal("error deleting from %s: %m", dict_dbm->path);
+ msg_fatal("error deleting from %s: %m", dict_dbm->dict.name);
status = 1; /* not found */
} else {
dict->flags &= ~DICT_FLAG_TRY0NULL; /* found */
dbm_clearerr(dict_dbm->dbm);
if ((status = dbm_delete(dict_dbm->dbm, dbm_key)) < 0) {
if (dbm_error(dict_dbm->dbm) != 0) /* fatal error */
- msg_fatal("error deleting from %s: %m", dict_dbm->path);
+ msg_fatal("error deleting from %s: %m", dict_dbm->dict.name);
status = 1; /* not found */
} else {
dict->flags &= ~DICT_FLAG_TRY1NULL; /* found */
*/
if ((dict->flags & DICT_FLAG_LOCK)
&& myflock(dict->fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0)
- msg_fatal("%s: unlock dictionary: %m", dict_dbm->path);
+ msg_fatal("%s: unlock dictionary: %m", dict_dbm->dict.name);
return (status);
}
*/
if ((dict->flags & DICT_FLAG_LOCK)
&& myflock(dict->fd, INTERNAL_LOCK, MYFLOCK_OP_EXCLUSIVE) < 0)
- msg_fatal("%s: lock dictionary: %m", dict_dbm->path);
+ msg_fatal("%s: lock dictionary: %m", dict_dbm->dict.name);
/*
* Determine and execute the seek function. It returns the key.
*/
if ((dict->flags & DICT_FLAG_LOCK)
&& myflock(dict->fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0)
- msg_fatal("%s: unlock dictionary: %m", dict_dbm->path);
+ msg_fatal("%s: unlock dictionary: %m", dict_dbm->dict.name);
if (dbm_key.dptr != 0 && dbm_key.dsize > 0) {
* condition.
*/
if (dbm_error(dict_dbm->dbm))
- msg_fatal("error seeking %s: %m", dict_dbm->path);
+ msg_fatal("error seeking %s: %m", dict_dbm->dict.name);
return (1); /* no error: eof/not found
* (should not happen!) */
}
* Determine if we have hit the last record or an error condition.
*/
if (dbm_error(dict_dbm->dbm))
- msg_fatal("error seeking %s: %m", dict_dbm->path);
+ msg_fatal("error seeking %s: %m", dict_dbm->dict.name);
return (1); /* no error: eof/not found */
}
return (0);
DICT_DBM *dict_dbm = (DICT_DBM *) dict;
dbm_close(dict_dbm->dbm);
- myfree(dict_dbm->path);
- myfree((char *) dict_dbm);
+ dict_free(dict);
}
/* dict_dbm_open - open DBM data base */
msg_fatal("close database %s: %m", dbm_path);
myfree(dbm_path);
}
- dict_dbm = (DICT_DBM *) mymalloc(sizeof(*dict_dbm));
+ dict_dbm = (DICT_DBM *) dict_alloc(DICT_TYPE_DBM, path, sizeof(*dict_dbm));
dict_dbm->dict.lookup = dict_dbm_lookup;
dict_dbm->dict.update = dict_dbm_update;
dict_dbm->dict.delete = dict_dbm_delete;
if ((dict_flags & (DICT_FLAG_TRY0NULL | DICT_FLAG_TRY1NULL)) == 0)
dict_dbm->dict.flags |= (DICT_FLAG_TRY0NULL | DICT_FLAG_TRY1NULL);
dict_dbm->dbm = dbm;
- dict_dbm->path = mystrdup(path);
- return (&dict_dbm->dict);
+ return (DICT_DEBUG(&dict_dbm->dict));
}
#endif
/*
* External interface.
*/
+#define DICT_TYPE_DBM "dbm"
+
extern DICT *dict_dbm_open(const char *, int, int);
/* LICENSE
--- /dev/null
+/*++
+/* NAME
+/* dict_debug 3
+/* SUMMARY
+/* dictionary manager, logging proxy
+/* SYNOPSIS
+/* #include <dict.h>
+/*
+/* DICT *dict_debug(dict_handle)
+/* DICT *dict_handle;
+/*
+/* DICT *DICT_DEBUG(dict_handle)
+/* DICT *dict_handle;
+/* DESCRIPTION
+/* dict_debug() encapsulates the given dictionary object and returns
+/* a proxy object that logs all access to the encapsulated object.
+/* This is more convenient than having to add logging capability
+/* to each individual dictionary access method.
+/*
+/* DICT_DEBUG() is an unsafe macro that returns the original object if
+/* the object's debugging flag is not set, and that otherwise encapsulates
+/* the object with dict_debug(). This macro simplifies usage by avoiding
+/* clumsy expressions. The macro evaluates its argument multiple times.
+/* DIAGNOSTICS
+/* Fatal errors: out of memory.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System libraries. */
+
+#include <sys_defs.h>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <mymalloc.h>
+#include <dict.h>
+
+/* Application-specific. */
+
+typedef struct {
+ DICT dict; /* the proxy service */
+ DICT *real_dict; /* encapsulated object */
+} DICT_DEBUG;
+
+/* dict_debug_lookup - log lookup operation */
+
+static const char *dict_debug_lookup(DICT *dict, const char *key)
+{
+ DICT_DEBUG *dict_debug = (DICT_DEBUG *) dict;
+ const char *result;
+
+ result = dict_get(dict_debug->real_dict, key);
+ msg_info("%s:%s lookup: \"%s\" = \"%s\"", dict->type, dict->name, key,
+ result ? result : dict_errno ? "try again" : "not_found");
+ return (result);
+}
+
+/* dict_debug_update - log update operation */
+
+static void dict_debug_update(DICT *dict, const char *key, const char *value)
+{
+ DICT_DEBUG *dict_debug = (DICT_DEBUG *) dict;
+
+ msg_info("%s:%s update: \"%s\" = \"%s\"", dict->type, dict->name,
+ key, value);
+ dict_put(dict_debug->real_dict, key, value);
+}
+
+/* dict_debug_delete - log delete operation */
+
+static int dict_debug_delete(DICT *dict, const char *key)
+{
+ DICT_DEBUG *dict_debug = (DICT_DEBUG *) dict;
+ int result;
+
+ result = dict_del(dict_debug->real_dict, key);
+ msg_info("%s:%s delete: \"%s\" = \"%s\"", dict->type, dict->name, key,
+ result ? "failed" : "success");
+ return (result);
+}
+
+/* dict_debug_sequence - log sequence operation */
+
+static int dict_debug_sequence(DICT *dict, int function,
+ const char **key, const char **value)
+{
+ DICT_DEBUG *dict_debug = (DICT_DEBUG *) dict;
+ int result;
+
+ result = dict_seq(dict_debug->real_dict, function, key, value);
+ if (result == 0)
+ msg_info("%s:%s sequence: \"%s\" = \"%s\"", dict->type, dict->name,
+ *key, *value);
+ else
+ msg_info("%s:%s sequence: found EOF", dict->type, dict->name);
+ return (result);
+}
+
+/* dict_debug_close - log operation */
+
+static void dict_debug_close(DICT *dict)
+{
+ DICT_DEBUG *dict_debug = (DICT_DEBUG *) dict;
+
+ dict_close(dict_debug->real_dict);
+ dict_free(dict);
+}
+
+/* dict_debug - encapsulate dictionary object and install proxies */
+
+DICT *dict_debug(DICT *real_dict)
+{
+ DICT_DEBUG *dict_debug;
+
+ dict_debug = (DICT_DEBUG *) dict_alloc(real_dict->type,
+ real_dict->name, sizeof(*dict_debug));
+ dict_debug->dict.flags = real_dict->flags; /* XXX not synchronized */
+ dict_debug->dict.lookup = dict_debug_lookup;
+ dict_debug->dict.update = dict_debug_update;
+ dict_debug->dict.delete = dict_debug_delete;
+ dict_debug->dict.sequence = dict_debug_sequence;
+ dict_debug->dict.close = dict_debug_close;
+ dict_debug->real_dict = real_dict;
+ return (&dict_debug->dict);
+}
static void dict_env_close(DICT *dict)
{
- myfree((char *) dict);
+ dict_free(dict);
}
/* dict_env_open - make association with environment array */
-DICT *dict_env_open(const char *unused_name, int unused_flags, int dict_flags)
+DICT *dict_env_open(const char *name, int unused_flags, int dict_flags)
{
DICT *dict;
- dict = (DICT *) mymalloc(sizeof(*dict));
+ dict = dict_alloc(DICT_TYPE_ENVIRON, name, sizeof(*dict));
dict->lookup = dict_env_lookup;
dict->update = dict_env_update;
dict->close = dict_env_close;
dict->flags = dict_flags | DICT_FLAG_FIXED;
- dict->fd = -1;
- return (dict);
+ return (DICT_DEBUG(dict));
}
/*
* External interface.
*/
+#define DICT_TYPE_ENVIRON "environ"
+
extern DICT *dict_env_open(const char *, int, int);
/* LICENSE
/* SYNOPSIS
/* #include <dict_ht.h>
/*
-/* DICT *dict_ht_open(table, remove)
+/* DICT *dict_ht_open(name, table, remove)
+/* const char *name;
/* HTABLE *table;
/* void (*remove)(char *value)
/* DESCRIPTION
if (dict_ht->remove)
htable_free(dict_ht->table, dict_ht->remove);
- myfree((char *) dict);
+ dict_free(dict);
}
/* dict_ht_open - create association with hash table */
-DICT *dict_ht_open(HTABLE *table, void (*remove) (char *))
+DICT *dict_ht_open(const char *name, HTABLE *table, void (*remove) (char *))
{
DICT_HT *dict_ht;
- dict_ht = (DICT_HT *) mymalloc(sizeof(*dict_ht));
+ dict_ht = (DICT_HT *) dict_alloc(DICT_TYPE_HT, name, sizeof(*dict_ht));
dict_ht->dict.lookup = dict_ht_lookup;
dict_ht->dict.update = dict_ht_update;
dict_ht->dict.close = dict_ht_close;
- dict_ht->dict.fd = -1;
dict_ht->table = table;
dict_ht->remove = remove;
return (&dict_ht->dict);
/*
* External interface.
*/
-extern DICT *dict_ht_open(HTABLE *, void (*) (char *));
+#define DICT_TYPE_HT "internal"
+
+extern DICT *dict_ht_open(const char *, HTABLE *, void (*) (char *));
/* LICENSE
/* .ad
#include <stdlib.h>
#include <lber.h>
#include <ldap.h>
+#include <string.h>
/* Utility library. */
* load on the LDAP server.
*/
if (dict_ldap->domain) {
- if (strrchr(name, '@') != 0) {
- if (match_list_match(dict_ldap->domain, (char *) strrchr(name, '@') + 1) == 0) {
- if (msg_verbose)
- msg_info("%s: domain of %s not found in domain list", myname,
- name);
- return (0);
- }
+ char *p=strrchr(name,'@');
+ if (p != 0)
+ p=p+1;
+ else
+ p=name;
+ if (match_list_match(dict_ldap->domain, p) == 0) {
+ if (msg_verbose)
+ msg_info("%s: domain of %s not found in domain list", myname,
+ name);
+ return (0);
}
}
return (VSTRING_LEN(result) > 0 && !dict_errno ? vstring_str(result) : 0);
}
-/* dict_ldap_update - add or update database entry */
-
-static void dict_ldap_update(DICT *dict, const char *unused_name,
- const char *unused_value)
-{
- msg_fatal("dict_ldap_update: Operation not implemented");
-}
-
/* dict_ldap_close - disassociate from data base */
static void dict_ldap_close(DICT *dict)
argv_free(dict_ldap->result_attributes);
myfree(dict_ldap->bind_dn);
myfree(dict_ldap->bind_pw);
- myfree((char *) dict_ldap);
+ dict_free(dict);
}
/* dict_ldap_open - create association with data base */
char *scope;
char *attr;
- dict_ldap = (DICT_LDAP *) mymalloc(sizeof(*dict_ldap));
+ dict_ldap = (DICT_LDAP *) dict_alloc(DICT_TYPE_LDAP, ldapsource,
+ sizeof(*dict_ldap));
dict_ldap->dict.lookup = dict_ldap_lookup;
- dict_ldap->dict.update = dict_ldap_update;
dict_ldap->dict.close = dict_ldap_close;
- dict_ldap->dict.fd = -1;
dict_ldap->dict.flags = dict_flags | DICT_FLAG_FIXED;
if (msg_verbose)
/*
* Otherwise, we're all set. Return the new dict_ldap structure.
*/
- return (&dict_ldap->dict);
+ return (DICT_DEBUG(&dict_ldap->dict));
}
#endif
/*
* External interface.
*/
+#define DICT_TYPE_LDAP "ldap"
+
extern DICT *dict_ldap_open(const char *, int, int);
/* AUTHOR(S)
#include <stdlib.h>
#include <syslog.h>
#include <time.h>
+#include <mysql.h>
/* Utility library. */
#include "dict.h"
#include "split_at.h"
#include "find_inet.h"
-/* external declarations */
-extern int dict_errno;
-
/* need some structs to help organize things */
typedef struct {
MYSQL *db;
MYSQL_NAME *name;
} DICT_MYSQL;
+#define STATACTIVE 0
+#define STATFAIL 1
+#define STATUNTRIED 2
+#define RETRY_CONN_INTV 60 /* 1 minute */
+
/* internal function declarations */
static PLMYSQL *plmysql_init(char *hostnames[], int);
static MYSQL_RES *plmysql_query(PLMYSQL *, const char *, char *, char *, char *);
static void plmysql_down_host(HOST *);
static void plmysql_connect_single(HOST *, char *, char *, char *);
static int plmysql_ready_reconn(HOST *);
-static void dict_mysql_update(DICT *, const char *, const char *);
-static void dict_mysql_delete(DICT *, const char *);
-static void dict_mysql_sequence(DICT *, const int, const char **, const char **);
static const char *dict_mysql_lookup(DICT *, const char *);
DICT *dict_mysql_open(const char *, int, int);
static void dict_mysql_close(DICT *);
* parse the map's config file
* allocate memory
**********************************************************************/
-DICT *dict_mysql_open(const char *name, int unused_flags, int unused_dict_flags)
+DICT *dict_mysql_open(const char *name, int unused_open_flags, int dict_flags)
{
DICT_MYSQL *dict_mysql;
int connections;
- dict_mysql = (DICT_MYSQL *) mymalloc(sizeof(DICT_MYSQL));
+ dict_mysql = (DICT_MYSQL *) dict_alloc(DICT_TYPE_MYSQL, name,
+ sizeof(DICT_MYSQL));
dict_mysql->dict.lookup = dict_mysql_lookup;
- dict_mysql->dict.update = dict_mysql_update;
- dict_mysql->dict.delete = dict_mysql_delete;
- dict_mysql->dict.sequence = dict_mysql_sequence;
dict_mysql->dict.close = dict_mysql_close;
- dict_mysql->dict.fd = -1; /* there's no file descriptor
- * for locking */
+ dict_mysql->dict.flags = dict_flags | DICT_FLAG_FIXED;
dict_mysql->name = mysqlname_parse(name);
dict_mysql->pldb = plmysql_init(dict_mysql->name->hostnames,
dict_mysql->name->len_hosts);
if (dict_mysql->pldb == NULL)
msg_fatal("couldn't intialize pldb!\n");
dict_register(name, (DICT *) dict_mysql);
- return &dict_mysql->dict;
+ return (DICT_DEBUG(&dict_mysql->dict));
}
/* mysqlname_parse - parse mysql configuration file */
}
myfree((char *) dict_mysql->name->hostnames);
myfree((char *) dict_mysql->name);
+ dict_free(dict);
}
/* plmysql_dealloc - free memory associated with PLMYSQL close databases */
myfree((char *) (PLDB));
}
-
-/**********************************************************************
- * public interface dict_mysql_update - add or update table entry
- *
- *********************************************************************/
-static void dict_mysql_update(DICT *dict, const char *unused_name, const char *unused_value)
-{
- DICT_MYSQL *dict_mysql = (DICT_MYSQL *) dict;
-
- msg_fatal("dict_mysql_update: attempt to update mysql database");
-}
-
-static void dict_mysql_delete(DICT *unused_dict, const char *unused_name)
-{
- msg_fatal("dict_mysql_delete: attempt to delete mysql database entry");
-}
-
-static void dict_mysql_sequence(DICT *unused_dict, const int unused_function,
- const char **unused_key, const char **unused_value)
-{
- msg_fatal("dict_mysql_sequence: attempt to iterate over mysql database");
-}
-
#endif
-#ifdef HAS_MYSQL
+#ifndef _DICT_MYSQL_H_INCLUDED_
+#define _DICT_MYSQL_H_INCLUDED_
-#include <time.h>
-#include "mysql.h"
+/*++
+/* NAME
+/* dict_mysql 3h
+/* SUMMARY
+/* dictionary manager interface to mysql databases
+/* SYNOPSIS
+/* #include <dict_mysql.h>
+/* DESCRIPTION
+/* .nf
-#define STATACTIVE 0
-#define STATFAIL 1
-#define STATUNTRIED 2
-#define RETRY_CONN_INTV 60 /* 1 minute */
+ /*
+ * Utility library.
+ */
+#include <dict.h>
-extern DICT *dict_mysql_open(const char *name, int unused_flags, int dict_flags);
+ /*
+ * External interface.
+ */
+#define DICT_TYPE_MYSQL "mysql"
+extern DICT *dict_mysql_open(const char *, int, int);
+
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Scott Cotton
+/* IC Group, Inc.
+/* scott@icgroup.com
+/*
+/* Joshua Marcus
+/* IC Group, Inc.
+/* josh@icgroup.com
+/*--*/
#endif
{
DICT_NI *d = (DICT_NI *) dict;
- return dict_ni_do_lookup(d->path, NETINFO_PROP_KEY,
+ return dict_ni_do_lookup(d->dict.name, NETINFO_PROP_KEY,
key, NETINFO_PROP_VALUE);
}
-/* dict_ni_update - add or update table entry (not!) */
-
-static void dict_ni_update(DICT *dict, const char *unused_name,
- const char *unused_value)
-{
- DICT_NI *d = (DICT_NI *) dict;
-
- msg_fatal("dict_ni_update: unimplemented: update NetInfo directory %s",
- d->path);
-}
-
/* dict_ni_close - disassociate from NetInfo map */
static void dict_ni_close(DICT *dict)
{
DICT_NI *d = (DICT_NI *) dict;
- myfree(d->path);
- myfree((char *) d);
+ dict_free(dict);
}
/* dict_ni_open - create association with NetInfo map */
DICT *dict_ni_open(const char *path, int unused_flags, int dict_flags)
{
- DICT_NI *d = (void *) mymalloc(sizeof(*d));
+ DICT_NI *d = (void *) dict_alloc(DICT_TYPE_NETINFO, path, sizeof(*d));
d->dict.lookup = dict_ni_lookup;
- d->dict.update = dict_ni_update;
d->dict.close = dict_ni_close;
- d->dict.fd = -1;
d->dict.flags = dict_flags | DICT_FLAG_FIXED;
- d->path = mystrdup(path);
- return &d->dict;
+ return (DICT_DEBUG(&d->dict));
}
#endif
/*
* External interface.
*/
+#define DICT_TYPE_NETINFO "netinfo"
+
extern DICT *dict_ni_open(const char *, int, int);
/* AUTHOR(S)
typedef struct {
DICT dict; /* generic members */
- char *map; /* NIS map name */
} DICT_NIS;
/*
* value.
*/
if (dict->flags & DICT_FLAG_TRY1NULL) {
- err = yp_match(dict_nis_domain, dict_nis->map,
+ err = yp_match(dict_nis_domain, dict_nis->dict.name,
(void *) key, strlen(key) + 1,
&result, &result_len);
if (err == 0) {
* value. This should never be the case, but better play safe.
*/
if (dict->flags & DICT_FLAG_TRY0NULL) {
- err = yp_match(dict_nis_domain, dict_nis->map,
+ err = yp_match(dict_nis_domain, dict_nis->dict.name,
(void *) key, strlen(key),
&result, &result_len);
if (err == 0) {
*/
if (err != YPERR_KEY) {
msg_warn("lookup %s, NIS domain %s, map %s: %s",
- key, dict_nis_domain, dict_nis->map,
+ key, dict_nis_domain, dict_nis->dict.name,
dict_nis_strerror(err));
dict_errno = DICT_ERR_RETRY;
}
return (0);
}
-/* dict_nis_update - add or update table entry */
-
-static void dict_nis_update(DICT *dict, const char *unused_name, const char *unused_value)
-{
- DICT_NIS *dict_nis = (DICT_NIS *) dict;
-
- msg_fatal("dict_nis_update: attempt to update NIS map %s", dict_nis->map);
-}
-
/* dict_nis_close - close NIS map */
static void dict_nis_close(DICT *dict)
{
DICT_NIS *dict_nis = (DICT_NIS *) dict;
- myfree(dict_nis->map);
- myfree((char *) dict_nis);
+ dict_free(dict);
}
/* dict_nis_open - open NIS map */
{
DICT_NIS *dict_nis;
- dict_nis = (DICT_NIS *) mymalloc(sizeof(*dict_nis));
+ dict_nis = (DICT_NIS *) dict_alloc(DICT_TYPE_NIS, map, sizeof(*dict_nis));
dict_nis->dict.lookup = dict_nis_lookup;
- dict_nis->dict.update = dict_nis_update;
dict_nis->dict.close = dict_nis_close;
- dict_nis->dict.fd = -1;
- dict_nis->map = mystrdup(map);
dict_nis->dict.flags = dict_flags | DICT_FLAG_FIXED;
if ((dict_flags & (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL)) == 0)
dict_nis->dict.flags |= (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL);
if (dict_nis_domain == 0)
dict_nis_init();
- return (&dict_nis->dict);
+ return (DICT_DEBUG(&dict_nis->dict));
}
#endif
/*
* External interface.
*/
+#define DICT_TYPE_NIS "nis"
+
extern DICT *dict_nis_open(const char *, int, int);
/* LICENSE
typedef struct {
DICT dict; /* generic members */
- char *map; /* NISPLUS map name */
} DICT_NISPLUS;
-/* dict_nisplus_lookup - find table entry */
-
-static const char *dict_nisplus_lookup(DICT *unused_dict, const char *unused_name)
-{
- dict_errno = 0;
- msg_warn("dict_nisplus_lookup: NISPLUS lookup not implemented");
- return (0);
-}
-
-/* dict_nisplus_update - add or update table entry */
-
-static void dict_nisplus_update(DICT *dict, const char *unused_name, const char *unused_value)
-{
- DICT_NISPLUS *dict_nisplus = (DICT_NISPLUS *) dict;
-
- msg_fatal("dict_nisplus_update: attempt to update NIS+ map %s",
- dict_nisplus->map);
-}
-
/* dict_nisplus_close - close NISPLUS map */
static void dict_nisplus_close(DICT *dict)
{
DICT_NISPLUS *dict_nisplus = (DICT_NISPLUS *) dict;
- myfree(dict_nisplus->map);
myfree((char *) dict_nisplus);
}
{
DICT_NISPLUS *dict_nisplus;
- dict_nisplus = (DICT_NISPLUS *) mymalloc(sizeof(*dict_nisplus));
- dict_nisplus->dict.lookup = dict_nisplus_lookup;
- dict_nisplus->dict.update = dict_nisplus_update;
+ dict_nisplus = (DICT_NISPLUS *) dict_alloc(DICT_TYPE_NISPLUS, map,
+ sizeof(*dict_nisplus));
dict_nisplus->dict.close = dict_nisplus_close;
- dict_nisplus->dict.fd = -1;
- dict_nisplus->map = mystrdup(map);
dict_nisplus->dict.flags = dict_flags | DICT_FLAG_FIXED;
- return (&dict_nisplus->dict);
+ return (DICT_DEBUG(&dict_nisplus->dict));
}
/*
* External interface.
*/
+#define DICT_TYPE_NISPLUS "nisplus"
+
extern DICT *dict_nisplus_open(const char *, int, int);
/* LICENSE
} DICT_OPEN_INFO;
static DICT_OPEN_INFO dict_open_info[] = {
- "environ", dict_env_open,
- "unix", dict_unix_open,
+ DICT_TYPE_ENVIRON, dict_env_open,
+ DICT_TYPE_UNIX, dict_unix_open,
#if 0
- "tcp", dict_tcp_open,
+ DICT_TYPE_TCP, dict_tcp_open,
#endif
#ifdef HAS_DBM
- "dbm", dict_dbm_open,
+ DICT_TYPE_DBM, dict_dbm_open,
#endif
#ifdef HAS_DB
- "hash", dict_hash_open,
- "btree", dict_btree_open,
+ DICT_TYPE_HASH, dict_hash_open,
+ DICT_TYPE_BTREE, dict_btree_open,
#endif
#ifdef HAS_NIS
- "nis", dict_nis_open,
+ DICT_TYPE_NIS, dict_nis_open,
#endif
#ifdef HAS_NISPLUS
- "nisplus", dict_nisplus_open,
+ DICT_TYPE_NISPLUS, dict_nisplus_open,
#endif
#ifdef HAS_NETINFO
- "netinfo", dict_ni_open,
+ DICT_TYPE_NETINFO, dict_ni_open,
#endif
#ifdef HAS_LDAP
- "ldap", dict_ldap_open,
+ DICT_TYPE_LDAP, dict_ldap_open,
#endif
#ifdef HAS_MYSQL
- "mysql", dict_mysql_open,
+ DICT_TYPE_MYSQL, dict_mysql_open,
#endif
#ifdef HAS_PCRE
- "pcre", dict_pcre_open,
+ DICT_TYPE_PCRE, dict_pcre_open,
#endif
#ifdef HAS_POSIX_REGEXP
- "regexp", dict_regexp_open,
+ DICT_TYPE_REGEXP, dict_regexp_open,
#endif
0,
};
typedef struct {
DICT dict; /* generic members */
- char *map; /* map name */
- int flags; /* unused at the moment */
struct dict_pcre_list *head;
} DICT_PCRE;
static dict_pcre_init = 0; /* flag need to init pcre library */
-/*
- * dict_pcre_update - not supported
- */
-static void dict_pcre_update(DICT *dict, const char *unused_name,
- const char *unused_value)
-{
- DICT_PCRE *dict_pcre = (DICT_PCRE *) dict;
-
- msg_fatal("dict_pcre_update: attempt to update regexp map %s",
- dict_pcre->map);
-}
-
/*
* Context for macro expansion callback.
*/
dict_errno = 0;
if (msg_verbose)
- msg_info("dict_pcre_lookup: %s: %s", dict_pcre->map, name);
+ msg_info("dict_pcre_lookup: %s: %s", dict_pcre->dict.name, name);
/* Search for a matching expression */
ctxt.matches = 0;
/* An error */
switch (ctxt.matches) {
case 0:
- msg_warn("regexp map %s, line %d: too many (...)",
- dict_pcre->map, pcre_list->lineno);
+ msg_warn("pcre map %s, line %d: too many (...)",
+ dict_pcre->dict.name, pcre_list->lineno);
break;
case PCRE_ERROR_NULL:
case PCRE_ERROR_BADOPTION:
- msg_fatal("regexp map %s, line %d: bad args to re_exec",
- dict_pcre->map, pcre_list->lineno);
+ msg_fatal("pcre map %s, line %d: bad args to re_exec",
+ dict_pcre->dict.name, pcre_list->lineno);
break;
case PCRE_ERROR_BADMAGIC:
case PCRE_ERROR_UNKNOWN_NODE:
- msg_fatal("regexp map %s, line %d: corrupt compiled regexp",
- dict_pcre->map, pcre_list->lineno);
+ msg_fatal("pcre map %s, line %d: corrupt compiled regexp",
+ dict_pcre->dict.name, pcre_list->lineno);
break;
default:
- msg_fatal("regexp map %s, line %d: unknown re_exec error: %d",
- dict_pcre->map, pcre_list->lineno, ctxt.matches);
+ msg_fatal("pcre map %s, line %d: unknown re_exec error: %d",
+ dict_pcre->dict.name, pcre_list->lineno, ctxt.matches);
break;
}
return ((char *) 0);
VSTRING_RESET(buf);
ctxt.buf = buf;
ctxt.subject = name;
- ctxt.dict_name = dict_pcre->map;
+ ctxt.dict_name = dict_pcre->dict.name;
ctxt.lineno = pcre_list->lineno;
if (mac_parse(pcre_list->replace, dict_pcre_action, (char *) &ctxt) & MAC_PARSE_ERROR)
- msg_fatal("regexp map %s, line %d: bad replacement syntax",
- dict_pcre->map, pcre_list->lineno);
+ msg_fatal("pcre map %s, line %d: bad replacement syntax",
+ dict_pcre->dict.name, pcre_list->lineno);
VSTRING_TERMINATE(buf);
return (vstring_str(buf));
{
DICT_PCRE *dict_pcre = (DICT_PCRE *) dict;
struct dict_pcre_list *pcre_list;
+ struct dict_pcre_list *next;
- for (pcre_list = dict_pcre->head; pcre_list; pcre_list = pcre_list->next) {
+ for (pcre_list = dict_pcre->head; pcre_list; pcre_list = next) {
+ next = pcre_list->next;
if (pcre_list->pattern)
myfree((char *) pcre_list->pattern);
if (pcre_list->hints)
myfree((char *) pcre_list->hints);
if (pcre_list->replace)
myfree((char *) pcre_list->replace);
+ myfree((char *) pcre_list);
}
- myfree(dict_pcre->map);
- myfree((char *) dict_pcre);
+ dict_free(dict);
}
/*
line_buffer = vstring_alloc(100);
- dict_pcre = (DICT_PCRE *) mymalloc(sizeof(*dict_pcre));
+ dict_pcre = (DICT_PCRE *) dict_alloc(DICT_TYPE_PCRE, map,
+ sizeof(*dict_pcre));
dict_pcre->dict.lookup = dict_pcre_lookup;
- dict_pcre->dict.update = dict_pcre_update;
dict_pcre->dict.close = dict_pcre_close;
- dict_pcre->dict.fd = -1;
- dict_pcre->map = mystrdup(map);
dict_pcre->dict.flags = dict_flags | DICT_FLAG_PATTERN;
dict_pcre->head = NULL;
vstring_free(line_buffer);
vstream_fclose(map_fp);
- return (&dict_pcre->dict);
+ return (DICT_DEBUG(&dict_pcre->dict));
}
#endif /* HAS_PCRE */
/*
* External interface.
*/
+#define DICT_TYPE_PCRE "pcre"
+
extern DICT *dict_pcre_open(const char *, int, int);
/* LICENSE
const char *subject; /* str against which we match */
};
-/*
- * dict_regexp_update - not supported
- */
-static void dict_regexp_update(DICT *dict, const char *unused_name,
- const char *unused_value)
-{
- DICT_REGEXP *dict_regexp = (DICT_REGEXP *) dict;
-
- msg_fatal("dict_regexp_update: attempt to update regexp map %s",
- dict_regexp->map);
-}
-
/*
* Macro expansion callback - replace $0-${99} with strings cut from
* matched string.
n = atoi(vstring_str(buf));
if (n >= dict->nmatch)
msg_fatal("regexp %s, line %d: replacement index out of range",
- dict->map, rule->lineno);
+ dict->dict.name, rule->lineno);
if (dict->pmatch[n].rm_so < 0 ||
dict->pmatch[n].rm_so == dict->pmatch[n].rm_eo) {
return (MAC_PARSE_UNDEF); /* empty string or not
dict_errno = 0;
if (msg_verbose)
- msg_info("dict_regexp_lookup: %s: %s", dict_regexp->map, name);
+ msg_info("dict_regexp_lookup: %s: %s", dict_regexp->dict.name, name);
/* Search for a matching expression */
for (rule = dict_regexp->head; rule; rule = rule->next) {
(void) regerror(error, rule->expr[1], errbuf, sizeof(errbuf));
msg_fatal("regexp map %s, line %d: %s.",
- dict_regexp->map, rule->lineno, errbuf);
+ dict_regexp->dict.name, rule->lineno, errbuf);
}
}
if (mac_parse(rule->replace, dict_regexp_action, (char *) &ctxt) & MAC_PARSE_ERROR)
msg_fatal("regexp map %s, line %d: bad replacement syntax.",
- dict_regexp->map, rule->lineno);
+ dict_regexp->dict.name, rule->lineno);
VSTRING_TERMINATE(buf);
return (vstring_str(buf));
(void) regerror(error, rule->expr[0], errbuf, sizeof(errbuf));
msg_fatal("regexp map %s, line %d: %s.",
- dict_regexp->map, rule->lineno, errbuf);
+ dict_regexp->dict.name, rule->lineno, errbuf);
return ((char *) 0);
}
}
}
if (dict_regexp->pmatch)
myfree((char *) dict_regexp->pmatch);
- myfree(dict_regexp->map);
- myfree((char *) dict_regexp);
+ dict_free(dict);
}
static regex_t *dict_regexp_get_expr(int lineno, char **bufp, VSTREAM *map_fp)
line_buffer = vstring_alloc(100);
- dict_regexp = (DICT_REGEXP *) mymalloc(sizeof(*dict_regexp));
+ dict_regexp = (DICT_REGEXP *) dict_alloc(DICT_TYPE_REGEXP, map,
+ sizeof(*dict_regexp));
dict_regexp->dict.lookup = dict_regexp_lookup;
- dict_regexp->dict.update = dict_regexp_update;
dict_regexp->dict.close = dict_regexp_close;
- dict_regexp->dict.fd = -1;
- dict_regexp->map = mystrdup(map);
dict_regexp->dict.flags = dict_flags | DICT_FLAG_PATTERN;
dict_regexp->head = 0;
dict_regexp->pmatch = 0;
vstring_free(line_buffer);
vstream_fclose(map_fp);
- return (&dict_regexp->dict);
+ return (DICT_DEBUG(&dict_regexp->dict));
}
#endif
/*
* External interface.
*/
+#define DICT_TYPE_REGEXP "regexp"
+
extern DICT *dict_regexp_open(const char *, int, int);
/* AUTHOR(S)
typedef struct {
DICT dict; /* generic members */
- char *map; /* server host:port */
VSTRING *raw_buf; /* raw I/O buffer */
VSTRING *hex_buf; /* quoted I/O buffer */
VSTREAM *fp; /* I/O stream */
* Connect to the server. Enforce a time limit on read/write operations
* so that we do not get stuck.
*/
- if ((fd = inet_connect(dict_tcp->map, BLOCKING, 0)) < 0) {
- msg_warn("connect to TCP map %s: %m", dict_tcp->map);
+ if ((fd = inet_connect(dict_tcp->dict.name, BLOCKING, 0)) < 0) {
+ msg_warn("connect to TCP map %s: %m", dict_tcp->dict.name);
return (-1);
}
dict_tcp->fp = vstream_fdopen(fd, O_RDWR);
* Disconnect from the server if it can't talk to us.
*/
msg_warn("read TCP map reply from %s: unexpected EOF (%m)",
- dict_tcp->map);
+ dict_tcp->dict.name);
dict_tcp_disconnect(dict_tcp);
}
|| !ISDIGIT(start[2]) || !ISSPACE(start[3])
|| !hex_unquote(dict_tcp->raw_buf, start + 4)) {
msg_warn("read TCP map reply from %s: malformed reply %.100s",
- dict_tcp->map, printable(STR(dict_tcp->hex_buf), '_'));
+ dict_tcp->dict.name, printable(STR(dict_tcp->hex_buf), '_'));
dict_tcp_disconnect(dict_tcp);
RETURN(DICT_ERR_RETRY, 0);
}
switch (start[0]) {
default:
msg_warn("read TCP map reply from %s: bad status code %.100s",
- dict_tcp->map, printable(STR(dict_tcp->hex_buf), '_'));
+ dict_tcp->dict.name, printable(STR(dict_tcp->hex_buf), '_'));
dict_tcp_disconnect(dict_tcp);
RETURN(DICT_ERR_RETRY, 0);
case '4':
}
}
-/* dict_tcp_update - add or update table entry */
-
-static void dict_tcp_update(DICT *dict, const char *unused_name, const char *unused_value)
-{
- DICT_TCP *dict_tcp = (DICT_TCP *) dict;
-
- msg_fatal("dict_tcp_update: attempt to update map %s", dict_tcp->map);
-}
-
-/* dict_tcp_delete - remove table entry */
-
-static int dict_tcp_delete(DICT *dict, const char *unused_name)
-{
- DICT_TCP *dict_tcp = (DICT_TCP *) dict;
-
- msg_fatal("dict_tcp_delete: attempt to update map %s", dict_tcp->map);
-}
-
-/* dict_tcp_sequence - iterate over table */
-
-static int dict_tcp_sequence(DICT *dict, int unused_func,
- const char **unused_name, const char **unused_value)
-{
- DICT_TCP *dict_tcp = (DICT_TCP *) dict;
-
- msg_fatal("dict_tcp_sequence: attempt to iterate map %s", dict_tcp->map);
-}
-
/* dict_tcp_close - close TCP map */
static void dict_tcp_close(DICT *dict)
vstring_free(dict_tcp->raw_buf);
if (dict_tcp->hex_buf)
vstring_free(dict_tcp->hex_buf);
- myfree(dict_tcp->map);
- myfree((char *) dict_tcp);
+ dict_free(dict);
}
/* dict_tcp_open - open TCP map */
dict_errno = 0;
- dict_tcp = (DICT_TCP *) mymalloc(sizeof(*dict_tcp));
+ dict_tcp = (DICT_TCP *) dict_alloc(DICT_TYPE_TCP, map, sizeof(*dict_tcp));
dict_tcp->fp = 0;
dict_tcp->raw_buf = dict_tcp->hex_buf = 0;
dict_tcp->dict.lookup = dict_tcp_lookup;
- dict_tcp->dict.update = dict_tcp_update;
- dict_tcp->dict.delete = dict_tcp_delete;
- dict_tcp->dict.sequence = dict_tcp_sequence;
dict_tcp->dict.close = dict_tcp_close;
- dict_tcp->dict.fd = -1;
- dict_tcp->map = mystrdup(map);
dict_tcp->dict.flags = dict_flags | DICT_FLAG_FIXED;
- return (&dict_tcp->dict);
+ return (DICT_DEBUG(&dict_tcp->dict));
}
/*
* External interface.
*/
+#define DICT_TYPE_TCP "tcp"
+
extern DICT *dict_tcp_open(const char *, int, int);
/* LICENSE
typedef struct {
DICT dict; /* generic members */
- char *map; /* UNIX map name */
} DICT_UNIX;
/* dict_unix_getpwnam - find password table entry */
}
}
-/* dict_unix_update - add or update table entry */
-
-static void dict_unix_update(DICT *dict, const char *unused_name, const char *unused_value)
-{
- DICT_UNIX *dict_unix = (DICT_UNIX *) dict;
-
- msg_fatal("dict_unix_update: attempt to update map %s", dict_unix->map);
-}
-
/* dict_unix_close - close UNIX map */
static void dict_unix_close(DICT *dict)
{
DICT_UNIX *dict_unix = (DICT_UNIX *) dict;
- myfree(dict_unix->map);
- myfree((char *) dict_unix);
+ dict_free(dict);
}
/* dict_unix_open - open UNIX map */
dict_errno = 0;
- dict_unix = (DICT_UNIX *) mymalloc(sizeof(*dict_unix));
+ dict_unix = (DICT_UNIX *) dict_alloc(DICT_TYPE_UNIX, map,
+ sizeof(*dict_unix));
for (lp = dict_unix_lookup; /* void */ ; lp++) {
if (lp->name == 0)
msg_fatal("dict_unix_open: unknown map name: %s", map);
break;
}
dict_unix->dict.lookup = lp->lookup;
- dict_unix->dict.update = dict_unix_update;
dict_unix->dict.close = dict_unix_close;
- dict_unix->dict.fd = -1;
- dict_unix->map = mystrdup(map);
dict_unix->dict.flags = dict_flags | DICT_FLAG_FIXED;
- return (&dict_unix->dict);
+ return (DICT_DEBUG(&dict_unix->dict));
}
/*
* External interface.
*/
+#define DICT_TYPE_UNIX "unix"
+
extern DICT *dict_unix_open(const char *, int, int);
/* LICENSE
/* Utility library. */
#include "iostuff.h"
+#include "sane_socketpair.h"
/* duplex_pipe - give me a duplex pipe or bust */
#ifdef HAS_DUPLEX_PIPE
return (pipe(fds));
#else
- return (socketpair(AF_UNIX, SOCK_STREAM, 0, fds));
+ return (sane_socketpair(AF_UNIX, SOCK_STREAM, 0, fds));
#endif
}
if (gethostname(namebuf, sizeof(namebuf)) < 0)
msg_fatal("gethostname: %m");
namebuf[MAXHOSTNAMELEN] = 0;
- if (valid_hostname(namebuf) == 0)
+ if (valid_hostname(namebuf, DO_GRIPE) == 0)
msg_fatal("unable to use my own hostname");
my_host_name = mystrdup(namebuf);
}
/* SYNOPSIS
/* #include <inet_addr_local.h>
/*
-/* int inet_addr_local(list)
-/* INET_ADDR_LIST *list;
+/* int inet_addr_local(addr_list, mask_list)
+/* INET_ADDR_LIST *addr_list;
+/* INET_ADDR_LIST *mask_list;
/* DESCRIPTION
/* inet_addr_local() determines all active IP interface addresses
/* of the local system. Any address found is appended to the
/* specified address list. The result value is the number of
/* active interfaces found.
+/*
+/* The mask_list is either a null pointer, or it is a list that
+/* receives the netmasks of the interface addresses that were found.
/* DIAGNOSTICS
/* Fatal errors: out of memory.
/* SEE ALSO
#include <sys/sockio.h>
#endif
#include <errno.h>
+#include <string.h>
/* Utility library. */
#ifdef _SIZEOF_ADDR_IFREQ
#define NEXT_INTERFACE(ifr) ((struct ifreq *) \
((char *) ifr + _SIZEOF_ADDR_IFREQ(*ifr)))
+#define IFREQ_SIZE(ifr) _SIZEOF_ADDR_IFREQ(*ifr)
#else
#ifdef HAS_SA_LEN
#define NEXT_INTERFACE(ifr) ((struct ifreq *) \
((char *) ifr + sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len))
+#define IFREQ_SIZE(ifr) (sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len)
#else
#define NEXT_INTERFACE(ifr) (ifr + 1)
+#define IFREQ_SIZE(ifr) sizeof(ifr[0])
#endif
#endif
/* inet_addr_local - find all IP addresses for this host */
-int inet_addr_local(INET_ADDR_LIST *addr_list)
+int inet_addr_local(INET_ADDR_LIST *addr_list, INET_ADDR_LIST *mask_list)
{
char *myname = "inet_addr_local";
struct ifconf ifc;
VSTRING *buf = vstring_alloc(1024);
int initial_count = addr_list->used;
struct in_addr addr;
+ struct ifreq *ifr_mask;
if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
msg_fatal("%s: socket: %m", myname);
for (ifr = ifc.ifc_req; ifr < the_end;) {
if (ifr->ifr_addr.sa_family == AF_INET) { /* IP interface */
addr = ((struct sockaddr_in *) & ifr->ifr_addr)->sin_addr;
- if (addr.s_addr != INADDR_ANY) /* has IP address */
+ if (addr.s_addr != INADDR_ANY) { /* has IP address */
inet_addr_list_append(addr_list, &addr);
+ if (mask_list) {
+ ifr_mask = (struct ifreq *) mymalloc(IFREQ_SIZE(ifr));
+ memcpy((char *) ifr_mask, (char *) ifr, IFREQ_SIZE(ifr));
+ if (ioctl(sock, SIOCGIFNETMASK, ifr_mask) < 0)
+ msg_fatal("%s: ioctl SIOCGIFNETMASK: %m", myname);
+ addr = ((struct sockaddr_in *) & ifr_mask->ifr_addr)->sin_addr;
+ inet_addr_list_append(mask_list, &addr);
+ myfree((char *) ifr_mask);
+ }
+ }
}
ifr = NEXT_INTERFACE(ifr);
}
int main(int unused_argc, char **argv)
{
INET_ADDR_LIST addr_list;
+ INET_ADDR_LIST mask_list;
int i;
msg_vstream_init(argv[0], VSTREAM_ERR);
inet_addr_list_init(&addr_list);
- inet_addr_local(&addr_list);
+ inet_addr_list_init(&mask_list);
+ inet_addr_local(&addr_list, &mask_list);
if (addr_list.used == 0)
msg_fatal("cannot find any active network interfaces");
if (addr_list.used == 1)
msg_warn("found only one active network interface");
- for (i = 0; i < addr_list.used; i++)
- vstream_printf("%s\n", inet_ntoa(addr_list.addrs[i]));
+ for (i = 0; i < addr_list.used; i++) {
+ vstream_printf("%s/", inet_ntoa(addr_list.addrs[i]));
+ vstream_printf("%s\n", inet_ntoa(mask_list.addrs[i]));
+ }
vstream_fflush(VSTREAM_OUT);
inet_addr_list_free(&addr_list);
+ inet_addr_list_free(&mask_list);
}
#endif
/*
* External interface.
*/
-extern int inet_addr_local(INET_ADDR_LIST *);
+extern int inet_addr_local(INET_ADDR_LIST *, INET_ADDR_LIST *);
/* LICENSE
/* .ad
extern int timed_read(int, void *, unsigned, int, void *);
extern int timed_write(int, void *, unsigned, int, void *);
extern void doze(unsigned);
+extern void rand_sleep(unsigned, unsigned);
extern int duplex_pipe(int *);
#define BLOCKING 0
--- /dev/null
+/*++
+/* NAME
+/* rand_sleep 3
+/* SUMMARY
+/* sleep for randomized interval
+/* SYNOPSIS
+/* #include <iostuff.h>
+/*
+/* void rand_sleep(delay, variation)
+/* unsigned delay;
+/* unsigned variation;
+/* DESCRIPTION
+/* rand_sleep() blocks the current process for an amount of time
+/* pseudo-randomly chosen from the interval (delay +- variation/2).
+/*
+/* Arguments:
+/* .IP delay
+/* Time to sleep in microseconds.
+/* .IP variation
+/* Variation in microseconds; must not be larger than delay.
+/* DIAGNOSTICS
+/* Panic: interface violation. All system call errors are fatal.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <time.h>
+
+#ifndef RAND_MAX
+#define RAND_MAX 0x7fffffff
+#endif
+
+/* Utility library. */
+
+#include <msg.h>
+#include <iostuff.h>
+
+/* rand_sleep - block for random time */
+
+void rand_sleep(unsigned delay, unsigned variation)
+{
+ char *myname = "rand_sleep";
+ static pid_t my_pid;
+ unsigned usec;
+
+ /*
+ * Sanity checks.
+ */
+ if (delay == 0)
+ msg_panic("%s: bad delay %d", myname, delay);
+ if (variation > delay)
+ msg_panic("%s: bad variation %d", myname, variation);
+
+ /*
+ * Use the semi-crappy random number generator.
+ */
+ if (my_pid == 0)
+ srandom((my_pid = getpid()) ^ time((time_t *) 0));
+ usec = (delay - variation / 2) + variation * (double) random() / RAND_MAX;
+ doze(usec);
+}
+
+#ifdef TEST
+
+#include <msg_vstream.h>
+
+int main(int argc, char **argv)
+{
+ int delay;
+ int variation;
+
+ msg_vstream_init(argv[0], VSTREAM_ERR);
+ if (argc != 3)
+ msg_fatal("usage: %s delay variation", argv[0]);
+ if ((delay = atoi(argv[1])) <= 0)
+ msg_fatal("bad delay: %s", argv[1]);
+ if ((variation = atoi(argv[2])) < 0)
+ msg_fatal("bad variation: %s", argv[2]);
+ rand_sleep(delay * 1000000, variation * 1000000);
+ exit(0);
+}
+
+#endif
/* safe_open_exist - open existing file */
static VSTREAM *safe_open_exist(const char *path, int flags,
- struct stat * fstat_st, VSTRING * why)
+ struct stat * fstat_st, VSTRING *why)
{
struct stat local_statbuf;
struct stat lstat_st;
* slowed down by arbitrary amounts, and there it would make sense to
* compare even more file attributes, such as the inode generation number
* on systems that have one.
+ *
+ * Grr. Solaris /dev/whatever is a symlink. We'll have to make an exception
+ * for symlinks owned by root. NEVER, NEVER, make exceptions for symlinks
+ * owned by a non-root user. This would open a security hole when
+ * delivering mail to a world-writable mailbox directory.
*/
- else if (lstat(path, &lstat_st) < 0
- || fstat_st->st_dev != lstat_st.st_dev
- || fstat_st->st_ino != lstat_st.st_ino
+ else if (lstat(path, &lstat_st) < 0) {
+ vstring_sprintf(why, "file status changed unexpectedly: %m");
+ } else if (S_ISLNK(lstat_st.st_mode)) {
+ if (lstat_st.st_uid == 0)
+ return (fp);
+ vstring_sprintf(why, "file is a symbolic link");
+ } else if (fstat_st->st_dev != lstat_st.st_dev
+ || fstat_st->st_ino != lstat_st.st_ino
#ifdef HAS_ST_GEN
- || fstat_st->st_gen != lstat_st.st_gen
+ || fstat_st->st_gen != lstat_st.st_gen
#endif
- || fstat_st->st_nlink != lstat_st.st_nlink
- || fstat_st->st_mode != lstat_st.st_mode) {
- vstring_sprintf(why, "%s", S_ISLNK(lstat_st.st_mode) ?
- "file is a symbolic link" : "file status changed unexpectedly");
+ || fstat_st->st_nlink != lstat_st.st_nlink
+ || fstat_st->st_mode != lstat_st.st_mode) {
+ vstring_sprintf(why, "file status changed unexpectedly");
}
/*
/* safe_open_create - create new file */
static VSTREAM *safe_open_create(const char *path, int flags, int mode,
- struct stat * st, uid_t user, uid_t group, VSTRING * why)
+ struct stat * st, uid_t user, uid_t group, VSTRING *why)
{
VSTREAM *fp;
/* safe_open - safely open or create file */
VSTREAM *safe_open(const char *path, int flags, int mode,
- struct stat * st, uid_t user, gid_t group, VSTRING * why)
+ struct stat * st, uid_t user, gid_t group, VSTRING *why)
{
VSTREAM *fp;
--- /dev/null
+/*++
+/* NAME
+/* sane_socketpair 3
+/* SUMMARY
+/* sanitize socketpair() error returns
+/* SYNOPSIS
+/* #include <sane_socketpair.h>
+/*
+/* int sane_socketpair(domain, type, protocol, result)
+/* int domain;
+/* int type;
+/* int protocol;
+/* int *result;
+/* DESCRIPTION
+/* sane_socketpair() implements the socketpair(2) socket call, and
+/* skips over silly error results such as EINTR.
+/* BUGS
+/* Bizarre systems may have other harmless error results. Such
+/* systems encourage programers to ignore error results, and
+/* penalizes programmers who code defensively.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include "sys_defs.h"
+#include <sys/socket.h>
+#include <unistd.h>
+#include <errno.h>
+
+/* Utility library. */
+
+#include "msg.h"
+#include "sane_socketpair.h"
+
+/* sane_socketpair - sanitize socketpair() error returns */
+
+int sane_socketpair(int domain, int type, int protocol, int *result)
+{
+ static int socketpair_ok_errors[] = {
+ EINTR,
+ 0,
+ };
+ int count;
+ int err;
+ int ret;
+
+ /*
+ * Solaris socketpair() can fail with EINTR.
+ */
+ while ((ret = socketpair(domain, type, protocol, result)) < 0) {
+ for (count = 0; /* void */ ; count++) {
+ if ((err = socketpair_ok_errors[count]) == 0)
+ return (ret);
+ if (errno == err) {
+ msg_warn("socketpair: %m (trying again)");
+ sleep(1);
+ break;
+ }
+ }
+ }
+ return (ret);
+}
--- /dev/null
+#ifndef _SANE_SOCKETPAIR_H_
+#define _SANE_SOCKETPAIR_H_
+
+/*++
+/* NAME
+/* sane_socketpair 3h
+/* SUMMARY
+/* sanitize socketpair() error returns
+/* SYNOPSIS
+/* #include <sane_socketpair.h>
+/* DESCRIPTION
+/* .nf
+
+ /* External interface. */
+
+extern int sane_socketpair(int, int, int, int *);
+
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+#endif
--- /dev/null
+/*++
+/* NAME
+/* sane_time 3
+/* SUMMARY
+/* time(2) with backward time jump protection.
+/* SYNOPSIS
+/* #include <sane_time.h>
+/*
+/* time_t sane_time(void)
+/*
+/* DESCRIPTION
+/* This module provides time(2) like call for applications
+/* which need monotonically increasing time function rather
+/* than the real exact time. It eliminates the need for various
+/* workarounds all over the application which would handle
+/* potential problems if time suddenly jumps backward.
+/* Instead we choose to deal with this problem inside this
+/* module and let the application focus on its own tasks.
+/*
+/* sane_time() returns the current timestamp as obtained from
+/* time(2) call, at least most of the time. In case this routine
+/* detects that time has jumped backward, it keeps returning
+/* whatever timestamp it returned before, until this timestamp
+/* and the time(2) timestamp become synchronized again.
+/* Additionally, the returned timestamp is slowly increased to
+/* prevent the faked clock from freezing for too long.
+/* SEE ALSO
+/* time(2) get current time
+/* DIAGNOSTICS
+/* Warning message is logged if backward time jump is detected.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Patrik Rak
+/* Modra 6
+/* 155 00, Prague, Czech Republic
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+
+/* Utility library. */
+
+#include <msg.h>
+
+/* Application-specific. */
+
+#include "sane_time.h"
+
+/*
+ * How many times shall we slow down the real clock when recovering from
+ * time jump.
+ */
+#define SLEW_FACTOR 2
+
+/* sane_time - get current time, protected against time warping */
+
+time_t sane_time(void)
+{
+ time_t now;
+ static time_t last_time,
+ last_real;
+ int delta;
+ static int fraction;
+ static int warned;
+
+ now = time((time_t *) 0);
+
+ if ((delta = now - last_time) < 0 && last_time != 0) {
+ if ((delta = now - last_real) < 0) {
+ msg_warn("%sbackward time jump detected -- slewing clock",
+ warned++ ? "another " : "");
+ } else {
+ delta += fraction;
+ last_time += delta / SLEW_FACTOR;
+ fraction = delta % SLEW_FACTOR;
+ }
+ } else {
+ if (warned) {
+ warned = 0;
+ msg_warn("backward time jump recovered -- back to normality");
+ fraction = 0;
+ }
+ last_time = now;
+ }
+ last_real = now;
+
+ return (last_time);
+}
+
+#ifdef TEST
+
+ /*
+ * Proof-of-concept test program. Repeatedly print current system time and
+ * time returned by sane_time(). Meanwhile, try stepping your system clock
+ * back and forth to see what happens.
+ */
+
+#include <stdlib.h>
+#include <msg_vstream.h>
+#include <iostuff.h> /* doze() */
+
+int main(int argc, char **argv)
+{
+ int delay = 1000000;
+ time_t now;
+
+ msg_vstream_init(argv[0], VSTREAM_ERR);
+
+ if (argc == 2 && (delay = atol(argv[1]) * 1000) > 0)
+ /* void */ ;
+ else if (argc != 1)
+ msg_fatal("usage: %s [delay in ms (default 1 second)]", argv[0]);
+
+ for (;;) {
+ now = time((time_t *) 0);
+ vstream_printf("real: %s", ctime(&now));
+ now = sane_time();
+ vstream_printf("fake: %s\n", ctime(&now));
+ vstream_fflush(VSTREAM_OUT);
+ doze(delay);
+ }
+}
+
+#endif
--- /dev/null
+#ifndef _SANE_TIME_H_
+#define _SANE_TIME_H_
+
+/*++
+/* NAME
+/* sane_time 3h
+/* SUMMARY
+/* time(2) with backward time jump protection
+/* SYNOPSIS
+/* #include <sane_time.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+ * System library.
+ */
+#include <time.h>
+
+ /*
+ * External interface.
+ */
+extern time_t sane_time(void);
+
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Patrik Rak
+/* Modra 6
+/* 155 00, Prague, Czech Republic
+/*--*/
+
+#endif
#define S_ISSOCK(mode) (((mode) & (_S_IFMT)) == (_S_IFSOCK))
#define S_ISFIFO(mode) (((mode) & (_S_IFMT)) == (_S_IFIFO))
#define S_ISREG(mode) (((mode) & (_S_IFMT)) == (_S_IFREG))
+#define S_ISLNK(mode) (((mode) & (_S_IFMT)) == (_S_IFLNK))
#endif
#ifdef MISSING_POSIX_S_MODES
/* SYNOPSIS
/* #include <valid_hostname.h>
/*
-/* int valid_hostname(name)
+/* int valid_hostname(name, gripe)
/* const char *name;
+/* int gripe;
/*
-/* int valid_hostaddr(addr)
+/* int valid_hostaddr(addr, gripe)
/* const char *addr;
+/* int gripe;
/* DESCRIPTION
/* valid_hostname() scrutinizes a hostname: the name should be no
/* longer than VALID_HOSTNAME_LEN characters, should contain only
/*
/* valid_hostaddr() requirs that the input is a valid string
/* representation of an internet network address.
+/*
+/* These routines operate silently unless the gripe parameter
+/* specifies a non-zero value. The macros DO_GRIPE and DONT_GRIPE
+/* provide suitable constants.
/* DIAGNOSTICS
/* Both functions return zero if they disagree with the input.
/* SEE ALSO
/* valid_hostname - screen out bad hostnames */
-int valid_hostname(const char *name)
+int valid_hostname(const char *name, int gripe)
{
char *myname = "valid_hostname";
const char *cp;
* Trivial cases first.
*/
if (*name == 0) {
- msg_warn("%s: empty hostname", myname);
+ if (gripe)
+ msg_warn("%s: empty hostname", myname);
return (0);
}
label_count++;
label_length++;
if (label_length > VALID_LABEL_LEN) {
- msg_warn("%s: hostname label too long: %.100s", myname, name);
+ if (gripe)
+ msg_warn("%s: hostname label too long: %.100s", myname, name);
return (0);
}
if (!ISDIGIT(ch))
non_numeric = 1;
} else if (ch == '.') {
if (label_length == 0 || cp[1] == 0) {
- msg_warn("%s: misplaced delimiter: %.100s", myname, name);
+ if (gripe)
+ msg_warn("%s: misplaced delimiter: %.100s", myname, name);
return (0);
}
label_length = 0;
} else if (ch == '-') {
label_length++;
if (label_length == 1 || cp[1] == 0 || cp[1] == '.') {
- msg_warn("%s: misplaced hyphen: %.100s", myname, name);
+ if (gripe)
+ msg_warn("%s: misplaced hyphen: %.100s", myname, name);
return (0);
}
} else {
- msg_warn("%s: invalid character %d(decimal): %.100s",
- myname, ch, name);
+ if (gripe)
+ msg_warn("%s: invalid character %d(decimal): %.100s",
+ myname, ch, name);
return (0);
}
}
if (non_numeric == 0) {
- msg_warn("%s: numeric hostname: %.100s", myname, name);
+ if (gripe)
+ msg_warn("%s: numeric hostname: %.100s", myname, name);
/* NOT: return (0); this confuses users of the DNS client */
}
if (cp - name > VALID_HOSTNAME_LEN) {
- msg_warn("%s: bad length %d for %.100s...",
- myname, (int) (cp - name), name);
+ if (gripe)
+ msg_warn("%s: bad length %d for %.100s...",
+ myname, (int) (cp - name), name);
return (0);
}
return (1);
/* valid_hostaddr - test dotted quad string for correctness */
-int valid_hostaddr(const char *addr)
+int valid_hostaddr(const char *addr, int gripe)
{
const char *cp;
char *myname = "valid_hostaddr";
* Trivial cases first.
*/
if (*addr == 0) {
- msg_warn("%s: empty address", myname);
+ if (gripe)
+ msg_warn("%s: empty address", myname);
return (0);
}
byte_val *= 10;
byte_val += ch - '0';
if (byte_val > 255) {
- msg_warn("%s: invalid octet value: %.100s", myname, addr);
+ if (gripe)
+ msg_warn("%s: invalid octet value: %.100s", myname, addr);
return (0);
}
} else if (ch == '.') {
if (in_byte == 0 || cp[1] == 0) {
- msg_warn("%s: misplaced dot: %.100s", myname, addr);
+ if (gripe)
+ msg_warn("%s: misplaced dot: %.100s", myname, addr);
return (0);
}
if ((byte_count == 1 && byte_val == 0)) {
- msg_warn("%s: bad initial octet value: %.100s", myname, addr);
+ if (gripe)
+ msg_warn("%s: bad initial octet value: %.100s", myname, addr);
return (0);
}
in_byte = 0;
} else {
- msg_warn("%s: invalid character %d(decimal): %.100s",
- myname, ch, addr);
+ if (gripe)
+ msg_warn("%s: invalid character %d(decimal): %.100s",
+ myname, ch, addr);
return (0);
}
}
if (byte_count != BYTES_NEEDED) {
- msg_warn("%s: invalid octet count: %.100s", myname, addr);
+ if (gripe)
+ msg_warn("%s: invalid octet count: %.100s", myname, addr);
return (0);
}
return (1);
while (vstring_fgets_nonl(buffer, VSTREAM_IN)) {
msg_info("testing: \"%s\"", vstring_str(buffer));
- valid_hostname(vstring_str(buffer));
- valid_hostaddr(vstring_str(buffer));
+ valid_hostname(vstring_str(buffer), DO_GRIPE);
+ valid_hostaddr(vstring_str(buffer), DO_GRIPE);
}
exit(0);
}
#define VALID_HOSTNAME_LEN 255 /* RFC 1035 */
#define VALID_LABEL_LEN 63 /* RFC 1035 */
-extern int valid_hostname(const char *);
-extern int valid_hostaddr(const char *);
+#define DONT_GRIPE 0
+#define DO_GRIPE 1
+
+extern int valid_hostname(const char *, int);
+extern int valid_hostaddr(const char *, int);
/* LICENSE
/* .ad
+++ /dev/null
-../../.indent.pro
\ No newline at end of file
+++ /dev/null
-SHELL = /bin/sh
-SRCS = virtual.c mailbox.c recipient.c deliver_attr.c maildir.c unknown.c
-OBJS = virtual.o mailbox.o recipient.o deliver_attr.o maildir.o unknown.o
-HDRS = virtual.h
-TESTSRC =
-WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \
- -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \
- -Wunused
-DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) -I..
-CFLAGS = $(DEBUG) $(OPT) $(DEFS)
-PROG = virtual
-TESTPROG=
-INC_DIR = ../../include
-LIBS = ../../lib/libmaster.a ../../lib/libglobal.a ../../lib/libutil.a $(AUXLIBS)
-
-.c.o:; $(CC) $(CFLAGS) -c $*.c
-
-$(PROG): $(OBJS) $(LIBS)
- $(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS)
-
-Makefile: Makefile.in
- (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs; cat $?) >$@
-
-test: $(TESTPROG)
-
-update: ../../libexec/$(PROG)
-
-../../libexec/$(PROG): $(PROG)
- cp $(PROG) ../../libexec
-
-printfck: $(OBJS) $(PROG)
- rm -rf printfck
- mkdir printfck
- cp *.h printfck
- sed '1,/^# do not edit/!d' Makefile >printfck/Makefile
- set -e; for i in *.c; do printfck -f .printfck $$i >printfck/$$i; done
- cd printfck; make "INC_DIR=../../include" `cd ..; ls *.o`
-
-lint:
- lint $(DEFS) $(SRCS) $(LINTFIX)
-
-clean:
- rm -f *.o *core $(PROG) $(TESTPROG) junk
- rm -rf printfck
-
-tidy: clean
-
-depend: $(MAKES)
- (sed '1,/^# do not edit/!d' Makefile.in; \
- set -e; for i in [a-z][a-z0-9]*.c; do \
- $(CC) -E $(DEFS) $(INCL) $$i | 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
-deliver_attr.o: deliver_attr.c
-deliver_attr.o: ../../include/sys_defs.h
-deliver_attr.o: ../../include/msg.h
-deliver_attr.o: ../../include/vstream.h
-deliver_attr.o: ../../include/vbuf.h
-deliver_attr.o: virtual.h
-deliver_attr.o: ../../include/htable.h
-deliver_attr.o: ../../include/vstring.h
-deliver_attr.o: ../../include/been_here.h
-deliver_attr.o: ../../include/tok822.h
-deliver_attr.o: ../../include/resolve_clnt.h
-deliver_attr.o: ../../include/deliver_request.h
-deliver_attr.o: ../../include/recipient_list.h
-deliver_attr.o: ../../include/maps.h
-deliver_attr.o: ../../include/dict.h
-deliver_attr.o: ../../include/argv.h
-mailbox.o: mailbox.c
-mailbox.o: ../../include/sys_defs.h
-mailbox.o: ../../include/msg.h
-mailbox.o: ../../include/htable.h
-mailbox.o: ../../include/vstring.h
-mailbox.o: ../../include/vbuf.h
-mailbox.o: ../../include/vstream.h
-mailbox.o: ../../include/mymalloc.h
-mailbox.o: ../../include/stringops.h
-mailbox.o: ../../include/set_eugid.h
-mailbox.o: ../../include/mail_copy.h
-mailbox.o: ../../include/safe_open.h
-mailbox.o: ../../include/deliver_flock.h
-mailbox.o: ../../include/dot_lockfile.h
-mailbox.o: ../../include/defer.h
-mailbox.o: ../../include/bounce.h
-mailbox.o: ../../include/sent.h
-mailbox.o: ../../include/mypwd.h
-mailbox.o: ../../include/mail_params.h
-mailbox.o: ../../include/deliver_pass.h
-mailbox.o: ../../include/deliver_request.h
-mailbox.o: ../../include/recipient_list.h
-mailbox.o: ../../include/mail_proto.h
-mailbox.o: ../../include/iostuff.h
-mailbox.o: virtual.h
-mailbox.o: ../../include/been_here.h
-mailbox.o: ../../include/tok822.h
-mailbox.o: ../../include/resolve_clnt.h
-mailbox.o: ../../include/maps.h
-mailbox.o: ../../include/dict.h
-mailbox.o: ../../include/argv.h
-maildir.o: maildir.c
-maildir.o: ../../include/sys_defs.h
-maildir.o: ../../include/msg.h
-maildir.o: ../../include/mymalloc.h
-maildir.o: ../../include/stringops.h
-maildir.o: ../../include/vstring.h
-maildir.o: ../../include/vbuf.h
-maildir.o: ../../include/vstream.h
-maildir.o: ../../include/make_dirs.h
-maildir.o: ../../include/set_eugid.h
-maildir.o: ../../include/get_hostname.h
-maildir.o: ../../include/mail_copy.h
-maildir.o: ../../include/bounce.h
-maildir.o: ../../include/sent.h
-maildir.o: ../../include/mail_params.h
-maildir.o: virtual.h
-maildir.o: ../../include/htable.h
-maildir.o: ../../include/been_here.h
-maildir.o: ../../include/tok822.h
-maildir.o: ../../include/resolve_clnt.h
-maildir.o: ../../include/deliver_request.h
-maildir.o: ../../include/recipient_list.h
-maildir.o: ../../include/maps.h
-maildir.o: ../../include/dict.h
-maildir.o: ../../include/argv.h
-recipient.o: recipient.c
-recipient.o: ../../include/sys_defs.h
-recipient.o: ../../include/msg.h
-recipient.o: ../../include/mymalloc.h
-recipient.o: ../../include/htable.h
-recipient.o: ../../include/split_at.h
-recipient.o: ../../include/stringops.h
-recipient.o: ../../include/vstring.h
-recipient.o: ../../include/vbuf.h
-recipient.o: ../../include/dict.h
-recipient.o: ../../include/vstream.h
-recipient.o: ../../include/argv.h
-recipient.o: ../../include/bounce.h
-recipient.o: ../../include/mail_params.h
-recipient.o: ../../include/split_addr.h
-recipient.o: ../../include/ext_prop.h
-recipient.o: virtual.h
-recipient.o: ../../include/been_here.h
-recipient.o: ../../include/tok822.h
-recipient.o: ../../include/resolve_clnt.h
-recipient.o: ../../include/deliver_request.h
-recipient.o: ../../include/recipient_list.h
-recipient.o: ../../include/maps.h
-unknown.o: unknown.c
-unknown.o: ../../include/sys_defs.h
-unknown.o: ../../include/msg.h
-unknown.o: ../../include/stringops.h
-unknown.o: ../../include/vstring.h
-unknown.o: ../../include/vbuf.h
-unknown.o: ../../include/mymalloc.h
-unknown.o: ../../include/mail_params.h
-unknown.o: ../../include/mail_proto.h
-unknown.o: ../../include/vstream.h
-unknown.o: ../../include/iostuff.h
-unknown.o: ../../include/bounce.h
-unknown.o: virtual.h
-unknown.o: ../../include/htable.h
-unknown.o: ../../include/been_here.h
-unknown.o: ../../include/tok822.h
-unknown.o: ../../include/resolve_clnt.h
-unknown.o: ../../include/deliver_request.h
-unknown.o: ../../include/recipient_list.h
-unknown.o: ../../include/maps.h
-unknown.o: ../../include/dict.h
-unknown.o: ../../include/argv.h
-virtual.o: virtual.c
-virtual.o: ../../include/sys_defs.h
-virtual.o: ../../include/msg.h
-virtual.o: ../../include/mymalloc.h
-virtual.o: ../../include/htable.h
-virtual.o: ../../include/vstring.h
-virtual.o: ../../include/vbuf.h
-virtual.o: ../../include/vstream.h
-virtual.o: ../../include/iostuff.h
-virtual.o: ../../include/name_mask.h
-virtual.o: ../../include/set_eugid.h
-virtual.o: ../../include/dict.h
-virtual.o: ../../include/argv.h
-virtual.o: ../../include/mail_queue.h
-virtual.o: ../../include/recipient_list.h
-virtual.o: ../../include/deliver_request.h
-virtual.o: ../../include/deliver_completed.h
-virtual.o: ../../include/mail_params.h
-virtual.o: ../../include/mail_addr.h
-virtual.o: ../../include/mail_conf.h
-virtual.o: ../../include/ext_prop.h
-virtual.o: ../../include/mail_server.h
-virtual.o: virtual.h
-virtual.o: ../../include/been_here.h
-virtual.o: ../../include/tok822.h
-virtual.o: ../../include/resolve_clnt.h
-virtual.o: ../../include/maps.h
-deliver_attr.o: deliver_attr.c
-deliver_attr.o: ../../include/sys_defs.h
-deliver_attr.o: ../../include/msg.h
-deliver_attr.o: ../../include/vstream.h
-deliver_attr.o: ../../include/vbuf.h
-deliver_attr.o: virtual.h
-deliver_attr.o: ../../include/vstring.h
-deliver_attr.o: ../../include/deliver_request.h
-deliver_attr.o: ../../include/recipient_list.h
-deliver_attr.o: ../../include/maps.h
-deliver_attr.o: ../../include/dict.h
-deliver_attr.o: ../../include/argv.h
-deliver_attr.o: ../../include/mbox_conf.h
-mailbox.o: mailbox.c
-mailbox.o: ../../include/sys_defs.h
-mailbox.o: ../../include/msg.h
-mailbox.o: ../../include/vstring.h
-mailbox.o: ../../include/vbuf.h
-mailbox.o: ../../include/vstream.h
-mailbox.o: ../../include/mymalloc.h
-mailbox.o: ../../include/stringops.h
-mailbox.o: ../../include/set_eugid.h
-mailbox.o: ../../include/mail_copy.h
-mailbox.o: ../../include/mbox_open.h
-mailbox.o: ../../include/safe_open.h
-mailbox.o: ../../include/defer.h
-mailbox.o: ../../include/bounce.h
-mailbox.o: ../../include/sent.h
-mailbox.o: ../../include/mypwd.h
-mailbox.o: ../../include/mail_params.h
-mailbox.o: virtual.h
-mailbox.o: ../../include/deliver_request.h
-mailbox.o: ../../include/recipient_list.h
-mailbox.o: ../../include/maps.h
-mailbox.o: ../../include/dict.h
-mailbox.o: ../../include/argv.h
-mailbox.o: ../../include/mbox_conf.h
-maildir.o: maildir.c
-maildir.o: ../../include/sys_defs.h
-maildir.o: ../../include/msg.h
-maildir.o: ../../include/mymalloc.h
-maildir.o: ../../include/stringops.h
-maildir.o: ../../include/vstring.h
-maildir.o: ../../include/vbuf.h
-maildir.o: ../../include/vstream.h
-maildir.o: ../../include/make_dirs.h
-maildir.o: ../../include/set_eugid.h
-maildir.o: ../../include/get_hostname.h
-maildir.o: ../../include/sane_fsops.h
-maildir.o: ../../include/mail_copy.h
-maildir.o: ../../include/bounce.h
-maildir.o: ../../include/sent.h
-maildir.o: ../../include/mail_params.h
-maildir.o: virtual.h
-maildir.o: ../../include/deliver_request.h
-maildir.o: ../../include/recipient_list.h
-maildir.o: ../../include/maps.h
-maildir.o: ../../include/dict.h
-maildir.o: ../../include/argv.h
-maildir.o: ../../include/mbox_conf.h
-recipient.o: recipient.c
-recipient.o: ../../include/sys_defs.h
-recipient.o: ../../include/msg.h
-recipient.o: ../../include/mymalloc.h
-recipient.o: ../../include/htable.h
-recipient.o: ../../include/split_at.h
-recipient.o: ../../include/stringops.h
-recipient.o: ../../include/vstring.h
-recipient.o: ../../include/vbuf.h
-recipient.o: ../../include/dict.h
-recipient.o: ../../include/vstream.h
-recipient.o: ../../include/argv.h
-recipient.o: ../../include/bounce.h
-recipient.o: ../../include/mail_params.h
-recipient.o: ../../include/split_addr.h
-recipient.o: ../../include/ext_prop.h
-recipient.o: virtual.h
-recipient.o: ../../include/deliver_request.h
-recipient.o: ../../include/recipient_list.h
-recipient.o: ../../include/maps.h
-recipient.o: ../../include/mbox_conf.h
-unknown.o: unknown.c
-unknown.o: ../../include/sys_defs.h
-unknown.o: ../../include/msg.h
-unknown.o: ../../include/stringops.h
-unknown.o: ../../include/vstring.h
-unknown.o: ../../include/vbuf.h
-unknown.o: ../../include/mymalloc.h
-unknown.o: ../../include/mail_params.h
-unknown.o: ../../include/mail_proto.h
-unknown.o: ../../include/vstream.h
-unknown.o: ../../include/iostuff.h
-unknown.o: ../../include/bounce.h
-unknown.o: virtual.h
-unknown.o: ../../include/deliver_request.h
-unknown.o: ../../include/recipient_list.h
-unknown.o: ../../include/maps.h
-unknown.o: ../../include/dict.h
-unknown.o: ../../include/argv.h
-unknown.o: ../../include/mbox_conf.h
-virtual.o: virtual.c
-virtual.o: ../../include/sys_defs.h
-virtual.o: ../../include/msg.h
-virtual.o: ../../include/mymalloc.h
-virtual.o: ../../include/htable.h
-virtual.o: ../../include/vstring.h
-virtual.o: ../../include/vbuf.h
-virtual.o: ../../include/vstream.h
-virtual.o: ../../include/iostuff.h
-virtual.o: ../../include/name_mask.h
-virtual.o: ../../include/set_eugid.h
-virtual.o: ../../include/dict.h
-virtual.o: ../../include/argv.h
-virtual.o: ../../include/mail_queue.h
-virtual.o: ../../include/recipient_list.h
-virtual.o: ../../include/deliver_request.h
-virtual.o: ../../include/deliver_completed.h
-virtual.o: ../../include/mail_params.h
-virtual.o: ../../include/mail_addr.h
-virtual.o: ../../include/mail_conf.h
-virtual.o: ../../include/mail_server.h
-virtual.o: virtual.h
-virtual.o: ../../include/maps.h
-virtual.o: ../../include/mbox_conf.h
-deliver_attr.o: deliver_attr.c
-deliver_attr.o: ../../include/sys_defs.h
-deliver_attr.o: ../../include/msg.h
-deliver_attr.o: ../../include/vstream.h
-deliver_attr.o: ../../include/vbuf.h
-deliver_attr.o: virtual.h
-deliver_attr.o: ../../include/vstring.h
-deliver_attr.o: ../../include/deliver_request.h
-deliver_attr.o: ../../include/recipient_list.h
-deliver_attr.o: ../../include/maps.h
-deliver_attr.o: ../../include/dict.h
-deliver_attr.o: ../../include/argv.h
-deliver_attr.o: ../../include/mbox_conf.h
-mailbox.o: mailbox.c
-mailbox.o: ../../include/sys_defs.h
-mailbox.o: ../../include/msg.h
-mailbox.o: ../../include/vstring.h
-mailbox.o: ../../include/vbuf.h
-mailbox.o: ../../include/vstream.h
-mailbox.o: ../../include/mymalloc.h
-mailbox.o: ../../include/stringops.h
-mailbox.o: ../../include/set_eugid.h
-mailbox.o: ../../include/mail_copy.h
-mailbox.o: ../../include/mbox_open.h
-mailbox.o: ../../include/safe_open.h
-mailbox.o: ../../include/defer.h
-mailbox.o: ../../include/bounce.h
-mailbox.o: ../../include/sent.h
-mailbox.o: ../../include/mypwd.h
-mailbox.o: ../../include/mail_params.h
-mailbox.o: virtual.h
-mailbox.o: ../../include/deliver_request.h
-mailbox.o: ../../include/recipient_list.h
-mailbox.o: ../../include/maps.h
-mailbox.o: ../../include/dict.h
-mailbox.o: ../../include/argv.h
-mailbox.o: ../../include/mbox_conf.h
-maildir.o: maildir.c
-maildir.o: ../../include/sys_defs.h
-maildir.o: ../../include/msg.h
-maildir.o: ../../include/mymalloc.h
-maildir.o: ../../include/stringops.h
-maildir.o: ../../include/vstring.h
-maildir.o: ../../include/vbuf.h
-maildir.o: ../../include/vstream.h
-maildir.o: ../../include/make_dirs.h
-maildir.o: ../../include/set_eugid.h
-maildir.o: ../../include/get_hostname.h
-maildir.o: ../../include/sane_fsops.h
-maildir.o: ../../include/mail_copy.h
-maildir.o: ../../include/bounce.h
-maildir.o: ../../include/sent.h
-maildir.o: ../../include/mail_params.h
-maildir.o: virtual.h
-maildir.o: ../../include/deliver_request.h
-maildir.o: ../../include/recipient_list.h
-maildir.o: ../../include/maps.h
-maildir.o: ../../include/dict.h
-maildir.o: ../../include/argv.h
-maildir.o: ../../include/mbox_conf.h
-recipient.o: recipient.c
-recipient.o: ../../include/sys_defs.h
-recipient.o: ../../include/msg.h
-recipient.o: ../../include/mymalloc.h
-recipient.o: ../../include/stringops.h
-recipient.o: ../../include/vstring.h
-recipient.o: ../../include/vbuf.h
-recipient.o: ../../include/bounce.h
-recipient.o: virtual.h
-recipient.o: ../../include/vstream.h
-recipient.o: ../../include/deliver_request.h
-recipient.o: ../../include/recipient_list.h
-recipient.o: ../../include/maps.h
-recipient.o: ../../include/dict.h
-recipient.o: ../../include/argv.h
-recipient.o: ../../include/mbox_conf.h
-unknown.o: unknown.c
-unknown.o: ../../include/sys_defs.h
-unknown.o: ../../include/msg.h
-unknown.o: ../../include/stringops.h
-unknown.o: ../../include/vstring.h
-unknown.o: ../../include/vbuf.h
-unknown.o: ../../include/mymalloc.h
-unknown.o: ../../include/mail_params.h
-unknown.o: ../../include/mail_proto.h
-unknown.o: ../../include/vstream.h
-unknown.o: ../../include/iostuff.h
-unknown.o: ../../include/bounce.h
-unknown.o: virtual.h
-unknown.o: ../../include/deliver_request.h
-unknown.o: ../../include/recipient_list.h
-unknown.o: ../../include/maps.h
-unknown.o: ../../include/dict.h
-unknown.o: ../../include/argv.h
-unknown.o: ../../include/mbox_conf.h
-virtual.o: virtual.c
-virtual.o: ../../include/sys_defs.h
-virtual.o: ../../include/msg.h
-virtual.o: ../../include/mymalloc.h
-virtual.o: ../../include/htable.h
-virtual.o: ../../include/vstring.h
-virtual.o: ../../include/vbuf.h
-virtual.o: ../../include/vstream.h
-virtual.o: ../../include/iostuff.h
-virtual.o: ../../include/name_mask.h
-virtual.o: ../../include/set_eugid.h
-virtual.o: ../../include/dict.h
-virtual.o: ../../include/argv.h
-virtual.o: ../../include/mail_queue.h
-virtual.o: ../../include/recipient_list.h
-virtual.o: ../../include/deliver_request.h
-virtual.o: ../../include/deliver_completed.h
-virtual.o: ../../include/mail_params.h
-virtual.o: ../../include/mail_addr.h
-virtual.o: ../../include/mail_conf.h
-virtual.o: ../../include/mail_server.h
-virtual.o: virtual.h
-virtual.o: ../../include/maps.h
-virtual.o: ../../include/mbox_conf.h
+++ /dev/null
-/*++
-/* NAME
-/* deliver_attr 3
-/* SUMMARY
-/* initialize message delivery attributes
-/* SYNOPSIS
-/* #include "virtual.h"
-/*
-/* void deliver_attr_init(attrp)
-/* DELIVER_ATTR *attrp;
-/*
-/* void deliver_attr_dump(attrp)
-/* DELIVER_ATTR *attrp;
-/* DESCRIPTION
-/* deliver_attr_init() initializes a structure with message delivery
-/* attributes to a known initial state (all zeros).
-/*
-/* deliver_attr_dump() logs the contents of the given attribute list.
-/* LICENSE
-/* .ad
-/* .fi
-/* The Secure Mailer license must be distributed with this software.
-/* AUTHOR(S)
-/* Wietse Venema
-/* IBM T.J. Watson Research
-/* P.O. Box 704
-/* Yorktown Heights, NY 10598, USA
-/*--*/
-
-/* System library. */
-
-#include <sys_defs.h>
-
-/* Utility library. */
-
-#include <msg.h>
-#include <vstream.h>
-
-/* Application-specific. */
-
-#include "virtual.h"
-
-/* deliver_attr_init - set message delivery attributes to all-zero state */
-
-void deliver_attr_init(DELIVER_ATTR *attrp)
-{
- attrp->level = 0;
- attrp->fp = 0;
- attrp->queue_name = 0;
- attrp->queue_id = 0;
- attrp->offset = 0;
- attrp->sender = 0;
- attrp->recipient = 0;
- attrp->user = 0;
- attrp->delivered = 0;
- attrp->relay = 0;
-}
-
-/* deliver_attr_dump - log message delivery attributes */
-
-void deliver_attr_dump(DELIVER_ATTR *attrp)
-{
- msg_info("level: %d", attrp->level);
- msg_info("path: %s", VSTREAM_PATH(attrp->fp));
- msg_info("fp: 0x%lx", (long) attrp->fp);
- msg_info("queue_name: %s", attrp->queue_name ? attrp->queue_name : "null");
- msg_info("queue_id: %s", attrp->queue_id ? attrp->queue_id : "null");
- msg_info("offset: %ld", attrp->offset);
- msg_info("sender: %s", attrp->sender ? attrp->sender : "null");
- msg_info("recipient: %s", attrp->recipient ? attrp->recipient : "null");
- msg_info("user: %s", attrp->user ? attrp->user : "null");
- msg_info("delivered: %s", attrp->delivered ? attrp->delivered : "null");
- msg_info("relay: %s", attrp->relay ? attrp->relay : "null");
-}
+++ /dev/null
-/*++
-/* NAME
-/* mailbox 3
-/* SUMMARY
-/* mailbox delivery
-/* SYNOPSIS
-/* #include "virtual.h"
-/*
-/* int deliver_mailbox(state, usr_attr, statusp)
-/* LOCAL_STATE state;
-/* USER_ATTR usr_attr;
-/* int *statusp;
-/* DESCRIPTION
-/* deliver_mailbox() delivers to UNIX-style mailbox or to maildir.
-/*
-/* A zero result means that the named user was not found.
-/*
-/* Arguments:
-/* .IP state
-/* The attributes that specify the message, recipient and more.
-/* .IP usr_attr
-/* Attributes describing user rights and mailbox location.
-/* .IP statusp
-/* Delivery status: see below.
-/* DIAGNOSTICS
-/* The message delivery status is non-zero when delivery should be tried
-/* again.
-/* LICENSE
-/* .ad
-/* .fi
-/* The Secure Mailer license must be distributed with this software.
-/* AUTHOR(S)
-/* Wietse Venema
-/* IBM T.J. Watson Research
-/* P.O. Box 704
-/* Yorktown Heights, NY 10598, USA
-/*--*/
-
-/* System library. */
-
-#include <sys_defs.h>
-#include <sys/stat.h>
-#include <stdlib.h>
-#include <errno.h>
-
-/* Utility library. */
-
-#include <msg.h>
-#include <vstring.h>
-#include <vstream.h>
-#include <mymalloc.h>
-#include <stringops.h>
-#include <set_eugid.h>
-
-/* Global library. */
-
-#include <mail_copy.h>
-#include <mbox_open.h>
-#include <defer.h>
-#include <sent.h>
-#include <mail_params.h>
-
-#ifndef EDQUOT
-#define EDQUOT EFBIG
-#endif
-
-/* Application-specific. */
-
-#include "virtual.h"
-
-#define YES 1
-#define NO 0
-
-/* deliver_mailbox_file - deliver to recipient mailbox */
-
-static int deliver_mailbox_file(LOCAL_STATE state, USER_ATTR usr_attr)
-{
- char *myname = "deliver_mailbox_file";
- VSTRING *why;
- MBOX *mp;
- int status;
- int copy_flags;
- long end;
- struct stat st;
-
- /*
- * Make verbose logging easier to understand.
- */
- state.level++;
- if (msg_verbose)
- MSG_LOG_STATE(myname, state);
-
- /*
- * Initialize. Assume the operation will fail. Set the delivered
- * attribute to reflect the final recipient.
- */
- if (vstream_fseek(state.msg_attr.fp, state.msg_attr.offset, SEEK_SET) < 0)
- msg_fatal("seek message file %s: %m", VSTREAM_PATH(state.msg_attr.fp));
- state.msg_attr.delivered = state.msg_attr.recipient;
- status = -1;
- why = vstring_alloc(100);
-
- /*
- * Lock the mailbox and open/create the mailbox file.
- *
- * Write the file as the recipient, so that file quota work.
- */
- copy_flags = MAIL_COPY_MBOX;
-
- set_eugid(usr_attr.uid, usr_attr.gid);
- mp = mbox_open(usr_attr.mailbox, O_APPEND | O_WRONLY | O_CREAT,
- S_IRUSR | S_IWUSR, &st, -1, -1,
- virtual_mbox_lock_mask, why);
- if (mp != 0) {
- if (S_ISREG(st.st_mode) == 0) {
- vstream_fclose(mp->fp);
- vstring_sprintf(why, "destination is not a regular file");
- errno = 0;
- } else {
- end = vstream_fseek(mp->fp, (off_t) 0, SEEK_END);
- status = mail_copy(COPY_ATTR(state.msg_attr), mp->fp,
- copy_flags, "\n", why);
- }
- mbox_release(mp);
- }
- set_eugid(var_owner_uid, var_owner_gid);
-
- /*
- * As the mail system, bounce, defer delivery, or report success.
- */
- if (status != 0)
- status = (errno == EDQUOT ? bounce_append : defer_append)
- (BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
- "cannot access mailbox for %s. %s",
- usr_attr.mailbox, state.msg_attr.recipient, vstring_str(why));
- else
- sent(SENT_ATTR(state.msg_attr), "mailbox");
-
- vstring_free(why);
- return (status);
-}
-
-/* deliver_mailbox - deliver to recipient mailbox */
-
-int deliver_mailbox(LOCAL_STATE state, USER_ATTR usr_attr, int *statusp)
-{
- char *myname = "deliver_mailbox";
- const char *result;
- long n;
-
- /*
- * Make verbose logging easier to understand.
- */
- state.level++;
- if (msg_verbose)
- MSG_LOG_STATE(myname, state);
-
- /*
- * Sanity check.
- */
- if (*var_virt_mailbox_base != '/')
- msg_fatal("do not specify relative pathname: %s = %s",
- VAR_VIRT_MAILBOX_BASE, var_virt_mailbox_base);
-
- /*
- * Look up the mailbox location and rights of the recipient user.
- */
- result = maps_find(virtual_mailbox_maps, state.msg_attr.user, 0);
- if (result == 0) {
- if (dict_errno == 0)
- return (NO);
-
- *statusp = defer_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
- "%s: lookup %s: %m",
- virtual_mailbox_maps->title, state.msg_attr.user);
- return (YES);
- }
- usr_attr.mailbox = concatenate(var_virt_mailbox_base, "/", result, (char *) 0);
-
- if ((result = maps_find(virtual_uid_maps, state.msg_attr.user, 0)) == 0) {
- myfree(usr_attr.mailbox);
- *statusp = defer_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
- "recipient %s: uid not found in %s",
- state.msg_attr.user, virtual_uid_maps->title);
- return (YES);
- }
- if ((n = atol(result)) < var_virt_minimum_uid) {
- myfree(usr_attr.mailbox);
- *statusp = defer_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
- "recipient %s: bad uid %s in %s",
- state.msg_attr.user, result, virtual_uid_maps->title);
- return (YES);
- }
- usr_attr.uid = (uid_t) n;
-
- if ((result = maps_find(virtual_gid_maps, state.msg_attr.user, 0)) == 0) {
- myfree(usr_attr.mailbox);
- *statusp = defer_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
- "recipient %s: gid not found in %s",
- state.msg_attr.user, virtual_gid_maps->title);
- return (YES);
- }
- if ((n = atol(result)) <= 0) {
- myfree(usr_attr.mailbox);
- *statusp = defer_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
- "recipient %s: bad gid %s in %s",
- state.msg_attr.user, result, virtual_gid_maps->title);
- return (YES);
- }
- usr_attr.gid = (gid_t) n;
-
- if (msg_verbose)
- msg_info("%s[%d]: set user_attr: %s, uid = %d, gid = %d",
- myname, state.level,
- usr_attr.mailbox, usr_attr.uid, usr_attr.gid);
-
- /*
- * Deliver to mailbox or to external command.
- */
-#define LAST_CHAR(s) (s[strlen(s) - 1])
-
- if (LAST_CHAR(usr_attr.mailbox) == '/')
- *statusp = deliver_maildir(state, usr_attr);
- else
- *statusp = deliver_mailbox_file(state, usr_attr);
-
- /*
- * Cleanup.
- */
- myfree(usr_attr.mailbox);
- return (YES);
-}
+++ /dev/null
-/*++
-/* NAME
-/* maildir 3
-/* SUMMARY
-/* delivery to maildir
-/* SYNOPSIS
-/* #include "virtual.h"
-/*
-/* int deliver_maildir(state, usr_attr)
-/* LOCAL_STATE state;
-/* USER_ATTR usr_attr;
-/* DESCRIPTION
-/* deliver_maildir() delivers a message to a qmail-style maildir.
-/*
-/* Arguments:
-/* .IP state
-/* The attributes that specify the message, recipient and more.
-/* .IP usr_attr
-/* Attributes describing user rights and environment information.
-/* DIAGNOSTICS
-/* deliver_maildir() always succeeds or it bounces the message.
-/* SEE ALSO
-/* bounce(3)
-/* LICENSE
-/* .ad
-/* .fi
-/* The Secure Mailer license must be distributed with this software.
-/* AUTHOR(S)
-/* Wietse Venema
-/* IBM T.J. Watson Research
-/* P.O. Box 704
-/* Yorktown Heights, NY 10598, USA
-/*--*/
-
-/* System library. */
-
-#include "sys_defs.h"
-#include <errno.h>
-
-/* Utility library. */
-
-#include <msg.h>
-#include <mymalloc.h>
-#include <stringops.h>
-#include <vstream.h>
-#include <vstring.h>
-#include <make_dirs.h>
-#include <set_eugid.h>
-#include <get_hostname.h>
-#include <sane_fsops.h>
-
-/* Global library. */
-
-#include <mail_copy.h>
-#include <bounce.h>
-#include <sent.h>
-#include <mail_params.h>
-
-/* Application-specific. */
-
-#include "virtual.h"
-
-/* deliver_maildir - delivery to maildir-style mailbox */
-
-int deliver_maildir(LOCAL_STATE state, USER_ATTR usr_attr)
-{
- char *myname = "deliver_maildir";
- char *newdir;
- char *tmpdir;
- char *curdir;
- char *tmpfile;
- char *newfile;
- VSTRING *why;
- VSTRING *buf;
- VSTREAM *dst;
- int status;
- int copy_flags;
- static int count;
-
- /*
- * Make verbose logging easier to understand.
- */
- state.level++;
- if (msg_verbose)
- MSG_LOG_STATE(myname, state);
-
- /*
- * Initialize. Assume the operation will fail. Set the delivered
- * attribute to reflect the final recipient.
- */
- if (vstream_fseek(state.msg_attr.fp, state.msg_attr.offset, SEEK_SET) < 0)
- msg_fatal("seek message file %s: %m", VSTREAM_PATH(state.msg_attr.fp));
- state.msg_attr.delivered = state.msg_attr.recipient;
- status = -1;
- buf = vstring_alloc(100);
- why = vstring_alloc(100);
-
- copy_flags = MAIL_COPY_TOFILE | MAIL_COPY_RETURN_PATH | MAIL_COPY_DELIVERED;
-
- newdir = concatenate(usr_attr.mailbox, "new/", (char *) 0);
- tmpdir = concatenate(usr_attr.mailbox, "tmp/", (char *) 0);
- curdir = concatenate(usr_attr.mailbox, "cur/", (char *) 0);
-
- /*
- * Create and write the file as the recipient, so that file quota work.
- * Create any missing directories on the fly. The file name is chosen
- * according to ftp://koobera.math.uic.edu/www/proto/maildir.html:
- *
- * "A unique name has three pieces, separated by dots. On the left is the
- * result of time(). On the right is the result of gethostname(). In the
- * middle is something that doesn't repeat within one second on a single
- * host. I fork a new process for each delivery, so I just use the
- * process ID. If you're delivering several messages from one process,
- * use starttime.pid_count.host, where starttime is the time that your
- * process started, and count is the number of messages you've
- * delivered."
- */
-#define STR vstring_str
-
- set_eugid(usr_attr.uid, usr_attr.gid);
- vstring_sprintf(buf, "%ld.%d_%d.%s", (long) var_starttime,
- var_pid, count++, get_hostname());
- tmpfile = concatenate(tmpdir, STR(buf), (char *) 0);
- newfile = concatenate(newdir, STR(buf), (char *) 0);
- if ((dst = vstream_fopen(tmpfile, O_WRONLY | O_CREAT | O_EXCL, 0600)) == 0
- && (errno != ENOENT
- || make_dirs(tmpdir, 0700) < 0
- || (dst = vstream_fopen(tmpfile, O_WRONLY | O_CREAT | O_EXCL, 0600)) == 0)) {
- vstring_sprintf(why, "create %s: %m", tmpfile);
- } else {
- if (mail_copy(COPY_ATTR(state.msg_attr), dst, copy_flags, "\n", why) == 0) {
- if (sane_link(tmpfile, newfile) < 0
- && (errno != ENOENT
- || (make_dirs(curdir, 0700), make_dirs(newdir, 0700)) < 0
- || sane_link(tmpfile, newfile) < 0)) {
- vstring_sprintf(why, "link to %s: %m", newfile);
- } else {
- status = 0;
- }
- }
- if (unlink(tmpfile) < 0)
- msg_warn("remove %s: %m", tmpfile);
- }
- set_eugid(var_owner_uid, var_owner_gid);
-
- if (status)
- bounce_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
- "maildir delivery failed: %s", vstring_str(why));
- else
- sent(SENT_ATTR(state.msg_attr), "maildir");
- vstring_free(buf);
- vstring_free(why);
- myfree(newdir);
- myfree(tmpdir);
- myfree(curdir);
- myfree(tmpfile);
- myfree(newfile);
- return (0);
-}
+++ /dev/null
-/*++
-/* NAME
-/* recipient 3
-/* SUMMARY
-/* deliver to one local recipient
-/* SYNOPSIS
-/* #include "virtual.h"
-/*
-/* int deliver_recipient(state, usr_attr)
-/* LOCAL_STATE state;
-/* USER_ATTR *usr_attr;
-/* DESCRIPTION
-/* deliver_recipient() delivers a message to a local recipient.
-/*
-/* Arguments:
-/* .IP state
-/* The attributes that specify the message, sender, and more.
-/* .IP usr_attr
-/* Attributes describing user rights and mailbox location.
-/* DIAGNOSTICS
-/* deliver_recipient() returns non-zero when delivery should be
-/* tried again.
-/* SEE ALSO
-/* mailbox(3) delivery to UNIX-style mailbox
-/* maildir(3) delivery to qmail-style maildir
-/* LICENSE
-/* .ad
-/* .fi
-/* The Secure Mailer license must be distributed with this software.
-/* AUTHOR(S)
-/* Wietse Venema
-/* IBM T.J. Watson Research
-/* P.O. Box 704
-/* Yorktown Heights, NY 10598, USA
-/*--*/
-
-/* System library. */
-
-#include <sys_defs.h>
-
-/* Utility library. */
-
-#include <msg.h>
-#include <mymalloc.h>
-#include <stringops.h>
-
-/* Global library. */
-
-#include <bounce.h>
-
-/* Application-specific. */
-
-#include "virtual.h"
-
-/* deliver_recipient - deliver one local recipient */
-
-int deliver_recipient(LOCAL_STATE state, USER_ATTR usr_attr)
-{
- char *myname = "deliver_recipient";
- int rcpt_stat;
-
- /*
- * Make verbose logging easier to understand.
- */
- state.level++;
- if (msg_verbose)
- MSG_LOG_STATE(myname, state);
-
- /*
- * Set up the recipient-specific attributes. The recipient's lookup
- * handle is the full address.
- */
- if (state.msg_attr.delivered == 0)
- state.msg_attr.delivered = state.msg_attr.recipient;
- state.msg_attr.user = mystrdup(state.msg_attr.recipient);
- lowercase(state.msg_attr.user);
-
- /*
- * Deliver
- */
- if (msg_verbose)
- deliver_attr_dump(&state.msg_attr);
-
- if (deliver_mailbox(state, usr_attr, &rcpt_stat) == 0)
- rcpt_stat = deliver_unknown(state);
-
- /*
- * Cleanup.
- */
- myfree(state.msg_attr.user);
-
- return (rcpt_stat);
-}
+++ /dev/null
-/*++
-/* NAME
-/* unknown 3
-/* SUMMARY
-/* delivery of unknown recipients
-/* SYNOPSIS
-/* #include "virtual.h"
-/*
-/* int deliver_unknown(state)
-/* LOCAL_STATE state;
-/* DESCRIPTION
-/* deliver_unknown() delivers a message for unknown recipients.
-/* .PP
-/* Arguments:
-/* .IP state
-/* Message delivery attributes (sender, recipient etc.).
-/* .IP usr_attr
-/* Attributes describing user rights and mailbox location.
-/* DIAGNOSTICS
-/* The result status is non-zero when delivery should be tried again.
-/* LICENSE
-/* .ad
-/* .fi
-/* The Secure Mailer license must be distributed with this software.
-/* AUTHOR(S)
-/* Wietse Venema
-/* IBM T.J. Watson Research
-/* P.O. Box 704
-/* Yorktown Heights, NY 10598, USA
-/*--*/
-
-/* System library. */
-
-#include <sys_defs.h>
-
-/* Utility library. */
-
-#include <msg.h>
-
-/* Global library. */
-
-#include <bounce.h>
-
-/* Application-specific. */
-
-#include "virtual.h"
-
-/* deliver_unknown - delivery for unknown recipients */
-
-int deliver_unknown(LOCAL_STATE state)
-{
- char *myname = "deliver_unknown";
-
- /*
- * Make verbose logging easier to understand.
- */
- state.level++;
- if (msg_verbose)
- MSG_LOG_STATE(myname, state);
-
- return (bounce_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
- "unknown user: \"%s\"", state.msg_attr.user));
-
-}
+++ /dev/null
-/*++
-/* NAME
-/* virtual 8
-/* SUMMARY
-/* Postfix virtual domain mail delivery agent
-/* SYNOPSIS
-/* \fBvirtual\fR [generic Postfix daemon options]
-/* DESCRIPTION
-/* The \fBvirtual\fR delivery agent is designed for virtual mail
-/* hosting services. Originally based on the Postfix local delivery
-/* agent, this agent looks up recipients with map lookups of their
-/* full recipient address, instead of using hard-coded unix password
-/* file lookups of the address local part only.
-/*
-/* This delivery agent only delivers mail. Other features such as
-/* mail forwarding, out-of-office notifications, etc., must be
-/* configured via virtual maps or via similar lookup mechanisms.
-/* MAILBOX LOCATION
-/* .ad
-/* .fi
-/* The mailbox location is controlled by the \fBvirtual_mailbox_base\fR
-/* and \fBvirtual_mailbox_maps\fR configuration parameters (see below).
-/* The pathname is constructed as follows:
-/*
-/* .ti +2
-/* \fB$virtual_mailbox_base/$virtual_mailbox_maps(\fIrecipient\fB)\fR
-/*
-/* where \fIrecipient\fR is the full recipient address.
-/* UNIX MAILBOX FORMAT
-/* .ad
-/* .fi
-/* When the mailbox location does not end in \fB/\fR, the message
-/* is delivered in UNIX mailbox format. This format stores multiple
-/* messages in one textfile.
-/*
-/* The \fBvirtual\fR delivery agent prepends a "\fBFrom \fIsender
-/* time_stamp\fR" envelope header to each message, prepends a
-/* \fBDelivered-To:\fR message header with the envelope recipient
-/* address, prepends a \fBReturn-Path:\fR message header with the
-/* envelope sender address, prepends a \fB>\fR character to lines
-/* beginning with "\fBFrom \fR", and appends an empty line.
-/*
-/* The mailbox is locked for exclusive access while delivery is in
-/* progress. In case of problems, an attempt is made to truncate the
-/* mailbox to its original length.
-/* QMAIL MAILDIR FORMAT
-/* .ad
-/* .fi
-/* When the mailbox location ends in \fB/\fR, the message is delivered
-/* in qmail \fBmaildir\fR format. This format stores one message per file.
-/*
-/* The \fBvirtual\fR delivery agent daemon prepends a \fBDelivered-To:\fR
-/* message header with the envelope recipient address and prepends a
-/* \fBReturn-Path:\fR message header with the envelope sender address.
-/*
-/* By definition, \fBmaildir\fR format does not require file locking
-/* during mail delivery or retrieval.
-/* MAILBOX OWNERSHIP
-/* .ad
-/* .fi
-/* Mailbox ownership is controlled by the \fBvirtual_owner_maps\fR
-/* lookup tables. These tables can perform the following mappings:
-/* .IP "recipient username"
-/* The mailbox is owned by the specified UNIX user.
-/* .IP "recipient uid:gid"
-/* The mailbox is owned by the specified numerical user and group ID.
-/* BACKWARDS COMPATIBILITY
-/* .ad
-/* .fi
-/* For backwards compatibility, mailbox ownership can also be specified
-/* through separate \fBvirtual_uid_maps\fR and \fBvirtual_gid_maps\fR
-/* tables.
-/* SAFETY
-/* .ad
-/* .fi
-/* The \fBvirtual_minimum_uid\fR parameter imposes a lower bound on
-/* numerical user ID values that may be specified in any
-/* \fBvirtual_owner_maps\fR or \fBvirtual_uid_maps\fR.
-/* STANDARDS
-/* RFC 822 (ARPA Internet Text Messages)
-/* DIAGNOSTICS
-/* Mail bounces when the recipient has no mailbox or when the
-/* recipient is over disk quota. In all other cases, mail for
-/* an existing recipient is deferred and a warning is logged.
-/*
-/* Problems and transactions are logged to \fBsyslogd\fR(8).
-/* Corrupted message files are marked so that the queue
-/* manager can move them to the \fBcorrupt\fR queue afterwards.
-/*
-/* Depending on the setting of the \fBnotify_classes\fR parameter,
-/* the postmaster is notified of bounces and of other trouble.
-/* BUGS
-/* This delivery agent silently ignores address extensions.
-/* CONFIGURATION PARAMETERS
-/* .ad
-/* .fi
-/* The following \fBmain.cf\fR parameters are especially relevant to
-/* this program. See the Postfix \fBmain.cf\fR file for syntax details
-/* and for default values. Use the \fBpostfix reload\fR command after
-/* a configuration change.
-/* .SH Mailbox delivery
-/* .ad
-/* .fi
-/* .IP \fBvirtual_mailbox_base\fR
-/* Specifies a path that is prepended to all mailbox or maildir paths.
-/* This is a safety measure to ensure that an out of control map in
-/* \fBvirtual_mailbox_maps\fR doesn't litter the filesystem with mailboxes.
-/* While it could be set to "/", this setting isn't recommended.
-/* .IP \fBvirtual_mailbox_maps\fR
-/* Recipients are looked up in these maps to determine the path to
-/* their mailbox or maildir. If the returned path ends in a slash
-/* ("/"), maildir-style delivery is carried out, otherwise the
-/* path is assumed to specify a mailbox file.
-/*
-/* Note that \fBvirtual_mailbox_base\fR is unconditionally prepended
-/* to this path.
-/* .IP \fBvirtual_minimum_uid\fR
-/* Specifies a minimum uid that will be accepted as a return from
-/* a \fBvirtual_owner_maps\fR or \fBvirtual_uid_maps\fR lookup.
-/* Returned values less than this will be rejected, and the message
-/* will be deferred.
-/* .IP \fBvirtual_owner_maps\fR
-/* Recipients are looked up in these maps to determine the UNIX user
-/* name of the mailbox owner, or the numerical user and group ID
-/* in numerical \fIuid:gid\fR format.
-/* .IP \fBvirtual_uid_maps\fR
-/* Recipients are looked up in these maps to determine the user ID to be
-/* used when writing to the target mailbox.
-/* .sp
-/* This feature exists for backwards compatibility; it will go away.
-/* .IP \fBvirtual_gid_maps\fR
-/* Recipients are looked up in these maps to determine the group ID to be
-/* used when writing to the target mailbox.
-/* .sp
-/* This feature exists for backwards compatibility; it will go away.
-/* .SH "Locking controls"
-/* .ad
-/* .fi
-/* .IP \fBmailbox_delivery_lock\fR
-/* How to lock UNIX-style mailboxes: one or more of \fBflock\fR,
-/* \fBfcntl\fR or \fBdotlock\fR.
-/*
-/* Use the command \fBpostconf -m\fR to find out what locking methods
-/* are available on your system.
-/* .IP \fBdeliver_lock_attempts\fR
-/* Limit the number of attempts to acquire an exclusive lock
-/* on a UNIX-style mailbox file.
-/* .IP \fBdeliver_lock_delay\fR
-/* Time (default: seconds) between successive attempts to acquire
-/* an exclusive lock on a UNIX-style mailbox file.
-/* .IP \fBstale_lock_time\fR
-/* Limit the time after which a stale lockfile is removed (applicable
-/* to UNIX-style mailboxes only).
-/* .SH "Resource controls"
-/* .ad
-/* .fi
-/* .IP \fBvirtual_destination_concurrency_limit\fR
-/* Limit the number of parallel deliveries to the same domain.
-/* The default limit is taken from the
-/* \fBdefault_destination_concurrency_limit\fR parameter.
-/* .IP \fBvirtual_destination_recipient_limit\fR
-/* Limit the number of recipients per message delivery.
-/* The default limit is taken from the
-/* \fBdefault_destination_recipient_limit\fR parameter.
-/* HISTORY
-/* .ad
-/* .fi
-/* This agent was originally based on the Postfix local delivery
-/* agent. Modifications mainly consisted of removing code that either
-/* was not applicable or that was not safe in this context: aliases,
-/* ~user/.forward files, delivery to "|command" or to /file/name.
-/*
-/* The \fBDelivered-To:\fR header appears in the \fBqmail\fR system
-/* by Daniel Bernstein.
-/*
-/* The \fImaildir\fR structure appears in the \fBqmail\fR system
-/* by Daniel Bernstein.
-/* SEE ALSO
-/* bounce(8) non-delivery status reports
-/* syslogd(8) system logging
-/* qmgr(8) queue manager
-/* LICENSE
-/* .ad
-/* .fi
-/* The Secure Mailer license must be distributed with this software.
-/* AUTHOR(S)
-/* Wietse Venema
-/* IBM T.J. Watson Research
-/* P.O. Box 704
-/* Yorktown Heights, NY 10598, USA
-/*
-/* Andrew McNamara
-/* andrewm@connect.com.au
-/* connect.com.au Pty. Ltd.
-/* Level 3, 213 Miller St
-/* North Sydney 2060, NSW, Australia
-/*--*/
-
-/* System library. */
-
-#include <sys_defs.h>
-
-/* Utility library. */
-
-#include <msg.h>
-#include <vstring.h>
-#include <vstream.h>
-#include <iostuff.h>
-#include <set_eugid.h>
-#include <dict.h>
-
-/* Global library. */
-
-#include <mail_queue.h>
-#include <recipient_list.h>
-#include <deliver_request.h>
-#include <deliver_completed.h>
-#include <mail_params.h>
-#include <mail_conf.h>
-#include <mail_params.h>
-
-/* Single server skeleton. */
-
-#include <mail_server.h>
-
-/* Application-specific. */
-
-#include "virtual.h"
-
- /*
- * Tunable parameters.
- */
-char *var_mailbox_maps;
-char *var_uid_maps;
-char *var_gid_maps;
-int var_virt_minimum_uid;
-char *var_virt_mailbox_base;
-char *var_mailbox_lock;
-
- /*
- * Mappings.
- */
-MAPS *virtual_mailbox_maps;
-MAPS *virtual_uid_maps;
-MAPS *virtual_gid_maps;
-
- /*
- * Bit masks.
- */
-int virtual_mbox_lock_mask;
-
-/* local_deliver - deliver message with extreme prejudice */
-
-static int local_deliver(DELIVER_REQUEST *rqst, char *service)
-{
- char *myname = "local_deliver";
- RECIPIENT *rcpt_end = rqst->rcpt_list.info + rqst->rcpt_list.len;
- RECIPIENT *rcpt;
- int rcpt_stat;
- int msg_stat;
- LOCAL_STATE state;
- USER_ATTR usr_attr;
-
- if (msg_verbose)
- msg_info("local_deliver: %s from %s", rqst->queue_id, rqst->sender);
-
- /*
- * Initialize the delivery attributes that are not recipient specific.
- * While messages are being delivered and while aliases or forward files
- * are being expanded, this attribute list is being changed constantly.
- * For this reason, the list is passed on by value (except when it is
- * being initialized :-), so that there is no need to undo attribute
- * changes made by lower-level routines. The alias/include/forward
- * expansion attribute list is part of a tree with self and parent
- * references (see the EXPAND_ATTR definitions). The user-specific
- * attributes are security sensitive, and are therefore kept separate.
- * All this results in a noticeable level of clumsiness, but passing
- * things around by value gives good protection against accidental change
- * by subroutines.
- */
- state.level = 0;
- deliver_attr_init(&state.msg_attr);
- state.msg_attr.queue_name = rqst->queue_name;
- state.msg_attr.queue_id = rqst->queue_id;
- state.msg_attr.fp = rqst->fp;
- state.msg_attr.offset = rqst->data_offset;
- state.msg_attr.sender = rqst->sender;
- state.msg_attr.relay = service;
- state.msg_attr.arrival_time = rqst->arrival_time;
- RESET_USER_ATTR(usr_attr, state.level);
- state.request = rqst;
-
- /*
- * Iterate over each recipient named in the delivery request. When the
- * mail delivery status for a given recipient is definite (i.e. bounced
- * or delivered), update the message queue file and cross off the
- * recipient. Update the per-message delivery status.
- */
- for (msg_stat = 0, rcpt = rqst->rcpt_list.info; rcpt < rcpt_end; rcpt++) {
- state.msg_attr.recipient = rcpt->address;
- rcpt_stat = deliver_recipient(state, usr_attr);
- if (rcpt_stat == 0)
- deliver_completed(state.msg_attr.fp, rcpt->offset);
- msg_stat |= rcpt_stat;
- }
-
- return (msg_stat);
-}
-
-/* local_service - perform service for client */
-
-static void local_service(VSTREAM *stream, char *service, char **argv)
-{
- DELIVER_REQUEST *request;
- int status;
-
- /*
- * Sanity check. This service takes no command-line arguments.
- */
- if (argv[0])
- msg_fatal("unexpected command-line argument: %s", argv[0]);
-
- /*
- * This routine runs whenever a client connects to the UNIX-domain socket
- * that is dedicated to local mail delivery service. What we see below is
- * a little protocol to (1) tell the client that we are ready, (2) read a
- * delivery request from the client, and (3) report the completion status
- * of that request.
- */
- if ((request = deliver_request_read(stream)) != 0) {
- status = local_deliver(request, service);
- deliver_request_done(stream, request, status);
- }
-}
-
-/* pre_accept - see if tables have changed */
-
-static void pre_accept(char *unused_name, char **unused_argv)
-{
- if (dict_changed()) {
- msg_info("table has changed -- exiting");
- exit(0);
- }
-}
-
-/* post_init - post-jail initialization */
-
-static void post_init(char *unused_name, char **unused_argv)
-{
-
- /*
- * Drop privileges most of the time.
- */
- set_eugid(var_owner_uid, var_owner_gid);
-
- virtual_mailbox_maps =
- maps_create(VAR_VIRT_MAILBOX_MAPS, var_mailbox_maps,
- DICT_FLAG_LOCK);
-
- virtual_uid_maps =
- maps_create(VAR_VIRT_UID_MAPS, var_uid_maps, DICT_FLAG_LOCK);
-
- virtual_gid_maps =
- maps_create(VAR_VIRT_UID_MAPS, var_gid_maps, DICT_FLAG_LOCK);
-
- virtual_mbox_lock_mask = mbox_lock_mask(var_mailbox_lock);
-}
-
-/* main - pass control to the single-threaded skeleton */
-
-int main(int argc, char **argv)
-{
- static CONFIG_INT_TABLE int_table[] = {
- VAR_VIRT_MINUID, DEF_VIRT_MINUID, &var_virt_minimum_uid, 1, 0,
- 0,
- };
- static CONFIG_STR_TABLE str_table[] = {
- VAR_VIRT_MAILBOX_MAPS, DEF_VIRT_MAILBOX_MAPS, &var_mailbox_maps, 0, 0,
- VAR_VIRT_UID_MAPS, DEF_VIRT_UID_MAPS, &var_uid_maps, 0, 0,
- VAR_VIRT_GID_MAPS, DEF_VIRT_GID_MAPS, &var_gid_maps, 0, 0,
- VAR_VIRT_MAILBOX_BASE, DEF_VIRT_MAILBOX_BASE, &var_virt_mailbox_base, 0, 0,
- VAR_MAILBOX_LOCK, DEF_MAILBOX_LOCK, &var_mailbox_lock, 1, 0,
- 0,
- };
-
- single_server_main(argc, argv, local_service,
- MAIL_SERVER_INT_TABLE, int_table,
- MAIL_SERVER_STR_TABLE, str_table,
- MAIL_SERVER_POST_INIT, post_init,
- MAIL_SERVER_PRE_ACCEPT, pre_accept,
- 0);
-}
+++ /dev/null
-/*++
-/* NAME
-/* virtual 3h
-/* SUMMARY
-/* virtual mail delivery
-/* SYNOPSIS
-/* #include "virtual.h"
-/* DESCRIPTION
-/* .nf
-
- /*
- * System library.
- */
-#include <unistd.h>
-
- /*
- * Utility library.
- */
-#include <vstream.h>
-#include <vstring.h>
-
- /*
- * Global library.
- */
-#include <deliver_request.h>
-#include <maps.h>
-#include <mbox_conf.h>
-
- /*
- * Mappings.
- */
-extern MAPS *virtual_mailbox_maps;
-extern MAPS *virtual_uid_maps;
-extern MAPS *virtual_gid_maps;
-
- /*
- * User attributes: these control the privileges for delivery to external
- * commands, external files, or mailboxes, and the initial environment of
- * external commands.
- */
-typedef struct USER_ATTR {
- uid_t uid; /* file/command access */
- gid_t gid; /* file/command access */
- char *mailbox; /* mailbox file or directory */
-} USER_ATTR;
-
- /*
- * Critical macros. Not for obscurity, but to ensure consistency.
- */
-#define RESET_USER_ATTR(usr_attr, level) { \
- usr_attr.uid = 0; usr_attr.gid = 0; usr_attr.mailbox = 0; \
- if (msg_verbose) \
- msg_info("%s[%d]: reset user_attr", myname, level); \
- }
-
- /*
- * The delivery attributes are inherited from files, from aliases, and from
- * whatnot. Some of the information is changed on the fly. DELIVER_ATTR
- * structres are therefore passed by value, so there is no need to undo
- * changes.
- */
-typedef struct DELIVER_ATTR {
- int level; /* recursion level */
- VSTREAM *fp; /* open queue file */
- char *queue_name; /* mail queue id */
- char *queue_id; /* mail queue id */
- long offset; /* data offset */
- char *sender; /* taken from envelope */
- char *recipient; /* taken from resolver */
- char *user; /* recipient lookup handle */
- char *delivered; /* for loop detection */
- char *relay; /* relay host */
- long arrival_time; /* arrival time */
-} DELIVER_ATTR;
-
-extern void deliver_attr_init(DELIVER_ATTR *);
-extern void deliver_attr_dump(DELIVER_ATTR *);
-
-#define FEATURE_NODELIVERED (1<<0) /* no delivered-to */
-
- /*
- * Rather than schlepping around dozens of arguments, here is one that has
- * all. Well, almost. The user attributes are just a bit too sensitive, so
- * they are passed around separately.
- */
-typedef struct LOCAL_STATE {
- int level; /* nesting level, for logging */
- DELIVER_ATTR msg_attr; /* message attributes */
- DELIVER_REQUEST *request; /* as from queue manager */
-} LOCAL_STATE;
-
- /*
- * Bundle up some often-user attributes.
- */
-#define BOUNCE_ATTR(attr) attr.queue_id, attr.recipient, attr.relay, \
- attr.arrival_time
-#define SENT_ATTR(attr) attr.queue_id, attr.recipient, attr.relay, \
- attr.arrival_time
-#define COPY_ATTR(attr) attr.sender, attr.delivered, attr.fp
-
-#define MSG_LOG_STATE(m, p) \
- msg_info("%s[%d]: recip %s deliver %s", m, \
- p.level, \
- p.msg_attr.recipient ? p.msg_attr.recipient : "", \
- p.msg_attr.delivered ? p.msg_attr.delivered : "")
-
- /*
- * "inner" nodes of the delivery graph.
- */
-extern int deliver_recipient(LOCAL_STATE, USER_ATTR);
-
- /*
- * "leaf" nodes of the delivery graph.
- */
-extern int deliver_mailbox(LOCAL_STATE, USER_ATTR, int *);
-extern int deliver_file(LOCAL_STATE, USER_ATTR, char *);
-extern int deliver_maildir(LOCAL_STATE, USER_ATTR);
-extern int deliver_unknown(LOCAL_STATE);
-
- /*
- * Mailbox lock protocol.
- */
-extern int virtual_mbox_lock_mask;
-
-/* LICENSE
-/* .ad
-/* .fi
-/* The Secure Mailer license must be distributed with this software.
-/* AUTHOR(S)
-/* Wietse Venema
-/* IBM T.J. Watson Research
-/* P.O. Box 704
-/* Yorktown Heights, NY 10598, USA
-/*--*/