perform-download.scm 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. ;;; GNU Guix --- Functional package management for GNU
  2. ;;; Copyright © 2016, 2017, 2018, 2020 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. (define-module (guix scripts perform-download)
  19. #:use-module (guix ui)
  20. #:use-module (guix scripts)
  21. #:use-module (guix derivations)
  22. #:use-module ((guix store) #:select (derivation-path? store-path?))
  23. #:use-module (guix build download)
  24. #:use-module (ice-9 match)
  25. #:export (guix-perform-download))
  26. ;; This program is a helper for the daemon's 'download' built-in builder.
  27. (define-syntax derivation-let
  28. (syntax-rules ()
  29. ((_ drv ((id name) rest ...) body ...)
  30. (let ((id (assoc-ref (derivation-builder-environment-vars drv)
  31. name)))
  32. (derivation-let drv (rest ...) body ...)))
  33. ((_ drv () body ...)
  34. (begin body ...))))
  35. (define %user-module
  36. ;; Module in which content-address mirror procedures are evaluated.
  37. (let ((module (make-fresh-user-module)))
  38. (module-use! module (resolve-interface '(guix base32)))
  39. module))
  40. (define* (perform-download drv #:optional output
  41. #:key print-build-trace?)
  42. "Perform the download described by DRV, a fixed-output derivation, to
  43. OUTPUT.
  44. Note: Unless OUTPUT is #f, we don't read the value of 'out' in DRV since the
  45. actual output is different from that when we're doing a 'bmCheck' or
  46. 'bmRepair' build."
  47. (derivation-let drv ((url "url")
  48. (output* "out")
  49. (executable "executable")
  50. (mirrors "mirrors")
  51. (content-addressed-mirrors "content-addressed-mirrors")
  52. (disarchive-mirrors "disarchive-mirrors"))
  53. (unless url
  54. (leave (G_ "~a: missing URL~%") (derivation-file-name drv)))
  55. (let* ((output (or output output*))
  56. (url (call-with-input-string url read))
  57. (drv-output (assoc-ref (derivation-outputs drv) "out"))
  58. (algo (derivation-output-hash-algo drv-output))
  59. (hash (derivation-output-hash drv-output)))
  60. (unless (and algo hash)
  61. (leave (G_ "~a is not a fixed-output derivation~%")
  62. (derivation-file-name drv)))
  63. ;; We're invoked by the daemon, which gives us write access to OUTPUT.
  64. (when (url-fetch url output
  65. #:print-build-trace? print-build-trace?
  66. #:mirrors (if mirrors
  67. (call-with-input-file mirrors read)
  68. '())
  69. #:content-addressed-mirrors
  70. (if content-addressed-mirrors
  71. (call-with-input-file content-addressed-mirrors
  72. (lambda (port)
  73. (eval (read port) %user-module)))
  74. '())
  75. #:disarchive-mirrors
  76. (if disarchive-mirrors
  77. (call-with-input-file disarchive-mirrors read)
  78. '())
  79. #:hashes `((,algo . ,hash))
  80. ;; Since DRV's output hash is known, X.509 certificate
  81. ;; validation is pointless.
  82. #:verify-certificate? #f)
  83. (when (and executable (string=? executable "1"))
  84. (chmod output #o755))))))
  85. (define (assert-low-privileges)
  86. (when (zero? (getuid))
  87. (leave (G_ "refusing to run with elevated privileges (UID ~a)~%")
  88. (getuid))))
  89. (define-command (guix-perform-download . args)
  90. (category internal)
  91. (synopsis "perform download described by fixed-output derivations")
  92. ;; This is an "out-of-band" download in that this code is executed directly
  93. ;; by the daemon and not explicitly described as an input of the derivation.
  94. ;; This allows us to sidestep bootstrapping problems, such as downloading
  95. ;; the source code of GnuTLS over HTTPS before we have built GnuTLS. See
  96. ;; <https://bugs.gnu.org/22774>.
  97. (define print-build-trace?
  98. (match (getenv "_NIX_OPTIONS")
  99. (#f #f)
  100. (str (string-contains str "print-extended-build-trace=1"))))
  101. ;; This program must be invoked by guix-daemon under an unprivileged UID to
  102. ;; prevent things downloading from 'file:///etc/shadow' or arbitrary code
  103. ;; execution via the content-addressed mirror procedures. (That means we
  104. ;; exclude users who did not pass '--build-users-group'.)
  105. (with-error-handling
  106. (match args
  107. (((? derivation-path? drv) (? store-path? output))
  108. (assert-low-privileges)
  109. (perform-download (read-derivation-from-file drv)
  110. output
  111. #:print-build-trace? print-build-trace?))
  112. (((? derivation-path? drv)) ;backward compatibility
  113. (assert-low-privileges)
  114. (perform-download (read-derivation-from-file drv)
  115. #:print-build-trace? print-build-trace?))
  116. (("--version")
  117. (show-version-and-exit))
  118. (x
  119. (leave
  120. (G_ "fixed-output derivation and output file name expected~%"))))))
  121. ;; Local Variables:
  122. ;; eval: (put 'derivation-let 'scheme-indent-function 2)
  123. ;; End:
  124. ;; perform-download.scm ends here