Merge pull request #11573 from hrdinka/refactor/dovecot

dovecot service: refactor module
This commit is contained in:
Peter Simons 2015-12-17 14:32:19 +01:00
commit 8f575eb0bf

View File

@ -3,101 +3,124 @@
with lib; with lib;
let let
cfg = config.services.dovecot2; cfg = config.services.dovecot2;
dovecotPkg = cfg.package;
dovecotConf = baseDir = "/run/dovecot2";
'' stateDir = "/var/lib/dovecot";
base_dir = /var/run/dovecot2/
protocols = ${optionalString cfg.enableImap "imap"} ${optionalString cfg.enablePop3 "pop3"} ${optionalString cfg.enableLmtp "lmtp"} protocols = concatStrings [
(optionalString cfg.enableImap "imap")
(optionalString cfg.enablePop3 "pop3")
(optionalString cfg.enableLmtp "lmtp")
];
dovecotConf = concatStrings [
'' ''
+ (if cfg.sslServerCert!="" then base_dir = ${baseDir}
protocols = ${protocols}
'' ''
ssl_cert = <${cfg.sslServerCert}
ssl_key = <${cfg.sslServerKey} (if isNull cfg.sslServerCert then ''
ssl_ca = <${cfg.sslCACert}
disable_plaintext_auth = yes
'' else ''
ssl = no ssl = no
disable_plaintext_auth = no disable_plaintext_auth = no
'' else ''
ssl_cert = <${cfg.sslServerCert}
ssl_key = <${cfg.sslServerKey}
${optionalString (!(isNull cfg.sslCACert)) ("ssl_ca = <" + cfg.sslCACert)}
disable_plaintext_auth = yes
'') '')
+ '' ''
default_internal_user = ${cfg.user} default_internal_user = ${cfg.user}
mail_location = ${cfg.mailLocation} mail_location = ${cfg.mailLocation}
maildir_copy_with_hardlinks = yes maildir_copy_with_hardlinks = yes
pop3_uidl_format = %08Xv%08Xu
auth_mechanisms = plain login auth_mechanisms = plain login
service auth { service auth {
user = root user = root
} }
''
(optionalString cfg.enablePAM ''
userdb { userdb {
driver = passwd driver = passwd
} }
passdb { passdb {
driver = pam driver = pam
args = ${optionalString cfg.showPAMFailure "failure_show_msg=yes"} dovecot2 args = ${optionalString cfg.showPAMFailure "failure_show_msg=yes"} dovecot2
} }
'')
pop3_uidl_format = %08Xv%08Xu cfg.extraConfig
'' + cfg.extraConfig; ];
modulesDir = pkgs.symlinkJoin "dovecot-modules"
(map (module: "${module}/lib/dovecot") cfg.modules);
in in
{ {
###### interface options.services.dovecot2 = {
enable = mkEnableOption "Dovecot 2.x POP3/IMAP server";
options = {
services.dovecot2 = {
enable = mkOption {
default = false;
description = "Whether to enable the Dovecot 2.x POP3/IMAP server.";
};
enablePop3 = mkOption { enablePop3 = mkOption {
type = types.bool;
default = true; default = true;
description = "Start the POP3 listener (when Dovecot is enabled)."; description = "Start the POP3 listener (when Dovecot is enabled).";
}; };
enableImap = mkOption { enableImap = mkOption {
type = types.bool;
default = true; default = true;
description = "Start the IMAP listener (when Dovecot is enabled)."; description = "Start the IMAP listener (when Dovecot is enabled).";
}; };
enableLmtp = mkOption { enableLmtp = mkOption {
type = types.bool;
default = false; default = false;
description = "Start the LMTP listener (when Dovecot is enabled)."; description = "Start the LMTP listener (when Dovecot is enabled).";
}; };
package = mkOption {
type = types.package;
default = pkgs.dovecot22;
description = "Dovecot package to use.";
};
user = mkOption { user = mkOption {
type = types.str;
default = "dovecot2"; default = "dovecot2";
description = "Dovecot user name."; description = "Dovecot user name.";
}; };
group = mkOption { group = mkOption {
type = types.str;
default = "dovecot2"; default = "dovecot2";
description = "Dovecot group name."; description = "Dovecot group name.";
}; };
extraConfig = mkOption { extraConfig = mkOption {
type = types.str;
default = ""; default = "";
example = "mail_debug = yes"; example = "mail_debug = yes";
description = "Additional entries to put verbatim into Dovecot's config file."; description = "Additional entries to put verbatim into Dovecot's config file.";
}; };
configFile = mkOption { configFile = mkOption {
type = types.nullOr types.str;
default = null; default = null;
description = "Config file used for the whole dovecot configuration."; description = "Config file used for the whole dovecot configuration.";
apply = v: if v != null then v else pkgs.writeText "dovecot.conf" dovecotConf; apply = v: if v != null then v else pkgs.writeText "dovecot.conf" dovecotConf;
}; };
mailLocation = mkOption { mailLocation = mkOption {
type = types.str;
default = "maildir:/var/spool/mail/%u"; /* Same as inbox, as postfix */ default = "maildir:/var/spool/mail/%u"; /* Same as inbox, as postfix */
example = "maildir:~/mail:INBOX=/var/spool/mail/%u"; example = "maildir:~/mail:INBOX=/var/spool/mail/%u";
description = '' description = ''
@ -105,35 +128,53 @@ in
''; '';
}; };
sslServerCert = mkOption { modules = mkOption {
default = ""; type = types.listOf types.package;
description = "Server certificate"; default = [];
example = [ pkgs.dovecot_pigeonhole ];
description = ''
Symlinks the contents of lib/dovecot of every given package into
/var/lib/dovecot/modules. This will make the given modules available
if a dovecot package with the module_dir patch applied (like
pkgs.dovecot22, the default) is being used.
'';
}; };
sslCACert = mkOption { sslCACert = mkOption {
default = ""; type = types.nullOr types.str;
description = "CA certificate used by the server certificate."; default = null;
description = "Path to the server's CA certificate key.";
};
sslServerCert = mkOption {
type = types.nullOr types.str;
default = null;
description = "Path to the server's public key.";
}; };
sslServerKey = mkOption { sslServerKey = mkOption {
default = ""; type = types.nullOr types.str;
description = "Server key."; default = null;
description = "Path to the server's private key.";
};
enablePAM = mkOption {
type = types.bool;
default = true;
description = "Wether to create a own Dovecot PAM service and configure PAM user logins.";
}; };
showPAMFailure = mkOption { showPAMFailure = mkOption {
type = types.bool;
default = false; default = false;
description = "Show the PAM failure message on authentication error (useful for OTPW)."; description = "Show the PAM failure message on authentication error (useful for OTPW).";
}; };
}; };
};
config = mkIf cfg.enable {
###### implementation security.pam.services.dovecot2 = mkIf cfg.enablePAM {};
config = mkIf config.services.dovecot2.enable {
security.pam.services.dovecot2 = {};
users.extraUsers = [ users.extraUsers = [
{ name = cfg.user; { name = cfg.user;
@ -148,36 +189,47 @@ in
} }
]; ];
users.extraGroups = singleton users.extraGroups = singleton {
{ name = cfg.group; name = cfg.group;
gid = config.ids.gids.dovecot2; gid = config.ids.gids.dovecot2;
}; };
systemd.services.dovecot2 = systemd.services.dovecot2 = {
{ description = "Dovecot IMAP/POP3 server"; description = "Dovecot IMAP/POP3 server";
after = [ "network.target" ]; after = [ "keys.target" "network.target" ];
wants = [ "keys.target" ];
wantedBy = [ "multi-user.target" ]; wantedBy = [ "multi-user.target" ];
preStart = preStart = ''
'' mkdir -p "${baseDir}/login"
${pkgs.coreutils}/bin/mkdir -p /var/run/dovecot2 /var/run/dovecot2/login chown -R ${cfg.user}:${cfg.group} "${baseDir}"
${pkgs.coreutils}/bin/chown -R ${cfg.user}:${cfg.group} /var/run/dovecot2 rm -f "${stateDir}/modules"
ln -s "${modulesDir}" "${stateDir}/modules"
''; '';
serviceConfig = { serviceConfig = {
ExecStart = "${pkgs.dovecot}/sbin/dovecot -F -c ${cfg.configFile}"; ExecStart = "${dovecotPkg}/sbin/dovecot -F -c ${cfg.configFile}";
Restart = "on-failure"; Restart = "on-failure";
RestartSec = "1s"; RestartSec = "1s";
StartLimitInterval = "1min"; StartLimitInterval = "1min";
}; };
}; };
environment.systemPackages = [ pkgs.dovecot ]; environment.systemPackages = [ dovecotPkg ];
assertions = [{ assertion = cfg.enablePop3 || cfg.enableImap; assertions = [
message = "dovecot needs at least one of the IMAP or POP3 listeners enabled";}]; { assertion = cfg.enablePop3 || cfg.enableImap;
message = "dovecot needs at least one of the IMAP or POP3 listeners enabled";
}
{ assertion = isNull cfg.sslServerCert == isNull cfg.sslServerKey
&& (!(isNull cfg.sslCACert) -> !(isNull cfg.sslServerCert || isNull cfg.sslServerKey));
message = "dovecot needs both sslServerCert and sslServerKey defined for working crypto";
}
{ assertion = cfg.showPAMFailure -> cfg.enablePAM;
message = "dovecot is configured with showPAMFailure while enablePAM is disabled";
}
];
}; };