file so people can keep track of the difference between
the Postfix LMTP client and the non-Postfix LMTP server.
+20011126
+
+ Feature: smtpd_noop_commands specifies a list of commands
+ that are treated as NOOP (no operation) commands, without
+ syntax check or state change. File: smtpd/smtpd.c.
+
+ Bugfix: the "mark queue file as corrupt" code did not work
+ because it was never used. Files: global/mark_corrupt.c,
+ global/mail_copy.c, global/pipe_command.c, *qmgr/qmgr_active.c,
+ local/maildir.c, local/mailbox.c, local/command.c, pipe/pipe.c,
+ virtual/mailbox.c, virtual/maildir.c.
+
+ Bugfix: the bounce daemon broke in case of a non-existing
+ message queue file. File: bounce/bounce_notify_util.c.
+
Open problems:
Medium: need in-process caching for map lookups. LDAP
# warn_if_reject: next restriction logs a warning instead of rejecting.
smtpd_etrn_restrictions =
+# The smtpd_noop_commands parameter specifies a list of commands that
+# the Postfix SMTP server replies to with "250 Ok", without doing any
+# syntax checks and without changing state. This list overrides any
+# commands built into the Postfix SMTP server.
+#
+smtpd_noop_commands =
+
# The smtpd_recipient_limit parameter restricts the number of recipients
# that the SMTP server accepts per message delivery.
#
same syntax as the right-hand side of a Postfix
transport table.
+ <b>smtpd</b><i>_</i><b>noop</b><i>_</i><b>commands</b>
+ List of commands that are treated as NOOP (no oper-
+ ation) commands without any parameter syntax check-
+ ing. This list overrides built-in command defini-
+ tions.
+
<b>Authentication</b> <b>controls</b>
<b>enable</b><i>_</i><b>sasl</b><i>_</i><b>authentication</b>
- Enable per-session authentication as per <a href="http://www.faqs.org/rfcs/rfc2554.html">RFC 2554</a>
- (SASL). This functionality is available only when
+ Enable per-session authentication as per <a href="http://www.faqs.org/rfcs/rfc2554.html">RFC 2554</a>
+ (SASL). This functionality is available only when
explicitly selected at program build time and
explicitly enabled at runtime.
Disallow anonymous logins.
<b>smtpd</b><i>_</i><b>sender</b><i>_</i><b>login</b><i>_</i><b>maps</b>
- Maps that specify the SASL login name that owns a
- MAIL FROM sender address. Used by the
+ Maps that specify the SASL login name that owns a
+ MAIL FROM sender address. Used by the
<b>reject</b><i>_</i><b>sender</b><i>_</i><b>login</b><i>_</i><b>mismatch</b> sender anti-spoofing
restriction.
<b>Miscellaneous</b>
<b>always</b><i>_</i><b>bcc</b>
- Address to send a copy of each message that enters
+ Address to send a copy of each message that enters
the system.
<b>command</b><i>_</i><b>directory</b>
<b>$program</b><i>_</i><b>directory</b>).
<b>debug</b><i>_</i><b>peer</b><i>_</i><b>level</b>
- Increment in verbose logging level when a remote
+ Increment in verbose logging level when a remote
host matches a pattern in the <b>debug</b><i>_</i><b>peer</b><i>_</i><b>list</b>
parameter.
<b>debug</b><i>_</i><b>peer</b><i>_</i><b>list</b>
- List of domain or network patterns. When a remote
- host matches a pattern, increase the verbose log-
- ging level by the amount specified in the
+ List of domain or network patterns. When a remote
+ host matches a pattern, increase the verbose log-
+ ging level by the amount specified in the
<b>debug</b><i>_</i><b>peer</b><i>_</i><b>level</b> parameter.
<b>default</b><i>_</i><b>verp</b><i>_</i><b>delimiters</b>
The default VERP delimiter characters that are used
- when the XVERP command is specified without
+ when the XVERP command is specified without
explicit delimiters.
<b>error</b><i>_</i><b>notice</b><i>_</i><b>recipient</b>
- Recipient of protocol/policy/resource/software
+ Recipient of protocol/policy/resource/software
error notices.
<b>hopcount</b><i>_</i><b>limit</b>
Limit the number of <b>Received:</b> message headers.
<b>local</b><i>_</i><b>recipient</b><i>_</i><b>maps</b>
- List of maps with user names that are local to
+ List of maps with user names that are local to
<b>$myorigin</b> or <b>$inet</b><i>_</i><b>interfaces</b>. If this parameter is
- defined, then the SMTP server rejects mail for
+ defined, then the SMTP server rejects mail for
unknown local users.
<b>notify</b><i>_</i><b>classes</b>
List of error classes. Of special interest are:
- <b>policy</b> When a client violates any policy, mail a
+ <b>policy</b> When a client violates any policy, mail a
transcript of the entire SMTP session to the
postmaster.
<b>protocol</b>
- When a client violates the SMTP protocol or
+ When a client violates the SMTP protocol or
issues an unimplemented command, mail a
transcript of the entire SMTP session to the
postmaster.
<b>smtpd</b><i>_</i><b>banner</b>
- Text that follows the <b>220</b> status code in the SMTP
+ Text that follows the <b>220</b> status code in the SMTP
greeting banner.
<b>smtpd</b><i>_</i><b>recipient</b><i>_</i><b>limit</b>
- Restrict the number of recipients that the SMTP
+ Restrict the number of recipients that the SMTP
server accepts per message delivery.
<b>smtpd</b><i>_</i><b>timeout</b>
- Limit the time to send a server response and to
+ Limit the time to send a server response and to
receive a client request.
<b>soft</b><i>_</i><b>bounce</b>
- Change hard (5xx) reject responses into soft (4xx)
- reject responses. This can be useful for testing
+ Change hard (5xx) reject responses into soft (4xx)
+ reject responses. This can be useful for testing
purposes.
<b>verp</b><i>_</i><b>delimiter</b><i>_</i><b>filter</b>
- The characters that Postfix accepts as VERP delim-
+ The characters that Postfix accepts as VERP delim-
iter characters.
<b>Resource</b> <b>controls</b>
<b>line</b><i>_</i><b>length</b><i>_</i><b>limit</b>
- Limit the amount of memory in bytes used for the
+ Limit the amount of memory in bytes used for the
handling of partial input lines.
<b>message</b><i>_</i><b>size</b><i>_</i><b>limit</b>
ing on-disk storage for envelope information.
<b>queue</b><i>_</i><b>minfree</b>
- Minimal amount of free space in bytes in the queue
- file system for the SMTP server to accept any mail
+ Minimal amount of free space in bytes in the queue
+ file system for the SMTP server to accept any mail
at all.
<b>Tarpitting</b>
<b>smtpd</b><i>_</i><b>soft</b><i>_</i><b>error</b><i>_</i><b>limit</b>
When an SMTP client has made this number of errors,
- wait <i>error_count</i> seconds before responding to any
+ wait <i>error_count</i> seconds before responding to any
client request.
<b>smtpd</b><i>_</i><b>hard</b><i>_</i><b>error</b><i>_</i><b>limit</b>
- Disconnect after a client has made this number of
+ Disconnect after a client has made this number of
errors.
<b>smtpd</b><i>_</i><b>junk</b><i>_</i><b>command</b><i>_</i><b>limit</b>
Limit the number of times a client can issue a junk
- command such as NOOP, VRFY, ETRN or RSET in one
- SMTP session before it is penalized with tarpit
+ command such as NOOP, VRFY, ETRN or RSET in one
+ SMTP session before it is penalized with tarpit
delays.
<b>UCE</b> <b>control</b> <b>restrictions</b>
<b>parent</b><i>_</i><b>domain</b><i>_</i><b>matches</b><i>_</i><b>subdomains</b> (versions >= 20011119)
- List of Postfix features that use <i>domain.name</i> pat-
+ List of Postfix features that use <i>domain.name</i> pat-
terns to match <i>sub.domain.name</i> (as opposed to
requiring <i>.domain.name</i> patterns).
tem.
<b>smtpd</b><i>_</i><b>helo</b><i>_</i><b>required</b>
- Require that clients introduce themselves at the
+ Require that clients introduce themselves at the
beginning of an SMTP session.
<b>smtpd</b><i>_</i><b>helo</b><i>_</i><b>restrictions</b>
- Restrict what client hostnames are allowed in <b>HELO</b>
+ Restrict what client hostnames are allowed in <b>HELO</b>
and <b>EHLO</b> commands.
<b>smtpd</b><i>_</i><b>sender</b><i>_</i><b>restrictions</b>
- Restrict what sender addresses are allowed in <b>MAIL</b>
+ Restrict what sender addresses are allowed in <b>MAIL</b>
<b>FROM</b> commands.
<b>smtpd</b><i>_</i><b>recipient</b><i>_</i><b>restrictions</b>
- Restrict what recipient addresses are allowed in
+ Restrict what recipient addresses are allowed in
<b>RCPT</b> <b>TO</b> commands.
<b>smtpd</b><i>_</i><b>etrn</b><i>_</i><b>restrictions</b>
mands, and what clients may issue <b>ETRN</b> commands.
<b>allow</b><i>_</i><b>untrusted</b><i>_</i><b>routing</b>
- Allow untrusted clients to specify addresses with
- sender-specified routing. Enabling this opens up
- nasty relay loopholes involving trusted backup MX
+ Allow untrusted clients to specify addresses with
+ sender-specified routing. Enabling this opens up
+ nasty relay loopholes involving trusted backup MX
hosts.
<b>smtpd</b><i>_</i><b>restriction</b><i>_</i><b>classes</b>
- Declares the name of zero or more parameters that
- contain a list of UCE restrictions. The names of
- these parameters can then be used instead of the
+ Declares the name of zero or more parameters that
+ contain a list of UCE restrictions. The names of
+ these parameters can then be used instead of the
restriction lists that they represent.
<b>maps</b><i>_</i><b>rbl</b><i>_</i><b>domains</b>
- List of DNS domains that publish the addresses of
+ List of DNS domains that publish the addresses of
blacklisted hosts.
<b>permit</b><i>_</i><b>mx</b><i>_</i><b>backup</b><i>_</i><b>networks</b>
- Only domains whose primary MX hosts match the
- listed networks are eligible for the <b>per-</b>
+ Only domains whose primary MX hosts match the
+ listed networks are eligible for the <b>per-</b>
<b>mit</b><i>_</i><b>mx</b><i>_</i><b>backup</b> feature.
<b>relay</b><i>_</i><b>domains</b>
- Restrict what domains or networks this mail system
+ Restrict what domains or networks this mail system
will relay mail from or to.
<b>UCE</b> <b>control</b> <b>responses</b>
<b>access</b><i>_</i><b>map</b><i>_</i><b>reject</b><i>_</i><b>code</b>
- Server response when a client violates an access
+ Server response when a client violates an access
database restriction.
<b>invalid</b><i>_</i><b>hostname</b><i>_</i><b>reject</b><i>_</i><b>code</b>
- Server response when a client violates the
+ Server response when a client violates the
<b>reject</b><i>_</i><b>invalid</b><i>_</i><b>hostname</b> restriction.
<b>maps</b><i>_</i><b>rbl</b><i>_</i><b>reject</b><i>_</i><b>code</b>
- Server response when a client violates the
+ Server response when a client violates the
<b>maps</b><i>_</i><b>rbl</b><i>_</i><b>domains</b> restriction.
<b>reject</b><i>_</i><b>code</b>
- Response code when the client matches a <b>reject</b>
+ Response code when the client matches a <b>reject</b>
restriction.
<b>relay</b><i>_</i><b>domains</b><i>_</i><b>reject</b><i>_</i><b>code</b>
- Server response when a client attempts to violate
+ Server response when a client attempts to violate
the mail relay policy.
<b>unknown</b><i>_</i><b>address</b><i>_</i><b>reject</b><i>_</i><b>code</b>
- Server response when a client violates the
+ Server response when a client violates the
<b>reject</b><i>_</i><b>unknown</b><i>_</i><b>address</b> restriction.
<b>unknown</b><i>_</i><b>client</b><i>_</i><b>reject</b><i>_</i><b>code</b>
- Server response when a client without address to
- name mapping violates the <b>reject</b><i>_</i><b>unknown</b><i>_</i><b>clients</b>
+ Server response when a client without address to
+ name mapping violates the <b>reject</b><i>_</i><b>unknown</b><i>_</i><b>clients</b>
restriction.
<b>unknown</b><i>_</i><b>hostname</b><i>_</i><b>reject</b><i>_</i><b>code</b>
- Server response when a client violates the
+ Server response when a client violates the
<b>reject</b><i>_</i><b>unknown</b><i>_</i><b>hostname</b> restriction.
<b>SEE</b> <b>ALSO</b>
syslogd(8) system logging
<b>LICENSE</b>
- The Secure Mailer license must be distributed with this
+ The Secure Mailer license must be distributed with this
software.
<b>AUTHOR(S)</b>
<a name="reject_sender_login_mismatch">
-<dt> <b>reject_sender_login_mismatch</b> <dd> Reject the request
-when <a href="#smtpd_sender_login_maps"> $smtpd_sender_owner_maps</a>
-specifies an owner for the MAIL FROM address, but the client is
-not (SASL) logged in as that MAIL FROM address owner; or when the
-client is (SASL) logged in, but the client login name doesn't own
-the MAIL FROM address according to <a href="#smtpd_sender_login_maps">
-$smtpd_sender_login_maps</a>.
+<dt> <b>reject_sender_login_mismatch</b> (Postfix versions >= 20011125)
+
+<dd> Reject the request when <a href="#smtpd_sender_login_maps">
+$smtpd_sender_owner_maps</a> specifies an owner for the MAIL FROM
+address, but the client is not (SASL) logged in as that MAIL FROM
+address owner; or when the client is (SASL) logged in, but the
+client login name doesn't own the MAIL FROM address according to
+<a href="#smtpd_sender_login_maps"> $smtpd_sender_login_maps</a>.
<p>
either bounces mail or re-injects the result back into Postfix.
This parameter uses the same syntax as the right-hand side of
a Postfix transport table.
+.IP \fBsmtpd_noop_commands\fR
+List of commands that are treated as NOOP (no operation) commands
+without any parameter syntax checking. This list overrides built-in
+command definitions.
.SH "Authentication controls"
.IP \fBenable_sasl_authentication\fR
Enable per-session authentication as per RFC 2554 (SASL).
* corrupted just send whatever we can (remember this is a best effort,
* it does not have to be perfect).
*/
- while ((rec_type = rec_get(bounce_info->orig_fp,
- bounce_info->buf, 0)) > 0) {
- if (rec_type == REC_TYPE_TIME && bounce_info->arrival_time == 0) {
- if ((bounce_info->arrival_time = atol(STR(bounce_info->buf))) < 0)
- bounce_info->arrival_time = 0;
- } else if (rec_type == REC_TYPE_MESG) {
- bounce_info->orig_offs = vstream_ftell(bounce_info->orig_fp);
- break;
+ if (bounce_info->orig_fp != 0) {
+ while ((rec_type = rec_get(bounce_info->orig_fp,
+ bounce_info->buf, 0)) > 0) {
+ if (rec_type == REC_TYPE_TIME && bounce_info->arrival_time == 0) {
+ if ((bounce_info->arrival_time = atol(STR(bounce_info->buf))) < 0)
+ bounce_info->arrival_time = 0;
+ } else if (rec_type == REC_TYPE_MESG) {
+ bounce_info->orig_offs = vstream_ftell(bounce_info->orig_fp);
+ break;
+ }
}
}
return (bounce_info);
mark_corrupt.o: ../../include/msg.h
mark_corrupt.o: ../../include/vstream.h
mark_corrupt.o: ../../include/vbuf.h
+mark_corrupt.o: ../../include/set_eugid.h
mark_corrupt.o: mail_queue.h
mark_corrupt.o: ../../include/vstring.h
+mark_corrupt.o: mail_params.h
+mark_corrupt.o: deliver_request.h
+mark_corrupt.o: recipient_list.h
mark_corrupt.o: mark_corrupt.h
match_parent_style.o: match_parent_style.c
match_parent_style.o: ../../include/sys_defs.h
char *hop_status; /* reason if unavailable */
} DELIVER_REQUEST;
+#define DEL_STAT_OK (0) /* success including bounced */
+#define DEL_STAT_DEFER (-1) /* deferred */
+#define DEL_STAT_CORRUPT (-1) /* corrupt */
+
#define DEL_REQ_FLAG_DEFLT (DEL_REQ_FLAG_SUCCESS | DEL_REQ_FLAG_BOUNCE)
#define DEL_REQ_FLAG_SUCCESS (1<<0) /* delete successful recipients */
#define DEL_REQ_FLAG_BOUNCE (1<<1) /* unimplemented */
/* DIAGNOSTICS
/* A non-zero result means the operation failed. Warnings: corrupt
/* message file. A corrupt message is marked as corrupt.
+/*
+/* The result is the bit-wise OR of zero or more of the following:
+/* .IP MAIL_COPY_STAT_CORRUPT
+/* The queue file is marked as corrupt.
+/* .IP MAIL_COPY_STAT_READ
+/* A read error was detected; errno specifies the nature of the problem.
+/* .IP MAIL_COPY_STAT_WRITE
+/* A write error was detected; errno specifies the nature of the problem.
/* SEE ALSO
/* mark_corrupt(3), mark queue file as corrupted.
/* LICENSE
#include <string.h>
#include <unistd.h>
#include <time.h>
+#include <errno.h>
/* Utility library. */
#endif
#ifndef NO_TRUNCATE
if ((flags & MAIL_COPY_TOFILE) != 0)
- if (read_error || write_error)
+ if (corrupt_error || read_error || write_error)
ftruncate(vstream_fileno(dst), (off_t) orig_length);
#endif
write_error |= vstream_fclose(dst);
vstring_sprintf(why, "error reading message: %m");
if (why && write_error)
vstring_sprintf(why, "error writing message: %m");
- return (corrupt_error || read_error || write_error);
+ return ((corrupt_error ? MAIL_COPY_STAT_CORRUPT : 0)
+ | (read_error ? MAIL_COPY_STAT_READ : 0)
+ | (write_error ? MAIL_COPY_STAT_WRITE : 0));
}
MAIL_COPY_RETURN_PATH | MAIL_COPY_BLANK)
#define MAIL_COPY_NONE 0 /* all turned off */
+#define MAIL_COPY_STAT_OK 0
+#define MAIL_COPY_STAT_CORRUPT (1<<0)
+#define MAIL_COPY_STAT_READ (1<<1)
+#define MAIL_COPY_STAT_WRITE (1<<2)
+
/* LICENSE
/* .ad
/* .fi
#define DEF_SMTPD_JUNK_CMD 1000
extern int var_smtpd_junk_cmd_limit;
+#define VAR_SMTPD_NOOP_CMDS "smtpd_noop_commands"
+#define DEF_SMTPD_NOOP_CMDS ""
+extern char *var_smtpd_noop_cmds;
+
/*
* SASL authentication support, SMTP server side.
*/
* Version of this program.
*/
#define VAR_MAIL_VERSION "mail_version"
-#define DEF_MAIL_VERSION "Snapshot-20011125"
+#define DEF_MAIL_VERSION "Snapshot-20011126"
extern char *var_mail_version;
/* LICENSE
#include <sys_defs.h>
#include <sys/stat.h>
+#include <unistd.h>
/* Utility library. */
#include <msg.h>
#include <vstream.h>
+#include <set_eugid.h>
/* Global library. */
#include <mail_queue.h>
+#include <mail_params.h>
+#include <deliver_request.h>
#include <mark_corrupt.h>
/* mark_corrupt - mark queue file as corrupt */
int mark_corrupt(VSTREAM *src)
{
char *myname = "mark_corrupt";
+ uid_t saved_uid;
+ gid_t saved_gid;
+
+ /*
+ * If not running as the mail system, change privileges first.
+ */
+ if ((saved_uid = geteuid()) != var_owner_uid) {
+ saved_gid = getegid();
+ set_eugid(var_owner_uid, var_owner_gid);
+ }
/*
* For now, the result value is -1; this may become a bit mask, or
msg_warn("corrupted queue file: %s", VSTREAM_PATH(src));
if (fchmod(vstream_fileno(src), MAIL_QUEUE_STAT_CORRUPT))
msg_fatal("%s: fchmod %s: %m", myname, VSTREAM_PATH(src));
- return (-1);
+
+ /*
+ * Restore privileges.
+ */
+ if (saved_uid != var_owner_uid)
+ set_eugid(saved_uid, saved_gid);
+
+ return (DEL_STAT_CORRUPT);
}
/* The command indicated that the message was not acceptable,
/* or the command did not finish within the time limit.
/* The reason is given via the \fIwhy\fR argument.
+/* .IP PIPE_STAT_CORRUPT
+/* The queue file is corrupted.
/* SEE ALSO
/* mail_copy(3) deliver to any.
+/* mark_corrupt(3) mark queue file as corrupt.
/* sys_exits(3) sendmail-compatible exit status codes.
/* LICENSE
/* .ad
log_len ? ". Command output: " : "", log_buf);
return (PIPE_STAT_BOUNCE);
}
+ } else if (write_status & MAIL_COPY_STAT_CORRUPT) {
+ return (PIPE_STAT_CORRUPT);
} else if (write_status && errno != EPIPE) {
vstring_sprintf(why, "Command failed: %m: \"%s\"", args.command);
return (PIPE_STAT_DEFER);
#define PIPE_STAT_OK 0 /* success */
#define PIPE_STAT_DEFER 1 /* try again */
#define PIPE_STAT_BOUNCE 2 /* failed */
+#define PIPE_STAT_CORRUPT 3 /* corrupted file */
extern int pipe_command(VSTREAM *, VSTRING *,...);
BOUNCE_ATTR(state.msg_attr),
"%s", vstring_str(why));
break;
+ case PIPE_STAT_CORRUPT:
+ deliver_status = DEL_STAT_CORRUPT;
+ break;
default:
msg_panic("%s: bad status %d", myname, cmd_status);
/* NOTREACHED */
struct stat st;
MBOX *mp;
VSTRING *why;
- int status = -1;
+ int mail_copy_status = MAIL_COPY_STAT_WRITE;
+ int deliver_status;
int copy_flags;
/*
vstring_sprintf(why, "destination file is executable");
errno = 0;
} else {
- status = mail_copy(COPY_ATTR(state.msg_attr), mp->fp,
- S_ISREG(st.st_mode) ? copy_flags :
- (copy_flags & ~MAIL_COPY_TOFILE),
- "\n", why);
+ mail_copy_status = mail_copy(COPY_ATTR(state.msg_attr), mp->fp,
+ S_ISREG(st.st_mode) ? copy_flags :
+ (copy_flags & ~MAIL_COPY_TOFILE),
+ "\n", why);
}
mbox_release(mp);
}
/*
* As the mail system, bounce, defer delivery, or report success.
*/
- if (status != 0) {
- status = (errno == EAGAIN || errno == ENOSPC || errno == ESTALE ?
- defer_append : bounce_append)
+ if (mail_copy_status & MAIL_COPY_STAT_CORRUPT) {
+ deliver_status = DEL_STAT_CORRUPT;
+ } else if (mail_copy_status != 0) {
+ deliver_status = (errno == EAGAIN || errno == ENOSPC || errno == ESTALE ?
+ defer_append : bounce_append)
(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
"cannot append message to destination file %s: %s",
path, STR(why));
} else {
- sent(SENT_ATTR(state.msg_attr), "%s", path);
+ deliver_status = sent(SENT_ATTR(state.msg_attr), "%s", path);
}
/*
* Clean up.
*/
vstring_free(why);
- return (status);
+ return (deliver_status);
}
char *mailbox;
VSTRING *why;
MBOX *mp;
- int status;
+ int mail_copy_status;
+ int deliver_status;
int copy_flags;
VSTRING *biff;
long end;
if (vstream_fseek(state.msg_attr.fp, state.msg_attr.offset, SEEK_SET) < 0)
msg_fatal("seek message file %s: %m", VSTREAM_PATH(state.msg_attr.fp));
state.msg_attr.delivered = state.msg_attr.recipient;
- status = -1;
+ mail_copy_status = MAIL_COPY_STAT_WRITE;
why = vstring_alloc(100);
if (*var_home_mailbox) {
spool_dir = 0;
errno = 0;
} else {
end = vstream_fseek(mp->fp, (off_t) 0, SEEK_END);
- status = mail_copy(COPY_ATTR(state.msg_attr), mp->fp,
- copy_flags, "\n", why);
+ mail_copy_status = mail_copy(COPY_ATTR(state.msg_attr), mp->fp,
+ copy_flags, "\n", why);
}
if (spool_uid != usr_attr.uid || spool_gid != usr_attr.gid)
set_eugid(spool_uid, spool_gid);
/*
* As the mail system, bounce, defer delivery, or report success.
*/
- if (status != 0) {
- status = (errno == EAGAIN || errno == ENOSPC || errno == ESTALE ?
- defer_append : bounce_append)
+ if (mail_copy_status & MAIL_COPY_STAT_CORRUPT) {
+ deliver_status = DEL_STAT_CORRUPT;
+ } else if (mail_copy_status != 0) {
+ deliver_status = (errno == EAGAIN || errno == ENOSPC || errno == ESTALE ?
+ defer_append : bounce_append)
(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
"cannot access mailbox %s for user %s. %s",
mailbox, state.msg_attr.user, vstring_str(why));
} else {
- sent(SENT_ATTR(state.msg_attr), "mailbox");
+ deliver_status = sent(SENT_ATTR(state.msg_attr), "mailbox");
if (var_biff) {
biff = vstring_alloc(100);
vstring_sprintf(biff, "%s@%ld", usr_attr.logname, (long) end);
*/
myfree(mailbox);
vstring_free(why);
- return (status);
+ return (deliver_status);
}
/* deliver_mailbox - deliver to recipient mailbox */
VSTRING *why;
VSTRING *buf;
VSTREAM *dst;
- int status;
+ int mail_copy_status;
+ int deliver_status;
int copy_flags;
static int count;
if (vstream_fseek(state.msg_attr.fp, state.msg_attr.offset, SEEK_SET) < 0)
msg_fatal("seek message file %s: %m", VSTREAM_PATH(state.msg_attr.fp));
state.msg_attr.delivered = state.msg_attr.recipient;
- status = -1;
+ mail_copy_status = MAIL_COPY_STAT_WRITE;
buf = vstring_alloc(100);
why = vstring_alloc(100);
|| (dst = vstream_fopen(tmpfile, O_WRONLY | O_CREAT | O_EXCL, 0600)) == 0)) {
vstring_sprintf(why, "create %s: %m", tmpfile);
} else {
- if (mail_copy(COPY_ATTR(state.msg_attr), dst, copy_flags, "\n", why) == 0) {
+ if ((mail_copy_status = mail_copy(COPY_ATTR(state.msg_attr),
+ dst, copy_flags, "\n", why)) == 0) {
if (sane_link(tmpfile, newfile) < 0
&& (errno != ENOENT
|| (make_dirs(curdir, 0700), make_dirs(newdir, 0700)) < 0
|| sane_link(tmpfile, newfile) < 0)) {
vstring_sprintf(why, "link to %s: %m", newfile);
- } else {
- status = 0;
+ mail_copy_status = MAIL_COPY_STAT_WRITE;
}
}
if (unlink(tmpfile) < 0)
}
set_eugid(var_owner_uid, var_owner_gid);
- if (status)
- status = (errno == ENOSPC || errno == ESTALE ?
- defer_append : bounce_append)
+ /*
+ * As the mail system, bounce or defer delivery.
+ */
+ if (mail_copy_status & MAIL_COPY_STAT_CORRUPT) {
+ deliver_status = DEL_STAT_CORRUPT;
+ } else if (mail_copy_status != 0) {
+ deliver_status = (errno == ENOSPC || errno == ESTALE ?
+ defer_append : bounce_append)
(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
"maildir delivery failed: %s", vstring_str(why));
- else
- status = sent(SENT_ATTR(state.msg_attr), "maildir");
+ } else {
+ deliver_status = sent(SENT_ATTR(state.msg_attr), "maildir");
+ }
vstring_free(buf);
vstring_free(why);
myfree(newdir);
myfree(curdir);
myfree(tmpfile);
myfree(newfile);
- return (status);
+ return (deliver_status);
}
mail_flow.o: mail_flow.c
mail_flow.o: ../../include/sys_defs.h
mail_flow.o: ../../include/msg.h
+mail_flow.o: ../../include/iostuff.h
mail_flow.o: mail_flow.h
mail_flow.o: master_proto.h
master.o: master.c
/* Utility library. */
#include <msg.h>
+#include <iostuff.h>
/* Global library. */
msg_warn("%s: save corrupt file queue %s id %s: %m",
myname, MAIL_QUEUE_ACTIVE, queue_id);
} else {
- msg_warn("corrupt file queue %s id %s", MAIL_QUEUE_ACTIVE, queue_id);
+ msg_warn("saving corrupt file \"%s\" from queue \"%s\" to queue \"%s\"",
+ queue_id, MAIL_QUEUE_ACTIVE, MAIL_QUEUE_CORRUPT);
}
}
* attributes, and by pretending that delivery was deferred.
*/
if (message->flags
- && !mail_open_ok(MAIL_QUEUE_ACTIVE, message->queue_id, &st, &path)) {
+ && mail_open_ok(MAIL_QUEUE_ACTIVE, message->queue_id, &st, &path) == MAIL_OPEN_NO) {
qmgr_active_corrupt(message->queue_id);
qmgr_message_free(message);
return;
/* This program expects to be run from the \fBmaster\fR(8) process
/* manager.
/*
-/* Message attributes such as sender address, recipient address and
-/* next-hop host name can be specified as command-line macros that are
+/* Message attributes such as sender address, recipient address and
+/* next-hop host name can be specified as command-line macros that are
/* expanded before the external command is executed.
/*
/* The \fBpipe\fR daemon updates queue files and marks recipients
/* Prepend a \fBReturn-Path:\fR message header with the envelope sender
/* address.
/* .IP \fBh\fR
-/* Fold the command-line \fB$recipient\fR domain name and \fB$nexthop\fR
+/* Fold the command-line \fB$recipient\fR domain name and \fB$nexthop\fR
/* host name to lower case.
/* This is recommended for delivery via \fBUUCP\fR.
/* .IP \fBq\fR
/* Quote white space and other special characters in the command-line
-/* \fB$sender\fR and \fB$recipient\fR address localparts (text to the
-/* left of the right-most \fB@\fR character), according to an 8-bit
+/* \fB$sender\fR and \fB$recipient\fR address localparts (text to the
+/* left of the right-most \fB@\fR character), according to an 8-bit
/* transparent version of RFC 822.
/* This is recommended for delivery via \fBUUCP\fR or \fBBSMTP\fR.
/* .sp
/* address information from the \fB$user\fR, \fB$extension\fR or
/* \fB$mailbox\fR command-line macros.
/* .IP \fBu\fR
-/* Fold the command-line \fB$recipient\fR address localpart (text to
+/* Fold the command-line \fB$recipient\fR address localpart (text to
/* the left of the right-most \fB@\fR character) to lower case.
/* This is recommended for delivery via \fBUUCP\fR.
/* .IP \fB.\fR
service, request->arrival_time, "%s", why);
}
break;
+ case PIPE_STAT_CORRUPT:
+ result |= DEL_STAT_CORRUPT;
+ break;
default:
msg_panic("eval_command_status: bad status %d", command_status);
/* NOTREACHED */
msg_warn("%s: save corrupt file queue %s id %s: %m",
myname, MAIL_QUEUE_ACTIVE, queue_id);
} else {
- msg_warn("corrupt file queue %s id %s", MAIL_QUEUE_ACTIVE, queue_id);
+ msg_warn("saving corrupt file \"%s\" from queue \"%s\" to queue \"%s\"",
+ queue_id, MAIL_QUEUE_ACTIVE, MAIL_QUEUE_CORRUPT);
}
}
* attributes, and by pretending that delivery was deferred.
*/
if (message->flags
- && !mail_open_ok(MAIL_QUEUE_ACTIVE, message->queue_id, &st, &path)) {
+ && mail_open_ok(MAIL_QUEUE_ACTIVE, message->queue_id, &st, &path) == MAIL_OPEN_NO) {
qmgr_active_corrupt(message->queue_id);
qmgr_message_free(message);
return;
smtpd.o: ../../include/tok822.h
smtpd.o: ../../include/resolve_clnt.h
smtpd.o: ../../include/verp_sender.h
+smtpd.o: ../../include/string_list.h
+smtpd.o: ../../include/match_list.h
+smtpd.o: ../../include/match_ops.h
smtpd.o: ../../include/mail_server.h
smtpd.o: smtpd_token.h
smtpd.o: smtpd.h
/* either bounces mail or re-injects the result back into Postfix.
/* This parameter uses the same syntax as the right-hand side of
/* a Postfix transport table.
+/* .IP \fBsmtpd_noop_commands\fR
+/* List of commands that are treated as NOOP (no operation) commands
+/* without any parameter syntax checking. This list overrides built-in
+/* command definitions.
/* .SH "Authentication controls"
/* .IP \fBenable_sasl_authentication\fR
/* Enable per-session authentication as per RFC 2554 (SASL).
#include <mail_queue.h>
#include <tok822.h>
#include <verp_sender.h>
+#include <string_list.h>
/* Single-threaded server skeleton. */
bool var_broken_auth_clients;
char *var_perm_mx_networks;
char *var_smtpd_snd_auth_maps;
+char *var_smtpd_noop_cmds;
/*
* Global state, for stand-alone mode queue file cleanup. When this is
0,
};
+static STRING_LIST *smtpd_noop_cmds;
+
/* smtpd_proto - talk the SMTP protocol */
static void smtpd_proto(SMTPD_STATE *state)
state->error_count++;
continue;
}
+ if (*var_smtpd_noop_cmds
+ && string_list_match(smtpd_noop_cmds, argv[0].strval)) {
+ smtpd_chat_reply(state, "250 Ok");
+ if (state->junk_cmds++ > var_smtpd_junk_cmd_limit)
+ state->error_count++;
+ continue;
+ }
for (cmdp = smtpd_cmd_table; cmdp->name != 0; cmdp++)
if (strcasecmp(argv[0].strval, cmdp->name) == 0)
break;
* Initialize blacklist/etc. patterns before entering the chroot jail, in
* case they specify a filename pattern.
*/
+ smtpd_noop_cmds = string_list_init(MATCH_FLAG_NONE, var_smtpd_noop_cmds);
smtpd_check_init();
debug_peer_init();
msg_cleanup(smtpd_cleanup);
VAR_FILTER_XPORT, DEF_FILTER_XPORT, &var_filter_xport, 0, 0,
VAR_PERM_MX_NETWORKS, DEF_PERM_MX_NETWORKS, &var_perm_mx_networks, 0, 0,
VAR_SMTPD_SND_AUTH_MAPS, DEF_SMTPD_SND_AUTH_MAPS, &var_smtpd_snd_auth_maps, 0, 0,
+ VAR_SMTPD_NOOP_CMDS, DEF_SMTPD_NOOP_CMDS, &var_smtpd_noop_cmds, 0, 0,
0,
};
argv_split.o: vstring.h
argv_split.o: vbuf.h
argv_split.o: argv.h
-attr_print.o: attr_print.c
-attr_print.o: sys_defs.h
-attr_print.o: msg.h
-attr_print.o: mymalloc.h
-attr_print.o: vstream.h
-attr_print.o: vbuf.h
-attr_print.o: htable.h
-attr_print.o: base64_code.h
-attr_print.o: vstring.h
-attr_print.o: attr.h
attr_print0.o: attr_print0.c
attr_print0.o: sys_defs.h
attr_print0.o: msg.h
attr_print64.o: base64_code.h
attr_print64.o: vstring.h
attr_print64.o: attr.h
-attr_scan.o: attr_scan.c
-attr_scan.o: sys_defs.h
-attr_scan.o: msg.h
-attr_scan.o: mymalloc.h
-attr_scan.o: vstream.h
-attr_scan.o: vbuf.h
-attr_scan.o: vstring.h
-attr_scan.o: htable.h
-attr_scan.o: base64_code.h
-attr_scan.o: attr.h
attr_scan0.o: attr_scan0.c
attr_scan0.o: sys_defs.h
attr_scan0.o: msg.h
char *myname = "deliver_mailbox_file";
VSTRING *why;
MBOX *mp;
- int status;
+ int mail_copy_status;
+ int deliver_status;
int copy_flags;
long end;
struct stat st;
if (vstream_fseek(state.msg_attr.fp, state.msg_attr.offset, SEEK_SET) < 0)
msg_fatal("seek message file %s: %m", VSTREAM_PATH(state.msg_attr.fp));
state.msg_attr.delivered = state.msg_attr.recipient;
- status = -1;
+ mail_copy_status = MAIL_COPY_STAT_WRITE;
why = vstring_alloc(100);
/*
errno = 0;
} else {
end = vstream_fseek(mp->fp, (off_t) 0, SEEK_END);
- status = mail_copy(COPY_ATTR(state.msg_attr), mp->fp,
- copy_flags, "\n", why);
+ mail_copy_status = mail_copy(COPY_ATTR(state.msg_attr), mp->fp,
+ copy_flags, "\n", why);
}
mbox_release(mp);
}
/*
* As the mail system, bounce, defer delivery, or report success.
*/
- if (status != 0)
- status = (errno == EDQUOT || errno == EFBIG ?
- bounce_append : defer_append)
+ if (mail_copy_status & MAIL_COPY_STAT_CORRUPT) {
+ deliver_status = DEL_STAT_CORRUPT;
+ } else if (mail_copy_status != 0) {
+ deliver_status = (errno == EDQUOT || errno == EFBIG ?
+ bounce_append : defer_append)
(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
"mailbox %s: %s", usr_attr.mailbox, vstring_str(why));
- else
- sent(SENT_ATTR(state.msg_attr), "mailbox");
-
+ } else {
+ deliver_status = sent(SENT_ATTR(state.msg_attr), "mailbox");
+ }
vstring_free(why);
- return (status);
+ return (deliver_status);
}
/* deliver_mailbox - deliver to recipient mailbox */
VSTRING *why;
VSTRING *buf;
VSTREAM *dst;
- int status;
+ int mail_copy_status;
+ int deliver_status;
int copy_flags;
static int count;
if (vstream_fseek(state.msg_attr.fp, state.msg_attr.offset, SEEK_SET) < 0)
msg_fatal("seek message file %s: %m", VSTREAM_PATH(state.msg_attr.fp));
state.msg_attr.delivered = state.msg_attr.recipient;
- status = -1;
+ mail_copy_status = MAIL_COPY_STAT_WRITE;
buf = vstring_alloc(100);
why = vstring_alloc(100);
|| (dst = vstream_fopen(tmpfile, O_WRONLY | O_CREAT | O_EXCL, 0600)) == 0)) {
vstring_sprintf(why, "create %s: %m", tmpfile);
} else {
- if (mail_copy(COPY_ATTR(state.msg_attr), dst, copy_flags, "\n", why) == 0) {
+ if ((mail_copy_status = mail_copy(COPY_ATTR(state.msg_attr),
+ dst, copy_flags, "\n", why)) == 0) {
if (sane_link(tmpfile, newfile) < 0
&& (errno != ENOENT
|| (make_dirs(curdir, 0700), make_dirs(newdir, 0700)) < 0
|| sane_link(tmpfile, newfile) < 0)) {
vstring_sprintf(why, "link to %s: %m", newfile);
- } else {
- status = 0;
+ mail_copy_status = MAIL_COPY_STAT_WRITE;
}
}
if (unlink(tmpfile) < 0)
* delivery fails, try again later. We would just bounce when the maildir
* location possibly under user control.
*/
- if (status)
- status = (errno == EDQUOT || errno == EFBIG ?
- bounce_append : defer_append)
+ if (mail_copy_status & MAIL_COPY_STAT_CORRUPT) {
+ deliver_status = DEL_STAT_CORRUPT;
+ } else if (mail_copy_status != 0) {
+ deliver_status = (errno == EDQUOT || errno == EFBIG ?
+ bounce_append : defer_append)
(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
"maildir delivery failed: %s", vstring_str(why));
- else
- status = sent(SENT_ATTR(state.msg_attr), "maildir");
+ } else {
+ deliver_status = sent(SENT_ATTR(state.msg_attr), "maildir");
+ }
vstring_free(buf);
vstring_free(why);
myfree(newdir);
myfree(curdir);
myfree(tmpfile);
myfree(newfile);
- return (status);
+ return (deliver_status);
}