about summary refs log tree commit diff
path: root/nixos
diff options
context:
space:
mode:
Diffstat (limited to 'nixos')
-rw-r--r--nixos/doc/manual/administration/declarative-containers.xml6
-rw-r--r--nixos/doc/manual/configuration/config-file.xml2
-rw-r--r--nixos/doc/manual/configuration/network-manager.xml6
-rw-r--r--nixos/doc/manual/man-nixos-rebuild.xml23
-rw-r--r--nixos/modules/config/nsswitch.nix7
-rw-r--r--nixos/modules/config/update-users-groups.pl10
-rw-r--r--nixos/modules/config/users-groups.nix1
-rw-r--r--nixos/modules/hardware/video/nvidia.nix9
-rw-r--r--nixos/modules/installer/tools/nixos-rebuild.sh11
-rw-r--r--nixos/modules/misc/ids.nix11
-rw-r--r--nixos/modules/module-list.nix5
-rw-r--r--nixos/modules/programs/ssh.nix25
-rw-r--r--nixos/modules/programs/uim.nix4
-rw-r--r--nixos/modules/rename.nix3
-rw-r--r--nixos/modules/security/grsecurity.nix3
-rw-r--r--nixos/modules/security/pam.nix43
-rw-r--r--nixos/modules/services/audio/mpd.nix29
-rw-r--r--nixos/modules/services/backup/tarsnap.nix176
-rw-r--r--nixos/modules/services/databases/couchdb.nix9
-rw-r--r--nixos/modules/services/databases/mongodb.nix1
-rw-r--r--nixos/modules/services/databases/redis.nix4
-rw-r--r--nixos/modules/services/misc/disnix.nix2
-rw-r--r--nixos/modules/services/misc/nix-daemon.nix6
-rw-r--r--nixos/modules/services/network-filesystems/samba.nix2
-rw-r--r--nixos/modules/services/network-filesystems/u9fs.nix75
-rw-r--r--nixos/modules/services/networking/consul.nix7
-rw-r--r--nixos/modules/services/networking/dnsmasq.nix2
-rw-r--r--nixos/modules/services/networking/networkmanager.nix37
-rw-r--r--nixos/modules/services/networking/ssh/sshd.nix8
-rw-r--r--nixos/modules/services/security/fail2ban.nix2
-rw-r--r--nixos/modules/services/torrent/transmission.nix22
-rw-r--r--nixos/modules/services/web-servers/apache-httpd/default.nix3
-rw-r--r--nixos/modules/services/web-servers/fcgiwrap.nix51
-rw-r--r--nixos/modules/services/x11/display-managers/default.nix12
-rw-r--r--nixos/modules/services/x11/display-managers/gdm.nix23
-rw-r--r--nixos/modules/services/x11/display-managers/kdm.nix2
-rw-r--r--nixos/modules/services/x11/display-managers/lightdm.nix55
-rw-r--r--nixos/modules/services/x11/display-managers/sddm.nix110
-rw-r--r--nixos/modules/services/x11/hardware/multitouch.nix44
-rw-r--r--nixos/modules/services/x11/unclutter.nix33
-rw-r--r--nixos/modules/services/x11/window-managers/default.nix2
-rw-r--r--nixos/modules/system/activation/switch-to-configuration.pl145
-rw-r--r--nixos/modules/system/boot/loader/generations-dir/generations-dir.nix2
-rw-r--r--nixos/modules/system/boot/loader/grub/grub.nix1
-rw-r--r--nixos/modules/system/boot/loader/init-script/init-script.nix1
-rw-r--r--nixos/modules/system/boot/loader/raspberrypi/raspberrypi.nix1
-rw-r--r--nixos/modules/system/boot/stage-1-init.sh10
-rw-r--r--nixos/modules/tasks/kbd.nix1
-rw-r--r--nixos/modules/tasks/network-interfaces-systemd.nix5
-rw-r--r--nixos/modules/virtualisation/containers.nix17
-rw-r--r--nixos/modules/virtualisation/google-compute-image.nix10
-rw-r--r--nixos/modules/virtualisation/lxc.nix11
-rw-r--r--nixos/modules/virtualisation/nixos-container.pl5
-rw-r--r--nixos/modules/virtualisation/xen-dom0.nix261
-rw-r--r--nixos/modules/virtualisation/xen-domU.nix5
-rw-r--r--nixos/release.nix3
-rw-r--r--nixos/tests/i3wm.nix28
57 files changed, 1056 insertions, 336 deletions
diff --git a/nixos/doc/manual/administration/declarative-containers.xml b/nixos/doc/manual/administration/declarative-containers.xml
index 177ebdd8db175..228c45b0c1fec 100644
--- a/nixos/doc/manual/administration/declarative-containers.xml
+++ b/nixos/doc/manual/administration/declarative-containers.xml
@@ -49,4 +49,8 @@ on container networking.)</para>
 switch</literal>. Note that this will not delete the root directory of
 the container in <literal>/var/lib/containers</literal>.</para>
 
-</section>
\ No newline at end of file
+<para>Declarative containers can be started and stopped using the
+corresponding systemd service, e.g. <literal>systemctl start
+container@database</literal>.</para>
+
+</section>
diff --git a/nixos/doc/manual/configuration/config-file.xml b/nixos/doc/manual/configuration/config-file.xml
index 2a58ff25941c1..b613c7f06cc89 100644
--- a/nixos/doc/manual/configuration/config-file.xml
+++ b/nixos/doc/manual/configuration/config-file.xml
@@ -68,7 +68,7 @@ instance, if you try to define an option that doesn’t exist (that is,
 doesn’t have a corresponding <emphasis>option declaration</emphasis>),
 <command>nixos-rebuild</command> will give an error like:
 <screen>
-The option `services.httpd.enabl' defined in `/etc/nixos/configuration.nix' does not exist.
+The option `services.httpd.enable' defined in `/etc/nixos/configuration.nix' does not exist.
 </screen>
 Likewise, values in option definitions must have a correct type.  For
 instance, <option>services.httpd.enable</option> must be a Boolean
diff --git a/nixos/doc/manual/configuration/network-manager.xml b/nixos/doc/manual/configuration/network-manager.xml
index ceac40b7a1f66..b7e47b8729f32 100644
--- a/nixos/doc/manual/configuration/network-manager.xml
+++ b/nixos/doc/manual/configuration/network-manager.xml
@@ -10,7 +10,7 @@
 use NetworkManager. You can enable NetworkManager by setting:
 
 <programlisting>
-services.networkmanager.enable = true;
+networking.networkmanager.enable = true;
 </programlisting>
 
 some desktop managers (e.g., GNOME) enable NetworkManager
@@ -19,8 +19,8 @@ automatically for you.</para>
 <para>All users that should have permission to change network settings
 must belong to the <code>networkmanager</code> group.</para>
 
-<note><para><code>services.networkmanager</code> and
-<code>services.wireless</code> can not be enabled at the same time:
+<note><para><code>networking.networkmanager</code> and
+<code>networking.wireless</code> can not be enabled at the same time:
 you can still connect to the wireless networks using
 NetworkManager.</para></note>
 
diff --git a/nixos/doc/manual/man-nixos-rebuild.xml b/nixos/doc/manual/man-nixos-rebuild.xml
index afc159dbd5d76..c529737c3bf3d 100644
--- a/nixos/doc/manual/man-nixos-rebuild.xml
+++ b/nixos/doc/manual/man-nixos-rebuild.xml
@@ -1,7 +1,7 @@
 <refentry xmlns="http://docbook.org/ns/docbook"
           xmlns:xlink="http://www.w3.org/1999/xlink"
           xmlns:xi="http://www.w3.org/2001/XInclude">
-  
+
 <refmeta>
   <refentrytitle><command>nixos-rebuild</command></refentrytitle>
   <manvolnum>8</manvolnum>
@@ -22,7 +22,8 @@
       <arg choice='plain'><option>boot</option></arg>
       <arg choice='plain'><option>test</option></arg>
       <arg choice='plain'><option>build</option></arg>
-      <arg choice='plain'><option>dry-run</option></arg>
+      <arg choice='plain'><option>dry-build</option></arg>
+      <arg choice='plain'><option>dry-activate</option></arg>
       <arg choice='plain'><option>build-vm</option></arg>
       <arg choice='plain'><option>build-vm-with-bootloader</option></arg>
     </group>
@@ -114,10 +115,22 @@ $ nix-build /path/to/nixpkgs/nixos -A system
   </varlistentry>
 
   <varlistentry>
-    <term><option>dry-run</option></term>
+    <term><option>dry-build</option></term>
+    <listitem>
+      <para>Show what store paths would be built or downloaded by any
+      of the operations above, but otherwise do nothing.</para>
+    </listitem>
+  </varlistentry>
+
+  <varlistentry>
+    <term><option>dry-activate</option></term>
     <listitem>
-      <para>Simply show what store paths would be built or downloaded
-      by any of the operations above.</para>
+      <para>Build the new configuration, but instead of activating it,
+      show what changes would be performed by the activation (i.e. by
+      <command>nixos-rebuild test</command>). For
+      instance, this command will print which systemd units would be
+      restarted. The list of changes is not guaranteed to be
+      complete.</para>
     </listitem>
   </varlistentry>
 
diff --git a/nixos/modules/config/nsswitch.nix b/nixos/modules/config/nsswitch.nix
index 549e731f3b08a..a39c2895bf84d 100644
--- a/nixos/modules/config/nsswitch.nix
+++ b/nixos/modules/config/nsswitch.nix
@@ -8,6 +8,7 @@ let
 
   inherit (config.services.avahi) nssmdns;
   inherit (config.services.samba) nsswins;
+  ldap = config.users.ldap.enable;
 
 in
 
@@ -40,9 +41,9 @@ in
     # should define an option used by this module.
     environment.etc."nsswitch.conf".text =
       ''
-        passwd:    files ldap
-        group:     files ldap
-        shadow:    files ldap
+        passwd:    files ${optionalString ldap "ldap"}
+        group:     files ${optionalString ldap "ldap"}
+        shadow:    files ${optionalString ldap "ldap"}
         hosts:     files ${optionalString nssmdns "mdns_minimal [NOTFOUND=return]"} dns ${optionalString nssmdns "mdns"} ${optionalString nsswins "wins"} myhostname mymachines
         networks:  files dns
         ethers:    files
diff --git a/nixos/modules/config/update-users-groups.pl b/nixos/modules/config/update-users-groups.pl
index d35ecb754bdb0..de73de91629b0 100644
--- a/nixos/modules/config/update-users-groups.pl
+++ b/nixos/modules/config/update-users-groups.pl
@@ -174,12 +174,12 @@ foreach my $u (@{$spec->{users}}) {
         } elsif (defined $u->{initialHashedPassword}) {
             $u->{hashedPassword} = $u->{initialHashedPassword};
         }
+    }
 
-        # Create a home directory.
-        if ($u->{createHome}) {
-            make_path($u->{home}, { mode => 0700 }) if ! -e $u->{home};
-            chown $u->{uid}, $u->{gid}, $u->{home};
-        }
+    # Create a home directory.
+    if ($u->{createHome} && ! -e $u->{home}) {
+        make_path($u->{home}, { mode => 0700 }) if ! -e $u->{home};
+        chown $u->{uid}, $u->{gid}, $u->{home};
     }
 
     if (defined $u->{passwordFile}) {
diff --git a/nixos/modules/config/users-groups.nix b/nixos/modules/config/users-groups.nix
index f585a27747994..db87f9fd0b1a5 100644
--- a/nixos/modules/config/users-groups.nix
+++ b/nixos/modules/config/users-groups.nix
@@ -489,6 +489,7 @@ in {
       utmp.gid = ids.gids.utmp;
       adm.gid = ids.gids.adm;
       grsecurity.gid = ids.gids.grsecurity;
+      input.gid = ids.gids.input;
     };
 
     system.activationScripts.users = stringAfter [ "etc" ]
diff --git a/nixos/modules/hardware/video/nvidia.nix b/nixos/modules/hardware/video/nvidia.nix
index 2b20dc7395af9..209310bec9991 100644
--- a/nixos/modules/hardware/video/nvidia.nix
+++ b/nixos/modules/hardware/video/nvidia.nix
@@ -47,6 +47,15 @@ in
 
     boot.extraModulePackages = [ nvidia_x11 ];
 
+    # nvidia-uvm is required by CUDA applications.
+    boot.kernelModules = [ "nvidia-uvm" ];
+
+    # Create /dev/nvidia-uvm when the nvidia-uvm module is loaded.
+    services.udev.extraRules =
+      ''
+        KERNEL=="nvidia_uvm", RUN+="${pkgs.stdenv.shell} -c 'mknod -m 666 /dev/nvidia-uvm c $(grep nvidia-uvm /proc/devices | cut -d \  -f 1) 0'"
+      '';
+
     boot.blacklistedKernelModules = [ "nouveau" "nvidiafb" ];
 
     services.acpid.enable = true;
diff --git a/nixos/modules/installer/tools/nixos-rebuild.sh b/nixos/modules/installer/tools/nixos-rebuild.sh
index 8157f8fc7da5d..1d6df8cb3f71a 100644
--- a/nixos/modules/installer/tools/nixos-rebuild.sh
+++ b/nixos/modules/installer/tools/nixos-rebuild.sh
@@ -26,7 +26,8 @@ while [ "$#" -gt 0 ]; do
       --help)
         showSyntax
         ;;
-      switch|boot|test|build|dry-run|build-vm|build-vm-with-bootloader)
+      switch|boot|test|build|dry-build|dry-run|dry-activate|build-vm|build-vm-with-bootloader)
+        if [ "$i" = dry-run ]; then i=dry-build; fi
         action="$i"
         ;;
       --install-grub)
@@ -137,7 +138,7 @@ fi
 
 # First build Nix, since NixOS may require a newer version than the
 # current one.
-if [ -n "$rollback" -o "$action" = dry-run ]; then
+if [ -n "$rollback" -o "$action" = dry-build ]; then
     buildNix=
 fi
 
@@ -180,7 +181,7 @@ if [ -n "$canRun" ]; then
 fi
 
 
-if [ "$action" = dry-run ]; then
+if [ "$action" = dry-build ]; then
     extraBuildFlags+=(--dry-run)
 fi
 
@@ -193,7 +194,7 @@ if [ -z "$rollback" ]; then
     if [ "$action" = switch -o "$action" = boot ]; then
         nix-env "${extraBuildFlags[@]}" -p "$profile" -f '<nixpkgs/nixos>' --set -A system
         pathToConfig="$profile"
-    elif [ "$action" = test -o "$action" = build -o "$action" = dry-run ]; then
+    elif [ "$action" = test -o "$action" = build -o "$action" = dry-build -o "$action" = dry-activate ]; then
         nix-build '<nixpkgs/nixos>' -A system -k "${extraBuildFlags[@]}" > /dev/null
         pathToConfig=./result
     elif [ "$action" = build-vm ]; then
@@ -224,7 +225,7 @@ fi
 
 # If we're not just building, then make the new configuration the boot
 # default and/or activate it now.
