FORMDUMP.CPP

/*++ 

Copyright (c) 1997 Microsoft Corporation

Module Name: formdump.cpp

Abstract:

ISAPI Extension sample illustrating how to obtain data from a web browser
and how to build a reply to the form.

--*/

#define WIN32_LEAN_AND_MEAN // the bare essential Win32 API
#include <windows.h>
#include <ctype.h> // for isprint()
#include <httpext.h>

#include "keys.h"
#include "html.h"

//
// local prototypes
//
void SendVariables( EXTENSION_CONTROL_BLOCK * pECB );
void HexDumper( EXTENSION_CONTROL_BLOCK * pECB, LPBYTE lpbyBuf, DWORD dwLength );
void WhoAmI( EXTENSION_CONTROL_BLOCK * pECB );
BOOL SendHttpHeaders( EXTENSION_CONTROL_BLOCK *, LPCSTR, LPCSTR );


BOOL WINAPI
GetExtensionVersion(
OUT HSE_VERSION_INFO * pVer
)
/*++

Purpose:

This is required ISAPI Extension DLL entry point.

Arguments:

pVer - poins to extension version info structure

Returns:

always returns TRUE

--*/
{
//
// set version to httpext.h version constants
//
pVer->dwExtensionVersion = MAKELONG(HSE_VERSION_MINOR, HSE_VERSION_MAJOR);

lstrcpyn((LPSTR) pVer->lpszExtensionDesc,
"FORMDUMP - A Form Decoder and Dumper",
HSE_MAX_EXT_DLL_NAME_LEN);

return TRUE;
}


DWORD WINAPI
HttpExtensionProc(
IN EXTENSION_CONTROL_BLOCK * pECB
)
/*++

Purpose:

Pull in all inbound data. Build a reply page
so the user can see how forms appear in our key list.

Arguments:

pECB - pointer to the extenstion control block

Returns:

HSE_STATUS_SUCCESS on successful completion
HSE_STATUS_ERROR on failure

--*/
{
HKEYLIST hKeyList;
char szMsg[128];

//
// Get the keys sent by the client
//

hKeyList = GetKeyList( pECB );


//
// Send HTTP headers
//

SendHttpHeaders( pECB, "200 OK", "Content-type: text/html\r\n\r\n" );

//
// Create a basic HTML page
//

HtmlCreatePage( pECB, "FormDump.dll Reply" );
HtmlHeading( pECB, 1, "Data Available via ISAPI" );
HtmlHorizontalRule( pECB );

//
// Send each form field
//

HtmlHeading( pECB, 2, "Form Fields" );

if ( !hKeyList ) {

//
// Report no data/error
//

HtmlBold( pECB, "No form fields sent" );
HtmlWriteText( pECB, " (or error decoding keys)" );
HtmlEndParagraph( pECB );

} else {
HKEYLIST hKey;

//
// Print a quick overview
//

HtmlWriteTextLine( pECB, "The form you submitted data to just called" );
HtmlWriteTextLine( pECB, "the Internet Information Server extension" );
HtmlWriteTextLine( pECB, "FormDump.dll. Here is a listing of what was" );
HtmlWriteTextLine( pECB, "received and what variables inside FormDump" );
HtmlWriteTextLine( pECB, "have the data." );
HtmlEndParagraph( pECB );

//
// Loop through all of the keys
//
hKey = hKeyList;
while ( hKey ) {

//
// Details about the key
//

LPCTSTR lpszKeyName;
DWORD dwLength;
BOOL bHasCtrlChars;
int nInstance;
HKEYLIST hLastKey;

//
// We get info, and hKey points to next key in list
//

hLastKey = hKey; // keep this for later

hKey = GetKeyInfo( hKey, &lpszKeyName, &dwLength,
&bHasCtrlChars, &nInstance );

//
// Build web page
//

HtmlBold( pECB, "Form Field Name (lpszKeyName): " );
HtmlWriteText( pECB, lpszKeyName );
HtmlLineBreak( pECB );

HtmlBold( pECB, "Length of Data (dwLength): " );
wsprintf( szMsg, "%u", dwLength );
HtmlWriteText( pECB, szMsg );
HtmlLineBreak( pECB );

HtmlBold( pECB, "Data Has Control Characters (bHasCtrlChars): " );
wsprintf( szMsg, "%u", bHasCtrlChars );
HtmlWriteText( pECB, szMsg );
HtmlLineBreak( pECB );

HtmlBold( pECB, "Instance of Form Field (nInstance): " );
wsprintf( szMsg, "%u", nInstance );
HtmlWriteText( pECB, szMsg );

if ( dwLength ) {
HtmlLineBreak( pECB );
HtmlBold( pECB, "Data Sent for Field:" );
HtmlLineBreak( pECB );

HexDumper( pECB, GetKeyBuffer( hLastKey ), dwLength );
}
HtmlEndParagraph( pECB );
}

//
// Clean up
//

FreeKeyList( hKeyList );
}

HtmlHorizontalRule( pECB );


//
// Get user name from SID and return it in the page
//

HtmlHeading( pECB, 2, "Security Context for HttpExtensionProc Thread" );
WhoAmI( pECB );
HtmlHorizontalRule( pECB );


//
// Display all server variables
//

HtmlHeading( pECB, 2, "Server Variables" );
HtmlWriteTextLine( pECB,
"Below is a list of all variables available via" );
HtmlWriteTextLine( pECB, "GetServerVariable ISAPI API. Much of this" );
HtmlWriteTextLine( pECB,
"information comes from the browser HTTP header." );
HtmlEndParagraph( pECB );

//
// Send server variables obtained from the HTTP header
//

SendVariables( pECB );


//
// Finish up...
//

HtmlEndPage( pECB );

return HSE_STATUS_SUCCESS;
}


