|
|
// --------------------------------------------------------------------------
// Module Name: CredentialTransfer.cpp
//
// Copyright (c) 2001, Microsoft Corporation
//
// Classes to handle credential transfer from one winlogon to another.
//
// History: 2001-01-11 vtan created
// --------------------------------------------------------------------------
#include "StandardHeader.h"
#include "CredentialTransfer.h"
#include <winsta.h>
#include "Access.h"
#include "Compatibility.h"
#include "RegistryResources.h"
#include "StatusCode.h"
// --------------------------------------------------------------------------
// CCredentials::s_hKeyCredentials
// CCredentials::s_szCredentialKeyName
// CCredentials::s_szCredentialValueName
//
// Purpose: Static member variables.
//
// History: 2001-01-12 vtan created
// --------------------------------------------------------------------------
HKEY CCredentials::s_hKeyCredentials = NULL; const TCHAR CCredentials::s_szCredentialKeyName[] = TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\Credentials"); const TCHAR CCredentials::s_szCredentialValueName[] = TEXT("Name");
// --------------------------------------------------------------------------
// CCredentials::CCredentials
//
// Arguments: <none>
//
// Returns: <none>
//
// Purpose: Constructor for CCredentials.
//
// History: 2001-01-12 vtan created
// --------------------------------------------------------------------------
CCredentials::CCredentials (void)
{ }
// --------------------------------------------------------------------------
// CCredentials::~CCredentials
//
// Arguments: <none>
//
// Returns: <none>
//
// Purpose: Destructor for CCredentials.
//
// History: 2001-01-12 vtan created
// --------------------------------------------------------------------------
CCredentials::~CCredentials (void)
{ }
// --------------------------------------------------------------------------
// CCredentials::OpenConduit
//
// Arguments: phPipe = Handle to the named pipe returned.
//
// Returns: NTSTATUS
//
// Purpose: Reads the name of the named pipe from the volatile section of
// the registry and opens the named pipe for read access. Returns
// this handle back to the caller.
//
// History: 2001-01-12 vtan created
// --------------------------------------------------------------------------
NTSTATUS CCredentials::OpenConduit (HANDLE *phPipe)
{ NTSTATUS status; HANDLE hPipe; TCHAR szName[MAX_PATH];
hPipe = NULL; if (s_hKeyCredentials != NULL) { status = GetConduitName(szName, ARRAYSIZE(szName)); if (NT_SUCCESS(status)) { hPipe = CreateFile(szName, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); if (hPipe == INVALID_HANDLE_VALUE) { status = CStatusCode::StatusCodeOfLastError(); } } } else { hPipe = INVALID_HANDLE_VALUE; status = STATUS_ACCESS_DENIED; } *phPipe = hPipe; return(status); }
// --------------------------------------------------------------------------
// CCredentials::CreateConduit
//
// Arguments: pSecurityAttributes = Security to apply to named pipe.
// phPipe = Handle to named pipe returned.
//
// Returns: NTSTATUS
//
// Purpose: Creates a uniquely named pipe and places this name in the
// volatile section of the registry for the open method.
//
// History: 2001-01-12 vtan created
// --------------------------------------------------------------------------
NTSTATUS CCredentials::CreateConduit (LPSECURITY_ATTRIBUTES pSecurityAttributes, HANDLE *phPipe)
{ NTSTATUS status; HANDLE hPipe;
hPipe = NULL; if (s_hKeyCredentials != NULL) { DWORD dwNumber; int iCount; TCHAR szName[MAX_PATH];
dwNumber = GetTickCount(); iCount = 0; do {
// Create a name for the pipe based on the tickcount. If this collides
// with one already there (unlikely but possible) then add tickcount and
// try again. The named pipe is actually short lived.
(NTSTATUS)CreateConduitName(dwNumber, szName); hPipe = CreateNamedPipe(szName, PIPE_ACCESS_OUTBOUND | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, 0, 0, NMPWAIT_USE_DEFAULT_WAIT, pSecurityAttributes); if (hPipe == NULL) { dwNumber += GetTickCount(); status = CStatusCode::StatusCodeOfLastError(); } else { status = STATUS_SUCCESS; } } while (!NT_SUCCESS(status) && (++iCount <= 5)); if (NT_SUCCESS(status)) { status = SetConduitName(szName); } } else { hPipe = NULL; status = STATUS_ACCESS_DENIED; } *phPipe = hPipe; return(status); }
// --------------------------------------------------------------------------
// CCredentials::ClearConduit
//
// Arguments: <none>
//
// Returns: NTSTATUS
//
// Purpose: Clears the named stored in the volatile section of the
// registry.
//
// History: 2001-01-12 vtan created
// --------------------------------------------------------------------------
NTSTATUS CCredentials::ClearConduit (void)
{ return(ClearConduitName()); }
// --------------------------------------------------------------------------
// CCredentials::Pack
//
// Arguments: pLogonIPCCredentials = Credentials to pack.
// ppvData = Block of memory allocated.
// pdwDataSize = Size of block of memory allocated.
//
// Returns: NTSTATUS
//
// Purpose: Packs the credentials into a stream-lined structure for
// transmission across a named pipe. This packs the user name,
// domain and password into a known structure for the client
// to pick up. The password is run encoded. The structure has
// pointer references removed.
//
// History: 2001-01-12 vtan created
// --------------------------------------------------------------------------
NTSTATUS CCredentials::Pack (LOGONIPC_CREDENTIALS *pLogonIPCCredentials, void* *ppvData, DWORD *pdwDataSize)
{ NTSTATUS status; DWORD dwSize, dwSizeUsername, dwSizeDomain, dwSizePassword; unsigned char *pUC;
// Marshall the credentials into the struct that is transferred across
// a named pipe. Calculate the size of the buffer required.
dwSizeUsername = lstrlenW(pLogonIPCCredentials->userID.wszUsername) + sizeof('\0'); dwSizeDomain = lstrlenW(pLogonIPCCredentials->userID.wszDomain) + sizeof('\0'); dwSizePassword = lstrlenW(pLogonIPCCredentials->wszPassword) + sizeof('\0'); *pdwDataSize = dwSize = sizeof(CREDENTIALS) + ((dwSizeUsername + dwSizeDomain + dwSizePassword) * sizeof(WCHAR));
// Allocate the buffer.
*ppvData = pUC = static_cast<unsigned char*>(LocalAlloc(LMEM_FIXED, dwSize)); if (pUC != NULL) { WCHAR *pszUsername, *pszDomain, *pszPassword; CREDENTIALS *pCredentials;
// Establish pointers into the buffer to fill it.
pCredentials = reinterpret_cast<CREDENTIALS*>(pUC); pszUsername = reinterpret_cast<WCHAR*>(pUC + sizeof(CREDENTIALS)); pszDomain = pszUsername + dwSizeUsername; pszPassword = pszDomain + dwSizeDomain;
// Copy the strings into the buffer.
(WCHAR*)lstrcpyW(pszUsername, pLogonIPCCredentials->userID.wszUsername); (WCHAR*)lstrcpyW(pszDomain, pLogonIPCCredentials->userID.wszDomain); (WCHAR*)lstrcpyW(pszPassword, pLogonIPCCredentials->wszPassword);
// Erase the password string given.
ZeroMemory(pLogonIPCCredentials->wszPassword, dwSizePassword * sizeof(WCHAR));
// Prepare a seed for the run encode.
pCredentials->dwSize = dwSize; pCredentials->ucPasswordSeed = static_cast<unsigned char>(GetTickCount());
// Create UNICODE_STRING structures into the buffer.
RtlInitUnicodeString(&pCredentials->username, pszUsername); RtlInitUnicodeString(&pCredentials->domain, pszDomain); RtlInitUnicodeString(&pCredentials->password, pszPassword);
// Run encode the password.
RtlRunEncodeUnicodeString(&pCredentials->ucPasswordSeed, &pCredentials->password);
// Make the pointers relative.
pCredentials->username.Buffer = reinterpret_cast<WCHAR*>(reinterpret_cast<unsigned char*>(pCredentials->username.Buffer) - pUC); pCredentials->domain.Buffer = reinterpret_cast<WCHAR*>(reinterpret_cast<unsigned char*>(pCredentials->domain.Buffer) - pUC); pCredentials->password.Buffer = reinterpret_cast<WCHAR*>(reinterpret_cast<unsigned char*>(pCredentials->password.Buffer) - pUC); status = STATUS_SUCCESS; } else { status = STATUS_NO_MEMORY; } return(status); }
// --------------------------------------------------------------------------
// CCredentials::Unpack
//
// Arguments: pvData = Packed credentials from server.
// pLogonIPCCredentials = Credentials received.
//
// Returns: NTSTATUS
//
// Purpose: Client side usage that unpacks the structure.
//
// History: 2001-01-12 vtan created
// --------------------------------------------------------------------------
NTSTATUS CCredentials::Unpack (void *pvData, LOGONIPC_CREDENTIALS *pLogonIPCCredentials)
{ NTSTATUS status; unsigned char *pUC;
// Marshall the credentials from the struct that is transferred across
// a named pipe.
pUC = static_cast<unsigned char*>(pvData); if (pUC != NULL) { CREDENTIALS *pCredentials;
pCredentials = reinterpret_cast<CREDENTIALS*>(pUC);
// Make the relative pointers absolute again.
pCredentials->username.Buffer = reinterpret_cast<WCHAR*>(pUC + PtrToUlong(pCredentials->username.Buffer)); pCredentials->domain.Buffer = reinterpret_cast<WCHAR*>(pUC + PtrToUlong(pCredentials->domain.Buffer)); pCredentials->password.Buffer = reinterpret_cast<WCHAR*>(pUC + PtrToUlong(pCredentials->password.Buffer));
// Decode the run encoded password.
RtlRunDecodeUnicodeString(pCredentials->ucPasswordSeed, &pCredentials->password);
// Copy it to the caller's struct.
(WCHAR*)lstrcpyW(pLogonIPCCredentials->userID.wszUsername, pCredentials->username.Buffer); (WCHAR*)lstrcpyW(pLogonIPCCredentials->userID.wszDomain, pCredentials->domain.Buffer); (WCHAR*)lstrcpyW(pLogonIPCCredentials->wszPassword, pCredentials->password.Buffer);
// Zero the named pipe buffer.
ZeroMemory(pCredentials->password.Buffer, (lstrlen(pCredentials->password.Buffer) + sizeof('\0')) * sizeof(WCHAR));
status = STATUS_SUCCESS; } else { status = STATUS_INVALID_PARAMETER; } return(status); }
// --------------------------------------------------------------------------
// CCredentials::StaticInitialize
//
// Arguments: fCreate = Create or open the registry key.
//
// Returns: NTSTATUS
//
// Purpose: Creates the volatile key in the registry where the named pipe
// name is placed for the client winlogon to pick. This section
// is volatile and ACL'd to prevent access by anything other than
// S-1-5-18 (NT AUTHORITY\SYSTEM).
//
// History: 2001-01-12 vtan created
// 2001-04-03 vtan add opening capability
// --------------------------------------------------------------------------
NTSTATUS CCredentials::StaticInitialize (bool fCreate)
{ NTSTATUS status;
if (s_hKeyCredentials == NULL) { LONG lErrorCode; PSECURITY_DESCRIPTOR pSecurityDescriptor;
// Build a security descriptor for the registry key that allows:
// S-1-5-18 NT AUTHORITY\SYSTEM KEY_ALL_ACCESS
static SID_IDENTIFIER_AUTHORITY s_SecurityNTAuthority = SECURITY_NT_AUTHORITY;
static const CSecurityDescriptor::ACCESS_CONTROL s_AccessControl[] = { { &s_SecurityNTAuthority, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, KEY_ALL_ACCESS } };
if (fCreate) {
// Build a security descriptor that allows the described access above.
pSecurityDescriptor = CSecurityDescriptor::Create(ARRAYSIZE(s_AccessControl), s_AccessControl); if (pSecurityDescriptor != NULL) { SECURITY_ATTRIBUTES securityAttributes;
securityAttributes.nLength = sizeof(securityAttributes); securityAttributes.lpSecurityDescriptor = pSecurityDescriptor; securityAttributes.bInheritHandle = FALSE; lErrorCode = RegCreateKeyEx(HKEY_LOCAL_MACHINE, s_szCredentialKeyName, 0, NULL, REG_OPTION_VOLATILE, KEY_QUERY_VALUE, &securityAttributes, &s_hKeyCredentials, NULL); (HLOCAL)LocalFree(pSecurityDescriptor); } else { lErrorCode = ERROR_OUTOFMEMORY; } } else { lErrorCode = RegOpenKeyEx(HKEY_LOCAL_MACHINE, s_szCredentialKeyName, 0, KEY_QUERY_VALUE, &s_hKeyCredentials); } status = CStatusCode::StatusCodeOfErrorCode(lErrorCode); } else { status = STATUS_SUCCESS; } return(status); }
// --------------------------------------------------------------------------
// CCredentials::StaticTerminate
//
// Arguments: <none>
//
// Returns: NTSTATUS
//
// Purpose: If a key is present the release the resource.
//
// History: 2001-01-12 vtan created
// --------------------------------------------------------------------------
NTSTATUS CCredentials::StaticTerminate (void)
{ if (s_hKeyCredentials != NULL) { TW32(RegCloseKey(s_hKeyCredentials)); s_hKeyCredentials = NULL; } return(STATUS_SUCCESS); }
// --------------------------------------------------------------------------
// CCredentials::GetConduitName
//
// Arguments: pszName = Buffer for name of named pipe returned.
// dwNameSize = Count of characters of buffer.
//
// Returns: NTSTATUS
//
// Purpose: Gets the name of the named pipe from the volatile section of
// the registry.
//
// History: 2001-01-12 vtan created
// --------------------------------------------------------------------------
NTSTATUS CCredentials::GetConduitName (TCHAR *pszName, DWORD dwNameSize)
{ LONG lErrorCode; CRegKey regKey;
lErrorCode = regKey.Open(HKEY_LOCAL_MACHINE, s_szCredentialKeyName, KEY_QUERY_VALUE); if (ERROR_SUCCESS == lErrorCode) { lErrorCode = regKey.GetString(s_szCredentialValueName, pszName, dwNameSize); } return(CStatusCode::StatusCodeOfErrorCode(lErrorCode)); }
// --------------------------------------------------------------------------
// CCredentials::SetConduitName
//
// Arguments: pszName = Name of the named pipe to write.
//
// Returns: NTSTATUS
//
// Purpose: Writes the name of the named pipe to the secure volatile
// section of the registry.
//
// History: 2001-01-12 vtan created
// --------------------------------------------------------------------------
NTSTATUS CCredentials::SetConduitName (const TCHAR *pszName)
{ LONG lErrorCode; CRegKey regKey;
lErrorCode = regKey.Open(HKEY_LOCAL_MACHINE, s_szCredentialKeyName, KEY_SET_VALUE); if (ERROR_SUCCESS == lErrorCode) { lErrorCode = regKey.SetString(s_szCredentialValueName, pszName); } return(CStatusCode::StatusCodeOfErrorCode(lErrorCode)); }
// --------------------------------------------------------------------------
// CCredentials::ClearConduitName
//
// Arguments: <none>
//
// Returns: NTSTATUS
//
// Purpose: Clears the name of the named pipe in the volatile section of
// the registry.
//
// History: 2001-01-12 vtan created
// --------------------------------------------------------------------------
NTSTATUS CCredentials::ClearConduitName (void)
{ LONG lErrorCode; CRegKey regKey;
lErrorCode = regKey.Open(HKEY_LOCAL_MACHINE, s_szCredentialKeyName, KEY_SET_VALUE); if (ERROR_SUCCESS == lErrorCode) { lErrorCode = regKey.DeleteValue(s_szCredentialValueName); } return(CStatusCode::StatusCodeOfErrorCode(lErrorCode)); }
// --------------------------------------------------------------------------
// CCredentials::CreateConduitName
//
// Arguments: dwNumber = Number to use.
// pszName = Name generated return buffer.
//
// Returns: NTSTATUS
//
// Purpose: Generate a name based on the number for the named pipe. This
// algorithm can be changed and all the callers will get the
// result.
//
// History: 2001-01-12 vtan created
// --------------------------------------------------------------------------
NTSTATUS CCredentials::CreateConduitName (DWORD dwNumber, TCHAR *pszName)
{ (int)wsprintf(pszName, TEXT("\\\\.\\pipe\\LogonCredentials_0x%08x"), dwNumber); return(STATUS_SUCCESS); }
// --------------------------------------------------------------------------
// CCredentialServer::CCredentialServer
//
// Arguments: dwTimeout = Time out to wait.
// pLogonIPCCredentials = Credentials to serve up.
//
// Returns: <none>
//
// Purpose: Constructor for the credential server. Allocate resources
// required for the server end of the named pipe.
//
// History: 2001-01-11 vtan created
// 2001-06-13 vtan added timeout
// --------------------------------------------------------------------------
CCredentialServer::CCredentialServer (DWORD dwTimeout, LOGONIPC_CREDENTIALS *pLogonIPCCredentials) : CThread(), _dwTimeout((dwTimeout != 0) ? dwTimeout : INFINITE), _fTerminate(false), _hPipe(NULL), _pvData(NULL), _dwSize(0)
{ PSECURITY_DESCRIPTOR pSecurityDescriptor;
ASSERTMSG(_dwTimeout != 0, "_dwTimeout cannot be 0 in CCredentialServer::CCredentialServer"); ZeroMemory(&_overlapped, sizeof(_overlapped));
// Build a security descriptor for the named pipe that allows:
// S-1-5-18 NT AUTHORITY\SYSTEM GENERIC_ALL | STANDARD_RIGHTS_ALL
// S-1-5-32-544 <local administrators> READ_CONTROL
static SID_IDENTIFIER_AUTHORITY s_SecurityNTAuthority = SECURITY_NT_AUTHORITY;
static const CSecurityDescriptor::ACCESS_CONTROL s_AccessControl[] = { { &s_SecurityNTAuthority, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, GENERIC_ALL | STANDARD_RIGHTS_ALL }, { &s_SecurityNTAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, READ_CONTROL } };
// Build a security descriptor that allows the described access above.
pSecurityDescriptor = CSecurityDescriptor::Create(ARRAYSIZE(s_AccessControl), s_AccessControl); if (pSecurityDescriptor != NULL) { SECURITY_ATTRIBUTES securityAttributes;
securityAttributes.nLength = sizeof(securityAttributes); securityAttributes.lpSecurityDescriptor = pSecurityDescriptor; securityAttributes.bInheritHandle = FALSE;
// Create the named pipe with the security descriptor.
if (NT_SUCCESS(CCredentials::CreateConduit(&securityAttributes, &_hPipe))) { ASSERTMSG(_hPipe != NULL, "NULL hPipe but success NTSTATUS code in CCredentialServer::CCredentialServer");
// Create an event for overlapped I/O.
_overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); } (HLOCAL)LocalFree(pSecurityDescriptor);
// Package credentials.
TSTATUS(CCredentials::Pack(pLogonIPCCredentials, &_pvData, &_dwSize)); } }
// --------------------------------------------------------------------------
// CCredentialServer::~CCredentialServer
//
// Arguments: <none>
//
// Returns: <none>
//
// Purpose: Destructor for CCredentialServer. Release memory and
// resources.
//
// History: 2001-01-11 vtan created
// --------------------------------------------------------------------------
CCredentialServer::~CCredentialServer (void)
{ ReleaseMemory(_pvData); ReleaseHandle(_overlapped.hEvent); ReleaseHandle(_hPipe); }
// --------------------------------------------------------------------------
// CCredentialServer::IsReady
//
// Arguments: <none>
//
// Returns: bool
//
// Purpose: Is the credential server ready to run?
//
// History: 2001-01-11 vtan created
// --------------------------------------------------------------------------
bool CCredentialServer::IsReady (void) const
{ return((_hPipe != NULL) && (_overlapped.hEvent != NULL)); }
// --------------------------------------------------------------------------
// CCredentialServer::Start
//
// Arguments: pLogonIPCCredentials = Logon credentials.
// dwWaitTime = Timeout value.
//
// Returns: NTSTATUS
//
// Purpose: Starts a new thread as the server of the credentials for the
// new logon session.
//
// History: 2001-04-06 vtan created
// --------------------------------------------------------------------------
NTSTATUS CCredentialServer::Start (LOGONIPC_CREDENTIALS *pLogonIPCCredentials, DWORD dwWaitTime)
{ NTSTATUS status; CCredentialServer *pCredentialServer;
// Otherwise credentials need to be transferred across sessions to
// a newly created session. Start the credential transfer server.
status = STATUS_NO_MEMORY; pCredentialServer = new CCredentialServer(dwWaitTime, pLogonIPCCredentials); if (pCredentialServer != NULL) { if (pCredentialServer->IsCreated() && pCredentialServer->IsReady()) { pCredentialServer->Resume();
// If the server is set up then disconnect the console.
// If this fails then we'll let the server thread timeout
// and terminate itself eventually.
if (WinStationDisconnect(SERVERNAME_CURRENT, USER_SHARED_DATA->ActiveConsoleId, TRUE) != FALSE) { status = STATUS_SUCCESS; if ((dwWaitTime != 0) && (WAIT_OBJECT_0 != pCredentialServer->WaitForCompletion(dwWaitTime))) { status = STATUS_UNSUCCESSFUL; } } else { status = CStatusCode::StatusCodeOfLastError(); } if (!NT_SUCCESS(status)) { pCredentialServer->ExecutePrematureTermination(); } } else { TSTATUS(pCredentialServer->Terminate()); } pCredentialServer->Release(); } return(status); }
// --------------------------------------------------------------------------
// CCredentialServer::Start
//
// Arguments: pszUsername = User name.
// pszDomain = Domain.
// pszPassword = Password.
// dwWaitTime = Timeout value.
//
// Returns: NTSTATUS
//
// Purpose: Package up the parameters into the required struct and pass
// it to the real function.
//
// History: 2001-04-06 vtan created
// --------------------------------------------------------------------------
NTSTATUS CCredentialServer::Start (const WCHAR *pszUsername, const WCHAR *pszDomain, WCHAR *pszPassword, DWORD dwWaitTime)
{ LOGONIPC_CREDENTIALS logonIPCCredentials;
(WCHAR*)lstrcpynW(logonIPCCredentials.userID.wszUsername, pszUsername, ARRAYSIZE(logonIPCCredentials.userID.wszUsername)); (WCHAR*)lstrcpynW(logonIPCCredentials.userID.wszDomain, pszDomain, ARRAYSIZE(logonIPCCredentials.userID.wszDomain)); (WCHAR*)lstrcpynW(logonIPCCredentials.wszPassword, pszPassword, ARRAYSIZE(logonIPCCredentials.wszPassword)); return(Start(&logonIPCCredentials, dwWaitTime)); }
// --------------------------------------------------------------------------
// CCredentialServer::Entry
//
// Arguments: <none>
//
// Returns: DWORD
//
// Purpose: Handles the server side of the named pipe credential transfer.
//
// History: 2001-01-11 vtan created
// --------------------------------------------------------------------------
DWORD CCredentialServer::Entry (void)
{ DWORD dwWaitResult;
// Wait for a client to connect to the named pipe. Wait no more than 30 seconds.
(BOOL)ConnectNamedPipe(_hPipe, &_overlapped); dwWaitResult = WaitForSingleObjectEx(_overlapped.hEvent, _dwTimeout, TRUE); if (!_fTerminate && (dwWaitResult == WAIT_OBJECT_0)) {
// Write the size of the buffer to the named pipe for the client to retrieve.
TBOOL(ResetEvent(_overlapped.hEvent)); if (WriteFileEx(_hPipe, &_dwSize, sizeof(_dwSize), &_overlapped, CB_FileIOCompletionRoutine) != FALSE) { do { dwWaitResult = WaitForSingleObjectEx(_overlapped.hEvent, _dwTimeout, TRUE); } while (!_fTerminate && (dwWaitResult == WAIT_IO_COMPLETION)); if (!_fTerminate) {
// Write the actual contents of the credentials to the named pipe.
TBOOL(ResetEvent(_overlapped.hEvent)); if (WriteFileEx(_hPipe, _pvData, _dwSize, &_overlapped, CB_FileIOCompletionRoutine) != FALSE) { do { dwWaitResult = WaitForSingleObjectEx(_overlapped.hEvent, _dwTimeout, TRUE); } while (!_fTerminate && (dwWaitResult == WAIT_IO_COMPLETION)); } } } } #ifdef DEBUG
else { INFORMATIONMSG("Wait on named pipe LogonCredentials abandoned in CCredentialsServer::Entry"); } #endif
// Disconnect the server side invalidating the client handle.
TBOOL(DisconnectNamedPipe(_hPipe));
// Clear the name of the named pipe used in the volatile section of the registry.
TSTATUS(CCredentials::ClearConduit()); return(0); }
// --------------------------------------------------------------------------
// CCredentialServer::ExecutePrematureTermination
//
// Arguments: <none>
//
// Returns: <none>
//
// Purpose: Queues an APC to the server thread to force it to terminate.
// Don't check for an error. Don't wait for termination.
// Reference counting should ensure that abnormal termination
// will still clean up references correctly.
//
// History: 2001-06-13 vtan created
// --------------------------------------------------------------------------
void CCredentialServer::ExecutePrematureTermination (void)
{ _fTerminate = true; (BOOL)QueueUserAPC(CB_APCProc, _hThread, NULL); }
// --------------------------------------------------------------------------
// CCredentialServer::CB_APCProc
//
// Arguments: dwParam = User defined data.
//
// Returns: <none>
//
// Purpose: APCProc executed on thread in alertable wait state.
//
// History: 2001-06-13 vtan created
// --------------------------------------------------------------------------
void CALLBACK CCredentialServer::CB_APCProc (ULONG_PTR dwParam)
{ UNREFERENCED_PARAMETER(dwParam); }
// --------------------------------------------------------------------------
// CCredentialServer::CB_FileIOCompletionRoutine
//
// Arguments: dwErrorCode = Error code of operation.
// dwNumberOfBytesTransferred = Number of bytes transferred.
// lpOverlapped = OVERLAPPED structure.
//
// Returns: <none>
//
// Purpose: Does nothing but is required for overlapped I/O.
//
// History: 2001-01-11 vtan created
// --------------------------------------------------------------------------
void CALLBACK CCredentialServer::CB_FileIOCompletionRoutine (DWORD dwErrorCode, DWORD dwNumberOfBytesTransferred, LPOVERLAPPED lpOverlapped)
{ UNREFERENCED_PARAMETER(dwErrorCode); UNREFERENCED_PARAMETER(dwNumberOfBytesTransferred);
TBOOL(SetEvent(lpOverlapped->hEvent)); }
// --------------------------------------------------------------------------
// CCredentialClient::Get
//
// Arguments: pLogonIPCCredentials = Credentials returned from server.
//
// Returns: NTSTATUS
//
// Purpose: Opens and reads the named pipe for the credential transfer
// from server (previous winlogon) to client (this winlogon).
//
// History: 2001-01-12 vtan created
// --------------------------------------------------------------------------
NTSTATUS CCredentialClient::Get (LOGONIPC_CREDENTIALS *pLogonIPCCredentials)
{ NTSTATUS status; HANDLE hPipe;
// Open the named pipe.
status = CCredentials::OpenConduit(&hPipe); if (NT_SUCCESS(status)) { DWORD dwSize, dwNumberOfBytesRead;
ASSERTMSG(hPipe != INVALID_HANDLE_VALUE, "INVALID_HANDLE_VALUE in CCredentialClient::Get");
// Read the size of the buffer from the named pipe.
if (ReadFile(hPipe, &dwSize, sizeof(dwSize), &dwNumberOfBytesRead, NULL) != FALSE) { void *pvData;
// Allocate a block of memory for the buffer to be received
// from the named pipe.
pvData = LocalAlloc(LMEM_FIXED, dwSize); if (pvData != NULL) {
// Read the buffer from the named pipe.
if (ReadFile(hPipe, pvData, dwSize, &dwNumberOfBytesRead, NULL) != FALSE) {
// Make an additional read to release the server side of the
// named pipe.
(BOOL)ReadFile(hPipe, &dwSize, sizeof(dwSize), &dwNumberOfBytesRead, NULL);
// Unpack the data into the LOGONIPC_CREDENTIALS parameter buffer.
status = CCredentials::Unpack(pvData, pLogonIPCCredentials); } else { status = CStatusCode::StatusCodeOfLastError(); } (HLOCAL)LocalFree(pvData); } else { status = STATUS_NO_MEMORY; } } else { status = CStatusCode::StatusCodeOfLastError(); } TBOOL(CloseHandle(hPipe)); } return(status); }
|