https://gitlab.synchro.net/main/sbbs/-/issues/1221#note_10137 ## Implemented, with one correction to the analysis above Items 1-4 of the suggested direction are implemented and validated against a scratch mail server (isolated ctrl/data tree, loopback, high ports). ### Correction: `servprot` cannot identify the submission port The description above says the submission listener's identity "could be captured" from `servprot`, since `servprot_smtp` and `servprot_submission` are separate pointers. **That is wrong**, and item 1 as written does not work: ```c static const char* servprot_smtp = "SMTP"; static const char* servprot_submission = "SMTP"; ``` Both initializers are the *same string literal*, and the compiler pools identical literals into one object, so `servprot_smtp == servprot_submission` is true. Verified with gcc at -O2: comparing the two yields "same pointer", while `servprot_submissions` ("SMTPS") is correctly distinct. The practical effect is that a `smtp->submission` flag set from a pointer comparison is **true on port 25 as well**. This was not visible by reading the code -- it showed up only when the test suite reported the transfer port answering `530 Authentication required.` to an unauthenticated `MAIL FROM`. `tls_port` is unaffected, because "SMTPS" is a distinct literal. The implementation instead derives it from the port actually bound, gated on the corresponding listener option, after the existing `getsockname()`: ```c server_port = inet_addrport(&server_addr); submission = ((startup->options & MAIL_OPT_USE_SUBMISSION_PORT) && server_port == startup->submission_port) || ((startup->options & MAIL_OPT_TLS_SUBMISSION) && server_port == startup->submissions_port); ``` Anyone reading item 1 above should use this approach, not the pointer comparison. ### What landed * Submission ports require SMTP AUTH by default, `530` on `MAIL` otherwise. `[Mail]` `RequireSubmissionAuth` (default `true`) restores the old behavior for sysops with unauthenticated automation pointed at 587. * An authenticated user sending to an external recipient via a submission port no longer consults `ALLOW_RELAY`, which continues to govern port 25. The `G`/`M` restrictions still apply on every port. * Sender verification per port class: `[Mail]` `SenderValidation` (transfer port, default `None`) and `SubmissionSenderValidation` (submission ports, default `User`), each `None` / `Domain` / `User`. Both `MAIL FROM` and the `From:` header are checked. A null reverse-path is still accepted. * The acceptable-sender set is generated from the user record (alias, real name when `MM_REALNAME` is set, sub-address tags) rather than by reverse lookup, so `alias.cfg` entries with external values and a configured `DefaultUser` catch-all cannot authorize a sender. * `mail_startup_t` grows three fields, so `sbbsctrl.exe` needs a rebuild. ### Validation 18 assertions over two configurations, all passing. Notably: unauthenticated `MAIL` gets `530` on 587 but `250` on 25; authenticated submission to an external recipient succeeds on 587 with `ALLOW_RELAY` clear but is still refused on 25; a foreign-domain or another local user's address is refused at `User` strictness and accepted at `Domain`; a forged `From:` header is caught during `DATA` even when `MAIL FROM` was valid. One early test failure turned out to be the test's fault rather than the code's: the scratch instance had inherited a `relay.cfg` listing `127.0.0. 1`, and that trusted-host list legitimately bypasses the `ALLOW_RELAY` gate. ### Not done * **SCFG exposure.** The new settings are `sbbs.ini`-only for now. The Mail Server menu in `scfg/scfgsrvr.c` dispatches on positional `case` indices, so placing these next to "Allow Users to Relay Mail" means renumbering roughly fifteen subsequent cases -- worth doing as its own change. * **`Sender:` stamping** (RFC 6409 section 8.1) at `Domain` strictness, so a shared address records which user actually submitted. Without it, `Domain` permits one local user to send as another. * Item 5 (`Message-ID` generation, `PIPELINING`, `ENHANCEDSTATUSCODES`). Note that responses here use plain reply codes, without enhanced status codes, matching the rest of the file and the fact that `ENHANCEDSTATUSCODES` is not advertised. * Sessions authorized via `SMTP_AUTH_VIA_IP` resolve their user at `RCPT TO`, after `MAIL FROM` has been accepted, so sender validation does not apply to them. They still go through the existing `chk_email_addr()` checks. -- *Authored by Claude (Claude Code), on behalf of @rswindell* --- SBBSecho 3.37-Linux * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
|