windows-nt/Source/XPSP1/NT/inetsrv/iis/svcs/infocomm/common/iisadmin.cxx
2020-09-26 16:20:57 +08:00

1098 lines
25 KiB
C++
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1996 Microsoft Corporation
Module Name :
iisadmin.cxx
Abstract:
Contains the admin functions of the IIS_SERVICE class
Author:
Johnson Apacible (JohnsonA) 24-June-1996
--*/
#include "tcpdllp.hxx"
#include <rpc.h>
#include <tsunami.hxx>
#include <iistypes.hxx>
#include "inetreg.h"
#include "tcpcons.h"
#include "apiutil.h"
BOOL
PopulateSiteArray(
LPINET_INFO_SITE_LIST * ppSites,
PVOID pvUnused,
IN IIS_SERVER_INSTANCE * pInst
);
PIIS_SERVICE
IIS_SERVICE::FindFromServiceInfoList(
IN DWORD dwServiceId
)
/*++
Description:
Finds a given Services Info object from the global list.
Arguments:
dwServiceId - Service id of service to look for.
Returns:
pointer to service object, if found.
NULL, otherwise.
--*/
{
PLIST_ENTRY listEntry;
PIIS_SERVICE pInetSvc;
//
// Loop through the list of running internet servers and call the callback
// for each server that has one of the service id bits set
//
AcquireGlobalLock( );
for ( listEntry = sm_ServiceInfoListHead.Flink;
listEntry != &sm_ServiceInfoListHead;
listEntry = listEntry->Flink ) {
pInetSvc = CONTAINING_RECORD(
listEntry,
IIS_SERVICE,
m_ServiceListEntry );
if ( dwServiceId == pInetSvc->QueryServiceId() &&
(pInetSvc->QueryCurrentServiceState() == SERVICE_RUNNING ||
pInetSvc->QueryCurrentServiceState() == SERVICE_PAUSED ) ) {
//
// reference and return
//
if ( !pInetSvc->CheckAndReference( ) ) {
IF_DEBUG( INSTANCE ) {
DBGPRINTF((DBG_CONTEXT,
"Failed to reference service %d\n", dwServiceId));
}
pInetSvc = NULL;
}
ReleaseGlobalLock( );
return pInetSvc;
}
}
ReleaseGlobalLock( );
IF_DEBUG( INSTANCE ) {
DBGPRINTF((DBG_CONTEXT,
"FindFromServiceList cannot find service %d\n", dwServiceId));
}
return NULL;
} // IIS_SERVICE::FindFromServiceInfoList
BOOL
IIS_SERVICE::SetServiceAdminInfo(
IN DWORD dwLevel,
IN DWORD dwServiceId,
IN DWORD dwInstance,
IN BOOL fCommonConfig,
IN INETA_CONFIG_INFO * pConfigInfo
)
/*++
Description:
Sets the service configuration.
Arguments:
dwLevel - Info level
dwServiceId - ID of service to set
dwInstance - ID of instance to set
fCommonConfig - Determines if we should set the common or the service
configuration
pConfigInfo - Configuration structure
Returns:
TRUE on sucess and FALSE if there is a failure
--*/
{
BOOL fRet = TRUE;
PIIS_SERVICE pInetSvc;
DBG_ASSERT( IIS_SERVICE::sm_fInitialized);
IF_DEBUG( INSTANCE ) {
DBGPRINTF((DBG_CONTEXT,
"SetServiceAdmin called for svc %d inst %d\n",
dwServiceId, dwInstance));
}
pInetSvc = FindFromServiceInfoList( dwServiceId );
if ( pInetSvc == NULL ) {
SetLastError( ERROR_SERVICE_NOT_ACTIVE);
fRet = FALSE;
goto exit;
}
//
// Set the parameters and update
//
fRet = pInetSvc->SetInstanceConfiguration(
dwInstance,
dwLevel,
fCommonConfig,
pConfigInfo );
//
// This was referenced in Find
//
pInetSvc->Dereference( );
exit:
return fRet;
} // IIS_SERVICE::SetServiceAdminInfo
BOOL
IIS_SERVICE::GetServiceAdminInfo(
IN DWORD dwLevel,
IN DWORD dwServiceId,
IN DWORD dwInstance,
IN BOOL fCommonConfig,
OUT PDWORD nRead,
OUT LPINETA_CONFIG_INFO * ppConfigInfo
)
/*++
Description:
Gets the service configuration.
Arguments:
dwLevel - Info level of this operation
dwServiceId - ID of service to get
dwInstance - ID of instance to get
fCommonConfig - Determines if we should get the common or the service
configuration
pBuffer - on return, will contains a pointer to
the configuration block
Returns:
TRUE on sucess and FALSE if there is a failure
--*/
{
BOOL fRet = FALSE;
PIIS_SERVICE pInetSvc;
DBG_ASSERT( IIS_SERVICE::sm_fInitialized);
IF_DEBUG( INSTANCE ) {
DBGPRINTF((DBG_CONTEXT,
"GetServiceAdmin called for svc %d inst %x\n",
dwServiceId, dwInstance));
}
pInetSvc = FindFromServiceInfoList( dwServiceId );
if ( pInetSvc == NULL ) {
SetLastError( ERROR_SERVICE_NOT_ACTIVE);
goto exit;
}
//
// Get the params
//
fRet = pInetSvc->GetInstanceConfiguration(
dwInstance,
dwLevel,
fCommonConfig,
nRead,
ppConfigInfo
);
//
// This was referenced in Find
//
pInetSvc->Dereference( );
exit:
return fRet;
} // IIS_SERVICE::GetServiceAdminInfo
BOOL
IIS_SERVICE::GetServiceSiteInfo(
IN DWORD dwServiceId,
OUT LPINET_INFO_SITE_LIST * ppSites
)
/*++
Description:
Gets the list of service instances.
Arguments:
dwServiceId - ID of service to get
ppSites - on return, will contain a pointer to
the array of sites
Returns:
TRUE on sucess and FALSE if there is a failure
--*/
{
BOOL fRet = FALSE;
PIIS_SERVICE pInetSvc;
DWORD cInstances = 0;
LPINET_INFO_SITE_LIST pSites;
DBG_ASSERT( IIS_SERVICE::sm_fInitialized);
IF_DEBUG( INSTANCE ) {
DBGPRINTF((DBG_CONTEXT,
"GetServiceSiteInfo called for svc %d\n",
dwServiceId));
}
pInetSvc = FindFromServiceInfoList( dwServiceId );
if ( pInetSvc == NULL ) {
SetLastError( ERROR_SERVICE_NOT_ACTIVE);
return FALSE;
}
//
// Get the params
//
pInetSvc->AcquireServiceLock(TRUE);
cInstances = pInetSvc->QueryInstanceCount();
//allocate enough memory to hold the Site Info Arrary
pSites = (LPINET_INFO_SITE_LIST)
midl_user_allocate (sizeof(INET_INFO_SITE_LIST) + sizeof(INET_INFO_SITE_ENTRY)*cInstances);
if (!pSites) {
pInetSvc->ReleaseServiceLock(TRUE);
//This was referenced in Find
pInetSvc->Dereference( );
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
*ppSites = pSites;
pSites->cEntries = 0;
fRet = pInetSvc->EnumServiceInstances(
(PVOID) ppSites,
NULL,
(PFN_INSTANCE_ENUM) PopulateSiteArray
);
if (!fRet) {
for (DWORD i=0; i<pSites->cEntries; i++) {
midl_user_free(pSites->aSiteEntry[i].pszComment);
}
midl_user_free(pSites);
*ppSites = NULL;
}
pInetSvc->ReleaseServiceLock(TRUE);
//This was referenced in Find
pInetSvc->Dereference( );
return fRet;
} // IIS_SERVICE::GetServiceSiteInfo
BOOL
PopulateSiteArray(
LPINET_INFO_SITE_LIST * ppSites,
PVOID pvUnused,
IN IIS_SERVER_INSTANCE * pInst
)
/*++
Description:
Fills the ppSites array with the instance id and site comment.
Arguments:
pvUnused - not used
pInst - pointer to service instance
ppSites - on return, will contain a pointer to
the array of sites
Returns:
TRUE on sucess and FALSE if there is a failure
--*/
{
DWORD cbComment = 0;
LPINET_INFO_SITE_LIST pSites = *ppSites;
//Set the instance ID
pSites->aSiteEntry[pSites->cEntries].dwInstance = pInst->QueryInstanceId();
//allocate memory for the site name
cbComment = (strlen(pInst->QuerySiteName())+1) * sizeof(WCHAR);
pSites->aSiteEntry[pSites->cEntries].pszComment = (LPWSTR)midl_user_allocate(cbComment);
if (!(pSites->aSiteEntry[pSites->cEntries].pszComment))
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
//
// Need unicode conversion here
//
if (!MultiByteToWideChar( CP_ACP, // code page
MB_PRECOMPOSED, // character-type options
pInst->QuerySiteName(), // address of string to map
-1, // number of bytes in string
pSites->aSiteEntry[pSites->cEntries].pszComment, // address of wide-character buffer
cbComment / sizeof(WCHAR) // size of buffer
))
{
pSites->aSiteEntry[pSites->cEntries].pszComment[0] = L'\0';
}
pSites->cEntries++;
return TRUE;
} //PopulateSiteArray
DWORD
IIS_SERVICE::GetNewInstanceId(
VOID
)
/*++
Description:
Returns a new instance ID.
Arguments:
None.
Returns:
A non zero dword containing the instance ID.
0 if there was an error.
--*/
{
DWORD dwId;
CHAR regParamKey[MAX_PATH+1];
MB mb( (IMDCOM*) QueryMDObject() );
AcquireServiceLock( );
for (; ; ) {
dwId = ++m_maxInstanceId;
if ( m_maxInstanceId > INET_INSTANCE_MAX ) {
m_maxInstanceId = INET_INSTANCE_MIN;
}
//
// Make sure the metapath does not exist
//
GetMDInstancePath( dwId, regParamKey );
if ( !mb.Open( regParamKey ) ) {
DBG_ASSERT(GetLastError() == ERROR_FILE_NOT_FOUND);
if ( GetLastError() != ERROR_FILE_NOT_FOUND ) {
DBGPRINTF((DBG_CONTEXT,
"Error %d trying to open %s.\n", GetLastError(), regParamKey ));
dwId = 0;
}
break;
}
}
ReleaseServiceLock( );
IF_DEBUG( INSTANCE ) {
DBGPRINTF((DBG_CONTEXT, "GetNewInstanceId returns %d\n", dwId));
}
return dwId;
} // IIS_SERVICE::GetNewInstanceId
BOOL
IIS_SERVICE::SetInstanceConfiguration(
IN DWORD dwInstance,
IN DWORD dwLevel,
IN BOOL fCommonConfig,
IN LPINETA_CONFIG_INFO pConfig
)
/*++
Description:
Set the configuration for the instance.
Arguments:
dwInstance - Instance number to find - IGNORED FOR SET!!
dwLevel - level of information to set
pCommonConfig - Whether info is common or service specific
pConfig - pointer to the configuration block
Returns:
A dword containing the instance ID.
--*/
{
BOOL fRet = FALSE;
PLIST_ENTRY listEntry;
PIIS_SERVER_INSTANCE pInstance;
IF_DEBUG( INSTANCE ) {
DBGPRINTF((DBG_CONTEXT,
"SetInstanceConfiguration called for instance %d\n", dwInstance));
}
//
// Try to find this instance
//
AcquireServiceLock( TRUE );
//
// Find the instance in the instance list
//
if ( dwInstance == INET_INSTANCE_ROOT ) {
DBG_ASSERT( !"Explicit default instance no longer supported inherited from metabase)\n" );
pInstance = NULL;
} else {
pInstance = FindIISInstance( QueryDownLevelInstance() );
}
if ( pInstance != NULL ) {
goto found;
}
SetLastError(ERROR_FILE_NOT_FOUND);
DBG_ASSERT(!fRet);
goto exit;
found:
if ( fCommonConfig ) {
fRet = pInstance->SetCommonConfig( pConfig, TRUE);
} else {
fRet = pInstance->SetServiceConfig( (CHAR *) pConfig);
}
exit:
ReleaseServiceLock( TRUE );
return fRet;
} // IIS_SERVICE::SetInstanceConfiguration
BOOL
IIS_SERVICE::GetInstanceConfiguration(
IN DWORD dwInstance,
IN DWORD dwLevel,
IN BOOL fCommonConfig,
OUT PDWORD nRead,
OUT LPINETA_CONFIG_INFO * pBuffer
)
/*++
Description:
Get the configuration for the instance.
Arguments:
dwInstance - Instance number to find - IGNORED!!
dwLevel - level of information to get
pCommonConfig - Whether info is common or service specific
nRead - pointer to a DWORD where the number of entries to be
returned is set.
pBuffer - pointer to the configuration block
Returns:
A dword containing the instance ID.
--*/
{
PLIST_ENTRY listEntry;
PIIS_SERVER_INSTANCE pInstance;
DWORD nInstances = 1;
DWORD nSize;
PCHAR pConfig;
//
// Set and Get only work against the default instance
//
dwInstance = QueryDownLevelInstance();
IF_DEBUG( INSTANCE ) {
DBGPRINTF((DBG_CONTEXT,
"GetInstanceConfiguration [%x][%d] called for instance %x L%d\n",
this, fCommonConfig, dwInstance, dwLevel));
}
//
// We support only 1
//
*nRead = 0;
*pBuffer = NULL;
if ( fCommonConfig ) {
DBG_ASSERT( dwLevel == 1 );
nSize = sizeof( INETA_CONFIG_INFO );
} else {
DWORD err;
nSize = GetServiceConfigInfoSize(dwLevel);
if ( nSize == 0 ) {
SetLastError(ERROR_INVALID_LEVEL);
return(FALSE);
}
}
//
// Try to find this instance
//
AcquireServiceLock( );
if ( dwInstance == INET_INSTANCE_ALL ) {
nInstances = QueryInstanceCount( );
if ( nInstances == 0 ) {
goto exit;
}
IF_DEBUG(INSTANCE) {
DBGPRINTF((DBG_CONTEXT,"%d instances found\n",nInstances));
}
}
*pBuffer = (LPINETA_CONFIG_INFO) MIDL_user_allocate(nInstances * nSize);
if ( *pBuffer == NULL ) {
goto error_exit;
}
ZeroMemory( *pBuffer, nInstances * nSize );
//
// Loop through the list of running internet servers and call the callback
// for each server that has one of the service id bits set
//
pConfig = (CHAR *) *pBuffer;
if ( dwInstance != INET_INSTANCE_ROOT ) {
for ( listEntry = m_InstanceListHead.Flink;
listEntry != &m_InstanceListHead;
listEntry = listEntry->Flink ) {
pInstance = CONTAINING_RECORD(
listEntry,
IIS_SERVER_INSTANCE,
m_InstanceListEntry );
if ( (dwInstance == pInstance->QueryInstanceId()) ||
(dwInstance == INET_INSTANCE_ALL) ||
(dwInstance == INET_INSTANCE_FIRST) ) {
if ( fCommonConfig ) {
if ( !pInstance->GetCommonConfig(pConfig,dwLevel) ) {
goto error_exit;
}
} else {
if ( !pInstance->GetServiceConfig(pConfig,dwLevel) ) {
goto error_exit;
}
}
//
// if not get all, return.
//
(*nRead)++;
pConfig += nSize;
if ( dwInstance != INET_INSTANCE_ALL ) {
break;
}
}
}
} else {
DBG_ASSERT( !"Default instance no longer supported!\n" );
}
exit:
if ( *nRead == 0 ) {
if ( dwInstance != INET_INSTANCE_ALL ) {
SetLastError(ERROR_FILE_NOT_FOUND);
goto error_exit;
}
}
ReleaseServiceLock( );
DBG_ASSERT(nInstances == *nRead);
return TRUE;
error_exit:
ReleaseServiceLock( );
IF_DEBUG(ERROR) {
DBGPRINTF((DBG_CONTEXT,"Error %x in GetInstanceConfiguration\n",
GetLastError()));
}
if ( *pBuffer != NULL ) {
MIDL_user_free(*pBuffer);
*pBuffer = NULL;
}
*nRead = 0;
return(FALSE);
} // IIS_SERVICE::GetInstanceConfiguration
PIIS_SERVER_INSTANCE
IIS_SERVICE::FindIISInstance(
IN DWORD dwInstance
)
/*++
Description:
Find the instance
*** Service lock assumed held ***
Arguments:
dwInstance - Instance number to find
Returns:
Pointer to the instance.
NULL if not found.
--*/
{
BOOL fRet = TRUE;
PLIST_ENTRY listEntry;
PIIS_SERVER_INSTANCE pInstance;
//
// Find the instance in the instance list
//
for ( listEntry = m_InstanceListHead.Flink;
listEntry != &m_InstanceListHead;
listEntry = listEntry->Flink ) {
pInstance = CONTAINING_RECORD(
listEntry,
IIS_SERVER_INSTANCE,
m_InstanceListEntry );
if ( (dwInstance == pInstance->QueryInstanceId()) ||
(dwInstance == INET_INSTANCE_FIRST) ) {
return pInstance;
}
}
IF_DEBUG( INSTANCE ) {
DBGPRINTF((DBG_CONTEXT,
"FindIISInstance: Cannot find instance %d\n", dwInstance));
}
SetLastError(ERROR_FILE_NOT_FOUND);
return(NULL);
} // IIS_SERVICE::FindIISInstance
BOOL
IIS_SERVICE::DeleteInstanceInfo(
IN DWORD dwInstance
)
{
PIIS_SERVER_INSTANCE pInstance;
DWORD err = NO_ERROR;
IF_DEBUG( INSTANCE ) {
DBGPRINTF((DBG_CONTEXT,
"DeleteInstanceInfo called for %d\n", dwInstance));
}
//
// Find the instance and close it
//
AcquireServiceLock( TRUE );
//
// Find the instance in the instance list
//
pInstance = FindIISInstance( dwInstance );
if( pInstance == NULL ) {
err = ERROR_FILE_NOT_FOUND;
} else {
//
// Remove it from the list
//
RemoveEntryList( &pInstance->m_InstanceListEntry );
m_nInstance--;
//
// Shut it down
//
pInstance->CloseInstance();
//
// Dereference it
//
pInstance->Dereference( );
}
ReleaseServiceLock( TRUE );
if( err == NO_ERROR ) {
return TRUE;
}
SetLastError( err );
return FALSE;
} // IIS_SERVICE::DeleteInstanceInfo
BOOL
IIS_SERVICE::EnumerateInstanceUsers(
IN DWORD dwInstance,
OUT PDWORD nRead,
OUT PCHAR* pBuffer
)
{
PIIS_SERVER_INSTANCE pInstance;
BOOL fRet;
IF_DEBUG( INSTANCE ) {
DBGPRINTF((DBG_CONTEXT,
"EnumerateInstanceUsers called for service %x (Instance %d)\n",
this, dwInstance ));
}
//
// Find the instance
//
AcquireServiceLock( );
//
// Find the instance in the instance list
//
pInstance = FindIISInstance( dwInstance );
if ( pInstance != NULL ) {
goto found;
}
ReleaseServiceLock( );
SetLastError(ERROR_FILE_NOT_FOUND);
return(FALSE);
found:
fRet = pInstance->EnumerateUsers( pBuffer, nRead );
ReleaseServiceLock( );
return(fRet);
} // IIS_SERVICE::EnumerateInstanceUsers
BOOL
IIS_SERVICE::DisconnectInstanceUser(
IN DWORD dwInstance,
IN DWORD dwIdUser
)
{
PIIS_SERVER_INSTANCE pInstance;
BOOL fRet;
IF_DEBUG( INSTANCE ) {
DBGPRINTF((DBG_CONTEXT,
"DisconnectInstanceUsers called for service %x (Instance %d)\n",
this, dwInstance ));
}
//
// Find the instance
//
AcquireServiceLock( );
//
// Find the instance in the instance list
//
pInstance = FindIISInstance( dwInstance );
if ( pInstance != NULL ) {
goto found;
}
ReleaseServiceLock( );
SetLastError(ERROR_FILE_NOT_FOUND);
return(FALSE);
found:
fRet = pInstance->DisconnectUser( dwIdUser );
ReleaseServiceLock( );
return(fRet);
} // IIS_SERVICE::DisconnectInstanceUsers
BOOL
IIS_SERVICE::GetInstanceStatistics(
IN DWORD dwInstance,
IN DWORD dwLevel,
OUT PCHAR* pBuffer
)
{
PIIS_SERVER_INSTANCE pInstance;
BOOL fRet;
IF_DEBUG( INSTANCE ) {
DBGPRINTF((DBG_CONTEXT,
"GetInstanceStats called for service %x (Instance %d)\n",
this, dwInstance ));
}
//
// Find the instance and close it
//
AcquireServiceLock( TRUE);
if (dwInstance == 0 )
{
fRet = GetGlobalStatistics(dwLevel,pBuffer);
}
else if ( dwInstance == INET_INSTANCE_GLOBAL)
{
//
// We need to aggregate statistics across all instances
//
PLIST_ENTRY listEntry;
PCHAR pStats;
BOOL fFirst = TRUE;
fRet = FALSE;
*pBuffer = NULL;
//
// Loop through all the instances and add their counters
//
for ( listEntry = m_InstanceListHead.Flink;
listEntry != &m_InstanceListHead;
listEntry = listEntry->Flink)
{
pInstance = CONTAINING_RECORD(
listEntry,
IIS_SERVER_INSTANCE,
m_InstanceListEntry );
pInstance->LockThisForRead();
fRet = pInstance->GetStatistics(dwLevel, &pStats);
pInstance->UnlockThis();
if (fRet)
{
if (fFirst)
{
//
// This is the first successful retrieval.
//
*pBuffer = pStats;
fFirst = FALSE;
}
else
{
AggregateStatistics(*pBuffer, pStats);
MIDL_user_free(pStats);
}
}
}
}
else
{
//
// Find the instance in the instance list
//
pInstance = FindIISInstance( dwInstance );
if ( pInstance != NULL )
{
fRet = pInstance->GetStatistics(dwLevel,pBuffer);
}
else
{
SetLastError(ERROR_FILE_NOT_FOUND);
fRet = FALSE;
}
}
ReleaseServiceLock( TRUE);
return(fRet);
} // IIS_SERVICE::GetInstanceStatistics
BOOL
IIS_SERVICE::GetGlobalStatistics(
IN DWORD dwLevel,
OUT PCHAR *pBuffer
)
{
return FALSE;
} // IIS_SERVICE::GetGlobalStatistics
BOOL
IIS_SERVICE::ClearInstanceStatistics(
IN DWORD dwInstance
)
{
PIIS_SERVER_INSTANCE pInstance;
BOOL fRet;
IF_DEBUG( INSTANCE ) {
DBGPRINTF((DBG_CONTEXT,
"ClearInstanceStats called for service %x (instance %d)\n",
this, dwInstance ));
}
//
// Find the instance and close it
//
AcquireServiceLock( );
//
// Find the instance in the instance list
//
pInstance = FindIISInstance( dwInstance );
if ( pInstance != NULL ) {
goto found;
}
ReleaseServiceLock( );
SetLastError(ERROR_FILE_NOT_FOUND);
return(FALSE);
found:
fRet = pInstance->ClearStatistics( );
ReleaseServiceLock( );
return(fRet);
} // IIS_SERVICE::ClearInstanceStatistics