when a session fails due to a TLS error in a smtp+tls:// connection, try
authorgilles <gilles@openbsd.org>
Tue, 29 Apr 2014 17:32:42 +0000 (17:32 +0000)
committergilles <gilles@openbsd.org>
Tue, 29 Apr 2014 17:32:42 +0000 (17:32 +0000)
plain before giving up

ok eric@

usr.sbin/smtpd/mta_session.c

index 615ddfd..0be56d7 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: mta_session.c,v 1.61 2014/04/29 10:18:06 reyk Exp $   */
+/*     $OpenBSD: mta_session.c,v 1.62 2014/04/29 17:32:42 gilles Exp $ */
 
 /*
  * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
@@ -80,6 +80,7 @@ enum mta_state {
 #define MTA_WANT_SECURE                0x0010
 #define MTA_USE_AUTH           0x0020
 #define MTA_USE_CERT           0x0040
+#define MTA_DOWNGRADE_PLAIN            0x0080
 
 #define MTA_TLS_TRIED          0x0080
 
@@ -525,6 +526,10 @@ mta_connect(struct mta_session *s)
                        s->use_smtps = 1;       /* tls+smtps */
                        break;
                }
+               else if (s->flags & MTA_DOWNGRADE_PLAIN) {
+                       /* smtp+tls, with tls failure */
+                       break;
+               }
        default:
                mta_free(s);
                return;
@@ -544,7 +549,6 @@ mta_connect(struct mta_session *s)
                ((struct sockaddr_in6 *)sa)->sin6_port = htons(portno);
 
        s->attempt += 1;
-
        if (s->use_smtp_tls)
                schema = "smtp+tls://";
        else if (s->use_starttls)
@@ -870,6 +874,11 @@ mta_response(struct mta_session *s, char *line)
        switch (s->state) {
 
        case MTA_BANNER:
+               if (line[0] != '2') {
+                       mta_error(s, "BANNER rejected: %s", line);
+                       s->flags |= MTA_FREE;
+                       return;
+               }
                if (s->flags & MTA_LMTP)
                        mta_enter_state(s, MTA_LHLO);
                else
@@ -1269,6 +1278,11 @@ mta_io(struct io *io, int evt)
                mta_error(s, "IO Error: %s", io->error);
                if (!s->ready)
                        mta_connect(s);
+               else if (!(s->flags & (MTA_FORCE_TLS|MTA_FORCE_ANYSSL))) {
+                       /* error in non-strict SSL negotiation, downgrade to plain */
+                               s->flags |= MTA_DOWNGRADE_PLAIN;
+                               mta_connect(s);
+               }
                else
                        mta_free(s);
                break;