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.

5815 lines
159 KiB

  1. //=============================================================================
  2. // Copyright (c) 2000 Microsoft Corporation
  3. //
  4. // controls.cpp
  5. //
  6. // User interface control classes.
  7. //
  8. // Created 02/29/2000 johnstep (John Stephens)
  9. //=============================================================================
  10. #include "precomp.hpp"
  11. #include "controls.hpp"
  12. #include "resource.h"
  13. #include "utils.hpp"
  14. #include <shlguid.h>
  15. #include <htmlhelp.h>
  16. //-----------------------------------------------------------------------------
  17. // Values
  18. //-----------------------------------------------------------------------------
  19. // These are the positions of the children controls of the credential control,
  20. // in DLUs:
  21. // make more space to localize the edit control tags.
  22. #define SIZEFIX 20
  23. #define CREDUI_CONTROL_USERNAME_STATIC_X 0
  24. #define CREDUI_CONTROL_USERNAME_STATIC_Y 2
  25. #define CREDUI_CONTROL_USERNAME_STATIC_WIDTH (48 + SIZEFIX)
  26. #define CREDUI_CONTROL_USERNAME_STATIC_HEIGHT 8
  27. #define CREDUI_CONTROL_USERNAME_X (50 + SIZEFIX)
  28. #define CREDUI_CONTROL_USERNAME_Y 0
  29. #define CREDUI_CONTROL_USERNAME_WIDTH (121 - SIZEFIX)
  30. #define CREDUI_CONTROL_USERNAME_HEIGHT 96
  31. #define CREDUI_CONTROL_VIEW_X 175
  32. #define CREDUI_CONTROL_VIEW_Y 0
  33. #define CREDUI_CONTROL_VIEW_WIDTH 13
  34. #define CREDUI_CONTROL_VIEW_HEIGHT 13
  35. #define CREDUI_CONTROL_PASSWORD_STATIC_X 0
  36. #define CREDUI_CONTROL_PASSWORD_STATIC_Y 19
  37. #define CREDUI_CONTROL_PASSWORD_STATIC_WIDTH (48 + SIZEFIX)
  38. #define CREDUI_CONTROL_PASSWORD_STATIC_HEIGHT 8
  39. #define CREDUI_CONTROL_PASSWORD_X (50 + SIZEFIX)
  40. #define CREDUI_CONTROL_PASSWORD_Y 17
  41. #define CREDUI_CONTROL_PASSWORD_WIDTH (121 - SIZEFIX)
  42. #define CREDUI_CONTROL_PASSWORD_HEIGHT 12
  43. #define CREDUI_CONTROL_SAVE_X (50 + SIZEFIX)
  44. #define CREDUI_CONTROL_SAVE_Y 36
  45. #define CREDUI_CONTROL_SAVE_WIDTH 138
  46. #define CREDUI_CONTROL_SAVE_HEIGHT 10
  47. // Use a common maximum string length for certificate display names:
  48. #define CREDUI_MAX_CERT_NAME_LENGTH 256
  49. #define CREDUI_MAX_CMDLINE_MSG_LENGTH 256
  50. //-----------------------------------------------------------------------------
  51. // Global Variables
  52. //-----------------------------------------------------------------------------
  53. CLSID CreduiStringArrayClassId = // 82BD0E67-9FEA-4748-8672-D5EFE5B779B0
  54. {
  55. 0x82BD0E67,
  56. 0x9FEA,
  57. 0x4748,
  58. {0x86, 0x72, 0xD5, 0xEF, 0xE5, 0xB7, 0x79, 0xB0}
  59. };
  60. // Balloon tip infos for PasswordBox control:
  61. CONST CREDUI_BALLOON_TIP_INFO CreduiCapsLockTipInfo =
  62. {
  63. CreduiStrings.CapsLockTipTitle,
  64. CreduiStrings.CapsLockTipText,
  65. TTI_WARNING, 90, 76
  66. };
  67. // Balloon tip infos for Credential control:
  68. CONST CREDUI_BALLOON_TIP_INFO CreduiBackwardsTipInfo =
  69. {
  70. CreduiStrings.BackwardsTipTitle,
  71. CreduiStrings.BackwardsTipText,
  72. TTI_ERROR, 90, 76
  73. };
  74. WCHAR CreduiCustomTipTitle[CREDUI_MAX_BALLOON_TITLE_LENGTH + 1];
  75. WCHAR CreduiCustomTipMessage[CREDUI_MAX_BALLOON_MESSAGE_LENGTH + 1];
  76. CREDUI_BALLOON_TIP_INFO CreduiCustomTipInfo =
  77. {
  78. CreduiCustomTipTitle,
  79. CreduiCustomTipMessage,
  80. TTI_INFO, 90, 76
  81. };
  82. //-----------------------------------------------------------------------------
  83. // CreduiBalloonTip Class Implementation
  84. //-----------------------------------------------------------------------------
  85. //=============================================================================
  86. // CreduiBalloonTip::CreduiBalloonTip
  87. //
  88. // Created 02/24/2000 johnstep (John Stephens)
  89. //=============================================================================
  90. CreduiBalloonTip::CreduiBalloonTip()
  91. {
  92. Window = NULL;
  93. ParentWindow = NULL;
  94. ControlWindow = NULL;
  95. TipInfo = NULL;
  96. Visible = FALSE;
  97. }
  98. //=============================================================================
  99. // CreduiBalloonTip::~CreduiBalloonTip
  100. //
  101. // Created 02/24/2000 johnstep (John Stephens)
  102. //=============================================================================
  103. CreduiBalloonTip::~CreduiBalloonTip()
  104. {
  105. if (Window != NULL)
  106. {
  107. DestroyWindow(Window);
  108. Window = NULL;
  109. }
  110. }
  111. //=============================================================================
  112. // CreduiBalloonTip::Init
  113. //
  114. // Creates and initializes the balloon window.
  115. //
  116. // Arguments:
  117. // instance (in) - this module
  118. // parentWindow (in) - the parent of the tool tip window
  119. //
  120. // Returns TRUE on success or FALSE otherwise.
  121. //
  122. // Created 02/24/2000 johnstep (John Stephens)
  123. //=============================================================================
  124. BOOL
  125. CreduiBalloonTip::Init(
  126. HINSTANCE instance,
  127. HWND parentWindow
  128. )
  129. {
  130. if (Window != NULL)
  131. {
  132. DestroyWindow(Window);
  133. Window = NULL;
  134. ParentWindow = NULL;
  135. ControlWindow = NULL;
  136. TipInfo = NULL;
  137. Visible = FALSE;
  138. }
  139. Window = CreateWindowEx(NULL, TOOLTIPS_CLASS, NULL,
  140. WS_POPUP | TTS_NOPREFIX | TTS_BALLOON,
  141. CW_USEDEFAULT, CW_USEDEFAULT,
  142. CW_USEDEFAULT, CW_USEDEFAULT,
  143. parentWindow, NULL, instance, NULL);
  144. // Only assign class member values once we have successfully created the
  145. // window:
  146. if (Window != NULL)
  147. {
  148. ParentWindow = parentWindow;
  149. TipInfo = NULL;
  150. return TRUE;
  151. }
  152. return FALSE;
  153. }
  154. //=============================================================================
  155. // CreduiBalloonTip::SetInfo
  156. //
  157. // Sets the tool tip information and adds or updates the tool.
  158. //
  159. // Returns TRUE on success or FALSE otherwise.
  160. //
  161. // Created 03/02/2000 johnstep (John Stephens)
  162. //=============================================================================
  163. BOOL CreduiBalloonTip::SetInfo(
  164. HWND controlWindow,
  165. CONST CREDUI_BALLOON_TIP_INFO *tipInfo
  166. )
  167. {
  168. //if ((controlWindow != ControlWindow) || (tipInfo != TipInfo))
  169. {
  170. TOOLINFO info;
  171. ZeroMemory(&info, sizeof info);
  172. info.cbSize = sizeof info;
  173. info.hwnd = ParentWindow;
  174. info.uId = reinterpret_cast<WPARAM>(ParentWindow);
  175. // If the tool already exists, hide it, then update the information.
  176. // Otherwise, add the tool now:
  177. if (SendMessage(Window, TTM_GETTOOLINFO, 0,
  178. reinterpret_cast<LPARAM>(&info)))
  179. {
  180. if (Visible)
  181. {
  182. Hide();
  183. }
  184. ZeroMemory(&info, sizeof info);
  185. info.cbSize = sizeof info;
  186. info.hwnd = ParentWindow;
  187. info.uId = reinterpret_cast<WPARAM>(ParentWindow);
  188. info.uFlags = TTF_IDISHWND | TTF_TRACK;
  189. info.hinst = NULL;
  190. info.lpszText = const_cast<WCHAR *>(tipInfo->Text);
  191. info.lParam = 0;
  192. SendMessage(Window, TTM_SETTOOLINFO, 0,
  193. reinterpret_cast<LPARAM>(&info));
  194. }
  195. else
  196. {
  197. info.uFlags = TTF_IDISHWND | TTF_TRACK;
  198. info.hinst = NULL;
  199. info.lpszText = const_cast<WCHAR *>(tipInfo->Text);
  200. info.lParam = 0;
  201. if (!SendMessage(Window, TTM_ADDTOOL, 0,
  202. reinterpret_cast<LPARAM>(&info)))
  203. {
  204. return FALSE;
  205. }
  206. }
  207. SendMessage(Window, TTM_SETTITLE, tipInfo->Icon,
  208. reinterpret_cast<LPARAM>(tipInfo->Title));
  209. TipInfo = const_cast<CREDUI_BALLOON_TIP_INFO *>(tipInfo);
  210. ControlWindow = controlWindow;
  211. }
  212. return TRUE;
  213. }
  214. //=============================================================================
  215. // CreduiBalloonTip::Show
  216. //
  217. // Updates the position of the balloon window, and then displays it.
  218. //
  219. // Returns TRUE on success or FALSE otherwise.
  220. //
  221. // Created 02/24/2000 johnstep (John Stephens)
  222. //=============================================================================
  223. BOOL
  224. CreduiBalloonTip::Show()
  225. {
  226. if (!Visible && IsWindowEnabled(ControlWindow))
  227. {
  228. SetFocus(ControlWindow);
  229. RECT rect;
  230. GetWindowRect(ControlWindow, &rect);
  231. SendMessage(Window,
  232. TTM_TRACKPOSITION, 0,
  233. MAKELONG(
  234. rect.left + TipInfo->XPercent *
  235. (rect.right - rect.left) / 100,
  236. rect.top + TipInfo->YPercent *
  237. (rect.bottom - rect.top) / 100));
  238. TOOLINFO info;
  239. ZeroMemory(&info, sizeof info);
  240. info.cbSize = sizeof info;
  241. info.hwnd = ParentWindow;
  242. info.uId = reinterpret_cast<WPARAM>(ParentWindow);
  243. SendMessage(Window, TTM_TRACKACTIVATE, TRUE,
  244. reinterpret_cast<LPARAM>(&info));
  245. Visible = TRUE;
  246. }
  247. return TRUE;
  248. }
  249. //=============================================================================
  250. // CreduiBalloonTip::Hide
  251. //
  252. // Hides the balloon window.
  253. //
  254. // Returns TRUE on success or FALSE otherwise.
  255. //
  256. // Created 02/24/2000 johnstep (John Stephens)
  257. //=============================================================================
  258. BOOL
  259. CreduiBalloonTip::Hide()
  260. {
  261. if (Visible)
  262. {
  263. SendMessage(Window, TTM_TRACKACTIVATE, (WPARAM) FALSE, 0);
  264. Visible = FALSE;
  265. if (ParentWindow)
  266. {
  267. HWND hD = GetParent(ParentWindow);
  268. if (hD)
  269. {
  270. InvalidateRgn(hD,NULL,FALSE);
  271. UpdateWindow(hD);
  272. }
  273. }
  274. }
  275. return TRUE;
  276. }
  277. //-----------------------------------------------------------------------------
  278. // CreduiPasswordBox Class Implementation
  279. //-----------------------------------------------------------------------------
  280. //=============================================================================
  281. // CreduiPasswordBox::CreduiPasswordBox
  282. //
  283. // Created 06/06/2000 johnstep (John Stephens)
  284. //=============================================================================
  285. CreduiPasswordBox::CreduiPasswordBox()
  286. {
  287. OriginalMessageHandler = NULL;
  288. Window = NULL;
  289. PasswordFont = NULL;
  290. BalloonTip = NULL;
  291. CapsLockTipInfo = NULL;
  292. }
  293. //=============================================================================
  294. // CreduiPasswordBox::~CreduiPasswordBox
  295. //
  296. // Created 06/06/2000 johnstep (John Stephens)
  297. //=============================================================================
  298. CreduiPasswordBox::~CreduiPasswordBox()
  299. {
  300. if (PasswordFont != NULL)
  301. {
  302. DeleteObject(static_cast<HGDIOBJ>(PasswordFont));
  303. PasswordFont = NULL;
  304. }
  305. }
  306. //=============================================================================
  307. // CreduiPasswordBox::Init
  308. //
  309. // Created 06/06/2000 johnstep (John Stephens)
  310. //=============================================================================
  311. BOOL
  312. CreduiPasswordBox::Init(
  313. HWND window,
  314. CreduiBalloonTip *balloonTip,
  315. CONST CREDUI_BALLOON_TIP_INFO *capsLockTipInfo,
  316. HFONT passwordFont,
  317. WCHAR passwordChar)
  318. {
  319. // If passwordFont was passed, use it here, but leave the class
  320. // PasswordFont NULL so it will not be cleaned up by the destructor. If
  321. // it was not passed, create a font here, which will be freed by the
  322. // destructor:
  323. if (passwordFont == NULL)
  324. {
  325. passwordFont = PasswordFont;
  326. }
  327. Window = window;
  328. // If we still failed to create the font, and are not planning to display
  329. // balloon tips, then there's nothing do to, just return.
  330. if ((passwordFont == NULL) && (balloonTip == NULL))
  331. {
  332. return FALSE;
  333. }
  334. if (balloonTip != NULL)
  335. {
  336. if (capsLockTipInfo == NULL)
  337. {
  338. return FALSE;
  339. }
  340. BalloonTip = balloonTip;
  341. CapsLockTipInfo = capsLockTipInfo;
  342. OriginalMessageHandler =
  343. reinterpret_cast<WNDPROC>(
  344. GetWindowLongPtr(Window, GWLP_WNDPROC));
  345. if (OriginalMessageHandler != NULL)
  346. {
  347. SetLastError(ERROR_SUCCESS);
  348. if ((SetWindowLongPtr(
  349. Window,
  350. GWLP_USERDATA,
  351. reinterpret_cast<LONG_PTR>(this)) == 0) &&
  352. (GetLastError() != ERROR_SUCCESS))
  353. {
  354. return FALSE;
  355. }
  356. SetLastError(ERROR_SUCCESS);
  357. if (SetWindowLongPtr(
  358. Window,
  359. GWLP_WNDPROC,
  360. reinterpret_cast<LONG_PTR>(MessageHandlerCallback)) &&
  361. (GetLastError() != ERROR_SUCCESS))
  362. {
  363. return FALSE;
  364. }
  365. }
  366. else
  367. {
  368. return FALSE;
  369. }
  370. }
  371. if (passwordFont != NULL)
  372. {
  373. SendMessage(Window,
  374. WM_SETFONT,
  375. reinterpret_cast<WPARAM>(passwordFont),
  376. 0);
  377. SendMessage(Window, EM_SETPASSWORDCHAR, passwordChar, 0);
  378. }
  379. return TRUE;
  380. }
  381. //=============================================================================
  382. // CreduiPasswordBox::MessageHandler
  383. //
  384. // This callback function just calls through to the original, except in a
  385. // special case where Caps Lock is pressed. We then check to see if the tip is
  386. // currently being displayed, and if the new state of Caps Lock is off, hide
  387. // the tip.
  388. //
  389. // Arguments:
  390. // message (in)
  391. // wParam (in)
  392. // lParam (in)
  393. //
  394. // Returns the result of calling the original message handler in every case.
  395. //
  396. // Created 02/25/2000 johnstep (John Stephens)
  397. //=============================================================================
  398. LRESULT
  399. CreduiPasswordBox::MessageHandler(
  400. UINT message,
  401. WPARAM wParam,
  402. LPARAM lParam
  403. )
  404. {
  405. switch (message)
  406. {
  407. case WM_KEYDOWN:
  408. if (wParam == VK_CAPITAL)
  409. {
  410. }
  411. else
  412. {
  413. if (BalloonTip->IsVisible())
  414. {
  415. BalloonTip->Hide();
  416. }
  417. }
  418. break;
  419. case WM_SETFOCUS:
  420. // Make sure no one can steal the focus while a user is
  421. // entering their password:
  422. LockSetForegroundWindow(LSFW_LOCK);
  423. // If the Caps Lock key is down, notify the user, unless the
  424. // password tip is already visible:
  425. if (!BalloonTip->IsVisible() && CreduiIsCapsLockOn())
  426. {
  427. // BalloonTip->SetInfo(Window, CapsLockTipInfo);
  428. // BalloonTip->Show();
  429. }
  430. break;
  431. case WM_PASTE:
  432. if (BalloonTip->IsVisible())
  433. {
  434. BalloonTip->Hide();
  435. }
  436. break;
  437. case WM_KILLFOCUS:
  438. if (BalloonTip->IsVisible())
  439. {
  440. BalloonTip->Hide();
  441. }
  442. // Make sure other processes can set foreground window
  443. // once again:
  444. LockSetForegroundWindow(LSFW_UNLOCK);
  445. break;
  446. }
  447. return CallWindowProc(OriginalMessageHandler,
  448. Window,
  449. message,
  450. wParam,
  451. lParam);
  452. }
  453. //=============================================================================
  454. // CreduiPasswordBox::MessageHandlerCallback
  455. //
  456. // This calls through to CreduiPasswordBox::MessageHandler, from the this
  457. // pointer.
  458. //
  459. // Arguments:
  460. // passwordWindow (in)
  461. // message (in)
  462. // wParam (in)
  463. // lParam (in)
  464. //
  465. // Returns the result of calling the original message handler in every case.
  466. //
  467. // Created 02/25/2000 johnstep (John Stephens)
  468. //=============================================================================
  469. LRESULT
  470. CALLBACK
  471. CreduiPasswordBox::MessageHandlerCallback(
  472. HWND passwordWindow,
  473. UINT message,
  474. WPARAM wParam,
  475. LPARAM lParam
  476. )
  477. {
  478. CreduiPasswordBox *that =
  479. reinterpret_cast<CreduiPasswordBox *>(
  480. GetWindowLongPtr(passwordWindow, GWLP_USERDATA));
  481. ASSERT(that != NULL);
  482. ASSERT(that->BalloonTip != NULL);
  483. ASSERT(that->CapsLockTipInfo != NULL);
  484. ASSERT(that->Window == passwordWindow);
  485. return that->MessageHandler(message, wParam, lParam);
  486. }
  487. //-----------------------------------------------------------------------------
  488. // CreduiStringArrayFactory Class Implementation
  489. //-----------------------------------------------------------------------------
  490. //=============================================================================
  491. // CreduiStringArrayFactory::CreduiStringArrayFactory
  492. //
  493. // Created 04/03/2000 johnstep (John Stephens)
  494. //=============================================================================
  495. CreduiStringArrayFactory::CreduiStringArrayFactory()
  496. {
  497. ReferenceCount = 1;
  498. }
  499. //=============================================================================
  500. // CreduiStringArrayFactory::~CreduiStringArrayFactory
  501. //
  502. // Created 04/03/2000 johnstep (John Stephens)
  503. //=============================================================================
  504. CreduiStringArrayFactory::~CreduiStringArrayFactory()
  505. {
  506. }
  507. //=============================================================================
  508. // CreduiStringArrayFactory::QueryInterface (IUnknown)
  509. //
  510. // Created 04/03/2000 johnstep (John Stephens)
  511. //=============================================================================
  512. HRESULT
  513. CreduiStringArrayFactory::QueryInterface(
  514. CONST IID &interfaceId,
  515. VOID **outInterface
  516. )
  517. {
  518. if ((interfaceId == IID_IUnknown) || (interfaceId == IID_IClassFactory))
  519. {
  520. *outInterface = static_cast<void *>(static_cast<IClassFactory *>(this));
  521. }
  522. else
  523. {
  524. *outInterface = NULL;
  525. return E_NOINTERFACE;
  526. }
  527. static_cast<IUnknown *>(*outInterface)->AddRef();
  528. return S_OK;
  529. }
  530. //=============================================================================
  531. // CreduiStringArrayFactory::Addref (IUnknown)
  532. //
  533. // Created 04/03/2000 johnstep (John Stephens)
  534. //=============================================================================
  535. ULONG
  536. CreduiStringArrayFactory::AddRef()
  537. {
  538. return InterlockedIncrement(reinterpret_cast<LONG *>(&ReferenceCount));
  539. }
  540. //=============================================================================
  541. // CreduiStringArrayFactory::Release (IUnknown)
  542. //
  543. // Created 04/03/2000 johnstep (John Stephens)
  544. //=============================================================================
  545. ULONG
  546. CreduiStringArrayFactory::Release()
  547. {
  548. if (InterlockedDecrement(reinterpret_cast<LONG *>(&ReferenceCount)) > 0)
  549. {
  550. return ReferenceCount;
  551. }
  552. delete this;
  553. return 0;
  554. }
  555. //=============================================================================
  556. // CreduiClassFactory::CreateInstance (IClassFactory)
  557. //
  558. // Created 04/03/2000 johnstep (John Stephens)
  559. //=============================================================================
  560. HRESULT
  561. CreduiStringArrayFactory::CreateInstance(
  562. IUnknown *unknownOuter,
  563. CONST IID &interfaceId,
  564. VOID **outInterface
  565. )
  566. {
  567. if (unknownOuter != NULL)
  568. {
  569. return CLASS_E_NOAGGREGATION;
  570. }
  571. CreduiStringArray *stringArray = new CreduiStringArray;
  572. if (stringArray == NULL)
  573. {
  574. return E_OUTOFMEMORY;
  575. }
  576. HRESULT result = stringArray->QueryInterface(interfaceId, outInterface);
  577. // Release the string array object in any case, because of the
  578. // QueryInterface succeeded, it already took another reference count on
  579. // the object:
  580. stringArray->Release();
  581. return result;
  582. }
  583. //=============================================================================
  584. // CreduiClassFactory::LockServer (IClassFactory)
  585. //
  586. // Created 04/03/2000 johnstep (John Stephens)
  587. //=============================================================================
  588. HRESULT
  589. CreduiStringArrayFactory::LockServer(
  590. BOOL lock
  591. )
  592. {
  593. if (lock)
  594. {
  595. InterlockedIncrement(reinterpret_cast<LONG *>(
  596. &CreduiComReferenceCount));
  597. }
  598. else
  599. {
  600. InterlockedDecrement(reinterpret_cast<LONG *>(
  601. &CreduiComReferenceCount));
  602. }
  603. return S_OK;
  604. }
  605. //-----------------------------------------------------------------------------
  606. // CreduiStringArray Class Implementation
  607. //-----------------------------------------------------------------------------
  608. //=============================================================================
  609. // CreduiStringArray::CreduiStringArray
  610. //
  611. // Created 02/25/2000 johnstep (John Stephens)
  612. //=============================================================================
  613. CreduiStringArray::CreduiStringArray()
  614. {
  615. ReferenceCount = 1;
  616. Index = 0;
  617. Count = 0;
  618. MaxCount = 0;
  619. Array = NULL;
  620. InterlockedIncrement(reinterpret_cast<LONG *>(&CreduiComReferenceCount));
  621. }
  622. //=============================================================================
  623. // CreduiStringArray::~CreduiStringArray
  624. //
  625. // Created 02/25/2000 johnstep (John Stephens)
  626. //=============================================================================
  627. CreduiStringArray::~CreduiStringArray()
  628. {
  629. if (Array != NULL)
  630. {
  631. while (Count > 0)
  632. {
  633. delete [] Array[--Count];
  634. }
  635. delete [] Array;
  636. MaxCount = 0;
  637. Count = 0;
  638. }
  639. InterlockedDecrement(reinterpret_cast<LONG *>(&CreduiComReferenceCount));
  640. }
  641. //=============================================================================
  642. // CreduiStringArray::Init
  643. //
  644. // Initializes the string array.
  645. //
  646. // Arguments:
  647. // count (in) - number of strings in the array
  648. //
  649. // Returns TRUE on success or FALSE otherwise.
  650. //
  651. // Created 02/25/2000 johnstep (John Stephens)
  652. //=============================================================================
  653. BOOL
  654. CreduiStringArray::Init(
  655. UINT count
  656. )
  657. {
  658. Count = 0;
  659. MaxCount = count;
  660. Array = new WCHAR *[count];
  661. if (Array != NULL)
  662. {
  663. return TRUE;
  664. }
  665. // Clean up:
  666. MaxCount = 0;
  667. return FALSE;
  668. }
  669. //=============================================================================
  670. // CreduiStringArray::Find
  671. //
  672. // Searches for a string in the array.
  673. //
  674. // Arguments:
  675. // string (in) - string to search for
  676. //
  677. // Returns TRUE if the string was found or FALSE otherwise.
  678. //
  679. // Created 02/27/2000 johnstep (John Stephens)
  680. //=============================================================================
  681. BOOL CreduiStringArray::Find(
  682. CONST WCHAR *string
  683. )
  684. {
  685. // Search for the string:
  686. for (UINT i = 0; i < Count; ++i)
  687. {
  688. ASSERT(Array[i] != NULL);
  689. if (lstrcmpi(Array[i], string) == 0)
  690. {
  691. return TRUE;
  692. }
  693. }
  694. return FALSE;
  695. }
  696. //=============================================================================
  697. // CreduiStringArray::Add
  698. //
  699. // Adds a string to the array.
  700. //
  701. // Arguments:
  702. // string (in) - string to add
  703. //
  704. // Returns TRUE if the string was added or FALSE otherwise.
  705. //
  706. // Created 02/25/2000 johnstep (John Stephens)
  707. //=============================================================================
  708. BOOL
  709. CreduiStringArray::Add(
  710. CONST WCHAR *string
  711. )
  712. {
  713. // The array does not grow, so once we reach the limit, no more:
  714. if (Count < MaxCount)
  715. {
  716. Array[Count] = new WCHAR[lstrlen(string) + 1];
  717. if (Array[Count] != NULL)
  718. {
  719. lstrcpy(Array[Count++], string);
  720. return TRUE;
  721. }
  722. }
  723. return FALSE;
  724. }
  725. //=============================================================================
  726. // CreduiStringArray::QueryInterface (IUnknown)
  727. //
  728. // Created 02/25/2000 johnstep (John Stephens)
  729. //=============================================================================
  730. HRESULT
  731. CreduiStringArray::QueryInterface(
  732. CONST IID &interfaceId,
  733. VOID **outInterface
  734. )
  735. {
  736. if ((interfaceId == IID_IUnknown) || (interfaceId == IID_IEnumString))
  737. {
  738. *outInterface = static_cast<void *>(static_cast<IEnumString *>(this));
  739. }
  740. else
  741. {
  742. *outInterface = NULL;
  743. return E_NOINTERFACE;
  744. }
  745. static_cast<IUnknown *>(*outInterface)->AddRef();
  746. return S_OK;
  747. }
  748. //=============================================================================
  749. // CreduiStringArray::Addref (IUnknown)
  750. //
  751. // Created 02/25/2000 johnstep (John Stephens)
  752. //=============================================================================
  753. ULONG
  754. CreduiStringArray::AddRef()
  755. {
  756. return InterlockedIncrement(reinterpret_cast<LONG *>(&ReferenceCount));
  757. }
  758. //=============================================================================
  759. // CreduiStringArray::Release (IUnknown)
  760. //
  761. // Created 02/25/2000 johnstep (John Stephens)
  762. //=============================================================================
  763. ULONG
  764. CreduiStringArray::Release()
  765. {
  766. if (InterlockedDecrement(reinterpret_cast<LONG *>(&ReferenceCount)) > 0)
  767. {
  768. return ReferenceCount;
  769. }
  770. delete this;
  771. return 0;
  772. }
  773. //=============================================================================
  774. // CreduiStringArray::Next (IEnumString)
  775. //
  776. // Created 02/25/2000 johnstep (John Stephens)
  777. //=============================================================================
  778. HRESULT
  779. CreduiStringArray::Next(
  780. ULONG count,
  781. LPOLESTR *array,
  782. ULONG *countFetched
  783. )
  784. {
  785. if ((count > 1) && (countFetched == NULL))
  786. {
  787. return E_INVALIDARG;
  788. }
  789. count = min(count, Count - Index);
  790. for (UINT i = 0; i < count; ++i)
  791. {
  792. array[i] = static_cast<WCHAR *>(CoTaskMemAlloc(
  793. (sizeof (WCHAR)) * (lstrlen(Array[Index]) + 1)));
  794. if (array[i] != NULL)
  795. {
  796. lstrcpy(array[i], Array[Index]);
  797. }
  798. else
  799. {
  800. while (i > 0)
  801. {
  802. CoTaskMemFree(array[--i]);
  803. array[i] = NULL;
  804. }
  805. if (countFetched != NULL)
  806. {
  807. *countFetched = 0;
  808. }
  809. return E_OUTOFMEMORY;
  810. }
  811. Index++;
  812. }
  813. if (countFetched != NULL)
  814. {
  815. *countFetched = count;
  816. }
  817. return (count > 0) ? S_OK : S_FALSE;
  818. }
  819. //=============================================================================
  820. // CreduiStringArray::Skip (IEnumString)
  821. //
  822. // Created 02/25/2000 johnstep (John Stephens)
  823. //=============================================================================
  824. HRESULT
  825. CreduiStringArray::Skip(
  826. ULONG
  827. )
  828. {
  829. return E_NOTIMPL;
  830. }
  831. //=============================================================================
  832. // CreduiStringArray::Reset (IEnumString)
  833. //
  834. // Created 02/25/2000 johnstep (John Stephens)
  835. //=============================================================================
  836. HRESULT
  837. CreduiStringArray::Reset()
  838. {
  839. Index = 0;
  840. return S_OK;
  841. }
  842. //=============================================================================
  843. // CreduiStringArray::Clone (IEnumString)
  844. //
  845. // Created 02/25/2000 johnstep (John Stephens)
  846. //=============================================================================
  847. HRESULT
  848. CreduiStringArray::Clone(
  849. IEnumString **
  850. )
  851. {
  852. return E_NOTIMPL;
  853. }
  854. //-----------------------------------------------------------------------------
  855. // CreduiAutoCompleteComboBox Class Implementation
  856. //-----------------------------------------------------------------------------
  857. //=============================================================================
  858. // CreduiAutoCompleteComboBox::CreduiAutoCompleteComboBox
  859. //
  860. // Created 02/25/2000 johnstep (John Stephens)
  861. //=============================================================================
  862. CreduiAutoCompleteComboBox::CreduiAutoCompleteComboBox()
  863. {
  864. Window = NULL;
  865. ImageList = NULL;
  866. StringArray = NULL;
  867. }
  868. //=============================================================================
  869. // CreduiAutoCompleteComboBox::~CreduiAutoCompleteComboBox
  870. //
  871. // Created 02/25/2000 johnstep (John Stephens)
  872. //=============================================================================
  873. CreduiAutoCompleteComboBox::~CreduiAutoCompleteComboBox()
  874. {
  875. if (StringArray != NULL)
  876. {
  877. StringArray->Release();
  878. StringArray = NULL;
  879. }
  880. if (ImageList != NULL)
  881. {
  882. ImageList_Destroy(ImageList);
  883. ImageList = NULL;
  884. }
  885. }
  886. //=============================================================================
  887. // CreduiAutoCompleteComboBox::Init
  888. //
  889. // Initializes the shell auto complete list control for the given combo box,
  890. // and sets the auto complete string list.
  891. //
  892. // Arguments:
  893. // instance (in)
  894. // comboBoxWindow (in)
  895. // stringCount (in)
  896. // imageListResourceId (in) - optional image list for the combo box
  897. //
  898. // Returns TRUE on success or FALSE otherwise.
  899. //
  900. // Created 02/25/2000 johnstep (John Stephens)
  901. //=============================================================================
  902. BOOL
  903. CreduiAutoCompleteComboBox::Init(
  904. HMODULE instance,
  905. HWND comboBoxWindow,
  906. UINT stringCount,
  907. INT imageListResourceId,
  908. INT initialImage
  909. )
  910. {
  911. Window = comboBoxWindow;
  912. if (imageListResourceId != 0)
  913. {
  914. ImageList = ImageList_LoadImage(
  915. instance,
  916. MAKEINTRESOURCE(imageListResourceId),
  917. 0, 16, RGB(0, 128, 128), IMAGE_BITMAP,
  918. LR_DEFAULTSIZE | LR_SHARED);
  919. if (ImageList != NULL)
  920. {
  921. SendMessage(Window,
  922. CBEM_SETIMAGELIST,
  923. 0, reinterpret_cast<LPARAM>(ImageList));
  924. }
  925. else
  926. {
  927. return FALSE;
  928. }
  929. }
  930. BOOL success = FALSE;
  931. if (stringCount > 0)
  932. {
  933. HRESULT result =
  934. CoCreateInstance(CreduiStringArrayClassId,
  935. NULL,
  936. CLSCTX_INPROC_SERVER,
  937. IID_IEnumString,
  938. reinterpret_cast<VOID **>(&StringArray));
  939. if (SUCCEEDED(result))
  940. {
  941. if (StringArray->Init(stringCount))
  942. {
  943. success = TRUE;
  944. }
  945. else
  946. {
  947. StringArray->Release();
  948. StringArray = NULL;
  949. }
  950. }
  951. }
  952. else
  953. {
  954. success = TRUE;
  955. }
  956. if (success == TRUE)
  957. {
  958. COMBOBOXEXITEMW item;
  959. item.mask = CBEIF_IMAGE | CBEIF_SELECTEDIMAGE;
  960. item.iItem = -1;
  961. item.iImage = initialImage;
  962. item.iSelectedImage = initialImage;
  963. SendMessage(Window, CBEM_SETITEM, 0,
  964. reinterpret_cast<LPARAM>(&item));
  965. return TRUE;
  966. }
  967. if (ImageList != NULL)
  968. {
  969. ImageList_Destroy(ImageList);
  970. ImageList = NULL;
  971. }
  972. return FALSE;
  973. }
  974. //=============================================================================
  975. // CreduiAutoCompleteComboBox::Add
  976. //
  977. // Returns the index of the new item or -1 on failure.
  978. //
  979. // Created 02/25/2000 johnstep (John Stephens)
  980. //=============================================================================
  981. INT
  982. CreduiAutoCompleteComboBox::Add(
  983. WCHAR *string,
  984. INT image,
  985. BOOL autoComplete,
  986. BOOL addUnique,
  987. INT indexBefore,
  988. INT indent
  989. )
  990. {
  991. INT index = -1;
  992. if (addUnique)
  993. {
  994. index = (INT) SendMessage(Window, CB_FINDSTRINGEXACT, 0,
  995. reinterpret_cast<LPARAM>(string));
  996. }
  997. if (index == -1)
  998. {
  999. if (!autoComplete || StringArray->Add(string))
  1000. {
  1001. COMBOBOXEXITEMW item;
  1002. item.mask = CBEIF_TEXT | CBEIF_INDENT;
  1003. item.iItem = indexBefore;
  1004. item.pszText = string;
  1005. item.iIndent = indent;
  1006. if (ImageList != NULL)
  1007. {
  1008. item.mask |= CBEIF_IMAGE | CBEIF_SELECTEDIMAGE;
  1009. item.iImage = image;
  1010. item.iSelectedImage = image;
  1011. }
  1012. index = (INT) SendMessage(Window, CBEM_INSERTITEM, 0,
  1013. reinterpret_cast<LPARAM>(&item));
  1014. }
  1015. }
  1016. return index;
  1017. }
  1018. //=============================================================================
  1019. // CreduiAutoCompleteComboBox::Update
  1020. //
  1021. // Updates an existing item. This does not update the associated string for
  1022. // auto complete items.
  1023. //
  1024. // Created 04/15/2000 johnstep (John Stephens)
  1025. //=============================================================================
  1026. BOOL
  1027. CreduiAutoCompleteComboBox::Update(
  1028. INT index,
  1029. WCHAR *string,
  1030. INT image
  1031. )
  1032. {
  1033. COMBOBOXEXITEMW item;
  1034. item.iItem = index;
  1035. // Use CBEM_SETITEM in these cases:
  1036. //
  1037. // 1. We're updating the default (-1) item.
  1038. // 2. The dropdown is closed.
  1039. //
  1040. // For other cases, we delete and recreate the item for the desired
  1041. // result.
  1042. BOOL isDropped = (BOOL) SendMessage(Window, CB_GETDROPPEDSTATE, 0, 0);
  1043. if ((index == -1) || !isDropped)
  1044. {
  1045. item.mask = CBEIF_TEXT;
  1046. item.pszText = string;
  1047. if (ImageList != NULL)
  1048. {
  1049. item.mask |= CBEIF_IMAGE | CBEIF_SELECTEDIMAGE;
  1050. item.iImage = image;
  1051. item.iSelectedImage = image;
  1052. }
  1053. if (SendMessage(Window, CBEM_SETITEM, 0,
  1054. reinterpret_cast<LPARAM>(&item)) != 0)
  1055. {
  1056. RECT rect;
  1057. GetClientRect(Window, &rect);
  1058. InvalidateRect(Window, &rect, FALSE);
  1059. return TRUE;
  1060. }
  1061. }
  1062. else
  1063. {
  1064. item.mask = CBEIF_IMAGE | CBEIF_INDENT | CBEIF_SELECTEDIMAGE;
  1065. if (SendMessage(Window, CBEM_GETITEM,
  1066. 0, reinterpret_cast<LPARAM>(&item)))
  1067. {
  1068. item.mask |= CBEIF_TEXT;
  1069. item.pszText = string;
  1070. LPARAM data = SendMessage(Window, CB_GETITEMDATA, index, 0);
  1071. if (ImageList != NULL)
  1072. {
  1073. item.mask |= CBEIF_IMAGE | CBEIF_SELECTEDIMAGE;
  1074. item.iImage = image;
  1075. item.iSelectedImage = image;
  1076. }
  1077. SendMessage(Window, CBEM_DELETEITEM, index, 0);
  1078. index = (INT) SendMessage(Window, CBEM_INSERTITEM, 0,
  1079. reinterpret_cast<LPARAM>(&item));
  1080. if (index != -1)
  1081. {
  1082. SendMessage(Window, CB_SETITEMDATA, index, data);
  1083. INT current = (INT) SendMessage(Window, CB_GETCURSEL, 0, 0);
  1084. if (current == index)
  1085. {
  1086. SendMessage(Window, CB_SETCURSEL, current, 0);
  1087. }
  1088. return TRUE;
  1089. }
  1090. }
  1091. }
  1092. return FALSE;
  1093. }
  1094. //=============================================================================
  1095. // CreduiAutoCompleteComboBox::Enable
  1096. //
  1097. // Created 02/27/2000 johnstep (John Stephens)
  1098. //=============================================================================
  1099. BOOL
  1100. CreduiAutoCompleteComboBox::Enable()
  1101. {
  1102. BOOL success = TRUE;
  1103. if (StringArray != NULL)
  1104. {
  1105. success = FALSE;
  1106. IAutoComplete2 *autoCompleteInterface;
  1107. HRESULT result =
  1108. CoCreateInstance(
  1109. CLSID_AutoComplete,
  1110. NULL,
  1111. CLSCTX_INPROC_SERVER,
  1112. IID_IAutoComplete2,
  1113. reinterpret_cast<void **>(&autoCompleteInterface));
  1114. if (SUCCEEDED(result))
  1115. {
  1116. result = autoCompleteInterface->Init((HWND)
  1117. SendMessage(Window, CBEM_GETEDITCONTROL, 0, 0),
  1118. StringArray, NULL, NULL);
  1119. if (SUCCEEDED(result))
  1120. {
  1121. result = autoCompleteInterface->SetOptions(ACO_AUTOSUGGEST);
  1122. if (SUCCEEDED(result))
  1123. {
  1124. success = TRUE;
  1125. }
  1126. else
  1127. {
  1128. CreduiDebugLog("CreduiAutoCompleteComboBox::Enable: "
  1129. "SetOptions failed: 0x%08X\n", result);
  1130. }
  1131. }
  1132. autoCompleteInterface->Release();
  1133. autoCompleteInterface = NULL;
  1134. }
  1135. else
  1136. {
  1137. CreduiDebugLog(
  1138. "CreduiAutoCompleteComboBox::Enable: "
  1139. "CoCreateInstance CLSID_AutoComplete failed: 0x%08X\n",
  1140. result);
  1141. }
  1142. StringArray->Release();
  1143. StringArray = NULL;
  1144. }
  1145. return success;
  1146. }
  1147. //-----------------------------------------------------------------------------
  1148. // CreduiIconParentWindow Class Implementation
  1149. //-----------------------------------------------------------------------------
  1150. CONST WCHAR *CreduiIconParentWindow::ClassName = L"CreduiIconParentWindow";
  1151. HINSTANCE CreduiIconParentWindow::Instance = NULL;
  1152. LONG CreduiIconParentWindow::Registered = FALSE;
  1153. //=============================================================================
  1154. // CreduiIconParentWindow::CreduiIconParentWindow
  1155. //
  1156. // Created 02/29/2000 johnstep (John Stephens)
  1157. //=============================================================================
  1158. CreduiIconParentWindow::CreduiIconParentWindow()
  1159. {
  1160. Window = NULL;
  1161. }
  1162. //=============================================================================
  1163. // CreduiIconParentWindow::~CreduiIconParentWindow
  1164. //
  1165. // Created 02/29/2000 johnstep (John Stephens)
  1166. //=============================================================================
  1167. CreduiIconParentWindow::~CreduiIconParentWindow()
  1168. {
  1169. if (Window != NULL)
  1170. {
  1171. DestroyWindow(Window);
  1172. Window = NULL;
  1173. }
  1174. }
  1175. //=============================================================================
  1176. // CreduiIconParentWindow::Register
  1177. //
  1178. // Set the instance to allow registration, which will be deferred until a
  1179. // window needs to be created.
  1180. //
  1181. // Arguments:
  1182. // instance (in)
  1183. //
  1184. // Returns TRUE on success or FALSE otherwise.
  1185. //
  1186. // Created 04/16/2000 johnstep (John Stephens)
  1187. //=============================================================================
  1188. BOOL
  1189. CreduiIconParentWindow::Register(
  1190. HINSTANCE instance
  1191. )
  1192. {
  1193. Instance = instance;
  1194. return TRUE;
  1195. }
  1196. //=============================================================================
  1197. // CreduiIconParentWindow::Unegister
  1198. //
  1199. // Unregisters the window class, if registered.
  1200. //
  1201. // Returns TRUE on success or FALSE otherwise.
  1202. //
  1203. // Created 04/16/2000 johnstep (John Stephens)
  1204. //=============================================================================
  1205. BOOL CreduiIconParentWindow::Unregister()
  1206. {
  1207. if (InterlockedCompareExchange(&Registered, FALSE, TRUE))
  1208. {
  1209. return UnregisterClass(ClassName, Instance);
  1210. }
  1211. return TRUE;
  1212. }
  1213. //=============================================================================
  1214. // CreduiIconParentWindow::Init
  1215. //
  1216. // Registers the window class, if not already registered, and creates the
  1217. // window.
  1218. //
  1219. // Arguments:
  1220. // instance (in) - module to load the icon from
  1221. // iconResourceId (in)
  1222. //
  1223. // Returns TRUE on success or FALSE otherwise.
  1224. //
  1225. // Created 02/29/2000 johnstep (John Stephens)
  1226. //=============================================================================
  1227. BOOL
  1228. CreduiIconParentWindow::Init(
  1229. HINSTANCE instance,
  1230. UINT iconResourceId
  1231. )
  1232. {
  1233. WNDCLASS windowClass;
  1234. ZeroMemory(&windowClass, sizeof windowClass);
  1235. if (!InterlockedCompareExchange(&Registered, TRUE, FALSE))
  1236. {
  1237. windowClass.lpfnWndProc = DefWindowProc;
  1238. windowClass.hInstance = Instance;
  1239. windowClass.hIcon =
  1240. LoadIcon(instance, MAKEINTRESOURCE(iconResourceId));
  1241. windowClass.hCursor = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));
  1242. windowClass.lpszClassName = ClassName;
  1243. InterlockedExchange(&Registered, RegisterClass(&windowClass) != 0);
  1244. if (!InterlockedCompareExchange(&Registered, FALSE, FALSE))
  1245. {
  1246. return FALSE;
  1247. }
  1248. }
  1249. Window = CreateWindow(
  1250. L"CreduiIconParentWindow",
  1251. NULL,
  1252. WS_CAPTION | WS_SYSMENU,
  1253. 0, 0, 0, 0,
  1254. NULL, NULL, instance, NULL);
  1255. return (Window != NULL);
  1256. }
  1257. //-----------------------------------------------------------------------------
  1258. // CreduiCredentialControl Class Implementation
  1259. //-----------------------------------------------------------------------------
  1260. CONST WCHAR *CreduiCredentialControl::ClassName = WC_CREDENTIAL;
  1261. HINSTANCE CreduiCredentialControl::Instance = NULL;
  1262. LONG CreduiCredentialControl::Registered = FALSE;
  1263. //=============================================================================
  1264. // CreduiCredentialControl::CreduiCredentialControl
  1265. //
  1266. // Created 06/20/2000 johnstep (John Stephens)
  1267. //=============================================================================
  1268. CreduiCredentialControl::CreduiCredentialControl()
  1269. {
  1270. IsInitialized = FALSE;
  1271. DisabledControlMask = 0;
  1272. Window = NULL;
  1273. Style = 0;
  1274. UserNameStaticWindow = NULL;
  1275. UserNameControlWindow = NULL;
  1276. ViewCertControlWindow = NULL;
  1277. PasswordStaticWindow = NULL;
  1278. PasswordControlWindow = NULL;
  1279. FirstPaint = FALSE;
  1280. ShowBalloonTip = FALSE;
  1281. IsAutoComplete = FALSE;
  1282. NoEditUserName = FALSE;
  1283. KeepUserName = FALSE;
  1284. IsPassport = FALSE;
  1285. CertHashes = NULL;
  1286. CertCount = 0;
  1287. CertBaseInComboBox = 0;
  1288. UserNameCertHash = NULL;
  1289. SmartCardBaseInComboBox = 0;
  1290. SmartCardReadCount = 0;
  1291. IsChangingUserName = FALSE;
  1292. IsChangingPassword = FALSE;
  1293. UserNameSelection = 0;
  1294. ScardUiHandle = NULL;
  1295. DoingCommandLine = FALSE;
  1296. TargetName = NULL;
  1297. InitialUserName = NULL;
  1298. }
  1299. //=============================================================================
  1300. // CreduiCredentialControl::~CreduiCredentialControl
  1301. //
  1302. // Created 06/20/2000 johnstep (John Stephens)
  1303. //=============================================================================
  1304. CreduiCredentialControl::~CreduiCredentialControl()
  1305. {
  1306. }
  1307. //=============================================================================
  1308. // CreduiCredentialControl::Register
  1309. //
  1310. // Arguments:
  1311. // instance (in)
  1312. //
  1313. // Returns TRUE on success or FALSE otherwise.
  1314. //
  1315. // Created 06/20/2000 johnstep (John Stephens)
  1316. //=============================================================================
  1317. BOOL
  1318. CreduiCredentialControl::Register(
  1319. HINSTANCE instance
  1320. )
  1321. {
  1322. Instance = instance;
  1323. WNDCLASS windowClass;
  1324. ZeroMemory(&windowClass, sizeof windowClass);
  1325. if (!InterlockedCompareExchange(&Registered, TRUE, FALSE))
  1326. {
  1327. windowClass.style = CS_GLOBALCLASS;
  1328. windowClass.lpfnWndProc = MessageHandlerCallback;
  1329. windowClass.cbWndExtra = sizeof (CreduiCredentialControl *);
  1330. windowClass.hInstance = Instance;
  1331. windowClass.hIcon = NULL;
  1332. windowClass.hCursor = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));
  1333. windowClass.lpszClassName = ClassName;
  1334. InterlockedExchange(&Registered, RegisterClass(&windowClass) != 0);
  1335. if (!InterlockedCompareExchange(&Registered, FALSE, FALSE))
  1336. {
  1337. return FALSE;
  1338. }
  1339. }
  1340. return TRUE;
  1341. }
  1342. //=============================================================================
  1343. // CreduiCredentialControl::Unegister
  1344. //
  1345. // Unregisters the window class, if registered.
  1346. //
  1347. // Returns TRUE on success or FALSE otherwise.
  1348. //
  1349. // Created 06/20/2000 johnstep (John Stephens)
  1350. //=============================================================================
  1351. BOOL CreduiCredentialControl::Unregister()
  1352. {
  1353. if (InterlockedCompareExchange(&Registered, FALSE, TRUE))
  1354. {
  1355. return UnregisterClass(ClassName, Instance);
  1356. }
  1357. return TRUE;
  1358. }
  1359. //=============================================================================
  1360. // CreduiCredentialControl::ViewCertificate
  1361. //
  1362. // Views the certificate at index in our combo box.
  1363. //
  1364. // Arguments:
  1365. // index (in) - index in the user name combo box
  1366. //
  1367. // Returns TRUE if the certificate was viewed, otherwise FALSE.
  1368. //
  1369. // Created 03/27/2000 johnstep (John Stephens)
  1370. //=============================================================================
  1371. BOOL
  1372. CreduiCredentialControl::ViewCertificate(
  1373. INT index
  1374. )
  1375. {
  1376. BOOL success = FALSE;
  1377. if (index < CertBaseInComboBox)
  1378. {
  1379. return FALSE;
  1380. }
  1381. CONST CERT_CONTEXT *certContext = NULL;
  1382. HCERTSTORE certStore = NULL;
  1383. // If this is not a smart card, open the MY store and find the certificate
  1384. // from the hash. Otherwise, just grab the certificate context from the
  1385. // CERT_ENUM structure:
  1386. if ((SmartCardBaseInComboBox > 0) &&
  1387. (index >= SmartCardBaseInComboBox))
  1388. {
  1389. CERT_ENUM *certEnum =
  1390. reinterpret_cast<CERT_ENUM *>(
  1391. SendMessage(UserNameControlWindow,
  1392. CB_GETITEMDATA, index, 0));
  1393. if (certEnum != NULL)
  1394. {
  1395. certContext = certEnum->pCertContext;
  1396. }
  1397. }
  1398. else
  1399. {
  1400. certStore = CertOpenSystemStore(NULL, L"MY");
  1401. if (certStore != NULL)
  1402. {
  1403. CRYPT_HASH_BLOB hashBlob;
  1404. hashBlob.cbData = CERT_HASH_LENGTH;
  1405. hashBlob.pbData = reinterpret_cast<BYTE *>(
  1406. CertHashes[index - CertBaseInComboBox]);
  1407. certContext = CertFindCertificateInStore(
  1408. certStore,
  1409. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  1410. 0,
  1411. CERT_FIND_SHA1_HASH,
  1412. &hashBlob,
  1413. NULL);
  1414. }
  1415. }
  1416. // If we found a certificate context, view the certificate:
  1417. if (certContext != NULL)
  1418. {
  1419. // Now, show the certificate with the common UI:
  1420. CRYPTUI_VIEWCERTIFICATE_STRUCT certViewInfo;
  1421. ZeroMemory(&certViewInfo, sizeof certViewInfo);
  1422. certViewInfo.dwSize = sizeof certViewInfo;
  1423. certViewInfo.hwndParent = Window;
  1424. certViewInfo.pCertContext = certContext;
  1425. BOOL changed;
  1426. changed = FALSE;
  1427. CryptUIDlgViewCertificate(&certViewInfo, &changed);
  1428. // Get the name again, in case it changed. However, skip this if this
  1429. // is a card reader, and is now invalid:
  1430. COMBOBOXEXITEMW item;
  1431. BOOL updateName = TRUE;
  1432. if (index >= SmartCardBaseInComboBox)
  1433. {
  1434. item.mask = CBEIF_IMAGE;
  1435. item.iItem = index;
  1436. if (!SendMessage(UserNameControlWindow,
  1437. CBEM_GETITEM,
  1438. 0,
  1439. reinterpret_cast<LPARAM>(&item)) ||
  1440. (item.iImage == IMAGE_SMART_CARD_MISSING))
  1441. {
  1442. updateName = FALSE;
  1443. }
  1444. }
  1445. if (updateName)
  1446. {
  1447. WCHAR displayName[CREDUI_MAX_CERT_NAME_LENGTH];
  1448. if (!CreduiGetCertificateDisplayName(
  1449. certContext,
  1450. displayName,
  1451. CREDUI_MAX_CERT_NAME_LENGTH,
  1452. CreduiStrings.Certificate,
  1453. CERT_NAME_FRIENDLY_DISPLAY_TYPE))
  1454. {
  1455. lstrcpyn(displayName,
  1456. CreduiStrings.Certificate,
  1457. CREDUI_MAX_CERT_NAME_LENGTH);
  1458. }
  1459. COMBOBOXEXITEMW item;
  1460. item.mask = CBEIF_TEXT;
  1461. item.iItem = index;
  1462. item.pszText = displayName;
  1463. SendMessage(UserNameControlWindow,
  1464. CBEM_SETITEM,
  1465. 0,
  1466. reinterpret_cast<LPARAM>(&item));
  1467. }
  1468. success = TRUE;
  1469. }
  1470. // If we opened a store, free the certificate and close the store:
  1471. if (certStore != NULL)
  1472. {
  1473. if (certContext != NULL)
  1474. {
  1475. CertFreeCertificateContext(certContext);
  1476. }
  1477. if (!CertCloseStore(certStore, 0))
  1478. {
  1479. CreduiDebugLog("CreduiCredentialControl::ViewCertificate: "
  1480. "CertCloseStore failed: %u\n", GetLastError());
  1481. }
  1482. }
  1483. return success;
  1484. }
  1485. //=============================================================================
  1486. // CreduiCredentialControl::AddCertificates
  1487. //
  1488. // Adds interesting certificates to the combo box, and allocates an array of
  1489. // hashes to match. The hash is all we need to store the credential, and can
  1490. // be used to get a CERT_CONTEXT later to view the certificate.
  1491. //
  1492. // Assume CertCount is 0 upon entry.
  1493. //
  1494. // Stack space is used for temporary storage of hashes, since each hash is
  1495. // only 160 bits. We use a linked list structure, so including the next
  1496. // pointer and worst case alignment (8-byte) on 64-bit, the maximum structure
  1497. // size is 32 bytes. We don't want to consume too much stack space, so limit
  1498. // the number of entries to 256, which will consume up to 8 KB of stack space.
  1499. //
  1500. // Returns TRUE if at least one interesting certificate exists, and all were
  1501. // added to the combo box without error. Otherwise, returns FALSE.
  1502. //
  1503. // Created 03/25/2000 johnstep (John Stephens)
  1504. //=============================================================================
  1505. BOOL
  1506. CreduiCredentialControl::AddCertificates()
  1507. {
  1508. BOOL success = FALSE;
  1509. ASSERT(CertCount == 0);
  1510. HCERTSTORE certStore = CertOpenSystemStore(NULL, L"MY");
  1511. if (certStore != NULL)
  1512. {
  1513. struct HASH_ENTRY
  1514. {
  1515. UCHAR Hash[CERT_HASH_LENGTH];
  1516. HASH_ENTRY *Next;
  1517. };
  1518. HASH_ENTRY *hashList = NULL;
  1519. HASH_ENTRY *current = NULL;
  1520. HASH_ENTRY *next = NULL;
  1521. CONST CERT_CONTEXT *certContext = NULL;
  1522. // NOTE: Currently, add all client authentication certificates. This
  1523. // should be revisited.
  1524. CHAR *ekUsageIdentifiers[] = {
  1525. szOID_PKIX_KP_CLIENT_AUTH
  1526. };
  1527. CERT_ENHKEY_USAGE ekUsage = { 1, ekUsageIdentifiers };
  1528. // We allow a maximum of 256 certificates to be added. This is a
  1529. // reasonable limit, given the current user interface. If this is an
  1530. // unreasonable limit for the personal certificate store, then this
  1531. // can always be changed.
  1532. while (CertCount < 256)
  1533. {
  1534. certContext =
  1535. CertFindCertificateInStore(
  1536. certStore,
  1537. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  1538. CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG,
  1539. CERT_FIND_ENHKEY_USAGE,
  1540. static_cast<VOID *>(&ekUsage),
  1541. certContext);
  1542. if (certContext != NULL)
  1543. {
  1544. DWORD length = CERT_HASH_LENGTH;
  1545. // Only allocate a new entry if necessary. Something may have
  1546. // failed from the previous loop iteration, so we can just
  1547. // reuse the entry allocated then:
  1548. if (next == NULL)
  1549. {
  1550. // Wrap the alloca in an exception handler because it will
  1551. // throw a stack overflow exception on failure. Of course,
  1552. // of we're out of stack space, we may not even be able to
  1553. // clean up properly without throwing an exception.
  1554. __try
  1555. {
  1556. next = static_cast<HASH_ENTRY *>(
  1557. alloca(sizeof HASH_ENTRY));
  1558. }
  1559. __except(EXCEPTION_EXECUTE_HANDLER)
  1560. {
  1561. next = NULL;
  1562. }
  1563. // If this fails, for whatever reason, break out of the
  1564. // loop:
  1565. if (next == NULL)
  1566. {
  1567. CertFreeCertificateContext(certContext);
  1568. break;
  1569. }
  1570. next->Next = NULL;
  1571. }
  1572. if (!CertGetCertificateContextProperty(
  1573. certContext,
  1574. CERT_SHA1_HASH_PROP_ID,
  1575. static_cast<VOID *>(&next->Hash),
  1576. &length))
  1577. {
  1578. // If we failed to get the hash for this certificate, just
  1579. // ignore it and continue with the next. The memory we
  1580. // allocation for this entry will be used on the next
  1581. // iteration if we do not set it to NULL.
  1582. continue;
  1583. }
  1584. if (CreduiIsRemovableCertificate(certContext))
  1585. {
  1586. // If this certificate requires a removable component,
  1587. // such as a smart card, then skip it. We will enumerate
  1588. // these later.
  1589. continue;
  1590. }
  1591. WCHAR displayName[CREDUI_MAX_CERT_NAME_LENGTH];
  1592. if (!CreduiGetCertificateDisplayName(
  1593. certContext,
  1594. displayName,
  1595. CREDUI_MAX_CERT_NAME_LENGTH,
  1596. CreduiStrings.Certificate,
  1597. CERT_NAME_FRIENDLY_DISPLAY_TYPE))
  1598. {
  1599. lstrcpyn(displayName,
  1600. CreduiStrings.Certificate,
  1601. CREDUI_MAX_CERT_NAME_LENGTH);
  1602. }
  1603. // Add the certificate to the combo box. Certificate names may
  1604. // not be unique, so allow duplicates:
  1605. if (UserNameComboBox.Add(
  1606. displayName,
  1607. CreduiIsExpiredCertificate(certContext) ?
  1608. IMAGE_CERT_EXPIRED :
  1609. IMAGE_CERT,
  1610. FALSE,
  1611. FALSE) == -1)
  1612. {
  1613. CertFreeCertificateContext(certContext);
  1614. break;
  1615. }
  1616. // Everything succeeded, so add the certificate to our list:
  1617. if (current == NULL)
  1618. {
  1619. current = next;
  1620. hashList = current;
  1621. }
  1622. else
  1623. {
  1624. ASSERT(current->Next == NULL);
  1625. current->Next = next;
  1626. current = current->Next;
  1627. }
  1628. if (current == NULL)
  1629. {
  1630. CertFreeCertificateContext(certContext);
  1631. break;
  1632. }
  1633. // Set next to NULL so we will allocate new memory on the
  1634. // next iteration:
  1635. next = NULL;
  1636. CertCount++;
  1637. }
  1638. else
  1639. {
  1640. break;
  1641. }
  1642. }
  1643. if (CertCount > 0)
  1644. {
  1645. current = hashList;
  1646. // Now, allocate the final array of certificates. We allocate
  1647. // this in a single block to help avoid thrashing the heap:
  1648. CertHashes = new UCHAR [CertCount][CERT_HASH_LENGTH];
  1649. if (CertHashes != NULL)
  1650. {
  1651. for (UINT i = 0; i < CertCount; ++i)
  1652. {
  1653. CopyMemory(CertHashes[i],
  1654. current->Hash,
  1655. CERT_HASH_LENGTH);
  1656. current = current->Next;
  1657. }
  1658. success = TRUE;
  1659. }
  1660. }
  1661. CertCloseStore(certStore, 0);
  1662. }
  1663. return success;
  1664. }
  1665. //=============================================================================
  1666. // CreduiCredentialControl::FindSmartCardInComboBox
  1667. //
  1668. // Finds a smart card entry in the user name combo box based on a CERT_ENUM.
  1669. //
  1670. // Arguments:
  1671. // certEnum (in)
  1672. //
  1673. // Returns the index of the smart card or -1 if not found.
  1674. //
  1675. // Created 04/15/2000 johnstep (John Stephens)
  1676. //=============================================================================
  1677. INT
  1678. CreduiCredentialControl::FindSmartCardInComboBox(
  1679. CERT_ENUM *certEnum
  1680. )
  1681. {
  1682. UINT count = (UINT) SendMessage(UserNameControlWindow, CB_GETCOUNT, 0, 0);
  1683. if (count == CB_ERR)
  1684. {
  1685. return -1;
  1686. }
  1687. CERT_ENUM *findCertEnum;
  1688. for (UINT i = SmartCardBaseInComboBox; i < count; ++i)
  1689. {
  1690. findCertEnum =
  1691. reinterpret_cast<CERT_ENUM *>(
  1692. SendMessage(UserNameControlWindow, CB_GETITEMDATA, i, 0));
  1693. ASSERT(findCertEnum != NULL);
  1694. if (lstrcmpi(findCertEnum->pszReaderName,
  1695. certEnum->pszReaderName) == 0)
  1696. {
  1697. return i;
  1698. }
  1699. }
  1700. return -1;
  1701. }
  1702. //=============================================================================
  1703. // CreduiCredentialControl::RemoveSmartCardFromComboBox
  1704. //
  1705. // Removes all entries for this smart card from the user name combo box.
  1706. //
  1707. // Arguments:
  1708. // certEnum (in)
  1709. // removeParent (in)
  1710. //
  1711. // Created 07/12/2000 johnstep (John Stephens)
  1712. //=============================================================================
  1713. VOID
  1714. CreduiCredentialControl::RemoveSmartCardFromComboBox(
  1715. CERT_ENUM *certEnum,
  1716. BOOL removeParent
  1717. )
  1718. {
  1719. INT count = (INT) SendMessage(UserNameControlWindow, CB_GETCOUNT, 0, 0);
  1720. INT current = (INT) SendMessage(UserNameControlWindow,
  1721. CB_GETCURSEL, 0, 0);
  1722. if (count != CB_ERR)
  1723. {
  1724. CERT_ENUM *findCertEnum;
  1725. BOOL parentEntry = TRUE;
  1726. BOOL currentRemoved = FALSE;
  1727. for (INT i = SmartCardBaseInComboBox; i < count; ++i)
  1728. {
  1729. findCertEnum =
  1730. reinterpret_cast<CERT_ENUM *>(
  1731. SendMessage(UserNameControlWindow, CB_GETITEMDATA, i, 0));
  1732. ASSERT(findCertEnum != NULL);
  1733. if (lstrcmpi(findCertEnum->pszReaderName,
  1734. certEnum->pszReaderName) == 0)
  1735. {
  1736. if (parentEntry)
  1737. {
  1738. parentEntry = FALSE;
  1739. if (!removeParent)
  1740. {
  1741. continue;
  1742. }
  1743. }
  1744. if (current == i)
  1745. {
  1746. currentRemoved = TRUE;
  1747. }
  1748. SendMessage(
  1749. UserNameControlWindow,
  1750. CBEM_DELETEITEM,
  1751. i,
  1752. 0);
  1753. i--, count--;
  1754. }
  1755. else if (!parentEntry)
  1756. {
  1757. break;
  1758. }
  1759. }
  1760. if (currentRemoved)
  1761. {
  1762. if (removeParent)
  1763. {
  1764. IsChangingUserName = TRUE;
  1765. SendMessage(UserNameControlWindow, CB_SETCURSEL, -1, 0);
  1766. UserNameComboBox.Update(-1, L"", IMAGE_USERNAME);
  1767. IsChangingUserName = FALSE;
  1768. IsChangingPassword = TRUE;
  1769. SetWindowText(PasswordControlWindow, NULL);
  1770. IsChangingPassword = FALSE;
  1771. OnUserNameSelectionChange();
  1772. }
  1773. else
  1774. {
  1775. IsChangingUserName = TRUE;
  1776. SendMessage(UserNameControlWindow, CB_SETCURSEL, --i, 0);
  1777. IsChangingUserName = FALSE;
  1778. }
  1779. OnUserNameSelectionChange();
  1780. }
  1781. }
  1782. }
  1783. //=============================================================================
  1784. // CreduiCredentialControl::HandleSmartCardMessages
  1785. //
  1786. // Handle smart card messages.
  1787. //
  1788. // Arguments:
  1789. // message (in)
  1790. // certEnum (in)
  1791. //
  1792. // Returns TRUE if the message was handled or FALSE otherwise.
  1793. //
  1794. // Created 04/14/2000 johnstep (John Stephens)
  1795. //=============================================================================
  1796. BOOL
  1797. CreduiCredentialControl::HandleSmartCardMessages(
  1798. UINT message,
  1799. CERT_ENUM *certEnum
  1800. )
  1801. {
  1802. ASSERT(ScardUiHandle != NULL);
  1803. // This is sort of ugly since we cannot use a switch. First check for any
  1804. // possible smart card message because we must do some things in common
  1805. // for any of the messages:
  1806. if ((message == CreduiScarduiWmReaderArrival) ||
  1807. (message == CreduiScarduiWmReaderRemoval) ||
  1808. (message == CreduiScarduiWmCardInsertion) ||
  1809. (message == CreduiScarduiWmCardRemoval) ||
  1810. (message == CreduiScarduiWmCardCertAvail) ||
  1811. (message == CreduiScarduiWmCardStatus))
  1812. {
  1813. if (certEnum == NULL)
  1814. {
  1815. CreduiDebugLog(
  1816. "CreduiCredentialControl::HandleSmartCardMessages: "
  1817. "NULL was passed for the CERT_ENUM!");
  1818. // We handled the message, even though it was invalid:
  1819. return TRUE;
  1820. }
  1821. ASSERT(certEnum->pszReaderName != NULL);
  1822. }
  1823. else
  1824. {
  1825. return FALSE;
  1826. }
  1827. WCHAR *displayString;
  1828. WCHAR string[256]; // Must be >= CREDUI_MAX_CERT_NAME_LENGTH
  1829. ASSERT((sizeof string / (sizeof string[0])) >=
  1830. CREDUI_MAX_CERT_NAME_LENGTH);
  1831. INT index = FindSmartCardInComboBox(certEnum);
  1832. if (message == CreduiScarduiWmReaderArrival)
  1833. {
  1834. #ifdef SCARDREPORTS
  1835. CreduiDebugLog("CREDUI: Reader arrival event for %0x\n",this->Window);
  1836. #endif
  1837. // Add the reader, if it is not already there; it should not be:
  1838. if (index == -1)
  1839. {
  1840. //
  1841. // Reset command line Hearbeat timer.
  1842. //
  1843. Heartbeats = 0;
  1844. INT index =
  1845. UserNameComboBox.Add(
  1846. DoingCommandLine ?
  1847. CreduiStrings.NoCard :
  1848. CreduiStrings.EmptyReader,
  1849. IMAGE_SMART_CARD_MISSING,
  1850. FALSE,
  1851. FALSE);
  1852. if (index != -1)
  1853. {
  1854. SendMessage(UserNameControlWindow,
  1855. CB_SETITEMDATA,
  1856. index,
  1857. reinterpret_cast<LPARAM>(certEnum));
  1858. if (UserNameCertHash != NULL)
  1859. {
  1860. EnableWindow(ViewCertControlWindow, FALSE);
  1861. DisabledControlMask |= DISABLED_CONTROL_VIEW;
  1862. SetWindowText(
  1863. PasswordStaticWindow,
  1864. CreduiStrings.PinStatic);
  1865. IsChangingPassword = TRUE;
  1866. SetWindowText(PasswordControlWindow, NULL);
  1867. IsChangingPassword = FALSE;
  1868. EnableWindow(PasswordControlWindow, TRUE);
  1869. EnableWindow(PasswordStaticWindow, TRUE);
  1870. DisabledControlMask &= ~DISABLED_CONTROL_PASSWORD;
  1871. SetWindowText(
  1872. UserNameStaticWindow,
  1873. CreduiStrings.SmartCardStatic);
  1874. if (SaveControlWindow != NULL)
  1875. {
  1876. EnableWindow(SaveControlWindow, FALSE);
  1877. DisabledControlMask |= DISABLED_CONTROL_SAVE;
  1878. }
  1879. IsChangingUserName = TRUE;
  1880. UserNameComboBox.Update(
  1881. -1,
  1882. DoingCommandLine ?
  1883. CreduiStrings.NoCard :
  1884. CreduiStrings.EmptyReader,
  1885. IMAGE_SMART_CARD_MISSING);
  1886. IsChangingUserName = FALSE;
  1887. }
  1888. }
  1889. else
  1890. {
  1891. CreduiDebugLog(
  1892. "CreduiCredentialControl::HandleSmartCardMessages: "
  1893. "Failed to add smart card\n");
  1894. }
  1895. }
  1896. else
  1897. {
  1898. CreduiDebugLog(
  1899. "CreduiCredentialControl::HandleSmartCardMessages: "
  1900. "Reader arrived more than once");
  1901. }
  1902. }
  1903. else if (message == CreduiScarduiWmReaderRemoval)
  1904. {
  1905. #ifdef SCARDREPORTS
  1906. CreduiDebugLog("CREDUI: Reader removal event for %0x\n",this->Window);
  1907. #endif
  1908. if (index != -1)
  1909. {
  1910. RemoveSmartCardFromComboBox(certEnum, TRUE);
  1911. }
  1912. else
  1913. {
  1914. CreduiDebugLog(
  1915. "CreduiCredentialControl::HandleSmartCardMessages: "
  1916. "Reader removed more than once");
  1917. }
  1918. }
  1919. else if (message == CreduiScarduiWmCardInsertion)
  1920. {
  1921. #ifdef SCARDREPORTS
  1922. CreduiDebugLog("CREDUI: card insertion event for %0x\n",this->Window);
  1923. #endif
  1924. if (index != -1)
  1925. {
  1926. //
  1927. // Reset command line Hearbeat timer.
  1928. //
  1929. Heartbeats = 0;
  1930. SmartCardReadCount++;
  1931. if (UserNameCertHash != NULL)
  1932. {
  1933. IsChangingUserName = TRUE;
  1934. UserNameComboBox.Update(
  1935. -1,
  1936. CreduiStrings.ReadingCard,
  1937. IMAGE_SMART_CARD_MISSING);
  1938. IsChangingUserName = FALSE;
  1939. }
  1940. IsChangingUserName = TRUE;
  1941. UserNameComboBox.Update(index,
  1942. CreduiStrings.ReadingCard,
  1943. IMAGE_SMART_CARD_MISSING);
  1944. IsChangingUserName = FALSE;
  1945. }
  1946. else
  1947. {
  1948. CreduiDebugLog(
  1949. "CreduiCredentialControl::HandleSmartCardMessages: "
  1950. "Card insertion to absent reader\n");
  1951. }
  1952. }
  1953. else if (message == CreduiScarduiWmCardRemoval)
  1954. {
  1955. #ifdef SCARDREPORTS
  1956. CreduiDebugLog("CREDUI: card removal event for %0x\n",this->Window);
  1957. #endif
  1958. if (index != -1)
  1959. {
  1960. if (BalloonTip.GetInfo() == &CreduiBackwardsTipInfo)
  1961. {
  1962. BalloonTip.Hide();
  1963. }
  1964. IsChangingUserName = TRUE;
  1965. UserNameComboBox.Update(index,
  1966. DoingCommandLine ?
  1967. CreduiStrings.NoCard :
  1968. CreduiStrings.EmptyReader,
  1969. IMAGE_SMART_CARD_MISSING);
  1970. IsChangingUserName = FALSE;
  1971. RemoveSmartCardFromComboBox(certEnum, FALSE);
  1972. }
  1973. else
  1974. {
  1975. CreduiDebugLog(
  1976. "CreduiCredentialControl::HandleSmartCardMessages: "
  1977. "Card removal from absent reader\n");
  1978. }
  1979. }
  1980. else if (message == CreduiScarduiWmCardCertAvail)
  1981. {
  1982. #ifdef SCARDREPORTS
  1983. CreduiDebugLog("CREDUI: cert available event for %0x\n",this->Window);
  1984. #endif
  1985. if (index != -1)
  1986. {
  1987. // Filter certificates which are not for client authentication:
  1988. if (!CreduiIsClientAuthCertificate(certEnum->pCertContext))
  1989. {
  1990. return TRUE;
  1991. }
  1992. UINT image = IMAGE_SMART_CARD_MISSING;
  1993. COMBOBOXEXITEM item;
  1994. item.mask = CBEIF_IMAGE;
  1995. item.iItem = index;
  1996. SendMessage(UserNameControlWindow, CBEM_GETITEM,
  1997. 0, reinterpret_cast<LPARAM>(&item));
  1998. //
  1999. // For command line,
  2000. // get the UPN display name since the user is expected to type it.
  2001. // For GUI,
  2002. // get the friendly display name since it is "friendly".
  2003. //
  2004. if (!CreduiGetCertificateDisplayName(
  2005. certEnum->pCertContext,
  2006. string,
  2007. CREDUI_MAX_CERT_NAME_LENGTH,
  2008. CreduiStrings.Certificate,
  2009. DoingCommandLine ?
  2010. CERT_NAME_UPN_TYPE :
  2011. CERT_NAME_FRIENDLY_DISPLAY_TYPE))
  2012. {
  2013. lstrcpyn(string,
  2014. CreduiStrings.Certificate,
  2015. CREDUI_MAX_CERT_NAME_LENGTH);
  2016. }
  2017. displayString = string;
  2018. //
  2019. // Trim trailing spaces and -'s so it doesn't look cheesy
  2020. //
  2021. if ( DoingCommandLine ) {
  2022. DWORD StringLength = wcslen(string);
  2023. while ( StringLength > 0 ) {
  2024. if ( string[StringLength-1] == ' ' || string[StringLength-1] == '-' ) {
  2025. string[StringLength-1] = '\0';
  2026. StringLength--;
  2027. } else {
  2028. break;
  2029. }
  2030. }
  2031. }
  2032. #ifdef SCARDREPORTS
  2033. CreduiDebugLog("CREDUI: cert name '%ws' %0x\n", string, this->Window);
  2034. #endif
  2035. if (SendMessage(UserNameControlWindow,
  2036. CB_GETCURSEL,
  2037. 0,
  2038. 0) == index)
  2039. {
  2040. EnableWindow(ViewCertControlWindow, TRUE);
  2041. DisabledControlMask &= ~DISABLED_CONTROL_VIEW;
  2042. }
  2043. image =
  2044. CreduiIsExpiredCertificate(certEnum->pCertContext) ?
  2045. IMAGE_SMART_CARD_EXPIRED :
  2046. IMAGE_SMART_CARD;
  2047. INT newIndex = index;
  2048. if (item.iImage != IMAGE_SMART_CARD_MISSING)
  2049. {
  2050. newIndex = UserNameComboBox.Add(displayString,
  2051. image,
  2052. FALSE,
  2053. FALSE,
  2054. index + 1,
  2055. 1);
  2056. if (newIndex != -1)
  2057. {
  2058. SendMessage(UserNameControlWindow,
  2059. CB_SETITEMDATA,
  2060. newIndex,
  2061. reinterpret_cast<LPARAM>(certEnum));
  2062. }
  2063. else
  2064. {
  2065. newIndex = index;
  2066. }
  2067. }
  2068. if (newIndex == index)
  2069. {
  2070. IsChangingUserName = TRUE;
  2071. UserNameComboBox.Update(index, displayString, image);
  2072. IsChangingUserName = FALSE;
  2073. }
  2074. if (UserNameCertHash != NULL)
  2075. {
  2076. UCHAR hash[CERT_HASH_LENGTH];
  2077. DWORD length = CERT_HASH_LENGTH;
  2078. if (CertGetCertificateContextProperty(
  2079. certEnum->pCertContext,
  2080. CERT_SHA1_HASH_PROP_ID,
  2081. static_cast<VOID *>(&hash),
  2082. &length))
  2083. {
  2084. if (RtlCompareMemory(UserNameCertHash,
  2085. hash,
  2086. CERT_HASH_LENGTH) ==
  2087. CERT_HASH_LENGTH)
  2088. {
  2089. delete [] UserNameCertHash;
  2090. UserNameCertHash = NULL;
  2091. IsChangingUserName = TRUE;
  2092. SendMessage(UserNameControlWindow,
  2093. CB_SETCURSEL, newIndex, 0);
  2094. IsChangingUserName = FALSE;
  2095. OnUserNameSelectionChange();
  2096. }
  2097. }
  2098. }
  2099. }
  2100. else
  2101. {
  2102. CreduiDebugLog(
  2103. "CreduiCredentialControl::HandleSmartCardMessages: "
  2104. "Card certificate to absent reader\n");
  2105. }
  2106. }
  2107. else if (message == CreduiScarduiWmCardStatus)
  2108. {
  2109. #ifdef SCARDREPORTS
  2110. CreduiDebugLog("CREDUI: card status event for %0x\n",this->Window);
  2111. #endif
  2112. if (index != -1)
  2113. {
  2114. if (--SmartCardReadCount == 0)
  2115. {
  2116. if (UserNameCertHash != NULL)
  2117. {
  2118. IsChangingUserName = TRUE;
  2119. SetWindowText(UserNameControlWindow,
  2120. DoingCommandLine ?
  2121. CreduiStrings.NoCard :
  2122. CreduiStrings.EmptyReader);
  2123. IsChangingUserName = FALSE;
  2124. }
  2125. }
  2126. UINT image = IMAGE_SMART_CARD_MISSING;
  2127. BOOL showBalloon = FALSE;
  2128. switch (certEnum->dwStatus)
  2129. {
  2130. case SCARD_S_SUCCESS:
  2131. UINT image;
  2132. COMBOBOXEXITEM item;
  2133. #ifdef SCARDREPORTS
  2134. CreduiDebugLog("CREDUI: card status SUCCESS: %ws\n", certEnum->pszCardName );
  2135. #endif
  2136. item.mask = CBEIF_IMAGE;
  2137. item.iItem = index;
  2138. if (SendMessage(UserNameControlWindow, CBEM_GETITEM,
  2139. 0, reinterpret_cast<LPARAM>(&item)) &&
  2140. (item.iImage != IMAGE_SMART_CARD_MISSING))
  2141. {
  2142. return TRUE;
  2143. }
  2144. displayString = CreduiStrings.EmptyCard;
  2145. break;
  2146. case SCARD_E_UNKNOWN_CARD:
  2147. #ifdef SCARDREPORTS
  2148. CreduiDebugLog("CREDUI: card status UNKNOWN CARD\n");
  2149. #endif
  2150. displayString = CreduiStrings.UnknownCard;
  2151. break;
  2152. case SCARD_W_UNRESPONSIVE_CARD:
  2153. #ifdef SCARDREPORTS
  2154. CreduiDebugLog("CREDUI: card status UNRESPONSIVE CARD\n");
  2155. #endif
  2156. displayString = CreduiStrings.BackwardsCard;
  2157. if (!DoingCommandLine) showBalloon = TRUE;
  2158. break;
  2159. case NTE_KEYSET_NOT_DEF:
  2160. #ifdef SCARDREPORTS
  2161. CreduiDebugLog("CREDUI: card status NTE_KEYSET_NOT_DEF\n");
  2162. #endif
  2163. // TODO: This case should be removed eventually.
  2164. displayString = CreduiStrings.EmptyCard;
  2165. break;
  2166. case SCARD_W_REMOVED_CARD:
  2167. #ifdef SCARDREPORTS
  2168. CreduiDebugLog("CREDUI: card status REMOVED CARD\n");
  2169. #endif
  2170. displayString = DoingCommandLine ?
  2171. CreduiStrings.NoCard :
  2172. CreduiStrings.EmptyReader;
  2173. CreduiStrings.EmptyReader;
  2174. break;
  2175. default:
  2176. #ifdef SCARDREPORTS
  2177. CreduiDebugLog("CREDUI: card status ERROR\n");
  2178. #endif
  2179. displayString = CreduiStrings.CardError;
  2180. break;
  2181. }
  2182. IsChangingUserName = TRUE;
  2183. UserNameComboBox.Update(index, displayString, image);
  2184. IsChangingUserName = FALSE;
  2185. if (showBalloon && !BalloonTip.IsVisible())
  2186. {
  2187. BalloonTip.SetInfo(UserNameControlWindow,
  2188. &CreduiBackwardsTipInfo);
  2189. BalloonTip.Show();
  2190. }
  2191. }
  2192. else
  2193. {
  2194. CreduiDebugLog(
  2195. "CreduiCredentialControl::HandleSmartCardMessages: "
  2196. "Card status to absent reader\n");
  2197. }
  2198. }
  2199. // We handled the message:
  2200. return TRUE;
  2201. }
  2202. //=============================================================================
  2203. // CreduiCredentialControl::CreateControls
  2204. //
  2205. // Created 06/23/2000 johnstep (John Stephens)
  2206. //=============================================================================
  2207. BOOL
  2208. CreduiCredentialControl::CreateControls()
  2209. {
  2210. // First we need the parent window:
  2211. HWND dialogWindow = GetParent(Window);
  2212. if (dialogWindow == NULL)
  2213. {
  2214. return FALSE;
  2215. }
  2216. // Create the various windows:
  2217. RECT clientRect;
  2218. RECT rect;
  2219. UINT add;
  2220. BOOL noViewCert = FALSE;
  2221. if ( Style & CRS_KEEPUSERNAME )
  2222. {
  2223. KeepUserName = TRUE;
  2224. }
  2225. if (!(Style & CRS_USERNAMES) )
  2226. {
  2227. NoEditUserName = TRUE;
  2228. }
  2229. else if ((Style & (CRS_CERTIFICATES | CRS_SMARTCARDS)) == 0)
  2230. {
  2231. noViewCert = TRUE;
  2232. }
  2233. if ( Style & CRS_SINGLESIGNON )
  2234. IsPassport = TRUE;
  2235. else
  2236. IsPassport = FALSE;
  2237. // Determine how much wider the control is than the minimum to resize and
  2238. // reposition controls as necessary:
  2239. GetClientRect(Window, &clientRect);
  2240. rect.left = 0;
  2241. rect.top = 0;
  2242. rect.right = CREDUI_CONTROL_MIN_WIDTH;
  2243. rect.bottom = CREDUI_CONTROL_MIN_HEIGHT;
  2244. if ( !DoingCommandLine && !MapDialogRect(dialogWindow, &rect))
  2245. {
  2246. goto ErrorExit;
  2247. }
  2248. if ((clientRect.right - clientRect.left) >
  2249. (rect.right - rect.left))
  2250. {
  2251. add = (clientRect.right - clientRect.left) -
  2252. (rect.right - rect.left);
  2253. }
  2254. else
  2255. {
  2256. add = 0;
  2257. }
  2258. // Create user name static text control:
  2259. rect.left = CREDUI_CONTROL_USERNAME_STATIC_X;
  2260. rect.top = CREDUI_CONTROL_USERNAME_STATIC_Y;
  2261. rect.right = rect.left + CREDUI_CONTROL_USERNAME_STATIC_WIDTH;
  2262. rect.bottom = rect.top + CREDUI_CONTROL_USERNAME_STATIC_HEIGHT;
  2263. if ( !DoingCommandLine && !MapDialogRect(dialogWindow, &rect))
  2264. {
  2265. goto ErrorExit;
  2266. }
  2267. WCHAR* pUserNameLabel;
  2268. if ( IsPassport )
  2269. pUserNameLabel = CreduiStrings.EmailName;
  2270. else
  2271. pUserNameLabel = CreduiStrings.UserNameStatic;
  2272. UserNameStaticWindow =
  2273. CreateWindowEx(
  2274. WS_EX_NOPARENTNOTIFY,
  2275. L"STATIC",
  2276. pUserNameLabel,
  2277. WS_VISIBLE | WS_CHILD | WS_GROUP,
  2278. rect.left,
  2279. rect.top,
  2280. rect.right - rect.left,
  2281. rect.bottom - rect.top,
  2282. Window,
  2283. reinterpret_cast<HMENU>(IDC_USERNAME_STATIC),
  2284. CreduiCredentialControl::Instance,
  2285. NULL);
  2286. if (UserNameStaticWindow == NULL)
  2287. {
  2288. goto ErrorExit;
  2289. }
  2290. // Create user name combo box:
  2291. rect.left = CREDUI_CONTROL_USERNAME_X;
  2292. rect.top = CREDUI_CONTROL_USERNAME_Y;
  2293. if (!noViewCert)
  2294. {
  2295. rect.right = rect.left + CREDUI_CONTROL_USERNAME_WIDTH;
  2296. }
  2297. else
  2298. {
  2299. rect.right = CREDUI_CONTROL_VIEW_X + CREDUI_CONTROL_VIEW_WIDTH;
  2300. }
  2301. if ( KeepUserName )
  2302. {
  2303. rect.top += 2; // fudge it to make them line up better
  2304. rect.bottom = rect.top + CREDUI_CONTROL_PASSWORD_STATIC_HEIGHT; // make it the same height as the password edit
  2305. }
  2306. else
  2307. {
  2308. rect.bottom = rect.top + CREDUI_CONTROL_USERNAME_HEIGHT; // set the height
  2309. }
  2310. if ( !DoingCommandLine && !MapDialogRect(dialogWindow, &rect))
  2311. {
  2312. goto ErrorExit;
  2313. }
  2314. // This block of statements and the usage of lExStyles : see bug 439840
  2315. LONG_PTR lExStyles = GetWindowLongPtr(Window,GWL_EXSTYLE);
  2316. SetWindowLongPtr(Window,GWL_EXSTYLE,(lExStyles | WS_EX_NOINHERITLAYOUT));
  2317. if ( KeepUserName )
  2318. {
  2319. // create an edit box instead of a combo box
  2320. UserNameControlWindow =
  2321. CreateWindowEx(
  2322. WS_EX_NOPARENTNOTIFY,
  2323. L"Edit",
  2324. L"",
  2325. WS_VISIBLE | WS_CHILD | WS_TABSTOP | ES_READONLY,
  2326. rect.left,
  2327. rect.top,
  2328. rect.right - rect.left + add,
  2329. rect.bottom - rect.top,
  2330. Window,
  2331. reinterpret_cast<HMENU>(IDC_USERNAME),
  2332. CreduiCredentialControl::Instance,
  2333. NULL);
  2334. }
  2335. else
  2336. {
  2337. UserNameControlWindow =
  2338. CreateWindowEx(
  2339. WS_EX_NOPARENTNOTIFY,
  2340. L"ComboBoxEx32",
  2341. L"",
  2342. WS_VISIBLE | WS_CHILD | WS_TABSTOP | WS_VSCROLL |
  2343. (NoEditUserName ? CBS_DROPDOWNLIST : CBS_DROPDOWN) |
  2344. CBS_AUTOHSCROLL,
  2345. rect.left,
  2346. rect.top,
  2347. rect.right - rect.left + add,
  2348. rect.bottom - rect.top,
  2349. Window,
  2350. reinterpret_cast<HMENU>(IDC_USERNAME),
  2351. CreduiCredentialControl::Instance,
  2352. NULL);
  2353. }
  2354. SetWindowLongPtr(Window,GWL_EXSTYLE,lExStyles);
  2355. if (UserNameControlWindow == NULL)
  2356. {
  2357. goto ErrorExit;
  2358. }
  2359. // Create view button:
  2360. if (!noViewCert)
  2361. {
  2362. rect.left = CREDUI_CONTROL_VIEW_X;
  2363. rect.top = CREDUI_CONTROL_VIEW_Y;
  2364. rect.right = rect.left + CREDUI_CONTROL_VIEW_WIDTH;
  2365. rect.bottom = rect.top + CREDUI_CONTROL_VIEW_HEIGHT;
  2366. if ( !DoingCommandLine && !MapDialogRect(dialogWindow, &rect))
  2367. {
  2368. goto ErrorExit;
  2369. }
  2370. ViewCertControlWindow =
  2371. CreateWindowEx(
  2372. WS_EX_NOPARENTNOTIFY,
  2373. L"BUTTON",
  2374. L"&...",
  2375. WS_VISIBLE | WS_CHILD | WS_TABSTOP | WS_GROUP |
  2376. BS_PUSHBUTTON | BS_CENTER,
  2377. rect.left + add,
  2378. rect.top,
  2379. rect.right - rect.left,
  2380. rect.bottom - rect.top,
  2381. Window,
  2382. reinterpret_cast<HMENU>(IDC_VIEW_CERT),
  2383. CreduiCredentialControl::Instance,
  2384. NULL);
  2385. if (ViewCertControlWindow == NULL)
  2386. {
  2387. goto ErrorExit;
  2388. }
  2389. EnableWindow(ViewCertControlWindow, FALSE);
  2390. DisabledControlMask |= DISABLED_CONTROL_VIEW;
  2391. }
  2392. // Create password static text control:
  2393. rect.left = CREDUI_CONTROL_PASSWORD_STATIC_X;
  2394. rect.top = CREDUI_CONTROL_PASSWORD_STATIC_Y;
  2395. rect.right = rect.left + CREDUI_CONTROL_PASSWORD_STATIC_WIDTH;
  2396. rect.bottom = rect.top + CREDUI_CONTROL_PASSWORD_STATIC_HEIGHT;
  2397. if ( !DoingCommandLine && !MapDialogRect(dialogWindow, &rect))
  2398. {
  2399. goto ErrorExit;
  2400. }
  2401. PasswordStaticWindow =
  2402. CreateWindowEx(
  2403. WS_EX_NOPARENTNOTIFY,
  2404. L"STATIC",
  2405. CreduiStrings.PasswordStatic,
  2406. WS_VISIBLE | WS_CHILD | WS_GROUP,
  2407. rect.left,
  2408. rect.top,
  2409. rect.right - rect.left,
  2410. rect.bottom - rect.top,
  2411. Window,
  2412. reinterpret_cast<HMENU>(IDC_PASSWORD_STATIC),
  2413. CreduiCredentialControl::Instance,
  2414. NULL);
  2415. if (PasswordStaticWindow == NULL)
  2416. {
  2417. goto ErrorExit;
  2418. }
  2419. // Create password edit control:
  2420. rect.left = CREDUI_CONTROL_PASSWORD_X;
  2421. rect.top = CREDUI_CONTROL_PASSWORD_Y;
  2422. if (!noViewCert)
  2423. {
  2424. rect.right = rect.left + CREDUI_CONTROL_PASSWORD_WIDTH;
  2425. }
  2426. else
  2427. {
  2428. rect.right = CREDUI_CONTROL_VIEW_X + CREDUI_CONTROL_VIEW_WIDTH;
  2429. }
  2430. rect.bottom = rect.top + CREDUI_CONTROL_PASSWORD_HEIGHT;
  2431. if (!DoingCommandLine && !MapDialogRect(dialogWindow, &rect))
  2432. {
  2433. goto ErrorExit;
  2434. }
  2435. // This block of statements and the usage of lExStyles : see bug 439840
  2436. lExStyles = GetWindowLongPtr(Window,GWL_EXSTYLE);
  2437. SetWindowLongPtr(Window,GWL_EXSTYLE,(lExStyles | WS_EX_NOINHERITLAYOUT));
  2438. PasswordControlWindow =
  2439. CreateWindowEx(
  2440. WS_EX_NOPARENTNOTIFY | WS_EX_CLIENTEDGE,
  2441. L"EDIT",
  2442. L"",
  2443. WS_VISIBLE | WS_CHILD | WS_TABSTOP | ES_PASSWORD | ES_AUTOHSCROLL,
  2444. rect.left,
  2445. rect.top,
  2446. rect.right - rect.left + add,
  2447. rect.bottom - rect.top + 1, // NOTE: Add 1 for now, investigate
  2448. Window,
  2449. reinterpret_cast<HMENU>(IDC_PASSWORD),
  2450. CreduiCredentialControl::Instance,
  2451. NULL);
  2452. SetWindowLongPtr(Window,GWL_EXSTYLE,lExStyles);
  2453. if (PasswordControlWindow == NULL)
  2454. {
  2455. goto ErrorExit;
  2456. }
  2457. // Create save check box:
  2458. if (Style & CRS_SAVECHECK )
  2459. {
  2460. rect.left = CREDUI_CONTROL_SAVE_X;
  2461. rect.top = CREDUI_CONTROL_SAVE_Y;
  2462. rect.right = rect.left + CREDUI_CONTROL_SAVE_WIDTH;
  2463. rect.bottom = rect.top + CREDUI_CONTROL_SAVE_HEIGHT;
  2464. if (!DoingCommandLine && !MapDialogRect(dialogWindow, &rect))
  2465. {
  2466. goto ErrorExit;
  2467. }
  2468. WCHAR* pSavePromptString;
  2469. if ( IsPassport )
  2470. pSavePromptString = CreduiStrings.PassportSave;
  2471. else
  2472. pSavePromptString = CreduiStrings.Save;
  2473. SaveControlWindow =
  2474. CreateWindowEx(
  2475. WS_EX_NOPARENTNOTIFY,
  2476. L"BUTTON",
  2477. pSavePromptString,
  2478. WS_VISIBLE | WS_CHILD | WS_TABSTOP | WS_GROUP |
  2479. BS_AUTOCHECKBOX,
  2480. rect.left,
  2481. rect.top,
  2482. rect.right - rect.left + add,
  2483. rect.bottom - rect.top,
  2484. Window,
  2485. reinterpret_cast<HMENU>(IDC_SAVE),
  2486. CreduiCredentialControl::Instance,
  2487. NULL);
  2488. if (SaveControlWindow == NULL)
  2489. {
  2490. goto ErrorExit;
  2491. }
  2492. SendMessage(SaveControlWindow, BM_SETCHECK, BST_UNCHECKED, 0);
  2493. }
  2494. SendMessage(
  2495. Window,
  2496. WM_SETFONT,
  2497. SendMessage(dialogWindow, WM_GETFONT, 0, 0),
  2498. FALSE);
  2499. return TRUE;
  2500. ErrorExit:
  2501. if (SaveControlWindow != NULL)
  2502. {
  2503. DestroyWindow(SaveControlWindow);
  2504. SaveControlWindow = NULL;
  2505. }
  2506. if (PasswordControlWindow != NULL)
  2507. {
  2508. DestroyWindow(PasswordControlWindow);
  2509. PasswordControlWindow = NULL;
  2510. }
  2511. if (PasswordStaticWindow != NULL)
  2512. {
  2513. DestroyWindow(PasswordStaticWindow);
  2514. PasswordStaticWindow = NULL;
  2515. }
  2516. if (ViewCertControlWindow != NULL)
  2517. {
  2518. DestroyWindow(ViewCertControlWindow);
  2519. ViewCertControlWindow = NULL;
  2520. }
  2521. if (UserNameControlWindow != NULL)
  2522. {
  2523. DestroyWindow(UserNameControlWindow);
  2524. UserNameControlWindow = NULL;
  2525. }
  2526. if (UserNameStaticWindow != NULL)
  2527. {
  2528. DestroyWindow(UserNameStaticWindow);
  2529. UserNameStaticWindow = NULL;
  2530. }
  2531. return FALSE;
  2532. }
  2533. LPWSTR
  2534. TrimUsername(
  2535. IN LPWSTR AccountDomainName OPTIONAL,
  2536. IN LPWSTR UserName
  2537. )
  2538. /*++
  2539. Routine Description:
  2540. Returns a pointer to the substring of UserName past any AccountDomainName prefix.
  2541. Arguments:
  2542. AccountDomainName - The DomainName to check to see if it prefixes the UserName.
  2543. UserName - The UserName to check
  2544. Return Values:
  2545. Return a pointer to the non-prefixed username
  2546. --*/
  2547. {
  2548. DWORD AccountDomainNameLength;
  2549. DWORD UserNameLength;
  2550. WCHAR Temp[CNLEN+1];
  2551. //
  2552. // If we couldn't determine the AccountDomainName,
  2553. // return the complete user name.
  2554. //
  2555. if ( AccountDomainName == NULL ) {
  2556. return UserName;
  2557. }
  2558. //
  2559. // If the user name isn't prefixed by the account domain name,
  2560. // return the complete user name.
  2561. //
  2562. AccountDomainNameLength = lstrlen( AccountDomainName );
  2563. UserNameLength = lstrlen( UserName );
  2564. if ( AccountDomainNameLength > CNLEN || AccountDomainNameLength < 1 ) {
  2565. return UserName;
  2566. }
  2567. if ( AccountDomainNameLength+2 > UserNameLength ) {
  2568. return UserName;
  2569. }
  2570. if ( UserName[AccountDomainNameLength] != '\\' ) {
  2571. return UserName;
  2572. }
  2573. RtlCopyMemory( Temp, UserName, AccountDomainNameLength*sizeof(WCHAR) );
  2574. Temp[AccountDomainNameLength] = '\0';
  2575. if ( lstrcmpi( Temp, AccountDomainName ) != 0 ) {
  2576. return UserName;
  2577. }
  2578. return &UserName[AccountDomainNameLength+1];
  2579. }
  2580. //=============================================================================
  2581. // CreduiCredentialControl::InitComboBoxUserNames
  2582. //
  2583. // Created 06/23/2000 johnstep (John Stephens)
  2584. //=============================================================================
  2585. BOOL
  2586. CreduiCredentialControl::InitComboBoxUserNames()
  2587. {
  2588. CREDENTIAL **credentialSet = NULL;
  2589. LOCALGROUP_MEMBERS_INFO_2 *groupInfo = NULL;
  2590. DWORD nameCount = 0;
  2591. LPWSTR AccountDomainName = NULL;
  2592. if (Style & CRS_ADMINISTRATORS)
  2593. {
  2594. //
  2595. // Enumerate the members of LocalAdministrators
  2596. //
  2597. if ( !CreduiGetAdministratorsGroupInfo(&groupInfo, &nameCount)) {
  2598. return FALSE;
  2599. }
  2600. }
  2601. else
  2602. {
  2603. if (!LocalCredEnumerateW(NULL, 0, &nameCount, &credentialSet))
  2604. {
  2605. return FALSE;
  2606. }
  2607. }
  2608. // Initialize COM for STA, unless there are zero names:
  2609. if ((Style & CRS_AUTOCOMPLETE) && nameCount > 0)
  2610. {
  2611. HRESULT comResult = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
  2612. if (SUCCEEDED(comResult))
  2613. {
  2614. IsAutoComplete = TRUE;
  2615. }
  2616. else
  2617. {
  2618. // The auto complete object and our string object require a STA.
  2619. // Our object could easily support a MTA, but we do not support
  2620. // marshaling between apartments.
  2621. if (comResult == RPC_E_CHANGED_MODE)
  2622. {
  2623. CreduiDebugLog("CreduiCredentialControl: "
  2624. "Auto complete disabled for MTA\n");
  2625. }
  2626. IsAutoComplete = FALSE;
  2627. }
  2628. }
  2629. else
  2630. {
  2631. IsAutoComplete = FALSE;
  2632. }
  2633. // Initialize the auto complete combo box:
  2634. if (!UserNameComboBox.Init(CreduiInstance,
  2635. UserNameControlWindow,
  2636. IsAutoComplete ? nameCount : 0,
  2637. IDB_TYPES,
  2638. IMAGE_USERNAME))
  2639. {
  2640. // If initialization failed, and we had attempted for auto complete
  2641. // support, try again without auto complete:
  2642. if (IsAutoComplete)
  2643. {
  2644. IsAutoComplete = FALSE;
  2645. CoUninitialize();
  2646. if (!UserNameComboBox.Init(CreduiInstance,
  2647. UserNameControlWindow,
  2648. 0,
  2649. IDB_TYPES,
  2650. IMAGE_USERNAME))
  2651. {
  2652. return FALSE;
  2653. }
  2654. }
  2655. else
  2656. {
  2657. return FALSE;
  2658. }
  2659. }
  2660. //
  2661. // If we'll complete the user name,
  2662. // truncate any username displayed here.
  2663. // (We'll complete it later.)
  2664. //
  2665. if ( Style & CRS_COMPLETEUSERNAME ) {
  2666. AccountDomainName = GetAccountDomainName();
  2667. }
  2668. // Add user names from credentials, if not requesting an
  2669. // Administrator:
  2670. if (!(Style & CRS_KEEPUSERNAME))
  2671. {
  2672. // only add usernames if we're not keeping the one set
  2673. UINT i = 0;
  2674. if (!(Style & CRS_ADMINISTRATORS))
  2675. {
  2676. for (i = 0; i < nameCount; ++i)
  2677. {
  2678. // Skip domain certificates:
  2679. if (credentialSet[i]->Type == CRED_TYPE_DOMAIN_CERTIFICATE)
  2680. {
  2681. continue;
  2682. }
  2683. // If this is a generic credential, look for a marshaled
  2684. // credential, and skip, if found:
  2685. if ((credentialSet[i]->Type == CRED_TYPE_GENERIC) &&
  2686. LocalCredIsMarshaledCredentialW(credentialSet[i]->UserName))
  2687. {
  2688. continue;
  2689. }
  2690. // Skip this credential if the name is empty:
  2691. if (credentialSet[i]->UserName == NULL)
  2692. {
  2693. continue;
  2694. }
  2695. // Add the user name to the combo box with auto complete. If
  2696. // this fails, do not continue:
  2697. if (UserNameComboBox.Add(
  2698. TrimUsername( AccountDomainName, credentialSet[i]->UserName),
  2699. 0, IsAutoComplete, TRUE) == -1)
  2700. {
  2701. break;
  2702. }
  2703. }
  2704. LocalCredFree(static_cast<VOID *>(credentialSet));
  2705. }
  2706. else if (groupInfo != NULL)
  2707. {
  2708. PSID adminSid = NULL;
  2709. if ( !CreduiLookupLocalSidFromRid(DOMAIN_USER_RID_ADMIN, &adminSid)) {
  2710. adminSid = NULL;
  2711. }
  2712. // Add local administrators to the combo box:
  2713. for (i = 0; i < nameCount; ++i)
  2714. {
  2715. if ( groupInfo[i].lgrmi2_sidusage == SidTypeUser )
  2716. {
  2717. DWORD ComboBoxIndex;
  2718. BOOLEAN IsAdminAccount;
  2719. BOOLEAN RememberComboBoxIndex;
  2720. //
  2721. // If this is Personal and not safe mode,
  2722. // Ignore the well-known Administrator account.
  2723. //
  2724. IsAdminAccount = (adminSid != NULL) &&
  2725. EqualSid(adminSid, groupInfo[i].lgrmi2_sid);
  2726. if ( CreduiIsPersonal &&
  2727. !CreduiIsSafeMode &&
  2728. IsAdminAccount ) {
  2729. continue;
  2730. }
  2731. //
  2732. // If the caller wants to prepopulate the edit box,
  2733. // flag that we need to remember this account
  2734. //
  2735. // Detect the well known admin account
  2736. //
  2737. RememberComboBoxIndex = FALSE;
  2738. if ( (Style & CRS_PREFILLADMIN) != 0 &&
  2739. IsAdminAccount ) {
  2740. RememberComboBoxIndex = TRUE;
  2741. }
  2742. //
  2743. // Add the name to the combo box
  2744. //
  2745. ComboBoxIndex = UserNameComboBox.Add(
  2746. TrimUsername( AccountDomainName, groupInfo[i].lgrmi2_domainandname),
  2747. 0,
  2748. IsAutoComplete,
  2749. TRUE);
  2750. if ( ComboBoxIndex == -1 ) {
  2751. break;
  2752. }
  2753. //
  2754. // If we're to remember the index,
  2755. // do so.
  2756. //
  2757. if ( RememberComboBoxIndex ) {
  2758. UserNameSelection = ComboBoxIndex;
  2759. IsChangingUserName = TRUE;
  2760. SendMessage(UserNameControlWindow,
  2761. CB_SETCURSEL,
  2762. ComboBoxIndex,
  2763. 0);
  2764. IsChangingUserName = FALSE;
  2765. }
  2766. }
  2767. }
  2768. delete [] adminSid;
  2769. NetApiBufferFree(groupInfo);
  2770. }
  2771. }
  2772. if ( AccountDomainName != NULL ) {
  2773. NetApiBufferFree( AccountDomainName );
  2774. }
  2775. return TRUE;
  2776. }
  2777. //=============================================================================
  2778. // CreduiCredentialControl::InitWindow
  2779. //
  2780. // Created 06/20/2000 johnstep (John Stephens)
  2781. //=============================================================================
  2782. BOOL
  2783. CreduiCredentialControl::InitWindow()
  2784. {
  2785. // Set that we're intialized here, even though the controls have not yet
  2786. // been created, etc.:
  2787. IsInitialized = TRUE;
  2788. // Make sure WS_EX_CONTROLPARENT is set:
  2789. SetWindowLong(Window,
  2790. GWL_EXSTYLE,
  2791. GetWindowLong(Window, GWL_EXSTYLE) |
  2792. WS_EX_CONTROLPARENT);
  2793. // Initialize the balloon tip for this window:
  2794. if (!CreateControls() ||
  2795. !BalloonTip.Init(CreduiInstance, Window))
  2796. {
  2797. return FALSE;
  2798. }
  2799. // Limit the number of characters entered into the user name and password
  2800. // edit controls:
  2801. SendMessage(UserNameControlWindow,
  2802. CB_LIMITTEXT,
  2803. CREDUI_MAX_USERNAME_LENGTH,
  2804. 0);
  2805. SendMessage(PasswordControlWindow,
  2806. EM_LIMITTEXT,
  2807. CREDUI_MAX_PASSWORD_LENGTH,
  2808. 0);
  2809. // Set the password character to something cooler:
  2810. PasswordBox.Init(PasswordControlWindow,
  2811. &BalloonTip,
  2812. &CreduiCapsLockTipInfo);
  2813. // Initialize the user name auto complete combo box:
  2814. if ( !KeepUserName )
  2815. {
  2816. if (((Style & CRS_USERNAMES) && InitComboBoxUserNames()) ||
  2817. UserNameComboBox.Init(CreduiInstance,
  2818. UserNameControlWindow,
  2819. 0,
  2820. IDB_TYPES,
  2821. IMAGE_USERNAME))
  2822. {
  2823. // Since we're finished adding auto complete names, enable it now.
  2824. // On failure, the UI can still be presented:
  2825. UserNameComboBox.Enable();
  2826. BOOL haveCertificates = FALSE;
  2827. CertBaseInComboBox = (ULONG)
  2828. SendMessage(UserNameControlWindow,
  2829. CB_GETCOUNT, 0, 0);
  2830. if (Style & CRS_CERTIFICATES)
  2831. {
  2832. haveCertificates = AddCertificates();
  2833. }
  2834. SmartCardBaseInComboBox = CertBaseInComboBox + CertCount;
  2835. if ((Style & CRS_SMARTCARDS) && CreduiHasSmartCardSupport)
  2836. {
  2837. #ifdef SCARDREPORTS
  2838. CreduiDebugLog("CREDUI: Call to SCardUIInit for %0x\n",Window);
  2839. #endif
  2840. ScardUiHandle = SCardUIInit(Window);
  2841. if (ScardUiHandle == NULL)
  2842. {
  2843. #ifdef SCARDREPORTS
  2844. CreduiDebugLog("CREDUI: Call to SCardUIInit failed\n");
  2845. #endif
  2846. CreduiDebugLog("CreduiCredentialControl::InitWindow: "
  2847. "SCardUIInit failed\n");
  2848. }
  2849. }
  2850. // If NoEditUserName is allowed, make sure we eithet have at least one certificate
  2851. // or a prefilled username for the control, otherwise fail
  2852. if (NoEditUserName )
  2853. {
  2854. if (!haveCertificates &&
  2855. (ScardUiHandle == NULL))
  2856. {
  2857. return FALSE;
  2858. }
  2859. IsChangingUserName = TRUE;
  2860. SendMessage(UserNameControlWindow,
  2861. CB_SETCURSEL,
  2862. 0,
  2863. 0);
  2864. IsChangingUserName = FALSE;
  2865. // If we have at least one certificate, enable the view control
  2866. // now. If a smart card, it will be enabled later:
  2867. if (CertCount > 0)
  2868. {
  2869. EnableWindow(ViewCertControlWindow, TRUE);
  2870. DisabledControlMask &= ~DISABLED_CONTROL_VIEW;
  2871. }
  2872. }
  2873. // Wait until everything has been initialized before
  2874. // we have the update. This will now properly determine if the default
  2875. // user name is a smart card or not.
  2876. OnUserNameSelectionChange();
  2877. }
  2878. else
  2879. {
  2880. return FALSE;
  2881. }
  2882. }
  2883. if ( !DoingCommandLine ) {
  2884. SetFocus(UserNameControlWindow);
  2885. }
  2886. return TRUE;
  2887. }
  2888. //=============================================================================
  2889. // CredioCredentialControl::Enable
  2890. //
  2891. // Enables or disables all the user controls in the control.
  2892. //
  2893. // Arguments:
  2894. // enable (in) - TRUE to enable the controls, FALSE to disable.
  2895. //
  2896. // Created 06/20/2000 johnstep (John Stephens)
  2897. //=============================================================================
  2898. VOID
  2899. CreduiCredentialControl::Enable(
  2900. BOOL enable
  2901. )
  2902. {
  2903. if (enable && (DisabledControlMask & DISABLED_CONTROL))
  2904. {
  2905. DisabledControlMask &= ~DISABLED_CONTROL;
  2906. //EnableWindow(UserNameStaticWindow, TRUE);
  2907. //EnableWindow(UserNameControlWindow, TRUE);
  2908. if (!(DisabledControlMask & DISABLED_CONTROL_USERNAME))
  2909. {
  2910. EnableWindow(UserNameControlWindow, TRUE);
  2911. EnableWindow(UserNameStaticWindow, TRUE);
  2912. }
  2913. if (!(DisabledControlMask & DISABLED_CONTROL_PASSWORD))
  2914. {
  2915. EnableWindow(PasswordControlWindow, TRUE);
  2916. EnableWindow(PasswordStaticWindow, TRUE);
  2917. }
  2918. if (!(DisabledControlMask & DISABLED_CONTROL_VIEW))
  2919. {
  2920. EnableWindow(ViewCertControlWindow, TRUE);
  2921. }
  2922. if (SaveControlWindow != NULL)
  2923. {
  2924. if (!(DisabledControlMask & DISABLED_CONTROL_SAVE))
  2925. {
  2926. EnableWindow(SaveControlWindow, TRUE);
  2927. }
  2928. }
  2929. IsChangingUserName = TRUE;
  2930. SendMessage(UserNameControlWindow,
  2931. CB_SETCURSEL,
  2932. UserNameSelection,
  2933. 0);
  2934. IsChangingUserName = FALSE;
  2935. OnUserNameSelectionChange();
  2936. }
  2937. else if (!(DisabledControlMask & DISABLED_CONTROL))
  2938. {
  2939. // Hide the balloon tip before disabling the window:
  2940. if (BalloonTip.IsVisible())
  2941. {
  2942. BalloonTip.Hide();
  2943. }
  2944. DisabledControlMask |= DISABLED_CONTROL;
  2945. UserNameSelection = (LONG) SendMessage(UserNameControlWindow,
  2946. CB_GETCURSEL, 0, 0);
  2947. EnableWindow(UserNameStaticWindow, FALSE);
  2948. EnableWindow(UserNameControlWindow, FALSE);
  2949. EnableWindow(ViewCertControlWindow, FALSE);
  2950. EnableWindow(PasswordControlWindow, FALSE);
  2951. SetFocus(UserNameControlWindow);
  2952. EnableWindow(PasswordStaticWindow, FALSE);
  2953. if (SaveControlWindow != NULL)
  2954. {
  2955. EnableWindow(SaveControlWindow, FALSE);
  2956. }
  2957. }
  2958. }
  2959. //=============================================================================
  2960. // CreduiCredentialControl::MessageHandlerCallback
  2961. //
  2962. // This is the actual callback function for the control window.
  2963. //
  2964. // Arguments:
  2965. // window (in)
  2966. // message (in)
  2967. // wParam (in)
  2968. // lParam (in)
  2969. //
  2970. // Created 06/20/2000 johnstep (John Stephens)
  2971. //=============================================================================
  2972. LRESULT
  2973. CALLBACK
  2974. CreduiCredentialControl::MessageHandlerCallback(
  2975. HWND window,
  2976. UINT message,
  2977. WPARAM wParam,
  2978. LPARAM lParam
  2979. )
  2980. {
  2981. // CreduiDebugLog( "Control Callback: %8.8lx %8.8lx %8.8lx\n", message, wParam, lParam );
  2982. CreduiCredentialControl *that =
  2983. reinterpret_cast<CreduiCredentialControl *>(
  2984. GetWindowLongPtr(window, 0));
  2985. if (that != NULL)
  2986. {
  2987. LRESULT result2;
  2988. ASSERT(window == that->Window);
  2989. // CreduiDebugLog( "Certhashes: %8.8lx %8.8lx\n", that, that->CertHashes );
  2990. result2 = that->MessageHandler(message, wParam, lParam);
  2991. // CreduiDebugLog( "Certhashes2: %8.8lx %8.8lx\n", that, that->CertHashes );
  2992. return result2;
  2993. }
  2994. if (message == WM_CREATE)
  2995. {
  2996. CreduiCredentialControl *control = new CreduiCredentialControl;
  2997. if (control != NULL)
  2998. {
  2999. // Initialize some state:
  3000. control->FirstPaint = TRUE;
  3001. control->ShowBalloonTip = FALSE;
  3002. control->Window = window;
  3003. control->Style = GetWindowLong(window, GWL_STYLE);
  3004. // Store this object's pointer in the user data window long:
  3005. SetLastError(0);
  3006. LONG_PTR retPtr = SetWindowLongPtr(window,
  3007. 0,
  3008. reinterpret_cast<LONG_PTR>(control));
  3009. if ( retPtr != 0 || GetLastError() == 0 )
  3010. {
  3011. // we sucessfully set the window pointer
  3012. // If any of the required styles are set, initialize the window
  3013. // now. Otherwise, defer until CRM_INITSTYLE:
  3014. if (control->Style & (CRS_USERNAMES |
  3015. CRS_CERTIFICATES |
  3016. CRS_SMARTCARDS))
  3017. {
  3018. if (control->InitWindow())
  3019. {
  3020. return TRUE;
  3021. }
  3022. }
  3023. else
  3024. {
  3025. return TRUE;
  3026. }
  3027. }
  3028. SetWindowLongPtr(window, 0, 0);
  3029. delete control;
  3030. control = NULL;
  3031. }
  3032. DestroyWindow(window);
  3033. return 0;
  3034. }
  3035. return DefWindowProc(window, message, wParam, lParam);
  3036. }
  3037. //=============================================================================
  3038. // CreduiCredentialControl::OnSetUserNameA
  3039. //
  3040. // Created 06/22/2000 johnstep (John Stephens)
  3041. //=============================================================================
  3042. BOOL
  3043. CreduiCredentialControl::OnSetUserNameA(
  3044. CHAR *userNameA
  3045. )
  3046. {
  3047. BOOL success = FALSE;
  3048. if (userNameA != NULL)
  3049. {
  3050. ULONG bufferSize = lstrlenA(userNameA) + 1;
  3051. WCHAR *userName = new WCHAR[bufferSize];
  3052. if (userName != NULL)
  3053. {
  3054. if (MultiByteToWideChar(CP_ACP,
  3055. 0,
  3056. userNameA,
  3057. -1,
  3058. userName,
  3059. bufferSize) > 0)
  3060. {
  3061. success = OnSetUserName(userName);
  3062. }
  3063. delete [] userName;
  3064. }
  3065. }
  3066. else
  3067. {
  3068. success = OnSetUserName(NULL);
  3069. }
  3070. return success;
  3071. };
  3072. //=============================================================================
  3073. // CreduiCredentialControl::OnSetUserName
  3074. //
  3075. // Created 06/22/2000 johnstep (John Stephens)
  3076. //=============================================================================
  3077. BOOL
  3078. CreduiCredentialControl::OnSetUserName(
  3079. WCHAR *userName
  3080. )
  3081. {
  3082. if ((userName == NULL) || !LocalCredIsMarshaledCredentialW(userName))
  3083. {
  3084. //
  3085. // Save the initial user name for command line
  3086. //
  3087. if ( DoingCommandLine ) {
  3088. InitialUserName = new WCHAR[lstrlen(userName) + 1];
  3089. if ( InitialUserName == NULL ) {
  3090. return FALSE;
  3091. }
  3092. lstrcpy( InitialUserName, userName );
  3093. }
  3094. return SetWindowText(UserNameControlWindow, userName);
  3095. }
  3096. else
  3097. {
  3098. CRED_MARSHAL_TYPE credMarshalType;
  3099. CERT_CREDENTIAL_INFO *certCredInfo = NULL;
  3100. BOOL foundCert = FALSE;
  3101. if (LocalCredUnmarshalCredentialW(
  3102. userName,
  3103. &credMarshalType,
  3104. reinterpret_cast<VOID **>(&certCredInfo)))
  3105. {
  3106. // Search for the certificate. What can we do if it is a
  3107. // smart card? Well, at least we can still search for it,
  3108. // but it is a bit more work because we must retrieve the
  3109. // hash from the context.
  3110. if (credMarshalType == CertCredential)
  3111. {
  3112. for (UINT i = 0; i < CertCount; ++i)
  3113. {
  3114. if (RtlCompareMemory(CertHashes[i],
  3115. certCredInfo->rgbHashOfCert,
  3116. CERT_HASH_LENGTH) ==
  3117. CERT_HASH_LENGTH)
  3118. {
  3119. IsChangingUserName = TRUE;
  3120. SendMessage(UserNameControlWindow,
  3121. CB_SETCURSEL,
  3122. CertBaseInComboBox + i,
  3123. 0);
  3124. IsChangingUserName = FALSE;
  3125. OnUserNameSelectionChange();
  3126. EnableWindow(ViewCertControlWindow, TRUE);
  3127. DisabledControlMask &= ~DISABLED_CONTROL_VIEW;
  3128. foundCert = TRUE;
  3129. break;
  3130. }
  3131. }
  3132. // If we couldn't find the certificate in our list, determine
  3133. // if this is a smart card certificate, based on its entry in
  3134. // the MY certificate store. If it is, store the hash and
  3135. // check for it on certificate arrival messages:
  3136. if (!foundCert)
  3137. {
  3138. CONST CERT_CONTEXT *certContext = NULL;
  3139. HCERTSTORE certStore = NULL;
  3140. certStore = CertOpenSystemStore(NULL, L"MY");
  3141. if (certStore != NULL)
  3142. {
  3143. CRYPT_HASH_BLOB hashBlob;
  3144. hashBlob.cbData = CERT_HASH_LENGTH;
  3145. hashBlob.pbData = reinterpret_cast<BYTE *>(
  3146. certCredInfo->rgbHashOfCert);
  3147. certContext = CertFindCertificateInStore(
  3148. certStore,
  3149. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  3150. 0,
  3151. CERT_FIND_SHA1_HASH,
  3152. &hashBlob,
  3153. NULL);
  3154. }
  3155. // If we found a certificate context, check to see if it
  3156. // is from a smart card:
  3157. if ((certContext != NULL) &&
  3158. CreduiIsRemovableCertificate(certContext))
  3159. {
  3160. UserNameCertHash = new UCHAR [1][CERT_HASH_LENGTH];
  3161. if (UserNameCertHash != NULL)
  3162. {
  3163. CopyMemory(UserNameCertHash,
  3164. certCredInfo->rgbHashOfCert,
  3165. CERT_HASH_LENGTH);
  3166. foundCert = TRUE;
  3167. }
  3168. }
  3169. // If we opened a store, free the certificate and close
  3170. // the store:
  3171. if (certStore != NULL)
  3172. {
  3173. if (certContext != NULL)
  3174. {
  3175. CertFreeCertificateContext(certContext);
  3176. }
  3177. if (!CertCloseStore(certStore, 0))
  3178. {
  3179. CreduiDebugLog(
  3180. "CreduiCredentialControl::OnSetUserName: "
  3181. "CertCloseStore failed: %u\n",
  3182. GetLastError());
  3183. }
  3184. }
  3185. }
  3186. }
  3187. LocalCredFree(static_cast<VOID *>(certCredInfo));
  3188. }
  3189. else
  3190. {
  3191. // Could not unmarshal, so just forget it:
  3192. CreduiDebugLog(
  3193. "CreduiCredentialControl::OnSetUserName: "
  3194. "CredUnmarshalCredential failed: %u\n",
  3195. GetLastError());
  3196. }
  3197. return foundCert;
  3198. }
  3199. };
  3200. //=============================================================================
  3201. // CreduiCredentialControl::OnGetUserNameA
  3202. //
  3203. // Created 06/22/2000 johnstep (John Stephens)
  3204. //=============================================================================
  3205. BOOL
  3206. CreduiCredentialControl::OnGetUserNameA(
  3207. CHAR *userNameA,
  3208. ULONG maxChars
  3209. )
  3210. {
  3211. BOOL success = FALSE;
  3212. if ((userNameA != NULL) && (maxChars != 0))
  3213. {
  3214. WCHAR *userName = new WCHAR[maxChars + 1];
  3215. if (userName != NULL)
  3216. {
  3217. if (OnGetUserName(userName, maxChars) &&
  3218. WideCharToMultiByte(
  3219. CP_ACP,
  3220. 0,
  3221. userName,
  3222. -1,
  3223. userNameA,
  3224. maxChars + 1, NULL, NULL))
  3225. {
  3226. success = TRUE;
  3227. }
  3228. delete [] userName;
  3229. }
  3230. }
  3231. return success;
  3232. };
  3233. //=============================================================================
  3234. // CreduiCredentialControl::OnGetUserName
  3235. //
  3236. // Created 06/22/2000 johnstep (John Stephens)
  3237. //=============================================================================
  3238. BOOL
  3239. CreduiCredentialControl::OnGetUserName(
  3240. WCHAR *userName,
  3241. ULONG maxChars
  3242. )
  3243. {
  3244. if ( KeepUserName )
  3245. {
  3246. SetLastError(0);
  3247. return (GetWindowText(UserNameControlWindow,
  3248. userName,
  3249. maxChars + 1) > 0) ||
  3250. (GetLastError() == ERROR_SUCCESS);
  3251. }
  3252. else
  3253. {
  3254. COMBOBOXEXITEM item;
  3255. item.iItem = SendMessage(UserNameControlWindow, CB_GETCURSEL, 0, 0);
  3256. // If we are trying to match a smart card certificate, fail this:
  3257. if (UserNameCertHash != NULL)
  3258. {
  3259. return FALSE;
  3260. }
  3261. // If this is not a certificate, it's easy:
  3262. if ((item.iItem == CB_ERR) || (item.iItem < CertBaseInComboBox))
  3263. {
  3264. BOOL RetVal;
  3265. SetLastError(0);
  3266. RetVal = GetWindowText(UserNameControlWindow,
  3267. userName,
  3268. maxChars + 1) > 0;
  3269. if ( !RetVal ) {
  3270. return ( GetLastError() == ERROR_SUCCESS );
  3271. }
  3272. //
  3273. // Complete the typed in username
  3274. if ( Style & CRS_COMPLETEUSERNAME) {
  3275. RetVal = CompleteUserName(
  3276. userName,
  3277. maxChars,
  3278. NULL, // No target info
  3279. NULL,
  3280. 0); // No target name
  3281. } else {
  3282. RetVal = TRUE;
  3283. }
  3284. return RetVal;
  3285. }
  3286. // This is a certificate, maybe from a smart card:
  3287. item.mask = CBEIF_IMAGE | CBEIF_TEXT;
  3288. item.pszText = userName;
  3289. item.cchTextMax = maxChars + 1;
  3290. if (!SendMessage(UserNameControlWindow,
  3291. CBEM_GETITEM,
  3292. 0,
  3293. reinterpret_cast<LPARAM>(&item)))
  3294. {
  3295. return FALSE;
  3296. }
  3297. CERT_CREDENTIAL_INFO certCredInfo;
  3298. certCredInfo.cbSize = sizeof certCredInfo;
  3299. if (item.iItem >= SmartCardBaseInComboBox)
  3300. {
  3301. if (item.iImage == IMAGE_SMART_CARD_MISSING)
  3302. {
  3303. return FALSE;
  3304. }
  3305. CERT_ENUM *certEnum =
  3306. reinterpret_cast<CERT_ENUM *>(
  3307. SendMessage(UserNameControlWindow,
  3308. CB_GETITEMDATA, item.iItem, 0));
  3309. // NOTE: Consider more complete error handling here.
  3310. if (certEnum != NULL)
  3311. {
  3312. DWORD length = CERT_HASH_LENGTH;
  3313. if (!CertGetCertificateContextProperty(
  3314. certEnum->pCertContext,
  3315. CERT_SHA1_HASH_PROP_ID,
  3316. static_cast<VOID *>(
  3317. certCredInfo.rgbHashOfCert),
  3318. &length))
  3319. {
  3320. return FALSE;
  3321. }
  3322. }
  3323. else
  3324. {
  3325. return FALSE;
  3326. }
  3327. }
  3328. else
  3329. {
  3330. CopyMemory(certCredInfo.rgbHashOfCert,
  3331. &CertHashes[item.iItem - CertBaseInComboBox],
  3332. CERT_HASH_LENGTH);
  3333. }
  3334. WCHAR *marshaledCred;
  3335. if (LocalCredMarshalCredentialW(CertCredential,
  3336. &certCredInfo,
  3337. &marshaledCred))
  3338. {
  3339. lstrcpyn(userName,
  3340. marshaledCred,
  3341. maxChars + 1);
  3342. LocalCredFree(static_cast<VOID *>(marshaledCred));
  3343. return TRUE;
  3344. }
  3345. else
  3346. {
  3347. CreduiDebugLog("CreduiCredentialControl::OnGetUserName: "
  3348. "CredMarshalCredential failed: %u\n",
  3349. GetLastError());
  3350. return FALSE;
  3351. }
  3352. }
  3353. }
  3354. //=============================================================================
  3355. // CreduiCredentialControl::OnSetPasswordA
  3356. //
  3357. // Created 06/22/2000 johnstep (John Stephens)
  3358. //=============================================================================
  3359. BOOL
  3360. CreduiCredentialControl::OnSetPasswordA(
  3361. CHAR *passwordA
  3362. )
  3363. {
  3364. return SetWindowTextA(PasswordControlWindow, passwordA);
  3365. };
  3366. //=============================================================================
  3367. // CreduiCredentialControl::OnSetPassword
  3368. //
  3369. // Created 06/22/2000 johnstep (John Stephens)
  3370. //=============================================================================
  3371. BOOL
  3372. CreduiCredentialControl::OnSetPassword(
  3373. WCHAR *password
  3374. )
  3375. {
  3376. return SetWindowText(PasswordControlWindow, password);
  3377. };
  3378. //=============================================================================
  3379. // CreduiCredentialControl::OnGetPasswordA
  3380. //
  3381. // Created 06/22/2000 johnstep (John Stephens)
  3382. //=============================================================================
  3383. BOOL
  3384. CreduiCredentialControl::OnGetPasswordA(
  3385. CHAR *passwordA,
  3386. ULONG maxChars
  3387. )
  3388. {
  3389. if (DisabledControlMask & DISABLED_CONTROL_PASSWORD)
  3390. {
  3391. return FALSE;
  3392. }
  3393. SetLastError(0);
  3394. return (GetWindowTextA(PasswordControlWindow,
  3395. passwordA,
  3396. maxChars + 1) > 0) ||
  3397. (GetLastError() == ERROR_SUCCESS);
  3398. };
  3399. //=============================================================================
  3400. // CreduiCredentialControl::OnGetPassword
  3401. //
  3402. // Created 06/22/2000 johnstep (John Stephens)
  3403. //=============================================================================
  3404. BOOL
  3405. CreduiCredentialControl::OnGetPassword(
  3406. WCHAR *password,
  3407. ULONG maxChars
  3408. )
  3409. {
  3410. if (DisabledControlMask & DISABLED_CONTROL_PASSWORD)
  3411. {
  3412. return FALSE;
  3413. }
  3414. SetLastError(0);
  3415. return (GetWindowText(PasswordControlWindow,
  3416. password,
  3417. maxChars + 1) > 0) ||
  3418. (GetLastError() == ERROR_SUCCESS);
  3419. };
  3420. //=============================================================================
  3421. // CreduiCredentialControl::OnGetUserNameLength
  3422. //
  3423. // Created 07/19/2000 johnstep (John Stephens)
  3424. //=============================================================================
  3425. LONG
  3426. CreduiCredentialControl::OnGetUserNameLength()
  3427. {
  3428. COMBOBOXEXITEM item;
  3429. if (UserNameCertHash != NULL)
  3430. {
  3431. return -1;
  3432. }
  3433. item.iItem = SendMessage(UserNameControlWindow, CB_GETCURSEL, 0, 0);
  3434. // If this is not a certificate, it's easy:
  3435. if ((item.iItem == CB_ERR) || (item.iItem < CertBaseInComboBox))
  3436. {
  3437. return GetWindowTextLength(UserNameControlWindow);
  3438. }
  3439. else
  3440. {
  3441. WCHAR userName[CREDUI_MAX_USERNAME_LENGTH + 1];
  3442. if (OnGetUserName(userName, CREDUI_MAX_USERNAME_LENGTH))
  3443. {
  3444. return lstrlen(userName);
  3445. }
  3446. else
  3447. {
  3448. return -1;
  3449. }
  3450. }
  3451. }
  3452. //=============================================================================
  3453. // CreduiCredentialControl::OnShowBalloonA
  3454. //
  3455. // Created 06/23/2000 johnstep (John Stephens)
  3456. //=============================================================================
  3457. BOOL
  3458. CreduiCredentialControl::OnShowBalloonA(
  3459. CREDUI_BALLOONA *balloonA
  3460. )
  3461. {
  3462. // If NULL was passed, this means to hide the balloon:
  3463. if (balloonA == NULL)
  3464. {
  3465. if (BalloonTip.IsVisible())
  3466. {
  3467. BalloonTip.Hide();
  3468. }
  3469. return TRUE;
  3470. }
  3471. // Argument validation, should match OnShowBalloon:
  3472. if ((balloonA->dwVersion != 1) ||
  3473. (balloonA->pszTitleText == NULL) ||
  3474. (balloonA->pszMessageText == NULL))
  3475. {
  3476. return FALSE;
  3477. }
  3478. if ((balloonA->pszTitleText[0] == '\0') ||
  3479. (balloonA->pszMessageText[0] == '\0'))
  3480. {
  3481. return FALSE;
  3482. }
  3483. BOOL success = FALSE;
  3484. CREDUI_BALLOON balloon;
  3485. balloon.dwVersion = balloonA->dwVersion;
  3486. balloon.iControl = balloonA->iControl;
  3487. balloon.iIcon = balloonA->iIcon;
  3488. ULONG titleTextLength = lstrlenA(balloonA->pszTitleText);
  3489. ULONG messageTextLength = lstrlenA(balloonA->pszMessageText);
  3490. balloon.pszTitleText = new WCHAR[titleTextLength + 1];
  3491. if (balloon.pszTitleText != NULL)
  3492. {
  3493. if (MultiByteToWideChar(CP_ACP,
  3494. 0,
  3495. balloonA->pszTitleText,
  3496. -1,
  3497. balloon.pszTitleText,
  3498. titleTextLength + 1) > 0)
  3499. {
  3500. balloon.pszMessageText = new WCHAR[messageTextLength + 1];
  3501. if (balloon.pszMessageText != NULL)
  3502. {
  3503. if (MultiByteToWideChar(CP_ACP,
  3504. 0,
  3505. balloonA->pszMessageText,
  3506. -1,
  3507. balloon.pszMessageText,
  3508. messageTextLength + 1) > 0)
  3509. {
  3510. success = OnShowBalloon(&balloon);
  3511. }
  3512. delete [] balloon.pszMessageText;
  3513. }
  3514. }
  3515. delete [] balloon.pszTitleText;
  3516. }
  3517. return success;
  3518. };
  3519. //=============================================================================
  3520. // CreduiCredentialControl::OnShowBalloon
  3521. //
  3522. // Created 06/23/2000 johnstep (John Stephens)
  3523. //=============================================================================
  3524. BOOL
  3525. CreduiCredentialControl::OnShowBalloon(
  3526. CREDUI_BALLOON *balloon
  3527. )
  3528. {
  3529. // If NULL was passed, this means to hide the balloon:
  3530. if (balloon == NULL)
  3531. {
  3532. if (BalloonTip.IsVisible())
  3533. {
  3534. BalloonTip.Hide();
  3535. }
  3536. return TRUE;
  3537. }
  3538. // Argument validation:
  3539. if ((balloon->dwVersion != 1) ||
  3540. (balloon->pszTitleText == NULL) ||
  3541. (balloon->pszMessageText == NULL))
  3542. {
  3543. return FALSE;
  3544. }
  3545. if ((balloon->pszTitleText[0] == L'\0') ||
  3546. (balloon->pszMessageText[0] == L'\0'))
  3547. {
  3548. return FALSE;
  3549. }
  3550. lstrcpyn(CreduiCustomTipInfo.Title,
  3551. balloon->pszTitleText,
  3552. CREDUI_MAX_BALLOON_TITLE_LENGTH + 1);
  3553. lstrcpyn(CreduiCustomTipInfo.Text,
  3554. balloon->pszMessageText,
  3555. CREDUI_MAX_BALLOON_MESSAGE_LENGTH + 1);
  3556. CreduiCustomTipInfo.Icon = balloon->iIcon;
  3557. // BalloonTip.SetInfo(
  3558. // (balloon->iControl == CREDUI_CONTROL_PASSWORD) ?
  3559. // PasswordControlWindow : UserNameControlWindow,
  3560. // &CreduiCustomTipInfo);
  3561. if ( balloon->iControl != CREDUI_CONTROL_PASSWORD )
  3562. BalloonTip.SetInfo( UserNameControlWindow, &CreduiCustomTipInfo);
  3563. BalloonTip.Show();
  3564. return TRUE;
  3565. };
  3566. //=============================================================================
  3567. // CreduiCredentialControl::OnUserNameSelectionChange
  3568. //
  3569. // Created 06/21/2000 johnstep (John Stephens)
  3570. //=============================================================================
  3571. VOID
  3572. CreduiCredentialControl::OnUserNameSelectionChange()
  3573. {
  3574. COMBOBOXEXITEM item;
  3575. LRESULT current;
  3576. // Delete the user name certificate hash if the user has changed the
  3577. // selection:
  3578. if (UserNameCertHash != NULL)
  3579. {
  3580. delete [] UserNameCertHash;
  3581. UserNameCertHash = NULL;
  3582. }
  3583. current = SendMessage(UserNameControlWindow,
  3584. CB_GETCURSEL, 0, 0);
  3585. item.mask = CBEIF_IMAGE;
  3586. item.iItem = current;
  3587. SendMessage(UserNameControlWindow, CBEM_GETITEM,
  3588. 0, reinterpret_cast<LPARAM>(&item));
  3589. if (current < CertBaseInComboBox)
  3590. {
  3591. EnableWindow(ViewCertControlWindow, FALSE);
  3592. DisabledControlMask |= DISABLED_CONTROL_VIEW;
  3593. SetWindowText(
  3594. PasswordStaticWindow,
  3595. CreduiStrings.PasswordStatic);
  3596. EnableWindow(PasswordControlWindow, TRUE);
  3597. EnableWindow(PasswordStaticWindow, TRUE);
  3598. DisabledControlMask &= ~DISABLED_CONTROL_PASSWORD;
  3599. WCHAR* pUserNameLabel;
  3600. if ( IsPassport )
  3601. pUserNameLabel = CreduiStrings.EmailName;
  3602. else
  3603. pUserNameLabel = CreduiStrings.UserNameStatic;
  3604. SetWindowText(
  3605. UserNameStaticWindow,
  3606. pUserNameLabel);
  3607. if (SaveControlWindow != NULL)
  3608. {
  3609. EnableWindow(SaveControlWindow, TRUE);
  3610. DisabledControlMask &= ~DISABLED_CONTROL_SAVE;
  3611. }
  3612. }
  3613. else
  3614. {
  3615. SetWindowText(
  3616. PasswordStaticWindow,
  3617. CreduiStrings.PinStatic);
  3618. if (item.iImage != IMAGE_SMART_CARD_MISSING)
  3619. {
  3620. EnableWindow(ViewCertControlWindow, TRUE);
  3621. DisabledControlMask &= ~DISABLED_CONTROL_VIEW;
  3622. }
  3623. else
  3624. {
  3625. EnableWindow(ViewCertControlWindow, FALSE);
  3626. DisabledControlMask |= DISABLED_CONTROL_VIEW;
  3627. }
  3628. IsChangingPassword = TRUE;
  3629. SetWindowText(PasswordControlWindow, NULL);
  3630. IsChangingPassword = FALSE;
  3631. if (current >= SmartCardBaseInComboBox)
  3632. {
  3633. EnableWindow(PasswordControlWindow, TRUE);
  3634. EnableWindow(PasswordStaticWindow, TRUE);
  3635. DisabledControlMask &= ~DISABLED_CONTROL_PASSWORD;
  3636. }
  3637. else
  3638. {
  3639. EnableWindow(PasswordControlWindow, FALSE);
  3640. EnableWindow(PasswordStaticWindow, FALSE);
  3641. DisabledControlMask |= DISABLED_CONTROL_PASSWORD;
  3642. }
  3643. SetWindowText(
  3644. UserNameStaticWindow,
  3645. item.iImage >= IMAGE_SMART_CARD ?
  3646. CreduiStrings.SmartCardStatic :
  3647. CreduiStrings.CertificateStatic);
  3648. if (SaveControlWindow != NULL)
  3649. {
  3650. EnableWindow(SaveControlWindow, FALSE);
  3651. DisabledControlMask |= DISABLED_CONTROL_SAVE;
  3652. }
  3653. }
  3654. }
  3655. //=============================================================================
  3656. // CreduiCredentialControl::MessageHandler
  3657. //
  3658. // Called from the control window callback to handle the window messages.
  3659. //
  3660. // Arguments:
  3661. // message (in)
  3662. // wParam (in)
  3663. // lParam (in)
  3664. //
  3665. // Created 06/20/2000 johnstep (John Stephens)
  3666. //=============================================================================
  3667. LRESULT
  3668. CreduiCredentialControl::MessageHandler(
  3669. UINT message,
  3670. WPARAM wParam,
  3671. LPARAM lParam
  3672. )
  3673. {
  3674. // If not initialized, only handle CRM_INITSTYLE:
  3675. if (!IsInitialized)
  3676. {
  3677. if (message == CRM_INITSTYLE)
  3678. {
  3679. wParam &= CRS_USERNAMES |
  3680. CRS_CERTIFICATES |
  3681. CRS_SMARTCARDS |
  3682. CRS_ADMINISTRATORS |
  3683. CRS_PREFILLADMIN |
  3684. CRS_COMPLETEUSERNAME |
  3685. CRS_SAVECHECK |
  3686. CRS_KEEPUSERNAME;
  3687. if (wParam != 0)
  3688. {
  3689. Style |= wParam;
  3690. SetWindowLong(Window,
  3691. GWL_STYLE,
  3692. GetWindowLong(Window, GWL_STYLE) | Style);
  3693. DoingCommandLine = (BOOL) lParam;
  3694. return InitWindow();
  3695. }
  3696. return FALSE;
  3697. }
  3698. else
  3699. {
  3700. return DefWindowProc(Window, message, wParam, lParam);
  3701. }
  3702. }
  3703. else if (message == WM_ENABLE)
  3704. {
  3705. Enable((BOOL) wParam);
  3706. }
  3707. // Always handle smart card messages, if support is available:
  3708. if (ScardUiHandle != NULL)
  3709. {
  3710. // This function call will return TRUE if the message was handled:
  3711. if (HandleSmartCardMessages(
  3712. message,
  3713. reinterpret_cast<CERT_ENUM *>(wParam)))
  3714. {
  3715. return 0;
  3716. }
  3717. }
  3718. switch (message)
  3719. {
  3720. case CRM_SETUSERNAMEMAX:
  3721. SendMessage(UserNameControlWindow, CB_LIMITTEXT, wParam, 0);
  3722. return TRUE;
  3723. case CRM_SETPASSWORDMAX:
  3724. SendMessage(PasswordControlWindow, EM_LIMITTEXT, wParam, 0);
  3725. return TRUE;
  3726. case CRM_DISABLEUSERNAME:
  3727. {
  3728. DisabledControlMask |= DISABLED_CONTROL_USERNAME;
  3729. EnableWindow(UserNameControlWindow,FALSE);
  3730. EnableWindow(UserNameStaticWindow,FALSE);
  3731. return TRUE;
  3732. }
  3733. case CRM_ENABLEUSERNAME:
  3734. {
  3735. DisabledControlMask &= ~DISABLED_CONTROL_USERNAME;
  3736. EnableWindow(UserNameControlWindow,TRUE);
  3737. EnableWindow(UserNameStaticWindow,TRUE);
  3738. return TRUE;
  3739. }
  3740. case CRM_GETUSERNAMEMAX:
  3741. return
  3742. SendMessage(
  3743. reinterpret_cast<HWND>(
  3744. SendMessage(Window, CBEM_GETEDITCONTROL, 0, 0)),
  3745. EM_GETLIMITTEXT,
  3746. 0,
  3747. 0);
  3748. case CRM_GETPASSWORDMAX:
  3749. return SendMessage(UserNameControlWindow, EM_GETLIMITTEXT, 0, 0);
  3750. case CRM_SETUSERNAMEA:
  3751. return OnSetUserNameA(reinterpret_cast<CHAR *>(lParam));
  3752. case CRM_SETUSERNAMEW:
  3753. return OnSetUserName(reinterpret_cast<WCHAR *>(lParam));
  3754. case CRM_GETUSERNAMEA:
  3755. return OnGetUserNameA(reinterpret_cast<CHAR *>(lParam), (ULONG) wParam);
  3756. case CRM_GETUSERNAMEW:
  3757. return OnGetUserName(reinterpret_cast<WCHAR *>(lParam), (ULONG) wParam);
  3758. case CRM_SETPASSWORDA:
  3759. return OnSetPasswordA(reinterpret_cast<CHAR *>(lParam));
  3760. case CRM_SETPASSWORDW:
  3761. return OnSetPassword(reinterpret_cast<WCHAR *>(lParam));
  3762. case CRM_GETPASSWORDA:
  3763. return OnGetPasswordA(reinterpret_cast<CHAR *>(lParam), (ULONG) wParam);
  3764. case CRM_GETPASSWORDW:
  3765. return OnGetPassword(reinterpret_cast<WCHAR *>(lParam), (ULONG) wParam);
  3766. case CRM_GETUSERNAMELENGTH:
  3767. return OnGetUserNameLength();
  3768. case CRM_GETPASSWORDLENGTH:
  3769. if (IsWindowEnabled(PasswordControlWindow))
  3770. {
  3771. return GetWindowTextLength(PasswordControlWindow);
  3772. }
  3773. return -1;
  3774. case CRM_SETFOCUS:
  3775. if ( DoingCommandLine ) {
  3776. return 0;
  3777. }
  3778. switch (wParam)
  3779. {
  3780. case CREDUI_CONTROL_USERNAME:
  3781. SetFocus(UserNameControlWindow);
  3782. return TRUE;
  3783. case CREDUI_CONTROL_PASSWORD:
  3784. if (IsWindowEnabled(PasswordControlWindow))
  3785. {
  3786. SetFocus(PasswordControlWindow);
  3787. // NOTE: Is it OK to always select the entire password text
  3788. // on this explicit set focus message?
  3789. SendMessage(PasswordControlWindow, EM_SETSEL, 0, -1);
  3790. return TRUE;
  3791. }
  3792. break;
  3793. }
  3794. return 0;
  3795. case CRM_SHOWBALLOONA:
  3796. return OnShowBalloonA(reinterpret_cast<CREDUI_BALLOONA *>(lParam));
  3797. case CRM_SHOWBALLOONW:
  3798. return OnShowBalloon(reinterpret_cast<CREDUI_BALLOON *>(lParam));
  3799. case CRM_GETMINSIZE:
  3800. SIZE *minSize;
  3801. minSize = reinterpret_cast<SIZE *>(lParam);
  3802. if (minSize != NULL)
  3803. {
  3804. minSize->cx = CREDUI_CONTROL_MIN_WIDTH;
  3805. minSize->cy = CREDUI_CONTROL_MIN_HEIGHT;
  3806. if (Style & CRS_SAVECHECK )
  3807. {
  3808. minSize->cy += CREDUI_CONTROL_ADD_SAVE;
  3809. }
  3810. return TRUE;
  3811. }
  3812. return FALSE;
  3813. case CRM_SETCHECK:
  3814. switch (wParam)
  3815. {
  3816. case CREDUI_CONTROL_SAVE:
  3817. if ((Style & CRS_SAVECHECK ) &&
  3818. IsWindowEnabled(SaveControlWindow))
  3819. {
  3820. CheckDlgButton(Window, IDC_SAVE,
  3821. lParam ? BST_CHECKED : BST_UNCHECKED);
  3822. return TRUE;
  3823. }
  3824. break;
  3825. }
  3826. return FALSE;
  3827. case CRM_GETCHECK:
  3828. switch (wParam)
  3829. {
  3830. case CREDUI_CONTROL_SAVE:
  3831. return
  3832. (Style & CRS_SAVECHECK ) &&
  3833. IsWindowEnabled(SaveControlWindow) &&
  3834. IsDlgButtonChecked(Window, IDC_SAVE);
  3835. default:
  3836. return FALSE;
  3837. }
  3838. case CRM_DOCMDLINE:
  3839. ASSERT( DoingCommandLine );
  3840. //
  3841. // For smartcards,
  3842. // just start the timer and we'll prompt when the timer has gone off.
  3843. //
  3844. TargetName = (LPWSTR)lParam;
  3845. if ( Style & CRS_SMARTCARDS) {
  3846. DWORD WinStatus;
  3847. Heartbeats = 0;
  3848. {
  3849. WCHAR szMsg[CREDUI_MAX_CMDLINE_MSG_LENGTH + 1];
  3850. szMsg[0] = 0;
  3851. FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  3852. CreduiInstance,
  3853. IDS_READING_SMARTCARDS,
  3854. 0,
  3855. szMsg,
  3856. CREDUI_MAX_CMDLINE_MSG_LENGTH,
  3857. NULL);
  3858. CredPutStdout(szMsg);
  3859. }
  3860. if ( SetTimer ( Window, CREDUI_HEARTBEAT_TIMER, CREDUI_HEARTBEAT_TIMER_VALUE, NULL ) == 0 ) {
  3861. // bail out of our wait loop if we couldn't set a timer
  3862. return GetLastError();
  3863. }
  3864. //
  3865. // For passwords,
  3866. // just do the prompt to save.
  3867. //
  3868. } else {
  3869. CmdlineSavePrompt();
  3870. PostQuitMessage( NO_ERROR );
  3871. }
  3872. return NO_ERROR;
  3873. case WM_HELP:
  3874. return OnHelpInfo(lParam);
  3875. case WM_SETFONT:
  3876. // Forward font setting from dialog to each control, except the
  3877. // password control since we use a special font there:
  3878. if (UserNameStaticWindow != NULL)
  3879. {
  3880. SendMessage(UserNameStaticWindow, message, wParam, lParam);
  3881. }
  3882. if (UserNameControlWindow != NULL)
  3883. {
  3884. SendMessage(UserNameControlWindow, message, wParam, lParam);
  3885. }
  3886. if (ViewCertControlWindow != NULL)
  3887. {
  3888. SendMessage(ViewCertControlWindow, message, wParam, lParam);
  3889. }
  3890. if (PasswordStaticWindow != NULL)
  3891. {
  3892. SendMessage(PasswordStaticWindow, message, wParam, lParam);
  3893. }
  3894. if (PasswordControlWindow != NULL)
  3895. {
  3896. SendMessage(PasswordControlWindow, message, wParam, lParam);
  3897. }
  3898. if (SaveControlWindow != NULL)
  3899. {
  3900. SendMessage(SaveControlWindow, message, wParam, lParam);
  3901. }
  3902. break;
  3903. case WM_COMMAND:
  3904. switch (LOWORD(wParam))
  3905. {
  3906. case IDC_VIEW_CERT:
  3907. ViewCertificate((INT)
  3908. SendMessage(UserNameControlWindow,
  3909. CB_GETCURSEL, 0, 0));
  3910. return 0;
  3911. case IDC_PASSWORD:
  3912. if (HIWORD(wParam) == EN_CHANGE)
  3913. {
  3914. // Always send the change message?
  3915. SendMessage(
  3916. GetParent(Window),
  3917. WM_COMMAND,
  3918. MAKELONG(GetWindowLongPtr(Window, GWLP_ID),
  3919. CRN_PASSWORDCHANGE),
  3920. reinterpret_cast<LPARAM>(Window));
  3921. }
  3922. return 0;
  3923. case IDC_USERNAME:
  3924. switch (HIWORD(wParam))
  3925. {
  3926. case CBN_EDITCHANGE:
  3927. case CBN_DROPDOWN:
  3928. case CBN_KILLFOCUS:
  3929. if ((HIWORD(wParam) != CBN_EDITCHANGE) || !IsChangingUserName)
  3930. {
  3931. if (BalloonTip.IsVisible())
  3932. {
  3933. BalloonTip.Hide();
  3934. }
  3935. }
  3936. if (HIWORD(wParam) == CBN_EDITCHANGE)
  3937. {
  3938. // Always send the change message?
  3939. SendMessage(
  3940. GetParent(Window),
  3941. WM_COMMAND,
  3942. MAKELONG(GetWindowLongPtr(Window, GWLP_ID),
  3943. CRN_USERNAMECHANGE),
  3944. reinterpret_cast<LPARAM>(Window));
  3945. // If the name has changed as a result of user editing,
  3946. // reset to user name settings:
  3947. BOOL isDropped = (BOOL)
  3948. SendMessage(UserNameControlWindow,
  3949. CB_GETDROPPEDSTATE, 0, 0);
  3950. if (isDropped)
  3951. {
  3952. OnUserNameSelectionChange();
  3953. RECT rect;
  3954. GetClientRect(UserNameControlWindow, &rect);
  3955. InvalidateRect(UserNameControlWindow, &rect, FALSE);
  3956. SendMessage(Window,
  3957. CB_SETCURSEL,
  3958. SendMessage(Window, CB_GETCURSEL, 0, 0),
  3959. 0);
  3960. return 0;
  3961. }
  3962. if (IsChangingUserName)
  3963. {
  3964. return 0;
  3965. }
  3966. if (((UserNameCertHash != NULL) ||
  3967. (SendMessage(UserNameControlWindow,
  3968. CB_GETCURSEL, 0, 0) >= CertBaseInComboBox)) &&
  3969. !isDropped)
  3970. {
  3971. if (UserNameCertHash != NULL)
  3972. {
  3973. delete [] UserNameCertHash;
  3974. UserNameCertHash = NULL;
  3975. }
  3976. if (!SendMessage(UserNameControlWindow,
  3977. CB_GETDROPPEDSTATE, 0, 0))
  3978. {
  3979. SetFocus(UserNameControlWindow);
  3980. if (SendMessage(UserNameControlWindow,
  3981. CB_GETCURSEL, 0, 0) == CB_ERR)
  3982. {
  3983. IsChangingUserName = TRUE;
  3984. UserNameComboBox.Update(
  3985. -1,
  3986. L"",
  3987. IMAGE_USERNAME);
  3988. IsChangingUserName = FALSE;
  3989. IsChangingPassword = TRUE;
  3990. SetWindowText(PasswordControlWindow, NULL);
  3991. IsChangingPassword = FALSE;
  3992. OnUserNameSelectionChange();
  3993. }
  3994. }
  3995. }
  3996. }
  3997. if (HIWORD(wParam) == CBN_DROPDOWN)
  3998. {
  3999. if (UserNameCertHash != NULL)
  4000. {
  4001. delete [] UserNameCertHash;
  4002. UserNameCertHash = NULL;
  4003. IsChangingUserName = TRUE;
  4004. UserNameComboBox.Update(
  4005. -1,
  4006. L"",
  4007. IMAGE_USERNAME);
  4008. IsChangingUserName = FALSE;
  4009. IsChangingPassword = TRUE;
  4010. SetWindowText(PasswordControlWindow, NULL);
  4011. IsChangingPassword = FALSE;
  4012. OnUserNameSelectionChange();
  4013. }
  4014. }
  4015. return 0;
  4016. case CBN_SELCHANGE:
  4017. OnUserNameSelectionChange();
  4018. return 0;
  4019. }
  4020. break;
  4021. case IDC_SAVE:
  4022. if (HIWORD(wParam) == BN_CLICKED)
  4023. {
  4024. return TRUE;
  4025. }
  4026. break;
  4027. }
  4028. break;
  4029. case WM_PAINT:
  4030. if (FirstPaint && GetUpdateRect(Window, NULL, FALSE))
  4031. {
  4032. FirstPaint = FALSE;
  4033. if (ShowBalloonTip)
  4034. {
  4035. ShowBalloonTip = FALSE;
  4036. BalloonTip.Show();
  4037. }
  4038. }
  4039. break;
  4040. case WM_TIMER:
  4041. if ( wParam == CREDUI_HEARTBEAT_TIMER )
  4042. {
  4043. Heartbeats++;
  4044. #ifdef SCARDREPORTS
  4045. CreduiDebugLog("CREDUI: thump thump\n",this->Window);
  4046. #endif
  4047. //
  4048. // If we've waited long enough,
  4049. // or all cards have been read,
  4050. // process the cards.
  4051. //
  4052. if ( Heartbeats > CREDUI_MAX_HEARTBEATS ||
  4053. ( Heartbeats > 2 && SmartCardReadCount == 0 )) {
  4054. #ifdef SCARDREPORTS
  4055. CreduiDebugLog("CREDUI: Heartbeat timeout\n",this->Window);
  4056. #endif
  4057. fputs( "\n", stdout );
  4058. KillTimer ( Window, CREDUI_HEARTBEAT_TIMER );
  4059. CmdlineSmartCardPrompt();
  4060. //
  4061. // If we're going to wait longer,
  4062. // let the user know we're making progress.
  4063. //
  4064. } else {
  4065. fputs( ".", stdout );
  4066. }
  4067. }
  4068. break;
  4069. case WM_DESTROY:
  4070. if (PasswordControlWindow != NULL)
  4071. {
  4072. SetWindowText(PasswordControlWindow, NULL);
  4073. DestroyWindow(PasswordControlWindow);
  4074. PasswordControlWindow = NULL;
  4075. }
  4076. if (PasswordStaticWindow != NULL)
  4077. {
  4078. DestroyWindow(PasswordStaticWindow);
  4079. PasswordStaticWindow = NULL;
  4080. }
  4081. if (ViewCertControlWindow != NULL)
  4082. {
  4083. DestroyWindow(ViewCertControlWindow);
  4084. ViewCertControlWindow = NULL;
  4085. }
  4086. if (UserNameControlWindow != NULL)
  4087. {
  4088. DestroyWindow(UserNameControlWindow);
  4089. UserNameControlWindow = NULL;
  4090. }
  4091. if (UserNameStaticWindow != NULL)
  4092. {
  4093. DestroyWindow(UserNameStaticWindow);
  4094. UserNameStaticWindow = NULL;
  4095. }
  4096. if (ScardUiHandle != NULL)
  4097. {
  4098. #ifdef SCARDREPORTS
  4099. CreduiDebugLog("CREDUI: Call to SCardUIExit\n");
  4100. #endif
  4101. SCardUIExit(ScardUiHandle);
  4102. ScardUiHandle = NULL;
  4103. }
  4104. if (UserNameCertHash != NULL)
  4105. {
  4106. delete [] UserNameCertHash;
  4107. UserNameCertHash = NULL;
  4108. }
  4109. if (CertCount > 0)
  4110. {
  4111. ASSERT(CertHashes != NULL);
  4112. delete [] CertHashes;
  4113. CertHashes = NULL;
  4114. CertCount = 0;
  4115. }
  4116. if ( InitialUserName != NULL ) {
  4117. delete InitialUserName;
  4118. InitialUserName = NULL;
  4119. }
  4120. // Only call CoUninitialize if we successfully initialized for STA:
  4121. if (IsAutoComplete)
  4122. {
  4123. CoUninitialize();
  4124. }
  4125. return 0;
  4126. case WM_NCDESTROY:
  4127. delete this;
  4128. return 0;
  4129. }
  4130. return DefWindowProc(Window, message, wParam, lParam);
  4131. }
  4132. BOOL CreduiCredentialControl::GetSmartCardInfo(
  4133. IN DWORD SmartCardIndex,
  4134. IN DWORD BufferLength,
  4135. OUT LPWSTR Buffer,
  4136. OUT BOOL *IsValid,
  4137. OUT CERT_ENUM **CertEnum OPTIONAL
  4138. )
  4139. /*++
  4140. Routine Description:
  4141. Routine to get the smart card info for a smart card in the combo box
  4142. Arguments:
  4143. SmartCardIndex - Index of the smart card relative to SmartCardBaseInComboBox
  4144. BufferLength - Specifies the length of Buffer (in characters)
  4145. Buffer - Specifies the buffer to return the text for the smart card
  4146. IsValid - Return TRUE if the smartcard is valid
  4147. Returns FALSE otherwise
  4148. CertEnum - If specified, returns the description of the cert on the smartcard
  4149. This field is should be ignore if IsValid is returns false
  4150. Return Values:
  4151. Returns TRUE if Buffer and IsValid are filled in.
  4152. --*/
  4153. {
  4154. COMBOBOXEXITEM item;
  4155. //
  4156. // Get the item from the control
  4157. //
  4158. item.iItem = SmartCardBaseInComboBox + SmartCardIndex;
  4159. item.mask = CBEIF_IMAGE | CBEIF_TEXT;
  4160. item.pszText = Buffer;
  4161. item.cchTextMax = BufferLength;
  4162. if (!SendMessage(UserNameControlWindow,
  4163. CBEM_GETITEM,
  4164. 0,
  4165. reinterpret_cast<LPARAM>(&item)))
  4166. {
  4167. return FALSE;
  4168. }
  4169. *IsValid = (item.iImage == IMAGE_SMART_CARD);
  4170. if ( CertEnum != NULL) {
  4171. if ( *IsValid ) {
  4172. *CertEnum = (CERT_ENUM *) SendMessage( UserNameControlWindow,
  4173. CB_GETITEMDATA, item.iItem, 0);
  4174. // NOTE: Consider more complete error handling here.
  4175. if ( *CertEnum == NULL) {
  4176. return FALSE;
  4177. }
  4178. }
  4179. }
  4180. return TRUE;
  4181. }
  4182. LPWSTR CreduiCredentialControl::MatchSmartCard(
  4183. IN DWORD SmartCardCount,
  4184. IN LPWSTR UserName,
  4185. OUT LPDWORD RetCertIndex,
  4186. OUT CERT_ENUM **RetCertEnum
  4187. )
  4188. /*++
  4189. Routine Description:
  4190. Returns the smart card that matches UserName.
  4191. Arguments:
  4192. SmartCardCount - specifies the number of smart cards to search
  4193. UserName - specifies the user name to match
  4194. RetCertIndex - returns an index to the found smart card.
  4195. RetCertEnum - returns the description of the cert on the smartcard
  4196. Return Values:
  4197. Returns NULL if UserName matches one of the smart cards
  4198. On failure, returns a printf-style format string describing the error
  4199. --*/
  4200. {
  4201. WCHAR SmartCardText[CREDUI_MAX_USERNAME_LENGTH + 1];
  4202. DWORD i;
  4203. BOOL SmartCardValid;
  4204. CERT_ENUM *CertEnum;
  4205. CERT_ENUM *SavedCertEnum = NULL;
  4206. DWORD SavedCertIndex = 0;
  4207. //
  4208. // Loop through the list of smart cards seeing if we see a match
  4209. //
  4210. for ( i=0; i<SmartCardCount; i++ ) {
  4211. if ( !GetSmartCardInfo( i, CREDUI_MAX_USERNAME_LENGTH, SmartCardText, &SmartCardValid, &CertEnum ) ) {
  4212. //return CreduiStrings.NoUsernameMatch;
  4213. return (LPWSTR) IDS_NO_USERNAME_MATCH;
  4214. }
  4215. if ( !SmartCardValid ) {
  4216. continue;
  4217. }
  4218. //
  4219. // If the username is marshaled,
  4220. // compare the marshaled strings.
  4221. //
  4222. if ( LocalCredIsMarshaledCredentialW( UserName ) ) {
  4223. WCHAR szTestmarshall[CREDUI_MAX_USERNAME_LENGTH+1];
  4224. // see if this is the marshalled cred
  4225. if ( CredUIMarshallNode ( CertEnum, szTestmarshall ) )
  4226. {
  4227. if ( wcscmp ( szTestmarshall, UserName) == 0 ) {
  4228. *RetCertEnum = CertEnum;
  4229. *RetCertIndex = i;
  4230. return NULL;
  4231. }
  4232. }
  4233. //
  4234. // If the username is not marshalled,
  4235. // just match a substring of the name
  4236. //
  4237. } else if ( LookForUserNameMatch ( UserName, SmartCardText ) ) {
  4238. //
  4239. // If we already found a match,
  4240. // complain about the ambiguity.
  4241. //
  4242. if ( SavedCertEnum != NULL ) {
  4243. //return CreduiStrings.ManyUsernameMatch;
  4244. return (LPWSTR) IDS_MANY_USERNAME_MATCH;
  4245. }
  4246. SavedCertEnum = CertEnum;
  4247. SavedCertIndex = i;
  4248. }
  4249. }
  4250. //
  4251. // If we didn't find a match,
  4252. // fail
  4253. //
  4254. if ( SavedCertEnum == NULL) {
  4255. //return CreduiStrings.NoUsernameMatch;
  4256. return (LPWSTR) IDS_NO_USERNAME_MATCH;
  4257. }
  4258. *RetCertEnum = SavedCertEnum;
  4259. *RetCertIndex = SavedCertIndex;
  4260. return NULL;
  4261. }
  4262. void CreduiCredentialControl::CmdlineSmartCardPrompt()
  4263. /*++
  4264. Routine Description:
  4265. Command line code to select a smartcard from the list of ones available.
  4266. Post a WM_QUIT message to terminate message processing. The status of the operation
  4267. is returned in wParam.
  4268. UserName and Password strings set in their respective controls.
  4269. Arguments:
  4270. None
  4271. Return Values:
  4272. None
  4273. --*/
  4274. {
  4275. DWORD WinStatus;
  4276. LONG ComboBoxItemCount;
  4277. DWORD SmartCardCount;
  4278. DWORD ValidSmartCardCount = 0;
  4279. DWORD InvalidSmartCardCount = 0;
  4280. DWORD KnownGoodCard = 0;
  4281. DWORD i;
  4282. DWORD_PTR rgarg[2]; // at most 2 substitution arguments
  4283. WCHAR szMsg[CREDUI_MAX_CMDLINE_MSG_LENGTH + 1];
  4284. WCHAR UserName[CREDUI_MAX_USERNAME_LENGTH + 1];
  4285. WCHAR Password[CREDUI_MAX_PASSWORD_LENGTH + 1];
  4286. WCHAR SmartCardText[CREDUI_MAX_USERNAME_LENGTH + 1];
  4287. BOOL SmartCardValid;
  4288. CERT_ENUM *SavedCertEnum = NULL;
  4289. DWORD SavedCertIndex = 0;
  4290. LPWSTR ErrorString = NULL;
  4291. //
  4292. // Compute the number of smart card entries
  4293. //
  4294. ComboBoxItemCount = (LONG) SendMessage(UserNameControlWindow, CB_GETCOUNT, 0, 0);
  4295. if ( ComboBoxItemCount == CB_ERR ||
  4296. ComboBoxItemCount <= SmartCardBaseInComboBox ) {
  4297. // Didn't find any smart card readers
  4298. szMsg[0] = 0;
  4299. FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  4300. CreduiInstance,
  4301. IDS_CHOOSE_A_CERT,
  4302. 0,
  4303. szMsg,
  4304. CREDUI_MAX_CMDLINE_MSG_LENGTH,
  4305. NULL);
  4306. CredPutStdout(szMsg);
  4307. WinStatus = ERROR_CANCELLED;
  4308. goto Cleanup;
  4309. }
  4310. SmartCardCount = ComboBoxItemCount - SmartCardBaseInComboBox;
  4311. //
  4312. // Get a count of the number of valid and invalid smartcards
  4313. //
  4314. for ( i=0; i<SmartCardCount; i++ ) {
  4315. if ( !GetSmartCardInfo( i, CREDUI_MAX_USERNAME_LENGTH, SmartCardText, &SmartCardValid, NULL ) ) {
  4316. WinStatus = ERROR_INTERNAL_ERROR;
  4317. goto Cleanup;
  4318. }
  4319. if ( SmartCardValid ) {
  4320. ValidSmartCardCount ++;
  4321. KnownGoodCard = i;
  4322. } else {
  4323. InvalidSmartCardCount ++;
  4324. }
  4325. }
  4326. //
  4327. // Get the username passed into the API
  4328. //
  4329. // Can't do a GetWindowText( UserNameControlWindow ) since the cert control has
  4330. // a non-editable window so we can't set the window text
  4331. //
  4332. if ( InitialUserName != NULL) {
  4333. lstrcpyn( UserName, InitialUserName, CREDUI_MAX_USERNAME_LENGTH );
  4334. } else {
  4335. UserName[0] = '\0';
  4336. }
  4337. //
  4338. // If the caller passed a name into the API,
  4339. // check to see if the name matches one of the smart cards.
  4340. //
  4341. if ( UserName[0] != '\0' ) {
  4342. //
  4343. // Find the smartcard that matches the username
  4344. //
  4345. ErrorString = MatchSmartCard(
  4346. SmartCardCount,
  4347. UserName,
  4348. &SavedCertIndex,
  4349. &SavedCertEnum );
  4350. if ( ErrorString == NULL ) {
  4351. WinStatus = NO_ERROR;
  4352. goto Cleanup;
  4353. }
  4354. }
  4355. //
  4356. // Report any errors to the user
  4357. //
  4358. if ( InvalidSmartCardCount ) {
  4359. szMsg[0] = 0;
  4360. FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  4361. CreduiInstance,
  4362. IDS_CMDLINE_ERRORS,
  4363. 0,
  4364. szMsg,
  4365. CREDUI_MAX_CMDLINE_MSG_LENGTH,
  4366. NULL);
  4367. CredPutStdout(szMsg);
  4368. for ( i=0; i<SmartCardCount; i++ ) {
  4369. if ( !GetSmartCardInfo( i, CREDUI_MAX_USERNAME_LENGTH, SmartCardText, &SmartCardValid, NULL ) ) {
  4370. WinStatus = ERROR_INTERNAL_ERROR;
  4371. goto Cleanup;
  4372. }
  4373. if ( !SmartCardValid ) {
  4374. // GetSmartCardInfo() fills SmartCardText, which may include user's name
  4375. CredPutStdout( SmartCardText );
  4376. //swprintf(szMsg,CreduiStrings.CmdLineError,i+1);
  4377. szMsg[0] = 0;
  4378. INT j = i+1;
  4379. FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  4380. Instance,
  4381. IDS_CMDLINE_ERROR,
  4382. 0,
  4383. szMsg,
  4384. CREDUI_MAX_CMDLINE_MSG_LENGTH,
  4385. (va_list *) &j);
  4386. CredPutStdout( szMsg);
  4387. }
  4388. }
  4389. CredPutStdout( L"\n" );
  4390. }
  4391. //
  4392. // If the caller passed a name into the API,
  4393. // simply report that we couldn't find the cert and return
  4394. //
  4395. if ( UserName[0] != '\0' ) {
  4396. // ErrorString is expected to be NoMatch or ManyMatch
  4397. //_snwprintf(szMsg,
  4398. // CREDUI_MAX_CMDLINE_MSG_LENGTH,
  4399. // ErrorString,
  4400. // UserName);
  4401. // szMsg[0] = 0;
  4402. //szMsg[CREDUI_MAX_CMDLINE_MSG_LENGTH] = L'\0';
  4403. szMsg[0] = 0;
  4404. // Note that ErrorString returned from MatchSmartCard has type LPWSTR, but it is actually
  4405. // a message ID. We take the low word of the pointer as the ID.
  4406. FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  4407. CreduiInstance,
  4408. LOWORD(ErrorString),
  4409. 0,
  4410. szMsg,
  4411. CREDUI_MAX_CMDLINE_MSG_LENGTH,
  4412. (va_list *) UserName);
  4413. CredPutStdout( szMsg );
  4414. WinStatus = ERROR_CANCELLED;
  4415. goto Cleanup;
  4416. }
  4417. //
  4418. // If there was only one smartcard and it was valid,
  4419. // use it
  4420. //
  4421. // if ( ValidSmartCardCount == 1 && InvalidSmartCardCount == 0 ) {
  4422. // gm: If list can only contain one item, use it.
  4423. if ( ValidSmartCardCount == 1 ) {
  4424. if ( !GetSmartCardInfo( KnownGoodCard, CREDUI_MAX_USERNAME_LENGTH, SmartCardText, &SmartCardValid, &SavedCertEnum ) ) {
  4425. WinStatus = ERROR_INTERNAL_ERROR;
  4426. goto Cleanup;
  4427. }
  4428. SavedCertIndex = KnownGoodCard;
  4429. WinStatus = NO_ERROR;
  4430. goto Cleanup;
  4431. //
  4432. // If there were valid smartcard,
  4433. // List the valid smartcards for the user
  4434. //
  4435. } else if ( ValidSmartCardCount ) {
  4436. //
  4437. // Tell user about all certs
  4438. //
  4439. szMsg[0] = 0;
  4440. FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  4441. CreduiInstance,
  4442. IDS_CHOOSE_A_CERT,
  4443. 0,
  4444. szMsg,
  4445. CREDUI_MAX_CMDLINE_MSG_LENGTH,
  4446. NULL);
  4447. CredPutStdout(szMsg);
  4448. for ( i=0; i<SmartCardCount; i++ ) {
  4449. if ( !GetSmartCardInfo( i, CREDUI_MAX_USERNAME_LENGTH, SmartCardText, &SmartCardValid, NULL ) ) {
  4450. WinStatus = ERROR_INTERNAL_ERROR;
  4451. goto Cleanup;
  4452. }
  4453. if ( SmartCardValid ) {
  4454. //swprintf(szMsg,CreduiStrings.CmdLinePreamble,i+1,SmartCardText);
  4455. szMsg[0] = 0;
  4456. rgarg[0] = i+1;
  4457. rgarg[1] = (DWORD_PTR) SmartCardText;
  4458. FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  4459. Instance,
  4460. IDS_CMDLINE_PREAMBLE,
  4461. 0,
  4462. szMsg,
  4463. CREDUI_MAX_CMDLINE_MSG_LENGTH,
  4464. (va_list *) &rgarg);
  4465. CredPutStdout( szMsg );
  4466. }
  4467. }
  4468. CredPutStdout( L"\n" );
  4469. //
  4470. // Ask user to enter the reader number of one of the smartcards
  4471. //
  4472. //_snwprintf(szMsg,
  4473. // CREDUI_MAX_CMDLINE_MSG_LENGTH,
  4474. // CreduiStrings.SCardPrompt,
  4475. // TargetName);
  4476. //szMsg[CREDUI_MAX_CMDLINE_MSG_LENGTH] = L'\0';
  4477. szMsg[0] = 0;
  4478. rgarg[0] = (DWORD_PTR)TargetName;
  4479. rgarg[1] = 0;
  4480. FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  4481. Instance,
  4482. IDS_SCARD_PROMPT,
  4483. 0,
  4484. szMsg,
  4485. CREDUI_MAX_CMDLINE_MSG_LENGTH,
  4486. (va_list *) rgarg);
  4487. CredPutStdout( szMsg );
  4488. CredGetStdin( UserName, CREDUI_MAX_USERNAME_LENGTH, TRUE );
  4489. if ( wcslen (UserName ) == 0 ) {
  4490. szMsg[0] = 0;
  4491. FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  4492. CreduiInstance,
  4493. IDS_NO_SCARD_ENTERED ,
  4494. 0,
  4495. szMsg,
  4496. CREDUI_MAX_CMDLINE_MSG_LENGTH,
  4497. NULL);
  4498. CredPutStdout(szMsg);
  4499. WinStatus = ERROR_CANCELLED;
  4500. goto Cleanup;
  4501. }
  4502. //
  4503. // Find the smartcard that matches the username
  4504. //
  4505. INT iWhich = 0;
  4506. WCHAR *pc = NULL;
  4507. iWhich = wcstol(UserName,&pc,10);
  4508. if (pc == UserName) {
  4509. // Invalid if at least one char was not numeric
  4510. szMsg[0] = 0;
  4511. FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  4512. CreduiInstance,
  4513. IDS_READERINVALID,
  4514. 0,
  4515. szMsg,
  4516. CREDUI_MAX_CMDLINE_MSG_LENGTH,
  4517. NULL);
  4518. CredPutStdout(szMsg);
  4519. WinStatus = ERROR_CANCELLED;
  4520. goto Cleanup;
  4521. }
  4522. // convert 1 based UI number to 0 based internal index
  4523. if (iWhich > 0) iWhich -= 1;
  4524. if ( !GetSmartCardInfo( iWhich, CREDUI_MAX_USERNAME_LENGTH, SmartCardText, &SmartCardValid, &SavedCertEnum ) ) {
  4525. // Invalid if that indexed card did not read correctly
  4526. szMsg[0] = 0;
  4527. FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  4528. CreduiInstance,
  4529. IDS_READERINVALID,
  4530. 0,
  4531. szMsg,
  4532. CREDUI_MAX_CMDLINE_MSG_LENGTH,
  4533. NULL);
  4534. CredPutStdout(szMsg);
  4535. WinStatus = ERROR_CANCELLED;
  4536. goto Cleanup;
  4537. }
  4538. // At this point, a valid number was entered, and an attempt to read the card made
  4539. // GetSmartCardInfo() returned OK, but SmartCardValid may still be false
  4540. if (!SmartCardValid)
  4541. {
  4542. szMsg[0] = 0;
  4543. FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  4544. CreduiInstance,
  4545. IDS_READERINVALID,
  4546. 0,
  4547. szMsg,
  4548. CREDUI_MAX_CMDLINE_MSG_LENGTH,
  4549. NULL);
  4550. CredPutStdout(szMsg);
  4551. WinStatus = ERROR_CANCELLED;
  4552. goto Cleanup;
  4553. }
  4554. else
  4555. {
  4556. SavedCertIndex = iWhich;
  4557. WinStatus = NO_ERROR;
  4558. goto Cleanup;
  4559. }
  4560. }
  4561. WinStatus = ERROR_CANCELLED;
  4562. //
  4563. // Complete the operation.
  4564. //
  4565. // WinStatus is the status of the operation so far
  4566. // if NO_ERROR, SavedCertEnum is the description of the cert to use, and
  4567. // SavedCertIndex is the index to the selected cert.
  4568. //
  4569. Cleanup:
  4570. if ( WinStatus == NO_ERROR) {
  4571. if ( CredUIMarshallNode ( SavedCertEnum, UserName ) ) {
  4572. //
  4573. // Save the username
  4574. //
  4575. UserNameSelection = SmartCardBaseInComboBox + SavedCertIndex;
  4576. IsChangingUserName = TRUE;
  4577. SendMessage(UserNameControlWindow,
  4578. CB_SETCURSEL,
  4579. UserNameSelection,
  4580. 0);
  4581. IsChangingUserName = FALSE;
  4582. //
  4583. // Prompt for the pin
  4584. //
  4585. //CredPutStdout( CreduiStrings.PinPrompt );
  4586. //swprintf(szMsg,CreduiStrings.CmdLineThisCard,SavedCertIndex + 1);
  4587. szMsg[0] = 0;
  4588. i = SavedCertIndex + 1;
  4589. FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  4590. Instance,
  4591. IDS_CMDLINE_THISCARD,
  4592. 0,
  4593. szMsg,
  4594. CREDUI_MAX_CMDLINE_MSG_LENGTH,
  4595. (va_list *) &i);
  4596. CredPutStdout(szMsg);
  4597. CredGetStdin( Password, CREDUI_MAX_PASSWORD_LENGTH, FALSE );
  4598. //
  4599. // Save the pin
  4600. //
  4601. if (!OnSetPassword( Password ) ) {
  4602. WinStatus = GetLastError();
  4603. CreduiDebugLog("CreduiCredentialControl::CmdlineSmartCardPrompt: "
  4604. "OnSetPassword failed: %u\n",
  4605. WinStatus );
  4606. }
  4607. //
  4608. // Prompt whether the save the cred or not
  4609. //
  4610. CmdlineSavePrompt();
  4611. } else {
  4612. WinStatus = GetLastError();
  4613. CreduiDebugLog("CreduiCredentialControl::CmdlineSmartCardPrompt: "
  4614. "CredMarshalCredential failed: %u\n",
  4615. WinStatus );
  4616. }
  4617. }
  4618. //
  4619. // Tell our parent window that we're done prompting
  4620. //
  4621. PostQuitMessage( WinStatus );
  4622. return;
  4623. }
  4624. void CreduiCredentialControl::CmdlineSavePrompt()
  4625. /*++
  4626. Routine Description:
  4627. Command line code to prompt for saving the credential
  4628. Arguments:
  4629. None
  4630. Return Values:
  4631. None
  4632. --*/
  4633. {
  4634. WCHAR szMsg[CREDUI_MAX_CMDLINE_MSG_LENGTH + 1];
  4635. WCHAR szY[CREDUI_MAX_CMDLINE_MSG_LENGTH + 1];
  4636. WCHAR szN[CREDUI_MAX_CMDLINE_MSG_LENGTH + 1];
  4637. //
  4638. // Only prompt if we've been asked to display the checkbox
  4639. //
  4640. while ( Style & CRS_SAVECHECK ) {
  4641. WCHAR szMsg[CREDUI_MAX_CMDLINE_MSG_LENGTH+1];
  4642. // Fetch the strings one by one from the messages, and cobble them together
  4643. WCHAR *rgsz[2];
  4644. szY[0] = 0;
  4645. szN[0] = 0;
  4646. rgsz[0] = szY;
  4647. rgsz[1] = szN;
  4648. szMsg[0] = 0;
  4649. // Fetch yes and no strings
  4650. FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  4651. CreduiInstance,
  4652. IDS_YES_TEXT,
  4653. 0,
  4654. szY,
  4655. CREDUI_MAX_CMDLINE_MSG_LENGTH,
  4656. NULL);
  4657. FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  4658. CreduiInstance,
  4659. IDS_NO_TEXT,
  4660. 0,
  4661. szN,
  4662. CREDUI_MAX_CMDLINE_MSG_LENGTH,
  4663. NULL);
  4664. // Arg substitute them into the prompt
  4665. FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  4666. CreduiInstance,
  4667. IDS_SAVE_PROMPT,
  4668. 0,
  4669. szMsg,
  4670. CREDUI_MAX_CMDLINE_MSG_LENGTH,
  4671. (va_list *) rgsz);
  4672. szMsg[CREDUI_MAX_CMDLINE_MSG_LENGTH] = L'\0';
  4673. CredPutStdout( szMsg );
  4674. CredGetStdin( szMsg, CREDUI_MAX_CMDLINE_MSG_LENGTH, TRUE );
  4675. // if ( toupper(szMsg[0]) == toupper(CreduiStrings.YesText[0]) ) {
  4676. if ( toupper(szMsg[0]) == toupper(szY[0]) ) {
  4677. Credential_CheckSave( Window, TRUE );
  4678. break;
  4679. // } else if ( toupper(szMsg[0]) == toupper(CreduiStrings.NoText[0]) ) {
  4680. } else if ( toupper(szMsg[0]) == toupper(szN[0]) ) {
  4681. Credential_CheckSave( Window, FALSE );
  4682. break;
  4683. }
  4684. }
  4685. }
  4686. UINT CreduiCredentialControl::MapID(UINT uiID) {
  4687. switch(uiID) {
  4688. case IDC_USERNAME:
  4689. return IDH_USERNAMEEDIT;
  4690. case IDC_PASSWORD:
  4691. return IDH_PASSWORDEDIT;
  4692. case IDC_SAVE:
  4693. return IDH_SAVECHECKBOX;
  4694. default:
  4695. return IDS_NOHELP;
  4696. }
  4697. }
  4698. BOOL
  4699. CreduiCredentialControl::OnHelpInfo(LPARAM lp) {
  4700. HELPINFO* pH;
  4701. INT iMapped;
  4702. pH = (HELPINFO *) lp;
  4703. HH_POPUP stPopUp;
  4704. RECT rcW;
  4705. UINT gID;
  4706. gID = pH->iCtrlId;
  4707. iMapped = MapID(gID);
  4708. if (iMapped == 0) return TRUE;
  4709. if (IDS_NOHELP != iMapped) {
  4710. memset(&stPopUp,0,sizeof(stPopUp));
  4711. stPopUp.cbStruct = sizeof(HH_POPUP);
  4712. stPopUp.hinst = Instance;
  4713. stPopUp.idString = iMapped;
  4714. stPopUp.pszText = NULL;
  4715. stPopUp.clrForeground = -1;
  4716. stPopUp.clrBackground = -1;
  4717. stPopUp.rcMargins.top = -1;
  4718. stPopUp.rcMargins.bottom = -1;
  4719. stPopUp.rcMargins.left = -1;
  4720. stPopUp.rcMargins.right = -1;
  4721. stPopUp.pszFont = NULL;
  4722. if (GetWindowRect((HWND)pH->hItemHandle,&rcW)) {
  4723. stPopUp.pt.x = (rcW.left + rcW.right) / 2;
  4724. stPopUp.pt.y = (rcW.top + rcW.bottom) / 2;
  4725. }
  4726. else stPopUp.pt = pH->MousePos;
  4727. HtmlHelp((HWND) pH->hItemHandle,NULL,HH_DISPLAY_TEXT_POPUP,(DWORD_PTR) &stPopUp);
  4728. }
  4729. return TRUE;
  4730. }