summary refs log tree commit diff
path: root/nixos/modules/services
diff options
context:
space:
mode:
Diffstat (limited to 'nixos/modules/services')
-rw-r--r--nixos/modules/services/cluster/kubernetes/dashboard.nix3
-rw-r--r--nixos/modules/services/cluster/kubernetes/default.nix1
-rw-r--r--nixos/modules/services/databases/aerospike.nix155
-rw-r--r--nixos/modules/services/databases/neo4j.nix677
-rw-r--r--nixos/modules/services/desktops/bamf.nix23
-rw-r--r--nixos/modules/services/hardware/pcscd.nix4
-rw-r--r--nixos/modules/services/misc/clipmenu.nix31
-rw-r--r--nixos/modules/services/networking/ssh/sshd.nix16
-rw-r--r--nixos/modules/services/printing/cupsd.nix17
-rw-r--r--nixos/modules/services/web-servers/apache-httpd/default.nix2
-rw-r--r--nixos/modules/services/x11/desktop-managers/plasma5.nix5
-rw-r--r--nixos/modules/services/x11/desktop-managers/xfce.nix8
-rw-r--r--nixos/modules/services/x11/display-managers/sddm.nix26
13 files changed, 856 insertions, 112 deletions
diff --git a/nixos/modules/services/cluster/kubernetes/dashboard.nix b/nixos/modules/services/cluster/kubernetes/dashboard.nix
index 6d9faada4401..cbd6e8f7bf73 100644
--- a/nixos/modules/services/cluster/kubernetes/dashboard.nix
+++ b/nixos/modules/services/cluster/kubernetes/dashboard.nix
@@ -10,8 +10,8 @@ in {
 
     rbac = mkOption {
       description = "Role-based access control (RBAC) options";
+      default = {};
       type = types.submodule {
-
         options = {
           enable = mkOption {
             description = "Whether to enable role based access control is enabled for kubernetes dashboard";
@@ -24,7 +24,6 @@ in {
             type = types.bool;
             default = false;
           };
-          
         };
       };
     };
diff --git a/nixos/modules/services/cluster/kubernetes/default.nix b/nixos/modules/services/cluster/kubernetes/default.nix
index 2707c176efd8..e5aba210b019 100644
--- a/nixos/modules/services/cluster/kubernetes/default.nix
+++ b/nixos/modules/services/cluster/kubernetes/default.nix
@@ -1116,6 +1116,7 @@ in {
         wantedBy = [ "kubernetes.target" ];
         after = [ "kube-apiserver.service" ];
         environment.ADDON_PATH = "/etc/kubernetes/addons/";
+        path = [ pkgs.gawk ];
         serviceConfig = {
           Slice = "kubernetes.slice";
           ExecStart = "${cfg.package}/bin/kube-addons";
diff --git a/nixos/modules/services/databases/aerospike.nix b/nixos/modules/services/databases/aerospike.nix
new file mode 100644
index 000000000000..5f33164998be
--- /dev/null
+++ b/nixos/modules/services/databases/aerospike.nix
@@ -0,0 +1,155 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.aerospike;
+
+  aerospikeConf = pkgs.writeText "aerospike.conf" ''
+    # This stanza must come first.
+    service {
+      user aerospike
+      group aerospike
+      paxos-single-replica-limit 1 # Number of nodes where the replica count is automatically reduced to 1.
+      proto-fd-max 15000
+      work-directory ${cfg.workDir}
+    }
+    logging {
+      console {
+        context any info
+      }
+    }
+    mod-lua {
+      system-path ${cfg.package}/share/udf/lua
+      user-path ${cfg.workDir}/udf/lua
+    }
+    network {
+      ${cfg.networkConfig}
+    }
+    ${cfg.extraConfig}
+  '';
+
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    services.aerospike = {
+      enable = mkEnableOption "Aerospike server";
+
+      package = mkOption {
+        default = pkgs.aerospike;
+        type = types.package;
+        description = "Which Aerospike derivation to use";
+      };
+
+      workDir = mkOption {
+        type = types.str;
+        default = "/var/lib/aerospike";
+        description = "Location where Aerospike stores its files";
+      };
+
+      networkConfig = mkOption {
+        type = types.lines;
+        default = ''
+          service {
+            address any
+            port 3000
+          }
+
+          heartbeat {
+            address any
+            mode mesh
+            port 3002
+            interval 150
+            timeout 10
+          }
+
+          fabric {
+            address any
+            port 3001
+          }
+
+          info {
+            address any
+            port 3003
+          }
+        '';
+        description = "network section of configuration file";
+      };
+
+      extraConfig = mkOption {
+        type = types.lines;
+        default = "";
+        example = ''
+          namespace test {
+            replication-factor 2
+            memory-size 4G
+            default-ttl 30d
+            storage-engine memory
+          }
+        '';
+        description = "Extra configuration";
+      };
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = mkIf config.services.aerospike.enable {
+
+    users.users.aerospike = {
+      name = "aerospike";
+      group = "aerospike";
+      uid = config.ids.uids.aerospike;
+      description = "Aerospike server user";
+    };
+    users.groups.aerospike.gid = config.ids.gids.aerospike;
+
+    systemd.services.aerospike = rec {
+      description = "Aerospike server";
+
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" ];
+
+      serviceConfig = {
+        ExecStart = "${cfg.package}/bin/asd --fgdaemon --config-file ${aerospikeConf}";
+        User = "aerospike";
+        Group = "aerospike";
+        LimitNOFILE = 100000;
+        PermissionsStartOnly = true;
+      };
+
+      preStart = ''
+        if [ $(echo "$(${pkgs.procps}/bin/sysctl -n kernel.shmall) < 4294967296" | ${pkgs.bc}/bin/bc) == "1"  ]; then
+          echo "kernel.shmall too low, setting to 4G pages"
+          ${pkgs.procps}/bin/sysctl -w kernel.shmall=4294967296
+        fi
+        if [ $(echo "$(${pkgs.procps}/bin/sysctl -n kernel.shmmax) < 1073741824" | ${pkgs.bc}/bin/bc) == "1"  ]; then
+          echo "kernel.shmmax too low, setting to 1GB"
+          ${pkgs.procps}/bin/sysctl -w kernel.shmmax=1073741824
+        fi
+        if [ $(echo "$(cat /proc/sys/net/core/rmem_max) < 15728640" | ${pkgs.bc}/bin/bc) == "1" ]; then
+          echo "increasing socket buffer limit (/proc/sys/net/core/rmem_max): $(cat /proc/sys/net/core/rmem_max) -> 15728640"
+          echo 15728640 > /proc/sys/net/core/rmem_max
+        fi
+        if [ $(echo "$(cat /proc/sys/net/core/wmem_max) <  5242880" | ${pkgs.bc}/bin/bc) == "1"  ]; then
+          echo "increasing socket buffer limit (/proc/sys/net/core/wmem_max): $(cat /proc/sys/net/core/wmem_max) -> 5242880"
+          echo  5242880 > /proc/sys/net/core/wmem_max
+        fi
+        install -d -m0700 -o ${serviceConfig.User} -g ${serviceConfig.Group} "${cfg.workDir}"
+        install -d -m0700 -o ${serviceConfig.User} -g ${serviceConfig.Group} "${cfg.workDir}/smd"
+        install -d -m0700 -o ${serviceConfig.User} -g ${serviceConfig.Group} "${cfg.workDir}/udf"
+        install -d -m0700 -o ${serviceConfig.User} -g ${serviceConfig.Group} "${cfg.workDir}/udf/lua"
+      '';
+    };
+
+  };
+
+}
diff --git a/nixos/modules/services/databases/neo4j.nix b/nixos/modules/services/databases/neo4j.nix
index 5015618c4247..5533182c3116 100644
--- a/nixos/modules/services/databases/neo4j.nix
+++ b/nixos/modules/services/databases/neo4j.nix
@@ -1,32 +1,87 @@
-{ config, lib, pkgs, ... }:
+{ config, options, lib, pkgs, ... }:
 
 with lib;
 
 let
   cfg = config.services.neo4j;
+  certDirOpt = options.services.neo4j.directories.certificates;
+  isDefaultPathOption = opt: isOption opt && opt.type == types.path && opt.highestPrio >= 1500;
+
+  sslPolicies = mapAttrsToList (
+    name: conf: ''
+      dbms.ssl.policy.${name}.allow_key_generation=${boolToString conf.allowKeyGeneration}
+      dbms.ssl.policy.${name}.base_directory=${conf.baseDirectory}
+      ${optionalString (conf.ciphers != null) ''
+        dbms.ssl.policy.${name}.ciphers=${concatStringsSep "," conf.ciphers}
+      ''}
+      dbms.ssl.policy.${name}.client_auth=${conf.clientAuth}
+      ${if length (splitString "/" conf.privateKey) > 1 then
+        ''dbms.ssl.policy.${name}.private_key=${conf.privateKey}''
+      else
+        ''dbms.ssl.policy.${name}.private_key=${conf.baseDirectory}/${conf.privateKey}''
+      }
+      ${if length (splitString "/" conf.privateKey) > 1 then
+        ''dbms.ssl.policy.${name}.public_certificate=${conf.publicCertificate}''
+      else
+        ''dbms.ssl.policy.${name}.public_certificate=${conf.baseDirectory}/${conf.publicCertificate}''
+      }
+      dbms.ssl.policy.${name}.revoked_dir=${conf.revokedDir}
+      dbms.ssl.policy.${name}.tls_versions=${concatStringsSep "," conf.tlsVersions}
+      dbms.ssl.policy.${name}.trust_all=${boolToString conf.trustAll}
+      dbms.ssl.policy.${name}.trusted_dir=${conf.trustedDir}
+    ''
+  ) cfg.ssl.policies;
 
   serverConfig = pkgs.writeText "neo4j.conf" ''
-    dbms.directories.data=${cfg.dataDir}/data
-    dbms.directories.certificates=${cfg.certDir}
-    dbms.directories.logs=${cfg.dataDir}/logs
-    dbms.directories.plugins=${cfg.dataDir}/plugins
-    dbms.connector.http.type=HTTP
-    dbms.connector.http.enabled=true
-    dbms.connector.http.address=${cfg.listenAddress}:${toString cfg.port}
-    ${optionalString cfg.enableBolt ''
-      dbms.connector.bolt.type=BOLT
-      dbms.connector.bolt.enabled=true
-      dbms.connector.bolt.tls_level=OPTIONAL
-      dbms.connector.bolt.address=${cfg.listenAddress}:${toString cfg.boltPort}
+    # General
+    dbms.allow_upgrade=${boolToString cfg.allowUpgrade}
+    dbms.connectors.default_listen_address=${cfg.defaultListenAddress}
+    dbms.read_only=${boolToString cfg.readOnly}
+    ${optionalString (cfg.workerCount > 0) ''
+      dbms.threads.worker_count=${toString cfg.workerCount}
     ''}
-    ${optionalString cfg.enableHttps ''
-      dbms.connector.https.type=HTTP
-      dbms.connector.https.enabled=true
-      dbms.connector.https.encryption=TLS
-      dbms.connector.https.address=${cfg.listenAddress}:${toString cfg.httpsPort}
+
+    # Directories
+    dbms.directories.certificates=${cfg.directories.certificates}
+    dbms.directories.data=${cfg.directories.data}
+    dbms.directories.logs=${cfg.directories.home}/logs
+    dbms.directories.plugins=${cfg.directories.plugins}
+    ${optionalString (cfg.constrainLoadCsv) ''
+      dbms.directories.import=${cfg.directories.imports}
     ''}
-    dbms.shell.enabled=true
-    ${cfg.extraServerConfig}
+
+    # HTTP Connector
+    ${optionalString (cfg.http.enable) ''
+      dbms.connector.http.enabled=${boolToString cfg.http.enable}
+      dbms.connector.http.listen_address=${cfg.http.listenAddress}
+    ''}
+    ${optionalString (!cfg.http.enable) ''
+      # It is not possible to disable the HTTP connector. To fully prevent
+      # clients from connecting to HTTP, block the HTTP port (7474 by default)
+      # via firewall. listen_address is set to the loopback interface to
+      # prevent remote clients from connecting.
+      dbms.connector.http.listen_address=127.0.0.1
+    ''}
+
+    # HTTPS Connector
+    dbms.connector.https.enabled=${boolToString cfg.https.enable}
+    dbms.connector.https.listen_address=${cfg.https.listenAddress}
+    https.ssl_policy=${cfg.https.sslPolicy}
+
+    # BOLT Connector
+    dbms.connector.bolt.enabled=${boolToString cfg.bolt.enable}
+    dbms.connector.bolt.listen_address=${cfg.bolt.listenAddress}
+    bolt.ssl_policy=${cfg.bolt.sslPolicy}
+    dbms.connector.bolt.tls_level=${cfg.bolt.tlsLevel}
+
+    # neo4j-shell
+    dbms.shell.enabled=${boolToString cfg.shell.enable}
+
+    # SSL Policies
+    ${concatStringsSep "\n" sslPolicies}
+
+    # Default retention policy from neo4j.conf
+    dbms.tx_log.rotation.retention_policy=1 days
 
     # Default JVM parameters from neo4j.conf
     dbms.jvm.additional=-XX:+UseG1GC
@@ -36,8 +91,14 @@ let
     dbms.jvm.additional=-XX:+TrustFinalNonStaticFields
     dbms.jvm.additional=-XX:+DisableExplicitGC
     dbms.jvm.additional=-Djdk.tls.ephemeralDHKeySize=2048
-
+    dbms.jvm.additional=-Djdk.tls.rejectClientInitiatedRenegotiation=true
     dbms.jvm.additional=-Dunsupported.dbms.udc.source=tarball
+
+    # Usage Data Collector
+    dbms.udc.enabled=${boolToString cfg.udc.enable}
+
+    # Extra Configuration
+    ${cfg.extraServerConfig}
   '';
 
 in {
@@ -45,105 +106,547 @@ in {
   ###### interface
 
   options.services.neo4j = {
+
     enable = mkOption {
-      description = "Whether to enable neo4j.";
+      type = types.bool;
       default = false;
+      description = ''
+        Whether to enable Neo4j Community Edition.
+      '';
+    };
+
+    allowUpgrade = mkOption {
       type = types.bool;
+      default = false;
+      description = ''
+        Allow upgrade of Neo4j database files from an older version.
+      '';
+    };
+
+    constrainLoadCsv = mkOption {
+      type = types.bool;
+      default = true;
+      description = ''
+        Sets the root directory for file URLs used with the Cypher
+        <literal>LOAD CSV</literal> clause to be that defined by
+        <option>directories.imports</option>. It restricts
+        access to only those files within that directory and its
+        subdirectories.
+        </para>
+        <para>
+        Setting this option to <literal>false</literal> introduces
+        possible security problems.
+      '';
+    };
+
+    defaultListenAddress = mkOption {
+      type = types.str;
+      default = "127.0.0.1";
+      description = ''
+        Default network interface to listen for incoming connections. To
+        listen for connections on all interfaces, use "0.0.0.0".
+        </para>
+        <para>
+        Specifies the default IP address and address part of connector
+        specific <option>listenAddress</option> options. To bind specific
+        connectors to a specific network interfaces, specify the entire
+        <option>listenAddress</option> option for that connector.
+      '';
+    };
+
+    extraServerConfig = mkOption {
+      type = types.lines;
+      default = "";
+      description = ''
+        Extra configuration for Neo4j Community server. Refer to the
+        <link xlink:href="https://neo4j.com/docs/operations-manual/current/reference/configuration-settings/">complete reference</link>
+        of Neo4j configuration settings.
+      '';
     };
 
     package = mkOption {
-      description = "Neo4j package to use.";
+      type = types.package;
       default = pkgs.neo4j;
       defaultText = "pkgs.neo4j";
-      type = types.package;
+      description = ''
+        Neo4j package to use.
+      '';
     };
 
-    listenAddress = mkOption {
-      description = "Neo4j listen address.";
-      default = "127.0.0.1";
-      type = types.str;
+    readOnly = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        Only allow read operations from this Neo4j instance.
+      '';
     };
 
-    port = mkOption {
-      description = "Neo4j port to listen for HTTP traffic.";
-      default = 7474;
-      type = types.int;
+    workerCount = mkOption {
+      type = types.ints.between 0 44738;
+      default = 0;
+      description = ''
+        Number of Neo4j worker threads, where the default of
+        <literal>0</literal> indicates a worker count equal to the number of
+        available processors.
+      '';
     };
 
-    enableBolt = mkOption {
-      description = "Enable bolt for Neo4j.";
-      default = true;
-      type = types.bool;
+    bolt = {
+      enable = mkOption {
+        type = types.bool;
+        default = true;
+        description = ''
+          Enable the BOLT connector for Neo4j. Setting this option to
+          <literal>false</literal> will stop Neo4j from listening for incoming
+          connections on the BOLT port (7687 by default).
+        '';
+      };
+
+      listenAddress = mkOption {
+        type = types.str;
+        default = ":7687";
+        description = ''
+          Neo4j listen address for BOLT traffic. The listen address is
+          expressed in the format <literal>&lt;ip-address&gt;:&lt;port-number&gt;</literal>.
+        '';
+      };
+
+      sslPolicy = mkOption {
+        type = types.str;
+        default = "legacy";
+        description = ''
+          Neo4j SSL policy for BOLT traffic.
+          </para>
+          <para>
+          The legacy policy is a special policy which is not defined in
+          the policy configuration section, but rather derives from
+          <option>directories.certificates</option> and
+          associated files (by default: <filename>neo4j.key</filename> and
+          <filename>neo4j.cert</filename>). Its use will be deprecated.
+          </para>
+          <para>
+          Note: This connector must be configured to support/require
+          SSL/TLS for the legacy policy to actually be utilized. See
+          <option>bolt.tlsLevel</option>.
+        '';
+      };
+
+      tlsLevel = mkOption {
+        type = types.enum [ "REQUIRED" "OPTIONAL" "DISABLED" ];
+        default = "OPTIONAL";
+        description = ''
+          SSL/TSL requirement level for BOLT traffic.
+        '';
+      };
     };
 
-    boltPort = mkOption {
-      description = "Neo4j port to listen for BOLT traffic.";
-      default = 7687;
-      type = types.int;
+    directories = {
+      certificates = mkOption {
+        type = types.path;
+        default = "${cfg.directories.home}/certificates";
+        description = ''
+          Directory for storing certificates to be used by Neo4j for
+          TLS connections.
+          </para>
+          <para>
+          When setting this directory to something other than its default,
+          ensure the directory's existence, and that read/write permissions are
+          given to the Neo4j daemon user <literal>neo4j</literal>.
+          </para>
+          <para>
+          Note that changing this directory from its default will prevent
+          the directory structure required for each SSL policy from being
+          automatically generated. A policy's directory structure as defined by
+          its <option>baseDirectory</option>,<option>revokedDir</option> and
+          <option>trustedDir</option> must then be setup manually. The
+          existence of these directories is mandatory, as well as the presence
+          of the certificate file and the private key. Ensure the correct
+          permissions are set on these directories and files.
+        '';
+      };
+
+      data = mkOption {
+        type = types.path;
+        default = "${cfg.directories.home}/data";
+        description = ''
+          Path of the data directory. You must not configure more than one
+          Neo4j installation to use the same data directory.
+          </para>
+          <para>
+          When setting this directory to something other than its default,
+          ensure the directory's existence, and that read/write permissions are
+          given to the Neo4j daemon user <literal>neo4j</literal>.
+        '';
+      };
+
+      home = mkOption {
+        type = types.path;
+        default = "/var/lib/neo4j";
+        description = ''
+          Path of the Neo4j home directory. Other default directories are
+          subdirectories of this path. This directory will be created if
+          non-existent, and its ownership will be <command>chown</command> to
+          the Neo4j daemon user <literal>neo4j</literal>.
+        '';
+      };
+
+      imports = mkOption {
+        type = types.path;
+        default = "${cfg.directories.home}/import";
+        description = ''
+          The root directory for file URLs used with the Cypher
+          <literal>LOAD CSV</literal> clause. Only meaningful when
+          <option>constrainLoadCvs</option> is set to
+          <literal>true</literal>.
+          </para>
+          <para>
+          When setting this directory to something other than its default,
+          ensure the directory's existence, and that read permission is
+          given to the Neo4j daemon user <literal>neo4j</literal>.
+        '';
+      };
+
+      plugins = mkOption {
+        type = types.path;
+        default = "${cfg.directories.home}/plugins";
+        description = ''
+          Path of the database plugin directory. Compiled Java JAR files that
+          contain database procedures will be loaded if they are placed in
+          this directory.
+          </para>
+          <para>
+          When setting this directory to something other than its default,
+          ensure the directory's existence, and that read permission is
+          given to the Neo4j daemon user <literal>neo4j</literal>.
+        '';
+      };
     };
 
-    enableHttps = mkOption {
-      description = "Enable https for Neo4j.";
-      default = false;
-      type = types.bool;
+    http = {
+      enable = mkOption {
+        type = types.bool;
+        default = true;
+        description = ''
+          The HTTP connector is required for Neo4j, and cannot be disabled.
+          Setting this option to <literal>false</literal> will force the HTTP
+          connector's <option>listenAddress</option> to the loopback
+          interface to prevent connection of remote clients. To prevent all
+          clients from connecting, block the HTTP port (7474 by default) by
+          firewall.
+        '';
+      };
+
+      listenAddress = mkOption {
+        type = types.str;
+        default = ":7474";
+        description = ''
+          Neo4j listen address for HTTP traffic. The listen address is
+          expressed in the format <literal>&lt;ip-address&gt;:&lt;port-number&gt;</literal>.
+        '';
+      };
     };
 
-    httpsPort = mkOption {
-      description = "Neo4j port to listen for HTTPS traffic.";
-      default = 7473;
-      type = types.int;
+    https = {
+      enable = mkOption {
+        type = types.bool;
+        default = true;
+        description = ''
+          Enable the HTTPS connector for Neo4j. Setting this option to
+          <literal>false</literal> will stop Neo4j from listening for incoming
+          connections on the HTTPS port (7473 by default).
+        '';
+      };
+
+      listenAddress = mkOption {
+        type = types.str;
+        default = ":7473";
+        description = ''
+          Neo4j listen address for HTTPS traffic. The listen address is
+          expressed in the format <literal>&lt;ip-address&gt;:&lt;port-number&gt;</literal>.
+        '';
+      };
+
+      sslPolicy = mkOption {
+        type = types.str;
+        default = "legacy";
+        description = ''
+          Neo4j SSL policy for HTTPS traffic.
+          </para>
+          <para>
+          The legacy policy is a special policy which is not defined in the
+          policy configuration section, but rather derives from
+          <option>directories.certificates</option> and
+          associated files (by default: <filename>neo4j.key</filename> and
+          <filename>neo4j.cert</filename>). Its use will be deprecated.
+        '';
+      };
     };
 
-    certDir = mkOption {
-      description = "Neo4j TLS certificates directory.";
-      default = "${cfg.dataDir}/certificates";
-      type = types.path;
+    shell = {
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Enable a remote shell server which Neo4j Shell clients can log in to.
+          Only applicable to <command>neo4j-shell</command>.
+        '';
+      };
     };
 
-    dataDir = mkOption {
-      description = "Neo4j data directory.";
-      default = "/var/lib/neo4j";
-      type = types.path;
+    ssl.policies = mkOption {
+      type = with types; attrsOf (submodule ({ name, config, options, ... }: {
+        options = {
+
+          allowKeyGeneration = mkOption {
+            type = types.bool;
+            default = false;
+            description = ''
+              Allows the generation of a private key and associated self-signed
+              certificate. Only performed when both objects cannot be found for
+              this policy. It is recommended to turn this off again after keys
+              have been generated.
+              </para>
+              <para>
+              The public certificate is required to be duplicated to the
+              directory holding trusted certificates as defined by the
+              <option>trustedDir</option> option.
+              </para>
+              <para>
+              Keys should in general be generated and distributed offline by a
+              trusted certificate authority and not by utilizing this mode.
+            '';
+          };
+
+          baseDirectory = mkOption {
+            type = types.path;
+            default = "${cfg.directories.certificates}/${name}";
+            description = ''
+              The mandatory base directory for cryptographic objects of this
+              policy. This path is only automatically generated when this
+              option as well as <option>directories.certificates</option> are
+              left at their default. Ensure read/write permissions are given
+              to the Neo4j daemon user <literal>neo4j</literal>.
+              </para>
+              <para>
+              It is also possible to override each individual
+              configuration with absolute paths. See the
+              <option>privateKey</option> and <option>publicCertificate</option>
+              policy options.
+            '';
+          };
+
+          ciphers = mkOption {
+            type = types.nullOr (types.listOf types.str);
+            default = null;
+            description = ''
+              Restrict the allowed ciphers of this policy to those defined
+              here. The default ciphers are those of the JVM platform.
+            '';
+          };
+
+          clientAuth = mkOption {
+            type = types.enum [ "NONE" "OPTIONAL" "REQUIRE" ];
+            default = "REQUIRE";
+            description = ''
+              The client authentication stance for this policy.
+            '';
+          };
+
+          privateKey = mkOption {
+            type = types.str;
+            default = "private.key";
+            description = ''
+              The name of private PKCS #8 key file for this policy to be found
+              in the <option>baseDirectory</option>, or the absolute path to
+              the key file. It is mandatory that a key can be found or generated.
+            '';
+          };
+
+          publicCertificate = mkOption {
+            type = types.str;
+            default = "public.crt";
+            description = ''
+              The name of public X.509 certificate (chain) file in PEM format
+              for this policy to be found in the <option>baseDirectory</option>,
+              or the absolute path to the certificate file. It is mandatory
+              that a certificate can be found or generated.
+              </para>
+              <para>
+              The public certificate is required to be duplicated to the
+              directory holding trusted certificates as defined by the
+              <option>trustedDir</option> option.
+            '';
+          };
+
+          revokedDir = mkOption {
+            type = types.path;
+            default = "${config.baseDirectory}/revoked";
+            description = ''
+              Path to directory of CRLs (Certificate Revocation Lists) in
+              PEM format. Must be an absolute path. The existence of this
+              directory is mandatory and will need to be created manually when:
+              setting this option to something other than its default; setting
+              either this policy's <option>baseDirectory</option> or
+              <option>directories.certificates</option> to something other than
+              their default. Ensure read/write permissions are given to the
+              Neo4j daemon user <literal>neo4j</literal>.
+            '';
+          };
+
+          tlsVersions = mkOption {
+            type = types.listOf types.str;
+            default = [ "TLSv1.2" ];
+            description = ''
+              Restrict the TLS protocol versions of this policy to those
+              defined here.
+            '';
+          };
+
+          trustAll = mkOption {
+            type = types.bool;
+            default = false;
+            description = ''
+              Makes this policy trust all remote parties. Enabling this is not
+              recommended and the policy's trusted directory will be ignored.
+              Use of this mode is discouraged. It would offer encryption but
+              no security.
+            '';
+          };
+
+          trustedDir = mkOption {
+            type = types.path;
+            default = "${config.baseDirectory}/trusted";
+            description = ''
+              Path to directory of X.509 certificates in PEM format for
+              trusted parties. Must be an absolute path. The existence of this
+              directory is mandatory and will need to be created manually when:
+              setting this option to something other than its default; setting
+              either this policy's <option>baseDirectory</option> or
+              <option>directories.certificates</option> to something other than
+              their default. Ensure read/write permissions are given to the
+              Neo4j daemon user <literal>neo4j</literal>.
+              </para>
+              <para>
+              The public certificate as defined by
+              <option>publicCertificate</option> is required to be duplicated
+              to this directory.
+            '';
+          };
+
+          directoriesToCreate = mkOption {
+            type = types.listOf types.path;
+            internal = true;
+            readOnly = true;
+            description = ''
+              Directories of this policy that will be created automatically
+              when the certificates directory is left at its default value.
+              This includes all options of type path that are left at their
+              default value.
+            '';
+          };
+
+        };
+
+        config.directoriesToCreate = optionals
+          (certDirOpt.highestPrio >= 1500 && options.baseDirectory.highestPrio >= 1500)
+          (map (opt: opt.value) (filter isDefaultPathOption (attrValues options)));
+
+      }));
+      default = {};
+      description = ''
+        Defines the SSL policies for use with Neo4j connectors. Each attribute
+        of this set defines a policy, with the attribute name defining the name
+        of the policy and its namespace. Refer to the operations manual section
+        on Neo4j's
+        <link xlink:href="https://neo4j.com/docs/operations-manual/current/security/ssl-framework/">SSL Framework</link>
+        for further details.
+      '';
     };
 
-    extraServerConfig = mkOption {
-      description = "Extra configuration for neo4j server.";
-      default = "";
-      type = types.lines;
+    udc = {
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Enable the Usage Data Collector which Neo4j uses to collect usage
+          data. Refer to the operations manual section on the
+          <link xlink:href="https://neo4j.com/docs/operations-manual/current/configuration/usage-data-collector/">Usage Data Collector</link>
+          for more information.
+        '';
+      };
     };
+
   };
 
   ###### implementation
 
-  config = mkIf cfg.enable {
-    systemd.services.neo4j = {
-      description = "Neo4j Daemon";
-      wantedBy = [ "multi-user.target" ];
-      after = [ "network.target" ];
-      environment = {
-        NEO4J_HOME = "${cfg.package}/share/neo4j";
-        NEO4J_CONF = "${cfg.dataDir}/conf";
-      };
-      serviceConfig = {
-        ExecStart = "${cfg.package}/bin/neo4j console";
-        User = "neo4j";
-        PermissionsStartOnly = true;
-        LimitNOFILE = 40000;
-      };
-      preStart = ''
-        mkdir -m 0700 -p ${cfg.dataDir}/{data/graph.db,conf,logs}
-        ln -fs ${serverConfig} ${cfg.dataDir}/conf/neo4j.conf
-        if [ "$(id -u)" = 0 ]; then chown -R neo4j ${cfg.dataDir}; fi
-      '';
-    };
+  config =
+    let
+      # Assertion helpers
+      policyNameList = attrNames cfg.ssl.policies;
+      validPolicyNameList = [ "legacy" ] ++ policyNameList;
+      validPolicyNameString = concatStringsSep ", " validPolicyNameList;
+
+      # Capture various directories left at their default so they can be created.
+      defaultDirectoriesToCreate = map (opt: opt.value) (filter isDefaultPathOption (attrValues options.services.neo4j.directories));
+      policyDirectoriesToCreate = concatMap (pol: pol.directoriesToCreate) (attrValues cfg.ssl.policies);
+    in
+
+    mkIf cfg.enable {
+      assertions = [
+        { assertion = !elem "legacy" policyNameList;
+          message = "The policy 'legacy' is special to Neo4j, and its name is reserved."; }
+        { assertion = elem cfg.bolt.sslPolicy validPolicyNameList;
+          message = "Invalid policy assigned: `services.neo4j.bolt.sslPolicy = \"${cfg.bolt.sslPolicy}\"`, defined policies are: ${validPolicyNameString}"; }
+        { assertion = elem cfg.https.sslPolicy validPolicyNameList;
+          message = "Invalid policy assigned: `services.neo4j.https.sslPolicy = \"${cfg.https.sslPolicy}\"`, defined policies are: ${validPolicyNameString}"; }
+      ];
+
+      systemd.services.neo4j = {
+        description = "Neo4j Daemon";
+        wantedBy = [ "multi-user.target" ];
+        after = [ "network.target" ];
+        environment = {
+          NEO4J_HOME = "${cfg.package}/share/neo4j";
+          NEO4J_CONF = "${cfg.directories.home}/conf";
+        };
+        serviceConfig = {
+          ExecStart = "${cfg.package}/bin/neo4j console";
+          User = "neo4j";
+          PermissionsStartOnly = true;
+          LimitNOFILE = 40000;
+        };
+
+        preStart = ''
+          # Directories Setup
+          #   Always ensure home exists with nested conf, logs directories.
+          mkdir -m 0700 -p ${cfg.directories.home}/{conf,logs}
 
-    environment.systemPackages = [ cfg.package ];
+          #   Create other sub-directories and policy directories that have been left at their default.
+          ${concatMapStringsSep "\n" (
+            dir: ''
+              mkdir -m 0700 -p ${dir}
+          '') (defaultDirectoriesToCreate ++ policyDirectoriesToCreate)}
 
-    users.users = singleton {
-      name = "neo4j";
-      uid = config.ids.uids.neo4j;
-      description = "Neo4j daemon user";
-      home = cfg.dataDir;
+          # Place the configuration where Neo4j can find it.
+          ln -fs ${serverConfig} ${cfg.directories.home}/conf/neo4j.conf
+
+          # Ensure neo4j user ownership
+          chown -R neo4j ${cfg.directories.home}
+        '';
+      };
+
+      environment.systemPackages = [ cfg.package ];
+
+      users.users = singleton {
+        name = "neo4j";
+        uid = config.ids.uids.neo4j;
+        description = "Neo4j daemon user";
+        home = cfg.directories.home;
+      };
     };
+
+  meta = {
+    maintainers = with lib.maintainers; [ patternspandemic ];
   };
 }
diff --git a/nixos/modules/services/desktops/bamf.nix b/nixos/modules/services/desktops/bamf.nix
new file mode 100644
index 000000000000..0928ee81a648
--- /dev/null
+++ b/nixos/modules/services/desktops/bamf.nix
@@ -0,0 +1,23 @@
+# Bamf
+
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+  ###### interface
+
+  options = {
+    services.bamf = {
+      enable = mkEnableOption "bamf";
+    };
+  };
+
+  ###### implementation
+
+  config = mkIf config.services.bamf.enable {
+    services.dbus.packages = [ pkgs.bamf ];
+
+    systemd.packages = [ pkgs.bamf ];
+  };
+}
diff --git a/nixos/modules/services/hardware/pcscd.nix b/nixos/modules/services/hardware/pcscd.nix
index fa97e8bf746b..f3fc4c3cc79e 100644
--- a/nixos/modules/services/hardware/pcscd.nix
+++ b/nixos/modules/services/hardware/pcscd.nix
@@ -61,8 +61,8 @@ in {
       description = "PCSC-Lite daemon";
       environment.PCSCLITE_HP_DROPDIR = pluginEnv;
       serviceConfig = {
-        ExecStart = "${pkgs.pcsclite}/sbin/pcscd -f -x -c ${cfgFile}";
-        ExecReload = "${pkgs.pcsclite}/sbin/pcscd -H";
+        ExecStart = "${getBin pkgs.pcsclite}/sbin/pcscd -f -x -c ${cfgFile}";
+        ExecReload = "${getBin pkgs.pcsclite}/sbin/pcscd -H";
       };
     };
   };
diff --git a/nixos/modules/services/misc/clipmenu.nix b/nixos/modules/services/misc/clipmenu.nix
new file mode 100644
index 000000000000..3ba050044cac
--- /dev/null
+++ b/nixos/modules/services/misc/clipmenu.nix
@@ -0,0 +1,31 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.clipmenu;
+in {
+
+  options.services.clipmenu = {
+    enable = mkEnableOption "clipmenu, the clipboard management daemon";
+
+    package = mkOption {
+      type = types.package;
+      default = pkgs.clipmenu;
+      defaultText = "pkgs.clipmenu";
+      description = "clipmenu derivation to use.";
+    };
+  };
+
+  config = mkIf cfg.enable {
+    systemd.user.services.clipmenu = {
+      enable      = true;
+      description = "Clipboard management daemon";
+      wantedBy = [ "graphical-session.target" ];
+      after    = [ "graphical-session.target" ];
+      serviceConfig.ExecStart = "${cfg.package}/bin/clipmenud";
+    };
+
+    environment.systemPackages = [ cfg.package ];
+  };
+}
diff --git a/nixos/modules/services/networking/ssh/sshd.nix b/nixos/modules/services/networking/ssh/sshd.nix
index 8b04fac089ef..7b2d1920f0f1 100644
--- a/nixos/modules/services/networking/ssh/sshd.nix
+++ b/nixos/modules/services/networking/ssh/sshd.nix
@@ -198,6 +198,10 @@ in
           [ { type = "rsa"; bits = 4096; path = "/etc/ssh/ssh_host_rsa_key"; }
             { type = "ed25519"; path = "/etc/ssh/ssh_host_ed25519_key"; }
           ];
+        example =
+          [ { type = "rsa"; bits = 4096; path = "/etc/ssh/ssh_host_rsa_key"; rounds = 100; openSSHFormat = true; }
+            { type = "ed25519"; path = "/etc/ssh/ssh_host_ed25519_key"; rounds = 100; comment = "key comment"; }
+          ];
         description = ''
           NixOS can automatically generate SSH host keys.  This option
           specifies the path, type and size of each key.  See
@@ -358,7 +362,14 @@ in
 
                 ${flip concatMapStrings cfg.hostKeys (k: ''
                   if ! [ -f "${k.path}" ]; then
-                      ssh-keygen -t "${k.type}" ${if k ? bits then "-b ${toString k.bits}" else ""} -f "${k.path}" -N ""
+                      ssh-keygen \
+                        -t "${k.type}" \
+                        ${if k ? bits then "-b ${toString k.bits}" else ""} \
+                        ${if k ? rounds then "-a ${toString k.rounds}" else ""} \
+                        ${if k ? comment then "-C '${k.comment}'" else ""} \
+                        ${if k ? openSSHFormat && k.openSSHFormat then "-o" else ""} \
+                        -f "${k.path}" \
+                        -N ""
                   fi
                 '')}
               '';
@@ -404,6 +415,9 @@ in
         unixAuth = cfg.passwordAuthentication;
       };
 
+    # These values are merged with the ones defined externally, see:
+    # https://github.com/NixOS/nixpkgs/pull/10155
+    # https://github.com/NixOS/nixpkgs/pull/41745
     services.openssh.authorizedKeysFiles =
       [ ".ssh/authorized_keys" ".ssh/authorized_keys2" "/etc/ssh/authorized_keys.d/%u" ];
 
diff --git a/nixos/modules/services/printing/cupsd.nix b/nixos/modules/services/printing/cupsd.nix
index b074d15cbec1..dbf18ec1d114 100644
--- a/nixos/modules/services/printing/cupsd.nix
+++ b/nixos/modules/services/printing/cupsd.nix
@@ -124,6 +124,16 @@ in
         '';
       };
 
+      startWhenNeeded = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          If set, CUPS is socket-activated; that is,
+          instead of having it permanently running as a daemon,
+          systemd will start it on the first incoming connection.
+        '';
+      };
+
       listenAddresses = mkOption {
         type = types.listOf types.str;
         default = [ "localhost:631" ];
@@ -287,8 +297,13 @@ in
 
     systemd.packages = [ cups.out ];
 
+    systemd.sockets.cups = mkIf cfg.startWhenNeeded {
+      wantedBy = [ "sockets.target" ];
+      listenStreams = map (x: replaceStrings ["localhost"] ["127.0.0.1"] (removePrefix "*:" x)) cfg.listenAddresses;
+    };
+
     systemd.services.cups =
-      { wantedBy = [ "multi-user.target" ];
+      { wantedBy = optionals (!cfg.startWhenNeeded) [ "multi-user.target" ];
         wants = [ "network.target" ];
         after = [ "network.target" ];
 
diff --git a/nixos/modules/services/web-servers/apache-httpd/default.nix b/nixos/modules/services/web-servers/apache-httpd/default.nix
index b71ff0531cc8..eb8ee9b5cf46 100644
--- a/nixos/modules/services/web-servers/apache-httpd/default.nix
+++ b/nixos/modules/services/web-servers/apache-httpd/default.nix
@@ -656,7 +656,7 @@ in
                      message = "SSL is enabled for httpd, but sslServerCert and/or sslServerKey haven't been specified."; }
                  ];
 
-    warnings = map (cfg: ''apache-httpd's port option is deprecated. Use listen = [{/*ip = "*"; */ port = ${toString cfg.port}";}]; instead'' ) (lib.filter (cfg: cfg.port != 0) allHosts);
+    warnings = map (cfg: ''apache-httpd's port option is deprecated. Use listen = [{/*ip = "*"; */ port = ${toString cfg.port};}]; instead'' ) (lib.filter (cfg: cfg.port != 0) allHosts);
 
     users.users = optionalAttrs (mainCfg.user == "wwwrun") (singleton
       { name = "wwwrun";
diff --git a/nixos/modules/services/x11/desktop-managers/plasma5.nix b/nixos/modules/services/x11/desktop-managers/plasma5.nix
index 91d091d7d7e2..4b9e561d53c8 100644
--- a/nixos/modules/services/x11/desktop-managers/plasma5.nix
+++ b/nixos/modules/services/x11/desktop-managers/plasma5.nix
@@ -221,6 +221,11 @@ in
       security.pam.services.sddm.enableKwallet = true;
       security.pam.services.slim.enableKwallet = true;
 
+      # Update the start menu for each user that has `isNormalUser` set.
+      system.activationScripts.plasmaSetup = stringAfter [ "users" "groups" ]
+        (concatStringsSep "\n"
+          (mapAttrsToList (name: value: "${pkgs.su}/bin/su ${name} -c kbuildsycoca5")
+            (filterAttrs (n: v: v.isNormalUser) config.users.users)));
     })
   ];
 
diff --git a/nixos/modules/services/x11/desktop-managers/xfce.nix b/nixos/modules/services/x11/desktop-managers/xfce.nix
index 7dcc600d2664..ae155470419d 100644
--- a/nixos/modules/services/x11/desktop-managers/xfce.nix
+++ b/nixos/modules/services/x11/desktop-managers/xfce.nix
@@ -43,12 +43,6 @@ in
         default = true;
         description = "Enable the XFWM (default) window manager.";
       };
-
-      screenLock = mkOption {
-        type = types.enum [ "xscreensaver" "xlockmore" "slock" ];
-        default = "xlockmore";
-        description = "Application used by XFCE to lock the screen.";
-      };
     };
   };
 
@@ -92,7 +86,7 @@ in
       thunar-volman # TODO: drop
     ] ++ (if config.hardware.pulseaudio.enable
           then [ xfce4-mixer-pulse xfce4-volumed-pulse ]
-	  else [ xfce4-mixer xfce4-volumed ])
+          else [ xfce4-mixer xfce4-volumed ])
       # TODO: NetworkManager doesn't belong here
       ++ optionals config.networking.networkmanager.enable [ networkmanagerapplet ]
       ++ optionals config.powerManagement.enable [ xfce4-power-manager ]
diff --git a/nixos/modules/services/x11/display-managers/sddm.nix b/nixos/modules/services/x11/display-managers/sddm.nix
index 8db7414e811f..426b899586f5 100644
--- a/nixos/modules/services/x11/display-managers/sddm.nix
+++ b/nixos/modules/services/x11/display-managers/sddm.nix
@@ -19,17 +19,6 @@ let
 
   Xsetup = pkgs.writeScript "Xsetup" ''
     #!/bin/sh
-
-    # Prior to Qt 5.9.2, there is a QML cache invalidation bug which sometimes
-    # strikes new Plasma 5 releases. If the QML cache is not invalidated, SDDM
-    # will segfault without explanation. We really tore our hair out for awhile
-    # before finding the bug:
-    # https://bugreports.qt.io/browse/QTBUG-62302
-    # We work around the problem by deleting the QML cache before startup. It
-    # will be regenerated, causing a small but perceptible delay when SDDM
-    # starts.
-    rm -fr /var/lib/sddm/.cache/sddm-greeter/qmlcache
-
     ${cfg.setupScript}
   '';
 
@@ -285,5 +274,20 @@ in
     # To enable user switching, allow sddm to allocate TTYs/displays dynamically.
     services.xserver.tty = null;
     services.xserver.display = null;
+
+    systemd.tmpfiles.rules = [
+      # Prior to Qt 5.9.2, there is a QML cache invalidation bug which sometimes
+      # strikes new Plasma 5 releases. If the QML cache is not invalidated, SDDM
+      # will segfault without explanation. We really tore our hair out for awhile
+      # before finding the bug:
+      # https://bugreports.qt.io/browse/QTBUG-62302
+      # We work around the problem by deleting the QML cache before startup.
+      # This was supposedly fixed in Qt 5.9.2 however it has been reported with
+      # 5.10 and 5.11 as well. The initial workaround was to delete the directory
+      # in the Xsetup script but that doesn't do anything.
+      # Instead we use tmpfiles.d to ensure it gets wiped.
+      # This causes a small but perceptible delay when SDDM starts.
+      "e ${config.users.users.sddm.home}/.cache - - - 0"
+    ];
   };
 }