untrusted comment: signature from openbsd 5.6 base private key
RWR0EANmo9nqhtUjvlcWzZLRaB6PUQom8RZ4qD/bLnJuIgqxf3orTr6Ze6Y44FkIuRf/3Nnxjxw2LyzttyrVrixxVoh0gUHwLg8=

OpenBSD 5.6 errata 31, Oct 1, 2015:

Fix multiple reliability and security issues in smtpd:
   * local and remote users could make smtpd crash or stop serving requests.
   * a buffer overflow in the unprivileged, non-chrooted smtpd (lookup)
     process could allow a local user to cause a crash or potentially
     execute arbitrary code.
   * a use-after-free in the unprivileged, non-chrooted smtpd (lookup)
     process could allow a remote attacker to cause a crash or potentially
     execute arbitrary code.
   * hardlink and symlink attacks allowed a local user to unset chflags or
     leak the first line of an arbitrary file.

Apply by doing:
   signify -Vep /etc/signify/openbsd-56-base.pub -x 031_smtpd.patch.sig \
       -m - | (cd /usr/src && patch -p0)

And then rebuild and install smtpd:
   cd /usr/src/usr.sbin/smtpd
   make obj
   make depend
   make
   make install

Index: usr.sbin/smtpd/control.c
===================================================================
RCS file: /cvs/src/usr.sbin/smtpd/control.c,v
retrieving revision 1.101.4.1
diff -u -p -r1.101.4.1 control.c
--- usr.sbin/smtpd/control.c    11 Jun 2015 19:24:38 -0000      1.101.4.1
+++ usr.sbin/smtpd/control.c    1 Oct 2015 22:32:04 -0000
@@ -70,7 +70,7 @@ static void control_broadcast_verbose(in
static struct stat_backend *stat_backend = NULL;
extern const char *backend_stat;

-static uint32_t                        connid = 0;
+static uint64_t                        connid = 0;
static struct tree             ctl_conns;
static struct tree             ctl_count;
static struct stat_digest      digest;
@@ -365,10 +365,14 @@ control_accept(int listenfd, short event
       }
       (*count)++;

+       do {
+               ++connid;
+       } while (tree_get(&ctl_conns, connid));
+
       c = xcalloc(1, sizeof(*c), "control_accept");
       c->euid = euid;
       c->egid = egid;
-       c->id = ++connid;
+       c->id = connid;
       c->mproc.proc = PROC_CLIENT;
       c->mproc.handler = control_dispatch_ext;
       c->mproc.data = c;
Index: usr.sbin/smtpd/lka.c
===================================================================
RCS file: /cvs/src/usr.sbin/smtpd/lka.c,v
retrieving revision 1.172
diff -u -p -r1.172 lka.c
--- usr.sbin/smtpd/lka.c        10 Jul 2014 15:54:55 -0000      1.172
+++ usr.sbin/smtpd/lka.c        1 Oct 2015 22:32:05 -0000
@@ -184,6 +184,7 @@ lka_imsg(struct mproc *p, struct imsg *i
                       free(req_ca_vrfy_smtp->chain_cert_len);
                       free(req_ca_vrfy_smtp->cert);
                       free(req_ca_vrfy_smtp);
+                       req_ca_vrfy_smtp = NULL;
                       return;

               case IMSG_SMTP_AUTHENTICATE:
@@ -305,6 +306,7 @@ lka_imsg(struct mproc *p, struct imsg *i
                       free(req_ca_vrfy_mta->chain_cert_len);
                       free(req_ca_vrfy_mta->cert);
                       free(req_ca_vrfy_mta);
+                       req_ca_vrfy_mta = NULL;
                       return;

               case IMSG_MTA_LOOKUP_CREDENTIALS:
Index: usr.sbin/smtpd/lka_session.c
===================================================================
RCS file: /cvs/src/usr.sbin/smtpd/lka_session.c,v
retrieving revision 1.68
diff -u -p -r1.68 lka_session.c
--- usr.sbin/smtpd/lka_session.c        8 Jul 2014 13:49:09 -0000       1.68
+++ usr.sbin/smtpd/lka_session.c        1 Oct 2015 22:32:05 -0000
@@ -799,6 +799,10 @@ lka_expand_format(char *buf, size_t len,
               if (exptoklen == 0)
                       return 0;

+               /* writing expanded token at ptmp will overflow tmpbuf */
+               if (sizeof (tmpbuf) - (ptmp - tmpbuf) <= exptoklen)
+                       return 0;
+
               memcpy(ptmp, exptok, exptoklen);
               pbuf   = ebuf + 1;
               ptmp  += exptoklen;
Index: usr.sbin/smtpd/mproc.c
===================================================================
RCS file: /cvs/src/usr.sbin/smtpd/mproc.c,v
retrieving revision 1.10.4.1
diff -u -p -r1.10.4.1 mproc.c
--- usr.sbin/smtpd/mproc.c      11 Jun 2015 19:24:38 -0000      1.10.4.1
+++ usr.sbin/smtpd/mproc.c      1 Oct 2015 22:32:05 -0000
@@ -41,6 +41,7 @@
static void mproc_dispatch(int, short, void *);

static ssize_t msgbuf_write2(struct msgbuf *);
+static ssize_t imsg_read_nofd(struct imsgbuf *);

int
mproc_fork(struct mproc *p, const char *path, char *argv[])
@@ -150,7 +151,12 @@ mproc_dispatch(int fd, short event, void

       if (event & EV_READ) {

-               if ((n = imsg_read(&p->imsgbuf)) == -1) {
+               if (p->proc == PROC_CLIENT)
+                       n = imsg_read_nofd(&p->imsgbuf);
+               else
+                       n = imsg_read(&p->imsgbuf);
+
+               if (n == -1) {
                       log_warn("warn: %s -> %s: imsg_read",
                           proc_name(smtpd_process),  p->name);
                       fatal("exiting");
@@ -280,6 +286,29 @@ again:
       msgbuf_drain(msgbuf, n);

       return (n);
+}
+
+/* This should go into libutil */
+static ssize_t
+imsg_read_nofd(struct imsgbuf *ibuf)
+{
+       ssize_t  n;
+       char    *buf;
+       size_t   len;
+
+       buf = ibuf->r.buf + ibuf->r.wpos;
+       len = sizeof(ibuf->r.buf) - ibuf->r.wpos;
+
+    again:
+       if ((n = recv(ibuf->fd, buf, len, 0)) == -1) {
+               if (errno != EINTR && errno != EAGAIN)
+                       goto fail;
+               goto again;
+       }
+
+        ibuf->r.wpos += n;
+fail:
+        return (n);
}

void
Index: usr.sbin/smtpd/mta_session.c
===================================================================
RCS file: /cvs/src/usr.sbin/smtpd/mta_session.c,v
retrieving revision 1.68
diff -u -p -r1.68 mta_session.c
--- usr.sbin/smtpd/mta_session.c        4 Jul 2014 15:24:46 -0000       1.68
+++ usr.sbin/smtpd/mta_session.c        1 Oct 2015 22:32:06 -0000
@@ -1503,12 +1503,28 @@ mta_start_tls(struct mta_session *s)
static int
mta_verify_certificate(struct mta_session *s)
{
+#define MAX_CERTS      16
+#define MAX_CERT_LEN   (MAX_IMSGSIZE - (IMSG_HEADER_SIZE + sizeof(req_ca_vrfy)))
       struct ca_vrfy_req_msg  req_ca_vrfy;
       struct iovec            iov[2];
       X509                   *x;
       STACK_OF(X509)         *xchain;
-       int                     i;
       const char             *pkiname;
+       unsigned char          *cert_der[MAX_CERTS];
+       int                     cert_len[MAX_CERTS];
+       int                     i, cert_count, res;
+
+       res = 0;
+       memset(cert_der, 0, sizeof(cert_der));
+       memset(&req_ca_vrfy, 0, sizeof req_ca_vrfy);
+
+       if (s->relay->pki_name)
+               pkiname = s->relay->pki_name;
+       else
+               pkiname = s->helo;
+       if (strlcpy(req_ca_vrfy.pkiname, pkiname, sizeof req_ca_vrfy.pkiname)
+           >= sizeof req_ca_vrfy.pkiname)
+               return 0;

       x = SSL_get_peer_certificate(s->io.ssl);
       if (x == NULL)
@@ -1523,47 +1539,68 @@ mta_verify_certificate(struct mta_sessio
        *
        */

+       cert_len[0] = i2d_X509(x, &cert_der[0]);
+       X509_free(x);
+
+       if (cert_len[0] < 0) {
+               log_warnx("warn: failed to encode certificate");
+               goto end;
+       }
+       log_debug("debug: certificate 0: len=%d", cert_len[0]);
+       if (cert_len[0] > (int)MAX_CERT_LEN) {
+               log_warnx("warn: certificate too long");
+               goto end;
+       }
+
+       if (xchain) {
+               cert_count = sk_X509_num(xchain);
+               log_debug("debug: certificate chain len: %d", cert_count);
+               if (cert_count >= MAX_CERTS) {
+                       log_warnx("warn: certificate chain too long");
+                       goto end;
+               }
+       }
+       else
+               cert_count = 0;
+
+       for (i = 0; i < cert_count; ++i) {
+               x = sk_X509_value(xchain, i);
+               cert_len[i+1] = i2d_X509(x, &cert_der[i+1]);
+               if (cert_len[i+1] < 0) {
+                       log_warnx("warn: failed to encode certificate");
+                       goto end;
+               }
+               log_debug("debug: certificate %i: len=%d", i+1, cert_len[i+1]);
+               if (cert_len[i+1] > (int)MAX_CERT_LEN) {
+                       log_warnx("warn: certificate too long");
+                       goto end;
+               }
+       }
+
       tree_xset(&wait_ssl_verify, s->id, s);
       s->flags |= MTA_WAIT;

       /* Send the client certificate */
-       memset(&req_ca_vrfy, 0, sizeof req_ca_vrfy);
-       if (s->relay->pki_name)
-               pkiname = s->relay->pki_name;
-       else
-               pkiname = s->helo;
-       if (strlcpy(req_ca_vrfy.pkiname, pkiname, sizeof req_ca_vrfy.pkiname)
-           >= sizeof req_ca_vrfy.pkiname)
-               return 0;
-
       req_ca_vrfy.reqid = s->id;
-       req_ca_vrfy.cert_len = i2d_X509(x, &req_ca_vrfy.cert);
-       if (xchain)
-               req_ca_vrfy.n_chain = sk_X509_num(xchain);
+       req_ca_vrfy.cert_len = cert_len[0];
+       req_ca_vrfy.n_chain = cert_count;
       iov[0].iov_base = &req_ca_vrfy;
       iov[0].iov_len = sizeof(req_ca_vrfy);
-       iov[1].iov_base = req_ca_vrfy.cert;
-       iov[1].iov_len = req_ca_vrfy.cert_len;
+       iov[1].iov_base = cert_der[0];
+       iov[1].iov_len = cert_len[0];
       m_composev(p_lka, IMSG_MTA_SSL_VERIFY_CERT, 0, 0, -1,
           iov, nitems(iov));
-       free(req_ca_vrfy.cert);
-       X509_free(x);

-       if (xchain) {
-               /* Send the chain, one cert at a time */
-               for (i = 0; i < sk_X509_num(xchain); ++i) {
-                       memset(&req_ca_vrfy, 0, sizeof req_ca_vrfy);
-                       req_ca_vrfy.reqid = s->id;
-                       x = sk_X509_value(xchain, i);
-                       req_ca_vrfy.cert_len = i2d_X509(x, &req_ca_vrfy.cert);
-                       iov[0].iov_base = &req_ca_vrfy;
-                       iov[0].iov_len  = sizeof(req_ca_vrfy);
-                       iov[1].iov_base = req_ca_vrfy.cert;
-                       iov[1].iov_len  = req_ca_vrfy.cert_len;
-                       m_composev(p_lka, IMSG_MTA_SSL_VERIFY_CHAIN, 0, 0, -1,
-                           iov, nitems(iov));
-                       free(req_ca_vrfy.cert);
-               }
+       memset(&req_ca_vrfy, 0, sizeof req_ca_vrfy);
+       req_ca_vrfy.reqid = s->id;
+
+       /* Send the chain, one cert at a time */
+       for (i = 0; i < cert_count; ++i) {
+               req_ca_vrfy.cert_len = cert_len[i+1];
+               iov[1].iov_base = cert_der[i+1];
+               iov[1].iov_len  = cert_len[i+1];
+               m_composev(p_lka, IMSG_MTA_SSL_VERIFY_CHAIN, 0, 0, -1,
+                   iov, nitems(iov));
       }

       /* Tell lookup process that it can start verifying, we're done */
@@ -1572,7 +1609,13 @@ mta_verify_certificate(struct mta_sessio
       m_compose(p_lka, IMSG_MTA_SSL_VERIFY, 0, 0, -1,
           &req_ca_vrfy, sizeof req_ca_vrfy);

-       return 1;
+       res = 1;
+
+    end:
+       for (i = 0; i < MAX_CERTS; ++i)
+               free(cert_der[i]);
+
+       return res;
}

static const char *
Index: usr.sbin/smtpd/smtp_session.c
===================================================================
RCS file: /cvs/src/usr.sbin/smtpd/smtp_session.c,v
retrieving revision 1.215.4.1
diff -u -p -r1.215.4.1 smtp_session.c
--- usr.sbin/smtpd/smtp_session.c       19 Apr 2015 20:30:06 -0000      1.215.4.1
+++ usr.sbin/smtpd/smtp_session.c       1 Oct 2015 22:32:07 -0000
@@ -141,6 +141,7 @@ struct smtp_session {
       size_t                   rcptfail;
       TAILQ_HEAD(, smtp_rcpt)  rcpts;

+       size_t                   datain;
       size_t                   datalen;
       FILE                    *ofile;
       int                      hdrdone;
@@ -1564,6 +1565,13 @@ smtp_message_write(struct smtp_session *
       if (*line == '\0')
               s->hdrdone = 1;

+       /* account for newline */
+       s->datain += strlen(line) + 1;
+       if (s->datain > env->sc_maxsize) {
+               s->msgflags |= MF_ERROR_SIZE;
+               return;
+       }
+
       /* check for loops */
       if (!s->hdrdone) {
               if (strncasecmp("Received: ", line, 10) == 0)
@@ -1577,11 +1585,6 @@ smtp_message_write(struct smtp_session *

       len = strlen(line) + 1;

-       if (s->datalen + len > env->sc_maxsize) {
-               s->msgflags |= MF_ERROR_SIZE;
-               return;
-       }
-
       if (fprintf(s->ofile, "%s\n", line) != (int)len) {
               s->msgflags |= MF_ERROR_IO;
               return;
@@ -1642,6 +1645,7 @@ smtp_message_reset(struct smtp_session *
       s->msgflags = 0;
       s->destcount = 0;
       s->rcptcount = 0;
+       s->datain = 0;
       s->datalen = 0;
       s->rcvcount = 0;
       s->hdrdone = 0;
@@ -1792,12 +1796,28 @@ smtp_mailaddr(struct mailaddr *maddr, ch
static int
smtp_verify_certificate(struct smtp_session *s)
{
+#define MAX_CERTS      16
+#define MAX_CERT_LEN   (MAX_IMSGSIZE - (IMSG_HEADER_SIZE + sizeof(req_ca_vrfy)))
       struct ca_vrfy_req_msg  req_ca_vrfy;
       struct iovec            iov[2];
       X509                   *x;
       STACK_OF(X509)         *xchain;
-       int                     i;
       const char             *pkiname;
+       unsigned char          *cert_der[MAX_CERTS];
+       int                     cert_len[MAX_CERTS];
+       int                     i, cert_count, res;
+
+       res = 0;
+       memset(cert_der, 0, sizeof(cert_der));
+       memset(&req_ca_vrfy, 0, sizeof req_ca_vrfy);
+
+       if (s->listener->pki_name[0])
+               pkiname = s->listener->pki_name;
+       else
+               pkiname = s->smtpname;
+       if (strlcpy(req_ca_vrfy.pkiname, pkiname, sizeof req_ca_vrfy.pkiname)
+           >= sizeof req_ca_vrfy.pkiname)
+               return 0;

       x = SSL_get_peer_certificate(s->io.ssl);
       if (x == NULL)
@@ -1812,47 +1832,67 @@ smtp_verify_certificate(struct smtp_sess
        *
        */

-       tree_xset(&wait_ssl_verify, s->id, s);
+       cert_len[0] = i2d_X509(x, &cert_der[0]);
+       X509_free(x);

-       /* Send the client certificate */
-       memset(&req_ca_vrfy, 0, sizeof req_ca_vrfy);
-       if (s->listener->pki_name[0])
-               pkiname = s->listener->pki_name;
+       if (cert_len[0] < 0) {
+               log_warnx("warn: failed to encode certificate");
+               goto end;
+       }
+       log_debug("debug: certificate 0: len=%d", cert_len[0]);
+       if (cert_len[0] > (int)MAX_CERT_LEN) {
+               log_warnx("warn: certificate too long");
+               goto end;
+       }
+
+       if (xchain) {
+               cert_count = sk_X509_num(xchain);
+               log_debug("debug: certificate chain len: %d", cert_count);
+               if (cert_count >= MAX_CERTS) {
+                       log_warnx("warn: certificate chain too long");
+                       goto end;
+               }
+       }
       else
-               pkiname = s->smtpname;
+               cert_count = 0;

-       if (strlcpy(req_ca_vrfy.pkiname, pkiname, sizeof req_ca_vrfy.pkiname)
-           >= sizeof req_ca_vrfy.pkiname)
-               return 0;
+       for (i = 0; i < cert_count; ++i) {
+               x = sk_X509_value(xchain, i);
+               cert_len[i+1] = i2d_X509(x, &cert_der[i+1]);
+               if (cert_len[i+1] < 0) {
+                       log_warnx("warn: failed to encode certificate");
+                       goto end;
+               }
+               log_debug("debug: certificate %i: len=%d", i+1, cert_len[i+1]);
+               if (cert_len[i+1] > (int)MAX_CERT_LEN) {
+                       log_warnx("warn: certificate too long");
+                       goto end;
+               }
+       }

+       tree_xset(&wait_ssl_verify, s->id, s);
+
+       /* Send the client certificate */
       req_ca_vrfy.reqid = s->id;
-       req_ca_vrfy.cert_len = i2d_X509(x, &req_ca_vrfy.cert);
-       if (xchain)
-               req_ca_vrfy.n_chain = sk_X509_num(xchain);
+       req_ca_vrfy.cert_len = cert_len[0];
+       req_ca_vrfy.n_chain = cert_count;
       iov[0].iov_base = &req_ca_vrfy;
       iov[0].iov_len = sizeof(req_ca_vrfy);
-       iov[1].iov_base = req_ca_vrfy.cert;
-       iov[1].iov_len = req_ca_vrfy.cert_len;
+       iov[1].iov_base = cert_der[0];
+       iov[1].iov_len = cert_len[0];
       m_composev(p_lka, IMSG_SMTP_SSL_VERIFY_CERT, 0, 0, -1,
           iov, nitems(iov));
-       free(req_ca_vrfy.cert);
-       X509_free(x);

-       if (xchain) {
-               /* Send the chain, one cert at a time */
-               for (i = 0; i < sk_X509_num(xchain); ++i) {
-                       memset(&req_ca_vrfy, 0, sizeof req_ca_vrfy);
-                       req_ca_vrfy.reqid = s->id;
-                       x = sk_X509_value(xchain, i);
-                       req_ca_vrfy.cert_len = i2d_X509(x, &req_ca_vrfy.cert);
-                       iov[0].iov_base = &req_ca_vrfy;
-                       iov[0].iov_len  = sizeof(req_ca_vrfy);
-                       iov[1].iov_base = req_ca_vrfy.cert;
-                       iov[1].iov_len  = req_ca_vrfy.cert_len;
-                       m_composev(p_lka, IMSG_SMTP_SSL_VERIFY_CHAIN, 0, 0, -1,
-                           iov, nitems(iov));
-                       free(req_ca_vrfy.cert);
-               }
+       memset(&req_ca_vrfy, 0, sizeof req_ca_vrfy);
+       req_ca_vrfy.reqid = s->id;
+
+       /* Send the chain, one cert at a time */
+       for (i = 0; i < cert_count; ++i) {
+               req_ca_vrfy.cert_len = cert_len[i+1];
+               iov[1].iov_base = cert_der[i+1];
+               iov[1].iov_len  = cert_len[i+1];
+               m_composev(p_lka, IMSG_SMTP_SSL_VERIFY_CHAIN, 0, 0, -1,
+                   iov, nitems(iov));
       }

       /* Tell lookup process that it can start verifying, we're done */
@@ -1861,7 +1901,13 @@ smtp_verify_certificate(struct smtp_sess
       m_compose(p_lka, IMSG_SMTP_SSL_VERIFY, 0, 0, -1,
           &req_ca_vrfy, sizeof req_ca_vrfy);

-       return 1;
+       res = 1;
+
+    end:
+       for (i = 0; i < MAX_CERTS; ++i)
+               free(cert_der[i]);
+
+       return res;
}

static void
Index: usr.sbin/smtpd/smtpd.c
===================================================================
RCS file: /cvs/src/usr.sbin/smtpd/smtpd.c,v
retrieving revision 1.234
diff -u -p -r1.234 smtpd.c
--- usr.sbin/smtpd/smtpd.c      10 Jul 2014 15:54:55 -0000      1.234
+++ usr.sbin/smtpd/smtpd.c      1 Oct 2015 22:32:07 -0000
@@ -348,7 +348,8 @@ parent_sig_handler(int sig, short event,
                               } else
                                       asprintf(&cause, "exited okay");
                       } else
-                               fatalx("smtpd: unexpected cause of SIGCHLD");
+                               /* WIFSTOPPED or WIFCONTINUED */
+                               continue;

                       if (pid == purge_pid)
                               purge_pid = -1;
@@ -1062,19 +1063,34 @@ offline_enqueue(char *name)

       if (pid == 0) {
               char    *envp[2], *p, *tmp;
+               int      fd;
               FILE    *fp;
               size_t   len;
               arglist  args;

+               if (closefrom(STDERR_FILENO + 1) == -1)
+                       _exit(1);
+
               memset(&args, 0, sizeof(args));

-               if (lstat(path, &sb) == -1) {
-                       log_warn("warn: smtpd: lstat: %s", path);
+               if ((fd = open(path, O_RDONLY|O_NOFOLLOW|O_NONBLOCK)) == -1) {
+                       log_warn("warn: smtpd: open: %s", path);
                       _exit(1);
               }

-               if (chflags(path, 0) == -1) {
-                       log_warn("warn: smtpd: chflags: %s", path);
+               if (fstat(fd, &sb) == -1) {
+                       log_warn("warn: smtpd: fstat: %s", path);
+                       _exit(1);
+               }
+
+               if (! S_ISREG(sb.st_mode)) {
+                       log_warnx("warn: smtpd: file %s (uid %d) not regular",
+                           path, sb.st_uid);
+                       _exit(1);
+               }
+
+               if (sb.st_nlink != 1) {
+                       log_warnx("warn: smtpd: file %s is hard-link", path);
                       _exit(1);
               }

@@ -1085,19 +1101,17 @@ offline_enqueue(char *name)
                       _exit(1);
               }

-               if (! S_ISREG(sb.st_mode)) {
-                       log_warnx("warn: smtpd: file %s (uid %d) not regular",
-                           path, sb.st_uid);
+               if (fchflags(fd, 0) == -1) {
+                       log_warn("warn: smtpd: chflags: %s", path);
                       _exit(1);
               }

               if (setgroups(1, &pw->pw_gid) ||
                   setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
-                   setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) ||
-                   closefrom(STDERR_FILENO + 1) == -1)
+                   setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
                       _exit(1);

-               if ((fp = fopen(path, "r")) == NULL)
+               if ((fp = fdopen(fd, "r")) == NULL)
                       _exit(1);

               if (chdir(pw->pw_dir) == -1 && chdir("/") == -1)
@@ -1196,7 +1210,7 @@ parent_forward_open(char *username, char
       }

       do {
-               fd = open(pathname, O_RDONLY);
+               fd = open(pathname, O_RDONLY|O_NOFOLLOW|O_NONBLOCK);
       } while (fd == -1 && errno == EINTR);
       if (fd == -1) {
               if (errno == ENOENT)
@@ -1205,7 +1219,11 @@ parent_forward_open(char *username, char
                       errno = EAGAIN;
                       return -1;
               }
-               log_warn("warn: smtpd: parent_forward_open: %s", pathname);
+               if (errno == ELOOP)
+                       log_warnx("warn: smtpd: parent_forward_open: %s: "
+                           "cannot follow symbolic links", pathname);
+               else
+                       log_warn("warn: smtpd: parent_forward_open: %s", pathname);
               return -1;
       }

Index: usr.sbin/smtpd/util.c
===================================================================
RCS file: /cvs/src/usr.sbin/smtpd/util.c,v
retrieving revision 1.110
diff -u -p -r1.110 util.c
--- usr.sbin/smtpd/util.c       25 May 2014 10:55:36 -0000      1.110
+++ usr.sbin/smtpd/util.c       1 Oct 2015 22:32:07 -0000
@@ -512,9 +512,6 @@ nextsub:
       return 1;
}

-/*
- * Check file for security. Based on usr.bin/ssh/auth.c.
- */
int
secure_file(int fd, char *path, char *userdir, uid_t uid, int mayread)
{
@@ -532,7 +529,7 @@ secure_file(int fd, char *path, char *us
       /* Check the open file to avoid races. */
       if (fstat(fd, &st) < 0 ||
           !S_ISREG(st.st_mode) ||
-           (st.st_uid != 0 && st.st_uid != uid) ||
+           st.st_uid != uid ||
           (st.st_mode & (mayread ? 022 : 066)) != 0)
               return 0;