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.

1018 lines
27 KiB

  1. #include "private.h"
  2. #include "multiutl.h"
  3. #include <wtypes.h>
  4. #include "strconst.h"
  5. #include <platform.h>
  6. extern HINSTANCE g_hInst;
  7. // Pstore related variables.
  8. static PST_KEY s_Key = PST_KEY_CURRENT_USER;
  9. // {89C39569-6841-11d2-9F59-0000F8085266}
  10. static const GUID GUID_PStoreType = { 0x89c39569, 0x6841, 0x11d2, { 0x9f, 0x59, 0x0, 0x0, 0xf8, 0x8, 0x52, 0x66 } };
  11. static WCHAR c_szIdentityMgr[] = L"IdentityMgr";
  12. static WCHAR c_szIdentities[] = L"Identities";
  13. static WCHAR c_szIdentityPass[] = L"IdentitiesPass";
  14. //Need these private implementations
  15. //OE has dependency on the particular allocator used
  16. void * __cdecl operator new(size_t nSize)
  17. {
  18. // Zero init just to save some headaches
  19. return CoTaskMemAlloc(nSize);
  20. }
  21. void __cdecl operator delete(void *pv)
  22. {
  23. //If changed to GlobalFree or HeapFree - must check for NULL here
  24. CoTaskMemFree(pv);
  25. }
  26. extern "C" int __cdecl _purecall(void)
  27. {
  28. DebugBreak();
  29. return 0;
  30. }
  31. // --------------------------------------------------------------------------
  32. // FIsSpaceA
  33. // --------------------------------------------------------------------------
  34. BOOL FIsSpaceA(LPSTR psz)
  35. {
  36. #ifdef MAC
  37. return (isspace(*psz));
  38. #else // !MAC
  39. WORD wType;
  40. if (IsDBCSLeadByte(*psz))
  41. GetStringTypeExA(LOCALE_USER_DEFAULT, CT_CTYPE1, psz, 2, &wType);
  42. else
  43. GetStringTypeExA(LOCALE_USER_DEFAULT, CT_CTYPE1, psz, 1, &wType);
  44. return (wType & C1_SPACE);
  45. #endif // MAC
  46. }
  47. // --------------------------------------------------------------------------
  48. // FIsSpaceW
  49. // --------------------------------------------------------------------------
  50. BOOL FIsSpaceW(LPWSTR psz)
  51. {
  52. #ifdef MAC
  53. // Maybe we should convert to ANSI before checking??
  54. return (isspace(*( ( (TCHAR *) psz ) + 1 ) ));
  55. #else // !MAC
  56. WORD wType;
  57. GetStringTypeExW(LOCALE_USER_DEFAULT, CT_CTYPE1, psz, 1, &wType);
  58. return (wType & C1_SPACE);
  59. #endif // !MAC
  60. }
  61. ULONG UlStripWhitespace(LPTSTR lpsz, BOOL fLeading, BOOL fTrailing, ULONG *pcb)
  62. {
  63. // Locals
  64. ULONG cb;
  65. LPTSTR psz;
  66. Assert(lpsz != NULL);
  67. Assert(fLeading || fTrailing);
  68. // Did the user pass in the length
  69. if (pcb)
  70. cb = *pcb;
  71. else
  72. cb = lstrlen (lpsz);
  73. if (cb == 0)
  74. return cb;
  75. if (fLeading)
  76. {
  77. psz = lpsz;
  78. while (FIsSpace(psz))
  79. {
  80. psz++;
  81. cb--;
  82. }
  83. if (psz != lpsz)
  84. // get the NULL at the end too
  85. MoveMemory(lpsz, psz, (cb + 1) * sizeof(TCHAR));
  86. }
  87. if (fTrailing)
  88. {
  89. psz = lpsz + cb;
  90. while (cb > 0)
  91. {
  92. if (!FIsSpace(psz-1))
  93. break;
  94. psz--;
  95. cb--;
  96. }
  97. // NULL Term
  98. *psz = '\0';
  99. }
  100. // Set String Size
  101. if (pcb)
  102. *pcb = cb;
  103. // Done
  104. return cb;
  105. }
  106. BOOL OnContextHelp(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, HELPMAP const * rgCtxMap)
  107. {
  108. if (uMsg == WM_HELP)
  109. {
  110. LPHELPINFO lphi = (LPHELPINFO) lParam;
  111. if (lphi->iContextType == HELPINFO_WINDOW) // must be for a control
  112. {
  113. WinHelp ((HWND)lphi->hItemHandle,
  114. c_szCtxHelpFile,
  115. HELP_WM_HELP,
  116. (DWORD_PTR)(void*)rgCtxMap);
  117. }
  118. return (TRUE);
  119. }
  120. else if (uMsg == WM_CONTEXTMENU)
  121. {
  122. WinHelp ((HWND) wParam,
  123. c_szCtxHelpFile,
  124. HELP_CONTEXTMENU,
  125. (DWORD_PTR)(void*)rgCtxMap);
  126. return (TRUE);
  127. }
  128. Assert(0);
  129. return FALSE;
  130. }
  131. #define OBFUSCATOR 0x14151875;
  132. #define PROT_SIZEOF_HEADER 0x02 // 2 bytes in the header
  133. #define PROT_SIZEOF_XORHEADER (PROT_SIZEOF_HEADER+sizeof(DWORD))
  134. #define PROT_VERSION_1 0x01
  135. #define PROT_PASS_XOR 0x01
  136. #define PROT_PASS_PST 0x02
  137. static BOOL FDataIsValidV1(BYTE *pb)
  138. { return pb && pb[0] == PROT_VERSION_1 && (pb[1] == PROT_PASS_XOR || pb[1] == PROT_PASS_PST); }
  139. static BOOL FDataIsPST(BYTE *pb)
  140. { return pb && pb[1] == PROT_PASS_PST; }
  141. ///////////////////////////////////////////////////////////////////////////
  142. //
  143. // NOTE - The functions for encoding the user passwords really should not
  144. // be here. Unfortunately, they are not anywhere else so for now,
  145. // this is where they will stay. They are defined as static since
  146. // other code should not rely on them staying here, particularly the
  147. // XOR stuff.
  148. //
  149. ///////////////////////////////////////////////////////////////////////////
  150. //
  151. // XOR functions
  152. //
  153. ///////////////////////////////////////////////////////////////////////////
  154. static HRESULT _XOREncodeProp(const BLOB *const pClear, BLOB *const pEncoded)
  155. {
  156. DWORD dwSize;
  157. DWORD last, last2;
  158. DWORD UNALIGNED *pdwCypher;
  159. DWORD dex;
  160. pEncoded->cbSize = pClear->cbSize+PROT_SIZEOF_XORHEADER;
  161. if (!MemAlloc((void* *)&pEncoded->pBlobData, pEncoded->cbSize + 6))
  162. return E_OUTOFMEMORY;
  163. // set up header data
  164. Assert(2 == PROT_SIZEOF_HEADER);
  165. pEncoded->pBlobData[0] = PROT_VERSION_1;
  166. pEncoded->pBlobData[1] = PROT_PASS_XOR;
  167. *((DWORD UNALIGNED *)&(pEncoded->pBlobData[2])) = pClear->cbSize;
  168. // nevermind that the pointer is offset by the header size, this is
  169. // where we start to write out the modified password
  170. pdwCypher = (DWORD UNALIGNED *)&(pEncoded->pBlobData[PROT_SIZEOF_XORHEADER]);
  171. dex = 0;
  172. last = OBFUSCATOR; // 0' = 0 ^ ob
  173. if (dwSize = pClear->cbSize / sizeof(DWORD))
  174. {
  175. // case where data is >= 4 bytes
  176. for (; dex < dwSize; dex++)
  177. {
  178. last2 = ((DWORD UNALIGNED *)pClear->pBlobData)[dex]; // 1
  179. pdwCypher[dex] = last2 ^ last; // 1' = 1 ^ 0
  180. last = last2; // save 1 for the 2 round
  181. }
  182. }
  183. // if we have bits left over
  184. // note that dwSize is computed now in bits
  185. if (dwSize = (pClear->cbSize % sizeof(DWORD))*8)
  186. {
  187. // need to not munge memory that isn't ours
  188. last >>= sizeof(DWORD)*8-dwSize;
  189. pdwCypher[dex] &= ((DWORD)-1) << dwSize;
  190. pdwCypher[dex] |=
  191. ((((DWORD UNALIGNED *)pClear->pBlobData)[dex] & (((DWORD)-1) >> (sizeof(DWORD)*8-dwSize))) ^ last);
  192. }
  193. return S_OK;
  194. }
  195. static HRESULT _XORDecodeProp(const BLOB *const pEncoded, BLOB *const pClear)
  196. {
  197. DWORD dwSize;
  198. DWORD last;
  199. DWORD UNALIGNED *pdwCypher;
  200. DWORD dex;
  201. // we use CoTaskMemAlloc to be in line with the PST implementation
  202. pClear->cbSize = *(DWORD UNALIGNED *)(&pEncoded->pBlobData[2]);
  203. MemAlloc((void **)&pClear->pBlobData, pClear->cbSize);
  204. if (!pClear->pBlobData)
  205. return E_OUTOFMEMORY;
  206. // should have been tested by now
  207. Assert(FDataIsValidV1(pEncoded->pBlobData));
  208. Assert(!FDataIsPST(pEncoded->pBlobData));
  209. // nevermind that the pointer is offset by the header size, this is
  210. // where the password starts
  211. pdwCypher = (DWORD UNALIGNED *)&(pEncoded->pBlobData[PROT_SIZEOF_XORHEADER]);
  212. dex = 0;
  213. last = OBFUSCATOR;
  214. if (dwSize = pClear->cbSize / sizeof(DWORD))
  215. {
  216. // case where data is >= 4 bytes
  217. for (; dex < dwSize; dex++)
  218. last = ((DWORD UNALIGNED *)pClear->pBlobData)[dex] = pdwCypher[dex] ^ last;
  219. }
  220. // if we have bits left over
  221. if (dwSize = (pClear->cbSize % sizeof(DWORD))*8)
  222. {
  223. // need to not munge memory that isn't ours
  224. last >>= sizeof(DWORD)*8-dwSize;
  225. ((DWORD UNALIGNED *)pClear->pBlobData)[dex] &= ((DWORD)-1) << dwSize;
  226. ((DWORD UNALIGNED *)pClear->pBlobData)[dex] |=
  227. ((pdwCypher[dex] & (((DWORD)-1) >> (sizeof(DWORD)*8-dwSize))) ^ last);
  228. }
  229. return S_OK;
  230. }
  231. /*
  232. EncodeUserPassword
  233. Encrypt the passed in password. This encryption seems to
  234. add an extra 6 bytes on to the beginning of the data
  235. that it passes back, so we need to make sure that the
  236. lpszPwd is large enough to hold a few extra characters.
  237. *cb should be different on return than it was when it
  238. was passed in.
  239. Parameters:
  240. lpszPwd - on entry, a c string containing the password.
  241. on exit, it is the encrypted data, plus some header info.
  242. cb - the size of lpszPwd on entry and exit. Note that it should
  243. include the trailing null, so "foo" would enter with *cb == 4.
  244. */
  245. void EncodeUserPassword(TCHAR *lpszPwd, ULONG *cb)
  246. {
  247. BLOB blobClient;
  248. BLOB blobProp;
  249. blobClient.pBlobData= (BYTE *)lpszPwd;
  250. blobClient.cbSize = *cb;
  251. blobProp.pBlobData = NULL;
  252. blobProp.cbSize = 0;
  253. _XOREncodeProp(&blobClient, &blobProp);
  254. if (blobProp.pBlobData)
  255. {
  256. memcpy(lpszPwd, blobProp.pBlobData, blobProp.cbSize);
  257. *cb = blobProp.cbSize;
  258. MemFree(blobProp.pBlobData);
  259. }
  260. }
  261. /*
  262. DecodeUserPassword
  263. Decrypt the passed in data and return a password. This
  264. encryption seems to add an extra 6 bytes on to the beginning
  265. so decrupting will result in a using less of lpszPwd.
  266. .
  267. *cb should be different on return than it was when it
  268. was passed in.
  269. Parameters:
  270. lpszPwd - on entry, the encrypted password plus some
  271. header info.
  272. on exit, a c string containing the password.
  273. cb - the size of lpszPwd on entry and exit. Note that it should
  274. include the trailing null, so "foo" would leave with *cb == 4.
  275. */
  276. void DecodeUserPassword(TCHAR *lpszPwd, ULONG *cb)
  277. {
  278. BLOB blobClient;
  279. BLOB blobProp;
  280. blobClient.pBlobData= (BYTE *)lpszPwd;
  281. blobClient.cbSize = *cb;
  282. blobProp.pBlobData = NULL;
  283. blobProp.cbSize = 0;
  284. _XORDecodeProp(&blobClient, &blobProp);
  285. if (blobProp.pBlobData)
  286. {
  287. memcpy(lpszPwd, blobProp.pBlobData, blobProp.cbSize);
  288. lpszPwd[blobProp.cbSize] = 0;
  289. *cb = blobProp.cbSize;
  290. MemFree(blobProp.pBlobData);
  291. }
  292. }
  293. // --------------------------------------------------------------------------------
  294. // MemInit
  295. // --------------------------------------------------------------------------------
  296. void MemInit()
  297. {
  298. }
  299. // --------------------------------------------------------------------------------
  300. // MemUnInit
  301. // --------------------------------------------------------------------------------
  302. void MemUnInit()
  303. {
  304. }
  305. // --------------------------------------------------------------------------------
  306. // MemFree
  307. // --------------------------------------------------------------------------------
  308. void MemFree(void* pv)
  309. {
  310. CoTaskMemFree(pv);
  311. }
  312. // --------------------------------------------------------------------------------
  313. // MemAlloc
  314. // --------------------------------------------------------------------------------
  315. BOOL MemAlloc(void** ppv, ULONG cb)
  316. {
  317. assert(ppv && cb);
  318. *ppv = CoTaskMemAlloc(cb);
  319. if (NULL == *ppv)
  320. return FALSE;
  321. return TRUE;
  322. }
  323. // --------------------------------------------------------------------------------
  324. // MemRealloc
  325. // --------------------------------------------------------------------------------
  326. BOOL MemRealloc(void* *ppv, ULONG cbNew)
  327. {
  328. assert(ppv && cbNew);
  329. void* pv = CoTaskMemRealloc(*ppv, cbNew);
  330. if (NULL == pv)
  331. return FALSE;
  332. *ppv = pv;
  333. return TRUE;
  334. }
  335. // --------------------------------------------------------------------------------
  336. // Functions to convert GUIDs to ascii strings
  337. // --------------------------------------------------------------------------------
  338. int AStringFromGUID(GUID *puid, TCHAR *lpsz, int cch)
  339. {
  340. WCHAR wsz[255];
  341. int i;
  342. i = StringFromGUID2(*puid, wsz, 255);
  343. if (WideCharToMultiByte(CP_ACP, 0, wsz, -1, lpsz, cch, NULL, NULL) == 0)
  344. return 0;
  345. return (lstrlen(lpsz) + 1);
  346. }
  347. HRESULT GUIDFromAString(TCHAR *lpsz, GUID *puid)
  348. {
  349. WCHAR wsz[255];
  350. HRESULT hr;
  351. if (MultiByteToWideChar(CP_ACP, 0, lpsz, -1, wsz, 255) == 0)
  352. return GetLastError();
  353. hr = CLSIDFromString(wsz, puid);
  354. return hr;
  355. }
  356. // ****************************************************************************************************
  357. // CNotifierList Class
  358. //
  359. // A really basic IUnknown list class. Actually, its a IUnknown array class, but you don't need to know
  360. // that.
  361. //
  362. CNotifierList::CNotifierList()
  363. {
  364. m_count = 0;
  365. m_ptrCount = 0;
  366. m_entries = NULL;
  367. m_nextCookie = 1;
  368. m_cRef = 1;
  369. InitializeCriticalSection(&m_rCritSect);
  370. }
  371. /*
  372. CNotifierList::~CNotifierList
  373. Clean up any memory that was allocated in the CNotifierList object
  374. */
  375. CNotifierList::~CNotifierList()
  376. {
  377. if (m_entries)
  378. {
  379. for (int i = 0; i < m_count; i++)
  380. {
  381. if (m_entries[i].punk)
  382. {
  383. m_entries[i].punk->Release();
  384. m_entries[i].punk = NULL;
  385. m_entries[i].dwCookie = 0;
  386. }
  387. }
  388. MemFree(m_entries);
  389. m_entries = NULL;
  390. m_count = 0;
  391. }
  392. DeleteCriticalSection(&m_rCritSect);
  393. }
  394. STDMETHODIMP_(ULONG) CNotifierList::AddRef()
  395. {
  396. return ++m_cRef;
  397. }
  398. STDMETHODIMP_(ULONG) CNotifierList::Release()
  399. {
  400. if( 0L != --m_cRef )
  401. return m_cRef;
  402. delete this;
  403. return 0L;
  404. }
  405. /*
  406. CNotifierList::Add
  407. Add a IUnknown to the end of the IUnknown list.
  408. */
  409. HRESULT CNotifierList::Add(IUnknown *punk, DWORD *pdwCookie)
  410. {
  411. TraceCall("Identity - CNotifierList::Add");
  412. EnterCriticalSection(&m_rCritSect);
  413. // make more room for pointers, if necessary
  414. if (m_ptrCount == m_count)
  415. {
  416. m_ptrCount += 5;
  417. if (!MemRealloc((void **)&m_entries, sizeof(UNKLIST_ENTRY) * m_ptrCount))
  418. {
  419. m_ptrCount -= 5;
  420. Assert(false);
  421. LeaveCriticalSection(&m_rCritSect);
  422. return E_OUTOFMEMORY;
  423. }
  424. // initialize the new IUnknowns to nil
  425. for (int i = m_count; i < m_ptrCount; i++)
  426. {
  427. ZeroMemory(&m_entries[i], sizeof(UNKLIST_ENTRY));
  428. }
  429. }
  430. //now put the IUnknown in the next location
  431. int iNewIndex = m_count++;
  432. punk->AddRef();
  433. m_entries[iNewIndex].punk = punk;
  434. m_entries[iNewIndex].bState = NS_NONE;
  435. m_entries[iNewIndex].dwCookie = ++m_nextCookie;
  436. m_entries[iNewIndex].dwThreadId = GetCurrentThreadId();
  437. *pdwCookie = m_entries[iNewIndex].dwCookie;
  438. LeaveCriticalSection(&m_rCritSect);
  439. CreateNotifyWindow();
  440. return S_OK;
  441. }
  442. /*
  443. CNotifierList::Remove
  444. Remove a IUnknown at zero based index iIndex
  445. */
  446. HRESULT CNotifierList::Remove(int iIndex)
  447. {
  448. int iCopySize;
  449. TraceCall("Identity - CNotifierList::Remove");
  450. EnterCriticalSection(&m_rCritSect);
  451. iCopySize = ((m_count - iIndex) - 1) * sizeof(UNKLIST_ENTRY);
  452. // free the memory for the IUnknown
  453. if (m_entries[iIndex].punk)
  454. {
  455. ReleaseWindow();
  456. m_entries[iIndex].punk->Release();
  457. ZeroMemory(&m_entries[iIndex], sizeof(UNKLIST_ENTRY));
  458. }
  459. // move the other IUnknowns down
  460. if (iCopySize)
  461. {
  462. memmove(&(m_entries[iIndex]), &(m_entries[iIndex+1]), iCopySize);
  463. }
  464. // null out the last item in the list and decrement the counter.
  465. m_entries[--m_count].punk = NULL;
  466. LeaveCriticalSection(&m_rCritSect);
  467. return S_OK;
  468. }
  469. /*
  470. CNotifierList::RemoveCookie
  471. Remove an IUnknown by its cookie
  472. */
  473. HRESULT CNotifierList::RemoveCookie(DWORD dwCookie)
  474. {
  475. int iIndex;
  476. for (iIndex = 0; iIndex < m_count; iIndex++)
  477. {
  478. if (m_entries[iIndex].dwCookie == dwCookie)
  479. {
  480. return Remove(iIndex);
  481. }
  482. }
  483. return E_FAIL;
  484. }
  485. /*
  486. CNotifierList::GetAtIndex
  487. Return the pointer to the IUnknown at zero based index iIndex.
  488. Return the IUnknown at the given index. Note that the object pointer
  489. is still owned by the IUnknown list and should not be deleted.
  490. */
  491. HRESULT CNotifierList::GetAtIndex(int iIndex, IUnknown **ppunk)
  492. {
  493. HRESULT hr = E_FAIL;
  494. EnterCriticalSection(&m_rCritSect);
  495. if (iIndex < m_count && iIndex >= 0 && m_entries[iIndex].punk)
  496. {
  497. *ppunk = m_entries[iIndex].punk;
  498. (*ppunk)->AddRef();
  499. hr = S_OK;
  500. }
  501. else
  502. *ppunk = NULL;
  503. LeaveCriticalSection(&m_rCritSect);
  504. return hr;
  505. }
  506. HRESULT CNotifierList::CreateNotifyWindow()
  507. {
  508. DWORD dwThreadCount = 0;
  509. DWORD dwThreadId = GetCurrentThreadId();
  510. int iIndex;
  511. int iFound = -1;
  512. HWND hwnd = NULL;
  513. for (iIndex = 0; iIndex < m_count; iIndex++)
  514. {
  515. if (m_entries[iIndex].dwThreadId == dwThreadId)
  516. {
  517. iFound = iIndex;
  518. if (!hwnd)
  519. hwnd = m_entries[iIndex].hwnd;
  520. else
  521. {
  522. Assert(NULL == m_entries[iIndex].hwnd || hwnd == m_entries[iIndex].hwnd);
  523. m_entries[iIndex].hwnd = hwnd;
  524. }
  525. dwThreadCount++;
  526. }
  527. }
  528. if (dwThreadCount == 1 && iFound >= 0)
  529. {
  530. hwnd = m_entries[iFound].hwnd = CreateWindowA(c_szNotifyWindowClass, c_szNotifyWindowClass, WS_POPUP,
  531. CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL,
  532. NULL, g_hInst, this);
  533. if (m_entries[iFound].hwnd)
  534. SetWindowLongPtr(m_entries[iFound].hwnd, GWLP_USERDATA, (LRESULT)this);
  535. }
  536. return (hwnd ? S_OK : E_FAIL);
  537. }
  538. HRESULT CNotifierList::ReleaseWindow()
  539. {
  540. DWORD dwThreadCount = 0;
  541. DWORD dwThreadId = GetCurrentThreadId();
  542. int iIndex;
  543. HWND hwnd = NULL;
  544. for (iIndex = 0; iIndex < m_count; iIndex++)
  545. {
  546. if (m_entries[iIndex].dwThreadId == dwThreadId)
  547. {
  548. if (dwThreadCount == 0)
  549. hwnd = m_entries[iIndex].hwnd;
  550. dwThreadCount++;
  551. }
  552. }
  553. if (dwThreadCount == 1 && hwnd)
  554. {
  555. SendMessage(hwnd, WM_CLOSE, 0, 0);
  556. }
  557. return S_OK;
  558. }
  559. HRESULT CNotifierList::PreNotify()
  560. {
  561. DWORD dwThreadId = GetCurrentThreadId();
  562. int iIndex;
  563. for (iIndex = m_count -1; iIndex >= 0; iIndex--)
  564. {
  565. if (m_entries[iIndex].dwThreadId == dwThreadId && NULL != m_entries[iIndex].punk)
  566. m_entries[iIndex].bState = NS_PRE_NOTIFY;
  567. // else //BUG 47472, this could cause problems during re-entrant calls to SendNotification
  568. // m_entries[iIndex].bState = NS_NONE;
  569. }
  570. return S_OK;
  571. }
  572. int CNotifierList::GetNextNotify()
  573. {
  574. DWORD dwThreadId = GetCurrentThreadId();
  575. int iIndex;
  576. for (iIndex = m_count -1; iIndex >= 0; iIndex--)
  577. {
  578. if (m_entries[iIndex].dwThreadId == dwThreadId && NULL != m_entries[iIndex].punk && NS_PRE_NOTIFY == m_entries[iIndex].bState)
  579. return iIndex;
  580. }
  581. return -1;
  582. }
  583. HRESULT CNotifierList::SendNotification(UINT msg, DWORD dwType)
  584. {
  585. DWORD dwThreadCount = 0, dwOldCount;
  586. DWORD dwThreadId = GetCurrentThreadId();
  587. int iIndex;
  588. HWND hwnd = NULL;
  589. HRESULT hr = S_OK;
  590. #if defined(DEBUG)
  591. DebugStrf("Identity - CNotifierList::SendNotification %ld\r\n", msg);
  592. #endif
  593. AddRef();
  594. PreNotify();
  595. while ((iIndex = GetNextNotify()) != -1)
  596. {
  597. IUnknown *punk;
  598. IIdentityChangeNotify *pICNotify;
  599. punk = m_entries[iIndex].punk;
  600. m_entries[iIndex].bState = NS_NOTIFIED;
  601. punk->AddRef();
  602. if (SUCCEEDED(punk->QueryInterface(IID_IIdentityChangeNotify, (void **)&pICNotify)) && pICNotify)
  603. {
  604. if( msg == WM_QUERY_IDENTITY_CHANGE )
  605. {
  606. if (FAILED(hr = pICNotify->QuerySwitchIdentities()))
  607. {
  608. punk->Release();
  609. pICNotify->Release();
  610. goto exit;
  611. }
  612. }
  613. else if( msg == WM_IDENTITY_CHANGED )
  614. {
  615. pICNotify->SwitchIdentities();
  616. }
  617. else if( msg == WM_IDENTITY_INFO_CHANGED )
  618. {
  619. pICNotify->IdentityInformationChanged(dwType);
  620. }
  621. pICNotify->Release();
  622. }
  623. punk->Release();
  624. }
  625. exit:
  626. Release();
  627. return hr;
  628. }
  629. #ifdef DEBUG
  630. // --------------------------------------------------------------------------------
  631. // DebugStrf
  632. // --------------------------------------------------------------------------------
  633. void DebugStrf(LPTSTR lpszFormat, ...)
  634. {
  635. static TCHAR szDebugBuff[500];
  636. va_list arglist;
  637. va_start(arglist, lpszFormat);
  638. wvsprintf(szDebugBuff, lpszFormat, arglist);
  639. va_end(arglist);
  640. OutputDebugString(szDebugBuff);
  641. }
  642. #endif
  643. // ---------------------------------------------------------------------------------
  644. // Pstore code for storing passwords
  645. // ---------------------------------------------------------------------------------
  646. // Functions related to saving and restoring user passwords from the pstore.
  647. // We have wrappers around Create and Release to allow for future caching of the pstore
  648. // instance within webcheck.
  649. STDAPI CreatePStore(IPStore **ppIPStore)
  650. {
  651. HRESULT hr;
  652. hr = PStoreCreateInstance ( ppIPStore,
  653. NULL,
  654. NULL,
  655. 0);
  656. return hr;
  657. }
  658. STDAPI ReleasePStore(IPStore *pIPStore)
  659. {
  660. HRESULT hr;
  661. if (pIPStore)
  662. {
  663. pIPStore->Release();
  664. hr = S_OK;
  665. }
  666. else
  667. {
  668. hr = E_POINTER;
  669. }
  670. return hr;
  671. }
  672. STDAPI ReadIdentityPassword(GUID *puidIdentity, PASSWORD_STORE *pPwdStore)
  673. {
  674. GUID itemType = GUID_NULL;
  675. GUID itemSubtype = GUID_NULL;
  676. PST_PROMPTINFO promptInfo = {0};
  677. IPStore* pStore = NULL;
  678. HRESULT hr ;
  679. if (pPwdStore == NULL)
  680. return E_POINTER;
  681. promptInfo.cbSize = sizeof(promptInfo);
  682. promptInfo.szPrompt = NULL;
  683. promptInfo.dwPromptFlags = 0;
  684. promptInfo.hwndApp = NULL;
  685. hr = CreatePStore(&pStore);
  686. if (SUCCEEDED(hr))
  687. {
  688. Assert(pStore != NULL);
  689. itemType = GUID_PStoreType;
  690. itemSubtype = *puidIdentity;
  691. if (SUCCEEDED(hr))
  692. {
  693. DWORD cbData;
  694. BYTE *pbData = NULL;
  695. hr = pStore->ReadItem(
  696. s_Key,
  697. &itemType,
  698. &itemSubtype,
  699. c_szIdentityPass,
  700. &cbData,
  701. &pbData,
  702. &promptInfo,
  703. 0);
  704. if (SUCCEEDED(hr))
  705. {
  706. CopyMemory(pPwdStore, pbData, (cbData <= sizeof(PASSWORD_STORE) ? cbData : sizeof(PASSWORD_STORE)));
  707. MemFree(pbData);
  708. hr = S_OK;
  709. }
  710. }
  711. ReleasePStore(pStore);
  712. }
  713. return hr;
  714. }
  715. STDAPI WriteIdentityPassword(GUID *puidIdentity, PASSWORD_STORE *pPwdStore)
  716. {
  717. HRESULT hr;
  718. PST_TYPEINFO typeInfo;
  719. PST_PROMPTINFO promptInfo;
  720. IPStore * pStore;
  721. typeInfo.cbSize = sizeof(typeInfo);
  722. typeInfo.szDisplayName = c_szIdentityMgr;
  723. promptInfo.cbSize = sizeof(promptInfo);
  724. promptInfo.dwPromptFlags = 0;
  725. promptInfo.hwndApp = NULL;
  726. promptInfo.szPrompt = NULL;
  727. hr = CreatePStore(&pStore);
  728. if (SUCCEEDED(hr))
  729. {
  730. GUID itemType = GUID_NULL;
  731. GUID itemSubtype = GUID_NULL;
  732. Assert(pStore != NULL);
  733. itemType = GUID_PStoreType;
  734. itemSubtype = *puidIdentity;
  735. if (SUCCEEDED(hr))
  736. {
  737. hr = pStore->CreateType(s_Key, &itemType, &typeInfo, 0);
  738. // PST_E_TYPE_EXISTS implies type already exists which is just fine
  739. // by us.
  740. if (SUCCEEDED(hr) || hr == PST_E_TYPE_EXISTS)
  741. {
  742. typeInfo.szDisplayName = c_szIdentities;
  743. hr = pStore->CreateSubtype(
  744. s_Key,
  745. &itemType,
  746. &itemSubtype,
  747. &typeInfo,
  748. NULL,
  749. 0);
  750. if (SUCCEEDED(hr) || hr == PST_E_TYPE_EXISTS)
  751. {
  752. if (pPwdStore != NULL)
  753. {
  754. hr = pStore->WriteItem(
  755. s_Key,
  756. &itemType,
  757. &itemSubtype,
  758. c_szIdentityPass,
  759. (sizeof(PASSWORD_STORE)),
  760. (BYTE *)pPwdStore,
  761. &promptInfo,
  762. PST_CF_NONE,
  763. 0);
  764. }
  765. else
  766. {
  767. hr = pStore->DeleteItem(
  768. s_Key,
  769. &itemType,
  770. &itemSubtype,
  771. c_szIdentityPass,
  772. &promptInfo,
  773. 0);
  774. }
  775. }
  776. }
  777. }
  778. ReleasePStore(pStore);
  779. }
  780. return hr;
  781. }
  782. #define CH_WHACK TEXT(FILENAME_SEPARATOR)
  783. // rips the last part of the path off including the backslash
  784. // C:\foo -> C:\ ;
  785. // C:\foo\bar -> C:\foo
  786. // C:\foo\ -> C:\foo
  787. // \\x\y\x -> \\x\y
  788. // \\x\y -> \\x
  789. // \\x -> ?? (test this)
  790. // \foo -> \ (Just the slash!)
  791. //
  792. // in/out:
  793. // pFile fully qualified path name
  794. // returns:
  795. // TRUE we stripped something
  796. // FALSE didn't strip anything (root directory case)
  797. //
  798. // Stolen from shlwapi\path.c
  799. STDAPI_(BOOL) _PathRemoveFileSpec(LPTSTR pFile)
  800. {
  801. LPTSTR pT;
  802. LPTSTR pT2 = pFile;
  803. for (pT = pT2; *pT2; pT2 = CharNext(pT2)) {
  804. if (*pT2 == CH_WHACK)
  805. pT = pT2; // last "\" found, (we will strip here)
  806. else if (*pT2 == TEXT(':')) { // skip ":\" so we don't
  807. if (pT2[1] ==TEXT('\\')) // strip the "\" from "C:\"
  808. pT2++;
  809. pT = pT2 + 1;
  810. }
  811. }
  812. if (*pT == 0)
  813. return FALSE; // didn't strip anything
  814. //
  815. // handle the \foo case
  816. //
  817. else if ((pT == pFile) && (*pT == CH_WHACK)) {
  818. // Is it just a '\'?
  819. if (*(pT+1) != TEXT('\0')) {
  820. // Nope.
  821. *(pT+1) = TEXT('\0');
  822. return TRUE; // stripped something
  823. }
  824. else {
  825. // Yep.
  826. return FALSE;
  827. }
  828. }
  829. else {
  830. *pT = 0;
  831. return TRUE; // stripped something
  832. }
  833. }