aboutsummaryrefslogtreecommitdiff
*.eps
*.go
*.log
*.mo
*.pdf
*.png
*.tar.xz
*.tmp
*~
.#*
\#*\#
,*
/ABOUT-NLS
/INSTALL
/aclocal.m4
/autom4te.cache
/build-aux/ar-lib
/build-aux/compile
/build-aux/config.guess
/build-aux/config.rpath
/build-aux/config.sub
/build-aux/depcomp
/build-aux/install-sh
/build-aux/mdate-sh
/build-aux/missing
/build-aux/test-driver
/build-aux/texinfo.tex
/config.status
/configure
/doc/*.1
/doc/.dirstamp
/doc/contributing.*.texi
/doc/guix*.aux
/doc/guix*.cp
/doc/guix*.cps
/doc/guix*.fn
/doc/guix*.fns
/doc/guix*.html
/doc/guix*.info
/doc/guix*.info-[0-9]
/doc/guix*.ky
/doc/guix*.pg
/doc/guix*.toc
/doc/guix*.t2p
/doc/guix*.tp
/doc/guix*.vr
/doc/guix*.vrs
/doc/guix.*.texi
/doc/guix-cookbook.*.texi
/doc/guix.aux
/doc/guix.cp
/doc/guix.cps
/doc/guix.fn
/doc/guix.fns
/doc/guix.html
/doc/guix.info
/doc/guix.info-[0-9]
/doc/guix.ky
/doc/guix.pg
/doc/guix.toc
/doc/guix.t2p
/doc/guix.tp
/doc/guix.vr
/doc/guix.vrs
/doc/os-config-bare-bones.texi
/doc/os-config-desktop.texi
/doc/stamp-vti
/doc/version.texi
/doc/version-*.texi
/etc/committer.scm
/etc/gnu-store.mount
/etc/guix-daemon.cil
/etc/guix-daemon.conf
/etc/guix-daemon.service
/etc/guix-publish.conf
/etc/guix-publish.service
/etc/guix-gc.service
/etc/init.d/guix-daemon
/etc/openrc/guix-daemon
/guix-*
/guix/config.scm
/libformat.a
/libstore.a
/libutil.a
/m4/*
/m4/ChangeLog
/m4/gettext.m4
/m4/iconv.m4
/m4/lib-ld.m4
/m4/lib-link.m4
/m4/lib-prefix.m4
/m4/nls.m4
/m4/po.m4
/m4/progtest.m4
/nix/config.h
/nix/config.h.in
/po/doc/*.mo
/po/doc/*.pot
/po/guix/*.gmo
/po/guix/*.insert-header
/po/guix/*.mo
/po/guix/ChangeLog
/po/guix/Makefile.in.in
/po/guix/Makevars.template
/po/guix/POTFILES
/po/guix/Rules-quot
/po/guix/boldquot.sed
/po/guix/en@boldquot.*
/po/guix/en@quot.*
/po/guix/guix.pot
/po/guix/insert-header.sin
/po/guix/quot.sed
/po/guix/remove-potcdate.sed
/po/guix/remove-potcdate.sin
/po/guix/stamp-po
/po/packages/*.gmo
/po/packages/*.insert-header
/po/packages/*.mo
/po/packages/ChangeLog
/po/packages/Makefile.in.in
/po/packages/Makevars.template
/po/packages/POTFILES
/po/packages/Rules-quot
/po/packages/boldquot.sed
/po/packages/en@boldquot.*
/po/packages/en@quot.*
/po/packages/guix-packages.pot
/po/packages/insert-header.sin
/po/packages/quot.sed
/po/packages/remove-potcdate.sed
/po/packages/remove-potcdate.sin
/po/packages/stamp-po
/pre-inst-env
/release-*
/scripts/guix
/t-*/
/test-env
/test-tmp
/tests/*.trs
/tests/services/*.trs
GPATH
GRTAGS
GTAGS
Makefile
Makefile.in
config.cache
stamp-h[0-9]
.am[0-9]*/
.dirstamp
.deps
tmp
/doc/os-config-lightweight-desktop.texi
/nix/scripts/download
/.tarball-version
/.version
/doc/stamp-*
/gnu/packages/bootstrap
/gnu/packages/aux-files/guile-guile-launcher.o
/guile
.DS_Store
.mumi/current-issue
t-message))) ;; Make PORT non-blocking. (let ((flags (fcntl port F_GETFL))) (fcntl port F_SETFL (logior O_NONBLOCK flags))) (let ((channel (make-channel))) (spawn-fiber (lambda () (sleep timeout) ;suspends the fiber (put-message channel 'timeout))) (spawn-fiber (lambda () (lookahead-u8 port) ;suspends the fiber (put-message channel 'readable))) (log "suspending fiber on socket...~%") (match (get-message channel) ('readable #t) ('timeout #f))))))) (define (socket-address->string address) "Return a human-readable representation of ADDRESS, an object as returned by 'make-socket-address'." (let ((family (sockaddr:fam address))) (cond ((= AF_INET family) (string-append (inet-ntop AF_INET (sockaddr:addr address)) ":" (number->string (sockaddr:port address)))) ((= AF_INET6 family) (string-append "[" (inet-ntop AF_INET6 (sockaddr:addr address)) "]" ":" (number->string (sockaddr:port address)))) ((= AF_UNIX family) (sockaddr:path address)) (else (object->string address))))) (define* (secret-service-send-secrets address secret-root #:key (retry 60) (handshake-timeout 180)) "Copy all files under SECRET-ROOT by connecting to secret-service listening at ADDRESS, an address as returned by 'make-socket-address'. If connection fails, sleep 1s and retry RETRY times; once connected, wait for at most HANDSHAKE-TIMEOUT seconds for handshake to complete. Return #f on failure." (define (file->file+size+mode file-name) (let ((stat (stat file-name)) (target (substring file-name (string-length secret-root)))) (list target (stat:size stat) (stat:mode stat)))) (define (send-files sock) (let* ((files (if secret-root (find-files secret-root) '())) (files-sizes-modes (map file->file+size+mode files)) (secrets `(secrets (version 0) (files ,files-sizes-modes)))) (write secrets sock) (for-each (lambda (file) (call-with-input-file file (lambda (input) (dump-port input sock)))) files))) (log "sending secrets to ~a~%" (socket-address->string address)) (let ((sock (socket AF_INET (logior SOCK_CLOEXEC SOCK_STREAM) 0)) (sleep (if (resolve-module '(fibers) #f) (module-ref (resolve-interface '(fibers)) 'sleep) sleep))) ;; Connect to QEMU on the forwarded port. The 'connect' call succeeds as ;; soon as QEMU is ready, even if there's no server listening on the ;; forward port inside the guest. (let loop ((retry retry)) (catch 'system-error (cute connect sock address) (lambda (key . args) (when (zero? retry) (apply throw key args)) (log "retrying connection [~a attempts left]~%" (- retry 1)) (sleep 1) (loop (1- retry))))) (log "connected; waiting for handshake...~%") ;; Wait for "hello" message from the server. This is the only way to know ;; that we're really connected to the server inside the guest. (if (wait-for-readable-fd sock handshake-timeout) (match (read sock) (('secret-service-server ('version version ...)) (log "sending files from ~s...~%" secret-root) (send-files sock) (log "done sending files to ~a~%" (socket-address->string address)) (close-port sock) secret-root) (x (log "invalid handshake ~s~%" x) (close-port sock) #f)) (begin ;timeout (log "timeout while sending files to ~a~%" (socket-address->string address)) (close-port sock) #f)))) (define (delete-file* file) "Ensure FILE does not exist." (catch 'system-error (lambda () (delete-file file)) (lambda args (unless (= ENOENT (system-error-errno args)) (apply throw args))))) (define (secret-service-receive-secrets address) "Listen to ADDRESS, an address returned by 'make-socket-address', and wait for a secret service client to send secrets. Write them to the file system. Return the list of files installed on success, and #f otherwise." (define (wait-for-client address) ;; Wait for a connection on ADDRESS. Note: virtio-serial ports are safer ;; than TCP connections but they are (presumably) unsupported on GNU/Hurd. (let ((sock (socket AF_INET (logior SOCK_CLOEXEC SOCK_STREAM) 0))) (bind sock address) (listen sock 1) (log "waiting for secrets on ~a...~%" (socket-address->string address)) (match (select (list sock) '() '() 60) (((_) () ()) (match (accept sock) ((client . address) (log "client connection from ~a~%" (inet-ntop (sockaddr:fam address) (sockaddr:addr address))) ;; Send a "hello" message. This allows the client running on the ;; host to know that it's now actually connected to server running ;; in the guest. (write '(secret-service-server (version 0)) client) (force-output client) (close-port sock) client))) ((() () ()) (log "did not receive any secrets; time out~%") (close-port sock) #f)))) ;; TODO: Remove when (@ (guix build utils) dump-port) has a 'size' ;; parameter. (define (dump in out size) ;; Copy SIZE bytes from IN to OUT. (define buf-size 65536) (define buf (make-bytevector buf-size)) (let loop ((left size)) (if (<= left 0) 0 (let ((read (get-bytevector-n! in buf 0 (min left buf-size)))) (if (eof-object? read) left (begin (put-bytevector out buf 0 read) (loop (- left read)))))))) (define (read-secrets port) ;; Read secret files from PORT and install them. (match (false-if-exception (read port)) (('secrets ('version 0) ('files ((files sizes modes) ...))) (for-each (lambda (file size mode) (log "installing file '~a' (~a bytes)...~%" file size) (mkdir-p (dirname file)) ;; It could be that FILE already exists, for instance ;; because it has been created by a service's activation ;; snippet (e.g., SSH host keys). Delete it. (delete-file* file) (call-with-output-file file (lambda (output) (dump port output size) (chmod file mode)))) files sizes modes) (log "received ~a secret files~%" (length files)) files) (_ (log "invalid secrets received~%") #f))) (let* ((port (wait-for-client address)) (result (and=> port read-secrets))) (when port (close-port port)) result)) ;;; Local Variables: ;;; eval: (put 'with-modules 'scheme-indent-function 1) ;;; End: ;;; secret-service.scm ends here