aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGilles Chehade <gilles@poolp.org>2017-05-25 22:39:49 +0200
committerGilles Chehade <gilles@poolp.org>2017-05-25 22:39:49 +0200
commite593619db65f91623a313f2f6d9a2f4126f1ccd2 (patch)
tree4ef12321fccc75d1a4ca7ba48b796f6dcfbbad76
parentsync with OpenBSD: (diff)
downloadOpenSMTPD-e593619db65f91623a313f2f6d9a2f4126f1ccd2.tar.xz
OpenSMTPD-e593619db65f91623a313f2f6d9a2f4126f1ccd2.zip
sync with OpenBSD:
- do not build mail/ subdirectory for upcoming MDA refactor - replace explicit_bzero()+free() with freezero() - remove some if (NULL) tests when block function handles NULL - malloc() -> calloc() and realloc() -> recallocarray() - log_warn() should use LOG_ERR not LOG_CRIT - improve allocation construct in mproc.c - fix possible fatal() in a corner SMTPS case - unplug filters - introduce smtpf_session - improve various man pages - fix purge_task() to correctly purge old messages/envelopes - disallow SSL client renegotiation - in table_dump_lookup() display ??? when unknown lookup kind
-rw-r--r--smtpd/mail.file.840
-rw-r--r--smtpd/mail.file.c109
-rw-r--r--smtpd/mail.lmtp.855
-rw-r--r--smtpd/mail.lmtp.c293
-rw-r--r--smtpd/mail.maildir.840
-rw-r--r--smtpd/mail.maildir.c177
-rw-r--r--smtpd/mail/Makefile9
-rw-r--r--smtpd/mail/mail.file/Makefile21
-rw-r--r--smtpd/mail/mail.lmtp/Makefile21
-rw-r--r--smtpd/mail/mail.maildir/Makefile21
-rw-r--r--smtpd/smtpf_session.c58
11 files changed, 844 insertions, 0 deletions
diff --git a/smtpd/mail.file.8 b/smtpd/mail.file.8
new file mode 100644
index 00000000..2cafb861
--- /dev/null
+++ b/smtpd/mail.file.8
@@ -0,0 +1,40 @@
+.\" $OpenBSD: mail.file.8,v 1.2 2017/02/14 20:36:41 gilles Exp $
+.\"
+.\" Copyright (c) 2017 Gilles Chehade <gilles@poolp.org>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd $Mdocdate: February 14 2017 $
+.Dt MAIL.FILE 8
+.Os
+.Sh NAME
+.Nm mail.file
+.Nd deliver mail to file
+.Sh SYNOPSIS
+.Nm mail.file
+.Ar filename
+.Sh DESCRIPTION
+.Nm
+reads the standard input up to an end-of-file and appends content
+to destination filename.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Ar filename
+Mandatory destination file where content will be appended.
+.El
+.Sh EXIT STATUS
+.Ex -std mail.file
+.Sh SEE ALSO
+.Xr mail 1 ,
+.Xr smtpd 8
diff --git a/smtpd/mail.file.c b/smtpd/mail.file.c
new file mode 100644
index 00000000..cd9fd88f
--- /dev/null
+++ b/smtpd/mail.file.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2017 Gilles Chehade <gilles@poolp.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static void file_engine(const char *);
+
+int
+main(int argc, char *argv[])
+{
+ int ch;
+
+ while ((ch = getopt(argc, argv, "")) != -1) {
+ switch (ch) {
+ default:
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc == 0)
+ errx(1, "mail.file: filename required");
+
+ if (argc > 1)
+ errx(1, "mail.file: only one filename is supported");
+
+ file_engine(argv[0]);
+
+ return (0);
+}
+
+static void
+file_engine(const char *filename)
+{
+ int fd;
+ FILE *fp;
+ char *line = NULL;
+ size_t linesize = 0;
+ ssize_t linelen;
+ int n;
+ struct stat sb;
+ int escaped = 0;
+
+ fd = open(filename, O_CREAT | O_APPEND | O_WRONLY, 0600);
+ if (fd < 0)
+ err(1, NULL);
+ if (fstat(fd, &sb) < 0)
+ err(1, NULL);
+ if (S_ISREG(sb.st_mode) && flock(fd, LOCK_EX) < 0)
+ err(1, NULL);
+
+ if ((fp = fdopen(fd, "a")) == NULL)
+ err(1, NULL);
+
+ while ((linelen = getline(&line, &linesize, stdin)) != -1) {
+ line[strcspn(line, "\n")] = '\0';
+ if (strncasecmp(line, "From ", 5) == 0) {
+ if (!escaped)
+ escaped = 1;
+ else
+ fprintf(fp, ">");
+ }
+ fprintf(fp, "%s\n", line);
+ }
+ free(line);
+ if (ferror(stdin))
+ goto truncate;
+
+ if (fflush(fp) == -1)
+ if (errno != EINVAL)
+ goto truncate;
+
+ if (fclose(fp) == EOF)
+ goto truncate;
+
+ exit(0);
+
+truncate:
+ n = errno;
+ ftruncate(fd, sb.st_size);
+ errno = n;
+ err(1, NULL);
+}
diff --git a/smtpd/mail.lmtp.8 b/smtpd/mail.lmtp.8
new file mode 100644
index 00000000..98dee00d
--- /dev/null
+++ b/smtpd/mail.lmtp.8
@@ -0,0 +1,55 @@
+.\" $OpenBSD: mail.lmtp.8,v 1.1 2017/02/14 15:16:34 gilles Exp $
+.\"
+.\" Copyright (c) 2017 Gilles Chehade <gilles@poolp.org>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd $Mdocdate: February 14 2017 $
+.Dt MAIL.LMTP 8
+.Os
+.Sh NAME
+.Nm mail.lmtp
+.Nd deliver mail through LMTP
+.Sh SYNOPSIS
+.Nm mail.lmtp
+.Op Fl d Ar destination
+.Op Fl f Ar from
+.Op Fl l Ar lhlo
+.Ar user ...
+.Sh DESCRIPTION
+.Nm
+reads the standard input up to an end-of-file and delivers it to
+an LMTP server for each
+.Ar user Ns 's
+address.
+The
+.Ar user
+must be a valid user name or email address.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl d Ar destination
+Specify the destination LMTP address.
+.It Fl f Ar from
+Specify the sender's name or email address.
+.It Fl l Ar lhlo
+Specify the LHLO argument used in the LMTP session.
+By default,
+.Nm mail.lmtp
+will default to "localhost".
+.El
+.Sh EXIT STATUS
+.Ex -std mail.lmtp
+.Sh SEE ALSO
+.Xr mail 1 ,
+.Xr smtpd 8
diff --git a/smtpd/mail.lmtp.c b/smtpd/mail.lmtp.c
new file mode 100644
index 00000000..55faa331
--- /dev/null
+++ b/smtpd/mail.lmtp.c
@@ -0,0 +1,293 @@
+/*
+ * Copyright (c) 2017 Gilles Chehade <gilles@poolp.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+enum phase {
+ PHASE_BANNER,
+ PHASE_HELO,
+ PHASE_MAILFROM,
+ PHASE_RCPTTO,
+ PHASE_DATA,
+ PHASE_EOM,
+ PHASE_QUIT
+};
+
+struct session {
+ const char *lhlo;
+ const char *mailfrom;
+
+ char **rcpts;
+ int n_rcpts;
+};
+
+static FILE *lmtp_connect(const char *);
+static void lmtp_engine(FILE *, struct session *);
+static void stream_file(FILE *);
+
+int
+main(int argc, char *argv[])
+{
+ int ch;
+ FILE *conn;
+ const char *destination = "inet:localhost";
+ struct session session;
+
+ session.lhlo = "localhost";
+ session.mailfrom = NULL;
+
+ while ((ch = getopt(argc, argv, "d:l:f:")) != -1) {
+ switch (ch) {
+ case 'd':
+ destination = optarg;
+ break;
+ case 'l':
+ session.lhlo = optarg;
+ break;
+ case 'f':
+ session.mailfrom = optarg;
+ break;
+ default:
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (session.mailfrom == NULL)
+ errx(1, "sender must be specified with -f");
+
+ if (argc == 0)
+ errx(1, "no recipient was specified");
+
+ session.rcpts = argv;
+ session.n_rcpts = argc;
+
+ conn = lmtp_connect(destination);
+ lmtp_engine(conn, &session);
+
+ return (0);
+}
+
+static FILE *
+lmtp_connect_inet(const char *destination)
+{
+ struct addrinfo hints, *res, *res0;
+ char *destcopy = NULL;
+ const char *hostname = NULL;
+ const char *servname = NULL;
+ const char *cause = NULL;
+ char *p;
+ int n, s = -1, save_errno;
+
+ if ((destcopy = strdup(destination)) == NULL)
+ err(1, NULL);
+
+ servname = "25";
+ hostname = destcopy;
+ p = destcopy;
+ if (*p == '[') {
+ if ((p = strchr(destcopy, ']')) == NULL)
+ errx(1, "inet: invalid address syntax");
+
+ /* remove [ and ] */
+ *p = '\0';
+ hostname++;
+ if (strncasecmp(hostname, "IPv6:", 5) == 0)
+ hostname += 5;
+
+ /* extract port if any */
+ switch (*(p+1)) {
+ case ':':
+ servname = p+2;
+ break;
+ case '\0':
+ break;
+ default:
+ errx(1, "inet: invalid address syntax");
+ }
+ }
+ else if ((p = strchr(destcopy, ':')) != NULL) {
+ *p++ = '\0';
+ servname = p;
+ }
+
+ memset(&hints, 0, sizeof hints);
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_NUMERICSERV;
+ n = getaddrinfo(hostname, servname, &hints, &res0);
+ if (n)
+ errx(1, "inet: %s", gai_strerror(n));
+
+ for (res = res0; res; res = res->ai_next) {
+ s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+ if (s == -1) {
+ cause = "socket";
+ continue;
+ }
+
+ if (connect(s, res->ai_addr, res->ai_addrlen) == -1) {
+ cause = "connect";
+ save_errno = errno;
+ close(s);
+ errno = save_errno;
+ s = -1;
+ continue;
+ }
+ break;
+ }
+
+ freeaddrinfo(res0);
+ if (s == -1)
+ errx(1, "%s", cause);
+
+ return fdopen(s, "r+");
+}
+
+static FILE *
+lmtp_connect_unix(const char *destination)
+{
+ struct sockaddr_un addr;
+ int s;
+
+ if (*destination != '/')
+ errx(1, "unix: path must be absolute");
+
+ if ((s = socket(PF_LOCAL, SOCK_STREAM, 0)) == -1)
+ err(1, NULL);
+
+ memset(&addr, 0, sizeof addr);
+ addr.sun_family = AF_UNIX;
+ if (strlcpy(addr.sun_path, destination, sizeof addr.sun_path)
+ >= sizeof addr.sun_path)
+ errx(1, "unix: socket path is too long");
+
+ if (connect(s, (struct sockaddr *)&addr, sizeof addr) == -1)
+ err(1, "connect");
+
+ return fdopen(s, "r+");
+}
+
+static FILE *
+lmtp_connect(const char *destination)
+{
+ if (strncasecmp(destination, "unix:", 5) == 0)
+ return lmtp_connect_unix(destination + 5);
+ if (strncasecmp(destination, "inet:", 5) == 0)
+ return lmtp_connect_inet(destination + 5);
+ errx(1, "invalid destination address, must start with 'unix:' or 'inet:'");
+}
+
+static void
+lmtp_engine(FILE *conn, struct session *session)
+{
+ char *line = NULL;
+ size_t linesize = 0;
+ ssize_t linelen;
+ enum phase phase = PHASE_BANNER;
+
+ do {
+ if ((linelen = getline(&line, &linesize, conn)) == -1)
+ err(1, "getline");
+ line[strcspn(line, "\n")] = '\0';
+
+ if (linelen < 4 ||
+ !isdigit(line[0]) ||
+ !isdigit(line[1]) ||
+ !isdigit(line[2]) ||
+ (line[3] != ' ' && line[3] != '-'))
+ errx(1, "LMTP server sent an invalid line");
+
+ if (line[0] != (phase == PHASE_DATA ? '3' : '2'))
+ errx(1, "LMTP server error: %s", line);
+
+ if (line[3] == '-')
+ continue;
+
+ switch (phase) {
+
+ case PHASE_BANNER:
+ fprintf(conn, "LHLO %s\r\n", session->lhlo);
+ phase++;
+ break;
+
+ case PHASE_HELO:
+ fprintf(conn, "MAIL FROM:<%s>\r\n", session->mailfrom);
+ phase++;
+ break;
+
+ case PHASE_MAILFROM:
+ fprintf(conn, "RCPT TO:<%s>\r\n", session->rcpts[session->n_rcpts - 1]);
+ if (session->n_rcpts - 1 == 0) {
+ phase++;
+ break;
+ }
+ session->n_rcpts--;
+ break;
+
+ case PHASE_RCPTTO:
+ fprintf(conn, "DATA\r\n");
+ phase++;
+ break;
+
+ case PHASE_DATA:
+ stream_file(conn);
+ fprintf(conn, ".\r\n");
+ phase++;
+ break;
+
+ case PHASE_EOM:
+ fprintf(conn, "QUIT\r\n");
+ phase++;
+ break;
+
+ case PHASE_QUIT:
+ exit(0);
+ }
+ if (ferror(stdin))
+ err(1, "getline");
+ } while (1);
+}
+
+static void
+stream_file(FILE *conn)
+{
+ char *line = NULL;
+ size_t linesize = 0;
+ ssize_t linelen;
+
+ while ((linelen = getline(&line, &linesize, stdin)) != -1) {
+ line[strcspn(line, "\n")] = '\0';
+ if (strcmp(line, ".") == 0)
+ fprintf(conn, ".");
+ fprintf(conn, "%s\r\n", line);
+ }
+ free(line);
+ if (ferror(stdin))
+ err(1, "getline");
+}
diff --git a/smtpd/mail.maildir.8 b/smtpd/mail.maildir.8
new file mode 100644
index 00000000..45f60f53
--- /dev/null
+++ b/smtpd/mail.maildir.8
@@ -0,0 +1,40 @@
+.\" $OpenBSD: mail.maildir.8,v 1.1 2017/02/14 16:48:30 gilles Exp $
+.\"
+.\" Copyright (c) 2017 Gilles Chehade <gilles@poolp.org>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd $Mdocdate: February 14 2017 $
+.Dt MAIL.MAILDIR 8
+.Os
+.Sh NAME
+.Nm mail.maildir
+.Nd store mail in a maildir
+.Sh SYNOPSIS
+.Nm mail.maildir
+.Op Fl d Ar maildir
+.Sh DESCRIPTION
+.Nm
+reads the standard input up to an end-of-file and adds it to the
+provided mail directory.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl d Ar maildir
+Specify the path to user mail directory.
+.El
+.Sh EXIT STATUS
+.Ex -std mail.maildir
+.Sh SEE ALSO
+.Xr mail 1 ,
+.Xr smtpd 8
diff --git a/smtpd/mail.maildir.c b/smtpd/mail.maildir.c
new file mode 100644
index 00000000..effbc49a
--- /dev/null
+++ b/smtpd/mail.maildir.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2017 Gilles Chehade <gilles@poolp.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static void maildir_engine(const char *);
+static int mkdirs_component(const char *, mode_t);
+static int mkdirs(const char *, mode_t);
+
+int
+main(int argc, char *argv[])
+{
+ int ch;
+ char *dirname = NULL;
+
+ while ((ch = getopt(argc, argv, "d:")) != -1) {
+ switch (ch) {
+ case 'd':
+ dirname = optarg;
+ break;
+ default:
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (dirname == NULL) {
+ exit(1);
+ }
+
+ maildir_engine(dirname);
+
+ return (0);
+}
+
+static void
+maildir_engine(const char *dirname)
+{
+ char tmp[PATH_MAX];
+ char new[PATH_MAX];
+ int fd;
+ FILE *fp;
+ char *line = NULL;
+ size_t linesize = 0;
+ ssize_t linelen;
+
+ if (mkdirs(dirname, 0700) < 0 && errno != EEXIST)
+ err(1, NULL);
+
+ if (chdir(dirname) < 0)
+ err(1, NULL);
+
+ if (mkdir("cur", 0700) < 0 && errno != EEXIST)
+ err(1, NULL);
+ if (mkdir("tmp", 0700) < 0 && errno != EEXIST)
+ err(1, NULL);
+ if (mkdir("new", 0700) < 0 && errno != EEXIST)
+ err(1, NULL);
+
+ (void)snprintf(tmp, sizeof tmp, "tmp/%lld.%08x.%s",
+ (long long int) time(NULL),
+ arc4random(),
+ "localhost");
+
+ fd = open(tmp, O_CREAT | O_EXCL | O_WRONLY, 0600);
+ if (fd < 0)
+ err(1, NULL);
+ if ((fp = fdopen(fd, "w")) == NULL)
+ err(1, NULL);
+
+ while ((linelen = getline(&line, &linesize, stdin)) != -1) {
+ line[strcspn(line, "\n")] = '\0';
+ fprintf(fp, "%s\n", line);
+ }
+ free(line);
+ if (ferror(stdin))
+ err(1, NULL);
+
+
+ if (fflush(fp) == EOF ||
+ ferror(fp) ||
+ fsync(fd) < 0 ||
+ fclose(fp) == EOF)
+ err(1, NULL);
+
+ (void)snprintf(new, sizeof new, "new/%s", tmp + 4);
+ if (rename(tmp, new) < 0)
+ err(1, NULL);
+
+ exit(0);
+}
+
+
+static int
+mkdirs_component(const char *path, mode_t mode)
+{
+ struct stat sb;
+
+ if (stat(path, &sb) == -1) {
+ if (errno != ENOENT)
+ return 0;
+ if (mkdir(path, mode | S_IWUSR | S_IXUSR) == -1)
+ return 0;
+ }
+ else if (!S_ISDIR(sb.st_mode))
+ return 0;
+
+ return 1;
+}
+
+static int
+mkdirs(const char *path, mode_t mode)
+{
+ char buf[PATH_MAX];
+ int i = 0;
+ int done = 0;
+ const char *p;
+
+ /* absolute path required */
+ if (*path != '/')
+ return 0;
+
+ /* make sure we don't exceed PATH_MAX */
+ if (strlen(path) >= sizeof buf)
+ return 0;
+
+ memset(buf, 0, sizeof buf);
+ for (p = path; *p; p++) {
+ if (*p == '/') {
+ if (buf[0] != '\0')
+ if (!mkdirs_component(buf, mode))
+ return 0;
+ while (*p == '/')
+ p++;
+ buf[i++] = '/';
+ buf[i++] = *p;
+ if (*p == '\0' && ++done)
+ break;
+ continue;
+ }
+ buf[i++] = *p;
+ }
+ if (!done)
+ if (!mkdirs_component(buf, mode))
+ return 0;
+
+ if (chmod(path, mode) == -1)
+ return 0;
+
+ return 1;
+}
diff --git a/smtpd/mail/Makefile b/smtpd/mail/Makefile
new file mode 100644
index 00000000..e83da451
--- /dev/null
+++ b/smtpd/mail/Makefile
@@ -0,0 +1,9 @@
+# $OpenBSD: Makefile,v 1.3 2017/02/14 16:48:30 gilles Exp $
+
+.include <bsd.own.mk>
+
+SUBDIR = mail.lmtp
+SUBDIR+= mail.file
+SUBDIR+= mail.maildir
+
+.include <bsd.subdir.mk>
diff --git a/smtpd/mail/mail.file/Makefile b/smtpd/mail/mail.file/Makefile
new file mode 100644
index 00000000..e2996b89
--- /dev/null
+++ b/smtpd/mail/mail.file/Makefile
@@ -0,0 +1,21 @@
+.PATH: ${.CURDIR}/../..
+
+PROG= mail.file
+BINOWN= root
+BINGRP= wheel
+
+BINMODE?=0555
+
+BINDIR= /usr/libexec
+MAN= mail.file.8
+
+CFLAGS+= -fstack-protector-all
+CFLAGS+= -Wall -Wstrict-prototypes -Wmissing-prototypes
+CFLAGS+= -Wmissing-declarations
+CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual
+CFLAGS+= -Wsign-compare
+CFLAGS+= -Werror-implicit-function-declaration
+
+SRCS= mail.file.c
+
+.include <bsd.prog.mk>
diff --git a/smtpd/mail/mail.lmtp/Makefile b/smtpd/mail/mail.lmtp/Makefile
new file mode 100644
index 00000000..5900b708
--- /dev/null
+++ b/smtpd/mail/mail.lmtp/Makefile
@@ -0,0 +1,21 @@
+.PATH: ${.CURDIR}/../..
+
+PROG= mail.lmtp
+BINOWN= root
+BINGRP= wheel
+
+BINMODE?=0555
+
+BINDIR= /usr/libexec
+MAN= mail.lmtp.8
+
+CFLAGS+= -fstack-protector-all
+CFLAGS+= -Wall -Wstrict-prototypes -Wmissing-prototypes
+CFLAGS+= -Wmissing-declarations
+CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual
+CFLAGS+= -Wsign-compare
+CFLAGS+= -Werror-implicit-function-declaration
+
+SRCS= mail.lmtp.c
+
+.include <bsd.prog.mk>
diff --git a/smtpd/mail/mail.maildir/Makefile b/smtpd/mail/mail.maildir/Makefile
new file mode 100644
index 00000000..a728ad4f
--- /dev/null
+++ b/smtpd/mail/mail.maildir/Makefile
@@ -0,0 +1,21 @@
+.PATH: ${.CURDIR}/../..
+
+PROG= mail.maildir
+BINOWN= root
+BINGRP= wheel
+
+BINMODE?=0555
+
+BINDIR= /usr/libexec
+MAN= mail.maildir.8
+
+CFLAGS+= -fstack-protector-all
+CFLAGS+= -Wall -Wstrict-prototypes -Wmissing-prototypes
+CFLAGS+= -Wmissing-declarations
+CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual
+CFLAGS+= -Wsign-compare
+CFLAGS+= -Werror-implicit-function-declaration
+
+SRCS= mail.maildir.c
+
+.include <bsd.prog.mk>
diff --git a/smtpd/smtpf_session.c b/smtpd/smtpf_session.c
new file mode 100644
index 00000000..4b3cc6b0
--- /dev/null
+++ b/smtpd/smtpf_session.c
@@ -0,0 +1,58 @@
+/* $OpenBSD: smtpf_session.c,v 1.1 2017/05/22 13:40:54 gilles Exp $ */
+
+/*
+ * Copyright (c) 2017 Gilles Chehade <gilles@poolp.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/tree.h>
+#include <sys/socket.h>
+
+#include <errno.h>
+#include <imsg.h>
+#include <limits.h>
+#include <openssl/ssl.h>
+
+#include "smtpd.h"
+#include "log.h"
+
+static void smtpf_session_init(void);
+
+static void
+smtpf_session_init(void)
+{
+ static int init = 0;
+
+ if (!init)
+ init = 1;
+}
+
+int
+smtpf_session(struct listener *listener, int sock,
+ const struct sockaddr_storage *ss, const char *hostname)
+{
+ log_debug("debug: smtpf: new client on listener: %p", listener);
+
+ smtpf_session_init();
+
+ errno = EOPNOTSUPP;
+ return (-1);
+}
+
+void
+smtpf_session_imsg(struct mproc *p, struct imsg *imsg)
+{
+}