bring things up to dma-dfly-2009-07-17 plus my Debian branch patches.
-dma (0.0.2009.02.11-1) unstable; urgency=low
+dma (0.0.2009.07.17-1) unstable; urgency=low
* Initial release
(Closes: #511410, #533458, #533614, #533890, #534101, #534860)
- -- Peter Pentchev <roam@ringlet.net> Mon, 29 Jun 2009 14:31:29 +0300
+ -- Peter Pentchev <roam@ringlet.net> Fri, 31 Jul 2009 18:41:35 +0300
Several fixes to make dma build on Debian:
- build and install the files in the etc/ subdirectory;
-- disable compiler warnings;
- generate aliases_parse.h and let the others depend on it;
-- replace open(..., O_EXLOCK) with a new open_locked() routine;
-- use st_mtime instead of st_mtimespec;
-- define the __unused function attribute;
-- do not redefine PATH_MAX.
+- define the __DECONST macro;
+- prototype open_locked() in dma.c, just in case;
+- use mtime instead of mtimespec.
All of these are taken from the Ringlet Subversion repository:
http://svn.ringlet.net/svn/ringlet/mail/dma/
+SUBDIR= etc
+
- CFLAGS+= -DHAVE_CRYPTO
CFLAGS+= -I${.CURDIR}
-@@ -14,6 +16,25 @@
- BINOWN= root
- BINGRP= mail
+ DPADD= ${LIBSSL} ${LIBCRYPTO}
+@@ -15,4 +17,23 @@
BINMODE=2555
--WARNS?= 1
-+#WARNS?= 1
-+
+ WARNS?= 6
+
+# The pmake Debian package does not seem to deal properly with y.tab.h
+
+DPSRCS+= aliases_parse.h
+
+aliases_parse.o: aliases_parse.h
+aliases_scan.o: aliases_parse.h
-
++
.include <bsd.prog.mk>
+
+.include <bsd.subdir.mk>
--- a/dma.c
+++ b/dma.c
@@ -74,6 +74,8 @@
- static int daemonize = 1;
- struct config *config;
+ static struct strlist seenmsg[16][16];
+
+static int open_locked(const char *, int);
+
char *
hostname(void)
{
-@@ -542,7 +544,7 @@
- }
-
- /* mailx removes users mailspool file if empty, so open with O_CREAT */
-- mbox = open(fn, O_WRONLY | O_EXLOCK | O_APPEND | O_CREAT);
-+ mbox = open_locked(fn, O_WRONLY | O_APPEND | O_CREAT);
- if (mbox < 0) {
- syslog(LOG_ERR, "%s: local delivery deferred: can not open `%s': %m",
- it->queueid, fn);
-@@ -639,7 +641,7 @@
+@@ -803,7 +805,7 @@
exit(1);
}
if (gettimeofday(&now, NULL) == 0 &&
- (now.tv_sec - st.st_mtimespec.tv_sec > MAX_TIMEOUT)) {
+ (now.tv_sec - st.st_mtime > MAX_TIMEOUT)) {
- char *msg;
-
- if (asprintf(&msg,
-@@ -703,7 +705,7 @@
- continue;
- if (asprintf(&queuefn, "%s/%s", config->spooldir, de->d_name) < 0)
- goto fail;
-- fd = open(queuefn, O_RDONLY|O_EXLOCK|O_NONBLOCK);
-+ fd = open_locked(queuefn, O_RDONLY|O_NONBLOCK);
- if (fd < 0) {
- /* Ignore locked files */
- if (errno == EWOULDBLOCK)
-@@ -962,3 +964,24 @@
- /* NOTREACHED */
- return (0);
- }
-+
-+static int
-+open_locked(const char *fname, int flags)
-+{
-+#ifndef O_EXLOCK
-+ int fd, save_errno;
-+
-+ fd = open(fname, flags, 0);
-+ if (fd < 0)
-+ return(fd);
-+ if (flock(fd, LOCK_EX|((flags & O_NONBLOCK)? LOCK_NB: 0)) < 0) {
-+ save_errno = errno;
-+ close(fd);
-+ errno = save_errno;
-+ return(-1);
-+ }
-+ return(fd);
-+#else
-+ return(open(fname, flags|O_EXLOCK));
-+#endif
-+}
+ asprintf(__DECONST(void *, &errmsg),
+ "Could not deliver for the last %d seconds. Giving up.",
+ MAX_TIMEOUT);
--- a/dma.h
+++ b/dma.h
-@@ -46,6 +46,13 @@
- #include <stdint.h>
- #include <stdio.h>
-
-+#ifndef __unused
-+#ifdef __GNUC__
-+#define __unused __attribute__((unused))
-+#else
-+#define __unused
-+#endif /* __GNUC__ */
-+#endif
+@@ -52,6 +52,10 @@
+ #endif /* __GNUC__ */
+ #endif
++#ifndef __DECONST
++#define __DECONST(type, var) ((type)(uintptr_t)(const void *)(var))
++#endif /* __DECONST */
++
#define VERSION "DragonFly Mail Agent"
-@@ -53,7 +60,9 @@
- #define MIN_RETRY 300 /* 5 minutes */
- #define MAX_RETRY (3*60*60) /* retry at least every 3 hours */
- #define MAX_TIMEOUT (5*24*60*60) /* give up after 5 days */
-+#ifndef PATH_MAX
- #define PATH_MAX 1024 /* Max path len */
-+#endif
- #define SMTP_PORT 25 /* Default SMTP port */
- #define CON_TIMEOUT 120 /* Connection timeout */
-
+ #define BUF_SIZE 2048
--- a/dma.8
+++ b/dma.8
-@@ -248,7 +248,7 @@
+@@ -269,7 +269,7 @@
The
.Nm
utility first appeared in
--- a/dma.8
+++ b/dma.8
-@@ -141,7 +141,7 @@
+@@ -143,7 +143,7 @@
.Pa dma.conf .
.Bl -tag -width 4n
.It Ic SMARTHOST Xo
.Xc
If you want to send outgoing mails via a smarthost, set this variable to
your smarthosts address.
-@@ -156,7 +156,7 @@
+@@ -158,7 +158,7 @@
will deliver all mails to this port, regardless of whether a smarthost is set
or not.
.It Ic ALIASES Xo
# Path to your spooldir. Just stay with the default.
SPOOLDIR /var/spool/dma
-@@ -39,4 +39,4 @@
+@@ -39,7 +39,7 @@
# Uncomment if you want to defer your mails. This is useful if you are
# behind a dialup line. You have to submit your mails manually with dma -q
-#DEFER
+DEFER
+
+ # Uncomment if you want the bounce message to include the complete original
+ # message, not just the headers.
--- a/Makefile
+++ b/Makefile
-@@ -15,7 +15,7 @@
+@@ -14,7 +14,7 @@
BINOWN= root
BINGRP= mail
-BINMODE=2555
+BINMODE=2755
- #WARNS?= 1
+ WARNS?= 6
# The pmake Debian package does not seem to deal properly with y.tab.h
+++ /dev/null
-Store the last error or status message received from the remote server in
-the neterr[] buffer and display it instead of the meaningless %m in
-remote delivery syslog messages.
-
---- a/crypto.c
-+++ b/crypto.c
-@@ -122,7 +122,8 @@
- send_remote_command(fd, "STARTTLS");
- if (read_remote(fd, 0, NULL) != 2) {
- syslog(LOG_ERR, "%s: remote delivery failed:"
-- " STARTTLS not available: %m", it->queueid);
-+ " STARTTLS not available: %s", it->queueid,
-+ neterr);
- config->features &= ~NOSSL;
- return (-1);
- }
-@@ -267,7 +268,8 @@
- send_remote_command(fd, "AUTH CRAM-MD5");
- if (read_remote(fd, sizeof(buffer), buffer) != 3) {
- syslog(LOG_ERR, "%s: smarthost authentification:"
-- " AUTH cram-md5 not available: %m", it->queueid);
-+ " AUTH cram-md5 not available: %s", it->queueid,
-+ neterr);
- /* if cram-md5 is not available */
- return (-1);
- }
-@@ -296,7 +298,8 @@
- send_remote_command(fd, "%s", temp);
- if (read_remote(fd, 0, NULL) != 2) {
- syslog(LOG_ERR, "%s: remote delivery deferred:"
-- " AUTH cram-md5 failed: %m", it->queueid);
-+ " AUTH cram-md5 failed: %s", it->queueid,
-+ neterr);
- return (-2);
- }
-
---- a/dma.h
-+++ b/dma.h
-@@ -139,6 +139,8 @@
-
- extern struct aliases aliases;
-
-+extern char neterr[BUF_SIZE];
-+
- /* aliases_parse.y */
- extern int yyparse(void);
- extern FILE *yyin;
---- a/net.c
-+++ b/net.c
-@@ -48,6 +48,7 @@
- #endif /* HAVE_CRYPTO */
-
- #include <err.h>
-+#include <errno.h>
- #include <netdb.h>
- #include <setjmp.h>
- #include <signal.h>
-@@ -59,6 +60,7 @@
- extern struct config *config;
- extern struct authusers authusers;
- static jmp_buf timeout_alarm;
-+char neterr[BUF_SIZE];
-
- static void
- sig_alarm(int signo __unused)
-@@ -99,10 +101,12 @@
- int done = 0, status = 0, extbufpos = 0;
-
- if (signal(SIGALRM, sig_alarm) == SIG_ERR) {
-- syslog(LOG_ERR, "SIGALRM error: %m");
-+ snprintf(neterr, sizeof(neterr), "SIGALRM error: %s",
-+ strerror(errno));
-+ return (1);
- }
- if (setjmp(timeout_alarm) != 0) {
-- syslog(LOG_ERR, "Timeout reached");
-+ snprintf(neterr, sizeof(neterr), "Timeout reached");
- return (1);
- }
- alarm(CON_TIMEOUT);
-@@ -163,6 +167,10 @@
- }
- alarm(0);
-
-+ buff[len] = '\0';
-+ while (len > 0 && (buff[len - 1] == '\r' || buff[len - 1] == '\n'))
-+ buff[--len] = '\0';
-+ snprintf(neterr, sizeof(neterr), "%s", buff);
- status = atoi(buff);
- return (status/100);
- }
-@@ -194,7 +202,8 @@
- send_remote_command(fd, "AUTH LOGIN");
- if (read_remote(fd, 0, NULL) != 3) {
- syslog(LOG_ERR, "%s: remote delivery deferred:"
-- " AUTH login not available: %m", it->queueid);
-+ " AUTH login not available: %s",
-+ it->queueid, neterr);
- return (1);
- }
-
-@@ -205,7 +214,8 @@
- send_remote_command(fd, "%s", temp);
- if (read_remote(fd, 0, NULL) != 3) {
- syslog(LOG_ERR, "%s: remote delivery deferred:"
-- " AUTH login failed: %m", it->queueid);
-+ " AUTH login failed: %s", it->queueid,
-+ neterr);
- return (-1);
- }
-
-@@ -217,11 +227,13 @@
- res = read_remote(fd, 0, NULL);
- if (res == 5) {
- syslog(LOG_ERR, "%s: remote delivery failed:"
-- " Authentication failed: %m", it->queueid);
-+ " Authentication failed: %s",
-+ it->queueid, neterr);
- return (-1);
- } else if (res != 2) {
- syslog(LOG_ERR, "%s: remote delivery failed:"
-- " AUTH password failed: %m", it->queueid);
-+ " AUTH password failed: %s",
-+ it->queueid, neterr);
- return (-1);
- }
- } else {
-@@ -341,7 +353,7 @@
- send_remote_command(fd, "EHLO %s", hostname());
- if (read_remote(fd, 0, NULL) != 2) {
- syslog(LOG_ERR, "%s: remote delivery deferred: "
-- " EHLO failed: %m", it->queueid);
-+ " EHLO failed: %s", it->queueid, neterr);
- return (-1);
- }
- }
-@@ -350,7 +362,7 @@
- send_remote_command(fd, "EHLO %s", hostname());
- if (read_remote(fd, 0, NULL) != 2) {
- syslog(LOG_ERR, "%s: remote delivery deferred: "
-- " EHLO failed: %m", it->queueid);
-+ " EHLO failed: %s", it->queueid, neterr);
- return (-1);
- }
- }
-@@ -388,27 +400,27 @@
- send_remote_command(fd, "MAIL FROM:<%s>", it->sender);
- if (read_remote(fd, 0, NULL) != 2) {
- syslog(LOG_ERR, "%s: remote delivery deferred:"
-- " MAIL FROM failed: %m", it->queueid);
-+ " MAIL FROM failed: %s", it->queueid, neterr);
- return (1);
- }
-
- send_remote_command(fd, "RCPT TO:<%s>", it->addr);
- if (read_remote(fd, 0, NULL) != 2) {
- syslog(LOG_ERR, "%s: remote delivery deferred:"
-- " RCPT TO failed: %m", it->queueid);
-+ " RCPT TO failed: %s", it->queueid, neterr);
- return (1);
- }
-
- send_remote_command(fd, "DATA");
- if (read_remote(fd, 0, NULL) != 3) {
- syslog(LOG_ERR, "%s: remote delivery deferred:"
-- " DATA failed: %m", it->queueid);
-+ " DATA failed: %s", it->queueid, neterr);
- return (1);
- }
-
- if (fseek(it->queuef, it->hdrlen, SEEK_SET) != 0) {
-- syslog(LOG_ERR, "%s: remote delivery deferred: cannot seek: %m",
-- it->queueid);
-+ syslog(LOG_ERR, "%s: remote delivery deferred: cannot seek: %s",
-+ it->queueid, neterr);
- return (1);
- }
-
-@@ -444,15 +456,15 @@
-
- send_remote_command(fd, ".");
- if (read_remote(fd, 0, NULL) != 2) {
-- syslog(LOG_ERR, "%s: remote delivery deferred: %m",
-- it->queueid);
-+ syslog(LOG_ERR, "%s: remote delivery deferred: %s",
-+ it->queueid, neterr);
- return (1);
- }
-
- send_remote_command(fd, "QUIT");
- if (read_remote(fd, 0, NULL) != 2) {
- syslog(LOG_ERR, "%s: remote delivery deferred: "
-- "QUIT failed: %m", it->queueid);
-+ "QUIT failed: %s", it->queueid, neterr);
- return (1);
- }
- out:
+++ /dev/null
-Treat a QUIT error as merely a warning: RFC 2821 only mandates that
-a QUIT error should abort an unfinished transaction, and since we've
-reached this point, the DATA command has succeeded and the message has
-been accepted for delivery by the remote end. Thus, just warn about it.
-
---- a/net.c
-+++ b/net.c
-@@ -462,11 +462,9 @@
- }
-
- send_remote_command(fd, "QUIT");
-- if (read_remote(fd, 0, NULL) != 2) {
-- syslog(LOG_ERR, "%s: remote delivery deferred: "
-+ if (read_remote(fd, 0, NULL) != 2)
-+ syslog(LOG_WARNING, "%s: remote delivery succeeded but "
- "QUIT failed: %s", it->queueid, neterr);
-- return (1);
-- }
- out:
-
- close(fd);
+++ /dev/null
-Recognize permanent delivery errors on remote deliveries and
-bounce the message immediately.
-
---- a/net.c
-+++ b/net.c
-@@ -397,26 +397,26 @@
- " Try without", it->queueid);
- }
-
-- send_remote_command(fd, "MAIL FROM:<%s>", it->sender);
-- if (read_remote(fd, 0, NULL) != 2) {
-- syslog(LOG_ERR, "%s: remote delivery deferred:"
-- " MAIL FROM failed: %s", it->queueid, neterr);
-- return (1);
-+#define READ_REMOTE_CHECK(c, exp) \
-+ res = read_remote(fd, 0, NULL); \
-+ if (res == 5) { \
-+ syslog(LOG_ERR, "%s: remote delivery failed: " \
-+ c " failed: %s", it->queueid, neterr); \
-+ return (-1); \
-+ } else if (res != exp) { \
-+ syslog(LOG_ERR, "%s: remote delivery deferred: " \
-+ c " failed: %s", it->queueid, neterr); \
-+ return (1); \
- }
-
-+ send_remote_command(fd, "MAIL FROM:<%s>", it->sender);
-+ READ_REMOTE_CHECK("MAIL FROM", 2);
-+
- send_remote_command(fd, "RCPT TO:<%s>", it->addr);
-- if (read_remote(fd, 0, NULL) != 2) {
-- syslog(LOG_ERR, "%s: remote delivery deferred:"
-- " RCPT TO failed: %s", it->queueid, neterr);
-- return (1);
-- }
-+ READ_REMOTE_CHECK("RCPT TO", 2);
-
- send_remote_command(fd, "DATA");
-- if (read_remote(fd, 0, NULL) != 3) {
-- syslog(LOG_ERR, "%s: remote delivery deferred:"
-- " DATA failed: %s", it->queueid, neterr);
-- return (1);
-- }
-+ READ_REMOTE_CHECK("DATA", 3);
-
- if (fseek(it->queuef, it->hdrlen, SEEK_SET) != 0) {
- syslog(LOG_ERR, "%s: remote delivery deferred: cannot seek: %s",
-@@ -455,11 +455,7 @@
- }
-
- send_remote_command(fd, ".");
-- if (read_remote(fd, 0, NULL) != 2) {
-- syslog(LOG_ERR, "%s: remote delivery deferred: %s",
-- it->queueid, neterr);
-- return (1);
-- }
-+ READ_REMOTE_CHECK("final DATA", 2);
-
- send_remote_command(fd, "QUIT");
- if (read_remote(fd, 0, NULL) != 2)
+++ /dev/null
-When listing the queue, show all messages, even those that are
-currently locked for delivery. Indicate the lock with a '*' after
-the queue ID.
-
---- a/dma.c
-+++ b/dma.c
-@@ -73,6 +73,7 @@
- struct authusers authusers = LIST_HEAD_INITIALIZER(authusers);
- static int daemonize = 1;
- struct config *config;
-+static struct strlist seenmsg[16][16];
-
- static int open_locked(const char *, int);
-
-@@ -666,8 +667,66 @@
- /* NOTREACHED */
- }
-
-+static int
-+c2x(char c)
-+{
-+ if (c <= '9')
-+ return (c - '0');
-+ else if (c <= 'F')
-+ return (c - 'A' + 10);
-+ else
-+ return (c - 'a' + 10);
-+}
-+
- static void
--load_queue(struct queue *queue)
-+seen_init(void)
-+{
-+ int i, j;
-+
-+ for (i = 0; i < 16; i++)
-+ for (j = 0; j < 16; j++)
-+ SLIST_INIT(&seenmsg[i][j]);
-+}
-+
-+static int
-+seen(const char *msgid)
-+{
-+ const char *p;
-+ size_t len;
-+ int i, j;
-+ struct stritem *t;
-+
-+ p = strchr(msgid, '.');
-+ if (p == NULL)
-+ return (0);
-+ len = p - msgid;
-+ if (len >= 2) {
-+ i = c2x(msgid[len - 2]);
-+ j = c2x(msgid[len - 1]);
-+ } else if (len == 1) {
-+ i = c2x(msgid[0]);
-+ j = 0;
-+ } else {
-+ i = j = 0;
-+ }
-+ if (i < 0 || i >= 16 || j < 0 || j >= 16)
-+ errx(1, "INTERNAL ERROR: bad seen code for msgid %s", msgid);
-+ SLIST_FOREACH(t, &seenmsg[i][j], next)
-+ if (!strncmp(t->str, msgid, len))
-+ return (1);
-+ t = malloc(sizeof(*t));
-+ if (t == NULL)
-+ errx(1, "Could not allocate %lu bytes",
-+ (unsigned long)(sizeof(*t)));
-+ t->str = strdup(msgid);
-+ if (t->str == NULL)
-+ errx(1, "Could not duplicate msgid %s", msgid);
-+ SLIST_INSERT_HEAD(&seenmsg[i][j], t, next);
-+ return (0);
-+}
-+
-+static void
-+load_queue(struct queue *queue, int nolock)
- {
- struct stat st;
- struct qitem *it;
-@@ -683,7 +742,7 @@
- char *queueid;
- char *queuefn;
- off_t hdrlen;
-- int fd;
-+ int fd, locked, seenit;
-
- LIST_INIT(&queue->queue);
-
-@@ -691,6 +750,7 @@
- if (spooldir == NULL)
- err(1, "reading queue");
-
-+ seen_init();
- while ((de = readdir(spooldir)) != NULL) {
- sender = NULL;
- queuef = NULL;
-@@ -705,12 +765,19 @@
- continue;
- if (asprintf(&queuefn, "%s/%s", config->spooldir, de->d_name) < 0)
- goto fail;
-+ seenit = seen(de->d_name);
-+ locked = 0;
- fd = open_locked(queuefn, O_RDONLY|O_NONBLOCK);
- if (fd < 0) {
- /* Ignore locked files */
-- if (errno == EWOULDBLOCK)
-+ if (errno != EWOULDBLOCK)
-+ goto skip_item;
-+ if (!nolock || seenit)
- continue;
-- goto skip_item;
-+ fd = open(queuefn, O_RDONLY);
-+ if (fd < 0)
-+ goto skip_item;
-+ locked = 1;
- }
-
- queuef = fdopen(fd, "r");
-@@ -751,6 +818,7 @@
- it->queuef = queuef;
- it->queueid = queueid;
- it->queuefn = fn;
-+ it->locked = locked;
- fn = NULL;
- }
- if (LIST_EMPTY(&itmqueue.queue)) {
-@@ -810,9 +878,9 @@
-
- LIST_FOREACH(it, &queue->queue, next) {
- printf("\
--ID\t: %s\n\
-+ID\t: %s%s\n\
- From\t: %s\n\
--To\t: %s\n--\n", it->queueid, it->sender, it->addr);
-+To\t: %s\n--\n", it->queueid, it->locked? "*": "", it->sender, it->addr);
- }
- }
-
-@@ -914,7 +982,7 @@
- if (argc != 0)
- errx(1, "sending mail and displaying queue is"
- " mutually exclusive");
-- load_queue(&lqueue);
-+ load_queue(&lqueue, 1);
- show_queue(&lqueue);
- return (0);
- }
-@@ -922,7 +990,7 @@
- if (doqueue) {
- if (argc != 0)
- errx(1, "sending mail and queue pickup is mutually exclusive");
-- load_queue(&lqueue);
-+ load_queue(&lqueue, 0);
- run_queue(&lqueue);
- return (0);
- }
---- a/dma.h
-+++ b/dma.h
-@@ -97,6 +97,7 @@
- FILE *queuef;
- off_t hdrlen;
- int remote;
-+ int locked;
- };
- LIST_HEAD(queueh, qitem);
-
-Fix two typos and a word order problem.
+Fix a typo.
--- a/crypto.c
+++ b/crypto.c
-@@ -155,7 +155,7 @@
- error = SSL_connect(config->ssl);
- if (error < 0) {
- syslog(LOG_ERR, "%s: remote delivery failed:"
-- " SSL handshake fataly failed: %m", it->queueid);
-+ " SSL handshake failed fatally: %m", it->queueid);
- return (-1);
- }
-
-@@ -163,7 +163,7 @@
- cert = SSL_get_peer_certificate(config->ssl);
- if (cert == NULL) {
- syslog(LOG_ERR, "%s: remote delivery deferred:"
-- " Peer did not provied certificate: %m", it->queueid);
-+ " Peer did not provide certificate: %m", it->queueid);
- }
- X509_free(cert);
-
-@@ -267,7 +267,7 @@
+@@ -271,7 +271,7 @@
/* Send AUTH command according to RFC 2554 */
send_remote_command(fd, "AUTH CRAM-MD5");
if (read_remote(fd, sizeof(buffer), buffer) != 3) {
-- syslog(LOG_ERR, "%s: smarthost authentification:"
-+ syslog(LOG_ERR, "%s: smarthost authentication:"
+- syslog(LOG_DEBUG, "%s: smarthost authentification:"
++ syslog(LOG_DEBUG, "%s: smarthost authentication:"
" AUTH cram-md5 not available: %s", it->queueid,
neterr);
/* if cram-md5 is not available */
--- a/Makefile
+++ b/Makefile
-@@ -4,10 +4,11 @@
+@@ -3,10 +3,11 @@
+
SUBDIR= etc
- CFLAGS+= -DHAVE_CRYPTO
+CFLAGS+= -DHAVE_LIBLOCKFILE
CFLAGS+= -I${.CURDIR}
SRCS= base64.c conf.c crypto.c net.c dma.c aliases_scan.l aliases_parse.y
--- a/dma.c
+++ b/dma.c
-@@ -60,9 +60,11 @@
+@@ -56,9 +56,11 @@
#include <syslog.h>
#include <unistd.h>
static void deliver(struct qitem *);
static int add_recp(struct queue *, const char *, const char *, int);
-@@ -526,6 +528,47 @@
+@@ -689,6 +691,47 @@
exit(1);
}
+liblockfile_strerror(int res)
+{
+ static char buf[512];
-+
++
+ switch (res) {
+ case L_SUCCESS:
+ snprintf(buf, sizeof(buf), "No error");
static int
deliver_local(struct qitem *it, const char **errmsg)
{
-@@ -536,6 +579,10 @@
+@@ -699,6 +742,10 @@
int error;
off_t mboxlen;
time_t now = time(NULL);
error = snprintf(fn, sizeof(fn), "%s/%s", _PATH_MAILDIR, it->addr);
if (error < 0 || (size_t)error >= sizeof(fn)) {
-@@ -545,17 +592,42 @@
+@@ -708,17 +755,42 @@
}
/* mailx removes users mailspool file if empty, so open with O_CREAT */
- mbox = open_locked(fn, O_WRONLY | O_APPEND | O_CREAT);
- if (mbox < 0) {
-- syslog(LOG_ERR, "%s: local delivery deferred: can not open `%s': %m",
+- syslog(LOG_NOTICE, "%s: local delivery deferred: can not open `%s': %m",
- it->queueid, fn);
- return (1);
+#ifdef HAVE_LIBLOCKFILE
+#endif
+ mbox = open_locked(fn, O_WRONLY | O_APPEND | O_CREAT);
+ if (mbox < 0) {
-+ syslog(LOG_ERR, "%s: local delivery deferred: can not open `%s': %m",
++ syslog(LOG_NOTICE, "%s: local delivery deferred: can not open `%s': %m",
+ it->queueid, fn);
+ return (1);
+ }
+ if (res == L_SUCCESS)
+ break;
+ else
-+ syslog(LOG_WARNING, "%s: could not dot-lock `%s': %s",
++ syslog(LOG_NOTICE, "%s: could not dot-lock `%s': %s",
+ it->queueid, fn, liblockfile_strerror(res));
+ close(mbox);
+ if (try++ >= 5) {
-+ syslog(LOG_ERR, "%s: local delivery deferred: can not dot-lock `%s'",
++ syslog(LOG_NOTICE, "%s: local delivery deferred: can not dot-lock `%s'",
+ it->queueid, fn);
+ return (1);
+ }
-+ syslog(LOG_WARNING, "%s: sleeping to retry the dot-lock",
++ syslog(LOG_NOTICE, "%s: sleeping to retry the dot-lock",
+ it->queueid);
+ sleep(5 * try);
}
mboxlen = lseek(mbox, 0, SEEK_CUR);
if (fseek(it->queuef, it->hdrlen, SEEK_SET) != 0) {
- syslog(LOG_ERR, "%s: local delivery deferred: can not seek: %m",
+ syslog(LOG_NOTICE, "%s: local delivery deferred: can not seek: %m",
it->queueid);
+#ifdef HAVE_LIBLOCKFILE
+ mailunlock();
return (1);
}
-@@ -563,6 +635,9 @@
+@@ -726,6 +798,9 @@
if (error < 0 || (size_t)error >= sizeof(line)) {
- syslog(LOG_ERR, "%s: local delivery deferred: can not write header: %m",
+ syslog(LOG_NOTICE, "%s: local delivery deferred: can not write header: %m",
it->queueid);
+#ifdef HAVE_LIBLOCKFILE
+ mailunlock();
return (1);
}
if (write(mbox, line, error) != error)
-@@ -575,6 +650,9 @@
+@@ -738,6 +813,9 @@
if (linelen == 0 || line[linelen - 1] != '\n') {
syslog(LOG_CRIT, "%s: local delivery failed: corrupted queue file",
it->queueid);
*errmsg = "corrupted queue file";
error = -1;
goto chop;
-@@ -592,6 +670,9 @@
+@@ -755,6 +833,9 @@
line[0] = '\n';
if (write(mbox, line, 1) != 1)
goto wrerror;
close(mbox);
return (0);
-@@ -603,6 +684,9 @@
+@@ -766,6 +847,9 @@
if (ftruncate(mbox, mboxlen) != 0)
syslog(LOG_WARNING, "%s: error recovering mbox `%s': %m",
it->queueid, fn);
--- a/conf.c
+++ b/conf.c
-@@ -233,6 +233,10 @@
+@@ -238,6 +238,10 @@
if (data != NULL)
config->certfile = strdup(data);
}
+ if (data != NULL)
+ config->dbounceprog = strdup(data);
+ }
- else if (strcmp(word, "VIRTUAL") == 0)
- config->features |= VIRTUAL;
- else if (strcmp(word, "STARTTLS") == 0)
+ else if (strcmp(word, "MAILNAME") == 0) {
+ if (data != NULL)
+ config->mailname = strdup(data);
--- a/dma.8
+++ b/dma.8
-@@ -215,6 +215,26 @@
+@@ -217,6 +217,26 @@
.Fl q
option.
This option is handy if you are behind a dialup line.
+.Ar queueid
+.Fl f
+.Ar messagefile
- .El
- .Ss virtusertable
- The
+ .It Ic FULLBOUNCE Xo
+ (boolean, default=commented)
+ .Xc
--- a/dma.c
+++ b/dma.c
-@@ -444,12 +444,114 @@
+@@ -595,14 +595,115 @@
+ struct queue bounceq;
struct qitem *bit;
char line[1000];
+- size_t pos;
int error;
+ int pipefd[2];
+ pid_t child;
+ char *buf;
+ size_t i, pos, bufsize;
+ ssize_t n;
-+ int stat;
++ int status;
+ struct sigaction sa;
/* Don't bounce bounced mails */
if (it->sender[0] == 0) {
-- syslog(LOG_CRIT, "%s: delivery panic: can't bounce a bounce",
-+ syslog(LOG_ERR, "%s: bounce delivery failed, double-bouncing",
+- syslog(LOG_INFO, "%s: can not bounce a bounce message, discarding",
++ syslog(LOG_INFO, "%s: bounce delivery failed, double-bouncing",
it->queueid);
- exit(1);
+ if (config->dbounceprog == NULL) {
+ */
+ buf[pos] = '\0';
+
-+ if (waitpid(child, &stat, 0) == -1) {
++ if (waitpid(child, &status, 0) == -1) {
+ syslog(LOG_ERR, "%s: double-bounce deferred: could not fetch the result from child process %ld: %m; child process output: %s",
+ it->queueid, (long)child, buf);
+ exit(1);
-+ } else if (WIFSIGNALED(stat)) {
++ } else if (WIFSIGNALED(status)) {
+ syslog(LOG_ERR, "%s: double-bounce deferred: child process %ld died from signal %d; child process output: %s",
-+ it->queueid, (long)child, WTERMSIG(stat), buf);
++ it->queueid, (long)child, WTERMSIG(status), buf);
+ exit(1);
-+ } else if (!WIFEXITED(stat)) {
++ } else if (!WIFEXITED(status)) {
+ syslog(LOG_ERR, "%s: double-bounce deferred: child process %ld got an unexpected waitpid code of %d; child process output: %s",
-+ it->queueid, (long)child, stat, buf);
++ it->queueid, (long)child, status, buf);
+ exit(1);
-+ } else if (WEXITSTATUS(stat) != 0) {
++ } else if (WEXITSTATUS(status) != 0) {
+ syslog(LOG_ERR, "%s: double-bounce deferred: child process %ld exited with code %d; child process output: %s",
-+ it->queueid, (long)child, (int)WEXITSTATUS(stat), buf);
++ it->queueid, (long)child, (int)WEXITSTATUS(status), buf);
+ exit(1);
+ }
+ syslog(LOG_ERR, "%s: double-bounce succeeded, message passed to handler `%s': %s",
syslog(LOG_ERR, "%s: delivery failed, bouncing",
--- a/dma.h
+++ b/dma.h
-@@ -120,6 +120,7 @@
- #ifdef HAVE_CRYPTO
+@@ -121,6 +121,7 @@
+ char *certfile;
+ int features;
SSL *ssl;
- #endif /* HAVE_CRYPTO */
+ char *dbounceprog;
+ char *mailname;
+ char *mailnamefile;
};
-
-
--- a/etc/dma.conf
+++ b/etc/dma.conf
-@@ -40,3 +40,8 @@
- # Uncomment if you want to defer your mails. This is useful if you are
+@@ -41,6 +41,11 @@
# behind a dialup line. You have to submit your mails manually with dma -q
DEFER
-+
+
+# The double-bounce handler program. Leave this blank if you like dma's
+# default behavior of simply aborting the delivery, or specify the name or
+# full path to a program that will process the double-bounce message.
+DBOUNCEPROG dbounce-simple-safecat
++
+ # Uncomment if you want the bounce message to include the complete original
+ # message, not just the headers.
+ #FULLBOUNCE
+++ /dev/null
-Note that the -q option requires an unused argument.
-
---- a/dma.8
-+++ b/dma.8
-@@ -39,13 +39,14 @@
- .Nd DragonFly Mail Agent
- .Sh SYNOPSIS
- .Nm
--.Op Fl DiOq
-+.Op Fl DiO
- .Op Fl A Ar mode
- .Op Fl b Ar mode
- .Op Fl f Ar sender
- .Op Fl L Ar tag
- .Op Fl o Ar option
- .Op Fl r Ar sender
-+.Op Fl q Ar arg
- .Op Ar recipient ...
- .Sh DESCRIPTION
- .Nm
-@@ -95,8 +96,9 @@
- is synonymous to
- .Fl i .
- All other options are ignored.
--.It Fl q
-+.It Fl q Ar arg
- Process saved messages in the queue.
-+The argument is required for compatibility with sendmail, and ignored.
- .It Fl r Ar sender
- Same as
- .Fl f .
+++ /dev/null
-Appease the Debian hardening wrapper:
-- check the result of fgets()
-- loop the network writes until the whole thing is sent
-- check one more write() result
-
---- a/conf.c
-+++ b/conf.c
-@@ -106,7 +106,8 @@
- return (-1);
-
- while (!feof(v)) {
-- fgets(line, sizeof(line), v);
-+ if (fgets(line, sizeof(line), v) == NULL)
-+ break;
- /* We hit a comment */
- if (strchr(line, '#'))
- *strchr(line, '#') = 0;
-@@ -162,7 +163,8 @@
- return (1);
-
- while (!feof(a)) {
-- fgets(line, sizeof(line), a);
-+ if (fgets(line, sizeof(line), a) == NULL)
-+ break;
- /* We hit a comment */
- if (strchr(line, '#'))
- *strchr(line, '#') = 0;
-@@ -199,7 +201,8 @@
- config->features = 0;
-
- while (!feof(conf)) {
-- fgets(line, sizeof(line), conf);
-+ if (fgets(line, sizeof(line), conf) == NULL)
-+ break;
- /* We hit a comment */
- if (strchr(line, '#'))
- *strchr(line, '#') = 0;
---- a/net.c
-+++ b/net.c
-@@ -73,23 +73,39 @@
- {
- va_list va;
- char cmd[4096];
-- ssize_t len = 0;
-+ size_t len, pos;
-+ int s;
-+ ssize_t n;
-
- va_start(va, fmt);
-- vsprintf(cmd, fmt, va);
-+ s = vsnprintf(cmd, sizeof(cmd) - 2, fmt, va);
-+ va_end(va);
-+ if (s == sizeof(cmd) - 2 || s < 0)
-+ errx(1, "Internal error: oversized command string");
-+ /* We *know* there are at least two more bytes available */
-+ strcat(cmd, "\r\n");
-+ len = strlen(cmd);
-
- if (((config->features & SECURETRANS) != 0) &&
- ((config->features & NOSSL) == 0)) {
-- len = SSL_write(config->ssl, (const char*)cmd, strlen(cmd));
-- SSL_write(config->ssl, "\r\n", 2);
-+ while ((s = SSL_write(config->ssl, (const char*)cmd, len)) <= 0) {
-+ s = SSL_get_error(config->ssl, s);
-+ if (s != SSL_ERROR_WANT_READ &&
-+ s != SSL_ERROR_WANT_WRITE)
-+ return (-1);
-+ }
- }
- else {
-- len = write(fd, cmd, strlen(cmd));
-- write(fd, "\r\n", 2);
-+ pos = 0;
-+ while (pos < len) {
-+ n = write(fd, cmd + pos, len - pos);
-+ if (n < 0)
-+ return (-1);
-+ pos += n;
-+ }
- }
-- va_end(va);
-
-- return (len+2);
-+ return (len);
- }
-
- int
---- a/dma.c
-+++ b/dma.c
-@@ -609,7 +609,8 @@
- break;
- if (line[0] == '\n')
- break;
-- write(bounceq.mailfd, line, strlen(line));
-+ if (write(bounceq.mailfd, line, strlen(line)) != strlen(line))
-+ goto fail;
- }
- if (fsync(bounceq.mailfd) != 0)
- goto fail;
+++ /dev/null
-Lock the temporary files after creating them to protect from a "dma -q"
-run at just the wrong time causing a double delivery attempt for
-the same message.
-
---- a/dma.c
-+++ b/dma.c
-@@ -226,6 +226,8 @@
- fd = mkstemp(fn);
- if (fd < 0)
- return (-1);
-+ if (flock(fd, LOCK_EX) == -1)
-+ return (-1);
- queue->mailfd = fd;
- queue->tmpf = strdup(fn);
- if (queue->tmpf == NULL) {
-Provide the proper bounce error message on failed deliveries.
+Make the bounce error message buffer dynamic. The rest of this comment
+is left over from when this read "Provide the proper bounce error message".
+
This may not be the best solution - the error message buffer has now
turned dynamic, but the only alternative I see is to make it a static
array in net.c... and I'm not quite sure if I want to do that just now.
--- a/dma.c
+++ b/dma.c
-@@ -440,7 +440,7 @@
+@@ -590,7 +590,7 @@
}
static void
{
struct queue bounceq;
struct qitem *bit;
-@@ -599,6 +599,7 @@
- VERSION, hostname(),
- it->addr,
- reason);
+@@ -751,6 +751,7 @@
+ config->features & FULLBOUNCE ?
+ "Original message follows." :
+ "Message headers follow.");
+ free(reason);
if (error < 0)
goto fail;
if (fflush(bit->queuef) != 0)
-@@ -675,7 +676,7 @@
+@@ -834,7 +835,7 @@
#endif
static int
{
char fn[PATH_MAX+1];
char line[1000];
-@@ -758,7 +759,7 @@
+@@ -917,7 +918,7 @@
#ifdef HAVE_LIBLOCKFILE
mailunlock();
#endif
error = -1;
goto chop;
}
-@@ -801,7 +802,7 @@
+@@ -960,7 +961,7 @@
{
int error;
unsigned int backoff = MIN_RETRY;
struct timeval now;
struct stat st;
-@@ -832,12 +833,9 @@
- }
- if (gettimeofday(&now, NULL) == 0 &&
- (now.tv_sec - st.st_mtime > MAX_TIMEOUT)) {
-- char *msg;
--
-- if (asprintf(&msg,
-+ asprintf(&errmsg,
- "Could not deliver for the last %d seconds. Giving up.",
-- MAX_TIMEOUT) > 0)
-- errmsg = msg;
-+ MAX_TIMEOUT);
- goto bounce;
- }
- sleep(backoff);
--- a/dma.h
+++ b/dma.h
-@@ -163,7 +163,7 @@
- /* net.c */
+@@ -165,7 +165,7 @@
+ extern char *ssl_errstr(void);
extern int read_remote(int, int, char *);
extern ssize_t send_remote_command(int, const char*, ...);
-extern int deliver_remote(struct qitem *, const char **);
extern int base64_encode(const void *, int, char **);
--- a/net.c
+++ b/net.c
-@@ -314,7 +314,7 @@
+@@ -347,7 +347,7 @@
}
int
{
struct authuser *a;
char *host, line[1000];
-@@ -323,11 +323,14 @@
-
- host = strrchr(it->addr, '@');
- /* Should not happen */
-- if (host == NULL)
-+ if (host == NULL) {
-+ asprintf(errmsg, "Internal error: badly formed address %s",
-+ it->addr);
- return(-1);
-- else
-+ } else {
- /* Step over the @ */
- host++;
-+ }
-
- /* Smarthost support? */
- if (config->smarthost != NULL && strlen(config->smarthost) > 0) {
-@@ -370,6 +373,8 @@
- if (read_remote(fd, 0, NULL) != 2) {
- syslog(LOG_ERR, "%s: remote delivery deferred: "
- " EHLO failed: %s", it->queueid, neterr);
-+ asprintf(errmsg, "%s did not like our EHLO:\n%s",
-+ host, neterr);
- return (-1);
- }
- }
-@@ -379,6 +384,8 @@
- if (read_remote(fd, 0, NULL) != 2) {
- syslog(LOG_ERR, "%s: remote delivery deferred: "
- " EHLO failed: %s", it->queueid, neterr);
-+ asprintf(errmsg, "%s did not like our EHLO:\n%s",
-+ host, neterr);
- return (-1);
- }
- }
-@@ -405,6 +412,7 @@
- if (error < 0) {
- syslog(LOG_ERR, "%s: remote delivery failed:"
- " SMTP login failed: %m", it->queueid);
-+ asprintf(errmsg, "SMTP login to %s failed", host);
- return (-1);
- }
- /* SMTP login is not available, so try without */
-@@ -418,6 +426,8 @@
- if (res == 5) { \
- syslog(LOG_ERR, "%s: remote delivery failed: " \
- c " failed: %s", it->queueid, neterr); \
-+ asprintf(errmsg, "%s did not like our " c ":\n%s", \
-+ host, neterr); \
- return (-1); \
- } else if (res != exp) { \
- syslog(LOG_ERR, "%s: remote delivery deferred: " \
-@@ -447,7 +457,7 @@
+@@ -474,7 +474,7 @@
if (linelen == 0 || line[linelen - 1] != '\n') {
syslog(LOG_CRIT, "%s: remote delivery failed:"
"corrupted queue file", it->queueid);
+++ /dev/null
-Add the FULLBOUNCE config option to include the full message in the bounce.
-
---- a/conf.c
-+++ b/conf.c
-@@ -250,6 +250,8 @@
- config->features |= DEFER;
- else if (strcmp(word, "INSECURE") == 0)
- config->features |= INSECURE;
-+ else if (strcmp(word, "FULLBOUNCE") == 0)
-+ config->features |= FULLBOUNCE;
- }
- }
-
---- a/dma.8
-+++ b/dma.8
-@@ -237,6 +237,11 @@
- .Ar queueid
- .Fl f
- .Ar messagefile
-+.It Ic FULLBOUNCE Xo
-+(boolean, default=commented)
-+.Xc
-+Uncomment if you want the bounce message to include the complete original
-+message, not just the headers.
- .El
- .Ss virtusertable
- The
---- a/dma.c
-+++ b/dma.c
-@@ -586,7 +586,7 @@
- \n\
- %s\n\
- \n\
--Message headers follow.\n\
-+%s\n\
- \n\
- ",
- bounceq.id,
-@@ -598,7 +598,9 @@
- rfc822date(),
- VERSION, hostname(),
- it->addr,
-- reason);
-+ reason,
-+ config->features & FULLBOUNCE? "Original message follows.":
-+ "Message headers follow.");
- free(reason);
- if (error < 0)
- goto fail;
-@@ -607,14 +609,20 @@
-
- if (fseek(it->queuef, it->hdrlen, SEEK_SET) != 0)
- goto fail;
-- while (!feof(it->queuef)) {
-- if (fgets(line, sizeof(line), it->queuef) == NULL)
-- break;
-- if (line[0] == '\n')
-- break;
-- if (write(bounceq.mailfd, line, strlen(line)) != strlen(line))
-- goto fail;
-- }
-+ if (config->features & FULLBOUNCE)
-+ while ((pos = fread(line, 1, sizeof(line), it->queuef)) > 0) {
-+ if (write(bounceq.mailfd, line, pos) != pos)
-+ goto fail;
-+ }
-+ else
-+ while (!feof(it->queuef)) {
-+ if (fgets(line, sizeof(line), it->queuef) == NULL)
-+ break;
-+ if (line[0] == '\n')
-+ break;
-+ if (write(bounceq.mailfd, line, strlen(line)) != strlen(line))
-+ goto fail;
-+ }
- if (fsync(bounceq.mailfd) != 0)
- goto fail;
- if (linkspool(&bounceq) != 0)
---- a/dma.h
-+++ b/dma.h
-@@ -72,6 +72,7 @@
- #define NOSSL 0x008 /* Do not use SSL */
- #define DEFER 0x010 /* Defer mails */
- #define INSECURE 0x020 /* Allow plain login w/o encryption */
-+#define FULLBOUNCE 0x040 /* Bounce the full message */
-
- #define CONF_PATH "/etc/dma/dma.conf" /* Default path to dma.conf */
-
---- a/etc/dma.conf
-+++ b/etc/dma.conf
-@@ -45,3 +45,7 @@
- # default behavior of simply aborting the delivery, or specify the name or
- # full path to a program that will process the double-bounce message.
- DBOUNCEPROG dbounce-simple-safecat
-+
-+# Uncomment if you want the bounce message to include the complete original
-+# message, not just the headers.
-+#FULLBOUNCE
-Add the MAILNAME and MAILNAMEFILE config options.
+Fix a file descriptor leak in the MAILNAMEFILE code.
+Fix a mistake in my patch submitted to DFBSD - "initialized" should be static!
For Debian, use /etc/mailname for the MAILNAMEFILE.
---- a/conf.c
-+++ b/conf.c
-@@ -240,6 +240,14 @@
- if (data != NULL)
- config->dbounceprog = strdup(data);
- }
-+ else if (strcmp(word, "MAILNAME") == 0) {
-+ if (data != NULL)
-+ config->mailname = strdup(data);
-+ }
-+ else if (strcmp(word, "MAILNAMEFILE") == 0) {
-+ if (data != NULL)
-+ config->mailnamefile = strdup(data);
-+ }
- else if (strcmp(word, "VIRTUAL") == 0)
- config->features |= VIRTUAL;
- else if (strcmp(word, "STARTTLS") == 0)
---- a/dma.8
-+++ b/dma.8
-@@ -242,6 +242,20 @@
- .Xc
- Uncomment if you want the bounce message to include the complete original
- message, not just the headers.
-+.It Ic MAILNAME Xo
-+(string, default=empty)
-+.Xc
-+The name to be used when introducing this host, if different from
-+the result of
-+.Xr hostname 1 .
-+If specified, this option overrides
-+.Sq MAILNAMEFILE .
-+.It Ic MAILNAMEFILE Xo
-+(string, default=empty)
-+.Xc
-+The name of the file to read the
-+.Sq MAILNAME
-+from.
- .El
- .Ss virtusertable
- The
--- a/dma.c
+++ b/dma.c
-@@ -83,10 +83,40 @@
+@@ -82,8 +82,9 @@
hostname(void)
{
static char name[MAXHOSTNAMELEN+1];
+- int initialized = 0;
+ static int initialized = 0;
-+ FILE *fp;
+ FILE *fp;
+ char *res;
-+ size_t len;
-+
-+ if (initialized)
-+ return (name);
+ size_t len;
-+ if (config->mailname != NULL && config->mailname[0] != '\0') {
-+ snprintf(name, sizeof(name), "%s", config->mailname);
-+ initialized = 1;
-+ return (name);
-+ }
-+ if (config->mailnamefile != NULL && config->mailnamefile[0] != '\0') {
-+ fp = fopen(config->mailnamefile, "r");
-+ if (fp != NULL) {
+ if (initialized)
+@@ -97,7 +98,9 @@
+ if (config->mailnamefile != NULL && config->mailnamefile[0] != '\0') {
+ fp = fopen(config->mailnamefile, "r");
+ if (fp != NULL) {
+- if (fgets(name, sizeof(name), fp) != NULL) {
+ res = fgets(name, sizeof(name), fp);
+ fclose(fp);
+ if (res != NULL) {
-+ len = strlen(name);
-+ while (len > 0 &&
-+ (name[len - 1] == '\r' ||
-+ name[len - 1] == '\n'))
-+ name[--len] = '\0';
-+ if (name[0] != '\0') {
-+ initialized = 1;
-+ return (name);
-+ }
-+ }
-+ }
-+ }
+ len = strlen(name);
+ while (len > 0 &&
+ (name[len - 1] == '\r' ||
+@@ -108,7 +111,6 @@
+ return (name);
+ }
+ }
+- fclose(fp);
+ }
+ }
if (gethostname(name, sizeof(name)) != 0)
- strcpy(name, "(unknown hostname)");
--
-+ initialized = 1;
- return name;
- }
-
---- a/dma.h
-+++ b/dma.h
-@@ -122,6 +122,8 @@
- SSL *ssl;
- #endif /* HAVE_CRYPTO */
- char *dbounceprog;
-+ char *mailname;
-+ char *mailnamefile;
- };
-
-
--- a/etc/dma.conf
+++ b/etc/dma.conf
-@@ -49,3 +49,11 @@
- # Uncomment if you want the bounce message to include the complete original
- # message, not just the headers.
- #FULLBOUNCE
-+
-+# The name to be used when introducing this host, if different from
-+# the result of "hostname". If specified, this overrides MAILNAMEFILE.
-+#MAILNAME mail.example.net
-+
-+# The name of the file to read the MAILNAME from; if this file is not
-+# present, the result of "hostname" will be used.
+@@ -56,4 +56,4 @@
+
+ # The name of the file to read the MAILNAME from; if this file is not
+ # present, the result of "hostname" will be used.
+-#MAILNAMEFILE /etc/mailname
+MAILNAMEFILE /etc/mailname
+++ /dev/null
-Apply better logic to guess the username when getlogin(3) is not
-available for some reason, e.g. no login session at all, no access
-to utmp/wtmp, etc.
-
---- a/dma.c
-+++ b/dma.c
-@@ -75,6 +75,8 @@
- struct authusers authusers = LIST_HEAD_INITIALIZER(authusers);
- static int daemonize = 1;
- struct config *config;
-+static const char *username;
-+static uid_t uid;
- static struct strlist seenmsg[16][16];
-
- static int open_locked(const char *, int);
-@@ -120,6 +122,45 @@
- return name;
- }
-
-+static const char *
-+check_username(const char *username, uid_t uid)
-+{
-+ struct passwd *pwd;
-+
-+ if (username == NULL)
-+ return (NULL);
-+ pwd = getpwnam(username);
-+ if (pwd == NULL || pwd->pw_uid != uid)
-+ return (NULL);
-+ return (username);
-+}
-+
-+static void
-+set_username(void)
-+{
-+ struct passwd *pwd;
-+ char *u;
-+
-+ uid = getuid();
-+ username = check_username(getlogin(), uid);
-+ if (username == NULL)
-+ username = check_username(getenv("LOGNAME"), uid);
-+ if (username == NULL)
-+ username = check_username(getenv("USER"), uid);
-+ if (username == NULL) {
-+ pwd = getpwuid(uid);
-+ if (pwd != NULL && pwd->pw_name != NULL &&
-+ pwd->pw_name[0] != '\0')
-+ username = check_username(strdup(pwd->pw_name), uid);
-+ }
-+ if (username == NULL) {
-+ asprintf(&u, "%ld", (long)uid);
-+ username = u;
-+ }
-+ if (username == NULL)
-+ username = "unknown-or-invalid-username";
-+}
-+
- static char *
- set_from(const char *osender)
- {
-@@ -128,7 +169,7 @@
-
- if ((config->features & VIRTUAL) != 0) {
- SLIST_FOREACH(v, &virtusers, next) {
-- if (strcmp(v->login, getlogin()) == 0) {
-+ if (strcmp(v->login, username) == 0) {
- sender = strdup(v->address);
- if (sender == NULL)
- return(NULL);
-@@ -142,7 +183,7 @@
- if (sender == NULL)
- return (NULL);
- } else {
-- if (asprintf(&sender, "%s@%s", getlogin(), hostname()) <= 0)
-+ if (asprintf(&sender, "%s@%s", username, hostname()) <= 0)
- return (NULL);
- }
-
-@@ -370,7 +411,7 @@
- \tid %"PRIxMAX"\n\
- \tby %s (%s)\n\
- \t%s\n",
-- getlogin(), getuid(),
-+ username, uid,
- sender,
- queue->id,
- hostname(), VERSION,
-@@ -1184,6 +1225,7 @@
- opterr = 1;
-
- openlog(tag, LOG_PID | LOG_PERROR, LOG_MAIL);
-+ set_username();
-
- config = malloc(sizeof(struct config));
- if (config == NULL)
+++ /dev/null
-Ignore a whole slew of sendmail options. Probably some more left.
-
---- a/dma.c
-+++ b/dma.c
-@@ -1174,7 +1174,7 @@
- snprintf(tag, 254, "dma");
-
- opterr = 0;
-- while ((ch = getopt(argc, argv, "A:b:Df:iL:o:O:q:r:")) != -1) {
-+ while ((ch = getopt(argc, argv, "A:b:B:C:d:Df:F:h:iL:N:no:O:q:r:R:UV:vX:")) != -1) {
- switch (ch) {
- case 'A':
- /* -AX is being ignored, except for -A{c,m} */
-@@ -1216,6 +1216,21 @@
- doqueue = 1;
- break;
-
-+ /* Ignored options */
-+ case 'B':
-+ case 'C':
-+ case 'd':
-+ case 'F':
-+ case 'h':
-+ case 'N':
-+ case 'n':
-+ case 'R':
-+ case 'U':
-+ case 'V':
-+ case 'v':
-+ case 'X':
-+ break;
-+
- default:
- exit(1);
- }
.Nm
--- a/dma.c
+++ b/dma.c
-@@ -77,6 +77,7 @@
+@@ -73,6 +73,7 @@
struct config *config;
static const char *username;
static uid_t uid;
+static FILE *scanfile;
static struct strlist seenmsg[16][16];
- static int open_locked(const char *, int);
-@@ -399,11 +400,307 @@
+
+@@ -429,6 +430,300 @@
}
static int
+parse_header_line(struct queue *queue, const char *sender, const char *line)
+{
-+ size_t len;
+ const char *p;
+ enum dma_header_state st;
+ char buf[1000];
+}
+
+static int
- readmail(struct queue *queue, const char *sender, int nodot)
+ strprefixcmp(const char *str, const char *prefix)
{
+ return (strncasecmp(str, prefix, strlen(prefix)));
+@@ -440,6 +735,7 @@
char line[1000]; /* by RFC2822 */
size_t linelen;
int error;
+ FILE *infile;
-
- error = snprintf(line, sizeof(line), "\
- Received: from %s (uid %d)\n\
-@@ -421,8 +718,12 @@
+ int had_headers = 0;
+ int had_from = 0;
+ int had_messagid = 0;
+@@ -461,8 +757,12 @@
if (write(queue->mailfd, line, error) != error)
return (-1);
break;
linelen = strlen(line);
if (linelen == 0 || line[linelen - 1] != '\n') {
-@@ -436,6 +737,8 @@
+@@ -504,6 +804,8 @@
}
if (fsync(queue->mailfd) != 0)
return (-1);
return (0);
}
-@@ -1167,14 +1470,14 @@
+@@ -1252,7 +1554,7 @@
struct queue queue;
struct queue lqueue;
int i, ch;
atexit(deltmp);
LIST_INIT(&queue.queue);
- snprintf(tag, 254, "dma");
+@@ -1267,7 +1569,7 @@
+ }
opterr = 0;
- while ((ch = getopt(argc, argv, "A:b:B:C:d:Df:F:h:iL:N:no:O:q:r:R:UV:vX:")) != -1) {
switch (ch) {
case 'A':
/* -AX is being ignored, except for -A{c,m} */
-@@ -1216,6 +1519,10 @@
+@@ -1309,6 +1611,10 @@
doqueue = 1;
break;
/* Ignored options */
case 'B':
case 'C':
-@@ -1288,12 +1595,19 @@
- errx(1, "invalid recipient `%s'\n", argv[i]);
+@@ -1382,12 +1688,19 @@
+ errx(1, "invalid recipient `%s'", argv[i]);
}
- if (LIST_EMPTY(&queue.queue))
errx(1, "no recipients");
if (gentempf(&queue) != 0)
- err(1, "create temp file");
+ err(1, "can not create temp file");
+ if (headerrecips) {
+ if (scanmail(&queue, sender) != 0)
+ }
+
if (preparespool(&queue, sender) != 0)
- err(1, "creating spools (1)");
+ err(1, "can not create spools (1)");
--- a/dma.h
+++ b/dma.h
+++ /dev/null
-Unbreak SMTP authentication with or without encrypted connections:
-- always send an EHLO command at the start of the "real" negotiation;
-- allow LOGIN authentication over an SSL link if CRAM-MD5 fails.
-
---- a/net.c
-+++ b/net.c
-@@ -213,7 +213,9 @@
- }
- #endif /* HAVE_CRYPTO */
-
-- if ((config->features & INSECURE) != 0) {
-+ if ((config->features & INSECURE) != 0 ||
-+ ((config->features & SECURETRANS) != 0 &&
-+ (config->features & NOSSL) == 0)) {
- /* Send AUTH command according to RFC 2554 */
- send_remote_command(fd, "AUTH LOGIN");
- if (read_remote(fd, 0, NULL) != 3) {
-@@ -363,6 +365,7 @@
- goto out;
- }
-
-+#if 0
- /*
- * If the user doesn't want STARTTLS, but SSL encryption, we
- * have to enable SSL first, then send EHLO
-@@ -378,8 +381,11 @@
- return (-1);
- }
- }
-+#endif
- #endif /* HAVE_CRYPTO */
-+#if 0
- if (((config->features & SECURETRANS) == 0)) {
-+#endif
- send_remote_command(fd, "EHLO %s", hostname());
- if (read_remote(fd, 0, NULL) != 2) {
- syslog(LOG_ERR, "%s: remote delivery deferred: "
-@@ -388,7 +394,9 @@
- host, neterr);
- return (-1);
- }
-+#if 0
- }
-+#endif
-
- /*
- * Use SMTP authentication if the user defined an entry for the remote
--- a/dma.c
+++ b/dma.c
-@@ -79,6 +79,7 @@
+@@ -75,7 +75,7 @@
static uid_t uid;
static FILE *scanfile;
static struct strlist seenmsg[16][16];
+-
+static int morefiles;
static int open_locked(const char *, int);
-@@ -1311,15 +1312,21 @@
+@@ -1392,15 +1392,21 @@
char *queueid;
char *queuefn;
off_t hdrlen;
while ((de = readdir(spooldir)) != NULL) {
sender = NULL;
queuef = NULL;
-@@ -1335,12 +1342,22 @@
+@@ -1416,12 +1422,22 @@
if (asprintf(&queuefn, "%s/%s", config->spooldir, de->d_name) < 0)
goto fail;
seenit = seen(de->d_name);
+ }
goto skip_item;
+ }
- if (!nolock || seenit)
+ if (!ignorelock || seenit)
continue;
fd = open(queuefn, O_RDONLY);
-@@ -1425,12 +1442,15 @@
+@@ -1506,12 +1522,15 @@
static void
run_queue(struct queue *queue)
{
deliver(it);
/* NOTREACHED */
}
-@@ -1450,6 +1470,8 @@
- ID\t: %s%s\n\
- From\t: %s\n\
- To\t: %s\n--\n", it->queueid, it->locked? "*": "", it->sender, it->addr);
+@@ -1534,6 +1553,8 @@
+ it->queueid,
+ it->locked ? "*" : "",
+ it->sender, it->addr);
+ if (it->queuef != NULL)
+ close(fileno(it->queuef));
}
}
-@@ -1571,16 +1593,21 @@
+@@ -1664,16 +1685,21 @@
if (argc != 0)
errx(1, "sending mail and displaying queue is"
" mutually exclusive");
02-man-dragonflybsd.patch
03-debian-locations.patch
04-debian-setgid.patch
-05-remote-error-messages.patch
-06-quit-nonfatal.patch
-07-permanent-errors.patch
-08-queue-list-all.patch
09-typos.patch
10-liblockfile.patch
11-double-bounce.patch
-12-man-q-argument.patch
-13-hardening.patch
-14-lock-new-files.patch
15-bounce-message.patch
-16-bounce-full.patch
17-mailname.patch
-18-guess-username.patch
-19-ignore-options.patch
20-parse-recipient.patch
-21-smtp-auth.patch
22-openfiles.patch