nixos/clamsmtp: init

Changed files
+180
nixos
modules
+1
nixos/modules/module-list.nix
···
./services/logging/rsyslogd.nix
./services/logging/syslog-ng.nix
./services/logging/syslogd.nix
+
./services/mail/clamsmtp.nix
./services/mail/dkimproxy-out.nix
./services/mail/dovecot.nix
./services/mail/dspam.nix
+179
nixos/modules/services/mail/clamsmtp.nix
···
+
{ config, lib, pkgs, ... }:
+
+
with lib;
+
let
+
cfg = config.services.clamsmtp;
+
clamdSocket = "/run/clamav/clamd.ctl"; # See services/security/clamav.nix
+
in
+
{
+
##### interface
+
options = {
+
services.clamsmtp = {
+
enable = mkOption {
+
type = types.bool;
+
default = false;
+
description = "Whether to enable clamsmtp.";
+
};
+
+
instances = mkOption {
+
description = "Instances of clamsmtp to run.";
+
type = types.listOf (types.submodule { options = {
+
action = mkOption {
+
type = types.enum [ "bounce" "drop" "pass" ];
+
default = "drop";
+
description =
+
''
+
Action to take when a virus is detected.
+
+
Note that viruses often spoof sender addresses, so bouncing is
+
in most cases not a good idea.
+
'';
+
};
+
+
header = mkOption {
+
type = types.str;
+
default = "";
+
example = "X-Virus-Scanned: ClamAV using ClamSMTP";
+
description =
+
''
+
A header to add to scanned messages. See clamsmtpd.conf(5) for
+
more details. Empty means no header.
+
'';
+
};
+
+
keepAlives = mkOption {
+
type = types.int;
+
default = 0;
+
description =
+
''
+
Number of seconds to wait between each NOOP sent to the sending
+
server. 0 to disable.
+
+
This is meant for slow servers where the sending MTA times out
+
waiting for clamd to scan the file.
+
'';
+
};
+
+
listen = mkOption {
+
type = types.str;
+
example = "127.0.0.1:10025";
+
description =
+
''
+
Address to wait for incoming SMTP connections on. See
+
clamsmtpd.conf(5) for more details.
+
'';
+
};
+
+
quarantine = mkOption {
+
type = types.bool;
+
default = false;
+
description =
+
''
+
Whether to quarantine files that contain viruses by leaving them
+
in the temporary directory.
+
'';
+
};
+
+
maxConnections = mkOption {
+
type = types.int;
+
default = 64;
+
description = "Maximum number of connections to accept at once.";
+
};
+
+
outAddress = mkOption {
+
type = types.str;
+
description =
+
''
+
Address of the SMTP server to send email to once it has been
+
scanned.
+
'';
+
};
+
+
tempDirectory = mkOption {
+
type = types.str;
+
default = "/tmp";
+
description =
+
''
+
Temporary directory that needs to be accessible to both clamd
+
and clamsmtpd.
+
'';
+
};
+
+
timeout = mkOption {
+
type = types.int;
+
default = 180;
+
description = "Time-out for network connections.";
+
};
+
+
transparentProxy = mkOption {
+
type = types.bool;
+
default = false;
+
description = "Enable clamsmtp's transparent proxy support.";
+
};
+
+
virusAction = mkOption {
+
type = with types; nullOr path;
+
default = null;
+
description =
+
''
+
Command to run when a virus is found. Please see VIRUS ACTION in
+
clamsmtpd(8) for a discussion of this option and its safe use.
+
'';
+
};
+
+
xClient = mkOption {
+
type = types.bool;
+
default = false;
+
description =
+
''
+
Send the XCLIENT command to the receiving server, for forwarding
+
client addresses and connection information if the receiving
+
server supports this feature.
+
'';
+
};
+
};});
+
};
+
};
+
};
+
+
##### implementation
+
config = let
+
configfile = conf: pkgs.writeText "clamsmtpd.conf"
+
''
+
Action: ${conf.action}
+
ClamAddress: ${clamdSocket}
+
Header: ${conf.header}
+
KeepAlives: ${toString conf.keepAlives}
+
Listen: ${conf.listen}
+
Quarantine: ${if conf.quarantine then "on" else "off"}
+
MaxConnections: ${toString conf.maxConnections}
+
OutAddress: ${conf.outAddress}
+
TempDirectory: ${conf.tempDirectory}
+
TimeOut: ${toString conf.timeout}
+
TransparentProxy: ${if conf.transparentProxy then "on" else "off"}
+
User: clamav
+
${optionalString (conf.virusAction != null) "VirusAction: ${conf.virusAction}"}
+
XClient: ${if conf.xClient then "on" else "off"}
+
'';
+
in
+
mkIf cfg.enable {
+
assertions = [
+
{ assertion = config.services.clamav.daemon.enable;
+
message = "clamsmtp requires clamav to be enabled";
+
}
+
];
+
+
systemd.services = listToAttrs (imap1 (i: conf:
+
nameValuePair "clamsmtp-${toString i}" {
+
description = "ClamSMTP instance ${toString i}";
+
wantedBy = [ "multi-user.target" ];
+
script = "exec ${pkgs.clamsmtp}/bin/clamsmtpd -f ${configfile conf}";
+
after = [ "clamav-daemon.service" ];
+
requires = [ "clamav-daemon.service" ];
+
serviceConfig.Type = "forking";
+
serviceConfig.PrivateTmp = "yes";
+
unitConfig.JoinsNamespaceOf = "clamav-daemon.service";
+
}
+
) cfg.instances);
+
};
+
}