Register native polkit agent for the login session

This commit is contained in:
Samuel Onoja committed 2026-10-01 08:34:38 +01:00
1 parent 1cad509275
commit 6d8041a59a
3 files changed
+64 -3

No files matched your search

+3
View File
@@ -93,6 +93,9 @@ and `previous` links for switching between releases during updates and rollback.
Your configuration, other desktop sessions and existing PAM policy stay in place, while
Ferese starts its authentication agent and portal services together with the session.
The authentication agent registers for the login session, so requests from desktop
apps use the Ferese dialog. Remove other polkit agents from your Ferese autostart
configuration to avoid competing session registrations.
### Initial configuration
+60 -2
View File
@@ -96,7 +96,7 @@ fn choose_identity(identities: &[Identity]) -> Option<u32> {
.or_else(|| available.first().copied())
}
fn session_subject() -> Result<(String, HashMap<String, Value<'static>>), String> {
fn process_subject() -> Result<(String, HashMap<String, Value<'static>>), String> {
let stat = std::fs::read_to_string("/proc/self/stat").map_err(|error| error.to_string())?;
let suffix = stat
.rsplit_once(") ")
@@ -115,12 +115,53 @@ fn session_subject() -> Result<(String, HashMap<String, Value<'static>>), String
Ok(("unix-process".into(), details))
}
async fn session_subject(
connection: &zbus::Connection,
) -> Result<(String, HashMap<String, Value<'static>>), Box<dyn std::error::Error>> {
// Nested previews must not take over authentication for the host desktop.
if std::env::var("FERESE_SESSION_IMPORT_ENV").as_deref() == Ok("0") {
return process_subject().map_err(Into::into);
}
let manager = zbus::Proxy::new(
connection,
"org.freedesktop.login1",
"/org/freedesktop/login1",
"org.freedesktop.login1.Manager",
)
.await?;
let path: zbus::zvariant::OwnedObjectPath = match manager.call("GetSessionByPID", &(std::process::id(),)).await {
Ok(path) => path,
Err(error) => {
// A launcher in the user manager can be outside the session cgroup
// while retaining the login session's environment.
let id = std::env::var("XDG_SESSION_ID").map_err(|_| error)?;
manager.call("GetSession", &(id,)).await?
}
};
let session = zbus::Proxy::new(
connection,
"org.freedesktop.login1",
path,
"org.freedesktop.login1.Session",
)
.await?;
let id: String = session.get_property("Id").await?;
Ok(login_session_subject(id))
}
fn login_session_subject(id: String) -> (String, HashMap<String, Value<'static>>) {
(
"unix-session".into(),
HashMap::from([("session-id".into(), Value::from(id))]),
)
}
async fn run_agent() -> Result<(), Box<dyn std::error::Error>> {
let subject = session_subject()?;
let connection = zbus::connection::Builder::system()?
.serve_at(AGENT_PATH, Agent::default())?
.build()
.await?;
let subject = session_subject(&connection).await?;
let authority = zbus::Proxy::new(&connection, AUTHORITY, AUTHORITY_PATH, AUTHORITY_INTERFACE).await?;
let locale = std::env::var("LANG").unwrap_or_default();
@@ -152,6 +193,23 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
mod tests {
use super::*;
#[test]
fn desktop_agent_registers_for_the_login_session() {
let (kind, details) = login_session_subject("test-session".into());
assert_eq!(kind, "unix-session");
assert_eq!(details.len(), 1);
assert_eq!(details["session-id"], Value::from("test-session"));
}
#[test]
fn process_subject_has_required_identity_fields() {
let (kind, details) = process_subject().unwrap();
assert_eq!(kind, "unix-process");
assert_eq!(details["pid"], Value::from(std::process::id()));
assert_eq!(details["uid"], Value::from(unsafe { libc::geteuid() } as i32));
assert!(u64::try_from(details["start-time"].clone()).unwrap() > 0);
}
#[test]
fn chooses_current_identity_when_available() {
let current = unsafe { libc::geteuid() };
+1 -1
View File
@@ -88,7 +88,7 @@ fn prompt_process(
.arg("--prompt")
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::null())
.stderr(Stdio::inherit())
.spawn()
.map_err(|e| e.to_string())?;
let stdin = child.stdin.take().ok_or("Prompt has no input")?;