// -------------------------------------------------------------------------- // Module Name: CInteractiveLogon.cpp // // Copyright (c) 2000, Microsoft Corporation // // File that implements encapsulation of interactive logon information. // // History: 2000-12-07 vtan created // -------------------------------------------------------------------------- #include "priv.h" #include "CInteractiveLogon.h" #include #include "GinaIPC.h" #include "TokenInformation.h" #include "UIHostIPC.h" const TCHAR CInteractiveLogon::s_szEventReplyName[] = TEXT("shgina: InteractiveLogonRequestReply"); const TCHAR CInteractiveLogon::s_szEventSignalName[] = TEXT("shgina: InteractiveLogonRequestSignal"); const TCHAR CInteractiveLogon::s_szSectionName[] = TEXT("shgina: InteractiveLogonRequestSection"); // -------------------------------------------------------------------------- // CInteractiveLogon::CRequestData::CRequestData // // Arguments: // // Returns: // // Purpose: Constructor for CRequestData. // // History: 2000-12-08 vtan created // -------------------------------------------------------------------------- CInteractiveLogon::CRequestData::CRequestData (void) { } // -------------------------------------------------------------------------- // CInteractiveLogon::CRequestData::~CRequestData // // Arguments: // // Returns: // // Purpose: Destructor for CRequestData. // // History: 2000-12-08 vtan created // -------------------------------------------------------------------------- CInteractiveLogon::CRequestData::~CRequestData (void) { } // -------------------------------------------------------------------------- // CInteractiveLogon::CRequestData::Set // // Arguments: pszUsername = Username. // pszDomain = Domain. // pszPassword = Password. // // Returns: // // Purpose: Sets the information into the section object. Makes the data // valid by signing it with a 4-byte signature. // // History: 2000-12-07 vtan created // -------------------------------------------------------------------------- void CInteractiveLogon::CRequestData::Set (const WCHAR *pszUsername, const WCHAR *pszDomain, WCHAR *pszPassword) { UNICODE_STRING passwordString; _ulMagicNumber = MAGIC_NUMBER; _dwErrorCode = ERROR_ACCESS_DENIED; StringCchCopy(_szEventReplyName, ARRAYSIZE(s_szEventReplyName), s_szEventReplyName); StringCchCopy(_szUsername, ARRAYSIZE(_szUsername), pszUsername); StringCchCopy(_szDomain, ARRAYSIZE(_szDomain), pszDomain); // REVIEW (jeffreys) I think the 127 char limit is bogus. I don't // agree with comments in logonipc.cpp. StringCchCopyNEx(_szPassword, ARRAYSIZE(_szPassword), pszPassword, 127, NULL, NULL, STRSAFE_FILL_BEHIND_NULL); ZeroMemory(pszPassword, (lstrlen(pszPassword) + 1) * sizeof(WCHAR)); _iPasswordLength = lstrlen(_szPassword); passwordString.Buffer = _szPassword; passwordString.Length = (USHORT)(_iPasswordLength * sizeof(WCHAR)); passwordString.MaximumLength = sizeof(_szPassword); _ucSeed = 0; RtlRunEncodeUnicodeString(&_ucSeed, &passwordString); } // -------------------------------------------------------------------------- // CInteractiveLogon::CRequestData::Get // // Arguments: pszUsername = Username (returned). // pszDomain = Domain (returned). // pszPassword = Password (clear-text) returned. // // Returns: DWORD // // Purpose: Extracts the information transmitted in the section across // sessions in the receiving process' context. Checks the // signature written by Set. // // History: 2000-12-07 vtan created // -------------------------------------------------------------------------- DWORD CInteractiveLogon::CRequestData::Get (WCHAR *pszUsername, size_t cchUsername, WCHAR *pszDomain, size_t cchDomain, WCHAR *pszPassword, size_t cchPassword) const { DWORD dwErrorCode; if (_ulMagicNumber == MAGIC_NUMBER) { if (cchPassword < ((UINT)_iPasswordLength + 1) || FAILED(StringCchCopy(pszUsername, cchUsername, _szUsername)) || FAILED(StringCchCopy(pszDomain, cchDomain, _szDomain))) { dwErrorCode = ERROR_INSUFFICIENT_BUFFER; } else { UNICODE_STRING passwordString; CopyMemory(pszPassword, _szPassword, (_iPasswordLength + 1) * sizeof(WCHAR)); passwordString.Buffer = pszPassword; passwordString.Length = (USHORT)(_iPasswordLength * sizeof(WCHAR)); passwordString.MaximumLength = (USHORT)(cchPassword * sizeof(WCHAR)); RtlRunDecodeUnicodeString(_ucSeed, &passwordString); pszPassword[_iPasswordLength] = L'\0'; dwErrorCode = ERROR_SUCCESS; } } else { dwErrorCode = ERROR_INVALID_PARAMETER; } return dwErrorCode; } // -------------------------------------------------------------------------- // CInteractiveLogon::CRequestData::SetErrorCode // // Arguments: dwErrorCode = Error code to set. // // Returns: DWORD // // Purpose: Sets the error code into the section. // // History: 2000-12-08 vtan created // -------------------------------------------------------------------------- void CInteractiveLogon::CRequestData::SetErrorCode (DWORD dwErrorCode) { _dwErrorCode = dwErrorCode; } // -------------------------------------------------------------------------- // CInteractiveLogon::CRequestData::GetErrorCode // // Arguments: // // Returns: DWORD // // Purpose: Returns the error code from the section. // // History: 2000-12-08 vtan created // -------------------------------------------------------------------------- DWORD CInteractiveLogon::CRequestData::GetErrorCode (void) const { return(_dwErrorCode); } // -------------------------------------------------------------------------- // CInteractiveLogon::CRequestData::OpenEventReply // // Arguments: // // Returns: HANDLE // // Purpose: Opens a handle to the reply event. The reply event is named // in the section object. // // History: 2000-12-08 vtan created // -------------------------------------------------------------------------- HANDLE CInteractiveLogon::CRequestData::OpenEventReply (void) const { return(OpenEvent(EVENT_MODIFY_STATE, FALSE, _szEventReplyName)); } // -------------------------------------------------------------------------- // CInteractiveLogon::CInteractiveLogon // // Arguments: // // Returns: // // Purpose: Constructor for CInteractiveLogon. Create a thread to wait // on the auto-reset event signaled on an external request. This // thread is cleaned up on object destruction and also on // process termination. // // History: 2000-12-08 vtan created // -------------------------------------------------------------------------- CInteractiveLogon::CInteractiveLogon (void) : _hThread(NULL), _fContinue(true), _hwndHost(NULL) { Start(); } // -------------------------------------------------------------------------- // CInteractiveLogon::~CInteractiveLogon // // Arguments: // // Returns: // // Purpose: Terminate the wait thread. Queue an APC to set the member // variable to end the termination. The wait is satisfied and // returns (WAIT_IO_COMPLETION). The loop is exited and the // thread is exited. // // History: 2000-12-08 vtan created // -------------------------------------------------------------------------- CInteractiveLogon::~CInteractiveLogon (void) { Stop(); } // -------------------------------------------------------------------------- // CInteractiveLogon::Start // // Arguments: // // Returns: // // Purpose: Create the thread that listens on interactive logon requests. // // History: 2001-04-06 vtan created // -------------------------------------------------------------------------- void CInteractiveLogon::Start (void) { if (_hThread == NULL) { DWORD dwThreadID; _hThread = CreateThread(NULL, 0, CB_ThreadProc, this, 0, &dwThreadID); } } // -------------------------------------------------------------------------- // CInteractiveLogon::Stop // // Arguments: // // Returns: // // Purpose: Stop the thread that listens on interactive logon requests. // // History: 2001-04-06 vtan created // -------------------------------------------------------------------------- void CInteractiveLogon::Stop (void) { HANDLE hThread; hThread = InterlockedExchangePointer(&_hThread, NULL); if (hThread != NULL) { if (QueueUserAPC(CB_APCProc, hThread, reinterpret_cast(this)) != FALSE) { (DWORD)WaitForSingleObject(hThread, INFINITE); } TBOOL(CloseHandle(hThread)); } } // -------------------------------------------------------------------------- // CInteractiveLogon::SetHostWindow // // Arguments: hwndHost = HWND of the actual UI host. // // Returns: // // Purpose: Sets the HWND into the member variable so that the message // can be sent directly to the UI host rather than the status // host which is a go-between. // // History: 2000-12-08 vtan created // -------------------------------------------------------------------------- void CInteractiveLogon::SetHostWindow (HWND hwndHost) { _hwndHost = hwndHost; } // -------------------------------------------------------------------------- // CInteractiveLogon::Initiate // // Arguments: pszUsername = User name. // pszDomain = Domain. // pszPassword = Password. // dwTimeout = Timeout value. // // Returns: DWORD // // Purpose: External entry point implementing interactive logon requests. // This function checks for privileges and mutexes and events // and does the right thing. // // History: 2001-04-06 vtan created // -------------------------------------------------------------------------- DWORD CInteractiveLogon::Initiate (const WCHAR *pszUsername, const WCHAR *pszDomain, WCHAR *pszPassword, DWORD dwTimeout) { DWORD dwErrorCode; dwErrorCode = CheckInteractiveLogonAllowed(dwTimeout); if (ERROR_SUCCESS == dwErrorCode) { HANDLE hToken; // First authenticate the user with the given credentials for an // interactive logon. Go no further unless that's valid. dwErrorCode = CTokenInformation::LogonUser(pszUsername, pszDomain, pszPassword, &hToken); if (ERROR_SUCCESS == dwErrorCode) { HANDLE hMutex; hMutex = OpenMutex(SYNCHRONIZE | MUTEX_MODIFY_STATE, FALSE, SZ_INTERACTIVE_LOGON_REQUEST_MUTEX_NAME); if (hMutex != NULL) { dwErrorCode = WaitForSingleObject(hMutex, dwTimeout); if (WAIT_OBJECT_0 == dwErrorCode) { DWORD dwSessionID, dwUserSessionID; HANDLE hEvent; // User is authenticated correctly. There are several cases // that need to be handled. dwSessionID = USER_SHARED_DATA->ActiveConsoleId; // Determine if the session has the welcome screen displayed // by opening the named signal event for the session. hEvent = OpenSessionNamedSignalEvent(dwSessionID); if (hEvent != NULL) { TBOOL(CloseHandle(hEvent)); dwErrorCode = SendRequest(pszUsername, pszDomain, pszPassword); } else { // Do whatever needs to be done to log the user on. if (FoundUserSessionID(hToken, &dwUserSessionID)) { if (dwUserSessionID == dwSessionID) { // User is the active console session. No further work needs // to be done. Return success. dwErrorCode = ERROR_SUCCESS; } else { // User is disconnected. Reconnect back to the user session. // If that fails then return the error code back. if (WinStationConnect(SERVERNAME_CURRENT, dwUserSessionID, USER_SHARED_DATA->ActiveConsoleId, L"", TRUE) != FALSE) { dwErrorCode = ERROR_SUCCESS; } else { dwErrorCode = GetLastError(); } } } else { HANDLE hEvent; hEvent = CreateEvent(NULL, TRUE, FALSE, SZ_INTERACTIVE_LOGON_REPLY_EVENT_NAME); if (hEvent != NULL) { // User has no session. If at the welcome screen then send the // request to the welcome screen. Otherwise disconnect the // current session and use a new session to log the user on. dwErrorCode = ShellStartCredentialServer(pszUsername, pszDomain, pszPassword, dwTimeout); if (ERROR_SUCCESS == dwErrorCode) { dwErrorCode = WaitForSingleObject(hEvent, dwTimeout); } TBOOL(CloseHandle(hEvent)); } else { dwErrorCode = GetLastError(); } } } TBOOL(ReleaseMutex(hMutex)); } TBOOL(CloseHandle(hMutex)); } TBOOL(CloseHandle(hToken)); } } return(dwErrorCode); } // -------------------------------------------------------------------------- // CInteractiveLogon::CheckInteractiveLogonAllowed // // Arguments: dwTimeout = Timeout value. // // Returns: DWORD // // Purpose: Check whether the interactive logon request is allowed. To // make this call: // // 1. You must have SE_TCB_PRIVILEGE. // 2. There must be an active console session ID that's valid. // 3. The machine must not be shutting down. // 4. The logon mutex must be available. // // History: 2001-04-06 vtan created // -------------------------------------------------------------------------- DWORD CInteractiveLogon::CheckInteractiveLogonAllowed (DWORD dwTimeout) { DWORD dwErrorCode; // 1. Check for trusted call (SE_TCB_PRIVILEGE). if (SHTestTokenPrivilege(NULL, SE_TCB_NAME) != FALSE) { // 2. Check for active console session. if (USER_SHARED_DATA->ActiveConsoleId != static_cast(-1)) { // 3. Check for machine shutdown. dwErrorCode = CheckShutdown(); if (ERROR_SUCCESS == dwErrorCode) { // 4. Check for mutex availability. dwErrorCode = CheckMutex(dwTimeout); } } else { dwErrorCode = ERROR_NOT_READY; } } else { dwErrorCode = ERROR_PRIVILEGE_NOT_HELD; } return(dwErrorCode); } // -------------------------------------------------------------------------- // CInteractiveLogon::CheckShutdown // // Arguments: // // Returns: DWORD // // Purpose: Returns an error code indicating if the machine is shutting // down or not. If the event cannot be opened then the request // is rejected. // // History: 2001-04-06 vtan created // -------------------------------------------------------------------------- DWORD CInteractiveLogon::CheckShutdown (void) { DWORD dwErrorCode; HANDLE hEvent; hEvent = OpenEvent(SYNCHRONIZE, FALSE, SZ_SHUT_DOWN_EVENT_NAME); if (hEvent != NULL) { if (WAIT_OBJECT_0 == WaitForSingleObject(hEvent, 0)) { dwErrorCode = ERROR_SHUTDOWN_IN_PROGRESS; } else { dwErrorCode = ERROR_SUCCESS; } TBOOL(CloseHandle(hEvent)); } else { dwErrorCode = GetLastError(); } return(dwErrorCode); } // -------------------------------------------------------------------------- // CInteractiveLogon::CheckMutex // // Arguments: dwTimeout = Timeout value. // // Returns: DWORD // // Purpose: Attempts to grab the logon mutex. This ensures that the state // of winlogon is known and it's not busy processing a request. // // History: 2001-04-06 vtan created // -------------------------------------------------------------------------- DWORD CInteractiveLogon::CheckMutex (DWORD dwTimeout) { DWORD dwErrorCode; HANDLE hMutex; hMutex = OpenMutex(SYNCHRONIZE, FALSE, SZ_INTERACTIVE_LOGON_MUTEX_NAME); if (hMutex != NULL) { dwErrorCode = WaitForSingleObject(hMutex, dwTimeout); if ((WAIT_OBJECT_0 == dwErrorCode) || (WAIT_ABANDONED == dwErrorCode)) { TBOOL(ReleaseMutex(hMutex)); dwErrorCode = ERROR_SUCCESS; } } else { dwErrorCode = GetLastError(); } return(dwErrorCode); } // -------------------------------------------------------------------------- // CInteractiveLogon::FoundUserSessionID // // Arguments: hToken = Token of user session to find. // pdwSessionID = Returned session ID. // // Returns: bool // // Purpose: Looks for a user session based on a given token. The match // is made by user SID. // // History: 2001-04-06 vtan created // -------------------------------------------------------------------------- bool CInteractiveLogon::FoundUserSessionID (HANDLE hToken, DWORD *pdwSessionID) { bool fResult; PLOGONID pLogonIDs; ULONG ulEntries; fResult = false; if (WinStationEnumerate(SERVERNAME_CURRENT, &pLogonIDs, &ulEntries) != FALSE) { ULONG ulIndex; PLOGONID pLogonID; for (ulIndex = 0, pLogonID = pLogonIDs; !fResult && (ulIndex < ulEntries); ++ulIndex, ++pLogonID) { if ((pLogonID->State == State_Active) || (pLogonID->State == State_Disconnected)) { ULONG ulReturnLength; WINSTATIONUSERTOKEN winStationUserToken; winStationUserToken.ProcessId = ULongToHandle(GetCurrentProcessId()); winStationUserToken.ThreadId = ULongToHandle(GetCurrentThreadId()); winStationUserToken.UserToken = NULL; if (WinStationQueryInformation(SERVERNAME_CURRENT, pLogonID->SessionId, WinStationUserToken, &winStationUserToken, sizeof(winStationUserToken), &ulReturnLength) != FALSE) { fResult = CTokenInformation::IsSameUser(hToken, winStationUserToken.UserToken); if (fResult) { *pdwSessionID = pLogonID->SessionId; } TBOOL(CloseHandle(winStationUserToken.UserToken)); } } } // Free any resources used. (BOOLEAN)WinStationFreeMemory(pLogonIDs); } return(fResult); } // -------------------------------------------------------------------------- // CInteractiveLogon::SendRequest // // Arguments: pszUsername = Username. // pszDomain = Domain. // pszPassword = Password. This string must be writable. // // Returns: DWORD // // Purpose: This function knows how to transmit the interactive logon // request from (presumably) session 0 to whatever session is // the active console session ID. // // pszUsername must be UNLEN + sizeof('\0') characters. // pszDomain must be DNLEN + sizeof('\0') characters. // pszPassword must be PWLEN + sizeof('\0') characters. // // pszPassword must be writable. The password is copied and // encoded and erased from the source buffer. // // History: 2000-12-07 vtan created // -------------------------------------------------------------------------- DWORD CInteractiveLogon::SendRequest (const WCHAR *pszUsername, const WCHAR *pszDomain, WCHAR *pszPassword) { DWORD dwErrorCode, dwActiveConsoleID; HANDLE hEventReply; dwErrorCode = ERROR_ACCESS_DENIED; // First get the active console session ID. dwActiveConsoleID = USER_SHARED_DATA->ActiveConsoleId; // Create a named event in that session named object space. hEventReply = CreateSessionNamedReplyEvent(dwActiveConsoleID); if (hEventReply != NULL) { HANDLE hEventSignal; hEventSignal = OpenSessionNamedSignalEvent(dwActiveConsoleID); if (hEventSignal != NULL) { HANDLE hSection; // Create a named section that the UI host will open. This code // is executed in the service context so it's always on session 0. hSection = CreateSessionNamedSection(dwActiveConsoleID); if (hSection != NULL) { void *pV; // Map the section into this process address space so we can put // stuff it in. pV = MapViewOfFile(hSection, FILE_MAP_WRITE, 0, 0, 0); if (pV != NULL) { __try { DWORD dwWaitResult; CRequestData *pRequestData; // Fill the section data with the information given. pRequestData = static_cast(pV); pRequestData->Set(pszUsername, pszDomain, pszPassword); // Wake up the waiting thread in the UI host. TBOOL(SetEvent(hEventSignal)); // Wait 15 seconds for a reply the UI host. dwWaitResult = WaitForSingleObject(hEventReply, 15000); // Return an error code accordingly. if (WAIT_OBJECT_0 == dwWaitResult) { dwErrorCode = pRequestData->GetErrorCode(); } else { dwErrorCode = dwWaitResult; } } __except (EXCEPTION_EXECUTE_HANDLER) { dwErrorCode = ERROR_OUTOFMEMORY; } TBOOL(UnmapViewOfFile(pV)); } TBOOL(CloseHandle(hSection)); } TBOOL(CloseHandle(hEventSignal)); } TBOOL(CloseHandle(hEventReply)); } return(dwErrorCode); } // -------------------------------------------------------------------------- // CInteractiveLogon::FormulateObjectBasePath // // Arguments: dwSessionID = Session ID of the named object space. // pszObjectPath = Buffer to receive path. // cchObjecPath = Count of characters in buffer // // Returns: // // Purpose: Creates the correct path to the named object space for the // given session ID. // // History: 2000-12-08 vtan created // -------------------------------------------------------------------------- HRESULT CInteractiveLogon::FormulateObjectBasePath (DWORD dwSessionID, WCHAR *pszObjectPath, size_t cchObjectPath) { HRESULT hr; if (dwSessionID == 0) { hr = StringCchCopyW(pszObjectPath, cchObjectPath, L"\\BaseNamedObjects\\"); } else { hr = StringCchPrintfW(pszObjectPath, cchObjectPath, L"\\Sessions\\%d\\BaseNamedObjects\\", dwSessionID); } return hr; } // -------------------------------------------------------------------------- // CInteractiveLogon::CreateSessionNamedReplyEvent // // Arguments: dwSessionID = Session ID. // // Returns: HANDLE // // Purpose: Creates the named reply event in the target session ID. // // History: 2000-12-08 vtan created // -------------------------------------------------------------------------- HANDLE CInteractiveLogon::CreateSessionNamedReplyEvent (DWORD dwSessionID) { HANDLE hEvent = NULL; UNICODE_STRING eventName; WCHAR szEventName[128]; if (SUCCEEDED(FormulateObjectBasePath(dwSessionID, szEventName, ARRAYSIZE(szEventName))) && SUCCEEDED(StringCchCat(szEventName, ARRAYSIZE(szEventName), s_szEventReplyName)) && NT_SUCCESS(RtlInitUnicodeStringEx(&eventName, szEventName))) { OBJECT_ATTRIBUTES objectAttributes; InitializeObjectAttributes(&objectAttributes, &eventName, 0, NULL, NULL); NtCreateEvent(&hEvent, EVENT_ALL_ACCESS, &objectAttributes, SynchronizationEvent, FALSE); } return hEvent; } // -------------------------------------------------------------------------- // CInteractiveLogon::OpenSessionNamedSignalEvent // // Arguments: dwSessionID = Session ID. // // Returns: HANDLE // // Purpose: Opens the named signal event in the target session ID. // // History: 2000-12-08 vtan created // -------------------------------------------------------------------------- HANDLE CInteractiveLogon::OpenSessionNamedSignalEvent (DWORD dwSessionID) { HANDLE hEvent = NULL; UNICODE_STRING eventName; WCHAR szEventName[128]; if (SUCCEEDED(FormulateObjectBasePath(dwSessionID, szEventName, ARRAYSIZE(szEventName))) && SUCCEEDED(StringCchCat(szEventName, ARRAYSIZE(szEventName), s_szEventSignalName)) && NT_SUCCESS(RtlInitUnicodeStringEx(&eventName, szEventName))) { OBJECT_ATTRIBUTES objectAttributes; InitializeObjectAttributes(&objectAttributes, &eventName, 0, NULL, NULL); NtOpenEvent(&hEvent, EVENT_MODIFY_STATE, &objectAttributes); } return hEvent; } // -------------------------------------------------------------------------- // CInteractiveLogon::CreateSessionNamedSection // // Arguments: dwSessionID = Session ID. // // Returns: HANDLE // // Purpose: Creates a named section object in the target session ID. // // History: 2000-12-08 vtan created // -------------------------------------------------------------------------- HANDLE CInteractiveLogon::CreateSessionNamedSection (DWORD dwSessionID) { HANDLE hSection = NULL; UNICODE_STRING sectionName; WCHAR szSectionName[128]; if (SUCCEEDED(FormulateObjectBasePath(dwSessionID, szSectionName, ARRAYSIZE(szSectionName))) && SUCCEEDED(StringCchCat(szSectionName, ARRAYSIZE(szSectionName), s_szSectionName)) && NT_SUCCESS(RtlInitUnicodeStringEx(§ionName, szSectionName))) { OBJECT_ATTRIBUTES objectAttributes; LARGE_INTEGER sectionSize; InitializeObjectAttributes(&objectAttributes, §ionName, 0, NULL, NULL); sectionSize.LowPart = sizeof(CRequestData); sectionSize.HighPart = 0; NtCreateSection(&hSection, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_WRITE | SECTION_MAP_READ, &objectAttributes, §ionSize, PAGE_READWRITE, SEC_COMMIT, NULL); } return hSection; } // -------------------------------------------------------------------------- // CInteractiveLogon::WaitForInteractiveLogonRequest // // Arguments: // // Returns: // // Purpose: Thread that executes in the UI host context of the receiving // session. This thread waits in an alertable state for the // signal event. If the event is signaled it does work to log the // specified user on. // // History: 2000-12-08 vtan created // -------------------------------------------------------------------------- void CInteractiveLogon::WaitForInteractiveLogonRequest (void) { HANDLE hEvent; // null SA ok, since we run as part of system hEvent = CreateEvent(NULL, FALSE, FALSE, s_szEventSignalName); if (hEvent != NULL) { DWORD dwWaitResult; while (_fContinue) { dwWaitResult = WaitForSingleObjectEx(hEvent, INFINITE, TRUE); if (WAIT_OBJECT_0 == dwWaitResult) { HANDLE hSection; hSection = OpenFileMapping(FILE_MAP_WRITE, FALSE, s_szSectionName); if (hSection != NULL) { void *pV; pV = MapViewOfFile(hSection, FILE_MAP_READ, 0, 0, 0); if (pV != NULL) { __try { DWORD dwErrorCode; HANDLE hEventReply; CRequestData *pRequestData; INTERACTIVE_LOGON_REQUEST interactiveLogonRequest; pRequestData = static_cast(pV); hEventReply = pRequestData->OpenEventReply(); if (hEventReply != NULL) { dwErrorCode = pRequestData->Get(interactiveLogonRequest.szUsername, ARRAYSIZE(interactiveLogonRequest.szUsername), interactiveLogonRequest.szDomain, ARRAYSIZE(interactiveLogonRequest.szDomain), interactiveLogonRequest.szPassword, ARRAYSIZE(interactiveLogonRequest.szPassword)); if (ERROR_SUCCESS == dwErrorCode) { dwErrorCode = static_cast(SendMessage(_hwndHost, WM_UIHOSTMESSAGE, HM_INTERACTIVE_LOGON_REQUEST, reinterpret_cast(&interactiveLogonRequest))); } pRequestData->SetErrorCode(dwErrorCode); TBOOL(SetEvent(hEventReply)); TBOOL(CloseHandle(hEventReply)); } else { dwErrorCode = GetLastError(); pRequestData->SetErrorCode(dwErrorCode); } } __except (EXCEPTION_EXECUTE_HANDLER) { } TBOOL(UnmapViewOfFile(pV)); } TBOOL(CloseHandle(hSection)); } } else { ASSERTMSG((WAIT_FAILED == dwWaitResult) || (WAIT_IO_COMPLETION == dwWaitResult), "Unexpected result from kernel32!WaitForSingleObjectEx in CInteractiveLogon::WaitForInteractiveLogonRequest"); _fContinue = false; } } TBOOL(CloseHandle(hEvent)); } } // -------------------------------------------------------------------------- // CInteractiveLogon::CB_ThreadProc // // Arguments: pParameter = this object. // // Returns: DWORD // // Purpose: Callback function stub to member function. // // History: 2000-12-08 vtan created // -------------------------------------------------------------------------- DWORD WINAPI CInteractiveLogon::CB_ThreadProc (void *pParameter) { static_cast(pParameter)->WaitForInteractiveLogonRequest(); return(0); } // -------------------------------------------------------------------------- // CInteractiveLogon::CB_APCProc // // Arguments: dwParam = this object. // // Returns: // // Purpose: Set object member variable to exit thread loop. // // History: 2000-12-08 vtan created // -------------------------------------------------------------------------- void CALLBACK CInteractiveLogon::CB_APCProc (ULONG_PTR dwParam) { reinterpret_cast(dwParam)->_fContinue = false; } // -------------------------------------------------------------------------- // ::InitiateInteractiveLogon // // Arguments: pszUsername = User name. // pszPassword = Password. // dwTimeout = Time out in milliseconds. // // Returns: BOOL // // Purpose: External entry point function exported by name to initiate // an interactive logon with specified timeout. // // History: 2001-04-10 vtan created // 2001-06-04 vtan added timeout // -------------------------------------------------------------------------- EXTERN_C BOOL WINAPI InitiateInteractiveLogon (const WCHAR *pszUsername, WCHAR *pszPassword, DWORD dwTimeout) { DWORD dwErrorCode; dwErrorCode = CInteractiveLogon::Initiate(pszUsername, L"", pszPassword, dwTimeout); if (ERROR_SUCCESS != dwErrorCode) { SetLastError(dwErrorCode); } return(ERROR_SUCCESS == dwErrorCode); }