You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
615 lines
14 KiB
615 lines
14 KiB
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows NT
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1995 - 1998
|
|
//
|
|
// File: ceppswrd.cpp
|
|
//
|
|
// Contents: Cisco enrollment protocol implementation. This module
|
|
// implement the password hash table.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
#include "global.hxx"
|
|
#include <dbgdef.h>
|
|
|
|
DWORD g_dwPasswordCount=0;
|
|
DWORD g_dwMaxPassword=0;
|
|
DWORD g_dwPasswordValidity=0;
|
|
CEP_PASSWORD_TABLE_INFO g_CEPPasswordTable;
|
|
|
|
//***************************************************************************
|
|
//
|
|
// The following are APIs called internally.
|
|
//
|
|
//
|
|
//***************************************************************************
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// CEPPasswordFreePasswordEntry
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
void CEPPasswordFreePasswordEntry(CEP_PASSWORD_ENTRY *pPasswordEntry)
|
|
{
|
|
if(pPasswordEntry)
|
|
{
|
|
if(pPasswordEntry->pwszPassword)
|
|
free(pPasswordEntry->pwszPassword);
|
|
|
|
free(pPasswordEntry);
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// CEPPasswordFreeValidityEntry
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
void CEPPasswordFreeValidityEntry(CEP_PASSWORD_VALIDITY_ENTRY *pValidityEntry,
|
|
BOOL fFreePasswordEntry)
|
|
{
|
|
if(pValidityEntry)
|
|
{
|
|
if(fFreePasswordEntry)
|
|
CEPPasswordFreePasswordEntry(pValidityEntry->pPasswordEntry);
|
|
|
|
free(pValidityEntry);
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// CEPHashPassword
|
|
//
|
|
// For any cases that we can not convert the psz, we use index 0.
|
|
//--------------------------------------------------------------------------
|
|
BOOL CEPHashPassword(LPWSTR pwsz, DWORD *pdw)
|
|
{
|
|
WCHAR wsz[3];
|
|
|
|
*pdw=0;
|
|
|
|
if(!pwsz)
|
|
return FALSE;
|
|
|
|
if(2 <= wcslen(pwsz))
|
|
{
|
|
memcpy(wsz, pwsz, 2 * sizeof(WCHAR));
|
|
wsz[2]=L'\0';
|
|
|
|
*pdw=wcstoul(wsz, NULL, 16);
|
|
|
|
if(ULONG_MAX == *pdw)
|
|
*pdw=0;
|
|
}
|
|
|
|
if(*pdw >= CEP_HASH_TABLE_SIZE)
|
|
*pdw=0;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// CEPSearchPassword
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
CEP_PASSWORD_ENTRY *CEPSearchPassword(LPWSTR pwszPassword, DWORD *pdwIndex)
|
|
{
|
|
CEP_PASSWORD_ENTRY *pPasswordEntry=NULL;
|
|
DWORD dwHashIndex=0;
|
|
|
|
if(pdwIndex)
|
|
*pdwIndex=0;
|
|
|
|
if(NULL==pwszPassword)
|
|
return NULL;
|
|
|
|
//hash based on the 1st and 2nd character
|
|
if(!CEPHashPassword(pwszPassword, &dwHashIndex))
|
|
return NULL;
|
|
|
|
for(pPasswordEntry=g_CEPPasswordTable.rgPasswordEntry[dwHashIndex]; NULL != pPasswordEntry; pPasswordEntry=pPasswordEntry->pNext)
|
|
{
|
|
if(0==wcscmp(pwszPassword, pPasswordEntry->pwszPassword))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(pPasswordEntry)
|
|
{
|
|
if(pdwIndex)
|
|
*pdwIndex=dwHashIndex;
|
|
}
|
|
|
|
return pPasswordEntry;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// CEPInsertValidityEntry
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
BOOL CEPInsertValidityEntry(CEP_PASSWORD_VALIDITY_ENTRY *pValidityEntry)
|
|
{
|
|
if(!pValidityEntry)
|
|
return FALSE;
|
|
|
|
if(g_CEPPasswordTable.pTimeNew)
|
|
{
|
|
g_CEPPasswordTable.pTimeNew->pNext=pValidityEntry;
|
|
pValidityEntry->pPrevious=g_CEPPasswordTable.pTimeNew;
|
|
g_CEPPasswordTable.pTimeNew=pValidityEntry;
|
|
}
|
|
else
|
|
{
|
|
//no item in the list yet
|
|
g_CEPPasswordTable.pTimeOld=pValidityEntry;
|
|
g_CEPPasswordTable.pTimeNew=pValidityEntry;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// CEPInsertPasswordEntry
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
BOOL CEPInsertPasswordEntry(CEP_PASSWORD_ENTRY *pPasswordEntry, DWORD dwHashIndex)
|
|
{
|
|
|
|
if(!pPasswordEntry)
|
|
return FALSE;
|
|
|
|
if(g_CEPPasswordTable.rgPasswordEntry[dwHashIndex])
|
|
{
|
|
g_CEPPasswordTable.rgPasswordEntry[dwHashIndex]->pPrevious=pPasswordEntry;
|
|
pPasswordEntry->pNext=g_CEPPasswordTable.rgPasswordEntry[dwHashIndex];
|
|
g_CEPPasswordTable.rgPasswordEntry[dwHashIndex]=pPasswordEntry;
|
|
}
|
|
else
|
|
{
|
|
//1st item
|
|
g_CEPPasswordTable.rgPasswordEntry[dwHashIndex]=pPasswordEntry;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// CEPPasswordRemoveValidityEntry
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
BOOL CEPPasswordRemoveValidityEntry(CEP_PASSWORD_VALIDITY_ENTRY *pValidityEntry)
|
|
{
|
|
BOOL fResult=FALSE;
|
|
|
|
if(!pValidityEntry)
|
|
goto InvalidArgErr;
|
|
|
|
if(pValidityEntry->pPrevious)
|
|
pValidityEntry->pPrevious->pNext=pValidityEntry->pNext;
|
|
else
|
|
{
|
|
//1st item
|
|
g_CEPPasswordTable.pTimeOld=pValidityEntry->pNext;
|
|
}
|
|
|
|
if(pValidityEntry->pNext)
|
|
pValidityEntry->pNext->pPrevious=pValidityEntry->pPrevious;
|
|
else
|
|
{
|
|
//last itme
|
|
g_CEPPasswordTable.pTimeNew=pValidityEntry->pPrevious;
|
|
|
|
}
|
|
|
|
fResult=TRUE;
|
|
|
|
CommonReturn:
|
|
|
|
return fResult;
|
|
|
|
ErrorReturn:
|
|
|
|
fResult=FALSE;
|
|
goto CommonReturn;
|
|
|
|
SET_ERROR(InvalidArgErr, E_INVALIDARG);
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// CEPPasswordRemovePasswordEntry
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
BOOL CEPPasswordRemovePasswordEntry(CEP_PASSWORD_ENTRY *pPasswordEntry, DWORD dwIndex)
|
|
{
|
|
BOOL fResult=FALSE;
|
|
|
|
if(!pPasswordEntry)
|
|
goto InvalidArgErr;
|
|
|
|
|
|
if(pPasswordEntry->pPrevious)
|
|
pPasswordEntry->pPrevious->pNext=pPasswordEntry->pNext;
|
|
else
|
|
g_CEPPasswordTable.rgPasswordEntry[dwIndex]=pPasswordEntry->pNext;
|
|
|
|
if(pPasswordEntry->pNext)
|
|
pPasswordEntry->pNext->pPrevious=pPasswordEntry->pPrevious;
|
|
|
|
fResult=TRUE;
|
|
|
|
CommonReturn:
|
|
|
|
return fResult;
|
|
|
|
ErrorReturn:
|
|
|
|
fResult=FALSE;
|
|
goto CommonReturn;
|
|
|
|
SET_ERROR(InvalidArgErr, E_INVALIDARG);
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// CEPPasswordRefresh
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
BOOL CEPPasswordRefresh()
|
|
{
|
|
BOOL fResult=FALSE;
|
|
DWORD dwHashIndex=0;
|
|
CEP_PASSWORD_VALIDITY_ENTRY *pValidityEntry=NULL;
|
|
|
|
while(g_CEPPasswordTable.pTimeOld)
|
|
{
|
|
if(!CEPHashIsCurrentTimeEntry(&(g_CEPPasswordTable.pTimeOld->TimeStamp), 0, g_dwPasswordValidity))
|
|
{
|
|
if(!CEPHashPassword(g_CEPPasswordTable.pTimeOld->pPasswordEntry->pwszPassword, &dwHashIndex))
|
|
{
|
|
g_CEPPasswordTable.pTimeOld->pPrevious=NULL;
|
|
goto InvalidArgErr;
|
|
}
|
|
|
|
CEPPasswordRemovePasswordEntry(g_CEPPasswordTable.pTimeOld->pPasswordEntry, dwHashIndex);
|
|
|
|
CEPPasswordFreePasswordEntry(g_CEPPasswordTable.pTimeOld->pPasswordEntry);
|
|
|
|
pValidityEntry=g_CEPPasswordTable.pTimeOld;
|
|
|
|
g_CEPPasswordTable.pTimeOld=g_CEPPasswordTable.pTimeOld->pNext;
|
|
|
|
CEPPasswordFreeValidityEntry(pValidityEntry, FALSE);
|
|
|
|
if(g_dwPasswordCount >= 1)
|
|
g_dwPasswordCount--;
|
|
}
|
|
else
|
|
{
|
|
//we find a new enough entry
|
|
g_CEPPasswordTable.pTimeOld->pPrevious=NULL;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
//we have get rid of all items
|
|
if(NULL == g_CEPPasswordTable.pTimeOld)
|
|
{
|
|
g_CEPPasswordTable.pTimeNew=NULL;
|
|
g_dwPasswordCount=0;
|
|
}
|
|
|
|
|
|
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
|
|
//
|
|
//
|
|
//***************************************************************************
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// InitPasswordTable
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
BOOL WINAPI InitPasswordTable()
|
|
{
|
|
DWORD cbData=0;
|
|
DWORD dwData=0;
|
|
DWORD dwType=0;
|
|
|
|
HKEY hKey=NULL;
|
|
|
|
memset(&g_CEPPasswordTable, 0, sizeof(CEP_PASSWORD_TABLE_INFO));
|
|
|
|
g_dwPasswordCount=0;
|
|
g_dwMaxPassword=CEP_MAX_PASSWORD;
|
|
g_dwPasswordValidity=CEP_PASSWORD_VALIDITY;
|
|
|
|
if(ERROR_SUCCESS == RegOpenKeyExU(
|
|
HKEY_LOCAL_MACHINE,
|
|
MSCEP_PASSWORD_MAX_LOCATION,
|
|
0,
|
|
KEY_READ,
|
|
&hKey))
|
|
{
|
|
cbData=sizeof(dwData);
|
|
|
|
if(ERROR_SUCCESS == RegQueryValueExU(
|
|
hKey,
|
|
MSCEP_KEY_PASSWORD_MAX,
|
|
NULL,
|
|
&dwType,
|
|
(BYTE *)&dwData,
|
|
&cbData))
|
|
{
|
|
if ((dwType == REG_DWORD) ||
|
|
(dwType == REG_BINARY))
|
|
{
|
|
g_dwMaxPassword=dwData;
|
|
}
|
|
}
|
|
}
|
|
|
|
dwType=0;
|
|
dwData=0;
|
|
if(hKey)
|
|
RegCloseKey(hKey);
|
|
|
|
hKey=NULL;
|
|
|
|
if(ERROR_SUCCESS == RegOpenKeyExU(
|
|
HKEY_LOCAL_MACHINE,
|
|
MSCEP_PASSWORD_VALIDITY_LOCATION,
|
|
0,
|
|
KEY_READ,
|
|
&hKey))
|
|
{
|
|
cbData=sizeof(dwData);
|
|
|
|
if(ERROR_SUCCESS == RegQueryValueExU(
|
|
hKey,
|
|
MSCEP_KEY_PASSWORD_VALIDITY,
|
|
NULL,
|
|
&dwType,
|
|
(BYTE *)&dwData,
|
|
&cbData))
|
|
{
|
|
if ((dwType == REG_DWORD) ||
|
|
(dwType == REG_BINARY))
|
|
{
|
|
g_dwPasswordValidity=dwData;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(hKey)
|
|
RegCloseKey(hKey);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// ReleasePasswordTable
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
BOOL WINAPI ReleasePasswordTable()
|
|
{
|
|
|
|
CEP_PASSWORD_VALIDITY_ENTRY *pValidityEntry=NULL;
|
|
|
|
//free the timestamp list and the password table's doublie linked lists
|
|
if(g_CEPPasswordTable.pTimeOld)
|
|
{
|
|
do{
|
|
pValidityEntry=g_CEPPasswordTable.pTimeOld;
|
|
|
|
g_CEPPasswordTable.pTimeOld = g_CEPPasswordTable.pTimeOld->pNext;
|
|
|
|
CEPPasswordFreeValidityEntry(pValidityEntry, TRUE);
|
|
}
|
|
while(g_CEPPasswordTable.pTimeOld);
|
|
}
|
|
|
|
memset(&g_CEPPasswordTable, 0, sizeof(CEP_PASSWORD_TABLE_INFO));
|
|
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// CEPAddPasswordToTable
|
|
//
|
|
// Need to be protected by the critical section.
|
|
//
|
|
// Last error is set to CRYPT_E_NO_MATCH if the max number of password is
|
|
// reached.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
BOOL WINAPI CEPAddPasswordToTable(LPWSTR pwszPassword)
|
|
{
|
|
BOOL fResult=FALSE;
|
|
SYSTEMTIME SystemTime;
|
|
DWORD dwHashIndex=0;
|
|
|
|
|
|
CEP_PASSWORD_ENTRY *pPasswordEntry=NULL;
|
|
CEP_PASSWORD_VALIDITY_ENTRY *pValidityEntry=NULL;
|
|
|
|
EnterCriticalSection(&PasswordCriticalSec);
|
|
|
|
if(NULL==pwszPassword)
|
|
goto InvalidArgErr;
|
|
|
|
//delete all expired passwords
|
|
CEPPasswordRefresh();
|
|
|
|
if(g_dwPasswordCount >= g_dwMaxPassword)
|
|
goto NoMatchErr;
|
|
|
|
g_dwPasswordCount++;
|
|
|
|
if(!CEPHashPassword(pwszPassword, &dwHashIndex))
|
|
goto InvalidArgErr;
|
|
|
|
|
|
pPasswordEntry=(CEP_PASSWORD_ENTRY *)malloc(sizeof(CEP_PASSWORD_ENTRY));
|
|
|
|
if(!pPasswordEntry)
|
|
goto MemoryErr;
|
|
|
|
memset(pPasswordEntry, 0, sizeof(CEP_PASSWORD_ENTRY));
|
|
|
|
pValidityEntry=(CEP_PASSWORD_VALIDITY_ENTRY *)malloc(sizeof(CEP_PASSWORD_VALIDITY_ENTRY));
|
|
|
|
if(!pValidityEntry)
|
|
goto MemoryErr;
|
|
|
|
memset(pValidityEntry, 0, sizeof(CEP_PASSWORD_VALIDITY_ENTRY));
|
|
|
|
pPasswordEntry->pwszPassword=(LPWSTR)malloc(sizeof(WCHAR) * (wcslen(pwszPassword)+1));
|
|
if(!(pPasswordEntry->pwszPassword))
|
|
goto MemoryErr;
|
|
|
|
wcscpy(pPasswordEntry->pwszPassword,pwszPassword);
|
|
|
|
//no usage has been requested
|
|
pPasswordEntry->dwUsageRequested=0;
|
|
pPasswordEntry->pValidityEntry=pValidityEntry;
|
|
pPasswordEntry->pNext=NULL;
|
|
pPasswordEntry->pPrevious=NULL;
|
|
|
|
GetSystemTime(&SystemTime);
|
|
if(!SystemTimeToFileTime(&SystemTime, &(pValidityEntry->TimeStamp)))
|
|
goto TraceErr;
|
|
|
|
pValidityEntry->pPasswordEntry=pPasswordEntry;
|
|
pValidityEntry->pNext=NULL;
|
|
pValidityEntry->pPrevious=NULL;
|
|
|
|
|
|
CEPInsertValidityEntry(pValidityEntry);
|
|
|
|
CEPInsertPasswordEntry(pPasswordEntry, dwHashIndex);
|
|
|
|
fResult=TRUE;
|
|
|
|
CommonReturn:
|
|
|
|
LeaveCriticalSection(&PasswordCriticalSec);
|
|
|
|
return fResult;
|
|
|
|
ErrorReturn:
|
|
|
|
if(pPasswordEntry)
|
|
CEPPasswordFreePasswordEntry(pPasswordEntry);
|
|
|
|
if(pValidityEntry)
|
|
CEPPasswordFreeValidityEntry(pValidityEntry, FALSE);
|
|
|
|
fResult=FALSE;
|
|
goto CommonReturn;
|
|
|
|
SET_ERROR(NoMatchErr, CRYPT_E_NO_MATCH);
|
|
TRACE_ERROR(TraceErr);
|
|
SET_ERROR(InvalidArgErr, E_INVALIDARG);
|
|
SET_ERROR(MemoryErr, E_OUTOFMEMORY);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// CEPVerifyPasswordAndDeleteFromTable
|
|
//
|
|
// Need to be protected by the critical section.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
BOOL WINAPI CEPVerifyPasswordAndDeleteFromTable(LPWSTR pwszPassword, DWORD dwUsage)
|
|
{
|
|
BOOL fResult=FALSE;
|
|
CEP_PASSWORD_ENTRY *pPasswordEntry=NULL;
|
|
DWORD dwIndex=0;
|
|
|
|
EnterCriticalSection(&PasswordCriticalSec);
|
|
|
|
//delete all expired passwords
|
|
CEPPasswordRefresh();
|
|
|
|
if(NULL == (pPasswordEntry=CEPSearchPassword(pwszPassword, &dwIndex)))
|
|
goto InvalidArgErr;
|
|
|
|
//verify the usage.
|
|
|
|
//only one signature and one exchange key per password
|
|
if(0 != ((pPasswordEntry->dwUsageRequested) & dwUsage))
|
|
goto InvalidArgErr;
|
|
|
|
pPasswordEntry->dwUsageRequested = (pPasswordEntry->dwUsageRequested) | dwUsage;
|
|
|
|
//remove the password only if both signature and exchange key are requested
|
|
if(((pPasswordEntry->dwUsageRequested) & CEP_REQUEST_SIGNATURE) &&
|
|
((pPasswordEntry->dwUsageRequested) & CEP_REQUEST_EXCHANGE))
|
|
{
|
|
|
|
CEPPasswordRemoveValidityEntry(pPasswordEntry->pValidityEntry);
|
|
|
|
CEPPasswordRemovePasswordEntry(pPasswordEntry, dwIndex);
|
|
|
|
CEPPasswordFreeValidityEntry(pPasswordEntry->pValidityEntry, FALSE);
|
|
|
|
CEPPasswordFreePasswordEntry(pPasswordEntry);
|
|
|
|
if(g_dwPasswordCount >= 1)
|
|
g_dwPasswordCount--;
|
|
}
|
|
|
|
fResult=TRUE;
|
|
|
|
|
|
CommonReturn:
|
|
|
|
LeaveCriticalSection(&PasswordCriticalSec);
|
|
|
|
return fResult;
|
|
|
|
ErrorReturn:
|
|
|
|
fResult=FALSE;
|
|
goto CommonReturn;
|
|
|
|
SET_ERROR(InvalidArgErr, E_INVALIDARG);
|
|
}
|
|
|
|
|
|
|