use eframe::egui;
use std::process::{Command, Stdio};
#[derive(PartialEq)]
enum Privilege {
Root,
User,
Suid,
}
pub fn privilege_request() {
if get_privilege() == Privilege::User {
let options = eframe::NativeOptions {
viewport: egui::ViewportBuilder::default().with_inner_size([400.0, 300.0]), ..Default::default()
};
let mut password = String::new();
let mut notification = String::new();
let _ = eframe::run_simple_native("Privilege Request", options, move |ctx, _frame| {
egui::CentralPanel::default().show(ctx, |ui| {
ui.vertical_centered(|ui| {
ui.heading("Privilege Request");
ui.add_space(20.0); ui.horizontal(|ui| {
let name_label = ui.label("Enter admin/root password: ");
ui.add_space(5.0); ui.add(egui::TextEdit::singleline(&mut password).password(true))
.labelled_by(name_label.id);
});
ui.add_space(10.0); if ui.button("Submit").clicked()
|| ui.input(|i| i.key_pressed(egui::Key::Enter))
{
if verify_password(&password) {
let _ = run_with_privilege(password.clone());
} else {
notification = "Failed to verify the password.".to_owned();
}
}
if !notification.is_empty() {
ui.add_space(15.0); ui.label(egui::RichText::new(¬ification).color(egui::Color32::RED));
}
});
});
});
}
}
fn get_privilege() -> Privilege {
let uid = unsafe { libc::getuid() };
let euid = unsafe { libc::geteuid() };
match (uid, euid) {
(0, 0) => Privilege::Root,
(_, 0) => Privilege::Suid,
(_, _) => Privilege::User,
}
}
fn verify_password(password: &str) -> bool {
let mut command = Command::new("sudo");
let mut child = command
.arg("-k") .arg("-S") .arg("true") .stdin(Stdio::piped())
.stdout(Stdio::null())
.stderr(Stdio::null())
.spawn()
.expect("Failed to execute sudo");
if let Some(mut stdin) = child.stdin.take() {
use std::io::Write;
writeln!(stdin, "{}", password).expect("Failed to write to stdin");
}
let ecode = child.wait().expect("Failed to wait on child");
ecode.success()
}
fn run_with_privilege(pwd: String) -> std::io::Result<Privilege> {
let current = get_privilege();
match current {
Privilege::Root => {
return Ok(current);
}
Privilege::Suid => {
unsafe {
libc::setuid(0);
}
return Ok(current);
}
Privilege::User => {
println!("Escalating privileges");
}
}
let mut args: Vec<_> = std::env::args().collect();
if let Some(absolute_path) = std::env::current_exe()
.ok()
.and_then(|p| p.to_str().map(|p| p.to_string()))
{
args[0] = absolute_path;
}
let mut command: Command = Command::new("sudo");
let mut child = command
.arg("-S")
.args(args)
.stdin(Stdio::piped())
.spawn()
.expect("failed to execute child");
if let Some(mut stdin) = child.stdin.take() {
use std::io::Write;
writeln!(stdin, "{}", pwd).expect("Failed to write to stdin");
}
std::process::exit(0);
}