The branch main has been updated by bapt:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=fbe95b885f3431b1d8003545b32e8ffa88f2d16b

commit fbe95b885f3431b1d8003545b32e8ffa88f2d16b
Merge: 9413dfd331e7 16a84834c279
Author:     Baptiste Daroussin <b...@freebsd.org>
AuthorDate: 2021-09-22 09:09:27 +0000
Commit:     Baptiste Daroussin <b...@freebsd.org>
CommitDate: 2021-09-22 09:10:58 +0000

    dma: import snapshot 2021-07-10

 contrib/dma/Makefile       |   2 +-
 contrib/dma/VERSION        |   2 +-
 contrib/dma/conf.c         |  20 +++-
 contrib/dma/crypto.c       |  43 ++++++-
 contrib/dma/dfcompat.c     |   6 +-
 contrib/dma/dma.8          |  17 ++-
 contrib/dma/dma.c          |  38 +++---
 contrib/dma/dma.conf       |   6 +-
 contrib/dma/dma.h          |  17 ++-
 contrib/dma/dns.c          |   5 -
 contrib/dma/get-version.sh |   0
 contrib/dma/local.c        |   5 +-
 contrib/dma/mail.c         |  40 +++++--
 contrib/dma/net.c          | 284 ++++++++++++++++++++++++++++++++-------------
 contrib/dma/spool.c        |   2 +
 contrib/dma/util.c         |  20 ++++
 16 files changed, 378 insertions(+), 129 deletions(-)

diff --cc contrib/dma/Makefile
index aed2ef7246cf,000000000000..8cae5b28f98b
mode 100644,000000..100644
--- a/contrib/dma/Makefile
+++ b/contrib/dma/Makefile
@@@ -1,111 -1,0 +1,111 @@@
 +#
 +# Depending on your operating system, you might want to influence
 +# the conditional inclusion of some helper functions:
 +#
 +# Define HAVE_* (in caps) if your system already provides:
 +#   reallocf
 +#   strlcpy
 +#   getprogname
 +#
 +
 +SH?=          sh
 +
 +version=      $(shell ${SH} get-version.sh)
 +debversion=   $(shell ${SH} get-version.sh | sed -Ee 
's/^v//;s/[.]([[:digit:]]+)[.](g[[:xdigit:]]+)$$/+\1+\2/')
 +
 +CC?=          gcc
 +CFLAGS?=      -O -pipe
 +LDADD?=               -lssl -lcrypto -lresolv
 +
