From 14dfb9912037c6e7f0ddb9ef1cd77d5e14246639 Mon Sep 17 00:00:00 2001 From: Joris Giovannangeli Date: Fri, 21 Feb 2014 18:17:22 +0100 Subject: [PATCH] dma(8) : update to version 0.9 * Sources from upstream commit 89702b7f148445240a308a5be65f79891e865a4b * (minor) local changes are kept. --- libexec/dma/README.markdown | 2 + libexec/dma/VERSION | 2 +- libexec/dma/aliases_parse.y | 11 ++- libexec/dma/conf.c | 9 +- libexec/dma/crypto.c | 4 + .../{dma-mbox-create => }/dma-mbox-create.c | 0 libexec/dma/dma.8 | 13 ++- libexec/dma/dma.c | 85 ++++++++++++++----- libexec/dma/dma.conf | 3 + libexec/dma/dma.h | 18 +++- libexec/dma/dma/Makefile | 4 +- libexec/dma/get-version.sh | 9 ++ libexec/dma/net.c | 27 +++--- libexec/dma/spool.c | 45 ++++++++++ 14 files changed, 187 insertions(+), 45 deletions(-) rename libexec/dma/{dma-mbox-create => }/dma-mbox-create.c (100%) create mode 100644 libexec/dma/get-version.sh diff --git a/libexec/dma/README.markdown b/libexec/dma/README.markdown index 528a4d65c8..13ff20c9aa 100644 --- a/libexec/dma/README.markdown +++ b/libexec/dma/README.markdown @@ -23,6 +23,8 @@ Installation make install sendmail-link mailq-link install-spool-dirs install-etc +See INSTALL for requirements and configuration options. + Contact ------- diff --git a/libexec/dma/VERSION b/libexec/dma/VERSION index 03776fb05e..490a0cdcc1 100644 --- a/libexec/dma/VERSION +++ b/libexec/dma/VERSION @@ -1 +1 @@ -v0.7 +v0.9 diff --git a/libexec/dma/aliases_parse.y b/libexec/dma/aliases_parse.y index dd8b88a810..a5a9e7b32f 100644 --- a/libexec/dma/aliases_parse.y +++ b/libexec/dma/aliases_parse.y @@ -2,6 +2,7 @@ #include #include +#include #include "dma.h" extern int yylineno; @@ -12,7 +13,12 @@ int yylex(void); static void yyerror(const char *msg) { - warnx("aliases line %d: %s", yylineno, msg); + /** + * Because we do error '\n' below, we need to report the error + * one line above of what yylineno points to. + */ + syslog(LOG_CRIT, "aliases line %d: %s", yylineno - 1, msg); + fprintf(stderr, "aliases line %d: %s\n", yylineno - 1, msg); } int @@ -72,8 +78,7 @@ alias : T_IDENT ':' dests '\n' } | error '\n' { - yyerrok; - $$ = NULL; + YYABORT; } ; diff --git a/libexec/dma/conf.c b/libexec/dma/conf.c index e8cb463383..919ab7c4d7 100644 --- a/libexec/dma/conf.c +++ b/libexec/dma/conf.c @@ -211,7 +211,7 @@ parse_conf(const char *config_path) } else { host = data; } - if (host && *host == 0) + if (host && *host == 0) host = NULL; if (user && *user == 0) user = NULL; @@ -229,11 +229,18 @@ parse_conf(const char *config_path) config.features |= INSECURE; else if (strcmp(word, "FULLBOUNCE") == 0 && data == NULL) config.features |= FULLBOUNCE; + else if (strcmp(word, "NULLCLIENT") == 0 && data == NULL) + config.features |= NULLCLIENT; else { errlogx(1, "syntax error in %s:%d", config_path, lineno); /* NOTREACHED */ } } + if ((config.features & NULLCLIENT) && config.smarthost == NULL) { + errlogx(1, "%s: NULLCLIENT requires SMARTHOST", config_path); + /* NOTREACHED */ + } + fclose(conf); } diff --git a/libexec/dma/crypto.c b/libexec/dma/crypto.c index 7e8865c602..897b55bfdc 100644 --- a/libexec/dma/crypto.c +++ b/libexec/dma/crypto.c @@ -80,7 +80,11 @@ int smtp_init_crypto(int fd, int feature) { SSL_CTX *ctx = NULL; +#if (OPENSSL_VERSION_NUMBER >= 0x00909000L) const SSL_METHOD *meth = NULL; +#else + SSL_METHOD *meth = NULL; +#endif X509 *cert; int error; diff --git a/libexec/dma/dma-mbox-create/dma-mbox-create.c b/libexec/dma/dma-mbox-create.c similarity index 100% rename from libexec/dma/dma-mbox-create/dma-mbox-create.c rename to libexec/dma/dma-mbox-create.c diff --git a/libexec/dma/dma.8 b/libexec/dma/dma.8 index e32fbfcff0..792ec426dd 100644 --- a/libexec/dma/dma.8 +++ b/libexec/dma/dma.8 @@ -29,7 +29,7 @@ .\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd January 9, 2012 +.Dd February 13, 2014 .Dt DMA 8 .Os .Sh NAME @@ -304,6 +304,15 @@ setting it to will send all mails as .Ql Sm off Va username @percolator . .Sm on +.It Ic NULLCLIENT Xo +.Xc +Bypass aliases and local delivery, and instead forward all mails to +the defined +.Sq SMARTHOST . +.Sq NULLCLIENT +requires +.Sq SMARTHOST +to be set. .El .Ss Environment variables The behavior of @@ -349,4 +358,4 @@ utility first appeared in was written by .An Matthias Schmidt Aq Mt matthias@dragonflybsd.org and -.An Simon Schubert Aq Mt 2@0x2c . +.An Simon Schubert Aq Mt 2@0x2c.org . diff --git a/libexec/dma/dma.c b/libexec/dma/dma.c index b6040ec223..9a67b63cb7 100644 --- a/libexec/dma/dma.c +++ b/libexec/dma/dma.c @@ -70,6 +70,7 @@ const char *logident_base; char errmsg[ERRMSG_SIZE]; static int daemonize = 1; +static int doqueue = 0; struct config config = { .smarthost = NULL, @@ -94,25 +95,31 @@ sighup_handler(int signo) static char * set_from(struct queue *queue, const char *osender) { + const char *addr; char *sender; if (osender) { - sender = strdup(osender); - if (sender == NULL) - return (NULL); + addr = osender; } else if (getenv("EMAIL") != NULL) { - sender = strdup(getenv("EMAIL")); - if (sender == NULL) - return (NULL); + addr = getenv("EMAIL"); } else { - const char *from_user = username; + if (config.masquerade_user) + addr = config.masquerade_user; + else + addr = username; + } + + if (!strchr(addr, '@')) { const char *from_host = hostname(); - if (config.masquerade_user) - from_user = config.masquerade_user; if (config.masquerade_host) from_host = config.masquerade_host; - if (asprintf(&sender, "%s@%s", from_user, from_host) <= 0) + + if (asprintf(&sender, "%s@%s", addr, from_host) <= 0) + return (NULL); + } else { + sender = strdup(addr); + if (sender == NULL) return (NULL); } @@ -195,7 +202,12 @@ add_recp(struct queue *queue, const char *str, int expand) } } LIST_INSERT_HEAD(&queue->queue, it, next); - if (strrchr(it->addr, '@') == NULL) { + + /** + * Do local delivery if there is no @. + * Do not do local delivery when NULLCLIENT is set. + */ + if (strrchr(it->addr, '@') == NULL && (config.features & NULLCLIENT) == 0) { it->remote = 0; if (expand) { aliased = do_alias(queue, it->addr); @@ -265,11 +277,21 @@ retit: /* * If necessary, acquire the queue and * mail files. * If this fails, we probably were raced by another - * process. + * process. It is okay to be raced if we're supposed + * to flush the queue. */ setlogident("%s", it->queueid); - if (acquirespool(it) < 0) + switch (acquirespool(it)) { + case 0: + break; + case 1: + if (doqueue) + exit(0); + syslog(LOG_WARNING, "could not lock queue file"); exit(1); + default: + exit(1); + } dropspool(queue, it); return (it); @@ -291,7 +313,7 @@ static void deliver(struct qitem *it) { int error; - unsigned int backoff = MIN_RETRY; + unsigned int backoff = MIN_RETRY, slept; struct timeval now; struct stat st; @@ -323,7 +345,14 @@ retry: MAX_TIMEOUT); goto bounce; } - if (sleep(backoff) == 0) { + for (slept = 0; slept < backoff;) { + slept += SLEEP_TIMEOUT - sleep(SLEEP_TIMEOUT); + if (flushqueue_since(slept)) { + backoff = MIN_RETRY; + goto retry; + } + } + if (slept >= backoff) { /* pick the next backoff between [1.5, 2.5) times backoff */ backoff = backoff + backoff / 2 + random() % backoff; if (backoff > MAX_RETRY) @@ -393,7 +422,7 @@ main(int argc, char **argv) char *sender = NULL; struct queue queue; int i, ch; - int nodot = 0, doqueue = 0, showq = 0, queue_only = 0; + int nodot = 0, showq = 0, queue_only = 0; int recp_from_header = 0; set_username(); @@ -405,9 +434,14 @@ main(int argc, char **argv) if (geteuid() == 0 || getuid() == 0) { struct passwd *pw; + errno = 0; pw = getpwnam(DMA_ROOT_USER); - if (pw == NULL) - err(1, "cannot drop root privileges"); + if (pw == NULL) { + if (errno == 0) + errx(1, "user '%s' not found", DMA_ROOT_USER); + else + err(1, "cannot drop root privileges"); + } if (setuid(pw->pw_uid) != 0) err(1, "cannot drop root privileges"); @@ -428,6 +462,13 @@ main(int argc, char **argv) if (argc != 0) errx(1, "invalid arguments"); goto skipopts; + } else if (strcmp(argv[0], "newaliases") == 0) { + logident_base = "dma"; + setlogident(NULL); + + if (read_aliases() != 0) + errx(1, "could not parse aliases file `%s'", config.aliases); + exit(0); } opterr = 0; @@ -476,6 +517,9 @@ main(int argc, char **argv) break; case 'q': + /* Don't let getopt slup up other arguments */ + if (optarg && *optarg == '-') + optind--; doqueue = 1; break; @@ -540,6 +584,7 @@ skipopts: } if (doqueue) { + flushqueue_signal(); if (load_queue(&queue) < 0) errlog(1, "can not load queue"); run_queue(&queue); @@ -547,13 +592,13 @@ skipopts: } if (read_aliases() != 0) - errlog(1, "can not read aliases file `%s'", config.aliases); + errlog(1, "could not parse aliases file `%s'", config.aliases); if ((sender = set_from(&queue, sender)) == NULL) errlog(1, NULL); if (newspoolf(&queue) != 0) - errlog(1, "can not create temp file"); + errlog(1, "can not create temp file in `%s'", config.spooldir); setlogident("%s", queue.id); diff --git a/libexec/dma/dma.conf b/libexec/dma/dma.conf index 56fa1045e0..1cc2bf5bc8 100644 --- a/libexec/dma/dma.conf +++ b/libexec/dma/dma.conf @@ -61,3 +61,6 @@ # MASQUERADE john@ on host "hamlet" will send all mails as john@hamlet # MASQUERADE percolator will send mails as $username@percolator, e.g. fish@percolator # MASQUERADE herb@ert will send all mails as herb@ert + +# Directly forward the mail to the SMARTHOST bypassing aliases and local delivery +#NULLCLIENT diff --git a/libexec/dma/dma.h b/libexec/dma/dma.h index d413ca5172..baacb0eddc 100644 --- a/libexec/dma/dma.h +++ b/libexec/dma/dma.h @@ -52,6 +52,7 @@ #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 */ +#define SLEEP_TIMEOUT 30 /* check for queue flush every 30 seconds */ #ifndef PATH_MAX #define PATH_MAX 1024 /* Max path len */ #endif @@ -65,6 +66,7 @@ #define INSECURE 0x020 /* Allow plain login w/o encryption */ #define FULLBOUNCE 0x040 /* Bounce the full message */ #define TLS_OPP 0x080 /* Opportunistic STARTTLS */ +#define NULLCLIENT 0x100 /* Nullclient support */ #ifndef CONF_PATH #error Please define CONF_PATH @@ -74,8 +76,14 @@ #error Please define LIBEXEC_PATH #endif +#define SPOOL_FLUSHFILE "flush" + +#ifndef DMA_ROOT_USER #define DMA_ROOT_USER "mail" +#endif +#ifndef DMA_GROUP #define DMA_GROUP "mail" +#endif #ifndef MBOX_STRICT #define MBOX_STRICT 0 @@ -182,7 +190,7 @@ int dns_get_mx_list(const char *, int, struct mx_hostentry **, int); /* net.c */ char *ssl_errstr(void); int read_remote(int, int, char *); -ssize_t send_remote_command(int, const char*, ...) __printflike(2, 3); +ssize_t send_remote_command(int, const char*, ...) __attribute__((__nonnull__(2), __format__ (__printf__, 2, 3))); int deliver_remote(struct qitem *); /* base64.c */ @@ -202,6 +210,8 @@ int load_queue(struct queue *); void delqueue(struct qitem *); int acquirespool(struct qitem *); void dropspool(struct queue *, struct qitem *); +int flushqueue_since(unsigned int); +int flushqueue_signal(void); /* local.c */ int deliver_local(struct qitem *); @@ -212,9 +222,9 @@ int readmail(struct queue *, int, int); /* util.c */ const char *hostname(void); -void setlogident(const char *, ...) __printf0like(1, 2); -void errlog(int, const char *, ...) __printf0like(2, 3); -void errlogx(int, const char *, ...) __printf0like(2, 3); +void setlogident(const char *, ...) __attribute__((__format__ (__printf__, 1, 2))); +void errlog(int, const char *, ...) __attribute__((__format__ (__printf__, 2, 3))); +void errlogx(int, const char *, ...) __attribute__((__format__ (__printf__, 2, 3))); void set_username(void); void deltmp(void); int do_timeout(int, int); diff --git a/libexec/dma/dma/Makefile b/libexec/dma/dma/Makefile index 2d89c536c6..ecd9c57321 100644 --- a/libexec/dma/dma/Makefile +++ b/libexec/dma/dma/Makefile @@ -1,9 +1,11 @@ +version!= sh get-version.sh + .PATH: ${.CURDIR}/.. CFLAGS+=-I${.CURDIR}/.. CFLAGS+= -DHAVE_REALLOCF -DHAVE_STRLCPY -DHAVE_GETPROGNAME CFLAGS+=-DCONF_PATH='"/etc/dma"' -CFLAGS+=-DLIBEXEC_PATH='"/usr/libexec"' -DDMA_VERSION='"v0.7"' +CFLAGS+=-DLIBEXEC_PATH='"/usr/libexec"' -DDMA_VERSION='"${version}"' DPADD= ${LIBSSL} ${LIBCRYPTO} LDADD= -lssl -lcrypto diff --git a/libexec/dma/get-version.sh b/libexec/dma/get-version.sh new file mode 100644 index 0000000000..aecc3331f4 --- /dev/null +++ b/libexec/dma/get-version.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +gitver=$(git describe 2>/dev/null | tr - .) +filever=$(cat VERSION) + +version=${gitver} +: ${version:=$filever} + +echo "$version" diff --git a/libexec/dma/net.c b/libexec/dma/net.c index 985c5393ac..d95a7884b8 100644 --- a/libexec/dma/net.c +++ b/libexec/dma/net.c @@ -256,7 +256,7 @@ smtp_login(int fd, char *login, char* password) return (0); } else if (res == -2) { /* - * If the return code is -2, then then the login attempt failed, + * If the return code is -2, then then the login attempt failed, * do not try other login mechanisms */ return (1); @@ -493,17 +493,6 @@ deliver_remote(struct qitem *it) int port; int error = 1, smarthost = 0; - host = strrchr(it->addr, '@'); - /* Should not happen */ - if (host == NULL) { - snprintf(errmsg, sizeof(errmsg), "Internal error: badly formed address %s", - it->addr); - return(-1); - } else { - /* Step over the @ */ - host++; - } - port = SMTP_PORT; /* Smarthost support? */ @@ -512,11 +501,23 @@ deliver_remote(struct qitem *it) port = config.port; syslog(LOG_INFO, "using smarthost (%s:%i)", host, port); smarthost = 1; + } else { + host = strrchr(it->addr, '@'); + /* Should not happen */ + if (host == NULL) { + snprintf(errmsg, sizeof(errmsg), "Internal error: badly formed address %s", + it->addr); + return(-1); + } else { + /* Step over the @ */ + host++; + } } error = dns_get_mx_list(host, port, &hosts, smarthost); if (error) { - syslog(LOG_NOTICE, "remote delivery %s: DNS failure (%s)", + snprintf(errmsg, sizeof(errmsg), "DNS lookup failure: host %s not found", host); + syslog(LOG_NOTICE, "remote delivery %s: DNS lookup failure: host %s not found", error < 0 ? "failed" : "deferred", host); return (error); diff --git a/libexec/dma/spool.c b/libexec/dma/spool.c index 9c4d79e854..416b5fa8f0 100644 --- a/libexec/dma/spool.c +++ b/libexec/dma/spool.c @@ -374,6 +374,8 @@ acquirespool(struct qitem *it) return (0); fail: + if (errno == EWOULDBLOCK) + return (1); syslog(LOG_INFO, "could not acquire queue file: %m"); return (-1); } @@ -393,3 +395,46 @@ dropspool(struct queue *queue, struct qitem *keep) fclose(it->mailf); } } + +int +flushqueue_since(unsigned int period) +{ + struct stat st; + struct timeval now; + char *flushfn = NULL; + + if (asprintf(&flushfn, "%s/%s", config.spooldir, SPOOL_FLUSHFILE) < 0) + return (0); + if (stat(flushfn, &st) < 0) { + free(flushfn); + return (0); + } + free(flushfn); + flushfn = NULL; + if (gettimeofday(&now, 0) != 0) + return (0); + + /* Did the flush file get touched within the last period seconds? */ + if (st.st_mtim.tv_sec + period >= now.tv_sec) + return (1); + else + return (0); +} + +int +flushqueue_signal(void) +{ + char *flushfn = NULL; + int fd; + + if (asprintf(&flushfn, "%s/%s", config.spooldir, SPOOL_FLUSHFILE) < 0) + return (-1); + fd = open(flushfn, O_CREAT|O_WRONLY|O_TRUNC, 0660); + free(flushfn); + if (fd < 0) { + syslog(LOG_ERR, "could not open flush file: %m"); + return (-1); + } + close(fd); + return (0); +} -- 2.41.0