summary refs log tree commit diff
path: root/nixos/modules/services
diff options
context:
space:
mode:
authorVladimír Čunát <vcunat@gmail.com>2016-02-14 08:33:51 +0100
committerVladimír Čunát <vcunat@gmail.com>2016-02-14 08:33:51 +0100
commitd039c879845ddcde6108203781e4b001c409e2c2 (patch)
tree1f9e2a99d95c8866ddbef81b4bfa6a49ce979451 /nixos/modules/services
parent34922a3951a0ada7af4fe808250abaf5feb4e28e (diff)
parent6a036d9fca013265b4109ffcaf6df62efa010fa3 (diff)
downloadnixlib-d039c879845ddcde6108203781e4b001c409e2c2.tar
nixlib-d039c879845ddcde6108203781e4b001c409e2c2.tar.gz
nixlib-d039c879845ddcde6108203781e4b001c409e2c2.tar.bz2
nixlib-d039c879845ddcde6108203781e4b001c409e2c2.tar.lz
nixlib-d039c879845ddcde6108203781e4b001c409e2c2.tar.xz
nixlib-d039c879845ddcde6108203781e4b001c409e2c2.tar.zst
nixlib-d039c879845ddcde6108203781e4b001c409e2c2.zip
Merge branch 'master' into closure-size
Diffstat (limited to 'nixos/modules/services')
-rw-r--r--nixos/modules/services/databases/postgresql.nix38
-rw-r--r--nixos/modules/services/hardware/acpid.nix174
-rw-r--r--nixos/modules/services/hardware/bluetooth.nix60
-rw-r--r--nixos/modules/services/hardware/udev.nix87
-rw-r--r--nixos/modules/services/logging/logstash.nix6
-rw-r--r--nixos/modules/services/mail/dovecot.nix1
-rw-r--r--nixos/modules/services/mail/dspam.nix5
-rw-r--r--nixos/modules/services/mail/opensmtpd.nix21
-rw-r--r--nixos/modules/services/mail/postfix.nix32
-rw-r--r--nixos/modules/services/mail/postsrsd.nix6
-rw-r--r--nixos/modules/services/misc/gitit.nix1
-rw-r--r--nixos/modules/services/misc/sundtek.nix2
-rw-r--r--nixos/modules/services/networking/connman.nix6
-rw-r--r--nixos/modules/services/networking/i2pd.nix300
-rw-r--r--nixos/modules/services/networking/ssh/sshd.nix13
-rw-r--r--nixos/modules/services/networking/tinc.nix12
-rw-r--r--nixos/modules/services/networking/unifi.nix2
-rw-r--r--nixos/modules/services/networking/wpa_supplicant.nix28
-rw-r--r--nixos/modules/services/search/elasticsearch.nix13
-rw-r--r--nixos/modules/services/search/kibana.nix65
-rw-r--r--nixos/modules/services/security/haka.nix156
-rw-r--r--nixos/modules/services/web-servers/apache-httpd/mediawiki.nix4
-rw-r--r--nixos/modules/services/x11/desktop-managers/default.nix8
-rw-r--r--nixos/modules/services/x11/desktop-managers/gnome3.nix2
-rw-r--r--nixos/modules/services/x11/desktop-managers/kde4.nix6
-rw-r--r--nixos/modules/services/x11/desktop-managers/kde5.nix10
-rw-r--r--nixos/modules/services/x11/display-managers/default.nix3
-rw-r--r--nixos/modules/services/x11/display-managers/lightdm.nix2
-rw-r--r--nixos/modules/services/x11/hardware/synaptics.nix29
-rw-r--r--nixos/modules/services/x11/window-managers/i3.nix2
30 files changed, 653 insertions, 441 deletions
diff --git a/nixos/modules/services/databases/postgresql.nix b/nixos/modules/services/databases/postgresql.nix
index c2045a5859c5..31ffe51c11ef 100644
--- a/nixos/modules/services/databases/postgresql.nix
+++ b/nixos/modules/services/databases/postgresql.nix
@@ -158,7 +158,7 @@ in
       # Note: when changing the default, make it conditional on
       # ‘system.stateVersion’ to maintain compatibility with existing
       # systems!
-      mkDefault pkgs.postgresql94;
+      mkDefault (if versionAtLeast config.system.stateVersion "16.03" then pkgs.postgresql95 else pkgs.postgresql94);
 
     services.postgresql.authentication = mkAfter
       ''
@@ -177,7 +177,7 @@ in
 
     users.extraGroups.postgres.gid = config.ids.gids.postgres;
 
