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.

2458 lines
71 KiB

  1. // IISCertObj.cpp : Implementation of CIISCertObj
  2. #include "stdafx.h"
  3. #include "common.h"
  4. #include "CertObj.h"
  5. #include "IISCertObj.h"
  6. #include "base64.h"
  7. #include "password.h"
  8. #include "certutil.h"
  9. #include "certobjlog.h"
  10. #include "certlog.h"
  11. #include "cryptpass.h"
  12. #include "process.h"
  13. #include <Sddl.h> // ConvertStringSecurityDescriptorToSecurityDescriptor
  14. #include <strsafe.h>
  15. #include <memory>
  16. #define TEMP_PASSWORD_LENGTH 50
  17. #define MAX_CERTIFICATE_BYTE_SIZE 500000
  18. // Checks a pointer which should be non NULL - can be used as follows.
  19. #define CheckPointer(p,ret){if((p)==NULL) return (ret);}
  20. //
  21. // HRESULT Foo(VOID *pBar)
  22. // {
  23. // CheckPointer(pBar,E_INVALIDARG)
  24. // }
  25. //
  26. // Or if the function returns a boolean
  27. //
  28. // BOOL Foo(VOID *pBar)
  29. // {
  30. // CheckPointer(pBar,FALSE)
  31. // }
  32. HRESULT ValidateBSTRIsntNULL(BSTR pbstrString)
  33. {
  34. if( !pbstrString ) return E_INVALIDARG;
  35. if( pbstrString[0] == 0 ) return E_INVALIDARG;
  36. return NOERROR;
  37. }
  38. void CIISCertObj::AddRemoteInterface(IIISCertObj * pAddMe)
  39. {
  40. // Increment count so we can release if we get unloaded...
  41. for (int i = 0; i < NUMBER_OF_AUTOMATION_INTERFACES; i++)
  42. {
  43. if (NULL == m_ppRemoteInterfaces[i])
  44. {
  45. m_ppRemoteInterfaces[i] = pAddMe;
  46. m_RemoteObjCoCreateCount++;
  47. break;
  48. }
  49. }
  50. return;
  51. }
  52. void CIISCertObj::DelRemoteInterface(IIISCertObj * pRemoveMe)
  53. {
  54. // Increment count so we can release if we get unloaded...
  55. for (int i = 0; i < NUMBER_OF_AUTOMATION_INTERFACES; i++)
  56. {
  57. if (pRemoveMe == m_ppRemoteInterfaces[i])
  58. {
  59. m_ppRemoteInterfaces[i] = NULL;
  60. m_RemoteObjCoCreateCount--;
  61. break;
  62. }
  63. }
  64. }
  65. void CIISCertObj::FreeRemoteInterfaces(void)
  66. {
  67. ASSERT(m_RemoteObjCoCreateCount == 0);
  68. if (m_RemoteObjCoCreateCount > 0)
  69. {
  70. // We should really never get here...
  71. // Uh, this should be 0, otherwise we probably
  72. // faild to Release a CoCreated interface..
  73. IISDebugOutput(_T("FreeRemoteInterfaces:WARNING:m_RemoteObjCoCreateCount=%d\r\n"),m_RemoteObjCoCreateCount);
  74. for (int i = 0; i < NUMBER_OF_AUTOMATION_INTERFACES; i++)
  75. {
  76. if (m_ppRemoteInterfaces[i])
  77. {
  78. if (m_ppRemoteInterfaces[i] != this)
  79. {
  80. m_ppRemoteInterfaces[i]->Release();
  81. m_ppRemoteInterfaces[i] = NULL;
  82. }
  83. }
  84. }
  85. delete[] m_ppRemoteInterfaces;
  86. m_RemoteObjCoCreateCount = 0;
  87. }
  88. }
  89. /////////////////////////////////////////////////////////////////////////////
  90. // CIISCertObj
  91. STDMETHODIMP CIISCertObj::put_ServerName(BSTR newVal)
  92. {
  93. IISDebugOutput(_T("put_ServerName\r\n"));
  94. HRESULT hr = S_OK;
  95. if(FAILED(hr = ValidateBSTRIsntNULL(newVal))){return hr;}
  96. // buffer overflow paranoia, make sure it's less than 255 characters long
  97. if (wcslen(newVal) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  98. m_ServerName = newVal;
  99. if (m_ServerName.m_str)
  100. {
  101. if (IsServerLocal(m_ServerName))
  102. {m_ServerName.Empty();}
  103. }
  104. else
  105. {
  106. // make sure it's empty
  107. m_ServerName.Empty();
  108. }
  109. return S_OK;
  110. }
  111. STDMETHODIMP CIISCertObj::put_UserName(BSTR newVal)
  112. {
  113. IISDebugOutput(_T("put_UserName\r\n"));
  114. HRESULT hr = S_OK;
  115. if(FAILED(hr = ValidateBSTRIsntNULL(newVal))){return hr;}
  116. // buffer overflow paranoia, make sure it's less than 255 characters long
  117. if (wcslen(newVal) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  118. m_UserName = newVal;
  119. return S_OK;
  120. }
  121. STDMETHODIMP CIISCertObj::put_UserPassword(BSTR newVal)
  122. {
  123. IISDebugOutput(_T("put_UserPassword\r\n"));
  124. HRESULT hr = S_OK;
  125. if(FAILED(hr = ValidateBSTRIsntNULL(newVal))){return hr;}
  126. // buffer overflow paranoia, make sure it's less than 255 characters long
  127. if (wcslen(newVal) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  128. // check if there was a previous value
  129. // if there was, then free it.
  130. if (m_lpwszUserPasswordEncrypted)
  131. {
  132. if (m_cbUserPasswordEncrypted > 0)
  133. {
  134. SecureZeroMemory(m_lpwszUserPasswordEncrypted,m_cbUserPasswordEncrypted);
  135. }
  136. LocalFree(m_lpwszUserPasswordEncrypted);
  137. }
  138. m_lpwszUserPasswordEncrypted = NULL;
  139. m_cbUserPasswordEncrypted = 0;
  140. // encrypt the password in memory (CryptProtectMemory)
  141. // this way if the process get's paged out to the swapfile,
  142. // the password won't be in clear text.
  143. if (FAILED(EncryptMemoryPassword(newVal,&m_lpwszUserPasswordEncrypted,&m_cbUserPasswordEncrypted)))
  144. {
  145. return E_FAIL;
  146. }
  147. return S_OK;
  148. }
  149. STDMETHODIMP CIISCertObj::put_InstanceName(BSTR newVal)
  150. {
  151. IISDebugOutput(_T("put_InstanceName\r\n"));
  152. HRESULT hr = S_OK;
  153. if(FAILED(hr = ValidateBSTRIsntNULL(newVal))){return hr;}
  154. // buffer overflow paranoia, make sure it's less than 255 characters long
  155. if (wcslen(newVal) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  156. m_InstanceName = newVal;
  157. return S_OK;
  158. }
  159. IIISCertObj *
  160. CIISCertObj::GetObject(HRESULT * phr)
  161. {
  162. IIISCertObj * pObj = NULL;
  163. if (NULL == phr){return NULL;}
  164. // decrypt before sending to this function...
  165. LPWSTR p = NULL;
  166. if (m_lpwszUserPasswordEncrypted)
  167. {
  168. *phr = DecryptMemoryPassword((LPWSTR) m_lpwszUserPasswordEncrypted,
  169. &p, m_cbUserPasswordEncrypted);
  170. if (FAILED(*phr))
  171. {
  172. return NULL;
  173. }
  174. pObj = GetObject(phr,m_ServerName,m_UserName,p);
  175. }
  176. else
  177. {
  178. pObj = GetObject(phr,m_ServerName,m_UserName,_T(""));
  179. }
  180. // clean up temporary password
  181. if (p)
  182. {
  183. // security percaution:Make sure to zero out memory that temporary password was used for.
  184. SecureZeroMemory(p, m_cbUserPasswordEncrypted);
  185. LocalFree(p);
  186. p = NULL;
  187. }
  188. return pObj;
  189. }
  190. IIISCertObj *
  191. CIISCertObj::GetObject(
  192. HRESULT * phr,
  193. CComBSTR csServerName,
  194. CComBSTR csUserName,
  195. CComBSTR csUserPassword
  196. )
  197. {
  198. IISDebugOutput(_T("GetObject\r\n"));
  199. IIISCertObj * pObjRemote = NULL;
  200. pObjRemote = this;
  201. if (0 == csServerName.Length())
  202. {
  203. // object is null, but it's the local machine, so just return back this pointer
  204. return this;
  205. }
  206. // There is a servername specified...
  207. // check if it's the local machine that was specified!
  208. if (IsServerLocal(csServerName))
  209. {
  210. return this;
  211. }
  212. else
  213. {
  214. // there is a remote servername specified
  215. // Check if we are already remoted.
  216. // cannot allow remotes to remote to other machines, this
  217. // could be some kind of security hole.
  218. if (AmIAlreadyRemoted())
  219. {
  220. IISDebugOutput(_T("GetObject:FAIL:Line=%d,Remote object cannot create another remote object\r\n"),__LINE__);
  221. *phr = HRESULT_FROM_WIN32(ERROR_REMOTE_SESSION_LIMIT_EXCEEDED);
  222. return NULL;
  223. }
  224. // let's see if the machine has the com object that we want....
  225. // we are using the user/name password that are in this object
  226. // so were probably on the local machine
  227. CComAuthInfo auth(csServerName,csUserName,csUserPassword);
  228. // RPC_C_AUTHN_LEVEL_DEFAULT 0
  229. // RPC_C_AUTHN_LEVEL_NONE 1
  230. // RPC_C_AUTHN_LEVEL_CONNECT 2
  231. // RPC_C_AUTHN_LEVEL_CALL 3
  232. // RPC_C_AUTHN_LEVEL_PKT 4
  233. // RPC_C_AUTHN_LEVEL_PKT_INTEGRITY 5
  234. // RPC_C_AUTHN_LEVEL_PKT_PRIVACY 6
  235. COSERVERINFO * pcsiName = auth.CreateServerInfoStruct(RPC_C_AUTHN_LEVEL_PKT_PRIVACY);
  236. MULTI_QI res[1] =
  237. {
  238. {&__uuidof(IIISCertObj), NULL, 0}
  239. };
  240. // Try to instantiante the object on the remote server...
  241. // with the supplied authentication info (pcsiName)
  242. //#define CLSCTX_SERVER (CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER)
  243. //#define CLSCTX_ALL (CLSCTX_INPROC_HANDLER | CLSCTX_SERVER)
  244. //if (NULL == pcsiName){IISDebugOutput(_T("CIISCertObj::GetObject:pcsiName=NULL failed!!!\n"));}
  245. // this one seems to work with surrogates..
  246. *phr = CoCreateInstanceEx(CLSID_IISCertObj,NULL,CLSCTX_LOCAL_SERVER,pcsiName,1,res);
  247. if (FAILED(*phr))
  248. {
  249. IISDebugOutput(_T("CIISCertObj::GetObject:CoCreateInstanceEx failed:0x%x, csServerName=%s,csUserName=%s\n"),
  250. *phr,(LPCTSTR) csServerName,(LPCTSTR) csUserName);
  251. goto GetObject_Exit;
  252. }
  253. // at this point we were able to instantiate the com object on the server (local or remote)
  254. pObjRemote = (IIISCertObj *)res[0].pItf;
  255. if (auth.UsesImpersonation())
  256. {
  257. *phr = auth.ApplyProxyBlanket(pObjRemote,RPC_C_AUTHN_LEVEL_PKT_PRIVACY);
  258. // There is a remote IUnknown Interface that lurks behind IUnknown.
  259. // If that is not set, then the Release call can return access denied.
  260. IUnknown * pUnk = NULL;
  261. if(FAILED(pObjRemote->QueryInterface(IID_IUnknown, (void **)&pUnk)))
  262. {
  263. // Don't pass back an invalid pointer
  264. IISDebugOutput(_T("GetObject:FAIL:Line=%d\r\n"),__LINE__);
  265. pObjRemote->Release();pObjRemote=NULL;
  266. goto GetObject_Exit;
  267. }
  268. if (FAILED(auth.ApplyProxyBlanket(pUnk,RPC_C_AUTHN_LEVEL_PKT_PRIVACY)))
  269. {
  270. // Don't pass back an invalid pointer
  271. pObjRemote->Release();pObjRemote=NULL;
  272. if (pUnk)
  273. {
  274. pUnk->Release();pUnk = NULL;
  275. }
  276. IISDebugOutput(_T("GetObject:FAIL:Line=%d\r\n"),__LINE__);
  277. goto GetObject_Exit;
  278. }
  279. pUnk->Release();pUnk = NULL;
  280. }
  281. auth.FreeServerInfoStruct(pcsiName);
  282. if (pObjRemote)
  283. {
  284. AddRemoteInterface(pObjRemote);
  285. }
  286. }
  287. GetObject_Exit:
  288. return pObjRemote;
  289. }
  290. STDMETHODIMP
  291. CIISCertObj::IsInstalled(VARIANT_BOOL * retval)
  292. {
  293. IISDebugOutput(_T("IsInstalled\r\n"));
  294. CheckPointer(retval, E_POINTER);
  295. HRESULT hr = S_OK;
  296. if (0 == m_ServerName.Length())
  297. {
  298. hr = IsInstalledRemote(retval);
  299. }
  300. else
  301. {
  302. if (!m_InstanceName)
  303. {
  304. return E_INVALIDARG;
  305. }
  306. //ASSERT(GetObject(&hr) != NULL);
  307. IIISCertObj * pObj;
  308. if (NULL != (pObj = GetObject(&hr)))
  309. {
  310. // For some reason we need to SysAllocString these instance names
  311. // if not com will AV when marshalling...
  312. // don't need to free _bstr_t
  313. _bstr_t bstrInstName(m_InstanceName);
  314. if (SUCCEEDED(hr = pObj->put_InstanceName(bstrInstName)))
  315. {
  316. hr = pObj->IsInstalledRemote(retval);
  317. }
  318. // release remote object
  319. if (pObj != NULL)
  320. {
  321. if (pObj != this)
  322. {
  323. DelRemoteInterface(pObj);
  324. pObj->Release();pObj=NULL;
  325. }
  326. }
  327. }
  328. }
  329. return hr;
  330. }
  331. STDMETHODIMP
  332. CIISCertObj::IsInstalledRemote(VARIANT_BOOL * retval)
  333. {
  334. IISDebugOutput(_T("IsInstalledRemote\r\n"));
  335. CheckPointer(retval, E_POINTER);
  336. CERT_CONTEXT * pCertContext = NULL;
  337. HRESULT hr = S_OK;
  338. if (!m_InstanceName)
  339. {
  340. return E_INVALIDARG;
  341. }
  342. pCertContext = GetInstalledCert(&hr, m_InstanceName);
  343. if (FAILED(hr) || NULL == pCertContext)
  344. {
  345. *retval = VARIANT_FALSE;
  346. }
  347. else
  348. {
  349. *retval = VARIANT_TRUE;
  350. CertFreeCertificateContext(pCertContext);
  351. }
  352. return S_OK;
  353. }
  354. STDMETHODIMP
  355. CIISCertObj::IsExportable(VARIANT_BOOL * retval)
  356. {
  357. IISDebugOutput(_T("IsExportable\r\n"));
  358. CheckPointer(retval, E_POINTER);
  359. HRESULT hr = S_OK;
  360. if (0 == m_ServerName.Length())
  361. {
  362. hr = IsExportableRemote(retval);
  363. }
  364. else
  365. {
  366. if (!m_InstanceName)
  367. {
  368. return E_INVALIDARG;
  369. }
  370. //ASSERT(GetObject(&hr) != NULL);
  371. IIISCertObj * pObj = NULL;
  372. if (NULL != (pObj = GetObject(&hr)))
  373. {
  374. // For some reason we need to SysAllocString these instance names
  375. // if not com will AV when marshalling...
  376. // don't need to free _bstr_t
  377. _bstr_t bstrInstName(m_InstanceName);
  378. hr = pObj->put_InstanceName(bstrInstName);
  379. if (SUCCEEDED(hr))
  380. {
  381. hr = pObj->IsExportableRemote(retval);
  382. }
  383. // release remote object
  384. if (pObj != NULL)
  385. {
  386. if (pObj != this)
  387. {
  388. DelRemoteInterface(pObj);
  389. pObj->Release();pObj=NULL;
  390. }
  391. }
  392. }
  393. }
  394. return hr;
  395. }
  396. STDMETHODIMP
  397. CIISCertObj::IsExportableRemote(VARIANT_BOOL * retval)
  398. {
  399. IISDebugOutput(_T("IsExportableRemote\r\n"));
  400. CheckPointer(retval, E_POINTER);
  401. HRESULT hr = S_OK;
  402. if (!m_InstanceName)
  403. {
  404. return E_INVALIDARG;
  405. }
  406. CERT_CONTEXT * pCertContext = GetInstalledCert(&hr, m_InstanceName);
  407. if (FAILED(hr) || NULL == pCertContext)
  408. {
  409. *retval = VARIANT_FALSE;
  410. }
  411. else
  412. {
  413. // check if it's exportable!
  414. if (IsCertExportable(pCertContext))
  415. {
  416. *retval = VARIANT_TRUE;
  417. }
  418. else
  419. {
  420. *retval = VARIANT_FALSE;
  421. }
  422. }
  423. if (pCertContext)
  424. {
  425. CertFreeCertificateContext(pCertContext);
  426. }
  427. return S_OK;
  428. }
  429. STDMETHODIMP
  430. CIISCertObj::GetCertInfo(VARIANT * pVtArray)
  431. {
  432. IISDebugOutput(_T("GetCertInfo\r\n"));
  433. CheckPointer(pVtArray, E_POINTER);
  434. HRESULT hr = S_OK;
  435. if (0 == m_ServerName.Length())
  436. {
  437. hr = GetCertInfoRemote(pVtArray);
  438. }
  439. else
  440. {
  441. if (!m_InstanceName)
  442. {
  443. return E_INVALIDARG;
  444. }
  445. //ASSERT(GetObject(&hr) != NULL);
  446. IIISCertObj * pObj;
  447. if (NULL != (pObj = GetObject(&hr)))
  448. {
  449. // For some reason we need to SysAllocString these instance names
  450. // if not com will AV when marshalling...
  451. // don't need to free _bstr_t
  452. _bstr_t bstrInstName(m_InstanceName);
  453. hr = pObj->put_InstanceName(bstrInstName);
  454. if (SUCCEEDED(hr))
  455. {
  456. hr = pObj->GetCertInfoRemote(pVtArray);
  457. }
  458. // release remote object
  459. if (pObj != NULL)
  460. {
  461. if (pObj != this)
  462. {
  463. DelRemoteInterface(pObj);
  464. pObj->Release();pObj=NULL;
  465. }
  466. }
  467. }
  468. }
  469. return hr;
  470. }
  471. STDMETHODIMP
  472. CIISCertObj::GetCertInfoRemote(
  473. VARIANT * pVtArray
  474. )
  475. {
  476. IISDebugOutput(_T("GetCertInfoRemote\r\n"));
  477. CheckPointer(pVtArray, E_POINTER);
  478. HRESULT hr = S_OK;
  479. if (!m_InstanceName)
  480. {
  481. return E_INVALIDARG;
  482. }
  483. CERT_CONTEXT * pCertContext = GetInstalledCert(&hr, m_InstanceName);
  484. if (FAILED(hr) || NULL == pCertContext)
  485. {
  486. hr = S_FALSE;
  487. }
  488. else
  489. {
  490. DWORD cb = 0;
  491. LPWSTR pwszText = NULL;
  492. if (TRUE == GetCertDescriptionForRemote(pCertContext,&pwszText,&cb,TRUE))
  493. {
  494. hr = S_OK;
  495. hr = HereIsBinaryGimmieVtArray(cb * sizeof(WCHAR),(char *) pwszText,pVtArray,FALSE);
  496. }
  497. else
  498. {
  499. hr = S_FALSE;
  500. }
  501. }
  502. if (pCertContext)
  503. {
  504. CertFreeCertificateContext(pCertContext);
  505. }
  506. return hr;
  507. }
  508. STDMETHODIMP
  509. CIISCertObj::RemoveCert(
  510. VARIANT_BOOL bRemoveFromCertStore,
  511. VARIANT_BOOL bPrivateKey
  512. )
  513. {
  514. IISDebugOutput(_T("RemoveCert\r\n"));
  515. HRESULT hr = E_FAIL;
  516. PCCERT_CONTEXT pCertContext = NULL;
  517. DWORD cbKpi = 0;
  518. PCRYPT_KEY_PROV_INFO pKpi = NULL ;
  519. HCRYPTPROV hCryptProv = NULL;
  520. BOOL bPleaseLogFailure = FALSE;
  521. if (!m_InstanceName)
  522. {
  523. return E_INVALIDARG;
  524. }
  525. // get the certificate from the server
  526. if (NULL != (pCertContext = GetInstalledCert(&hr, m_InstanceName)))
  527. {
  528. do
  529. {
  530. // VARIANT_TRUE is passed when invoked from VB! Make sure to check that too!
  531. if (TRUE == bRemoveFromCertStore || VARIANT_TRUE == bRemoveFromCertStore )
  532. {
  533. bPleaseLogFailure = TRUE;
  534. if (!CertGetCertificateContextProperty(pCertContext,
  535. CERT_KEY_PROV_INFO_PROP_ID, NULL, &cbKpi)
  536. )
  537. {
  538. break;
  539. }
  540. PCRYPT_KEY_PROV_INFO pKpi = (PCRYPT_KEY_PROV_INFO)malloc(cbKpi);
  541. if (NULL == pKpi)
  542. {
  543. ::SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  544. IISDebugOutput(_T("RemoveCert:FAIL:Line=%d,0x%x\r\n"),__LINE__,ERROR_NOT_ENOUGH_MEMORY);
  545. break;
  546. }
  547. if ( !CertGetCertificateContextProperty(pCertContext,
  548. CERT_KEY_PROV_INFO_PROP_ID, pKpi, &cbKpi)
  549. || !CryptAcquireContext(&hCryptProv,
  550. pKpi->pwszContainerName,
  551. pKpi->pwszProvName,
  552. pKpi->dwProvType,
  553. pKpi->dwFlags | CRYPT_DELETEKEYSET | CRYPT_MACHINE_KEYSET)
  554. || !CertSetCertificateContextProperty(pCertContext,
  555. CERT_KEY_PROV_INFO_PROP_ID, 0, NULL)
  556. )
  557. {
  558. free(pKpi);
  559. break;
  560. }
  561. free(pKpi);
  562. }
  563. // uninstall the certificate from the site, reset SSL flag
  564. // if we are exporting the private key, remove the cert from the storage
  565. // and delete private key
  566. UninstallCert(m_InstanceName);
  567. // remove ssl key from metabase
  568. // ShutdownSSL(m_InstanceName);
  569. // VARIANT_TRUE is passed when invoked from VB! Make sure to check that too!
  570. if (TRUE == bRemoveFromCertStore || VARIANT_TRUE == bRemoveFromCertStore )
  571. {
  572. // delete the private key
  573. if (TRUE == bPrivateKey || VARIANT_TRUE == bPrivateKey)
  574. {
  575. PCCERT_CONTEXT pcDup = NULL ;
  576. pcDup = CertDuplicateCertificateContext(pCertContext);
  577. if (pcDup)
  578. {
  579. if (!CertDeleteCertificateFromStore(pcDup))
  580. {
  581. break;
  582. }
  583. }
  584. }
  585. }
  586. ::SetLastError(ERROR_SUCCESS);
  587. ReportIt(CERTOBJ_CERT_REMOVE_SUCCEED, m_InstanceName);
  588. bPleaseLogFailure = FALSE;
  589. } while (FALSE);
  590. hr = HRESULT_FROM_WIN32(GetLastError());
  591. }
  592. if (bPleaseLogFailure)
  593. {
  594. ReportIt(CERTOBJ_CERT_REMOVE_FAILED, m_InstanceName);
  595. }
  596. if (pCertContext)
  597. {
  598. CertFreeCertificateContext(pCertContext);
  599. }
  600. return hr;
  601. }
  602. STDMETHODIMP
  603. CIISCertObj::Import(
  604. BSTR FileName,
  605. BSTR Password,
  606. VARIANT_BOOL bAllowExport,
  607. VARIANT_BOOL bOverWriteExisting
  608. )
  609. {
  610. IISDebugOutput(_T("Import\r\n"));
  611. HRESULT hr = S_OK;
  612. BYTE * pbData = NULL;
  613. DWORD actual = 0, cbData = 0;
  614. BOOL bPleaseLogFailure = FALSE;
  615. // Check mandatory properties
  616. if ( FileName == NULL || *FileName == 0
  617. || Password == NULL || *Password == 0
  618. )
  619. {
  620. return E_INVALIDARG;
  621. }
  622. if (!m_InstanceName)
  623. {
  624. return E_INVALIDARG;
  625. }
  626. // ------------------------
  627. // buffer overflow paranoia
  628. // check all parameters...
  629. // ------------------------
  630. // no need to check FileName size, CreateFile will handle...
  631. //if (wcslen(FileName) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  632. if (wcslen(Password) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  633. HANDLE hFile = CreateFile(FileName, GENERIC_READ, FILE_SHARE_READ, NULL,
  634. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  635. if (hFile == INVALID_HANDLE_VALUE)
  636. {
  637. hr = HRESULT_FROM_WIN32(GetLastError());
  638. hFile = NULL;
  639. IISDebugOutput(_T("Import:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  640. goto Import_Exit;
  641. }
  642. if (-1 == (cbData = ::GetFileSize(hFile, NULL)))
  643. {
  644. hr = HRESULT_FROM_WIN32(GetLastError());
  645. IISDebugOutput(_T("Import:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  646. goto Import_Exit;
  647. }
  648. if (cbData > MAX_CERTIFICATE_BYTE_SIZE)
  649. {
  650. hr = E_OUTOFMEMORY;
  651. IISDebugOutput(_T("Import:FAIL:Line=%d,Cert Size > Max=%d\r\n"),__LINE__,MAX_CERTIFICATE_BYTE_SIZE);
  652. goto Import_Exit;
  653. }
  654. if (NULL == (pbData = (BYTE *)::CoTaskMemAlloc(cbData)))
  655. {
  656. hr = E_OUTOFMEMORY;
  657. IISDebugOutput(_T("Import:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  658. goto Import_Exit;
  659. }
  660. if (ReadFile(hFile, pbData, cbData, &actual, NULL))
  661. {
  662. IIISCertObj * pObj = GetObject(&hr);
  663. if (SUCCEEDED(hr))
  664. {
  665. bPleaseLogFailure = TRUE;
  666. // don't need to free _bstr_t
  667. try
  668. {
  669. _bstr_t bstrInstName(m_InstanceName);
  670. hr = ImportFromBlobProxy(pObj, bstrInstName, Password, VARIANT_TRUE,
  671. bAllowExport, bOverWriteExisting, actual, pbData, 0, NULL);
  672. if (SUCCEEDED(hr))
  673. {
  674. ReportIt(CERTOBJ_CERT_IMPORT_SUCCEED, m_InstanceName);
  675. bPleaseLogFailure = FALSE;
  676. }
  677. }
  678. catch(...)
  679. {
  680. }
  681. }
  682. // release remote object
  683. if (pObj != NULL)
  684. {
  685. if (pObj != this)
  686. {
  687. DelRemoteInterface(pObj);
  688. pObj->Release();pObj=NULL;
  689. }
  690. }
  691. }
  692. else
  693. {
  694. hr = HRESULT_FROM_WIN32(GetLastError());
  695. IISDebugOutput(_T("Import:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  696. goto Import_Exit;
  697. }
  698. if (bPleaseLogFailure)
  699. {
  700. ReportIt(CERTOBJ_CERT_EXPORT_FAILED, m_InstanceName);
  701. }
  702. Import_Exit:
  703. if (pbData != NULL)
  704. {
  705. SecureZeroMemory(pbData, cbData);
  706. ::CoTaskMemFree(pbData);
  707. }
  708. if (hFile != NULL)
  709. {
  710. CloseHandle(hFile);
  711. }
  712. return hr;
  713. }
  714. STDMETHODIMP
  715. CIISCertObj::ImportToCertStore(
  716. BSTR FileName,
  717. BSTR Password,
  718. VARIANT_BOOL bAllowExport,
  719. VARIANT_BOOL bOverWriteExisting,
  720. VARIANT * pVtArray
  721. )
  722. {
  723. IISDebugOutput(_T("ImportToCertStore\r\n"));
  724. HRESULT hr = S_OK;
  725. BYTE * pbData = NULL;
  726. DWORD actual = 0, cbData = 0;
  727. BOOL bPleaseLogFailure = FALSE;
  728. // Check mandatory properties
  729. if ( FileName == NULL || *FileName == 0
  730. || Password == NULL || *Password == 0)
  731. {
  732. return E_INVALIDARG;
  733. }
  734. // ------------------------
  735. // buffer overflow paranoia
  736. // check all parameters...
  737. // ------------------------
  738. if (wcslen(FileName) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  739. if (wcslen(Password) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  740. HANDLE hFile = CreateFile(FileName, GENERIC_READ, FILE_SHARE_READ, NULL,
  741. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  742. if (hFile == INVALID_HANDLE_VALUE)
  743. {
  744. hr = HRESULT_FROM_WIN32(GetLastError());
  745. hFile = NULL;
  746. IISDebugOutput(_T("ImportToCertStore:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  747. goto Import_Exit;
  748. }
  749. if (-1 == (cbData = ::GetFileSize(hFile, NULL)))
  750. {
  751. hr = HRESULT_FROM_WIN32(GetLastError());
  752. IISDebugOutput(_T("ImportToCertStore:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  753. goto Import_Exit;
  754. }
  755. if (NULL == (pbData = (BYTE *)::CoTaskMemAlloc(cbData)))
  756. {
  757. hr = E_OUTOFMEMORY;
  758. IISDebugOutput(_T("ImportToCertStore:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  759. goto Import_Exit;
  760. }
  761. if (ReadFile(hFile, pbData, cbData, &actual, NULL))
  762. {
  763. IIISCertObj * pObj = GetObject(&hr);
  764. if (SUCCEEDED(hr))
  765. {
  766. DWORD cbHashBufferSize = 0;
  767. char * pszHashBuffer = NULL;
  768. bPleaseLogFailure = TRUE;
  769. hr = ImportFromBlobProxy(pObj, _T("none"), Password, VARIANT_FALSE,
  770. bAllowExport, bOverWriteExisting, actual, pbData,
  771. &cbHashBufferSize, &pszHashBuffer);
  772. if (SUCCEEDED(hr))
  773. {
  774. //ReportIt(CERTOBJ_CERT_IMPORT_CERT_STORE_SUCCEED, bstrInstanceName);
  775. bPleaseLogFailure = FALSE;
  776. hr = HereIsBinaryGimmieVtArray(cbHashBufferSize,pszHashBuffer,
  777. pVtArray,FALSE);
  778. }
  779. // free the memory that was alloced for us
  780. if (0 != cbHashBufferSize)
  781. {
  782. if (pszHashBuffer)
  783. {
  784. ::CoTaskMemFree(pszHashBuffer);
  785. }
  786. }
  787. }
  788. // release remote object
  789. if (pObj != NULL)
  790. {
  791. if (pObj != this)
  792. {
  793. DelRemoteInterface(pObj);
  794. pObj->Release();pObj=NULL;
  795. }
  796. }
  797. }
  798. else
  799. {
  800. hr = HRESULT_FROM_WIN32(GetLastError());
  801. IISDebugOutput(_T("ImportToCertStore:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  802. goto Import_Exit;
  803. }
  804. Import_Exit:
  805. if (bPleaseLogFailure)
  806. {
  807. //ReportIt(CERTOBJ_CERT_IMPORT_CERT_STORE_FAILED, bstrInstanceName);
  808. }
  809. if (pbData != NULL)
  810. {
  811. SecureZeroMemory(pbData, cbData);
  812. ::CoTaskMemFree(pbData);
  813. }
  814. if (hFile != NULL){CloseHandle(hFile);}
  815. return hr;
  816. }
  817. static HRESULT
  818. ImportFromBlobWork(
  819. BSTR InstanceName,
  820. BSTR Password,
  821. VARIANT_BOOL bInstallToMetabase,
  822. VARIANT_BOOL bAllowExport,
  823. VARIANT_BOOL bOverWriteExisting,
  824. DWORD count,
  825. char *pData,
  826. DWORD *pcbHashBufferSize,
  827. char **pbHashBuffer
  828. )
  829. {
  830. HRESULT hr = S_OK;
  831. CRYPT_DATA_BLOB blob;
  832. SecureZeroMemory(&blob, sizeof(CRYPT_DATA_BLOB));
  833. LPTSTR pPass = Password;
  834. int err;
  835. DWORD dwAddDisposition = CERT_STORE_ADD_NEW;
  836. CheckPointer(pData, E_POINTER);
  837. BOOL bCertIsForServiceAuthentication = TRUE;
  838. // VARIANT_TRUE is passed when invoked from VB! Make sure to check that too!
  839. if (TRUE == bOverWriteExisting || VARIANT_TRUE == bOverWriteExisting)
  840. {
  841. dwAddDisposition = CERT_STORE_ADD_REPLACE_EXISTING;
  842. }
  843. // The data we got back was Base64 encoded to remove nulls.
  844. // we need to decode it back to it's original format.
  845. if ((err = Base64DecodeA(pData,count,NULL,&blob.cbData)) != ERROR_SUCCESS)
  846. {
  847. SetLastError(err);
  848. hr = HRESULT_FROM_WIN32(err);
  849. IISDebugOutput(_T("ImportFromBlobWork:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  850. goto ImportFromBlobWork_Exit;
  851. }
  852. blob.pbData = (BYTE *) malloc(blob.cbData);
  853. if (NULL == blob.pbData)
  854. {
  855. hr = E_OUTOFMEMORY;
  856. IISDebugOutput(_T("ImportFromBlobWork:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  857. goto ImportFromBlobWork_Exit;
  858. }
  859. if ((err = Base64DecodeA(pData,count,blob.pbData,&blob.cbData)) != ERROR_SUCCESS )
  860. {
  861. SetLastError(err);
  862. hr = HRESULT_FROM_WIN32(err);
  863. IISDebugOutput(_T("ImportFromBlobWork:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  864. goto ImportFromBlobWork_Exit;
  865. }
  866. if (!PFXVerifyPassword(&blob, pPass, 0))
  867. {
  868. // Try empty password
  869. if (pPass == NULL)
  870. {
  871. if (!PFXVerifyPassword(&blob, pPass = L'\0', 0))
  872. {
  873. hr = E_INVALIDARG;
  874. }
  875. }
  876. else
  877. {
  878. hr = E_INVALIDARG;
  879. }
  880. }
  881. if (SUCCEEDED(hr))
  882. {
  883. // CRYPT_EXPORTABLE - which would then specify that any imported keys should
  884. // be marked as exportable (see documentation on CryptImportKey)
  885. // CRYPT_USER_PROTECTED - (see documentation on CryptImportKey)
  886. // PKCS12_NO_DATA_COMMIT - will unpack the pfx blob but does not persist its contents.
  887. // In this case, returns BOOL indicating successful unpack.
  888. // CRYPT_MACHINE_KEYSET - used to force the private key to be stored in the
  889. // the local machine and not the current user.
  890. // CRYPT_USER_KEYSET - used to force the private key to be stored in the
  891. // the current user and not the local machine, even if
  892. // the pfx blob specifies that it should go into local machine.
  893. HCERTSTORE hStore = PFXImportCertStore(&blob, pPass,
  894. (bAllowExport ? CRYPT_MACHINE_KEYSET|CRYPT_EXPORTABLE : CRYPT_MACHINE_KEYSET));
  895. if (hStore != NULL)
  896. {
  897. //add the certificate with private key to my store; and the rest
  898. //to the ca store
  899. PCCERT_CONTEXT pCertContext = NULL;
  900. PCCERT_CONTEXT pCertPre = NULL;
  901. while (SUCCEEDED(hr)
  902. && NULL != (pCertContext = CertEnumCertificatesInStore(hStore, pCertPre)
  903. )
  904. )
  905. {
  906. //check if the certificate has the property on it
  907. //make sure the private key matches the certificate
  908. //search for both machine key and user keys
  909. DWORD dwData = 0;
  910. if ( CertGetCertificateContextProperty(pCertContext,
  911. CERT_KEY_PROV_INFO_PROP_ID, NULL, &dwData)
  912. && CryptFindCertificateKeyProvInfo(pCertContext, 0, NULL)
  913. )
  914. {
  915. // Check if this cert can even be used for SeverAuthentication.
  916. // if it can't then don't let them assign it.
  917. if (!CanIISUseThisCertForServerAuth(pCertContext))
  918. {
  919. hr = SEC_E_CERT_WRONG_USAGE;
  920. IISDebugOutput(_T("ImportFromBlobWork:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  921. bCertIsForServiceAuthentication = FALSE;
  922. break;
  923. }
  924. if (bCertIsForServiceAuthentication)
  925. {
  926. // This certificate should go to the My store
  927. HCERTSTORE hDestStore = CertOpenStore(
  928. CERT_STORE_PROV_SYSTEM,PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
  929. NULL, CERT_SYSTEM_STORE_LOCAL_MACHINE, L"MY");
  930. if (hDestStore != NULL)
  931. {
  932. // Put it to store
  933. BOOL bTemp = CertAddCertificateContextToStore(hDestStore, pCertContext, dwAddDisposition, NULL);
  934. if (!bTemp)
  935. {
  936. // check if it failed with CRYPT_E_EXISTS
  937. // if it did then gee, it already exists...
  938. // check if we want to overwrite anyways...
  939. if (CRYPT_E_EXISTS == GetLastError())
  940. {
  941. // it's okay if it already exists
  942. // we don't need to warn user since they want to overwrite it
  943. bTemp = TRUE;
  944. }
  945. }
  946. if (bTemp)
  947. {
  948. // Succeeded to put it to the storage
  949. hr = S_OK;
  950. // Install to metabase
  951. CRYPT_HASH_BLOB hash;
  952. if (CertGetCertificateContextProperty(pCertContext,
  953. CERT_SHA1_HASH_PROP_ID, NULL, &hash.cbData))
  954. {
  955. hash.pbData = (BYTE *) LocalAlloc(LPTR, hash.cbData);
  956. if (NULL != hash.pbData)
  957. {
  958. if (CertGetCertificateContextProperty(pCertContext,
  959. CERT_SHA1_HASH_PROP_ID, hash.pbData, &hash.cbData))
  960. {
  961. BOOL bSomethingFailed = FALSE;
  962. // VARIANT_TRUE is passed when invoked from VB! Make sure to check that too!
  963. if (TRUE == bInstallToMetabase || VARIANT_TRUE == bInstallToMetabase)
  964. {
  965. // returns error code in hr
  966. if (!InstallHashToMetabase(&hash, InstanceName, &hr))
  967. {
  968. // failed for some reason.
  969. bSomethingFailed = TRUE;
  970. IISDebugOutput(_T("ImportFromBlobWork:FAIL:Line=%d (InstallHashToMetabase)\r\n"),__LINE__);
  971. }
  972. }
  973. if (!bSomethingFailed)
  974. {
  975. // check if we need to return back the hash
  976. if (NULL != pbHashBuffer)
  977. {
  978. *pbHashBuffer = (char *) ::CoTaskMemAlloc(hash.cbData);
  979. if (NULL == *pbHashBuffer)
  980. {
  981. hr = E_OUTOFMEMORY;
  982. *pbHashBuffer = NULL;
  983. if (pcbHashBufferSize)
  984. {*pcbHashBufferSize = 0;}
  985. IISDebugOutput(_T("ImportFromBlobWork:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  986. }
  987. else
  988. {
  989. if (pcbHashBufferSize)
  990. {*pcbHashBufferSize = hash.cbData;}
  991. memcpy(*pbHashBuffer,hash.pbData,hash.cbData);
  992. }
  993. }
  994. }
  995. } //CertGetCertificateContextProperty
  996. else
  997. {
  998. hr = HRESULT_FROM_WIN32(GetLastError());
  999. IISDebugOutput(_T("ImportFromBlobWork:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  1000. }
  1001. // free the memory we used
  1002. if (hash.pbData)
  1003. {
  1004. LocalFree(hash.pbData);
  1005. hash.pbData=NULL;
  1006. }
  1007. } // hash.pbData
  1008. else
  1009. {
  1010. hr = HRESULT_FROM_WIN32(GetLastError());
  1011. IISDebugOutput(_T("ImportFromBlobWork:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  1012. }
  1013. } // CertGetCertificateContextProperty
  1014. else
  1015. {
  1016. hr = HRESULT_FROM_WIN32(GetLastError());
  1017. IISDebugOutput(_T("ImportFromBlobWork:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  1018. }
  1019. } // bTemp
  1020. else
  1021. {
  1022. hr = HRESULT_FROM_WIN32(GetLastError());
  1023. IISDebugOutput(_T("ImportFromBlobWork:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  1024. }
  1025. CertCloseStore(hDestStore, 0);
  1026. }
  1027. else
  1028. {
  1029. hr = HRESULT_FROM_WIN32(GetLastError());
  1030. IISDebugOutput(_T("ImportFromBlobWork:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  1031. }
  1032. }
  1033. } // my store certificate
  1034. //see if the certificate is self-signed.
  1035. //if it is selfsigned, goes to the root store
  1036. else if (TrustIsCertificateSelfSigned(pCertContext,pCertContext->dwCertEncodingType, 0))
  1037. {
  1038. if (bCertIsForServiceAuthentication)
  1039. {
  1040. //Put it to the root store
  1041. HCERTSTORE hDestStore=CertOpenStore(
  1042. CERT_STORE_PROV_SYSTEM,PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
  1043. NULL, CERT_SYSTEM_STORE_LOCAL_MACHINE, L"ROOT");
  1044. if (hDestStore != NULL)
  1045. {
  1046. // Put it to store
  1047. BOOL bTemp = CertAddCertificateContextToStore(hDestStore,pCertContext,dwAddDisposition,NULL);
  1048. if (!bTemp)
  1049. {
  1050. // check if it failed with CRYPT_E_EXISTS
  1051. // if it did then gee, it already exists...
  1052. // check if we want to overwrite anyways...
  1053. if (CRYPT_E_EXISTS == GetLastError())
  1054. {
  1055. if (TRUE == bOverWriteExisting || VARIANT_TRUE == bOverWriteExisting)
  1056. {
  1057. // it's okay if it already exists
  1058. // we don't need to warn user since they want to overwrite it
  1059. bTemp = TRUE;
  1060. hr = S_OK;
  1061. }
  1062. }
  1063. }
  1064. if (!bTemp)
  1065. {
  1066. hr = HRESULT_FROM_WIN32(GetLastError());
  1067. IISDebugOutput(_T("ImportFromBlobWork:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  1068. }
  1069. CertCloseStore(hDestStore, 0);
  1070. }
  1071. else
  1072. {
  1073. hr = HRESULT_FROM_WIN32(GetLastError());
  1074. IISDebugOutput(_T("ImportFromBlobWork:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  1075. }
  1076. }
  1077. }
  1078. else
  1079. {
  1080. if (bCertIsForServiceAuthentication)
  1081. {
  1082. //Put it to the CA store
  1083. HCERTSTORE hDestStore=CertOpenStore(
  1084. CERT_STORE_PROV_SYSTEM,PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
  1085. NULL, CERT_SYSTEM_STORE_LOCAL_MACHINE, L"CA");
  1086. if (hDestStore != NULL)
  1087. {
  1088. // Put it to store
  1089. BOOL bTemp = CertAddCertificateContextToStore(hDestStore,pCertContext,dwAddDisposition,NULL);
  1090. if (!bTemp)
  1091. {
  1092. // check if it failed with CRYPT_E_EXISTS
  1093. // if it did then gee, it already exists...
  1094. // check if we want to overwrite anyways...
  1095. if (CRYPT_E_EXISTS == GetLastError())
  1096. {
  1097. if (TRUE == bOverWriteExisting || VARIANT_TRUE == bOverWriteExisting)
  1098. {
  1099. // it's okay if it already exists
  1100. // we don't need to warn user since they want to overwrite it
  1101. bTemp = TRUE;
  1102. hr = S_OK;
  1103. }
  1104. }
  1105. }
  1106. if (!bTemp)
  1107. {
  1108. hr = HRESULT_FROM_WIN32(GetLastError());
  1109. IISDebugOutput(_T("ImportFromBlobWork:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  1110. }
  1111. CertCloseStore(hDestStore, 0);
  1112. }
  1113. else
  1114. {
  1115. hr = HRESULT_FROM_WIN32(GetLastError());
  1116. IISDebugOutput(_T("ImportFromBlobWork:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  1117. }
  1118. }
  1119. }
  1120. pCertPre = pCertContext;
  1121. } //while
  1122. CertCloseStore(hStore, 0);
  1123. }
  1124. else
  1125. {
  1126. hr = HRESULT_FROM_WIN32(GetLastError());
  1127. IISDebugOutput(_T("ImportFromBlobWork:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  1128. }
  1129. }
  1130. ImportFromBlobWork_Exit:
  1131. if (blob.pbData != NULL)
  1132. {
  1133. SecureZeroMemory(blob.pbData, blob.cbData);
  1134. free(blob.pbData);
  1135. blob.pbData=NULL;
  1136. }
  1137. return hr;
  1138. }
  1139. HRESULT
  1140. CIISCertObj::ImportFromBlob(
  1141. BSTR InstanceName,
  1142. BSTR Password,
  1143. VARIANT_BOOL bInstallToMetabase,
  1144. VARIANT_BOOL bAllowExport,
  1145. VARIANT_BOOL bOverWriteExisting,
  1146. DWORD count,
  1147. char *pData
  1148. )
  1149. {
  1150. HRESULT hr;
  1151. // Check mandatory properties
  1152. if ( Password == NULL
  1153. || *Password == 0
  1154. || InstanceName == NULL
  1155. || *InstanceName == 0
  1156. )
  1157. {
  1158. return E_INVALIDARG;
  1159. }
  1160. // ------------------------
  1161. // buffer overflow paranoia
  1162. // check all parameters...
  1163. // ------------------------
  1164. if (wcslen(InstanceName) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  1165. if (wcslen(Password) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  1166. hr = ImportFromBlobWork(InstanceName,Password,bInstallToMetabase,bAllowExport,
  1167. bOverWriteExisting,count,pData,0,NULL);
  1168. return hr;
  1169. }
  1170. HRESULT
  1171. CIISCertObj::ImportFromBlobGetHash(
  1172. BSTR InstanceName,
  1173. BSTR Password,
  1174. VARIANT_BOOL bInstallToMetabase,
  1175. VARIANT_BOOL bAllowExport,
  1176. VARIANT_BOOL bOverWriteExisting,
  1177. DWORD count,
  1178. char *pData,
  1179. DWORD *pcbHashBufferSize,
  1180. char **pbHashBuffer
  1181. )
  1182. {
  1183. HRESULT hr;
  1184. // Check mandatory properties
  1185. if ( Password == NULL || *Password == 0
  1186. || InstanceName == NULL || *InstanceName == 0)
  1187. {
  1188. return E_INVALIDARG;
  1189. }
  1190. // ------------------------
  1191. // buffer overflow paranoia
  1192. // check all parameters...
  1193. // ------------------------
  1194. if (wcslen(InstanceName) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  1195. if (wcslen(Password) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  1196. hr = ImportFromBlobWork(InstanceName,Password,bInstallToMetabase,bAllowExport,
  1197. bOverWriteExisting,count,pData,pcbHashBufferSize,pbHashBuffer);
  1198. return hr;
  1199. }
  1200. STDMETHODIMP
  1201. CIISCertObj::Export(
  1202. BSTR FileName,
  1203. BSTR Password,
  1204. VARIANT_BOOL bPrivateKey,
  1205. VARIANT_BOOL bCertChain,
  1206. VARIANT_BOOL bRemoveCert)
  1207. {
  1208. IISDebugOutput(_T("Export\r\n"));
  1209. HRESULT hr = S_OK;
  1210. DWORD cbEncodedSize = 0;
  1211. char * pszEncodedString = NULL;
  1212. DWORD blob_cbData = 0;
  1213. BYTE * blob_pbData = NULL;
  1214. BOOL bPleaseLogFailure = FALSE;
  1215. // Check mandatory properties
  1216. if ( FileName == NULL || *FileName == 0
  1217. || Password == NULL || *Password == 0
  1218. )
  1219. {
  1220. return E_INVALIDARG;
  1221. }
  1222. // ------------------------
  1223. // buffer overflow paranoia
  1224. // check all parameters...
  1225. // ------------------------
  1226. if (wcslen(FileName) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  1227. if (wcslen(Password) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  1228. IIISCertObj * pObj = GetObject(&hr);
  1229. if (FAILED(hr))
  1230. {
  1231. IISDebugOutput(_T("Export:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  1232. goto Export_Exit;
  1233. }
  1234. // Call function go get data from the remote/local iis store
  1235. // and return it back as a blob. the blob could be returned back as Base64 encoded
  1236. // so check that flag
  1237. // don't need to free _bstr_t
  1238. {
  1239. _bstr_t bstrInstName(m_InstanceName);
  1240. hr = ExportToBlobProxy(pObj, bstrInstName, Password, bPrivateKey,
  1241. bCertChain, &cbEncodedSize, &pszEncodedString);
  1242. }
  1243. if (FAILED(hr))
  1244. {
  1245. IISDebugOutput(_T("Export:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  1246. goto Export_Exit;
  1247. }
  1248. // check if things are kool
  1249. // VARIANT_TRUE is passed when invoked from VB! Make sure to check that too!
  1250. if (TRUE == bRemoveCert || VARIANT_TRUE == bRemoveCert)
  1251. {
  1252. // don't need to free _bstr_t
  1253. _bstr_t bstrInstName2(m_InstanceName);
  1254. hr = RemoveCertProxy(pObj, bstrInstName2, bPrivateKey);
  1255. if (FAILED(hr))
  1256. {
  1257. IISDebugOutput(_T("Export:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  1258. goto Export_Exit;
  1259. }
  1260. }
  1261. if (SUCCEEDED(hr))
  1262. {
  1263. int err;
  1264. bPleaseLogFailure = TRUE;
  1265. // The data we got back was Base64 encoded to remove nulls.
  1266. // we need to decode it back to it's original format.
  1267. if((err = Base64DecodeA(pszEncodedString,cbEncodedSize,NULL,&blob_cbData)) != ERROR_SUCCESS)
  1268. {
  1269. SetLastError(err);
  1270. hr = HRESULT_FROM_WIN32(err);
  1271. IISDebugOutput(_T("Export:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  1272. goto Export_Exit;
  1273. }
  1274. blob_pbData = (BYTE *) malloc(blob_cbData);
  1275. if (NULL == blob_pbData)
  1276. {
  1277. hr = E_OUTOFMEMORY;
  1278. IISDebugOutput(_T("Export:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  1279. goto Export_Exit;
  1280. }
  1281. if ((err = Base64DecodeA(pszEncodedString,cbEncodedSize,blob_pbData,&blob_cbData)) != ERROR_SUCCESS )
  1282. {
  1283. SetLastError(err);
  1284. hr = HRESULT_FROM_WIN32(err);
  1285. IISDebugOutput(_T("Export:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  1286. goto Export_Exit;
  1287. }
  1288. //
  1289. // Set up and ACL Full access for system, admin and creator, no access for anyone else
  1290. // We're the owner so we're good...
  1291. //
  1292. SECURITY_ATTRIBUTES SA;
  1293. // don't use this one -- it has OICI which inherits from above
  1294. //WCHAR *pwszSD=L"D:(A;OICI;GA;;;SY)(A;OICI;GA;;;BA)(A;OICI;GA;;;CO)";
  1295. //
  1296. // This is the right one without inheritance -- we don't want to inherit an everyone readonly ACE
  1297. WCHAR *pwszSD=L"D:(A;;GA;;;SY)(A;;GA;;;BA)(A;;GA;;;CO)";
  1298. SA.nLength = sizeof(SECURITY_ATTRIBUTES);
  1299. SA.bInheritHandle = TRUE;
  1300. // Caller will delete the SD w/ LocalFree
  1301. if (!ConvertStringSecurityDescriptorToSecurityDescriptor(
  1302. pwszSD,
  1303. SDDL_REVISION_1,
  1304. &(SA.lpSecurityDescriptor),
  1305. NULL) )
  1306. {
  1307. IISDebugOutput(_T("Export:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  1308. return E_FAIL;
  1309. }
  1310. // Create the dir if it doesn't exist..
  1311. HANDLE hFile = CreateFile(FileName, GENERIC_WRITE, 0, &SA, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  1312. if (INVALID_HANDLE_VALUE == hFile)
  1313. {
  1314. hr = HRESULT_FROM_WIN32(GetLastError());
  1315. if (hr == ERROR_PATH_NOT_FOUND || hr == ERROR_FILE_NOT_FOUND || hr == 0x80070003)
  1316. {
  1317. //
  1318. // Create folders as needed
  1319. //
  1320. hr = CreateFolders(FileName, TRUE);
  1321. if (FAILED(hr))
  1322. {
  1323. LocalFree(SA.lpSecurityDescriptor);
  1324. IISDebugOutput(_T("Export:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  1325. return hr;
  1326. }
  1327. //
  1328. // Try again
  1329. //
  1330. hFile = CreateFile(FileName,
  1331. GENERIC_WRITE, 0, &SA, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  1332. if (INVALID_HANDLE_VALUE == hFile)
  1333. {
  1334. LocalFree(SA.lpSecurityDescriptor);
  1335. hr = HRESULT_FROM_WIN32(GetLastError());
  1336. IISDebugOutput(_T("Export:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  1337. return hr;
  1338. }
  1339. }
  1340. else
  1341. {
  1342. LocalFree(SA.lpSecurityDescriptor);
  1343. IISDebugOutput(_T("Export:FAIL:Line=%d,0x%x,FileName=%s\r\n"),__LINE__,hr,FileName);
  1344. return hr;
  1345. }
  1346. }
  1347. DWORD written = 0;
  1348. if (!WriteFile(hFile, blob_pbData, blob_cbData, &written, NULL))
  1349. {
  1350. hr = HRESULT_FROM_WIN32(GetLastError());
  1351. IISDebugOutput(_T("Export:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  1352. }
  1353. else
  1354. {
  1355. hr = S_OK;
  1356. ReportIt(CERTOBJ_CERT_EXPORT_SUCCEED, m_InstanceName);
  1357. bPleaseLogFailure = FALSE;
  1358. }
  1359. CloseHandle(hFile);
  1360. LocalFree(SA.lpSecurityDescriptor);
  1361. }
  1362. Export_Exit:
  1363. if (bPleaseLogFailure)
  1364. {
  1365. ReportIt(CERTOBJ_CERT_EXPORT_FAILED, m_InstanceName);
  1366. }
  1367. // release remote object
  1368. if (pObj != NULL)
  1369. {
  1370. if (pObj != this)
  1371. {
  1372. DelRemoteInterface(pObj);
  1373. pObj->Release();pObj=NULL;
  1374. }
  1375. }
  1376. if (blob_pbData != NULL)
  1377. {
  1378. // Erase the memory that the private key used to be in!!!
  1379. SecureZeroMemory(blob_pbData, blob_cbData);
  1380. free(blob_pbData);blob_pbData=NULL;
  1381. }
  1382. if (pszEncodedString != NULL)
  1383. {
  1384. // Erase the memory that the private key used to be in!!!
  1385. SecureZeroMemory(pszEncodedString, cbEncodedSize);
  1386. CoTaskMemFree(pszEncodedString);pszEncodedString=NULL;
  1387. }
  1388. return hr;
  1389. }
  1390. STDMETHODIMP
  1391. CIISCertObj::ExportToBlob(
  1392. BSTR InstanceName,
  1393. BSTR Password,
  1394. VARIANT_BOOL bPrivateKey,
  1395. VARIANT_BOOL bCertChain,
  1396. DWORD *cbBufferSize,
  1397. char **pbBuffer
  1398. )
  1399. {
  1400. HRESULT hr = E_FAIL;
  1401. PCCERT_CONTEXT pCertContext = NULL;
  1402. HCERTSTORE hStore = NULL;
  1403. DWORD dwOpenFlags = CERT_STORE_READONLY_FLAG | CERT_STORE_ENUM_ARCHIVED_FLAG;
  1404. CRYPT_DATA_BLOB DataBlob;
  1405. SecureZeroMemory(&DataBlob, sizeof(CRYPT_DATA_BLOB));
  1406. char *pszB64Out = NULL;
  1407. DWORD pcchB64Out = 0;
  1408. DWORD err;
  1409. DWORD dwExportFlags = EXPORT_PRIVATE_KEYS | REPORT_NO_PRIVATE_KEY;
  1410. DWORD dwFlags = REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY;
  1411. // Check mandatory properties
  1412. if ( Password == NULL || *Password == 0
  1413. || InstanceName == NULL || *InstanceName == 0)
  1414. {
  1415. return E_INVALIDARG;
  1416. }
  1417. // ------------------------
  1418. // buffer overflow paranoia
  1419. // check all parameters...
  1420. // ------------------------
  1421. if (wcslen(Password) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  1422. if (wcslen(InstanceName) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  1423. //
  1424. // get the certificate from the server
  1425. //
  1426. pCertContext = GetInstalledCert(&hr,InstanceName);
  1427. if (NULL == pCertContext)
  1428. {
  1429. *cbBufferSize = 0;
  1430. pbBuffer = NULL;
  1431. IISDebugOutput(_T("ExportToBlob:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  1432. goto ExportToBlob_Exit;
  1433. }
  1434. // Check if this cert can even be used for SeverAuthentication.
  1435. // if it can't then don't let them export it.
  1436. if (!CanIISUseThisCertForServerAuth(pCertContext))
  1437. {
  1438. hr = SEC_E_CERT_WRONG_USAGE;
  1439. IISDebugOutput(_T("ExportToBlob:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  1440. goto ExportToBlob_Exit;
  1441. }
  1442. //
  1443. // Export cert
  1444. //
  1445. // Open a temporary store to stick the cert in.
  1446. hStore = CertOpenStore(CERT_STORE_PROV_MEMORY,X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  1447. 0,dwOpenFlags,NULL);
  1448. if(NULL == hStore)
  1449. {
  1450. *cbBufferSize = 0;
  1451. pbBuffer = NULL;
  1452. hr = HRESULT_FROM_WIN32(GetLastError());
  1453. IISDebugOutput(_T("ExportToBlob:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  1454. goto ExportToBlob_Exit;
  1455. }
  1456. //
  1457. // get all the certs in the chain if we need to
  1458. //
  1459. // VARIANT_TRUE is passed when invoked from VB! Make sure to check that too!
  1460. if (TRUE == bCertChain || VARIANT_TRUE == bCertChain)
  1461. {
  1462. AddChainToStore(hStore, pCertContext, 0, 0, FALSE, NULL);
  1463. }
  1464. if(!CertAddCertificateContextToStore(hStore,pCertContext,
  1465. CERT_STORE_ADD_REPLACE_EXISTING,NULL))
  1466. {
  1467. *cbBufferSize = 0;
  1468. pbBuffer = NULL;
  1469. hr = HRESULT_FROM_WIN32(GetLastError());
  1470. IISDebugOutput(_T("ExportToBlob:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  1471. goto ExportToBlob_Exit;
  1472. }
  1473. // free cert context since we no longer need to hold it
  1474. if (pCertContext)
  1475. {
  1476. CertFreeCertificateContext(pCertContext);pCertContext=NULL;
  1477. }
  1478. DataBlob.cbData = 0;
  1479. DataBlob.pbData = NULL;
  1480. if (TRUE == bPrivateKey || VARIANT_TRUE == bPrivateKey)
  1481. {
  1482. dwFlags = dwFlags | dwExportFlags;
  1483. }
  1484. if (TRUE == bCertChain || VARIANT_TRUE == bCertChain)
  1485. {
  1486. // make sure to remove REPORT_NO_PRIVATE_KEY
  1487. // since something on the chain will not have a private key
  1488. // and will produce an error in PFXExportCertStoreEx
  1489. dwFlags &= ~REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY;
  1490. dwFlags &= ~REPORT_NO_PRIVATE_KEY;
  1491. }
  1492. if (!PFXExportCertStoreEx(hStore,&DataBlob,Password,NULL,dwFlags))
  1493. {
  1494. hr = HRESULT_FROM_WIN32(GetLastError());
  1495. IISDebugOutput(_T("ExportToBlob:FAIL:Line=%d,0x%x,dwFlags=0x%x\r\n"),__LINE__,hr,dwFlags);
  1496. goto ExportToBlob_Exit;
  1497. }
  1498. if (DataBlob.cbData <= 0)
  1499. {
  1500. hr = HRESULT_FROM_WIN32(GetLastError());
  1501. IISDebugOutput(_T("ExportToBlob:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  1502. goto ExportToBlob_Exit;
  1503. }
  1504. if (NULL == (DataBlob.pbData = (PBYTE) ::CoTaskMemAlloc(DataBlob.cbData)))
  1505. {
  1506. hr = E_OUTOFMEMORY;
  1507. IISDebugOutput(_T("ExportToBlob:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  1508. goto ExportToBlob_Exit;
  1509. }
  1510. //
  1511. // at this point they have allocated enough memory
  1512. // let's go and get the cert and put it into DataBlob
  1513. //
  1514. if(!PFXExportCertStoreEx(hStore,&DataBlob,Password,NULL,dwFlags))
  1515. {
  1516. if (DataBlob.pbData){CoTaskMemFree(DataBlob.pbData);DataBlob.pbData = NULL;}
  1517. hr = HRESULT_FROM_WIN32(GetLastError());
  1518. IISDebugOutput(_T("ExportToBlob:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  1519. goto ExportToBlob_Exit;
  1520. }
  1521. // Encode it so that it can be passed back as a string (there are no Nulls in it)
  1522. err = Base64EncodeA(DataBlob.pbData,DataBlob.cbData,NULL,&pcchB64Out);
  1523. if (err != ERROR_SUCCESS)
  1524. {
  1525. hr = E_FAIL;
  1526. IISDebugOutput(_T("ExportToBlob:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  1527. goto ExportToBlob_Exit;
  1528. }
  1529. // allocate some space and then try it.
  1530. pcchB64Out = pcchB64Out * sizeof(char);
  1531. pszB64Out = (char *) ::CoTaskMemAlloc(pcchB64Out);
  1532. if (NULL == pszB64Out)
  1533. {
  1534. hr = E_OUTOFMEMORY;
  1535. IISDebugOutput(_T("ExportToBlob:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  1536. goto ExportToBlob_Exit;
  1537. }
  1538. err = Base64EncodeA(DataBlob.pbData,DataBlob.cbData,pszB64Out,&pcchB64Out);
  1539. if (err != ERROR_SUCCESS)
  1540. {
  1541. if (NULL != pszB64Out){CoTaskMemFree(pszB64Out);pszB64Out = NULL;}
  1542. hr = E_FAIL;
  1543. IISDebugOutput(_T("ExportToBlob:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  1544. goto ExportToBlob_Exit;
  1545. }
  1546. // copy the new memory to pass back
  1547. *cbBufferSize = pcchB64Out;
  1548. *pbBuffer = pszB64Out;
  1549. hr = ERROR_SUCCESS;
  1550. ExportToBlob_Exit:
  1551. if (NULL != DataBlob.pbData)
  1552. {
  1553. // perhaspse will this up with zeros...
  1554. SecureZeroMemory(DataBlob.pbData, DataBlob.cbData);
  1555. ::CoTaskMemFree(DataBlob.pbData);DataBlob.pbData = NULL;
  1556. }
  1557. if (NULL != hStore){CertCloseStore(hStore, 0);hStore=NULL;}
  1558. if (NULL != pCertContext) {CertFreeCertificateContext(pCertContext);pCertContext=NULL;}
  1559. return hr;
  1560. }
  1561. STDMETHODIMP
  1562. CIISCertObj::Copy(
  1563. VARIANT_BOOL bAllowExport,
  1564. VARIANT_BOOL bOverWriteExisting,
  1565. BSTR bstrDestinationServerName,
  1566. BSTR bstrDestinationServerInstance,
  1567. VARIANT varDestinationServerUserName,
  1568. VARIANT varDestinationServerPassword
  1569. )
  1570. {
  1571. IISDebugOutput(_T("Copy\r\n"));
  1572. VARIANT VtArray;
  1573. // Check mandatory properties
  1574. if ( bstrDestinationServerName == NULL || *bstrDestinationServerName == 0
  1575. || bstrDestinationServerInstance == NULL || *bstrDestinationServerInstance == 0)
  1576. {
  1577. return E_INVALIDARG;
  1578. }
  1579. // ------------------------
  1580. // buffer overflow paranoia
  1581. // check all parameters...
  1582. // ------------------------
  1583. if (wcslen(bstrDestinationServerName) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  1584. if (wcslen(bstrDestinationServerInstance) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  1585. return CopyOrMove(VARIANT_FALSE,VARIANT_FALSE,bAllowExport,bOverWriteExisting,&VtArray,
  1586. bstrDestinationServerName,bstrDestinationServerInstance,
  1587. varDestinationServerUserName,varDestinationServerPassword);
  1588. }
  1589. STDMETHODIMP
  1590. CIISCertObj::Move(
  1591. VARIANT_BOOL bAllowExport,
  1592. VARIANT_BOOL bOverWriteExisting,
  1593. BSTR bstrDestinationServerName,
  1594. BSTR bstrDestinationServerInstance,
  1595. VARIANT varDestinationServerUserName,
  1596. VARIANT varDestinationServerPassword
  1597. )
  1598. {
  1599. IISDebugOutput(_T("Move\r\n"));
  1600. VARIANT VtArray;
  1601. // Check mandatory properties
  1602. if ( bstrDestinationServerName == NULL || *bstrDestinationServerName == 0
  1603. || bstrDestinationServerInstance == NULL || *bstrDestinationServerInstance == 0)
  1604. {
  1605. return E_INVALIDARG;
  1606. }
  1607. // ------------------------
  1608. // buffer overflow paranoia
  1609. // check all parameters...
  1610. // ------------------------
  1611. if (wcslen(bstrDestinationServerName) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  1612. if (wcslen(bstrDestinationServerInstance) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  1613. return CopyOrMove(VARIANT_TRUE,VARIANT_FALSE,bAllowExport,bOverWriteExisting,&VtArray,
  1614. bstrDestinationServerName,bstrDestinationServerInstance,
  1615. varDestinationServerUserName,varDestinationServerPassword);
  1616. }
  1617. static BOOL
  1618. CreateCompletePath(const CString& inst, CString& res)
  1619. {
  1620. CString str;
  1621. if (NULL != CMetabasePath::GetLastNodeName(inst, str))
  1622. {
  1623. CMetabasePath path(TRUE, SZ_MBN_WEB, str);
  1624. res = path;
  1625. return TRUE;
  1626. }
  1627. return FALSE;
  1628. }
  1629. HRESULT
  1630. CIISCertObj::CopyOrMove(
  1631. VARIANT_BOOL bMove,
  1632. VARIANT_BOOL bCopyCertDontInstallRetHash,
  1633. VARIANT_BOOL bAllowExport,
  1634. VARIANT_BOOL bOverWriteExisting,
  1635. VARIANT * pVtArray,
  1636. BSTR bstrDestinationServerName,
  1637. BSTR bstrDestinationServerInstance,
  1638. VARIANT varDestinationServerUserName,
  1639. VARIANT varDestinationServerPassword
  1640. )
  1641. {
  1642. IISDebugOutput(_T("CopyOrMove\r\n"));
  1643. HRESULT hr = E_FAIL;
  1644. DWORD cbEncodedSize = 0;
  1645. char * pszEncodedString = NULL;
  1646. BOOL bGuessingUserNamePass = FALSE;
  1647. DWORD blob_cbData;
  1648. BYTE * blob_pbData = NULL;
  1649. VARIANT_BOOL bPrivateKey = VARIANT_TRUE;
  1650. VARIANT_BOOL bCertChain = VARIANT_FALSE;
  1651. CComBSTR csDestinationServerName = bstrDestinationServerName;
  1652. CComBSTR csDestinationServerUserName;
  1653. CComBSTR csDestinationServerUserPassword;
  1654. CComBSTR csTempPassword;
  1655. WCHAR * pwszPassword = NULL;
  1656. BSTR bstrPassword = NULL;
  1657. IIISCertObj * pObj = NULL;
  1658. IIISCertObj * pObj2 = NULL;
  1659. // Check mandatory properties
  1660. if ( bstrDestinationServerName == NULL || *bstrDestinationServerName == 0
  1661. || bstrDestinationServerInstance == NULL || *bstrDestinationServerInstance == 0)
  1662. {
  1663. return E_INVALIDARG;
  1664. }
  1665. // We could have local dest case, when both destination and source servers
  1666. // are the same machine
  1667. BOOL bLocal = FALSE;
  1668. if (0 == m_ServerName.Length())
  1669. {
  1670. // then this side is local that's for sure.
  1671. if (IsServerLocal(bstrDestinationServerName))
  1672. {
  1673. bLocal = TRUE;
  1674. }
  1675. }
  1676. else
  1677. {
  1678. if (0 == _tcsicmp(m_ServerName,bstrDestinationServerName))
  1679. {
  1680. if (IsServerLocal(m_ServerName))
  1681. {
  1682. bLocal = TRUE;
  1683. }
  1684. else
  1685. {
  1686. bLocal = FALSE;
  1687. }
  1688. }
  1689. }
  1690. if (bLocal)
  1691. {
  1692. // All we need to do here is to add hash and store name to the destination instance
  1693. // and optionally remove it from the source instance
  1694. LPWSTR pwd = NULL;
  1695. if (m_lpwszUserPasswordEncrypted)
  1696. {
  1697. hr = DecryptMemoryPassword((LPWSTR) m_lpwszUserPasswordEncrypted,
  1698. &pwd, m_cbUserPasswordEncrypted);
  1699. if (FAILED(hr))
  1700. {
  1701. IISDebugOutput(_T("CopyOrMove:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  1702. goto Copy_Exit;
  1703. }
  1704. }
  1705. CComAuthInfo auth(m_ServerName, m_UserName, pwd);
  1706. //COSERVERINFO * pcsiName = auth.CreateServerInfoStruct(RPC_C_AUTHN_LEVEL_PKT_PRIVACY);
  1707. CMetaKey key(&auth);
  1708. CString src;
  1709. CreateCompletePath(m_InstanceName, src);
  1710. if (FAILED(hr = key.Open(METADATA_PERMISSION_READ|METADATA_PERMISSION_WRITE, src)))
  1711. {
  1712. IISDebugOutput(_T("CopyOrMove:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  1713. goto Copy_Exit;
  1714. }
  1715. CString store_name;
  1716. CBlob hash;
  1717. if ( FAILED(hr = key.QueryValue(MD_SSL_CERT_STORE_NAME, store_name))
  1718. || FAILED(hr = key.QueryValue(MD_SSL_CERT_HASH, hash))
  1719. )
  1720. {
  1721. IISDebugOutput(_T("CopyOrMove:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  1722. goto Copy_Exit;
  1723. }
  1724. if (bMove)
  1725. {
  1726. // The user could have specified to move the
  1727. // certificate to and from the same site
  1728. // if this is the case, then don't delete the metabase entries...
  1729. BOOL bSameNode = FALSE;
  1730. CString dst;
  1731. CreateCompletePath(bstrDestinationServerInstance, dst);
  1732. if (!src.IsEmpty() && !dst.IsEmpty())
  1733. {
  1734. if (0 == src.CompareNoCase(dst))
  1735. {
  1736. bSameNode = TRUE;
  1737. }
  1738. }
  1739. if (!bSameNode)
  1740. {
  1741. VERIFY((SUCCEEDED(key.DeleteValue(MD_SSL_CERT_HASH))));
  1742. VERIFY((SUCCEEDED(key.DeleteValue(MD_SSL_CERT_STORE_NAME))));
  1743. DWORD dwSSL = 0;
  1744. CString root = _T("root");
  1745. if (SUCCEEDED(key.QueryValue(MD_SSL_ACCESS_PERM, dwSSL, NULL, root)) && dwSSL > 0)
  1746. {
  1747. VERIFY(SUCCEEDED(key.SetValue(MD_SSL_ACCESS_PERM, 0, NULL, root)));
  1748. }
  1749. CStringListEx sl;
  1750. if (SUCCEEDED(key.QueryValue(MD_SECURE_BINDINGS, sl, NULL, root)))
  1751. {
  1752. VERIFY(SUCCEEDED(key.DeleteValue(MD_SECURE_BINDINGS, root)));
  1753. }
  1754. DWORD dwMDIdentifier, dwMDAttributes, dwMDUserType,dwMDDataType;
  1755. VERIFY(CMetaKey::GetMDFieldDef(MD_SSL_ACCESS_PERM, dwMDIdentifier, dwMDAttributes,
  1756. dwMDUserType, dwMDDataType));
  1757. hr = key.GetDataPaths(sl, dwMDIdentifier,dwMDDataType);
  1758. if (SUCCEEDED(hr) && !sl.empty())
  1759. {
  1760. CStringListEx::iterator it = sl.begin();
  1761. while (it != sl.end())
  1762. {
  1763. CString& str2 = (*it++);
  1764. if (SUCCEEDED(key.QueryValue(MD_SSL_ACCESS_PERM, dwSSL, NULL, str2)) && dwSSL > 0)
  1765. {
  1766. key.SetValue(MD_SSL_ACCESS_PERM, 0, NULL, str2);
  1767. }
  1768. }
  1769. }
  1770. }
  1771. }
  1772. key.Close();
  1773. CString dst;
  1774. CreateCompletePath(bstrDestinationServerInstance, dst);
  1775. if (FAILED(hr = key.Open(METADATA_PERMISSION_READ|METADATA_PERMISSION_WRITE, dst)))
  1776. {
  1777. IISDebugOutput(_T("CopyOrMove:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  1778. goto Copy_Exit;
  1779. }
  1780. // Overwrite should be set, or it doesn't make any sence
  1781. // ASSERT(bOverWriteExisting);
  1782. if (FAILED(hr = key.SetValue(MD_SSL_CERT_HASH, hash)))
  1783. {
  1784. IISDebugOutput(_T("CopyOrMove:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  1785. goto Copy_Exit;
  1786. }
  1787. if (FAILED(hr = key.SetValue(MD_SSL_CERT_STORE_NAME, store_name)))
  1788. {
  1789. IISDebugOutput(_T("CopyOrMove:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  1790. goto Copy_Exit;
  1791. }
  1792. if (pwd)
  1793. {
  1794. // security percaution:Make sure to zero out memory that temporary password was used for.
  1795. SecureZeroMemory(pwd, m_cbUserPasswordEncrypted);
  1796. LocalFree(pwd);pwd = NULL;
  1797. }
  1798. goto Copy_Exit;
  1799. }
  1800. // if the optional parameter serverusername isn't empty, use that; otherwise, use...
  1801. if (V_VT(&varDestinationServerUserName) != VT_ERROR)
  1802. {
  1803. VARIANT varBstrUserName;
  1804. VariantInit(&varBstrUserName);
  1805. if (FAILED(VariantChangeType(&varBstrUserName, &varDestinationServerUserName, 0, VT_BSTR)))
  1806. {
  1807. IISDebugOutput(_T("CopyOrMove:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  1808. goto Copy_Exit;
  1809. }
  1810. csDestinationServerUserName = V_BSTR(&varBstrUserName);
  1811. VariantClear(&varBstrUserName);
  1812. }
  1813. else
  1814. {
  1815. // it's empty so don't use it
  1816. //csDestinationServerUserName = varDestinationServerUserName;
  1817. bGuessingUserNamePass = TRUE;
  1818. csDestinationServerUserName = m_UserName;
  1819. }
  1820. // if the optional parameter serverusername isn't empty, use that; otherwise, use...
  1821. if (V_VT(&varDestinationServerPassword) != VT_ERROR)
  1822. {
  1823. VARIANT varBstrUserPassword;
  1824. VariantInit(&varBstrUserPassword);
  1825. if (FAILED(VariantChangeType(&varBstrUserPassword,
  1826. &varDestinationServerPassword, 0, VT_BSTR)))
  1827. {
  1828. IISDebugOutput(_T("CopyOrMove:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  1829. goto Copy_Exit;
  1830. }
  1831. csDestinationServerUserPassword = V_BSTR(&varBstrUserPassword);
  1832. VariantClear(&varBstrUserPassword);
  1833. }
  1834. else
  1835. {
  1836. if (bGuessingUserNamePass)
  1837. {
  1838. LPWSTR lpwstrTempPassword = NULL;
  1839. if (m_lpwszUserPasswordEncrypted)
  1840. {
  1841. hr = DecryptMemoryPassword((LPWSTR) m_lpwszUserPasswordEncrypted,
  1842. &lpwstrTempPassword,m_cbUserPasswordEncrypted);
  1843. if (FAILED(hr))
  1844. {
  1845. IISDebugOutput(_T("CopyOrMove:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  1846. goto Copy_Exit;
  1847. }
  1848. }
  1849. // set password from decrypted value
  1850. csDestinationServerUserPassword = lpwstrTempPassword;
  1851. // clean up temporary password
  1852. if (lpwstrTempPassword)
  1853. {
  1854. // security percaution:Make sure to zero out memory that temporary password was used for.
  1855. SecureZeroMemory(lpwstrTempPassword,m_cbUserPasswordEncrypted);
  1856. LocalFree(lpwstrTempPassword);
  1857. lpwstrTempPassword = NULL;
  1858. }
  1859. }
  1860. else
  1861. {
  1862. // maybe the password was intended to be empty!
  1863. }
  1864. }
  1865. // --------------------------
  1866. // step 1.
  1867. // 1st of all check if we have access to
  1868. // both the servers!!!!
  1869. // --------------------------
  1870. // 1st we have to get the certblob from the Server#1
  1871. // so call export to get the data
  1872. hr = S_OK;
  1873. pObj = GetObject(&hr);
  1874. if (FAILED(hr))
  1875. {
  1876. IISDebugOutput(_T("CopyOrMove:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  1877. goto Copy_Exit;
  1878. }
  1879. // Logon to that server's CertObj.dll with the credentials supplied...
  1880. //
  1881. // if there were no credential's supplied then just use the ones that are in our object....
  1882. //
  1883. // if that doesn't work then try just the logged on user.
  1884. pObj2 = GetObject(&hr,csDestinationServerName,csDestinationServerUserName,
  1885. csDestinationServerUserPassword);
  1886. if (FAILED(hr))
  1887. {
  1888. IISDebugOutput(_T("CIISCertObj::CopyOrMove:Copy csDestinationServerName=%s,csDestinationServerUserName=%s\n"),
  1889. (LPCTSTR) csDestinationServerName,(LPCTSTR) csDestinationServerUserName);
  1890. if (bGuessingUserNamePass)
  1891. {
  1892. // try something else.
  1893. }
  1894. IISDebugOutput(_T("CopyOrMove:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  1895. goto Copy_Exit;
  1896. }
  1897. //
  1898. // Create a unique password
  1899. //
  1900. // use the new secure password generator
  1901. // unfortunately this baby doesn't use unicode.
  1902. // so we'll call it and then convert it to unicode afterwards.
  1903. pwszPassword = CreatePassword(TEMP_PASSWORD_LENGTH);
  1904. // if its null -- ah, we can still use that...
  1905. bstrPassword = SysAllocString(pwszPassword);
  1906. // -----------------------------------
  1907. // step 2.
  1908. // okay we have access to both servers
  1909. // Grab the cert from server #1
  1910. // -----------------------------------
  1911. // Get data from the remote/local iis store return it back as a blob.
  1912. // The blob could be returned back as Base64 encoded so check that flag
  1913. // don't need to free _bstr_t
  1914. {
  1915. _bstr_t bstrInstName(m_InstanceName);
  1916. hr = ExportToBlobProxy(pObj, bstrInstName, bstrPassword,
  1917. bPrivateKey, bCertChain, &cbEncodedSize, &pszEncodedString);
  1918. }
  1919. if (FAILED(hr))
  1920. {
  1921. IISDebugOutput(_T("CopyOrMove:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  1922. goto Copy_Exit;
  1923. }
  1924. int err;
  1925. // The data we got back was Base64 encoded to remove nulls.
  1926. // we need to decode it back to it's original format.
  1927. if ((err = Base64DecodeA(pszEncodedString,cbEncodedSize,NULL,&blob_cbData)) != ERROR_SUCCESS)
  1928. {
  1929. SetLastError(err);
  1930. hr = HRESULT_FROM_WIN32(err);
  1931. IISDebugOutput(_T("CopyOrMove:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  1932. goto Copy_Exit;
  1933. }
  1934. blob_pbData = (BYTE *) malloc(blob_cbData);
  1935. if (NULL == blob_pbData)
  1936. {
  1937. hr = E_OUTOFMEMORY;
  1938. IISDebugOutput(_T("CopyOrMove:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  1939. goto Copy_Exit;
  1940. }
  1941. if ((err = Base64DecodeA(pszEncodedString,cbEncodedSize,blob_pbData,&blob_cbData)) != ERROR_SUCCESS)
  1942. {
  1943. SetLastError(err);
  1944. hr = HRESULT_FROM_WIN32(err);
  1945. IISDebugOutput(_T("CopyOrMove:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  1946. goto Copy_Exit;
  1947. }
  1948. // -----------------------------------
  1949. // step 3.
  1950. // okay we have access to both servers
  1951. // we have the cert blob from server#1 in memory
  1952. // now we need to push this blob into the server#2
  1953. // -----------------------------------
  1954. if (bCopyCertDontInstallRetHash)
  1955. {
  1956. DWORD cbHashBufferSize = 0;
  1957. char * pszHashBuffer = NULL;
  1958. hr = ImportFromBlobProxy(pObj2, _T("none"), bstrPassword,
  1959. VARIANT_FALSE, bAllowExport, bOverWriteExisting, blob_cbData,
  1960. blob_pbData, &cbHashBufferSize, &pszHashBuffer);
  1961. if (SUCCEEDED(hr))
  1962. {
  1963. hr = HereIsBinaryGimmieVtArray(cbHashBufferSize,pszHashBuffer,pVtArray,FALSE);
  1964. }
  1965. // free the memory that was alloced for us
  1966. if (0 != cbHashBufferSize)
  1967. {
  1968. if (pszHashBuffer)
  1969. {
  1970. ::CoTaskMemFree(pszHashBuffer);
  1971. }
  1972. }
  1973. }
  1974. else
  1975. {
  1976. hr = ImportFromBlobProxy(pObj2, bstrDestinationServerInstance, bstrPassword,
  1977. VARIANT_TRUE, bAllowExport, bOverWriteExisting, blob_cbData,
  1978. blob_pbData, 0, NULL);
  1979. }
  1980. if (FAILED(hr))
  1981. {
  1982. // This could have failed with CRYPT_E_EXISTS
  1983. // if the certificate already exists in the cert store.
  1984. if (CRYPT_E_EXISTS == hr)
  1985. {
  1986. if (TRUE == bOverWriteExisting || VARIANT_TRUE == bOverWriteExisting)
  1987. {
  1988. hr = S_OK;
  1989. }
  1990. else
  1991. {
  1992. IISDebugOutput(_T("CopyOrMove:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  1993. goto Copy_Exit;
  1994. }
  1995. }
  1996. else
  1997. {
  1998. IISDebugOutput(_T("CopyOrMove:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  1999. goto Copy_Exit;
  2000. }
  2001. }
  2002. // we successfully copied the cert from machine #1 to machine #2.
  2003. // lets see if we need to delete the original cert!.
  2004. // VARIANT_TRUE is passed when invoked from VB! Make sure to check that too!
  2005. if (TRUE == bMove || VARIANT_TRUE == bMove)
  2006. {
  2007. // Do not delete the cert if it was moved to the same machine!!!!!!!!!!!!!!
  2008. // For some reason we need to SysAllocString these instance names
  2009. // if not com will AV when marshalling...
  2010. // don't need to free _bstr_t
  2011. _bstr_t bstrInstName2(m_InstanceName);
  2012. hr = pObj->put_InstanceName(bstrInstName2);
  2013. if (SUCCEEDED(hr))
  2014. {
  2015. hr = pObj->RemoveCert(pObj != pObj2, bPrivateKey);
  2016. if (FAILED(hr))
  2017. {
  2018. IISDebugOutput(_T("CopyOrMove:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  2019. goto Copy_Exit;
  2020. }
  2021. }
  2022. }
  2023. hr = S_OK;
  2024. Copy_Exit:
  2025. if (pwszPassword)
  2026. {
  2027. LocalFree(pwszPassword);
  2028. }
  2029. if (NULL != bstrPassword)
  2030. {
  2031. SysFreeString(bstrPassword);
  2032. }
  2033. if (blob_pbData != NULL)
  2034. {
  2035. SecureZeroMemory(blob_pbData, blob_cbData);
  2036. free(blob_pbData);blob_pbData=NULL;
  2037. }
  2038. if (pszEncodedString != NULL)
  2039. {
  2040. SecureZeroMemory(pszEncodedString,cbEncodedSize);
  2041. CoTaskMemFree(pszEncodedString);pszEncodedString=NULL;
  2042. }
  2043. // release remote object
  2044. if (pObj != NULL)
  2045. {
  2046. if (pObj != this)
  2047. {
  2048. DelRemoteInterface(pObj);
  2049. pObj->Release();pObj=NULL;
  2050. }
  2051. }
  2052. // release remote object
  2053. if (pObj2 != NULL)
  2054. {
  2055. if (pObj2 != this)
  2056. {
  2057. DelRemoteInterface(pObj2);
  2058. pObj2->Release();pObj2=NULL;
  2059. }
  2060. }
  2061. return hr;
  2062. }
  2063. //////////////////////////////////////////////////
  2064. // These are not part of the class
  2065. HRESULT
  2066. RemoveCertProxy(
  2067. IIISCertObj * pObj,
  2068. BSTR bstrInstanceName,
  2069. VARIANT_BOOL bPrivateKey
  2070. )
  2071. {
  2072. CheckPointer(pObj, E_POINTER);
  2073. HRESULT hr = E_FAIL;
  2074. // Check mandatory properties
  2075. if (bstrInstanceName == NULL || *bstrInstanceName == 0)
  2076. {
  2077. return E_INVALIDARG;
  2078. }
  2079. // ------------------------
  2080. // buffer overflow paranoia
  2081. // check all parameters...
  2082. // ------------------------
  2083. if (wcslen(bstrInstanceName) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  2084. if (pObj)
  2085. {
  2086. hr = pObj->put_InstanceName(bstrInstanceName);
  2087. if (SUCCEEDED(hr))
  2088. {
  2089. hr = pObj->RemoveCert(VARIANT_TRUE, bPrivateKey);
  2090. }
  2091. }
  2092. return hr;
  2093. }
  2094. HRESULT
  2095. ImportFromBlobProxy(
  2096. IIISCertObj * pObj,
  2097. BSTR InstanceName,
  2098. BSTR Password,
  2099. VARIANT_BOOL bInstallToMetabase,
  2100. VARIANT_BOOL bAllowExport,
  2101. VARIANT_BOOL bOverWriteExisting,
  2102. DWORD actual,
  2103. BYTE *pData,
  2104. DWORD *pcbHashBufferSize,
  2105. char **pbHashBuffer
  2106. )
  2107. {
  2108. CheckPointer(pObj, E_POINTER);
  2109. CheckPointer(pData, E_POINTER);
  2110. HRESULT hr = E_FAIL;
  2111. char *pszB64Out = NULL;
  2112. DWORD pcchB64Out = 0;
  2113. // base64 encode the data for transfer to the remote machine
  2114. DWORD err;
  2115. pcchB64Out = 0;
  2116. // Check mandatory properties
  2117. if (InstanceName == NULL || *InstanceName == 0)
  2118. {
  2119. return E_INVALIDARG;
  2120. }
  2121. // ------------------------
  2122. // buffer overflow paranoia
  2123. // check all parameters...
  2124. // ------------------------
  2125. if (wcslen(InstanceName) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  2126. // Encode it so that it can be passed back as a string (there are no Nulls in it)
  2127. err = Base64EncodeA(pData,actual,NULL,&pcchB64Out);
  2128. if (err != ERROR_SUCCESS)
  2129. {
  2130. hr = E_FAIL;
  2131. IISDebugOutput(_T("ImportFromBlobProxy:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  2132. goto ImportFromBlobProxy_Exit;
  2133. }
  2134. // allocate some space and then try it.
  2135. pcchB64Out = pcchB64Out * sizeof(char);
  2136. pszB64Out = (char *) ::CoTaskMemAlloc(pcchB64Out);
  2137. if (NULL == pszB64Out)
  2138. {
  2139. hr = E_OUTOFMEMORY;
  2140. IISDebugOutput(_T("ImportFromBlobProxy:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  2141. goto ImportFromBlobProxy_Exit;
  2142. }
  2143. err = Base64EncodeA(pData,actual,pszB64Out,&pcchB64Out);
  2144. if (err != ERROR_SUCCESS)
  2145. {
  2146. hr = E_FAIL;
  2147. IISDebugOutput(_T("ImportFromBlobProxy:FAIL:Line=%d,0x%x\r\n"),__LINE__,hr);
  2148. goto ImportFromBlobProxy_Exit;
  2149. }
  2150. // the data to send are now in these variables
  2151. // pcchB64Out
  2152. // pszB64Out
  2153. if (NULL == pbHashBuffer)
  2154. {
  2155. hr = pObj->ImportFromBlob(InstanceName, Password, bInstallToMetabase,
  2156. bAllowExport, bOverWriteExisting, pcchB64Out, pszB64Out);
  2157. }
  2158. else
  2159. {
  2160. hr = pObj->ImportFromBlobGetHash(InstanceName, Password,
  2161. bInstallToMetabase, bAllowExport, bOverWriteExisting, pcchB64Out,
  2162. pszB64Out, pcbHashBufferSize, pbHashBuffer);
  2163. }
  2164. if (SUCCEEDED(hr))
  2165. {
  2166. // otherwise hey, The data was imported!
  2167. hr = S_OK;
  2168. }
  2169. ImportFromBlobProxy_Exit:
  2170. if (NULL != pszB64Out)
  2171. {
  2172. SecureZeroMemory(pszB64Out,pcchB64Out);
  2173. CoTaskMemFree(pszB64Out);
  2174. }
  2175. return hr;
  2176. }
  2177. //
  2178. // Proxy to the real call ExportToBlob()
  2179. // this function figures out how much space to allocate, and then calls ExportToBlob().
  2180. //
  2181. // if succeeded and they get the blob back,
  2182. // and the caller must call CoTaskMemFree()
  2183. //
  2184. HRESULT
  2185. ExportToBlobProxy(
  2186. IIISCertObj * pObj,
  2187. BSTR InstanceName,
  2188. BSTR Password,
  2189. VARIANT_BOOL bPrivateKey,
  2190. VARIANT_BOOL bCertChain,
  2191. DWORD * pcbSize,
  2192. char ** pBlobBinary
  2193. )
  2194. {
  2195. CheckPointer(pObj, E_POINTER);
  2196. HRESULT hr = E_FAIL;
  2197. DWORD cbEncodedSize = 0;
  2198. char * pszEncodedString = NULL;
  2199. *pBlobBinary = NULL;
  2200. // Check mandatory properties
  2201. if ( InstanceName == NULL || *InstanceName == 0
  2202. || Password == NULL || *Password == 0
  2203. )
  2204. {
  2205. return E_INVALIDARG;
  2206. }
  2207. // ------------------------
  2208. // buffer overflow paranoia
  2209. // check all parameters...
  2210. // ------------------------
  2211. if (wcslen(InstanceName) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  2212. if (wcslen(Password) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  2213. // call the remote function that will run on the remote/local machine
  2214. // and grab it's certificate from iis and send it back to us
  2215. hr = pObj->ExportToBlob(InstanceName, Password, bPrivateKey, bCertChain,
  2216. &cbEncodedSize, (char **) &pszEncodedString);
  2217. if (ERROR_SUCCESS == hr)
  2218. {
  2219. // otherwise hey, we've got our data!
  2220. // copy it back
  2221. *pcbSize = cbEncodedSize;
  2222. *pBlobBinary = pszEncodedString;
  2223. hr = S_OK;
  2224. }
  2225. return hr;
  2226. }