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 <rzvncj@gmail.com>
  • Loading branch information
rzvncj committed Dec 17, 2024
1 parent e60691b commit a43ca7e
Show file tree
Hide file tree
Showing 5 changed files with 154 additions and 87 deletions.
16 changes: 11 additions & 5 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 Down Expand Up @@ -72,7 +78,7 @@ impl Properties {
.instance
.read()
.await
.set(property_name, &value, &emitter)
.set(property_name, &value, &emitter, &header)
{
zbus::object_server::DispatchResult::RequiresMut => {}
zbus::object_server::DispatchResult::NotFound => {
Expand All @@ -88,7 +94,7 @@ impl Properties {
.instance
.write()
.await
.set_mut(property_name, &value, &emitter)
.set_mut(property_name, &value, &emitter, &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
28 changes: 23 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,23 @@ 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 used by the current process,
/// where we just query the value for administrative purposes. Since in that case there are no
/// "real" callers, it doesn't make sense to think of this parameter being relevant.
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 +76,9 @@ pub trait Interface: Any + Send + Sync {
property_name: &'call str,
value: &'call Value<'_>,
emitter: &'call SignalEmitter<'_>,
header: &'call message::Header<'_>,
) -> DispatchResult<'call> {
let _ = (property_name, value, emitter);
let _ = (property_name, value, emitter, header);
DispatchResult::RequiresMut
}

Expand All @@ -75,6 +92,7 @@ pub trait Interface: Any + Send + Sync {
property_name: &str,
value: &Value<'_>,
emitter: &SignalEmitter<'_>,
header: &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 a43ca7e

Please sign in to comment.