use crate::logging; use crate::token::get_current_token_for_restriction; use crate::token::get_logon_sid_bytes; use crate::winutil::format_last_error; use crate::winutil::to_wide; use anyhow::Result; use rand::Rng; use rand::SeedableRng; use rand::rngs::SmallRng; use std::path::Path; use std::ffi::c_void; use std::ptr; use windows_sys::Win32::Foundation::CloseHandle; use windows_sys::Win32::Foundation::GetLastError; use windows_sys::Win32::Foundation::HLOCAL; use windows_sys::Win32::Foundation::ERROR_SUCCESS; use windows_sys::Win32::Foundation::LocalFree; use windows_sys::Win32::Security::Authorization::EXPLICIT_ACCESS_W; use windows_sys::Win32::Security::Authorization::GRANT_ACCESS; use windows_sys::Win32::Security::Authorization::SE_WINDOW_OBJECT; use windows_sys::Win32::Security::Authorization::SetEntriesInAclW; use windows_sys::Win32::Security::Authorization::SetSecurityInfo; use windows_sys::Win32::Security::Authorization::TRUSTEE_IS_SID; use windows_sys::Win32::Security::Authorization::TRUSTEE_IS_UNKNOWN; use windows_sys::Win32::Security::Authorization::TRUSTEE_W; use windows_sys::Win32::Security::DACL_SECURITY_INFORMATION; use windows_sys::Win32::System::StationsAndDesktops::CloseDesktop; use windows_sys::Win32::System::StationsAndDesktops::DESKTOP_CREATEMENU; use windows_sys::Win32::System::StationsAndDesktops::CreateDesktopW; use windows_sys::Win32::System::StationsAndDesktops::DESKTOP_CREATEWINDOW; use windows_sys::Win32::System::StationsAndDesktops::DESKTOP_DELETE; use windows_sys::Win32::System::StationsAndDesktops::DESKTOP_ENUMERATE; use windows_sys::Win32::System::StationsAndDesktops::DESKTOP_HOOKCONTROL; use windows_sys::Win32::System::StationsAndDesktops::DESKTOP_JOURNALPLAYBACK; use windows_sys::Win32::System::StationsAndDesktops::DESKTOP_JOURNALRECORD; use windows_sys::Win32::System::StationsAndDesktops::DESKTOP_READOBJECTS; use windows_sys::Win32::System::StationsAndDesktops::DESKTOP_READ_CONTROL; use windows_sys::Win32::System::StationsAndDesktops::DESKTOP_SWITCHDESKTOP; use windows_sys::Win32::System::StationsAndDesktops::DESKTOP_WRITE_DAC; use windows_sys::Win32::System::StationsAndDesktops::DESKTOP_WRITE_OWNER; use windows_sys::Win32::System::StationsAndDesktops::DESKTOP_WRITEOBJECTS; const DESKTOP_ALL_ACCESS: u32 = DESKTOP_READOBJECTS | DESKTOP_CREATEWINDOW | DESKTOP_CREATEMENU | DESKTOP_HOOKCONTROL | DESKTOP_JOURNALRECORD | DESKTOP_JOURNALPLAYBACK | DESKTOP_ENUMERATE | DESKTOP_WRITEOBJECTS | DESKTOP_SWITCHDESKTOP | DESKTOP_DELETE | DESKTOP_READ_CONTROL | DESKTOP_WRITE_DAC | DESKTOP_WRITE_OWNER; pub struct LaunchDesktop { _private_desktop: Option, startup_name: Vec, } impl LaunchDesktop { pub fn prepare(use_private_desktop: bool, logs_base_dir: Option<&Path>) -> Result { if use_private_desktop { let private_desktop = PrivateDesktop::create(logs_base_dir)?; let startup_name = to_wide(format!("Winsta0\\{}", private_desktop.name)); Ok(Self { _private_desktop: Some(private_desktop), startup_name, }) } else { Ok(Self { _private_desktop: None, startup_name: to_wide("Winsta0\\Default"), }) } } pub fn startup_info_desktop(&self) -> *mut u16 { self.startup_name.as_ptr() as *mut u16 } } struct PrivateDesktop { handle: isize, name: String, } impl PrivateDesktop { fn create(logs_base_dir: Option<&Path>) -> Result { let mut rng = SmallRng::from_entropy(); let name = format!("CodexSandboxDesktop-{:x}", rng.r#gen::()); let name_wide = to_wide(&name); let handle = unsafe { CreateDesktopW( name_wide.as_ptr(), ptr::null(), ptr::null_mut(), 0, DESKTOP_ALL_ACCESS, ptr::null_mut(), ) }; if handle == 0 { let err = unsafe { GetLastError() } as i32; logging::debug_log( &format!( "CreateDesktopW failed for {name}: {} ({})", err, format_last_error(err), ), logs_base_dir, ); return Err(anyhow::anyhow!("CreateDesktopW failed: {err}")); } unsafe { if let Err(err) = grant_desktop_access(handle, logs_base_dir) { let _ = CloseDesktop(handle); return Err(err); } } Ok(Self { handle, name }) } } unsafe fn grant_desktop_access(handle: isize, logs_base_dir: Option<&Path>) -> Result<()> { let token = get_current_token_for_restriction()?; let mut logon_sid = get_logon_sid_bytes(token)?; CloseHandle(token); let entries = [EXPLICIT_ACCESS_W { grfAccessPermissions: DESKTOP_ALL_ACCESS, grfAccessMode: GRANT_ACCESS, grfInheritance: 0, Trustee: TRUSTEE_W { pMultipleTrustee: ptr::null_mut(), MultipleTrusteeOperation: 0, TrusteeForm: TRUSTEE_IS_SID, TrusteeType: TRUSTEE_IS_UNKNOWN, ptstrName: logon_sid.as_mut_ptr() as *mut c_void as *mut u16, }, }]; let mut updated_dacl = ptr::null_mut(); let set_entries_code = SetEntriesInAclW( entries.len() as u32, entries.as_ptr(), ptr::null_mut(), &mut updated_dacl, ); if set_entries_code != ERROR_SUCCESS { logging::debug_log( &format!("SetEntriesInAclW failed for private desktop: {set_entries_code}"), logs_base_dir, ); return Err(anyhow::anyhow!( "SetEntriesInAclW failed for private desktop: {set_entries_code}" )); } let set_security_code = SetSecurityInfo( handle, SE_WINDOW_OBJECT, DACL_SECURITY_INFORMATION, ptr::null_mut(), ptr::null_mut(), updated_dacl, ptr::null_mut(), ); if !updated_dacl.is_null() { LocalFree(updated_dacl as HLOCAL); } if set_security_code != ERROR_SUCCESS { logging::debug_log( &format!("SetSecurityInfo failed for private desktop: {set_security_code}"), logs_base_dir, ); return Err(anyhow::anyhow!( "SetSecurityInfo failed for private desktop: {set_security_code}" )); } Ok(()) } impl Drop for PrivateDesktop { fn drop(&mut self) { unsafe { if self.handle != 0 { let _ = CloseDesktop(self.handle); } } } }