Merge branch 'core-updates'
[jackhill/guix/guix.git] / gnu / services / ssh.scm
1 ;;; GNU Guix --- Functional package management for GNU
2 ;;; Copyright © 2014, 2015 Ludovic Courtès <ludo@gnu.org>
3 ;;;
4 ;;; This file is part of GNU Guix.
5 ;;;
6 ;;; GNU Guix is free software; you can redistribute it and/or modify it
7 ;;; under the terms of the GNU General Public License as published by
8 ;;; the Free Software Foundation; either version 3 of the License, or (at
9 ;;; your option) any later version.
10 ;;;
11 ;;; GNU Guix is distributed in the hope that it will be useful, but
12 ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
13 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ;;; GNU General Public License for more details.
15 ;;;
16 ;;; You should have received a copy of the GNU General Public License
17 ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
18
19 (define-module (gnu services ssh)
20 #:use-module (guix gexp)
21 #:use-module (guix records)
22 #:use-module (gnu services)
23 #:use-module (gnu services dmd)
24 #:use-module (gnu system linux) ; 'pam-service'
25 #:use-module (gnu packages lsh)
26 #:export (lsh-service))
27
28 ;;; Commentary:
29 ;;;
30 ;;; This module implements secure shell (SSH) services.
31 ;;;
32 ;;; Code:
33
34 ;; TODO: Export.
35 (define-record-type* <lsh-configuration>
36 lsh-configuration make-lsh-configuration
37 lsh-configuration?
38 (lsh lsh-configuration-lsh
39 (default lsh))
40 (daemonic? lsh-configuration-daemonic?)
41 (host-key lsh-configuration-host-key)
42 (interfaces lsh-configuration-interfaces)
43 (port-number lsh-configuration-port-number)
44 (allow-empty-passwords? lsh-configuration-allow-empty-passwords?)
45 (root-login? lsh-configuration-root-login?)
46 (syslog-output? lsh-configuration-syslog-output?)
47 (pid-file? lsh-configuration-pid-file?)
48 (pid-file lsh-configuration-pid-file)
49 (x11-forwarding? lsh-configuration-x11-forwarding?)
50 (tcp/ip-forwarding? lsh-configuration-tcp/ip-forwarding?)
51 (password-authentication? lsh-configuration-password-authentication?)
52 (public-key-authentication? lsh-configuration-public-key-authentication?)
53 (initialize? lsh-configuration-initialize?))
54
55 (define %yarrow-seed
56 "/var/spool/lsh/yarrow-seed-file")
57
58 (define (lsh-initialization lsh host-key)
59 "Return the gexp to initialize the LSH service for HOST-KEY."
60 #~(begin
61 (unless (file-exists? #$%yarrow-seed)
62 (system* (string-append #$lsh "/bin/lsh-make-seed")
63 "--sloppy" "-o" #$%yarrow-seed))
64
65 (unless (file-exists? #$host-key)
66 (mkdir-p (dirname #$host-key))
67 (format #t "creating SSH host key '~a'...~%" #$host-key)
68
69 ;; FIXME: We're just doing a simple pipeline, but 'system' cannot be
70 ;; used yet because /bin/sh might be dangling; factorize this somehow.
71 (let* ((in+out (pipe))
72 (keygen (primitive-fork)))
73 (case keygen
74 ((0)
75 (close-port (car in+out))
76 (close-fdes 1)
77 (dup2 (fileno (cdr in+out)) 1)
78 (execl (string-append #$lsh "/bin/lsh-keygen")
79 "lsh-keygen" "--server"))
80 (else
81 (let ((write-key (primitive-fork)))
82 (case write-key
83 ((0)
84 (close-port (cdr in+out))
85 (close-fdes 0)
86 (dup2 (fileno (car in+out)) 0)
87 (execl (string-append #$lsh "/bin/lsh-writekey")
88 "lsh-writekey" "--server" "-o" #$host-key))
89 (else
90 (close-port (car in+out))
91 (close-port (cdr in+out))
92 (waitpid keygen)
93 (waitpid write-key))))))))))
94
95 (define (lsh-activation config)
96 "Return the activation gexp for CONFIG."
97 #~(begin
98 (use-modules (guix build utils))
99 (mkdir-p "/var/spool/lsh")
100 #$(if (lsh-configuration-initialize? config)
101 (lsh-initialization (lsh-configuration-lsh config)
102 (lsh-configuration-host-key config))
103 #t)))
104
105 (define (lsh-dmd-service config)
106 "Return a <dmd-service> for lsh with CONFIG."
107 (define lsh (lsh-configuration-lsh config))
108 (define pid-file (lsh-configuration-pid-file config))
109 (define pid-file? (lsh-configuration-pid-file? config))
110 (define daemonic? (lsh-configuration-daemonic? config))
111 (define interfaces (lsh-configuration-interfaces config))
112
113 (define lsh-command
114 (append
115 (cons #~(string-append #$lsh "/sbin/lshd")
116 (if daemonic?
117 (let ((syslog (if (lsh-configuration-syslog-output? config)
118 '()
119 (list "--no-syslog"))))
120 (cons "--daemonic"
121 (if pid-file?
122 (cons #~(string-append "--pid-file=" #$pid-file)
123 syslog)
124 (cons "--no-pid-file" syslog))))
125 (if pid-file?
126 (list #~(string-append "--pid-file=" #$pid-file))
127 '())))
128 (cons* #~(string-append "--host-key="
129 #$(lsh-configuration-host-key config))
130 #~(string-append "--password-helper=" #$lsh "/sbin/lsh-pam-checkpw")
131 #~(string-append "--subsystems=sftp=" #$lsh "/sbin/sftp-server")
132 "-p" (number->string (lsh-configuration-port-number config))
133 (if (lsh-configuration-password-authentication? config)
134 "--password" "--no-password")
135 (if (lsh-configuration-public-key-authentication? config)
136 "--publickey" "--no-publickey")
137 (if (lsh-configuration-root-login? config)
138 "--root-login" "--no-root-login")
139 (if (lsh-configuration-x11-forwarding? config)
140 "--x11-forward" "--no-x11-forward")
141 (if (lsh-configuration-tcp/ip-forwarding? config)
142 "--tcpip-forward" "--no-tcpip-forward")
143 (if (null? interfaces)
144 '()
145 (list (string-append "--interfaces="
146 (string-join interfaces ",")))))))
147
148 (define requires
149 (if (and daemonic? (lsh-configuration-syslog-output? config))
150 '(networking syslogd)
151 '(networking)))
152
153 (list (dmd-service
154 (documentation "GNU lsh SSH server")
155 (provision '(ssh-daemon))
156 (requirement requires)
157 (start #~(make-forkexec-constructor (list #$@lsh-command)))
158 (stop #~(make-kill-destructor)))))
159
160 (define (lsh-pam-services config)
161 "Return a list of <pam-services> for lshd with CONFIG."
162 (list (unix-pam-service
163 "lshd"
164 #:allow-empty-passwords?
165 (lsh-configuration-allow-empty-passwords? config))))
166
167 (define lsh-service-type
168 (service-type (name 'lsh)
169 (extensions
170 (list (service-extension dmd-root-service-type
171 lsh-dmd-service)
172 (service-extension pam-root-service-type
173 lsh-pam-services)
174 (service-extension activation-service-type
175 lsh-activation)))))
176
177 (define* (lsh-service #:key
178 (lsh lsh)
179 (daemonic? #t)
180 (host-key "/etc/lsh/host-key")
181 (interfaces '())
182 (port-number 22)
183 (allow-empty-passwords? #f)
184 (root-login? #f)
185 (syslog-output? #t)
186 (pid-file? #f)
187 (pid-file "/var/run/lshd.pid")
188 (x11-forwarding? #t)
189 (tcp/ip-forwarding? #t)
190 (password-authentication? #t)
191 (public-key-authentication? #t)
192 (initialize? #t))
193 "Run the @command{lshd} program from @var{lsh} to listen on port @var{port-number}.
194 @var{host-key} must designate a file containing the host key, and readable
195 only by root.
196
197 When @var{daemonic?} is true, @command{lshd} will detach from the
198 controlling terminal and log its output to syslogd, unless one sets
199 @var{syslog-output?} to false. Obviously, it also makes lsh-service
200 depend on existence of syslogd service. When @var{pid-file?} is true,
201 @command{lshd} writes its PID to the file called @var{pid-file}.
202
203 When @var{initialize?} is true, automatically create the seed and host key
204 upon service activation if they do not exist yet. This may take long and
205 require interaction.
206
207 When @var{initialize?} is false, it is up to the user to initialize the
208 randomness generator (@pxref{lsh-make-seed,,, lsh, LSH Manual}), and to create
209 a key pair with the private key stored in file @var{host-key} (@pxref{lshd
210 basics,,, lsh, LSH Manual}).
211
212 When @var{interfaces} is empty, lshd listens for connections on all the
213 network interfaces; otherwise, @var{interfaces} must be a list of host names
214 or addresses.
215
216 @var{allow-empty-passwords?} specifies whether to accept log-ins with empty
217 passwords, and @var{root-login?} specifies whether to accept log-ins as
218 root.
219
220 The other options should be self-descriptive."
221 (service lsh-service-type
222 (lsh-configuration (lsh lsh) (daemonic? daemonic?)
223 (host-key host-key) (interfaces interfaces)
224 (port-number port-number)
225 (allow-empty-passwords? allow-empty-passwords?)
226 (root-login? root-login?)
227 (syslog-output? syslog-output?)
228 (pid-file? pid-file?) (pid-file pid-file)
229 (x11-forwarding? x11-forwarding?)
230 (tcp/ip-forwarding? tcp/ip-forwarding?)
231 (password-authentication?
232 password-authentication?)
233 (public-key-authentication?
234 public-key-authentication?)
235 (initialize? initialize?))))
236
237 ;;; ssh.scm ends here