windows-nt/Source/XPSP1/NT/inetsrv/iis/iisrearc/iisplus/ulw3/iiscertmapprovider.cxx
2020-09-26 16:20:57 +08:00

385 lines
10 KiB
C++

/*++
Copyright (c) 1999 Microsoft Corporation
Module Name :
certmapprovider.cxx
Abstract:
IIS Certificate Mapper provider
Author:
Bilal Alam (balam) 10-Jan-2000
Environment:
Win32 - User Mode
Project:
ULW3.DLL
--*/
#include "precomp.hxx"
#include "iiscertmapprovider.hxx"
HRESULT
IISCERTMAP_AUTH_PROVIDER::DoesApply(
W3_MAIN_CONTEXT * pMainContext,
BOOL * pfApplies
)
/*++
Routine Description:
Does certificate map authentication apply?
Arguments:
pMainContext - Main context
pfApplies - Set to TRUE if cert map auth applies
Return Value:
HRESULT
--*/
{
CERTIFICATE_CONTEXT * pCertificateContext;
URL_CONTEXT * pUrlContext = NULL;
W3_METADATA * pMetaData = NULL;
BOOL fApplies = FALSE;
W3_SITE * pSite = NULL;
IIS_CERTIFICATE_MAPPING * pIISCertificateMapping = NULL;
TOKEN_CACHE_ENTRY * pCachedIISMappedToken = NULL;
BOOL fClientCertDeniedByMapper = FALSE;
if ( pMainContext == NULL ||
pfApplies == NULL )
{
DBG_ASSERT( FALSE );
return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
}
//
// If cert mapping is not allowed for this vroot, then ignore client
// cert token and let other authentication mechanisms do their thing
//
pUrlContext = pMainContext->QueryUrlContext();
DBG_ASSERT( pUrlContext != NULL );
pMetaData = pUrlContext->QueryMetaData();
DBG_ASSERT( pMetaData != NULL );
pSite = pMainContext->QuerySite();
DBG_ASSERT( pSite != NULL );
if ( pMetaData->QuerySslAccessPerms() & VROOT_MASK_MAP_CERT )
{
pCertificateContext = pMainContext->QueryCertificateContext();
if ( pCertificateContext == NULL )
{
fApplies = FALSE;
goto Finished;
}
if ( ! pSite->QueryUseDSMapper() )
{
//
// IIS mapper enabled
//
HRESULT hr = E_FAIL;
PBYTE pbClientCertBlob = NULL;
DWORD cbClientCertBlob = 0;
//
// No need to call DereferenceCertMapping after QueryIISCertificateMapping
// IISCertificateMapping is referenced by W3_SITE and we hold reference
// to W3_SITE already
//
hr = pSite->GetIISCertificateMapping( &pIISCertificateMapping );
if ( FAILED( hr ) ||
( pIISCertificateMapping == NULL ) )
{
//
// If we couldn't read the mapping because not found, thats OK.
//
// CODEWORK: we may need smarted error handling (ignoring error
// and assuming that mapping was not found is not very good idea
//
fApplies = FALSE;
goto Finished;
}
//
// retrieve client certificate
//
pCertificateContext->QueryEncodedCertificate(
reinterpret_cast<PVOID *>(&pbClientCertBlob),
&cbClientCertBlob );
if( pbClientCertBlob == NULL || cbClientCertBlob == 0 )
{
fApplies = FALSE;
goto Finished;
}
DBG_ASSERT( pIISCertificateMapping != NULL );
hr = pIISCertificateMapping->DoMapCredential( pbClientCertBlob,
cbClientCertBlob,
&pCachedIISMappedToken,
&fClientCertDeniedByMapper );
if ( FAILED( hr ) )
{
//
// IISCERTMAP applies only when there was successful mapping
// Otherwise it will yield other auth providers
//
if ( hr == SEC_E_UNKNOWN_CREDENTIALS )
{
//
// DoMapCredential didn't find any mathing mapping
// or user/pwd in the mapping was invalid
//
hr = S_OK;
}
fApplies = FALSE;
goto Finished;
}
DBG_ASSERT ( fClientCertDeniedByMapper || pCachedIISMappedToken!= NULL );
if( ( pCachedIISMappedToken != NULL &&
pCachedIISMappedToken->QueryImpersonationToken() != NULL ) ||
fClientCertDeniedByMapper )
{
IISCERTMAP_CONTEXT_STATE * pContextState = NULL;
//
// Use IISCERTMAP_CONTEXT_STATE to communicate information
// from DoesApply() to DoAuthenticate()
// We don't want to be calling mapper twice
//
pContextState = new (pMainContext) IISCERTMAP_CONTEXT_STATE(
pCachedIISMappedToken,
fClientCertDeniedByMapper );
if ( pContextState == NULL )
{
if ( pCachedIISMappedToken != NULL )
{
pCachedIISMappedToken->DereferenceCacheEntry();
pCachedIISMappedToken = NULL;
}
hr = HRESULT_FROM_WIN32( ERROR_OUTOFMEMORY );
goto Finished;
}
//
// pContextState is taking ownership of pCachedIISMappedToken
//
pMainContext->SetContextState( pContextState );
fApplies = TRUE;
}
}
}
Finished:
*pfApplies = fApplies;
if ( pCachedIISMappedToken != NULL )
{
//
// if creating CERTMAP_CONTEXT_STATE succeeded it will hold it's own reference
// to cached token
//
pCachedIISMappedToken->DereferenceCacheEntry();
pCachedIISMappedToken = NULL;
}
return NO_ERROR;
}
HRESULT
IISCERTMAP_AUTH_PROVIDER::DoAuthenticate(
W3_MAIN_CONTEXT * pMainContext
)
/*++
Routine Description:
Create a user context representing a cert mapped token
Arguments:
pMainContext - Main context
Return Value:
HRESULT
--*/
{
IISCERTMAP_USER_CONTEXT * pUserContext = NULL;
CERTIFICATE_CONTEXT * pCertificateContext = NULL;
HANDLE hImpersonation;
BOOL fDelegatable = FALSE;
HRESULT hr = NO_ERROR;
W3_SITE * pSite = NULL;
IISCERTMAP_CONTEXT_STATE * pContextState = NULL;
TOKEN_CACHE_ENTRY * CachedToken = NULL;
if ( pMainContext == NULL )
{
DBG_ASSERT( FALSE );
return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
}
pSite = pMainContext->QuerySite();
DBG_ASSERT( pSite != NULL );
// IIS mapper
DBG_ASSERT ( !pSite->QueryUseDSMapper() );
pContextState = (IISCERTMAP_CONTEXT_STATE *) pMainContext->QueryContextState();
DBG_ASSERT( pContextState != NULL );
if ( pContextState->QueryClientCertDeniedByIISCertMap() )
{
//
// Report denied by IIS mapper error
//
pMainContext->QueryResponse()->SetStatus( HttpStatusForbidden,
Http403MapperDenyAccess);
pMainContext->SetErrorStatus( S_OK );
return S_OK;
}
CachedToken = pContextState->QueryCachedIISCertMapToken();
DBG_ASSERT( CachedToken != NULL );
//
// Create the user context for this request
//
pUserContext = new IISCERTMAP_USER_CONTEXT( this );
if ( pUserContext == NULL )
{
CachedToken->DereferenceCacheEntry();
return HRESULT_FROM_WIN32( GetLastError() );
}
hr = pUserContext->Create( CachedToken );
if ( FAILED( hr ) )
{
pUserContext->DereferenceUserContext();
pUserContext = NULL;
return hr;
}
pMainContext->SetUserContext( pUserContext );
return NO_ERROR;
}
HRESULT
IISCERTMAP_AUTH_PROVIDER::OnAccessDenied(
W3_MAIN_CONTEXT * pMainContext
)
/*++
Routine Description:
NOP since we have nothing to do on access denied
Arguments:
pMainContext - Main context
Return Value:
HRESULT
--*/
{
//
// No headers to add
//
return NO_ERROR;
}
HRESULT
IISCERTMAP_USER_CONTEXT::Create(
TOKEN_CACHE_ENTRY * pCachedToken
)
/*++
Routine Description:
Create a certificate mapped user context
Arguments:
pCachedToken - cached token
Note: function takes ownership of pCachedToken.
It will dereference it even in the case of failure
Return Value:
HRESULT
--*/
{
HRESULT hr = E_FAIL;
DWORD cchUserName = sizeof( _achUserName ) / sizeof( WCHAR );
if ( pCachedToken == NULL )
{
DBG_ASSERT( FALSE );
return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
}
//
// First the easy stuff
//
pCachedToken->ReferenceCacheEntry();
_pCachedToken = pCachedToken;
//
// Now get the user name
//
if ( !SetThreadToken( NULL, _pCachedToken->QueryImpersonationToken() ) )
{
hr = HRESULT_FROM_WIN32( GetLastError() );
goto Failed;
}
if ( !GetUserNameEx( NameSamCompatible,
_achUserName,
&cchUserName ) )
{
RevertToSelf();
hr = HRESULT_FROM_WIN32( GetLastError() );
goto Failed;
}
RevertToSelf();
return NO_ERROR;
Failed:
if ( _pCachedToken != NULL )
{
_pCachedToken->DereferenceCacheEntry();
_pCachedToken = NULL;
}
return hr;
}