simplify the smtp_command() function by splitting cmd handlers into
authorgilles <gilles@openbsd.org>
Mon, 3 Sep 2018 19:01:29 +0000 (19:01 +0000)
committergilles <gilles@openbsd.org>
Mon, 3 Sep 2018 19:01:29 +0000 (19:01 +0000)
two sets of functions smtp_check_<verb> and smtp_proceed_<verb>. we
use the check functions to validate that verb is acceptable at this
point of a session and proceed to actually move the session forward

ok eric@

usr.sbin/smtpd/smtp_session.c

index d7c8346..64323ea 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: smtp_session.c,v 1.336 2018/09/03 17:41:55 gilles Exp $       */
+/*     $OpenBSD: smtp_session.c,v 1.337 2018/09/03 19:01:29 gilles Exp $       */
 
 /*
  * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org>
@@ -190,6 +190,27 @@ static void smtp_message_fd(struct smtp_tx *, int);
 static void smtp_message_end(struct smtp_tx *);
 static int  smtp_message_printf(struct smtp_tx *, const char *, ...);
 
+static int  smtp_check_rset(struct smtp_session *);
+static int  smtp_check_helo(struct smtp_session *, int, const char *);
+static int  smtp_check_auth(struct smtp_session *s, const char *);
+static int  smtp_check_starttls(struct smtp_session *, const char *);
+static int  smtp_check_mail_from(struct smtp_session *);
+static int  smtp_check_rcpt_to(struct smtp_session *);
+static int  smtp_check_data(struct smtp_session *);
+
+static void smtp_proceed_rset(struct smtp_session *);
+static void smtp_proceed_helo(struct smtp_session *, int, char *);
+static void smtp_proceed_auth(struct smtp_session *, char *);
+static void smtp_proceed_starttls(struct smtp_session *);
+static void smtp_proceed_mail_from(struct smtp_session *, char *);
+static void smtp_proceed_rcpt_to(struct smtp_session *, char *);
+static void smtp_proceed_data(struct smtp_session *);
+static void smtp_proceed_noop(struct smtp_session *);
+static void smtp_proceed_help(struct smtp_session *);
+static void smtp_proceed_wiz(struct smtp_session *);
+static void smtp_proceed_quit(struct smtp_session *);
+
+
 static struct { int code; const char *cmd; } commands[] = {
        { CMD_HELO,             "HELO" },
        { CMD_EHLO,             "EHLO" },
@@ -1013,7 +1034,7 @@ smtp_io(struct io *io, int evt, void *arg)
 static void
 smtp_command(struct smtp_session *s, char *line)
 {
-       char                           *args, *eom, *method;
+       char                           *args;
        int                             cmd, i;
 
        log_trace(TRACE_SMTP, "smtp: %p: <<< %s", s, line);
@@ -1059,255 +1080,69 @@ smtp_command(struct smtp_session *s, char *line)
         */
        case CMD_HELO:
        case CMD_EHLO:
