1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6
7 cfg = config.services.dspam;
8
9 dspam = pkgs.dspam;
10
11 defaultSock = "/run/dspam/dspam.sock";
12
13 cfgfile = pkgs.writeText "dspam.conf" ''
14 Home /var/lib/dspam
15 StorageDriver ${dspam}/lib/dspam/lib${cfg.storageDriver}_drv.so
16
17 Trust root
18 Trust ${cfg.user}
19 SystemLog on
20 UserLog on
21
22 ${optionalString (cfg.domainSocket != null) ''
23 ServerDomainSocketPath "${cfg.domainSocket}"
24 ClientHost "${cfg.domainSocket}"
25 ''}
26
27 ${cfg.extraConfig}
28 '';
29
30in {
31
32 ###### interface
33
34 options = {
35
36 services.dspam = {
37
38 enable = mkOption {
39 type = types.bool;
40 default = false;
41 description = "Whether to enable the dspam spam filter.";
42 };
43
44 user = mkOption {
45 type = types.str;
46 default = "dspam";
47 description = "User for the dspam daemon.";
48 };
49
50 group = mkOption {
51 type = types.str;
52 default = "dspam";
53 description = "Group for the dspam daemon.";
54 };
55
56 storageDriver = mkOption {
57 type = types.str;
58 default = "hash";
59 description = "Storage driver backend to use for dspam.";
60 };
61
62 domainSocket = mkOption {
63 type = types.nullOr types.path;
64 default = defaultSock;
65 description = "Path to local domain socket which is used for communication with the daemon. Set to null to disable UNIX socket.";
66 };
67
68 extraConfig = mkOption {
69 type = types.lines;
70 default = "";
71 description = "Additional dspam configuration.";
72 };
73
74 maintenanceInterval = mkOption {
75 type = types.nullOr types.str;
76 default = null;
77 description = "If set, maintenance script will be run at specified (in systemd.timer format) interval";
78 };
79
80 };
81
82 };
83
84
85 ###### implementation
86
87 config = mkIf cfg.enable (mkMerge [
88 {
89 users.extraUsers = optionalAttrs (cfg.user == "dspam") (singleton
90 { name = "dspam";
91 group = cfg.group;
92 uid = config.ids.uids.dspam;
93 });
94
95 users.extraGroups = optionalAttrs (cfg.group == "dspam") (singleton
96 { name = "dspam";
97 gid = config.ids.gids.dspam;
98 });
99
100 environment.systemPackages = [ dspam ];
101
102 environment.etc."dspam/dspam.conf".source = cfgfile;
103
104 systemd.services.dspam = {
105 description = "dspam spam filtering daemon";
106 wantedBy = [ "multi-user.target" ];
107 restartTriggers = [ cfgfile ];
108
109 serviceConfig = {
110 ExecStart = "${dspam}/bin/dspam --daemon --nofork";
111 User = cfg.user;
112 Group = cfg.group;
113 RuntimeDirectory = optional (cfg.domainSocket == defaultSock) "dspam";
114 RuntimeDirectoryMode = optional (cfg.domainSocket == defaultSock) "0750";
115 PermissionsStartOnly = true;
116 # DSPAM segfaults on just about every error
117 Restart = "on-failure";
118 RestartSec = "1s";
119 };
120
121 preStart = ''
122 mkdir -m750 -p /var/lib/dspam
123 chown -R "${cfg.user}:${cfg.group}" /var/lib/dspam
124
125 mkdir -m750 -p /var/log/dspam
126 chown -R "${cfg.user}:${cfg.group}" /var/log/dspam
127 '';
128 };
129 }
130
131 (mkIf (cfg.maintenanceInterval != null) {
132 systemd.timers.dspam-maintenance = {
133 description = "Timer for dspam maintenance script";
134 wantedBy = [ "timers.target" ];
135 timerConfig = {
136 OnCalendar = cfg.maintenanceInterval;
137 Unit = "dspam-maintenance.service";
138 };
139 };
140
141 systemd.services.dspam-maintenance = {
142 description = "dspam maintenance script";
143 restartTriggers = [ cfgfile ];
144
145 serviceConfig = {
146 ExecStart = "${dspam}/bin/dspam_maintenance --verbose";
147 Type = "oneshot";
148 User = cfg.user;
149 Group = cfg.group;
150 };
151 };
152 })
153 ]);
154}