mirror of
https://github.com/vdukhovni/postfix
synced 2025-08-30 05:38:06 +00:00
snapshot-20010520
This commit is contained in:
parent
6b85132d41
commit
6ac89aab2c
@ -5125,3 +5125,45 @@ Apologies for any names omitted.
|
||||
Code cleanup: in order to make postsuper -d more usable,
|
||||
the showq command was extended to safely list the possibly
|
||||
world-writable maildrop directory. File: showq/showq.c.
|
||||
|
||||
20010505
|
||||
|
||||
RFC 2821 feature: an SMTP server must accept a recipient
|
||||
address of "postmaster" without domain name. File:
|
||||
smtpd/smtpd_check.c.
|
||||
|
||||
RFC 2821 recommendation: reply with 503 to commands sent
|
||||
after 554 greeting. File: smtpd/smtpd.c.
|
||||
|
||||
RFC 2821 recommendation: if VRFY is enabled, list it in
|
||||
the EHLO response.
|
||||
|
||||
20010507
|
||||
|
||||
Bugfix: with soft_bounce=yes, the SMTP server would log
|
||||
5xx replies even though it would send 4xx replies to the
|
||||
client (Phil Howard, ipal.net). File: smtpd/smtpd_check.c.
|
||||
|
||||
20010515
|
||||
|
||||
Compatibility: Microsoft sends "AUTH=MBS_BASIC LOGIN".
|
||||
Updated the parsing code in smtp/smtp_proto.c. Problem
|
||||
reported by Ralf Tessmann, Godot GmbH.
|
||||
|
||||
20010520
|
||||
|
||||
Standard: deleted the "via" portion from Received: headers
|
||||
generated by Postfix bounce or other notification processes.
|
||||
File: global/post_mail.c.
|
||||
|
||||
Robustness: eliminated stack-based recursion from the RFC
|
||||
822 address parser. File: global/tok822_parse.c.
|
||||
|
||||
Standard: annotated the source code with comments based on
|
||||
RFC 2821 and 2822. Not all the changes make sense.
|
||||
|
||||
Cleanup: moved ownership of the debug_peer parameters from
|
||||
the applications to the library, so that a Postfix shared
|
||||
library does not suffer from undefined references. Files:
|
||||
smtp/smtp.c, lmtp/lmtp.c, smtpd/smtpd.c, global/mail_params.c.
|
||||
LaMont Jones, for Debian.
|
||||
|
@ -98,8 +98,10 @@ mail_owner = postfix
|
||||
#inet_interfaces = $myhostname, localhost
|
||||
|
||||
# The mydestination parameter specifies the list of domains that this
|
||||
# machine considers itself the final destination for. That does not
|
||||
# include domains that are hosted on this machine. Those domains are
|
||||
# machine considers itself the final destination for. That includes
|
||||
# Sendmail-style virtual domains hosted on this machine.
|
||||
#
|
||||
# Do not include Postfix-style virtual domains - those domains are
|
||||
# specified elsewhere (see sample-virtual.cf, and sample-transport.cf).
|
||||
#
|
||||
# The default is $myhostname + localhost.$mydomain. On a mail domain
|
||||
|
@ -165,7 +165,11 @@ max_idle = 100s
|
||||
max_use = 100
|
||||
|
||||
# The mydestination parameter specifies the list of domains that this
|
||||
# machine considers itself the final destination for.
|
||||
# machine considers itself the final destination for. That includes
|
||||
# Sendmail-style virtual domains hosted on this machine.
|
||||
#
|
||||
# Do not include Postfix-style virtual domains - those domains are
|
||||
# specified elsewhere (see sample-virtual.cf, and sample-transport.cf).
|
||||
#
|
||||
# The default is $myhostname + localhost.$mydomain. On a mail domain
|
||||
# gateway, you should also include $mydomain. Do not specify the
|
||||
|
@ -1366,8 +1366,9 @@ record, and that this one PTR record needs a matching A record.
|
||||
Some people read the RFCs such that one IP address can have multiple
|
||||
PTR records, but that makes PTR records even less useful than they
|
||||
already are. And in any case, having multiple names per IP address
|
||||
would only worsen the problem of finding out the "official name"
|
||||
of a machine's IP address.
|
||||
only worsens the problem of finding out the SMTP client hostname.
|
||||
|
||||
<hr>
|
||||
|
||||
<a name="open_relay"><h3>Help! Postfix is an open relay</h3>
|
||||
|
||||
|
@ -43,14 +43,14 @@ SENDMAIL(1) SENDMAIL(1)
|
||||
daemon.
|
||||
|
||||
<b>newaliases</b>
|
||||
Initialize the alias database. If no alias database
|
||||
type is specified, the program uses the type speci-
|
||||
fied in the <b>database</b><i>_</i><b>type</b> configuration parameter;
|
||||
if no input file is specified, the program pro-
|
||||
cesses the file(s) specified with the
|
||||
<b>alias</b><i>_</i><b>database</b> configuration parameter. This mode
|
||||
of operation is implemented by running the <b>postal-</b>
|
||||
<b>ias</b>(1) command.
|
||||
Initialize the alias database. If no input file is
|
||||
specified (with the <b>-oA</b> option, see below), the
|
||||
program processes the file(s) specified with the
|
||||
<b>alias</b><i>_</i><b>database</b> configuration parameter. If no
|
||||
alias database type is specified, the program uses
|
||||
the type specified with the <b>database</b><i>_</i><b>type</b> configu-
|
||||
ration parameter. This mode of operation is imple-
|
||||
mented by running the <a href="postalias.1.html"><b>postalias</b>(1)</a> command.
|
||||
|
||||
Note: it may take a minute or so before an alias
|
||||
database update becomes visible. Use the <b>postfix</b>
|
||||
|
@ -40,12 +40,13 @@ be delivered. If mail could not be delivered upon the last attempt,
|
||||
the reason for failure is shown. This mode of operation is implemented
|
||||
by connecting to the \fBshowq\fR(8) daemon.
|
||||
.IP \fBnewaliases\fR
|
||||
Initialize the alias database. If no alias database type is
|
||||
specified, the program uses the type specified in the
|
||||
\fBdatabase_type\fR configuration parameter; if no input file
|
||||
is specified, the program processes the file(s) specified with the
|
||||
\fBalias_database\fR configuration parameter. This mode of operation
|
||||
is implemented by running the \fBpostalias\fR(1) command.
|
||||
Initialize the alias database. If no input file is specified (with
|
||||
the \fB-oA\fR option, see below), the program processes the file(s)
|
||||
specified with the \fBalias_database\fR configuration parameter.
|
||||
If no alias database type is specified, the program uses the type
|
||||
specified with the \fBdatabase_type\fR configuration parameter.
|
||||
This mode of operation is implemented by running the \fBpostalias\fR(1)
|
||||
command.
|
||||
.sp
|
||||
Note: it may take a minute or so before an alias database update
|
||||
becomes visible. Use the \fBpostfix reload\fR command to eliminate
|
||||
|
@ -138,8 +138,7 @@ int bounce_notify_service(char *service, char *queue_name,
|
||||
postmaster = flush ? var_2bounce_rcpt : var_delay_rcpt;
|
||||
if ((bounce = post_mail_fopen_nowait(mail_addr_double_bounce(),
|
||||
postmaster,
|
||||
NULL_CLEANUP_FLAGS,
|
||||
"BOUNCE")) != 0) {
|
||||
NULL_CLEANUP_FLAGS)) != 0) {
|
||||
|
||||
/*
|
||||
* Double bounce to Postmaster. This is the last opportunity
|
||||
@ -163,8 +162,7 @@ int bounce_notify_service(char *service, char *queue_name,
|
||||
*/
|
||||
else {
|
||||
if ((bounce = post_mail_fopen_nowait(NULL_SENDER, recipient,
|
||||
NULL_CLEANUP_FLAGS,
|
||||
"BOUNCE")) != 0) {
|
||||
NULL_CLEANUP_FLAGS)) != 0) {
|
||||
|
||||
/*
|
||||
* Send the bounce message header, some boilerplate text that
|
||||
@ -203,8 +201,7 @@ int bounce_notify_service(char *service, char *queue_name,
|
||||
postmaster = flush ? var_bounce_rcpt : var_delay_rcpt;
|
||||
if ((bounce = post_mail_fopen_nowait(mail_addr_double_bounce(),
|
||||
postmaster,
|
||||
NULL_CLEANUP_FLAGS,
|
||||
"BOUNCE")) != 0) {
|
||||
NULL_CLEANUP_FLAGS)) != 0) {
|
||||
if (bounce_header(bounce, bounce_info, postmaster) == 0
|
||||
&& bounce_diagnostic_log(bounce, bounce_info) == 0
|
||||
&& bounce_header_dsn(bounce, bounce_info) == 0
|
||||
|
@ -287,6 +287,29 @@ static void cleanup_header(CLEANUP_STATE *state)
|
||||
* we should do with this header: delete, count, rewrite. Note that we
|
||||
* should examine headers even when they will be deleted from the output,
|
||||
* because the addresses in those headers might be needed elsewhere.
|
||||
*
|
||||
* XXX 2821: Return-path breakage.
|
||||
*
|
||||
* RFC 821 specifies: When the receiver-SMTP makes the "final delivery" of a
|
||||
* message it inserts at the beginning of the mail data a return path
|
||||
* line. The return path line preserves the information in the
|
||||
* <reverse-path> from the MAIL command. Here, final delivery means the
|
||||
* message leaves the SMTP world. Normally, this would mean it has been
|
||||
* delivered to the destination user, but in some cases it may be further
|
||||
* processed and transmitted by another mail system.
|
||||
*
|
||||
* And that is what Postfix implements. Delivery agents prepend
|
||||
* Return-Path:. In order to avoid cluttering up the message with
|
||||
* possibly inconsistent Return-Path: information (the sender can change
|
||||
* as the result of mail forwarding or mailing list delivery), Postfix
|
||||
* removes any existing Return-Path: headers.
|
||||
*
|
||||
* RFC 2821 Section 4.4 specifies: A message-originating SMTP system
|
||||
* SHOULD NOT send a message that already contains a Return-path header.
|
||||
* SMTP servers performing a relay function MUST NOT inspect the message
|
||||
* data, and especially not to the extent needed to determine if
|
||||
* Return-path headers are present. SMTP servers making final delivery
|
||||
* MAY remove Return-path headers before adding their own.
|
||||
*/
|
||||
else {
|
||||
state->headers_seen |= (1 << hdr_opts->type);
|
||||
@ -324,6 +347,11 @@ static void cleanup_missing_headers(CLEANUP_STATE *state)
|
||||
/*
|
||||
* Add a missing (Resent-)Message-Id: header. The message ID gives the
|
||||
* time in GMT units, plus the local queue ID.
|
||||
*
|
||||
* XXX Message-Id is not a required message header (RFC 822 and RFC 2822).
|
||||
*
|
||||
* XXX It is the queue ID non-inode bits that prevent messages from getting
|
||||
* the same Message-Id within the same second.
|
||||
*/
|
||||
if ((state->headers_seen & (1 << (state->resent[0] ?
|
||||
HDR_RESENT_MESSAGE_ID : HDR_MESSAGE_ID))) == 0) {
|
||||
@ -365,6 +393,29 @@ static void cleanup_missing_headers(CLEANUP_STATE *state)
|
||||
CLEANUP_OUT_BUF(state, REC_TYPE_NORM, state->temp2);
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX 2821: Appendix B: The return address in the MAIL command SHOULD,
|
||||
* if possible, be derived from the system's identity for the submitting
|
||||
* (local) user, and the "From:" header field otherwise. If there is a
|
||||
* system identity available, it SHOULD also be copied to the Sender
|
||||
* header field if it is different from the address in the From header
|
||||
* field. (Any Sender field that was already there SHOULD be removed.)
|
||||
* Similar wording appears in RFC 2822 section 3.6.2.
|
||||
*
|
||||
* Postfix presently does not insert a Sender: header if envelope and From:
|
||||
* address differ. Older Postfix versions assumed that the envelope
|
||||
* sender address specifies the system identity and inserted Sender:
|
||||
* whenever envelope and From: differed. This was wrong with relayed
|
||||
* mail, and was often not even desirable with original submissions.
|
||||
*
|
||||
* XXX 2822 Section 3.6.2, as well as RFC 822 Section 4.1: FROM headers can
|
||||
* contain multiple addresses. If this is the case, then a Sender: header
|
||||
* must be provided with a single address.
|
||||
*
|
||||
* Postfix does not count the number of addresses in a From: header
|
||||
* (although doing so is trivial, once the address is parsed).
|
||||
*/
|
||||
|
||||
/*
|
||||
* Add a missing destination header.
|
||||
*/
|
||||
|
@ -12,7 +12,7 @@ SRCS = been_here.c bounce.c canon_addr.c cleanup_strerror.c clnt_stream.c \
|
||||
mail_scan_dir.c mail_stream.c mail_task.c mail_trigger.c maps.c \
|
||||
mark_corrupt.c mkmap_db.c mkmap_dbm.c mkmap_open.c mynetworks.c \
|
||||
mypwd.c namadr_list.c off_cvt.c opened.c own_inet_addr.c \
|
||||
peer_name.c pipe_command.c post_mail.c quote_821_local.c \
|
||||
pipe_command.c post_mail.c quote_821_local.c \
|
||||
quote_822_local.c rec_streamlf.c rec_type.c recipient_list.c \
|
||||
record.c remove.c resolve_clnt.c resolve_local.c rewrite_clnt.c \
|
||||
sent.c smtp_stream.c split_addr.c string_list.c sys_exits.c \
|
||||
@ -32,7 +32,7 @@ OBJS = been_here.o bounce.o canon_addr.o cleanup_strerror.o clnt_stream.o \
|
||||
mail_scan_dir.o mail_stream.o mail_task.o mail_trigger.o maps.o \
|
||||
mark_corrupt.o mkmap_db.o mkmap_dbm.o mkmap_open.o mynetworks.o \
|
||||
mypwd.o namadr_list.o off_cvt.o opened.o own_inet_addr.o \
|
||||
peer_name.o pipe_command.o post_mail.o quote_821_local.o \
|
||||
pipe_command.o post_mail.o quote_821_local.o \
|
||||
quote_822_local.o rec_streamlf.o rec_type.o recipient_list.o \
|
||||
record.o remove.o resolve_clnt.o resolve_local.o rewrite_clnt.o \
|
||||
sent.o smtp_stream.o split_addr.o string_list.o sys_exits.o \
|
||||
@ -49,7 +49,7 @@ HDRS = been_here.h bounce.h canon_addr.h cleanup_user.h clnt_stream.h \
|
||||
mail_proto.h mail_queue.h mail_run.h mail_scan_dir.h mail_stream.h \
|
||||
mail_task.h mail_version.h maps.h mark_corrupt.h mkmap.h \
|
||||
mynetworks.h mypwd.h namadr_list.h off_cvt.h opened.h \
|
||||
own_inet_addr.h peer_name.h pipe_command.h post_mail.h \
|
||||
own_inet_addr.h pipe_command.h post_mail.h \
|
||||
quote_821_local.h quote_822_local.h rec_streamlf.h rec_type.h \
|
||||
recipient_list.h record.h resolve_clnt.h resolve_local.h \
|
||||
rewrite_clnt.h sent.h smtp_stream.h split_addr.h string_list.h \
|
||||
@ -65,7 +65,7 @@ INCL =
|
||||
LIB = libglobal.a
|
||||
TESTPROG= domain_list dot_lockfile mail_addr_crunch mail_addr_find \
|
||||
mail_addr_map mail_date maps mynetworks mypwd namadr_list \
|
||||
off_cvt peer_name quote_822_local rec2stream recdump resolve_clnt \
|
||||
off_cvt quote_822_local rec2stream recdump resolve_clnt \
|
||||
resolve_local rewrite_clnt stream2rec string_list tok822_parse \
|
||||
quote_821_local mail_conf_time
|
||||
|
||||
|
@ -41,6 +41,13 @@ int is_header(const char *str)
|
||||
const char *cp;
|
||||
int c;
|
||||
|
||||
/*
|
||||
* XXX RFC 2822 Section 4.5.2, Obsolete header fields: whitespace may
|
||||
* appear between header label and ":" (see: RFC 822, Section 3.4.2.).
|
||||
*
|
||||
* The code below allows no such whitespace. This has never been a problem,
|
||||
* and therefore we're not inclined to add code for it.
|
||||
*/
|
||||
for (cp = str; (c = *(unsigned char *) cp) != 0; cp++) {
|
||||
if (c == ':')
|
||||
return (cp > str);
|
||||
|
@ -65,6 +65,8 @@
|
||||
/*
|
||||
/* char *var_import_environ;
|
||||
/* char *var_export_environ;
|
||||
/* char *var_debug_peer_list;
|
||||
/* int var_debug_peer_level;
|
||||
/*
|
||||
/* void mail_params_init()
|
||||
/* DESCRIPTION
|
||||
@ -181,6 +183,8 @@ char *var_mynetworks_style;
|
||||
|
||||
char *var_import_environ;
|
||||
char *var_export_environ;
|
||||
char *var_debug_peer_list;
|
||||
int var_debug_peer_level;
|
||||
|
||||
/* check_myhostname - lookup hostname and validate */
|
||||
|
||||
@ -298,6 +302,7 @@ void mail_params_init()
|
||||
VAR_IMPORT_ENVIRON, DEF_IMPORT_ENVIRON, &var_import_environ, 0, 0,
|
||||
VAR_DEF_TRANSPORT, DEF_DEF_TRANSPORT, &var_def_transport, 0, 0,
|
||||
VAR_MYNETWORKS_STYLE, DEF_MYNETWORKS_STYLE, &var_mynetworks_style, 1, 0,
|
||||
VAR_DEBUG_PEER_LIST, DEF_DEBUG_PEER_LIST, &var_debug_peer_list, 0, 0,
|
||||
0,
|
||||
};
|
||||
static CONFIG_STR_FN_TABLE function_str_defaults_2[] = {
|
||||
@ -312,6 +317,7 @@ void mail_params_init()
|
||||
VAR_HASH_QUEUE_DEPTH, DEF_HASH_QUEUE_DEPTH, &var_hash_queue_depth, 1, 0,
|
||||
VAR_FORK_TRIES, DEF_FORK_TRIES, &var_fork_tries, 1, 0,
|
||||
VAR_FLOCK_TRIES, DEF_FLOCK_TRIES, &var_flock_tries, 1, 0,
|
||||
VAR_DEBUG_PEER_LEVEL, DEF_DEBUG_PEER_LEVEL, &var_debug_peer_level, 1, 0,
|
||||
0,
|
||||
};
|
||||
static CONFIG_TIME_TABLE time_defaults[] = {
|
||||
|
@ -224,6 +224,10 @@ extern char *var_always_bcc;
|
||||
|
||||
/*
|
||||
* What to put in the To: header when no recipients were disclosed.
|
||||
*
|
||||
* XXX 2822: When no recipient headers remain, a system should insert a Bcc:
|
||||
* header without additional information. That is not so great given that
|
||||
* MTAs routinely strip Bcc: headers from message headers.
|
||||
*/
|
||||
#define VAR_RCPT_WITHELD "undisclosed_recipients_header"
|
||||
#define DEF_RCPT_WITHELD "To: undisclosed-recipients:;"
|
||||
@ -634,6 +638,9 @@ extern int var_hash_queue_depth;
|
||||
* determines how many recipient addresses the SMTP client sends along with
|
||||
* each message. Unfortunately, some mailers misbehave and disconnect (smap)
|
||||
* when given more recipients than they are willing to handle.
|
||||
*
|
||||
* XXX 2821: A mail system is supposed to use EHLO instead of HELO, and to fall
|
||||
* back to HELO if EHLO is not supported.
|
||||
*/
|
||||
#define VAR_BESTMX_TRANSP "best_mx_transport"
|
||||
#define DEF_BESTMX_TRANSP ""
|
||||
@ -688,7 +695,11 @@ extern bool var_ign_mx_lookup_err;
|
||||
extern bool var_skip_quit_resp;
|
||||
|
||||
#define VAR_SMTP_ALWAYS_EHLO "smtp_always_send_ehlo"
|
||||
#ifdef RFC821_SYNTAX
|
||||
#define DEF_SMTP_ALWAYS_EHLO 0
|
||||
#else
|
||||
#define DEF_SMTP_ALWAYS_EHLO 1
|
||||
#endif
|
||||
extern bool var_smtp_always_ehlo;
|
||||
|
||||
#define VAR_SMTP_NEVER_EHLO "smtp_never_send_ehlo"
|
||||
|
@ -378,6 +378,13 @@ VSTREAM *mail_queue_enter(const char *queue_name, int mode)
|
||||
file_id = get_file_id(fd);
|
||||
GETTIMEOFDAY(&tv);
|
||||
|
||||
/*
|
||||
* XXX Some systems seem to have clocks that correlate with process
|
||||
* scheduling or something. Unfortunately, we cannot add random
|
||||
* quantities to the time, because the non-inode part of a queue ID must
|
||||
* not repeat within the same second. The queue ID is the sole thing that
|
||||
* prevents multiple messages from getting the same Message-ID value.
|
||||
*/
|
||||
for (count = 0;; count++) {
|
||||
vstring_sprintf(id_buf, "%05X%s", (int) tv.tv_usec, file_id);
|
||||
mail_queue_path(path_buf, queue_name, STR(id_buf));
|
||||
|
@ -15,7 +15,7 @@
|
||||
* Version of this program.
|
||||
*/
|
||||
#define VAR_MAIL_VERSION "mail_version"
|
||||
#define DEF_MAIL_VERSION "Snapshot-20010502"
|
||||
#define DEF_MAIL_VERSION "Snapshot-20010520"
|
||||
extern char *var_mail_version;
|
||||
|
||||
/* LICENSE
|
||||
|
@ -6,17 +6,15 @@
|
||||
/* SYNOPSIS
|
||||
/* #include <post_mail.h>
|
||||
/*
|
||||
/* VSTREAM *post_mail_fopen(sender, recipient, flags, via)
|
||||
/* VSTREAM *post_mail_fopen(sender, recipient, flags)
|
||||
/* const char *sender;
|
||||
/* const char *recipient;
|
||||
/* int flags;
|
||||
/* const char *via;
|
||||
/*
|
||||
/* VSTREAM *post_mail_fopen_nowait(sender, recipient, flags, via)
|
||||
/* VSTREAM *post_mail_fopen_nowait(sender, recipient, flags)
|
||||
/* const char *sender;
|
||||
/* const char *recipient;
|
||||
/* int flags;
|
||||
/* const char *via;
|
||||
/*
|
||||
/* int post_mail_fprintf(stream, format, ...)
|
||||
/* VSTREAM *stream;
|
||||
@ -132,7 +130,7 @@
|
||||
/* post_mail_init - initial negotiations */
|
||||
|
||||
static void post_mail_init(VSTREAM *stream, const char *sender,
|
||||
const char *recipient, int flags, const char *via)
|
||||
const char *recipient, int flags)
|
||||
{
|
||||
VSTRING *id = vstring_alloc(100);
|
||||
long now = time((time_t *) 0);
|
||||
@ -158,8 +156,8 @@ static void post_mail_init(VSTREAM *stream, const char *sender,
|
||||
* Do the Received: and Date: header lines. This allows us to shave a few
|
||||
* cycles by using the expensive date conversion result for both.
|
||||
*/
|
||||
post_mail_fprintf(stream, "Received: by %s (%s) via %s",
|
||||
var_myhostname, var_mail_name, via);
|
||||
post_mail_fprintf(stream, "Received: by %s (%s)",
|
||||
var_myhostname, var_mail_name);
|
||||
post_mail_fprintf(stream, "\tid %s; %s", vstring_str(id), date);
|
||||
post_mail_fprintf(stream, "Date: %s", date);
|
||||
vstring_free(id);
|
||||
@ -167,26 +165,25 @@ static void post_mail_init(VSTREAM *stream, const char *sender,
|
||||
|
||||
/* post_mail_fopen - prepare for posting a message */
|
||||
|
||||
VSTREAM *post_mail_fopen(const char *sender, const char *recipient,
|
||||
int flags, const char *via)
|
||||
VSTREAM *post_mail_fopen(const char *sender, const char *recipient, int flags)
|
||||
{
|
||||
VSTREAM *stream;
|
||||
|
||||
stream = mail_connect_wait(MAIL_CLASS_PRIVATE, MAIL_SERVICE_CLEANUP);
|
||||
post_mail_init(stream, sender, recipient, flags, via);
|
||||
post_mail_init(stream, sender, recipient, flags);
|
||||
return (stream);
|
||||
}
|
||||
|
||||
/* post_mail_fopen_nowait - prepare for posting a message */
|
||||
|
||||
VSTREAM *post_mail_fopen_nowait(const char *sender, const char *recipient,
|
||||
int flags, const char *via)
|
||||
int flags)
|
||||
{
|
||||
VSTREAM *stream;
|
||||
|
||||
if ((stream = mail_connect(MAIL_CLASS_PRIVATE, MAIL_SERVICE_CLEANUP,
|
||||
BLOCKING)) != 0)
|
||||
post_mail_init(stream, sender, recipient, flags, via);
|
||||
post_mail_init(stream, sender, recipient, flags);
|
||||
return (stream);
|
||||
}
|
||||
|
||||
|
@ -24,9 +24,8 @@
|
||||
/*
|
||||
* External interface.
|
||||
*/
|
||||
extern VSTREAM *post_mail_fopen(const char *, const char *, int, const char *);
|
||||
extern VSTREAM *post_mail_fopen_nowait(const char *, const char *,
|
||||
int, const char *);
|
||||
extern VSTREAM *post_mail_fopen(const char *, const char *, int);
|
||||
extern VSTREAM *post_mail_fopen_nowait(const char *, const char *, int);
|
||||
extern int PRINTFLIKE(2, 3) post_mail_fprintf(VSTREAM *, const char *,...);
|
||||
extern int post_mail_fputs(VSTREAM *, const char *);
|
||||
extern int post_mail_buffer(VSTREAM *, const char *, int);
|
||||
|
@ -200,6 +200,9 @@ int smtp_get(VSTRING *vp, VSTREAM *stream, int bound)
|
||||
* Allow for partial long lines (we will read the remainder later) and
|
||||
* allow for lines ending in bare LF. The idea is to be liberal in what
|
||||
* we accept, strict in what we send.
|
||||
*
|
||||
* XXX 2821: Section 4.1.1.4 says that an SMTP server must not recognize
|
||||
* bare LF as record terminator.
|
||||
*/
|
||||
smtp_timeout_reset(stream);
|
||||
last_char = (bound == 0 ? vstring_get(vp, stream) :
|
||||
|
@ -45,8 +45,7 @@ typedef struct TOK822 {
|
||||
#define TOK822_DOMLIT 259 /* stuff between [] not nesting */
|
||||
#define TOK822_ADDR 260 /* actually a token group */
|
||||
#define TOK822_STARTGRP 261 /* start of named group */
|
||||
#define TOK822_COMMENT_TEXT 262 /* comment text */
|
||||
#define TOK822_MAXTOK 262
|
||||
#define TOK822_MAXTOK 261
|
||||
|
||||
/*
|
||||
* tok822_node.c
|
||||
|
@ -57,7 +57,7 @@ TOK822 *tok822_alloc(int type, const char *strval)
|
||||
TOK822 *tp;
|
||||
|
||||
#define CONTAINER_TOKEN(x) \
|
||||
((x) == TOK822_ADDR || (x) == TOK822_COMMENT || (x) == TOK822_STARTGRP)
|
||||
((x) == TOK822_ADDR || (x) == TOK822_STARTGRP)
|
||||
|
||||
tp = (TOK822 *) mymalloc(sizeof(*tp));
|
||||
tp->type = type;
|
||||
|
@ -192,12 +192,7 @@ VSTRING *tok822_internalize(VSTRING *vp, TOK822 *tree, int flags)
|
||||
tok822_internalize(vp, tp->head, TOK822_STR_NONE);
|
||||
break;
|
||||
case TOK822_COMMENT:
|
||||
VSTRING_ADDCH(vp, '(');
|
||||
tok822_internalize(vp, tp->head, TOK822_STR_NONE);
|
||||
VSTRING_ADDCH(vp, ')');
|
||||
break;
|
||||
case TOK822_ATOM:
|
||||
case TOK822_COMMENT_TEXT:
|
||||
case TOK822_QSTRING:
|
||||
vstring_strcat(vp, vstring_str(tp->vstr));
|
||||
break;
|
||||
@ -244,15 +239,8 @@ VSTRING *tok822_externalize(VSTRING *vp, TOK822 *tree, int flags)
|
||||
tok822_externalize(vp, tp->head, TOK822_STR_NONE);
|
||||
break;
|
||||
case TOK822_ATOM:
|
||||
vstring_strcat(vp, vstring_str(tp->vstr));
|
||||
break;
|
||||
case TOK822_COMMENT:
|
||||
VSTRING_ADDCH(vp, '(');
|
||||
tok822_externalize(vp, tp->head, TOK822_STR_NONE);
|
||||
VSTRING_ADDCH(vp, ')');
|
||||
break;
|
||||
case TOK822_COMMENT_TEXT:
|
||||
tok822_copy_quoted(vp, vstring_str(tp->vstr), "()\\");
|
||||
vstring_strcat(vp, vstring_str(tp->vstr));
|
||||
break;
|
||||
case TOK822_QSTRING:
|
||||
VSTRING_ADDCH(vp, '"');
|
||||
@ -321,6 +309,13 @@ TOK822 *tok822_scan(const char *str, TOK822 **tailp)
|
||||
TOK822 *tp;
|
||||
int ch;
|
||||
|
||||
/*
|
||||
* XXX 2822 new feature: Section 4.1 allows "." to appear in a phrase (to
|
||||
* allow for forms such as: Johnny B. Goode <johhny@domain.org>. I cannot
|
||||
* handle that at the tokenizer level - it is not context sensitive. And
|
||||
* to fix this at the parser level requires radical changes to preserve
|
||||
* white space as part of the token stream. Thanks a lot, people.
|
||||
*/
|
||||
while ((ch = *(unsigned char *) str++) != 0) {
|
||||
if (ISSPACE(ch))
|
||||
continue;
|
||||
@ -466,36 +461,32 @@ static void tok822_quote_atom(TOK822 *tp)
|
||||
|
||||
static const char *tok822_comment(TOK822 *tp, const char *str)
|
||||
{
|
||||
TOK822 *tc = 0;
|
||||
int level = 1;
|
||||
int ch;
|
||||
|
||||
#define COMMENT_TEXT_TOKEN(t) ((t) && (t)->type == TOK822_COMMENT_TEXT)
|
||||
|
||||
#define APPEND_NEW_TOKEN(tp, type, strval) \
|
||||
tok822_sub_append(tp, tok822_alloc(type, strval))
|
||||
/*
|
||||
* XXX We cheat by storing comments in their external form. Otherwise it
|
||||
* would be a royal pain to preserve \ before (. That would require a
|
||||
* recursive parser, which could consume unreasonable amounts of memory.
|
||||
*/
|
||||
VSTRING_ADDCH(tp->vstr, '(');
|
||||
|
||||
while ((ch = *(unsigned char *) str) != 0) {
|
||||
VSTRING_ADDCH(tp->vstr, ch);
|
||||
str++;
|
||||
if (ch == '(') { /* comments can nest! */
|
||||
if (COMMENT_TEXT_TOKEN(tc))
|
||||
VSTRING_TERMINATE(tc->vstr);
|
||||
tc = APPEND_NEW_TOKEN(tp, TOK822_COMMENT, (char *) 0);
|
||||
str = tok822_comment(tc, str);
|
||||
level++;
|
||||
} else if (ch == ')') {
|
||||
break;
|
||||
} else {
|
||||
if (ch == '\\') {
|
||||
if ((ch = *(unsigned char *) str) == 0)
|
||||
break;
|
||||
str++;
|
||||
}
|
||||
if (!COMMENT_TEXT_TOKEN(tc))
|
||||
tc = APPEND_NEW_TOKEN(tp, TOK822_COMMENT_TEXT, (char *) 0);
|
||||
VSTRING_ADDCH(tc->vstr, ch);
|
||||
if (--level == 0)
|
||||
break;
|
||||
} else if (ch == '\\') {
|
||||
if ((ch = *(unsigned char *) str) == 0)
|
||||
break;
|
||||
VSTRING_ADDCH(tp->vstr, ch);
|
||||
str++;
|
||||
}
|
||||
}
|
||||
if (COMMENT_TEXT_TOKEN(tc))
|
||||
VSTRING_TERMINATE(tc->vstr);
|
||||
VSTRING_TERMINATE(tp->vstr);
|
||||
return (str);
|
||||
}
|
||||
|
||||
@ -554,14 +545,11 @@ static void tok822_print(TOK822 *list, int indent)
|
||||
} else if (tp->type == TOK822_ADDR) {
|
||||
vstream_printf("%*s %s\n", indent, "", "address");
|
||||
tok822_print(tp->head, indent + 2);
|
||||
} else if (tp->type == TOK822_COMMENT) {
|
||||
vstream_printf("%*s %s\n", indent, "", "comment");
|
||||
tok822_print(tp->head, indent + 2);
|
||||
} else if (tp->type == TOK822_STARTGRP) {
|
||||
vstream_printf("%*s %s\n", indent, "", "group \":\"");
|
||||
} else {
|
||||
vstream_printf("%*s %s \"%s\"\n", indent, "",
|
||||
tp->type == TOK822_COMMENT_TEXT ? "text" :
|
||||
tp->type == TOK822_COMMENT ? "comment" :
|
||||
tp->type == TOK822_ATOM ? "atom" :
|
||||
tp->type == TOK822_QSTRING ? "quoted string" :
|
||||
tp->type == TOK822_DOMLIT ? "domain literal" :
|
||||
|
@ -86,8 +86,7 @@ Parse tree:
|
||||
OP ","
|
||||
address
|
||||
atom "venema"
|
||||
comment
|
||||
text ""wietse "
|
||||
comment "("wietse )"
|
||||
OP ","
|
||||
address
|
||||
quoted string ")"
|
||||
@ -135,11 +134,7 @@ Parse tree:
|
||||
OP "."
|
||||
atom "org"
|
||||
OP ")"
|
||||
comment
|
||||
text " "
|
||||
comment
|
||||
text ""wietse "
|
||||
text " venema""
|
||||
comment "( ("wietse ) venema")"
|
||||
|
||||
Internalized:
|
||||
wietse venema@porcupine.org) ( ("wietse ) venema")
|
||||
@ -272,9 +267,8 @@ Parse tree:
|
||||
atom "wietse"
|
||||
OP "@"
|
||||
atom "foo"
|
||||
comment
|
||||
text "wietse
|
||||
venema"
|
||||
comment "(wietse
|
||||
venema)"
|
||||
|
||||
Internalized:
|
||||
wietse@foo (wietse
|
||||
|
@ -269,8 +269,6 @@ int var_lmtp_data0_tmout;
|
||||
int var_lmtp_data1_tmout;
|
||||
int var_lmtp_data2_tmout;
|
||||
int var_lmtp_quit_tmout;
|
||||
char *var_debug_peer_list;
|
||||
int var_debug_peer_level;
|
||||
int var_lmtp_cache_conn;
|
||||
int var_lmtp_skip_quit_resp;
|
||||
char *var_notify_classes;
|
||||
@ -505,7 +503,6 @@ static void pre_accept(char *unused_name, char **unused_argv)
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
static CONFIG_STR_TABLE str_table[] = {
|
||||
VAR_DEBUG_PEER_LIST, DEF_DEBUG_PEER_LIST, &var_debug_peer_list, 0, 0,
|
||||
VAR_NOTIFY_CLASSES, DEF_NOTIFY_CLASSES, &var_notify_classes, 0, 0,
|
||||
VAR_ERROR_RCPT, DEF_ERROR_RCPT, &var_error_rcpt, 1, 0,
|
||||
VAR_LMTP_SASL_PASSWD, DEF_LMTP_SASL_PASSWD, &var_lmtp_sasl_passwd, 0, 0,
|
||||
@ -514,7 +511,6 @@ int main(int argc, char **argv)
|
||||
};
|
||||
static CONFIG_INT_TABLE int_table[] = {
|
||||
VAR_LMTP_TCP_PORT, DEF_LMTP_TCP_PORT, &var_lmtp_tcp_port, 0, 0,
|
||||
VAR_DEBUG_PEER_LEVEL, DEF_DEBUG_PEER_LEVEL, &var_debug_peer_level, 1, 0,
|
||||
0,
|
||||
};
|
||||
static CONFIG_TIME_TABLE time_table[] = {
|
||||
|
@ -268,7 +268,7 @@ void lmtp_chat_notify(LMTP_STATE *state)
|
||||
|
||||
notice = post_mail_fopen_nowait(mail_addr_double_bounce(),
|
||||
var_error_rcpt,
|
||||
NULL_CLEANUP_FLAGS, "NOTICE");
|
||||
NULL_CLEANUP_FLAGS);
|
||||
if (notice == 0) {
|
||||
msg_warn("postmaster notify: %m");
|
||||
return;
|
||||
|
@ -66,7 +66,9 @@ postsuper.o: ../../include/vstring.h
|
||||
postsuper.o: ../../include/safe.h
|
||||
postsuper.o: ../../include/set_ugid.h
|
||||
postsuper.o: ../../include/argv.h
|
||||
postsuper.o: ../../include/vstring_vstream.h
|
||||
postsuper.o: ../../include/mail_task.h
|
||||
postsuper.o: ../../include/mail_conf.h
|
||||
postsuper.o: ../../include/mail_params.h
|
||||
postsuper.o: ../../include/mail_queue.h
|
||||
postsuper.o: ../../include/mail_open_ok.h
|
||||
|
@ -170,29 +170,43 @@ static int delete_one(const char *queue_id)
|
||||
MAIL_QUEUE_ACTIVE, /* foolproof but adequate */
|
||||
0,
|
||||
};
|
||||
const char *log_queue_names[] = {
|
||||
MAIL_QUEUE_BOUNCE,
|
||||
MAIL_QUEUE_DEFER,
|
||||
0,
|
||||
};
|
||||
struct stat st;
|
||||
const char **cpp;
|
||||
const char *path;
|
||||
const char **msg_qpp;
|
||||
const char **log_qpp;
|
||||
const char *msg_path;
|
||||
VSTRING *log_path_buf = vstring_alloc(100);
|
||||
int found = 0;
|
||||
|
||||
/*
|
||||
* Do not delete defer or bounce logfiles, because we could lose a race
|
||||
* and delete a defer/bounce logfile from a message that reuses the queue
|
||||
* ID.
|
||||
* Delete defer or bounce logfiles before deleting the corresponding
|
||||
* message file, and only if the message file exists. This minimizes but
|
||||
* does not eliminate a race condition with queue ID reuse which results
|
||||
* in deleting the wrong files.
|
||||
*/
|
||||
for (cpp = msg_queue_names; *cpp != 0; cpp++) {
|
||||
if (!mail_open_ok(*cpp, queue_id, &st, &path)) {
|
||||
for (msg_qpp = msg_queue_names; *msg_qpp != 0; msg_qpp++) {
|
||||
if (!mail_open_ok(*msg_qpp, queue_id, &st, &msg_path))
|
||||
continue;
|
||||
} else if (unlink(path) == 0) {
|
||||
for (log_qpp = log_queue_names; *log_qpp != 0; log_qpp++)
|
||||
(void) mail_queue_path(log_path_buf, *log_qpp, queue_id);
|
||||
if (unlink(STR(log_path_buf)) < 0 && errno != ENOENT)
|
||||
msg_warn("remove file %s: %m", STR(log_path_buf));
|
||||
if (unlink(msg_path) == 0) {
|
||||
found = 1;
|
||||
msg_info("removed file %s", path);
|
||||
msg_info("removed file %s", msg_path);
|
||||
break;
|
||||
} else if (errno != ENOENT) {
|
||||
msg_warn("remove file %s: %m", path);
|
||||
}
|
||||
if (errno != ENOENT) {
|
||||
msg_warn("remove file %s: %m", msg_path);
|
||||
} else if (msg_verbose) {
|
||||
msg_info("remove file %s: %m", path);
|
||||
msg_info("remove file %s: %m", msg_path);
|
||||
}
|
||||
}
|
||||
vstring_free(log_path_buf);
|
||||
return (found);
|
||||
}
|
||||
|
||||
|
@ -34,12 +34,13 @@
|
||||
/* the reason for failure is shown. This mode of operation is implemented
|
||||
/* by connecting to the \fBshowq\fR(8) daemon.
|
||||
/* .IP \fBnewaliases\fR
|
||||
/* Initialize the alias database. If no alias database type is
|
||||
/* specified, the program uses the type specified in the
|
||||
/* \fBdatabase_type\fR configuration parameter; if no input file
|
||||
/* is specified, the program processes the file(s) specified with the
|
||||
/* \fBalias_database\fR configuration parameter. This mode of operation
|
||||
/* is implemented by running the \fBpostalias\fR(1) command.
|
||||
/* Initialize the alias database. If no input file is specified (with
|
||||
/* the \fB-oA\fR option, see below), the program processes the file(s)
|
||||
/* specified with the \fBalias_database\fR configuration parameter.
|
||||
/* If no alias database type is specified, the program uses the type
|
||||
/* specified with the \fBdatabase_type\fR configuration parameter.
|
||||
/* This mode of operation is implemented by running the \fBpostalias\fR(1)
|
||||
/* command.
|
||||
/* .sp
|
||||
/* Note: it may take a minute or so before an alias database update
|
||||
/* becomes visible. Use the \fBpostfix reload\fR command to eliminate
|
||||
|
@ -234,8 +234,6 @@ int var_smtp_data1_tmout;
|
||||
int var_smtp_data2_tmout;
|
||||
int var_smtp_quit_tmout;
|
||||
char *var_inet_interfaces;
|
||||
char *var_debug_peer_list;
|
||||
int var_debug_peer_level;
|
||||
char *var_notify_classes;
|
||||
int var_smtp_skip_4xx_greeting;
|
||||
int var_smtp_skip_5xx_greeting;
|
||||
@ -395,7 +393,6 @@ static void pre_exit(void)
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
static CONFIG_STR_TABLE str_table[] = {
|
||||
VAR_DEBUG_PEER_LIST, DEF_DEBUG_PEER_LIST, &var_debug_peer_list, 0, 0,
|
||||
VAR_NOTIFY_CLASSES, DEF_NOTIFY_CLASSES, &var_notify_classes, 0, 0,
|
||||
VAR_FALLBACK_RELAY, DEF_FALLBACK_RELAY, &var_fallback_relay, 0, 0,
|
||||
VAR_BESTMX_TRANSP, DEF_BESTMX_TRANSP, &var_bestmx_transp, 0, 0,
|
||||
@ -417,7 +414,6 @@ int main(int argc, char **argv)
|
||||
0,
|
||||
};
|
||||
static CONFIG_INT_TABLE int_table[] = {
|
||||
VAR_DEBUG_PEER_LEVEL, DEF_DEBUG_PEER_LEVEL, &var_debug_peer_level, 1, 0,
|
||||
0,
|
||||
};
|
||||
static CONFIG_BOOL_TABLE bool_table[] = {
|
||||
|
@ -207,6 +207,11 @@ static DNS_RR *smtp_addr_list(DNS_RR *mx_names, VSTRING *why)
|
||||
/*
|
||||
* As long as we are able to look up any host address, we ignore problems
|
||||
* with DNS lookups.
|
||||
*
|
||||
* XXX 2821: update smtp_errno (0->FAIL upon unrecoverable lookup error,
|
||||
* any->RETRY upon temporary lookup error) so that we can correctly
|
||||
* handle the case of no resolvable MX host. Currently this is always
|
||||
* treated as a soft error. RFC 2821 wants a more precise response.
|
||||
*/
|
||||
for (rr = mx_names; rr; rr = rr->next) {
|
||||
if (rr->type != T_MX)
|
||||
@ -320,6 +325,19 @@ DNS_RR *smtp_domain_addr(char *name, VSTRING *why, int *found_myself)
|
||||
* as we're looking up all the hosts, it would be better to look up the
|
||||
* least preferred host first, so that DNS lookup error messages make
|
||||
* more sense.
|
||||
*
|
||||
* XXX 2821: RFC 2821 says that the sender must shuffle equal-preference MX
|
||||
* hosts, whereas multiple A records per hostname must be used in the
|
||||
* order as received. They make the bogus assumption that a hostname with
|
||||
* multiple A records corresponds to one machine with multiple network
|
||||
* interfaces.
|
||||
*
|
||||
* XXX 2821: Postfix recognizes the local machine by looking for its own IP
|
||||
* address in the list of mail exchangers. RFC 2821 says one has to look
|
||||
* at the mail exchanger hostname as well, making the bogus assumption
|
||||
* that an IP address is listed only under one hostname. However, looking
|
||||
* at hostnames provides a partial solution for MX hosts behind a NAT
|
||||
* gateway.
|
||||
*/
|
||||
switch (dns_lookup(name, T_MX, 0, &mx_names, (VSTRING *) 0, why)) {
|
||||
default:
|
||||
|
@ -252,7 +252,7 @@ void smtp_chat_notify(SMTP_STATE *state)
|
||||
|
||||
notice = post_mail_fopen_nowait(mail_addr_double_bounce(),
|
||||
var_error_rcpt,
|
||||
NULL_CLEANUP_FLAGS, "NOTICE");
|
||||
NULL_CLEANUP_FLAGS);
|
||||
if (notice == 0) {
|
||||
msg_warn("postmaster notify: %m");
|
||||
return;
|
||||
|
@ -213,10 +213,13 @@ int smtp_helo(SMTP_STATE *state)
|
||||
* overflow detection, ignore the message size limit advertised by the
|
||||
* SMTP server. Otherwise, we might do the wrong thing when the server
|
||||
* advertises a really huge message size limit.
|
||||
*
|
||||
* XXX Allow for "code (SP|-) ehlo-keyword (SP|=) ehlo-param...", because
|
||||
* MicroSoft implemented AUTH based on an old draft.
|
||||
*/
|
||||
lines = resp->str;
|
||||
while ((words = mystrtok(&lines, "\n")) != 0) {
|
||||
if (mystrtok(&words, "- ") && (word = mystrtok(&words, " \t")) != 0) {
|
||||
if (mystrtok(&words, "- =") && (word = mystrtok(&words, " \t")) != 0) {
|
||||
if (strcasecmp(word, "8BITMIME") == 0)
|
||||
state->features |= SMTP_FEATURE_8BITMIME;
|
||||
else if (strcasecmp(word, "PIPELINING") == 0)
|
||||
@ -226,8 +229,6 @@ int smtp_helo(SMTP_STATE *state)
|
||||
#ifdef USE_SASL_AUTH
|
||||
else if (var_smtp_sasl_enable && strcasecmp(word, "AUTH") == 0)
|
||||
smtp_sasl_helo_auth(state, words);
|
||||
else if (var_smtp_sasl_enable && strncasecmp(word, "AUTH=", 5) == 0)
|
||||
smtp_sasl_helo_auth(state, word + 5);
|
||||
#endif
|
||||
else if (strcasecmp(word, var_myhostname) == 0) {
|
||||
msg_warn("host %s replied to HELO/EHLO with my own hostname %s",
|
||||
@ -480,9 +481,16 @@ int smtp_xfer(SMTP_STATE *state)
|
||||
* rejected, ignore RCPT TO responses: all recipients are
|
||||
* dead already. When all recipients are rejected the
|
||||
* receiver may apply a course correction.
|
||||
*
|
||||
* XXX 2821: Section 4.5.3.1 says that a 552 RCPT TO reply
|
||||
* must be treated as if the server replied with 452.
|
||||
*/
|
||||
case SMTP_STATE_RCPT:
|
||||
if (!mail_from_rejected) {
|
||||
#ifndef RFC821_SYNTAX
|
||||
if (resp->code == 552)
|
||||
resp->code = 452;
|
||||
#endif
|
||||
if (resp->code / 100 == 2) {
|
||||
++nrcpt;
|
||||
} else {
|
||||
|
@ -311,8 +311,6 @@ int var_smtpd_soft_erlim;
|
||||
int var_smtpd_hard_erlim;
|
||||
int var_queue_minfree; /* XXX use off_t */
|
||||
char *var_smtpd_banner;
|
||||
char *var_debug_peer_list;
|
||||
int var_debug_peer_level;
|
||||
char *var_notify_classes;
|
||||
char *var_client_checks;
|
||||
char *var_helo_checks;
|
||||
@ -416,6 +414,11 @@ static int ehlo_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
||||
{
|
||||
char *err;
|
||||
|
||||
/*
|
||||
* XXX 2821 new feature: Section 4.1.4 specifies that a server must clear
|
||||
* all buffers and reset the state exactly as if a RSET command had been
|
||||
* issued.
|
||||
*/
|
||||
if (argc < 2) {
|
||||
state->error_mask |= MAIL_ERROR_PROTOCOL;
|
||||
smtpd_chat_reply(state, "501 Syntax: EHLO hostname");
|
||||
@ -423,7 +426,7 @@ static int ehlo_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
||||
}
|
||||
if (state->helo_name != 0)
|
||||
helo_reset(state);
|
||||
#if 0
|
||||
#ifndef RFC821_SYNTAX
|
||||
mail_reset(state);
|
||||
rcpt_reset(state);
|
||||
#endif
|
||||
@ -444,6 +447,8 @@ static int ehlo_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
||||
(unsigned long) var_message_limit); /* XXX */
|
||||
else
|
||||
smtpd_chat_reply(state, "250-SIZE");
|
||||
if (var_disable_vrfy_cmd == 0)
|
||||
smtpd_chat_reply(state, "250-VRFY");
|
||||
smtpd_chat_reply(state, "250-ETRN");
|
||||
#ifdef USE_SASL_AUTH
|
||||
if (var_smtpd_sasl_enable) {
|
||||
@ -471,6 +476,18 @@ static void mail_open_stream(SMTPD_STATE *state)
|
||||
{
|
||||
char *postdrop_command;
|
||||
|
||||
/*
|
||||
* XXX 2821: An SMTP server is not allowed to "clean up" mail except in
|
||||
* the case of original submissions. Presently, Postfix always runs all
|
||||
* mail through the cleanup server.
|
||||
*
|
||||
* We could approximate the RFC as follows: Postfix rewrites mail if it
|
||||
* comes from a source that we are willing to relay for. This way, we
|
||||
* avoid rewriting most mail that comes from elsewhere. However, that
|
||||
* requires moving functionality away from the cleanup daemon elsewhere,
|
||||
* such as virtual address expansion, and header/body pattern matching.
|
||||
*/
|
||||
|
||||
/*
|
||||
* If running from the master or from inetd, connect to the cleanup
|
||||
* service.
|
||||
@ -613,6 +630,12 @@ static int mail_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
||||
/*
|
||||
* Sanity checks. XXX Ignore bad SIZE= values until we can reliably and
|
||||
* portably detect overflows while converting from string to off_t.
|
||||
*
|
||||
* XXX 2821 pedantism: Section 4.1.2 says that SMTP servers that receive a
|
||||
* command in which invalid character codes have been employed, and for
|
||||
* which there are no other reasons for rejection, MUST reject that
|
||||
* command with a 501 response. So much for the principle of "be liberal
|
||||
* in what you accept, be strict in what you send".
|
||||
*/
|
||||
if (var_helo_required && state->helo_name == 0) {
|
||||
state->error_mask |= MAIL_ERROR_POLICY;
|
||||
@ -746,6 +769,12 @@ static int rcpt_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
||||
|
||||
/*
|
||||
* Sanity checks.
|
||||
*
|
||||
* XXX 2821 pedantism: Section 4.1.2 says that SMTP servers that receive a
|
||||
* command in which invalid character codes have been employed, and for
|
||||
* which there are no other reasons for rejection, MUST reject that
|
||||
* command with a 501 response. So much for the principle of "be liberal
|
||||
* in what you accept, be strict in what you send".
|
||||
*/
|
||||
if (state->cleanup == 0) {
|
||||
state->error_mask |= MAIL_ERROR_PROTOCOL;
|
||||
@ -1023,6 +1052,15 @@ static int rset_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv)
|
||||
static int noop_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv)
|
||||
{
|
||||
|
||||
/*
|
||||
* XXX 2821 incompatibility: Section 4.1.1.9 says that NOOP can have a
|
||||
* parameter string which is to be ignored. NOOP instructions with
|
||||
* parameters? Go figure.
|
||||
*
|
||||
* RFC 2821 violates RFC 821, which says that NOOP takes no parameters.
|
||||
*/
|
||||
#ifdef RFC821_SYNTAX
|
||||
|
||||
/*
|
||||
* Sanity checks.
|
||||
*/
|
||||
@ -1031,6 +1069,7 @@ static int noop_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv)
|
||||
smtpd_chat_reply(state, "501 Syntax: NOOP");
|
||||
return (-1);
|
||||
}
|
||||
#endif
|
||||
smtpd_chat_reply(state, "250 Ok");
|
||||
return (0);
|
||||
}
|
||||
@ -1051,6 +1090,17 @@ static int vrfy_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
||||
* address forms. Therefore we must parse out the address, or we must
|
||||
* stop doing recipient restriction checks and lose the opportunity to
|
||||
* say "user unknown" at the SMTP port.
|
||||
*
|
||||
* XXX 2821 incompatibility and brain damage: Section 4.5.1 requires that
|
||||
* VRFY is implemented. RFC 821 specifies that VRFY is optional. It gets
|
||||
* even worse: section 3.5.3 says that a 502 (command recognized but not
|
||||
* implemented) reply is not fully compliant.
|
||||
*
|
||||
* Thus, an RFC 2821 compliant implementation cannot refuse to supply
|
||||
* information in reply to VRFY queries. That is simply bogus. The only
|
||||
* reply we could supply is a generic 252 reply. This causes spammers to
|
||||
* add tons of bogus addresses to their mailing lists (spam harvesting by
|
||||
* trying out large lists of potential recipient names with VRFY).
|
||||
*/
|
||||
#define SLOPPY 0
|
||||
|
||||
@ -1076,7 +1126,17 @@ static int vrfy_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
||||
smtpd_chat_reply(state, "%s", err);
|
||||
return (-1);
|
||||
}
|
||||
smtpd_chat_reply(state, "252 <%s>", argv[1].strval);
|
||||
|
||||
/*
|
||||
* XXX 2821 new feature: Section 3.5.1 requires that the VRFY response is
|
||||
* either "full name <user@domain>" or "user@domain". Postfix replies
|
||||
* with the address that was provided by the client, whether or not it is
|
||||
* in fully qualified domain form or not.
|
||||
*
|
||||
* Reply code 250 is reserved for the case where the address is verified;
|
||||
* reply code 252 should be used when no definitive certainty exists.
|
||||
*/
|
||||
smtpd_chat_reply(state, "252 %s", argv[1].strval);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -1256,7 +1316,8 @@ static void smtpd_proto(SMTPD_STATE *state)
|
||||
continue;
|
||||
}
|
||||
if (state->access_denied && cmdp->action != quit_cmd) {
|
||||
smtpd_chat_reply(state, "%s", state->access_denied);
|
||||
smtpd_chat_reply(state, "503 Error: access denied for %s",
|
||||
state->namaddr); /* RFC 2821 Sec 3.1 */
|
||||
state->error_count++;
|
||||
continue;
|
||||
}
|
||||
@ -1445,7 +1506,6 @@ int main(int argc, char **argv)
|
||||
VAR_SMTPD_SOFT_ERLIM, DEF_SMTPD_SOFT_ERLIM, &var_smtpd_soft_erlim, 1, 0,
|
||||
VAR_SMTPD_HARD_ERLIM, DEF_SMTPD_HARD_ERLIM, &var_smtpd_hard_erlim, 1, 0,
|
||||
VAR_QUEUE_MINFREE, DEF_QUEUE_MINFREE, &var_queue_minfree, 0, 0,
|
||||
VAR_DEBUG_PEER_LEVEL, DEF_DEBUG_PEER_LEVEL, &var_debug_peer_level, 1, 0,
|
||||
VAR_UNK_CLIENT_CODE, DEF_UNK_CLIENT_CODE, &var_unk_client_code, 0, 0,
|
||||
VAR_BAD_NAME_CODE, DEF_BAD_NAME_CODE, &var_bad_name_code, 0, 0,
|
||||
VAR_UNK_NAME_CODE, DEF_UNK_NAME_CODE, &var_unk_name_code, 0, 0,
|
||||
@ -1475,7 +1535,6 @@ int main(int argc, char **argv)
|
||||
};
|
||||
static CONFIG_STR_TABLE str_table[] = {
|
||||
VAR_SMTPD_BANNER, DEF_SMTPD_BANNER, &var_smtpd_banner, 1, 0,
|
||||
VAR_DEBUG_PEER_LIST, DEF_DEBUG_PEER_LIST, &var_debug_peer_list, 0, 0,
|
||||
VAR_NOTIFY_CLASSES, DEF_NOTIFY_CLASSES, &var_notify_classes, 0, 0,
|
||||
VAR_CLIENT_CHECKS, DEF_CLIENT_CHECKS, &var_client_checks, 0, 0,
|
||||
VAR_HELO_CHECKS, DEF_HELO_CHECKS, &var_helo_checks, 0, 0,
|
||||
|
@ -207,7 +207,7 @@ void smtpd_chat_notify(SMTPD_STATE *state)
|
||||
|
||||
notice = post_mail_fopen_nowait(mail_addr_double_bounce(),
|
||||
var_error_rcpt,
|
||||
NULL_CLEANUP_FLAGS, "NOTICE");
|
||||
NULL_CLEANUP_FLAGS);
|
||||
if (notice == 0) {
|
||||
msg_warn("postmaster notify: %m");
|
||||
return;
|
||||
|
@ -551,6 +551,26 @@ static int smtpd_check_reject(SMTPD_STATE *state, int error_class,
|
||||
}
|
||||
printable(STR(error_text), ' ');
|
||||
|
||||
/*
|
||||
* XXX The code below also appears in the SMTP server reply output
|
||||
* routine. It is duplicated here in order to avoid discrepancies between
|
||||
* the reply codes that are shown in "reject" logging and the reply codes
|
||||
* that are actually sent to the SMTP client.
|
||||
*
|
||||
* Implementing the soft_bounce safety net in the SMTP server reply output
|
||||
* routine has the advantage that it covers all 5xx replies, including
|
||||
* SMTP protocol or syntax errors, which makes soft_bounce great for
|
||||
* non-destructive tests (especially by people who are paranoid about
|
||||
* losing mail).
|
||||
*
|
||||
* We could eliminate the code duplication and implement the soft_bounce
|
||||
* safety net only in the code below. But then the safety net would cover
|
||||
* the UCE restrictions only. This would be at odds with the documentation
|
||||
* which says soft_bounce changes all 5xx replies into 4xx ones.
|
||||
*/
|
||||
if (var_soft_bounce && STR(error_text)[0] == '5')
|
||||
STR(error_text)[0] = '4';
|
||||
|
||||
/*
|
||||
* Log what is happening. When the sysadmin discards policy violation
|
||||
* postmaster notices, this may be the only trace left that service was
|
||||
@ -1898,6 +1918,13 @@ char *smtpd_check_rcpt(SMTPD_STATE *state, char *recipient)
|
||||
if (recipient == 0)
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* XXX 2821: Section 3.6 requires that "postmaster" be accepted even when
|
||||
* specified without a fully qualified domain name.
|
||||
*/
|
||||
if (strcasecmp(recipient, "postmaster") == 0)
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* Minor kluge so that we can delegate work to the generic routine and so
|
||||
* that we can syslog the recipient with the reject messages.
|
||||
|
Loading…
x
Reference in New Issue
Block a user