about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--nixos/modules/module-list.nix1
-rw-r--r--nixos/modules/system/boot/initrd-network.nix149
-rw-r--r--nixos/modules/system/boot/luksroot.nix26
-rw-r--r--nixos/modules/system/boot/stage-1-init.sh4
-rw-r--r--nixos/modules/system/boot/stage-1.nix12
-rw-r--r--pkgs/build-support/nuke-references/builder.sh25
-rw-r--r--pkgs/build-support/nuke-references/default.nix5
-rw-r--r--pkgs/os-specific/linux/mkinitcpio-nfs-utils/default.nix26
-rw-r--r--pkgs/tools/networking/dropbear/default.nix6
-rw-r--r--pkgs/tools/networking/dropbear/pass-path.patch23
-rw-r--r--pkgs/top-level/all-packages.nix2
11 files changed, 252 insertions, 27 deletions
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index ce9353d58b35..0db7ee916baa 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -441,6 +441,7 @@
   ./system/activation/top-level.nix
   ./system/boot/coredump.nix
   ./system/boot/emergency-mode.nix
+  ./system/boot/initrd-network.nix
   ./system/boot/kernel.nix
   ./system/boot/kexec.nix
   ./system/boot/loader/efi.nix
diff --git a/nixos/modules/system/boot/initrd-network.nix b/nixos/modules/system/boot/initrd-network.nix
new file mode 100644
index 000000000000..6c6e2fafad43
--- /dev/null
+++ b/nixos/modules/system/boot/initrd-network.nix
@@ -0,0 +1,149 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.boot.initrd.network;
+
+in
+{
+
+  options = {
+
+    boot.initrd.network.enable = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        Add network connectivity support to initrd.
+
+        Network options are configured via <literal>ip</literal> kernel
+        option, according to the kernel documentation.
+      '';
+    };
+
+    boot.initrd.network.ssh.enable = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        Start SSH service during initrd boot. It can be used to debug failing
+        boot on a remote server, enter pasphrase for an encrypted partition etc.
+        Service is killed when stage-1 boot is finished.
+      '';
+    };
+
+    boot.initrd.network.ssh.port = mkOption {
+      type = types.int;
+      default = 22;
+      description = ''
+        Port on which SSH initrd service should listen.
+      '';
+    };
+
+    boot.initrd.network.ssh.shell = mkOption {
+      type = types.str;
+      default = "/bin/ash";
+      description = ''
+        Login shell of the remote user. Can be used to limit actions user can do.
+      '';
+    };
+
+    boot.initrd.network.ssh.hostRSAKey = mkOption {
+      type = types.nullOr types.path;
+      default = null;
+      description = ''
+        RSA SSH private key file in the Dropbear format.
+
+        WARNING: This key is contained insecurely in the global Nix store. Do NOT
+        use your regular SSH host private keys for this purpose or you'll expose
+        them to regular users!
+      '';
+    };
+
+    boot.initrd.network.ssh.hostDSSKey = mkOption {
+      type = types.nullOr types.path;
+      default = null;
+      description = ''
+        DSS SSH private key file in the Dropbear format.
+
+        WARNING: This key is contained insecurely in the global Nix store. Do NOT
+        use your regular SSH host private keys for this purpose or you'll expose
+        them to regular users!
+      '';
+    };
+
+    boot.initrd.network.ssh.hostECDSAKey = mkOption {
+      type = types.nullOr types.path;
+      default = null;
+      description = ''
+        ECDSA SSH private key file in the Dropbear format.
+
+        WARNING: This key is contained insecurely in the global Nix store. Do NOT
+        use your regular SSH host private keys for this purpose or you'll expose
+        them to regular users!
+      '';
+    };
+
+    boot.initrd.network.ssh.authorizedKeys = mkOption {
+      type = types.listOf types.str;
+      default = config.users.extraUsers.root.openssh.authorizedKeys.keys;
+      description = ''
+        Authorized keys for the root user on initrd.
+      '';
+    };
+
+  };
+
+  config = mkIf cfg.enable {
+
+    boot.initrd.kernelModules = [ "af_packet" ];
+
+    boot.initrd.extraUtilsCommands = ''
+      copy_bin_and_libs ${pkgs.mkinitcpio-nfs-utils}/bin/ipconfig
+    '' + optionalString cfg.ssh.enable ''
+      copy_bin_and_libs ${pkgs.dropbear}/bin/dropbear
+
+      cp -pv ${pkgs.glibc}/lib/libnss_files.so.* $out/lib
+    '';
+
+    boot.initrd.extraUtilsCommandsTest = optionalString cfg.ssh.enable ''
+      $out/bin/dropbear -V
+    '';
+
+    boot.initrd.postEarlyDeviceCommands = ''
+      # Search for interface definitions in command line
+      for o in $(cat /proc/cmdline); do
+        case $o in
+          ip=*)
+            ipconfig $o && hasNetwork=1
+            ;;
+        esac
+      done
+    '' + optionalString cfg.ssh.enable ''
+      if [ -n "$hasNetwork" ]; then
+        mkdir /dev/pts
+        mount -t devpts devpts /dev/pts
+
+        mkdir -p /etc
+        echo 'root:x:0:0:root:/root:${cfg.ssh.shell}' > /etc/passwd
+        echo '${cfg.ssh.shell}' > /etc/shells
+        echo 'passwd: files' > /etc/nsswitch.conf
+
+        mkdir -p /var/log
+        touch /var/log/lastlog
+
+        mkdir -p /etc/dropbear
+        ${optionalString (cfg.ssh.hostRSAKey != null) "ln -s ${cfg.ssh.hostRSAKey} /etc/dropbear/dropbear_rsa_host_key"}
+        ${optionalString (cfg.ssh.hostDSSKey != null) "ln -s ${cfg.ssh.hostDSSKey} /etc/dropbear/dropbear_dss_host_key"}
+        ${optionalString (cfg.ssh.hostECDSAKey != null) "ln -s ${cfg.ssh.hostECDSAKey} /etc/dropbear/dropbear_ecdsa_host_key"}
+
+        mkdir -p /root/.ssh
+        ${concatStrings (map (key: ''
+          echo -n ${escapeShellArg key} >> /root/.ssh/authorized_keys
+        '') cfg.ssh.authorizedKeys)}
+
+        dropbear -s -j -k -E -m -p ${toString cfg.ssh.port}
+      fi
+    '';
+
+  };
+}
diff --git a/nixos/modules/system/boot/luksroot.nix b/nixos/modules/system/boot/luksroot.nix
index 4a14ff1879c9..763703205630 100644
--- a/nixos/modules/system/boot/luksroot.nix
+++ b/nixos/modules/system/boot/luksroot.nix
@@ -32,9 +32,12 @@ let
     ''}
 
     open_normally() {
-        cryptsetup luksOpen ${device} ${name} ${optionalString allowDiscards "--allow-discards"} \
+        echo luksOpen ${device} ${name} ${optionalString allowDiscards "--allow-discards"} \
           ${optionalString (header != null) "--header=${header}"} \
-          ${optionalString (keyFile != null) "--key-file=${keyFile} ${optionalString (keyFileSize != null) "--keyfile-size=${toString keyFileSize}"}"}
+          ${optionalString (keyFile != null) "--key-file=${keyFile} ${optionalString (keyFileSize != null) "--keyfile-size=${toString keyFileSize}"}"} \
+          > /.luksopen_args
+        cryptsetup-askpass
+        rm /.luksopen_args
     }
 
     ${optionalString (luks.yubikeySupport && (yubikey != null)) ''
@@ -418,6 +421,18 @@ in
     boot.initrd.extraUtilsCommands = ''
       copy_bin_and_libs ${pkgs.cryptsetup}/bin/cryptsetup
 
+      cat > $out/bin/cryptsetup-askpass <<EOF
+      #!$out/bin/sh -e
+      if [ -e /.luksopen_args ]; then
+        cryptsetup \$(cat /.luksopen_args)
+        killall cryptsetup
+      else
+        echo "Passphrase is not requested now"
+        exit 1
+      fi
+      EOF
+      chmod +x $out/bin/cryptsetup-askpass
+
       ${optionalString luks.yubikeySupport ''
         copy_bin_and_libs ${pkgs.ykpers}/bin/ykchalresp
         copy_bin_and_libs ${pkgs.ykpers}/bin/ykinfo
@@ -432,6 +447,8 @@ in
 
         cat > $out/bin/openssl-wrap <<EOF
         #!$out/bin/sh
+        export OPENSSL_CONF=$out/etc/ssl/openssl.cnf
+        $out/bin/openssl "\$@"
         EOF
         chmod +x $out/bin/openssl-wrap
       ''}
@@ -442,11 +459,6 @@ in
       ${optionalString luks.yubikeySupport ''
         $out/bin/ykchalresp -V
         $out/bin/ykinfo -V
-        cat > $out/bin/openssl-wrap <<EOF
-        #!$out/bin/sh
-        export OPENSSL_CONF=$out/etc/ssl/openssl.cnf
-        $out/bin/openssl "\$@"
-        EOF
         $out/bin/openssl-wrap version
       ''}
     '';
diff --git a/nixos/modules/system/boot/stage-1-init.sh b/nixos/modules/system/boot/stage-1-init.sh
index 51828c5c090b..2b5d547353f8 100644
--- a/nixos/modules/system/boot/stage-1-init.sh
+++ b/nixos/modules/system/boot/stage-1-init.sh
@@ -149,6 +149,10 @@ udevadm trigger --action=add
 udevadm settle
 
 
+# Additional devices initialization.
+@postEarlyDeviceCommands@
+
+
 # Load boot-time keymap before any LVM/LUKS initialization
 @extraUtils@/bin/busybox loadkmap < "@busyboxKeymap@"
 
diff --git a/nixos/modules/system/boot/stage-1.nix b/nixos/modules/system/boot/stage-1.nix
index fe34e8227289..58a0749c74e2 100644
--- a/nixos/modules/system/boot/stage-1.nix
+++ b/nixos/modules/system/boot/stage-1.nix
@@ -104,7 +104,7 @@ let
       stripDirs "lib bin" "-s"
 
       # Run patchelf to make the programs refer to the copied libraries.
-      for i in $out/bin/* $out/lib/*; do if ! test -L $i; then nuke-refs $i; fi; done
+      for i in $out/bin/* $out/lib/*; do if ! test -L $i; then nuke-refs -e $out $i; fi; done
 
       for i in $out/bin/*; do
           if ! test -L $i; then
@@ -203,7 +203,7 @@ let
     inherit (config.boot) resumeDevice devSize runSize;
 
     inherit (config.boot.initrd) checkJournalingFS
-      preLVMCommands postDeviceCommands postMountCommands kernelModules;
+      postEarlyDeviceCommands preLVMCommands postDeviceCommands postMountCommands kernelModules;
 
     resumeDevices = map (sd: if sd ? device then sd.device else "/dev/disk/by-label/${sd.label}")
                     (filter (sd: (sd ? label || hasPrefix "/dev/" sd.device) && !sd.randomEncryption) config.swapDevices);
@@ -313,6 +313,14 @@ in
       '';
     };
 
+    boot.initrd.postEarlyDeviceCommands = mkOption {
+      default = "";
+      type = types.lines;
+      description = ''
+        Shell commands to be executed early after creation of device nodes.
+      '';
+    };
+
     boot.initrd.postMountCommands = mkOption {
       default = "";
       type = types.lines;
diff --git a/pkgs/build-support/nuke-references/builder.sh b/pkgs/build-support/nuke-references/builder.sh
index 9e8c464d8288..02eac664d437 100644
--- a/pkgs/build-support/nuke-references/builder.sh
+++ b/pkgs/build-support/nuke-references/builder.sh
@@ -3,11 +3,26 @@ source $stdenv/setup
 mkdir -p $out/bin
 cat > $out/bin/nuke-refs <<EOF
 #! $SHELL -e
-for i in \$*; do
-    if test ! -L \$i -a -f \$i; then
-        cat \$i | sed "s|$NIX_STORE/[a-z0-9]*-|$NIX_STORE/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-|g" > \$i.tmp
-        if test -x \$i; then chmod +x \$i.tmp; fi
-        mv \$i.tmp \$i
+
+excludes=""
+while getopts e: o; do
+    case "\$o" in
+        e) storeId=\$(echo "\$OPTARG" | sed -n "s|^$NIX_STORE/\\([a-z0-9]\{32\}\\)-.*|\1|p")
+           if [ -z "\$storeId" ]; then
+               echo "-e argument must be a Nix store path"
+               exit 1
+           fi
+           excludes="\$excludes(?!\$storeId)"
+        ;;
+    esac
+done
+shift \$((\$OPTIND-1))
+
+for i in "\$@"; do
+    if test ! -L "\$i" -a -f "\$i"; then
+        cat "\$i" | $perl/bin/perl -pe "s|$NIX_STORE/\$excludes[a-z0-9]{32}-|$NIX_STORE/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-|g" > "\$i.tmp"
+        if test -x "\$i"; then chmod +x "\$i.tmp"; fi
+        mv "\$i.tmp" "\$i"
     fi
 done
 EOF
diff --git a/pkgs/build-support/nuke-references/default.nix b/pkgs/build-support/nuke-references/default.nix
index d672184553f6..8f976ad462cc 100644
--- a/pkgs/build-support/nuke-references/default.nix
+++ b/pkgs/build-support/nuke-references/default.nix
@@ -3,9 +3,10 @@
 # path (/nix/store/eeee...).  This is useful for getting rid of
 # dependencies that you know are not actually needed at runtime.
 
-{stdenv}:
+{ stdenv, perl }:
 
 stdenv.mkDerivation {
   name = "nuke-references";
   builder = ./builder.sh;
-}
\ No newline at end of file
+  inherit perl;
+}
diff --git a/pkgs/os-specific/linux/mkinitcpio-nfs-utils/default.nix b/pkgs/os-specific/linux/mkinitcpio-nfs-utils/default.nix
new file mode 100644
index 000000000000..f4e7ad1f2344
--- /dev/null
+++ b/pkgs/os-specific/linux/mkinitcpio-nfs-utils/default.nix
@@ -0,0 +1,26 @@
+{ stdenv, fetchurl, xz }:
+
+stdenv.mkDerivation rec {
+  name = "mkinitcpio-nfs-utils-0.3";
+
+  src = fetchurl {
+    url = "https://sources.archlinux.org/other/mkinitcpio/${name}.tar.xz";
+    sha256 = "0fc93sfk41ycpa33083kyd7i4y00ykpbhj5qlw611bjghj4x946j";
+    # ugh, upstream...
+    name = "${name}.tar.gz";
+  };
+
+  makeFlags = [ "DESTDIR=$(out)" "bindir=/bin" ];
+
+  postInstall = ''
+    rm -rf $out/usr
+  '';
+
+  meta = with stdenv.lib; {
+    homepage = https://archlinux.org/;
+    description = "ipconfig and nfsmount tools for root on NFS, ported from klibc";
+    license = licenses.gpl2;
+    platforms  = platforms.linux;
+    maintainers = with maintainers; [ abbradar ];
+  };
+}
diff --git a/pkgs/tools/networking/dropbear/default.nix b/pkgs/tools/networking/dropbear/default.nix
index 79a23ae38327..98ea4c82304b 100644
--- a/pkgs/tools/networking/dropbear/default.nix
+++ b/pkgs/tools/networking/dropbear/default.nix
@@ -35,9 +35,11 @@ stdenv.mkDerivation rec {
 
   buildInputs = [ zlib ];
 
-  meta = {
+  meta = with stdenv.lib; {
     homepage = http://matt.ucc.asn.au/dropbear/dropbear.html;
     description = "An small footprint implementation of the SSH 2 protocol";
-    license = stdenv.lib.licenses.mit;
+    license = licenses.mit;
+    maintainers = with maintainers; [ abbradar ];
+    platforms = platforms.unix;
   };
 }
diff --git a/pkgs/tools/networking/dropbear/pass-path.patch b/pkgs/tools/networking/dropbear/pass-path.patch
index 1e223e0ad64d..2ce08b05799d 100644
--- a/pkgs/tools/networking/dropbear/pass-path.patch
+++ b/pkgs/tools/networking/dropbear/pass-path.patch
@@ -1,31 +1,36 @@
 diff --git a/svr-chansession.c b/svr-chansession.c
-index 23dad8c..32cac13 100644
+index e44299e..7ef750a 100644
 --- a/svr-chansession.c
 +++ b/svr-chansession.c
-@@ -823,6 +823,7 @@ static void addchildpid(struct ChanSess *chansess, pid_t pid) {
+@@ -893,6 +893,8 @@ static void addchildpid(struct ChanSess *chansess, pid_t pid) {
  static void execchild(void *user_data) {
  	struct ChanSess *chansess = user_data;
  	char *usershell = NULL;
 +	const char *path = DEFAULT_PATH;
++	const char *ldpath = NULL;
  
-     /* with uClinux we'll have vfork()ed, so don't want to overwrite the
-      * hostkey. can't think of a workaround to clear it */
-@@ -835,6 +836,9 @@ static void execchild(void *user_data) {
- 	reseedrandom();
+ 	/* with uClinux we'll have vfork()ed, so don't want to overwrite the
+ 	 * hostkey. can't think of a workaround to clear it */
+@@ -905,6 +907,10 @@ static void execchild(void *user_data) {
+ 	seedrandom();
  #endif
  
-+    if (getenv("PATH"))
-+        path = getenv("PATH");
++	if (getenv("PATH"))
++		path = getenv("PATH");
++	ldpath = getenv("LD_LIBRARY_PATH");
 +
  	/* clear environment */
  	/* if we're debugging using valgrind etc, we need to keep the LD_PRELOAD
  	 * etc. This is hazardous, so should only be used for debugging. */
-@@ -878,7 +882,7 @@ static void execchild(void *user_data) {
+@@ -948,7 +954,10 @@ static void execchild(void *user_data) {
  	addnewvar("LOGNAME", ses.authstate.pw_name);
  	addnewvar("HOME", ses.authstate.pw_dir);
  	addnewvar("SHELL", get_user_shell());
 -	addnewvar("PATH", DEFAULT_PATH);
 +	addnewvar("PATH", path);
++	if (ldpath != NULL) {
++		addnewvar("LD_LIBRARY_PATH", ldpath);
++	}
  	if (chansess->term != NULL) {
  		addnewvar("TERM", chansess->term);
  	}
diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix
index b0d5f22124f4..da80a4ee8cb4 100644
--- a/pkgs/top-level/all-packages.nix
+++ b/pkgs/top-level/all-packages.nix
@@ -10169,6 +10169,8 @@ let
     systemd = systemd.override { enableKDbus = true; };
   };
 
+  mkinitcpio-nfs-utils = callPackage ../os-specific/linux/mkinitcpio-nfs-utils { };
+
   module_init_tools = callPackage ../os-specific/linux/module-init-tools { };
 
   aggregateModules = modules: