about summary refs log tree commit diff
path: root/nixos/modules/services
diff options
context:
space:
mode:
authorTuomas Tynkkynen <tuomas@tuxera.com>2016-05-03 23:12:48 +0300
committerTuomas Tynkkynen <tuomas@tuxera.com>2016-05-03 23:12:48 +0300
commitaadaa913792b0fdeb68b02425e4f03d2f8286a1f (patch)
treeea582b078a00e6ba27e2c887a9df5a792c37fb0e /nixos/modules/services
parent2362891dc815160e343e52458f25db22508ac487 (diff)
parente7d3166656af0d98da9f59c78e2213cec842d743 (diff)
downloadnixlib-aadaa913792b0fdeb68b02425e4f03d2f8286a1f.tar
nixlib-aadaa913792b0fdeb68b02425e4f03d2f8286a1f.tar.gz
nixlib-aadaa913792b0fdeb68b02425e4f03d2f8286a1f.tar.bz2
nixlib-aadaa913792b0fdeb68b02425e4f03d2f8286a1f.tar.lz
nixlib-aadaa913792b0fdeb68b02425e4f03d2f8286a1f.tar.xz
nixlib-aadaa913792b0fdeb68b02425e4f03d2f8286a1f.tar.zst
nixlib-aadaa913792b0fdeb68b02425e4f03d2f8286a1f.zip
Merge remote-tracking branch 'upstream/master' into staging
Conflicts:
	pkgs/applications/networking/browsers/vivaldi/default.nix
	pkgs/misc/emulators/wine/base.nix
