1 ;;; GNU Guix --- Functional package management for GNU
2 ;;; Copyright © 2013, 2014, 2015, 2016, 2017, 2019 Ludovic Courtès <ludo@gnu.org>
3 ;;; Copyright © 2015 Sou Bunnbu <iyzsong@gmail.com>
5 ;;; This file is part of GNU Guix.
7 ;;; GNU Guix is free software; you can redistribute it and/or modify it
8 ;;; under the terms of the GNU General Public License as published by
9 ;;; the Free Software Foundation; either version 3 of the License, or (at
10 ;;; your option) any later version.
12 ;;; GNU Guix is distributed in the hope that it will be useful, but
13 ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
14 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 ;;; GNU General Public License for more details.
17 ;;; You should have received a copy of the GNU General Public License
18 ;;; 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 (srfi srfi-1)
32 #:use-module (ice-9 match)
33 #:export (dbus-configuration
35 dbus-root-service-type
46 (define-record-type* <dbus-configuration>
47 dbus-configuration make-dbus-configuration
49 (dbus dbus-configuration-dbus ;<package>
51 (services dbus-configuration-services ;list of <package>
54 (define (system-service-directory services)
55 "Return the system service directory, containing @code{.service} files for
56 all the services that may be activated by the daemon."
57 (computed-file "dbus-system-services"
58 (with-imported-modules '((guix build utils))
60 (use-modules (guix build utils)
64 (append-map (lambda (service)
73 (for-each (lambda (file)
75 (string-append #$output "/"
80 (define (dbus-configuration-directory services)
81 "Return a directory contains the @code{system-local.conf} file for DBUS that
82 includes the @code{etc/dbus-1/system.d} directories of each package listed in
86 (use-modules (sxml simple)
89 (define-syntax directives
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)
97 ,@(directives rest ...))
98 (directives rest ...))))
102 (define (services->sxml services)
103 ;; Return the SXML 'includedir' clauses for DIRS.
105 (servicehelper "/run/setuid-programs/dbus-daemon-launch-helper")
107 ;; First, the '.service' files of services subject to activation.
108 ;; We use a fixed location under /etc because the setuid helper
109 ;; looks for them in that location and nowhere else. See
110 ;; <https://bugs.freedesktop.org/show_bug.cgi?id=92458>.
111 (servicedir "/etc/dbus-1/system-services")
113 ,@(append-map (lambda (dir)
116 (string-append dir "/etc/dbus-1/system.d"))
118 (string-append dir "/share/dbus-1/system.d"))
119 (servicedir ;for '.service' files
120 (string-append dir "/share/dbus-1/services"))))
125 ;; Provide /etc/dbus-1/system-services, which is where the setuid
126 ;; helper looks for system service files.
127 (symlink #$(system-service-directory services)
128 (string-append #$output "/system-services"))
130 ;; 'system-local.conf' is automatically included by the default
131 ;; 'system.conf', so this is where we stuff our own things.
132 (call-with-output-file (string-append #$output "/system-local.conf")
134 (sxml->xml (services->sxml (list #$@services))
137 (computed-file "dbus-configuration" build))
139 (define (dbus-etc-files config)
140 "Return a list of FILES for @var{etc-service-type} to build the
141 @code{/etc/dbus-1} directory."
142 (list `("dbus-1" ,(dbus-configuration-directory
143 (dbus-configuration-services config)))))
145 (define %dbus-accounts
146 ;; Accounts used by the system bus.
147 (list (user-group (name "messagebus") (system? #t))
152 (comment "D-Bus system bus user")
153 (home-directory "/var/run/dbus")
154 (shell (file-append shadow "/sbin/nologin")))))
156 (define dbus-setuid-programs
157 ;; Return the file name of the setuid program that we need.
159 (($ <dbus-configuration> dbus services)
160 (list (file-append dbus "/libexec/dbus-daemon-launch-helper")))))
162 (define (dbus-activation config)
163 "Return an activation gexp for D-Bus using @var{config}."
165 (use-modules (guix build utils))
167 (mkdir-p "/var/run/dbus")
169 (let ((user (getpwnam "messagebus")))
170 (chown "/var/run/dbus"
171 (passwd:uid user) (passwd:gid user))
173 ;; This directory contains the daemon's socket so it must be
175 (chmod "/var/run/dbus" #o755))
177 (unless (file-exists? "/etc/machine-id")
178 (format #t "creating /etc/machine-id...~%")
179 (let ((prog (string-append #$(dbus-configuration-dbus config)
180 "/bin/dbus-uuidgen")))
181 ;; XXX: We can't use 'system' because the initrd's
182 ;; guile system(3) only works when 'sh' is in $PATH.
183 (let ((pid (primitive-fork)))
185 (call-with-output-file "/etc/machine-id"
188 (dup2 (port->fdes port) 1)
192 (define dbus-shepherd-service
194 (($ <dbus-configuration> dbus)
195 (list (shepherd-service
196 (documentation "Run the D-Bus system daemon.")
197 (provision '(dbus-system))
198 (requirement '(user-processes))
199 (start #~(make-forkexec-constructor
200 (list (string-append #$dbus "/bin/dbus-daemon")
201 "--nofork" "--system")
202 #:pid-file "/var/run/dbus/pid"))
203 (stop #~(make-kill-destructor)))))))
205 (define dbus-root-service-type
206 (service-type (name 'dbus)
208 (list (service-extension shepherd-root-service-type
209 dbus-shepherd-service)
210 (service-extension activation-service-type
212 (service-extension etc-service-type
214 (service-extension account-service-type
215 (const %dbus-accounts))
216 (service-extension setuid-program-service-type
217 dbus-setuid-programs)))
219 ;; Extensions consist of lists of packages (representing D-Bus
220 ;; services) that we just concatenate.
221 (compose concatenate)
223 ;; The service's parameters field is extended by augmenting
224 ;; its <dbus-configuration> 'services' field.
225 (extend (lambda (config services)
229 (append (dbus-configuration-services config)
232 (default-value (dbus-configuration))))
234 (define* (dbus-service #:key (dbus dbus) (services '()))
235 "Return a service that runs the \"system bus\", using @var{dbus}, with
236 support for @var{services}.
238 @uref{http://dbus.freedesktop.org/, D-Bus} is an inter-process communication
239 facility. Its system bus is used to allow system services to communicate and
240 be notified of system-wide events.
242 @var{services} must be a list of packages that provide an
243 @file{etc/dbus-1/system.d} directory containing additional D-Bus configuration
244 and policy files. For example, to allow avahi-daemon to use the system bus,
245 @var{services} must be equal to @code{(list avahi)}."
246 (service dbus-root-service-type
247 (dbus-configuration (dbus dbus)
248 (services services))))
250 (define (wrapped-dbus-service service program variables)
251 "Return a wrapper for @var{service}, a package containing a D-Bus service,
252 where @var{program} is wrapped such that @var{variables}, a list of name/value
253 tuples, are all set as environment variables when the bus daemon launches it."
255 (program-file (string-append (package-name service) "-program-wrapper")
257 (use-modules (ice-9 match))
259 (for-each (match-lambda
261 (setenv variable value)))
264 (apply execl (string-append #$service "/" #$program)
265 (string-append #$service "/" #$program)
266 (cdr (command-line))))))
269 (with-imported-modules '((guix build utils))
271 (use-modules (guix build utils))
273 (define service-directory
274 "/share/dbus-1/system-services")
276 (mkdir-p (dirname (string-append #$output
278 (copy-recursively (string-append #$service
280 (string-append #$output
282 (symlink (string-append #$service "/etc") ;for etc/dbus-1
283 (string-append #$output "/etc"))
285 (for-each (lambda (file)
287 (("Exec[[:blank:]]*=[[:blank:]]*([[:graph:]]+)(.*)$"
288 _ original-program arguments)
289 (string-append "Exec=" #$wrapper arguments
291 (find-files #$output "\\.service$")))))
293 (computed-file (string-append (package-name service) "-wrapper")
298 ;;; Polkit privilege management service.
301 (define-record-type* <polkit-configuration>
302 polkit-configuration make-polkit-configuration
303 polkit-configuration?
304 (polkit polkit-configuration-polkit ;<package>
306 (actions polkit-configuration-actions ;list of <package>
309 (define %polkit-accounts
310 (list (user-group (name "polkitd") (system? #t))
315 (comment "Polkit daemon user")
316 (home-directory "/var/empty")
317 (shell "/run/current-system/profile/sbin/nologin"))))
319 (define %polkit-pam-services
320 (list (unix-pam-service "polkit-1")))
322 (define (polkit-directory packages)
323 "Return a directory containing an @file{actions} and possibly a
324 @file{rules.d} sub-directory, for use as @file{/etc/polkit-1}."
325 (with-imported-modules '((guix build union))
326 (computed-file "etc-polkit-1"
328 (use-modules (guix build union) (srfi srfi-26))
330 (union-build #$output
331 (map (cut string-append <>
333 (list #$@packages)))))))
335 (define polkit-etc-files
337 (($ <polkit-configuration> polkit packages)
338 `(("polkit-1" ,(polkit-directory (cons polkit packages)))))))
340 (define polkit-setuid-programs
342 (($ <polkit-configuration> polkit)
343 (list (file-append polkit "/lib/polkit-1/polkit-agent-helper-1")
344 (file-append polkit "/bin/pkexec")))))
346 (define polkit-service-type
347 (service-type (name 'polkit)
349 (list (service-extension account-service-type
350 (const %polkit-accounts))
351 (service-extension pam-root-service-type
352 (const %polkit-pam-services))
353 (service-extension dbus-root-service-type
356 polkit-configuration-polkit))
357 (service-extension etc-service-type
359 (service-extension setuid-program-service-type
360 polkit-setuid-programs)))
362 ;; Extensions are lists of packages that provide polkit rules
363 ;; or actions under share/polkit-1/{actions,rules.d}.
364 (compose concatenate)
365 (extend (lambda (config actions)
366 (polkit-configuration
369 (append (polkit-configuration-actions config)
372 (default-value (polkit-configuration))))
374 (define* (polkit-service #:key (polkit polkit))
375 "Return a service that runs the
376 @uref{http://www.freedesktop.org/wiki/Software/polkit/, Polkit privilege
377 management service}, which allows system administrators to grant access to
378 privileged operations in a structured way. By querying the Polkit service, a
379 privileged system component can know when it should grant additional
380 capabilities to ordinary users. For example, an ordinary user can be granted
381 the capability to suspend the system if the user is logged in locally."
382 (service polkit-service-type
383 (polkit-configuration (polkit polkit))))
385 ;;; dbus.scm ends here