git.delta.rocks / remowt / refs/commits / 06498c3c37da

difftreelog

source

cmds/remowt-agent/src/helper/suid.rs2.9 KiBsourcehistory
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            // TODO: Dedicated codec?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                // TODO: Success/failure handling71                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}