-               if (s->helo[0]) {
-                       smtp_reply(s, "503 %s %s: Already identified",
-                           esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
-                           esc_description(ESC_INVALID_COMMAND));
-                       break;
-               }
-
-               if (args == NULL) {
-                       smtp_reply(s, "501 %s %s: %s requires domain name",
-                           esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
-                           esc_description(ESC_INVALID_COMMAND),
-                           (cmd == CMD_HELO) ? "HELO" : "EHLO");
-
+               if (!smtp_check_helo(s, cmd, args))
                        break;
-               }
-
-               if (!valid_domainpart(args)) {
-                       smtp_reply(s, "501 %s %s: Invalid domain name",
-                           esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND_ARGUMENTS),
-                           esc_description(ESC_INVALID_COMMAND_ARGUMENTS));
-                       break;
-               }
-               (void)strlcpy(s->helo, args, sizeof(s->helo));
-               s->flags &= SF_SECURE | SF_AUTHENTICATED | SF_VERIFIED;
-               if (cmd == CMD_EHLO) {
-                       s->flags |= SF_EHLO;
-                       s->flags |= SF_8BITMIME;
-               }
-
-               smtp_enter_state(s, STATE_HELO);
-               smtp_reply(s, "250%c%s Hello %s [%s], pleased to meet you",
-                   (s->flags & SF_EHLO) ? '-' : ' ',
-                   s->smtpname,
-                   s->helo,
-                   ss_to_text(&s->ss));
-
-               if (s->flags & SF_EHLO) {
-                       smtp_reply(s, "250-8BITMIME");
-                       smtp_reply(s, "250-ENHANCEDSTATUSCODES");
-                       smtp_reply(s, "250-SIZE %zu", env->sc_maxsize);
-                       if (ADVERTISE_EXT_DSN(s))
-                               smtp_reply(s, "250-DSN");
-                       if (ADVERTISE_TLS(s))
-                               smtp_reply(s, "250-STARTTLS");
-                       if (ADVERTISE_AUTH(s))
-                               smtp_reply(s, "250-AUTH PLAIN LOGIN");
-                       smtp_reply(s, "250 HELP");
-               }
+               smtp_proceed_helo(s, cmd, args);
                break;
        /*
         * SETUP
         */
        case CMD_STARTTLS:
-               if (s->helo[0] == '\0' || s->tx) {
-                       smtp_reply(s, "503 %s %s: Command not allowed at this point.",
-                           esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
-                           esc_description(ESC_INVALID_COMMAND));
-                       break;
-               }
-
-               if (!(s->listener->flags & F_STARTTLS)) {
-                       smtp_reply(s, "503 %s %s: Command not supported",
-                           esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
-                           esc_description(ESC_INVALID_COMMAND));
-                       break;
-               }
-
-               if (s->flags & SF_SECURE) {
-                       smtp_reply(s, "503 %s %s: Channel already secured",
-                           esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
-                           esc_description(ESC_INVALID_COMMAND));
+               if (!smtp_check_starttls(s, args))
                        break;
-               }
-               if (args != NULL) {
-                       smtp_reply(s, "501 %s %s: No parameters allowed",
-                           esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND_ARGUMENTS),
-                           esc_description(ESC_INVALID_COMMAND_ARGUMENTS));
-                       break;
-               }
-               smtp_reply(s, "220 %s: Ready to start TLS",
-                   esc_code(ESC_STATUS_OK, ESC_OTHER_STATUS));
-               smtp_enter_state(s, STATE_TLS);
+               smtp_proceed_starttls(s);
                break;
 
        case CMD_AUTH:
-               if (s->helo[0] == '\0' || s->tx) {
-                       smtp_reply(s, "503 %s %s: Command not allowed at this point.",
-                           esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
-                           esc_description(ESC_INVALID_COMMAND));
-                       break;
-               }
-
-               if (s->flags & SF_AUTHENTICATED) {
-                       smtp_reply(s, "503 %s %s: Already authenticated",
-                           esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
-                           esc_description(ESC_INVALID_COMMAND));
-                       break;
-               }
-
-               if (!ADVERTISE_AUTH(s)) {
-                       smtp_reply(s, "503 %s %s: Command not supported",
-                           esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
-                           esc_description(ESC_INVALID_COMMAND));
+               if (!smtp_check_auth(s, args))
                        break;
-               }
-
-               if (args == NULL) {
-                       smtp_reply(s, "501 %s %s: No parameters given",
-                           esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND_ARGUMENTS),
-                           esc_description(ESC_INVALID_COMMAND_ARGUMENTS));
-                       break;
-               }
-
-               method = args;
-               eom = strchr(args, ' ');
-               if (eom == NULL)
-                       eom = strchr(args, '\t');
-               if (eom != NULL)
-                       *eom++ = '\0';
-               if (strcasecmp(method, "PLAIN") == 0)
-                       smtp_rfc4954_auth_plain(s, eom);
-               else if (strcasecmp(method, "LOGIN") == 0)
-                       smtp_rfc4954_auth_login(s, eom);
-               else
-                       smtp_reply(s, "504 %s %s: AUTH method \"%s\" not supported",
-                           esc_code(ESC_STATUS_PERMFAIL, ESC_SECURITY_FEATURES_NOT_SUPPORTED),
-                           esc_description(ESC_SECURITY_FEATURES_NOT_SUPPORTED),
-                           method);
+               smtp_proceed_auth(s, args);
                break;
 
        case CMD_MAIL_FROM:
