1use std::ffi::CString;
8
9#[allow(unused)]
10use winapi::um::synchapi::{CreateMutexA, ReleaseMutex, WaitForSingleObject};
11use winapi::um::winnt::HANDLE;
12use std::io::Write;
13use std::net::TcpStream;
14pub type MutexHandle = HANDLE;
15pub enum ResultCode {
16 Ok,
17 Abandoned = winapi::um::winbase::WAIT_ABANDONED as isize,
18}
19
20use std::process::{Command, Stdio};
21use std::thread::sleep;
22
23pub fn powershell_message_box_non_blocking(message: &str) {
24 let title = "UNPISPAS SERVICIO IMPRESION";
25 let command = format!(
26 "[reflection.assembly]::LoadWithPartialName('System.Windows.Forms')|out-null;[windows.forms.messagebox]::Show('{}', '{}')",
27 message, title
28 );
29
30 let result = Command::new("powershell")
31 .arg("-WindowStyle")
32 .arg("Hidden")
33 .arg("-Command")
34 .arg(command)
35 .stdout(Stdio::null())
36 .stderr(Stdio::piped())
37 .spawn();
38
39 if let Err(e) = result {
40 tracing::error!("Error al ejecutar el comando PowerShell: {}", e);
41 }
42}
43
44pub fn create_mutex(name: &str) -> MutexHandle {
45 unsafe {
46 let mutex_name = CString::new(name).unwrap();
47 CreateMutexA(std::ptr::null_mut(), 1, mutex_name.as_ptr())
48 }
49}
50
51pub unsafe fn close_handle(handle: MutexHandle) {
52 unsafe {
53 winapi::um::handleapi::CloseHandle(handle);
54 }
55}
56
57pub fn send_messagebox_to_tray(message: String) -> crate::PisPasResult<()> {
58 match TcpStream::connect(crate::CHANNEL_NAME) {
59 Ok(mut stream) => {
60 let action = crate::service::Action::MessageBox(message);
62 match stream.write_all(action.to_string().as_bytes()) {
63 Ok(_) => {
64 tracing::info!("Message sent: {}", action.to_string());
65 return Ok(());
66 }
67 Err(e) => {
68 tracing::error!("Failed to write to socket in dedicated thread {}", e);
69 return Err(anyhow::anyhow!("Failed to write to socket in dedicated thread {}", e));
70 }
71 }
72 }
73 Err(e) => {
74 tracing::error!("Error connecting to pispas-channel: {}", e);
75 }
76 }
77 Ok(())
78}
79
80pub fn stop_pispas_modules() -> crate::PisPasResult<()> {
81 match TcpStream::connect(crate::CHANNEL_NAME) {
82 Ok(mut stream) => {
83 match stream.write_all(crate::service::Action::Stop.to_string().as_bytes()) {
84 Ok(_) => {
85 tracing::info!("Message sent: {}", crate::service::Action::Stop.to_string());
86 return Ok(());
87 }
88 Err(e) => {
89 tracing::error!("Failed to write to socket in dedicated thread {}", e);
90 return Err(anyhow::anyhow!("Failed to write to socket in dedicated thread {}", e));
91 }
92 }
93 }
94 Err(e) => {
95 tracing::error!("Error connecting to pispas-channel: {}", e);
96 }
97 }
98 sleep(std::time::Duration::from_secs(1));
99 Ok(())
100}
101
102pub unsafe fn wait_for_single_object(handle: MutexHandle, timeout: u32) -> ResultCode {
103 let code = unsafe { WaitForSingleObject(handle, timeout) };
104 if !(code == winapi::um::winbase::WAIT_ABANDONED || code == winapi::um::winbase::WAIT_OBJECT_0) {
105 ResultCode::Abandoned
106 } else {
107 ResultCode::Ok
108 }
109}
110
111pub unsafe fn release_mutex(handle: MutexHandle) {
112 unsafe { ReleaseMutex(handle) };
113}
114
115#[allow(non_camel_case_types, non_snake_case)]
116#[cfg(target_os = "windows")]
117pub mod native {
118 use std::{
119 ffi::CString,
120 ptr::null_mut,
121 thread::sleep,
122 time::Duration,
123 };
124 use widestring::WideCString;
125 use winapi::{
126 shared::minwindef::{BOOL, DWORD},
127 um::{
128 handleapi::CloseHandle,
129 processthreadsapi::{CreateProcessAsUserW, OpenProcess},
130 winbase::{CREATE_UNICODE_ENVIRONMENT},
131 winnt::{HANDLE, PROCESS_ALL_ACCESS, PROCESS_SUSPEND_RESUME},
132 },
133 };
134 use windows_sys::Win32::System::Environment::{
135 CreateEnvironmentBlock, DestroyEnvironmentBlock,
136 };
137 use windows_sys::Win32::Foundation::GetLastError;
138 use std::ptr;
139 use std::ffi::OsStr;
140 use std::os::windows::ffi::OsStrExt;
141 use winapi::um::winbase::WTSGetActiveConsoleSessionId;
142 use std::ffi::c_void; const WTS_CURRENT_SERVER_HANDLE: HANDLE = null_mut();
145 const WTS_USER_NAME: DWORD = 5;
146
147 #[repr(C)]
148 struct WTS_SESSION_INFO {
149 SessionId: DWORD,
150 pWinStationName: *mut u16,
151 State: DWORD,
152 }
153
154 enum WTSSessionState {
155 WTSActive = 0,
156 WTSConnected = 1,
157 WTSDisconnected = 4,
158 }
159
160 #[link(name = "wtsapi32")]
161 extern "system" {
162 fn LoadLibraryA(lpFileName: *const i8) -> HANDLE;
163 fn GetProcAddress(hModule: HANDLE, lpProcName: *const i8) -> *mut c_void;
164 fn FreeLibrary(hLibModule: HANDLE) -> BOOL;
165 fn WTSQueryUserToken(SessionId: DWORD, phToken: *mut HANDLE) -> BOOL;
166 fn WTSQuerySessionInformationW(hServer: HANDLE, SessionId: DWORD, WTSInfoClass: DWORD, ppBuffer: *mut *mut u16, pBytesReturned: *mut DWORD) -> BOOL;
168 fn WTSFreeMemory(pMemory: *mut c_void);
169 }
170
171 fn load_wtsapi32_module() -> Result<HANDLE, &'static str> {
172 let library_name = CString::new("wtsapi32.dll").expect("CString::new failed");
173 let h_module = unsafe { LoadLibraryA(library_name.as_ptr()) };
174 if h_module.is_null() {
175 Err("Failed to load wtsapi32.dll")
176 } else {
177 Ok(h_module)
178 }
179 }
180
181 fn get_function_addresses(h_module: HANDLE) -> Result<
182 (
183 extern "system" fn(HANDLE, DWORD, DWORD, *mut *mut WTS_SESSION_INFO, *mut DWORD) -> BOOL,
184 extern "system" fn(HANDLE, DWORD, DWORD, *mut *mut c_void, *mut DWORD) -> BOOL
185 ),
186 &'static str
187 > {
188 let function_name = CString::new("WTSEnumerateSessionsW").unwrap();
189 let enum_sessions: Option<extern "system" fn(HANDLE, DWORD, DWORD, *mut *mut WTS_SESSION_INFO, *mut DWORD) -> BOOL> = unsafe {
190 std::mem::transmute(GetProcAddress(h_module, function_name.as_ptr()))
191 };
192
193 let function_name_cstr = CString::new("WTSQuerySessionInformationW").unwrap();
194 let query_session: Option<extern "system" fn(HANDLE, DWORD, DWORD, *mut *mut c_void, *mut DWORD) -> BOOL> = unsafe {
195 std::mem::transmute(GetProcAddress(h_module, function_name_cstr.as_ptr()))
196 };
197
198 match (enum_sessions, query_session) {
199 (Some(enumerate_sessions_func), Some(query_session_func)) => Ok((enumerate_sessions_func, query_session_func)),
200 _ => Err("Failed to get procedure addresses.")
201 }
202 }
203
204 fn to_wide_cstring(value: &str) -> WideCString {
205 WideCString::from_str(value).unwrap()
206 }
207
208 fn create_command_line_wide(executable_path: &str, script_path: &str) -> WideCString {
209 let cmd = format!("\"{}\" \"{}\"", executable_path.trim_end_matches('\\'), script_path);
210 WideCString::from_str(&cmd).unwrap()
211 }
212
213 fn wait_for_user_session(session_id: DWORD) -> anyhow::Result<()> {
214 loop {
215 let state = query_session_state(session_id)?;
216 if state == WTSSessionState::WTSActive as DWORD {
217 return Ok(()); }
219 sleep(Duration::from_millis(500));
220 }
221 }
222
223 fn query_session_state(session_id: DWORD) -> anyhow::Result<DWORD> {
224 let mut p_buffer: *mut u16 = null_mut();
225 let mut bytes_returned: DWORD = 0;
226
227 unsafe {
228 let success = WTSQuerySessionInformationW(
229 WTS_CURRENT_SERVER_HANDLE,
230 session_id,
231 0, &mut p_buffer,
233 &mut bytes_returned,
234 );
235
236 if success == 0 {
237 return Err(anyhow::anyhow!("Failed to query session information"));
238 }
239
240 let state = *p_buffer as DWORD;
241 WTSFreeMemory(p_buffer as *mut c_void);
242 Ok(state)
243 }
244 }
245
246 fn wait_for_any_active_session(enumerate_sessions_func: extern "system" fn(HANDLE, DWORD, DWORD, *mut *mut WTS_SESSION_INFO, *mut DWORD) -> BOOL) -> anyhow::Result<()> {
247 loop {
248 let mut session_info_ptr: *mut WTS_SESSION_INFO = null_mut();
249 let mut session_count: DWORD = 0;
250
251 let success = enumerate_sessions_func(
252 WTS_CURRENT_SERVER_HANDLE,
253 0,
254 1,
255 &mut session_info_ptr,
256 &mut session_count,
257 );
258
259 if success != 0 {
260 unsafe {
261 for i in 0..session_count {
262 let session = session_info_ptr.offset(i as isize);
263
264 if (*session).State == WTSSessionState::WTSActive as u32 {
265 return Ok(()); }
267 }
268 }
269 }
270 sleep(Duration::from_secs(1));
271 }
272 }
273
274 fn launch_process_for_user(executable_path: &str, command_line: &str, session_id: DWORD) -> Option<HANDLE> {
275 unsafe {
276 if let Err(e) = wait_for_user_session(session_id) {
277 tracing::error!("Failed to wait for user session: {}", e);
278 return None;
279 }
280
281 sleep(Duration::from_secs(1));
283
284 let mut user_token: HANDLE = null_mut();
285 if WTSQueryUserToken(session_id, &mut user_token) != 0 {
286 let exe_path_wide = to_wide_cstring(executable_path);
287 let cmd_line_wide = create_command_line_wide(executable_path, command_line);
288 let path_current_dir_wide = to_wide_cstring(&crate::paths::bin_dir().display().to_string());
289
290 tracing::info!("Executable path: {}", executable_path);
291 tracing::info!("Command line: {:?}", cmd_line_wide);
292
293 let mut startup_info = std::mem::zeroed::<winapi::um::processthreadsapi::STARTUPINFOW>();
294 startup_info.cb = std::mem::size_of::<winapi::um::processthreadsapi::STARTUPINFOW>() as u32;
295
296 let desktop_name_wide: Box<Vec<u16>> = Box::new(to_wide_string("WinSta0\\Default"));
297 startup_info.lpDesktop = desktop_name_wide.as_ptr() as *mut u16;
298
299 let mut environment_block: *mut c_void = std::ptr::null_mut();
300 if CreateEnvironmentBlock(&mut environment_block, user_token as *mut c_void, 1) == 0 {
302 let error_code = GetLastError();
303 tracing::error!("Failed to create environment block for user. Error code: {}", error_code);
304 CloseHandle(user_token);
305 return None;
306 }
307
308 let _keep_alive = desktop_name_wide; let mut process_info = std::mem::zeroed::<winapi::um::processthreadsapi::PROCESS_INFORMATION>();
311 tracing::info!("exe_path: {:?}, command_line: {:?}, path_current_dir: {:?}", cmd_line_wide, cmd_line_wide, path_current_dir_wide);
312
313
314 let success = CreateProcessAsUserW(
315 user_token,
316 exe_path_wide.as_ptr() as *mut u16,
317 cmd_line_wide.as_ptr() as *mut u16,
318 null_mut(),
319 null_mut(),
320 0,
321 CREATE_UNICODE_ENVIRONMENT,
322 environment_block as *mut winapi::ctypes::c_void,
323 path_current_dir_wide.as_ptr() as *mut u16,
324 &mut startup_info,
325 &mut process_info,
326 );
327
328 if success != 0 {
329 CloseHandle(user_token);
330 DestroyEnvironmentBlock(environment_block);
331 return Some(process_info.hProcess);
332 } else {
333 let error_code = GetLastError();
334 tracing::error!("CreateProcessAsUserW failed: Error code = {}", error_code);
335 }
336 DestroyEnvironmentBlock(environment_block);
337 CloseHandle(user_token);
338 } else {
339 let error_code = GetLastError();
340 tracing::error!("WTSQueryUserToken failed for session {}: Error code = {}", session_id, error_code);
341 }
342 }
343
344 None
345 }
346
347 fn enumerate_and_launch(
348 executable_path: &str,
349 command_line: &str,
350 all_users: bool,
351 first_execution: bool,
352 enumerate_sessions_func: extern "system" fn(HANDLE, DWORD, DWORD, *mut *mut WTS_SESSION_INFO, *mut DWORD) -> BOOL,
353 query_session_func: extern "system" fn(HANDLE, DWORD, DWORD, *mut *mut c_void, *mut DWORD) -> BOOL
354 ) -> crate::PisPasResult<Option<HANDLE>> {
355 wait_for_any_active_session(enumerate_sessions_func)?;
356
357 let mut session_info_ptr: *mut WTS_SESSION_INFO = null_mut();
358 let mut session_count: DWORD = 0;
359
360 let success = enumerate_sessions_func(
361 WTS_CURRENT_SERVER_HANDLE,
362 0,
363 1,
364 &mut session_info_ptr,
365 &mut session_count,
366 );
367
368 if success != 0 {
369 tracing::info!("Found {} sessions.", session_count);
370 unsafe {
371 for i in 0..session_count {
372 if session_info_ptr.is_null() {
373 return Err(anyhow::anyhow!("Session info pointer is null"));
374 }
375 let session = session_info_ptr.offset(i as isize);
376
377 if (*session).State == WTSSessionState::WTSActive as u32 ||
378 (*session).State == WTSSessionState::WTSConnected as u32 ||
379 (*session).State == WTSSessionState::WTSDisconnected as u32 {
380 let mut data: *mut c_void = null_mut();
381 let mut bytes: DWORD = 0;
382
383 if query_session_func(WTS_CURRENT_SERVER_HANDLE, (*session).SessionId, WTS_USER_NAME, &mut data, &mut bytes) != 0 {
384 let user_name: *const u16 = data as *const u16;
385 let user_slice = std::slice::from_raw_parts(user_name, bytes as usize / 2);
386 match String::from_utf16(user_slice) {
387 Ok(mut user) => {
388 user = user.trim_end_matches('\0').to_string(); if !user.trim().is_empty() && (*session).SessionId != 0 {
390 tracing::info!("Session {}: User = {}", (*session).SessionId, user);
391 let bin_dir = crate::paths::bin_dir().display().to_string();
392 tracing::info!("bin_dir: {}", bin_dir);
393 if first_execution {
394 if let Err(e) = set_permissions_robust(&bin_dir, &user) {
395 tracing::error!("Failed to set permissions for user {}: {}", user, e);
396 } else {
397 tracing::info!("Permissions set for user {}", user);
398 sleep(Duration::from_secs(1));
399 }
400 }
401
402 if let Some(process_handle) = launch_process_for_user(executable_path, command_line, (*session).SessionId) {
403 tracing::info!("Process launched for user {}", user);
404 if !all_users {
405 return Ok(Some(process_handle));
406 }
407 } else {
408 tracing::error!("Failed to launch process for user {}", user);
409 }
410 } else {
411 tracing::warn!("Ignoring session {}: User name is empty or session ID is 0", (*session).SessionId);
412 }
413 }
414 Err(e) => {
415 tracing::info!("Failed to convert UTF-16 to string: {}", e);
416 return Err(anyhow::anyhow!("Error converting UTF-16 to string"));
417 }
418 }
419 }
420 }
421 }
422 }
423 } else {
424 return Err(anyhow::anyhow!("Error enumerate_sessions_func"));
425 }
426 Ok(None)
427 }
428 fn to_wide_string(s: &str) -> Vec<u16> {
430 OsStr::new(s).encode_wide().chain(Some(0)).collect()
431 }
432 struct WideString {
433 inner: Vec<u16>,
434 }
435
436 impl WideString {
437 pub fn new(s: &str) -> Self {
438 Self {
439 inner: to_wide_string(s),
440 }
441 }
442
443 pub fn as_ptr(&self) -> *const u16 {
444 self.inner.as_ptr()
445 }
446 }
447 pub fn launch_process_as_logged_in_user(executable_path: &str, command_line: &str, first_launch: bool) -> crate::PisPasResult<Option<HANDLE>> {
449 let mut attempts = 0;
450 let user = loop {
451 if attempts >= 20 {
452 return Err(anyhow::anyhow!("No user found logged in after multiple attempts."));
453 }
454
455 let output = std::process::Command::new("powershell")
456 .args(&["-Command", "(Get-WmiObject -Class Win32_ComputerSystem).UserName"])
457 .output()
458 .map_err(|e| anyhow::anyhow!("Failed to execute PowerShell command to get logged in user: {}", e))?;
459
460 if output.status.success() {
461 let user = String::from_utf8_lossy(&output.stdout).trim().to_string();
462 if !user.is_empty() {
463 break user;
464 } else {
465 tracing::error!("No user found logged in, retrying...");
466 }
467 } else {
468 let stderr = String::from_utf8_lossy(&output.stderr);
469 tracing::error!("Error getting logged in user: {}, retrying...", stderr);
470 }
471
472 attempts += 1;
473 sleep(Duration::from_secs(1));
474 };
475
476
477 tracing::info!("Logged in user: {}", user);
478 let username = user.split('\\').last().unwrap_or(&user);
479 tracing::info!("Extracted username: {}", username);
480
481 if first_launch{
483 if let Err(e) = set_permissions_robust(executable_path, &username) {
484 tracing::error!("Failed to set permissions for user {}: {}", user, e);
485 } else {
486 tracing::info!("Permissions set for user {}", user);
487 sleep(Duration::from_secs(1));
488 }
489 }
490
491 let session_id = unsafe { WTSGetActiveConsoleSessionId() };
493 if session_id == u32::MAX {
494 let error_code = unsafe { GetLastError() };
495 tracing::error!("Failed to get active session ID: {}", error_code);
496 return Err(anyhow::anyhow!("Failed to get active session ID: {}", error_code));
497 }
498
499 let mut user_token: HANDLE = ptr::null_mut();
500 if unsafe { WTSQueryUserToken(session_id, &mut user_token) } == 0 {
501 let error_code = unsafe { GetLastError() };
502 tracing::error!("Failed to get user token: {}", error_code);
503 return Err(anyhow::anyhow!("Failed to get user token: {}", error_code));
504 }
505
506 let full_command = format!("\"{}\" \"{}\"", executable_path, command_line);
507 let command_utf16 = OsStr::new(&full_command).encode_wide().chain(Some(0)).collect::<Vec<u16>>();
508
509 if first_launch {
510 sleep(Duration::from_secs(4));
511 }
512 let mut startup_info = unsafe { std::mem::zeroed::<winapi::um::processthreadsapi::STARTUPINFOW>() };
513 startup_info.cb = std::mem::size_of::<winapi::um::processthreadsapi::STARTUPINFOW>() as u32;
514 let desktop_name = WideString::new("WinSta0\\Default");
515 startup_info.lpDesktop = desktop_name.as_ptr() as *mut u16;
516
517 let mut process_info = unsafe { std::mem::zeroed::<winapi::um::processthreadsapi::PROCESS_INFORMATION>() };
519
520 let success = unsafe {
522 CreateProcessAsUserW(
523 user_token,
524 ptr::null(),
525 command_utf16.as_ptr() as *mut _,
526 ptr::null_mut(),
527 ptr::null_mut(),
528 0,
529 CREATE_UNICODE_ENVIRONMENT,
530 ptr::null_mut(),
531 ptr::null(),
532 &mut startup_info,
533 &mut process_info,
534 )
535 };
536
537 unsafe { CloseHandle(user_token) };
538
539 if success == 0 {
540 let error_code = unsafe { GetLastError() };
541 tracing::error!("Failed to launch process: {}", error_code);
542 Err(anyhow::anyhow!("Failed to launch process: {}", error_code))
543 } else {
544 tracing::info!("Process launched successfully in the context of the logged-in user.");
545 Ok(Some(process_info.hProcess))
546 }
547 }
548
549 pub fn run_in_all_sessions(executable_path: &str, command_line: &str, all_user: bool, first_execution: bool) -> crate::PisPasResult<Option<HANDLE>> {
550 match load_wtsapi32_module() {
551 Ok(h_module) => {
552 match get_function_addresses(h_module) {
553 Ok((enumerate_sessions_func, query_session_func)) => {
554 tracing::info!("Enumerating sessions...");
555 let result = enumerate_and_launch(executable_path, command_line, all_user, first_execution, enumerate_sessions_func, query_session_func);
556 unsafe { FreeLibrary(h_module); }
557 result
558 }
559 Err(e) => {
560 unsafe { FreeLibrary(h_module); }
561 tracing::error!("{}", e);
562 Err(anyhow::anyhow!("Error getting function addresses"))
563 }
564 }
565 }
566 Err(e) => {
567 tracing::error!("error {}", e);
568 Err(anyhow::anyhow!("Error loading wtsapi32 module"))
569 }
570 }
571 }
572
573 pub fn open_process(pid: u32) -> Option<HANDLE> {
574 let desired_access = PROCESS_ALL_ACCESS | PROCESS_SUSPEND_RESUME;
575 let process_handle = unsafe { OpenProcess(desired_access, 0, pid) };
576
577 if process_handle.is_null() {
578 unsafe {
579 tracing::info!("Error obtaining process handle. Error: {}", GetLastError());
580 }
581 None
582 } else {
583 tracing::info!("Process handle: {:?}", process_handle);
584 Some(process_handle)
585 }
586 }
587
588 pub fn set_permissions_robust(path: &str, user: &str) -> Result<(), String> {
590 let user = user.trim_end_matches('\0');
591 let path = path.trim_end_matches('\0');
592
593 let powershell_script = format!(
594 r#"
595 try {{
596 $path = '{}'
597 $user = '{}'
598 $successCount = 0
599 $errorCount = 0
600
601 # Set permissions on root folder first
602 try {{
603 $acl = Get-Acl $path
604 $rule = New-Object System.Security.AccessControl.FileSystemAccessRule($user,'FullControl','ContainerInherit,ObjectInherit','None','Allow')
605 $acl.SetAccessRule($rule)
606 Set-Acl $path $acl
607 $successCount++
608 Write-Output "Root permissions set: $path"
609 }} catch {{
610 $errorCount++
611 Write-Warning "Failed to set root permissions: $($_.Exception.Message)"
612 }}
613
614 # Process all child items
615 Get-ChildItem -Path $path -Recurse -Force -ErrorAction SilentlyContinue | ForEach-Object {{
616 try {{
617 $acl = Get-Acl $_.FullName
618 $rule = New-Object System.Security.AccessControl.FileSystemAccessRule($user,'FullControl','ContainerInherit,ObjectInherit','None','Allow')
619 $acl.SetAccessRule($rule)
620 Set-Acl $_.FullName $acl
621 $successCount++
622 }} catch {{
623 $errorCount++
624 Write-Warning "Failed: $($_.FullName) - $($_.Exception.Message)"
625 }}
626 }}
627
628 Write-Output "Completed: $successCount successful, $errorCount errors"
629 }} catch {{
630 Write-Error $_.Exception.Message
631 exit 1
632 }}
633 "#,
634 path, user
635 );
636
637 tracing::info!("Executing robust recursive permissions for: {}", path);
638
639 let output = std::process::Command::new("powershell")
640 .args(&["-ExecutionPolicy", "Bypass", "-Command", &powershell_script])
641 .output()
642 .expect("Failed to execute process");
643
644 let stdout = String::from_utf8_lossy(&output.stdout).to_string();
645 let stderr = String::from_utf8_lossy(&output.stderr).to_string();
646
647 tracing::info!("robust_permissions stdout: {}", stdout);
648 if !stderr.is_empty() {
649 tracing::warn!("robust_permissions stderr: {}", stderr);
650 }
651
652 if !output.status.success() {
653 return Err(format!("Failed to set robust permissions: {}", stderr));
654 }
655
656 Ok(())
657 }
658 pub fn set_permissions_for_user(path: &str, user: &str) -> Result<(), String> {
659 let user = user.trim_end_matches('\0');
660 let path = path.trim_end_matches('\0');
661 let powershell_script = format!(
662 r#"
663 try {{
664 $path = '{}'
665 $user = '{}'
666 $acl = Get-Acl $path
667 $rule = New-Object System.Security.AccessControl.FileSystemAccessRule($user,'FullControl','None','None','Allow')
668 $acl.SetAccessRule($rule)
669 Set-Acl $path $acl
670 Write-Output "Permissions set successfully"
671 }} catch {{
672 Write-Error $_.Exception.Message
673 }}
674 "#,
675 path, user
676 );
677
678 tracing::info!("powershell_script: {:?}", powershell_script);
679
680 let output = std::process::Command::new("powershell")
681 .args(&["-Command", &powershell_script])
682 .output()
683 .expect("Failed to execute process");
684
685 let stdout = String::from_utf8_lossy(&output.stdout).to_string();
686 let stderr = String::from_utf8_lossy(&output.stderr).to_string();
687
688 tracing::info!("set_permissions_for_user stdout: {}", stdout);
689 tracing::info!("set_permissions_for_user stderr: {}", stderr);
690
691 if !output.status.success() {
692 return Err(format!("Failed to set permissions: {}", stderr));
693 }
694
695 Ok(())
696 }
697}
698
699pub fn get_name_service() -> String {
700 let path = match std::env::current_exe() {
701 Ok(path) => path,
702 Err(e) => {
703 println!("Error al obtener el nombre del archivo ejecutable: {:?}", e);
704 return "ServiceDefault".to_string();
705 }
706 };
707 let name = match path.file_name() {
708 Some(name_without_extension) => name_without_extension.to_str().unwrap(),
709 None => {
710 println!("Error al obtener el nombre del archivo ejecutable");
711 return "ServiceDefault".to_string();
712 }
713 };
714 let _name_without_extension = name.replace(".exe", "");
715 _name_without_extension.to_string()
716}