|
|
/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
application.cxx
Abstract:
Encapsulates the IAzApplication object. Does all the grunt work to get an AzContext, determine operations, and build up server variable table
Author:
Bilal Alam (balam) Nov 26, 2001
--*/
#include "precomp.hxx"
BSTR AZ_APPLICATION::sm_bstrOperationName; DWORD AZ_APPLICATION::sm_cParameterCount; VARIANT AZ_APPLICATION::sm_vNameArray;
CHAR * AZ_APPLICATION::sm_rgParameterNames[] = { "ALL_HTTP", "APPL_MD_PATH", "APPL_PHYSICAL_PATH", "AUTH_PASSWORD", "AUTH_TYPE", "AUTH_USER", "CERT_COOKIE", "CERT_FLAGS", "CERT_ISSUER", "CERT_KEYSIZE", "CERT_SECRETKEYSIZE", "CERT_SERIALNUMBER", "CERT_SERVER_ISSUER", "CERT_SERVER_SUBJECT", "CERT_SUBJECT", "CONTENT_LENGTH", "CONTENT_TYPE", "GATEWAY_INTERFACE", "LOGON_USER", "HTTPS", "HTTPS_KEYSIZE", "HTTPS_SECRETKEYSIZE", "HTTPS_SERVER_ISSUER", "HTTPS_SERVER_SUBJECT", "INSTANCE_ID", "INSTANCE_META_PATH", "PATH_INFO", "PATH_TRANSLATED", "QUERY_STRING", "REMOTE_ADDR", "REMOTE_HOST", "REMOTE_USER", "REQUEST_METHOD", "SERVER_NAME", "LOCAL_ADDR", "SERVER_PORT", "SERVER_PORT_SECURE", "SERVER_PROTOCOL", "SERVER_SOFTWARE", "UNMAPPED_REMOTE_USER", "URL", "HTTP_METHOD", "HTTP_VERSION", "APP_POOL_ID", "SCRIPT_TRANSLATED", "UNENCODED_URL", NULL };
//static
HRESULT AZ_APPLICATION::Initialize( VOID ) /*++
Routine Description:
Global initialization of AZ_APPLICATION
Arguments:
None
Return Value:
HRESULT
--*/ { VARIANT vName; SAFEARRAY * psaNames = NULL; SAFEARRAYBOUND rgsaBound[ 1 ]; LONG lArrayIndex[ 1 ]; HRESULT hr = NO_ERROR; BSTR bstrName = NULL; STACK_STRU( strTemp, 512 ); VariantInit( &sm_vNameArray ); //
// Allocate the single operation BSTR only once
//
sm_bstrOperationName = SysAllocString( URL_AUTH_OPERATION_NAME ); if ( sm_bstrOperationName == NULL ) { hr = HRESULT_FROM_WIN32( GetLastError() ); goto Finished; } //
// Allocate the parameter name array for use with AccessCheck() and
// business logic
//
//
// How many parameters in array?
//
DBG_ASSERT( sm_cParameterCount == 0 ); while ( sm_rgParameterNames[ sm_cParameterCount ] != NULL ) { sm_cParameterCount++; } DBG_ASSERT( sm_cParameterCount > 0 ); //
// Allocate the array
//
rgsaBound[ 0 ].lLbound = 0; rgsaBound[ 0 ].cElements = sm_cParameterCount; psaNames = SafeArrayCreate( VT_VARIANT, 1, rgsaBound ); if ( psaNames == NULL ) { hr = HRESULT_FROM_WIN32( GetLastError() ); goto Finished; } //
// Create a new BSTR for each parameter name and add to safe array
//
lArrayIndex[ 0 ] = 0; for ( DWORD j = 0; j < sm_cParameterCount; j++ ) { DBG_ASSERT( sm_rgParameterNames[ j ] != NULL );
hr = strTemp.CopyA( sm_rgParameterNames[ j ] ); if ( FAILED( hr ) ) { goto Finished; }
bstrName = SysAllocString( strTemp.QueryStr() ); if ( bstrName == NULL ) { hr = HRESULT_FROM_WIN32( GetLastError() ); goto Finished; } VariantInit( &vName ); vName.vt = VT_BSTR; vName.bstrVal = bstrName; hr = SafeArrayPutElement( psaNames, lArrayIndex, &vName ); if ( FAILED( hr ) ) { goto Finished; } bstrName = NULL; (lArrayIndex[ 0 ])++; } //
// Finally, setup the variant for the array
//
sm_vNameArray.vt = VT_ARRAY; sm_vNameArray.parray = psaNames; psaNames = NULL; Finished:
if ( bstrName != NULL ) { SysFreeString( bstrName ); bstrName = NULL; } if ( psaNames != NULL ) { SafeArrayDestroy( psaNames ); psaNames = NULL; } return hr; }
//static
VOID AZ_APPLICATION::Terminate( VOID ) /*++
Routine Description:
Cleanup globals for AZ_APPLICATION
Arguments:
None
Return Value:
None
--*/ { VariantClear( &sm_vNameArray ); if ( sm_bstrOperationName != NULL ) { SysFreeString( sm_bstrOperationName ); sm_bstrOperationName = NULL; } }
HRESULT AZ_APPLICATION::Create( VOID ) /*++
Routine Description:
Initialize an AZ_APPLICATION object
Arguments:
None
Return Value:
HRESULT
--*/ { IAzOperation * pIOperation; HRESULT hr; VARIANT vNoParam; LONG operationId; SAFEARRAY * psaOperations = NULL; SAFEARRAYBOUND rgsaBound[ 1 ]; LONG lArrayIndex[ 1 ]; VARIANT vOperation;
DBG_ASSERT( _pIApplication != NULL ); //
// We need to get the one operation we care about.
//
VariantInit( &vNoParam ); vNoParam.vt = VT_ERROR; vNoParam.scode = DISP_E_PARAMNOTFOUND; hr = _pIApplication->OpenOperation( sm_bstrOperationName, vNoParam, &pIOperation ); if ( FAILED( hr ) ) { return hr; } DBG_ASSERT( pIOperation != NULL ); //
// Get the operation ID
//
hr = pIOperation->get_OperationID( &operationId ); pIOperation->Release(); //
// Now do some grunt work and create a variant array for use in our call
// to AccessCheck(). How do developers live with this crap?
//
rgsaBound[ 0 ].lLbound = 0; rgsaBound[ 0 ].cElements = 1; psaOperations = SafeArrayCreate( VT_VARIANT, 1, rgsaBound ); if ( psaOperations == NULL ) { return HRESULT_FROM_WIN32( GetLastError() ); } lArrayIndex[ 0 ] = 0; VariantInit( &vOperation ); vOperation.vt = VT_I4; vOperation.lVal = operationId; hr = SafeArrayPutElement( psaOperations, lArrayIndex, &vOperation ); if ( FAILED( hr ) ) { SafeArrayDestroy( psaOperations ); return hr; } VariantInit( &_vOperations ); _vOperations.vt = VT_ARRAY; _vOperations.parray = psaOperations; psaOperations = NULL; return NO_ERROR; }
HRESULT AZ_APPLICATION::BuildValueArray( EXTENSION_CONTROL_BLOCK * pecb, VARIANT * pValueArray ) /*++
Routine Description:
Build value array for the given ECB. This just means retrieving all the server variables and building up an array with these values
Arguments:
pecb - ECB from which operations and sever variable table are built pValueArray - Filled with a variant for the array of values :-(
Return Value:
HRESULT
--*/ { SAFEARRAY * psaValues = NULL; SAFEARRAYBOUND rgsaBound[ 1 ]; LONG lArrayIndex[ 1 ]; VARIANT vValue; HRESULT hr = NO_ERROR; STACK_BUFFER( buffVariable, 512 ); STACK_STRU( strVariable, 512 ); DWORD cbVariable; BSTR bstrValue = NULL; BOOL fRet; if ( pecb == NULL || pValueArray == NULL ) { DBG_ASSERT( FALSE ); return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } //
// First create a safe array of required size
//
rgsaBound[ 0 ].lLbound = 0; rgsaBound[ 0 ].cElements = sm_cParameterCount; psaValues = SafeArrayCreate( VT_VARIANT, 1, rgsaBound ); if ( psaValues == NULL ) { hr = HRESULT_FROM_WIN32( GetLastError() ); goto Finished; } lArrayIndex[ 0 ] = 0; //
// Now iterate thru variables, retrieve each one and add to array
//
for ( DWORD i = 0; i < sm_cParameterCount; i++ ) { DBG_ASSERT( sm_rgParameterNames[ i ] != NULL ); //
// First get the variable
//
cbVariable = buffVariable.QuerySize();
fRet = pecb->GetServerVariable( pecb->ConnID, sm_rgParameterNames[ i ], buffVariable.QueryPtr(), &cbVariable ); if ( !fRet ) { if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER ) { hr = HRESULT_FROM_WIN32( GetLastError() ); goto Finished; } DBG_ASSERT( cbVariable > buffVariable.QuerySize() ); fRet = buffVariable.Resize( cbVariable ); if ( !fRet ) { hr = HRESULT_FROM_WIN32( GetLastError() ); goto Finished; } cbVariable = buffVariable.QuerySize(); fRet = pecb->GetServerVariable( pecb->ConnID, sm_rgParameterNames[ i ], buffVariable.QueryPtr(), &cbVariable ); if ( !fRet ) { hr = HRESULT_FROM_WIN32( GetLastError() ); goto Finished; } } //
// Convert to UNICODE
//
hr = strVariable.CopyA( (CHAR*) buffVariable.QueryPtr() ); if ( FAILED( hr ) ) { goto Finished; } //
// Make a BSTR
//
bstrValue = SysAllocString( strVariable.QueryStr() ); if ( bstrValue == NULL ) { hr = HRESULT_FROM_WIN32( GetLastError() ); goto Finished; } VariantInit( &vValue ); vValue.vt = VT_BSTR; vValue.bstrVal = bstrValue; hr = SafeArrayPutElement( psaValues, lArrayIndex, &vValue ); if ( FAILED( hr ) ) { goto Finished; } bstrValue = NULL; (lArrayIndex[ 0 ])++; } //
// Finally, setup the variant for the array
//
pValueArray->vt = VT_ARRAY; pValueArray->parray = psaValues; psaValues = NULL; Finished:
if ( bstrValue != NULL ) { SysFreeString( bstrValue ); bstrValue = NULL; } if ( psaValues != NULL ) { SafeArrayDestroy( psaValues ); psaValues = NULL; }
return hr; }
HRESULT AZ_APPLICATION::DoAccessCheck( EXTENSION_CONTROL_BLOCK * pecb, WCHAR * pszScopeName, BOOL * pfAccessGranted ) /*++
Routine Description:
Check access
Arguments:
pecb - ECB from which operations and sever variable table are built pszScopeName - Scope name pfAccessGranted - Set to TRUE if access is granted
Return Value:
HRESULT
--*/ { BOOL fRet; HANDLE hToken; HRESULT hr = NO_ERROR; VARIANT vNoParam; IAzClientContext * pIClientContext = NULL; SAFEARRAY * psaScopes = NULL; SAFEARRAYBOUND rgsaBound[ 1 ]; LONG lArrayIndex[ 1 ]; VARIANT vScope; VARIANT vScopes; BSTR bstrScope = NULL; BSTR bstrObjectName = NULL; STACK_BUFFER( buffUrl, 256 ); DWORD cbBuffUrl; VARIANT vAccessCheckOutput; VARIANT * pResults = NULL; LONG lTokenHandle; VARIANT vValueArray; if ( pecb == NULL || pfAccessGranted == NULL ) { DBG_ASSERT( FALSE ); return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } VariantInit( &vNoParam ); VariantInit( &vScope ); VariantInit( &vScopes ); VariantInit( &vAccessCheckOutput ); VariantInit( &vValueArray ); *pfAccessGranted = FALSE; //
// First, get the token for this request.
//
fRet = pecb->ServerSupportFunction( pecb->ConnID, HSE_REQ_GET_IMPERSONATION_TOKEN, (VOID*)&hToken, NULL, NULL );
if ( !fRet ) { hr = HRESULT_FROM_WIN32( GetLastError() ); goto Finished; } //
// Now, get the AzClientContext from the token
//
DBG_ASSERT( _pIApplication != NULL );
vNoParam.vt = VT_ERROR; vNoParam.scode = DISP_E_PARAMNOTFOUND;
//
// BUGBUG: This AZRoles API needs to be Win64 friendly
//
#if defined( _WIN64 )
LARGE_INTEGER liLarge; liLarge.QuadPart = (LONGLONG) hToken; lTokenHandle = liLarge.LowPart; #else
lTokenHandle = (LONG) hToken; #endif
hr = _pIApplication->InitializeClientContextFromToken( lTokenHandle, vNoParam, &pIClientContext ); if ( FAILED( hr ) ) { goto Finished; } DBG_ASSERT( pIClientContext != NULL ); //
// Determine the object name. We'll just use the URL (probably want to
// expose a "FULL_URL" variable which is just the Unicode-untranslated
// (i.e. pathinfo/URL not split) string.
//
cbBuffUrl = buffUrl.QuerySize(); fRet = pecb->GetServerVariable( pecb->ConnID, "UNICODE_URL", (CHAR*) buffUrl.QueryPtr(), &cbBuffUrl ); if ( !fRet ) { if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER ) { hr = HRESULT_FROM_WIN32( GetLastError() ); goto Finished; } DBG_ASSERT( cbBuffUrl > buffUrl.QuerySize() ); fRet = buffUrl.Resize( cbBuffUrl ); if ( !fRet ) { hr = HRESULT_FROM_WIN32( GetLastError() ); goto Finished; } cbBuffUrl = buffUrl.QuerySize(); fRet = pecb->GetServerVariable( pecb->ConnID, "UNICODE_URL", (CHAR*) buffUrl.QueryPtr(), &cbBuffUrl ); if ( !fRet ) { hr = HRESULT_FROM_WIN32( GetLastError() ); goto Finished; } } //
// How many more heap allocations can we do???
//
bstrObjectName = SysAllocString( (WCHAR*) buffUrl.QueryPtr() ); if ( bstrObjectName == NULL ) { hr = HRESULT_FROM_WIN32( GetLastError() ); goto Finished; } //
// Setup the scope variant array for this request. This is excruciating!
//
rgsaBound[ 0 ].lLbound = 0; rgsaBound[ 0 ].cElements = 1; psaScopes = SafeArrayCreate( VT_VARIANT, 1, rgsaBound ); if ( psaScopes == NULL ) { hr = HRESULT_FROM_WIN32( GetLastError() ); goto Finished; } bstrScope = SysAllocString( pszScopeName ? pszScopeName : L"" ); if ( bstrScope == NULL ) { hr = HRESULT_FROM_WIN32( GetLastError() ); goto Finished; } vScope.vt = VT_BSTR; vScope.bstrVal = bstrScope; lArrayIndex[ 0 ] = 0; hr = SafeArrayPutElement( psaScopes, lArrayIndex, &vScope ); if ( FAILED( hr ) ) { goto Finished; } bstrScope = NULL; vScopes.vt = VT_ARRAY; vScopes.parray = psaScopes; psaScopes = NULL;
//
// Build up the value array for use with business logic
//
hr = BuildValueArray( pecb, &vValueArray );
//
// After that ordeal, we're ready to call AccessCheck()!
//
hr = pIClientContext->AccessCheck( bstrObjectName, vScopes, _vOperations, sm_vNameArray, vValueArray, vNoParam, vNoParam, vNoParam, &vAccessCheckOutput ); if ( FAILED( hr ) ) { goto Finished; } //
// Joy continues. Need to parse out what AccessCheck() returned
//
//
// Return variant should be 1 dimension, 0 based array
//
DBG_ASSERT( vAccessCheckOutput.parray->rgsabound[ 0 ].lLbound == 0 ); DBG_ASSERT( vAccessCheckOutput.parray->rgsabound[ 0 ].cElements == 1 ); SafeArrayAccessData( vAccessCheckOutput.parray, (VOID**) &pResults ); DBG_ASSERT( pResults[ 0 ].vt == VT_I4 );
//
// Finally, we can tell whether access was allowed or not
//
*pfAccessGranted = pResults[ 0 ].lVal == 0 ? TRUE : FALSE; SafeArrayUnaccessData( vAccessCheckOutput.parray ); Finished:
if ( pIClientContext != NULL ) { pIClientContext->Release(); pIClientContext = NULL; }
if ( bstrScope != NULL ) { SysFreeString( bstrScope ); bstrScope = NULL; } if ( bstrObjectName != NULL ) { SysFreeString( bstrObjectName ); bstrObjectName = NULL; }
if ( psaScopes != NULL ) { SafeArrayDestroy( psaScopes ); psaScopes = NULL; } VariantClear( &vScopes ); VariantClear( &vAccessCheckOutput ); VariantClear( &vValueArray );
return hr; }
|