-               if (s->helo[0] == '\0' || s->tx) {
-                       smtp_reply(s, "503 %s %s: Command not allowed at this point.",
-                           esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
-                           esc_description(ESC_INVALID_COMMAND));
-
-                       break;
-               }
-
-               if (s->listener->flags & F_STARTTLS_REQUIRE &&
-                   !(s->flags & SF_SECURE)) {
-                       smtp_reply(s,
-                           "530 %s %s: Must issue a STARTTLS command first",
-                           esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
-                           esc_description(ESC_INVALID_COMMAND));
-                       break;
-               }
-
-               if (s->listener->flags & F_AUTH_REQUIRE &&
-                   !(s->flags & SF_AUTHENTICATED)) {
-                       smtp_reply(s,
-                           "530 %s %s: Must issue an AUTH command first",
-                           esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
-                           esc_description(ESC_INVALID_COMMAND));
+               if (!smtp_check_mail_from(s))
                        break;
-               }
-
-               if (s->mailcount >= env->sc_session_max_mails) {
-                       /* we can pretend we had too many recipients */
-                       smtp_reply(s, "452 %s %s: Too many messages sent",
-                           esc_code(ESC_STATUS_TEMPFAIL, ESC_TOO_MANY_RECIPIENTS),
-                           esc_description(ESC_TOO_MANY_RECIPIENTS));
-                       break;
-               }
-
-               if (!smtp_tx(s)) {
-                       smtp_reply(s, "421 %s: Temporary Error",
-                           esc_code(ESC_STATUS_TEMPFAIL, ESC_OTHER_MAIL_SYSTEM_STATUS));
-                       smtp_enter_state(s, STATE_QUIT);
-                       break;
-               }
-
-               smtp_tx_mail_from(s->tx, args);
+               smtp_proceed_mail_from(s, args);
                break;
+
        /*
         * TRANSACTION
         */
        case CMD_RCPT_TO:
-               if (s->tx == NULL) {
-                       smtp_reply(s, "503 %s %s: Command not allowed at this point.",
-                           esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
-                           esc_description(ESC_INVALID_COMMAND));
+               if (!smtp_check_rcpt_to(s))
                        break;
-               }
-
-               smtp_tx_rcpt_to(s->tx, args);
+               smtp_proceed_rcpt_to(s, args);
                break;
 
        case CMD_RSET:
-               if (s->helo[0] == '\0') {
-                       smtp_reply(s, "503 %s %s: Command not allowed at this point.",
-                           esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
-                           esc_description(ESC_INVALID_COMMAND));
+               if (!smtp_check_rset(s))
                        break;
-               }
-
-               if (s->tx) {
-                       if (s->tx->msgid)
-                               smtp_tx_rollback(s->tx);
-                       smtp_tx_free(s->tx);
-               }
-
-               smtp_reply(s, "250 %s: Reset state",
-                   esc_code(ESC_STATUS_OK, ESC_OTHER_STATUS));
+               smtp_proceed_rset(s);
                break;
 
        case CMD_DATA:
-               if (s->tx == NULL) {
-                       smtp_reply(s, "503 %s %s: Command not allowed at this point.",
-                           esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
-                           esc_description(ESC_INVALID_COMMAND));
+               if (!smtp_check_data(s))
                        break;
-               }
-               if (s->tx->rcptcount == 0) {
-                       smtp_reply(s, "503 %s %s: No recipient specified",
-                           esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND_ARGUMENTS),
-                           esc_description(ESC_INVALID_COMMAND_ARGUMENTS));
-                       break;
-               }
-
-               smtp_tx_open_message(s->tx);
+               smtp_proceed_data(s);
                break;
+
        /*
         * ANY
         */
        case CMD_QUIT:
