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.

662 lines
17 KiB

  1. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2. Microsoft Windows, Copyright (C) Microsoft Corporation, 2000
  3. File: ExtendedProperty.cpp
  4. Content: Implementation of CExtendedProperty.
  5. History: 06-15-2001 dsie created
  6. ------------------------------------------------------------------------------*/
  7. #include "StdAfx.h"
  8. #include "CAPICOM.h"
  9. #include "ExtendedProperty.h"
  10. #include "Convert.h"
  11. #include "Settings.h"
  12. ////////////////////////////////////////////////////////////////////////////////
  13. //
  14. // Exported functions.
  15. //
  16. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  17. Function : CreateExtendedPropertyObject
  18. Synopsis : Create an IExtendedProperty object.
  19. Parameter: PCCERT_CONTEXT pCertContext - Pointer to CERT_CONTEXT to be used
  20. to initialize the IExtendedProperty
  21. object.
  22. DWORD dwPropId - Property ID.
  23. BOOL bReadOnly - TRUE for read-only, else FALSE.
  24. IExtendedProperty ** ppIExtendedProperty - Pointer to pointer
  25. IExtendedProperty
  26. object.
  27. Remark :
  28. ------------------------------------------------------------------------------*/
  29. HRESULT CreateExtendedPropertyObject (PCCERT_CONTEXT pCertContext,
  30. DWORD dwPropId,
  31. BOOL bReadOnly,
  32. IExtendedProperty ** ppIExtendedProperty)
  33. {
  34. HRESULT hr = S_OK;
  35. CComObject<CExtendedProperty> * pCExtendedProperty = NULL;
  36. DebugTrace("Entering CreateExtendedPropertyObject().\n", hr);
  37. //
  38. // Sanity check.
  39. //
  40. ATLASSERT(pCertContext);
  41. ATLASSERT(ppIExtendedProperty);
  42. try
  43. {
  44. //
  45. // Create the object. Note that the ref count will still be 0
  46. // after the object is created.
  47. //
  48. if (FAILED(hr = CComObject<CExtendedProperty>::CreateInstance(&pCExtendedProperty)))
  49. {
  50. DebugTrace("Error [%#x]: CComObject<CExtendedProperty>::CreateInstance() failed.\n", hr);
  51. goto ErrorExit;
  52. }
  53. //
  54. // Initialize object.
  55. //
  56. if (FAILED(hr = pCExtendedProperty->Init(pCertContext, dwPropId, bReadOnly)))
  57. {
  58. DebugTrace("Error [%#x]: pCExtendedProperty->Init() failed.\n", hr);
  59. goto ErrorExit;
  60. }
  61. //
  62. // Return interface pointer to caller.
  63. //
  64. if (FAILED(hr = pCExtendedProperty->QueryInterface(ppIExtendedProperty)))
  65. {
  66. DebugTrace("Error [%#x]: pCExtendedProperty->QueryInterface() failed.\n", hr);
  67. goto ErrorExit;
  68. }
  69. }
  70. catch(...)
  71. {
  72. hr = E_POINTER;
  73. DebugTrace("Exception: invalid parameter.\n");
  74. goto ErrorExit;
  75. }
  76. CommonExit:
  77. DebugTrace("Leaving CreateExtendedPropertyObject().\n");
  78. return hr;
  79. ErrorExit:
  80. //
  81. // Sanity check.
  82. //
  83. ATLASSERT(FAILED(hr));
  84. if (pCExtendedProperty)
  85. {
  86. delete pCExtendedProperty;
  87. }
  88. goto CommonExit;
  89. }
  90. ////////////////////////////////////////////////////////////////////////////////
  91. //
  92. // CExtendedProperty
  93. //
  94. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  95. Function : CExtendedProperty::get_PropID
  96. Synopsis : Return the prop ID.
  97. Parameter: CAPICOM_PROPID * pVal - Pointer to CAPICOM_PROPID to receive ID.
  98. Remark :
  99. ------------------------------------------------------------------------------*/
  100. STDMETHODIMP CExtendedProperty:: get_PropID (CAPICOM_PROPID * pVal)
  101. {
  102. HRESULT hr = S_OK;
  103. DebugTrace("Entering CExtendedProperty::get_PropID().\n");
  104. try
  105. {
  106. //
  107. // Lock access to this object.
  108. //
  109. m_Lock.Lock();
  110. //
  111. // Check parameters.
  112. //
  113. if (NULL == pVal)
  114. {
  115. hr = E_INVALIDARG;
  116. DebugTrace("Error [%#x]: Parameter pVal is NULL.\n", hr);
  117. goto ErrorExit;
  118. }
  119. //
  120. // Return result.
  121. //
  122. *pVal = (CAPICOM_PROPID) m_dwPropId;
  123. }
  124. catch(...)
  125. {
  126. hr = E_POINTER;
  127. DebugTrace("Exception: invalid parameter.\n");
  128. goto ErrorExit;
  129. }
  130. UnlockExit:
  131. //
  132. // Unlock access to this object.
  133. //
  134. m_Lock.Unlock();
  135. DebugTrace("Leaving CExtendedProperty::get_PropID().\n");
  136. return hr;
  137. ErrorExit:
  138. //
  139. // Sanity check.
  140. //
  141. ATLASSERT(FAILED(hr));
  142. ReportError(hr);
  143. goto UnlockExit;
  144. }
  145. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  146. Function : CExtendedProperty::put_PropID
  147. Synopsis : Set prop ID.
  148. Parameter: CAPICOM_PROPID newVal - new prop ID.
  149. Remark :
  150. ------------------------------------------------------------------------------*/
  151. STDMETHODIMP CExtendedProperty::put_PropID (CAPICOM_PROPID newVal)
  152. {
  153. HRESULT hr = S_OK;
  154. DebugTrace("Entering CExtendedProperty::put_PropID().\n");
  155. try
  156. {
  157. //
  158. // Lock access to this object.
  159. //
  160. m_Lock.Lock();
  161. //
  162. // Make sure it is not read-only.
  163. //
  164. if (m_bReadOnly)
  165. {
  166. hr = CAPICOM_E_NOT_ALLOWED;
  167. DebugTrace("Error [%#x]: Writing read-only PropID property is not allowed.\n", hr);
  168. goto ErrorExit;
  169. }
  170. //
  171. // Don't allow ID change if this is part of a cert. User need to delete
  172. // and then add to the ExtendedProperties collection.
  173. //
  174. if (m_pCertContext)
  175. {
  176. hr = CAPICOM_E_NOT_ALLOWED;
  177. DebugTrace("Error [%#x]: not allowed to change prop ID when the property is attached to a cert.\n", hr);
  178. goto ErrorExit;
  179. }
  180. //
  181. // Free previous blob if available.
  182. //
  183. if (m_DataBlob.pbData)
  184. {
  185. ::CoTaskMemFree((LPVOID) m_DataBlob.pbData);
  186. }
  187. //
  188. // Store value.
  189. //
  190. m_dwPropId = newVal;
  191. m_DataBlob.cbData = 0;
  192. m_DataBlob.pbData = NULL;
  193. }
  194. catch(...)
  195. {
  196. hr = E_POINTER;
  197. DebugTrace("Exception: invalid parameter.\n");
  198. goto ErrorExit;
  199. }
  200. UnlockExit:
  201. //
  202. // Unlock access to this object.
  203. //
  204. m_Lock.Unlock();
  205. DebugTrace("Leaving CExtendedProperty::put_PropID().\n");
  206. return hr;
  207. ErrorExit:
  208. //
  209. // Sanity check.
  210. //
  211. ATLASSERT(FAILED(hr));
  212. ReportError(hr);
  213. goto UnlockExit;
  214. }
  215. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  216. Function : CExtendedProperty::get_Value
  217. Synopsis : Return the ExtendedProperty data.
  218. Parameter: CAPICOM_ENCODING_TYPE EncodingType - Encoding type.
  219. BSTR * pVal - Pointer to BSTR to receive the data.
  220. Remark :
  221. ------------------------------------------------------------------------------*/
  222. STDMETHODIMP CExtendedProperty::get_Value (CAPICOM_ENCODING_TYPE EncodingType,
  223. BSTR * pVal)
  224. {
  225. HRESULT hr = S_OK;
  226. DebugTrace("Entering CExtendedProperty::get_Value().\n");
  227. try
  228. {
  229. //
  230. // Lock access to this object.
  231. //
  232. m_Lock.Lock();
  233. //
  234. // Check parameters.
  235. //
  236. if (NULL == pVal)
  237. {
  238. hr = E_INVALIDARG;
  239. DebugTrace("Error [%#x]: Parameter pVal is NULL.\n", hr);
  240. goto ErrorExit;
  241. }
  242. //
  243. // Make sure Prop ID is valid.
  244. //
  245. if (CAPICOM_PROPID_UNKNOWN == m_dwPropId)
  246. {
  247. hr = CAPICOM_E_PROPERTY_NOT_INITIALIZED;
  248. DebugTrace("Error [%#x]: m_dwPropId member is not initialized.\n", hr);
  249. goto ErrorExit;
  250. }
  251. //
  252. // Return result.
  253. //
  254. if (FAILED(hr = ::ExportData(m_DataBlob, EncodingType, pVal)))
  255. {
  256. DebugTrace("Error [%#x]: ExportData() failed.\n", hr);
  257. goto ErrorExit;
  258. }
  259. }
  260. catch(...)
  261. {
  262. hr = E_POINTER;
  263. DebugTrace("Exception: invalid parameter.\n");
  264. goto ErrorExit;
  265. }
  266. UnlockExit:
  267. //
  268. // Unlock access to this object.
  269. //
  270. m_Lock.Unlock();
  271. DebugTrace("Leaving CExtendedProperty::get_Value().\n");
  272. return hr;
  273. ErrorExit:
  274. //
  275. // Sanity check.
  276. //
  277. ATLASSERT(FAILED(hr));
  278. ReportError(hr);
  279. goto UnlockExit;
  280. }
  281. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  282. Function : CExtendedProperty::put_Value
  283. Synopsis : Set the ExtendedProperty data.
  284. Parameter: CAPICOM_ENCODING_TYPE EncodingType - Encoding type.
  285. BSTR newVal - BSTR containing the encoded property.
  286. Remark :
  287. ------------------------------------------------------------------------------*/
  288. STDMETHODIMP CExtendedProperty::put_Value (CAPICOM_ENCODING_TYPE EncodingType,
  289. BSTR newVal)
  290. {
  291. HRESULT hr = S_OK;
  292. DATA_BLOB DataBlob = {0, NULL};
  293. DebugTrace("Entering CExtendedProperty::put_Value().\n");
  294. try
  295. {
  296. //
  297. // Lock access to this object.
  298. //
  299. m_Lock.Lock();
  300. //
  301. // Make sure Prop ID is valid.
  302. //
  303. if (CAPICOM_PROPID_UNKNOWN == m_dwPropId)
  304. {
  305. hr = CAPICOM_E_PROPERTY_NOT_INITIALIZED;
  306. DebugTrace("Error [%#x]: m_dwPropId member is not initialized.\n", hr);
  307. goto ErrorExit;
  308. }
  309. //
  310. // Make sure it is not read-only.
  311. //
  312. if (m_bReadOnly)
  313. {
  314. hr = CAPICOM_E_NOT_ALLOWED;
  315. DebugTrace("Error [%#x]: Writing read-only PropID property is not allowed.\n", hr);
  316. goto ErrorExit;
  317. }
  318. //
  319. // Import non-NULL data.
  320. //
  321. if (0 < ::SysStringByteLen(newVal))
  322. {
  323. if (FAILED(hr = ::ImportData(newVal, EncodingType, &DataBlob)))
  324. {
  325. DebugTrace("Error [%#x]: ImportData() failed.\n", hr);
  326. goto ErrorExit;
  327. }
  328. }
  329. //
  330. // Write through to cert, if attached.
  331. //
  332. if (m_pCertContext)
  333. {
  334. LPVOID pvData;
  335. //
  336. // Some properties point to the data directly.
  337. //
  338. if (m_dwPropId == CAPICOM_PROPID_KEY_CONTEXT ||
  339. m_dwPropId == CAPICOM_PROPID_KEY_PROV_HANDLE ||
  340. m_dwPropId == CAPICOM_PROPID_KEY_PROV_INFO ||
  341. m_dwPropId == CAPICOM_PROPID_KEY_SPEC ||
  342. m_dwPropId == CAPICOM_PROPID_DATE_STAMP)
  343. {
  344. pvData = DataBlob.pbData;
  345. }
  346. else if ((m_dwPropId == CAPICOM_PROPID_FRIENDLY_NAME) &&
  347. (L'\0' != newVal[::SysStringLen(newVal) - 1]))
  348. {
  349. LPBYTE pbNewVal = NULL;
  350. if (NULL == (pbNewVal = (LPBYTE) ::CoTaskMemAlloc(DataBlob.cbData + sizeof(WCHAR))))
  351. {
  352. hr = E_OUTOFMEMORY;
  353. DebugTrace("Error [%#x]: CoTaskMemAlloc() failed.\n", hr);
  354. goto ErrorExit;
  355. }
  356. ::ZeroMemory(pbNewVal, DataBlob.cbData + sizeof(WCHAR));
  357. ::CopyMemory(pbNewVal, DataBlob.pbData, DataBlob.cbData);
  358. ::CoTaskMemFree(DataBlob.pbData);
  359. DataBlob.cbData += sizeof(WCHAR);
  360. DataBlob.pbData = pbNewVal;
  361. pvData = &DataBlob;
  362. }
  363. else
  364. {
  365. pvData = &DataBlob;
  366. }
  367. if (!::CertSetCertificateContextProperty(m_pCertContext,
  368. m_dwPropId,
  369. 0,
  370. pvData))
  371. {
  372. hr = HRESULT_FROM_WIN32(::GetLastError());
  373. DebugTrace("Error [%#x]: CertSetCertificateContextProperty() failed.\n", hr);
  374. goto ErrorExit;
  375. }
  376. }
  377. //
  378. // Set it.
  379. //
  380. if (m_DataBlob.pbData)
  381. {
  382. ::CoTaskMemFree(m_DataBlob.pbData);
  383. }
  384. m_DataBlob = DataBlob;
  385. }
  386. catch(...)
  387. {
  388. hr = E_POINTER;
  389. DebugTrace("Exception: invalid parameter.\n");
  390. goto ErrorExit;
  391. }
  392. UnlockExit:
  393. //
  394. // Unlock access to this object.
  395. //
  396. m_Lock.Unlock();
  397. DebugTrace("Leaving CExtendedProperty::put_Value().\n");
  398. return hr;
  399. ErrorExit:
  400. //
  401. // Sanity check.
  402. //
  403. ATLASSERT(FAILED(hr));
  404. //
  405. // Free resources.
  406. //
  407. if (DataBlob.pbData)
  408. {
  409. ::CoTaskMemFree(DataBlob.pbData);
  410. }
  411. ReportError(hr);
  412. goto UnlockExit;
  413. }
  414. ////////////////////////////////////////////////////////////////////////////////
  415. //
  416. // Private methods.
  417. //
  418. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  419. Function : CExtendedProperty::Init
  420. Synopsis : Initialize the object.
  421. Parameter: PCCERT_CONTEXT pCertContext - Pointer to CERT_CONTEXT to be used
  422. to initialize the IExtendedProperty
  423. object.
  424. DWORD dwPropId - Property ID.
  425. BOOL bReadOnly - TRUE for read-only, else FALSE.
  426. Remark : This method is not part of the COM interface (it is a normal C++
  427. member function). We need it to initialize the object created
  428. internally by us with CERT_ExtendedProperty.
  429. Since it is only a normal C++ member function, this function can
  430. only be called from a C++ class pointer, not an interface pointer.
  431. ------------------------------------------------------------------------------*/
  432. STDMETHODIMP CExtendedProperty::Init (PCCERT_CONTEXT pCertContext,
  433. DWORD dwPropId,
  434. BOOL bReadOnly)
  435. {
  436. HRESULT hr = S_OK;
  437. DATA_BLOB DataBlob = {0, NULL};
  438. PCCERT_CONTEXT pCertContext2 = NULL;
  439. DebugTrace("Entering CExtendedProperty::Init().\n");
  440. //
  441. // Sanity check.
  442. //
  443. ATLASSERT(pCertContext);
  444. ATLASSERT(CAPICOM_PROPID_UNKNOWN != dwPropId);
  445. //
  446. // Duplicate the handle.
  447. //
  448. if (!(pCertContext2 = ::CertDuplicateCertificateContext(pCertContext)))
  449. {
  450. hr = HRESULT_FROM_WIN32(::GetLastError());
  451. DebugTrace("Error [%#x]: CertDuplicateCertificateContext() failed.\n", hr);
  452. goto ErrorExit;
  453. }
  454. //
  455. // Get content of property.
  456. //
  457. if (::CertGetCertificateContextProperty(pCertContext,
  458. dwPropId,
  459. NULL,
  460. &DataBlob.cbData))
  461. {
  462. if (NULL == (DataBlob.pbData = (LPBYTE) ::CoTaskMemAlloc(DataBlob.cbData)))
  463. {
  464. hr = E_OUTOFMEMORY;
  465. DebugTrace("Error: out of memory.\n", hr);
  466. goto ErrorExit;
  467. }
  468. if (!::CertGetCertificateContextProperty(pCertContext,
  469. dwPropId,
  470. DataBlob.pbData,
  471. &DataBlob.cbData))
  472. {
  473. hr = HRESULT_FROM_WIN32(::GetLastError());
  474. DebugTrace("Error [%#x]: CertGetCertificateContextProperty() failed.\n", hr);
  475. goto ErrorExit;
  476. }
  477. }
  478. //
  479. // Set states.
  480. //
  481. m_dwPropId = dwPropId;
  482. m_bReadOnly = bReadOnly;
  483. m_DataBlob = DataBlob;
  484. m_pCertContext = pCertContext2;
  485. CommonExit:
  486. DebugTrace("Leaving CExtendedProperty::Init().\n");
  487. return hr;
  488. ErrorExit:
  489. //
  490. // Sanity check.
  491. //
  492. ATLASSERT(FAILED(hr));
  493. //
  494. // Free resources.
  495. //
  496. if (pCertContext2)
  497. {
  498. ::CertFreeCertificateContext(pCertContext2);
  499. }
  500. if (DataBlob.pbData)
  501. {
  502. ::CoTaskMemFree((LPVOID) DataBlob.pbData);
  503. }
  504. goto CommonExit;
  505. }