Diffstat (limited to 'nixos/modules/services')
-rw-r--r--nixos/modules/services/hardware/sane_extra_backends/brscan4.nix116
-rw-r--r--nixos/modules/services/hardware/sane_extra_backends/brscan4_etc_files.nix71
-rw-r--r--nixos/modules/services/logging/graylog.nix161
-rw-r--r--nixos/modules/services/mail/rmilter.nix67
-rw-r--r--nixos/modules/services/mail/rspamd.nix59
-rw-r--r--nixos/modules/services/misc/taskserver/default.nix4
-rw-r--r--nixos/modules/services/networking/copy-com.nix54
-rw-r--r--nixos/modules/services/search/elasticsearch.nix1
-rw-r--r--nixos/modules/services/security/fail2ban.nix28
-rw-r--r--nixos/modules/services/x11/desktop-managers/gnome3.nix2
-rw-r--r--nixos/modules/services/x11/desktop-managers/xfce.nix5
-rw-r--r--nixos/modules/services/x11/display-managers/default.nix8
-rw-r--r--nixos/modules/services/x11/xserver.nix9
13 files changed, 496 insertions, 89 deletions
diff --git a/nixos/modules/services/hardware/sane_extra_backends/brscan4.nix b/nixos/modules/services/hardware/sane_extra_backends/brscan4.nix
new file mode 100644
index 000000000000..3ec74458cd29
--- /dev/null
+++ b/nixos/modules/services/hardware/sane_extra_backends/brscan4.nix
@@ -0,0 +1,116 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.hardware.sane.brscan4;
+
+  netDeviceList = attrValues cfg.netDevices;
+
+  etcFiles = pkgs.callPackage ./brscan4_etc_files.nix { netDevices = netDeviceList; };
+
+  netDeviceOpts = { name, config, ... }: {
+
+    options = {
+
+      name = mkOption {
+        type = types.str;
+        description = ''
+          The friendly name you give to the network device. If undefined,
+          the name of attribute will be used.
+        '';
+
+        example = literalExample "office1";
+      };
+
+      model = mkOption {
+        type = types.str;
+        description = ''
+          The model of the network device.
+        '';
+
+        example = literalExample "MFC-7860DW";
+      };
+
+      ip = mkOption {
+        type = with types; nullOr str;
+        default = null;
+        description = ''
+          The ip address of the device. If undefined, you will have to
+          provide a nodename.
+        '';
+
+        example = literalExample "192.168.1.2";
+      };
+
+      nodename = mkOption {
+        type = with types; nullOr str;
+        default = null;
+        description = ''
+          The node name of the device. If undefined, you will have to
+          provide an ip.
+        '';
+
+        example = literalExample "BRW0080927AFBCE";
+      };
+
+    };
+
+
+    config =
+      { name = mkDefault name;
+      };
+  };
+
+in
+
+{
+  options = {
+
+    hardware.sane.brscan4.enable = 
+      mkEnableOption "Brother's brscan4 scan backend" // {
+      description = ''
+        When enabled, will automatically register the "brscan4" sane
+        backend and bring configuration files to their expected location. 
+      '';
+    };
+
+    hardware.sane.brscan4.netDevices = mkOption {
+      default = {};
+      example =
+        { office1 = { model = "MFC-7860DW"; ip = "192.168.1.2"; };
+          office2 = { model = "MFC-7860DW"; nodename = "BRW0080927AFBCE"; };
+        };
+      type = types.loaOf types.optionSet;
+      description = ''
+        The list of network devices that will be registered against the brscan4
+        sane backend.
+      '';
+      options = [ netDeviceOpts ];
+    };
+  };
+
+  config = mkIf (config.hardware.sane.enable && cfg.enable) {
+
+    hardware.sane.extraBackends = [
+      pkgs.brscan4
+    ];
+
+    environment.etc = singleton {
+      target = "opt/brother/scanner/brscan4";
+      source = "${etcFiles}/etc/opt/brother/scanner/brscan4";
+    };
+
+    assertions = [
+      { assertion = all (x: !(null != x.ip && null != x.nodename)) netDeviceList;
+          
+        message = ''
+          When describing a network device as part of the attribute list
+          `hardware.sane.brscan4.netDevices`, only one of its `ip` or `nodename`
+          attribute should be specified, not both!
+        '';
+      }
+    ];
+
+  };
+}
\ No newline at end of file
diff --git a/nixos/modules/services/hardware/sane_extra_backends/brscan4_etc_files.nix b/nixos/modules/services/hardware/sane_extra_backends/brscan4_etc_files.nix
new file mode 100644
index 000000000000..bd114f0d2cca
--- /dev/null
+++ b/nixos/modules/services/hardware/sane_extra_backends/brscan4_etc_files.nix
@@ -0,0 +1,71 @@
+{ stdenv, lib, brscan4, netDevices ? [] }:
+
+/*
+
+Testing
+-------
+
+No net devices:
+
+~~~
+nix-shell -E 'with import <nixpkgs> { }; brscan4-etc-files'
+~~~
+
+Two net devices:
+
+~~~
+nix-shell -E 'with import <nixpkgs> { }; brscan4-etc-files.override{netDevices=[{name="a"; model="MFC-7860DW"; nodename="BRW0080927AFBCE";} {name="b"; model="MFC-7860DW"; ip="192.168.1.2";}];}'
+~~~
+
+*/
+
+with lib; 
+
+let
+
+  addNetDev = nd: ''
+    brsaneconfig4 -a \
+    name="${nd.name}" \
+    model="${nd.model}" \
+    ${if (hasAttr "nodename" nd && nd.nodename != null) then
+      ''nodename="${nd.nodename}"'' else
+      ''ip="${nd.ip}"''}'';
+  addAllNetDev = xs: concatStringsSep "\n" (map addNetDev xs);
+in
+
+stdenv.mkDerivation rec {
+
+  name = "brscan4-etc-files-0.4.3-3";
+  src = "${brscan4}/opt/brother/scanner/brscan4";
+
+  nativeBuildInputs = [ brscan4 ];
+
+  configurePhase = ":";
+
+  buildPhase = ''
+    TARGET_DIR="$out/etc/opt/brother/scanner/brscan4"
+    mkdir -p "$TARGET_DIR"
+    cp -rp "./models4" "$TARGET_DIR"
+    cp -rp "./Brsane4.ini" "$TARGET_DIR"
+    cp -rp "./brsanenetdevice4.cfg" "$TARGET_DIR"
+
+    export BRSANENETDEVICE4_CFG_FILENAME="$TARGET_DIR/brsanenetdevice4.cfg"
+
+    printf '${addAllNetDev netDevices}\n'
+
+    ${addAllNetDev netDevices}
+  '';
+
+  installPhase = ":";
+
+  dontStrip = true;
+  dontPatchELF = true;
+
+  meta = {
+    description = "Brother brscan4 sane backend driver etc files";
+    homepage = http://www.brother.com;
+    platforms = stdenv.lib.platforms.linux;
+    license = stdenv.lib.licenses.unfree;
+    maintainers = with stdenv.lib.maintainers; [ jraygauthier ];
+  };
+}
diff --git a/nixos/modules/services/logging/graylog.nix b/nixos/modules/services/logging/graylog.nix
new file mode 100644
index 000000000000..a7785decd19a
--- /dev/null
+++ b/nixos/modules/services/logging/graylog.nix
@@ -0,0 +1,161 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.graylog;
+  configBool = b: if b then "true" else "false";
+
+  confFile = pkgs.writeText "graylog.conf" ''
+    is_master = ${configBool cfg.isMaster}
+    node_id_file = ${cfg.nodeIdFile}
+    password_secret = ${cfg.passwordSecret}
+    root_username = ${cfg.rootUsername}
+    root_password_sha2 = ${cfg.rootPasswordSha2}
+    elasticsearch_cluster_name = ${cfg.elasticsearchClusterName}
+    elasticsearch_discovery_zen_ping_multicast_enabled = ${configBool cfg.elasticsearchDiscoveryZenPingMulticastEnabled}
+    elasticsearch_discovery_zen_ping_unicast_hosts = ${cfg.elasticsearchDiscoveryZenPingUnicastHosts}
+    message_journal_dir = ${cfg.messageJournalDir}
+    mongodb_uri = ${cfg.mongodbUri}
+
+    ${cfg.extraConfig}
+  '';
+in
+
+{
+  ###### interface
+
+  options = {
+
+    services.graylog = {
+
+      enable = mkEnableOption "Graylog";
+
+      package = mkOption {
+        type = types.package;
+        default = pkgs.graylog;
+        defaultText = "pkgs.graylog";
+        example = literalExample "pkgs.graylog";
+        description = "Graylog package to use.";
+      };
+
+      user = mkOption {
+        type = types.str;
+        default = "graylog";
+        example = literalExample "graylog";
+        description = "User account under which graylog runs";
+      };
+
+      isMaster = mkOption {
+        type = types.bool;
+        default = true;
+        description = "Whether this is the master instance of your Graylog cluster";
+      };
+
+      nodeIdFile = mkOption {
+        type = types.str;
+        default = "/var/lib/graylog/server/node-id";
+        description = "Path of the file containing the graylog node-id";
+      };
+
+      passwordSecret = mkOption {
+        type = types.str;
+        description = ''
+          You MUST set a secret to secure/pepper the stored user passwords here. Use at least 64 characters.
+          Generate one by using for example: pwgen -N 1 -s 96
+        '';
+      };
+
+      rootUsername = mkOption {
+        type = types.str;
+        default = "admin";
+        description = "Name of the default administrator user";
+      };
+
+      rootPasswordSha2 = mkOption {
+        type = types.str;
+        example = "e3c652f0ba0b4801205814f8b6bc49672c4c74e25b497770bb89b22cdeb4e952";
+        description = ''
+          You MUST specify a hash password for the root user (which you only need to initially set up the
+          system and in case you lose connectivity to your authentication backend)
+          This password cannot be changed using the API or via the web interface. If you need to change it,
+          modify it here.
+          Create one by using for example: echo -n yourpassword | shasum -a 256
+          and use the resulting hash value as string for the option
+        '';
+      };
+
+      elasticsearchClusterName = mkOption {
+        type = types.str;
+        example = "graylog";
+        description = "This must be the same as for your Elasticsearch cluster";
+      };
+
+      elasticsearchDiscoveryZenPingMulticastEnabled = mkOption {
+        type = types.bool;
+        default = false;
+        description = "Whether to use elasticsearch multicast discovery";
+      };
+
+      elasticsearchDiscoveryZenPingUnicastHosts = mkOption {
+        type = types.str;
+        default = "127.0.0.1:9300";
+        description = "Tells Graylogs Elasticsearch client how to find other cluster members. See Elasticsearch documentation for details";
+      };
+
+      messageJournalDir = mkOption {
+        type = types.str;
+        default = "/var/lib/graylog/data/journal";
+        description = "The directory which will be used to store the message journal. The directory must be exclusively used by Graylog and must not contain any other files than the ones created by Graylog itself";
+      };
+
+      mongodbUri = mkOption {
+        type = types.str;
+        default = "mongodb://localhost/graylog";
+        description = "MongoDB connection string. See http://docs.mongodb.org/manual/reference/connection-string/ for details";
+      };
+
+      extraConfig = mkOption {
+        type = types.str;
+        default = "";
+        description = "Any other configuration options you might want to add";
+      };
+
+    };
+  };
+
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    users.extraUsers = mkIf (cfg.user == "graylog") {
+      graylog = {
+        uid = config.ids.uids.graylog;
+        description = "Graylog server daemon user";
+      };
+    };
+
+    systemd.services.graylog = with pkgs; {
+      description = "Graylog Server";
+      wantedBy = [ "multi-user.target" ];
+      environment = {
+        JAVA_HOME = jre;
+        GRAYLOG_CONF = "${confFile}";
+      };
+      path = [ pkgs.openjdk8 pkgs.which pkgs.procps ];
+      preStart = ''
+        mkdir -p /var/lib/graylog -m 755
+        chown -R ${cfg.user} /var/lib/graylog
+
+        mkdir -p ${cfg.messageJournalDir} -m 755
+        chown -R ${cfg.user} ${cfg.messageJournalDir}
+      '';
+      serviceConfig = {
+        User="${cfg.user}";
+        PermissionsStartOnly=true;
+        ExecStart = "${cfg.package}/bin/graylogctl run";
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/mail/rmilter.nix b/nixos/modules/services/mail/rmilter.nix
index a6e2a9fc7808..d1f7cd2e173e 100644
--- a/nixos/modules/services/mail/rmilter.nix
+++ b/nixos/modules/services/mail/rmilter.nix
@@ -7,9 +7,14 @@ let
   rspamdCfg = config.services.rspamd;
   cfg = config.services.rmilter;
 
+  inetSockets = map (sock: let s = stringSplit ":" sock; in "inet:${last s}:${head s}") cfg.bindInetSockets;
+  unixSockets = map (sock: "unix:${sock}") cfg.bindUnixSockets;
+
+  allSockets = unixSockets ++ inetSockets;
+
   rmilterConf = ''
 pidfile = /run/rmilter/rmilter.pid;
-bind_socket = ${cfg.bindSocket};
+bind_socket = ${if cfg.socketActivation then "fd:3" else concatStringsSep ", " allSockets};
 tempdir = /tmp;
 
   '' + (with cfg.rspamd; if enable then ''
@@ -68,14 +73,37 @@ in
         '';
        };
 
-      bindSocket =  mkOption {
-        type = types.string;
-        default = "unix:/run/rmilter/rmilter.sock";
-        description = "Socket to listed for MTA requests";
+      bindUnixSockets =  mkOption {
+        type = types.listOf types.str;
+        default = ["/run/rmilter.sock"];
+        description = ''
+          Unix domain sockets to listen for MTA requests.
+        '';
         example = ''
-            "unix:/run/rmilter/rmilter.sock" or
-            "inet:11990@127.0.0.1"
-          '';
+            [ "/run/rmilter.sock"]
+        '';
+      };
+
+      bindInetSockets = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        description = ''
+          Inet addresses to listen (in format accepted by systemd.socket)
+        '';
+        example = ''
+            ["127.0.0.1:11990"]
+        '';
+      };
+
+      socketActivation = mkOption {
+        type = types.bool;
+        default = true;
+        description = ''
+          Enable systemd socket activation for rmilter.
+          (disabling socket activation not recommended
+          when unix socket used, and follow to wrong
+          permissions on unix domain socket.)
+        '';
       };
 
       rspamd = {
@@ -86,7 +114,7 @@ in
 
         servers = mkOption {
           type = types.listOf types.str;
-          default = ["r:0.0.0.0:11333"];
+          default = ["r:/run/rspamd.sock"];
           description = ''
             Spamd socket definitions.
             Is server name is prefixed with r: it is rspamd server.
@@ -129,7 +157,7 @@ in
           type = types.str;
           description = "Addon to postfix configuration";
           default = ''
-smtpd_milters = ${cfg.bindSocket}
+smtpd_milters = ${head allSockets}
 # or for TCP socket
 # # smtpd_milters = inet:localhost:9900
 milter_protocol = 6
@@ -169,21 +197,30 @@ milter_default_action = accept
 
       serviceConfig = {
         ExecStart = "${pkgs.rmilter}/bin/rmilter ${optionalString cfg.debug "-d"} -n -c ${rmilterConfigFile}";
+        ExecReload = "/bin/kill -USR1 $MAINPID";
         User = cfg.user;
         Group = cfg.group;
         PermissionsStartOnly = true;
         Restart = "always";
+        RuntimeDirectory = "rmilter";
+        RuntimeDirectoryPermissions="0755";
       };
 
-      preStart = ''
-        ${pkgs.coreutils}/bin/mkdir -p /run/rmilter
-        ${pkgs.coreutils}/bin/chown ${cfg.user}:${cfg.group} /run/rmilter
-      '';
+    };
 
+    systemd.sockets.rmilter = mkIf cfg.socketActivation {
+      description = "Rmilter service socket";
+      wantedBy = [ "sockets.target" ];
+      socketConfig = {
+          ListenStream = cfg.bindUnixSockets ++ cfg.bindInetSockets;
+          SocketUser = cfg.user;
+          SocketGroup = cfg.group;
+          SocketMode = "0660";
+      };
     };
 
     services.postfix.extraConfig = optionalString cfg.postfix.enable cfg.postfix.configFragment;
-
+    users.users.postfix.extraGroups = [ cfg.group ];
   };
 
 }
diff --git a/nixos/modules/services/mail/rspamd.nix b/nixos/modules/services/mail/rspamd.nix
index a083f8293243..412b99ccc570 100644
--- a/nixos/modules/services/mail/rspamd.nix
+++ b/nixos/modules/services/mail/rspamd.nix
@@ -6,6 +6,35 @@ let
 
   cfg = config.services.rspamd;
 
+  mkBindSockets = socks: concatStringsSep "\n" (map (each: "  bind_socket = \"${each}\"") socks);
+
+  rspamdConf =
+    ''
+      .include "$CONFDIR/common.conf"
+
+      options {
+        pidfile = "$RUNDIR/rspamd.pid";
+        .include "$CONFDIR/options.inc"
+      }
+
+      logging {
+        type = "file";
+        filename = "$LOGDIR/rspamd.log";
+        .include "$CONFDIR/logging.inc"
+      }
+
+      worker {
+      ${mkBindSockets cfg.bindSocket}
+        .include "$CONFDIR/worker-normal.inc"
+      }
+
+      worker {
+      ${mkBindSockets cfg.bindUISocket}
+        .include "$CONFDIR/worker-controller.inc"
+      }
+   '';
+   rspamdConfFile = pkgs.writeText "rspamd.conf" rspamdConf;
+
 in
 
 {
@@ -26,6 +55,32 @@ in
         description = "Whether to run the rspamd daemon in debug mode.";
       };
 
+      bindSocket = mkOption {
+        type = types.listOf types.str;
+        default = [
+          "/run/rspamd.sock mode=0666 owner=${cfg.user}"
+        ];
+        description = ''
+          List of sockets to listen, in format acceptable by rspamd
+        '';
+        example = ''
+          bindSocket = [
+            "/run/rspamd.sock mode=0666 owner=rspamd"
+            "*:11333"
+          ];
+        '';
+      };
+
+      bindUISocket = mkOption {
+        type = types.listOf types.str;
+        default = [
+          "localhost:11334"
+        ];
+        description = ''
+          List of sockets for web interface, in format acceptable by rspamd
+        '';
+      };
+
       user = mkOption {
         type = types.string;
         default = "rspamd";
@@ -62,7 +117,7 @@ in
 
     users.extraGroups = singleton {
       name = cfg.group;
-      gid = config.ids.gids.spamd;
+      gid = config.ids.gids.rspamd;
     };
 
     systemd.services.rspamd = {
@@ -72,7 +127,7 @@ in
       after = [ "network.target" ];
 
       serviceConfig = {
-        ExecStart = "${pkgs.rspamd}/bin/rspamd ${optionalString cfg.debug "-d"} --user=${cfg.user} --group=${cfg.group} --pid=/run/rspamd.pid -f";
+        ExecStart = "${pkgs.rspamd}/bin/rspamd ${optionalString cfg.debug "-d"} --user=${cfg.user} --group=${cfg.group} --pid=/run/rspamd.pid -c ${rspamdConfFile} -f";
         RuntimeDirectory = "/var/lib/rspamd";
         PermissionsStartOnly = true;
         Restart = "always";
diff --git a/nixos/modules/services/misc/taskserver/default.nix b/nixos/modules/services/misc/taskserver/default.nix
index 8459aafeee73..b7d14e90a2b7 100644
--- a/nixos/modules/services/misc/taskserver/default.nix
+++ b/nixos/modules/services/misc/taskserver/default.nix
@@ -449,7 +449,7 @@ in {
         };
       };
     })
-    (mkIf needToCreateCA {
+    (mkIf (cfg.enable && needToCreateCA) {
       systemd.services.taskserver-ca = {
         wantedBy = [ "taskserver.service" ];
         after = [ "taskserver-init.service" ];
@@ -533,7 +533,7 @@ in {
         '';
       };
     })
-    (mkIf (cfg.listenHost != "localhost") {
+    (mkIf (cfg.enable && cfg.listenHost != "localhost") {
       networking.firewall.allowedTCPPorts = [ cfg.listenPort ];
     })
     { meta.doc = ./taskserver.xml; }
diff --git a/nixos/modules/services/networking/copy-com.nix b/nixos/modules/services/networking/copy-com.nix
deleted file mode 100644
index ee0d043d471b..000000000000
--- a/nixos/modules/services/networking/copy-com.nix
+++ /dev/null
@@ -1,54 +0,0 @@
-{ config, lib, pkgs, ... }:
-
-with lib;
-
-let
-
-  cfg = config.services.copy-com;
-
-in
-
-{
-  options = {
-
-    services.copy-com = {
-
-	  enable = mkOption {
-          default = false;
-          description = "
-            Enable the Copy.com client.
-            NOTE: before enabling the client for the first time, it must be
-            configured by first running CopyConsole (command line) or CopyAgent
-            (graphical) as the appropriate user.
-          ";
-      };
-
-      user = mkOption {
-        description = "The user for which the Copy.com client should be run.";
-      };
-
-      debug = mkOption {
-        default = false;
-        description = "Output more (debugging) messages to the console.";
-      };
-	  };
-  };
-
-  config = mkIf cfg.enable {
-    environment.systemPackages = [ pkgs.postfix ];
-
-    systemd.services."copy-com-${cfg.user}" = {
-      description = "Copy.com client";
-      wants = [ "network-online.target" ];
-      after = [ "network-online.target" "local-fs.target" ];
-      wantedBy = [ "multi-user.target" ];
-      serviceConfig = {
-        ExecStart = "${pkgs.copy-com}/bin/CopyConsole ${if cfg.debug then "-consoleOutput -debugToConsole=dirwatch,path-watch,csm_path,csm -debug -console" else ""}";
-        User = "${cfg.user}";
-      };
-
-    };
-  };
-
-}
-
diff --git a/nixos/modules/services/search/elasticsearch.nix b/nixos/modules/services/search/elasticsearch.nix
index c51a42b8e9c1..17ac8fe7e245 100644
--- a/nixos/modules/services/search/elasticsearch.nix
+++ b/nixos/modules/services/search/elasticsearch.nix
@@ -145,6 +145,7 @@ in {
         # Install plugins
         ln -sfT ${esPlugins}/plugins ${cfg.dataDir}/plugins
         ln -sfT ${cfg.package}/lib ${cfg.dataDir}/lib
+        ln -sfT ${cfg.package}/modules ${cfg.dataDir}/modules
         if [ "$(id -u)" = 0 ]; then chown -R elasticsearch ${cfg.dataDir}; fi
       '';
       postStart = mkBefore ''
diff --git a/nixos/modules/services/security/fail2ban.nix b/nixos/modules/services/security/fail2ban.nix
index afbd81be91f2..33c4910fc0ce 100644
--- a/nixos/modules/services/security/fail2ban.nix
+++ b/nixos/modules/services/security/fail2ban.nix
@@ -99,34 +99,32 @@ in
 
         wantedBy = [ "multi-user.target" ];
         after = [ "network.target" ];
+        partOf = optional config.networking.firewall.enable "firewall.service";
 
         restartTriggers = [ fail2banConf jailConf ];
         path = [ pkgs.fail2ban pkgs.iptables ];
 
         preStart =
           ''
-            mkdir -p /run/fail2ban -m 0755
             mkdir -p /var/lib/fail2ban
           '';
 
+        unitConfig.Documentation = "man:fail2ban(1)";
+
         serviceConfig =
-          { ExecStart = "${pkgs.fail2ban}/bin/fail2ban-server -f";
+          { Type = "forking";
+            ExecStart = "${pkgs.fail2ban}/bin/fail2ban-client -x start";
+            ExecStop = "${pkgs.fail2ban}/bin/fail2ban-client stop";
+            ExecReload = "${pkgs.fail2ban}/bin/fail2ban-client reload";
+            PIDFile = "/run/fail2ban/fail2ban.pid";
+            Restart = "always";
+
             ReadOnlyDirectories = "/";
-            ReadWriteDirectories = "/run /var/tmp /var/lib";
+            ReadWriteDirectories = "/run/fail2ban /var/tmp /var/lib";
+            PrivateTmp = "true";
+            RuntimeDirectory = "fail2ban";
             CapabilityBoundingSet = "CAP_DAC_READ_SEARCH CAP_NET_ADMIN CAP_NET_RAW";
           };
-
-        postStart =
-          ''
-            # Wait for the server to start listening.
-            for ((n = 0; n < 20; n++)); do
-              if fail2ban-client ping; then break; fi
-              sleep 0.5
-            done
-
-            # Reload its configuration.
-            fail2ban-client reload
-          '';
       };
 
     # Add some reasonable default jails.  The special "DEFAULT" jail
diff --git a/nixos/modules/services/x11/desktop-managers/gnome3.nix b/nixos/modules/services/x11/desktop-managers/gnome3.nix
index b112fc2422a7..16996b9f96c1 100644
--- a/nixos/modules/services/x11/desktop-managers/gnome3.nix
+++ b/nixos/modules/services/x11/desktop-managers/gnome3.nix
@@ -165,6 +165,8 @@ in {
         '';
       };
 
+    services.xserver.updateDbusEnvironment = true;
+
     environment.variables.GIO_EXTRA_MODULES = [ "${gnome3.dconf}/lib/gio/modules"
                                                 "${gnome3.glib_networking.out}/lib/gio/modules"
                                                 "${gnome3.gvfs}/lib/gio/modules" ];
diff --git a/nixos/modules/services/x11/desktop-managers/xfce.nix b/nixos/modules/services/x11/desktop-managers/xfce.nix
index 33b6dd32c193..60934ed5f190 100644
--- a/nixos/modules/services/x11/desktop-managers/xfce.nix
+++ b/nixos/modules/services/x11/desktop-managers/xfce.nix
@@ -42,10 +42,13 @@ in
             # Set GTK_DATA_PREFIX so that GTK+ can find the Xfce themes.
             export GTK_DATA_PREFIX=${config.system.path}
 
-            exec ${pkgs.stdenv.shell} ${pkgs.xfce.xinitrc}
+            ${pkgs.stdenv.shell} ${pkgs.xfce.xinitrc} &
+            waitPID=$!
           '';
       };
 
+    services.xserver.updateDbusEnvironment = true;
+
     environment.systemPackages =
       [ pkgs.gtk # To get GTK+'s themes.
         pkgs.hicolor_icon_theme
diff --git a/nixos/modules/services/x11/display-managers/default.nix b/nixos/modules/services/x11/display-managers/default.nix
index be634fc259a2..376f9f4b46b5 100644
--- a/nixos/modules/services/x11/display-managers/default.nix
+++ b/nixos/modules/services/x11/display-managers/default.nix
@@ -126,6 +126,14 @@ let
         (*) echo "$0: Desktop manager '$desktopManager' not found.";;
       esac
 
+      ${optionalString (cfg.startDbusSession && cfg.updateDbusEnvironment) ''
+        ${pkgs.glib}/bin/gdbus call --session \
+          --dest org.freedesktop.DBus --object-path /org/freedesktop/DBus \
+          --method org.freedesktop.DBus.UpdateActivationEnvironment \
+          "{$(env | ${pkgs.gnused}/bin/sed "s/'/\\\\'/g; s/\([^=]*\)=\(.*\)/'\1':'\2'/" \
+                  | ${pkgs.coreutils}/bin/paste -sd,)}"
+      ''}
+
       test -n "$waitPID" && wait "$waitPID"
       exit 0
     '';
diff --git a/nixos/modules/services/x11/xserver.nix b/nixos/modules/services/x11/xserver.nix
index dcf9f820f59c..9cb9c8de31d7 100644
--- a/nixos/modules/services/x11/xserver.nix
+++ b/nixos/modules/services/x11/xserver.nix
@@ -233,6 +233,15 @@ in
         '';
       };
 
+      updateDbusEnvironment = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to update the DBus activation environment after launching the
+          desktop manager.
+        '';
+      };
+
       layout = mkOption {
         type = types.str;
         default = "us";