1{ config, lib, pkgs, ... }:
2with lib;
3let
4 clamavUser = "clamav";
5 stateDir = "/var/lib/clamav";
6 runDir = "/var/run/clamav";
7 logDir = "/var/log/clamav";
8 clamavGroup = clamavUser;
9 cfg = config.services.clamav;
10 clamdConfigFile = pkgs.writeText "clamd.conf" ''
11 DatabaseDirectory ${stateDir}
12 LocalSocket ${runDir}/clamd.ctl
13 LogFile ${logDir}/clamav.log
14 PidFile ${runDir}/clamd.pid
15 User clamav
16
17 ${cfg.daemon.extraConfig}
18 '';
19 pkg = pkgs.clamav.override { freshclamConf = cfg.updater.config; };
20in
21{
22 options = {
23 services.clamav = {
24 daemon = {
25 enable = mkEnableOption "clamd daemon";
26
27 extraConfig = mkOption {
28 type = types.lines;
29 default = "";
30 description = ''
31 Extra configuration for clamd. Contents will be added verbatim to the
32 configuration file.
33 '';
34 };
35 };
36 updater = {
37 enable = mkEnableOption "freshclam updater";
38
39 frequency = mkOption {
40 default = 12;
41 description = ''
42 Number of database checks per day.
43 '';
44 };
45
46 config = mkOption {
47 default = "";
48 description = ''
49 Extra configuration for freshclam. Contents will be added verbatim to the
50 configuration file.
51 '';
52 };
53 };
54 };
55 };
56
57 config = mkIf cfg.updater.enable or cfg.daemon.enable {
58 environment.systemPackages = [ pkg ];
59 users.extraUsers = singleton {
60 name = clamavUser;
61 uid = config.ids.uids.clamav;
62 description = "ClamAV daemon user";
63 home = stateDir;
64 };
65
66 users.extraGroups = singleton {
67 name = clamavGroup;
68 gid = config.ids.gids.clamav;
69 };
70
71 services.clamav.updater.config = mkIf cfg.updater.enable ''
72 DatabaseDirectory ${stateDir}
73 Foreground yes
74 Checks ${toString cfg.updater.frequency}
75 DatabaseMirror database.clamav.net
76 '';
77
78 systemd.services.clamd = mkIf cfg.daemon.enable {
79 description = "ClamAV daemon (clamd)";
80 path = [ pkg ];
81 after = [ "network.target" "freshclam.service" ];
82 requires = [ "freshclam.service" ];
83 wantedBy = [ "multi-user.target" ];
84 preStart = ''
85 mkdir -m 0755 -p ${logDir}
86 mkdir -m 0755 -p ${runDir}
87 chown ${clamavUser}:${clamavGroup} ${logDir}
88 chown ${clamavUser}:${clamavGroup} ${runDir}
89 '';
90 serviceConfig = {
91 ExecStart = "${pkg}/bin/clamd --config-file=${clamdConfigFile}";
92 Type = "forking";
93 ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
94 Restart = "on-failure";
95 RestartSec = "10s";
96 StartLimitInterval = "1min";
97 };
98 };
99
100 systemd.services.freshclam = mkIf cfg.updater.enable {
101 description = "ClamAV updater (freshclam)";
102 after = [ "network.target" ];
103 wantedBy = [ "multi-user.target" ];
104 path = [ pkg ];
105 preStart = ''
106 mkdir -m 0755 -p ${stateDir}
107 chown ${clamavUser}:${clamavGroup} ${stateDir}
108 '';
109 serviceConfig = {
110 ExecStart = "${pkg}/bin/freshclam --daemon --config-file=${pkgs.writeText "freshclam.conf" cfg.updater.config}";
111 ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
112 Restart = "on-failure";
113 RestartSec = "10s";
114 StartLimitInterval = "1min";
115 };
116 };
117 };
118}