From: Peter Pentchev Date: Fri, 31 Jul 2009 15:45:50 +0000 (+0000) Subject: Bring it up to current dma, part I: refresh all patches to X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=0e8129da28ccc0b8a5d0d3ad075c30164e3d403c;p=people%2Fms%2Fdma.git Bring it up to current dma, part I: refresh all patches to bring things up to dma-dfly-2009-07-17 plus my Debian branch patches. --- diff --git a/changelog b/changelog index 4c504e1..5359b43 100644 --- a/changelog +++ b/changelog @@ -1,6 +1,6 @@ -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 Mon, 29 Jun 2009 14:31:29 +0300 + -- Peter Pentchev Fri, 31 Jul 2009 18:41:35 +0300 diff --git a/patches/01-debian-build.patch b/patches/01-debian-build.patch index 923ef11..3c26232 100644 --- a/patches/01-debian-build.patch +++ b/patches/01-debian-build.patch @@ -1,11 +1,9 @@ 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/ @@ -19,16 +17,13 @@ http://svn.ringlet.net/cgi-bin/viewvc/viewvc.cgi/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 @@ -45,96 +40,40 @@ http://svn.ringlet.net/cgi-bin/viewvc/viewvc.cgi/ringlet/mail/dma/ + +aliases_parse.o: aliases_parse.h +aliases_scan.o: aliases_parse.h - ++ .include + +.include --- 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 - #include - -+#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 diff --git a/patches/02-man-dragonflybsd.patch b/patches/02-man-dragonflybsd.patch index 46d8cca..db19d15 100644 --- a/patches/02-man-dragonflybsd.patch +++ b/patches/02-man-dragonflybsd.patch @@ -3,7 +3,7 @@ not have the ".Dx" macro yet. --- a/dma.8 +++ b/dma.8 -@@ -248,7 +248,7 @@ +@@ -269,7 +269,7 @@ The .Nm utility first appeared in diff --git a/patches/03-debian-locations.patch b/patches/03-debian-locations.patch index 0c7eb42..95b6496 100644 --- a/patches/03-debian-locations.patch +++ b/patches/03-debian-locations.patch @@ -4,7 +4,7 @@ Use deferred delivery - the package includes a cron job running the queue. --- 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 @@ -13,7 +13,7 @@ Use deferred delivery - the package includes a cron job running the queue. .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 @@ -40,9 +40,12 @@ Use deferred delivery - the package includes a cron job running the queue. # 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. diff --git a/patches/04-debian-setgid.patch b/patches/04-debian-setgid.patch index 042db9a..ed7626b 100644 --- a/patches/04-debian-setgid.patch +++ b/patches/04-debian-setgid.patch @@ -3,12 +3,12 @@ to 2755, since removing root write access gains us nothing. --- 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 diff --git a/patches/05-remote-error-messages.patch b/patches/05-remote-error-messages.patch deleted file mode 100644 index fc094fd..0000000 --- a/patches/05-remote-error-messages.patch +++ /dev/null @@ -1,197 +0,0 @@ -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 -+#include - #include - #include - #include -@@ -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: diff --git a/patches/06-quit-nonfatal.patch b/patches/06-quit-nonfatal.patch deleted file mode 100644 index b36c3a2..0000000 --- a/patches/06-quit-nonfatal.patch +++ /dev/null @@ -1,21 +0,0 @@ -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); diff --git a/patches/07-permanent-errors.patch b/patches/07-permanent-errors.patch deleted file mode 100644 index 384cf33..0000000 --- a/patches/07-permanent-errors.patch +++ /dev/null @@ -1,60 +0,0 @@ -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) diff --git a/patches/08-queue-list-all.patch b/patches/08-queue-list-all.patch deleted file mode 100644 index 1d517ef..0000000 --- a/patches/08-queue-list-all.patch +++ /dev/null @@ -1,169 +0,0 @@ -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); - diff --git a/patches/09-typos.patch b/patches/09-typos.patch index af470f3..dc26c45 100644 --- a/patches/09-typos.patch +++ b/patches/09-typos.patch @@ -1,31 +1,13 @@ -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 */ diff --git a/patches/10-liblockfile.patch b/patches/10-liblockfile.patch index b84b6a4..539e58f 100644 --- a/patches/10-liblockfile.patch +++ b/patches/10-liblockfile.patch @@ -3,10 +3,10 @@ liblockfile, as mandated by Debian Policy. --- a/Makefile +++ b/Makefile -@@ -4,10 +4,11 @@ +@@ -3,10 +3,11 @@ + SUBDIR= etc - CFLAGS+= -DHAVE_CRYPTO +CFLAGS+= -DHAVE_LIBLOCKFILE CFLAGS+= -I${.CURDIR} @@ -19,7 +19,7 @@ liblockfile, as mandated by Debian Policy. 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 #include @@ -33,7 +33,7 @@ liblockfile, as mandated by Debian Policy. 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); } @@ -42,7 +42,7 @@ liblockfile, as mandated by Debian Policy. +liblockfile_strerror(int res) +{ + static char buf[512]; -+ ++ + switch (res) { + case L_SUCCESS: + snprintf(buf, sizeof(buf), "No error"); @@ -81,7 +81,7 @@ liblockfile, as mandated by Debian Policy. 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); @@ -92,13 +92,13 @@ liblockfile, as mandated by Debian Policy. 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 @@ -107,7 +107,7 @@ liblockfile, as mandated by Debian Policy. +#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); + } @@ -116,15 +116,15 @@ liblockfile, as mandated by Debian Policy. + 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); } @@ -132,7 +132,7 @@ liblockfile, as mandated by Debian Policy. 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(); @@ -140,9 +140,9 @@ liblockfile, as mandated by Debian Policy. 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(); @@ -150,7 +150,7 @@ liblockfile, as mandated by Debian Policy. 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); @@ -160,7 +160,7 @@ liblockfile, as mandated by Debian Policy. *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; @@ -170,7 +170,7 @@ liblockfile, as mandated by Debian Policy. 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); diff --git a/patches/11-double-bounce.patch b/patches/11-double-bounce.patch index 9d4af1a..f3ff7ed 100644 --- a/patches/11-double-bounce.patch +++ b/patches/11-double-bounce.patch @@ -5,7 +5,7 @@ helper installed by the package. --- a/conf.c +++ b/conf.c -@@ -233,6 +233,10 @@ +@@ -238,6 +238,10 @@ if (data != NULL) config->certfile = strdup(data); } @@ -13,12 +13,12 @@ helper installed by the package. + 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. @@ -42,27 +42,29 @@ helper installed by the package. +.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) { @@ -139,21 +141,21 @@ helper installed by the package. + */ + 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", @@ -166,22 +168,25 @@ helper installed by the package. 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 diff --git a/patches/12-man-q-argument.patch b/patches/12-man-q-argument.patch deleted file mode 100644 index dfded9a..0000000 --- a/patches/12-man-q-argument.patch +++ /dev/null @@ -1,31 +0,0 @@ -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 . diff --git a/patches/13-hardening.patch b/patches/13-hardening.patch deleted file mode 100644 index 6a6b204..0000000 --- a/patches/13-hardening.patch +++ /dev/null @@ -1,99 +0,0 @@ -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; diff --git a/patches/14-lock-new-files.patch b/patches/14-lock-new-files.patch deleted file mode 100644 index 3ff6628..0000000 --- a/patches/14-lock-new-files.patch +++ /dev/null @@ -1,15 +0,0 @@ -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) { diff --git a/patches/15-bounce-message.patch b/patches/15-bounce-message.patch index 3e2161f..178b0fd 100644 --- a/patches/15-bounce-message.patch +++ b/patches/15-bounce-message.patch @@ -1,11 +1,13 @@ -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 @@ -14,15 +16,15 @@ array in net.c... and I'm not quite sure if I want to do that just now. { 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 @@ -31,7 +33,7 @@ array in net.c... and I'm not quite sure if I want to do that just now. { char fn[PATH_MAX+1]; char line[1000]; -@@ -758,7 +759,7 @@ +@@ -917,7 +918,7 @@ #ifdef HAVE_LIBLOCKFILE mailunlock(); #endif @@ -40,7 +42,7 @@ array in net.c... and I'm not quite sure if I want to do that just now. error = -1; goto chop; } -@@ -801,7 +802,7 @@ +@@ -960,7 +961,7 @@ { int error; unsigned int backoff = MIN_RETRY; @@ -49,25 +51,10 @@ array in net.c... and I'm not quite sure if I want to do that just now. 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 **); @@ -77,7 +64,7 @@ array in net.c... and I'm not quite sure if I want to do that just now. extern int base64_encode(const void *, int, char **); --- a/net.c +++ b/net.c -@@ -314,7 +314,7 @@ +@@ -347,7 +347,7 @@ } int @@ -86,59 +73,7 @@ array in net.c... and I'm not quite sure if I want to do that just now. { 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); diff --git a/patches/16-bounce-full.patch b/patches/16-bounce-full.patch deleted file mode 100644 index 5dae966..0000000 --- a/patches/16-bounce-full.patch +++ /dev/null @@ -1,98 +0,0 @@ -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 diff --git a/patches/17-mailname.patch b/patches/17-mailname.patch index 437f2d7..ff8f999 100644 --- a/patches/17-mailname.patch +++ b/patches/17-mailname.patch @@ -1,112 +1,44 @@ -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 diff --git a/patches/18-guess-username.patch b/patches/18-guess-username.patch deleted file mode 100644 index af30c73..0000000 --- a/patches/18-guess-username.patch +++ /dev/null @@ -1,96 +0,0 @@ -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) diff --git a/patches/19-ignore-options.patch b/patches/19-ignore-options.patch deleted file mode 100644 index 61ddfcf..0000000 --- a/patches/19-ignore-options.patch +++ /dev/null @@ -1,35 +0,0 @@ -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); - } diff --git a/patches/20-parse-recipient.patch b/patches/20-parse-recipient.patch index e37608f..dabe714 100644 --- a/patches/20-parse-recipient.patch +++ b/patches/20-parse-recipient.patch @@ -23,21 +23,20 @@ to obtain the recipient addresses. .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]; @@ -330,16 +329,18 @@ to obtain the recipient addresses. +} + +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); @@ -354,7 +355,7 @@ to obtain the recipient addresses. 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); @@ -363,7 +364,7 @@ to obtain the recipient addresses. return (0); } -@@ -1167,14 +1470,14 @@ +@@ -1252,7 +1554,7 @@ struct queue queue; struct queue lqueue; int i, ch; @@ -372,7 +373,8 @@ to obtain the recipient addresses. 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) { @@ -380,7 +382,7 @@ to obtain the recipient addresses. switch (ch) { case 'A': /* -AX is being ignored, except for -A{c,m} */ -@@ -1216,6 +1519,10 @@ +@@ -1309,6 +1611,10 @@ doqueue = 1; break; @@ -391,8 +393,8 @@ to obtain the recipient addresses. /* 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)) @@ -400,7 +402,7 @@ to obtain the recipient addresses. 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) @@ -410,7 +412,7 @@ to obtain the recipient addresses. + } + if (preparespool(&queue, sender) != 0) - err(1, "creating spools (1)"); + err(1, "can not create spools (1)"); --- a/dma.h +++ b/dma.h diff --git a/patches/21-smtp-auth.patch b/patches/21-smtp-auth.patch deleted file mode 100644 index 2b0c1bf..0000000 --- a/patches/21-smtp-auth.patch +++ /dev/null @@ -1,47 +0,0 @@ -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 diff --git a/patches/22-openfiles.patch b/patches/22-openfiles.patch index ddbcd99..b1a0cff 100644 --- a/patches/22-openfiles.patch +++ b/patches/22-openfiles.patch @@ -2,15 +2,16 @@ Handle the "too many open files" error gracefully, retrying. --- 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; @@ -34,7 +35,7 @@ Handle the "too many open files" error gracefully, retrying. 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); @@ -55,10 +56,10 @@ Handle the "too many open files" error gracefully, retrying. + } 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) { @@ -75,16 +76,16 @@ Handle the "too many open files" error gracefully, retrying. 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"); diff --git a/patches/series b/patches/series index ce0e157..b487785 100644 --- a/patches/series +++ b/patches/series @@ -2,21 +2,10 @@ 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