Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

567 lines
15 KiB

// NCProvider.cpp : Implementation of CNCProvider
#include "precomp.h"
#include "NCProv.h"
#include "NCProvider.h"
#include "NCDefs.h"
#include <list>
#include "Buffer.h"
#include "dutils.h"
#include "NCObjAPI.h"
#include <Winntsec.h>
#define COUNTOF(x) (sizeof(x)/sizeof(x[0]))
/////////////////////////////////////////////////////////////////////////////
// CNCProvider
CNCProvider::CNCProvider() :
m_heventDone(NULL),
m_heventConnect(NULL),
m_hPipe( NULL ),
m_hthreadConnect(NULL),
m_pProv(NULL)
{
InitializeCriticalSection(&m_cs);
}
CNCProvider::~CNCProvider()
{
DeleteCriticalSection(&m_cs);
}
void CNCProvider::FinalRelease()
{
//
// do potentially time consuming cleanup in this function rather than
// DTOR. Reason is that ATL decrements the module ref count before calling
// the DTOR. This means that a call to DllCanUnloadNow will return TRUE
// while there is still a call executing in the module. The race condition
// is that the module could be unloaded while it is still being executed.
// ATL will call FinalRelease() before decrementing the module refcount
// making this race condition much smaller. COM addresses this race
// condition by waiting for a bit to unload the module after returning
// TRUE. This wait can be controlled by the delay unload param to
// CoFreeUnusedLibrariesEx(). This allows the call to the last Release()
// of the COM object to finish, before being unloaded.
//
if ( m_hthreadConnect )
{
SetEvent(m_heventDone);
WaitForSingleObject( m_hthreadConnect, INFINITE );
CloseHandle(m_hthreadConnect);
}
if (m_heventDone)
CloseHandle(m_heventDone);
delete m_pProv;
}
HRESULT STDMETHODCALLTYPE CNCProvider::Initialize(
/* [in] */ LPWSTR pszUser,
/* [in] */ LONG lFlags,
/* [in] */ LPWSTR pszNamespace,
/* [in] */ LPWSTR pszLocale,
/* [in] */ IWbemServices __RPC_FAR *pNamespace,
/* [in] */ IWbemContext __RPC_FAR *pCtx,
/* [in] */ IWbemProviderInitSink __RPC_FAR *pInitSink)
{
m_pProv = new CProvInfo;
if ( m_pProv == NULL )
{
return WBEM_E_OUT_OF_MEMORY;
}
m_pProv->SetNamespace(pNamespace);
m_heventDone =
CreateEvent(
NULL,
TRUE,
FALSE,
NULL);
if ( m_heventDone == NULL )
{
return HRESULT_FROM_WIN32( GetLastError() );
}
try
{
m_strNamespace = pszNamespace;
}
catch( _com_error )
{
return WBEM_E_OUT_OF_MEMORY;
}
// Tell Windows Management our initialization status.
return pInitSink->SetStatus( WBEM_S_INITIALIZED, 0 );
}
HRESULT STDMETHODCALLTYPE CNCProvider::SetRegistrationObject(
LONG lFlags,
IWbemClassObject __RPC_FAR *pProvReg)
{
_variant_t vName;
if (SUCCEEDED(pProvReg->Get(
L"Name",
0,
&vName,
NULL,
NULL)) )
{
if ( V_VT(&vName) != VT_BSTR )
return WBEM_E_INVALID_OBJECT;
m_strProvider = V_BSTR(&vName);
}
return S_OK;
}
HRESULT STDMETHODCALLTYPE CNCProvider::AccessCheck(
/* [in] */ WBEM_CWSTR wszQueryLanguage,
/* [in] */ WBEM_CWSTR wszQuery,
/* [in] */ long lSidLength,
/* [unique][size_is][in] */ const BYTE __RPC_FAR *pSid)
{
HRESULT hr;
try
{
hr =
m_pProv->AccessCheck(
wszQueryLanguage,
wszQuery,
lSidLength,
(LPBYTE) pSid);
}
catch(...)
{
hr = WBEM_E_FAILED;
}
return hr;
}
HRESULT STDMETHODCALLTYPE CNCProvider::NewQuery(
/* [in] */ DWORD dwID,
/* [in] */ WBEM_WSTR wszQueryLanguage,
/* [in] */ WBEM_WSTR wszQuery)
{
HRESULT hr;
try
{
hr = m_pProv->NewQuery(dwID, wszQueryLanguage, wszQuery);
}
catch(...)
{
hr = WBEM_E_FAILED;
}
return hr;
}
HRESULT STDMETHODCALLTYPE CNCProvider::CancelQuery(
/* [in] */ DWORD dwID)
{
try
{
// Get rid of the query item(s).
m_pProv->CancelQuery(dwID);
}
catch(...)
{
}
return S_OK;
}
HRESULT STDMETHODCALLTYPE CNCProvider::ProvideEvents(
/* [in] */ IWbemObjectSink __RPC_FAR *pSink,
/* [in] */ long lFlags)
{
DWORD dwID;
IWbemEventSink *pEventSink = NULL;
HRESULT hr;
if (SUCCEEDED(pSink->QueryInterface(
IID_IWbemEventSink, (LPVOID*) &pEventSink)))
{
m_pProv->SetSink(pEventSink);
pEventSink->Release();
if (!m_hthreadConnect)
{
m_hthreadConnect =
CreateThread(
NULL,
0,
(LPTHREAD_START_ROUTINE) ConnectThreadProc,
this,
0,
&dwID);
}
hr = S_OK;
}
else
hr = WBEM_E_FAILED;
return hr;
}
DWORD WINAPI CNCProvider::ConnectThreadProc(CNCProvider *pThis)
{
DWORD dwRet = ERROR_SUCCESS;
if (SUCCEEDED(CoInitializeEx(NULL, COINIT_MULTITHREADED)))
{
try
{
pThis->ConnectLoop();
}
catch( CX_MemoryException )
{
dwRet = ERROR_OUTOFMEMORY;
}
CoUninitialize();
}
return dwRet;
}
// ConnectToNewClient(HANDLE, LPOVERLAPPED)
// This function is called to start an overlapped connect operation.
// It returns TRUE if an operation is pending or FALSE if the
// connection has been completed.
BOOL CNCProvider::ConnectToNewClient(HANDLE hPipe, LPOVERLAPPED lpo)
{
BOOL bConnected,
bPendingIO = FALSE;
// Start an overlapped connection for this pipe instance.
bConnected = ConnectNamedPipe(hPipe, lpo);
// Overlapped ConnectNamedPipe should return zero.
if (bConnected)
return FALSE;
switch (GetLastError())
{
// The overlapped connection in progress.
case ERROR_IO_PENDING:
bPendingIO = TRUE;
break;
// Client is already connected, so signal an event.
case ERROR_PIPE_CONNECTED:
SetEvent(lpo->hEvent);
break;
// If an error occurs during the connect operation...
default:
return FALSE;
}
return bPendingIO;
}
#define PIPE_SIZE 64000
BOOL CNCProvider::CreateAndConnectInstance(LPOVERLAPPED lpoOverlap, BOOL bFirst)
{
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof( SECURITY_ATTRIBUTES );
sa.bInheritHandle = FALSE;
LPWSTR lpwszSD = L"D:" // DACL
L"(A;;GA;;;SY)" // Allow local system full control
L"(A;;GRGW;;;LS)" // Allow local service Read/Write
L"(A;;GRGW;;;NS)"; // Allow network service Read/Write
if ( ConvertStringSecurityDescriptorToSecurityDescriptor(
lpwszSD,
SDDL_REVISION_1,
&(sa.lpSecurityDescriptor),
NULL ) )
{
long lFlags = PIPE_ACCESS_DUPLEX | // read/write access
FILE_FLAG_OVERLAPPED; // overlapped mode
if( bFirst )
{
lFlags |= FILE_FLAG_FIRST_PIPE_INSTANCE;
}
m_hPipe = CreateNamedPipe(
m_szNamedPipe, // pipe name
lFlags,
PIPE_TYPE_MESSAGE | // message-type pipe
PIPE_READMODE_MESSAGE | // message read mode
PIPE_WAIT, // blocking mode
PIPE_UNLIMITED_INSTANCES, // unlimited instances
PIPE_SIZE, // output buffer size
PIPE_SIZE, // input buffer size
0, // client time-out
&sa ); // security per above
if ( INVALID_HANDLE_VALUE == m_hPipe )
{
return FALSE;
}
}
else
{
return FALSE;
}
//
// Make sure that the pipe is owned by us
// Call a subroutine to connect to the new client.
//
return ConnectToNewClient(m_hPipe, lpoOverlap);
/*
HRESULT hr = WBEM_S_NO_ERROR;
SID_IDENTIFIER_AUTHORITY id = SECURITY_NT_AUTHORITY;
PSID pSidSystem;
if (AllocateAndInitializeSid(&id, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0,0,0,0,0,0,&pSidSystem))
{
// Create an everyone SID
PSID pRawSid;
SID_IDENTIFIER_AUTHORITY id2 = SECURITY_WORLD_SID_AUTHORITY;;
if( FALSE == AllocateAndInitializeSid( &id2, 1,0,0,0,0,0,0,0,0, &pRawSid ) )
{
FreeSid ( pSidSystem );
return FALSE;
}
// setup security descriptor with read/write for everyone & owned by local system
// actual check for valid client is performed in CProvInfo::ClientAccessCheck
CNtSid sidWorld( pRawSid );
FreeSid(pRawSid);
CNtAce aceWorld(GENERIC_READ | GENERIC_WRITE, ACCESS_ALLOWED_ACE_TYPE, 0, sidWorld);
CNtSid sidSystem(pSidSystem);
FreeSid ( pSidSystem );
pSidSystem = NULL;
CNtAce aceSystem(FULL_CONTROL, ACCESS_ALLOWED_ACE_TYPE, 0, sidSystem);
CNtAcl ackl;
ackl.AddAce(&aceWorld);
ackl.AddAce(&aceSystem);
ackl.Resize(CNtAcl::MinimumSize);
CNtSecurityDescriptor cSD;
cSD.SetDacl(&ackl);
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.bInheritHandle = true;
sa.lpSecurityDescriptor = (void*)cSD.GetPtr();
long lFlags = PIPE_ACCESS_DUPLEX | // read/write access
FILE_FLAG_OVERLAPPED; // overlapped mode
if(bFirst)
lFlags |= FILE_FLAG_FIRST_PIPE_INSTANCE;
m_hPipe =
CreateNamedPipe(
m_szNamedPipe, // pipe name
lFlags,
PIPE_TYPE_MESSAGE | // message-type pipe
PIPE_READMODE_MESSAGE | // message read mode
PIPE_WAIT, // blocking mode
PIPE_UNLIMITED_INSTANCES, // unlimited instances
PIPE_SIZE, // output buffer size
PIPE_SIZE, // input buffer size
0, // client time-out
&sa); // security per above
}
else // AllocateAndInitSid failed - outta here
return FALSE;
if (m_hPipe == INVALID_HANDLE_VALUE)
return FALSE;
//
// Make sure that the pipe is owned by us
// Call a subroutine to connect to the new client.
return ConnectToNewClient(m_hPipe, lpoOverlap);
*/
}
void CNCProvider::ConnectLoop()
{
// Init our provider info which will tell our comless providers that
// we're ready.
try
{
m_pProv->Init(m_strNamespace, m_strProvider);
}
catch( CX_MemoryException )
{
return;
}
m_heventConnect =
CreateEvent(
NULL, // no security attribute
TRUE, // manual reset event
TRUE, // initial state = signaled
NULL); // unnamed event object
//m_pServerPost = new CPostBuffer(this);
// TODO: We need to indicate an error here.
if (!m_heventConnect)
return;
StringCchPrintf(
m_szNamedPipe,
256,
L"\\\\.\\pipe\\" OBJNAME_NAMED_PIPE L"%s%s",
(LPCWSTR) m_pProv->m_strBaseNamespace,
(LPCWSTR) m_pProv->m_strBaseName);
OVERLAPPED oConnect;
BOOL bSuccess,
bPendingIO;
HANDLE hWait[2] = { m_heventDone, m_heventConnect };
DWORD dwRet;
oConnect.hEvent = m_heventConnect;
bPendingIO = CreateAndConnectInstance(&oConnect, TRUE); // first instance
while ((dwRet = WaitForMultipleObjectsEx(2, hWait, FALSE, INFINITE, TRUE))
!= WAIT_OBJECT_0)
{
if ( dwRet == WAIT_FAILED )
{
break;
}
switch(dwRet)
{
case 1:
{
if (bPendingIO)
{
DWORD dwBytes;
bSuccess =
GetOverlappedResult(
m_hPipe, // pipe handle
&oConnect, // OVERLAPPED structure
&dwBytes, // bytes transferred
FALSE); // does not wait
// TODO: This is an error, but what to do?
if (!bSuccess)
break;
}
CPipeClient *pInfo = new CPipeClient(this, m_hPipe);
if (pInfo)
{
bSuccess =
ReadFileEx(
pInfo->m_hPipe,
pInfo->m_bufferRecv.m_pBuffer,
pInfo->m_bufferRecv.m_dwSize,
&pInfo->m_info.overlap,
(LPOVERLAPPED_COMPLETION_ROUTINE) CompletedReadRoutine);
if (!bSuccess)
DisconnectAndClose(pInfo);
}
bPendingIO = CreateAndConnectInstance(&oConnect, FALSE);
break;
}
case WAIT_IO_COMPLETION:
break;
}
}
CloseHandle(m_hPipe);
CloseHandle(m_heventConnect);
}
void CNCProvider::DisconnectAndClose(CClientInfo *pInfo)
{
m_pProv->RemoveClient(pInfo);
}
void WINAPI CNCProvider::CompletedReadRoutine(
DWORD dwErr,
DWORD nBytesRead,
LPOVERLAPPED pOverlap)
{
CPipeClient *pInfo = ((OLAP_AND_CLIENT*) pOverlap)->pInfo;
CNCProvider *pThis = pInfo->m_pProvider;
#ifndef _DEBUG
try
#endif
{
#ifndef NO_DECODE
if (nBytesRead)
{
pInfo->PostBuffer(pInfo->m_bufferRecv.m_pBuffer, nBytesRead);
}
#endif
}
#ifndef _DEBUG
catch(...)
{
}
#endif
try
{
// The read operation has finished, so write a response (if no
// error occurred).
if (dwErr == 0)
{
BOOL bSuccess;
bSuccess =
ReadFileEx(
pInfo->m_hPipe,
pInfo->m_bufferRecv.m_pBuffer,
pInfo->m_bufferRecv.m_dwSize,
pOverlap,
(LPOVERLAPPED_COMPLETION_ROUTINE) CompletedReadRoutine);
if (!bSuccess)
pThis->DisconnectAndClose(pInfo);
}
else
pThis->DisconnectAndClose(pInfo);
}
catch( CX_MemoryException )
{
}
}