summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/smtpd-starttls-proxy/smtpd-starttls-proxy-io.c66
1 files changed, 40 insertions, 26 deletions
diff --git a/src/smtpd-starttls-proxy/smtpd-starttls-proxy-io.c b/src/smtpd-starttls-proxy/smtpd-starttls-proxy-io.c
index 177bc4f..1e48193 100644
--- a/src/smtpd-starttls-proxy/smtpd-starttls-proxy-io.c
+++ b/src/smtpd-starttls-proxy/smtpd-starttls-proxy-io.c
@@ -3,6 +3,8 @@
 #include <unistd.h>
 #include <errno.h>
 #include <signal.h>
+#include <string.h>
+#include <strings.h>
 #include <stdlib.h>
 
 #include <skalibs/posixplz.h>
@@ -12,6 +14,7 @@
 #include <skalibs/allreadwrite.h>
 #include <skalibs/buffer.h>
 #include <skalibs/alloc.h>
+#include <skalibs/stralloc.h>
 #include <skalibs/bufalloc.h>
 #include <skalibs/error.h>
 #include <skalibs/strerr2.h>
@@ -162,10 +165,10 @@ static int command_forward (char const *s)
   return command_enqueue(s, &answer_forward) ;
 }
 
-static int do_rcpt (char const *s)
+static int do_badorder (char const *s)
 {
   (void)s ;
-  answer_enqueue("503 MAIL first (#5.5.1)\r\n") ;
+  answer_enqueue("503 MAIL has to come first\r\n") ;
   return 0 ;
 }
 
@@ -176,10 +179,23 @@ static int do_ehlo (char const *s)
 
 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(sslfds[1]) ;
   fd_close(sslfds[0]) ;
+  if (n)
+  {
+    if (!stralloc_readyplus(&io[1].out.x, n)) dienomem() ;
+    buffer_getnofill(&io[0].in, io[1].out.x.s + io[1].out.x.len, n) ;
+    io[1].out.x.len += n ;
+  }
+  n = buffer_len(&io[1].in) ;
+  {
+    if (!stralloc_readyplus(&io[0].out.x, n)) dienomem() ;
+    buffer_getnofill(&io[1].in, io[0].out.x.s + io[0].out.x.len, n) ;
+    io[0].out.x.len += n ;
+  }
   wantexec = 1 ;
   return 1 ;
 }
@@ -198,31 +214,33 @@ static int do_starttls (char const *s)
 
 static cmdmap const commands[] =
 {
-  { .name = "noop", .f = &do_noop },
-  { .name = "help", .f = &command_forward },
-  { .name = "vrfy", .f = &command_forward },
-  { .name = "expn", .f = &command_forward },
-  { .name = "quit", .f = &command_forward },
-  { .name = "rcpt", .f = &do_rcpt },
   { .name = "ehlo", .f = &do_ehlo },
+  { .name = "starttls", .f = &do_starttls },
   { .name = "helo", .f = &do_notls },
   { .name = "mail", .f = &do_notls },
-  { .name = "starttls", .f = &do_starttls },
+  { .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 = "noop", .f = &do_noop },
+  { .name = "quit", .f = &command_forward },
   { .name = 0, .f = 0 }
 } ;
 
 static int process_client_line (char const *s)
 {
   cmdmap const *cmd = commands ;
-  for (cmdmap const *cmd = commands ; cmd->name ; cmd++)
-    if (case_starts(s, cmd->name)) break ;
-  if (cmd->name)
+  for (; cmd->name ; cmd++)
   {
     size_t len = strlen(cmd->name) ;
-    if (s[len] == ' ' || s[len] == '\r' || s[len] == '\n')
-      return (*cmd->f)(s) ;
+    if (!strncasecmp(s, cmd->name, strlen(cmd->name))
+     && (s[len] == ' ' || s[len] == '\r' || s[len] == '\n'))
+      break ;
   }
-  answer_enqueue("502 unimplemented (#5.5.1)\r\n") ;
+  if (cmd->name) return (*cmd->f)(s) ;
+  answer_enqueue("500 SMTP mother!@#$er, do you speak it\r\n") ;
   return 0 ;
 }
 
@@ -246,8 +264,7 @@ int main (int argc, char const *const *argv)
   {
     { .events = IOPAUSE_READ },
     { .fd = 0 },
-    { .fd = 1 },
-    { .events = IOPAUSE_READ }
+    { .fd = 1 }
   } ;
   tain_t deadline ;
   PROG = "smtpd-starttls-proxy-io" ;
@@ -297,8 +314,8 @@ int main (int argc, char const *const *argv)
     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)
-      strerr_diefu1sys(111, "make server fds non-blocking") ;
+    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] ;
@@ -313,8 +330,9 @@ int main (int argc, char const *const *argv)
   {
     int r ;
     if (!bufalloc_len(&io[0].out) && (x[3].fd == -1 || (cbsentinel.next == &cbsentinel && wantexec))) break ;
-    x[1].events = wantexec ? 0 : IOPAUSE_READ ;
+    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 (r == -1) strerr_diefu1sys(111, "iopause") ;
@@ -381,6 +399,8 @@ int main (int argc, char const *const *argv)
   }
 
   if (!wantexec) return 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 ;
@@ -399,12 +419,6 @@ int main (int argc, char const *const *argv)
     if (fd_move2(0, sslfds[0], 1, sslfds[1]) == -1)
       strerr_diefu1sys(111, "move fds") ;
   }
-  else if (io[0].indata.len)
-  {
-    if (!bufalloc_puts(&io[1].out, io[0].indata.s)) dienomem() ;
-    io[0].indata.len = 0 ;
-    if (!bufalloc_timed_flush_g(&io[1].out, &deadline)) strerr_dief1x(99, "timed out") ;
-  }
   {
     char fmtr[UINT_FMT] ;
     char fmtw[UINT_FMT] ;