#include "__SMTP_MAIL.h" #include "SMTPServer.h" #include "SPFChecker.h" namespace mail { int __SMTP_MAIL::processCommand(coreutils::ZString &request, SMTPSession &session, SMTPServer &server) { if(request[1].ifNext("FROM:")) { request[1].skipWhitespace(); if(request[1].ifNext("<")) { session.from = request[1].getTokenExclude(">"); // Deliberately unconditional - not gated on authState. A // receiving MX server accepts MAIL FROM addressed to its own // local mailboxes from anyone; sending MTAs never AUTH to a // destination domain, only to their own outbound smarthost. // Authentication only needs to gate relaying to a NON-local // recipient, which __SMTP_RCPT.cpp already does via // session.relay. This used to be // `if(session.authState = USER_KNOWN)` - an assignment, not // a comparison - which accidentally produced this same // "always accept" behavior; a literal `==` fix would instead // have started rejecting all normal inbound mail. session.out << "250 OK" << CRLF; session.recipientList.clear(); session.state = MAIL; // RFC 7208 2.4: the identity to check is the MAIL FROM // address's own domain, or - for the null reverse-path <> // bounce messages use, which has no domain of its own - the // HELO/EHLO domain instead. Computed here (not deferred to // DATA) since MAIL FROM is where the RFC actually anchors the // check; DATA just reuses the result via session.spfHeader // rather than re-running the DNS lookups a second time. This // does block this connection's EPoll worker thread for // however long the SPF DNS lookups take (matching // SendMail::lookupMX()'s own res_query() calls, which are // synchronous the same way) - acceptable for a well-behaved // sender domain, not for a slow/hostile one, same tradeoff // already accepted elsewhere in this codebase rather than a // new one introduced here. std::string fromStr = session.from.str(); size_t at = fromStr.find_last_of('@'); std::string spfDomain = (at == std::string::npos) ? session.clientDomainName.str() : fromStr.substr(at + 1); std::string clientIP = session.ipAddress.getClientAddress(); session.spfDomain = spfDomain; session.spfResult = SPFChecker::check(spfDomain, clientIP); session.spfHeader = SPFChecker::receivedSPFHeader(session.spfResult, spfDomain, clientIP, session.clientDomainName.str(), server.hostName); } else session.out << "550 Usage: MAIL FROM:" << CRLF; } else session.out << "550 Usage: MAIL FROM:" << CRLF; return 1; } }