1
0
mirror of https://blitiri.com.ar/repos/chasquid synced 2026-10-29 15:02:30 +00:00
Files
go-chasquid-smtp/test/t-03-queue_persistency/addtoqueue.go
T
Alberto Bertogli 61792e3bb4 Reject invalid characters in domains
Domains in addresses had very lax validation, which allowed them to
include characters like "/".

That could be exploited to trigger a daemon panic: a MAIL FROM
"x@evil/foo" could be accepted and, on failed delivery, a DSN queued.
Attempting to deliver the DSN would cause an MTA-STS cache lookup, which
would panic because the domain includes a "/" and crash the server.
Because the DSN would be queued, the server would crash again on
restarts, and only self-recover after give_up_send_after (20h by
default).

To fix this, we now explicitly validate the domain when normalizing it,
make MTA-STS cache not panic on invalid domains, and also make the SMTP
courier fail permanently on invalid domains.

Thanks to John JEAN <john@wargan.com> for finding and reporting this
problem. The detailed report can be found in
https://johnjean.io/advisories/chasquid-unauthenticated-remote-dos/.
2026-10-09 00:00:12 +01:00

69 lines
1.4 KiB
Go

// addtoqueue is a test helper which adds a queue item directly to the queue
// directory, behind chasquid's back.
//
// Note that chasquid does NOT support this, we do it before starting up the
// daemon for testing purposes only.
//
//go:build ignore
package main
import (
"flag"
"fmt"
"io"
"os"
"time"
"blitiri.com.ar/go/chasquid/internal/queue"
)
var (
queueDir = flag.String("queue_dir", ".queue", "queue directory")
id = flag.String("id", "mid1234", "Message ID")
from = flag.String("from", "from", "Mail from")
rcpt = flag.String("rcpt", "rcpt", "Rcpt to")
rcptType = flag.String("rcpt_type", "EMAIL",
"Recipient type (EMAIL, PIPE, FORWARD)")
)
func main() {
flag.Parse()
rType, ok := queue.Recipient_Type_value[*rcptType]
if !ok {
fmt.Printf("unknown recipient type %q\n", *rcptType)
os.Exit(1)
}
data, err := io.ReadAll(os.Stdin)
if err != nil {
fmt.Printf("error reading data: %v\n", err)
os.Exit(1)
}
item := &queue.Item{
Message: queue.Message{
ID: *id,
From: *from,
To: []string{*rcpt},
Rcpt: []*queue.Recipient{
{
Address: *rcpt,
Type: queue.Recipient_Type(rType),
Status: queue.Recipient_PENDING,
},
},
Data: data,
},
CreatedAt: time.Now(),
}
os.MkdirAll(*queueDir, 0700)
err = item.WriteTo(*queueDir)
if err != nil {
fmt.Printf("error writing item: %v\n", err)
os.Exit(1)
}
}