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 after = [ "postgresql.service" ];
108 restartTriggers = [ cfgfile ];
109
110 serviceConfig = {
111 ExecStart = "${dspam}/bin/dspam --daemon --nofork";
112 User = cfg.user;
113 Group = cfg.group;
114 RuntimeDirectory = optional (cfg.domainSocket == defaultSock) "dspam";
115 RuntimeDirectoryMode = optional (cfg.domainSocket == defaultSock) "0750";
116 PermissionsStartOnly = true;
117 # DSPAM segfaults on just about every error
118 Restart = "on-abort";
119 RestartSec = "1s";
120 };
121
122 preStart = ''
123 mkdir -m750 -p /var/lib/dspam
124 chown -R "${cfg.user}:${cfg.group}" /var/lib/dspam
125
126 mkdir -m750 -p /var/log/dspam
127 chown -R "${cfg.user}:${cfg.group}" /var/log/dspam
128 '';
129 };
130 }
131
132 (mkIf (cfg.maintenanceInterval != null) {
133 systemd.timers.dspam-maintenance = {
134 description = "Timer for dspam maintenance script";
135 wantedBy = [ "timers.target" ];
136 timerConfig = {
137 OnCalendar = cfg.maintenanceInterval;
138 Unit = "dspam-maintenance.service";
139 };
140 };
141
142 systemd.services.dspam-maintenance = {
143 description = "dspam maintenance script";
144 restartTriggers = [ cfgfile ];
145
146 serviceConfig = {
147 ExecStart = "${dspam}/bin/dspam_maintenance --verbose";
148 Type = "oneshot";
149 User = cfg.user;
150 Group = cfg.group;
151 };
152 };
153 })
154 ]);
155}