From owner-svn-src-all@freebsd.org Sat Aug 20 16:29:09 2016 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id D2C65BC08D6; Sat, 20 Aug 2016 16:29:09 +0000 (UTC) (envelope-from bapt@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id A33A01890; Sat, 20 Aug 2016 16:29:09 +0000 (UTC) (envelope-from bapt@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id u7KGT8WL034317; Sat, 20 Aug 2016 16:29:08 GMT (envelope-from bapt@FreeBSD.org) Received: (from bapt@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id u7KGT8Te034312; Sat, 20 Aug 2016 16:29:08 GMT (envelope-from bapt@FreeBSD.org) Message-Id: <201608201629.u7KGT8Te034312@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: bapt set sender to bapt@FreeBSD.org using -f From: Baptiste Daroussin Date: Sat, 20 Aug 2016 16:29:08 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-vendor@freebsd.org Subject: svn commit: r304534 - vendor/dma/20160806 X-SVN-Group: vendor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.22 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 20 Aug 2016 16:29:09 -0000 Author: bapt Date: Sat Aug 20 16:29:08 2016 New Revision: 304534 URL: https://svnweb.freebsd.org/changeset/base/304534 Log: tag import of Dragonfly Mail Agent 20160806 Added: vendor/dma/20160806/ - copied from r304532, vendor/dma/dist/ Replaced: vendor/dma/20160806/VERSION - copied unchanged from r304533, vendor/dma/dist/VERSION vendor/dma/20160806/dma-mbox-create.c - copied unchanged from r304533, vendor/dma/dist/dma-mbox-create.c vendor/dma/20160806/dma.c - copied unchanged from r304533, vendor/dma/dist/dma.c vendor/dma/20160806/dma.h - copied unchanged from r304533, vendor/dma/dist/dma.h vendor/dma/20160806/dns.c - copied unchanged from r304533, vendor/dma/dist/dns.c vendor/dma/20160806/local.c - copied unchanged from r304533, vendor/dma/dist/local.c vendor/dma/20160806/net.c - copied unchanged from r304533, vendor/dma/dist/net.c Copied: vendor/dma/20160806/VERSION (from r304533, vendor/dma/dist/VERSION) ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ vendor/dma/20160806/VERSION Sat Aug 20 16:29:08 2016 (r304534, copy of r304533, vendor/dma/dist/VERSION) @@ -0,0 +1 @@ +v0.11 Copied: vendor/dma/20160806/dma-mbox-create.c (from r304533, vendor/dma/dist/dma-mbox-create.c) ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ vendor/dma/20160806/dma-mbox-create.c Sat Aug 20 16:29:08 2016 (r304534, copy of r304533, vendor/dma/dist/dma-mbox-create.c) @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2010-2014, Simon Schubert <2@0x2c.org>. + * Copyright (c) 2008 The DragonFly Project. All rights reserved. + * + * This code is derived from software contributed to The DragonFly Project + * by Simon Schubert <2@0x2c.org>. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of The DragonFly Project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific, prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * This binary is setuid root. Use extreme caution when touching + * user-supplied information. Keep the root window as small as possible. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dma.h" + + +static void +logfail(int exitcode, const char *fmt, ...) +{ + int oerrno = errno; + va_list ap; + char outs[1024]; + + outs[0] = 0; + if (fmt != NULL) { + va_start(ap, fmt); + vsnprintf(outs, sizeof(outs), fmt, ap); + va_end(ap); + } + + errno = oerrno; + if (*outs != 0) + syslog(LOG_ERR, errno ? "%s: %m" : "%s", outs); + else + syslog(LOG_ERR, errno ? "%m" : "unknown error"); + + exit(exitcode); +} + +/* + * Create a mbox in /var/mail for a given user, or make sure + * the permissions are correct for dma. + */ + +int +main(int argc, char **argv) +{ + const char *user; + struct passwd *pw; + struct group *gr; + uid_t user_uid; + gid_t mail_gid; + int error; + char fn[PATH_MAX+1]; + int f; + + openlog("dma-mbox-create", 0, LOG_MAIL); + + errno = 0; + gr = getgrnam(DMA_GROUP); + if (!gr) + logfail(EX_CONFIG, "cannot find dma group `%s'", DMA_GROUP); + + mail_gid = gr->gr_gid; + + if (setgid(mail_gid) != 0) + logfail(EX_NOPERM, "cannot set gid to %d (%s)", mail_gid, DMA_GROUP); + if (getegid() != mail_gid) + logfail(EX_NOPERM, "cannot set gid to %d (%s), still at %d", mail_gid, DMA_GROUP, getegid()); + + /* + * We take exactly one argument: the username. + */ + if (argc != 2) { + errno = 0; + logfail(EX_USAGE, "no arguments"); + } + user = argv[1]; + + syslog(LOG_NOTICE, "creating mbox for `%s'", user); + + /* the username may not contain a pathname separator */ + if (strchr(user, '/')) { + errno = 0; + logfail(EX_DATAERR, "path separator in username `%s'", user); + exit(1); + } + + /* verify the user exists */ + errno = 0; + pw = getpwnam(user); + if (!pw) + logfail(EX_NOUSER, "cannot find user `%s'", user); + + user_uid = pw->pw_uid; + + error = snprintf(fn, sizeof(fn), "%s/%s", _PATH_MAILDIR, user); + if (error < 0 || (size_t)error >= sizeof(fn)) { + if (error >= 0) { + errno = 0; + logfail(EX_USAGE, "mbox path too long"); + } + logfail(EX_CANTCREAT, "cannot build mbox path for `%s/%s'", _PATH_MAILDIR, user); + } + + f = open(fn, O_RDONLY|O_CREAT|O_NOFOLLOW, 0600); + if (f < 0) + logfail(EX_NOINPUT, "cannt open mbox `%s'", fn); + + if (fchown(f, user_uid, mail_gid)) + logfail(EX_OSERR, "cannot change owner of mbox `%s'", fn); + + if (fchmod(f, 0620)) + logfail(EX_OSERR, "cannot change permissions of mbox `%s'", fn); + + /* file should be present with the right owner and permissions */ + + syslog(LOG_NOTICE, "successfully created mbox for `%s'", user); + + return (0); +} Copied: vendor/dma/20160806/dma.c (from r304533, vendor/dma/dist/dma.c) ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ vendor/dma/20160806/dma.c Sat Aug 20 16:29:08 2016 (r304534, copy of r304533, vendor/dma/dist/dma.c) @@ -0,0 +1,632 @@ +/* + * Copyright (c) 2008-2014, Simon Schubert <2@0x2c.org>. + * Copyright (c) 2008 The DragonFly Project. All rights reserved. + * + * This code is derived from software contributed to The DragonFly Project + * by Simon Schubert <2@0x2c.org>. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of The DragonFly Project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific, prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "dfcompat.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dma.h" + + +static void deliver(struct qitem *); + +struct aliases aliases = LIST_HEAD_INITIALIZER(aliases); +struct strlist tmpfs = SLIST_HEAD_INITIALIZER(tmpfs); +struct authusers authusers = LIST_HEAD_INITIALIZER(authusers); +char username[USERNAME_SIZE]; +uid_t useruid; +const char *logident_base; +char errmsg[ERRMSG_SIZE]; + +static int daemonize = 1; +static int doqueue = 0; + +struct config config = { + .smarthost = NULL, + .port = 25, + .aliases = "/etc/aliases", + .spooldir = "/var/spool/dma", + .authpath = NULL, + .certfile = NULL, + .features = 0, + .mailname = NULL, + .masquerade_host = NULL, + .masquerade_user = NULL, +}; + + +static void +sighup_handler(int signo) +{ + (void)signo; /* so that gcc doesn't complain */ +} + +static char * +set_from(struct queue *queue, const char *osender) +{ + const char *addr; + char *sender; + + if (osender) { + addr = osender; + } else if (getenv("EMAIL") != NULL) { + addr = getenv("EMAIL"); + } else { + if (config.masquerade_user) + addr = config.masquerade_user; + else + addr = username; + } + + if (!strchr(addr, '@')) { + const char *from_host = hostname(); + + if (config.masquerade_host) + from_host = config.masquerade_host; + + if (asprintf(&sender, "%s@%s", addr, from_host) <= 0) + return (NULL); + } else { + sender = strdup(addr); + if (sender == NULL) + return (NULL); + } + + if (strchr(sender, '\n') != NULL) { + errno = EINVAL; + return (NULL); + } + + queue->sender = sender; + return (sender); +} + +static int +read_aliases(void) +{ + yyin = fopen(config.aliases, "r"); + if (yyin == NULL) { + /* + * Non-existing aliases file is not a fatal error + */ + if (errno == ENOENT) + return (0); + /* Other problems are. */ + return (-1); + } + if (yyparse()) + return (-1); /* fatal error, probably malloc() */ + fclose(yyin); + return (0); +} + +static int +do_alias(struct queue *queue, const char *addr) +{ + struct alias *al; + struct stritem *sit; + int aliased = 0; + + LIST_FOREACH(al, &aliases, next) { + if (strcmp(al->alias, addr) != 0) + continue; + SLIST_FOREACH(sit, &al->dests, next) { + if (add_recp(queue, sit->str, EXPAND_ADDR) != 0) + return (-1); + } + aliased = 1; + } + + return (aliased); +} + +int +add_recp(struct queue *queue, const char *str, int expand) +{ + struct qitem *it, *tit; + struct passwd *pw; + char *host; + int aliased = 0; + + it = calloc(1, sizeof(*it)); + if (it == NULL) + return (-1); + it->addr = strdup(str); + if (it->addr == NULL) + return (-1); + + it->sender = queue->sender; + host = strrchr(it->addr, '@'); + if (host != NULL && + (strcmp(host + 1, hostname()) == 0 || + strcmp(host + 1, "localhost") == 0)) { + *host = 0; + } + LIST_FOREACH(tit, &queue->queue, next) { + /* weed out duplicate dests */ + if (strcmp(tit->addr, it->addr) == 0) { + free(it->addr); + free(it); + return (0); + } + } + LIST_INSERT_HEAD(&queue->queue, it, next); + + /** + * 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); + if (!aliased && expand == EXPAND_WILDCARD) + aliased = do_alias(queue, "*"); + if (aliased < 0) + return (-1); + if (aliased) { + LIST_REMOVE(it, next); + } else { + /* Local destination, check */ + pw = getpwnam(it->addr); + if (pw == NULL) + goto out; + /* XXX read .forward */ + endpwent(); + } + } + } else { + it->remote = 1; + } + + return (0); + +out: + free(it->addr); + free(it); + return (-1); +} + +static struct qitem * +go_background(struct queue *queue) +{ + struct sigaction sa; + struct qitem *it; + pid_t pid; + + if (daemonize && daemon(0, 0) != 0) { + syslog(LOG_ERR, "can not daemonize: %m"); + exit(EX_OSERR); + } + daemonize = 0; + + bzero(&sa, sizeof(sa)); + sa.sa_handler = SIG_IGN; + sigaction(SIGCHLD, &sa, NULL); + + LIST_FOREACH(it, &queue->queue, next) { + /* No need to fork for the last dest */ + if (LIST_NEXT(it, next) == NULL) + goto retit; + + pid = fork(); + switch (pid) { + case -1: + syslog(LOG_ERR, "can not fork: %m"); + exit(EX_OSERR); + break; + + case 0: + /* + * Child: + * + * return and deliver mail + */ +retit: + /* + * If necessary, acquire the queue and * mail files. + * If this fails, we probably were raced by another + * process. It is okay to be raced if we're supposed + * to flush the queue. + */ + setlogident("%s", it->queueid); + switch (acquirespool(it)) { + case 0: + break; + case 1: + if (doqueue) + exit(EX_OK); + syslog(LOG_WARNING, "could not lock queue file"); + exit(EX_SOFTWARE); + default: + exit(EX_SOFTWARE); + } + dropspool(queue, it); + return (it); + + default: + /* + * Parent: + * + * fork next child + */ + break; + } + } + + syslog(LOG_CRIT, "reached dead code"); + exit(EX_SOFTWARE); +} + +static void +deliver(struct qitem *it) +{ + int error; + unsigned int backoff = MIN_RETRY, slept; + struct timeval now; + struct stat st; + + snprintf(errmsg, sizeof(errmsg), "unknown bounce reason"); + +retry: + syslog(LOG_INFO, "<%s> trying delivery", it->addr); + + if (it->remote) + error = deliver_remote(it); + else + error = deliver_local(it); + + switch (error) { + case 0: + delqueue(it); + syslog(LOG_INFO, "<%s> delivery successful", it->addr); + exit(EX_OK); + + case 1: + if (stat(it->queuefn, &st) != 0) { + syslog(LOG_ERR, "lost queue file `%s'", it->queuefn); + exit(EX_SOFTWARE); + } + if (gettimeofday(&now, NULL) == 0 && + (now.tv_sec - st.st_mtim.tv_sec > MAX_TIMEOUT)) { + snprintf(errmsg, sizeof(errmsg), + "Could not deliver for the last %d seconds. Giving up.", + MAX_TIMEOUT); + goto bounce; + } + 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) + backoff = MAX_RETRY; + } + goto retry; + + case -1: + default: + break; + } + +bounce: + bounce(it, errmsg); + /* NOTREACHED */ +} + +void +run_queue(struct queue *queue) +{ + struct qitem *it; + + if (LIST_EMPTY(&queue->queue)) + return; + + it = go_background(queue); + deliver(it); + /* NOTREACHED */ +} + +static void +show_queue(struct queue *queue) +{ + struct qitem *it; + int locked = 0; /* XXX */ + + if (LIST_EMPTY(&queue->queue)) { + printf("Mail queue is empty\n"); + return; + } + + LIST_FOREACH(it, &queue->queue, next) { + printf("ID\t: %s%s\n" + "From\t: %s\n" + "To\t: %s\n", + it->queueid, + locked ? "*" : "", + it->sender, it->addr); + + if (LIST_NEXT(it, next) != NULL) + printf("--\n"); + } +} + +/* + * TODO: + * + * - alias processing + * - use group permissions + * - proper sysexit codes + */ + +int +main(int argc, char **argv) +{ + struct sigaction act; + char *sender = NULL; + struct queue queue; + int i, ch; + int nodot = 0, showq = 0, queue_only = 0; + int recp_from_header = 0; + + set_username(); + + /* + * We never run as root. If called by root, drop permissions + * to the mail user. + */ + if (geteuid() == 0 || getuid() == 0) { + struct passwd *pw; + + errno = 0; + pw = getpwnam(DMA_ROOT_USER); + if (pw == NULL) { + if (errno == 0) + errx(EX_CONFIG, "user '%s' not found", DMA_ROOT_USER); + else + err(EX_OSERR, "cannot drop root privileges"); + } + + if (setuid(pw->pw_uid) != 0) + err(EX_OSERR, "cannot drop root privileges"); + + if (geteuid() == 0 || getuid() == 0) + errx(EX_OSERR, "cannot drop root privileges"); + } + + atexit(deltmp); + init_random(); + + bzero(&queue, sizeof(queue)); + LIST_INIT(&queue.queue); + + if (strcmp(argv[0], "mailq") == 0) { + argv++; argc--; + showq = 1; + if (argc != 0) + errx(EX_USAGE, "invalid arguments"); + goto skipopts; + } else if (strcmp(argv[0], "newaliases") == 0) { + logident_base = "dma"; + setlogident(NULL); + + if (read_aliases() != 0) + errx(EX_SOFTWARE, "could not parse aliases file `%s'", config.aliases); + exit(EX_OK); + } + + opterr = 0; + while ((ch = getopt(argc, argv, ":A:b:B:C:d:Df:F:h:iL:N:no:O:q:r:R:tUV:vX:")) != -1) { + switch (ch) { + case 'A': + /* -AX is being ignored, except for -A{c,m} */ + if (optarg[0] == 'c' || optarg[0] == 'm') { + break; + } + /* else FALLTRHOUGH */ + case 'b': + /* -bX is being ignored, except for -bp */ + if (optarg[0] == 'p') { + showq = 1; + break; + } else if (optarg[0] == 'q') { + queue_only = 1; + break; + } + /* else FALLTRHOUGH */ + case 'D': + daemonize = 0; + break; + case 'L': + logident_base = optarg; + break; + case 'f': + case 'r': + sender = optarg; + break; + + case 't': + recp_from_header = 1; + break; + + case 'o': + /* -oX is being ignored, except for -oi */ + if (optarg[0] != 'i') + break; + /* else FALLTRHOUGH */ + case 'O': + break; + case 'i': + nodot = 1; + break; + + case 'q': + /* Don't let getopt slup up other arguments */ + if (optarg && *optarg == '-') + optind--; + 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; + + case ':': + if (optopt == 'q') { + doqueue = 1; + break; + } + /* FALLTHROUGH */ + + default: + fprintf(stderr, "invalid argument: `-%c'\n", optopt); + exit(EX_USAGE); + } + } + argc -= optind; + argv += optind; + opterr = 1; + + if (argc != 0 && (showq || doqueue)) + errx(EX_USAGE, "sending mail and queue operations are mutually exclusive"); + + if (showq + doqueue > 1) + errx(EX_USAGE, "conflicting queue operations"); + +skipopts: + if (logident_base == NULL) + logident_base = "dma"; + setlogident(NULL); + + act.sa_handler = sighup_handler; + act.sa_flags = 0; + sigemptyset(&act.sa_mask); + if (sigaction(SIGHUP, &act, NULL) != 0) + syslog(LOG_WARNING, "can not set signal handler: %m"); + + parse_conf(CONF_PATH "/dma.conf"); + + if (config.authpath != NULL) + parse_authfile(config.authpath); + + if (showq) { + if (load_queue(&queue) < 0) + errlog(EX_NOINPUT, "can not load queue"); + show_queue(&queue); + return (0); + } + + if (doqueue) { + flushqueue_signal(); + if (load_queue(&queue) < 0) + errlog(EX_NOINPUT, "can not load queue"); + run_queue(&queue); + return (0); + } + + if (read_aliases() != 0) + errlog(EX_SOFTWARE, "could not parse aliases file `%s'", config.aliases); + + if ((sender = set_from(&queue, sender)) == NULL) + errlog(EX_SOFTWARE, NULL); + + if (newspoolf(&queue) != 0) + errlog(EX_CANTCREAT, "can not create temp file in `%s'", config.spooldir); + + setlogident("%s", queue.id); + + for (i = 0; i < argc; i++) { + if (add_recp(&queue, argv[i], EXPAND_WILDCARD) != 0) + errlogx(EX_DATAERR, "invalid recipient `%s'", argv[i]); + } + + if (LIST_EMPTY(&queue.queue) && !recp_from_header) + errlogx(EX_NOINPUT, "no recipients"); + + if (readmail(&queue, nodot, recp_from_header) != 0) + errlog(EX_NOINPUT, "can not read mail"); + + if (LIST_EMPTY(&queue.queue)) + errlogx(EX_NOINPUT, "no recipients"); + + if (linkspool(&queue) != 0) + errlog(EX_CANTCREAT, "can not create spools"); + + /* From here on the mail is safe. */ + + if (config.features & DEFER || queue_only) + return (0); + + run_queue(&queue); + + /* NOTREACHED */ + return (0); +} Copied: vendor/dma/20160806/dma.h (from r304533, vendor/dma/dist/dma.h) ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ vendor/dma/20160806/dma.h Sat Aug 20 16:29:08 2016 (r304534, copy of r304533, vendor/dma/dist/dma.h) @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2008-2014, Simon Schubert <2@0x2c.org>. + * Copyright (c) 2008 The DragonFly Project. All rights reserved. + * + * This code is derived from software contributed to The DragonFly Project + * by Simon Schubert <2@0x2c.org> and + * Matthias Schmidt . + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of The DragonFly Project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific, prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef DMA_H +#define DMA_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#define VERSION "DragonFly Mail Agent " DMA_VERSION + +#define BUF_SIZE 2048 +#define ERRMSG_SIZE 1024 +#define USERNAME_SIZE 50 +#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 +#define SMTP_PORT 25 /* Default SMTP port */ +#define CON_TIMEOUT (5*60) /* Connection timeout per RFC5321 */ + +#define STARTTLS 0x002 /* StartTLS support */ +#define SECURETRANS 0x004 /* SSL/TLS in general */ +#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 TLS_OPP 0x080 /* Opportunistic STARTTLS */ +#define NULLCLIENT 0x100 /* Nullclient support */ + +#ifndef CONF_PATH +#error Please define CONF_PATH +#endif + +#ifndef LIBEXEC_PATH +#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 +#endif + + +struct stritem { + SLIST_ENTRY(stritem) next; + char *str; +}; +SLIST_HEAD(strlist, stritem); + +struct alias { + LIST_ENTRY(alias) next; + char *alias; + struct strlist dests; +}; +LIST_HEAD(aliases, alias); + +struct qitem { + LIST_ENTRY(qitem) next; + const char *sender; + char *addr; + char *queuefn; + char *mailfn; + char *queueid; + FILE *queuef; + FILE *mailf; + int remote; +}; +LIST_HEAD(queueh, qitem); + +struct queue { + struct queueh queue; + char *id; + FILE *mailf; + char *tmpf; + const char *sender; +}; + +struct config { + const char *smarthost; + int port; + const char *aliases; + const char *spooldir; + const char *authpath; + const char *certfile; + int features; + const char *mailname; + const char *masquerade_host; + const char *masquerade_user; + + /* XXX does not belong into config */ + SSL *ssl; +}; + + +struct authuser { + SLIST_ENTRY(authuser) next; + char *login; + char *password; + char *host; +}; +SLIST_HEAD(authusers, authuser); + + +struct mx_hostentry { + char host[MAXDNAME]; + char addr[INET6_ADDRSTRLEN]; + int pref; + struct addrinfo ai; + struct sockaddr_storage sa; +}; + + +/* global variables */ +extern struct aliases aliases; +extern struct config config; +extern struct strlist tmpfs; +extern struct authusers authusers; +extern char username[USERNAME_SIZE]; +extern uid_t useruid; +extern const char *logident_base; + +extern char neterr[ERRMSG_SIZE]; +extern char errmsg[ERRMSG_SIZE]; + +/* aliases_parse.y */ +int yyparse(void); +int yywrap(void); +int yylex(void); +extern FILE *yyin; + +/* conf.c */ +void trim_line(char *); +void parse_conf(const char *); +void parse_authfile(const char *); + +/* crypto.c */ +void hmac_md5(unsigned char *, int, unsigned char *, int, unsigned char *); +int smtp_auth_md5(int, char *, char *); +int smtp_init_crypto(int, int); + +/* dns.c */ +int dns_get_mx_list(const char *, int, struct mx_hostentry **, int); + +/* net.c */ *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***