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}