1use std::collections::HashMap;2use std::ffi::{CStr, CString};3use std::future;45use pam_client::{Context, ConversationHandler, ErrorCode, Flag};6use serde::Deserialize;7use zbus::zvariant::{OwnedValue, Str, Type, Value};8use zbus::{interface, Connection};9use zbus_polkit::policykit1::Subject;101112#[derive(Deserialize, Type, PartialEq, Debug)]13pub struct Identity<'s> {14 pub kind: &'s str,15 pub details: HashMap<&'s str, Value<'s>>,16}17struct Agent {18 19}2021impl Agent {22 pub fn new() -> Self {23 Self {24 25 }26 }27}28#[interface(name = "org.freedesktop.PolicyKit1.AuthenticationAgent")]29impl Agent {30 31 async fn begin_authentication(32 &mut self,33 action_id: &str,34 message: &str,35 icon_name: &str,36 details: HashMap<&str, &str>,37 cookie: &str,38 identities: Vec<Identity<'_>>,39 ) -> zbus::fdo::Result<()> {40 println!("ASKED");41 dbg!(action_id, message, icon_name, details, cookie, identities);42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 Ok(())65 }6667 68 async fn cancel_authentication(&self, cookie: &str) -> zbus::fdo::Result<()> {69 println!("CANCELED");70 71 Ok(())72 }73}7475const OBJ_PATH: &str = "/0lach/polkitAgent";7677async fn mainw() -> anyhow::Result<()> {78 let conn = Connection::system().await?;79 let proxy = zbus_polkit::policykit1::AuthorityProxy::new(&conn).await?;80 conn.object_server().at(OBJ_PATH, Agent::new()).await?;81 8283 let session_id = std::env::var("XDG_SESSION_ID")?;84 let mut details = HashMap::new();85 let val: OwnedValue = {86 let wrapped: Str<'_> = session_id.into();87 wrapped.into()88 };89 details.insert("session-id".to_string(), val);90 proxy91 .register_authentication_agent(92 &Subject {93 subject_kind: "unix-session".to_string(),94 subject_details: details,95 },96 "C",97 OBJ_PATH,98 )99 .await?;100101 future::pending::<()>().await;102 Ok(())103}104105struct Conv;106impl ConversationHandler for Conv {107 #[doc = " Obtains a string whilst echoing text (e.g. username)"]108 #[doc = ""]109 #[doc = " # Errors"]110 #[doc = " You should return one of the following error codes on failure."]111 #[doc = " - [`ErrorCode::CONV_ERR`]: Conversation failure."]112 #[doc = " - [`ErrorCode::BUF_ERR`]: Memory allocation error."]113 #[doc = " - [`ErrorCode::CONV_AGAIN`]: no result yet, the PAM library should"]114 #[doc = " pass [`ErrorCode::INCOMPLETE`] to the application and let it"]115 #[doc = " try again later."]116 fn prompt_echo_on(&mut self, prompt: &CStr) -> Result<CString, ErrorCode> {117 todo!()118 }119120 #[doc = " Obtains a string without echoing any text (e.g. password)"]121 #[doc = ""]122 #[doc = " # Errors"]123 #[doc = " You should return one of the following error codes on failure."]124 #[doc = " - [`ErrorCode::CONV_ERR`]: Conversation failure."]125 #[doc = " - [`ErrorCode::BUF_ERR`]: Memory allocation error."]126 #[doc = " - [`ErrorCode::CONV_AGAIN`]: no result yet, the PAM library should"]127 #[doc = " pass [`ErrorCode::INCOMPLETE`] to the application and let it"]128 #[doc = " try again later."]129 fn prompt_echo_off(&mut self, prompt: &CStr) -> Result<CString, ErrorCode> {130 dbg!(prompt);131 Ok(CString::new("1").expect("valid"))132 }133134 #[doc = " Displays some text."]135 fn text_info(&mut self, msg: &CStr) {136 todo!()137 }138139 #[doc = " Displays an error message."]140 fn error_msg(&mut self, msg: &CStr) {141 todo!()142 }143}144145#[tokio::main]146async fn main() {147 let mut ctx = Context::new("login", Some("lach"), Conv).expect("context init failed");148149150 ctx.set_user_prompt(Some("Hello"));151 ctx.authenticate(Flag::NONE).expect("fail?");152153 println!("authenticated!");154}