Source code of Windows XP (NT5)
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.

969 lines
26 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. // Obtain mutex.
  509. if (!Lock())
  510. {
  511. _dwStatus = GetLastError();
  512. goto exit;
  513. }
  514. // First check to see if any credential in this session matches realm.
  515. pCred = SearchCredList(pSess, NULL, pInfo->szRealm, NULL, FALSE);
  516. if (pCred)
  517. {
  518. CredList.Init(&pSess->dwCred);
  519. CredList.DeLink(pCred);
  520. CCred::Free(_pMMFile, pSess, pCred);
  521. }
  522. // Create a credential.
  523. // BUGBUG - this could fail, transact any cred update.
  524. pCred = CCred::Create(_pMMFile, pInfo->szHost, pInfo->szRealm,
  525. pInfo->szUser, pInfo->szPass, pInfo->szNonce, pInfo->szCNonce);
  526. DIGEST_ASSERT(pCred);
  527. // Insert into head of session's credential list.
  528. if (!CSess::GetCred(pSess))
  529. CSess::SetCred(pSess, pCred);
  530. else
  531. {
  532. CredList.Init(&pSess->dwCred);
  533. CredList.Insert(pCred);
  534. }
  535. _dwStatus = ERROR_SUCCESS;
  536. // Relase mutex.
  537. Unlock();
  538. exit:
  539. return pCred;
  540. }
  541. //--------------------------------------------------------------------
  542. // CCredCache::FindCred
  543. //--------------------------------------------------------------------
  544. CCredInfo* CCredCache::FindCred(CSess *pSessIn, LPSTR szHost,
  545. LPSTR szRealm, LPSTR szUser, LPSTR szNonce,
  546. LPSTR szCNonce, DWORD dwFlags)
  547. {
  548. CCred *pCred;
  549. CCredInfo *pInfo = NULL;
  550. BOOL fLocked = FALSE;
  551. // Obtain mutex.
  552. if (!Lock())
  553. {
  554. DIGEST_ASSERT(FALSE);
  555. _dwStatus = GetLastError();
  556. goto exit;
  557. }
  558. fLocked = TRUE;
  559. // If finding a credential for preauthentication.
  560. if (dwFlags & FIND_CRED_PREAUTH)
  561. {
  562. // First search this session's credential list for a match,
  563. // filtering on the host field in available nonces.
  564. pCred = SearchCredList(pSessIn, szHost, szRealm, szUser, TRUE);
  565. // If a credential is found the nonce is also required.
  566. // We do not attempt to search other sessions for a nonce
  567. // because nonce counts must remain in sync. See note below.
  568. if (pCred)
  569. {
  570. // Increment this credential's nonce count.
  571. CNonce *pNonce;
  572. pNonce = CCred::GetNonce(pCred, szHost, SERVER_NONCE);
  573. if (pNonce)
  574. {
  575. pNonce->cCount++;
  576. pInfo = new CCredInfo(pCred, szHost);
  577. if (!pInfo || pInfo->dwStatus != ERROR_SUCCESS)
  578. {
  579. DIGEST_ASSERT(FALSE);
  580. _dwStatus = ERROR_NOT_ENOUGH_MEMORY;
  581. goto exit;
  582. }
  583. }
  584. }
  585. }
  586. // Otherwise if finding a credential for response to challenge.
  587. else if (dwFlags & FIND_CRED_AUTH)
  588. {
  589. // First search this session's credential list for a match,
  590. // ignoring the host field in available nonces.
  591. pCred = SearchCredList(pSessIn, NULL, szRealm, szUser, FALSE);
  592. // If a credential was found.
  593. if (pCred)
  594. {
  595. // Update the credential's nonce value if extant.
  596. // SetNonce will update any existing nonce entry
  597. // or create a new one if necessary.
  598. CCred::SetNonce(_pMMFile, pCred, szHost, szNonce, SERVER_NONCE);
  599. // BUGBUG - if credential contains a client nonce for a host,
  600. // (for MD5-sess) and is challenged for MD5, we don't revert
  601. // the credential's client nonce to null, so that on subsequent
  602. // auths we will default to MD5. Fix is to delete client nonce
  603. // in this case. Not serious problem though since we don't expect this.
  604. if (szCNonce)
  605. CCred::SetNonce(_pMMFile, pCred, szHost, szCNonce, CLIENT_NONCE);
  606. // Increment this credential's nonce count.
  607. CNonce *pNonce;
  608. pNonce = CCred::GetNonce(pCred, szHost, SERVER_NONCE);
  609. pNonce->cCount++;
  610. // Create and return the found credential.
  611. pInfo = new CCredInfo(pCred, szHost);
  612. if (!pInfo || pInfo->dwStatus != ERROR_SUCCESS)
  613. {
  614. DIGEST_ASSERT(FALSE);
  615. _dwStatus = ERROR_NOT_ENOUGH_MEMORY;
  616. goto exit;
  617. }
  618. }
  619. // If no credential was found and the username has been specified
  620. // also search other sessions for the latest matching credential.
  621. else if (szUser)
  622. {
  623. CSess* pSessCur;
  624. _pSessList->Seek();
  625. CCred* pMatch;
  626. while (pSessCur = (CSess*) _pSessList->GetNext())
  627. {
  628. // We've already searched the session passed in.
  629. if (pSessIn == pSessCur)
  630. continue;
  631. // Are this session's credentials shareable?
  632. if (CSess::CtxMatch(pSessIn, pSessCur))
  633. {
  634. // Find latest credential based on time stamp.
  635. CCred *pCredList;
  636. pMatch = SearchCredList(pSessCur, NULL, szRealm, szUser, FALSE);
  637. if (pMatch && ((!pCred || (pMatch->tStamp > pCred->tStamp))))
  638. {
  639. pCred = pMatch;
  640. }
  641. }
  642. }
  643. // If we found a credential in another session, duplicate it
  644. // and add it to the passed in session's credential list.
  645. // NOTE : WHEN CREATING THE CREDENTIAL DO NOT DUPLICATE
  646. // THE NONCE, OTHERWISE NONCE COUNTS WILL BE INCORRECT.
  647. // USE THE NONCE SUPPLIED IN THE CHALLENGE.
  648. if (pCred)
  649. {
  650. // Create a cred info from the found credential
  651. // and the nonce received from the challenge.
  652. pInfo = new CCredInfo(szHost, CCred::GetRealm(pCred),
  653. CCred::GetUser(pCred), CCred::GetPass(pCred),
  654. szNonce, szCNonce);
  655. if (!pInfo || pInfo->dwStatus != ERROR_SUCCESS)
  656. {
  657. DIGEST_ASSERT(FALSE);
  658. _dwStatus = ERROR_NOT_ENOUGH_MEMORY;
  659. goto exit;
  660. }
  661. // Create the credential in the session list.
  662. pCred = CreateCred(pSessIn, pInfo);
  663. // Increment this credential's nonce count
  664. CNonce *pNonce;
  665. pNonce = CCred::GetNonce(pCred, szHost, SERVER_NONCE);
  666. pNonce->cCount++;
  667. }
  668. }
  669. }
  670. // Otherwise we are prompting for UI.
  671. else if (dwFlags & FIND_CRED_UI)
  672. {
  673. // First search this session's credential list for a match,
  674. // ignoring the host field in available nonces.
  675. pCred = SearchCredList(pSessIn, NULL, szRealm, szUser, FALSE);
  676. if (pCred)
  677. {
  678. // Create and return the found credential.
  679. pInfo = new CCredInfo(szHost, CCred::GetRealm(pCred),
  680. CCred::GetUser(pCred), CCred::GetPass(pCred),
  681. szNonce, szCNonce);
  682. if (!pInfo || pInfo->dwStatus != ERROR_SUCCESS)
  683. {
  684. DIGEST_ASSERT(FALSE);
  685. _dwStatus = ERROR_NOT_ENOUGH_MEMORY;
  686. goto exit;
  687. }
  688. }
  689. else
  690. {
  691. // No credential found in this session's list. Search
  692. // the credentials in other sessions and assemble a list
  693. // of available credentials. If multiple credentials
  694. // are found for a user, select the latest based on
  695. // time stamp.
  696. CSess* pSessCur;
  697. _pSessList->Seek();
  698. while (pSessCur = (CSess*) _pSessList->GetNext())
  699. {
  700. // We've already searched the session passed in.
  701. if (pSessIn == pSessCur)
  702. continue;
  703. // Are this session's credentials shareable?
  704. if (CSess::CtxMatch(pSessIn, pSessCur))
  705. {
  706. pCred = SearchCredList(pSessCur, NULL, szRealm, szUser, FALSE);
  707. if (pCred)
  708. {
  709. // Found a valid credential.
  710. CCredInfo *pNew;
  711. pNew = new CCredInfo(szHost, CCred::GetRealm(pCred),
  712. CCred::GetUser(pCred), CCred::GetPass(pCred),
  713. szNonce, szCNonce);
  714. if (!pNew || pNew->dwStatus != ERROR_SUCCESS)
  715. {
  716. DIGEST_ASSERT(FALSE);
  717. _dwStatus = ERROR_NOT_ENOUGH_MEMORY;
  718. goto exit;
  719. }
  720. // Update list based on timestamps.
  721. pInfo = UpdateInfoList(pNew, pInfo);
  722. }
  723. }
  724. }
  725. }
  726. }
  727. _dwStatus = ERROR_SUCCESS;
  728. exit:
  729. // Clean up allocated cred infos if
  730. // we failed for some reason.
  731. // bugbug - clean this up.
  732. if (_dwStatus != ERROR_SUCCESS)
  733. {
  734. CCredInfo *pNext;
  735. while (pInfo)
  736. {
  737. pNext = pInfo->pNext;
  738. delete pInfo;
  739. pInfo = pNext;
  740. }
  741. pInfo = NULL;
  742. }
  743. // Relase mutex.
  744. if(fLocked)
  745. Unlock();
  746. // Return any CCredInfo found, possibly a list or NULL.
  747. return pInfo;
  748. }
  749. //--------------------------------------------------------------------
  750. // CCredCache::FlushCreds
  751. //--------------------------------------------------------------------
  752. VOID CCredCache::FlushCreds(CSess *pSess, LPSTR szRealm)
  753. {
  754. CSess *pSessCur;
  755. CCred *pCred;
  756. CList CredList;
  757. // Obtain mutex.
  758. if (!Lock())
  759. {
  760. DIGEST_ASSERT(FALSE);
  761. _dwStatus = GetLastError();
  762. return;
  763. }
  764. // BUGBUG - don't scan through all sessions.
  765. // BUGBUG - abstract cred deletion.
  766. // Flush all credentials if no session specified
  767. // or only the credentials of the indicated session.
  768. _pSessList->Seek();
  769. while (pSessCur = (CSess*) _pSessList->GetNext())
  770. {
  771. if (pSess && (pSessCur != pSess))
  772. continue;
  773. CredList.Init(&pSessCur->dwCred);
  774. while (pCred = (CCred*) CredList.GetNext())
  775. {
  776. // If a realm is specified, only delete
  777. // credentials with that realm.
  778. if (!szRealm || (!strcmp(szRealm, CCred::GetRealm(pCred))))
  779. CCred::Free(_pMMFile, pSessCur, pCred);
  780. }
  781. }
  782. // Release mutex.
  783. Unlock();
  784. }
  785. //--------------------------------------------------------------------
  786. // CCredCache::GetStatus
  787. //--------------------------------------------------------------------
  788. DWORD CCredCache::GetStatus()
  789. {
  790. return _dwStatus;
  791. }
  792.