|
|
//+-------------------------------------------------------------------------
//
// Microsoft Windows NT
//
// Copyright (C) Microsoft Corporation, 1995 - 1998
//
// File: cephash.cpp
//
// Contents: Cisco enrollment protocal implementation
//
//--------------------------------------------------------------------------
#include "global.hxx"
#include <dbgdef.h>
CEP_HASH_TABLE_INFO g_CEPHashTable;
//***************************************************************************
//
// The following are APIs called internally.
//
//
//***************************************************************************
//--------------------------------------------------------------------------
//
// CEPHashFreeHashEntry
//
//--------------------------------------------------------------------------
void CEPHashFreeHashEntry(CEP_HASH_ENTRY *pHashEntry) { if(pHashEntry) { if(pHashEntry->pszTransactionID) free(pHashEntry->pszTransactionID);
free(pHashEntry); } }
//--------------------------------------------------------------------------
//
// CEPHashFreeTimeEntry
//
//--------------------------------------------------------------------------
void CEPHashFreeTimeEntry(CEP_TIME_ENTRY *pTimeEntry, BOOL fFreeHashEntry) { if(pTimeEntry) { if(fFreeHashEntry) CEPHashFreeHashEntry(pTimeEntry->pHashEntry);
free(pTimeEntry); } }
//--------------------------------------------------------------------------
//
// CEPHashByte
//
// For any cases that we can not convert the psz, we use index 0.
//--------------------------------------------------------------------------
BOOL CEPHashByte(LPSTR psz, DWORD *pdw) { CHAR sz[3];
*pdw=0;
if(!psz) return FALSE;
if(2 <= strlen(psz)) {
memcpy(sz, psz, 2 * sizeof(CHAR)); sz[2]='\0';
*pdw=strtoul(sz, NULL, 16);
if(ULONG_MAX == *pdw) *pdw=0; }
if(*pdw >= CEP_HASH_TABLE_SIZE) *pdw=0;
return TRUE; }
//--------------------------------------------------------------------------
//
// CEPSearchTransactionID
//
//--------------------------------------------------------------------------
CEP_HASH_ENTRY *CEPSearchTransactionID(CERT_BLOB *pTransactionID, DWORD *pdwIndex) { CEP_HASH_ENTRY *pHashEntry=NULL; DWORD dwHashIndex=0;
if(pdwIndex) *pdwIndex=0;
if(NULL==pTransactionID->pbData) return NULL;
//hash based on the 1st and 2nd character
if(!CEPHashByte((LPSTR)(pTransactionID->pbData), &dwHashIndex)) return NULL;
for(pHashEntry=g_CEPHashTable.rgHashEntry[dwHashIndex]; NULL != pHashEntry; pHashEntry=pHashEntry->pNext) { if(0==strcmp((LPSTR)(pTransactionID->pbData), pHashEntry->pszTransactionID)) { break; } }
if(pHashEntry) { if(pdwIndex) *pdwIndex=dwHashIndex; }
return pHashEntry; }
//--------------------------------------------------------------------------
//
// CEPInsertTimeEntry
//
//--------------------------------------------------------------------------
BOOL CEPInsertTimeEntry(CEP_TIME_ENTRY *pTimeEntry) { BOOL fResult=FALSE;
if(g_CEPHashTable.pTimeNew) { g_CEPHashTable.pTimeNew->pNext=pTimeEntry; pTimeEntry->pPrevious=g_CEPHashTable.pTimeNew; g_CEPHashTable.pTimeNew=pTimeEntry; } else { //no item in the list yet
g_CEPHashTable.pTimeOld=pTimeEntry; g_CEPHashTable.pTimeNew=pTimeEntry; }
fResult=TRUE;
return fResult; }
//--------------------------------------------------------------------------
//
// CEPInsertHashEntry
//
//--------------------------------------------------------------------------
BOOL CEPInsertHashEntry(CEP_HASH_ENTRY *pHashEntry, DWORD dwHashIndex) { BOOL fResult=FALSE;
if(g_CEPHashTable.rgHashEntry[dwHashIndex]) { g_CEPHashTable.rgHashEntry[dwHashIndex]->pPrevious=pHashEntry; pHashEntry->pNext=g_CEPHashTable.rgHashEntry[dwHashIndex]; g_CEPHashTable.rgHashEntry[dwHashIndex]=pHashEntry; } else { //1st item
g_CEPHashTable.rgHashEntry[dwHashIndex]=pHashEntry; }
fResult=TRUE;
return fResult; }
//--------------------------------------------------------------------------
//
// CEPHashRemoveTimeEntry
//
//--------------------------------------------------------------------------
BOOL CEPHashRemoveTimeEntry(CEP_TIME_ENTRY *pTimeEntry) { BOOL fResult=FALSE;
if(!pTimeEntry) goto InvalidArgErr;
if(pTimeEntry->pPrevious) pTimeEntry->pPrevious->pNext=pTimeEntry->pNext; else { //1st item
g_CEPHashTable.pTimeOld=pTimeEntry->pNext; }
if(pTimeEntry->pNext) pTimeEntry->pNext->pPrevious=pTimeEntry->pPrevious; else { //last itme
g_CEPHashTable.pTimeNew=pTimeEntry->pPrevious;
}
fResult=TRUE;
CommonReturn:
return fResult;
ErrorReturn:
fResult=FALSE; goto CommonReturn;
SET_ERROR(InvalidArgErr, E_INVALIDARG); }
//--------------------------------------------------------------------------
//
// CEPHashRemoveHashEntry
//
//--------------------------------------------------------------------------
BOOL CEPHashRemoveHashEntry(CEP_HASH_ENTRY *pHashEntry, DWORD dwIndex) { BOOL fResult=FALSE;
if(!pHashEntry) goto InvalidArgErr;
if(pHashEntry->pPrevious) pHashEntry->pPrevious->pNext=pHashEntry->pNext; else g_CEPHashTable.rgHashEntry[dwIndex]=pHashEntry->pNext;
if(pHashEntry->pNext) pHashEntry->pNext->pPrevious=pHashEntry->pPrevious;
fResult=TRUE;
CommonReturn:
return fResult;
ErrorReturn:
fResult=FALSE; goto CommonReturn;
SET_ERROR(InvalidArgErr, E_INVALIDARG); }
//--------------------------------------------------------------------------
//
// CEPHashCheckCurrentTime
//
// If we are still waiting for the pending results, use the default
// waiting time, otherwise, use the cach time
//--------------------------------------------------------------------------
BOOL CEPHashCheckCurrentTime(FILETIME *pTimeStamp, BOOL fFinished, DWORD dwRefreshDays) { DWORD dwDays=0; DWORD dwMinutes=0;
if(fFinished) { dwMinutes=g_dwRequestDuration; } else { dwDays=dwRefreshDays; }
return CEPHashIsCurrentTimeEntry(pTimeStamp, dwDays, dwMinutes);
}
//--------------------------------------------------------------------------
//
// CEPHashIsCurrentTimeEntry
//
// If anything went wrong, we think the time entry is not current.
//--------------------------------------------------------------------------
BOOL CEPHashIsCurrentTimeEntry(FILETIME *pTimeStamp, DWORD dwRefreshDays, DWORD dwMinutes) { BOOL fCurrent=FALSE; SYSTEMTIME SystemTime; FILETIME CurrentTime; ULARGE_INTEGER dwSeconds; ULARGE_INTEGER OldTime; FILETIME UpdatedTimeStamp;
if(!pTimeStamp) goto CLEANUP;
GetSystemTime(&SystemTime); if(!SystemTimeToFileTime(&SystemTime, &(CurrentTime))) goto CLEANUP;
//add the # of seconds
//// FILETIME is in units of 100 nanoseconds (10**-7)
if(dwRefreshDays) dwSeconds.QuadPart=dwRefreshDays * 24 * 3600; else dwSeconds.QuadPart=dwMinutes * 60;
dwSeconds.QuadPart=dwSeconds.QuadPart * 10000000;
OldTime.LowPart=pTimeStamp->dwLowDateTime; OldTime.HighPart=pTimeStamp->dwHighDateTime;
OldTime.QuadPart = OldTime.QuadPart + dwSeconds.QuadPart;
UpdatedTimeStamp.dwLowDateTime=OldTime.LowPart; UpdatedTimeStamp.dwHighDateTime=OldTime.HighPart;
//1 means CurrentTime is greater than the UpdatedTimeStamp
if( 1 == CompareFileTime(&CurrentTime, &UpdatedTimeStamp)) goto CLEANUP;
fCurrent=TRUE;
CLEANUP:
return fCurrent; }
//--------------------------------------------------------------------------
//
// CEPHashRefresh
//
//--------------------------------------------------------------------------
BOOL CEPHashRefresh(DWORD dwRefreshDays) { BOOL fResult=FALSE; DWORD dwHashIndex=0; CEP_TIME_ENTRY *pTimeEntry=NULL;
while(g_CEPHashTable.pTimeOld) { if(!CEPHashCheckCurrentTime(&(g_CEPHashTable.pTimeOld->TimeStamp), g_CEPHashTable.pTimeOld->pHashEntry->fFinished, dwRefreshDays)) { if(!CEPHashByte(g_CEPHashTable.pTimeOld->pHashEntry->pszTransactionID, &dwHashIndex)) { g_CEPHashTable.pTimeOld->pPrevious=NULL; goto InvalidArgErr; }
CEPHashRemoveHashEntry(g_CEPHashTable.pTimeOld->pHashEntry, dwHashIndex);
CEPHashFreeHashEntry(g_CEPHashTable.pTimeOld->pHashEntry);
pTimeEntry=g_CEPHashTable.pTimeOld;
g_CEPHashTable.pTimeOld=g_CEPHashTable.pTimeOld->pNext;
CEPHashFreeTimeEntry(pTimeEntry, FALSE); } else { //we find a new enough entry
g_CEPHashTable.pTimeOld->pPrevious=NULL; break; } }
//we have get rid of all items
if(NULL == g_CEPHashTable.pTimeOld) g_CEPHashTable.pTimeNew=NULL;
fResult=TRUE;
CommonReturn:
return fResult;
ErrorReturn:
fResult=FALSE; goto CommonReturn;
SET_ERROR(InvalidArgErr, E_INVALIDARG); }
//***************************************************************************
//
// The following are APIs called by the upper (external) layer
//
//
//***************************************************************************
//
// Function called without critical section protection
//
//--------------------------------------------------------------------------
//
// InitHashTable
//
//--------------------------------------------------------------------------
BOOL InitHashTable() { memset(&g_CEPHashTable, 0, sizeof(CEP_HASH_TABLE_INFO));
return TRUE; }
//--------------------------------------------------------------------------
//
// ReleaseHashTable
//
//--------------------------------------------------------------------------
BOOL ReleaseHashTable() {
CEP_TIME_ENTRY *pTimeEntry=NULL;
//free the timestamp list and the hash table's doublie linked lists
if(g_CEPHashTable.pTimeOld) { do{ pTimeEntry=g_CEPHashTable.pTimeOld;
g_CEPHashTable.pTimeOld = g_CEPHashTable.pTimeOld->pNext; //free both the time entry and the hash entry
CEPHashFreeTimeEntry(pTimeEntry, TRUE); } while(g_CEPHashTable.pTimeOld); } memset(&g_CEPHashTable, 0, sizeof(CEP_HASH_TABLE_INFO));
return TRUE; }
//
// Function called with critical section protection
//
//--------------------------------------------------------------------------
//
// CEPHashGetRequestID
//
// Retriev the MS Cert Server's requestID based on the transaction ID
//--------------------------------------------------------------------------
BOOL CEPHashGetRequestID( DWORD dwRefreshDays, CERT_BLOB *pTransactionID, DWORD *pdwRequestID) { BOOL fResult=FALSE; CEP_HASH_ENTRY *pHashEntry=NULL; *pdwRequestID=0;
//we refresh the time list so that we only keep most up-to-date entries
if(0 != dwRefreshDays) CEPHashRefresh(dwRefreshDays);
if(NULL == (pHashEntry=CEPSearchTransactionID(pTransactionID, NULL))) goto InvalidArgErr;
//we do not process the stable items. They could exit due to the
//20 minutes buffer
if(!CEPHashCheckCurrentTime(&(pHashEntry->pTimeEntry->TimeStamp), pHashEntry->fFinished, dwRefreshDays)) goto InvalidArgErr;
*pdwRequestID=pHashEntry->dwRequestID;
fResult=TRUE;
CommonReturn:
return fResult;
ErrorReturn:
fResult=FALSE; goto CommonReturn;
SET_ERROR(InvalidArgErr, E_INVALIDARG); }
//--------------------------------------------------------------------------
//
// CEPHashRemoveRequestAndTransaction
//
//
//--------------------------------------------------------------------------
BOOL CEPHashRemoveRequestAndTransaction(DWORD dwRequestID, CERT_BLOB *pTransactionID) { BOOL fResult=FALSE; CEP_HASH_ENTRY *pHashEntry=NULL; DWORD dwIndex=0;
if(NULL == (pHashEntry=CEPSearchTransactionID(pTransactionID, &dwIndex))) goto InvalidArgErr;
CEPHashRemoveTimeEntry(pHashEntry->pTimeEntry);
CEPHashRemoveHashEntry(pHashEntry, dwIndex);
CEPHashFreeTimeEntry(pHashEntry->pTimeEntry, FALSE);
CEPHashFreeHashEntry(pHashEntry);
fResult=TRUE;
CommonReturn:
return fResult;
ErrorReturn:
fResult=FALSE; goto CommonReturn;
SET_ERROR(InvalidArgErr, E_INVALIDARG); } //--------------------------------------------------------------------------
//
// CEPHashMarkTransactionFinished
//
//
//--------------------------------------------------------------------------
BOOL CEPHashMarkTransactionFinished(DWORD dwRequestID, CERT_BLOB *pTransactionID) { BOOL fResult=FALSE; CEP_HASH_ENTRY *pHashEntry=NULL; DWORD dwIndex=0; SYSTEMTIME SystemTime;
if(NULL == (pHashEntry=CEPSearchTransactionID(pTransactionID, &dwIndex))) goto InvalidArgErr;
pHashEntry->fFinished=TRUE;
//re-timestamp the entry since it should last for another 20 minutes for
//retrial cases
GetSystemTime(&SystemTime); if(!SystemTimeToFileTime(&SystemTime, &(pHashEntry->pTimeEntry->TimeStamp))) goto InvalidArgErr;
fResult=TRUE;
CommonReturn:
return fResult;
ErrorReturn:
fResult=FALSE; goto CommonReturn;
SET_ERROR(InvalidArgErr, E_INVALIDARG); }
//--------------------------------------------------------------------------
//
// AddRequestAndTransaction
//
// Add a requestID and TransactionID pair
//--------------------------------------------------------------------------
BOOL CEPHashAddRequestAndTransaction(DWORD dwRefreshDays, DWORD dwRequestID, CERT_BLOB *pTransactionID) {
BOOL fResult=FALSE; SYSTEMTIME SystemTime; DWORD dwHashIndex=0;
CEP_HASH_ENTRY *pHashEntry=NULL; CEP_TIME_ENTRY *pTimeEntry=NULL; //remove the old requestID/transactionID pair
CEPHashRemoveRequestAndTransaction(dwRequestID, pTransactionID);
if(!CEPHashByte((LPSTR)(pTransactionID->pbData), &dwHashIndex)) goto InvalidArgErr;
pHashEntry=(CEP_HASH_ENTRY *)malloc(sizeof(CEP_HASH_ENTRY));
if(!pHashEntry) goto MemoryErr;
memset(pHashEntry, 0, sizeof(CEP_HASH_ENTRY)); pTimeEntry=(CEP_TIME_ENTRY *)malloc(sizeof(CEP_TIME_ENTRY));
if(!pTimeEntry) goto MemoryErr;
memset(pTimeEntry, 0, sizeof(CEP_TIME_ENTRY));
pHashEntry->pszTransactionID=(LPSTR)malloc(strlen((LPSTR)(pTransactionID->pbData))+1); if(!(pHashEntry->pszTransactionID)) goto MemoryErr;
strcpy(pHashEntry->pszTransactionID,(LPSTR)(pTransactionID->pbData)); pHashEntry->dwRequestID=dwRequestID; pHashEntry->fFinished=FALSE; pHashEntry->pTimeEntry=pTimeEntry; pHashEntry->pNext=NULL; pHashEntry->pPrevious=NULL;
GetSystemTime(&SystemTime); if(!SystemTimeToFileTime(&SystemTime, &(pTimeEntry->TimeStamp))) goto TraceErr; pTimeEntry->pHashEntry=pHashEntry; pTimeEntry->pNext=NULL; pTimeEntry->pPrevious=NULL;
CEPInsertTimeEntry(pTimeEntry);
CEPInsertHashEntry(pHashEntry, dwHashIndex);
//we refresh the time list so that we only keep most up-to-date entries
if(0 != dwRefreshDays) CEPHashRefresh(dwRefreshDays);
fResult=TRUE;
CommonReturn:
return fResult;
ErrorReturn:
if(pHashEntry) CEPHashFreeHashEntry(pHashEntry);
if(pTimeEntry) CEPHashFreeTimeEntry(pTimeEntry, FALSE);
fResult=FALSE; goto CommonReturn;
SET_ERROR(InvalidArgErr, E_INVALIDARG); TRACE_ERROR(TraceErr); SET_ERROR(MemoryErr, E_OUTOFMEMORY); }
//***************************************************************************
//
// obsolete
//
//
//***************************************************************************
/*
//TODO: Send to database later
//DWORD g_dwRequestID=0;
//CERT_BLOB g_TransactionID={0, NULL};
//--------------------------------------------------------------------------
//
// GetRequestID
//
// TODO: we need to call the database layer in this case
//--------------------------------------------------------------------------
BOOL GetRequestID(CERT_BLOB *pTransactionID, DWORD *pdwRequestID) { *pdwRequestID=0;
if(NULL==pTransactionID->pbData) return FALSE;
//make sure we have the correct transaction ID
if(0!=strcmp((LPSTR)(pTransactionID->pbData), (LPSTR)(g_TransactionID.pbData))) return FALSE;
*pdwRequestID=g_dwRequestID;
return TRUE;
}
//--------------------------------------------------------------------------
//
// DeleteRequestAndTransaction
//
// TODO: we need to call the database layer in this case
//--------------------------------------------------------------------------
BOOL DeleteRequestAndTransaction(DWORD dwRequestID, CERT_BLOB *pTransactionID) { g_dwRequestID=0;
if(g_TransactionID.pbData) free(g_TransactionID.pbData);
g_TransactionID.pbData=NULL; g_TransactionID.cbData=0;
return TRUE; }
//--------------------------------------------------------------------------
//
// CopyRequestAndTransaction
//
// TODO: we need to call the database layer in this case
//--------------------------------------------------------------------------
BOOL CopyRequestAndTransaction(DWORD dwRequestID, CERT_BLOB *pTransactionID) { //delete the old requestID/transactionID pair
DeleteRequestAndTransaction(dwRequestID, pTransactionID);
g_dwRequestID=dwRequestID;
g_TransactionID.pbData=(BYTE *)malloc(strlen((LPSTR)(pTransactionID->pbData))+1);
if(NULL == g_TransactionID.pbData) { SetLastError(E_OUTOFMEMORY); return FALSE; }
g_TransactionID.cbData=strlen((LPSTR)(pTransactionID->pbData));
memcpy(g_TransactionID.pbData, (LPSTR)(pTransactionID->pbData), g_TransactionID.cbData+1);
return TRUE; } */
|