2025-04-27 07:49:33 -04:00

1693 lines
45 KiB
C++
Raw 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) 1994 Microsoft Corporation
Module Name :
tsvccfg.cxx
Abstract:
Defines the functions for TCP services Info class.
This module is intended to capture the common scheduler
code for the tcp services ( especially internet services)
which involves the Service Controller dispatch functions.
Also this class provides an interface for common dll of servers.
Author:
Murali R. Krishnan ( MuraliK ) 15-Nov-1994
Project:
Internet Servers Common DLL
--*/
#include "tcpdllp.hxx"
#include <rpc.h>
#include <tsunami.hxx>
#include <iistypes.hxx>
#include <iisendp.hxx>
#include <iisbind.hxx>
#include <iisassoc.hxx>
#include "inetreg.h"
#include "tcpcons.h"
#include "apiutil.h"
#include <iiscnfg.h>
#include <rdns.hxx>
#include <ole2.h>
#include <imd.h>
#include <inetreg.h>
#include <mb.hxx>
//
// Used to configure
//
typedef struct _IIS_SOCKET_CONFIG {
DWORD nAcceptExOutstanding;
} IIS_SOCKET_CONFIG;
IIS_SOCKET_CONFIG TsSocketConfig[3] = {{5}, {40}, {100}};
//
// from security.cxx
//
BOOL
BuildAnonymousAcctDesc(
IN OUT PCHAR pszAcctDesc,
IN const CHAR * pszDomainAndUser,
IN const CHAR * pszPwd,
OUT LPDWORD pdwAcctDescLen
);
BOOL
AppendDottedDecimal(
STR * pstr,
DWORD dwAddress
);
//
// private functions
//
extern VOID
CopyUnicodeStringToBuffer(
OUT WCHAR * pwchBuffer,
IN DWORD cchMaxSize,
IN LPCWSTR pwszSource
);
DWORD
SetInetLogConfiguration(
IN LOGGING *pLogging,
IN EVENT_LOG * pEventLog,
IN const INET_LOG_CONFIGURATION * pRpcLogConfig
);
DWORD
GetRPCLogConfiguration(
LOGGING *pLogging,
OUT LPINET_LOG_CONFIGURATION * ppLogConfig
);
BOOL
GenerateIpList(
BOOL fIsGrant,
ADDRESS_CHECK *pCheck,
LPINET_INFO_IP_SEC_LIST *ppInfo
);
BOOL
FillAddrCheckFromIpList(
BOOL fIsGrant,
LPINET_INFO_IP_SEC_LIST pInfo,
ADDRESS_CHECK *pCheck
);
BOOL
GetVrootCount(
PVOID pvContext,
MB * pmb,
VIRTUAL_ROOT * pvr
);
BOOL
GetVroots(
PVOID pvContext,
MB * pmb,
VIRTUAL_ROOT * pvr
);
VOID
CopyUnicodeStringToBuffer(
OUT WCHAR * pwchBuffer,
IN DWORD cchMaxSize,
IN LPCWSTR pwszSource)
/*
copies at most cbMaxSize-1 characters from pwszSource to pwchBuffer
*/
{
DBG_ASSERT( pwszSource != NULL);
DWORD cchLen = lstrlenW( pwszSource);
if ( cchLen >= cchMaxSize) {
DBGPRINTF( ( DBG_CONTEXT,
"Long String ( %d chars) %ws given."
" Truncating to %d chars\n",
cchLen, pwszSource,
cchMaxSize - 1));
// There is a bug in the lstrcpyn. hence need to work around it.
#ifndef LSTRCPYN_DEBUGGED
cchLen = cchMaxSize - 2;
# else
cchLen = cchMaxSize -1;
# endif
}
#ifndef LSTRCPYN_DEBUGGED
lstrcpynW( pwchBuffer, pwszSource, cchLen + 1);
# else
lstrcpynW( pwchBuffer, pwszSource, cchLen );
# endif
return;
} // CopyUnicodeStringToBuffer()
BOOL
IIS_SERVER_INSTANCE::GetCommonConfig(
IN OUT PCHAR pConfig,
IN DWORD dwLevel
)
/*++
This function copies the current configuration for a service (IIS_SERVER_INSTANCE)
into the given RPC object pConfig.
In case of any failures, it deallocates any memory block that was
allocated during the process of copy by this function alone.
Arguments:
pConfig - pointer to RPC configuration object for a service.
dwLevel - level of our configuration.
Returns:
TRUE for success and FALSE for any errors.
--*/
{
BOOL fReturn = TRUE;
LPIIS_INSTANCE_INFO_1 pInfoConfig = (LPIIS_INSTANCE_INFO_1)pConfig;
ADDRESS_CHECK acCheck;
BOOL fMustRel;
MB mb( (IMDCOM*) m_Service->QueryMDObject() );
DWORD cRoots = 0;
STR strAnon;
STR strAnonPwd;
STR strServerComment;
IF_DEBUG(INSTANCE) {
DBGPRINTF((DBG_CONTEXT,"GetCommonConfig called with L%d for instance %d\n",
dwLevel, QueryInstanceId() ));
}
LockThisForRead();
if ( dwLevel == 2 ) {
LPIIS_INSTANCE_INFO_2 pInfo2 = (LPIIS_INSTANCE_INFO_2)pConfig;
pInfo2->FieldControl = FC_INET_INFO_ALL;
pInfo2->dwInstance = QueryInstanceId( );
//
// HACK: Map MD_SERVER_STATE_* to IIS_SERVER_*.
//
switch( QueryServerState() ) {
case MD_SERVER_STATE_STARTING:
case MD_SERVER_STATE_STARTED:
case MD_SERVER_STATE_CONTINUING:
pInfo2->dwServerState = IIS_SERVER_RUNNING;
break;
case MD_SERVER_STATE_STOPPING:
case MD_SERVER_STATE_STOPPED:
pInfo2->dwServerState = IIS_SERVER_STOPPED;
break;
case MD_SERVER_STATE_PAUSING:
case MD_SERVER_STATE_PAUSED:
pInfo2->dwServerState = IIS_SERVER_PAUSED;
break;
default:
pInfo2->dwServerState = IIS_SERVER_INVALID;
break;
}
pInfo2->sSecurePort = QuerySecurePort();
(VOID)ConvertStringToRpc( &pInfo2->lpszServerName,
""); //QueryServerName());
// (VOID)ConvertStringToRpc( &pInfo2->lpszHostName,
// ""); //QueryHostName());
UnlockThis();
return(TRUE);
}
//
// Get always retrieves all of the parameters except for the anonymous
// password, which is retrieved as a secret
//
pInfoConfig->FieldControl = (FC_INET_INFO_ALL & ~FC_INET_INFO_ANON_PASSWORD);
pInfoConfig->dwInstance = QueryInstanceId( );
pInfoConfig->dwConnectionTimeout = QueryConnectionTimeout();
pInfoConfig->dwMaxConnections = QueryMaxConnections();
pInfoConfig->fAutoStart = IsAutoStart();
pInfoConfig->LangId = GetSystemDefaultLangID();
pInfoConfig->LocalId = GetSystemDefaultLCID();
//
// This is the PSS product ID
//
ZeroMemory( pInfoConfig->ProductId,sizeof( pInfoConfig->ProductId ));
//
// Copy the strings
//
fReturn = (ConvertStringToRpc(&pInfoConfig->lpszAdminName,
""/*QueryAdminName()*/ ) &&
ConvertStringToRpc( &pInfoConfig->lpszAdminEmail,
"" /*QueryAdminEmail()*/ ) &&
// ConvertStringToRpc( &pInfoConfig->lpszHostName,
// "" /*QueryHostName()*/ ) &&
ConvertStringToRpc( &pInfoConfig->lpszServerName,
"" /*QueryServerName()*/) &&
ConvertStringToRpc( &pInfoConfig->lpszDefBasicAuthDomain,
"" /*QueryDefaultLogonDomain()*/)
);
if ( !fReturn ) {
IF_DEBUG(INSTANCE) {
DBGPRINTF((DBG_CONTEXT,"ConvertStringToRpc failed with %d\n",
GetLastError() ));
}
goto Exit;
} else {
DWORD dwError;
dwError = GetRPCLogConfiguration(&m_Logging,
&pInfoConfig->lpLogConfig);
if ( pInfoConfig->lpLogConfig != NULL )
{
// convert the structure to RPC
}
if ( dwError != NO_ERROR) {
IF_DEBUG(INSTANCE) {
DBGPRINTF((DBG_CONTEXT,"GetRPCLogConfiguration failed with %d\n",
dwError));
}
SetLastError( dwError);
fReturn = FALSE;
goto Exit;
}
}
pInfoConfig->fLogAnonymous = QueryLogAnonymous();
pInfoConfig->fLogNonAnonymous = QueryLogNonAnonymous();
pInfoConfig->sSecurePort = QuerySecurePort();
ZeroMemory(
pInfoConfig->szAnonPassword,
sizeof( pInfoConfig->szAnonPassword )
);
//
// Copy the IP security info from metabase
//
if ( mb.Open( QueryMDVRPath() ) )
{
VOID * pvData;
DWORD cbData;
DWORD dwTag;
if ( mb.ReferenceData( "",
MD_IP_SEC,
IIS_MD_UT_FILE,
BINARY_METADATA,
&pvData,
&cbData,
&dwTag ) &&
dwTag )
{
acCheck.BindCheckList( (BYTE *) pvData, cbData );
fMustRel = TRUE;
}
else
{
fMustRel = FALSE;
}
fReturn = GenerateIpList( TRUE, &acCheck, &pInfoConfig->GrantIPList ) &&
GenerateIpList( FALSE, &acCheck, &pInfoConfig->DenyIPList );
if ( fMustRel )
{
DBG_REQUIRE( mb.ReleaseReferenceData( dwTag ));
}
DBG_REQUIRE( mb.Close() );
}
else
{
fReturn = FALSE;
}
if ( !fReturn )
{
goto Exit;
}
//
// Copy the virtual root info, note a NULL VirtualRoots is not
// valid as it is for IP security. This should be the last
// allocated item for the pConfig structure
//
if ( TsEnumVirtualRoots( GetVrootCount, &cRoots ) )
{
DWORD cbSize = sizeof(INET_INFO_VIRTUAL_ROOT_LIST) +
cRoots * sizeof(INET_INFO_VIRTUAL_ROOT_ENTRY)
;
pInfoConfig->VirtualRoots = (LPINET_INFO_VIRTUAL_ROOT_LIST)
MIDL_user_allocate( cbSize );
memset( pInfoConfig->VirtualRoots, 0, cbSize );
if ( pInfoConfig->VirtualRoots )
{
fReturn = TsEnumVirtualRoots( GetVroots, pInfoConfig->VirtualRoots );
}
}
if ( !fReturn )
{
goto Exit;
}
if ( !mb.Open( QueryMDPath() ))
{
fReturn = FALSE;
goto Exit;
}
if ( !mb.GetDword( "",
MD_AUTHORIZATION,
IIS_MD_UT_FILE,
&pInfoConfig->dwAuthentication ))
{
pInfoConfig->dwAuthentication = MD_AUTH_ANONYMOUS;
}
if ( !mb.GetStr( "",
MD_ANONYMOUS_USER_NAME,
IIS_MD_UT_FILE,
&strAnon,
METADATA_INHERIT,
"<>" ))
{
fReturn = FALSE;
goto Exit;
}
if ( !mb.GetStr( "",
MD_SERVER_COMMENT,
IIS_MD_UT_SERVER,
&strServerComment,
METADATA_INHERIT,
INETA_DEF_SERVER_COMMENT ))
{
//
// If this is a single instance service, this is also the
// service comment
//
if ( !m_Service->IsMultiInstance() ) {
m_Service->SetServiceComment( strServerComment.QueryStr() );
}
}
fReturn = ConvertStringToRpc( &pInfoConfig->lpszServerComment,
strServerComment.QueryStr() ) &&
ConvertStringToRpc( &pInfoConfig->lpszAnonUserName,
strAnon.QueryStr() );
//
// Get the anonymous user password but store it as an LSA secret
//
if ( mb.GetStr( "",
MD_ANONYMOUS_PWD,
IIS_MD_UT_FILE,
&strAnonPwd,
METADATA_INHERIT | METADATA_SECURE ))
{
#if 0
fReturn = SetSecret( QueryService()->QueryAnonSecret,
strAnonPwd.QueryStr() );
#endif
}
if ( !fReturn ) {
IF_DEBUG(INSTANCE) {
DBGPRINTF((DBG_CONTEXT,"Cannot get anonymous user name"));
}
}
Exit:
if ( !fReturn ) {
if ( pInfoConfig->lpLogConfig != NULL) {
MIDL_user_free( pInfoConfig->lpLogConfig);
pInfoConfig->lpLogConfig = NULL;
}
//
// FreeRpcString checks for NULL pointer
//
FreeRpcString( pInfoConfig->lpszAdminName );
FreeRpcString( pInfoConfig->lpszAdminEmail );
FreeRpcString( pInfoConfig->lpszServerComment );
// FreeRpcString( pInfoConfig->lpszHostName );
FreeRpcString( pInfoConfig->lpszAnonUserName );
if ( pInfoConfig->DenyIPList ) {
MIDL_user_free( pInfoConfig->DenyIPList );
pInfoConfig->DenyIPList = NULL;
}
if ( pInfoConfig->GrantIPList ) {
MIDL_user_free( pInfoConfig->GrantIPList );
pInfoConfig->GrantIPList = NULL;
}
}
UnlockThis();
return (fReturn);
} // IIS_SERVER_INSTANCE::GetConfiguration()
BOOL
IIS_SERVER_INSTANCE::RegReadCommonParams(
BOOL fReadVirtualDirs
)
/*++
Description
Reads the service common items from the registry
Arguments:
Note:
--*/
{
MB mb( (IMDCOM*) m_Service->QueryMDObject() );
DBG_ASSERT( QueryInstanceId() != INET_INSTANCE_ROOT );
IF_DEBUG( DLL_RPC) {
DBGPRINTF(( DBG_CONTEXT,
"IIS_SERVER_INSTANCE::ReadParamsFromRegistry() Entered\n"));
}
//
// Open the metabase and read parameters for IIS_SERVER_INSTANCE object
// itself.
//
if ( !mb.Open( QueryMDPath(),
METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE )) {
DBGPRINTF(( DBG_CONTEXT,
"[ReadParamsFromRegistry] mb.Open returned error %d for path %s\n",
GetLastError(),
QueryMDPath() ));
#if 1 // Temporary until setup writes values to the metabase - Note this case
// happens when the default instance is created and the metabase doesn't
// exist yet - thus /LM/W3Svc/ doesn't exist. This creates both the
// default instance and the first real server instance.
//
if ( !mb.Open( METADATA_MASTER_ROOT_HANDLE,
METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE ) ||
!mb.AddObject( "/LM/W3SVC" ))
{
DBGPRINTF(( DBG_CONTEXT,
"[ReadParamsFromRegistry] Unable to create meta path, error %d\n",
GetLastError() ));
return FALSE;
}
#else
return FALSE;
#endif
}
LockThisForWrite();
if ( !mb.GetDword( "",
MD_CONNECTION_TIMEOUT,
IIS_MD_UT_SERVER,
&m_dwConnectionTimeout )) {
m_dwConnectionTimeout = INETA_DEF_CONNECTION_TIMEOUT;
}
if ( !mb.GetDword( "",
MD_MAX_CONNECTIONS,
IIS_MD_UT_SERVER,
&m_dwMaxConnections )) {
m_dwMaxConnections = INETA_DEF_MAX_CONNECTIONS;
}
if ( !mb.GetDword( "",
MD_MAX_ENDPOINT_CONNECTIONS,
IIS_MD_UT_SERVER,
&m_dwMaxEndpointConnections )) {
m_dwMaxEndpointConnections = INETA_DEF_MAX_ENDPOINT_CONNECTIONS;
}
if ( !mb.GetDword( "",
MD_LEVELS_TO_SCAN,
IIS_MD_UT_SERVER,
&m_dwLevelsToScan )) {
m_dwLevelsToScan = INETA_DEF_LEVELS_TO_SCAN;
}
//
// if not NTS, limit the connections. If reg value exceeds 40,
// set it to 10.
//
if ( !TsIsNtServer() ) {
if ( m_dwMaxConnections > INETA_MAX_MAX_CONNECTIONS_PWS ) {
m_dwMaxConnections = INETA_DEF_MAX_CONNECTIONS_PWS;
}
if ( m_dwMaxEndpointConnections > INETA_MAX_MAX_ENDPOINT_CONNECTIONS_PWS ) {
m_dwMaxEndpointConnections = INETA_DEF_MAX_ENDPOINT_CONNECTIONS_PWS;
}
}
//
// Log anonymous and Log non-anonymous or for FTP only
//
if ( !mb.GetDword( "",
MD_LOG_ANONYMOUS,
IIS_MD_UT_SERVER,
(DWORD *) &m_fLogAnonymous )) {
m_fLogAnonymous = INETA_DEF_LOG_ANONYMOUS;
}
if ( !mb.GetDword( "",
MD_LOG_NONANONYMOUS,
IIS_MD_UT_SERVER,
(DWORD *) &m_fLogNonAnonymous )) {
m_fLogNonAnonymous = INETA_DEF_LOG_NONANONYMOUS;
}
DWORD dwSPort;
if ( !mb.GetDword( "",
MD_SECURE_PORT,
IIS_MD_UT_SERVER,
&dwSPort )) {
dwSPort = 0;
}
m_sSecurePort = (USHORT) dwSPort;
if ( !mb.GetDword( "",
MD_SERVER_AUTOSTART,
IIS_MD_UT_SERVER,
(DWORD *) &m_fAutoStart )) {
m_fAutoStart = TRUE;
}
//
// Take this opportunity to write a reasonable initial server
// state into the metabase.
//
if( !mb.SetDword( "",
MD_SERVER_STATE,
IIS_MD_UT_SERVER,
MD_SERVER_STATE_STOPPED )) {
DBGPRINTF((
DBG_CONTEXT,
"RegReadCommonParams: cannot set server state, error %lu [ignoring]\n",
GetLastError()
));
}
if( !mb.SetDword( "",
MD_WIN32_ERROR,
IIS_MD_UT_SERVER,
NO_ERROR )) {
DBGPRINTF((
DBG_CONTEXT,
"RegReadCommonParams: cannot set win32 status, error %lu [ignoring]\n",
GetLastError()
));
}
//
// Other fields
//
//
// socket values
//
if ( !mb.GetDword( "",
MD_SERVER_SIZE,
IIS_MD_UT_SERVER,
&m_dwServerSize )) {
m_dwServerSize = INETA_DEF_SERVER_SIZE;
}
if ( m_dwServerSize > MD_SERVER_SIZE_LARGE ) {
m_dwServerSize = INETA_DEF_SERVER_SIZE;
}
if ( !mb.GetDword( "",
MD_SERVER_LISTEN_BACKLOG,
IIS_MD_UT_SERVER,
&m_nAcceptExOutstanding )) {
m_nAcceptExOutstanding =
TsSocketConfig[m_dwServerSize].nAcceptExOutstanding;
}
if ( !mb.GetDword( "",
MD_SERVER_LISTEN_TIMEOUT,
IIS_MD_UT_SERVER,
&m_AcceptExTimeout )) {
m_AcceptExTimeout = INETA_DEF_ACCEPTEX_TIMEOUT;
}
// Root instance does not have VRs. Close the metabase because the
// virtual directories are going to be re-enumerated.
//
mb.Close();
if ( fReadVirtualDirs ) {
TsReadVirtualRoots( );
}
UnlockThis();
return TRUE;
} // IIS_SERVER_INSTANCE::ReadParamsFromRegistry()
BOOL
IIS_SERVER_INSTANCE::SetCommonConfig(
IN LPIIS_INSTANCE_INFO_1 pInfoConfig,
IN BOOL fRefresh
)
/*++
Description
Writes the service common items to the registry
Arguments:
pInfoConfig - Admin items to write to the registry
fRefresh - Indicates whether we need to read back the data
Note:
We don't need to lock "this" object because we only write to the registry
The anonymous password is set as a secret from the client side
--*/
{
DWORD err = NO_ERROR;
FIELD_CONTROL fcConfig;
ADDRESS_CHECK acCheck;
BUFFER buff;
MB mb( (IMDCOM*) m_Service->QueryMDObject() );
//
// Open the metabase and read parameters for IIS_SERVER_INSTANCE object
// itself.
//
if ( !mb.Open( QueryMDPath(),
METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE )) {
DBGPRINTF(( DBG_CONTEXT,
"[SetCommonConfig] mb.Open returned error %d for path %s\n",
GetLastError(),
QueryMDPath() ));
return FALSE;
}
fcConfig = pInfoConfig->FieldControl;
if ( IsFieldSet( fcConfig, FC_INET_INFO_CONNECTION_TIMEOUT ))
{
mb.SetDword( "",
MD_CONNECTION_TIMEOUT,
IIS_MD_UT_SERVER,
pInfoConfig->dwConnectionTimeout );
}
if ( (err == NO_ERROR) && IsFieldSet( fcConfig, FC_INET_INFO_MAX_CONNECTIONS ))
{
mb.SetDword( "",
MD_MAX_CONNECTIONS,
IIS_MD_UT_SERVER,
pInfoConfig->dwMaxConnections );
}
if ( (err == NO_ERROR) &&
IsFieldSet( fcConfig, FC_INET_INFO_SERVER_COMMENT ) &&
(pInfoConfig->lpszServerComment != NULL) )
{
if ( buff.Resize( 2 * (wcslen(pInfoConfig->lpszServerComment) + 1) *
sizeof(CHAR) ) )
{
(VOID) ConvertUnicodeToAnsi( pInfoConfig->lpszServerComment,
(CHAR *) buff.QueryPtr(),
buff.QuerySize() );
mb.SetString( "",
MD_SERVER_COMMENT,
IIS_MD_UT_SERVER,
(CHAR *) buff.QueryPtr() );
}
}
#if 0
if ( (err == NO_ERROR) &&
IsFieldSet( fcConfig, FC_INET_INFO_HOST_NAME ) &&
(pInfoConfig->lpszHostName != NULL) )
{
if ( buff.Resize( 2 * (wcslen(pInfoConfig->lpszHostName) + 1) *
sizeof(CHAR) ) )
{
(VOID) ConvertUnicodeToAnsi( pInfoConfig->lpszHostName,
(CHAR *) buff.QueryPtr(),
buff.QuerySize() );
mb.SetData( "",
MD_HOSTNAME,
IIS_MD_UT_SERVER,
(CHAR *) buff.QueryPtr() );
}
err = WriteRegistryStringW( hkey,
INETA_HOST_NAME_W,
pInfoConfig->lpszHostName,
(wcslen( pInfoConfig->lpszHostName ) + 1) *
sizeof( WCHAR ),
REG_SZ);
}
if ( (err == NO_ERROR) && IsFieldSet( fcConfig, FC_INET_INFO_PORT_NUMBER ))
{
err = WriteRegistryDword( hkey,
INETA_PORT,
(USHORT) pInfoConfig->sPort);
}
if ( (err == NO_ERROR) && IsFieldSet( fcConfig, FC_INET_INFO_SECURE_PORT_NUMBER ))
{
err = WriteRegistryDword( hkey,
INETA_PORT_SECURE,
(USHORT) pInfoConfig->sSecurePort);
}
#endif
if ( (err == NO_ERROR) &&
IsFieldSet( fcConfig, FC_INET_INFO_ANON_USER_NAME ) &&
(pInfoConfig->lpszAnonUserName != NULL) )
{
if ( buff.Resize( 2 * (wcslen(pInfoConfig->lpszAnonUserName) + 1) *
sizeof(CHAR) ) )
{
(VOID) ConvertUnicodeToAnsi( pInfoConfig->lpszAnonUserName,
(CHAR *) buff.QueryPtr(),
buff.QuerySize() );
mb.SetString( "",
MD_ANONYMOUS_USER_NAME,
IIS_MD_UT_FILE,
(CHAR *) buff.QueryPtr() );
}
}
if ( (err == NO_ERROR) && IsFieldSet( fcConfig, FC_INET_INFO_AUTHENTICATION ))
{
mb.SetDword( "",
MD_AUTHORIZATION,
IIS_MD_UT_FILE,
pInfoConfig->dwAuthentication );
}
//
// Write other fields
//
if ( (err == NO_ERROR) &&
IsFieldSet( fcConfig, FC_INET_INFO_SITE_SECURITY ))
{
if ( (pInfoConfig->GrantIPList && pInfoConfig->GrantIPList->cEntries)
|| (pInfoConfig->DenyIPList && pInfoConfig->DenyIPList->cEntries) )
{
acCheck.BindCheckList( NULL, 0 );
if ( FillAddrCheckFromIpList( TRUE, pInfoConfig->GrantIPList, &acCheck ) &&
FillAddrCheckFromIpList( FALSE, pInfoConfig->DenyIPList, &acCheck ) )
{
if ( !mb.SetData( "IIS_MD_INSTANCE_ROOT",
MD_IP_SEC,
IIS_MD_UT_FILE,
BINARY_METADATA,
(acCheck.GetStorage()->GetAlloc()
? acCheck.GetStorage()->GetAlloc() : (LPBYTE)""),
acCheck.GetStorage()->GetUsed(),
METADATA_INHERIT | METADATA_REFERENCE ))
{
err = GetLastError();
}
}
acCheck.UnbindCheckList();
}
else
{
if ( !mb.DeleteData( "IIS_MD_INSTANCE_ROOT",
MD_IP_SEC,
IIS_MD_UT_FILE,
BINARY_METADATA ) )
{
// not an error : property may not exists
//err = GetLastError();
}
}
}
DBG_REQUIRE( mb.Close() );
if ( (err == NO_ERROR) &&
IsFieldSet( fcConfig, FC_INET_INFO_LOG_CONFIG) &&
(pInfoConfig->lpLogConfig != NULL) ) {
err = SetInetLogConfiguration(&m_Logging,
m_Service->QueryEventLog(),
pInfoConfig->lpLogConfig);
if ( err != NO_ERROR) {
DBGPRINTF(( DBG_CONTEXT,
"SetConfiguration() SetInetLogConfig() failed. "
" Err=%u\n",
err));
} else {
m_Logging.Active();
}
}
if ( (err == NO_ERROR) &&
IsFieldSet( fcConfig, FC_INET_INFO_VIRTUAL_ROOTS )) {
if ( QueryInstanceId() != INET_INSTANCE_ROOT ) {
if ( !TsSetVirtualRoots( pInfoConfig
)) {
err = GetLastError();
DBGPRINTF(( DBG_CONTEXT,
"[SetConfiguration()]SetVirtualRoots "
" returns error %d\n",
err));
}
}
}
if ( err != NO_ERROR ) {
IF_DEBUG( ERROR) {
DBGPRINTF(( DBG_CONTEXT,
"IIS_SERVER_INSTANCE::SetCommonConfig ==> Error = %u\n",
err));
}
SetLastError( err );
return(FALSE);
}
return TRUE;
} // IIS_SERVER_INSTANCE::SetCommonConfig
VOID
IIS_SERVER_INSTANCE::MDChangeNotify(
MD_CHANGE_OBJECT * pcoChangeList
)
/*++
This method handles the metabase change notification for this service.
Arguments:
pcoChangeList - path and id that has changed
--*/
{
DWORD i;
DWORD status;
BOOL fVRUpdated = FALSE;
BOOL fReadCommon = FALSE;
BOOL fShouldMirror = FALSE;
if ( (pcoChangeList->dwMDChangeType &
(MD_CHANGE_TYPE_DELETE_OBJECT |
MD_CHANGE_TYPE_RENAME_OBJECT |
MD_CHANGE_TYPE_ADD_OBJECT) ) != 0 )
{
//
// Something got added/deleted/renamed
//
fShouldMirror = TRUE;
}
LockThisForWrite();
for ( i = 0; i < pcoChangeList->dwMDNumDataIDs; i++ )
{
m_Logging.NotifyChange( pcoChangeList->pdwMDDataIDs[i] );
switch ( pcoChangeList->pdwMDDataIDs[i] )
{
case MD_SERVER_BINDINGS:
if( QueryServerState() != MD_SERVER_STATE_STOPPED ) {
status = UpdateNormalBindings();
if( status != NO_ERROR ) {
DBGPRINTF((
DBG_CONTEXT,
"MDChangeNotify: UpdateNormalBindings() failed,error %lu\n",
status
));
}
SetWin32Error( status );
}
break;
case MD_SECURE_PORT:
if( QueryServerState() != MD_SERVER_STATE_STOPPED ) {
status = UpdateSecureBindings();
if( status != NO_ERROR ) {
DBGPRINTF((
DBG_CONTEXT,
"MDChangeNotify: UpdateSecureBindings() failed,error %lu\n",
status
));
}
SetWin32Error( status );
}
break;
case MD_SERVER_STATE:
status = PerformStateChange();
if( status != NO_ERROR ) {
IF_DEBUG( INSTANCE ) {
DBGPRINTF((
DBG_CONTEXT,
"MDChangeNotify: ProcessStateChange() failed, error %lu\n",
status
));
}
}
break;
case MD_VR_PATH:
case MD_VR_USERNAME:
case MD_VR_PASSWORD:
fShouldMirror = TRUE;
if ( !fVRUpdated )
{
//
// Note individual root errors log an event
//
if ( !TsReadVirtualRoots() )
{
DBGPRINTF(( DBG_CONTEXT,
"Error %d (0x%lx) reading virtual roots\n",
GetLastError(), GetLastError() ));
}
fVRUpdated = TRUE;
}
break;
//
// Ignore status updates
//
case MD_WIN32_ERROR:
break;
case MD_ACCESS_PERM:
fShouldMirror = TRUE;
default:
fReadCommon = TRUE;
break;
}
}
if ( fReadCommon )
{
m_Logging.NotifyChange( 0 );
RegReadCommonParams( FALSE );
}
//
// reflect the changes to the registry
//
if ( fShouldMirror && (QueryInstanceId() == 1) )
{
MDMirrorVirtualRoots( );
}
UnlockThis();
} // IIS_SERVER_INSTANCE::MDChangeNotify
VOID
IIS_SERVER_INSTANCE::MDMirrorVirtualRoots(
VOID
)
{
DWORD err;
HKEY hkey = NULL;
//
// Delete VR key
//
err = RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
m_Service->QueryRegParamKey(),
0,
KEY_ALL_ACCESS,
&hkey );
if ( err != NO_ERROR ) {
DBGPRINTF(( DBG_CONTEXT, "RegOpenKeyEx for returned error %d\n",err ));
return;
}
//
// First delete the key to remove any old values
//
err = RegDeleteKey( hkey, VIRTUAL_ROOTS_KEY_A );
RegCloseKey(hkey);
if ( err != NO_ERROR )
{
DBGPRINTF(( DBG_CONTEXT,
"[MDMirrorVRoots] Unable to remove old values\n"));
return;
}
//
// Now recreate the keys
//
MoveMDVroots2Registry( );
return;
} // IIS_SERVER_INSTANCE::MDMirrorVirtualRoots
INETLOG_TYPE
FindInetLogType(
IN DWORD dwValue
)
{
INETLOG_TYPE ilType;
switch (dwValue) {
case INET_LOG_DISABLED: ilType = InetNoLog; break;
case INET_LOG_TO_FILE: ilType = InetLogToFile; break;
case INET_LOG_TO_SQL: ilType = InetLogToSql; break;
default: ilType = InetLogInvalidType; break;
} // switch()
return (ilType);
} // FindInetLogType()
INETLOG_FORMAT
FindInetLogFormat(
IN DWORD dwValue
)
{
INETLOG_FORMAT ilFormat;
switch (dwValue) {
case INET_LOG_FORMAT_INTERNET_STD: ilFormat = InternetStdLogFormat; break;
case INET_LOG_FORMAT_BINARY: ilFormat = InetsvcsBinaryLogFormat; break;
case INET_LOG_FORMAT_NCSA: ilFormat = NCSALogFormat; break;
case INET_LOG_FORMAT_CUSTOM: ilFormat = CustomLogFormat; break;
default: ilFormat = InternetStdLogFormat; break;
} // switch()
return (ilFormat);
} // FindInetLogFormat()
INETLOG_PERIOD
FindInetLogPeriod(
IN DWORD dwValue
)
{
INETLOG_PERIOD ilPeriod;
switch (dwValue) {
case INET_LOG_PERIOD_NONE: ilPeriod = InetLogNoPeriod; break;
case INET_LOG_PERIOD_DAILY: ilPeriod = InetLogDaily; break;
case INET_LOG_PERIOD_WEEKLY: ilPeriod = InetLogWeekly; break;
case INET_LOG_PERIOD_MONTHLY:ilPeriod = InetLogMonthly; break;
case INET_LOG_PERIOD_YEARLY: ilPeriod = InetLogYearly; break;
default: ilPeriod = InetLogInvalidPeriod; break;
} // switch()
return (ilPeriod);
} // FindInetLogPeriod()
DWORD
GetRPCLogConfiguration(IN LOGGING *pLogging,
OUT LPINET_LOG_CONFIGURATION * ppLogConfig)
/*++
This function allocates space (using MIDL_ functions) and stores
log configuration for the given log handle in it.
Arguments:
hInetLog handle for InetLog object.
ppLogConfig pointer to INET_LOG_CONFIGURATION object which on return
contains valid log config informtion, on success.
Returns:
Win32 error code.
--*/
{
DWORD dwError = NO_ERROR;
LPINET_LOG_CONFIGURATION pRpcConfig;
WCHAR cBuffer[MAX_PATH];
DBG_ASSERT( ppLogConfig != NULL);
pRpcConfig = ((LPINET_LOG_CONFIGURATION )
MIDL_user_allocate( sizeof(INET_LOG_CONFIGURATION)));
if ( pRpcConfig != NULL) {
INETLOG_CONFIGURATIONA ilogConfig;
DWORD cbConfig = sizeof(ilogConfig);
BOOL fReturn=TRUE;
ZeroMemory( &ilogConfig, sizeof(ilogConfig ));
pLogging->GetConfig( &ilogConfig );
//
// we got valid config. copy it into pRpcConfig.
// since the enumerated values in inetlog.w are same in inetasrv.h
// we do no mapping, we directly copy values.
ZeroMemory( pRpcConfig, sizeof( INET_LOG_CONFIGURATION));
pRpcConfig->inetLogType = ilogConfig.inetLogType;
switch ( ilogConfig.inetLogType) {
case InetNoLog:
// do nothing
break;
case InetLogToFile:
pRpcConfig->ilPeriod = ilogConfig.u.logFile.ilPeriod;
pRpcConfig->cbSizeForTruncation =
ilogConfig.u.logFile.cbSizeForTruncation;
::MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,
ilogConfig.u.logFile.rgchLogFileDirectory, -1,
(WCHAR *)cBuffer, MAX_PATH );
CopyUnicodeStringToBuffer(
pRpcConfig->rgchLogFileDirectory,
MAX_PATH,
cBuffer);
*((DWORD *)&(pRpcConfig->rgchDataSource[MAX_PATH-sizeof(DWORD)]))=ilogConfig.u.logFile.ilFormat;
*((DWORD *)&(pRpcConfig->rgchDataSource[MAX_PATH-2*sizeof(DWORD)]))=ilogConfig.u.logFile.dwFieldMask;
break;
case InetLogToSql:
::MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,
ilogConfig.u.logSql.rgchDataSource, -1,
(WCHAR *)cBuffer, MAX_PATH );
CopyUnicodeStringToBuffer(
pRpcConfig->rgchDataSource,
MAX_PATH,
cBuffer);
::MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,
ilogConfig.u.logSql.rgchTableName, -1,
(WCHAR *)cBuffer, MAX_PATH );
CopyUnicodeStringToBuffer(
pRpcConfig->rgchTableName,
MAX_TABLE_NAME_LEN,
cBuffer);
::MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,
ilogConfig.u.logSql.rgchUserName, -1,
(WCHAR *)cBuffer, MAX_PATH );
CopyUnicodeStringToBuffer(
pRpcConfig->rgchUserName,
UNLEN,
cBuffer);
::MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,
ilogConfig.u.logSql.rgchPassword, -1,
(WCHAR *)cBuffer, MAX_PATH );
CopyUnicodeStringToBuffer(
pRpcConfig->rgchPassword,
PWLEN,
cBuffer);
break;
default:
break;
} // switch()
} else {
dwError = ERROR_NOT_ENOUGH_MEMORY;
}
*ppLogConfig = pRpcConfig;
return (dwError);
} // GetRPCLogConfiguration()
DWORD
SetInetLogConfiguration(IN LOGGING *pLogging,
IN EVENT_LOG * pEventLog,
IN const INET_LOG_CONFIGURATION * pRpcLogConfig)
/*++
This function modifies the logconfiguration associated with a given InetLog
handle. It also updates the registry containing log configuration for service
with which the inetlog handle is associated.
Arguments:
hInetLog Handle to INETLOG object whose configuration needs to be
changed.
pRpcLogConfig new RPC log configuration
Returns:
Win32 Error code. NO_ERROR returned on success.
--*/
{
DWORD dwError = NO_ERROR;
INETLOG_CONFIGURATIONA ilConfig;
WCHAR cBuffer[MAX_PATH];
// initialize
ZeroMemory( &ilConfig, sizeof(INETLOG_CONFIGURATIONA));
// Copy the RPC inet log configuration into local INETLOG_CONFIGURATIONW
// since the enumerated values in inetlog.w are same in inetasrv.h
// we do no mapping, we directly copy values.
ilConfig.inetLogType = FindInetLogType(pRpcLogConfig->inetLogType);
if ( ilConfig.inetLogType == InetLogInvalidType) {
return (ERROR_INVALID_PARAMETER);
}
switch (ilConfig.inetLogType) {
case INET_LOG_DISABLED:
break; // do nothing
case INET_LOG_TO_FILE:
CopyUnicodeStringToBuffer(cBuffer,
MAX_PATH,
pRpcLogConfig->rgchLogFileDirectory);
(VOID) ConvertUnicodeToAnsi(
cBuffer,
ilConfig.u.logFile.rgchLogFileDirectory,
MAX_PATH
);
ilConfig.u.logFile.ilPeriod =
FindInetLogPeriod(pRpcLogConfig->ilPeriod);
if ( ilConfig.u.logFile.ilPeriod == InetLogInvalidPeriod) {
return (ERROR_INVALID_PARAMETER);
}
ilConfig.u.logFile.cbSizeForTruncation =
pRpcLogConfig->cbSizeForTruncation;
ilConfig.u.logFile.ilFormat = FindInetLogFormat(*((DWORD *)&(pRpcLogConfig->rgchDataSource[MAX_PATH-sizeof(DWORD)])));
ilConfig.u.logFile.dwFieldMask = *((DWORD *)&(pRpcLogConfig->rgchDataSource[MAX_PATH-2*sizeof(DWORD)]));
break;
case INET_LOG_TO_SQL:
CopyUnicodeStringToBuffer(cBuffer,
MAX_PATH,
pRpcLogConfig->rgchDataSource);
(VOID) ConvertUnicodeToAnsi(
cBuffer,
ilConfig.u.logSql.rgchDataSource,
MAX_PATH);
CopyUnicodeStringToBuffer(cBuffer,
MAX_TABLE_NAME_LEN,
pRpcLogConfig->rgchTableName);
(VOID) ConvertUnicodeToAnsi(
cBuffer,
ilConfig.u.logSql.rgchTableName,
MAX_PATH);
CopyUnicodeStringToBuffer(cBuffer,
UNLEN,
pRpcLogConfig->rgchUserName);
(VOID) ConvertUnicodeToAnsi(
cBuffer,
ilConfig.u.logSql.rgchUserName,
MAX_PATH);
CopyUnicodeStringToBuffer(cBuffer,
CNLEN,
pRpcLogConfig->rgchPassword);
(VOID) ConvertUnicodeToAnsi(
cBuffer,
ilConfig.u.logSql.rgchPassword,
MAX_PATH);
break;
default:
return (ERROR_INVALID_PARAMETER);
} // switch()
//
// Now the ilConfig contains the local data related to configuration.
// call modify log config to modify dynamically the log handle.
//
WCHAR pszErrorMessage[200] = L"";
DWORD cchErrorMessage = sizeof(pszErrorMessage) /sizeof(WCHAR);
pLogging->SetConfig( &ilConfig );
return (dwError);
} // SetInetLogConfiguration()
BOOL
GenerateIpList(
BOOL fIsGrant,
ADDRESS_CHECK *pCheck,
LPINET_INFO_IP_SEC_LIST *ppInfo
)
/*++
Routine Description:
generate an IP address list from an access check object
Arguments:
fIsGrant - TRUE to access grant list, FALSE to access deny list
pCheck - ptr to address check object to query from
ppInfo - updated with ptr to IP list if success
Return:
TRUE if success, otherwise FALSE
--*/
{
UINT iM = pCheck->GetNbAddr( fIsGrant );
LPINET_INFO_IP_SEC_LIST pInfo;
LPINET_INFO_IP_SEC_ENTRY pI;
UINT x;
if ( iM == 0 )
{
*ppInfo = NULL;
return TRUE;
}
if ( pInfo = (LPINET_INFO_IP_SEC_LIST)MIDL_user_allocate( sizeof(INET_INFO_IP_SEC_LIST) + iM * sizeof(INET_INFO_IP_SEC_ENTRY) ) )
{
pInfo->cEntries = 0;
for ( x = 0, pI = pInfo->aIPSecEntry ;
x < iM ;
++x )
{
LPBYTE pM;
LPBYTE pA;
DWORD dwF;
if ( pCheck->GetAddr( fIsGrant, x, &dwF, &pM, &pA ) && dwF == AF_INET )
{
pI->dwMask = *(LPDWORD)pM;
pI->dwNetwork = *(LPDWORD)pA;
++pI;
++pInfo->cEntries;
}
}
*ppInfo = pInfo;
return TRUE;
}
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
return FALSE;
}
BOOL
FillAddrCheckFromIpList(
BOOL fIsGrant,
LPINET_INFO_IP_SEC_LIST pInfo,
ADDRESS_CHECK *pCheck
)
/*++
Routine Description:
Fill an access check object from an IP address list from
Arguments:
fIsGrant - TRUE to access grant list, FALSE to access deny list
pInfo - ptr to IP address list
pCheck - ptr to address check object to update
Return:
TRUE if success, otherwise FALSE
--*/
{
UINT x;
if ( pInfo )
{
for ( x = 0 ; x < pInfo->cEntries ; ++x )
{
if ( ! pCheck->AddAddr( fIsGrant,
AF_INET,
(LPBYTE)&pInfo->aIPSecEntry[x].dwMask,
(LPBYTE)&pInfo->aIPSecEntry[x].dwNetwork ) )
{
return FALSE;
}
}
}
return TRUE;
}
BOOL
GetVrootCount(
PVOID pvContext,
MB * pmb,
VIRTUAL_ROOT * pvr
)
/*++
Routine Description:
Virtual directory enumerater callback that calculates the total required
buffer size
Arguments:
pvContext is a dword * that receives the count of virtual directories
Return:
TRUE if success, otherwise FALSE
--*/
{
*((DWORD *) pvContext) += 1;
return TRUE;
}
BOOL
GetVroots(
PVOID pvContext,
MB * pmb,
VIRTUAL_ROOT * pvr
)
/*++
Routine Description:
Virtual directory enumerater callback that allocates and builds the
virtual directory structure list
Arguments:
pvContext is a pointer to the midl allocated memory
Return:
TRUE if success, otherwise FALSE
--*/
{
LPINET_INFO_VIRTUAL_ROOT_LIST pvrl = (LPINET_INFO_VIRTUAL_ROOT_LIST) pvContext;
DWORD i = pvrl->cEntries;
LPINET_INFO_VIRTUAL_ROOT_ENTRY pvre = &pvrl->aVirtRootEntry[i];
//
// Password doesn't go on the wire
//
DBG_ASSERT( pvr->pszMetaPath[0] == '/' &&
pvr->pszMetaPath[1] == '/' );
if ( !ConvertStringToRpc( &pvre->pszRoot,
pvr->pszAlias ) ||
!ConvertStringToRpc( &pvre->pszDirectory,
pvr->pszPath ) ||
!ConvertStringToRpc( &pvre->pszAddress,
"" ) ||
!ConvertStringToRpc( &pvre->pszAccountName,
pvr->pszUserName ))
{
FreeRpcString( pvre->pszRoot ); pvre->pszRoot = NULL;
FreeRpcString( pvre->pszDirectory ); pvre->pszDirectory = NULL;
FreeRpcString( pvre->pszAddress ); pvre->pszAddress = NULL;
FreeRpcString( pvre->pszAccountName ); pvre->pszAccountName = NULL;
return FALSE;
}
pvre->dwMask = pvr->dwAccessPerm;
pmb->GetDword( pvr->pszAlias,
MD_WIN32_ERROR,
IIS_MD_UT_SERVER,
&pvre->dwError );
pvrl->cEntries++;
return TRUE;
}