/*++ Copyright (c) 1999 Microsoft Corporation Module Name : certmapprovider.cxx Abstract: Active Directory Certificate Mapper provider Author: Bilal Alam (balam) 10-Jan-2000 Environment: Win32 - User Mode Project: ULW3.DLL --*/ #include "precomp.hxx" #include "certmapprovider.hxx" HRESULT CERTMAP_AUTH_PROVIDER::DoesApply( W3_MAIN_CONTEXT * pMainContext, BOOL * pfApplies ) /*++ Routine Description: Does Active Directory certificate map authentication apply? MD_ACCESS_MAP_CERT covers 2 kinds of mappings (DS mapper and IIS mapper) CERT_AUTH_PROVIDER represents only the DS mapper 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; 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 ); // // Are certmappings allowed? // if ( pMetaData->QuerySslAccessPerms() & MD_ACCESS_MAP_CERT ) { DBG_ASSERT( pMainContext->QuerySite() ); // // Is Active Directory mapping allowed // if ( pMainContext->QuerySite()->QueryUseDSMapper() ) { pCertificateContext = pMainContext->QueryCertificateContext(); // // Did schannel successfully mapped client certificate to token? // if ( pCertificateContext != NULL ) { if ( pCertificateContext->QueryImpersonationToken() != NULL ) { fApplies = TRUE; } } } } *pfApplies = fApplies; return NO_ERROR; } HRESULT CERTMAP_AUTH_PROVIDER::DoAuthenticate( W3_MAIN_CONTEXT * pMainContext, BOOL * // unused ) /*++ Routine Description: Create a user context representing a cert mapped token Arguments: pMainContext - Main context pfFilterFinished - Set to TRUE if filter wants out Return Value: HRESULT --*/ { CERTMAP_USER_CONTEXT * pUserContext = NULL; CERTIFICATE_CONTEXT * pCertificateContext = NULL; HANDLE hImpersonation; HRESULT hr = NO_ERROR; if ( pMainContext == NULL ) { DBG_ASSERT( FALSE ); return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } pCertificateContext = pMainContext->QueryCertificateContext(); DBG_ASSERT( pCertificateContext != NULL ); hImpersonation = pCertificateContext->QueryImpersonationToken(); DBG_ASSERT( hImpersonation != NULL ); // // Create the user context for this request // pUserContext = new CERTMAP_USER_CONTEXT( this ); if ( pUserContext == NULL ) { return HRESULT_FROM_WIN32( GetLastError() ); } // // Is this a delegatable token? Put another way is this token mapped // using an IIS cert mapper (IIS cert mapper creates delegatable token, // the DS mapper does not) // hr = pUserContext->Create( hImpersonation ); if ( FAILED( hr ) ) { pUserContext->DereferenceUserContext(); pUserContext = NULL; return hr; } pMainContext->SetUserContext( pUserContext ); return NO_ERROR; } HRESULT CERTMAP_AUTH_PROVIDER::OnAccessDenied( W3_MAIN_CONTEXT * /*pMainContext*/ ) /*++ Routine Description: NOP since we have nothing to do on access denied Arguments: pMainContext - Main context (not used) Return Value: HRESULT --*/ { // // No headers to add // return NO_ERROR; } HRESULT CERTMAP_USER_CONTEXT::Create( HANDLE hImpersonation ) /*++ Routine Description: Create a certificate mapped user context Arguments: hImpersonation - Impersonation token Return Value: HRESULT --*/ { HRESULT hr = E_FAIL; if ( hImpersonation == NULL ) { DBG_ASSERT( FALSE ); return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER ); } // // First the easy stuff // if ( !DuplicateTokenEx( hImpersonation, TOKEN_ALL_ACCESS, NULL, SecurityImpersonation, TokenImpersonation, &_hImpersonationToken ) ) { hr = HRESULT_FROM_WIN32( GetLastError() ); DBGPRINTF(( DBG_CONTEXT, "DuplicateTokenEx failed, hr = 0x%x\n", hr )); return hr; } DBG_ASSERT( _hImpersonationToken != NULL ); // // Disable the backup privilege for the token // DisableTokenBackupPrivilege( _hImpersonationToken ); // // Now get the user name // if ( !SetThreadToken( NULL, _hImpersonationToken ) ) { return HRESULT_FROM_WIN32( GetLastError() ); } // cchUserName includes buffer size in characters including terminating 0 DWORD cchUserName = sizeof( _achUserName ) / sizeof( WCHAR ); if ( !GetUserNameEx( NameSamCompatible, _achUserName, &cchUserName ) ) { hr = HRESULT_FROM_WIN32( GetLastError() ); RevertToSelf(); return hr; } RevertToSelf(); return NO_ERROR; } HANDLE CERTMAP_USER_CONTEXT::QueryPrimaryToken( VOID ) /*++ Routine Description: Get a primary token Arguments: None Return Value: HANDLE --*/ { if ( _hPrimaryToken == NULL ) { if ( DuplicateTokenEx( _hImpersonationToken, TOKEN_ALL_ACCESS, NULL, SecurityImpersonation, TokenPrimary, &_hPrimaryToken ) ) { DBG_ASSERT( _hImpersonationToken != NULL ); } else { DBGPRINTF(( DBG_CONTEXT, "DuplicateTokenEx failed, hr = 0x%x\n", HRESULT_FROM_WIN32( GetLastError() ) )); } } return _hPrimaryToken; }