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.

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