windows-nt/Source/XPSP1/NT/inetsrv/iis/admin/adsi/iisext/csrv.cxx
2020-09-26 16:20:57 +08:00

774 lines
16 KiB
C++

//---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996 - 1997
//
// File: csrv.cxx
//
// Contents: Contains methods for CIISServer object
//
// History: 21-1-98 SophiaC Created.
//
//----------------------------------------------------------------------------
#include "iisext.hxx"
#pragma hdrstop
//
// Period to sleep while waiting for service to attain desired state
//
#define SLEEP_INTERVAL (500L)
#define MAX_SLEEP_INST (60000) // For an instance
// Class CIISServer
DEFINE_IPrivateDispatch_Implementation(CIISServer)
DEFINE_DELEGATING_IDispatch_Implementation(CIISServer)
DEFINE_CONTAINED_IADs_Implementation(CIISServer)
DEFINE_IADsExtension_Implementation(CIISServer)
CIISServer::CIISServer():
_pUnkOuter(NULL),
_pADs(NULL),
_pszServerName(NULL),
_pszMetaBasePath(NULL),
_pAdminBase(NULL),
_pDispMgr(NULL),
_fDispInitialized(FALSE)
{
ENLIST_TRACKING(CIISServer);
}
HRESULT
CIISServer::CreateServer(
IUnknown *pUnkOuter,
REFIID riid,
void **ppvObj
)
{
CCredentials Credentials;
CIISServer FAR * pServer = NULL;
HRESULT hr = S_OK;
BSTR bstrAdsPath = NULL;
OBJECTINFO ObjectInfo;
POBJECTINFO pObjectInfo = &ObjectInfo;
CLexer * pLexer = NULL;
LPWSTR pszIISPathName = NULL;
hr = AllocateServerObject(pUnkOuter, Credentials, &pServer);
BAIL_ON_FAILURE(hr);
//
// get ServerName and pszPath
//
hr = pServer->_pADs->get_ADsPath(&bstrAdsPath);
BAIL_ON_FAILURE(hr);
pLexer = new CLexer();
hr = pLexer->Initialize(bstrAdsPath);
BAIL_ON_FAILURE(hr);
//
// Parse the pathname
//
memset(pObjectInfo, 0, sizeof(OBJECTINFO));
hr = ADsObject(pLexer, pObjectInfo);
BAIL_ON_FAILURE(hr);
pszIISPathName = AllocADsStr(bstrAdsPath);
if (!pszIISPathName) {
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
*pszIISPathName = L'\0';
hr = BuildIISPathFromADsPath(
pObjectInfo,
pszIISPathName
);
BAIL_ON_FAILURE(hr);
hr = pServer->InitializeServerObject(
pObjectInfo->TreeName,
pszIISPathName );
BAIL_ON_FAILURE(hr);
//
// pass non-delegating IUnknown back to the aggregator
//
*ppvObj = (INonDelegatingUnknown FAR *) pServer;
if (bstrAdsPath)
{
ADsFreeString(bstrAdsPath);
}
if (pLexer) {
delete pLexer;
}
if (pszIISPathName ) {
FreeADsStr( pszIISPathName );
}
FreeObjectInfo( &ObjectInfo );
RRETURN(hr);
error:
if (bstrAdsPath)
{
ADsFreeString(bstrAdsPath);
}
if (pLexer) {
delete pLexer;
}
if (pszIISPathName ) {
FreeADsStr( pszIISPathName );
}
FreeObjectInfo( &ObjectInfo );
*ppvObj = NULL;
delete pServer;
RRETURN(hr);
}
CIISServer::~CIISServer( )
{
if (_pszServerName) {
FreeADsStr(_pszServerName);
}
if (_pszMetaBasePath) {
FreeADsStr(_pszMetaBasePath);
}
delete _pDispMgr;
}
STDMETHODIMP
CIISServer::QueryInterface(
REFIID iid,
LPVOID FAR* ppv
)
{
HRESULT hr = S_OK;
hr = _pUnkOuter->QueryInterface(iid,ppv);
RRETURN(hr);
}
HRESULT
CIISServer::AllocateServerObject(
IUnknown *pUnkOuter,
CCredentials& Credentials,
CIISServer ** ppServer
)
{
CIISServer FAR * pServer = NULL;
IADs FAR * pADs = NULL;
CAggregateeDispMgr FAR * pDispMgr = NULL;
HRESULT hr = S_OK;
pServer = new CIISServer();
if (pServer == NULL) {
hr = E_OUTOFMEMORY;
}
BAIL_ON_FAILURE(hr);
pDispMgr = new CAggregateeDispMgr;
if (pDispMgr == NULL) {
hr = E_OUTOFMEMORY;
}
BAIL_ON_FAILURE(hr);
hr = pDispMgr->LoadTypeInfoEntry(
LIBID_ADs,
IID_IADsServiceOperations,
(IADsServiceOperations *)pServer,
DISPID_REGULAR
);
BAIL_ON_FAILURE(hr);
//
// Store the IADs Pointer, but again do NOT ref-count
// this pointer - we keep the pointer around, but do
// a release immediately.
//
hr = pUnkOuter->QueryInterface(IID_IADs, (void **)&pADs);
pADs->Release();
pServer->_pADs = pADs;
//
// Store the pointer to the pUnkOuter object
// AND DO NOT add ref this pointer
//
pServer->_pUnkOuter = pUnkOuter;
//
// Store the pointer to the internal generic object
// AND add ref this pointer
//
pServer->_Credentials = Credentials;
pServer->_pDispMgr = pDispMgr;
*ppServer = pServer;
RRETURN(hr);
error:
delete pDispMgr;
delete pServer;
RRETURN(hr);
}
HRESULT
CIISServer::InitializeServerObject(
LPWSTR pszServerName,
LPWSTR pszPath
)
{
HRESULT hr = S_OK;
if (pszServerName) {
_pszServerName = AllocADsStr(pszServerName);
if (!_pszServerName) {
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
}
if (pszPath) {
_pszMetaBasePath = AllocADsStr(pszPath);
if (!_pszMetaBasePath) {
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
}
hr = InitServerInfo(pszServerName, &_pAdminBase);
BAIL_ON_FAILURE(hr);
error:
RRETURN(hr);
}
STDMETHODIMP
CIISServer::SetPassword(THIS_ BSTR bstrNewPassword)
{
RRETURN(E_NOTIMPL);
}
//+---------------------------------------------------------------------------
//
// Function: CIISServer::Start
//
// Synopsis: Attempts to start the service specified in _bstrServiceName on
// the server named in _bstrPath.
//
// Arguments:
//
// Returns: HRESULT.
//
// Modifies:
//
// History: 01/04/97 SophiaC Created
//
// Notes:
//----------------------------------------------------------------------------
STDMETHODIMP
CIISServer::Start(THIS)
{
RRETURN(IISControlServer(MD_SERVER_COMMAND_START));
}
//+---------------------------------------------------------------------------
//
// Function: CIISServer::Stop
//
// Synopsis: Attempts to stop the service specified in _bstrServiceName on
// the server named in _bstrPath.
//
// Arguments:
//
// Returns: HRESULT.
//
// Modifies:
//
// History: 01/04/96 SophiaC Created
//
//----------------------------------------------------------------------------
STDMETHODIMP
CIISServer::Stop(THIS)
{
RRETURN(IISControlServer(MD_SERVER_COMMAND_STOP));
}
//+---------------------------------------------------------------------------
//
// Function: CIISServer::Pause
//
// Synopsis: Attempts to pause the service named _bstrServiceName on the
// server named in _bstrPath.
//
// Arguments:
//
// Returns: HRESULT.
//
// Modifies:
//
// History: 01-04-96 SophiaC Created
//
//----------------------------------------------------------------------------
STDMETHODIMP
CIISServer::Pause(THIS)
{
RRETURN(IISControlServer(MD_SERVER_COMMAND_PAUSE));
}
//+---------------------------------------------------------------------------
//
// Function: CIISServer::Continue
//
// Synopsis: Attempts to "unpause" the service specified in _bstrServiceName
// on the server named in _bstrPath.
//
// Arguments:
//
// Returns: HRESULT.
//
// Modifies:
//
// History: 01/04/96 SophiaC Created
//
//----------------------------------------------------------------------------
STDMETHODIMP
CIISServer::Continue(THIS)
{
RRETURN(IISControlServer(MD_SERVER_COMMAND_CONTINUE));
}
STDMETHODIMP
CIISServer::get_Status(THIS_ long FAR* plStatusCode)
{
HRESULT hr = S_OK;
DWORD dwStatus = 0;
DWORD dwCurrentState = 0;
if(plStatusCode == NULL){
RRETURN(E_POINTER);
}
hr = IISGetServerState(METADATA_MASTER_ROOT_HANDLE, &dwCurrentState);
BAIL_ON_FAILURE(hr);
*plStatusCode = (long) dwCurrentState;
error:
RRETURN(hr);
}
//
// Helper Functions
//
HRESULT
CIISServer::IISGetServerState(
METADATA_HANDLE hObjHandle,
PDWORD pdwState
)
{
HRESULT hr = S_OK;
DWORD dwBufferSize = sizeof(DWORD);
METADATA_RECORD mdrMDData;
LPBYTE pBuffer = (LPBYTE)pdwState;
MD_SET_DATA_RECORD(&mdrMDData,
MD_SERVER_STATE, // server state
METADATA_NO_ATTRIBUTES,
IIS_MD_UT_SERVER,
DWORD_METADATA,
dwBufferSize,
pBuffer);
hr = _pAdminBase->GetData(
hObjHandle,
_pszMetaBasePath,
&mdrMDData,
&dwBufferSize
);
if (FAILED(hr)) {
if( hr == MD_ERROR_DATA_NOT_FOUND )
{
//
// If the data is not there, but the path exists, then the
// most likely cause is that the service is not running and
// this object was just created.
//
// Since MD_SERVER_STATE would be set as stopped if the
// service were running when the key is added, we'll just
// say that it's stopped.
//
// Note: starting the server or service will automatically set
// the MB value.
//
*pdwState = MD_SERVER_STATE_STOPPED;
hr = S_FALSE;
}
else if ((HRESULT_CODE(hr) == RPC_S_SERVER_UNAVAILABLE) ||
((HRESULT_CODE(hr) >= RPC_S_NO_CALL_ACTIVE) &&
(HRESULT_CODE(hr) <= RPC_S_CALL_FAILED_DNE)) ||
hr == RPC_E_DISCONNECTED) {
hr = ReCacheAdminBase(_pszServerName, &_pAdminBase);
BAIL_ON_FAILURE(hr);
hr = _pAdminBase->GetData(
hObjHandle,
_pszMetaBasePath,
&mdrMDData,
&dwBufferSize
);
BAIL_ON_FAILURE(hr);
}
else
{
BAIL_ON_FAILURE(hr);
}
}
error:
RRETURN(hr);
}
//
// Helper routine for ExecMethod.
// Gets Win32 error from the metabase
//
HRESULT
CIISServer::IISGetServerWin32Error(
METADATA_HANDLE hObjHandle,
HRESULT* phrError)
{
DBG_ASSERT(phrError != NULL);
long lWin32Error = 0;
DWORD dwLen;
METADATA_RECORD mr = {
MD_WIN32_ERROR,
METADATA_NO_ATTRIBUTES,
IIS_MD_UT_SERVER,
DWORD_METADATA,
sizeof(DWORD),
(unsigned char*)&lWin32Error,
0
};
HRESULT hr = _pAdminBase->GetData(
hObjHandle,
_pszMetaBasePath,
&mr,
&dwLen);
if(hr == MD_ERROR_DATA_NOT_FOUND)
{
hr = S_FALSE;
}
//
// Set out param
//
*phrError = HRESULT_FROM_WIN32(lWin32Error);
RRETURN(hr);
}
HRESULT
CIISServer::IISControlServer(
DWORD dwControl
)
{
METADATA_HANDLE hObjHandle = NULL;
DWORD dwTargetState;
DWORD dwPendingState;
DWORD dwState = 0;
DWORD dwSleepTotal = 0L;
HRESULT hr = S_OK;
HRESULT hrMbNode = S_OK;
switch(dwControl)
{
case MD_SERVER_COMMAND_STOP:
dwTargetState = MD_SERVER_STATE_STOPPED;
dwPendingState = MD_SERVER_STATE_STOPPING;
break;
case MD_SERVER_COMMAND_START:
dwTargetState = MD_SERVER_STATE_STARTED;
dwPendingState = MD_SERVER_STATE_STARTING;
break;
case MD_SERVER_COMMAND_CONTINUE:
dwTargetState = MD_SERVER_STATE_STARTED;
dwPendingState = MD_SERVER_STATE_CONTINUING;
break;
case MD_SERVER_COMMAND_PAUSE:
dwTargetState = MD_SERVER_STATE_PAUSED;
dwPendingState = MD_SERVER_STATE_PAUSING;
break;
default:
hr = RETURNCODETOHRESULT(ERROR_INVALID_PARAMETER);
BAIL_ON_FAILURE(hr);
}
hr = IISGetServerState(METADATA_MASTER_ROOT_HANDLE, &dwState);
BAIL_ON_FAILURE(hr);
if (dwState == dwTargetState) {
RRETURN (hr);
}
//
// Write the command to the metabase
//
hr = OpenAdminBaseKey(
_pszServerName,
_pszMetaBasePath,
METADATA_PERMISSION_WRITE,
&_pAdminBase,
&hObjHandle
);
BAIL_ON_FAILURE(hr);
hr = IISSetCommand(hObjHandle, dwControl);
BAIL_ON_FAILURE(hr);
CloseAdminBaseKey(_pAdminBase, hObjHandle);
while (dwSleepTotal < MAX_SLEEP_INST) {
hr = IISGetServerState(METADATA_MASTER_ROOT_HANDLE, &dwState);
BAIL_ON_FAILURE(hr);
hrMbNode = 0;
hr = IISGetServerWin32Error(METADATA_MASTER_ROOT_HANDLE, &hrMbNode);
BAIL_ON_FAILURE(hr);
// check to see if we hit the target state
if (dwState != dwPendingState)
{
//
// Done one way or another
//
if (dwState == dwTargetState)
{
break;
}
}
// check to see if there was a Win32 error from the server
if (FAILED(hrMbNode))
{
hr = hrMbNode;
BAIL_ON_FAILURE(hr);
}
//
// Still pending...
//
::Sleep(SLEEP_INTERVAL);
dwSleepTotal += SLEEP_INTERVAL;
}
if (dwSleepTotal >= MAX_SLEEP_INST)
{
//
// Timed out. If there is a real error in the metabase
// use it, otherwise use a generic timeout error
//
hr = HRESULT_FROM_WIN32(ERROR_SERVICE_REQUEST_TIMEOUT);
}
error :
if (_pAdminBase && hObjHandle) {
CloseAdminBaseKey(_pAdminBase, hObjHandle);
}
RRETURN (hr);
}
HRESULT
CIISServer::IISSetCommand(
METADATA_HANDLE hObjHandle,
DWORD dwControl
)
{
HRESULT hr = S_OK;
DWORD dwBufferSize = sizeof(DWORD);
METADATA_RECORD mdrMDData;
LPBYTE pBuffer = (LPBYTE)&dwControl;
MD_SET_DATA_RECORD(&mdrMDData,
MD_SERVER_COMMAND, // server command
METADATA_NO_ATTRIBUTES,
IIS_MD_UT_SERVER,
DWORD_METADATA,
dwBufferSize,
pBuffer);
hr = _pAdminBase->SetData(
hObjHandle,
L"",
&mdrMDData
);
BAIL_ON_FAILURE(hr);
error:
RRETURN(hr);
}
STDMETHODIMP
CIISServer::ADSIInitializeDispatchManager(
long dwExtensionId
)
{
HRESULT hr = S_OK;
if (_fDispInitialized) {
RRETURN(E_FAIL);
}
hr = _pDispMgr->InitializeDispMgr(dwExtensionId);
if (SUCCEEDED(hr)) {
_fDispInitialized = TRUE;
}
RRETURN(hr);
}
STDMETHODIMP
CIISServer::ADSIInitializeObject(
THIS_ BSTR lpszUserName,
BSTR lpszPassword,
long lnReserved
)
{
CCredentials NewCredentials(lpszUserName, lpszPassword, lnReserved);
_Credentials = NewCredentials;
RRETURN(S_OK);
}
STDMETHODIMP
CIISServer::ADSIReleaseObject()
{
delete this;
RRETURN(S_OK);
}
STDMETHODIMP
CIISServer::NonDelegatingQueryInterface(
REFIID iid,
LPVOID FAR* ppv
)
{
if (IsEqualIID(iid, IID_IADsServiceOperations)) {
*ppv = (IADsUser FAR *) this;
} else if (IsEqualIID(iid, IID_IADsExtension)) {
*ppv = (IADsExtension FAR *) this;
} else if (IsEqualIID(iid, IID_IUnknown)) {
//
// probably not needed since our 3rd party extension does not stand
// alone and provider does not ask for this, but to be safe
//
*ppv = (INonDelegatingUnknown FAR *) this;
} else {
*ppv = NULL;
return E_NOINTERFACE;
}
//
// Delegating AddRef to aggregator for IADsExtesnion and IISServer.
// AddRef on itself for IPrivateUnknown. (both tested.)
//
((IUnknown *) (*ppv)) -> AddRef();
return S_OK;
}
//
// IADsExtension::Operate()
//
STDMETHODIMP
CIISServer::Operate(
THIS_ DWORD dwCode,
VARIANT varUserName,
VARIANT varPassword,
VARIANT varFlags
)
{
RRETURN(E_NOTIMPL);
}