windows-nt/Source/XPSP1/NT/shell/ext/gina/credentialtransfer.cpp
2020-09-26 16:20:57 +08:00

1006 lines
33 KiB
C++

// --------------------------------------------------------------------------
// 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);
}