zbus/fdo/dbus.rs
1//! D-Bus standard interfaces.
2//!
3//! The D-Bus specification defines the message bus messages and some standard interfaces that may
4//! be useful across various D-Bus applications. This module provides their proxy.
5
6use enumflags2::{BitFlags, bitflags};
7use serde::{Deserialize, Serialize};
8use serde_repr::{Deserialize_repr, Serialize_repr};
9use std::collections::HashMap;
10use zbus_names::{
11 BusName, OwnedBusName, OwnedInterfaceName, OwnedUniqueName, UniqueName, WellKnownName,
12};
13#[cfg(unix)]
14use zvariant::OwnedFd;
15use zvariant::{DeserializeDict, Optional, SerializeDict, Type};
16
17use super::Result;
18use crate::{OwnedGuid, proxy};
19
20/// The flags used by the [`DBusProxy::request_name`] method.
21///
22/// The default flags (returned by [`BitFlags::default`]) are `AllowReplacement`, `ReplaceExisting`,
23/// and `DoNotQueue`.
24#[bitflags(default = AllowReplacement | ReplaceExisting | DoNotQueue)]
25#[repr(u32)]
26#[derive(Type, Debug, PartialEq, Eq, Copy, Clone, Serialize, Deserialize)]
27pub enum RequestNameFlags {
28 /// If an application A specifies this flag and succeeds in becoming the owner of the name, and
29 /// another application B later calls [`DBusProxy::request_name`] with the `ReplaceExisting`
30 /// flag, then application A will lose ownership and receive a `org.freedesktop.DBus.NameLost`
31 /// signal, and application B will become the new owner. If `AllowReplacement` is not specified
32 /// by application A, or `ReplaceExisting` is not specified by application B, then application
33 /// B will not replace application A as the owner.
34 AllowReplacement = 0x01,
35 /// Try to replace the current owner if there is one. If this flag is not set the application
36 /// will only become the owner of the name if there is no current owner. If this flag is set,
37 /// the application will replace the current owner if the current owner specified
38 /// `AllowReplacement`.
39 ReplaceExisting = 0x02,
40 /// Without this flag, if an application requests a name that is already owned, the
41 /// application will be placed in a queue to own the name when the current owner gives it
42 /// up. If this flag is given, the application will not be placed in the queue; the
43 /// request for the name will simply fail. This flag also affects behavior when an
44 /// application is replaced as name owner; by default the application moves back into the
45 /// waiting queue, unless this flag was provided when the application became the name
46 /// owner.
47 DoNotQueue = 0x04,
48}
49
50/// The return code of the [`DBusProxy::request_name`] method.
51#[repr(u32)]
52#[derive(Deserialize_repr, Serialize_repr, Type, Debug, PartialEq, Eq)]
53pub enum RequestNameReply {
54 /// The caller is now the primary owner of the name, replacing any previous owner. Either the
55 /// name had no owner before, or the caller specified [`RequestNameFlags::ReplaceExisting`] and
56 /// the current owner specified [`RequestNameFlags::AllowReplacement`].
57 PrimaryOwner = 0x01,
58 /// The name already had an owner, [`RequestNameFlags::DoNotQueue`] was not specified, and
59 /// either the current owner did not specify [`RequestNameFlags::AllowReplacement`] or the
60 /// requesting application did not specify [`RequestNameFlags::ReplaceExisting`].
61 InQueue = 0x02,
62 /// The name already had an owner, [`RequestNameFlags::DoNotQueue`] was specified, and either
63 /// [`RequestNameFlags::AllowReplacement`] was not specified by the current owner, or
64 /// [`RequestNameFlags::ReplaceExisting`] was not specified by the requesting application.
65 Exists = 0x03,
66 /// The application trying to request ownership of a name is already the owner of it.
67 AlreadyOwner = 0x04,
68}
69
70impl std::fmt::Display for RequestNameReply {
71 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
72 match self {
73 Self::PrimaryOwner => write!(f, "PrimaryOwner"),
74 Self::InQueue => write!(f, "InQueue"),
75 Self::Exists => write!(f, "Exists"),
76 Self::AlreadyOwner => write!(f, "AlreadyOwner"),
77 }
78 }
79}
80
81/// The return code of the [`DBusProxy::release_name`] method.
82#[repr(u32)]
83#[derive(Deserialize_repr, Serialize_repr, Type, Debug, PartialEq, Eq)]
84pub enum ReleaseNameReply {
85 /// The caller has released their claim on the given name. Either the caller was the primary
86 /// owner of the name, and the name is now unused or taken by somebody waiting in the queue for
87 /// the name, or the caller was waiting in the queue for the name and has now been removed from
88 /// the queue.
89 Released = 0x01,
90 /// The given name does not exist on this bus.
91 NonExistent = 0x02,
92 /// The caller was not the primary owner of this name, and was also not waiting in the queue to
93 /// own this name.
94 NotOwner = 0x03,
95}
96
97impl std::fmt::Display for ReleaseNameReply {
98 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
99 match self {
100 Self::Released => write!(f, "Released"),
101 Self::NonExistent => write!(f, "NonExistent"),
102 Self::NotOwner => write!(f, "NotOwner"),
103 }
104 }
105}
106
107/// The return code of the [`DBusProxy::start_service_by_name`] method.
108///
109/// In zbus 6.0, this will become the return type of `start_service_by_name`.
110/// For now, it's provided separately with a `TryFrom<u32>` implementation
111/// to avoid breaking changes in the API.
112#[repr(u32)]
113#[derive(Deserialize_repr, Serialize_repr, Type, Debug, PartialEq, Eq)]
114pub enum StartServiceReply {
115 /// The service was successfully started.
116 Success = 0x01,
117 /// The service was already running.
118 AlreadyRunning = 0x02,
119}
120
121impl std::fmt::Display for StartServiceReply {
122 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
123 match self {
124 Self::Success => write!(f, "Success"),
125 Self::AlreadyRunning => write!(f, "AlreadyRunning"),
126 }
127 }
128}
129
130// FIXME: When releasing 6.0, use StartServiceReply directly in start_service_by_name instead
131impl TryFrom<u32> for StartServiceReply {
132 type Error = super::Error;
133
134 fn try_from(value: u32) -> Result<Self> {
135 match value {
136 0x01 => Ok(StartServiceReply::Success),
137 0x02 => Ok(StartServiceReply::AlreadyRunning),
138 _ => Err(super::Error::ZBus(crate::Error::InvalidReply)),
139 }
140 }
141}
142
143/// Credentials of a process connected to a bus server.
144///
145/// If unable to determine certain credentials (for instance, because the process is not on the same
146/// machine as the bus daemon, or because this version of the bus daemon does not support a
147/// particular security framework), or if the values of those credentials cannot be represented as
148/// documented here, then those credentials are omitted.
149///
150/// **Note**: unknown keys, in particular those with "." that are not from the specification, will
151/// be ignored. Use your own implementation or contribute your keys here, or in the specification.
152#[derive(Debug, Default, DeserializeDict, PartialEq, Eq, SerializeDict, Type)]
153#[zvariant(signature = "a{sv}")]
154pub struct ConnectionCredentials {
155 #[zvariant(rename = "UnixUserID")]
156 pub(crate) unix_user_id: Option<u32>,
157
158 #[zvariant(rename = "UnixGroupIDs")]
159 pub(crate) unix_group_ids: Option<Vec<u32>>,
160
161 #[cfg(unix)]
162 #[zvariant(rename = "ProcessFD")]
163 pub(crate) process_fd: Option<OwnedFd>,
164
165 #[zvariant(rename = "ProcessID")]
166 pub(crate) process_id: Option<u32>,
167
168 #[zvariant(rename = "WindowsSID")]
169 pub(crate) windows_sid: Option<String>,
170
171 #[zvariant(rename = "LinuxSecurityLabel")]
172 pub(crate) linux_security_label: Option<Vec<u8>>,
173}
174
175impl ConnectionCredentials {
176 /// The numeric Unix user ID, as defined by POSIX.
177 pub fn unix_user_id(&self) -> Option<u32> {
178 self.unix_user_id
179 }
180
181 /// The numeric Unix group IDs (including both the primary group and the supplementary groups),
182 /// as defined by POSIX, in numerically sorted order. This array is either complete or absent:
183 /// if the message bus is able to determine some but not all of the caller's groups, or if one
184 /// of the groups is not representable in a UINT32, it must not add this credential to the
185 /// dictionary.
186 pub fn unix_group_ids(&self) -> Option<&Vec<u32>> {
187 self.unix_group_ids.as_ref()
188 }
189
190 /// Same as [`ConnectionCredentials::unix_group_ids`], but consumes `self` and returns the group
191 /// IDs Vec.
192 pub fn into_unix_group_ids(self) -> Option<Vec<u32>> {
193 self.unix_group_ids
194 }
195
196 /// A file descriptor pinning the process, on platforms that have this concept. On Linux, the
197 /// SO_PEERPIDFD socket option is a suitable implementation. This is safer to use to identify
198 /// a process than the ProcessID, as the latter is subject to re-use attacks, while the FD
199 /// cannot be recycled. If the original process no longer exists the FD will no longer be
200 /// resolvable.
201 #[cfg(unix)]
202 pub fn process_fd(&self) -> Option<&OwnedFd> {
203 self.process_fd.as_ref()
204 }
205
206 /// The numeric process ID, on platforms that have this concept. On Unix, this is the process ID
207 /// defined by POSIX.
208 pub fn process_id(&self) -> Option<u32> {
209 self.process_id
210 }
211
212 /// The Windows security identifier in its string form, e.g.
213 /// `S-1-5-21-3623811015-3361044348-30300820-1013` for a domain or local computer user or
214 /// "S-1-5-18` for the LOCAL_SYSTEM user.
215 pub fn windows_sid(&self) -> Option<&String> {
216 self.windows_sid.as_ref()
217 }
218
219 /// Same as [`ConnectionCredentials::windows_sid`], but consumes `self` and returns the SID
220 /// string.
221 pub fn into_windows_sid(self) -> Option<String> {
222 self.windows_sid
223 }
224
225 /// On Linux systems, the security label that would result from the SO_PEERSEC getsockopt call.
226 /// The array contains the non-zero bytes of the security label in an unspecified
227 /// ASCII-compatible encoding, followed by a single zero byte.
228 ///
229 /// For example, the SELinux context `system_u:system_r:init_t:s0` (a string of length 27) would
230 /// be encoded as 28 bytes ending with `':', 's', '0', '\x00'`
231 ///
232 /// On SELinux systems this is the SELinux context, as output by `ps -Z` or `ls -Z`. Typical
233 /// values might include `system_u:system_r:init_t:s0`,
234 /// `unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023`, or
235 /// `unconfined_u:unconfined_r:chrome_sandbox_t:s0-s0:c0.c1023`.
236 ///
237 /// On Smack systems, this is the Smack label. Typical values might include `_`, `*`, `User`,
238 /// `System` or `System::Shared`.
239 ///
240 /// On AppArmor systems, this is the AppArmor context, a composite string encoding the AppArmor
241 /// label (one or more profiles) and the enforcement mode. Typical values might include
242 /// `unconfined`, `/usr/bin/firefox (enforce)` or `user1 (complain)`.
243 pub fn linux_security_label(&self) -> Option<&Vec<u8>> {
244 self.linux_security_label.as_ref()
245 }
246
247 /// Same as [`ConnectionCredentials::linux_security_label`], but consumes `self` and returns
248 /// the security label bytes.
249 pub fn into_linux_security_label(self) -> Option<Vec<u8>> {
250 self.linux_security_label
251 }
252
253 /// Set the numeric Unix user ID, as defined by POSIX.
254 pub fn set_unix_user_id(mut self, unix_user_id: u32) -> Self {
255 self.unix_user_id = Some(unix_user_id);
256
257 self
258 }
259
260 /// Add a numeric Unix group ID.
261 ///
262 /// See [`ConnectionCredentials::unix_group_ids`] for more information.
263 pub fn add_unix_group_id(mut self, unix_group_id: u32) -> Self {
264 self.unix_group_ids
265 .get_or_insert_with(Vec::new)
266 .push(unix_group_id);
267
268 self
269 }
270
271 /// Set the process FD, on platforms that have this concept
272 #[cfg(unix)]
273 pub fn set_process_fd(mut self, process_fd: OwnedFd) -> Self {
274 self.process_fd = Some(process_fd);
275
276 self
277 }
278
279 /// Set the numeric process ID, on platforms that have this concept.
280 ///
281 /// See [`ConnectionCredentials::process_id`] for more information.
282 pub fn set_process_id(mut self, process_id: u32) -> Self {
283 self.process_id = Some(process_id);
284
285 self
286 }
287
288 /// Set the Windows security identifier in its string form.
289 pub fn set_windows_sid(mut self, windows_sid: String) -> Self {
290 self.windows_sid = Some(windows_sid);
291
292 self
293 }
294
295 /// Set the Linux security label.
296 ///
297 /// See [`ConnectionCredentials::linux_security_label`] for more information.
298 pub fn set_linux_security_label(mut self, linux_security_label: Vec<u8>) -> Self {
299 self.linux_security_label = Some(linux_security_label);
300
301 self
302 }
303}
304
305/// Proxy for the `org.freedesktop.DBus` interface.
306#[proxy(
307 default_service = "org.freedesktop.DBus",
308 default_path = "/org/freedesktop/DBus",
309 interface = "org.freedesktop.DBus"
310)]
311pub trait DBus {
312 /// Adds a match rule to match messages going through the message bus
313 #[zbus(name = "AddMatch")]
314 fn add_match_rule(&self, rule: crate::MatchRule<'_>) -> Result<()>;
315
316 /// Returns auditing data used by Solaris ADT, in an unspecified binary format.
317 fn get_adt_audit_session_data(&self, bus_name: BusName<'_>) -> Result<Vec<u8>>;
318
319 /// Returns as many credentials as possible for the process connected to the server.
320 fn get_connection_credentials(&self, bus_name: BusName<'_>) -> Result<ConnectionCredentials>;
321
322 /// Returns the security context used by SELinux, in an unspecified format.
323 #[zbus(name = "GetConnectionSELinuxSecurityContext")]
324 fn get_connection_selinux_security_context(&self, bus_name: BusName<'_>) -> Result<Vec<u8>>;
325
326 /// Returns the Unix process ID of the process connected to the server.
327 #[zbus(name = "GetConnectionUnixProcessID")]
328 fn get_connection_unix_process_id(&self, bus_name: BusName<'_>) -> Result<u32>;
329
330 /// Returns the Unix user ID of the process connected to the server.
331 fn get_connection_unix_user(&self, bus_name: BusName<'_>) -> Result<u32>;
332
333 /// Gets the unique ID of the bus.
334 fn get_id(&self) -> Result<OwnedGuid>;
335
336 /// Returns the unique connection name of the primary owner of the name given.
337 fn get_name_owner(&self, name: BusName<'_>) -> Result<OwnedUniqueName>;
338
339 /// Returns the unique name assigned to the connection.
340 fn hello(&self) -> Result<OwnedUniqueName>;
341
342 /// Returns a list of all names that can be activated on the bus.
343 fn list_activatable_names(&self) -> Result<Vec<OwnedBusName>>;
344
345 /// Returns a list of all currently-owned names on the bus.
346 fn list_names(&self) -> Result<Vec<OwnedBusName>>;
347
348 /// List the connections currently queued for a bus name.
349 fn list_queued_owners(&self, name: WellKnownName<'_>) -> Result<Vec<OwnedUniqueName>>;
350
351 /// Checks if the specified name exists (currently has an owner).
352 fn name_has_owner(&self, name: BusName<'_>) -> Result<bool>;
353
354 /// Ask the message bus to release the method caller's claim to the given name.
355 fn release_name(&self, name: WellKnownName<'_>) -> Result<ReleaseNameReply>;
356
357 /// Reload server configuration.
358 fn reload_config(&self) -> Result<()>;
359
360 /// Removes the first rule that matches.
361 #[zbus(name = "RemoveMatch")]
362 fn remove_match_rule(&self, rule: crate::MatchRule<'_>) -> Result<()>;
363
364 /// Ask the message bus to assign the given name to the method caller.
365 fn request_name(
366 &self,
367 name: WellKnownName<'_>,
368 flags: BitFlags<RequestNameFlags>,
369 ) -> Result<RequestNameReply>;
370
371 /// Tries to launch the executable associated with a name (service
372 /// activation), as an explicit request.
373 fn start_service_by_name(&self, name: WellKnownName<'_>, flags: u32) -> Result<u32>;
374
375 /// This method adds to or modifies that environment when activating services.
376 fn update_activation_environment(&self, environment: HashMap<&str, &str>) -> Result<()>;
377
378 /// This signal indicates that the owner of a name has
379 /// changed. It's also the signal to use to detect the appearance
380 /// of new names on the bus.
381 #[zbus(signal)]
382 fn name_owner_changed(
383 &self,
384 name: BusName<'_>,
385 old_owner: Optional<UniqueName<'_>>,
386 new_owner: Optional<UniqueName<'_>>,
387 );
388
389 /// This signal is sent to a specific application when it loses ownership of a name.
390 #[zbus(signal)]
391 fn name_lost(&self, name: BusName<'_>);
392
393 /// This signal is sent to a specific application when it gains ownership of a name.
394 #[zbus(signal)]
395 fn name_acquired(&self, name: BusName<'_>);
396
397 /// This property lists abstract “features” provided by the message bus, and can be used by
398 /// clients to detect the capabilities of the message bus with which they are communicating.
399 #[zbus(property)]
400 fn features(&self) -> Result<Vec<String>>;
401
402 /// This property lists interfaces provided by the `/org/freedesktop/DBus` object, and can be
403 /// used by clients to detect the capabilities of the message bus with which they are
404 /// communicating. Unlike the standard Introspectable interface, querying this property does not
405 /// require parsing XML. This property was added in version 1.11.x of the reference
406 /// implementation of the message bus.
407 ///
408 /// The standard `org.freedesktop.DBus` and `org.freedesktop.DBus.Properties` interfaces are not
409 /// included in the value of this property, because their presence can be inferred from the fact
410 /// that a method call on `org.freedesktop.DBus.Properties` asking for properties of
411 /// `org.freedesktop.DBus` was successful. The standard `org.freedesktop.DBus.Peer` and
412 /// `org.freedesktop.DBus.Introspectable` interfaces are not included in the value of this
413 /// property either, because they do not indicate features of the message bus implementation.
414 #[zbus(property)]
415 fn interfaces(&self) -> Result<Vec<OwnedInterfaceName>>;
416}
417
418#[cfg(test)]
419mod test {
420 use super::*;
421
422 #[test]
423 fn request_name_flags_default() {
424 let flags = BitFlags::<RequestNameFlags>::default();
425 assert!(flags.contains(RequestNameFlags::AllowReplacement));
426 assert!(flags.contains(RequestNameFlags::ReplaceExisting));
427 assert!(flags.contains(RequestNameFlags::DoNotQueue));
428 }
429}