/*++ 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 #include #include #include #include #include #include "inetreg.h" #include "tcpcons.h" #include "apiutil.h" #include #include #include #include #include #include // // 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; }