|
|
/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
certcach.cxx
Abstract:
Contains class implementation for certificate cache object. This object will hold various Certificate entries.
Contents: SECURITY_CACHE_LIST_ENTRY::SECURITY_CACHE_LIST_ENTRY SECURITY_CACHE_LIST_ENTRY::~SECURITY_CACHE_LIST_ENTRY SECURITY_CACHE_LIST_ENTRY::AddRef SECURITY_CACHE_LIST_ENTRY::Release SECURITY_CACHE_LIST_ENTRY::Clear SECURITY_CACHE_LIST::Find SECURITY_CACHE_LIST::Add SECURITY_CACHE_LIST::ClearList
TODO: Add Cert validation. What if Cert is given but different?
Author:
Arthur L Bierer (arthurbi) 20-Apr-1996
Revision History:
20-Apr-1996 arthurbi Created
--*/ #include <wininetp.h>
//
// private manifests
//
#define MAX_CERT_CACHE_CERTS 16
//
// private types
//
//
// SECURITY_CACHE_LIST_ENTRY member functions
//
SECURITY_CACHE_LIST_ENTRY::SECURITY_CACHE_LIST_ENTRY( IN LPSTR lpszHostName )
/*++
Routine Description:
SECURITY_CACHE_LIST_ENTRY constructor. Create object; don't add it to list
Arguments:
lpszHostName - name of host for which this cache entry created
Return Value:
None.
--*/
{ DEBUG_ENTER((DBG_OBJECTS, None, "SECURITY_CACHE_LIST_ENTRY::SECURITY_CACHE_LIST_ENTRY", "%q", lpszHostName ));
#if INET_DEBUG
_List.Flink = _List.Blink = NULL; #endif
_cRef = 1; _fInCache = FALSE; _ServerName = lpszHostName; ZeroMemory(&_CertInfo, sizeof(_CertInfo)); _dwSecurityFlags = 0; _dwStatusFlags = 0; _pCertContextArray = NULL;
#if INET_DEBUG
m_Signature = 0x454c4353; // 'SCLE'
#endif
DEBUG_LEAVE(0); }
SECURITY_CACHE_LIST_ENTRY::~SECURITY_CACHE_LIST_ENTRY()
/*++
Routine Description:
SECURITY_CACHE_LIST_ENTRY destructor.
Arguments:
None.
Return Value:
None.
--*/
{ DEBUG_ENTER((DBG_OBJECTS, None, "~SECURITY_CACHE_LIST_ENTRY", "{%#x [%q]}", this, _ServerName.StringAddress() ));
INET_ASSERT((_List.Flink == NULL) && (_List.Blink == NULL));
Clear();
DEBUG_LEAVE(0); }
LONG SECURITY_CACHE_LIST_ENTRY::AddRef( VOID )
/*++
Routine Description:
Increment reference count of SECURITY_CACHE_LIST_ENTRY
Arguments:
None.
Return Value:
LONG - reference count after increment
--*/
{ DEBUG_ENTER((DBG_OBJECTS, Int, "SECURITY_CACHE_LIST_ENTRY::AddRef", "{%#x [%q, %d]}", this, _ServerName.StringAddress(), _cRef ));
InterlockedIncrement(&_cRef);
DEBUG_LEAVE(_cRef);
return _cRef; }
LONG SECURITY_CACHE_LIST_ENTRY::Release( VOID )
/*++
Routine Description:
Decrement reference count and destroy object if (<=) zero
Arguments:
None.
Return Value:
LONG - reference count after decrement
--*/
{ DEBUG_ENTER((DBG_OBJECTS, Int, "SECURITY_CACHE_LIST_ENTRY::Release", "{%q [%d]}", _ServerName.StringAddress(), _cRef ));
LONG cRet;
if (0 >= (cRet = InterlockedDecrement(&_cRef))) { delete this; }
DEBUG_LEAVE(cRet);
return cRet; }
VOID SECURITY_CACHE_LIST_ENTRY::Clear()
/*++
Routine Description:
Clear out SECURITY_CACHE_LIST_ENTRY
Arguments:
Clear -
Return Value:
None.
--*/
{ if (_CertInfo.pCertificate != NULL) { SAFE_WRAP_REVERT_USER_VOID(CertFreeCertificateContext, (_CertInfo.pCertificate)); _CertInfo.pCertificate = NULL; }
ZeroMemory(&_CertInfo, sizeof(_CertInfo)); _CertInfo.dwSize = sizeof(_CertInfo);
_dwSecurityFlags = 0; _dwStatusFlags = 0; _ServerName = NULL; if( _pCertContextArray ) { delete _pCertContextArray; _pCertContextArray = NULL; } }
//
// SECURITY_CACHE_LIST member functions
//
VOID SECURITY_CACHE_LIST::ClearList( VOID )
/*++
Routine Description:
description-of-function.
Arguments:
None.
Return Value:
None.
--*/
{ DEBUG_ENTER((DBG_OBJECTS, None, "SECURITY_CACHE_LIST::ClearList", NULL ));
if (!LockSerializedList(&_List)) { DEBUG_PRINT(OBJECTS, ERROR, ("Failed to obtain lock -- SECURITY_CACHE_LIST potentially leaked\n" )); goto quit; }
while (!IsSerializedListEmpty(&_List)) {
SECURITY_CACHE_LIST_ENTRY * CacheEntry;
//
// remove the PROXY_SERVER_LIST_ENTRY at the head of the serialized
// list
//
LPVOID entry = SlDequeueHead(&_List);
//
// entry should not be NULL - IsSerializedListEmpty() told us we
// could expect something
//
INET_ASSERT(entry != NULL);
//
// get the address of the object (should be the same as entry) and
// delete it
//
CacheEntry = CONTAINING_RECORD(entry, SECURITY_CACHE_LIST_ENTRY, _List);
DEBUG_PRINT(OBJECTS, INFO, ("releasing %q (%d)\n", CacheEntry->_ServerName.StringAddress(), CacheEntry->_cRef ));
CacheEntry->Release(); }
UnlockSerializedList(&_List);
quit: DEBUG_LEAVE(0); }
DWORD SECURITY_CACHE_LIST::Add( IN SECURITY_CACHE_LIST_ENTRY * entry )
/*++
Routine Description:
Adds a CertInfo Structure to the list front of the list.
Arguments:
lpszHost - Hostname to add.
Return Value:
DWORD Success - ERROR_SUCCESS
Failure - ERROR_NOT_ENOUGH_MEMORY
--*/
{ DEBUG_ENTER((DBG_HTTP, Dword, "SECURITY_CACHE_LIST::Add", "%#x [%q, %d]", entry, entry ? entry->_ServerName.StringAddress() : "", entry ? entry->_cRef : 0 ));
DWORD error = ERROR_SUCCESS;
INET_ASSERT(entry != NULL);
if (entry != NULL) { if (LockSerializedList(&_List)) {
//
// If we've grown too much, nuke the oldest one.
//
if (ElementsOnSerializedList(&_List) >= MAX_CERT_CACHE_CERTS) {
SECURITY_CACHE_LIST_ENTRY *pOld; LPVOID old_entry = SlDequeueTail(&_List);
INET_ASSERT(old_entry != NULL);
pOld = CONTAINING_RECORD(old_entry, SECURITY_CACHE_LIST_ENTRY, _List);
//
// entry should not be NULL - IsSerializedListEmpty() told us we
// could expect something
//
pOld->_fInCache = FALSE;
//
// Clean Our old object, and reinstatiate with a new name.
//
pOld->Release(); } if (InsertAtHeadOfSerializedList(&_List, &entry->_List)) { entry->AddRef(); entry->_fInCache = TRUE; } UnlockSerializedList(&_List); } else error = ERROR_NOT_ENOUGH_MEMORY; }
DEBUG_LEAVE(error);
return error; }
SECURITY_CACHE_LIST_ENTRY * SECURITY_CACHE_LIST::Find( IN LPSTR lpszHost )
/*++
Routine Description:
Searches the linked list for the Cert, and returns the found entry, or NULL if not found.
Arguments:
lpszHost - Hostname to search on.
Return Value:
CERT_CACHE_LIST_ENTRY * Success - Pointer to found entry.
Failure - NULL, not found.
--*/
{ DEBUG_ENTER((DBG_HTTP, Pointer, "SECURITY_CACHE_LIST::Find", "%q", lpszHost ));
SECURITY_CACHE_LIST_ENTRY * info = NULL;
//
// BUGBUG need to validate against Server Certifcate on every
// connection, this Find only validates by Hostname.
// What about DNS spoofing? Won't we be hosed?
//
//
// TODO if found, need to push to front of list.
//
if (LockSerializedList(&_List)) { for (PLIST_ENTRY entry = HeadOfSerializedList(&_List); entry != (PLIST_ENTRY)SlSelf(&_List); entry = entry->Flink) { info = CONTAINING_RECORD(entry, SECURITY_CACHE_LIST_ENTRY, _List);
//
// check to see if they match.
//
if (info->_ServerName.Stricmp(lpszHost) == 0) { info->AddRef(); break; // match.
} info = NULL; } UnlockSerializedList(&_List); }
DEBUG_LEAVE(info);
return info; }
|