html/ HTML format
man/ UNIX on-line manual page format
+Example files:
+
+ conf/ sample configuration files
+ examples/ chroot environments, virtual domains
+
Library routines:
dns/ DNS client library
--- /dev/null
+LINUX SYSLOGD PERFORMANCE
+=========================
+
+LINUX syslogd uses synchronous writes by default, which is very
+expensive. For services such a mail it is recommended that you
+disable synchronous logfile writes by prepending a - to the logfile
+name:
+
+ mail.* -/var/log/mail.log
+
+SPAM BLOCKING SOURCE ROUTED ADDRESSES
+=====================================
+
+If you relay mail for other domains, you must prevent unauthorized
+relay of addresses such as:
+
+ user@elsewhere@the.other.domain
+ user%elsewhere@the.other.domain
+ elsewhere!user@the.other.domain
+
+The simplest solution is to install a regular expression filter:
+
+ /etc/postfix/main.cf:
+ smtpd_recipient_restrictions = regexp:/etc/postfix/regexp_access
+
+ /etc/postfix/regexp_access:
+ /[%!@].*@/ 550 Sender specified routing is not supported here.
+
+For the local domain, Postfix will do the right thing with:
+
+ user@elsewhere@my.own.domain
+ user%elsewhere@my.own.domain
+ elsewhere!user@my.own.domain
+
+That is, it bounces the first form because "user@elsewhere" is not
+a valid local user, and it accepts the second and third forms only
+when user@elsewhere is a valid relay destination.
+
is: "prepend_delivered_header = command, file, forward".
Turning off the Delivered-To: header when forwarding mail
is not recommended.
+
+19990628
+
+ Feature: the postlock command now returns EX_TEMPFAIL
+ when the destination file is locked by another process.
+
+19990705
+
+ Workaround: in the SMTP client, move the "mail loops back
+ to myself test" from the 220 greeting to the HELO response.
+ This change does not weaken the test, and makes Postfix
+ more robust against broken software that greets with the
+ client hostname.
+
+19990706
+
+ Workaround: in the INSTALL file, use `&&' instead of `;'
+ in (cd path; tar ...) pipelines because some UNIX re-invented
+ shells don't bail out when cd fails. Matthias Andree
+ @dosis.uni-dortmund.de.
+
+19990709
+
+ Bugfix: $user was not set when delivering to a non-user.
+ Found by Vladimir Ulogov @ rohan.control.att.com when
+ configuring a luser_relay that contained $user.
+
+19990714
+
+ Robustness: add PATH statement to Solaris2 chroot setup
+ script to avoid running the ucb commands. Problem found
+ by Panagiotis Astithas @ ece.ntua.gr.
+
+19990721
+
+ Bugfix: don't claim a "mail loops to myself" error when
+ the best MX host was not found in the DNS. Found by Andrew
+ McNamara, connect.com.au Pty Ltd. File: smtp/smtp_addr.c.
+
+19990810
+
+ Feature: added "-c config_directory" support to the postconf
+ command. This probably means that "-f file" will never be
+ implemented.
+
+19990812
+
+ Bugfix: showq didn't print properly when listing a maildrop
+ file. Fix by: Andrew McNamara, connect.com.au Pty Ltd.
+ File: showq/showq.c.
+
+ Feature: added SENDER to the list of parameters exported
+ to external commands. File: local/command.c. Code by: Lars
+ Hecking, National Microelectronics Research Centre, Ireland.
+
+19990813
+
+ Bugfix: sendmail -t (extract recipients from headers) did not
+ work when the always_bcc feature was turned on. Reported
+ by: Denis Shaposhnikov @ neva.vlink.ru.
+
+19990813
+ Bugfix: "sendmail -bd" returns a bogus exit status (the child
+ process ID). Fix by Lamont Jones of Hewlett-Packard. File:
+ sendmail/sendmail.c.
+
+19990824
+
+ Bugfix: null pointer dereference while rejecting VRFY before
+ MAIL FROM. Found by Laurent Wacrenier @ fr.clara.net.
+
+19990826
+
+ Portability: more MacOS X Server patches; some NEXTSTEP/OPENSTEP
+ code that had been removed for the first public beta release;
+ NEXTSTEP/OPENSTEP now defaults to netinfo for the aliases
+ database. Submitted by Gerben Wierda.
+
+ Portability: workaround for a FreeBSD 3.x active network
+ interface without IP address by Pierre Beyssac @ enst.fr.
+ File: inet_addr_local.c.
+
+19990831
+
+ Workaround: sendmail now prints a warning when installed
+ set-uid or when run by a set-uid command. Reportedly, the
+ linuxconf software turns on the set-uid bit, which could
+ open up a security loophole. File: sendmail/sendmail.c.
+
+ Bugfix: Postfix daemons now temporarily lock DB/DBM files
+ while opening them, in order to avoid "invalid argument"
+ errors because some other process is changing the file.
+ Files: util/dict_db.c, util/dict_dbm.c.
+
+ Robustness: Postfix locks queue files during delivery, to
+ prevent duplicate delivery when "postfix reload" is
+ immediately followed by "sendmail -q". This involves a
+ change of the deliver_request interface: delivery agents
+ no longer need to open and close queue files explicitly.
+ Files: global/deliver_request.c, pipe/pipe.c, smtp/smtp.c,
+ local/local.c, qmgr/qmgr_active.c, qmgr/qmgr_message.c.
+
+ Feature: reject_unauth_destination SMTP recipient restriction
+ that rejects destinations not in $relay_domains. By Lamont
+ Jones of Hewlett-Packard. File: smtpd/smtpd_check.c.
+
+ Robustness: postconf now validates the syntax of all main.cf
+ parameters.
If your system is supported, it is one of
+ AIX 3.2.5
AIX 4.1.x
AIX 4.2.0
BSD/OS 2.x
Linux RedHat 5.x
Linux Slackware 3.5
Linux SuSE 5.x
+ Mac OS X server
NEXTSTEP 3.x
NetBSD 1.x
OPENSTEP 4.x
+ OSF1.V3 (Digital UNIX)
OSF1.V4 aka Digital UNIX V4
OpenBSD 2.x
+ Reliant UNIX 5.x
+ Rhapsody 5.x
SunOS 4.1.x
SunOS 5.4..5.7 (Solaris 2.4..7)
+ Ultrix 4.x
-or something closely resemblant. Some platforms such as Ultrix 4
-need a bit of work because their shell is a bit brain damaged.
+or something closely resemblant.
If at any time in the build process you get messages like: "make:
don't know how to ..." you should be able to recover by running
- On-line manual pages:
# mkdir /some/where/man
- # (cd man; tar cf - .) | (cd /some/where/man; tar xvf -)
+ # (cd man && tar cf - .) | (cd /some/where/man && tar xvf -)
Alternative: leave the manpages in the Postfix source tree.
-IBM PUBLIC LICENSE VERSION 1.0 6/14/1999 - SECURE MAILER
+IBM PUBLIC LICENSE VERSION 1.0 - SECURE MAILER
THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS IBM PUBLIC
LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE
Each Contributor must include the following in a conspicuous location
in the Program:
- Copyright (c) {date here}, International Business Machines Corporation
- and others. All Rights Reserved.
+ Copyright (c) 1997,1998,1999, International Business Machines
+ Corporation and others. All Rights Reserved.
In addition, each Contributor must identify itself as the originator of
its Contribution, if any, in a manner that reasonably allows subsequent
/* 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.
+/* 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 Miscellaneous
/* .ad
/* .fi
+/* .IP \fBalways_bcc\fR
+/* Address to send a copy of each message that enters the system.
/* .IP \fBhopcount_limit\fR
/* Limit the number of \fBReceived:\fR message headers.
/* .SH "Address transformations"
char *var_empty_addr; /* destination of bounced bounces */
int var_delay_warn_time; /* delay that triggers warning */
char *var_prop_extension; /* propagate unmatched extension */
+char *var_always_bcc;
/*
* Mappings.
if (*var_masq_domains)
cleanup_masq_domains = argv_split(var_masq_domains, " ,\t\r\n");
if (*var_header_checks)
- cleanup_header_checks =
+ cleanup_header_checks =
maps_create(VAR_HEADER_CHECKS, var_header_checks, DICT_FLAG_LOCK);
}
VAR_MASQ_EXCEPTIONS, DEF_MASQ_EXCEPTIONS, &var_masq_exceptions, 0, 0,
VAR_HEADER_CHECKS, DEF_HEADER_CHECKS, &var_header_checks, 0, 0,
VAR_PROP_EXTENSION, DEF_PROP_EXTENSION, &var_prop_extension, 0, 0,
+ VAR_ALWAYS_BCC, DEF_ALWAYS_BCC, &var_always_bcc, 0, 0,
0,
};
/*
* Optionally account for missing recipient envelope records.
+ *
+ * XXX Code duplication from cleanup_envelope.c. This should be in one
+ * place.
*/
if (cleanup_recip == 0) {
rcpt = (cleanup_resent[0] ? cleanup_resent_recip : cleanup_recipients);
+ if (*var_always_bcc && rcpt->argv[0]) {
+ clean_addr = vstring_alloc(100);
+ cleanup_rewrite_internal(clean_addr, var_always_bcc);
+ if (cleanup_rcpt_canon_maps)
+ cleanup_map11_internal(clean_addr, cleanup_rcpt_canon_maps,
+ cleanup_ext_prop_mask & EXT_PROP_CANONICAL);
+ if (cleanup_comm_canon_maps)
+ cleanup_map11_internal(clean_addr, cleanup_comm_canon_maps,
+ cleanup_ext_prop_mask & EXT_PROP_CANONICAL);
+ argv_add(rcpt, STR(clean_addr), (char *) 0);
+ vstring_free(clean_addr);
+ }
argv_terminate(rcpt);
for (cpp = rcpt->argv; CLEANUP_OUT_OK() && *cpp; cpp++)
cleanup_out_recipient(*cpp);
-IBM PUBLIC LICENSE VERSION 1.0 6/14/1999 - SECURE MAILER
+IBM PUBLIC LICENSE VERSION 1.0 - SECURE MAILER
THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS IBM PUBLIC
LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE
Each Contributor must include the following in a conspicuous location
in the Program:
- Copyright (c) {date here}, International Business Machines Corporation
- and others. All Rights Reserved.
+ Copyright (c) 1997,1998,1999, International Business Machines
+ Corporation and others. All Rights Reserved.
In addition, each Contributor must identify itself as the originator of
its Contribution, if any, in a manner that reasonably allows subsequent
#
-# >>>>>>>>>> The program "newaliases" must be run after
-# >> NOTE >> this file is updated for any changes to
-# >>>>>>>>>> show through to sendmail.
+# >>>>>>>>>> The program "newaliases" must be run after
+# >> NOTE >> this file is updated for any changes to
+# >>>>>>>>>> show through to Postfix.
#
# Basic system aliases -- these MUST be present
-MAILER-DAEMON: postmaster
-postmaster: root
+MAILER-DAEMON: postmaster
+postmaster: root
# General redirections for pseudo accounts
-bin: root
-daemon: root
-named: root
-nobody: root
-operator: root
-uucp: root
-www: root
-ftp-bugs: root
+bin: root
+daemon: root
+named: root
+nobody: root
+uucp: root
+www: root
+ftp-bugs: root
# Put your local aliases here.
-# Well-known aliases -- these should be filled in!
-# root:
-# manager:
-# dumper:
-# operator:
+# Well-known aliases
+manager: root
+dumper: root
+operator: root
+abuse: postmaster
+
+# trap decode to catch security attacks
+decode: root
+
+# Person who should get root's mail
+#root: you
#++
# NAME
#alias_maps = dbm:/etc/aliases
#alias_maps = hash:/etc/aliases
#alias_maps = hash:/etc/aliases, nis:mail.aliases
+#alias_maps = netinfo:/aliases
# The alias_database parameter specifies the alias database(s) that
# are built with "newaliases" or "sendmail -bi". This is a separate
# The header_checks parameter restricts what may appear in message
# headers. This requires that POSIX or PCRE regular expression support
-# is built-in. Specify "/^header-name: stuff you don not want/ REJECT"
-# in the pattern file. Patterns are case-insensitive by default.
+# is built-in. Specify "/^header-name: stuff you do not want/ REJECT"
+# in the pattern file. Patterns are case-insensitive by default. Note:
+# specify only patterns ending in REJECT. Patterns ending in OK are
+# a waste of cycles.
#
#header_checks = regexp:/etc/postfix/filename
#header_checks = pcre:/etc/postfix/filename
# Chroot: whether or not the service runs chrooted to the mail queue
# directory (pathname is controlled by the queue_directory configuration
# variable in the main.cf file). Presently, all Postfix daemons can run
-# chrooted, except for the pipe and local daemons. The contributed
-# source code from http://www.postfix.org/ describes how to set up
-# a Postfix chroot environment for your type of machine.
+# chrooted, except for the pipe and local daemons. The files in the
+# examples/chroot-setup subdirectory describe how to set up a Postfix
+# chroot environment for your type of machine.
#
# Wakeup time: automatically wake up the named service after the
# specified number of seconds. Specify 0 for no wakeup. Presently,
flags=F user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient)
ifmail unix - n n - - pipe
flags=F user=ftn argv=/usr/lib/ifmail/ifmail -r $nexthop ($recipient)
+bsmtp unix - n n - - pipe
+ flags=F user=foo argv=/usr/local/sbin/bsmtp -f $sender $nexthop $recipient
+
# LINUX by default does not synchronously update directories -
# that's dangerous for mail.
#
-if [ -x /usr/bin/chattr ]
+if [ -f /usr/bin/chattr ]
then
CHATTR="/usr/bin/chattr +S"
else
$FATAL no Postfix daemon directory $daemon_directory!
exit 1
}
-test -x master || {
+test -f master || {
$FATAL no Postfix master program $daemon_directory/master!
exit 1
}
# LINUX by default does not synchronously update directories -
# that's dangerous for mail.
#
-if [ -x /usr/bin/chattr ]
+if [ -f /usr/bin/chattr ]
then
CHATTR="/usr/bin/chattr +S"
else
$FATAL no Postfix daemon directory $daemon_directory!
exit 1
}
-test -x master || {
+test -f master || {
$FATAL no Postfix master program $daemon_directory/master!
exit 1
}
# The queue_directory specifies the location of the Postfix queue.
# This is also the root directory of Postfix daemons that run chrooted.
-# The contributed source code from http://www.postfix.org/ has examples
-# for setting up Postfix chroot environments on different UNIX systems.
+# The files in the examples/chroot-setup subdirectory describe how
+# to set up Postfix chroot environments on different UNIX systems.
#
queue_directory = /var/spool/postfix
# second (if present) must not match. The first matching line wins,
# terminating processing of the ruleset.
+# Disallow sender-specified routing. This is a must if you relay mail
+#for other domains.
+/[%!@].*@/ 550 Sender-specified routing rejected
+
# Postmaster is OK, that way they can talk to us about how to fix their problem.
/^postmaster@.*$/ OK
# reject_unknown_hostname: reject HELO hostname without DNS A or MX record.
# reject_unknown_sender_domain: reject sender domain without A or MX record.
# check_relay_domains: permit only mail from/to domains in $relay_domains.
+# reject_unauth_destination: reject mail not to domains in $relay_domains.
# permit_mx_backup: accept mail for sites that list me as MX host.
# reject_unknown_recipient_domain: reject domains without A or MX record.
# check_recipient_access maptype:mapname
#!/bin/sh
+PATH=/usr/bin:/sbin:/usr/sbin
+
# Create chroot'd area under Solaris 2.5.1 for postfix.
#
# Dug Song <dugsong@UMICH.EDU>
deliver_request.o: ../include/vstring.h
deliver_request.o: ../include/mymalloc.h
deliver_request.o: ../include/iostuff.h
+deliver_request.o: ../include/myflock.h
deliver_request.o: mail_queue.h
deliver_request.o: mail_proto.h
deliver_request.o: mail_open_ok.h
/*
/* typedef struct DELIVER_REQUEST {
/* .in +5
+/* VSTREAM *fp;
/* char *queue_name;
/* char *queue_id;
/* long data_offset;
/* to delivery agent' protocol. In this game, the queue manager is
/* the client, while the delivery agent is the server.
/*
-/* deliver_request_read() reads a client message delivery request.
+/* deliver_request_read() reads a client message delivery request,
+/* opens the queue file, and acquires a shared lock.
/* A null result means that the client sent bad information or that
/* it went away unexpectedly.
/*
/*
/* deliver_request_done() reports the delivery status back to the
/* client, including the optional \fIhop_status\fR information,
+/* closes the queue file,
/* and destroys the DELIVER_REQUEST structure. The result is
/* non-zero when the status could not be reported to the client.
/* DIAGNOSTICS
#include <vstring.h>
#include <mymalloc.h>
#include <iostuff.h>
+#include <myflock.h>
/* Global library. */
static int deliver_request_get(VSTREAM *stream, DELIVER_REQUEST *request)
{
+ char *myname = "deliver_request_get";
const char *path;
struct stat st;
static VSTRING *queue_name;
if (mail_open_ok(vstring_str(queue_name),
vstring_str(queue_id), &st, &path) == 0)
return (-1);
+
request->queue_name = mystrdup(vstring_str(queue_name));
request->queue_id = mystrdup(vstring_str(queue_id));
request->nexthop = mystrdup(vstring_str(nexthop));
return (-1);
recipient_list_add(&request->rcpt_list, offset, vstring_str(address));
}
+
+ /*
+ * Open the queue file and set a shared lock, in order to prevent
+ * duplicate deliveries when the queue is flushed immediately after queue
+ * manager restart.
+ *
+ * Opening the queue file can fail for a variety of reasons, such as the
+ * system running out of resources. Instead of throwing away mail, we're
+ * raising a fatal error which forces the mail system to back off, and
+ * retry later.
+ */
+#define DELIVER_LOCK_MODE (MYFLOCK_SHARED | MYFLOCK_NOWAIT)
+
+ request->fp =
+ mail_queue_open(request->queue_name, request->queue_id, O_RDWR, 0);
+ if (request->fp == 0)
+ msg_fatal("open %s %s: %m", request->queue_name, request->queue_id);
+ if (msg_verbose)
+ msg_info("%s: file %s", myname, VSTREAM_PATH(request->fp));
+ if (myflock(vstream_fileno(request->fp), DELIVER_LOCK_MODE) < 0)
+ msg_fatal("shared lock %s: %m", VSTREAM_PATH(request->fp));
+ close_on_exec(vstream_fileno(request->fp), CLOSE_ON_EXEC);
+
return (0);
}
DELIVER_REQUEST *request;
request = (DELIVER_REQUEST *) mymalloc(sizeof(*request));
+ request->fp = 0;
request->queue_name = 0;
request->queue_id = 0;
request->nexthop = 0;
static void deliver_request_free(DELIVER_REQUEST *request)
{
+ if (request->fp)
+ vstream_fclose(request->fp);
if (request->queue_name)
myfree(request->queue_name);
if (request->queue_id)
* Structure of a server mail delivery request.
*/
typedef struct DELIVER_REQUEST {
+ VSTREAM *fp; /* stream, shared lock */
char *queue_name; /* message queue name */
char *queue_id; /* message queue id */
long data_offset; /* offset to message */
* XXX Solaris workaround for ECONNREFUSED on a busy socket.
*/
while ((stream = mail_connect(class, name, BLOCKING)) == 0) {
- if (errno == ECONNREFUSED || errno == ENOENT)
- (count++ >= 10 ? msg_fatal : msg_warn)
- ("connect #%d to subsystem %s/%s: %m", count, class, name);
+ if (errno == ECONNREFUSED || errno == ENOENT) {
+ if (count++ >= 10) {
+ msg_fatal("connect #%d to subsystem %s/%s: %m",
+ count, class, name);
+ } else {
+ msg_warn("connect #%d to subsystem %s/%s: %m",
+ count, class, name);
+ }
+ }
sleep(10); /* XXX make configurable */
}
return (stream);
ABCDEFGHIJKLMNOPQRSTUVWXYZ"
extern char *var_cmd_exp_filter;
+#define VAR_FWD_EXP_FILTER "forward_expansion_filter"
+#define DEF_FWD_EXP_FILTER "1234567890!@%-_=+:,.\
+abcdefghijklmnopqrstuvwxyz\
+ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+extern char *var_fwd_exp_filter;
+
#define VAR_DELIVER_HDR "prepend_delivered_header"
#define DEF_DELIVER_HDR "command, file, forward"
extern char *var_deliver_hdr;
#define DEF_UNK_ADDR_CODE 450
extern int var_unk_addr_code;
+#define REJECT_UNAUTH_DEST "reject_unauth_destination"
#define CHECK_RELAY_DOMAINS "check_relay_domains"
#define VAR_RELAY_CODE "relay_domains_reject_code"
#define DEF_RELAY_CODE 554
* Version of this program.
*/
#define VAR_MAIL_VERSION "mail_version"
-#define DEF_MAIL_VERSION "Snapshot-19990627"
+#define DEF_MAIL_VERSION "Snapshot-19990831"
extern char *var_mail_version;
/* LICENSE
const char *expansion;
DICT *dict;
+ /*
+ * Temp. workaround, for buggy callers that pass zero-length keys when
+ * given partial addresses.
+ */
+ if (*name == 0)
+ return (0);
+
for (map_name = maps->argv->argv; *map_name; map_name++) {
if ((dict = dict_handle(*map_name)) == 0)
msg_panic("%s: dictionary not found: %s", myname, *map_name);
command after a configuration change.
<b>Miscellaneous</b>
+ <b>always</b><i>_</i><b>bcc</b>
+ Address to send a copy of each message that enters
+ the system.
+
<b>hopcount</b><i>_</i><b>limit</b>
Limit the number of <b>Received:</b> message headers.
<b>Address</b> <b>transformations</b>
<b>empty</b><i>_</i><b>address</b><i>_</i><b>recipient</b>
- The destination for undeliverable mail from <>.
- This substitution is done before all other address
+ The destination for undeliverable mail from <>.
+ This substitution is done before all other address
rewriting.
<b>canonical</b><i>_</i><b>maps</b>
header sender addresses.
<b>masquerade</b><i>_</i><b>domains</b>
- List of domains that hide their subdomain struc-
+ List of domains that hide their subdomain struc-
ture.
<b>masquerade</b><i>_</i><b>exceptions</b>
- List of user names that are not subject to address
+ List of user names that are not subject to address
masquerading.
<b>virtual</b><i>_</i><b>maps</b>
<b>Resource</b> <b>controls</b>
<b>duplicate</b><i>_</i><b>filter</b><i>_</i><b>limit</b>
- Limit the number of envelope recipients that are
- remembered.
-
- <b>header</b><i>_</i><b>size</b><i>_</i><b>limit</b>
- Limit the amount of memory in bytes used to process
+ Limit the number of envelope recipients that are
CLEANUP(8) CLEANUP(8)
+ remembered.
+
+ <b>header</b><i>_</i><b>size</b><i>_</i><b>limit</b>
+ Limit the amount of memory in bytes used to process
a message header.
<b>SEE</b> <b>ALSO</b>
/etc/postfix/virtual*, virtual mapping table
<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>
-
-
-
-
<li><a href="#local">Delivering some users locally while sending mail as user@domain</a>
+<li><a href="#scanning">Support for virus scanning</a>
+
<li><a href="#maildir">Support for maildir-style mailboxes</a>
<li><a href="#procmail">Using Procmail for local delivery</a>
<p>
-<i> When you disable DNS lookups, you must specify a</i> <b>relayhost</b>
-<i> as either a numeric IP address, or as a hostname that appears
-in</i> <b>/etc/hosts</b>.
+<i> When you disable DNS lookups, you must specify the</i>
+<b>relayhost</b> <i> as either a numeric IP address, or as a hostname
+that resolves to one or more IP addresses (Postfix does no</i>
+<b>MX</b> lookup).
<p>
<hr>
+<a name="scanning"><h2>Support for virus scanning</h2> </a>
+
+Would not it be great if operating systems and applications actually
+worked the way they are supposed to, instead of being as fragile
+as today's products? Well, we can solve only one problem at a time.
+
+<p>
+
+Currently, Postfix has no hooks to let other programs inspect every
+message, so the scanning has to be done before mail enters Postfix
+or while mail leaves Postfix, for example at mailbox delivery time.
+
+<p>
+
+<dl>
+
+<dt>Examples:
+
+<dl>
+
+<dt><b>mailbox_command = </b><i>/some/program ...</i>
+
+<dd>specifies a command that runs whenever mail is delivered to
+mailbox. See the sample <b>main.cf</b> file for examples. In
+<b>/etc/aliases</i>, you must specify an alias for <b>root</b> that
+directs mail to a real person, otherwise funny things happen with
+mail sent to <b>root</b>.
+
+<p>
+
+<dt><b> mailbox_transport = </b><i>foo</i>
+
+<dd>delegates local mailbox delivery to the transport <i>foo</i> as
+configured in <b>/etc/postfix/master.cf</b>. If you follow this
+route you will build something around the pipe mailer. See examples
+in <b>master.cf</b>.
+
+</dl>
+
+</dl>
+
+<hr>
+
<a name="maildir"><h2>Support for maildir-style mailboxes</h2> </a>
<b>Maildir</b> is a specific one-file-per-message organization that
<dl>
-<dt><tt>smtpd_recipients = ... regexp:/etc/postfix/access_regexp ...</tt>
+<dt><tt>smtpd_recipient_restrictions = ... regexp:/etc/postfix/access_regexp ...</tt>
-<dt><tt>smtpd_recipients = ... pcre:/etc/postfix/access_regexp ...</tt>
+<dt><tt>smtpd_recipient_restrictions = ... pcre:/etc/postfix/access_regexp ...</tt>
</dl>
address extension), <b>$domain</b> (recipient domain), <b>local</b>
(entire recipient address localpart) and <b>$recipient</b><i>_</i><b>delim-</b>
<b>iter.</b> The forms <i>${name?value}</i> and <i>${name:value}</i> expand
- conditionally to <i>value</i> when <i>$name</i> is (is not) defined.
+ conditionally to <i>value</i> when <i>$name</i> is (is not) defined.
+ Characters that may have special meaning to the shell or
+ file system are replaced by underscores. The list of
+ acceptable characters is specified with the <b>forward</b><i>_</i><b>expan-</b>
+ <b>sion</b><i>_</i><b>filter</b> configuration
An alias or ~/.<b>forward</b> file may list any combination of
external commands, destination file names, <b>:include:</b>
When an address is found in its own alias expansion,
delivery is made to the user instead. When a user is
listed in the user's own ~/.<b>forward</b> file, delivery is made
- to the user's mailbox instead. An empty ~/.<b>forward</b> file
- means do not forward mail.
-
- In order to prevent the mail system from using up
LOCAL(8) LOCAL(8)
- unreasonable amounts of memory, input records read from
+ to the user's mailbox instead. An empty ~/.<b>forward</b> file
+ means do not forward mail.
+
+ In order to prevent the mail system from using up unrea-
+ sonable amounts of memory, input records read from
<b>:include:</b> or from ~/.<b>forward</b> files are broken up into
chunks of length <b>line</b><i>_</i><b>length</b><i>_</i><b>limit</b>.
rate on-file delivery status record.
In order to stop mail forwarding loops early, the software
- adds a <b>Delivered-To:</b> header with the envelope recipient
- address. If mail arrives for a recipient that is already
- listed in a <b>Delivered-To:</b> header, the message is bounced.
+ adds an optional <b>Delivered-To:</b> header with the envelope
+ recipient address. If mail arrives for a recipient that is
+ already listed in a <b>Delivered-To:</b> header, the message is
+ bounced.
<b>MAILBOX</b> <b>DELIVERY</b>
The default per-user mailbox is a file in the UNIX mail
In the case of UNIX-style mailbox delivery, the <b>local</b> dae-
mon prepends a "<b>From</b> <i>sender</i> <i>time_stamp</i>" envelope header to
- each message, prepends an optional <b>Delivered-To:</b> header
- with the envelope recipient address, prepends a <b>Return-</b>
- <b>Path:</b> header with the envelope sender address, prepends a
- > character to lines beginning with "<b>From</b> ", and appends
- an empty line. The mailbox is locked for exclusive access
LOCAL(8) LOCAL(8)
+ each message, prepends an optional <b>Delivered-To:</b> header
+ with the envelope recipient address, prepends a <b>Return-</b>
+ <b>Path:</b> header with the envelope sender address, prepends a
+ > character to lines beginning with "<b>From</b> ", 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.
<b>LOCAL</b> The entire recipient address localpart (text to the
left of the rightmost @ character).
- <b>RECIPIENT</b>
- The entire recipient address.
-
- The <b>PATH</b> environment variable is always reset to a system-
-
3
LOCAL(8) LOCAL(8)
+ <b>RECIPIENT</b>
+ The entire recipient address.
+
+ The <b>PATH</b> environment variable is always reset to a system-
dependent default path, and the <b>TZ</b> (time zone) environment
variable is always passed on without change.
<b>DELIVERY</b> <b>RIGHTS</b>
Deliveries to external files and external commands are
- made with the rights of the receiving user on whose behalf
- the delivery is made. In the absence of a user context,
- the <b>local</b> daemon uses the owner rights of the <b>:include:</b>
- file or alias database. When those files are owned by the
LOCAL(8) LOCAL(8)
+ made with the rights of the receiving user on whose behalf
+ the delivery is made. In the absence of a user context,
+ the <b>local</b> daemon uses the owner rights of the <b>:include:</b>
+ file or alias database. When those files are owned by the
superuser, delivery is made with the rights specified with
the <b>default</b><i>_</i><b>privs</b> configuration parameter.
<b>local</b><i>_</i><b>command</b><i>_</i><b>shell</b>
Shell to use for external command execution (for
example, /some/where/smrsh -c). When a shell is
- specified, it is invoked even when the command con-
- tains no shell built-in commands or meta charac-
- ters.
-
-
+ specified, it is invoked even when the command
LOCAL(8) LOCAL(8)
- <b>prepend</b><i>_</i><b>delivered</b><i>_</i><b>header</b>
- Prepend an optional <b>Delivered-To:</b> header upon
- external forwarding, delivery to command or file.
- Specify zero or more of: <b>command,</b> <b>file,</b> <b>forward</b>.
- Turning off <b>Delivered-To:</b> when forwarding mail is
- not recommended.
+ contains no shell built-in commands or meta charac-
+ ters.
<b>owner</b><i>_</i><b>request</b><i>_</i><b>special</b>
Give special treatment to <b>owner-</b><i>xxx</i> and <i>xxx</i><b>-request</b>
addresses.
+ <b>prepend</b><i>_</i><b>delivered</b><i>_</i><b>header</b>
+ Prepend an optional <b>Delivered-To:</b> header upon
+ external forwarding, delivery to command or file.
+ Specify zero or more of: <b>command,</b> <b>file,</b> <b>forward</b>.
+ Turning off <b>Delivered-To:</b> when forwarding mail is
+ not recommended.
+
<b>recipient</b><i>_</i><b>delimiter</b>
Separator between username and address extension.
Limit the number of attempts to acquire an exclu-
sive lock on a mailbox or external file.
- <b>deliver</b><i>_</i><b>lock</b><i>_</i><b>delay</b>
- Time in seconds between successive attempts to
-
6
LOCAL(8) LOCAL(8)
+ <b>deliver</b><i>_</i><b>lock</b><i>_</i><b>delay</b>
+ Time in seconds between successive attempts to
acquire an exclusive lock.
<b>stale</b><i>_</i><b>lock</b><i>_</i><b>time</b>
Default rights for delivery to external file or
command.
-<b>HISTORY</b>
- The <b>Delivered-To:</b> header appears in the <b>qmail</b> system by
- Daniel Bernstein.
-
- The <i>maildir</i> structure appears in the <b>qmail</b> system by
- Daniel Bernstein.
+ <b>forward</b><i>_</i><b>expansion</b><i>_</i><b>filter</b>
+ What characters are allowed to appear in $name
+ expansions of forward_path. Illegal characters are
+ replaced by underscores.
LOCAL(8) LOCAL(8)
+<b>HISTORY</b>
+ The <b>Delivered-To:</b> header appears in the <b>qmail</b> system by
+ Daniel Bernstein.
+
+ The <i>maildir</i> structure appears in the <b>qmail</b> system by
+ Daniel Bernstein.
+
<b>SEE</b> <b>ALSO</b>
<a href="aliases.5.html">aliases(5)</a> format of alias database
<a href="bounce.8.html">bounce(8)</a> non-delivery status reports
-
-
-
-
-
-
-
postalias - Postfix alias database maintenance
<b>SYNOPSIS</b>
- <b>postalias</b> [<b>-c</b> <i>config_dir</i>] [<b>-i</b>] [<b>-v</b>] [<i>file_type</i>:]<i>file_name</i>
- ...
+ <b>postalias</b> [<b>-c</b> <i>config_dir</i>] [<b>-i</b>] [<b>-v</b>] [<b>-w</b>]
+ [<i>file_type</i>:]<i>file_name</i> ...
<b>DESCRIPTION</b>
The <b>postalias</b> command creates a new Postfix alias
postconf - Postfix configuration utility
<b>SYNOPSIS</b>
- <b>postconf</b> [<b>-d</b>] [<b>-h</b>] [<b>-n</b>] [<b>-v</b>] [<i>parameter</i> <i>...</i>]
+ <b>postconf</b> [<b>-c</b> <i>config_dir</i>] [<b>-d</b>] [<b>-h</b>] [<b>-n</b>] [<b>-v</b>] [<i>parameter</i>
+ <i>...</i>]
<b>DESCRIPTION</b>
- The <b>postconf</b> command prints the actual value of <i>parameter</i>
+ The <b>postconf</b> command prints the actual value of <i>parameter</i>
(all known parameters by default), one parameter per line.
Options:
+ <b>-c</b> <i>config_dir</i>
+ The <b>main.cf</b> configuration file is in the named
+ directory.
+
<b>-d</b> Print default parameter settings instead of actual
settings.
- <b>-h</b> Show parameter values only, not the <i>name</i> <i>=</i> informa-
- tion that normally precedes the value.
+ <b>-h</b> Show parameter values only, not the ``name =''
+ label that normally precedes the value.
<b>-n</b> Print non-default parameter settings only.
bose.
<b>DIAGNOSTICS</b>
- Problems are reported to the standard error stream.
+ Problems are reported to the standard error stream. Fatal
+ error: out of memory, file not found, invalid <b>main.cf</b>
+ parameter syntax.
<b>LICENSE</b>
The Secure Mailer license must be distributed with this
-
-
-
-
-
-
-
1
command interpreter.
<b>DIAGNOSTICS</b>
- The result status is 255 (on some systems: -1) when <b>post-</b>
- <b>lock</b> could not perform the requested operation. Other-
- wise, the exit status is the exit status from the command.
+ The result status is 75 (EX_TEMPFAIL) when the file is
+ locked by another process, 255 (on some systems: -1) when
+ <b>postlock</b> could not perform the requested operation. Oth-
+ erwise, the exit status is the exit status from the com-
+ mand.
<b>BUGS</b>
- With remote file systems, the ability to acquire a lock
- does not necessarily eliminate access conflicts. Avoid
+ With remote file systems, the ability to acquire a lock
+ does not necessarily eliminate access conflicts. Avoid
file access by processes running on different machines.
<b>ENVIRONMENT</b>
Enable verbose logging.
<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.
-
+ The following <b>main.cf</b> parameters are especially relevant
+ to this program. See the Postfix <b>main.cf</b> file for syntax
POSTLOCK(1) POSTLOCK(1)
+ details and for default values.
+
<b>Locking</b> <b>controls</b>
<b>deliver</b><i>_</i><b>lock</b><i>_</i><b>attempts</b>
- Limit the number of attempts to acquire an exclu-
+ Limit the number of attempts to acquire an exclu-
sive lock.
<b>deliver</b><i>_</i><b>lock</b><i>_</i><b>delay</b>
- Time in seconds between successive attempts to
+ Time in seconds between successive attempts to
acquire an exclusive lock.
<b>stale</b><i>_</i><b>lock</b><i>_</i><b>time</b>
<b>Resource</b> <b>controls</b>
<b>fork</b><i>_</i><b>attempts</b>
- Number of attempts to <b>fork</b>() a process before giv-
+ Number of attempts to <b>fork</b>() a process before giv-
ing up.
<b>fork</b><i>_</i><b>delay</b>
- Delay in seconds between successive <b>fork</b>()
+ Delay in seconds between successive <b>fork</b>()
attempts.
<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>
-
-
postmap - Postfix lookup table management
<b>SYNOPSIS</b>
- <b>postmap</b> [<b>-c</b> <i>config_dir</i>] [<b>-i</b>] [<b>-v</b>] [<i>file_type</i>:]<i>file_name</i>
+ <b>postmap</b> [<b>-c</b> <i>config_dir</i>] [<b>-i</b>] [<b>-v</b>] [<b>-w</b>]
+ [<i>file_type</i>:]<i>file_name</i>
<b>DESCRIPTION</b>
The <b>postmap</b> command creates a new Postfix lookup table, or
- updates an existing one. The input and output formats are
+ updates an existing one. The input and output formats are
expected to be compatible with:
<b>makemap</b> <i>file_type</i> <i>file_name</i> < <i>file_name</i>
- While the table update is in progress, signal delivery is
- postponed, and an exclusive, advisory, lock is placed on
+ While the table update is in progress, signal delivery is
+ postponed, and an exclusive, advisory, lock is placed on
the entire table, in order to avoid surprises in spectator
programs.
The format of a lookup table input file is as follows:
- <b>o</b> Blank lines are ignored. So are lines beginning
+ <b>o</b> Blank lines are ignored. So are lines beginning
with `#'.
<b>o</b> A table entry has the form
<i>key</i> whitespace <i>value</i>
- <b>o</b> A line that starts with whitespace continues the
+ <b>o</b> A line that starts with whitespace continues the
preceding line.
- The <i>key</i> and <i>value</i> are processed as is, except that sur-
- rounding white space is stripped off. Unlike with Postfix
- alias databases, quotes cannot be used to protect lookup
- keys that contain special characters such as `#' or
+ The <i>key</i> and <i>value</i> are processed as is, except that sur-
+ rounding white space is stripped off. Unlike with Postfix
+ alias databases, quotes cannot be used to protect lookup
+ keys that contain special characters such as `#' or
whitespace. The <i>key</i> is mapped to lowercase to make mapping
lookups case insensitive.
Options:
<b>-c</b> <i>config_dir</i>
- Read the <b>main.cf</b> configuration file in the named
+ Read the <b>main.cf</b> configuration file in the named
directory.
- <b>-i</b> Incremental mode. Read entries from standard input
+ <b>-i</b> Incremental mode. Read entries from standard input
and do not truncate an existing database. By
- default, <b>postmap</b> creates a new database from the
+ default, <b>postmap</b> creates a new database from the
entries in <b>file</b><i>_</i><b>name</b>.
<b>-v</b> Enable verbose logging for debugging purposes. Mul-
- tiple <b>-v</b> options make the software increasingly
+ tiple <b>-v</b> options make the software increasingly
verbose.
B-w Do not warn about duplicate entries; silently
- ignore them.
POSTMAP(1) POSTMAP(1)
+ ignore them.
+
Arguments:
<i>file_type</i>
The type of database to be produced.
- <b>btree</b> The output file is a btree file, named
- <i>file_name</i><b>.db</b>. This is available only on
+ <b>btree</b> The output file is a btree file, named
+ <i>file_name</i><b>.db</b>. This is available only on
systems with support for <b>db</b> databases.
- <b>dbm</b> The output consists of two files, named
- <i>file_name</i><b>.pag</b> and <i>file_name</i><b>.dir</b>. This is
- available only on systems with support for
+ <b>dbm</b> The output consists of two files, named
+ <i>file_name</i><b>.pag</b> and <i>file_name</i><b>.dir</b>. This is
+ available only on systems with support for
<b>dbm</b> databases.
- <b>hash</b> The output file is a hashed file, named
- <i>file_name</i><b>.db</b>. This is available only on
+ <b>hash</b> The output file is a hashed file, named
+ <i>file_name</i><b>.db</b>. This is available only on
systems with support for <b>db</b> databases.
- When no <i>file_type</i> is specified, the software uses
- the database type specified via the <b>database</b><i>_</i><b>type</b>
+ When no <i>file_type</i> is specified, the software uses
+ the database type specified via the <b>database</b><i>_</i><b>type</b>
configuration parameter.
<i>file_name</i>
- The name of the lookup table source file when
+ The name of the lookup table source file when
rebuilding a database.
<b>DIAGNOSTICS</b>
<b>CONFIGURATION</b> <b>PARAMETERS</b>
<b>database</b><i>_</i><b>type</b>
- Default output database type. On many UNIX sys-
- tems, the default database type is either <b>hash</b> or
+ Default output database type. On many UNIX sys-
+ tems, the default database type is either <b>hash</b> or
<b>dbm</b>.
<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
P.O. Box 704
+
+
+
+ 2
+
+
+
+
+
+POSTMAP(1) POSTMAP(1)
+
+
Yorktown Heights, NY 10598, USA
- 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 3
</pre> </body> </html>
<dd> <b>smtpd_recipient_restrictions = permit_mynetworks,
check_relay_domains</b>
+<dd> <b>smtpd_recipient_restrictions = permit_mynetworks,
+reject_unauth_destination</b>
+
<p>
<dt> Restrictions:
<p>
+<a name="reject_unauth_destination">
+
+<dt> <b>reject_unauth_destination</b> <dd> Ignore the client
+hostname. Permit the request when the resolved destination address
+matches <a href="#relay_domains"> $relay_domains</a>, otherwise
+reject. The <b>relay_domains_reject_code</b> parameter specifies
+the response code for rejected requests (default: <b>554</b>).
+
+<p>
+
<a name="permit_mx_backup">
<dt> <b>permit_mx_backup</b> <dd> Permit the request when the local
<dt> <b>relay_domains</b>
<dd> This parameter controls the behavior of the <a
-href="#check_relay_domains"> check_relay_domains</a> restriction
-that can appear as part of a recipient address restriction list.
+href="#check_relay_domains"> check_relay_domains</a> and a
+href="#reject_unauth_destination"> reject_unauth_destination</a>
+restrictions that can appear as part of a recipient address
+restriction list.
<p>
forward.o: ../include/iostuff.h
forward.o: ../include/stringops.h
forward.o: ../include/mail_proto.h
-forward.o: ../include/mail_queue.h
forward.o: ../include/cleanup_user.h
forward.o: ../include/sent.h
forward.o: ../include/record.h
local.o: ../include/name_mask.h
local.o: ../include/set_eugid.h
local.o: ../include/dict.h
-local.o: ../include/mail_queue.h
local.o: ../include/recipient_list.h
local.o: ../include/deliver_request.h
local.o: ../include/deliver_completed.h
/* Duplicate commands for the same recipient are suppressed.
/* A limited amount of information is exported via the environment:
/* HOME, SHELL, LOGNAME, USER, EXTENSION, DOMAIN, RECIPIENT (entire
-/* address) and LOCAL (just the local part). The exported
+/* address) LOCAL (just the local part) and SENDER. The exported
/* information is censored with var_cmd_filter.
/*
/* Arguments:
argv_add(env,
"LOGNAME", state.msg_attr.user,
"USER", state.msg_attr.user,
+ "SENDER", state.msg_attr.sender,
"RECIPIENT", state.msg_attr.recipient,
"LOCAL", state.msg_attr.local,
ARGV_END);
/* listed in a recipient's .forward file(s) as specified through
/* the forward_path configuration parameter. The result is
/* zero when no acceptable .forward file was found, or when
-/* a recipient is listed in her own .forward file.
+/* a recipient is listed in her own .forward file. Expansions
+/* are scrutinized with the forward_expansion_filter parameter.
/*
/* Arguments:
/* .IP state
MSG_LOG_STATE(myname, state);
/*
- * Skip this module if per-user forwarding is disabled.
+ * Skip this module if per-user forwarding is disabled.
*/
if (*var_forward_path == 0)
return (NO);
* these are the rights of root, the /file and |command delivery routines
* will use unprivileged default rights instead. Better safe than sorry.
*/
- SET_USER_ATTR(usr_attr, mypwd, state.level);
+ SET_USER_ATTR(usr_attr, mypwd, state.level);
/*
* DELIVERY POLICY
lookup_status = -1;
while ((lhs = mystrtok(&next, ", \t\r\n")) != 0) {
- expand_status = local_expand(path, lhs, &state, &usr_attr, (char *) 0);
+ expand_status = local_expand(path, lhs, &state, &usr_attr,
+ var_fwd_exp_filter);
if ((expand_status & (MAC_PARSE_ERROR | MAC_PARSE_UNDEF)) == 0) {
lookup_status =
lstat_as(STR(path), &st, usr_attr.uid, usr_attr.gid);
/* Global library. */
#include <mail_proto.h>
-#include <mail_queue.h>
#include <cleanup_user.h>
#include <sent.h>
#include <record.h>
/* \fB$recipient_delimiter.\fR The forms \fI${name?value}\fR and
/* \fI${name:value}\fR expand conditionally to \fIvalue\fR when
/* \fI$name\fR is (is not) defined.
+/* Characters that may have special meaning to the shell or file system
+/* are replaced by underscores. The list of acceptable characters
+/* is specified with the \fBforward_expansion_filter\fR configuration
/*
/* An alias or ~/.\fBforward\fR file may list any combination of external
/* commands, destination file names, \fB:include:\fR directives, or
/* a new message, so that each recipient has a separate on-file
/* delivery status record.
/*
-/* In order to stop mail forwarding loops early, the software adds a
+/* In order to stop mail forwarding loops early, the software adds an
+/* optional
/* \fBDelivered-To:\fR header with the envelope recipient address. If
/* mail arrives for a recipient that is already listed in a
/* \fBDelivered-To:\fR header, the message is bounced.
/* /some/where/smrsh -c).
/* When a shell is specified, it is invoked even when the command
/* contains no shell built-in commands or meta characters.
+/* .IP \fBowner_request_special\fR
+/* Give special treatment to \fBowner-\fIxxx\fR and \fIxxx\fB-request\fR
+/* addresses.
/* .IP \fBprepend_delivered_header\fR
/* Prepend an optional \fBDelivered-To:\fR header upon external
/* forwarding, delivery to command or file. Specify zero or more of:
/* \fBcommand, file, forward\fR. Turning off \fBDelivered-To:\fR when
/* forwarding mail is not recommended.
-/* .IP \fBowner_request_special\fR
-/* Give special treatment to \fBowner-\fIxxx\fR and \fIxxx\fB-request\fR
-/* addresses.
/* .IP \fBrecipient_delimiter\fR
/* Separator between username and address extension.
/* .SH Mailbox delivery
/* mailbox_command. Illegal characters are replaced by underscores.
/* .IP \fBdefault_privs\fR
/* Default rights for delivery to external file or command.
+/* .IP \fBforward_expansion_filter\fR
+/* What characters are allowed to appear in $name expansions of
+/* forward_path. Illegal characters are replaced by underscores.
/* HISTORY
/* .ad
/* .fi
/* Global library. */
-#include <mail_queue.h>
#include <recipient_list.h>
#include <deliver_request.h>
#include <deliver_completed.h>
char *var_fallback_transport;
char *var_forward_path;
char *var_cmd_exp_filter;
+char *var_fwd_exp_filter;
char *var_prop_extension;
int var_exp_own_alias;
char *var_deliver_hdr;
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 =
- mail_queue_open(rqst->queue_name, rqst->queue_id, O_RDWR, 0);
- if (state.msg_attr.fp == 0)
- msg_fatal("open file %s %s: %m", rqst->queue_name, rqst->queue_id);
- close_on_exec(vstream_fileno(state.msg_attr.fp), CLOSE_ON_EXEC);
+ state.msg_attr.fp = rqst->fp;
state.msg_attr.offset = rqst->data_offset;
state.msg_attr.sender = rqst->sender;
state.msg_attr.relay = service;
* Clean up.
*/
delivered_free(state.loop_info);
- vstream_fclose(state.msg_attr.fp);
return (msg_stat);
}
VAR_MAILBOX_TRANSP, DEF_MAILBOX_TRANSP, &var_mailbox_transport, 0, 0,
VAR_FALLBACK_TRANSP, DEF_FALLBACK_TRANSP, &var_fallback_transport, 0, 0,
VAR_CMD_EXP_FILTER, DEF_CMD_EXP_FILTER, &var_cmd_exp_filter, 1, 0,
+ VAR_FWD_EXP_FILTER, DEF_FWD_EXP_FILTER, &var_fwd_exp_filter, 1, 0,
VAR_PROP_EXTENSION, DEF_PROP_EXTENSION, &var_prop_extension, 0, 0,
VAR_DELIVER_HDR, DEF_DELIVER_HDR, &var_deliver_hdr, 0, 0,
0,
#define STREQ(x,y) (*(x) == *(y) && strcmp((x), (y)) == 0)
if (STREQ(name, "user")) {
- return (local->usr_attr->logname);
+ return (local->state->msg_attr.user);
} else if (STREQ(name, "home")) {
return (local->usr_attr->home);
} else if (STREQ(name, "shell")) {
RANLIB=echo
SYSLIBS="-lresolv -lsocket -lnsl"
case $RELEASE in
- 5.[0-4]) CCARGS="$CCARGS -Dusleep=doze";;
+ 5.[0-4]) CCARGS="$CCARGS -DMISSING_USLEEP";;
*) CCARGS="$CCARGS -DHAS_POSIX_REGEXP";;
esac
# Avoid common types of braindamage
;;
HP-UX.A.09.*) SYSTYPE=HPUX9
SYSLIBS=-ldbm
- CCARGS="$CCARGS -Dusleep=doze"
+ CCARGS="$CCARGS -DMISSING_USLEEP"
if [ -f /usr/lib/libdb.a ]; then
CCARGS="$CCARGS -DHAS_DB"
SYSLIBS="$SYSLIBS -ldb"
;;
HP-UX.B.10.*) SYSTYPE=HPUX10
CCARGS="$CCARGS `nm /usr/lib/libc.a 2>/dev/null |
- (grep usleep >/dev/null || echo '-Dusleep=doze')`"
+ (grep usleep >/dev/null || echo '-DMISSING_USLEEP')`"
if [ -f /usr/lib/libdb.a ]; then
CCARGS="$CCARGS -DHAS_DB"
SYSLIBS=-ldb
SYSLIBS="-lresolv -lsocket -lnsl"
;;
Rhapsody.5*) SYSTYPE=RHAPSODY5
+ # Use the native compiler by default
+ : ${CC=cc}
+ AWK=gawk
;;
".") if [ -d /NextApps ]; then
SYSTYPE=`hostinfo | sed -n \
SYSTYPE=`hostinfo | sed -n \
's/^.*NeXT Mach 4.*$/OPENSTEP4/;/OPENSTEP4/{p;q;}'`
fi
+ : ${CC=cc}
RANLIB="sleep 5; ranlib"
else
echo "Unable to determine your system type." 1>&2; exit 1
*) : ${OPT='-O'};;
esac
-: ${CC='gcc $(WARN)'} ${OPT='-O'} ${DEBUG='-g'}
+: ${CC='gcc $(WARN)'} ${OPT='-O'} ${DEBUG='-g'} ${AWK=awk}
-export SYSTYPE AR ARFL RANLIB SYSLIBS CC OPT DEBUG OPTS
+export SYSTYPE AR ARFL RANLIB SYSLIBS CC OPT DEBUG AWK OPTS
sed 's/ / /g' <<EOF
SYSTYPE = $SYSTYPE
CC = $CC $CCARGS
OPT = $OPT
DEBUG = $DEBUG
+AWK = $AWK
EOF
.nf
.fi
\fBpostalias\fR [\fB-c \fIconfig_dir\fR] [\fB-i\fR] [\fB-v\fR]
-[\fIfile_type\fR:]\fIfile_name\fR ...
+[\fB-w\fR] [\fIfile_type\fR:]\fIfile_name\fR ...
.SH DESCRIPTION
.ad
.fi
.na
.nf
.fi
-\fBpostconf\fR [\fB-d\fR] [\fB-h\fR] [\fB-n\fR] [\fB-v\fR]
-[\fIparameter ...\fR]
+\fBpostconf\fR [\fB-c \fIconfig_dir\fR] [\fB-d\fR] [\fB-h\fR]
+[\fB-n\fR] [\fB-v\fR] [\fIparameter ...\fR]
.SH DESCRIPTION
.ad
.fi
parameter per line.
Options:
+.IP "\fB-c \fIconfig_dir\fR"
+The \fBmain.cf\fR configuration file is in the named directory.
.IP \fB-d\fR
Print default parameter settings instead of actual settings.
.IP \fB-h\fR
-Show parameter values only, not the \fIname =\fR information
+Show parameter values only, not the ``name ='' label
that normally precedes the value.
.IP \fB-n\fR
Print non-default parameter settings only.
.ad
.fi
Problems are reported to the standard error stream.
+Fatal error: out of memory, file not found, invalid \fBmain.cf\fR
+parameter syntax.
.SH LICENSE
.na
.nf
.SH DIAGNOSTICS
.ad
.fi
-The result status is 255 (on some systems: -1) when \fBpostlock\fR
+The result status is 75 (EX_TEMPFAIL) when the file is locked by
+another process, 255 (on some systems: -1) when \fBpostlock\fR
could not perform the requested operation. Otherwise, the
exit status is the exit status from the command.
.SH BUGS
.nf
.fi
\fBpostmap\fR [\fB-c \fIconfig_dir\fR] [\fB-i\fR] [\fB-v\fR]
-[\fIfile_type\fR:]\fIfile_name\fR
+[\fB-w\fR] [\fIfile_type\fR:]\fIfile_name\fR
.SH DESCRIPTION
.ad
.fi
.SH Miscellaneous
.ad
.fi
+.IP \fBalways_bcc\fR
+Address to send a copy of each message that enters the system.
.IP \fBhopcount_limit\fR
Limit the number of \fBReceived:\fR message headers.
.SH "Address transformations"
\fB$recipient_delimiter.\fR The forms \fI${name?value}\fR and
\fI${name:value}\fR expand conditionally to \fIvalue\fR when
\fI$name\fR is (is not) defined.
+Characters that may have special meaning to the shell or file system
+are replaced by underscores. The list of acceptable characters
+is specified with the \fBforward_expansion_filter\fR configuration
An alias or ~/.\fBforward\fR file may list any combination of external
commands, destination file names, \fB:include:\fR directives, or
a new message, so that each recipient has a separate on-file
delivery status record.
-In order to stop mail forwarding loops early, the software adds a
+In order to stop mail forwarding loops early, the software adds an
+optional
\fBDelivered-To:\fR header with the envelope recipient address. If
mail arrives for a recipient that is already listed in a
\fBDelivered-To:\fR header, the message is bounced.
/some/where/smrsh -c).
When a shell is specified, it is invoked even when the command
contains no shell built-in commands or meta characters.
+.IP \fBowner_request_special\fR
+Give special treatment to \fBowner-\fIxxx\fR and \fIxxx\fB-request\fR
+addresses.
.IP \fBprepend_delivered_header\fR
Prepend an optional \fBDelivered-To:\fR header upon external
forwarding, delivery to command or file. Specify zero or more of:
\fBcommand, file, forward\fR. Turning off \fBDelivered-To:\fR when
forwarding mail is not recommended.
-.IP \fBowner_request_special\fR
-Give special treatment to \fBowner-\fIxxx\fR and \fIxxx\fB-request\fR
-addresses.
.IP \fBrecipient_delimiter\fR
Separator between username and address extension.
.SH Mailbox delivery
mailbox_command. Illegal characters are replaced by underscores.
.IP \fBdefault_privs\fR
Default rights for delivery to external file or command.
+.IP \fBforward_expansion_filter\fR
+What characters are allowed to appear in $name expansions of
+forward_path. Illegal characters are replaced by underscores.
.SH HISTORY
.na
.nf
struct stat st; /* queue file status */
char *path; /* name for open/remove */
char *sender; /* sender address */
+ char *rcpt; /* recipient address */
} PICKUP_INFO;
/*
if (type == REC_TYPE_FROM)
if (info->sender == 0)
info->sender = mystrdup(vstring_str(buf));
+ if (type == REC_TYPE_RCPT)
+ if (info->rcpt == 0)
+ info->rcpt = mystrdup(vstring_str(buf));
if (type == REC_TYPE_TIME)
continue;
else {
* Copy the message envelope segment. Allow only those records that we
* expect to see in the envelope section. The envelope segment must
* contain an envelope sender address.
+ *
+ * If the segment contains a recipient address, include the optional
+ * always_bcc recipient.
*/
info->sender = 0;
+ info->rcpt = 0;
if ((status = copy_segment(qfile, cleanup, info, buf, REC_TYPE_ENVELOPE)) != 0)
return (status);
if (info->sender == 0) {
(int) info->st.st_uid, info->sender);
myfree(info->sender);
- if (*var_always_bcc)
- rec_fputs(cleanup, REC_TYPE_RCPT, var_always_bcc);
+ if (info->rcpt) {
+ if (*var_always_bcc)
+ rec_fputs(cleanup, REC_TYPE_RCPT, var_always_bcc);
+ myfree(info->rcpt);
+ }
/*
* Message content segment. Send a dummy message length. Prepend a
pipe.o: ../include/stringops.h
pipe.o: ../include/recipient_list.h
pipe.o: ../include/deliver_request.h
-pipe.o: ../include/mail_queue.h
pipe.o: ../include/mail_params.h
pipe.o: ../include/mail_conf.h
pipe.o: ../include/bounce.h
#include <recipient_list.h>
#include <deliver_request.h>
-#include <mail_queue.h>
#include <mail_params.h>
#include <mail_conf.h>
#include <bounce.h>
char *myname = "deliver_message";
static PIPE_PARAMS conf;
static PIPE_ATTR attr;
- VSTREAM *src;
RECIPIENT_LIST *rcpt_list = &request->rcpt_list;
VSTRING *why = vstring_alloc(100);
VSTRING *buf;
get_service_attr(&attr, argv);
}
- /*
- * Open the queue file. Opening the file can fail for a variety of
- * reasons, such as the system running out of resources. Instead of
- * throwing away mail, we're raising a fatal error which forces the mail
- * system to back off, and retry later. XXX deliver_request() should
- * pre-open the queue file while it does all its sanity checks.
- */
- src = mail_queue_open(request->queue_name, request->queue_id, O_RDWR, 0);
- if (src == 0)
- msg_fatal("%s: open %s %s: %m", myname,
- request->queue_name, request->queue_id);
- if (msg_verbose)
- msg_info("%s: file %s", myname, VSTREAM_PATH(src));
- close_on_exec(vstream_fileno(src), CLOSE_ON_EXEC);
-
/*
* Deliver. Set the nexthop and sender variables, and expand the command
* argument vector. Recipients will be expanded on the fly. XXX Rewrite
* envelope and header addresses according to transport-specific
* rewriting rules.
*/
- if (vstream_fseek(src, request->data_offset, SEEK_SET) < 0)
- msg_fatal("seek queue file %s: %m", VSTREAM_PATH(src));
+ if (vstream_fseek(request->fp, request->data_offset, SEEK_SET) < 0)
+ msg_fatal("seek queue file %s: %m", VSTREAM_PATH(request->fp));
dict_update(PIPE_DICT_TABLE, PIPE_DICT_SENDER, request->sender);
dict_update(PIPE_DICT_TABLE, PIPE_DICT_NEXTHOP, request->nexthop);
expanded_argv = expand_argv(attr.command, rcpt_list);
- command_status = pipe_command(src, why,
+ command_status = pipe_command(request->fp, why,
PIPE_CMD_UID, attr.uid,
PIPE_CMD_GID, attr.gid,
PIPE_CMD_SENDER, request->sender,
PIPE_CMD_END);
deliver_status = eval_command_status(command_status, service, request,
- src, vstring_str(why));
+ request->fp, vstring_str(why));
/*
* Clean up.
*/
- if (vstream_fclose(src))
- msg_warn("close %s %s: %m", request->queue_name, request->queue_id);
-
vstring_free(why);
argv_free(expanded_argv);
/* SYNOPSIS
/* .fi
/* \fBpostalias\fR [\fB-c \fIconfig_dir\fR] [\fB-i\fR] [\fB-v\fR]
-/* [\fIfile_type\fR:]\fIfile_name\fR ...
+/* [\fB-w\fR] [\fIfile_type\fR:]\fIfile_name\fR ...
/* DESCRIPTION
/* The \fBpostalias\fR command creates a new Postfix alias database,
/* or updates an existing one. The input and output file formats
cp $(PROG) ../bin
$(MAKES): $(INC_DIR)/mail_params.h
- sh extract.sh ../*/*.c
+ $(AWK) -f extract.awk ../*/*.c
printfck: $(OBJS) $(PROG)
rm -rf printfck
-#!/bin/sh
-
# Extract initialization tables from actual source code.
-awk '
/static CONFIG_INT_TABLE/,/};/ {
if ($1 ~ /VAR/) {
print "int " substr($3,2,length($3)-2) ";" > "int_vars.h"
print | "sort -u >bool_table.h"
}
}
-' $*
/* Postfix configuration utility
/* SYNOPSIS
/* .fi
-/* \fBpostconf\fR [\fB-d\fR] [\fB-h\fR] [\fB-n\fR] [\fB-v\fR]
-/* [\fIparameter ...\fR]
+/* \fBpostconf\fR [\fB-c \fIconfig_dir\fR] [\fB-d\fR] [\fB-h\fR]
+/* [\fB-n\fR] [\fB-v\fR] [\fIparameter ...\fR]
/* DESCRIPTION
/* The \fBpostconf\fR command prints the actual value of
/* \fIparameter\fR (all known parameters by default), one
/* parameter per line.
/*
/* Options:
+/* .IP "\fB-c \fIconfig_dir\fR"
+/* The \fBmain.cf\fR configuration file is in the named directory.
/* .IP \fB-d\fR
/* Print default parameter settings instead of actual settings.
/* .IP \fB-h\fR
-/* Show parameter values only, not the \fIname =\fR information
+/* Show parameter values only, not the ``name ='' label
/* that normally precedes the value.
/* .IP \fB-n\fR
/* Print non-default parameter settings only.
/* options make the software increasingly verbose.
/* DIAGNOSTICS
/* Problems are reported to the standard error stream.
+/* Fatal error: out of memory, file not found, invalid \fBmain.cf\fR
+/* parameter syntax.
/* LICENSE
/* .ad
/* .fi
show_strval(mode, cbt->name, cbt->defval ? "yes" : "no");
} else {
value = dict_lookup(CONFIG_DICT, cbt->name);
+ if (value)
+ (void) get_mail_conf_bool(cbt->name, cbt->defval);
if ((mode & SHOW_NONDEF) == 0) {
if (value == 0) {
show_strval(mode, cbt->name, cbt->defval ? "yes" : "no");
show_intval(mode, cit->name, cit->defval);
} else {
value = dict_lookup(CONFIG_DICT, cit->name);
+ if (value)
+ (void) get_mail_conf_int(cit->name, cit->defval, cit->min, cit->max);
if ((mode & SHOW_NONDEF) == 0) {
if (value == 0) {
show_intval(mode, cit->name, cit->defval);
show_strval(mode, cst->name, cst->defval);
} else {
value = dict_lookup(CONFIG_DICT, cst->name);
+ if (value)
+ (void) get_mail_conf_str(cst->name, cst->defval, cst->min, cst->max);
if ((mode & SHOW_NONDEF) == 0) {
if (value == 0) {
show_strval(mode, cst->name, cst->defval);
/*
* Parse JCL.
*/
- while ((ch = GETOPT(argc, argv, "dhnv")) > 0) {
+ while ((ch = GETOPT(argc, argv, "c:dhnv")) > 0) {
switch (ch) {
+ case 'c':
+ if (setenv(CONF_ENV_PATH, optarg, 1) < 0)
+ msg_fatal("out of memory");
+ break;
case 'd':
if (mode & SHOW_NONDEF)
msg_fatal("specify one of -d and -n");
msg_verbose++;
break;
default:
- msg_fatal("usage: %s [-d (defaults)] [-h (no names)] [-n (non-defaults)] [-v] name...", argv[0]);
+ msg_fatal("usage: %s [-c config_directory] [-d (defaults)] [-h (no names)] [-n (non-defaults)] [-v] name...", argv[0]);
}
}
/* access. The command is executed directly, i.e. without
/* interpretation by a shell command interpreter.
/* DIAGNOSTICS
-/* The result status is 255 (on some systems: -1) when \fBpostlock\fR
+/* The result status is 75 (EX_TEMPFAIL) when the file is locked by
+/* another process, 255 (on some systems: -1) when \fBpostlock\fR
/* could not perform the requested operation. Otherwise, the
/* exit status is the exit status from the command.
/* BUGS
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
+#include <errno.h>
+#include <sysexits.h>
/* Utility library. */
msg_fatal("usage: %s [-c config_dir] [-v] folder command...", myname);
}
-/* fatal_exit - as promised, return 255 in case of locking problems */
+/* fatal_exit - as promised, return 255 in case of unexpected problems */
static void fatal_exit(void)
{
close_on_exec(fd, CLOSE_ON_EXEC);
why = vstring_alloc(1);
#ifdef USE_DOT_LOCK
- if (dot_lockfile(folder, why) < 0)
+ if (dot_lockfile(folder, why) < 0) {
+ if (errno == EEXIST) {
+ msg_warn("dotlock file %s: %s", folder, vstring_str(why));
+ exit(EX_TEMPFAIL);
+ }
msg_fatal("dotlock file %s: %s", folder, vstring_str(why));
+ }
#endif
- if (deliver_flock(fd, why) < 0)
+ if (deliver_flock(fd, why) < 0) {
+ if (errno == EAGAIN) {
+ msg_warn("lock %s: %s", folder, vstring_str(why));
+#ifdef USE_DOT_LOCK
+ dot_unlockfile(folder);
+#endif
+ exit(EX_TEMPFAIL);
+ }
msg_fatal("lock %s: %s", folder, vstring_str(why));
+ }
/*
* Run the command. Remove the lock after completion.
/* SYNOPSIS
/* .fi
/* \fBpostmap\fR [\fB-c \fIconfig_dir\fR] [\fB-i\fR] [\fB-v\fR]
-/* [\fIfile_type\fR:]\fIfile_name\fR
+/* [\fB-w\fR] [\fIfile_type\fR:]\fIfile_name\fR
/* DESCRIPTION
/* The \fBpostmap\fR command creates a new Postfix lookup table,
/* or updates an existing one. The input and output formats are
QMGR_RCPT_LIST rcpt_list; /* complete addresses */
};
+#define QMGR_MESSAGE_LOCKED ((QMGR_MESSAGE *) 1)
+
extern int qmgr_message_count;
extern int qmgr_recipient_count;
extern MAPS *qmgr_relocated;
}
}
+/* qmgr_active_defer - defer queue file */
+
+static void qmgr_active_defer(QMGR_MESSAGE *message, time_t delay)
+{
+ char *myname = "qmgr_active_defer";
+ const char *path;
+ struct utimbuf tbuf;
+
+ if (msg_verbose)
+ msg_info("wakeup %s after %ld secs", message->queue_id, (long) delay);
+
+ tbuf.actime = tbuf.modtime = event_time() + delay;
+ path = mail_queue_path((VSTRING *) 0, message->queue_name,
+ message->queue_id);
+ if (utime(path, &tbuf) < 0)
+ msg_fatal("%s: update %s time stamps: %m", myname, path);
+ if (mail_queue_rename(message->queue_id, message->queue_name,
+ MAIL_QUEUE_DEFERRED)) {
+ if (errno != ENOENT)
+ msg_fatal("%s: rename %s from %s to %s: %m", myname,
+ message->queue_id, message->queue_name, MAIL_QUEUE_DEFERRED);
+ msg_warn("%s: rename %s from %s to %s: %m", myname,
+ message->queue_id, message->queue_name, MAIL_QUEUE_DEFERRED);
+ } else if (msg_verbose) {
+ msg_info("%s: defer %s", myname, message->queue_id);
+ }
+}
+
/* qmgr_active_feed - feed one message into active queue */
void qmgr_active_feed(QMGR_SCAN *scan_info, const char *queue_id)
return;
}
- /*
- * Reset the defer log. Leave the bounce log alone; if it is still
- * around, something did not send it previously.
- */
- if (mail_queue_remove(MAIL_QUEUE_DEFER, queue_id) && errno != ENOENT)
- msg_fatal("%s: %s: remove %s %s: %m", myname,
- queue_id, MAIL_QUEUE_DEFER, queue_id);
-
/*
* Extract envelope information: sender and recipients. At this point,
* mail addresses have been processed by the cleanup service so they
* Throwing away queue files seems bad, especially when they made it this
* far into the mail system. Therefore we save bad files to a separate
* directory for further inspection.
+ *
+ * After queue manager restart it is possible that a queue file is still
+ * being delivered. In that case (the file is locked), defer delivery by
+ * a minimal amount of time.
*/
if ((message = qmgr_message_alloc(MAIL_QUEUE_ACTIVE, queue_id,
scan_info->flags)) == 0) {
qmgr_active_corrupt(queue_id);
+ } else if (message == QMGR_MESSAGE_LOCKED) {
+ qmgr_active_defer(message, (time_t) var_min_backoff_time);
} else {
+
+ /*
+ * Reset the defer log. Leave the bounce log alone; if it is still
+ * around, something did not send it previously.
+ */
+ if (mail_queue_remove(MAIL_QUEUE_DEFER, queue_id) && errno != ENOENT)
+ msg_fatal("%s: %s: remove %s %s: %m", myname,
+ queue_id, MAIL_QUEUE_DEFER, queue_id);
+
+ /*
+ * Special case if all recipients were already delivered. Send any
+ * bounces and clean up.
+ */
if (message->refcount == 0)
qmgr_active_done(message);
}
char *myname = "qmgr_active_done";
struct stat st;
const char *path;
- struct utimbuf tbuf;
time_t delay;
if (msg_verbose)
if (msg_verbose)
msg_info("%s: sending defer warning for %s", myname, message->queue_id);
if (defer_warn(BOUNCE_FLAG_KEEP,
- message->queue_name,
- message->queue_id,
- message->errors_to) == 0) {
+ message->queue_name,
+ message->queue_id,
+ message->errors_to) == 0) {
qmgr_message_update_warn(message);
}
}
} else {
delay = var_min_backoff_time;
}
- if (msg_verbose)
- msg_info("wakeup %s after %ld secs", message->queue_id, delay);
- tbuf.actime = tbuf.modtime = event_time() + delay;
- path = mail_queue_path((VSTRING *) 0, message->queue_name,
- message->queue_id);
- if (utime(path, &tbuf) < 0)
- msg_fatal("%s: update %s time stamps: %m", myname, path);
- if (mail_queue_rename(message->queue_id, message->queue_name,
- MAIL_QUEUE_DEFERRED)) {
- if (errno != ENOENT)
- msg_fatal("%s: rename %s from %s to %s: %m", myname,
- message->queue_id, message->queue_name, MAIL_QUEUE_DEFERRED);
- msg_warn("%s: rename %s from %s to %s: %m", myname,
- message->queue_id, message->queue_name, MAIL_QUEUE_DEFERRED);
- } else if (msg_verbose) {
- msg_info("%s: defer %s", myname, message->queue_id);
- }
+ qmgr_active_defer(message, delay);
}
/*
/* qmgr_message_alloc() creates an in-core message structure
/* with sender and recipient information taken from the named queue
/* file. A null result means the queue file could not be read or
-/* that the queue file contained incorrect information. The number
+/* that the queue file contained incorrect information. A result
+/* QMGR_MESSAGE_LOCKED means delivery must be deferred. The number
/* of recipients read from a queue file is limited by the global
/* var_qmgr_rcpt_limit configuration parameter. When the limit
/* is reached, the \fIrcpt_offset\fR structure member is set to
/* the position where the read was terminated. Recipients are
-/* ru through the resolver, and are assigned to destination
+/* run through the resolver, and are assigned to destination
/* queues. Recipients that cannot be assigned are deferred or
/* bounced. Mail that has bounced twice is silently absorbed.
/*
#include <valid_hostname.h>
#include <argv.h>
#include <stringops.h>
+#include <myflock.h>
/* Global library. */
* Extract message envelope information: time of arrival, sender address,
* recipient addresses. Skip files with malformed envelope information.
*/
+#define QMGR_LOCK_MODE (MYFLOCK_EXCLUSIVE | MYFLOCK_NOWAIT)
+
if (qmgr_message_open(message) < 0) {
qmgr_message_free(message);
return (0);
}
+ if (myflock(vstream_fileno(message->fp), QMGR_LOCK_MODE) < 0) {
+ qmgr_message_close(message);
+ qmgr_message_free(message);
+ return (QMGR_MESSAGE_LOCKED);
+ }
if (qmgr_message_read(message) < 0) {
qmgr_message_close(message);
qmgr_message_free(message);
msg_syslog_init(mail_task("sendmail"), LOG_PID, LOG_FACILITY);
set_mail_conf_str(VAR_PROCNAME, var_procname = mystrdup(argv[0]));
+ /*
+ * Do not set[e]uid(getuid()). This allows the real user to manipulate
+ * the process, which is dangerous, because some systems do not reset the
+ * saved set-userid unless euid == 0.
+ */
+#ifdef WARN_SETXID_SENDMAIL
+ if (geteuid() != getuid())
+ msg_warn("sendmail is set-uid or is run from a set-uid process");
+ if (getegid() != getgid())
+ msg_warn("sendmail is set-gid or is run from a set-gid process");
+#endif
+
mail_conf_read();
if (chdir(var_queue_dir))
msg_fatal("chdir %s: %m", var_queue_dir);
argv_add(ext_argv, "-v", (char *) 0);
argv_add(ext_argv, "start", (char *) 0);
argv_terminate(ext_argv);
- err = mail_run_background(var_command_dir, ext_argv->argv);
+ err = (mail_run_background(var_command_dir, ext_argv->argv) < 0);
argv_free(ext_argv);
exit(err);
break;
msg_warn("close file %s %s: %m", *queue, id);
} else if (strcmp(*queue, MAIL_QUEUE_MAILDROP) == 0) {
queue_size += st.st_size;
- vstream_fprintf(client, DATA_FORMAT, id, (long) st.st_size,
+ vstream_fprintf(client, DATA_FORMAT, id, ' ',
+ (long) st.st_size,
asctime(localtime(&st.st_mtime)),
"(to be determined)");
} else if (errno != ENOENT)
smtp.o: ../include/deliver_request.h
smtp.o: ../include/vstring.h
smtp.o: ../include/recipient_list.h
-smtp.o: ../include/mail_queue.h
smtp.o: ../include/mail_params.h
smtp.o: ../include/mail_conf.h
smtp.o: ../include/debug_peer.h
/* Global library. */
#include <deliver_request.h>
-#include <mail_queue.h>
#include <mail_params.h>
#include <mail_conf.h>
#include <debug_peer.h>
why = vstring_alloc(100);
state = smtp_state_alloc();
state->request = request;
-
- /*
- * Open the queue file. Opening the file can fail for a variety of
- * reasons, such as the system running out of resources. Instead of
- * throwing away mail, we're raising a fatal error which forces the mail
- * system to back off, and retry later.
- */
- state->src = mail_queue_open(request->queue_name, request->queue_id,
- O_RDWR, 0);
- if (state->src == 0)
- msg_fatal("%s: open %s %s: %m", myname,
- request->queue_name, request->queue_id);
- if (msg_verbose)
- msg_info("%s: file %s", myname, VSTREAM_PATH(state->src));
+ state->src = request->fp;
/*
* Establish an SMTP session and deliver this message to all requested
/*
* Clean up.
*/
- if (vstream_fclose(state->src))
- msg_warn("close %s %s: %m", request->queue_name, request->queue_id);
vstring_free(why);
smtp_chat_reset(state);
result = state->status;
DNS_RR *mx_names;
DNS_RR *addr_list = 0;
DNS_RR *self;
+ unsigned best_pref;
+ unsigned best_found;
/*
* Sanity check.
break;
case DNS_OK:
mx_names = dns_rr_sort(mx_names, smtp_compare_mx);
+ best_pref = (mx_names ? mx_names->pref : ~0);
addr_list = smtp_addr_list(mx_names, why);
dns_rr_free(mx_names);
+ best_found = (addr_list ? addr_list->pref : ~0);
if (*var_fallback_relay)
addr_list = smtp_addr_fallback(addr_list);
if (msg_verbose)
smtp_print_addr(name, addr_list);
if ((self = smtp_find_self(addr_list)) != 0)
addr_list = smtp_truncate_self(addr_list, self->pref, name, why);
+ if (addr_list == 0 && best_pref < best_found) {
+ vstring_sprintf(why, "unable to find primary mail relay for %s",
+ name);
+ smtp_errno = SMTP_RETRY;
+ }
break;
case DNS_NOTFOUND:
addr_list = smtp_host_addr(name, why);
break;
}
msg_info("%s; address %s port %d", vstring_str(why),
- inet_ntoa(*((struct in_addr *) addr->data)), port);
+ inet_ntoa(*((struct in_addr *) addr->data)), ntohs(port));
}
dns_rr_free(addr_list);
return (session);
if (n == 0 && strcasecmp(word, var_myhostname) == 0) {
msg_warn("host %s greeted me with my own hostname %s",
session->namaddr, var_myhostname);
- return (smtp_site_fail(state, session->best ? 550 : 450,
- "mail for %s loops back to myself",
- request->nexthop));
} else if (strcasecmp(word, "ESMTP") == 0)
state->features |= SMTP_FEATURE_ESMTP;
}
* advertises a really huge message size limit.
*/
lines = resp->str;
- (void) mystrtok(&lines, "\n");
while ((words = mystrtok(&lines, "\n")) != 0) {
if (mystrtok(&words, "- ") && (word = mystrtok(&words, " \t")) != 0) {
if (strcasecmp(word, "8BITMIME") == 0)
state->features |= SMTP_FEATURE_PIPELINING;
else if (strcasecmp(word, "SIZE") == 0)
state->features |= SMTP_FEATURE_SIZE;
+ else if (strcasecmp(word, var_myhostname) == 0) {
+ msg_warn("host %s replied to HELO/EHLO with my own hostname %s",
+ session->namaddr, var_myhostname);
+ return (smtp_site_fail(state, session->best ? 550 : 450,
+ "mail for %s loops back to myself",
+ request->nexthop));
+ }
}
}
if (msg_verbose)
/* parameter. Reject the request otherwise.
/* The \fIrelay_domains_reject_code\fR configuration parameter specifies
/* the reject status code (default: 554).
+/* .IP reject_unauth_destination
+/* Allow the request when the resolved recipient domain matches the
+/* \fIrelay_domains\fR configuration parameter. Reject the request
+/* otherwise. Same error code as check_relay_domains.
/* .IP permit_mx_backup
/* Allow the request when the local mail system is mail exchanger
/* for the recipient domain (this includes the case where the local
* postmaster notices, this may be the only trace left that service was
* rejected. Print the request, client name/address, and response.
*/
- msg_info(state->recipient ? "reject: %s from %s: %s; from=<%s> to=<%s>"
- : state->sender ? "reject: %s from %s: %s; from=<%s>"
- : "reject: %s from %s: %s",
- state->where, state->namaddr, STR(error_text),
- state->sender, state->recipient);
+ if (state->recipient && state->sender) {
+ msg_info("reject: %s from %s: %s; from=<%s> to=<%s>",
+ state->where, state->namaddr, STR(error_text),
+ state->sender, state->recipient);
+ } else if (state->recipient) {
+ msg_info("reject: %s from %s: %s; to=<%s>",
+ state->where, state->namaddr, STR(error_text),
+ state->recipient);
+ } else if (state->sender) {
+ msg_info("reject: %s from %s: %s; from=<%s>",
+ state->where, state->namaddr, STR(error_text),
+ state->sender);
+ } else {
+ msg_info("reject: %s from %s: %s",
+ state->where, state->namaddr, STR(error_text));
+ }
return (SMTPD_CHECK_REJECT);
}
var_relay_code, reply_name, reply_class));
}
+/* reject_unauth_destination - FAIL for message relaying */
+
+static int reject_unauth_destination(SMTPD_STATE *state, char *recipient)
+{
+ char *myname = "reject_unauth_destination";
+ char *domain;
+
+ if (msg_verbose)
+ msg_info("%s: %s", myname, recipient);
+
+ /*
+ * Resolve the address.
+ */
+ canon_addr_internal(query, recipient);
+ resolve_clnt_query(STR(query), &reply);
+
+ /*
+ * Permit if destination is local. XXX This must be generalized for
+ * per-domain user tables and for non-UNIX local delivery agents.
+ */
+ if (STR(reply.nexthop)[0] == 0
+ || (domain = strrchr(STR(reply.recipient), '@')) == 0)
+ return (SMTPD_CHECK_DUNNO);
+ domain += 1;
+
+ /*
+ * Permit if the destination matches the relay_domains list.
+ */
+ if (domain_list_match(relay_domains, domain))
+ return (SMTPD_CHECK_DUNNO);
+
+ /*
+ * Deny relaying between sites that both are not in relay_domains.
+ */
+ return (smtpd_check_reject(state, MAIL_ERROR_POLICY,
+ "%d <%s>: Relay access denied",
+ var_relay_code, recipient));
+}
+
/* has_my_addr - see if this host name lists one of my network addresses */
static int has_my_addr(char *host)
recipient, SMTPD_NAME_RECIPIENT);
} else if (strcasecmp(name, PERMIT_MX_BACKUP) == 0) {
status = permit_mx_backup(state, recipient);
+ } else if (strcasecmp(name, REJECT_UNAUTH_DEST) == 0) {
+ status = reject_unauth_destination(state, recipient);
} else if (strcasecmp(name, CHECK_RELAY_DOMAINS) == 0) {
status = check_relay_domains(state, recipient,
recipient, SMTPD_NAME_RECIPIENT);
#include <mymalloc.h>
#include <events.h>
#include <find_inet.h>
+#include <iostuff.h>
/* Global library. */
if (!connect(fd, (struct sockaddr *) & sin, sizeof(sin)))
break;
if (session->connect_count-- > 1)
+#ifdef MISSING_USLEEP
+ doze(10);
+#else
usleep(10);
+#endif
}
session->stream = vstream_fdopen(fd, O_RDWR);
smtp_timeout_setup(session->stream, var_timeout);
close_on_exec.o: sys_defs.h
close_on_exec.o: msg.h
close_on_exec.o: iostuff.h
-compat.o: compat.c
concatenate.o: concatenate.c
concatenate.o: sys_defs.h
concatenate.o: mymalloc.h
#include <db.h>
#endif
#include <string.h>
+#include <unistd.h>
/* Utility library. */
/* dict_db_open - open data base */
-static DICT *dict_db_open(const char *path, int flags, int type,
+static DICT *dict_db_open(const char *path, int open_flags, int type,
void *tweak, int dict_flags)
{
DICT_DB *dict_db;
struct stat st;
DB *db;
char *db_path;
+ int lock_fd = -1;
db_path = concatenate(path, ".db", (char *) 0);
- if ((db = dbopen(db_path, flags, 0644, type, tweak)) == 0)
+
+ if (dict_flags & DICT_FLAG_LOCK) {
+ if ((lock_fd = open(db_path, open_flags, 0644)) < 0)
+ msg_fatal("open database %s: %m", db_path);
+ if (myflock(lock_fd, MYFLOCK_SHARED) < 0)
+ msg_fatal("shared-lock database %s for open: %m", db_path);
+ }
+ if ((db = dbopen(db_path, open_flags, 0644, type, tweak)) == 0)
msg_fatal("open database %s: %m", db_path);
+ if (dict_flags & DICT_FLAG_LOCK) {
+ if (myflock(lock_fd, MYFLOCK_NONE) < 0)
+ msg_fatal("unlock database %s for open: %m", db_path);
+ if (close(lock_fd) < 0)
+ msg_fatal("close database %s: %m", db_path);
+ }
dict_db = (DICT_DB *) mymalloc(sizeof(*dict_db));
dict_db->dict.lookup = dict_db_lookup;
dict_db->dict.update = dict_db_update;
dict_db->dict.mtime = st.st_mtime;
close_on_exec(dict_db->dict.fd, CLOSE_ON_EXEC);
dict_db->dict.flags = dict_flags | DICT_FLAG_FIXED;
- if ((flags & (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL)) == 0)
+ 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;
#include <sys/stat.h>
#include <ndbm.h>
#include <string.h>
+#include <unistd.h>
/* Utility library. */
#include "iostuff.h"
#include "vstring.h"
#include "myflock.h"
+#include "stringops.h"
#include "dict.h"
#include "dict_dbm.h"
DICT_DBM *dict_dbm;
struct stat st;
DBM *dbm;
+ char *dbm_path;
+ int lock_fd;
+
+ if (dict_flags & DICT_FLAG_LOCK) {
+ dbm_path = concatenate(path, ".pag", (char *) 0);
+ if ((lock_fd = open(dbm_path, open_flags, 0644)) < 0)
+ msg_fatal("open database %s: %m", dbm_path);
+ if (myflock(lock_fd, MYFLOCK_SHARED) < 0)
+ msg_fatal("shared-lock database %s for open: %m", dbm_path);
+ }
/*
* XXX SunOS 5.x has no const in dbm_open() prototype.
if ((dbm = dbm_open((char *) path, open_flags, 0644)) == 0)
msg_fatal("open database %s.{dir,pag}: %m", path);
+ if (dict_flags & DICT_FLAG_LOCK) {
+ if (myflock(lock_fd, MYFLOCK_NONE) < 0)
+ msg_fatal("unlock database %s for open: %m", dbm_path);
+ if (close(lock_fd) < 0)
+ msg_fatal("close database %s: %m", dbm_path);
+ myfree(dbm_path);
+ }
dict_dbm = (DICT_DBM *) mymalloc(sizeof(*dict_dbm));
dict_dbm->dict.lookup = dict_dbm_lookup;
dict_dbm->dict.update = dict_dbm_update;
if (fstat(dict_dbm->dict.fd, &st) < 0)
msg_fatal("dict_dbm_open: fstat: %m");
dict_dbm->dict.mtime = st.st_mtime;
- close_on_exec(dict_dbm->dict.fd, CLOSE_ON_EXEC);
dict_dbm->dict.flags = dict_flags | DICT_FLAG_FIXED;
if ((dict_flags & (DICT_FLAG_TRY0NULL | DICT_FLAG_TRY1NULL)) == 0)
dict_dbm->dict.flags |= (DICT_FLAG_TRY0NULL | DICT_FLAG_TRY1NULL);
/* int inet_addr_local(list)
/* INET_ADDR_LIST *list;
/* DESCRIPTION
-/* inet_addr_local() determines all active interface addresses
+/* 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.
#include <inet_addr_list.h>
#include <inet_addr_local.h>
+ /*
+ * Support for variable-length addresses.
+ */
+#ifdef _SIZEOF_ADDR_IFREQ
+#define NEXT_INTERFACE(ifr) ((struct ifreq *) \
+ ((char *) 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))
+#else
+#define NEXT_INTERFACE(ifr) (ifr + 1)
+#endif
+#endif
+
/* inet_addr_local - find all IP addresses for this host */
int inet_addr_local(INET_ADDR_LIST *addr_list)
&(((struct sockaddr_in *) & ifreq.ifr_addr)->sin_addr));
}
}
-
- /*
- * Support for variable-length addresses.
- */
-#ifdef HAS_SA_LEN
- ifr = (struct ifreq *)
- ((char *) ifr + sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len);
-#else
- ifr++;
-#endif
+ ifr = NEXT_INTERFACE(ifr);
}
vstring_free(buf);
(void) close(sock);
/* System library. */
#include <sys_defs.h>
+#ifdef HAVE_DIRENT_H
#include <dirent.h>
+#else
+#define dirent direct
+#ifdef HAVE_SYS_NDIR_H
+#include <sys/ndir.h>
+#endif
+#ifdef HAVE_SYS_DIR_H
+#include <sys/dir.h>
+#endif
+#ifdef HAVE_NDIR_H
+#include <ndir.h>
+#endif
+#endif
#include <string.h>
/* Utility library. */
/*
/* split_at_right() looks for the rightmost delimiter
/* occurrence, but is otherwise identical to split_at().
+/* DIAGNOSTICS
+/* The result is a null pointer when the delimiter character
+/* was not found.
/* HISTORY
/* .ad
/* .fi
#if defined(RHAPSODY5)
#define NORETURN void
+#define HAS_NETINFO
#endif
#ifdef ULTRIX4
#define SUPPORTED
+/* Ultrix by default has only 64 descriptors per process */
+#ifndef FD_SETSIZE
+#define FD_SETSIZE 96
+#endif
#include <sys/types.h>
#define UNSAFE_CTYPE /* XXX verify */
#define _PATH_MAILDIR "/var/spool/mail"
/* Ultrix misses just S_ISSOCK, the others are there */
#define S_ISSOCK(mode) (((mode) & (S_IFMT)) == (S_IFSOCK))
#define DUP2_DUPS_CLOSE_ON_EXEC
-/* Ultrix by default has only 64 descriptors per process */
-#ifndef FD_SETSIZE
-#define FD_SETSIZE 100
-#endif
-#define usleep doze
+#define MISSING_USLEEP
#endif
#ifdef OSF1
#endif
#if defined(IRIX5)
-#define usleep doze
+#define MISSING_USLEEP
#endif
#ifdef LINUX2
#include <sys/types.h>
#define USE_PATHS_H
#define USE_FLOCK_LOCK
+#define USE_DOT_LOCK
#define HAS_FSYNC
#define HAS_DB
#define DEF_DB_TYPE "hash"
#define UNIX_DOMAIN_CONNECT_BLOCKS_FOR_ACCEPT
#define PREPEND_PLUS_TO_OPTSTRING
#define HAS_POSIX_REGEXP
+#define WARN_SETXID_SENDMAIL
#endif
/*
#define _PATH_STDPATH "/bin:/usr/bin:/usr/ucb"
#define ROOT_PATH "/bin:/usr/bin:/usr/etc:/usr/ucb"
#define DEF_DB_TYPE "dbm"
-#define ALIAS_DB_MAP "dbm:/etc/sendmail/aliases"
+#define ALIAS_DB_MAP "netinfo:/aliases"
#include <libc.h>
#define MISSING_POSIX_S_IS
#define MISSING_POSIX_S_MODES
#define _PATH_STDPATH "/bin:/usr/bin:/usr/ucb"
#define ROOT_PATH "/bin:/usr/bin:/usr/etc:/usr/ucb"
#define DEF_DB_TYPE "dbm"
-#define ALIAS_DB_MAP "dbm:/etc/sendmail/aliases"
+#define ALIAS_DB_MAP "netinfo:/aliases"
#include <libc.h>
#define MISSING_POSIX_S_IS
#define MISSING_POSIX_S_MODES
#define ROOT_PATH "/bin:/usr/bin:/sbin:/usr/sbin:/usr/ucb"
#define USE_STATVFS
#define STATVFS_IN_SYS_STATVFS_H
-#define usleep doze
+#define MISSING_USLEEP
#endif
/*