dbus.scm 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. ;;; GNU Guix --- Functional package management for GNU
  2. ;;; Copyright © 2013, 2014, 2015, 2016, 2017, 2019, 2020, 2021 Ludovic Courtès <ludo@gnu.org>
  3. ;;; Copyright © 2015 Sou Bunnbu <iyzsong@gmail.com>
  4. ;;; Copyright © 2021 Maxime Devos <maximedevos@telenet.be>
  5. ;;; Copyright © 2021 Brice Waegeneire <brice@waegenei.re>
  6. ;;;
  7. ;;; This file is part of GNU Guix.
  8. ;;;
  9. ;;; GNU Guix is free software; you can redistribute it and/or modify it
  10. ;;; under the terms of the GNU General Public License as published by
  11. ;;; the Free Software Foundation; either version 3 of the License, or (at
  12. ;;; your option) any later version.
  13. ;;;
  14. ;;; GNU Guix is distributed in the hope that it will be useful, but
  15. ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
  16. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. ;;; GNU General Public License for more details.
  18. ;;;
  19. ;;; You should have received a copy of the GNU General Public License
  20. ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
  21. (define-module (gnu services dbus)
  22. #:use-module (gnu services)
  23. #:use-module (gnu services shepherd)
  24. #:use-module (gnu system setuid)
  25. #:use-module (gnu system shadow)
  26. #:use-module (gnu system pam)
  27. #:use-module ((gnu packages glib) #:select (dbus))
  28. #:use-module (gnu packages polkit)
  29. #:use-module (gnu packages admin)
  30. #:use-module (guix gexp)
  31. #:use-module ((guix packages) #:select (package-name))
  32. #:use-module (guix records)
  33. #:use-module (guix modules)
  34. #:use-module (srfi srfi-1)
  35. #:use-module (ice-9 match)
  36. #:export (dbus-configuration
  37. dbus-configuration?
  38. dbus-root-service-type
  39. dbus-service
  40. wrapped-dbus-service
  41. polkit-service-type
  42. polkit-service))
  43. ;;;
  44. ;;; D-Bus.
  45. ;;;
  46. (define-record-type* <dbus-configuration>
  47. dbus-configuration make-dbus-configuration
  48. dbus-configuration?
  49. (dbus dbus-configuration-dbus ;file-like
  50. (default dbus))
  51. (services dbus-configuration-services ;list of <package>
  52. (default '())))
  53. (define (system-service-directory services)
  54. "Return the system service directory, containing @code{.service} files for
  55. all the services that may be activated by the daemon."
  56. (computed-file "dbus-system-services"
  57. (with-imported-modules '((guix build utils))
  58. #~(begin
  59. (use-modules (guix build utils)
  60. (srfi srfi-1))
  61. (define files
  62. (append-map (lambda (service)
  63. (find-files
  64. (string-append
  65. service
  66. "/share/dbus-1/")
  67. "\\.service$"))
  68. (list #$@services)))
  69. (mkdir #$output)
  70. (for-each (lambda (file)
  71. (symlink file
  72. (string-append #$output "/"
  73. (basename file))))
  74. files)
  75. #t))))
  76. (define (dbus-configuration-directory services)
  77. "Return a directory contains the @code{system-local.conf} file for DBUS that
  78. includes the @code{etc/dbus-1/system.d} directories of each package listed in
  79. @var{services}."
  80. (define build
  81. #~(begin
  82. (use-modules (sxml simple)
  83. (srfi srfi-1))
  84. (define-syntax directives
  85. (syntax-rules ()
  86. ;; Expand the given directives (SXML expressions) only if their
  87. ;; key names a file that exists.
  88. ((_ (name directory) rest ...)
  89. (let ((dir directory))
  90. (if (file-exists? dir)
  91. `((name ,dir)
  92. ,@(directives rest ...))
  93. (directives rest ...))))
  94. ((_)
  95. '())))
  96. (define (services->sxml services)
  97. ;; Return the SXML 'includedir' clauses for DIRS.
  98. `(busconfig
  99. ;; Increase this timeout to 300 seconds to work around race-y
  100. ;; failures such as <https://issues.guix.gnu.org/52051> on slow
  101. ;; computers with slow I/O.
  102. (limit (@ (name "auth_timeout")) "300000")
  103. (servicehelper "/run/setuid-programs/dbus-daemon-launch-helper")
  104. ;; First, the '.service' files of services subject to activation.
  105. ;; We use a fixed location under /etc because the setuid helper
  106. ;; looks for them in that location and nowhere else. See
  107. ;; <https://bugs.freedesktop.org/show_bug.cgi?id=92458>.
  108. (servicedir "/etc/dbus-1/system-services")
  109. ,@(append-map (lambda (dir)
  110. (directives
  111. (includedir
  112. (string-append dir "/etc/dbus-1/system.d"))
  113. (includedir
  114. (string-append dir "/share/dbus-1/system.d"))
  115. (servicedir ;for '.service' files
  116. (string-append dir "/share/dbus-1/services"))))
  117. services)))
  118. (mkdir #$output)
  119. ;; Provide /etc/dbus-1/system-services, which is where the setuid
  120. ;; helper looks for system service files.
  121. (symlink #$(system-service-directory services)
  122. (string-append #$output "/system-services"))
  123. ;; 'system-local.conf' is automatically included by the default
  124. ;; 'system.conf', so this is where we stuff our own things.
  125. (call-with-output-file (string-append #$output "/system-local.conf")
  126. (lambda (port)
  127. (sxml->xml (services->sxml (list #$@services))
  128. port)))))
  129. (computed-file "dbus-configuration" build))
  130. (define (dbus-etc-files config)
  131. "Return a list of FILES for @var{etc-service-type} to build the
  132. @code{/etc/dbus-1} directory."
  133. (list `("dbus-1" ,(dbus-configuration-directory
  134. (dbus-configuration-services config)))))
  135. (define %dbus-accounts
  136. ;; Accounts used by the system bus.
  137. (list (user-group (name "messagebus") (system? #t))
  138. (user-account
  139. (name "messagebus")
  140. (group "messagebus")
  141. (system? #t)
  142. (comment "D-Bus system bus user")
  143. (home-directory "/var/run/dbus")
  144. (shell (file-append shadow "/sbin/nologin")))))
  145. (define dbus-setuid-programs
  146. ;; Return a list of <setuid-program> for the program that we need.
  147. (match-lambda
  148. (($ <dbus-configuration> dbus services)
  149. (list (setuid-program
  150. (program (file-append
  151. dbus "/libexec/dbus-daemon-launch-helper")))))))
  152. (define (dbus-activation config)
  153. "Return an activation gexp for D-Bus using @var{config}."
  154. (with-imported-modules (source-module-closure
  155. '((gnu build activation)
  156. (guix build utils)))
  157. #~(begin
  158. (use-modules (gnu build activation)
  159. (guix build utils))
  160. (let ((user (getpwnam "messagebus")))
  161. ;; This directory contains the daemon's socket so it must be
  162. ;; world-readable.
  163. (mkdir-p/perms "/var/run/dbus" user #o755))
  164. (unless (file-exists? "/etc/machine-id")
  165. (format #t "creating /etc/machine-id...~%")
  166. (invoke (string-append #$(dbus-configuration-dbus config)
  167. "/bin/dbus-uuidgen")
  168. "--ensure=/etc/machine-id")))))
  169. (define dbus-shepherd-service
  170. (match-lambda
  171. (($ <dbus-configuration> dbus)
  172. (list (shepherd-service
  173. (documentation "Run the D-Bus system daemon.")
  174. (provision '(dbus-system))
  175. (requirement '(user-processes syslogd))
  176. (start #~(make-forkexec-constructor
  177. (list (string-append #$dbus "/bin/dbus-daemon")
  178. "--nofork" "--system" "--syslog-only")
  179. #:pid-file "/var/run/dbus/pid"))
  180. (stop #~(make-kill-destructor)))))))
  181. (define dbus-root-service-type
  182. (service-type (name 'dbus)
  183. (extensions
  184. (list (service-extension shepherd-root-service-type
  185. dbus-shepherd-service)
  186. (service-extension activation-service-type
  187. dbus-activation)
  188. (service-extension etc-service-type
  189. dbus-etc-files)
  190. (service-extension account-service-type
  191. (const %dbus-accounts))
  192. (service-extension setuid-program-service-type
  193. dbus-setuid-programs)))
  194. ;; Extensions consist of lists of packages (representing D-Bus
  195. ;; services) that we just concatenate.
  196. (compose concatenate)
  197. ;; The service's parameters field is extended by augmenting
  198. ;; its <dbus-configuration> 'services' field.
  199. (extend (lambda (config services)
  200. (dbus-configuration
  201. (inherit config)
  202. (services
  203. (append (dbus-configuration-services config)
  204. services)))))
  205. (default-value (dbus-configuration))
  206. (description "Run the system-wide D-Bus inter-process message
  207. bus. It allows programs and daemons to communicate and is also responsible
  208. for spawning (@dfn{activating}) D-Bus services on demand.")))
  209. (define* (dbus-service #:key (dbus dbus) (services '()))
  210. "Return a service that runs the \"system bus\", using @var{dbus}, with
  211. support for @var{services}.
  212. @uref{http://dbus.freedesktop.org/, D-Bus} is an inter-process communication
  213. facility. Its system bus is used to allow system services to communicate and
  214. be notified of system-wide events.
  215. @var{services} must be a list of packages that provide an
  216. @file{etc/dbus-1/system.d} directory containing additional D-Bus configuration
  217. and policy files. For example, to allow avahi-daemon to use the system bus,
  218. @var{services} must be equal to @code{(list avahi)}."
  219. (service dbus-root-service-type
  220. (dbus-configuration (dbus dbus)
  221. (services services))))
  222. (define (wrapped-dbus-service service program variables)
  223. "Return a wrapper for @var{service}, a package containing a D-Bus service,
  224. where @var{program} is wrapped such that @var{variables}, a list of name/value
  225. tuples, are all set as environment variables when the bus daemon launches it."
  226. (define wrapper
  227. (program-file (string-append (package-name service) "-program-wrapper")
  228. #~(begin
  229. (use-modules (ice-9 match))
  230. (for-each (match-lambda
  231. ((variable value)
  232. (setenv variable value)))
  233. '#$variables)
  234. (apply execl (string-append #$service "/" #$program)
  235. (string-append #$service "/" #$program)
  236. (cdr (command-line))))))
  237. (define build
  238. (with-imported-modules '((guix build utils))
  239. #~(begin
  240. (use-modules (guix build utils))
  241. (define service-directory
  242. "/share/dbus-1/system-services")
  243. (mkdir-p (dirname (string-append #$output
  244. service-directory)))
  245. (copy-recursively (string-append #$service
  246. service-directory)
  247. (string-append #$output
  248. service-directory))
  249. (symlink (string-append #$service "/etc") ;for etc/dbus-1
  250. (string-append #$output "/etc"))
  251. (for-each (lambda (file)
  252. (substitute* file
  253. (("Exec[[:blank:]]*=[[:blank:]]*([[:graph:]]+)(.*)$"
  254. _ original-program arguments)
  255. (string-append "Exec=" #$wrapper arguments
  256. "\n"))))
  257. (find-files #$output "\\.service$")))))
  258. (computed-file (string-append (package-name service) "-wrapper")
  259. build))
  260. ;;;
  261. ;;; Polkit privilege management service.
  262. ;;;
  263. (define-record-type* <polkit-configuration>
  264. polkit-configuration make-polkit-configuration
  265. polkit-configuration?
  266. (polkit polkit-configuration-polkit ;file-like
  267. (default %default-polkit))
  268. (actions polkit-configuration-actions ;list of file-like
  269. (default '())))
  270. (define %default-polkit
  271. ;; The default polkit package.
  272. (let-system (system target)
  273. ;; Since mozjs depends on Rust, which is currently x86_64-only, use
  274. ;; polkit-duktape on other systems.
  275. (if (string-prefix? "x86_64-" (or target system))
  276. polkit-mozjs
  277. polkit-duktape)))
  278. (define %polkit-accounts
  279. (list (user-group (name "polkitd") (system? #t))
  280. (user-account
  281. (name "polkitd")
  282. (group "polkitd")
  283. (system? #t)
  284. (comment "Polkit daemon user")
  285. (home-directory "/var/empty")
  286. (shell "/run/current-system/profile/sbin/nologin"))))
  287. (define %polkit-pam-services
  288. (list (unix-pam-service "polkit-1")))
  289. (define (polkit-directory packages)
  290. "Return a directory containing an @file{actions} and possibly a
  291. @file{rules.d} sub-directory, for use as @file{/etc/polkit-1}."
  292. (with-imported-modules '((guix build union))
  293. (computed-file "etc-polkit-1"
  294. #~(begin
  295. (use-modules (guix build union) (srfi srfi-26))
  296. (union-build #$output
  297. (map (cut string-append <>
  298. "/share/polkit-1")
  299. (list #$@packages)))))))
  300. (define polkit-etc-files
  301. (match-lambda
  302. (($ <polkit-configuration> polkit packages)
  303. `(("polkit-1" ,(polkit-directory (cons polkit packages)))))))
  304. (define polkit-setuid-programs
  305. (match-lambda
  306. (($ <polkit-configuration> polkit)
  307. (map file-like->setuid-program
  308. (list (file-append polkit "/lib/polkit-1/polkit-agent-helper-1")
  309. (file-append polkit "/bin/pkexec"))))))
  310. (define polkit-service-type
  311. (service-type (name 'polkit)
  312. (extensions
  313. (list (service-extension account-service-type
  314. (const %polkit-accounts))
  315. (service-extension pam-root-service-type
  316. (const %polkit-pam-services))
  317. (service-extension dbus-root-service-type
  318. (compose
  319. list
  320. polkit-configuration-polkit))
  321. (service-extension etc-service-type
  322. polkit-etc-files)
  323. (service-extension setuid-program-service-type
  324. polkit-setuid-programs)))
  325. ;; Extensions are lists of packages that provide polkit rules
  326. ;; or actions under share/polkit-1/{actions,rules.d}.
  327. (compose concatenate)
  328. (extend (lambda (config actions)
  329. (polkit-configuration
  330. (inherit config)
  331. (actions
  332. (append (polkit-configuration-actions config)
  333. actions)))))
  334. (default-value (polkit-configuration))
  335. (description
  336. "Run the
  337. @uref{http://www.freedesktop.org/wiki/Software/polkit/, Polkit privilege
  338. management service}, which allows system administrators to grant access to
  339. privileged operations in a structured way. Polkit is a requirement for most
  340. desktop environments, such as GNOME.")))
  341. (define* (polkit-service #:key (polkit polkit))
  342. "Return a service that runs the
  343. @uref{http://www.freedesktop.org/wiki/Software/polkit/, Polkit privilege
  344. management service}, which allows system administrators to grant access to
  345. privileged operations in a structured way. By querying the Polkit service, a
  346. privileged system component can know when it should grant additional
  347. capabilities to ordinary users. For example, an ordinary user can be granted
  348. the capability to suspend the system if the user is logged in locally."
  349. (service polkit-service-type
  350. (polkit-configuration (polkit polkit))))
  351. ;;; dbus.scm ends here