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