2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-08-29 13:18:12 +00:00

snapshot-20000625

This commit is contained in:
Wietse Venema 2000-06-25 00:00:00 +00:00
parent a8e8c4d123
commit 9f6c81ebcd
43 changed files with 569 additions and 134 deletions

View File

@ -1,4 +1,8 @@
This is a very first implementation of Postfix content filtering. This is a very first implementation of Postfix content filtering.
A Postfix content filter re-injects filtered mail back into Postfix.
If all you want is content _inspection_, see the INSPECT_README
file instead.
It involves an incompatible change to queue file formats. Older It involves an incompatible change to queue file formats. Older
Postfix versions will reject mail that needs to be content filtered, Postfix versions will reject mail that needs to be content filtered,
and will move the queue file to the "corrupt" mail queue subdirectory. and will move the queue file to the "corrupt" mail queue subdirectory.
@ -76,18 +80,19 @@ content through run a third-party content filter program. If the
mail cannot be captured to file, mail delivery is deferred by mail cannot be captured to file, mail delivery is deferred by
terminating with exit status 75 (EX_TEMPFAIL). If the content terminating with exit status 75 (EX_TEMPFAIL). If the content
filter program finds a problem, the mail is bounced by terminating filter program finds a problem, the mail is bounced by terminating
the filter command with exit status 69 (EX_UNAVAILABLE). If the the shell script with exit status 69 (EX_UNAVAILABLE). If the
content is OK, it is given as input to Postfix sendmail, and the content is OK, it is given as input to Postfix sendmail, and the
exit status of the filter command is whatever exit status Postfix exit status of the filter command is whatever exit status Postfix
sendmail produces. sendmail produces.
The problem with content filterings like this is that they are not The problem with content filters like this is that they are not
very robust, because they do not talk a well-defined protocol with very robust, because the software does not talk a well-defined
Postfix. If the filter command aborts because of some memory protocol with Postfix. If the filter shell script aborts because
allocation problem, it will not produce a nice exit status as per the shell runs into some memory allocation problem, the script will
/usr/include/sysexits.h and mail will probably bounce. The same not produce a nice exit status as per /usr/include/sysexits.h and
lack of robustness is possible when the content filtering software mail will probably bounce. The same lack of robustness is possible
itself runs into a resource problem. 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 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, satisfied with the results. Run it as root or as the filter user,
@ -159,7 +164,7 @@ When a queue file has content filtering information, the queue
manager will deliver the mail to the specified content filtering manager will deliver the mail to the specified content filtering
regardless of its final destination. regardless of its final destination.
The content filtering can be set up with the Postfix spawn service, The content filter can be set up with the Postfix spawn service,
which is the Postfix equivalent of inetd. For example, to instantiate which is the Postfix equivalent of inetd. For example, to instantiate
up to 10 content filtering processes on demand: up to 10 content filtering processes on demand:
@ -184,18 +189,18 @@ For now, it is left up to the Postfix users to come up with a
PERL/SMTP framework for Postfix content filtering. If done well, PERL/SMTP framework for Postfix content filtering. If done well,
it can be used with other mailers too, which is a nice spin-off. it can be used with other mailers too, which is a nice spin-off.
The simplest content filtering just copies SMTP commands and data The simplest content filter just copies SMTP commands and data
between its inputs and outputs. If it has a problem, all it has to 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 do is to reply to an input of `.' with `550 content rejected', and
to disconnect its output side instead of sending `.'. to disconnect its output side instead of sending `.'.
The job of the content filtering is to either bounce mail with a The job of the content filter is to either bounce mail with a
suitable diagnostic, or to feed the mail back into Postfix through suitable diagnostic, or to feed the mail back into Postfix through
a dedicated listener on port localhost 10026: a dedicated listener on port localhost 10026:
/etc/postfix/master.cf: /etc/postfix/master.cf:
localhost:10026 inet n - n - 10 smtpd localhost:10026 inet n - n - 10 smtpd
-o content_filter= myhostname=localhost.domain.name -o content_filter= -o myhostname=localhost.domain.name
This is just another SMTP server. It is configured NOT to request This is just another SMTP server. It is configured NOT to request
content filtering for incoming mail, has the same process limit content filtering for incoming mail, has the same process limit

View File

@ -4032,3 +4032,66 @@ Apologies for any names omitted.
Renamed "content inspection" etc. to "content filtering" Renamed "content inspection" etc. to "content filtering"
in anticipation of a new hook for content inspection that in anticipation of a new hook for content inspection that
only inspects mail without re-injecting it into Postfix. only inspects mail without re-injecting it into Postfix.
20000601
Feature: limit the size of pipe mailer deliveries with the
size=nnn command-line attribute. Patch by Andrew McNamara.
20000603
Bugfix: don't try to do SASL authentication when running
in stand-alone (sendmail -bs) mode. Fix by Liviu Daia.
Bug: the unauthorized pipelining test fails with single
recipient mail when smtpd_delay_reject = yes.
20000617
Bugfix: conf/sample-ldap.cf was no longer up to date with
reality. Patch by Lamont Jones, HP.
Bugfix: the maildir delivery routine left temporary files
lying around after unsuccessful delivery (problem reported
by Brian Laughton @ Corp.Axxent.Ca).
20000619
Workaround: if append_dot_mydomain=no, turn on parent domain
search in the Postfix SMTP client, so that mail does not
bounce. Files: smtp/smtp.c, smtp/smtp_unalias.c.
20000621
AIX 4.x had POSIX regular expression support all the time
I was working on Postfix. Beter find out late than never.
20000623
Bugfix: the SMTP server did not reset the so-called junk
command counter after successfull delivery (Mark Hoffman
@ wallst.com). File: smtpd/smtpd.c.
20000625
Cleanup: remove Content-Length from incoming mail. The
sender has no authority over the format of mail as stored
by the receiving system. File: global/header_opts.h.
Feature: rewrite Mail-Followup-To: as sender. Files:
global/header_opts.[hc].
Cleanup: rewrite Reply-To, Errors-To, Return-Receipt-To as
sender, so that address masquerading works as expected.
Files: global/header_opts.c.
Feature: specify "test_home_directory = yes" to prevent
mail from being delivered to a user whose home directory
is not mounted. File: local/dotforward.c.
Cleanup: the pipe deliver agent no longer appends a blank
line when the F flag (prepend From_ line) is specified.
Specify the B flag if you need that blank line. The local
delivery agent no longer appends a blank line to mail that
is delivered to external command. Files: pipe/pipe.c,
global/mail_copy.[hc].

181
postfix/INSPECT_README Normal file
View File

