diff --git a/src/config.rs b/src/config.rs index 62e98e2..7b4c0c2 100644 --- a/src/config.rs +++ b/src/config.rs @@ -71,7 +71,7 @@ pub struct BusConfig { pub syslog: bool, /// This element only controls which message bus specific environment variables are set in activated clients. - pub r#type: Option, + pub r#type: Option, /// The user account the daemon should run as, as either a username or a UID. /// If the daemon cannot change to this UID on startup, it will exit. @@ -139,7 +139,7 @@ impl TryFrom for BusConfig { impl BusConfig { pub fn limits(&self) -> Limits { match self.r#type { - Some(Type::Session) => Limits { + Some(BusType::Session) => Limits { /* For the session bus, override the default relatively-low limits with essentially infinite limits, since the bus is just running as the user anyway, using up bus resources is not something we need @@ -169,7 +169,7 @@ impl BusConfig { max_replies_per_connection: 50000, ..Default::default() }, - Some(Type::System) => Limits { + Some(BusType::System) => Limits { max_incoming_bytes: 133169152, max_incoming_unix_fds: 64, max_outgoing_bytes: 133169152, @@ -236,6 +236,17 @@ impl BusConfig { } } +#[derive(Clone, Debug, Deserialize, PartialEq)] +#[serde(rename_all = "lowercase")] +pub enum BusType { + /// The DBUS_STARTER_BUS_TYPE environment variable will be set to "session", + /// and the DBUS_SESSION_BUS_ADDRESS environment variable will be set to the address of the session bus. + Session, + /// The DBUS_STARTER_BUS_TYPE environment variable will be set to "system", + /// and the DBUS_SYSTEM_BUS_ADDRESS environment variable will be set to the address of the system bus. + System, +} + #[derive(Clone, Debug, Default, Deserialize, PartialEq)] struct Document { #[serde(rename = "$value", default)] @@ -305,11 +316,27 @@ pub struct Limits { pub reply_timeout: Duration, } +#[derive(Clone, Debug, Default, Deserialize, PartialEq)] +#[serde(rename_all = "snake_case")] +pub enum MessageType { + #[default] + #[serde(rename = "*")] + Any, + MethodCall, + MethodReturn, + Signal, + Error, +} + #[derive(Clone, Debug, PartialEq)] pub enum Operation { + /// rules checked when a new connection to the message bus is established Connect, + /// rules checked when a connection attempts to own a well-known bus names Own, + /// rules that are checked for each recipient of a message Receive(ReceiveOperation), + /// rules that are checked when a connection attempts to send a message Send(SendOperation), } type OptionalOperation = Option; @@ -319,7 +346,15 @@ impl TryFrom for OptionalOperation { fn try_from(value: RuleAttributes) -> std::result::Result { let has_connect = false; let has_own = value.own.is_some(); - let has_send = value.send_destination.is_some(); + let has_send = value.send_broadcast.is_some() + || value.send_destination.is_some() + || value.send_destination_prefix.is_some() + || value.send_error.is_some() + || value.send_interface.is_some() + || value.send_member.is_some() + || value.send_path.is_some() + || value.send_requested_reply.is_some() + || value.send_type.is_some(); let has_receive = value.receive_sender.is_some(); let operations_count: i8 = vec![has_connect, has_own, has_receive, has_send] @@ -331,6 +366,12 @@ impl TryFrom for OptionalOperation { return Err(Error::msg(format!("do not mix rule attributes for connect, own, receive, and/or send operations in the same rule: {value:?}"))); } + if value.send_member.is_some() { + eprintln!( + "warning: busd does not implement `<(allow|deny) send_member=...`: {value:?}" + ); + } + if has_connect { Ok(Some(Operation::Connect)) } else if has_own { @@ -338,11 +379,10 @@ impl TryFrom for OptionalOperation { } else if has_receive { Ok(Some(Operation::Receive(ReceiveOperation { sender: value.receive_sender.unwrap_or(String::from("*")), + ..Default::default() }))) } else if has_send { - Ok(Some(Operation::Send(SendOperation { - destination: value.send_destination.unwrap_or(String::from("*")), - }))) + Ok(Some(Operation::Send(SendOperation::from(value)))) } else { Err(Error::msg(format!("rule must specify supported attributes for connect, own, receive, or send operations: {value:?}"))) } @@ -436,9 +476,20 @@ struct PolicyElement { user: Option, } -#[derive(Clone, Debug, Default, PartialEq)] +#[derive(Clone, Debug, PartialEq)] pub struct ReceiveOperation { pub sender: String, + pub max_fds: u32, + pub min_fds: u32, +} +impl Default for ReceiveOperation { + fn default() -> Self { + Self { + sender: String::default(), + max_fds: u32::MAX, + min_fds: 0, + } + } } type OptionalRule = Option; @@ -451,11 +502,19 @@ impl TryFrom for OptionalRule { eavesdrop: Some(true), group: None, own: None, - receive_sender: None, receive_requested_reply: None, + receive_sender: None, + send_broadcast: None, send_destination: None, + send_destination_prefix: None, + send_error: None, + send_interface: None, + send_member: None, + send_path: None, send_requested_reply: None, + send_type: None, user: None, + .. }) => { // see: https://github.com/dbus2/busd/pull/146#issuecomment-2408429760 eprintln!( @@ -540,20 +599,42 @@ pub type Rule = (Access, Operation); #[derive(Clone, Debug, Default, Deserialize, PartialEq)] struct RuleAttributes { + /// deprecated and ignored #[serde(rename = "@eavesdrop")] eavesdrop: Option, #[serde(rename = "@group")] group: Option, + #[serde(rename = "@max_fds")] + max_fds: Option, + #[serde(rename = "@min_fds")] + min_fds: Option, #[serde(rename = "@own")] own: Option, #[serde(rename = "@receive_sender")] receive_sender: Option, + /// deprecated and ignored #[serde(rename = "@receive_requested_reply")] receive_requested_reply: Option, + #[serde(rename = "@send_broadcast")] + send_broadcast: Option, #[serde(rename = "@send_destination")] send_destination: Option, + #[serde(rename = "@send_destination_prefix")] + send_destination_prefix: Option, + #[serde(rename = "@send_error")] + send_error: Option, + #[serde(rename = "@send_interface")] + send_interface: Option, + /// deprecated and ignored: https://github.com/dbus2/busd/issues/79 + #[serde(rename = "@send_member")] + send_member: Option, + #[serde(rename = "@send_path")] + send_path: Option, + /// deprecated and ignored #[serde(rename = "@send_requested_reply")] send_requested_reply: Option, + #[serde(rename = "@send_type")] + send_type: Option, #[serde(rename = "@user")] user: Option, } @@ -565,26 +646,53 @@ enum RuleElement { Deny(RuleAttributes), } -#[derive(Clone, Debug, Default, PartialEq)] +#[derive(Clone, Debug, PartialEq)] pub struct SendOperation { + pub broadcast: Option, pub destination: String, + pub destination_prefix: String, + pub error: String, + pub interface: String, + pub max_fds: u32, + pub min_fds: u32, + pub path: String, + pub r#type: MessageType, } - -#[derive(Clone, Debug, Deserialize, PartialEq)] -#[serde(rename_all = "lowercase")] -pub enum Type { - /// The DBUS_STARTER_BUS_TYPE environment variable will be set to "session", - /// and the DBUS_SESSION_BUS_ADDRESS environment variable will be set to the address of the session bus. - Session, - /// The DBUS_STARTER_BUS_TYPE environment variable will be set to "system", - /// and the DBUS_SYSTEM_BUS_ADDRESS environment variable will be set to the address of the system bus. - System, +impl Default for SendOperation { + fn default() -> Self { + Self { + broadcast: None, + destination: String::from("*"), + destination_prefix: String::default(), + error: String::from("*"), + interface: String::from("*"), + max_fds: u32::MAX, + min_fds: 0, + path: String::from("*"), + r#type: MessageType::default(), + } + } +} +impl From for SendOperation { + fn from(value: RuleAttributes) -> Self { + Self { + broadcast: value.send_broadcast, + destination: value.send_destination.unwrap_or(String::from("*")), + destination_prefix: value.send_destination_prefix.unwrap_or_default(), + error: value.send_error.unwrap_or(String::from("*")), + interface: value.send_interface.unwrap_or(String::from("*")), + max_fds: value.max_fds.unwrap_or(u32::MAX), + min_fds: value.min_fds.unwrap_or(0), + path: value.send_path.unwrap_or(String::from("*")), + r#type: value.send_type.unwrap_or_default(), + } + } } #[derive(Clone, Debug, Deserialize, PartialEq)] struct TypeElement { #[serde(rename = "$text")] - r#type: Type, + r#type: BusType, } #[cfg(test)] @@ -750,10 +858,20 @@ mod tests { - + - + @@ -773,7 +891,15 @@ mod tests { vec![( Access::Allow, Operation::Send(SendOperation { - destination: String::from("org.freedesktop.DBus") + broadcast: Some(true), + destination: String::from("org.freedesktop.DBus"), + destination_prefix: String::from("org.freedesktop"), + error: String::from("something bad"), + interface: String::from("org.freedesktop.systemd1.Activator"), + max_fds: 128, + min_fds: 12, + path: String::from("/org/freedesktop"), + r#type: MessageType::Signal }) ),], String::from("root") @@ -783,13 +909,16 @@ mod tests { ( Access::Allow, Operation::Send(SendOperation { - destination: String::from("org.freedesktop.Avahi") + destination: String::from("org.freedesktop.Avahi"), + ..Default::default() }) ), + // ` + @@ -838,7 +971,8 @@ mod tests { Access::Allow, // `eavesdrop="true"` is dropped, keep other attributes Operation::Send(SendOperation { - destination: String::from("*") + destination: String::from("*"), + ..Default::default() }) ), // `` has nothing left after dropping eavesdrop @@ -847,6 +981,15 @@ mod tests { // `` is completely ignored ], @@ -981,7 +1124,7 @@ mod tests { assert_eq!( busconfig, BusConfig { - r#type: Some(Type::System), + r#type: Some(BusType::System), ..Default::default() } );