gnu: guile-xapian: Update to 0.1.0.
[jackhill/guix/guix.git] / gnu / tests / ssh.scm
CommitLineData
d5b0c902 1;;; GNU Guix --- Functional package management for GNU
e6b1a224 2;;; Copyright © 2016, 2017, 2018, 2019 Ludovic Courtès <ludo@gnu.org>
c24b1547 3;;; Copyright © 2017, 2018 Clément Lassieur <clement@lassieur.org>
5d7141cd 4;;; Copyright © 2017 Marius Bakke <mbakke@fastmail.com>
d5b0c902
LC
5;;;
6;;; This file is part of GNU Guix.
7;;;
8;;; GNU Guix is free software; you can redistribute it and/or modify it
9;;; under the terms of the GNU General Public License as published by
10;;; the Free Software Foundation; either version 3 of the License, or (at
11;;; your option) any later version.
12;;;
13;;; GNU Guix is distributed in the hope that it will be useful, but
14;;; WITHOUT ANY WARRANTY; without even the implied warranty of
15;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16;;; GNU General Public License for more details.
17;;;
18;;; You should have received a copy of the GNU General Public License
19;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
20
21(define-module (gnu tests ssh)
22 #:use-module (gnu tests)
23 #:use-module (gnu system)
d5b0c902
LC
24 #:use-module (gnu system vm)
25 #:use-module (gnu services)
d5b0c902
LC
26 #:use-module (gnu services ssh)
27 #:use-module (gnu services networking)
28 #:use-module (gnu packages ssh)
29 #:use-module (guix gexp)
30 #:use-module (guix store)
2b436389
LC
31 #:export (%test-openssh
32 %test-dropbear))
d5b0c902 33
e6b1a224
LC
34(define* (run-ssh-test name ssh-service pid-file
35 #:key (sftp? #f) (test-getlogin? #t))
0e598850
LC
36 "Run a test of an OS running SSH-SERVICE, which writes its PID to PID-FILE.
37SSH-SERVICE must be configured to listen on port 22 and to allow for root and
36f666c6
CL
38empty-password logins.
39
40When SFTP? is true, run an SFTP server test."
8b113790
LC
41 (define os
42 (marionette-operating-system
39d7fdce 43 (simple-operating-system (service dhcp-client-service-type) ssh-service)
8b113790
LC
44 #:imported-modules '((gnu services herd)
45 (guix combinators))))
46 (define vm
47 (virtual-machine
48 (operating-system os)
49 (port-forwardings '((2222 . 22)))))
50
51 (define test
52 (with-imported-modules '((gnu build marionette))
ff913cf5
LC
53 (with-extensions (list guile-ssh)
54 #~(begin
55 (use-modules (gnu build marionette)
56 (srfi srfi-26)
57 (srfi srfi-64)
e6b1a224 58 (ice-9 textual-ports)
ff913cf5
LC
59 (ice-9 match)
60 (ssh session)
61 (ssh auth)
62 (ssh channel)
e6b1a224 63 (ssh popen)
ff913cf5
LC
64 (ssh sftp))
65
66 (define marionette
67 ;; Enable TCP forwarding of the guest's port 22.
68 (make-marionette (list #$vm)))
69
70 (define (make-session-for-test)
71 "Make a session with predefined parameters for a test."
72 (make-session #:user "root"
73 #:port 2222
74 #:host "localhost"
75 #:log-verbosity 'protocol))
76
77 (define (call-with-connected-session proc)
78 "Call the one-argument procedure PROC with a freshly created and
cfaf4d11
CL
79connected SSH session object, return the result of the procedure call. The
80session is disconnected when the PROC is finished."
ff913cf5
LC
81 (let ((session (make-session-for-test)))
82 (dynamic-wind
83 (lambda ()
84 (let ((result (connect! session)))
85 (unless (equal? result 'ok)
86 (error "Could not connect to a server"
87 session result))))
88 (lambda () (proc session))
89 (lambda () (disconnect! session)))))
90
91 (define (call-with-connected-session/auth proc)
92 "Make an authenticated session. We should be able to connect as
cfaf4d11 93root with an empty password."
ff913cf5
LC
94 (call-with-connected-session
95 (lambda (session)
96 ;; Try the simple authentication methods. Dropbear requires
97 ;; 'none' when there are no passwords, whereas OpenSSH accepts
98 ;; 'password' with an empty password.
99 (let loop ((methods (list (cut userauth-password! <> "")
100 (cut userauth-none! <>))))
101 (match methods
102 (()
103 (error "all the authentication methods failed"))
104 ((auth rest ...)
105 (match (pk 'auth (auth session))
106 ('success
107 (proc session))
108 ('denied
109 (loop rest)))))))))
110
111 (mkdir #$output)
112 (chdir #$output)
113
114 (test-begin "ssh-daemon")
115
116 ;; Wait for sshd to be up and running.
c24b1547 117 (test-assert "service running"
ff913cf5
LC
118 (marionette-eval
119 '(begin
120 (use-modules (gnu services herd))
c24b1547 121 (start-service 'ssh-daemon))
ff913cf5
LC
122 marionette))
123
124 ;; Check sshd's PID file.
125 (test-equal "sshd PID"
126 (wait-for-file #$pid-file marionette)
127 (marionette-eval
128 '(begin
129 (use-modules (gnu services herd)
130 (srfi srfi-1))
131
132 (live-service-running
133 (find (lambda (live)
134 (memq 'ssh-daemon
135 (live-service-provision live)))
136 (current-services))))
137 marionette))
138
139 ;; Connect to the guest over SSH. Make sure we can run a shell
140 ;; command there.
141 (test-equal "shell command"
142 'hello
143 (call-with-connected-session/auth
144 (lambda (session)
145 ;; FIXME: 'get-server-public-key' segfaults.
146 ;; (get-server-public-key session)
147 (let ((channel (make-channel session)))
148 (channel-open-session channel)
149 (channel-request-exec channel "echo hello > /root/witness")
150 (and (zero? (channel-get-exit-status channel))
151 (wait-for-file "/root/witness" marionette))))))
152
e6b1a224
LC
153 ;; Check whether the 'getlogin' procedure returns the right thing.
154 (unless #$test-getlogin?
155 (test-skip 1))
156 (test-equal "getlogin"
157 '(0 "root")
158 (call-with-connected-session/auth
159 (lambda (session)
160 (let* ((pipe (open-remote-input-pipe
161 session
162 "guile -c '(display (getlogin))'"))
163 (output (get-string-all pipe))
164 (status (channel-get-exit-status pipe)))
165 (list status output)))))
166
ff913cf5
LC
167 ;; Connect to the guest over SFTP. Make sure we can write and
168 ;; read a file there.
169 (unless #$sftp?
170 (test-skip 1))
171 (test-equal "SFTP file writing and reading"
172 'hello
173 (call-with-connected-session/auth
174 (lambda (session)
175 (let ((sftp-session (make-sftp-session session))
176 (witness "/root/sftp-witness"))
177 (call-with-remote-output-file sftp-session witness
178 (cut display "hello" <>))
179 (call-with-remote-input-file sftp-session witness
180 read)))))
181
182 ;; Connect to the guest over SSH. Make sure we can run commands
183 ;; from the system profile.
184 (test-equal "run executables from system profile"
185 #t
186 (call-with-connected-session/auth
187 (lambda (session)
188 (let ((channel (make-channel session)))
189 (channel-open-session channel)
190 (channel-request-exec
191 channel
192 (string-append
193 "mkdir -p /root/.guix-profile/bin && "
194 "touch /root/.guix-profile/bin/path-witness && "
195 "chmod 755 /root/.guix-profile/bin/path-witness"))
196 (zero? (channel-get-exit-status channel))))))
197
198 ;; Connect to the guest over SSH. Make sure we can run commands
199 ;; from the user profile.
200 (test-equal "run executable from user profile"
201 #t
202 (call-with-connected-session/auth
203 (lambda (session)
204 (let ((channel (make-channel session)))
205 (channel-open-session channel)
206 (channel-request-exec channel "path-witness")
207 (zero? (channel-get-exit-status channel))))))
208
209 (test-end)
210 (exit (= (test-runner-fail-count (test-runner-current)) 0))))))
8b113790
LC
211
212 (gexp->derivation name test))
d5b0c902
LC
213
214(define %test-openssh
215 (system-test
216 (name "openssh")
217 (description "Connect to a running OpenSSH daemon.")
0e598850
LC
218 (value (run-ssh-test name
219 ;; Allow root logins with an empty password to
220 ;; simplify testing.
221 (service openssh-service-type
222 (openssh-configuration
223 (permit-root-login #t)
224 (allow-empty-passwords? #t)))
36f666c6
CL
225 "/var/run/sshd.pid"
226 #:sftp? #t))))
2b436389
LC
227
228(define %test-dropbear
229 (system-test
230 (name "dropbear")
231 (description "Connect to a running Dropbear SSH daemon.")
232 (value (run-ssh-test name
233 (service dropbear-service-type
234 (dropbear-configuration
235 (root-login? #t)
236 (allow-empty-passwords? #t)))
e6b1a224
LC
237 "/var/run/dropbear.pid"
238
239 ;; XXX: Our Dropbear is not built with PAM support.
240 ;; Even when it is, it seems to ignore the PAM
241 ;; 'session' requirements.
242 #:test-getlogin? #f))))