1# D-Bus configuration and system bus daemon.
2
3{ config, lib, pkgs, ... }:
4
5let
6
7 cfg = config.services.dbus;
8
9 homeDir = "/run/dbus";
10
11 configDir = pkgs.makeDBusConf {
12 inherit (cfg) apparmor;
13 suidHelper = "${config.security.wrapperDir}/dbus-daemon-launch-helper";
14 serviceDirectories = cfg.packages;
15 };
16
17 inherit (lib) mkOption mkEnableOption mkIf mkMerge types;
18
19in
20
21{
22 options = {
23
24 boot.initrd.systemd.dbus = {
25 enable = mkEnableOption "dbus in stage 1";
26 };
27
28 services.dbus = {
29
30 enable = mkOption {
31 type = types.bool;
32 default = false;
33 internal = true;
34 description = ''
35 Whether to start the D-Bus message bus daemon, which is
36 required by many other system services and applications.
37 '';
38 };
39
40 implementation = mkOption {
41 type = types.enum [ "dbus" "broker" ];
42 default = "dbus";
43 description = ''
44 The implementation to use for the message bus defined by the D-Bus specification.
45 Can be either the classic dbus daemon or dbus-broker, which aims to provide high
46 performance and reliability, while keeping compatibility to the D-Bus
47 reference implementation.
48 '';
49
50 };
51
52 packages = mkOption {
53 type = types.listOf types.path;
54 default = [ ];
55 description = ''
56 Packages whose D-Bus configuration files should be included in
57 the configuration of the D-Bus system-wide or session-wide
58 message bus. Specifically, files in the following directories
59 will be included into their respective DBus configuration paths:
60 {file}`«pkg»/etc/dbus-1/system.d`
61 {file}`«pkg»/share/dbus-1/system.d`
62 {file}`«pkg»/share/dbus-1/system-services`
63 {file}`«pkg»/etc/dbus-1/session.d`
64 {file}`«pkg»/share/dbus-1/session.d`
65 {file}`«pkg»/share/dbus-1/services`
66 '';
67 };
68
69 apparmor = mkOption {
70 type = types.enum [ "enabled" "disabled" "required" ];
71 description = ''
72 AppArmor mode for dbus.
73
74 `enabled` enables mediation when it's
75 supported in the kernel, `disabled`
76 always disables AppArmor even with kernel support, and
77 `required` fails when AppArmor was not found
78 in the kernel.
79 '';
80 default = "disabled";
81 };
82 };
83 };
84
85 config = mkIf cfg.enable (mkMerge [
86 {
87 environment.etc."dbus-1".source = configDir;
88
89 environment.pathsToLink = [
90 "/etc/dbus-1"
91 "/share/dbus-1"
92 ];
93
94 users.users.messagebus = {
95 uid = config.ids.uids.messagebus;
96 description = "D-Bus system message bus daemon user";
97 home = homeDir;
98 homeMode = "0755";
99 group = "messagebus";
100 };
101
102 users.groups.messagebus.gid = config.ids.gids.messagebus;
103
104 # Install dbus for dbus tools even when using dbus-broker
105 environment.systemPackages = [
106 pkgs.dbus
107 ];
108
109 # You still need the dbus reference implementation installed to use dbus-broker
110 systemd.packages = [
111 pkgs.dbus
112 ];
113
114 services.dbus.packages = [
115 pkgs.dbus
116 config.system.path
117 ];
118
119 systemd.user.sockets.dbus.wantedBy = [
120 "sockets.target"
121 ];
122 }
123
124 (mkIf config.boot.initrd.systemd.dbus.enable {
125 boot.initrd.systemd = {
126 users.messagebus = { };
127 groups.messagebus = { };
128 contents."/etc/dbus-1".source = pkgs.makeDBusConf {
129 inherit (cfg) apparmor;
130 suidHelper = "/bin/false";
131 serviceDirectories = [ pkgs.dbus ];
132 };
133 packages = [ pkgs.dbus ];
134 storePaths = [ "${pkgs.dbus}/bin/dbus-daemon" ];
135 targets.sockets.wants = [ "dbus.socket" ];
136 };
137 })
138
139 (mkIf (cfg.implementation == "dbus") {
140 security.wrappers.dbus-daemon-launch-helper = {
141 source = "${pkgs.dbus}/libexec/dbus-daemon-launch-helper";
142 owner = "root";
143 group = "messagebus";
144 setuid = true;
145 setgid = false;
146 permissions = "u+rx,g+rx,o-rx";
147 };
148
149 systemd.services.dbus = {
150 aliases = [
151 # hack aiding to prevent dbus from restarting when switching from dbus-broker back to dbus
152 "dbus-broker.service"
153 ];
154 # Don't restart dbus-daemon. Bad things tend to happen if we do.
155 reloadIfChanged = true;
156 restartTriggers = [
157 configDir
158 ];
159 environment = {
160 LD_LIBRARY_PATH = config.system.nssModules.path;
161 };
162 };
163
164 systemd.user.services.dbus = {
165 aliases = [
166 # hack aiding to prevent dbus from restarting when switching from dbus-broker back to dbus
167 "dbus-broker.service"
168 ];
169 # Don't restart dbus-daemon. Bad things tend to happen if we do.
170 reloadIfChanged = true;
171 restartTriggers = [
172 configDir
173 ];
174 };
175
176 })
177
178 (mkIf (cfg.implementation == "broker") {
179 environment.systemPackages = [
180 pkgs.dbus-broker
181 ];
182
183 systemd.packages = [
184 pkgs.dbus-broker
185 ];
186
187 # Just to be sure we don't restart through the unit alias
188 systemd.services.dbus.reloadIfChanged = true;
189 systemd.user.services.dbus.reloadIfChanged = true;
190
191 # NixOS Systemd Module doesn't respect 'Install'
192 # https://github.com/NixOS/nixpkgs/issues/108643
193 systemd.services.dbus-broker = {
194 aliases = [
195 # allow other services to just depend on dbus,
196 # but also a hack aiding to prevent dbus from restarting when switching from dbus-broker back to dbus
197 "dbus.service"
198 ];
199 unitConfig = {
200 # We get errors when reloading the dbus-broker service
201 # if /tmp got remounted after this service started
202 RequiresMountsFor = [ "/tmp" ];
203 };
204 # Don't restart dbus. Bad things tend to happen if we do.
205 reloadIfChanged = true;
206 restartTriggers = [
207 configDir
208 ];
209 environment = {
210 LD_LIBRARY_PATH = config.system.nssModules.path;
211 };
212 };
213
214 systemd.user.services.dbus-broker = {
215 aliases = [
216 # allow other services to just depend on dbus,
217 # but also a hack aiding to prevent dbus from restarting when switching from dbus-broker back to dbus
218 "dbus.service"
219 ];
220 # Don't restart dbus. Bad things tend to happen if we do.
221 reloadIfChanged = true;
222 restartTriggers = [
223 configDir
224 ];
225 };
226 })
227
228 ]);
229}