at 25.11-pre 6.2 kB view raw
1{ 2 config, 3 lib, 4 pkgs, 5 ... 6}: 7let 8 cfg = config.services.clamsmtp; 9 clamdSocket = "/run/clamav/clamd.ctl"; # See services/security/clamav.nix 10in 11{ 12 ##### interface 13 options = { 14 services.clamsmtp = { 15 enable = lib.mkOption { 16 type = lib.types.bool; 17 default = false; 18 description = "Whether to enable clamsmtp."; 19 }; 20 21 instances = lib.mkOption { 22 description = "Instances of clamsmtp to run."; 23 type = lib.types.listOf ( 24 lib.types.submodule { 25 options = { 26 action = lib.mkOption { 27 type = lib.types.enum [ 28 "bounce" 29 "drop" 30 "pass" 31 ]; 32 default = "drop"; 33 description = '' 34 Action to take when a virus is detected. 35 36 Note that viruses often spoof sender addresses, so bouncing is 37 in most cases not a good idea. 38 ''; 39 }; 40 41 header = lib.mkOption { 42 type = lib.types.str; 43 default = ""; 44 example = "X-Virus-Scanned: ClamAV using ClamSMTP"; 45 description = '' 46 A header to add to scanned messages. See {manpage}`clamsmtpd.conf(5)` for 47 more details. Empty means no header. 48 ''; 49 }; 50 51 keepAlives = lib.mkOption { 52 type = lib.types.int; 53 default = 0; 54 description = '' 55 Number of seconds to wait between each NOOP sent to the sending 56 server. 0 to disable. 57 58 This is meant for slow servers where the sending MTA times out 59 waiting for clamd to scan the file. 60 ''; 61 }; 62 63 listen = lib.mkOption { 64 type = lib.types.str; 65 example = "127.0.0.1:10025"; 66 description = '' 67 Address to wait for incoming SMTP connections on. See 68 {manpage}`clamsmtpd.conf(5)` for more details. 69 ''; 70 }; 71 72 quarantine = lib.mkOption { 73 type = lib.types.bool; 74 default = false; 75 description = '' 76 Whether to quarantine files that contain viruses by leaving them 77 in the temporary directory. 78 ''; 79 }; 80 81 maxConnections = lib.mkOption { 82 type = lib.types.int; 83 default = 64; 84 description = "Maximum number of connections to accept at once."; 85 }; 86 87 outAddress = lib.mkOption { 88 type = lib.types.str; 89 description = '' 90 Address of the SMTP server to send email to once it has been 91 scanned. 92 ''; 93 }; 94 95 tempDirectory = lib.mkOption { 96 type = lib.types.str; 97 default = "/tmp"; 98 description = '' 99 Temporary directory that needs to be accessible to both clamd 100 and clamsmtpd. 101 ''; 102 }; 103 104 timeout = lib.mkOption { 105 type = lib.types.int; 106 default = 180; 107 description = "Time-out for network connections."; 108 }; 109 110 transparentProxy = lib.mkOption { 111 type = lib.types.bool; 112 default = false; 113 description = "Enable clamsmtp's transparent proxy support."; 114 }; 115 116 virusAction = lib.mkOption { 117 type = with lib.types; nullOr path; 118 default = null; 119 description = '' 120 Command to run when a virus is found. Please see VIRUS ACTION in 121 {manpage}`clamsmtpd(8)` for a discussion of this option and its safe use. 122 ''; 123 }; 124 125 xClient = lib.mkOption { 126 type = lib.types.bool; 127 default = false; 128 description = '' 129 Send the XCLIENT command to the receiving server, for forwarding 130 client addresses and connection information if the receiving 131 server supports this feature. 132 ''; 133 }; 134 }; 135 } 136 ); 137 }; 138 }; 139 }; 140 141 ##### implementation 142 config = 143 let 144 configfile = 145 conf: 146 pkgs.writeText "clamsmtpd.conf" '' 147 Action: ${conf.action} 148 ClamAddress: ${clamdSocket} 149 Header: ${conf.header} 150 KeepAlives: ${toString conf.keepAlives} 151 Listen: ${conf.listen} 152 Quarantine: ${if conf.quarantine then "on" else "off"} 153 MaxConnections: ${toString conf.maxConnections} 154 OutAddress: ${conf.outAddress} 155 TempDirectory: ${conf.tempDirectory} 156 TimeOut: ${toString conf.timeout} 157 TransparentProxy: ${if conf.transparentProxy then "on" else "off"} 158 User: clamav 159 ${lib.optionalString (conf.virusAction != null) "VirusAction: ${conf.virusAction}"} 160 XClient: ${if conf.xClient then "on" else "off"} 161 ''; 162 in 163 lib.mkIf cfg.enable { 164 assertions = [ 165 { 166 assertion = config.services.clamav.daemon.enable; 167 message = "clamsmtp requires clamav to be enabled"; 168 } 169 ]; 170 171 systemd.services = lib.listToAttrs ( 172 lib.imap1 ( 173 i: conf: 174 lib.nameValuePair "clamsmtp-${toString i}" { 175 description = "ClamSMTP instance ${toString i}"; 176 wantedBy = [ "multi-user.target" ]; 177 script = "exec ${pkgs.clamsmtp}/bin/clamsmtpd -f ${configfile conf}"; 178 after = [ "clamav-daemon.service" ]; 179 requires = [ "clamav-daemon.service" ]; 180 serviceConfig.Type = "forking"; 181 serviceConfig.PrivateTmp = "yes"; 182 unitConfig.JoinsNamespaceOf = "clamav-daemon.service"; 183 } 184 ) cfg.instances 185 ); 186 }; 187 188 meta.maintainers = with lib.maintainers; [ ekleog ]; 189}