Parameter: fault_injection_code, must be left at zero for
production use.
+20011128
+
+ Robustness: add a file size limit to the sendmail and
+ postdrop submission programs to stop run-away process
+ accidents. This is not a defense against DOS attack.
+ Files: sendmail/sendmail.c, postdrop/postdrop.c.
+
+ That resulted in a considerable amount of work to properly
+ propagate "file too large" conditions back to the sendmail
+ mail posting user interface. Took the opportunity to express
+ other mail submission fatal exits with the <sysexits.h>
+ exit status codes. Files: sendmail/sendmail.c,
+ postdrop/postdrop.c.
+
Open problems:
Medium: need in-process caching for map lookups. LDAP
<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.
+ ation) commands, without any parameter syntax
+ checking and without any state change. This list
+ overrides built-in command definitions.
<b>Authentication</b> <b>controls</b>
<b>enable</b><i>_</i><b>sasl</b><i>_</i><b>authentication</b>
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.
+List of commands that are treated as NOOP (no operation) commands,
+without any parameter syntax checking and without any state change.
+This list overrides built-in command definitions.
.SH "Authentication controls"
.IP \fBenable_sasl_authentication\fR
Enable per-session authentication as per RFC 2554 (SASL).
mail_copy.o: rec_type.h
mail_copy.o: mail_queue.h
mail_copy.o: mail_addr.h
-mail_copy.o: mail_copy.h
mail_copy.o: mark_corrupt.h
+mail_copy.o: mail_params.h
+mail_copy.o: mail_copy.h
mail_date.o: mail_date.c
mail_date.o: ../../include/sys_defs.h
mail_date.o: ../../include/msg.h
#include <sys_defs.h>
#include <sys/stat.h>
#include <unistd.h>
+#include <errno.h>
/* Utility library. */
|| fsync(vstream_fileno(info->stream))
#endif
)
- status = CLEANUP_STAT_WRITE;
+ status = (errno == EFBIG ? CLEANUP_STAT_SIZE : CLEANUP_STAT_WRITE);
/*
* Close the queue file and mark it as closed. Be prepared for
* reasons.
*/
if (info->close(info->stream))
- status = CLEANUP_STAT_WRITE;
+ status = (errno == EFBIG ? CLEANUP_STAT_SIZE : CLEANUP_STAT_WRITE);
info->stream = 0;
/*
* Version of this program.
*/
#define VAR_MAIL_VERSION "mail_version"
-#define DEF_MAIL_VERSION "Snapshot-20011127"
+#define DEF_MAIL_VERSION "Snapshot-20011128"
extern char *var_mail_version;
/* LICENSE
msg_vstream_init(argv[0], VSTREAM_OUT);
while (offset = vstream_ftell(VSTREAM_IN),
- (type = rec_get(VSTREAM_IN, buf, 0)) > 0) {
+ ((type = rec_get(VSTREAM_IN, buf, 0)) != REC_TYPE_EOF
+ && type != REC_TYPE_ERROR)) {
vstream_fprintf(VSTREAM_OUT, "%15s|%4ld|%3d|%s\n",
rec_type_name(type), offset,
VSTRING_LEN(buf), vstring_str(buf));
postdrop.o: ../../include/msg_vstream.h
postdrop.o: ../../include/msg_syslog.h
postdrop.o: ../../include/argv.h
-postdrop.o: ../../include/mail_proto.h
postdrop.o: ../../include/iostuff.h
+postdrop.o: ../../include/mail_proto.h
postdrop.o: ../../include/attr.h
postdrop.o: ../../include/mail_queue.h
postdrop.o: ../../include/mail_params.h
#include <stdlib.h>
#include <signal.h>
#include <syslog.h>
+#include <errno.h>
/* Utility library. */
#include <msg_vstream.h>
#include <msg_syslog.h>
#include <argv.h>
+#include <iostuff.h>
/* Global library. */
*/
mail_conf_read();
+ /*
+ * Stop run-away process accidents by limiting the queue file size. This
+ * is not a defense against DOS attack.
+ */
+ if (get_file_limit() > var_message_limit)
+ set_file_limit((off_t) var_message_limit);
+
/*
* Strip the environment so we don't have to trust the C library.
*/
* clean up incomplete output.
*/
signal(SIGPIPE, SIG_IGN);
+ signal(SIGXFSZ, SIG_IGN);
signal(SIGHUP, postdrop_sig);
signal(SIGINT, postdrop_sig);
* file descriptor to the cleanup daemon. These are by no means all
* sanity checks - the cleanup service and queue manager services will
* reject messages that lack required information.
+ *
+ * If something goes wrong, slurp up the input before responding to the
+ * client, otherwise the client will give up after detecting SIGPIPE.
*/
vstream_control(VSTREAM_IN, VSTREAM_CTL_PATH, "stdin", VSTREAM_CTL_END);
buf = vstring_alloc(100);
msg_fatal("uid=%ld: unexpected record type: %d", (long) uid, rec_type);
if (rec_type == **expected)
expected++;
- if (REC_PUT_BUF(dst->stream, rec_type, buf) < 0)
- msg_fatal("uid=%ld: queue file write error", (long) uid);
+ if (REC_PUT_BUF(dst->stream, rec_type, buf) < 0) {
+ while ((rec_type = rec_get(VSTREAM_IN, buf, var_line_limit)) > 0
+ && rec_type != REC_TYPE_END)
+ /* void */ ;
+ break;
+ }
if (rec_type == REC_TYPE_END)
break;
}
/*
* Finish the file.
*/
- if ((status = mail_stream_finish(dst, (VSTRING *) 0)) != 0)
- msg_fatal("uid=%ld: %s", (long) uid, cleanup_strerror(status));
+ if ((status = mail_stream_finish(dst, (VSTRING *) 0)) != 0) {
+ postdrop_cleanup();
+ msg_warn("uid=%ld: %m", (long) uid);
+ }
/*
* Disable deletion on fatal error before reporting success, so the file
/* configuration parameter instead.
/* .IP \fB-qR\fIsite\fR
/* Schedule immediate delivery of all mail that is queued for the named
-/* \fIsite\fR. This option accepts only \fIsite\fR names that are
+/* \fIsite\fR. This option accepts only \fIsite\fR names that are
/* eligible for the "fast flush" service, and is implemented by
/* connecting to the local SMTP server at \fB$myhostname\fR.
/* See \fBflush\fR(8) for more information about the "fast flush"
#include <errno.h>
#include <ctype.h>
#include <stdarg.h>
+#include <sysexits.h>
/* Utility library. */
*/
static char *sendmail_path;
static void sendmail_cleanup(void);
+static NORETURN fatal_error(int, const char *,...);
/*
* Flag parade.
if ((flags & SM_FLAG_AEOF) && VSTRING_LEN(buf) == 1 && *STR(buf) == '.')
break;
if (REC_PUT_BUF(dst, type, buf) < 0)
- msg_fatal("%s(%ld): error writing queue file: %m",
- saved_sender, (long) uid);
+ fatal_error(EX_CANTCREAT, "%s(%ld): error writing queue file: %m",
+ saved_sender, (long) uid);
}
/*
* handler from removing the file.
*/
if (vstream_ferror(VSTREAM_IN))
- msg_fatal("%s(%ld): error reading input: %m",
- saved_sender, (long) uid);
+ fatal_error(EX_DATAERR, "%s(%ld): error reading input: %m",
+ saved_sender, (long) uid);
if ((status = mail_stream_finish(handle, (VSTRING *) 0)) != 0)
- msg_fatal("%s(%ld): %s", saved_sender,
- (long) uid, cleanup_strerror(status));
+ fatal_error(EX_CANTCREAT, "%s(%ld): %s", saved_sender,
+ (long) uid, cleanup_strerror(status));
if (sendmail_path) {
myfree(sendmail_path);
sendmail_path = 0;
vstring_free(buf);
}
+static int fatal_status;
+
/* sendmail_cleanup - callback for the runtime error handler */
-static void sendmail_cleanup(void)
+static NORETURN sendmail_cleanup(void)
{
/*
msg_info("remove %s", sendmail_path);
sendmail_path = 0;
}
+ exit(fatal_status > 0 ? fatal_status : 1);
}
/* sendmail_sig - catch signal and clean up */
static void sendmail_sig(int sig)
{
+ fatal_status = sig;
sendmail_cleanup();
- exit(sig);
+}
+
+/* fatal_error - give up and notify parent */
+
+static void fatal_error(int status, const char *fmt,...)
+{
+ VSTRING *text = vstring_alloc(10);
+ va_list ap;
+
+ fatal_status = status;
+ va_start(ap, fmt);
+ vstring_vsprintf(text, fmt, ap);
+ va_end(ap);
+ msg_fatal("%s", vstring_str(text));
}
/* main - the main program */
for (fd = 0; fd < 3; fd++)
if (fstat(fd, &st) == -1
&& (close(fd), open("/dev/null", O_RDWR, 0)) != fd)
- msg_fatal("open /dev/null: %m");
+ fatal_error(EX_UNAVAILABLE, "open /dev/null: %m");
/*
* The CDE desktop calendar manager leaks a parent file descriptor into
*/
mail_conf_read();
if (chdir(var_queue_dir))
- msg_fatal("chdir %s: %m", var_queue_dir);
+ fatal_error(EX_UNAVAILABLE, "chdir %s: %m", var_queue_dir);
+
+ /*
+ * Stop run-away process accidents by limiting the queue file size. This
+ * is not a defense against DOS attack.
+ */
+ if (get_file_limit() > var_message_limit)
+ set_file_limit((off_t) var_message_limit);
signal(SIGPIPE, SIG_IGN);
+ signal(SIGXFSZ, SIG_IGN);
signal(SIGHUP, sendmail_sig);
signal(SIGINT, sendmail_sig);
msg_info("-%c option ignored", c);
break;
case 'n':
- msg_fatal("-%c option not supported", c);
+ fatal_error(EX_USAGE, "-%c option not supported", c);
case 'B': /* body type */
break;
case 'F': /* full name */
break;
case 'V': /* VERP */
if (verp_delims_verify(optarg) != 0)
- msg_fatal("-V option requires two characters from %s",
- var_verp_filter);
+ fatal_error(EX_USAGE, "-V requires two characters from %s",
+ var_verp_filter);
verp_delims = optarg;
break;
case 'b':
switch (*optarg) {
default:
- msg_fatal("unsupported: -%c%c", c, *optarg);
+ fatal_error(EX_USAGE, "unsupported: -%c%c", c, *optarg);
case 'd': /* daemon mode */
if (mode == SM_MODE_FLUSHQ)
msg_warn("ignoring -q option in daemon mode");
break;
case 'A':
if (optarg[1] == 0)
- msg_fatal("-oA requires pathname");
+ fatal_error(EX_USAGE, "-oA requires pathname");
myfree(var_alias_db_map);
var_alias_db_map = mystrdup(optarg + 1);
set_mail_conf_str(VAR_ALIAS_DB_MAP, var_alias_db_map);
if (*site_to_flush == 0)
msg_fatal("specify: -qRsitename");
} else {
- msg_fatal("-q%c is not implemented", optarg[0]);
+ fatal_error(EX_USAGE, "-q%c is not implemented", optarg[0]);
}
break;
case 't':
msg_verbose++;
break;
case '?':
- msg_fatal("usage: %s [options]", argv[0]);
+ fatal_error(EX_USAGE, "usage: %s [options]", argv[0]);
}
}
transport.o: ../../include/argv.h
transport.o: ../../include/mail_params.h
transport.o: ../../include/maps.h
+transport.o: ../../include/match_parent_style.h
+transport.o: ../../include/match_ops.h
transport.o: transport.h
trivial-rewrite.o: trivial-rewrite.c
trivial-rewrite.o: ../../include/sys_defs.h