Source code of Windows XP (NT5)
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.

1499 lines
32 KiB

  1. /*++
  2. Copyright (c) 1994-1998 Microsoft Corporation
  3. Module Name :
  4. authent.cpp
  5. Abstract:
  6. WWW Authentication Dialog
  7. Author:
  8. Ronald Meijer (ronaldm)
  9. Project:
  10. Internet Services Manager
  11. Revision History:
  12. --*/
  13. //
  14. // Include Files
  15. //
  16. #include "stdafx.h"
  17. #include "w3scfg.h"
  18. #include "wincrypt.h"
  19. #include "cryptui.h"
  20. #include "certmap.h"
  21. #include "basdom.h"
  22. #include "anondlg.h"
  23. #include "seccom.h"
  24. #ifdef _DEBUG
  25. #define new DEBUG_NEW
  26. #undef THIS_FILE
  27. static char THIS_FILE[] = __FILE__;
  28. #endif
  29. const LPCTSTR SZ_CTL_DEFAULT_STORE_NAME = _T("CA");
  30. const LPCSTR szOID_IIS_VIRTUAL_SERVER = "1.3.6.1.4.1.311.30.1";
  31. //
  32. // Needed for GetModuleFileName() below:
  33. //
  34. extern HINSTANCE hInstance;
  35. CSecCommDlg::CSecCommDlg(
  36. IN LPCTSTR lpstrServerName,
  37. IN LPCTSTR lpstrMetaPath,
  38. IN CString & strBasicDomain,
  39. IN DWORD & dwAuthFlags,
  40. IN DWORD & dwAccessPermissions,
  41. IN BOOL fIsMasterInstance,
  42. IN BOOL fSSLSupported,
  43. IN BOOL fSSL128Supported,
  44. IN BOOL fU2Installed,
  45. IN CString & strCTLIdentifier,
  46. IN CString & strCTLStoreName,
  47. IN BOOL fEditCTLs,
  48. IN BOOL fIsLocal,
  49. IN CWnd * pParent OPTIONAL
  50. )
  51. /*++
  52. Routine Description:
  53. Authentication dialog constructor
  54. Arguments:
  55. LPCTSTR lpstrServerName : Server name
  56. LPCTSTR lpstrMetaPath : Metabase path
  57. CString & strBasicDomain : Basic domain name
  58. DWORD & dwAuthFlags : Authorization flags
  59. DWORD & dwAccessPermissions : Access permissions
  60. BOOL fIsMasterInstance : Master instance
  61. BOOL fSSLSupported : TRUE if SSL is supported
  62. BOOL fSSL128Supported : TRUE if 128 bit SSL is supported
  63. CString & strCTLIdentifier
  64. CString & strCTLStoreName
  65. BOOL fEditCTLs
  66. BOOL fIsLocal
  67. CWnd * pParent : Optional parent window
  68. Return Value:
  69. N/A
  70. --*/
  71. : CDialog(CSecCommDlg::IDD, pParent),
  72. m_strServerName(lpstrServerName),
  73. m_strMetaPath(lpstrMetaPath),
  74. m_dwAuthFlags(dwAuthFlags),
  75. m_dwAccessPermissions(dwAccessPermissions),
  76. m_fIsMasterInstance(fIsMasterInstance),
  77. m_fSSLEnabledOnServer(FALSE),
  78. m_fSSLInstalledOnServer(FALSE),
  79. m_fSSL128Supported(fSSL128Supported),
  80. m_fU2Installed(fU2Installed),
  81. m_hCTLStore(NULL),
  82. m_bCTLDirty(FALSE),
  83. m_iLastUsedCert(-1),
  84. m_fIsLocal(fIsLocal),
  85. m_fEditCTLs(fEditCTLs)
  86. {
  87. #if 0 // Keep Class Wizard happy
  88. //{{AFX_DATA_INIT(CSecCommDlg)
  89. m_nRadioNoCert = -1;
  90. m_fAccountMapping = FALSE;
  91. //m_fEnableDS = FALSE;
  92. m_fRequireSSL = FALSE;
  93. m_fEnableCtl = FALSE;
  94. m_strCtl = _T("");
  95. //}}AFX_DATA_INIT
  96. #endif // 0
  97. if (fSSLSupported)
  98. {
  99. ::IsSSLEnabledOnServer(
  100. m_strServerName,
  101. m_fSSLInstalledOnServer,
  102. m_fSSLEnabledOnServer
  103. );
  104. }
  105. else
  106. {
  107. m_fSSLInstalledOnServer = m_fSSLEnabledOnServer = FALSE;
  108. }
  109. if (IS_FLAG_SET(m_dwAccessPermissions, MD_ACCESS_REQUIRE_CERT))
  110. {
  111. m_nRadioNoCert = RADIO_REQ_CERT;
  112. }
  113. else if (IS_FLAG_SET(m_dwAccessPermissions, MD_ACCESS_NEGO_CERT))
  114. {
  115. m_nRadioNoCert = RADIO_ACCEPT_CERT;
  116. }
  117. else
  118. {
  119. m_nRadioNoCert = RADIO_NO_CERT;
  120. }
  121. m_fRequireSSL = m_fSSLInstalledOnServer
  122. && IS_FLAG_SET(m_dwAccessPermissions, MD_ACCESS_SSL);
  123. m_fRequire128BitSSL = m_fSSLInstalledOnServer
  124. && IS_FLAG_SET(m_dwAccessPermissions, MD_ACCESS_SSL128);
  125. m_fAccountMapping = m_fSSLInstalledOnServer
  126. && IS_FLAG_SET(m_dwAccessPermissions, MD_ACCESS_MAP_CERT);
  127. //
  128. // CTL information.
  129. //
  130. if (fEditCTLs)
  131. {
  132. m_strCTLIdentifier = strCTLIdentifier;
  133. m_strCTLStoreName = strCTLStoreName;
  134. if (m_strCTLStoreName.IsEmpty())
  135. {
  136. m_strCTLStoreName = SZ_CTL_DEFAULT_STORE_NAME;
  137. }
  138. m_strCtl.Empty();
  139. m_fEnableCtl = !m_strCTLIdentifier.IsEmpty()
  140. && !strCTLStoreName.IsEmpty();
  141. //
  142. // For now, we only allow enabling when editing the local machine
  143. //
  144. m_fEnableCtl &= m_fIsLocal;
  145. }
  146. else
  147. {
  148. m_fEnableCtl = FALSE;
  149. m_check_EnableCtl.EnableWindow(FALSE);
  150. }
  151. }
  152. CSecCommDlg::~CSecCommDlg()
  153. /*++
  154. Routine Description:
  155. custom destructor for CSecCommDlg
  156. Arguments:
  157. None
  158. Return Value:
  159. None
  160. --*/
  161. {
  162. // dereference the CTL context pointers in the combo box
  163. //CleanUpCTLList();
  164. }
  165. void
  166. CSecCommDlg::DoDataExchange(
  167. IN CDataExchange * pDX
  168. )
  169. /*++
  170. Routine Description:
  171. Initialise/Store control data
  172. Arguments:
  173. CDataExchange * pDX - DDX/DDV control structure
  174. Return Value:
  175. None
  176. --*/
  177. {
  178. CDialog::DoDataExchange(pDX);
  179. //{{AFX_DATA_MAP(CSecCommDlg)
  180. DDX_Radio(pDX, IDC_RADIO_NO_CERT, m_nRadioNoCert);
  181. DDX_Check(pDX, IDC_CHECK_SSL_ACCOUNT_MAPPING, m_fAccountMapping);
  182. DDX_Check(pDX, IDC_CHECK_REQUIRE_SSL, m_fRequireSSL);
  183. DDX_Check(pDX, IDC_CHECK_REQUIRE_128BIT, m_fRequire128BitSSL);
  184. DDX_Check(pDX, IDC_CHECK_ENABLE_CTL, m_fEnableCtl);
  185. DDX_CBString(pDX, IDC_COMBO_CTL, m_strCtl);
  186. DDX_Control(pDX, IDC_CTL_SEPERATOR, m_static_CTLSeparator);
  187. DDX_Control(pDX, IDC_STATIC_CURRENT_CTL, m_static_CTLPrompt);
  188. DDX_Control(pDX, IDC_CHECK_SSL_ACCOUNT_MAPPING, m_check_AccountMapping);
  189. DDX_Control(pDX, IDC_CHECK_REQUIRE_SSL, m_check_RequireSSL);
  190. DDX_Control(pDX, IDC_CHECK_REQUIRE_128BIT, m_check_Require128BitSSL);
  191. DDX_Control(pDX, IDC_CHECK_ENABLE_CTL, m_check_EnableCtl);
  192. DDX_Control(pDX, IDC_BUTTON_EDIT_CTL, m_button_EditCtl);
  193. DDX_Control(pDX, IDC_BUTTON_NEW_CTL, m_button_NewCtl);
  194. DDX_Control(pDX, IDC_CERTMAPCTRL1, m_ocx_ClientMappings);
  195. DDX_Control(pDX, IDC_COMBO_CTL, m_combo_ctl);
  196. //}}AFX_DATA_MAP
  197. //
  198. // Private DDX Controls
  199. //
  200. DDX_Control(pDX, IDC_RADIO_REQUIRE_CERT, m_radio_RequireCert);
  201. DDX_Control(pDX, IDC_RADIO_ACCEPT_CERT, m_radio_AcceptCert);
  202. }
  203. //
  204. // Message Map
  205. //
  206. BEGIN_MESSAGE_MAP(CSecCommDlg, CDialog)
  207. //{{AFX_MSG_MAP(CSecCommDlg)
  208. ON_BN_CLICKED(IDC_CHECK_SSL_ACCOUNT_MAPPING, OnCheckSslAccountMapping)
  209. ON_BN_CLICKED(IDC_CHECK_REQUIRE_SSL, OnCheckRequireSsl)
  210. ON_BN_CLICKED(IDC_RADIO_ACCEPT_CERT, OnRadioAcceptCert)
  211. ON_BN_CLICKED(IDC_RADIO_NO_CERT, OnRadioNoCert)
  212. ON_BN_CLICKED(IDC_RADIO_REQUIRE_CERT, OnRadioRequireCert)
  213. ON_BN_CLICKED(IDC_BUTTON_EDIT_CTL, OnButtonEditCtl)
  214. ON_BN_CLICKED(IDC_CHECK_ENABLE_CTL, OnCheckEnableCtl)
  215. ON_BN_CLICKED(IDC_BUTTON_NEW_CTL, OnButtonNewCtl)
  216. ON_CBN_SELCHANGE(IDC_COMBO_CTL, OnSelchangeComboCtl)
  217. ON_WM_DESTROY()
  218. //}}AFX_MSG_MAP
  219. END_MESSAGE_MAP()
  220. void
  221. CSecCommDlg::SetControlStates()
  222. /*++
  223. Routine Description:
  224. Set control states depending on current data in the dialog
  225. Arguments:
  226. None
  227. Return Value:
  228. None
  229. --*/
  230. {
  231. m_check_RequireSSL.EnableWindow(m_fSSLEnabledOnServer);
  232. m_check_Require128BitSSL.EnableWindow(
  233. m_fSSLEnabledOnServer
  234. && m_fSSL128Supported
  235. && m_fRequireSSL
  236. );
  237. m_ocx_ClientMappings.EnableWindow(
  238. m_fAccountMapping
  239. && !m_fU2Installed
  240. && !m_fIsMasterInstance
  241. );
  242. m_radio_RequireCert.EnableWindow(m_fRequireSSL);
  243. //
  244. // Special case: if "require SSL" is off, but "require
  245. // client certificates" is on, change the latter to "accept
  246. // client certificates"
  247. //
  248. if (m_radio_RequireCert.GetCheck() > 0 && !m_fRequireSSL)
  249. {
  250. m_radio_RequireCert.SetCheck(0);
  251. m_radio_AcceptCert.SetCheck(1);
  252. m_nRadioNoCert = RADIO_ACCEPT_CERT;
  253. }
  254. if (m_fEditCTLs)
  255. {
  256. m_static_CTLPrompt.EnableWindow(m_fEnableCtl);
  257. m_combo_ctl.EnableWindow(m_fEnableCtl);
  258. m_button_EditCtl.EnableWindow(m_fEnableCtl);
  259. m_button_NewCtl.EnableWindow(m_fEnableCtl);
  260. m_ocx_CertificateAuthorities.EnableWindow(m_fEnableCtl);
  261. //
  262. // If enable Ctl is on, but nothing is selected, disable Edit
  263. //
  264. if (m_fEnableCtl)
  265. {
  266. if (m_combo_ctl.GetCurSel() == CB_ERR)
  267. {
  268. m_button_EditCtl.EnableWindow(FALSE);
  269. }
  270. }
  271. }
  272. else
  273. {
  274. m_fEnableCtl = FALSE;
  275. //
  276. // Hide the controls
  277. //
  278. DeActivateControl(m_static_CTLPrompt);
  279. DeActivateControl(m_combo_ctl);
  280. DeActivateControl(m_button_EditCtl);
  281. DeActivateControl(m_button_NewCtl);
  282. DeActivateControl(m_ocx_CertificateAuthorities);
  283. DeActivateControl(m_check_EnableCtl);
  284. DeActivateControl(m_static_CTLSeparator);
  285. }
  286. }
  287. //
  288. // Message Handlers
  289. //
  290. // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  291. BOOL
  292. CSecCommDlg::OnInitDialog()
  293. /*++
  294. Routine Description:
  295. WM_INITDIALOG handler. Initialize the dialog.
  296. Arguments:
  297. None.
  298. Return Value:
  299. TRUE if no focus is to be set automatically, FALSE if the focus
  300. is already set.
  301. --*/
  302. {
  303. CDialog::OnInitDialog();
  304. //
  305. // Initialize certificate authorities ocx
  306. //
  307. CRect rc(0, 0, 0, 0);
  308. m_ocx_CertificateAuthorities.Create(
  309. _T("CertWiz"),
  310. WS_BORDER,
  311. rc,
  312. this,
  313. IDC_APPSCTRL
  314. );
  315. CString strCaption;
  316. VERIFY(strCaption.LoadString(IDS_OCX_CERTMAP));
  317. m_ocx_ClientMappings.SetCaption(strCaption);
  318. m_ocx_ClientMappings.SetServerInstance(m_strMetaPath);
  319. m_ocx_ClientMappings.SetMachineName(m_strServerName);
  320. //
  321. // Initialize the CTL list data
  322. //
  323. InitializeCTLList();
  324. SetControlStates();
  325. return TRUE;
  326. }
  327. void
  328. CSecCommDlg::OnCheckSslAccountMapping()
  329. /*++
  330. Routine Description:
  331. SSL Account mapping checkbox handler
  332. Arguments:
  333. None
  334. Return Value:
  335. None
  336. --*/
  337. {
  338. m_fAccountMapping = !m_fAccountMapping;
  339. SetControlStates();
  340. }
  341. void
  342. CSecCommDlg::OnOK()
  343. /*++
  344. Routine Description:
  345. OK button handler, save information
  346. Arguments:
  347. None
  348. Return Value:
  349. None
  350. --*/
  351. {
  352. if (UpdateData(TRUE))
  353. {
  354. SET_FLAG_IF(m_fAccountMapping, m_dwAccessPermissions, MD_ACCESS_MAP_CERT);
  355. SET_FLAG_IF(m_fRequireSSL, m_dwAccessPermissions, MD_ACCESS_SSL);
  356. SET_FLAG_IF(m_fRequire128BitSSL, m_dwAccessPermissions, MD_ACCESS_SSL128);
  357. RESET_FLAG(m_dwAccessPermissions,
  358. (MD_ACCESS_REQUIRE_CERT | MD_ACCESS_NEGO_CERT));
  359. switch(m_nRadioNoCert)
  360. {
  361. case RADIO_REQ_CERT:
  362. SET_FLAG(m_dwAccessPermissions,
  363. (MD_ACCESS_REQUIRE_CERT | MD_ACCESS_NEGO_CERT));
  364. break;
  365. case RADIO_ACCEPT_CERT:
  366. SET_FLAG(m_dwAccessPermissions, MD_ACCESS_NEGO_CERT);
  367. break;
  368. }
  369. //
  370. // Provide warning if no authentication is selected
  371. //
  372. if (!m_dwAuthFlags && !m_dwAccessPermissions
  373. && !NoYesMessageBox(IDS_WRN_NO_AUTH))
  374. {
  375. //
  376. // Don't dismiss the dialog
  377. //
  378. return;
  379. }
  380. //
  381. // If CTL stuff has changed, update the strings
  382. //
  383. if (m_bCTLDirty)
  384. {
  385. //
  386. // Get the index of the selected item
  387. //
  388. INT iSel = m_combo_ctl.GetCurSel();
  389. //
  390. // If nothing is selected, then clear out the strings
  391. //
  392. if (!m_fEnableCtl || (iSel == CB_ERR))
  393. {
  394. m_strCTLIdentifier.Empty();
  395. m_strCTLStoreName.Empty();
  396. }
  397. else
  398. {
  399. //
  400. // There is one selected. Update the Identifier string
  401. // first get the context itself
  402. //
  403. PCCTL_CONTEXT pCTL =
  404. (PCCTL_CONTEXT)m_combo_ctl.GetItemData(iSel);
  405. if (pCTL != NULL)
  406. {
  407. //
  408. // Now get the list identifier for it and put it in
  409. // the string the list identifier is a inherint value
  410. // of the context and doesn't need to be read in seperately.
  411. // We can just reference it.
  412. //
  413. m_strCTLIdentifier.Empty();
  414. if (pCTL->pCtlInfo
  415. && pCTL->pCtlInfo->ListIdentifier.cbData >= 2
  416. && pCTL->pCtlInfo->ListIdentifier.cbData)
  417. {
  418. //
  419. // If the identifiers are the same, then this is
  420. // our default CTL
  421. //
  422. // m_strCTLIdentifier =
  423. // (PWCHAR)pCTL->pCtlInfo->ListIdentifier.pbData;
  424. wcsncpy(m_strCTLIdentifier.GetBuffer(
  425. pCTL->pCtlInfo->ListIdentifier.cbData + 2),
  426. (PWCHAR)pCTL->pCtlInfo->ListIdentifier.pbData,
  427. pCTL->pCtlInfo->ListIdentifier.cbData
  428. );
  429. m_strCTLIdentifier.ReleaseBuffer();
  430. }
  431. }
  432. else
  433. {
  434. m_strCTLIdentifier.Empty();
  435. m_strCTLStoreName.Empty();
  436. }
  437. }
  438. }
  439. CDialog::OnOK();
  440. }
  441. }
  442. void
  443. CSecCommDlg::OnCheckRequireSsl()
  444. /*++
  445. Routine Description:
  446. 'require ssl' checkbox handler
  447. Arguments:
  448. None
  449. Return Value:
  450. None
  451. --*/
  452. {
  453. m_fRequireSSL = !m_fRequireSSL;
  454. // Uncheck 128bit stuff if more generic is unchecked
  455. if (m_check_RequireSSL.GetCheck() == 0)
  456. m_check_Require128BitSSL.SetCheck(0);
  457. SetControlStates();
  458. }
  459. void
  460. CSecCommDlg::OnRadioNoCert()
  461. /*++
  462. Routine Description:
  463. 'Do not accept certificates' radio button handler
  464. Arguments:
  465. None
  466. Return Value:
  467. None
  468. --*/
  469. {
  470. m_nRadioNoCert = RADIO_NO_CERT;
  471. SetControlStates();
  472. }
  473. void
  474. CSecCommDlg::OnRadioAcceptCert()
  475. /*++
  476. Routine Description:
  477. 'accept certificates' radio button handler
  478. Arguments:
  479. None
  480. Return Value:
  481. None
  482. --*/
  483. {
  484. m_nRadioNoCert = RADIO_ACCEPT_CERT;
  485. SetControlStates();
  486. }
  487. void
  488. CSecCommDlg::OnRadioRequireCert()
  489. /*++
  490. Routine Description:
  491. 'require certificates' radio button handler
  492. Arguments:
  493. None
  494. Return Value:
  495. None
  496. --*/
  497. {
  498. m_nRadioNoCert = RADIO_REQ_CERT;
  499. SetControlStates();
  500. }
  501. void
  502. CSecCommDlg::OnCheckEnableCtl()
  503. /*++
  504. Routine Description:
  505. 'Enable CTL' checkbox handler
  506. Arguments:
  507. None
  508. Return Value:
  509. None
  510. --*/
  511. {
  512. //
  513. // Since this is local only, if we are remote and the user checks the
  514. // box, then we should alert them to the situation and then do nothing.
  515. //
  516. if (!m_fIsLocal)
  517. {
  518. AfxMessageBox(IDS_CTL_LOCAL_ONLY);
  519. return;
  520. }
  521. m_fEnableCtl = !m_fEnableCtl;
  522. //
  523. // If we are now disabling, record the current cert and then blank it
  524. //
  525. if (!m_fEnableCtl)
  526. {
  527. m_iLastUsedCert = m_combo_ctl.GetCurSel();
  528. m_combo_ctl.SetCurSel(-1);
  529. }
  530. else
  531. {
  532. //
  533. // We are enabling, use the last recorded cert
  534. //
  535. m_combo_ctl.SetCurSel(m_iLastUsedCert);
  536. }
  537. m_bCTLDirty = TRUE;
  538. SetControlStates();
  539. }
  540. void
  541. CSecCommDlg::OnButtonEditCtl()
  542. /*++
  543. Routine Description:
  544. "Edit CTL" button handler
  545. Arguments:
  546. None
  547. Return Value:
  548. None
  549. --*/
  550. {
  551. //
  552. // Get the index of the selected item
  553. //
  554. INT iSel = m_combo_ctl.GetCurSel();
  555. ASSERT( iSel != CB_ERR );
  556. //
  557. // Get the selected CTL context
  558. //
  559. PCCTL_CONTEXT pCTL = (PCCTL_CONTEXT)m_combo_ctl.GetItemData(iSel);
  560. //
  561. // Pass in the selected CTL context to edit it
  562. //
  563. PCCTL_CONTEXT pCTLNew = CallCTLWizard( pCTL );
  564. //
  565. // If the CTL on the item has changed, then update the private data item
  566. //
  567. if (pCTLNew && pCTLNew != pCTL)
  568. {
  569. //
  570. // start be deleting the current item from the list
  571. //
  572. m_combo_ctl.DeleteString(iSel);
  573. //
  574. // free the old context
  575. //
  576. CertFreeCTLContext(pCTL);
  577. //
  578. // now add the new one and select it.
  579. //
  580. AddCTLToList(pCTLNew, TRUE);
  581. SetControlStates();
  582. //
  583. // set the dirty flag
  584. //
  585. m_bCTLDirty = TRUE;
  586. }
  587. }
  588. void
  589. CSecCommDlg::OnButtonNewCtl()
  590. /*++
  591. Routine Description:
  592. "New CTL" button handler
  593. Arguments:
  594. None
  595. Return Value:
  596. None
  597. --*/
  598. {
  599. //
  600. // Pass in NULL to create a new CTL
  601. //
  602. PCCTL_CONTEXT pCTL = CallCTLWizard(NULL);
  603. //
  604. // If a CTL was created, add it to the list and select it.
  605. //
  606. if (pCTL != NULL)
  607. {
  608. AddCTLToList(pCTL, TRUE);
  609. SetControlStates();
  610. m_bCTLDirty = TRUE;
  611. }
  612. }
  613. PCCTL_CONTEXT
  614. CSecCommDlg::CallCTLWizard(
  615. IN PCCTL_CONTEXT pCTLSrc
  616. )
  617. /*++
  618. Routine Description:
  619. Adds a CTL to the drop down CTL list. Note that the context pointers are
  620. set as the private data on the list items. This means that they will need
  621. to be de-referenced when this object is destroyed. See the
  622. routine CleanUpCTLList.
  623. This routine by boydm
  624. Arguments:
  625. PCCTL_CONTEXT pctl ctl context pointer of the ctl being added
  626. BOOL fSelect flag specifying if this ctl should be selected after it
  627. is added
  628. Return Value:
  629. returns TRUE if successful
  630. --*/
  631. {
  632. PCCTL_CONTEXT pCTLOut = NULL;
  633. CRYPTUI_WIZ_BUILDCTL_NEW_CTL_INFO newInfo;
  634. CTL_USAGE useInfo;
  635. CString szFriendly;
  636. CString szDescription;
  637. CString szListIdentifier;
  638. LPOLESTR pszListIdentifier = NULL;
  639. LPCSTR rgbpszUsageArray[2];
  640. //
  641. // Prepare the main src structure
  642. //
  643. CRYPTUI_WIZ_BUILDCTL_SRC_INFO srcInfo;
  644. ZeroMemory( &srcInfo, sizeof(srcInfo) );
  645. srcInfo.dwSize = sizeof(srcInfo);
  646. //
  647. // If we are editing an existing CTL then we do one thing
  648. //
  649. if ( pCTLSrc )
  650. {
  651. srcInfo.dwSourceChoice = CRYPTUI_WIZ_BUILDCTL_SRC_EXISTING_CTL;
  652. srcInfo.pCTLContext = pCTLSrc;
  653. }
  654. else
  655. {
  656. //
  657. // Prepare the usage arrays
  658. //
  659. ZeroMemory( &rgbpszUsageArray, sizeof(rgbpszUsageArray) );
  660. rgbpszUsageArray[0] = szOID_IIS_VIRTUAL_SERVER;
  661. //
  662. // Must also have client auth - or else no certs show up in the list!
  663. //
  664. rgbpszUsageArray[1] = szOID_PKIX_KP_CLIENT_AUTH;
  665. ZeroMemory( &useInfo, sizeof(useInfo) );
  666. useInfo.cUsageIdentifier = 2;
  667. useInfo.rgpszUsageIdentifier = (PCHAR*)&rgbpszUsageArray;
  668. //
  669. // Prep the new ctl structure, which may or may not get used
  670. //
  671. ZeroMemory( &newInfo, sizeof(newInfo) );
  672. //
  673. // We making a new CTL, fill in the rest of the stuff
  674. //
  675. srcInfo.dwSourceChoice = CRYPTUI_WIZ_BUILDCTL_SRC_NEW_CTL;
  676. srcInfo.pNewCTLInfo = &newInfo;
  677. //
  678. // Load the friendly name and the description
  679. //
  680. szFriendly.LoadString(IDS_CTL_NEW);
  681. szDescription.LoadString(IDS_CTL_DESCRIPTION);
  682. //
  683. // Create a guid string for the identifier
  684. //
  685. GUID id;
  686. HRESULT hres;
  687. hres = CoCreateGuid(&id);
  688. hres = StringFromGUID2(id, szListIdentifier.GetBuffer(1000), 1000);
  689. szListIdentifier.ReleaseBuffer();
  690. //
  691. // Fill in the newInfo structure
  692. //
  693. newInfo.dwSize = sizeof(newInfo);
  694. //
  695. // For now - don't set the usage
  696. //
  697. newInfo.pSubjectUsage = &useInfo;
  698. //
  699. // Put the generated list identifier into place
  700. //
  701. newInfo.pwszListIdentifier = (LPTSTR)(LPCTSTR)szListIdentifier;
  702. //
  703. // Fill in the friendly strings that were loaded from the resources
  704. //
  705. newInfo.pwszFriendlyName = (LPTSTR)(LPCTSTR)szFriendly;
  706. newInfo.pwszDescription = (LPTSTR)(LPCTSTR)szDescription;
  707. }
  708. //
  709. // Make the call to the CTL wizard
  710. //
  711. if (!CryptUIWizBuildCTL(
  712. CRYPTUI_WIZ_BUILDCTL_SKIP_SIGNING |
  713. CRYPTUI_WIZ_BUILDCTL_SKIP_PURPOSE |
  714. CRYPTUI_WIZ_BUILDCTL_SKIP_DESTINATION,
  715. m_hWnd,
  716. NULL,
  717. &srcInfo,
  718. NULL,
  719. &pCTLOut
  720. ))
  721. {
  722. //
  723. // The user canceled the CTL wizard or it failed in general.
  724. // the CTL wizard puts up its own error dialogs
  725. //
  726. return NULL;
  727. }
  728. /*
  729. // get the friendly name from the CTL that comes out of the wizard.
  730. // the process of signing this CTL does not transfer the friendly
  731. // name to the resulting new CTL. Oh well.
  732. DWORD cbProperty;
  733. CertGetCTLContextProperty(
  734. IN pCTLOut,
  735. IN CERT_FRIENDLY_NAME_PROP_ID,
  736. OUT NULL,
  737. IN OUT &cbProperty
  738. );
  739. // increase buffer just to cover any nulls just to be safe
  740. cbProperty += 2;
  741. // get the friendly name
  742. CertGetCTLContextProperty(
  743. IN pCTLOut,
  744. IN CERT_FRIENDLY_NAME_PROP_ID,
  745. OUT szFriendly.GetBuffer(cbProperty),
  746. IN OUT &cbProperty
  747. );
  748. szFriendly.ReleaseBuffer();
  749. // get the description from the CTL that comes out of the wizard.
  750. // the process of signing this CTL does not transfer the friendly
  751. // name to the resulting new CTL. Oh well.
  752. CertGetCTLContextProperty(
  753. IN pCTLOut,
  754. IN CERT_DESCRIPTION_PROP_ID,
  755. OUT NULL,
  756. IN OUT &cbProperty
  757. );
  758. // increase buffer just to cover any nulls just to be safe
  759. cbProperty += 2;
  760. // get the friendly name
  761. CertGetCTLContextProperty(
  762. IN pCTLOut,
  763. IN CERT_DESCRIPTION_PROP_ID,
  764. OUT szDescription.GetBuffer(cbProperty),
  765. IN OUT &cbProperty
  766. );
  767. szDescription.ReleaseBuffer();
  768. // prepare the signer information
  769. CMSG_SIGNER_ENCODE_INFO infoSigner;
  770. ZeroMemory( &infoSigner, sizeof(infoSigner) );
  771. infoSigner.cbSize = sizeof(infoSigner);
  772. infoSigner.pCertInfo = m_pServerCert->pCertInfo;
  773. // infoSigner.HashAlgorithm.pszObjId = szOID_RSA_SHA1RSA;
  774. //CERT_CONTEXT
  775. // prepare the signing cert information
  776. CERT_BLOB infoSigningCert;
  777. infoSigningCert.cbData = m_pServerCert->cbCertEncoded;
  778. infoSigningCert.pbData = m_pServerCert->pbCertEncoded;
  779. // prepare the signed information
  780. CMSG_SIGNED_ENCODE_INFO infoSigned;
  781. ZeroMemory( &infoSigned, sizeof(infoSigned) );
  782. infoSigned.cbSize = sizeof(infoSigned);
  783. // infoSigned.cSigners = 1;
  784. // infoSigned.rgSigners = &infoSigner;
  785. infoSigned.cCertEncoded = 1;
  786. infoSigned.rgCertEncoded = &infoSigningCert;
  787. // find out how much space we need for the encoded signed message
  788. DWORD cbEncodedCTLMessage;
  789. PBYTE pbyteEncodedMessage = NULL;
  790. // make the call to get the space requirement
  791. BOOL f = CryptMsgSignCTL(
  792. IN CRYPT_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  793. IN pCTLOut->pbCtlContent,
  794. IN pCTLOut->cbCtlContent,
  795. IN &infoSigned,
  796. IN 0,
  797. OUT NULL,
  798. IN OUT &cbEncodedCTLMessage
  799. );
  800. if ( f )
  801. {
  802. // allocate the buffer for the message
  803. pbyteEncodedMessage = (PBYTE)GlobalAlloc( GPTR, cbEncodedCTLMessage );
  804. if ( !pbyteEncodedMessage )
  805. {
  806. f = FALSE;
  807. }
  808. else
  809. {
  810. // make the real call and get the message
  811. f = CryptMsgSignCTL(
  812. IN CRYPT_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  813. IN pCTLOut->pbCtlContent,
  814. IN pCTLOut->cbCtlContent,
  815. IN &infoSigned,
  816. IN 0,
  817. OUT pbyteEncodedMessage,
  818. IN OUT &cbEncodedCTLMessage
  819. );
  820. }
  821. }
  822. // at this point we are done with the CTL returned by the wizard
  823. CertFreeCTLContext( pCTLOut );
  824. pCTLOut = NULL;
  825. // If the signing failed, ask the user if that want to proceed anyway
  826. if ( !f && AfxMessageBox( IDS_CTL_SIGN_FAIL, MB_YESNO ) == IDNO )
  827. {
  828. CertFreeCTLContext( pCTLOut );
  829. if ( pbyteEncodedMessage )
  830. {
  831. GlobalFree( pbyteEncodedMessage );
  832. }
  833. return NULL;
  834. }
  835. // add the encoded and signed CTL to the Cert store.
  836. if ( CertAddEncodedCTLToStore(
  837. IN m_hCTLStore,
  838. IN CRYPT_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  839. IN pbyteEncodedMessage,
  840. IN cbEncodedCTLMessage,
  841. IN CERT_STORE_ADD_REPLACE_EXISTING,
  842. OUT &pCTLOut
  843. ) )
  844. {
  845. */
  846. /*
  847. // replace the friendly name and description that just got lost
  848. CertSetCTLContextProperty(
  849. IN pCTLOut,
  850. IN CERT_FRIENDLY_NAME_PROP_ID,
  851. IN 0,
  852. IN (LPCTSTR)szFriendly
  853. );
  854. CertSetCTLContextProperty(
  855. IN pCTLOut,
  856. IN CERT_DESCRIPTION_PROP_ID,
  857. IN 0,
  858. IN (LPCTSTR)szDescription
  859. );
  860. */
  861. /*
  862. }
  863. else
  864. {
  865. // we failed to write it out to the store.
  866. AfxMessageBox( IDS_CTL_WRITE_FAIL );
  867. }
  868. // cleanup
  869. if ( pbyteEncodedMessage )
  870. {
  871. GlobalFree( pbyteEncodedMessage );
  872. }
  873. */
  874. //
  875. // Add the certificate context to the store
  876. //
  877. if (pCTLOut != NULL)
  878. {
  879. PCCTL_CONTEXT pCTLAdded = NULL;
  880. if (CertAddCTLContextToStore(
  881. m_hCTLStore,
  882. pCTLOut,
  883. CERT_STORE_ADD_REPLACE_EXISTING,
  884. &pCTLAdded
  885. ))
  886. {
  887. CertFreeCTLContext( pCTLOut );
  888. pCTLOut = pCTLAdded;
  889. }
  890. else
  891. {
  892. CertFreeCTLContext( pCTLOut );
  893. pCTLOut = NULL;
  894. }
  895. }
  896. return pCTLOut;
  897. }
  898. BOOL
  899. CSecCommDlg::AddCTLToList(
  900. IN PCCTL_CONTEXT pCTL,
  901. IN BOOL fSelect
  902. )
  903. /*++
  904. Routine Description:
  905. Adds a CTL to the drop down CTL list. Note that the context pointers are
  906. set as the private data on the list items. This means that they will need
  907. to be de-referenced when this object is destroyed. See the
  908. routine CleanUpCTLList.
  909. This routine by boydm
  910. Arguments:
  911. PCCTL_CONTEXT pctl ctl context pointer of the ctl being added
  912. BOOL fSelect - flag specifying if this ctl should be selected after it
  913. is added
  914. Return Value:
  915. returns TRUE if successful
  916. --*/
  917. {
  918. BOOL fSuccess;
  919. ASSERT(pCTL != NULL);
  920. if (!pCTL)
  921. {
  922. return FALSE;
  923. }
  924. //
  925. // First, we extract the friendly name from the CTL.
  926. //
  927. CString szFriendlyName; // the friendly name
  928. DWORD cbName = 0; // count of BYTES for the name, not chars
  929. //
  930. // Find out how much space we need
  931. //
  932. fSuccess = CertGetCTLContextProperty(
  933. pCTL,
  934. CERT_FRIENDLY_NAME_PROP_ID,
  935. NULL,
  936. &cbName
  937. );
  938. //
  939. // Increase buffer just to cover any nulls just to be safe
  940. //
  941. cbName += 2;
  942. //
  943. // Get the friendly name
  944. //
  945. fSuccess = CertGetCTLContextProperty(
  946. pCTL,
  947. CERT_FRIENDLY_NAME_PROP_ID,
  948. szFriendlyName.GetBuffer(cbName),
  949. &cbName
  950. );
  951. szFriendlyName.ReleaseBuffer();
  952. //
  953. // If we did not get the name, then load the default name.
  954. // The friendly name is an optional parameter in the CTL so it
  955. // is OK if it is not there.
  956. //
  957. if (!fSuccess)
  958. {
  959. szFriendlyName.LoadString(IDS_CTL_UNNAMED);
  960. }
  961. //
  962. // Add the friendly name string to the drop down CTL list and record
  963. // the index of the newly created item
  964. //
  965. INT iCTLPosition = m_combo_ctl.AddString(szFriendlyName);
  966. //
  967. // If it worked, then add the context pointer to the item as private data
  968. //
  969. if (iCTLPosition >=0)
  970. {
  971. m_combo_ctl.SetItemData(iCTLPosition, (ULONG_PTR)pCTL);
  972. //
  973. // if we have been told to select the CTL, do so at this point
  974. //
  975. if (fSelect)
  976. {
  977. m_combo_ctl.SetCurSel(iCTLPosition);
  978. }
  979. }
  980. //
  981. // Return TRUE if we successfully added the CTL
  982. //
  983. return (iCTLPosition >=0);
  984. }
  985. void
  986. CSecCommDlg::InitializeCTLList()
  987. /*++
  988. Routine Description:
  989. Initializes the CTL drop down box by opening the CTL store pointer
  990. to the target store and filling in the CTL list box with the enumerated
  991. values.
  992. This routine by boydm
  993. Arguments:
  994. None
  995. Return Value:
  996. None
  997. --*/
  998. {
  999. //
  1000. // For now this is Local ONLY
  1001. //
  1002. if (!m_fIsLocal)
  1003. {
  1004. return;
  1005. }
  1006. //
  1007. // Build the remote name for the store.
  1008. // It takes the form of "\\MACHINE_NAME\STORENAME"
  1009. // The store name is always "MY" and is define above. The machine
  1010. // name is the name of the machine being edited. The leading \\ in the
  1011. // machine name is optional so we will skip it in this case
  1012. //
  1013. CString szStore;
  1014. //
  1015. // Start by adding the machine name that we are targeting
  1016. //
  1017. szStore = m_strServerName;
  1018. //
  1019. // Add the specific store name
  1020. //
  1021. //szStore += _T('\\');
  1022. //szStore += m_strCTLStoreName;
  1023. szStore = m_strCTLStoreName;
  1024. //
  1025. // Open the store
  1026. //
  1027. m_hCTLStore = CertOpenStore( CERT_STORE_PROV_SYSTEM,
  1028. 0,
  1029. NULL,
  1030. CERT_SYSTEM_STORE_LOCAL_MACHINE,
  1031. szStore
  1032. );
  1033. //
  1034. // If we failed to open the store, then we will be unable to do anything
  1035. // with CTLs on this machine at all. Disable everything having to do
  1036. // with the CTL controls.
  1037. //
  1038. if (!m_hCTLStore)
  1039. {
  1040. m_fEnableCtl = FALSE;
  1041. //
  1042. // Return early as we have no need to enumerate the CTLs
  1043. //
  1044. return;
  1045. }
  1046. //
  1047. // Enumerate all the CTLs in the store and add them to the drop-down list
  1048. //
  1049. PCCTL_CONTEXT pCTLEnum = NULL;
  1050. //
  1051. // Enumerate undil NULL is returned. Note that CertEnumCTLsInStore
  1052. // free the context passed into pCTLEnum if it is non NULL. Thus we
  1053. // need to create a duplicate of it to add to the drop-list
  1054. //
  1055. while (pCTLEnum = CertEnumCTLsInStore(m_hCTLStore, pCTLEnum))
  1056. {
  1057. //
  1058. // Make a duplicate of the CTL context for storing in thte list
  1059. //
  1060. PCCTL_CONTEXT pCTL = CertDuplicateCTLContext(pCTLEnum);
  1061. if (!pCTL)
  1062. {
  1063. //
  1064. // Duplication Failed
  1065. //
  1066. continue;
  1067. }
  1068. //
  1069. // The list identifier is a inherint value of the context and doesn't
  1070. // need to be read in separately. We can just referenece it
  1071. //
  1072. BOOL fIsCurrentCTL = FALSE;
  1073. if (pCTL->pCtlInfo
  1074. && pCTL->pCtlInfo->ListIdentifier.cbData >= 2
  1075. && pCTL->pCtlInfo->ListIdentifier.cbData)
  1076. {
  1077. //
  1078. // If the identifiers are the same, then this is our default CTL
  1079. //
  1080. fIsCurrentCTL = (wcsncmp(
  1081. (LPCTSTR)m_strCTLIdentifier,
  1082. (PWCHAR)pCTL->pCtlInfo->ListIdentifier.pbData,
  1083. pCTL->pCtlInfo->ListIdentifier.cbData
  1084. ) == 0);
  1085. // fIsCurrentCTL = ( m_strCTLIdentifier == (PWCHAR)pCTL->pCtlInfo->ListIdentifier.pbData );
  1086. }
  1087. //
  1088. // Add the CTL to the list
  1089. //
  1090. AddCTLToList(pCTL, fIsCurrentCTL);
  1091. }
  1092. }
  1093. void
  1094. CSecCommDlg::CleanUpCTLList()
  1095. /*++
  1096. Routine Description:
  1097. Dereferences all the CTL context pointers in the private data of
  1098. the items in the CTL combo box.
  1099. Then it closes the CTL store handle
  1100. This routine by boydm
  1101. Arguments:
  1102. None
  1103. Return Value:
  1104. None
  1105. --*/
  1106. {
  1107. DWORD cItems = m_combo_ctl.GetCount();
  1108. //
  1109. // Loop through each item and free its reference to the CTL pointer
  1110. //
  1111. for (DWORD i = 0; i < cItems; ++i)
  1112. {
  1113. //
  1114. // Get the CTL context pointer from the item's private data
  1115. //
  1116. PCCTL_CONTEXT pCTL = (PCCTL_CONTEXT)m_combo_ctl.GetItemData(i);
  1117. if (pCTL)
  1118. {
  1119. CertFreeCTLContext(pCTL);
  1120. }
  1121. }
  1122. //
  1123. // Close the handle to the store that contains the CTLs
  1124. //
  1125. if (m_hCTLStore)
  1126. {
  1127. CertCloseStore( m_hCTLStore, CERT_CLOSE_STORE_FORCE_FLAG );
  1128. m_hCTLStore = NULL;
  1129. }
  1130. }
  1131. void
  1132. CSecCommDlg::OnSelchangeComboCtl()
  1133. /*++
  1134. Routine Description:
  1135. The selection in the drop-down list changed
  1136. This routine by boydm
  1137. Arguments:
  1138. None
  1139. Return Value:
  1140. None
  1141. --*/
  1142. {
  1143. SetControlStates();
  1144. m_bCTLDirty = TRUE;
  1145. }
  1146. void
  1147. CSecCommDlg::OnDestroy()
  1148. /*++
  1149. Routine Description:
  1150. WM_DESTROY handler. Clean up internal data
  1151. Arguments:
  1152. None
  1153. Return Value:
  1154. None
  1155. --*/
  1156. {
  1157. CDialog::OnDestroy();
  1158. CleanUpCTLList();
  1159. }