Skip to content

Commit

Permalink
✨ zb,zm: Support Option<Header<'_>> parameter in property getters
Browse files Browse the repository at this point in the history
This allows for fine-grained connecting-UID checking, in order to
be able to control who is able to access property values.

Signed-off-by: Razvan Cojocaru <[email protected]>
  • Loading branch information
rzvncj committed Dec 17, 2024
1 parent e2ec19b commit 082c2f3
Show file tree
Hide file tree
Showing 6 changed files with 163 additions and 93 deletions.
26 changes: 16 additions & 10 deletions zbus/src/fdo/properties.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use zbus_names::InterfaceName;
use zvariant::{OwnedValue, Value};

use super::{Error, Result};
use crate::{interface, message::Header, object_server::SignalEmitter, ObjectServer};
use crate::{interface, message::Header, object_server::SignalEmitter, Connection, ObjectServer};

/// Service-side implementation for the `org.freedesktop.DBus.Properties` interface.
/// This interface is implemented automatically for any object registered to the
Expand All @@ -29,6 +29,7 @@ impl Properties {
&self,
interface_name: InterfaceName<'_>,
property_name: &str,
#[zbus(connection)] conn: &Connection,
#[zbus(object_server)] server: &ObjectServer,
#[zbus(header)] header: Header<'_>,
) -> Result<OwnedValue> {
Expand All @@ -41,7 +42,12 @@ impl Properties {
Error::UnknownInterface(format!("Unknown interface '{interface_name}'"))
})?;

let res = iface.instance.read().await.get(property_name).await;
let res = iface
.instance
.read()
.await
.get(property_name, server, conn, &Some(header))
.await;
res.unwrap_or_else(|| {
Err(Error::UnknownProperty(format!(
"Unknown property '{property_name}'"
Expand All @@ -68,12 +74,12 @@ impl Properties {
Error::UnknownInterface(format!("Unknown interface '{interface_name}'"))
})?;

match iface
.instance
.read()
.await
.set(property_name, &value, &emitter)
{
match iface.instance.read().await.set(
property_name,
&value,
&emitter,
&Some(header.clone()),
) {
zbus::object_server::DispatchResult::RequiresMut => {}
zbus::object_server::DispatchResult::NotFound => {
return Err(Error::UnknownProperty(format!(
Expand All @@ -88,7 +94,7 @@ impl Properties {
.instance
.write()
.await
.set_mut(property_name, &value, &emitter)
.set_mut(property_name, &value, &emitter, &Some(header))
.await;
res.unwrap_or_else(|| {
Err(Error::UnknownProperty(format!(
Expand All @@ -113,7 +119,7 @@ impl Properties {
Error::UnknownInterface(format!("Unknown interface '{interface_name}'"))
})?;

let res = iface.instance.read().await.get_all().await?;
let res = iface.instance.read().await.get_all(&Some(header)).await?;
Ok(res)
}

Expand Down
29 changes: 24 additions & 5 deletions zbus/src/object_server/interface/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@ use zbus_names::{InterfaceName, MemberName};
use zvariant::{OwnedValue, Value};

use crate::{
async_lock::RwLock, fdo, message::Message, object_server::SignalEmitter, Connection,
ObjectServer,
async_lock::RwLock,
fdo,
message::{self, Header, Message},
object_server::SignalEmitter,
Connection, ObjectServer,
};

/// This trait is used to dispatch messages to an interface instance.
Expand All @@ -45,10 +48,24 @@ pub trait Interface: Any + Send + Sync {
}

/// Get a property value. Returns `None` if the property doesn't exist.
async fn get(&self, property_name: &str) -> Option<fdo::Result<OwnedValue>>;
///
/// Note: The header parameter will be None when the getter is not being called as part
/// of D-Bus communication (for example, when it is called as part of initial object setup,
/// before it is registered on the bus, or when we manually send out property changed
/// notifications).
async fn get(
&self,
property_name: &str,
server: &ObjectServer,
connection: &Connection,
header: &Option<message::Header<'_>>,
) -> Option<fdo::Result<OwnedValue>>;

/// Return all the properties.
async fn get_all(&self) -> fdo::Result<HashMap<String, OwnedValue>>;
async fn get_all(
&self,
header: &Option<message::Header<'_>>,
) -> fdo::Result<HashMap<String, OwnedValue>>;

/// Set a property value.
///
Expand All @@ -60,8 +77,9 @@ pub trait Interface: Any + Send + Sync {
property_name: &'call str,
value: &'call Value<'_>,
emitter: &'call SignalEmitter<'_>,
header: &'call Option<message::Header<'_>>,
) -> DispatchResult<'call> {
let _ = (property_name, value, emitter);
let _ = (property_name, value, emitter, header);
DispatchResult::RequiresMut
}

Expand All @@ -75,6 +93,7 @@ pub trait Interface: Any + Send + Sync {
property_name: &str,
value: &Value<'_>,
emitter: &SignalEmitter<'_>,
header: &Option<Header<'_>>,
) -> Option<fdo::Result<()>>;

/// Call a method.
Expand Down
2 changes: 1 addition & 1 deletion zbus/src/object_server/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ impl Node {
.instance
.read()
.await
.get_all()
.get_all(&None)
.await
}
}
8 changes: 8 additions & 0 deletions zbus/tests/e2e.rs
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,13 @@ impl MyIface {
self.count
}

#[instrument]
#[zbus(property)]
fn test_header_prop(&self, #[zbus(header)] header: Option<Header<'_>>) -> bool {
debug!("`TestHeaderProp` getter called: {:?}.", header);
header.is_some()
}

#[instrument]
#[zbus(property)]
async fn hash_map(&self) -> HashMap<String, String> {
Expand Down Expand Up @@ -570,6 +577,7 @@ async fn my_iface_test(conn: Connection, event: Event) -> zbus::Result<u32> {
drop(props_changed_stream);

proxy.ping().await?;
assert_eq!(proxy.test_header_prop().await?, true);
assert_eq!(proxy.count().await?, 1);
assert_eq!(proxy.cached_count()?, None);

Expand Down
Loading

0 comments on commit 082c2f3

Please sign in to comment.