From b4a6cf4c7842dc9f62c3eec34fbbf947349f729d Mon Sep 17 00:00:00 2001
From: ale <ale@incal.net>
Date: Tue, 28 Sep 2021 22:19:08 +0100
Subject: [PATCH] Fix SMTP authentication

Provide our own net/smtp.Auth implementation to do AUTH PLAIN without
the TLS check.

Fixes issue #1.
---
 protocol/smtp/smtp.go | 34 +++++++++++++++++++++++++++++++++-
 1 file changed, 33 insertions(+), 1 deletion(-)

diff --git a/protocol/smtp/smtp.go b/protocol/smtp/smtp.go
index 92b931c..f57970a 100644
--- a/protocol/smtp/smtp.go
+++ b/protocol/smtp/smtp.go
@@ -58,7 +58,7 @@ func (c *Conn) Close() error {
 }
 
 func (c *Conn) SendMail(username, password, from string, to []string, msg []byte) error {
-	auth := smtp.PlainAuth("", username, password, c.hostname)
+	auth := newPlainAuth("", username, password, c.hostname)
 	if ok, _ := c.client.Extension("AUTH"); !ok {
 		return errors.New("server does not support AUTH extension")
 	}
@@ -86,3 +86,35 @@ func (c *Conn) SendMail(username, password, from string, to []string, msg []byte
 	}
 	return nil
 }
+
+// This is almost a copy of net/smtp/auth.go, but without the TLS
+// check. The net/smtp package attempts to autodetect TLS usage by
+// checking if the net.Conn it got is actually a *tls.Conn. Since we
+// wrap our connection in the logging wrapper, this check fails, and
+// net/smtp.PlainAuth will refuse to authenticate, thinking the
+// connection is unencrypted.
+type plainAuth struct {
+	identity, username, password string
+	host                         string
+}
+
+func newPlainAuth(identity, username, password, host string) smtp.Auth {
+	return &plainAuth{identity, username, password, host}
+}
+
+func (a *plainAuth) Start(server *smtp.ServerInfo) (string, []byte, error) {
+	// We know we have TLS.
+	if server.Name != a.host {
+		return "", nil, errors.New("wrong host name")
+	}
+	resp := []byte(a.identity + "\x00" + a.username + "\x00" + a.password)
+	return "PLAIN", resp, nil
+}
+
+func (a *plainAuth) Next(fromServer []byte, more bool) ([]byte, error) {
+	if more {
+		// We've already sent everything.
+		return nil, errors.New("unexpected server challenge")
+	}
+	return nil, nil
+}
-- 
GitLab