Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

790 lines
19 KiB

/*++
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;
}