GhostManSec
Server: Apache
System: Linux s323.xrea.com 5.15.0-164-generic #174-Ubuntu SMP Fri Nov 14 20:25:16 UTC 2025 x86_64
User: moonarc (17751)
PHP: 8.1.34
Disabled: NONE
Upload Files
File: //run/dovecot/dovecot.conf
#########################################################################
# dovecot.conf — XREA/CORE V1/VS mail engine template (Q2E-7, Model A)
#
# Target: Dovecot 2.3.x (MT boxes run 2.3.16). 2.4 changed the passdb
# args/%d syntax — do NOT validate this file with a 2.4 doveconf.
#
# Static per-container daemon config. The exim_dovecot_make.pl generator
# maintains ONLY the per-domain passwd-file pair referenced below:
#   /etc/dovecot/vusers/<domain>/passwd  (passdb, {BLF-CRYPT} bcrypt cost11, 0640)
#   /etc/dovecot/vusers/<domain>/users   (userdb: uid=89 gid=89 home=/virtual/<ID>)
#
# Drafted by Dev AI (parity knowledge) — deployed/tuned/canonicalized by
# Infra on the MT boxes. Open items are marked TODO(...).
#
# Generated-by: Claude Dev AI (Q2E-7 draft for MT)
#########################################################################

protocols = imap pop3 lmtp

# ---- Model A (Infra final, 2026-06-06) --------------------------------
# Dovecot accesses mail as vpopmail(89):vchkpw(89) — the owner of every
# existing mail file (0600). Zero chown/chmod I/O at cutover.
# first_valid_uid MUST admit uid 89 (default 500 would reject it).
first_valid_uid = 89
last_valid_uid  = 89
first_valid_gid = 89

# real-path mail location (Infra 6/6 correction): /home/vpopmail/domains is
# 0700 vpopmail and partially hash-sharded => the symlink path is unusable.
# The real path is FLAT for both domain and account:
#   /virtual/<ID>/Maildir/<domain>/<account>/Maildir
# %h comes from the generator userdb (home=/virtual/<ID>); %d/%n from login.
mail_location = maildir:%h/Maildir/%d/%n/Maildir

# ---- courier-compatible namespace (plan §2.1, D-7) ---------------------
# SquirrelMail keeps imap_server_type='courier'; existing folders are
# Maildir++ (".Sent" etc) and MUST appear as INBOX.* — do not use LAYOUT=fs.
namespace inbox {
  type          = private
  separator     = .
  prefix        = INBOX.
  inbox         = yes
  list          = yes
  subscriptions = yes
}
# 15-mailboxes.conf-style autocreate/special-use is intentionally absent
# (duplicate special folders would appear next to the migrated ones).

# ---- authentication ----------------------------------------------------
# Username = full email address (courier authvchkpw parity).
auth_mechanisms = plain login

# ---- Courier parity: `user%domain` login names (2026-08-12, SPT/670809) ----------
# vpopmail treats '%' as an alias for '@' (verified read-only with `vuserinfo user%domain`
# resolving identically to user@domain). Courier authenticated through authvchkpw and so
# accepted `user%domain`; a number of customer mail clients are configured that way.
# Dovecot does NOT: '%' is absent from auth_username_chars, so it is rewritten to '_'
# before the userdb lookup and every such login fails (measured on s87: 2,958 successes
# in the pure-Courier week -> 0 successes / 210 failures after cutover; fleet: 13 hosts,
# 51 users, 0 successes). SMTP submission fails too (exim 535 with set_id=...%...).
# Translating '%' -> '@' restores parity. Safe: no account has '%' in its local part
# (checked vusers + vpasswd on 8 hosts = 0 hits).
# See work-logs/2026-08-12/q2e-courier-meta-migration-gap.md
auth_username_translation = %@

# PLAIN/LOGIN only (CEO 2026-06-06). APOP/CRAM-MD5/DIGEST-MD5 dropped: a one-way
# {BLF-CRYPT} passdb cannot serve challenge-response. Live capture (s1000, 6/6)
# confirmed the only live challenge-response was POP3 APOP — dropped (mitigation:
# POP3S/995). This is an algorithm requirement, not a config toggle.

# POP3/IMAP without TLS exist on the current fleet (parity); TLS is OFFERED but NOT
# enforced (CEO 6/6 — keeps legacy clients). Future observe->enforce is held in reserve.
disable_plaintext_auth = no

