474 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			474 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*++
 | |
| 
 | |
|    Copyright    (c)    1998    Microsoft Corporation
 | |
| 
 | |
|    Module  Name :
 | |
|      siteconfig.cxx
 | |
| 
 | |
|    Abstract:
 | |
|      SSL configuration for a given site
 | |
|  
 | |
|    Author:
 | |
|      Bilal Alam         (BAlam)         29-March-2000
 | |
| 
 | |
|    Environment:
 | |
|      Win32 - User Mode
 | |
| 
 | |
|    Project:
 | |
|      Stream Filter Worker Process
 | |
| --*/
 | |
| 
 | |
| #include "precomp.hxx"
 | |
| 
 | |
| SITE_CONFIG_HASH *   SITE_CONFIG::sm_pSiteConfigHash;
 | |
| 
 | |
| //static
 | |
| HRESULT
 | |
| SITE_CONFIG::Initialize(
 | |
|     VOID
 | |
| )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|     Initialize site configuration globals
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|     None
 | |
| 
 | |
| Return Value:
 | |
| 
 | |
|     HRESULT
 | |
| 
 | |
| --*/
 | |
| {
 | |
|     sm_pSiteConfigHash = new SITE_CONFIG_HASH();
 | |
|     if ( sm_pSiteConfigHash == NULL )
 | |
|     {
 | |
|         return HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
 | |
|     }
 | |
|     
 | |
|     return NO_ERROR;
 | |
| }
 | |
| 
 | |
| //static
 | |
| VOID
 | |
| SITE_CONFIG::Terminate(
 | |
|     VOID
 | |
| )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|     Cleanup site configuration globals
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|     None
 | |
| 
 | |
| Return Value:
 | |
| 
 | |
|     None
 | |
| 
 | |
| --*/
 | |
| {
 | |
|     if ( sm_pSiteConfigHash != NULL )
 | |
|     {
 | |
|         //
 | |
|         // Clear hash table before deleting it
 | |
|         //
 | |
|         sm_pSiteConfigHash->Clear();
 | |
|         delete sm_pSiteConfigHash;
 | |
|         sm_pSiteConfigHash = NULL;
 | |
|     }
 | |
| }
 | |
| 
 | |
| //static
 | |
| HRESULT
 | |
| SITE_CONFIG::GetSiteConfig(
 | |
|     DWORD                   dwSiteId,
 | |
|     SITE_CONFIG **          ppSiteConfig
 | |
| )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|     Lookup site configuration in hash table.  If not there then create it
 | |
|     and add it to table
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|     dwSiteId - Site ID to lookup
 | |
|     ppSiteConfig - Filled with pointer to site config on success
 | |
| 
 | |
| Return Value:
 | |
| 
 | |
|     HRESULT
 | |
| 
 | |
| --*/
 | |
