1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6
7 inherit (pkgs) lsh;
8
9 cfg = config.services.lshd;
10
11in
12
13{
14
15 ###### interface
16
17 options = {
18
19 services.lshd = {
20
21 enable = mkOption {
22 type = types.bool;
23 default = false;
24 description = ''
25 Whether to enable the GNU lshd SSH2 daemon, which allows
26 secure remote login.
27 '';
28 };
29
30 portNumber = mkOption {
31 default = 22;
32 type = types.port;
33 description = ''
34 The port on which to listen for connections.
35 '';
36 };
37
38 interfaces = mkOption {
39 default = [];
40 type = types.listOf types.str;
41 description = ''
42 List of network interfaces where listening for connections.
43 When providing the empty list, `[]`, lshd listens on all
44 network interfaces.
45 '';
46 example = [ "localhost" "1.2.3.4:443" ];
47 };
48
49 hostKey = mkOption {
50 default = "/etc/lsh/host-key";
51 type = types.str;
52 description = ''
53 Path to the server's private key. Note that this key must
54 have been created, e.g., using "lsh-keygen --server |
55 lsh-writekey --server", so that you can run lshd.
56 '';
57 };
58
59 syslog = mkOption {
60 type = types.bool;
61 default = true;
62 description = "Whether to enable syslog output.";
63 };
64
65 passwordAuthentication = mkOption {
66 type = types.bool;
67 default = true;
68 description = "Whether to enable password authentication.";
69 };
70
71 publicKeyAuthentication = mkOption {
72 type = types.bool;
73 default = true;
74 description = "Whether to enable public key authentication.";
75 };
76
77 rootLogin = mkOption {
78 type = types.bool;
79 default = false;
80 description = "Whether to enable remote root login.";
81 };
82
83 loginShell = mkOption {
84 default = null;
85 type = types.nullOr types.str;
86 description = ''
87 If non-null, override the default login shell with the
88 specified value.
89 '';
90 example = "/nix/store/xyz-bash-10.0/bin/bash10";
91 };
92
93 srpKeyExchange = mkOption {
94 default = false;
95 type = types.bool;
96 description = ''
97 Whether to enable SRP key exchange and user authentication.
98 '';
99 };
100
101 tcpForwarding = mkOption {
102 type = types.bool;
103 default = true;
104 description = "Whether to enable TCP/IP forwarding.";
105 };
106
107 x11Forwarding = mkOption {
108 type = types.bool;
109 default = true;
110 description = "Whether to enable X11 forwarding.";
111 };
112
113 subsystems = mkOption {
114 type = types.listOf types.path;
115 description = ''
116 List of subsystem-path pairs, where the head of the pair
117 denotes the subsystem name, and the tail denotes the path to
118 an executable implementing it.
119 '';
120 };
121
122 };
123
124 };
125
126
127 ###### implementation
128
129 config = mkIf cfg.enable {
130
131 services.lshd.subsystems = [ ["sftp" "${pkgs.lsh}/sbin/sftp-server"] ];
132
133 systemd.services.lshd = {
134 description = "GNU lshd SSH2 daemon";
135
136 after = [ "network.target" ];
137
138 wantedBy = [ "multi-user.target" ];
139
140 environment = {
141 LD_LIBRARY_PATH = config.system.nssModules.path;
142 };
143
144 preStart = ''
145 test -d /etc/lsh || mkdir -m 0755 -p /etc/lsh
146 test -d /var/spool/lsh || mkdir -m 0755 -p /var/spool/lsh
147
148 if ! test -f /var/spool/lsh/yarrow-seed-file
149 then
150 # XXX: It would be nice to provide feedback to the
151 # user when this fails, so that they can retry it
152 # manually.
153 ${lsh}/bin/lsh-make-seed --sloppy \
154 -o /var/spool/lsh/yarrow-seed-file
155 fi
156
157 if ! test -f "${cfg.hostKey}"
158 then
159 ${lsh}/bin/lsh-keygen --server | \
160 ${lsh}/bin/lsh-writekey --server -o "${cfg.hostKey}"
161 fi
162 '';
163
164 script = with cfg; ''
165 ${lsh}/sbin/lshd --daemonic \
166 --password-helper="${lsh}/sbin/lsh-pam-checkpw" \
167 -p ${toString portNumber} \
168 ${optionalString (interfaces != []) (concatStrings (map (i: "--interface=\"${i}\"") interfaces))} \
169 -h "${hostKey}" \
170 ${optionalString (!syslog) "--no-syslog" } \
171 ${if passwordAuthentication then "--password" else "--no-password" } \
172 ${if publicKeyAuthentication then "--publickey" else "--no-publickey" } \
173 ${if rootLogin then "--root-login" else "--no-root-login" } \
174 ${optionalString (loginShell != null) "--login-shell=\"${loginShell}\"" } \
175 ${if srpKeyExchange then "--srp-keyexchange" else "--no-srp-keyexchange" } \
176 ${if !tcpForwarding then "--no-tcpip-forward" else "--tcpip-forward"} \
177 ${if x11Forwarding then "--x11-forward" else "--no-x11-forward" } \
178 --subsystems=${concatStringsSep ","
179 (map (pair: (head pair) + "=" +
180 (head (tail pair)))
181 subsystems)}
182 '';
183 };
184
185 security.pam.services.lshd = {};
186 };
187}