@ -0,0 +1,181 @@
This is a very first implementation of Postfix content inspection.
A Postfix content inspector causes "bad" mail to be bounced. All
other mail is delivered normally. If you want content _inspection_,
which allows you to modify mail content or destination, see the
FILTER_README file instead.
Content inspection involves an incompatible change to queue file
formats. Older Postfix versions will reject mail that needs to be
content inspected, and will move the queue file to the "corrupt"
mail queue subdirectory.
This document describes two approaches to content inspection.
Simple content inspection example
=================================
The example is relatively simple to set up, but is resource intensive
because it runs a shell script for each message.
With the shell script as shown you can lose a factor in Postfix
performance for each temporary file that is created and deleted in
the process of content inspection. The performance impact is less
for mail that is submitted or delivered locally, because such
deliveries are not as fast as SMTP transit mail.
The example assumes that only mail received via SMTP needs to be
content inspected.
..................................
. Postfix .
------smtpd \ /local-----
. -cleanup->queue- .
-----pickup / \smtp------
. | .
. \pipe------>inspector
..................................
Create a dedicated local user account called "inspect". The user
will never log in, and can be given a "*" password and non-existent
shell and home.
Create a directory /var/spool/inspect that is accessible only to
the "inspect" user. This is where the content inspection software
will store any temporary files.
Define a content inspection entry in the Postfix master file:
/etc/postfix/master.cf:
inspect unix - n n - - pipe
user=inspect argv=/some/where/inspect ${sender} ${recipient}
The filter program can start out as a simple shell script like this:
#!/bin/sh
# Localize this
INSPECT_DIR=/var/spool/inspect
# Exit codes from <sysexits.h>
EX_TEMPFAIL=75
EX_UNAVAILABLE=69
cd $INSPECT_DIR || { echo $INSPECT_DIR does not exist; exit $EX_TEMPFAIL; }
# Clean up when done or when aborting.
trap "rm -f in.$$; exit" 0 1 2 3 15
cat >in.$$ || { echo Cannot save mail to file; exit $EX_TEMPFAIL; }
# inspect <in.$$ || { echo Message content rejected; exit $EX_UNAVAILABLE; }
exit 0
The idea is to first capture the message to file and then run the
content through run a third-party content inspection program. If
the mail cannot be captured to file, mail delivery is deferred by
terminating with exit status 75 (EX_TEMPFAIL). If the content
inspection program finds a problem, the mail is bounced by terminating
the shell script with exit status 69 (EX_UNAVAILABLE). An exit
status of zero means everything is hunky-dory and the mail can
be delivered to its recipients.
If mail is rejected, another possible action is to mail a copy to
the local postmaster. If you do that, be sure not to enable content
inspection for locally-posted mail or else rejected mail will loop.
The problem with content inspection sotware like this is that it is
not very robust, because the software does not talk a well-defined
protocol with Postfix. If the shell scripts 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 inspection 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:
# /some/where/inspect sender recipient... <message-file
Turn on content inspection for mail arriving via SMTP only, by
appending "-o content_inspector=inspect:dummy" to the master.cf
entry that defines the Postfix SMTP server:
/etc/postfix/master.cf:
smtp inet ...stuff... smtpd
-o content_inspector=inspect:dummy
The content_inspector configuration parameter accepts the same
syntax as the right-hand side in a Postfix transport table.
Advanced content inspection example
===================================
The second example is more complex, but can give better performance,
and is less likely to bounce mail when the machine runs into a
resource problem. This approach uses content inspection software
that can receive mail via SMTP, and that can run as a resident
server. You can expect to lose about a factor in Postfix performance
for every temporary file created.
We will set up a content inspection program listening on localhost
port 10025 that receives mail via the SMTP protocol.
..................................
. Postfix .
------smtpd \ /local-----
. -cleanup->queue- .
-----pickup / | \smtp------
. v .
. smtp .
. | .
......................|...........
|
v
.................
. 10025 .
. inspection .
. .
.................
To enable content inspection in this manner, specify in main.cf a
new parameter:
/etc/postfix/main.cf:
content_filter = smtp:localhost:10025
This causes Postfix to add one extra content inspection record to
each incoming mail message, with content smtp:localhost:10025.
You can use the same syntax as in the right-hand side of a Postfix
transport table. The content inspection records are added by the
smtpd and pickup servers.
When a queue file has content inspection information, the queue
manager will deliver the mail to the specified content inspector
before attempting final delivery.
The content filter can be set up with the Postfix spawn service,
which is the Postfix equivalent of inetd. For example, to instantiate
up to 10 content inspection processes on demand:
/etc/postfix/master.cf:
localhost:10025 inet n n n - 10 spawn
user=inspect argv=/some/where/inspect
"inspect" is a dedicated local user account. The user will never
log in, and can be given a "*" password and non-existent shell and
home.
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.
The /some/where/inspect command is most likely a PERL script. PERL
has modules that make talking SMTP easy.
For now, it is left up to the Postfix users to come up with a
PERL/SMTP framework for Postfix content inspection. If done well,
it can be used with other mailers too, which is a nice spin-off.

View File

@ -1,3 +1,12 @@
Incompatible changes with snapshot-20000625
===========================================
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. Specify the B flag if you need that blank line.
Incompatible changes with snapshot-20000531 Incompatible changes with snapshot-20000531
=========================================== ===========================================

BIN
postfix/base64/base64decode Executable file

Binary file not shown.

BIN
postfix/base64/base64encode Executable file

Binary file not shown.

View File

@ -118,6 +118,8 @@ cleanup_envelope.o: ../include/tok822.h
cleanup_envelope.o: ../include/resolve_clnt.h cleanup_envelope.o: ../include/resolve_clnt.h
cleanup_envelope.o: ../include/mail_params.h cleanup_envelope.o: ../include/mail_params.h
cleanup_envelope.o: ../include/ext_prop.h cleanup_envelope.o: ../include/ext_prop.h
cleanup_envelope.o: ../include/mail_addr.h
cleanup_envelope.o: ../include/canon_addr.h
cleanup_envelope.o: cleanup.h cleanup_envelope.o: cleanup.h
cleanup_envelope.o: ../include/argv.h cleanup_envelope.o: ../include/argv.h
cleanup_envelope.o: ../include/maps.h cleanup_envelope.o: ../include/maps.h

View File

@ -8,12 +8,62 @@
# The ldap_lookup_timeout parameter specifies the timeout for LDAP # The ldap_lookup_timeout parameter specifies the timeout for LDAP
# database lookups. # database lookups.
# #
ldap_lookup_timeout = 10 #ldap_timeout = 10
# The ldap_search_base parameter specifies the LDAP database to search. # The ldap_search_base parameter specifies the LDAP database to search.
# #
ldap_search_base = #ldap_search_base =
# The ldap_server_host parameter specifies the LDAP server hostname. # The ldap_server_host parameter specifies the LDAP server hostname.
# #
ldap_server_host = #ldap_server_host = localhost
# The ldap_server_port parameter specifies the LDAP server port number.
#
#ldap_server_port = 389
# The ldap_query_filter parameter specifies the filter used for queries.
#
#ldap_query_filter = (mailacceptinggeneralid=%s)
# The ldap_result_attribute parameter specifies the attribute returned by
# the search.
#
#ldap_result_attribute = maildrop
# The ldap_scope parameter specifies the LDAP search scope: sub, base, or one.
#
#ldap_scope = sub
# The ldap_bind parameter specifies whether or not to bind to the server.
# LDAP v3 implementations don't require it, which saves some overhead.
#
#ldap_bind = yes
# The ldap_bind_dn parameter specifies what distinguished name to use
# when binding.
#
#ldap_bind_dn =
# The ldap_bind_pw parameter specifies the password to use.
#
#ldap_bind_pw =
# The ldap_cache parameter specifies whether or not to turn on client-side
# caching.
#
#ldap_cache = no
# The ldap_cache_expiry parameter specifies how many seconds to cache results
# for (if ldap_cache=yes)
#
#ldap_cache_expiry = 30
# The ldap_cache_size parameter specifies the cache size, in bytes.
#
#ldap_cache_size = 32768
# The ldap_deference parameter specifies how to handle LDAP aliases. See the
# ldap_open(3) man page.
#
#ldap_dereference = 0

View File

