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.

664 lines
18 KiB

  1. /**********************************************************************/
  2. /** Microsoft Passport **/
  3. /** Copyright(c) Microsoft Corporation, 1999 - 2001 **/
  4. /**********************************************************************/
  5. /*
  6. ppshadowdocument.cpp
  7. manages a local shadow of the CCD
  8. FILE HISTORY:
  9. */
  10. #include "precomp.h"
  11. //===========================================================================
  12. //
  13. // PpShadowDocument
  14. //
  15. PpShadowDocument::PpShadowDocument()
  16. {
  17. }
  18. //===========================================================================
  19. //
  20. // PpShadowDocument
  21. //
  22. PpShadowDocument::PpShadowDocument(
  23. tstring& strURL) : m_strURL(strURL)
  24. {
  25. }
  26. //===========================================================================
  27. //
  28. // PpShadowDocument
  29. //
  30. PpShadowDocument::PpShadowDocument(
  31. tstring& strURL,
  32. tstring& strLocalFile) : m_strURL(strURL), m_strLocalFile(strLocalFile)
  33. {
  34. }
  35. //===========================================================================
  36. //
  37. // SetURL -- URL
  38. //
  39. void
  40. PpShadowDocument::SetURL(
  41. tstring& strURL)
  42. {
  43. m_strURL = strURL;
  44. }
  45. //===========================================================================
  46. //
  47. // SetLocalFile -- localfile name
  48. //
  49. void
  50. PpShadowDocument::SetLocalFile(
  51. tstring& strLocalFile)
  52. {
  53. m_strLocalFile = strLocalFile;
  54. }
  55. //===========================================================================
  56. //
  57. // GetDocument -- get CCDs DOM interface
  58. // -- bForceFetch : force an HTTPs, otherwise using local shadow
  59. //
  60. HRESULT
  61. PpShadowDocument::GetDocument(
  62. IXMLDocument** ppiXMLDocument,
  63. BOOL bForceFetch
  64. )
  65. {
  66. HRESULT hr;
  67. PpNexusClient nexusClient;
  68. IPersistStreamInitPtr xmlStream;
  69. IXMLDocumentPtr xmlDoc;
  70. if(ppiXMLDocument == NULL)
  71. {
  72. hr = E_INVALIDARG;
  73. goto Cleanup;
  74. }
  75. *ppiXMLDocument = NULL;
  76. if(bForceFetch)
  77. {
  78. // Fetch the XML document
  79. if(!m_strURL.empty())
  80. hr = nexusClient.FetchCCD(m_strURL, ppiXMLDocument);
  81. else
  82. {
  83. tstring strMsg;
  84. if(!m_strLocalFile.empty())
  85. {
  86. strMsg = TEXT("for ");
  87. strMsg += m_strLocalFile;
  88. }
  89. if (NULL != g_pAlert)
  90. {
  91. g_pAlert->report(PassportAlertInterface::ERROR_TYPE,
  92. NEXUS_EMPTYREMOTENAME,
  93. strMsg.c_str()
  94. );
  95. }
  96. hr = S_FALSE;
  97. }
  98. if(m_strLocalFile.empty())
  99. {
  100. tstring strMsg;
  101. if(!m_strURL.empty())
  102. {
  103. strMsg = TEXT("for ");
  104. strMsg += m_strURL;
  105. }
  106. if (NULL != g_pAlert)
  107. {
  108. g_pAlert->report(PassportAlertInterface::INFORMATION_TYPE,
  109. NEXUS_EMPTYLOCALNAME,
  110. strMsg.c_str()
  111. );
  112. }
  113. goto Cleanup;
  114. }
  115. // If FetchCCD failed and a local file is configured, read from the file.
  116. // If FetchCCD succeeded and a local file is configured, write to the file.
  117. if(hr == S_OK)
  118. {
  119. if(!NoPersist(*ppiXMLDocument))
  120. SaveDocument(*ppiXMLDocument);
  121. else
  122. {
  123. if (NULL != g_pAlert)
  124. {
  125. g_pAlert->report(PassportAlertInterface::INFORMATION_TYPE,
  126. NEXUS_NOTPERSISTING,
  127. m_strURL.c_str());
  128. }
  129. }
  130. }
  131. else
  132. {
  133. // use new hr variable, not to eat the global one
  134. HRESULT hr1 = LoadDocument(ppiXMLDocument);
  135. if (NULL != g_pAlert)
  136. {
  137. if (hr1 != S_OK)
  138. g_pAlert->report(PassportAlertInterface::ERROR_TYPE,
  139. NEXUS_LOADFAILED,
  140. m_strLocalFile.c_str());
  141. else
  142. g_pAlert->report(PassportAlertInterface::INFORMATION_TYPE,
  143. NEXUS_USINGLOCAL,
  144. m_strLocalFile.c_str());
  145. }
  146. }
  147. }
  148. else
  149. {
  150. if(!m_strLocalFile.empty())
  151. {
  152. hr = LoadDocument(ppiXMLDocument);
  153. if(hr == S_OK)
  154. {
  155. // If the file is still valid, then return.
  156. if(IsValidCCD(*ppiXMLDocument))
  157. {
  158. if (NULL != g_pAlert)
  159. {
  160. g_pAlert->report(PassportAlertInterface::INFORMATION_TYPE,
  161. NEXUS_USINGLOCAL,
  162. m_strLocalFile.c_str());
  163. }
  164. goto Cleanup;
  165. }
  166. }
  167. else
  168. {
  169. if (NULL != g_pAlert)
  170. {
  171. g_pAlert->report(PassportAlertInterface::ERROR_TYPE,
  172. NEXUS_LOADFAILED,
  173. m_strLocalFile.c_str());
  174. }
  175. }
  176. }
  177. else
  178. {
  179. tstring strMsg;
  180. if(!m_strURL.empty())
  181. {
  182. strMsg = TEXT("for ");
  183. strMsg += m_strURL;
  184. }
  185. if (NULL != g_pAlert)
  186. {
  187. g_pAlert->report(PassportAlertInterface::INFORMATION_TYPE,
  188. NEXUS_EMPTYLOCALNAME,
  189. strMsg.c_str()
  190. );
  191. }
  192. }
  193. // At this point, we're in one of two states:
  194. // 1. *ppiXMLDocument is NULL
  195. // 2. *ppiXMLDocument is not NULL, but points to a document that is old
  196. // Fetch the XML document, if successful release the document loaded from
  197. // disk (if any).
  198. if(!m_strURL.empty())
  199. hr = nexusClient.FetchCCD(m_strURL, &xmlDoc);
  200. else
  201. {
  202. tstring strMsg;
  203. if(!m_strLocalFile.empty())
  204. {
  205. strMsg = TEXT("for ");
  206. strMsg += m_strLocalFile;
  207. }
  208. if (NULL != g_pAlert)
  209. {
  210. g_pAlert->report(PassportAlertInterface::ERROR_TYPE,
  211. NEXUS_EMPTYREMOTENAME,
  212. strMsg.c_str()
  213. );
  214. }
  215. hr = S_FALSE;
  216. }
  217. if(hr == S_OK)
  218. {
  219. if(*ppiXMLDocument) (*ppiXMLDocument)->Release();
  220. xmlDoc->QueryInterface(IID_IXMLDocument, (void**)ppiXMLDocument);
  221. // If FetchCCD succeeded and a local file is configured, write to the file.
  222. if(!m_strLocalFile.empty())
  223. {
  224. if(!NoPersist(*ppiXMLDocument))
  225. {
  226. HANDLE hToken = NULL;
  227. //
  228. // In certain configurations this code can be run while impersonating a user who
  229. // does not have access to the directory to store the partner2.xml. Therefore
  230. // we revert to self prior to attempting to save the document.
  231. //
  232. if (OpenThreadToken(GetCurrentThread(),
  233. MAXIMUM_ALLOWED,
  234. TRUE,
  235. &hToken))
  236. {
  237. RevertToSelf();
  238. }
  239. SaveDocument(*ppiXMLDocument);
  240. if (hToken)
  241. {
  242. // put the impersonation token back
  243. if (!SetThreadToken(NULL, hToken))
  244. {
  245. hr = E_FAIL;
  246. }
  247. CloseHandle(hToken);
  248. }
  249. }
  250. else
  251. {
  252. if (NULL != g_pAlert)
  253. {
  254. g_pAlert->report(PassportAlertInterface::INFORMATION_TYPE,
  255. NEXUS_NOTPERSISTING,
  256. m_strURL.c_str());
  257. }
  258. }
  259. }
  260. else
  261. {
  262. tstring strMsg;
  263. if(!m_strURL.empty())
  264. {
  265. strMsg = TEXT("for ");
  266. strMsg += m_strURL;
  267. }
  268. if (NULL != g_pAlert)
  269. {
  270. g_pAlert->report(PassportAlertInterface::INFORMATION_TYPE,
  271. NEXUS_EMPTYLOCALNAME,
  272. strMsg.c_str()
  273. );
  274. }
  275. }
  276. }
  277. else if(*ppiXMLDocument)
  278. {
  279. // TODO: the logic is not so clear, on 3.0 timeframe, rewrite this whole func
  280. if (NULL != g_pAlert)
  281. {
  282. g_pAlert->report(PassportAlertInterface::INFORMATION_TYPE,
  283. NEXUS_USINGLOCAL,
  284. m_strLocalFile.c_str());
  285. }
  286. hr = S_OK;
  287. }
  288. else
  289. {
  290. // If we get here it means that the fetch from the nexus failed
  291. // and the load from disk failed. It is sufficient here to simply
  292. // fall through because hr will already contain an error code
  293. // which should indicate to the caller that no document is
  294. // available.
  295. }
  296. }
  297. Cleanup:
  298. return hr;
  299. }
  300. //===========================================================================
  301. //
  302. // IsValidCCD -- check ValidUntil attribute of the CCD
  303. //
  304. BOOL
  305. PpShadowDocument::IsValidCCD(
  306. IXMLDocument* piXMLDocument
  307. )
  308. {
  309. BOOL bReturn;
  310. HRESULT hr;
  311. IXMLElementPtr piRootElement;
  312. SYSTEMTIME sysTime;
  313. DOUBLE dblTime;
  314. VARIANT vAttrValue;
  315. VARIANT vAttrDate;
  316. hr = piXMLDocument->get_root(&piRootElement);
  317. if(hr != S_OK)
  318. {
  319. bReturn = FALSE;
  320. goto Cleanup;
  321. }
  322. VariantInit(&vAttrValue);
  323. hr = piRootElement->getAttribute(L"ValidUntil", &vAttrValue);
  324. if(hr != S_OK)
  325. {
  326. bReturn = FALSE;
  327. goto Cleanup;
  328. }
  329. VariantInit(&vAttrDate);
  330. hr = VariantChangeType(&vAttrDate, &vAttrValue, 0, VT_DATE);
  331. if(hr != S_OK)
  332. {
  333. bReturn = FALSE;
  334. goto Cleanup;
  335. }
  336. GetSystemTime(&sysTime);
  337. SystemTimeToVariantTime(&sysTime, &dblTime);
  338. bReturn = ((long)V_DATE(&vAttrDate) >= (long)dblTime);
  339. Cleanup:
  340. VariantClear(&vAttrValue);
  341. VariantClear(&vAttrDate);
  342. return bReturn;
  343. }
  344. //===========================================================================
  345. //
  346. // NoPersist -- Check no persist attribute of the document
  347. //
  348. BOOL
  349. PpShadowDocument::NoPersist(
  350. IXMLDocument* piXMLDocument
  351. )
  352. {
  353. BOOL bReturn;
  354. HRESULT hr;
  355. IXMLElementPtr piRootElement;
  356. VARIANT vAttrValue;
  357. hr = piXMLDocument->get_root(&piRootElement);
  358. if(hr != S_OK)
  359. {
  360. bReturn = FALSE;
  361. goto Cleanup;
  362. }
  363. VariantInit(&vAttrValue);
  364. hr = piRootElement->getAttribute(L"NoPersist", &vAttrValue);
  365. if(hr != S_OK)
  366. {
  367. bReturn = FALSE;
  368. goto Cleanup;
  369. }
  370. bReturn = (lstrcmpiW(L"true", V_BSTR(&vAttrValue)) == 0);
  371. Cleanup:
  372. VariantClear(&vAttrValue);
  373. return bReturn;
  374. }
  375. //===========================================================================
  376. //
  377. // SaveDocument -- save CCD to local file
  378. //
  379. HRESULT
  380. PpShadowDocument::SaveDocument(
  381. IXMLDocument* piXMLDoc
  382. )
  383. {
  384. HRESULT hr;
  385. HANDLE hFile = INVALID_HANDLE_VALUE;
  386. ULARGE_INTEGER uliSize;
  387. LARGE_INTEGER liZero = {0,0};
  388. IStreamPtr piStream;
  389. IPersistStreamInitPtr piPSI;
  390. LPBYTE lpBuf = NULL;
  391. DWORD dwCurBlock;
  392. DWORD dwBytesWritten;
  393. hr = CreateStreamOnHGlobal(NULL, TRUE, &piStream);
  394. if(hr != S_OK)
  395. goto Cleanup;
  396. hr = piXMLDoc->QueryInterface(IID_IPersistStreamInit, (void**)&piPSI);
  397. if(hr != S_OK)
  398. goto Cleanup;
  399. piPSI->Save(piStream, TRUE);
  400. piStream->Seek(liZero, STREAM_SEEK_CUR, &uliSize);
  401. piStream->Seek(liZero, STREAM_SEEK_SET, NULL);
  402. if(uliSize.HighPart != 0)
  403. {
  404. hr = E_FAIL;
  405. goto Cleanup;
  406. }
  407. lpBuf = new BYTE[uliSize.LowPart];
  408. if(lpBuf == NULL)
  409. {
  410. hr = E_OUTOFMEMORY;
  411. goto Cleanup;
  412. }
  413. hFile = CreateFile(
  414. m_strLocalFile.c_str(),
  415. GENERIC_WRITE,
  416. 0,
  417. NULL,
  418. CREATE_ALWAYS,
  419. FILE_ATTRIBUTE_NORMAL,
  420. NULL);
  421. if(hFile == INVALID_HANDLE_VALUE)
  422. {
  423. hr = GetLastError();
  424. goto Cleanup;
  425. }
  426. for(dwCurBlock = 0; dwCurBlock < uliSize.HighPart; dwCurBlock++)
  427. {
  428. hr = piStream->Read(lpBuf, 0xFFFFFFFF, NULL);
  429. if(!WriteFile(hFile, lpBuf, 0xFFFFFFFF, NULL, NULL))
  430. {
  431. hr = GetLastError();
  432. goto Cleanup;
  433. }
  434. }
  435. hr = piStream->Read(lpBuf, uliSize.LowPart, NULL);
  436. if(hr != S_OK)
  437. goto Cleanup;
  438. if(!WriteFile(hFile, lpBuf, uliSize.LowPart, &dwBytesWritten, NULL))
  439. {
  440. hr = GetLastError();
  441. goto Cleanup;
  442. }
  443. hr = S_OK;
  444. Cleanup:
  445. if(hr != S_OK)
  446. {
  447. TCHAR achErrBuf[1024];
  448. LPCTSTR apszStrings[] = { m_strLocalFile.c_str(), achErrBuf };
  449. LPVOID lpMsgBuf = NULL;
  450. ULONG cchTmp;
  451. FormatMessage(
  452. FORMAT_MESSAGE_ALLOCATE_BUFFER |
  453. FORMAT_MESSAGE_FROM_SYSTEM |
  454. FORMAT_MESSAGE_IGNORE_INSERTS |
  455. FORMAT_MESSAGE_FROM_HMODULE |
  456. FORMAT_MESSAGE_MAX_WIDTH_MASK,
  457. GetModuleHandle(TEXT("wininet.dll")),
  458. hr,
  459. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  460. (LPTSTR) &lpMsgBuf,
  461. 0,
  462. NULL );
  463. lstrcpy(achErrBuf, TEXT("0x"));
  464. _ultot(hr, &(achErrBuf[2]), 16);
  465. achErrBuf[sizeof(achErrBuf) / sizeof(achErrBuf[0]) - 1] = TEXT('\0');
  466. if(lpMsgBuf != NULL && *(LPTSTR)lpMsgBuf != TEXT('\0'))
  467. {
  468. cchTmp = _tcslen(achErrBuf) + 1;
  469. _tcsncat(achErrBuf, TEXT(" ("), (sizeof(achErrBuf) / sizeof(achErrBuf[0])) - cchTmp);
  470. _tcsncat(achErrBuf, (LPTSTR)lpMsgBuf, (sizeof(achErrBuf) / sizeof(achErrBuf[0])) - (cchTmp + 2));
  471. cchTmp = _tcslen(achErrBuf) + 1;
  472. _tcsncat(achErrBuf, TEXT(") "), (sizeof(achErrBuf) / sizeof(achErrBuf[0])) - cchTmp);
  473. }
  474. lstrcat(achErrBuf, TEXT(" when trying to save the fetched file to disk."));
  475. g_pAlert->report(PassportAlertInterface::ERROR_TYPE,
  476. NEXUS_LOCALSAVEFAILED,
  477. 2,
  478. apszStrings,
  479. 0,
  480. NULL
  481. );
  482. LocalFree(lpMsgBuf);
  483. hr = E_FAIL;
  484. }
  485. if(lpBuf != NULL)
  486. delete [] lpBuf;
  487. if(hFile != INVALID_HANDLE_VALUE)
  488. CloseHandle(hFile);
  489. return hr;
  490. }
  491. //===========================================================================
  492. //
  493. // LoadDocument -- get CCDs from local
  494. //
  495. HRESULT
  496. PpShadowDocument::LoadDocument(
  497. IXMLDocument** ppiXMLDocument
  498. )
  499. {
  500. HRESULT hr;
  501. HANDLE hFile = INVALID_HANDLE_VALUE;
  502. DWORD dwFileSizeLow;
  503. DWORD dwBytesRead;
  504. LPBYTE lpBuf = NULL;
  505. IStreamPtr piStream;
  506. IPersistStreamInitPtr piPSI;
  507. LARGE_INTEGER liZero = {0,0};
  508. hFile = CreateFile(
  509. m_strLocalFile.c_str(),
  510. GENERIC_READ,
  511. FILE_SHARE_READ,
  512. NULL,
  513. OPEN_EXISTING,
  514. FILE_ATTRIBUTE_NORMAL,
  515. NULL);
  516. if(hFile == INVALID_HANDLE_VALUE)
  517. {
  518. hr = E_FAIL;
  519. goto Cleanup;
  520. }
  521. dwFileSizeLow = GetFileSize(hFile, NULL);
  522. if(dwFileSizeLow == 0xFFFFFFFF)
  523. {
  524. hr = GetLastError();
  525. goto Cleanup;
  526. }
  527. lpBuf = new BYTE[dwFileSizeLow];
  528. if(lpBuf == NULL)
  529. {
  530. hr = E_OUTOFMEMORY;
  531. goto Cleanup;
  532. }
  533. hr = CreateStreamOnHGlobal(NULL, TRUE, &piStream);
  534. if(hr != S_OK)
  535. {
  536. hr = E_FAIL;
  537. goto Cleanup;
  538. }
  539. if(ReadFile(hFile, lpBuf, dwFileSizeLow, &dwBytesRead, NULL) == 0)
  540. {
  541. hr = E_FAIL;
  542. goto Cleanup;
  543. }
  544. try
  545. {
  546. hr = piStream->Write(lpBuf, dwFileSizeLow, NULL);
  547. hr = piStream->Seek(liZero, STREAM_SEEK_SET, NULL);
  548. }
  549. catch(...)
  550. {
  551. hr = E_FAIL;
  552. goto Cleanup;
  553. }
  554. //
  555. // Now create an XML object and initialize it using the stream.
  556. //
  557. hr = CoCreateInstance(__uuidof(XMLDocument), NULL, CLSCTX_ALL, IID_IPersistStreamInit, (void**)&piPSI);
  558. if(hr != S_OK)
  559. goto Cleanup;
  560. hr = piPSI->Load((IStream*)piStream);
  561. if(hr != S_OK)
  562. goto Cleanup;
  563. hr = piPSI->QueryInterface(__uuidof(IXMLDocument), (void**)ppiXMLDocument);
  564. Cleanup:
  565. if(lpBuf != NULL)
  566. delete [] lpBuf;
  567. if(hFile != INVALID_HANDLE_VALUE)
  568. CloseHandle(hFile);
  569. return hr;
  570. }