| {
 | |
|     LK_RETCODE              lkrc; 
 | |
|     SITE_CONFIG *           pSiteConfig = NULL;
 | |
|     SERVER_CERT *           pServerCert = NULL;
 | |
|     HRESULT                 hr = NO_ERROR;
 | |
|     WCHAR                   achNum[ 64 ];
 | |
|     STACK_STRU(             strMBPath, 64 );
 | |
|     
 | |
|     if ( ppSiteConfig == NULL ||
 | |
|          dwSiteId == 0 )
 | |
|     {
 | |
|         DBG_ASSERT( FALSE );
 | |
|         return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
 | |
|     }
 | |
|     
 | |
|     *ppSiteConfig = NULL;
 | |
|     
 | |
|     //
 | |
|     // First lookup in the cache
 | |
|     //
 | |
| 
 | |
|     DBG_ASSERT( sm_pSiteConfigHash != NULL );
 | |
| 
 | |
|     lkrc = sm_pSiteConfigHash->FindKey( dwSiteId,
 | |
|                                         &pSiteConfig );
 | |
| 
 | |
|     if ( lkrc == LK_SUCCESS )
 | |
|     {
 | |
|         DBG_ASSERT( pSiteConfig != NULL );
 | |
|         *ppSiteConfig = pSiteConfig;
 | |
|         return NO_ERROR;
 | |
|     }
 | |
|     
 | |
|     //
 | |
|     // Ok.  We will have to make a new config object and add it to cache.  
 | |
|     // Start by getting the server certificate.
 | |
|     //
 | |
| 
 | |
|     
 | |
|     //
 | |
|     // Check if Client certificates are required on the site's root level
 | |
|     //
 | |
|     
 | |
|     MB                      mb( g_pStreamFilter->QueryMDObject() );
 | |
|     WCHAR                   achMBPath[ 256 ];
 | |
|     DWORD                   dwSslAccessPerm = 0;
 | |
|     BOOL                    fRequireClientCert = FALSE;
 | |
|     DWORD                   dwUseDsMapper = 0;
 | |
|     BOOL                    fUseDSMapper = FALSE;
 | |
|     DWORD                   dwCertCheckMode = 0;
 | |
|     DWORD                   dwRevocationFreshnessTime = 86400;   // 1 day in seconds
 | |
|     DWORD                   dwRevocationUrlRetrievalTimeout = 0; // default timeout
 | |
|         
 | |
|     if ( mb.Open( L"/LM/W3SVC/",
 | |
|                   METADATA_PERMISSION_READ ) )
 | |
|     {
 | |
|         //
 | |
|         // Lookup SSLUseDsMapper 
 | |
|         // SSLUseDsMapper is global setting that is not inherited to sites (IIS5 legacy)
 | |
|         // We have to read it from lm/w3svc
 | |
|         //    
 | |
| 
 | |
|         mb.GetDword( L"",
 | |
|                      MD_SSL_USE_DS_MAPPER,
 | |
|                      IIS_MD_UT_SERVER,
 | |
|                      &dwUseDsMapper );
 | |
|                      
 | |
|         fUseDSMapper = !!dwUseDsMapper;
 | |
| 
 | |
|         //
 | |
|         // lookup if client certificates are required on site (or site's root level)
 | |
|         //
 | |
|         
 | |
|         _snwprintf( achMBPath,
 | |
|                 sizeof( achMBPath ) / sizeof( WCHAR ) - 1,
 | |
|                 L"/%d/root/",
 | |
|                 dwSiteId );
 | |
|     
 | |
|         mb.GetDword( achMBPath,
 | |
|                      MD_SSL_ACCESS_PERM,
 | |
|                      IIS_MD_UT_FILE,
 | |
|                      &dwSslAccessPerm );
 | |
|                      
 | |
|         fRequireClientCert = ( ( dwSslAccessPerm & MD_ACCESS_REQUIRE_CERT ) &&
 | |
|                                 ( dwSslAccessPerm & MD_ACCESS_NEGO_CERT ) );
 | |
| 
 | |
|         //
 | |
|         // lookup Certificate revocation related parameters
 | |
|         //
 | |
|         
 | |
|         _snwprintf( achMBPath,
 | |
|                     sizeof( achMBPath ) / sizeof( WCHAR ) - 1,
 | |
|                     L"/%d/",
 | |
|                     dwSiteId );
 | |
|         
 | |
|         mb.GetDword( achMBPath,
 | |
|                      MD_CERT_CHECK_MODE,
 | |
|                      IIS_MD_UT_SERVER,
 | |
|                      &dwCertCheckMode );
 | |
|         
 | |
|         mb.GetDword( achMBPath,
 | |
|                      MD_REVOCATION_FRESHNESS_TIME,
 | |
|                      IIS_MD_UT_SERVER,
 | |
|                      &dwRevocationFreshnessTime );
 | |
|         
 | |
|         mb.GetDword( achMBPath,
 | |
|                      MD_REVOCATION_URL_RETRIEVAL_TIMEOUT,
 | |
|                      IIS_MD_UT_SERVER,
 | |
|                      &dwRevocationUrlRetrievalTimeout );
 | |
|         
 | |
|         mb.Close();
 | |
|     }
 | |
| 
 | |
|    
 | |
|     //
 | |
|     // We have enough to lookup in SERVER_CERT cache
 | |
|     //
 | |
|     
 | |
|     hr = SERVER_CERT::GetServerCertificate( dwSiteId,
 | |
|                                             &pServerCert );
 | |
|     if ( FAILED( hr ) )
 | |
|     {
 | |
|         //
 | |
|         // If we couldn't get a server cert, then we're toast and SSL will
 | |
|         // not be enablable for this site.
 | |
|         //
 | |
|         
 | |
|         return hr;
 | |
|     }
 | |
|     
 | |
|     DBG_ASSERT( pServerCert != NULL );
 | |
| 
 | |
|     
 | |
|     //
 | |
|     // OK.  Create the config and attempt to add it to the cache
 | |
|     //
 | |
| 
 | |
|     pSiteConfig = new SITE_CONFIG( dwSiteId, 
 | |
|                                    pServerCert,
 | |
|                                    fRequireClientCert,
 | |
|                                    fUseDSMapper,
 | |
|                                    dwCertCheckMode,
 | |
|                                    dwRevocationFreshnessTime,
 | |
|                                    dwRevocationUrlRetrievalTimeout );
 | |
|     if ( pSiteConfig == NULL )
 | |
|     {
 | |
|         pServerCert->DereferenceServerCert();
 | |
|         return HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
 | |
|     }
 | |
|     
 | |
|     //
 | |
|     // Acquire credentials
 | |
|     //
 | |
|     
 | |
|     hr = pSiteConfig->AcquireCredentials();
 | |
|     if ( FAILED( hr ) )
 | |
|     {
 | |
|         delete pSiteConfig;
 | |
|         return hr;
 | |
|     }
 | |
|     
 | |
|     //
 | |
|     // We don't care what the success of the insertion was.  If it failed,
 | |
|     // then the pSiteConfig will not be extra referenced and the caller
 | |
|     // will clean it up when it derefs
 | |
|     //
 | |
|      
 | |
|     sm_pSiteConfigHash->InsertRecord( pSiteConfig ); 
 | |
|     
 | |
|     *ppSiteConfig = pSiteConfig;
 | |
|     
 | |
|     return NO_ERROR;
 | |
| }
 | |
