mirror of
https://github.com/openai/codex.git
synced 2026-09-09 15:58:47 +00:00
windows sandbox: initialize sandbox user profiles
This commit is contained in:
@@ -12,9 +12,12 @@ use std::ffi::c_void;
|
||||
use std::fs::File;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use windows_sys::Win32::Foundation::CloseHandle;
|
||||
use windows_sys::Win32::Foundation::ERROR_INSUFFICIENT_BUFFER;
|
||||
use windows_sys::Win32::Foundation::GetLastError;
|
||||
use windows_sys::Win32::Foundation::LocalFree;
|
||||
use windows_sys::Win32::Foundation::WAIT_OBJECT_0;
|
||||
use windows_sys::Win32::Foundation::WAIT_TIMEOUT;
|
||||
use windows_sys::Win32::NetworkManagement::NetManagement::LOCALGROUP_INFO_1;
|
||||
use windows_sys::Win32::NetworkManagement::NetManagement::LOCALGROUP_MEMBERS_INFO_3;
|
||||
use windows_sys::Win32::NetworkManagement::NetManagement::NERR_Success;
|
||||
@@ -33,6 +36,14 @@ use windows_sys::Win32::Security::GetLengthSid;
|
||||
use windows_sys::Win32::Security::LookupAccountNameW;
|
||||
use windows_sys::Win32::Security::LookupAccountSidW;
|
||||
use windows_sys::Win32::Security::SID_NAME_USE;
|
||||
use windows_sys::Win32::System::Threading::CREATE_NO_WINDOW;
|
||||
use windows_sys::Win32::System::Threading::CreateProcessWithLogonW;
|
||||
use windows_sys::Win32::System::Threading::GetExitCodeProcess;
|
||||
use windows_sys::Win32::System::Threading::INFINITE;
|
||||
use windows_sys::Win32::System::Threading::LOGON_WITH_PROFILE;
|
||||
use windows_sys::Win32::System::Threading::PROCESS_INFORMATION;
|
||||
use windows_sys::Win32::System::Threading::STARTUPINFOW;
|
||||
use windows_sys::Win32::System::Threading::WaitForSingleObject;
|
||||
|
||||
use codex_windows_sandbox::SETUP_VERSION;
|
||||
use codex_windows_sandbox::SetupErrorCode;
|
||||
@@ -76,6 +87,8 @@ pub fn provision_sandbox_users(
|
||||
let online_password = random_password();
|
||||
ensure_sandbox_user(offline_username, &offline_password, log)?;
|
||||
ensure_sandbox_user(online_username, &online_password, log)?;
|
||||
initialize_user_profile(offline_username, &offline_password, log)?;
|
||||
initialize_user_profile(online_username, &online_password, log)?;
|
||||
write_secrets(
|
||||
codex_home,
|
||||
offline_username,
|
||||
@@ -88,6 +101,107 @@ pub fn provision_sandbox_users(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn initialize_user_profile(username: &str, password: &str, log: &mut File) -> Result<()> {
|
||||
let profile_dir = PathBuf::from(format!(r"C:\Users\{username}"));
|
||||
if profile_dir.exists() {
|
||||
super::log_line(
|
||||
log,
|
||||
&format!("sandbox user profile already initialized for {username}"),
|
||||
)?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let exe = r"C:\Windows\System32\cmd.exe";
|
||||
let command = format!(r#""{exe}" /c exit 0"#);
|
||||
let user_w = to_wide(OsStr::new(username));
|
||||
let domain_w = to_wide(".");
|
||||
let password_w = to_wide(OsStr::new(password));
|
||||
let exe_w = to_wide(OsStr::new(exe));
|
||||
let mut command_w = to_wide(command.as_str());
|
||||
let mut startup_info: STARTUPINFOW = unsafe { std::mem::zeroed() };
|
||||
startup_info.cb = std::mem::size_of::<STARTUPINFOW>() as u32;
|
||||
let mut process_info: PROCESS_INFORMATION = unsafe { std::mem::zeroed() };
|
||||
|
||||
super::log_line(
|
||||
log,
|
||||
&format!("initializing sandbox user profile for {username}"),
|
||||
)?;
|
||||
|
||||
let launched = unsafe {
|
||||
CreateProcessWithLogonW(
|
||||
user_w.as_ptr(),
|
||||
domain_w.as_ptr(),
|
||||
password_w.as_ptr(),
|
||||
LOGON_WITH_PROFILE,
|
||||
exe_w.as_ptr(),
|
||||
command_w.as_mut_ptr(),
|
||||
CREATE_NO_WINDOW,
|
||||
std::ptr::null(),
|
||||
std::ptr::null(),
|
||||
&startup_info,
|
||||
&mut process_info,
|
||||
)
|
||||
};
|
||||
if launched == 0 {
|
||||
return Err(anyhow::Error::new(SetupFailure::new(
|
||||
SetupErrorCode::HelperUserProfileInitFailed,
|
||||
format!(
|
||||
"CreateProcessWithLogonW failed for {username}: {}",
|
||||
unsafe { GetLastError() }
|
||||
),
|
||||
)));
|
||||
}
|
||||
|
||||
let wait_result = unsafe {
|
||||
if process_info.hThread != 0 {
|
||||
CloseHandle(process_info.hThread);
|
||||
}
|
||||
WaitForSingleObject(process_info.hProcess, INFINITE)
|
||||
};
|
||||
|
||||
let mut exit_code: u32 = 1;
|
||||
let got_exit_code = unsafe { GetExitCodeProcess(process_info.hProcess, &mut exit_code) };
|
||||
unsafe {
|
||||
if process_info.hProcess != 0 {
|
||||
CloseHandle(process_info.hProcess);
|
||||
}
|
||||
}
|
||||
if wait_result == WAIT_TIMEOUT {
|
||||
return Err(anyhow::Error::new(SetupFailure::new(
|
||||
SetupErrorCode::HelperUserProfileInitFailed,
|
||||
format!("profile bootstrap timed out for {username}"),
|
||||
)));
|
||||
}
|
||||
if wait_result != WAIT_OBJECT_0 {
|
||||
return Err(anyhow::Error::new(SetupFailure::new(
|
||||
SetupErrorCode::HelperUserProfileInitFailed,
|
||||
format!("WaitForSingleObject failed for {username}: {wait_result}"),
|
||||
)));
|
||||
}
|
||||
if got_exit_code == 0 {
|
||||
return Err(anyhow::Error::new(SetupFailure::new(
|
||||
SetupErrorCode::HelperUserProfileInitFailed,
|
||||
format!("GetExitCodeProcess failed for {username}: {}", unsafe {
|
||||
GetLastError()
|
||||
}),
|
||||
)));
|
||||
}
|
||||
if exit_code != 0 {
|
||||
return Err(anyhow::Error::new(SetupFailure::new(
|
||||
SetupErrorCode::HelperUserProfileInitFailed,
|
||||
format!("profile bootstrap command exited with {exit_code} for {username}"),
|
||||
)));
|
||||
}
|
||||
if !profile_dir.exists() {
|
||||
return Err(anyhow::Error::new(SetupFailure::new(
|
||||
SetupErrorCode::HelperUserProfileInitFailed,
|
||||
format!("profile directory was not created for {username}"),
|
||||
)));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn ensure_sandbox_user(username: &str, password: &str, log: &mut File) -> Result<()> {
|
||||
ensure_local_user(username, password, log)?;
|
||||
ensure_local_group_member(SANDBOX_USERS_GROUP, username)?;
|
||||
|
||||
@@ -42,6 +42,8 @@ pub enum SetupErrorCode {
|
||||
HelperUsersGroupCreateFailed,
|
||||
/// Helper failed to create or update a sandbox user account.
|
||||
HelperUserCreateOrUpdateFailed,
|
||||
/// Helper failed to initialize a sandbox user profile.
|
||||
HelperUserProfileInitFailed,
|
||||
/// Helper failed to protect user passwords with DPAPI.
|
||||
HelperDpapiProtectFailed,
|
||||
/// Helper failed to write the sandbox users secrets file.
|
||||
@@ -84,6 +86,7 @@ impl SetupErrorCode {
|
||||
Self::HelperUserProvisionFailed => "helper_user_provision_failed",
|
||||
Self::HelperUsersGroupCreateFailed => "helper_users_group_create_failed",
|
||||
Self::HelperUserCreateOrUpdateFailed => "helper_user_create_or_update_failed",
|
||||
Self::HelperUserProfileInitFailed => "helper_user_profile_init_failed",
|
||||
Self::HelperDpapiProtectFailed => "helper_dpapi_protect_failed",
|
||||
Self::HelperUsersFileWriteFailed => "helper_users_file_write_failed",
|
||||
Self::HelperSetupMarkerWriteFailed => "helper_setup_marker_write_failed",
|
||||
|
||||
@@ -34,7 +34,7 @@ use windows_sys::Win32::Security::CheckTokenMembership;
|
||||
use windows_sys::Win32::Security::FreeSid;
|
||||
use windows_sys::Win32::Security::SECURITY_NT_AUTHORITY;
|
||||
|
||||
pub const SETUP_VERSION: u32 = 5;
|
||||
pub const SETUP_VERSION: u32 = 6;
|
||||
pub const OFFLINE_USERNAME: &str = "CodexSandboxOffline";
|
||||
pub const ONLINE_USERNAME: &str = "CodexSandboxOnline";
|
||||
const ERROR_CANCELLED: u32 = 1223;
|
||||
|
||||
Reference in New Issue
Block a user