-               smtp_reply(s, "221 %s: Bye",
-                   esc_code(ESC_STATUS_OK, ESC_OTHER_STATUS));
-               smtp_enter_state(s, STATE_QUIT);
+               smtp_proceed_quit(s);
                break;
 
        case CMD_NOOP:
-               smtp_reply(s, "250 %s: Ok",
-                   esc_code(ESC_STATUS_OK, ESC_OTHER_STATUS));
+               smtp_proceed_noop(s);
                break;
 
        case CMD_HELP:
-               smtp_reply(s, "214- This is " SMTPD_NAME);
-               smtp_reply(s, "214- To report bugs in the implementation, "
-                   "please contact bugs@openbsd.org");
-               smtp_reply(s, "214- with full details");
-               smtp_reply(s, "214 %s: End of HELP info",
-                   esc_code(ESC_STATUS_OK, ESC_OTHER_STATUS));
+               smtp_proceed_help(s);
                break;
 
        case CMD_WIZ:
-               smtp_reply(s, "500 %s %s: this feature is not supported yet ;-)",
-                           esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
-                           esc_description(ESC_INVALID_COMMAND));
+               smtp_proceed_wiz(s);
                break;
 
        default:
@@ -1318,6 +1153,320 @@ smtp_command(struct smtp_session *s, char *line)
        }
 }
 
