dbus.scm 17 KB

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