dbus.scm 17 KB

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