- CFLAGS+=      -Wall -DDMA_VERSION='"${version}"' 
-DLIBEXEC_PATH='"${LIBEXEC}"' -DCONF_PATH='"${CONFDIR}"'
++CFLAGS+=      -Wall -Wno-format-truncation -DDMA_VERSION='"${version}"' 
-DLIBEXEC_PATH='"${LIBEXEC}"' -DCONF_PATH='"${CONFDIR}"'
 +
 +INSTALL?=     install -p
 +CHGRP?=               chgrp
 +CHMOD?=               chmod
 +
 +PREFIX?=      /usr/local
 +SBIN?=                ${PREFIX}/sbin
 +LIBEXEC?=     ${PREFIX}/lib
 +CONFDIR?=     /etc/dma
 +MAN?=         ${PREFIX}/share/man
 +VAR?=         /var
 +DMASPOOL?=    ${VAR}/spool/dma
 +VARMAIL?=     ${VAR}/mail
 +SYMLINK?=     -s # or empty to create hard link
 +
 +YACC?=                yacc
 +LEX?=         lex
 +LN?=          ln
 +
 +OBJS= aliases_parse.o aliases_scan.o base64.o conf.o crypto.o
 +OBJS+=        dma.o dns.o local.o mail.o net.o spool.o util.o
 +OBJS+=        dfcompat.o
 +
 +all: dma dma-mbox-create
 +
 +clean:
 +      -rm -f .depend dma dma-mbox-create *.[do]
 +      -rm -f aliases_parse.[ch] aliases_scan.c
 +
 +install: all
 +      ${INSTALL} -d ${DESTDIR}${SBIN}
 +      ${INSTALL} -d ${DESTDIR}${MAN}/man8 ${DESTDIR}${LIBEXEC}
 +      ${INSTALL} -m 2755 -o root -g mail dma ${DESTDIR}${SBIN}
 +      ${INSTALL} -m 4754 -o root -g mail dma-mbox-create ${DESTDIR}${LIBEXEC}
 +      ${INSTALL} -m 0644 dma.8 ${DESTDIR}${MAN}/man8/
 +
 +sendmail-link:
 +      cd ${DESTDIR}${SBIN} && ${LN} ${SYMLINK} dma sendmail
 +
 +mailq-link:
 +      cd ${DESTDIR}${SBIN} && ${LN} ${SYMLINK} dma mailq
 +
 +install-spool-dirs:
 +      ${INSTALL} -d -m 2775 -o root -g mail ${DESTDIR}${DMASPOOL}
 +      ${INSTALL} -d -m 2775 -o root -g mail ${DESTDIR}${VARMAIL}
 +
 +permissions:
 +      -${CHGRP} mail ${DESTDIR}${VARMAIL}/*
 +      -${CHMOD} g+w ${DESTDIR}${VARMAIL}/*
 +      -${CHMOD} 660 ${DESTDIR}${DMASPOOL}/flush
 +
 +install-etc:
 +      ${INSTALL} -d ${DESTDIR}${CONFDIR}
 +      @if [ -e ${DESTDIR}${CONFDIR}/dma.conf ]; then \
 +              echo "Not overwriting ${DESTDIR}${CONFDIR}/dma.conf."; \
 +      else \
 +              echo ${INSTALL} -m 644 -o root -g mail dma.conf 
${DESTDIR}${CONFDIR}; \
 +              ${INSTALL} -m 644 -o root -g mail dma.conf 
${DESTDIR}${CONFDIR}; \
 +      fi
 +      @if [ -e ${DESTDIR}${CONFDIR}/auth.conf ]; then \
 +              echo "Not overwriting ${DESTDIR}${CONFDIR}/auth.conf."; \
 +      else \
 +              echo ${INSTALL} -m 640 -o root -g mail auth.conf 
${DESTDIR}${CONFDIR}; \
 +              ${INSTALL} -m 640 -o root -g mail auth.conf 
${DESTDIR}${CONFDIR}; \
 +      fi
 +
 +aliases_parse.c: aliases_parse.y
 +      ${YACC} -d -o aliases_parse.c aliases_parse.y
 +
 +aliases_scan.c: aliases_scan.l
 +      ${LEX} -t aliases_scan.l > aliases_scan.c
 +
 +.SUFFIXES: .c .o
 +
 +.c.o:
 +      ${CC} ${CFLAGS} ${CPPFLAGS} -include dfcompat.h -o $@ -c $<
 +
 +dma: ${OBJS}
 +      ${CC} ${LDFLAGS} -o $@ ${OBJS} ${LDADD}
 +
 +
 +dch:
 +      dch --release-heuristic changelog -v ${debversion}
 +
 +
 +ppa:
 +      @if [ -z '${DEB_DIST}' ]; then echo "please set DEB_DIST to build"; 
exit 1; fi
 +      dch -v "${debversion}~${DEB_DIST}" -D ${DEB_DIST} "${DEB_DIST} build" -b
 +      debuild -S -sa
 +      ver=$$(dpkg-parsechangelog -n1 | awk '$$1 == "Version:" { print $$2 
}'); \
 +      dput ppa:corecode/dma ../dma_$${ver}_source.changes
diff --cc contrib/dma/conf.c
index b8a6a2e2cbd7,000000000000..13cfac7a6de4
mode 100644,000000..100644
--- a/contrib/dma/conf.c
+++ b/contrib/dma/conf.c
@@@ -1,245 -1,0 +1,261 @@@
 +/*
 + * Copyright (c) 2008 The DragonFly Project.  All rights reserved.
 + *
 + * This code is derived from software contributed to The DragonFly Project
 + * by Matthias Schmidt <matth...@dragonflybsd.org>, University of Marburg,
 + * Germany.
 + *
 + * 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 <err.h>
 +#include <errno.h>
 +#include <stdio.h>
 +#include <stdlib.h>
 +#include <string.h>
 +#include <syslog.h>
 +#include <stdarg.h>
 +
 +#include "dma.h"
 +
 +#define DP    ": \t"
 +#define EQS   " \t"
 +
 +
 +/*
 + * Remove trailing \n's
 + */
 +void
 +trim_line(char *line)
 +{
 +      size_t linelen;
 +      char *p;
 +
 +      if ((p = strchr(line, '\n')))
 +              *p = (char)0;
 +
 +      /* Escape leading dot in every case */
 +      linelen = strlen(line);
 +      if (line[0] == '.') {
 +              if ((linelen + 2) > 1000) {
 +                      syslog(LOG_CRIT, "Cannot escape leading dot.  Buffer 
overflow");
 +                      exit(EX_DATAERR);
 +              }
 +              memmove((line + 1), line, (linelen + 1));
 +              line[0] = '.';
 +      }
 +}
 +
 +static void
 +chomp(char *str)
 +{
 +      size_t len = strlen(str);
 +
 +      if (len == 0)
 +              return;
 +      if (str[len - 1] == '\n')
 +              str[len - 1] = 0;
 +}
 +
 +/*
 + * Read the SMTP authentication config file
 + *
 + * file format is:
 + * user|host:password
 + *
 + * A line starting with # is treated as comment and ignored.
 + */
 +void
 +parse_authfile(const char *path)
 +{
 +      char line[2048];
 +      struct authuser *au;
 +      FILE *a;
 +      char *data;
 +      int lineno = 0;
 +
 +      a = fopen(path, "r");
 +      if (a == NULL) {
 +              errlog(EX_NOINPUT, "can not open auth file `%s'", path);
 +              /* NOTREACHED */
 +      }
 +
 +      while (!feof(a)) {
 +              if (fgets(line, sizeof(line), a) == NULL)
 +                      break;
 +              lineno++;
 +
 +              chomp(line);
 +
 +              /* We hit a comment */
 +              if (*line == '#')
 +                      continue;
 +              /* Ignore empty lines */
 +              if (*line == 0)
 +                      continue;
 +
 +              au = calloc(1, sizeof(*au));
 +              if (au == NULL)
 +                      errlog(EX_OSERR, "calloc()");
 +
 +              data = strdup(line);
 +              au->login = strsep(&data, "|");
 +              au->host = strsep(&data, DP);
 +              au->password = data;
 +
 +              if (au->login == NULL ||
 +                  au->host == NULL ||
 +                  au->password == NULL) {
 +                      errlogx(EX_CONFIG, "syntax error in authfile %s:%d", 
path, lineno);
 +                      /* NOTREACHED */
 +              }
 +
 +              SLIST_INSERT_HEAD(&authusers, au, next);
 +      }
 +
 +      fclose(a);
 +}
 +
 +/*
 + * XXX TODO
 + * Check for bad things[TM]
 + */
 +void
 +parse_conf(const char *config_path)
 +{
 +      char *word;
 +      char *data;
 +      FILE *conf;
 +      char line[2048];
 +      int lineno = 0;
 +
 +      conf = fopen(config_path, "r");
 +      if (conf == NULL) {
 +              /* Don't treat a non-existing config file as error */
 +              if (errno == ENOENT)
 +                      return;
 +              errlog(EX_NOINPUT, "can not open config `%s'", config_path);
 +              /* NOTREACHED */
 +      }
 +
 +      while (!feof(conf)) {
 +              if (fgets(line, sizeof(line), conf) == NULL)
 +                      break;
 +              lineno++;
 +
 +              chomp(line);
 +
 +              /* We hit a comment */
 +              if (strchr(line, '#'))
 +                      *strchr(line, '#') = 0;
 +
 +              data = line;
 +              word = strsep(&data, EQS);
 +
 +              /* Ignore empty lines */
 +              if (word == NULL || *word == 0)
 +                      continue;
 +
 +              if (data != NULL && *data != 0)
 +                      data = strdup(data);
 +              else
 +                      data = NULL;
 +
 +              if (strcmp(word, "SMARTHOST") == 0 && data != NULL)
 +                      config.smarthost = data;
 +              else if (strcmp(word, "PORT") == 0 && data != NULL)
 +                      config.port = atoi(data);
 +              else if (strcmp(word, "ALIASES") == 0 && data != NULL)
 +                      config.aliases = data;
 +              else if (strcmp(word, "SPOOLDIR") == 0 && data != NULL)
 +                      config.spooldir = data;
 +              else if (strcmp(word, "AUTHPATH") == 0 && data != NULL)
 +                      config.authpath= data;
 +              else if (strcmp(word, "CERTFILE") == 0 && data != NULL)
 +                      config.certfile = data;
 +              else if (strcmp(word, "MAILNAME") == 0 && data != NULL)
 +                      config.mailname = data;
 +              else if (strcmp(word, "MASQUERADE") == 0 && data != NULL) {
 +                      char *user = NULL, *host = NULL;
 +                      if (strrchr(data, '@')) {
 +                              host = strrchr(data, '@');
 +                              *host = 0;
 +                              host++;
 +                              user = data;
 +                      } else {
 +                              host = data;
 +                      }
 +                      if (host && *host == 0)
 +                              host = NULL;
 +                        if (user && *user == 0)
 +                                user = NULL;
 +                      config.masquerade_host = host;
 +                      config.masquerade_user = user;
 +              } else if (strcmp(word, "STARTTLS") == 0 && data == NULL)
 +                      config.features |= STARTTLS;
-               else if (strcmp(word, "OPPORTUNISTIC_TLS") == 0 && data == NULL)
++              else if (strcmp(word, "FINGERPRINT") == 0) {
++                      if (strlen(data) != SHA256_DIGEST_LENGTH * 2) {
++                              errlogx(EX_CONFIG, "invalid sha256 fingerprint 
length");
++                      }
++                      unsigned char *fingerprint = 
malloc(SHA256_DIGEST_LENGTH);
++                      if (fingerprint == NULL) {
++                              errlogx(EX_CONFIG, "fingerprint allocation 
failed");
++                      }
++                      unsigned int i;
++                      for (i = 0; i < SHA256_DIGEST_LENGTH; i++) {
++                              if(sscanf(data + 2 * i, "%02hhx", 
&fingerprint[i]) != 1) {
++                                      errlogx(EX_CONFIG, "failed to read 
fingerprint");
++                              }
++                      }
++                      free(data);
++                      config.fingerprint = fingerprint;
++              } else if (strcmp(word, "OPPORTUNISTIC_TLS") == 0 && data == 
NULL)
 +                      config.features |= TLS_OPP;
 +              else if (strcmp(word, "SECURETRANSFER") == 0 && data == NULL)
-                       config.features |= SECURETRANS;
++                      config.features |= SECURETRANSFER;
 +              else if (strcmp(word, "DEFER") == 0 && data == NULL)
 +                      config.features |= DEFER;
 +              else if (strcmp(word, "INSECURE") == 0 && data == NULL)
 +                      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(EX_CONFIG, "syntax error in %s:%d", 
config_path, lineno);
 +                      /* NOTREACHED */
 +              }
 +      }
 +
 +      if ((config.features & NULLCLIENT) && config.smarthost == NULL) {
 +              errlogx(EX_CONFIG, "%s: NULLCLIENT requires SMARTHOST", 
config_path);
 +              /* NOTREACHED */
 +      }
 +
 +      fclose(conf);
 +}
diff --cc contrib/dma/dma.8
index cadf899e50fc,a906f75447f2..e0f5e79ff47d
--- a/contrib/dma/dma.8
+++ b/contrib/dma/dma.8
@@@ -305,10 -313,10 +313,11 @@@ will send all mails a
  setting it to
  .Ql percolator
  will send all mails as
 -.Ql Sm off Va username @percolator .
 +.Sm off
 +.Ql Va username @percolator .
  .Sm on
  .It Ic NULLCLIENT Xo
+ (boolean, default=commented)
  .Xc
  Bypass aliases and local delivery, and instead forward all mails to
  the defined
diff --cc contrib/dma/dma.c
index b553c0fa0eef,ae0018a243d2..72115ae2b55e
--- a/contrib/dma/dma.c
+++ b/contrib/dma/dma.c
@@@ -596,8 -595,11 +595,11 @@@ skipopts
        if (read_aliases() != 0)
                errlog(EX_SOFTWARE, "could not parse aliases file `%s'", 
config.aliases);
  
+       if (newaliases)
+               return(0);
+ 
        if ((sender = set_from(&queue, sender)) == NULL)
 -              errlog(EX_SOFTWARE, NULL);
 +              errlog(EX_SOFTWARE, "set_from()");
  
        if (newspoolf(&queue) != 0)
                errlog(EX_CANTCREAT, "can not create temp file in `%s'", 
config.spooldir);
diff --cc contrib/dma/get-version.sh
index d9691ac37c95,d9691ac37c95..d9691ac37c95
mode 100755,100644..100644
--- a/contrib/dma/get-version.sh
+++ b/contrib/dma/get-version.sh
diff --cc contrib/dma/mail.c
index ad928272e1a1,000000000000..48c8ee6d4dd2
mode 100644,000000..100644
--- a/contrib/dma/mail.c
+++ b/contrib/dma/mail.c
@@@ -1,492 -1,0 +1,518 @@@
 +/*
 + * 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 <errno.h>
 +#include <inttypes.h>
 +#include <signal.h>
++#include <strings.h>
 +#include <string.h>
 +#include <syslog.h>
 +#include <unistd.h>
 +
 +#include "dma.h"
 +
 +#define MAX_LINE_RFC822       1000
 +
 +void
 +bounce(struct qitem *it, const char *reason)
 +{
 +      struct queue bounceq;
 +      char line[1000];
 +      size_t pos;
 +      int error;
 +
 +      /* Don't bounce bounced mails */
 +      if (it->sender[0] == 0) {
 +              syslog(LOG_INFO, "can not bounce a bounce message, discarding");
 +              exit(EX_SOFTWARE);
 +      }
 +
 +      bzero(&bounceq, sizeof(bounceq));
 +      LIST_INIT(&bounceq.queue);
 +      bounceq.sender = "";
 +      if (add_recp(&bounceq, it->sender, EXPAND_WILDCARD) != 0)
 +              goto fail;
 +
 +      if (newspoolf(&bounceq) != 0)
 +              goto fail;
 +
 +      syslog(LOG_ERR, "delivery failed, bouncing as %s", bounceq.id);
 +      setlogident("%s", bounceq.id);
 +
 +      error = fprintf(bounceq.mailf,
 +              "Received: from MAILER-DAEMON\n"
 +              "\tid %s\n"
-               "\tby %s (%s);\n"
++              "\tby %s (%s on %s);\n"
 +              "\t%s\n"
 +              "X-Original-To: <%s>\n"
 +              "From: MAILER-DAEMON <>\n"
 +              "To: %s\n"
 +              "Subject: Mail delivery failed\n"
 +              "Message-Id: <%s@%s>\n"
 +              "Date: %s\n"
 +              "\n"
 +              "This is the %s at %s.\n"
 +              "\n"
 +              "There was an error delivering your mail to <%s>.\n"
 +              "\n"
 +              "%s\n"
 +              "\n"
 +              "%s\n"
 +              "\n",
 +              bounceq.id,
-               hostname(), VERSION,
++              hostname(), VERSION, systemhostname(),
 +              rfc822date(),
 +              it->addr,
 +              it->sender,
 +              bounceq.id, hostname(),
 +              rfc822date(),
 +              VERSION, hostname(),
 +              it->addr,
 +              reason,
 +              config.features & FULLBOUNCE ?
 +                  "Original message follows." :
 +                  "Message headers follow.");
 +      if (error < 0)
 +              goto fail;
 +
 +      if (fseek(it->mailf, 0, SEEK_SET) != 0)
 +              goto fail;
 +      if (config.features & FULLBOUNCE) {
 +              while ((pos = fread(line, 1, sizeof(line), it->mailf)) > 0) {
 +                      if (fwrite(line, 1, pos, bounceq.mailf) != pos)
 +                              goto fail;
 +              }
 +      } else {
 +              while (!feof(it->mailf)) {
 +                      if (fgets(line, sizeof(line), it->mailf) == NULL)
 +                              break;
 +                      if (line[0] == '\n')
 +                              break;
 +                      if (fwrite(line, strlen(line), 1, bounceq.mailf) != 1)
 +                              goto fail;
 +              }
 +      }
 +
 +      if (linkspool(&bounceq) != 0)
 +              goto fail;
 +      /* bounce is safe */
 +
 +      delqueue(it);
 +
 +      run_queue(&bounceq);
 +      /* NOTREACHED */
 +
 +fail:
 +      syslog(LOG_CRIT, "error creating bounce: %m");
 +      delqueue(it);
 +      exit(EX_IOERR);
 +}
 +
 +struct parse_state {
 +      char addr[1000];
 +      int pos;
 +
 +      enum {
 +              NONE = 0,
 +              START,
 +              MAIN,
 +              EOL,
 +              QUIT
 +      } state;
 +      int comment;
 +      int quote;
 +      int brackets;
 +      int esc;
 +};
 +
 +/*
 + * Simplified RFC2822 header/address parsing.
 + * We copy escapes and quoted strings directly, since
 + * we have to pass them like this to the mail server anyways.
 + * XXX local addresses will need treatment
 + */
 +static int
 +parse_addrs(struct parse_state *ps, char *s, struct queue *queue)
 +{
 +      char *addr;
 +
 +again:
 +      switch (ps->state) {
 +      case NONE:
 +              return (-1);
 +
 +      case START:
 +              /* init our data */
 +              bzero(ps, sizeof(*ps));
 +
 +              /* skip over header name */
 +              while (*s != ':')
 +                      s++;
 +              s++;
 +              ps->state = MAIN;
 +              break;
 +
 +      case MAIN:
 +              /* all fine */
 +              break;
 +
 +      case EOL:
 +              switch (*s) {
 +              case ' ':
 +              case '\t':
-                       s++;
-                       /* continue */
++                      ps->state = MAIN;
 +                      break;
 +
 +              default:
 +                      ps->state = QUIT;
 +                      if (ps->pos != 0)
 +                              goto newaddr;
 +                      return (0);
 +              }
++              break;
 +
 +      case QUIT:
 +              return (0);
 +      }
 +
 +      for (; *s != 0; s++) {
 +              if (ps->esc) {
 +                      ps->esc = 0;
 +
 +                      switch (*s) {
 +                      case '\r':
 +                      case '\n':
 +                              goto err;
 +
 +                      default:
 +                              goto copy;
 +                      }
 +              }
 +
 +              if (ps->quote) {
 +                      switch (*s) {
 +                      case '"':
 +                              ps->quote = 0;
 +                              goto copy;
 +
 +                      case '\\':
 +                              ps->esc = 1;
 +                              goto copy;
 +
 +                      case '\r':
 +                      case '\n':
 +                              goto eol;
 +
 +                      default:
 +                              goto copy;
 +                      }
 +              }
 +
 +              switch (*s) {
 +              case '(':
 +                      ps->comment++;
 +                      break;
 +
 +              case ')':
 +                      if (ps->comment)
 +                              ps->comment--;
 +                      else
 +                              goto err;
 +                      goto skip;
 +
 +              case '"':
 +                      ps->quote = 1;
 +                      goto copy;
 +
 +              case '\\':
 +                      ps->esc = 1;
 +                      goto copy;
 +
 +              case '\r':
 +              case '\n':
 +                      goto eol;
 +              }
 +
 +              if (ps->comment)
 +                      goto skip;
 +
 +              switch (*s) {
 +              case ' ':
 +              case '\t':
 +                      /* ignore whitespace */
 +                      goto skip;
 +
 +              case '<':
 +                      /* this is the real address now */
 +                      ps->brackets = 1;
 +                      ps->pos = 0;
 +                      goto skip;
 +
 +              case '>':
 +                      if (!ps->brackets)
 +                              goto err;
 +                      ps->brackets = 0;
 +
 +                      s++;
 +                      goto newaddr;
 +
 +              case ':':
 +                      /* group - ignore */
 +                      ps->pos = 0;
 +                      goto skip;
 +
 +              case ',':
 +              case ';':
 +                      /*
 +                       * Next address, copy previous one.
 +                       * However, we might be directly after
 +                       * a <address>, or have two consecutive
 +                       * commas.
 +                       * Skip the comma unless there is
 +                       * really something to copy.
 +                       */
 +                      if (ps->pos == 0)
 +                              goto skip;
 +                      s++;
 +                      goto newaddr;
 +
 +              default:
 +                      goto copy;
 +              }
 +
 +copy:
 +              if (ps->comment)
 +                      goto skip;
 +
 +              if (ps->pos + 1 == sizeof(ps->addr))
 +                      goto err;
 +              ps->addr[ps->pos++] = *s;
 +
 +skip:
 +              ;
 +      }
 +
 +eol:
 +      ps->state = EOL;
 +      return (0);
 +
 +err:
 +      ps->state = QUIT;
 +      return (-1);
 +
 +newaddr:
 +      ps->addr[ps->pos] = 0;
 +      ps->pos = 0;
 +      addr = strdup(ps->addr);
 +      if (addr == NULL)
 +              errlog(EX_SOFTWARE, "strdup");
 +
 +      if (add_recp(queue, addr, EXPAND_WILDCARD) != 0)
 +              errlogx(EX_DATAERR, "invalid recipient `%s'", addr);
 +
 +      goto again;
 +}
 +
 +static int
 +writeline(struct queue *queue, const char *line, ssize_t linelen)
 +{
 +      ssize_t len;
 +
 +      while (linelen > 0) {
 +              len = linelen;
 +              if (linelen > MAX_LINE_RFC822) {
 +                      len = MAX_LINE_RFC822 - 10;
 +              }
 +
 +              if (fwrite(line, len, 1, queue->mailf) != 1)
 +                      return (-1);
 +
 +              if (linelen <= MAX_LINE_RFC822)
 +                      break;
 +
 +              if (fwrite("\n", 1, 1, queue->mailf) != 1)
 +                      return (-1);
 +
 +              line += MAX_LINE_RFC822 - 10;
 +              linelen = strlen(line);
 +      }
 +      return (0);
 +}
 +
 +int
 +readmail(struct queue *queue, int nodot, int recp_from_header)
 +{
 +      struct parse_state parse_state;
 +      char *line = NULL;
 +      ssize_t linelen;
 +      size_t linecap = 0;
 +      char newline[MAX_LINE_RFC822];
 +      size_t error;
 +      int had_headers = 0;
 +      int had_from = 0;
 +      int had_messagid = 0;
 +      int had_date = 0;
++      int had_first_line = 0;
++      int had_last_line = 0;
 +      int nocopy = 0;
 +      int ret = -1;
 +
 +      parse_state.state = NONE;
 +
 +      error = fprintf(queue->mailf,
 +              "Received: from %s (uid %d)\n"
 +              "\t(envelope-from %s)\n"
 +              "\tid %s\n"
-               "\tby %s (%s);\n"
++              "\tby %s (%s on %s);\n"
 +              "\t%s\n",
 +              username, useruid,
 +              queue->sender,
 +              queue->id,
-               hostname(), VERSION,
++              hostname(), VERSION, systemhostname(),
 +              rfc822date());
 +      if ((ssize_t)error < 0)
 +              return (-1);
 +
 +      while (!feof(stdin)) {
 +              newline[0] = '\0';
 +              if ((linelen = getline(&line, &linecap, stdin)) <= 0)
 +                      break;
- 
++              if (had_last_line)
++                      errlogx(EX_DATAERR, "bad mail input format:"
++                              " from %s (uid %d) (envelope-from %s)",
++                              username, useruid, queue->sender);
++              linelen = strlen(line);
++              if (linelen == 0 || line[linelen - 1] != '\n') {
++                      /*
++                       * This line did not end with a newline character.
++                       * If we fix it, it better be the last line of
++                       * the file.
++                       */
++                      line[linelen] = '\n';
++                      line[linelen + 1] = 0;
++                      had_last_line = 1;
++              }
++              if (!had_first_line) {
++                      /*
++                       * Ignore a leading RFC-976 From_ or >From_ line 
mistakenly
++                       * inserted by some programs.
++                       */
++                      if (strprefixcmp(line, "From ") == 0 || 
strprefixcmp(line, ">From ") == 0)
++                              continue;
++                      had_first_line = 1;
++              }
 +              if (!had_headers) {
 +                      if (linelen > MAX_LINE_RFC822) {
 +                              /* XXX also split headers */
 +                              errlogx(EX_DATAERR, "bad mail input format:"
 +                                  " from %s (uid %d) (envelope-from %s)",
 +                                  username, useruid, queue->sender);
 +                      }
 +                      /*
 +                       * Unless this is a continuation, switch of
 +                       * the Bcc: nocopy flag.
 +                       */
 +                      if (!(line[0] == ' ' || line[0] == '\t'))
 +                              nocopy = 0;
 +
 +                      if (strprefixcmp(line, "Date:") == 0)
 +                              had_date = 1;
 +                      else if (strprefixcmp(line, "Message-Id:") == 0)
 +                              had_messagid = 1;
 +                      else if (strprefixcmp(line, "From:") == 0)
 +                              had_from = 1;
 +                      else if (strprefixcmp(line, "Bcc:") == 0)
 +                              nocopy = 1;
 +
 +                      if (parse_state.state != NONE) {
 +                              if (parse_addrs(&parse_state, line, queue) < 0) 
{
 +                                      errlogx(EX_DATAERR, "invalid address in 
header\n");
 +                                      /* NOTREACHED */
 +                              }
 +                      }
 +
 +                      if (recp_from_header && (
 +                                      strprefixcmp(line, "To:") == 0 ||
 +                                      strprefixcmp(line, "Cc:") == 0 ||
 +                                      strprefixcmp(line, "Bcc:") == 0)) {
 +                              parse_state.state = START;
 +                              if (parse_addrs(&parse_state, line, queue) < 0) 
{
 +                                      errlogx(EX_DATAERR, "invalid address in 
header\n");
 +                                      /* NOTREACHED */
 +                              }
 +                      }
 +              }
 +
 +              if (strcmp(line, "\n") == 0 && !had_headers) {
 +                      had_headers = 1;
 +                      while (!had_date || !had_messagid || !had_from) {
 +                              if (!had_date) {
 +                                      had_date = 1;
 +                                      snprintf(newline, sizeof(newline), 
"Date: %s\n", rfc822date());
 +                              } else if (!had_messagid) {
 +                                      /* XXX msgid, assign earlier and log? */
 +                                      had_messagid = 1;
 +                                      snprintf(newline, sizeof(newline), 
"Message-Id: <%"PRIxMAX".%s.%"PRIxMAX"@%s>\n",
 +                                               (uintmax_t)time(NULL),
 +                                               queue->id,
 +                                               (uintmax_t)random(),
 +                                               hostname());
 +                              } else if (!had_from) {
 +                                      had_from = 1;
 +                                      snprintf(newline, sizeof(newline), 
"From: <%s>\n", queue->sender);
 +                              }
 +                              if (fwrite(newline, strlen(newline), 1, 
queue->mailf) != 1)
 +                                      goto fail;
 +                      }
 +                      strlcpy(newline, "\n", sizeof(newline));
 +              }
 +              if (!nodot && linelen == 2 && line[0] == '.')
 +                      break;
 +              if (!nocopy) {
 +                      if (newline[0]) {
 +                              if (fwrite(newline, strlen(newline), 1, 
queue->mailf) != 1)
 +                                      goto fail;
 +                      } else {
 +                              if (writeline(queue, line, linelen) != 0)
 +                                      goto fail;
 +                      }
 +              }
 +      }
 +
 +      ret = 0;
 +fail:
 +      free(line);
 +      return (ret);
*** 1 LINES SKIPPED ***
_______________________________________________
dev-commits-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/dev-commits-src-all
To unsubscribe, send any mail to "dev-commits-src-all-unsubscr...@freebsd.org"

Reply via email to