diff --git a/Cargo.lock b/Cargo.lock index 348d5ee24b6..3093a9e2602 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3627,6 +3627,7 @@ dependencies = [ "fluent", "libc", "uucore", + "windows-sys 0.60.2", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index da8dfb30ec4..3e9ca9ef66b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -577,6 +577,7 @@ feat_Tier1 = [ "env", "hostname", "kill", + "logname", "nohup", "nproc", "more", @@ -636,7 +637,6 @@ feat_require_unix_core = [ "groups", "id", "install", - "logname", "mkfifo", "mknod", "stat", diff --git a/src/uu/logname/Cargo.toml b/src/uu/logname/Cargo.toml index edc1b0e90f2..5a6cc302073 100644 --- a/src/uu/logname/Cargo.toml +++ b/src/uu/logname/Cargo.toml @@ -19,9 +19,17 @@ doctest = false [dependencies] clap = { workspace = true } fluent = { workspace = true } -libc = { workspace = true } uucore = { workspace = true } +[target.'cfg(unix)'.dependencies] +libc = { workspace = true } + +[target.'cfg(windows)'.dependencies] +windows-sys = { workspace = true, features = [ + "Win32_Foundation", + "Win32_System_RemoteDesktop", +] } + [lints] workspace = true diff --git a/src/uu/logname/src/logname.rs b/src/uu/logname/src/logname.rs index 0ecfe134a7c..0a036791db9 100644 --- a/src/uu/logname/src/logname.rs +++ b/src/uu/logname/src/logname.rs @@ -3,15 +3,16 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -// spell-checker:ignore (ToDO) getlogin userlogin +// spell-checker:ignore (ToDO) getlogin userlogin runas use clap::Command; -use core::ffi::CStr; use std::io::{Write, stdout}; use uucore::translate; use uucore::{error::UResult, show_error}; +#[cfg(unix)] fn get_userlogin() -> Option { + use core::ffi::CStr; let login_ptr = unsafe { libc::getlogin() }; if login_ptr.is_null() { None @@ -20,6 +21,43 @@ fn get_userlogin() -> Option { } } +#[cfg(windows)] +fn get_userlogin() -> Option { + use std::ffi::OsString; + use std::os::windows::ffi::OsStringExt; + use windows_sys::Win32::System::RemoteDesktop::{ + WTS_CURRENT_SERVER_HANDLE, WTS_CURRENT_SESSION, WTSFreeMemory, WTSQuerySessionInformationW, + WTSUserName, + }; + // Ask for the user logged on to this session rather than the process token's user + // (`GetUserNameW`, as `whoami` does), so `runas` or a service account still reports + // the person who logged in, like `getlogin` does on Unix. + let mut buffer = std::ptr::null_mut(); + let mut bytes = 0_u32; + // SAFETY: on success the buffer holds `bytes` bytes, a NUL-terminated UTF-16 string. + let ok = unsafe { + WTSQuerySessionInformationW( + WTS_CURRENT_SERVER_HANDLE, + WTS_CURRENT_SESSION, + WTSUserName, + &raw mut buffer, + &raw mut bytes, + ) + }; + if ok == 0 || buffer.is_null() { + return None; + } + // `bytes` includes the terminating NUL + let len = (bytes as usize / 2).saturating_sub(1); + // SAFETY: `buffer` is valid for `len` u16s and is freed right after copying. + let name = OsString::from_wide(unsafe { std::slice::from_raw_parts(buffer, len) }); + // SAFETY: `buffer` was allocated by `WTSQuerySessionInformationW`, is freed exactly once + // and is not used afterwards; `name` owns its own copy. + unsafe { WTSFreeMemory(buffer.cast()) }; + // Session 0 (services) has no logged-on user and returns an empty name. + (!name.is_empty()).then(|| name.to_string_lossy().into_owned()) +} + #[uucore::main(no_signals)] pub fn uumain(args: impl uucore::Args) -> UResult<()> { let _ = uucore::clap_localization::handle_clap_result(uu_app(), args)?; diff --git a/tests/by-util/test_logname.rs b/tests/by-util/test_logname.rs index c3ff0458670..6d3d90abe55 100644 --- a/tests/by-util/test_logname.rs +++ b/tests/by-util/test_logname.rs @@ -48,7 +48,7 @@ fn test_output_format() { } result.success(); assert!( - Regex::new(r"^\w+\n$") + Regex::new(r"^[^\r\n]+\n$") .unwrap() .is_match(result.stdout_str()), "unexpected logname output: {:?}",