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

postfix-2.4-20060823

This commit is contained in:
Wietse Venema 2006-08-23 00:00:00 -05:00 committed by Viktor Dukhovni
parent 05d7ee7dca
commit 0e961e79a8
36 changed files with 1104 additions and 83 deletions

View File

@ -12628,9 +12628,10 @@ Apologies for any names omitted.
limit in the SMTP server didn't work for size limits close
enough to INT_MAX. File: smtpd/smtpd.c.
Bugfix: after an SMTP client was rejected with "smtpd_delay_reject
= no", the SMTP server would panic as it generated spurious
Milter requests for unrecognized commands. File: smtpd/smtpd.c.
Bugfix (introduced Postfix 2.3): after an SMTP client was
rejected with "smtpd_delay_reject = no", the SMTP server
would panic as it generated spurious Milter requests for
unrecognized commands. File: smtpd/smtpd.c.
20060727
@ -12640,8 +12641,9 @@ Apologies for any names omitted.
20060805
Bugfix: #ifdef damage caused smtp_sasl_start() to be invoked
twice. Reported by C-J Lofstedt. File: smtp/smtp_sasl_proto.c.
Bugfix (introduced Postfix 2.3): #ifdef damage caused
smtp_sasl_start() to be invoked twice. Reported by C-J
Lofstedt. File: smtp/smtp_sasl_proto.c.
20060806
@ -12650,8 +12652,63 @@ Apologies for any names omitted.
helpdesk service that solves all their email problems.
Credits to Jonathan Balester. File: bounce/bounce_templates.c.
20060807
Bugfix (introduced Postfix 2.2): when upgrading from Postfix
< 2.2 with the third-party TLS patch, the post-install
upgrade procedure didn't put a "?" in the existing tlsmgr
entry, causing tlsmgr to repeatedly start and exit when TLS
support was not compiled in. File: conf/post-install.
20060812
Bugfix (introduced < Postfix alpha): safety mechanism in
mail_date() didn't work. Found in code review. File:
global/mail_date.c.
20060817
Test programs for host address->name and name->address
lookups to debug name service inconsistencies, typically
when the Postfix SMTP server claims that a hostname is
"unknown". Files: auxiliary/name-addr-test/*.
20060822
Added missing logging for "message to large" etc. Files:
smtpd/smtpd.c, cleanup/cleanup_milter.c.
20060823
Bugfix (introduced Postfix 2.2): vstream_fdclose() did not
flush unwritten output before disconnecting a stream from
its file descriptor. File: util/vstream.c.
Bugfix (introduced Postfix 2.2): segfault when vstream_fclose()
attempted to flush unwritten output, after vstream_fdclose()
disconnected the stream from its file descriptor. File:
util/vstream.c.
Feature: smtp-sink can capture mail to file, either as one
individual message per file, or as multiple messages per
file. After an initial implementation by Weidong Cui. File:
smtpstone/smtp-sink.c.
Bugfix (introduced < Postfix alpha): smtp-sink did not
correctly recognize DOT-CR-LF immediately after DATA. File:
smtpstone/smtp-sink.c.
Cleanup: smtp-sink now requires that MAIL FROM, RCPT TO and
DATA be send in the correct order. This simplified the
implementation of the capture to file feature. File:
smtpstone/smtp-sink.c.
Wish list:
Make null local-part handling configurable: either expand
into mailer-daemon (current bahavior) or disallow (strict
behavior, currently implemented only in the SMTP server).
The type of var_message_limit should be changed from int
to long or better, to take advantage of LP64 architectures.
This also requires checking all expressions in which

View File

@ -49,10 +49,11 @@ Alternatively, for the D.J.B. version of CDB:
"AUXLIBS=$CDB/cdb.a $CDB/alloc.a $CDB/buffer.a $CDB/unix.a $CDB/byte.a"
% make
After postfix has been built with cdb support, you can use "cdb" tables
After Postfix has been built with cdb support, you can use "cdb" tables
wherever you can use read-only "hash", "btree" or "dbm" tables. However, the
"ppoossttmmaapp --ii" (incremental record insertion) and "ppoossttmmaapp --dd" (incremental
record deletion) command-line options are not available. For the same reason
the "cdb" map type cannot be used to store the persistent address verification
cache for the verify(8) service.
cache for the verify(8) service, or to store TLS session information for the
tlsmgr(8) service.

View File

@ -61,24 +61,23 @@ Needless to say, these commands are not available in earlier Postfix versions.
BBuuiillddiinngg PPoossttffiixx wwiitthh DDoovveeccoott SSAASSLL ssuuppppoorrtt
Dovecot SASL support is available in Postfix 2.3 and later. The Dovecot source
code is available via http://www.dovecot.org/. At the time of writing, only
server-side SASL support is available, so you can't use it to authenticate to
your network provider's server. Dovecot uses its own daemon process for
authentication. This keeps the Postfix build process simple, because there is
no need to link extra libraries into Postfix.
Support for the Dovecot version 1 SASL protocol is available in Postfix 2.3 and
later. At the time of writing, only server-side SASL support is available, so
you can't use it to authenticate to your network provider's server. Dovecot
uses its own daemon process for authentication. This keeps the Postfix build
process simple, because there is no need to link extra libraries into Postfix.
To generate the necessary Makefiles, execute the following in the Postfix top-
level directory:
% make makefiles CCARGS='-DUSE_SASL_AUTH -
DDEF_SASL_SERVER_TYPE=\"dovecot\"'
DDEF_SERVER_SASL_TYPE=\"dovecot\"'
After this, proceed with "make" as described in the INSTALL document.
Notes:
* The "-DDEF_SASL_SERVER_TYPE" stuff is not necessary; it just makes Postfix
* The "-DDEF_SERVER_SASL_TYPE" stuff is not necessary; it just makes Postfix
configuration a little more convenient because you don't have to specify
the SASL plug-in type in the Postfix main.cf file.

View File

@ -0,0 +1,64 @@
/*
* getaddrinfo(3) (name->address lookup) tester.
*
* Compile with:
*
* cc -o getaddrinfo getaddrinfo.c (BSD, Linux)
*
* cc -o getaddrinfo getaddrinfo.c -lsocket -lnsl (SunOS 5.x)
*
* Run as: getaddrinfo hostname
*
* Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
*
* Author: Wietse Venema, IBM T.J. Watson Research, USA.
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
char hostbuf[NI_MAXHOST]; /* XXX */
struct addrinfo hints;
struct addrinfo *res0;
struct addrinfo *res;
const char *addr;
int err;
#define NO_SERVICE ((char *) 0)
if (argc != 2) {
fprintf(stderr, "usage: %s hostname\n", argv[0]);
exit(1);
}
memset((char *) &hints, 0, sizeof(hints));
hints.ai_family = PF_UNSPEC;
hints.ai_flags = AI_CANONNAME;
hints.ai_socktype = SOCK_STREAM;
if ((err = getaddrinfo(argv[1], NO_SERVICE, &hints, &res0)) != 0) {
fprintf(stderr, "host %s not found\n", argv[1]);
exit(1);
}
printf("Hostname:\t%s\n", res0->ai_canonname);
printf("Addresses:\t");
for (res = res0; res != 0; res = res->ai_next) {
addr = (res->ai_family == AF_INET ?
(char *) &((struct sockaddr_in *) res->ai_addr)->sin_addr :
(char *) &((struct sockaddr_in6 *) res->ai_addr)->sin6_addr);
if (inet_ntop(res->ai_family, addr, hostbuf, sizeof(hostbuf)) == 0) {
perror("inet_ntop:");
exit(1);
}
printf("%s ", hostbuf);
}
printf("\n");
freeaddrinfo(res0);
exit(0);
}

View File