@ -87,7 +87,8 @@ static int deliver_pass_send_request(VSTREAM *stream, DELIVER_REQUEST *request,
{ {
int stat; int stat;
mail_print(stream, "%s %s %ld %ld %s %s %s %s %ld %ld %s %s", mail_print(stream, "%d %s %s %ld %ld %s %s %s %s %ld %ld %s %s",
request->flags,
request->queue_name, request->queue_id, request->queue_name, request->queue_id,
request->data_offset, request->data_size, request->data_offset, request->data_size,
request->nexthop, request->sender, request->nexthop, request->sender,

View File

@ -9,6 +9,7 @@
/* typedef struct DELIVER_REQUEST { /* typedef struct DELIVER_REQUEST {
/* .in +5 /* .in +5
/* VSTREAM *fp; /* VSTREAM *fp;
/* int flags;
/* char *queue_name; /* char *queue_name;
/* char *queue_id; /* char *queue_id;
/* long data_offset; /* long data_offset;
@ -40,6 +41,17 @@
/* A null result means that the client sent bad information or that /* A null result means that the client sent bad information or that
/* it went away unexpectedly. /* it went away unexpectedly.
/* /*
/* The \fBflags\fR structure member is the bit-wise OR of zero or more
/* of the following:
/* .IP \fBDEL_REQ_FLAG_SUCCESS\fR
/* Delete successful recipients from the queue file.
/* .IP \fBDEL_REQ_FLAG_BOUNCE\fR
/* Delete bounced recipients from the queue file. Currently,
/* this flag is considered to be "always on".
/* .PP
/* The \fBDEL_REQ_FLAG_DEFLT\fR constant provides a convenient shorthand
/* for the most common case: delete successful and bounced recipients.
/*
/* The \fIhop_status\fR structure member must be updated /* The \fIhop_status\fR structure member must be updated
/* by the caller when all delivery to the destination in /* by the caller when all delivery to the destination in
/* \fInexthop\fR should be deferred. The value of the /* \fInexthop\fR should be deferred. The value of the
@ -174,7 +186,8 @@ static int deliver_request_get(VSTREAM *stream, DELIVER_REQUEST *request)
* Extract the queue file name, data offset, and sender address. Abort * Extract the queue file name, data offset, and sender address. Abort
* the conversation when they send bad information. * the conversation when they send bad information.
*/ */
if (mail_scan(stream, "%s %s %ld %ld %s %s %s %s %ld", if (mail_scan(stream, "%d %s %s %ld %ld %s %s %s %s %ld",
&request->flags,
queue_name, queue_id, &request->data_offset, queue_name, queue_id, &request->data_offset,
&request->data_size, nexthop, address, &request->data_size, nexthop, address,
errors_to, return_receipt, &request->arrival_time) != 9) errors_to, return_receipt, &request->arrival_time) != 9)

View File

@ -27,6 +27,7 @@
*/ */
typedef struct DELIVER_REQUEST { typedef struct DELIVER_REQUEST {
VSTREAM *fp; /* stream, shared lock */ VSTREAM *fp; /* stream, shared lock */
int flags; /* see below */
char *queue_name; /* message queue name */ char *queue_name; /* message queue name */
char *queue_id; /* message queue id */ char *queue_id; /* message queue id */
long data_offset; /* offset to message */ long data_offset; /* offset to message */
@ -40,6 +41,10 @@ typedef struct DELIVER_REQUEST {
char *hop_status; /* reason if unavailable */ char *hop_status; /* reason if unavailable */
} DELIVER_REQUEST; } DELIVER_REQUEST;
#define DEL_REQ_FLAG_DEFLT (DEL_REQ_FLAG_SUCCESS | DEL_REQ_FLAG_BOUNCE)
#define DEL_REQ_FLAG_SUCCESS (1<<0) /* delete successful recipients */
#define DEL_REQ_FLAG_BOUNCE (1<<1) /* unimplemented */
typedef struct VSTREAM _deliver_vstream_; typedef struct VSTREAM _deliver_vstream_;
extern DELIVER_REQUEST *deliver_request_read(_deliver_vstream_ *); extern DELIVER_REQUEST *deliver_request_read(_deliver_vstream_ *);
extern int deliver_request_done(_deliver_vstream_ *, DELIVER_REQUEST *, int); extern int deliver_request_done(_deliver_vstream_ *, DELIVER_REQUEST *, int);

View File

@ -51,13 +51,15 @@ static HEADER_OPTS header_opts[] = {
"Apparently-To", HDR_APPARENTLY_TO, HDR_OPT_RECIP, "Apparently-To", HDR_APPARENTLY_TO, HDR_OPT_RECIP,
"Bcc", HDR_BCC, HDR_OPT_DROP | HDR_OPT_XRECIP, "Bcc", HDR_BCC, HDR_OPT_DROP | HDR_OPT_XRECIP,
"Cc", HDR_CC, HDR_OPT_XRECIP, "Cc", HDR_CC, HDR_OPT_XRECIP,
"Content-Length", HDR_CONTENT_LENGTH, HDR_OPT_DROP,
"Delivered-To", HDR_DELIVERED_TO, 0, "Delivered-To", HDR_DELIVERED_TO, 0,
"Date", HDR_DATE, 0, "Date", HDR_DATE, 0,
"Errors-To", HDR_ERRORS_TO, HDR_OPT_RECIP, "Errors-To", HDR_ERRORS_TO, HDR_OPT_SENDER,
"From", HDR_FROM, HDR_OPT_SENDER, "From", HDR_FROM, HDR_OPT_SENDER,
"Mail-Followup-To", HDR_MAIL_FOLLOWUP_TO, HDR_OPT_SENDER,
"Message-Id", HDR_MESSAGE_ID, 0, "Message-Id", HDR_MESSAGE_ID, 0,
"Received", HDR_RECEIVED, 0, "Received", HDR_RECEIVED, 0,
"Reply-To", HDR_REPLY_TO, HDR_OPT_RECIP, "Reply-To", HDR_REPLY_TO, HDR_OPT_SENDER,
"Resent-Bcc", HDR_RESENT_BCC, HDR_OPT_DROP | HDR_OPT_XRECIP | HDR_OPT_RR, "Resent-Bcc", HDR_RESENT_BCC, HDR_OPT_DROP | HDR_OPT_XRECIP | HDR_OPT_RR,
"Resent-Cc", HDR_RESENT_CC, HDR_OPT_XRECIP | HDR_OPT_RR, "Resent-Cc", HDR_RESENT_CC, HDR_OPT_XRECIP | HDR_OPT_RR,
"Resent-Date", HDR_RESENT_DATE, HDR_OPT_RR, "Resent-Date", HDR_RESENT_DATE, HDR_OPT_RR,
@ -67,7 +69,7 @@ static HEADER_OPTS header_opts[] = {
"Resent-Sender", HDR_RESENT_SENDER, HDR_OPT_SENDER | HDR_OPT_RR, "Resent-Sender", HDR_RESENT_SENDER, HDR_OPT_SENDER | HDR_OPT_RR,
"Resent-To", HDR_RESENT_TO, HDR_OPT_XRECIP | HDR_OPT_RR, "Resent-To", HDR_RESENT_TO, HDR_OPT_XRECIP | HDR_OPT_RR,
"Return-Path", HDR_RETURN_PATH, HDR_OPT_DROP | HDR_OPT_SENDER, "Return-Path", HDR_RETURN_PATH, HDR_OPT_DROP | HDR_OPT_SENDER,
"Return-Receipt-To", HDR_RETURN_RECEIPT_TO, HDR_OPT_RECIP, "Return-Receipt-To", HDR_RETURN_RECEIPT_TO, HDR_OPT_SENDER,
"Sender", HDR_SENDER, HDR_OPT_SENDER, "Sender", HDR_SENDER, HDR_OPT_SENDER,
"To", HDR_TO, HDR_OPT_XRECIP, "To", HDR_TO, HDR_OPT_XRECIP,
}; };

View File

@ -48,6 +48,7 @@ typedef struct {
#define HDR_RETURN_RECEIPT_TO 23 #define HDR_RETURN_RECEIPT_TO 23
#define HDR_SENDER 24 #define HDR_SENDER 24
#define HDR_TO 25 #define HDR_TO 25
#define HDR_MAIL_FOLLOWUP_TO 26
/* /*
* Header flags. * Header flags.

View File

@ -186,7 +186,7 @@ int mail_copy(const char *sender, const char *delivered,
corrupt_error = mark_corrupt(src); corrupt_error = mark_corrupt(src);
if (prev_type != REC_TYPE_NORM) if (prev_type != REC_TYPE_NORM)
vstream_fputs(eol, dst); vstream_fputs(eol, dst);
if (flags & MAIL_COPY_FROM) if (flags & MAIL_COPY_BLANK)
vstream_fputs(eol, dst); vstream_fputs(eol, dst);
} }
vstring_free(buf); vstring_free(buf);

View File

@ -29,9 +29,10 @@ extern int mail_copy(const char *, const char *, VSTREAM *, VSTREAM *,
#define MAIL_COPY_DELIVERED (1<<3) /* prepend Delivered-To: */ #define MAIL_COPY_DELIVERED (1<<3) /* prepend Delivered-To: */
#define MAIL_COPY_RETURN_PATH (1<<4) /* prepend Return-Path: */ #define MAIL_COPY_RETURN_PATH (1<<4) /* prepend Return-Path: */
#define MAIL_COPY_DOT (1<<5) /* escape dots - needed for bsmtp */ #define MAIL_COPY_DOT (1<<5) /* escape dots - needed for bsmtp */
#define MAIL_COPY_BLANK (1<<6) /* append blank line */
#define MAIL_COPY_MBOX (MAIL_COPY_FROM | MAIL_COPY_QUOTE | \ #define MAIL_COPY_MBOX (MAIL_COPY_FROM | MAIL_COPY_QUOTE | \
MAIL_COPY_TOFILE | MAIL_COPY_DELIVERED | \ MAIL_COPY_TOFILE | MAIL_COPY_DELIVERED | \
MAIL_COPY_RETURN_PATH) MAIL_COPY_RETURN_PATH | MAIL_COPY_BLANK)
#define MAIL_COPY_NONE 0 /* all turned off */ #define MAIL_COPY_NONE 0 /* all turned off */
/* LICENSE /* LICENSE

View File

@ -385,6 +385,10 @@ extern char *var_deliver_hdr;
#define DEF_EXP_OWN_ALIAS 0 #define DEF_EXP_OWN_ALIAS 0
extern bool var_exp_own_alias; extern bool var_exp_own_alias;
#define VAR_STAT_HOME_DIR "test_home_directory"
#define DEF_STAT_HOME_DIR 0
extern bool var_stat_home_dir;
/* /*
* Queue manager: maximal size of the duplicate expansion filter. By * Queue manager: maximal size of the duplicate expansion filter. By
* default, we do graceful degradation with huge mailing lists. * default, we do graceful degradation with huge mailing lists.

View File

@ -15,7 +15,7 @@
* Version of this program. * Version of this program.
*/ */
#define VAR_MAIL_VERSION "mail_version" #define VAR_MAIL_VERSION "mail_version"
#define DEF_MAIL_VERSION "Snapshot-20000531" #define DEF_MAIL_VERSION "Snapshot-20000625"
extern char *var_mail_version; extern char *var_mail_version;
/* LICENSE /* LICENSE

View File

@ -1020,10 +1020,9 @@ types Postfix supports, use the command <b>postconf -m</b>.
<p> <p>
N.B. Some non-Postfix software such as <a N.B. Some non-Postfix software such as <a
href="http://www.mbnet.mb.ca/howto/dynamic.htm">DRAC</a> uses href="http://mail.cc.umanitoba.ca/drac/">DRAC</a> uses <b>btree</b>
<b>btree</b> files instead of <b>hash</b> files. In that case, files instead of <b>hash</b> files. In that case, you will have
you will have to adjust the above <b>check_client_access</b> to adjust the above <b>check_client_access</b> restriction accordingly.
restriction accordingly.
<p> <p>

View File

@ -216,7 +216,7 @@ LOCAL(8) LOCAL(8)
lope header to each message, prepends an optional <b>Deliv-</b> lope header to each message, prepends an optional <b>Deliv-</b>
<b>ered-To:</b> header with the recipient envelope address, <b>ered-To:</b> header with the recipient envelope address,
prepends a <b>Return-Path:</b> header with the sender envelope prepends a <b>Return-Path:</b> header with the sender envelope
address, and appends an empty line. address, and appends no empty line.
<b>EXTERNAL</b> <b>FILE</b> <b>DELIVERY</b> <b>EXTERNAL</b> <b>FILE</b> <b>DELIVERY</b>
The <b>allow</b><i>_</i><b>mail</b><i>_</i><b>to</b><i>_</i><b>files</b> configuration parameter restricts The <b>allow</b><i>_</i><b>mail</b><i>_</i><b>to</b><i>_</i><b>files</b> configuration parameter restricts
@ -277,7 +277,7 @@ LOCAL(8) LOCAL(8)
the <b>default</b><i>_</i><b>privs</b> configuration parameter. the <b>default</b><i>_</i><b>privs</b> configuration parameter.
<b>STANDARDS</b> <b>STANDARDS</b>
RFC 822 (ARPA Internet Text Messages) <a href="http://www.faqs.org/rfcs/rfc822.html">RFC 822</a> (ARPA Internet Text Messages)
<b>DIAGNOSTICS</b> <b>DIAGNOSTICS</b>
Problems and transactions are logged to <b>syslogd</b>(8). Cor- Problems and transactions are logged to <b>syslogd</b>(8). Cor-
@ -352,6 +352,10 @@ LOCAL(8) LOCAL(8)
<b>recipient</b><i>_</i><b>delimiter</b> <b>recipient</b><i>_</i><b>delimiter</b>
Separator between username and address extension. Separator between username and address extension.
<b>test</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.
<b>Mailbox</b> <b>delivery</b> <b>Mailbox</b> <b>delivery</b>
<b>fallback</b><i>_</i><b>transport</b> <b>fallback</b><i>_</i><b>transport</b>
Message transport for recipients that are not found Message transport for recipients that are not found
@ -385,10 +389,6 @@ LOCAL(8) LOCAL(8)
rides all other configuration parameters that con- rides all other configuration parameters that con-
trol mailbox delivery, including <b>luser</b><i>_</i><b>relay</b>. trol mailbox delivery, including <b>luser</b><i>_</i><b>relay</b>.
<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-
sive lock on a mailbox or external file.
@ -401,6 +401,11 @@ LOCAL(8) LOCAL(8)
LOCAL(8) LOCAL(8) LOCAL(8) LOCAL(8)
<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-
sive lock on a mailbox or external file.
<b>deliver</b><i>_</i><b>lock</b><i>_</i><b>delay</b> <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. acquire an exclusive lock.
@ -449,11 +454,6 @@ LOCAL(8) LOCAL(8)
Default rights for delivery to external file or Default rights for delivery to external file or
command. command.
<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.
@ -467,6 +467,11 @@ LOCAL(8) LOCAL(8)
LOCAL(8) LOCAL(8) LOCAL(8) LOCAL(8)
<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.
<b>HISTORY</b> <b>HISTORY</b>
The <b>Delivered-To:</b> header appears in the <b>qmail</b> system by The <b>Delivered-To:</b> header appears in the <b>qmail</b> system by
Daniel Bernstein. Daniel Bernstein.
@ -513,11 +518,6 @@ LOCAL(8) LOCAL(8)

View File

@ -30,10 +30,15 @@ PIPE(8) PIPE(8)
file at the end of a service definition. The syntax is as file at the end of a service definition. The syntax is as
follows: follows:
<b>flags=FR.</b>&gt; (optional) <b>flags=BFR.</b>&gt; (optional)
Optional message processing flags. By default, a Optional message processing flags. By default, a
message is copied unchanged. message is copied unchanged.
<b>B</b> Append a blank line at the end of each mes-
sage. This is required by some mail user
agents that recognize "<b>From</b> " lines only
when preceded by a blank line.
<b>F</b> Prepend a "<b>From</b> <i>sender</i> <i>time_stamp</i>" envelope <b>F</b> Prepend a "<b>From</b> <i>sender</i> <i>time_stamp</i>" envelope
header to the message content. This is header to the message content. This is
expected by, for example, <b>UUCP</b> software. The expected by, for example, <b>UUCP</b> software. The
@ -54,11 +59,6 @@ PIPE(8) PIPE(8)
<b>user</b>=<i>username</i>:<i>groupname</i> <b>user</b>=<i>username</i>:<i>groupname</i>
The external command is executed with the rights of The external command is executed with the rights of
the specified <i>username</i>. The software refuses to
execute commands with root privileges, or with the
privileges of the mail system owner. If <i>groupname</i>
is specified, the corresponding group ID is used
instead of the group ID of <i>username</i>.
@ -71,12 +71,22 @@ PIPE(8) PIPE(8)
PIPE(8) PIPE(8) PIPE(8) PIPE(8)
the specified <i>username</i>. The software refuses to
execute commands with root privileges, or with the
privileges of the mail system owner. If <i>groupname</i>
is specified, the corresponding group ID is used
instead of the group ID of <i>username</i>.
<b>eol=string</b> (default: <b>\n</b>) <b>eol=string</b> (default: <b>\n</b>)
The output record delimiter. Typically one would The output record delimiter. Typically one would
use either <b>\r\n</b> or <b>\n</b>. The usual C-style backslash use either <b>\r\n</b> or <b>\n</b>. The usual C-style backslash
escape sequences are recognized: <b>\a</b> <b>\b</b> <b>\f</b> <b>\n</b> <b>\r</b> <b>\t</b> escape sequences are recognized: <b>\a</b> <b>\b</b> <b>\f</b> <b>\n</b> <b>\r</b> <b>\t</b>
<b>\v</b> <b>\</b><i>octal</i> and <b>\\</b>. <b>\v</b> <b>\</b><i>octal</i> and <b>\\</b>.
<b>size</b>=<i>size_limit</i> (optional)
Messages greater in size than this limit (in bytes)
will be bounced back to the sender.
<b>argv</b>=<i>command</i>... (required) <b>argv</b>=<i>command</i>... (required)
The command to be executed. This must be specified The command to be executed. This must be specified
as the last command attribute. The command is exe- as the last command attribute. The command is exe-
@ -115,16 +125,6 @@ PIPE(8) PIPE(8)
tains <b>${recipient</b>} expands into as many com- tains <b>${recipient</b>} expands into as many com-
mand-line arguments as there are recipients. mand-line arguments as there are recipients.
<b>${sender</b>}
This macro expands to the envelope sender
address.
<b>${user</b>}
This macro expands to the username part of a
recipient address. For example, with an
address <i>user+foo@domain</i> the username part is
<i>user</i>. A command-line argument that contains
<b>${user</b>} expands into as many command-line
@ -137,6 +137,16 @@ PIPE(8) PIPE(8)
PIPE(8) PIPE(8) PIPE(8) PIPE(8)
<b>${sender</b>}
This macro expands to the envelope sender
address.
<b>${user</b>}
This macro expands to the username part of a
recipient address. For example, with an
address <i>user+foo@domain</i> the username part is
<i>user</i>. A command-line argument that contains
<b>${user</b>} expands into as many command-line
arguments as there are recipients. arguments as there are recipients.
In addition to the form ${<i>name</i>}, the forms $<i>name</i> and In addition to the form ${<i>name</i>}, the forms $<i>name</i> and
@ -180,17 +190,7 @@ PIPE(8) PIPE(8)
enforced by the Postfix queue manager. enforced by the Postfix queue manager.
<i>transport_</i><b>destination</b><i>_</i><b>recipient</b><i>_</i><b>limit</b> <i>transport_</i><b>destination</b><i>_</i><b>recipient</b><i>_</i><b>limit</b>
Limit the number of recipients per message deliv- Limit the number of recipients per message
ery, for delivery via the named <i>transport</i>. The
default limit is taken from the <b>default</b><i>_</i><b>destina-</b>
<b>tion</b><i>_</i><b>recipient</b><i>_</i><b>limit</b> parameter. The limit is
enforced by the Postfix queue manager.
<i>transport_</i><b>time</b><i>_</i><b>limit</b>
Limit the time for delivery to external command,
for delivery via the named <b>transport</b>. The default
limit is taken from the <b>command</b><i>_</i><b>time</b><i>_</i><b>limit</b> parame-
ter. The limit is enforced by the Postfix queue
@ -203,6 +203,16 @@ PIPE(8) PIPE(8)
PIPE(8) PIPE(8) PIPE(8) PIPE(8)
delivery, for delivery via the named <i>transport</i>. The
default limit is taken from the <b>default</b><i>_</i><b>destina-</b>
<b>tion</b><i>_</i><b>recipient</b><i>_</i><b>limit</b> parameter. The limit is
enforced by the Postfix queue manager.
<i>transport_</i><b>time</b><i>_</i><b>limit</b>
Limit the time for delivery to external command,
for delivery via the named <b>transport</b>. The default
limit is taken from the <b>command</b><i>_</i><b>time</b><i>_</i><b>limit</b> parame-
ter. The limit is enforced by the Postfix queue
manager. manager.
<b>SEE</b> <b>ALSO</b> <b>SEE</b> <b>ALSO</b>
@ -239,16 +249,6 @@ PIPE(8) PIPE(8)

View File

@ -75,6 +75,9 @@ SMTP(8) SMTP(8)
command after a configuration change. command after a configuration change.
<b>Miscellaneous</b> <b>Miscellaneous</b>
<b>append</b><i>_</i><b>dot</b><i>_</i><b>mydomain</b>
Rewrite <i>user</i>@<i>host</i> to <i>user</i>@<i>host</i>.$<b>mydomain</b>.
<b>best</b><i>_</i><b>mx</b><i>_</i><b>transport</b> <b>best</b><i>_</i><b>mx</b><i>_</i><b>transport</b>
Name of the delivery transport to use when the Name of the delivery transport to use when the
local machine is the most-preferred mail exchanger local machine is the most-preferred mail exchanger
@ -123,9 +126,6 @@ SMTP(8) SMTP(8)
<b>smtp</b><i>_</i><b>always</b><i>_</i><b>send</b><i>_</i><b>ehlo</b> <b>smtp</b><i>_</i><b>always</b><i>_</i><b>send</b><i>_</i><b>ehlo</b>
Always send EHLO at the start of a connection. Always send EHLO at the start of a connection.
<b>smtp</b><i>_</i><b>skip</b><i>_</i><b>4xx</b><i>_</i><b>greeting</b>
Skip servers that greet us with a 4xx status code.
2 2
@ -137,6 +137,9 @@ SMTP(8) SMTP(8)
SMTP(8) SMTP(8) SMTP(8) SMTP(8)
<b>smtp</b><i>_</i><b>skip</b><i>_</i><b>4xx</b><i>_</i><b>greeting</b>
Skip servers that greet us with a 4xx status code.
<b>smtp</b><i>_</i><b>skip</b><i>_</i><b>5xx</b><i>_</i><b>greeting</b> <b>smtp</b><i>_</i><b>skip</b><i>_</i><b>5xx</b><i>_</i><b>greeting</b>
Skip servers that greet us with a 5xx status code. Skip servers that greet us with a 5xx status code.
@ -188,9 +191,6 @@ SMTP(8) SMTP(8)
ery. The default limit is taken from the 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>default</b><i>_</i><b>destination</b><i>_</i><b>recipient</b><i>_</i><b>limit</b> parameter.
<b>Timeout</b> <b>controls</b>
<b>smtp</b><i>_</i><b>connect</b><i>_</i><b>timeout</b>
Timeout in seconds for completing a TCP connection.
@ -203,6 +203,9 @@ SMTP(8) SMTP(8)
SMTP(8) SMTP(8) SMTP(8) SMTP(8)
<b>Timeout</b> <b>controls</b>
<b>smtp</b><i>_</i><b>connect</b><i>_</i><b>timeout</b>
Timeout in seconds for completing a TCP connection.
When no connection can be made within the deadline, When no connection can be made within the deadline,
the SMTP client tries the next address on the mail the SMTP client tries the next address on the mail
exchanger list. exchanger list.
@ -254,9 +257,6 @@ SMTP(8) SMTP(8)
The Secure Mailer license must be distributed with this The Secure Mailer license must be distributed with this
software. software.
<b>AUTHOR(S)</b>
Wietse Venema
IBM T.J. Watson Research
@ -269,6 +269,9 @@ SMTP(8) SMTP(8)
SMTP(8) SMTP(8) SMTP(8) SMTP(8)
<b>AUTHOR(S)</b>
Wietse Venema
IBM T.J. Watson Research
P.O. Box 704 P.O. Box 704
Yorktown Heights, NY 10598, USA Yorktown Heights, NY 10598, USA
@ -319,9 +322,6 @@ SMTP(8) SMTP(8)

View File

@ -531,6 +531,7 @@ static int lmtp_loop(LMTP_STATE *state, int send_state, int recv_state)
sent(request->queue_id, rcpt->address, sent(request->queue_id, rcpt->address,
session->namaddr, request->arrival_time, session->namaddr, request->arrival_time,
"%s", resp->str); "%s", resp->str);
if (request->flags & DEL_REQ_FLAG_SUCCESS)
deliver_completed(state->src, rcpt->offset); deliver_completed(state->src, rcpt->offset);
rcpt->offset = 0; rcpt->offset = 0;
} }

View File

@ -64,6 +64,7 @@
#include <vstream.h> #include <vstream.h>
#include <htable.h> #include <htable.h>
#include <open_as.h> #include <open_as.h>
#include <stat_as.h>
#include <lstat_as.h> #include <lstat_as.h>
#include <iostuff.h> #include <iostuff.h>
#include <stringops.h> #include <stringops.h>
@ -78,6 +79,7 @@
#include <mail_params.h> #include <mail_params.h>
#include <mail_conf.h> #include <mail_conf.h>
#include <ext_prop.h> #include <ext_prop.h>
#include <defer.h>
/* Application-specific. */ /* Application-specific. */
@ -112,18 +114,36 @@ int deliver_dotforward(LOCAL_STATE state, USER_ATTR usr_attr, int *statusp)
if (msg_verbose) if (msg_verbose)
MSG_LOG_STATE(myname, state); MSG_LOG_STATE(myname, state);
/*
* Skip non-existing users. The mailbox delivery routine will catch the
* error.
*
* Defer delivery to recipients whose home directory is not accessible.
*
* XXX This code should be one level up. The caller should pass the
* recipient's password file info along with the call.
*
* XXX This code should also be executed for \user deliveries that bypass
* aliasing and .forward processing. Said code is currently broken after
* a revision of the RFC822 address parser.
*/
if ((mypwd = mypwnam(state.msg_attr.user)) == 0)
return (NO);
if (var_stat_home_dir
&& stat_as(mypwd->pw_dir, &st, mypwd->pw_uid, mypwd->pw_gid) < 0) {
*statusp = defer_append(BOUNCE_FLAG_KEEP,
BOUNCE_ATTR(state.msg_attr),
"cannot access %s home directory %s: %m",
mypwd->pw_name, mypwd->pw_dir);
return (YES);
}
/* /*
* Skip this module if per-user forwarding is disabled. * Skip this module if per-user forwarding is disabled.
*/ */
if (*var_forward_path == 0) if (*var_forward_path == 0)
return (NO); return (NO);
/*
* Skip non-existing users. The mailbox delivery routine will catch the
* error.
*/
if ((mypwd = mypwnam(state.msg_attr.user)) == 0)
return (NO);
/* /*
* From here on no early returns or we have a memory leak. * From here on no early returns or we have a memory leak.

View File

@ -173,7 +173,7 @@
/* optional \fBDelivered-To:\fR /* optional \fBDelivered-To:\fR
/* header with the recipient envelope address, prepends a /* header with the recipient envelope address, prepends a
/* \fBReturn-Path:\fR header with the sender envelope address, /* \fBReturn-Path:\fR header with the sender envelope address,
/* and appends an empty line. /* and appends no empty line.
/* EXTERNAL FILE DELIVERY /* EXTERNAL FILE DELIVERY
/* .ad /* .ad
/* .fi /* .fi
@ -278,6 +278,9 @@
/* forwarding mail is not recommended. /* forwarding mail is not recommended.
/* .IP \fBrecipient_delimiter\fR /* .IP \fBrecipient_delimiter\fR
/* Separator between username and address extension. /* Separator between username and address extension.
/* .IP \fBtest_home_directory\fR
/* Require that a recipient's home directory is accessible by the
/* recipient before attempting delivery.
/* .SH Mailbox delivery /* .SH Mailbox delivery
/* .ad /* .ad
/* .fi /* .fi
@ -439,6 +442,7 @@ char *var_fwd_exp_filter;
char *var_prop_extension; char *var_prop_extension;
int var_exp_own_alias; int var_exp_own_alias;
char *var_deliver_hdr; char *var_deliver_hdr;
int var_stat_home_dir;
int local_cmd_deliver_mask; int local_cmd_deliver_mask;
int local_file_deliver_mask; int local_file_deliver_mask;
@ -500,7 +504,7 @@ static int local_deliver(DELIVER_REQUEST *rqst, char *service)
state.msg_attr.recipient = rcpt->address; state.msg_attr.recipient = rcpt->address;
rcpt_stat = deliver_recipient(state, usr_attr); rcpt_stat = deliver_recipient(state, usr_attr);
rcpt_stat |= forward_finish(state.msg_attr, rcpt_stat); rcpt_stat |= forward_finish(state.msg_attr, rcpt_stat);
if (rcpt_stat == 0) if (rcpt_stat == 0 && (rqst->flags & DEL_REQ_FLAG_SUCCESS))
deliver_completed(state.msg_attr.fp, rcpt->offset); deliver_completed(state.msg_attr.fp, rcpt->offset);
been_here_free(state.dup_filter); been_here_free(state.dup_filter);
msg_stat |= rcpt_stat; msg_stat |= rcpt_stat;
@ -618,6 +622,7 @@ int main(int argc, char **argv)
static CONFIG_BOOL_TABLE bool_table[] = { static CONFIG_BOOL_TABLE bool_table[] = {
VAR_BIFF, DEF_BIFF, &var_biff, VAR_BIFF, DEF_BIFF, &var_biff,
VAR_EXP_OWN_ALIAS, DEF_EXP_OWN_ALIAS, &var_exp_own_alias, VAR_EXP_OWN_ALIAS, DEF_EXP_OWN_ALIAS, &var_exp_own_alias,
VAR_STAT_HOME_DIR, DEF_STAT_HOME_DIR, &var_stat_home_dir,
0, 0,
}; };

View File

@ -143,11 +143,11 @@ int deliver_maildir(LOCAL_STATE state, USER_ATTR usr_attr, char *path)
|| sane_link(tmpfile, newfile) < 0)) { || sane_link(tmpfile, newfile) < 0)) {
vstring_sprintf(why, "link to %s: %m", newfile); vstring_sprintf(why, "link to %s: %m", newfile);
} else { } else {
if (unlink(tmpfile) < 0)
msg_warn("remove %s: %m", tmpfile);
status = 0; status = 0;
} }
} }
if (unlink(tmpfile) < 0)
msg_warn("remove %s: %m", tmpfile);
} }
set_eugid(var_owner_uid, var_owner_gid); set_eugid(var_owner_uid, var_owner_gid);

View File

@ -104,6 +104,10 @@ static int deliver_switch(LOCAL_STATE state, USER_ATTR usr_attr)
/* /*
* \user is special: it means don't do any alias or forward expansion. * \user is special: it means don't do any alias or forward expansion.
*
* XXX This code currently does not work due to revision of the RFC822
* address parser. \user should be permitted only in locally specified
* aliases, includes or forward files.
*/ */
if (state.msg_attr.recipient[0] == '\\') { if (state.msg_attr.recipient[0] == '\\') {
state.msg_attr.recipient++, state.msg_attr.local++, state.msg_attr.user++; state.msg_attr.recipient++, state.msg_attr.local++, state.msg_attr.user++;

View File

@ -147,7 +147,7 @@ case "$SYSTEM.$RELEASE" in
case "$CC" in case "$CC" in
cc|*/cc|xlc|*/xlc) OPT=; CCARGS="$CCARGS -w -blibpath:/usr/lib:/lib:/usr/local/lib";; cc|*/cc|xlc|*/xlc) OPT=; CCARGS="$CCARGS -w -blibpath:/usr/lib:/lib:/usr/local/lib";;
esac esac
CCARGS="$CCARGS -D_ALL_SOURCE" CCARGS="$CCARGS -D_ALL_SOURCE -DHAS_POSIX_REGEXP"
;; ;;
3) SYSTYPE=AIX3 3) SYSTYPE=AIX3
# How embarrassing... # How embarrassing...

View File

@ -187,7 +187,7 @@ envelope header to each message, prepends an
optional \fBDelivered-To:\fR optional \fBDelivered-To:\fR
header with the recipient envelope address, prepends a header with the recipient envelope address, prepends a
\fBReturn-Path:\fR header with the sender envelope address, \fBReturn-Path:\fR header with the sender envelope address,
and appends an empty line. and appends no empty line.
.SH EXTERNAL FILE DELIVERY .SH EXTERNAL FILE DELIVERY
.na .na
.nf .nf
@ -306,6 +306,9 @@ forwarding, delivery to command or file. Specify zero or more of:
forwarding mail is not recommended. forwarding mail is not recommended.
.IP \fBrecipient_delimiter\fR .IP \fBrecipient_delimiter\fR
Separator between username and address extension. Separator between username and address extension.
.IP \fBtest_home_directory\fR
Require that a recipient's home directory is accessible by the
recipient before attempting delivery.
.SH Mailbox delivery .SH Mailbox delivery
.ad .ad
.fi .fi

View File

@ -30,10 +30,14 @@ to the \fBbounce\fR(8) or \fBdefer\fR(8) daemon as appropriate.
.fi .fi
The external command attributes are given in the \fBmaster.cf\fR The external command attributes are given in the \fBmaster.cf\fR
file at the end of a service definition. The syntax is as follows: file at the end of a service definition. The syntax is as follows:
.IP "\fBflags=FR.>\fR (optional)" .IP "\fBflags=BFR.>\fR (optional)"
Optional message processing flags. By default, a message is Optional message processing flags. By default, a message is
copied unchanged. copied unchanged.
.RS .RS
.IP \fBB\fR
Append a blank line at the end of each message. This is required
by some mail user agents that recognize "\fBFrom \fR" lines only
when preceded by a blank line.
.IP \fBF\fR .IP \fBF\fR
Prepend a "\fBFrom \fIsender time_stamp\fR" envelope header to Prepend a "\fBFrom \fIsender time_stamp\fR" envelope header to
the message content. the message content.
@ -62,6 +66,9 @@ The output record delimiter. Typically one would use either
\fB\er\en\fR or \fB\en\fR. The usual C-style backslash escape \fB\er\en\fR or \fB\en\fR. The usual C-style backslash escape
sequences are recognized: \fB\ea \eb \ef \en \er \et \ev sequences are recognized: \fB\ea \eb \ef \en \er \et \ev
\e\fIoctal\fR and \fB\e\e\fR. \e\fIoctal\fR and \fB\e\e\fR.
.IP "\fBsize\fR=\fIsize_limit\fR (optional)"
Messages greater in size than this limit (in bytes) will be bounced
back to the sender.
.IP "\fBargv\fR=\fIcommand\fR... (required)" .IP "\fBargv\fR=\fIcommand\fR... (required)"
The command to be executed. This must be specified as the The command to be executed. This must be specified as the
last command attribute. last command attribute.

View File

@ -72,6 +72,8 @@ a configuration change.
.SH Miscellaneous .SH Miscellaneous
.ad .ad
.fi .fi
.IP \fBappend_dot_mydomain\fR
Rewrite \fIuser\fR@\fIhost\fR to \fIuser\fR@\fIhost\fR.$\fBmydomain\fR.
.IP \fBbest_mx_transport\fR .IP \fBbest_mx_transport\fR
Name of the delivery transport to use when the local machine Name of the delivery transport to use when the local machine
is the most-preferred mail exchanger (by default, a mailer is the most-preferred mail exchanger (by default, a mailer

View File

@ -22,10 +22,14 @@
/* .fi /* .fi
/* The external command attributes are given in the \fBmaster.cf\fR /* The external command attributes are given in the \fBmaster.cf\fR
/* file at the end of a service definition. The syntax is as follows: /* file at the end of a service definition. The syntax is as follows:
/* .IP "\fBflags=FR.>\fR (optional)" /* .IP "\fBflags=BFR.>\fR (optional)"
/* Optional message processing flags. By default, a message is /* Optional message processing flags. By default, a message is
/* copied unchanged. /* copied unchanged.
/* .RS /* .RS
/* .IP \fBB\fR
/* Append a blank line at the end of each message. This is required
/* by some mail user agents that recognize "\fBFrom \fR" lines only
/* when preceded by a blank line.
/* .IP \fBF\fR /* .IP \fBF\fR
/* Prepend a "\fBFrom \fIsender time_stamp\fR" envelope header to /* Prepend a "\fBFrom \fIsender time_stamp\fR" envelope header to
/* the message content. /* the message content.
@ -54,6 +58,9 @@
/* \fB\er\en\fR or \fB\en\fR. The usual C-style backslash escape /* \fB\er\en\fR or \fB\en\fR. The usual C-style backslash escape
/* sequences are recognized: \fB\ea \eb \ef \en \er \et \ev /* sequences are recognized: \fB\ea \eb \ef \en \er \et \ev
/* \e\fIoctal\fR and \fB\e\e\fR. /* \e\fIoctal\fR and \fB\e\e\fR.
/* .IP "\fBsize\fR=\fIsize_limit\fR (optional)"
/* Messages greater in size than this limit (in bytes) will be bounced
/* back to the sender.
/* .IP "\fBargv\fR=\fIcommand\fR... (required)" /* .IP "\fBargv\fR=\fIcommand\fR... (required)"
/* The command to be executed. This must be specified as the /* The command to be executed. This must be specified as the
/* last command attribute. /* last command attribute.
@ -200,6 +207,7 @@
#include <mail_addr.h> #include <mail_addr.h>
#include <canon_addr.h> #include <canon_addr.h>
#include <split_addr.h> #include <split_addr.h>
#include <off_cvt.h>
/* Single server skeleton. */ /* Single server skeleton. */
@ -255,6 +263,7 @@ typedef struct {
gid_t gid; /* command privileges */ gid_t gid; /* command privileges */
int flags; /* mail_copy() flags */ int flags; /* mail_copy() flags */
VSTRING *eol; /* output record delimiter */ VSTRING *eol; /* output record delimiter */
off_t size_limit; /* max size in bytes we will accept */
} PIPE_ATTR; } PIPE_ATTR;
/* parse_callback - callback for mac_parse() */ /* parse_callback - callback for mac_parse() */
@ -415,6 +424,7 @@ static void get_service_attr(PIPE_ATTR *attr, char **argv)
struct group *grp; struct group *grp;
char *user; /* user name */ char *user; /* user name */
char *group; /* group name */ char *group; /* group name */
char *size; /* max message size */
char *cp; char *cp;
/* /*
@ -425,6 +435,7 @@ static void get_service_attr(PIPE_ATTR *attr, char **argv)
attr->command = 0; attr->command = 0;
attr->flags = 0; attr->flags = 0;
attr->eol = vstring_strcpy(vstring_alloc(1), "\n"); attr->eol = vstring_strcpy(vstring_alloc(1), "\n");
attr->size_limit = 0;
/* /*
* Iterate over the command-line attribute list. * Iterate over the command-line attribute list.
@ -437,6 +448,9 @@ static void get_service_attr(PIPE_ATTR *attr, char **argv)
if (strncasecmp("flags=", *argv, sizeof("flags=") - 1) == 0) { if (strncasecmp("flags=", *argv, sizeof("flags=") - 1) == 0) {
for (cp = *argv + sizeof("flags=") - 1; *cp; cp++) { for (cp = *argv + sizeof("flags=") - 1; *cp; cp++) {
switch (*cp) { switch (*cp) {
case 'B':
attr->flags |= MAIL_COPY_BLANK;
break;
case 'F': case 'F':
attr->flags |= MAIL_COPY_FROM; attr->flags |= MAIL_COPY_FROM;
break; break;
@ -483,6 +497,15 @@ static void get_service_attr(PIPE_ATTR *attr, char **argv)
unescape(attr->eol, *argv + sizeof("eol=") - 1); unescape(attr->eol, *argv + sizeof("eol=") - 1);
} }
/*
* size=max_message_size (in bytes)
*/
else if (strncasecmp("size=", *argv, sizeof("size=") - 1) == 0) {
size = *argv + sizeof("size=") - 1;
if ((attr->size_limit = off_cvt_string(size)) < 0)
msg_fatal("%s: bad size= value: %s", myname, size);
}
/* /*
* argv=command... * argv=command...
*/ */
@ -519,8 +542,9 @@ static void get_service_attr(PIPE_ATTR *attr, char **argv)
* Give the poor tester a clue of what is going on. * Give the poor tester a clue of what is going on.
*/ */
if (msg_verbose) if (msg_verbose)
msg_info("%s: uid %d, gid %d. flags %d", msg_info("%s: uid %d, gid %d, flags %d, size %ld",
myname, attr->uid, attr->gid, attr->flags); myname, attr->uid, attr->gid, attr->flags,
(long) attr->size_limit);
} }
/* eval_command_status - do something with command completion status */ /* eval_command_status - do something with command completion status */
@ -544,6 +568,7 @@ static int eval_command_status(int command_status, char *service,
rcpt = request->rcpt_list.info + n; rcpt = request->rcpt_list.info + n;
sent(request->queue_id, rcpt->address, service, sent(request->queue_id, rcpt->address, service,
request->arrival_time, "%s", request->nexthop); request->arrival_time, "%s", request->nexthop);
if (request->flags & DEL_REQ_FLAG_SUCCESS)
deliver_completed(src, rcpt->offset); deliver_completed(src, rcpt->offset);
} }
break; break;
@ -621,6 +646,19 @@ static int deliver_message(DELIVER_REQUEST *request, char *service, char **argv)
get_service_attr(&attr, argv); get_service_attr(&attr, argv);
} }
/*
* Check that this agent accepts messages this large.
*/
if (attr.size_limit != 0 && request->data_size > attr.size_limit) {
if (msg_verbose)
msg_info("%s: too big: size_limit = %ld, request->data_size = %ld",
myname, (long) attr.size_limit, request->data_size);
deliver_status = eval_command_status(PIPE_STAT_BOUNCE, service,
request, request->fp, "message too large");
return (deliver_status);
}
/* /*
* Deliver. Set the nexthop and sender variables, and expand the command * Deliver. Set the nexthop and sender variables, and expand the command
* argument vector. Recipients will be expanded on the fly. XXX Rewrite * argument vector. Recipients will be expanded on the fly. XXX Rewrite

View File

@ -134,6 +134,7 @@ qmgr_deliver.o: ../include/mail_queue.h
qmgr_deliver.o: ../include/mail_proto.h qmgr_deliver.o: ../include/mail_proto.h
qmgr_deliver.o: ../include/recipient_list.h qmgr_deliver.o: ../include/recipient_list.h
qmgr_deliver.o: ../include/mail_params.h qmgr_deliver.o: ../include/mail_params.h
qmgr_deliver.o: ../include/deliver_request.h
qmgr_deliver.o: qmgr.h qmgr_deliver.o: qmgr.h
qmgr_deliver.o: ../include/scan_dir.h qmgr_deliver.o: ../include/scan_dir.h
qmgr_deliver.o: ../include/maps.h qmgr_deliver.o: ../include/maps.h

View File

@ -229,7 +229,8 @@ struct QMGR_MESSAGE {
char *sender; /* complete address */ char *sender; /* complete address */
char *errors_to; /* error report address */ char *errors_to; /* error report address */
char *return_receipt; /* confirm receipt address */ char *return_receipt; /* confirm receipt address */
char *filter_xport; /* inspection transport */ char *filter_xport; /* filtering transport */
char *inspect_xport; /* inspecting transport */
long data_size; /* message content size */ long data_size; /* message content size */
long rcpt_offset; /* more recipients here */ long rcpt_offset; /* more recipients here */
QMGR_RCPT_LIST rcpt_list; /* complete addresses */ QMGR_RCPT_LIST rcpt_list; /* complete addresses */

