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>
7 ;;; This file is part of GNU Guix.
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.
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.
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/>.
22 (define-module (gnu services dbus)
23 #:use-module (gnu services)
24 #:use-module (gnu services shepherd)
25 #:use-module (gnu system setuid)
26 #:use-module (gnu system shadow)
27 #:use-module (gnu system pam)
28 #:use-module ((gnu packages glib) #:select (dbus))
29 #:use-module (gnu packages polkit)
30 #:use-module (gnu packages admin)
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
39 dbus-root-service-type
50 (define-record-type* <dbus-configuration>
51 dbus-configuration make-dbus-configuration
53 (dbus dbus-configuration-dbus ;file-like
55 (services dbus-configuration-services ;list of <package>
57 (verbose? dbus-configuration-verbose? ;boolean
60 (define (system-service-directory services)
61 "Return the system service directory, containing @code{.service} files for
62 all the services that may be activated by the daemon."
63 (computed-file "dbus-system-services"
64 (with-imported-modules '((guix build utils))
66 (use-modules (guix build utils)
70 (append-map (lambda (service)
79 (for-each (lambda (file)
81 (string-append #$output "/"
86 (define (dbus-configuration-directory services)
87 "Return a directory contains the @code{system-local.conf} file for DBUS that
88 includes the @code{etc/dbus-1/system.d} directories of each package listed in
92 (use-modules (sxml simple)
95 (define-syntax directives
97 ;; Expand the given directives (SXML expressions) only if their
98 ;; key names a file that exists.
99 ((_ (name directory) rest ...)
100 (let ((dir directory))
101 (if (file-exists? dir)
103 ,@(directives rest ...))
104 (directives rest ...))))
108 (define (services->sxml services)
109 ;; Return the SXML 'includedir' clauses for DIRS.
111 ;; Increase this timeout to 300 seconds to work around race-y
112 ;; failures such as <https://issues.guix.gnu.org/52051> on slow
113 ;; computers with slow I/O.
114 (limit (@ (name "auth_timeout")) "300000")
115 (servicehelper "/run/setuid-programs/dbus-daemon-launch-helper")
117 ;; First, the '.service' files of services subject to activation.
118 ;; We use a fixed location under /etc because the setuid helper
119 ;; looks for them in that location and nowhere else. See
120 ;; <https://bugs.freedesktop.org/show_bug.cgi?id=92458>.
121 (servicedir "/etc/dbus-1/system-services")
123 ,@(append-map (lambda (dir)
126 (string-append dir "/etc/dbus-1/system.d"))
128 (string-append dir "/share/dbus-1/system.d"))
129 (servicedir ;for '.service' files
130 (string-append dir "/share/dbus-1/services"))))
135 ;; Provide /etc/dbus-1/system-services, which is where the setuid
136 ;; helper looks for system service files.
137 (symlink #$(system-service-directory services)
138 (string-append #$output "/system-services"))
140 ;; 'system-local.conf' is automatically included by the default
141 ;; 'system.conf', so this is where we stuff our own things.
142 (call-with-output-file (string-append #$output "/system-local.conf")
144 (sxml->xml (services->sxml (list #$@services))
147 (computed-file "dbus-configuration" build))
149 (define (dbus-etc-files config)
150 "Return a list of FILES for @var{etc-service-type} to build the
151 @code{/etc/dbus-1} directory."
152 (list `("dbus-1" ,(dbus-configuration-directory
153 (dbus-configuration-services config)))))
155 (define %dbus-accounts
156 ;; Accounts used by the system bus.
157 (list (user-group (name "messagebus") (system? #t))
162 (comment "D-Bus system bus user")
163 (home-directory "/var/run/dbus")
164 (shell (file-append shadow "/sbin/nologin")))))
166 (define dbus-setuid-programs
167 ;; Return a list of <setuid-program> for the program that we need.
169 (($ <dbus-configuration> dbus services)
170 (list (setuid-program
171 (program (file-append
172 dbus "/libexec/dbus-daemon-launch-helper")))))))
174 (define (dbus-activation config)
175 "Return an activation gexp for D-Bus using @var{config}."
176 (with-imported-modules (source-module-closure
177 '((gnu build activation)
180 (use-modules (gnu build activation)
183 (let ((user (getpwnam "messagebus")))
184 ;; This directory contains the daemon's socket so it must be
186 (mkdir-p/perms "/var/run/dbus" user #o755))
188 (unless (file-exists? "/etc/machine-id")
189 (format #t "creating /etc/machine-id...~%")
190 (invoke (string-append #$(dbus-configuration-dbus config)
192 "--ensure=/etc/machine-id")))))
194 (define dbus-shepherd-service
196 (($ <dbus-configuration> dbus _ verbose?)
197 (list (shepherd-service
198 (documentation "Run the D-Bus system daemon.")
199 (provision '(dbus-system))
200 (requirement '(user-processes syslogd))
201 (start #~(make-forkexec-constructor
202 (list (string-append #$dbus "/bin/dbus-daemon")
203 "--nofork" "--system" "--syslog-only")
205 ;; Since the verbose output goes to the console,
206 ;; not syslog, add a log file to capture it.
207 '(#:environment-variables '("DBUS_VERBOSE=1")
208 #:log-file "/var/log/dbus-daemon.log")
210 #:pid-file "/var/run/dbus/pid"))
211 (stop #~(make-kill-destructor)))))))
213 (define dbus-root-service-type
214 (service-type (name 'dbus)
216 (list (service-extension shepherd-root-service-type
217 dbus-shepherd-service)
218 (service-extension activation-service-type
220 (service-extension etc-service-type
222 (service-extension account-service-type
223 (const %dbus-accounts))
224 (service-extension setuid-program-service-type
225 dbus-setuid-programs)))
227 ;; Extensions consist of lists of packages (representing D-Bus
228 ;; services) that we just concatenate.
229 (compose concatenate)
231 ;; The service's parameters field is extended by augmenting
232 ;; its <dbus-configuration> 'services' field.
233 (extend (lambda (config services)
237 (append (dbus-configuration-services config)
240 (default-value (dbus-configuration))
241 (description "Run the system-wide D-Bus inter-process message
242 bus. It allows programs and daemons to communicate and is also responsible
243 for spawning (@dfn{activating}) D-Bus services on demand.")))
245 (define* (dbus-service #:key (dbus dbus) (services '()) verbose?)
246 "Return a service that runs the \"system bus\", using @var{dbus}, with
247 support for @var{services}. When @var{verbose?} is true, it causes the
248 @samp{DBUS_VERBOSE} environment variable to be set to @samp{1}; a
249 verbose-enabled D-Bus package such as @code{dbus-verbose} should be provided
250 as @var{dbus} in this scenario.
252 @uref{http://dbus.freedesktop.org/, D-Bus} is an inter-process communication
253 facility. Its system bus is used to allow system services to communicate and
254 be notified of system-wide events.
256 @var{services} must be a list of packages that provide an
257 @file{etc/dbus-1/system.d} directory containing additional D-Bus configuration
258 and policy files. For example, to allow avahi-daemon to use the system bus,
259 @var{services} must be equal to @code{(list avahi)}."
260 (service dbus-root-service-type
261 (dbus-configuration (dbus dbus)
263 (verbose? verbose?))))
265 (define (wrapped-dbus-service service program variables)
266 "Return a wrapper for @var{service}, a package containing a D-Bus service,
267 where @var{program} is wrapped such that @var{variables}, a list of name/value
268 tuples, are all set as environment variables when the bus daemon launches it."
270 (program-file (string-append (package-name service) "-program-wrapper")
272 (use-modules (ice-9 match))
274 (for-each (match-lambda
276 (setenv variable value)))
279 (apply execl (string-append #$service "/" #$program)
280 (string-append #$service "/" #$program)
281 (cdr (command-line))))))
284 (with-imported-modules '((guix build utils))
286 (use-modules (guix build utils))
288 (define service-directory
289 "/share/dbus-1/system-services")
291 (mkdir-p (dirname (string-append #$output
293 (copy-recursively (string-append #$service
295 (string-append #$output
297 (symlink (string-append #$service "/etc") ;for etc/dbus-1
298 (string-append #$output "/etc"))
300 (for-each (lambda (file)
302 (("Exec[[:blank:]]*=[[:blank:]]*([[:graph:]]+)(.*)$"
303 _ original-program arguments)
304 (string-append "Exec=" #$wrapper arguments
306 (find-files #$output "\\.service$")))))
308 (computed-file (string-append (package-name service) "-wrapper")
313 ;;; Polkit privilege management service.
316 (define-record-type* <polkit-configuration>
317 polkit-configuration make-polkit-configuration
318 polkit-configuration?
319 (polkit polkit-configuration-polkit ;file-like
320 (default %default-polkit))
321 (actions polkit-configuration-actions ;list of file-like
324 (define %default-polkit
325 ;; The default polkit package.
326 (let-system (system target)
327 ;; Since mozjs depends on Rust, which is currently x86_64-only, use
328 ;; polkit-duktape on other systems.
329 (if (string-prefix? "x86_64-" (or target system))
333 (define %polkit-accounts
334 (list (user-group (name "polkitd") (system? #t))
339 (comment "Polkit daemon user")
340 (home-directory "/var/empty")
341 (shell "/run/current-system/profile/sbin/nologin"))))
343 (define %polkit-pam-services
344 (list (unix-pam-service "polkit-1")))
346 (define (polkit-directory packages)
347 "Return a directory containing an @file{actions} and possibly a
348 @file{rules.d} sub-directory, for use as @file{/etc/polkit-1}."
349 (with-imported-modules '((guix build union))
350 (computed-file "etc-polkit-1"
352 (use-modules (guix build union) (srfi srfi-26))
354 (union-build #$output
355 (map (cut string-append <>
357 (list #$@packages)))))))
359 (define polkit-etc-files
361 (($ <polkit-configuration> polkit packages)
362 `(("polkit-1" ,(polkit-directory (cons polkit packages)))))))
364 (define polkit-setuid-programs
366 (($ <polkit-configuration> polkit)
367 (map file-like->setuid-program
368 (list (file-append polkit "/lib/polkit-1/polkit-agent-helper-1")
369 (file-append polkit "/bin/pkexec"))))))
371 (define polkit-service-type
372 (service-type (name 'polkit)
374 (list (service-extension account-service-type
375 (const %polkit-accounts))
376 (service-extension pam-root-service-type
377 (const %polkit-pam-services))
378 (service-extension dbus-root-service-type
381 polkit-configuration-polkit))
382 (service-extension etc-service-type
384 (service-extension setuid-program-service-type
385 polkit-setuid-programs)))
387 ;; Extensions are lists of packages that provide polkit rules
388 ;; or actions under share/polkit-1/{actions,rules.d}.
389 (compose concatenate)
390 (extend (lambda (config actions)
391 (polkit-configuration
394 (append (polkit-configuration-actions config)
397 (default-value (polkit-configuration))
400 @uref{http://www.freedesktop.org/wiki/Software/polkit/, Polkit privilege
401 management service}, which allows system administrators to grant access to
402 privileged operations in a structured way. Polkit is a requirement for most
403 desktop environments, such as GNOME.")))
405 (define* (polkit-service #:key (polkit polkit))
406 "Return a service that runs the
407 @uref{http://www.freedesktop.org/wiki/Software/polkit/, Polkit privilege
408 management service}, which allows system administrators to grant access to
409 privileged operations in a structured way. By querying the Polkit service, a
410 privileged system component can know when it should grant additional
411 capabilities to ordinary users. For example, an ordinary user can be granted
412 the capability to suspend the system if the user is logged in locally."
413 (service polkit-service-type
414 (polkit-configuration (polkit polkit))))
416 ;;; dbus.scm ends here