-    environment.systemPackages = [postgresql];
+    environment.systemPackages = [ postgresql ];
 
     systemd.services.postgresql =
       { description = "PostgreSQL Server";
@@ -187,35 +187,37 @@ in
 
         environment.PGDATA = cfg.dataDir;
 
-        path = [ pkgs.su postgresql ];
+        path = [ postgresql ];
 
         preStart =
           ''
-            # Initialise the database.
+            # Create data directory.
             if ! test -e ${cfg.dataDir}/PG_VERSION; then
-                mkdir -m 0700 -p ${cfg.dataDir}
-                rm -f ${cfg.dataDir}/*.conf
-                if [ "$(id -u)" = 0 ]; then
-                  chown -R postgres ${cfg.dataDir}
-                  su -s ${pkgs.stdenv.shell} postgres -c 'initdb -U root'
-                else
-                  # For non-root operation.
-                  initdb
-                fi
-                # See postStart!
-                touch "${cfg.dataDir}/.first_startup"
+              mkdir -m 0700 -p ${cfg.dataDir}
+              rm -f ${cfg.dataDir}/*.conf
+              chown -R postgres:postgres ${cfg.dataDir}
             fi
+          ''; # */
 
+        script =
+          ''
+            # Initialise the database.
+            if ! test -e ${cfg.dataDir}/PG_VERSION; then
+              initdb -U root
+              # See postStart!
+              touch "${cfg.dataDir}/.first_startup"
+            fi
             ln -sfn "${configFile}" "${cfg.dataDir}/postgresql.conf"
             ${optionalString (cfg.recoveryConfig != null) ''
               ln -sfn "${pkgs.writeText "recovery.conf" cfg.recoveryConfig}" \
                 "${cfg.dataDir}/recovery.conf"
             ''}
-          ''; # */
+
+             exec postgres ${toString flags}
+          '';
 
         serviceConfig =
-          { ExecStart = "@${postgresql}/bin/postgres postgres ${toString flags}";
-            ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+          { ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
             User = "postgres";
             Group = "postgres";
             PermissionsStartOnly = true;
diff --git a/nixos/modules/services/hardware/acpid.nix b/nixos/modules/services/hardware/acpid.nix
index 48b2b6be09ed..bb17c8859d84 100644
--- a/nixos/modules/services/hardware/acpid.nix
+++ b/nixos/modules/services/hardware/acpid.nix
@@ -4,111 +4,38 @@ with lib;
 
 let
 
-  acpiConfDir = pkgs.runCommand "acpi-events" {}
-    ''
-      mkdir -p $out
-      ${
-        # Generate a configuration file for each event. (You can't have
-        # multiple events in one config file...)
-        let f = event:
-          ''
-            fn=$out/${event.name}
-            echo "event=${event.event}" > $fn
-            echo "action=${pkgs.writeScript "${event.name}.sh" event.action}" >> $fn
-          '';
-        in lib.concatMapStrings f events
-      }
-    '';
-
-  events = [powerEvent lidEvent acEvent muteEvent volumeDownEvent volumeUpEvent cdPlayEvent cdNextEvent cdPrevEvent];
-
-  # Called when the power button is pressed.
-  powerEvent =
-    { name = "power-button";
+  canonicalHandlers = {
+    powerEvent = {
       event = "button/power.*";
-      action =
-        ''
-          #! ${pkgs.bash}/bin/sh
-          ${config.services.acpid.powerEventCommands}
-        '';
+      action = config.services.acpid.powerEventCommands;
     };
 
-  # Called when the laptop lid is opened/closed.
-  lidEvent =
-    { name = "lid";
+    lidEvent = {
       event = "button/lid.*";
-      action =
-        ''
-          #! ${pkgs.bash}/bin/sh
-          ${config.services.acpid.lidEventCommands}
-        '';
+      action = config.services.acpid.lidEventCommands;
     };
 
-  # Called when the AC power is connected or disconnected.
-  acEvent =
-    { name = "ac-power";
+    acEvent = {
       event = "ac_adapter.*";
-      action =
-        ''
-          #! ${pkgs.bash}/bin/sh
-          ${config.services.acpid.acEventCommands}
-        '';
+      action = config.services.acpid.acEventCommands;
     };
-
-  muteEvent = {
-    name = "mute";
-    event = "button/mute.*";
-    action = ''
-      #! ${pkgs.bash}/bin/sh
-      ${config.services.acpid.muteCommands}
-    '';
-  };
-
-  volumeDownEvent = {
-    name = "volume-down";
-    event = "button/volumedown.*";
-    action = ''
-      #! ${pkgs.bash}/bin/sh
-      ${config.services.acpid.volumeDownEventCommands}
-    '';
   };
 
-  volumeUpEvent = {
-    name = "volume-up";
-    event = "button/volumeup.*";
-    action = ''
-      #! ${pkgs.bash}/bin/sh
-      ${config.services.acpid.volumeUpEventCommands}
-    '';
-  };
-
-  cdPlayEvent = {
-    name = "cd-play";
-    event = "cd/play.*";
-    action = ''
-      #! ${pkgs.bash}/bin/sh
-      ${config.services.acpid.cdPlayEventCommands}
-    '';
-  };
-
-  cdNextEvent = {
-    name = "cd-next";
-    event = "cd/next.*";
-    action = ''
-      #! ${pkgs.bash}/bin/sh
-      ${config.services.acpid.cdNextEventCommands}
-    '';
-  };
-
-  cdPrevEvent = {
-    name = "cd-prev";
-    event = "cd/prev.*";
-    action = ''
-      #! ${pkgs.bash}/bin/sh
-      ${config.services.acpid.cdPrevEventCommands}
+  acpiConfDir = pkgs.runCommand "acpi-events" {}
+    ''
+      mkdir -p $out
+      ${
+        # Generate a configuration file for each event. (You can't have
+        # multiple events in one config file...)
+        let f = name: handler:
+          ''
+            fn=$out/${name}
+            echo "event=${handler.event}" > $fn
+            echo "action=${pkgs.writeScript "${name}.sh" (concatStringsSep "\n" [ "#! ${pkgs.bash}/bin/sh" handler.action ])}" >> $fn
+          '';
+        in concatStringsSep "\n" (mapAttrsToList f (canonicalHandlers // config.services.acpid.handlers))
+      }
     '';
-  };
-
 
 in
 
@@ -126,58 +53,45 @@ in
         description = "Whether to enable the ACPI daemon.";
       };
 
-      powerEventCommands = mkOption {
-        type = types.lines;
-        default = "";
-        description = "Shell commands to execute on a button/power.* event.";
-      };
+      handlers = mkOption {
+        type = types.attrsOf (types.submodule {
+          options = {
+            event = mkOption {
+              type = types.str;
+              example = [ "button/power.*" "button/lid.*" "ac_adapter.*" "button/mute.*" "button/volumedown.*" "cd/play.*" "cd/next.*" ];
+              description = "Event type.";
+            };
 
-      lidEventCommands = mkOption {
-        type = types.lines;
-        default = "";
-        description = "Shell commands to execute on a button/lid.* event.";
-      };
+            action = mkOption {
+              type = types.lines;
+              description = "Shell commands to execute when the event is triggered.";
+            };
+          };
+        });
 
-      acEventCommands = mkOption {
-        type = types.lines;
-        default = "";
-        description = "Shell commands to execute on an ac_adapter.* event.";
-      };
-
-      muteCommands = mkOption {
-        type = types.lines;
-        default = "";
-        description = "Shell commands to execute on an button/mute.* event.";
-      };
+        description = "Event handlers.";
+        default = {};
+        example = { mute = { event = "button/mute.*"; action = "amixer set Master toggle"; }; };
 
-      volumeDownEventCommands = mkOption {
-        type = types.lines;
-        default = "";
-        description = "Shell commands to execute on an button/volumedown.* event.";
-      };
 
-      volumeUpEventCommands = mkOption {
-        type = types.lines;
-        default = "";
-        description = "Shell commands to execute on an button/volumeup.* event.";
       };
 
-      cdPlayEventCommands = mkOption {
+      powerEventCommands = mkOption {
         type = types.lines;
         default = "";
-        description = "Shell commands to execute on an cd/play.* event.";
+        description = "Shell commands to execute on a button/power.* event.";
       };
 
-      cdNextEventCommands = mkOption {
+      lidEventCommands = mkOption {
         type = types.lines;
         default = "";
-        description = "Shell commands to execute on an cd/next.* event.";
+        description = "Shell commands to execute on a button/lid.* event.";
       };
 
-      cdPrevEventCommands = mkOption {
+      acEventCommands = mkOption {
         type = types.lines;
         default = "";
-        description = "Shell commands to execute on an cd/prev.* event.";
+        description = "Shell commands to execute on an ac_adapter.* event.";
       };
 
     };
diff --git a/nixos/modules/services/hardware/bluetooth.nix b/nixos/modules/services/hardware/bluetooth.nix
index 68d0406e63bd..fc95c4910bf7 100644
--- a/nixos/modules/services/hardware/bluetooth.nix
+++ b/nixos/modules/services/hardware/bluetooth.nix
@@ -1,6 +1,43 @@
 { config, lib, pkgs, ... }:
 
 with lib;
+let
+    bluez-bluetooth = if config.services.xserver.desktopManager.kde4.enable then pkgs.bluez else pkgs.bluez5;
+
+    configBluez = {
+        description = "Bluetooth Service";
+        serviceConfig = {
+          Type = "dbus";
+          BusName = "org.bluez";
+          ExecStart = "${bluez-bluetooth}/sbin/bluetoothd -n";
+        };
+        wantedBy = [ "bluetooth.target" ];
+    };
+
+    configBluez5 =  {
+        description = "Bluetooth Service";
+        serviceConfig = {
+          Type = "dbus";
+          BusName = "org.bluez";
+          ExecStart = "${bluez-bluetooth}/sbin/bluetoothd -n";
+          NotifyAccess="main";
+          CapabilityBoundingSet="CAP_NET_ADMIN CAP_NET_BIND_SERVICE";
+          LimitNPROC=1;
+        };
+        wantedBy = [ "bluetooth.target" ];
+    };
+
+    obexConfig = {
+        description = "Bluetooth OBEX service";
+        serviceConfig = {
+          Type = "dbus";
+          BusName = "org.bluez.obex";
+          ExecStart = "${bluez-bluetooth}/sbin/obexd";
+        };
+    };
+
+    bluezConfig = if config.services.xserver.desktopManager.kde4.enable then configBluez else configBluez5;
+in
 
 {
 
@@ -16,26 +53,15 @@ with lib;
 
   };
 
-
   ###### implementation
-
+  
   config = mkIf config.hardware.bluetooth.enable {
 
-    environment.systemPackages = [ pkgs.bluez pkgs.openobex pkgs.obexftp ];
-
-    services.udev.packages = [ pkgs.bluez ];
-
-    services.dbus.packages = [ pkgs.bluez ];
-
-    systemd.services."dbus-org.bluez" = {
-      description = "Bluetooth Service";
-      serviceConfig = {
-        Type = "dbus";
-        BusName = "org.bluez";
-        ExecStart = "${pkgs.bluez}/sbin/bluetoothd -n";
-      };
-      wantedBy = [ "bluetooth.target" ];
-    };
+    environment.systemPackages = [ bluez-bluetooth pkgs.openobex pkgs.obexftp ];
+    services.udev.packages = [ bluez-bluetooth ];
+    services.dbus.packages = [ bluez-bluetooth ];
+    systemd.services."dbus-org.bluez" = bluezConfig;
+    systemd.services."dbus-org.bluez.obex" = obexConfig;
 
   };
 
diff --git a/nixos/modules/services/hardware/udev.nix b/nixos/modules/services/hardware/udev.nix
index 107e1012b88d..369a50bd6a85 100644
--- a/nixos/modules/services/hardware/udev.nix
+++ b/nixos/modules/services/hardware/udev.nix
@@ -16,6 +16,12 @@ let
     destination = "/etc/udev/rules.d/10-local.rules";
   };
 
+  extraHwdbFile = pkgs.writeTextFile {
+    name = "extra-hwdb-file";
+    text = cfg.extraHwdb;
+    destination = "/etc/udev/hwdb.d/10-local.hwdb";
+  };
+
   nixosRules = ''
     # Miscellaneous devices.
     KERNEL=="kvm",                  MODE="0666"
@@ -55,7 +61,9 @@ let
           --replace \"/sbin/modprobe \"${config.system.sbin.modprobe}/sbin/modprobe \
           --replace \"/sbin/mdadm \"${pkgs.mdadm}/sbin/mdadm \
           --replace \"/sbin/blkid \"${pkgs.utillinux}/sbin/blkid \
-          --replace \"/bin/mount \"${pkgs.utillinux}/bin/mount
+          --replace \"/bin/mount \"${pkgs.utillinux}/bin/mount \
+          --replace /usr/bin/readlink ${pkgs.coreutils}/bin/readlink \
+          --replace /usr/bin/basename ${pkgs.coreutils}/bin/basename
       done
 
       echo -n "Checking that all programs called by relative paths in udev rules exist in ${udev}/lib/udev... "
@@ -86,10 +94,30 @@ let
       done
       echo "OK"
 
-      echo "Consider fixing the following udev rules:"
-      for i in ${toString cfg.packages}; do
-        grep -l '\(RUN+\|IMPORT{program}\)="\(/usr\)\?/s\?bin' $i/*/udev/rules.d/* || true
-      done
+      filesToFixup="$(for i in "$out"/*; do
+        grep -l '\B\(/usr\)\?/s\?bin' "$i" || :
+      done)"
+
+      if [ -n "$filesToFixup" ]; then
+        echo "Consider fixing the following udev rules:"
+        echo "$filesToFixup" | while read localFile; do
+          remoteFile="origin unknown"
+          for i in ${toString cfg.packages}; do
+            for j in "$i"/*/udev/rules.d/*; do
+              [ -e "$out/$(basename "$j")" ] || continue
+              [ "$(basename "$j")" = "$(basename "$localFile")" ] || continue
+              remoteFile="originally from $j"
+              break 2
+            done
+          done
+          refs="$(
+            grep -o '\B\(/usr\)\?/s\?bin/[^ "]\+' "$localFile" \
+              | sed -e ':r;N;''${s/\n/ and /;br};s/\n/, /g;br'
+          )"
+          echo "$localFile ($remoteFile) contains references to $refs."
+        done
+        exit 1
+      fi
 
       ${optionalString config.networking.usePredictableInterfaceNames ''
         cp ${./80-net-setup-link.rules} $out/80-net-setup-link.rules
@@ -104,6 +132,27 @@ let
     ''; # */
   };
 
+  hwdbBin = stdenv.mkDerivation {
+    name = "hwdb.bin";
+
+    preferLocalBuild = true;
+    allowSubstitutes = false;
+
+    buildCommand = ''
+      mkdir -p etc/udev/hwdb.d
+      for i in ${toString ([udev] ++ cfg.packages)}; do
+        echo "Adding hwdb files for package $i"
+        for j in $i/{etc,lib}/udev/hwdb.d/*; do
+          ln -s $j etc/udev/hwdb.d/$(basename $j)
+        done
+      done
+
+      echo "Generating hwdb database..."
+      ${udev}/bin/udevadm hwdb --update --root=$(pwd)
+      mv etc/udev/hwdb.bin $out
+    '';
+  };
+
   # Udev has a 512-character limit for ENV{PATH}, so create a symlink
   # tree to work around this.
   udevPath = pkgs.buildEnv {
@@ -168,6 +217,21 @@ in
         '';
       };
 
+      extraHwdb = mkOption {
+        default = "";
+        example = ''
+          evdev:input:b0003v05AFp8277*
+            KEYBOARD_KEY_70039=leftalt
+            KEYBOARD_KEY_700e2=leftctrl
+        '';
+        type = types.lines;
+        description = ''
+          Additional <command>hwdb</command> files. They'll be written
+          into file <filename>10-local.hwdb</filename>. Thus they are
+          read before all other files.
+        '';
+      };
+
     };
 
     hardware.firmware = mkOption {
@@ -216,7 +280,7 @@ in
 
     services.udev.extraRules = nixosRules;
 
-    services.udev.packages = [ extraUdevRules ];
+    services.udev.packages = [ extraUdevRules extraHwdbFile ];
 
     services.udev.path = [ pkgs.coreutils pkgs.gnused pkgs.gnugrep pkgs.utillinux udev ];
 
@@ -224,6 +288,9 @@ in
       [ { source = udevRules;
           target = "udev/rules.d";
         }
+        { source = hwdbBin;
+          target = "udev/hwdb.bin";
+        }
       ];
 
     system.requiredKernelConfig = with config.lib.kernelConfig; [
@@ -241,13 +308,6 @@ in
           echo "" > /proc/sys/kernel/hotplug
         fi
 
-        # Regenerate the hardware database /var/lib/udev/hwdb.bin
-        # whenever systemd changes.
-        if [ ! -e /var/lib/udev/prev-systemd -o "$(readlink /var/lib/udev/prev-systemd)" != ${config.systemd.package} ]; then
-          echo "regenerating udev hardware database..."
-          ${config.systemd.package}/bin/udevadm hwdb --update && ln -sfn ${config.systemd.package} /var/lib/udev/prev-systemd
-        fi
-
         # Allow the kernel to find our firmware.
         if [ -e /sys/module/firmware_class/parameters/path ]; then
           echo -n "${config.hardware.firmware}/lib/firmware" > /sys/module/firmware_class/parameters/path
@@ -256,6 +316,7 @@ in
 
     systemd.services.systemd-udevd =
       { environment.MODULE_DIR = "/run/booted-system/kernel-modules/lib/modules";
+        restartTriggers = cfg.packages;
       };
 
   };
diff --git a/nixos/modules/services/logging/logstash.nix b/nixos/modules/services/logging/logstash.nix
index e019e6c3f237..d27456e59e88 100644
--- a/nixos/modules/services/logging/logstash.nix
+++ b/nixos/modules/services/logging/logstash.nix
@@ -85,7 +85,7 @@ in
         type = types.lines;
         default = ''stdin { type => "example" }'';
         description = "Logstash input configuration.";
-        example = ''
+        example = literalExample ''
           # Read from journal
           pipe {
             command => "''${pkgs.systemd}/bin/journalctl -f -o json"
@@ -98,7 +98,7 @@ in
         type = types.lines;
         default = ''noop {}'';
         description = "logstash filter configuration.";
-        example = ''
+        example = literalExample ''
           if [type] == "syslog" {
             # Keep only relevant systemd fields
             # http://www.freedesktop.org/software/systemd/man/systemd.journal-fields.html
@@ -114,7 +114,7 @@ in
 
       outputConfig = mkOption {
         type = types.lines;
-        default = ''stdout { debug => true debug_format => "json"}'';
+        default = literalExample ''stdout { debug => true debug_format => "json"}'';
         description = "Logstash output configuration.";
         example = ''
           redis { host => "localhost" data_type => "list" key => "logstash" codec => json }
diff --git a/nixos/modules/services/mail/dovecot.nix b/nixos/modules/services/mail/dovecot.nix
index 11e8b26c75ef..333a03315bca 100644
--- a/nixos/modules/services/mail/dovecot.nix
+++ b/nixos/modules/services/mail/dovecot.nix
@@ -13,6 +13,7 @@ let
     ''
       base_dir = ${baseDir}
       protocols = ${concatStringsSep " " cfg.protocols}
+      sendmail_path = /var/setuid-wrappers/sendmail
     ''
 
     (if isNull cfg.sslServerCert then ''
diff --git a/nixos/modules/services/mail/dspam.nix b/nixos/modules/services/mail/dspam.nix
index 10352ba6abcc..2d8aebe20575 100644
--- a/nixos/modules/services/mail/dspam.nix
+++ b/nixos/modules/services/mail/dspam.nix
@@ -109,6 +109,9 @@ in {
           Group = cfg.group;
           RuntimeDirectory = optional (cfg.domainSocket == defaultSock) "dspam";
           PermissionsStartOnly = true;
+          # DSPAM segfaults on just about every error
+          Restart = "on-failure";
+          RestartSec = "1s";
         };
 
         preStart = ''
@@ -136,7 +139,7 @@ in {
         restartTriggers = [ cfgfile ];
 
         serviceConfig = {
-          ExecStart = "${dspam}/bin/dspam_maintenance";
+          ExecStart = "${dspam}/bin/dspam_maintenance --verbose";
           Type = "oneshot";
           User = cfg.user;
           Group = cfg.group;
diff --git a/nixos/modules/services/mail/opensmtpd.nix b/nixos/modules/services/mail/opensmtpd.nix
index a1cfd84365a2..42a1244cde57 100644
--- a/nixos/modules/services/mail/opensmtpd.nix
+++ b/nixos/modules/services/mail/opensmtpd.nix
@@ -9,6 +9,11 @@ let
   conf = writeText "smtpd.conf" cfg.serverConfiguration;
   args = concatStringsSep " " cfg.extraServerArgs;
 
+  sendmail = pkgs.runCommand "opensmtpd-sendmail" {} ''
+    mkdir -p $out/bin
+    ln -s ${opensmtpd}/sbin/smtpctl $out/bin/sendmail
+  '';
+
 in {
 
   ###### interface
@@ -23,6 +28,15 @@ in {
         description = "Whether to enable the OpenSMTPD server.";
       };
 
+      addSendmailToSystemPath = mkOption {
+        type = types.bool;
+        default = true;
+        description = ''
+          Whether to add OpenSMTPD's sendmail binary to the
+          system path or not.
+        '';
+      };
+
       extraServerArgs = mkOption {
         type = types.listOf types.str;
         default = [];
@@ -64,7 +78,7 @@ in {
 
   ###### implementation
 
-  config = mkIf config.services.opensmtpd.enable {
+  config = mkIf cfg.enable {
     users.extraGroups = {
       smtpd.gid = config.ids.gids.smtpd;
       smtpq.gid = config.ids.gids.smtpq;
@@ -98,9 +112,6 @@ in {
       environment.OPENSMTPD_PROC_PATH = "${procEnv}/libexec/opensmtpd";
     };
 
-    environment.systemPackages = [ (pkgs.runCommand "opensmtpd-sendmail" {} ''
-      mkdir -p $out/bin
-      ln -s ${opensmtpd}/sbin/smtpctl $out/bin/sendmail
-    '') ];
+    environment.systemPackages = mkIf cfg.addSendmailToSystemPath [ sendmail ];
   };
 }
diff --git a/nixos/modules/services/mail/postfix.nix b/nixos/modules/services/mail/postfix.nix
index f2d8189de6ef..404cdf0f564b 100644
--- a/nixos/modules/services/mail/postfix.nix
+++ b/nixos/modules/services/mail/postfix.nix
@@ -13,6 +13,18 @@ let
   haveTransport = cfg.transport != "";
   haveVirtual = cfg.virtual != "";
 
+  clientAccess =
+    if (cfg.dnsBlacklistOverrides != "")
+    then [ "check_client_access hash:/etc/postfix/client_access" ]
+    else [];
+
+  dnsBl =
+    if (cfg.dnsBlacklists != [])
+    then [ (concatStringsSep ", " (map (s: "reject_rbl_client " + s) cfg.dnsBlacklists)) ]
+    else [];
+
+  clientRestrictions = concatStringsSep ", " (clientAccess ++ dnsBl);
+
   mainCf =
     ''
       compatibility_level = 2
@@ -104,6 +116,9 @@ let
     + optionalString haveVirtual ''
       virtual_alias_maps = hash:/etc/postfix/virtual
     ''
+    + optionalString (cfg.dnsBlacklists != []) ''
+      smtpd_client_restrictions = ${clientRestrictions}
+    ''
     + cfg.extraConfig;
 
   masterCf = ''
@@ -161,6 +176,7 @@ let
 
   aliasesFile = pkgs.writeText "postfix-aliases" aliases;
   virtualFile = pkgs.writeText "postfix-virtual" cfg.virtual;
+  checkClientAccessFile = pkgs.writeText "postfix-check-client-access" cfg.dnsBlacklistOverrides;
   mainCfFile = pkgs.writeText "postfix-main.cf" mainCf;
   masterCfFile = pkgs.writeText "postfix-master.cf" masterCf;
   transportFile = pkgs.writeText "postfix-transport" cfg.transport;
@@ -366,6 +382,17 @@ in
         ";
       };
 
+      dnsBlacklists = mkOption {
+        default = [];
+        type = with types; listOf string;
+        description = "dns blacklist servers to use with smtpd_client_restrictions";
+      };
+
+      dnsBlacklistOverrides = mkOption {
+        default = "";
+        description = "contents of check_client_access for overriding dnsBlacklists";
+      };
+
       extraMasterConf = mkOption {
         type = types.lines;
         default = "";
@@ -461,7 +488,7 @@ in
             rm -rf /var/lib/postfix/conf
             mkdir -p /var/lib/postfix/conf
             chmod 0755 /var/lib/postfix/conf
-            ln -sf ${pkgs.postfix}/etc/postfix/postfix-files
+            ln -sf ${pkgs.postfix}/etc/postfix/postfix-files /var/lib/postfix/conf/postfix-files
             ln -sf ${mainCfFile} /var/lib/postfix/conf/main.cf
             ln -sf ${masterCfFile} /var/lib/postfix/conf/master.cf
 
@@ -494,6 +521,9 @@ in
     (mkIf haveVirtual {
       services.postfix.mapFiles."virtual" = virtualFile;
     })
+    (mkIf (cfg.dnsBlacklists != []) {
+      services.postfix.mapFiles."client_access" = checkClientAccessFile;
+    })
   ]);
 
 }
diff --git a/nixos/modules/services/mail/postsrsd.nix b/nixos/modules/services/mail/postsrsd.nix
index 36a0f8218d88..68a4c1012064 100644
--- a/nixos/modules/services/mail/postsrsd.nix
+++ b/nixos/modules/services/mail/postsrsd.nix
@@ -95,7 +95,11 @@ in {
       preStart = ''
         if [ ! -e "${cfg.secretsFile}" ]; then
           echo "WARNING: secrets file not found, autogenerating!"
-          mkdir -p -m750 "$(dirname "${cfg.secretsFile}")"
+          DIR="$(dirname "${cfg.secretsFile}")"
+          if [ ! -d "$DIR" ]; then
+            mkdir -p -m750 "$DIR"
+            chown "${cfg.user}:${cfg.group}" "$DIR"
+          fi
           dd if=/dev/random bs=18 count=1 | base64 > "${cfg.secretsFile}"
           chmod 600 "${cfg.secretsFile}"
         fi
diff --git a/nixos/modules/services/misc/gitit.nix b/nixos/modules/services/misc/gitit.nix
index ab4d385ba165..befd8c628f16 100644
--- a/nixos/modules/services/misc/gitit.nix
+++ b/nixos/modules/services/misc/gitit.nix
@@ -35,7 +35,6 @@ let
       };
 
       haskellPackages = mkOption {
-        type = types.attrsOf types.package;
         default = pkgs.haskellPackages;
         defaultText = "pkgs.haskellPackages";
         example = literalExample "pkgs.haskell.packages.ghc784";
diff --git a/nixos/modules/services/misc/sundtek.nix b/nixos/modules/services/misc/sundtek.nix
index 8438ef79904f..e3234518c940 100644
--- a/nixos/modules/services/misc/sundtek.nix
+++ b/nixos/modules/services/misc/sundtek.nix
@@ -23,7 +23,7 @@ in
         Type = "oneshot";
         ExecStart = ''
           ${pkgs.sundtek}/bin/mediasrv -d -v -p ${pkgs.sundtek}/bin ;\
-          ${pkgs.sundtek}/bin/mediaclient --start=5 --wait-for-devices
+          ${pkgs.sundtek}/bin/mediaclient --start --wait-for-devices
           '';
         ExecStop = "${pkgs.sundtek}/bin/mediaclient --shutdown";
         RemainAfterExit = true;
diff --git a/nixos/modules/services/networking/connman.nix b/nixos/modules/services/networking/connman.nix
index deb1cbfc1858..3fecfbb13a04 100644
--- a/nixos/modules/services/networking/connman.nix
+++ b/nixos/modules/services/networking/connman.nix
@@ -53,13 +53,13 @@ in {
   config = mkIf cfg.enable {
 
     assertions = [{
-      assertion = config.networking.useDHCP == false;
+      assertion = !config.networking.useDHCP;
       message = "You can not use services.networking.connman with services.networking.useDHCP";
     }{
-      assertion = config.networking.wireless.enable == true;
+      assertion = config.networking.wireless.enable;
       message = "You must use services.networking.connman with services.networking.wireless";
     }{
-      assertion = config.networking.networkmanager.enable == false;
+      assertion = !config.networking.networkmanager.enable;
       message = "You can not use services.networking.connman with services.networking.networkmanager";
     }];
 
diff --git a/nixos/modules/services/networking/i2pd.nix b/nixos/modules/services/networking/i2pd.nix
index c467402dbcf6..c32b935cf940 100644
--- a/nixos/modules/services/networking/i2pd.nix
+++ b/nixos/modules/services/networking/i2pd.nix
@@ -12,21 +12,69 @@ let
 
   toOneZero = b: if b then "1" else "0";
 
+  mkEndpointOpt = name: addr: port: {
+    name = mkOption {
+      type = types.str;
+      default = name;
+      description = "The endpoint name.";
+    };
+    address = mkOption {
+      type = types.str;
+      default = addr;
+      description = "Bind address for ${name} endpoint. Default: " + addr;
+    };
+    port = mkOption {
+      type = types.int;
+      default = port;
+      description = "Bind port for ${name} endoint. Default: " + toString port;
+    };
+  };
+
+  commonTunOpts = let
+    i2cpOpts = {
+      length = mkOption {
+        type = types.int;
+        description = "Guaranteed minimum hops.";
+        default = 3;
+      };
+      quantity = mkOption {
+        type = types.int;
+        description = "Number of simultaneous tunnels.";
+        default = 5;
+      };
+    };
+  in name: {
+    outbound = i2cpOpts;
+    inbound = i2cpOpts;
+    crypto.tagsToSend = mkOption {
+      type = types.int;
+      description = "Number of ElGamal/AES tags to send.";
+      default = 40;
+    };
+   destination = mkOption {
+      type = types.str;
+      description = "Remote endpoint, I2P hostname or b32.i2p address.";
+    };
+    keys = mkOption {
+      type = types.str;
+      default = name + "-keys.dat";
+      description = "Keyset used for tunnel identity.";
+    };
+  } // mkEndpointOpt name "127.0.0.1" 0;
+
   i2pdConf = pkgs.writeText "i2pd.conf" ''
-      v6 = ${toOneZero cfg.enableIPv6}
-      unreachable = ${toOneZero cfg.unreachable}
+      ipv6 = ${toOneZero cfg.enableIPv6}
+      notransit = ${toOneZero cfg.notransit}
       floodfill = ${toOneZero cfg.floodfill}
       ${if isNull cfg.port then "" else "port = ${toString cfg.port}"}
-      httpproxyport = ${toString cfg.proxy.httpPort}
-      socksproxyport = ${toString cfg.proxy.socksPort}
-      ircaddress = ${cfg.irc.host}
-      ircport = ${toString cfg.irc.port}
-      ircdest = ${cfg.irc.dest}
-      irckeys = ${cfg.irc.keyFile}
-      eepport = ${toString cfg.eep.port}
-      ${if isNull cfg.sam.port then "" else "--samport=${toString cfg.sam.port}"}
-      eephost = ${cfg.eep.host}
-      eepkeys = ${cfg.eep.keyFile}
+      ${flip concatMapStrings
+        (collect (proto: proto ? port && proto ? address && proto ? name) cfg.proto)
+        (proto: let portStr = toString proto.port; in ''
+      [${proto.name}]
+      address = ${proto.address}
+      port = ${toString proto.port}
+      '')
+      }
   '';
 
   i2pdTunnelConf = pkgs.writeText "i2pd-tunnels.conf" ''
@@ -39,10 +87,15 @@ let
   keys = ${tun.keys}
   address = ${tun.address}
   port = ${toString tun.port}
+  inbound.length = ${toString tun.inbound.length}
+  outbound.length = ${toString tun.outbound.length}
+  inbound.quantity = ${toString tun.inbound.quantity}
+  outbound.quantity = ${toString tun.outbound.quantity}
+  crypto.tagsToSend = ${toString tun.crypto.tagsToSend}
   '')
   }
   ${flip concatMapStrings
-    (collect (tun: tun ? port && tun ? host) cfg.outTunnels)
+    (collect (tun: tun ? port && tun ? host) cfg.inTunnels)
     (tun: let portStr = toString tun.port; in ''
   [${tun.name}]
   type = server
@@ -59,10 +112,10 @@ let
   i2pdSh = pkgs.writeScriptBin "i2pd" ''
     #!/bin/sh
     ${if isNull cfg.extIp then extip else ""}
-    ${pkgs.i2pd}/bin/i2pd --log=1 --daemon=0 --service=0 \
+    ${pkgs.i2pd}/bin/i2pd --log=1 \
       --host=${if isNull cfg.extIp then "$EXTIP" else cfg.extIp} \
       --conf=${i2pdConf} \
-      --tunnelscfg=${i2pdTunnelConf}
+      --tunconf=${i2pdTunnelConf}
   '';
 
 in
@@ -91,11 +144,11 @@ in
         '';
       };
 
-      unreachable = mkOption {
+      notransit = mkOption {
         type = types.bool;
         default = false;
         description = ''
-          If the router is declared to be unreachable and needs introduction nodes.
+          Tells the router to not accept transit tunnels during startup.
         '';
       };
 
@@ -111,7 +164,7 @@ in
         type = with types; nullOr int;
         default = null;
         description = ''
-	        I2P listen port. If no one is given the router will pick between 9111 and 30777.
+          I2P listen port. If no one is given the router will pick between 9111 and 30777.
         '';
       };
 
@@ -123,184 +176,53 @@ in
         '';
       };
 
-      http = {
-        port = mkOption {
-          type = types.int;
-          default = 7070;
-          description = ''
-            HTTP listen port.
-          '';
-        };
-      };
-
-      proxy = {
-        httpPort = mkOption {
-          type = types.int;
-          default = 4446;
-          description = ''
-            HTTP proxy listen port.
-          '';
-        };
-        socksPort = mkOption {
-          type = types.int;
-          default = 4447;
-          description = ''
-            SOCKS proxy listen port.
-          '';
-        };
-      };
-
-      irc = {
-        host = mkOption {
-          type = types.str;
-          default = "127.0.0.1";
-          description = ''
-            Address to forward incoming traffic to. 127.0.0.1 by default.
-          '';
-        };
-        dest = mkOption {
-          type = types.str;
-          default = "irc.postman.i2p";
-          description = ''
-            Destination I2P tunnel endpoint address of IRC server. irc.postman.i2p by default.
-          '';
-        };
-        port = mkOption {
-          type = types.int;
-          default = 6668;
-          description = ''
-            Local IRC tunnel endoint port to listen on. 6668 by default.
-          '';
-        };
-        keyFile = mkOption {
-          type = types.str;
-          default = "privKeys.dat";
-          description = ''
-            File name containing destination keys. privKeys.dat by default.
-          '';
-        };
-      };
-
-      eep = {
-        host = mkOption {
-          type = types.str;
-          default = "127.0.0.1";
-          description = ''
-            Address to forward incoming traffic to. 127.0.0.1 by default.
-          '';
-        };
-        port = mkOption {
-          type = types.int;
-          default = 80;
-          description = ''
-            Port to forward incoming traffic to. 80 by default.
-          '';
-        };
-        keyFile = mkOption {
-          type = types.str;
-          default = "privKeys.dat";
-          description = ''
-            File name containing destination keys. privKeys.dat by default.
-          '';
-        };
-      };
-
-      sam = {
-        port = mkOption {
-          type = with types; nullOr int;
-          default = null;
-          description = ''
-            Local SAM tunnel endpoint. Usually 7656. SAM is disabled if not specified.
-          '';
-        };
-      };
+      proto.http = mkEndpointOpt "http" "127.0.0.1" 7070;
+      proto.sam = mkEndpointOpt "sam" "127.0.0.1" 7656;
+      proto.bob = mkEndpointOpt "bob" "127.0.0.1" 2827;
+      proto.i2pControl = mkEndpointOpt "i2pcontrol" "127.0.0.1" 7650;
+      proto.httpProxy = mkEndpointOpt "httpproxy" "127.0.0.1" 4446;
+      proto.socksProxy = mkEndpointOpt "socksproxy" "127.0.0.1" 4447;
 
       outTunnels = mkOption {
         default = {};
-	      type = with types; loaOf optionSet;
-	      description = ''
-	      '';
-	      options = [ ({ name, config, ... }: {
-
-	        options = {
-	          name = mkOption {
-	            type = types.str;
-	            description = "The name of the tunnel.";
-	          };
-	          destination = mkOption {
-	            type = types.str;
-	            description = "Remote endpoint, I2P hostname or b32.i2p address.";
-	          };
-	          keys = mkOption {
-	            type = types.str;
-	            default = name + "-keys.dat";
-	            description = "Keyset used for tunnel identity.";
-	          };
-	          address = mkOption {
-	            type = types.str;
-	            default = "127.0.0.1";
-	            description = "Local bind address for tunnel.";
-	          };
-	          port = mkOption {
-	            type = types.int;
-	            default = 0;
-	            description = "Local tunnel listen port.";
-	          };
-	        };
-
-	        config = {
-	          name = mkDefault name;
-	        };
-
-	      }) ];
+        type = with types; loaOf optionSet;
+        description = ''
+          Connect to someone as a client and establish a local accept endpoint
+        '';
+        options = [ ({ name, config, ... }: {
+          options = commonTunOpts name;
+          config = {
+            name = mkDefault name;
+          };
+        }) ];
       };
 
       inTunnels = mkOption {
         default = {};
-	      type = with types; loaOf optionSet;
-	      description = ''
-	      '';
-	      options = [ ({ name, config, ... }: {
-
-	        options = {
-
-	          name = mkOption {
-	            type = types.str;
-	            description = "The name of the tunnel.";
-	          };
-	          keys = mkOption {
-	            type = types.path;
-	            default = name + "-keys.dat";
-	            description = "Keyset used for tunnel identity.";
-	          };
-	          address = mkOption {
-	            type = types.str;
-	            default = "127.0.0.1";
-	            description = "Local service IP address.";
-	          };
-	          port = mkOption {
-	            type = types.int;
-	            default = 0;
-	            description = "Local tunnel listen port.";
-	          };
-	          inPort = mkOption {
-	            type = types.int;
-	            default = 0;
-	            description = "I2P service port. Default to the tunnel's listen port.";
-	          };
-	          accessList = mkOption {
-	            type = with types; listOf str;
-	            default = [];
-	            description = "I2P nodes that are allowed to connect to this service.";
-	          };
-
-	        };
-
-	        config = {
-	          name = mkDefault name;
-	        };
-
-	      }) ];
+        type = with types; loaOf optionSet;
+        description = ''
+          Serve something on I2P network at port and delegate requests to address inPort.
+        '';
+        options = [ ({ name, config, ... }: {
+
+          options = {
+            inPort = mkOption {
+              type = types.int;
+              default = 0;
+              description = "Service port. Default to the tunnel's listen port.";
+            };
+            accessList = mkOption {
+              type = with types; listOf str;
+              default = [];
+              description = "I2P nodes that are allowed to connect to this service.";
+            };
+          } // commonTunOpts name;
+
+          config = {
+            name = mkDefault name;
+          };
+
+        }) ];
       };
     };
   };
diff --git a/nixos/modules/services/networking/ssh/sshd.nix b/nixos/modules/services/networking/ssh/sshd.nix
index 5baea4bc6aea..ba3efc8c0c2a 100644
--- a/nixos/modules/services/networking/ssh/sshd.nix
+++ b/nixos/modules/services/networking/ssh/sshd.nix
@@ -52,6 +52,8 @@ let
     ));
   in listToAttrs (map mkAuthKeyFile usersWithKeys);
 
+  supportOldHostKeys = !versionAtLeast config.system.stateVersion "15.07";
+
 in
 
 {
@@ -177,7 +179,7 @@ in
         default =
           [ { type = "rsa"; bits = 4096; path = "/etc/ssh/ssh_host_rsa_key"; }
             { type = "ed25519"; path = "/etc/ssh/ssh_host_ed25519_key"; }
-          ] ++ optionals (!versionAtLeast config.system.stateVersion "15.07")
+          ] ++ optionals supportOldHostKeys
           [ { type = "dsa"; path = "/etc/ssh/ssh_host_dsa_key"; }
             { type = "ecdsa"; bits = 521; path = "/etc/ssh/ssh_host_ecdsa_key"; }
           ];
@@ -347,6 +349,15 @@ in
         ${flip concatMapStrings cfg.hostKeys (k: ''
           HostKey ${k.path}
         '')}
+
+        # Allow DSA client keys for now. (These were deprecated
+        # in OpenSSH 7.0.)
+        PubkeyAcceptedKeyTypes +ssh-dss
+
+        # Re-enable DSA host keys for now.
+        ${optionalString supportOldHostKeys ''
+          HostKeyAlgorithms +ssh-dss
+        ''}
       '';
 
     assertions = [{ assertion = if cfg.forwardX11 then cfgc.setXAuthLocation else true;
diff --git a/nixos/modules/services/networking/tinc.nix b/nixos/modules/services/networking/tinc.nix
index 34f4f6b37b60..9330e6c92ba8 100644
--- a/nixos/modules/services/networking/tinc.nix
+++ b/nixos/modules/services/networking/tinc.nix
@@ -95,6 +95,16 @@ in
             '';
           };
 
+          chroot = mkOption {
+            default = true;
+            type = types.bool;
+            description = ''
+              Change process root directory to the directory where the config file is located (/etc/tinc/netname/), for added security.
+              The chroot is performed after all the initialization is done, after writing pid files and opening network sockets.
+
+              Note that tinc can't run scripts anymore (such as tinc-down or host-up), unless it is setup to be runnable inside chroot environment.
+            '';
+          };
         };
       };
     };
@@ -166,7 +176,7 @@ in
           fi
         '';
         script = ''
-          tincd -D -U tinc.${network} -n ${network} --pidfile /run/tinc.${network}.pid -d ${toString data.debugLevel}
+          tincd -D -U tinc.${network} -n ${network} ${optionalString (data.chroot) "-R"} --pidfile /run/tinc.${network}.pid -d ${toString data.debugLevel}
         '';
       })
     );
diff --git a/nixos/modules/services/networking/unifi.nix b/nixos/modules/services/networking/unifi.nix
index be8f12ecd32d..4dc0cd96904c 100644
--- a/nixos/modules/services/networking/unifi.nix
+++ b/nixos/modules/services/networking/unifi.nix
@@ -61,6 +61,8 @@ in
       partOf = systemdMountPoints;
       bindsTo = systemdMountPoints;
       unitConfig.RequiresMountsFor = stateDir;
+      # This a HACK to fix missing dependencies of dynamic libs extracted from jars
+      environment.LD_LIBRARY_PATH = with pkgs.stdenv; "${cc.cc}/lib";
 
       preStart = ''
         # Ensure privacy of state
diff --git a/nixos/modules/services/networking/wpa_supplicant.nix b/nixos/modules/services/networking/wpa_supplicant.nix
index 1b655af6c82d..1558c5832892 100644
--- a/nixos/modules/services/networking/wpa_supplicant.nix
+++ b/nixos/modules/services/networking/wpa_supplicant.nix
@@ -8,11 +8,15 @@ let
     ${optionalString cfg.userControlled.enable ''
       ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=${cfg.userControlled.group}
       update_config=1''}
-    ${concatStringsSep "\n" (mapAttrsToList (ssid: networkConfig: ''
+    ${concatStringsSep "\n" (mapAttrsToList (ssid: networkConfig: let
+      psk = if networkConfig.psk != null
+        then ''"${networkConfig.psk}"''
+        else networkConfig.pskRaw;
+    in ''
       network={
         ssid="${ssid}"
-        ${optionalString (networkConfig.psk != null) ''psk="${networkConfig.psk}"''}
-        ${optionalString (networkConfig.psk == null) ''key_mgmt=NONE''}
+        ${optionalString (psk != null) ''psk=${psk}''}
+        ${optionalString (psk == null) ''key_mgmt=NONE''}
       }
     '') cfg.networks)}
   '' else "/etc/wpa_supplicant.conf";
@@ -49,6 +53,19 @@ in {
 
                 Be aware that these will be written to the nix store
                 in plaintext!
+
+                Mutually exclusive with <varname>pskRaw</varname>.
+              '';
+            };
+
+            pskRaw = mkOption {
+              type = types.nullOr types.str;
+              default = null;
+              description = ''
+                The network's pre-shared key in hex defaulting
+                to being a network without any authentication.
+
+                Mutually exclusive with <varname>psk</varname>.
               '';
             };
           };
@@ -95,6 +112,11 @@ in {
 
   config = mkMerge [
     (mkIf cfg.enable {
+      assertions = flip mapAttrsToList cfg.networks (name: cfg: {
+        assertion = cfg.psk == null || cfg.pskRaw == null;
+        message = ''networking.wireless."${name}".psk and networking.wireless."${name}".pskRaw are mutually exclusive'';
+      });
+
       environment.systemPackages =  [ pkgs.wpa_supplicant ];
 
       services.dbus.packages = [ pkgs.wpa_supplicant ];
diff --git a/nixos/modules/services/search/elasticsearch.nix b/nixos/modules/services/search/elasticsearch.nix
index 478ebcfb9664..c51a42b8e9c1 100644
--- a/nixos/modules/services/search/elasticsearch.nix
+++ b/nixos/modules/services/search/elasticsearch.nix
@@ -9,6 +9,8 @@ let
     network.host: ${cfg.listenAddress}
     network.port: ${toString cfg.port}
     network.tcp.port: ${toString cfg.tcp_port}
+    # TODO: find a way to enable security manager
+    security.manager.enabled: false
     cluster.name: ${cfg.cluster_name}
     ${cfg.extraConf}
   '';
@@ -39,8 +41,8 @@ in {
 
     package = mkOption {
       description = "Elasticsearch package to use.";
-      default = pkgs.elasticsearch;
-      defaultText = "pkgs.elasticsearch";
+      default = pkgs.elasticsearch2;
+      defaultText = "pkgs.elasticsearch2";
       type = types.package;
     };
 
@@ -129,7 +131,9 @@ in {
       wantedBy = [ "multi-user.target" ];
       after = [ "network-interfaces.target" ];
       path = [ pkgs.inetutils ];
-      environment = { ES_HOME = cfg.dataDir; };
+      environment = {
+        ES_HOME = cfg.dataDir;
+      };
       serviceConfig = {
         ExecStart = "${cfg.package}/bin/elasticsearch -Des.path.conf=${configDir} ${toString cfg.extraCmdLineOptions}";
         User = "elasticsearch";
@@ -137,10 +141,11 @@ in {
       };
       preStart = ''
         mkdir -m 0700 -p ${cfg.dataDir}
-        if [ "$(id -u)" = 0 ]; then chown -R elasticsearch ${cfg.dataDir}; fi
 
         # Install plugins
         ln -sfT ${esPlugins}/plugins ${cfg.dataDir}/plugins
+        ln -sfT ${cfg.package}/lib ${cfg.dataDir}/lib
+        if [ "$(id -u)" = 0 ]; then chown -R elasticsearch ${cfg.dataDir}; fi
       '';
       postStart = mkBefore ''
         until ${pkgs.curl.bin}/bin/curl -s -o /dev/null ${cfg.listenAddress}:${toString cfg.port}; do
diff --git a/nixos/modules/services/search/kibana.nix b/nixos/modules/services/search/kibana.nix
index 4263ed22a8db..033b8139d341 100644
--- a/nixos/modules/services/search/kibana.nix
+++ b/nixos/modules/services/search/kibana.nix
@@ -7,37 +7,33 @@ let
 
   cfgFile = pkgs.writeText "kibana.json" (builtins.toJSON (
     (filterAttrsRecursive (n: v: v != null) ({
-      server = {
-        host = cfg.listenAddress;
-        port = cfg.port;
-        ssl = {
-          cert = cfg.cert;
-          key = cfg.key;
-        };
-      };
-
-      kibana = {
-        index = cfg.index;
-        defaultAppId = cfg.defaultAppId;
-      };
-
-      elasticsearch = {
-        url = cfg.elasticsearch.url;
-        username = cfg.elasticsearch.username;
-        password = cfg.elasticsearch.password;
-        ssl = {
-          cert = cfg.elasticsearch.cert;
-          key = cfg.elasticsearch.key;
-          ca = cfg.elasticsearch.ca;
-        };
-      };
-
-      logging = {
-        verbose = cfg.logLevel == "verbose";
-        quiet = cfg.logLevel == "quiet";
-        silent = cfg.logLevel == "silent";
-        dest = "stdout";
-      };
+      host = cfg.listenAddress;
+      port = cfg.port;
+      ssl_cert_file = cfg.cert;
+      ssl_key_file = cfg.key;
+
+      kibana_index = cfg.index;
+      default_app_id = cfg.defaultAppId;
+
+      elasticsearch_url = cfg.elasticsearch.url;
+      kibana_elasticsearch_username = cfg.elasticsearch.username;
+      kibana_elasticsearch_password = cfg.elasticsearch.password;
+      kibana_elasticsearch_cert = cfg.elasticsearch.cert;
+      kibana_elasticsearch_key = cfg.elasticsearch.key;
+      ca = cfg.elasticsearch.ca;
+
+      bundled_plugin_ids = [
+        "plugins/dashboard/index"
+        "plugins/discover/index"
+        "plugins/doc/index"
+        "plugins/kibana/index"
+        "plugins/markdown_vis/index"
+        "plugins/metric_vis/index"
+        "plugins/settings/index"
+        "plugins/table_vis/index"
+        "plugins/vis_types/index"
+        "plugins/visualize/index"
+      ];
     } // cfg.extraConf)
   )));
 in {
@@ -118,12 +114,6 @@ in {
       };
     };
 
-    logLevel = mkOption {
-      description = "Kibana log level";
-      default = "normal";
-      type = types.enum ["verbose" "normal" "silent" "quiet"];
-    };
-
     package = mkOption {
       description = "Kibana package to use";
       default = pkgs.kibana;
@@ -149,6 +139,7 @@ in {
       description = "Kibana Service";
       wantedBy = [ "multi-user.target" ];
       after = [ "network-interfaces.target" "elasticsearch.service" ];
+      environment = { BABEL_CACHE_PATH = "${cfg.dataDir}/.babelcache.json"; };
       serviceConfig = {
         ExecStart = "${cfg.package}/bin/kibana --config ${cfgFile}";
         User = "kibana";
diff --git a/nixos/modules/services/security/haka.nix b/nixos/modules/services/security/haka.nix
new file mode 100644
index 000000000000..4f2bdd29cc49
--- /dev/null
+++ b/nixos/modules/services/security/haka.nix
@@ -0,0 +1,156 @@
+# This module defines global configuration for Haka.
+
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.haka;
+
+  haka = cfg.package;
+
+  hakaConf = pkgs.writeText "haka.conf"
+  ''
+    [general]
+    configuration = ${if lib.strings.hasPrefix "/" cfg.configFile
+      then "${cfg.configFile}"
+      else "${haka}/share/haka/sample/${cfg.configFile}"}
+    ${optionalString (builtins.lessThan 0 cfg.threads) "thread = ${cfg.threads}"}
+
+    [packet]
+    ${optionalString cfg.pcap ''module = "packet/pcap"''}
+    ${optionalString cfg.nfqueue ''module = "packet/nqueue"''}
+    ${optionalString cfg.dump.enable ''dump = "yes"''}
+    ${optionalString cfg.dump.enable ''dump_input = "${cfg.dump.input}"''}
+    ${optionalString cfg.dump.enable ''dump_output = "${cfg.dump.output}"''}
+
+    interfaces = "${lib.strings.concatStringsSep "," cfg.interfaces}"
+
+    [log]
+    # Select the log module
+    module = "log/syslog"
+
+    # Set the default logging level
+    #level = "info,packet=debug"
+
+    [alert]
+    # Select the alert module
+    module = "alert/syslog"
+
+    # Disable alert on standard output
+    #alert_on_stdout = no
+
+    # alert/file module option
+    #file = "/dev/null"
+  '';
+
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    services.haka = {
+
+      enable = mkEnableOption "Haka";
+
+      package = mkOption {
+        default = pkgs.haka;
+        type = types.package;
+        description = "
+          Which Haka derivation to use.
+        ";
+      };
+
+      configFile = mkOption {
+        default = "empty.lua";
+        example = "/srv/haka/myfilter.lua";
+        type = types.string;
+        description = ''
+          Specify which configuration file Haka uses.
+          It can be absolute path or a path relative to the sample directory of
+          the haka git repo.
+        '';
+      };
+
+      interfaces = mkOption {
+        default = [ "eth0" ];
+        example = [ "any" ];
+        type = with types; listOf string;
+        description = ''
+          Specify which interface(s) Haka listens to.
+          Use 'any' to listen to all interfaces.
+        '';
+      };
+
+      threads = mkOption {
+        default = 0;
+        example = 4;
+        type = types.int;
+        description = ''
+          The number of threads that will be used.
+          All system threads are used by default.
+        '';
+      };
+
+      pcap = mkOption {
+        default = true;
+        example = false;
+        type = types.bool;
+        description = "Whether to enable pcap";
+      };
+
+      nfqueue = mkEnableOption "nfqueue";
+
+      dump.enable = mkEnableOption "dump";
+      dump.input  = mkOption {
+        default = "/tmp/input.pcap";
+        example = "/path/to/file.pcap";
+        type = types.path;
+        description = "Path to file where incoming packets are dumped";
+      };
+
+      dump.output  = mkOption {
+        default = "/tmp/output.pcap";
+        example = "/path/to/file.pcap";
+        type = types.path;
+        description = "Path to file where outgoing packets are dumped";
+      };
+    };
+  };
+
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    assertions = [
+      { assertion = cfg.pcap != cfg.nfqueue;
+        message = "either pcap or nfqueue can be enabled, not both.";
+      }
+      { assertion = cfg.nfqueue -> !dump.enable;
+        message = "dump can only be used with nfqueue.";
+      }
+      { assertion = cfg.interfaces != [];
+        message = "at least one interface must be specified.";
+      }];
+
+
+    environment.systemPackages = [ haka ];
+
+    systemd.services.haka = {
+      description = "Haka";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" ];
+      serviceConfig = {
+        ExecStart = "${haka}/bin/haka -c ${hakaConf}";
+        ExecStop = "${haka}/bin/hakactl stop";
+        User = "root";
+        Type = "forking";
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/web-servers/apache-httpd/mediawiki.nix b/nixos/modules/services/web-servers/apache-httpd/mediawiki.nix
index 52d8c89baff2..0fe8d1a89cf3 100644
--- a/nixos/modules/services/web-servers/apache-httpd/mediawiki.nix
+++ b/nixos/modules/services/web-servers/apache-httpd/mediawiki.nix
@@ -83,11 +83,11 @@ let
 
   # Unpack Mediawiki and put the config file in its root directory.
   mediawikiRoot = pkgs.stdenv.mkDerivation rec {
-    name= "mediawiki-1.23.9";
+    name= "mediawiki-1.23.13";
 
     src = pkgs.fetchurl {
       url = "http://download.wikimedia.org/mediawiki/1.23/${name}.tar.gz";
-      sha256 = "1l7k4g0pgz92yvrfr52w26x740s4362v0gc95pk0i30vn2sp5bql";
+      sha256 = "168wpf53n4ksj2g5q5r0hxapx6238dvsfng5ff9ixk6axsn0j5d0";
     };
 
     skins = config.skins;
diff --git a/nixos/modules/services/x11/desktop-managers/default.nix b/nixos/modules/services/x11/desktop-managers/default.nix
index 998bcd354c53..3e91450a39d2 100644
--- a/nixos/modules/services/x11/desktop-managers/default.nix
+++ b/nixos/modules/services/x11/desktop-managers/default.nix
@@ -64,7 +64,13 @@ in
           else if any (w: w.name == defaultDM) cfg.session.list then
             defaultDM
           else
-            throw "Default desktop manager ($(defaultDM)) not found.";
+            throw ''
+              Default desktop manager (${defaultDM}) not found.
+              Probably you want to change
+                services.xserver.desktopManager.default = "${defaultDM}";
+              to one of
+                ${concatMapStringsSep "\n  " (w: "services.xserver.desktopManager.default = \"${w.name}\";") cfg.session.list}
+            '';
       };
 
     };
diff --git a/nixos/modules/services/x11/desktop-managers/gnome3.nix b/nixos/modules/services/x11/desktop-managers/gnome3.nix
index 55d7fd80cf97..6cb4f3acba8d 100644
--- a/nixos/modules/services/x11/desktop-managers/gnome3.nix
+++ b/nixos/modules/services/x11/desktop-managers/gnome3.nix
@@ -64,7 +64,7 @@ in {
     environment.gnome3.packageSet = mkOption {
       type = types.nullOr types.package;
       default = null;
-      example = literalExample "pkgs.gnome3_16";
+      example = literalExample "pkgs.gnome3_18";
       description = "Which GNOME 3 package set to use.";
       apply = p: if p == null then pkgs.gnome3 else p;
     };
diff --git a/nixos/modules/services/x11/desktop-managers/kde4.nix b/nixos/modules/services/x11/desktop-managers/kde4.nix
index 29cca248cde3..80e408be4923 100644
--- a/nixos/modules/services/x11/desktop-managers/kde4.nix
+++ b/nixos/modules/services/x11/desktop-managers/kde4.nix
@@ -108,6 +108,12 @@ in
                 sed -e '/nix\\store\|nix\/store/ d' -i $HOME/.config/Trolltech.conf
             fi
 
+            # Load PulseAudio module for routing support.
+            # See http://colin.guthr.ie/2009/10/so-how-does-the-kde-pulseaudio-support-work-anyway/
+            ${optionalString config.hardware.pulseaudio.enable ''
+              ${config.hardware.pulseaudio.package}/bin/pactl load-module module-device-manager "do_routing=1"
+            ''}
+
             # Start KDE.
             exec ${kde_workspace}/bin/startkde
           '';
diff --git a/nixos/modules/services/x11/desktop-managers/kde5.nix b/nixos/modules/services/x11/desktop-managers/kde5.nix
index 4b238938d927..62e483ae7061 100644
--- a/nixos/modules/services/x11/desktop-managers/kde5.nix
+++ b/nixos/modules/services/x11/desktop-managers/kde5.nix
@@ -55,7 +55,15 @@ in
     services.xserver.desktopManager.session = singleton {
       name = "kde5";
       bgSupport = true;
-      start = ''exec startkde;'';
+      start = ''
+        # Load PulseAudio module for routing support.
+        # See http://colin.guthr.ie/2009/10/so-how-does-the-kde-pulseaudio-support-work-anyway/
+        ${optionalString config.hardware.pulseaudio.enable ''
+          ${config.hardware.pulseaudio.package}/bin/pactl load-module module-device-manager "do_routing=1"
+        ''}
+
+        exec startkde
+      '';
     };
 
     security.setuidOwners = singleton {
diff --git a/nixos/modules/services/x11/display-managers/default.nix b/nixos/modules/services/x11/display-managers/default.nix
index 3437d8f38930..b93e7db46003 100644
--- a/nixos/modules/services/x11/display-managers/default.nix
+++ b/nixos/modules/services/x11/display-managers/default.nix
@@ -83,9 +83,6 @@ let
 
         # Publish access credentials in the root window.
         ${config.hardware.pulseaudio.package.out}/bin/pactl load-module module-x11-publish "display=$DISPLAY"
-
-        # Keep track of devices.  Mostly useful for Phonon/KDE.
-        ${config.hardware.pulseaudio.package.out}/bin/pactl load-module module-device-manager "do_routing=1"
       ''}
 
       # Tell systemd about our $DISPLAY. This is needed by the
diff --git a/nixos/modules/services/x11/display-managers/lightdm.nix b/nixos/modules/services/x11/display-managers/lightdm.nix
index 9460395f86d6..3949bf01a316 100644
--- a/nixos/modules/services/x11/display-managers/lightdm.nix
+++ b/nixos/modules/services/x11/display-managers/lightdm.nix
@@ -86,7 +86,7 @@ in
       };
 
       background = mkOption {
-        type = types.path;
+        type = types.str;
         description = ''
           The background image or color to use.
         '';
diff --git a/nixos/modules/services/x11/hardware/synaptics.nix b/nixos/modules/services/x11/hardware/synaptics.nix
index e50ed08a218a..2981e7545e81 100644
--- a/nixos/modules/services/x11/hardware/synaptics.nix
+++ b/nixos/modules/services/x11/hardware/synaptics.nix
@@ -62,6 +62,13 @@ in {
         description = "Cursor speed factor for highest-speed finger motion.";
       };
 
+      scrollDelta = mkOption {
+        type = types.nullOr types.int;
+        default = null;
+        example = 75;
+        description = "Move distance of the finger for a scroll event.";
+      };
+
       twoFingerScroll = mkOption {
         type = types.bool;
         default = false;
@@ -122,6 +129,20 @@ in {
         description = "Whether to enable palm detection (hardware support required)";
       };
 
+      palmMinWidth = mkOption {
+        type = types.nullOr types.int;
+        default = null;
+        example = 5;
+        description = "Minimum finger width at which touch is considered a palm";
+      };
+
+      palmMinZ = mkOption {
+        type = types.nullOr types.int;
+        default = null;
+        example = 20;
+        description = "Minimum finger pressure at which touch is considered a palm";
+      };
+
       horizontalScroll = mkOption {
         type = types.bool;
         default = true;
@@ -174,8 +195,12 @@ in {
           Option "HorizTwoFingerScroll" "${if cfg.horizTwoFingerScroll then "1" else "0"}"
           Option "VertEdgeScroll" "${if cfg.vertEdgeScroll then "1" else "0"}"
           Option "HorizEdgeScroll" "${if cfg.horizEdgeScroll then "1" else "0"}"
-          ${if cfg.palmDetect then ''Option "PalmDetect" "1"'' else ""}
-          ${if cfg.horizontalScroll then "" else ''Option "HorizScrollDelta" "0"''}
+          ${optionalString cfg.palmDetect ''Option "PalmDetect" "1"''}
+          ${optionalString (cfg.palmMinWidth != null) ''Option "PalmMinWidth" "${toString cfg.palmMinWidth}"''}
+          ${optionalString (cfg.palmMinZ != null) ''Option "PalmMinZ" "${toString cfg.palmMinZ}"''}
+          ${optionalString (cfg.scrollDelta != null) ''Option "VertScrollDelta" "${toString cfg.scrollDelta}"''}
+          ${if !cfg.horizontalScroll then ''Option "HorizScrollDelta" "0"''
+            else (optionalString (cfg.scrollDelta != null) ''Option "HorizScrollDelta" "${toString cfg.scrollDelta}"'')}
           ${cfg.additionalOptions}
         EndSection
       '';
diff --git a/nixos/modules/services/x11/window-managers/i3.nix b/nixos/modules/services/x11/window-managers/i3.nix
index d43dacb1be6b..2e2e10cc33b0 100644
--- a/nixos/modules/services/x11/window-managers/i3.nix
+++ b/nixos/modules/services/x11/window-managers/i3.nix
@@ -34,6 +34,6 @@ in
         '';
       }];
     };
-    environment.systemPackages = with pkgs; [ i3 i3status dmenu ];
+    environment.systemPackages = with pkgs; [ i3 ];
   };
 }