BOOL WINAPI
TerminateExtension(
DWORD dwFlags
)
/*++

Purpose:

This is optional ISAPI extension DLL entry point.
If present, it will be called before unloading the DLL,
giving it a chance to perform any shutdown procedures.

Arguments:

dwFlags - specifies whether the DLL can refuse to unload or not

Returns:

TRUE, if the DLL can be unloaded

--*/
{
return TRUE;
}




void
HexDumper(
IN EXTENSION_CONTROL_BLOCK * pECB,
IN LPBYTE lpbyBuf,
IN DWORD dwLength
)
/*++

Purpose:

Put the inbound data in a hex dump format

Arguments:

pECB - points to the extension control block
lpbyByf - bytes to dump
dwLength - specifies the number of bytes to dump

--*/
{
DWORD dwSize;
char szLine[80];
char szHex[3];
DWORD i;
DWORD dwPos = 0;

HtmlBeginPreformattedText( pECB );

while (dwLength) {

//
// Take min of 16 or dwLength
//

dwSize = min(16, dwLength );

//
// Build text line
//

wsprintf(szLine, " %04X ", dwPos );

for (i = 0; i < dwSize; i++) {
wsprintf(szHex, "%02X", lpbyBuf[i] );
lstrcat(szLine, szHex );
lstrcat(szLine, " " );
}

//
// Add spaces for short lines
//

while (i < 16) {
lstrcat(szLine, " " );
i++;
}

//
// Add ASCII chars
//

for (i = 0; i < dwSize; i++) {
if (isprint(lpbyBuf[i])) {
wsprintf(szHex, "%c", lpbyBuf[i] );
lstrcat(szLine, szHex );
} else {
lstrcat(szLine, "." );
}
}

//
// Write data to web page
//

HtmlWriteTextLine( pECB, szLine );

//
// Advance positions
//

dwLength -= dwSize;
dwPos += dwSize;
lpbyBuf += dwSize;
}

HtmlEndPreformattedText( pECB );
}


void
DumpVariable(
IN EXTENSION_CONTROL_BLOCK * pECB,
IN LPCTSTR szName
)
/*++

Purpose:

Dump a server variable

Arguments:

pECB - points to the extension control block
lpbyByf - points to ASCIIZ name of the server variable to dump

--*/
{
DWORD dwBufferSize;
char szBuffer[4096];
BOOL bReturn;

dwBufferSize = sizeof szBuffer;
bReturn = pECB->GetServerVariable( pECB->ConnID,
(LPSTR) szName,
szBuffer,
&dwBufferSize );

if ( !bReturn || !szBuffer[0] )
return;

HtmlWriteText( pECB, szName );
HtmlWriteText( pECB, "=" );
HtmlWriteText( pECB, szBuffer );
HtmlLineBreak( pECB );
}


BOOL
SendHttpHeaders(
EXTENSION_CONTROL_BLOCK *pECB,
LPCSTR pszStatus,
LPCSTR pszHeaders
)
/*++

Purpose:
Send specified HTTP status string and any additional header strings
using new ServerSupportFunction() request HSE_SEND_HEADER_EX_INFO

Arguments:

pECB - pointer to the extension control block
pszStatus - HTTP status string (e.g. "200 OK")
pszHeaders - any additional headers, separated by CRLFs and
terminated by empty line

Returns:

TRUE if headers were successfully sent
FALSE otherwise

--*/
{
HSE_SEND_HEADER_EX_INFO header_ex_info;
BOOL success;

header_ex_info.pszStatus = pszStatus;
header_ex_info.pszHeader = pszHeaders;
header_ex_info.cchStatus = strlen( pszStatus );
header_ex_info.cchHeader = strlen( pszHeaders );
header_ex_info.fKeepConn = FALSE;


success = pECB->ServerSupportFunction(
pECB->ConnID,
HSE_REQ_SEND_RESPONSE_HEADER_EX,
&header_ex_info,
NULL,
NULL
);

return success;
}