passdb {
  driver = passwd-file
  args   = /etc/dovecot/vusers/%d/passwd
}
userdb {
  driver = passwd-file
  args   = /etc/dovecot/vusers/%d/users
  # TODO(MT): per-user quota — candidate is a userdb extra field
  #   quota_rule=*:bytes=<N>
  # appended by the generator (value currently parked in the routes table).
  # The ':' inside the value vs passwd-file field separators must be verified
  # on 2.3.16 (Infra 6/6 found per-user mail= colon values broken; extra
  # fields are space-separated AFTER the 7th field so quota_rule may be fine).
  # Fallback: dict quota or a global quota_rule with %{userdb:...}.
}

# ---- quota (Maildir++ maildirsize compatible, D-1) ----------------------
mail_plugins = $mail_plugins quota
plugin {
  quota = maildir:User quota
  # enforcement limits arrive per-user via userdb quota_rule (see above);
  # absent rule = unlimited (generator omits the rule for quota=0).
}

protocol imap {
  mail_plugins = $mail_plugins imap_quota
}

protocol pop3 {
  # TODO(Q2E-18, live): courier-compatible UIDL so POP3 clients do not
  # re-download everything. Candidate for courier migration:
  #   pop3_uidl_format = %f
  # (courier's UIDL derives from the maildir filename). MUST be confirmed
  # against a live courier UIDL capture before M4.
  pop3_uidl_format = %08Xu%08Xv
}

# ---- services: LMTP for Exim local delivery + SASL for Exim SMTP AUTH ---
# PER-OS socket owner: the listener `user` MUST equal the OS's Exim run-user, else Exim
# cannot connect → LMTP local delivery AND SMTP AUTH both fail (k1 soak finding; fleet
# blocker). FLEET DEFAULT = AlmaLinux/EL exim user `exim` (the 712-container fleet is
# AlmaLinux). Debian/dev (exim4) overrides to `Debian-exim` at deploy. `group = mail` +
# mode 0660 also lets any mail-group Exim connect. The M5 runner verifies the connecting
# exim user matches this owner (contract C11).
service lmtp {
  unix_listener lmtp {
    # Exim's dovecot_lmtp transport connects here (runs as the OS exim user)
    mode  = 0660
    user  = exim          # AlmaLinux/EL fleet default; Debian deploy overrides to Debian-exim
    group = mail
  }
}

service auth {
  unix_listener auth-client {
    # Exim's "dovecot" authenticator socket (server_socket in exim.conf)
    mode  = 0660
    user  = exim          # AlmaLinux/EL fleet default; Debian deploy overrides to Debian-exim
    group = mail
  }
}

# LMTP writes as the userdb uid (89) — Model A.
# ⚠️ TODO(MT, CEO-acknowledged): new-mail file mode. Dovecot derives maildir
# FILE modes from the maildir DIRECTORY mode (0770 dir => 0660 files), so the
# agreed "new mail 0644 (user-readable over FTP/shell)" is NOT automatic.
# Candidate: keep the security boundary at the parent dir (0770) and relax
# cur/new/tmp to 0755 so files come out 0644. If MT shows this cannot be done
# cleanly, fallback = files stay 0660 (customers keep IMAP/POP/Webmail access;
# no regression vs today where files are 0600 vpopmail-owned).

# ---- TLS ----------------------------------------------------------------
# TODO(Q2E-42): certificates + SNI (local_name blocks) + cipher list — Infra provisions.
ssl = yes
# TLS 1.2/1.3 offered, 1.0/1.1 disabled (mail-auth-security-baseline §TLS, RFC 8996/BCP195)
ssl_min_protocol = TLSv1.2
ssl_cert = </etc/dovecot/ssl/dovecot.crt
ssl_key  = </etc/dovecot/ssl/dovecot.key
#local_name mail.example.com {
#  ssl_cert = </etc/dovecot/ssl/mail.example.com.crt
#  ssl_key  = </etc/dovecot/ssl/mail.example.com.key
#}

# ---- logging / misc ------------------------------------------------------
log_path = syslog
syslog_facility = mail
# NOTE (corrected 2026-08-12): `courier-dovecot-migrate.pl` is NOT run at cutover.
# Q2E-19 deliberately skips it (migrate.pl writes uidlist entries carrying the old `,S=`
# filenames, and the mandatory `,S=` rename that follows orphans them -> POP3 breaks).
# Consequence, accepted and announced (告知890, 8/8): one-time client re-download.
# 🔴 Subscriptions were lost as collateral damage of that skip and are NOT part of the
# accepted trade-off — `subscriptions` holds folder names only, so it never conflicted
# with the `,S=` rename. Restored separately by
# `scripts/q2e_courier_subscriptions_restore.sh` (add-only, existing folders only).
# See work-logs/2026-08-12/q2e-courier-meta-migration-gap.md

## SPT/670714 login process_limit (2026-07-28)
## Required for cutover: conf.d drop-in is NOT auto-included without this line.
!include conf.d/99-login-process-limit.conf