-if [ "$action" = switch -o "$action" = boot -o "$action" = test ]; then
+if [ "$action" = switch -o "$action" = boot -o "$action" = test -o "$action" = dry-activate ]; then
     if ! $pathToConfig/bin/switch-to-configuration "$action"; then
         echo "warning: error(s) occured while switching to the new configuration" >&2
         exit 1
diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix
index 0c863ec8de1cc..158609dcf7931 100644
--- a/nixos/modules/misc/ids.nix
+++ b/nixos/modules/misc/ids.nix
@@ -180,6 +180,7 @@
       panamax = 170;
       marathon = 171;
       exim = 172;
+      sddm = 175;
 
       # When adding a uid, make sure it doesn't match an existing gid. And don't use uids above 399!
 
@@ -301,8 +302,6 @@
       mlmmj = 135;
       riemann = 137;
       riemanndash = 138;
-      hbase = 139;
-      opentsdb = 140;
       uhub = 142;
       mailpile = 146;
       redmine = 147;
@@ -313,14 +312,18 @@
       systemd-resolve = 153;
       systemd-timesync = 154;
       liquidsoap = 155;
-      fleet = 159;
+      hbase = 158;
+      opentsdb = 159;
       scollector = 160;
       bosun = 161;
       kubernetes = 162;
       gitlab = 165;
-      nylon = 166;
+      nylon = 168;
       panamax = 170;
       exim = 172;
+      fleet = 173;
+      input = 174;
+      sddm = 175;
 
       # When adding a gid, make sure it doesn't match an existing
       # uid. Users and groups with the same name should have equal
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index c41ae69c1ace6..de86f11c6bbe0 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -228,6 +228,7 @@
   ./services/network-filesystems/rsyncd.nix
   ./services/network-filesystems/samba.nix
   ./services/network-filesystems/diod.nix
+  ./services/network-filesystems/u9fs.nix
   ./services/network-filesystems/yandex-disk.nix
   ./services/networking/amuled.nix
   ./services/networking/atftpd.nix
@@ -352,12 +353,14 @@
   ./services/web-servers/varnish/default.nix
   ./services/web-servers/winstone.nix
   ./services/web-servers/zope2.nix
+  ./services/x11/unclutter.nix
   ./services/x11/desktop-managers/default.nix
   ./services/x11/display-managers/auto.nix
   ./services/x11/display-managers/default.nix
   ./services/x11/display-managers/gdm.nix
   ./services/x11/display-managers/kdm.nix
   ./services/x11/display-managers/lightdm.nix
+  ./services/x11/display-managers/sddm.nix
   ./services/x11/display-managers/slim.nix
   ./services/x11/hardware/multitouch.nix
   ./services/x11/hardware/synaptics.nix
@@ -432,5 +435,5 @@
   ./virtualisation/openvswitch.nix
   ./virtualisation/parallels-guest.nix
   ./virtualisation/virtualbox-guest.nix
-  #./virtualisation/xen-dom0.nix
+  ./virtualisation/xen-dom0.nix
 ]
diff --git a/nixos/modules/programs/ssh.nix b/nixos/modules/programs/ssh.nix
index 796740ea636ac..bd9b897158dc1 100644
--- a/nixos/modules/programs/ssh.nix
+++ b/nixos/modules/programs/ssh.nix
@@ -4,8 +4,19 @@
 
 with lib;
 
-let cfg  = config.programs.ssh;
-    cfgd = config.services.openssh;
+let
+
+  cfg  = config.programs.ssh;
+  cfgd = config.services.openssh;
+
+  askPassword = "${pkgs.x11_ssh_askpass}/libexec/x11-ssh-askpass";
+
+  askPasswordWrapper = pkgs.writeScript "ssh-askpass-wrapper"
+    ''
+      #! ${pkgs.stdenv.shell} -e
+      export DISPLAY="$(systemctl --user show-environment | ${pkgs.gnused}/bin/sed 's/^DISPLAY=\(.*\)/\1/; t; d')"
+      exec ${askPassword}
+    '';
 
 in
 {
@@ -117,6 +128,11 @@ in
             Restart = "on-failure";
             SuccessExitStatus = "0 2";
           };
+        # Allow ssh-agent to ask for confirmation. This requires the
+        # unit to know about the user's $DISPLAY (via ‘systemctl
+        # import-environment’).
+        environment.SSH_ASKPASS = optionalString config.services.xserver.enable askPasswordWrapper;
+        environment.DISPLAY = "fake"; # required to make ssh-agent start $SSH_ASKPASS
       };
 
     environment.extraInit = optionalString cfg.startAgent
@@ -126,5 +142,10 @@ in
         fi
       '';
 
+    environment.interactiveShellInit = optionalString config.services.xserver.enable
+      ''
+        export SSH_ASKPASS=${askPassword}
+      '';
+
   };
 }
diff --git a/nixos/modules/programs/uim.nix b/nixos/modules/programs/uim.nix
index fc25ba6f9694c..4bf2f9a175716 100644
--- a/nixos/modules/programs/uim.nix
+++ b/nixos/modules/programs/uim.nix
@@ -7,14 +7,16 @@ let
 in
 {
   options = {
+
     uim = {
       enable = mkOption {
         type = types.bool;
         default = false;
         example = true;
-        description = "enable UIM input method";
+        description = "Enable UIM input method";
       };
     };
+
   };
 
   config = mkIf cfg.enable {
diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix
index 1efc278aeb224..e820b2cb9ce48 100644
--- a/nixos/modules/rename.nix
+++ b/nixos/modules/rename.nix
@@ -112,6 +112,9 @@ in zipModules ([]
 # VirtualBox
 ++ obsolete [ "services" "virtualbox" "enable" ] [ "services" "virtualboxGuest" "enable" ]
 
+# Tarsnap
+++ obsolete [ "services" "tarsnap" "config" ] [ "services" "tarsnap" "archives" ]
+
 # proxy
 ++ obsolete [ "nix" "proxy" ] [ "networking" "proxy" "default" ]
 
diff --git a/nixos/modules/security/grsecurity.nix b/nixos/modules/security/grsecurity.nix
index d0c7fa6ec288f..66eeab7503db3 100644
--- a/nixos/modules/security/grsecurity.nix
+++ b/nixos/modules/security/grsecurity.nix
@@ -286,10 +286,11 @@ in
 
     systemd.services.grsec-lock = mkIf cfg.config.sysctl {
       description     = "grsecurity sysctl-lock Service";
-      requires        = [ "sysctl.service" ];
+      requires        = [ "systemd-sysctl.service" ];
       wantedBy        = [ "multi-user.target" ];
       serviceConfig.Type = "oneshot";
       serviceConfig.RemainAfterExit = "yes";
+      unitConfig.ConditionPathIsReadWrite = "/proc/sys/kernel/grsecurity/grsec_lock";
       script = ''
         locked=`cat /proc/sys/kernel/grsecurity/grsec_lock`
         if [ "$locked" == "0" ]; then
diff --git a/nixos/modules/security/pam.nix b/nixos/modules/security/pam.nix
index 65761865859f1..e81278a95d5c5 100644
--- a/nixos/modules/security/pam.nix
+++ b/nixos/modules/security/pam.nix
@@ -63,6 +63,14 @@ let
         '';
       };
 
+      oathAuth = mkOption {
+        default = config.security.pam.enableOATH;
+        type = types.bool;
+        description = ''
+          If set, the OATH Toolkit will be used.
+        '';
+      };
+
       sshAgentAuth = mkOption {
         default = false;
         type = types.bool;
@@ -203,9 +211,13 @@ let
           ${optionalString cfg.usbAuth
               "auth sufficient ${pkgs.pam_usb}/lib/security/pam_usb.so"}
           ${optionalString cfg.unixAuth
-              "auth sufficient pam_unix.so ${optionalString cfg.allowNullPassword "nullok"} likeauth"}
+              "auth ${if config.security.pam.enableEcryptfs then "required" else "sufficient"} pam_unix.so ${optionalString cfg.allowNullPassword "nullok"} likeauth"}
+          ${optionalString config.security.pam.enableEcryptfs
+              "auth required ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so unwrap"}
           ${optionalString cfg.otpwAuth
               "auth sufficient ${pkgs.otpw}/lib/security/pam_otpw.so"}
+          ${optionalString cfg.oathAuth
+              "auth sufficient ${pkgs.oathToolkit}/lib/security/pam_oath.so window=5 usersfile=/etc/users.oath"}
           ${optionalString config.users.ldap.enable
               "auth sufficient ${pam_ldap}/lib/security/pam_ldap.so use_first_pass"}
           ${optionalString config.krb5.enable ''
@@ -213,9 +225,11 @@ let
             auth [default=die success=done] ${pam_ccreds}/lib/security/pam_ccreds.so action=validate use_first_pass
             auth sufficient ${pam_ccreds}/lib/security/pam_ccreds.so action=store use_first_pass
           ''}
-          auth required   pam_deny.so
+          ${optionalString (! config.security.pam.enableEcryptfs) "auth required pam_deny.so"}
 
           # Password management.
+          ${optionalString config.security.pam.enableEcryptfs
+              "password optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so"}
           password requisite pam_unix.so nullok sha512
           ${optionalString config.users.ldap.enable
               "password sufficient ${pam_ldap}/lib/security/pam_ldap.so"}
@@ -235,12 +249,16 @@ let
               "session required ${pkgs.pam}/lib/security/pam_mkhomedir.so silent skel=/etc/skel umask=0022"}
           ${optionalString cfg.updateWtmp
               "session required ${pkgs.pam}/lib/security/pam_lastlog.so silent"}
+          ${optionalString config.security.pam.enableEcryptfs
+              "session optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so"}
           ${optionalString config.users.ldap.enable
               "session optional ${pam_ldap}/lib/security/pam_ldap.so"}
           ${optionalString config.krb5.enable
               "session optional ${pam_krb5}/lib/security/pam_krb5.so"}
           ${optionalString cfg.otpwAuth
               "session optional ${pkgs.otpw}/lib/security/pam_otpw.so"}
+          ${optionalString cfg.oathAuth
+              "session optional ${pkgs.oathToolkit}/lib/security/pam_oath.so window=5 usersfile=/etc/users.oath"}
           ${optionalString cfg.startSession
               "session optional ${pkgs.systemd}/lib/security/pam_systemd.so"}
           ${optionalString cfg.forwardXAuth
@@ -338,6 +356,20 @@ in
       '';
     };
 
+    security.pam.enableOATH = mkOption {
+      default = false;
+      description = ''
+        Enable the OATH (one-time password) PAM module.
+      '';
+    };
+
+    security.pam.enableEcryptfs = mkOption {
+      default = false;
+      description = ''
+        Enable eCryptfs PAM module (mounting ecryptfs home directory on login).
+      '';
+    };
+
     users.motd = mkOption {
       default = null;
       example = "Today is Sweetmorn, the 4th day of The Aftermath in the YOLD 3178.";
@@ -357,7 +389,12 @@ in
       [ pkgs.pam ]
       ++ optional config.users.ldap.enable pam_ldap
       ++ optionals config.krb5.enable [pam_krb5 pam_ccreds]
-      ++ optionals config.security.pam.enableOTPW [ pkgs.otpw ];
+      ++ optionals config.security.pam.enableOTPW [ pkgs.otpw ]
+      ++ optionals config.security.pam.enableOATH [ pkgs.oathToolkit ]
+      ++ optionals config.security.pam.enableEcryptfs [ pkgs.ecryptfs ];
+
+    security.setuidPrograms =
+        optionals config.security.pam.enableEcryptfs [ "mount.ecryptfs_private" "umount.ecryptfs_private" ];
 
     environment.etc =
       mapAttrsToList (n: v: makePAMService v) config.security.pam.services;
diff --git a/nixos/modules/services/audio/mpd.nix b/nixos/modules/services/audio/mpd.nix
index b79052337597e..9abfb41087b71 100644
--- a/nixos/modules/services/audio/mpd.nix
+++ b/nixos/modules/services/audio/mpd.nix
@@ -15,6 +15,8 @@ let
     state_file          "${cfg.dataDir}/state"
     sticker_file        "${cfg.dataDir}/sticker.sql"
     log_file            "syslog"
+    user                "${cfg.user}"
+    group               "${cfg.group}"
     ${if cfg.network.host != "any" then
    "bind_to_address     ${cfg.network.host}" else ""}
     ${if cfg.network.port != 6600 then
@@ -40,8 +42,7 @@ in {
       musicDirectory = mkOption {
         default = "${cfg.dataDir}/music";
         description = ''
-          Extra configuration added to the end of MPD's
-          configuration file, mpd.conf.
+          The directory where mpd reads music from.
         '';
       };
 
@@ -62,6 +63,16 @@ in {
         '';
       };
 
+      user = mkOption {
+        default = "mpd";
+        description = "User account under which MPD runs.";
+      };
+
+      group = mkOption {
+        default = "mpd";
+        description = "Group account under which MPD runs.";
+      };
+
       network = {
 
         host = mkOption {
@@ -96,7 +107,7 @@ in {
       description = "Music Player Daemon";
       wantedBy = [ "multi-user.target" ];
       path = [ pkgs.mpd ];
-      preStart = "mkdir -p ${cfg.dataDir} && chown -R mpd:mpd  ${cfg.dataDir}";
+      preStart = "mkdir -p ${cfg.dataDir} && chown -R ${cfg.user}:${cfg.group} ${cfg.dataDir}";
       script = "exec mpd --no-daemon ${mpdConf}";
       serviceConfig = {
         User = "mpd";
@@ -104,16 +115,18 @@ in {
       };
     };
 
-    users.extraUsers.mpd = {
+    users.extraUsers = optionalAttrs (cfg.user == "mpd") (singleton {
       inherit uid;
-      group = "mpd";
+      name = "mpd";
+      group = cfg.group;
       extraGroups = [ "audio" ];
       description = "Music Player Daemon user";
       home = "${cfg.dataDir}";
-    };
-
-    users.extraGroups.mpd.gid = gid;
+    });
 
+    users.extraGroups = optionalAttrs (cfg.group == "mpd") (singleton {
+      gid = gid;
+    });
   };
 
 }
diff --git a/nixos/modules/services/backup/tarsnap.nix b/nixos/modules/services/backup/tarsnap.nix
index 1b0bcadca1515..155161945cd90 100644
--- a/nixos/modules/services/backup/tarsnap.nix
+++ b/nixos/modules/services/backup/tarsnap.nix
@@ -12,6 +12,7 @@ let
     keyfile  ${config.services.tarsnap.keyfile}
     ${optionalString cfg.nodump "nodump"}
     ${optionalString cfg.printStats "print-stats"}
+    ${optionalString cfg.printStats "humanize-numbers"}
     ${optionalNullStr cfg.checkpointBytes "checkpoint-bytes "+cfg.checkpointBytes}
     ${optionalString cfg.aggressiveNetworking "aggressive-networking"}
     ${concatStringsSep "\n" (map (v: "exclude "+v) cfg.excludes)}
@@ -27,46 +28,39 @@ in
         type = types.bool;
         default = false;
         description = ''
-          If enabled, NixOS will periodically create backups of the
-          specified directories using the <literal>tarsnap</literal>
-          backup service. This installs a <literal>systemd</literal>
-          service called <literal>tarsnap-backup</literal> which is
-          periodically run by cron, or you may run it on-demand.
-
-          See the Tarsnap <link
-          xlink:href='http://www.tarsnap.com/gettingstarted.html'>Getting
-          Started</link> page.
+          Enable periodic tarsnap backups.
         '';
       };
 
       keyfile = mkOption {
-        type = types.path;
+        type = types.str;
         default = "/root/tarsnap.key";
         description = ''
-          Path to the keyfile which identifies the machine
-          associated with your Tarsnap account. This file can
-          be created using the
-          <literal>tarsnap-keygen</literal> utility, and
-          providing your Tarsnap login credentials.
+          The keyfile which associates this machine with your tarsnap
+          account.
+          Create the keyfile with <command>tarsnap-keygen</command>.
+
+          The keyfile name should be given as a string and not a path, to
+          avoid the key being copied into the Nix store.
         '';
       };
 
       cachedir = mkOption {
-        type    = types.path;
+        type    = types.nullOr types.path;
         default = "/var/cache/tarsnap";
         description = ''
-          Tarsnap operations use a "cache directory" which
-          allows Tarsnap to identify which blocks of data have
-          been previously stored; this directory is specified
-          via the <literal>cachedir</literal> option. If the
-          cache directory is lost or out of date, tarsnap
-          creation/deletion operations will exit with an error
-          message instructing you to run <literal>tarsnap
-          --fsck</literal> to regenerate the cache directory.
+          The cache allows tarsnap to identify previously stored data
+          blocks, reducing archival time and bandwidth usage.
+
+          Should the cache become desynchronized or corrupted, tarsnap
+          will refuse to run until you manually rebuild the cache with
+          <command>tarsnap --fsck</command>.
+
+          Set to <literal>null</literal> to disable caching.
         '';
       };
 
-      config = mkOption {
+      archives = mkOption {
         type = types.attrsOf (types.submodule (
           {
             options = {
@@ -74,41 +68,44 @@ in
                 type = types.bool;
                 default = true;
                 description = ''
-                  If set to <literal>true</literal>, then don't
-                  archive files which have the
-                  <literal>nodump</literal> flag set.
+                  Exclude files with the <literal>nodump</literal> flag.
                 '';
               };
 
               printStats = mkOption {
                 type = types.bool;
                 default = true;
-                description = "Print statistics when creating archives.";
+                description = ''
+                  Print global archive statistics upon completion.
+                  The output is available via
+                  <command>systemctl status tarsnap@archive-name</command>.
+                '';
               };
 
               checkpointBytes = mkOption {
                 type = types.nullOr types.str;
-                default = "1G";
+                default = "1GB";
                 description = ''
-                  Create a checkpoint per a particular amount of
-                  uploaded data. By default, Tarsnap will create
-                  checkpoints once per GB of data uploaded. At
-                  minimum, <literal>checkpointBytes</literal> must be
-                  1GB.
-
-                  Can also be set to <literal>null</literal> to
-                  disable checkpointing.
+                  Create a checkpoint every <literal>checkpointBytes</literal>
+                  of uploaded data (optionally specified using an SI prefix).
+
+                  1GB is the minimum value. A higher value is recommended,
+                  as checkpointing is expensive.
+
+                  Set to <literal>null</literal> to disable checkpointing.
                 '';
               };
 
               period = mkOption {
                 type = types.str;
-                default = "15 01 * * *";
+                default = "01:15";
+                example = "hourly";
                 description = ''
-                  This option defines (in the format used by cron)
-                  when tarsnap is run for backups. The default is to
-                  backup the specified paths at 01:15 at night every
-                  day.
+                  Create archive at this interval.
+
+                  The format is described in
+                  <citerefentry><refentrytitle>systemd.time</refentrytitle>
+                  <manvolnum>7</manvolnum></citerefentry>.
                 '';
               };
 
@@ -116,11 +113,11 @@ in
                 type = types.bool;
                 default = false;
                 description = ''
-                  Aggressive network behaviour: Use multiple TCP
-                  connections when writing archives.  Use of this
-                  option is recommended only in cases where TCP
-                  congestion control is known to be the limiting
-                  factor in upload performance.
+                  Upload data over multiple TCP connections, potentially
+                  increasing tarsnap's bandwidth utilisation at the cost
+                  of slowing down all other network traffic. Not
+                  recommended unless TCP congestion is the dominant
+                  limiting factor.
                 '';
               };
 
@@ -134,8 +131,7 @@ in
                 type = types.listOf types.str;
                 default = [];
                 description = ''
-                  Exclude files and directories matching the specified
-                  patterns.
+                  Exclude files and directories matching these patterns.
                 '';
               };
 
@@ -143,12 +139,10 @@ in
                 type = types.listOf types.str;
                 default = [];
                 description = ''
-                  Include only files and directories matching the
-                  specified patterns.
+                  Include only files and directories matching these
+                  patterns (the empty list includes everything).
 
-                  Note that exclusions specified via
-                  <literal>excludes</literal> take precedence over
-                  inclusions.
+                  Exclusions have precedence over inclusions.
                 '';
               };
 
@@ -156,10 +150,10 @@ in
                 type = types.bool;
                 default = false;
                 description = ''
-                  Attempt to reduce tarsnap memory consumption.  This
-                  option will slow down the process of creating
-                  archives, but may help on systems where the average
-                  size of files being backed up is less than 1 MB.
+                  Reduce memory consumption by not caching small files.
+                  Possibly beneficial if the average file size is smaller
+                  than 1 MB and the number of files is lower than the
+                  total amount of RAM in KB.
                 '';
               };
 
@@ -167,11 +161,9 @@ in
                 type = types.bool;
                 default = false;
                 description = ''
-                  Try even harder to reduce tarsnap memory
-                  consumption.  This can significantly slow down
-                  tarsnap, but reduces its memory usage by an
-                  additional factor of 2 beyond what the
-                  <literal>lowmem</literal> option does.
+                  Reduce memory consumption by a factor of 2 beyond what
+                  <literal>lowmem</literal> does, at the cost of significantly
+                  slowing down the archiving process.
                 '';
               };
             };
@@ -188,25 +180,22 @@ in
 
             gamedata =
               { directories = [ "/var/lib/minecraft "];
-                period      = "*/30 * * * *";
+                period      = "*:30";
               };
           }
         '';
 
         description = ''
-          Configuration of a Tarsnap archive. In the example, your
-          machine will have two tarsnap archives:
-          <literal>gamedata</literal> (backed up every 30 minutes) and
-          <literal>nixos</literal> (backed up at 1:15 AM every night by
-          default). You can control individual archive backups using
-          <literal>systemctl</literal>, using the
-          <literal>tarsnap@nixos</literal> or
-          <literal>tarsnap@gamedata</literal> units. For example,
-          <literal>systemctl start tarsnap@nixos</literal> will
-          immediately create a new NixOS archive. By default, archives
-          are suffixed with the timestamp of when they were started,
-          down to second resolution. This means you can use GNU
-          <literal>sort</literal> to sort output easily.
+          Tarsnap archive configurations. Each attribute names an archive
+          to be created at a given time interval, according to the options
+          associated with it. When uploading to the tarsnap server,
+          archive names are suffixed by a 1 second resolution timestamp.
+
+          For each member of the set is created a timer which triggers the
+          instanced <literal>tarsnap@</literal> service unit. You may use
+          <command>systemctl start tarsnap@archive-name</command> to
+          manually trigger creation of <literal>archive-name</literal> at
+          any time.
         '';
       };
     };
@@ -216,38 +205,45 @@ in
     assertions =
       (mapAttrsToList (name: cfg:
         { assertion = cfg.directories != [];
-          message = "Must specify directories for Tarsnap to back up";
-        }) cfg.config) ++
+          message = "Must specify paths for tarsnap to back up";
+        }) cfg.archives) ++
       (mapAttrsToList (name: cfg:
-        { assertion = cfg.lowmem -> !cfg.verylowmem && (cfg.verylowmem -> !cfg.lowmem);
+        { assertion = !(cfg.lowmem && cfg.verylowmem);
           message = "You cannot set both lowmem and verylowmem";
-        }) cfg.config);
+        }) cfg.archives);
 
     systemd.services."tarsnap@" = {
-      description = "Tarsnap Backup of '%i'";
+      description = "Tarsnap archive '%i'";
       requires    = [ "network.target" ];
 
       path = [ pkgs.tarsnap pkgs.coreutils ];
       scriptArgs = "%i";
       script = ''
-        mkdir -p -m 0755 $(dirname ${cfg.cachedir})
-        mkdir -p -m 0600 ${cfg.cachedir}
+        mkdir -p -m 0755 ${dirOf cfg.cachedir}
+        mkdir -p -m 0700 ${cfg.cachedir}
         DIRS=`cat /etc/tarsnap/$1.dirs`
         exec tarsnap --configfile /etc/tarsnap/$1.conf -c -f $1-$(date +"%Y%m%d%H%M%S") $DIRS
       '';
+
+      serviceConfig = {
+        IOSchedulingClass = "idle";
+        NoNewPrivileges = "true";
+        CapabilityBoundingSet = "CAP_DAC_READ_SEARCH";
+      };
     };
 
