sender check: the sender map read and looked up as Postfix does it

Postfix 3.7.11 takes the owners of the first key mail_addr_find() finds -
the address, then without its extension, then @domain, each tried only
when the one before is absent (src/global/mail_addr_find.c,
mail_addr_find_opt()) - and compares the login with them by
strcasecmp_utf8() (src/smtpd/smtpd_check.c,
reject_auth_sender_login_mismatch()). The check accepted a From: address
when any of the three keys named the application: an application holding
@domain could write an address listed for another application of the
domain, which Postfix refuses it in the envelope, and have it signed
(assumptions B-PS1).

The table is now read as dict_thash_open() reads it: continuation lines,
owners split on commas and blanks (B-PS4), the key ending at the first
blank outside quotes, keys folded; a key given twice makes Postfix refuse
the whole table (no DICT_FLAG_DUP_* flag), and the check then defers too.
The writer folds keys, so two cases of one address cannot be two lines.

e2e on the stand (2026-10-14, make e2e, exit 0): the wildcard application
is refused billing@ - listed for app-list - in From: (550 5.7.1), and in
the envelope by Postfix at RCPT ("553 5.7.1 <billing@...>: Sender address
rejected: not owned by user"). go vet and go test ./... pass on the
server (23 packages).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
mix
2026-10-14 20:03:34 +03:00
co-authored by Claude Opus 5.5
parent 31c2b50457
commit 55aef6e721
8 changed files with 262 additions and 53 deletions
+12
View File
@@ -17,6 +17,18 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); version
both exceptions off; tried against rspamd 3.11.1 before and after
(audit 2026-10-12, stage 2c; assumptions C-R7). Copy the new
`antispam/rspamd/` files next to your compose fragment.
- **An address listed for one application could be put in `From:` by
another of its domain.** The sender check accepted a `From:` address when
any of its keys in the sender map - the address, the address without its
extension, the domain - named the application; Postfix takes the first
key it finds and asks only its owners. An application set to any address
of a domain could therefore write in `From:` an address listed for
another application of that domain - which Postfix refuses it in the
envelope - and have it signed. The check now reads the map as Postfix
does: the first key found decides, logins are compared without regard to
case, owners may be separated by blanks or continue on the next line, and
a key written twice makes the check defer, as it makes Postfix refuse the
whole table (assumptions B-PS1, B-PS4).
### Fixed