Browse Source

Merge pull request #19 from decke/allow-any-sender-recipient

Move remaining config option parsing to ConfigLoad()
Bernhard Fröhlich 4 years ago
parent
commit
2cd636c082
3 changed files with 90 additions and 43 deletions
  1. 76 3
      config.go
  2. 10 38
      main.go
  3. 4 2
      smtprelay.ini

+ 76 - 3
config.go

@@ -3,6 +3,8 @@ package main
 import (
 	"flag"
 	"net"
+	"regexp"
+	"net/smtp"
 
 	"github.com/vharitonsky/iniflags"
 	"github.com/sirupsen/logrus"
@@ -25,13 +27,16 @@ var (
 	localForceTLS     = flag.Bool("local_forcetls", false, "Force STARTTLS (needs local_cert and local_key)")
 	allowedNetsStr    = flag.String("allowed_nets", "127.0.0.0/8 ::1/128", "Networks allowed to send mails")
 	allowedNets       = []*net.IPNet{}
-	allowedSender     = flag.String("allowed_sender", "", "Regular expression for valid FROM EMail addresses")
-	allowedRecipients = flag.String("allowed_recipients", "", "Regular expression for valid TO EMail addresses")
+	allowedSenderStr  = flag.String("allowed_sender", "", "Regular expression for valid FROM EMail addresses")
+	allowedSender     *regexp.Regexp
+	allowedRecipStr   = flag.String("allowed_recipients", "", "Regular expression for valid TO EMail addresses")
+	allowedRecipients *regexp.Regexp
 	allowedUsers      = flag.String("allowed_users", "", "Path to file with valid users/passwords")
 	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")
 )
@@ -59,6 +64,72 @@ func setupAllowedNetworks() {
 	}
 }
 
+func setupAllowedPatterns() {
+	var err error
+
+	if (*allowedSenderStr != "") {
+		allowedSender, err = regexp.Compile(*allowedSenderStr)
+		if err != nil {
+			log.WithField("allowed_sender", *allowedSenderStr).
+				WithError(err).
+				Fatal("allowed_sender pattern invalid")
+		}
+	}
+
+	if (*allowedRecipStr != "") {
+		allowedRecipients, err = regexp.Compile(*allowedRecipStr)
+		if err != nil {
+			log.WithField("allowed_recipients", *allowedRecipStr).
+				WithError(err).
+				Fatal("allowed_recipients pattern invalid")
+		}
+	}
+}
+
+
+func setupRemoteAuth() {
+	logger := log.WithField("remote_auth", *remoteAuthStr)
+
+	// Remote auth disabled?
+	if *remoteAuthStr == "" || *remoteAuthStr == "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()
 
@@ -70,4 +141,6 @@ func ConfigLoad() {
 	}
 
 	setupAllowedNetworks()
+	setupAllowedPatterns()
+	setupRemoteAuth()
 }

+ 10 - 38
main.go

@@ -4,10 +4,8 @@ import (
 	"crypto/tls"
 	"fmt"
 	"net"
-	"net/smtp"
 	"net/textproto"
 	"os"
-	"regexp"
 	"strings"
 	"time"
 
@@ -103,43 +101,31 @@ func senderChecker(peer smtpd.Peer, addr string) error {
 		}
 	}
 
-	if *allowedSender == "" {
+	if allowedSender == nil {
+		// Any sender is permitted
 		return nil
 	}
 
-	re, err := regexp.Compile(*allowedSender)
-	if err != nil {
-		log.WithFields(logrus.Fields{
-			"allowed_sender": *allowedSender,
-		}).WithError(err).Warn("allowed_sender pattern invalid")
-		return smtpd.Error{Code: 451, Message: "Bad sender address"}
-	}
-
-	if re.MatchString(addr) {
+	if allowedSender.MatchString(addr) {
+		// Permitted by regex
 		return nil
 	}
 
 	log.WithFields(logrus.Fields{
 		"sender_address": addr,
 		"peer": peer.Addr,
-	}).Warn("Sender address not allowed by allowed_sender pattern")
+	}).Warn("sender address not allowed by allowed_sender pattern")
 	return smtpd.Error{Code: 451, Message: "Bad sender address"}
 }
 
 func recipientChecker(peer smtpd.Peer, addr string) error {
-	if *allowedRecipients == "" {
+	if allowedRecipients == nil {
+		// Any recipient is permitted
 		return nil
 	}
 
-	re, err := regexp.Compile(*allowedRecipients)
-	if err != nil {
-		log.WithFields(logrus.Fields{
-			"allowed_recipients": *allowedRecipients,
-		}).WithError(err).Warn("allowed_recipients pattern invalid")
-		return smtpd.Error{Code: 451, Message: "Bad recipient address"}
-	}
-
-	if re.MatchString(addr) {
+	if allowedRecipients.MatchString(addr) {
+		// Permitted by regex
 		return nil
 	}
 
@@ -183,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
@@ -209,7 +181,7 @@ func mailHandler(peer smtpd.Peer, env smtpd.Envelope) error {
 
 	err := SendMail(
 		*remoteHost,
-		auth,
+		remoteAuth,
 		sender,
 		env.Recipients,
 		env.Data,

+ 4 - 2
smtprelay.ini

@@ -35,10 +35,12 @@
 ;allowed_nets = 127.0.0.0/8 ::1/128
 
 ; Regular expression for valid FROM EMail addresses
+; If set to "", then any sender is permitted.
 ; Example: ^(.*)@localhost.localdomain$
 ;allowed_sender =
 
 ; Regular expression for valid TO EMail addresses
+; If set to "", then any recipient is permitted.
 ; Example: ^(.*)@localhost.localdomain$
 ;allowed_recipients =
 
@@ -71,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 =