rsync.scm 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. ;;; GNU Guix --- Functional package management for GNU
  2. ;;; Copyright © 2017 Oleg Pykhalov <go.wigust@gmail.com>
  3. ;;; Copyright © 2021, 2023 Ludovic Courtès <ludo@gnu.org>
  4. ;;; Copyright © 2023 Maxim Cournoyer <maxim.cournoyer@gmail.com>
  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. (define-module (gnu services rsync)
  21. #:use-module ((gnu build linux-container) #:select (%namespaces))
  22. #:use-module (gnu services)
  23. #:use-module (gnu services base)
  24. #:use-module (gnu services shepherd)
  25. #:autoload (gnu system file-systems) (file-system-mapping)
  26. #:use-module (gnu system shadow)
  27. #:use-module (gnu packages admin)
  28. #:use-module (gnu packages linux)
  29. #:use-module (gnu packages rsync)
  30. #:use-module (guix records)
  31. #:use-module (guix gexp)
  32. #:use-module (guix diagnostics)
  33. #:use-module (guix i18n)
  34. #:use-module (guix least-authority)
  35. #:use-module (srfi srfi-1)
  36. #:use-module (srfi srfi-26)
  37. #:use-module (ice-9 match)
  38. #:export (rsync-configuration
  39. rsync-configuration?
  40. rsync-configuration-modules
  41. rsync-module
  42. rsync-module?
  43. rsync-module-name
  44. rsync-module-file-name
  45. rsync-module-comment
  46. rsync-module-read-only
  47. rsync-module-timeout
  48. rsync-service-type))
  49. ;;;; Commentary:
  50. ;;;
  51. ;;; This module implements a service that to run instance of Rsync,
  52. ;;; files synchronization tool.
  53. ;;;
  54. ;;;; Code:
  55. (define-with-syntax-properties (warn-share-field-deprecation (value properties))
  56. (unless (unspecified? value)
  57. (warning (source-properties->location properties)
  58. (G_ "the 'share-path' and 'share-comment' fields is deprecated, \
  59. please use 'modules' instead~%")))
  60. value)
  61. (define-record-type* <rsync-configuration>
  62. rsync-configuration
  63. make-rsync-configuration
  64. rsync-configuration?
  65. (package rsync-configuration-package ; file-like
  66. (default rsync))
  67. (address rsync-configuration-address ; string | #f
  68. (default #f))
  69. (port-number rsync-configuration-port-number ; integer
  70. (default 873))
  71. (pid-file rsync-configuration-pid-file ; string
  72. (default "/var/run/rsyncd/rsyncd.pid"))
  73. (lock-file rsync-configuration-lock-file ; string
  74. (default "/var/run/rsyncd/rsyncd.lock"))
  75. (log-file rsync-configuration-log-file ; string
  76. (default "/var/log/rsyncd.log"))
  77. (use-chroot? rsync-configuration-use-chroot? ; boolean
  78. (sanitize warn-share-field-deprecation)
  79. (default *unspecified*))
  80. (modules rsync-configuration-actual-modules ;list of <rsync-module>
  81. (default %default-modules)) ;TODO: eventually remove default
  82. (share-path rsync-configuration-share-path ; string
  83. (sanitize warn-share-field-deprecation)
  84. (default *unspecified*))
  85. (share-comment rsync-configuration-share-comment ; string
  86. (sanitize warn-share-field-deprecation)
  87. (default *unspecified*))
  88. (read-only? rsync-configuration-read-only? ; boolean
  89. (sanitize warn-share-field-deprecation)
  90. (default *unspecified*))
  91. (timeout rsync-configuration-timeout ; integer
  92. (sanitize warn-share-field-deprecation)
  93. (default *unspecified*))
  94. (user rsync-configuration-user ; string
  95. (default "root"))
  96. (group rsync-configuration-group ; string
  97. (default "root"))
  98. (uid rsync-configuration-uid ; string
  99. (default "rsyncd"))
  100. (gid rsync-configuration-gid ; string
  101. (default "rsyncd")))
  102. ;; Rsync "module": a directory exported the rsync protocol.
  103. (define-record-type* <rsync-module>
  104. rsync-module make-rsync-module
  105. rsync-module?
  106. (name rsync-module-name) ;string
  107. (file-name rsync-module-file-name) ;string
  108. (comment rsync-module-comment ;string
  109. (default ""))
  110. (read-only? rsync-module-read-only? ;boolean
  111. (default #t))
  112. (chroot? rsync-module-chroot? ;boolean
  113. (default #t))
  114. (timeout rsync-module-timeout ;integer
  115. (default 300)))
  116. (define %default-modules
  117. ;; Default modules, provided for backward compatibility.
  118. (list (rsync-module (name "files")
  119. (file-name "/srv/rsyncd")
  120. (comment "Rsync share")
  121. (read-only? #f)))) ;yes, that was the default
  122. (define (rsync-configuration-modules config)
  123. (match-record config <rsync-configuration>
  124. (modules
  125. share-path share-comment use-chroot? read-only? timeout) ;deprecated
  126. (if (unspecified? share-path)
  127. (rsync-configuration-actual-modules config)
  128. (list (rsync-module ;backward compatibility
  129. (name "files")
  130. (file-name share-path)
  131. (comment "Rsync share")
  132. (chroot?
  133. (if (unspecified? use-chroot?) #t use-chroot?))
  134. (read-only?
  135. (if (unspecified? read-only?) #f read-only?))
  136. (timeout
  137. (if (unspecified? timeout) 300 timeout)))))))
  138. (define (rsync-account config)
  139. "Return the user accounts and user groups for CONFIG."
  140. (let ((rsync-user (if (rsync-configuration-uid config)
  141. (rsync-configuration-uid config)
  142. (rsync-configuration-user config)))
  143. (rsync-group (if (rsync-configuration-gid config)
  144. (rsync-configuration-gid config)
  145. (rsync-configuration-group config))))
  146. (list (user-group (name rsync-group) (system? #t))
  147. (user-account
  148. (name rsync-user)
  149. (system? #t)
  150. (group rsync-group)
  151. (comment "rsyncd privilege separation user")
  152. (home-directory (string-append "/var/run/"
  153. rsync-user))
  154. (shell (file-append shadow "/sbin/nologin"))))))
  155. (define (rsync-activation config)
  156. "Return the activation GEXP for CONFIG."
  157. (with-imported-modules '((guix build utils))
  158. #~(begin
  159. (let ((user (getpw (if #$(rsync-configuration-uid config)
  160. #$(rsync-configuration-uid config)
  161. #$(rsync-configuration-user config))))
  162. (group (getpw (if #$(rsync-configuration-gid config)
  163. #$(rsync-configuration-gid config)
  164. #$(rsync-configuration-group config)))))
  165. (mkdir-p (dirname #$(rsync-configuration-pid-file config)))
  166. (for-each (lambda (directory)
  167. (mkdir-p directory)
  168. (chown directory (passwd:uid user) (group:gid group)))
  169. '#$(map rsync-module-file-name
  170. (rsync-configuration-modules config)))))))
  171. (define (rsync-config-file config)
  172. ;; Return the rsync configuration file corresponding to CONFIG.
  173. (define (module-config module)
  174. (match-record module <rsync-module>
  175. (name file-name comment chroot? read-only? timeout)
  176. (list "[" name "]\n"
  177. " path = " file-name "\n"
  178. " use chroot = " (if chroot? "true" "false") "\n"
  179. " comment = " comment "\n"
  180. " read only = " (if read-only? "true" "false") "\n"
  181. " timeout = " (number->string timeout) "\n")))
  182. (define modules
  183. (rsync-configuration-modules config))
  184. (match-record config <rsync-configuration>
  185. (package address port-number pid-file lock-file log-file
  186. user group uid gid)
  187. (unless (string=? user "root")
  188. (cond
  189. ((<= port-number 1024)
  190. (error (string-append "rsync-service: to run on port "
  191. (number->string port-number)
  192. ", user must be root.")))
  193. ((find rsync-module-chroot? modules)
  194. (error (string-append "rsync-service: to run in a chroot"
  195. ", user must be root.")))
  196. (uid
  197. (error "rsync-service: to use uid, user must be root."))
  198. (gid
  199. (error "rsync-service: to use gid, user must be root."))))
  200. (apply mixed-text-file "rsync.conf"
  201. "# Generated by 'rsync-service'.\n\n"
  202. "pid file = " pid-file "\n"
  203. "lock file = " lock-file "\n"
  204. "log file = " log-file "\n"
  205. (if address (string-append "address = " address "\n") "")
  206. "port = " (number->string port-number) "\n"
  207. (if uid (string-append "uid = " uid "\n") "")
  208. "gid = " (if gid gid "nogroup") "\n" ; no group nobody
  209. "\n\n"
  210. (append-map module-config modules))))
  211. (define (rsync-shepherd-service config)
  212. "Return a <shepherd-service> for rsync with CONFIG."
  213. ;; XXX: Predicates copied from (gnu services ssh).
  214. (define inetd-style?
  215. #~(and (defined? 'make-inetd-constructor)
  216. (not (string=? (@ (shepherd config) Version) "0.9.0"))))
  217. (define ipv6-support?
  218. #~(catch 'system-error
  219. (lambda ()
  220. (let ((sock (socket AF_INET6 SOCK_STREAM 0)))
  221. (close-port sock)
  222. #t))
  223. (const #f)))
  224. (define (module->file-system-mapping module)
  225. "Return the <file-system-mapping> record corresponding to MODULE, an
  226. <rsync-module> object."
  227. (match-record module <rsync-module>
  228. (file-name read-only?)
  229. (file-system-mapping
  230. (source file-name)
  231. (target source)
  232. (writable? (not read-only?)))))
  233. (match-record config <rsync-configuration>
  234. (package log-file modules pid-file port-number user group)
  235. ;; Run the rsync daemon in its own 'mnt' namespace, to guard against
  236. ;; change to mount points it may be serving.
  237. (let* ((config-file (rsync-config-file config))
  238. (rsync-command #~(list #$(least-authority-wrapper
  239. (file-append rsync "/bin/rsync")
  240. #:name "rsync"
  241. #:namespaces (fold delq %namespaces
  242. '(net user))
  243. #:mappings
  244. (append (list (file-system-mapping
  245. (source "/var/run/rsyncd")
  246. (target source)
  247. (writable? #t))
  248. (file-system-mapping
  249. (source (dirname log-file))
  250. (target source)
  251. (writable? #t))
  252. (file-system-mapping
  253. (source config-file)
  254. (target source)))
  255. (map module->file-system-mapping
  256. modules)))
  257. "--config" #$config-file "--daemon")))
  258. (list (shepherd-service
  259. (provision '(rsync))
  260. (documentation "Run rsync daemon.")
  261. (actions (list (shepherd-configuration-action config-file)))
  262. (start #~(if #$inetd-style?
  263. (make-inetd-constructor
  264. #$rsync-command
  265. (cons (endpoint
  266. (make-socket-address AF_INET INADDR_ANY
  267. #$port-number))
  268. (if #$ipv6-support?
  269. (list
  270. (endpoint
  271. (make-socket-address AF_INET6 IN6ADDR_ANY
  272. #$port-number)))
  273. '()))
  274. #:user #$user
  275. #:group #$group)
  276. (make-forkexec-constructor #$rsync-command
  277. #:pid-file #$pid-file
  278. #:user #$user
  279. #:group #$group)))
  280. (stop #~(if #$inetd-style?
  281. (make-inetd-destructor)
  282. (make-kill-destructor))))))))
  283. (define rsync-service-type
  284. (service-type
  285. (name 'rsync)
  286. (extensions
  287. (list (service-extension shepherd-root-service-type rsync-shepherd-service)
  288. (service-extension account-service-type rsync-account)
  289. (service-extension activation-service-type rsync-activation)))
  290. (default-value (rsync-configuration))
  291. (description
  292. "Run the rsync file copying tool in daemon mode. This allows remote hosts
  293. to keep synchronized copies of the files exported by rsync.")))