| 
 | |
| //static
 | |
| LK_PREDICATE
 | |
| SITE_CONFIG::ServerCertPredicate(
 | |
|     SITE_CONFIG *           pSiteConfig,
 | |
|     void *                  pvState
 | |
| )
 | |
| /*++
 | |
| 
 | |
|   Description:
 | |
| 
 | |
|     DeleteIf() predicate used to find items which reference the 
 | |
|     SERVER_CERT pointed to by pvState    
 | |
| 
 | |
|   Arguments:
 | |
| 
 | |
|     pSiteConfig - Site config (duh)
 | |
|     pvState - SERVER_CERT to check for
 | |
| 
 | |
|   Returns:
 | |
| 
 | |
|     LK_PREDICATE   - LKP_PERFORM indicates removing the current 
 | |
|                                  token from token cache
 | |
| 
 | |
|                      LKP_NO_ACTION indicates doing nothing.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|     LK_PREDICATE          lkpAction;
 | |
|     SERVER_CERT *         pServerCert;
 | |
| 
 | |
|     DBG_ASSERT( pSiteConfig != NULL );
 | |
|     
 | |
|     pServerCert = (SERVER_CERT*) pvState;
 | |
|     DBG_ASSERT( pServerCert != NULL );
 | |
|     
 | |
|     if ( pSiteConfig->QueryServerCert() == pServerCert )
 | |
|     {
 | |
|         lkpAction = LKP_PERFORM;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         lkpAction = LKP_NO_ACTION;
 | |
|     }
 | |
| 
 | |
|     return lkpAction;
 | |
| } 
 | |
| 
 | |
| //static
 | |
| HRESULT
 | |
| SITE_CONFIG::FlushByServerCert(
 | |
|     SERVER_CERT *           pServerCert
 | |
| )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|     Flush the SITE_CONFIG cache of anything referecing the given server
 | |
|     certificate
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|     pServerCert - Server certificate to reference
 | |
| 
 | |
| Return Value:
 | |
| 
 | |
|     HRESULT
 | |
| 
 | |
| --*/
 | |
