at 25.11-pre 11 kB view raw
1{ 2 config, 3 lib, 4 pkgs, 5 options, 6 ... 7}: 8let 9 cfg = config.services.biboumi; 10 inherit (config.environment) etc; 11 rootDir = "/run/biboumi/mnt-root"; 12 stateDir = "/var/lib/biboumi"; 13 settingsFile = pkgs.writeText "biboumi.cfg" ( 14 lib.generators.toKeyValue { 15 mkKeyValue = k: v: lib.optionalString (v != null) (lib.generators.mkKeyValueDefault { } "=" k v); 16 } cfg.settings 17 ); 18 need_CAP_NET_BIND_SERVICE = cfg.settings.identd_port != 0 && cfg.settings.identd_port < 1024; 19in 20{ 21 options = { 22 services.biboumi = { 23 enable = lib.mkEnableOption "the Biboumi XMPP gateway to IRC"; 24 25 package = lib.mkPackageOption pkgs "biboumi" { }; 26 27 settings = lib.mkOption { 28 description = '' 29 See [biboumi 9.0](https://doc.biboumi.louiz.org/9.0/admin.html#configuration) 30 31 for documentation. 32 ''; 33 default = { }; 34 type = lib.types.submodule { 35 freeformType = 36 with lib.types; 37 (attrsOf ( 38 nullOr (oneOf [ 39 str 40 int 41 bool 42 ]) 43 )) 44 // { 45 description = "settings option"; 46 }; 47 options.admin = lib.mkOption { 48 type = with lib.types; listOf str; 49 default = [ ]; 50 example = [ "admin@example.org" ]; 51 apply = lib.concatStringsSep ":"; 52 description = '' 53 The bare JID of the gateway administrator. This JID will have more 54 privileges than other standard users, for example some administration 55 ad-hoc commands will only be available to that JID. 56 ''; 57 }; 58 options.ca_file = lib.mkOption { 59 type = lib.types.path; 60 default = config.security.pki.caBundle; 61 defaultText = lib.literalExpression "config.security.pki.caBundle"; 62 description = '' 63 Specifies which file should be used as the list of trusted CA 64 when negotiating a TLS session. 65 ''; 66 }; 67 options.db_name = lib.mkOption { 68 type = with lib.types; nullOr (either path str); 69 default = "${stateDir}/biboumi.sqlite"; 70 description = '' 71 The name of the database to use. 72 73 Set it to null and use [credentialsFile](#opt-services.biboumi.credentialsFile) 74 if you do not want this connection string to go into the Nix store. 75 ''; 76 example = "postgresql://user:secret@localhost"; 77 }; 78 options.hostname = lib.mkOption { 79 type = lib.types.str; 80 example = "biboumi.example.org"; 81 description = '' 82 The hostname served by the XMPPgateway. 83 This domain must be configured in the XMPP server 84 as an external component. 85 ''; 86 }; 87 options.identd_port = lib.mkOption { 88 type = lib.types.port; 89 default = 113; 90 example = 0; 91 description = '' 92 The TCP port on which to listen for identd queries. 93 ''; 94 }; 95 options.log_level = lib.mkOption { 96 type = lib.types.ints.between 0 3; 97 default = 1; 98 description = '' 99 Indicate what type of log messages to write in the logs. 100 0 is debug, 1 is info, 2 is warning, 3 is error. 101 ''; 102 }; 103 options.password = lib.mkOption { 104 type = with lib.types; nullOr str; 105 description = '' 106 The password used to authenticate the XMPP component to your XMPP server. 107 This password must be configured in the XMPP server, 108 associated with the external component on 109 [hostname](#opt-services.biboumi.settings.hostname). 110 111 Set it to null and use [credentialsFile](#opt-services.biboumi.credentialsFile) 112 if you do not want this password to go into the Nix store. 113 ''; 114 }; 115 options.persistent_by_default = lib.mkOption { 116 type = lib.types.bool; 117 default = false; 118 description = '' 119 Whether all rooms will be persistent by default: 120 the value of the persistent option in the global configuration of each 121 user will be true, but the value of each individual room will still 122 default to false. This means that a user just needs to change the global 123 persistent configuration option to false in order to override this. 124 ''; 125 }; 126 options.policy_directory = lib.mkOption { 127 type = lib.types.path; 128 default = "${cfg.package}/etc/biboumi"; 129 defaultText = lib.literalExpression ''"''${pkgs.biboumi}/etc/biboumi"''; 130 description = '' 131 A directory that should contain the policy files, 132 used to customize Botans behaviour 133 when negotiating the TLS connections with the IRC servers. 134 ''; 135 }; 136 options.port = lib.mkOption { 137 type = lib.types.port; 138 default = 5347; 139 description = '' 140 The TCP port to use to connect to the local XMPP component. 141 ''; 142 }; 143 options.realname_customization = lib.mkOption { 144 type = lib.types.bool; 145 default = true; 146 description = '' 147 Whether the users will be able to use 148 the ad-hoc commands that lets them configure 149 their realname and username. 150 ''; 151 }; 152 options.realname_from_jid = lib.mkOption { 153 type = lib.types.bool; 154 default = false; 155 description = '' 156 Whether the realname and username of each biboumi 157 user will be extracted from their JID. 158 Otherwise they will be set to the nick 159 they used to connect to the IRC server. 160 ''; 161 }; 162 options.xmpp_server_ip = lib.mkOption { 163 type = lib.types.str; 164 default = "127.0.0.1"; 165 description = '' 166 The IP address to connect to the XMPP server on. 167 The connection to the XMPP server is unencrypted, 168 so the biboumi instance and the server should 169 normally be on the same host. 170 ''; 171 }; 172 }; 173 }; 174 175 credentialsFile = lib.mkOption { 176 type = lib.types.path; 177 description = '' 178 Path to a configuration file to be merged with the settings. 179 Beware not to surround "=" with spaces when setting biboumi's options in this file. 180 Useful to merge a file which is better kept out of the Nix store 181 because it contains sensible data like 182 [password](#opt-services.biboumi.settings.password). 183 ''; 184 default = "/dev/null"; 185 example = "/run/keys/biboumi.cfg"; 186 }; 187 188 openFirewall = lib.mkEnableOption "opening of the identd port in the firewall"; 189 }; 190 }; 191 192 config = lib.mkIf cfg.enable { 193 networking.firewall = lib.mkIf (cfg.openFirewall && cfg.settings.identd_port != 0) { 194 allowedTCPPorts = [ cfg.settings.identd_port ]; 195 }; 196 197 systemd.services.biboumi = { 198 description = "Biboumi, XMPP to IRC gateway"; 199 after = [ "network.target" ]; 200 wantedBy = [ "multi-user.target" ]; 201 202 serviceConfig = { 203 Type = "notify"; 204 # Biboumi supports systemd's watchdog. 205 WatchdogSec = 20; 206 Restart = "always"; 207 # Use "+" because credentialsFile may not be accessible to User= or Group=. 208 ExecStartPre = [ 209 ( 210 "+" 211 + pkgs.writeShellScript "biboumi-prestart" '' 212 set -eux 213 cat ${settingsFile} '${cfg.credentialsFile}' | 214 install -m 644 /dev/stdin /run/biboumi/biboumi.cfg 215 '' 216 ) 217 ]; 218 ExecStart = "${lib.getExe cfg.package} /run/biboumi/biboumi.cfg"; 219 ExecReload = "${pkgs.coreutils}/bin/kill -USR1 $MAINPID"; 220 # Firewalls needing opening for output connections can still do that 221 # selectively for biboumi with: 222 # users.users.biboumi.isSystemUser = true; 223 # and, for example: 224 # networking.nftables.ruleset = '' 225 # add rule inet filter output meta skuid biboumi tcp accept 226 # ''; 227 DynamicUser = true; 228 RootDirectory = rootDir; 229 RootDirectoryStartOnly = true; 230 InaccessiblePaths = [ "-+${rootDir}" ]; 231 RuntimeDirectory = [ 232 "biboumi" 233 (lib.removePrefix "/run/" rootDir) 234 ]; 235 RuntimeDirectoryMode = "700"; 236 StateDirectory = "biboumi"; 237 StateDirectoryMode = "700"; 238 MountAPIVFS = true; 239 UMask = "0066"; 240 BindPaths = [ 241 stateDir 242 # This is for Type="notify" 243 # See https://github.com/systemd/systemd/issues/3544 244 "/run/systemd/notify" 245 "/run/systemd/journal/socket" 246 ]; 247 BindReadOnlyPaths = [ 248 builtins.storeDir 249 "/etc" 250 ]; 251 # The following options are only for optimizing: 252 # systemd-analyze security biboumi 253 AmbientCapabilities = [ (lib.optionalString need_CAP_NET_BIND_SERVICE "CAP_NET_BIND_SERVICE") ]; 254 CapabilityBoundingSet = [ (lib.optionalString need_CAP_NET_BIND_SERVICE "CAP_NET_BIND_SERVICE") ]; 255 # ProtectClock= adds DeviceAllow=char-rtc r 256 DeviceAllow = ""; 257 LockPersonality = true; 258 MemoryDenyWriteExecute = true; 259 NoNewPrivileges = true; 260 PrivateDevices = true; 261 PrivateMounts = true; 262 PrivateNetwork = lib.mkDefault false; 263 PrivateTmp = true; 264 # PrivateUsers=true breaks AmbientCapabilities=CAP_NET_BIND_SERVICE 265 # See https://bugs.archlinux.org/task/65921 266 PrivateUsers = !need_CAP_NET_BIND_SERVICE; 267 ProtectClock = true; 268 ProtectControlGroups = true; 269 ProtectHome = true; 270 ProtectHostname = true; 271 ProtectKernelLogs = true; 272 ProtectKernelModules = true; 273 ProtectKernelTunables = true; 274 ProtectSystem = "strict"; 275 RemoveIPC = true; 276 # AF_UNIX is for /run/systemd/notify 277 RestrictAddressFamilies = [ 278 "AF_UNIX" 279 "AF_INET" 280 "AF_INET6" 281 ]; 282 RestrictNamespaces = true; 283 RestrictRealtime = true; 284 RestrictSUIDSGID = true; 285 SystemCallFilter = [ 286 "@system-service" 287 # Groups in @system-service which do not contain a syscall 288 # listed by perf stat -e 'syscalls:sys_enter_*' biboumi biboumi.cfg 289 # in tests, and seem likely not necessary for biboumi. 290 # To run such a perf in ExecStart=, you have to: 291 # - AmbientCapabilities="CAP_SYS_ADMIN" 292 # - mount -o remount,mode=755 /sys/kernel/debug/{,tracing} 293 "~@aio" 294 "~@chown" 295 "~@ipc" 296 "~@keyring" 297 "~@resources" 298 "~@setuid" 299 "~@timer" 300 ]; 301 SystemCallArchitectures = "native"; 302 SystemCallErrorNumber = "EPERM"; 303 }; 304 }; 305 }; 306 307 meta.maintainers = with lib.maintainers; [ julm ]; 308}