diff options
author | Laurent Bercot <ska-skaware@skarnet.org> | 2021-06-04 19:42:33 +0000 |
---|---|---|
committer | Laurent Bercot <ska-skaware@skarnet.org> | 2021-06-04 19:42:33 +0000 |
commit | eb9672690c8cd08572556b689951639d04ff7c63 (patch) | |
tree | c5d6441260669a4c2885d058df9fef6ceee589a5 | |
parent | ba46cc5078517056ba58a9e751f6c71846a43c58 (diff) | |
download | smtpd-starttls-proxy-eb9672690c8cd08572556b689951639d04ff7c63.tar.gz smtpd-starttls-proxy-eb9672690c8cd08572556b689951639d04ff7c63.tar.xz smtpd-starttls-proxy-eb9672690c8cd08572556b689951639d04ff7c63.zip |
Change to run as a child, not a parent
-rw-r--r-- | doc/smtpd-starttls-proxy-io.html | 17 | ||||
-rw-r--r-- | src/smtpd-starttls-proxy/smtpd-starttls-proxy-io.c | 203 |
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) ; +} |