diff --git a/Cargo.lock b/Cargo.lock
index dd0ff0e..a4c9337 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1029,7 +1029,7 @@ dependencies = [
"thiserror 1.0.69",
"tokio",
"tokio-tungstenite",
- "toml",
+ "toml 0.8.2",
"tracing",
"tracing-subscriber",
"tray-icon",
@@ -1037,6 +1037,7 @@ dependencies = [
"uuid",
"windows",
"windows-service",
+ "winres",
"zstd",
]
@@ -1061,7 +1062,7 @@ dependencies = [
"sqlx",
"thiserror 1.0.69",
"tokio",
- "toml",
+ "toml 0.8.2",
"tower",
"tower-http",
"tracing",
@@ -2968,7 +2969,7 @@ dependencies = [
"cfg-expr",
"heck 0.5.0",
"pkg-config",
- "toml",
+ "toml 0.8.2",
"version-compare",
]
@@ -3172,6 +3173,15 @@ dependencies = [
"tokio",
]
+[[package]]
+name = "toml"
+version = "0.5.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
+dependencies = [
+ "serde",
+]
+
[[package]]
name = "toml"
version = "0.8.2"
@@ -3969,6 +3979,15 @@ dependencies = [
"memchr",
]
+[[package]]
+name = "winres"
+version = "0.1.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b68db261ef59e9e52806f688020631e987592bd83619edccda9c47d42cde4f6c"
+dependencies = [
+ "toml 0.5.11",
+]
+
[[package]]
name = "wit-bindgen"
version = "0.46.0"
diff --git a/agent/Cargo.toml b/agent/Cargo.toml
index a49d6bb..60c0f3f 100644
--- a/agent/Cargo.toml
+++ b/agent/Cargo.toml
@@ -79,6 +79,7 @@ windows-service = "0.7"
[build-dependencies]
prost-build = "0.13"
+winres = "0.1"
[profile.release]
lto = true
diff --git a/agent/build.rs b/agent/build.rs
index d1606dc..f93ee9d 100644
--- a/agent/build.rs
+++ b/agent/build.rs
@@ -7,5 +7,26 @@ fn main() -> Result<()> {
// Rerun if proto changes
println!("cargo:rerun-if-changed=../proto/guruconnect.proto");
+ // On Windows, embed the manifest for UAC elevation
+ #[cfg(target_os = "windows")]
+ {
+ println!("cargo:rerun-if-changed=guruconnect.manifest");
+
+ let mut res = winres::WindowsResource::new();
+ res.set_manifest_file("guruconnect.manifest");
+ res.set("ProductName", "GuruConnect Agent");
+ res.set("FileDescription", "GuruConnect Remote Desktop Agent");
+ res.set("LegalCopyright", "Copyright (c) AZ Computer Guru");
+ res.set_icon("guruconnect.ico"); // Optional: add icon if available
+
+ // Only compile if the manifest exists
+ if std::path::Path::new("guruconnect.manifest").exists() {
+ if let Err(e) = res.compile() {
+ // Don't fail the build if resource compilation fails
+ eprintln!("Warning: Failed to compile Windows resources: {}", e);
+ }
+ }
+ }
+
Ok(())
}
diff --git a/agent/guruconnect.manifest b/agent/guruconnect.manifest
new file mode 100644
index 0000000..aec389f
--- /dev/null
+++ b/agent/guruconnect.manifest
@@ -0,0 +1,36 @@
+
+
+
+ GuruConnect Remote Desktop Agent
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true/pm
+ PerMonitorV2, PerMonitor
+
+
+
diff --git a/agent/src/main.rs b/agent/src/main.rs
index 4615d02..d27a00f 100644
--- a/agent/src/main.rs
+++ b/agent/src/main.rs
@@ -28,6 +28,10 @@ use tracing_subscriber::FmtSubscriber;
use windows::Win32::UI::WindowsAndMessaging::{MessageBoxW, MB_OK, MB_ICONINFORMATION};
#[cfg(windows)]
use windows::core::PCWSTR;
+#[cfg(windows)]
+use windows::Win32::Security::{GetTokenInformation, TokenElevation, TOKEN_ELEVATION, TOKEN_QUERY};
+#[cfg(windows)]
+use windows::Win32::System::Threading::{GetCurrentProcess, OpenProcessToken};
/// Extract a 6-digit support code from the executable's filename.
/// Looks for patterns like "GuruConnect-123456.exe" or "123456.exe"
@@ -56,6 +60,38 @@ fn extract_code_from_filename() -> Option {
None
}
+/// Check if the process is running with elevated privileges (Windows only)
+#[cfg(windows)]
+fn is_elevated() -> bool {
+ unsafe {
+ let mut token_handle = windows::Win32::Foundation::HANDLE::default();
+ if OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &mut token_handle).is_err() {
+ return false;
+ }
+
+ let mut elevation = TOKEN_ELEVATION::default();
+ let mut size = std::mem::size_of::() as u32;
+
+ let result = GetTokenInformation(
+ token_handle,
+ TokenElevation,
+ Some(&mut elevation as *mut _ as *mut _),
+ size,
+ &mut size,
+ );
+
+ let _ = windows::Win32::Foundation::CloseHandle(token_handle);
+
+ result.is_ok() && elevation.TokenIsElevated != 0
+ }
+}
+
+#[cfg(not(windows))]
+fn is_elevated() -> bool {
+ // On non-Windows, check if running as root
+ unsafe { libc::geteuid() == 0 }
+}
+
/// Show a message box to the user (Windows only)
#[cfg(windows)]
fn show_message_box(title: &str, message: &str) {
@@ -98,6 +134,13 @@ async fn main() -> Result<()> {
info!("GuruConnect Agent v{}", env!("CARGO_PKG_VERSION"));
+ // Check and log elevation status
+ if is_elevated() {
+ info!("Running with elevated (administrator) privileges");
+ } else {
+ info!("Running with standard user privileges");
+ }
+
// Extract support code from executable filename
// e.g., GuruConnect-123456.exe -> 123456
let support_code = extract_code_from_filename();