diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index 2c89bed9c9c3..ca32aab07ca1 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -588,6 +588,7 @@
./services/networking/atftpd.nix
./services/networking/avahi-daemon.nix
./services/networking/babeld.nix
+ ./services/networking/biboumi.nix
./services/networking/bind.nix
./services/networking/bitcoind.nix
./services/networking/autossh.nix
diff --git a/nixos/modules/services/networking/biboumi.nix b/nixos/modules/services/networking/biboumi.nix
new file mode 100644
index 000000000000..66ddca93d818
--- /dev/null
+++ b/nixos/modules/services/networking/biboumi.nix
@@ -0,0 +1,269 @@
+{ config, lib, pkgs, options, ... }:
+with lib;
+let
+ cfg = config.services.biboumi;
+ inherit (config.environment) etc;
+ rootDir = "/run/biboumi/mnt-root";
+ stateDir = "/var/lib/biboumi";
+ settingsFile = pkgs.writeText "biboumi.cfg" (
+ generators.toKeyValue {
+ mkKeyValue = k: v:
+ if v == null then ""
+ else generators.mkKeyValueDefault {} "=" k v;
+ } cfg.settings);
+ need_CAP_NET_BIND_SERVICE = cfg.settings.identd_port != 0 && cfg.settings.identd_port < 1024;
+in
+{
+ options = {
+ services.biboumi = {
+ enable = mkEnableOption "the Biboumi XMPP gateway to IRC";
+
+ settings = mkOption {
+ description = ''
+ See biboumi 8.5
+ for documentation.
+ '';
+ default = {};
+ type = types.submodule {
+ freeformType = with types;
+ (attrsOf (nullOr (oneOf [str int bool]))) // {
+ description = "settings option";
+ };
+ options.admin = mkOption {
+ type = with types; listOf str;
+ default = [];
+ example = ["admin@example.org"];
+ apply = concatStringsSep ":";
+ description = ''
+ The bare JID of the gateway administrator. This JID will have more
+ privileges than other standard users, for example some administration
+ ad-hoc commands will only be available to that JID.
+ '';
+ };
+ options.ca_file = mkOption {
+ type = types.path;
+ default = "/etc/ssl/certs/ca-certificates.crt";
+ description = ''
+ Specifies which file should be used as the list of trusted CA
+ when negociating a TLS session.
+ '';
+ };
+ options.db_name = mkOption {
+ type = with types; either path str;
+ default = "${stateDir}/biboumi.sqlite";
+ description = ''
+ The name of the database to use.
+ '';
+ example = "postgresql://user:secret@localhost";
+ };
+ options.hostname = mkOption {
+ type = types.str;
+ example = "biboumi.example.org";
+ description = ''
+ The hostname served by the XMPP gateway.
+ This domain must be configured in the XMPP server
+ as an external component.
+ '';
+ };
+ options.identd_port = mkOption {
+ type = types.port;
+ default = 113;
+ example = 0;
+ description = ''
+ The TCP port on which to listen for identd queries.
+ '';
+ };
+ options.log_level = mkOption {
+ type = types.ints.between 0 3;
+ default = 1;
+ description = ''
+ Indicate what type of log messages to write in the logs.
+ 0 is debug, 1 is info, 2 is warning, 3 is error.
+ '';
+ };
+ options.password = mkOption {
+ type = with types; nullOr str;
+ description = ''
+ The password used to authenticate the XMPP component to your XMPP server.
+ This password must be configured in the XMPP server,
+ associated with the external component on
+ hostname.
+
+ Set it to null and use credentialsFile
+ if you do not want this password to go into the Nix store.
+ '';
+ };
+ options.persistent_by_default = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ Whether all rooms will be persistent by default:
+ the value of the “persistent” option in the global configuration of each
+ user will be “true”, but the value of each individual room will still
+ default to false. This means that a user just needs to change the global
+ “persistent” configuration option to false in order to override this.
+ '';
+ };
+ options.policy_directory = mkOption {
+ type = types.path;
+ default = "${pkgs.biboumi}/etc/biboumi";
+ description = ''
+ A directory that should contain the policy files,
+ used to customize Botan’s behaviour
+ when negociating the TLS connections with the IRC servers.
+ '';
+ };
+ options.port = mkOption {
+ type = types.port;
+ default = 5347;
+ description = ''
+ The TCP port to use to connect to the local XMPP component.
+ '';
+ };
+ options.realname_customization = mkOption {
+ type = types.bool;
+ default = true;
+ description = ''
+ Whether the users will be able to use
+ the ad-hoc commands that lets them configure
+ their realname and username.
+ '';
+ };
+ options.realname_from_jid = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ Whether the realname and username of each biboumi
+ user will be extracted from their JID.
+ Otherwise they will be set to the nick
+ they used to connect to the IRC server.
+ '';
+ };
+ options.xmpp_server_ip = mkOption {
+ type = types.str;
+ default = "127.0.0.1";
+ description = ''
+ The IP address to connect to the XMPP server on.
+ The connection to the XMPP server is unencrypted,
+ so the biboumi instance and the server should
+ normally be on the same host.
+ '';
+ };
+ };
+ };
+
+ credentialsFile = mkOption {
+ type = types.path;
+ description = ''
+ Path to a configuration file to be merged with the settings.
+ Beware not to surround "=" with spaces when setting biboumi's options in this file.
+ Useful to merge a file which is better kept out of the Nix store
+ because it contains sensible data like
+ password.
+ '';
+ default = "/dev/null";
+ example = "/run/keys/biboumi.cfg";
+ };
+
+ openFirewall = mkEnableOption "opening of the identd port in the firewall";
+ };
+ };
+
+ config = mkIf cfg.enable {
+ networking.firewall = mkIf (cfg.openFirewall && cfg.settings.identd_port != 0)
+ { allowedTCPPorts = [ cfg.settings.identd_port ]; };
+
+ systemd.services.biboumi = {
+ description = "Biboumi, XMPP to IRC gateway";
+ after = [ "network.target" ];
+ wantedBy = [ "multi-user.target" ];
+
+ serviceConfig = {
+ Type = "notify";
+ # Biboumi supports systemd's watchdog.
+ WatchdogSec = 20;
+ Restart = "always";
+ # Use "+" because credentialsFile may not be accessible to User= or Group=.
+ ExecStartPre = [("+" + pkgs.writeShellScript "biboumi-prestart" ''
+ set -eux
+ cat ${settingsFile} '${cfg.credentialsFile}' |
+ install -m 644 /dev/stdin /run/biboumi/biboumi.cfg
+ '')];
+ ExecStart = "${pkgs.biboumi}/bin/biboumi /run/biboumi/biboumi.cfg";
+ ExecReload = "${pkgs.coreutils}/bin/kill -USR1 $MAINPID";
+ # Firewalls needing opening for output connections can still do that
+ # selectively for biboumi with:
+ # users.users.biboumi.isSystemUser = true;
+ # and, for example:
+ # networking.nftables.ruleset = ''
+ # add rule inet filter output meta skuid biboumi tcp accept
+ # '';
+ DynamicUser = true;
+ RootDirectory = rootDir;
+ RootDirectoryStartOnly = true;
+ InaccessiblePaths = [ "-+${rootDir}" ];
+ RuntimeDirectory = [ "biboumi" (removePrefix "/run/" rootDir) ];
+ RuntimeDirectoryMode = "700";
+ StateDirectory = "biboumi";
+ StateDirectoryMode = "700";
+ MountAPIVFS = true;
+ UMask = "0066";
+ BindPaths = [
+ stateDir
+ # This is for Type="notify"
+ # See https://github.com/systemd/systemd/issues/3544
+ "/run/systemd/notify"
+ "/run/systemd/journal/socket"
+ ];
+ BindReadOnlyPaths = [
+ builtins.storeDir
+ "/etc"
+ ];
+ # The following options are only for optimizing:
+ # systemd-analyze security biboumi
+ AmbientCapabilities = [ (optionalString need_CAP_NET_BIND_SERVICE "CAP_NET_BIND_SERVICE") ];
+ CapabilityBoundingSet = [ (optionalString need_CAP_NET_BIND_SERVICE "CAP_NET_BIND_SERVICE") ];
+ # ProtectClock= adds DeviceAllow=char-rtc r
+ DeviceAllow = "";
+ LockPersonality = true;
+ MemoryDenyWriteExecute = true;
+ NoNewPrivileges = true;
+ PrivateDevices = true;
+ PrivateMounts = true;
+ PrivateNetwork = mkDefault false;
+ PrivateTmp = true;
+ # PrivateUsers=true breaks AmbientCapabilities=CAP_NET_BIND_SERVICE
+ # See https://bugs.archlinux.org/task/65921
+ PrivateUsers = !need_CAP_NET_BIND_SERVICE;
+ ProtectClock = true;
+ ProtectControlGroups = true;
+ ProtectHome = true;
+ ProtectHostname = true;
+ ProtectKernelLogs = true;
+ ProtectKernelModules = true;
+ ProtectKernelTunables = true;
+ ProtectSystem = "strict";
+ RemoveIPC = true;
+ # AF_UNIX is for /run/systemd/notify
+ RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" ];
+ RestrictNamespaces = true;
+ RestrictRealtime = true;
+ RestrictSUIDSGID = true;
+ SystemCallFilter = [
+ "@system-service"
+ # Groups in @system-service which do not contain a syscall
+ # listed by perf stat -e 'syscalls:sys_enter_*' biboumi biboumi.cfg
+ # in tests, and seem likely not necessary for biboumi.
+ # To run such a perf in ExecStart=, you have to:
+ # - AmbientCapabilities="CAP_SYS_ADMIN"
+ # - mount -o remount,mode=755 /sys/kernel/debug/{,tracing}
+ "~@aio" "~@chown" "~@ipc" "~@keyring" "~@resources" "~@setuid" "~@timer"
+ ];
+ SystemCallArchitectures = "native";
+ SystemCallErrorNumber = "EPERM";
+ };
+ };
+ };
+
+ meta.maintainers = with maintainers; [ julm ];
+}
diff --git a/pkgs/servers/xmpp/biboumi/default.nix b/pkgs/servers/xmpp/biboumi/default.nix
index e1cec51e4ab0..257d94f4a733 100644
--- a/pkgs/servers/xmpp/biboumi/default.nix
+++ b/pkgs/servers/xmpp/biboumi/default.nix
@@ -3,11 +3,11 @@
stdenv.mkDerivation rec {
pname = "biboumi";
- version = "8.3";
+ version = "8.5";
src = fetchurl {
url = "https://git.louiz.org/biboumi/snapshot/biboumi-${version}.tar.xz";
- sha256 = "0896f52nh8vd0idkdznv3gj6wqh1nqhjbwv0m560f0h62f01vm7k";
+ sha256 = "0rn9p99iqdyvxjzjq9w0ra7pkk0mngjy65nlg3hqfdw8kq9mv5qf";
};
louiz_catch = fetchgit {
@@ -24,10 +24,7 @@ stdenv.mkDerivation rec {
preConfigure = ''
substituteInPlace CMakeLists.txt --replace /etc/biboumi $out/etc/biboumi
- substituteInPlace unit/biboumi.service.cmake --replace /bin/kill ${coreutils}/bin/kill
cp $louiz_catch/single_include/catch.hpp tests/
- # echo "policy_directory=$out/etc/biboumi" >> conf/biboumi.cfg
- # TODO include conf/biboumi.cfg as example somewhere
'';
enableParallelBuilding = true;