1
0
mirror of https://blitiri.com.ar/repos/chasquid synced 2025-12-17 14:37:02 +00:00

smtpsrv: Return a temporary error when we fail to check if a user exists

When we fail to check if a user exists, we currently return a permanent
error, which can be misleading and also make things more difficult to
troubleshoot.

This patch makes chasquid return a temporary error in that case.

Thanks to Thor77 (thor77@thor77.org) for suggesting this change.
This commit is contained in:
Alberto Bertogli
2021-05-30 00:32:54 +01:00
parent fa651e74e3
commit d3396ace0b
2 changed files with 30 additions and 9 deletions

View File

@@ -578,7 +578,14 @@ func (c *Conn) RCPT(params string) (code int, msg string) {
return 550, "5.1.3 Destination address is invalid" return 550, "5.1.3 Destination address is invalid"
} }
if !c.userExists(addr) { ok, err := c.userExists(addr)
if err != nil {
c.tr.Errorf("error checking if user %q exists: %v", addr, err)
maillog.Rejected(c.remoteAddr, c.mailFrom, []string{addr},
fmt.Sprintf("error checking if user exists: %v", err))
return 451, "4.4.3 Temporary error checking address"
}
if !ok {
maillog.Rejected(c.remoteAddr, c.mailFrom, []string{addr}, maillog.Rejected(c.remoteAddr, c.mailFrom, []string{addr},
"local user does not exist") "local user does not exist")
return 550, "5.1.1 Destination address is unknown (user does not exist)" return 550, "5.1.1 Destination address is unknown (user does not exist)"
@@ -1081,11 +1088,11 @@ func (c *Conn) resetEnvelope() {
c.spfError = nil c.spfError = nil
} }
func (c *Conn) userExists(addr string) bool { func (c *Conn) userExists(addr string) (bool, error) {
var ok bool var ok bool
addr, ok = c.aliasesR.Exists(addr) addr, ok = c.aliasesR.Exists(addr)
if ok { if ok {
return true return true, nil
} }
// Note we used the address returned by the aliases resolver, which has // Note we used the address returned by the aliases resolver, which has
@@ -1093,11 +1100,7 @@ func (c *Conn) userExists(addr string) bool {
// look up "user" in our databases if the domain is local, which is what // look up "user" in our databases if the domain is local, which is what
// we want. // we want.
user, domain := envelope.Split(addr) user, domain := envelope.Split(addr)
ok, err := c.authr.Exists(user, domain) return c.authr.Exists(user, domain)
if err != nil {
c.tr.Errorf("error checking if user %q exists: %v", addr, err)
}
return ok
} }
func (c *Conn) readCommand() (cmd, params string, err error) { func (c *Conn) readCommand() (cmd, params string, err error) {

View File

@@ -308,7 +308,7 @@ func TestTooManyRecipients(t *testing.T) {
} }
} }
func TestRcptFailsExistsCheck(t *testing.T) { func TestRcptBrokenExists(t *testing.T) {
c := mustDial(t, ModeSMTP, true) c := mustDial(t, ModeSMTP, true)
defer c.Close() defer c.Close()
@@ -320,6 +320,24 @@ func TestRcptFailsExistsCheck(t *testing.T) {
if err == nil { if err == nil {
t.Errorf("Accepted RCPT with broken Exists") t.Errorf("Accepted RCPT with broken Exists")
} }
expect := "451 4.4.3 Temporary error checking address"
if err.Error() != expect {
t.Errorf("RCPT returned unexpected error %q", err.Error())
}
}
func TestRcptUserDoesNotExist(t *testing.T) {
c := mustDial(t, ModeSMTP, true)
defer c.Close()
if err := c.Mail("from@localhost"); err != nil {
t.Fatalf("Mail: %v", err)
}
err := c.Rcpt("doesnotexist@localhost")
if err == nil {
t.Errorf("Accepted RCPT for non-existent user")
}
expect := "550 5.1.1 Destination address is unknown (user does not exist)" expect := "550 5.1.1 Destination address is unknown (user does not exist)"
if err.Error() != expect { if err.Error() != expect {
t.Errorf("RCPT returned unexpected error %q", err.Error()) t.Errorf("RCPT returned unexpected error %q", err.Error())