-    services.cron.systemCronJobs = mapAttrsToList (name: cfg:
-      "${cfg.period} root ${config.systemd.package}/bin/systemctl start tarsnap@${name}"
-    ) cfg.config;
+    systemd.timers = mapAttrs' (name: cfg: nameValuePair "tarsnap@${name}"
+      { timerConfig.OnCalendar = cfg.period;
+        wantedBy = [ "timers.target" ];
+      }) cfg.archives;
 
     environment.etc =
       (mapAttrs' (name: cfg: nameValuePair "tarsnap/${name}.conf"
         { text = configFile cfg;
-        }) cfg.config) //
+        }) cfg.archives) //
       (mapAttrs' (name: cfg: nameValuePair "tarsnap/${name}.dirs"
         { text = concatStringsSep " " cfg.directories;
-        }) cfg.config);
+        }) cfg.archives);
 
     environment.systemPackages = [ pkgs.tarsnap ];
   };
diff --git a/nixos/modules/services/databases/couchdb.nix b/nixos/modules/services/databases/couchdb.nix
index e1fe6be6f6a36..2b1d07c355ef8 100644
--- a/nixos/modules/services/databases/couchdb.nix
+++ b/nixos/modules/services/databases/couchdb.nix
@@ -131,8 +131,8 @@ in {
         type = types.string;
         default = "/var/lib/couchdb/couchdb.ini";
         description = ''
-          Custom configuration file. File needs to be readable and writable
-          from couchdb user/group.
+          Configuration file for persisting runtime changes. File
+          needs to be readable and writable from couchdb user/group.
         '';
       };
 
@@ -157,12 +157,15 @@ in {
         mkdir -p ${cfg.databaseDir};
         mkdir -p ${cfg.viewIndexDir};
         touch ${cfg.configFile}
+        touch -a ${cfg.logFile}
 
         if [ "$(id -u)" = 0 ]; then
-          chown ${cfg.user}:${cfg.group} ${cfg.uriFile}
+          chown ${cfg.user}:${cfg.group} `dirname ${cfg.uriFile}`;
+          (-f ${cfg.uriFile} && chown ${cfg.user}:${cfg.group} ${cfg.uriFile}) || true
           chown ${cfg.user}:${cfg.group} ${cfg.databaseDir}
           chown ${cfg.user}:${cfg.group} ${cfg.viewIndexDir}
           chown ${cfg.user}:${cfg.group} ${cfg.configFile}
+          chown ${cfg.user}:${cfg.group} ${cfg.logFile}
         fi
         '';
 
diff --git a/nixos/modules/services/databases/mongodb.nix b/nixos/modules/services/databases/mongodb.nix
index 02e44ad887049..14ffdad9217d2 100644
--- a/nixos/modules/services/databases/mongodb.nix
+++ b/nixos/modules/services/databases/mongodb.nix
@@ -120,6 +120,7 @@ in
         };
 
         preStart = ''
+          rm ${cfg.dbpath}/mongod.lock || true
           if ! test -e ${cfg.dbpath}; then
               install -d -m0700 -o ${cfg.user} ${cfg.dbpath}
           fi
diff --git a/nixos/modules/services/databases/redis.nix b/nixos/modules/services/databases/redis.nix
index b91c389e90a2d..f2612d0b43b94 100644
--- a/nixos/modules/services/databases/redis.nix
+++ b/nixos/modules/services/databases/redis.nix
@@ -201,7 +201,7 @@ in
     environment.systemPackages = [ cfg.package ];
 
     systemd.services.redis_init =
