diff options
-rw-r--r-- | machines/mailserver.nix | 114 | ||||
-rw-r--r-- | modules/postfix/restrictions.nix | 53 |
2 files changed, 167 insertions, 0 deletions
diff --git a/machines/mailserver.nix b/machines/mailserver.nix new file mode 100644 index 00000000..e3f6f847 --- /dev/null +++ b/machines/mailserver.nix @@ -0,0 +1,114 @@ +{ config, pkgs, lib, ... }: let + vhostMap = { + smtpd_sender_login_maps = [ + "SELECT username AS allowedUser" + "FROM mailbox" + "WHERE username='%s' AND active = 1" + "UNION SELECT goto FROM alias" + "WHERE address='%s' AND active = 1" + ]; + + virtual_alias_maps = [ + "SELECT goto" + "FROM alias" + "WHERE address='%s' AND active = '1'" + ]; + + virtual_mailbox_domains = [ + "SELECT domain" + "FROM domain" + "WHERE domain='%s' AND active = '1'" + ]; + + virtual_mailbox_maps = [ + "SELECT maildir" + "FROM mailbox" + "WHERE username='%s' AND active = '1'" + ]; + }; + + mkDbMap = query: "proxy:pgsql:${pkgs.writeText "database.cf" '' + hosts = localhost + user = postfix + dbname = postfix + query = ${query} + ''}"; + +in { + imports = [ ../modules/postfix/restrictions.nix ]; + services.spamassassin.enable = true; + + services.postfix.enable = true; + services.postfix.hostname = "mailtest.lan"; + + openlab.postfix.restrictions = { + sender = [ + "reject_authenticated_sender_login_mismatch" + "reject_unknown_sender_domain" + ]; + recipient = [ + "permit_sasl_authenticated" + "permit_mynetworks" + "reject_unauth_destination" + "reject_invalid_hostname" + "reject_non_fqdn_hostname" + "reject_non_fqdn_sender" + "reject_non_fqdn_recipient" + "reject_unknown_reverse_client_hostname" + ]; + helo = [ + "permit_sasl_authenticated" + "permit_mynetworks" + "reject_invalid_hostname" + "reject_unauth_pipelining" + "reject_non_fqdn_hostname" + ]; + }; + + services.postfix.extraConfig = '' + ${lib.concatStrings (lib.mapAttrsToList (cfgvar: query: '' + ${cfgvar} = ${mkDbMap (lib.concatStringsSep " " query)} + '') vhostMap)} + + # a bit more spam protection + disable_vrfy_command = yes + + smtpd_sasl_type=dovecot + smtpd_sasl_path=private/auth_dovecot XXXXXXXXXXXXXXX + smtpd_sasl_auth_enable = yes + smtpd_sasl_authenticated_header = yes + broken_sasl_auth_clients = yes + + proxy_read_maps = ${lib.concatStringsSep " " (map (s: "\$${s}") [ + "local_recipient_maps" "mydestination" "virtual_alias_maps" + "virtual_alias_domains" "virtual_mailbox_maps" "virtual_mailbox_domains" + "relay_recipient_maps" "relay_domains" "canonical_maps" + "sender_canonical_maps" "recipient_canonical_maps" "relocated_maps" + "transport_maps" "mynetworks" "smtpd_sender_login_maps" + ])} + + local_transport = virtual + virtual_transport = dovecot + + virtual_uid_maps = static:5000 XXXXXXXXXXXX + virtual_gid_maps = static:5000 XXXXXXXXXXXX + + smtpd_tls_cert_file=/etc/ssl/mail.crt XXXX: KEYS + smtpd_tls_key_file=/etc/ssl/mail.key XXXX: KEYS + smtpd_use_tls=yes + ''; + + services.postfix.extraMasterConf = '' + mailman unix - n n - - pipe + flags=FR user=list argv=/usr/lib/mailman/bin/postfix-to-mailman.py ''${nexthop} ''${user} + # ^^^ FIXME: maybe not needed! + + dovecot unix - n n - - pipe + flags=DRhu user=vmail:vmail argv=/usr/lib/dovecot/deliver -d ''${recipient} + # ^^^ FIXME: maybe not needed! + + spamassassin unix - n n - - pipe + user=${toString config.ids.uids.spamd} argv=${pkgs.spamassassin}/bin/spamc -f -e /var/setuid-wrappers/sendmail -oi -f ''${sender} ''${recipient} + # ^^^ FIXME: maybe not needed! + ''; +} diff --git a/modules/postfix/restrictions.nix b/modules/postfix/restrictions.nix new file mode 100644 index 00000000..8f2412ca --- /dev/null +++ b/modules/postfix/restrictions.nix @@ -0,0 +1,53 @@ +{ config, lib, ... }: + +with lib; + +let + mkRestriction = name: specificDescription: { + option.${name} = mkOption { + default = null; + type = types.nullOr types.list; + description = '' + A list of restrictions to apply or <option>null</option> to use the + built-in default value from Postfix. + ${specificDescription} + ''; + }; + config = let + cfg = config.openlab.postfix.restrictions.${name}; + in mkIf (cfg != null) '' + smtpd_${name}_restrictions = ${concatStringsSep ", " cfg} + ''; + }; + restrictions = mapAttrsToList mkRestriction { + client = mkRestriction '' + SMTP server access restrictions in the context of a client SMTP connection + request. + ''; + data = mkRestriction '' + Access restrictions that the Postfix SMTP server applies in the context of + the SMTP DATA command. + ''; + end_of_data = mkRestriction '' + Access restrictions that the Postfix SMTP server applies in the context of + the SMTP END-OF-DATA command. + ''; + etrn = mkRestriction '' + SMTP server access restrictions in the context of a client ETRN request. + ''; + helo = mkRestriction '' + Restrictions that the Postfix SMTP server applies in the context of the + SMTP HELO command. + ''; + recipient = mkRestriction '' + Access restrictions that the Postfix SMTP server applies in the context of + the RCPT TO command. + ''; + sender = mkRestriction '' + Restrictions that the Postfix SMTP server applies in the context of the + MAIL FROM command. + ''; + }; +in { + options.openlab.postfix.restrictions = mapAttrs mkRestriction restrictions; +} |