about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/smtpd-starttls-proxy/smtpd-starttls-proxy-io.c41
1 files changed, 27 insertions, 14 deletions
diff --git a/src/smtpd-starttls-proxy/smtpd-starttls-proxy-io.c b/src/smtpd-starttls-proxy/smtpd-starttls-proxy-io.c
index a22d997..c802686 100644
--- a/src/smtpd-starttls-proxy/smtpd-starttls-proxy-io.c
+++ b/src/smtpd-starttls-proxy/smtpd-starttls-proxy-io.c
@@ -86,28 +86,38 @@ static inline void cbfunc_pop (void)
   alloc_free(node) ;
 }
 
-static inline void transfer_to_client (char const *s)
+static inline void answer_enqueue (char const *s)
 {
   if (!bufalloc_puts(&io[0].out, s)) dienomem() ;
 }
 
 static int answer_forward (char const *s)
 {
-  transfer_to_client(s) ;
+  answer_enqueue(s) ;
   return 1 ;
 }
 
 static int answer_ehlo (char const *s)
 {
-  transfer_to_client(s) ;
-  if (s[0] == '2' && case_starts(s+4, "starttls"))
+  static int needed = 1 ;
+  if (needed && s[0] == '2' && case_starts(s+4, "starttls"))
+  {
+    needed = 0 ;
     strerr_warni1x("server seems to support STARTTLS natively") ;
+  }
+  if (needed && s[3] == ' ') answer_enqueue("250-STARTTLS\r\n") ;
+  answer_enqueue(s) ;
   return s[3] == ' ' ;
 }
 
 static int trigger_starttls (char const *s)
 {
-  if (s[0] != '2') strerr_diefu2x(111, "STARTTLS: RSET failed, server answered: ", s) ;
+  if (s[0] != '2')
+  {
+    answer_enqueue("454 Server failed to reset\r\n") ;
+    wantexec = 0 ;
+  }
+  else answer_enqueue("220 Ready to start TLS\r\n") ;
   return 1 ;
 }
 
@@ -140,11 +150,6 @@ static int command_enqueue (char const *s, cbfunc_ref f)
   return 0 ;
 }
 
-static void answer_enqueue (char const *s)
-{
-  if (!bufalloc_puts(&io[0].out, s)) dienomem() ;
-}
-
 static int do_noop (char const *s)
 {
   (void)s ;
@@ -181,8 +186,13 @@ static int do_notls (char const *s)
 
 static int do_starttls (char const *s)
 {
-  command_enqueue("RSET\r\n", &trigger_starttls) ;
-  wantexec = 2 ;
+  if (buffer_len(&io[0].in))
+    answer_enqueue("503 STARTTLS must be the last command in a group\r\n") ;
+  else
+  {
+    command_enqueue("RSET\r\n", &trigger_starttls) ;
+    wantexec = 2 ;
+  }
   return 0 ;
 }
 
@@ -372,20 +382,23 @@ int main (int argc, char const *const *argv)
   if (!wantexec) return 0 ;
   if (wantexec >= 2)
   {
+    int got = 0 ;
     if (fd_write(fd_control, "Y", 1) < 0)
       strerr_diefu1sys(111, "send ucspi-tls start command") ;
     fd_shutdown(fd_control, 1) ;
     for (;;)
     {
       ssize_t r = fd_read(fd_control, io[1].buf, BUFFER_INSIZE) ;
-      if (r < 0) strerr_diefu1sys(111, "read handshake environment") ;
+      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 (fd_move2(0, sslfds[0], 1, sslfds[1]) == -1)
       strerr_diefu1sys(111, "move fds") ;
   }
-  if (io[0].indata.len)
+  else if (io[0].indata.len)
   {
     if (!bufalloc_puts(&io[1].out, io[0].indata.s)) dienomem() ;
     io[0].indata.len = 0 ;