@ -0,0 +1,46 @@
/*
* gethostbyaddr tester. compile with:
*
* cc -o gethostbyaddr gethostbyaddr.c (SunOS 4.x)
*
* cc -o gethostbyaddr gethostbyaddr.c -lnsl (SunOS 5.x)
*
* run as: gethostbyaddr address
*
* Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
main(argc, argv)
int argc;
char **argv;
{
struct hostent *hp;
long addr;
if (argc != 2) {
fprintf(stderr, "usage: %s i.p.addres\n", argv[0]);
exit(1);
}
addr = inet_addr(argv[1]);
if (hp = gethostbyaddr((char *) &addr, sizeof(addr), AF_INET)) {
printf("Hostname:\t%s\n", hp->h_name);
printf("Aliases:\t");
while (hp->h_aliases[0])
printf("%s ", *hp->h_aliases++);
printf("\n");
printf("Addresses:\t");
while (hp->h_addr_list[0])
printf("%s ", inet_ntoa(*(struct in_addr *) * hp->h_addr_list++));
printf("\n");
exit(0);
}
fprintf(stderr, "host %s not found\n", argv[1]);
exit(1);
}

View File

@ -0,0 +1,44 @@
/*
* gethostbyname tester. compile with:
*
* cc -o gethostbyname gethostbyname.c (SunOS 4.x)
*
* cc -o gethostbyname gethostbyname.c -lnsl (SunOS 5.x)
*
* run as: gethostbyname hostname
*
* Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
main(argc, argv)
int argc;
char **argv;
{
struct hostent *hp;
if (argc != 2) {
fprintf(stderr, "usage: %s hostname\n", argv[0]);
exit(1);
}
if (hp = gethostbyname(argv[1])) {
printf("Hostname:\t%s\n", hp->h_name);
printf("Aliases:\t");
while (hp->h_aliases[0])
printf("%s ", *hp->h_aliases++);
printf("\n");
printf("Addresses:\t");
while (hp->h_addr_list[0])
printf("%s ", inet_ntoa(*(struct in_addr *) * hp->h_addr_list++));
printf("\n");
exit(0);
} else {
fprintf(stderr, "host %s not found\n", argv[1]);
exit(1);
}
}

View File

@ -0,0 +1,79 @@
/*
* getnameinfo(3) (address->name lookup) tester.
*
* Compile with:
*
* cc -o getnameinfo getnameinfo.c (BSD, Linux)
*
* cc -o getnameinfo getnameinfo.c -lsocket -lnsl (SunOS 5.x)
*
* Run as: getnameinfo address
*
* Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
*
* Author: Wietse Venema, IBM T.J. Watson Research, USA.
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
char hostbuf[NI_MAXHOST]; /* XXX */
struct addrinfo hints;
struct addrinfo *res0;
struct addrinfo *res;
const char *host;
const char *addr;
int err;
#define NO_SERVICE ((char *) 0)
if (argc != 2) {
fprintf(stderr, "usage: %s ipaddres\n", argv[0]);
exit(1);
}
/*
* Convert address to internal form.
*/
host = argv[1];
memset((char *) &hints, 0, sizeof(hints));
hints.ai_family = (strchr(host, ':') ? AF_INET6 : AF_INET);
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags |= AI_NUMERICHOST;
if ((err = getaddrinfo(host, NO_SERVICE, &hints, &res0)) != 0) {
fprintf(stderr, "getaddrinfo %s: %s\n", host, gai_strerror(err));
exit(1);
}
/*
* Convert host address to name.
*/
for (res = res0; res != 0; res = res->ai_next) {
err = getnameinfo(res->ai_addr, res->ai_addrlen,
hostbuf, sizeof(hostbuf),
NO_SERVICE, 0, NI_NAMEREQD);
if (err) {
fprintf(stderr, "getnameinfo %s: %s\n", host, gai_strerror(err));
exit(1);
}
printf("Hostname:\t%s\n", hostbuf);
addr = (res->ai_family == AF_INET ?
(char *) &((struct sockaddr_in *) res->ai_addr)->sin_addr :
(char *) &((struct sockaddr_in6 *) res->ai_addr)->sin6_addr);
if (inet_ntop(res->ai_family, addr, hostbuf, sizeof(hostbuf)) == 0) {
perror("inet_ntop:");
exit(1);
}
printf("Address:\t%s\n", hostbuf);
}
freeaddrinfo(res0);
exit(0);
}

View File

@ -643,6 +643,7 @@ EOF
ed $config_directory/master.cf <<EOF || exit 1
/^tlsmgr[ ]*fifo[ ]/
s/fifo/unix/
s/[0-9][0-9]*/&?/
p
w
q

View File

@ -79,10 +79,11 @@ like: </p>
</pre>
</blockquote>
<p> After postfix has been built with cdb support, you can use
<p> After Postfix has been built with cdb support, you can use
"cdb" tables wherever you can use read-only "hash", "btree" or
"dbm" tables. However, the "<b>postmap -i</b>" (incremental record
insertion) and "<b>postmap -d</b>" (incremental record deletion)
command-line options are not available. For the same reason the
"cdb" map type cannot be used to store the persistent address
verification cache for the <a href="verify.8.html">verify(8)</a> service. </p>
verification cache for the <a href="verify.8.html">verify(8)</a> service, or to store
TLS session information for the <a href="tlsmgr.8.html">tlsmgr(8)</a> service. </p>

View File

@ -113,9 +113,8 @@ Postfix versions. </p>
<h2><a name="build_dovecot">Building Postfix with Dovecot SASL
support</a></h2>
<p> Dovecot SASL support is available in Postfix 2.3 and later. The
Dovecot source code is available via <a href="http://www.dovecot.org/">http://www.dovecot.org/</a>. At
the time
<p> Support for the Dovecot version 1 SASL protocol is available
in Postfix 2.3 and later. At the time
of writing, only server-side SASL support is available, so you can't
use it to authenticate to your network provider's server. Dovecot
uses its own daemon process for authentication. This keeps the
@ -127,7 +126,7 @@ in the Postfix top-level directory: </p>
<blockquote>
<pre>
% make makefiles CCARGS='-DUSE_SASL_AUTH -DDEF_SASL_SERVER_TYPE=\"dovecot\"'
% make makefiles CCARGS='-DUSE_SASL_AUTH -DDEF_SERVER_SASL_TYPE=\"dovecot\"'
</pre>
</blockquote>
@ -138,7 +137,7 @@ in the Postfix top-level directory: </p>
<ul>
<li> <p> The "-DDEF_SASL_SERVER_TYPE" stuff is not necessary; it just
<li> <p> The "-DDEF_SERVER_SASL_TYPE" stuff is not necessary; it just
makes Postfix configuration a little more convenient because you
don't have to specify the SASL plug-in type in the Postfix <a href="postconf.5.html">main.cf</a>
file. </p>

View File

@ -147,8 +147,8 @@ MASTER(5) MASTER(5)
mented by connecting to the service and sending a
wake up request. A ? at the end of the wake-up
time field requests that no wake up events be sent
before the service is used. Specify 0 for no auto-
matic wake up.
before the first time a service is used. Specify 0
for no automatic wake up.
The <a href="pickup.8.html"><b>pickup</b>(8)</a>, <a href="qmgr.8.html"><b>qmgr</b>(8)</a> and <a href="flush.8.html"><b>flush</b>(8)</a> daemons require
a wake up timer.

View File

@ -5508,6 +5508,11 @@ may wish to turn on the policy (UCE and mail relaying) and protocol
error (broken mail software) reports.
</p>
<p> NOTE: postmaster notifications may contain confidential information
such as SASL passwords or message content. It is the system
administrator's responsibility to treat such information with care.
</p>
<p>
The error classes are:
</p>
@ -11823,7 +11828,8 @@ message contains no To: or Cc: message header. </p>
<p>
The numerical Postfix SMTP server response code when a sender or
recipient address is rejected by the <a href="postconf.5.html#reject_unknown_sender_domain">reject_unknown_sender_domain</a>
or <a href="postconf.5.html#reject_unknown_recipient_domain">reject_unknown_recipient_domain</a> restriction.
or <a href="postconf.5.html#reject_unknown_recipient_domain">reject_unknown_recipient_domain</a> restriction. The response is
always 450 in case of a temporary DNS error.
</p>
<p>

View File

@ -23,6 +23,12 @@ QMQP-SINK(1) QMQP-SINK(1)
and IPv6 are the default. This program is the complement
of the <a href="qmqp-source.1.html"><b>qmqp-source</b>(1)</a> program.
Note: this is an unsupported test program. No attempt is
made to maintain compatibility between successive ver-
sions.
Arguments:
<b>-4</b> Support IPv4 only. This option has no effect when
Postfix is built without IPv6 support.

View File

@ -21,7 +21,11 @@ QMQP-SOURCE(1) QMQP-SOURCE(1)
protocol. Connections can be made to UNIX-domain and IPv4
or IPv6 servers. IPv4 and IPv6 are the default.
Options:
Note: this is an unsupported test program. No attempt is
made to maintain compatibility between successive ver-
sions.
Arguments:
<b>-4</b> Connect to the server with IPv4. This option has no
effect when Postfix is built without IPv6 support.

View File

