feat(daemon): add polkit authorizer with permissive + system modes
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
use anyhow::Result;
|
||||
use tracing::info;
|
||||
|
||||
mod polkit;
|
||||
mod state;
|
||||
|
||||
#[tokio::main]
|
||||
|
||||
80
daemon/src/polkit.rs
Normal file
80
daemon/src/polkit.rs
Normal file
@@ -0,0 +1,80 @@
|
||||
use std::collections::HashMap;
|
||||
use thiserror::Error;
|
||||
use zbus::Connection;
|
||||
use zvariant::Value;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum PolkitError {
|
||||
#[error("not authorized: {action}")]
|
||||
NotAuthorized { action: String },
|
||||
#[error(transparent)]
|
||||
Bus(#[from] zbus::Error),
|
||||
}
|
||||
|
||||
#[allow(dead_code)] // wired up in Task 1.8.
|
||||
pub enum Polkit {
|
||||
Permissive,
|
||||
System(Connection),
|
||||
}
|
||||
|
||||
#[allow(dead_code)] // wired up in Task 1.8.
|
||||
impl Polkit {
|
||||
pub fn permissive() -> Self {
|
||||
Self::Permissive
|
||||
}
|
||||
|
||||
pub async fn system(conn: Connection) -> Self {
|
||||
Self::System(conn)
|
||||
}
|
||||
|
||||
/// Check whether `pid` may invoke `action`. Permissive always allows; system mode
|
||||
/// calls org.freedesktop.PolicyKit1.Authority.CheckAuthorization on the bus.
|
||||
pub async fn check(&self, action: &str, pid: u32) -> Result<(), PolkitError> {
|
||||
match self {
|
||||
Self::Permissive => Ok(()),
|
||||
Self::System(conn) => system_check(conn, action, pid).await,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn system_check(conn: &Connection, action: &str, pid: u32) -> Result<(), PolkitError> {
|
||||
// Subject = ("unix-process", { "pid": u32, "start-time": u64 }).
|
||||
// start-time 0 is accepted by polkit; it will look up /proc itself.
|
||||
let mut subject_details: HashMap<&str, Value<'_>> = HashMap::new();
|
||||
subject_details.insert("pid", Value::U32(pid));
|
||||
subject_details.insert("start-time", Value::U64(0));
|
||||
|
||||
let subject = ("unix-process", subject_details);
|
||||
let details: HashMap<&str, &str> = HashMap::new();
|
||||
let flags: u32 = 0; // No interaction; we don't block on auth prompt here.
|
||||
let cancellation_id = "";
|
||||
|
||||
let proxy = zbus::Proxy::new(
|
||||
conn,
|
||||
"org.freedesktop.PolicyKit1",
|
||||
"/org/freedesktop/PolicyKit1/Authority",
|
||||
"org.freedesktop.PolicyKit1.Authority",
|
||||
)
|
||||
.await?;
|
||||
|
||||
let (is_authorized, _is_challenge, _details): (bool, bool, HashMap<String, String>) = proxy
|
||||
.call("CheckAuthorization", &(subject, action, details, flags, cancellation_id))
|
||||
.await?;
|
||||
|
||||
if is_authorized {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(PolkitError::NotAuthorized { action: action.to_string() })
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[tokio::test]
|
||||
async fn permissive_always_allows() {
|
||||
let p = Polkit::permissive();
|
||||
p.check("io.dangerousthings.AuthForge.set-policy", 1234).await.unwrap();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user