Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Ability to get user that ran the process #198

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions examples/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ async fn flip_the_table(p: process::Process) -> process::ProcessResult<prettytab
table.add_row(row!["PID", p.pid()]);
table.add_row(row!["Parent PID", p.parent_pid().await?]);
table.add_row(row!["Name", p.name().await?]);
#[cfg(target_os = "windows")] // Not implemented yet
table.add_row(row!["User", p.user().await?.username()]);
sandorex marked this conversation as resolved.
Show resolved Hide resolved
table.add_row(row!["Exe", p.exe().await?.display()]);
#[cfg(not(target_os = "windows"))] // Not implemented yet
table.add_row(row!["Command", format!("{:?}", p.command().await?)]);
Expand Down
6 changes: 6 additions & 0 deletions heim-common/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,12 @@ impl From<convert::Infallible> for Error {
}
}

impl From<std::string::FromUtf16Error> for Error {
fn from(e: std::string::FromUtf16Error) -> Self {
Error::from(io::Error::new(io::ErrorKind::InvalidData, e))
}
}

#[cfg(unix)]
impl From<nix::Error> for Error {
fn from(e: nix::Error) -> Self {
Expand Down
12 changes: 11 additions & 1 deletion heim-host/src/os/windows.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
//! Windows-specific extensions.

use std::net::IpAddr;
use winapi::um::winnt::PSID;

use heim_common::Result;

/// Extension for [User] struct.
///
/// [User]: ../../struct.User.html
pub trait UserExt {
pub trait UserExt: Sized {
#[doc(hidden)]
fn try_from_sid(sid: PSID) -> Result<Self>;
sandorex marked this conversation as resolved.
Show resolved Hide resolved

/// Domain name that the user belongs to.
fn domain(&self) -> &str;

Expand All @@ -26,6 +32,10 @@ pub trait UserExt {

#[cfg(target_os = "windows")]
impl UserExt for crate::User {
fn try_from_sid(sid: PSID) -> Result<Self> {
crate::sys::User::try_from_sid(sid).map(crate::User::from)
}

fn domain(&self) -> &str {
self.as_ref().domain()
}
Expand Down
40 changes: 40 additions & 0 deletions heim-host/src/sys/windows/users.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
use std::net::IpAddr;
use std::ptr;
use winapi::shared::minwindef::DWORD;
use winapi::um::winbase::LookupAccountSidW;
use winapi::um::winnt::{SidTypeUser, PSID, SID_NAME_USE, WCHAR};

use super::wrappers::{Session, Sessions};
use heim_common::prelude::*;
Expand Down Expand Up @@ -27,6 +31,42 @@ impl User {
}))
}

pub fn try_from_sid(sid: PSID) -> Result<Self> {
// name and domain cannot be longer than 256
let mut name_cch: DWORD = 256;
let mut name: Vec<WCHAR> = Vec::with_capacity(name_cch as usize);
let mut domain_cch: DWORD = 256;
let mut domain: Vec<WCHAR> = Vec::with_capacity(domain_cch as usize);
let mut account_type: SID_NAME_USE = 0;
sandorex marked this conversation as resolved.
Show resolved Hide resolved

let result = unsafe {
LookupAccountSidW(
ptr::null(),
sid,
name.as_mut_ptr(),
&mut name_cch,
domain.as_mut_ptr(),
&mut domain_cch,
&mut account_type,
)
};

if result == 0 || account_type != SidTypeUser {
return Err(Error::last_os_error().with_ffi("LookupAccountSidW"));
}

unsafe {
name.set_len(name_cch as usize);
domain.set_len(domain_cch as usize);
}

Ok(Self {
domain: String::from_utf16(domain.as_slice())?,
username: String::from_utf16(name.as_slice())?,
address: None,
})
}

pub fn domain(&self) -> &str {
self.domain.as_str()
}
Expand Down
6 changes: 3 additions & 3 deletions heim-process/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ github-actions = { repository = "heim-rs/heim", workflow = "Tier 1 CI" }
heim-common = { version = "0.1.0-alpha.1", path = "../heim-common" }
heim-runtime = { version = "0.1.0-alpha.1", path = "../heim-runtime", default-features = false }
heim-cpu = { version = "0.1.0-alpha.1", path = "../heim-cpu", default-features = false }
heim-host = { version = "0.1.0-alpha.1", path = "../heim-host", default-features = false }
cfg-if = "~0.1"
libc = "~0.2"
lazy_static = "1.3.0"
Expand All @@ -27,10 +28,8 @@ async-trait = "~0.1"

[target.'cfg(target_os = "linux")'.dependencies]
heim-net = { version = "0.1.0-alpha.1", path = "../heim-net", default-features = false }
heim-host = { version = "0.1.0-alpha.1", path = "../heim-host", default-features = false }

[target.'cfg(target_os = "windows")'.dependencies]
heim-host = { version = "0.1.0-alpha.1", path = "../heim-host", default-features = false }
ntapi = "0.3.3"

[target.'cfg(target_os = "windows")'.dependencies.winapi]
Expand All @@ -45,7 +44,8 @@ features = [
"psapi",
"processthreadsapi",
"winerror",
"tlhelp32"
"tlhelp32",
"securitybaseapi"
]

[target.'cfg(target_os = "macos")'.dependencies]
Expand Down
6 changes: 6 additions & 0 deletions heim-process/src/process/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use std::time::Instant;

use heim_common::prelude::*;
use heim_common::units::Time;
use heim_host::User;

use crate::{sys, Pid, ProcessResult};

Expand Down Expand Up @@ -165,6 +166,11 @@ impl Process {
self.as_ref().memory().await.map(Into::into)
}

/// Returns user who owns this process.
pub async fn user(&self) -> ProcessResult<User> {
self.as_ref().user().await.map(Into::into)
}

/// Checks if this `Process` is still running.
pub async fn is_running(&self) -> ProcessResult<bool> {
self.as_ref().is_running().await
Expand Down
9 changes: 9 additions & 0 deletions heim-process/src/sys/linux/process/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use std::path::{Path, PathBuf};

use heim_common::prelude::*;
use heim_common::units::Time;
use heim_host::User;
use heim_runtime as rt;

use super::{pid_exists, pids};
Expand Down Expand Up @@ -122,6 +123,14 @@ impl Process {
procfs::stat_memory(self.pid).await
}

pub async fn user(&self) -> ProcessResult<User> {
// TODO: implement
// 1. Read `/proc/{pid}/stat` or smth else
// 2. parse uid and gid
// 3. Construct `heim_host::User` from them
unimplemented!("https://github.com/heim-rs/heim/issues/194")
}

pub async fn is_running(&self) -> ProcessResult<bool> {
let other = get(self.pid).await?;

Expand Down
7 changes: 7 additions & 0 deletions heim-process/src/sys/macos/process/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use futures::future::BoxFuture;
use heim_common::prelude::*;
use heim_common::sys::IntoTime;
use heim_common::units::Time;
use heim_host::User;

use super::{bindings, pids, utils::catch_zombie};
use crate::os::unix::Signal;
Expand Down Expand Up @@ -114,6 +115,12 @@ impl Process {
}
}

pub async fn user(&self) -> ProcessResult<User> {
// Fetch user infomation with `darwin_libproc` help,
// construct user from this information somehow.
unimplemented!("https://github.com/heim-rs/heim/issues/194")
}

pub async fn is_running(&self) -> ProcessResult<bool> {
let other = get(self.pid).await?;

Expand Down
6 changes: 6 additions & 0 deletions heim-process/src/sys/windows/bindings/handle/limited_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ use winapi::um::{processthreadsapi, psapi, winbase, winnt};
use heim_common::sys::IntoTime;
use heim_common::units::{time, Time};
use heim_common::Error;
use heim_host::User;

use super::super::token::Token;
use super::{ProcessHandle, ProcessHandlePermissions};
use crate::sys::windows::process::CpuTime;
use crate::{Pid, ProcessError, ProcessResult};
Expand Down Expand Up @@ -139,4 +141,8 @@ impl ProcessHandle<QueryLimitedInformation> {
Ok((creation, exit, kernel, user))
}
}

pub fn owner(&self) -> ProcessResult<User> {
Token::open(&self.handle)?.user().map_err(Into::into)
}
}
1 change: 1 addition & 0 deletions heim-process/src/sys/windows/bindings/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use heim_common::{Error, Result};
pub mod handle;
pub mod processes;
pub mod snapshot;
pub mod token;

pub use self::handle::ProcessHandle;

Expand Down
52 changes: 52 additions & 0 deletions heim-process/src/sys/windows/bindings/token.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
use std::mem;
use std::ptr;
use winapi::shared::minwindef::{DWORD, LPVOID};
use winapi::um::processthreadsapi::OpenProcessToken;
use winapi::um::securitybaseapi::GetTokenInformation;
use winapi::um::winnt::{TokenUser, HANDLE, TOKEN_QUERY, TOKEN_USER};

use heim_common::prelude::*;
use heim_common::sys::windows::Handle;
use heim_common::Result;
use heim_host::os::windows::UserExt;
use heim_host::User;

pub struct Token(Handle);

impl Token {
pub fn open(process_handle: &Handle) -> Result<Self> {
let mut token_handle: HANDLE = ptr::null_mut();
sandorex marked this conversation as resolved.
Show resolved Hide resolved

let result = unsafe { OpenProcessToken(**process_handle, TOKEN_QUERY, &mut token_handle) };

if result == 0 {
return Err(Error::last_os_error().with_ffi("OpenProcessToken"));
}

Ok(Self(Handle::new(token_handle)))
}

pub fn user(&self) -> Result<User> {
let mut data = mem::MaybeUninit::<TOKEN_USER>::uninit();
let mut length: DWORD = 0;

let result = unsafe {
GetTokenInformation(
*self.0,
TokenUser,
data.as_mut_ptr() as LPVOID,
// data should always be 44 bytes
44,
&mut length,
)
};

if result == 0 {
return Err(Error::last_os_error().with_ffi("GetTokenInformation"));
}

let token_user = unsafe { data.assume_init() };

User::try_from_sid(token_user.User.Sid)
}
}
11 changes: 11 additions & 0 deletions heim-process/src/sys/windows/process/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use std::path::PathBuf;

use heim_common::prelude::*;
use heim_common::units::Time;
use heim_host::User;
use winapi::um::processthreadsapi;

use super::{bindings, pid_exists, pids};
Expand Down Expand Up @@ -142,6 +143,16 @@ impl Process {
}
}

pub async fn user(&self) -> ProcessResult<User> {
if self.pid == 0 || self.pid == 4 {
Err(ProcessError::AccessDenied(self.pid))
} else {
let handle = bindings::ProcessHandle::query_limited_info(self.pid)?;

handle.owner()
}
}

pub async fn is_running(&self) -> ProcessResult<bool> {
let other = get(self.pid).await?;

Expand Down
1 change: 1 addition & 0 deletions heim-process/tests/smoke.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ async fn smoke_processes() {
let _ = process.pid();
try_method!(process.parent_pid());
try_method!(process.name());
try_method!(process.user());
try_method!(process.command());
try_method!(process.exe());
#[cfg(not(target_os = "windows"))] // Not implemented yet
Expand Down