// -------------------------------------------------------------------------- // Module Name: BadApplicationAPIRequest.cpp // // Copyright (c) 2000, Microsoft Corporation // // This file contains a class to implement bad application manager API // requests. // // History: 2000-08-25 vtan created // 2000-12-04 vtan moved to separate file // -------------------------------------------------------------------------- #ifdef _X86_ #include "StandardHeader.h" #include "BadApplicationAPIRequest.h" #include "StatusCode.h" #include "TokenInformation.h" // -------------------------------------------------------------------------- // CBadApplicationAPIRequest::s_pBadApplicationManager // // Purpose: Single instance of the CBadApplicationManager object. // // History: 2000-08-26 vtan created // -------------------------------------------------------------------------- CBadApplicationManager* CBadApplicationAPIRequest::s_pBadApplicationManager = NULL; // -------------------------------------------------------------------------- // CBadApplicationAPIRequest::CBadApplicationAPIRequest // // Arguments: pAPIDispatcher = CAPIDispatcher that calls this object. // // Returns: // // Purpose: Constructor for the CBadApplicationAPIRequest class. It just passes the // control to the super class. // // History: 2000-08-25 vtan created // -------------------------------------------------------------------------- CBadApplicationAPIRequest::CBadApplicationAPIRequest (CAPIDispatcher* pAPIDispatcher) : CAPIRequest(pAPIDispatcher) { } // -------------------------------------------------------------------------- // CBadApplicationAPIRequest::CBadApplicationAPIRequest // // Arguments: pAPIDispatcher = CAPIDispatcher that calls this object. // portMessage = CPortMessage to copy construct. // // Returns: // // Purpose: Constructor for the CBadApplicationAPIRequest class. It just passes the // control to the super class. // // History: 2000-08-25 vtan created // -------------------------------------------------------------------------- CBadApplicationAPIRequest::CBadApplicationAPIRequest (CAPIDispatcher* pAPIDispatcher, const CPortMessage& portMessage) : CAPIRequest(pAPIDispatcher, portMessage) { } // -------------------------------------------------------------------------- // CBadApplicationAPIRequest::~CBadApplicationAPIRequest // // Arguments: // // Returns: // // Purpose: Destructor for the CBadApplicationAPIRequest class. // // History: 2000-08-25 vtan created // -------------------------------------------------------------------------- CBadApplicationAPIRequest::~CBadApplicationAPIRequest (void) { } // -------------------------------------------------------------------------- // CBadApplicationAPIRequest::Execute // // Arguments: pAPIDispatchSync - allows request execution access to various // service notifications and events // // Returns: NTSTATUS // // Purpose: Execute implementation for bad application API requests. This // function dispatches requests based on the API request number. // // History: 2000-08-25 vtan created // 2002-03-24 scotthan add DispatchSync arg // -------------------------------------------------------------------------- NTSTATUS CBadApplicationAPIRequest::Execute (CAPIDispatchSync* pAPIDispatchSync) { NTSTATUS status; UNREFERENCED_PARAMETER(pAPIDispatchSync); switch (reinterpret_cast(&_data)->apiGeneric.ulAPINumber) { case API_BAM_QUERYRUNNING: status = Execute_QueryRunning(); break; case API_BAM_REGISTERRUNNING: status = Execute_RegisterRunning(); break; case API_BAM_QUERYUSERPERMISSION: status = Execute_QueryUserPermission(); break; case API_BAM_TERMINATERUNNING: status = Execute_TerminateRunning(); break; case API_BAM_REQUESTSWITCHUSER: status = Execute_RequestSwitchUser(); break; default: DISPLAYMSG("Unknown API request in CBadApplicationAPIRequest::Execute"); status = STATUS_NOT_IMPLEMENTED; break; } TSTATUS(status); return(status); } // -------------------------------------------------------------------------- // CBadApplicationAPIRequest::StaticInitialize // // Arguments: // // Returns: NTSTATUS // // Purpose: Static initializer for the class. It creates the static // instance of the CBadApplicationManager which must be a single // instance and knows about bad running applications. // // History: 2000-08-26 vtan created // -------------------------------------------------------------------------- NTSTATUS CBadApplicationAPIRequest::StaticInitialize (HINSTANCE hInstance) { NTSTATUS status; if (s_pBadApplicationManager == NULL) { s_pBadApplicationManager = new CBadApplicationManager(hInstance); if (s_pBadApplicationManager != NULL) { status = STATUS_SUCCESS; } else { status = STATUS_NO_MEMORY; } } else { status = STATUS_SUCCESS; } return(status); } // -------------------------------------------------------------------------- // CBadApplicationAPIRequest::StaticTerminate // // Arguments: // // Returns: NTSTATUS // // Purpose: Static destructor for the class. This terminates the bad // application manager, releases the reference on the object and // clears out the static variable. When the thread dies it will // clean itself up. // // History: 2000-08-26 vtan created // -------------------------------------------------------------------------- NTSTATUS CBadApplicationAPIRequest::StaticTerminate (void) { if (s_pBadApplicationManager != NULL) { s_pBadApplicationManager->Terminate(); s_pBadApplicationManager->Release(); s_pBadApplicationManager = NULL; } return(STATUS_SUCCESS); } // -------------------------------------------------------------------------- // CBadApplicationAPIRequest::Execute_QueryRunning // // Arguments: // // Returns: NTSTATUS // // Purpose: Handles API_BAM_QUERYRUNNING. Returns whether or not the // requested image path is currently a known (tracked) // executable that is running. Let the bad application manager // do the work. Exclude checking in the same session. // // History: 2000-08-26 vtan created // -------------------------------------------------------------------------- NTSTATUS CBadApplicationAPIRequest::Execute_QueryRunning (void) { NTSTATUS status; HANDLE hProcessClient; SIZE_T dwNumberOfBytesRead; API_BAM_QUERYRUNNING_IN *pAPIIn; API_BAM_QUERYRUNNING_OUT *pAPIOut; WCHAR szImageName[MAX_PATH]; hProcessClient = _pAPIDispatcher->GetClientProcess(); pAPIIn = &reinterpret_cast(&_data)->apiSpecific.apiQueryRunning.in; pAPIOut = &reinterpret_cast(&_data)->apiSpecific.apiQueryRunning.out; if (ReadProcessMemory(hProcessClient, pAPIIn->pszImageName, szImageName, pAPIIn->cchImageName * sizeof(WCHAR), &dwNumberOfBytesRead) != FALSE) { CBadApplication badApplication(szImageName); pAPIOut->fResult = s_pBadApplicationManager->QueryRunning(badApplication, _pAPIDispatcher->GetClientSessionID()); status = STATUS_SUCCESS; } else { status = CStatusCode::StatusCodeOfLastError(); } SetDataLength(sizeof(API_BAM)); return(status); } // -------------------------------------------------------------------------- // CBadApplicationAPIRequest::Execute_RegisterRunning // // Arguments: // // Returns: NTSTATUS // // Purpose: Handles API_BAM_REGISTERRUNNING. Adds the given image // executable to the list of currently running bad applications // so that further instances can be excluded. // // History: 2000-08-26 vtan created // -------------------------------------------------------------------------- NTSTATUS CBadApplicationAPIRequest::Execute_RegisterRunning (void) { NTSTATUS status; SIZE_T dwNumberOfBytesRead; API_BAM_REGISTERRUNNING_IN *pAPIIn; API_BAM_REGISTERRUNNING_OUT *pAPIOut; WCHAR szImageName[MAX_PATH]; pAPIIn = &reinterpret_cast(&_data)->apiSpecific.apiRegisterRunning.in; pAPIOut = &reinterpret_cast(&_data)->apiSpecific.apiRegisterRunning.out; if ((pAPIIn->bamType > BAM_TYPE_MINIMUM) && (pAPIIn->bamType < BAM_TYPE_MAXIMUM)) { if (ReadProcessMemory(_pAPIDispatcher->GetClientProcess(), pAPIIn->pszImageName, szImageName, pAPIIn->cchImageName * sizeof(WCHAR), &dwNumberOfBytesRead) != FALSE) { HANDLE hProcess; CBadApplication badApplication(szImageName); hProcess = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION, FALSE, pAPIIn->dwProcessID); if (hProcess != NULL) { status = s_pBadApplicationManager->RegisterRunning(badApplication, hProcess, pAPIIn->bamType); TBOOL(CloseHandle(hProcess)); } else { status = CStatusCode::StatusCodeOfLastError(); } } else { status = CStatusCode::StatusCodeOfLastError(); } } else { status = STATUS_INVALID_PARAMETER; } SetDataLength(sizeof(API_BAM)); return(status); } // -------------------------------------------------------------------------- // CBadApplicationAPIRequest::Execute_QueryUserPermission // // Arguments: // // Returns: NTSTATUS // // Purpose: Handles API_BAM_QUERYUSERPERMISSION. Queries the client // permission to close down the bad application. Also returns // the current user of the bad application. // // History: 2000-08-31 vtan created // -------------------------------------------------------------------------- NTSTATUS CBadApplicationAPIRequest::Execute_QueryUserPermission (void) { NTSTATUS status; SIZE_T dwNumberOfBytesRead; API_BAM_QUERYUSERPERMISSION_IN *pAPIIn; API_BAM_QUERYUSERPERMISSION_OUT *pAPIOut; WCHAR szImageName[MAX_PATH]; pAPIIn = &reinterpret_cast(&_data)->apiSpecific.apiQueryUserPermission.in; pAPIOut = &reinterpret_cast(&_data)->apiSpecific.apiQueryUserPermission.out; if (ReadProcessMemory(_pAPIDispatcher->GetClientProcess(), pAPIIn->pszImageName, szImageName, pAPIIn->cchImageName * sizeof(WCHAR), &dwNumberOfBytesRead) != FALSE) { HANDLE hProcess; CBadApplication badApplication(szImageName); // Query information on the bad application // (get back the process handle). status = s_pBadApplicationManager->QueryInformation(badApplication, hProcess); if (NT_SUCCESS(status)) { HANDLE hToken; // Get the client token and impersonate that user. status = OpenClientToken(hToken); if (NT_SUCCESS(status)) { bool fCanShutdownApplication; HANDLE hTokenProcess; CTokenInformation tokenInformationClient(hToken); fCanShutdownApplication = tokenInformationClient.IsUserAnAdministrator(); // Get the bad application process token to get // information on the user for the process. if (OpenProcessToken(hProcess, TOKEN_QUERY, &hTokenProcess) != FALSE) { const WCHAR *pszUserDisplayName; CTokenInformation tokenInformationProcess(hTokenProcess); pszUserDisplayName = tokenInformationProcess.GetUserDisplayName(); if (pszUserDisplayName != NULL) { int iCharsToWrite; SIZE_T dwNumberOfBytesWritten; // Return the information back to the client. pAPIOut->fCanShutdownApplication = fCanShutdownApplication; iCharsToWrite = lstrlen(pszUserDisplayName) + sizeof('\0'); if (iCharsToWrite > pAPIIn->cchUser) { iCharsToWrite = pAPIIn->cchUser; } if (WriteProcessMemory(_pAPIDispatcher->GetClientProcess(), pAPIIn->pszUser, const_cast(pszUserDisplayName), iCharsToWrite * sizeof(WCHAR), &dwNumberOfBytesWritten) != FALSE) { status = STATUS_SUCCESS; } else { status = CStatusCode::StatusCodeOfLastError(); } } else { status = CStatusCode::StatusCodeOfLastError(); } TBOOL(CloseHandle(hTokenProcess)); } else { status = CStatusCode::StatusCodeOfLastError(); } TBOOL(CloseHandle(hToken)); } else { status = CStatusCode::StatusCodeOfLastError(); } TBOOL(CloseHandle(hProcess)); } } else { status = CStatusCode::StatusCodeOfLastError(); } SetDataLength(sizeof(API_BAM)); return(status); } // -------------------------------------------------------------------------- // CBadApplicationAPIRequest::Execute_QueryUserPermission // // Arguments: // // Returns: NTSTATUS // // Purpose: Handles API_BAM_TERMINATERUNNING. Terminates the given running // bad application so a different instance on a different // window station can start it. // // History: 2000-08-31 vtan created // -------------------------------------------------------------------------- NTSTATUS CBadApplicationAPIRequest::Execute_TerminateRunning (void) { NTSTATUS status; SIZE_T dwNumberOfBytesRead; API_BAM_TERMINATERUNNING_IN *pAPIIn; API_BAM_TERMINATERUNNING_OUT *pAPIOut; WCHAR szImageName[MAX_PATH]; pAPIIn = &reinterpret_cast(&_data)->apiSpecific.apiTerminateRunning.in; pAPIOut = &reinterpret_cast(&_data)->apiSpecific.apiTerminateRunning.out; if (ReadProcessMemory(_pAPIDispatcher->GetClientProcess(), pAPIIn->pszImageName, szImageName, pAPIIn->cchImageName * sizeof(WCHAR), &dwNumberOfBytesRead) != FALSE) { HANDLE hToken; // Get the client token and for membership of the local administrators // group. DO NOT IMPERSONATE THE CLIENT. This will almost certainly // guarantee that the process cannot be terminated. status = OpenClientToken(hToken); if (NT_SUCCESS(status)) { CTokenInformation tokenInformationClient(hToken); if (tokenInformationClient.IsUserAnAdministrator()) { HANDLE hProcess; CBadApplication badApplication(szImageName); // Query information on the bad application // (get back the process handle). status = s_pBadApplicationManager->QueryInformation(badApplication, hProcess); if (NT_SUCCESS(status)) { do { status = CBadApplicationManager::PerformTermination(hProcess, true); TBOOL(CloseHandle(hProcess)); } while (NT_SUCCESS(status) && NT_SUCCESS(s_pBadApplicationManager->QueryInformation(badApplication, hProcess))); } // If the information could not be found then it's // probably not running. This indicates success. else { status = STATUS_SUCCESS; } } else { status = STATUS_ACCESS_DENIED; } TBOOL(CloseHandle(hToken)); } } else { status = CStatusCode::StatusCodeOfLastError(); } pAPIOut->fResult = NT_SUCCESS(status); SetDataLength(sizeof(API_BAM)); return(status); } // -------------------------------------------------------------------------- // CBadApplicationAPIRequest::Execute_RequestSwitchUser // // Arguments: // // Returns: NTSTATUS // // Purpose: Handles API_BAM_REQUESTSWITCHUSER. Request from // winlogon/msgina to switch a user. Terminate all bad // applications related to disconnect. Reject the disconnect if // it fails. // // History: 2000-11-02 vtan created // -------------------------------------------------------------------------- NTSTATUS CBadApplicationAPIRequest::Execute_RequestSwitchUser (void) { API_BAM_REQUESTSWITCHUSER_OUT *pAPIOut; pAPIOut = &reinterpret_cast(&_data)->apiSpecific.apiRequestSwitchUser.out; pAPIOut->fAllowSwitch = NT_SUCCESS(s_pBadApplicationManager->RequestSwitchUser()); SetDataLength(sizeof(API_BAM)); return(STATUS_SUCCESS); } #endif /* _X86_ */