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 (services->sxml services)
90 ;; Return the SXML 'includedir' clauses for DIRS.
92 (servicehelper "/run/setuid-programs/dbus-daemon-launch-helper")
94 ;; First, the '.service' files of services subject to activation.
95 ;; We use a fixed location under /etc because the setuid helper
96 ;; looks for them in that location and nowhere else. See
97 ;; <https://bugs.freedesktop.org/show_bug.cgi?id=92458>.
98 (servicedir "/etc/dbus-1/system-services")
100 ,@(append-map (lambda (dir)
102 ,(string-append dir "/etc/dbus-1/system.d"))
103 (servicedir ;for '.service' files
104 ,(string-append dir "/share/dbus-1/services"))))
109 ;; Provide /etc/dbus-1/system-services, which is where the setuid
110 ;; helper looks for system service files.
111 (symlink #$(system-service-directory services)
112 (string-append #$output "/system-services"))
114 ;; 'system-local.conf' is automatically included by the default
115 ;; 'system.conf', so this is where we stuff our own things.
116 (call-with-output-file (string-append #$output "/system-local.conf")
118 (sxml->xml (services->sxml (list #$@services))
121 (computed-file "dbus-configuration" build))
123 (define (dbus-etc-files config)
124 "Return a list of FILES for @var{etc-service-type} to build the
125 @code{/etc/dbus-1} directory."
126 (list `("dbus-1" ,(dbus-configuration-directory
127 (dbus-configuration-services config)))))
129 (define %dbus-accounts
130 ;; Accounts used by the system bus.
131 (list (user-group (name "messagebus") (system? #t))
136 (comment "D-Bus system bus user")
137 (home-directory "/var/run/dbus")
138 (shell (file-append shadow "/sbin/nologin")))))
140 (define dbus-setuid-programs
141 ;; Return the file name of the setuid program that we need.
143 (($ <dbus-configuration> dbus services)
144 (list (file-append dbus "/libexec/dbus-daemon-launch-helper")))))
146 (define (dbus-activation config)
147 "Return an activation gexp for D-Bus using @var{config}."
149 (use-modules (guix build utils))
151 (mkdir-p "/var/run/dbus")
153 (let ((user (getpwnam "messagebus")))
154 (chown "/var/run/dbus"
155 (passwd:uid user) (passwd:gid user))
157 ;; This directory contains the daemon's socket so it must be
159 (chmod "/var/run/dbus" #o755))
161 (unless (file-exists? "/etc/machine-id")
162 (format #t "creating /etc/machine-id...~%")
163 (let ((prog (string-append #$(dbus-configuration-dbus config)
164 "/bin/dbus-uuidgen")))
165 ;; XXX: We can't use 'system' because the initrd's
166 ;; guile system(3) only works when 'sh' is in $PATH.
167 (let ((pid (primitive-fork)))
169 (call-with-output-file "/etc/machine-id"
172 (dup2 (port->fdes port) 1)
176 (define dbus-shepherd-service
178 (($ <dbus-configuration> dbus)
179 (list (shepherd-service
180 (documentation "Run the D-Bus system daemon.")
181 (provision '(dbus-system))
182 (requirement '(user-processes))
183 (start #~(make-forkexec-constructor
184 (list (string-append #$dbus "/bin/dbus-daemon")
185 "--nofork" "--system")
186 #:pid-file "/var/run/dbus/pid"))
187 (stop #~(make-kill-destructor)))))))
189 (define dbus-root-service-type
190 (service-type (name 'dbus)
192 (list (service-extension shepherd-root-service-type
193 dbus-shepherd-service)
194 (service-extension activation-service-type
196 (service-extension etc-service-type
198 (service-extension account-service-type
199 (const %dbus-accounts))
200 (service-extension setuid-program-service-type
201 dbus-setuid-programs)))
203 ;; Extensions consist of lists of packages (representing D-Bus
204 ;; services) that we just concatenate.
205 (compose concatenate)
207 ;; The service's parameters field is extended by augmenting
208 ;; its <dbus-configuration> 'services' field.
209 (extend (lambda (config services)
213 (append (dbus-configuration-services config)
216 (default-value (dbus-configuration))))
218 (define* (dbus-service #:key (dbus dbus) (services '()))
219 "Return a service that runs the \"system bus\", using @var{dbus}, with
220 support for @var{services}.
222 @uref{http://dbus.freedesktop.org/, D-Bus} is an inter-process communication
223 facility. Its system bus is used to allow system services to communicate and
224 be notified of system-wide events.
226 @var{services} must be a list of packages that provide an
227 @file{etc/dbus-1/system.d} directory containing additional D-Bus configuration
228 and policy files. For example, to allow avahi-daemon to use the system bus,
229 @var{services} must be equal to @code{(list avahi)}."
230 (service dbus-root-service-type
231 (dbus-configuration (dbus dbus)
232 (services services))))
234 (define (wrapped-dbus-service service program variables)
235 "Return a wrapper for @var{service}, a package containing a D-Bus service,
236 where @var{program} is wrapped such that @var{variables}, a list of name/value
237 tuples, are all set as environment variables when the bus daemon launches it."
239 (program-file (string-append (package-name service) "-program-wrapper")
241 (use-modules (ice-9 match))
243 (for-each (match-lambda
245 (setenv variable value)))
248 (apply execl (string-append #$service "/" #$program)
249 (string-append #$service "/" #$program)
250 (cdr (command-line))))))
253 (with-imported-modules '((guix build utils))
255 (use-modules (guix build utils))
257 (define service-directory
258 "/share/dbus-1/system-services")
260 (mkdir-p (dirname (string-append #$output
262 (copy-recursively (string-append #$service
264 (string-append #$output
266 (symlink (string-append #$service "/etc") ;for etc/dbus-1
267 (string-append #$output "/etc"))
269 (for-each (lambda (file)
271 (("Exec[[:blank:]]*=[[:blank:]]*([[:graph:]]+)(.*)$"
272 _ original-program arguments)
273 (string-append "Exec=" #$wrapper arguments
275 (find-files #$output "\\.service$")))))
277 (computed-file (string-append (package-name service) "-wrapper")
282 ;;; Polkit privilege management service.
285 (define-record-type* <polkit-configuration>
286 polkit-configuration make-polkit-configuration
287 polkit-configuration?
288 (polkit polkit-configuration-polkit ;<package>
290 (actions polkit-configuration-actions ;list of <package>
293 (define %polkit-accounts
294 (list (user-group (name "polkitd") (system? #t))
299 (comment "Polkit daemon user")
300 (home-directory "/var/empty")
301 (shell "/run/current-system/profile/sbin/nologin"))))
303 (define %polkit-pam-services
304 (list (unix-pam-service "polkit-1")))
306 (define (polkit-directory packages)
307 "Return a directory containing an @file{actions} and possibly a
308 @file{rules.d} sub-directory, for use as @file{/etc/polkit-1}."
309 (with-imported-modules '((guix build union))
310 (computed-file "etc-polkit-1"
312 (use-modules (guix build union) (srfi srfi-26))
314 (union-build #$output
315 (map (cut string-append <>
317 (list #$@packages)))))))
319 (define polkit-etc-files
321 (($ <polkit-configuration> polkit packages)
322 `(("polkit-1" ,(polkit-directory (cons polkit packages)))))))
324 (define polkit-setuid-programs
326 (($ <polkit-configuration> polkit)
327 (list (file-append polkit "/lib/polkit-1/polkit-agent-helper-1")
328 (file-append polkit "/bin/pkexec")))))
330 (define polkit-service-type
331 (service-type (name 'polkit)
333 (list (service-extension account-service-type
334 (const %polkit-accounts))
335 (service-extension pam-root-service-type
336 (const %polkit-pam-services))
337 (service-extension dbus-root-service-type
340 polkit-configuration-polkit))
341 (service-extension etc-service-type
343 (service-extension setuid-program-service-type
344 polkit-setuid-programs)))
346 ;; Extensions are lists of packages that provide polkit rules
347 ;; or actions under share/polkit-1/{actions,rules.d}.
348 (compose concatenate)
349 (extend (lambda (config actions)
350 (polkit-configuration
353 (append (polkit-configuration-actions config)
356 (default-value (polkit-configuration))))
358 (define* (polkit-service #:key (polkit polkit))
359 "Return a service that runs the
360 @uref{http://www.freedesktop.org/wiki/Software/polkit/, Polkit privilege
361 management service}, which allows system administrators to grant access to
362 privileged operations in a structured way. By querying the Polkit service, a
363 privileged system component can know when it should grant additional
364 capabilities to ordinary users. For example, an ordinary user can be granted
365 the capability to suspend the system if the user is logged in locally."
366 (service polkit-service-type
367 (polkit-configuration (polkit polkit))))
369 ;;; dbus.scm ends here