-      { description = "Redis server initialisation";
+      { description = "Redis Server Initialisation";
 
         wantedBy = [ "redis.service" ];
         before = [ "redis.service" ];
@@ -216,7 +216,7 @@ in
       };
 
     systemd.services.redis =
-      { description = "Redis server";
+      { description = "Redis Server";
 
         wantedBy = [ "multi-user.target" ];
         after = [ "network.target" ];
diff --git a/nixos/modules/services/misc/disnix.nix b/nixos/modules/services/misc/disnix.nix
index 219c7ed958749..48bb9e4293e79 100644
--- a/nixos/modules/services/misc/disnix.nix
+++ b/nixos/modules/services/misc/disnix.nix
@@ -132,7 +132,7 @@ in
 
           restartIfChanged = false;
           
-          path = [ pkgs.nix pkgs.disnix dysnomia ];
+          path = [ pkgs.nix pkgs.disnix dysnomia "/run/current-system/sw" ];
           
           environment = {
             HOME = "/root";
diff --git a/nixos/modules/services/misc/nix-daemon.nix b/nixos/modules/services/misc/nix-daemon.nix
index f231998d8f479..2da84c031a789 100644
--- a/nixos/modules/services/misc/nix-daemon.nix
+++ b/nixos/modules/services/misc/nix-daemon.nix
@@ -20,6 +20,8 @@ let
       extraGroups = [ "nixbld" ];
     };
 
+  nixbldUsers = map makeNixBuildUser (range 1 cfg.nrBuildUsers);
+
   nixConf =
     let
       # If we're using a chroot for builds, then provide /bin/sh in
@@ -357,7 +359,9 @@ in
 
     nix.nrBuildUsers = mkDefault (lib.max 10 cfg.maxJobs);
 
-    users.extraUsers = map makeNixBuildUser (range 1 cfg.nrBuildUsers);
+    users.extraUsers = nixbldUsers;
+
+    services.xserver.displayManager.hiddenUsers = map ({ name, ... }: name) nixbldUsers;
 
     system.activationScripts.nix = stringAfter [ "etc" "users" ]
       ''
diff --git a/nixos/modules/services/network-filesystems/samba.nix b/nixos/modules/services/network-filesystems/samba.nix
index 8c79bf663d15d..d6babb8e9a51d 100644
--- a/nixos/modules/services/network-filesystems/samba.nix
+++ b/nixos/modules/services/network-filesystems/samba.nix
@@ -27,7 +27,7 @@ let
       [ global ]
       security = ${cfg.securityType}
       passwd program = /var/setuid-wrappers/passwd %u
-      pam password change = ${toString cfg.syncPasswordsByPam}
+      pam password change = ${if cfg.syncPasswordsByPam then "yes" else "no"}
       invalid users = ${toString cfg.invalidUsers}
 
       ${cfg.extraConfig}
diff --git a/nixos/modules/services/network-filesystems/u9fs.nix b/nixos/modules/services/network-filesystems/u9fs.nix
new file mode 100644
index 0000000000000..648097274641c
--- /dev/null
+++ b/nixos/modules/services/network-filesystems/u9fs.nix
@@ -0,0 +1,75 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.u9fs;
+in
+{
+
+  options = {
+
+    services.u9fs = {
+
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = "Whether to run the u9fs 9P server for Unix.";
+      };
+
+      listenStreams = mkOption {
+        type = types.listOf types.str;
+        default = [ "564" ];
+        example = [ "192.168.16.1:564" ];
+        description = ''
+          Sockets to listen for clients on.
+          See <command>man 5 systemd.socket</command> for socket syntax.
+        '';
+      };
+
+      extraArgs = mkOption {
+        type = types.str;
+        default = "";
+        example = "-a none -u nobody";
+        description =
+          ''
+            Extra arguments to pass on invocation,
+            see <command>man 4 u9fs</command>
+          '';
+      };
+
+      fsroot = mkOption {
+        type = types.path;
+        default = "/";
+        example = "/srv";
+        description = "File system root to serve to clients.";
+      };
+
+    };
+
+  };
+
+  config = mkIf cfg.enable {
+
+    systemd = {
+      sockets.u9fs = {
+        description = "U9fs Listening Socket";
+        wantedBy = [ "sockets.target" ];
+        inherit (cfg) listenStreams;
+        socketConfig.Accept = "yes";
+      };
+      services."u9fs@" = {
+        description = "9P Protocol Server";
+        reloadIfChanged = true;
+        requires = [ "u9fs.socket" ];
+        serviceConfig =
+          { ExecStart = "-${pkgs.u9fs}/bin/u9fs ${cfg.extraArgs} ${cfg.fsroot}";
+            StandardInput = "socket";
+            StandardError = "journal";
+          };
+      };
+    };
+
+  };
+
+}
diff --git a/nixos/modules/services/networking/consul.nix b/nixos/modules/services/networking/consul.nix
index 3ae010e810704..5308fd9950855 100644
--- a/nixos/modules/services/networking/consul.nix
+++ b/nixos/modules/services/networking/consul.nix
@@ -178,7 +178,7 @@ in
         ExecReload = "${pkgs.consul}/bin/consul reload";
         PermissionsStartOnly = true;
         User = if cfg.dropPrivileges then "consul" else null;
-        TimeoutStartSec = "${toString (20 + (3 * cfg.joinRetries))}s";
+        TimeoutStartSec = "0";
       } // (optionalAttrs (cfg.leaveOnStop) {
         ExecStop = "${pkgs.consul}/bin/consul leave";
       });
@@ -209,13 +209,14 @@ in
           echo "$ADDR"
         }
         echo "{" > /etc/consul-addrs.json
+        delim=" "
       ''
       + concatStrings (flip mapAttrsToList cfg.interface (name: i:
         optionalString (i != null) ''
-          echo "    \"${name}_addr\": \"$(getAddr "${i}")\"," >> /etc/consul-addrs.json
+          echo "$delim \"${name}_addr\": \"$(getAddr "${i}")\"" >> /etc/consul-addrs.json
+          delim=","
         ''))
       + ''
-        echo "    \"\": \"\"" >> /etc/consul-addrs.json
         echo "}" >> /etc/consul-addrs.json
       '';
       postStart = ''
diff --git a/nixos/modules/services/networking/dnsmasq.nix b/nixos/modules/services/networking/dnsmasq.nix
index fbb211911f1ce..7ddabf73106e0 100644
--- a/nixos/modules/services/networking/dnsmasq.nix
+++ b/nixos/modules/services/networking/dnsmasq.nix
@@ -82,7 +82,7 @@ in
 
     systemd.services.dnsmasq = {
         description = "dnsmasq daemon";
-        after = [ "network.target" "systemd-resolved.conf" ];
+        after = [ "network.target" "systemd-resolved.service" ];
         wantedBy = [ "multi-user.target" ];
         path = [ dnsmasq ];
         preStart = ''
diff --git a/nixos/modules/services/networking/networkmanager.nix b/nixos/modules/services/networking/networkmanager.nix
index f72c7fb39d6c5..3a64d3f09e025 100644
--- a/nixos/modules/services/networking/networkmanager.nix
+++ b/nixos/modules/services/networking/networkmanager.nix
@@ -71,6 +71,13 @@ let
     ${coreutils}/bin/rm -f $tmp $tmp.ns
   '';
 
+  # pre-up and pre-down hooks were added in NM 0.9.10, but we still use 0.9.0
+  dispatcherTypesSubdirMap = {
+    "basic" = "";
+    /*"pre-up" = "pre-up.d/";
+    "pre-down" = "pre-down.d/";*/
+  };
+
 in {
 
   ###### interface
@@ -118,6 +125,30 @@ in {
         '';
       };
 
+      dispatcherScripts = mkOption {
+        type = types.listOf (types.submodule {
+          options = {
+            source = mkOption {
+              type = types.str;
+              description = ''
+                A script source.
+              '';
+            };
+
+            type = mkOption {
+              type = types.enum (attrNames dispatcherTypesSubdirMap); 
+              default = "basic";
+              description = ''
+                Dispatcher hook type. Only basic hooks are currently available.
+              '';
+            };
+          };
+        });
+        default = [];
+        description = ''
+          A list of scripts which will be executed in response to  network  events.
+        '';
+      };
     };
   };
 
@@ -155,7 +186,11 @@ in {
     ] ++ optional (cfg.appendNameservers == [] || cfg.insertNameservers == [])
            { source = overrideNameserversScript;
              target = "NetworkManager/dispatcher.d/02overridedns";
-           };
+           }
+      ++ lib.imap (i: s: {
+        text = s.source;
+        target = "NetworkManager/dispatcher.d/${dispatcherTypesSubdirMap.${s.type}}03userscript${lib.fixedWidthNumber 4 i}";
+      }) cfg.dispatcherScripts;
 
     environment.systemPackages = cfg.packages ++ [
         networkmanager_openvpn
diff --git a/nixos/modules/services/networking/ssh/sshd.nix b/nixos/modules/services/networking/ssh/sshd.nix
index c0ad9e17c4130..b11f996c63cf9 100644
--- a/nixos/modules/services/networking/ssh/sshd.nix
+++ b/nixos/modules/services/networking/ssh/sshd.nix
@@ -195,12 +195,14 @@ in
         default =
           [ { path = "/etc/ssh/ssh_host_dsa_key";
               type = "dsa";
-              bits = 1024;
             }
             { path = "/etc/ssh/ssh_host_ecdsa_key";
               type = "ecdsa";
               bits = 521;
             }
+            { path = "/etc/ssh/ssh_host_ed25519_key";
+              type = "ed25519";
+            }
           ];
         description = ''
           NixOS can automatically generate SSH host keys.  This option
@@ -323,7 +325,7 @@ in
 
                 ${flip concatMapStrings cfg.hostKeys (k: ''
                   if ! [ -f "${k.path}" ]; then
-                      ssh-keygen -t "${k.type}" -b "${toString k.bits}" -f "${k.path}" -N ""
+                      ssh-keygen -t "${k.type}" ${if k ? bits then "-b ${toString k.bits}" else ""} -f "${k.path}" -N ""
                   fi
                 '')}
               '';
@@ -379,6 +381,8 @@ in
 
         UsePAM yes
 
+        UsePrivilegeSeparation sandbox
+
         AddressFamily ${if config.networking.enableIPv6 then "any" else "inet"}
         ${concatMapStrings (port: ''
           Port ${toString port}
diff --git a/nixos/modules/services/security/fail2ban.nix b/nixos/modules/services/security/fail2ban.nix
index c40f41e07d4fc..6288b1b3ba863 100644
--- a/nixos/modules/services/security/fail2ban.nix
+++ b/nixos/modules/services/security/fail2ban.nix
@@ -95,7 +95,7 @@ in
     environment.etc."fail2ban/filter.d".source = "${pkgs.fail2ban}/etc/fail2ban/filter.d/*.conf";
 
     systemd.services.fail2ban =
-      { description = "Fail2ban intrusion prevention system";
+      { description = "Fail2ban Intrusion Prevention System";
 
         wantedBy = [ "multi-user.target" ];
         after = [ "network.target" ];
diff --git a/nixos/modules/services/torrent/transmission.nix b/nixos/modules/services/torrent/transmission.nix
index 1b38ea3b679be..135113b3ceb14 100644
--- a/nixos/modules/services/torrent/transmission.nix
+++ b/nixos/modules/services/torrent/transmission.nix
@@ -9,28 +9,16 @@ let
   homeDir = "/var/lib/transmission";
   downloadDir = "${homeDir}/Downloads";
   incompleteDir = "${homeDir}/.incomplete";
+  
   settingsDir = "${homeDir}/.config/transmission-daemon";
-  settingsFile = "${settingsDir}/settings.json";
+  settingsFile = pkgs.writeText "settings.json" (builtins.toJSON fullSettings);
 
   # Strings must be quoted, ints and bools must not (for settings.json).
   toOption = x:
     if x == true then "true"
     else if x == false then "false"
     else if isInt x then toString x
-    else toString ''\"${x}\"'';
-
-  # All lines in settings.json end with a ',' (comma), except for the last
-  # line. This is standard JSON. But a comma can also appear *inside* some
-  # fields, notably the "rpc-whitelist" field. This is difficult to handle in
-  # sed so we simply ignore it and say that if you want to change the option at
-  # the last line of settings.json, you have to do it manually. At this time of
-  # writing, the last option is "utp-enable":true.
-  attrsToSedArgs = as:
-    concatStrings (concatLists (mapAttrsToList (name: value:
-      #map (x: '' -e 's=\(\"${name}\":\)[^,]*\(.*\)=\1 ${toOption x}\2=' '') # breaks if comma inside value field
-      map (x: '' -e 's=\(\"${name}\":\).*=\1 ${toOption x},=' '') # always append ',' (breaks last line in settings.json)
-        (if isList value then value else [value]))
-        as));
+    else toString ''"${x}"'';
 
   # for users in group "transmission" to have access to torrents
   fullSettings = cfg.settings // { umask = 2; };
@@ -73,7 +61,7 @@ in
           boolean values must not.
 
           See https://trac.transmissionbt.com/wiki/EditConfigFiles for
-          documentation and/or look at ${settingsFile}.
+          documentation.
         '';
       };
 
@@ -95,7 +83,7 @@ in
       # 1) Only the "transmission" user and group have access to torrents.
       # 2) Optionally update/force specific fields into the configuration file.
       serviceConfig.ExecStartPre = ''
-          ${pkgs.stdenv.shell} -c "chmod 770 ${homeDir} && mkdir -p ${settingsDir} ${downloadDir} ${incompleteDir} && ${pkgs.transmission}/bin/transmission-daemon -d |& sed ${attrsToSedArgs fullSettings} > ${settingsFile}.tmp && mv ${settingsFile}.tmp ${settingsFile}"
+          ${pkgs.stdenv.shell} -c "chmod 770 ${homeDir} && mkdir -p ${settingsDir} ${downloadDir} ${incompleteDir} && rm -f ${settingsDir}/settings.json && cp -f ${settingsFile} ${settingsDir}/settings.json"
       '';
       serviceConfig.ExecStart = "${pkgs.transmission}/bin/transmission-daemon -f --port ${toString config.services.transmission.port}";
       serviceConfig.ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
diff --git a/nixos/modules/services/web-servers/apache-httpd/default.nix b/nixos/modules/services/web-servers/apache-httpd/default.nix
index 6a830827fd783..2b5cba68d457a 100644
--- a/nixos/modules/services/web-servers/apache-httpd/default.nix
+++ b/nixos/modules/services/web-servers/apache-httpd/default.nix
@@ -171,6 +171,9 @@ let
 
     SSLRandomSeed startup builtin
     SSLRandomSeed connect builtin
+
+    SSLProtocol All -SSLv2 -SSLv3
+    SSLCipherSuite HIGH:MEDIUM:!aNULL:!MD5:!EXP
   '';
 
 
diff --git a/nixos/modules/services/web-servers/fcgiwrap.nix b/nixos/modules/services/web-servers/fcgiwrap.nix
index 7e91e7b60eef3..2c5e433003c8c 100644
--- a/nixos/modules/services/web-servers/fcgiwrap.nix
+++ b/nixos/modules/services/web-servers/fcgiwrap.nix
@@ -4,7 +4,6 @@ with lib;
 
 let
   cfg = config.services.fcgiwrap;
-
 in {
 
   options = {
@@ -21,29 +20,53 @@ in {
         description = "Number of processes to prefork.";
       };
 
-      bindSocket = mkOption {
-        type = types.string;
-        default = "unix:/run/fcgiwrap.sock";
-        description = ''
-          Socket to bind to. Valid socket URLs are:
-            unix:/path/to/socket for Unix sockets
-            tcp:dot.ted.qu.ad:port for IPv4 sockets
-            tcp6:[ipv6_addr]:port for IPv6 sockets
-        '';
+      socketType = mkOption {
+        type = types.addCheck types.str (t: t == "unix" || t == "tcp" || t == "tcp6");
+        default = "unix";
+        description = "Socket type: 'unix', 'tcp' or 'tcp6'.";
+      };
+
+      socketAddress = mkOption {
+        type = types.str;
+        default = "/run/fcgiwrap.sock";
+        example = "1.2.3.4:5678";
+        description = "Socket address. In case of a UNIX socket, this should be its filesystem path.";
+      };
+
+      user = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        description = "User permissions for the socket.";
+      };
+
+      group = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        description = "Group permissions for the socket.";
       };
     };
   };
 
   config = mkIf cfg.enable {
-
     systemd.services.fcgiwrap = {
       after = [ "nss-user-lookup.target" ];
-      wantedBy = [ "multi-user.target" ];
+      wantedBy = optional (cfg.socketType != "unix") "multi-user.target";
 
       serviceConfig = {
-        ExecStart = "${pkgs.fcgiwrap}/sbin/fcgiwrap -c ${builtins.toString cfg.preforkProcesses} -s ${cfg.bindSocket}";
-      };
+        ExecStart = "${pkgs.fcgiwrap}/sbin/fcgiwrap -c ${builtins.toString cfg.preforkProcesses} ${
+          if (cfg.socketType != "unix") then "-s ${cfg.socketType}:${cfg.socketAddress}" else ""
+        }";
+      } // (if cfg.user != null && cfg.group != null then {
+        User = cfg.user;
+        Group = cfg.group;
+      } else { } );
     };
 