| {
 | |
|     DBG_ASSERT( sm_pSiteConfigHash != NULL );
 | |
|     
 | |
|     sm_pSiteConfigHash->DeleteIf( SITE_CONFIG::ServerCertPredicate,
 | |
|                                   pServerCert );
 | |
|     
 | |
|     return NO_ERROR;
 | |
| }
 | |
| 
 | |
| //static
 | |
| LK_PREDICATE
 | |
| SITE_CONFIG::SiteIdPredicate(
 | |
|     SITE_CONFIG *           pSiteConfig,
 | |
|     void *                  pvState
 | |
| )
 | |
| /*++
 | |
| 
 | |
|   Description:
 | |
| 
 | |
|     DeleteIf() predicate to delete config specified by site id (pvState)
 | |
| 
 | |
|   Arguments:
 | |
| 
 | |
|     pSiteConfig - Site config (duh)
 | |
|     pvState - Site ID
 | |
| 
 | |
|   Returns:
 | |
| 
 | |
|     LK_PREDICATE   - LKP_PERFORM indicates removing the current 
 | |
|                                  token from token cache
 | |
| 
 | |
|                      LKP_NO_ACTION indicates doing nothing.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|     LK_PREDICATE            lkpAction;
 | |
|     DWORD                   dwSiteId;
 | |
| 
 | |
|     DBG_ASSERT( pSiteConfig != NULL );
 | |
|     
 | |
|     dwSiteId = PtrToUlong(pvState);
 | |
|     
 | |
|     if ( pSiteConfig->QuerySiteId() == dwSiteId ||
 | |
|          dwSiteId == 0 )
 | |
|     {
 | |
|         lkpAction = LKP_PERFORM;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         lkpAction = LKP_NO_ACTION;
 | |
|     }
 | |
| 
 | |
|     return lkpAction;
 | |
| } 
 | |
| 
 | |
| //static
 | |
| HRESULT
 | |
| SITE_CONFIG::FlushBySiteId(
 | |
|     DWORD                   dwSiteId
 | |
| )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|     Flush specified site configuration.  If dwSiteId is 0, then flush all
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|     dwSiteId - Site ID to flush (0 for all)
 | |
| 
 | |
| Return Value:
 | |
| 
 | |
|     HRESULT
 | |
| 
 | |
| --*/
 | |
| {
 | |
|     DBG_ASSERT( sm_pSiteConfigHash != NULL );
 | |
|     
 | |
|     sm_pSiteConfigHash->DeleteIf( SITE_CONFIG::SiteIdPredicate,
 | |
|                                   (PVOID) UIntToPtr(dwSiteId) );
 | |
| 
 | |
|     return NO_ERROR;
 | |
| }
 | |
| 
 | |
| SITE_CONFIG::~SITE_CONFIG()
 | |
| {
 | |
|     if ( _pServerCert != NULL )
 | |
|     {
 | |
|         _pServerCert->DereferenceServerCert();
 | |
|         _pServerCert = NULL;
 | |
|     }
 | |
|     
 | |
|     _dwSignature = SITE_CONFIG_SIGNATURE_FREE;
 | |
| }
 | |
| 
 | |
| HRESULT
 | |
| SITE_CONFIG::AcquireCredentials(
 | |
|     VOID
 | |
| )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|     To the Schannel thing to get credentials handles representing the 
 | |
|     server cert/mapping configuration of this site
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|     None
 | |
| 
 | |
| Return Value:
 | |
| 
 | |
|     HRESULT
 | |
| 
 | |
| --*/
 | |
| {
 | |
|     DBG_ASSERT( _pServerCert != NULL );
 | |
|     
 | |
|     return _SiteCreds.AcquireCredentials( _pServerCert,
 | |
|                                           _fUseDSMapper );
 | |
|                                         
 | |
| }
 |