// -------------------------------------------------------------------------- // Module Name: RestoreApplication.cpp // // Copyright (c) 2000, Microsoft Corporation // // Class to implement holding information required to restore an application // and to actually restore it. // // History: 2000-10-26 vtan created // 2000-11-04 vtan split into separate file // -------------------------------------------------------------------------- #ifdef _X86_ #include "StandardHeader.h" #include "RestoreApplication.h" #include "StatusCode.h" // -------------------------------------------------------------------------- // CRestoreApplication::CRestoreApplication // // Purpose: Static const string to the user desktop.. // // History: 2000-11-04 vtan created // -------------------------------------------------------------------------- const WCHAR CRestoreApplication::s_szDefaultDesktop[] = L"WinSta0\\Default"; // -------------------------------------------------------------------------- // CRestoreApplication::CRestoreApplication // // Arguments: // // Returns: // // Purpose: Constructor for CRestoreApplication. // // History: 2000-10-26 vtan created // -------------------------------------------------------------------------- CRestoreApplication::CRestoreApplication (void) : _hToken(NULL), _dwSessionID(static_cast(-1)), _pszCommandLine(NULL), _pEnvironment(NULL), _pszCurrentDirectory(NULL), _pszDesktop(NULL), _pszTitle(NULL), _dwFlags(0), _wShowWindow(0), _hStdInput(NULL), _hStdOutput(NULL), _hStdError(NULL) { } // -------------------------------------------------------------------------- // CRestoreApplication::~CRestoreApplication // // Arguments: // // Returns: // // Purpose: Destructor for CRestoreApplication. Release any resources. // // History: 2000-10-26 vtan created // -------------------------------------------------------------------------- CRestoreApplication::~CRestoreApplication (void) { ReleaseMemory(_pszTitle); ReleaseMemory(_pszDesktop); ReleaseMemory(_pszCurrentDirectory); ReleaseMemory(_pEnvironment); ReleaseMemory(_pszCommandLine); ReleaseHandle(_hToken); } // -------------------------------------------------------------------------- // CRestoreApplication::GetInformation // // Arguments: hProcessIn = Handle to the process to get information. // // Returns: NTSTATUS // // Purpose: Gets information about the currently running process to // allow it to be re-run in the case when the user re-connects. // This effectively restores the process but it's not identical // to how it was originally run. // // History: 2000-10-26 vtan created // -------------------------------------------------------------------------- NTSTATUS CRestoreApplication::GetInformation (HANDLE hProcessIn) { NTSTATUS status; HANDLE hProcess; if (DuplicateHandle(GetCurrentProcess(), hProcessIn, GetCurrentProcess(), &hProcess, PROCESS_VM_READ | PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION, FALSE, 0) != FALSE) { status = GetToken(hProcess); if (NT_SUCCESS(status)) { status = GetSessionID(hProcess); if (NT_SUCCESS(status)) { RTL_USER_PROCESS_PARAMETERS processParameters; status = GetProcessParameters(hProcess, &processParameters); if (NT_SUCCESS(status)) { status = GetCommandLine(hProcess, processParameters); if (NT_SUCCESS(status)) { TSTATUS(GetEnvironment(hProcess, processParameters)); TSTATUS(GetCurrentDirectory(hProcess, processParameters)); TSTATUS(GetDesktop(hProcess, processParameters)); TSTATUS(GetTitle(hProcess, processParameters)); TSTATUS(GetFlags(hProcess, processParameters)); TSTATUS(GetStdHandles(hProcess, processParameters)); } } } } TBOOL(CloseHandle(hProcess)); } else { status = CStatusCode::StatusCodeOfLastError(); } return(status); } // -------------------------------------------------------------------------- // CRestoreApplication::IsEqualSessionID // // Arguments: dwSessionID = Session ID to check. // // Returns: bool // // Purpose: Returns whether the given session ID is the same as the // process that needs restoration. This assists in determining // whether restoration is required. // // History: 2000-10-26 vtan created // -------------------------------------------------------------------------- bool CRestoreApplication::IsEqualSessionID (DWORD dwSessionID) const { return(_dwSessionID == dwSessionID); } // -------------------------------------------------------------------------- // CRestoreApplication::GetCommandLine // // Arguments: // // Returns: const WCHAR* // // Purpose: Returns the pointer to the internal storage for the command // line of the process. // // History: 2000-10-26 vtan created // -------------------------------------------------------------------------- const WCHAR* CRestoreApplication::GetCommandLine (void) const { return(_pszCommandLine); } // -------------------------------------------------------------------------- // CRestoreApplication::Restore // // Arguments: phProcess = Receives the handle to the restored process. // // Returns: NTSTATUS // // Purpose: Restores the process whose information was gathered with // GetInformation to as close as possibly to the original start // state. Relevant information was saved off to allow an // effective restore. // // The handle returned is optional. If requested a non-NULL // phProcess must be passed in and it is the caller's // responsibility to close that handle. If not required then // NULL is passed in and the handle is closed. // // History: 2000-10-26 vtan created // -------------------------------------------------------------------------- NTSTATUS CRestoreApplication::Restore (HANDLE *phProcess) const { NTSTATUS status; STARTUPINFO startupInfo; PROCESS_INFORMATION processInformation; ZeroMemory(&startupInfo, sizeof(startupInfo)); ZeroMemory(&processInformation, sizeof(processInformation)); startupInfo.cb = sizeof(startupInfo); startupInfo.lpDesktop = _pszDesktop; startupInfo.lpTitle = _pszTitle; startupInfo.dwFlags = _dwFlags; startupInfo.wShowWindow = _wShowWindow; if (ImpersonateLoggedOnUser(_hToken) != FALSE) { if (CreateProcessAsUser(_hToken, NULL, _pszCommandLine, NULL, NULL, FALSE, 0, NULL, _pszCurrentDirectory, &startupInfo, &processInformation) != FALSE) { if (phProcess != NULL) { *phProcess = processInformation.hProcess; } else { TBOOL(CloseHandle(processInformation.hProcess)); } TBOOL(CloseHandle(processInformation.hThread)); status = STATUS_SUCCESS; } else { status = CStatusCode::StatusCodeOfLastError(); } TBOOL(RevertToSelf()); } else { status = CStatusCode::StatusCodeOfLastError(); } return(status); } // -------------------------------------------------------------------------- // CRestoreApplication::GetProcessParameters // // Arguments: hProcess = Handle to the process. // processParameters = Process parameters returned. // // Returns: NTSTATUS // // Purpose: Reads the RTL_USER_PROCESS_PARAMETERS information from the // given process. Addresses in this struct belong to the given // process address space. // // History: 2000-10-26 vtan created // -------------------------------------------------------------------------- NTSTATUS CRestoreApplication::GetProcessParameters (HANDLE hProcess, RTL_USER_PROCESS_PARAMETERS* pProcessParameters) { NTSTATUS status; ULONG ulReturnLength; PROCESS_BASIC_INFORMATION processBasicInformation; status = NtQueryInformationProcess(hProcess, ProcessBasicInformation, &processBasicInformation, sizeof(processBasicInformation), &ulReturnLength); if (NT_SUCCESS(status)) { SIZE_T dwNumberOfBytesRead; PEB peb; if ((ReadProcessMemory(hProcess, processBasicInformation.PebBaseAddress, &peb, sizeof(peb), &dwNumberOfBytesRead) != FALSE) && (ReadProcessMemory(hProcess, peb.ProcessParameters, pProcessParameters, sizeof(*pProcessParameters), &dwNumberOfBytesRead) != FALSE)) { status = STATUS_SUCCESS; } else { status = CStatusCode::StatusCodeOfLastError(); } } return(status); } // -------------------------------------------------------------------------- // CRestoreApplication::GetUnicodeString // // Arguments: hProcess = Handle to the process. // string = UNICODE_STRING to read from process. // psz = Received newly allocated memory for string. // // Returns: NTSTATUS // // Purpose: Reads the given UNICODE_STRING from the process and allocates // memory to hold this string and copies it. The string is // NULL terminated. // // History: 2000-10-26 vtan created // -------------------------------------------------------------------------- NTSTATUS CRestoreApplication::GetUnicodeString (HANDLE hProcess, const UNICODE_STRING& string, WCHAR** ppsz) { NTSTATUS status; WCHAR *psz; psz = static_cast(LocalAlloc(LMEM_FIXED, string.Length + (sizeof('\0') * sizeof(WCHAR)))); if (psz != NULL) { SIZE_T dwNumberOfBytesRead; if (ReadProcessMemory(hProcess, string.Buffer, psz, string.Length, &dwNumberOfBytesRead) != FALSE) { psz[string.Length / sizeof(WCHAR)] = L'\0'; status = STATUS_SUCCESS; } else { ReleaseMemory(psz); status = CStatusCode::StatusCodeOfLastError(); } } else { status = STATUS_NO_MEMORY; } *ppsz = psz; return(status); } // -------------------------------------------------------------------------- // CRestoreApplication::GetToken // // Arguments: hProcess = Handle to process to get token of. // // Returns: NTSTATUS // // Purpose: Stores internally the token of the give process. // // History: 2000-10-26 vtan created // -------------------------------------------------------------------------- NTSTATUS CRestoreApplication::GetToken (HANDLE hProcess) { NTSTATUS status; if ((OpenProcessToken(hProcess, TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_QUERY, &_hToken) != FALSE)) { status = STATUS_SUCCESS; } else { status = CStatusCode::StatusCodeOfLastError(); } return(status); } // -------------------------------------------------------------------------- // CRestoreApplication::GetSessionID // // Arguments: hProcess = Handle to the process. // // Returns: NTSTATUS // // Purpose: Stores the session ID associated with the process. // // History: 2000-10-26 vtan created // -------------------------------------------------------------------------- NTSTATUS CRestoreApplication::GetSessionID (HANDLE hProcess) { NTSTATUS status; ULONG ulReturnLength; PROCESS_SESSION_INFORMATION processSessionInformation; status = NtQueryInformationProcess(hProcess, ProcessSessionInformation, &processSessionInformation, sizeof(processSessionInformation), &ulReturnLength); if (NT_SUCCESS(status)) { _dwSessionID = processSessionInformation.SessionId; } return(status); } // -------------------------------------------------------------------------- // CRestoreApplication::GetCommandLine // // Arguments: hProcess = Handle to the process. // processParameters = Process parameters returned. // // Returns: NTSTATUS // // Purpose: Stores the command line (that started the process) from the // given process. // // History: 2000-10-26 vtan created // -------------------------------------------------------------------------- NTSTATUS CRestoreApplication::GetCommandLine (HANDLE hProcess, const RTL_USER_PROCESS_PARAMETERS& processParameters) { return(GetUnicodeString(hProcess, processParameters.CommandLine, &_pszCommandLine)); } // -------------------------------------------------------------------------- // CRestoreApplication::GetEnvironment // // Arguments: hProcess = Handle to the process. // processParameters = Process parameters returned. // // Returns: NTSTATUS // // Purpose: Stores the environment block for the given process. Currently // this is NOT implemented. // // History: 2000-10-26 vtan created // -------------------------------------------------------------------------- NTSTATUS CRestoreApplication::GetEnvironment (HANDLE hProcess, const RTL_USER_PROCESS_PARAMETERS& processParameters) { UNREFERENCED_PARAMETER(hProcess); UNREFERENCED_PARAMETER(processParameters); return(STATUS_SUCCESS); } // -------------------------------------------------------------------------- // CRestoreApplication::GetCurrentDirectory // // Arguments: hProcess = Handle to the process. // processParameters = Process parameters returned. // // Returns: NTSTATUS // // Purpose: Stores the current directory of the given process. // // History: 2000-10-26 vtan created // -------------------------------------------------------------------------- NTSTATUS CRestoreApplication::GetCurrentDirectory (HANDLE hProcess, const RTL_USER_PROCESS_PARAMETERS& processParameters) { return(GetUnicodeString(hProcess, processParameters.CurrentDirectory.DosPath, &_pszCurrentDirectory)); } // -------------------------------------------------------------------------- // CRestoreApplication::GetDesktop // // Arguments: hProcess = Handle to the process. // processParameters = Process parameters returned. // // Returns: NTSTATUS // // Purpose: Stores the window station and desktop that the given process // was started on. // // History: 2000-10-26 vtan created // -------------------------------------------------------------------------- NTSTATUS CRestoreApplication::GetDesktop (HANDLE hProcess, const RTL_USER_PROCESS_PARAMETERS& processParameters) { NTSTATUS status; status = GetUnicodeString(hProcess, processParameters.DesktopInfo, &_pszDesktop); if (!NT_SUCCESS(status)) { _pszDesktop = static_cast(LocalAlloc(LMEM_FIXED, sizeof(s_szDefaultDesktop))); if (_pszDesktop != NULL) { CopyMemory(_pszDesktop, s_szDefaultDesktop, sizeof(s_szDefaultDesktop)); status = STATUS_SUCCESS; } else { status = STATUS_NO_MEMORY; } } return(status); } // -------------------------------------------------------------------------- // CRestoreApplication::GetTitle // // Arguments: hProcess = Handle to the process. // processParameters = Process parameters returned. // // Returns: NTSTATUS // // Purpose: Stores the window title used to start the given process. // // History: 2000-10-26 vtan created // -------------------------------------------------------------------------- NTSTATUS CRestoreApplication::GetTitle (HANDLE hProcess, const RTL_USER_PROCESS_PARAMETERS& processParameters) { return(GetUnicodeString(hProcess, processParameters.WindowTitle, &_pszTitle)); } // -------------------------------------------------------------------------- // CRestoreApplication::GetFlags // // Arguments: hProcess = Handle to the process. // processParameters = Process parameters returned. // // Returns: NTSTATUS // // Purpose: Stores the flags and wShowWindow used to start the given // process. // // History: 2000-10-26 vtan created // -------------------------------------------------------------------------- NTSTATUS CRestoreApplication::GetFlags (HANDLE hProcess, const RTL_USER_PROCESS_PARAMETERS& processParameters) { UNREFERENCED_PARAMETER(hProcess); _dwFlags = processParameters.WindowFlags; _wShowWindow = static_cast(processParameters.ShowWindowFlags); return(STATUS_SUCCESS); } // -------------------------------------------------------------------------- // CRestoreApplication::GetStdHandles // // Arguments: hProcess = Handle to the process. // processParameters = Process parameters returned. // // Returns: NTSTATUS // // Purpose: Stores the standard handles that may have been used to start // the given process. Currently NOT implemented. // // History: 2000-10-26 vtan created // -------------------------------------------------------------------------- NTSTATUS CRestoreApplication::GetStdHandles (HANDLE hProcess, const RTL_USER_PROCESS_PARAMETERS& processParameters) { UNREFERENCED_PARAMETER(hProcess); UNREFERENCED_PARAMETER(processParameters); return(STATUS_SUCCESS); } #endif /* _X86_ */