diff --git a/src/config.rs b/src/config.rs index 6bfafc5..3b250f0 100644 --- a/src/config.rs +++ b/src/config.rs @@ -51,6 +51,8 @@ pub struct BusConfig { /// The bus daemon will write its pid to the specified file. pub pidfile: Option, + pub policies: Vec, + /// Adds a directory to search for .service files, /// which tell the dbus-daemon how to start a program to provide a particular well-known bus name. #[serde(default)] @@ -92,6 +94,11 @@ impl TryFrom for BusConfig { bc.listen.insert(s); } Element::Pidfile(p) => bc.pidfile = Some(p), + Element::Policy(pe) => { + if let Some(p) = OptionalPolicy::try_from(pe)? { + bc.policies.push(p); + } + } Element::Servicedir(p) => { bc.servicedir.push(p); } @@ -222,13 +229,6 @@ impl BusConfig { } } -#[derive(Clone, Debug, Deserialize, PartialEq)] -#[serde(rename_all = "lowercase")] -pub enum Type { - Session, - System, -} - #[derive(Clone, Debug, Default, Deserialize, PartialEq)] struct Document { #[serde(rename = "$value", default)] @@ -247,6 +247,7 @@ enum Element { Listen(String), Limit, Pidfile(PathBuf), + Policy(PolicyElement), Servicedir(PathBuf), Servicehelper(PathBuf), /// Requests a standard set of session service directories. @@ -297,6 +298,90 @@ pub struct Limits { pub reply_timeout: Duration, } +#[derive(Clone, Debug, PartialEq)] +pub enum Policy { + DefaultContext, + Group(String), + MandatoryContext, + User(String), +} +// TODO: implement Cmp/Ord to help stable-sort Policy values: +// DefaultContext < Group < User < MandatoryContext +type OptionalPolicy = Option; +impl TryFrom for OptionalPolicy { + type Error = Error; + + fn try_from(value: PolicyElement) -> Result { + match value { + PolicyElement { + at_console: Some(_), + context: None, + group: None, + user: None, + .. + } => { + eprintln!(r#"warning: busd does not implement ``"#); + Ok(None) + } + PolicyElement { + at_console: None, + context: Some(c), + group: None, + user: None, + .. + } => Ok(Some(match c { + PolicyContext::Default => Policy::DefaultContext, + PolicyContext::Mandatory => Policy::MandatoryContext, + })), + PolicyElement { + at_console: None, + context: None, + group: Some(group), + user: None, + .. + } => Ok(Some(Policy::Group(group))), + PolicyElement { + at_console: None, + context: None, + group: None, + user: Some(user), + .. + } => Ok(Some(Policy::User(user))), + _ => Err(Error::msg(format!( + "policy contains conflicting attributes: {value:?}" + ))), + } + } +} + +#[derive(Clone, Debug, Deserialize, PartialEq)] +#[serde(rename_all = "snake_case")] +enum PolicyContext { + Default, + Mandatory, +} + +#[derive(Clone, Debug, Default, Deserialize, PartialEq)] +struct PolicyElement { + #[serde(rename = "@at_console")] + at_console: Option, + #[serde(rename = "@context")] + context: Option, + #[serde(rename = "@group")] + group: Option, + // #[serde(rename = "$value", default)] + // rules: Vec, + #[serde(rename = "@user")] + user: Option, +} + +#[derive(Clone, Debug, Deserialize, PartialEq)] +#[serde(rename_all = "lowercase")] +pub enum Type { + Session, + System, +} + #[derive(Clone, Debug, Deserialize, PartialEq)] struct TypeElement { #[serde(rename = "$text")] @@ -457,6 +542,48 @@ mod tests { ); } + #[test] + fn bus_config_parse_with_policies_ok() { + let input = r#" + + + + + + + + + + + + + + + + + + + + + "#; + + let busconfig = BusConfig::parse(input).expect("should parse XML input"); + + assert_eq!( + busconfig, + BusConfig { + policies: vec![ + Policy::DefaultContext, + Policy::User(String::from("root")), + Policy::Group(String::from("network")), + Policy::MandatoryContext, + ], + ..Default::default() + } + ); + } + #[test] fn bus_config_parse_with_servicedir_and_standard_session_servicedirs_ok() { let input = r#"