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.

697 lines
18 KiB

  1. //+----------------------------------------------------------------------------
  2. // File: persist.cxx
  3. //
  4. // Synopsis:
  5. //
  6. //-----------------------------------------------------------------------------
  7. // Includes -------------------------------------------------------------------
  8. #include <mgr.hxx>
  9. #include <factory.hxx>
  10. #include "wininet.h"
  11. // Constants ------------------------------------------------------------------
  12. const LARGE_INTEGER LIB_ZERO = { 0, 0 };
  13. const ULONG BUFFER_SIZE = 256;
  14. const ULONG CHARS_PER_LINE = 65;
  15. const WCHAR LPKPATH[] = L"LPKPath";
  16. const TCHAR SZ_URLMON[] = _T("URLMON.DLL");
  17. const TCHAR SZ_ISVALIDURL[] = _T("IsValidURL");
  18. const TCHAR SZ_URLDOWNLOADTOCACHEFILE[] = _T("URLDownloadToCacheFileW");
  19. typedef HRESULT (STDMETHODCALLTYPE *ISVALIDURL)(LPBC, LPCWSTR, DWORD);
  20. typedef HRESULT (STDMETHODCALLTYPE *URLDOWNLOADTOCACHEFILE)(LPUNKNOWN,LPCWSTR,LPWSTR,
  21. DWORD,DWORD,LPBINDSTATUSCALLBACK);
  22. //+----------------------------------------------------------------------------
  23. //
  24. // Member: FindInStream
  25. //
  26. // Synopsis:
  27. //
  28. // Arguments:
  29. //
  30. // Returns:
  31. //
  32. //-----------------------------------------------------------------------------
  33. HRESULT
  34. CLicenseManager::FindInStream(
  35. IStream * pstm,
  36. BYTE * pbData,
  37. ULONG cbData)
  38. {
  39. BYTE bByte;
  40. ULONG cbRead;
  41. ULONG ibData = 0;
  42. HRESULT hr;
  43. Assert(pstm);
  44. Assert(pbData);
  45. Assert(cbData);
  46. // Read through the stream looking for the data
  47. for (;;)
  48. {
  49. // Read a byte of data
  50. hr = pstm->Read(&bByte, sizeof(BYTE), &cbRead);
  51. if (hr)
  52. goto Cleanup;
  53. if (!cbRead)
  54. break;
  55. if (bByte == pbData[ibData])
  56. {
  57. ibData++;
  58. if (ibData >= cbData)
  59. break;
  60. }
  61. }
  62. // If the data was found, return success
  63. hr = (ibData == cbData
  64. ? S_OK
  65. : E_FAIL);
  66. Cleanup:
  67. return hr;
  68. }
  69. //+----------------------------------------------------------------------------
  70. //
  71. // Member: GetClassID
  72. //
  73. // Synopsis: Return the object's CLSID
  74. //
  75. // Arguments: pclsid - Location at which to return the object's CLSID
  76. //
  77. //-----------------------------------------------------------------------------
  78. STDMETHODIMP
  79. CLicenseManager::GetClassID(
  80. CLSID * pclsid)
  81. {
  82. if (!pclsid)
  83. return E_INVALIDARG;
  84. *pclsid = CLSID_LicenseManager;
  85. return S_OK;
  86. }
  87. //+----------------------------------------------------------------------------
  88. //
  89. // Member: IsDirty
  90. //
  91. // Synopsis: Return whether the object is dirty or not
  92. //
  93. //-----------------------------------------------------------------------------
  94. STDMETHODIMP
  95. CLicenseManager::IsDirty()
  96. {
  97. return (_fDirty
  98. ? S_OK
  99. : S_FALSE);
  100. }
  101. //+----------------------------------------------------------------------------
  102. //
  103. // Member: Load
  104. //
  105. // Synopsis:
  106. //
  107. // Arguments:
  108. //
  109. // Returns:
  110. //
  111. //-----------------------------------------------------------------------------
  112. STDMETHODIMP
  113. CLicenseManager::Load(
  114. IStream * pstm)
  115. {
  116. CBufferedStream bstm(pstm);
  117. LARGE_INTEGER libCur;
  118. ULARGE_INTEGER uibSize;
  119. HRESULT hr;
  120. Assert(_fPersistStream || _fPersistPBag);
  121. if (!pstm)
  122. return E_INVALIDARG;
  123. if (_fLoaded)
  124. return E_UNEXPECTED;
  125. // Prepare the buffered stream for use
  126. hr = bstm.SetBufferSize(BUFFER_SIZE);
  127. if (hr)
  128. goto Cleanup;
  129. // Determine the size of the stream
  130. hr = pstm->Seek(LIB_ZERO, STREAM_SEEK_CUR, (ULARGE_INTEGER *)&libCur);
  131. if (hr)
  132. goto Cleanup;
  133. hr = pstm->Seek(LIB_ZERO, STREAM_SEEK_END, &uibSize);
  134. if (hr)
  135. goto Cleanup;
  136. hr = pstm->Seek(libCur, STREAM_SEEK_SET, NULL);
  137. if (hr)
  138. goto Cleanup;
  139. // Load from the buffered stream
  140. Assert(!uibSize.HighPart);
  141. hr = Load(&bstm, uibSize.LowPart);
  142. Cleanup:
  143. return hr;
  144. }
  145. //+----------------------------------------------------------------------------
  146. //
  147. // Member: Load
  148. //
  149. // Synopsis:
  150. //
  151. // Arguments:
  152. //
  153. // Returns:
  154. //
  155. //-----------------------------------------------------------------------------
  156. HRESULT
  157. CLicenseManager::Load(
  158. IStream * pstm,
  159. ULONG cbSize)
  160. {
  161. CMemoryStream mstm;
  162. ULARGE_INTEGER uibSize = { cbSize, 0 };
  163. char * psz = NULL;
  164. OLECHAR * polechar = NULL;
  165. DWORD cch;
  166. DWORD cchMax = 0;
  167. DWORD cLic;
  168. DWORD iLic;
  169. BOOL fSkipClass;
  170. HRESULT hr;
  171. // Scan for the LPK version identifier and skip over it
  172. cch = ::lstrlenA(g_pszLPKVersion1);
  173. hr = FindInStream(pstm, (BYTE *)g_pszLPKVersion1, cch);
  174. if (hr)
  175. goto Cleanup;
  176. // Allocate a memory-based stream to hold the binary data
  177. hr = mstm.SetSize(uibSize);
  178. if (hr)
  179. goto Cleanup;
  180. // Convert and load the LPK identifier
  181. hr = DecodeMIME64(pstm, &mstm, NULL);
  182. if (hr)
  183. goto Cleanup;
  184. Verify(SUCCEEDED(mstm.Seek(LIB_ZERO, STREAM_SEEK_SET, NULL)));
  185. hr = mstm.Read((void *)&_guidLPK, sizeof(_guidLPK), NULL);
  186. if (hr)
  187. goto Cleanup;
  188. // Convert and load the number of CLSID-License pairs
  189. Verify(SUCCEEDED(mstm.Seek(LIB_ZERO, STREAM_SEEK_SET, NULL)));
  190. hr = DecodeMIME64(pstm, &mstm, NULL);
  191. if (hr)
  192. goto Cleanup;
  193. Verify(SUCCEEDED(mstm.Seek(LIB_ZERO, STREAM_SEEK_SET, NULL)));
  194. hr = mstm.Read((void *)&cLic, sizeof(DWORD), NULL);
  195. if (hr)
  196. goto Cleanup;
  197. hr = _aryLic.SetSize((int)cLic);
  198. if (hr)
  199. goto Cleanup;
  200. ::memset((LICENSE *)_aryLic, 0, sizeof(LICENSE)*cLic);
  201. // Convert the remainder of the stream and from it load each CLSID-License pair
  202. // (If, somehow, invalid CLSIDs end up in the stream, skip over them during load)
  203. for (iLic = 0; iLic < cLic; )
  204. {
  205. Verify(SUCCEEDED(mstm.Seek(LIB_ZERO, STREAM_SEEK_SET, NULL)));
  206. hr = DecodeMIME64(pstm, &mstm, NULL);
  207. if (hr)
  208. goto Cleanup;
  209. Verify(SUCCEEDED(mstm.Seek(LIB_ZERO, STREAM_SEEK_SET, NULL)));
  210. hr = mstm.Read((void *)&(_aryLic[iLic].clsid), sizeof(_aryLic[0].clsid), NULL);
  211. if (hr)
  212. goto Cleanup;
  213. fSkipClass = (_aryLic[iLic].clsid == CLSID_NULL);
  214. hr = mstm.Read((void *)&cch, sizeof(DWORD), NULL);
  215. if (hr)
  216. goto Cleanup;
  217. if (cch > cchMax)
  218. {
  219. delete [] psz;
  220. delete [] polechar;
  221. psz = new char[cch*sizeof(OLECHAR)]; // Review:JulianJ
  222. polechar = new OLECHAR[cch];
  223. if (!psz || !polechar)
  224. {
  225. hr = E_OUTOFMEMORY;
  226. goto Cleanup;
  227. }
  228. cchMax = cch;
  229. }
  230. Assert(psz);
  231. Assert(polechar);
  232. //
  233. // REVIEW JulianJ read cch*2 bytes as we persisted entire string
  234. //
  235. hr = mstm.Read((void *)psz, cch*sizeof(OLECHAR), NULL);
  236. if (hr)
  237. goto Cleanup;
  238. if (!fSkipClass)
  239. {
  240. #if 1
  241. ::memcpy(polechar, psz, cch*sizeof(OLECHAR));
  242. #else
  243. #ifndef _PPCMAC
  244. ::MultiByteToWideChar(CP_ACP, 0, psz, cch, polechar, cch);
  245. #else
  246. ::memcpy(polechar, psz, cch);
  247. #endif
  248. #endif
  249. _aryLic[iLic].bstrLic = ::SysAllocStringLen(polechar, cch);
  250. if (!_aryLic[iLic].bstrLic)
  251. {
  252. hr = E_OUTOFMEMORY;
  253. goto Cleanup;
  254. }
  255. iLic++;
  256. }
  257. else
  258. {
  259. cLic--;
  260. }
  261. }
  262. // Ensure the array size is correct (in case any classes were skipped during load)
  263. if (cLic < (DWORD)_aryLic.Size())
  264. {
  265. Verify(SUCCEEDED(_aryLic.SetSize(cLic)));
  266. }
  267. Cleanup:
  268. delete [] psz;
  269. delete [] polechar;
  270. _fLoaded = TRUE;
  271. return hr;
  272. }
  273. //+----------------------------------------------------------------------------
  274. //
  275. // Member: Save
  276. //
  277. // Synopsis:
  278. //
  279. // Arguments:
  280. //
  281. // Returns:
  282. //
  283. //-----------------------------------------------------------------------------
  284. STDMETHODIMP
  285. CLicenseManager::Save(
  286. IStream * pstm,
  287. BOOL fClearDirty)
  288. {
  289. CBufferedStream bstm(pstm, CHARS_PER_LINE, FALSE);
  290. ULARGE_INTEGER uibCur;
  291. TCHAR szString[MAX_PATH];
  292. DWORD cbBuf = 0;
  293. DWORD cbLic;
  294. DWORD cb;
  295. BYTE * pb = NULL;
  296. BYTE * pbNext;
  297. int iLic;
  298. HRESULT hr = S_OK;
  299. Assert(_fPersistStream);
  300. if (!pstm)
  301. return E_INVALIDARG;
  302. // If this is a new LPK, generate an identifying GUID
  303. if (_guidLPK == GUID_NULL)
  304. {
  305. Assert(!_fLoaded);
  306. Verify(SUCCEEDED(::CoCreateGuid(&_guidLPK)));
  307. }
  308. // Write the text header to the LPK
  309. for (iLic=IDS_COPYTEXT; iLic <= IDS_COPYTEXT_MAX; iLic++)
  310. {
  311. cb = ::LoadString((HINSTANCE)g_hinst, iLic, szString, ARRAY_SIZE(szString));
  312. hr = pstm->Write(szString, cb, NULL);
  313. if (hr)
  314. goto Cleanup;
  315. hr = pstm->Write(SZ_NEWLINE, CB_NEWLINE, NULL);
  316. if (hr)
  317. goto Cleanup;
  318. }
  319. // Write the version GUID to the LPK
  320. hr = pstm->Write(g_pszLPKVersion1, ::lstrlenA(g_pszLPKVersion1), NULL);
  321. if (hr)
  322. goto Cleanup;
  323. hr = pstm->Write(SZ_NEWLINE, CB_NEWLINE, NULL);
  324. if (hr)
  325. goto Cleanup;
  326. // Prepare the buffered stream as the target for encoding
  327. hr = bstm.SetBufferSize(BUFFER_SIZE);
  328. if (hr)
  329. goto Cleanup;
  330. // Write the identifying GUID to the LPK
  331. hr = EncodeMIME64((BYTE *)&_guidLPK, sizeof(_guidLPK), &bstm, NULL);
  332. if (hr)
  333. goto Cleanup;
  334. hr = bstm.Write(SZ_NEWLINE, CB_NEWLINE, NULL);
  335. if (hr)
  336. goto Cleanup;
  337. // Write the number of CLSID-License pairs to the LPK
  338. cb = (DWORD)_aryLic.Size();
  339. hr = EncodeMIME64((BYTE *)&cb, sizeof(cb), &bstm, NULL);
  340. if (hr)
  341. goto Cleanup;
  342. hr = bstm.Write(SZ_NEWLINE, CB_NEWLINE, NULL);
  343. if (hr)
  344. goto Cleanup;
  345. // Write each CLSID-License pair to the LPK
  346. // (If the array contains empty entries, they are still persisted; this is necessary
  347. // because the number of entries persisted must match the count already written)
  348. for (iLic = 0; iLic < _aryLic.Size(); iLic++)
  349. {
  350. // Determine the amount of class data and ensure the buffer is sufficiently large
  351. cbLic = ::SysStringLen(_aryLic[iLic].bstrLic);
  352. cb = sizeof(CLSID) + sizeof(DWORD) + (sizeof(OLECHAR) * cbLic);
  353. if (cb > cbBuf)
  354. {
  355. cbBuf = cb;
  356. delete [] pb;
  357. pb = new BYTE[cbBuf];
  358. if (!pb)
  359. {
  360. hr = E_OUTOFMEMORY;
  361. goto Cleanup;
  362. }
  363. }
  364. pbNext = pb;
  365. // Fill the buffer with the persistent state of the class
  366. *((CLSID *)pbNext) = _aryLic[iLic].clsid;
  367. pbNext += sizeof(CLSID);
  368. *((DWORD *)pbNext) = cbLic;
  369. pbNext += sizeof(DWORD);
  370. //
  371. // REVIEW JulianJ, Weird - we seem to get back a length prefixed ansi string!
  372. //
  373. #if 1
  374. memcpy(pbNext, _aryLic[iLic].bstrLic, cbLic * (sizeof(OLECHAR)));
  375. #else
  376. #ifndef _PPCMAC
  377. ::WideCharToMultiByte(CP_ACP, 0, _aryLic[iLic].bstrLic, cbLic, (LPSTR)pbNext, cbLic, NULL, NULL);
  378. #else
  379. ::memcpy(pbNext, _aryLic[iLic].bstrLic, cbLic);
  380. #endif
  381. #endif
  382. // Encode the class to the stream
  383. hr = EncodeMIME64(pb, cb, &bstm, NULL);
  384. if (hr)
  385. goto Cleanup;
  386. hr = bstm.Write(SZ_NEWLINE, CB_NEWLINE, NULL);
  387. if (hr)
  388. goto Cleanup;
  389. }
  390. // Flush the buffered stream and mark the end of data
  391. // (Since not all streams support Seek and SetSize, errors from those methods
  392. // are ignored; since the stream contains a count, it can be safely loaded
  393. // without truncating unnecessary bytes)
  394. hr = bstm.Flush();
  395. if (hr)
  396. goto Cleanup;
  397. Verify(SUCCEEDED(pstm->Seek(LIB_ZERO, STREAM_SEEK_CUR, &uibCur)));
  398. Verify(SUCCEEDED(pstm->SetSize(uibCur)));
  399. Cleanup:
  400. delete [] pb;
  401. _fLoaded = TRUE;
  402. _fDirty = !fClearDirty && SUCCEEDED(hr);
  403. return hr;
  404. }
  405. //+----------------------------------------------------------------------------
  406. //
  407. // Member: GetSizeMax
  408. //
  409. // Synopsis:
  410. //
  411. // Arguments:
  412. //
  413. // Returns:
  414. //
  415. //-----------------------------------------------------------------------------
  416. STDMETHODIMP
  417. CLicenseManager::GetSizeMax(
  418. ULARGE_INTEGER * pcbSize)
  419. {
  420. if (!pcbSize)
  421. return E_INVALIDARG;
  422. pcbSize->LowPart =
  423. pcbSize->HighPart = 0;
  424. return E_NOTIMPL;
  425. }
  426. //+----------------------------------------------------------------------------
  427. //
  428. // Member: InitNew
  429. //
  430. // Synopsis:
  431. //
  432. // Arguments:
  433. //
  434. // Returns:
  435. //
  436. //-----------------------------------------------------------------------------
  437. STDMETHODIMP
  438. CLicenseManager::InitNew()
  439. {
  440. if (_fLoaded)
  441. return E_UNEXPECTED;
  442. _fLoaded = TRUE;
  443. return S_OK;
  444. }
  445. //+----------------------------------------------------------------------------
  446. //
  447. // Member: Load
  448. //
  449. // Synopsis:
  450. //
  451. // Arguments:
  452. //
  453. // Returns:
  454. //
  455. //-----------------------------------------------------------------------------
  456. STDMETHODIMP
  457. CLicenseManager::Load(
  458. IPropertyBag * pPropBag,
  459. IErrorLog * pErrorLog)
  460. {
  461. HMODULE hURLMon = NULL;
  462. VARIANT var;
  463. HRESULT hr;
  464. Assert(_fPersistPBag);
  465. if (!pPropBag)
  466. return E_INVALIDARG;
  467. if (_fLoaded)
  468. return E_UNEXPECTED;
  469. ::VariantInit(&var);
  470. V_VT(&var) = VT_BSTR;
  471. V_BSTR(&var) = NULL;
  472. // Read the path from which to load the LPK file
  473. hr = pPropBag->Read(LPKPATH, &var, pErrorLog);
  474. if (!hr)
  475. {
  476. CFileStream fstm;
  477. FARPROC fpIsValidURL;
  478. FARPROC fpURLDownloadToCacheFileW;
  479. WCHAR szCachedFilename[MAX_PATH];
  480. // Load the URL moniker library
  481. hURLMon = (HMODULE)::LoadLibrary(SZ_URLMON);
  482. if (!hURLMon)
  483. {
  484. hr = GetWin32Hresult();
  485. goto Cleanup;
  486. }
  487. // Check the path, if it is for an absolute URL, reject it
  488. // (Only relative URLs are accepted)
  489. fpIsValidURL = GetProcAddress(hURLMon, SZ_ISVALIDURL);
  490. if (!fpIsValidURL)
  491. {
  492. hr = GetWin32Hresult();
  493. goto Cleanup;
  494. }
  495. hr = (*((ISVALIDURL)fpIsValidURL))(NULL, V_BSTR(&var), 0);
  496. if (hr == S_OK)
  497. {
  498. hr = E_INVALIDARG;
  499. goto Cleanup;
  500. }
  501. // Download the .LPK to a locally cached file
  502. fpURLDownloadToCacheFileW = GetProcAddress(hURLMon, SZ_URLDOWNLOADTOCACHEFILE);
  503. if (!fpURLDownloadToCacheFileW)
  504. {
  505. hr = GetWin32Hresult();
  506. goto Cleanup;
  507. }
  508. //
  509. // Get the service provider from our site
  510. //
  511. IServiceProvider * pServiceProvider;
  512. hr = GetSite(IID_IServiceProvider, (void**)&pServiceProvider);
  513. if (!SUCCEEDED(hr))
  514. goto Cleanup;
  515. //
  516. // Get an IBindHost from the service provider
  517. //
  518. IBindHost *pBindHost;
  519. hr = pServiceProvider->QueryService(
  520. SID_IBindHost, IID_IBindHost, (void**)&pBindHost);
  521. pServiceProvider->Release();
  522. if (!SUCCEEDED(hr))
  523. goto Cleanup;
  524. //
  525. // Now create a full moniker
  526. //
  527. IMoniker *pMoniker;
  528. hr = pBindHost->CreateMoniker(V_BSTR(&var), NULL, &pMoniker,0);
  529. pBindHost->Release();
  530. if (!SUCCEEDED(hr))
  531. goto Cleanup;
  532. //
  533. // Create a bind context
  534. //
  535. IBindCtx * pBindCtx;
  536. hr = CreateBindCtx(0, &pBindCtx);
  537. if (!SUCCEEDED(hr))
  538. {
  539. pMoniker->Release();
  540. goto Cleanup;
  541. }
  542. //
  543. // Extract display name
  544. //
  545. LPOLESTR wszFullLPKPath;
  546. hr = pMoniker->GetDisplayName(pBindCtx, NULL, &wszFullLPKPath);
  547. pMoniker->Release();
  548. pBindCtx->Release();
  549. if (!SUCCEEDED(hr))
  550. goto Cleanup;
  551. hr = (*((URLDOWNLOADTOCACHEFILE)fpURLDownloadToCacheFileW))(
  552. _pUnkOuter,
  553. wszFullLPKPath,
  554. szCachedFilename,
  555. URLOSTRM_GETNEWESTVERSION,
  556. 0, NULL);
  557. CoTaskMemFree(wszFullLPKPath);
  558. if (hr)
  559. goto Cleanup;
  560. // Open a stream on the file and load from the stream
  561. hr = fstm.Init(szCachedFilename, GENERIC_READ);
  562. if (!hr)
  563. {
  564. CBufferedStream mstm(&fstm);
  565. ULONG cbSize;
  566. hr = mstm.SetBufferSize(BUFFER_SIZE);
  567. if (hr)
  568. goto Cleanup;
  569. Verify(SUCCEEDED(fstm.GetFileSize(&cbSize)));
  570. hr = Load(&mstm, cbSize);
  571. }
  572. }
  573. Cleanup:
  574. _fLoaded = TRUE;
  575. ::VariantClear(&var);
  576. if (hURLMon)
  577. {
  578. ::FreeLibrary(hURLMon);
  579. }
  580. return hr;
  581. }
  582. //+----------------------------------------------------------------------------
  583. //
  584. // Member: Save
  585. //
  586. // Synopsis:
  587. //
  588. // Arguments:
  589. //
  590. // Returns:
  591. //
  592. //-----------------------------------------------------------------------------
  593. STDMETHODIMP
  594. CLicenseManager::Save(
  595. IPropertyBag * pPropBag,
  596. BOOL fClearDirty,
  597. BOOL fSaveAllProperties)
  598. {
  599. UNREF(pPropBag);
  600. UNREF(fClearDirty);
  601. UNREF(fSaveAllProperties);
  602. return E_NOTIMPL;
  603. }