20010411
- Compatibility: the SMTP server now replies with 550 instead
- of 503 when it receives the DATA command without having
- received a valid recipient address. This is needed for the
- Sendmail client-side pipelining implementation. Problem
- reported by Lutz Jaenicke. File: smtpd/smtpd.c.
+ Bugfix: the SMTP server now replies with 550 instead of
+ 503 when it receives the DATA command without having received
+ a valid recipient address. This is needed for the Sendmail
+ client-side pipelining implementation. Problem reported by
+ Lutz Jaenicke. File: smtpd/smtpd.c.
Cleanup: shut up if chattr fails on Reiserfs and other file
systems that do not support the respective attributes.
20010426
- Workaround: the SMTP server did not really parse invalid
- addresses such as <first last <user@domain>> well. I
- thought this was taken care of years ago. File: smtpd/smtpd.c.
+ Bugfix: the SMTP server did not parse invalid MAIL FROM or
+ RCPT TO addresses such as <first last <user@domain>> the
+ way it was supposed to do. I thought this was taken care
+ of years ago. File: smtpd/smtpd.c.
20010427
Feature: the Postfix SMTP client now by default randomly
shuffles destination IP addresses of equal preference.
- File: smtp/smtp_addr.c. Based on an idea by Aleph1.
+ Specify "smtp_randomize_addresses = no" to disable.
+ Shuffling code by Elias Levy @ SecurityFocus.com Files:
+ dns/dns_rr.c, smtp/smtp_addr.c.
+
+20010501
+
+ Bugfix: The SMTP server's 550 in reply to DATA should be
+ a 554 response. And it wasn't Sendmail. Claus Assman.
+
+ Bugfix: the INSTALL.sh test for non-interactive upgrade
+ broke rooted installations that specify settings via the
+ environment. Simon Mudd.
+
+ Bugfix: mailq output is now really flushed one message at
+ a time. File: sendmail/sendmail.c.
+
+ Feature: "postsuper -d queueID" deletes one message queue
+ file; "postsuper -d -" reads zero or more queue IDs from
+ standard input. In order to make this operation usable
+ with a running Postfix mail system, some routines were made
+ more tolerant for sudden queue file disappearances. Files:
+ postsuper/postsuper.c, global/deliver_request.c,
+ *qmgr/qmgr_move.c.
done
}
-test -f $CONFIG_DIRECTORY/install.cf && . $CONFIG_DIRECTORY/install.cf || {
- test -t 0 || {
- echo Non-interactive install needs the $CONFIG_DIRECTORY/install.cf 1>&2
- echo file from a previous Postfix installation. 1>&2
- echo 1>&2
- echo Use interactive installation instead. 1>&2
- exit 1
- }
-}
+if [ -f $CONFIG_DIRECTORY/install.cf ]
+then
+ . $CONFIG_DIRECTORY/install.cf
+elif [ ! -t 0 -a -z "$install_root" ]
+then
+ echo Non-interactive install needs the $CONFIG_DIRECTORY/install.cf 1>&2
+ echo file from a previous Postfix installation. 1>&2
+ echo 1>&2
+ echo Use interactive installation instead. 1>&2
+ exit 1
+fi
# Override default settings.
master - Postfix master process
<b>SYNOPSIS</b>
- <b>master</b> [<b>-c</b> <i>config_dir</i>] [<b>-D</b>] [<b>-t</b>] [<b>-v</b>]
+ <b>master</b> [<b>-c</b> <i>config_dir</i>] [<b>-e</b> <i>exit_time</i>] [<b>-D</b>] [<b>-t</b>] [<b>-v</b>]
<b>DESCRIPTION</b>
The <b>master</b> daemon is the resident process that runs Post-
in the named directory instead of the default con-
figuration directory.
+ <b>-e</b> <i>exit_time</i>
+ Terminate the master process after <i>exit_time</i> sec-
+ onds. Child processes terminate at their conve-
+ nience.
+
<b>-D</b> After initialization, run a debugger on the master
process. The debugging command is specified with
the <b>debugger</b><i>_</i><b>command</b> in the <b>main.cf</b> global configu-
Signals:
<b>SIGHUP</b> Upon receipt of a <b>HUP</b> signal (e.g., after <b>postfix</b>
- <b>reload</b>), the master process re-reads its configura-
- tion files. If a service has been removed from the
- <b>master.cf</b> file, its running processes are termi-
- nated immediately. Otherwise, running processes
- are allowed to terminate as soon as is convenient,
MASTER(8) MASTER(8)
+ <b>reload</b>), the master process re-reads its configura-
+ tion files. If a service has been removed from the
+ <b>master.cf</b> file, its running processes are termi-
+ nated immediately. Otherwise, running processes
+ are allowed to terminate as soon as is convenient,
so that changes in configuration settings affect
only new service requests.
<b>daemon</b><i>_</i><b>directory</b>
Directory with Postfix daemon programs.
- <b>queue</b><i>_</i><b>directory</b>
- Top-level directory of the Postfix queue. This is
- also the root directory of Postfix daemons that run
- chrooted.
-
MASTER(8) MASTER(8)
+ <b>queue</b><i>_</i><b>directory</b>
+ Top-level directory of the Postfix queue. This is
+ also the root directory of Postfix daemons that run
+ chrooted.
+
<b>Resource</b> <b>controls</b>
<b>default</b><i>_</i><b>process</b><i>_</i><b>limit</b>
Default limit for the number of simultaneous child
-
-
-
-
-
3
postsuper - Postfix super intendent
<b>SYNOPSIS</b>
- <b>postsuper</b> [<b>-p</b>] [<b>-s</b>] [<b>-v</b>] [<i>directory</i> <i>...</i>]
+ <b>postsuper</b> [<b>-d</b> <i>queue_id</i>] [<b>-p</b>] [<b>-s</b>] [<b>-v</b>] [<i>directory</i> <i>...</i>]
<b>DESCRIPTION</b>
The <b>postsuper</b> command does small maintenance jobs on the
Options:
- <b>-s</b> Structure check. Move queue files that are in the
+ <b>-d</b> Delete one message queue file with the named queue
+ ID. Specify multiple <b>-d</b> options to delete multiple
+ queue files by name.
+
+ Alternatively, if a <i>queue_id</i> of <b>-</b> is specified, the
+ program reads queue IDs from standard input.
+
+ This operation can be performed safely while the
+ mail system is running, although the queue manager
+ may issue warnings when a file suddenly disappears.
+ The exit status is zero if at least one of the
+ named message queue files was found.
+
+ <b>-s</b> Structure check. Move queue files that are in the
wrong place in the file system hierarchy and remove
- subdirectories that are no longer needed. File
- rearrangements are necessary after a change in the
+ subdirectories that are no longer needed. File
+ rearrangements are necessary after a change in the
<b>hash</b><i>_</i><b>queue</b><i>_</i><b>names</b> and/or <b>hash</b><i>_</i><b>queue</b><i>_</i><b>depth</b> configura-
- tion parameters. It is highly recommended to run
+ tion parameters. It is highly recommended to run
this check once before Postfix startup.
- <b>-p</b> Purge stale files (files that are left over after
+ <b>-p</b> Purge stale files (files that are left over after
system or software crashes).
<b>-v</b> Enable verbose logging for debugging purposes. Mul-
- tiple <b>-v</b> options make the software increasingly
+ tiple <b>-v</b> options make the software increasingly
verbose.
<b>DIAGNOSTICS</b>
- Problems are reported to the standard error stream and to
+ Problems are reported to the standard error stream and to
<b>syslogd</b>.
<b>CONFIGURATION</b> <b>PARAMETERS</b>
- See the Postfix <b>main.cf</b> file for syntax details and for
- default values.
+ See the Postfix <b>main.cf</b> file for syntax details and for
- <b>hash</b><i>_</i><b>queue</b><i>_</i><b>depth</b>
- Number of subdirectory levels for hashed queues.
- <b>hash</b><i>_</i><b>queue</b><i>_</i><b>names</b>
- The names of queues that are organized into multi-
- ple levels of subdirectories.
-<b>LICENSE</b>
- The Secure Mailer license must be distributed with this
- software.
+ 1
- 1
+POSTSUPER(1) POSTSUPER(1)
+ default values.
+ <b>hash</b><i>_</i><b>queue</b><i>_</i><b>depth</b>
+ Number of subdirectory levels for hashed queues.
-POSTSUPER(1) POSTSUPER(1)
+ <b>hash</b><i>_</i><b>queue</b><i>_</i><b>names</b>
+ The names of queues that are organized into multi-
+ ple levels of subdirectories.
+<b>LICENSE</b>
+ The Secure Mailer license must be distributed with this
+ software.
<b>AUTHOR(S)</b>
Wietse Venema
-
-
-
-
-
-
-
-
-
-
-
-
-
nasty relay loopholes involving trusted backup MX
hosts.
- <b>restriction</b><i>_</i><b>classes</b>
+ <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
echo "See the RELEASE_NOTES file for more information." 1>&2
exit 1
fi
- # See where GDBM's ndbm.h include file sits. XXX verify that
- # gdbm links in by default (i.e. NO -lgdbm is needed).
+ # See where GDBM's ndbm.h include file sits.
if [ -f /usr/include/gdbm-ndbm.h ]
then
CCARGS="$CCARGS -DHAS_DBM -DPATH_NDBM_H=\\\"<gdbm-ndbm.h>\\\""
+ GDBM_LIBS=gdbm
elif [ -f /usr/include/gdbm/ndbm.h ]
then
CCARGS="$CCARGS -DHAS_DBM -DPATH_NDBM_H=\\\"<gdbm/ndbm.h>\\\""
+ GDBM_LIBS=gdbm
fi
SYSLIBS="-ldb"
- for name in nsl resolv
+ for name in nsl resolv $GDBM_LIBS
do
test -f /usr/lib/lib$name.a && SYSLIBS="$SYSLIBS -l$name"
done
.na
.nf
.fi
-\fBpostsuper\fR [\fB-p\fR] [\fB-s\fR] [\fB-v\fR] [\fIdirectory ...\fR]
+\fBpostsuper\fR [\fB-d \fIqueue_id\fR] [\fB-p\fR]
+[\fB-s\fR] [\fB-v\fR] [\fIdirectory ...\fR]
.SH DESCRIPTION
.ad
.fi
nor directories. Use of this command is restricted to the super-user.
Options:
+.IP \fB-d \fIqueue_id\fR
+Delete one message queue file with the named queue ID. Specify
+multiple \fB-d\fR options to delete multiple queue files by name.
+.sp
+Alternatively, if a \fIqueue_id\fR of \fB-\fR is specified, the
+program reads queue IDs from standard input.
+.sp
+This operation can be performed safely while the mail system is
+running, although the queue manager may issue warnings when a
+file suddenly disappears. The exit status is zero if at least one
+of the named message queue files was found.
.IP \fB-s\fR
Structure check. Move queue files that are in the wrong place
in the file system hierarchy and remove subdirectories that are
.na
.nf
.fi
-\fBmaster\fR [\fB-c \fIconfig_dir\fR] [\fB-D\fR] [\fB-t\fR] [\fB-v\fR]
+\fBmaster\fR [\fB-c \fIconfig_dir\fR] [\fB-e \fIexit_time\fR]
+[\fB-D\fR] [\fB-t\fR] [\fB-v\fR]
.SH DESCRIPTION
.ad
.fi
.IP "\fB-c \fIconfig_dir\fR"
Read the \fBmain.cf\fR and \fBmaster.cf\fR configuration files in
the named directory instead of the default configuration directory.
+.IP "\fB-e \fIexit_time\fR"
+Terminate the master process after \fIexit_time\fR seconds. Child
+processes terminate at their convenience.
.IP \fB-D\fR
After initialization, run a debugger on the master process. The
debugging command is specified with the \fBdebugger_command\fR in
Allow untrusted clients to specify addresses with sender-specified
routing. Enabling this opens up nasty relay loopholes involving
trusted backup MX hosts.
-.IP \fBrestriction_classes\fR
+.IP \fBsmtpd_restriction_classes\fR
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.
dns_rr.o: ../../include/sys_defs.h
dns_rr.o: ../../include/msg.h
dns_rr.o: ../../include/mymalloc.h
+dns_rr.o: ../../include/myrand.h
dns_rr.o: dns.h
dns_rr.o: ../../include/vstring.h
dns_rr.o: ../../include/vbuf.h
extern DNS_RR *dns_rr_copy(DNS_RR *);
extern DNS_RR *dns_rr_append(DNS_RR *, DNS_RR *);
extern DNS_RR *dns_rr_sort(DNS_RR *, int (*) (DNS_RR *, DNS_RR *));
+extern DNS_RR *dns_rr_shuffle(DNS_RR *);
/*
* dns_lookup.c
/* DNS_RR *dns_rr_sort(list, compar)
/* DNS_RR *list
/* int (*compar)(DNS_RR *, DNS_RR *);
+/*
+/* DNS_RR *dns_rr_shuffle(list)
+/* DNS_RR *list;
/* DESCRIPTION
/* The routines in this module maintain memory for DNS resource record
/* information, and maintain lists of DNS resource records.
/* dns_rr_sort() sorts a list of resource records into ascending
/* order according to a user-specified criterion. The result is the
/* sorted list.
+/*
+/* dns_rr_shuffle() randomly permutes a list of resource records.
/* LICENSE
/* .ad
/* .fi
#include <msg.h>
#include <mymalloc.h>
+#include <myrand.h>
/* DNS library. */
dns_rr_sort_user = saved_user;
return (list);
}
+
+/* dns_rr_shuffle - shuffle resource record list */
+
+DNS_RR *dns_rr_shuffle(DNS_RR *list)
+{
+ DNS_RR **rr_array;
+ DNS_RR *rr;
+ int len;
+ int i;
+ int r;
+
+ /*
+ * Build linear array with pointers to each list element.
+ */
+ for (len = 0, rr = list; rr != 0; len++, rr = rr->next)
+ /* void */ ;
+ rr_array = (DNS_RR **) mymalloc(len * sizeof(*rr_array));
+ for (len = 0, rr = list; rr != 0; len++, rr = rr->next)
+ rr_array[len] = rr;
+
+ /*
+ * Shuffle resource records.
+ */
+ for (i = 0; i < len; i++) {
+ r = myrand() % len;
+ rr = rr_array[i];
+ rr_array[i] = rr_array[r];
+ rr_array[r] = rr;
+ }
+
+ /*
+ * Fix the links.
+ */
+ for (i = 0; i < len - 1; i++)
+ rr_array[i]->next = rr_array[i + 1];
+ rr_array[i]->next = 0;
+ list = rr_array[0];
+
+ /*
+ * Cleanup.
+ */
+ myfree((char *) rr_array);
+ return (list);
+}
#include <sys/stat.h>
#include <string.h>
#include <unistd.h>
+#include <errno.h>
/* Utility library. */
request->fp =
mail_queue_open(request->queue_name, request->queue_id, O_RDWR, 0);
- if (request->fp == 0)
- msg_fatal("open %s %s: %m", request->queue_name, request->queue_id);
+ if (request->fp == 0) {
+ if (errno != ENOENT)
+ msg_fatal("open %s %s: %m", request->queue_name, request->queue_id);
+ msg_warn("open %s %s: %m", request->queue_name, request->queue_id);
+ return (-1);
+ }
if (msg_verbose)
msg_info("%s: file %s", myname, VSTREAM_PATH(request->fp));
if (myflock(vstream_fileno(request->fp), INTERNAL_LOCK, DELIVER_LOCK_MODE) < 0)
/* #include <mail_conf.h>
/*
/* int get_mail_conf_bool(name, defval)
-/* const char *path;
/* const char *name;
/* int defval;
/*
/* int get_mail_conf_bool_fn(name, defval)
-/* const char *path;
/* const char *name;
/* int (*defval)();
/*
#define DEF_SMTP_BIND_ADDR ""
extern char *var_smtp_bind_addr;
-#define VAR_SMTP_RAND_ADDR "smtp_randomize_address"
+#define VAR_SMTP_RAND_ADDR "smtp_randomize_addresses"
#define DEF_SMTP_RAND_ADDR 1
extern bool var_smtp_rand_addr;
* Version of this program.
*/
#define VAR_MAIL_VERSION "mail_version"
-#define DEF_MAIL_VERSION "Snapshot-20010429"
+#define DEF_MAIL_VERSION "Snapshot-20010501"
extern char *var_mail_version;
/* LICENSE
"alias database unavailable") :
deliver_token_string(state, usr_attr, expansion, &alias_count));
#if 0
- if (state.msg_attr.owner == 0 && alias_count > 10)
+ if (var_ownreq_special
+ && strncmp("owner-", state.msg_attr.sender, 6) != 0
+ && alias_count > 10)
msg_warn("mailing list \"%s\" needs an \"owner-%s\" alias",
name, name);
#endif
master_ent.o: ../../include/stringops.h
master_ent.o: ../../include/readlline.h
master_ent.o: ../../include/inet_addr_list.h
+master_ent.o: ../../include/inet_util.h
+master_ent.o: ../../include/inet_addr_host.h
master_ent.o: ../../include/mail_proto.h
master_ent.o: ../../include/iostuff.h
master_ent.o: ../../include/mail_params.h
int *listen_fd; /* incoming requests */
int listen_fd_count; /* nr of descriptors */
union {
- struct INET_ADDR_LIST *inet;
- } addr_list;
+ struct {
+ char *port; /* inet listen port */
+ struct INET_ADDR_LIST *addr;/* inet listen address */
+ } inet_ep;
+#define MASTER_INET_ADDRLIST(s) ((s)->endpoint.inet_ep.addr)
+#define MASTER_INET_PORT(s) ((s)->endpoint.inet_ep.port)
+ } endpoint;
int max_proc; /* upper bound on # processes */
char *path; /* command pathname */
struct ARGV *args; /* argument vector */
if (STR_SAME(transport, MASTER_XPORT_NAME_INET)) {
serv->type = MASTER_SERV_TYPE_INET;
atmp = inet_parse(name, &host, &port);
- if (host && *host) {
+ if (*host) {
serv->flags |= MASTER_FLAG_INETHOST;/* host:port */
- serv->addr_list.inet =
- (INET_ADDR_LIST *) mymalloc(sizeof(*serv->addr_list.inet));
- inet_addr_list_init(serv->addr_list.inet);
- inet_addr_host(serv->addr_list.inet, host);
- serv->listen_fd_count = serv->addr_list.inet->used;
+ MASTER_INET_ADDRLIST(serv) = (INET_ADDR_LIST *)
+ mymalloc(sizeof(*MASTER_INET_ADDRLIST(serv)));
+ inet_addr_list_init(MASTER_INET_ADDRLIST(serv));
+ inet_addr_host(MASTER_INET_ADDRLIST(serv), host);
+ serv->listen_fd_count = MASTER_INET_ADDRLIST(serv)->used;
} else if (strcasecmp(var_inet_interfaces, DEF_INET_INTERFACES) == 0) {
- serv->addr_list.inet = 0; /* wild-card */
+ MASTER_INET_ADDRLIST(serv) = 0; /* wild-card */
serv->listen_fd_count = 1;
} else {
- serv->addr_list.inet = own_inet_addr_list(); /* virtual */
- serv->listen_fd_count = serv->addr_list.inet->used;
+ MASTER_INET_ADDRLIST(serv) = own_inet_addr_list(); /* virtual */
+ serv->listen_fd_count = MASTER_INET_ADDRLIST(serv)->used;
}
+ MASTER_INET_PORT(serv) = mystrdup(port);
myfree(atmp);
} else if (STR_SAME(transport, MASTER_XPORT_NAME_UNIX)) {
serv->type = MASTER_SERV_TYPE_UNIX;
/*
* Undo what get_master_ent() created.
*/
- if (serv->flags & MASTER_FLAG_INETHOST)
- inet_addr_list_free(serv->addr_list.inet);
+ if (serv->flags & MASTER_FLAG_INETHOST) {
+ inet_addr_list_free(MASTER_INET_ADDRLIST(serv));
+ myfree((char *) MASTER_INET_ADDRLIST(serv));
+ }
+ if (serv->type == MASTER_SERV_TYPE_INET)
+ myfree(MASTER_INET_PORT(serv));
myfree(serv->name);
myfree(serv->path);
argv_free(serv->args);
* bound to specific interface addresses.
*/
case MASTER_SERV_TYPE_INET:
- if (serv->addr_list.inet == 0) { /* wild-card */
+ if (MASTER_INET_ADDRLIST(serv) == 0) { /* wild-card */
serv->listen_fd[0] =
- inet_listen(serv->name, serv->max_proc > var_proc_limit ?
+ inet_listen(MASTER_INET_PORT(serv),
+ serv->max_proc > var_proc_limit ?
serv->max_proc : var_proc_limit, NON_BLOCKING);
close_on_exec(serv->listen_fd[0], CLOSE_ON_EXEC);
- } else { /* virtual */
+ } else { /* virtual or host:port */
for (n = 0; n < serv->listen_fd_count; n++) {
- end_point = concatenate(inet_ntoa(serv->addr_list.inet->addrs[n]),
- ":", serv->name, (char *) 0);
+ end_point = concatenate(inet_ntoa(MASTER_INET_ADDRLIST(serv)->addrs[n]),
+ ":", MASTER_INET_PORT(serv), (char *) 0);
serv->listen_fd[n]
= inet_listen(end_point, serv->max_proc > var_proc_limit ?
serv->max_proc : var_proc_limit, NON_BLOCKING);
#include <sys/stat.h>
#include <string.h>
#include <utime.h>
+#include <errno.h>
/* Utility library. */
if (time_stamp > 0) {
tbuf.actime = tbuf.modtime = time_stamp;
path = mail_queue_path((VSTRING *) 0, src_queue, queue_id);
- if (utime(path, &tbuf) < 0)
- msg_fatal("%s: update %s time stamps: %m", myname, path);
+ if (utime(path, &tbuf) < 0) {
+ if (errno != ENOENT)
+ msg_fatal("%s: update %s time stamps: %m", myname, path);
+ msg_warn("%s: update %s time stamps: %m", myname, path);
+ continue;
+ }
+ }
+ if (mail_queue_rename(queue_id, src_queue, dst_queue)) {
+ if (errno != ENOENT)
+ msg_fatal("%s: rename %s from %s to %s: %m",
+ myname, queue_id, src_queue, dst_queue);
+ msg_warn("%s: rename %s from %s to %s: %m",
+ myname, queue_id, src_queue, dst_queue);
+ continue;
}
- if (mail_queue_rename(queue_id, src_queue, dst_queue))
- msg_fatal("%s: rename %s from %s to %s: %m",
- myname, queue_id, src_queue, dst_queue);
if (msg_verbose)
msg_info("%s: moved %s from %s to %s",
myname, queue_id, src_queue, dst_queue);
postalias.o: ../../include/stringops.h
postalias.o: ../../include/split_at.h
postalias.o: ../../include/get_hostname.h
+postalias.o: ../../include/vstring_vstream.h
postalias.o: ../../include/tok822.h
postalias.o: ../../include/resolve_clnt.h
postalias.o: ../../include/mail_conf.h
postmap.o: ../../include/readlline.h
postmap.o: ../../include/stringops.h
postmap.o: ../../include/split_at.h
+postmap.o: ../../include/vstring_vstream.h
postmap.o: ../../include/mail_conf.h
postmap.o: ../../include/mail_params.h
postmap.o: ../../include/mkmap.h
/* Postfix super intendent
/* SYNOPSIS
/* .fi
-/* \fBpostsuper\fR [\fB-p\fR] [\fB-s\fR] [\fB-v\fR] [\fIdirectory ...\fR]
+/* \fBpostsuper\fR [\fB-d \fIqueue_id\fR] [\fB-p\fR]
+/* [\fB-s\fR] [\fB-v\fR] [\fIdirectory ...\fR]
/* DESCRIPTION
/* The \fBpostsuper\fR command does small maintenance jobs on the named
/* Postfix queue directories (default: all).
/* nor directories. Use of this command is restricted to the super-user.
/*
/* Options:
+/* .IP \fB-d \fIqueue_id\fR
+/* Delete one message queue file with the named queue ID. Specify
+/* multiple \fB-d\fR options to delete multiple queue files by name.
+/* .sp
+/* Alternatively, if a \fIqueue_id\fR of \fB-\fR is specified, the
+/* program reads queue IDs from standard input.
+/* .sp
+/* This operation can be performed safely while the mail system is
+/* running, although the queue manager may issue warnings when a
+/* file suddenly disappears. The exit status is zero if at least one
+/* of the named message queue files was found.
/* .IP \fB-s\fR
/* Structure check. Move queue files that are in the wrong place
/* in the file system hierarchy and remove subdirectories that are
#include <safe.h>
#include <set_ugid.h>
#include <argv.h>
+#include <vstring_vstream.h>
/* Global library. */
#define ACTION_STRUCT (1<<0) /* fix file organization */
#define ACTION_PURGE (1<<1) /* purge old temp files */
+#define ACTION_DELETE (1<<2) /* delete named queue file(s) */
#define ACTION_DEFAULT (ACTION_STRUCT | ACTION_PURGE)
0,
};
+/* delete_one - delete one message instance and all its associated files */
+
+static int delete_one(const char *queue_id)
+{
+ const char *msg_queue_names[] = {
+ MAIL_QUEUE_INCOMING, /* twice, to avoid */
+ MAIL_QUEUE_ACTIVE, /* missing a file while */
+ MAIL_QUEUE_DEFERRED, /* it is being renamed */
+ MAIL_QUEUE_INCOMING, /* this is not 100% */
+ MAIL_QUEUE_ACTIVE, /* foolproof but adequate */
+ MAIL_QUEUE_DEFERRED,
+ 0,
+ };
+ const char **cpp;
+ VSTRING *msg_path = 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.
+ */
+ for (cpp = msg_queue_names; *cpp != 0; cpp++) {
+ (void) mail_queue_path(msg_path, *cpp, queue_id);
+ if (unlink(STR(msg_path)) == 0) {
+ found = 1;
+ if (msg_verbose)
+ msg_info("removed file %s", STR(msg_path));
+ break;
+ } else if (errno != ENOENT) {
+ msg_warn("remove file %s: %m", STR(msg_path));
+ }
+ }
+ vstring_free(msg_path);
+ return (found);
+}
+
+/* delete_stream - delete queue IDs given on stream */
+
+static int delete_stream(VSTREAM *fp)
+{
+ VSTRING *buf = vstring_alloc(20);
+ int found = 0;
+
+ while (vstring_get_nonl(buf, fp) != VSTREAM_EOF)
+ found |= delete_one(STR(buf));
+
+ vstring_free(buf);
+ return (found);
+}
+
/* super - check queue file location and clean up */
static void super(char **queues, int action)
int action = 0;
char **queues;
int c;
+ int found = 0;
/*
* Defaults.
/*
* Parse JCL.
*/
- while ((c = GETOPT(argc, argv, "spv")) > 0) {
+ while ((c = GETOPT(argc, argv, "d:spv")) > 0) {
switch (c) {
default:
- msg_fatal("usage: %s [-s (fix structure)] [-p (purge stale files)]",
+ msg_fatal("usage: %s [-d queue_id] [-p (purge stale files)] [-s (fix structure)]",
argv[0]);
+ case 'd':
+ if (strcmp(optarg, "-") == 0)
+ found |= delete_stream(VSTREAM_IN);
+ else
+ found |= delete_one(optarg);
+ action |= ACTION_DELETE;
+ break;
case 's':
action |= ACTION_STRUCT;
break;
else
queues = argv + optind;
- super(queues, action);
+ if (action & ~ACTION_DELETE)
+ super(queues, action & ~ACTION_DELETE);
- exit(0);
+ exit((action & ACTION_DELETE) ? !found : 0);
}
#include <sys/stat.h>
#include <string.h>
#include <utime.h>
+#include <errno.h>
/* Utility library. */
if (time_stamp > 0) {
tbuf.actime = tbuf.modtime = time_stamp;
path = mail_queue_path((VSTRING *) 0, src_queue, queue_id);
- if (utime(path, &tbuf) < 0)
- msg_fatal("%s: update %s time stamps: %m", myname, path);
+ if (utime(path, &tbuf) < 0) {
+ if (errno != ENOENT)
+ msg_fatal("%s: update %s time stamps: %m", myname, path);
+ msg_warn("%s: update %s time stamps: %m", myname, path);
+ continue;
+ }
+ }
+ if (mail_queue_rename(queue_id, src_queue, dst_queue)) {
+ if (errno != ENOENT)
+ msg_fatal("%s: rename %s from %s to %s: %m",
+ myname, queue_id, src_queue, dst_queue);
+ msg_warn("%s: rename %s from %s to %s: %m",
+ myname, queue_id, src_queue, dst_queue);
+ continue;
}
- if (mail_queue_rename(queue_id, src_queue, dst_queue))
- msg_fatal("%s: rename %s from %s to %s: %m",
- myname, queue_id, src_queue, dst_queue);
if (msg_verbose)
msg_info("%s: moved %s from %s to %s",
myname, queue_id, src_queue, dst_queue);
signal(SIGPIPE, SIG_DFL);
if ((showq = mail_connect(MAIL_CLASS_PUBLIC, MAIL_SERVICE_SHOWQ, BLOCKING)) != 0) {
while ((n = vstream_fread(showq, buf, sizeof(buf))) > 0)
- if (vstream_fwrite(VSTREAM_OUT, buf, n) != n)
+ if (vstream_fwrite(VSTREAM_OUT, buf, n) != n
+ || vstream_fflush(VSTREAM_OUT) != 0)
msg_fatal("write error: %m");
- if (vstream_fflush(VSTREAM_OUT))
- msg_fatal("write error: %m");
-
if (vstream_fclose(showq))
msg_warn("close: %m");
}
smtp_addr.o: ../../include/mymalloc.h
smtp_addr.o: ../../include/inet_addr_list.h
smtp_addr.o: ../../include/stringops.h
+smtp_addr.o: ../../include/myrand.h
smtp_addr.o: ../../include/mail_params.h
smtp_addr.o: ../../include/own_inet_addr.h
smtp_addr.o: ../../include/dns.h
msg_info("end %s address list", what);
}
-/* smtp_rand_addr - randomize equal-preference resource records */
-
-static int smtp_rand_addr(DNS_RR *a, DNS_RR *b)
-{
- int diff;
-
- /*
- * XXX Equal-preference records are made to appear different. The bogus
- * difference is not consistent from one call to the next. Code based on
- * an idea by Aleph1.
- */
- return ((diff = a->pref - b->pref != 0) ? diff : (myrand() & 1) ? -1 : 1);
-}
-
/* smtp_addr_one - address lookup for one host name */
static DNS_RR *smtp_addr_one(DNS_RR *addr_list, char *host, unsigned pref, VSTRING *why)
}
}
}
- if (addr_list && var_smtp_rand_addr)
- addr_list = dns_rr_sort(addr_list, smtp_rand_addr);
+ if (addr_list && addr_list->next && var_smtp_rand_addr) {
+ addr_list = dns_rr_shuffle(addr_list);
+ addr_list = dns_rr_sort(addr_list, smtp_compare_pref);
+ }
break;
case DNS_NOTFOUND:
addr_list = smtp_host_addr(name, why);
*/
#define PREF0 0
addr_list = smtp_addr_one((DNS_RR *) 0, host, PREF0, why);
- if (addr_list && var_smtp_rand_addr)
- addr_list = dns_rr_sort(addr_list, smtp_rand_addr);
+ if (addr_list && addr_list->next && var_smtp_rand_addr)
+ addr_list = dns_rr_shuffle(addr_list);
if (msg_verbose)
smtp_print_addr(host, addr_list);
return (addr_list);
state->error_mask |= MAIL_ERROR_PROTOCOL;
smtpd_chat_reply(state, "503 Error: need RCPT command");
} else {
- smtpd_chat_reply(state, "550 Error: no valid recipients");
+ smtpd_chat_reply(state, "554 Error: no valid recipients");
}
return (-1);
}
/* SMTPD_STATE *state;
/* char *recipient;
/*
+/* char *smtpd_check_rcptmap(state, recipient)
+/* SMTPD_STATE *state;
+/* char *recipient;
+/*
/* char *smtpd_check_etrn(state, destination)
/* SMTPD_STATE *state;
/* char *destination;
/* Restrictions on the recipient address that is sent with the RCPT
/* TO command.
/* .PP
+/* smtpd_check_rcptmap() validates the recipient address provided
+/* with an RCPT TO request. Relevant configuration parameters:
+/* .IP local_recipients_map
+/* Tables of user names (not addresses) that exist in $mydestination.
+/* Mail for local users not in these tables is rejected.
+/* .PP
/* smtpd_check_etrn() validates the domain name provided with the
/* ETRN command, and other client-provided information. Relevant
/* configuration parameters:
#
# MX backup
#
-mydestination spike.porcupine.org,localhost.porcupine.org
-inet_interfaces 168.100.189.2,127.0.0.1
-recipient_restrictions permit_mx_backup,reject
-rcpt wietse@wzv.win.tue.nl
-rcpt wietse@trouble.org
-rcpt wietse@porcupine.org
+#mydestination spike.porcupine.org,localhost.porcupine.org
+#inet_interfaces 168.100.189.2,127.0.0.1
+#recipient_restrictions permit_mx_backup,reject
+#rcpt wietse@wzv.win.tue.nl
+#rcpt wietse@trouble.org
+#rcpt wietse@porcupine.org
#
# Deferred restrictions
#
>>> client foo 123.123.123.123
OK
>>> helo foo.
-./smtpd_check: warning: valid_hostname: misplaced delimiter: foo.
-./smtpd_check: warning: valid_hostname: misplaced delimiter: foo.
./smtpd_check: reject: HELO from foo[123.123.123.123]: 450 <foo.>: Helo command rejected: Host not found
450 <foo.>: Helo command rejected: Host not found
>>> helo foo
>>> helo_restrictions reject_invalid_hostname,reject_unknown_hostname
OK
>>> helo 123.123.123.123
-./smtpd_check: warning: valid_hostname: numeric hostname: 123.123.123.123
-./smtpd_check: warning: valid_hostname: numeric hostname: 123.123.123.123
-./smtpd_check: warning: valid_hostname: numeric hostname: 123.123.123.123
./smtpd_check: reject: HELO from foo[123.123.123.123]: 450 <123.123.123.123>: Helo command rejected: Host not found
450 <123.123.123.123>: Helo command rejected: Host not found
>>> helo_restrictions permit_naked_ip_address,reject_invalid_hostname,reject_unknown_hostname
>>> client spike.porcupine.org 168.100.189.2
OK
>>> client foo 127.0.0.2
-./smtpd_check: reject: CONNECT from foo[127.0.0.2]: 554 Service unavailable; [127.0.0.2] blocked using rbl.maps.vix.com, reason: Blackholed - see <URL:http://mail-abuse.org/cgi-bin/lookup?127.0.0.2>; from=<foo@friend.bad.domain>
-554 Service unavailable; [127.0.0.2] blocked using rbl.maps.vix.com, reason: Blackholed - see <URL:http://mail-abuse.org/cgi-bin/lookup?127.0.0.2>
+./smtpd_check: reject: CONNECT from foo[127.0.0.2]: 554 Service unavailable; [127.0.0.2] blocked using blackholes.mail-abuse.org, reason: Blackholed - see <URL:http://mail-abuse.org/cgi-bin/lookup?127.0.0.2>; from=<foo@friend.bad.domain>
+554 Service unavailable; [127.0.0.2] blocked using blackholes.mail-abuse.org, reason: Blackholed - see <URL:http://mail-abuse.org/cgi-bin/lookup?127.0.0.2>
>>> #
>>> # Hybrids
>>> #
./smtpd_check: reject: RCPT from foo[131.155.210.17]: 554 <bad.domain>: Helo command rejected: match bad.domain; from=<foo@friend.bad.domain> to=<foo@porcupine.org>
554 <bad.domain>: Helo command rejected: match bad.domain
>>> helo 131.155.210.17
-./smtpd_check: warning: valid_hostname: numeric hostname: 131.155.210.17
OK
>>> rcpt foo@porcupine.org
OK
>>> #
>>> # MX backup
>>> #
->>> mydestination spike.porcupine.org,localhost.porcupine.org
-OK
->>> inet_interfaces 168.100.189.2,127.0.0.1
-OK
->>> recipient_restrictions permit_mx_backup,reject
-OK
->>> rcpt wietse@wzv.win.tue.nl
-OK
->>> rcpt wietse@trouble.org
-./smtpd_check: reject: RCPT from foo[131.155.210.17]: 554 <wietse@trouble.org>: Recipient address rejected: Access denied; from=<foo@friend.bad.domain> to=<wietse@trouble.org>
-554 <wietse@trouble.org>: Recipient address rejected: Access denied
->>> rcpt wietse@porcupine.org
-OK
+>>> #mydestination spike.porcupine.org,localhost.porcupine.org
+>>> #inet_interfaces 168.100.189.2,127.0.0.1
+>>> #recipient_restrictions permit_mx_backup,reject
+>>> #rcpt wietse@wzv.win.tue.nl
+>>> #rcpt wietse@trouble.org
+>>> #rcpt wietse@porcupine.org
>>> #
>>> # Deferred restrictions
>>> #
>>> helo [1.2.3.4]
OK
>>> helo [321.255.255.255]
-./smtpd_check: warning: valid_hostaddr: invalid octet value: 321.255.255.255
./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <[321.255.255.255]>: Helo command rejected: invalid ip address; from=<foo>
501 <[321.255.255.255]>: Helo command rejected: invalid ip address
>>> helo [0.255.255.255]
-./smtpd_check: warning: valid_hostaddr: bad initial octet value: 0.255.255.255
./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <[0.255.255.255]>: Helo command rejected: invalid ip address; from=<foo>
501 <[0.255.255.255]>: Helo command rejected: invalid ip address
>>> helo [1.2.3.321]
-./smtpd_check: warning: valid_hostaddr: invalid octet value: 1.2.3.321
./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <[1.2.3.321]>: Helo command rejected: invalid ip address; from=<foo>
501 <[1.2.3.321]>: Helo command rejected: invalid ip address
>>> helo [1.2.3]
-./smtpd_check: warning: valid_hostaddr: invalid octet count: 1.2.3
./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <[1.2.3]>: Helo command rejected: invalid ip address; from=<foo>
501 <[1.2.3]>: Helo command rejected: invalid ip address
>>> helo [1.2.3.4.5]
-./smtpd_check: warning: valid_hostaddr: invalid octet count: 1.2.3.4.5
./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <[1.2.3.4.5]>: Helo command rejected: invalid ip address; from=<foo>
501 <[1.2.3.4.5]>: Helo command rejected: invalid ip address
>>> helo [1..2.3.4]
-./smtpd_check: warning: valid_hostaddr: misplaced dot: 1..2.3.4
./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <[1..2.3.4]>: Helo command rejected: invalid ip address; from=<foo>
501 <[1..2.3.4]>: Helo command rejected: invalid ip address
>>> helo [.1.2.3.4]
-./smtpd_check: warning: valid_hostaddr: misplaced dot: .1.2.3.4
./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <[.1.2.3.4]>: Helo command rejected: invalid ip address; from=<foo>
501 <[.1.2.3.4]>: Helo command rejected: invalid ip address
>>> helo [1.2.3.4.5.]
-./smtpd_check: warning: valid_hostaddr: misplaced dot: 1.2.3.4.5.
./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <[1.2.3.4.5.]>: Helo command rejected: invalid ip address; from=<foo>
501 <[1.2.3.4.5.]>: Helo command rejected: invalid ip address
>>> helo 1.2.3.4
OK
>>> helo 321.255.255.255
-./smtpd_check: warning: valid_hostaddr: invalid octet value: 321.255.255.255
./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <321.255.255.255>: Helo command rejected: invalid ip address; from=<foo>
501 <321.255.255.255>: Helo command rejected: invalid ip address
>>> helo 0.255.255.255
-./smtpd_check: warning: valid_hostaddr: bad initial octet value: 0.255.255.255
./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <0.255.255.255>: Helo command rejected: invalid ip address; from=<foo>
501 <0.255.255.255>: Helo command rejected: invalid ip address
>>> helo 1.2.3.321
-./smtpd_check: warning: valid_hostaddr: invalid octet value: 1.2.3.321
./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <1.2.3.321>: Helo command rejected: invalid ip address; from=<foo>
501 <1.2.3.321>: Helo command rejected: invalid ip address
>>> helo 1.2.3
-./smtpd_check: warning: valid_hostaddr: invalid octet count: 1.2.3
./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <1.2.3>: Helo command rejected: invalid ip address; from=<foo>
501 <1.2.3>: Helo command rejected: invalid ip address
>>> helo 1.2.3.4.5
-./smtpd_check: warning: valid_hostaddr: invalid octet count: 1.2.3.4.5
./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <1.2.3.4.5>: Helo command rejected: invalid ip address; from=<foo>
501 <1.2.3.4.5>: Helo command rejected: invalid ip address
>>> helo 1..2.3.4
-./smtpd_check: warning: valid_hostaddr: misplaced dot: 1..2.3.4
./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <1..2.3.4>: Helo command rejected: invalid ip address; from=<foo>
501 <1..2.3.4>: Helo command rejected: invalid ip address
>>> helo .1.2.3.4
-./smtpd_check: warning: valid_hostaddr: misplaced dot: .1.2.3.4
./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <.1.2.3.4>: Helo command rejected: invalid ip address; from=<foo>
501 <.1.2.3.4>: Helo command rejected: invalid ip address
>>> helo 1.2.3.4.5.
-./smtpd_check: warning: valid_hostaddr: misplaced dot: 1.2.3.4.5.
./smtpd_check: reject: HELO from foo[131.155.210.17]: 501 <1.2.3.4.5.>: Helo command rejected: invalid ip address; from=<foo>
501 <1.2.3.4.5.>: Helo command rejected: invalid ip address
>>> client foo 123.123.123.123
OK
>>> helo foo.
-./smtpd_check: warning: valid_hostname: misplaced delimiter: foo.
-./smtpd_check: warning: valid_hostname: misplaced delimiter: foo.
./smtpd_check: reject: HELO from foo[123.123.123.123]: 450 <foo.>: Helo command rejected: Host not found
450 <foo.>: Helo command rejected: Host not found
>>> helo foo
>>> client spike.porcupine.org 168.100.189.2
OK
>>> client foo 127.0.0.2
-./smtpd_check: reject: CONNECT from foo[127.0.0.2]: 554 Service unavailable; [127.0.0.2] blocked using rbl.maps.vix.com, reason: Blackholed - see <URL:http://mail-abuse.org/cgi-bin/lookup?127.0.0.2>; from=<foo@friend.bad.domain>
-554 Service unavailable; [127.0.0.2] blocked using rbl.maps.vix.com, reason: Blackholed - see <URL:http://mail-abuse.org/cgi-bin/lookup?127.0.0.2>
+./smtpd_check: reject: CONNECT from foo[127.0.0.2]: 554 Service unavailable; [127.0.0.2] blocked using blackholes.mail-abuse.org, reason: Blackholed - see <URL:http://mail-abuse.org/cgi-bin/lookup?127.0.0.2>; from=<foo@friend.bad.domain>
+554 Service unavailable; [127.0.0.2] blocked using blackholes.mail-abuse.org, reason: Blackholed - see <URL:http://mail-abuse.org/cgi-bin/lookup?127.0.0.2>
>>> #
>>> # unknown sender/recipient domain
>>> #
rand_sleep.o: rand_sleep.c
rand_sleep.o: sys_defs.h
rand_sleep.o: msg.h
+rand_sleep.o: myrand.h
rand_sleep.o: iostuff.h
read_wait.o: read_wait.c
read_wait.o: sys_defs.h
/* mysrand() performs initialization. This call may be skipped.
/*
/* myrand() returns a pseudo-random number in the range [0, RAND_MAX].
-/* If mysrand() was not called, it is invoked with the process ID.
+/* If mysrand() was not called, it is invoked with the process ID
+/* ex-or-ed with the time of day in seconds.
/* LICENSE
/* .ad
/* .fi
/* The Secure Mailer license must be distributed with this software.
+/* WARNING
+/* Do not use this code for generating unpredictable numbers.
/* AUTHOR(S)
/* Wietse Venema
/* IBM T.J. Watson Research
#include <sys_defs.h>
#include <stdlib.h>
#include <unistd.h>
+#include <time.h>
/* Utility library. */
int myrand(void)
{
if (myrand_initdone == 0)
- mysrand(getpid());
+ mysrand(getpid() ^ time((time_t *) 0));
return (rand());
}
/* SYNOPSIS
/* #include <sane_fsops.h>
/*
-/* int sane_link(old, new)
+/* int sane_link(from, to)
/* const char *from;
/* const char *to;
/* DESCRIPTION
/* int fd;
/* DESCRIPTION
/* writable() asks the kernel if the specified file descriptor
-/* is writable, i.e. a read operation would not block.
+/* is writable, i.e. a write operation would not block.
/*
/* Arguments:
/* .IP fd