void
SendVariables(
IN EXTENSION_CONTROL_BLOCK * pECB
)
/*++

Purpose:

Send all server variables (they came in the HTTP header)

Arguments:

pECB - pointer to the extension control block

--*/
{
char *pChar, *pOpts, *pEnd;
DWORD dwBufferSize;
char szBuffer[4096];
BOOL bReturn;

//
// Dump the standard variables
//

DumpVariable( pECB, "AUTH_TYPE" );
DumpVariable( pECB, "CONTENT_LENGTH" );
DumpVariable( pECB, "CONTENT_TYPE" );
DumpVariable( pECB, "GATEWAY_INTERFACE" );
DumpVariable( pECB, "PATH_INFO" );
DumpVariable( pECB, "PATH_TRANSLATED" );
DumpVariable( pECB, "QUERY_STRING" );
DumpVariable( pECB, "REMOTE_ADDR" );
DumpVariable( pECB, "REMOTE_HOST" );
DumpVariable( pECB, "REMOTE_USER" );
DumpVariable( pECB, "REQUEST_METHOD" );
DumpVariable( pECB, "SCRIPT_NAME" );
DumpVariable( pECB, "SERVER_NAME" );
DumpVariable( pECB, "SERVER_PORT" );
DumpVariable( pECB, "SERVER_PROTOCOL" );
DumpVariable( pECB, "SERVER_SOFTWARE" );
DumpVariable( pECB, "AUTH_PASS" );


//
// Dump any others (in ALL_HTTP)
//

dwBufferSize = sizeof szBuffer;
bReturn = pECB->GetServerVariable( pECB->ConnID,
"ALL_HTTP",
szBuffer,
&dwBufferSize );

if ( bReturn ) {
//
// Find lines, split key/data pair and write them as output
//

pChar = szBuffer;
while ( *pChar ) {
if ( *pChar == '\r' || *pChar == '\n' ) {
pChar++;
continue;
}
pOpts = strchr( pChar, ':' ); // look for separator

if ( !pOpts )
break;
if ( !*pOpts )
break;

pEnd = pOpts;
while ( *pEnd && *pEnd != '\r' && *pEnd != '\n' )
pEnd++;

*pOpts = 0; // split strings

*pEnd = 0;

//
// pChar points to variable name, pOpts + 1 points to variable
// val
//

HtmlWriteText( pECB, pChar );
HtmlWriteText( pECB, "=" );
HtmlWriteText( pECB, pOpts + 1 );
HtmlLineBreak( pECB );

pChar = pEnd + 1;
}
}
HtmlEndParagraph( pECB );
HtmlHorizontalRule( pECB );
}


void
WhoAmI(
IN EXTENSION_CONTROL_BLOCK * pECB
)
/*++

Purpose:

Get the user SID, lookup the account name and display it

Arguments:

pECB - pointer to the extension control block

--*/
{
HANDLE hToken;
PTOKEN_USER pTokenUser;
BYTE byBuf[1024];
DWORD dwLen;
char szName[256], szDomain[256];
DWORD dwNameLen, dwDomainLen;
SID_NAME_USE eUse;

if ( !OpenThreadToken(
GetCurrentThread( ), TOKEN_QUERY, TRUE, &hToken ) ) {

DWORD dwError = GetLastError( );

HtmlBold( pECB, "OpenThreadToken failed. " );
HtmlPrintf( pECB, "Error code=%u", dwError );
HtmlEndParagraph( pECB );
return;
}

pTokenUser = (PTOKEN_USER) byBuf;
if ( !GetTokenInformation(
hToken, TokenUser, pTokenUser, sizeof byBuf, &dwLen ) ) {

DWORD dwError = GetLastError( );

CloseHandle( hToken );

HtmlBold( pECB, "GetTokenInformation failed. " );
HtmlPrintf( pECB, "Error code=%u dwLen=%u", dwError, dwLen );
HtmlEndParagraph( pECB );
return;
}

dwNameLen = sizeof szName;
dwDomainLen = sizeof szDomain;
if ( !LookupAccountSid( NULL, pTokenUser->User.Sid,
szName, &dwNameLen,
szDomain, &dwDomainLen, &eUse )) {

DWORD dwError = GetLastError( );

CloseHandle( hToken );

HtmlBold( pECB, "LookupAccountSid failed. " );
HtmlPrintf( pECB, "Error code=%u dwNameLen=%u dwDomainLen=%u",
dwError, dwNameLen, dwDomainLen );
HtmlEndParagraph( pECB );
return;
}

HtmlBold( pECB, "Domain: " );
HtmlWriteText( pECB, szDomain );
HtmlLineBreak( pECB );
HtmlBold( pECB, "User: " );
HtmlWriteText( pECB, szName );
HtmlEndParagraph( pECB );

CloseHandle( hToken );
}