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.

636 lines
18 KiB

  1. /********************************************************************
  2. Copyright (c) 1999-2001 Microsoft Corporation
  3. Module Name:
  4. Package.cpp
  5. Abstract:
  6. Cryptography stuff for hcupdate packages
  7. Revision History:
  8. Ghim-Sim Chua (gschua) 07/07/99
  9. - created
  10. Davide Massarenti (dmassare) 03/24/2001
  11. - moved into database code.
  12. ********************************************************************/
  13. #include "stdafx.h"
  14. #include <wintrust.h>
  15. #include <wincrypt.h>
  16. #include <sipbase.h>
  17. #include <softpub.h>
  18. #include <strsafe.h>
  19. ////////////////////////////////////////////////////////////////////////////////
  20. static void local_GetDNInfo( PCCERT_CONTEXT pCC ,
  21. LPCSTR field ,
  22. LPCWSTR fieldName ,
  23. MPC::wstring& strBuf ,
  24. MPC::wstring* strPlainName = NULL)
  25. {
  26. WCHAR rgTmp[512];
  27. if(strBuf.length()) strBuf += L",";
  28. strBuf += fieldName;
  29. ::CertGetNameStringW( pCC, CERT_NAME_ATTR_TYPE, 0, (void*)field, rgTmp, MAXSTRLEN(rgTmp) ); rgTmp[MAXSTRLEN(rgTmp)] = 0;
  30. if(strPlainName) *strPlainName = rgTmp;
  31. strBuf += rgTmp;
  32. }
  33. ////////////////////////////////////////////////////////////////////////////////
  34. Taxonomy::Package::Package()
  35. {
  36. // MPC::wstring m_strFileName;
  37. m_fTemporary = false; // bool m_fTemporary;
  38. m_lSequence = 0; // long m_lSequence;
  39. m_dwCRC = 0; // DWORD m_dwCRC;
  40. //
  41. // MPC::wstring m_strSKU;
  42. // MPC::wstring m_strLanguage;
  43. // MPC::wstring m_strVendorID;
  44. // MPC::wstring m_strVendorName;
  45. // MPC::wstring m_strProductID;
  46. // MPC::wstring m_strVersion;
  47. //
  48. m_fMicrosoft = false; // bool m_fMicrosoft;
  49. m_fBuiltin = false; // bool m_fBuiltin;
  50. }
  51. Taxonomy::Package::~Package()
  52. {
  53. if(m_fTemporary) Remove( Logger() );
  54. }
  55. HRESULT Taxonomy::operator>>( /*[in]*/ MPC::Serializer& stream, /*[out]*/ Taxonomy::Package& val )
  56. {
  57. HRESULT hr;
  58. if(SUCCEEDED(hr = (stream >> val.m_lSequence )) &&
  59. SUCCEEDED(hr = (stream >> val.m_dwCRC )) &&
  60. SUCCEEDED(hr = (stream >> val.m_strSKU )) &&
  61. SUCCEEDED(hr = (stream >> val.m_strLanguage )) &&
  62. SUCCEEDED(hr = (stream >> val.m_strVendorID )) &&
  63. SUCCEEDED(hr = (stream >> val.m_strVendorName)) &&
  64. SUCCEEDED(hr = (stream >> val.m_strProductID )) &&
  65. SUCCEEDED(hr = (stream >> val.m_strVersion )) &&
  66. SUCCEEDED(hr = (stream >> val.m_fMicrosoft )) &&
  67. SUCCEEDED(hr = (stream >> val.m_fBuiltin )) )
  68. {
  69. hr = S_OK;
  70. }
  71. return hr;
  72. }
  73. HRESULT Taxonomy::operator<<( /*[in]*/ MPC::Serializer& stream, /*[in] */ const Taxonomy::Package& val )
  74. {
  75. HRESULT hr;
  76. if(SUCCEEDED(hr = (stream << val.m_lSequence )) &&
  77. SUCCEEDED(hr = (stream << val.m_dwCRC )) &&
  78. SUCCEEDED(hr = (stream << val.m_strSKU )) &&
  79. SUCCEEDED(hr = (stream << val.m_strLanguage )) &&
  80. SUCCEEDED(hr = (stream << val.m_strVendorID )) &&
  81. SUCCEEDED(hr = (stream << val.m_strVendorName)) &&
  82. SUCCEEDED(hr = (stream << val.m_strProductID )) &&
  83. SUCCEEDED(hr = (stream << val.m_strVersion )) &&
  84. SUCCEEDED(hr = (stream << val.m_fMicrosoft )) &&
  85. SUCCEEDED(hr = (stream << val.m_fBuiltin )) )
  86. {
  87. hr = S_OK;
  88. }
  89. return hr;
  90. }
  91. ////////////////////
  92. static int local_nCompareVersion( /*[in]*/ DWORD dwVer1, /*[in]*/ DWORD dwBuild1 ,
  93. /*[in]*/ DWORD dwVer2, /*[in]*/ DWORD dwBuild2 )
  94. {
  95. if(dwVer1 > dwVer2) return 1;
  96. if(dwVer1 < dwVer2) return -1;
  97. // dwVer1 == dwVer2
  98. if(dwBuild1 > dwBuild2) return 1;
  99. if(dwBuild1 < dwBuild2) return -1;
  100. return 0;
  101. }
  102. static bool local_fConvertDotVersionStrToDwords( /*[in ]*/ const MPC::wstring& strVer ,
  103. /*[out]*/ DWORD& dwVer ,
  104. /*[out]*/ DWORD& dwBuild )
  105. {
  106. unsigned int iVerFields[4];
  107. if(swscanf( strVer.c_str(), L"%u.%u.%u.%u", &iVerFields[0], &iVerFields[1], &iVerFields[2], &iVerFields[3] ) == 4)
  108. {
  109. dwVer = (iVerFields[0] << 16) + iVerFields[1];
  110. dwBuild = (iVerFields[2] << 16) + iVerFields[3];
  111. return true;
  112. }
  113. return false;
  114. }
  115. int Taxonomy::Package::Compare( /*[in]*/ const Package& pkg, /*[in]*/ DWORD dwMode ) const
  116. {
  117. int iCmp = 0;
  118. DWORD dwVer1;
  119. DWORD dwVer2;
  120. DWORD dwBuild1;
  121. DWORD dwBuild2;
  122. if(dwMode & c_Cmp_SKU)
  123. {
  124. iCmp = MPC::StrICmp( m_strSKU , pkg.m_strSKU ); if(iCmp) return iCmp;
  125. iCmp = MPC::StrICmp( m_strLanguage , pkg.m_strLanguage ); if(iCmp) return iCmp;
  126. }
  127. if(dwMode & c_Cmp_ID)
  128. {
  129. iCmp = MPC::StrICmp( m_strVendorID , pkg.m_strVendorID ); if(iCmp) return iCmp;
  130. iCmp = MPC::StrICmp( m_strProductID, pkg.m_strProductID ); if(iCmp) return iCmp;
  131. }
  132. if(dwMode & c_Cmp_VERSION)
  133. {
  134. if(local_fConvertDotVersionStrToDwords( m_strVersion, dwVer1, dwBuild1 ) &&
  135. local_fConvertDotVersionStrToDwords( pkg.m_strVersion, dwVer2, dwBuild2 ) )
  136. {
  137. iCmp = local_nCompareVersion( dwVer1, dwBuild1, dwVer2, dwBuild2 );
  138. }
  139. else
  140. {
  141. iCmp = MPC::StrICmp( m_strVersion, pkg.m_strVersion );
  142. }
  143. }
  144. return iCmp;
  145. }
  146. ////////////////////////////////////////////////////////////////////////////////
  147. HRESULT Taxonomy::Package::GenerateFileName()
  148. {
  149. HRESULT hr;
  150. if(m_strFileName.size() == 0)
  151. {
  152. WCHAR rgBuf[MAX_PATH]; StringCchPrintfW( rgBuf, ARRAYSIZE(rgBuf), L"%s\\package_%ld.cab", HC_ROOT_HELPSVC_PKGSTORE, m_lSequence ); rgBuf[MAXSTRLEN(rgBuf)] = 0;
  153. if(FAILED(hr = MPC::SubstituteEnvVariables( m_strFileName = rgBuf ))) return hr;
  154. }
  155. return S_OK;
  156. }
  157. HRESULT Taxonomy::Package::Import( /*[in]*/ Logger& log ,
  158. /*[in]*/ LPCWSTR szFile ,
  159. /*[in]*/ long lSequence ,
  160. /*[in]*/ MPC::Impersonation* imp )
  161. {
  162. __HCP_FUNC_ENTRY( "Taxonomy::Package::Import" );
  163. HRESULT hr;
  164. m_fTemporary = true;
  165. m_lSequence = lSequence;
  166. __MPC_EXIT_IF_METHOD_FAILS(hr, GenerateFileName());
  167. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::DeleteFile( m_strFileName ));
  168. if(imp)
  169. {
  170. __MPC_EXIT_IF_METHOD_FAILS(hr, SVC::CopyFileWhileImpersonating( szFile, m_strFileName.c_str(), *imp, /*fImpersonateForSource*/true ));
  171. }
  172. else
  173. {
  174. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::CopyFile( szFile, m_strFileName.c_str() ));
  175. }
  176. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::ComputeCRC( m_dwCRC, m_strFileName.c_str() ));
  177. ::SetFileAttributesW( m_strFileName.c_str(), FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM );
  178. log.WriteLog( -1, L"\nImported package %s into package store\n\n", szFile );
  179. hr = S_OK;
  180. __HCP_FUNC_CLEANUP;
  181. if(FAILED(hr))
  182. {
  183. log.WriteLog( hr, L"Failed to copy %s into package store", szFile );
  184. }
  185. __HCP_FUNC_EXIT(hr);
  186. }
  187. ////////////////////////////////////////////////////////////////////////////////
  188. static HRESULT local_GetSignerInfo( /*[in]*/ HCRYPTMSG hMsg, /*[in]*/ DWORD index, /*[in/out]*/ BYTE*& pSignerInfo )
  189. {
  190. __HCP_FUNC_ENTRY( "local_GetSignerInfo" );
  191. HRESULT hr;
  192. BYTE* pbEncodedSigner = NULL;
  193. DWORD cbEncodedSigner = 0;
  194. DWORD cbSignerInfo = 0;
  195. delete [] pSignerInfo; pSignerInfo = NULL;
  196. //
  197. // get the encoded signer BLOB
  198. //
  199. ::CryptMsgGetParam( hMsg, CMSG_ENCODED_SIGNER, index, NULL, &cbEncodedSigner );
  200. __MPC_EXIT_IF_ALLOC_FAILS(hr, pbEncodedSigner, new BYTE[cbEncodedSigner]);
  201. __MPC_EXIT_IF_CALL_RETURNS_FALSE(hr, ::CryptMsgGetParam( hMsg, CMSG_ENCODED_SIGNER, index, pbEncodedSigner, &cbEncodedSigner ));
  202. //
  203. // decode the EncodedSigner info
  204. //
  205. ::CryptDecodeObject( PKCS_7_ASN_ENCODING|CRYPT_ASN_ENCODING, PKCS7_SIGNER_INFO, pbEncodedSigner, cbEncodedSigner, 0, NULL, &cbSignerInfo );
  206. __MPC_EXIT_IF_ALLOC_FAILS(hr, pSignerInfo, new BYTE[cbSignerInfo]);
  207. __MPC_EXIT_IF_CALL_RETURNS_FALSE(hr, ::CryptDecodeObject( PKCS_7_ASN_ENCODING|CRYPT_ASN_ENCODING, PKCS7_SIGNER_INFO,
  208. pbEncodedSigner, cbEncodedSigner, 0, pSignerInfo, &cbSignerInfo ));
  209. hr = S_OK;
  210. __HCP_FUNC_CLEANUP;
  211. delete [] pbEncodedSigner;
  212. __HCP_FUNC_EXIT(hr);
  213. }
  214. HRESULT Taxonomy::Package::Authenticate( /*[in]*/ Logger& log )
  215. {
  216. __HCP_FUNC_ENTRY( "Taxonomy::Package::Authenticate" );
  217. HRESULT hr;
  218. if(m_fBuiltin == false)
  219. {
  220. __MPC_EXIT_IF_METHOD_FAILS(hr, GenerateFileName());
  221. //
  222. // First, verify the signature is valid.
  223. //
  224. {
  225. WINTRUST_DATA wtdWinTrust;
  226. WINTRUST_FILE_INFO wtfWinTrustFile;
  227. GUID c_guidPubSoftwareTrustProv = WINTRUST_ACTION_GENERIC_VERIFY_V2;
  228. //
  229. // set up wintrust file info struct
  230. //
  231. ::ZeroMemory( &wtfWinTrustFile, sizeof(wtfWinTrustFile) );
  232. wtfWinTrustFile.cbStruct = sizeof(wtfWinTrustFile);
  233. wtfWinTrustFile.pcwszFilePath = m_strFileName.c_str();
  234. wtfWinTrustFile.hFile = NULL;
  235. //
  236. // set up wintrust data struct
  237. //
  238. ::ZeroMemory( &wtdWinTrust, sizeof(wtdWinTrust) );
  239. wtdWinTrust.cbStruct = sizeof(wtdWinTrust);
  240. wtdWinTrust.dwUnionChoice = WTD_CHOICE_FILE;
  241. wtdWinTrust.pFile = &wtfWinTrustFile;
  242. wtdWinTrust.dwUIChoice = WTD_UI_NONE; // Whistler special : must always be silent otherwise won't come back
  243. // Verify the trust of the help package
  244. if(FAILED(hr = ::WinVerifyTrust( 0, &c_guidPubSoftwareTrustProv, &wtdWinTrust )))
  245. {
  246. LPCWSTR szError;
  247. switch(hr)
  248. {
  249. case TRUST_E_SUBJECT_NOT_TRUSTED : szError = L"subject not trusted" ; break;
  250. case TRUST_E_PROVIDER_UNKNOWN : szError = L"provider unknown" ; break;
  251. case TRUST_E_ACTION_UNKNOWN : szError = L"action unknown" ; break;
  252. case TRUST_E_SUBJECT_FORM_UNKNOWN: szError = L"subject form unknown"; break;
  253. default: szError = L"unknown" ; break;
  254. }
  255. __MPC_SET_ERROR_AND_EXIT(hr, log.WriteLog( hr, L"Help package cannot be trusted\nError WinVerifyTrust %s", szError ));
  256. }
  257. }
  258. //
  259. // Then open the certificate and extract the DN.
  260. //
  261. {
  262. HCRYPTMSG hMsg = NULL;
  263. m_strVendorID.erase();
  264. if(::CryptQueryObject( CERT_QUERY_OBJECT_FILE,
  265. m_strFileName.c_str(),
  266. CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
  267. CERT_QUERY_FORMAT_FLAG_BINARY ,
  268. 0, NULL, NULL, NULL, NULL, &hMsg, NULL ))
  269. {
  270. HCERTSTORE hCertStore;
  271. hCertStore = ::CertOpenStore( CERT_STORE_PROV_MSG, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, NULL, NULL, (const void *)hMsg );
  272. if(hCertStore)
  273. {
  274. BYTE* rgSignerInfo = NULL;
  275. if(SUCCEEDED(local_GetSignerInfo( hMsg, 0, rgSignerInfo )))
  276. {
  277. PCMSG_SIGNER_INFO pSignerInfo = (PCMSG_SIGNER_INFO)rgSignerInfo;
  278. CERT_INFO certInfo; ::ZeroMemory( &certInfo, sizeof(certInfo) );
  279. PCCERT_CONTEXT pCertContext;
  280. certInfo.SerialNumber = pSignerInfo->SerialNumber;
  281. certInfo.Issuer = pSignerInfo->Issuer;
  282. pCertContext = ::CertGetSubjectCertificateFromStore( hCertStore, X509_ASN_ENCODING, &certInfo );
  283. if(pCertContext)
  284. {
  285. local_GetDNInfo( pCertContext, szOID_COMMON_NAME , L"CN=", m_strVendorID, &m_strVendorName );
  286. local_GetDNInfo( pCertContext, szOID_LOCALITY_NAME , L"L=" , m_strVendorID );
  287. local_GetDNInfo( pCertContext, szOID_STATE_OR_PROVINCE_NAME, L"S=" , m_strVendorID );
  288. local_GetDNInfo( pCertContext, szOID_COUNTRY_NAME , L"C=" , m_strVendorID );
  289. ::CertFreeCertificateContext( pCertContext );
  290. }
  291. delete [] rgSignerInfo;
  292. }
  293. ::CertCloseStore( hCertStore, 0 );
  294. }
  295. ::CryptMsgClose( hMsg );
  296. }
  297. if(m_strVendorID.size() == 0)
  298. {
  299. __MPC_SET_ERROR_AND_EXIT(hr, log.WriteLog( HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED), L"Help package cannot be trusted: unable to extract signer\n" ));
  300. }
  301. //
  302. // Escape unsafe character in the CertID.
  303. //
  304. {
  305. LPWSTR szCertID = (LPWSTR)m_strVendorID.c_str();
  306. while(szCertID[0])
  307. {
  308. switch(szCertID[0])
  309. {
  310. case L'\\':
  311. case L'/':
  312. case L':':
  313. case L'*':
  314. case L'?':
  315. case L'"':
  316. case L'<':
  317. case L'>':
  318. case L'|':
  319. szCertID[0] = L'_';
  320. }
  321. szCertID++;
  322. }
  323. }
  324. }
  325. }
  326. else
  327. {
  328. m_strVendorID = HC_MICROSOFT_DN;
  329. MPC::LocalizeString( IDS_HELPSVC_SEMGR_OWNER, m_strVendorName );
  330. }
  331. m_fMicrosoft = (MPC::StrICmp( m_strVendorID, HC_MICROSOFT_DN ) == 0);
  332. //
  333. // Extract package info from packagedescription.xml
  334. //
  335. {
  336. MPC::XmlUtil xml;
  337. bool fFound;
  338. __MPC_EXIT_IF_METHOD_FAILS(hr, ExtractPkgDesc( log, xml ));
  339. __MPC_EXIT_IF_METHOD_FAILS(hr, xml.GetAttribute( L"PRODUCT", L"ID", m_strProductID, fFound ));
  340. if(fFound == false) // Set some default.
  341. {
  342. m_strProductID = L"<default>";
  343. }
  344. __MPC_EXIT_IF_METHOD_FAILS(hr, xml.GetAttribute( L"VERSION", L"VALUE", m_strVersion, fFound ));
  345. if(fFound == false) // Set some default.
  346. {
  347. m_strVersion = L"1.0.0.0";
  348. }
  349. if(m_fBuiltin == false) // System packages inherit SKU/Language from the database.
  350. {
  351. __MPC_EXIT_IF_METHOD_FAILS(hr, xml.GetAttribute( L"SKU", L"VALUE", m_strSKU, fFound ));
  352. if(fFound == false) // Not a valid package!!
  353. {
  354. __MPC_SET_ERROR_AND_EXIT(hr, log.WriteLog( E_INVALIDARG, L"Missing SKU element" ));
  355. }
  356. __MPC_EXIT_IF_METHOD_FAILS(hr, xml.GetAttribute( L"LANGUAGE", L"VALUE", m_strLanguage, fFound ));
  357. if(fFound == false) // Not a valid package!!
  358. {
  359. __MPC_SET_ERROR_AND_EXIT(hr, log.WriteLog( E_INVALIDARG, L"Missing LANGAUGE element" ));
  360. }
  361. }
  362. }
  363. if(m_lSequence >= 0)
  364. {
  365. m_fTemporary = false;
  366. }
  367. hr = S_OK;
  368. __HCP_FUNC_CLEANUP;
  369. __HCP_FUNC_EXIT(hr);
  370. }
  371. HRESULT Taxonomy::Package::Remove( /*[in]*/ Logger& log )
  372. {
  373. __HCP_FUNC_ENTRY( "Taxonomy::Package::Remove" );
  374. HRESULT hr;
  375. //
  376. // There's no private file for this package, nothing to do.
  377. //
  378. if(m_lSequence == -1)
  379. {
  380. __MPC_SET_ERROR_AND_EXIT(hr, S_OK);
  381. }
  382. if(m_lSequence)
  383. {
  384. if(SUCCEEDED(GenerateFileName()))
  385. {
  386. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::DeleteFile( m_strFileName ));
  387. log.WriteLog( -1, L"\nRemove package %s [%s] (Vendor: %s) from package store\n\n", m_strProductID.c_str(), m_strVersion.c_str(), m_strVendorID.c_str() );
  388. m_strFileName.erase();
  389. }
  390. }
  391. hr = S_OK;
  392. __HCP_FUNC_CLEANUP;
  393. __HCP_FUNC_EXIT(hr);
  394. }
  395. HRESULT Taxonomy::Package::ExtractFile( /*[in]*/ Logger& log ,
  396. /*[in]*/ LPCWSTR szFileDestination ,
  397. /*[in]*/ LPCWSTR szNameInCabinet )
  398. {
  399. __HCP_FUNC_ENTRY( "Taxonomy::Package::ExtractFile" );
  400. HRESULT hr;
  401. __MPC_EXIT_IF_METHOD_FAILS(hr, GenerateFileName());
  402. if(FAILED(hr = MPC::DecompressFromCabinet( m_strFileName.c_str(), szFileDestination, szNameInCabinet )))
  403. {
  404. __MPC_SET_ERROR_AND_EXIT(hr, log.WriteLog( hr, L"Error extracting %s from help package", szNameInCabinet ));
  405. }
  406. log.WriteLog( S_OK, L"Extracted %s from help package", szNameInCabinet );
  407. hr = S_OK;
  408. __HCP_FUNC_CLEANUP;
  409. __HCP_FUNC_EXIT(hr);
  410. }
  411. HRESULT Taxonomy::Package::ExtractXMLFile( /*[in]*/ Logger& log ,
  412. /*[in]*/ MPC::XmlUtil& xml ,
  413. /*[in]*/ LPCWSTR szTag ,
  414. /*[in]*/ LPCWSTR szNameInCabinet )
  415. {
  416. __HCP_FUNC_ENTRY( "Taxonomy::Package::ExtractXMLFile" );
  417. HRESULT hr;
  418. MPC::wstring strTmp;
  419. bool fLoaded;
  420. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::GetTemporaryFileName( strTmp ));
  421. __MPC_EXIT_IF_METHOD_FAILS(hr, ExtractFile( log, strTmp.c_str(), szNameInCabinet ));
  422. // load the XML with the root tag
  423. __MPC_EXIT_IF_METHOD_FAILS(hr, xml.Load( strTmp.c_str(), szTag, fLoaded ));
  424. if(fLoaded == false)
  425. {
  426. __MPC_SET_ERROR_AND_EXIT(hr, log.WriteLog( HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED), L"Error invalid XML in %s", szNameInCabinet ));
  427. }
  428. hr = S_OK;
  429. __HCP_FUNC_CLEANUP;
  430. (void)MPC::RemoveTemporaryFile( strTmp );
  431. __HCP_FUNC_EXIT(hr);
  432. }
  433. HRESULT Taxonomy::Package::ExtractPkgDesc( /*[in]*/ Logger& log ,
  434. /*[in]*/ MPC::XmlUtil& xml )
  435. {
  436. return ExtractXMLFile( log, xml, Taxonomy::Strings::s_tag_root_PackageDescription, Taxonomy::Strings::s_file_PackageDescription );
  437. }
  438. ////////////////////////////////////////////////////////////////////////////////
  439. ////////////////////////////////////////////////////////////////////////////////
  440. Taxonomy::ProcessedPackage::ProcessedPackage()
  441. {
  442. m_lSequence = 0; // long m_lSequence;
  443. m_fProcessed = false; // bool m_fProcessed;
  444. m_fDisabled = false; // bool m_fDisabled;
  445. }
  446. HRESULT Taxonomy::operator>>( /*[in]*/ MPC::Serializer& stream, /*[out]*/ Taxonomy::ProcessedPackage& val )
  447. {
  448. HRESULT hr;
  449. if(SUCCEEDED(hr = (stream >> val.m_lSequence )) &&
  450. SUCCEEDED(hr = (stream >> val.m_fProcessed)) &&
  451. SUCCEEDED(hr = (stream >> val.m_fDisabled )) )
  452. {
  453. hr = S_OK;
  454. }
  455. return hr;
  456. }
  457. HRESULT Taxonomy::operator<<( /*[in]*/ MPC::Serializer& stream, /*[in] */ const Taxonomy::ProcessedPackage& val )
  458. {
  459. HRESULT hr;
  460. if(SUCCEEDED(hr = (stream << val.m_lSequence )) &&
  461. SUCCEEDED(hr = (stream << val.m_fProcessed)) &&
  462. SUCCEEDED(hr = (stream << val.m_fDisabled )) )
  463. {
  464. hr = S_OK;
  465. }
  466. return hr;
  467. }