From d472362c94d8bff65e124ee55c06860c35fb1068 Mon Sep 17 00:00:00 2001 From: pnyani Date: Fri, 6 Feb 2026 17:33:55 +0900 Subject: [PATCH] feat: add Windows administrator privilege check --- .github/workflows/ci.yml | 8 +++ Cargo.lock | 94 ++++++++++++++++++++++++++++++---- Cargo.toml | 11 +++- src/bin/it.rs | 6 +++ src/command/allow_non_admin.rs | 10 +++- src/util.rs | 43 ++++++++++++++++ 6 files changed, 159 insertions(+), 13 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b99199a..74d756a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,3 +21,11 @@ jobs: - uses: actions/checkout@v4 - name: Build run: cargo build + + test-windows: + runs-on: windows-latest + + steps: + - uses: actions/checkout@v4 + - name: Build + run: cargo build diff --git a/Cargo.lock b/Cargo.lock index 87f99ee..03bd855 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -255,7 +255,7 @@ dependencies = [ [[package]] name = "bootit" -version = "0.1.1" +version = "0.1.2" dependencies = [ "clap", "derive_more", @@ -269,6 +269,7 @@ dependencies = [ "serde_yaml", "system_shutdown", "which", + "windows-sys 0.59.0", ] [[package]] @@ -1570,13 +1571,22 @@ dependencies = [ "windows-link", ] +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-sys" version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets", + "windows-targets 0.53.5", ] [[package]] @@ -1588,6 +1598,22 @@ dependencies = [ "windows-link", ] +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + [[package]] name = "windows-targets" version = "0.53.5" @@ -1595,14 +1621,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" dependencies = [ "windows-link", - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", ] [[package]] @@ -1614,48 +1640,96 @@ dependencies = [ "windows-link", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + [[package]] name = "windows_aarch64_gnullvm" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + [[package]] name = "windows_aarch64_msvc" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + [[package]] name = "windows_i686_gnu" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + [[package]] name = "windows_i686_gnullvm" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + [[package]] name = "windows_i686_msvc" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + [[package]] name = "windows_x86_64_gnu" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + [[package]] name = "windows_x86_64_gnullvm" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + [[package]] name = "windows_x86_64_msvc" version = "0.53.1" diff --git a/Cargo.toml b/Cargo.toml index 143ff54..d438d05 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,12 +12,21 @@ derive_more = { version = "2.1.1", features = ["from", "into", "from_str", "add" dirs = "6.0.0" efivar = "2.0.0" inquire = "0.9.2" -libc = "0.2.180" miette = { version = "7.6.0", features = ["fancy"] } serde = { version = "1.0.228", features = ["derive"] } serde_yaml = "0.9" system_shutdown = "4.1.0" which = "8.0.0" +[target.'cfg(unix)'.dependencies] +libc = "0.2.180" + [target.'cfg(target_os = "linux")'.dependencies] nix = { version = "0.31.1", features = ["fs", "user"] } + +[target.'cfg(target_os = "windows")'.dependencies] +windows-sys = { version = "0.59", features = [ + "Win32_Security", + "Win32_System_Threading", + "Win32_Foundation", +] } diff --git a/src/bin/it.rs b/src/bin/it.rs index 5013d11..7459e10 100644 --- a/src/bin/it.rs +++ b/src/bin/it.rs @@ -9,6 +9,12 @@ fn main() { Err(e) => { eprintln!("Error: Failed to execute 'bootit' command: {}", e); eprintln!("Make sure 'bootit' is installed and in your PATH."); + + #[cfg(windows)] + eprintln!( + "\nIf you are not running as Administrator, try opening an elevated terminal." + ); + std::process::exit(127); } }; diff --git a/src/command/allow_non_admin.rs b/src/command/allow_non_admin.rs index 80a7a8b..a2ba9c2 100644 --- a/src/command/allow_non_admin.rs +++ b/src/command/allow_non_admin.rs @@ -35,9 +35,15 @@ pub fn allow_non_admin(it_path: Option) -> miette::Result<()> { println!("Non-admin users can now use it command to boot."); } - #[cfg(not(target_os = "linux"))] + #[cfg(target_os = "windows")] { - println!("Setting setuid bit is not supported on this operating system."); + println!("The setuid mechanism is not available on Windows."); + println!("Run bootit from an elevated terminal (right-click -> Run as administrator)."); + } + + #[cfg(not(any(target_os = "linux", target_os = "windows")))] + { + println!("allow-non-admin is not supported on this operating system."); } Ok(()) diff --git a/src/util.rs b/src/util.rs index 935aa3a..0bb9116 100644 --- a/src/util.rs +++ b/src/util.rs @@ -13,9 +13,52 @@ pub fn check_privileges() -> miette::Result<()> { )); } } + + #[cfg(windows)] + { + if !is_elevated() { + return Err(miette!( + "This program must be run as Administrator (try: run terminal as administrator)" + )); + } + } + Ok(()) } +#[cfg(windows)] +fn is_elevated() -> bool { + use std::ptr::null_mut; + use windows_sys::Win32::Foundation::{CloseHandle, HANDLE}; + use windows_sys::Win32::Security::{ + GetTokenInformation, TokenElevation, TOKEN_ELEVATION, TOKEN_QUERY, + }; + use windows_sys::Win32::System::Threading::{GetCurrentProcess, OpenProcessToken}; + + unsafe { + let mut token_handle: HANDLE = null_mut(); + if OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &mut token_handle) == 0 { + return false; + } + + let mut elevation = TOKEN_ELEVATION { TokenIsElevated: 0 }; + let mut return_length: u32 = 0; + let size = std::mem::size_of::() as u32; + + let result = GetTokenInformation( + token_handle, + TokenElevation, + &mut elevation as *mut _ as *mut _, + size, + &mut return_length, + ); + + CloseHandle(token_handle); + + result != 0 && elevation.TokenIsElevated != 0 + } +} + #[allow(unused)] pub fn find_it() -> miette::Result { if let Ok(path) = which("it") {