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