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