116 lines
3.9 KiB
Rust
116 lines
3.9 KiB
Rust
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<String>, input: Vec<u8>, #[zbus(header)] header: MessageHeader<'_>) -> (bool, Vec<u8>, Vec<u8>, 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<u8>, #[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<u8>, Vec<u8>, i32) {
|
|
// }
|
|
}
|
|
|
|
|
|
fn main() -> Result<(), Box<dyn Error>> {
|
|
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
|
|
}
|