windows-nt/Source/XPSP1/NT/inetcore/digest/cache.cxx

970 lines
26 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1998 Microsoft Corporation
Module Name:
cache.cxx
Abstract:
Credential cache object for digest sspi package.
Author:
Adriaan Canter (adriaanc) 01-Aug-1998
--*/
#include "include.hxx"
//-----------------CCredCache Private Functions --------------------------------
//--------------------------------------------------------------------
// CCredCache::Lock
//--------------------------------------------------------------------
BOOL CCredCache::Lock()
{
BOOL bRet;
DWORD dwError;
dwError = WaitForSingleObject(_hMutex, INFINITE);
switch (dwError)
{
// Mutex is signalled. We own the mutex. Fall through.
case WAIT_OBJECT_0:
// The thread owning the mutex failed to release it
// before terminating. We still own the mutex.
case WAIT_ABANDONED:
bRet = TRUE;
break;
// Fall through.
case WAIT_FAILED:
// Fail.
default:
bRet = FALSE;
}
return bRet;
}
//--------------------------------------------------------------------
// CCredCache::Unlock
//--------------------------------------------------------------------
BOOL CCredCache::Unlock()
{
BOOL bRet;
bRet = ReleaseMutex(_hMutex);
return bRet;
}
//--------------------------------------------------------------------
// CCredCache::GetPtrToObject
//--------------------------------------------------------------------
LPDWORD CCredCache::GetPtrToObject(DWORD dwObject)
{
return _pMMFile->GetHeaderData(dwObject);
}
//--------------------------------------------------------------------
// CCredCache::SearchCredList
//--------------------------------------------------------------------
CCred* CCredCache::SearchCredList(CSess *pSess, LPSTR szHost,
LPSTR szRealm, LPSTR szUser, BOOL fMatchHost)
{
CList CredList;
CCred *pMatch = NULL;
if (!pSess->dwCred)
goto exit;
CredList.Init(&pSess->dwCred);
while (pMatch = (CCred*) CredList.GetNext())
{
if ((!szRealm || !lstrcmpi(szRealm, CCred::GetRealm(pMatch)))
&& (!szUser || !lstrcmpi(szUser, CCred::GetUser(pMatch))))
{
if (!fMatchHost)
break;
CNonce *pNonce;
CList NonceList;
NonceList.Init(&pMatch->dwNonce);
while (pNonce = (CNonce*) NonceList.GetNext())
{
if (CNonce::IsHostMatch(pNonce, szHost))
goto exit;
}
pMatch = NULL;
break;
}
}
exit:
return pMatch;
}
//--------------------------------------------------------------------
// CCredCache::UpdateInfoList
//--------------------------------------------------------------------
CCredInfo* CCredCache::UpdateInfoList(CCredInfo *pInfo, CCredInfo *pHead)
{
CCredInfo *pList, *pCur;
BOOL fUpdate = TRUE;
if (!pHead)
return (pInfo);
pList = pCur = pHead;
while (pCur)
{
// Do entry usernames match ?
if (!strcmp(pInfo->szUser, pCur->szUser))
{
// Is the new entry timestamp greater?
if (pInfo->tStamp > pCur->tStamp)
{
// De-link existing entry.
if (pCur->pPrev)
pCur->pPrev->pNext = pCur->pNext;
else
pList = pCur->pNext;
if (pCur->pNext)
pCur->pNext->pPrev = pCur->pPrev;
// Delete existing entry.
delete pCur;
}
else
{
// Found a match but time stamp
// of existing entry was greater.
fUpdate = FALSE;
}
break;
}
pCur = pCur->pNext;
}
// If we superceded an existing matching entry
// or found no matching entries, prepend to list.
if (fUpdate)
{
pInfo->pNext = pList;
if (pList)
pList->pPrev = pInfo;
pList = pInfo;
}
return pList;
}
//-----------------CCredCache Public Functions --------------------------------
//--------------------------------------------------------------------
// CCredCache::GetHeapPtr
//--------------------------------------------------------------------
DWORD_PTR CCredCache::GetHeapPtr()
{
return _pMMFile->GetMapPtr();
}
//--------------------------------------------------------------------
// CCredCache::IsTrustedHost
// BUGBUG - no limits on szCtx
//--------------------------------------------------------------------
BOOL CCredCache::IsTrustedHost(LPSTR szCtx, LPSTR szHost)
{
CHAR szBuf[MAX_PATH];
CHAR szRegPath[MAX_PATH];
DWORD dwType, dwError, cbBuf = MAX_PATH;
BOOL fRet = FALSE;
HKEY hHosts = (HKEY) INVALID_HANDLE_VALUE;
memcpy(szRegPath, DIGEST_HOSTS_REG_KEY, sizeof(DIGEST_HOSTS_REG_KEY) - 1);
memcpy(szRegPath + sizeof(DIGEST_HOSTS_REG_KEY) - 1, szCtx, strlen(szCtx) + 1);
if ((dwError = RegCreateKey(HKEY_CURRENT_USER, szRegPath, &hHosts)) == ERROR_SUCCESS)
{
if ((dwError = RegQueryValueEx(hHosts, szHost, NULL, &dwType, (LPBYTE) szBuf, &cbBuf)) == ERROR_SUCCESS)
{
fRet = TRUE;
}
}
if (hHosts != INVALID_HANDLE_VALUE)
RegCloseKey(hHosts);
return fRet;
}
//--------------------------------------------------------------------
// CCredCache::SetTrustedHostInfo
//--------------------------------------------------------------------
BOOL CCredCache::SetTrustedHostInfo(LPSTR szCtx, CParams *pParams)
{
CHAR szRegPath[MAX_PATH], *szUrlBuf = NULL, *szHostBuf = NULL;
DWORD dwZero = 0, dwError = ERROR_SUCCESS, cbUrlBuf, cbHostBuf;
BOOL fRet = FALSE;
HKEY hHosts = (HKEY) INVALID_HANDLE_VALUE;
// Form path to trusted host reg key.
memcpy(szRegPath, DIGEST_HOSTS_REG_KEY, sizeof(DIGEST_HOSTS_REG_KEY) - 1);
memcpy(szRegPath + sizeof(DIGEST_HOSTS_REG_KEY) - 1, szCtx, strlen(szCtx) + 1);
// Open top-level reg key.
if ((dwError = RegCreateKey(HKEY_CURRENT_USER, szRegPath, &hHosts)) != ERROR_SUCCESS)
goto exit;
// First set authenticating host in registry.
LPSTR szHost;
szHost = pParams->GetParam(CParams::HOST);
DIGEST_ASSERT(szHost);
if ((dwError = RegSetValueEx(hHosts, szHost, NULL, REG_DWORD,
(LPBYTE) &dwZero, sizeof(DWORD))) != ERROR_SUCCESS)
goto exit;
// Now check the domain header for any additional trusted hosts.
LPSTR szDomain, pszUrl;
DWORD cbDomain, cbUrl;
pszUrl = NULL;
pParams->GetParam(CParams::DOMAIN, &szDomain, &cbDomain);
if (!szDomain)
{
fRet = TRUE;
goto exit;
}
// Parse the domain header for urls. Crack each url to get the
// host and set the host value in the registry.
// First attempt to load shlwapi. If this fails then we simply do not have
// domain header support.
if (!g_hShlwapi)
{
g_hShlwapi = LoadLibrary(SHLWAPI_DLL_SZ);
if (!g_hShlwapi)
{
dwError = ERROR_DLL_INIT_FAILED;
goto exit;
}
}
// Attempt to get addresses of UrlUnescape and UrlGetPart
PFNURLUNESCAPE pfnUrlUnescape;
PFNURLGETPART pfnUrlGetPart;
pfnUrlUnescape = (PFNURLUNESCAPE) GetProcAddress(g_hShlwapi, "UrlUnescapeA");
pfnUrlGetPart = (PFNURLGETPART) GetProcAddress(g_hShlwapi, "UrlGetPartA");
if (!(pfnUrlUnescape && pfnUrlGetPart))
{
dwError = ERROR_INVALID_FUNCTION;
goto exit;
}
// Strtok through string to get each url (ws and tab delimiters)
pszUrl = NULL;
while (pszUrl = strtok((pszUrl ? NULL : szDomain), " \t"))
{
// Allocate a buffer for the url since we will first unescape it.
// Also allocate buffer for host which will be returned from
// call to shlwapi. Unescaped url and host buffer sizes are
// bounded by length of original url.
cbUrl = strlen(pszUrl) + 1;
cbUrlBuf = cbHostBuf = cbUrl;
szUrlBuf = new CHAR[cbUrlBuf];
szHostBuf = new CHAR[cbHostBuf];
if (!(szUrlBuf && szHostBuf))
{
dwError = ERROR_NOT_ENOUGH_MEMORY;
goto exit;
}
// Copy strtoked url to buffer.
memcpy(szUrlBuf, pszUrl, cbUrl);
// Unescape the url
if (S_OK == pfnUrlUnescape(szUrlBuf, NULL, NULL, URL_UNESCAPE_INPLACE))
{
// If unescape is successful, parse host from url.
if (S_OK == pfnUrlGetPart(szUrlBuf, szHostBuf, &cbHostBuf, URL_PART_HOSTNAME, 0))
{
// If parse is successful, set host in registry.
if ((dwError = RegSetValueEx(hHosts, szHostBuf, NULL, REG_DWORD,
(LPBYTE) &dwZero, sizeof(DWORD))) != ERROR_SUCCESS)
goto exit;
}
}
delete [] szUrlBuf;
delete [] szHostBuf;
szUrlBuf = szHostBuf = NULL;
}
fRet = TRUE;
// Cleanup.
exit:
DIGEST_ASSERT(dwError == ERROR_SUCCESS);
if (hHosts != INVALID_HANDLE_VALUE)
RegCloseKey(hHosts);
if (szUrlBuf)
delete [] szUrlBuf;
if (szHostBuf)
delete [] szHostBuf;
return fRet;
}
//--------------------------------------------------------------------
// CCredCache::MapHandleToSession
//--------------------------------------------------------------------
// BUGBUG - don't walk the sessionlist, just obfuscate the ptr in handle.
CSess *CCredCache::MapHandleToSession(DWORD_PTR dwSess)
{
// BUGBUG - if locking fails, return error directly,
// no last error.
CSess *pSess = NULL;
if (!Lock())
{
DIGEST_ASSERT(FALSE);
_dwStatus = GetLastError();
goto exit;
}
_pSessList->Seek();
while (pSess = (CSess*) _pSessList->GetNext())
{
if ((CSess*) (dwSess + (DWORD_PTR) _pMMFile->GetMapPtr()) == pSess)
break;
}
Unlock();
exit:
return pSess;
}
//--------------------------------------------------------------------
// CCredCache::MapSessionToHandle
//--------------------------------------------------------------------
DWORD CCredCache::MapSessionToHandle(CSess* pSess)
{
DWORD dwSess = 0;
if (!Lock())
{
DIGEST_ASSERT(FALSE);
_dwStatus = GetLastError();
goto exit;
}
dwSess = (DWORD) ((DWORD_PTR) pSess - _pMMFile->GetMapPtr());
Unlock();
exit:
return dwSess;
}
// BUGBUG - init mutex issues.
//--------------------------------------------------------------------
// CCredCache::CCredCache
//--------------------------------------------------------------------
CCredCache::CCredCache()
{
Init();
}
//--------------------------------------------------------------------
// CCredCache::~CCredCache
//--------------------------------------------------------------------
CCredCache::~CCredCache()
{
DeInit();
}
//--------------------------------------------------------------------
// CCredCache::Init
//--------------------------------------------------------------------
DWORD CCredCache::Init()
{
BOOL fFirstProc;
CHAR szMutexName[MAX_PATH];
DWORD cbMutexName = MAX_PATH;
_dwSig = SIG_CACH;
// IE5# 89288
// Get mutex name based on user
if ((_dwStatus = CMMFile::MakeUserObjectName(szMutexName,
&cbMutexName, MAKE_MUTEX_NAME)) != ERROR_SUCCESS)
return _dwStatus;
// Create/Open mutex.
_hMutex = CreateMutex(NULL, FALSE, szMutexName);
// BUGBUG - this goes at a higher level.
// BUGBUG - also watch out for failure to create mutex
// and then unlocking it.
if (_hMutex)
{
// Created/opened mutex. Flag if we're first process.
fFirstProc = (GetLastError() != ERROR_ALREADY_EXISTS);
}
else
{
// Failed to create/open mutex.
DIGEST_ASSERT(FALSE);
_dwStatus = GetLastError();
goto exit;
}
// Acquire mutex.
if (!Lock())
{
DIGEST_ASSERT(FALSE);
_dwStatus = GetLastError();
return _dwStatus;
}
// Open or create memory map.
_pMMFile = new CMMFile(CRED_CACHE_HEAP_SIZE,
CRED_CACHE_ENTRY_SIZE);
if (!_pMMFile)
{
DIGEST_ASSERT(FALSE);
_dwStatus = ERROR_NOT_ENOUGH_MEMORY;
goto exit;
}
_dwStatus = _pMMFile->Init();
if (_dwStatus != ERROR_SUCCESS)
{
DIGEST_ASSERT(FALSE);
goto exit;
}
g_pHeap = GetHeapPtr();
// Initialize session list.
// BUGBUG - check return codes on failure.
_pSessList = new CList();
DIGEST_ASSERT(_pSessList);
_pSessList->Init(GetPtrToObject(CRED_CACHE_SESSION_LIST));
exit:
// Relase mutex.
Unlock();
return _dwStatus;
}
//--------------------------------------------------------------------
// CCredCache::DeInit
//--------------------------------------------------------------------
DWORD CCredCache::DeInit()
{
// bugbug - assert session list is null and destroy.
// bugbug - release lock before closing handle.
if (!Lock())
{
DIGEST_ASSERT(FALSE);
_dwStatus = GetLastError();
goto exit;
}
delete _pMMFile;
_dwStatus = CloseHandle(_hMutex);
Unlock();
exit:
return _dwStatus;
}
//--------------------------------------------------------------------
// CCredCache::LogOnToCache
//--------------------------------------------------------------------
CSess *CCredCache::LogOnToCache(LPSTR szAppCtx, LPSTR szUserCtx, BOOL fHTTP)
{
CSess *pSessNew = NULL;
BOOL fLocked = FALSE;
// Obtain mutex.
if (!Lock())
{
DIGEST_ASSERT(FALSE);
_dwStatus = GetLastError();
goto exit;
}
fLocked = TRUE;
// For non-http clients, find or create the single
// global session which all non-http clients use.
if (!fHTTP)
{
CSess * pSess;
pSess = NULL;
_pSessList->Seek();
while (pSess = (CSess*) _pSessList->GetNext())
{
if (!pSess->fHTTP)
{
// Found the session.
pSessNew = pSess;
_dwStatus = ERROR_SUCCESS;
goto exit;
}
}
if (!pSessNew)
{
// Create the non-http gobal session.
pSessNew = CSess::Create(_pMMFile, NULL, NULL, FALSE);
}
}
else
{
// Create a session context; add to list.
pSessNew = CSess::Create(_pMMFile, szAppCtx, szUserCtx, TRUE);
}
if (!pSessNew)
{
// This reflects running out of space in the memmap
// file. Shouldn't happen in practice.
DIGEST_ASSERT(FALSE);
_dwStatus = ERROR_NOT_ENOUGH_MEMORY;
goto exit;
}
// Push this session on to the session list.
_pSessList->Insert(pSessNew);
_dwStatus = ERROR_SUCCESS;
exit:
// Release mutex.
if(fLocked)
Unlock();
return pSessNew;
}
//--------------------------------------------------------------------
// CCredCache::LogOffFromCache
//--------------------------------------------------------------------
DWORD CCredCache::LogOffFromCache(CSess *pSess)
{
CList CredList;
CCred *pCred;
// Obtain mutex.
if (!Lock())
{
DIGEST_ASSERT(FALSE);
_dwStatus = GetLastError();
goto exit;
}
if (pSess->fHTTP)
{
// Purge all credentials for this session.
// BUGBUG - not needed.
// CredList.Init((CEntry **) &pSess->pCred);
// Flush all credentials for this session
// This will also delete nonces.
FlushCreds(pSess, NULL);
// Finally, free the session.
_pSessList->DeLink(pSess);
CEntry::Free(_pMMFile, pSess);
}
_dwStatus = ERROR_SUCCESS;
// Release mutex.
Unlock();
exit:
return _dwStatus;
}
//--------------------------------------------------------------------
// CCredCache::CreateCred
//--------------------------------------------------------------------
CCred* CCredCache::CreateCred(CSess *pSess, CCredInfo *pInfo)
{
CCred* pCred = NULL, *pCredList;
CList CredList;
// Obtain mutex.
if (!Lock())
{
_dwStatus = GetLastError();
goto exit;
}
// First check to see if any credential in this session matches realm.
pCred = SearchCredList(pSess, NULL, pInfo->szRealm, NULL, FALSE);
if (pCred)
{
CredList.Init(&pSess->dwCred);
CredList.DeLink(pCred);
CCred::Free(_pMMFile, pSess, pCred);
}
// Create a credential.
// BUGBUG - this could fail, transact any cred update.
pCred = CCred::Create(_pMMFile, pInfo->szHost, pInfo->szRealm,
pInfo->szUser, pInfo->szPass, pInfo->szNonce, pInfo->szCNonce);
DIGEST_ASSERT(pCred);
// Insert into head of session's credential list.
if (!CSess::GetCred(pSess))
CSess::SetCred(pSess, pCred);
else
{
CredList.Init(&pSess->dwCred);
CredList.Insert(pCred);
}
_dwStatus = ERROR_SUCCESS;
// Relase mutex.
Unlock();
exit:
return pCred;
}
//--------------------------------------------------------------------
// CCredCache::FindCred
//--------------------------------------------------------------------
CCredInfo* CCredCache::FindCred(CSess *pSessIn, LPSTR szHost,
LPSTR szRealm, LPSTR szUser, LPSTR szNonce,
LPSTR szCNonce, DWORD dwFlags)
{
CCred *pCred;
CCredInfo *pInfo = NULL;
BOOL fLocked = FALSE;
// Obtain mutex.
if (!Lock())
{
DIGEST_ASSERT(FALSE);
_dwStatus = GetLastError();
goto exit;
}
fLocked = TRUE;
// If finding a credential for preauthentication.
if (dwFlags & FIND_CRED_PREAUTH)
{
// First search this session's credential list for a match,
// filtering on the host field in available nonces.
pCred = SearchCredList(pSessIn, szHost, szRealm, szUser, TRUE);
// If a credential is found the nonce is also required.
// We do not attempt to search other sessions for a nonce
// because nonce counts must remain in sync. See note below.
if (pCred)
{
// Increment this credential's nonce count.
CNonce *pNonce;
pNonce = CCred::GetNonce(pCred, szHost, SERVER_NONCE);
if (pNonce)
{
pNonce->cCount++;
pInfo = new CCredInfo(pCred, szHost);
if (!pInfo || pInfo->dwStatus != ERROR_SUCCESS)
{
DIGEST_ASSERT(FALSE);
_dwStatus = ERROR_NOT_ENOUGH_MEMORY;
goto exit;
}
}
}
}
// Otherwise if finding a credential for response to challenge.
else if (dwFlags & FIND_CRED_AUTH)
{
// First search this session's credential list for a match,
// ignoring the host field in available nonces.
pCred = SearchCredList(pSessIn, NULL, szRealm, szUser, FALSE);
// If a credential was found.
if (pCred)
{
// Update the credential's nonce value if extant.
// SetNonce will update any existing nonce entry
// or create a new one if necessary.
CCred::SetNonce(_pMMFile, pCred, szHost, szNonce, SERVER_NONCE);
// BUGBUG - if credential contains a client nonce for a host,
// (for MD5-sess) and is challenged for MD5, we don't revert
// the credential's client nonce to null, so that on subsequent
// auths we will default to MD5. Fix is to delete client nonce
// in this case. Not serious problem though since we don't expect this.
if (szCNonce)
CCred::SetNonce(_pMMFile, pCred, szHost, szCNonce, CLIENT_NONCE);
// Increment this credential's nonce count.
CNonce *pNonce;
pNonce = CCred::GetNonce(pCred, szHost, SERVER_NONCE);
pNonce->cCount++;
// Create and return the found credential.
pInfo = new CCredInfo(pCred, szHost);
if (!pInfo || pInfo->dwStatus != ERROR_SUCCESS)
{
DIGEST_ASSERT(FALSE);
_dwStatus = ERROR_NOT_ENOUGH_MEMORY;
goto exit;
}
}
// If no credential was found and the username has been specified
// also search other sessions for the latest matching credential.
else if (szUser)
{
CSess* pSessCur;
_pSessList->Seek();
CCred* pMatch;
while (pSessCur = (CSess*) _pSessList->GetNext())
{
// We've already searched the session passed in.
if (pSessIn == pSessCur)
continue;
// Are this session's credentials shareable?
if (CSess::CtxMatch(pSessIn, pSessCur))
{
// Find latest credential based on time stamp.
CCred *pCredList;
pMatch = SearchCredList(pSessCur, NULL, szRealm, szUser, FALSE);
if (pMatch && ((!pCred || (pMatch->tStamp > pCred->tStamp))))
{
pCred = pMatch;
}
}
}
// If we found a credential in another session, duplicate it
// and add it to the passed in session's credential list.
// NOTE : WHEN CREATING THE CREDENTIAL DO NOT DUPLICATE
// THE NONCE, OTHERWISE NONCE COUNTS WILL BE INCORRECT.
// USE THE NONCE SUPPLIED IN THE CHALLENGE.
if (pCred)
{
// Create a cred info from the found credential
// and the nonce received from the challenge.
pInfo = new CCredInfo(szHost, CCred::GetRealm(pCred),
CCred::GetUser(pCred), CCred::GetPass(pCred),
szNonce, szCNonce);
if (!pInfo || pInfo->dwStatus != ERROR_SUCCESS)
{
DIGEST_ASSERT(FALSE);
_dwStatus = ERROR_NOT_ENOUGH_MEMORY;
goto exit;
}
// Create the credential in the session list.
pCred = CreateCred(pSessIn, pInfo);
// Increment this credential's nonce count
CNonce *pNonce;
pNonce = CCred::GetNonce(pCred, szHost, SERVER_NONCE);
pNonce->cCount++;
}
}
}
// Otherwise we are prompting for UI.
else if (dwFlags & FIND_CRED_UI)
{
// First search this session's credential list for a match,
// ignoring the host field in available nonces.
pCred = SearchCredList(pSessIn, NULL, szRealm, szUser, FALSE);
if (pCred)
{
// Create and return the found credential.
pInfo = new CCredInfo(szHost, CCred::GetRealm(pCred),
CCred::GetUser(pCred), CCred::GetPass(pCred),
szNonce, szCNonce);
if (!pInfo || pInfo->dwStatus != ERROR_SUCCESS)
{
DIGEST_ASSERT(FALSE);
_dwStatus = ERROR_NOT_ENOUGH_MEMORY;
goto exit;
}
}
else
{
// No credential found in this session's list. Search
// the credentials in other sessions and assemble a list
// of available credentials. If multiple credentials
// are found for a user, select the latest based on
// time stamp.
CSess* pSessCur;
_pSessList->Seek();
while (pSessCur = (CSess*) _pSessList->GetNext())
{
// We've already searched the session passed in.
if (pSessIn == pSessCur)
continue;
// Are this session's credentials shareable?
if (CSess::CtxMatch(pSessIn, pSessCur))
{
pCred = SearchCredList(pSessCur, NULL, szRealm, szUser, FALSE);
if (pCred)
{
// Found a valid credential.
CCredInfo *pNew;
pNew = new CCredInfo(szHost, CCred::GetRealm(pCred),
CCred::GetUser(pCred), CCred::GetPass(pCred),
szNonce, szCNonce);
if (!pNew || pNew->dwStatus != ERROR_SUCCESS)
{
DIGEST_ASSERT(FALSE);
_dwStatus = ERROR_NOT_ENOUGH_MEMORY;
goto exit;
}
// Update list based on timestamps.
pInfo = UpdateInfoList(pNew, pInfo);
}
}
}
}
}
_dwStatus = ERROR_SUCCESS;
exit:
// Clean up allocated cred infos if
// we failed for some reason.
// bugbug - clean this up.
if (_dwStatus != ERROR_SUCCESS)
{
CCredInfo *pNext;
while (pInfo)
{
pNext = pInfo->pNext;
delete pInfo;
pInfo = pNext;
}
pInfo = NULL;
}
// Relase mutex.
if(fLocked)
Unlock();
// Return any CCredInfo found, possibly a list or NULL.
return pInfo;
}
//--------------------------------------------------------------------
// CCredCache::FlushCreds
//--------------------------------------------------------------------
VOID CCredCache::FlushCreds(CSess *pSess, LPSTR szRealm)
{
CSess *pSessCur;
CCred *pCred;
CList CredList;
// Obtain mutex.
if (!Lock())
{
DIGEST_ASSERT(FALSE);
_dwStatus = GetLastError();
return;
}
// BUGBUG - don't scan through all sessions.
// BUGBUG - abstract cred deletion.
// Flush all credentials if no session specified
// or only the credentials of the indicated session.
_pSessList->Seek();
while (pSessCur = (CSess*) _pSessList->GetNext())
{
if (pSess && (pSessCur != pSess))
continue;
CredList.Init(&pSessCur->dwCred);
while (pCred = (CCred*) CredList.GetNext())
{
// If a realm is specified, only delete
// credentials with that realm.
if (!szRealm || (!strcmp(szRealm, CCred::GetRealm(pCred))))
CCred::Free(_pMMFile, pSessCur, pCred);
}
}
// Release mutex.
Unlock();
}
//--------------------------------------------------------------------
// CCredCache::GetStatus
//--------------------------------------------------------------------
DWORD CCredCache::GetStatus()
{
return _dwStatus;
}