/*++ Copyright (c) 2001 Microsoft Corporation Module Name : updateini.cpp Abstract: High level function to update the ini with new values Author: Christopher Achille (cachille) Project: URLScan Update Revision History: March 2002: Created --*/ #include "stdafx.h" #include "windows.h" #include "updateini.h" #include "parseini.h" sURLScan_Settings g_urlSettings[] = { { L"options", L"UseAllowVerbs", { L"UseAllowVerbs=1 ; If 1, use [AllowVerbs] section, else use the", L" ; [DenyVerbs] section.", L"", NULL } }, // UseAllowVerbs { L"options", L"UseAllowExtensions", { L"UseAllowExtensions=0 ; If 1, use [AllowExtensions] section, else use", L" ; the [DenyExtensions] section.", L"", NULL } }, // UseAllowExtensions { L"options", L"NormalizeUrlBeforeScan", { L"NormalizeUrlBeforeScan=1 ; If 1, canonicalize URL before processing.", L"", NULL } }, // NormalizeUrlBeforeScan { L"options", L"VerifyNormalization", { L"VerifyNormalization=1 ; If 1, canonicalize URL twice and reject request", L" ; if a change occurs.", NULL } }, // VerifyNormalization { L"options", L"AllowHighBitCharacters", { L"AllowHighBitCharacters=0 ; If 1, allow high bit (ie. UTF8 or MBCS)", L" ; characters in URL.", L"", NULL } }, // AllowHighBitCharacters { L"options", L"AllowDotInPath", { L"AllowDotInPath=0 ; If 1, allow dots that are not file extensions.", L"", NULL } }, // AllowDotInPath { L"options", L"RemoveServerHeader", { L"RemoveServerHeader=0 ; If 1, remove the 'Server' header from response.", L"", NULL } }, // RemoveServerHeader { L"options", L"EnableLogging", { L"EnableLogging=1 ; If 1, log UrlScan activity.", L"", NULL } }, // EnableLogging { L"options", L"PerProcessLogging", { L"PerProcessLogging=0 ; If 1, the UrlScan.log filename will contain a PID", L" ; (ie. UrlScan.123.log).", L"", NULL } }, // PerProcessLogging { L"options", L"AllowLateScanning", { L"AllowLateScanning=0 ; If 1, then UrlScan will load as a low priority", L" ; filter.", L"", NULL } }, // AllowLateScanning { L"options", L"PerDayLogging", { L"PerDayLogging=1 ; If 1, UrlScan will produce a new log each day with", L" ; activity in the form 'UrlScan.010101.log'.", L"", NULL } }, // PerDayLogging { L"options", L"UseFastPathReject", { L"UseFastPathReject=0 ; If 1, then UrlScan will not use the", L" ; RejectResponseUrl or allow IIS to log the request.", L"", NULL } }, // UseFastPathReject { L"options", // Section Name L"LogLongUrls", // Setting Name { L"LogLongUrls=0 ; If 1, then up to 128K per request can be logged.", L" ; If 0, then only 1k is allowed.", L"", NULL } }, // LogLongURLs { L"options", L"RejectResponseUrl", { L";", L"; If UseFastPathReject is 0, then UrlScan will send", L"; rejected requests to the URL specified by RejectResponseUrl.", L"; If not specified, '/' will be used.", L";", L"", L"RejectResponseUrl=", L"", NULL } }, // RejectResponseUrl { L"options", L"LoggingDirectory", { L";", L"; LoggingDirectory can be used to specify the directory where the", L"; log file will be created. This value should be the absolute path", L"; (ie. c:\\some\\path). If not specified, then UrlScan will create", L"; the log in the same directory where the UrlScan.dll file is located.", L";", L"", L"LoggingDirectory=", L"", NULL } }, // Logging Directory { L"options", L"AlternateServerName", { L";", L"; If RemoveServerHeader is 0, then AlternateServerName can be", L"; used to specify a replacement for IIS's built in 'Server' header", L";", L"", L"AlternateServerName=", L"", NULL } }, // AlternateServerName { L"RequestLimits", L"MaxUrl", { L"MaxUrl=16384", NULL } }, // MaxUrl { L"RequestLimits", L"MaxQueryString", { L"MaxQueryString=4096", NULL} }, // MaxQueryString { L"RequestLimits", L"MaxAllowedContentLength", #ifdef PLEASE_BUILD_LESS_AGRESSIVE_DEFAULTS_VERSION { L"MaxAllowedContentLength=2000000000", #else { L"MaxAllowedContentLength=30000000", #endif NULL } } // MaxAllowedContentLength }; sURLScan_Sections g_urlSections[] = { { L"RequestLimits", // Section Name { L"", L";", L"; The entries in this section impose limits on the length", L"; of allowed parts of requests reaching the server.", L";", L"; It is possible to impose a limit on the length of the", L"; value of a specific request header by prepending \"Max-\" to the", L"; name of the header. For example, the following entry would", L"; impose a limit of 100 bytes to the value of the", L"; 'Content-Type' header:", L";", L"; Max-Content-Type=100", L";", L"; To list a header and not specify a maximum value, use 0", L"; (ie. 'Max-User-Agent=0'). Also, any headers not listed", L"; in this section will not be checked for length limits.", L";", L"; There are 3 special case limits:", L";", L"; - MaxAllowedContentLength specifies the maximum allowed", L"; numeric value of the Content-Length request header. For", L"; example, setting this to 1000 would cause any request", L"; with a content length that exceeds 1000 to be rejected.", #ifdef PLEASE_BUILD_LESS_AGRESSIVE_DEFAULTS_VERSION L"; The default is 2000000000.", #else L"; The default is 30000000.", #endif L";", L"; - MaxUrl specifies the maximum length of the request URL,", L"; not including the query string. The default is 260 (which", L"; is equivalent to MAX_PATH).", L";", L"; - MaxQueryString specifies the maximum length of the query", L"; string. The default is 4096.", L";", L"", #ifdef PLEASE_BUILD_LESS_AGRESSIVE_DEFAULTS_VERSION L"MaxAllowedContentLength=2000000000", #else L"MaxAllowedContentLength=30000000", #endif L"MaxUrl=16384", L"MaxQueryString=4096", L"", NULL } } // end of RequestLimits }; sURLScan_Items g_urlItems[] = { { L"DenyHeaders", L"Transfer-Encoding:", { L"Transfer-Encoding:", NULL } } }; // GetListLen // // Retrieve the Length of a variable length array of Strings // This is a special case function that works for our structs // above, because we leave the last String as NULL // DWORD GetListLen(LPWSTR szLines[]) { DWORD dwLen = 0; while ( szLines[dwLen] != NULL ) { dwLen++; } return dwLen; } // GetIniPath // // Given the Path to the Dll, create the path to the ini // // Parameters: // szDllPath - [in] The path to the binary for urlscan.dll // szIniPath - [out] The path to the ini file // dwIniLen - [in] The length of the string passed in for szIniPath // BOOL GetIniPath( LPTSTR szDllPath, LPTSTR szIniPath, DWORD dwIniLen ) { LPTSTR szLastPeriod; if ( _tcslen( szDllPath ) >= ( dwIniLen - 3 ) ) { // Error, string is not big enough return FALSE; } _tcscpy( szIniPath, szDllPath); szLastPeriod = _tcsrchr( szIniPath, '.' ); if ( !szLastPeriod ) { // Can not find the extension return FALSE; } _tcscpy( szLastPeriod, URLSCAN_INI_EXTENSION ); return TRUE; } // UpdateIniSections // // Update the Sections in the Ini, by merging them with the ones we have // defined // BOOL UpdateIniSections( CIniFile *pURLScanIniFile ) { DWORD dwCurrentSection; for ( dwCurrentSection = 0; dwCurrentSection < ( (DWORD) sizeof( g_urlSections ) / sizeof ( sURLScan_Sections ) ); dwCurrentSection++) { if ( !pURLScanIniFile->DoesSectionExist( g_urlSections[ dwCurrentSection].szSection ) ) { // Try to Create Section Then if ( !pURLScanIniFile->AddSection( g_urlSections[dwCurrentSection].szSection ) ) { // Failed to Add Section return FALSE; } // Now try to add the correct lines to it if ( g_urlSections[dwCurrentSection].szLines && !pURLScanIniFile->AddLinesToSection( g_urlSections[dwCurrentSection].szSection, GetListLen( g_urlSections[dwCurrentSection].szLines ), g_urlSections[dwCurrentSection].szLines ) ) { // Failed to Add Lines return FALSE; } } } return TRUE; } // UpdateIniSettings // // Update the Ini Settings inside the different sections if they are // not already set // BOOL UpdateIniSettings( CIniFile *pURLScanIniFile ) { DWORD dwCurrentSettings; for ( dwCurrentSettings = 0; dwCurrentSettings < ( (DWORD) sizeof( g_urlSettings ) / sizeof ( sURLScan_Settings ) ); dwCurrentSettings++) { if ( !pURLScanIniFile->DoesSectionExist( g_urlSettings[ dwCurrentSettings].szSection ) ) { // Create Section Since it does not exist if ( !pURLScanIniFile->AddSection( g_urlSettings[dwCurrentSettings].szSection ) ) { return FALSE; } } // !pURLScanIniFile->DoesSectionExist if ( !pURLScanIniFile->DoesSettingInSectionExist( g_urlSettings[dwCurrentSettings].szSection, g_urlSettings[dwCurrentSettings].szSettingName ) ) { // This setting does not exist, so lets add it if ( !pURLScanIniFile->AddLinesToSection( g_urlSettings[dwCurrentSettings].szSection, GetListLen( g_urlSettings[dwCurrentSettings].szLines ), g_urlSettings[dwCurrentSettings].szLines ) ) { return FALSE; } } // !pURLScanIniFile->DoesSettingInSectionExist } return TRUE; } // UpdateIniItems // // Update the Ini Settings inside the different sections if they are // not already set // BOOL UpdateIniItems( CIniFile *pURLScanIniFile ) { DWORD dwCurrentItems; for ( dwCurrentItems = 0; dwCurrentItems < ( (DWORD) sizeof( g_urlItems ) / sizeof ( sURLScan_Items ) ); dwCurrentItems++) { if ( !pURLScanIniFile->DoesSectionExist( g_urlItems[ dwCurrentItems].szSection ) ) { // Create Section Since it does not exist if ( !pURLScanIniFile->AddSection( g_urlSettings[dwCurrentItems].szSection ) ) { return FALSE; } } // !pURLScanIniFile->DoesSectionExist if ( !pURLScanIniFile->DoesItemInSectionExist( g_urlItems[dwCurrentItems].szSection, g_urlItems[dwCurrentItems].szSettingName ) ) { // This setting does not exist, so lets add it if ( !pURLScanIniFile->AddLinesToSection( g_urlItems[dwCurrentItems].szSection, GetListLen( g_urlItems[dwCurrentItems].szLines ), g_urlItems[dwCurrentItems].szLines ) ) { return FALSE; } } // !pURLScanIniFile->DoesItemInSectionExist } return TRUE; } // UpdateIni File // // Update the inf file with the new features // BOOL UpdateIni( LPTSTR szUrlScanPath ) { CIniFile URLScanIniFile; TCHAR szIniLocation[MAX_PATH]; BOOL bRet = TRUE; if ( !GetIniPath( szUrlScanPath, szIniLocation, MAX_PATH ) || !URLScanIniFile.LoadFile( szIniLocation ) ) { // Either we couldn't determine the location, or we couldn't // load the file return FALSE; } if ( bRet ) { // Note: UpdateIniSections must come before UpdateIniSettings #ifdef PLEASE_BUILD_LESS_AGRESSIVE_DEFAULTS_VERSION bRet = UpdateIniSections( &URLScanIniFile ) && UpdateIniSettings( &URLScanIniFile ); #else bRet = UpdateIniSections( &URLScanIniFile ) && UpdateIniSettings( &URLScanIniFile ) && UpdateIniItems( &URLScanIniFile ); #endif } if ( bRet ) { // Everything so far so good, so lets write the new ini bRet = URLScanIniFile.SaveFile( szIniLocation ); } return bRet; }