+static int
+smtp_check_rset(struct smtp_session *s)
+{
+       if (s->helo[0] == '\0') {
+               smtp_reply(s, "503 %s %s: Command not allowed at this point.",
+                   esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
+                   esc_description(ESC_INVALID_COMMAND));
+               return 0;
+       }
+       return 1;
+}
+
+static int
+smtp_check_helo(struct smtp_session *s, int cmd, const char *args)
+{
+       if (s->helo[0]) {
+               smtp_reply(s, "503 %s %s: Already identified",
+                   esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
+                   esc_description(ESC_INVALID_COMMAND));
+               return 0;
+       }
+
+       if (args == NULL) {
+               smtp_reply(s, "501 %s %s: %s requires domain name",
+                   esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
+                   esc_description(ESC_INVALID_COMMAND),
+                   (cmd == CMD_HELO) ? "HELO" : "EHLO");
+               return 0;
+       }
+
+       if (!valid_domainpart(args)) {
+               smtp_reply(s, "501 %s %s: Invalid domain name",
+                   esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND_ARGUMENTS),
+                   esc_description(ESC_INVALID_COMMAND_ARGUMENTS));
+               return 0;
+       }
+
+       return 1;
+}
+
+static int
+smtp_check_auth(struct smtp_session *s, const char *args)
+{
+       if (s->helo[0] == '\0' || s->tx) {
+               smtp_reply(s, "503 %s %s: Command not allowed at this point.",
+                   esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
+                   esc_description(ESC_INVALID_COMMAND));
+               return 0;
+       }
+
+       if (s->flags & SF_AUTHENTICATED) {
+               smtp_reply(s, "503 %s %s: Already authenticated",
+                   esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
+                   esc_description(ESC_INVALID_COMMAND));
+               return 0;
+       }
+
+       if (!ADVERTISE_AUTH(s)) {
+               smtp_reply(s, "503 %s %s: Command not supported",
+                   esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
+                   esc_description(ESC_INVALID_COMMAND));
+               return 0;
+       }
+
+       if (args == NULL) {
+               smtp_reply(s, "501 %s %s: No parameters given",
+                   esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND_ARGUMENTS),
+                   esc_description(ESC_INVALID_COMMAND_ARGUMENTS));
+               return 0;
+       }
+
+       return 1;
+}
+
+static int
+smtp_check_starttls(struct smtp_session *s, const char *args)
+{
+       if (s->helo[0] == '\0' || s->tx) {
+               smtp_reply(s, "503 %s %s: Command not allowed at this point.",
+                   esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
+                   esc_description(ESC_INVALID_COMMAND));
+               return 0;
+       }
+
+       if (!(s->listener->flags & F_STARTTLS)) {
+               smtp_reply(s, "503 %s %s: Command not supported",
+                   esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
+                   esc_description(ESC_INVALID_COMMAND));
+               return 0;
+       }
+
+       if (s->flags & SF_SECURE) {
+               smtp_reply(s, "503 %s %s: Channel already secured",
+                   esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
+                   esc_description(ESC_INVALID_COMMAND));
+               return 0;
+       }
+
+       if (args != NULL) {
+               smtp_reply(s, "501 %s %s: No parameters allowed",
+                   esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND_ARGUMENTS),
+                   esc_description(ESC_INVALID_COMMAND_ARGUMENTS));
+               return 0;
+       }
+
+       return 1;
+}
+
+static int
+smtp_check_mail_from(struct smtp_session *s)
+{
+       if (s->helo[0] == '\0' || s->tx) {
+               smtp_reply(s, "503 %s %s: Command not allowed at this point.",
+                   esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
+                   esc_description(ESC_INVALID_COMMAND));
+               return 0;
+       }
+
+       if (s->listener->flags & F_STARTTLS_REQUIRE &&
+           !(s->flags & SF_SECURE)) {
+               smtp_reply(s,
+                   "530 %s %s: Must issue a STARTTLS command first",
+                   esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
+                   esc_description(ESC_INVALID_COMMAND));
+               return 0;
+       }
+
+       if (s->listener->flags & F_AUTH_REQUIRE &&
+           !(s->flags & SF_AUTHENTICATED)) {
+               smtp_reply(s,
+                   "530 %s %s: Must issue an AUTH command first",
+                   esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
+                   esc_description(ESC_INVALID_COMMAND));
+               return 0;
+       }
+
+       if (s->mailcount >= env->sc_session_max_mails) {
+               /* we can pretend we had too many recipients */
+               smtp_reply(s, "452 %s %s: Too many messages sent",
+                   esc_code(ESC_STATUS_TEMPFAIL, ESC_TOO_MANY_RECIPIENTS),
+                   esc_description(ESC_TOO_MANY_RECIPIENTS));
+               return 0;
+       }
+
+       if (!smtp_tx(s)) {
+               smtp_reply(s, "421 %s: Temporary Error",
+                   esc_code(ESC_STATUS_TEMPFAIL, ESC_OTHER_MAIL_SYSTEM_STATUS));
+               smtp_enter_state(s, STATE_QUIT);
+               return 0;
+       }
+
+       return 1;
+}
+
+static int
+smtp_check_rcpt_to(struct smtp_session *s)
+{
+       if (s->tx == NULL) {
+               smtp_reply(s, "503 %s %s: Command not allowed at this point.",
+                   esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
+                   esc_description(ESC_INVALID_COMMAND));
+               return 0;
+       }
+
+       return 1;
+}
+
+static int
+smtp_check_data(struct smtp_session *s)
+{
+       if (s->tx == NULL) {
+               smtp_reply(s, "503 %s %s: Command not allowed at this point.",
+                   esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
+                   esc_description(ESC_INVALID_COMMAND));
+               return 0;
+       }
+
+       if (s->tx->rcptcount == 0) {
+               smtp_reply(s, "503 %s %s: No recipient specified",
+                   esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND_ARGUMENTS),
+                   esc_description(ESC_INVALID_COMMAND_ARGUMENTS));
+               return 0;
+       }
+
+       return 1;
+}
+
+
+static void
+smtp_proceed_rset(struct smtp_session *s)
+{
+       if (s->tx) {
+               if (s->tx->msgid)
+                       smtp_tx_rollback(s->tx);
+               smtp_tx_free(s->tx);
+       }
+
+       smtp_reply(s, "250 %s: Reset state",
+           esc_code(ESC_STATUS_OK, ESC_OTHER_STATUS));
+}
+
+static void
+smtp_proceed_helo(struct smtp_session *s, int cmd, char *args)
+{
+       (void)strlcpy(s->helo, args, sizeof(s->helo));
+       s->flags &= SF_SECURE | SF_AUTHENTICATED | SF_VERIFIED;
+       if (cmd == CMD_EHLO) {
+               s->flags |= SF_EHLO;
+               s->flags |= SF_8BITMIME;
+       }
+
+       smtp_enter_state(s, STATE_HELO);
+       smtp_reply(s, "250%c%s Hello %s [%s], pleased to meet you",
+           (s->flags & SF_EHLO) ? '-' : ' ',
+           s->smtpname,
+           s->helo,
+           ss_to_text(&s->ss));
+
+       if (s->flags & SF_EHLO) {
+               smtp_reply(s, "250-8BITMIME");
+               smtp_reply(s, "250-ENHANCEDSTATUSCODES");
+               smtp_reply(s, "250-SIZE %zu", env->sc_maxsize);
+               if (ADVERTISE_EXT_DSN(s))
+                       smtp_reply(s, "250-DSN");
+               if (ADVERTISE_TLS(s))
+                       smtp_reply(s, "250-STARTTLS");
+               if (ADVERTISE_AUTH(s))
+                       smtp_reply(s, "250-AUTH PLAIN LOGIN");
+               smtp_reply(s, "250 HELP");
+       }
+}
+
+static void
+smtp_proceed_auth(struct smtp_session *s, char *args)
+{
+       char *eom, *method;
+
+       method = args;
+       eom = strchr(args, ' ');
+       if (eom == NULL)
+               eom = strchr(args, '\t');
+       if (eom != NULL)
+               *eom++ = '\0';
+       if (strcasecmp(method, "PLAIN") == 0)
+               smtp_rfc4954_auth_plain(s, eom);
+       else if (strcasecmp(method, "LOGIN") == 0)
+               smtp_rfc4954_auth_login(s, eom);
+       else
+               smtp_reply(s, "504 %s %s: AUTH method \"%s\" not supported",
+                   esc_code(ESC_STATUS_PERMFAIL, ESC_SECURITY_FEATURES_NOT_SUPPORTED),
+                   esc_description(ESC_SECURITY_FEATURES_NOT_SUPPORTED),
+                   method);
+}
+
+static void
+smtp_proceed_starttls(struct smtp_session *s)
+{
+       smtp_reply(s, "220 %s: Ready to start TLS",
+           esc_code(ESC_STATUS_OK, ESC_OTHER_STATUS));
+       smtp_enter_state(s, STATE_TLS);
+}
+
+static void
+smtp_proceed_mail_from(struct smtp_session *s, char *args)
+{
+       smtp_tx_mail_from(s->tx, args);
+}
+
+static void
+smtp_proceed_rcpt_to(struct smtp_session *s, char *args)
+{
+       smtp_tx_rcpt_to(s->tx, args);
+}
+
+static void
+smtp_proceed_data(struct smtp_session *s)
+{
+       smtp_tx_open_message(s->tx);
+}
+
+static void
+smtp_proceed_quit(struct smtp_session *s)
+{
+       smtp_reply(s, "221 %s: Bye",
+           esc_code(ESC_STATUS_OK, ESC_OTHER_STATUS));
+       smtp_enter_state(s, STATE_QUIT);
+}
+
+static void
+smtp_proceed_noop(struct smtp_session *s)
+{
+       smtp_reply(s, "250 %s: Ok",
+           esc_code(ESC_STATUS_OK, ESC_OTHER_STATUS));
+}
+
+static void
+smtp_proceed_help(struct smtp_session *s)
+{
+       smtp_reply(s, "214- This is " SMTPD_NAME);
+       smtp_reply(s, "214- To report bugs in the implementation, "
+           "please contact bugs@openbsd.org");
+       smtp_reply(s, "214- with full details");
+       smtp_reply(s, "214 %s: End of HELP info",
+           esc_code(ESC_STATUS_OK, ESC_OTHER_STATUS));
+}
+
+static void
+smtp_proceed_wiz(struct smtp_session *s)
+{
+       smtp_reply(s, "500 %s %s: this feature is not supported yet ;-)",
+           esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
+           esc_description(ESC_INVALID_COMMAND));
+}
+
 static void
 smtp_rfc4954_auth_plain(struct smtp_session *s, char *arg)
 {