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
func (b *Bot) AllowAuth(email, password string) bool {
func (b *Bot) AllowAuth(email, password string) (id.RoomID, bool) {
var suffix bool
for _, domain := range b.domains {
if strings.HasSuffix(email, "@"+domain) {
@@ -134,22 +134,27 @@ func (b *Bot) AllowAuth(email, password string) bool {
}
}
if !suffix {
return false
return "", false
}
roomID, ok := b.getMapping(utils.Mailbox(email))
if !ok {
return false
return "", false
}
cfg, err := b.getRoomSettings(roomID)
if err != nil {
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)
if err != nil {
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 {
AllowAuth(string, string) bool
AllowAuth(string, string) (id.RoomID, bool)
IsGreylisted(net.Addr) bool
IsBanned(net.Addr) bool
Ban(net.Addr)

View File

@@ -47,20 +47,23 @@ func (m *mailServer) Login(state *smtp.ConnectionState, username, password strin
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.bot.Ban(state.RemoteAddr)
return nil, ErrBanned
}
return &outgoingSession{
ctx: sentry.SetHubOnContext(context.Background(), sentry.CurrentHub().Clone()),
sendmail: m.SendEmail,
privkey: m.bot.GetDKIMprivkey(),
from: username,
log: m.log,
domains: m.domains,
tos: []string{},
ctx: sentry.SetHubOnContext(context.Background(), sentry.CurrentHub().Clone()),
sendmail: m.SendEmail,
privkey: m.bot.GetDKIMprivkey(),
from: username,
log: m.log,
domains: m.domains,
getRoomID: m.bot.GetMapping,
fromRoom: roomID,
tos: []string{},
}, nil
}

View File

@@ -48,9 +48,10 @@ func (s *incomingSession) Mail(from string, opts smtp.MailOptions) error {
func (s *incomingSession) Rcpt(to string) error {
sentry.GetHubFromContext(s.ctx).Scope().SetTag("to", to)
s.tos = append(s.tos, to)
hostname := utils.Hostname(to)
var domainok bool
for _, domain := range s.domains {
if utils.Hostname(to) == domain {
if hostname == domain {
domainok = true
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
type outgoingSession struct {
log *logger.Logger
sendmail func(string, string, string) error
privkey string
domains []string
log *logger.Logger
sendmail func(string, string, string) error
privkey string
domains []string
getRoomID func(string) (id.RoomID, bool)
ctx context.Context
tos []string
from string
ctx context.Context
tos []string
from string
fromRoom id.RoomID
}
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) {
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
}