biboumi: add service
authorJulien Moutinho <julm@sourcephile.fr>
Sat, 8 Aug 2020 05:41:18 +0000 (07:41 +0200)
committerJulien Moutinho <julm@sourcephile.fr>
Sat, 8 Aug 2020 06:02:48 +0000 (08:02 +0200)
machines/losurdo/networking/nftables.nix
machines/losurdo/prosody.nix
machines/losurdo/prosody/biboumi.nix [new file with mode: 0644]
nixos/modules.nix
nixpkgs/overlays.nix
nixpkgs/overlays/prosody.nix
nixpkgs/patches/security.gnupg.diff [deleted file]
nixpkgs/patches/security.pass.diff [deleted file]
nixpkgs/patches/services.croc.diff [deleted file]
nixpkgs/patches/transmission+apparmor.diff [deleted file]
shell.nix

index 137f00c87a8f6e219f4936bd4475ae94ad5db074..ef59cd5c3dc9383f4d94817ae543d5e1d8531612 100644 (file)
@@ -68,7 +68,9 @@ networking.nftables = {
         ct state {related,established} accept
         ct state invalid drop
 
+        ip6 nexthdr icmpv6 icmpv6 type echo-request accept comment "Ping6"
         icmp type echo-request counter accept comment "Ping"
+
         tcp dport 22 counter accept comment "SSH"
 
         # Some .nix append gotos here with: add rule inet filter output oifname ... goto ...
index f71b6a81cdd3816b293a9d9eda40c0f7a35eb26e..e2a94dca5caa74e28710359419ed9e0de413ac6d 100644 (file)
@@ -1,4 +1,4 @@
-{ pkgs, lib, config, machines, ... }:
+{ pkgs, lib, config, machines, ipv4, ... }:
 let
   inherit (builtins.extraBuiltins) pass-chomp;
   inherit (config) networking;
@@ -7,7 +7,7 @@ let
 in
 {
 imports = [
-  #prosody/biboumi.nix
+  prosody/biboumi.nix
 ];
 networking.nftables.ruleset = ''
   add rule inet filter net2fw tcp dport {5222,5269} counter accept comment "XMPP"
@@ -29,6 +29,7 @@ services.prosody = {
   xmppComplianceSuite = true;
   modules = {
     announce = true;
+    blocklist = true;
     cloud_notify = true;
     groups = true;
     limits = false;
@@ -44,6 +45,10 @@ services.prosody = {
     #"extdisco"
   ];
   extraConfig = ''
+    -- Listen only in IPv4 until hosting provider's IPv6 works well.
+    interfaces = { "0.0.0.0" }
+    c2s_interfaces = { "0.0.0.0" }
+
     turncredentials_host = "turn.${networking.domain}"
     turncredentials_secret = "${pass-chomp "machines/mermet/coturn/static-auth-secret"}"
     turncredentials_port = 3478
@@ -74,8 +79,8 @@ services.prosody = {
       proxy65_address = "proxy65.${networking.domain}"
       proxy65_acl = { "${networking.domain}" }
       
-    -- Component "irc.${networking.domain}"
-    --   component_secret = "useless-secret-on-loopback"
+    Component "biboumi.${networking.domain}"
+      component_secret = "useless-secret-on-loopback"
   '';
   #ports = {80};
   #ssl_ports = {443};
@@ -124,7 +129,10 @@ services.prosody = {
   authentication = "internal_hashed";
   httpPorts = [];
   httpsPorts = [5281];
-  disco_items = [];
+  disco_items = [
+    { url = "biboumi.${networking.domain}";
+      description = "Passerelle vers des serveurs IRC (Internet Relay Chat)"; }
+  ];
   package = pkgs.prosody.override {
     withCommunityModules = [
       "turncredentials"
diff --git a/machines/losurdo/prosody/biboumi.nix b/machines/losurdo/prosody/biboumi.nix
new file mode 100644 (file)
index 0000000..df8ca91
--- /dev/null
@@ -0,0 +1,31 @@
+{ pkgs, lib, config, ... }:
+let
+  inherit (config) networking;
+  inherit (config.services) biboumi;
+  inherit (config.users) users;
+in
+{
+networking.nftables.ruleset = ''
+  add rule inet filter net2fw tcp dport ${toString biboumi.settings.identd_port} counter accept comment "identd"
+  add rule inet filter fw2net meta skuid ${users.biboumi.name} tcp counter accept comment "Biboumi"
+'';
+users.users.biboumi.isSystemUser = true;
+systemd.services.biboumi.after = ["prosody.service"];
+services.biboumi = {
+  enable = true;
+  settings = {
+    hostname = "biboumi.${networking.domain}";
+    password = "useless-secret-on-loopback";
+    xmpp_server_ip = "127.0.0.1";
+    port = 5347;
+    admin = lib.concatStringsSep ":" [
+      "julm@${networking.domain}"
+    ];
+    #fixed_irc_server = "";
+    persistent_by_default = true;
+    realname_customization = true;
+    realname_from_jid = false;
+    log_level = 1;
+  };
+};
+}
index 89825ee4a9a438d00d6b4f13c8ebf5598708cc5c..683c961c802ace824d20311e526cd068012580bb 100644 (file)
@@ -5,12 +5,15 @@
 imports = [
   modules/services/databases/openldap.nix
   modules/services/mail/public-inbox.nix
+  #modules/services/networking/biboumi.nix
+  #/home/julm/src/nix/nixpkgs/.git-worktree/transmission/nixos/modules/services/torrent/transmission.nix
   #/home/julm/src/nix/nixpkgs/nixos/modules/services/torrent/transmission.nix
   #modules/services/mail/mlmmj.nix
 ];
 disabledModules = [
   "services/mail/mlmmj.nix"
   "services/mail/public-inbox.nix"
+  #"services/networking/biboumi.nix"
   #"services/torrent/transmission.nix"
 ];
 }
index 4b4d21f4501c3d4cc9aa0196379670ddcd12da15..ee22aef428321df02d74ca497ef58e8dae5fa5b7 100644 (file)
@@ -4,5 +4,4 @@ map import
   overlays/public-inbox.nix
   overlays/smartctl-tbw.nix
   overlays/swaplist.nix
-  overlays/prosody.nix
 ]
index 97b6f28b9711fdf9b7a265406c14da802ad9b571..1b23ac5f407efb475dcf7772302624935696a4fc 100644 (file)
@@ -2,8 +2,8 @@ self: super: {
   prosody = super.prosody.overrideAttrs (oldAttrs:  {
     communityModules = super.fetchhg {
       url = "https://hg.prosody.im/prosody-modules";
-      rev = "268fa9d45840";
-      sha256 = "1a5ihbg5b0bsw224hdj4fxwy0j98yjzbijz85gd34x923dh3vvkl";
+      rev = "2dcbc01c9931";
+      sha256 = "0ydhbvfp7vk5zqpsc54ihxz6y2gmzh0bcgyz0xidlxrmxzwcvvyh";
     };
   });
 }
diff --git a/nixpkgs/patches/security.gnupg.diff b/nixpkgs/patches/security.gnupg.diff
deleted file mode 100644 (file)
index b7b37b9..0000000
+++ /dev/null
@@ -1,289 +0,0 @@
-diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
-index f361163ca63..8c199f0fc25 100644
---- a/nixos/modules/module-list.nix
-+++ b/nixos/modules/module-list.nix
-@@ -193,6 +193,7 @@
-   ./security/lock-kernel-modules.nix
-   ./security/misc.nix
-   ./security/oath.nix
-+  ./security/gnupg.nix
-   ./security/pam.nix
-   ./security/pam_usb.nix
-   ./security/pam_mount.nix
-diff --git a/nixos/modules/security/gnupg.nix b/nixos/modules/security/gnupg.nix
-new file mode 100644
-index 00000000000..cbf9aad3eae
---- /dev/null
-+++ b/nixos/modules/security/gnupg.nix
-@@ -0,0 +1,271 @@
-+{ config, lib, pkgs, ... }:
-+let
-+  inherit (builtins) dirOf match split;
-+  inherit (lib) types;
-+  cfg = config.security.gnupg;
-+  gnupgHome = "/var/lib/gnupg";
-+  escapeUnitName = name:
-+    lib.concatMapStrings (s: if lib.isList s then "-" else s)
-+    (split "[^a-zA-Z0-9_.\\-]+" name);
-+in
-+{
-+options.security.gnupg = {
-+  store = lib.mkOption {
-+    type = types.path;
-+    default = "/root/.password-store";
-+    description = ''
-+      Default base path for the <literal>gpg</literal> option
-+      of the <link linkend="opt-security.gnupg.secrets">secrets</link>.
-+      Note that you may set it up with something like:
-+      <literal>builtins.getEnv "PASSWORD_STORE_DIR" + "/machines/example"</literal>.
-+    '';
-+    # Does not copy the entire password-store into the Nix store,
-+    # only the keys actually used will be.
-+    apply = toString;
-+  };
-+  secrets = lib.mkOption {
-+    description = "Available secrets.";
-+    default = {};
-+    example = {
-+      "/root/.ssh/id_ed25519" = {};
-+      "knot/tsig/example.org/acme.conf" = {
-+        user = "knot";
-+      };
-+      "lego/example.org/rfc2136" = {
-+        pipe = "
-+          cat -
-+          cat <EOF
-+          RFC2136_NAMESERVER=ns.example.org:53
-+          RFC2136_TSIG_ALGORITHM=hmac-sha256.
-+          RFC2136_TSIG_KEY=acme_example_org
-+          RFC2136_PROPAGATION_TIMEOUT=1000
-+          RFC2136_POLLING_INTERVAL=30
-+          RFC2136_SEQUENCE_INTERVAL=30
-+          RFC2136_DNS_TIMEOUT=1000
-+          RFC2136_TTL=1
-+          EOF
-+        ";
-+      };
-+    };
-+    type = types.attrsOf (types.submodule ({name, config, ...}: {
-+      options = {
-+        gpg = lib.mkOption {
-+          type = types.path;
-+          default = builtins.path {
-+            path = cfg.store + "/${name}.gpg";
-+            name = "${escapeUnitName name}.gpg";
-+          };
-+          description = ''
-+            The path to the GnuPG-encrypted secret.
-+            It will be copied into the Nix store of the orchestrating and of the target system.
-+            It must be decipherable by an OpenPGP key within the GnuPG home <filename>/var/lib/gnupg/</filename>.
-+            Defaults to the name of the secret,
-+            prefixed by the path of the <link linkend="opt-security.gnupg.store">store</link>
-+            and suffixed by <filename>.gpg</filename>.
-+          '';
-+        };
-+        mode = lib.mkOption {
-+          type = types.str;
-+          default = "400";
-+          description = ''
-+            Permission mode of the secret <literal>path</literal>.
-+          '';
-+        };
-+        user = lib.mkOption {
-+          type = types.str;
-+          default = "root";
-+          description = ''
-+            Owner of the secret <literal>path</literal>.
-+          '';
-+        };
-+        group = lib.mkOption {
-+          type = types.str;
-+          default = "root";
-+          description = ''
-+            Group of the secret <literal>path</literal>.
-+          '';
-+        };
-+        pipe = lib.mkOption {
-+          type = types.nullOr types.str;
-+          default = null;
-+          apply = x: if x == null then null else pkgs.writeShellScript "pipe" x;
-+          description = ''
-+            Shell script taking the deciphered secret on its standard input
-+            and which must put on its standard output
-+            the actual secret material to be installed.
-+            This allows to decorate the secret with non-secret bits.
-+          '';
-+        };
-+        path = lib.mkOption {
-+          type = types.str;
-+          default = name;
-+          apply = p: if match "^/.*" p == null then "/run/keys/gnupg/"+p+"/file" else p;
-+          description = ''
-+            The path on the target system where the secret is installed to.
-+            Default to the name of the secret,
-+            prefixed by <filename>/run/keys/gnupg/</filename>
-+            and suffixed by <filename>/file</filename>,
-+            if non-absolute.
-+          '';
-+        };
-+        service = lib.mkOption {
-+          type = types.str;
-+          default = "secret-" + escapeUnitName name + ".service";
-+          description = ''
-+            The name of the systemd service.
-+            Useful to put constraints like <literal>after</literal> or <literal>wants</wants>
-+            into services requiring this secret.
-+          '';
-+        };
-+        postStart = lib.mkOption {
-+          type = types.lines;
-+          default = "";
-+          example = "systemctl reload nginx.service";
-+          description = ''
-+            Commands to run after new secrets go live.
-+            Typically the web server and other servers using secrets
-+            need to be reloaded.
-+          '';
-+        };
-+        postStop = lib.mkOption {
-+          type = types.lines;
-+          default = "";
-+          example = ''shred -u "$secret_file"'';
-+          description = ''
-+            Commands to run after stopping the service.
-+            Typically removing a persistent secret.
-+            For convenience the <literal>path</literal> of the secret
-+            is provided in the shell variable <literal>secret_file</literal>.
-+          '';
-+        };
-+      };
-+    }));
-+  };
-+  enableGpgAgent = lib.mkEnableOption ''gpg-agent for decrypting secrets.
-+
-+    Otherwise, you'll have to forward an <literal>agent-extra-socket</literal>:
-+    <screen>
-+    <prompt>$ </prompt>ssh -nNT root@example.org -o StreamLocalBindUnlink=yes -R /var/lib/gnupg/S.gpg-agent:$(gpgconf --list-dirs agent-extra-socket)
-+    </screen>
-+  '' // {default = true; example = false;};
-+  gpgAgentFlags = lib.mkOption {
-+    type = types.listOf types.str;
-+    default = [
-+      "--default-cache-ttl" "600"
-+      "--max-cache-ttl" "7200"
-+    ];
-+    description = ''
-+      Extra flags passed to the <literal>gpg-agent</literal>
-+      used to decrypt secrets.
-+    '';
-+  };
-+};
-+config = lib.mkIf (cfg.secrets != {}) {
-+  # Because /run/user/0 is wiped out by pam_systemd when root logouts,
-+  # systemd.services.gpg-agent cannot put its socket in
-+  # the path expected by gpg: /run/user/0/gnupg/d.6qoenf9br6fajbkknuz1i6ts
-+  # derived from ${gnupgHome}, since this removal would kill gpg-agent.
-+  #
-+  # Unfortunately, for reaching such a persistent gpg-agent,
-+  # GPG_AGENT_INFO can no longer be used as it is ignored with gpg >= 2.1,
-+  # hence three different hacks are done here to make gpg connect
-+  # to ${gnupgHome}/S.gpg-agent depending on the concern:
-+  # - For gpg-agent, --supervised mode is used to pass it a socket
-+  #   in the persistent directory gnupgHome.
-+  # - For the root user, on its login pam_systemd is mounting a fresh tmpfs on /run/user/0
-+  #   so wrong perms are set on /run/user/0/gnupg/d.6qoenf9br6fajbkknuz1i6ts
-+  #   when /run/user/0 is mounted, by overriding user-runtime-dir@.service
-+  # - For secret decrypting services, /run/user/0/gnupg
-+  #   is emptied and keept empty by privately mounting
-+  #   an empty directory on it, using BindReadOnlyPaths=
-+  systemd.sockets."gpg-agent" = lib.optionalAttrs cfg.enableGpgAgent {
-+    description = "Socket for gpg-agent";
-+    wantedBy = ["sockets.target"];
-+    socketConfig.ListenStream = "${gnupgHome}/S.gpg-agent";
-+    socketConfig.SocketMode = "0600";
-+  };
-+  environment.systemPackages =
-+    # TODO: maybe this would be better to do that directly in pkgs.gnupg?
-+    let gpgPresetPassphrase = pkgs.runCommand "gpg-preset-passphrase"
-+      { preferLocalBuild = true;
-+        allowSubstitutes = false;
-+      } ''
-+      mkdir -p $out/bin
-+      ln -s -t $out/bin ${pkgs.gnupg}/libexec/gpg-preset-passphrase
-+    ''; in
-+    [ pkgs.gnupg gpgPresetPassphrase ];
-+  systemd.packages = [
-+    # Here, passing by systemd.packages is kind of a hack to be able to
-+    # write this file which is neither writable using environment.etc
-+    # (because environment.etc."systemd/system".source is set)
-+    # nor using systemd.services (because systemd.services."user-runtime-dir@0"
-+    # does not exist, and should not to keep using systemd's upstream template
-+    # and systemd.services."user-runtime-dir@").
-+    (pkgs.writeTextDir "etc/systemd/system/user-runtime-dir@0.service.d/override.conf" ''
-+      [Unit]
-+      [Service]
-+      ExecStartPost=${pkgs.writeShellScript "redirect-gpg-agent-run-socket" ''
-+        install -D -d -m 640 /run/user/0/gnupg/d.6qoenf9br6fajbkknuz1i6ts
-+      ''}
-+    '')
-+  ];
-+  systemd.services =
-+    lib.optionalAttrs cfg.enableGpgAgent {
-+      gpg-agent = {
-+        description = "gpg-agent for decrypting GnuPG-protected secrets";
-+        requires = ["gpg-agent.socket"];
-+        serviceConfig = {
-+          Type = "simple";
-+          ExecStart = ''${pkgs.gnupg}/bin/gpg-agent \
-+           --supervised \
-+           --homedir '${gnupgHome}' \
-+           --allow-loopback-pinentry \
-+           --allow-preset-passphrase \
-+           ${lib.escapeShellArgs cfg.gpgAgentFlags}
-+          '';
-+          Restart = "on-failure";
-+          RestartSec = 5;
-+          StateDirectory = ["gnupg" "gnupg/empty"];
-+          StateDirectoryMode = "700";
-+        };
-+      };
-+    } //
-+    lib.mapAttrs' (target: secret:
-+      lib.nameValuePair (lib.removeSuffix ".service" secret.service) {
-+        description = "Install secret ${secret.path}";
-+        after = ["gpg-agent.service"];
-+        wants = ["gpg-agent.service"];
-+        script = ''
-+          set -o pipefail
-+          set -eux
-+          decrypt() {
-+            ${pkgs.gnupg}/bin/gpg --homedir '${gnupgHome}' --no-autostart --batch --decrypt '${secret.gpg}' |
-+            ${lib.optionalString (secret.pipe != null) (secret.pipe+" |")} \
-+            install -D -m '${secret.mode}' -o '${secret.user}' -g '${secret.group}' /dev/stdin '${secret.path}'
-+          }
-+          while ! decrypt; do sleep $((1 + ($RANDOM % 12))); done
-+        '';
-+        postStart = lib.optionalString (secret.postStart != "") ''
-+          set -eux
-+          ${secret.postStart}
-+        '';
-+        postStop = lib.optionalString (secret.postStop != "") ''
-+          secret_file='${secret.path}'
-+          set -eux
-+          ${secret.postStop}
-+        '';
-+        serviceConfig = {
-+          Type = "oneshot";
-+          RemainAfterExit = true;
-+          PrivateTmp = true;
-+          BindReadOnlyPaths = [ "/var/lib/gnupg/empty:/run/user/0/gnupg" ];
-+        } // lib.optionalAttrs (match "^/.*" target == null) {
-+          RuntimeDirectory = lib.removePrefix "/run/" (dirOf secret.path);
-+          RuntimeDirectoryMode = "711";
-+          RuntimeDirectoryPreserve = false;
-+        };
-+      }
-+    ) cfg.secrets;
-+};
-+meta.maintainers = with lib.maintainers; [ julm ];
-+}
diff --git a/nixpkgs/patches/security.pass.diff b/nixpkgs/patches/security.pass.diff
deleted file mode 100644 (file)
index df45009..0000000
+++ /dev/null
@@ -1,234 +0,0 @@
-diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
-index f361163ca63..5e306de7dad 100644
---- a/nixos/modules/module-list.nix
-+++ b/nixos/modules/module-list.nix
-@@ -193,6 +193,7 @@
-   ./security/lock-kernel-modules.nix
-   ./security/misc.nix
-   ./security/oath.nix
-+  ./security/pass.nix
-   ./security/pam.nix
-   ./security/pam_usb.nix
-   ./security/pam_mount.nix
-diff --git a/nixos/modules/security/pass.nix b/nixos/modules/security/pass.nix
-new file mode 100644
-index 00000000000..28a0af36ac5
---- /dev/null
-+++ b/nixos/modules/security/pass.nix
-@@ -0,0 +1,216 @@
-+{ config, lib, pkgs, ... }:
-+let
-+  inherit (builtins) dirOf head listToAttrs match split;
-+  inherit (lib) types;
-+  cfg = config.security.pass;
-+  escapeUnitName = name:
-+    lib.concatMapStrings (s: if lib.isList s then "-" else s)
-+    (split "[^a-zA-Z0-9_.\\-]+" name);
-+in
-+{
-+options.security.pass = {
-+  store = lib.mkOption {
-+    type = types.path;
-+    default = lib.maybeEnv "PASSWORD_STORE_DIR" ".password-store";
-+    description = ''
-+      Default path to the password-store of the orchestrating system.
-+    '';
-+    # Does not copy the entire password-store into the Nix store,
-+    # only the keys actually used will be.
-+    apply = toString;
-+  };
-+  passphraseFile = lib.mkOption {
-+    type = types.str;
-+    default = "/root/key.pass";
-+    description = ''
-+      The directory on the target system to a file containing
-+      the password of an OpenPGP key in <literal>gnupgHome</literal>,
-+      to which <literal>gpg</literal> secret is encrypted to.
-+      Set it to a temporary directory like <literal>/run/keys/key.pass</literal>
-+      if you don't want it to persist accross reboot.
-+      It can be customized per secret.
-+    '';
-+  };
-+  gnupgHome = lib.mkOption {
-+    type = types.str;
-+    default = "/root/.gnupg";
-+    description = ''
-+      The directory on the target system to the <literal>gnupg</literal> home
-+      used to decrypt the secret.
-+      It can be customized per secret.
-+    '';
-+  };
-+  secrets = lib.mkOption {
-+    description = "Available secrets.";
-+    default = {};
-+    example = {
-+      "/root/.ssh/id_ed25519" = {};
-+      "knot/tsig/example.org/acme.conf" = {
-+        user = "knot";
-+      };
-+      "lego/example.org/rfc2136" = {
-+        pipe = "
-+          cat -
-+          cat <EOF
-+          RFC2136_NAMESERVER=ns.example.org:53
-+          RFC2136_TSIG_ALGORITHM=hmac-sha256.
-+          RFC2136_TSIG_KEY=acme_example_org
-+          RFC2136_PROPAGATION_TIMEOUT=1000
-+          RFC2136_POLLING_INTERVAL=30
-+          RFC2136_SEQUENCE_INTERVAL=30
-+          RFC2136_DNS_TIMEOUT=1000
-+          RFC2136_TTL=1
-+          EOF
-+        ";
-+      };
-+    };
-+    type = types.attrsOf (types.submodule ({name, config, ...}: {
-+      options = {
-+        gpg = lib.mkOption {
-+          type = types.path;
-+          default = builtins.path {
-+            path = cfg.store + "/${name}.gpg";
-+            name = "${escapeUnitName name}.gpg";
-+          };
-+          description = ''
-+            The path to the gnupg-encrypted secret.
-+            It will be copied into the Nix store of the orchestrating and of the target system.
-+            It must be decipherable by an OpenPGP key within <literal>gnupgHome</literal>,
-+            whose passhrase is on the target system into <literal>passphraseFile</literal>.
-+            Defaults to the name of the secret, prefixed by <literal>passwordStore</literal>
-+            and suffixed by <literal>.gpg</literal>.
-+          '';
-+        };
-+        gnupgHome = lib.mkOption {
-+          type = types.str;
-+          default = cfg.gnupgHome;
-+          description = ''
-+            Custom <literal>gnupgHome</literal> for this secret.
-+          '';
-+        };
-+        passphraseFile = lib.mkOption {
-+          type = types.str;
-+          default = cfg.passphraseFile;
-+          description = ''
-+            Custom <literal>passphraseFile</literal> for this secret.
-+          '';
-+        };
-+        mode = lib.mkOption {
-+          type = types.str;
-+          default = "400";
-+          description = ''
-+            Permission mode of the secret <literal>path</literal>.
-+          '';
-+        };
-+        user = lib.mkOption {
-+          type = types.str;
-+          default = "root";
-+          description = ''
-+            Owner of the secret <literal>path</literal>.
-+          '';
-+        };
-+        group = lib.mkOption {
-+          type = types.str;
-+          default = "root";
-+          description = ''
-+            Group of the secret <literal>path</literal>.
-+          '';
-+        };
-+        pipe = lib.mkOption {
-+          type = types.nullOr types.str;
-+          default = null;
-+          apply = x: if x == null then null else pkgs.writeShellScript "pipe" x;
-+          description = ''
-+            Shell script taking the deciphered secret on its standard input
-+            and which must put on its standard output
-+            the actual secret material to be installed.
-+            This allows to decorate the secret with non-secret bits.
-+          '';
-+        };
-+        path = lib.mkOption {
-+          type = types.str;
-+          default = name;
-+          apply = p: if match "^/.*" p == null then "/run/pass-secrets/"+p+"/file" else p;
-+          description = ''
-+            The path on the target system where the secret is installed to.
-+            Any non-absolute path is relative to <filename>/run/pass-secrets</filename>.
-+            Default to the name of the secret.
-+          '';
-+        };
-+        service = lib.mkOption {
-+          type = types.str;
-+          default = "secret-" + escapeUnitName name + ".service";
-+          description = ''
-+            The name of the systemd service.
-+            Useful to put constraints like <literal>after</literal> or <literal>wants</wants>
-+            into services requiring this secret.
-+          '';
-+        };
-+        postStart = lib.mkOption {
-+          type = types.lines;
-+          default = "";
-+          example = "systemctl reload nginx.service";
-+          description = ''
-+            Commands to run after new secrets go live.
-+            Typically the web server and other servers using secrets
-+            need to be reloaded.
-+          '';
-+        };
-+        postStop = lib.mkOption {
-+          type = types.lines;
-+          default = "";
-+          example = ''shred -u "$secret_file"'';
-+          description = ''
-+            Commands to run after stopping the service.
-+            Typically removing a persistent secret.
-+            For convenience the <literal>path</literal> of the secret
-+            is provided in the shell variable <literal>secret_file</literal>.
-+          '';
-+        };
-+      };
-+    }));
-+  };
-+};
-+config = lib.mkIf (cfg.secrets != {}) {
-+  systemd.services =
-+    lib.mapAttrs' (target: secret:
-+      lib.nameValuePair (lib.removeSuffix ".service" secret.service) {
-+        description = "Install secret ${secret.path}";
-+        script = ''
-+          set -o pipefail
-+          set -eux
-+          decrypt() {
-+            ${pkgs.gnupg}/bin/gpg --batch --pinentry-mode loopback \
-+             --passphrase-file '${secret.passphraseFile}' \
-+             --decrypt '${secret.gpg}' \
-+            ${lib.optionalString (secret.pipe != null) (" | "+secret.pipe)} |
-+            install -D -m '${secret.mode}' -o '${secret.user}' -g '${secret.group}' /dev/stdin \
-+             '${secret.path}'
-+          }
-+          while ! decrypt; do sleep $((1 + ($RANDOM % 10))); done
-+        '';
-+        postStart = lib.optionalString (secret.postStart != "") ''
-+          set -eux
-+          ${secret.postStart}
-+        '';
-+        postStop = lib.optionalString (secret.postStop != "") ''
-+          secret_file='${secret.path}'
-+          set -eux
-+          ${secret.postStop}
-+        '';
-+        serviceConfig = {
-+          Type = "oneshot";
-+          Environment = "GNUPGHOME=${secret.gnupgHome}";
-+          PrivateTmp = true;
-+          RemainAfterExit = true;
-+          WorkingDirectory = dirOf secret.gnupgHome;
-+        } // lib.optionalAttrs (match "^/.*" target == null) {
-+          RuntimeDirectory = lib.removePrefix "/run/" (dirOf secret.path);
-+          RuntimeDirectoryMode = "711";
-+          RuntimeDirectoryPreserve = false;
-+        };
-+      }
-+    ) cfg.secrets;
-+};
-+meta.maintainers = with lib.maintainers; [ julm ];
-+}
diff --git a/nixpkgs/patches/services.croc.diff b/nixpkgs/patches/services.croc.diff
deleted file mode 100644 (file)
index c8678bb..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
-index f361163ca63..24dcf53e635 100644
---- a/nixos/modules/module-list.nix
-+++ b/nixos/modules/module-list.nix
-@@ -598,6 +598,7 @@
-   ./services/networking/coredns.nix
-   ./services/networking/corerad.nix
-   ./services/networking/coturn.nix
-+  ./services/networking/croc.nix
-   ./services/networking/dante.nix
-   ./services/networking/ddclient.nix
-   ./services/networking/dhcpcd.nix
-diff --git a/nixos/modules/services/networking/croc.nix b/nixos/modules/services/networking/croc.nix
-new file mode 100644
-index 00000000000..adba6f7f565
---- /dev/null
-+++ b/nixos/modules/services/networking/croc.nix
-@@ -0,0 +1,78 @@
-+{ config, lib, pkgs, ... }:
-+let
-+  inherit (lib) types;
-+  cfg = config.services.croc;
-+in
-+{
-+  options.services.croc = {
-+    enable = lib.mkEnableOption "croc relay";
-+    ports = lib.mkOption {
-+      type = types.listOf types.port;
-+      default = [9009 9010 9011 9012 9013];
-+      description = "Ports of the relay.";
-+    };
-+    pass = lib.mkOption {
-+      type = types.str;
-+      default = "pass123";
-+      description = "Password for the relay (warning: it will be visible in the Nix store and the list of processes).";
-+    };
-+  };
-+
-+  config = lib.mkIf cfg.enable {
-+    systemd.services.croc = {
-+      after = [ "network.target" ];
-+      wantedBy = [ "multi-user.target" ];
-+      serviceConfig = {
-+        ExecStart = "${pkgs.croc}/bin/croc --pass '${cfg.pass}' relay --ports ${lib.concatMapStringsSep "," toString cfg.ports}";
-+        # systemd-analyze security croc
-+        # → Overall exposure level for croc.service: 1.1 OK
-+        AmbientCapabilities = "";
-+        CapabilityBoundingSet = "";
-+        DynamicUser = true;
-+        LockPersonality = true;
-+        MemoryDenyWriteExecute = true;
-+        NoNewPrivileges = true;
-+        PrivateDevices = true;
-+        PrivateMounts = true;
-+        PrivateNetwork = false;
-+        PrivateTmp = true;
-+        PrivateUsers = true;
-+        ProtectClock = true;
-+        ProtectControlGroups = true;
-+        ProtectHome = true;
-+        ProtectHostname = true;
-+        ProtectKernelLogs = true;
-+        ProtectKernelModules = true;
-+        ProtectKernelTunables = true;
-+        ProtectSystem = "strict";
-+        RemoveIPC = true;
-+        RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ];
-+        RestrictNamespaces = true;
-+        RestrictRealtime = true;
-+        RestrictSUIDSGID = true;
-+        SystemCallFilter = [
-+          # perf stat -o /dev/stdout -e 'syscalls:sys_enter_*' croc relay |
-+          # awk '$1 && $2 ~ /syscalls:/ { sub("syscalls:sys_enter_", ""); print $2 }' |
-+          # sort >croc.syscalls
-+          # <use croc>
-+          # pkill croc
-+          # systemd-analyze syscall-filter | grep -v -e '#' |
-+          # sed -e ':loop; /^[^ ]/N; s/\n //; t loop' |
-+          # grep --color $(printf ' -e \\<%s\\>' $(cat croc.syscalls))
-+          "@default" "@basic-io" "@file-system" "@io-event" "@ipc" "@network-io" "@process" "@signal"
-+          "brk getrandom ioctl madvise mprotect sched_getaffinity sched_yield uname"
-+        ];
-+        SystemCallArchitectures = "native";
-+        SystemCallErrorNumber = "EPERM";
-+        UMask = "0077";
-+      };
-+    };
-+
-+    networking.firewall =
-+      { allowedTCPPorts = [ cfg.ports ];
-+        allowedUDPPorts = [ cfg.ports ];
-+      };
-+  };
-+
-+  meta.maintainers = with lib.maintainers; [ julm ];
-+}
diff --git a/nixpkgs/patches/transmission+apparmor.diff b/nixpkgs/patches/transmission+apparmor.diff
deleted file mode 100644 (file)
index 34d6db8..0000000
+++ /dev/null
@@ -1,1459 +0,0 @@
-diff --git a/nixos/doc/manual/release-notes/rl-2009.xml b/nixos/doc/manual/release-notes/rl-2009.xml
-index 2225619d481..d5c1a5cb614 100644
---- a/nixos/doc/manual/release-notes/rl-2009.xml
-+++ b/nixos/doc/manual/release-notes/rl-2009.xml
-@@ -680,6 +680,37 @@ systemd.services.nginx.serviceConfig.ReadWritePaths = [ "/var/www" ];
-      was removed, as udev gained native support to handle FIDO security tokens.
-     </para>
-    </listitem>
-+   <listitem>
-+    <para>
-+     The <literal>services.transmission</literal> module
-+     was enhanced with the new options:
-+     <xref linkend="opt-services.transmission.credentialsFile"/>,
-+     <xref linkend="opt-services.transmission.openFirewall"/>,
-+     and <xref linkend="opt-services.transmission.performanceNetParameters"/>.
-+    </para>
-+    <para>
-+     <literal>transmission-daemon</literal> is now started with additional systemd sandbox/hardening options for better security.
-+     Please <link xlink:href="https://github.com/NixOS/nixpkgs/issues">report</link>
-+     any use case where this is not working well.
-+     In particular, the <literal>RootDirectory</literal> option newly set
-+     forbids uploading or downloading a torrent outside of the default directory
-+     configured at <link linkend="opt-services.transmission.settings">settings.download-dir</link>.
-+     If you really need Transmission to access other directories,
-+     you must include those directories into the <literal>BindPaths</literal> of the service:
-+<programlisting>
-+systemd.services.transmission.serviceConfig.BindPaths = [ "/path/to/alternative/download-dir" ];
-+</programlisting>
-+    </para>
-+    <para>
-+     Also, connection to the RPC (Remote Procedure Call) of <literal>transmission-daemon</literal>
-+     is now only available on the local network interface by default.
-+     Use:
-+<programlisting>
-+services.transmission.settings.rpc-bind-address = "0.0.0.0";
-+</programlisting>
-+     to get the previous behavior of listening on all network interfaces.
-+    </para>
-+   </listitem>
-    <listitem>
-     <para>
-      With this release <literal>systemd-networkd</literal> (when enabled through <xref linkend="opt-networking.useNetworkd"/>)
-diff --git a/nixos/modules/config/fonts/fontconfig.nix b/nixos/modules/config/fonts/fontconfig.nix
-index 52d284f739b..3670487200d 100644
---- a/nixos/modules/config/fonts/fontconfig.nix
-+++ b/nixos/modules/config/fonts/fontconfig.nix
-@@ -485,6 +485,38 @@ in
-     (mkIf cfg.enable {
-       environment.systemPackages    = [ pkgs.fontconfig ];
-       environment.etc.fonts.source  = "${fontconfigEtc}/etc/fonts/";
-+      security.apparmor.includes."abstractions/fonts" = ''
-+        # fonts.conf
-+        r ${supportFontsConf},
-+        r ${latestPkg.out}/etc/fonts/fonts.conf,
-+
-+        # fontconfig default config files
-+        r ${supportPkg.out}/etc/fonts/conf.d/*.conf,
-+        r ${latestPkg.out}/etc/fonts/conf.d/*.conf,
-+
-+        # 00-nixos-cache.conf
-+        r ${cacheConfSupport},
-+        r ${cacheConfLatest},
-+
-+        # 10-nixos-rendering.conf
-+        r ${renderConf},
-+
-+        # local.conf (indirect priority 51)
-+        ${optionalString (cfg.localConf != "") ''
-+        r ${localConf},
-+        ''}
-+
-+        # 52-nixos-default-fonts.conf
-+        r ${defaultFontsConf},
-+
-+        # 53-no-bitmaps.conf
-+        r ${rejectBitmaps},
-+
-+        ${optionalString (!cfg.allowType1) ''
-+        # 53-nixos-reject-type1.conf
-+        r ${rejectType1},
-+        ''}
-+      '';
-     })
-     (mkIf (cfg.enable && !cfg.penultimate.enable) {
-       fonts.fontconfig.confPackages = [ confPkg ];
-diff --git a/nixos/modules/security/apparmor-suid.nix b/nixos/modules/security/apparmor-suid.nix
-index 6c479e070e2..e6d9467f296 100644
---- a/nixos/modules/security/apparmor-suid.nix
-+++ b/nixos/modules/security/apparmor-suid.nix
-@@ -21,9 +21,9 @@ with lib;
-   };
-   config = mkIf (cfg.confineSUIDApplications) {
--    security.apparmor.profiles = [ (pkgs.writeText "ping" ''
-+    security.apparmor.policies."bin/ping".profile = ''
-       #include <tunables/global>
--      /run/wrappers/bin/ping {
-+      /run/wrappers/wrappers.*/ping {
-         #include <abstractions/base>
-         #include <abstractions/consoles>
-         #include <abstractions/nameservice>
-@@ -32,10 +32,19 @@ with lib;
-         capability setuid,
-         network inet raw,
--        ${pkgs.stdenv.cc.libc.out}/lib/*.so mr,
--        ${pkgs.libcap.lib}/lib/libcap.so* mr,
--        ${pkgs.attr.out}/lib/libattr.so* mr,
-+        ${getLib pkgs.stdenv.cc.cc}/lib/*.so* mr,
-+        ${getLib pkgs.stdenv.cc.libc}/lib/*.so* mr,
-+        ${getLib pkgs.stdenv.cc.libc}/lib/gconv/gconv-modules r,
-+        ${getLib pkgs.glibcLocales}/lib/locale/locale-archive r,
-+        ${getLib pkgs.attr.out}/lib/libattr.so* mr,
-+        ${getLib pkgs.libcap.lib}/lib/libcap.so* mr,
-+        ${getLib pkgs.libcap_ng}/lib/libcap-ng.so* mr,
-+        ${getLib pkgs.libidn2}/lib/libidn2.so* mr,
-+        ${getLib pkgs.libunistring}/lib/libunistring.so* mr,
-+        ${getLib pkgs.nettle}/lib/libnettle.so* mr,
-+        #@{PROC}/@{pid}/environ r,
-+        /run/wrappers/wrappers.*/ping.real r,
-         ${pkgs.iputils}/bin/ping mixr,
-         #/etc/modules.conf r,
-@@ -43,7 +52,7 @@ with lib;
-         ## Site-specific additions and overrides. See local/README for details.
-         ##include <local/bin.ping>
-       }
--    '') ];
-+    '';
-   };
- }
-diff --git a/nixos/modules/security/apparmor.nix b/nixos/modules/security/apparmor.nix
-index cfc65b347bc..f9abb18afd2 100644
---- a/nixos/modules/security/apparmor.nix
-+++ b/nixos/modules/security/apparmor.nix
-@@ -1,59 +1,190 @@
- { config, lib, pkgs, ... }:
- let
--  inherit (lib) mkIf mkOption types concatMapStrings;
-+  inherit (builtins) head match readFile;
-+  inherit (lib) types;
-+  inherit (config.environment) etc;
-   cfg = config.security.apparmor;
-+  mkDisableOption = name: lib.mkEnableOption name // {
-+    default = true;
-+    example = false;
-+  };
- in
- {
--   options = {
--     security.apparmor = {
--       enable = mkOption {
--         type = types.bool;
--         default = false;
--         description = "Enable the AppArmor Mandatory Access Control system.";
--       };
--       profiles = mkOption {
--         type = types.listOf types.path;
--         default = [];
--         description = "List of files containing AppArmor profiles.";
--       };
--       packages = mkOption {
--         type = types.listOf types.package;
--         default = [];
--         description = "List of packages to be added to apparmor's include path";
--       };
--     };
--   };
-+  imports = [
-+    (lib.mkRemovedOptionModule [ "security" "apparmor" "profiles" ] "Please use the new option: `security.apparmor.policies'.")
-+    apparmor/profiles.nix
-+  ];
-+  options = {
-+    security.apparmor = {
-+      enable = lib.mkEnableOption "the AppArmor Mandatory Access Control system";
-+      policies = lib.mkOption {
-+        description = ''
-+          AppArmor policies.
-+        '';
-+        type = types.attrsOf (types.submodule ({ name, config, ... }: {
-+          options = {
-+            enable = mkDisableOption "loading of the profile into the kernel";
-+            enforce = mkDisableOption "enforcing of the policy or only complain in the logs";
-+            profile = lib.mkOption {
-+              description = "The policy of the profile.";
-+              type = types.lines;
-+              apply = pkgs.writeText name;
-+            };
-+          };
-+        }));
-+        default = {};
-+      };
-+      includes = lib.mkOption {
-+        type = types.attrsOf types.lines;
-+        default = [];
-+        description = ''
-+          List of paths to be added to AppArmor's searched paths
-+          when resolving absolute #include directives.
-+        '';
-+        apply = lib.mapAttrs pkgs.writeText;
-+      };
-+      packages = lib.mkOption {
-+        type = types.listOf types.package;
-+        default = [];
-+        description = "List of packages to be added to AppArmor's include path";
-+      };
-+      enableCache = lib.mkEnableOption ''caching of AppArmor policies
-+        in <literal>/var/cache/apparmor/</literal>.
-+        Beware that AppArmor policies almost always contain Nix store paths,
-+        and thus produce at each change of these paths
-+        a new cached version accumulating in the cache.
-+      '';
-+      killUnconfinedConfinables = mkDisableOption ''killing of processes
-+        which have an AppArmor profile enabled
-+        (in <link linkend="opt-security.apparmor.policies">policies</link>)
-+        but are not confined (because AppArmor can only confine new processes).
-+      '';
-+    };
-+  };
--   config = mkIf cfg.enable {
--     environment.systemPackages = [ pkgs.apparmor-utils ];
-+  config = lib.mkIf cfg.enable {
-+    environment.systemPackages = [ pkgs.apparmor-utils ];
-+    environment.etc."apparmor.d".source = pkgs.linkFarm "apparmor.d" (
-+      lib.mapAttrsToList (name: p: {inherit name; path=p.profile;}) cfg.policies ++
-+      lib.mapAttrsToList (name: path: {inherit name path;}) cfg.includes
-+    );
-+    environment.etc."apparmor/parser.conf".text = ''
-+      ${if cfg.enableCache then "write-cache" else "skip-cache"}
-+      cache-loc /var/cache/apparmor
-+      Include /etc/apparmor.d
-+    '' +
-+    lib.concatMapStrings (p: "Include ${p}/etc/apparmor.d\n") cfg.packages;
-+    environment.etc."apparmor/logprof.conf".text = ''
-+      [settings]
-+        profiledir = /etc/apparmor.d
-+        inactive_profiledir = ${pkgs.apparmor-profiles}/share/apparmor/extra-profiles
-+        logfiles = /var/log/audit/audit.log /var/log/syslog /var/log/messages
--     boot.kernelParams = [ "apparmor=1" "security=apparmor" ];
-+        parser = ${pkgs.apparmor-parser}/bin/apparmor_parser
-+        ldd = ${pkgs.glibc.bin}/bin/ldd
-+        logger = ${pkgs.utillinux}/bin/logger
--     systemd.services.apparmor = let
--       paths = concatMapStrings (s: " -I ${s}/etc/apparmor.d")
--         ([ pkgs.apparmor-profiles ] ++ cfg.packages);
--     in {
--       after = [ "local-fs.target" ];
--       before = [ "sysinit.target" ];
--       wantedBy = [ "multi-user.target" ];
--       unitConfig = {
--         DefaultDependencies = "no";
--       };
--       serviceConfig = {
--         Type = "oneshot";
--         RemainAfterExit = "yes";
--         ExecStart = map (p:
--           ''${pkgs.apparmor-parser}/bin/apparmor_parser -rKv ${paths} "${p}"''
--         ) cfg.profiles;
--         ExecStop = map (p:
--           ''${pkgs.apparmor-parser}/bin/apparmor_parser -Rv "${p}"''
--         ) cfg.profiles;
--         ExecReload = map (p:
--           ''${pkgs.apparmor-parser}/bin/apparmor_parser --reload ${paths} "${p}"''
--         ) cfg.profiles;
--       };
--     };
--   };
-+        # customize how file ownership permissions are presented
-+        # 0 - off
-+        # 1 - default of what ever mode the log reported
-+        # 2 - force the new permissions to be user
-+        # 3 - force all perms on the rule to be user
-+        default_owner_prompt = 1
-+
-+        # custom directory locations to look for #includes
-+        #
-+        # each name should be a valid directory containing possible #include
-+        # candidate files under the profile dir which by default is /etc/apparmor.d.
-+        #
-+        # So an entry of my-includes will allow /etc/apparmor.d/my-includes to
-+        # be used by the yast UI and profiling tools as a source of #include
-+        # files.
-+        custom_includes =
-+
-+      [qualifiers]
-+        ${pkgs.runtimeShell} = icnu
-+        ${pkgs.bashInteractive}/bin/sh = icnu
-+        ${pkgs.bashInteractive}/bin/bash = icnu
-+    '' + head (match "^.*\\[qualifiers](.*)" # Drop the original [settings] section.
-+                     (readFile "${pkgs.apparmor-utils}/etc/apparmor/logprof.conf"));
-+
-+    boot.kernelParams = [ "apparmor=1" "security=apparmor" ];
-+
-+    systemd.services.apparmor = {
-+      after = [
-+        "local-fs.target"
-+        "systemd-journald-audit.socket"
-+      ];
-+      before = [ "sysinit.target" ];
-+      wantedBy = [ "multi-user.target" ];
-+      restartTriggers = [
-+        etc."apparmor/parser.conf".source
-+        etc."apparmor.d".source
-+      ];
-+      unitConfig = {
-+        Description="Load AppArmor policies";
-+        DefaultDependencies = "no";
-+        ConditionSecurity = "apparmor";
-+      };
-+      # Reloading instead of restarting enables to load new AppArmor profiles
-+      # without necessarily restarting all services which have Requires=apparmor.service
-+      # It works by:
-+      # - Adding or replacing into the kernel profiles enabled in cfg.policies
-+      #   (because AppArmor can do that without stopping the processes already confined).
-+      # - Removing from the kernel any profile whose name is not
-+      #   one of the names within the content of the profiles in cfg.policies.
-+      # - Killing the processes which are unconfined but now have a profile loaded
-+      #   (because AppArmor can only confine new processes).
-+      reloadIfChanged = true;
-+      # Avoid searchs in /usr/share/locale/
-+      environment.LANG="C";
-+      serviceConfig = let
-+        enabledPolicies = lib.attrValues (lib.filterAttrs (n: p: p.enable) cfg.policies);
-+        removeDisabledProfiles = pkgs.writeShellScript "apparmor-remove" ''
-+          set -eux
-+          
-+          enabledProfiles=$(mktemp)
-+          loadedProfiles=$(mktemp)
-+          trap "rm -f $enabledProfiles $loadedProfiles" EXIT
-+          
-+          ${pkgs.apparmor-parser}/bin/apparmor_parser --names /dev/null ${
-+            lib.concatMapStrings (p: "\\\n "+p.profile) enabledPolicies} |
-+          sort -u >"$enabledProfiles"
-+          
-+          sed -e "s/ (\(enforce\|complain\))$//" /sys/kernel/security/apparmor/profiles |
-+          sort -u >"$loadedProfiles"
-+
-+          comm -23 "$loadedProfiles" "$enabledProfiles" |
-+          while IFS=$'\n\r' read -r profile
-+          do printf %s "$profile" >/sys/kernel/security/apparmor/.remove
-+          done
-+        '';
-+        killUnconfinedConfinables = pkgs.writeShellScript "apparmor-kill" ''
-+          set -eux
-+          ${pkgs.apparmor-utils}/bin/aa-status --json |
-+          ${pkgs.jq}/bin/jq --raw-output '.processes | .[] | .[] | select (.status == "unconfined") | .pid' |
-+          xargs --verbose --no-run-if-empty --delimiter='\n' \
-+          kill
-+        '';
-+        commonOpts = p: "--verbose --show-cache ${lib.optionalString (!p.enforce) "--complain "}${p.profile}";
-+        in {
-+        Type = "oneshot";
-+        RemainAfterExit = "yes";
-+        ExecStartPre = "${pkgs.apparmor-utils}/bin/aa-teardown";
-+        ExecStart = map (p: "${pkgs.apparmor-parser}/bin/apparmor_parser --add ${commonOpts p}") enabledPolicies;
-+        ExecStartPost = lib.optional cfg.killUnconfinedConfinables killUnconfinedConfinables;
-+        ExecReload =
-+          map (p: "${pkgs.apparmor-parser}/bin/apparmor_parser --replace ${commonOpts p}") enabledPolicies ++
-+          [ removeDisabledProfiles ] ++
-+          lib.optional cfg.killUnconfinedConfinables killUnconfinedConfinables;
-+        ExecStop = "${pkgs.apparmor-utils}/bin/aa-teardown";
-+        CacheDirectory = [ "apparmor" ];
-+        CacheDirectoryMode = "0700";
-+      };
-+    };
-+  };
-+
-+  meta.maintainers = with lib.maintainers; [ julm ];
- }
-diff --git a/nixos/modules/security/apparmor/profiles.nix b/nixos/modules/security/apparmor/profiles.nix
-new file mode 100644
-index 00000000000..7e33e630798
---- /dev/null
-+++ b/nixos/modules/security/apparmor/profiles.nix
-@@ -0,0 +1,333 @@
-+{ config, lib, pkgs, ... }:
-+let
-+  inherit (builtins) attrNames hasAttr isAttrs;
-+  inherit (lib) getLib;
-+  inherit (config.environment) etc;
-+  etcRule = arg:
-+    let go = {path ? null, mode ? "r", trail ? ""}:
-+      lib.optionalString (hasAttr path etc)
-+        "${mode} ${config.environment.etc."${path}".source}${trail},";
-+    in if isAttrs arg
-+    then go arg
-+    else go {path=arg;};
-+in
-+{
-+config.security.apparmor.packages = [ pkgs.apparmor-profiles ];
-+# FIXME: most of the etcRule calls below have been
-+# written systematically by converting from apparmor-profiles's profiles
-+# without testing nor deep understanding of their uses,
-+# and thus may need more rules or can have less rules;
-+# this remains to me determined case by case,
-+# some may even be completely useless.
-+config.security.apparmor.includes = {
-+  # This one is included by <tunables/global>
-+  # which is usualy included before any profile.
-+  "abstractions/tunables/alias" = ''
-+    alias /bin -> /run/current-system/sw/bin,
-+    # Unfortunately /etc is mainly built using symlinks,
-+    # thus aliasing does not work.
-+    #alias /etc -> /run/current-system/etc,
-+    alias /lib/modules -> /run/current-system/kernel/lib/modules,
-+    alias /sbin -> /run/current-system/sw/sbin,
-+    alias /usr -> /run/current-system/sw,
-+  '';
-+  "abstractions/audio" = ''
-+    #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/audio
-+    ${etcRule "asound.conf"}
-+    ${etcRule "esound/esd.conf"}
-+    ${etcRule "libao.conf"}
-+    ${etcRule {path="pulse"; trail="/";}}
-+    ${etcRule {path="pulse"; trail="/**";}}
-+    ${etcRule {path="sound"; trail="/";}}
-+    ${etcRule {path="sound"; trail="/**";}}
-+    ${etcRule {path="alsa/conf.d"; trail="/";}}
-+    ${etcRule {path="alsa/conf.d"; trail="/*";}}
-+    ${etcRule "openal/alsoft.conf"}
-+    ${etcRule "wildmidi/wildmidi.conf"}
-+  '';
-+  # FIXME: security.pam configures more .so than allowed here,
-+  # but has many tests to decide what .so to use,
-+  # so it would be simpler to let security.pam add those .so
-+  # to the present security.apparmor.includes."abstractions/authentication"
-+  "abstractions/authentication" = ''
-+    #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/authentication
-+    ${etcRule "nologin"}
-+    ${lib.concatMapStringsSep "\n"
-+       (name: "r ${etc."pam.d/${name}".source},")
-+       (attrNames config.security.pam.services)}
-+    mr ${getLib pkgs.pam}/lib/security/pam_filter/*,
-+    mr ${getLib pkgs.pam}/lib/security/pam_*.so,
-+    r ${getLib pkgs.pam}/lib/security/,
-+    ${etcRule "securetty"}
-+    ${etcRule {path="security"; trail="/*";}}
-+    ${etcRule "shadow"}
-+    ${etcRule "gshadow"}
-+    ${etcRule "pwdb.conf"}
-+    ${etcRule "default/passwd"}
-+    ${etcRule "login.defs"}
-+  '';
-+  "abstractions/base" = ''
-+     #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/base
-+     r ${pkgs.stdenv.cc.libc}/share/locale/**,
-+     r ${pkgs.stdenv.cc.libc}/share/locale.alias,
-+     ${etcRule "localtime"}
-+     r /etc/ld-nix.so.preload,
-+     ${etcRule "ld-nix.so.preload"}
-+     ${lib.concatMapStrings (p: lib.optionalString (p != "") "mr ${p},\n")
-+                            (lib.splitString "\n" etc."ld-nix.so.preload".text)
-+       # TODO: avoid this line splitting by nixifying ld-nix.so.preload as a list or attrset,
-+       # and make services.config.malloc use it.
-+     }
-+     r ${pkgs.tzdata}/share/zoneinfo/**,
-+     r ${pkgs.stdenv.cc.libc}/share/i18n/**,
-+  '';
-+  "abstractions/bash" = ''
-+    #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/bash
-+    # system-wide bash configuration
-+    ${etcRule "profile.dos"}
-+    ${etcRule "profile"}
-+    ${etcRule "profile.d"}
-+    ${etcRule {path="profile.d"; trail="/*";}}
-+    ${etcRule "bashrc"}
-+    ${etcRule "bash.bashrc"}
-+    ${etcRule "bash.bashrc.local"}
-+    ${etcRule "bash_completion"}
-+    ${etcRule "bash_completion.d"}
-+    ${etcRule {path="bash_completion.d"; trail="/*";}}
-+    # bash relies on system-wide readline configuration
-+    ${etcRule "inputrc"}
-+    # bash inspects filesystems at startup
-+    # and /etc/mtab is linked to /proc/mounts
-+    @{PROC}/mounts
-+
-+    # run out of /etc/bash.bashrc
-+    ${etcRule "DIR_COLORS"}
-+  '';
-+  "abstractions/cups-client" = ''
-+    #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/cpus-client
-+    ${etcRule "cups/cups-client.conf"}
-+  '';
-+  "abstractions/consoles" = ''
-+     #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/consoles
-+  '';
-+  "abstractions/dbus-session-strict" = ''
-+    #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/dbus-session-strict
-+    ${etcRule "machine-id"}
-+  '';
-+  "abstractions/dconf" = ''
-+    #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/dconf
-+    ${etcRule {path="dconf"; trail="/**";}}
-+  '';
-+  "abstractions/dri-common" = ''
-+    #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/dri-common
-+    ${etcRule "drirc"}
-+  '';
-+  # The config.fonts.fontconfig NixOS module adds many files to /etc/fonts/
-+  # by symlinking them but without exporting them outside of its NixOS module,
-+  # those are therefore added there to this "abstractions/fonts".
-+  "abstractions/fonts" = ''
-+    #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/fonts
-+    ${etcRule {path="fonts"; trail="/**";}}
-+  '';
-+  "abstractions/gnome" = ''
-+    #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/gnome
-+    ${etcRule {path="gnome"; trail="/gtkrc*";}}
-+    ${etcRule {path="gtk"; trail="/*";}}
-+    ${etcRule {path="gtk-2.0"; trail="/*";}}
-+    ${etcRule {path="gtk-3.0"; trail="/*";}}
-+    ${etcRule "orbitrc"}
-+    #include <abstractions/fonts>
-+    ${etcRule {path="pango"; trail="/*";}}
-+    ${etcRule {path="/etc/gnome-vfs-2.0"; trail="/modules/";}}
-+    ${etcRule {path="/etc/gnome-vfs-2.0"; trail="/modules/*";}}
-+    ${etcRule "papersize"}
-+    ${etcRule {path="cups"; trail="/lpoptions";}}
-+    ${etcRule {path="gnome"; trail="/defaults.list";}}
-+    ${etcRule {path="xdg"; trail="/{,*-}mimeapps.list";}}
-+    ${etcRule "xdg/mimeapps.list"}
-+  '';
-+  "abstractions/kde" = ''
-+    #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/kde
-+    ${etcRule {path="qt3"; trail="/kstylerc";}}
-+    ${etcRule {path="qt3"; trail="/qt_plugins_3.3rc";}}
-+    ${etcRule {path="qt3"; trail="/qtrc";}}
-+    ${etcRule "kderc"}
-+    ${etcRule {path="kde3"; trail="/*";}}
-+    ${etcRule "kde4rc"}
-+    ${etcRule {path="xdg"; trail="/kdeglobals";}}
-+    ${etcRule {path="xdg"; trail="/Trolltech.conf";}}
-+  '';
-+  "abstractions/kerberosclient" = ''
-+    #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/kerberosclient
-+    ${etcRule {path="krb5.keytab"; mode="rk";}}
-+    ${etcRule "krb5.conf"}
-+    ${etcRule "krb5.conf.d"}
-+    ${etcRule {path="krb5.conf.d"; trail="/*";}}
-+    
-+    # config files found via strings on libs
-+    ${etcRule "krb.conf"}
-+    ${etcRule "krb.realms"}
-+    ${etcRule "srvtab"}
-+  '';
-+  "abstractions/ldapclient" = ''
-+    #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/ldapclient
-+    ${etcRule "ldap.conf"}
-+    ${etcRule "ldap.secret"}
-+    ${etcRule {path="openldap"; trail="/*";}}
-+    ${etcRule {path="openldap"; trail="/cacerts/*";}}
-+    ${etcRule {path="sasl2"; trail="/*";}}
-+  '';
-+  "abstractions/likewise" = ''
-+    #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/likewise
-+  '';
-+  "abstractions/mdns" = ''
-+    #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/mdns
-+     ${etcRule "nss_mdns.conf"}
-+  '';
-+  "abstractions/nameservice" = ''
-+    #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/nameservice
-+
-+    # Many programs wish to perform nameservice-like operations, such as
-+    # looking up users by name or id, groups by name or id, hosts by name
-+    # or IP, etc. These operations may be performed through files, dns,
-+    # NIS, NIS+, LDAP, hesiod, wins, etc. Allow them all here.
-+    ${etcRule "group"}
-+    ${etcRule "host.conf"}
-+    ${etcRule "hosts"}
-+    ${etcRule "nsswitch.conf"}
-+    ${etcRule "gai.conf"}
-+    ${etcRule "passwd"}
-+    ${etcRule "protocols"}
-+
-+    # libtirpc (used for NIS/YP login) needs this
-+    ${etcRule "netconfig"}
-+
-+    ${etcRule "resolv.conf"}
-+
-+    ${etcRule {path="samba"; trail="/lmhosts";}}
-+    ${etcRule "services"}
-+
-+    ${etcRule "default/nss"}
-+
-+    # libnl-3-200 via libnss-gw-name
-+    ${etcRule {path="libnl"; trail="/classid";}}
-+    ${etcRule {path="libnl-3"; trail="/classid";}}
-+
-+    mr ${getLib pkgs.nss}/lib/libnss_*.so*,
-+    mr ${getLib pkgs.nss}/lib64/libnss_*.so*,
-+  '';
-+  "abstractions/nis" = ''
-+    #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/nis
-+  '';
-+  "abstractions/nvidia" = ''
-+    #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/nvidia
-+    ${etcRule "vdpau_wrapper.cfg"}
-+  '';
-+  "abstractions/opencl-common" = ''
-+    #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/opencl-common
-+    ${etcRule {path="OpenCL"; trail="/**";}}
-+  '';
-+  "abstractions/opencl-mesa" = ''
-+    #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/opencl-mesa
-+    ${etcRule "default/drirc"}
-+  '';
-+  "abstractions/openssl" = ''
-+    #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/openssl
-+    ${etcRule {path="ssl"; trail="/openssl.cnf";}}
-+  '';
-+  "abstractions/p11-kit" = ''
-+    #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/p11-kit
-+    ${etcRule {path="pkcs11"; trail="/";}}
-+    ${etcRule {path="pkcs11"; trail="/pkcs11.conf";}}
-+    ${etcRule {path="pkcs11"; trail="/modules/";}}
-+    ${etcRule {path="pkcs11"; trail="/modules/*";}}
-+  '';
-+  "abstractions/perl" = ''
-+    #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/perl
-+    ${etcRule {path="perl"; trail="/**";}}
-+  '';
-+  "abstractions/php" = ''
-+    #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/php
-+    ${etcRule {path="php"; trail="/**/";}}
-+    ${etcRule {path="php5"; trail="/**/";}}
-+    ${etcRule {path="php7"; trail="/**/";}}
-+    ${etcRule {path="php"; trail="/**.ini";}}
-+    ${etcRule {path="php5"; trail="/**.ini";}}
-+    ${etcRule {path="php7"; trail="/**.ini";}}
-+  '';
-+  "abstractions/postfix-common" = ''
-+    #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/postfix-common
-+    ${etcRule "mailname"}
-+    ${etcRule {path="postfix"; trail="/*.cf";}}
-+    ${etcRule "postfix/main.cf"}
-+    ${etcRule "postfix/master.cf"}
-+  '';
-+  "abstractions/python" = ''
-+    #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/python
-+    ${etcRule {path="python2.4"; trail="/**";}}
-+    ${etcRule {path="python2.5"; trail="/**";}}
-+    ${etcRule {path="python2.6"; trail="/**";}}
-+    ${etcRule {path="python2.7"; trail="/**";}}
-+    ${etcRule {path="python3.0"; trail="/**";}}
-+    ${etcRule {path="python3.1"; trail="/**";}}
-+    ${etcRule {path="python3.2"; trail="/**";}}
-+    ${etcRule {path="python3.3"; trail="/**";}}
-+    ${etcRule {path="python3.4"; trail="/**";}}
-+    ${etcRule {path="python3.5"; trail="/**";}}
-+    ${etcRule {path="python3.6"; trail="/**";}}
-+    ${etcRule {path="python3.7"; trail="/**";}}
-+    ${etcRule {path="python3.8"; trail="/**";}}
-+    ${etcRule {path="python3.9"; trail="/**";}}
-+  '';
-+  "abstractions/qt5" = ''
-+    #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/qt5
-+    ${etcRule {path="xdg"; trail="/QtProject/qtlogging.ini";}}
-+    ${etcRule {path="xdg/QtProject"; trail="/qtlogging.ini";}}
-+    ${etcRule "xdg/QtProject/qtlogging.ini"}
-+  '';
-+  "abstractions/samba" = ''
-+    #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/samba
-+    ${etcRule {path="samba"; trail="/*";}}
-+  '';
-+  "abstractions/ssl_certs" = ''
-+    #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/ssl_certs
-+    ${etcRule "ssl/certs/ca-certificates.crt"}
-+    ${etcRule "ssl/certs/ca-bundle.crt"}
-+    ${etcRule "pki/tls/certs/ca-bundle.crt"}
-+
-+    ${etcRule {path="ssl/trust"; trail="/";}}
-+    ${etcRule {path="ssl/trust"; trail="/*";}}
-+    ${etcRule {path="ssl/trust/anchors"; trail="/";}}
-+    ${etcRule {path="ssl/trust/anchors"; trail="/**";}}
-+    ${etcRule {path="pki/trust"; trail="/";}}
-+    ${etcRule {path="pki/trust"; trail="/*";}}
-+    ${etcRule {path="pki/trust/anchors"; trail="/";}}
-+    ${etcRule {path="pki/trust/anchors"; trail="/**";}}
-+
-+    # security.acme NixOS module
-+    r /var/lib/acme/*/cert.pem,
-+    r /var/lib/acme/*/chain.pem,
-+    r /var/lib/acme/*/fullchain.pem,
-+  '';
-+  "abstractions/ssl_keys" = ''
-+    # security.acme NixOS module
-+    r /var/lib/acme/*/full.pem,
-+    r /var/lib/acme/*/key.pem,
-+  '';
-+  "abstractions/vulkan" = ''
-+    #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/vulkan
-+    ${etcRule {path="vulkan/icd.d"; trail="/";}}
-+    ${etcRule {path="vulkan/icd.d"; trail="/*.json";}}
-+  '';
-+  "abstractions/winbind" = ''
-+    #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/winbind
-+    ${etcRule {path="samba"; trail="/smb.conf";}}
-+    ${etcRule {path="samba"; trail="/dhcp.conf";}}
-+  '';
-+  "abstractions/X" = ''
-+    #include ${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/X
-+    ${etcRule {path="X11/cursors"; trail="/";}}
-+    ${etcRule {path="X11/cursors"; trail="/**";}}
-+  '';
-+};
-+}
-diff --git a/nixos/modules/security/pam.nix b/nixos/modules/security/pam.nix
-index 565c15dec24..66219d37c7d 100644
---- a/nixos/modules/security/pam.nix
-+++ b/nixos/modules/security/pam.nix
-@@ -836,6 +836,57 @@ in
-         runuser-l = { rootOK = true; unixAuth = false; };
-       };
-+    security.apparmor.includes."abstractions/pam" = let
-+      isEnabled = test: fold or false (map test (attrValues config.security.pam.services));
-+      in ''
-+      ${optionalString use_ldap
-+        "mr ${pam_ldap}/lib/security/pam_ldap.so,"}
-+      ${optionalString config.services.sssd.enable
-+        "mr ${pkgs.sssd}/lib/security/pam_sss.so,"}
-+      ${optionalString config.krb5.enable ''
-+        mr ${pam_krb5}/lib/security/pam_krb5.so,
-+        mr ${pam_ccreds}/lib/security/pam_ccreds.so,
-+      ''}
-+      ${optionalString (isEnabled (cfg: cfg.googleOsLoginAccountVerification)) ''
-+        mr ${pkgs.google-compute-engine-oslogin}/lib/pam_oslogin_login.so,
-+        mr ${pkgs.google-compute-engine-oslogin}/lib/pam_oslogin_admin.so,
-+      ''}
-+      ${optionalString (isEnabled (cfg: cfg.googleOsLoginAuthentication))
-+        "mr ${pkgs.google-compute-engine-oslogin}/lib/pam_oslogin_login.so,"}
-+      ${optionalString (config.security.pam.enableSSHAgentAuth && isEnabled (cfg: cfg.sshAgentAuth))
-+        "mr ${pkgs.pam_ssh_agent_auth}/libexec/pam_ssh_agent_auth.so,"}
-+      ${optionalString (isEnabled (cfg: cfg.fprintAuth))
-+        "mr ${pkgs.fprintd}/lib/security/pam_fprintd.so,"}
-+      ${optionalString (isEnabled (cfg: cfg.u2fAuth))
-+        "mr ${pkgs.pam_u2f}/lib/security/pam_u2f.so,"}
-+      ${optionalString (isEnabled (cfg: cfg.usbAuth))
-+        "mr ${pkgs.pam_usb}/lib/security/pam_usb.so,"}
-+      ${optionalString (isEnabled (cfg: cfg.oathAuth))
-+        "mr ${pkgs.oathToolkit}/lib/security/pam_oath.so,"}
-+      ${optionalString (isEnabled (cfg: cfg.yubicoAuth))
-+        "mr ${pkgs.yubico-pam}/lib/security/pam_yubico.so,"}
-+      ${optionalString (isEnabled (cfg: cfg.duoSecurity.enable))
-+        "mr ${pkgs.duo-unix}/lib/security/pam_duo.so,"}
-+      ${optionalString (isEnabled (cfg: cfg.otpwAuth))
-+        "mr ${pkgs.otpw}/lib/security/pam_otpw.so,"}
-+      ${optionalString config.security.pam.enableEcryptfs
-+        "mr ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so,"}
-+      ${optionalString (isEnabled (cfg: cfg.pamMount))
-+        "mr ${pkgs.pam_mount}/lib/security/pam_mount.so,"}
-+      ${optionalString config.services.samba.syncPasswordsByPam
-+        "mr ${pkgs.samba}/lib/security/pam_smbpass.so,"}
-+      ${optionalString (isEnabled (cfg: cfg.enableGnomeKeyring))
-+        "mr ${pkgs.gnome3.gnome-keyring}/lib/security/pam_gnome_keyring.so,"}
-+      ${optionalString (isEnabled (cfg: cfg.startSession))
-+        "mr ${pkgs.systemd}/lib/security/pam_systemd.so,"}
-+      ${optionalString (isEnabled (cfg: cfg.enableAppArmor) && config.security.apparmor.enable)
-+        "mr ${pkgs.apparmor-pam}/lib/security/pam_apparmor.so,"}
-+      ${optionalString (isEnabled (cfg: cfg.enableKwallet))
-+        "mr ${pkgs.plasma5.kwallet-pam}/lib/security/pam_kwallet5.so,"}
-+      ${optionalString config.virtualisation.lxc.lxcfs.enable
-+        "mr ${pkgs.lxc}/lib/security/pam_cgfs.so"}
-+    '';
-+
-   };
- }
-diff --git a/nixos/modules/services/torrent/transmission.nix b/nixos/modules/services/torrent/transmission.nix
-index 1bfcf2de82f..f589c31ad75 100644
---- a/nixos/modules/services/torrent/transmission.nix
-+++ b/nixos/modules/services/torrent/transmission.nix
-@@ -1,52 +1,51 @@
--{ config, lib, pkgs, ... }:
-+{ config, lib, pkgs, options, ... }:
- with lib;
- let
-   cfg = config.services.transmission;
-+  inherit (config.environment) etc;
-   apparmor = config.security.apparmor.enable;
--
--  homeDir = cfg.home;
--  downloadDirPermissions = cfg.downloadDirPermissions;
--  downloadDir = "${homeDir}/Downloads";
--  incompleteDir = "${homeDir}/.incomplete";
--
--  settingsDir = "${homeDir}/config";
--  settingsFile = pkgs.writeText "settings.json" (builtins.toJSON fullSettings);
--
--  # for users in group "transmission" to have access to torrents
--  fullSettings = { umask = 2; download-dir = downloadDir; incomplete-dir = incompleteDir; } // cfg.settings;
--
--  preStart = pkgs.writeScript "transmission-pre-start" ''
--    #!${pkgs.runtimeShell}
--    set -ex
--    cp -f ${settingsFile} ${settingsDir}/settings.json
--  '';
-+  rootDir = "/run/transmission";
-+  homeDir = "/var/lib/transmission";
-+  settingsDir = ".config/transmission-daemon";
-+  downloadsDir = "Downloads";
-+  incompleteDir = ".incomplete";
-+  # TODO: switch to configGen.json once RFC0042 is implemented
-+  settingsFile = pkgs.writeText "settings.json" (builtins.toJSON cfg.settings);
- in
- {
-   options = {
-     services.transmission = {
--      enable = mkOption {
--        type = types.bool;
--        default = false;
--        description = ''
--          Whether or not to enable the headless Transmission BitTorrent daemon.
-+      enable = mkEnableOption ''the headless Transmission BitTorrent daemon.
--          Transmission daemon can be controlled via the RPC interface using
--          transmission-remote or the WebUI (http://localhost:9091/ by default).
-+        Transmission daemon can be controlled via the RPC interface using
-+        transmission-remote, the WebUI (http://127.0.0.1:9091/ by default),
-+        or other clients like stig or tremc.
--          Torrents are downloaded to ${downloadDir} by default and are
--          accessible to users in the "transmission" group.
--        '';
--      };
-+        Torrents are downloaded to ${homeDir}/${downloadsDir} by default and are
-+        accessible to users in the "transmission" group'';
--      settings = mkOption {
-+      settings = mkOption rec {
-+        # TODO: switch to types.config.json as prescribed by RFC0042 once it's implemented
-         type = types.attrs;
-+        apply = recursiveUpdate default;
-         default =
-           {
--            download-dir = downloadDir;
--            incomplete-dir = incompleteDir;
-+            download-dir = "${cfg.home}/${downloadsDir}";
-+            incomplete-dir = "${cfg.home}/${incompleteDir}";
-             incomplete-dir-enabled = true;
-+            message-level = 1;
-+            peer-port = 51413;
-+            peer-port-random-high = 65535;
-+            peer-port-random-low = 49152;
-+            peer-port-random-on-start = false;
-+            rpc-bind-address = "127.0.0.1";
-+            rpc-port = 9091;
-+            script-torrent-done-enabled = false;
-+            script-torrent-done-filename = "";
-+            umask = 2; # 0o002 in decimal as expected by Transmission
-+            utp-enabled = true;
-           };
-         example =
-           {
-@@ -56,11 +55,12 @@ in
-             rpc-whitelist = "127.0.0.1,192.168.*.*";
-           };
-         description = ''
--          Attribute set whos fields overwrites fields in settings.json (each
--          time the service starts). String values must be quoted, integer and
-+          Attribute set whose fields overwrites fields in
-+          <literal>.config/transmission-daemon/settings.json</literal>
-+          (each time the service starts). String values must be quoted, integer and
-           boolean values must not.
--          See https://github.com/transmission/transmission/wiki/Editing-Configuration-Files
-+          See <link xlink:href="https://github.com/transmission/transmission/wiki/Editing-Configuration-Files">Transmission's Wiki</link>
-           for documentation.
-         '';
-       };
-@@ -70,22 +70,32 @@ in
-         default = "770";
-         example = "775";
-         description = ''
--          The permissions to set for download-dir and incomplete-dir.
--          They will be applied on every service start.
-+          The permissions set by <literal>systemd.activationScripts.transmission-daemon</literal>
-+          on the directories <link linkend="opt-services.transmission.settings">settings.download-dir</link>
-+          and <link linkend="opt-services.transmission.settings">settings.incomplete-dir</link>.
-+          Note that you may also want to change
-+          <link linkend="opt-services.transmission.settings">settings.umask</link>.
-         '';
-       };
-       port = mkOption {
--        type = types.int;
--        default = 9091;
--        description = "TCP port number to run the RPC/web interface.";
-+        type = types.port;
-+        description = ''
-+          TCP port number to run the RPC/web interface.
-+
-+          If instead you want to change the peer port,
-+          use <link linkend="opt-services.transmission.settings">settings.peer-port</link>
-+          or <link linkend="opt-services.transmission.settings">settings.peer-port-random-on-start</link>.
-+        '';
-       };
-       home = mkOption {
-         type = types.path;
--        default = "/var/lib/transmission";
-+        default = homeDir;
-         description = ''
--          The directory where transmission will create files.
-+          The directory where Transmission will create <literal>${settingsDir}</literal>.
-+          as well as <literal>${downloadsDir}/</literal> unless <link linkend="opt-services.transmission.settings">settings.download-dir</link> is changed,
-+          and <literal>${incompleteDir}/</literal> unless <link linkend="opt-services.transmission.settings">settings.incomplete-dir</link> is changed.
-         '';
-       };
-@@ -100,32 +110,173 @@ in
-         default = "transmission";
-         description = "Group account under which Transmission runs.";
-       };
-+
-+      credentialsFile = mkOption {
-+        type = types.path;
-+        description = ''
-+          Path to a JSON file to be merged with the settings.
-+          Useful to merge a file which is better kept out of the Nix store
-+          because it contains sensible data like <link linkend="opt-services.transmission.settings">settings.rpc-password</link>.
-+        '';
-+        default = "/dev/null";
-+        example = "/var/lib/secrets/transmission/settings.json";
-+      };
-+
-+      openFirewall = mkEnableOption "opening of the peer port(s) in the firewall";
-+
-+      performanceNetParameters = mkEnableOption ''tweaking of kernel parameters
-+        to open many more connections at the same time.
-+
-+        Note that you may also want to increase
-+        <link linkend="opt-services.transmission.settings">settings.peer-limit-global</link>.
-+        And be aware that these settings are quite aggressive
-+        and might not suite your regular desktop use.
-+        For instance, SSH sessions may time out more easily'';
-     };
-   };
-   config = mkIf cfg.enable {
--    systemd.tmpfiles.rules = [
--      "d '${homeDir}' 0770 '${cfg.user}' '${cfg.group}' - -"
--      "d '${settingsDir}' 0700 '${cfg.user}' '${cfg.group}' - -"
--      "d '${fullSettings.download-dir}' '${downloadDirPermissions}' '${cfg.user}' '${cfg.group}' - -"
--      "d '${fullSettings.incomplete-dir}' '${downloadDirPermissions}' '${cfg.user}' '${cfg.group}' - -"
-+    # Note that using systemd.tmpfiles would not work here
-+    # because it would fail when creating a directory
-+    # with a different owner than its parent directory, by saying:
-+    # Detected unsafe path transition /home/foo → /home/foo/Downloads during canonicalization of /home/foo/Downloads
-+    # when /home/foo is not owned by cfg.user.
-+    # Note also that using an ExecStartPre= wouldn't work either
-+    # because BindPaths= needs these directories before.
-+    system.activationScripts.transmission-daemon = ''
-+      install -D -d -m 700 '${cfg.home}/${settingsDir}'
-+      chown -R '${cfg.user}:${cfg.group}' ${cfg.home}/${settingsDir}
-+      install -D -d -m '${cfg.downloadDirPermissions}' -o '${cfg.user}' -g '${cfg.group}' '${cfg.settings.download-dir}'
-+      '' + optionalString cfg.settings.incomplete-dir-enabled ''
-+      install -D -d -m '${cfg.downloadDirPermissions}' -o '${cfg.user}' -g '${cfg.group}' '${cfg.settings.incomplete-dir}'
-+      '';
-+
-+    assertions = [
-+      { assertion = builtins.match "^/.*" cfg.home != null;
-+        message = "`services.transmission.home' must be an absolute path.";
-+      }
-+      { assertion = types.path.check cfg.settings.download-dir;
-+        message = "`services.transmission.settings.download-dir' must be an absolute path.";
-+      }
-+      { assertion = types.path.check cfg.settings.incomplete-dir;
-+        message = "`services.transmission.settings.incomplete-dir' must be an absolute path.";
-+      }
-+      { assertion = cfg.settings.script-torrent-done-filename == "" || types.path.check cfg.settings.script-torrent-done-filename;
-+        message = "`services.transmission.settings.script-torrent-done-filename' must be an absolute path.";
-+      }
-+      { assertion = types.port.check cfg.settings.rpc-port;
-+        message = "${toString cfg.settings.rpc-port} is not a valid port number for `services.transmission.settings.rpc-port`.";
-+      }
-+      # In case both port and settings.rpc-port are explicitely defined: they must be the same.
-+      { assertion = !options.services.transmission.port.isDefined || cfg.port == cfg.settings.rpc-port;
-+        message = "`services.transmission.port' is not equal to `services.transmission.settings.rpc-port'";
-+      }
-     ];
-+    services.transmission.settings =
-+      optionalAttrs options.services.transmission.port.isDefined { rpc-port = cfg.port; };
-+
-     systemd.services.transmission = {
-       description = "Transmission BitTorrent Service";
-       after = [ "network.target" ] ++ optional apparmor "apparmor.service";
--      requires = mkIf apparmor [ "apparmor.service" ];
-+      requires = optional apparmor "apparmor.service";
-       wantedBy = [ "multi-user.target" ];
-+      environment.CURL_CA_BUNDLE = etc."ssl/certs/ca-certificates.crt".source;
--      # 1) Only the "transmission" user and group have access to torrents.
--      # 2) Optionally update/force specific fields into the configuration file.
--      serviceConfig.ExecStartPre = preStart;
--      serviceConfig.ExecStart = "${pkgs.transmission}/bin/transmission-daemon -f --port ${toString config.services.transmission.port} --config-dir ${settingsDir}";
--      serviceConfig.ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
--      serviceConfig.User = cfg.user;
--      serviceConfig.Group = cfg.group;
--      # NOTE: transmission has an internal umask that also must be set (in settings.json)
--      serviceConfig.UMask = "0002";
-+      serviceConfig = {
-+        # Use "+" because credentialsFile may not be accessible to User= or Group=.
-+        ExecStartPre = "+" + pkgs.writeShellScript "transmission-prestart" ''
-+          set -eu${lib.optionalString (cfg.settings.message-level >= 3) "x"}
-+          ${pkgs.jq}/bin/jq --slurp add ${settingsFile} '${cfg.credentialsFile}' |
-+          install -D -m 600 -o '${cfg.user}' -g '${cfg.group}' /dev/stdin \
-+           '${cfg.home}/${settingsDir}/settings.json'
-+        '';
-+        ExecStart="${pkgs.transmission}/bin/transmission-daemon -f";
-+        ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
-+        User = cfg.user;
-+        Group = cfg.group;
-+        # Create rootDir in the host's mount namespace.
-+        RuntimeDirectory = [(baseNameOf rootDir)];
-+        RuntimeDirectoryMode = "755";
-+        # Avoid mounting rootDir in the own rootDir of ExecStart='s mount namespace.
-+        InaccessiblePaths = ["-+${rootDir}"];
-+        # This is for BindPaths= and BindReadOnlyPaths=
-+        # to allow traversal of directories they create in RootDirectory=.
-+        UMask = "0066";
-+        # Using a RootDirectory= allows to use the same paths download-dir/incomplete-dir
-+        # (which appear in user's interfaces) without requiring cfg.user
-+        # to have access to their parent directories,
-+        # by using BindPaths=/BindReadOnlyPaths=.
-+        # Note that TemporaryFileSystem= could have been used instead
-+        # but not without adding some BindPaths=/BindReadOnlyPaths=
-+        # that would only be needed for ExecStartPre=,
-+        # because RootDirectoryStartOnly=true would not help.
-+        RootDirectory = rootDir;
-+        RootDirectoryStartOnly = true;
-+        MountAPIVFS = true;
-+        BindPaths =
-+          [ "${cfg.home}/${settingsDir}"
-+            cfg.settings.download-dir
-+          ] ++
-+          optional cfg.settings.incomplete-dir-enabled
-+            cfg.settings.incomplete-dir;
-+        BindReadOnlyPaths = [
-+          # No confinement done of /nix/store here like in systemd-confinement.nix,
-+          # an AppArmor profile is provided to get a confinement based upon paths and rights.
-+          builtins.storeDir
-+          "-/etc/hosts"
-+          "-/etc/ld-nix.so.preload"
-+          "-/etc/localtime"
-+          ] ++
-+          optional (cfg.settings.script-torrent-done-enabled &&
-+                    cfg.settings.script-torrent-done-filename != "")
-+            cfg.settings.script-torrent-done-filename;
-+        # The following options are only for optimizing:
-+        # systemd-analyze security transmission
-+        AmbientCapabilities = "";
-+        CapabilityBoundingSet = "";
-+        # ProtectClock= adds DeviceAllow=char-rtc r
-+        DeviceAllow = "";
-+        LockPersonality = true;
-+        MemoryDenyWriteExecute = true;
-+        NoNewPrivileges = true;
-+        PrivateDevices = true;
-+        PrivateMounts = true;
-+        PrivateNetwork = false;
-+        PrivateTmp = true;
-+        PrivateUsers = true;
-+        ProtectClock = true;
-+        ProtectControlGroups = true;
-+        # ProtectHome=true would not allow BindPaths= to work accross /home,
-+        # and ProtectHome=tmpfs would break statfs(),
-+        # preventing transmission-daemon to report the available free space.
-+        # However, RootDirectory= is used, so this is not a security concern
-+        # since there would be nothing in /home but any BindPaths= wanted by the user.
-+        ProtectHome = "read-only";
-+        ProtectHostname = true;
-+        ProtectKernelLogs = true;
-+        ProtectKernelModules = true;
-+        ProtectKernelTunables = true;
-+        ProtectSystem = "strict";
-+        RemoveIPC = true;
-+        # AF_UNIX may become usable one day:
-+        # https://github.com/transmission/transmission/issues/441
-+        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 -e 'syscalls:sys_enter_*' transmission-daemon -f
-+          # in tests, and seem likely not necessary for transmission-daemon.
-+          "~@aio" "~@chown" "~@keyring" "~@memlock" "~@resources" "~@setuid" "~@timer"
-+          # In the @privileged group, but reached when querying infos through RPC (eg. with stig).
-+          "quotactl"
-+        ];
-+        SystemCallArchitectures = "native";
-+        SystemCallErrorNumber = "EPERM";
-+      };
-     };
-     # It's useful to have transmission in path, e.g. for remote control
-@@ -133,70 +284,137 @@ in
-     users.users = optionalAttrs (cfg.user == "transmission") ({
-       transmission = {
--        name = "transmission";
-         group = cfg.group;
-         uid = config.ids.uids.transmission;
-         description = "Transmission BitTorrent user";
--        home = homeDir;
--        createHome = true;
-+        home = cfg.home;
-       };
-     });
-     users.groups = optionalAttrs (cfg.group == "transmission") ({
-       transmission = {
--        name = "transmission";
-         gid = config.ids.gids.transmission;
-       };
-     });
--    # AppArmor profile
--    security.apparmor.profiles = mkIf apparmor [
--      (pkgs.writeText "apparmor-transmission-daemon" ''
--        #include <tunables/global>
-+    networking.firewall = mkIf cfg.openFirewall (
-+      if cfg.settings.peer-port-random-on-start
-+      then
-+        { allowedTCPPortRanges =
-+            [ { from = cfg.settings.peer-port-random-low;
-+                to   = cfg.settings.peer-port-random-high;
-+              }
-+            ];
-+          allowedUDPPortRanges =
-+            [ { from = cfg.settings.peer-port-random-low;
-+                to   = cfg.settings.peer-port-random-high;
-+              }
-+            ];
-+        }
-+      else
-+        { allowedTCPPorts = [ cfg.settings.peer-port ];
-+          allowedUDPPorts = [ cfg.settings.peer-port ];
-+        }
-+    );
-+
-+    boot.kernel.sysctl = mkMerge [
-+      # Transmission uses a single UDP socket in order to implement multiple uTP sockets,
-+      # and thus expects large kernel buffers for the UDP socket,
-+      # https://trac.transmissionbt.com/browser/trunk/libtransmission/tr-udp.c?rev=11956.
-+      # at least up to the values hardcoded here:
-+      (mkIf cfg.settings.utp-enabled {
-+        "net.core.rmem_max" = mkDefault "4194304"; # 4MB
-+        "net.core.wmem_max" = mkDefault "1048576"; # 1MB
-+      })
-+      (mkIf cfg.performanceNetParameters {
-+        # Increase the number of available source (local) TCP and UDP ports to 49151.
-+        # Usual default is 32768 60999, ie. 28231 ports.
-+        # Find out your current usage with: ss -s
-+        "net.ipv4.ip_local_port_range" = "16384 65535";
-+        # Timeout faster generic TCP states.
-+        # Usual default is 600.
-+        # Find out your current usage with: watch -n 1 netstat -nptuo
-+        "net.netfilter.nf_conntrack_generic_timeout" = 60;
-+        # Timeout faster established but inactive connections.
-+        # Usual default is 432000.
-+        "net.netfilter.nf_conntrack_tcp_timeout_established" = 600;
-+        # Clear immediately TCP states after timeout.
-+        # Usual default is 120.
-+        "net.netfilter.nf_conntrack_tcp_timeout_time_wait" = 1;
-+        # Increase the number of trackable connections.
-+        # Usual default is 262144.
-+        # Find out your current usage with: conntrack -C
-+        "net.netfilter.nf_conntrack_max" = 1048576;
-+      })
-+    ];
-+
-+    security.apparmor.policies."bin/transmission-daemon".profile = ''
-+        include <tunables/global>
-         ${pkgs.transmission}/bin/transmission-daemon {
--          #include <abstractions/base>
--          #include <abstractions/nameservice>
-+          include <abstractions/base>
-+          include <abstractions/nameservice>
--          ${getLib pkgs.glibc}/lib/*.so                    mr,
--          ${getLib pkgs.libevent}/lib/libevent*.so*        mr,
--          ${getLib pkgs.curl}/lib/libcurl*.so*             mr,
--          ${getLib pkgs.openssl}/lib/libssl*.so*           mr,
--          ${getLib pkgs.openssl}/lib/libcrypto*.so*        mr,
--          ${getLib pkgs.zlib}/lib/libz*.so*                mr,
--          ${getLib pkgs.libssh2}/lib/libssh2*.so*          mr,
--          ${getLib pkgs.systemd}/lib/libsystemd*.so*       mr,
--          ${getLib pkgs.xz}/lib/liblzma*.so*               mr,
--          ${getLib pkgs.libgcrypt}/lib/libgcrypt*.so*      mr,
--          ${getLib pkgs.libgpgerror}/lib/libgpg-error*.so* mr,
--          ${getLib pkgs.nghttp2}/lib/libnghttp2*.so*       mr,
--          ${getLib pkgs.c-ares}/lib/libcares*.so*          mr,
--          ${getLib pkgs.libcap}/lib/libcap*.so*            mr,
--          ${getLib pkgs.attr}/lib/libattr*.so*             mr,
--          ${getLib pkgs.lz4}/lib/liblz4*.so*               mr,
--          ${getLib pkgs.libkrb5}/lib/lib*.so*              mr,
--          ${getLib pkgs.keyutils}/lib/libkeyutils*.so*     mr,
--          ${getLib pkgs.utillinuxMinimal.out}/lib/libblkid.so.* mr,
--          ${getLib pkgs.utillinuxMinimal.out}/lib/libmount.so.* mr,
--          ${getLib pkgs.utillinuxMinimal.out}/lib/libuuid.so.* mr,
--          ${getLib pkgs.gcc.cc.lib}/lib/libstdc++.so.* mr,
--          ${getLib pkgs.gcc.cc.lib}/lib/libgcc_s.so.* mr,
-+          mr ${getLib pkgs.stdenv.cc.cc}/lib/*.so*,
-+          mr ${getLib pkgs.stdenv.cc.libc}/lib/*.so*,
-+          mr ${getLib pkgs.attr}/lib/libattr*.so*,
-+          mr ${getLib pkgs.c-ares}/lib/libcares*.so*,
-+          mr ${getLib pkgs.curl}/lib/libcurl*.so*,
-+          mr ${getLib pkgs.keyutils}/lib/libkeyutils*.so*,
-+          mr ${getLib pkgs.libcap}/lib/libcap*.so*,
-+          mr ${getLib pkgs.libevent}/lib/libevent*.so*,
-+          mr ${getLib pkgs.libgcrypt}/lib/libgcrypt*.so*,
-+          mr ${getLib pkgs.libgpgerror}/lib/libgpg-error*.so*,
-+          mr ${getLib pkgs.libkrb5}/lib/lib*.so*,
-+          mr ${getLib pkgs.libssh2}/lib/libssh2*.so*,
-+          mr ${getLib pkgs.lz4}/lib/liblz4*.so*,
-+          mr ${getLib pkgs.nghttp2}/lib/libnghttp2*.so*,
-+          mr ${getLib pkgs.openssl}/lib/libcrypto*.so*,
-+          mr ${getLib pkgs.openssl}/lib/libssl*.so*,
-+          mr ${getLib pkgs.systemd}/lib/libsystemd*.so*,
-+          mr ${getLib pkgs.utillinuxMinimal.out}/lib/libblkid.so*,
-+          mr ${getLib pkgs.utillinuxMinimal.out}/lib/libmount.so*,
-+          mr ${getLib pkgs.utillinuxMinimal.out}/lib/libuuid.so*,
-+          mr ${getLib pkgs.xz}/lib/liblzma*.so*,
-+          mr ${getLib pkgs.zlib}/lib/libz*.so*,
--          @{PROC}/sys/kernel/random/uuid   r,
--          @{PROC}/sys/vm/overcommit_memory r,
-+          r @{PROC}/sys/kernel/random/uuid,
-+          r @{PROC}/sys/vm/overcommit_memory,
-+          # @{pid} is not a kernel variable yet but a regexp
-+          #r @{PROC}/@{pid}/environ,
-+          r @{PROC}/@{pid}/mounts,
-+          rwk /tmp/tr_session_id_*,
--          ${pkgs.openssl.out}/etc/**                     r,
--          ${pkgs.transmission}/share/transmission/** r,
-+          r ${pkgs.openssl.out}/etc/**,
-+          r ${config.systemd.services.transmission.environment.CURL_CA_BUNDLE},
-+          r ${pkgs.transmission}/share/transmission/**,
--          owner ${settingsDir}/** rw,
--
--          ${fullSettings.download-dir}/** rw,
--          ${optionalString fullSettings.incomplete-dir-enabled ''
--            ${fullSettings.incomplete-dir}/** rw,
-+          owner rw ${cfg.home}/${settingsDir}/**,
-+          rw ${cfg.settings.download-dir}/**,
-+          ${optionalString cfg.settings.incomplete-dir-enabled ''
-+            rw ${cfg.settings.incomplete-dir}/**,
-           ''}
-+          profile dirs {
-+            rw ${cfg.settings.download-dir}/**,
-+            ${optionalString cfg.settings.incomplete-dir-enabled ''
-+              rw ${cfg.settings.incomplete-dir}/**,
-+            ''}
-+          }
-+
-+          ${optionalString (cfg.settings.script-torrent-done-enabled &&
-+                            cfg.settings.script-torrent-done-filename != "") ''
-+            # Stack transmission_directories profile on top of
-+            # any existing profile for script-torrent-done-filename
-+            # FIXME: to be tested as I'm not sure it works well with NoNewPrivileges=
-+            # https://gitlab.com/apparmor/apparmor/-/wikis/AppArmorStacking#seccomp-and-no_new_privs
-+            px ${cfg.settings.script-torrent-done-filename} -> &@{dirs},
-+          ''}
-+
-+          # FIXME: enable customizing using https://github.com/NixOS/nixpkgs/pull/93457
-+          # include <local/transmission-daemon>
-         }
--      '')
--    ];
-+    '';
-   };
-+  meta.maintainers = with lib.maintainers; [ julm ];
- }
-diff --git a/nixos/modules/virtualisation/lxc.nix b/nixos/modules/virtualisation/lxc.nix
-index f484d5ee59a..a2f4a9867c6 100644
---- a/nixos/modules/virtualisation/lxc.nix
-+++ b/nixos/modules/virtualisation/lxc.nix
-@@ -74,9 +74,13 @@ in
-     systemd.tmpfiles.rules = [ "d /var/lib/lxc/rootfs 0755 root root -" ];
-     security.apparmor.packages = [ pkgs.lxc ];
--    security.apparmor.profiles = [
--      "${pkgs.lxc}/etc/apparmor.d/lxc-containers"
--      "${pkgs.lxc}/etc/apparmor.d/usr.bin.lxc-start"
--    ];
-+    security.apparmor.policies = {
-+      "bin/lxc-start".profile = ''
-+        #include ${pkgs.lxc}/etc/apparmor.d/usr.bin.lxc-start
-+      '';
-+      "lxc-containers".profile = ''
-+        #include ${pkgs.lxc}/etc/apparmor.d/lxc-containers
-+      '';
-+    };
-   };
- }
-diff --git a/nixos/modules/virtualisation/lxd.nix b/nixos/modules/virtualisation/lxd.nix
-index 3958fc2c1d7..84c8e88f8b4 100644
---- a/nixos/modules/virtualisation/lxd.nix
-+++ b/nixos/modules/virtualisation/lxd.nix
-@@ -93,11 +93,15 @@ in
-     security.apparmor = {
-       enable = true;
--      profiles = [
--        "${cfg.lxcPackage}/etc/apparmor.d/usr.bin.lxc-start"
--        "${cfg.lxcPackage}/etc/apparmor.d/lxc-containers"
--      ];
-       packages = [ cfg.lxcPackage ];
-+      policies = {
-+        "bin/lxc-start".profile = ''
-+          #include ${cfg.lxcPackage}/etc/apparmor.d/usr.bin.lxc-start
-+        '';
-+        "lxc-containers".profile = ''
-+          #include ${cfg.lxcPackage}/etc/apparmor.d/lxc-containers
-+        '';
-+      };
-     };
-     systemd.services.lxd = {
-diff --git a/nixos/tests/bittorrent.nix b/nixos/tests/bittorrent.nix
-index 0a97d5556a2..c195b60cd56 100644
---- a/nixos/tests/bittorrent.nix
-+++ b/nixos/tests/bittorrent.nix
-@@ -19,6 +19,7 @@ let
-   externalClient2Address = "80.100.100.2";
-   externalTrackerAddress = "80.100.100.3";
-+  download-dir = "/var/lib/transmission/Downloads";
-   transmissionConfig = { ... }: {
-     environment.systemPackages = [ pkgs.transmission ];
-     services.transmission = {
-@@ -26,6 +27,7 @@ let
-       settings = {
-         dht-enabled = false;
-         message-level = 3;
-+        inherit download-dir;
-       };
-     };
-   };
-@@ -117,12 +119,12 @@ in
-       router.wait_for_unit("miniupnpd")
-       # Create the torrent.
--      tracker.succeed("mkdir /tmp/data")
-+      tracker.succeed("mkdir ${download-dir}/data")
-       tracker.succeed(
--          "cp ${file} /tmp/data/test.tar.bz2"
-+          "cp ${file} ${download-dir}/data/test.tar.bz2"
-       )
-       tracker.succeed(
--          "transmission-create /tmp/data/test.tar.bz2 --private --tracker http://${externalTrackerAddress}:6969/announce --outfile /tmp/test.torrent"
-+          "transmission-create ${download-dir}/data/test.tar.bz2 --private --tracker http://${externalTrackerAddress}:6969/announce --outfile /tmp/test.torrent"
-       )
-       tracker.succeed("chmod 644 /tmp/test.torrent")
-@@ -133,18 +135,16 @@ in
-       # Start the initial seeder.
-       tracker.succeed(
--          "transmission-remote --add /tmp/test.torrent --no-portmap --no-dht --download-dir /tmp/data"
-+          "transmission-remote --add /tmp/test.torrent --no-portmap --no-dht --download-dir ${download-dir}/data"
-       )
-       # Now we should be able to download from the client behind the NAT.
-       tracker.wait_for_unit("httpd")
-       client1.wait_for_unit("network-online.target")
-+      client1.succeed("transmission-remote --add http://${externalTrackerAddress}/test.torrent >&2 &")
-+      client1.wait_for_file("${download-dir}/test.tar.bz2")
-       client1.succeed(
--          "transmission-remote --add http://${externalTrackerAddress}/test.torrent --download-dir /tmp >&2 &"
--      )
--      client1.wait_for_file("/tmp/test.tar.bz2")
--      client1.succeed(
--          "cmp /tmp/test.tar.bz2 ${file}"
-+          "cmp ${download-dir}/test.tar.bz2 ${file}"
-       )
-       # Bring down the initial seeder.
-@@ -154,11 +154,11 @@ in
-       # the first client created a NAT hole in the router.
-       client2.wait_for_unit("network-online.target")
-       client2.succeed(
--          "transmission-remote --add http://${externalTrackerAddress}/test.torrent --no-portmap --no-dht --download-dir /tmp >&2 &"
-+          "transmission-remote --add http://${externalTrackerAddress}/test.torrent --no-portmap --no-dht >&2 &"
-       )
--      client2.wait_for_file("/tmp/test.tar.bz2")
-+      client2.wait_for_file("${download-dir}/test.tar.bz2")
-       client2.succeed(
--          "cmp /tmp/test.tar.bz2 ${file}"
-+          "cmp ${download-dir}/test.tar.bz2 ${file}"
-       )
-     '';
- })
-diff --git a/pkgs/os-specific/linux/apparmor/default.nix b/pkgs/os-specific/linux/apparmor/default.nix
-index 807ab4fa44b..fa7cded9aed 100644
---- a/pkgs/os-specific/linux/apparmor/default.nix
-+++ b/pkgs/os-specific/linux/apparmor/default.nix
-@@ -10,6 +10,10 @@
- , pam
- , libnotify
- , buildPackages
-+, coreutils
-+, gnugrep
-+, gnused
-+, writeShellScript
- }:
- let
-@@ -38,6 +42,22 @@ let
-     sha256 = "0xw028iqp69j9mxv0kbwraplgkj5i5djdlgf0anpkc5cdbsf96r9";
-   };
-+  aa-teardown = writeShellScript "aa-teardown" ''
-+    SECURITYFS=/sys/kernel/security
-+    SFS_MOUNTPOINT="$SECURITYFS/apparmor"
-+    ${gnused}/bin/sed -e "s/ (\(enforce\|complain\))$//" "$SFS_MOUNTPOINT/profiles" | \
-+    LC_COLLATE=C ${coreutils}/bin/sort | ${gnugrep}/bin/grep -v // | {
-+      while read -r profile ; do
-+        printf "%s" "$profile" > "$SFS_MOUNTPOINT/.remove"
-+        rc=$?
-+        if [ "$rc" -ne 0 ] ; then
-+          retval=$rc
-+        fi
-+      done
-+      exit "''${retval:-0}"
-+    }
-+  '';
-+
-   prePatchCommon = ''
-     patch -p1 < ${gnumake43Patch}
-     chmod a+x ./common/list_capabilities.sh ./common/list_af_names.sh
-@@ -145,6 +165,8 @@ let
-       # aa-notify checks its name and does not work named ".aa-notify-wrapped"
-       mv $out/bin/aa-notify $out/bin/aa-notify-wrapped
-       makeWrapper ${perl}/bin/perl $out/bin/aa-notify --set PERL5LIB ${libapparmor}/${perl.libPrefix} --add-flags $out/bin/aa-notify-wrapped
-+
-+      ln -s ${aa-teardown} $out/bin/aa-teardown
-     '';
-     inherit doCheck;
index c327461269b882623535943e80a677e9236ac53a..a7b03b3b54629d9bfde63f9dd23c3703beb6c389 100644 (file)
--- a/shell.nix
+++ b/shell.nix
@@ -23,22 +23,33 @@ let
       url = "https://github.com/NixOS/nixpkgs/pull/77450.diff";
       sha256 = "13ikg7chpbf6rrg5sngbdb95q3awhdgl4g8vci42xmqyf208hzzd";
     }
-    /*
     { meta.description = "transmission: apply RFC0042 and harden the service";
       url = "https://github.com/NixOS/nixpkgs/pull/92106.diff";
-      sha256 = "0h1105qy0wrirvi9fk5d00qsjvm745196vb7wgr648d56rm17vv1";
+      sha256 = "0d3dd511h7fw0k5q0k6wp7hcwkk7xikfwracp68f1y7hn4jj0pn0";
     }
     { meta.description = "apparmor: fix and improve the service";
       url = "https://github.com/NixOS/nixpkgs/pull/93457.diff";
-      sha256 = "0y1kvsnm8xiplbm4w4cadmfkr452vipswkz3kwyyikknh06vj3mn";
+      sha256 = "1yhs0459r7mxdzl70l67yzbj6i67ps2znaca852hd1gffi650bkr";
+    }
+    { meta.description = "nixos/security.gnupg: provisioning GnuPG-protected secrets through the Nix store";
+      url = "https://github.com/NixOS/nixpkgs/pull/93659.diff";
+      sha256 = "08pmka7ryz2gbyc8by40p31ky7s3dqxlj90dnw7fmlgb4pb3pkn0";
+    }
+    { meta.description = "nixos/croc: init";
+      url = "https://github.com/NixOS/nixpkgs/pull/93629.diff";
+      sha256 = "0fv3lpj244hvxyixxv4akrr70jv5wwbhb3kmbmd2yskx59a71rch";
+    }
+    { meta.description = "prosody-modules: update to revision 2dcbc01c9931";
+      url = "https://github.com/NixOS/nixpkgs/pull/94916.diff";
+      sha256 = "1cpdv5bd3837qh54yd0n6vvbfpn0p0cshkic5q0lv60lmm9raqk4";
+    }
+    { meta.description = "nixos/biboumi: init";
+      url = "https://github.com/NixOS/nixpkgs/pull/94917.diff";
+      sha256 = "19rizzxiszszsr1xz1ax0rsagx14ka0ndllb0s9y1fvdjxhb87iz";
     }
-    */
   ];
   localNixpkgsPatches = [
-    nixpkgs/patches/transmission+apparmor.diff
     nixpkgs/patches/installer.ssh-nixos.diff
-    nixpkgs/patches/security.gnupg.diff
-    nixpkgs/patches/services.croc.diff
     nixpkgs/patches/fix-flushBeforeStage2.diff
   ];
   # Build nixpkgs with some patches.