dbus.scm 16 KB

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