Leaked source code of windows server 2003
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.

1003 lines
28 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. cache.cxx
  5. Abstract:
  6. Credential cache object for digest sspi package.
  7. Author:
  8. Adriaan Canter (adriaanc) 01-Aug-1998
  9. --*/
  10. #include "include.hxx"
  11. //-----------------CCredCache Private Functions --------------------------------
  12. //--------------------------------------------------------------------
  13. // CCredCache::Lock
  14. //--------------------------------------------------------------------
  15. BOOL CCredCache::Lock()
  16. {
  17. BOOL bRet;
  18. DWORD dwError;
  19. dwError = WaitForSingleObject(_hMutex, INFINITE);
  20. switch (dwError)
  21. {
  22. // Mutex is signalled. We own the mutex. Fall through.
  23. case WAIT_OBJECT_0:
  24. // The thread owning the mutex failed to release it
  25. // before terminating. We still own the mutex.
  26. case WAIT_ABANDONED:
  27. bRet = TRUE;
  28. break;
  29. // Fall through.
  30. case WAIT_FAILED:
  31. // Fail.
  32. default:
  33. bRet = FALSE;
  34. }
  35. return bRet;
  36. }
  37. //--------------------------------------------------------------------
  38. // CCredCache::Unlock
  39. //--------------------------------------------------------------------
  40. BOOL CCredCache::Unlock()
  41. {
  42. BOOL bRet;
  43. bRet = ReleaseMutex(_hMutex);
  44. return bRet;
  45. }
  46. //--------------------------------------------------------------------
  47. // CCredCache::GetPtrToObject
  48. //--------------------------------------------------------------------
  49. LPDWORD CCredCache::GetPtrToObject(DWORD dwObject)
  50. {
  51. return _pMMFile->GetHeaderData(dwObject);
  52. }
  53. //--------------------------------------------------------------------
  54. // CCredCache::SearchCredList
  55. //--------------------------------------------------------------------
  56. CCred* CCredCache::SearchCredList(CSess *pSess, LPSTR szHost,
  57. LPSTR szRealm, LPSTR szUser, BOOL fMatchHost)
  58. {
  59. CList CredList;
  60. CCred *pMatch = NULL;
  61. if (!pSess->dwCred)
  62. goto exit;
  63. CredList.Init(&pSess->dwCred);
  64. while (pMatch = (CCred*) CredList.GetNext())
  65. {
  66. if ((!szRealm || !lstrcmpi(szRealm, CCred::GetRealm(pMatch)))
  67. && (!szUser || !lstrcmpi(szUser, CCred::GetUser(pMatch))))
  68. {
  69. if (!fMatchHost)
  70. break;
  71. CNonce *pNonce;
  72. CList NonceList;
  73. NonceList.Init(&pMatch->dwNonce);
  74. while (pNonce = (CNonce*) NonceList.GetNext())
  75. {
  76. if (CNonce::IsHostMatch(pNonce, szHost))
  77. goto exit;
  78. }
  79. pMatch = NULL;
  80. break;
  81. }
  82. }
  83. exit:
  84. return pMatch;
  85. }
  86. //--------------------------------------------------------------------
  87. // CCredCache::UpdateInfoList
  88. //--------------------------------------------------------------------
  89. CCredInfo* CCredCache::UpdateInfoList(CCredInfo *pInfo, CCredInfo *pHead)
  90. {
  91. CCredInfo *pList, *pCur;
  92. BOOL fUpdate = TRUE;
  93. if (!pHead)
  94. return (pInfo);
  95. pList = pCur = pHead;
  96. while (pCur)
  97. {
  98. // Do entry usernames match ?
  99. if (!strcmp(pInfo->szUser, pCur->szUser))
  100. {
  101. // Is the new entry timestamp greater?
  102. if (pInfo->tStamp > pCur->tStamp)
  103. {
  104. // De-link existing entry.
  105. if (pCur->pPrev)
  106. pCur->pPrev->pNext = pCur->pNext;
  107. else
  108. pList = pCur->pNext;
  109. if (pCur->pNext)
  110. pCur->pNext->pPrev = pCur->pPrev;
  111. // Delete existing entry.
  112. delete pCur;
  113. }
  114. else
  115. {
  116. // Found a match but time stamp
  117. // of existing entry was greater.
  118. fUpdate = FALSE;
  119. }
  120. break;
  121. }
  122. pCur = pCur->pNext;
  123. }
  124. // If we superceded an existing matching entry
  125. // or found no matching entries, prepend to list.
  126. if (fUpdate)
  127. {
  128. pInfo->pNext = pList;
  129. if (pList)
  130. pList->pPrev = pInfo;
  131. pList = pInfo;
  132. }
  133. return pList;
  134. }
  135. //-----------------CCredCache Public Functions --------------------------------
  136. //--------------------------------------------------------------------
  137. // CCredCache::GetHeapPtr
  138. //--------------------------------------------------------------------
  139. DWORD_PTR CCredCache::GetHeapPtr()
  140. {
  141. return _pMMFile->GetMapPtr();
  142. }
  143. //--------------------------------------------------------------------
  144. // CCredCache::IsTrustedHost
  145. // BUGBUG - no limits on szCtx
  146. //--------------------------------------------------------------------
  147. BOOL CCredCache::IsTrustedHost(LPSTR szCtx, LPSTR szHost)
  148. {
  149. CHAR szBuf[MAX_PATH];
  150. CHAR szRegPath[MAX_PATH];
  151. DWORD dwType, dwError, cbBuf = MAX_PATH;
  152. BOOL fRet = FALSE;
  153. HKEY hHosts = (HKEY) INVALID_HANDLE_VALUE;
  154. memcpy(szRegPath, DIGEST_HOSTS_REG_KEY, sizeof(DIGEST_HOSTS_REG_KEY) - 1);
  155. memcpy(szRegPath + sizeof(DIGEST_HOSTS_REG_KEY) - 1, szCtx, strlen(szCtx) + 1);
  156. if ((dwError = RegCreateKey(HKEY_CURRENT_USER, szRegPath, &hHosts)) == ERROR_SUCCESS)
  157. {
  158. if ((dwError = RegQueryValueEx(hHosts, szHost, NULL, &dwType, (LPBYTE) szBuf, &cbBuf)) == ERROR_SUCCESS)
  159. {
  160. fRet = TRUE;
  161. }
  162. }
  163. if (hHosts != INVALID_HANDLE_VALUE)
  164. RegCloseKey(hHosts);
  165. return fRet;
  166. }
  167. //--------------------------------------------------------------------
  168. // CCredCache::SetTrustedHostInfo
  169. //--------------------------------------------------------------------
  170. BOOL CCredCache::SetTrustedHostInfo(LPSTR szCtx, CParams *pParams)
  171. {
  172. CHAR szRegPath[MAX_PATH], *szUrlBuf = NULL, *szHostBuf = NULL;
  173. DWORD dwZero = 0, dwError = ERROR_SUCCESS, cbUrlBuf, cbHostBuf;
  174. BOOL fRet = FALSE;
  175. HKEY hHosts = (HKEY) INVALID_HANDLE_VALUE;
  176. // Form path to trusted host reg key.
  177. memcpy(szRegPath, DIGEST_HOSTS_REG_KEY, sizeof(DIGEST_HOSTS_REG_KEY) - 1);
  178. memcpy(szRegPath + sizeof(DIGEST_HOSTS_REG_KEY) - 1, szCtx, strlen(szCtx) + 1);
  179. // Open top-level reg key.
  180. if ((dwError = RegCreateKey(HKEY_CURRENT_USER, szRegPath, &hHosts)) != ERROR_SUCCESS)
  181. goto exit;
  182. // First set authenticating host in registry.
  183. LPSTR szHost;
  184. szHost = pParams->GetParam(CParams::HOST);
  185. DIGEST_ASSERT(szHost);
  186. if ((dwError = RegSetValueEx(hHosts, szHost, NULL, REG_DWORD,
  187. (LPBYTE) &dwZero, sizeof(DWORD))) != ERROR_SUCCESS)
  188. goto exit;
  189. // Now check the domain header for any additional trusted hosts.
  190. LPSTR szDomain, pszUrl;
  191. DWORD cbDomain, cbUrl;
  192. pszUrl = NULL;
  193. pParams->GetParam(CParams::DOMAIN, &szDomain, &cbDomain);
  194. if (!szDomain)
  195. {
  196. fRet = TRUE;
  197. goto exit;
  198. }
  199. // Parse the domain header for urls. Crack each url to get the
  200. // host and set the host value in the registry.
  201. // First attempt to load shlwapi. If this fails then we simply do not have
  202. // domain header support.
  203. if (!g_hShlwapi)
  204. {
  205. g_hShlwapi = LoadLibrary(SHLWAPI_DLL_SZ);
  206. if (!g_hShlwapi)
  207. {
  208. dwError = ERROR_DLL_INIT_FAILED;
  209. goto exit;
  210. }
  211. }
  212. // Attempt to get addresses of UrlUnescape and UrlGetPart
  213. PFNURLUNESCAPE pfnUrlUnescape;
  214. PFNURLGETPART pfnUrlGetPart;
  215. pfnUrlUnescape = (PFNURLUNESCAPE) GetProcAddress(g_hShlwapi, "UrlUnescapeA");
  216. pfnUrlGetPart = (PFNURLGETPART) GetProcAddress(g_hShlwapi, "UrlGetPartA");
  217. if (!(pfnUrlUnescape && pfnUrlGetPart))
  218. {
  219. dwError = ERROR_INVALID_FUNCTION;
  220. goto exit;
  221. }
  222. // Strtok through string to get each url (ws and tab delimiters)
  223. pszUrl = NULL;
  224. while (pszUrl = strtok((pszUrl ? NULL : szDomain), " \t"))
  225. {
  226. // Allocate a buffer for the url since we will first unescape it.
  227. // Also allocate buffer for host which will be returned from
  228. // call to shlwapi. Unescaped url and host buffer sizes are
  229. // bounded by length of original url.
  230. cbUrl = strlen(pszUrl) + 1;
  231. cbUrlBuf = cbHostBuf = cbUrl;
  232. szUrlBuf = new CHAR[cbUrlBuf];
  233. szHostBuf = new CHAR[cbHostBuf];
  234. if (!(szUrlBuf && szHostBuf))
  235. {
  236. dwError = ERROR_NOT_ENOUGH_MEMORY;
  237. goto exit;
  238. }
  239. // Copy strtoked url to buffer.
  240. memcpy(szUrlBuf, pszUrl, cbUrl);
  241. // Unescape the url
  242. if (S_OK == pfnUrlUnescape(szUrlBuf, NULL, NULL, URL_UNESCAPE_INPLACE))
  243. {
  244. // If unescape is successful, parse host from url.
  245. if (S_OK == pfnUrlGetPart(szUrlBuf, szHostBuf, &cbHostBuf, URL_PART_HOSTNAME, 0))
  246. {
  247. // If parse is successful, set host in registry.
  248. if ((dwError = RegSetValueEx(hHosts, szHostBuf, NULL, REG_DWORD,
  249. (LPBYTE) &dwZero, sizeof(DWORD))) != ERROR_SUCCESS)
  250. goto exit;
  251. }
  252. }
  253. delete [] szUrlBuf;
  254. delete [] szHostBuf;
  255. szUrlBuf = szHostBuf = NULL;
  256. }
  257. fRet = TRUE;
  258. // Cleanup.
  259. exit:
  260. DIGEST_ASSERT(dwError == ERROR_SUCCESS);
  261. if (hHosts != INVALID_HANDLE_VALUE)
  262. RegCloseKey(hHosts);
  263. if (szUrlBuf)
  264. delete [] szUrlBuf;
  265. if (szHostBuf)
  266. delete [] szHostBuf;
  267. return fRet;
  268. }
  269. //--------------------------------------------------------------------
  270. // CCredCache::MapHandleToSession
  271. //--------------------------------------------------------------------
  272. // BUGBUG - don't walk the sessionlist, just obfuscate the ptr in handle.
  273. CSess *CCredCache::MapHandleToSession(DWORD_PTR dwSess)
  274. {
  275. // BUGBUG - if locking fails, return error directly,
  276. // no last error.
  277. CSess *pSess = NULL;
  278. if (!Lock())
  279. {
  280. DIGEST_ASSERT(FALSE);
  281. _dwStatus = GetLastError();
  282. goto exit;
  283. }
  284. _pSessList->Seek();
  285. while (pSess = (CSess*) _pSessList->GetNext())
  286. {
  287. if ((CSess*) (dwSess + (DWORD_PTR) _pMMFile->GetMapPtr()) == pSess)
  288. break;
  289. }
  290. Unlock();
  291. exit:
  292. return pSess;
  293. }
  294. //--------------------------------------------------------------------
  295. // CCredCache::MapSessionToHandle
  296. //--------------------------------------------------------------------
  297. DWORD CCredCache::MapSessionToHandle(CSess* pSess)
  298. {
  299. DWORD dwSess = 0;
  300. if (!Lock())
  301. {
  302. DIGEST_ASSERT(FALSE);
  303. _dwStatus = GetLastError();
  304. goto exit;
  305. }
  306. dwSess = (DWORD) ((DWORD_PTR) pSess - _pMMFile->GetMapPtr());
  307. Unlock();
  308. exit:
  309. return dwSess;
  310. }
  311. // BUGBUG - init mutex issues.
  312. //--------------------------------------------------------------------
  313. // CCredCache::CCredCache
  314. //--------------------------------------------------------------------
  315. CCredCache::CCredCache()
  316. {
  317. Init();
  318. }
  319. //--------------------------------------------------------------------
  320. // CCredCache::~CCredCache
  321. //--------------------------------------------------------------------
  322. CCredCache::~CCredCache()
  323. {
  324. DeInit();
  325. }
  326. //--------------------------------------------------------------------
  327. // CCredCache::Init
  328. //--------------------------------------------------------------------
  329. DWORD CCredCache::Init()
  330. {
  331. BOOL fFirstProc;
  332. CHAR szMutexName[MAX_PATH];
  333. DWORD cbMutexName = MAX_PATH;
  334. _dwSig = SIG_CACH;
  335. // IE5# 89288
  336. // Get mutex name based on user
  337. if ((_dwStatus = CMMFile::MakeUserObjectName(szMutexName,
  338. &cbMutexName, MAKE_MUTEX_NAME)) != ERROR_SUCCESS)
  339. return _dwStatus;
  340. // Create/Open mutex.
  341. _hMutex = CreateMutex(NULL, FALSE, szMutexName);
  342. // BUGBUG - this goes at a higher level.
  343. // BUGBUG - also watch out for failure to create mutex
  344. // and then unlocking it.
  345. if (_hMutex)
  346. {
  347. // Created/opened mutex. Flag if we're first process.
  348. fFirstProc = (GetLastError() != ERROR_ALREADY_EXISTS);
  349. }
  350. else
  351. {
  352. // Failed to create/open mutex.
  353. DIGEST_ASSERT(FALSE);
  354. _dwStatus = GetLastError();
  355. goto exit;
  356. }
  357. // Acquire mutex.
  358. if (!Lock())
  359. {
  360. DIGEST_ASSERT(FALSE);
  361. _dwStatus = GetLastError();
  362. return _dwStatus;
  363. }
  364. // Open or create memory map.
  365. _pMMFile = new CMMFile(CRED_CACHE_HEAP_SIZE,
  366. CRED_CACHE_ENTRY_SIZE);
  367. if (!_pMMFile)
  368. {
  369. DIGEST_ASSERT(FALSE);
  370. _dwStatus = ERROR_NOT_ENOUGH_MEMORY;
  371. goto exit;
  372. }
  373. _dwStatus = _pMMFile->Init();
  374. if (_dwStatus != ERROR_SUCCESS)
  375. {
  376. DIGEST_ASSERT(FALSE);
  377. goto exit;
  378. }
  379. g_pHeap = GetHeapPtr();
  380. // Initialize session list.
  381. // BUGBUG - check return codes on failure.
  382. _pSessList = new CList();
  383. DIGEST_ASSERT(_pSessList);
  384. _pSessList->Init(GetPtrToObject(CRED_CACHE_SESSION_LIST));
  385. exit:
  386. // Relase mutex.
  387. Unlock();
  388. return _dwStatus;
  389. }
  390. //--------------------------------------------------------------------
  391. // CCredCache::DeInit
  392. //--------------------------------------------------------------------
  393. DWORD CCredCache::DeInit()
  394. {
  395. // bugbug - assert session list is null and destroy.
  396. // bugbug - release lock before closing handle.
  397. if (!Lock())
  398. {
  399. DIGEST_ASSERT(FALSE);
  400. _dwStatus = GetLastError();
  401. goto exit;
  402. }
  403. delete _pMMFile;
  404. _dwStatus = CloseHandle(_hMutex);
  405. Unlock();
  406. exit:
  407. return _dwStatus;
  408. }
  409. //--------------------------------------------------------------------
  410. // CCredCache::LogOnToCache
  411. //--------------------------------------------------------------------
  412. CSess *CCredCache::LogOnToCache(LPSTR szAppCtx, LPSTR szUserCtx, BOOL fHTTP)
  413. {
  414. CSess *pSessNew = NULL;
  415. BOOL fLocked = FALSE;
  416. // Obtain mutex.
  417. if (!Lock())
  418. {
  419. DIGEST_ASSERT(FALSE);
  420. _dwStatus = GetLastError();
  421. goto exit;
  422. }
  423. fLocked = TRUE;
  424. // For non-http clients, find or create the single
  425. // global session which all non-http clients use.
  426. if (!fHTTP)
  427. {
  428. CSess * pSess;
  429. pSess = NULL;
  430. _pSessList->Seek();
  431. while (pSess = (CSess*) _pSessList->GetNext())
  432. {
  433. if (!pSess->fHTTP)
  434. {
  435. // Found the session.
  436. pSessNew = pSess;
  437. _dwStatus = ERROR_SUCCESS;
  438. goto exit;
  439. }
  440. }
  441. if (!pSessNew)
  442. {
  443. // Create the non-http gobal session.
  444. pSessNew = CSess::Create(_pMMFile, NULL, NULL, FALSE);
  445. }
  446. }
  447. else
  448. {
  449. // Create a session context; add to list.
  450. pSessNew = CSess::Create(_pMMFile, szAppCtx, szUserCtx, TRUE);
  451. }
  452. if (!pSessNew)
  453. {
  454. // This reflects running out of space in the memmap
  455. // file. Shouldn't happen in practice.
  456. DIGEST_ASSERT(FALSE);
  457. _dwStatus = ERROR_NOT_ENOUGH_MEMORY;
  458. goto exit;
  459. }
  460. // Push this session on to the session list.
  461. _pSessList->Insert(pSessNew);
  462. _dwStatus = ERROR_SUCCESS;
  463. exit:
  464. // Release mutex.
  465. if(fLocked)
  466. Unlock();
  467. return pSessNew;
  468. }
  469. //--------------------------------------------------------------------
  470. // CCredCache::LogOffFromCache
  471. //--------------------------------------------------------------------
  472. DWORD CCredCache::LogOffFromCache(CSess *pSess)
  473. {
  474. CList CredList;
  475. CCred *pCred;
  476. // Obtain mutex.
  477. if (!Lock())
  478. {
  479. DIGEST_ASSERT(FALSE);
  480. _dwStatus = GetLastError();
  481. goto exit;
  482. }
  483. if (pSess->fHTTP)
  484. {
  485. // Purge all credentials for this session.
  486. // BUGBUG - not needed.
  487. // CredList.Init((CEntry **) &pSess->pCred);
  488. // Flush all credentials for this session
  489. // This will also delete nonces.
  490. FlushCreds(pSess, NULL);
  491. // Finally, free the session.
  492. _pSessList->DeLink(pSess);
  493. CEntry::Free(_pMMFile, pSess);
  494. }
  495. _dwStatus = ERROR_SUCCESS;
  496. // Release mutex.
  497. Unlock();
  498. exit:
  499. return _dwStatus;
  500. }
  501. //--------------------------------------------------------------------
  502. // CCredCache::CreateCred
  503. //--------------------------------------------------------------------
  504. CCred* CCredCache::CreateCred(CSess *pSess, CCredInfo *pInfo)
  505. {
  506. CCred* pCred = NULL, *pCredList;
  507. CList CredList;
  508. LPSTR szPass = NULL;
  509. // Obtain mutex.
  510. if (!Lock())
  511. {
  512. _dwStatus = GetLastError();
  513. goto exit;
  514. }
  515. // First check to see if any credential in this session matches realm.
  516. pCred = SearchCredList(pSess, NULL, pInfo->szRealm, NULL, FALSE);
  517. if (pCred)
  518. {
  519. CredList.Init(&pSess->dwCred);
  520. CredList.DeLink(pCred);
  521. CCred::Free(_pMMFile, pSess, pCred);
  522. }
  523. // Create a credential.
  524. // BUGBUG - this could fail, transact any cred update.
  525. pCred = CCred::Create(_pMMFile, pInfo->szHost, pInfo->szRealm,
  526. pInfo->szUser, (szPass = pInfo->GetPass()),
  527. pInfo->szNonce, pInfo->szCNonce);
  528. DIGEST_ASSERT(pCred);
  529. // Insert into head of session's credential list.
  530. if (!CSess::GetCred(pSess))
  531. CSess::SetCred(pSess, pCred);
  532. else
  533. {
  534. CredList.Init(&pSess->dwCred);
  535. CredList.Insert(pCred);
  536. }
  537. _dwStatus = ERROR_SUCCESS;
  538. // Relase mutex.
  539. Unlock();
  540. exit:
  541. if (szPass)
  542. {
  543. SecureZeroMemory(szPass, strlen(szPass));
  544. delete [] szPass;
  545. }
  546. return pCred;
  547. }
  548. //--------------------------------------------------------------------
  549. // CCredCache::FindCred
  550. //--------------------------------------------------------------------
  551. CCredInfo* CCredCache::FindCred(CSess *pSessIn, LPSTR szHost,
  552. LPSTR szRealm, LPSTR szUser, LPSTR szNonce,
  553. LPSTR szCNonce, DWORD dwFlags)
  554. {
  555. CCred *pCred;
  556. CCredInfo *pInfo = NULL;
  557. BOOL fLocked = FALSE;
  558. // Obtain mutex.
  559. if (!Lock())
  560. {
  561. DIGEST_ASSERT(FALSE);
  562. _dwStatus = GetLastError();
  563. goto exit;
  564. }
  565. fLocked = TRUE;
  566. // If finding a credential for preauthentication.
  567. if (dwFlags & FIND_CRED_PREAUTH)
  568. {
  569. // First search this session's credential list for a match,
  570. // filtering on the host field in available nonces.
  571. pCred = SearchCredList(pSessIn, szHost, szRealm, szUser, TRUE);
  572. // If a credential is found the nonce is also required.
  573. // We do not attempt to search other sessions for a nonce
  574. // because nonce counts must remain in sync. See note below.
  575. if (pCred)
  576. {
  577. // Increment this credential's nonce count.
  578. CNonce *pNonce;
  579. pNonce = CCred::GetNonce(pCred, szHost, SERVER_NONCE);
  580. if (pNonce)
  581. {
  582. pNonce->cCount++;
  583. pInfo = new CCredInfo(pCred, szHost);
  584. if (!pInfo || pInfo->dwStatus != ERROR_SUCCESS)
  585. {
  586. DIGEST_ASSERT(FALSE);
  587. _dwStatus = ERROR_NOT_ENOUGH_MEMORY;
  588. goto exit;
  589. }
  590. }
  591. }
  592. }
  593. // Otherwise if finding a credential for response to challenge.
  594. else if (dwFlags & FIND_CRED_AUTH)
  595. {
  596. // First search this session's credential list for a match,
  597. // ignoring the host field in available nonces.
  598. pCred = SearchCredList(pSessIn, NULL, szRealm, szUser, FALSE);
  599. // If a credential was found.
  600. if (pCred)
  601. {
  602. // Update the credential's nonce value if extant.
  603. // SetNonce will update any existing nonce entry
  604. // or create a new one if necessary.
  605. CCred::SetNonce(_pMMFile, pCred, szHost, szNonce, SERVER_NONCE);
  606. // BUGBUG - if credential contains a client nonce for a host,
  607. // (for MD5-sess) and is challenged for MD5, we don't revert
  608. // the credential's client nonce to null, so that on subsequent
  609. // auths we will default to MD5. Fix is to delete client nonce
  610. // in this case. Not serious problem though since we don't expect this.
  611. if (szCNonce)
  612. CCred::SetNonce(_pMMFile, pCred, szHost, szCNonce, CLIENT_NONCE);
  613. // Increment this credential's nonce count.
  614. CNonce *pNonce;
  615. pNonce = CCred::GetNonce(pCred, szHost, SERVER_NONCE);
  616. pNonce->cCount++;
  617. // Create and return the found credential.
  618. pInfo = new CCredInfo(pCred, szHost);
  619. if (!pInfo || pInfo->dwStatus != ERROR_SUCCESS)
  620. {
  621. DIGEST_ASSERT(FALSE);
  622. _dwStatus = ERROR_NOT_ENOUGH_MEMORY;
  623. goto exit;
  624. }
  625. }
  626. // If no credential was found and the username has been specified
  627. // also search other sessions for the latest matching credential.
  628. else if (szUser)
  629. {
  630. CSess* pSessCur;
  631. _pSessList->Seek();
  632. CCred* pMatch;
  633. while (pSessCur = (CSess*) _pSessList->GetNext())
  634. {
  635. // We've already searched the session passed in.
  636. if (pSessIn == pSessCur)
  637. continue;
  638. // Are this session's credentials shareable?
  639. if (CSess::CtxMatch(pSessIn, pSessCur))
  640. {
  641. // Find latest credential based on time stamp.
  642. CCred *pCredList;
  643. pMatch = SearchCredList(pSessCur, NULL, szRealm, szUser, FALSE);
  644. if (pMatch && ((!pCred || (pMatch->tStamp > pCred->tStamp))))
  645. {
  646. pCred = pMatch;
  647. }
  648. }
  649. }
  650. // If we found a credential in another session, duplicate it
  651. // and add it to the passed in session's credential list.
  652. // NOTE : WHEN CREATING THE CREDENTIAL DO NOT DUPLICATE
  653. // THE NONCE, OTHERWISE NONCE COUNTS WILL BE INCORRECT.
  654. // USE THE NONCE SUPPLIED IN THE CHALLENGE.
  655. if (pCred)
  656. {
  657. LPSTR szPass = NULL;
  658. // Create a cred info from the found credential
  659. // and the nonce received from the challenge.
  660. pInfo = new CCredInfo(szHost, CCred::GetRealm(pCred),
  661. CCred::GetUser(pCred), (szPass = CCred::GetPass(pCred)),
  662. szNonce, szCNonce);
  663. if (szPass)
  664. {
  665. SecureZeroMemory(szPass, strlen(szPass));
  666. delete [] szPass;
  667. szPass = NULL;
  668. }
  669. if (!pInfo || pInfo->dwStatus != ERROR_SUCCESS)
  670. {
  671. DIGEST_ASSERT(FALSE);
  672. _dwStatus = ERROR_NOT_ENOUGH_MEMORY;
  673. goto exit;
  674. }
  675. // Create the credential in the session list.
  676. pCred = CreateCred(pSessIn, pInfo);
  677. // Increment this credential's nonce count
  678. CNonce *pNonce;
  679. pNonce = CCred::GetNonce(pCred, szHost, SERVER_NONCE);
  680. pNonce->cCount++;
  681. }
  682. }
  683. }
  684. // Otherwise we are prompting for UI.
  685. else if (dwFlags & FIND_CRED_UI)
  686. {
  687. // First search this session's credential list for a match,
  688. // ignoring the host field in available nonces.
  689. pCred = SearchCredList(pSessIn, NULL, szRealm, szUser, FALSE);
  690. if (pCred)
  691. {
  692. LPSTR szPass = NULL;
  693. // Create and return the found credential.
  694. pInfo = new CCredInfo(szHost, CCred::GetRealm(pCred),
  695. CCred::GetUser(pCred), (szPass = CCred::GetPass(pCred)),
  696. szNonce, szCNonce);
  697. if (szPass)
  698. {
  699. SecureZeroMemory(szPass, strlen(szPass));
  700. delete [] szPass;
  701. szPass = NULL;
  702. }
  703. if (!pInfo || pInfo->dwStatus != ERROR_SUCCESS)
  704. {
  705. DIGEST_ASSERT(FALSE);
  706. _dwStatus = ERROR_NOT_ENOUGH_MEMORY;
  707. goto exit;
  708. }
  709. }
  710. else
  711. {
  712. // No credential found in this session's list. Search
  713. // the credentials in other sessions and assemble a list
  714. // of available credentials. If multiple credentials
  715. // are found for a user, select the latest based on
  716. // time stamp.
  717. CSess* pSessCur;
  718. _pSessList->Seek();
  719. while (pSessCur = (CSess*) _pSessList->GetNext())
  720. {
  721. // We've already searched the session passed in.
  722. if (pSessIn == pSessCur)
  723. continue;
  724. // Are this session's credentials shareable?
  725. if (CSess::CtxMatch(pSessIn, pSessCur))
  726. {
  727. pCred = SearchCredList(pSessCur, NULL, szRealm, szUser, FALSE);
  728. if (pCred)
  729. {
  730. LPSTR szPass = NULL;
  731. // Found a valid credential.
  732. CCredInfo *pNew;
  733. pNew = new CCredInfo(szHost, CCred::GetRealm(pCred),
  734. CCred::GetUser(pCred), (szPass = CCred::GetPass(pCred)),
  735. szNonce, szCNonce);
  736. if (szPass)
  737. {
  738. SecureZeroMemory(szPass, strlen(szPass));
  739. delete [] szPass;
  740. szPass = NULL;
  741. }
  742. if (!pNew || pNew->dwStatus != ERROR_SUCCESS)
  743. {
  744. DIGEST_ASSERT(FALSE);
  745. _dwStatus = ERROR_NOT_ENOUGH_MEMORY;
  746. goto exit;
  747. }
  748. // Update list based on timestamps.
  749. pInfo = UpdateInfoList(pNew, pInfo);
  750. }
  751. }
  752. }
  753. }
  754. }
  755. _dwStatus = ERROR_SUCCESS;
  756. exit:
  757. // Clean up allocated cred infos if
  758. // we failed for some reason.
  759. // bugbug - clean this up.
  760. if (_dwStatus != ERROR_SUCCESS)
  761. {
  762. CCredInfo *pNext;
  763. while (pInfo)
  764. {
  765. pNext = pInfo->pNext;
  766. delete pInfo;
  767. pInfo = pNext;
  768. }
  769. pInfo = NULL;
  770. }
  771. // Relase mutex.
  772. if(fLocked)
  773. Unlock();
  774. // Return any CCredInfo found, possibly a list or NULL.
  775. return pInfo;
  776. }
  777. //--------------------------------------------------------------------
  778. // CCredCache::FlushCreds
  779. //--------------------------------------------------------------------
  780. VOID CCredCache::FlushCreds(CSess *pSess, LPSTR szRealm)
  781. {
  782. CSess *pSessCur;
  783. CCred *pCred;
  784. CList CredList;
  785. // Obtain mutex.
  786. if (!Lock())
  787. {
  788. DIGEST_ASSERT(FALSE);
  789. _dwStatus = GetLastError();
  790. return;
  791. }
  792. // BUGBUG - don't scan through all sessions.
  793. // BUGBUG - abstract cred deletion.
  794. // Flush all credentials if no session specified
  795. // or only the credentials of the indicated session.
  796. _pSessList->Seek();
  797. while (pSessCur = (CSess*) _pSessList->GetNext())
  798. {
  799. if (pSess && (pSessCur != pSess))
  800. continue;
  801. CredList.Init(&pSessCur->dwCred);
  802. while (pCred = (CCred*) CredList.GetNext())
  803. {
  804. // If a realm is specified, only delete
  805. // credentials with that realm.
  806. if (!szRealm || (!strcmp(szRealm, CCred::GetRealm(pCred))))
  807. CCred::Free(_pMMFile, pSessCur, pCred);
  808. }
  809. }
  810. // Release mutex.
  811. Unlock();
  812. }
  813. //--------------------------------------------------------------------
  814. // CCredCache::GetStatus
  815. //--------------------------------------------------------------------
  816. DWORD CCredCache::GetStatus()
  817. {
  818. return _dwStatus;
  819. }