1837 lines
48 KiB
C++
1837 lines
48 KiB
C++
/*++
|
||
|
||
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 <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;
|
||
LPINETA_CONFIG_INFO pInfoConfig = (LPINETA_CONFIG_INFO)pConfig;
|
||
ADDRESS_CHECK acCheck;
|
||
BOOL fMustRel;
|
||
MB mb( (IMDCOM*) m_Service->QueryMDObject() );
|
||
DWORD cRoots = 0;
|
||
STR strAnon;
|
||
STR strAnonPwd;
|
||
STR strServerComment;
|
||
DWORD err = NO_ERROR;
|
||
|
||
|
||
IF_DEBUG(INSTANCE) {
|
||
DBGPRINTF((DBG_CONTEXT,"GetCommonConfig called with L%d for instance %d\n",
|
||
dwLevel, QueryInstanceId() ));
|
||
}
|
||
|
||
LockThisForRead();
|
||
|
||
//
|
||
// 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->dwConnectionTimeout = QueryConnectionTimeout();
|
||
pInfoConfig->dwMaxConnections = QueryMaxConnections();
|
||
|
||
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()*/ )
|
||
);
|
||
|
||
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 ( 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();
|
||
|
||
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 ( !mb.Open( QueryMDPath(),
|
||
METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE ))
|
||
{
|
||
fReturn = FALSE;
|
||
goto Exit;
|
||
}
|
||
|
||
if ( TsEnumVirtualRoots( GetVrootCount, &cRoots, &mb ) )
|
||
{
|
||
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, &mb );
|
||
}
|
||
|
||
// only used for UNC virtual directories (to store the passwords)
|
||
err = TsSetSecretW( m_lpwszRootPasswordSecretName,
|
||
L"",
|
||
sizeof(WCHAR) );
|
||
if ( err == ERROR_ACCESS_DENIED && g_fW3OnlyNoAuth )
|
||
{
|
||
err = 0;
|
||
}
|
||
}
|
||
|
||
mb.Close();
|
||
|
||
if ( !fReturn )
|
||
{
|
||
goto Exit;
|
||
}
|
||
|
||
if ( !mb.Open( QueryMDPath() ))
|
||
{
|
||
fReturn = FALSE;
|
||
goto Exit;
|
||
}
|
||
|
||
mb.GetDword( "",
|
||
MD_AUTHORIZATION,
|
||
IIS_MD_UT_FILE,
|
||
MD_AUTH_ANONYMOUS,
|
||
&pInfoConfig->dwAuthentication );
|
||
|
||
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 ))
|
||
{
|
||
BUFFER buff;
|
||
|
||
if ( buff.Resize( (strAnonPwd.QueryCCH() + 1) * sizeof(WCHAR )))
|
||
{
|
||
if ( MultiByteToWideChar( CP_ACP,
|
||
MB_PRECOMPOSED,
|
||
strAnonPwd.QueryStr(),
|
||
strAnonPwd.QueryCCH() + 1,
|
||
(LPWSTR) buff.QueryPtr(),
|
||
strAnonPwd.QueryCCH() + 1 ))
|
||
{
|
||
err = TsSetSecretW( m_lpwszAnonPasswordSecretName,
|
||
(LPWSTR) buff.QueryPtr(),
|
||
wcslen( (LPWSTR) buff.QueryPtr()) * sizeof(WCHAR) );
|
||
if ( err == ERROR_ACCESS_DENIED && g_fW3OnlyNoAuth )
|
||
{
|
||
err = 0;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// store an empty password if there's no anonymous user at this level
|
||
//
|
||
|
||
err = TsSetSecretW( m_lpwszAnonPasswordSecretName,
|
||
L"",
|
||
sizeof(WCHAR) );
|
||
if ( err == ERROR_ACCESS_DENIED && g_fW3OnlyNoAuth )
|
||
{
|
||
err = 0;
|
||
}
|
||
}
|
||
|
||
if ( err ) {
|
||
SetLastError( err );
|
||
fReturn = FALSE;
|
||
}
|
||
|
||
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->lpszAnonUserName );
|
||
|
||
pInfoConfig->lpszAdminName = NULL;
|
||
pInfoConfig->lpszAdminEmail = NULL;
|
||
pInfoConfig->lpszServerComment = NULL;
|
||
pInfoConfig->lpszAnonUserName = NULL;
|
||
|
||
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 fReadAll,
|
||
BOOL fReadVirtualDirs
|
||
)
|
||
/*++
|
||
|
||
Description
|
||
|
||
Reads the service common items from the registry
|
||
|
||
Arguments:
|
||
|
||
fReadAll - If TRUE read all parameters.
|
||
If FALSE read only those parameters that are necessary for initialization.
|
||
|
||
fReadVirtualDirs - Initalize Virtual DIrectories.
|
||
|
||
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. fReadAll = %d\n",
|
||
fReadAll));
|
||
}
|
||
|
||
//
|
||
// Open the metabase and read parameters for IIS_SERVER_INSTANCE object
|
||
// itself.
|
||
//
|
||
|
||
|
||
if ( !mb.Open( QueryMDPath(),
|
||
TsIsNtServer() ? METADATA_PERMISSION_READ :
|
||
METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE ))
|
||
{
|
||
DBGPRINTF(( DBG_CONTEXT,
|
||
"[ReadParamsFromRegistry] mb.Open returned error %d for path %s\n",
|
||
GetLastError(),
|
||
QueryMDPath() ));
|
||
|
||
}
|
||
|
||
LockThisForWrite();
|
||
|
||
//
|
||
// Values needed for initialization
|
||
//
|
||
|
||
mb.GetDword( "",
|
||
MD_SERVER_AUTOSTART,
|
||
IIS_MD_UT_SERVER,
|
||
TRUE,
|
||
(DWORD *) &m_fAutoStart
|
||
);
|
||
|
||
mb.GetDword( "",
|
||
MD_CLUSTER_ENABLED,
|
||
IIS_MD_UT_SERVER,
|
||
FALSE,
|
||
(DWORD *) &m_fClusterEnabled
|
||
);
|
||
|
||
/*
|
||
That's a fix for a bug 367791 when restarting IIS with
|
||
vhost sites marked for auto restart isn't bringing them online
|
||
becuase of current disgn limitation how cluster service is checking for helth of
|
||
vhost site it is not able to distinguish that only one of few vhost sites are running
|
||
and is not starting the rest. The fix is to allow to admin to set autorestart on site
|
||
and then during startup of IIS to start that site not with cluster command but automaticcally
|
||
Because of that the following lines are removed.
|
||
|
||
if ( m_fClusterEnabled )
|
||
{
|
||
m_fAutoStart = FALSE;
|
||
}
|
||
*/
|
||
|
||
if ( !mb.GetStr( "",
|
||
MD_SERVER_COMMENT,
|
||
IIS_MD_UT_SERVER,
|
||
&m_strSiteName ) ||
|
||
m_strSiteName.IsEmpty())
|
||
{
|
||
m_strSiteName.Copy(QueryMDPath());
|
||
}
|
||
|
||
//
|
||
// Other values needed to run the instance
|
||
//
|
||
|
||
if ( fReadAll)
|
||
{
|
||
|
||
mb.GetDword( "",
|
||
MD_CONNECTION_TIMEOUT,
|
||
IIS_MD_UT_SERVER,
|
||
INETA_DEF_CONNECTION_TIMEOUT,
|
||
&m_dwConnectionTimeout
|
||
);
|
||
|
||
mb.GetDword( "",
|
||
MD_MAX_CONNECTIONS,
|
||
IIS_MD_UT_SERVER,
|
||
INETA_DEF_MAX_CONNECTIONS,
|
||
&m_dwMaxConnections
|
||
);
|
||
|
||
mb.GetDword( "",
|
||
MD_MAX_ENDPOINT_CONNECTIONS,
|
||
IIS_MD_UT_SERVER,
|
||
(TsIsNtServer()
|
||
? TsSocketConfig[MD_SERVER_SIZE_LARGE].nAcceptExOutstanding
|
||
: INETA_DEF_MAX_ENDPOINT_CONNECTIONS_PWS
|
||
),
|
||
&m_dwMaxEndpointConnections
|
||
);
|
||
|
||
mb.GetDword( "",
|
||
MD_LEVELS_TO_SCAN,
|
||
IIS_MD_UT_SERVER,
|
||
INETA_DEF_LEVELS_TO_SCAN,
|
||
&m_dwLevelsToScan
|
||
);
|
||
|
||
//
|
||
// 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;
|
||
|
||
mb.SetDword( "",
|
||
MD_MAX_CONNECTIONS,
|
||
IIS_MD_UT_SERVER,
|
||
m_dwMaxConnections
|
||
);
|
||
}
|
||
|
||
if ( m_dwMaxEndpointConnections > INETA_MAX_MAX_ENDPOINT_CONNECTIONS_PWS ) {
|
||
m_dwMaxEndpointConnections = INETA_DEF_MAX_ENDPOINT_CONNECTIONS_PWS;
|
||
|
||
mb.SetDword( "",
|
||
MD_MAX_ENDPOINT_CONNECTIONS,
|
||
IIS_MD_UT_SERVER,
|
||
m_dwMaxEndpointConnections
|
||
);
|
||
}
|
||
}
|
||
|
||
//
|
||
// Log anonymous and Log non-anonymous or for FTP only
|
||
//
|
||
|
||
mb.GetDword( "",
|
||
MD_LOG_TYPE,
|
||
IIS_MD_UT_SERVER,
|
||
TRUE,
|
||
(DWORD *) &m_fLoggingEnabled
|
||
);
|
||
|
||
mb.GetDword( "",
|
||
MD_LOG_ANONYMOUS,
|
||
IIS_MD_UT_SERVER,
|
||
INETA_DEF_LOG_ANONYMOUS,
|
||
(DWORD *) &m_fLogAnonymous
|
||
);
|
||
|
||
mb.GetDword( "",
|
||
MD_LOG_NONANONYMOUS,
|
||
IIS_MD_UT_SERVER,
|
||
INETA_DEF_LOG_NONANONYMOUS,
|
||
(DWORD *) &m_fLogNonAnonymous
|
||
);
|
||
|
||
#if 0
|
||
//
|
||
// I don't believe that ServerCommand can be set to
|
||
// started without our noticing, so I'm removing this
|
||
// code.
|
||
//
|
||
if (!m_fAutoStart) {
|
||
|
||
//
|
||
// Server Command to start this instance may
|
||
// have been written while service was stopped.
|
||
// Need to pick it up
|
||
//
|
||
|
||
DWORD dwServerCommand;
|
||
|
||
mb.GetDword( "",
|
||
MD_SERVER_COMMAND,
|
||
IIS_MD_UT_SERVER,
|
||
TRUE,
|
||
(DWORD *) &dwServerCommand
|
||
);
|
||
|
||
if (dwServerCommand == MD_SERVER_COMMAND_START) {
|
||
m_fAutoStart = TRUE;
|
||
}
|
||
|
||
}
|
||
#endif
|
||
|
||
//
|
||
// Other fields
|
||
//
|
||
|
||
//
|
||
// socket values
|
||
//
|
||
|
||
mb.GetDword( "",
|
||
MD_SERVER_SIZE,
|
||
IIS_MD_UT_SERVER,
|
||
INETA_DEF_SERVER_SIZE,
|
||
&m_dwServerSize
|
||
);
|
||
|
||
if ( m_dwServerSize > MD_SERVER_SIZE_LARGE ) {
|
||
m_dwServerSize = INETA_DEF_SERVER_SIZE;
|
||
}
|
||
|
||
mb.GetDword( "",
|
||
MD_SERVER_LISTEN_BACKLOG,
|
||
IIS_MD_UT_SERVER,
|
||
TsSocketConfig[m_dwServerSize].nAcceptExOutstanding,
|
||
&m_nAcceptExOutstanding
|
||
);
|
||
|
||
mb.GetDword( "",
|
||
MD_SERVER_LISTEN_TIMEOUT,
|
||
IIS_MD_UT_SERVER,
|
||
INETA_DEF_ACCEPTEX_TIMEOUT,
|
||
&m_AcceptExTimeout
|
||
);
|
||
//
|
||
// Setup a bandwidth throttle descriptor if necessary (for NT server)
|
||
//
|
||
|
||
SetBandwidthThrottle( &mb );
|
||
|
||
//
|
||
// Set the maximum number of blocked requests for throttler
|
||
//
|
||
|
||
SetBandwidthThrottleMaxBlocked( &mb );
|
||
|
||
// 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 LPINETA_CONFIG_INFO 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 ( (err == NO_ERROR) &&
|
||
IsFieldSet( fcConfig, FC_INET_INFO_ANON_USER_NAME ) &&
|
||
(pInfoConfig->lpszAnonUserName != NULL) )
|
||
{
|
||
STR strAnonPwd;
|
||
|
||
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() );
|
||
}
|
||
|
||
//
|
||
// Set the anonymous password also. The client sets it as an LSA
|
||
// secret
|
||
//
|
||
|
||
if ( TsGetSecretW( m_lpwszAnonPasswordSecretName,
|
||
&strAnonPwd ) &&
|
||
mb.SetString( "",
|
||
MD_ANONYMOUS_PWD,
|
||
IIS_MD_UT_FILE,
|
||
strAnonPwd.QueryStr() ))
|
||
{
|
||
DBGPRINTF(( DBG_CONTEXT,
|
||
"Failed to get/set anonymous secret, err %d\n",
|
||
GetLastError() ));
|
||
}
|
||
|
||
}
|
||
|
||
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));
|
||
}
|
||
}
|
||
|
||
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 = NO_ERROR;
|
||
BOOL fVRUpdated = FALSE;
|
||
BOOL fReadCommon = FALSE;
|
||
BOOL fShouldMirror = FALSE;
|
||
HRESULT hr;
|
||
BOOL fShouldCoUninitialize = FALSE;
|
||
|
||
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
|
||
if ( SUCCEEDED(hr) ) {
|
||
fShouldCoUninitialize = TRUE;
|
||
}
|
||
else if (hr != E_INVALIDARG &&
|
||
hr != RPC_E_CHANGED_MODE) {
|
||
|
||
//
|
||
// E_INVALIDARG and RPC_E_CHANGED_MODE could mean com was already
|
||
// initialized with different parameters, so ignore it but don't
|
||
// Uninit. Assert on other errors.
|
||
//
|
||
|
||
DBGPRINTF((DBG_CONTEXT,"CoInitializeEx failed with %x\n",hr));
|
||
DBG_ASSERT(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_BINDINGS:
|
||
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_DISABLE_SOCKET_POOLING:
|
||
if( QueryServerState() != MD_SERVER_STATE_STOPPED )
|
||
{
|
||
if (HasNormalBindings())
|
||
{
|
||
status = RemoveNormalBindings();
|
||
|
||
if (NO_ERROR == status)
|
||
{
|
||
status = UpdateNormalBindings();
|
||
|
||
if( status != NO_ERROR ) {
|
||
DBGPRINTF((
|
||
DBG_CONTEXT,
|
||
"MDChangeNotify: UpdateNormalBindings() failed,error %lu\n",
|
||
status
|
||
));
|
||
}
|
||
}
|
||
else
|
||
{
|
||
DBGPRINTF((
|
||
DBG_CONTEXT,
|
||
"MDChangeNotify: RemoveNormalBindings() failed,error %lu\n",
|
||
status
|
||
));
|
||
}
|
||
}
|
||
|
||
if ( (status == NO_ERROR) && HasSecureBindings())
|
||
{
|
||
status = RemoveSecureBindings();
|
||
|
||
if (NO_ERROR == status)
|
||
{
|
||
status = UpdateSecureBindings();
|
||
|
||
if( status != NO_ERROR ) {
|
||
DBGPRINTF((
|
||
DBG_CONTEXT,
|
||
"MDChangeNotify: UpdateSecureBindings() failed,error %lu\n",
|
||
status
|
||
));
|
||
}
|
||
}
|
||
else
|
||
{
|
||
DBGPRINTF((
|
||
DBG_CONTEXT,
|
||
"MDChangeNotify: RemoveSecureBindings() failed,error %lu\n",
|
||
status
|
||
));
|
||
}
|
||
}
|
||
|
||
SetWin32Error( status );
|
||
}
|
||
break;
|
||
|
||
case MD_CLUSTER_ENABLED:
|
||
status = PerformClusterModeChange();
|
||
if( status != NO_ERROR ) {
|
||
IF_DEBUG( INSTANCE ) {
|
||
DBGPRINTF((
|
||
DBG_CONTEXT,
|
||
"MDChangeNotify: PerformClusterModeChange() failed, error %lu\n",
|
||
status
|
||
));
|
||
}
|
||
}
|
||
break;
|
||
|
||
case MD_SERVER_COMMAND:
|
||
|
||
//
|
||
// If cluster mode is enabled command must be specified
|
||
// using MD_CLUSTER_SERVER_COMMAND, so that ISM cannot set the server state :
|
||
// State management is to be done by cluster code exclusively.
|
||
//
|
||
|
||
if ( IsClusterEnabled() )
|
||
{
|
||
break;
|
||
}
|
||
|
||
case MD_CLUSTER_SERVER_COMMAND:
|
||
status = PerformStateChange();
|
||
if( status != NO_ERROR ) {
|
||
IF_DEBUG( INSTANCE ) {
|
||
DBGPRINTF((
|
||
DBG_CONTEXT,
|
||
"MDChangeNotify: ProcessStateChange() failed, error %lu\n",
|
||
status
|
||
));
|
||
}
|
||
}
|
||
|
||
//
|
||
// if command started server then need to reload virtual roots
|
||
// as failing-over may have enabled new file system resources
|
||
//
|
||
|
||
if ( QueryServerState() != MD_SERVER_STATE_STARTED )
|
||
{
|
||
break;
|
||
}
|
||
|
||
// fall-through
|
||
|
||
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(pcoChangeList) )
|
||
{
|
||
DBGPRINTF(( DBG_CONTEXT,
|
||
"Error %d (0x%lx) reading virtual root info for %s\n",
|
||
GetLastError(), GetLastError(), pcoChangeList->pszMDPath ));
|
||
}
|
||
|
||
fVRUpdated = TRUE;
|
||
}
|
||
break;
|
||
|
||
case MD_MAX_BANDWIDTH:
|
||
{
|
||
MB mb( (IMDCOM*) m_Service->QueryMDObject() );
|
||
|
||
if ( mb.Open( QueryMDPath() ) )
|
||
{
|
||
if ( !SetBandwidthThrottle( &mb ) )
|
||
{
|
||
DWORD dwError = GetLastError();
|
||
|
||
DBGPRINTF(( DBG_CONTEXT,
|
||
"MDChangeNotify: SetBandwidthThrottle failed, error %lu\n",
|
||
dwError ));
|
||
|
||
SetWin32Error( dwError );
|
||
}
|
||
DBG_REQUIRE( mb.Close() );
|
||
}
|
||
break;
|
||
}
|
||
|
||
case MD_MAX_BANDWIDTH_BLOCKED:
|
||
{
|
||
MB mb( (IMDCOM*) m_Service->QueryMDObject() );
|
||
|
||
if ( mb.Open( QueryMDPath() ) )
|
||
{
|
||
if ( !SetBandwidthThrottleMaxBlocked( &mb ) )
|
||
{
|
||
DWORD dwError = GetLastError();
|
||
|
||
DBGPRINTF(( DBG_CONTEXT,
|
||
"MDChangeNotify: SetBandwidthThrottle failed, error %lu\n",
|
||
dwError ));
|
||
|
||
SetWin32Error( dwError );
|
||
}
|
||
DBG_REQUIRE( mb.Close() );
|
||
}
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Ignore state & status updates
|
||
//
|
||
|
||
case MD_SERVER_STATE:
|
||
case MD_WIN32_ERROR:
|
||
break;
|
||
|
||
case MD_ACCESS_PERM:
|
||
fShouldMirror = TRUE;
|
||
break;
|
||
|
||
case MD_LOG_TYPE:
|
||
{
|
||
DWORD dwLogType;
|
||
MB mb( (IMDCOM*) m_Service->QueryMDObject() );
|
||
|
||
if ( mb.Open( QueryMDPath() ) &&
|
||
mb.GetDword("", MD_LOG_TYPE, IIS_MD_UT_SERVER, &dwLogType)
|
||
)
|
||
{
|
||
m_fLoggingEnabled = (1 == dwLogType);
|
||
}
|
||
|
||
fReadCommon = TRUE;
|
||
break;
|
||
}
|
||
|
||
default:
|
||
fReadCommon = TRUE;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if ( fReadCommon )
|
||
{
|
||
m_Logging.NotifyChange( 0 );
|
||
RegReadCommonParams( TRUE, FALSE );
|
||
}
|
||
|
||
if ((MD_CHANGE_TYPE_DELETE_OBJECT == pcoChangeList->dwMDChangeType) &&
|
||
(! _strnicmp( (LPCSTR) pcoChangeList->pszMDPath+QueryMDPathLen()+1,
|
||
IIS_MD_INSTANCE_ROOT,
|
||
sizeof(IIS_MD_INSTANCE_ROOT)-1))
|
||
)
|
||
{
|
||
if ( !TsReadVirtualRoots(pcoChangeList) )
|
||
{
|
||
DBGPRINTF(( DBG_CONTEXT,
|
||
"Error %d (0x%lx) removing virtual root %s\n",
|
||
GetLastError(), GetLastError(), pcoChangeList->pszMDPath ));
|
||
}
|
||
}
|
||
|
||
//
|
||
// reflect the changes to the registry
|
||
//
|
||
|
||
if ( fShouldMirror && IsDownLevelInstance() )
|
||
{
|
||
MDMirrorVirtualRoots( );
|
||
}
|
||
|
||
UnlockThis();
|
||
|
||
if ( fShouldCoUninitialize ) {
|
||
CoUninitialize( );
|
||
}
|
||
|
||
return;
|
||
|
||
} // 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
|
||
|
||
|
||
|
||
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 INET_LOG_TO_FILE:
|
||
|
||
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 INET_LOG_TO_SQL:
|
||
|
||
::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;
|
||
|
||
|
||
case INET_LOG_DISABLED:
|
||
default:
|
||
// do nothing
|
||
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
|
||
|
||
ilConfig.inetLogType = pRpcLogConfig->inetLogType;
|
||
|
||
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 = pRpcLogConfig->ilPeriod;
|
||
|
||
if ( ilConfig.u.logFile.ilPeriod > INET_LOG_PERIOD_MONTHLY ) {
|
||
return (ERROR_INVALID_PARAMETER);
|
||
}
|
||
|
||
ilConfig.u.logFile.cbSizeForTruncation =
|
||
pRpcLogConfig->cbSizeForTruncation;
|
||
|
||
ilConfig.u.logFile.ilFormat =
|
||
*((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.
|
||
//
|
||
|
||
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->pszAlias[0] == '/' );
|
||
|
||
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;
|
||
}
|
||
|
||
|
||
|