use std::fs::{self, OpenOptions}; use std::error::Error; use std::convert::TryInto; use std::io::{Seek, SeekFrom, Write}; use std::process::{Command, Stdio}; use zbus_polkit::policykit1::*; use zbus::{Connection, dbus_interface, fdo, MessageHeader}; struct ExternalCommandHelper; #[dbus_interface(name = "org.kde.kpmcore.externalcommand")] impl ExternalCommandHelper { fn run_command(&self, command: &str, arguments: Vec, input: Vec, #[zbus(header)] header: MessageHeader<'_>) -> (bool, Vec, Vec, i32) { let authorized = is_authorized(header); if !authorized { // FIXME: Send AccessDenied error back return (false, vec![0; 0], vec![0; 0], 1) } //Implement command whitelist let mut child = Command::new(command) .args(&arguments) .stdin(Stdio::piped()) .stdout(Stdio::piped()) .stderr(Stdio::piped()) .spawn().unwrap(); // FIXME unwrap let child_stdin = child.stdin.as_mut().unwrap(); child_stdin.write_all(&input).unwrap(); let result = child.wait_with_output(); match result { Ok(v) => return (true, v.stdout, v.stderr, v.status.code().unwrap()), // FIXME: unwrap Err(_) => return (false, vec![0; 0], vec![0; 0], 1) } } fn create_file(&self, file_path: &str, file_contents: Vec, #[zbus(header)] header: MessageHeader<'_>) -> bool { let authorized = is_authorized(header); if !authorized { // FIXME: Send AccessDenied error back return false } if !file_path.contains("/etc/fstab") { return false } let result = fs::write(file_path, file_contents); match result { Ok(()) => return true, Err(_) => return false, } } fn write_data(&self, data: &[u8], target_device: &str, target_first_byte: u64, #[zbus(header)] header: MessageHeader<'_>) -> bool { let authorized = is_authorized(header); if !authorized { // FIXME: Send AccessDenied error back return false } let mut file = OpenOptions::new().write(true).open(target_device).unwrap(); let result = file.seek(SeekFrom::Start(target_first_byte)); match result { Ok(_) => match file.write(data) { Ok(_) => true, Err(_) => false, } Err(_) => false, } } // fn copyblocks(&self, source_device: &str, source_first_byte: i64, source_length: i64, target_device: &str, target_first_byte: i64, block_size: i64, #[zbus(header)] header: MessageHeader<'_>) -> (bool, Vec, Vec, i32) { // } } fn main() -> Result<(), Box> { let connection = Connection::new_system()?; fdo::DBusProxy::new(&connection)?.request_name( "org.kde.kpmcore.helperinterface", fdo::RequestNameFlags::ReplaceExisting.into(), )?; let mut object_server = zbus::ObjectServer::new(&connection); let helper = ExternalCommandHelper; object_server.at(&"/Helper".try_into()?, helper)?; loop { if let Err(err) = object_server.try_handle_next() { eprintln!("{}", err); } } } fn is_authorized(header: MessageHeader<'_>) -> bool { let sender = header.sender().unwrap().unwrap(); println!("Sender: {}", sender); let connection = Connection::new_system().unwrap(); let proxy = AuthorityProxy::new(&connection).unwrap(); let subject = Subject::new_for_message_header(&header).unwrap(); let result = proxy.check_authorization( &subject, "org.kde.kpmcore.externalcommand.init", std::collections::HashMap::new(), CheckAuthorizationFlags::AllowUserInteraction.into(), "", ).unwrap(); result.is_authorized }