10809 lines
242 KiB
C++
10809 lines
242 KiB
C++
/*++
|
|
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
ism.cxx
|
|
|
|
Abstract:
|
|
|
|
HTML administrator for Internet services as a BGI DLL
|
|
|
|
Author:
|
|
|
|
Philippe Choquier (phillich) 10-january-1996
|
|
|
|
--*/
|
|
|
|
#include <windows.h>
|
|
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <ctype.h>
|
|
#include <limits.h>
|
|
#include <time.h>
|
|
#include <lmaccess.h>
|
|
|
|
#include <winsock2.h>
|
|
|
|
#include "iis64.h"
|
|
#include "iisext.h"
|
|
#include "inetinfo.h"
|
|
#include "apiutil.h"
|
|
|
|
#include <mbstring.h>
|
|
#include <pudebug.h>
|
|
|
|
typedef
|
|
BOOL
|
|
(*GET_DEFAULT_DOMAIN_NAME_FN)(PCHAR,DWORD);
|
|
|
|
#if defined(IISv1)
|
|
#define GENERATE_AUTH_HEADERS
|
|
#endif
|
|
|
|
//#define _CHECK_NEW_BALANCED
|
|
#if defined(_CHECK_NEW_BALANCED)
|
|
unsigned int g_cA = 0;
|
|
|
|
void* __cdecl operator new( unsigned int nb )
|
|
{
|
|
LPVOID p;
|
|
|
|
++g_cA;
|
|
|
|
if ( p = VirtualAlloc( NULL, 4096 + nb, MEM_RESERVE, PAGE_READWRITE) )
|
|
{
|
|
if ( VirtualAlloc( p, nb, MEM_COMMIT, PAGE_READWRITE ) )
|
|
{
|
|
return p;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
void __cdecl operator delete( void* p )
|
|
{
|
|
--g_cA;
|
|
|
|
VirtualFree( p, 0, MEM_RELEASE );
|
|
}
|
|
#endif
|
|
|
|
#define _ENABLE_KEEP_ALIVE
|
|
#include "ism.hxx"
|
|
#include "htmlarc.h"
|
|
|
|
// This BGI DLL presents HTTP requests to an extended syntax HTML
|
|
// file. Extensions includes variables ( mostly used to interface
|
|
// use the structures defined by the admin RPC layer ), flow control
|
|
// ( if, goto, onerror ), HTTP redirection control, calls to C++ functions,
|
|
// iterated construct access ( begin/end iteration ).
|
|
// These files are stored with an .htr extension
|
|
//
|
|
// The HTTP request is composed of 2 parts :
|
|
// - the query string, of the form <service_name>/<script_path>+<param>
|
|
// where <service_name> is the name of the service to access
|
|
// ( http, ftp, gopher )
|
|
// <script_path> defines the name of the .htr file to use. The .htr
|
|
// extension is appended automatically.
|
|
// <param> is made available to the .htr script through the <%urlparam%>
|
|
// variable, and is typically used to pass back a reference to an
|
|
// element to the script ( i.e. some unique ID referencing an element
|
|
// to update / delete, such as an IP security entry ).
|
|
// - the request body ( optional ), which must contains the result of
|
|
// an HTML FORM to be processed by the !Update function.
|
|
// This is to be present only for information update ( see below )
|
|
//
|
|
// Settings are accessed using variables ( via the '<%' varname '%>'
|
|
// construct ). Most variables map directly to a member variable of
|
|
// one the structures defined by the admin RPC layer, but some are
|
|
// defined onl to easily map with UI objects ( i.e. settings stored in
|
|
// a DWORD bitmask are exposed as multiple independant variables ).
|
|
//
|
|
// Variables are defined in the g_InetInfoConfigInfoMap array. A variable is
|
|
// defined by its name ( referenced using '<%' varname '%>' in a .htr file ),
|
|
// its type ( cf INET_ELEM_TYPE, this is also used to define the input and
|
|
// and output format ), a GET function ( update a pointer allowing get/set access
|
|
// to the variable, i.e. a LP(W)STR* for strings, DWORD* for numeric, LPBYTE* for IP
|
|
// addresses, LPWSTR for array of WCHAR. This function returns FALSE is the access
|
|
// is invalid ( e.g. RPC call to retrieve settings failed )
|
|
// and an UPDATE function ( a place to validate the new value ) to be called
|
|
// after updating the variable. This will returns FALSE if validation fails,
|
|
// or if the variable is inaccessible ( same as for GET : RPC failed, ... )
|
|
//
|
|
// A transaction ( seeing and modifying an internet server setting )
|
|
// is typically composed of 2 parts :
|
|
// - information display
|
|
// Using variables.
|
|
// - information update
|
|
// Some settings resides in iterated constructs ( e.g. IP security entries )
|
|
// accessing these settings is a 2 part process :
|
|
// - positionning
|
|
// To set the position on an existing instance of an iterated
|
|
// settings the HTTP request must includes a setting specific
|
|
// unique ID in the <param> part of the URL ( see above ).
|
|
// This ID is used by a positionning function ( such as PosVirtDir )
|
|
// to access the correct element. Deletion uses the same basic mechanism
|
|
// but requires a specific delete function to position and delete the
|
|
// element. This ID is available as a variable ( e.g. ipdenyref ) and is
|
|
// typically used to build the <param> field of an URL.
|
|
// To add an instance of an iterated settings, add functions are defined
|
|
// on a per iterated construct basis.
|
|
// - updating : same as a non iterated field.
|
|
//
|
|
// The settings are updated from the request body by the !Update
|
|
// function. The names in the HTML FORM construct must be the same
|
|
// as the one defined in the g_InetInfoConfigInfoMap array.
|
|
//
|
|
// As RPC structures are updated, so are the relevant FieldControl variables
|
|
// so that only the minimal amount of updating is done by the RPC server.
|
|
//
|
|
// In addition to functions to position, add, delete, set default, update
|
|
// variables there is a !Clear function to set to 0 a DWORD variable.
|
|
// This is necessary because a web browser doesn't send back information
|
|
// for a checkbox item if not checked, so te update script has to clear
|
|
// the relevant variable before calling the !Update function.
|
|
//
|
|
// As an error occurs, the error code is stored in reqstatus. If the error
|
|
// involves an RPC call the rpcstatus variable is also updated.
|
|
// This is typically used with the onerror statement to branch on error.
|
|
//
|
|
// Special note for IP security lists : there are 2 of them, the deny list
|
|
// and the grat list. If the grant list is empty, the default is assumed
|
|
// to be grant access. If the grant list is not empty, the default is deny access.
|
|
// To signal a default set to deny access when the grant list is empty, as is
|
|
// the case initially when a user modify the default to deny, a dummy entry
|
|
// is created by the windows based admin tool ( cf. g_achIPNullAddr ).
|
|
// This tool uses instead the IP HOST address for the current request,
|
|
// to allow the administrator access to the web server after switching the
|
|
// default to deny.
|
|
//
|
|
// The implementation of the current admin tools uses 2 types of .htr :
|
|
// - display .htr, which includes HTML FORMs and do not call update functions
|
|
// - update .htr, which calls update functions and typically only display
|
|
// something in case of error. If no error, they use a redirect construct
|
|
// to branch to a display .htr
|
|
// This distinction is a UI design conveniance : nothing in the design
|
|
// of this DLL enforce this.
|
|
// The .htr are typically common to all services ( http, ftp, gopher ).
|
|
// Service specific behaviour is possible by testing the servid variable.
|
|
|
|
// Hierarchy of the current implementation ( update .htr between parenthesis ) :
|
|
//
|
|
// HTMLA.HTM Top level menu to select service
|
|
// SERV.HTR "Service"
|
|
// ( SERVU.HTR )
|
|
// CONN.HTR Current connections ( FTP Only )
|
|
// ( DISC.HTR ) Disconnect a user
|
|
// ( DISCA.HTR ) Disconnect all users
|
|
// DIR.HTR "Diretories"
|
|
// ( DIRU.HTR )
|
|
// ( DIRDEL.HTR ) Delete a directory
|
|
// DIRADD.HTR Add a directory
|
|
// ( DIRADDU.HTR )
|
|
// DIREDT.HTR Edit a directory
|
|
// ( DIREDTU.HTR )
|
|
// LOG.HTR "Logging"
|
|
// ( LOGU.HTR )
|
|
// ADV.HTR "Advanced"
|
|
// ( ADVU.HTR )
|
|
// ADVDENY.HTR Ask is set default to deny
|
|
// ( ADVDENY2.HTR ) Set default to deny
|
|
// ( ADVGRANT.HTR ) Set default to grant
|
|
// ( ADVDED.HTR ) Delete a denied access entry
|
|
// ADVADDD.HTR Add a denied access entry
|
|
// ( ADVADDDU.HTR )
|
|
// ADVEDD.HTR Edit a denied access entry
|
|
// ( ADVEDDU.HTR )
|
|
// ( ADVDEG.HTR ) Delete a granted access entry
|
|
// ADVADDG.HTR Add a granted access entry
|
|
// ( ADVADDGU.HTR )
|
|
// ADVEDG.HTR Edit a granted access entry
|
|
// ( ADVEDGU.HTR )
|
|
// MSG.HTR "Messages" ( FTP Only )
|
|
// ( MSGU.HTR )
|
|
|
|
// If defined, enable DEBUG_TR() function. DEBUG_LEVEL value enables
|
|
// calls to DEBUG_TR up to this level ( as specified in the 1st param of
|
|
// DEBUG_TR(), the rest being equivalent to printf() )
|
|
|
|
#define DEBUG_LEVEL 0
|
|
|
|
// Separator used in a reference ( i.e. IP addr ref and virtdir ref )
|
|
|
|
#define REF_SEP '|'
|
|
#define REF_SEP_STR "|"
|
|
|
|
// Expire header insuring that the returned document will always be considered
|
|
// expired, so that it will not be cached.
|
|
|
|
#define ALWAYS_EXPIRE "Expires: Tue, 01 Jan 1980 00:00:00 GMT\r\n\r\n"
|
|
|
|
#if defined(GENERATE_AUTH_HEADERS)
|
|
char WWW_AUTHENTICATE_HEADER[] = "WWW-Authenticate: ";
|
|
#define W3SVC_REGISTRY_NTAUTHENTICATIONPROVIDERS "NtAuthenticationProviders"
|
|
#define W3SVC_REGISTRY_AUTHENTICATION "Authorization"
|
|
#endif
|
|
#define W3SVC_REGISTRY_PATH "SYSTEM\\CurrentControlSet\\Services\\W3SVC\\Parameters"
|
|
#define W3SVC_REGISTRY_HTMLAPATH "HtmlaPath"
|
|
|
|
|
|
// tokens used to extend the HTML syntax. Extended tokens are inclosed
|
|
// in a '<%' '%>' construct.
|
|
|
|
BYTE TOKEN_BEGIN_ITERATION[]="beginiteration";
|
|
BYTE TOKEN_END_ITERATION[]="enditeration";
|
|
BYTE TOKEN_IF[]="if ";
|
|
BYTE TOKEN_ELSE[]="else";
|
|
BYTE TOKEN_ENDIF[]="endif";
|
|
BYTE TOKEN_ELIF[]="elif ";
|
|
BYTE TOKEN_REDIRECT[]="redirect";
|
|
BYTE TOKEN_END_REDIRECT[]="/redirect";
|
|
BYTE TOKEN_REDIRECTH[]="redirecthttp";
|
|
BYTE TOKEN_END_REDIRECTH[]="/redirecthttp";
|
|
BYTE TOKEN_GOTO[]="goto ";
|
|
BYTE TOKEN_LABEL[]="label ";
|
|
BYTE TOKEN_ONERROR[]="onerror ";
|
|
BYTE TOKEN_POST[]="post";
|
|
BYTE TOKEN_END_POST[]="/post";
|
|
|
|
// null IP address used by the RPC admin layer to indicates a non-empty
|
|
// IP security list
|
|
|
|
char g_achIPNullAddr[]="0.0.0.0" REF_SEP_STR "255.255.255.255";
|
|
LPSTR g_pszIPNullAddr = g_achIPNullAddr;
|
|
|
|
// Instance handle of this DLL
|
|
|
|
HINSTANCE g_hModule = (HINSTANCE)INVALID_HANDLE_VALUE;
|
|
|
|
// Used to return a zero or one value when accessing an invalid DWORD variable
|
|
|
|
DWORD g_dwZero = 0;
|
|
DWORD g_dwOne = 1;
|
|
|
|
// TRUE if invoked from a test shell ( i.e. not from the web server )
|
|
|
|
BOOL g_fFakeServer = FALSE;
|
|
|
|
#if defined(GENERATE_AUTH_HEADERS)
|
|
CAuthenticationReqs g_AuthReqs;
|
|
#endif
|
|
|
|
BOOL g_InitDone = FALSE;
|
|
PSTR g_pszDefaultHostName = NULL;
|
|
CHAR g_achHtmlaPath[MAX_PATH + 1];
|
|
CHAR g_achW3Version[128];
|
|
|
|
CHAR g_achAccessDenied[128];
|
|
CHAR g_achAccessDeniedBody[256];
|
|
CHAR g_achInternalError[128];
|
|
CHAR g_achNotFound[128];
|
|
CHAR g_achNotFoundBody[256];
|
|
|
|
#if defined(IISv1)
|
|
OSVERSIONINFO g_OSVersion;
|
|
DWORD g_dwCap1Flag = 0x0000003f;
|
|
DWORD g_dwCap1Mask = 0x0000003f;
|
|
#endif
|
|
|
|
HINSTANCE g_hLonsi = NULL;
|
|
GET_DEFAULT_DOMAIN_NAME_FN g_pfnGetDefaultDomainName = NULL;
|
|
|
|
////////// Directory lists management
|
|
|
|
char g_achSysDir[MAX_PATH] = "";
|
|
|
|
|
|
CDriveView::CDriveView(
|
|
VOID )
|
|
{
|
|
}
|
|
|
|
|
|
CDriveView::~CDriveView(
|
|
VOID )
|
|
{
|
|
}
|
|
|
|
|
|
BOOL
|
|
CDriveView::Init(
|
|
CInetInfoConfigInfoMapper* pM )
|
|
{
|
|
m_pMapper = pM;
|
|
|
|
m_dsDriveName.Reset();
|
|
m_dsDriveLabel.Reset();
|
|
m_dsDriveType.Reset();
|
|
m_dwCachedDrive = 0;
|
|
m_tmCacheExpire = 0;
|
|
m_cDrives = 0;
|
|
|
|
if ( g_achSysDir[0] == '\0' )
|
|
{
|
|
if ( !GetSystemDirectory( g_achSysDir, sizeof(g_achSysDir) ) )
|
|
{
|
|
strcpy( g_achSysDir, "c:\\*.*" );
|
|
}
|
|
else
|
|
{
|
|
strcpy( g_achSysDir + 2, "\\*.*" );
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CDriveView::Reset(
|
|
VOID )
|
|
{
|
|
m_dsDirs.Reset();
|
|
m_dsComp.Reset();
|
|
m_dsFComp.Reset();
|
|
|
|
m_cDirs = 0;
|
|
m_cComp = 0;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CDriveView::Entry(
|
|
UINT i,
|
|
UINT cMax,
|
|
CDStr &dsList,
|
|
PVOID pRes )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns the ith entry ( base 0 ) in a CDStr considered
|
|
as a collection of sz strings.
|
|
|
|
Arguments:
|
|
|
|
i - index of entry to return
|
|
cMax - # of entries in the list
|
|
dsList - CDStr as collection of sz string entries
|
|
pRes - points to a LPSTR update with address of entry
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
LPSTR pList = dsList.GetString();
|
|
|
|
if ( i < cMax )
|
|
{
|
|
while ( i-- )
|
|
{
|
|
pList += strlen( pList ) + 1;
|
|
}
|
|
*(LPSTR*)pRes = pList;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CDriveView::ValidateDir(
|
|
LPSTR pDir )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Validate a directory path, set reqstatus HTR_VALIDATION_FAILED
|
|
if path invalid.
|
|
|
|
Arguments:
|
|
|
|
pDir - directory path to validate
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
updates reqstatus
|
|
|
|
--*/
|
|
{
|
|
DWORD dwS;
|
|
|
|
if ( (dwS = GetFileAttributes( pDir )) == 0xffffffff
|
|
|| !(dwS & FILE_ATTRIBUTE_DIRECTORY) )
|
|
{
|
|
m_pMapper->SetRequestStatus( HTR_VALIDATION_FAILED );
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CDriveView::CreateDir(
|
|
LPSTR pPath,
|
|
LPSTR pNewDir )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Create a new directory path from an existing path and
|
|
a directory name to be created.
|
|
set reqstatus HTR_VALIDATION_FAILED if creation fails
|
|
|
|
Arguments:
|
|
|
|
pPath - directory path inn which to create the new directory
|
|
pNewDir - directory to create
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
updates reqstatus
|
|
|
|
--*/
|
|
{
|
|
BOOL fSt = FALSE;
|
|
|
|
// Create path : insert '\\'\ between path and NewDir if
|
|
// necessary
|
|
|
|
int cP = strlen( pPath );
|
|
LPSTR pDir = new char[cP + 1 + strlen(pNewDir) + 1];
|
|
if ( pDir == NULL )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
memcpy( pDir, pPath, cP );
|
|
if ( cP > 0
|
|
&& &pPath[cP-1] != (LPSTR)_mbsrchr((LPBYTE)pPath,'\\')
|
|
&& pPath[cP-1] != '/'
|
|
&& *pNewDir != '\\'
|
|
&& *pNewDir != '/' )
|
|
{
|
|
pDir[cP++] = '\\';
|
|
}
|
|
strcpy( pDir + cP, pNewDir );
|
|
|
|
if ( !CreateDirectory( pDir, NULL ) )
|
|
{
|
|
m_pMapper->SetRequestStatus( HTR_VALIDATION_FAILED );
|
|
}
|
|
|
|
delete [] pDir;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
extern "C" int __cdecl
|
|
QsortStrCmp(
|
|
const void *pA,
|
|
const void *pB )
|
|
{
|
|
return _stricmp( *(LPSTR*)pA, *(LPSTR*)pB );
|
|
}
|
|
|
|
/* #pragma INTRINSA suppress=null_pointers */
|
|
|
|
BOOL
|
|
CDriveView::GenerateDirList(
|
|
LPSTR pDrive )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Generate all directory lists and related values :
|
|
m_achRootDir - path actually used in the search
|
|
always contains a drive designation,
|
|
ends with a '\'
|
|
m_achBaseDir - as m_achRootDir but without trailing '\'
|
|
m_dsComp - list of all the directory components of the path
|
|
m_dsFComp - list of all the directory components of the path
|
|
as an absolute path
|
|
m_dsDirs - list of all sub-directory of the path
|
|
m_dsDriveName - list of all drive names ( i.e "c:" )
|
|
m_dsDriveLabel - list of all drive labels
|
|
m_dsDriveType - list of all drive types ( as DRIVE_* )
|
|
|
|
Arguments:
|
|
|
|
pDrive - path where directory browsing is to take place.
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
updates reqstatus
|
|
|
|
--*/
|
|
{
|
|
WIN32_FIND_DATA fdF;
|
|
NETRESOURCE *pNetResource;
|
|
LPSTR pAdd;
|
|
LPSTR pPath;
|
|
BOOL fSt = TRUE;
|
|
DWORD dwSize;
|
|
DWORD cbBuffer;
|
|
DWORD dwResult;
|
|
HANDLE hEnum;
|
|
DWORD cEntries;
|
|
DWORD dwD;
|
|
UINT i;
|
|
int x;
|
|
|
|
Reset();
|
|
|
|
// replace all '/' with '\\'
|
|
for ( pPath = pDrive ; pPath = strchr( pPath, '/' ) ; ++pPath )
|
|
*pPath = '\\';
|
|
|
|
// Normalize pPath from pDrive : must end with '\*.*'
|
|
|
|
int cP = strlen( pDrive );
|
|
if ( cP > 0 && &pDrive[cP-1] == (LPSTR)_mbsrchr((LPBYTE)pDrive,'\\') )
|
|
{
|
|
pAdd = "*.*";
|
|
}
|
|
else
|
|
{
|
|
if ( cP == 0 )
|
|
{
|
|
pAdd = g_achSysDir;
|
|
}
|
|
else
|
|
{
|
|
pAdd = "\\*.*";
|
|
}
|
|
}
|
|
|
|
pPath = m_achRootDir;
|
|
memcpy( pPath, pDrive, cP );
|
|
strcpy( pPath + cP, pAdd );
|
|
|
|
// check directory path valid, if not use default value
|
|
|
|
HANDLE hF = FindFirstFile( pPath, &fdF) ;
|
|
if ( hF == INVALID_HANDLE_VALUE )
|
|
{
|
|
strcpy( pPath, g_achSysDir );
|
|
hF = FindFirstFile( pPath, &fdF) ;
|
|
}
|
|
|
|
if ( hF != INVALID_HANDLE_VALUE )
|
|
{
|
|
// build path component list
|
|
m_cComp = 0;
|
|
LPSTR pND, pCD = pPath;
|
|
for ( ; pND = (LPSTR)_mbschr( (LPBYTE)pCD, '\\' ) ; pCD = pND + 1 )
|
|
{
|
|
// copy subdir, or drive letter + ':' + '\\' for root
|
|
m_dsComp.AddRange( pCD, DIFF(pND - pCD) + (m_cComp == 0 ? 1 : 0) );
|
|
m_dsComp.AddRange( "", sizeof("") );
|
|
m_dsFComp.AddRange( pPath, DIFF(pND - pPath) + (m_cComp == 0 ? 1 : 0) );
|
|
m_dsFComp.AddRange( "", sizeof("") );
|
|
++m_cComp;
|
|
}
|
|
|
|
CDStr dsTempDir;
|
|
CDStr dsTempPtr;
|
|
DWORD dwI;
|
|
|
|
// build sub-directory list
|
|
do {
|
|
if ( fdF.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
|
|
{
|
|
if ( strcmp( fdF.cFileName, "." ) && strcmp( fdF.cFileName, ".." ) )
|
|
{
|
|
dwI = dsTempDir.GetLen();
|
|
dsTempDir.Add( fdF.cFileName );
|
|
dsTempDir.AddRange( "", sizeof("") );
|
|
dsTempPtr.AddRange( (LPSTR)&dwI, sizeof(DWORD) );
|
|
++m_cDirs;
|
|
}
|
|
}
|
|
} while ( FindNextFile( hF, &fdF ) );
|
|
|
|
if ( m_cDirs )
|
|
{
|
|
// adjust TempPtr from offset to ptr
|
|
LPSTR *pA = (LPSTR*)dsTempPtr.GetString();
|
|
for ( i = 0 ; i < m_cDirs ; ++i )
|
|
{
|
|
pA[i] = dsTempDir.GetString() + (ULONG_PTR)pA[i];
|
|
}
|
|
|
|
// sort
|
|
qsort( pA, m_cDirs, sizeof(LPSTR), QsortStrCmp );
|
|
|
|
// build sorted list
|
|
for ( i = 0 ; i < m_cDirs ; ++ i )
|
|
{
|
|
m_dsDirs.AddRange( pA[i], strlen(pA[i]) + 1 );
|
|
}
|
|
}
|
|
|
|
FindClose( hF );
|
|
}
|
|
else
|
|
{
|
|
if ( GetLastError() == ERROR_ACCESS_DENIED )
|
|
{
|
|
m_pMapper->SetRequestStatus( HTR_ACCESS_DENIED );
|
|
}
|
|
else
|
|
{
|
|
m_pMapper->SetRequestStatus( HTR_VALIDATION_FAILED );
|
|
}
|
|
}
|
|
|
|
// build drive list
|
|
|
|
dwD = GetLogicalDrives();
|
|
if ( dwD == m_dwCachedDrive
|
|
&& time(NULL) < m_tmCacheExpire )
|
|
{
|
|
// use cache
|
|
}
|
|
else
|
|
{
|
|
// build list of name for network drives
|
|
|
|
pNetResource = NULL;
|
|
dwResult = WNetOpenEnum( RESOURCE_REMEMBERED, RESOURCETYPE_DISK,
|
|
0, NULL, &hEnum );
|
|
|
|
if ( dwResult == NO_ERROR )
|
|
{
|
|
// start with a reasonable buffer size
|
|
cbBuffer = 100 * sizeof( NETRESOURCE );
|
|
pNetResource = (NETRESOURCE*) new BYTE[cbBuffer];
|
|
|
|
while ( TRUE )
|
|
{
|
|
dwSize = cbBuffer,
|
|
cEntries = 0xffffffff;
|
|
|
|
dwResult = WNetEnumResource( hEnum, &cEntries, pNetResource,
|
|
&dwSize );
|
|
|
|
if ( dwResult == ERROR_MORE_DATA )
|
|
{
|
|
// the buffer was too small, enlarge
|
|
cbBuffer = dwSize;
|
|
delete [] pNetResource;
|
|
pNetResource = (NETRESOURCE*) new BYTE[cbBuffer];
|
|
continue;
|
|
}
|
|
|
|
if ( dwResult != NO_ERROR )
|
|
{
|
|
delete [] pNetResource;
|
|
pNetResource = NULL;
|
|
cEntries = 0;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
}
|
|
WNetCloseEnum( hEnum );
|
|
}
|
|
else
|
|
{
|
|
cEntries = 0;
|
|
}
|
|
|
|
// because of x86 compiler bug
|
|
if ( pNetResource == NULL )
|
|
{
|
|
cEntries = 0;
|
|
}
|
|
|
|
m_dsDriveName.Reset();
|
|
m_dsDriveLabel.Reset();
|
|
m_dsDriveType.Reset();
|
|
m_cDrives = 0;
|
|
|
|
// iterate for all possible drive names
|
|
|
|
for ( x = 0 ; x < 'Z'-'A'+1 ; ++x )
|
|
{
|
|
char achD[4];
|
|
|
|
// check drive present and visible by this process
|
|
|
|
if ( dwD & (1<<x) )
|
|
{
|
|
strcpy( achD + 1, ":\\" );
|
|
achD[0] = 'A' + x;
|
|
UINT iT = GetDriveType( achD );
|
|
if ( iT > 1 )
|
|
{
|
|
DWORD dwI = iT;
|
|
char achVolName[80];
|
|
DWORD dwSerNum;
|
|
DWORD dwCompLen;
|
|
DWORD dwSysFlg;
|
|
BOOL fInf = FALSE;
|
|
|
|
// get volume information for non-removable
|
|
// & non cd-rom ( too slow to get info )
|
|
if ( iT == DRIVE_FIXED )
|
|
{
|
|
if ( GetVolumeInformation( achD,
|
|
achVolName,
|
|
sizeof(achVolName),
|
|
&dwSerNum,
|
|
&dwCompLen,
|
|
&dwSysFlg,
|
|
NULL,
|
|
0 ) )
|
|
{
|
|
m_dsDriveLabel.Add( achVolName );
|
|
fInf = TRUE;
|
|
}
|
|
}
|
|
else if ( iT == DRIVE_REMOTE )
|
|
{
|
|
if ( cEntries != 0 )
|
|
{
|
|
// search for the specified drive letter
|
|
for ( i = 0; i < (int) cEntries; i++ )
|
|
{
|
|
if ( pNetResource[i].lpLocalName &&
|
|
achD[0] == toupper(pNetResource[i]
|
|
.lpLocalName[0]) )
|
|
{
|
|
m_dsDriveLabel.Add( pNetResource[i]
|
|
.lpRemoteName );
|
|
fInf = TRUE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dwCompLen = sizeof( achVolName );
|
|
achD[2] = '\0';
|
|
|
|
if ( WNetGetConnection( achD, achVolName,
|
|
&dwCompLen ) == NO_ERROR )
|
|
{
|
|
m_dsDriveLabel.Add( achVolName );
|
|
fInf = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( fInf )
|
|
{
|
|
m_dsDriveType.AddRange( (LPSTR)&dwI, sizeof(DWORD) );
|
|
m_dsDriveName.AddRange( achD, 2 );
|
|
m_dsDriveName.AddRange( "", sizeof("") );
|
|
m_dsDriveLabel.AddRange( "", sizeof("") );
|
|
}
|
|
|
|
++m_cDrives;
|
|
}
|
|
}
|
|
}
|
|
m_dwCachedDrive = dwD;
|
|
if ( pNetResource != NULL )
|
|
{
|
|
delete [] pNetResource ;
|
|
}
|
|
}
|
|
m_tmCacheExpire = time(NULL) + DRIVE_CACHE_EXPIRE;
|
|
|
|
// delimit RootDir after last '\\'
|
|
LPSTR pL = pPath + strlen(pPath);
|
|
BOOL fAddedSep;
|
|
pL = (LPSTR)_mbsrchr((LPBYTE)pPath, '\\');
|
|
if (pL == NULL) pL = pPath;
|
|
if ( pL == (LPSTR)_mbschr( (LPBYTE)pPath, '\\' ) )
|
|
{
|
|
fAddedSep = TRUE;
|
|
++pL;
|
|
}
|
|
else
|
|
{
|
|
fAddedSep = FALSE;
|
|
}
|
|
if ( pL != pPath )
|
|
{
|
|
*pL = '\0';
|
|
}
|
|
|
|
strcpy( m_achBaseDir, pPath );
|
|
if ( fAddedSep )
|
|
{
|
|
*_mbschr( (LPBYTE)m_achBaseDir, '\\' ) = '\0';
|
|
}
|
|
|
|
return fSt;
|
|
}
|
|
|
|
|
|
// DEBUG handling
|
|
|
|
#if defined(DEBUG_LEVEL)
|
|
CInetInfoRequest *g_pReq;
|
|
#endif
|
|
|
|
void
|
|
TR_DEBUG(
|
|
int iLev,
|
|
LPSTR pFormat,
|
|
... )
|
|
{
|
|
#if defined(DEBUG_LEVEL)
|
|
if ( iLev <= DEBUG_LEVEL )
|
|
{
|
|
char achBuf[1024];
|
|
va_list arglist;
|
|
va_start( arglist, pFormat );
|
|
UINT cL = (UINT)wvsprintf( achBuf, pFormat, arglist );
|
|
g_pReq->GetBuffer()->CopyBuff( (LPBYTE)achBuf, cL );
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
// Global helper functions
|
|
|
|
|
|
void
|
|
DelimStrcpyN(
|
|
LPSTR pDest,
|
|
LPSTR pSrc,
|
|
int cLen )
|
|
{
|
|
memcpy( pDest, pSrc, cLen );
|
|
pDest[ cLen ] = '\0';
|
|
}
|
|
|
|
|
|
// Convert a Multi-byte string to a DWORD
|
|
|
|
DWORD
|
|
MultiByteToDWORD(
|
|
LPSTR pSet )
|
|
{
|
|
DWORD dwV = 0;
|
|
int c;
|
|
|
|
while ( (c=*pSet) != '\0' && c==' ' )
|
|
{
|
|
++pSet;
|
|
}
|
|
|
|
while ( (c=*pSet++) != '\0' && ((c>='0' && c<='9') || c==',') )
|
|
{
|
|
if ( c != ',' )
|
|
{
|
|
dwV = dwV*10 + c-'0';
|
|
}
|
|
}
|
|
|
|
return dwV;
|
|
}
|
|
|
|
|
|
// Convert a DWORD to a Multi-byte string
|
|
|
|
void
|
|
DWORDToMultiByte(
|
|
DWORD dwV,
|
|
LPSTR pS )
|
|
{
|
|
LPSTR pF = pS;
|
|
|
|
if ( dwV == 0 )
|
|
{
|
|
*pS++ = '0';
|
|
}
|
|
else for ( ; dwV ; dwV/=10 )
|
|
{
|
|
*pS++ = '0' + (int)(dwV%10);
|
|
}
|
|
*pS-- = '\0';
|
|
|
|
while ( pF < pS )
|
|
{
|
|
int c = *pF;
|
|
*pF++ = *pS;
|
|
*pS-- = (CHAR)c;
|
|
}
|
|
}
|
|
|
|
|
|
// convert ASCII Hex digit to UINT
|
|
|
|
UINT
|
|
HexCharToUINT(
|
|
UINT cH )
|
|
{
|
|
if ( cH>='0' && cH<='9' )
|
|
{
|
|
return cH-'0';
|
|
}
|
|
else if ( cH>='a' && cH<='f' )
|
|
{
|
|
return cH-'a'+10;
|
|
}
|
|
else if ( cH>='A' && cH<='F' )
|
|
{
|
|
return cH-'A'+10;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
///////////// Variable list
|
|
|
|
// to be accessed by the '<%' varname '%>'construct, and by various tokens
|
|
//
|
|
// Most of these variables map directly to a member variable of one of the
|
|
// structures defined bu the RPC admin layer ( cf. inetcom.h & inetinfo.h )
|
|
//
|
|
// Variables in iterated costructs ( e.g. virtual roots ) are to be used
|
|
// in a beginiteration ... enditeration construct. The element being accessed
|
|
// will be designated by the value of the CInetInfoConfigInfoMapper::m_iIter
|
|
// variable.
|
|
//
|
|
// Some of these variables are "virtual" : they do not map to a RPC struct,
|
|
// either because they are linked to the current BGI request ( e.g. reqstatus )
|
|
// or because the UI need to access info in a different way that what the RPC
|
|
// struct define ( e.g. we need to expose different variables to set/reset
|
|
// authentication method even if they are stored in one DWORD bitmask in the
|
|
// RPC struct ).
|
|
|
|
CInetInfoMap g_InetInfoConfigInfoMap[] = {
|
|
|
|
// request variables ( linked to the current BGI request )
|
|
|
|
{ "reqstatus", ITYPE_DWORD, &CInetInfoConfigInfoMapper::RequestStatus,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate, 0
|
|
},
|
|
{ "rpcstatus", ITYPE_DWORD, &CInetInfoConfigInfoMapper::RPCStatus,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate, 0
|
|
},
|
|
{ "rpcstatusstring", ITYPE_LPSTR, &CInetInfoConfigInfoMapper::RPCStatusString,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate, 0
|
|
},
|
|
{ "iter", ITYPE_DWORD, &CInetInfoConfigInfoMapper::Iter,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate, 0
|
|
},
|
|
{ "httpstatus", ITYPE_DWORD, &CInetInfoConfigInfoMapper::HttpStatus,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate, 0
|
|
},
|
|
{ "ftpstatus", ITYPE_DWORD, &CInetInfoConfigInfoMapper::FtpStatus,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate, 0
|
|
},
|
|
{ "gopherstatus", ITYPE_DWORD, &CInetInfoConfigInfoMapper::GopherStatus,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate, 0
|
|
},
|
|
|
|
|
|
// version information
|
|
|
|
{ "osmajorversion", ITYPE_DWORD, &CInetInfoConfigInfoMapper::OSMajorVersion,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate, 0
|
|
},
|
|
{ "osminorversion", ITYPE_DWORD, &CInetInfoConfigInfoMapper::OSMinorVersion,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate, 0
|
|
},
|
|
{ "osbuildnumber", ITYPE_DWORD, &CInetInfoConfigInfoMapper::OSBuildNumber,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate, 0
|
|
},
|
|
{ "majorversion", ITYPE_DWORD, &CInetInfoConfigInfoMapper::MajorVersion,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate, 0
|
|
},
|
|
{ "minorversion", ITYPE_DWORD, &CInetInfoConfigInfoMapper::MinorVersion,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate, 0
|
|
},
|
|
{ "w3version", ITYPE_LPSTR, &CInetInfoConfigInfoMapper::W3Version,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate, 0
|
|
},
|
|
{ "platformtype", ITYPE_DWORD, &CInetInfoConfigInfoMapper::PlatformType,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate, 0
|
|
},
|
|
{ "cap1flag", ITYPE_DWORD, &CInetInfoConfigInfoMapper::Cap1Flag,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate, 0
|
|
},
|
|
{ "cap1mask", ITYPE_DWORD, &CInetInfoConfigInfoMapper::Cap1Mask,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate, 0
|
|
},
|
|
{ "userflags", ITYPE_DWORD, &CInetInfoConfigInfoMapper::UserFlags,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate, 0
|
|
},
|
|
|
|
{ "urlparam", ITYPE_LPSTR, &CInetInfoConfigInfoMapper::URLParam,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate , 0
|
|
},
|
|
{ "servname", ITYPE_LPSTR, &CInetInfoConfigInfoMapper::ServName,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate , 0
|
|
},
|
|
{ "servid", ITYPE_DWORD, &CInetInfoConfigInfoMapper::ServIdx,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate , 0
|
|
},
|
|
{ "reqparam", ITYPE_LPSTR, &CInetInfoConfigInfoMapper::ReqParam,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate , 0
|
|
},
|
|
{ "remoteaddr", ITYPE_LPSTR, &CInetInfoConfigInfoMapper::RemoteAddr,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate , 0
|
|
},
|
|
{ "ipnulladdr", ITYPE_LPSTR, &CInetInfoConfigInfoMapper::IPNullAddr,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate , 0
|
|
},
|
|
{ "hostname", ITYPE_LPSTR, &CInetInfoConfigInfoMapper::HostName,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate , 0
|
|
},
|
|
{ "htmlapath", ITYPE_LPSTR, &CInetInfoConfigInfoMapper::HtmlaPath,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate , 0
|
|
},
|
|
{ "iter", ITYPE_DWORD, &CInetInfoConfigInfoMapper::Iter,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate , 0
|
|
},
|
|
|
|
|
|
// INET_COM_CONFIG_INFO ( same name, different values for each service )
|
|
|
|
{ "comconntimeout", ITYPE_SHORTDW, &CInetInfoConfigInfoMapper::CommTimeout,
|
|
&CInetInfoConfigInfoMapper::UpdateCommTimeout, 0
|
|
},
|
|
{ "commaxconn", ITYPE_DWORD, &CInetInfoConfigInfoMapper::MaxConn,
|
|
&CInetInfoConfigInfoMapper::UpdateMaxConn, 0
|
|
},
|
|
{ "comadminname", ITYPE_LPWSTR, &CInetInfoConfigInfoMapper::AdminName,
|
|
&CInetInfoConfigInfoMapper::UpdateAdminName, 0
|
|
},
|
|
{ "comadminemail", ITYPE_LPWSTR, &CInetInfoConfigInfoMapper::AdminEmail,
|
|
&CInetInfoConfigInfoMapper::UpdateAdminEmail, 0
|
|
},
|
|
{ "comservercomment", ITYPE_LPWSTR, &CInetInfoConfigInfoMapper::ServerComment,
|
|
&CInetInfoConfigInfoMapper::UpdateServerComment, 0
|
|
},
|
|
|
|
// INET_LOG_CONFIGURATION
|
|
|
|
{ "enablelog", ITYPE_BOOL, &CInetInfoConfigInfoMapper::EnableLog,
|
|
&CInetInfoConfigInfoMapper::UpdateLog, 0
|
|
} , // log type
|
|
{ "logtype", ITYPE_DWORD, &CInetInfoConfigInfoMapper::LogType,
|
|
&CInetInfoConfigInfoMapper::UpdateLogType, 0
|
|
},
|
|
{ "enablenewlog", ITYPE_BOOL, &CInetInfoConfigInfoMapper::EnableNewLog,
|
|
&CInetInfoConfigInfoMapper::UpdateNewLog, 0
|
|
} ,
|
|
{ "logperiod", ITYPE_DWORD, &CInetInfoConfigInfoMapper::LogPeriod,
|
|
&CInetInfoConfigInfoMapper::UpdateLogPeriod, 0
|
|
}, // log period
|
|
{ "logformat", ITYPE_DWORD, &CInetInfoConfigInfoMapper::LogFormat,
|
|
&CInetInfoConfigInfoMapper::UpdateLogFormat, 0
|
|
},
|
|
{ "logdir", ITYPE_AWCHAR, &CInetInfoConfigInfoMapper::LogDir,
|
|
&CInetInfoConfigInfoMapper::UpdateLogFileInfo, MAX_PATH
|
|
},
|
|
{ "logsize", ITYPE_1M, &CInetInfoConfigInfoMapper::LogSize,
|
|
&CInetInfoConfigInfoMapper::UpdateLogSize, 0
|
|
},
|
|
{ "logsrc", ITYPE_AWCHAR, &CInetInfoConfigInfoMapper::LogSrc,
|
|
&CInetInfoConfigInfoMapper::UpdateLogODBCInfo, MAX_PATH // sizeof(INET_LOG_CONFIGURATION.rgchDataSource)
|
|
},
|
|
{ "logname", ITYPE_AWCHAR, &CInetInfoConfigInfoMapper::LogName,
|
|
&CInetInfoConfigInfoMapper::UpdateLogODBCInfo, MAX_TABLE_NAME_LEN // sizeof(INET_LOG_CONFIGURATION.rgchTableName)
|
|
},
|
|
{ "loguser", ITYPE_AWCHAR, &CInetInfoConfigInfoMapper::LogUser,
|
|
&CInetInfoConfigInfoMapper::UpdateLogODBCInfo, MAX_USER_NAME_LEN // sizeof(INET_LOG_CONFIGURATION.rgchUserName)
|
|
},
|
|
{ "logpw", ITYPE_AWCHAR, &CInetInfoConfigInfoMapper::LogPw,
|
|
&CInetInfoConfigInfoMapper::UpdateLogODBCInfo, MAX_PASSWORD_LEN // sizeof(INET_LOG_CONFIGURATION.rgchPassword)
|
|
},
|
|
{ "invalidlogupdate", ITYPE_BOOL, &CInetInfoConfigInfoMapper::InvalidLogUpdate,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate, 0
|
|
},
|
|
|
|
// INET_INFO_CONFIG_INFO
|
|
{ "loganon", ITYPE_BOOL, &CInetInfoConfigInfoMapper::LogAnonymous,
|
|
&CInetInfoConfigInfoMapper::UpdateLogAnonymous, 0
|
|
},
|
|
{ "lognona", ITYPE_BOOL, &CInetInfoConfigInfoMapper::LogNonAnonymous,
|
|
&CInetInfoConfigInfoMapper::UpdateLogNonAnonymous, 0
|
|
},
|
|
{ "anonun", ITYPE_LPWSTR, &CInetInfoConfigInfoMapper::AnonUserName,
|
|
&CInetInfoConfigInfoMapper::UpdateAnonUserName, 0
|
|
},
|
|
{ "anonpw", ITYPE_AWCHAR, &CInetInfoConfigInfoMapper::AnonUserPw,
|
|
&CInetInfoConfigInfoMapper::UpdateAnonUserPw, PWLEN+1, // sizeof(INET_INFO_CONFIG_INFO.szAnonPassword)
|
|
},
|
|
{ "authanon", ITYPE_BOOL, &CInetInfoConfigInfoMapper::AuthAnon,
|
|
&CInetInfoConfigInfoMapper::UpdateAuth, 0
|
|
},
|
|
{ "authbasic", ITYPE_BOOL, &CInetInfoConfigInfoMapper::AuthBasic,
|
|
&CInetInfoConfigInfoMapper::UpdateAuth, 0
|
|
},
|
|
{ "authnt", ITYPE_BOOL, &CInetInfoConfigInfoMapper::AuthNT,
|
|
&CInetInfoConfigInfoMapper::UpdateAuth, 0
|
|
},
|
|
{ "sport", ITYPE_SHORT, &CInetInfoConfigInfoMapper::SPort,
|
|
&CInetInfoConfigInfoMapper::UpdateSPort, 0
|
|
},
|
|
// Deny IP list
|
|
{ "denyipcount", ITYPE_DWORD, &CInetInfoConfigInfoMapper::DenyIPCount,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate, 0
|
|
},
|
|
{ "denyisipsingle", ITYPE_BOOL, &CInetInfoConfigInfoMapper::DenyIsIPSingle,
|
|
&CInetInfoConfigInfoMapper::UpdateDenyIsIPSingle, 0
|
|
},
|
|
{ "denyipaddr", ITYPE_IP_ADDR, &CInetInfoConfigInfoMapper::DenyIPAddr,
|
|
&CInetInfoConfigInfoMapper::UpdateIP, 0
|
|
},
|
|
{ "denyipmask", ITYPE_IP_MASK, &CInetInfoConfigInfoMapper::DenyIPMask,
|
|
&CInetInfoConfigInfoMapper::UpdateDenyIsIPSingle, 0
|
|
},
|
|
// Grant IP list
|
|
{ "grantipcount", ITYPE_DWORD, &CInetInfoConfigInfoMapper::GrantIPCount,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate, 0
|
|
},
|
|
{ "grantisipsingle", ITYPE_BOOL, &CInetInfoConfigInfoMapper::GrantIsIPSingle,
|
|
&CInetInfoConfigInfoMapper::UpdateGrantIsIPSingle, 0
|
|
},
|
|
{ "grantipaddr", ITYPE_IP_ADDR, &CInetInfoConfigInfoMapper::GrantIPAddr,
|
|
&CInetInfoConfigInfoMapper::UpdateIP, 0
|
|
},
|
|
{ "grantipmask", ITYPE_IP_MASK, &CInetInfoConfigInfoMapper::GrantIPMask,
|
|
&CInetInfoConfigInfoMapper::UpdateGrantIsIPSingle, 0
|
|
},
|
|
// IP reference
|
|
{ "ipdenyref", ITYPE_LPSTR, &CInetInfoConfigInfoMapper::IPDenyRef,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate, 0
|
|
},
|
|
{ "ipgrantref", ITYPE_LPSTR, &CInetInfoConfigInfoMapper::IPGrantRef,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate, 0
|
|
},
|
|
// Virtual root
|
|
{ "rootcount", ITYPE_DWORD, &CInetInfoConfigInfoMapper::RootCount,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate, 0
|
|
},
|
|
{ "rootname", ITYPE_VIRT_DIR_LPWSTR, &CInetInfoConfigInfoMapper::RootName,
|
|
&CInetInfoConfigInfoMapper::UpdateRootName, 0
|
|
},
|
|
{ "rootaddr", ITYPE_LPWSTR, &CInetInfoConfigInfoMapper::RootAddr,
|
|
&CInetInfoConfigInfoMapper::UpdateRoot, 0
|
|
},
|
|
{ "rootdir", ITYPE_PATH_LPWSTR, &CInetInfoConfigInfoMapper::RootDir,
|
|
&CInetInfoConfigInfoMapper::UpdateRoot, 0
|
|
},
|
|
{ "rootishome", ITYPE_BOOL, &CInetInfoConfigInfoMapper::RootIsHome,
|
|
&CInetInfoConfigInfoMapper::UpdateRoot, 0
|
|
},
|
|
{ "rootisread", ITYPE_BOOL, &CInetInfoConfigInfoMapper::RootIsRead,
|
|
&CInetInfoConfigInfoMapper::UpdateRootMask, 0
|
|
},
|
|
{ "rootiswrite", ITYPE_BOOL, &CInetInfoConfigInfoMapper::RootIsWrite,
|
|
&CInetInfoConfigInfoMapper::UpdateRootMask, 0
|
|
},
|
|
{ "rootisexec", ITYPE_BOOL, &CInetInfoConfigInfoMapper::RootIsExec,
|
|
&CInetInfoConfigInfoMapper::UpdateRootMask, 0
|
|
},
|
|
{ "rootisssl", ITYPE_BOOL, &CInetInfoConfigInfoMapper::RootIsSSL,
|
|
&CInetInfoConfigInfoMapper::UpdateRootMask, 0
|
|
},
|
|
{ "rootacctname", ITYPE_LPWSTR, &CInetInfoConfigInfoMapper::RootAcctName,
|
|
&CInetInfoConfigInfoMapper::UpdateRoot, 0
|
|
},
|
|
{ "rootacctpw", ITYPE_AWCHAR, &CInetInfoConfigInfoMapper::RootAcctPw,
|
|
&CInetInfoConfigInfoMapper::UpdateRoot, PWLEN +1 // sizeof(INET_INFO_VIRTUAL_ROOT_ENTRY.AccountPassword)
|
|
},
|
|
{ "rooterror", ITYPE_DWORD, &CInetInfoConfigInfoMapper::RootError,
|
|
&CInetInfoConfigInfoMapper::UpdateRoot, 0
|
|
},
|
|
// Virtual Root reference
|
|
{ "rootref", ITYPE_LPSTR, &CInetInfoConfigInfoMapper::RootRef,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate, 0
|
|
},
|
|
|
|
// W3
|
|
{ "w3dirbrowseenabled", ITYPE_BOOL, &CInetInfoConfigInfoMapper::DirBrowseEnab,
|
|
&CInetInfoConfigInfoMapper::UpdateDirControl, 0
|
|
},
|
|
{ "w3defaultfileenabled", ITYPE_BOOL, &CInetInfoConfigInfoMapper::DefFileEnab,
|
|
&CInetInfoConfigInfoMapper::UpdateDirControl, 0
|
|
},
|
|
{ "w3defaultfile", ITYPE_LPWSTR, &CInetInfoConfigInfoMapper::DefFile,
|
|
&CInetInfoConfigInfoMapper::UpdateDefFile, 0
|
|
},
|
|
{ "w3ssienabled", ITYPE_BOOL, &CInetInfoConfigInfoMapper::SSIEnabled,
|
|
&CInetInfoConfigInfoMapper::UpdateSSIEnabled, 0
|
|
},
|
|
{ "w3ssiext", ITYPE_LPWSTR, &CInetInfoConfigInfoMapper::SSIExt,
|
|
&CInetInfoConfigInfoMapper::UpdateSSIExt, 0
|
|
},
|
|
{ "w3cryptcapable", ITYPE_DWORD, &CInetInfoConfigInfoMapper::CryptCapable,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate, 0
|
|
},
|
|
|
|
// Gopher
|
|
{ "gophersite", ITYPE_LPWSTR, &CInetInfoConfigInfoMapper::GopherSite,
|
|
&CInetInfoConfigInfoMapper::UpdateGopherSite, 0
|
|
},
|
|
{ "gopherorg", ITYPE_LPWSTR, &CInetInfoConfigInfoMapper::GopherOrg,
|
|
&CInetInfoConfigInfoMapper::UpdateGopherOrg, 0
|
|
},
|
|
{ "gopherloc", ITYPE_LPWSTR, &CInetInfoConfigInfoMapper::GopherLoc,
|
|
&CInetInfoConfigInfoMapper::UpdateGopherLoc, 0
|
|
},
|
|
{ "gophergeo", ITYPE_LPWSTR, &CInetInfoConfigInfoMapper::GopherGeo,
|
|
&CInetInfoConfigInfoMapper::UpdateGopherGeo, 0
|
|
},
|
|
{ "gopherlang", ITYPE_LPWSTR, &CInetInfoConfigInfoMapper::GopherLang,
|
|
&CInetInfoConfigInfoMapper::UpdateGopherLang, 0
|
|
},
|
|
|
|
// FTP
|
|
{ "ftpallowanon", ITYPE_BOOL, &CInetInfoConfigInfoMapper::FTPIsAnon,
|
|
&CInetInfoConfigInfoMapper::UpdateFTPIsAnon, 0
|
|
},
|
|
{ "ftpallowguest", ITYPE_BOOL, &CInetInfoConfigInfoMapper::FTPIsGuest,
|
|
&CInetInfoConfigInfoMapper::UpdateFTPIsGuest, 0
|
|
},
|
|
{ "ftpannotdir", ITYPE_BOOL, &CInetInfoConfigInfoMapper::FTPIsAnotDir,
|
|
&CInetInfoConfigInfoMapper::UpdateFTPIsAnotDir, 0
|
|
},
|
|
{ "ftpanononly", ITYPE_BOOL, &CInetInfoConfigInfoMapper::FTPIsAnonOnly,
|
|
&CInetInfoConfigInfoMapper::UpdateFTPIsAnonOnly, 0
|
|
},
|
|
{ "ftpexitmsg", ITYPE_LPWSTR, &CInetInfoConfigInfoMapper::FTPExitMsg,
|
|
&CInetInfoConfigInfoMapper::UpdateFTPExitMsg, 0
|
|
},
|
|
{ "ftpgreetmsg", ITYPE_LPWSTR, &CInetInfoConfigInfoMapper::FTPGreetMsg,
|
|
&CInetInfoConfigInfoMapper::UpdateFTPGreetMsg, 0
|
|
},
|
|
{ "ftphomedir", ITYPE_LPWSTR, &CInetInfoConfigInfoMapper::FTPHomeDir,
|
|
&CInetInfoConfigInfoMapper::UpdateFTPHomeDir, 0
|
|
},
|
|
{ "ftmaxclmsg", ITYPE_LPWSTR, &CInetInfoConfigInfoMapper::FTPMaxClMsg,
|
|
&CInetInfoConfigInfoMapper::UpdateFTPMaxClMsg, 0
|
|
},
|
|
{ "ftpmsdosdirout", ITYPE_BOOL, &CInetInfoConfigInfoMapper::FTPIsMsdos,
|
|
&CInetInfoConfigInfoMapper::UpdateFTPIsMsdos, 0
|
|
},
|
|
|
|
// User enumeration
|
|
{ "enumusercount", ITYPE_DWORD, &CInetInfoConfigInfoMapper::UCount,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate, 0
|
|
},
|
|
{ "enumusername", ITYPE_LPWSTR, &CInetInfoConfigInfoMapper::UName,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate, 0
|
|
},
|
|
{ "enumuseranon", ITYPE_BOOL, &CInetInfoConfigInfoMapper::UAnonymous,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate, 0
|
|
},
|
|
{ "enumuseraddr", ITYPE_IP_ADDR, &CInetInfoConfigInfoMapper::UAddr,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate, 0
|
|
},
|
|
{ "enumusertime", ITYPE_TIME, &CInetInfoConfigInfoMapper::UTime,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate, 0
|
|
},
|
|
{ "enumuserid", ITYPE_DWORD, &CInetInfoConfigInfoMapper::UID,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate, 0
|
|
},
|
|
|
|
|
|
// Global
|
|
{ "globalisbandwidthlimited", ITYPE_DWORD, &CInetInfoConfigInfoMapper::GlobalIsBandwidthLimited,
|
|
&CInetInfoConfigInfoMapper::UpdateGlobalIsBandwidthLimited, 0
|
|
},
|
|
{ "globalbandwidth", ITYPE_1K, &CInetInfoConfigInfoMapper::GlobalBandwidth,
|
|
&CInetInfoConfigInfoMapper::UpdateGlobalBandwidth, 0
|
|
},
|
|
{ "globalcache", ITYPE_DWORD, &CInetInfoConfigInfoMapper::GlobalCache,
|
|
&CInetInfoConfigInfoMapper::UpdateGlobal, 0
|
|
},
|
|
} ;
|
|
|
|
|
|
CInetInfoMap g_InetInfoDirInfoMap[] = {
|
|
|
|
// request variables ( linked to the current BGI request )
|
|
|
|
{ "reqstatus", ITYPE_DWORD, &CInetInfoConfigInfoMapper::RequestStatus,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate, 0
|
|
},
|
|
{ "rpcstatus", ITYPE_DWORD, &CInetInfoConfigInfoMapper::RPCStatus,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate, 0
|
|
},
|
|
{ "rpcstatusstring", ITYPE_LPSTR, &CInetInfoConfigInfoMapper::RPCStatusString,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate, 0
|
|
},
|
|
{ "iter", ITYPE_DWORD, &CInetInfoConfigInfoMapper::Iter,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate , 0
|
|
},
|
|
{ "userflags", ITYPE_DWORD, &CInetInfoConfigInfoMapper::UserFlags,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate, 0
|
|
},
|
|
{ "urlparam", ITYPE_LPSTR, &CInetInfoConfigInfoMapper::URLParam,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate , 0
|
|
},
|
|
{ "reqparam", ITYPE_LPSTR, &CInetInfoConfigInfoMapper::ReqParam,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate , 0
|
|
},
|
|
{ "remoteaddr", ITYPE_LPSTR, &CInetInfoConfigInfoMapper::RemoteAddr,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate , 0
|
|
},
|
|
{ "hostname", ITYPE_LPSTR, &CInetInfoConfigInfoMapper::HostName,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate , 0
|
|
},
|
|
{ "htmlapath", ITYPE_LPSTR, &CInetInfoConfigInfoMapper::HtmlaPath,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate , 0
|
|
},
|
|
{ "arg1", ITYPE_LPSTR, &CInetInfoConfigInfoMapper::Arg1,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate , 0
|
|
},
|
|
{ "arg2", ITYPE_LPSTR, &CInetInfoConfigInfoMapper::Arg2,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate , 0
|
|
},
|
|
{ "arg3", ITYPE_LPSTR, &CInetInfoConfigInfoMapper::Arg3,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate , 0
|
|
},
|
|
|
|
// version information
|
|
|
|
{ "w3version", ITYPE_LPSTR, &CInetInfoConfigInfoMapper::W3Version,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate, 0
|
|
},
|
|
{ "platformtype", ITYPE_DWORD, &CInetInfoConfigInfoMapper::PlatformType,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate, 0
|
|
},
|
|
|
|
{ "w3cryptcapable", ITYPE_DWORD, &CInetInfoConfigInfoMapper::CryptCapable,
|
|
&CInetInfoConfigInfoMapper::DenyUpdate, 0
|
|
},
|
|
|
|
{ "rootdir", ITYPE_LPSTR, &CInetInfoConfigInfoMapper::DirRootDir,
|
|
&CInetInfoConfigInfoMapper::IgnoreUpdate , 0
|
|
},
|
|
{ "basedir", ITYPE_LPSTR, &CInetInfoConfigInfoMapper::DirBaseDir,
|
|
&CInetInfoConfigInfoMapper::IgnoreUpdate, 0
|
|
},
|
|
{ "dircount", ITYPE_DWORD, &CInetInfoConfigInfoMapper::DirCount,
|
|
&CInetInfoConfigInfoMapper::IgnoreUpdate , 0
|
|
},
|
|
{ "direntry", ITYPE_LPSTR, &CInetInfoConfigInfoMapper::DirEntry,
|
|
&CInetInfoConfigInfoMapper::IgnoreUpdate , 0
|
|
},
|
|
{ "dircompcount", ITYPE_DWORD, &CInetInfoConfigInfoMapper::DirCompCount,
|
|
&CInetInfoConfigInfoMapper::IgnoreUpdate , 0
|
|
},
|
|
{ "dircompentry", ITYPE_LPSTR, &CInetInfoConfigInfoMapper::DirCompEntry,
|
|
&CInetInfoConfigInfoMapper::IgnoreUpdate , 0
|
|
},
|
|
{ "dirfcompentry", ITYPE_LPSTR, &CInetInfoConfigInfoMapper::DirFCompEntry,
|
|
&CInetInfoConfigInfoMapper::IgnoreUpdate , 0
|
|
},
|
|
{ "drivecount", ITYPE_DWORD, &CInetInfoConfigInfoMapper::DriveCount,
|
|
&CInetInfoConfigInfoMapper::IgnoreUpdate , 0
|
|
},
|
|
{ "drivenameentry", ITYPE_LPSTR, &CInetInfoConfigInfoMapper::DriveNameEntry,
|
|
&CInetInfoConfigInfoMapper::IgnoreUpdate , 0
|
|
},
|
|
{ "drivelabelentry", ITYPE_LPSTR, &CInetInfoConfigInfoMapper::DriveLabelEntry,
|
|
&CInetInfoConfigInfoMapper::IgnoreUpdate , 0
|
|
},
|
|
{ "drivetypeentry", ITYPE_DWORD, &CInetInfoConfigInfoMapper::DriveTypeEntry,
|
|
&CInetInfoConfigInfoMapper::IgnoreUpdate , 0
|
|
},
|
|
|
|
} ;
|
|
|
|
|
|
///////////// User enumeration
|
|
|
|
// Generic for all services. This structure is bound to
|
|
// a CInetInfoConfigInfoMapper object, which will provide service type.
|
|
// Gives access to the list of currently connected users for this service.
|
|
|
|
|
|
CUserEnum::CUserEnum(
|
|
VOID )
|
|
{
|
|
}
|
|
|
|
|
|
CUserEnum::~CUserEnum(
|
|
VOID )
|
|
{
|
|
}
|
|
|
|
|
|
BOOL
|
|
CUserEnum::Init(
|
|
CInetInfoConfigInfoMapper* pM )
|
|
{
|
|
m_pMapper = pM;
|
|
m_pUsers = NULL;
|
|
Reset();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
// Unbind object with user list
|
|
|
|
void
|
|
CUserEnum::Reset(
|
|
VOID )
|
|
{
|
|
if ( m_pUsers != NULL )
|
|
{
|
|
MIDL_user_free( m_pUsers );
|
|
m_pUsers = NULL;
|
|
}
|
|
m_dwCount = 0;
|
|
}
|
|
|
|
|
|
// Insure list loaded. This allow usage on a "load on demand" basis
|
|
|
|
BOOL
|
|
CUserEnum::InsureLoaded(
|
|
VOID )
|
|
{
|
|
NET_API_STATUS is = 0;
|
|
|
|
if ( m_pUsers == NULL )
|
|
{
|
|
// get list relevant to current service
|
|
|
|
__try {
|
|
|
|
switch ( m_pMapper->GetType() )
|
|
{
|
|
case INET_HTTP_SVC_ID:
|
|
is = W3EnumerateUsers( m_pMapper->GetComputerName(),
|
|
&m_dwCount, &m_pUsers );
|
|
break;
|
|
|
|
case INET_FTP_SVC_ID:
|
|
is = I_FtpEnumerateUsers( m_pMapper->GetComputerName(),
|
|
&m_dwCount, (LPFTP_USER_INFO*)&m_pUsers );
|
|
break;
|
|
|
|
default:
|
|
// no list : error
|
|
is = (NET_API_STATUS)~0;
|
|
break;
|
|
}
|
|
|
|
}
|
|
__except( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
if ( m_pUsers != NULL )
|
|
{
|
|
MIDL_user_free( m_pUsers );
|
|
}
|
|
is = (NET_API_STATUS)~0;
|
|
}
|
|
|
|
if ( is != 0 )
|
|
{
|
|
m_pMapper->SetRequestStatus( HTR_USER_ENUM_ACCESS_ERROR );
|
|
}
|
|
}
|
|
|
|
return is == 0 ? TRUE : FALSE;
|
|
}
|
|
|
|
|
|
// User count
|
|
|
|
BOOL
|
|
CUserEnum::GetCount(
|
|
LPVOID* pV )
|
|
{
|
|
if ( InsureLoaded() )
|
|
{
|
|
*pV = (LPVOID)&m_dwCount;
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// User Name
|
|
|
|
BOOL
|
|
CUserEnum::GetName(
|
|
LPVOID* pV )
|
|
{
|
|
DWORD dwI = m_pMapper->GetIter();
|
|
|
|
if ( InsureLoaded() && dwI < m_dwCount )
|
|
{
|
|
*pV = (LPVOID)&m_pUsers[dwI].pszUser;
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// Is user logged-in as anonymous ?
|
|
|
|
BOOL
|
|
CUserEnum::GetAnonymous(
|
|
LPVOID* pV )
|
|
{
|
|
DWORD dwI = m_pMapper->GetIter();
|
|
|
|
if ( InsureLoaded() && dwI < m_dwCount )
|
|
{
|
|
*pV = (LPVOID)&m_pUsers[dwI].fAnonymous;
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// User IP address
|
|
|
|
BOOL
|
|
CUserEnum::GetAddr(
|
|
LPVOID* pV )
|
|
{
|
|
DWORD dwI = m_pMapper->GetIter();
|
|
|
|
if ( InsureLoaded() && dwI < m_dwCount )
|
|
{
|
|
*pV = (LPVOID)&m_pUsers[dwI].inetHost;
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CUserEnum::GetCountAsDWORD(
|
|
LPDWORD pDW )
|
|
{
|
|
if ( InsureLoaded() )
|
|
{
|
|
*pDW = m_dwCount;
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CUserEnum::GetIDAsDWORD(
|
|
LPDWORD pDW )
|
|
{
|
|
DWORD dwI = m_pMapper->GetIter();
|
|
|
|
if ( InsureLoaded() && dwI < m_dwCount )
|
|
{
|
|
*pDW = m_pUsers[dwI].idUser;
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// User connection time
|
|
|
|
BOOL
|
|
CUserEnum::GetTime(
|
|
LPVOID* pV )
|
|
{
|
|
DWORD dwI = m_pMapper->GetIter();
|
|
|
|
if ( InsureLoaded() && dwI < m_dwCount )
|
|
{
|
|
*pV = (LPVOID)&m_pUsers[dwI].tConnect;
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// User ID
|
|
|
|
BOOL
|
|
CUserEnum::GetID(
|
|
LPVOID* pV )
|
|
{
|
|
DWORD dwI = m_pMapper->GetIter();
|
|
|
|
if ( InsureLoaded() && dwI < m_dwCount )
|
|
{
|
|
*pV = (LPVOID)&m_pUsers[dwI].idUser;
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
///////////// Dynamic string class
|
|
|
|
CDStr::CDStr(
|
|
VOID )
|
|
{
|
|
Init();
|
|
}
|
|
|
|
|
|
CDStr::~CDStr(
|
|
VOID )
|
|
{
|
|
if ( m_pStr != NULL )
|
|
{
|
|
delete [] m_pStr;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
CDStr::Reset(
|
|
VOID )
|
|
{
|
|
if ( m_pStr != NULL )
|
|
{
|
|
delete [] m_pStr;
|
|
}
|
|
Init();
|
|
}
|
|
|
|
|
|
BOOL
|
|
CDStr::Init(
|
|
VOID )
|
|
{
|
|
m_pStr = NULL;
|
|
m_dwAlloc = m_dwLen = 0;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
LPSTR
|
|
CDStr::GetString(
|
|
VOID )
|
|
{
|
|
return m_pStr;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CDStr::Add(
|
|
LPSTR pS )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Add a sz string to a dynamic string
|
|
|
|
Arguments:
|
|
|
|
pS - string to add at the end of the dynamic string
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
return AddRange( pS, lstrlen( pS ) );
|
|
}
|
|
|
|
|
|
BOOL
|
|
CDStr::AddRange(
|
|
LPSTR pS,
|
|
DWORD dwL )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Add a character range to a dynamic string
|
|
|
|
Arguments:
|
|
|
|
pS - character range to add at the end of the dynamic string
|
|
dwL - # of characters to add
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
if ( m_dwLen + dwL + 1 > m_dwAlloc )
|
|
{
|
|
DWORD dwN = ( ( m_dwLen + dwL + 1 + 128 ) / 128 ) * 128;
|
|
LPSTR pN = new char[dwN];
|
|
if ( pN == NULL )
|
|
{
|
|
return FALSE;
|
|
}
|
|
if ( m_pStr != NULL )
|
|
{
|
|
memcpy( pN, m_pStr, m_dwLen );
|
|
delete [] m_pStr;
|
|
}
|
|
m_pStr = pN;
|
|
m_dwAlloc = dwN;
|
|
}
|
|
|
|
memcpy( m_pStr + m_dwLen, pS, dwL );
|
|
m_dwLen += dwL;
|
|
m_pStr[ m_dwLen ] = '\0';
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
#if defined(GENERATE_AUTH_HEADERS)
|
|
|
|
//
|
|
// This class handles the generation of the authentication sequence
|
|
// as a list of supported WWW-Authenticate scheme.
|
|
// This is necessary for IIS/1.0, not for IIS/1.1+
|
|
//
|
|
|
|
|
|
CAuthenticationReqs::CAuthenticationReqs(
|
|
VOID )
|
|
{
|
|
}
|
|
|
|
|
|
CAuthenticationReqs::~CAuthenticationReqs(
|
|
VOID )
|
|
{
|
|
}
|
|
|
|
|
|
DWORD
|
|
WINAPI AuthUpdateIndication(
|
|
LPVOID pV )
|
|
{
|
|
return ((CAuthenticationReqs*)pV)->UpdateIndication();
|
|
}
|
|
|
|
|
|
BOOL
|
|
CAuthenticationReqs::Init(
|
|
VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialize the authentication package, which provides a way
|
|
for an ISAPI app to retrieve the list of supported authentication
|
|
methods as a list of HTTP WWW-Authenticate headers.
|
|
build the initial authentication list, create a registry update
|
|
monitor thread to check for changes in supported authentication
|
|
methods.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
m_dsH.Init();
|
|
m_pszProviders = NULL;
|
|
INITIALIZE_CRITICAL_SECTION( &m_csR );
|
|
|
|
m_hNotifyEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
|
|
m_fRequestTerminate = FALSE;
|
|
|
|
if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
|
W3SVC_REGISTRY_PATH,
|
|
0,
|
|
KEY_READ,
|
|
&m_hKey ) == ERROR_SUCCESS )
|
|
{
|
|
// retrieve methods
|
|
UpdateMethodsIndication();
|
|
|
|
// retrieve NT list
|
|
UpdateNTAuthenticationProvidersIndication();
|
|
|
|
// create registry monitoring thread
|
|
DWORD dwID;
|
|
if ( (m_hThread = CreateThread( NULL,
|
|
0,
|
|
(LPTHREAD_START_ROUTINE)::AuthUpdateIndication,
|
|
(LPVOID)this,
|
|
0,
|
|
&dwID )) == NULL )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
return BuildListHeader();
|
|
}
|
|
else
|
|
{
|
|
m_hKey = NULL;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// wait for an update notification from the registry
|
|
//
|
|
|
|
DWORD
|
|
CAuthenticationReqs::UpdateIndication(
|
|
VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Thread monitoring authentication methods update in registry
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
NT error
|
|
|
|
--*/
|
|
{
|
|
for ( ;; )
|
|
{
|
|
if ( RegNotifyChangeKeyValue( m_hKey,
|
|
FALSE,
|
|
REG_NOTIFY_CHANGE_LAST_SET,
|
|
m_hNotifyEvent,
|
|
TRUE ) != ERROR_SUCCESS )
|
|
{
|
|
break;
|
|
}
|
|
if ( WaitForSingleObject( m_hNotifyEvent, INFINITE)
|
|
!= WAIT_OBJECT_0 )
|
|
{
|
|
break;
|
|
}
|
|
if ( m_fRequestTerminate )
|
|
{
|
|
break;
|
|
}
|
|
UpdateMethodsIndication();
|
|
UpdateNTAuthenticationProvidersIndication();
|
|
BuildListHeader();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CAuthenticationReqs::Terminate(
|
|
VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Request the monitoring thread to terminate
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE if thread successfully terminated, else FALSE
|
|
|
|
--*/
|
|
{
|
|
// request thread kill
|
|
m_fRequestTerminate = TRUE;
|
|
SetEvent( m_hNotifyEvent );
|
|
|
|
if ( m_hThread != NULL && WaitForSingleObject( m_hThread, 1000 * 3 )
|
|
== WAIT_OBJECT_0 )
|
|
{
|
|
CloseHandle( m_hThread );
|
|
m_hThread = NULL;
|
|
|
|
DeleteCriticalSection( &m_csR );
|
|
if ( m_pszProviders != NULL )
|
|
{
|
|
delete [] m_pszProviders;
|
|
}
|
|
if ( m_hKey != NULL )
|
|
{
|
|
RegCloseKey( m_hKey );
|
|
}
|
|
if ( m_hNotifyEvent != NULL )
|
|
{
|
|
CloseHandle( m_hNotifyEvent );
|
|
}
|
|
if ( m_hThread != NULL )
|
|
{
|
|
CloseHandle( m_hThread );
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CAuthenticationReqs::UpdateMethodsIndication(
|
|
VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Update bitmap of supported authentication methods
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE on success, else FALSE
|
|
|
|
--*/
|
|
{
|
|
BOOL fSt = FALSE;
|
|
|
|
Lock();
|
|
|
|
// access registry
|
|
DWORD dwType;
|
|
DWORD dwM;
|
|
DWORD cData = sizeof( dwM );
|
|
if ( RegQueryValueEx( m_hKey, W3SVC_REGISTRY_AUTHENTICATION,
|
|
NULL, &dwType, (PBYTE)&dwM, &cData ) == ERROR_SUCCESS
|
|
&& dwType == REG_DWORD )
|
|
{
|
|
fSt = TRUE;
|
|
m_dwMethods = dwM;
|
|
}
|
|
|
|
UnLock();
|
|
|
|
return fSt;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CAuthenticationReqs::BuildListHeader(
|
|
VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Build a list of HTTP headers specifying all authentication methods
|
|
supported by the local HTTP server in m_dsH
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
BOOL fAdded = FALSE;
|
|
|
|
Lock();
|
|
|
|
m_dsH.Reset();
|
|
|
|
if ( m_dwMethods & INET_INFO_AUTH_CLEARTEXT )
|
|
{
|
|
m_dsH.Add( WWW_AUTHENTICATE_HEADER );
|
|
m_dsH.Add( "Basic realm=\"NTSRV\"\r\n" );
|
|
fAdded = TRUE;
|
|
}
|
|
|
|
if ( (m_dwMethods & INET_INFO_AUTH_NT_AUTH)
|
|
&& m_pszProviders != NULL )
|
|
{
|
|
LPSTR pS, pT;
|
|
// iterate through comma-separated list
|
|
for ( pS = m_pszProviders ; *pS ; )
|
|
{
|
|
if ( (pT = strchr( pS, ',' )) == NULL )
|
|
{
|
|
pT = pS + lstrlen( pS );
|
|
}
|
|
m_dsH.Add( WWW_AUTHENTICATE_HEADER );
|
|
m_dsH.AddRange( pS, pT - pS );
|
|
m_dsH.Add( "\r\n" );
|
|
pS = *pT ? pT + 1 : pT;
|
|
fAdded = TRUE;
|
|
}
|
|
}
|
|
|
|
if ( fAdded )
|
|
{
|
|
m_dsH.Add( "\r\n" );
|
|
}
|
|
|
|
UnLock();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CAuthenticationReqs::UpdateNTAuthenticationProvidersIndication(
|
|
VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Update list of supported SSPI authentication methods
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
BOOL fSt = FALSE;
|
|
|
|
Lock();
|
|
|
|
if ( m_pszProviders != NULL )
|
|
{
|
|
delete [] m_pszProviders;
|
|
m_pszProviders = NULL;
|
|
}
|
|
|
|
// access registry
|
|
DWORD cData = 256;
|
|
DWORD dwType;
|
|
if ( (m_pszProviders = new char[cData]) != NULL )
|
|
{
|
|
if ( RegQueryValueEx( m_hKey,
|
|
W3SVC_REGISTRY_NTAUTHENTICATIONPROVIDERS,
|
|
NULL,
|
|
&dwType,
|
|
(PBYTE)m_pszProviders,
|
|
&cData ) == ERROR_SUCCESS
|
|
&& dwType == REG_SZ )
|
|
{
|
|
fSt = TRUE;
|
|
}
|
|
else
|
|
{
|
|
delete [] m_pszProviders;
|
|
m_pszProviders = NULL;
|
|
}
|
|
}
|
|
|
|
UnLock();
|
|
|
|
return fSt;
|
|
}
|
|
|
|
|
|
LPSTR
|
|
CAuthenticationReqs::GetAuthenticationListHeader(
|
|
VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Return the list of supported authentication
|
|
methods as a list of HTTP WWW-Authenticate headers.
|
|
The returned string is either empty or terminated by
|
|
a blank line.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
return m_dsH.GetString();
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
///////////// Mapper
|
|
|
|
CInetInfoConfigInfoMapper::CInetInfoConfigInfoMapper(
|
|
VOID )
|
|
{
|
|
}
|
|
|
|
|
|
CInetInfoConfigInfoMapper::~CInetInfoConfigInfoMapper(
|
|
VOID )
|
|
{
|
|
#if !defined(IISv1)
|
|
if ( m_pServerCaps != NULL )
|
|
{
|
|
MIDL_user_free( m_pServerCaps );
|
|
}
|
|
#endif
|
|
DeleteCriticalSection( &m_csLock );
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::Init(
|
|
CInetInfoMap* pMap,
|
|
int cNbMap,
|
|
DWORD dwS )
|
|
{
|
|
INITIALIZE_CRITICAL_SECTION( &m_csLock );
|
|
m_pMap = pMap;
|
|
m_cNbMap = cNbMap;
|
|
m_dwCurrentServerType = dwS;
|
|
|
|
m_pGlobalConfig = NULL;
|
|
m_pConfig = NULL;
|
|
m_pServerCaps = NULL;
|
|
m_pW3Config = NULL;
|
|
m_pFtpConfig = NULL;
|
|
m_pGdConfig = NULL;
|
|
|
|
m_pFirstAlloc = m_pLastAlloc = NULL;
|
|
|
|
m_fGotServerCapsAndVersion = FALSE;
|
|
|
|
m_pszHtmlaPath = g_achHtmlaPath;
|
|
m_pszHostName = m_achHostName;
|
|
m_pszW3Version = g_achW3Version;
|
|
m_pszRPCStatusString = NULL;
|
|
m_fAllocatedRPCStatusString = FALSE;
|
|
|
|
m_Users.Init( this );
|
|
m_Drive.Init( this );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
// variables access
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::GlobalIsBandwidthLimited(
|
|
LPVOID* pV )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Update a pointer to the virtual variable exposing the
|
|
"global bandwidth is limited" setting.
|
|
HTMLA var: "globalisbandwidthlimited"
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
if ( m_pGlobalConfig != NULL )
|
|
{
|
|
m_dwIsBandwidthLimited = m_pGlobalConfig->BandwidthLevel
|
|
!= DWORD(-1) ? TRUE : FALSE;
|
|
*pV = (LPVOID)&m_dwIsBandwidthLimited;
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
void
|
|
CInetInfoConfigInfoMapper::AdjustFromIPSingle(
|
|
LPBYTE pMsk )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Adjust network mask to be consistent
|
|
with the virtual var controlling if this entry is for
|
|
a single address or not.
|
|
If single address the mask if set to all 1 ( i.e. the whole
|
|
network address is significant ).
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
if ( m_dwIsIPSingle == 1 )
|
|
{
|
|
memset( pMsk, 0xff, IP_ADDR_BYTE_SIZE );
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
CInetInfoConfigInfoMapper::AdjustIPSingle(
|
|
LPBYTE pMsk )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determine if the mask describes a single IP address ( i.e. is all 1 )
|
|
and updates the virtual var controlling 'singleness' accordingly
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
m_dwIsIPSingle = 0;
|
|
for ( int x = 0 ; x < IP_ADDR_BYTE_SIZE ; ++x )
|
|
{
|
|
if ( pMsk[x] != 0xff )
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
m_dwIsIPSingle = 1;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::DenyIsIPSingle(
|
|
LPVOID* pV )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Adjust the virtual variable to be TRUE if the current entry
|
|
in the IP deny access list is a single address, otherwise FALSE.
|
|
Update a pointer to this virtual variable on exit.
|
|
HTMLA var: "denyisipsingle"
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
if ( m_pConfig!=NULL && m_pConfig->DenyIPList
|
|
&& m_iIter < m_pConfig->DenyIPList->cEntries )
|
|
{
|
|
AdjustIPSingle( (LPBYTE)&m_pConfig->DenyIPList
|
|
->aIPSecEntry[m_iIter].dwMask );
|
|
*pV = (LPVOID)&m_dwIsIPSingle;
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::GrantIsIPSingle(
|
|
LPVOID* pV )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Adjust the virtual variable to be TRUE if the current entry
|
|
in the IP grant access list is a single address, otherwise FALSE.
|
|
Update a pointer to this virtual variable on exit.
|
|
HTMLA var: "grantisipsingle"
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
if ( m_pConfig!=NULL && m_pConfig->GrantIPList
|
|
&& m_iIter < m_pConfig->GrantIPList->cEntries )
|
|
{
|
|
AdjustIPSingle( (LPBYTE)&m_pConfig->GrantIPList
|
|
->aIPSecEntry[m_iIter].dwMask );
|
|
*pV = (LPVOID)&m_dwIsIPSingle;
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::DirBrowseEnab(
|
|
LPVOID *pV )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Update a pointer to the virtual variable exposing the
|
|
"directory browsing enabled" setting.
|
|
HTMLA var: "w3dirbrowseenabled"
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
if ( m_pW3Config != NULL )
|
|
{
|
|
m_DirBrowseEnab = (m_pW3Config->dwDirBrowseControl&DIRBROW_ENABLED)
|
|
? TRUE : FALSE;
|
|
*pV = &m_DirBrowseEnab;
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::DefFileEnab(
|
|
LPVOID *pV )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Update a pointer to the virtual variable exposing the
|
|
"default file enabled" setting.
|
|
HTMLA var: "w3defaultfileenabled"
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
if ( m_pW3Config != NULL )
|
|
{
|
|
m_DefFileEnab = (m_pW3Config->dwDirBrowseControl&DIRBROW_LOADDEFAULT)
|
|
? TRUE : FALSE;
|
|
*pV = &m_DefFileEnab;
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::SetRootEntryVars(
|
|
VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set virtual vars exposing various properties of the current
|
|
virtual root entry :
|
|
Home status, read, write, exec, SSL required
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
if ( m_fInvEntry )
|
|
{
|
|
if ( m_pConfig->VirtualRoots->aVirtRootEntry[m_iIter].pszRoot
|
|
!= NULL )
|
|
{
|
|
m_fRootIsHome = !wcscmp(
|
|
m_pConfig->VirtualRoots->aVirtRootEntry[m_iIter].pszRoot,
|
|
HOME_DIR_PATH ) ? TRUE : FALSE;
|
|
}
|
|
else
|
|
{
|
|
m_fRootIsHome = FALSE;
|
|
}
|
|
|
|
m_fRootIsRead =
|
|
(m_pConfig->VirtualRoots->aVirtRootEntry[m_iIter].dwMask
|
|
& VROOT_MASK_READ) ? TRUE : FALSE;
|
|
|
|
m_fRootIsWrite =
|
|
(m_pConfig->VirtualRoots->aVirtRootEntry[m_iIter].dwMask
|
|
& VROOT_MASK_WRITE) ? TRUE : FALSE;
|
|
|
|
m_fRootIsExec =
|
|
(m_pConfig->VirtualRoots->aVirtRootEntry[m_iIter].dwMask
|
|
& VROOT_MASK_EXECUTE) ? TRUE : FALSE;
|
|
|
|
m_fRootIsSSL =
|
|
(m_pConfig->VirtualRoots->aVirtRootEntry[m_iIter].dwMask
|
|
& VROOT_MASK_SSL) ? TRUE : FALSE;
|
|
|
|
m_fInvEntry = TRUE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::RootIsHome(
|
|
LPVOID *pV )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Update a pointer to the virtual variable exposing the
|
|
"current virtual root is home" setting.
|
|
HTMLA var: rootishome
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
if ( m_pConfig != NULL && m_pConfig->VirtualRoots
|
|
&& m_iIter < m_pConfig->VirtualRoots->cEntries )
|
|
{
|
|
// must call set vars, cannot make any assumptions about
|
|
// current virtual root entry
|
|
|
|
SetRootEntryVars();
|
|
*pV = &m_fRootIsHome;
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::RootName(
|
|
LPVOID *pV )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Update a pointer to the name of the current virtual root entry
|
|
HTMLA var: "rootname"
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
if ( m_pConfig!=NULL && m_pConfig->VirtualRoots
|
|
&& m_iIter < m_pConfig->VirtualRoots->cEntries )
|
|
{
|
|
*pV = (LPVOID)&m_pConfig->VirtualRoots
|
|
->aVirtRootEntry[m_iIter].pszRoot;
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::RootIsRead(
|
|
LPVOID *pV )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Update a pointer to the virtual variable exposing the
|
|
"current virtual root has read access" setting.
|
|
HTMLA var: "rootisread"
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
if ( m_pConfig != NULL
|
|
&& m_pConfig->VirtualRoots
|
|
&& m_iIter < m_pConfig->VirtualRoots->cEntries )
|
|
{
|
|
// must call set vars, cannot make any assumptions about
|
|
// current virtual root entry
|
|
|
|
SetRootEntryVars();
|
|
*pV = &m_fRootIsRead;
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::RootIsWrite(
|
|
LPVOID *pV )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Update a pointer to the virtual variable exposing the
|
|
"current virtual root has write access" setting.
|
|
HTMLA var: "rootiswrite"
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
if ( m_pConfig != NULL
|
|
&& m_pConfig->VirtualRoots
|
|
&& m_iIter < m_pConfig->VirtualRoots->cEntries )
|
|
{
|
|
// must call set vars, cannot make any assumptions about
|
|
// current virtual root entry
|
|
|
|
SetRootEntryVars();
|
|
*pV = &m_fRootIsWrite;
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::RootIsExec(
|
|
LPVOID *pV )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Update a pointer to the virtual variable exposing the
|
|
"current virtual root has execute access" setting.
|
|
HTMLA var: "rootisexec"
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
if ( m_pConfig != NULL
|
|
&& m_pConfig->VirtualRoots
|
|
&& m_iIter < m_pConfig->VirtualRoots->cEntries )
|
|
{
|
|
// must call set vars, cannot make any assumptions about
|
|
// current virtual root entry
|
|
|
|
SetRootEntryVars();
|
|
*pV = &m_fRootIsExec;
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::RootIsSSL(
|
|
LPVOID *pV )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Update a pointer to the virtual variable exposing the
|
|
"current virtual root requires SSL access" setting.
|
|
HTMLA var: "rootisssl"
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
if ( m_pConfig != NULL
|
|
&& m_pConfig->VirtualRoots
|
|
&& m_iIter < m_pConfig->VirtualRoots->cEntries )
|
|
{
|
|
// must call set vars, cannot make any assumptions about
|
|
// current virtual root entry
|
|
|
|
SetRootEntryVars();
|
|
*pV = &m_fRootIsSSL;
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::AuthAnon(
|
|
LPVOID *pV )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Update a pointer to the virtual variable exposing the
|
|
enable anonymous access setting.
|
|
HTMLA var: "authanon"
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
if ( m_pConfig != NULL )
|
|
{
|
|
m_fAuthAnon = m_pConfig->dwAuthentication&INET_INFO_AUTH_ANONYMOUS
|
|
? TRUE : FALSE;
|
|
*pV = &m_fAuthAnon;
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::AuthBasic(
|
|
LPVOID *pV )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Update a pointer to the virtual variable exposing the
|
|
enable basic ( clear text password ) access setting.
|
|
HTMLA var: "authbasic"
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
if ( m_pConfig != NULL )
|
|
{
|
|
m_fAuthBasic = m_pConfig->dwAuthentication&INET_INFO_AUTH_CLEARTEXT
|
|
? TRUE : FALSE;
|
|
*pV = &m_fAuthBasic;
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::AuthNT(
|
|
LPVOID *pV )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Update a pointer to the virtual variable exposing the
|
|
enable NTLM based authentication access setting.
|
|
HTMLA var: "authnt"
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
if ( m_pConfig != NULL )
|
|
{
|
|
m_fAuthNT = m_pConfig->dwAuthentication&INET_INFO_AUTH_NT_AUTH
|
|
? TRUE : FALSE;
|
|
*pV = &m_fAuthNT;
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::EnableLog(
|
|
LPVOID *pV )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Update a pointer to the virtual variable exposing the
|
|
enable log setting.
|
|
HTMLA var: "enablelog"
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
if ( m_pConfig != NULL )
|
|
{
|
|
m_fEnableLog = m_pConfig->lpLogConfig->inetLogType
|
|
? TRUE : FALSE;
|
|
*pV = &m_fEnableLog;
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::EnableNewLog(
|
|
LPVOID *pV )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Update a pointer to the virtual variable exposing the
|
|
enable new log file creation setting.
|
|
HTMLA var: "enablenewlog"
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
if ( m_pConfig != NULL )
|
|
{
|
|
m_fEnableNewLog = m_dwLogPeriod ? TRUE : FALSE;
|
|
*pV = &m_fEnableNewLog;
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// Update indication for variables
|
|
// These functions are called AFTER the script updated the
|
|
// corresponding variable.
|
|
//
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::UpdateGlobalIsBandwidthLimited(
|
|
VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Adjust bandwidth limit to be consistent
|
|
with setting controlling whether bandwidth is limited.
|
|
HTMLA var: "globalisbandwidthlimited"
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
if ( m_pGlobalConfig != NULL )
|
|
{
|
|
if ( m_dwIsBandwidthLimited == 0 )
|
|
m_pGlobalConfig->BandwidthLevel = DWORD(-1);
|
|
SetField( m_pGlobalConfig->FieldControl, FC_GINET_INFO_ALL );
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::UpdateGlobalBandwidth(
|
|
VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Adjust bandwidth limit to be consistent
|
|
with the virtual var controlling whether bandwidth is limited.
|
|
This assumes that the virtual var "globalisbandwidthlimited" appears
|
|
BEFORE the "globalbandwidth" variable.
|
|
HTMLA var: "globalbandwidth"
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
if ( m_pGlobalConfig != NULL )
|
|
{
|
|
if ( m_dwIsBandwidthLimited == 0 )
|
|
{
|
|
m_pGlobalConfig->BandwidthLevel = DWORD(-1);
|
|
}
|
|
SetField( m_pGlobalConfig->FieldControl, FC_GINET_INFO_ALL );
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::UpdateDenyIsIPSingle(
|
|
VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Adjust network mask for Deny IP access list to be consistent
|
|
with the virtual var controlling if this entry is for
|
|
a single address or not.
|
|
This assumes that the virtual var "denyisipsingle" appears
|
|
BEFORE the "denyipmask" variable.
|
|
HTMLA var: "denyisipsingle"
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
if ( m_pConfig!=NULL
|
|
&& m_pConfig->DenyIPList
|
|
&& m_iIter < m_pConfig->DenyIPList->cEntries )
|
|
{
|
|
AdjustFromIPSingle( (LPBYTE)&m_pConfig->DenyIPList
|
|
->aIPSecEntry[m_iIter].dwMask );
|
|
UpdateIP();
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::UpdateGrantIsIPSingle(
|
|
VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Adjust network mask for Grant IP access list to be consistent
|
|
with the virtual var controlling if this entry is for
|
|
a single address or not.
|
|
This assumes that the virtual var "grantisipsingle" appears
|
|
BEFORE the "grantipmask" variable.
|
|
HTMLA var: "grantisipsingle"
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
if ( m_pConfig!=NULL
|
|
&& m_pConfig->GrantIPList
|
|
&& m_iIter < m_pConfig->GrantIPList->cEntries )
|
|
{
|
|
AdjustFromIPSingle( (LPBYTE)&m_pConfig->GrantIPList
|
|
->aIPSecEntry[m_iIter].dwMask );
|
|
UpdateIP();
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::UpdateDirControl(
|
|
VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Synchronize virtual vars updated by the user request
|
|
for directory attributes ( browsing, use default file )
|
|
and RPC structures.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
if ( m_DirBrowseEnab )
|
|
{
|
|
m_pW3Config->dwDirBrowseControl |= DIRBROW_ENABLED;
|
|
}
|
|
else
|
|
{
|
|
m_pW3Config->dwDirBrowseControl &= ~DIRBROW_ENABLED;
|
|
}
|
|
|
|
if ( m_DefFileEnab )
|
|
{
|
|
m_pW3Config->dwDirBrowseControl |= DIRBROW_LOADDEFAULT;
|
|
}
|
|
else
|
|
{
|
|
m_pW3Config->dwDirBrowseControl &= ~DIRBROW_LOADDEFAULT;
|
|
}
|
|
|
|
SetField( m_pW3Config->FieldControl, FC_W3_DIR_BROWSE_CONTROL );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::UpdateRootName(
|
|
VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Synchronize virtual vars updated by the user request
|
|
for virtual root name ( name, home directory or not )
|
|
and RPC structures.
|
|
It assumes that the 'homeness' status of this virtual root
|
|
is determined BEFORE the name, i.e. that the 'home' setting
|
|
appears before the virtual root name in the HTMLA form
|
|
|
|
The user setting will be overidden if the virtual root is home
|
|
In this case, the virtual root name will be set to HOME_DIR_PATH
|
|
|
|
HTMLA var: "rootname"
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
BOOL fSt = TRUE;
|
|
|
|
if ( UpdateRoot() )
|
|
{
|
|
if ( m_fRootIsHome )
|
|
{
|
|
LPWSTR pszRoot = (LPWSTR)Alloc( (wcslen( HOME_DIR_PATH ) + 1)
|
|
* sizeof(WCHAR) );
|
|
if ( pszRoot == NULL )
|
|
{
|
|
fSt = FALSE;
|
|
}
|
|
else
|
|
{
|
|
wcscpy( pszRoot, HOME_DIR_PATH );
|
|
m_pConfig->VirtualRoots->aVirtRootEntry[m_iIter]
|
|
.pszRoot = pszRoot;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LPWSTR pszR = m_pConfig->VirtualRoots->aVirtRootEntry[m_iIter].pszRoot;
|
|
if ( pszR[0] == L'\0' || !wcscmp( L"/", pszR ) )
|
|
{
|
|
// no name was specified, auto-alias
|
|
fSt = AliasVirtDir( m_pConfig->VirtualRoots
|
|
->aVirtRootEntry + m_iIter );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fSt = FALSE;
|
|
}
|
|
|
|
return fSt;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::UpdateRootMask(
|
|
VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Synchronize virtual vars updated by the user request
|
|
for directory attributes ( read, execute, SSL required )
|
|
and RPC structures.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
if ( m_pConfig != NULL && m_iIter < m_pConfig->VirtualRoots->cEntries )
|
|
{
|
|
DWORD dwMsk = m_pConfig->VirtualRoots->aVirtRootEntry[m_iIter].dwMask;
|
|
|
|
if ( m_fRootIsRead )
|
|
{
|
|
dwMsk |= VROOT_MASK_READ;
|
|
}
|
|
else
|
|
{
|
|
dwMsk &= ~VROOT_MASK_READ;
|
|
}
|
|
|
|
if ( m_fRootIsWrite )
|
|
{
|
|
dwMsk |= VROOT_MASK_WRITE;
|
|
}
|
|
else
|
|
{
|
|
dwMsk &= ~VROOT_MASK_WRITE;
|
|
}
|
|
|
|
if ( m_fRootIsExec )
|
|
{
|
|
dwMsk |= VROOT_MASK_EXECUTE;
|
|
}
|
|
else
|
|
{
|
|
dwMsk &= ~VROOT_MASK_EXECUTE;
|
|
}
|
|
|
|
if ( m_fRootIsSSL )
|
|
{
|
|
dwMsk |= VROOT_MASK_SSL;
|
|
}
|
|
else
|
|
{
|
|
dwMsk &= ~VROOT_MASK_SSL;
|
|
}
|
|
|
|
m_pConfig->VirtualRoots->aVirtRootEntry[m_iIter].dwMask = dwMsk;
|
|
|
|
SetField( m_pConfig->FieldControl, FC_INET_INFO_VIRTUAL_ROOTS );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::UpdateAuth(
|
|
VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Synchronize virtual vars updated by the user request
|
|
for supported authetication methods ( anon, clear text, NTLMSSP )
|
|
and RPC structures.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
if ( m_pConfig != NULL )
|
|
{
|
|
DWORD dwMsk = m_pConfig->dwAuthentication;
|
|
|
|
if ( m_fAuthAnon )
|
|
{
|
|
dwMsk |= INET_INFO_AUTH_ANONYMOUS;
|
|
}
|
|
else
|
|
{
|
|
dwMsk &= ~INET_INFO_AUTH_ANONYMOUS;
|
|
}
|
|
|
|
if ( m_fAuthBasic )
|
|
{
|
|
dwMsk |= INET_INFO_AUTH_CLEARTEXT;
|
|
}
|
|
else
|
|
{
|
|
dwMsk &= ~INET_INFO_AUTH_CLEARTEXT;
|
|
}
|
|
|
|
if ( m_fAuthNT )
|
|
{
|
|
dwMsk |= INET_INFO_AUTH_NT_AUTH;
|
|
}
|
|
else
|
|
{
|
|
dwMsk &= ~INET_INFO_AUTH_NT_AUTH;
|
|
}
|
|
|
|
m_pConfig->dwAuthentication = dwMsk;
|
|
|
|
SetField( m_pConfig->FieldControl, FC_INET_INFO_AUTHENTICATION );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::UpdateLog(
|
|
VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Acknowledge update to log settings
|
|
( dummy entry, no action for now )
|
|
HTMLA var: "enablelog"
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE
|
|
|
|
--*/
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::UpdateNewLog(
|
|
VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Insure consistency between user request ( new log enabled,
|
|
log period ) and RPC structures.
|
|
This assumes that enable new Log type is updated BEFORE the log period
|
|
setting, i.e. it appears before this setting in the
|
|
HTMLA form.
|
|
HTMLA var: "enablenewlog"
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
if ( m_pConfig != NULL )
|
|
{
|
|
if ( !m_fEnableNewLog )
|
|
{
|
|
if ( INET_LOG_PERIOD_NONE
|
|
!= m_pConfig->lpLogConfig->ilPeriod )
|
|
{
|
|
m_dwLogPeriod
|
|
= m_pConfig->lpLogConfig->ilPeriod
|
|
= INET_LOG_PERIOD_NONE;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::UpdateLogType(
|
|
VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Insure consistency between user request ( log enabled,
|
|
log type ) and RPC structures.
|
|
This assumes that Log type is updated AFTER the log enabled
|
|
setting, i.e. it appears after this setting in the
|
|
HTMLA form.
|
|
HTMLA var : "logtype"
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
if ( m_pConfig != NULL )
|
|
{
|
|
if ( !m_fEnableLog )
|
|
{
|
|
m_pConfig->lpLogConfig->inetLogType
|
|
= INET_LOG_DISABLED;
|
|
}
|
|
if ( m_dwWasLogType != m_pConfig->lpLogConfig->inetLogType )
|
|
{
|
|
SetField( m_pConfig->FieldControl, FC_INET_INFO_LOG_CONFIG );
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::SetLogEntryVars(
|
|
VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Update virtual vars needed by the log settings, such as
|
|
the log period. Virtual vars are needed to expose the log type
|
|
as a single value, in contrast with the RPC struct definition
|
|
where multiple variables are used to encode this information
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
m_dwLogPeriod = m_pConfig->lpLogConfig->ilPeriod;
|
|
m_dwLogFormat = *((DWORD UNALIGNED *)&(m_pConfig->lpLogConfig->rgchDataSource[MAX_PATH-sizeof(DWORD)]));
|
|
|
|
if ( m_pConfig->lpLogConfig->inetLogType
|
|
&& m_dwLogPeriod == INET_LOG_PERIOD_NONE
|
|
&& m_pConfig->lpLogConfig->cbSizeForTruncation
|
|
!= (DWORD)-1 )
|
|
{
|
|
m_dwLogPeriod = INET_LOG_PERIOD_ON_SIZE;
|
|
}
|
|
|
|
m_dwInvalidLogUpdate = 0;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::LogPeriod(
|
|
LPVOID *pV )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Update a pointer to the virtual variable exposing the
|
|
log period. In addition to the RPC definition for log period
|
|
we support a new log period defined as "create new log when size
|
|
reaches xxx"
|
|
HTMLA var: "logperiod"
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
if ( m_pConfig!= NULL )
|
|
{
|
|
*pV = &m_dwLogPeriod;
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::LogFormat(
|
|
LPVOID *pV )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Update a pointer to the virtual variable exposing the
|
|
log format.
|
|
HTMLA var: "logformat"
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
if ( m_pConfig!= NULL )
|
|
{
|
|
*pV = &m_dwLogFormat;
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::UpdateLogPeriod(
|
|
VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Insure consistency between user request ( log enabled, new log
|
|
enabled, create new log based on size, log period ) and
|
|
RPC structures.
|
|
This assumes that Log period is updated AFTER the log enabled & new
|
|
log enabled settings, i.e. it appears after these settings in the
|
|
HTMLA form.
|
|
HTMLA var: "logperiod"
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
BOOL fUp = FALSE;
|
|
|
|
if ( m_pConfig != NULL )
|
|
{
|
|
DWORD dwN;
|
|
|
|
// check disabled or set to open on file size
|
|
if ( !m_fEnableLog
|
|
|| !m_fEnableNewLog
|
|
|| m_dwLogPeriod == INET_LOG_PERIOD_ON_SIZE )
|
|
{
|
|
dwN = INET_LOG_PERIOD_NONE;
|
|
}
|
|
else
|
|
{
|
|
if ( 0 == (dwN = m_dwLogPeriod) )
|
|
{
|
|
if ( m_fEnableLog && m_fEnableNewLog )
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
m_pConfig->lpLogConfig->cbSizeForTruncation
|
|
= 0;
|
|
}
|
|
|
|
if ( dwN != m_pConfig->lpLogConfig->ilPeriod )
|
|
{
|
|
m_pConfig->lpLogConfig->ilPeriod = dwN;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::UpdateLogFormat(
|
|
VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Insure consistency between user request ( log enabled, new log
|
|
enabled, create new log based on size, log period ) and
|
|
RPC structures.
|
|
HTMLA var: "logformat"
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
BOOL fUp = FALSE;
|
|
|
|
if ( m_pConfig != NULL )
|
|
{
|
|
if ((*(DWORD UNALIGNED*)&(m_pConfig->lpLogConfig->rgchDataSource[MAX_PATH-sizeof(DWORD)])) != m_dwLogFormat )
|
|
{
|
|
(*(DWORD UNALIGNED*)&(m_pConfig->lpLogConfig->rgchDataSource[MAX_PATH-sizeof(DWORD)])) = m_dwLogFormat;
|
|
UpdateLogFileInfo();
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::UpdateLogSize(
|
|
VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Insure consistency between user request ( log enabled, new log
|
|
enabled, create new log based on size, log size ) and
|
|
RPC structures.
|
|
This assumes that Log size is updated AFTER the log enabled, new
|
|
log enabled & log period settings, i.e. it appears after these
|
|
settings in the HTMLA form.
|
|
HTMLA var: "logsize"
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
if ( m_pConfig != NULL )
|
|
{
|
|
if ( !m_fEnableNewLog )
|
|
{
|
|
m_pConfig->lpLogConfig->cbSizeForTruncation
|
|
= (DWORD)-1;
|
|
return TRUE;
|
|
}
|
|
else if ( m_dwLogPeriod != INET_LOG_PERIOD_ON_SIZE )
|
|
{
|
|
// restore original log size if not currently creating
|
|
// new file on size
|
|
|
|
if ( m_pConfig->lpLogConfig->cbSizeForTruncation
|
|
!= m_dwWasSizeForTruncation
|
|
&& m_pConfig->lpLogConfig->cbSizeForTruncation
|
|
!= 0 )
|
|
{
|
|
m_pConfig->lpLogConfig->cbSizeForTruncation
|
|
= m_dwWasSizeForTruncation;
|
|
m_dwInvalidLogUpdate = INET_LOG_INVALID_TO_FILE;
|
|
}
|
|
else
|
|
{
|
|
m_pConfig->lpLogConfig->cbSizeForTruncation
|
|
= m_dwWasSizeForTruncation;
|
|
}
|
|
}
|
|
else if ( (int)m_pConfig->lpLogConfig->cbSizeForTruncation
|
|
< 1
|
|
&& m_pConfig->lpLogConfig->inetLogType
|
|
== INET_LOG_TO_FILE )
|
|
{
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
UpdateLogInfo();
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::InvalidLogUpdate(
|
|
LPVOID *pV )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Check for invalid changes requested by user to the log settings
|
|
and returns a numeric value indicating what invalid change was made
|
|
|
|
Arguments:
|
|
|
|
pV - pointer to DWORD where to put invalid change status
|
|
can be updated with INET_LOG_TO_FILE if invalid change made
|
|
to the file log settings, INET_LOG_TO_SQL if invalid changes
|
|
to the ODBC log settings, or 0 if no invalid change.
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
if ( m_pConfig->lpLogConfig->ilPeriod != m_dwWasLogPeriod
|
|
|| (m_pConfig->lpLogConfig->cbSizeForTruncation
|
|
!= m_dwWasSizeForTruncation
|
|
&& (m_pConfig->lpLogConfig->ilPeriod
|
|
!= INET_LOG_PERIOD_NONE || m_pConfig->lpLogConfig->cbSizeForTruncation==(DWORD)-1)) )
|
|
{
|
|
if ( m_pConfig->lpLogConfig->cbSizeForTruncation
|
|
== (DWORD)-1 && m_dwWasSizeForTruncation == 0)
|
|
{
|
|
// does not consider it as invalid log to file
|
|
// if in ODBC mode
|
|
UpdateLogInfo();
|
|
}
|
|
else
|
|
{
|
|
UpdateLogFileInfo();
|
|
}
|
|
}
|
|
|
|
if ( !m_fEnableLog
|
|
&& !m_dwWasLogType
|
|
&& (m_fLogFileUpdate || m_fLogODBCUpdate ) )
|
|
{
|
|
m_dwInvalidLogUpdate = INET_LOG_INVALID_TO_FILE;
|
|
}
|
|
|
|
if ( m_pConfig->lpLogConfig->inetLogType
|
|
== INET_LOG_TO_SQL
|
|
&& m_fLogFileUpdate )
|
|
{
|
|
m_dwInvalidLogUpdate = INET_LOG_TO_FILE;
|
|
}
|
|
else if ( m_pConfig->lpLogConfig->inetLogType
|
|
== INET_LOG_TO_FILE
|
|
&& m_fLogODBCUpdate )
|
|
{
|
|
m_dwInvalidLogUpdate = INET_LOG_TO_SQL;
|
|
}
|
|
|
|
*pV = (LPVOID)&m_dwInvalidLogUpdate;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::UpdateLogFileInfo(
|
|
VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Mark the log to file settings as updated by the user
|
|
This will be used to check for invalid log updates
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
m_fLogFileUpdate = TRUE;
|
|
|
|
return UpdateLogInfo();
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::UpdateLogODBCInfo(
|
|
VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Mark the log to ODBC settings as updated by the user
|
|
This will be used to check for invalid log updates
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
m_fLogODBCUpdate = TRUE;
|
|
|
|
return UpdateLogInfo();
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::IPDenyRef(
|
|
LPVOID *pV )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Builds a reference to the current IP element in the deny access list
|
|
|
|
Arguments:
|
|
|
|
pV - LPSTR** to be updated with the address of the LPSTR that will
|
|
contains the reference as a sz string
|
|
HTMLA var: "ipdenyref"
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
return IPRef( pV, m_pConfig->DenyIPList, &m_pDenyRef );
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::IPGrantRef(
|
|
LPVOID *pV )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Builds a reference to the current IP element in the grant access list
|
|
|
|
Arguments:
|
|
|
|
pV - LPSTR** to be updated with the address of the LPSTR that will
|
|
contains the reference as a sz string
|
|
HTMLA var: "ipgrantref"
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
return IPRef( pV, m_pConfig->GrantIPList, &m_pGrantRef );
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::IPRef(
|
|
LPVOID *pV,
|
|
INET_INFO_IP_SEC_LIST* pL,
|
|
LPSTR* pS )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
build a reference to the current IP element in the specified list
|
|
|
|
Arguments:
|
|
|
|
pV - LPSTR** to be updated with the address of the LPSTR that will
|
|
contains the reference as a sz string
|
|
pL - pointer to the a IP access list, to be indexed with the current
|
|
value of the <%beginiteration%> construct : m_iIter
|
|
pS - LPSTR* updated with the address of the generated
|
|
reference
|
|
|
|
WARNING:
|
|
|
|
Must be in sync with BuildIPUniqueID()
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
if ( m_pConfig != NULL && pL && m_iIter < pL->cEntries )
|
|
{
|
|
// get ASCII format of IP address & mask
|
|
LPSTR pN = IPToMultiByte(
|
|
(LPBYTE)&pL->aIPSecEntry[m_iIter].dwNetwork );
|
|
LPSTR pM = IPToMultiByte(
|
|
(LPBYTE)&pL->aIPSecEntry[m_iIter].dwMask );
|
|
if ( pN == NULL || pM == NULL )
|
|
{
|
|
SetRequestStatus( HTR_OUT_OF_RESOURCE );
|
|
return FALSE;
|
|
}
|
|
|
|
// build IP ref string
|
|
LPSTR pR = (LPSTR)Alloc( lstrlen(pN)
|
|
+ sizeof(REF_SEP_STR)-1
|
|
+ lstrlen(pM)
|
|
+ 1 );
|
|
if ( pR == NULL )
|
|
{
|
|
return FALSE;
|
|
}
|
|
lstrcpy( pR, pN );
|
|
lstrcat( pR, REF_SEP_STR );
|
|
lstrcat( pR, pM );
|
|
|
|
*pS = pR;
|
|
*pV = (LPVOID*)pS;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::RootRef(
|
|
LPVOID *pV )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
build a reference to the current virtual root element
|
|
HTMLA var: "rootref"
|
|
|
|
Arguments:
|
|
|
|
pV - LPSTR** to be updated with the address of the LPSTR that will
|
|
contains the reference as a sz string
|
|
|
|
WARNING:
|
|
|
|
must be in sync with BuildVirtDirUniqueID()
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
if ( m_pConfig != NULL && m_pConfig->VirtualRoots && m_iIter < m_pConfig->VirtualRoots->cEntries )
|
|
{
|
|
INET_INFO_VIRTUAL_ROOT_ENTRY* pE
|
|
= &m_pConfig->VirtualRoots->aVirtRootEntry[m_iIter];
|
|
size_t lR = wcslen( pE->pszRoot );
|
|
size_t lD = wcslen( pE->pszDirectory );
|
|
size_t lA = wcslen( pE->pszAddress );
|
|
LPSTR pR = (LPSTR)Alloc( lR*2 + 1 + lD*2 +1 + lA*2 + 1);
|
|
if ( pR == NULL )
|
|
{
|
|
return FALSE;
|
|
}
|
|
DWORD dwLr, dwLd, dwLa;
|
|
// contains Root SEP Directory SEP Address
|
|
if ( (dwLr=lR)==0 || (dwLr = WideCharToMultiByte( CP_ACP,
|
|
0,
|
|
pE->pszRoot,
|
|
lR,
|
|
pR,
|
|
lR*2,
|
|
NULL,
|
|
NULL )) != 0 )
|
|
{
|
|
pR[dwLr] = REF_SEP;
|
|
if ( (dwLd=lD)==0 || (dwLd = WideCharToMultiByte( CP_ACP,
|
|
0,
|
|
pE->pszDirectory,
|
|
lD,
|
|
pR+dwLr+1,
|
|
lD*2,
|
|
NULL,
|
|
NULL )) != 0 )
|
|
{
|
|
pR[dwLr+1+dwLd] = REF_SEP;
|
|
if ( (dwLa=lA)==0 || (dwLa = WideCharToMultiByte( CP_ACP,
|
|
0,
|
|
pE->pszAddress,
|
|
lA,
|
|
pR+dwLr+1+dwLd+1,
|
|
lA*2,
|
|
NULL,
|
|
NULL )) != 0 )
|
|
{
|
|
pR[dwLr+1+dwLd+1+dwLa] = '\0';
|
|
m_pRootRef = pR;
|
|
*pV = (LPVOID*)&m_pRootRef;
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::CryptCapable(
|
|
LPVOID *pV
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Return status on availability of encryption capability for
|
|
the W3 service only.
|
|
HTMLA var: "w3cryptcapable"
|
|
|
|
Arguments:
|
|
|
|
pV - DWORD** to be updated with the address of a DWORD that
|
|
will be non zero if encryption capability available
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
if ( m_pW3Config != NULL )
|
|
{
|
|
m_dwCryptCapable = (m_pW3Config->dwEncCaps
|
|
& (ENC_CAPS_NOT_INSTALLED|ENC_CAPS_DISABLED))
|
|
? 0 : (m_pW3Config->dwEncCaps & ENC_CAPS_TYPE_MASK);
|
|
}
|
|
else
|
|
{
|
|
char achEncCaps[32];
|
|
DWORD dwEncCaps = sizeof( achEncCaps );
|
|
EXTENSION_CONTROL_BLOCK* pECB = m_piiR->GetECB();
|
|
if ( pECB->GetServerVariable( (HCONN)pECB->ConnID,
|
|
"HTTP_CFG_ENC_CAPS", achEncCaps, &dwEncCaps ) )
|
|
{
|
|
m_dwCryptCapable = (DWORD)atol( achEncCaps );
|
|
m_dwCryptCapable = (m_dwCryptCapable
|
|
& (ENC_CAPS_NOT_INSTALLED|ENC_CAPS_DISABLED))
|
|
? 0 : (m_dwCryptCapable & ENC_CAPS_TYPE_MASK);
|
|
}
|
|
else
|
|
{
|
|
m_dwCryptCapable = 0;
|
|
}
|
|
}
|
|
|
|
*pV = &m_dwCryptCapable;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//
|
|
// array of services descriptor mapping name to service type
|
|
//
|
|
|
|
CServType g_aServTypes[] = {
|
|
{ "http", INET_HTTP_SVC_ID },
|
|
{ "ftp", INET_FTP_SVC_ID },
|
|
{ "gopher", INET_GOPHER_SVC_ID },
|
|
{ "dns", INET_DNS_SVC_ID },
|
|
{ "dir", INET_DIR },
|
|
} ;
|
|
|
|
|
|
CServTypeEnum g_ServTypeEnum;
|
|
|
|
|
|
CServType*
|
|
CServTypeEnum::GetServByName(
|
|
LPSTR pName )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Map a service name to a service descriptor entry
|
|
|
|
Arguments:
|
|
|
|
pName - Service name, i.e. http, ftp, ...
|
|
|
|
Returns:
|
|
|
|
pointer to service descriptor or NULL if service name not found
|
|
|
|
--*/
|
|
{
|
|
for ( int x = 0 ; x < sizeof(g_aServTypes)/sizeof(CServType) ; ++x )
|
|
{
|
|
if ( !strcmp( g_aServTypes[x].GetName(), pName ) )
|
|
{
|
|
return g_aServTypes+x;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
CServType*
|
|
CServTypeEnum::GetServByType(
|
|
DWORD dwT )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Map a service type to a service descriptor entry
|
|
|
|
Arguments:
|
|
|
|
dwT - Service type, i.e. INET_HTTP, ...
|
|
|
|
Returns:
|
|
|
|
pointer to service descriptor or NULL if service type not found
|
|
|
|
--*/
|
|
{
|
|
for ( int x = 0 ; x < sizeof(g_aServTypes)/sizeof(CServType) ; ++x )
|
|
{
|
|
if ( g_aServTypes[x].GetType() == dwT )
|
|
{
|
|
return g_aServTypes+x;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
//////
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::ServName(
|
|
LPVOID *pV )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Map the service type associated with this object to a string
|
|
representation ( i.e http, ftp, ... )
|
|
|
|
Arguments:
|
|
|
|
pV - LPSTR** updated with address of string representation of
|
|
service name
|
|
|
|
Returns:
|
|
|
|
TRUE if success, else FALSE
|
|
|
|
--*/
|
|
{
|
|
CServType *pS = g_ServTypeEnum.GetServByType( m_dwCurrentServerType );
|
|
if ( pS != NULL )
|
|
{
|
|
m_pszVarServName = pS->GetName();
|
|
*pV = (LPVOID)&m_pszVarServName;
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
void
|
|
CInetInfoConfigInfoMapper::Lock(
|
|
VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Lock access to this mapper object
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
EnterCriticalSection( &m_csLock );
|
|
}
|
|
|
|
|
|
void
|
|
CInetInfoConfigInfoMapper::UnLock(
|
|
VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Unlock access to this mapper object
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
LeaveCriticalSection( &m_csLock );
|
|
}
|
|
|
|
|
|
LPVOID
|
|
CInetInfoConfigInfoMapper::Alloc(
|
|
DWORD dwL )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocate a block of memory which will automatically de-allocated
|
|
by calling FreeInfo()
|
|
|
|
Arguments:
|
|
|
|
dwL - size of memory block to allocate
|
|
|
|
Returns:
|
|
|
|
pointer to allocated block or NULL if failure
|
|
updates reqstatus if failure
|
|
|
|
--*/
|
|
{
|
|
CAllocNode *pA = new CAllocNode( dwL );
|
|
|
|
if ( pA == NULL )
|
|
{
|
|
SetRequestStatus( HTR_OUT_OF_RESOURCE );
|
|
return NULL;
|
|
}
|
|
|
|
if ( m_pFirstAlloc == NULL )
|
|
{
|
|
m_pFirstAlloc = pA;
|
|
}
|
|
else
|
|
{
|
|
m_pLastAlloc->SetNext( pA );
|
|
}
|
|
m_pLastAlloc = pA;
|
|
|
|
return pA->GetBuff();
|
|
}
|
|
|
|
|
|
LPSTR
|
|
CInetInfoConfigInfoMapper::IPToMultiByte(
|
|
LPBYTE pB )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns a created string buffer containing the ASCII
|
|
representation of an IP address
|
|
|
|
Arguments:
|
|
|
|
pB - pointer to IP address as a byte sequence
|
|
length is given by IP_ADDR_BYTE_SIZE
|
|
|
|
Returns:
|
|
|
|
pointer to allocated string or NULL if failure
|
|
string is of auto-deallocate type
|
|
|
|
--*/
|
|
{
|
|
LPSTR pF,pS;
|
|
pF = pS = (char*)Alloc( IP_ADDR_BYTE_SIZE*4+1 );
|
|
if ( pS == NULL )
|
|
{
|
|
return NULL;
|
|
}
|
|
for ( int y = 0 ; y < IP_ADDR_BYTE_SIZE ; ++y )
|
|
{
|
|
DWORDToMultiByte( (DWORD)*pB++, pS );
|
|
pS += lstrlen( pS );
|
|
if ( y != IP_ADDR_BYTE_SIZE-1 )
|
|
{
|
|
*pS ++ = '.';
|
|
}
|
|
}
|
|
*pS = '\0';
|
|
|
|
return pF;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::MultiByteToIP(
|
|
LPSTR *ppS,
|
|
LPBYTE pB )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Convert the ASCII representation of an IP address
|
|
to a sequence of byte
|
|
|
|
Arguments:
|
|
|
|
ppS - pointer to string containing ASCII representation
|
|
of IP address. Does not have to be zero delimited.
|
|
pB - pointer to IP address as a byte sequence
|
|
length will be IP_ADDR_BYTE_SIZE
|
|
|
|
Returns:
|
|
|
|
TRUE if success, FALSE if failure
|
|
|
|
--*/
|
|
{
|
|
LPSTR pS = *ppS;
|
|
|
|
for ( int y = 0 ; y < IP_ADDR_BYTE_SIZE ; ++y )
|
|
{
|
|
int c;
|
|
UINT v;
|
|
for ( v = 0 ; (c=*pS)>='0' && c<='9' ; ++pS )
|
|
{
|
|
v = v * 10 + *pS-'0';
|
|
}
|
|
if ( v > 255 )
|
|
{
|
|
return FALSE;
|
|
}
|
|
*pB++ = (BYTE)v;
|
|
if ( y != IP_ADDR_BYTE_SIZE-1 && *pS++ != '.' )
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
*ppS = pS;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
extern "C" int __cdecl
|
|
QsortVirtDirCmp(
|
|
const void *pA,
|
|
const void *pB )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Compare two Virtual root entries for sorting order
|
|
1st key is the address field, then the name
|
|
|
|
Arguments:
|
|
|
|
pA - pointer to the 1st virtual root entry
|
|
pB - pointer to the 2nd virtual root entry
|
|
|
|
Returns:
|
|
|
|
-1 if 1st entry to be placed 1st as defined by the
|
|
sort order, 0 if same rank, 1 if 2nd entry is to
|
|
be placed first
|
|
|
|
--*/
|
|
{
|
|
LPWSTR pNameA = ((INET_INFO_VIRTUAL_ROOT_ENTRY*)pA)->pszRoot;
|
|
LPWSTR pNameB = ((INET_INFO_VIRTUAL_ROOT_ENTRY*)pB)->pszRoot;
|
|
LPWSTR pAddrA = ((INET_INFO_VIRTUAL_ROOT_ENTRY*)pA)->pszAddress;
|
|
LPWSTR pAddrB = ((INET_INFO_VIRTUAL_ROOT_ENTRY*)pB)->pszAddress;
|
|
int iCmp;
|
|
|
|
//
|
|
// sort on Addr, then Name
|
|
//
|
|
|
|
if ( pAddrA && pAddrB )
|
|
{
|
|
iCmp = _wcsicmp( pAddrA, pAddrB );
|
|
}
|
|
else
|
|
{
|
|
iCmp = 0;
|
|
}
|
|
|
|
if ( iCmp == 0 && pNameA && pNameB )
|
|
{
|
|
iCmp = _wcsicmp( pNameA, pNameB );
|
|
}
|
|
|
|
return iCmp;
|
|
}
|
|
|
|
|
|
extern "C" int __cdecl
|
|
QsortIpSecCmp(
|
|
const void *pA,
|
|
const void *pB )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Compare two IP access entries for sorting order
|
|
Uses the network address as the compare field
|
|
|
|
Arguments:
|
|
|
|
pA - pointer to the 1st IP access entry
|
|
pB - pointer to the 2nd IP access entry
|
|
|
|
Returns:
|
|
|
|
-1 if 1st entry to be placed 1st as defined by the
|
|
sort order, 0 if same rank, 1 if 2nd entry is to
|
|
be placed first
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// sort on network address
|
|
//
|
|
|
|
return memcmp( &((INET_INFO_IP_SEC_ENTRY*)pA)->dwNetwork,
|
|
&((INET_INFO_IP_SEC_ENTRY*)pB)->dwNetwork,
|
|
IP_ADDR_BYTE_SIZE );
|
|
}
|
|
|
|
|
|
BOOL SortVirtualRoots(
|
|
LPINET_INFO_VIRTUAL_ROOT_LIST pL )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sort a virtual root list for display
|
|
|
|
Arguments:
|
|
|
|
pL - pointer to a virtual root list
|
|
|
|
Returns:
|
|
|
|
TRUE
|
|
|
|
--*/
|
|
{
|
|
if ( pL != NULL && pL->cEntries )
|
|
{
|
|
qsort( pL->aVirtRootEntry,
|
|
pL->cEntries,
|
|
sizeof(INET_INFO_VIRTUAL_ROOT_ENTRY),
|
|
QsortVirtDirCmp );
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL SortIpSecList(
|
|
LPINET_INFO_IP_SEC_LIST pL )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sort a IP access list for display
|
|
|
|
Arguments:
|
|
|
|
pL - pointer to an IP access list
|
|
|
|
Returns:
|
|
|
|
TRUE
|
|
|
|
--*/
|
|
{
|
|
if ( pL != NULL && pL->cEntries )
|
|
{
|
|
qsort( pL->aIPSecEntry,
|
|
pL->cEntries,
|
|
sizeof(INET_INFO_IP_SEC_ENTRY),
|
|
QsortIpSecCmp );
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::GetCurrentConfig(
|
|
VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get the current configuration for the service linked
|
|
to this object by calling the IIS RPC layer
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
updates reqstatus
|
|
|
|
--*/
|
|
{
|
|
BOOL fSt = TRUE;
|
|
NET_API_STATUS iStat;
|
|
DWORD dwSize = sizeof(m_achComputerName)-2;
|
|
|
|
m_pConfig = NULL;
|
|
m_pW3Config = NULL;
|
|
m_pFtpConfig = NULL;
|
|
m_pGdConfig = NULL;
|
|
m_pGlobalConfig = NULL;
|
|
|
|
// free user enumeration
|
|
m_Users.Reset();
|
|
m_Drive.Reset();
|
|
ResetIter();
|
|
m_dwRPCStatus = 0;
|
|
m_dwInvalidLogUpdate = 0;
|
|
m_fLogFileUpdate = FALSE;
|
|
m_fLogODBCUpdate = FALSE;
|
|
|
|
if ( !GetComputerNameW( m_achComputerName+2, &dwSize ) )
|
|
{
|
|
m_achComputerName[0] = 0;
|
|
}
|
|
else
|
|
{
|
|
// adjust computer name for reference through Named Pipes
|
|
m_achComputerName[0] = L'\\';
|
|
m_achComputerName[1] = L'\\';
|
|
#if 0
|
|
m_achComputerName[2] = L'.';
|
|
m_achComputerName[3] = L'\0';
|
|
#endif
|
|
}
|
|
|
|
|
|
if ( m_dwCurrentServerType == INET_DIR )
|
|
{
|
|
// udpate arg1...3 from m_pszURLParam
|
|
|
|
m_pszArg1 = (LPSTR)Alloc( strlen( m_pszURLParam ) + 1 );
|
|
m_pszArg2 = m_pszArg3 = NULL;
|
|
if ( m_pszArg1 == NULL )
|
|
{
|
|
return FALSE;
|
|
}
|
|
strcpy( m_pszArg1, m_pszURLParam );
|
|
LPSTR pD = strchr( m_pszArg1, '?' );
|
|
if ( pD != NULL )
|
|
{
|
|
*pD = '\0';
|
|
m_pszArg2 = pD + 1;
|
|
pD = strchr( m_pszArg2, '?' );
|
|
if ( pD != NULL )
|
|
{
|
|
*pD = '\0';
|
|
m_pszArg3 = pD + 1;
|
|
|
|
// insure does not end with '\'
|
|
pD = m_pszArg3 + strlen(m_pszArg3);
|
|
if ( pD > m_pszArg3 && &pD[-1] == (LPSTR)_mbsrchr((LPBYTE)m_pszArg3,'\\') )
|
|
{
|
|
pD[-1] = '\0';
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( !m_fGotServerCapsAndVersion )
|
|
{
|
|
#if defined(IISv1)
|
|
m_pServerCaps = NULL;
|
|
|
|
g_OSVersion.dwOSVersionInfoSize = sizeof(g_OSVersion);
|
|
GetVersionEx( &g_OSVersion );
|
|
|
|
m_dwMinorVersion = 0;
|
|
m_dwMajorVersion = 1;
|
|
#else
|
|
if ( InetInfoGetServerCapabilities( m_achComputerName,
|
|
0,
|
|
&m_pServerCaps ) != NO_ERROR )
|
|
{
|
|
m_pServerCaps = NULL;
|
|
}
|
|
|
|
DWORD dwVer;
|
|
if ( InetInfoGetVersion( m_achComputerName,
|
|
0,
|
|
&dwVer ) != NO_ERROR )
|
|
{
|
|
dwVer = 0;
|
|
}
|
|
m_dwMinorVersion = dwVer >> 16;
|
|
m_dwMajorVersion = (DWORD)(WORD)dwVer;
|
|
#endif
|
|
m_fGotServerCapsAndVersion = TRUE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
__try {
|
|
if ( (iStat = InetInfoGetAdminInformation( m_achComputerName,
|
|
m_dwCurrentServerType,
|
|
&m_pConfig ))
|
|
== NO_ERROR || iStat == 2 )
|
|
{
|
|
m_pConfig->FieldControl = 0;
|
|
SetLogEntryVars();
|
|
m_dwWasLogPeriod = m_pConfig->lpLogConfig->ilPeriod;
|
|
m_dwWasLogType = m_pConfig->lpLogConfig->inetLogType;
|
|
m_dwWasSizeForTruncation = m_pConfig->lpLogConfig->cbSizeForTruncation ;
|
|
}
|
|
else
|
|
{
|
|
SetRequestStatus( HTR_CONFIG_ACCESS_ERROR );
|
|
m_dwRPCStatus = (DWORD)iStat;
|
|
fSt = FALSE;
|
|
m_pConfig = NULL;
|
|
}
|
|
|
|
if ( fSt )
|
|
{
|
|
SortVirtualRoots( m_pConfig->VirtualRoots );
|
|
SortIpSecList( m_pConfig->DenyIPList );
|
|
SortIpSecList( m_pConfig->GrantIPList );
|
|
|
|
if ( (iStat = InetInfoGetGlobalAdminInformation( m_achComputerName,
|
|
0,
|
|
&m_pGlobalConfig ))
|
|
== NO_ERROR || iStat == 2 )
|
|
{
|
|
m_pGlobalConfig->FieldControl = 0;
|
|
m_dwIsBandwidthLimited = 2; // undefined
|
|
}
|
|
else
|
|
{
|
|
SetRequestStatus( HTR_COM_CONFIG_ACCESS_ERROR );
|
|
m_dwRPCStatus = (DWORD)iStat;
|
|
fSt = FALSE;
|
|
m_pGlobalConfig = NULL;
|
|
}
|
|
}
|
|
|
|
if ( fSt )
|
|
{
|
|
if ( !m_fGotServerCapsAndVersion )
|
|
{
|
|
#if defined(IISv1)
|
|
m_pServerCaps = NULL;
|
|
|
|
g_OSVersion.dwOSVersionInfoSize = sizeof(g_OSVersion);
|
|
GetVersionEx( &g_OSVersion );
|
|
|
|
m_dwMinorVersion = 0;
|
|
m_dwMajorVersion = 1;
|
|
#else
|
|
if ( InetInfoGetServerCapabilities( m_achComputerName,
|
|
0,
|
|
&m_pServerCaps ) != NO_ERROR )
|
|
{
|
|
m_pServerCaps = NULL;
|
|
}
|
|
|
|
DWORD dwVer;
|
|
if ( InetInfoGetVersion( m_achComputerName,
|
|
0,
|
|
&dwVer ) != NO_ERROR )
|
|
{
|
|
dwVer = 0;
|
|
}
|
|
m_dwMinorVersion = dwVer >> 16;
|
|
m_dwMajorVersion = (DWORD)(WORD)dwVer;
|
|
#endif
|
|
m_fGotServerCapsAndVersion = TRUE;
|
|
}
|
|
switch ( m_dwCurrentServerType )
|
|
{
|
|
case INET_HTTP_SVC_ID:
|
|
if ( (iStat = W3GetAdminInformation( m_achComputerName, &m_pW3Config )) == NO_ERROR )
|
|
{
|
|
m_pW3Config->FieldControl = 0;
|
|
}
|
|
else
|
|
{
|
|
SetRequestStatus( HTR_W3_CONFIG_ACCESS_ERROR );
|
|
m_dwRPCStatus = (DWORD)iStat;
|
|
fSt = FALSE;
|
|
m_pW3Config = NULL;
|
|
}
|
|
|
|
break;
|
|
|
|
case INET_FTP_SVC_ID:
|
|
if ( (iStat = FtpGetAdminInformation( m_achComputerName,
|
|
&m_pFtpConfig )) == NO_ERROR )
|
|
{
|
|
m_pFtpConfig->FieldControl = 0;
|
|
}
|
|
else
|
|
{
|
|
SetRequestStatus( HTR_FTP_CONFIG_ACCESS_ERROR );
|
|
m_dwRPCStatus = (DWORD)iStat;
|
|
fSt = FALSE;
|
|
m_pFtpConfig = NULL;
|
|
}
|
|
break;
|
|
#if 0
|
|
case INET_GOPHER_SVC_ID:
|
|
if ( (iStat = GdGetAdminInformation( m_achComputerName,
|
|
&m_pGdConfig )) == NO_ERROR )
|
|
{
|
|
m_pGdConfig->FieldControl = 0;
|
|
}
|
|
else
|
|
{
|
|
SetRequestStatus( HTR_GD_CONFIG_ACCESS_ERROR );
|
|
m_dwRPCStatus = (DWORD)iStat;
|
|
fSt = FALSE;
|
|
m_pGdConfig = NULL;
|
|
}
|
|
break;
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
__except( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
SetRequestStatus( HTR_CONFIG_ACCESS_ERROR );
|
|
FreeInfo();
|
|
fSt = FALSE;
|
|
}
|
|
|
|
switch ( m_dwCurrentServerType )
|
|
{
|
|
case INET_HTTP_SVC_ID:
|
|
m_dwHttpStatus = m_dwRPCStatus; break;
|
|
|
|
case INET_FTP_SVC_ID:
|
|
m_dwFtpStatus = m_dwRPCStatus; break;
|
|
|
|
case INET_GOPHER_SVC_ID:
|
|
m_dwGopherStatus = m_dwRPCStatus; break;
|
|
}
|
|
|
|
return fSt;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::Update(
|
|
VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Update the current configuration for the service linked
|
|
to this object by calling the IIS RPC layer
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
updates reqstatus
|
|
|
|
--*/
|
|
{
|
|
BOOL fSt = TRUE;
|
|
NET_API_STATUS iStat;
|
|
|
|
if ( m_dwRequestStatus != HTR_OK )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if ( m_dwCurrentServerType == INET_DIR )
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
__try {
|
|
|
|
if ( m_pConfig != NULL && m_pConfig->FieldControl &&
|
|
(iStat = InetInfoSetAdminInformation( m_achComputerName,
|
|
m_dwCurrentServerType, m_pConfig )) != NO_ERROR )
|
|
{
|
|
SetRequestStatus( HTR_CONFIG_WRITE_ERROR );
|
|
m_dwRPCStatus = (DWORD)iStat;
|
|
fSt = FALSE;
|
|
}
|
|
|
|
if ( fSt )
|
|
{
|
|
#if 0
|
|
// update Authentication header if Authentication methods field updated
|
|
// not necessary : done via registry notification thread
|
|
if ( m_pConfig != NULL && (m_pConfig->FieldControl
|
|
& FC_INET_INFO_AUTHENTICATION) )
|
|
g_AuthReqs.UpdateMethodsIndication();
|
|
#endif
|
|
if ( m_pGlobalConfig != NULL && m_pGlobalConfig->FieldControl &&
|
|
(iStat = InetInfoSetGlobalAdminInformation( m_achComputerName,
|
|
0, m_pGlobalConfig )) != NO_ERROR && iStat != 2 )
|
|
{
|
|
SetRequestStatus( HTR_COM_CONFIG_WRITE_ERROR );
|
|
m_dwRPCStatus = (DWORD)iStat;
|
|
fSt = FALSE;
|
|
}
|
|
}
|
|
|
|
if ( fSt )
|
|
{
|
|
switch ( m_dwCurrentServerType )
|
|
{
|
|
case INET_HTTP_SVC_ID:
|
|
if ( m_pW3Config != NULL && m_pW3Config->FieldControl &&
|
|
(iStat = W3SetAdminInformation( m_achComputerName,
|
|
m_pW3Config )) != NO_ERROR )
|
|
{
|
|
SetRequestStatus( HTR_W3_CONFIG_WRITE_ERROR );
|
|
m_dwRPCStatus = (DWORD)iStat;
|
|
fSt = FALSE;
|
|
}
|
|
break;
|
|
|
|
case INET_FTP_SVC_ID:
|
|
if ( m_pFtpConfig != NULL && m_pFtpConfig->FieldControl &&
|
|
(iStat = FtpSetAdminInformation( m_achComputerName,
|
|
m_pFtpConfig )) != NO_ERROR )
|
|
{
|
|
SetRequestStatus( HTR_FTP_CONFIG_WRITE_ERROR );
|
|
m_dwRPCStatus = (DWORD)iStat;
|
|
fSt = FALSE;
|
|
}
|
|
break;
|
|
#if 0
|
|
case INET_GOPHER_SVC_ID:
|
|
if ( m_pGdConfig != NULL && m_pGdConfig->FieldControl &&
|
|
(iStat = GdSetAdminInformation( m_achComputerName,
|
|
m_pGdConfig )) != NO_ERROR )
|
|
{
|
|
SetRequestStatus( HTR_GD_CONFIG_WRITE_ERROR );
|
|
m_dwRPCStatus = (DWORD)iStat;
|
|
fSt = FALSE;
|
|
}
|
|
break;
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
__except( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
SetRequestStatus( HTR_CONFIG_WRITE_ERROR );
|
|
fSt = FALSE;
|
|
}
|
|
|
|
return fSt;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::FreeInfo(
|
|
VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Free memory associated with the current map object
|
|
including memory used by the structure used in the IIS RPC calls
|
|
and memory allocated using Alloc()
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
updates reqstatus
|
|
|
|
--*/
|
|
{
|
|
BOOL fSt = TRUE;
|
|
CAllocNode *pAllocNode;
|
|
|
|
// free all memory alloced to update RPC structures
|
|
for ( pAllocNode = m_pFirstAlloc ; pAllocNode != NULL ; )
|
|
{
|
|
CAllocNode *pN = pAllocNode->GetNext();
|
|
delete pAllocNode;
|
|
pAllocNode = pN;
|
|
}
|
|
m_pFirstAlloc = m_pLastAlloc = NULL;
|
|
|
|
if ( m_pConfig != NULL )
|
|
{
|
|
MIDL_user_free( m_pConfig );
|
|
m_pConfig = NULL;
|
|
}
|
|
|
|
if ( m_pGlobalConfig != NULL )
|
|
{
|
|
MIDL_user_free( m_pGlobalConfig );
|
|
m_pGlobalConfig = NULL;
|
|
}
|
|
|
|
// free user enumeration
|
|
m_Users.Reset();
|
|
|
|
m_Drive.Reset();
|
|
|
|
switch ( m_dwCurrentServerType )
|
|
{
|
|
case INET_HTTP_SVC_ID:
|
|
if ( m_pW3Config != NULL )
|
|
{
|
|
MIDL_user_free( m_pW3Config );
|
|
m_pW3Config = NULL;
|
|
}
|
|
break;
|
|
|
|
case INET_FTP_SVC_ID:
|
|
if ( m_pFtpConfig != NULL )
|
|
{
|
|
MIDL_user_free( m_pFtpConfig );
|
|
m_pFtpConfig = NULL;
|
|
}
|
|
break;
|
|
|
|
case INET_GOPHER_SVC_ID:
|
|
if ( m_pGdConfig != NULL )
|
|
{
|
|
MIDL_user_free( m_pGdConfig );
|
|
m_pGdConfig = NULL;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return fSt;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::Map(
|
|
LPBYTE pName,
|
|
DWORD dwNameLen,
|
|
CInetInfoMap** ppMap )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Map a variable name to a variable descriptor structure
|
|
|
|
Arguments:
|
|
|
|
pName - variable name
|
|
dwNameLen - variable name length
|
|
ppMap - updated with pointer to variable descriptor
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE if failure ( variable not found )
|
|
|
|
--*/
|
|
{
|
|
int x;
|
|
LPBYTE pLN = new BYTE[dwNameLen];
|
|
if ( pLN == NULL )
|
|
{
|
|
SetRequestStatus( HTR_OUT_OF_RESOURCE );
|
|
return FALSE;
|
|
}
|
|
memcpy( pLN, pName, dwNameLen );
|
|
|
|
// case insensitive lookup : normalize name to lower case
|
|
for ( x = 0 ; x < (int)dwNameLen ; ++x )
|
|
{
|
|
if ( IsDBCSLeadByte( pLN[x] ) )
|
|
{
|
|
++x;
|
|
}
|
|
else if ( isupper( (UCHAR)pLN[x] ) )
|
|
{
|
|
pLN[x] = (UINT)_tolower( (int)pLN[x] );
|
|
}
|
|
}
|
|
|
|
for ( x = 0 ; x < m_cNbMap ; ++x )
|
|
{
|
|
DWORD l = (DWORD)lstrlen(m_pMap[x].pName);
|
|
if ( l == dwNameLen && !memcmp( m_pMap[x].pName, pLN, l) )
|
|
{
|
|
*ppMap = m_pMap+x;
|
|
delete [] pLN;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
delete [] pLN;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::GetFromMsgBody(
|
|
LPSTR pName,
|
|
DWORD dwNameLen,
|
|
LPSTR *pResult,
|
|
DWORD *pdwResLen )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns the value of the specified variable in the message
|
|
body of the current request
|
|
|
|
Arguments:
|
|
|
|
pName - variable name
|
|
dwNameLen - variable name length
|
|
pResult - updated with address of string value
|
|
pdwResLen - updated with length of value
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE if failure ( variable not found )
|
|
|
|
--*/
|
|
{
|
|
// Use the raw request body to avoid parsing errors caused
|
|
// by escaped data values.
|
|
LPSTR pV = m_pszReqParamRaw;
|
|
|
|
// assume variable name begins with "msgbody."
|
|
|
|
pName += sizeof("msgbody.") - 1;
|
|
dwNameLen -= sizeof("msgbody.") - 1;
|
|
|
|
for ( ; *pV ; )
|
|
{
|
|
while ( isspace((UCHAR)(*pV)) )
|
|
{
|
|
++pV;
|
|
}
|
|
|
|
// scan for end of variable name
|
|
|
|
LPSTR pE = strchr( pV, '=' );
|
|
BOOL fIsLast = FALSE;
|
|
|
|
if ( pE != NULL )
|
|
{
|
|
++pE;
|
|
|
|
// scan for end of value
|
|
|
|
LPSTR pN = strchr( pE, '&' );
|
|
if ( pN == NULL )
|
|
{
|
|
if ( (pN = strchr( pE, '\r' )) == NULL )
|
|
{
|
|
if ( (pN = strchr( pE, '\n' )) == NULL )
|
|
{
|
|
pN = pE + strlen( pE );
|
|
}
|
|
}
|
|
|
|
fIsLast = TRUE;
|
|
}
|
|
|
|
// check for matching variable name
|
|
|
|
if ( pE - pV - 1 == (int)dwNameLen
|
|
&& !memcmp( pV, pName, dwNameLen ) )
|
|
{
|
|
*pdwResLen = DIFF(pN - pE);
|
|
if ( (*pResult = (LPSTR)Alloc( *pdwResLen + 1 )) == NULL )
|
|
{
|
|
return FALSE;
|
|
}
|
|
DelimStrcpyN( *pResult, pE, *pdwResLen );
|
|
|
|
// Escape the data
|
|
InlineFromTransparent( (LPBYTE)*pResult, pdwResLen, FALSE );
|
|
(*pResult)[*pdwResLen] = '\0';
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
if ( fIsLast )
|
|
{
|
|
break;
|
|
}
|
|
|
|
pV = pN + 1;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::GetFromServer(
|
|
LPSTR pName,
|
|
DWORD dwNameLen,
|
|
LPSTR *pResult,
|
|
DWORD *pdwResLen )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns the value of the specified variable from IIS
|
|
|
|
Arguments:
|
|
|
|
pName - variable name
|
|
dwNameLen - variable name length
|
|
pResult - updated with address of string value
|
|
pdwResLen - updated with length of value
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE if failure ( variable not found )
|
|
|
|
--*/
|
|
{
|
|
LPSTR pN;
|
|
|
|
// assume variable name begins with "iis."
|
|
|
|
pName += sizeof("iis.") - 1;
|
|
dwNameLen -= sizeof("iis.") - 1;
|
|
|
|
DWORD dwLen = 256;
|
|
|
|
if ( (*pResult = (LPSTR)Alloc( dwLen )) == NULL ||
|
|
(pN = (LPSTR)Alloc( dwNameLen+1 )) == NULL )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if ( dwNameLen == sizeof("DEFAULT_DOMAIN")-1 &&
|
|
!_memicmp( pName, "DEFAULT_DOMAIN", dwNameLen ) )
|
|
{
|
|
if ( g_pfnGetDefaultDomainName == NULL ||
|
|
!g_pfnGetDefaultDomainName( *pResult, dwLen))
|
|
{
|
|
*pdwResLen = 0;
|
|
}
|
|
else
|
|
{
|
|
*pdwResLen = strlen( *pResult );
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
memcpy( pN, pName, dwNameLen );
|
|
pN[dwNameLen] = '\0';
|
|
|
|
if ( m_piiR->GetECB()->GetServerVariable( (HCONN)m_piiR->GetECB()->ConnID,
|
|
pN,
|
|
*pResult,
|
|
&dwLen ) )
|
|
{
|
|
*pdwResLen = dwLen ? dwLen-1 : 0;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::EscapeString(
|
|
LPSTR *pResult,
|
|
LPDWORD pdwResLen,
|
|
BOOL fFreeAfterUse )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Escape the specified string in a form suitable for inclusion
|
|
in a URL
|
|
|
|
Arguments:
|
|
|
|
pResult - updated with address of string value
|
|
pdwResLen - updated with length of value
|
|
fFreeAfterUse - TRUE if input content of pResult needs to be freed
|
|
after usage ( using delete[] )
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE if failure
|
|
|
|
--*/
|
|
{
|
|
LPSTR pIn = *pResult;
|
|
LPSTR pOut;
|
|
LPSTR pEsc;
|
|
LPSTR pScan;
|
|
DWORD dwIn = *pdwResLen;
|
|
DWORD dwOut = 0;
|
|
|
|
//
|
|
// allocate output string base on its max length
|
|
//
|
|
|
|
if ( (pOut = (LPSTR)Alloc( dwIn * 3 + 1 )) == NULL )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
for ( pEsc = pOut, pScan = pIn ; dwIn-- ; )
|
|
{
|
|
int ch = *pScan++;
|
|
|
|
if ( (((ch >= 0) && (ch <= 32)) ||
|
|
(ch&0x80)||
|
|
( ch == '\\') || ( ch == ':' ) ||
|
|
(ch == '%') || (ch == '?') || (ch == '+') || (ch == '&')) &&
|
|
!(ch == TEXT('\n') || ch == TEXT('\r')) )
|
|
{
|
|
*pEsc++ = TEXT('%');
|
|
|
|
//
|
|
// Convert the high then the low character to hex
|
|
//
|
|
|
|
UINT nDigit = (UINT)(ch >> 4);
|
|
|
|
*pEsc++ = HEXDIGIT( nDigit );
|
|
|
|
nDigit = (UINT)(ch & 0x0f);
|
|
|
|
*pEsc++ = HEXDIGIT( nDigit );
|
|
|
|
dwOut += 3;
|
|
}
|
|
else
|
|
{
|
|
*pEsc++ = (char)ch;
|
|
++dwOut;
|
|
}
|
|
}
|
|
|
|
*pResult = pOut;
|
|
*pdwResLen = dwOut;
|
|
|
|
if ( fFreeAfterUse )
|
|
{
|
|
delete [] pIn;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::GetString(
|
|
LPBYTE pName,
|
|
DWORD dwNameLen,
|
|
LPSTR *pResult,
|
|
DWORD *pdwResLen,
|
|
BOOL *pfFree )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns the value of the specified variable as specified
|
|
by its name as a string
|
|
|
|
Arguments:
|
|
|
|
pName - variable name
|
|
dwNameLen - variable name length
|
|
pResult - updated with address of string value
|
|
pdwResLen - updated with length of value
|
|
pfFree - updated with TRUE if pResult needs to be freed
|
|
after usage ( using delete[] )
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE if failure ( variable not found )
|
|
|
|
--*/
|
|
{
|
|
CInetInfoMap *pMap;
|
|
BOOL fMustEscape;
|
|
BOOL fSt;
|
|
|
|
if ( !memcmp( "\"&z\",", pName, sizeof("\"&z\",")-1 ) )
|
|
{
|
|
pName += sizeof("\"&z\",")-1;
|
|
dwNameLen -= sizeof("\"&z\",")-1;
|
|
fMustEscape = TRUE;
|
|
}
|
|
else
|
|
{
|
|
fMustEscape = FALSE;
|
|
}
|
|
|
|
if ( !memcmp( "msgbody.", pName, sizeof("msgbody.")-1 ) )
|
|
{
|
|
*pfFree = FALSE;
|
|
fSt = GetFromMsgBody( (LPSTR)pName, dwNameLen, pResult, pdwResLen );
|
|
}
|
|
else if ( !memcmp( "iis.", pName, sizeof("iis.")-1 ) )
|
|
{
|
|
*pfFree = FALSE;
|
|
fSt = GetFromServer( (LPSTR)pName, dwNameLen, pResult, pdwResLen );
|
|
}
|
|
else if ( Map( pName, dwNameLen, &pMap ) )
|
|
{
|
|
fSt = GetString( pMap, pResult, pdwResLen, pfFree );
|
|
}
|
|
else
|
|
{
|
|
fSt = FALSE;
|
|
}
|
|
|
|
if ( fSt == FALSE )
|
|
{
|
|
*pfFree = FALSE;
|
|
}
|
|
else if ( fMustEscape )
|
|
{
|
|
if ( fSt = EscapeString( pResult, pdwResLen, *pfFree ) )
|
|
{
|
|
*pfFree = FALSE;
|
|
}
|
|
}
|
|
|
|
return fSt;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::GetString(
|
|
CInetInfoMap *pMap,
|
|
LPSTR *pResult,
|
|
DWORD *pdwResLen,
|
|
BOOL *pfFree )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns the value of the specified variable as specified
|
|
by its descriptor as a string
|
|
|
|
Arguments:
|
|
|
|
pMap - variable descriptor
|
|
pResult - updated with address of string value
|
|
pdwResLen - updated with length of value
|
|
pfFree - updated with TRUE if pResult needs to be freed
|
|
after usage ( using delete[] )
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE if failure
|
|
updates reqstatus
|
|
|
|
--*/
|
|
{
|
|
BOOL fSt = FALSE;
|
|
LPVOID *pV;
|
|
|
|
*pResult = NULL;
|
|
*pdwResLen = 0;
|
|
*pfFree = FALSE;
|
|
|
|
if ( (this->*pMap->GetAddr)( (LPVOID*)&pV ) == FALSE )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
LPSTR pR;
|
|
|
|
switch ( pMap->iType )
|
|
{
|
|
case ITYPE_LPWSTR:
|
|
case ITYPE_VIRT_DIR_LPWSTR:
|
|
case ITYPE_PATH_LPWSTR:
|
|
if ( pV != NULL )
|
|
{
|
|
pV = (LPVOID*)*(LPWSTR*)pV;
|
|
}
|
|
// fall-through
|
|
|
|
// convert from Unicode to ASCII
|
|
|
|
case ITYPE_AWCHAR:
|
|
if ( pV != NULL )
|
|
{
|
|
DWORD dwResLen = wcslen((LPWSTR)pV);
|
|
pR = new char[ dwResLen*2 + 1 + 1];
|
|
if ( pR == NULL )
|
|
{
|
|
SetRequestStatus( HTR_OUT_OF_RESOURCE );
|
|
fSt = FALSE;
|
|
}
|
|
else
|
|
{
|
|
if ( dwResLen == 0 ||
|
|
( dwResLen = WideCharToMultiByte(
|
|
CP_ACP,
|
|
0,
|
|
(LPWSTR)pV,
|
|
wcslen((LPWSTR)pV),
|
|
pR,
|
|
wcslen( (LPWSTR)pV)*2,
|
|
NULL,
|
|
NULL ) )
|
|
!= 0 )
|
|
{
|
|
// if type is path, normalize path
|
|
// so that root directory ends with '\'
|
|
|
|
if ( pMap->iType == ITYPE_PATH_LPWSTR
|
|
&& dwResLen == 2 && pR[1] == ':' )
|
|
{
|
|
pR[ dwResLen++ ] = L'\\';
|
|
}
|
|
|
|
pR[ dwResLen ] = '\0';
|
|
*pdwResLen = dwResLen;
|
|
*pResult = (LPSTR)pR;
|
|
*pfFree = TRUE;
|
|
fSt = TRUE;
|
|
}
|
|
else
|
|
{
|
|
delete [] pR;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*pdwResLen = 0;
|
|
*pResult = "";
|
|
*pfFree = FALSE;
|
|
fSt = TRUE;
|
|
}
|
|
break;
|
|
|
|
case ITYPE_LPSTR:
|
|
if ( pV != NULL )
|
|
{
|
|
pV = (LPVOID*)*(LPSTR*)pV;
|
|
}
|
|
if ( pV != NULL )
|
|
{
|
|
*pdwResLen = lstrlen( (LPSTR)pV );
|
|
*pResult = (LPSTR)pV;
|
|
*pfFree = FALSE;
|
|
fSt = TRUE;
|
|
}
|
|
else
|
|
{
|
|
*pdwResLen = 0;
|
|
*pResult = "";
|
|
*pfFree = FALSE;
|
|
fSt = TRUE;
|
|
}
|
|
break;
|
|
|
|
// convert from numeric to string after possible scaling
|
|
|
|
case ITYPE_DWORD:
|
|
case ITYPE_BOOL:
|
|
case ITYPE_SHORT:
|
|
case ITYPE_SHORTDW:
|
|
case ITYPE_1K:
|
|
case ITYPE_1M:
|
|
case ITYPE_TIME:
|
|
pR = new char[MAX_SIZE_OF_DWORD_AS_STRING];
|
|
if ( pR == NULL )
|
|
{
|
|
SetRequestStatus( HTR_OUT_OF_RESOURCE );
|
|
fSt = FALSE;
|
|
}
|
|
else
|
|
{
|
|
DWORD dwV = pMap->iType==ITYPE_SHORT
|
|
? (DWORD)*(unsigned short*)pV : *(DWORD*)pV;
|
|
|
|
if ( pMap->iType==ITYPE_1K )
|
|
{
|
|
dwV /= 1024;
|
|
}
|
|
else if ( pMap->iType==ITYPE_1M )
|
|
{
|
|
dwV /= 1024*1024;
|
|
}
|
|
|
|
if ( pMap->iType==ITYPE_TIME )
|
|
{
|
|
wsprintf( pR,
|
|
"%d:%02d:%02d",
|
|
dwV/3600,
|
|
(dwV/60)%60,
|
|
dwV%60 );
|
|
}
|
|
else
|
|
{
|
|
DWORDToMultiByte( dwV, pR );
|
|
}
|
|
|
|
*pResult = pR;
|
|
*pdwResLen = lstrlen( pR );
|
|
*pfFree = TRUE;
|
|
fSt = TRUE;
|
|
}
|
|
break;
|
|
|
|
case ITYPE_IP_ADDR:
|
|
case ITYPE_IP_MASK:
|
|
*pResult = IPToMultiByte( (LPBYTE)pV );
|
|
*pdwResLen = lstrlen( *pResult );
|
|
*pfFree = FALSE;
|
|
fSt = TRUE;
|
|
break;
|
|
|
|
default:
|
|
SetRequestStatus( HTR_INVALID_VAR_TYPE );
|
|
break;
|
|
}
|
|
|
|
return fSt;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::PutString(
|
|
CInetInfoMap *pMap,
|
|
LPSTR pSet )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
update the value of the specified variable as specified
|
|
by its descriptor from a string
|
|
|
|
Arguments:
|
|
|
|
pMap - variable descriptor
|
|
pSet - string representation of the new value
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE if failure
|
|
updates reqstatus
|
|
|
|
--*/
|
|
{
|
|
BOOL fSt = FALSE;
|
|
BOOL fUp = FALSE;
|
|
LPVOID pV;
|
|
LPWSTR pW;
|
|
LPSTR pS;
|
|
LPSTR pSM = NULL;
|
|
DWORD dwResLen;
|
|
DWORD dwRes;
|
|
int cL = strlen( pSet );
|
|
DWORD dwN;
|
|
DWORD dwC;
|
|
WCHAR *pT;
|
|
|
|
// assume variable accessible, as was checked when
|
|
// retrieving the variable descriptor
|
|
|
|
(this->*pMap->GetAddr)( (LPVOID*)&pV );
|
|
|
|
if ( pV != NULL )
|
|
{
|
|
switch ( pMap->iType )
|
|
{
|
|
case ITYPE_VIRT_DIR_LPWSTR:
|
|
pSM = (LPSTR)Alloc( (cL+2) );
|
|
if ( pSM == NULL )
|
|
{
|
|
break;
|
|
}
|
|
if ( *pSet == '\\' )
|
|
{
|
|
*pSet = '/';
|
|
}
|
|
if ( *pSet != '/' )
|
|
{
|
|
pSM[0] = '/';
|
|
strcpy( pSM + 1, pSet );
|
|
++cL;
|
|
}
|
|
else
|
|
{
|
|
strcpy( pSM, pSet );
|
|
}
|
|
// fall-through
|
|
|
|
case ITYPE_LPWSTR:
|
|
case ITYPE_PATH_LPWSTR:
|
|
pW = (WCHAR*)Alloc( (cL+1)*sizeof(WCHAR) );
|
|
if ( pW == NULL )
|
|
{
|
|
break;
|
|
}
|
|
if ( (dwResLen=cL)==0 || (pW != NULL && (dwResLen
|
|
= MultiByteToWideChar( CP_ACP,
|
|
0,
|
|
pSM ? pSM : pSet,
|
|
cL,
|
|
pW,
|
|
cL )) != 0) )
|
|
{
|
|
pW[ dwResLen ] = 0;
|
|
*(LPWSTR*)pV = pW;
|
|
fUp = (this->*pMap->UpdateIndication)();
|
|
fSt = TRUE;
|
|
}
|
|
break;
|
|
|
|
case ITYPE_AWCHAR:
|
|
pT = new WCHAR[pMap->dwParam];
|
|
if ( pT == NULL )
|
|
{
|
|
SetRequestStatus( HTR_OUT_OF_RESOURCE );
|
|
break;
|
|
}
|
|
dwC = MultiByteToWideChar(
|
|
CP_ACP,
|
|
0,
|
|
(LPSTR)pSet,
|
|
cL,
|
|
(LPWSTR)pT,
|
|
pMap->dwParam-1 );
|
|
if ( (dwResLen = cL) == 0 || (dwResLen = dwC) != 0 )
|
|
{
|
|
pT[dwResLen++] = 0;
|
|
if ( lstrcmpW( (PWSTR)pV, pT ) )
|
|
{
|
|
memcpy( pV, pT, dwResLen * sizeof(WCHAR) );
|
|
fUp = (this->*pMap->UpdateIndication)();
|
|
}
|
|
else
|
|
{
|
|
fUp = TRUE;
|
|
}
|
|
fSt = TRUE;
|
|
}
|
|
delete [] pT;
|
|
break;
|
|
|
|
case ITYPE_LPSTR:
|
|
pS = (char*)Alloc( cL+1 );
|
|
if ( pS != NULL )
|
|
{
|
|
memcpy( pS, pSet, cL+1 );
|
|
fUp = (this->*pMap->UpdateIndication)();
|
|
fSt = TRUE;
|
|
}
|
|
else
|
|
{
|
|
fSt = FALSE;
|
|
}
|
|
break;
|
|
|
|
case ITYPE_TIME:
|
|
fSt = FALSE;
|
|
break;
|
|
|
|
case ITYPE_1K:
|
|
*(DWORD*)pV = MultiByteToDWORD( pSet ) * 1024;
|
|
goto to_upd;
|
|
|
|
case ITYPE_1M:
|
|
*(DWORD*)pV = MultiByteToDWORD( pSet ) * 1024*1024;
|
|
goto to_upd;
|
|
|
|
case ITYPE_SHORT:
|
|
case ITYPE_SHORTDW:
|
|
dwRes = MultiByteToDWORD( pSet );
|
|
if ( dwRes > (pMap->iType == ITYPE_SHORT
|
|
? USHRT_MAX : (DWORD)SHRT_MAX) )
|
|
{
|
|
fUp = FALSE;
|
|
fSt = TRUE;
|
|
break;
|
|
}
|
|
if ( pMap->iType == ITYPE_SHORT )
|
|
{
|
|
*(unsigned short*)pV = (unsigned short)dwRes;
|
|
}
|
|
else
|
|
{
|
|
*(DWORD*)pV = dwRes;
|
|
}
|
|
goto to_upd;
|
|
|
|
case ITYPE_DWORD:
|
|
dwN = MultiByteToDWORD( pSet );
|
|
//if ( dwN != *(DWORD*)pV )
|
|
{
|
|
*(DWORD*)pV = dwN;
|
|
goto to_upd;
|
|
}
|
|
fSt = TRUE;
|
|
fUp = TRUE;
|
|
break;
|
|
|
|
case ITYPE_BOOL:
|
|
*(BOOL*)pV = MultiByteToDWORD( pSet ) ? TRUE : FALSE;
|
|
to_upd:
|
|
fUp = (this->*pMap->UpdateIndication)();
|
|
fSt = TRUE;
|
|
break;
|
|
|
|
case ITYPE_IP_ADDR:
|
|
case ITYPE_IP_MASK:
|
|
if ( isalpha( (UCHAR)(*pSet) ) )
|
|
{
|
|
hostent *pH;
|
|
if( (pH = gethostbyname( pSet )) != NULL
|
|
&& pH->h_addr != NULL )
|
|
{
|
|
memcpy( pV, pH->h_addr, IP_ADDR_BYTE_SIZE );
|
|
fUp = (this->*pMap->UpdateIndication)();
|
|
fSt = TRUE;
|
|
}
|
|
}
|
|
else if ( MultiByteToIP( &pSet, (LPBYTE)pV ) )
|
|
{
|
|
fUp = (this->*pMap->UpdateIndication)();
|
|
fSt = TRUE;
|
|
}
|
|
else if ( pMap->iType == ITYPE_IP_MASK && *pSet == '\0' )
|
|
{
|
|
memset( pV, 0xff, IP_ADDR_BYTE_SIZE );
|
|
fUp = (this->*pMap->UpdateIndication)();
|
|
fSt = TRUE;
|
|
}
|
|
else
|
|
{
|
|
SetRequestStatus( HTR_BAD_PARAM );
|
|
fSt = FALSE;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
SetRequestStatus( HTR_INVALID_VAR_TYPE );
|
|
fSt = FALSE;
|
|
break;
|
|
}
|
|
if ( fSt == TRUE && fUp == FALSE )
|
|
{
|
|
SetRequestStatus( HTR_VALIDATION_FAILED );
|
|
fSt = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fSt = FALSE;
|
|
}
|
|
|
|
return fSt;
|
|
}
|
|
|
|
|
|
//
|
|
// Disconnect user management
|
|
//
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::DisconnectUser(
|
|
LPSTR pU )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Disconnect user from the specified service based on numeric ID as string
|
|
The ID is opaque to HTMLA, only meaningfull to the FTP service
|
|
It is retrieved using user enumeration
|
|
|
|
Arguments:
|
|
|
|
pU - ASCII representation of the numeric ID
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
updates reqstatus
|
|
|
|
--*/
|
|
{
|
|
BOOL fSt = FALSE;
|
|
|
|
DWORD dwID = MultiByteToDWORD( pU );
|
|
fSt = I_FtpDisconnectUser( m_achComputerName, dwID ) == NO_ERROR;
|
|
if ( !fSt )
|
|
{
|
|
SetRequestStatus( HTR_USER_DISCONNECT_ERROR );
|
|
}
|
|
|
|
return fSt;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::DisconnectAll(
|
|
VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Disconnect all users from the specified service
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
BOOL fSt = FALSE;
|
|
|
|
DWORD dwC, dwI, dwCurID;
|
|
if ( m_Users.GetCountAsDWORD( &dwC ) )
|
|
{
|
|
ResetIter();
|
|
for ( dwI = 0 ; dwI < dwC ; ++dwI )
|
|
{
|
|
if ( !m_Users.GetIDAsDWORD( &dwCurID ) )
|
|
{
|
|
break;
|
|
}
|
|
// can't do anything with status at this point,
|
|
// so ignore error
|
|
I_FtpDisconnectUser( m_achComputerName, dwCurID );
|
|
IncIter();
|
|
}
|
|
fSt = TRUE;
|
|
}
|
|
// if error accessing user enum, RequestStatus already set by CUserEnum
|
|
|
|
return fSt;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::AliasVirtDir(
|
|
INET_INFO_VIRTUAL_ROOT_ENTRY *pU )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
create an alias for the matching virtual root
|
|
by coalescing all alpha-numeric characters
|
|
from the virtual root physical path
|
|
|
|
Arguments:
|
|
|
|
pU - ptr to virtual root entry
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
int lD = wcslen( pU->pszDirectory );
|
|
int lR = 0;
|
|
if ( !(pU->pszRoot = (LPWSTR)Alloc( (lD + 1 + 1)*sizeof(WCHAR) )) )
|
|
{
|
|
return FALSE;
|
|
}
|
|
pU->pszRoot[lR++] = L'/';
|
|
for ( int x = 0 ; x < lD ; ++x )
|
|
{
|
|
if ( iswalpha( pU->pszDirectory[x] )
|
|
|| iswdigit( pU->pszDirectory[x] ) )
|
|
{
|
|
pU->pszRoot[lR++] = pU->pszDirectory[x];
|
|
}
|
|
}
|
|
pU->pszRoot[lR] = 0;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::HandleVirtDirRequest(
|
|
LPSTR pszVirt,
|
|
LPSTR pszAddr,
|
|
int iReq )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handle a virtual root command. can be one of :
|
|
|
|
_VIRT_DIR_REQ_ALIAS : create an alias for the matching virtual root
|
|
by coalescing all alpha-numeric characters
|
|
from the virtual root physical path
|
|
|
|
_VIRT_DIR_REQ_CHECK : check for the existence of the specified
|
|
virtual root, set reqstatus to HTR_DIR_SAME_NAME
|
|
if present
|
|
|
|
Arguments:
|
|
|
|
pszVirt - name of virtual root
|
|
pszAddr - network address virtual root
|
|
iReq : a _VIRT_DIR_REQ_ command
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
updates reqstatus
|
|
|
|
--*/
|
|
{
|
|
LPINET_INFO_VIRTUAL_ROOT_LIST pL = m_pConfig->VirtualRoots;
|
|
INET_INFO_VIRTUAL_ROOT_ENTRY isE;
|
|
BOOL fSt = FALSE;
|
|
CHAR achID[MAX_PATH + 80];
|
|
|
|
if ( pL == NULL )
|
|
{
|
|
goto no_match;
|
|
}
|
|
|
|
// drive dir part is empty
|
|
strcpy( achID, pszVirt );
|
|
strcat( achID, REF_SEP_STR REF_SEP_STR);
|
|
strcat( achID, pszAddr );
|
|
|
|
// parse ID
|
|
if ( BuildVirtDirUniqueID( achID, &isE ) )
|
|
{
|
|
ResetIter();
|
|
// iterate through list
|
|
DWORD dwI;
|
|
for ( dwI = 0 ; dwI < pL->cEntries ; ++dwI )
|
|
{
|
|
if ( VirtDirCmp( pL->aVirtRootEntry + dwI, &isE, FALSE ) )
|
|
{
|
|
break;
|
|
}
|
|
IncIter();
|
|
}
|
|
if ( dwI == pL->cEntries )
|
|
{
|
|
goto no_match;
|
|
}
|
|
else if ( iReq == _VIRT_DIR_REQ_ALIAS )
|
|
{
|
|
// update pszRoot with alphanum chars from pszDirectory
|
|
fSt = AliasVirtDir( pL->aVirtRootEntry + dwI );
|
|
}
|
|
else // check root
|
|
{
|
|
SetRequestStatus( HTR_DIR_SAME_NAME );
|
|
}
|
|
goto ret;
|
|
}
|
|
else
|
|
{
|
|
SetRequestStatus( HTR_BAD_PARAM );
|
|
}
|
|
|
|
goto ret;
|
|
|
|
no_match:
|
|
if ( iReq != _VIRT_DIR_REQ_CHECK )
|
|
{
|
|
SetRequestStatus( HTR_REF_NOT_FOUND );
|
|
fSt = FALSE;
|
|
}
|
|
else
|
|
{
|
|
fSt = TRUE;
|
|
}
|
|
ret:
|
|
|
|
return fSt;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::GetStatus(
|
|
VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Update the status of the IIS services : HTTP, FTP, Gopher
|
|
stored in m_dw*Status
|
|
status is the return code from the RPC InetInfoGetAdminInformation()
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
BOOL fSt = TRUE;
|
|
INET_INFO_CONFIG_INFO *pConfig;
|
|
DWORD dwNeed;
|
|
|
|
// check which status are missing :
|
|
// all services except the one linked to this object
|
|
|
|
switch ( m_dwCurrentServerType )
|
|
{
|
|
case INET_HTTP_SVC_ID:
|
|
dwNeed = INET_FTP_SVC_ID | INET_GOPHER_SVC_ID; break;
|
|
|
|
case INET_FTP_SVC_ID:
|
|
dwNeed = INET_HTTP_SVC_ID | INET_GOPHER_SVC_ID; break;
|
|
|
|
case INET_GOPHER_SVC_ID:
|
|
dwNeed = INET_HTTP_SVC_ID | INET_FTP_SVC_ID; break;
|
|
|
|
default:
|
|
dwNeed = INET_HTTP_SVC_ID | INET_FTP_SVC_ID | INET_GOPHER_SVC_ID;
|
|
}
|
|
|
|
if ( dwNeed & INET_HTTP_SVC_ID )
|
|
{
|
|
pConfig = NULL;
|
|
|
|
if ( (m_dwHttpStatus = InetInfoGetAdminInformation(
|
|
m_achComputerName, INET_HTTP_SVC_ID, &pConfig ))
|
|
== NO_ERROR || m_dwHttpStatus == 2 )
|
|
{
|
|
if ( pConfig != NULL )
|
|
{
|
|
MIDL_user_free( pConfig );
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( dwNeed & INET_FTP_SVC_ID )
|
|
{
|
|
pConfig = NULL;
|
|
|
|
if ( (m_dwFtpStatus = InetInfoGetAdminInformation( m_achComputerName,
|
|
INET_FTP_SVC_ID, &pConfig ))
|
|
== NO_ERROR || m_dwFtpStatus == 2 )
|
|
{
|
|
if ( pConfig != NULL )
|
|
{
|
|
MIDL_user_free( pConfig );
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( dwNeed & INET_GOPHER_SVC_ID )
|
|
{
|
|
pConfig = NULL;
|
|
|
|
if ( (m_dwGopherStatus = InetInfoGetAdminInformation( m_achComputerName,
|
|
INET_GOPHER_SVC_ID, &pConfig ))
|
|
== NO_ERROR || m_dwGopherStatus == 2 )
|
|
{
|
|
if ( pConfig != NULL )
|
|
{
|
|
MIDL_user_free( pConfig );
|
|
}
|
|
}
|
|
}
|
|
|
|
return fSt;
|
|
}
|
|
|
|
|
|
// IP list management
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::AddIPAccess(
|
|
BOOL fDenyList )
|
|
{
|
|
return CloneIPAccesses( fDenyList, TRUE, FALSE, 0 );
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::DeleteIPAccess(
|
|
BOOL fDenyList,
|
|
LPSTR pID )
|
|
{
|
|
if ( PositionIPAccess( fDenyList, pID ) )
|
|
{
|
|
BOOL fSt = CloneIPAccesses( fDenyList, FALSE, TRUE, m_iIter );
|
|
if ( fSt )
|
|
{
|
|
UpdateIP();
|
|
}
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::BuildIPUniqueID(
|
|
LPSTR pI,
|
|
INET_INFO_IP_SEC_ENTRY* pE )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Decode the ASCII representation of an IP entry reference
|
|
|
|
Arguments:
|
|
|
|
pI - contains the IP reference
|
|
pE - pointer to a IP entry where dwMask & dwNetwork will be filled
|
|
|
|
WARNING:
|
|
|
|
Must be in sync with IPRef()
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
for ( int x = 0 ; x < 2 ; ++x )
|
|
{
|
|
LPBYTE pB = x ? (LPBYTE)&pE->dwMask : (LPBYTE)&pE->dwNetwork;
|
|
if ( !MultiByteToIP( &pI, pB ) )
|
|
{
|
|
return FALSE;
|
|
}
|
|
if ( x != 1 && *pI++ != REF_SEP )
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::PositionIPAccess(
|
|
BOOL fDenyList,
|
|
LPSTR pID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Position the iteration counter ( m_iIter ) on the IP entry
|
|
matching the specified IP reference in the specified list
|
|
|
|
Arguments:
|
|
|
|
fDenyList - TRUE if the list is the deny list, else FALSE
|
|
for the grant list
|
|
pID - pointer to an IP entry reference
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
updates reqstatus, m_iIter
|
|
|
|
--*/
|
|
{
|
|
LPINET_INFO_IP_SEC_LIST pL = fDenyList
|
|
? m_pConfig->DenyIPList : m_pConfig->GrantIPList;
|
|
INET_INFO_IP_SEC_ENTRY isE;
|
|
BOOL fSt = FALSE;
|
|
|
|
InvalidateIPSingle();
|
|
|
|
if ( pL == NULL )
|
|
{
|
|
SetRequestStatus( HTR_REF_NOT_FOUND );
|
|
return FALSE;
|
|
}
|
|
|
|
// parse ID
|
|
if ( BuildIPUniqueID( pID, &isE ) )
|
|
{
|
|
ResetIter();
|
|
// iterate through list
|
|
DWORD dwI;
|
|
for ( dwI = 0 ; dwI < pL->cEntries ; ++dwI )
|
|
{
|
|
if ( !memcmp( pL->aIPSecEntry + dwI, &isE, sizeof(isE) ) )
|
|
{
|
|
fSt = TRUE;
|
|
break;
|
|
}
|
|
IncIter();
|
|
}
|
|
if ( dwI == pL->cEntries )
|
|
{
|
|
SetRequestStatus( HTR_REF_NOT_FOUND );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SetRequestStatus( HTR_BAD_PARAM );
|
|
}
|
|
|
|
return fSt;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::CloneIPAccesses(
|
|
BOOL fDenyList,
|
|
BOOL fExtend,
|
|
BOOL fDel,
|
|
DWORD dwToDel )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Clone the specified IP list with optional extension and/or
|
|
deletion of an entry
|
|
|
|
Arguments:
|
|
|
|
fDenyList - TRUE if the list is the deny list, else FALSE
|
|
for the grant list
|
|
fExtend - TRUE if list is to be extended by one entry ( added
|
|
at the end of the list, m_iIter will be positioned
|
|
on this new entry )
|
|
fDel - TRUE if the entry specified in dwToDel is to be deleted
|
|
from the list
|
|
dwToDel - specify the entry index ( 0-based ) to delete if fDel
|
|
is TRUE
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
updates reqstatus, m_iIter
|
|
|
|
--*/
|
|
{
|
|
LPINET_INFO_IP_SEC_LIST pL;
|
|
DWORD dwNewCount, dwOldCount;
|
|
LPINET_INFO_IP_SEC_LIST pN;
|
|
|
|
pL = fDenyList ? m_pConfig->DenyIPList : m_pConfig->GrantIPList;
|
|
dwOldCount = pL ? pL->cEntries : 0;
|
|
dwNewCount = dwOldCount + (fExtend ? 1 : 0) - (fDel ? 1 : 0);
|
|
pN = (LPINET_INFO_IP_SEC_LIST)Alloc(
|
|
sizeof(INET_INFO_IP_SEC_LIST) + dwNewCount
|
|
* sizeof(INET_INFO_IP_SEC_ENTRY));
|
|
if ( pN == NULL )
|
|
{
|
|
// insure m_iIter is invalid ( so update attempts will fail )
|
|
if ( fExtend )
|
|
{
|
|
SetIter( dwOldCount );
|
|
}
|
|
return FALSE;
|
|
}
|
|
pN->cEntries = dwNewCount;
|
|
|
|
DWORD dwF;
|
|
DWORD dwT;
|
|
for ( dwF = dwT = 0 ; dwF < dwOldCount ; ++dwF )
|
|
{
|
|
if ( fDel && dwF == dwToDel )
|
|
{
|
|
continue;
|
|
}
|
|
memcpy( pN->aIPSecEntry + dwT,
|
|
pL->aIPSecEntry + dwF,
|
|
sizeof(INET_INFO_IP_SEC_ENTRY) );
|
|
++dwT;
|
|
}
|
|
|
|
if ( fDenyList )
|
|
{
|
|
m_pConfig->DenyIPList = pN;
|
|
}
|
|
else
|
|
{
|
|
m_pConfig->GrantIPList = pN;
|
|
}
|
|
|
|
if ( fExtend )
|
|
{
|
|
SetIter( dwNewCount - 1 );
|
|
memset( &pN->aIPSecEntry[dwNewCount-1].dwMask,
|
|
0xff,
|
|
IP_ADDR_BYTE_SIZE );
|
|
memset( &pN->aIPSecEntry[dwNewCount-1].dwNetwork,
|
|
0x00,
|
|
IP_ADDR_BYTE_SIZE );
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::SetRemoteAddr(
|
|
LPSTR pR )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Store the client IP address in binary and ASCII format
|
|
for later use
|
|
|
|
Arguments:
|
|
|
|
pR - ASCII representation of the client IP address.
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
BOOL fSt = FALSE;
|
|
|
|
m_pRemoteAddr = (LPBYTE)Alloc( IP_ADDR_BYTE_SIZE );
|
|
m_pszRemoteAddr = (LPSTR)Alloc( lstrlen( pR ) + 1 );
|
|
if ( m_pRemoteAddr != NULL && m_pszRemoteAddr != NULL )
|
|
{
|
|
LPSTR pC = pR;
|
|
if ( MultiByteToIP( &pC, m_pRemoteAddr ) )
|
|
{
|
|
lstrcpy( m_pszRemoteAddr, pR );
|
|
fSt = TRUE;
|
|
}
|
|
else
|
|
{
|
|
SetRequestStatus( HTR_BAD_PARAM );
|
|
}
|
|
}
|
|
|
|
return fSt;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::SetIPAccessDefault(
|
|
BOOL fIsDeny )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set the default action for the IP access check made by the server
|
|
Can be either deny or grant access.
|
|
To signal a 'deny' default condition we set the deny list to be
|
|
empty, and to signal 'grant' we set the grant list to be empty
|
|
If both lists are empty the default is 'grant'
|
|
To set the default to deny with an empty 'grant' list the regular
|
|
admin tool create a dummy entry 0.0.0.0
|
|
As we must provide access to the distant admin after switching the
|
|
default to 'deny', we use the address of the client as the entry
|
|
to store in the 'grant' list in this case.
|
|
|
|
Arguments:
|
|
|
|
dIsDeny - TRUE if default is to be deny, FALSE for grant
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
LPINET_INFO_IP_SEC_LIST *pL;
|
|
BOOL fSt = TRUE;
|
|
|
|
if ( fIsDeny )
|
|
{
|
|
m_pConfig->DenyIPList = (LPINET_INFO_IP_SEC_LIST)NULL;
|
|
pL = &m_pConfig->GrantIPList;
|
|
// insert null entry if none exist in exception list
|
|
if ( *pL == NULL || (*pL)->cEntries == 0 )
|
|
{
|
|
fSt = CloneIPAccesses( !fIsDeny, TRUE, FALSE, 0 );
|
|
if ( fSt )
|
|
{
|
|
// set addr to REMOTE_ADDR
|
|
INET_INFO_IP_SEC_ENTRY *pE = &(*pL)->aIPSecEntry[m_iIter];
|
|
memcpy( &pE->dwNetwork, m_pRemoteAddr, IP_ADDR_BYTE_SIZE );
|
|
memset( &pE->dwMask, 0xff, IP_ADDR_BYTE_SIZE );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_pConfig->GrantIPList = (LPINET_INFO_IP_SEC_LIST)NULL;
|
|
}
|
|
if ( fSt )
|
|
{
|
|
UpdateIP();
|
|
}
|
|
return fSt;
|
|
}
|
|
|
|
|
|
// Virtual Directories list management
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::AddVirtDir(
|
|
VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Add a virtual root entry in the current list, position
|
|
the iteration counter to point to this new entry.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
Updates m_iIter ( iteration counter )
|
|
|
|
--*/
|
|
{
|
|
return CloneVirtDirs( TRUE, FALSE, 0 );
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::DeleteVirtDir(
|
|
LPSTR pID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Delete the virtual root entry specified by the reference
|
|
|
|
Arguments:
|
|
|
|
pID - virtual root reference
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure ( e.g. inexistant reference )
|
|
|
|
--*/
|
|
{
|
|
if ( PositionVirtDir( pID ) )
|
|
{
|
|
BOOL fSt = CloneVirtDirs( FALSE, TRUE, m_iIter );
|
|
if ( fSt )
|
|
{
|
|
UpdateRoot();
|
|
}
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::BuildVirtDirUniqueID(
|
|
LPSTR pI,
|
|
INET_INFO_VIRTUAL_ROOT_ENTRY* pE )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Decode the ASCII representation of a virtual root reference
|
|
|
|
Arguments:
|
|
|
|
pI - contains the virtual root reference
|
|
pE - pointer to a virtual root entry pszRoot,
|
|
pszDirectory & pszAddress will be filled
|
|
|
|
WARNING:
|
|
|
|
Must be in sync with RootRef()
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
LPSTR p;
|
|
LPSTR pA;
|
|
|
|
if ( (p = strchr( pI, REF_SEP )) != NULL )
|
|
{
|
|
if ( (pA = strchr( p+1, REF_SEP )) != NULL )
|
|
{
|
|
int l1, l2, l3;
|
|
DWORD dwL1, dwL2, dwL3;
|
|
|
|
pE->pszRoot = (LPWSTR)Alloc( (ULONG)(((l1=DIFF(p-pI))+1)*sizeof(WCHAR)) );
|
|
pE->pszDirectory = (LPWSTR)Alloc( (ULONG)(((l2=DIFF(pA-p)-1)+1)*sizeof(WCHAR)) );
|
|
pE->pszAddress = (LPWSTR)Alloc( ((l3=lstrlen(pI)-l1-l2-2)+1)
|
|
*sizeof(WCHAR) );
|
|
|
|
if ( pE->pszRoot == NULL
|
|
|| pE->pszDirectory == NULL
|
|
|| pE->pszAddress == NULL )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// convert to UNICODE if string non empty
|
|
|
|
if ( dwL1 = l1 )
|
|
{
|
|
dwL1 = MultiByteToWideChar( CP_ACP,
|
|
0,
|
|
pI,
|
|
l1,
|
|
pE->pszRoot,
|
|
l1 );
|
|
}
|
|
|
|
if ( dwL2 = l2 )
|
|
{
|
|
dwL2 = MultiByteToWideChar( CP_ACP,
|
|
0,
|
|
p+1,
|
|
l2,
|
|
pE->pszDirectory,
|
|
l2 );
|
|
}
|
|
|
|
if ( dwL3 = l3 )
|
|
{
|
|
dwL3 = MultiByteToWideChar( CP_ACP,
|
|
0,
|
|
pA+1,
|
|
l3,
|
|
pE->pszAddress,
|
|
l3 );
|
|
}
|
|
|
|
pE->pszRoot[ dwL1 ] = '\0';
|
|
pE->pszDirectory[ dwL2 ] = '\0';
|
|
pE->pszAddress[ dwL3 ] = '\0';
|
|
|
|
// return OK if empty string or convertion successfull
|
|
// for both components
|
|
|
|
return (!l1 || dwL1) && (!l2 || dwL2 ) && (!l3 || dwL3 )
|
|
? TRUE : FALSE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::VirtDirCmp(
|
|
INET_INFO_VIRTUAL_ROOT_ENTRY* p1,
|
|
INET_INFO_VIRTUAL_ROOT_ENTRY* p2,
|
|
BOOL fCompareDrive )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Test two virtual root entries for identity
|
|
if fCompareDrive is TRUE, pszRoot, pszDirectory & pszAddress
|
|
will be used in the compare operation
|
|
if FALSE, only pszRoot & pszAddress will be used
|
|
|
|
Arguments:
|
|
|
|
p1 - 1st virtual root entry
|
|
p2 - 2nd virtual root entry
|
|
fCompareDrive - TRUE to enable compare of pszDirectory
|
|
|
|
Returns:
|
|
|
|
TRUE if identical.
|
|
|
|
--*/
|
|
{
|
|
return ( !wcscmp(p1->pszRoot ? p1->pszRoot : L"", p2->pszRoot)
|
|
&& (!fCompareDrive || !wcscmp( p1->pszDirectory
|
|
? p1->pszDirectory : L"", p2->pszDirectory))
|
|
&& !wcscmp( p1->pszAddress ? p1->pszAddress : L"",
|
|
p2->pszAddress) )
|
|
? TRUE : FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::PositionVirtDir(
|
|
LPSTR pID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Position the iteration counter ( m_iIter ) on the virtual
|
|
root entry matching the specified virtual root reference
|
|
|
|
Arguments:
|
|
|
|
pID - pointer to a virutal root reference
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
updates reqstatus, m_iIter
|
|
|
|
--*/
|
|
{
|
|
LPINET_INFO_VIRTUAL_ROOT_LIST pL = m_pConfig->VirtualRoots;
|
|
INET_INFO_VIRTUAL_ROOT_ENTRY isE;
|
|
BOOL fSt = FALSE;
|
|
|
|
if ( pL == NULL )
|
|
{
|
|
SetRequestStatus( HTR_REF_NOT_FOUND );
|
|
return FALSE;
|
|
}
|
|
|
|
// parse ID
|
|
if ( BuildVirtDirUniqueID( pID, &isE ) )
|
|
{
|
|
ResetIter();
|
|
// iterate through list
|
|
DWORD dwI;
|
|
for ( dwI = 0 ; dwI < pL->cEntries ; ++dwI )
|
|
{
|
|
if ( VirtDirCmp( pL->aVirtRootEntry + dwI, &isE, TRUE ) )
|
|
{
|
|
fSt = TRUE;
|
|
break;
|
|
}
|
|
IncIter();
|
|
}
|
|
if ( dwI == pL->cEntries )
|
|
{
|
|
SetRequestStatus( HTR_REF_NOT_FOUND );
|
|
}
|
|
else
|
|
{
|
|
SetRootEntryVars();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SetRequestStatus( HTR_BAD_PARAM );
|
|
}
|
|
|
|
return fSt;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoConfigInfoMapper::CloneVirtDirs(
|
|
BOOL fExtend,
|
|
BOOL fDel,
|
|
DWORD dwToDel )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Clone the virtual root list with optional extension and/or
|
|
deletion of an entry
|
|
|
|
Arguments:
|
|
|
|
fExtend - TRUE if list is to be extended by one entry ( added
|
|
at the end of the list, m_iIter will be positioned
|
|
on this new entry )
|
|
fDel - TRUE if the entry specified in dwToDel is to be deleted
|
|
from the list
|
|
dwToDel - specify the entry index ( 0-based ) to delete if fDel
|
|
is TRUE
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
updates reqstatus, m_iIter
|
|
|
|
--*/
|
|
{
|
|
LPINET_INFO_VIRTUAL_ROOT_LIST pL;
|
|
DWORD dwNewCount;
|
|
LPINET_INFO_VIRTUAL_ROOT_LIST pN;
|
|
|
|
pL = m_pConfig->VirtualRoots;
|
|
dwNewCount = pL->cEntries + (fExtend ? 1 : 0) - (fDel ? 1 : 0);
|
|
pN = (LPINET_INFO_VIRTUAL_ROOT_LIST)Alloc(
|
|
sizeof(INET_INFO_VIRTUAL_ROOT_LIST) + dwNewCount
|
|
* sizeof(INET_INFO_VIRTUAL_ROOT_ENTRY));
|
|
if ( pN == NULL )
|
|
{
|
|
// insure m_iIter is invalid ( so update attempts will fail )
|
|
if ( fExtend )
|
|
{
|
|
SetIter( pL->cEntries );
|
|
}
|
|
return FALSE;
|
|
}
|
|
pN->cEntries = dwNewCount;
|
|
|
|
DWORD dwF;
|
|
DWORD dwT;
|
|
for ( dwF = dwT = 0 ; dwF < pL->cEntries ; ++dwF )
|
|
{
|
|
if ( fDel && dwF == dwToDel )
|
|
{
|
|
continue;
|
|
}
|
|
memcpy( pN->aVirtRootEntry + dwT,
|
|
pL->aVirtRootEntry + dwF,
|
|
sizeof(INET_INFO_VIRTUAL_ROOT_ENTRY) );
|
|
++dwT;
|
|
}
|
|
|
|
m_pConfig->VirtualRoots = pN;
|
|
|
|
if ( fExtend )
|
|
{
|
|
SetIter( dwNewCount - 1 );
|
|
LPWSTR pA = (LPWSTR)Alloc( sizeof(WCHAR) );
|
|
if ( pA != NULL )
|
|
{
|
|
pA[0] = L'\0';
|
|
pN->aVirtRootEntry[dwNewCount-1].pszAddress = pA;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
VOID
|
|
CInetInfoConfigInfoMapper::SetRPCStatusString( DWORD dwS )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set the RPC status string to the system message with code dwS. If no matching
|
|
code is found, set status string to empty string
|
|
|
|
Arguments:
|
|
|
|
dwS - System message code
|
|
|
|
Returns:
|
|
|
|
VOID
|
|
|
|
--*/
|
|
{
|
|
LPVOID pszMsgBuffer;
|
|
BOOL fFoundMessage = FALSE;
|
|
DWORD result = 0;
|
|
HANDLE hdll;
|
|
|
|
DWORD flags = FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
|
FORMAT_MESSAGE_FROM_SYSTEM |
|
|
FORMAT_MESSAGE_IGNORE_INSERTS;
|
|
//
|
|
//Check whether we can find the error message in the current
|
|
//image
|
|
//
|
|
|
|
if ( ! FormatMessage( flags,
|
|
NULL,
|
|
dwS,
|
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
|
|
(LPTSTR) &pszMsgBuffer,
|
|
0,
|
|
NULL ))
|
|
{
|
|
|
|
//
|
|
//Couldn't find it in current image, check a list of DLLs
|
|
//
|
|
flags = FORMAT_MESSAGE_ALLOCATE_BUFFER
|
|
| FORMAT_MESSAGE_IGNORE_INSERTS
|
|
| FORMAT_MESSAGE_MAX_WIDTH_MASK
|
|
| FORMAT_MESSAGE_FROM_HMODULE;
|
|
|
|
for (int i = 0; i < NUM_ERROR_CODE_DLLS; i++)
|
|
{
|
|
hdll = LoadLibraryA(g_apszErrorCodeDlls[i]);
|
|
|
|
//
|
|
//Check for error msg in this dll
|
|
//
|
|
if (hdll != NULL)
|
|
{
|
|
result = FormatMessage( flags,
|
|
(LPVOID) hdll,
|
|
(DWORD) dwS,
|
|
0,
|
|
(LPTSTR)&pszMsgBuffer,
|
|
0,
|
|
NULL );
|
|
|
|
//Done with the lib, unload
|
|
FreeLibrary((HMODULE)hdll);
|
|
|
|
//
|
|
//Found an error string
|
|
//
|
|
|
|
if (result)
|
|
{
|
|
fFoundMessage = TRUE;
|
|
break;
|
|
}
|
|
|
|
} //if (hdll != NULL)
|
|
|
|
} //for (int i = 0; ...)
|
|
|
|
} //if ( ! FormatMessage...)
|
|
|
|
//
|
|
//Found error message in current image
|
|
//
|
|
else
|
|
{
|
|
fFoundMessage = TRUE;
|
|
}
|
|
|
|
|
|
if (fFoundMessage)
|
|
{
|
|
//deallocate the string if it's been allocated by FormatMessage
|
|
if (m_fAllocatedRPCStatusString)
|
|
{
|
|
LocalFree((HLOCAL) m_pszRPCStatusString);
|
|
}
|
|
m_pszRPCStatusString = (LPTSTR) pszMsgBuffer;
|
|
m_fAllocatedRPCStatusString = TRUE;
|
|
}
|
|
else
|
|
{
|
|
//Couldn't get an error message string, set status string to be the numeric
|
|
//error code
|
|
|
|
//free the string if it's been allocated by FormatMessage
|
|
if (m_fAllocatedRPCStatusString)
|
|
{
|
|
LocalFree((HLOCAL) m_pszRPCStatusString);
|
|
}
|
|
|
|
m_pszRPCStatusString = (LPTSTR) m_achRPCErrorCodeBuffer;
|
|
wsprintf(m_pszRPCStatusString,"%ld", dwS);
|
|
m_fAllocatedRPCStatusString = FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/////////////////// Verb Context
|
|
|
|
CVerbContext::CVerbContext(
|
|
VOID )
|
|
{
|
|
m_pszVerbName = NULL;
|
|
m_cNbInfoMap = m_cAllocedInfoMap = 0;
|
|
m_pMaps = NULL;
|
|
}
|
|
|
|
|
|
CVerbContext::~CVerbContext(
|
|
VOID )
|
|
{
|
|
if ( m_pszVerbName != NULL )
|
|
{
|
|
delete [] m_pszVerbName;
|
|
}
|
|
|
|
if ( m_pMaps != NULL )
|
|
{
|
|
delete [] m_pMaps;
|
|
}
|
|
}
|
|
|
|
|
|
CInetInfoMap*
|
|
CVerbContext::GetInfoMap(
|
|
DWORD dwI )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Access the specified entry ( 0-based ) in the parameter list
|
|
of a verb context
|
|
|
|
Arguments:
|
|
|
|
dwI - index in the array of parameters
|
|
|
|
Returns:
|
|
|
|
pointer to variable descriptor or NULL if error
|
|
|
|
--*/
|
|
{
|
|
if ( dwI < m_cNbInfoMap )
|
|
{
|
|
return m_pMaps[dwI];
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CVerbContext::AddInfoMap(
|
|
CInetInfoMap* pI )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Add a parameter entry in the list of parameters for a verb context
|
|
|
|
Arguments:
|
|
|
|
pI - pointer to a parameter descriptor
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
|
|
--*/
|
|
{
|
|
if ( m_cNbInfoMap == m_cAllocedInfoMap )
|
|
{
|
|
m_cAllocedInfoMap += 4;
|
|
CInetInfoMap **pN = new CInetInfoMap*[m_cAllocedInfoMap];
|
|
if ( pN == NULL )
|
|
{
|
|
return FALSE;
|
|
}
|
|
if ( m_pMaps )
|
|
{
|
|
memcpy( pN, m_pMaps, m_cNbInfoMap * sizeof(CInetInfoMap*) );
|
|
delete [] m_pMaps;
|
|
}
|
|
m_pMaps = pN;
|
|
}
|
|
|
|
m_pMaps[m_cNbInfoMap++] = pI;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
DWORD
|
|
CVerbContext::Parse(
|
|
CInetInfoConfigInfoMapper *pMapper,
|
|
LPBYTE pS,
|
|
DWORD dwL )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Parse a verb command for parameters ( separated with space )
|
|
remember the verb name &
|
|
create an internal array of parameters as variable descriptors
|
|
|
|
Arguments:
|
|
|
|
pMapper - pointer to object used to map variable names to variable
|
|
descriptors
|
|
pS - verb command to parse
|
|
dwL - maximum # of characters available for parsing
|
|
|
|
Returns:
|
|
|
|
length of characters used for parsing the verb excluding the "%>"
|
|
delimitor or 0 if error
|
|
|
|
--*/
|
|
{
|
|
DWORD dwW = dwL;
|
|
BOOL fIsVerb;
|
|
CInetInfoMap* pM;
|
|
LPSTR pResult;
|
|
DWORD dwResLen;
|
|
|
|
for ( fIsVerb = TRUE ; dwL ; fIsVerb = FALSE )
|
|
{
|
|
// skip white space
|
|
while ( dwL && *pS == ' ' )
|
|
{
|
|
++pS;
|
|
--dwL;
|
|
}
|
|
|
|
LPBYTE pW = pS;
|
|
DWORD dwLenTok = 0;
|
|
|
|
// get until '%', ' '
|
|
int c = '%';
|
|
while ( dwL && (c=*pS)!='%' && c!=' ' )
|
|
{
|
|
++dwLenTok;
|
|
++pS;
|
|
--dwL;
|
|
}
|
|
|
|
if ( fIsVerb )
|
|
{
|
|
m_pszVerbName = new char[dwLenTok+1];
|
|
if ( m_pszVerbName == NULL )
|
|
{
|
|
pMapper->SetRequestStatus( HTR_OUT_OF_RESOURCE );
|
|
return 0;
|
|
}
|
|
memcpy( m_pszVerbName, pW, dwLenTok );
|
|
m_pszVerbName[dwLenTok] = '\0';
|
|
}
|
|
else if ( !memcmp( "iis.", pW, sizeof("iis.")-1 ) )
|
|
{
|
|
if ( pMapper->GetFromServer( (LPSTR)pW, dwLenTok, &pResult,
|
|
&dwResLen ) )
|
|
{
|
|
goto alloc_map;
|
|
}
|
|
return 0; // error
|
|
}
|
|
else if ( !memcmp( "msgbody.", pW, sizeof("msgbody.")-1 ) )
|
|
{
|
|
if ( pMapper->GetFromMsgBody( (LPSTR)pW, dwLenTok, &pResult,
|
|
&dwResLen ) )
|
|
{
|
|
alloc_map:
|
|
pM = (CInetInfoMap*)pMapper->Alloc( sizeof(CInetInfoMap) );
|
|
if ( !pM )
|
|
{
|
|
return 0;
|
|
}
|
|
pM->iType = ITYPE_PARAM_LIT_STRING;
|
|
pM->pName = pResult;
|
|
|
|
goto add_map;
|
|
}
|
|
return 0; // error
|
|
}
|
|
else if ( *pW == '"' )
|
|
{
|
|
pM = (CInetInfoMap*)pMapper->Alloc( sizeof(CInetInfoMap) );
|
|
if ( !pM )
|
|
{
|
|
return 0;
|
|
}
|
|
pM->iType = ITYPE_PARAM_LIT_STRING;
|
|
if ( !(pM->pName = (LPSTR)pMapper->Alloc( dwLenTok - 1 )) )
|
|
{
|
|
return 0;
|
|
}
|
|
memcpy( pM->pName, pW + 1, dwLenTok - 2 );
|
|
pM->pName[ dwLenTok -2 ] ='\0';
|
|
add_map:
|
|
if ( !AddInfoMap( pM ) )
|
|
{
|
|
pMapper->SetRequestStatus( HTR_OUT_OF_RESOURCE );
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CInetInfoMap *pM;
|
|
if ( pMapper->Map( pW, dwLenTok, &pM ) )
|
|
{
|
|
if ( !AddInfoMap( pM ) )
|
|
{
|
|
pMapper->SetRequestStatus( HTR_OUT_OF_RESOURCE );
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0; // error
|
|
}
|
|
}
|
|
|
|
if ( c=='%' )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
return dwW - dwL;
|
|
}
|
|
|
|
|
|
/////////////////// Request
|
|
|
|
// adjust the IF status at the nested IF level
|
|
|
|
void
|
|
Adjust(
|
|
int *piIsSkip,
|
|
int iIf )
|
|
{
|
|
if ( iIf )
|
|
{
|
|
*piIsSkip |= HSS_SKIP_IF;
|
|
}
|
|
else
|
|
{
|
|
*piIsSkip &= ~HSS_SKIP_IF;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Extensible buffer class
|
|
//
|
|
|
|
CExtBuff::CExtBuff(
|
|
VOID )
|
|
{
|
|
m_pB = NULL;
|
|
m_cCurrent = m_cAlloc = 0;
|
|
}
|
|
|
|
|
|
CExtBuff::~CExtBuff(
|
|
VOID )
|
|
{
|
|
if ( m_pB )
|
|
{
|
|
delete [] m_pB;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
CExtBuff::Reset(
|
|
VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Reset a buffer to an empty state
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
VOID
|
|
|
|
--*/
|
|
{
|
|
if ( m_pB != NULL )
|
|
{
|
|
delete [] m_pB;
|
|
}
|
|
m_pB = NULL;
|
|
m_cCurrent = m_cAlloc = 0;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CExtBuff::Extend(
|
|
UINT cReq )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Insure buffer at least wide enough for additional
|
|
specified # of bytes
|
|
|
|
Arguments:
|
|
|
|
cReq - # of characters to add to current buffer length
|
|
|
|
Returns:
|
|
|
|
TRUE if success, FALSE if failure
|
|
|
|
--*/
|
|
{
|
|
BOOL fSt = TRUE;
|
|
|
|
if ( m_cAlloc - m_cCurrent < cReq )
|
|
{
|
|
UINT cAlloc = m_cAlloc + EXTBUFF_INCALLOC;
|
|
if ( cAlloc < m_cCurrent + cReq )
|
|
{
|
|
cAlloc = ((cAlloc + cReq + EXTBUFF_INCALLOC)/EXTBUFF_INCALLOC)
|
|
* EXTBUFF_INCALLOC;
|
|
}
|
|
LPBYTE pN = new BYTE[cAlloc];
|
|
if ( pN != NULL )
|
|
{
|
|
if ( m_pB != NULL )
|
|
{
|
|
memcpy( pN, m_pB, m_cCurrent );
|
|
delete [] m_pB;
|
|
}
|
|
m_pB = pN;
|
|
m_cAlloc = cAlloc;
|
|
}
|
|
else
|
|
{
|
|
fSt = FALSE;
|
|
}
|
|
}
|
|
|
|
return fSt;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CExtBuff::CopyBuff(
|
|
LPBYTE pB,
|
|
UINT cB )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
append bytes at end of buffer
|
|
|
|
Arguments:
|
|
|
|
pB - pointer to origine bytes
|
|
cB - count of bytes to copy
|
|
|
|
Returns:
|
|
|
|
TRUE if success, FALSE if failure
|
|
|
|
--*/
|
|
{
|
|
if ( !cB )
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
if ( Extend( cB ) )
|
|
{
|
|
memcpy( m_pB + m_cCurrent, pB, cB );
|
|
m_cCurrent += cB;
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// Map HTTP status numeric code to ASCII status
|
|
//
|
|
|
|
CStatusStringAndCode g_aStatus[] = {
|
|
{ HT_OK, IDS_HTRESP_OKANS },
|
|
{ HT_REDIRECT, IDS_HTRESP_REDIRECT },
|
|
{ HT_SERVER_ERROR, IDS_HTRESP_SERVER_ERROR },
|
|
{ HT_BAD_GATEWAY, IDS_HTRESP_BAD_GATEWAY },
|
|
} ;
|
|
|
|
|
|
//
|
|
// list of recognized verbs
|
|
//
|
|
|
|
CInetInfoVerbMap g_aIVerbMap[] = {
|
|
|
|
{ "AddDenyIpAccess", &CInetInfoRequest::AddDenyIPAccess },
|
|
{ "DelDenyIpAccess", &CInetInfoRequest::DeleteDenyIPAccess },
|
|
{ "PosDenyIpAccess", &CInetInfoRequest::PositionDenyIPAccess },
|
|
{ "SetDefaultIpAccessToDeny", &CInetInfoRequest::DefaultIsDenyIPAccess },
|
|
|
|
{ "AddGrantIpAccess", &CInetInfoRequest::AddGrantIPAccess },
|
|
{ "DelGrantIpAccess", &CInetInfoRequest::DeleteGrantIPAccess },
|
|
{ "PosGrantIpAccess", &CInetInfoRequest::PositionGrantIPAccess },
|
|
{ "SetDefaultIpAccessToGrant", &CInetInfoRequest::DefaultIsGrantIPAccess },
|
|
|
|
{ "AddVirtDir", &CInetInfoRequest::AddVirtDir },
|
|
{ "DelVirtDir", &CInetInfoRequest::DeleteVirtDir },
|
|
{ "PosVirtDir", &CInetInfoRequest::PositionVirtDir },
|
|
|
|
{ "ChangePassword", &CInetInfoRequest::ChangePassword },
|
|
{ "GetUserFlags", &CInetInfoRequest::GetUserFlags },
|
|
{ "SetHttpStatus", &CInetInfoRequest::SetHttpStatus },
|
|
|
|
{ "Update", &CInetInfoRequest::Update },
|
|
{ "Clear", &CInetInfoRequest::Clear },
|
|
|
|
{ "DisconnectUser", &CInetInfoRequest::DisconnectUser },
|
|
{ "DisconnectAll", &CInetInfoRequest::DisconnectAll },
|
|
|
|
{ "GetStatus", &CInetInfoRequest::GetStatus },
|
|
|
|
{ "ValidateDir", &CInetInfoRequest::ValidateDir },
|
|
{ "CreateDir", &CInetInfoRequest::CreateDir },
|
|
{ "GenerateDirList", &CInetInfoRequest::GenerateDirList },
|
|
|
|
{ "CheckForVirtDir", &CInetInfoRequest::CheckForVirtDir },
|
|
{ "AliasVirtDir", &CInetInfoRequest::AliasVirtDir },
|
|
} ;
|
|
|
|
|
|
CInetInfoRequest::CInetInfoRequest(
|
|
EXTENSION_CONTROL_BLOCK*p_ECB,
|
|
CInetInfoConfigInfoMapper* pMapper,
|
|
LPSTR pScr,
|
|
LPSTR pParam )
|
|
{
|
|
m_pECB = p_ECB;
|
|
m_pMapper = pMapper;
|
|
m_pScr = pScr;
|
|
m_pParam = pParam;
|
|
m_pData = NULL;
|
|
m_dwDataLen = 0;
|
|
|
|
m_pDataRaw = NULL;
|
|
m_dwDataRawLen = 0;
|
|
|
|
m_dwHTTPStatus = HT_OK;
|
|
}
|
|
|
|
|
|
CInetInfoRequest::~CInetInfoRequest(
|
|
VOID )
|
|
{
|
|
if ( m_pData != NULL )
|
|
{
|
|
delete [] m_pData;
|
|
}
|
|
|
|
if( m_pDataRaw != NULL )
|
|
{
|
|
delete [] m_pDataRaw;
|
|
}
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoRequest::DoVerb(
|
|
CVerbContext *pC )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Invoke an already parsed verb
|
|
|
|
Arguments:
|
|
|
|
pC - pointer to parsed verb
|
|
|
|
Returns:
|
|
|
|
TRUE if success, FALSE if failure
|
|
|
|
--*/
|
|
{
|
|
m_pVerbContext = pC;
|
|
|
|
// find verb, call it
|
|
UINT iH;
|
|
for ( iH = 0 ; iH < sizeof(g_aIVerbMap)/sizeof(CInetInfoVerbMap) ; ++iH )
|
|
{
|
|
if ( !strcmp( g_aIVerbMap[iH].pszName, pC->GetVerbName() ) )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( iH == sizeof(g_aIVerbMap)/sizeof(CInetInfoVerbMap) )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
return (this->*g_aIVerbMap[iH].pHandler)();
|
|
}
|
|
|
|
|
|
BOOL
|
|
InlineFromTransparent(
|
|
LPBYTE pData,
|
|
DWORD *pdwDataLen,
|
|
BOOL fFilterEscPlus
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Decode inline a buffer from HTTP character transparency
|
|
|
|
Arguments:
|
|
|
|
pData - array of characters to decode
|
|
pdwDataLen - # of characters in buffer, updated on output
|
|
fFilterEscPlus - TRUE if "%+" is to be decoded to "+"
|
|
|
|
Returns:
|
|
|
|
TRUE if success, FALSE if failure
|
|
|
|
--*/
|
|
{
|
|
DWORD dwDataLen, dwWas;
|
|
LPBYTE pT, pScan, pWas ;
|
|
int ch;
|
|
|
|
|
|
dwWas = *pdwDataLen;
|
|
pWas = pData;
|
|
|
|
for ( dwDataLen = dwWas, pScan = pWas ;
|
|
dwDataLen-- ; )
|
|
{
|
|
switch ( ch = *pScan++ )
|
|
{
|
|
case '%':
|
|
if ( dwDataLen )
|
|
{
|
|
if ( !fFilterEscPlus && pScan[0] == '%' )
|
|
{
|
|
--dwWas;
|
|
++pScan;
|
|
--dwDataLen;
|
|
*pData++ = '%';
|
|
}
|
|
else if ( pScan[0] == '+' )
|
|
{
|
|
if ( fFilterEscPlus )
|
|
{
|
|
--dwWas;
|
|
}
|
|
else
|
|
{
|
|
*pData++ = '%';
|
|
}
|
|
*pData++ = '+';
|
|
++pScan;
|
|
--dwDataLen;
|
|
}
|
|
else if ( !fFilterEscPlus && dwDataLen >= 2 )
|
|
{
|
|
*pData++ = (HexCharToUINT( pScan[0] )<<4)
|
|
+ HexCharToUINT( pScan[1] );
|
|
dwWas -= 2;
|
|
pScan += 2;
|
|
dwDataLen -= 2;
|
|
}
|
|
else
|
|
{
|
|
*pData++ = '%';
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*pData++ = '%';
|
|
}
|
|
break;
|
|
|
|
case '+':
|
|
if ( !fFilterEscPlus )
|
|
{
|
|
*pData++ = ' ';
|
|
break;
|
|
}
|
|
// fall-through
|
|
|
|
default:
|
|
*pData ++ = (char)ch;
|
|
}
|
|
}
|
|
|
|
*pdwDataLen = dwWas;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoRequest::Init(
|
|
LPSTR pMsg,
|
|
int cMsg )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialize a HTMLA request from the associated ISAPI object
|
|
|
|
Arguments:
|
|
|
|
pMsg - message body. If NULL, uses the associated ISAPI
|
|
structure to retrieve message body
|
|
cMsg - message body length if pMsg is non NULL
|
|
|
|
Returns:
|
|
|
|
TRUE if success, FALSE if failure
|
|
|
|
--*/
|
|
{
|
|
BOOL fSt = TRUE;
|
|
BOOL fDoTrp = TRUE;
|
|
int cTotal;
|
|
|
|
if ( pMsg == NULL )
|
|
{
|
|
cMsg = m_pECB->cbAvailable;
|
|
cTotal = m_pECB->cbTotalBytes;
|
|
// work-around bug in IIS
|
|
if ( cMsg > cTotal )
|
|
{
|
|
cMsg = cTotal;
|
|
}
|
|
pMsg = (LPSTR)m_pECB->lpbData;
|
|
}
|
|
else
|
|
{
|
|
cTotal = cMsg;
|
|
fDoTrp = FALSE;
|
|
}
|
|
|
|
// get request body
|
|
m_pData = new char[cTotal + 1];
|
|
if ( m_pData == NULL )
|
|
{
|
|
return FALSE;
|
|
}
|
|
if ( (m_dwDataLen = cMsg) )
|
|
{
|
|
memcpy( m_pData, pMsg, cMsg );
|
|
}
|
|
if ( cMsg < cTotal )
|
|
{
|
|
DWORD dwRead = cTotal - cMsg;
|
|
if ( m_pECB->ReadClient( (HCONN)m_pECB->ConnID, m_pData + cMsg,
|
|
&dwRead ) )
|
|
{
|
|
m_dwDataLen += dwRead;
|
|
}
|
|
else
|
|
{
|
|
fSt = FALSE;
|
|
}
|
|
}
|
|
|
|
// Get the raw version of the entity data
|
|
// Bug NT-3643652
|
|
m_dwDataRawLen = m_dwDataLen;
|
|
m_pDataRaw = new char[m_dwDataRawLen + 1];
|
|
if( m_pDataRaw == NULL )
|
|
{
|
|
return FALSE;
|
|
}
|
|
memcpy( m_pDataRaw, m_pData, m_dwDataRawLen );
|
|
m_pDataRaw[m_dwDataRawLen] = '\0';
|
|
|
|
|
|
// Generate "Expires" header
|
|
|
|
m_pHeader = ALWAYS_EXPIRE;
|
|
|
|
// retrieve remote addr
|
|
|
|
char achAddr[64];
|
|
DWORD dwAddr = sizeof( achAddr );
|
|
if ( g_fFakeServer
|
|
|| !m_pECB->GetServerVariable( (HCONN)m_pECB->ConnID,
|
|
"REMOTE_ADDR",
|
|
achAddr,
|
|
&dwAddr ) )
|
|
{
|
|
achAddr[0] = '\0';
|
|
}
|
|
GetMapper()->SetRemoteAddr( achAddr );
|
|
|
|
// set host name
|
|
|
|
LPVOID *ppV;
|
|
LPSTR pS;
|
|
if ( GetMapper()->HostName( (LPVOID*)&ppV ) )
|
|
{
|
|
pS = *(LPSTR*)ppV;
|
|
if ( g_pszDefaultHostName != NULL )
|
|
{
|
|
strcpy( pS, g_pszDefaultHostName );
|
|
}
|
|
else
|
|
{
|
|
DWORD dwL = MAX_DOMAIN_LENGTH;
|
|
if ( m_pECB->GetServerVariable( (HCONN)m_pECB->ConnID,
|
|
"SERVER_NAME", pS, &dwL ) == FALSE )
|
|
{
|
|
*pS = '\0';
|
|
}
|
|
}
|
|
}
|
|
|
|
// retrieve HTTP server version
|
|
|
|
if ( g_achW3Version[0] == '\0' )
|
|
{
|
|
DWORD dwL = sizeof(g_achW3Version);
|
|
if ( m_pECB->GetServerVariable( (HCONN)m_pECB->ConnID,
|
|
"SERVER_SOFTWARE", g_achW3Version, &dwL ) == FALSE )
|
|
{
|
|
g_achW3Version[0] = '\0';
|
|
}
|
|
}
|
|
|
|
if ( fDoTrp )
|
|
{
|
|
// Handle request body for transparency
|
|
|
|
InlineFromTransparent( (LPBYTE)m_pData, &m_dwDataLen, FALSE );
|
|
m_pData[m_dwDataLen] = '\0';
|
|
}
|
|
|
|
// Handle query string for transparency
|
|
|
|
DWORD dwLQ = lstrlen( m_pParam );
|
|
InlineFromTransparent( (LPBYTE)m_pParam, &dwLQ, !fDoTrp );
|
|
if ( m_pParam[dwLQ] != '\0' )
|
|
{
|
|
m_pParam[dwLQ] = '\0';
|
|
}
|
|
|
|
return fSt;
|
|
}
|
|
|
|
|
|
LPSTR
|
|
CInetInfoRequest::HTTPStatusStringFromCode(
|
|
VOID )
|
|
{
|
|
for ( int x = 0 ; x < sizeof(g_aStatus)/sizeof(CStatusStringAndCode) ;
|
|
++x )
|
|
{
|
|
if ( g_aStatus[x].dwStatus == m_dwHTTPStatus )
|
|
{
|
|
return g_aStatus[x].achStatus;
|
|
}
|
|
}
|
|
|
|
return "";
|
|
}
|
|
|
|
|
|
DWORD
|
|
CInetInfoRequest::Done(
|
|
VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Send result from HTMLA request to the associated ISAPI object
|
|
|
|
Arguments:
|
|
|
|
None, uses internal m_dwHTTPStatus & message buffer
|
|
|
|
Returns:
|
|
|
|
ISAPI status, to be returned by the ExtensionProc
|
|
|
|
--*/
|
|
{
|
|
DWORD dwLen = 0;
|
|
DWORD dwS = HSE_STATUS_SUCCESS;
|
|
char achStatus[80];
|
|
|
|
if ( g_fFakeServer )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
switch ( m_dwHTTPStatus )
|
|
{
|
|
case HT_REPROCESS:
|
|
dwS = HSE_REPROCESS;
|
|
break;
|
|
|
|
case HT_REDIRECT:
|
|
//dwLen = m_eb.GetLen();
|
|
if ( !m_pECB->ServerSupportFunction( m_pECB->ConnID,
|
|
HSE_REQ_SEND_URL_REDIRECT_RESP,
|
|
m_eb.GetPtr(),
|
|
0,
|
|
NULL ) )
|
|
{
|
|
dwS = HSE_STATUS_ERROR;
|
|
}
|
|
break;
|
|
|
|
|
|
case HT_REDIRECTH:
|
|
if ( !m_pECB->ServerSupportFunction( m_pECB->ConnID,
|
|
HSE_REQ_SEND_URL_REDIRECT_RESP,
|
|
m_eb.GetPtr(),
|
|
0,
|
|
NULL ) )
|
|
{
|
|
dwS = HSE_STATUS_ERROR;
|
|
}
|
|
break;
|
|
|
|
case HT_DENIED:
|
|
#if defined(GENERATE_AUTH_HEADERS)
|
|
g_AuthReqs.Lock();
|
|
LPSTR pszAuthReqs = g_AuthReqs.GetAuthenticationListHeader();
|
|
|
|
if ( pszAuthReqs == NULL )
|
|
{
|
|
dwLen = 0;
|
|
}
|
|
else
|
|
{
|
|
dwLen = lstrlen( pszAuthReqs );
|
|
}
|
|
|
|
if ( !m_pECB->ServerSupportFunction( m_pECB->ConnID,
|
|
HSE_REQ_SEND_RESPONSE_HEADER,
|
|
g_achAccessDenied,
|
|
&dwLen,
|
|
(LPDWORD)pszAuthReqs ) )
|
|
{
|
|
dwS = HSE_STATUS_ERROR;
|
|
}
|
|
g_AuthReqs.UnLock();
|
|
break;
|
|
#else
|
|
dwLen = strlen(g_achAccessDeniedBody);
|
|
if ( !m_pECB->ServerSupportFunction( m_pECB->ConnID,
|
|
HSE_REQ_SEND_RESPONSE_HEADER,
|
|
g_achAccessDenied,
|
|
&dwLen,
|
|
(LPDWORD)g_achAccessDeniedBody ) )
|
|
{
|
|
dwS = HSE_STATUS_ERROR;
|
|
}
|
|
break;
|
|
#endif
|
|
|
|
case HT_NOT_FOUND:
|
|
dwLen = lstrlen( g_achNotFoundBody );
|
|
|
|
if ( !m_pECB->ServerSupportFunction( m_pECB->ConnID,
|
|
HSE_REQ_SEND_RESPONSE_HEADER,
|
|
g_achNotFound,
|
|
&dwLen,
|
|
(LPDWORD) g_achNotFoundBody ) )
|
|
{
|
|
dwS = HSE_STATUS_ERROR;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
HSE_SEND_HEADER_EX_INFO HSHEI;
|
|
memset( &HSHEI, 0, sizeof( HSHEI ) );
|
|
|
|
wsprintf( achStatus, "%d %s", m_dwHTTPStatus,
|
|
HTTPStatusStringFromCode() );
|
|
|
|
HSHEI.pszStatus = achStatus;
|
|
HSHEI.cchStatus = 0;
|
|
|
|
if ( m_dwHTTPStatus != HT_OK )
|
|
{
|
|
m_eb.Reset();
|
|
}
|
|
|
|
#if defined( _ENABLE_KEEP_ALIVE )
|
|
LPSTR pNewH = new char[ lstrlen( m_pHeader ) + 128 ];
|
|
if ( pNewH != NULL )
|
|
{
|
|
BOOL fKeep = FALSE;
|
|
m_pECB->ServerSupportFunction( m_pECB->ConnID,
|
|
HSE_REQ_IS_KEEP_CONN,
|
|
&fKeep,
|
|
0,
|
|
NULL );
|
|
|
|
strcpy( pNewH, m_pHeader );
|
|
wsprintf( pNewH + lstrlen(pNewH) - 2,
|
|
"%sContent-Length: %lu\r\n\r\n",
|
|
fKeep ? "Connection: keep-alive\r\n" : "",
|
|
m_eb.GetLen() );
|
|
|
|
dwLen = lstrlen( pNewH );
|
|
|
|
HSHEI.pszHeader = pNewH;
|
|
HSHEI.cchHeader = 0;
|
|
HSHEI.fKeepConn = fKeep;
|
|
|
|
if ( m_pECB->ServerSupportFunction( m_pECB->ConnID,
|
|
HSE_REQ_SEND_RESPONSE_HEADER_EX,
|
|
(LPVOID) &HSHEI,
|
|
NULL,
|
|
NULL ) )
|
|
{
|
|
dwS = fKeep
|
|
? HSE_STATUS_SUCCESS_AND_KEEP_CONN
|
|
: HSE_STATUS_SUCCESS ;
|
|
}
|
|
else
|
|
{
|
|
dwS = HSE_STATUS_ERROR;
|
|
}
|
|
|
|
delete [] pNewH;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
dwLen = lstrlen( m_pHeader );
|
|
|
|
HSHEI.pszHeader = m_pHeader;
|
|
HSHEI.cchHeader = 0;
|
|
|
|
if ( !m_pECB->ServerSupportFunction( m_pECB->ConnID,
|
|
HSE_REQ_SEND_RESPONSE_HEADER_EX,
|
|
(LPVOID) &HSHEI,
|
|
NULL,
|
|
NULL ) )
|
|
|
|
{
|
|
dwS = HSE_STATUS_ERROR;
|
|
}
|
|
}
|
|
|
|
if ( dwS != HSE_STATUS_ERROR )
|
|
{
|
|
dwLen = m_eb.GetLen();
|
|
|
|
//
|
|
// If WriteClient fails, nothing useful to do at this point,
|
|
// so ignore return value
|
|
//
|
|
|
|
m_pECB->WriteClient( m_pECB->ConnID,
|
|
m_eb.GetPtr(),
|
|
&dwLen,
|
|
0 );
|
|
}
|
|
|
|
}
|
|
|
|
return dwS;
|
|
}
|
|
|
|
|
|
LPSTR
|
|
CInetInfoRequest::GetVarAsString(
|
|
DWORD dwI,
|
|
BOOL *pfF )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Access the specified entry ( 0-based ) in the parameter list
|
|
of the associated verb context and returns the result as a string
|
|
|
|
Arguments:
|
|
|
|
dwI - index in the array of parameters ( 0-based )
|
|
pfF - updated with TRUE if buffer to be freed after usage
|
|
( using delete[] )
|
|
|
|
Returns:
|
|
|
|
pointer to string representation of parameter or NULL if error
|
|
|
|
--*/
|
|
{
|
|
LPSTR pResult;
|
|
DWORD dwResLen;
|
|
|
|
if ( m_pVerbContext->GetNbInfoMap() > dwI )
|
|
{
|
|
CInetInfoMap* pM = m_pVerbContext->GetInfoMap( dwI );
|
|
if ( pM->iType == ITYPE_PARAM_LIT_STRING )
|
|
{
|
|
*pfF = FALSE;
|
|
return pM->pName;
|
|
}
|
|
else if ( GetMapper()->GetString( pM, &pResult, &dwResLen, pfF ) )
|
|
{
|
|
return pResult;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
//
|
|
// HTMLA Verbs handling. verb is already parsed
|
|
//
|
|
// These functions are basically wrappers around functions in
|
|
// CInetInfoConfigInfoMapper
|
|
//
|
|
// The "HTMLA Arguments:" will indicates arguments for this function
|
|
// in a HTMLA script.
|
|
//
|
|
|
|
|
|
BOOL
|
|
CInetInfoRequest::AddDenyIPAccess(
|
|
VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Add an empty entry in the deny access IP list
|
|
This entry is to be set later by the HTMLA script
|
|
( the relevant variables will point to the newly created entry )
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
HTMLA Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE if success, otherwise FALSE
|
|
updates reqstatus
|
|
|
|
--*/
|
|
{
|
|
return GetMapper()->AddIPAccess( TRUE );
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoRequest::DeleteDenyIPAccess(
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Delete an entry in the deny access IP list
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
HTMLA Arguments:
|
|
|
|
access list entry reference
|
|
|
|
Returns:
|
|
|
|
TRUE if success, otherwise FALSE
|
|
updates reqstatus
|
|
|
|
--*/
|
|
{
|
|
LPSTR pV;
|
|
BOOL fF;
|
|
BOOL fSt = FALSE;
|
|
|
|
if ( (pV = GetVarAsString( 0, &fF )) != NULL )
|
|
{
|
|
fSt = GetMapper()->DeleteIPAccess( TRUE, pV );
|
|
if ( fF )
|
|
{
|
|
delete [] pV;
|
|
}
|
|
}
|
|
|
|
return fSt;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoRequest::PositionDenyIPAccess(
|
|
VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set the iteration counter ( m_iIter ) to point to the entry
|
|
matching the specified reference in the deny access list.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
HTMLA Arguments:
|
|
|
|
access list entry reference
|
|
|
|
Returns:
|
|
|
|
TRUE if success, otherwise FALSE
|
|
updates reqstatus
|
|
|
|
--*/
|
|
{
|
|
LPSTR pV;
|
|
BOOL fF;
|
|
BOOL fSt = FALSE;
|
|
|
|
if ( (pV = GetVarAsString( 0, &fF )) != NULL )
|
|
{
|
|
if ( GetMapper()->PositionIPAccess( TRUE, pV ) )
|
|
{
|
|
fSt = Update();
|
|
}
|
|
if ( fF )
|
|
{
|
|
delete [] pV;
|
|
}
|
|
}
|
|
|
|
return fSt;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoRequest::DefaultIsDenyIPAccess(
|
|
VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set the default condition to be denied access to the service
|
|
if the client address is not in the grant list
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
HTMLA Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE if success, otherwise FALSE
|
|
updates reqstatus
|
|
|
|
--*/
|
|
{
|
|
return GetMapper()->SetIPAccessDefault( TRUE );
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoRequest::AddGrantIPAccess(
|
|
VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Add an empty entry in the grant access IP list
|
|
This entry is to be set later by the HTMLA script
|
|
( the relevant variables will point to the newly created entry )
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
HTMLA Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE if success, otherwise FALSE
|
|
updates reqstatus
|
|
|
|
--*/
|
|
{
|
|
return GetMapper()->AddIPAccess( FALSE );
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoRequest::DeleteGrantIPAccess(
|
|
VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Delete an entry in the grant access IP list
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
HTMLA Arguments:
|
|
|
|
access list entry reference
|
|
|
|
Returns:
|
|
|
|
TRUE if success, otherwise FALSE
|
|
updates reqstatus
|
|
|
|
--*/
|
|
{
|
|
LPSTR pV;
|
|
BOOL fF;
|
|
BOOL fSt = FALSE;
|
|
|
|
if ( (pV = GetVarAsString( 0, &fF )) != NULL )
|
|
{
|
|
fSt = GetMapper()->DeleteIPAccess( FALSE, pV );
|
|
if ( fF )
|
|
{
|
|
delete [] pV;
|
|
}
|
|
}
|
|
|
|
return fSt;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoRequest::PositionGrantIPAccess(
|
|
VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set the iteration counter ( m_iIter ) to point to the entry
|
|
matching the specified reference in the grant access list.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
HTMLA Arguments:
|
|
|
|
access list entry reference
|
|
|
|
Returns:
|
|
|
|
TRUE if success, otherwise FALSE
|
|
updates reqstatus
|
|
|
|
--*/
|
|
{
|
|
LPSTR pV;
|
|
BOOL fF;
|
|
BOOL fSt = FALSE;
|
|
|
|
if ( (pV = GetVarAsString( 0, &fF )) != NULL )
|
|
{
|
|
if ( GetMapper()->PositionIPAccess( FALSE, pV ) )
|
|
{
|
|
fSt = Update();
|
|
}
|
|
if ( fF )
|
|
{
|
|
delete [] pV;
|
|
}
|
|
}
|
|
|
|
return fSt;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoRequest::DefaultIsGrantIPAccess(
|
|
VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set the default condition to be granted access to the service
|
|
if the client address is not in the deny list
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
HTMLA Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE if success, otherwise FALSE
|
|
updates reqstatus
|
|
|
|
--*/
|
|
{
|
|
return GetMapper()->SetIPAccessDefault( FALSE );
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoRequest::AddVirtDir(
|
|
VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Add an empty entry in the virtual root list
|
|
This entry is to be set later by the HTMLA script
|
|
( the relevant variables will point to the newly created entry )
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
HTMLA Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE if success, otherwise FALSE
|
|
updates reqstatus
|
|
|
|
--*/
|
|
{
|
|
return GetMapper()->AddVirtDir();
|
|
}
|
|
|
|
/* INTRINSA suppress=null_pointers, uninitialized */
|
|
BOOL
|
|
CInetInfoRequest::DeleteVirtDir(
|
|
VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Delete an entry in the grant access IP list
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
HTMLA Arguments:
|
|
|
|
virtual root list entry reference
|
|
|
|
Returns:
|
|
|
|
TRUE if success, otherwise FALSE
|
|
updates reqstatus
|
|
|
|
--*/
|
|
{
|
|
LPSTR pV;
|
|
BOOL fF;
|
|
BOOL fSt = FALSE;
|
|
|
|
if ( (pV = GetVarAsString( 0, &fF )) != NULL )
|
|
{
|
|
fSt = GetMapper()->DeleteVirtDir( pV );
|
|
if ( fF )
|
|
{
|
|
delete [] pV;
|
|
}
|
|
}
|
|
|
|
return fSt;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoRequest::PositionVirtDir(
|
|
VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set the iteration counter ( m_iIter ) to point to the entry
|
|
matching the specified reference in the virtual root list.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
HTMLA Arguments:
|
|
|
|
virtual root list entry reference
|
|
|
|
Returns:
|
|
|
|
TRUE if success, otherwise FALSE
|
|
updates reqstatus
|
|
|
|
--*/
|
|
{
|
|
LPSTR pV;
|
|
BOOL fF;
|
|
BOOL fSt = FALSE;
|
|
|
|
if ( (pV = GetVarAsString( 0, &fF )) != NULL )
|
|
{
|
|
fSt = GetMapper()->PositionVirtDir( pV );
|
|
if ( fF )
|
|
{
|
|
delete [] pV;
|
|
}
|
|
}
|
|
|
|
return fSt;
|
|
}
|
|
|
|
|
|
LPWSTR
|
|
CInetInfoRequest::AnsiToUnicode(
|
|
LPSTR psz
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Convert ANSI string to UNICODE
|
|
Storage will be automatically released at end of HTMLA request
|
|
|
|
Arguments:
|
|
|
|
psz - ANSI string
|
|
|
|
Returns:
|
|
|
|
pointer to UNICODE string or NULL if failure
|
|
updates reqstatus on failure.
|
|
|
|
--*/
|
|
{
|
|
UINT cL = strlen( psz );
|
|
LPWSTR pwsz = (LPWSTR)GetMapper()->Alloc( (cL+1)*sizeof(WCHAR) );
|
|
|
|
if ( pwsz && cL )
|
|
{
|
|
if ( !(cL = MultiByteToWideChar( CP_ACP, 0, psz, cL, pwsz, cL )) )
|
|
{
|
|
pwsz = NULL;
|
|
GetMapper()->SetRequestStatus( HTR_BAD_PARAM );
|
|
}
|
|
else
|
|
{
|
|
pwsz[cL] = L'\0';
|
|
}
|
|
}
|
|
|
|
return pwsz;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
CInetInfoRequest::GetUserFlags(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set the userflag variable with up to date info from GetUserInfo
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
HTMLA arguments:
|
|
|
|
UserAccout
|
|
|
|
Returns:
|
|
|
|
TRUE if success, otherwise FALSE
|
|
updates reqstatus, rpcstatus with return from NetUserChangePassword
|
|
|
|
--*/
|
|
{
|
|
LPSTR pUser;
|
|
BOOL fUser = FALSE;
|
|
PUSER_INFO_1 pUI1;
|
|
NET_API_STATUS s;
|
|
|
|
if ( (pUser = GetVarAsString( 0, &fUser )) )
|
|
{
|
|
//(pU = strchr( pUser, '\\' )) != NULL
|
|
LPWSTR pwszUser = AnsiToUnicode( pUser );
|
|
|
|
if ( pwszUser )
|
|
{
|
|
if ( (s = NetUserGetInfo( NULL, pwszUser, 1, (LPBYTE*)&pUI1)) == 0 )
|
|
{
|
|
GetMapper()->SetUserFlags( pUI1->usri1_flags );
|
|
}
|
|
else
|
|
{
|
|
GetMapper()->SetRequestStatus( HTR_VALIDATION_FAILED );
|
|
}
|
|
GetMapper()->SetRPCStatus( s );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if ( fUser )
|
|
{
|
|
delete [] pUser;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
CInetInfoRequest::SetHttpStatus(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set the HTTP status for the current request
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
HTMLA arguments:
|
|
|
|
Numeric status
|
|
|
|
Returns:
|
|
|
|
TRUE if success, otherwise FALSE
|
|
|
|
--*/
|
|
{
|
|
LPSTR pUser;
|
|
BOOL fUser = FALSE;
|
|
PUSER_INFO_1 pUI1;
|
|
NET_API_STATUS s;
|
|
|
|
if ( (pUser = GetVarAsString( 0, &fUser )) )
|
|
{
|
|
SetHTTPStatus( atol(pUser) );
|
|
}
|
|
else
|
|
{
|
|
GetMapper()->SetRequestStatus( HTR_BAD_PARAM );
|
|
return FALSE;
|
|
}
|
|
|
|
if ( fUser )
|
|
{
|
|
delete [] pUser;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoRequest::ChangePassword(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Change NT account pwd using user name, old pwd, new pwd
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
HTMLA arguments:
|
|
|
|
UserAccout OldPwd NewPwd
|
|
|
|
Returns:
|
|
|
|
TRUE if success, otherwise FALSE
|
|
updates reqstatus, rpcstatus with return from NetUserChangePassword
|
|
|
|
--*/
|
|
{
|
|
LPSTR pDomain;
|
|
LPSTR pUser;
|
|
LPSTR pOld;
|
|
LPSTR pNew;
|
|
LPSTR pTmp;
|
|
LPSTR pSep = NULL;
|
|
LPSTR pU = NULL;
|
|
BOOL fDomain = FALSE;
|
|
BOOL fUser = FALSE;
|
|
BOOL fOld = FALSE;
|
|
BOOL fNew = FALSE;
|
|
BOOL fSt = FALSE;
|
|
BOOL fGotAllParams = FALSE;
|
|
CHAR achDefaultDomain[DNLEN + 1];
|
|
|
|
NET_API_STATUS s;
|
|
|
|
GetMapper()->SetRPCStatus( 0 );
|
|
|
|
pDomain = GetVarAsString( 0, &fDomain );
|
|
pUser = GetVarAsString( 1, &fUser );
|
|
pOld = GetVarAsString( 2, &fOld );
|
|
pNew = GetVarAsString( 3, &fNew );
|
|
|
|
//
|
|
// We may have the user and domain in the pUser and pDomain fields or
|
|
// we may get both user and domain in the pUser field, in the form
|
|
// DOMAIN\USERNAME. In either case, try to split the information into
|
|
// two variables, pU and pUser, for domain and user name respectively.
|
|
//
|
|
|
|
if ( pUser )
|
|
{
|
|
//
|
|
// Got the domain as separate field
|
|
//
|
|
if ( pDomain && *pDomain )
|
|
{
|
|
pU = pDomain;
|
|
}
|
|
//
|
|
// Got domain\user as single field
|
|
//
|
|
else if ( (pU = (LPSTR)_mbschr( (LPBYTE)pUser, '\\' )) != NULL )
|
|
{
|
|
pSep = pU;
|
|
pU[0] = '\0';
|
|
pTmp = pU + 1;
|
|
pU = pUser;
|
|
pUser = pTmp;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If we still don't have a logon domain, try to retrieve the default
|
|
//
|
|
if (pU == NULL)
|
|
{
|
|
if ( g_pfnGetDefaultDomainName &&
|
|
g_pfnGetDefaultDomainName((LPSTR) &achDefaultDomain, DNLEN) )
|
|
{
|
|
pU = achDefaultDomain;
|
|
}
|
|
}
|
|
|
|
if ( pUser != NULL &&
|
|
pU != NULL &&
|
|
pOld != NULL &&
|
|
pNew != NULL
|
|
)
|
|
{
|
|
LPWSTR pwszDomain = pU ? AnsiToUnicode( pU ) : NULL;
|
|
LPWSTR pwszUser = AnsiToUnicode( pUser );
|
|
LPWSTR pwszOld = AnsiToUnicode( pOld );
|
|
LPWSTR pwszNew = AnsiToUnicode( pNew );
|
|
|
|
if ( pwszUser && pwszOld && pwszNew )
|
|
{
|
|
fGotAllParams = TRUE;
|
|
|
|
if ( (s = NetUserChangePassword( pwszDomain,
|
|
pwszUser,
|
|
pwszOld,
|
|
pwszNew )) != 0 )
|
|
{
|
|
GetMapper()->SetRPCStatus( s );
|
|
GetMapper()->SetRequestStatus( HTR_VALIDATION_FAILED );
|
|
}
|
|
}
|
|
|
|
if ( pSep )
|
|
{
|
|
*pSep = '\\';
|
|
}
|
|
}
|
|
|
|
//
|
|
// If we didn't get enough parameters, eg no user name or couldn't convert some of them into
|
|
// the correct format, set error status. We could set more specific error code, eg
|
|
// ERROR_INVALID_PASSWORD, ERROR_BAD_USERNAME, but this would be misleading if more than
|
|
// one of these error conditions happens, so just return generic "bad parameter"
|
|
//
|
|
if (!fGotAllParams)
|
|
{
|
|
GetMapper()->SetRPCStatus( ERROR_INVALID_PARAMETER );
|
|
GetMapper()->SetRequestStatus( HTR_BAD_PARAM );
|
|
}
|
|
|
|
if ( fDomain )
|
|
{
|
|
delete [] pDomain;
|
|
}
|
|
|
|
if ( fUser )
|
|
{
|
|
delete [] pUser;
|
|
}
|
|
|
|
if ( fOld )
|
|
{
|
|
delete [] pOld;
|
|
}
|
|
|
|
if ( fNew )
|
|
{
|
|
delete [] pNew;
|
|
}
|
|
|
|
return fSt;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoRequest::DisconnectUser(
|
|
VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Disconnect the user specified by a numeric ID from the service
|
|
mapped to this request.
|
|
This ID is an opaque numeric value returned by the server
|
|
in one of the RPC structure
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
HTMLA Arguments:
|
|
|
|
User numeric ID
|
|
|
|
Returns:
|
|
|
|
TRUE if success, otherwise FALSE
|
|
updates reqstatus
|
|
|
|
--*/
|
|
{
|
|
BOOL fSt = FALSE;
|
|
LPSTR pV;
|
|
BOOL fF;
|
|
|
|
if ( (pV = GetVarAsString( 0, &fF )) != NULL )
|
|
{
|
|
fSt = GetMapper()->DisconnectUser( pV );
|
|
if ( fF )
|
|
{
|
|
delete [] pV;
|
|
}
|
|
}
|
|
|
|
return fSt;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoRequest::DisconnectAll(
|
|
VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Disconnect all users from the service mapped to this request
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
HTMLA Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE if success, otherwise FALSE
|
|
updates reqstatus
|
|
|
|
--*/
|
|
{
|
|
return GetMapper()->DisconnectAll();
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoRequest::GetStatus(
|
|
VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Updates the HTMLA variables exposing the status of IP services
|
|
( HTTP, FTP, Gopher ) so that they can be accessed in the HTMLA
|
|
script.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
HTMLA Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE if success, otherwise FALSE
|
|
updates reqstatus
|
|
|
|
--*/
|
|
{
|
|
return GetMapper()->GetStatus();
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoRequest::ValidateDir(
|
|
VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Validate a directory path ( checks for existence )
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
HTMLA Arguments:
|
|
|
|
Directory path to validate
|
|
|
|
Returns:
|
|
|
|
TRUE if success, otherwise FALSE
|
|
updates reqstatus
|
|
|
|
--*/
|
|
{
|
|
BOOL fSt = FALSE;
|
|
LPSTR pV;
|
|
BOOL fF;
|
|
|
|
if ( (pV = GetVarAsString( 0, &fF )) != NULL )
|
|
{
|
|
fSt = GetMapper()->ValidateDir( pV );
|
|
if ( fF )
|
|
{
|
|
delete [] pV;
|
|
}
|
|
}
|
|
|
|
return fSt;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoRequest::CreateDir(
|
|
VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Validate a directory path ( checks for existence )
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
HTMLA Arguments:
|
|
|
|
- Directory path where to create directory
|
|
- Directory name to create ( w/o '\' )
|
|
|
|
Returns:
|
|
|
|
TRUE if success, otherwise FALSE
|
|
updates reqstatus
|
|
|
|
--*/
|
|
{
|
|
BOOL fSt = FALSE;
|
|
LPSTR pV1, pV2;
|
|
BOOL fF1 = FALSE, fF2 = FALSE;
|
|
|
|
pV1 = GetVarAsString( 0, &fF1 );
|
|
pV2 = GetVarAsString( 1, &fF2 );
|
|
|
|
if ( pV1 != NULL && pV2 != NULL )
|
|
{
|
|
fSt = GetMapper()->CreateDir( pV1, pV2 );
|
|
}
|
|
|
|
if ( fF1 )
|
|
{
|
|
delete [] pV1;
|
|
}
|
|
|
|
if ( fF2 )
|
|
{
|
|
delete [] pV2;
|
|
}
|
|
|
|
return fSt;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoRequest::CheckForVirtDir(
|
|
VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handle the _VIRT_DIR_REQ_CHECK command.
|
|
see HandleVirtDirRequest() below
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
updates reqstatus
|
|
|
|
--*/
|
|
{
|
|
return HandleVirtDirRequest( _VIRT_DIR_REQ_CHECK );
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoRequest::AliasVirtDir(
|
|
VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handle the _VIRT_DIR_REQ_ALIAS command.
|
|
see HandleVirtDirRequest() below
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
updates reqstatus
|
|
|
|
--*/
|
|
{
|
|
return HandleVirtDirRequest( _VIRT_DIR_REQ_ALIAS );
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoRequest::HandleVirtDirRequest(
|
|
int iReq )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handle a virtual root command. can be one of :
|
|
|
|
_VIRT_DIR_REQ_ALIAS : create an alias for the matching virtual root
|
|
by coalescing all alpha-numeric characters
|
|
from the virtual root physical path
|
|
|
|
_VIRT_DIR_REQ_CHECK : check for the existence of the specified
|
|
virtual root, set reqstatus to HTR_DIR_SAME_NAME
|
|
if present
|
|
|
|
Arguments:
|
|
|
|
iReq : a _VIRT_DIR_REQ_ command
|
|
|
|
HTMLA Arguments:
|
|
|
|
- Virtual root name ( e.g. "/scripts" )
|
|
- Virtual root IP address or empty string
|
|
|
|
Returns:
|
|
|
|
TRUE on success, FALSE on failure
|
|
updates reqstatus
|
|
|
|
--*/
|
|
{
|
|
BOOL fSt = FALSE;
|
|
LPSTR pV1, pV2;
|
|
BOOL fF1 = FALSE, fF2 = FALSE;
|
|
|
|
pV1 = GetVarAsString( 0, &fF1 );
|
|
pV2 = GetVarAsString( 1, &fF2 );
|
|
|
|
if ( pV1 != NULL && pV2 != NULL )
|
|
{
|
|
fSt = GetMapper()->HandleVirtDirRequest( pV1, pV2, iReq );
|
|
}
|
|
|
|
if ( fF1 )
|
|
{
|
|
delete [] pV1;
|
|
}
|
|
|
|
if ( fF2 )
|
|
{
|
|
delete [] pV2;
|
|
}
|
|
|
|
return fSt;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoRequest::GenerateDirList(
|
|
VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Generate the vairous lists used by the directory browsing capability
|
|
cf. CDriveView::GenerateDirList()
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
HTMLA Arguments:
|
|
|
|
Path of the root of the directory structure to browse
|
|
|
|
Returns:
|
|
|
|
TRUE if success, otherwise FALSE
|
|
updates reqstatus
|
|
|
|
--*/
|
|
{
|
|
BOOL fSt = FALSE;
|
|
LPSTR pV;
|
|
BOOL fF;
|
|
|
|
if ( (pV = GetVarAsString( 0, &fF )) != NULL )
|
|
{
|
|
fSt = GetMapper()->GenerateDirList( pV );
|
|
if ( fF )
|
|
{
|
|
delete [] pV;
|
|
}
|
|
}
|
|
|
|
return fSt;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoRequest::Clear(
|
|
VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Clear ( set to 0 ) a numeric HTMLA script variable
|
|
Used to clear variables used in HTML checkboxes, as an
|
|
unchecked box will not be transmitted in the FORM request
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
HTMLA Arguments:
|
|
|
|
HTMLA variable name
|
|
|
|
Returns:
|
|
|
|
TRUE if success, otherwise FALSE
|
|
updates reqstatus
|
|
|
|
--*/
|
|
{
|
|
BOOL fSt = TRUE;
|
|
|
|
LPSTR pResult;
|
|
DWORD dwResLen;
|
|
LPVOID pV;
|
|
|
|
|
|
if ( m_pVerbContext->GetNbInfoMap() > 0 )
|
|
{
|
|
CInetInfoMap *pMap = m_pVerbContext->GetInfoMap(0);
|
|
switch ( pMap->iType )
|
|
{
|
|
case ITYPE_DWORD:
|
|
case ITYPE_SHORTDW:
|
|
case ITYPE_BOOL:
|
|
case ITYPE_1K:
|
|
case ITYPE_1M:
|
|
(GetMapper()->*pMap->GetAddr)( (LPVOID*)&pV );
|
|
*(DWORD*)pV = 0;
|
|
(GetMapper()->*pMap->UpdateIndication)();
|
|
break;
|
|
|
|
default:
|
|
GetMapper()->SetRequestStatus( HTR_INVALID_VAR_TYPE );
|
|
fSt = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
GetMapper()->SetRequestStatus( HTR_BAD_PARAM );
|
|
fSt = FALSE;
|
|
}
|
|
|
|
return fSt;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoRequest::Update(
|
|
VOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Scan the request message body as a FORM request
|
|
updating HTMLA variables
|
|
If parsing successfull, calls the RPC layer to updates
|
|
the Web Server status.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
HTMLA Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
TRUE if success, otherwise FALSE
|
|
updates reqstatus
|
|
|
|
--*/
|
|
{
|
|
BOOL fSt = TRUE;
|
|
DWORD dwL;
|
|
LPSTR pV = m_pData; // request body
|
|
|
|
for ( ; *pV ; )
|
|
{
|
|
while ( isspace((UCHAR)(*pV)) )
|
|
{
|
|
++pV;
|
|
}
|
|
|
|
LPSTR pE = strchr( pV, '=' );
|
|
BOOL fIsLast = FALSE;
|
|
if ( pE != NULL )
|
|
{
|
|
// find end of value
|
|
|
|
LPSTR pN = strchr( pE + 1, '&' );
|
|
if ( pN == NULL )
|
|
{
|
|
if ( (pN = strchr( pE + 1, '\r' )) != NULL )
|
|
{
|
|
*pN = '\0';
|
|
}
|
|
if ( (pN = strchr( pE + 1, '\n' )) != NULL )
|
|
{
|
|
*pN = '\0';
|
|
}
|
|
|
|
fIsLast = TRUE;
|
|
}
|
|
else
|
|
{
|
|
*pN = '\0';
|
|
}
|
|
|
|
//TR_DEBUG( 0, "Update Mapping %s, value %s<p>", pV, pE+1 );
|
|
|
|
CInetInfoMap *pMap;
|
|
if ( GetMapper()->Map( (LPBYTE)pV, DIFF(pE-pV), &pMap ) )
|
|
{
|
|
if ( GetMapper()->PutString( pMap, pE + 1 ) == FALSE )
|
|
{
|
|
GetMapper()->SetRequestStatus( HTR_INVALID_FORM_PARAM );
|
|
fSt = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( fIsLast )
|
|
{
|
|
break;
|
|
}
|
|
pV = pN + 1;
|
|
}
|
|
else
|
|
{
|
|
GetMapper()->SetRequestStatus( HTR_INVALID_FORM_PARAM_NAME );
|
|
fSt = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// if success, call RPC to update server status
|
|
|
|
if ( fSt == TRUE )
|
|
{
|
|
PDWORD pdwI;
|
|
if ( GetMapper()->InvalidLogUpdate( (LPVOID*)&pdwI) && *pdwI )
|
|
{
|
|
GetMapper()->SetRequestStatus( HTR_INVALID_FORM_PARAM );
|
|
fSt = FALSE;
|
|
}
|
|
else
|
|
{
|
|
fSt = GetMapper()->Update();
|
|
}
|
|
}
|
|
|
|
return fSt;
|
|
}
|
|
|
|
|
|
////////////////////// Merger
|
|
|
|
CInetInfoMerger::CInetInfoMerger(
|
|
VOID )
|
|
{
|
|
}
|
|
|
|
|
|
CInetInfoMerger::~CInetInfoMerger(
|
|
VOID )
|
|
{
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoMerger::Init(
|
|
VOID )
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
CInetInfoMap *
|
|
CInetInfoMerger::GetVarMap(
|
|
CInetInfoConfigInfoMapper *pM,
|
|
LPBYTE pVS,
|
|
DWORD dwSize )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Retrieve the variable descriptor from variable name and mapper object
|
|
|
|
Arguments:
|
|
|
|
pM - pointer to mapper object
|
|
pVS - variable name
|
|
dwSize - size of variable name
|
|
|
|
Returns:
|
|
|
|
Variable descriptor
|
|
|
|
--*/
|
|
{
|
|
CInetInfoMap *pMap;
|
|
|
|
LPBYTE pName = (LPBYTE)memchr( pVS, '%', dwSize );
|
|
|
|
if ( pName != NULL )
|
|
{
|
|
CInetInfoMap *pMap;
|
|
if ( pM->Map( pVS, (DWORD)(pName - pVS), &pMap ) )
|
|
{
|
|
return pMap;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
LPSTR
|
|
CInetInfoMerger::AllocDup(
|
|
CInetInfoConfigInfoMapper *pM,
|
|
LPBYTE pDup,
|
|
DWORD dwL )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Duplicate a memory block using Alloc()
|
|
|
|
Arguments:
|
|
|
|
pM - mapper object providing the Alloc() function
|
|
pDup - memory block to duplicate
|
|
dwL - length of emory block to duplicate
|
|
|
|
Returns:
|
|
|
|
Duplicated memory block, zero-terminated, auto-deallocate
|
|
|
|
--*/
|
|
{
|
|
LPSTR pD = (LPSTR)pM->Alloc( dwL + 1 );
|
|
if ( pD == NULL )
|
|
{
|
|
return NULL;
|
|
}
|
|
memcpy( pD, pDup, dwL );
|
|
pD[dwL] = '\0';
|
|
|
|
return pD;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoMerger::GetToken(
|
|
LPBYTE pVS,
|
|
DWORD dwSize,
|
|
LPBYTE* pStart,
|
|
DWORD* pdwL )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Scan for token, returning its length
|
|
|
|
Arguments:
|
|
|
|
pVS - pointer to memory block to scan
|
|
dwSize - length of memory block to scan
|
|
pStart - updated with pointer to start of token
|
|
pdwL - updated with token length
|
|
|
|
Returns:
|
|
|
|
TRUE if succes, FALSE if failure
|
|
|
|
--*/
|
|
{
|
|
// skip initial spaces
|
|
|
|
while ( dwSize && *pVS == ' ' )
|
|
{
|
|
--dwSize;
|
|
++pVS;
|
|
}
|
|
|
|
*pStart = pVS;
|
|
|
|
// get length
|
|
|
|
LPBYTE pName = (LPBYTE)memchr( pVS, '%', dwSize );
|
|
if ( pName != NULL )
|
|
{
|
|
*pdwL = DIFF(pName - pVS);
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoMerger::Merge(
|
|
CInetInfoRequest* pR )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Merge a template ( .htr ) file with variables as exposed in the
|
|
context of the specified HTMLA request.
|
|
This function opens and closes the file for each request, no caching
|
|
is done. The file is mapped in memory for access.
|
|
|
|
Arguments:
|
|
|
|
pR - HTMLA request object, linked to a mapper object
|
|
|
|
Returns:
|
|
|
|
TRUE if succes, FALSE if failure
|
|
|
|
--*/
|
|
{
|
|
CInetInfoConfigInfoMapper *pM = pR->GetMapper();
|
|
CExtBuff *pB = pR->GetBuffer();
|
|
DWORD dwE;
|
|
BOOL fSt = TRUE;
|
|
|
|
// build filename, open file, map
|
|
|
|
HANDLE hFile;
|
|
HANDLE hFileMapping;
|
|
PBYTE pF;
|
|
DWORD dwFileSize;
|
|
char achFileName[MAX_PATH+1];
|
|
DWORD dwL;
|
|
int iIsSkip = HSS_NO_SKIP;
|
|
CExpr v1( pM ), v2( pM );
|
|
CRelop r1;
|
|
UINT cNestedIf = 0;
|
|
int aiNestedIf[MAX_NESTED_IF] = { 0 };
|
|
DWORD dwNewStat, dwOldStat = HTR_OK;
|
|
LPSTR pchGoto = NULL;
|
|
LPSTR pchOnError = NULL;
|
|
LPBYTE pStart;
|
|
BOOL fValid;
|
|
|
|
|
|
if ( pR->GetScr()[1] == ':' )
|
|
{
|
|
// absolute file name, keep as is
|
|
dwL = 0;
|
|
}
|
|
else
|
|
{
|
|
if ( g_fFakeServer )
|
|
{
|
|
strcpy( achFileName, "\\inetsrv\\scripts\\");
|
|
dwL = lstrlen( achFileName );
|
|
}
|
|
else
|
|
{
|
|
if ( (dwL = GetModuleFileName( g_hModule, achFileName, sizeof(achFileName) )) != 0 )
|
|
{
|
|
// back to last directory marker
|
|
char *p = (LPSTR)_mbsrchr((LPBYTE)achFileName, '\\');
|
|
dwL = (p) ? DIFF(p-achFileName)+1 : 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
strncpy( achFileName+dwL, pR->GetScr(), sizeof(achFileName) - dwL - 5 );
|
|
achFileName[ sizeof( achFileName ) - 1 ] = '\0';
|
|
if ( strchr( achFileName, '.' ) == NULL )
|
|
{
|
|
strcat( achFileName, ".htr" );
|
|
}
|
|
|
|
if ( (hFile = CreateFile( achFileName, GENERIC_READ, FILE_SHARE_READ,
|
|
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ))
|
|
!= INVALID_HANDLE_VALUE )
|
|
{
|
|
if( (hFileMapping = CreateFileMapping( hFile, NULL, PAGE_READONLY,
|
|
0, 0, NULL )) != NULL )
|
|
{
|
|
dwFileSize = GetFileSize( hFile, NULL );
|
|
if ( dwFileSize != 0xffffffff && (pF = (LPBYTE)MapViewOfFile(
|
|
hFileMapping, FILE_MAP_READ, 0, 0, 0 )) != NULL )
|
|
{
|
|
LPBYTE pS, pOS, pAfter = pF+dwFileSize;
|
|
|
|
// remembered position
|
|
LPBYTE pIterS = NULL;
|
|
DWORD dwIterFileSize;
|
|
DWORD dwIter = 0;
|
|
|
|
for ( pOS = pS = pF ; dwFileSize; pOS = pS )
|
|
{
|
|
// check for error raised ( only once )
|
|
if ( (dwNewStat = pM->GetRequestStatus()) != dwOldStat )
|
|
{
|
|
if ( dwOldStat == HTR_OK && pchOnError != NULL )
|
|
{
|
|
iIsSkip |= HSS_SKIP_GOTO;
|
|
// copy onerror label to goto target label
|
|
if ( (pchGoto = AllocDup( pM, (LPBYTE)pchOnError,
|
|
strlen(pchOnError) )) == NULL )
|
|
{
|
|
pR->SetHTTPStatus( HT_BAD_GATEWAY );
|
|
fSt = FALSE;
|
|
// can't continue parsing : nested errors
|
|
break;
|
|
}
|
|
}
|
|
dwOldStat = dwNewStat;
|
|
}
|
|
|
|
if ( (pS = (LPBYTE)memchr( pOS, '<', (size_t)dwFileSize ))
|
|
== NULL )
|
|
{
|
|
if ( !iIsSkip )
|
|
{
|
|
pB->CopyBuff( pOS, dwFileSize );
|
|
}
|
|
break; // end of file
|
|
}
|
|
|
|
// copy up to ( but not including ) '<'
|
|
if ( !iIsSkip )
|
|
{
|
|
pB->CopyBuff( pOS, DIFF(pS - pOS) );
|
|
}
|
|
|
|
++pS;
|
|
dwFileSize = DIFF(pAfter - pS);
|
|
|
|
if ( dwFileSize && *pS == '%' )
|
|
{
|
|
LPBYTE pVS = ++pS;
|
|
DWORD dwSize = --dwFileSize;
|
|
|
|
// skip to next '>'
|
|
while ( dwFileSize )
|
|
{
|
|
int c = *pS++;
|
|
--dwFileSize;
|
|
|
|
if ( c == '>' )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( dwSize && *pVS == '!' )
|
|
{
|
|
if ( !iIsSkip )
|
|
{
|
|
++pVS;
|
|
--dwSize;
|
|
|
|
// verb : must build CVerbContext
|
|
CVerbContext *pVerb = new CVerbContext();
|
|
if ( pVerb == NULL )
|
|
{
|
|
pR->SetHTTPStatus( HT_BAD_GATEWAY );
|
|
fSt = FALSE;
|
|
break;
|
|
}
|
|
DWORD dwL;
|
|
if ( dwL = pVerb->Parse( pM, pVS, dwSize ) )
|
|
{
|
|
pR->DoVerb( pVerb );
|
|
}
|
|
delete pVerb;
|
|
}
|
|
}
|
|
|
|
else if ( dwSize>sizeof(TOKEN_REDIRECT)-1
|
|
&& !memcmp( pVS, TOKEN_REDIRECT,
|
|
sizeof(TOKEN_REDIRECT)-1) )
|
|
{
|
|
if ( !iIsSkip )
|
|
{
|
|
pB->Reset();
|
|
}
|
|
}
|
|
|
|
else if ( dwSize>sizeof(TOKEN_REDIRECTH)-1
|
|
&& !memcmp( pVS, TOKEN_REDIRECTH,
|
|
sizeof(TOKEN_REDIRECTH)-1) )
|
|
{
|
|
if ( !iIsSkip )
|
|
{
|
|
pB->Reset();
|
|
}
|
|
}
|
|
|
|
else if ( dwSize>sizeof(TOKEN_END_REDIRECT)-1
|
|
&& !memcmp( pVS, TOKEN_END_REDIRECT,
|
|
sizeof(TOKEN_END_REDIRECT)-1) )
|
|
{
|
|
if ( !iIsSkip )
|
|
{
|
|
pB->CopyBuff( (LPBYTE)"", 1 ); // add delimiter
|
|
pR->SetHTTPStatus( HT_REDIRECT );
|
|
break;
|
|
}
|
|
}
|
|
|
|
else if ( dwSize>sizeof(TOKEN_END_REDIRECTH)-1
|
|
&& !memcmp( pVS, TOKEN_END_REDIRECTH,
|
|
sizeof(TOKEN_END_REDIRECTH)-1) )
|
|
{
|
|
if ( !iIsSkip )
|
|
{
|
|
pB->CopyBuff( (LPBYTE)"", 1 ); // add delimiter
|
|
pR->SetHTTPStatus( HT_REDIRECTH );
|
|
break;
|
|
}
|
|
}
|
|
|
|
else if ( dwSize>sizeof(TOKEN_POST)-1
|
|
&& !memcmp( pVS, TOKEN_POST,
|
|
sizeof(TOKEN_POST)-1) )
|
|
{
|
|
if ( !iIsSkip )
|
|
{
|
|
pB->Reset();
|
|
}
|
|
}
|
|
|
|
else if ( dwSize>sizeof(TOKEN_END_POST)-1
|
|
&& !memcmp( pVS, TOKEN_END_POST,
|
|
sizeof(TOKEN_END_POST)-1) )
|
|
{
|
|
if ( !iIsSkip )
|
|
{
|
|
pR->SetHTTPStatus( HT_REPROCESS );
|
|
break;
|
|
}
|
|
}
|
|
|
|
else if ( dwSize>sizeof(TOKEN_GOTO)-1
|
|
&& !memcmp( pVS, TOKEN_GOTO,
|
|
sizeof(TOKEN_GOTO)-1) )
|
|
{
|
|
if ( !iIsSkip )
|
|
{
|
|
pVS += sizeof(TOKEN_GOTO)-1;
|
|
dwSize -= sizeof(TOKEN_GOTO)-1;
|
|
// ignore all other skip status
|
|
// i.e. cancel If, BeginIteration status
|
|
iIsSkip = HSS_SKIP_GOTO;
|
|
// store goto target
|
|
if ( GetToken( pVS, dwSize, &pStart, &dwL ) )
|
|
{
|
|
if ( (pchGoto = AllocDup( pM, pStart,
|
|
dwL)) == NULL )
|
|
{
|
|
pR->SetHTTPStatus( HT_BAD_GATEWAY );
|
|
fSt = FALSE;
|
|
// can't continue parsing : nested errors
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pM->SetRequestStatus( HTR_BAD_PARAM );
|
|
}
|
|
}
|
|
}
|
|
|
|
else if ( dwSize>sizeof(TOKEN_LABEL)-1
|
|
&& !memcmp( pVS, TOKEN_LABEL,
|
|
sizeof(TOKEN_LABEL)-1) )
|
|
{
|
|
if ( iIsSkip&HSS_SKIP_GOTO )
|
|
{
|
|
pVS += sizeof(TOKEN_LABEL)-1;
|
|
dwSize -= sizeof(TOKEN_LABEL)-1;
|
|
if ( GetToken( pVS, dwSize, &pStart, &dwL ) )
|
|
{
|
|
if ( pchGoto && dwL == (DWORD)lstrlen(
|
|
pchGoto)
|
|
&& !memcmp( pStart, pchGoto, dwL ) )
|
|
{
|
|
iIsSkip &= ~HSS_SKIP_GOTO;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pM->SetRequestStatus( HTR_BAD_PARAM );
|
|
}
|
|
}
|
|
}
|
|
|
|
else if ( dwSize>sizeof(TOKEN_ONERROR)-1
|
|
&& !memcmp( pVS, TOKEN_ONERROR,
|
|
sizeof(TOKEN_ONERROR)-1) )
|
|
{
|
|
if ( !iIsSkip )
|
|
{
|
|
pVS += sizeof(TOKEN_ONERROR)-1;
|
|
dwSize -= sizeof(TOKEN_ONERROR)-1;
|
|
// store onerror target
|
|
if ( GetToken( pVS, dwSize, &pStart, &dwL ) )
|
|
{
|
|
if ( (pchOnError = AllocDup( pM, pStart,
|
|
dwL)) == NULL )
|
|
{
|
|
pR->SetHTTPStatus( HT_BAD_GATEWAY );
|
|
fSt = FALSE;
|
|
// can't continue parsing : no onerror target
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pM->SetRequestStatus( HTR_BAD_PARAM );
|
|
}
|
|
}
|
|
}
|
|
|
|
else if ( dwSize>sizeof(TOKEN_IF)-1
|
|
&& !memcmp( pVS, TOKEN_IF,
|
|
sizeof(TOKEN_IF)-1) )
|
|
{
|
|
if ( cNestedIf == MAX_NESTED_IF-1 )
|
|
{
|
|
pM->SetRequestStatus( HTR_TOO_MANY_NESTED_IF );
|
|
continue;
|
|
}
|
|
|
|
pVS += sizeof(TOKEN_IF)-1;
|
|
dwSize -= sizeof(TOKEN_IF)-1;
|
|
|
|
++cNestedIf;
|
|
if ( iIsSkip & (HSS_SKIP_IF|HSS_WAIT_ENDIF) )
|
|
{
|
|
aiNestedIf[cNestedIf] = HSS_WAIT_ENDIF;
|
|
}
|
|
else
|
|
{
|
|
aiNestedIf[cNestedIf] = HSS_NO_SKIP;
|
|
//iIsSkip &= ~HSS_SKIP_IF;
|
|
}
|
|
|
|
if ( iIsSkip )
|
|
{
|
|
continue;
|
|
}
|
|
as_if_token:
|
|
// get 1st var
|
|
if ( dwL = v1.Get( pVS, dwSize ) )
|
|
{
|
|
pVS += dwL;
|
|
dwSize -= dwL;
|
|
}
|
|
else
|
|
{
|
|
pM->SetRequestStatus( HTR_VAR_NOT_FOUND );
|
|
goto inv_if;
|
|
}
|
|
|
|
// get relop
|
|
if ( dwL = r1.Get( pVS, dwSize ) )
|
|
{
|
|
pVS += dwL;
|
|
dwSize -= dwL;
|
|
}
|
|
else
|
|
{
|
|
pM->SetRequestStatus( HTR_BAD_PARAM );
|
|
goto inv_if;
|
|
}
|
|
|
|
// get 2nd var
|
|
if ( dwL = v2.Get( pVS, dwSize ) )
|
|
{
|
|
pVS += dwL;
|
|
dwSize -= dwL;
|
|
}
|
|
else
|
|
{
|
|
pM->SetRequestStatus( HTR_VAR_NOT_FOUND );
|
|
goto inv_if;
|
|
}
|
|
|
|
if ( !r1.IsTrue( v1, v2, &fValid ) )
|
|
{
|
|
if ( !fValid )
|
|
{
|
|
pM->SetRequestStatus( HTR_INVALID_VAR_TYPE );
|
|
inv_if:
|
|
aiNestedIf[cNestedIf] = HSS_WAIT_ENDIF;
|
|
Adjust( &iIsSkip, aiNestedIf[cNestedIf] );
|
|
}
|
|
else
|
|
{
|
|
aiNestedIf[cNestedIf] = HSS_SKIP_IF;
|
|
Adjust( &iIsSkip, aiNestedIf[cNestedIf] );
|
|
}
|
|
}
|
|
}
|
|
else if ( dwSize>sizeof(TOKEN_ELSE)-1
|
|
&& !memcmp( pVS, TOKEN_ELSE,
|
|
sizeof(TOKEN_ELSE)-1) )
|
|
{
|
|
if ( aiNestedIf[cNestedIf] == HSS_SKIP_IF )
|
|
{
|
|
aiNestedIf[cNestedIf] = HSS_NO_SKIP;
|
|
}
|
|
else
|
|
{
|
|
aiNestedIf[cNestedIf] = HSS_WAIT_ENDIF;
|
|
}
|
|
Adjust( &iIsSkip, aiNestedIf[cNestedIf] );
|
|
}
|
|
else if ( dwSize>sizeof(TOKEN_ELIF)-1
|
|
&& !memcmp( pVS, TOKEN_ELIF,
|
|
sizeof(TOKEN_ELIF)-1) )
|
|
{
|
|
if ( aiNestedIf[cNestedIf] == HSS_SKIP_IF )
|
|
{
|
|
pVS += sizeof(TOKEN_ELIF)-1;
|
|
dwSize -= sizeof(TOKEN_ELIF)-1;
|
|
|
|
aiNestedIf[cNestedIf] = HSS_NO_SKIP;
|
|
Adjust( &iIsSkip, aiNestedIf[cNestedIf] );
|
|
goto as_if_token;
|
|
}
|
|
else
|
|
{
|
|
aiNestedIf[cNestedIf] = HSS_WAIT_ENDIF;
|
|
}
|
|
Adjust( &iIsSkip, aiNestedIf[cNestedIf] );
|
|
}
|
|
else if ( dwSize>sizeof(TOKEN_ENDIF)-1
|
|
&& !memcmp( pVS, TOKEN_ENDIF,
|
|
sizeof(TOKEN_ENDIF)-1) )
|
|
{
|
|
if ( cNestedIf )
|
|
{
|
|
--cNestedIf;
|
|
Adjust( &iIsSkip, aiNestedIf[cNestedIf] );
|
|
}
|
|
else
|
|
{
|
|
pM->SetRequestStatus( HTR_IF_UNDERFLOW );
|
|
}
|
|
}
|
|
else if ( dwSize>sizeof(TOKEN_BEGIN_ITERATION)-1
|
|
&& !memcmp( pVS, TOKEN_BEGIN_ITERATION,
|
|
sizeof(TOKEN_BEGIN_ITERATION)-1) )
|
|
{
|
|
// get counter
|
|
dwSize -= sizeof(TOKEN_BEGIN_ITERATION)-1;
|
|
pVS += sizeof(TOKEN_BEGIN_ITERATION)-1;
|
|
while ( dwSize && isspace((UCHAR)(*pVS)) )
|
|
{
|
|
--dwSize;
|
|
++pVS;
|
|
}
|
|
CInetInfoMap *pVar = GetVarMap( pM, pVS, dwSize );
|
|
DWORD *pdwV;
|
|
if ( pVar != NULL && (pVar->iType == ITYPE_DWORD
|
|
|| pVar->iType == ITYPE_BOOL) )
|
|
{
|
|
(pM->*pVar->GetAddr)( (LPVOID*)&pdwV );
|
|
dwIter = *pdwV;
|
|
}
|
|
else
|
|
{
|
|
pM->SetRequestStatus( HTR_VAR_NOT_FOUND );
|
|
dwIter = 0;
|
|
continue;
|
|
}
|
|
// remember position to loop on enditeration
|
|
pIterS = pS;
|
|
dwIterFileSize = dwFileSize;
|
|
pM->ResetIter();
|
|
if ( dwIter )
|
|
{
|
|
--dwIter;
|
|
}
|
|
else
|
|
{
|
|
iIsSkip |= HSS_SKIP_ITER;
|
|
}
|
|
}
|
|
else if ( dwSize>sizeof(TOKEN_END_ITERATION)-1
|
|
&& !memcmp( pVS, TOKEN_END_ITERATION,
|
|
sizeof(TOKEN_END_ITERATION)-1) )
|
|
{
|
|
pM->IncIter();
|
|
if ( dwIter )
|
|
{
|
|
--dwIter;
|
|
pS = pIterS;
|
|
dwFileSize = dwIterFileSize;
|
|
}
|
|
else
|
|
{
|
|
iIsSkip &= ~HSS_SKIP_ITER;
|
|
}
|
|
}
|
|
else if ( !iIsSkip )
|
|
{
|
|
// is a variable
|
|
LPSTR pRes;
|
|
DWORD dwResLen;
|
|
BOOL fFree;
|
|
LPBYTE pAF = (LPBYTE)memchr( pVS, '%', dwSize );
|
|
if ( pAF && pM->GetString( pVS, DIFF(pAF - pVS),
|
|
&pRes, &dwResLen, &fFree ) )
|
|
{
|
|
pB->CopyBuff( (LPBYTE)pRes, dwResLen );
|
|
if ( fFree )
|
|
{
|
|
delete [] pRes;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pM->SetRequestStatus( HTR_VAR_NOT_FOUND );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else if ( !iIsSkip )
|
|
{
|
|
pB->CopyBuff( (LPBYTE)"<", 1 );
|
|
}
|
|
}
|
|
|
|
UnmapViewOfFile( (LPVOID)pF );
|
|
}
|
|
else
|
|
{
|
|
pR->SetHTTPStatus( HT_BAD_GATEWAY );
|
|
fSt = FALSE;
|
|
}
|
|
|
|
CloseHandle( hFileMapping );
|
|
}
|
|
else
|
|
{
|
|
pR->SetHTTPStatus( HT_BAD_GATEWAY );
|
|
fSt = FALSE;
|
|
}
|
|
|
|
CloseHandle( hFile );
|
|
}
|
|
else
|
|
{
|
|
switch ( GetLastError() )
|
|
{
|
|
case ERROR_FILE_NOT_FOUND :
|
|
pR->SetHTTPStatus( HT_NOT_FOUND );
|
|
break;
|
|
|
|
case ERROR_ACCESS_DENIED:
|
|
pR->SetHTTPStatus( HT_DENIED );
|
|
break;
|
|
|
|
default:
|
|
|
|
pR->SetHTTPStatus( HT_SERVER_ERROR );
|
|
break;
|
|
}
|
|
|
|
fSt = FALSE;
|
|
}
|
|
|
|
return fSt;
|
|
}
|
|
|
|
|
|
////////////// Dispatcher
|
|
|
|
CInetInfoRequestMap g_aIReqMap[] = {
|
|
{ "display", &CInetInfoDispatcher::HandleDisplay, TRUE }, // all displays
|
|
} ;
|
|
|
|
|
|
CInetInfoDispatcher::CInetInfoDispatcher(
|
|
VOID )
|
|
{
|
|
}
|
|
|
|
|
|
CInetInfoDispatcher::~CInetInfoDispatcher(
|
|
VOID )
|
|
{
|
|
}
|
|
|
|
|
|
// map a service name to a CInetInfoConfigInfoMapper
|
|
|
|
CInetInfoConfigInfoMapper*
|
|
CInetInfoDispatcher::GetMapperFromString(
|
|
LPSTR pszServ )
|
|
{
|
|
if ( !strcmp( pszServ, "http" ) )
|
|
{
|
|
return &m_MapperHTTP;
|
|
}
|
|
else if ( !strcmp( pszServ, "ftp" ) )
|
|
{
|
|
return &m_MapperFTP;
|
|
}
|
|
else if ( !strcmp( pszServ, "gopher" ) )
|
|
{
|
|
return &m_MapperGOPHER;
|
|
}
|
|
else if ( !strcmp( pszServ, "dns" ) )
|
|
{
|
|
return &m_MapperDNS;
|
|
}
|
|
else if ( !strcmp( pszServ, "dir" ) )
|
|
{
|
|
return &m_MapperDIR;
|
|
}
|
|
|
|
// default is HTTP
|
|
return &m_MapperHTTP;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoDispatcher::HandleDisplay(
|
|
CInetInfoRequest* pR )
|
|
{
|
|
BOOL fSt = FALSE;
|
|
|
|
// display screen
|
|
|
|
fSt = m_IFMerger.Merge( pR );
|
|
|
|
return fSt;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CInetInfoDispatcher::Init(
|
|
VOID )
|
|
{
|
|
m_apH = g_aIReqMap;
|
|
m_cH = sizeof(g_aIReqMap)/sizeof(CInetInfoRequestMap);
|
|
|
|
// initialize mappers
|
|
m_MapperHTTP.Init( g_InetInfoConfigInfoMap,
|
|
sizeof(g_InetInfoConfigInfoMap)/sizeof(CInetInfoMap),
|
|
INET_HTTP_SVC_ID );
|
|
m_MapperFTP.Init( g_InetInfoConfigInfoMap,
|
|
sizeof(g_InetInfoConfigInfoMap)/sizeof(CInetInfoMap),
|
|
INET_FTP_SVC_ID );
|
|
m_MapperGOPHER.Init( g_InetInfoConfigInfoMap,
|
|
sizeof(g_InetInfoConfigInfoMap)/sizeof(CInetInfoMap),
|
|
INET_GOPHER_SVC_ID );
|
|
m_MapperDNS.Init( g_InetInfoConfigInfoMap,
|
|
sizeof(g_InetInfoConfigInfoMap)/sizeof(CInetInfoMap),
|
|
INET_DNS_SVC_ID );
|
|
|
|
m_MapperDIR.Init( g_InetInfoDirInfoMap,
|
|
sizeof(g_InetInfoDirInfoMap)/sizeof(CInetInfoMap),
|
|
INET_DIR );
|
|
|
|
// initialize merger
|
|
m_IFMerger.Init();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
DWORD
|
|
CInetInfoDispatcher::Invoke(
|
|
EXTENSION_CONTROL_BLOCK *pECB )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handle an ISAPI request.
|
|
|
|
Arguments:
|
|
|
|
pECB - pointer ISAPI object
|
|
|
|
Returns:
|
|
|
|
ISAPI status
|
|
|
|
--*/
|
|
{
|
|
LPSTR pScr;
|
|
CInetInfoConfigInfoMapper *pIFMapper;
|
|
LPSTR pParam;
|
|
LPSTR p;
|
|
DWORD dwS = HSE_STATUS_ERROR;
|
|
LPSTR pMsgBody = NULL;
|
|
int cMsgBody = 0;
|
|
LPSTR pQueryString = NULL;
|
|
|
|
#if 0
|
|
// check authentication
|
|
|
|
char achRemoteUser[128];
|
|
DWORD dwRemoteUser = sizeof( achRemoteUser );
|
|
if ( !g_fFakeServer )
|
|
{
|
|
if ( pECB->GetServerVariable( (HCONN)pECB->ConnID,
|
|
"REMOTE_USER", achRemoteUser, &dwRemoteUser ) == FALSE
|
|
|| achRemoteUser[0] == '\0' )
|
|
{
|
|
// send back authentication required header
|
|
#if defined(GENERATE_AUTH_HEADERS)
|
|
g_AuthReqs.Lock();
|
|
DWORD dwLen;
|
|
LPSTR pszAuthReqs = g_AuthReqs.GetAuthenticationListHeader();
|
|
if ( pszAuthReqs != NULL )
|
|
{
|
|
dwLen = lstrlen( pszAuthReqs );
|
|
pECB->ServerSupportFunction( pECB->ConnID,
|
|
HSE_REQ_SEND_RESPONSE_HEADER,
|
|
g_achAccessDenied,
|
|
&dwLen,
|
|
(LPDWORD)pszAuthReqs );
|
|
}
|
|
else
|
|
{
|
|
#if 0
|
|
dwLen = 0;
|
|
pECB->ServerSupportFunction( pECB->ConnID,
|
|
HSE_REQ_SEND_RESPONSE_HEADER,
|
|
"500 Authentication access failed",
|
|
&dwLen,
|
|
(LPDWORD)NULL );
|
|
#else
|
|
// no authentication method supported by server
|
|
// allow anonymous access ( likely to fail access to RPC,
|
|
// this will set reqstatus and give a chance to the .htr
|
|
// to handle it ).
|
|
g_AuthReqs.UnLock();
|
|
goto allow_in;
|
|
#endif
|
|
}
|
|
g_AuthReqs.UnLock();
|
|
dwS = HSE_STATUS_SUCCESS;
|
|
#else
|
|
DWORD dwLen = strlen(g_achAccessDeniedBody);
|
|
if ( !pECB->ServerSupportFunction( pECB->ConnID,
|
|
HSE_REQ_SEND_RESPONSE_HEADER,
|
|
g_achAccessDenied,
|
|
&dwLen,
|
|
(LPDWORD)g_achAccessDeniedBody ) )
|
|
{
|
|
dwS = HSE_STATUS_ERROR;
|
|
}
|
|
#endif
|
|
return dwS;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if ( pECB->lpszPathTranslated
|
|
&& pECB->lpszPathInfo[0]
|
|
&& pECB->lpszPathTranslated[0] )
|
|
{
|
|
if ( (pQueryString = new char[sizeof("dir/")
|
|
+ strlen( pECB->lpszQueryString ) + 1
|
|
+ strlen(pECB->lpszPathTranslated)]) == NULL )
|
|
{
|
|
return HSE_STATUS_ERROR;
|
|
}
|
|
memcpy( pQueryString, "dir/", sizeof("dir/")-1 );
|
|
strcpy( pQueryString + sizeof("dir/")-1, pECB->lpszPathTranslated );
|
|
strcat( pQueryString, "+" );
|
|
strcat( pQueryString, pECB->lpszQueryString );
|
|
}
|
|
|
|
allow_in:
|
|
|
|
if ( (p = strchr( pQueryString ? pQueryString : pECB->lpszQueryString,
|
|
'/' )) != NULL )
|
|
{
|
|
*p = '\0';
|
|
pIFMapper = GetMapperFromString( pQueryString
|
|
? pQueryString : pECB->lpszQueryString );
|
|
pScr = p + 1;
|
|
|
|
// Look for parameter ( exposed as %urlparam% ) after '+'
|
|
if ( (pParam = strchr( pScr, '+' )) != NULL )
|
|
{
|
|
if ( pParam > pScr && pParam[-1] == '%' )
|
|
{
|
|
pParam[-1] = '\0';
|
|
}
|
|
else
|
|
{
|
|
*pParam = '\0';
|
|
}
|
|
++pParam;
|
|
}
|
|
else
|
|
{
|
|
pParam = "";
|
|
}
|
|
|
|
UINT iH = 0;
|
|
|
|
CInetInfoRequest *pR = new CInetInfoRequest( pECB, pIFMapper,
|
|
pScr, pParam );
|
|
#if defined(DEBUG_LEVEL)
|
|
g_pReq = pR;
|
|
#endif
|
|
BOOL fSt = FALSE;
|
|
|
|
if ( pR != NULL && pR->Init( pMsgBody, cMsgBody ) )
|
|
{
|
|
// current methods are all Std
|
|
if ( m_apH[iH].fIsStd )
|
|
{
|
|
// Standard shell : retrieve info inside lock
|
|
pIFMapper->Lock();
|
|
pIFMapper->SetRequestStatus( HTR_OK );
|
|
pIFMapper->SetURLParam( pParam );
|
|
pIFMapper->SetReqParam( pR->GetData(), pR, pR->GetDataRaw() );
|
|
pIFMapper->GetCurrentConfig();
|
|
if ( pIFMapper->GetRPCStatus() == ERROR_ACCESS_DENIED )
|
|
{
|
|
pR->SetHTTPStatus( HT_DENIED );
|
|
fSt = TRUE;
|
|
}
|
|
else
|
|
{
|
|
fSt = (this->*m_apH[iH].pHandler)( pR );
|
|
}
|
|
pIFMapper->FreeInfo();
|
|
pIFMapper->UnLock();
|
|
}
|
|
else
|
|
{
|
|
fSt = (this->*m_apH[iH].pHandler)( pR );
|
|
}
|
|
|
|
//
|
|
// Always send back the response to the client
|
|
//
|
|
DWORD dwStatus = pR->Done();
|
|
|
|
dwS = fSt ? dwStatus : HSE_STATUS_ERROR;
|
|
|
|
if ( pMsgBody )
|
|
{
|
|
delete [] pMsgBody;
|
|
}
|
|
|
|
if ( pQueryString )
|
|
{
|
|
delete [] pQueryString;
|
|
}
|
|
|
|
if ( dwS == HSE_REPROCESS )
|
|
{
|
|
// store msg body, query string
|
|
LPSTR pB = (LPSTR)pR->GetBuffer()->GetPtr();
|
|
LPSTR pD = strchr( pB ? pB : "", '?' );
|
|
if ( pD != NULL )
|
|
{
|
|
cMsgBody = pR->GetBuffer()->GetLen() - DIFF( pD - pB ) - 1;
|
|
pQueryString = new char[ DIFF(pD - pB) + 1 ];
|
|
pMsgBody = new char[ cMsgBody + 1];
|
|
if ( pQueryString == NULL || pMsgBody == NULL )
|
|
goto no_rep;
|
|
DelimStrcpyN( pQueryString, pB, DIFF(pD - pB) );
|
|
DelimStrcpyN( pMsgBody, pB + ( pD - pB ) + 1, cMsgBody++ );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
no_rep:
|
|
pMsgBody = NULL;
|
|
cMsgBody = 0;
|
|
pQueryString = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DWORD dwLen = 0;
|
|
pECB->ServerSupportFunction( pECB->ConnID,
|
|
HSE_REQ_SEND_RESPONSE_HEADER,
|
|
g_achInternalError,
|
|
&dwLen,
|
|
NULL );
|
|
dwS = HSE_STATUS_SUCCESS;
|
|
}
|
|
if ( pR != NULL )
|
|
{
|
|
delete pR;
|
|
}
|
|
}
|
|
|
|
if ( dwS == HSE_REPROCESS )
|
|
{
|
|
goto allow_in;
|
|
}
|
|
|
|
return dwS;
|
|
}
|
|
|
|
|
|
///////////// CExpr, CRelop
|
|
|
|
// Get an expr, returns length of relop token or 0 if error
|
|
// expr can be either a var reference or an unsigned numeric literal
|
|
|
|
DWORD
|
|
CExpr::Get(
|
|
LPBYTE pS,
|
|
DWORD dwL )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Parse memory block for expression
|
|
expression can one of :
|
|
- variable name
|
|
- numeric literal
|
|
- string literal ( inside "" )
|
|
|
|
Arguments:
|
|
|
|
pS - memory block to parse
|
|
dwL - size of memory block to parse
|
|
|
|
Returns:
|
|
|
|
# of bytes consumed to parse the expression or 0 if error
|
|
|
|
--*/
|
|
{
|
|
DWORD dwW = dwL;
|
|
int c;
|
|
|
|
// check if this object is re-used from previous call
|
|
if ( m_fMustFree )
|
|
{
|
|
delete [] m_pV;
|
|
m_fMustFree = FALSE;
|
|
}
|
|
|
|
// skip white space
|
|
while ( dwL && *pS == ' ' )
|
|
{
|
|
++pS;
|
|
--dwL;
|
|
}
|
|
|
|
LPBYTE pW = pS;
|
|
DWORD dwLenTok = 0;
|
|
DWORD dwRes;
|
|
|
|
// get until '%', ' '
|
|
while ( dwL && (c=*pS)!='%' && c!=' ' )
|
|
{
|
|
++dwLenTok;
|
|
++pS;
|
|
--dwL;
|
|
}
|
|
|
|
if ( dwLenTok )
|
|
{
|
|
if ( *pW>='0' && *pW<='9' )
|
|
{
|
|
// litteral num
|
|
m_dwV = MultiByteToDWORD( (LPSTR)pW );
|
|
m_iType = ITYPE_DWORD;
|
|
return dwW - dwL;
|
|
}
|
|
else if ( *pW == '"' )
|
|
{
|
|
// String literal
|
|
|
|
m_pV = new char[ dwLenTok - 1 ];
|
|
if ( m_pV != NULL )
|
|
{
|
|
memcpy( m_pV, pW + 1, dwLenTok - 2 );
|
|
m_pV[ dwLenTok - 2 ] = '\0';
|
|
m_iType = ITYPE_LPSTR;
|
|
m_fMustFree = TRUE;
|
|
return dwW - dwL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CInetInfoMap* pMap;
|
|
if ( m_pMap->Map( pW, dwLenTok, &pMap ) )
|
|
{
|
|
if ( pMap->iType == ITYPE_BOOL
|
|
|| pMap->iType == ITYPE_DWORD
|
|
|| pMap->iType == ITYPE_SHORT
|
|
|| pMap->iType == ITYPE_SHORTDW )
|
|
{
|
|
LPVOID pV;
|
|
if ( (m_pMap->*pMap->GetAddr)( (LPVOID*)&pV ) )
|
|
{
|
|
m_dwV = pMap->iType == ITYPE_SHORT
|
|
? (DWORD)*(unsigned short*)pV : *(DWORD*)pV;
|
|
m_iType = ITYPE_DWORD;
|
|
return dwW - dwL;
|
|
}
|
|
}
|
|
else if ( m_pMap->GetString( pMap,
|
|
&m_pV, &dwLenTok, &m_fMustFree ) )
|
|
{
|
|
m_iType = ITYPE_LPSTR;
|
|
return dwW - dwL;
|
|
}
|
|
}
|
|
else if ( m_pMap->GetString( pW, dwLenTok,
|
|
&m_pV, &dwRes, &m_fMustFree ) )
|
|
{
|
|
m_iType = ITYPE_LPSTR;
|
|
return dwW - dwL;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0; // error
|
|
}
|
|
|
|
|
|
DWORD
|
|
CExpr::GetAsDWORD(
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns content as a DWORD, converting from string to DWORD
|
|
if type is LPSR
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
Value of object
|
|
|
|
--*/
|
|
{
|
|
if ( m_iType == ITYPE_DWORD )
|
|
{
|
|
return m_dwV;
|
|
}
|
|
else if ( m_iType == ITYPE_LPSTR )
|
|
{
|
|
return MultiByteToDWORD( m_pV );
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
// relop list. Must be in sync with the RELOP_TYPE enum type.
|
|
|
|
LPSTR RELOP_TOKS[] = {
|
|
"~~", // invalid, not used
|
|
"EQ",
|
|
"NE",
|
|
"GT",
|
|
"LT",
|
|
"GE",
|
|
"LE",
|
|
"RF",
|
|
"BA",
|
|
} ;
|
|
|
|
|
|
DWORD
|
|
CRelop::Get(
|
|
LPBYTE pS,
|
|
DWORD dwL )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Parse memory block for relational operator
|
|
as defined in RELOP_TOKS
|
|
|
|
Arguments:
|
|
|
|
pS - memory block to parse
|
|
dwL - size of memory block to parse
|
|
|
|
Returns:
|
|
|
|
# of bytes consumed to parse the operator or 0 if error
|
|
|
|
--*/
|
|
{
|
|
DWORD dwW = dwL;
|
|
UINT c;
|
|
|
|
// skip white space
|
|
while ( dwL && *pS == ' ' )
|
|
{
|
|
++pS;
|
|
--dwL;
|
|
}
|
|
|
|
LPBYTE pW = pS;
|
|
DWORD dwLenTok = 0;
|
|
|
|
// get until '%', ' '
|
|
while ( dwL && (c=*pS)!='%' && c!=' ' )
|
|
{
|
|
++dwLenTok;
|
|
++pS;
|
|
--dwL;
|
|
}
|
|
|
|
if ( dwLenTok == 2 )
|
|
{
|
|
int x;
|
|
for ( x = 1 ; x < sizeof(RELOP_TOKS)/sizeof(LPSTR) ; ++x )
|
|
{
|
|
if ( !memcmp( RELOP_TOKS[x], pW, 2 ) )
|
|
{
|
|
m_iType = (RELOP_TYPE)x;
|
|
return dwW - dwL;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0; // error
|
|
}
|
|
|
|
|
|
// return TRUE if v1 RELOP v2 is TRUE
|
|
// handle only LPSTR and DWORD types
|
|
|
|
BOOL
|
|
CRelop::IsTrue(
|
|
CExpr& v1,
|
|
CExpr& v2,
|
|
BOOL *pfValid )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Test the specified expressions with the current relational operator
|
|
|
|
Arguments:
|
|
|
|
v1 - left expression
|
|
v2 - right expression
|
|
pfValid - updated with FALSE is expression is invalid, else TRUE
|
|
|
|
Returns:
|
|
|
|
TRUE if v1 relop v2 is TRUE, otherwise FALSE
|
|
|
|
--*/
|
|
{
|
|
int iC;
|
|
DWORD num1, num2;
|
|
|
|
*pfValid = TRUE;
|
|
|
|
if ( v1.GetType() != v2.GetType() )
|
|
{
|
|
if ( (v1.GetType() == ITYPE_DWORD && v2.GetType() == ITYPE_LPSTR)
|
|
|| (v1.GetType() == ITYPE_LPSTR && v2.GetType() == ITYPE_DWORD) )
|
|
{
|
|
goto as_dword;
|
|
}
|
|
*pfValid = FALSE;
|
|
return FALSE;
|
|
}
|
|
else if ( v1.GetType() == ITYPE_DWORD )
|
|
{
|
|
as_dword:
|
|
iC = (v1.GetAsDWORD() < v2.GetAsDWORD()) ? -1
|
|
: ((v1.GetAsDWORD() == v2.GetAsDWORD()) ? 0 : 1);
|
|
}
|
|
else if ( v1.GetType() == ITYPE_LPSTR )
|
|
{
|
|
if ( m_iType != RELOP_RF )
|
|
{
|
|
iC = lstrcmp( v1.GetAsStr(), v2.GetAsStr() );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
iC = 0;
|
|
}
|
|
|
|
BOOL fR;
|
|
LPSTR pV;
|
|
LPSTR p2;
|
|
DWORD dwL2;
|
|
|
|
switch ( m_iType )
|
|
{
|
|
case RELOP_EQ: fR = iC == 0; break;
|
|
case RELOP_NE: fR = iC != 0; break;
|
|
case RELOP_GT: fR = iC > 0; break;
|
|
case RELOP_LT: fR = iC < 0; break;
|
|
case RELOP_GE: fR = iC >= 0; break;
|
|
case RELOP_LE: fR = iC <= 0; break;
|
|
|
|
case RELOP_BA: fR = !!(v1.GetAsDWORD() & v2.GetAsDWORD());
|
|
break;
|
|
|
|
case RELOP_RF:
|
|
fR = FALSE;
|
|
|
|
if ( v1.GetType() == ITYPE_LPSTR )
|
|
{
|
|
// parse v1 for v2
|
|
pV = v1.GetAsStr();
|
|
p2 = v2.GetAsStr();
|
|
dwL2 = lstrlen( p2 );
|
|
|
|
for ( ; *pV ; )
|
|
{
|
|
while ( isspace((UCHAR)(*pV)) )
|
|
{
|
|
++pV;
|
|
}
|
|
|
|
LPSTR pE = strchr( pV, '=' );
|
|
BOOL fIsLast = FALSE;
|
|
if ( pE != NULL )
|
|
{
|
|
LPSTR pN = strchr( pE + 1, '&' );
|
|
if ( pN == NULL )
|
|
{
|
|
fIsLast = TRUE;
|
|
}
|
|
|
|
//TR_DEBUG( 0, "Update Mapping %s, value %s<p>", pV, pE+1 );
|
|
|
|
if ( (DWORD)(pE-pV) == dwL2
|
|
&& !memcmp( pV, p2, DIFF(pE-pV) ) )
|
|
{
|
|
fR = TRUE;
|
|
break;
|
|
}
|
|
|
|
if ( fIsLast )
|
|
{
|
|
break;
|
|
}
|
|
|
|
pV = pN + 1;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
default: fR = FALSE; break;
|
|
}
|
|
|
|
return fR;
|
|
}
|
|
|
|
|
|
/////////////
|
|
|
|
CInetInfoDispatcher g_InetInfoDispatcher;
|
|
|
|
/////////////
|
|
|
|
|
|
// version information
|
|
|
|
extern "C" BOOL WINAPI
|
|
GetExtensionVersion(
|
|
HSE_VERSION_INFO *version
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
ISAPI function : called once to return version #
|
|
|
|
Arguments:
|
|
|
|
version - updated with version #
|
|
|
|
Returns:
|
|
|
|
TRUE if initialization success, else FALSE
|
|
|
|
--*/
|
|
{
|
|
version->dwExtensionVersion
|
|
= MAKELONG(HSE_VERSION_MINOR, HSE_VERSION_MAJOR);
|
|
|
|
strcpy(version->lpszExtensionDesc, "ism.dll v1.0");
|
|
|
|
if ( !g_InitDone )
|
|
{
|
|
g_InetInfoDispatcher.Init();
|
|
#if defined(GENERATE_AUTH_HEADERS)
|
|
g_AuthReqs.Init();
|
|
#endif
|
|
// initialize host name
|
|
|
|
char hn[MAX_DOMAIN_LENGTH + 1];
|
|
struct hostent FAR* pH;
|
|
if ( !gethostname( hn, sizeof(hn) )
|
|
&& (pH = gethostbyname( hn ))
|
|
&& pH->h_name
|
|
&& pH->h_addr_list
|
|
&& pH->h_addr_list[0]
|
|
)
|
|
{
|
|
g_pszDefaultHostName = new char[strlen( pH->h_name ) + 1];
|
|
if ( g_pszDefaultHostName == NULL )
|
|
{
|
|
return FALSE;
|
|
}
|
|
strcpy( g_pszDefaultHostName, pH->h_name );
|
|
}
|
|
|
|
// initialize htmla path
|
|
|
|
HKEY hK;
|
|
BOOL fDef = TRUE;
|
|
if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
|
W3SVC_REGISTRY_PATH,
|
|
0,
|
|
KEY_READ,
|
|
&hK ) == ERROR_SUCCESS )
|
|
{
|
|
DWORD dwType;
|
|
DWORD cData = sizeof( g_achHtmlaPath );
|
|
if ( RegQueryValueEx( hK, W3SVC_REGISTRY_HTMLAPATH,
|
|
NULL, &dwType, (PBYTE)g_achHtmlaPath, &cData )
|
|
== ERROR_SUCCESS && dwType == REG_SZ )
|
|
{
|
|
fDef = FALSE;
|
|
}
|
|
RegCloseKey( hK );
|
|
}
|
|
if ( fDef )
|
|
{
|
|
strcpy( g_achHtmlaPath, "/htmla" );
|
|
}
|
|
|
|
//
|
|
// init strings from resources
|
|
//
|
|
|
|
if ( LoadString( g_hModule,
|
|
IDS_HTRESPX_DENIED,
|
|
g_achAccessDenied,
|
|
sizeof( g_achAccessDenied ) ) == 0 )
|
|
{
|
|
strcpy( g_achAccessDenied, "401" );
|
|
}
|
|
|
|
if ( LoadString( g_hModule,
|
|
IDS_HTRESPX_DENIED_BODY,
|
|
g_achAccessDeniedBody,
|
|
sizeof( g_achAccessDeniedBody ) ) == 0 )
|
|
{
|
|
strcpy( g_achAccessDeniedBody, "<html>Error: access denied</html>" );
|
|
}
|
|
|
|
if ( LoadString( g_hModule,
|
|
IDS_HTRESPX_SERVER_ERROR,
|
|
g_achInternalError,
|
|
sizeof( g_achInternalError ) ) == 0 )
|
|
{
|
|
strcpy( g_achInternalError, "500" );
|
|
}
|
|
|
|
if ( LoadString( g_hModule,
|
|
IDS_HTRESPX_NOT_FOUND,
|
|
g_achNotFound,
|
|
sizeof( g_achNotFound ) ) == 0 )
|
|
{
|
|
strcpy( g_achNotFound, "404" );
|
|
}
|
|
|
|
if ( LoadString( g_hModule,
|
|
IDS_HTRESPX_NOT_FOUND_BODY,
|
|
g_achNotFoundBody,
|
|
sizeof( g_achNotFoundBody ) ) == 0 )
|
|
{
|
|
strcpy( g_achNotFoundBody,
|
|
"<html>Error : The requested file could not be found.</html>" );
|
|
}
|
|
|
|
for ( int x = 0 ;
|
|
x < sizeof(g_aStatus)/sizeof(CStatusStringAndCode) ;
|
|
++x )
|
|
{
|
|
if ( LoadString( g_hModule,
|
|
g_aStatus[x].dwID,
|
|
g_aStatus[x].achStatus,
|
|
sizeof( g_aStatus[x].achStatus ) ) == 0 )
|
|
{
|
|
wsprintf( g_aStatus[x].achStatus,
|
|
"%d",
|
|
g_aStatus[x].dwStatus );
|
|
}
|
|
}
|
|
|
|
g_InitDone = TRUE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
extern "C" DWORD WINAPI
|
|
HttpExtensionProc(
|
|
EXTENSION_CONTROL_BLOCK* pEcb
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
ISAPI function : called for each incoming HTTP request
|
|
|
|
Arguments:
|
|
|
|
pEcb - pointer to ISAPI request object
|
|
|
|
Returns:
|
|
|
|
ISAPI status
|
|
|
|
--*/
|
|
{
|
|
return g_InetInfoDispatcher.Invoke( pEcb );
|
|
}
|
|
|
|
|
|
extern "C" BOOL WINAPI
|
|
DllMain(
|
|
HANDLE hModule,
|
|
DWORD dwReason,
|
|
LPVOID )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
DLL init/terminate notification function
|
|
|
|
Arguments:
|
|
|
|
hModule - DLL handle
|
|
dwReason - notification type
|
|
LPVOID - not used
|
|
|
|
Returns:
|
|
|
|
TRUE if success, FALSE if failure
|
|
|
|
--*/
|
|
{
|
|
switch ( dwReason )
|
|
{
|
|
case DLL_PROCESS_ATTACH:
|
|
// record the module handle to access module info later
|
|
g_hModule = (HINSTANCE)hModule;
|
|
if ( g_hLonsi = LoadLibrary("lonsint.dll") )
|
|
{
|
|
g_pfnGetDefaultDomainName = (GET_DEFAULT_DOMAIN_NAME_FN)
|
|
GetProcAddress( g_hLonsi, "IISGetDefaultDomainName" );
|
|
}
|
|
break;
|
|
|
|
case DLL_PROCESS_DETACH:
|
|
#if defined(GENERATE_AUTH_HEADERS)
|
|
g_AuthReqs.Terminate();
|
|
#endif
|
|
if ( g_hLonsi )
|
|
{
|
|
g_pfnGetDefaultDomainName = NULL;
|
|
FreeLibrary( g_hLonsi );
|
|
g_hLonsi = NULL;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
// Test shell. To be used to simulate a BGI call using a console app.
|
|
|
|
BYTE achTest[]="rootdir=c:\\inetsrv&rootishome=0&rootname=/w&rootacctname=&rootacctpw=&rootaddr=&rootisread=1";
|
|
|
|
void __declspec( dllexport )
|
|
Test(
|
|
VOID )
|
|
{
|
|
HSE_VERSION_INFO hv;
|
|
EXTENSION_CONTROL_BLOCK Ecb;
|
|
|
|
Ecb.cbTotalBytes = sizeof(achTest);
|
|
Ecb.cbAvailable = sizeof(achTest);
|
|
Ecb.lpbData = achTest;
|
|
//Ecb.lpszQueryString = "http/w3/advdeny+/-c:\\inetsrv\\wwwroot";
|
|
Ecb.lpszQueryString = "http/w3/serv+/syuyr!/ttt";
|
|
printf( "Nb Handler : %d\n", g_InetInfoDispatcher.GetNbH() );
|
|
|
|
GetExtensionVersion( &hv );
|
|
g_fFakeServer = TRUE;
|
|
HttpExtensionProc( &Ecb );
|
|
}
|