diff options
| author | Alejandro Soto <alejandro@34project.org> | 2025-08-24 18:55:06 -0600 |
|---|---|---|
| committer | Alejandro Soto <alejandro@34project.org> | 2025-08-24 18:55:06 -0600 |
| commit | d7ac88762db111a7962c4e14b5f4e37ab85ccac7 (patch) | |
| tree | 0c2c8c4383bef74215e3b7c48a2f6b0117f084bc /sys/mail/default.nix | |
| parent | 504589d1035f27b766bd33040b415b2725ece4ca (diff) | |
tree-wide: reformat using alejandra after enabling trivionomicon
Diffstat (limited to 'sys/mail/default.nix')
| -rw-r--r-- | sys/mail/default.nix | 328 |
1 files changed, 164 insertions, 164 deletions
diff --git a/sys/mail/default.nix b/sys/mail/default.nix index 6eba9cd..f87b6fe 100644 --- a/sys/mail/default.nix +++ b/sys/mail/default.nix @@ -1,4 +1,9 @@ -{ config, lib, pkgs, ... }: +{ + config, + lib, + pkgs, + ... +}: with lib; let cfg = config.local.mailHost; imapHostname = config.local.domains.imap.main; @@ -6,8 +11,7 @@ with lib; let cert = config.security.acme.certs.${imapHostname}.directory; inherit (config.local) users virtual; -in -{ +in { options.local.mailHost = { enable = mkEnableOption "mailbox host service"; @@ -45,7 +49,7 @@ in mailUser = "vmail"; mailGroup = "vmail"; mailLocation = "maildir:~/mail"; - mailPlugins.perProtocol.lmtp.enable = [ "sieve" ]; + mailPlugins.perProtocol.lmtp.enable = ["sieve"]; # https://github.com/NixOS/nixpkgs/issues/286859 sieve.extensions = [ @@ -53,168 +57,164 @@ in "mailbox" ]; - extraConfig = - let - inherit (config.networking) domain; - - # https://dovecot.org/list/dovecot/2019-March/115250.html - # Otra solución posible (https://serverfault.com/a/1062274/980378): - # auth_username_format = %{if;%d;eq;${domain};%Ln;%Lu} - localEntry = canonical: username: '' - ${username}:::::::user=${canonical} nopassword userdb_user=${canonical} - ''; - - localMailboxes = - pkgs.writeText "local-mailboxes" - (concatStrings - (flatten (mapAttrsToList - (canonical: user: - map (localEntry canonical) ([ canonical ] ++ user.hardAliases)) - users))); - - localCerts = - flatten (mapAttrsToList - (canonical: user: - let - certNames = { - inherit canonical; - logins = [ canonical ] ++ user.hardAliases; - }; - in - map (flip nameValuePair certNames) user.mail.certs) - users); - - vmailCerts = - flatten (flatten (mapAttrsToList - (domain: virtual: mapAttrsToList - (username: user: - let - address = "${username}@${domain}"; - - certNames = { - canonical = address; - logins = [ address ]; - }; - in - map (flip nameValuePair certNames) user.mail.certs) - virtual.users) - virtual)); - - certLogins = - pkgs.writeText "cert-logins" - (concatLines (flatten (mapAttrsToList - (certPath: names: map - (addr: "${config.local.pki.byPath.${certPath}.commonName}@nodomain,${addr}:::::::user=${names.canonical}") - names.logins) - (listToAttrs (localCerts ++ vmailCerts))))); - - vmailPath = "/var/lib/vmail/%{if;%d;ne;;%Ld;${domain}}"; - in - '' - auth_mechanisms = plain login external - - ssl_ca = <${config.local.pki.ca.mail.fullchain} - ssl_require_crl = yes - ssl_verify_client_cert = yes - - # Esto descarta @domain.tld de locales explícitos, pero lo exige para los demás. - # Implicación: locales implícitos sin dominio fallan en autenticar - auth_username_format = %{if;%Ld;eq;${domain};%Ln;%{if;%d;ne;;%Lu;%Ln@nodomain}} - auth_ssl_username_from_cert = yes - - # TODO: los defaults de nixpkgs dejan los sockets bajo - # /run/dovecot2 con demasiados permisos rwx, arreglar - - service auth { - inet_listener mta-sasl { - port = ${toString cfg.saslPort} - address = ${cfg.mdaListen} - } - } - - service lmtp { - inet_listener mta-lmtp { - port = ${toString cfg.lmtpPort} - address = ${cfg.mdaListen} - } - } - - # FIXME: Esta cadena de passdbs hace que 'doveadm user lookup' - # falle para usuarios locales, pero todo lo demás sirve. Parece - # ser debido a que pam no puede enumerar. - - passdb { - driver = static - args = nopassword - - master = yes - mechanisms = external - - result_success = continue-fail - result_failure = return-fail - result_internalfail = return-fail - } - - passdb { - driver = passwd-file - args = scheme=PLAIN username_format=%{master_user},%Lu ${certLogins} - - mechanisms = external - override_fields = nopassword - - result_failure = return-fail - result_internalfail = return-fail - } - - passdb { - driver = passwd-file - args = username_format=%Ln ${vmailPath}/passwd - } - - passdb { - driver = passwd-file - args = scheme=PLAIN ${localMailboxes} - - # Esta es una forma de determinar si se encontró el usuario en - # el passwd-file por medio de nopassword sin realmente - # autenticarlo. Cuidado con result_success, porque si eso se - # configura mal se permite inicio de sesión con cualquier - # contraseña (!!!). - result_success = continue - result_failure = return-fail - result_internalfail = return-fail - - username_filter = !*@* - } + extraConfig = let + inherit (config.networking) domain; - passdb { - driver = pam - args = dovecot2 - username_filter = !*@* - #TODO: algo como 'override_fields = allow_nets=...' - } - - userdb { - driver = passwd-file - args = username_format=%Ln ${vmailPath}/passwd - override_fields = uid=vmail gid=vmail home=${vmailPath}/home/%Ln - } - - userdb { - driver = passwd-file - args = ${localMailboxes} + # https://dovecot.org/list/dovecot/2019-March/115250.html + # Otra solución posible (https://serverfault.com/a/1062274/980378): + # auth_username_format = %{if;%d;eq;${domain};%Ln;%Lu} + localEntry = canonical: username: '' + ${username}:::::::user=${canonical} nopassword userdb_user=${canonical} + ''; - result_success = continue-ok - result_internalfail = return-fail - skip = found + localMailboxes = + pkgs.writeText "local-mailboxes" + (concatStrings + (flatten (mapAttrsToList + (canonical: user: + map (localEntry canonical) ([canonical] ++ user.hardAliases)) + users))); + + localCerts = flatten (mapAttrsToList + (canonical: user: let + certNames = { + inherit canonical; + logins = [canonical] ++ user.hardAliases; + }; + in + map (flip nameValuePair certNames) user.mail.certs) + users); + + vmailCerts = flatten (flatten (mapAttrsToList + (domain: virtual: + mapAttrsToList + (username: user: let + address = "${username}@${domain}"; + + certNames = { + canonical = address; + logins = [address]; + }; + in + map (flip nameValuePair certNames) user.mail.certs) + virtual.users) + virtual)); + + certLogins = + pkgs.writeText "cert-logins" + (concatLines (flatten (mapAttrsToList + (certPath: names: + map + (addr: "${config.local.pki.byPath.${certPath}.commonName}@nodomain,${addr}:::::::user=${names.canonical}") + names.logins) + (listToAttrs (localCerts ++ vmailCerts))))); + + vmailPath = "/var/lib/vmail/%{if;%d;ne;;%Ld;${domain}}"; + in '' + auth_mechanisms = plain login external + + ssl_ca = <${config.local.pki.ca.mail.fullchain} + ssl_require_crl = yes + ssl_verify_client_cert = yes + + # Esto descarta @domain.tld de locales explícitos, pero lo exige para los demás. + # Implicación: locales implícitos sin dominio fallan en autenticar + auth_username_format = %{if;%Ld;eq;${domain};%Ln;%{if;%d;ne;;%Lu;%Ln@nodomain}} + auth_ssl_username_from_cert = yes + + # TODO: los defaults de nixpkgs dejan los sockets bajo + # /run/dovecot2 con demasiados permisos rwx, arreglar + + service auth { + inet_listener mta-sasl { + port = ${toString cfg.saslPort} + address = ${cfg.mdaListen} } + } - userdb { - driver = passwd - args = blocking=no - skip = notfound + service lmtp { + inet_listener mta-lmtp { + port = ${toString cfg.lmtpPort} + address = ${cfg.mdaListen} } - ''; + } + + # FIXME: Esta cadena de passdbs hace que 'doveadm user lookup' + # falle para usuarios locales, pero todo lo demás sirve. Parece + # ser debido a que pam no puede enumerar. + + passdb { + driver = static + args = nopassword + + master = yes + mechanisms = external + + result_success = continue-fail + result_failure = return-fail + result_internalfail = return-fail + } + + passdb { + driver = passwd-file + args = scheme=PLAIN username_format=%{master_user},%Lu ${certLogins} + + mechanisms = external + override_fields = nopassword + + result_failure = return-fail + result_internalfail = return-fail + } + + passdb { + driver = passwd-file + args = username_format=%Ln ${vmailPath}/passwd + } + + passdb { + driver = passwd-file + args = scheme=PLAIN ${localMailboxes} + + # Esta es una forma de determinar si se encontró el usuario en + # el passwd-file por medio de nopassword sin realmente + # autenticarlo. Cuidado con result_success, porque si eso se + # configura mal se permite inicio de sesión con cualquier + # contraseña (!!!). + result_success = continue + result_failure = return-fail + result_internalfail = return-fail + + username_filter = !*@* + } + + passdb { + driver = pam + args = dovecot2 + username_filter = !*@* + #TODO: algo como 'override_fields = allow_nets=...' + } + + userdb { + driver = passwd-file + args = username_format=%Ln ${vmailPath}/passwd + override_fields = uid=vmail gid=vmail home=${vmailPath}/home/%Ln + } + + userdb { + driver = passwd-file + args = ${localMailboxes} + + result_success = continue-ok + result_internalfail = return-fail + skip = found + } + + userdb { + driver = passwd + args = blocking=no + skip = notfound + } + ''; }; fail2ban.jails.dovecot.settings = { @@ -225,12 +225,12 @@ in security = { # Necesario debido a 'enablePAM = false' - pam.services.dovecot2 = { }; + pam.services.dovecot2 = {}; acme.certs.${imapHostname} = { inherit (config.services.dovecot2) group; - reloadServices = [ "dovecot2.service" ]; + reloadServices = ["dovecot2.service"]; }; }; @@ -239,7 +239,7 @@ in groups.${config.services.dovecot2.mailGroup}.gid = 993; }; - networking.firewall.allowedTCPPorts = [ 143 993 ]; + networking.firewall.allowedTCPPorts = [143 993]; local.certs.imap.enable = true; }; |