+    systemd.sockets = if (cfg.socketType == "unix") then {
+      fcgiwrap = {
+        wantedBy = [ "sockets.target" ];
+        socketConfig.ListenStream = cfg.socketAddress;
+      };
+    } else { };
   };
 }
diff --git a/nixos/modules/services/x11/display-managers/default.nix b/nixos/modules/services/x11/display-managers/default.nix
index 601971d27b69f..c5012dbb5e304 100644
--- a/nixos/modules/services/x11/display-managers/default.nix
+++ b/nixos/modules/services/x11/display-managers/default.nix
@@ -89,6 +89,10 @@ let
         ${config.hardware.pulseaudio.package}/bin/pactl load-module module-device-manager "do_routing=1"
       ''}
 
+      # Tell systemd about our $DISPLAY. This is needed by the
+      # ssh-agent unit.
+      ${config.systemd.package}/bin/systemctl --user import-environment DISPLAY
+
       # Load X defaults.
       ${xorg.xrdb}/bin/xrdb -merge ${xresourcesXft}
       if test -e ~/.Xresources; then
@@ -204,6 +208,14 @@ in
         description = "Shell commands executed just before the window or desktop manager is started.";
       };
 
+      hiddenUsers = mkOption {
+        type = types.listOf types.str;
+        default = [ "nobody" ];
+        description = ''
+          A list of users which will not be shown in the display manager.
+        '';
+      };
+
       desktopManagerHandlesLidAndPower = mkOption {
         type = types.bool;
         default = true;
diff --git a/nixos/modules/services/x11/display-managers/gdm.nix b/nixos/modules/services/x11/display-managers/gdm.nix
index b3da0cda04a30..a7ebafa28b38a 100644
--- a/nixos/modules/services/x11/display-managers/gdm.nix
+++ b/nixos/modules/services/x11/display-managers/gdm.nix
@@ -95,15 +95,23 @@ in
 
         auth     required       pam_succeed_if.so uid >= 1000 quiet
         auth     optional       ${gnome3.gnome_keyring}/lib/security/pam_gnome_keyring.so
-        auth     sufficient     pam_unix.so nullok likeauth
-        auth     required       pam_deny.so
+        auth     ${if config.security.pam.enableEcryptfs then "required" else "sufficient"} pam_unix.so nullok likeauth
+        ${optionalString config.security.pam.enableEcryptfs
+          "auth required ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so unwrap"}
+
+        ${optionalString (! config.security.pam.enableEcryptfs)
+          "auth     required       pam_deny.so"}
 
         account  sufficient     pam_unix.so
 
         password requisite      pam_unix.so nullok sha512
+        ${optionalString config.security.pam.enableEcryptfs
+          "password optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so"}
 
         session  required       pam_env.so envfile=${config.system.build.pamEnvironment}
         session  required       pam_unix.so
+        ${optionalString config.security.pam.enableEcryptfs
+          "session optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so"}
         session  required       pam_loginuid.so
         session  optional       ${pkgs.systemd}/lib/security/pam_systemd.so
         session  optional       ${gnome3.gnome_keyring}/lib/security/pam_gnome_keyring.so auto_start
@@ -115,15 +123,22 @@ in
 
         auth     required       pam_succeed_if.so uid >= 1000 quiet
         auth     optional       ${gnome3.gnome_keyring}/lib/security/pam_gnome_keyring.so
-        auth     sufficient     pam_unix.so nullok likeauth
-        auth     required       pam_deny.so 
+        auth     ${if config.security.pam.enableEcryptfs then "required" else "sufficient"} pam_unix.so nullok likeauth
+        ${optionalString config.security.pam.enableEcryptfs
+          "auth required ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so unwrap"}
+        ${optionalString (! config.security.pam.enableEcryptfs)
+          "auth     required       pam_deny.so"}
 
         account  sufficient     pam_unix.so
         
         password requisite      pam_unix.so nullok sha512
+        ${optionalString config.security.pam.enableEcryptfs
+          "password optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so"}
 
         session  required       pam_env.so envfile=${config.system.build.pamEnvironment}
         session  required       pam_unix.so
+        ${optionalString config.security.pam.enableEcryptfs
+          "session optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so"}
         session  required       pam_loginuid.so
         session  optional       ${pkgs.systemd}/lib/security/pam_systemd.so
         session  optional       ${gnome3.gnome_keyring}/lib/security/pam_gnome_keyring.so auto_start
diff --git a/nixos/modules/services/x11/display-managers/kdm.nix b/nixos/modules/services/x11/display-managers/kdm.nix
index 42eaacfe84afd..d0b69c5452c2c 100644
--- a/nixos/modules/services/x11/display-managers/kdm.nix
+++ b/nixos/modules/services/x11/display-managers/kdm.nix
@@ -38,7 +38,7 @@ let
       ''} 
 
       [X-*-Greeter]
-      HiddenUsers=root,nixbld1,nixbld2,nixbld3,nixbld4,nixbld5,nixbld6,nixbld7,nixbld8,nixbld9,nixbld10
+      HiddenUsers=root,${concatStringsSep "," dmcfg.hiddenUsers}
       PluginsLogin=${kdebase_workspace}/lib/kde4/kgreet_classic.so
       ${optionalString (cfg.themeDirectory != null)
       ''
diff --git a/nixos/modules/services/x11/display-managers/lightdm.nix b/nixos/modules/services/x11/display-managers/lightdm.nix
index 98e3fd6d6a5d1..e7ddb7ff254dc 100644
--- a/nixos/modules/services/x11/display-managers/lightdm.nix
+++ b/nixos/modules/services/x11/display-managers/lightdm.nix
@@ -18,6 +18,9 @@ let
       exec ${dmcfg.xserverBin} ${dmcfg.xserverArgs}
     '';
 
+  theme = pkgs.gnome3.gnome_themes_standard;
+  icons = pkgs.gnome3.gnome_icon_theme;
+
   # The default greeter provided with this expression is the GTK greeter.
   # Again, we need a few things in the environment for the greeter to run with
   # fonts/icons.
@@ -26,19 +29,16 @@ let
     buildInputs = [ pkgs.makeWrapper ];
 
     buildCommand = ''
-      mkdir -p $out/gtk-3.0/
-
-      # This wrapper ensures that we actually get ?? (fonts should be OK now)
+      # This wrapper ensures that we actually get themes
       makeWrapper ${pkgs.lightdm_gtk_greeter}/sbin/lightdm-gtk-greeter \
         $out/greeter \
-        --set XDG_DATA_DIRS ${pkgs.gnome2.gnome_icon_theme}/share \
-        --set XDG_CONFIG_HOME $out/
-
-      # We need this to ensure that it actually tries to find icons from gnome-icon-theme
-      cat - > $out/gtk-3.0/settings.ini << EOF
-      [Settings]
-      gtk-icon-theme-name=gnome
-      EOF
+        --prefix PATH : "${pkgs.glibc}/bin" \
+        --set GDK_PIXBUF_MODULE_FILE "$(find ${theme} -name loaders.cache)" \
+        --set GTK_PATH "${theme}:${pkgs.gtk3}" \
+        --set GTK_EXE_PREFIX "${theme}" \
+        --set GTK_DATA_PREFIX "${theme}" \
+        --set XDG_DATA_DIRS "${theme}/share:${icons}/share" \
+        --set XDG_CONFIG_HOME "${theme}/share"
 
       cat - > $out/lightdm-gtk-greeter.desktop << EOF
       [Desktop Entry]
@@ -50,6 +50,14 @@ let
     '';
   };
 
+  usersConf = writeText "users.conf"
+    ''
+      [UserList]
+      minimum-uid=500
+      hidden-users=${concatStringsSep " " dmcfg.hiddenUsers}
+      hidden-shells=/run/current-system/sw/sbin/nologin
+    '';
+
   lightdmConf = writeText "lightdm.conf"
     ''
       [LightDM]
@@ -63,10 +71,19 @@ let
       greeter-session = ${cfg.greeter.name}
     '';
 
+  gtkGreeterConf = writeText "lightdm-gtk-greeter.conf"
+    ''
+    [greeter]
+    theme-name = Adwaita
+    icon-theme-name = Adwaita
+    background = ${cfg.background}
+    '';
+
 in
 {
   options = {
     services.xserver.displayManager.lightdm = {
+
       enable = mkOption {
         default = false;
         description = ''
@@ -84,6 +101,14 @@ in
           package = wrappedGtkGreeter;
         };
       };
+
+      background = mkOption {
+        default = "${pkgs.nixos-artwork}/gnome/Gnome_Dark.png";
+        description = ''
+          The background image or color to use.
+        '';
+      };
+
     };
   };
 
@@ -97,10 +122,14 @@ in
       # lightdm relaunches itself via just `lightdm`, so needs to be on the PATH
       execCmd = ''
         export PATH=${lightdm}/sbin:$PATH
-        ${lightdm}/sbin/lightdm --log-dir=/var/log --run-dir=/run --config=${lightdmConf}
+        exec ${lightdm}/sbin/lightdm --log-dir=/var/log --run-dir=/run
       '';
     };
 
+    environment.etc."lightdm/lightdm-gtk-greeter.conf".source = gtkGreeterConf;
+    environment.etc."lightdm/lightdm.conf".source = lightdmConf;
+    environment.etc."lightdm/users.conf".source = usersConf;
+
     services.dbus.enable = true;
     services.dbus.packages = [ lightdm ];
 
@@ -109,7 +138,7 @@ in
 
     users.extraUsers.lightdm = {
       createHome = true;
-      home = "/var/lib/lightdm";
+      home = "/var/lib/lightdm-data";
       group = "lightdm";
       uid = config.ids.uids.lightdm;
     };
diff --git a/nixos/modules/services/x11/display-managers/sddm.nix b/nixos/modules/services/x11/display-managers/sddm.nix
new file mode 100644
index 0000000000000..c14c13b1cba90
--- /dev/null
+++ b/nixos/modules/services/x11/display-managers/sddm.nix
@@ -0,0 +1,110 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  xcfg = config.services.xserver;
+  dmcfg = xcfg.displayManager;
+  cfg = dmcfg.sddm;
+  xEnv = config.systemd.services."display-manager".environment;
+
+  xserverWrapper = pkgs.writeScript "xserver-wrapper" ''
+    #!/bin/sh
+    ${concatMapStrings (n: "export ${n}=\"${getAttr n xEnv}\"\n") (attrNames xEnv)}
+    exec ${dmcfg.xserverBin} ${dmcfg.xserverArgs} "$@"
+  '';
+
+  cfgFile = pkgs.writeText "sddm.conf" ''
+    [General]
+    HaltCommand=${pkgs.systemd}/bin/systemctl poweroff
+    RebootCommand=${pkgs.systemd}/bin/systemctl reboot
+
+    [Theme]
+    Current=${cfg.theme}
+
+    [Users]
+    MaximumUid=${toString config.ids.uids.nixbld}
+    HideUsers=${concatStringsSep "," dmcfg.hiddenUsers}
+    HideShells=/run/current-system/sw/sbin/nologin
+
+    [XDisplay]
+    MinimumVT=${toString xcfg.tty}
+    ServerPath=${xserverWrapper}
+    XephyrPath=${pkgs.xorg.xorgserver}/bin/Xephyr
+    SessionCommand=${dmcfg.session.script}
+    SessionDir=${dmcfg.session.desktops}
+    XauthPath=${pkgs.xorg.xauth}/bin/xauth
+  '';
+
+in
+{
+  options = {
+
+    services.xserver.displayManager.sddm = {
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to enable sddm as the display manager.
+        '';
+      };
+
+      theme = mkOption {
+        type = types.str;
+        default = "maui";
+        description = ''
+          Greeter theme to use.
+        '';
+      };
+    };
+
+  };
+
+  config = mkIf cfg.enable {
+
+    services.xserver.displayManager.slim.enable = false;
+
+    services.xserver.displayManager.job = {
+      logsXsession = true;
+
+      #execCmd = "${pkgs.sddm}/bin/sddm";
+      execCmd = "exec ${pkgs.sddm}/bin/sddm";
+    };
+
+    security.pam.services = {
+      sddm = {
+        allowNullPassword = true;
+        startSession = true;
+      };
+
+      sddm-greeter.text = ''
+        auth     required       pam_succeed_if.so audit quiet_success user = sddm
+        auth     optional       pam_permit.so
+
+        account  required       pam_succeed_if.so audit quiet_success user = sddm
+        account  sufficient     pam_unix.so
+
+        password required       pam_deny.so
+
+        session  required       pam_succeed_if.so audit quiet_success user = sddm
+        session  required       pam_env.so envfile=${config.system.build.pamEnvironment}
+        session  optional       ${pkgs.systemd}/lib/security/pam_systemd.so
+        session  optional       pam_keyinit.so force revoke
+        session  optional       pam_permit.so
+      '';
+    };
+
+    users.extraUsers.sddm = {
+      createHome = true;
+      home = "/var/lib/sddm";
+      group = "sddm";
+      uid = config.ids.uids.sddm;
+    };
+
+    environment.etc."sddm.conf".source = cfgFile;
+
+    users.extraGroups.sddm.gid = config.ids.gids.sddm;
+
+  };
+}
diff --git a/nixos/modules/services/x11/hardware/multitouch.nix b/nixos/modules/services/x11/hardware/multitouch.nix
index 6e6e88e672180..f8386b5e333bf 100644
--- a/nixos/modules/services/x11/hardware/multitouch.nix
+++ b/nixos/modules/services/x11/hardware/multitouch.nix
@@ -2,9 +2,15 @@
 
 with lib;
 
-let cfg = config.services.xserver.multitouch; in
-
-{
+let cfg = config.services.xserver.multitouch;
+    disabledTapConfig = ''
+      Option "MaxTapTime" "0"
+      Option "MaxTapMove" "0"
+      Option "TapButton1" "0"
+      Option "TapButton2" "0"
+      Option "TapButton3" "0"
+    '';
+in {
 
   options = {
 
@@ -30,6 +36,33 @@ let cfg = config.services.xserver.multitouch; in
         description = "Whether to ignore touches detected as being the palm (i.e when typing)";
       };
 
+      tapButtons = mkOption {
+        type = types.bool;
+        default = true;
+        example = false;
+        description = "Whether to enable tap buttons.";
+      };
+
+      buttonsMap = mkOption {
+        type = types.listOf types.int;
+        default = [3 2 0];
+        example = [1 3 2];
+        description = "Remap touchpad buttons.";
+        apply = map toString;
+      };
+
+      additionalOptions = mkOption {
+        type = types.str;
+        default = "";
+        example = ''
+          Option "ScaleDistance" "50"
+          Option "RotateDistance" "60"
+        '';
+        description = ''
+          Additional options for mtrack touchpad driver.
+        '';
+      };
+
     };
 
   };
@@ -46,12 +79,17 @@ let cfg = config.services.xserver.multitouch; in
           Identifier "Touchpads"
           Driver "mtrack"
           Option "IgnorePalm" "${if cfg.ignorePalm then "true" else "false"}"
