2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-08-30 05:38:06 +00:00

snapshot-20010520

This commit is contained in:
Wietse Venema 2001-05-20 00:00:00 -05:00 committed by Viktor Dukhovni
parent 6b85132d41
commit 6ac89aab2c
33 changed files with 365 additions and 135 deletions

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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>

View File

@ -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

View File

@ -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

View File

@ -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.
*/

View File

@ -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

View File

@ -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);

View File

@ -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[] = {

View File

@ -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"

View File

@ -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));

View File

@ -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

View File

@ -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);
}

View File

@ -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);

View File

@ -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) :

View File

@ -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

View File

@ -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;

View File

@ -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" :

View File

@ -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

View File

@ -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[] = {

View File

@ -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;

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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[] = {

View File

@ -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:

View File

@ -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;

View File

@ -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 {

View File

@ -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,

View File

@ -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;

View File

@ -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.