@ -20,11 +20,21 @@ SMTP-SINK(1) SMTP-SINK(1)
away. The purpose is to measure client performance, not
protocol compliance.
<b>smtp-sink</b> may also be configured to capture each mail
delivery transaction to file. Since disk latencies are
large compared to network delays, this mode of operation
can reduce the maximal performance by several orders of
magnitude.
Connections can be accepted on IPv4 or IPv6 endpoints, or
on UNIX-domain sockets. IPv4 and IPv6 are the default.
This program is the complement of the <a href="smtp-source.1.html"><b>smtp-source</b>(1)</a> pro-
gram.
Note: this is an unsupported test program. No attempt is
made to maintain compatibility between successive ver-
sions.
Arguments:
<b>-4</b> Support IPv4 only. This option has no effect when
@ -43,6 +53,30 @@ SMTP-SINK(1) SMTP-SINK(1)
<b>-C</b> Disable XCLIENT support.
<b>-d</b> <i>dump-template</i>
Dump each mail transaction to a single-message file
whose name is created by expanding the <i>dump-tem-</i>
<i>plate</i> via strftime(3) and appending a pseudo-random
hexadecimal number (example: "%Y%m%d%H/%M." expands
into "2006081203/05.809a62e3"). If the template
contains "/" characters, missing directories are
created automatically. The message dump format is
described below.
Note: this option keeps one capture file open for
every mail transaction in progress.
<b>-D</b> <i>dump-template</i>
Append mail transactions to a multi-message dump
file whose name is created by expanding the <i>dump-</i>
<i>template</i> via strftime(3). If the template contains
"/" characters, missing directories are created
automatically. The message dump format is
described below.
Note: this option keeps one capture file open for
every mail transaction in progress.
<b>-e</b> Do not announce ESMTP support.
<b>-E</b> Do not announce ENHANCEDSTATUSCODES support.
@ -66,6 +100,13 @@ SMTP-SINK(1) SMTP-SINK(1)
<b>-L</b> Enable LMTP instead of SMTP.
<b>-m</b> <i>count</i> (default: 256)
An upper bound on the maximal number of simultane-
ous connections that <b>smtp-sink</b> will handle. This
prevents the process from running out of file
descriptors. Excess connections will stay queued in
the TCP/IP stack.
<b>-n</b> <i>count</i>
Terminate after <i>count</i> sessions. This is for testing
purposes.
@ -105,9 +146,19 @@ SMTP-SINK(1) SMTP-SINK(1)
and use quotes to protect white space from the
shell. Command names are case-insensitive.
<b>-S start-string</b>
An optional string that is prepended to each mes-
sage that is written to a dump file (see the dump
file format description below). The following C
escape sequences are supported: \a (bell), \b
(backslace), \f (formfeed), \n (newline), \r (car-
riage return), \t (horizontal tab), \v (vertical
tab), \<i>ddd</i> (up to three octal digits) and \\ (the
backslash character).
<b>-t</b> <i>timeout</i> (default: 100)
Limit the time for receiving a command or sending a
response. The time limit is specified in seconds.
response. The time limit is specified in seconds.
<b>-v</b> Show the SMTP conversations.
@ -116,7 +167,7 @@ SMTP-SINK(1) SMTP-SINK(1)
mand.
[<b>inet:</b>][<i>host</i>]:<i>port</i>
Listen on network interface <i>host</i> (default: any
Listen on network interface <i>host</i> (default: any
interface) TCP port <i>port</i>. Both <i>host</i> and <i>port</i> may be
specified in numeric or symbolic form.
@ -124,9 +175,76 @@ SMTP-SINK(1) SMTP-SINK(1)
Listen on the UNIX-domain socket at <i>pathname</i>.
<i>backlog</i>
The maximum length the queue of pending connec-
The maximum length the queue of pending connec-
tions, as defined by the <b>listen</b>(2) system call.
<b>DUMP FILE FORMAT</b>
Each dumped message contains a sequence of text lines,
terminated with the newline character. The sequence of
information is as follows:
<b>o</b> The optional string specified with the <b>-S</b> option.
<b>o</b> The <b>smtp-sink</b> generated headers as documented
below.
<b>o</b> The message header and body as received from the
SMTP client.
<b>o</b> An empty line.
The format of the <b>smtp-sink</b> generated headers is as fol-
lows:
<b>X-Client-Addr:</b> <i>text</i>
The client IP address without enclosing []. An IPv6
address is prefixed with "ipv6:". This record is
always present.
<b>X-Client-Proto:</b> <i>text</i>
The client protocol: SMTP, ESMTP or LMTP. This
record is always present.
<b>X-Helo-Args:</b> <i>text</i>
The arguments of the last HELO or EHLO command
before this mail delivery transaction. This record
is present only if the client sent a recognizable
HELO or EHLO command before the DATA command.
<b>X-Mail-Args:</b> <i>text</i>
The arguments, if any, of the MAIL command that
started this mail delivery transaction. This record
is present only if the client sent a recognizable
MAIL command.
<b>X-Rcpt-Args:</b> <i>text</i>
The arguments, if any, of each successive RCPT com-
mand within this mail delivery transaction. There
may be zero or more of these records. This record
is present only if the client sent a recognizable
RCPT command.
<b>Received:</b> <i>text</i>
A message header for compatibility with mail pro-
cessing software. This three-line header marks the
end of the headers provided by <b>smtp-sink</b>, and is
formatted as follows:
<b>from</b> <i>helo</i> <b>([</b><i>addr</i><b>])</b>
The HELO or EHLO command argument and client
IP address. If the client did not send HELO
or EHLO, the client IP address is used
instead.
<b>by</b> <i>host</i> <b>(smtp-sink) with</b> <i>proto</i> <b>id</b> <i>random</i><b>;</b>
The hostname specified with the <b>-h</b> option,
the client protocol (see <b>X-Client-Proto</b>
above), and the pseudo-random portion of the
per-message capture file name.
<i>time-stamp</i>
A time stamp as defined in <a href="http://www.faqs.org/rfcs/rfc2822.html">RFC 2822</a>.
<b>SEE ALSO</b>
<a href="smtp-source.1.html">smtp-source(1)</a>, SMTP/LMTP message generator

View File

@ -22,6 +22,10 @@ SMTP-SOURCE(1) SMTP-SOURCE(1)
UNIX-domain and IPv4 or IPv6 servers. IPv4 and IPv6 are
the default.
Note: this is an unsupported test program. No attempt is
made to maintain compatibility between successive ver-
sions.
Arguments:
<b>-4</b> Connect to the server with IPv4. This option has no

View File

@ -25,6 +25,11 @@ Connections can be accepted on IPv4 or IPv6 endpoints, or on
UNIX-domain sockets.
IPv4 and IPv6 are the default.
This program is the complement of the \fBqmqp-source\fR(1) program.
Note: this is an unsupported test program. No attempt is made
to maintain compatibility between successive versions.
Arguments:
.IP \fB-4\fR
Support IPv4 only. This option has no effect when
Postfix is built without IPv6 support.

View File

@ -21,7 +21,10 @@ or in parallel. The program speaks the QMQP protocol.
Connections can be made to UNIX-domain and IPv4 or IPv6 servers.
IPv4 and IPv6 are the default.
Options:
Note: this is an unsupported test program. No attempt is made
to maintain compatibility between successive versions.
Arguments:
.IP \fB-4\fR
Connect to the server with IPv4. This option has no effect when
Postfix is built without IPv6 support.

View File

@ -21,11 +21,19 @@ It takes SMTP messages from the network and throws them away.
The purpose is to measure client performance, not protocol
compliance.
\fBsmtp-sink\fR may also be configured to capture each mail
delivery transaction to file. Since disk latencies are large
compared to network delays, this mode of operation can
reduce the maximal performance by several orders of magnitude.
Connections can be accepted on IPv4 or IPv6 endpoints, or on
UNIX-domain sockets.
IPv4 and IPv6 are the default.
This program is the complement of the \fBsmtp-source\fR(1) program.
Note: this is an unsupported test program. No attempt is made
to maintain compatibility between successive versions.
Arguments:
.IP \fB-4\fR
Support IPv4 only. This option has no effect when
@ -43,6 +51,27 @@ session ends, a QUIT command is executed, or when "." is
received.
.IP \fB-C\fR
Disable XCLIENT support.
.IP "\fB-d \fIdump-template\fR"
Dump each mail transaction to a single-message file whose
name is created by expanding the \fIdump-template\fR via
strftime(3) and appending a pseudo-random hexadecimal number
(example: "%Y%m%d%H/%M." expands into "2006081203/05.809a62e3").
If the template contains "/" characters, missing directories
are created automatically. The message dump format is
described below.
.sp
Note: this option keeps one capture file open for every
mail transaction in progress.
.IP "\fB-D \fIdump-template\fR"
Append mail transactions to a multi-message dump file whose
name is created by expanding the \fIdump-template\fR via
strftime(3).
If the template contains "/" characters, missing directories
are created automatically. The message dump format is
described below.
.sp
Note: this option keeps one capture file open for every
mail transaction in progress.
.IP \fB-e\fR
Do not announce ESMTP support.
.IP \fB-E\fR
@ -62,6 +91,11 @@ Use \fIhostname\fR in the SMTP greeting, in the HELO response,
and in the EHLO response. The default hostname is "smtp-sink".
.IP \fB-L\fR
Enable LMTP instead of SMTP.
.IP "\fB-m \fIcount\fR (default: 256)"
An upper bound on the maximal number of simultaneous
connections that \fBsmtp-sink\fR will handle. This prevents
the process from running out of file descriptors. Excess
connections will stay queued in the TCP/IP stack.
.IP "\fB-n \fIcount\fR"
Terminate after \fIcount\fR sessions. This is for testing purposes.
.IP \fB-p\fR
@ -92,6 +126,14 @@ Examples of commands are CONNECT, HELO, EHLO, LHLO, MAIL, RCPT, VRFY,
DATA, ., RSET, NOOP, and QUIT. Separate command names by
white space or commas, and use quotes to protect white space
from the shell. Command names are case-insensitive.
.IP "\fB-S start-string\fR"
An optional string that is prepended to each message that is
written to a dump file (see the dump file format description
below). The following C escape sequences are supported: \ea
(bell), \eb (backslace), \ef (formfeed), \en (newline), \er
(carriage return), \et (horizontal tab), \ev (vertical tab),
\e\fIddd\fR (up to three octal digits) and \e\e (the backslash
character).
.IP "\fB-t \fItimeout\fR (default: 100)"
Limit the time for receiving a command or sending a response.
The time limit is specified in seconds.
@ -108,6 +150,62 @@ Listen on the UNIX-domain socket at \fIpathname\fR.
.IP \fIbacklog\fR
The maximum length the queue of pending connections,
as defined by the \fBlisten\fR(2) system call.
.SH "DUMP FILE FORMAT"
.na
.nf
.ad
.fi
Each dumped message contains a sequence of text lines,
terminated with the newline character. The sequence of
information is as follows:
.IP \(bu
The optional string specified with the \fB-S\fR option.
.IP \(bu
The \fBsmtp-sink\fR generated headers as documented below.
.IP \(bu
The message header and body as received from the SMTP client.
.IP \(bu
An empty line.
.PP
The format of the \fBsmtp-sink\fR generated headers is as
follows:
.IP "\fBX-Client-Addr: \fItext\fR"
The client IP address without enclosing []. An IPv6 address
is prefixed with "ipv6:". This record is always present.
.IP "\fBX-Client-Proto: \fItext\fR"
The client protocol: SMTP, ESMTP or LMTP. This record is
always present.
.IP "\fBX-Helo-Args: \fItext\fR"
The arguments of the last HELO or EHLO command before this
mail delivery transaction. This record is present only if
the client sent a recognizable HELO or EHLO command before
the DATA command.
.IP "\fBX-Mail-Args: \fItext\fR"
The arguments, if any, of the MAIL command that started
this mail delivery transaction. This record is present only
if the client sent a recognizable MAIL command.
.IP "\fBX-Rcpt-Args: \fItext\fR"
The arguments, if any, of each successive RCPT command
within this mail delivery transaction. There may be zero
or more of these records. This record is present only if
the client sent a recognizable RCPT command.
.IP "\fBReceived: \fItext\fR"
A message header for compatibility with mail processing
software. This three-line header marks the end of the headers
provided by \fBsmtp-sink\fR, and is formatted
as follows:
.RS
.IP "\fBfrom \fIhelo\fB ([\fIaddr\fB])\fR"
The HELO or EHLO command argument and client IP address.
If the client did not send HELO or EHLO, the client IP
address is used instead.
.IP "\fBby \fIhost\fB (smtp-sink) with \fIproto\fB id \fIrandom\fB;\fR"
The hostname specified with the \fB-h\fR option, the client
protocol (see \fBX-Client-Proto\fR above), and the pseudo-random
portion of the per-message capture file name.
.IP \fItime-stamp\fR
A time stamp as defined in RFC 2822.
.RE
.SH "SEE ALSO"
.na
.nf

View File

@ -23,6 +23,9 @@ LMTP.
Connections can be made to UNIX-domain and IPv4 or IPv6 servers.
IPv4 and IPv6 are the default.
Note: this is an unsupported test program. No attempt is made
to maintain compatibility between successive versions.
Arguments:
.IP \fB-4\fR
Connect to the server with IPv4. This option has no effect when

View File

@ -134,7 +134,7 @@ Automatically wake up the named service after the specified
number of seconds. The wake up is implemented by connecting
to the service and sending a wake up request. A ? at the
end of the wake-up time field requests that no wake up
events be sent before the service is used.
events be sent before the first time a service is used.
Specify 0 for no automatic wake up.
.sp
The \fBpickup\fR(8), \fBqmgr\fR(8) and \fBflush\fR(8)

View File

@ -3019,6 +3019,10 @@ default is to report only the most serious problems. The paranoid
may wish to turn on the policy (UCE and mail relaying) and protocol
error (broken mail software) reports.
.PP
NOTE: postmaster notifications may contain confidential information
such as SASL passwords or message content. It is the system
administrator's responsibility to treat such information with care.
.PP
The error classes are:
.IP "\fBbounce\fR (also implies \fB2bounce\fR)"
Send the postmaster copies of the headers of bounced mail, and
@ -7164,7 +7168,8 @@ message contains no To: or Cc: message header.
.SH unknown_address_reject_code (default: 450)
The numerical Postfix SMTP server response code when a sender or
recipient address is rejected by the reject_unknown_sender_domain
or reject_unknown_recipient_domain restriction.
or reject_unknown_recipient_domain restriction. The response is
always 450 in case of a temporary DNS error.
.PP
Do not change this unless you have a complete understanding of RFC 821.
.SH unknown_client_reject_code (default: 450)

View File

@ -79,10 +79,11 @@ like: </p>
</pre>
</blockquote>
<p> After postfix has been built with cdb support, you can use
<p> After Postfix has been built with cdb support, you can use
"cdb" tables wherever you can use read-only "hash", "btree" or
"dbm" tables. However, the "<b>postmap -i</b>" (incremental record
insertion) and "<b>postmap -d</b>" (incremental record deletion)
command-line options are not available. For the same reason the
"cdb" map type cannot be used to store the persistent address
verification cache for the verify(8) service. </p>
verification cache for the verify(8) service, or to store
TLS session information for the tlsmgr(8) service. </p>

View File

@ -113,9 +113,8 @@ Postfix versions. </p>
<h2><a name="build_dovecot">Building Postfix with Dovecot SASL
support</a></h2>
<p> Dovecot SASL support is available in Postfix 2.3 and later. The
Dovecot source code is available via http://www.dovecot.org/. At
the time
<p> Support for the Dovecot version 1 SASL protocol is available
in Postfix 2.3 and later. At the time
of writing, only server-side SASL support is available, so you can't
use it to authenticate to your network provider's server. Dovecot
uses its own daemon process for authentication. This keeps the
@ -127,7 +126,7 @@ in the Postfix top-level directory: </p>
<blockquote>
<pre>
% make makefiles CCARGS='-DUSE_SASL_AUTH -DDEF_SASL_SERVER_TYPE=\"dovecot\"'
% make makefiles CCARGS='-DUSE_SASL_AUTH -DDEF_SERVER_SASL_TYPE=\"dovecot\"'
</pre>
</blockquote>
@ -138,7 +137,7 @@ INSTALL document. </p>
<ul>
<li> <p> The "-DDEF_SASL_SERVER_TYPE" stuff is not necessary; it just
<li> <p> The "-DDEF_SERVER_SASL_TYPE" stuff is not necessary; it just
makes Postfix configuration a little more convenient because you
don't have to specify the SASL plug-in type in the Postfix main.cf
file. </p>

View File

@ -128,7 +128,7 @@
# number of seconds. The wake up is implemented by connecting
# to the service and sending a wake up request. A ? at the
# end of the wake-up time field requests that no wake up
# events be sent before the service is used.
# events be sent before the first time a service is used.
# Specify 0 for no automatic wake up.
# .sp
# The \fBpickup\fR(8), \fBqmgr\fR(8) and \fBflush\fR(8)

View File

@ -2801,6 +2801,11 @@ may wish to turn on the policy (UCE and mail relaying) and protocol
error (broken mail software) reports.
</p>
<p> NOTE: postmaster notifications may contain confidential information
such as SASL passwords or message content. It is the system
administrator's responsibility to treat such information with care.
</p>
<p>
The error classes are:
</p>
@ -5894,7 +5899,8 @@ The default time unit is s (seconds).
<p>
The numerical Postfix SMTP server response code when a sender or
recipient address is rejected by the reject_unknown_sender_domain
or reject_unknown_recipient_domain restriction.
or reject_unknown_recipient_domain restriction. The response is
always 450 in case of a temporary DNS error.
</p>
<p>

View File

@ -213,10 +213,13 @@
static void cleanup_milter_set_error(CLEANUP_STATE *state, int err)
{
if (err == EFBIG)
if (err == EFBIG) {
msg_warn("%s: queue file size limit exceeded", state->queue_id);
state->errs |= CLEANUP_STAT_SIZE;
else
} else {
msg_warn("%s: write queue file: %m", state->queue_id);
state->errs |= CLEANUP_STAT_WRITE;
}
}
/* cleanup_milter_error - return dummy error description */

View File

@ -121,7 +121,7 @@ const char *mail_date(time_t when)
* Finally, add the time zone name.
*/
while (strftime(vstring_end(vp), vstring_avail(vp), " (%Z)", lt) == 0)
VSTRING_SPACE(vp, 100);
VSTRING_SPACE(vp, vstring_avail(vp) + 100);
VSTRING_SKIP(vp);
return (vstring_str(vp));

View File

@ -20,7 +20,7 @@
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
#define MAIL_RELEASE_DATE "20060806"
#define MAIL_RELEASE_DATE "20060823"
#define MAIL_VERSION_NUMBER "2.4"
#ifdef SNAPSHOT

View File

@ -2250,7 +2250,7 @@ static int rcpt_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
}
vstring_strcpy(state->dsn_orcpt_buf, arg + 6);
if (dsn_orcpt_addr
|| (coded_addr = split_at(STR(state->dsn_orcpt_buf), ';')) == 0
|| (coded_addr = split_at(STR(state->dsn_orcpt_buf), ';')) == 0
|| xtext_unquote(state->dsn_buf, coded_addr) == 0
|| *(dsn_orcpt_type = STR(state->dsn_orcpt_buf)) == 0) {
state->error_mask |= MAIL_ERROR_PROTOCOL;
@ -2643,9 +2643,11 @@ static int data_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv)
&& (state->proxy == 0 ? (++start, --len) == 0 : len == 1))
break;
if (state->err == CLEANUP_STAT_OK) {
if (var_message_limit > 0 && var_message_limit - state->act_size < len + 2)
if (var_message_limit > 0 && var_message_limit - state->act_size < len + 2) {
state->err = CLEANUP_STAT_SIZE;
else {
msg_warn("%s: queue file size limit exceeded",
state->queue_id ? state->queue_id : "NOQUEUE");
} else {
state->act_size += len + 2;
if (out_record(out_stream, curr_rec_type, start, len) < 0)
state->err = out_error;

View File

@ -19,6 +19,11 @@
/* UNIX-domain sockets.
/* IPv4 and IPv6 are the default.
/* This program is the complement of the \fBqmqp-source\fR(1) program.
/*
/* Note: this is an unsupported test program. No attempt is made
/* to maintain compatibility between successive versions.
/*
/* Arguments:
/* .IP \fB-4\fR
/* Support IPv4 only. This option has no effect when
/* Postfix is built without IPv6 support.

View File

@ -15,7 +15,10 @@
/* Connections can be made to UNIX-domain and IPv4 or IPv6 servers.
/* IPv4 and IPv6 are the default.
/*
/* Options:
/* Note: this is an unsupported test program. No attempt is made
/* to maintain compatibility between successive versions.
/*
/* Arguments:
/* .IP \fB-4\fR
/* Connect to the server with IPv4. This option has no effect when
/* Postfix is built without IPv6 support.

View File

@ -15,11 +15,19 @@
/* The purpose is to measure client performance, not protocol
/* compliance.
/*
/* \fBsmtp-sink\fR may also be configured to capture each mail
/* delivery transaction to file. Since disk latencies are large
/* compared to network delays, this mode of operation can
/* reduce the maximal performance by several orders of magnitude.
/*
/* Connections can be accepted on IPv4 or IPv6 endpoints, or on
/* UNIX-domain sockets.
/* IPv4 and IPv6 are the default.
/* This program is the complement of the \fBsmtp-source\fR(1) program.
/*
/* Note: this is an unsupported test program. No attempt is made
/* to maintain compatibility between successive versions.
/*
/* Arguments:
/* .IP \fB-4\fR
/* Support IPv4 only. This option has no effect when
@ -37,6 +45,27 @@
/* received.
/* .IP \fB-C\fR
/* Disable XCLIENT support.
/* .IP "\fB-d \fIdump-template\fR"
/* Dump each mail transaction to a single-message file whose
/* name is created by expanding the \fIdump-template\fR via
/* strftime(3) and appending a pseudo-random hexadecimal number
/* (example: "%Y%m%d%H/%M." expands into "2006081203/05.809a62e3").
/* If the template contains "/" characters, missing directories
/* are created automatically. The message dump format is
/* described below.
/* .sp
/* Note: this option keeps one capture file open for every
/* mail transaction in progress.
/* .IP "\fB-D \fIdump-template\fR"
/* Append mail transactions to a multi-message dump file whose
/* name is created by expanding the \fIdump-template\fR via
/* strftime(3).
/* If the template contains "/" characters, missing directories
/* are created automatically. The message dump format is
/* described below.
/* .sp
/* Note: this option keeps one capture file open for every
/* mail transaction in progress.
/* .IP \fB-e\fR
/* Do not announce ESMTP support.
/* .IP \fB-E\fR
@ -56,6 +85,11 @@
/* and in the EHLO response. The default hostname is "smtp-sink".
/* .IP \fB-L\fR
/* Enable LMTP instead of SMTP.
/* .IP "\fB-m \fIcount\fR (default: 256)"
/* An upper bound on the maximal number of simultaneous
/* connections that \fBsmtp-sink\fR will handle. This prevents
/* the process from running out of file descriptors. Excess
/* connections will stay queued in the TCP/IP stack.
/* .IP "\fB-n \fIcount\fR"
/* Terminate after \fIcount\fR sessions. This is for testing purposes.
/* .IP \fB-p\fR
@ -86,6 +120,14 @@
/* DATA, ., RSET, NOOP, and QUIT. Separate command names by
/* white space or commas, and use quotes to protect white space
/* from the shell. Command names are case-insensitive.
/* .IP "\fB-S start-string\fR"
/* An optional string that is prepended to each message that is
/* written to a dump file (see the dump file format description
/* below). The following C escape sequences are supported: \ea
/* (bell), \eb (backslace), \ef (formfeed), \en (newline), \er
/* (carriage return), \et (horizontal tab), \ev (vertical tab),
/* \e\fIddd\fR (up to three octal digits) and \e\e (the backslash
/* character).
/* .IP "\fB-t \fItimeout\fR (default: 100)"
/* Limit the time for receiving a command or sending a response.
/* The time limit is specified in seconds.
@ -102,6 +144,60 @@
/* .IP \fIbacklog\fR
/* The maximum length the queue of pending connections,
/* as defined by the \fBlisten\fR(2) system call.
/* DUMP FILE FORMAT
/* .ad
/* .fi
/* Each dumped message contains a sequence of text lines,
/* terminated with the newline character. The sequence of
/* information is as follows:
/* .IP \(bu
/* The optional string specified with the \fB-S\fR option.
/* .IP \(bu
/* The \fBsmtp-sink\fR generated headers as documented below.
/* .IP \(bu
/* The message header and body as received from the SMTP client.
/* .IP \(bu
/* An empty line.
/* .PP
/* The format of the \fBsmtp-sink\fR generated headers is as
/* follows:
/* .IP "\fBX-Client-Addr: \fItext\fR"
/* The client IP address without enclosing []. An IPv6 address
/* is prefixed with "ipv6:". This record is always present.
/* .IP "\fBX-Client-Proto: \fItext\fR"
/* The client protocol: SMTP, ESMTP or LMTP. This record is
/* always present.
/* .IP "\fBX-Helo-Args: \fItext\fR"
/* The arguments of the last HELO or EHLO command before this
/* mail delivery transaction. This record is present only if
/* the client sent a recognizable HELO or EHLO command before
/* the DATA command.
/* .IP "\fBX-Mail-Args: \fItext\fR"
/* The arguments, if any, of the MAIL command that started
/* this mail delivery transaction. This record is present only
/* if the client sent a recognizable MAIL command.
/* .IP "\fBX-Rcpt-Args: \fItext\fR"
/* The arguments, if any, of each successive RCPT command
/* within this mail delivery transaction. There may be zero
/* or more of these records. This record is present only if
/* the client sent a recognizable RCPT command.
/* .IP "\fBReceived: \fItext\fR"
/* A message header for compatibility with mail processing
/* software. This three-line header marks the end of the headers
/* provided by \fBsmtp-sink\fR, and is formatted
/* as follows:
/* .RS
/* .IP "\fBfrom \fIhelo\fB ([\fIaddr\fB])\fR"
/* The HELO or EHLO command argument and client IP address.
/* If the client did not send HELO or EHLO, the client IP
/* address is used instead.
/* .IP "\fBby \fIhost\fB (smtp-sink) with \fIproto\fB id \fIrandom\fB;\fR"
/* The hostname specified with the \fB-h\fR option, the client
/* protocol (see \fBX-Client-Proto\fR above), and the pseudo-random
/* portion of the per-message capture file name.
/* .IP \fItime-stamp\fR
/* A time stamp as defined in RFC 2822.
/* .RE
/* SEE ALSO
/* smtp-source(1), SMTP/LMTP message generator
/* LICENSE
@ -120,12 +216,15 @@
#include <sys_defs.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <syslog.h>
#include <signal.h>
#include <time.h>
#include <ctype.h>
#ifdef STRCASECMP_IN_STRINGS_H
#include <strings.h>
@ -146,10 +245,14 @@
#include <stringops.h>
#include <sane_accept.h>
#include <inet_proto.h>
#include <myaddrinfo.h>
#include <make_dirs.h>
#include <myrand.h>
/* Global library. */
#include <smtp_stream.h>
#include <mail_date.h>
/* Application-specific. */
@ -158,8 +261,17 @@ typedef struct SINK_STATE {
VSTRING *buffer;
int data_state;
int (*read_fn) (struct SINK_STATE *);
int in_mail;
int rcpts;
char *push_back_ptr;
/* Capture file information for fake Received: header */
MAI_HOSTADDR_STR client_addr; /* IP address */
char *addr_prefix; /* ipv6: or empty */
char *helo_args; /* text after HELO or EHLO */
const char *client_proto; /* SMTP, ESMTP, LMTP */
time_t start_time; /* MAIL command time */
int id; /* pseudo-random */
VSTREAM *dump_file; /* dump file or null */
} SINK_STATE;
#define ST_ANY 0
@ -173,6 +285,10 @@ typedef struct SINK_STATE {
#define PUSH_BACK_GET(state) (*(state)->push_back_ptr++)
#define PUSH_BACK_SET(state, text) ((state)->push_back_ptr = (text))
#ifndef DEF_MAX_CLIENT_COUNT
#define DEF_MAX_CLIENT_COUNT 256
#endif
static int var_tmout = 100;
static int var_max_line_length = 2048;
static char *var_myhostname;
@ -194,10 +310,19 @@ static int disable_saslauth;
static int disable_xclient;
static int disable_xforward;
static int disable_enh_status;
static int max_client_count = DEF_MAX_CLIENT_COUNT;
static int client_count;
static int sock;
static char *single_template; /* individual template */
static char *shared_template; /* shared template */
static VSTRING *start_string; /* dump content prefix */
#define SOFT_ERROR_RESP "450 4.3.0 Error: command failed"
#define HARD_ERROR_RESP "500 5.3.0 Error: command failed"
#define STR(x) vstring_str(x)
/* do_stats - show counters */
static void do_stats(void)
@ -223,10 +348,211 @@ static void soft_err_resp(SINK_STATE *state)
smtp_flush(state->stream);
}
/* exp_path_template - expand template pathname, static result */
static VSTRING *exp_path_template(const char *template, time_t start_time)
{
static VSTRING *path_buf = 0;
struct tm *lt;
if (path_buf == 0)
path_buf = vstring_alloc(100);
else
VSTRING_RESET(path_buf);
lt = localtime(&start_time);
while (strftime(STR(path_buf), vstring_avail(path_buf), template, lt) == 0)
VSTRING_SPACE(path_buf, vstring_avail(path_buf) + 100);
VSTRING_SKIP(path_buf);
return (path_buf);
}
/* make_parent_dir - create parent directory or bust */
static void make_parent_dir(const char *path, mode_t mode)
{
const char *parent;
parent = sane_dirname((VSTRING *) 0, path);
if (make_dirs(parent, mode) < 0)
msg_fatal("mkdir %s: %m", parent);
}
/* mail_file_open - open mail capture file */
static void mail_file_open(SINK_STATE *state)
{
const char *myname = "mail_file_open";
VSTRING *path_buf;
ssize_t len;
int tries = 0;
/*
* Save the start time for later.
*/
time(&(state->start_time));
/*
* Expand the per-message dumpfile pathname template.
*/
path_buf = exp_path_template(single_template, state->start_time);
/*
* Append a random hexadecimal string to the pathname and create a new
* file. Retry with a different path if the file already exists. Create
* intermediate directories on the fly when the template specifies
* multiple pathname segments.
*/
#define ID_FORMAT "%08x"
for (len = VSTRING_LEN(path_buf); /* void */ ; vstring_truncate(path_buf, len)) {
if (++tries > 100)
msg_fatal("%s: something is looping", myname);
state->id = myrand();
vstring_sprintf_append(path_buf, ID_FORMAT, state->id);
if ((state->dump_file = vstream_fopen(STR(path_buf),
O_RDWR | O_CREAT | O_EXCL,
0644)) != 0) {
break;
} else if (errno == EEXIST) {
continue;
} else if (errno == ENOENT) {
make_parent_dir(STR(path_buf), 0755);
continue;
} else {
msg_fatal("open %s: %m", STR(path_buf));
}
}
/*
* Don't leave temporary files behind.
*/
if (shared_template != 0 && unlink(STR(path_buf)) < 0)
msg_fatal("unlink %s: %m", STR(path_buf));
/*
* Do initial header records.
*/
if (start_string)
vstream_fprintf(state->dump_file, "%s", STR(start_string));
vstream_fprintf(state->dump_file, "X-Client-Addr: %s%s\n",
state->addr_prefix, state->client_addr.buf);
vstream_fprintf(state->dump_file, "X-Client-Proto: %s\n", state->client_proto);
if (state->helo_args)
vstream_fprintf(state->dump_file, "X-Helo-Args: %s\n", state->helo_args);
/* Note: there may be more than one recipient. */
}
/* mail_file_finish_header - do final smtp-sink generated header records */
static void mail_file_finish_header(SINK_STATE *state)
{
if (state->helo_args)
vstream_fprintf(state->dump_file, "Received: from %s ([%s%s])\n",
state->helo_args, state->addr_prefix,
state->client_addr.buf);
else
vstream_fprintf(state->dump_file, "Received: from [%s%s] ([%s%s])\n",
state->addr_prefix, state->client_addr.buf,
state->addr_prefix, state->client_addr.buf);
vstream_fprintf(state->dump_file, "\tby %s (smtp-sink)"
" with %s id " ID_FORMAT ";\n",
var_myhostname, state->client_proto, state->id);
vstream_fprintf(state->dump_file, "\t%s\n", mail_date(state->start_time));
}
/* mail_file_cleanup - common cleanup for capture file */
static void mail_file_cleanup(SINK_STATE *state)
{
(void) vstream_fclose(state->dump_file);
state->dump_file = 0;
}
/* mail_file_finish - handle message completion for capture file */
static void mail_file_finish(SINK_STATE *state)
{
/*
* Optionally append the captured message to a shared dumpfile.
*/
if (shared_template) {
const char *out_path;
VSTREAM *out_fp;
ssize_t count;
/*
* Expand the shared dumpfile pathname template.
*/
out_path = STR(exp_path_template(shared_template, state->start_time));
/*
* Open the shared dump file.
*/
#define OUT_OPEN_FLAGS (O_WRONLY | O_CREAT | O_APPEND)
#define OUT_OPEN_MODE 0644
if ((out_fp = vstream_fopen(out_path, OUT_OPEN_FLAGS, OUT_OPEN_MODE))
== 0 && errno == ENOENT) {
make_parent_dir(out_path, 0755);
out_fp = vstream_fopen(out_path, OUT_OPEN_FLAGS, OUT_OPEN_MODE);
}
if (out_fp == 0)
msg_fatal("open %s: %m", out_path);
/*
* Append message content from single-message dump file.
*/
if (vstream_fseek(state->dump_file, 0L, SEEK_SET) < 0)
msg_fatal("seek file %s: %m", VSTREAM_PATH(state->dump_file));
VSTRING_RESET(state->buffer);
for (;;) {
count = vstream_fread(state->dump_file, STR(state->buffer),
vstring_avail(state->buffer));
if (count <= 0)
break;
if (vstream_fwrite(out_fp, STR(state->buffer), count) != count)
msg_fatal("append file %s: %m", out_path);
}
if (vstream_ferror(state->dump_file))
msg_fatal("read file %s: %m", VSTREAM_PATH(state->dump_file));
if (vstream_fclose(out_fp))
msg_fatal("append file %s: %m", out_path);
}
mail_file_cleanup(state);
}
/* mail_file_reset - abort mail to capture file */
static void mail_file_reset(SINK_STATE *state)
{
if (shared_template == 0
&& unlink(VSTREAM_PATH(state->dump_file)) < 0
&& errno != ENOENT)
msg_fatal("unlink %s: %m", VSTREAM_PATH(state->dump_file));
mail_file_cleanup(state);
}
/* mail_cmd_reset - reset mail transaction information */
static void mail_cmd_reset(SINK_STATE *state)
{
state->in_mail = 0;
/* Not: state->rcpts = 0. This breaks the DOT reply with LMTP. */
if (state->dump_file)
mail_file_reset(state);
}
/* ehlo_response - respond to EHLO command */
static void ehlo_response(SINK_STATE *state)
static void ehlo_response(SINK_STATE *state, const char *args)
{
#define SKIP(cp, cond) for (/* void */; *cp && (cond); cp++)
/* EHLO aborts a mail transaction in progress. */
mail_cmd_reset(state);
if (enable_lmtp == 0)
state->client_proto = "ESMTP";
smtp_printf(state->stream, "250-%s", var_myhostname);
if (!disable_pipelining)
smtp_printf(state->stream, "250-PIPELINING");
@ -242,50 +568,107 @@ static void ehlo_response(SINK_STATE *state)
smtp_printf(state->stream, "250-ENHANCEDSTATUSCODES");
smtp_printf(state->stream, "250 ");
smtp_flush(state->stream);
if (single_template) {
if (state->helo_args)
myfree(state->helo_args);
SKIP(args, ISSPACE(*args));
state->helo_args = mystrdup(args);
}
}
/* helo_response - respond to HELO command */
static void helo_response(SINK_STATE *state)
static void helo_response(SINK_STATE *state, const char *args)
{
/* HELO aborts a mail transaction in progress. */
mail_cmd_reset(state);
state->client_proto = "SMTP";
smtp_printf(state->stream, "250 %s", var_myhostname);
smtp_flush(state->stream);
if (single_template) {
if (state->helo_args)
myfree(state->helo_args);
SKIP(args, ISSPACE(*args));
state->helo_args = mystrdup(args);
}
}
/* ok_response - send 250 OK */
static void ok_response(SINK_STATE *state)
static void ok_response(SINK_STATE *state, const char *unused_args)
{
smtp_printf(state->stream, "250 2.0.0 Ok");
smtp_flush(state->stream);
}
/* mail_response - reset recipient count, send 250 OK */
/* rset_response - reset, send 250 OK */
static void mail_response(SINK_STATE *state)
static void rset_response(SINK_STATE *state, const char *unused_args)
{
state->rcpts = 0;
mail_cmd_reset(state);
smtp_printf(state->stream, "250 2.1.0 Ok");
smtp_flush(state->stream);
}
/* mail_response - reset recipient count, send 250 OK */
static void mail_response(SINK_STATE *state, const char *args)
{
if (state->in_mail) {
smtp_printf(state->stream, "503 5.5.1 Error: nested MAIL command");
smtp_flush(state->stream);
return;
}
state->in_mail++;
state->rcpts = 0;
smtp_printf(state->stream, "250 2.1.0 Ok");
smtp_flush(state->stream);
if (single_template) {
mail_file_open(state);
SKIP(args, *args != ':');
SKIP(args, *args == ':');
SKIP(args, ISSPACE(*args));
vstream_fprintf(state->dump_file, "X-Mail-Args: %s\n", args);
}
}
/* rcpt_response - bump recipient count, send 250 OK */
static void rcpt_response(SINK_STATE *state)
static void rcpt_response(SINK_STATE *state, const char *args)
{
if (state->in_mail == 0) {
smtp_printf(state->stream, "503 5.5.1 Error: need MAIL command");
smtp_flush(state->stream);
return;
}
state->rcpts++;
smtp_printf(state->stream, "250 2.1.5 Ok");
smtp_flush(state->stream);
/* Note: there may be more than one recipient per mail transaction. */
if (state->dump_file) {
SKIP(args, *args != ':');
SKIP(args, *args == ':');
SKIP(args, ISSPACE(*args));
vstream_fprintf(state->dump_file, "X-Rcpt-Args: %s\n", args);
}
}
/* data_response - respond to DATA command */
static void data_response(SINK_STATE *state)
static void data_response(SINK_STATE *state, const char *unused_args)
{
if (state->in_mail == 0 || state->rcpts == 0) {
smtp_printf(state->stream, "503 5.5.1 Error: need RCPT command");
smtp_flush(state->stream);
return;
}
/* Not: ST_ANY. */
state->data_state = ST_CR_LF;
smtp_printf(state->stream, "354 End data with <CR><LF>.<CR><LF>");
smtp_flush(state->stream);
state->read_fn = data_read;
if (state->dump_file)
mail_file_finish_header(state);
}
/* data_event - delayed response to DATA command */
@ -294,7 +677,7 @@ static void data_event(int unused_event, char *context)
{
SINK_STATE *state = (SINK_STATE *) context;
data_response(state);
data_response(state, "");
}
/* dot_resp_hard - hard error response to . command */
@ -325,7 +708,7 @@ static void dot_resp_soft(SINK_STATE *state)
/* dot_response - response to . command */
static void dot_response(SINK_STATE *state)
static void dot_response(SINK_STATE *state, const char *unused_args)
{
if (enable_lmtp) {
while (state->rcpts-- > 0) /* XXX this could block */
@ -338,7 +721,7 @@ static void dot_response(SINK_STATE *state)
/* quit_response - respond to QUIT command */
static void quit_response(SINK_STATE *state)
static void quit_response(SINK_STATE *state, const char *unused_args)
{
smtp_printf(state->stream, "221 Bye");
smtp_flush(state->stream);
@ -348,7 +731,7 @@ static void quit_response(SINK_STATE *state)
/* conn_response - respond to connect command */
static void conn_response(SINK_STATE *state)
static void conn_response(SINK_STATE *state, const char *unused_args)
{
if (pretend_pix)
smtp_printf(state->stream, "220 ********");
@ -400,10 +783,19 @@ static int data_read(SINK_STATE *state)
state->data_state = data_trans[0].next_state;
else
state->data_state = ST_ANY;
if (state->dump_file) {
if (ch != '\r' && state->data_state != ST_CR_LF_DOT)
VSTREAM_PUTC(ch, state->dump_file);
if (vstream_ferror(state->dump_file))
msg_fatal("append file %s: %m", VSTREAM_PATH(state->dump_file));
}
if (state->data_state == ST_CR_LF_DOT_CR_LF) {
PUSH_BACK_SET(state, ".\r\n");
state->read_fn = command_read;
state->data_state = ST_ANY;
if (state->dump_file)
mail_file_finish(state);
mail_cmd_reset(state);
if (count) {
mesg_count++;
do_stats();
@ -427,7 +819,7 @@ static int data_read(SINK_STATE *state)
*/
typedef struct SINK_COMMAND {
const char *name;
void (*response) (SINK_STATE *);
void (*response) (SINK_STATE *, const char *);
void (*hard_response) (SINK_STATE *);
void (*soft_response) (SINK_STATE *);
int flags;
@ -451,7 +843,7 @@ static SINK_COMMAND command_table[] = {
"rcpt", rcpt_response, hard_err_resp, soft_err_resp, FLAG_ENABLE,
"data", data_response, hard_err_resp, soft_err_resp, FLAG_ENABLE,
".", dot_response, dot_resp_hard, dot_resp_soft, FLAG_ENABLE,
"rset", ok_response, hard_err_resp, soft_err_resp, FLAG_ENABLE,
"rset", rset_response, hard_err_resp, soft_err_resp, FLAG_ENABLE,
"noop", ok_response, hard_err_resp, soft_err_resp, FLAG_ENABLE,
"vrfy", ok_response, hard_err_resp, soft_err_resp, FLAG_ENABLE,
"quit", quit_response, hard_err_resp, soft_err_resp, FLAG_ENABLE,
@ -502,11 +894,12 @@ static void set_cmds_flags(const char *cmds, int flags)
/* command_resp - respond to command */
static int command_resp(SINK_STATE *state, SINK_COMMAND *cmdp, const char *command, char *args)
static int command_resp(SINK_STATE *state, SINK_COMMAND *cmdp,
const char *command, const char *args)
{
/* We use raw syslog. Sanitize data content and length. */
if (cmdp->flags & FLAG_SYSLOG)
syslog(LOG_INFO, "%s %.100s", command, printable(args, '?'));
syslog(LOG_INFO, "%s %.100s", command, args);
if (cmdp->flags & FLAG_DISCONNECT)
return (-1);
if (cmdp->flags & FLAG_HARD_ERR) {
@ -520,7 +913,7 @@ static int command_resp(SINK_STATE *state, SINK_COMMAND *cmdp, const char *comma
if (cmdp->response == data_response && fixed_delay > 0) {
event_request_timer(data_event, (char *) state, fixed_delay);
} else {
cmdp->response(state);
cmdp->response(state, args);
if (cmdp->response == quit_response)
return (-1);
}
@ -604,7 +997,7 @@ static int command_read(SINK_STATE *state)
*/
vstring_truncate(state->buffer, VSTRING_LEN(state->buffer) - 2);
VSTRING_TERMINATE(state->buffer);
state->data_state = ST_ANY;
state->data_state = ST_CR_LF;
VSTRING_RESET(state->buffer);
/*
@ -626,7 +1019,7 @@ static int command_read(SINK_STATE *state)
smtp_flush(state->stream);
return (0);
}
return (command_resp(state, cmdp, command, ptr));
return (command_resp(state, cmdp, command, printable(ptr, '?')));
}
/* read_timeout - handle timer event */
@ -698,6 +1091,8 @@ static void read_event(int unused_event, char *context)
static void disconnect(SINK_STATE *state)
{
static void connect_event(int, char *);
event_disable_readwrite(vstream_fileno(state->stream));
event_cancel_timer(read_timeout, (char *) state);
if (count) {
@ -706,24 +1101,36 @@ static void disconnect(SINK_STATE *state)
}
vstream_fclose(state->stream);
vstring_free(state->buffer);
/* Clean up file capture attributes. */
if (state->helo_args)
myfree(state->helo_args);
/* Delete incomplete mail transaction. */
mail_cmd_reset(state);
myfree((char *) state);
if (max_quit_count > 0 && quit_count >= max_quit_count)
exit(0);
if (client_count-- == max_client_count)
event_enable_read(sock, connect_event, (char *) 0);
}
/* connect_event - handle connection events */
static void connect_event(int unused_event, char *context)
static void connect_event(int unused_event, char *unused_context)
{
int sock = CAST_CHAR_PTR_TO_INT(context);
struct sockaddr sa;
SOCKADDR_SIZE len = sizeof(sa);
SINK_STATE *state;
int fd;
if ((fd = sane_accept(sock, &sa, &len)) >= 0) {
/* Safety: limit the number of open sockets and capture files. */
if (++client_count == max_client_count)
event_disable_readwrite(sock);
state = (SINK_STATE *) mymalloc(sizeof(*state));
SOCKADDR_TO_HOSTADDR(&sa, len, &state->client_addr,
(MAI_SERVPORT_STR *) 0, sa.sa_family);
if (msg_verbose)
msg_info("connect (%s)",
msg_info("connect (%s %s)",
#ifdef AF_LOCAL
sa.sa_family == AF_LOCAL ? "AF_LOCAL" :
#else
@ -733,15 +1140,24 @@ static void connect_event(int unused_event, char *context)
#ifdef AF_INET6
sa.sa_family == AF_INET6 ? "AF_INET6" :
#endif
"unknown protocol family");
"unknown protocol family",
state->client_addr.buf);
non_blocking(fd, NON_BLOCKING);
state = (SINK_STATE *) mymalloc(sizeof(*state));
state->stream = vstream_fdopen(fd, O_RDWR);
state->buffer = vstring_alloc(1024);
state->read_fn = command_read;
state->data_state = ST_ANY;
PUSH_BACK_SET(state, "");
smtp_timeout_setup(state->stream, var_tmout);
state->in_mail = 0;
state->rcpts = 0;
/* Initialize file capture attributes. */
state->addr_prefix = (sa.sa_family == AF_INET6 ? "ipv6:" : "");
state->helo_args = 0;
state->client_proto = enable_lmtp ? "LMTP" : "SMTP";
state->start_time = 0;
state->id = 0;
state->dump_file = 0;
/*
* We use the smtp_stream module to produce output. That module
@ -780,12 +1196,11 @@ static void connect_event(int unused_event, char *context)
static void usage(char *myname)
{
msg_fatal("usage: %s [-468acCeEFLpPv] [-f commands] [-h hostname] [-n count] [-q commands] [-r commands] [-s commands] [-w delay] [host]:port backlog", myname);
msg_fatal("usage: %s [-468acCeEFLpPv] [-f commands] [-h hostname] [-m max_concurrency] [-n quit_count] [-q commands] [-r commands] [-s commands] [-w delay] [-d dump-template] [-D dump-template] [-S start-string] [host]:port backlog", myname);
}
int main(int argc, char **argv)
{
int sock;
int backlog;
int ch;
const char *protocols = INET_PROTO_NAME_ALL;
@ -804,7 +1219,7 @@ int main(int argc, char **argv)
/*
* Parse JCL.
*/
while ((ch = GETOPT(argc, argv, "468acCeEf:Fh:Ln:pPq:r:s:t:vw:")) > 0) {
while ((ch = GETOPT(argc, argv, "468acCeEf:Fh:Ln:m:pPq:r:s:S:t:vw:d:D:")) > 0) {
switch (ch) {
case '4':
protocols = INET_PROTO_NAME_IPV4;
@ -825,6 +1240,12 @@ int main(int argc, char **argv)
disable_xclient = 1;
reset_cmd_flags("xclient", FLAG_ENABLE);
break;
case 'd':
single_template = optarg;
break;
case 'D':
shared_template = optarg;
break;
case 'e':
disable_esmtp = 1;
break;
@ -845,9 +1266,13 @@ int main(int argc, char **argv)
case 'L':
enable_lmtp = 1;
break;
case 'm':
if ((max_client_count = atoi(optarg)) <= 0)
msg_fatal("bad concurrency limit: %s", optarg);
break;
case 'n':
if ((max_quit_count = atoi(optarg)) <= 0)
msg_fatal("bad count: %s", optarg);
msg_fatal("bad quit count: %s", optarg);
break;
case 'p':
disable_pipelining = 1;
@ -867,6 +1292,10 @@ int main(int argc, char **argv)
openlog(basename(argv[0]), LOG_PID, LOG_MAIL);
set_cmds_flags(optarg, FLAG_SYSLOG);
break;
case 'S':
start_string = vstring_alloc(10);
unescape(start_string, optarg);
break;
case 't':
if ((var_tmout = atoi(optarg)) <= 0)
msg_fatal("bad timeout: %s", optarg);
@ -886,6 +1315,8 @@ int main(int argc, char **argv)
usage(argv[0]);
if ((backlog = atoi(argv[optind + 1])) <= 0)
usage(argv[0]);
if (single_template && shared_template)
msg_fatal("use only one of -d or -D, but not both");
/*
* Initialize.
@ -904,10 +1335,15 @@ int main(int argc, char **argv)
sock = inet_listen(argv[optind], backlog, BLOCKING);
}
if (single_template)
mysrand((int) time((time_t *) 0));
else if (shared_template)
single_template = shared_template;
/*
* Start the event handler.
*/
event_enable_read(sock, connect_event, CAST_INT_TO_CHAR_PTR(sock));
event_enable_read(sock, connect_event, (char *) 0);
for (;;)
event_loop(-1);
}

View File

@ -17,6 +17,9 @@
/* Connections can be made to UNIX-domain and IPv4 or IPv6 servers.
/* IPv4 and IPv6 are the default.
/*
/* Note: this is an unsupported test program. No attempt is made
/* to maintain compatibility between successive versions.
/*
/* Arguments:
/* .IP \fB-4\fR
/* Connect to the server with IPv4. This option has no effect when
@ -510,7 +513,7 @@ static void send_helo(SESSION *session)
* Send the standard greeting with our hostname
*/
if ((except = vstream_setjmp(session->stream)) != 0)
msg_fatal("%s while sending HELO", exception_text(except));
msg_fatal("%s while sending %s", exception_text(except), protocol);
command(session->stream, "%s %s", protocol, var_myhostname);
@ -528,15 +531,16 @@ static void helo_done(int unused_event, char *context)
SESSION *session = (SESSION *) context;
RESPONSE *resp;
int except;
const char *protocol = (talk_lmtp ? "LHLO" : "HELO");
/*
* Get response to HELO command.
*/
if ((except = vstream_setjmp(session->stream)) != 0)
msg_fatal("%s while sending HELO", exception_text(except));
msg_fatal("%s while sending %s", exception_text(except), protocol);
if ((resp = response(session->stream, buffer))->code / 100 != 2)
msg_fatal("HELO rejected: %d %s", resp->code, resp->str);
msg_fatal("%s rejected: %d %s", protocol, resp->code, resp->str);
send_mail(session);
}

View File

@ -15,6 +15,10 @@
/* DIAGNOSTICS
/* peekfd() returns -1 in case of trouble. The global \fIerrno\fR
/* variable reflects the nature of the problem.
/* BUGS
/* On some systems, non-blocking read() may fail even after a
/* positive return from peekfd(). The smtp-sink program works
/* around this by using the readable() function instead.
/* LICENSE
/* .ad
/* .fi

View File

@ -1049,8 +1049,9 @@ int vstream_fclose(VSTREAM *stream)
*/
if (stream->pid != 0)
msg_panic("vstream_fclose: stream has process");
if ((stream->buf.flags & VSTREAM_FLAG_WRITE_DOUBLE) != 0)
if ((stream->buf.flags & VSTREAM_FLAG_WRITE_DOUBLE) != 0 && stream->fd >= 0)
vstream_fflush(stream);
/* Do not remove: vstream_fdclose() depends on this error test. */
err = vstream_ferror(stream);
if (stream->buf.flags & VSTREAM_FLAG_DOUBLE) {
if (stream->read_fd >= 0)
@ -1079,8 +1080,22 @@ int vstream_fclose(VSTREAM *stream)
int vstream_fdclose(VSTREAM *stream)
{
/*
* Flush unwritten output, just like vstream_fclose(). Errors are
* reported by vstream_fclose().
*/
if ((stream->buf.flags & VSTREAM_FLAG_WRITE_DOUBLE) != 0)
(void) vstream_fflush(stream);
/*
* NOTE: Negative file descriptors are not part of the external
* interface. They are for internal use only, in order to support
* vstream_fdclose() without a lot of code duplication. Applications that
* rely on negative VSTREAM file descriptors will break without warning.
*/
if (stream->buf.flags & VSTREAM_FLAG_DOUBLE) {
stream->read_fd = stream->write_fd = -1;
stream->fd = stream->read_fd = stream->write_fd = -1;
} else {
stream->fd = -1;
}