about summary refs log tree commit diff
path: root/nixpkgs/nixos/modules/config
diff options
context:
space:
mode:
Diffstat (limited to 'nixpkgs/nixos/modules/config')
-rw-r--r--nixpkgs/nixos/modules/config/appstream.nix25
-rw-r--r--nixpkgs/nixos/modules/config/debug-info.nix45
-rw-r--r--nixpkgs/nixos/modules/config/fonts/corefonts.nix36
-rw-r--r--nixpkgs/nixos/modules/config/fonts/fontconfig-penultimate.nix292
-rw-r--r--nixpkgs/nixos/modules/config/fonts/fontconfig-ultimate.nix86
-rw-r--r--nixpkgs/nixos/modules/config/fonts/fontconfig.nix476
-rw-r--r--nixpkgs/nixos/modules/config/fonts/fontdir.nix47
-rw-r--r--nixpkgs/nixos/modules/config/fonts/fonts.nix51
-rw-r--r--nixpkgs/nixos/modules/config/fonts/ghostscript.nix32
-rw-r--r--nixpkgs/nixos/modules/config/gnu.nix46
-rw-r--r--nixpkgs/nixos/modules/config/gtk/gtk-icon-cache.nix86
-rw-r--r--nixpkgs/nixos/modules/config/i18n.nix160
-rw-r--r--nixpkgs/nixos/modules/config/iproute2.nix32
-rw-r--r--nixpkgs/nixos/modules/config/krb5/default.nix367
-rw-r--r--nixpkgs/nixos/modules/config/ldap.nix293
-rw-r--r--nixpkgs/nixos/modules/config/locale.nix94
-rw-r--r--nixpkgs/nixos/modules/config/malloc.nix91
-rw-r--r--nixpkgs/nixos/modules/config/networking.nix219
-rw-r--r--nixpkgs/nixos/modules/config/no-x-libs.nix41
-rw-r--r--nixpkgs/nixos/modules/config/nsswitch.nix116
-rw-r--r--nixpkgs/nixos/modules/config/power-management.nix106
-rw-r--r--nixpkgs/nixos/modules/config/pulseaudio.nix326
-rw-r--r--nixpkgs/nixos/modules/config/qt5.nix102
-rw-r--r--nixpkgs/nixos/modules/config/resolvconf.nix149
-rw-r--r--nixpkgs/nixos/modules/config/shells-environment.nix204
-rw-r--r--nixpkgs/nixos/modules/config/swap.nix222
-rw-r--r--nixpkgs/nixos/modules/config/sysctl.nix63
-rw-r--r--nixpkgs/nixos/modules/config/system-environment.nix99
-rw-r--r--nixpkgs/nixos/modules/config/system-path.nix150
-rw-r--r--nixpkgs/nixos/modules/config/terminfo.nix33
-rw-r--r--nixpkgs/nixos/modules/config/unix-odbc-drivers.nix38
-rw-r--r--nixpkgs/nixos/modules/config/update-users-groups.pl285
-rw-r--r--nixpkgs/nixos/modules/config/users-groups.nix601
-rw-r--r--nixpkgs/nixos/modules/config/vpnc.nix41
-rw-r--r--nixpkgs/nixos/modules/config/vte.nix52
-rw-r--r--nixpkgs/nixos/modules/config/xdg/autostart.nix22
-rw-r--r--nixpkgs/nixos/modules/config/xdg/icons.nix38
-rw-r--r--nixpkgs/nixos/modules/config/xdg/menus.nix25
-rw-r--r--nixpkgs/nixos/modules/config/xdg/mime.nix36
-rw-r--r--nixpkgs/nixos/modules/config/xdg/portal.nix58
-rw-r--r--nixpkgs/nixos/modules/config/xdg/sounds.nix22
-rw-r--r--nixpkgs/nixos/modules/config/zram.nix189
42 files changed, 5496 insertions, 0 deletions
diff --git a/nixpkgs/nixos/modules/config/appstream.nix b/nixpkgs/nixos/modules/config/appstream.nix
new file mode 100644
index 000000000000..483ac9c3cd76
--- /dev/null
+++ b/nixpkgs/nixos/modules/config/appstream.nix
@@ -0,0 +1,25 @@
+{ config, lib, ... }:
+
+with lib;
+{
+  options = {
+    appstream.enable = mkOption {
+      type = types.bool;
+      default = true;
+      description = ''
+        Whether to install files to support the 
+        <link xlink:href="https://www.freedesktop.org/software/appstream/docs/index.html">AppStream metadata specification</link>.
+      '';
+    };
+  };
+
+  config = mkIf config.appstream.enable {
+    environment.pathsToLink = [ 
+      # per component metadata
+      "/share/metainfo" 
+      # legacy path for above
+      "/share/appdata" 
+    ];
+  };
+
+}
diff --git a/nixpkgs/nixos/modules/config/debug-info.nix b/nixpkgs/nixos/modules/config/debug-info.nix
new file mode 100644
index 000000000000..2942ae5905d1
--- /dev/null
+++ b/nixpkgs/nixos/modules/config/debug-info.nix
@@ -0,0 +1,45 @@
+{ config, lib, ... }:
+
+with lib;
+
+{
+
+  options = {
+
+    environment.enableDebugInfo = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        Some NixOS packages provide debug symbols. However, these are
+        not included in the system closure by default to save disk
+        space. Enabling this option causes the debug symbols to appear
+        in <filename>/run/current-system/sw/lib/debug/.build-id</filename>,
+        where tools such as <command>gdb</command> can find them.
+        If you need debug symbols for a package that doesn't
+        provide them by default, you can enable them as follows:
+        <programlisting>
+        nixpkgs.config.packageOverrides = pkgs: {
+          hello = pkgs.hello.overrideAttrs (oldAttrs: {
+            separateDebugInfo = true;
+          });
+        };
+        </programlisting>
+      '';
+    };
+
+  };
+
+
+  config = mkIf config.environment.enableDebugInfo {
+
+    # FIXME: currently disabled because /lib is already in
+    # environment.pathsToLink, and we can't have both.
+    #environment.pathsToLink = [ "/lib/debug/.build-id" ];
+
+    environment.extraOutputsToInstall = [ "debug" ];
+
+    environment.variables.NIX_DEBUG_INFO_DIRS = [ "/run/current-system/sw/lib/debug" ];
+
+  };
+
+}
diff --git a/nixpkgs/nixos/modules/config/fonts/corefonts.nix b/nixpkgs/nixos/modules/config/fonts/corefonts.nix
new file mode 100644
index 000000000000..b9f69879a103
--- /dev/null
+++ b/nixpkgs/nixos/modules/config/fonts/corefonts.nix
@@ -0,0 +1,36 @@
+# This module is deprecated, since you can just say ‘fonts.fonts = [
+# pkgs.corefonts ];’ instead.
+
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+
+  options = {
+
+    fonts = {
+
+      enableCoreFonts = mkOption {
+        visible = false;
+        default = false;
+        description = ''
+          Whether to include Microsoft's proprietary Core Fonts.  These fonts
+          are redistributable, but only verbatim, among other restrictions.
+          See <link xlink:href="http://corefonts.sourceforge.net/eula.htm"/>
+          for details.
+       '';
+      };
+
+    };
+
+  };
+
+
+  config = mkIf config.fonts.enableCoreFonts {
+
+    fonts.fonts = [ pkgs.corefonts ];
+
+  };
+
+}
diff --git a/nixpkgs/nixos/modules/config/fonts/fontconfig-penultimate.nix b/nixpkgs/nixos/modules/config/fonts/fontconfig-penultimate.nix
new file mode 100644
index 000000000000..7e311a21acf6
--- /dev/null
+++ b/nixpkgs/nixos/modules/config/fonts/fontconfig-penultimate.nix
@@ -0,0 +1,292 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+  cfg = config.fonts.fontconfig;
+
+  fcBool = x: "<bool>" + (boolToString x) + "</bool>";
+
+  # back-supported fontconfig version and package
+  # version is used for font cache generation
+  supportVersion = "210";
+  supportPkg     = pkgs."fontconfig_${supportVersion}";
+
+  # latest fontconfig version and package
+  # version is used for configuration folder name, /etc/fonts/VERSION/
+  # note: format differs from supportVersion and can not be used with makeCacheConf
+  latestVersion  = pkgs.fontconfig.configVersion;
+  latestPkg      = pkgs.fontconfig;
+
+  # supported version fonts.conf
+  supportFontsConf = pkgs.makeFontsConf { fontconfig = supportPkg; fontDirectories = config.fonts.fonts; };
+
+  # configuration file to read fontconfig cache
+  # version dependent
+  # priority 0
+  cacheConfSupport = makeCacheConf { version = supportVersion; };
+  cacheConfLatest  = makeCacheConf {};
+
+  # generate the font cache setting file for a fontconfig version
+  # use latest when no version is passed
+  makeCacheConf = { version ? null }:
+    let
+      fcPackage = if version == null
+                  then "fontconfig"
+                  else "fontconfig_${version}";
+      makeCache = fontconfig: pkgs.makeFontsCache { inherit fontconfig; fontDirectories = config.fonts.fonts; };
+      cache     = makeCache pkgs.${fcPackage};
+      cache32   = makeCache pkgs.pkgsi686Linux.${fcPackage};
+    in
+    pkgs.writeText "fc-00-nixos-cache.conf" ''
+      <?xml version='1.0'?>
+      <!DOCTYPE fontconfig SYSTEM 'fonts.dtd'>
+      <fontconfig>
+        <!-- Font directories -->
+        ${concatStringsSep "\n" (map (font: "<dir>${font}</dir>") config.fonts.fonts)}
+        <!-- Pre-generated font caches -->
+        <cachedir>${cache}</cachedir>
+        ${optionalString (pkgs.stdenv.isx86_64 && cfg.cache32Bit) ''
+          <cachedir>${cache32}</cachedir>
+        ''}
+      </fontconfig>
+    '';
+
+  # local configuration file
+  localConf = pkgs.writeText "fc-local.conf" cfg.localConf;
+
+  # rendering settings configuration files
+  # priority 10
+  hintingConf = pkgs.writeText "fc-10-hinting.conf" ''
+    <?xml version='1.0'?>
+    <!DOCTYPE fontconfig SYSTEM 'fonts.dtd'>
+    <fontconfig>
+
+      <!-- Default rendering settings -->
+      <match target="pattern">
+        <edit mode="append" name="hinting">
+          ${fcBool cfg.hinting.enable}
+        </edit>
+        <edit mode="append" name="autohint">
+          ${fcBool cfg.hinting.autohint}
+        </edit>
+        <edit mode="append" name="hintstyle">
+          <const>hintslight</const>
+        </edit>
+      </match>
+
+    </fontconfig>
+  '';
+
+  antialiasConf = pkgs.writeText "fc-10-antialias.conf" ''
+    <?xml version='1.0'?>
+    <!DOCTYPE fontconfig SYSTEM 'fonts.dtd'>
+    <fontconfig>
+
+      <!-- Default rendering settings -->
+      <match target="pattern">
+        <edit mode="append" name="antialias">
+          ${fcBool cfg.antialias}
+        </edit>
+      </match>
+
+    </fontconfig>
+  '';
+
+  subpixelConf = pkgs.writeText "fc-10-subpixel.conf" ''
+    <?xml version='1.0'?>
+    <!DOCTYPE fontconfig SYSTEM 'fonts.dtd'>
+    <fontconfig>
+
+      <!-- Default rendering settings -->
+      <match target="pattern">
+        <edit mode="append" name="rgba">
+          <const>${cfg.subpixel.rgba}</const>
+        </edit>
+        <edit mode="append" name="lcdfilter">
+          <const>lcd${cfg.subpixel.lcdfilter}</const>
+        </edit>
+      </match>
+
+    </fontconfig>
+  '';
+
+  dpiConf = pkgs.writeText "fc-11-dpi.conf" ''
+    <?xml version='1.0'?>
+    <!DOCTYPE fontconfig SYSTEM 'fonts.dtd'>
+    <fontconfig>
+
+      <match target="pattern">
+        <edit name="dpi" mode="assign">
+          <double>${toString cfg.dpi}</double>
+        </edit>
+      </match>
+
+    </fontconfig>
+  '';
+
+  # default fonts configuration file
+  # priority 52
+  defaultFontsConf =
+    let genDefault = fonts: name:
+      optionalString (fonts != []) ''
+        <alias>
+          <family>${name}</family>
+          <prefer>
+          ${concatStringsSep ""
+          (map (font: ''
+            <family>${font}</family>
+          '') fonts)}
+          </prefer>
+        </alias>
+      '';
+    in
+    pkgs.writeText "fc-52-nixos-default-fonts.conf" ''
+    <?xml version='1.0'?>
+    <!DOCTYPE fontconfig SYSTEM 'fonts.dtd'>
+    <fontconfig>
+
+      <!-- Default fonts -->
+      ${genDefault cfg.defaultFonts.sansSerif "sans-serif"}
+
+      ${genDefault cfg.defaultFonts.serif     "serif"}
+
+      ${genDefault cfg.defaultFonts.monospace "monospace"}
+
+    </fontconfig>
+  '';
+
+  # reject Type 1 fonts
+  # priority 53
+  rejectType1 = pkgs.writeText "fc-53-nixos-reject-type1.conf" ''
+    <?xml version="1.0"?>
+    <!DOCTYPE fontconfig SYSTEM "fonts.dtd">
+    <fontconfig>
+
+    <!-- Reject Type 1 fonts -->
+    <selectfont>
+      <rejectfont>
+        <pattern>
+          <patelt name="fontformat"><string>Type 1</string></patelt>
+        </pattern>
+      </rejectfont>
+    </selectfont>
+
+    </fontconfig>
+  '';
+
+  # The configuration to be included in /etc/font/
+  penultimateConf = pkgs.runCommand "fontconfig-penultimate-conf" {
+    preferLocalBuild = true;
+  } ''
+    support_folder=$out/etc/fonts/conf.d
+    latest_folder=$out/etc/fonts/${latestVersion}/conf.d
+
+    mkdir -p $support_folder
+    mkdir -p $latest_folder
+
+    # fonts.conf
+    ln -s ${supportFontsConf} $support_folder/../fonts.conf
+    ln -s ${latestPkg.out}/etc/fonts/fonts.conf \
+          $latest_folder/../fonts.conf
+
+    # fontconfig-penultimate various configuration files
+    ln -s ${pkgs.fontconfig-penultimate}/etc/fonts/conf.d/*.conf \
+          $support_folder
+    ln -s ${pkgs.fontconfig-penultimate}/etc/fonts/conf.d/*.conf \
+          $latest_folder
+
+    ln -s ${cacheConfSupport} $support_folder/00-nixos-cache.conf
+    ln -s ${cacheConfLatest}  $latest_folder/00-nixos-cache.conf
+
+    rm $support_folder/10-antialias.conf $latest_folder/10-antialias.conf
+    ln -s ${antialiasConf} $support_folder/10-antialias.conf
+    ln -s ${antialiasConf} $latest_folder/10-antialias.conf
+
+    rm $support_folder/10-hinting.conf $latest_folder/10-hinting.conf
+    ln -s ${hintingConf} $support_folder/10-hinting.conf
+    ln -s ${hintingConf} $latest_folder/10-hinting.conf
+
+    ${optionalString cfg.useEmbeddedBitmaps ''
+    rm $support_folder/10-no-embedded-bitmaps.conf
+    rm $latest_folder/10-no-embedded-bitmaps.conf
+    ''}
+
+    rm $support_folder/10-subpixel.conf $latest_folder/10-subpixel.conf
+    ln -s ${subpixelConf} $support_folder/10-subpixel.conf
+    ln -s ${subpixelConf} $latest_folder/10-subpixel.conf
+
+    ${optionalString (cfg.dpi != 0) ''
+    ln -s ${dpiConf} $support_folder/11-dpi.conf
+    ln -s ${dpiConf} $latest_folder/11-dpi.conf
+    ''}
+
+    # 50-user.conf
+    ${optionalString (!cfg.includeUserConf) ''
+    rm $support_folder/50-user.conf
+    rm $latest_folder/50-user.conf
+    ''}
+
+    # 51-local.conf
+    rm $latest_folder/51-local.conf
+    substitute \
+      ${pkgs.fontconfig-penultimate}/etc/fonts/conf.d/51-local.conf \
+      $latest_folder/51-local.conf \
+      --replace local.conf /etc/fonts/${latestVersion}/local.conf
+
+    # local.conf (indirect priority 51)
+    ${optionalString (cfg.localConf != "") ''
+    ln -s ${localConf}        $support_folder/../local.conf
+    ln -s ${localConf}        $latest_folder/../local.conf
+    ''}
+
+    # 52-nixos-default-fonts.conf
+    ln -s ${defaultFontsConf} $support_folder/52-nixos-default-fonts.conf
+    ln -s ${defaultFontsConf} $latest_folder/52-nixos-default-fonts.conf
+
+    # 53-no-bitmaps.conf
+    ${optionalString cfg.allowBitmaps ''
+    rm $support_folder/53-no-bitmaps.conf
+    rm $latest_folder/53-no-bitmaps.conf
+    ''}
+
+    ${optionalString (!cfg.allowType1) ''
+    # 53-nixos-reject-type1.conf
+    ln -s ${rejectType1} $support_folder/53-nixos-reject-type1.conf
+    ln -s ${rejectType1} $latest_folder/53-nixos-reject-type1.conf
+    ''}
+  '';
+
+in
+{
+
+  options = {
+
+    fonts = {
+
+      fontconfig = {
+
+        penultimate = {
+          enable = mkOption {
+            type = types.bool;
+            default = false;
+            description = ''
+              Enable fontconfig-penultimate settings to supplement the
+              NixOS defaults by providing per-font rendering defaults and
+              metric aliases.
+            '';
+          };
+        };
+
+      };
+    };
+
+  };
+
+  config = mkIf (config.fonts.fontconfig.enable && config.fonts.fontconfig.penultimate.enable) {
+
+    fonts.fontconfig.confPackages = [ penultimateConf ];
+
+  };
+
+}
diff --git a/nixpkgs/nixos/modules/config/fonts/fontconfig-ultimate.nix b/nixpkgs/nixos/modules/config/fonts/fontconfig-ultimate.nix
new file mode 100644
index 000000000000..84d90899dfff
--- /dev/null
+++ b/nixpkgs/nixos/modules/config/fonts/fontconfig-ultimate.nix
@@ -0,0 +1,86 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let cfg = config.fonts.fontconfig.ultimate;
+
+    latestVersion  = pkgs.fontconfig.configVersion;
+
+    # The configuration to be included in /etc/font/
+    confPkg = pkgs.runCommand "font-ultimate-conf" { preferLocalBuild = true; } ''
+      support_folder=$out/etc/fonts/conf.d
+      latest_folder=$out/etc/fonts/${latestVersion}/conf.d
+
+      mkdir -p $support_folder
+      mkdir -p $latest_folder
+
+      # fontconfig ultimate substitutions
+      ${optionalString (cfg.substitutions != "none") ''
+      ln -s ${pkgs.fontconfig-ultimate}/etc/fonts/presets/${cfg.substitutions}/*.conf \
+            $support_folder
+      ln -s ${pkgs.fontconfig-ultimate}/etc/fonts/presets/${cfg.substitutions}/*.conf \
+            $latest_folder
+      ''}
+
+      # fontconfig ultimate various configuration files
+      ln -s ${pkgs.fontconfig-ultimate}/etc/fonts/conf.d/*.conf \
+            $support_folder
+      ln -s ${pkgs.fontconfig-ultimate}/etc/fonts/conf.d/*.conf \
+            $latest_folder
+    '';
+
+in
+{
+
+  options = {
+
+    fonts = {
+
+      fontconfig = {
+
+        ultimate = {
+          enable = mkOption {
+            type = types.bool;
+            default = false;
+            description = ''
+              Enable fontconfig-ultimate settings (formerly known as
+              Infinality). Besides the customizable settings in this NixOS
+              module, fontconfig-ultimate also provides many font-specific
+              rendering tweaks.
+            '';
+          };
+
+          substitutions = mkOption {
+            type = types.enum ["free" "combi" "ms" "none"];
+            default = "free";
+            description = ''
+              Font substitutions to replace common Type 1 fonts with nicer
+              TrueType fonts. <literal>free</literal> uses free fonts,
+              <literal>ms</literal> uses Microsoft fonts,
+              <literal>combi</literal> uses a combination, and
+              <literal>none</literal> disables the substitutions.
+            '';
+          };
+
+          preset = mkOption {
+            type = types.enum ["ultimate1" "ultimate2" "ultimate3" "ultimate4" "ultimate5" "osx" "windowsxp"];
+            default = "ultimate3";
+            description = ''
+              FreeType rendering settings preset. Any of the presets may be
+              customized by setting environment variables.
+            '';
+          };
+        };
+      };
+    };
+
+  };
+
+  config = mkIf (config.fonts.fontconfig.enable && cfg.enable) {
+
+    fonts.fontconfig.confPackages = [ confPkg ];
+    environment.variables.INFINALITY_FT = cfg.preset;
+
+  };
+
+}
diff --git a/nixpkgs/nixos/modules/config/fonts/fontconfig.nix b/nixpkgs/nixos/modules/config/fonts/fontconfig.nix
new file mode 100644
index 000000000000..8f227c423266
--- /dev/null
+++ b/nixpkgs/nixos/modules/config/fonts/fontconfig.nix
@@ -0,0 +1,476 @@
+/*
+
+NixOS support 2 fontconfig versions, "support" and "latest".
+
+- "latest" refers to default fontconfig package (pkgs.fontconfig).
+  configuration files are linked to /etc/fonts/VERSION/conf.d/
+- "support" refers to supportPkg (pkgs."fontconfig_${supportVersion}").
+  configuration files are linked to /etc/fonts/conf.d/
+
+This module generates a package containing configuration files and link it in /etc/fonts.
+
+Fontconfig reads files in folder name / file name order, so the number prepended to the configuration file name decide the order of parsing.
+Low number means high priority.
+
+*/
+
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+  cfg = config.fonts.fontconfig;
+
+  fcBool = x: "<bool>" + (boolToString x) + "</bool>";
+
+  # back-supported fontconfig version and package
+  # version is used for font cache generation
+  supportVersion = "210";
+  supportPkg     = pkgs."fontconfig_${supportVersion}";
+
+  # latest fontconfig version and package
+  # version is used for configuration folder name, /etc/fonts/VERSION/
+  # note: format differs from supportVersion and can not be used with makeCacheConf
+  latestVersion  = pkgs.fontconfig.configVersion;
+  latestPkg      = pkgs.fontconfig;
+
+  # supported version fonts.conf
+  supportFontsConf = pkgs.makeFontsConf { fontconfig = supportPkg; fontDirectories = config.fonts.fonts; };
+
+  # configuration file to read fontconfig cache
+  # version dependent
+  # priority 0
+  cacheConfSupport = makeCacheConf { version = supportVersion; };
+  cacheConfLatest  = makeCacheConf {};
+
+  # generate the font cache setting file for a fontconfig version
+  # use latest when no version is passed
+  makeCacheConf = { version ? null }:
+    let
+      fcPackage = if version == null
+                  then "fontconfig"
+                  else "fontconfig_${version}";
+      makeCache = fontconfig: pkgs.makeFontsCache { inherit fontconfig; fontDirectories = config.fonts.fonts; };
+      cache     = makeCache pkgs.${fcPackage};
+      cache32   = makeCache pkgs.pkgsi686Linux.${fcPackage};
+    in
+    pkgs.writeText "fc-00-nixos-cache.conf" ''
+      <?xml version='1.0'?>
+      <!DOCTYPE fontconfig SYSTEM 'fonts.dtd'>
+      <fontconfig>
+        <!-- Font directories -->
+        ${concatStringsSep "\n" (map (font: "<dir>${font}</dir>") config.fonts.fonts)}
+        <!-- Pre-generated font caches -->
+        <cachedir>${cache}</cachedir>
+        ${optionalString (pkgs.stdenv.isx86_64 && cfg.cache32Bit) ''
+          <cachedir>${cache32}</cachedir>
+        ''}
+      </fontconfig>
+    '';
+
+  # rendering settings configuration file
+  # priority 10
+  renderConf = pkgs.writeText "fc-10-nixos-rendering.conf" ''
+    <?xml version='1.0'?>
+    <!DOCTYPE fontconfig SYSTEM 'fonts.dtd'>
+    <fontconfig>
+
+      <!-- Default rendering settings -->
+      <match target="pattern">
+        <edit mode="append" name="hinting">
+          ${fcBool cfg.hinting.enable}
+        </edit>
+        <edit mode="append" name="autohint">
+          ${fcBool cfg.hinting.autohint}
+        </edit>
+        <edit mode="append" name="hintstyle">
+          <const>hintslight</const>
+        </edit>
+        <edit mode="append" name="antialias">
+          ${fcBool cfg.antialias}
+        </edit>
+        <edit mode="append" name="rgba">
+          <const>${cfg.subpixel.rgba}</const>
+        </edit>
+        <edit mode="append" name="lcdfilter">
+          <const>lcd${cfg.subpixel.lcdfilter}</const>
+        </edit>
+      </match>
+
+      ${optionalString (cfg.dpi != 0) ''
+      <match target="pattern">
+        <edit name="dpi" mode="assign">
+          <double>${toString cfg.dpi}</double>
+        </edit>
+      </match>
+      ''}
+
+    </fontconfig>
+  '';
+
+  # local configuration file
+  localConf = pkgs.writeText "fc-local.conf" cfg.localConf;
+
+  # default fonts configuration file
+  # priority 52
+  defaultFontsConf =
+    let genDefault = fonts: name:
+      optionalString (fonts != []) ''
+        <alias binding="same">
+          <family>${name}</family>
+          <prefer>
+          ${concatStringsSep ""
+          (map (font: ''
+            <family>${font}</family>
+          '') fonts)}
+          </prefer>
+        </alias>
+      '';
+    in
+    pkgs.writeText "fc-52-nixos-default-fonts.conf" ''
+    <?xml version='1.0'?>
+    <!DOCTYPE fontconfig SYSTEM 'fonts.dtd'>
+    <fontconfig>
+
+      <!-- Default fonts -->
+      ${genDefault cfg.defaultFonts.sansSerif "sans-serif"}
+
+      ${genDefault cfg.defaultFonts.serif     "serif"}
+
+      ${genDefault cfg.defaultFonts.monospace "monospace"}
+
+      ${genDefault cfg.defaultFonts.emoji "emoji"}
+
+    </fontconfig>
+  '';
+
+  # bitmap font options
+  # priority 53
+  rejectBitmaps = pkgs.writeText "fc-53-no-bitmaps.conf" ''
+    <?xml version="1.0"?>
+    <!DOCTYPE fontconfig SYSTEM "fonts.dtd">
+    <fontconfig>
+
+    ${optionalString (!cfg.allowBitmaps) ''
+    <!-- Reject bitmap fonts -->
+    <selectfont>
+      <rejectfont>
+        <pattern>
+          <patelt name="scalable"><bool>false</bool></patelt>
+        </pattern>
+      </rejectfont>
+    </selectfont>
+    ''}
+
+    <!-- Use embedded bitmaps in fonts like Calibri? -->
+    <match target="font">
+      <edit name="embeddedbitmap" mode="assign">
+        ${fcBool cfg.useEmbeddedBitmaps}
+      </edit>
+    </match>
+
+    </fontconfig>
+  '';
+
+  # reject Type 1 fonts
+  # priority 53
+  rejectType1 = pkgs.writeText "fc-53-nixos-reject-type1.conf" ''
+    <?xml version="1.0"?>
+    <!DOCTYPE fontconfig SYSTEM "fonts.dtd">
+    <fontconfig>
+
+    <!-- Reject Type 1 fonts -->
+    <selectfont>
+      <rejectfont>
+        <pattern>
+          <patelt name="fontformat"><string>Type 1</string></patelt>
+        </pattern>
+      </rejectfont>
+    </selectfont>
+
+    </fontconfig>
+  '';
+
+  # fontconfig configuration package
+  confPkg = pkgs.runCommand "fontconfig-conf" {
+    preferLocalBuild = true;
+  } ''
+    support_folder=$out/etc/fonts/conf.d
+    latest_folder=$out/etc/fonts/${latestVersion}/conf.d
+
+    mkdir -p $support_folder
+    mkdir -p $latest_folder
+
+    # fonts.conf
+    ln -s ${supportFontsConf} $support_folder/../fonts.conf
+    ln -s ${latestPkg.out}/etc/fonts/fonts.conf \
+          $latest_folder/../fonts.conf
+
+    # fontconfig default config files
+    ln -s ${supportPkg.out}/etc/fonts/conf.d/*.conf \
+          $support_folder/
+    ln -s ${latestPkg.out}/etc/fonts/conf.d/*.conf \
+          $latest_folder/
+
+    # update latest 51-local.conf path to look at the latest local.conf
+    rm    $latest_folder/51-local.conf
+
+    substitute ${latestPkg.out}/etc/fonts/conf.d/51-local.conf \
+               $latest_folder/51-local.conf \
+               --replace local.conf /etc/fonts/${latestVersion}/local.conf
+
+    # 00-nixos-cache.conf
+    ln -s ${cacheConfSupport} \
+          $support_folder/00-nixos-cache.conf
+    ln -s ${cacheConfLatest}  $latest_folder/00-nixos-cache.conf
+
+    # 10-nixos-rendering.conf
+    ln -s ${renderConf}       $support_folder/10-nixos-rendering.conf
+    ln -s ${renderConf}       $latest_folder/10-nixos-rendering.conf
+
+    # 50-user.conf
+    ${optionalString (!cfg.includeUserConf) ''
+    rm $support_folder/50-user.conf
+    rm $latest_folder/50-user.conf
+    ''}
+
+    # local.conf (indirect priority 51)
+    ${optionalString (cfg.localConf != "") ''
+    ln -s ${localConf}        $support_folder/../local.conf
+    ln -s ${localConf}        $latest_folder/../local.conf
+    ''}
+
+    # 52-nixos-default-fonts.conf
+    ln -s ${defaultFontsConf} $support_folder/52-nixos-default-fonts.conf
+    ln -s ${defaultFontsConf} $latest_folder/52-nixos-default-fonts.conf
+
+    # 53-no-bitmaps.conf
+    ln -s ${rejectBitmaps} $support_folder/53-no-bitmaps.conf
+    ln -s ${rejectBitmaps} $latest_folder/53-no-bitmaps.conf
+
+    ${optionalString (!cfg.allowType1) ''
+    # 53-nixos-reject-type1.conf
+    ln -s ${rejectType1} $support_folder/53-nixos-reject-type1.conf
+    ln -s ${rejectType1} $latest_folder/53-nixos-reject-type1.conf
+    ''}
+  '';
+
+  # Package with configuration files
+  # this merge all the packages in the fonts.fontconfig.confPackages list
+  fontconfigEtc = pkgs.buildEnv {
+    name  = "fontconfig-etc";
+    paths = cfg.confPackages;
+    ignoreCollisions = true;
+  };
+in
+{
+
+  options = {
+
+    fonts = {
+
+      fontconfig = {
+        enable = mkOption {
+          type = types.bool;
+          default = true;
+          description = ''
+            If enabled, a Fontconfig configuration file will be built
+            pointing to a set of default fonts.  If you don't care about
+            running X11 applications or any other program that uses
+            Fontconfig, you can turn this option off and prevent a
+            dependency on all those fonts.
+          '';
+        };
+
+        confPackages = mkOption {
+          internal = true;
+          type     = with types; listOf path;
+          default  = [ ];
+          description = ''
+            Fontconfig configuration packages.
+          '';
+        };
+
+        antialias = mkOption {
+          type = types.bool;
+          default = true;
+          description = ''
+            Enable font antialiasing. At high resolution (> 200 DPI),
+            antialiasing has no visible effect; users of such displays may want
+            to disable this option.
+          '';
+        };
+
+        dpi = mkOption {
+          type = types.int;
+          default = 0;
+          description = ''
+            Force DPI setting. Setting to <literal>0</literal> disables DPI
+            forcing; the DPI detected for the display will be used.
+          '';
+        };
+
+        localConf = mkOption {
+          type = types.lines;
+          default = "";
+          description = ''
+            System-wide customization file contents, has higher priority than
+            <literal>defaultFonts</literal> settings.
+          '';
+        };
+
+        defaultFonts = {
+          monospace = mkOption {
+            type = types.listOf types.str;
+            default = ["DejaVu Sans Mono"];
+            description = ''
+              System-wide default monospace font(s). Multiple fonts may be
+              listed in case multiple languages must be supported.
+            '';
+          };
+
+          sansSerif = mkOption {
+            type = types.listOf types.str;
+            default = ["DejaVu Sans"];
+            description = ''
+              System-wide default sans serif font(s). Multiple fonts may be
+              listed in case multiple languages must be supported.
+            '';
+          };
+
+          serif = mkOption {
+            type = types.listOf types.str;
+            default = ["DejaVu Serif"];
+            description = ''
+              System-wide default serif font(s). Multiple fonts may be listed
+              in case multiple languages must be supported.
+            '';
+          };
+
+          emoji = mkOption {
+            type = types.listOf types.str;
+            default = ["Noto Color Emoji"];
+            description = ''
+              System-wide default emoji font(s). Multiple fonts may be listed
+              in case a font does not support all emoji.
+
+              Note that fontconfig matches color emoji fonts preferentially,
+              so if you want to use a black and white font while having
+              a color font installed (eg. Noto Color Emoji installed alongside
+              Noto Emoji), fontconfig will still choose the color font even
+              when it is later in the list.
+            '';
+          };
+        };
+
+        hinting = {
+          enable = mkOption {
+            type = types.bool;
+            default = true;
+            description = ''
+              Enable font hinting. Hinting aligns glyphs to pixel boundaries to
+              improve rendering sharpness at low resolution. At high resolution
+              (> 200 dpi) hinting will do nothing (at best); users of such
+              displays may want to disable this option.
+            '';
+          };
+
+          autohint = mkOption {
+            type = types.bool;
+            default = false;
+            description = ''
+              Enable the autohinter in place of the default interpreter.
+              The results are usually lower quality than correctly-hinted
+              fonts, but better than unhinted fonts.
+            '';
+          };
+        };
+
+        includeUserConf = mkOption {
+          type = types.bool;
+          default = true;
+          description = ''
+            Include the user configuration from
+            <filename>~/.config/fontconfig/fonts.conf</filename> or
+            <filename>~/.config/fontconfig/conf.d</filename>.
+          '';
+        };
+
+        subpixel = {
+
+          rgba = mkOption {
+            default = "rgb";
+            type = types.enum ["rgb" "bgr" "vrgb" "vbgr" "none"];
+            description = ''
+              Subpixel order. The overwhelming majority of displays are
+              <literal>rgb</literal> in their normal orientation. Select
+              <literal>vrgb</literal> for mounting such a display 90 degrees
+              clockwise from its normal orientation or <literal>vbgr</literal>
+              for mounting 90 degrees counter-clockwise. Select
+              <literal>bgr</literal> in the unlikely event of mounting 180
+              degrees from the normal orientation. Reverse these directions in
+              the improbable event that the display's native subpixel order is
+              <literal>bgr</literal>.
+            '';
+          };
+
+          lcdfilter = mkOption {
+            default = "default";
+            type = types.enum ["none" "default" "light" "legacy"];
+            description = ''
+              FreeType LCD filter. At high resolution (> 200 DPI), LCD filtering
+              has no visible effect; users of such displays may want to select
+              <literal>none</literal>.
+            '';
+          };
+
+        };
+
+        cache32Bit = mkOption {
+          default = false;
+          type = types.bool;
+          description = ''
+            Generate system fonts cache for 32-bit applications.
+          '';
+        };
+
+        allowBitmaps = mkOption {
+          type = types.bool;
+          default = true;
+          description = ''
+            Allow bitmap fonts. Set to <literal>false</literal> to ban all
+            bitmap fonts.
+          '';
+        };
+
+        allowType1 = mkOption {
+          type = types.bool;
+          default = false;
+          description = ''
+            Allow Type-1 fonts. Default is <literal>false</literal> because of
+            poor rendering.
+          '';
+        };
+
+        useEmbeddedBitmaps = mkOption {
+          type = types.bool;
+          default = false;
+          description = ''Use embedded bitmaps in fonts like Calibri.'';
+        };
+
+      };
+
+    };
+
+  };
+  config = mkMerge [
+    (mkIf cfg.enable {
+      environment.systemPackages    = [ pkgs.fontconfig ];
+      environment.etc.fonts.source  = "${fontconfigEtc}/etc/fonts/";
+    })
+    (mkIf (cfg.enable && !cfg.penultimate.enable) {
+      fonts.fontconfig.confPackages = [ confPkg ];
+    })
+  ];
+
+}
diff --git a/nixpkgs/nixos/modules/config/fonts/fontdir.nix b/nixpkgs/nixos/modules/config/fonts/fontdir.nix
new file mode 100644
index 000000000000..cc70fbf8744d
--- /dev/null
+++ b/nixpkgs/nixos/modules/config/fonts/fontdir.nix
@@ -0,0 +1,47 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  x11Fonts = pkgs.runCommand "X11-fonts" { preferLocalBuild = true; } ''
+    mkdir -p "$out/share/X11-fonts"
+    find ${toString config.fonts.fonts} \
+      \( -name fonts.dir -o -name '*.ttf' -o -name '*.otf' \) \
+      -exec ln -sf -t "$out/share/X11-fonts" '{}' \;
+    cd "$out/share/X11-fonts"
+    rm -f fonts.dir fonts.scale fonts.alias
+    ${pkgs.xorg.mkfontdir}/bin/mkfontdir
+    ${pkgs.xorg.mkfontscale}/bin/mkfontscale
+    cat $(find ${pkgs.xorg.fontalias}/ -name fonts.alias) >fonts.alias
+  '';
+
+in
+
+{
+
+  options = {
+
+    fonts = {
+
+      enableFontDir = mkOption {
+        default = false;
+        description = ''
+          Whether to create a directory with links to all fonts in
+          <filename>/run/current-system/sw/share/X11-fonts</filename>.
+        '';
+      };
+
+    };
+
+  };
+
+  config = mkIf config.fonts.enableFontDir {
+
+    environment.systemPackages = [ x11Fonts ];
+
+    environment.pathsToLink = [ "/share/X11-fonts" ];
+
+  };
+
+}
diff --git a/nixpkgs/nixos/modules/config/fonts/fonts.nix b/nixpkgs/nixos/modules/config/fonts/fonts.nix
new file mode 100644
index 000000000000..abb806b601a7
--- /dev/null
+++ b/nixpkgs/nixos/modules/config/fonts/fonts.nix
@@ -0,0 +1,51 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+
+  options = {
+
+    fonts = {
+
+      # TODO: find another name for it.
+      fonts = mkOption {
+        type = types.listOf types.path;
+        default = [];
+        example = literalExample "[ pkgs.dejavu_fonts ]";
+        description = "List of primary font paths.";
+      };
+
+      enableDefaultFonts = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Enable a basic set of fonts providing several font styles
+          and families and reasonable coverage of Unicode.
+        '';
+      };
+
+    };
+
+  };
+
+  config = {
+
+    fonts.fonts = mkIf config.fonts.enableDefaultFonts
+      [
+        pkgs.xorg.fontbhlucidatypewriter100dpi
+        pkgs.xorg.fontbhlucidatypewriter75dpi
+        pkgs.dejavu_fonts
+        pkgs.freefont_ttf
+        pkgs.gyre-fonts # TrueType substitutes for standard PostScript fonts
+        pkgs.liberation_ttf
+        pkgs.xorg.fontbh100dpi
+        pkgs.xorg.fontmiscmisc
+        pkgs.xorg.fontcursormisc
+        pkgs.unifont
+        pkgs.noto-fonts-emoji
+      ];
+
+  };
+
+}
diff --git a/nixpkgs/nixos/modules/config/fonts/ghostscript.nix b/nixpkgs/nixos/modules/config/fonts/ghostscript.nix
new file mode 100644
index 000000000000..1c62a525de94
--- /dev/null
+++ b/nixpkgs/nixos/modules/config/fonts/ghostscript.nix
@@ -0,0 +1,32 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+
+  options = {
+
+    fonts = {
+
+      enableGhostscriptFonts = mkOption {
+        default = false;
+        description = ''
+          Whether to add the fonts provided by Ghostscript (such as
+          various URW fonts and the “Base-14” Postscript fonts) to the
+          list of system fonts, making them available to X11
+          applications.
+        '';
+      };
+
+    };
+
+  };
+
+
+  config = mkIf config.fonts.enableGhostscriptFonts {
+
+    fonts.fonts = [ "${pkgs.ghostscript}/share/ghostscript/fonts" ];
+
+  };
+
+}
diff --git a/nixpkgs/nixos/modules/config/gnu.nix b/nixpkgs/nixos/modules/config/gnu.nix
new file mode 100644
index 000000000000..93d130970190
--- /dev/null
+++ b/nixpkgs/nixos/modules/config/gnu.nix
@@ -0,0 +1,46 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+  options = {
+    gnu = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        When enabled, GNU software is chosen by default whenever a there is
+        a choice between GNU and non-GNU software (e.g., GNU lsh
+        vs. OpenSSH).
+      '';
+    };
+  };
+
+  config = mkIf config.gnu {
+
+    environment.systemPackages = with pkgs;
+      # TODO: Adjust `requiredPackages' from `system-path.nix'.
+      # TODO: Add Inetutils once it has the new `ifconfig'.
+      [ parted
+        #fdisk  # XXX: GNU fdisk currently fails to build and it's redundant
+                # with the `parted' command.
+        nano zile
+        texinfo # for the stand-alone Info reader
+      ]
+      ++ stdenv.lib.optional (!stdenv.isAarch32) grub2;
+
+
+    # GNU GRUB, where available.
+    boot.loader.grub.enable = !pkgs.stdenv.isAarch32;
+    boot.loader.grub.version = 2;
+
+    # GNU lsh.
+    services.openssh.enable = false;
+    services.lshd.enable = true;
+    programs.ssh.startAgent = false;
+    services.xserver.startGnuPGAgent = true;
+
+    # TODO: GNU dico.
+    # TODO: GNU Inetutils' inetd.
+    # TODO: GNU Pies.
+  };
+}
diff --git a/nixpkgs/nixos/modules/config/gtk/gtk-icon-cache.nix b/nixpkgs/nixos/modules/config/gtk/gtk-icon-cache.nix
new file mode 100644
index 000000000000..86a6bfb5af41
--- /dev/null
+++ b/nixpkgs/nixos/modules/config/gtk/gtk-icon-cache.nix
@@ -0,0 +1,86 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+{
+  options = {
+    gtk.iconCache.enable = mkOption {
+      type = types.bool;
+      default = config.services.xserver.enable;
+      description = ''
+        Whether to build icon theme caches for GTK applications.
+      '';
+    };
+  };
+
+  config = mkIf config.gtk.iconCache.enable {
+
+    # (Re)build icon theme caches
+    # ---------------------------
+    # Each icon theme has its own cache. The difficult is that many
+    # packages may contribute with icons to the same theme by installing
+    # some icons.
+    #
+    # For instance, on my current NixOS system, the following packages
+    # (among many others) have icons installed into the hicolor icon
+    # theme: hicolor-icon-theme, psensor, wpa_gui, caja, etc.
+    #
+    # As another example, the mate icon theme has icons installed by the
+    # packages mate-icon-theme, mate-settings-daemon, and libmateweather.
+    #
+    # The HighContrast icon theme also has icons from different packages,
+    # like gnome-theme-extras and meld.
+
+    # When the cache is built all of its icons has to be known. How to
+    # implement this?
+    #
+    # I think that most themes have all icons installed by only one
+    # package. On my system there are 71 themes installed. Only 3 of them
+    # have icons installed from more than one package.
+    #
+    # If the main package of the theme provides a cache, presumably most
+    # of its icons will be available to applications without running this
+    # module. But additional icons offered by other packages will not be
+    # available. Therefore I think that it is good that the main theme
+    # package installs a cache (although it does not completely fixes the
+    # situation for packages installed with nix-env).
+    #
+    # The module solution presented here keeps the cache when there is
+    # only one package contributing with icons to the theme. Otherwise it
+    # rebuilds the cache taking into account the icons provided all
+    # packages.
+
+    environment.extraSetup = ''
+      # For each icon theme directory ...
+
+      find $out/share/icons -mindepth 1 -maxdepth 1 -print0 | while read -d $'\0' themedir
+      do
+
+        # In order to build the cache, the theme dir should be
+        # writable. When the theme dir is a symbolic link to somewhere
+        # in the nix store it is not writable and it means that only
+        # one package is contributing to the theme. If it already has
+        # a cache, no rebuild is needed. Otherwise a cache has to be
+        # built, and to be able to do that we first remove the
+        # symbolic link and make a directory, and then make symbolic
+        # links from the original directory into the new one.
+
+        if [ ! -w "$themedir" -a -L "$themedir" -a ! -r "$themedir"/icon-theme.cache ]; then
+          name=$(basename "$themedir")
+          path=$(readlink -f "$themedir")
+          rm "$themedir"
+          mkdir -p "$themedir"
+          ln -s "$path"/* "$themedir"/
+        fi
+
+        # (Re)build the cache if the theme dir is writable, replacing any
+        # existing cache for the theme
+
+        if [ -w "$themedir" ]; then
+          rm -f "$themedir"/icon-theme.cache
+          ${pkgs.gtk3.out}/bin/gtk-update-icon-cache --ignore-theme-index "$themedir"
+        fi
+      done
+    '';
+  };
+
+}
diff --git a/nixpkgs/nixos/modules/config/i18n.nix b/nixpkgs/nixos/modules/config/i18n.nix
new file mode 100644
index 000000000000..dc7305b1ba24
--- /dev/null
+++ b/nixpkgs/nixos/modules/config/i18n.nix
@@ -0,0 +1,160 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+  ###### interface
+
+  options = {
+
+    i18n = {
+      glibcLocales = mkOption {
+        type = types.path;
+        default = pkgs.buildPackages.glibcLocales.override {
+          allLocales = any (x: x == "all") config.i18n.supportedLocales;
+          locales = config.i18n.supportedLocales;
+        };
+        example = literalExample "pkgs.glibcLocales";
+        description = ''
+          Customized pkg.glibcLocales package.
+
+          Changing this option can disable handling of i18n.defaultLocale
+          and supportedLocale.
+        '';
+      };
+
+      defaultLocale = mkOption {
+        type = types.str;
+        default = "en_US.UTF-8";
+        example = "nl_NL.UTF-8";
+        description = ''
+          The default locale.  It determines the language for program
+          messages, the format for dates and times, sort order, and so on.
+          It also determines the character set, such as UTF-8.
+        '';
+      };
+
+      extraLocaleSettings = mkOption {
+        type = types.attrsOf types.str;
+        default = {};
+        example = { LC_MESSAGES = "en_US.UTF-8"; LC_TIME = "de_DE.UTF-8"; };
+        description = ''
+          A set of additional system-wide locale settings other than
+          <literal>LANG</literal> which can be configured with
+          <option>i18n.defaultLocale</option>.
+        '';
+      };
+
+      supportedLocales = mkOption {
+        type = types.listOf types.str;
+        default = ["all"];
+        example = ["en_US.UTF-8/UTF-8" "nl_NL.UTF-8/UTF-8" "nl_NL/ISO-8859-1"];
+        description = ''
+          List of locales that the system should support.  The value
+          <literal>"all"</literal> means that all locales supported by
+          Glibc will be installed.  A full list of supported locales
+          can be found at <link
+          xlink:href="https://sourceware.org/git/?p=glibc.git;a=blob;f=localedata/SUPPORTED"/>.
+        '';
+      };
+
+      consolePackages = mkOption {
+        type = types.listOf types.package;
+        default = with pkgs.kbdKeymaps; [ dvp neo ];
+        defaultText = ''with pkgs.kbdKeymaps; [ dvp neo ]'';
+        description = ''
+          List of additional packages that provide console fonts, keymaps and
+          other resources.
+        '';
+      };
+
+      consoleFont = mkOption {
+        type = types.str;
+        default = "Lat2-Terminus16";
+        example = "LatArCyrHeb-16";
+        description = ''
+          The font used for the virtual consoles.  Leave empty to use
+          whatever the <command>setfont</command> program considers the
+          default font.
+        '';
+      };
+
+      consoleUseXkbConfig = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          If set, configure the console keymap from the xserver keyboard
+          settings.
+        '';
+      };
+
+      consoleKeyMap = mkOption {
+        type = mkOptionType {
+          name = "string or path";
+          check = t: (isString t || types.path.check t);
+        };
+
+        default = "us";
+        example = "fr";
+        description = ''
+          The keyboard mapping table for the virtual consoles.
+        '';
+      };
+
+      consoleColors = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        example = [
+          "002b36" "dc322f" "859900" "b58900"
+          "268bd2" "d33682" "2aa198" "eee8d5"
+          "002b36" "cb4b16" "586e75" "657b83"
+          "839496" "6c71c4" "93a1a1" "fdf6e3"
+        ];
+        description = ''
+          The 16 colors palette used by the virtual consoles.
+          Leave empty to use the default colors.
+          Colors must be in hexadecimal format and listed in
+          order from color 0 to color 15.
+        '';
+      };
+
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = {
+
+    i18n.consoleKeyMap = with config.services.xserver;
+      mkIf config.i18n.consoleUseXkbConfig
+        (pkgs.runCommand "xkb-console-keymap" { preferLocalBuild = true; } ''
+          '${pkgs.ckbcomp}/bin/ckbcomp' -model '${xkbModel}' -layout '${layout}' \
+            -option '${xkbOptions}' -variant '${xkbVariant}' > "$out"
+        '');
+
+    environment.systemPackages =
+      optional (config.i18n.supportedLocales != []) config.i18n.glibcLocales;
+
+    environment.sessionVariables =
+      { LANG = config.i18n.defaultLocale;
+        LOCALE_ARCHIVE = "/run/current-system/sw/lib/locale/locale-archive";
+      } // config.i18n.extraLocaleSettings;
+
+    systemd.globalEnvironment = mkIf (config.i18n.supportedLocales != []) {
+      LOCALE_ARCHIVE = "${config.i18n.glibcLocales}/lib/locale/locale-archive";
+    };
+
+    # ‘/etc/locale.conf’ is used by systemd.
+    environment.etc = singleton
+      { target = "locale.conf";
+        source = pkgs.writeText "locale.conf"
+          ''
+            LANG=${config.i18n.defaultLocale}
+            ${concatStringsSep "\n" (mapAttrsToList (n: v: ''${n}=${v}'') config.i18n.extraLocaleSettings)}
+          '';
+      };
+
+  };
+}
diff --git a/nixpkgs/nixos/modules/config/iproute2.nix b/nixpkgs/nixos/modules/config/iproute2.nix
new file mode 100644
index 000000000000..a1d9ebcec66b
--- /dev/null
+++ b/nixpkgs/nixos/modules/config/iproute2.nix
@@ -0,0 +1,32 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.networking.iproute2;
+in
+{
+  options.networking.iproute2 = {
+    enable = mkEnableOption "copy IP route configuration files";
+    rttablesExtraConfig = mkOption {
+      type = types.lines;
+      default = "";
+      description = ''
+        Verbatim lines to add to /etc/iproute2/rt_tables
+      '';
+    };
+  };
+
+  config = mkIf cfg.enable {
+    environment.etc."iproute2/bpf_pinning" = { mode = "0644"; text = fileContents "${pkgs.iproute}/etc/iproute2/bpf_pinning"; };
+    environment.etc."iproute2/ematch_map"  = { mode = "0644"; text = fileContents "${pkgs.iproute}/etc/iproute2/ematch_map";  };
+    environment.etc."iproute2/group"       = { mode = "0644"; text = fileContents "${pkgs.iproute}/etc/iproute2/group";       };
+    environment.etc."iproute2/nl_protos"   = { mode = "0644"; text = fileContents "${pkgs.iproute}/etc/iproute2/nl_protos";   };
+    environment.etc."iproute2/rt_dsfield"  = { mode = "0644"; text = fileContents "${pkgs.iproute}/etc/iproute2/rt_dsfield";  };
+    environment.etc."iproute2/rt_protos"   = { mode = "0644"; text = fileContents "${pkgs.iproute}/etc/iproute2/rt_protos";   };
+    environment.etc."iproute2/rt_realms"   = { mode = "0644"; text = fileContents "${pkgs.iproute}/etc/iproute2/rt_realms";   };
+    environment.etc."iproute2/rt_scopes"   = { mode = "0644"; text = fileContents "${pkgs.iproute}/etc/iproute2/rt_scopes";   };
+    environment.etc."iproute2/rt_tables"   = { mode = "0644"; text = (fileContents "${pkgs.iproute}/etc/iproute2/rt_tables")
+                                                                   + (optionalString (cfg.rttablesExtraConfig != "") "\n\n${cfg.rttablesExtraConfig}"); };
+  };
+}
diff --git a/nixpkgs/nixos/modules/config/krb5/default.nix b/nixpkgs/nixos/modules/config/krb5/default.nix
new file mode 100644
index 000000000000..ff16ffcf9c65
--- /dev/null
+++ b/nixpkgs/nixos/modules/config/krb5/default.nix
@@ -0,0 +1,367 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.krb5;
+
+  # This is to provide support for old configuration options (as much as is
+  # reasonable). This can be removed after 18.03 was released.
+  defaultConfig = {
+    libdefaults = optionalAttrs (cfg.defaultRealm != null)
+      { default_realm = cfg.defaultRealm; };
+
+    realms = optionalAttrs (lib.all (value: value != null) [
+      cfg.defaultRealm cfg.kdc cfg.kerberosAdminServer
+    ]) {
+      ${cfg.defaultRealm} = {
+        kdc = cfg.kdc;
+        admin_server = cfg.kerberosAdminServer;
+      };
+    };
+
+    domain_realm = optionalAttrs (lib.all (value: value != null) [
+      cfg.domainRealm cfg.defaultRealm
+    ]) {
+      ".${cfg.domainRealm}" = cfg.defaultRealm;
+      ${cfg.domainRealm} = cfg.defaultRealm;
+    };
+  };
+
+  mergedConfig = (recursiveUpdate defaultConfig {
+    inherit (config.krb5)
+      kerberos libdefaults realms domain_realm capaths appdefaults plugins
+      extraConfig config;
+  });
+
+  filterEmbeddedMetadata = value: if isAttrs value then
+    (filterAttrs
+      (attrName: attrValue: attrName != "_module" && attrValue != null)
+        value)
+    else value;
+
+  mkIndent = depth: concatStrings (builtins.genList (_:  " ") (2 * depth));
+
+  mkRelation = name: value: "${name} = ${mkVal { inherit value; }}";
+
+  mkVal = { value, depth ? 0 }:
+    if (value == true) then "true"
+    else if (value == false) then "false"
+    else if (isInt value) then (toString value)
+    else if (isList value) then
+      concatMapStringsSep " " mkVal { inherit value depth; }
+    else if (isAttrs value) then
+      (concatStringsSep "\n${mkIndent (depth + 1)}"
+        ([ "{" ] ++ (mapAttrsToList
+          (attrName: attrValue: let
+            mappedAttrValue = mkVal {
+              value = attrValue;
+              depth = depth + 1;
+            };
+          in "${attrName} = ${mappedAttrValue}")
+        value))) + "\n${mkIndent depth}}"
+    else value;
+
+  mkMappedAttrsOrString = value: concatMapStringsSep "\n"
+    (line: if builtins.stringLength line > 0
+      then "${mkIndent 1}${line}"
+      else line)
+    (splitString "\n"
+      (if isAttrs value then
+        concatStringsSep "\n"
+            (mapAttrsToList mkRelation value)
+        else value));
+
+in {
+
+  ###### interface
+
+  options = {
+    krb5 = {
+      enable = mkEnableOption "building krb5.conf, configuration file for Kerberos V";
+
+      kerberos = mkOption {
+        type = types.package;
+        default = pkgs.krb5Full;
+        defaultText = "pkgs.krb5Full";
+        example = literalExample "pkgs.heimdalFull";
+        description = ''
+          The Kerberos implementation that will be present in
+          <literal>environment.systemPackages</literal> after enabling this
+          service.
+        '';
+      };
+
+      libdefaults = mkOption {
+        type = with types; either attrs lines;
+        default = {};
+        apply = attrs: filterEmbeddedMetadata attrs;
+        example = literalExample ''
+          {
+            default_realm = "ATHENA.MIT.EDU";
+          };
+        '';
+        description = ''
+          Settings used by the Kerberos V5 library.
+        '';
+      };
+
+      realms = mkOption {
+        type = with types; either attrs lines;
+        default = {};
+        example = literalExample ''
+          {
+            "ATHENA.MIT.EDU" = {
+              admin_server = "athena.mit.edu";
+              kdc = "athena.mit.edu";
+            };
+          };
+        '';
+        apply = attrs: filterEmbeddedMetadata attrs;
+        description = "Realm-specific contact information and settings.";
+      };
+
+      domain_realm = mkOption {
+        type = with types; either attrs lines;
+        default = {};
+        example = literalExample ''
+          {
+            "example.com" = "EXAMPLE.COM";
+            ".example.com" = "EXAMPLE.COM";
+          };
+        '';
+        apply = attrs: filterEmbeddedMetadata attrs;
+        description = ''
+          Map of server hostnames to Kerberos realms.
+        '';
+      };
+
+      capaths = mkOption {
+        type = with types; either attrs lines;
+        default = {};
+        example = literalExample ''
+          {
+            "ATHENA.MIT.EDU" = {
+              "EXAMPLE.COM" = ".";
+            };
+            "EXAMPLE.COM" = {
+              "ATHENA.MIT.EDU" = ".";
+            };
+          };
+        '';
+        apply = attrs: filterEmbeddedMetadata attrs;
+        description = ''
+          Authentication paths for non-hierarchical cross-realm authentication.
+        '';
+      };
+
+      appdefaults = mkOption {
+        type = with types; either attrs lines;
+        default = {};
+        example = literalExample ''
+          {
+            pam = {
+              debug = false;
+              ticket_lifetime = 36000;
+              renew_lifetime = 36000;
+              max_timeout = 30;
+              timeout_shift = 2;
+              initial_timeout = 1;
+            };
+          };
+        '';
+        apply = attrs: filterEmbeddedMetadata attrs;
+        description = ''
+          Settings used by some Kerberos V5 applications.
+        '';
+      };
+
+      plugins = mkOption {
+        type = with types; either attrs lines;
+        default = {};
+        example = literalExample ''
+          {
+            ccselect = {
+              disable = "k5identity";
+            };
+          };
+        '';
+        apply = attrs: filterEmbeddedMetadata attrs;
+        description = ''
+          Controls plugin module registration.
+        '';
+      };
+
+      extraConfig = mkOption {
+        type = with types; nullOr lines;
+        default = null;
+        example = ''
+          [logging]
+            kdc          = SYSLOG:NOTICE
+            admin_server = SYSLOG:NOTICE
+            default      = SYSLOG:NOTICE
+        '';
+        description = ''
+          These lines go to the end of <literal>krb5.conf</literal> verbatim.
+          <literal>krb5.conf</literal> may include any of the relations that are
+          valid for <literal>kdc.conf</literal> (see <literal>man
+          kdc.conf</literal>), but it is not a recommended practice.
+        '';
+      };
+
+      config = mkOption {
+        type = with types; nullOr lines;
+        default = null;
+        example = ''
+          [libdefaults]
+            default_realm = EXAMPLE.COM
+
+          [realms]
+            EXAMPLE.COM = {
+              admin_server = kerberos.example.com
+              kdc = kerberos.example.com
+              default_principal_flags = +preauth
+            }
+
+          [domain_realm]
+            example.com  = EXAMPLE.COM
+            .example.com = EXAMPLE.COM
+
+          [logging]
+            kdc          = SYSLOG:NOTICE
+            admin_server = SYSLOG:NOTICE
+            default      = SYSLOG:NOTICE
+        '';
+        description = ''
+          Verbatim <literal>krb5.conf</literal> configuration.  Note that this
+          is mutually exclusive with configuration via
+          <literal>libdefaults</literal>, <literal>realms</literal>,
+          <literal>domain_realm</literal>, <literal>capaths</literal>,
+          <literal>appdefaults</literal>, <literal>plugins</literal> and
+          <literal>extraConfig</literal> configuration options.  Consult
+          <literal>man krb5.conf</literal> for documentation.
+        '';
+      };
+
+      defaultRealm = mkOption {
+        type = with types; nullOr str;
+        default = null;
+        example = "ATHENA.MIT.EDU";
+        description = ''
+          DEPRECATED, please use
+          <literal>krb5.libdefaults.default_realm</literal>.
+        '';
+      };
+
+      domainRealm = mkOption {
+        type = with types; nullOr str;
+        default = null;
+        example = "athena.mit.edu";
+        description = ''
+          DEPRECATED, please create a map of server hostnames to Kerberos realms
+          in <literal>krb5.domain_realm</literal>.
+        '';
+      };
+
+      kdc = mkOption {
+        type = with types; nullOr str;
+        default = null;
+        example = "kerberos.mit.edu";
+        description = ''
+          DEPRECATED, please pass a <literal>kdc</literal> attribute to a realm
+          in <literal>krb5.realms</literal>.
+        '';
+      };
+
+      kerberosAdminServer = mkOption {
+        type = with types; nullOr str;
+        default = null;
+        example = "kerberos.mit.edu";
+        description = ''
+          DEPRECATED, please pass an <literal>admin_server</literal> attribute
+          to a realm in <literal>krb5.realms</literal>.
+        '';
+      };
+    };
+  };
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    environment.systemPackages = [ cfg.kerberos ];
+
+    environment.etc."krb5.conf".text = if isString cfg.config
+      then cfg.config
+      else (''
+        [libdefaults]
+        ${mkMappedAttrsOrString mergedConfig.libdefaults}
+
+        [realms]
+        ${mkMappedAttrsOrString mergedConfig.realms}
+
+        [domain_realm]
+        ${mkMappedAttrsOrString mergedConfig.domain_realm}
+
+        [capaths]
+        ${mkMappedAttrsOrString mergedConfig.capaths}
+
+        [appdefaults]
+        ${mkMappedAttrsOrString mergedConfig.appdefaults}
+
+        [plugins]
+        ${mkMappedAttrsOrString mergedConfig.plugins}
+      '' + optionalString (mergedConfig.extraConfig != null)
+          ("\n" + mergedConfig.extraConfig));
+
+    warnings = flatten [
+      (optional (cfg.defaultRealm != null) ''
+        The option krb5.defaultRealm is deprecated, please use
+        krb5.libdefaults.default_realm.
+      '')
+      (optional (cfg.domainRealm != null) ''
+        The option krb5.domainRealm is deprecated, please use krb5.domain_realm.
+      '')
+      (optional (cfg.kdc != null) ''
+        The option krb5.kdc is deprecated, please pass a kdc attribute to a
+        realm in krb5.realms.
+      '')
+      (optional (cfg.kerberosAdminServer != null) ''
+        The option krb5.kerberosAdminServer is deprecated, please pass an
+        admin_server attribute to a realm in krb5.realms.
+      '')
+    ];
+
+    assertions = [
+      { assertion = !((builtins.any (value: value != null) [
+            cfg.defaultRealm cfg.domainRealm cfg.kdc cfg.kerberosAdminServer
+          ]) && ((builtins.any (value: value != {}) [
+              cfg.libdefaults cfg.realms cfg.domain_realm cfg.capaths
+              cfg.appdefaults cfg.plugins
+            ]) || (builtins.any (value: value != null) [
+              cfg.config cfg.extraConfig
+            ])));
+        message = ''
+          Configuration of krb5.conf by deprecated options is mutually exclusive
+          with configuration by section.  Please migrate your config using the
+          attributes suggested in the warnings.
+        '';
+      }
+      { assertion = !(cfg.config != null
+          && ((builtins.any (value: value != {}) [
+              cfg.libdefaults cfg.realms cfg.domain_realm cfg.capaths
+              cfg.appdefaults cfg.plugins
+            ]) || (builtins.any (value: value != null) [
+              cfg.extraConfig cfg.defaultRealm cfg.domainRealm cfg.kdc
+              cfg.kerberosAdminServer
+            ])));
+        message = ''
+          Configuration of krb5.conf using krb.config is mutually exclusive with
+          configuration by section.  If you want to mix the two, you can pass
+          lines to any configuration section or lines to krb5.extraConfig.
+        '';
+      }
+    ];
+  };
+}
diff --git a/nixpkgs/nixos/modules/config/ldap.nix b/nixpkgs/nixos/modules/config/ldap.nix
new file mode 100644
index 000000000000..e008497a2a6e
--- /dev/null
+++ b/nixpkgs/nixos/modules/config/ldap.nix
@@ -0,0 +1,293 @@
+{ config, lib, pkgs, ... }:
+
+with pkgs;
+with lib;
+
+let
+
+  cfg = config.users.ldap;
+
+  # Careful: OpenLDAP seems to be very picky about the indentation of
+  # this file.  Directives HAVE to start in the first column!
+  ldapConfig = {
+    target = "ldap.conf";
+    source = writeText "ldap.conf" ''
+      uri ${config.users.ldap.server}
+      base ${config.users.ldap.base}
+      timelimit ${toString config.users.ldap.timeLimit}
+      bind_timelimit ${toString config.users.ldap.bind.timeLimit}
+      bind_policy ${config.users.ldap.bind.policy}
+      ${optionalString config.users.ldap.useTLS ''
+        ssl start_tls
+      ''}
+      ${optionalString (config.users.ldap.bind.distinguishedName != "") ''
+        binddn ${config.users.ldap.bind.distinguishedName}
+      ''}
+      ${optionalString (cfg.extraConfig != "") cfg.extraConfig }
+    '';
+  };
+
+  nslcdConfig = writeText "nslcd.conf" ''
+    uid nslcd
+    gid nslcd
+    uri ${cfg.server}
+    base ${cfg.base}
+    timelimit ${toString cfg.timeLimit}
+    bind_timelimit ${toString cfg.bind.timeLimit}
+    ${optionalString (cfg.bind.distinguishedName != "")
+      "binddn ${cfg.bind.distinguishedName}" }
+    ${optionalString (cfg.daemon.rootpwmoddn != "")
+      "rootpwmoddn ${cfg.daemon.rootpwmoddn}" }
+    ${optionalString (cfg.daemon.extraConfig != "") cfg.daemon.extraConfig }
+  '';
+
+  # nslcd normally reads configuration from /etc/nslcd.conf.
+  # this file might contain secrets. We append those at runtime,
+  # so redirect its location to something more temporary.
+  nslcdWrapped = runCommandNoCC "nslcd-wrapped" { nativeBuildInputs = [ makeWrapper ]; } ''
+    mkdir -p $out/bin
+    makeWrapper ${nss_pam_ldapd}/sbin/nslcd $out/bin/nslcd \
+      --set LD_PRELOAD    "${pkgs.libredirect}/lib/libredirect.so" \
+      --set NIX_REDIRECTS "/etc/nslcd.conf=/run/nslcd/nslcd.conf"
+  '';
+
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    users.ldap = {
+
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = "Whether to enable authentication against an LDAP server.";
+      };
+
+      loginPam = mkOption {
+        type = types.bool;
+        default = true;
+        description = "Whether to include authentication against LDAP in login PAM";
+      };
+
+      nsswitch = mkOption {
+        type = types.bool;
+        default = true;
+        description = "Whether to include lookup against LDAP in NSS";
+      };
+
+      server = mkOption {
+        example = "ldap://ldap.example.org/";
+        description = "The URL of the LDAP server.";
+      };
+
+      base = mkOption {
+        example = "dc=example,dc=org";
+        description = "The distinguished name of the search base.";
+      };
+
+      useTLS = mkOption {
+        default = false;
+        description = ''
+          If enabled, use TLS (encryption) over an LDAP (port 389)
+          connection.  The alternative is to specify an LDAPS server (port
+          636) in <option>users.ldap.server</option> or to forego
+          security.
+        '';
+      };
+
+      timeLimit = mkOption {
+        default = 0;
+        type = types.int;
+        description = ''
+          Specifies the time limit (in seconds) to use when performing
+          searches. A value of zero (0), which is the default, is to
+          wait indefinitely for searches to be completed.
+        '';
+      };
+
+      daemon = {
+        enable = mkOption {
+          default = false;
+          description = ''
+            Whether to let the nslcd daemon (nss-pam-ldapd) handle the
+            LDAP lookups for NSS and PAM. This can improve performance,
+            and if you need to bind to the LDAP server with a password,
+            it increases security, since only the nslcd user needs to
+            have access to the bindpw file, not everyone that uses NSS
+            and/or PAM. If this option is enabled, a local nscd user is
+            created automatically, and the nslcd service is started
+            automatically when the network get up.
+          '';
+        };
+
+        extraConfig = mkOption {
+          default =  "";
+          type = types.lines;
+          description = ''
+            Extra configuration options that will be added verbatim at
+            the end of the nslcd configuration file (nslcd.conf).
+          '' ;
+        } ;
+
+        rootpwmoddn = mkOption {
+          default = "";
+          example = "cn=admin,dc=example,dc=com";
+          type = types.str;
+          description = ''
+            The distinguished name to use to bind to the LDAP server
+            when the root user tries to modify a user's password.
+          '';
+        };
+
+        rootpwmodpwFile = mkOption {
+          default = "";
+          example = "/run/keys/nslcd.rootpwmodpw";
+          type = types.str;
+          description = ''
+            The path to a file containing the credentials with which to bind to
+            the LDAP server if the root user tries to change a user's password.
+          '';
+        };
+      };
+
+      bind = {
+        distinguishedName = mkOption {
+          default = "";
+          example = "cn=admin,dc=example,dc=com";
+          type = types.str;
+          description = ''
+            The distinguished name to bind to the LDAP server with. If this
+            is not specified, an anonymous bind will be done.
+          '';
+        };
+
+        passwordFile = mkOption {
+          default = "/etc/ldap/bind.password";
+          type = types.str;
+          description = ''
+            The path to a file containing the credentials to use when binding
+            to the LDAP server (if not binding anonymously).
+          '';
+        };
+
+        timeLimit = mkOption {
+          default = 30;
+          type = types.int;
+          description = ''
+            Specifies the time limit (in seconds) to use when connecting
+            to the directory server. This is distinct from the time limit
+            specified in <literal>users.ldap.timeLimit</literal> and affects
+            the initial server connection only.
+          '';
+        };
+
+        policy = mkOption {
+          default = "hard_open";
+          type = types.enum [ "hard_open" "hard_init" "soft" ];
+          description = ''
+            Specifies the policy to use for reconnecting to an unavailable
+            LDAP server. The default is <literal>hard_open</literal>, which
+            reconnects if opening the connection to the directory server
+            failed. By contrast, <literal>hard_init</literal> reconnects if
+            initializing the connection failed. Initializing may not
+            actually contact the directory server, and it is possible that
+            a malformed configuration file will trigger reconnection. If
+            <literal>soft</literal> is specified, then
+            <literal>nss_ldap</literal> will return immediately on server
+            failure. All hard reconnect policies block with exponential
+            backoff before retrying.
+          '';
+        };
+      };
+
+      extraConfig = mkOption {
+        default = "";
+        type = types.lines;
+        description = ''
+          Extra configuration options that will be added verbatim at
+          the end of the ldap configuration file (ldap.conf).
+          If <literal>users.ldap.daemon</literal> is enabled, this
+          configuration will not be used. In that case, use
+          <literal>users.ldap.daemon.extraConfig</literal> instead.
+        '' ;
+      };
+
+    };
+
+  };
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    environment.etc = optional (!cfg.daemon.enable) ldapConfig;
+
+    system.activationScripts = mkIf (!cfg.daemon.enable) {
+      ldap = stringAfter [ "etc" "groups" "users" ] ''
+        if test -f "${cfg.bind.passwordFile}" ; then
+          umask 0077
+          conf="$(mktemp)"
+          printf 'bindpw %s\n' "$(cat ${cfg.bind.passwordFile})" |
+          cat ${ldapConfig.source} - >"$conf"
+          mv -fT "$conf" /etc/ldap.conf
+        fi
+      '';
+    };
+
+    system.nssModules = singleton (
+      if cfg.daemon.enable then nss_pam_ldapd else nss_ldap
+    );
+
+    users = mkIf cfg.daemon.enable {
+      groups.nslcd = {
+        gid = config.ids.gids.nslcd;
+      };
+
+      users.nslcd = {
+        uid = config.ids.uids.nslcd;
+        description = "nslcd user.";
+        group = "nslcd";
+      };
+    };
+
+    systemd.services = mkIf cfg.daemon.enable {
+      nslcd = {
+        wantedBy = [ "multi-user.target" ];
+
+        preStart = ''
+          umask 0077
+          conf="$(mktemp)"
+          {
+            cat ${nslcdConfig}
+            test -z '${cfg.bind.distinguishedName}' -o ! -f '${cfg.bind.passwordFile}' ||
+            printf 'bindpw %s\n' "$(cat '${cfg.bind.passwordFile}')"
+            test -z '${cfg.daemon.rootpwmoddn}' -o ! -f '${cfg.daemon.rootpwmodpwFile}' ||
+            printf 'rootpwmodpw %s\n' "$(cat '${cfg.daemon.rootpwmodpwFile}')"
+          } >"$conf"
+          mv -fT "$conf" /run/nslcd/nslcd.conf
+        '';
+        restartTriggers = [ "/run/nslcd/nslcd.conf" ];
+
+        serviceConfig = {
+          ExecStart = "${nslcdWrapped}/bin/nslcd";
+          Type = "forking";
+          Restart = "always";
+          User = "nslcd";
+          Group = "nslcd";
+          RuntimeDirectory = [ "nslcd" ];
+          PIDFile = "/run/nslcd/nslcd.pid";
+        };
+      };
+
+    };
+
+  };
+
+  imports =
+    [ (mkRenamedOptionModule [ "users" "ldap" "bind" "password"] [ "users" "ldap" "bind" "passwordFile"])
+    ];
+}
diff --git a/nixpkgs/nixos/modules/config/locale.nix b/nixpkgs/nixos/modules/config/locale.nix
new file mode 100644
index 000000000000..6f0565881877
--- /dev/null
+++ b/nixpkgs/nixos/modules/config/locale.nix
@@ -0,0 +1,94 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  tzdir = "${pkgs.tzdata}/share/zoneinfo";
+  nospace  = str: filter (c: c == " ") (stringToCharacters str) == [];
+  timezone = types.nullOr (types.addCheck types.str nospace)
+    // { description = "null or string without spaces"; };
+
+  lcfg = config.location;
+
+in
+
+{
+  options = {
+
+    time = {
+
+      timeZone = mkOption {
+        default = null;
+        type = timezone;
+        example = "America/New_York";
+        description = ''
+          The time zone used when displaying times and dates. See <link
+          xlink:href="https://en.wikipedia.org/wiki/List_of_tz_database_time_zones"/>
+          for a comprehensive list of possible values for this setting.
+
+          If null, the timezone will default to UTC and can be set imperatively
+          using timedatectl.
+        '';
+      };
+
+      hardwareClockInLocalTime = mkOption {
+        default = false;
+        type = types.bool;
+        description = "If set, keep the hardware clock in local time instead of UTC.";
+      };
+
+    };
+
+    location = {
+
+      latitude = mkOption {
+        type = types.float;
+        description = ''
+          Your current latitude, between
+          <literal>-90.0</literal> and <literal>90.0</literal>. Must be provided
+          along with longitude.
+        '';
+      };
+
+      longitude = mkOption {
+        type = types.float;
+        description = ''
+          Your current longitude, between
+          between <literal>-180.0</literal> and <literal>180.0</literal>. Must be
+          provided along with latitude.
+        '';
+      };
+
+      provider = mkOption {
+        type = types.enum [ "manual" "geoclue2" ];
+        default = "manual";
+        description = ''
+          The location provider to use for determining your location. If set to
+          <literal>manual</literal> you must also provide latitude/longitude.
+        '';
+      };
+
+    };
+  };
+
+  config = {
+
+    environment.sessionVariables.TZDIR = "/etc/zoneinfo";
+
+    services.geoclue2.enable = mkIf (lcfg.provider == "geoclue2") true;
+
+    # This way services are restarted when tzdata changes.
+    systemd.globalEnvironment.TZDIR = tzdir;
+
+    systemd.services.systemd-timedated.environment = lib.optionalAttrs (config.time.timeZone != null) { NIXOS_STATIC_TIMEZONE = "1"; };
+
+    environment.etc = {
+      zoneinfo.source = tzdir;
+    } // lib.optionalAttrs (config.time.timeZone != null) {
+        localtime.source = "/etc/zoneinfo/${config.time.timeZone}";
+        localtime.mode = "direct-symlink";
+      };
+  };
+
+}
diff --git a/nixpkgs/nixos/modules/config/malloc.nix b/nixpkgs/nixos/modules/config/malloc.nix
new file mode 100644
index 000000000000..31a659ee83fe
--- /dev/null
+++ b/nixpkgs/nixos/modules/config/malloc.nix
@@ -0,0 +1,91 @@
+{ config, lib, pkgs, ... }:
+with lib;
+
+let
+  cfg = config.environment.memoryAllocator;
+
+  # The set of alternative malloc(3) providers.
+  providers = {
+    graphene-hardened = {
+      libPath = "${pkgs.graphene-hardened-malloc}/lib/libhardened_malloc.so";
+      description = ''
+        An allocator designed to mitigate memory corruption attacks, such as
+        those caused by use-after-free bugs.
+      '';
+    };
+
+    jemalloc = {
+      libPath = "${pkgs.jemalloc}/lib/libjemalloc.so";
+      description = ''
+        A general purpose allocator that emphasizes fragmentation avoidance
+        and scalable concurrency support.
+      '';
+    };
+
+    scudo = {
+      libPath = "${pkgs.llvmPackages.compiler-rt}/lib/linux/libclang_rt.scudo-x86_64.so";
+      description = ''
+        A user-mode allocator based on LLVM Sanitizer’s CombinedAllocator,
+        which aims at providing additional mitigations against heap based
+        vulnerabilities, while maintaining good performance.
+      '';
+    };
+  };
+
+  providerConf = providers.${cfg.provider};
+
+  # An output that contains only the shared library, to avoid
+  # needlessly bloating the system closure
+  mallocLib = pkgs.runCommand "malloc-provider-${cfg.provider}"
+    rec {
+      preferLocalBuild = true;
+      allowSubstitutes = false;
+      origLibPath = providerConf.libPath;
+      libName = baseNameOf origLibPath;
+    }
+    ''
+      mkdir -p $out/lib
+      cp -L $origLibPath $out/lib/$libName
+    '';
+
+  # The full path to the selected provider shlib.
+  providerLibPath = "${mallocLib}/lib/${mallocLib.libName}";
+in
+
+{
+  meta = {
+    maintainers = [ maintainers.joachifm ];
+  };
+
+  options = {
+    environment.memoryAllocator.provider = mkOption {
+      type = types.enum ([ "libc" ] ++ attrNames providers);
+      default = "libc";
+      description = ''
+        The system-wide memory allocator.
+
+        Briefly, the system-wide memory allocator providers are:
+        <itemizedlist>
+        <listitem><para><literal>libc</literal>: the standard allocator provided by libc</para></listitem>
+        ${toString (mapAttrsToList
+            (name: value: "<listitem><para><literal>${name}</literal>: ${value.description}</para></listitem>")
+            providers)}
+        </itemizedlist>
+
+        <warning>
+        <para>
+        Selecting an alternative allocator (i.e., anything other than
+        <literal>libc</literal>) may result in instability, data loss,
+        and/or service failure.
+        </para>
+        </warning>
+      '';
+    };
+  };
+
+  config = mkIf (cfg.provider != "libc") {
+    environment.etc."ld-nix.so.preload".text = ''
+      ${providerLibPath}
+    '';
+  };
+}
diff --git a/nixpkgs/nixos/modules/config/networking.nix b/nixpkgs/nixos/modules/config/networking.nix
new file mode 100644
index 000000000000..a89667ea221c
--- /dev/null
+++ b/nixpkgs/nixos/modules/config/networking.nix
@@ -0,0 +1,219 @@
+# /etc files related to networking, such as /etc/services.
+
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.networking;
+
+  localhostMapped4 = cfg.hosts ? "127.0.0.1" && elem "localhost" cfg.hosts."127.0.0.1";
+  localhostMapped6 = cfg.hosts ? "::1"       && elem "localhost" cfg.hosts."::1";
+
+  localhostMultiple = any (elem "localhost") (attrValues (removeAttrs cfg.hosts [ "127.0.0.1" "::1" ]));
+
+in
+
+{
+
+  options = {
+
+    networking.hosts = lib.mkOption {
+      type = types.attrsOf (types.listOf types.str);
+      example = literalExample ''
+        {
+          "127.0.0.1" = [ "foo.bar.baz" ];
+          "192.168.0.2" = [ "fileserver.local" "nameserver.local" ];
+        };
+      '';
+      description = ''
+        Locally defined maps of hostnames to IP addresses.
+      '';
+    };
+
+    networking.extraHosts = lib.mkOption {
+      type = types.lines;
+      default = "";
+      example = "192.168.0.1 lanlocalhost";
+      description = ''
+        Additional verbatim entries to be appended to <filename>/etc/hosts</filename>.
+      '';
+    };
+
+    networking.hostConf = lib.mkOption {
+      type = types.lines;
+      default = "multi on";
+      example = ''
+        multi on
+        reorder on
+        trim lan
+      '';
+      description = ''
+        The contents of <filename>/etc/host.conf</filename>. See also <citerefentry><refentrytitle>host.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
+      '';
+    };
+
+    networking.timeServers = mkOption {
+      default = [
+        "0.nixos.pool.ntp.org"
+        "1.nixos.pool.ntp.org"
+        "2.nixos.pool.ntp.org"
+        "3.nixos.pool.ntp.org"
+      ];
+      description = ''
+        The set of NTP servers from which to synchronise.
+      '';
+    };
+
+    networking.proxy = {
+
+      default = lib.mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        description = ''
+          This option specifies the default value for httpProxy, httpsProxy, ftpProxy and rsyncProxy.
+        '';
+        example = "http://127.0.0.1:3128";
+      };
+
+      httpProxy = lib.mkOption {
+        type = types.nullOr types.str;
+        default = cfg.proxy.default;
+        description = ''
+          This option specifies the http_proxy environment variable.
+        '';
+        example = "http://127.0.0.1:3128";
+      };
+
+      httpsProxy = lib.mkOption {
+        type = types.nullOr types.str;
+        default = cfg.proxy.default;
+        description = ''
+          This option specifies the https_proxy environment variable.
+        '';
+        example = "http://127.0.0.1:3128";
+      };
+
+      ftpProxy = lib.mkOption {
+        type = types.nullOr types.str;
+        default = cfg.proxy.default;
+        description = ''
+          This option specifies the ftp_proxy environment variable.
+        '';
+        example = "http://127.0.0.1:3128";
+      };
+
+      rsyncProxy = lib.mkOption {
+        type = types.nullOr types.str;
+        default = cfg.proxy.default;
+        description = ''
+          This option specifies the rsync_proxy environment variable.
+        '';
+        example = "http://127.0.0.1:3128";
+      };
+
+      allProxy = lib.mkOption {
+        type = types.nullOr types.str;
+        default = cfg.proxy.default;
+        description = ''
+          This option specifies the all_proxy environment variable.
+        '';
+        example = "http://127.0.0.1:3128";
+      };
+
+      noProxy = lib.mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        description = ''
+          This option specifies the no_proxy environment variable.
+          If a default proxy is used and noProxy is null,
+          then noProxy will be set to 127.0.0.1,localhost.
+        '';
+        example = "127.0.0.1,localhost,.localdomain";
+      };
+
+      envVars = lib.mkOption {
+        type = types.attrs;
+        internal = true;
+        default = {};
+        description = ''
+          Environment variables used for the network proxy.
+        '';
+      };
+    };
+  };
+
+  config = {
+
+    assertions = [{
+      assertion = localhostMapped4;
+      message = ''`networking.hosts` doesn't map "127.0.0.1" to "localhost"'';
+    } {
+      assertion = !cfg.enableIPv6 || localhostMapped6;
+      message = ''`networking.hosts` doesn't map "::1" to "localhost"'';
+    } {
+      assertion = !localhostMultiple;
+      message = ''
+        `networking.hosts` maps "localhost" to something other than "127.0.0.1"
+        or "::1". This will break some applications. Please use
+        `networking.extraHosts` if you really want to add such a mapping.
+      '';
+    }];
+
+    networking.hosts = {
+      "127.0.0.1" = [ "localhost" ];
+    } // optionalAttrs (cfg.hostName != "") {
+      "127.0.1.1" = [ cfg.hostName ];
+    } // optionalAttrs cfg.enableIPv6 {
+      "::1" = [ "localhost" ];
+    };
+
+    environment.etc =
+      { # /etc/services: TCP/UDP port assignments.
+        services.source = pkgs.iana-etc + "/etc/services";
+
+        # /etc/protocols: IP protocol numbers.
+        protocols.source  = pkgs.iana-etc + "/etc/protocols";
+
+        # /etc/hosts: Hostname-to-IP mappings.
+        hosts.text = let
+          oneToString = set: ip: ip + " " + concatStringsSep " " set.${ip};
+          allToString = set: concatMapStringsSep "\n" (oneToString set) (attrNames set);
+        in ''
+          ${allToString (filterAttrs (_: v: v != []) cfg.hosts)}
+          ${cfg.extraHosts}
+        '';
+
+        # /etc/host.conf: resolver configuration file
+        "host.conf".text = cfg.hostConf;
+
+      } // optionalAttrs (pkgs.stdenv.hostPlatform.libc == "glibc") {
+        # /etc/rpc: RPC program numbers.
+        rpc.source = pkgs.glibc.out + "/etc/rpc";
+      };
+
+      networking.proxy.envVars =
+        optionalAttrs (cfg.proxy.default != null) {
+          # other options already fallback to proxy.default
+          no_proxy = "127.0.0.1,localhost";
+        } // optionalAttrs (cfg.proxy.httpProxy != null) {
+          http_proxy  = cfg.proxy.httpProxy;
+        } // optionalAttrs (cfg.proxy.httpsProxy != null) {
+          https_proxy = cfg.proxy.httpsProxy;
+        } // optionalAttrs (cfg.proxy.rsyncProxy != null) {
+          rsync_proxy = cfg.proxy.rsyncProxy;
+        } // optionalAttrs (cfg.proxy.ftpProxy != null) {
+          ftp_proxy   = cfg.proxy.ftpProxy;
+        } // optionalAttrs (cfg.proxy.allProxy != null) {
+          all_proxy   = cfg.proxy.allProxy;
+        } // optionalAttrs (cfg.proxy.noProxy != null) {
+          no_proxy    = cfg.proxy.noProxy;
+        };
+
+    # Install the proxy environment variables
+    environment.sessionVariables = cfg.proxy.envVars;
+
+  };
+
+}
diff --git a/nixpkgs/nixos/modules/config/no-x-libs.nix b/nixpkgs/nixos/modules/config/no-x-libs.nix
new file mode 100644
index 000000000000..74cf74d74181
--- /dev/null
+++ b/nixpkgs/nixos/modules/config/no-x-libs.nix
@@ -0,0 +1,41 @@
+# This module gets rid of all dependencies on X11 client libraries
+# (including fontconfig).
+
+{ config, lib, ... }:
+
+with lib;
+
+{
+  options = {
+    environment.noXlibs = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        Switch off the options in the default configuration that
+        require X11 libraries. This includes client-side font
+        configuration and SSH forwarding of X11 authentication
+        in. Thus, you probably do not want to enable this option if
+        you want to run X11 programs on this machine via SSH.
+      '';
+    };
+  };
+
+  config = mkIf config.environment.noXlibs {
+    programs.ssh.setXAuthLocation = false;
+    security.pam.services.su.forwardXAuth = lib.mkForce false;
+
+    fonts.fontconfig.enable = false;
+
+    nixpkgs.overlays = singleton (const (super: {
+      dbus = super.dbus.override { x11Support = false; };
+      networkmanager-fortisslvpn = super.networkmanager-fortisslvpn.override { withGnome = false; };
+      networkmanager-l2tp = super.networkmanager-l2tp.override { withGnome = false; };
+      networkmanager-openconnect = super.networkmanager-openconnect.override { withGnome = false; };
+      networkmanager-openvpn = super.networkmanager-openvpn.override { withGnome = false; };
+      networkmanager-vpnc = super.networkmanager-vpnc.override { withGnome = false; };
+      networkmanager-iodine = super.networkmanager-iodine.override { withGnome = false; };
+      pinentry = super.pinentry.override { gtk2 = null; gcr = null; qt4 = null; qt5 = null; };
+      gobject-introspection = super.gobject-introspection.override { x11Support = false; };
+    }));
+  };
+}
diff --git a/nixpkgs/nixos/modules/config/nsswitch.nix b/nixpkgs/nixos/modules/config/nsswitch.nix
new file mode 100644
index 000000000000..13277fe56e42
--- /dev/null
+++ b/nixpkgs/nixos/modules/config/nsswitch.nix
@@ -0,0 +1,116 @@
+# Configuration for the Name Service Switch (/etc/nsswitch.conf).
+
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  # only with nscd up and running we can load NSS modules that are not integrated in NSS
+  canLoadExternalModules = config.services.nscd.enable;
+  myhostname = canLoadExternalModules;
+  mymachines = canLoadExternalModules;
+  nssmdns = canLoadExternalModules && config.services.avahi.nssmdns;
+  nsswins = canLoadExternalModules && config.services.samba.nsswins;
+  ldap = canLoadExternalModules && (config.users.ldap.enable && config.users.ldap.nsswitch);
+  sssd = canLoadExternalModules && config.services.sssd.enable;
+  resolved = canLoadExternalModules && config.services.resolved.enable;
+  googleOsLogin = canLoadExternalModules && config.security.googleOsLogin.enable;
+
+  hostArray = [ "files" ]
+    ++ optional mymachines "mymachines"
+    ++ optional nssmdns "mdns_minimal [NOTFOUND=return]"
+    ++ optional nsswins "wins"
+    ++ optional resolved "resolve [!UNAVAIL=return]"
+    ++ [ "dns" ]
+    ++ optional nssmdns "mdns"
+    ++ optional myhostname "myhostname";
+
+  passwdArray = [ "files" ]
+    ++ optional sssd "sss"
+    ++ optional ldap "ldap"
+    ++ optional mymachines "mymachines"
+    ++ optional googleOsLogin "cache_oslogin oslogin"
+    ++ [ "systemd" ];
+
+  shadowArray = [ "files" ]
+    ++ optional sssd "sss"
+    ++ optional ldap "ldap";
+
+  servicesArray = [ "files" ]
+    ++ optional sssd "sss";
+
+in {
+  options = {
+
+    # NSS modules.  Hacky!
+    # Only works with nscd!
+    system.nssModules = mkOption {
+      type = types.listOf types.path;
+      internal = true;
+      default = [];
+      description = ''
+        Search path for NSS (Name Service Switch) modules.  This allows
+        several DNS resolution methods to be specified via
+        <filename>/etc/nsswitch.conf</filename>.
+      '';
+      apply = list:
+        {
+          inherit list;
+          path = makeLibraryPath list;
+        };
+    };
+
+    system.nssHosts = mkOption {
+      type = types.listOf types.str;
+      default = [];
+      example = [ "mdns" ];
+      description = ''
+        List of host entries to configure in <filename>/etc/nsswitch.conf</filename>.
+      '';
+    };
+
+  };
+
+  config = {
+    assertions = [
+      {
+        # generic catch if the NixOS module adding to nssModules does not prevent it with specific message.
+        assertion = config.system.nssModules.path != "" -> canLoadExternalModules;
+        message = "Loading NSS modules from path ${config.system.nssModules.path} requires nscd being enabled.";
+      }
+      {
+        # resolved does not need to add to nssModules, therefore needs an extra assertion
+        assertion = resolved -> canLoadExternalModules;
+        message = "Loading systemd-resolved's nss-resolve NSS module requires nscd being enabled.";
+      }
+    ];
+
+    # Name Service Switch configuration file.  Required by the C
+    # library.  !!! Factor out the mdns stuff.  The avahi module
+    # should define an option used by this module.
+    environment.etc."nsswitch.conf".text = ''
+      passwd:    ${concatStringsSep " " passwdArray}
+      group:     ${concatStringsSep " " passwdArray}
+      shadow:    ${concatStringsSep " " shadowArray}
+
+      hosts:     ${concatStringsSep " " config.system.nssHosts}
+      networks:  files
+
+      ethers:    files
+      services:  ${concatStringsSep " " servicesArray}
+      protocols: files
+      rpc:       files
+    '';
+
+    system.nssHosts = hostArray;
+
+    # Systemd provides nss-myhostname to ensure that our hostname
+    # always resolves to a valid IP address.  It returns all locally
+    # configured IP addresses, or ::1 and 127.0.0.2 as
+    # fallbacks. Systemd also provides nss-mymachines to return IP
+    # addresses of local containers.
+    system.nssModules = (optionals canLoadExternalModules [ config.systemd.package.out ])
+      ++ optional googleOsLogin pkgs.google-compute-engine-oslogin.out;
+  };
+}
diff --git a/nixpkgs/nixos/modules/config/power-management.nix b/nixpkgs/nixos/modules/config/power-management.nix
new file mode 100644
index 000000000000..64cdf50f1413
--- /dev/null
+++ b/nixpkgs/nixos/modules/config/power-management.nix
@@ -0,0 +1,106 @@
+{ config, lib, ... }:
+
+with lib;
+
+let
+
+  cfg = config.powerManagement;
+
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    powerManagement = {
+
+      enable = mkOption {
+        type = types.bool;
+        default = true;
+        description =
+          ''
+            Whether to enable power management.  This includes support
+            for suspend-to-RAM and powersave features on laptops.
+          '';
+      };
+
+      resumeCommands = mkOption {
+        type = types.lines;
+        default = "";
+        description = "Commands executed after the system resumes from suspend-to-RAM.";
+      };
+
+      powerUpCommands = mkOption {
+        type = types.lines;
+        default = "";
+        example = literalExample ''
+          "''${pkgs.hdparm}/sbin/hdparm -B 255 /dev/sda"
+        '';
+        description =
+          ''
+            Commands executed when the machine powers up.  That is,
+            they're executed both when the system first boots and when
+            it resumes from suspend or hibernation.
+          '';
+      };
+
+      powerDownCommands = mkOption {
+        type = types.lines;
+        default = "";
+        example = literalExample ''
+          "''${pkgs.hdparm}/sbin/hdparm -B 255 /dev/sda"
+        '';
+        description =
+          ''
+            Commands executed when the machine powers down.  That is,
+            they're executed both when the system shuts down and when
+            it goes to suspend or hibernation.
+          '';
+      };
+
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    systemd.targets.post-resume = {
+      description = "Post-Resume Actions";
+      requires = [ "post-resume.service" ];
+      after = [ "post-resume.service" ];
+      wantedBy = [ "sleep.target" ];
+      unitConfig.StopWhenUnneeded = true;
+    };
+
+    # Service executed before suspending/hibernating.
+    systemd.services.pre-sleep =
+      { description = "Pre-Sleep Actions";
+        wantedBy = [ "sleep.target" ];
+        before = [ "sleep.target" ];
+        script =
+          ''
+            ${cfg.powerDownCommands}
+          '';
+        serviceConfig.Type = "oneshot";
+      };
+
+    systemd.services.post-resume =
+      { description = "Post-Resume Actions";
+        after = [ "suspend.target" "hibernate.target" "hybrid-sleep.target" ];
+        script =
+          ''
+            ${config.systemd.package}/bin/systemctl try-restart post-resume.target
+            ${cfg.resumeCommands}
+            ${cfg.powerUpCommands}
+          '';
+        serviceConfig.Type = "oneshot";
+      };
+
+  };
+
+}
diff --git a/nixpkgs/nixos/modules/config/pulseaudio.nix b/nixpkgs/nixos/modules/config/pulseaudio.nix
new file mode 100644
index 000000000000..5c3e39302583
--- /dev/null
+++ b/nixpkgs/nixos/modules/config/pulseaudio.nix
@@ -0,0 +1,326 @@
+{ config, lib, pkgs, ... }:
+
+with pkgs;
+with lib;
+
+let
+
+  cfg = config.hardware.pulseaudio;
+  alsaCfg = config.sound;
+
+  systemWide = cfg.enable && cfg.systemWide;
+  nonSystemWide = cfg.enable && !cfg.systemWide;
+  hasZeroconf = let z = cfg.zeroconf; in z.publish.enable || z.discovery.enable;
+
+  overriddenPackage = cfg.package.override
+    (optionalAttrs hasZeroconf { zeroconfSupport = true; });
+  binary = "${getBin overriddenPackage}/bin/pulseaudio";
+  binaryNoDaemon = "${binary} --daemonize=no";
+
+  # Forces 32bit pulseaudio and alsaPlugins to be built/supported for apps
+  # using 32bit alsa on 64bit linux.
+  enable32BitAlsaPlugins = cfg.support32Bit && stdenv.isx86_64 && (pkgs.pkgsi686Linux.alsaLib != null && pkgs.pkgsi686Linux.libpulseaudio != null);
+
+
+  myConfigFile =
+    let
+      addModuleIf = cond: mod: optionalString cond "load-module ${mod}";
+      allAnon = optional cfg.tcp.anonymousClients.allowAll "auth-anonymous=1";
+      ipAnon =  let a = cfg.tcp.anonymousClients.allowedIpRanges;
+                in optional (a != []) ''auth-ip-acl=${concatStringsSep ";" a}'';
+    in writeTextFile {
+      name = "default.pa";
+        text = ''
+        .include ${cfg.configFile}
+        ${addModuleIf cfg.zeroconf.publish.enable "module-zeroconf-publish"}
+        ${addModuleIf cfg.zeroconf.discovery.enable "module-zeroconf-discover"}
+        ${addModuleIf cfg.tcp.enable (concatStringsSep " "
+           ([ "module-native-protocol-tcp" ] ++ allAnon ++ ipAnon))}
+        ${cfg.extraConfig}
+      '';
+    };
+
+  ids = config.ids;
+
+  uid = ids.uids.pulseaudio;
+  gid = ids.gids.pulseaudio;
+
+  stateDir = "/run/pulse";
+
+  # Create pulse/client.conf even if PulseAudio is disabled so
+  # that we can disable the autospawn feature in programs that
+  # are built with PulseAudio support (like KDE).
+  clientConf = writeText "client.conf" ''
+    autospawn=${if nonSystemWide then "yes" else "no"}
+    ${optionalString nonSystemWide "daemon-binary=${binary}"}
+    ${cfg.extraClientConf}
+  '';
+
+  # Write an /etc/asound.conf that causes all ALSA applications to
+  # be re-routed to the PulseAudio server through ALSA's Pulse
+  # plugin.
+  alsaConf = writeText "asound.conf" (''
+    pcm_type.pulse {
+      libs.native = ${pkgs.alsaPlugins}/lib/alsa-lib/libasound_module_pcm_pulse.so ;
+      ${lib.optionalString enable32BitAlsaPlugins
+     "libs.32Bit = ${pkgs.pkgsi686Linux.alsaPlugins}/lib/alsa-lib/libasound_module_pcm_pulse.so ;"}
+    }
+    pcm.!default {
+      type pulse
+      hint.description "Default Audio Device (via PulseAudio)"
+    }
+    ctl_type.pulse {
+      libs.native = ${pkgs.alsaPlugins}/lib/alsa-lib/libasound_module_ctl_pulse.so ;
+      ${lib.optionalString enable32BitAlsaPlugins
+     "libs.32Bit = ${pkgs.pkgsi686Linux.alsaPlugins}/lib/alsa-lib/libasound_module_ctl_pulse.so ;"}
+    }
+    ctl.!default {
+      type pulse
+    }
+    ${alsaCfg.extraConfig}
+  '');
+
+in {
+
+  options = {
+
+    hardware.pulseaudio = {
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to enable the PulseAudio sound server.
+        '';
+      };
+
+      systemWide = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          If false, a PulseAudio server is launched automatically for
+          each user that tries to use the sound system. The server runs
+          with user privileges. This is the recommended and most secure
+          way to use PulseAudio. If true, one system-wide PulseAudio
+          server is launched on boot, running as the user "pulse", and
+          only users in the "audio" group will have access to the server.
+          Please read the PulseAudio documentation for more details.
+        '';
+      };
+
+      support32Bit = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to include the 32-bit pulseaudio libraries in the system or not.
+          This is only useful on 64-bit systems and currently limited to x86_64-linux.
+        '';
+      };
+
+      configFile = mkOption {
+        type = types.nullOr types.path;
+        description = ''
+          The path to the default configuration options the PulseAudio server
+          should use. By default, the "default.pa" configuration
+          from the PulseAudio distribution is used.
+        '';
+      };
+
+      extraConfig = mkOption {
+        type = types.lines;
+        default = "";
+        description = ''
+          Literal string to append to <literal>configFile</literal>
+          and the config file generated by the pulseaudio module.
+        '';
+      };
+
+      extraClientConf = mkOption {
+        type = types.lines;
+        default = "";
+        description = ''
+          Extra configuration appended to pulse/client.conf file.
+        '';
+      };
+
+      package = mkOption {
+        type = types.package;
+        default = pkgs.pulseaudio;
+        defaultText = "pkgs.pulseaudio";
+        example = literalExample "pkgs.pulseaudioFull";
+        description = ''
+          The PulseAudio derivation to use.  This can be used to enable
+          features (such as JACK support, Bluetooth) via the
+          <literal>pulseaudioFull</literal> package.
+        '';
+      };
+
+      extraModules = mkOption {
+        type = types.listOf types.package;
+        default = [];
+        example = literalExample "[ pkgs.pulseaudio-modules-bt ]";
+        description = ''
+          Extra pulseaudio modules to use. This is intended for out-of-tree
+          pulseaudio modules like extra bluetooth codecs.
+
+          Extra modules take precedence over built-in pulseaudio modules.
+        '';
+      };
+
+      daemon = {
+        logLevel = mkOption {
+          type = types.str;
+          default = "notice";
+          description = ''
+            The log level that the system-wide pulseaudio daemon should use,
+            if activated.
+          '';
+        };
+
+        config = mkOption {
+          type = types.attrsOf types.unspecified;
+          default = {};
+          description = ''Config of the pulse daemon. See <literal>man pulse-daemon.conf</literal>.'';
+          example = literalExample ''{ realtime-scheduling = "yes"; }'';
+        };
+      };
+
+      zeroconf = {
+        discovery.enable =
+          mkEnableOption "discovery of pulseaudio sinks in the local network";
+        publish.enable =
+          mkEnableOption "publishing the pulseaudio sink in the local network";
+      };
+
+      # TODO: enable by default?
+      tcp = {
+        enable = mkEnableOption "tcp streaming support";
+
+        anonymousClients = {
+          allowAll = mkEnableOption "all anonymous clients to stream to the server";
+          allowedIpRanges = mkOption {
+            type = types.listOf types.str;
+            default = [];
+            example = literalExample ''[ "127.0.0.1" "192.168.1.0/24" ]'';
+            description = ''
+              A list of IP subnets that are allowed to stream to the server.
+            '';
+          };
+        };
+      };
+
+    };
+
+  };
+
+
+  config = mkMerge [
+    {
+      environment.etc = singleton {
+        target = "pulse/client.conf";
+        source = clientConf;
+      };
+
+      hardware.pulseaudio.configFile = mkDefault "${getBin overriddenPackage}/etc/pulse/default.pa";
+    }
+
+    (mkIf cfg.enable {
+      environment.systemPackages = [ overriddenPackage ];
+
+      sound.enable = true;
+
+      environment.etc = [
+        { target = "asound.conf";
+          source = alsaConf; }
+
+        { target = "pulse/daemon.conf";
+          source = writeText "daemon.conf" (lib.generators.toKeyValue {} cfg.daemon.config); }
+
+        { target = "openal/alsoft.conf";
+          source = writeText "alsoft.conf" "drivers=pulse"; }
+
+        { target = "libao.conf";
+          source = writeText "libao.conf" "default_driver=pulse"; }
+      ];
+
+      # Disable flat volumes to enable relative ones
+      hardware.pulseaudio.daemon.config.flat-volumes = mkDefault "no";
+
+      # Upstream defaults to speex-float-1 which results in audible artifacts
+      hardware.pulseaudio.daemon.config.resample-method = mkDefault "speex-float-5";
+
+      # Allow PulseAudio to get realtime priority using rtkit.
+      security.rtkit.enable = true;
+
+      systemd.packages = [ overriddenPackage ];
+    })
+
+    (mkIf (cfg.extraModules != []) {
+      hardware.pulseaudio.daemon.config.dl-search-path = let
+        overriddenModules = builtins.map
+          (drv: drv.override { pulseaudio = overriddenPackage; })
+          cfg.extraModules;
+        modulePaths = builtins.map
+          (drv: "${drv}/lib/pulse-${overriddenPackage.version}/modules")
+          # User-provided extra modules take precedence
+          (overriddenModules ++ [ overriddenPackage ]);
+      in lib.concatStringsSep ":" modulePaths;
+    })
+
+    (mkIf hasZeroconf {
+      services.avahi.enable = true;
+    })
+    (mkIf cfg.zeroconf.publish.enable {
+      services.avahi.publish.enable = true;
+      services.avahi.publish.userServices = true;
+    })
+
+    (mkIf nonSystemWide {
+      environment.etc = singleton {
+        target = "pulse/default.pa";
+        source = myConfigFile;
+      };
+      systemd.user = {
+        services.pulseaudio = {
+          restartIfChanged = true;
+          serviceConfig = {
+            RestartSec = "500ms";
+            PassEnvironment = "DISPLAY";
+          };
+        };
+        sockets.pulseaudio = {
+          wantedBy = [ "sockets.target" ];
+        };
+      };
+    })
+
+    (mkIf systemWide {
+      users.users.pulse = {
+        # For some reason, PulseAudio wants UID == GID.
+        uid = assert uid == gid; uid;
+        group = "pulse";
+        extraGroups = [ "audio" ];
+        description = "PulseAudio system service user";
+        home = stateDir;
+        createHome = true;
+      };
+
+      users.groups.pulse.gid = gid;
+
+      systemd.services.pulseaudio = {
+        description = "PulseAudio System-Wide Server";
+        wantedBy = [ "sound.target" ];
+        before = [ "sound.target" ];
+        environment.PULSE_RUNTIME_PATH = stateDir;
+        serviceConfig = {
+          Type = "notify";
+          ExecStart = "${binaryNoDaemon} --log-level=${cfg.daemon.logLevel} --system -n --file=${myConfigFile}";
+          Restart = "on-failure";
+          RestartSec = "500ms";
+        };
+      };
+
+      environment.variables.PULSE_COOKIE = "${stateDir}/.config/pulse/cookie";
+    })
+  ];
+
+}
diff --git a/nixpkgs/nixos/modules/config/qt5.nix b/nixpkgs/nixos/modules/config/qt5.nix
new file mode 100644
index 000000000000..7de1c0f5d557
--- /dev/null
+++ b/nixpkgs/nixos/modules/config/qt5.nix
@@ -0,0 +1,102 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.qt5;
+
+  isQGnome = cfg.platformTheme == "gnome" && cfg.style == "adwaita";
+  isQtStyle = cfg.platformTheme == "gtk2" && cfg.style != "adwaita";
+
+  packages = if isQGnome then [ pkgs.qgnomeplatform pkgs.adwaita-qt ]
+    else if isQtStyle then [ pkgs.qtstyleplugins ]
+    else throw "`qt5.platformTheme` ${cfg.platformTheme} and `qt5.style` ${cfg.style} are not compatible.";
+
+in
+
+{
+
+  options = {
+    qt5 = {
+
+      enable = mkEnableOption "Qt5 theming configuration";
+
+      platformTheme = mkOption {
+        type = types.enum [
+          "gtk2"
+          "gnome"
+        ];
+        example = "gnome";
+        relatedPackages = [
+          "qgnomeplatform"
+          ["libsForQt5" "qtstyleplugins"]
+        ];
+        description = ''
+          Selects the platform theme to use for Qt5 applications.</para>
+          <para>The options are
+          <variablelist>
+            <varlistentry>
+              <term><literal>gtk</literal></term>
+              <listitem><para>Use GTK theme with
+                <link xlink:href="https://github.com/qt/qtstyleplugins">qtstyleplugins</link>
+              </para></listitem>
+            </varlistentry>
+            <varlistentry>
+              <term><literal>gnome</literal></term>
+              <listitem><para>Use GNOME theme with
+                <link xlink:href="https://github.com/FedoraQt/QGnomePlatform">qgnomeplatform</link>
+              </para></listitem>
+            </varlistentry>
+          </variablelist>
+        '';
+      };
+
+      style = mkOption {
+        type = types.enum [
+          "adwaita"
+          "cleanlooks"
+          "gtk2"
+          "motif"
+          "plastique"
+        ];
+        example = "adwaita";
+        relatedPackages = [
+          "adwaita-qt"
+          ["libsForQt5" "qtstyleplugins"]
+        ];
+        description = ''
+          Selects the style to use for Qt5 applications.</para>
+          <para>The options are
+          <variablelist>
+            <varlistentry>
+              <term><literal>adwaita</literal></term>
+              <listitem><para>Use Adwaita Qt style with
+                <link xlink:href="https://github.com/FedoraQt/adwaita-qt">adwaita</link>
+              </para></listitem>
+            </varlistentry>
+            <varlistentry>
+              <term><literal>cleanlooks</literal></term>
+              <term><literal>gtk2</literal></term>
+              <term><literal>motif</literal></term>
+              <term><literal>plastique</literal></term>
+              <listitem><para>Use styles from
+                <link xlink:href="https://github.com/qt/qtstyleplugins">qtstyleplugins</link>
+              </para></listitem>
+            </varlistentry>
+          </variablelist>
+        '';
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+
+    environment.variables.QT_QPA_PLATFORMTHEME = cfg.platformTheme;
+
+    environment.variables.QT_STYLE_OVERRIDE = cfg.style;
+
+    environment.systemPackages = packages;
+
+  };
+}
diff --git a/nixpkgs/nixos/modules/config/resolvconf.nix b/nixpkgs/nixos/modules/config/resolvconf.nix
new file mode 100644
index 000000000000..406c6a7ac329
--- /dev/null
+++ b/nixpkgs/nixos/modules/config/resolvconf.nix
@@ -0,0 +1,149 @@
+# /etc files related to networking, such as /etc/services.
+
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.networking.resolvconf;
+
+  resolvconfOptions = cfg.extraOptions
+    ++ optional cfg.dnsSingleRequest "single-request"
+    ++ optional cfg.dnsExtensionMechanism "edns0";
+
+  configText =
+    ''
+      # This is the default, but we must set it here to prevent
+      # a collision with an apparently unrelated environment
+      # variable with the same name exported by dhcpcd.
+      interface_order='lo lo[0-9]*'
+    '' + optionalString config.services.nscd.enable ''
+      # Invalidate the nscd cache whenever resolv.conf is
+      # regenerated.
+      libc_restart='${pkgs.systemd}/bin/systemctl try-restart --no-block nscd.service 2> /dev/null'
+    '' + optionalString (length resolvconfOptions > 0) ''
+      # Options as described in resolv.conf(5)
+      resolv_conf_options='${concatStringsSep " " resolvconfOptions}'
+    '' + optionalString cfg.useLocalResolver ''
+      # This hosts runs a full-blown DNS resolver.
+      name_servers='127.0.0.1'
+    '' + cfg.extraConfig;
+
+in
+
+{
+
+  options = {
+
+    networking.resolvconf = {
+
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        internal = true;
+        description = ''
+          DNS configuration is managed by resolvconf.
+        '';
+      };
+
+      useHostResolvConf = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          In containers, whether to use the
+          <filename>resolv.conf</filename> supplied by the host.
+        '';
+      };
+
+      dnsSingleRequest = lib.mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Recent versions of glibc will issue both ipv4 (A) and ipv6 (AAAA)
+          address queries at the same time, from the same port. Sometimes upstream
+          routers will systemically drop the ipv4 queries. The symptom of this problem is
+          that 'getent hosts example.com' only returns ipv6 (or perhaps only ipv4) addresses. The
+          workaround for this is to specify the option 'single-request' in
+          /etc/resolv.conf. This option enables that.
+        '';
+      };
+
+      dnsExtensionMechanism = mkOption {
+        type = types.bool;
+        default = true;
+        description = ''
+          Enable the <code>edns0</code> option in <filename>resolv.conf</filename>. With
+          that option set, <code>glibc</code> supports use of the extension mechanisms for
+          DNS (EDNS) specified in RFC 2671. The most popular user of that feature is DNSSEC,
+          which does not work without it.
+        '';
+      };
+
+      extraConfig = mkOption {
+        type = types.lines;
+        default = "";
+        example = "libc=NO";
+        description = ''
+          Extra configuration to append to <filename>resolvconf.conf</filename>.
+        '';
+      };
+
+      extraOptions = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        example = [ "ndots:1" "rotate" ];
+        description = ''
+          Set the options in <filename>/etc/resolv.conf</filename>.
+        '';
+      };
+
+      useLocalResolver = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Use local DNS server for resolving.
+        '';
+      };
+
+    };
+
+  };
+
+  config = mkMerge [
+    {
+      networking.resolvconf.enable = !(config.environment.etc ? "resolv.conf");
+
+      environment.etc."resolvconf.conf".text =
+        if !cfg.enable then
+          # Force-stop any attempts to use resolvconf
+          ''
+            echo "resolvconf is disabled on this system but was used anyway:" >&2
+            echo "$0 $*" >&2
+            exit 1
+          ''
+        else configText;
+    }
+
+    (mkIf cfg.enable {
+      environment.systemPackages = [ pkgs.openresolv ];
+
+      systemd.services.resolvconf = {
+        description = "resolvconf update";
+
+        before = [ "network-pre.target" ];
+        wants = [ "network-pre.target" ];
+        wantedBy = [ "multi-user.target" ];
+        restartTriggers = [ config.environment.etc."resolvconf.conf".source ];
+
+        serviceConfig = {
+          Type = "oneshot";
+          ExecStart = "${pkgs.openresolv}/bin/resolvconf -u";
+          RemainAfterExit = true;
+        };
+      };
+
+    })
+  ];
+
+}
diff --git a/nixpkgs/nixos/modules/config/shells-environment.nix b/nixpkgs/nixos/modules/config/shells-environment.nix
new file mode 100644
index 000000000000..d939cbb393ee
--- /dev/null
+++ b/nixpkgs/nixos/modules/config/shells-environment.nix
@@ -0,0 +1,204 @@
+# This module defines a global environment configuration and
+# a common configuration for all shells.
+
+{ config, lib, utils, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.environment;
+
+  exportedEnvVars =
+    let
+      absoluteVariables =
+        mapAttrs (n: toList) cfg.variables;
+
+      suffixedVariables =
+        flip mapAttrs cfg.profileRelativeEnvVars (envVar: listSuffixes:
+          concatMap (profile: map (suffix: "${profile}${suffix}") listSuffixes) cfg.profiles
+        );
+
+      allVariables =
+        zipAttrsWith (n: concatLists) [ absoluteVariables suffixedVariables ];
+
+      exportVariables =
+        mapAttrsToList (n: v: ''export ${n}="${concatStringsSep ":" v}"'') allVariables;
+    in
+      concatStringsSep "\n" exportVariables;
+in
+
+{
+
+  options = {
+
+    environment.variables = mkOption {
+      default = {};
+      example = { EDITOR = "nvim"; VISUAL = "nvim"; };
+      description = ''
+        A set of environment variables used in the global environment.
+        These variables will be set on shell initialisation (e.g. in /etc/profile).
+        The value of each variable can be either a string or a list of
+        strings.  The latter is concatenated, interspersed with colon
+        characters.
+      '';
+      type = with types; attrsOf (either str (listOf str));
+      apply = mapAttrs (n: v: if isList v then concatStringsSep ":" v else v);
+    };
+
+    environment.profiles = mkOption {
+      default = [];
+      description = ''
+        A list of profiles used to setup the global environment.
+      '';
+      type = types.listOf types.str;
+    };
+
+    environment.profileRelativeEnvVars = mkOption {
+      type = types.attrsOf (types.listOf types.str);
+      example = { PATH = [ "/bin" ]; MANPATH = [ "/man" "/share/man" ]; };
+      description = ''
+        Attribute set of environment variable.  Each attribute maps to a list
+        of relative paths.  Each relative path is appended to the each profile
+        of <option>environment.profiles</option> to form the content of the
+        corresponding environment variable.
+      '';
+    };
+
+    # !!! isn't there a better way?
+    environment.extraInit = mkOption {
+      default = "";
+      description = ''
+        Shell script code called during global environment initialisation
+        after all variables and profileVariables have been set.
+        This code is assumed to be shell-independent, which means you should
+        stick to pure sh without sh word split.
+      '';
+      type = types.lines;
+    };
+
+    environment.shellInit = mkOption {
+      default = "";
+      description = ''
+        Shell script code called during shell initialisation.
+        This code is assumed to be shell-independent, which means you should
+        stick to pure sh without sh word split.
+      '';
+      type = types.lines;
+    };
+
+    environment.loginShellInit = mkOption {
+      default = "";
+      description = ''
+        Shell script code called during login shell initialisation.
+        This code is assumed to be shell-independent, which means you should
+        stick to pure sh without sh word split.
+      '';
+      type = types.lines;
+    };
+
+    environment.interactiveShellInit = mkOption {
+      default = "";
+      description = ''
+        Shell script code called during interactive shell initialisation.
+        This code is assumed to be shell-independent, which means you should
+        stick to pure sh without sh word split.
+      '';
+      type = types.lines;
+    };
+
+    environment.shellAliases = mkOption {
+      example = { l = null; ll = "ls -l"; };
+      description = ''
+        An attribute set that maps aliases (the top level attribute names in
+        this option) to command strings or directly to build outputs. The
+        aliases are added to all users' shells.
+        Aliases mapped to <code>null</code> are ignored.
+      '';
+      type = with types; attrsOf (nullOr (either str path));
+    };
+
+    environment.binsh = mkOption {
+      default = "${config.system.build.binsh}/bin/sh";
+      defaultText = "\${config.system.build.binsh}/bin/sh";
+      example = literalExample ''
+        "''${pkgs.dash}/bin/dash"
+      '';
+      type = types.path;
+      visible = false;
+      description = ''
+        The shell executable that is linked system-wide to
+        <literal>/bin/sh</literal>. Please note that NixOS assumes all
+        over the place that shell to be Bash, so override the default
+        setting only if you know exactly what you're doing.
+      '';
+    };
+
+    environment.shells = mkOption {
+      default = [];
+      example = literalExample "[ pkgs.bashInteractive pkgs.zsh ]";
+      description = ''
+        A list of permissible login shells for user accounts.
+        No need to mention <literal>/bin/sh</literal>
+        here, it is placed into this list implicitly.
+      '';
+      type = types.listOf (types.either types.shellPackage types.path);
+    };
+
+  };
+
+  config = {
+
+    system.build.binsh = pkgs.bashInteractive;
+
+    # Set session variables in the shell as well. This is usually
+    # unnecessary, but it allows changes to session variables to take
+    # effect without restarting the session (e.g. by opening a new
+    # terminal instead of logging out of X11).
+    environment.variables = config.environment.sessionVariables;
+
+    environment.profileRelativeEnvVars = config.environment.profileRelativeSessionVariables;
+
+    environment.shellAliases = mapAttrs (name: mkDefault) {
+      ls = "ls --color=tty";
+      ll = "ls -l";
+      l  = "ls -alh";
+    };
+
+    environment.etc.shells.text =
+      ''
+        ${concatStringsSep "\n" (map utils.toShellPath cfg.shells)}
+        /bin/sh
+      '';
+
+    # For resetting environment with `. /etc/set-environment` when needed
+    # and discoverability (see motivation of #30418).
+    environment.etc.set-environment.source = config.system.build.setEnvironment;
+
+    system.build.setEnvironment = pkgs.writeText "set-environment"
+      ''
+        # DO NOT EDIT -- this file has been generated automatically.
+
+        # Prevent this file from being sourced by child shells.
+        export __NIXOS_SET_ENVIRONMENT_DONE=1
+
+        ${exportedEnvVars}
+
+        ${cfg.extraInit}
+
+        # ~/bin if it exists overrides other bin directories.
+        export PATH="$HOME/bin:$PATH"
+      '';
+
+    system.activationScripts.binsh = stringAfter [ "stdio" ]
+      ''
+        # Create the required /bin/sh symlink; otherwise lots of things
+        # (notably the system() function) won't work.
+        mkdir -m 0755 -p /bin
+        ln -sfn "${cfg.binsh}" /bin/.sh.tmp
+        mv /bin/.sh.tmp /bin/sh # atomically replace /bin/sh
+      '';
+
+  };
+
+}
diff --git a/nixpkgs/nixos/modules/config/swap.nix b/nixpkgs/nixos/modules/config/swap.nix
new file mode 100644
index 000000000000..fed3fa3bc7c8
--- /dev/null
+++ b/nixpkgs/nixos/modules/config/swap.nix
@@ -0,0 +1,222 @@
+{ config, lib, pkgs, utils, ... }:
+
+with utils;
+with lib;
+
+let
+
+  randomEncryptionCoerce = enable: { inherit enable; };
+
+  randomEncryptionOpts = { ... }: {
+
+    options = {
+
+      enable = mkOption {
+        default = false;
+        type = types.bool;
+        description = ''
+          Encrypt swap device with a random key. This way you won't have a persistent swap device.
+
+          WARNING: Don't try to hibernate when you have at least one swap partition with
+          this option enabled! We have no way to set the partition into which hibernation image
+          is saved, so if your image ends up on an encrypted one you would lose it!
+
+          WARNING #2: Do not use /dev/disk/by-uuid/… or /dev/disk/by-label/… as your swap device
+          when using randomEncryption as the UUIDs and labels will get erased on every boot when
+          the partition is encrypted. Best to use /dev/disk/by-partuuid/…
+        '';
+      };
+
+      cipher = mkOption {
+        default = "aes-xts-plain64";
+        example = "serpent-xts-plain64";
+        type = types.str;
+        description = ''
+          Use specified cipher for randomEncryption.
+
+          Hint: Run "cryptsetup benchmark" to see which one is fastest on your machine.
+        '';
+      };
+
+      source = mkOption {
+        default = "/dev/urandom";
+        example = "/dev/random";
+        type = types.str;
+        description = ''
+          Define the source of randomness to obtain a random key for encryption.
+        '';
+      };
+
+    };
+
+  };
+
+  swapCfg = {config, options, ...}: {
+
+    options = {
+
+      device = mkOption {
+        example = "/dev/sda3";
+        type = types.str;
+        description = "Path of the device.";
+      };
+
+      label = mkOption {
+        example = "swap";
+        type = types.str;
+        description = ''
+          Label of the device.  Can be used instead of <varname>device</varname>.
+        '';
+      };
+
+      size = mkOption {
+        default = null;
+        example = 2048;
+        type = types.nullOr types.int;
+        description = ''
+          If this option is set, ‘device’ is interpreted as the
+          path of a swapfile that will be created automatically
+          with the indicated size (in megabytes).
+        '';
+      };
+
+      priority = mkOption {
+        default = null;
+        example = 2048;
+        type = types.nullOr types.int;
+        description = ''
+          Specify the priority of the swap device. Priority is a value between 0 and 32767.
+          Higher numbers indicate higher priority.
+          null lets the kernel choose a priority, which will show up as a negative value.
+        '';
+      };
+
+      randomEncryption = mkOption {
+        default = false;
+        example = {
+          enable = true;
+          cipher = "serpent-xts-plain64";
+          source = "/dev/random";
+        };
+        type = types.coercedTo types.bool randomEncryptionCoerce (types.submodule randomEncryptionOpts);
+        description = ''
+          Encrypt swap device with a random key. This way you won't have a persistent swap device.
+
+          HINT: run "cryptsetup benchmark" to test cipher performance on your machine.
+
+          WARNING: Don't try to hibernate when you have at least one swap partition with
+          this option enabled! We have no way to set the partition into which hibernation image
+          is saved, so if your image ends up on an encrypted one you would lose it!
+
+          WARNING #2: Do not use /dev/disk/by-uuid/… or /dev/disk/by-label/… as your swap device
+          when using randomEncryption as the UUIDs and labels will get erased on every boot when
+          the partition is encrypted. Best to use /dev/disk/by-partuuid/…
+        '';
+      };
+
+      deviceName = mkOption {
+        type = types.str;
+        internal = true;
+      };
+
+      realDevice = mkOption {
+        type = types.path;
+        internal = true;
+      };
+
+    };
+
+    config = rec {
+      device = mkIf options.label.isDefined
+        "/dev/disk/by-label/${config.label}";
+      deviceName = lib.replaceChars ["\\"] [""] (escapeSystemdPath config.device);
+      realDevice = if config.randomEncryption.enable then "/dev/mapper/${deviceName}" else config.device;
+    };
+
+  };
+
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    swapDevices = mkOption {
+      default = [];
+      example = [
+        { device = "/dev/hda7"; }
+        { device = "/var/swapfile"; }
+        { label = "bigswap"; }
+      ];
+      description = ''
+        The swap devices and swap files.  These must have been
+        initialised using <command>mkswap</command>.  Each element
+        should be an attribute set specifying either the path of the
+        swap device or file (<literal>device</literal>) or the label
+        of the swap device (<literal>label</literal>, see
+        <command>mkswap -L</command>).  Using a label is
+        recommended.
+      '';
+
+      type = types.listOf (types.submodule swapCfg);
+    };
+
+  };
+
+  config = mkIf ((length config.swapDevices) != 0) {
+
+    system.requiredKernelConfig = with config.lib.kernelConfig; [
+      (isYes "SWAP")
+    ];
+
+    # Create missing swapfiles.
+    # FIXME: support changing the size of existing swapfiles.
+    systemd.services =
+      let
+
+        createSwapDevice = sw:
+          assert sw.device != "";
+          assert !(sw.randomEncryption.enable && lib.hasPrefix "/dev/disk/by-uuid"  sw.device);
+          assert !(sw.randomEncryption.enable && lib.hasPrefix "/dev/disk/by-label" sw.device);
+          let realDevice' = escapeSystemdPath sw.realDevice;
+          in nameValuePair "mkswap-${sw.deviceName}"
+          { description = "Initialisation of swap device ${sw.device}";
+            wantedBy = [ "${realDevice'}.swap" ];
+            before = [ "${realDevice'}.swap" ];
+            path = [ pkgs.utillinux ] ++ optional sw.randomEncryption.enable pkgs.cryptsetup;
+
+            script =
+              ''
+                ${optionalString (sw.size != null) ''
+                  currentSize=$(( $(stat -c "%s" "${sw.device}" 2>/dev/null || echo 0) / 1024 / 1024 ))
+                  if [ "${toString sw.size}" != "$currentSize" ]; then
+                    fallocate -l ${toString sw.size}M "${sw.device}" ||
+                      dd if=/dev/zero of="${sw.device}" bs=1M count=${toString sw.size}
+                    if [ "${toString sw.size}" -lt "$currentSize" ]; then
+                      truncate --size "${toString sw.size}M" "${sw.device}"
+                    fi
+                    chmod 0600 ${sw.device}
+                    ${optionalString (!sw.randomEncryption.enable) "mkswap ${sw.realDevice}"}
+                  fi
+                ''}
+                ${optionalString sw.randomEncryption.enable ''
+                  cryptsetup plainOpen -c ${sw.randomEncryption.cipher} -d ${sw.randomEncryption.source} ${sw.device} ${sw.deviceName}
+                  mkswap ${sw.realDevice}
+                ''}
+              '';
+
+            unitConfig.RequiresMountsFor = [ "${dirOf sw.device}" ];
+            unitConfig.DefaultDependencies = false; # needed to prevent a cycle
+            serviceConfig.Type = "oneshot";
+            serviceConfig.RemainAfterExit = sw.randomEncryption.enable;
+            serviceConfig.ExecStop = optionalString sw.randomEncryption.enable "${pkgs.cryptsetup}/bin/cryptsetup luksClose ${sw.deviceName}";
+            restartIfChanged = false;
+          };
+
+      in listToAttrs (map createSwapDevice (filter (sw: sw.size != null || sw.randomEncryption.enable) config.swapDevices));
+
+  };
+
+}
diff --git a/nixpkgs/nixos/modules/config/sysctl.nix b/nixpkgs/nixos/modules/config/sysctl.nix
new file mode 100644
index 000000000000..fb2b58eed720
--- /dev/null
+++ b/nixpkgs/nixos/modules/config/sysctl.nix
@@ -0,0 +1,63 @@
+{ config, lib, ... }:
+
+with lib;
+
+let
+
+  sysctlOption = mkOptionType {
+    name = "sysctl option value";
+    check = val:
+      let
+        checkType = x: isBool x || isString x || isInt x || x == null;
+      in
+        checkType val || (val._type or "" == "override" && checkType val.content);
+    merge = loc: defs: mergeOneOption loc (filterOverrides defs);
+  };
+
+in
+
+{
+
+  options = {
+
+    boot.kernel.sysctl = mkOption {
+      default = {};
+      example = literalExample ''
+        { "net.ipv4.tcp_syncookies" = false; "vm.swappiness" = 60; }
+      '';
+      type = types.attrsOf sysctlOption;
+      description = ''
+        Runtime parameters of the Linux kernel, as set by
+        <citerefentry><refentrytitle>sysctl</refentrytitle>
+        <manvolnum>8</manvolnum></citerefentry>.  Note that sysctl
+        parameters names must be enclosed in quotes
+        (e.g. <literal>"vm.swappiness"</literal> instead of
+        <literal>vm.swappiness</literal>).  The value of each
+        parameter may be a string, integer, boolean, or null
+        (signifying the option will not appear at all).
+      '';
+    };
+
+  };
+
+  config = {
+
+    environment.etc."sysctl.d/60-nixos.conf".text =
+      concatStrings (mapAttrsToList (n: v:
+        optionalString (v != null) "${n}=${if v == false then "0" else toString v}\n"
+      ) config.boot.kernel.sysctl);
+
+    systemd.services.systemd-sysctl =
+      { wantedBy = [ "multi-user.target" ];
+        restartTriggers = [ config.environment.etc."sysctl.d/60-nixos.conf".source ];
+      };
+
+    # Hide kernel pointers (e.g. in /proc/modules) for unprivileged
+    # users as these make it easier to exploit kernel vulnerabilities.
+    boot.kernel.sysctl."kernel.kptr_restrict" = 1;
+
+    # Disable YAMA by default to allow easy debugging.
+    boot.kernel.sysctl."kernel.yama.ptrace_scope" = mkDefault 0;
+
+  };
+}
diff --git a/nixpkgs/nixos/modules/config/system-environment.nix b/nixpkgs/nixos/modules/config/system-environment.nix
new file mode 100644
index 000000000000..792d1dbb38f6
--- /dev/null
+++ b/nixpkgs/nixos/modules/config/system-environment.nix
@@ -0,0 +1,99 @@
+# This module defines a system-wide environment that will be
+# initialised by pam_env (that is, not only in shells).
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.environment;
+
+  pamProfiles =
+    map
+      (replaceStrings ["$HOME" "$USER"] ["@{HOME}" "@{PAM_USER}"])
+      cfg.profiles;
+
+in
+
+{
+
+  options = {
+
+    environment.sessionVariables = mkOption {
+      default = {};
+      description = ''
+        A set of environment variables used in the global environment.
+        These variables will be set by PAM early in the login process.
+
+        The value of each session variable can be either a string or a
+        list of strings. The latter is concatenated, interspersed with
+        colon characters.
+
+        Note, due to limitations in the PAM format values may not
+        contain the <literal>"</literal> character.
+
+        Also, these variables are merged into
+        <xref linkend="opt-environment.variables"/> and it is
+        therefore not possible to use PAM style variables such as
+        <code>@{HOME}</code>.
+      '';
+      type = with types; attrsOf (either str (listOf str));
+      apply = mapAttrs (n: v: if isList v then concatStringsSep ":" v else v);
+    };
+
+    environment.profileRelativeSessionVariables = mkOption {
+      type = types.attrsOf (types.listOf types.str);
+      example = { PATH = [ "/bin" ]; MANPATH = [ "/man" "/share/man" ]; };
+      description = ''
+        Attribute set of environment variable used in the global
+        environment. These variables will be set by PAM early in the
+        login process.
+
+        Variable substitution is available as described in
+        <citerefentry>
+          <refentrytitle>pam_env.conf</refentrytitle>
+          <manvolnum>5</manvolnum>
+        </citerefentry>.
+
+        Each attribute maps to a list of relative paths. Each relative
+        path is appended to the each profile of
+        <option>environment.profiles</option> to form the content of
+        the corresponding environment variable.
+
+        Also, these variables are merged into
+        <xref linkend="opt-environment.profileRelativeEnvVars"/> and it is
+        therefore not possible to use PAM style variables such as
+        <code>@{HOME}</code>.
+      '';
+    };
+
+  };
+
+  config = {
+
+    system.build.pamEnvironment =
+      let
+        suffixedVariables =
+          flip mapAttrs cfg.profileRelativeSessionVariables (envVar: suffixes:
+            flip concatMap pamProfiles (profile:
+              map (suffix: "${profile}${suffix}") suffixes
+            )
+          );
+
+        pamVariable = n: v:
+          ''${n}   DEFAULT="${concatStringsSep ":" (toList v)}"'';
+
+        pamVariables =
+          concatStringsSep "\n"
+          (mapAttrsToList pamVariable
+          (zipAttrsWith (n: concatLists)
+            [
+              (mapAttrs (n: toList) cfg.sessionVariables)
+              suffixedVariables
+            ]));
+      in
+        pkgs.writeText "pam-environment" "${pamVariables}\n";
+
+  };
+
+}
diff --git a/nixpkgs/nixos/modules/config/system-path.nix b/nixpkgs/nixos/modules/config/system-path.nix
new file mode 100644
index 000000000000..aba9bc0945b1
--- /dev/null
+++ b/nixpkgs/nixos/modules/config/system-path.nix
@@ -0,0 +1,150 @@
+# This module defines the packages that appear in
+# /run/current-system/sw.
+
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  requiredPackages = map (pkg: setPrio ((pkg.meta.priority or 5) + 3) pkg)
+    [ config.nix.package
+      pkgs.acl
+      pkgs.attr
+      pkgs.bashInteractive # bash with ncurses support
+      pkgs.bzip2
+      pkgs.coreutils-full
+      pkgs.cpio
+      pkgs.curl
+      pkgs.diffutils
+      pkgs.findutils
+      pkgs.gawk
+      pkgs.stdenv.cc.libc
+      pkgs.getent
+      pkgs.getconf
+      pkgs.gnugrep
+      pkgs.gnupatch
+      pkgs.gnused
+      pkgs.gnutar
+      pkgs.gzip
+      pkgs.xz
+      pkgs.less
+      pkgs.libcap
+      pkgs.nano
+      pkgs.ncurses
+      pkgs.netcat
+      pkgs.nix-info
+      config.programs.ssh.package
+      pkgs.perl
+      pkgs.procps
+      pkgs.rsync
+      pkgs.strace
+      pkgs.su
+      pkgs.time
+      pkgs.utillinux
+      pkgs.which # 88K size
+    ];
+
+in
+
+{
+  options = {
+
+    environment = {
+
+      systemPackages = mkOption {
+        type = types.listOf types.package;
+        default = [];
+        example = literalExample "[ pkgs.firefox pkgs.thunderbird ]";
+        description = ''
+          The set of packages that appear in
+          /run/current-system/sw.  These packages are
+          automatically available to all users, and are
+          automatically updated every time you rebuild the system
+          configuration.  (The latter is the main difference with
+          installing them in the default profile,
+          <filename>/nix/var/nix/profiles/default</filename>.
+        '';
+      };
+
+      pathsToLink = mkOption {
+        type = types.listOf types.str;
+        # Note: We need `/lib' to be among `pathsToLink' for NSS modules
+        # to work.
+        default = [];
+        example = ["/"];
+        description = "List of directories to be symlinked in <filename>/run/current-system/sw</filename>.";
+      };
+
+      extraOutputsToInstall = mkOption {
+        type = types.listOf types.str;
+        default = [ ];
+        example = [ "doc" "info" "devdoc" ];
+        description = "List of additional package outputs to be symlinked into <filename>/run/current-system/sw</filename>.";
+      };
+
+      extraSetup = mkOption {
+        type = types.lines;
+        default = "";
+        description = "Shell fragments to be run after the system environment has been created. This should only be used for things that need to modify the internals of the environment, e.g. generating MIME caches. The environment being built can be accessed at $out.";
+      };
+
+    };
+
+    system = {
+
+      path = mkOption {
+        internal = true;
+        description = ''
+          The packages you want in the boot environment.
+        '';
+      };
+
+    };
+
+  };
+
+  config = {
+
+    environment.systemPackages = requiredPackages;
+
+    environment.pathsToLink =
+      [ "/bin"
+        "/etc/xdg"
+        "/etc/gtk-2.0"
+        "/etc/gtk-3.0"
+        "/lib" # FIXME: remove and update debug-info.nix
+        "/sbin"
+        "/share/emacs"
+        "/share/nano"
+        "/share/org"
+        "/share/themes"
+        "/share/vim-plugins"
+        "/share/vulkan"
+        "/share/kservices5"
+        "/share/kservicetypes5"
+        "/share/kxmlgui5"
+      ];
+
+    system.path = pkgs.buildEnv {
+      name = "system-path";
+      paths = config.environment.systemPackages;
+      inherit (config.environment) pathsToLink extraOutputsToInstall;
+      ignoreCollisions = true;
+      # !!! Hacky, should modularise.
+      # outputs TODO: note that the tools will often not be linked by default
+      postBuild =
+        ''
+          # Remove wrapped binaries, they shouldn't be accessible via PATH.
+          find $out/bin -maxdepth 1 -name ".*-wrapped" -type l -delete
+
+          if [ -x $out/bin/glib-compile-schemas -a -w $out/share/glib-2.0/schemas ]; then
+              $out/bin/glib-compile-schemas $out/share/glib-2.0/schemas
+          fi
+
+          ${config.environment.extraSetup}
+        '';
+    };
+
+  };
+}
diff --git a/nixpkgs/nixos/modules/config/terminfo.nix b/nixpkgs/nixos/modules/config/terminfo.nix
new file mode 100644
index 000000000000..1396640af672
--- /dev/null
+++ b/nixpkgs/nixos/modules/config/terminfo.nix
@@ -0,0 +1,33 @@
+# This module manages the terminfo database
+# and its integration in the system.
+{ config, ... }:
+{
+  config = {
+
+    environment.pathsToLink = [
+      "/share/terminfo"
+    ];
+
+    environment.etc.terminfo = {
+      source = "${config.system.path}/share/terminfo";
+    };
+
+    environment.profileRelativeSessionVariables = {
+      TERMINFO_DIRS = [ "/share/terminfo" ];
+    };
+
+    environment.extraInit = ''
+
+      # reset TERM with new TERMINFO available (if any)
+      export TERM=$TERM
+    '';
+
+    security.sudo.extraConfig = ''
+
+      # Keep terminfo database for root and %wheel.
+      Defaults:root,%wheel env_keep+=TERMINFO_DIRS
+      Defaults:root,%wheel env_keep+=TERMINFO
+    '';
+
+  };
+}
diff --git a/nixpkgs/nixos/modules/config/unix-odbc-drivers.nix b/nixpkgs/nixos/modules/config/unix-odbc-drivers.nix
new file mode 100644
index 000000000000..8dd811727389
--- /dev/null
+++ b/nixpkgs/nixos/modules/config/unix-odbc-drivers.nix
@@ -0,0 +1,38 @@
+{ config, lib, ... }:
+
+with lib;
+
+# unixODBC drivers (this solution is not perfect.. Because the user has to
+# ask the admin to add a driver.. but it's simple and works
+
+let
+  iniDescription = pkg: ''
+    [${pkg.fancyName}]
+    Description = ${pkg.meta.description}
+    Driver = ${pkg}/${pkg.driver}
+  '';
+
+in {
+  ###### interface
+
+  options = {
+    environment.unixODBCDrivers = mkOption {
+      type = types.listOf types.package;
+      default = [];
+      example = literalExample "with pkgs.unixODBCDrivers; [ sqlite psql ]";
+      description = ''
+        Specifies Unix ODBC drivers to be registered in
+        <filename>/etc/odbcinst.ini</filename>.  You may also want to
+        add <literal>pkgs.unixODBC</literal> to the system path to get
+        a command line client to connnect to ODBC databases.
+      '';
+    };
+  };
+
+  ###### implementation
+
+  config = mkIf (config.environment.unixODBCDrivers != []) {
+    environment.etc."odbcinst.ini".text = concatMapStringsSep "\n" iniDescription config.environment.unixODBCDrivers;
+  };
+
+}
diff --git a/nixpkgs/nixos/modules/config/update-users-groups.pl b/nixpkgs/nixos/modules/config/update-users-groups.pl
new file mode 100644
index 000000000000..ee5c77c1a908
--- /dev/null
+++ b/nixpkgs/nixos/modules/config/update-users-groups.pl
@@ -0,0 +1,285 @@
+use strict;
+use File::Basename;
+use File::Path qw(make_path);
+use File::Slurp;
+use JSON;
+
+make_path("/var/lib/nixos", { mode => 0755 });
+
+
+# Keep track of deleted uids and gids.
+my $uidMapFile = "/var/lib/nixos/uid-map";
+my $uidMap = -e $uidMapFile ? decode_json(read_file($uidMapFile)) : {};
+
+my $gidMapFile = "/var/lib/nixos/gid-map";
+my $gidMap = -e $gidMapFile ? decode_json(read_file($gidMapFile)) : {};
+
+
+sub updateFile {
+    my ($path, $contents, $perms) = @_;
+    write_file("$path.tmp", { binmode => ':utf8', perms => $perms // 0644 }, $contents);
+    rename("$path.tmp", $path) or die;
+}
+
+
+sub hashPassword {
+    my ($password) = @_;
+    my $salt = "";
+    my @chars = ('.', '/', 0..9, 'A'..'Z', 'a'..'z');
+    $salt .= $chars[rand 64] for (1..8);
+    return crypt($password, '$6$' . $salt . '$');
+}
+
+
+# Functions for allocating free GIDs/UIDs. FIXME: respect ID ranges in
+# /etc/login.defs.
+sub allocId {
+    my ($used, $prevUsed, $idMin, $idMax, $up, $getid) = @_;
+    my $id = $up ? $idMin : $idMax;
+    while ($id >= $idMin && $id <= $idMax) {
+        if (!$used->{$id} && !$prevUsed->{$id} && !defined &$getid($id)) {
+            $used->{$id} = 1;
+            return $id;
+        }
+        $used->{$id} = 1;
+        if ($up) { $id++; } else { $id--; }
+    }
+    die "$0: out of free UIDs or GIDs\n";
+}
+
+my (%gidsUsed, %uidsUsed, %gidsPrevUsed, %uidsPrevUsed);
+
+sub allocGid {
+    my ($name) = @_;
+    my $prevGid = $gidMap->{$name};
+    if (defined $prevGid && !defined $gidsUsed{$prevGid}) {
+        print STDERR "reviving group '$name' with GID $prevGid\n";
+        $gidsUsed{$prevGid} = 1;
+        return $prevGid;
+    }
+    return allocId(\%gidsUsed, \%gidsPrevUsed, 400, 499, 0, sub { my ($gid) = @_; getgrgid($gid) });
+}
+
+sub allocUid {
+    my ($name, $isSystemUser) = @_;
+    my ($min, $max, $up) = $isSystemUser ? (400, 499, 0) : (1000, 29999, 1);
+    my $prevUid = $uidMap->{$name};
+    if (defined $prevUid && $prevUid >= $min && $prevUid <= $max && !defined $uidsUsed{$prevUid}) {
+        print STDERR "reviving user '$name' with UID $prevUid\n";
+        $uidsUsed{$prevUid} = 1;
+        return $prevUid;
+    }
+    return allocId(\%uidsUsed, \%uidsPrevUsed, $min, $max, $up, sub { my ($uid) = @_; getpwuid($uid) });
+}
+
+
+# Read the declared users/groups.
+my $spec = decode_json(read_file($ARGV[0]));
+
+# Don't allocate UIDs/GIDs that are manually assigned.
+foreach my $g (@{$spec->{groups}}) {
+    $gidsUsed{$g->{gid}} = 1 if defined $g->{gid};
+}
+
+foreach my $u (@{$spec->{users}}) {
+    $uidsUsed{$u->{uid}} = 1 if defined $u->{uid};
+}
+
+# Likewise for previously used but deleted UIDs/GIDs.
+$uidsPrevUsed{$_} = 1 foreach values %{$uidMap};
+$gidsPrevUsed{$_} = 1 foreach values %{$gidMap};
+
+
+# Read the current /etc/group.
+sub parseGroup {
+    chomp;
+    my @f = split(':', $_, -4);
+    my $gid = $f[2] eq "" ? undef : int($f[2]);
+    $gidsUsed{$gid} = 1 if defined $gid;
+    return ($f[0], { name => $f[0], password => $f[1], gid => $gid, members => $f[3] });
+}
+
+my %groupsCur = -f "/etc/group" ? map { parseGroup } read_file("/etc/group") : ();
+
+# Read the current /etc/passwd.
+sub parseUser {
+    chomp;
+    my @f = split(':', $_, -7);
+    my $uid = $f[2] eq "" ? undef : int($f[2]);
+    $uidsUsed{$uid} = 1 if defined $uid;
+    return ($f[0], { name => $f[0], fakePassword => $f[1], uid => $uid,
+        gid => $f[3], description => $f[4], home => $f[5], shell => $f[6] });
+}
+
+my %usersCur = -f "/etc/passwd" ? map { parseUser } read_file("/etc/passwd") : ();
+
+# Read the groups that were created declaratively (i.e. not by groups)
+# in the past. These must be removed if they are no longer in the
+# current spec.
+my $declGroupsFile = "/var/lib/nixos/declarative-groups";
+my %declGroups;
+$declGroups{$_} = 1 foreach split / /, -e $declGroupsFile ? read_file($declGroupsFile) : "";
+
+# Idem for the users.
+my $declUsersFile = "/var/lib/nixos/declarative-users";
+my %declUsers;
+$declUsers{$_} = 1 foreach split / /, -e $declUsersFile ? read_file($declUsersFile) : "";
+
+
+# Generate a new /etc/group containing the declared groups.
+my %groupsOut;
+foreach my $g (@{$spec->{groups}}) {
+    my $name = $g->{name};
+    my $existing = $groupsCur{$name};
+
+    my %members = map { ($_, 1) } @{$g->{members}};
+
+    if (defined $existing) {
+        $g->{gid} = $existing->{gid} if !defined $g->{gid};
+        if ($g->{gid} != $existing->{gid}) {
+            warn "warning: not applying GID change of group ‘$name’ ($existing->{gid} -> $g->{gid})\n";
+            $g->{gid} = $existing->{gid};
+        }
+        $g->{password} = $existing->{password}; # do we want this?
+        if ($spec->{mutableUsers}) {
+            # Merge in non-declarative group members.
+            foreach my $uname (split /,/, $existing->{members} // "") {
+                $members{$uname} = 1 if !defined $declUsers{$uname};
+            }
+        }
+    } else {
+        $g->{gid} = allocGid($name) if !defined $g->{gid};
+        $g->{password} = "x";
+    }
+
+    $g->{members} = join ",", sort(keys(%members));
+    $groupsOut{$name} = $g;
+
+    $gidMap->{$name} = $g->{gid};
+}
+
+# Update the persistent list of declarative groups.
+updateFile($declGroupsFile, join(" ", sort(keys %groupsOut)));
+
+# Merge in the existing /etc/group.
+foreach my $name (keys %groupsCur) {
+    my $g = $groupsCur{$name};
+    next if defined $groupsOut{$name};
+    if (!$spec->{mutableUsers} || defined $declGroups{$name}) {
+        print STDERR "removing group ‘$name’\n";
+    } else {
+        $groupsOut{$name} = $g;
+    }
+}
+
+
+# Rewrite /etc/group. FIXME: acquire lock.
+my @lines = map { join(":", $_->{name}, $_->{password}, $_->{gid}, $_->{members}) . "\n" }
+    (sort { $a->{gid} <=> $b->{gid} } values(%groupsOut));
+updateFile($gidMapFile, encode_json($gidMap));
+updateFile("/etc/group", \@lines);
+system("nscd --invalidate group");
+
+# Generate a new /etc/passwd containing the declared users.
+my %usersOut;
+foreach my $u (@{$spec->{users}}) {
+    my $name = $u->{name};
+
+    # Resolve the gid of the user.
+    if ($u->{group} =~ /^[0-9]$/) {
+        $u->{gid} = $u->{group};
+    } elsif (defined $groupsOut{$u->{group}}) {
+        $u->{gid} = $groupsOut{$u->{group}}->{gid} // die;
+    } else {
+        warn "warning: user ‘$name’ has unknown group ‘$u->{group}’\n";
+        $u->{gid} = 65534;
+    }
+
+    my $existing = $usersCur{$name};
+    if (defined $existing) {
+        $u->{uid} = $existing->{uid} if !defined $u->{uid};
+        if ($u->{uid} != $existing->{uid}) {
+            warn "warning: not applying UID change of user ‘$name’ ($existing->{uid} -> $u->{uid})\n";
+            $u->{uid} = $existing->{uid};
+        }
+    } else {
+        $u->{uid} = allocUid($name, $u->{isSystemUser}) if !defined $u->{uid};
+
+        if (defined $u->{initialPassword}) {
+            $u->{hashedPassword} = hashPassword($u->{initialPassword});
+        } elsif (defined $u->{initialHashedPassword}) {
+            $u->{hashedPassword} = $u->{initialHashedPassword};
+        }
+    }
+
+    # Create a home directory.
+    if ($u->{createHome}) {
+        make_path(dirname($u->{home}), { mode => 0755 });
+        mkdir $u->{home}, 0700 if ! -e $u->{home};
+        chown $u->{uid}, $u->{gid}, $u->{home};
+    }
+
+    if (defined $u->{passwordFile}) {
+        if (-e $u->{passwordFile}) {
+            $u->{hashedPassword} = read_file($u->{passwordFile});
+            chomp $u->{hashedPassword};
+        } else {
+            warn "warning: password file ‘$u->{passwordFile}’ does not exist\n";
+        }
+    } elsif (defined $u->{password}) {
+        $u->{hashedPassword} = hashPassword($u->{password});
+    }
+
+    $u->{fakePassword} = $existing->{fakePassword} // "x";
+    $usersOut{$name} = $u;
+
+    $uidMap->{$name} = $u->{uid};
+}
+
+# Update the persistent list of declarative users.
+updateFile($declUsersFile, join(" ", sort(keys %usersOut)));
+
+# Merge in the existing /etc/passwd.
+foreach my $name (keys %usersCur) {
+    my $u = $usersCur{$name};
+    next if defined $usersOut{$name};
+    if (!$spec->{mutableUsers} || defined $declUsers{$name}) {
+        print STDERR "removing user ‘$name’\n";
+    } else {
+        $usersOut{$name} = $u;
+    }
+}
+
+# Rewrite /etc/passwd. FIXME: acquire lock.
+@lines = map { join(":", $_->{name}, $_->{fakePassword}, $_->{uid}, $_->{gid}, $_->{description}, $_->{home}, $_->{shell}) . "\n" }
+    (sort { $a->{uid} <=> $b->{uid} } (values %usersOut));
+updateFile($uidMapFile, encode_json($uidMap));
+updateFile("/etc/passwd", \@lines);
+system("nscd --invalidate passwd");
+
+
+# Rewrite /etc/shadow to add new accounts or remove dead ones.
+my @shadowNew;
+my %shadowSeen;
+
+foreach my $line (-f "/etc/shadow" ? read_file("/etc/shadow") : ()) {
+    chomp $line;
+    my ($name, $hashedPassword, @rest) = split(':', $line, -9);
+    my $u = $usersOut{$name};;
+    next if !defined $u;
+    $hashedPassword = "!" if !$spec->{mutableUsers};
+    $hashedPassword = $u->{hashedPassword} if defined $u->{hashedPassword} && !$spec->{mutableUsers}; # FIXME
+    chomp $hashedPassword;
+    push @shadowNew, join(":", $name, $hashedPassword, @rest) . "\n";
+    $shadowSeen{$name} = 1;
+}
+
+foreach my $u (values %usersOut) {
+    next if defined $shadowSeen{$u->{name}};
+    my $hashedPassword = "!";
+    $hashedPassword = $u->{hashedPassword} if defined $u->{hashedPassword};
+    # FIXME: set correct value for sp_lstchg.
+    push @shadowNew, join(":", $u->{name}, $hashedPassword, "1::::::") . "\n";
+}
+
+updateFile("/etc/shadow", \@shadowNew, 0600);
diff --git a/nixpkgs/nixos/modules/config/users-groups.nix b/nixpkgs/nixos/modules/config/users-groups.nix
new file mode 100644
index 000000000000..ba79bd3d6ecc
--- /dev/null
+++ b/nixpkgs/nixos/modules/config/users-groups.nix
@@ -0,0 +1,601 @@
+{ config, lib, utils, pkgs, ... }:
+
+with lib;
+
+let
+  ids = config.ids;
+  cfg = config.users;
+
+  passwordDescription = ''
+    The options <option>hashedPassword</option>,
+    <option>password</option> and <option>passwordFile</option>
+    controls what password is set for the user.
+    <option>hashedPassword</option> overrides both
+    <option>password</option> and <option>passwordFile</option>.
+    <option>password</option> overrides <option>passwordFile</option>.
+    If none of these three options are set, no password is assigned to
+    the user, and the user will not be able to do password logins.
+    If the option <option>users.mutableUsers</option> is true, the
+    password defined in one of the three options will only be set when
+    the user is created for the first time. After that, you are free to
+    change the password with the ordinary user management commands. If
+    <option>users.mutableUsers</option> is false, you cannot change
+    user passwords, they will always be set according to the password
+    options.
+  '';
+
+  hashedPasswordDescription = ''
+    To generate hashed password install <literal>mkpasswd</literal>
+    package and run <literal>mkpasswd -m sha-512</literal>.
+  '';
+
+  userOpts = { name, config, ... }: {
+
+    options = {
+
+      name = mkOption {
+        type = types.str;
+        apply = x: assert (builtins.stringLength x < 32 || abort "Username '${x}' is longer than 31 characters which is not allowed!"); x;
+        description = ''
+          The name of the user account. If undefined, the name of the
+          attribute set will be used.
+        '';
+      };
+
+      description = mkOption {
+        type = types.str;
+        default = "";
+        example = "Alice Q. User";
+        description = ''
+          A short description of the user account, typically the
+          user's full name.  This is actually the “GECOS” or “comment”
+          field in <filename>/etc/passwd</filename>.
+        '';
+      };
+
+      uid = mkOption {
+        type = with types; nullOr int;
+        default = null;
+        description = ''
+          The account UID. If the UID is null, a free UID is picked on
+          activation.
+        '';
+      };
+
+      isSystemUser = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Indicates if the user is a system user or not. This option
+          only has an effect if <option>uid</option> is
+          <option>null</option>, in which case it determines whether
+          the user's UID is allocated in the range for system users
+          (below 500) or in the range for normal users (starting at
+          1000).
+        '';
+      };
+
+      isNormalUser = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Indicates whether this is an account for a “real” user. This
+          automatically sets <option>group</option> to
+          <literal>users</literal>, <option>createHome</option> to
+          <literal>true</literal>, <option>home</option> to
+          <filename>/home/<replaceable>username</replaceable></filename>,
+          <option>useDefaultShell</option> to <literal>true</literal>,
+          and <option>isSystemUser</option> to
+          <literal>false</literal>.
+        '';
+      };
+
+      group = mkOption {
+        type = types.str;
+        apply = x: assert (builtins.stringLength x < 32 || abort "Group name '${x}' is longer than 31 characters which is not allowed!"); x;
+        default = "nogroup";
+        description = "The user's primary group.";
+      };
+
+      extraGroups = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        description = "The user's auxiliary groups.";
+      };
+
+      home = mkOption {
+        type = types.path;
+        default = "/var/empty";
+        description = "The user's home directory.";
+      };
+
+      cryptHomeLuks = mkOption {
+        type = with types; nullOr str;
+        default = null;
+        description = ''
+          Path to encrypted luks device that contains
+          the user's home directory.
+        '';
+      };
+
+      shell = mkOption {
+        type = types.either types.shellPackage types.path;
+        default = pkgs.shadow;
+        defaultText = "pkgs.shadow";
+        example = literalExample "pkgs.bashInteractive";
+        description = ''
+          The path to the user's shell. Can use shell derivations,
+          like <literal>pkgs.bashInteractive</literal>. Don’t
+          forget to enable your shell in
+          <literal>programs</literal> if necessary,
+          like <code>programs.zsh.enable = true;</code>.
+        '';
+      };
+
+      subUidRanges = mkOption {
+        type = with types; listOf (submodule subordinateUidRange);
+        default = [];
+        example = [
+          { startUid = 1000; count = 1; }
+          { startUid = 100001; count = 65534; }
+        ];
+        description = ''
+          Subordinate user ids that user is allowed to use.
+          They are set into <filename>/etc/subuid</filename> and are used
+          by <literal>newuidmap</literal> for user namespaces.
+        '';
+      };
+
+      subGidRanges = mkOption {
+        type = with types; listOf (submodule subordinateGidRange);
+        default = [];
+        example = [
+          { startGid = 100; count = 1; }
+          { startGid = 1001; count = 999; }
+        ];
+        description = ''
+          Subordinate group ids that user is allowed to use.
+          They are set into <filename>/etc/subgid</filename> and are used
+          by <literal>newgidmap</literal> for user namespaces.
+        '';
+      };
+
+      createHome = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          If true, the home directory will be created automatically. If this
+          option is true and the home directory already exists but is not
+          owned by the user, directory owner and group will be changed to
+          match the user.
+        '';
+      };
+
+      useDefaultShell = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          If true, the user's shell will be set to
+          <option>users.defaultUserShell</option>.
+        '';
+      };
+
+      hashedPassword = mkOption {
+        type = with types; nullOr str;
+        default = null;
+        description = ''
+          Specifies the hashed password for the user.
+          ${passwordDescription}
+          ${hashedPasswordDescription}
+        '';
+      };
+
+      password = mkOption {
+        type = with types; nullOr str;
+        default = null;
+        description = ''
+          Specifies the (clear text) password for the user.
+          Warning: do not set confidential information here
+          because it is world-readable in the Nix store. This option
+          should only be used for public accounts.
+          ${passwordDescription}
+        '';
+      };
+
+      passwordFile = mkOption {
+        type = with types; nullOr str;
+        default = null;
+        description = ''
+          The full path to a file that contains the user's password. The password
+          file is read on each system activation. The file should contain
+          exactly one line, which should be the password in an encrypted form
+          that is suitable for the <literal>chpasswd -e</literal> command.
+          ${passwordDescription}
+        '';
+      };
+
+      initialHashedPassword = mkOption {
+        type = with types; nullOr str;
+        default = null;
+        description = ''
+          Specifies the initial hashed password for the user, i.e. the
+          hashed password assigned if the user does not already
+          exist. If <option>users.mutableUsers</option> is true, the
+          password can be changed subsequently using the
+          <command>passwd</command> command. Otherwise, it's
+          equivalent to setting the <option>hashedPassword</option> option.
+
+          ${hashedPasswordDescription}
+        '';
+      };
+
+      initialPassword = mkOption {
+        type = with types; nullOr str;
+        default = null;
+        description = ''
+          Specifies the initial password for the user, i.e. the
+          password assigned if the user does not already exist. If
+          <option>users.mutableUsers</option> is true, the password
+          can be changed subsequently using the
+          <command>passwd</command> command. Otherwise, it's
+          equivalent to setting the <option>password</option>
+          option. The same caveat applies: the password specified here
+          is world-readable in the Nix store, so it should only be
+          used for guest accounts or passwords that will be changed
+          promptly.
+        '';
+      };
+
+      packages = mkOption {
+        type = types.listOf types.package;
+        default = [];
+        example = literalExample "[ pkgs.firefox pkgs.thunderbird ]";
+        description = ''
+          The set of packages that should be made availabe to the user.
+          This is in contrast to <option>environment.systemPackages</option>,
+          which adds packages to all users.
+        '';
+      };
+
+    };
+
+    config = mkMerge
+      [ { name = mkDefault name;
+          shell = mkIf config.useDefaultShell (mkDefault cfg.defaultUserShell);
+        }
+        (mkIf config.isNormalUser {
+          group = mkDefault "users";
+          createHome = mkDefault true;
+          home = mkDefault "/home/${config.name}";
+          useDefaultShell = mkDefault true;
+          isSystemUser = mkDefault false;
+        })
+        # If !mutableUsers, setting ‘initialPassword’ is equivalent to
+        # setting ‘password’ (and similarly for hashed passwords).
+        (mkIf (!cfg.mutableUsers && config.initialPassword != null) {
+          password = mkDefault config.initialPassword;
+        })
+        (mkIf (!cfg.mutableUsers && config.initialHashedPassword != null) {
+          hashedPassword = mkDefault config.initialHashedPassword;
+        })
+      ];
+
+  };
+
+  groupOpts = { name, ... }: {
+
+    options = {
+
+      name = mkOption {
+        type = types.str;
+        description = ''
+          The name of the group. If undefined, the name of the attribute set
+          will be used.
+        '';
+      };
+
+      gid = mkOption {
+        type = with types; nullOr int;
+        default = null;
+        description = ''
+          The group GID. If the GID is null, a free GID is picked on
+          activation.
+        '';
+      };
+
+      members = mkOption {
+        type = with types; listOf str;
+        default = [];
+        description = ''
+          The user names of the group members, added to the
+          <literal>/etc/group</literal> file.
+        '';
+      };
+
+    };
+
+    config = {
+      name = mkDefault name;
+    };
+
+  };
+
+  subordinateUidRange = {
+    options = {
+      startUid = mkOption {
+        type = types.int;
+        description = ''
+          Start of the range of subordinate user ids that user is
+          allowed to use.
+        '';
+      };
+      count = mkOption {
+        type = types.int;
+        default = 1;
+        description = ''Count of subordinate user ids'';
+      };
+    };
+  };
+
+  subordinateGidRange = {
+    options = {
+      startGid = mkOption {
+        type = types.int;
+        description = ''
+          Start of the range of subordinate group ids that user is
+          allowed to use.
+        '';
+      };
+      count = mkOption {
+        type = types.int;
+        default = 1;
+        description = ''Count of subordinate group ids'';
+      };
+    };
+  };
+
+  mkSubuidEntry = user: concatStrings (
+    map (range: "${user.name}:${toString range.startUid}:${toString range.count}\n")
+      user.subUidRanges);
+
+  subuidFile = concatStrings (map mkSubuidEntry (attrValues cfg.users));
+
+  mkSubgidEntry = user: concatStrings (
+    map (range: "${user.name}:${toString range.startGid}:${toString range.count}\n")
+        user.subGidRanges);
+
+  subgidFile = concatStrings (map mkSubgidEntry (attrValues cfg.users));
+
+  idsAreUnique = set: idAttr: !(fold (name: args@{ dup, acc }:
+    let
+      id = builtins.toString (builtins.getAttr idAttr (builtins.getAttr name set));
+      exists = builtins.hasAttr id acc;
+      newAcc = acc // (builtins.listToAttrs [ { name = id; value = true; } ]);
+    in if dup then args else if exists
+      then builtins.trace "Duplicate ${idAttr} ${id}" { dup = true; acc = null; }
+      else { dup = false; acc = newAcc; }
+    ) { dup = false; acc = {}; } (builtins.attrNames set)).dup;
+
+  uidsAreUnique = idsAreUnique (filterAttrs (n: u: u.uid != null) cfg.users) "uid";
+  gidsAreUnique = idsAreUnique (filterAttrs (n: g: g.gid != null) cfg.groups) "gid";
+
+  spec = pkgs.writeText "users-groups.json" (builtins.toJSON {
+    inherit (cfg) mutableUsers;
+    users = mapAttrsToList (_: u:
+      { inherit (u)
+          name uid group description home createHome isSystemUser
+          password passwordFile hashedPassword
+          initialPassword initialHashedPassword;
+        shell = utils.toShellPath u.shell;
+      }) cfg.users;
+    groups = mapAttrsToList (n: g:
+      { inherit (g) name gid;
+        members = g.members ++ (mapAttrsToList (n: u: u.name) (
+          filterAttrs (n: u: elem g.name u.extraGroups) cfg.users
+        ));
+      }) cfg.groups;
+  });
+
+  systemShells =
+    let
+      shells = mapAttrsToList (_: u: u.shell) cfg.users;
+    in
+      filter types.shellPackage.check shells;
+
+in {
+
+  ###### interface
+
+  options = {
+
+    users.mutableUsers = mkOption {
+      type = types.bool;
+      default = true;
+      description = ''
+        If set to <literal>true</literal>, you are free to add new users and groups to the system
+        with the ordinary <literal>useradd</literal> and
+        <literal>groupadd</literal> commands. On system activation, the
+        existing contents of the <literal>/etc/passwd</literal> and
+        <literal>/etc/group</literal> files will be merged with the
+        contents generated from the <literal>users.users</literal> and
+        <literal>users.groups</literal> options.
+        The initial password for a user will be set
+        according to <literal>users.users</literal>, but existing passwords
+        will not be changed.
+
+        <warning><para>
+        If set to <literal>false</literal>, the contents of the user and
+        group files will simply be replaced on system activation. This also
+        holds for the user passwords; all changed
+        passwords will be reset according to the
+        <literal>users.users</literal> configuration on activation.
+        </para></warning>
+      '';
+    };
+
+    users.enforceIdUniqueness = mkOption {
+      type = types.bool;
+      default = true;
+      description = ''
+        Whether to require that no two users/groups share the same uid/gid.
+      '';
+    };
+
+    users.users = mkOption {
+      default = {};
+      type = with types; loaOf (submodule userOpts);
+      example = {
+        alice = {
+          uid = 1234;
+          description = "Alice Q. User";
+          home = "/home/alice";
+          createHome = true;
+          group = "users";
+          extraGroups = ["wheel"];
+          shell = "/bin/sh";
+        };
+      };
+      description = ''
+        Additional user accounts to be created automatically by the system.
+        This can also be used to set options for root.
+      '';
+    };
+
+    users.groups = mkOption {
+      default = {};
+      example =
+        { students.gid = 1001;
+          hackers = { };
+        };
+      type = with types; loaOf (submodule groupOpts);
+      description = ''
+        Additional groups to be created automatically by the system.
+      '';
+    };
+
+    # FIXME: obsolete - will remove.
+    security.initialRootPassword = mkOption {
+      type = types.str;
+      default = "!";
+      example = "";
+      visible = false;
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = {
+
+    users.users = {
+      root = {
+        uid = ids.uids.root;
+        description = "System administrator";
+        home = "/root";
+        shell = mkDefault cfg.defaultUserShell;
+        group = "root";
+        initialHashedPassword = mkDefault config.security.initialRootPassword;
+      };
+      nobody = {
+        uid = ids.uids.nobody;
+        description = "Unprivileged account (don't use!)";
+        group = "nogroup";
+      };
+    };
+
+    users.groups = {
+      root.gid = ids.gids.root;
+      wheel.gid = ids.gids.wheel;
+      disk.gid = ids.gids.disk;
+      kmem.gid = ids.gids.kmem;
+      tty.gid = ids.gids.tty;
+      floppy.gid = ids.gids.floppy;
+      uucp.gid = ids.gids.uucp;
+      lp.gid = ids.gids.lp;
+      cdrom.gid = ids.gids.cdrom;
+      tape.gid = ids.gids.tape;
+      audio.gid = ids.gids.audio;
+      video.gid = ids.gids.video;
+      dialout.gid = ids.gids.dialout;
+      nogroup.gid = ids.gids.nogroup;
+      users.gid = ids.gids.users;
+      nixbld.gid = ids.gids.nixbld;
+      utmp.gid = ids.gids.utmp;
+      adm.gid = ids.gids.adm;
+      input.gid = ids.gids.input;
+      kvm.gid = ids.gids.kvm;
+      render.gid = ids.gids.render;
+    };
+
+    system.activationScripts.users = stringAfter [ "stdio" ]
+      ''
+        install -m 0700 -d /root
+        install -m 0755 -d /home
+
+        ${pkgs.perl}/bin/perl -w \
+          -I${pkgs.perlPackages.FileSlurp}/${pkgs.perl.libPrefix} \
+          -I${pkgs.perlPackages.JSON}/${pkgs.perl.libPrefix} \
+          ${./update-users-groups.pl} ${spec}
+      '';
+
+    # for backwards compatibility
+    system.activationScripts.groups = stringAfter [ "users" ] "";
+
+    # Install all the user shells
+    environment.systemPackages = systemShells;
+
+    environment.etc = {
+      subuid = {
+        text = subuidFile;
+        mode = "0644";
+      };
+      subgid = {
+        text = subgidFile;
+        mode = "0644";
+      };
+    } // (mapAttrs' (name: { packages, ... }: {
+      name = "profiles/per-user/${name}";
+      value.source = pkgs.buildEnv {
+        name = "user-environment";
+        paths = packages;
+        inherit (config.environment) pathsToLink extraOutputsToInstall;
+        inherit (config.system.path) ignoreCollisions postBuild;
+      };
+    }) (filterAttrs (_: u: u.packages != []) cfg.users));
+
+    environment.profiles = [
+      "$HOME/.nix-profile"
+      "/etc/profiles/per-user/$USER"
+    ];
+
+    assertions = [
+      { assertion = !cfg.enforceIdUniqueness || (uidsAreUnique && gidsAreUnique);
+        message = "UIDs and GIDs must be unique!";
+      }
+      { # If mutableUsers is false, to prevent users creating a
+        # configuration that locks them out of the system, ensure that
+        # there is at least one "privileged" account that has a
+        # password or an SSH authorized key. Privileged accounts are
+        # root and users in the wheel group.
+        assertion = !cfg.mutableUsers ->
+          any id (mapAttrsToList (name: cfg:
+            (name == "root"
+             || cfg.group == "wheel"
+             || elem "wheel" cfg.extraGroups)
+            &&
+            ((cfg.hashedPassword != null && cfg.hashedPassword != "!")
+             || cfg.password != null
+             || cfg.passwordFile != null
+             || cfg.openssh.authorizedKeys.keys != []
+             || cfg.openssh.authorizedKeys.keyFiles != [])
+          ) cfg.users);
+        message = ''
+          Neither the root account nor any wheel user has a password or SSH authorized key.
+          You must set one to prevent being locked out of your system.'';
+      }
+    ];
+
+  };
+
+}
diff --git a/nixpkgs/nixos/modules/config/vpnc.nix b/nixpkgs/nixos/modules/config/vpnc.nix
new file mode 100644
index 000000000000..356e007c0a3e
--- /dev/null
+++ b/nixpkgs/nixos/modules/config/vpnc.nix
@@ -0,0 +1,41 @@
+{ config, lib, ... }:
+
+with lib;
+
+let
+  cfg = config.networking.vpnc;
+  mkServiceDef = name: value:
+    {
+      name = "vpnc/${name}.conf";
+      value = { text = value; };
+    };
+
+in
+{
+  options = {
+    networking.vpnc = {
+      services = mkOption {
+       type = types.attrsOf types.str;
+       default = {};
+       example = literalExample ''
+         { test = '''
+             IPSec gateway 192.168.1.1
+             IPSec ID someID
+             IPSec secret secretKey
+             Xauth username name
+             Xauth password pass
+           ''';
+         }
+       '';
+       description = 
+         ''
+           The names of cisco VPNs and their associated definitions
+         '';
+      };
+    };
+  };
+
+  config.environment.etc = mapAttrs' mkServiceDef cfg.services;
+}
+
+
diff --git a/nixpkgs/nixos/modules/config/vte.nix b/nixpkgs/nixos/modules/config/vte.nix
new file mode 100644
index 000000000000..d4a8c926fef2
--- /dev/null
+++ b/nixpkgs/nixos/modules/config/vte.nix
@@ -0,0 +1,52 @@
+# VTE
+
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+
+  vteInitSnippet = ''
+    # Show current working directory in VTE terminals window title.
+    # Supports both bash and zsh, requires interactive shell.
+    . ${pkgs.vte}/etc/profile.d/vte.sh
+  '';
+
+in
+
+{
+
+  options = {
+
+    programs.bash.vteIntegration = mkOption {
+      default = false;
+      type = types.bool;
+      description = ''
+        Whether to enable Bash integration for VTE terminals.
+        This allows it to preserve the current directory of the shell
+        across terminals.
+      '';
+    };
+
+    programs.zsh.vteIntegration = mkOption {
+      default = false;
+      type = types.bool;
+      description = ''
+        Whether to enable Zsh integration for VTE terminals.
+        This allows it to preserve the current directory of the shell
+        across terminals.
+      '';
+    };
+
+  };
+
+  config = mkMerge [
+    (mkIf config.programs.bash.vteIntegration {
+      programs.bash.interactiveShellInit = mkBefore vteInitSnippet;
+    })
+
+    (mkIf config.programs.zsh.vteIntegration {
+      programs.zsh.interactiveShellInit = vteInitSnippet;
+    })
+  ];
+}
diff --git a/nixpkgs/nixos/modules/config/xdg/autostart.nix b/nixpkgs/nixos/modules/config/xdg/autostart.nix
new file mode 100644
index 000000000000..0ee94fed818b
--- /dev/null
+++ b/nixpkgs/nixos/modules/config/xdg/autostart.nix
@@ -0,0 +1,22 @@
+{ config, lib, ... }:
+
+with lib;
+{
+  options = {
+    xdg.autostart.enable = mkOption {
+      type = types.bool;
+      default = true;
+      description = ''
+        Whether to install files to support the 
+        <link xlink:href="https://specifications.freedesktop.org/autostart-spec/autostart-spec-latest.html">XDG Autostart specification</link>.
+      '';
+    };
+  };
+
+  config = mkIf config.xdg.autostart.enable {
+    environment.pathsToLink = [ 
+      "/etc/xdg/autostart"
+    ];
+  };
+
+}
diff --git a/nixpkgs/nixos/modules/config/xdg/icons.nix b/nixpkgs/nixos/modules/config/xdg/icons.nix
new file mode 100644
index 000000000000..4677ce090b0b
--- /dev/null
+++ b/nixpkgs/nixos/modules/config/xdg/icons.nix
@@ -0,0 +1,38 @@
+{ config, lib, ... }:
+
+with lib;
+{
+  options = {
+    xdg.icons.enable = mkOption {
+      type = types.bool;
+      default = true;
+      description = ''
+        Whether to install files to support the
+        <link xlink:href="https://specifications.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html">XDG Icon Theme specification</link>.
+      '';
+    };
+  };
+
+  config = mkIf config.xdg.icons.enable {
+    environment.pathsToLink = [
+      "/share/icons"
+      "/share/pixmaps"
+    ];
+
+    # libXcursor looks for cursors in XCURSOR_PATH
+    # it mostly follows the spec for icons
+    # See: https://www.x.org/releases/current/doc/man/man3/Xcursor.3.xhtml Themes
+
+    # These are preferred so they come first in the list
+    environment.sessionVariables.XCURSOR_PATH = [
+      "$HOME/.icons"
+      "$HOME/.local/share/icons"
+    ];
+
+    environment.profileRelativeSessionVariables.XCURSOR_PATH = [
+      "/share/icons"
+      "/share/pixmaps"
+    ];
+  };
+
+}
diff --git a/nixpkgs/nixos/modules/config/xdg/menus.nix b/nixpkgs/nixos/modules/config/xdg/menus.nix
new file mode 100644
index 000000000000..c172692df5d7
--- /dev/null
+++ b/nixpkgs/nixos/modules/config/xdg/menus.nix
@@ -0,0 +1,25 @@
+{ config, lib, ... }:
+
+with lib;
+{
+  options = {
+    xdg.menus.enable = mkOption {
+      type = types.bool;
+      default = true;
+      description = ''
+        Whether to install files to support the 
+        <link xlink:href="https://specifications.freedesktop.org/menu-spec/menu-spec-latest.html">XDG Desktop Menu specification</link>.
+      '';
+    };
+  };
+
+  config = mkIf config.xdg.menus.enable {
+    environment.pathsToLink = [ 
+      "/share/applications"
+      "/share/desktop-directories"
+      "/etc/xdg/menus"
+      "/etc/xdg/menus/applications-merged"
+    ];
+  };
+
+}
diff --git a/nixpkgs/nixos/modules/config/xdg/mime.nix b/nixpkgs/nixos/modules/config/xdg/mime.nix
new file mode 100644
index 000000000000..a5374c2b468d
--- /dev/null
+++ b/nixpkgs/nixos/modules/config/xdg/mime.nix
@@ -0,0 +1,36 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+{
+  options = {
+    xdg.mime.enable = mkOption {
+      type = types.bool;
+      default = true;
+      description = ''
+        Whether to install files to support the
+        <link xlink:href="https://specifications.freedesktop.org/shared-mime-info-spec/shared-mime-info-spec-latest.html">XDG Shared MIME-info specification</link> and the
+        <link xlink:href="https://specifications.freedesktop.org/mime-apps-spec/mime-apps-spec-latest.html">XDG MIME Applications specification</link>.
+      '';
+    };
+  };
+
+  config = mkIf config.xdg.mime.enable {
+    environment.pathsToLink = [ "/share/mime" ];
+
+    environment.systemPackages = [
+      # this package also installs some useful data, as well as its utilities
+      pkgs.shared-mime-info
+    ];
+
+    environment.extraSetup = ''
+      if [ -w $out/share/mime ] && [ -d $out/share/mime/packages ]; then
+          XDG_DATA_DIRS=$out/share PKGSYSTEM_ENABLE_FSYNC=0 ${pkgs.buildPackages.shared-mime-info}/bin/update-mime-database -V $out/share/mime > /dev/null
+      fi
+
+      if [ -w $out/share/applications ]; then
+          ${pkgs.buildPackages.desktop-file-utils}/bin/update-desktop-database $out/share/applications
+      fi
+    '';
+  };
+
+}
diff --git a/nixpkgs/nixos/modules/config/xdg/portal.nix b/nixpkgs/nixos/modules/config/xdg/portal.nix
new file mode 100644
index 000000000000..bdbbfda2bb42
--- /dev/null
+++ b/nixpkgs/nixos/modules/config/xdg/portal.nix
@@ -0,0 +1,58 @@
+{ config, pkgs ,lib ,... }:
+
+with lib;
+
+{
+  options.xdg.portal = {
+    enable =
+      mkEnableOption "<link xlink:href='https://github.com/flatpak/xdg-desktop-portal'>xdg desktop integration</link>"//{
+        default = false;
+      };
+
+    extraPortals = mkOption {
+      type = types.listOf types.package;
+      default = [];
+      description = ''
+        List of additional portals to add to path. Portals allow interaction
+        with system, like choosing files or taking screenshots. At minimum,
+        a desktop portal implementation should be listed. GNOME and KDE already
+        adds <package>xdg-desktop-portal-gtk</package>; and
+        <package>xdg-desktop-portal-kde</package> respectively. On other desktop
+        environments you probably want to add them yourself.
+      '';
+    };
+
+    gtkUsePortal = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        Sets environment variable <literal>GTK_USE_PORTAL</literal> to <literal>1</literal>.
+        This is needed for packages ran outside Flatpak to respect and use XDG Desktop Portals.
+        For example, you'd need to set this for non-flatpak Firefox to use native filechoosers.
+        Defaults to <literal>false</literal> to respect its opt-in nature.
+      '';
+    };
+  };
+
+  config =
+    let
+      cfg = config.xdg.portal;
+      packages = [ pkgs.xdg-desktop-portal ] ++ cfg.extraPortals;
+
+    in mkIf cfg.enable {
+
+      assertions = [
+        { assertion = (cfg.gtkUsePortal -> cfg.extraPortals != []);
+          message = "Setting xdg.portal.gtkUsePortal to true requires a portal implementation in xdg.portal.extraPortals such as xdg-desktop-portal-gtk or xdg-desktop-portal-kde.";
+        }
+      ];
+
+      services.dbus.packages  = packages;
+      systemd.packages = packages;
+
+      environment.variables = {
+        GTK_USE_PORTAL = mkIf cfg.gtkUsePortal "1";
+        XDG_DESKTOP_PORTAL_PATH = map (p: "${p}/share/xdg-desktop-portal/portals") cfg.extraPortals;
+      };
+    };
+}
diff --git a/nixpkgs/nixos/modules/config/xdg/sounds.nix b/nixpkgs/nixos/modules/config/xdg/sounds.nix
new file mode 100644
index 000000000000..148240d631cf
--- /dev/null
+++ b/nixpkgs/nixos/modules/config/xdg/sounds.nix
@@ -0,0 +1,22 @@
+{ config, lib, ... }:
+
+with lib;
+{
+  options = {
+    xdg.sounds.enable = mkOption {
+      type = types.bool;
+      default = true;
+      description = ''
+        Whether to install files to support the
+        <link xlink:href="https://www.freedesktop.org/wiki/Specifications/sound-theme-spec/">XDG Sound Theme specification</link>.
+      '';
+    };
+  };
+
+  config = mkIf config.xdg.sounds.enable {
+    environment.pathsToLink = [
+      "/share/sounds"
+    ];
+  };
+
+}
diff --git a/nixpkgs/nixos/modules/config/zram.nix b/nixpkgs/nixos/modules/config/zram.nix
new file mode 100644
index 000000000000..5d411c73a560
--- /dev/null
+++ b/nixpkgs/nixos/modules/config/zram.nix
@@ -0,0 +1,189 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.zramSwap;
+
+  # don't set swapDevices as mkDefault, so we can detect user had read our warning
+  # (see below) and made an action (or not)
+  devicesCount = if cfg.swapDevices != null then cfg.swapDevices else cfg.numDevices;
+
+  devices = map (nr: "zram${toString nr}") (range 0 (devicesCount - 1));
+
+  modprobe = "${pkgs.kmod}/bin/modprobe";
+
+  warnings =
+  assert cfg.swapDevices != null -> cfg.numDevices >= cfg.swapDevices;
+  flatten [
+    (optional (cfg.numDevices > 1 && cfg.swapDevices == null) ''
+      Using several small zram devices as swap is no better than using one large.
+      Set either zramSwap.numDevices = 1 or explicitly set zramSwap.swapDevices.
+
+      Previously multiple zram devices were used to enable multithreaded
+      compression. Linux supports multithreaded compression for 1 device
+      since 3.15. See https://lkml.org/lkml/2014/2/28/404 for details.
+    '')
+  ];
+
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    zramSwap = {
+
+      enable = mkOption {
+        default = false;
+        type = types.bool;
+        description = ''
+          Enable in-memory compressed devices and swap space provided by the zram
+          kernel module.
+          See <link xlink:href="https://www.kernel.org/doc/Documentation/blockdev/zram.txt">
+            https://www.kernel.org/doc/Documentation/blockdev/zram.txt
+          </link>.
+        '';
+      };
+
+      numDevices = mkOption {
+        default = 1;
+        type = types.int;
+        description = ''
+          Number of zram devices to create. See also
+          <literal>zramSwap.swapDevices</literal>
+        '';
+      };
+
+      swapDevices = mkOption {
+        default = null;
+        example = 1;
+        type = with types; nullOr int;
+        description = ''
+          Number of zram devices to be used as swap. Must be
+          <literal>&lt;= zramSwap.numDevices</literal>.
+          Default is same as <literal>zramSwap.numDevices</literal>, recommended is 1.
+        '';
+      };
+
+      memoryPercent = mkOption {
+        default = 50;
+        type = types.int;
+        description = ''
+          Maximum amount of memory that can be used by the zram swap devices
+          (as a percentage of your total memory). Defaults to 1/2 of your total
+          RAM. Run <literal>zramctl</literal> to check how good memory is
+          compressed.
+        '';
+      };
+
+      priority = mkOption {
+        default = 5;
+        type = types.int;
+        description = ''
+          Priority of the zram swap devices. It should be a number higher than
+          the priority of your disk-based swap devices (so that the system will
+          fill the zram swap devices before falling back to disk swap).
+        '';
+      };
+
+      algorithm = mkOption {
+        default = "lzo";
+        example = "lz4";
+        type = with types; either (enum [ "lzo" "lz4" "zstd" ]) str;
+        description = ''
+          Compression algorithm. <literal>lzo</literal> has good compression,
+          but is slow. <literal>lz4</literal> has bad compression, but is fast.
+          <literal>zstd</literal> is both good compression and fast, but requires newer kernel.
+          You can check what other algorithms are supported by your zram device with
+          <programlisting>cat /sys/class/block/zram*/comp_algorithm</programlisting>
+        '';
+      };
+    };
+
+  };
+
+  config = mkIf cfg.enable {
+
+    inherit warnings;
+
+    system.requiredKernelConfig = with config.lib.kernelConfig; [
+      (isModule "ZRAM")
+    ];
+
+    # Disabling this for the moment, as it would create and mkswap devices twice,
+    # once in stage 2 boot, and again when the zram-reloader service starts.
+    # boot.kernelModules = [ "zram" ];
+
+    boot.extraModprobeConfig = ''
+      options zram num_devices=${toString cfg.numDevices}
+    '';
+
+    services.udev.extraRules = ''
+      KERNEL=="zram[0-9]*", ENV{SYSTEMD_WANTS}="zram-init-%k.service", TAG+="systemd"
+    '';
+
+    systemd.services =
+      let
+        createZramInitService = dev:
+          nameValuePair "zram-init-${dev}" {
+            description = "Init swap on zram-based device ${dev}";
+            after = [ "dev-${dev}.device" "zram-reloader.service" ];
+            requires = [ "dev-${dev}.device" "zram-reloader.service" ];
+            before = [ "dev-${dev}.swap" ];
+            requiredBy = [ "dev-${dev}.swap" ];
+            unitConfig.DefaultDependencies = false; # needed to prevent a cycle
+            serviceConfig = {
+              Type = "oneshot";
+              RemainAfterExit = true;
+              ExecStop = "${pkgs.runtimeShell} -c 'echo 1 > /sys/class/block/${dev}/reset'";
+            };
+            script = ''
+              set -euo pipefail
+
+              # Calculate memory to use for zram
+              mem=$(${pkgs.gawk}/bin/awk '/MemTotal: / {
+                  print int($2*${toString cfg.memoryPercent}/100.0/${toString devicesCount}*1024)
+              }' /proc/meminfo)
+
+              ${pkgs.utillinux}/sbin/zramctl --size $mem --algorithm ${cfg.algorithm} /dev/${dev}
+              ${pkgs.utillinux}/sbin/mkswap /dev/${dev}
+            '';
+            restartIfChanged = false;
+          };
+      in listToAttrs ((map createZramInitService devices) ++ [(nameValuePair "zram-reloader"
+        {
+          description = "Reload zram kernel module when number of devices changes";
+          wants = [ "systemd-udevd.service" ];
+          after = [ "systemd-udevd.service" ];
+          unitConfig.DefaultDependencies = false; # needed to prevent a cycle
+          serviceConfig = {
+            Type = "oneshot";
+            RemainAfterExit = true;
+            ExecStartPre = "${modprobe} -r zram";
+            ExecStart = "${modprobe} zram";
+            ExecStop = "${modprobe} -r zram";
+          };
+          restartTriggers = [
+            cfg.numDevices
+            cfg.algorithm
+            cfg.memoryPercent
+          ];
+          restartIfChanged = true;
+        })]);
+
+    swapDevices =
+      let
+        useZramSwap = dev:
+          {
+            device = "/dev/${dev}";
+            priority = cfg.priority;
+          };
+      in map useZramSwap devices;
+
+  };
+
+}