sharing/
proc.rs

1/*
2 * Authors: Jorge.A Duran & Mario Gónzalez
3 * Company: pispas Technologies SL
4 * Date: April 23, 2023
5 * Description: Sharing Process function definition and implementation for web-driver.
6 */
7use std::fmt::Display;
8use std::sync::Mutex;
9use lazy_static::lazy_static;
10use sysinfo::{Signal, System};
11
12#[cfg(target_os = "windows")]
13use sysinfo::{Pid};
14
15#[cfg(target_os = "windows")]
16use winreg::RegKey;
17#[cfg(target_os = "windows")]
18use winreg::enums::{KEY_READ, HKEY_USERS};
19pub type ProcResult<T> = crate::PisPasResult<T>;
20
21#[derive(Debug, Default, Clone)]
22pub struct UserInfo {
23    pub pid: u32,
24    pub sesion_id: u32,
25    pub sid: String,
26    pub username: String,
27    pub userprofile: String,
28    pub desktop: String,
29    pub path: String,
30    pub tmp_path: String,
31}
32impl Display for UserInfo {
33    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
34        write!(f, "pid: {}, sid: {}, username: {}, userprofile: {}, desktop: {}, path: {}", self.pid, self.sid, self.username, self.userprofile, self.desktop, self.path)
35    }
36}
37
38/// Kill process by name
39/// cross platform
40pub fn kill_process_by_name(name: &str)  {
41    let mut system = System::new_all();
42    system.refresh_processes();
43
44    // let process_to_kill = system.processes_by_name(name);
45
46    for process in system.processes_by_name(name) {
47        tracing::info!("{} {}", process.pid(), process.name());
48        if process.kill_with(Signal::Kill).is_none() {
49            tracing::error!("This signal isn't supported on this platform");
50        }
51    }
52}
53
54#[cfg(target_os = "windows")]
55fn get_user_desktop(sid: &str) -> ProcResult<String> {
56    let pispas_users = RegKey::predef(HKEY_USERS);
57    let full_key_path = format!(r"{}\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders", sid);
58
59    match pispas_users.open_subkey_with_flags(&full_key_path, KEY_READ) {
60        Ok(profiles_key) => {
61            if let Ok(desktop_path) = profiles_key.get_value("Desktop") {
62                return Ok(desktop_path);
63            }
64        }
65        Err(e) => {
66            tracing::error!("Error opening user's Shell Folders key: {}", e);
67            return Err(e.into());
68        }
69    }
70    Err(anyhow::anyhow!("Error getting user's desktop path"))
71}
72
73#[cfg(target_os = "windows")]
74pub fn get_temp(sid: &str, userprofile: &str) -> ProcResult<String> {
75    let pispas_users = RegKey::predef(HKEY_USERS);
76    match pispas_users.open_subkey_with_flags(&format!(r"{}\{}", sid, crate::ENVIRONMENT), KEY_READ) {
77        Ok(enviroment_key) => {
78            if let Ok(temp_path) = enviroment_key.get_value::<String, &str>(crate::TMP_KEY) {
79                let temp_path = temp_path.replace(format!("%{}%", crate::USER_PROFILE_KEY).as_str(), userprofile);
80                tracing::info!("temp_path: {}", temp_path);
81                return Ok(temp_path);
82            }
83        }
84        Err(e) => {
85            tracing::error!("Error opening user's Shell Folders key: {}", e);
86            return Err(e.into());
87        }
88    }
89    Err(anyhow::anyhow!("Error getting user's temp path"))
90}
91
92#[cfg(target_os = "windows")]
93pub fn get_user_profile(sid: &str) -> ProcResult<String> {
94    let pispas_users = RegKey::predef(HKEY_USERS);
95
96    match pispas_users.open_subkey_with_flags(&format!(r"{}\{}", sid, crate::VOLATILE_ENVIRONMENT), KEY_READ) {
97        Ok(profiles_key) => {
98            if let Ok(userprofile) = profiles_key.get_value::<String, &str>(crate::USER_PROFILE_KEY) {
99                return Ok(userprofile);
100            }
101        }
102        Err(e) => {
103            tracing::error!("Error opening user's Volatile Environment key: {}", e);
104            return Err(e.into());
105        }
106    }
107    Err(anyhow::anyhow!("Error getting user's userprofile path"))
108}
109
110#[cfg(target_os = "windows")]
111pub fn get_parent_pid(pid: u32) -> Pid {
112    let system = System::new_all();
113    if let Some(process) = system.process(Pid::from_u32(pid)) {
114        process.parent().map_or(Pid::from_u32(0) , |parent| parent)
115    } else {
116        Pid::from_u32(0)
117    }
118}
119#[cfg(target_os = "windows")]
120pub fn get_parent_info(pid: u32) -> ProcResult<UserInfo> {
121    let system = System::new_all();
122    let mut user_info = UserInfo::default();
123    let parent_pid = get_parent_pid(pid);
124    tracing::info!("tray get_parent_info: {}", parent_pid);
125    match system.process(parent_pid) {
126        Some(pparent) => {
127            if let Some(sid) = pparent.user_id() {
128                user_info.sid = sid.to_string();
129            }
130            if let Some(sesion_id) = pparent.session_id() {
131                user_info.sesion_id = sesion_id.as_u32();
132            }
133            tracing::info!("tray get_parent_info: {}", pparent.name());
134            match pparent.user_id() {
135                Some(sid) => {
136                    let sid = sid.to_string();
137                    user_info.pid = pparent.pid().as_u32();
138                    if let Ok(user_profile) = get_user_profile(sid.as_str()) {
139                        user_info.username = get_username_from_path(&user_profile).unwrap_or_default();
140                        user_info.userprofile = user_profile.clone();
141                        if let Ok(desktop) = get_user_desktop(sid.as_str()) {
142                            user_info.desktop = desktop.clone();
143                        }
144                        if let Ok(tmp_path) = get_temp(sid.as_str(), &user_profile) {
145                            user_info.tmp_path = tmp_path.clone();
146                        } else{
147                            user_info.tmp_path = std::env::temp_dir().to_str().unwrap_or_default().to_string();
148                        }
149                    }
150                    if let Ok(path) = get_process_path(user_info.pid) {
151                        tracing::info!("parent path => {}", path);
152                        user_info.path = path.clone();
153                    }
154                    tracing::info!("parent info => {:?}", user_info);
155                }
156                None => {
157                    tracing::error!("SID pparent not found");
158                }
159            }
160        }
161        None => {
162            tracing::error!("parent process not found");
163        }
164    }
165    tracing::info!("parent user_info => {:?}", user_info);
166    Ok(user_info)
167}
168
169#[cfg(target_os = "windows")]
170pub fn get_process_path(pid: u32) -> ProcResult<String>{
171    let system = System::new_all();
172    if let Some(process) = system.process(Pid::from_u32(pid)) {
173        if let Some(path) = process.exe().expect("Can't get process path").to_str().map(|s| s.to_string()) {
174                return Ok(path);
175        }
176        else{
177             return Err(anyhow::anyhow!("Error getting process path"));
178        }
179    } else {
180        Err(anyhow::anyhow!("Process not found"))
181    }
182}
183
184#[cfg(target_os = "windows")]
185pub fn get_username_from_path(path: &str) -> ProcResult<String> {
186    let username= std::path::Path::new(&path).file_name().unwrap().to_string_lossy().to_string();
187    return Ok(username);
188}
189lazy_static! {
190    static ref GRAND_FATHER_INFO: Mutex<Option<UserInfo>> = Mutex::new(None);
191}
192
193#[cfg(target_os = "windows")]
194pub fn get_gran_father_info() -> ProcResult<UserInfo> {
195    tracing::info!("call get_gran_father_info");
196    let mut info = GRAND_FATHER_INFO.lock().unwrap(); // Bloquea el Mutex para acceder de forma segura
197
198    if let Some(grand_father_info) = info.as_ref() {
199        // Si ya está inicializado, devuelve el valor
200        return Ok(grand_father_info.clone());
201    }
202
203    let mut pid = std::process::id();
204    tracing::info!("pid => {}", pid);
205
206    loop {
207        match get_parent_info(pid) {
208            Ok(parent_info) => {
209                if parent_info.pid != 0 {
210                    pid = parent_info.pid;
211
212                    // Compara el nombre del proceso
213                    if parent_info.path.contains("explorer.exe")
214                        || parent_info.path.contains("SystemSettings.exe")
215                        || parent_info.path.contains("services.exe")
216                    {
217                        // Actualiza el valor dentro del Mutex
218                        *info = Some(parent_info.clone());
219                        return Ok(parent_info);
220                    } else {
221                        tracing::info!("Parent Info => {:?}", parent_info);
222                    }
223                } else {
224                    // No se encontró un proceso padre
225                    return Err(anyhow::anyhow!("No parent process found"));
226                }
227            }
228            Err(e) => {
229                tracing::error!("Error getting parent info: {}", e);
230                return Err(e);
231            }
232        }
233    }
234}