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

chasquid: Minor fixes to MAIL FROM and RCPT TO handling

This patch tidies up the MAIL FROM and RCPT TO handling, in particular:

 - Preserve the case on received email. It could be outgoing and we
   should not change it.
 - Accept (but ignore) RCPT TO options, instead of failing.
 - Fix some error codes to make them follow the RFC.
This commit is contained in:
Alberto Bertogli
2016-10-08 10:29:04 +01:00
parent 3e6dd12d06
commit 7403dbb8a3
2 changed files with 32 additions and 12 deletions

View File

@@ -595,8 +595,8 @@ func (c *Conn) NOOP(params string) (code int, msg string) {
func (c *Conn) MAIL(params string) (code int, msg string) {
// params should be: "FROM:<name@host>", and possibly followed by
// "BODY=8BITMIME" (which we ignore).
// Check that it begins with "FROM:" first, otherwise it's pointless.
// options such as "BODY=8BITMIME" (which we ignore).
// Check that it begins with "FROM:" first, it's mandatory.
if !strings.HasPrefix(strings.ToLower(params), "from:") {
return 500, "unknown command"
}
@@ -655,23 +655,30 @@ func (c *Conn) MAIL(params string) (code int, msg string) {
}
func (c *Conn) RCPT(params string) (code int, msg string) {
// params should be: "TO:<name@host>"
// First, get rid of the "TO:" part (but check it, it's mandatory).
sp := strings.SplitN(strings.ToLower(params), ":", 2)
if len(sp) != 2 || sp[0] != "to" {
// params should be: "TO:<name@host>", and possibly followed by options
// such as "NOTIFY=SUCCESS,DELAY" (which we ignore).
// Check that it begins with "TO:" first, it's mandatory.
if !strings.HasPrefix(strings.ToLower(params), "to:") {
return 500, "unknown command"
}
rawAddr := ""
_, err := fmt.Sscanf(params[3:], "%s ", &rawAddr)
if err != nil {
return 500, "malformed command - " + err.Error()
}
// RFC says 100 is the minimum limit for this, but it seems excessive.
// https://tools.ietf.org/html/rfc5321#section-4.5.3.1.8
if len(c.rcptTo) > 100 {
return 503, "too many recipients"
return 452, "too many recipients"
}
// TODO: Write our own parser (we have different needs, mail.ParseAddress
// is useful for other things).
// Allow utf8, but prevent "control" characters.
e, err := mail.ParseAddress(sp[1])
e, err := mail.ParseAddress(rawAddr)
if err != nil || e.Address == "" {
return 501, "malformed address"
}

View File

@@ -184,11 +184,9 @@ func TestNullMailFrom(t *testing.T) {
c := mustDial(t, ModeSMTP, false)
defer c.Close()
addrs := []string{"", "<>", " <>", " < > "}
addrs := []string{"<>", " <>", "<> OPTION"}
for _, addr := range addrs {
if err := c.Text.PrintfLine(addr); err != nil {
t.Fatalf("MAIL FROM failed with addr %q: %v", addr, err)
}
simpleCmd(t, c, fmt.Sprintf("MAIL FROM:%s", addr), 250)
}
}
@@ -201,6 +199,21 @@ func TestRcptBeforeMail(t *testing.T) {
}
}
func TestRcptOption(t *testing.T) {
c := mustDial(t, ModeSMTP, false)
defer c.Close()
if err := c.Mail("from@localhost"); err != nil {
t.Errorf("Mail: %v", err)
}
params := []string{
"<to@localhost>", " <to@localhost>", "<to@localhost> OPTION"}
for _, p := range params {
simpleCmd(t, c, fmt.Sprintf("RCPT TO:%s", p), 250)
}
}
func TestRelayForbidden(t *testing.T) {
c := mustDial(t, ModeSMTP, false)
defer c.Close()