mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1836 lines
48 KiB
1836 lines
48 KiB
/*++
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
|