2020-01-15 09:24:11 -08:00
|
|
|
{ config, lib, pkgs, environment, ... }:
|
|
|
|
|
|
|
|
with lib;
|
|
|
|
let
|
|
|
|
cfg = config.fudo.mail-server;
|
|
|
|
|
|
|
|
state-directory = "${cfg.state-directory}/dovecot";
|
|
|
|
|
|
|
|
pipe-bin = pkgs.stdenv.mkDerivation {
|
|
|
|
name = "pipe_bin";
|
|
|
|
src = ./dovecot/pipe_bin;
|
|
|
|
buildInputs = with pkgs; [ makeWrapper coreutils bash rspamd ];
|
|
|
|
buildCommand = ''
|
|
|
|
mkdir -p $out/pipe/bin
|
|
|
|
cp $src/* $out/pipe/bin/
|
|
|
|
chmod a+x $out/pipe/bin/*
|
|
|
|
patchShebangs $out/pipe/bin
|
|
|
|
|
|
|
|
for file in $out/pipe/bin/*; do
|
|
|
|
wrapProgram $file \
|
|
|
|
--set PATH "${pkgs.coreutils}/bin:${pkgs.rspamd}/bin"
|
|
|
|
done
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
2020-06-25 20:38:50 -07:00
|
|
|
ldap-conf = filename: config:
|
|
|
|
let
|
|
|
|
ssl-config = if config.ca == null then ''
|
|
|
|
tls = no
|
|
|
|
tls_require_cert = try
|
|
|
|
'' else ''
|
|
|
|
tls_ca_cert_file = ${config.ca}
|
|
|
|
tls = yes
|
|
|
|
tls_require_cert = try
|
|
|
|
'';
|
|
|
|
|
|
|
|
in
|
|
|
|
pkgs.writeText filename ''
|
|
|
|
uris = ${concatStringsSep " " config.server-urls}
|
2020-01-15 09:24:11 -08:00
|
|
|
ldap_version = 3
|
2020-06-25 20:38:50 -07:00
|
|
|
dn = ${config.reader-dn}
|
|
|
|
dnpass = ${config.reader-passwd}
|
2020-01-15 09:24:11 -08:00
|
|
|
auth_bind = yes
|
|
|
|
auth_bind_userdn = uid=%u,ou=members,dc=fudo,dc=org
|
|
|
|
base = dc=fudo,dc=org
|
2020-06-25 20:38:50 -07:00
|
|
|
${ssl-config}
|
2020-01-15 09:24:11 -08:00
|
|
|
'';
|
|
|
|
|
2020-06-25 20:38:50 -07:00
|
|
|
ldap-passwd-entry = ldap-config: ''
|
|
|
|
passdb {
|
|
|
|
driver = ldap
|
|
|
|
args = ${ldap-conf "ldap-passdb.conf" ldap-config}
|
|
|
|
}
|
|
|
|
'';
|
2020-01-15 09:24:11 -08:00
|
|
|
|
2020-07-20 23:16:30 -07:00
|
|
|
ldapOpts = {
|
|
|
|
options = with types; {
|
|
|
|
ca = mkOption {
|
|
|
|
type = nullOr str;
|
|
|
|
description = "The path to the CA cert used to sign the LDAP server certificate.";
|
|
|
|
default = null;
|
|
|
|
};
|
2020-01-15 09:24:11 -08:00
|
|
|
|
2020-07-20 23:16:30 -07:00
|
|
|
server-urls = mkOption {
|
|
|
|
type = listOf str;
|
|
|
|
description = "A list of LDAP server URLs used for authentication.";
|
|
|
|
};
|
2020-01-15 09:24:11 -08:00
|
|
|
|
2020-07-20 23:16:30 -07:00
|
|
|
reader-dn = mkOption {
|
|
|
|
type = str;
|
|
|
|
description = ''
|
2020-01-15 09:24:11 -08:00
|
|
|
DN to use for reading user information. Needs access to homeDirectory,
|
|
|
|
uidNumber, gidNumber, and uid, but not password attributes.
|
|
|
|
'';
|
2020-07-20 23:16:30 -07:00
|
|
|
};
|
2020-01-15 09:24:11 -08:00
|
|
|
|
2020-07-20 23:16:30 -07:00
|
|
|
reader-passwd = mkOption {
|
|
|
|
type = str;
|
|
|
|
description = ''
|
2020-01-15 09:24:11 -08:00
|
|
|
Password for the user specified in ldap-reader-dn.
|
|
|
|
'';
|
2020-07-20 23:16:30 -07:00
|
|
|
};
|
2020-01-15 09:24:11 -08:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2020-06-25 20:38:50 -07:00
|
|
|
dovecot-user = config.services.dovecot2.user;
|
|
|
|
|
|
|
|
in {
|
|
|
|
options.fudo.mail-server.dovecot = with types; {
|
|
|
|
ssl-private-key = mkOption {
|
|
|
|
type = str;
|
|
|
|
description = "Location of the server SSL private key.";
|
|
|
|
};
|
|
|
|
|
|
|
|
ssl-certificate = mkOption {
|
|
|
|
type = str;
|
|
|
|
description = "Location of the server SSL certificate.";
|
|
|
|
};
|
|
|
|
|
|
|
|
ldap = mkOption {
|
|
|
|
type = nullOr (submodule ldapOpts);
|
|
|
|
default = null;
|
|
|
|
description = ''
|
|
|
|
LDAP auth server configuration. If omitted, the server will use local authentication.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2020-01-15 09:24:11 -08:00
|
|
|
config = mkIf cfg.enable {
|
|
|
|
|
|
|
|
services.prometheus.exporters.dovecot = mkIf cfg.monitoring {
|
|
|
|
enable = true;
|
|
|
|
scopes = ["user" "global"];
|
|
|
|
listenAddress = "127.0.0.1";
|
|
|
|
port = 9166;
|
|
|
|
socketPath = "/var/run/dovecot2/old-stats";
|
|
|
|
};
|
|
|
|
|
|
|
|
services.dovecot2 = {
|
|
|
|
enable = true;
|
|
|
|
enableImap = true;
|
|
|
|
enableLmtp = true;
|
|
|
|
enablePop3 = true;
|
2020-06-25 20:38:50 -07:00
|
|
|
enablePAM = cfg.dovecot.ldap == null;
|
2020-01-15 09:24:11 -08:00
|
|
|
|
|
|
|
createMailUser = true;
|
|
|
|
|
|
|
|
mailUser = cfg.mail-user;
|
|
|
|
mailGroup = cfg.mail-group;
|
|
|
|
mailLocation = "maildir:${cfg.mail-directory}/%u/";
|
|
|
|
|
|
|
|
sslServerCert = cfg.dovecot.ssl-certificate;
|
|
|
|
sslServerKey = cfg.dovecot.ssl-private-key;
|
|
|
|
|
|
|
|
modules = [ pkgs.dovecot_pigeonhole ];
|
|
|
|
protocols = [ "sieve" ];
|
|
|
|
|
|
|
|
sieveScripts = {
|
|
|
|
after = builtins.toFile "spam.sieve" ''
|
|
|
|
require "fileinto";
|
|
|
|
|
|
|
|
if header :is "X-Spam" "Yes" {
|
|
|
|
fileinto "Junk";
|
|
|
|
stop;
|
|
|
|
}
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
mailboxes = cfg.mailboxes;
|
|
|
|
|
|
|
|
extraConfig = ''
|
|
|
|
#Extra Config
|
|
|
|
|
2020-06-25 20:38:50 -07:00
|
|
|
${optionalString cfg.monitoring ''
|
|
|
|
# The prometheus exporter still expects an older style of metrics
|
|
|
|
mail_plugins = $mail_plugins old_stats
|
|
|
|
service old-stats {
|
|
|
|
unix_listener old-stats {
|
|
|
|
user = dovecot-exporter
|
|
|
|
group = dovecot-exporter
|
|
|
|
}
|
2020-01-15 09:24:11 -08:00
|
|
|
}
|
2020-06-25 20:38:50 -07:00
|
|
|
''}
|
2020-01-15 09:24:11 -08:00
|
|
|
|
|
|
|
${lib.optionalString cfg.debug ''
|
|
|
|
mail_debug = yes
|
|
|
|
auth_debug = yes
|
|
|
|
verbose_ssl = yes
|
|
|
|
''}
|
|
|
|
|
|
|
|
protocol imap {
|
|
|
|
mail_max_userip_connections = ${toString cfg.max-user-connections}
|
|
|
|
mail_plugins = $mail_plugins imap_sieve
|
|
|
|
}
|
|
|
|
|
|
|
|
protocol pop3 {
|
|
|
|
mail_max_userip_connections = ${toString cfg.max-user-connections}
|
|
|
|
}
|
|
|
|
|
|
|
|
protocol lmtp {
|
|
|
|
mail_plugins = $mail_plugins sieve
|
|
|
|
}
|
|
|
|
|
|
|
|
mail_access_groups = ${cfg.mail-group}
|
|
|
|
ssl = required
|
|
|
|
|
|
|
|
# When looking up usernames, just use the name, not the full address
|
|
|
|
auth_username_format = %n
|
|
|
|
|
|
|
|
service lmtp {
|
|
|
|
# Enable logging in debug mode
|
|
|
|
${optionalString cfg.debug "executable = lmtp -L"}
|
|
|
|
|
|
|
|
# Unix socket for postfix to deliver messages via lmtp
|
|
|
|
unix_listener dovecot-lmtp {
|
|
|
|
user = "postfix"
|
|
|
|
group = ${cfg.mail-group}
|
|
|
|
mode = 0600
|
|
|
|
}
|
|
|
|
|
|
|
|
# Drop privs, since all mail is owned by one user
|
2020-06-25 20:38:50 -07:00
|
|
|
# user = ${cfg.mail-user}
|
|
|
|
# group = ${cfg.mail-group}
|
|
|
|
user = root
|
2020-01-15 09:24:11 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
auth_mechanisms = login plain
|
2020-06-25 20:38:50 -07:00
|
|
|
|
|
|
|
${optionalString (cfg.dovecot.ldap != null)
|
2020-07-20 23:16:30 -07:00
|
|
|
(ldap-passwd-entry cfg.dovecot.ldap)}
|
2020-01-15 09:24:11 -08:00
|
|
|
userdb {
|
|
|
|
driver = static
|
|
|
|
args = uid=${toString cfg.mail-user-id} home=${cfg.mail-directory}/%u
|
|
|
|
}
|
|
|
|
|
|
|
|
# Used by postfix to authorize users
|
|
|
|
service auth {
|
|
|
|
unix_listener auth {
|
|
|
|
mode = 0660
|
|
|
|
user = "${config.services.postfix.user}"
|
2020-06-25 20:38:50 -07:00
|
|
|
group = ${cfg.mail-group}
|
2020-01-15 09:24:11 -08:00
|
|
|
}
|
2020-06-25 20:38:50 -07:00
|
|
|
|
|
|
|
unix_listener auth-userdb {
|
|
|
|
mode = 0660
|
|
|
|
user = "${config.services.postfix.user}"
|
|
|
|
group = ${cfg.mail-group}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
service auth-worker {
|
|
|
|
user = root
|
2020-01-15 09:24:11 -08:00
|
|
|
}
|
|
|
|
|
2020-07-26 08:22:28 -07:00
|
|
|
service imap {
|
|
|
|
vsz_limit = 1024M
|
|
|
|
}
|
|
|
|
|
2020-01-15 09:24:11 -08:00
|
|
|
namespace inbox {
|
|
|
|
separator = "/"
|
|
|
|
inbox = yes
|
|
|
|
}
|
|
|
|
|
|
|
|
plugin {
|
|
|
|
sieve_plugins = sieve_imapsieve sieve_extprograms
|
|
|
|
sieve = file:/var/sieve/%u/scripts;active=/var/sieve/%u/active.sieve
|
|
|
|
sieve_default = file:/var/sieve/%u/default.sieve
|
|
|
|
sieve_default_name = default
|
|
|
|
# From elsewhere to Spam folder
|
|
|
|
imapsieve_mailbox1_name = Junk
|
|
|
|
imapsieve_mailbox1_causes = COPY
|
|
|
|
imapsieve_mailbox1_before = file:${state-directory}/imap_sieve/report-spam.sieve
|
|
|
|
# From Spam folder to elsewhere
|
|
|
|
imapsieve_mailbox2_name = *
|
|
|
|
imapsieve_mailbox2_from = Junk
|
|
|
|
imapsieve_mailbox2_causes = COPY
|
|
|
|
imapsieve_mailbox2_before = file:${state-directory}/imap_sieve/report-ham.sieve
|
|
|
|
sieve_pipe_bin_dir = ${pipe-bin}/pipe/bin
|
|
|
|
sieve_global_extensions = +vnd.dovecot.pipe +vnd.dovecot.environment
|
|
|
|
}
|
|
|
|
|
|
|
|
recipient_delimiter = +
|
|
|
|
|
|
|
|
lmtp_save_to_detail_mailbox = yes
|
|
|
|
|
|
|
|
lda_mailbox_autosubscribe = yes
|
|
|
|
lda_mailbox_autocreate = yes
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
systemd.services.dovecot2.preStart = ''
|
|
|
|
mkdir -p '${state-directory}'
|
|
|
|
chown ${dovecot-user}:${cfg.mail-group} '${state-directory}'
|
|
|
|
rm -rf '${state-directory}/imap_sieve'
|
|
|
|
mkdir '${state-directory}/imap_sieve'
|
|
|
|
cp -p "${./dovecot/imap_sieve}"/*.sieve '${state-directory}/imap_sieve/'
|
|
|
|
for k in "${state-directory}/imap_sieve"/*.sieve ; do
|
|
|
|
${pkgs.dovecot_pigeonhole}/bin/sievec "$k"
|
|
|
|
done
|
|
|
|
chown -R '${dovecot-user}:${cfg.mail-group}' '${state-directory}/imap_sieve'
|
|
|
|
|
2020-06-25 20:38:50 -07:00
|
|
|
chown '${cfg.mail-user}:${cfg.mail-group}' ${cfg.mail-directory}
|
|
|
|
chmod g+w ${cfg.mail-directory}
|
2020-01-15 09:24:11 -08:00
|
|
|
'';
|
|
|
|
};
|
|
|
|
}
|