1use std::pin::pin;2use std::process::Stdio;34use anyhow::{bail, anyhow};5use futures::stream::Peekable;6use futures::StreamExt as _;7use nix::unistd::User;8use polkit_shared::Identity;9use tokio::io::AsyncWriteExt as _;10use tokio::process::Command;11use tokio::select;12use tokio_util::codec::{FramedRead, LinesCodec};13use ui_prompt::Prompter;1415use super::Helper;1617#[derive(Clone)]18pub struct SuidHelper;19impl Helper for SuidHelper {20 async fn help_me<P: Prompter + 'static>(21 &self,22 cookie: &str,23 prompt: P,24 identity: Identity,25 ) -> anyhow::Result<()> {26 let Some(uid) = dbg!(identity.uid()) else {27 bail!("can't process identity");28 };29 let user = User::from_uid(dbg!(uid))30 .map_err(|e| anyhow!("error querying user: {e}"))?31 .ok_or_else(|| anyhow!("user not found"))?;3233 let mut cmd = Command::new("polkit-agent-helper-1");34 cmd.arg(user.name);35 cmd.stdin(Stdio::piped());36 cmd.stdout(Stdio::piped());37 cmd.kill_on_drop(true);38 let mut child = cmd.spawn()?;39 let mut stdin = child.stdin.take().expect("piped");40 let mut stdout =41 pin!(42 FramedRead::new(child.stdout.take().expect("piped"), LinesCodec::new()).peekable()43 );4445 assert!(!cookie.contains("\n"));46 stdin.write_all(cookie.as_bytes()).await?;47 stdin.write_all(b"\n").await?;4849 while let Some(line) = stdout.next().await {50 let line = dbg!(line?);51 52 let res = if let Some(prompt_text) = line.strip_prefix("PAM_PROMPT_ECHO_OFF ") {53 prompt.prompt_text(false, prompt_text, "", &[]).await?54 } else if let Some(prompt_text) = line.strip_prefix("PAM_PROMPT_ECHO_ON ") {55 prompt.prompt_text(true, prompt_text, "", &[]).await?56 } else if let Some(msg_text) = line.strip_prefix("PAM_ERROR_MSG ") {57 prompt.display_text(true, msg_text, &[]).await?;58 String::new()59 } else if let Some(msg_text) = line.strip_prefix("PAM_TEXT_INFO ") {60 select! {61 _ = Peekable::peek(stdout.as_mut()) => {},62 r = prompt.display_text(false, msg_text, &[]) => {r?}63 }64 String::new()65 } else if line == "SUCCESS" {66 return Ok(());67 } else if line == "FAILURE" {68 bail!("helper binary reported failure")69 } else {70 71 bail!("unknown agent request");72 };7374 if res.contains("\n") {75 bail!("response should not include newline")76 }7778 stdin.write_all(res.as_bytes()).await?;79 stdin.write_all(b"\n").await?;80 }81 bail!("agent finished unexpectedly")82 }83}