reject wrong email in SMTP MAIL(), reject impersonation attempts

This commit is contained in:
Aine
2022-11-23 11:51:12 +02:00
parent b4d6d992ac
commit 0701f8c9c3
4 changed files with 55 additions and 22 deletions

View File

@@ -125,7 +125,7 @@ func (b *Bot) Ban(addr net.Addr) {
} }
// AllowAuth check if SMTP login (email) and password are valid // AllowAuth check if SMTP login (email) and password are valid
func (b *Bot) AllowAuth(email, password string) bool { func (b *Bot) AllowAuth(email, password string) (id.RoomID, bool) {
var suffix bool var suffix bool
for _, domain := range b.domains { for _, domain := range b.domains {
if strings.HasSuffix(email, "@"+domain) { if strings.HasSuffix(email, "@"+domain) {
@@ -134,22 +134,27 @@ func (b *Bot) AllowAuth(email, password string) bool {
} }
} }
if !suffix { if !suffix {
return false return "", false
} }
roomID, ok := b.getMapping(utils.Mailbox(email)) roomID, ok := b.getMapping(utils.Mailbox(email))
if !ok { if !ok {
return false return "", false
} }
cfg, err := b.getRoomSettings(roomID) cfg, err := b.getRoomSettings(roomID)
if err != nil { if err != nil {
b.log.Error("failed to retrieve settings: %v", err) b.log.Error("failed to retrieve settings: %v", err)
return false return "", false
}
if cfg.NoSend() {
b.log.Warn("trying to send email from %q (%q), but it's receive-only", email, roomID)
return "", false
} }
allow, err := argon2pw.CompareHashWithPassword(cfg.Password(), password) allow, err := argon2pw.CompareHashWithPassword(cfg.Password(), password)
if err != nil { if err != nil {
b.log.Warn("Password for %s is not valid: %v", email, err) b.log.Warn("Password for %s is not valid: %v", email, err)
} }
return allow return roomID, allow
} }

View File

@@ -40,7 +40,7 @@ type Manager struct {
} }
type matrixbot interface { type matrixbot interface {
AllowAuth(string, string) bool AllowAuth(string, string) (id.RoomID, bool)
IsGreylisted(net.Addr) bool IsGreylisted(net.Addr) bool
IsBanned(net.Addr) bool IsBanned(net.Addr) bool
Ban(net.Addr) Ban(net.Addr)

View File

@@ -47,20 +47,23 @@ func (m *mailServer) Login(state *smtp.ConnectionState, username, password strin
return nil, ErrBanned return nil, ErrBanned
} }
if !m.bot.AllowAuth(username, password) { roomID, allow := m.bot.AllowAuth(username, password)
if !allow {
m.log.Debug("username=%s or password=<redacted> is invalid", username) m.log.Debug("username=%s or password=<redacted> is invalid", username)
m.bot.Ban(state.RemoteAddr) m.bot.Ban(state.RemoteAddr)
return nil, ErrBanned return nil, ErrBanned
} }
return &outgoingSession{ return &outgoingSession{
ctx: sentry.SetHubOnContext(context.Background(), sentry.CurrentHub().Clone()), ctx: sentry.SetHubOnContext(context.Background(), sentry.CurrentHub().Clone()),
sendmail: m.SendEmail, sendmail: m.SendEmail,
privkey: m.bot.GetDKIMprivkey(), privkey: m.bot.GetDKIMprivkey(),
from: username, from: username,
log: m.log, log: m.log,
domains: m.domains, domains: m.domains,
tos: []string{}, getRoomID: m.bot.GetMapping,
fromRoom: roomID,
tos: []string{},
}, nil }, nil
} }

View File

@@ -48,9 +48,10 @@ func (s *incomingSession) Mail(from string, opts smtp.MailOptions) error {
func (s *incomingSession) Rcpt(to string) error { func (s *incomingSession) Rcpt(to string) error {
sentry.GetHubFromContext(s.ctx).Scope().SetTag("to", to) sentry.GetHubFromContext(s.ctx).Scope().SetTag("to", to)
s.tos = append(s.tos, to) s.tos = append(s.tos, to)
hostname := utils.Hostname(to)
var domainok bool var domainok bool
for _, domain := range s.domains { for _, domain := range s.domains {
if utils.Hostname(to) == domain { if hostname == domain {
domainok = true domainok = true
break break
} }
@@ -105,14 +106,16 @@ func (s *incomingSession) Logout() error { return nil }
// outgoingSession represents an SMTP-submission session sending emails from external scripts, using postmoogle as SMTP server // outgoingSession represents an SMTP-submission session sending emails from external scripts, using postmoogle as SMTP server
type outgoingSession struct { type outgoingSession struct {
log *logger.Logger log *logger.Logger
sendmail func(string, string, string) error sendmail func(string, string, string) error
privkey string privkey string
domains []string domains []string
getRoomID func(string) (id.RoomID, bool)
ctx context.Context ctx context.Context
tos []string tos []string
from string from string
fromRoom id.RoomID
} }
func (s *outgoingSession) Mail(from string, opts smtp.MailOptions) error { func (s *outgoingSession) Mail(from string, opts smtp.MailOptions) error {
@@ -120,6 +123,28 @@ func (s *outgoingSession) Mail(from string, opts smtp.MailOptions) error {
if !email.AddressValid(from) { if !email.AddressValid(from) {
return errors.New("please, provide email address") return errors.New("please, provide email address")
} }
hostname := utils.Hostname(from)
var domainok bool
for _, domain := range s.domains {
if hostname == domain {
domainok = true
break
}
}
if !domainok {
s.log.Debug("wrong domain of %s", from)
return ErrNoUser
}
roomID, ok := s.getRoomID(utils.Mailbox(from))
if !ok {
s.log.Debug("mapping for %s not found", from)
return ErrNoUser
}
if s.fromRoom != roomID {
s.log.Warn("sender from %q tries to impersonate %q", s.fromRoom, roomID)
return ErrNoUser
}
return nil return nil
} }