summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2021-06-04 19:42:33 +0000
committerLaurent Bercot <ska-skaware@skarnet.org>2021-06-04 19:42:33 +0000
commiteb9672690c8cd08572556b689951639d04ff7c63 (patch)
treec5d6441260669a4c2885d058df9fef6ceee589a5
parentba46cc5078517056ba58a9e751f6c71846a43c58 (diff)
downloadsmtpd-starttls-proxy-eb9672690c8cd08572556b689951639d04ff7c63.tar.xz
Change to run as a child, not a parent
-rw-r--r--doc/smtpd-starttls-proxy-io.html17
-rw-r--r--src/smtpd-starttls-proxy/smtpd-starttls-proxy-io.c203
2 files changed, 110 insertions, 110 deletions
diff --git a/doc/smtpd-starttls-proxy-io.html b/doc/smtpd-starttls-proxy-io.html
index 9f699b9..2bf20ca 100644
--- a/doc/smtpd-starttls-proxy-io.html
+++ b/doc/smtpd-starttls-proxy-io.html
@@ -18,13 +18,28 @@
<h1> The <tt>smtpd-starttls-proxy-io</tt> program </h1>
+<p>
+<tt>smtpd-starttls-proxy-io</tt> is a program that runs in front of a UCSPI-compliant
+SMTP server (such as <tt>qmail-smtpd</tt>) and extends it with STARTTLS
+capability.
+</p>
+
+<p>
+ <tt>smtpd-starttls-proxy-io</tt> provides no TLS on its own;
+instead, it expects to be run under a
+<a href="https://web.archive.org/web/20150311223933/http://www.suspectclass.com/sgifford/ucspi-tls/ucspi-tls.txt">UCSPI-TLS</a>
+server, and interfaces with it.
+</p>
+
<h2> Interface </h2>
<pre>
- smtpd-starttls-proxy-io <em>server...</em>
+ smtpd-starttls-proxy-io <em>smtpd...</em>
</pre>
<ul>
+ <li> <tt>smtpd-starttls-proxy-io</tt> spawns <em>smtpd...</em> as
+a child process. It interposes itself between
</ul>
</body>
diff --git a/src/smtpd-starttls-proxy/smtpd-starttls-proxy-io.c b/src/smtpd-starttls-proxy/smtpd-starttls-proxy-io.c
index 1e48193..950b987 100644
--- a/src/smtpd-starttls-proxy/smtpd-starttls-proxy-io.c
+++ b/src/smtpd-starttls-proxy/smtpd-starttls-proxy-io.c
@@ -2,11 +2,11 @@
#include <unistd.h>
#include <errno.h>
-#include <signal.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
+#include <skalibs/gccattributes.h>
#include <skalibs/posixplz.h>
#include <skalibs/types.h>
#include <skalibs/bytestr.h>
@@ -18,8 +18,6 @@
#include <skalibs/bufalloc.h>
#include <skalibs/error.h>
#include <skalibs/strerr2.h>
-#include <skalibs/sig.h>
-#include <skalibs/selfpipe.h>
#include <skalibs/tai.h>
#include <skalibs/djbunix.h>
#include <skalibs/iopause.h>
@@ -35,7 +33,7 @@
#define reset_timeout() tain_addsec_g(&deadline, 300000)
-static int fd_control ;
+static int fdctl ;
static int sslfds[2] ;
static int wantexec = 0 ;
@@ -53,9 +51,6 @@ static io_t io[2] =
{ .in = BUFFER_ZERO, .out = BUFALLOC_ZERO, .indata = STRALLOC_ZERO, .buf = "" }
} ;
-
- /* Server answer processing */
-
typedef int cbfunc (char const *) ;
typedef cbfunc *cbfunc_ref ;
@@ -134,8 +129,6 @@ static void process_server_line (char const *s)
if ((*cbsentinel.next->f)(s)) cbfunc_pop() ;
}
- /* Client command processing */
-
typedef int cmdfunc (char const *) ;
typedef cmdfunc *cmdfunc_ref ;
@@ -160,7 +153,7 @@ static int do_noop (char const *s)
return 0 ;
}
-static int command_forward (char const *s)
+static int do_forward (char const *s)
{
return command_enqueue(s, &answer_forward) ;
}
@@ -181,7 +174,7 @@ static int do_notls (char const *s)
{
size_t n = buffer_len(&io[0].in) ;
if (!bufalloc_puts(&io[1].out, s)) dienomem() ;
- fd_close(fd_control) ;
+ fd_close(fdctl) ;
fd_close(sslfds[1]) ;
fd_close(sslfds[0]) ;
if (n)
@@ -220,12 +213,12 @@ static cmdmap const commands[] =
{ .name = "mail", .f = &do_notls },
{ .name = "rcpt", .f = &do_badorder },
{ .name = "data", .f = &do_badorder },
- { .name = "rset", .f = &command_forward },
- { .name = "vrfy", .f = &command_forward },
- { .name = "expn", .f = &command_forward },
- { .name = "help", .f = &command_forward },
+ { .name = "rset", .f = &do_forward },
+ { .name = "vrfy", .f = &do_forward },
+ { .name = "expn", .f = &do_forward },
+ { .name = "help", .f = &do_forward },
{ .name = "noop", .f = &do_noop },
- { .name = "quit", .f = &command_forward },
+ { .name = "quit", .f = &do_forward },
{ .name = 0, .f = 0 }
} ;
@@ -247,80 +240,17 @@ static int process_client_line (char const *s)
/* Engine */
-static void handle_signals (void)
+static int child (int, int) gccattr_noreturn ;
+static int child (int fdr, int fdw)
{
- for (;;) switch (selfpipe_read())
- {
- case -1 : strerr_diefu1sys(111, "selfpipe_read()") ;
- case 0 : return ;
- case SIGCHLD : wait_reap() ; break ;
- default : break ;
- }
-}
-
-int main (int argc, char const *const *argv)
-{
- iopause_fd x[5] =
- {
- { .events = IOPAUSE_READ },
- { .fd = 0 },
- { .fd = 1 }
- } ;
+ iopause_fd x[4] = { { .fd = 0 }, { .fd = 1 }, { .fd = fdr }, { .fd = fdw } } ;
tain_t deadline ;
PROG = "smtpd-starttls-proxy-io" ;
- {
- subgetopt_t l = SUBGETOPT_ZERO ;
- for (;;)
- {
- int opt = subgetopt_r(argc, argv, "", &l) ;
- if (opt == -1) break ;
- switch (opt)
- {
- default : dieusage() ;
- }
- }
- argc -= l.ind ; argv += l.ind ;
- }
- if (!argc) dieusage() ;
-
- {
- unsigned int u ;
- char const *x = getenv("SSLCTLFD") ;
- if (!x) strerr_dienotset(100, "SSLCTLFD") ;
- if (!uint0_scan(x, &u)) strerr_dieinvalid(100, "SSLCTLFD") ;
- fd_control = u ;
- x = getenv("SSLREADFD") ;
- if (!x) strerr_dienotset(100, "SSLREADFD") ;
- if (!uint0_scan(x, &u)) strerr_dieinvalid(100, "SSLREADFD") ;
- sslfds[0] = u ;
- x = getenv("SSLWRITEFD") ;
- if (!x) strerr_dienotset(100, "SSLWRITEFD") ;
- if (!uint0_scan(x, &u)) strerr_dieinvalid(100, "SSLWRITEFD") ;
- sslfds[1] = u ;
- }
-
- if (ndelay_on(0) < 0 || ndelay_on(1) < 0)
- strerr_diefu1sys(111, "make stdin/stdout non-blocking") ;
- x[0].fd = selfpipe_init() ;
- if (x[0].fd < 0) strerr_diefu1sys(111, "selfpipe_init") ;
- if (sig_ignore(SIGPIPE) < 0) strerr_diefu1sys(111, "ignore SIGPIPE") ;
- {
- sigset_t set ;
- sigemptyset(&set) ;
- sigaddset(&set, SIGCHLD) ;
- if (selfpipe_trapset(&set) < 0) strerr_diefu1sys(111, "trap signals") ;
- }
- {
- int fd[2] = { 0, 1 } ;
- if (!child_spawn2(argv[0], argv, (char const *const *)environ, fd))
- strerr_diefu2sys(111, "spawn ", argv[0]) ;
- if (ndelay_on(fd[0]) == -1 || ndelay_on(fd[1]) == -1 || uncoe(fd[0]) == -1 || uncoe(fd[1]) == -1)
- strerr_diefu1sys(111, "set flags on server fds") ;
- buffer_init(&io[1].in, &buffer_read, fd[0], io[1].buf, BUFFER_INSIZE) ;
- bufalloc_init(&io[1].out, &fd_write, fd[1]) ;
- x[3].fd = fd[0] ; x[4].fd = fd[1] ;
- }
+ if (ndelay_on(0) < 0 || ndelay_on(1) < 0 || ndelay_on(fdr) < 0 || ndelay_on(fdw) < 0)
+ strerr_diefu1sys(111, "make fds non-blocking") ;
+ buffer_init(&io[1].in, &buffer_read, fdr, io[0].buf, BUFFER_INSIZE) ;
+ bufalloc_init(&io[1].out, &fd_write, fdw) ;
tain_now_set_stopwatch_g() ;
reset_timeout() ;
@@ -329,33 +259,31 @@ int main (int argc, char const *const *argv)
for (;;)
{
int r ;
- if (!bufalloc_len(&io[0].out) && (x[3].fd == -1 || (cbsentinel.next == &cbsentinel && wantexec))) break ;
- x[1].events = !wantexec ? IOPAUSE_READ : 0 ;
- x[2].events = bufalloc_len(&io[0].out) ? IOPAUSE_WRITE : 0 ;
- x[3].events = wantexec != 1 ? IOPAUSE_READ : 0 ;
- x[4].events = bufalloc_len(&io[1].out) ? IOPAUSE_WRITE : 0 ;
- r = iopause_g(x, 5, &deadline) ;
+ if (!bufalloc_len(&io[0].out) && (x[2].fd == -1 || (cbsentinel.next == &cbsentinel && wantexec))) break ;
+ x[0].events = !wantexec ? IOPAUSE_READ : 0 ;
+ x[1].events = bufalloc_len(&io[0].out) ? IOPAUSE_WRITE : 0 ;
+ x[2].events = wantexec != 1 ? IOPAUSE_READ : 0 ;
+ x[3].events = bufalloc_len(&io[1].out) ? IOPAUSE_WRITE : 0 ;
+ r = iopause_g(x, 4, &deadline) ;
if (r == -1) strerr_diefu1sys(111, "iopause") ;
if (!r) strerr_dief1x(99, "timed out") ;
- for (size_t i = 0 ; i < 5 ; i++) if (x[0].revents & IOPAUSE_EXCEPT) x[0].revents |= IOPAUSE_READ | IOPAUSE_WRITE ;
+ for (size_t i = 0 ; i < 4 ; i++) if (x[i].revents & IOPAUSE_EXCEPT) x[i].revents |= IOPAUSE_READ | IOPAUSE_WRITE ;
- if (x[0].revents & IOPAUSE_READ) handle_signals() ;
-
- if (x[2].events & x[2].revents & IOPAUSE_WRITE)
+ if (x[1].events & x[1].revents & IOPAUSE_WRITE)
{
reset_timeout() ;
if (!bufalloc_flush(&io[0].out) && !error_isagain(errno))
strerr_diefu1sys(111, "write to client") ;
}
- if (x[4].events & x[4].revents & IOPAUSE_WRITE)
+ if (x[3].events & x[3].revents & IOPAUSE_WRITE)
{
reset_timeout() ;
if (!bufalloc_flush(&io[1].out) && !error_isagain(errno))
strerr_diefu1sys(111, "write to server") ;
}
- if (x[3].revents & IOPAUSE_READ)
+ if (x[2].revents & IOPAUSE_READ)
{
reset_timeout() ;
for (;;)
@@ -368,8 +296,8 @@ int main (int argc, char const *const *argv)
}
if (!r)
{
- x[4].fd = -1 ;
x[3].fd = -1 ;
+ x[2].fd = -1 ;
wantexec = 0 ;
break ;
}
@@ -379,7 +307,7 @@ int main (int argc, char const *const *argv)
}
}
- if (x[1].revents & IOPAUSE_READ)
+ if (x[0].revents & IOPAUSE_READ)
{
reset_timeout() ;
for (;;)
@@ -390,7 +318,7 @@ int main (int argc, char const *const *argv)
if (error_isagain(errno)) break ;
else strerr_diefu1sys(111, "read line from client") ;
}
- if (!r) return 0 ;
+ if (!r) _exit(0) ;
if (!stralloc_0(&io[0].indata)) dienomem() ;
if (process_client_line(io[0].indata.s)) break ;
io[0].indata.len = 0 ;
@@ -398,24 +326,24 @@ int main (int argc, char const *const *argv)
}
}
- if (!wantexec) return 0 ;
+ if (!wantexec) _exit(0) ;
if (bufalloc_len(&io[1].out) && !bufalloc_timed_flush_g(&io[1].out, &deadline))
strerr_diefu1sys(111, "write to server") ;
if (wantexec >= 2)
{
int got = 0 ;
- if (fd_write(fd_control, "Y", 1) < 0)
+ if (fd_write(fdctl, "Y", 1) < 0)
strerr_diefu1sys(111, "send ucspi-tls start command") ;
- fd_shutdown(fd_control, 1) ;
+ fd_shutdown(fdctl, 1) ;
for (;;)
{
- ssize_t r = fd_read(fd_control, io[1].buf, BUFFER_INSIZE) ;
+ ssize_t r = fd_read(fdctl, io[1].buf, BUFFER_INSIZE) ;
if (r < 0) strerr_diefu1sys(111, "read handshake data") ;
if (!r) break ;
got = 1 ;
}
- if (!got) return 1 ; /* handshake failed */
- fd_close(fd_control) ;
+ if (!got) _exit(1) ; /* handshake failed */
+ fd_close(fdctl) ;
if (fd_move2(0, sslfds[0], 1, sslfds[1]) == -1)
strerr_diefu1sys(111, "move fds") ;
}
@@ -423,9 +351,66 @@ int main (int argc, char const *const *argv)
char fmtr[UINT_FMT] ;
char fmtw[UINT_FMT] ;
char const *newargv[7] = { S6_EXTBINPREFIX "s6-ioconnect", "-r", fmtr, "-w", fmtw, 0, 0 } ;
- fmtr[uint_fmt(fmtr, x[3].fd)] = 0 ;
- fmtw[uint_fmt(fmtw, x[4].fd)] = 0 ;
+ fmtr[uint_fmt(fmtr, fdr)] = 0 ;
+ fmtw[uint_fmt(fmtw, fdw)] = 0 ;
if (wantexec == 1) newargv[5] = "-01" ;
xexec(newargv) ;
}
}
+
+int main (int argc, char const *const *argv)
+{
+ int p[2][2] ;
+ PROG = "smtpd-starttls-proxy-io (parent)" ;
+ {
+ subgetopt_t l = SUBGETOPT_ZERO ;
+ for (;;)
+ {
+ int opt = subgetopt_r(argc, argv, "", &l) ;
+ if (opt == -1) break ;
+ switch (opt)
+ {
+ default : dieusage() ;
+ }
+ }
+ argc -= l.ind ; argv += l.ind ;
+ }
+ if (!argc) dieusage() ;
+
+ {
+ unsigned int u ;
+ char const *x = getenv("SSLCTLFD") ;
+ if (!x) strerr_dienotset(100, "SSLCTLFD") ;
+ if (!uint0_scan(x, &u)) strerr_dieinvalid(100, "SSLCTLFD") ;
+ fdctl = u ;
+ x = getenv("SSLREADFD") ;
+ if (!x) strerr_dienotset(100, "SSLREADFD") ;
+ if (!uint0_scan(x, &u)) strerr_dieinvalid(100, "SSLREADFD") ;
+ sslfds[0] = u ;
+ x = getenv("SSLWRITEFD") ;
+ if (!x) strerr_dienotset(100, "SSLWRITEFD") ;
+ if (!uint0_scan(x, &u)) strerr_dieinvalid(100, "SSLWRITEFD") ;
+ sslfds[1] = u ;
+ }
+
+ if (pipe(p[0]) == -1 || pipe(p[1]) == -1)
+ strerr_diefu1sys(111, "pipe") ;
+ switch (fork())
+ {
+ case -1 : strerr_diefu1sys(111, "fork") ;
+ case 0 :
+ close(p[0][1]) ;
+ close(p[1][0]) ;
+ return child(p[0][0], p[1][1]) ;
+ default : break ;
+ }
+
+ close(p[1][1]) ;
+ close(p[0][0]) ;
+ close(fdctl) ;
+ close(sslfds[1]) ;
+ close(sslfds[0]) ;
+ if (fd_move2(0, p[1][0], 1, p[0][1]) == -1)
+ strerr_diefu1sys(111, "move fds") ;
+ xexec(argv) ;
+}