Skip to content

Commit

Permalink
🔧 Support <policy><(allow|deny) send_*=...
Browse files Browse the repository at this point in the history
  • Loading branch information
jokeyrhyme committed Nov 14, 2024
1 parent ce0eae5 commit e89212d
Showing 1 changed file with 172 additions and 29 deletions.
201 changes: 172 additions & 29 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Type>,
pub r#type: Option<BusType>,

/// 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.
Expand Down Expand Up @@ -139,7 +139,7 @@ impl TryFrom<Document> 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
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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)]
Expand Down Expand Up @@ -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<Operation>;
Expand All @@ -319,7 +346,15 @@ impl TryFrom<RuleAttributes> for OptionalOperation {
fn try_from(value: RuleAttributes) -> std::result::Result<Self, Self::Error> {
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]
Expand All @@ -331,18 +366,23 @@ impl TryFrom<RuleAttributes> 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 {
Ok(Some(Operation::Own))
} 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:?}")))
}
Expand Down Expand Up @@ -436,9 +476,20 @@ struct PolicyElement {
user: Option<String>,
}

#[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<Rule>;
Expand All @@ -451,11 +502,19 @@ impl TryFrom<RuleElement> 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!(
Expand Down Expand Up @@ -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<bool>,
#[serde(rename = "@group")]
group: Option<String>,
#[serde(rename = "@max_fds")]
max_fds: Option<u32>,
#[serde(rename = "@min_fds")]
min_fds: Option<u32>,
#[serde(rename = "@own")]
own: Option<String>,
#[serde(rename = "@receive_sender")]
receive_sender: Option<String>,
/// deprecated and ignored
#[serde(rename = "@receive_requested_reply")]
receive_requested_reply: Option<bool>,
#[serde(rename = "@send_broadcast")]
send_broadcast: Option<bool>,
#[serde(rename = "@send_destination")]
send_destination: Option<String>,
#[serde(rename = "@send_destination_prefix")]
send_destination_prefix: Option<String>,
#[serde(rename = "@send_error")]
send_error: Option<String>,
#[serde(rename = "@send_interface")]
send_interface: Option<String>,
/// deprecated and ignored: https://github.com/dbus2/busd/issues/79
#[serde(rename = "@send_member")]
send_member: Option<String>,
#[serde(rename = "@send_path")]
send_path: Option<String>,
/// deprecated and ignored
#[serde(rename = "@send_requested_reply")]
send_requested_reply: Option<bool>,
#[serde(rename = "@send_type")]
send_type: Option<MessageType>,
#[serde(rename = "@user")]
user: Option<String>,
}
Expand All @@ -565,26 +646,53 @@ enum RuleElement {
Deny(RuleAttributes),
}

#[derive(Clone, Debug, Default, PartialEq)]
#[derive(Clone, Debug, PartialEq)]
pub struct SendOperation {
pub broadcast: Option<bool>,
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<RuleAttributes> 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)]
Expand Down Expand Up @@ -750,10 +858,20 @@ mod tests {
<allow own="*"/>
</policy>
<policy user="root">
<allow send_destination="org.freedesktop.DBus" send_interface="org.freedesktop.systemd1.Activator"/>
<allow
send_broadcast="true"
send_destination="org.freedesktop.DBus"
send_destination_prefix="org.freedesktop"
send_error="something bad"
send_interface="org.freedesktop.systemd1.Activator"
send_path="/org/freedesktop"
send_type="signal"
max_fds="128"
min_fds="12"
/>
</policy>
<policy group="network">
<allow send_destination="org.freedesktop.Avahi"/>
<allow send_destination="org.freedesktop.Avahi" send_member="DoSomething" />
<allow receive_sender="org.freedesktop.Avahi"/>
</policy>
<policy context="mandatory">
Expand All @@ -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")
Expand All @@ -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()
})
),
// `<allow send_member=...` should be dropped
(
Access::Allow,
Operation::Receive(ReceiveOperation {
sender: String::from("org.freedesktop.Avahi")
sender: String::from("org.freedesktop.Avahi"),
..Default::default()
})
),
],
Expand All @@ -798,7 +927,8 @@ mod tests {
Policy::MandatoryContext(vec![(
Access::Deny,
Operation::Send(SendOperation {
destination: String::from("net.connman.iwd")
destination: String::from("net.connman.iwd"),
..Default::default()
})
),]),
],
Expand All @@ -820,6 +950,9 @@ mod tests {
<allow send_requested_reply="false" send_type="method_return"/>
<deny receive_requested_reply="true" receive_type="error"/>
<allow receive_requested_reply="false" receive_type="error"/>
<allow send_destination="org.gnome.DisplayManager"
send_interface="org.gnome.DisplayManager.Manager"
send_member="GetRemoteHostname"/>
</policy>
<policy at_console="true">
<allow send_destination="org.freedesktop.DBus" send_interface="org.freedesktop.systemd1.Activator"/>
Expand All @@ -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()
})
),
// `<allow eavesdrop="true"/>` has nothing left after dropping eavesdrop
Expand All @@ -847,6 +981,15 @@ mod tests {
// `<allow send_requested_reply="false" ...` is completely ignored
// `<deny receive_requested_reply="true" ...` is completely ignored
// `<allow receive_requested_reply="false" ...` is completely ignored
(
Access::Allow,
Operation::Send(SendOperation {
destination: String::from("org.gnome.DisplayManager"),
interface: String::from("org.gnome.DisplayManager.Manager"),
// `member=... is dropped`
..Default::default()
}),
),
]),
// `<policy at_console="true">` is completely ignored
],
Expand Down Expand Up @@ -981,7 +1124,7 @@ mod tests {
assert_eq!(
busconfig,
BusConfig {
r#type: Some(Type::System),
r#type: Some(BusType::System),
..Default::default()
}
);
Expand Down

0 comments on commit e89212d

Please sign in to comment.