about summary refs log tree commit diff
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.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.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) ;
+}