Files
BARANTMail/BARANTMailConfig.h
T
Brad Arant e8b2a79907 Add authenticated domain/mailbox/alias/password admin console
Port 1027 used to be an unauthenticated console (see ServerCore's
ConsoleServer/ConsoleSession fix) that also exposed the raw SMTP
command set (AUTH/DATA/EHLO/EXPN/HELO/...) to anyone who could reach
it. It's now started only when barantmail.cfg has a real "admin"
section configured (BARANTMailConfig::hasAdmin/getAdminPort/
getAdminUser/getAdminPassword), matching the same optional-listener
pattern already used for smtpTLS/imap/pop3, and registers four real
commands instead of the SMTP command table:

  domain add|remove|list
  mailbox add|remove|list
  alias add|remove|list
  password reset

MailFileSystem gained the actual domain/mailbox/alias/password CRUD
these commands call (createDomain/removeDomain/listDomains,
createMailbox/removeMailbox/listMailboxes, createAlias/removeAlias/
listAliases, setPassword), matching its existing on-disk layout: a
domain is a directory, a mailbox is a directory with Inbox/Spam/Trash
and a .password file, an alias is a plain file listing target
mailboxes one per line.

getAliasMailboxes() was previously an unconditional stub that always
returned empty (confirmed via grep to have zero callers anywhere),
so an alias could be "created" but could never actually receive mail.
It's now wired for real: SMTPServer::inCreate() checks
ifAliasExists()/getAliasMailboxes() during local delivery and copies
the same spam-scanned message to every target mailbox (extracted into
a new deliverToMailbox() helper so the alias and single-mailbox
delivery paths share it).
2026-09-06 04:08:57 +00:00

118 lines
3.6 KiB
C++

#ifndef __BARANTMailConfig_h__
#define __BARANTMailConfig_h__
#include "TLSInfo.h"
#include <string>
namespace coreutils { class JFile; }
namespace mail {
///
/// Server startup configuration, loaded from a JSON file via
/// CoreUtils' JFile - mirrors APIServer's own ApiServerConfig (see
/// that class's doc comment for JFile's create-on-missing behavior).
///
/// Schema:
/// {
/// "hostName": "mail.example.com",
/// "mailPath": "/var/mail",
/// "smtp": { "port": 25 },
/// "smtpTLS": { "port": 465 },
/// "imap": { "port": 993 },
/// "pop3": { "port": 995 },
/// "tls": {
/// "certificate": "/path/to/fullchain.pem",
/// "key": "/path/to/privkey.pem",
/// "caCertificate": "/path/to/ca.pem"
/// },
/// "dkim": {
/// "domain": "mail.example.com",
/// "selector": "default",
/// "privateKey": "/path/to/dkim_private.pem"
/// }
/// }
///
/// "hostName", "mailPath", and "smtp.port" are required - plain port
/// 25 is the one listener every deployment needs (an inbound peer
/// MTA relaying mail in has no TLS-first negotiation to fall back
/// on). "smtpTLS"/"imap"/"pop3" are each independently optional -
/// leaving one out just means that listener isn't started, so this
/// same file covers a plaintext-only relay just as well as a full
/// mail server. The moment any one of those three IS present,
/// "tls.certificate" and "tls.key" become required - there is no
/// path through this class that hands back a submission/IMAPS/POP3S
/// listener request without a real certificate configured for it.
/// "dkim" is entirely optional - outbound mail goes out unsigned
/// unless all three of its fields are present.
///
class BARANTMailConfig {
public:
BARANTMailConfig(const std::string &path);
~BARANTMailConfig();
std::string getHostName();
std::string getMailPath();
int getSmtpPort();
bool hasSmtpTLS();
int getSmtpTLSPort();
bool hasImap();
int getImapPort();
bool hasPop3();
int getPop3Port();
///
/// NULL if none of smtpTLS/imap/pop3 are configured. Owned by
/// this BARANTMailConfig, valid for as long as it is - pass
/// straight through to a server's tlsInfo parameter, do not
/// delete, and don't let this config object go out of scope
/// while a server built from this pointer is still running.
///
core::TLSInfo *getTlsInfo();
bool hasDkim();
std::string getDkimDomain();
std::string getDkimSelector();
std::string getDkimPrivateKeyPath();
///
/// The admin console (see ConsoleServer/ConsoleSession) - "port"
/// defaults to 1027 if omitted. "user"/"password" are required
/// once "admin" is present at all; there is no path through this
/// class that hands back an admin listener with nothing to check
/// logins against.
///
bool hasAdmin();
int getAdminPort();
std::string getAdminUser();
std::string getAdminPassword();
private:
coreutils::JFile *file;
// Owned, persistent storage for the TLSInfo fields below -
// TLSInfo's own ZString members are non-owning views, so they
// have to point at something that outlives them; pointing them at
// temporary std::strings decoded during construction would leave
// them dangling the moment this constructor returned.
std::string certPath, keyPath, caPath;
core::TLSInfo tlsInfo;
bool hasTls = false;
};
}
#endif