From 22ef0c2ee6261145176b964ffa38d70c5c1bcd02 Mon Sep 17 00:00:00 2001 From: Jonathon Reinhart Date: Sun, 14 Mar 2021 14:06:21 -0400 Subject: [PATCH] Move SMTP auth setup to ConfigLoad() This has several benefits: - Configuration errors are caught at startup rather than upon a connection - mailHandler() has less work to do for each connection Rather than relying on remote_user and remote_pass to control whether authentication is used, introduce an explicit "none" type for remote_auth, and make that the default. (This is effectively the same default behavior since remote_user and remote_pass default to empty.) Also, we are in a better position to more thoroughly check for configuration errors or mismatches: - If remote_auth is given, remote_user and remote_pass are required. - If remote_auth is given, remote_host is also required (because it makes no sense to say we're going to authenticate if we have no server to which to authenticate.) - If remote_user or remote_pass are given, remote_auth cannot be "none". --- config.go | 50 +++++++++++++++++++++++++++++++++++++++++++++++++- main.go | 17 +---------------- smtprelay.ini | 4 ++-- 3 files changed, 52 insertions(+), 19 deletions(-) diff --git a/config.go b/config.go index a1bdc53..fdc7394 100644 --- a/config.go +++ b/config.go @@ -4,6 +4,7 @@ import ( "flag" "net" "regexp" + "net/smtp" "github.com/vharitonsky/iniflags" "github.com/sirupsen/logrus" @@ -34,7 +35,8 @@ var ( remoteHost = flag.String("remote_host", "", "Outgoing SMTP server") remoteUser = flag.String("remote_user", "", "Username for authentication on outgoing SMTP server") remotePass = flag.String("remote_pass", "", "Password for authentication on outgoing SMTP server") - remoteAuth = flag.String("remote_auth", "plain", "Auth method on outgoing SMTP server (plain, login)") + remoteAuthStr = flag.String("remote_auth", "none", "Auth method on outgoing SMTP server (none, plain, login)") + remoteAuth smtp.Auth remoteSender = flag.String("remote_sender", "", "Sender e-mail address on outgoing SMTP server") versionInfo = flag.Bool("version", false, "Show version information") ) @@ -84,6 +86,51 @@ func setupAllowedPatterns() { } } + +func setupRemoteAuth() { + logger := log.WithField("remote_auth", *remoteAuthStr) + + // Remote auth disabled? + switch *remoteAuthStr { + case "", "none": + if *remoteUser != "" { + logger.Fatal("remote_user given but not used") + } + if *remotePass != "" { + logger.Fatal("remote_pass given but not used") + } + + // No auth; use empty default + return + } + + // We need a username, password, and remote host + if *remoteUser == "" { + logger.Fatal("remote_user required but empty") + } + if *remotePass == "" { + logger.Fatal("remote_pass required but empty") + } + if *remoteHost == "" { + logger.Fatal("remote_auth without remote_host is pointless") + } + + host, _, err := net.SplitHostPort(*remoteHost) + if err != nil { + logger.WithField("remote_host", *remoteHost). + Fatal("Invalid remote_host") + } + + switch *remoteAuthStr { + case "plain": + remoteAuth = smtp.PlainAuth("", *remoteUser, *remotePass, host) + case "login": + remoteAuth = LoginAuth(*remoteUser, *remotePass) + default: + logger.Fatal("Invalid remote_auth type") + } +} + func ConfigLoad() { iniflags.Parse() @@ -96,4 +143,5 @@ func ConfigLoad() { setupAllowedNetworks() setupAllowedPatterns() + setupRemoteAuth() } diff --git a/main.go b/main.go index 5c960ef..556647d 100644 --- a/main.go +++ b/main.go @@ -4,7 +4,6 @@ import ( "crypto/tls" "fmt" "net" - "net/smtp" "net/textproto" "os" "strings" @@ -170,20 +169,6 @@ func mailHandler(peer smtpd.Peer, env smtpd.Envelope) error { logger.Info("delivering mail from peer using smarthost") - var auth smtp.Auth - host, _, _ := net.SplitHostPort(*remoteHost) - - if *remoteUser != "" && *remotePass != "" { - switch *remoteAuth { - case "plain": - auth = smtp.PlainAuth("", *remoteUser, *remotePass, host) - case "login": - auth = LoginAuth(*remoteUser, *remotePass) - default: - return smtpd.Error{Code: 530, Message: "Authentication method not supported"} - } - } - env.AddReceivedLine(peer) var sender string @@ -196,7 +181,7 @@ func mailHandler(peer smtpd.Peer, env smtpd.Envelope) error { err := SendMail( *remoteHost, - auth, + remoteAuth, sender, env.Recipients, env.Data, diff --git a/smtprelay.ini b/smtprelay.ini index d0f3d4e..b47f103 100644 --- a/smtprelay.ini +++ b/smtprelay.ini @@ -73,8 +73,8 @@ ;remote_pass = ; Authentication method on outgoing SMTP server -; (plain, login) -;remote_auth = plain +; (none, plain, login) +;remote_auth = none ; Sender e-mail address on outgoing SMTP server ;remote_sender =