diff --git a/nixos/modules/config/gnu.nix b/nixos/modules/config/gnu.nix index 5cc41ce8690f..f8c35b440d12 100644 --- a/nixos/modules/config/gnu.nix +++ b/nixos/modules/config/gnu.nix @@ -9,7 +9,8 @@ with lib; default = false; description = '' When enabled, GNU software is chosen by default whenever a there is - a choice between GNU and non-GNU software. + a choice between GNU and non-GNU software (e.g., GNU lsh + vs. OpenSSH). ''; }; }; @@ -32,6 +33,12 @@ with lib; boot.loader.grub.enable = !pkgs.stdenv.isArm; 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/nixos/modules/services/networking/ssh/lshd.nix b/nixos/modules/services/networking/ssh/lshd.nix new file mode 100644 index 000000000000..661a6a524631 --- /dev/null +++ b/nixos/modules/services/networking/ssh/lshd.nix @@ -0,0 +1,176 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + inherit (pkgs) lsh; + + cfg = config.services.lshd; + +in + +{ + + ###### interface + + options = { + + services.lshd = { + + enable = mkOption { + default = false; + description = '' + Whether to enable the GNU lshd SSH2 daemon, which allows + secure remote login. + ''; + }; + + portNumber = mkOption { + default = 22; + description = '' + The port on which to listen for connections. + ''; + }; + + interfaces = mkOption { + default = []; + description = '' + List of network interfaces where listening for connections. + When providing the empty list, `[]', lshd listens on all + network interfaces. + ''; + example = [ "localhost" "1.2.3.4:443" ]; + }; + + hostKey = mkOption { + default = "/etc/lsh/host-key"; + description = '' + Path to the server's private key. Note that this key must + have been created, e.g., using "lsh-keygen --server | + lsh-writekey --server", so that you can run lshd. + ''; + }; + + syslog = mkOption { + default = true; + description = ''Whether to enable syslog output.''; + }; + + passwordAuthentication = mkOption { + default = true; + description = ''Whether to enable password authentication.''; + }; + + publicKeyAuthentication = mkOption { + default = true; + description = ''Whether to enable public key authentication.''; + }; + + rootLogin = mkOption { + default = false; + description = ''Whether to enable remote root login.''; + }; + + loginShell = mkOption { + default = null; + description = '' + If non-null, override the default login shell with the + specified value. + ''; + example = "/nix/store/xyz-bash-10.0/bin/bash10"; + }; + + srpKeyExchange = mkOption { + default = false; + description = '' + Whether to enable SRP key exchange and user authentication. + ''; + }; + + tcpForwarding = mkOption { + default = true; + description = ''Whether to enable TCP/IP forwarding.''; + }; + + x11Forwarding = mkOption { + default = true; + description = ''Whether to enable X11 forwarding.''; + }; + + subsystems = mkOption { + description = '' + List of subsystem-path pairs, where the head of the pair + denotes the subsystem name, and the tail denotes the path to + an executable implementing it. + ''; + }; + + }; + + }; + + + ###### implementation + + config = mkIf cfg.enable { + + services.lshd.subsystems = [ ["sftp" "${pkgs.lsh}/sbin/sftp-server"] ]; + + systemd.services.lshd = { + description = "GNU lshd SSH2 daemon"; + + after = [ "network-interfaces.target" ]; + + wantedBy = [ "multi-user.target" ]; + + environment = { + LD_LIBRARY_PATH = config.system.nssModules.path; + }; + + preStart = '' + test -d /etc/lsh || mkdir -m 0755 -p /etc/lsh + test -d /var/spool/lsh || mkdir -m 0755 -p /var/spool/lsh + + if ! test -f /var/spool/lsh/yarrow-seed-file + then + # XXX: It would be nice to provide feedback to the + # user when this fails, so that they can retry it + # manually. + ${lsh}/bin/lsh-make-seed --sloppy \ + -o /var/spool/lsh/yarrow-seed-file + fi + + if ! test -f "${cfg.hostKey}" + then + ${lsh}/bin/lsh-keygen --server | \ + ${lsh}/bin/lsh-writekey --server -o "${cfg.hostKey}" + fi + ''; + + script = with cfg; '' + ${lsh}/sbin/lshd --daemonic \ + --password-helper="${lsh}/sbin/lsh-pam-checkpw" \ + -p ${toString portNumber} \ + ${if interfaces == [] then "" + else (concatStrings (map (i: "--interface=\"${i}\"") + interfaces))} \ + -h "${hostKey}" \ + ${if !syslog then "--no-syslog" else ""} \ + ${if passwordAuthentication then "--password" else "--no-password" } \ + ${if publicKeyAuthentication then "--publickey" else "--no-publickey" } \ + ${if rootLogin then "--root-login" else "--no-root-login" } \ + ${if loginShell != null then "--login-shell=\"${loginShell}\"" else "" } \ + ${if srpKeyExchange then "--srp-keyexchange" else "--no-srp-keyexchange" } \ + ${if !tcpForwarding then "--no-tcpip-forward" else "--tcpip-forward"} \ + ${if x11Forwarding then "--x11-forward" else "--no-x11-forward" } \ + --subsystems=${concatStringsSep "," + (map (pair: (head pair) + "=" + + (head (tail pair))) + subsystems)} + ''; + }; + + security.pam.services.lshd = {}; + }; +} diff --git a/pkgs/tools/networking/lsh/default.nix b/pkgs/tools/networking/lsh/default.nix new file mode 100644 index 000000000000..77d268f3a47c --- /dev/null +++ b/pkgs/tools/networking/lsh/default.nix @@ -0,0 +1,49 @@ +{ stdenv, fetchurl, gperf, guile, gmp, zlib, liboop, readline, gnum4, pam +, nettools, lsof, procps }: + +stdenv.mkDerivation rec { + name = "lsh-2.0.4"; + src = fetchurl { + url = "mirror://gnu/lsh/${name}.tar.gz"; + sha256 = "614b9d63e13ad3e162c82b6405d1f67713fc622a8bc11337e72949d613713091"; + }; + + patches = [ ./pam-service-name.patch ./lshd-no-root-login.patch ]; + + preConfigure = '' + # Patch `lsh-make-seed' so that it can gather enough entropy. + sed -i "src/lsh-make-seed.c" \ + -e "s|/usr/sbin/arp|${nettools}/sbin/arp|g ; + s|/usr/bin/netstat|${nettools}/bin/netstat|g ; + s|/usr/local/bin/lsof|${lsof}/bin/lsof|g ; + s|/bin/vmstat|${procps}/bin/vmstat|g ; + s|/bin/ps|${procps}/bin/sp|g ; + s|/usr/bin/w|${procps}/bin/w|g ; + s|/usr/bin/df|$(type -P df)|g ; + s|/usr/bin/ipcs|$(type -P ipcs)|g ; + s|/usr/bin/uptime|$(type -P uptime)|g" + + # Skip the `configure' script that checks whether /dev/ptmx & co. work as + # expected, because it relies on impurities (for instance, /dev/pts may + # be unavailable in chroots.) + export lsh_cv_sys_unix98_ptys=yes + ''; + + buildInputs = [ gperf guile gmp zlib liboop readline gnum4 pam ]; + + meta = { + description = "GPL'd implementation of the SSH protocol"; + + longDescription = '' + lsh is a free implementation (in the GNU sense) of the ssh + version 2 protocol, currently being standardised by the IETF + SECSH working group. + ''; + + homepage = http://www.lysator.liu.se/~nisse/lsh/; + license = stdenv.lib.licenses.gpl2Plus; + + maintainers = [ ]; + platforms = [ "x86_64-linux" ]; + }; +} diff --git a/pkgs/tools/networking/lsh/lshd-no-root-login.patch b/pkgs/tools/networking/lsh/lshd-no-root-login.patch new file mode 100644 index 000000000000..9dd81de3fbc1 --- /dev/null +++ b/pkgs/tools/networking/lsh/lshd-no-root-login.patch @@ -0,0 +1,16 @@ +Correctly handle the `--no-root-login' option. + +--- lsh-2.0.4/src/lshd.c 2006-05-01 13:47:44.000000000 +0200 ++++ lsh-2.0.4/src/lshd.c 2009-09-08 12:20:36.000000000 +0200 +@@ -758,6 +758,10 @@ main_argp_parser(int key, char *arg, str + self->allow_root = 1; + break; + ++ case OPT_NO_ROOT_LOGIN: ++ self->allow_root = 0; ++ break; ++ + case OPT_KERBEROS_PASSWD: + self->pw_helper = PATH_KERBEROS_HELPER; + break; + diff --git a/pkgs/tools/networking/lsh/pam-service-name.patch b/pkgs/tools/networking/lsh/pam-service-name.patch new file mode 100644 index 000000000000..6a6156855c51 --- /dev/null +++ b/pkgs/tools/networking/lsh/pam-service-name.patch @@ -0,0 +1,14 @@ +Tell `lsh-pam-checkpw', the PAM password helper program, to use a more +descriptive service name. + +--- lsh-2.0.4/src/lsh-pam-checkpw.c 2003-02-16 22:30:10.000000000 +0100 ++++ lsh-2.0.4/src/lsh-pam-checkpw.c 2008-11-28 16:16:58.000000000 +0100 +@@ -38,7 +38,7 @@ + #include + + #define PWD_MAXLEN 1024 +-#define SERVICE_NAME "other" ++#define SERVICE_NAME "lshd" + #define TIMEOUT 600 + + static int diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index a4dbe1aca1b5..81df0d777a6e 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -2452,6 +2452,10 @@ in lsb-release = callPackage ../os-specific/linux/lsb-release { }; + # lsh installs `bin/nettle-lfib-stream' and so does Nettle. Give the + # former a lower priority than Nettle. + lsh = lowPrio (callPackage ../tools/networking/lsh { }); + lshw = callPackage ../tools/system/lshw { }; lxc = callPackage ../os-specific/linux/lxc { };