View File

@ -61,6 +61,7 @@
#include <mail_proto.h> #include <mail_proto.h>
#include <recipient_list.h> #include <recipient_list.h>
#include <mail_params.h> #include <mail_params.h>
#include <deliver_request.h>
/* Application-specific. */ /* Application-specific. */
@ -117,7 +118,8 @@ static int qmgr_deliver_send_request(QMGR_ENTRY *entry, VSTREAM *stream)
QMGR_RCPT *recipient; QMGR_RCPT *recipient;
QMGR_MESSAGE *message = entry->message; QMGR_MESSAGE *message = entry->message;
mail_print(stream, "%s %s %ld %ld %s %s %s %s %ld", mail_print(stream, "%d %s %s %ld %ld %s %s %s %s %ld",
message->inspect_xport ? DEL_REQ_FLAG_BOUNCE : DEL_REQ_FLAG_DEFLT,
message->queue_name, message->queue_id, message->queue_name, message->queue_id,
message->data_offset, message->data_size, message->data_offset, message->data_size,
entry->queue->name, message->sender, entry->queue->name, message->sender,

View File

@ -145,6 +145,7 @@ static QMGR_MESSAGE *qmgr_message_create(const char *queue_name,
message->errors_to = 0; message->errors_to = 0;
message->return_receipt = 0; message->return_receipt = 0;
message->filter_xport = 0; message->filter_xport = 0;
message->inspect_xport = 0;
message->data_size = 0; message->data_size = 0;
message->warn_offset = 0; message->warn_offset = 0;
message->warn_time = 0; message->warn_time = 0;
@ -250,6 +251,9 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
} else if (rec_type == REC_TYPE_FILT) { } else if (rec_type == REC_TYPE_FILT) {
if (message->filter_xport == 0) if (message->filter_xport == 0)
message->filter_xport = mystrdup(start); message->filter_xport = mystrdup(start);
} else if (rec_type == REC_TYPE_INSP) {
if (message->inspect_xport == 0)
message->inspect_xport = mystrdup(start);
} else if (rec_type == REC_TYPE_FROM) { } else if (rec_type == REC_TYPE_FROM) {
if (message->sender == 0) { if (message->sender == 0) {
message->sender = mystrdup(start); message->sender = mystrdup(start);
@ -706,6 +710,8 @@ void qmgr_message_free(QMGR_MESSAGE *message)
myfree(message->return_receipt); myfree(message->return_receipt);
if (message->filter_xport) if (message->filter_xport)
myfree(message->filter_xport); myfree(message->filter_xport);
if (message->inspect_xport)
myfree(message->inspect_xport);
qmgr_rcpt_list_free(&message->rcpt_list); qmgr_rcpt_list_free(&message->rcpt_list);
qmgr_message_count--; qmgr_message_count--;
myfree((char *) message); myfree((char *) message);

View File

@ -56,6 +56,8 @@
/* .SH Miscellaneous /* .SH Miscellaneous
/* .ad /* .ad
/* .fi /* .fi
/* .IP \fBappend_dot_mydomain\fR
/* Rewrite \fIuser\fR@\fIhost\fR to \fIuser\fR@\fIhost\fR.$\fBmydomain\fR.
/* .IP \fBbest_mx_transport\fR /* .IP \fBbest_mx_transport\fR
/* Name of the delivery transport to use when the local machine /* Name of the delivery transport to use when the local machine
/* is the most-preferred mail exchanger (by default, a mailer /* is the most-preferred mail exchanger (by default, a mailer
@ -239,6 +241,7 @@ char *var_smtp_sasl_opts;
char *var_smtp_sasl_passwd; char *var_smtp_sasl_passwd;
bool var_smtp_sasl_enable; bool var_smtp_sasl_enable;
char *var_smtp_bind_addr; char *var_smtp_bind_addr;
bool var_append_dot_mydomain;
/* /*
* Global variables. smtp_errno is set by the address lookup routines and by * Global variables. smtp_errno is set by the address lookup routines and by
@ -408,6 +411,7 @@ int main(int argc, char **argv)
VAR_SKIP_QUIT_RESP, DEF_SKIP_QUIT_RESP, &var_skip_quit_resp, VAR_SKIP_QUIT_RESP, DEF_SKIP_QUIT_RESP, &var_skip_quit_resp,
VAR_SMTP_ALWAYS_EHLO, DEF_SMTP_ALWAYS_EHLO, &var_smtp_always_ehlo, VAR_SMTP_ALWAYS_EHLO, DEF_SMTP_ALWAYS_EHLO, &var_smtp_always_ehlo,
VAR_SMTP_SASL_ENABLE, DEF_SMTP_SASL_ENABLE, &var_smtp_sasl_enable, VAR_SMTP_SASL_ENABLE, DEF_SMTP_SASL_ENABLE, &var_smtp_sasl_enable,
VAR_APP_DOT_MYDOMAIN, DEF_APP_DOT_MYDOMAIN, &var_append_dot_mydomain,
0, 0,
}; };

View File

@ -533,6 +533,7 @@ int smtp_xfer(SMTP_STATE *state)
session->namaddr, session->namaddr,
request->arrival_time, "%s", request->arrival_time, "%s",
resp->str); resp->str);
if (request->flags & DEL_REQ_FLAG_SUCCESS)
deliver_completed(state->src, rcpt->offset); deliver_completed(state->src, rcpt->offset);
rcpt->offset = 0; rcpt->offset = 0;
} }

View File

@ -50,6 +50,10 @@
#include <vstring.h> #include <vstring.h>
#include <msg.h> #include <msg.h>
/* Global library. */
#include <mail_params.h>
/* DNS library. */ /* DNS library. */
#include <dns.h> #include <dns.h>
@ -73,8 +77,11 @@ const char *smtp_unalias_name(const char *name)
* after servicing a limited number of requests, so there is no need to * after servicing a limited number of requests, so there is no need to
* prevent the cache from growing too large, or to expire old entries. * prevent the cache from growing too large, or to expire old entries.
*/ */
if (cache == 0) if (cache == 0) {
cache = htable_create(10); cache = htable_create(10);
if (var_append_dot_mydomain == 0)
smtp_unalias_flags |= RES_DNSRCH;
}
/* /*
* Look up the fqdn. If none is found use the query name instead, so that * Look up the fqdn. If none is found use the query name instead, so that

View File

@ -431,7 +431,7 @@ static int ehlo_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
smtpd_chat_reply(state, "250-SIZE"); smtpd_chat_reply(state, "250-SIZE");
smtpd_chat_reply(state, "250-ETRN"); smtpd_chat_reply(state, "250-ETRN");
#ifdef USE_SASL_AUTH #ifdef USE_SASL_AUTH
if (SMTPD_STAND_ALONE(state) == 0 && var_smtpd_sasl_enable) if (var_smtpd_sasl_enable)
smtpd_chat_reply(state, "250-AUTH %s", state->sasl_mechanism_list); smtpd_chat_reply(state, "250-AUTH %s", state->sasl_mechanism_list);
#endif #endif
smtpd_chat_reply(state, "250 8BITMIME"); smtpd_chat_reply(state, "250 8BITMIME");
@ -624,9 +624,7 @@ static int mail_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
if ((state->msg_size = off_cvt_string(arg + 5)) < 0) if ((state->msg_size = off_cvt_string(arg + 5)) < 0)
state->msg_size = 0; state->msg_size = 0;
#ifdef USE_SASL_AUTH #ifdef USE_SASL_AUTH
} else if (SMTPD_STAND_ALONE(state) == 0 } else if (var_smtpd_sasl_enable && strncasecmp(arg, "AUTH=", 5) == 0) {
&& var_smtpd_sasl_enable
&& strncasecmp(arg, "AUTH=", 5) == 0) {
if ((err = smtpd_sasl_mail_opt(state, arg + 5)) != 0) { if ((err = smtpd_sasl_mail_opt(state, arg + 5)) != 0) {
smtpd_chat_reply(state, "%s", err); smtpd_chat_reply(state, "%s", err);
return (-1); return (-1);
@ -913,6 +911,7 @@ static int data_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv)
if (state->err == CLEANUP_STAT_OK) { if (state->err == CLEANUP_STAT_OK) {
state->error_count = 0; state->error_count = 0;
state->error_mask = 0; state->error_mask = 0;
state->junk_cmds = 0;
smtpd_chat_reply(state, "250 Ok: queued as %s", state->queue_id); smtpd_chat_reply(state, "250 Ok: queued as %s", state->queue_id);
} else if ((state->err & CLEANUP_STAT_BAD) != 0) { } else if ((state->err & CLEANUP_STAT_BAD) != 0) {
state->error_mask |= MAIL_ERROR_SOFTWARE; state->error_mask |= MAIL_ERROR_SOFTWARE;

View File

@ -92,6 +92,8 @@ void smtpd_state_init(SMTPD_STATE *state, VSTREAM *stream)
state->junk_cmds = 0; state->junk_cmds = 0;
#ifdef USE_SASL_AUTH #ifdef USE_SASL_AUTH
if (SMTPD_STAND_ALONE(state))
var_smtpd_sasl_enable = 0;
if (var_smtpd_sasl_enable) if (var_smtpd_sasl_enable)
smtpd_sasl_connect(state); smtpd_sasl_connect(state);
#endif #endif

View File

@ -13,8 +13,6 @@
/* DESCRIPTION /* DESCRIPTION
/* dict_pcre_open() opens the named file and compiles the contained /* dict_pcre_open() opens the named file and compiles the contained
/* regular expressions. /* regular expressions.
/*
/* The lookup interface will match only user@domain form addresses.
/* SEE ALSO /* SEE ALSO
/* dict(3) generic dictionary manager /* dict(3) generic dictionary manager
/* AUTHOR(S) /* AUTHOR(S)

View File

@ -13,8 +13,6 @@
/* DESCRIPTION /* DESCRIPTION
/* dict_regexp_open() opens the named file and compiles the contained /* dict_regexp_open() opens the named file and compiles the contained
/* regular expressions. /* regular expressions.
/*
/* The lookup interface will match only user@domain form addresses.
/* SEE ALSO /* SEE ALSO
/* dict(3) generic dictionary manager /* dict(3) generic dictionary manager
/* AUTHOR(S) /* AUTHOR(S)

View File

@ -213,7 +213,7 @@
/* value arguments. /* value arguments.
/* .IP "VSTREAM_CTL_READ_FN (int (*)(int, void *, unsigned, int, void *))" /* .IP "VSTREAM_CTL_READ_FN (int (*)(int, void *, unsigned, int, void *))"
/* The argument specifies an alternative for the timed_read(3) function, /* The argument specifies an alternative for the timed_read(3) function,
/* for example, a read function that performs encryption. /* for example, a read function that performs decryption.
/* .IP "VSTREAM_CTL_WRITE_FN (int (*)(int, void *, unsigned, int, void *))" /* .IP "VSTREAM_CTL_WRITE_FN (int (*)(int, void *, unsigned, int, void *))"
/* The argument specifies an alternative for the timed_write(3) function, /* The argument specifies an alternative for the timed_write(3) function,
/* for example, a write function that performs encryption. /* for example, a write function that performs encryption.