+          Option "ClickFinger1" "${builtins.elemAt cfg.buttonsMap 0}"
+          Option "ClickFinger2" "${builtins.elemAt cfg.buttonsMap 1}"
+          Option "ClickFinger3" "${builtins.elemAt cfg.buttonsMap 2}"
+          ${optionalString (!cfg.tapButtons) disabledTapConfig}
           ${optionalString cfg.invertScroll ''
             Option "ScrollUpButton" "5"
             Option "ScrollDownButton" "4"
             Option "ScrollLeftButton" "7"
             Option "ScrollRightButton" "6"
           ''}
+          ${cfg.additionalOptions}
         EndSection
       '';
 
diff --git a/nixos/modules/services/x11/unclutter.nix b/nixos/modules/services/x11/unclutter.nix
new file mode 100644
index 0000000000000..556d9e187fddf
--- /dev/null
+++ b/nixos/modules/services/x11/unclutter.nix
@@ -0,0 +1,33 @@
+{ config, lib, pkgs, ... }:
+with lib;
+let cfg = config.services.unclutter;
+in {
+  options = {
+    services.unclutter.enable = mkOption {
+      type = types.bool;
+      default = false;
+      example = true;
+      description = "Enable unclutter to hide your mouse cursor when inactive";
+    };
+
+    services.unclutter.arguments = mkOption {
+      description = "Arguments to pass to unclutter command";
+      default = "-idle 1";
+      type = types.uniq types.string;
+    };
+  };
+
+  config = mkIf cfg.enable {
+    systemd.services.unclutter = {
+      description = "unclutter";
+      requires = [ "display-manager.service" ];
+      after = [ "display-manager.service" ];
+      wantedBy = [ "graphical.target" ];
+      serviceConfig.ExecStart = ''
+        ${pkgs.unclutter}/bin/unclutter ${cfg.arguments}
+      '';
+      environment = { DISPLAY = ":0"; };
+      serviceConfig.Restart = "always";
+    };
+  };
+}
diff --git a/nixos/modules/services/x11/window-managers/default.nix b/nixos/modules/services/x11/window-managers/default.nix
index 628d475c96842..97cc198137c41 100644
--- a/nixos/modules/services/x11/window-managers/default.nix
+++ b/nixos/modules/services/x11/window-managers/default.nix
@@ -8,8 +8,10 @@ in
 
 {
   imports = [
+    ./afterstep.nix
     ./bspwm.nix
     ./compiz.nix
+    ./fluxbox.nix
     ./herbstluftwm.nix
     ./i3.nix
     ./metacity.nix
diff --git a/nixos/modules/system/activation/switch-to-configuration.pl b/nixos/modules/system/activation/switch-to-configuration.pl
index dbe13c022f09e..ce36bac2bdcf8 100644
--- a/nixos/modules/system/activation/switch-to-configuration.pl
+++ b/nixos/modules/system/activation/switch-to-configuration.pl
@@ -9,19 +9,21 @@ use Cwd 'abs_path';
 
 my $out = "@out@";
 
+# To be robust against interruption, record what units need to be started etc.
 my $startListFile = "/run/systemd/start-list";
 my $restartListFile = "/run/systemd/restart-list";
 my $reloadListFile = "/run/systemd/reload-list";
 
 my $action = shift @ARGV;
 
-if (!defined $action || ($action ne "switch" && $action ne "boot" && $action ne "test")) {
+if (!defined $action || ($action ne "switch" && $action ne "boot" && $action ne "test" && $action ne "dry-activate")) {
     print STDERR <<EOF;
 Usage: $0 [switch|boot|test]
 
-switch: make the configuration the boot default and activate now
-boot:   make the configuration the boot default
-test:   activate the configuration, but don\'t make it the boot default
+switch:       make the configuration the boot default and activate now
+boot:         make the configuration the boot default
+test:         activate the configuration, but don\'t make it the boot default
+dry-activate: show what would be done if this configuration were activated
 EOF
     exit 1;
 }
@@ -56,8 +58,6 @@ EOF
     exit 100;
 }
 
-syslog(LOG_NOTICE, "switching to system configuration $out");
-
 # Ignore SIGHUP so that we're not killed if we're running on (say)
 # virtual console 1 and we restart the "tty1" unit.
 $SIG{PIPE} = "IGNORE";
@@ -116,6 +116,11 @@ sub boolIsTrue {
     return $s eq "yes" || $s eq "true";
 }
 
+sub recordUnit {
+    my ($fn, $unit) = @_;
+    write_file($fn, { append => 1 }, "$unit\n") if $action ne "dry-activate";
+}
+
 # As a fingerprint for determining whether a unit has changed, we use
 # its absolute path. If it has an override file, we append *its*
 # absolute path as well.
@@ -124,9 +129,20 @@ sub fingerprintUnit {
     return abs_path($s) . (-f "${s}.d/overrides.conf" ? " " . abs_path "${s}.d/overrides.conf" : "");
 }
 
-# Stop all services that no longer exist or have changed in the new
-# configuration.
-my (@unitsToStop, @unitsToSkip);
+# Figure out what units need to be stopped, started, restarted or reloaded.
+my (%unitsToStop, %unitsToSkip, %unitsToStart, %unitsToRestart, %unitsToReload);
+
+my %unitsToFilter; # units not shown
+
+$unitsToStart{$_} = 1 foreach
+    split('\n', read_file($startListFile, err_mode => 'quiet') // "");
+
+$unitsToRestart{$_} = 1 foreach
+    split('\n', read_file($restartListFile, err_mode => 'quiet') // "");
+
+$unitsToReload{$_} = 1 foreach
+    split '\n', read_file($reloadListFile, err_mode => 'quiet') // "";
+
 my $activePrev = getActiveUnits;
 while (my ($unit, $state) = each %{$activePrev}) {
     my $baseUnit = $unit;
@@ -141,7 +157,7 @@ while (my ($unit, $state) = each %{$activePrev}) {
 
     if (-e $prevUnitFile && ($state->{state} eq "active" || $state->{state} eq "activating")) {
         if (! -e $newUnitFile || abs_path($newUnitFile) eq "/dev/null") {
-            push @unitsToStop, $unit;
+            $unitsToStop{$unit} = 1;
         }
 
         elsif ($unit =~ /\.target$/) {
@@ -155,7 +171,10 @@ while (my ($unit, $state) = each %{$activePrev}) {
             # should not be the case.  Just ignore it.
             if ($unit ne "suspend.target" && $unit ne "hibernate.target" && $unit ne "hybrid-sleep.target") {
                 unless (boolIsTrue($unitInfo->{'RefuseManualStart'} // "no")) {
-                    write_file($startListFile, { append => 1 }, "$unit\n");
+                    $unitsToStart{$unit} = 1;
+                    recordUnit($startListFile, $unit);
+                    # Don't spam the user with target units that always get started.
+                    $unitsToFilter{$unit} = 1;
                 }
             }
 
@@ -171,7 +190,7 @@ while (my ($unit, $state) = each %{$activePrev}) {
             # (unless there is a PartOf dependency), so this is just a
             # bookkeeping thing to get systemd to do the right thing.
             if (boolIsTrue($unitInfo->{'X-StopOnReconfiguration'} // "no")) {
-                push @unitsToStop, $unit;
+                $unitsToStop{$unit} = 1;
             }
         }
 
@@ -180,16 +199,18 @@ while (my ($unit, $state) = each %{$activePrev}) {
                 # Do nothing.  These cannot be restarted directly.
             } elsif ($unit =~ /\.mount$/) {
                 # Reload the changed mount unit to force a remount.
-                write_file($reloadListFile, { append => 1 }, "$unit\n");
+                $unitsToReload{$unit} = 1;
+                recordUnit($reloadListFile, $unit);
             } elsif ($unit =~ /\.socket$/ || $unit =~ /\.path$/ || $unit =~ /\.slice$/) {
                 # FIXME: do something?
             } else {
                 my $unitInfo = parseUnit($newUnitFile);
                 if (boolIsTrue($unitInfo->{'X-ReloadIfChanged'} // "no")) {
-                    write_file($reloadListFile, { append => 1 }, "$unit\n");
+                    $unitsToReload{$unit} = 1;
+                    recordUnit($reloadListFile, $unit);
                 }
                 elsif (!boolIsTrue($unitInfo->{'X-RestartIfChanged'} // "yes") || boolIsTrue($unitInfo->{'RefuseManualStop'} // "no") ) {
-                    push @unitsToSkip, $unit;
+                    $unitsToSkip{$unit} = 1;
                 } else {
                     # If this unit is socket-activated, then stop the
                     # socket unit(s) as well, and restart the
@@ -202,8 +223,9 @@ while (my ($unit, $state) = each %{$activePrev}) {
                         }
                         foreach my $socket (@sockets) {
                             if (defined $activePrev->{$socket}) {
-                                push @unitsToStop, $socket;
-                                write_file($startListFile, { append => 1 }, "$socket\n");
+                                $unitsToStop{$unit} = 1;
+                                $unitsToStart{$unit} = 1;
+                                recordUnit($startListFile, $socket);
                                 $socketActivated = 1;
                             }
                         }
@@ -213,7 +235,8 @@ while (my ($unit, $state) = each %{$activePrev}) {
 
                         # This unit should be restarted instead of
                         # stopped and started.
-                        write_file($restartListFile, { append => 1 }, "$unit\n");
+                        $unitsToRestart{$unit} = 1;
+                        recordUnit($restartListFile, $unit);
 
                     } else {
 
@@ -222,10 +245,11 @@ while (my ($unit, $state) = each %{$activePrev}) {
                         # We write this to a file to ensure that the
                         # service gets restarted if we're interrupted.
                         if (!$socketActivated) {
-                            write_file($startListFile, { append => 1 }, "$unit\n");
+                            $unitsToStart{$unit} = 1;
+                            recordUnit($startListFile, $unit);
                         }
 
-                        push @unitsToStop, $unit;
+                        $unitsToStop{$unit} = 1;
 
                     }
                 }
@@ -268,14 +292,16 @@ foreach my $mountPoint (keys %$prevFss) {
     my $unit = pathToUnitName($mountPoint) . ".mount";
     if (!defined $new) {
         # Filesystem entry disappeared, so unmount it.
-        push @unitsToStop, $unit;
+        $unitsToStop{$unit} = 1;
     } elsif ($prev->{fsType} ne $new->{fsType} || $prev->{device} ne $new->{device}) {
         # Filesystem type or device changed, so unmount and mount it.
-        write_file($startListFile, { append => 1 }, "$unit\n");
-        push @unitsToStop, $unit;
+        $unitsToStop{$unit} = 1;
+        $unitsToStart{$unit} = 1;
+        recordUnit($startListFile, $unit);
     } elsif ($prev->{options} ne $new->{options}) {
         # Mount options changes, so remount it.
-        write_file($reloadListFile, { append => 1 }, "$unit\n");
+        $unitsToReload{$unit} = 1;
+        recordUnit($reloadListFile, $unit);
     }
 }
 
@@ -294,14 +320,51 @@ foreach my $device (keys %$prevSwaps) {
     # FIXME: update swap options (i.e. its priority).
 }
 
-if (scalar @unitsToStop > 0) {
-    @unitsToStop = unique(@unitsToStop);
-    print STDERR "stopping the following units: ", join(", ", sort(@unitsToStop)), "\n";
-    system("systemctl", "stop", "--", @unitsToStop); # FIXME: ignore errors?
+
+# Should we have systemd re-exec itself?
+my $restartSystemd = abs_path("/proc/1/exe") ne abs_path("@systemd@/lib/systemd/systemd");
+
+
+sub filterUnits {
+    my ($units) = @_;
+    my @res;
+    foreach my $unit (sort(keys %{$units})) {
+        push @res, $unit if !defined $unitsToFilter{$unit};
+    }
+    return @res;
+}
+
+my @unitsToStopFiltered = filterUnits(\%unitsToStop);
+my @unitsToStartFiltered = filterUnits(\%unitsToStart);
+
+
+# Show dry-run actions.
+if ($action eq "dry-activate") {
+    print STDERR "would stop the following units: ", join(", ", @unitsToStopFiltered), "\n"
+        if scalar @unitsToStopFiltered > 0;
+    print STDERR "would NOT stop the following changed units: ", join(", ", sort(keys %unitsToSkip)), "\n"
+        if scalar(keys %unitsToSkip) > 0;
+    print STDERR "would restart systemd\n" if $restartSystemd;
+    print STDERR "would restart the following units: ", join(", ", sort(keys %unitsToRestart)), "\n"
+        if scalar(keys %unitsToRestart) > 0;
+    print STDERR "would start the following units: ", join(", ", @unitsToStartFiltered), "\n"
+        if scalar @unitsToStartFiltered;
+    print STDERR "would reload the following units: ", join(", ", sort(keys %unitsToReload)), "\n"
+        if scalar(keys %unitsToReload) > 0;
+    exit 0;
+}
+
+
+syslog(LOG_NOTICE, "switching to system configuration $out");
+
+if (scalar (keys %unitsToStop) > 0) {
+    print STDERR "stopping the following units: ", join(", ", @unitsToStopFiltered), "\n"
+        if scalar @unitsToStopFiltered;
+    system("systemctl", "stop", "--", sort(keys %unitsToStop)); # FIXME: ignore errors?
 }
 
-print STDERR "NOT restarting the following units: ", join(", ", sort(@unitsToSkip)), "\n"
-    if scalar @unitsToSkip > 0;
+print STDERR "NOT restarting the following changed units: ", join(", ", sort(keys %unitsToSkip)), "\n"
+    if scalar(keys %unitsToSkip) > 0;
 
 # Activate the new configuration (i.e., update /etc, make accounts,
 # and so on).
@@ -310,7 +373,7 @@ print STDERR "activating the configuration...\n";
 system("$out/activate", "$out") == 0 or $res = 2;
 
 # Restart systemd if necessary.
-if (abs_path("/proc/1/exe") ne abs_path("@systemd@/lib/systemd/systemd")) {
+if ($restartSystemd) {
     print STDERR "restarting systemd...\n";
     system("@systemd@/bin/systemctl", "daemon-reexec") == 0 or $res = 2;
 }
@@ -327,10 +390,9 @@ system("@systemd@/bin/systemctl", "reload-or-restart", "dbus.service");
 
 # Restart changed services (those that have to be restarted rather
 # than stopped and started).
-my @restart = unique(split('\n', read_file($restartListFile, err_mode => 'quiet') // ""));
-if (scalar @restart > 0) {
-    print STDERR "restarting the following units: ", join(", ", sort(@restart)), "\n";
-    system("@systemd@/bin/systemctl", "restart", "--", @restart) == 0 or $res = 4;
+if (scalar(keys %unitsToRestart) > 0) {
+    print STDERR "restarting the following units: ", join(", ", sort(keys %unitsToRestart)), "\n";
+    system("@systemd@/bin/systemctl", "restart", "--", sort(keys %unitsToRestart)) == 0 or $res = 4;
     unlink($restartListFile);
 }
 
@@ -340,17 +402,16 @@ if (scalar @restart > 0) {
 # that are symlinks to other units.  We shouldn't start both at the
 # same time because we'll get a "Failed to add path to set" error from
 # systemd.
-my @start = unique("default.target", "timers.target", "sockets.target", split('\n', read_file($startListFile, err_mode => 'quiet') // ""));
-print STDERR "starting the following units: ", join(", ", sort(@start)), "\n";
-system("@systemd@/bin/systemctl", "start", "--", @start) == 0 or $res = 4;
+print STDERR "starting the following units: ", join(", ", @unitsToStartFiltered), "\n"
+    if scalar @unitsToStartFiltered;
+system("@systemd@/bin/systemctl", "start", "--", sort(keys %unitsToStart)) == 0 or $res = 4;
 unlink($startListFile);
 
 # Reload units that need it.  This includes remounting changed mount
 # units.
-my @reload = unique(split '\n', read_file($reloadListFile, err_mode => 'quiet') // "");
-if (scalar @reload > 0) {
-    print STDERR "reloading the following units: ", join(", ", sort(@reload)), "\n";
-    system("@systemd@/bin/systemctl", "reload", "--", @reload) == 0 or $res = 4;
+if (scalar(keys %unitsToReload) > 0) {
+    print STDERR "reloading the following units: ", join(", ", sort(keys %unitsToReload)), "\n";
+    system("@systemd@/bin/systemctl", "reload", "--", sort(keys %unitsToReload)) == 0 or $res = 4;
     unlink($reloadListFile);
 }
 
diff --git a/nixos/modules/system/boot/loader/generations-dir/generations-dir.nix b/nixos/modules/system/boot/loader/generations-dir/generations-dir.nix
index 4b5e84f53c1ac..6153578612c11 100644
--- a/nixos/modules/system/boot/loader/generations-dir/generations-dir.nix
+++ b/nixos/modules/system/boot/loader/generations-dir/generations-dir.nix
@@ -24,6 +24,7 @@ in
 
       enable = mkOption {
         default = false;
+        type = types.bool;
         description = ''
           Whether to create symlinks to the system generations under
           <literal>/boot</literal>.  When enabled,
@@ -42,6 +43,7 @@ in
 
       copyKernels = mkOption {
         default = false;
+        type = types.bool;
         description = "
           Whether copy the necessary boot files into /boot, so
           /nix/store is not needed by the boot loader.
diff --git a/nixos/modules/system/boot/loader/grub/grub.nix b/nixos/modules/system/boot/loader/grub/grub.nix
index a166709d39a32..585c8854feecc 100644
--- a/nixos/modules/system/boot/loader/grub/grub.nix
+++ b/nixos/modules/system/boot/loader/grub/grub.nix
@@ -179,6 +179,7 @@ in
       };
 
       splashImage = mkOption {
+        type = types.nullOr types.path;
         example = literalExample "./my-background.png";
         description = ''
           Background image used for GRUB.  It must be a 640x480,
diff --git a/nixos/modules/system/boot/loader/init-script/init-script.nix b/nixos/modules/system/boot/loader/init-script/init-script.nix
index 3b33d42b4ae4e..374d9524ff1ee 100644
--- a/nixos/modules/system/boot/loader/init-script/init-script.nix
+++ b/nixos/modules/system/boot/loader/init-script/init-script.nix
@@ -23,6 +23,7 @@ in
 
       enable = mkOption {
         default = false;
+        type = types.bool;
         description = ''
           Some systems require a /sbin/init script which is started.
           Or having it makes starting NixOS easier.
diff --git a/nixos/modules/system/boot/loader/raspberrypi/raspberrypi.nix b/nixos/modules/system/boot/loader/raspberrypi/raspberrypi.nix
index d3f32418a64c4..1ea3ddd8867c3 100644
--- a/nixos/modules/system/boot/loader/raspberrypi/raspberrypi.nix
+++ b/nixos/modules/system/boot/loader/raspberrypi/raspberrypi.nix
@@ -21,6 +21,7 @@ in
 
     boot.loader.raspberryPi.enable = mkOption {
       default = false;
+      type = types.bool;
       description = ''
         Whether to create files with the system generations in
         <literal>/boot</literal>.
diff --git a/nixos/modules/system/boot/stage-1-init.sh b/nixos/modules/system/boot/stage-1-init.sh
index a34a136026506..5af644279e5f4 100644
--- a/nixos/modules/system/boot/stage-1-init.sh
+++ b/nixos/modules/system/boot/stage-1-init.sh
@@ -177,20 +177,24 @@ fi
 if test -e /sys/power/resume -a -e /sys/power/disk; then
     if test -n "@resumeDevice@"; then
         resumeDev="@resumeDevice@"
+        resumeInfo="$(udevadm info -q property "$resumeDev" )"
     else
         for sd in @resumeDevices@; do
             # Try to detect resume device. According to Ubuntu bug:
             # https://bugs.launchpad.net/ubuntu/+source/pm-utils/+bug/923326/comments/1
             # When there are multiple swap devices, we can't know where will hibernate
             # image reside. We can check all of them for swsuspend blkid.
-            if [ "$(udevadm info -q property "$sd" | sed -n 's/^ID_FS_TYPE=//p')" = "swsuspend" ]; then
+            resumeInfo="$(udevadm info -q property "$sd" )"
+            if [ "$(echo "$resumeInfo" | sed -n 's/^ID_FS_TYPE=//p')" = "swsuspend" ]; then
                 resumeDev="$sd"
                 break
             fi
         done
     fi
-    if test -n "$resumeDev"; then
-        readlink -f "$resumeDev" > /sys/power/resume 2> /dev/null || echo "failed to resume..."
+    if test -e "$resumeDev"; then
+        resumeMajor="$(echo "$resumeInfo" | sed -n 's/^MAJOR=//p')"
+        resumeMinor="$(echo "$resumeInfo" | sed -n 's/^MINOR=//p')"
+        echo "$resumeMajor:$resumeMinor" > /sys/power/resume 2> /dev/null || echo "failed to resume..."
     fi
 fi
 
diff --git a/nixos/modules/tasks/kbd.nix b/nixos/modules/tasks/kbd.nix
index 03c42404e5d55..8d26998021d33 100644
--- a/nixos/modules/tasks/kbd.nix
+++ b/nixos/modules/tasks/kbd.nix
@@ -22,6 +22,7 @@ in
     # FIXME: still needed?
     boot.extraTTYs = mkOption {
       default = [];
+      type = types.listOf types.string;
       example = ["tty8" "tty9"];
       description = ''
         Tty (virtual console) devices, in addition to the consoles on
diff --git a/nixos/modules/tasks/network-interfaces-systemd.nix b/nixos/modules/tasks/network-interfaces-systemd.nix
index 70158fc7252b0..8223c5a4941e5 100644
--- a/nixos/modules/tasks/network-interfaces-systemd.nix
+++ b/nixos/modules/tasks/network-interfaces-systemd.nix
@@ -35,7 +35,10 @@ in
     assertions = [ {
       assertion = cfg.defaultGatewayWindowSize == null;
       message = "networking.defaultGatewayWindowSize is not supported by networkd.";
-    } ];
+    } ] ++ flip mapAttrsToList cfg.bridges (n: { rstp, ... }: {
+      assertion = !rstp;
+      message = "networking.bridges.${n}.rstp is not supported by networkd.";
+    });
 
     systemd.services.dhcpcd.enable = mkDefault false;
 
diff --git a/nixos/modules/virtualisation/containers.nix b/nixos/modules/virtualisation/containers.nix
index c461cf8c00cb8..da39dda853535 100644
--- a/nixos/modules/virtualisation/containers.nix
+++ b/nixos/modules/virtualisation/containers.nix
@@ -10,6 +10,7 @@ let
     isExecutable = true;
     src = ./nixos-container.pl;
     perl = "${pkgs.perl}/bin/perl -I${pkgs.perlPackages.FileSlurp}/lib/perl5/site_perl";
+    su = "${pkgs.shadow.su}/bin/su";
     inherit (pkgs) utillinux;
   };
 
@@ -202,7 +203,7 @@ in
         script =
           ''
             mkdir -p -m 0755 "$root/etc" "$root/var/lib"
-            mkdir -p -m 0700 "$root/var/lib/private" "$root/root"
+            mkdir -p -m 0700 "$root/var/lib/private" "$root/root" /run/containers
             if ! [ -e "$root/etc/os-release" ]; then
               touch "$root/etc/os-release"
             fi
@@ -211,7 +212,7 @@ in
               "/nix/var/nix/profiles/per-container/$INSTANCE" \
               "/nix/var/nix/gcroots/per-container/$INSTANCE"
 
-            cp -f /etc/resolv.conf "$root/etc/resolv.conf"
+            cp --remove-destination /etc/resolv.conf "$root/etc/resolv.conf"
 
             if [ "$PRIVATE_NETWORK" = 1 ]; then
               extraFlags+=" --network-veth"
@@ -260,11 +261,21 @@ in
                 ip route add $LOCAL_ADDRESS dev $ifaceHost
               fi
             fi
+
+            # Get the leader PID so that we can signal it in
+            # preStop. We can't use machinectl there because D-Bus
+            # might be shutting down. FIXME: in systemd 219 we can
+            # just signal systemd-nspawn to do a clean shutdown.
+            machinectl show "$INSTANCE" | sed 's/Leader=\(.*\)/\1/;t;d' > "/run/containers/$INSTANCE.pid"
           '';
 
         preStop =
           ''
-            machinectl poweroff "$INSTANCE" || true
+            pid="$(cat /run/containers/$INSTANCE.pid)"
+            if [ -n "$pid" ]; then
+              kill -RTMIN+4 "$pid"
+            fi
+            rm -f "/run/containers/$INSTANCE.pid"
           '';
 
         restartIfChanged = false;
diff --git a/nixos/modules/virtualisation/google-compute-image.nix b/nixos/modules/virtualisation/google-compute-image.nix
index 4d493b3896f24..98985d2d2c57c 100644
--- a/nixos/modules/virtualisation/google-compute-image.nix
+++ b/nixos/modules/virtualisation/google-compute-image.nix
@@ -129,10 +129,10 @@ in
 
       wantedBy = [ "sshd.service" ];
       before = [ "sshd.service" ];
-      after = [ "network-online.target" ];
-      wants = [ "network-online.target" ];
+      after = [ "network-online.target" "ip-up.target" ];
+      wants = [ "network-online.target" "ip-up.target" ];
 
-      script = let wget = "${pkgs.wget}/bin/wget --retry-connrefused -t 6 --waitretry=10"; in
+      script = let wget = "${pkgs.wget}/bin/wget --retry-connrefused -t 15 --waitretry=10 --header='Metadata-Flavor: Google'"; in
         ''
           # When dealing with cryptographic keys, we want to keep things private.
           umask 077
@@ -140,7 +140,7 @@ in
           if ! [ -e /root/.ssh/authorized_keys ]; then
                 echo "obtaining SSH key..."
                 mkdir -m 0700 -p /root/.ssh
-                ${wget} -O /root/authorized-keys-metadata http://metadata/0.1/meta-data/authorized-keys
+                ${wget} -O /root/authorized-keys-metadata http://metadata.google.internal/0.1/meta-data/authorized-keys
                 if [ $? -eq 0 -a -e /root/authorized-keys-metadata ]; then
                     cat /root/authorized-keys-metadata | cut -d: -f2- > /root/key.pub
                     if ! grep -q -f /root/key.pub /root/.ssh/authorized_keys; then
@@ -156,7 +156,7 @@ in
           ${flip concatMapStrings config.services.openssh.hostKeys (k :
             let kName = baseNameOf k.path; in ''
               echo "trying to obtain SSH private host key ${kName}"
-              ${wget} -O /root/${kName} http://metadata/0.1/meta-data/attributes/${kName} && :
+              ${wget} -O /root/${kName} http://metadata.google.internal/0.1/meta-data/attributes/${kName} && :
               if [ $? -eq 0 -a -e /root/${kName} ]; then
                   countKeys=$((countKeys+1))
                   mv -f /root/${kName} ${k.path}
diff --git a/nixos/modules/virtualisation/lxc.nix b/nixos/modules/virtualisation/lxc.nix
index 10d3a6575fb9b..22da012e4141e 100644
--- a/nixos/modules/virtualisation/lxc.nix
+++ b/nixos/modules/virtualisation/lxc.nix
@@ -32,7 +32,9 @@ in
         default = "";
         description =
           ''
-            This is the system-wide LXC config. See lxc.system.conf(5).
+            This is the system-wide LXC config. See
+            <citerefentry><refentrytitle>lxc.system.conf</refentrytitle>
+            <manvolnum>5</manvolnum></citerefentry>.
           '';
       };
 
@@ -43,7 +45,8 @@ in
         description =
           ''
             Default config (default.conf) for new containers, i.e. for
-            network config. See lxc.container.conf(5).
+            network config. See <citerefentry><refentrytitle>lxc.container.conf
+            </refentrytitle><manvolnum>5</manvolnum></citerefentry>.
           '';
       };
 
@@ -54,7 +57,9 @@ in
         description =
           ''
             This is the config file for managing unprivileged user network
-            administration access in LXC. See lxc-user-net(5).
+            administration access in LXC. See <citerefentry>
+            <refentrytitle>lxc-user-net</refentrytitle><manvolnum>5</manvolnum>
+            </citerefentry>.
           '';
       };
 
diff --git a/nixos/modules/virtualisation/nixos-container.pl b/nixos/modules/virtualisation/nixos-container.pl
index 94edfb37948a3..1455f7143f131 100644
--- a/nixos/modules/virtualisation/nixos-container.pl
+++ b/nixos/modules/virtualisation/nixos-container.pl
@@ -8,6 +8,7 @@ use Fcntl ':flock';
 use Getopt::Long qw(:config gnu_getopt);
 
 my $nsenter = "@utillinux@/bin/nsenter";
+my $su = "@su@";
 
 # Ensure a consistent umask.
 umask 0022;
@@ -271,14 +272,14 @@ elsif ($action eq "login") {
 }
 
 elsif ($action eq "root-login") {
-    runInContainer("su", "root", "-l");
+    runInContainer("@su@", "root", "-l");
 }
 
 elsif ($action eq "run") {
     shift @ARGV; shift @ARGV;
     # Escape command.
     my $s = join(' ', map { s/'/'\\''/g; "'$_'" } @ARGV);
-    runInContainer("su", "root", "-l", "-c", "exec " . $s);
+    runInContainer("@su@", "root", "-l", "-c", "exec " . $s);
 }
 
 elsif ($action eq "show-ip") {
diff --git a/nixos/modules/virtualisation/xen-dom0.nix b/nixos/modules/virtualisation/xen-dom0.nix
index f3a24c5cf25bc..ea9f61aad6a68 100644
--- a/nixos/modules/virtualisation/xen-dom0.nix
+++ b/nixos/modules/virtualisation/xen-dom0.nix
@@ -5,18 +5,8 @@
 with lib;
 
 let
-
   cfg = config.virtualisation.xen;
-
   xen = pkgs.xen;
-
-  xendConfig = pkgs.writeText "xend-config.sxp"
-    ''
-      (loglevel DEBUG)
-      (network-script network-bridge)
-      (vif-script vif-bridge)
-    '';
-
 in
 
 {
@@ -58,23 +48,62 @@ in
           '';
       };
 
+    virtualisation.xen.bridge =
+      mkOption {
+        default = "xenbr0";
+        description =
+          ''
+            Create a bridge for the Xen domUs to connect to.
+          '';
+      };
+
+    virtualisation.xen.stored =
+      mkOption {
+        type = types.path;
+        description =
+          ''
+            Xen Store daemon to use. Defaults to oxenstored of the xen package.
+          '';
+      };
+
+    virtualisation.xen.trace =
+      mkOption {
+        default = false;
+        description =
+          ''
+            Enable Xen tracing.
+          '';
+      };
   };
 
 
   ###### implementation
 
   config = mkIf cfg.enable {
+    assertions = [ {
+      assertion = pkgs.stdenv.isx86_64;
+      message = "Xen currently not supported on ${pkgs.stdenv.system}";
+    } {
+      assertion = config.boot.loader.grub.enable && (config.boot.loader.grub.efiSupport == false);
+      message = "Xen currently does not support EFI boot";
+    } ];
+
+    virtualisation.xen.stored = mkDefault "${xen}/bin/oxenstored";
 
     environment.systemPackages = [ xen ];
 
-    # Domain 0 requires a pvops-enabled kernel.
-    boot.kernelPackages = pkgs.linuxPackages_3_2_xen;
+    # Make sure Domain 0 gets the required configuration
+    #boot.kernelPackages = pkgs.boot.kernelPackages.override { features={xen_dom0=true;}; };
 
     boot.kernelModules =
-      [ "xen_evtchn" "xen_gntdev" "xen_blkback" "xen_netback" "xen_pciback"
-        "blktap" "tun"
+      [ "xen-evtchn" "xen-gntdev" "xen-gntalloc" "xen-blkback" "xen-netback"
+        "xen-pciback" "evtchn" "gntdev" "netbk" "blkbk" "xen-scsibk"
+        "usbbk" "pciback" "xen-acpi-processor" "blktap2" "tun" "netxen_nic"
+        "xen_wdt" "xen-acpi-processor" "xen-privcmd" "xen-scsiback"
+        "xenfs"
       ];
 
+
     # The radeonfb kernel module causes the screen to go black as soon
     # as it's loaded, so don't load it.
     boot.blacklistedKernelModules = [ "radeonfb" ];
@@ -87,8 +116,8 @@ in
         options loop max_loop=64
       '';
 
-    virtualisation.xen.bootParams =
-      [ "loglvl=all" "guest_loglvl=all" ] ++
+    virtualisation.xen.bootParams = [] ++
+      optionals cfg.trace [ "loglvl=all" "guest_loglvl=all" ] ++
       optional (cfg.domain0MemorySize != 0) "dom0_mem=${toString cfg.domain0MemorySize}M";
 
     system.extraSystemBuilderCmds =
@@ -101,71 +130,36 @@ in
     system.activationScripts.xen =
       ''
         if [ -d /proc/xen ]; then
-            ${pkgs.sysvtools}/bin/mountpoint -q /proc/xen || \
+            ${pkgs.kmod}/bin/modprobe xenfs 2> /dev/null
+            ${pkgs.utillinux}/bin/mountpoint -q /proc/xen || \
                 ${pkgs.utillinux}/bin/mount -t xenfs none /proc/xen
         fi
       '';
 
-    jobs.xend =
-      { description = "Xen Control Daemon";
-
-        startOn = "stopped udevtrigger";
-
-        path =
-          [ pkgs.bridge-utils pkgs.gawk pkgs.iproute pkgs.nettools
-            pkgs.utillinux pkgs.bash xen pkgs.pciutils pkgs.procps
-          ];
-
-        environment.XENCONSOLED_TRACE = "hv";
-
-        preStart =
-          ''
-            mkdir -p /var/log/xen/console -m 0700
-
-            ${xen}/sbin/xend start
-
-            # Wait until Xend is running.
-            for ((i = 0; i < 60; i++)); do echo "waiting for xend..."; ${xen}/sbin/xend status && break; done
-
-            ${xen}/sbin/xend status || exit 1
-          '';
-
-        postStop = "${xen}/sbin/xend stop";
-      };
-
-    jobs.xendomains =
-      { description = "Automatically starts, saves and restores Xen domains on startup/shutdown";
-
-        startOn = "started xend";
-
-        stopOn = "starting shutdown and stopping xend";
-
-        restartIfChanged = false;
-        
-        path = [ pkgs.xen ];
-
-        environment.XENDOM_CONFIG = "${xen}/etc/sysconfig/xendomains";
-
-        preStart =
-          ''
-            mkdir -p /var/lock/subsys -m 755
-            ${xen}/etc/init.d/xendomains start
-          '';
-
-        postStop = "${xen}/etc/init.d/xendomains stop";
-      };
+    # Domain 0 requires a pvops-enabled kernel.
+    system.requiredKernelConfig = with config.lib.kernelConfig;
+      [ (isYes "XEN")
+        (isYes "X86_IO_APIC")
+        (isYes "ACPI")
+        (isYes "XEN_DOM0")
+        (isYes "PCI_XEN")
+        (isYes "XEN_DEV_EVTCHN")
+        (isYes "XENFS")
+        (isYes "XEN_COMPAT_XENFS")
+        (isYes "XEN_SYS_HYPERVISOR")
+        (isYes "XEN_GNTDEV")
+        (isYes "XEN_BACKEND")
+        (isModule "XEN_NETDEV_BACKEND")
+        (isModule "XEN_BLKDEV_BACKEND")
+        (isModule "XEN_PCIDEV_BACKEND")
+        (isYes "XEN_BALLOON")
+        (isYes "XEN_SCRUB_PAGES")
+      ];
 
-    # To prevent a race between dhcpcd and xend's bridge setup script
-    # (which renames eth* to peth* and recreates eth* as a virtual
-    # device), start dhcpcd after xend.
-    jobs.dhcpcd.startOn = mkOverride 50 "started xend";
 
     environment.etc =
-      [ { source = xendConfig;
-          target = "xen/xend-config.sxp";
-        }
-        { source = "${xen}/etc/xen/scripts";
-          target = "xen/scripts";
+      [ { source = "${xen}/etc/xen/xl.conf";
+          target = "xen/xl.conf";
         }
       ];
 
@@ -174,6 +168,125 @@ in
 
     services.udev.path = [ pkgs.bridge-utils pkgs.iproute ];
 
+    systemd.services.xen-store = {
+      description = "Xen Store Daemon";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" "xen-store.socket" ];
+      requires = [ "xen-store.socket" ];
+      preStart = ''
+        export XENSTORED_ROOTDIR="/var/lib/xenstored"
+        rm -f "$XENSTORED_ROOTDIR"/tdb* &>/dev/null
+
+        mkdir -p /var/run
+        ${optionalString cfg.trace "mkdir -p /var/log/xen"}
+        grep -q control_d /proc/xen/capabilities
+        '';
+      serviceConfig.ExecStart = ''
+        ${cfg.stored}${optionalString cfg.trace " -T /var/log/xen/xenstored-trace.log"} --no-fork
+        '';
+      postStart = ''
+        time=0
+        timeout=30
+        # Wait for xenstored to actually come up, timing out after 30 seconds
+        while [ $time -lt $timeout ] && ! `${pkgs.xen}/bin/xenstore-read -s / >/dev/null 2>&1` ; do
+            time=$(($time+1))
+            sleep 1
+        done
+
+        # Exit if we timed out
+        if ! [ $time -lt $timeout ] ; then
+            echo "Could not start Xenstore Daemon"
+            exit 1
+        fi
+
+        ${pkgs.xen}/bin/xenstore-write "/local/domain/0/name" "Domain-0"
+        ${pkgs.xen}/bin/xenstore-write "/local/domain/0/domid" 0
+        '';
+    };
+
+    systemd.sockets.xen-store = {
+      description = "XenStore Socket for userspace API";
+      wantedBy = [ "sockets.target" ];
+      socketConfig = {
+        ListenStream = [ "/var/run/xenstored/socket" "/var/run/xenstored/socket_ro" ];
+        SocketMode = "0660";
+        SocketUser = "root";
+        SocketGroup = "root";
+      };
+    };
+
+
+    systemd.services.xen-console = {
+      description = "Xen Console Daemon";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "xen-store.service" ];
+      preStart = ''
+        mkdir -p /var/run/xen
+        ${optionalString cfg.trace "mkdir -p /var/log/xen"}
+        grep -q control_d /proc/xen/capabilities
+        '';
+      serviceConfig = {
+        ExecStart = ''
+          ${pkgs.xen}/bin/xenconsoled${optionalString cfg.trace " --log=all --log-dir=/var/log/xen"}
+          '';
+      };
+    };
+
+
+    systemd.services.xen-qemu = {
+      description = "Xen Qemu Daemon";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "xen-console.service" ];
+      serviceConfig.ExecStart = ''
+        ${pkgs.xen}/lib/xen/bin/qemu-system-i386 -xen-domid 0 -xen-attach -name dom0 -nographic -M xenpv \
+           -monitor /dev/null -serial /dev/null -parallel /dev/null
+        '';
+    };
+
+
+    systemd.services.xen-watchdog = {
+      description = "Xen Watchdog Daemon";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "xen-qemu.service" ];
+      serviceConfig.ExecStart = "${pkgs.xen}/bin/xenwatchdogd 30 15";
+      serviceConfig.Type = "forking";
+      serviceConfig.RestartSec = "1";
+      serviceConfig.Restart = "on-failure";
+    };
+
+
+    systemd.services.xen-bridge = {
+      description = "Xen bridge";
+      wantedBy = [ "multi-user.target" ];
+      before = [ "xen-domains.service" ];
+      serviceConfig.RemainAfterExit = "yes";
+      serviceConfig.ExecStart = ''
+        ${pkgs.bridge-utils}/bin/brctl addbr ${cfg.bridge}
+        ${pkgs.inetutils}/bin/ifconfig ${cfg.bridge} up
+        '';
+      serviceConfig.ExecStop = ''
+        ${pkgs.inetutils}/bin/ifconfig ${cfg.bridge} down
+        ${pkgs.bridge-utils}/bin/brctl delbr ${cfg.bridge}
+        '';
+    };
+
+    systemd.services.xen-domains = {
+      description = "Xen domains - automatically starts, saves and restores Xen domains";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "xen-bridge.service" "xen-qemu.service" ];
+      ## To prevent a race between dhcpcd and xend's bridge setup script
+      ## (which renames eth* to peth* and recreates eth* as a virtual
+      ## device), start dhcpcd after xend.
+      before = [ "dhcpd.service" ];
+      restartIfChanged = false;
+      serviceConfig.RemainAfterExit = "yes";
+      path = [ pkgs.xen ];
+      environment.XENDOM_CONFIG = "${pkgs.xen}/etc/sysconfig/xendomains";
+      preStart = "mkdir -p /var/lock/subsys -m 755";
+      serviceConfig.ExecStart = "${pkgs.xen}/etc/init.d/xendomains start";
+      serviceConfig.ExecStop = "${pkgs.xen}/etc/init.d/xendomains stop";
+    };
+
   };
 
 }
diff --git a/nixos/modules/virtualisation/xen-domU.nix b/nixos/modules/virtualisation/xen-domU.nix
index 4835896693456..2db3190ad139d 100644
--- a/nixos/modules/virtualisation/xen-domU.nix
+++ b/nixos/modules/virtualisation/xen-domU.nix
@@ -9,7 +9,10 @@
   boot.loader.grub.device = "nodev";
   boot.loader.grub.extraPerEntryConfig = "root (hd0)";
 
-  boot.initrd.kernelModules = [ "xen-blkfront" ];
+  boot.initrd.kernelModules =
+    [ "xen-blkfront" "xen-tpmfront" "xen-kbdfront" "xen-fbfront"
+      "xen-netfront" "xen-pcifront" "xen-scsifront"
+    ];
 
   # Send syslog messages to the Xen console.
   services.syslogd.tty = "hvc0";
diff --git a/nixos/release.nix b/nixos/release.nix
index 1bd3ec5773189..cc451f7fe15bc 100644
--- a/nixos/release.nix
+++ b/nixos/release.nix
@@ -244,7 +244,7 @@ in rec {
   tests.blivet = callTest tests/blivet.nix {};
   tests.cadvisor = scrubDrv (import tests/cadvisor.nix { system = "x86_64-linux"; });
   tests.chromium = callTest tests/chromium.nix {};
-  tests.cjdns = callTest tests/cjdns.nix {};
+  #tests.cjdns = callTest tests/cjdns.nix {};
   tests.containers = callTest tests/containers.nix {};
   tests.docker = scrubDrv (import tests/docker.nix { system = "x86_64-linux"; });
   tests.dockerRegistry = scrubDrv (import tests/docker-registry.nix { system = "x86_64-linux"; });
@@ -254,6 +254,7 @@ in rec {
   tests.fleet = scrubDrv (import tests/fleet.nix { system = "x86_64-linux"; });
   #tests.gitlab = callTest tests/gitlab.nix {};
   tests.gnome3 = callTest tests/gnome3.nix {};
+  tests.i3wm = callTest tests/i3wm.nix {};
   tests.installer.grub1 = forAllSystems (system: scrubDrv (import tests/installer.nix { inherit system; }).grub1.test);
   tests.installer.lvm = forAllSystems (system: scrubDrv (import tests/installer.nix { inherit system; }).lvm.test);
   tests.installer.rebuildCD = forAllSystems (system: scrubDrv (import tests/installer.nix { inherit system; }).rebuildCD.test);
diff --git a/nixos/tests/i3wm.nix b/nixos/tests/i3wm.nix
new file mode 100644
index 0000000000000..0966dba8a3c89
--- /dev/null
+++ b/nixos/tests/i3wm.nix
@@ -0,0 +1,28 @@
+import ./make-test.nix {
+  name = "i3wm";
+
+  machine = { lib, pkgs, ... }: {
+    imports = [ ./common/x11.nix ./common/user-account.nix ];
+    services.xserver.displayManager.auto.user = "alice";
+    services.xserver.windowManager.default = lib.mkForce "i3";
+    services.xserver.windowManager.i3.enable = true;
+  };
+
+  testScript = { nodes, ... }: ''
+    $machine->waitForX;
+    $machine->waitForWindow(qr/first configuration/);
+    $machine->sleep(1);
+    $machine->screenshot("started");
+    $machine->sendKeys("ret");
+    $machine->sleep(1);
+    $machine->sendKeys("alt");
+    $machine->sleep(1);
+    $machine->screenshot("configured");
+    $machine->sendKeys("ret");
+    $machine->sleep(2);
+    $machine->sendKeys("alt-ret");
+    $machine->waitForWindow(qr/machine.*alice/);
+    $machine->sleep(1);
+    $machine->screenshot("terminal");
+  '';
+}