dbus.scm 16 KB

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