File: ssh.scm.in

package info (click to toggle)
guile-git 0.9.0-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 892 kB
  • sloc: lisp: 6,231; makefile: 132; sh: 8
file content (161 lines) | stat: -rw-r--r-- 5,519 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
;;; Guile-Git --- GNU Guile bindings of libgit2
;;; Copyright © 2019 Mathieu Othacehe <m.othacehe@gmail.com>
;;;
;;; This file is part of Guile-Git.
;;;
;;; Guile-Git is free software; you can redistribute it and/or modify it
;;; under the terms of the GNU General Public License as published by
;;; the Free Software Foundation; either version 3 of the License, or
;;; (at your option) any later version.
;;;
;;; Guile-Git is distributed in the hope that it will be useful, but
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
;;; General Public License for more details.
;;;
;;; You should have received a copy of the GNU General Public License
;;; along with Guile-Git.  If not, see <http://www.gnu.org/licenses/>.

(define-module (tests ssh)
  #:use-module (git auth)
  #:use-module (tests helpers)
  #:use-module ((srfi srfi-64) #:select (test-skip))
  #:use-module (ice-9 popen)
  #:use-module (ice-9 rdelim)
  #:use-module (ice-9 regex)
  #:export (sshd-available?
            with-sshd-server
            with-ssh-agent
            make-client-ssh-auth))

(define sshd "@SSHD@")
(define %ssh-dir (path-join "@abs_top_builddir@" "/tests/.ssh"))
(define (in-ssh-directory . args)
  (apply path-join %ssh-dir args))

(define (sshd-available?)
  ;; Return #t if sshd is available (it does not support
  ;; ‘--version’ or anything similar though).
  (= 256 (parameterize ((current-error-port (%make-void-port "w")))
           (system* sshd "--something-not-supported"))))

(define (start-sshd port)
  (define (write-authorized-keys file)
    (call-with-output-file file
      (lambda (port)
        ;; We need to pass PATH so that git binary (git-upload-pack) can be
        ;; found from sshd.
        (format port "environment=\"PATH=~a\" ~a"
                (getenv "PATH")
                (call-with-input-file (in-ssh-directory "id_rsa_client.pub")
                  read-string)))))

  (define (write-sshd-conf conf authorized-keys)
    (call-with-output-file conf
      (lambda (port)
        (format port "\
# Listen only on the loopback device.
ListenAddress localhost

AuthorizedKeysFile ~a
PidFile ~a
PermitUserEnvironment yes

# libssh2 and therefore libgit2 do not yet support
# sha2-based rsa algorithms.
# See upstream issue:
#   https://github.com/libssh2/libssh2/issues/536
HostkeyAlgorithms +ssh-rsa
PubkeyAcceptedAlgorithms +ssh-rsa

# Disable permission checks on auth files for the sake
# of isolated build environments.
StrictModes no~%"
                authorized-keys
                (in-ssh-directory "sshd_pid")))))

  (let ((sshd-conf (in-ssh-directory "sshd.conf"))
        (sshd-key (in-ssh-directory "id_rsa_server"))
        (authorized-keys (in-ssh-directory "authorized_keys")))
    (unsetenv "SSH_AUTH_SOCK")
    (chmod sshd-key #o600)
    (write-authorized-keys authorized-keys)
    (write-sshd-conf sshd-conf authorized-keys)
    (system* sshd "-p" (number->string port) "-f" sshd-conf "-h" sshd-key)))

(define (stop-sshd)
  (define (read-pid port)
    (string-trim-right (read-string port) #\newline))

  (let ((pid
         (call-with-input-file (in-ssh-directory "sshd_pid")
           read-pid)))
    (system* "kill" pid)))

(define (valid-user-shell?)
  "Return true if the current user has a valid shell in /etc/passwd."
  ;; Note: This check is useful to account for Guix build environments, where
  ;; /etc/passwd refers to a non-existent shell for the build user.  In that
  ;; case, it's impossible to log in over SSH as sshd blindly attempts to
  ;; execute the user shell.
  (and=> (false-if-exception (getpwuid (getuid)))
         (lambda (passwd)
           (let ((shell (passwd:shell passwd)))
             (access? shell (logior R_OK X_OK))))))

(define-syntax-rule (with-sshd-server port tests ...)
  (let ((skip? (or (not (sshd-available?))
                   (not (valid-user-shell?)))))
    (dynamic-wind
      (lambda ()
        (if skip?
            (test-skip (length '(tests ...)))
            (start-sshd port)))
      (lambda ()
        tests ...)
      (lambda ()
        (unless skip?
          (stop-sshd))))))

(define %ssh-auth-sock-regexp
  (make-regexp "SSH_AUTH_SOCK=(.*); export SSH_AUTH_SOCK;"))

(define %ssh-agent-pid-regexp
  (make-regexp "SSH_AGENT_PID=(.*); export SSH_AGENT_PID;"))

(define (start-ssh-agent)
  (let* ((p (open-input-pipe "ssh-agent -s"))
         (ssh-auth-sock-data (read-line p))
         (ssh-agent-pid-data (read-line p))
         (sock
          (let ((match (regexp-exec %ssh-auth-sock-regexp
                                    ssh-auth-sock-data)))
            (match:substring match 1)))
         (pid (let ((match (regexp-exec %ssh-agent-pid-regexp
                                        ssh-agent-pid-data)))
                (match:substring match 1))))
    (setenv "SSH_AUTH_SOCK" sock)
    pid))

(define (ssh-agent-add-client-key)
  (system* "ssh-add" (in-ssh-directory "id_rsa_client")))

(define-syntax-rule (with-ssh-agent body ...)
  (let ((pid (start-ssh-agent)))
    (dynamic-wind
      (const #f)
      (lambda ()
        (ssh-agent-add-client-key)
        body ...)
      (lambda ()
        (system* "kill" pid)
        (unsetenv "SSH_AUTH_SOCK")))))

(define (make-client-ssh-auth)
  (let ((pub-key (in-ssh-directory "id_rsa_client.pub"))
        (pri-key (in-ssh-directory "id_rsa_client")))
    (chmod pri-key #o600)
    (chmod pub-key #o644)
    (%make-auth-ssh-credentials
     pub-key
     pri-key)))