ssh.scm 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. ;;; GNU Guix --- Functional package management for GNU
  2. ;;; Copyright © 2016, 2017 Ludovic Courtès <ludo@gnu.org>
  3. ;;; Copyright © 2017 Clément Lassieur <clement@lassieur.org>
  4. ;;;
  5. ;;; This file is part of GNU Guix.
  6. ;;;
  7. ;;; GNU Guix is free software; you can redistribute it and/or modify it
  8. ;;; under the terms of the GNU General Public License as published by
  9. ;;; the Free Software Foundation; either version 3 of the License, or (at
  10. ;;; your option) any later version.
  11. ;;;
  12. ;;; GNU Guix is distributed in the hope that it will be useful, but
  13. ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
  14. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. ;;; GNU General Public License for more details.
  16. ;;;
  17. ;;; You should have received a copy of the GNU General Public License
  18. ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
  19. (define-module (gnu tests ssh)
  20. #:use-module (gnu tests)
  21. #:use-module (gnu system)
  22. #:use-module (gnu system vm)
  23. #:use-module (gnu services)
  24. #:use-module (gnu services ssh)
  25. #:use-module (gnu services networking)
  26. #:use-module (gnu packages ssh)
  27. #:use-module (guix gexp)
  28. #:use-module (guix store)
  29. #:export (%test-openssh
  30. %test-dropbear))
  31. (define* (run-ssh-test name ssh-service pid-file #:key (sftp? #f))
  32. "Run a test of an OS running SSH-SERVICE, which writes its PID to PID-FILE.
  33. SSH-SERVICE must be configured to listen on port 22 and to allow for root and
  34. empty-password logins.
  35. When SFTP? is true, run an SFTP server test."
  36. (define os
  37. (marionette-operating-system
  38. (simple-operating-system (dhcp-client-service) ssh-service)
  39. #:imported-modules '((gnu services herd)
  40. (guix combinators))))
  41. (define vm
  42. (virtual-machine
  43. (operating-system os)
  44. (port-forwardings '((2222 . 22)))))
  45. (define test
  46. (with-imported-modules '((gnu build marionette))
  47. #~(begin
  48. (eval-when (expand load eval)
  49. ;; Prepare to use Guile-SSH.
  50. (set! %load-path
  51. (cons (string-append #+guile-ssh "/share/guile/site/"
  52. (effective-version))
  53. %load-path)))
  54. (use-modules (gnu build marionette)
  55. (srfi srfi-26)
  56. (srfi srfi-64)
  57. (ice-9 match)
  58. (ssh session)
  59. (ssh auth)
  60. (ssh channel)
  61. (ssh sftp))
  62. (define marionette
  63. ;; Enable TCP forwarding of the guest's port 22.
  64. (make-marionette (list #$vm)))
  65. (define (make-session-for-test)
  66. "Make a session with predefined parameters for a test."
  67. (make-session #:user "root"
  68. #:port 2222
  69. #:host "localhost"
  70. #:log-verbosity 'protocol))
  71. (define (call-with-connected-session proc)
  72. "Call the one-argument procedure PROC with a freshly created and
  73. connected SSH session object, return the result of the procedure call. The
  74. session is disconnected when the PROC is finished."
  75. (let ((session (make-session-for-test)))
  76. (dynamic-wind
  77. (lambda ()
  78. (let ((result (connect! session)))
  79. (unless (equal? result 'ok)
  80. (error "Could not connect to a server"
  81. session result))))
  82. (lambda () (proc session))
  83. (lambda () (disconnect! session)))))
  84. (define (call-with-connected-session/auth proc)
  85. "Make an authenticated session. We should be able to connect as
  86. root with an empty password."
  87. (call-with-connected-session
  88. (lambda (session)
  89. ;; Try the simple authentication methods. Dropbear requires
  90. ;; 'none' when there are no passwords, whereas OpenSSH accepts
  91. ;; 'password' with an empty password.
  92. (let loop ((methods (list (cut userauth-password! <> "")
  93. (cut userauth-none! <>))))
  94. (match methods
  95. (()
  96. (error "all the authentication methods failed"))
  97. ((auth rest ...)
  98. (match (pk 'auth (auth session))
  99. ('success
  100. (proc session))
  101. ('denied
  102. (loop rest)))))))))
  103. (mkdir #$output)
  104. (chdir #$output)
  105. (test-begin "ssh-daemon")
  106. ;; Wait for sshd to be up and running.
  107. (test-eq "service running"
  108. 'running!
  109. (marionette-eval
  110. '(begin
  111. (use-modules (gnu services herd))
  112. (start-service 'ssh-daemon)
  113. 'running!)
  114. marionette))
  115. ;; Check sshd's PID file.
  116. (test-equal "sshd PID"
  117. (wait-for-file #$pid-file marionette)
  118. (marionette-eval
  119. '(begin
  120. (use-modules (gnu services herd)
  121. (srfi srfi-1))
  122. (live-service-running
  123. (find (lambda (live)
  124. (memq 'ssh-daemon
  125. (live-service-provision live)))
  126. (current-services))))
  127. marionette))
  128. ;; Connect to the guest over SSH. Make sure we can run a shell
  129. ;; command there.
  130. (test-equal "shell command"
  131. 'hello
  132. (call-with-connected-session/auth
  133. (lambda (session)
  134. ;; FIXME: 'get-server-public-key' segfaults.
  135. ;; (get-server-public-key session)
  136. (let ((channel (make-channel session)))
  137. (channel-open-session channel)
  138. (channel-request-exec channel "echo hello > /root/witness")
  139. (and (zero? (channel-get-exit-status channel))
  140. (wait-for-file "/root/witness" marionette))))))
  141. ;; Connect to the guest over SFTP. Make sure we can write and
  142. ;; read a file there.
  143. (unless #$sftp?
  144. (test-skip 1))
  145. (test-equal "SFTP file writing and reading"
  146. 'hello
  147. (call-with-connected-session/auth
  148. (lambda (session)
  149. (let ((sftp-session (make-sftp-session session))
  150. (witness "/root/sftp-witness"))
  151. (call-with-remote-output-file sftp-session witness
  152. (cut display "hello" <>))
  153. (call-with-remote-input-file sftp-session witness
  154. read)))))
  155. (test-end)
  156. (exit (= (test-runner-fail-count (test-runner-current)) 0)))))
  157. (gexp->derivation name test))
  158. (define %test-openssh
  159. (system-test
  160. (name "openssh")
  161. (description "Connect to a running OpenSSH daemon.")
  162. (value (run-ssh-test name
  163. ;; Allow root logins with an empty password to
  164. ;; simplify testing.
  165. (service openssh-service-type
  166. (openssh-configuration
  167. (permit-root-login #t)
  168. (allow-empty-passwords? #t)))
  169. "/var/run/sshd.pid"
  170. #:sftp? #t))))
  171. (define %test-dropbear
  172. (system-test
  173. (name "dropbear")
  174. (description "Connect to a running Dropbear SSH daemon.")
  175. (value (run-ssh-test name
  176. (service dropbear-service-type
  177. (dropbear-configuration
  178. (root-login? #t)
  179. (allow-empty-passwords? #t)))
  180. "/var/run/dropbear.pid"))))