at 24.11-pre 13 kB view raw
1{ config, lib, pkgs, ... }: 2 3with lib; 4 5let 6 cfg = config.services.murmur; 7 forking = cfg.logFile != null; 8 configFile = pkgs.writeText "murmurd.ini" '' 9 database=/var/lib/murmur/murmur.sqlite 10 dbDriver=QSQLITE 11 12 autobanAttempts=${toString cfg.autobanAttempts} 13 autobanTimeframe=${toString cfg.autobanTimeframe} 14 autobanTime=${toString cfg.autobanTime} 15 16 logfile=${optionalString (cfg.logFile != null) cfg.logFile} 17 ${optionalString forking "pidfile=/run/murmur/murmurd.pid"} 18 19 welcometext="${cfg.welcometext}" 20 port=${toString cfg.port} 21 22 ${optionalString (cfg.hostName != "") "host=${cfg.hostName}"} 23 ${optionalString (cfg.password != "") "serverpassword=${cfg.password}"} 24 25 bandwidth=${toString cfg.bandwidth} 26 users=${toString cfg.users} 27 28 textmessagelength=${toString cfg.textMsgLength} 29 imagemessagelength=${toString cfg.imgMsgLength} 30 allowhtml=${boolToString cfg.allowHtml} 31 logdays=${toString cfg.logDays} 32 bonjour=${boolToString cfg.bonjour} 33 sendversion=${boolToString cfg.sendVersion} 34 35 ${optionalString (cfg.registerName != "") "registerName=${cfg.registerName}"} 36 ${optionalString (cfg.registerPassword != "") "registerPassword=${cfg.registerPassword}"} 37 ${optionalString (cfg.registerUrl != "") "registerUrl=${cfg.registerUrl}"} 38 ${optionalString (cfg.registerHostname != "") "registerHostname=${cfg.registerHostname}"} 39 40 certrequired=${boolToString cfg.clientCertRequired} 41 ${optionalString (cfg.sslCert != "") "sslCert=${cfg.sslCert}"} 42 ${optionalString (cfg.sslKey != "") "sslKey=${cfg.sslKey}"} 43 ${optionalString (cfg.sslCa != "") "sslCA=${cfg.sslCa}"} 44 45 ${optionalString (cfg.dbus != null) "dbus=${cfg.dbus}"} 46 47 ${cfg.extraConfig} 48 ''; 49in 50{ 51 imports = [ 52 (mkRenamedOptionModule [ "services" "murmur" "welcome" ] [ "services" "murmur" "welcometext" ]) 53 (mkRemovedOptionModule [ "services" "murmur" "pidfile" ] "Hardcoded to /run/murmur/murmurd.pid now") 54 ]; 55 56 options = { 57 services.murmur = { 58 enable = mkOption { 59 type = types.bool; 60 default = false; 61 description = "If enabled, start the Murmur Mumble server."; 62 }; 63 64 openFirewall = mkOption { 65 type = types.bool; 66 default = false; 67 description = '' 68 Open ports in the firewall for the Murmur Mumble server. 69 ''; 70 }; 71 72 autobanAttempts = mkOption { 73 type = types.int; 74 default = 10; 75 description = '' 76 Number of attempts a client is allowed to make in 77 `autobanTimeframe` seconds, before being 78 banned for `autobanTime`. 79 ''; 80 }; 81 82 autobanTimeframe = mkOption { 83 type = types.int; 84 default = 120; 85 description = '' 86 Timeframe in which a client can connect without being banned 87 for repeated attempts (in seconds). 88 ''; 89 }; 90 91 autobanTime = mkOption { 92 type = types.int; 93 default = 300; 94 description = "The amount of time an IP ban lasts (in seconds)."; 95 }; 96 97 logFile = mkOption { 98 type = types.nullOr types.path; 99 default = null; 100 example = "/var/log/murmur/murmurd.log"; 101 description = "Path to the log file for Murmur daemon. Empty means log to journald."; 102 }; 103 104 welcometext = mkOption { 105 type = types.str; 106 default = ""; 107 description = "Welcome message for connected clients."; 108 }; 109 110 port = mkOption { 111 type = types.port; 112 default = 64738; 113 description = "Ports to bind to (UDP and TCP)."; 114 }; 115 116 hostName = mkOption { 117 type = types.str; 118 default = ""; 119 description = "Host to bind to. Defaults binding on all addresses."; 120 }; 121 122 package = mkPackageOption pkgs "murmur" { }; 123 124 password = mkOption { 125 type = types.str; 126 default = ""; 127 description = "Required password to join server, if specified."; 128 }; 129 130 bandwidth = mkOption { 131 type = types.int; 132 default = 72000; 133 description = '' 134 Maximum bandwidth (in bits per second) that clients may send 135 speech at. 136 ''; 137 }; 138 139 users = mkOption { 140 type = types.int; 141 default = 100; 142 description = "Maximum number of concurrent clients allowed."; 143 }; 144 145 textMsgLength = mkOption { 146 type = types.int; 147 default = 5000; 148 description = "Max length of text messages. Set 0 for no limit."; 149 }; 150 151 imgMsgLength = mkOption { 152 type = types.int; 153 default = 131072; 154 description = "Max length of image messages. Set 0 for no limit."; 155 }; 156 157 allowHtml = mkOption { 158 type = types.bool; 159 default = true; 160 description = '' 161 Allow HTML in client messages, comments, and channel 162 descriptions. 163 ''; 164 }; 165 166 logDays = mkOption { 167 type = types.int; 168 default = 31; 169 description = '' 170 How long to store RPC logs for in the database. Set 0 to 171 keep logs forever, or -1 to disable DB logging. 172 ''; 173 }; 174 175 bonjour = mkOption { 176 type = types.bool; 177 default = false; 178 description = '' 179 Enable Bonjour auto-discovery, which allows clients over 180 your LAN to automatically discover Murmur servers. 181 ''; 182 }; 183 184 sendVersion = mkOption { 185 type = types.bool; 186 default = true; 187 description = "Send Murmur version in UDP response."; 188 }; 189 190 registerName = mkOption { 191 type = types.str; 192 default = ""; 193 description = '' 194 Public server registration name, and also the name of the 195 Root channel. Even if you don't publicly register your 196 server, you probably still want to set this. 197 ''; 198 }; 199 200 registerPassword = mkOption { 201 type = types.str; 202 default = ""; 203 description = '' 204 Public server registry password, used authenticate your 205 server to the registry to prevent impersonation; required for 206 subsequent registry updates. 207 ''; 208 }; 209 210 registerUrl = mkOption { 211 type = types.str; 212 default = ""; 213 description = "URL website for your server."; 214 }; 215 216 registerHostname = mkOption { 217 type = types.str; 218 default = ""; 219 description = '' 220 DNS hostname where your server can be reached. This is only 221 needed if you want your server to be accessed by its 222 hostname and not IP - but the name *must* resolve on the 223 internet properly. 224 ''; 225 }; 226 227 clientCertRequired = mkOption { 228 type = types.bool; 229 default = false; 230 description = "Require clients to authenticate via certificates."; 231 }; 232 233 sslCert = mkOption { 234 type = types.str; 235 default = ""; 236 description = "Path to your SSL certificate."; 237 }; 238 239 sslKey = mkOption { 240 type = types.str; 241 default = ""; 242 description = "Path to your SSL key."; 243 }; 244 245 sslCa = mkOption { 246 type = types.str; 247 default = ""; 248 description = "Path to your SSL CA certificate."; 249 }; 250 251 extraConfig = mkOption { 252 type = types.lines; 253 default = ""; 254 description = "Extra configuration to put into murmur.ini."; 255 }; 256 257 environmentFile = mkOption { 258 type = types.nullOr types.path; 259 default = null; 260 example = "/var/lib/murmur/murmurd.env"; 261 description = '' 262 Environment file as defined in {manpage}`systemd.exec(5)`. 263 264 Secrets may be passed to the service without adding them to the world-readable 265 Nix store, by specifying placeholder variables as the option value in Nix and 266 setting these variables accordingly in the environment file. 267 268 ``` 269 # snippet of murmur-related config 270 services.murmur.password = "$MURMURD_PASSWORD"; 271 ``` 272 273 ``` 274 # content of the environment file 275 MURMURD_PASSWORD=verysecretpassword 276 ``` 277 278 Note that this file needs to be available on the host on which 279 `murmur` is running. 280 ''; 281 }; 282 283 dbus = mkOption { 284 type = types.enum [ null "session" "system" ]; 285 default = null; 286 description = "Enable D-Bus remote control. Set to the bus you want Murmur to connect to."; 287 }; 288 }; 289 }; 290 291 config = mkIf cfg.enable { 292 users.users.murmur = { 293 description = "Murmur Service user"; 294 home = "/var/lib/murmur"; 295 createHome = true; 296 uid = config.ids.uids.murmur; 297 group = "murmur"; 298 }; 299 users.groups.murmur = { 300 gid = config.ids.gids.murmur; 301 }; 302 303 networking.firewall = mkIf cfg.openFirewall { 304 allowedTCPPorts = [ cfg.port ]; 305 allowedUDPPorts = [ cfg.port ]; 306 }; 307 308 systemd.services.murmur = { 309 description = "Murmur Chat Service"; 310 wantedBy = [ "multi-user.target" ]; 311 after = [ "network.target" ]; 312 preStart = '' 313 ${pkgs.envsubst}/bin/envsubst \ 314 -o /run/murmur/murmurd.ini \ 315 -i ${configFile} 316 ''; 317 318 serviceConfig = { 319 # murmurd doesn't fork when logging to the console. 320 Type = if forking then "forking" else "simple"; 321 PIDFile = mkIf forking "/run/murmur/murmurd.pid"; 322 EnvironmentFile = mkIf (cfg.environmentFile != null) cfg.environmentFile; 323 ExecStart = "${cfg.package}/bin/mumble-server -ini /run/murmur/murmurd.ini"; 324 Restart = "always"; 325 RuntimeDirectory = "murmur"; 326 RuntimeDirectoryMode = "0700"; 327 User = "murmur"; 328 Group = "murmur"; 329 330 # service hardening 331 AmbientCapabilities = "CAP_NET_BIND_SERVICE"; 332 CapabilityBoundingSet = "CAP_NET_BIND_SERVICE"; 333 LockPersonality = true; 334 MemoryDenyWriteExecute = true; 335 NoNewPrivileges = true; 336 PrivateDevices = true; 337 PrivateTmp = true; 338 ProtectClock = true; 339 ProtectControlGroups = true; 340 ProtectHome = true; 341 ProtectHostname = true; 342 ProtectKernelLogs = true; 343 ProtectKernelModules = true; 344 ProtectKernelTunables = true; 345 ProtectSystem = "full"; 346 RestrictAddressFamilies = "~AF_PACKET AF_NETLINK"; 347 RestrictNamespaces = true; 348 RestrictSUIDSGID = true; 349 RestrictRealtime = true; 350 SystemCallArchitectures = "native"; 351 SystemCallFilter = "@system-service"; 352 }; 353 }; 354 355 # currently not included in upstream package, addition requested at 356 # https://github.com/mumble-voip/mumble/issues/6078 357 services.dbus.packages = mkIf (cfg.dbus == "system") [(pkgs.writeTextFile { 358 name = "murmur-dbus-policy"; 359 text = '' 360 <!DOCTYPE busconfig PUBLIC 361 "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN" 362 "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd"> 363 <busconfig> 364 <policy user="murmur"> 365 <allow own="net.sourceforge.mumble.murmur"/> 366 </policy> 367 368 <policy context="default"> 369 <allow send_destination="net.sourceforge.mumble.murmur"/> 370 <allow receive_sender="net.sourceforge.mumble.murmur"/> 371 </policy> 372 </busconfig> 373 ''; 374 destination = "/share/dbus-1/system.d/murmur.conf"; 375 })]; 376 377 security.apparmor.policies."bin.mumble-server".profile = '' 378 include <tunables/global> 379 380 ${cfg.package}/bin/{mumble-server,.mumble-server-wrapped} { 381 include <abstractions/base> 382 include <abstractions/nameservice> 383 include <abstractions/ssl_certs> 384 include "${pkgs.apparmorRulesFromClosure { name = "mumble-server"; } cfg.package}" 385 pix ${cfg.package}/bin/.mumble-server-wrapped, 386 387 r ${config.environment.etc."os-release".source}, 388 r ${config.environment.etc."lsb-release".source}, 389 owner rwk /var/lib/murmur/murmur.sqlite, 390 owner rw /var/lib/murmur/murmur.sqlite-journal, 391 owner r /var/lib/murmur/, 392 r /run/murmur/murmurd.pid, 393 r /run/murmur/murmurd.ini, 394 r ${configFile}, 395 '' + optionalString (cfg.logFile != null) '' 396 rw ${cfg.logFile}, 397 '' + optionalString (cfg.sslCert != "") '' 398 r ${cfg.sslCert}, 399 '' + optionalString (cfg.sslKey != "") '' 400 r ${cfg.sslKey}, 401 '' + optionalString (cfg.sslCa != "") '' 402 r ${cfg.sslCa}, 403 '' + optionalString (cfg.dbus != null) '' 404 dbus bus=${cfg.dbus} 405 '' + '' 406 } 407 ''; 408 }; 409}