Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

5849 lines
168 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 (_wcsicmp(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. // Count is a object state variable pointing to the next free slot.
  715. if (Count < MaxCount)
  716. {
  717. int bufferLength = wcslen(string) + 1;
  718. Array[Count] = new WCHAR[bufferLength];
  719. if (Array[Count] != NULL)
  720. {
  721. StringCchCopyW(Array[Count++], bufferLength, string);
  722. return TRUE;
  723. }
  724. }
  725. return FALSE;
  726. }
  727. //=============================================================================
  728. // CreduiStringArray::QueryInterface (IUnknown)
  729. //
  730. // Created 02/25/2000 johnstep (John Stephens)
  731. //=============================================================================
  732. HRESULT
  733. CreduiStringArray::QueryInterface(
  734. CONST IID &interfaceId,
  735. VOID **outInterface
  736. )
  737. {
  738. if ((interfaceId == IID_IUnknown) || (interfaceId == IID_IEnumString))
  739. {
  740. *outInterface = static_cast<void *>(static_cast<IEnumString *>(this));
  741. }
  742. else
  743. {
  744. *outInterface = NULL;
  745. return E_NOINTERFACE;
  746. }
  747. static_cast<IUnknown *>(*outInterface)->AddRef();
  748. return S_OK;
  749. }
  750. //=============================================================================
  751. // CreduiStringArray::Addref (IUnknown)
  752. //
  753. // Created 02/25/2000 johnstep (John Stephens)
  754. //=============================================================================
  755. ULONG
  756. CreduiStringArray::AddRef()
  757. {
  758. return InterlockedIncrement(reinterpret_cast<LONG *>(&ReferenceCount));
  759. }
  760. //=============================================================================
  761. // CreduiStringArray::Release (IUnknown)
  762. //
  763. // Created 02/25/2000 johnstep (John Stephens)
  764. //=============================================================================
  765. ULONG
  766. CreduiStringArray::Release()
  767. {
  768. if (InterlockedDecrement(reinterpret_cast<LONG *>(&ReferenceCount)) > 0)
  769. {
  770. return ReferenceCount;
  771. }
  772. delete this;
  773. return 0;
  774. }
  775. //=============================================================================
  776. // CreduiStringArray::Next (IEnumString)
  777. //
  778. // Created 02/25/2000 johnstep (John Stephens)
  779. //=============================================================================
  780. HRESULT
  781. CreduiStringArray::Next(
  782. ULONG count,
  783. LPOLESTR *array,
  784. ULONG *countFetched
  785. )
  786. {
  787. if ((count > 1) && (countFetched == NULL))
  788. {
  789. return E_INVALIDARG;
  790. }
  791. count = min(count, Count - Index);
  792. for (UINT i = 0; i < count; ++i)
  793. {
  794. int bufferLength = wcslen(Array[Index]) + 1;
  795. array[i] = static_cast<WCHAR *>(CoTaskMemAlloc(
  796. (sizeof (WCHAR)) * bufferLength));
  797. if (array[i] != NULL)
  798. {
  799. StringCchCopyW(array[i], bufferLength, Array[Index]);
  800. }
  801. else
  802. {
  803. while (i > 0)
  804. {
  805. CoTaskMemFree(array[--i]);
  806. array[i] = NULL;
  807. }
  808. if (countFetched != NULL)
  809. {
  810. *countFetched = 0;
  811. }
  812. return E_OUTOFMEMORY;
  813. }
  814. Index++;
  815. }
  816. if (countFetched != NULL)
  817. {
  818. *countFetched = count;
  819. }
  820. return (count > 0) ? S_OK : S_FALSE;
  821. }
  822. //=============================================================================
  823. // CreduiStringArray::Skip (IEnumString)
  824. //
  825. // Created 02/25/2000 johnstep (John Stephens)
  826. //=============================================================================
  827. HRESULT
  828. CreduiStringArray::Skip(
  829. ULONG
  830. )
  831. {
  832. return E_NOTIMPL;
  833. }
  834. //=============================================================================
  835. // CreduiStringArray::Reset (IEnumString)
  836. //
  837. // Created 02/25/2000 johnstep (John Stephens)
  838. //=============================================================================
  839. HRESULT
  840. CreduiStringArray::Reset()
  841. {
  842. Index = 0;
  843. return S_OK;
  844. }
  845. //=============================================================================
  846. // CreduiStringArray::Clone (IEnumString)
  847. //
  848. // Created 02/25/2000 johnstep (John Stephens)
  849. //=============================================================================
  850. HRESULT
  851. CreduiStringArray::Clone(
  852. IEnumString **
  853. )
  854. {
  855. return E_NOTIMPL;
  856. }
  857. //-----------------------------------------------------------------------------
  858. // CreduiAutoCompleteComboBox Class Implementation
  859. //-----------------------------------------------------------------------------
  860. //=============================================================================
  861. // CreduiAutoCompleteComboBox::CreduiAutoCompleteComboBox
  862. //
  863. // Created 02/25/2000 johnstep (John Stephens)
  864. //=============================================================================
  865. CreduiAutoCompleteComboBox::CreduiAutoCompleteComboBox()
  866. {
  867. Window = NULL;
  868. ImageList = NULL;
  869. StringArray = NULL;
  870. }
  871. //=============================================================================
  872. // CreduiAutoCompleteComboBox::~CreduiAutoCompleteComboBox
  873. //
  874. // Created 02/25/2000 johnstep (John Stephens)
  875. //=============================================================================
  876. CreduiAutoCompleteComboBox::~CreduiAutoCompleteComboBox()
  877. {
  878. if (StringArray != NULL)
  879. {
  880. StringArray->Release();
  881. StringArray = NULL;
  882. }
  883. if (ImageList != NULL)
  884. {
  885. ImageList_Destroy(ImageList);
  886. ImageList = NULL;
  887. }
  888. }
  889. //=============================================================================
  890. // CreduiAutoCompleteComboBox::Init
  891. //
  892. // Initializes the shell auto complete list control for the given combo box,
  893. // and sets the auto complete string list.
  894. //
  895. // Arguments:
  896. // instance (in)
  897. // comboBoxWindow (in)
  898. // stringCount (in)
  899. // imageListResourceId (in) - optional image list for the combo box
  900. //
  901. // Returns TRUE on success or FALSE otherwise.
  902. //
  903. // Created 02/25/2000 johnstep (John Stephens)
  904. //=============================================================================
  905. BOOL
  906. CreduiAutoCompleteComboBox::Init(
  907. HMODULE instance,
  908. HWND comboBoxWindow,
  909. UINT stringCount,
  910. INT imageListResourceId,
  911. INT initialImage
  912. )
  913. {
  914. Window = comboBoxWindow;
  915. if (imageListResourceId != 0)
  916. {
  917. ImageList = ImageList_LoadImage(
  918. instance,
  919. MAKEINTRESOURCE(imageListResourceId),
  920. 0, 16, RGB(0, 128, 128), IMAGE_BITMAP,
  921. LR_DEFAULTSIZE | LR_SHARED);
  922. if (ImageList != NULL)
  923. {
  924. SendMessage(Window,
  925. CBEM_SETIMAGELIST,
  926. 0, reinterpret_cast<LPARAM>(ImageList));
  927. }
  928. else
  929. {
  930. return FALSE;
  931. }
  932. }
  933. BOOL success = FALSE;
  934. if (stringCount > 0)
  935. {
  936. HRESULT result =
  937. CoCreateInstance(CreduiStringArrayClassId,
  938. NULL,
  939. CLSCTX_INPROC_SERVER,
  940. IID_IEnumString,
  941. reinterpret_cast<VOID **>(&StringArray));
  942. if (SUCCEEDED(result))
  943. {
  944. if (StringArray->Init(stringCount))
  945. {
  946. success = TRUE;
  947. }
  948. else
  949. {
  950. StringArray->Release();
  951. StringArray = NULL;
  952. }
  953. }
  954. }
  955. else
  956. {
  957. success = TRUE;
  958. }
  959. if (success == TRUE)
  960. {
  961. COMBOBOXEXITEMW item;
  962. item.mask = CBEIF_IMAGE | CBEIF_SELECTEDIMAGE;
  963. item.iItem = -1;
  964. item.iImage = initialImage;
  965. item.iSelectedImage = initialImage;
  966. SendMessage(Window, CBEM_SETITEM, 0,
  967. reinterpret_cast<LPARAM>(&item));
  968. return TRUE;
  969. }
  970. if (ImageList != NULL)
  971. {
  972. ImageList_Destroy(ImageList);
  973. ImageList = NULL;
  974. }
  975. return FALSE;
  976. }
  977. //=============================================================================
  978. // CreduiAutoCompleteComboBox::Add
  979. //
  980. // Returns the index of the new item or -1 on failure.
  981. //
  982. // Created 02/25/2000 johnstep (John Stephens)
  983. //=============================================================================
  984. INT
  985. CreduiAutoCompleteComboBox::Add(
  986. WCHAR *string,
  987. INT image,
  988. BOOL autoComplete,
  989. BOOL addUnique,
  990. INT indexBefore,
  991. INT indent
  992. )
  993. {
  994. INT index = -1;
  995. if (addUnique)
  996. {
  997. index = (INT) SendMessage(Window, CB_FINDSTRINGEXACT, 0,
  998. reinterpret_cast<LPARAM>(string));
  999. }
  1000. if (index == -1)
  1001. {
  1002. if (!autoComplete || StringArray->Add(string))
  1003. {
  1004. COMBOBOXEXITEMW item;
  1005. item.mask = CBEIF_TEXT | CBEIF_INDENT;
  1006. item.iItem = indexBefore;
  1007. item.pszText = string;
  1008. item.iIndent = indent;
  1009. if (ImageList != NULL)
  1010. {
  1011. item.mask |= CBEIF_IMAGE | CBEIF_SELECTEDIMAGE;
  1012. item.iImage = image;
  1013. item.iSelectedImage = image;
  1014. }
  1015. index = (INT) SendMessage(Window, CBEM_INSERTITEM, 0,
  1016. reinterpret_cast<LPARAM>(&item));
  1017. }
  1018. }
  1019. return index;
  1020. }
  1021. //=============================================================================
  1022. // CreduiAutoCompleteComboBox::Update
  1023. //
  1024. // Updates an existing item. This does not update the associated string for
  1025. // auto complete items.
  1026. //
  1027. // Created 04/15/2000 johnstep (John Stephens)
  1028. //=============================================================================
  1029. BOOL
  1030. CreduiAutoCompleteComboBox::Update(
  1031. INT index,
  1032. WCHAR *string,
  1033. INT image
  1034. )
  1035. {
  1036. COMBOBOXEXITEMW item;
  1037. item.iItem = index;
  1038. // Use CBEM_SETITEM in these cases:
  1039. //
  1040. // 1. We're updating the default (-1) item.
  1041. // 2. The dropdown is closed.
  1042. //
  1043. // For other cases, we delete and recreate the item for the desired
  1044. // result.
  1045. BOOL isDropped = (BOOL) SendMessage(Window, CB_GETDROPPEDSTATE, 0, 0);
  1046. if ((index == -1) || !isDropped)
  1047. {
  1048. item.mask = CBEIF_TEXT;
  1049. item.pszText = string;
  1050. if (ImageList != NULL)
  1051. {
  1052. item.mask |= CBEIF_IMAGE | CBEIF_SELECTEDIMAGE;
  1053. item.iImage = image;
  1054. item.iSelectedImage = image;
  1055. }
  1056. if (SendMessage(Window, CBEM_SETITEM, 0,
  1057. reinterpret_cast<LPARAM>(&item)) != 0)
  1058. {
  1059. RECT rect;
  1060. GetClientRect(Window, &rect);
  1061. InvalidateRect(Window, &rect, FALSE);
  1062. return TRUE;
  1063. }
  1064. }
  1065. else
  1066. {
  1067. item.mask = CBEIF_IMAGE | CBEIF_INDENT | CBEIF_SELECTEDIMAGE;
  1068. if (SendMessage(Window, CBEM_GETITEM,
  1069. 0, reinterpret_cast<LPARAM>(&item)))
  1070. {
  1071. item.mask |= CBEIF_TEXT;
  1072. item.pszText = string;
  1073. LPARAM data = SendMessage(Window, CB_GETITEMDATA, index, 0);
  1074. if (ImageList != NULL)
  1075. {
  1076. item.mask |= CBEIF_IMAGE | CBEIF_SELECTEDIMAGE;
  1077. item.iImage = image;
  1078. item.iSelectedImage = image;
  1079. }
  1080. SendMessage(Window, CBEM_DELETEITEM, index, 0);
  1081. index = (INT) SendMessage(Window, CBEM_INSERTITEM, 0,
  1082. reinterpret_cast<LPARAM>(&item));
  1083. if (index != -1)
  1084. {
  1085. SendMessage(Window, CB_SETITEMDATA, index, data);
  1086. INT current = (INT) SendMessage(Window, CB_GETCURSEL, 0, 0);
  1087. if (current == index)
  1088. {
  1089. SendMessage(Window, CB_SETCURSEL, current, 0);
  1090. }
  1091. return TRUE;
  1092. }
  1093. }
  1094. }
  1095. return FALSE;
  1096. }
  1097. //=============================================================================
  1098. // CreduiAutoCompleteComboBox::Enable
  1099. //
  1100. // Created 02/27/2000 johnstep (John Stephens)
  1101. //=============================================================================
  1102. BOOL
  1103. CreduiAutoCompleteComboBox::Enable()
  1104. {
  1105. BOOL success = TRUE;
  1106. if (StringArray != NULL)
  1107. {
  1108. success = FALSE;
  1109. IAutoComplete2 *autoCompleteInterface;
  1110. HRESULT result =
  1111. CoCreateInstance(
  1112. CLSID_AutoComplete,
  1113. NULL,
  1114. CLSCTX_INPROC_SERVER,
  1115. IID_IAutoComplete2,
  1116. reinterpret_cast<void **>(&autoCompleteInterface));
  1117. if (SUCCEEDED(result))
  1118. {
  1119. result = autoCompleteInterface->Init((HWND)
  1120. SendMessage(Window, CBEM_GETEDITCONTROL, 0, 0),
  1121. StringArray, NULL, NULL);
  1122. if (SUCCEEDED(result))
  1123. {
  1124. result = autoCompleteInterface->SetOptions(ACO_AUTOSUGGEST);
  1125. if (SUCCEEDED(result))
  1126. {
  1127. success = TRUE;
  1128. }
  1129. else
  1130. {
  1131. CreduiDebugLog("CreduiAutoCompleteComboBox::Enable: "
  1132. "SetOptions failed: 0x%08X\n", result);
  1133. }
  1134. }
  1135. autoCompleteInterface->Release();
  1136. autoCompleteInterface = NULL;
  1137. }
  1138. else
  1139. {
  1140. CreduiDebugLog(
  1141. "CreduiAutoCompleteComboBox::Enable: "
  1142. "CoCreateInstance CLSID_AutoComplete failed: 0x%08X\n",
  1143. result);
  1144. }
  1145. StringArray->Release();
  1146. StringArray = NULL;
  1147. }
  1148. return success;
  1149. }
  1150. //-----------------------------------------------------------------------------
  1151. // CreduiIconParentWindow Class Implementation
  1152. //-----------------------------------------------------------------------------
  1153. CONST WCHAR *CreduiIconParentWindow::ClassName = L"CreduiIconParentWindow";
  1154. HINSTANCE CreduiIconParentWindow::Instance = NULL;
  1155. LONG CreduiIconParentWindow::Registered = FALSE;
  1156. //=============================================================================
  1157. // CreduiIconParentWindow::CreduiIconParentWindow
  1158. //
  1159. // Created 02/29/2000 johnstep (John Stephens)
  1160. //=============================================================================
  1161. CreduiIconParentWindow::CreduiIconParentWindow()
  1162. {
  1163. Window = NULL;
  1164. }
  1165. //=============================================================================
  1166. // CreduiIconParentWindow::~CreduiIconParentWindow
  1167. //
  1168. // Created 02/29/2000 johnstep (John Stephens)
  1169. //=============================================================================
  1170. CreduiIconParentWindow::~CreduiIconParentWindow()
  1171. {
  1172. if (Window != NULL)
  1173. {
  1174. DestroyWindow(Window);
  1175. Window = NULL;
  1176. }
  1177. }
  1178. //=============================================================================
  1179. // CreduiIconParentWindow::Register
  1180. //
  1181. // Set the instance to allow registration, which will be deferred until a
  1182. // window needs to be created.
  1183. //
  1184. // Arguments:
  1185. // instance (in)
  1186. //
  1187. // Returns TRUE on success or FALSE otherwise.
  1188. //
  1189. // Created 04/16/2000 johnstep (John Stephens)
  1190. //=============================================================================
  1191. BOOL
  1192. CreduiIconParentWindow::Register(
  1193. HINSTANCE instance
  1194. )
  1195. {
  1196. Instance = instance;
  1197. return TRUE;
  1198. }
  1199. //=============================================================================
  1200. // CreduiIconParentWindow::Unegister
  1201. //
  1202. // Unregisters the window class, if registered.
  1203. //
  1204. // Returns TRUE on success or FALSE otherwise.
  1205. //
  1206. // Created 04/16/2000 johnstep (John Stephens)
  1207. //=============================================================================
  1208. BOOL CreduiIconParentWindow::Unregister()
  1209. {
  1210. if (InterlockedCompareExchange(&Registered, FALSE, TRUE))
  1211. {
  1212. return UnregisterClass(ClassName, Instance);
  1213. }
  1214. return TRUE;
  1215. }
  1216. //=============================================================================
  1217. // CreduiIconParentWindow::Init
  1218. //
  1219. // Registers the window class, if not already registered, and creates the
  1220. // window.
  1221. //
  1222. // Arguments:
  1223. // instance (in) - module to load the icon from
  1224. // iconResourceId (in)
  1225. //
  1226. // Returns TRUE on success or FALSE otherwise.
  1227. //
  1228. // Created 02/29/2000 johnstep (John Stephens)
  1229. //=============================================================================
  1230. BOOL
  1231. CreduiIconParentWindow::Init(
  1232. HINSTANCE instance,
  1233. UINT iconResourceId
  1234. )
  1235. {
  1236. WNDCLASS windowClass;
  1237. ZeroMemory(&windowClass, sizeof windowClass);
  1238. if (!InterlockedCompareExchange(&Registered, TRUE, FALSE))
  1239. {
  1240. windowClass.lpfnWndProc = DefWindowProc;
  1241. windowClass.hInstance = Instance;
  1242. windowClass.hIcon =
  1243. LoadIcon(instance, MAKEINTRESOURCE(iconResourceId));
  1244. windowClass.hCursor = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));
  1245. windowClass.lpszClassName = ClassName;
  1246. InterlockedExchange(&Registered, RegisterClass(&windowClass) != 0);
  1247. if (!InterlockedCompareExchange(&Registered, FALSE, FALSE))
  1248. {
  1249. return FALSE;
  1250. }
  1251. }
  1252. Window = CreateWindow(
  1253. L"CreduiIconParentWindow",
  1254. NULL,
  1255. WS_CAPTION | WS_SYSMENU,
  1256. 0, 0, 0, 0,
  1257. NULL, NULL, instance, NULL);
  1258. return (Window != NULL);
  1259. }
  1260. //-----------------------------------------------------------------------------
  1261. // CreduiCredentialControl Class Implementation
  1262. //-----------------------------------------------------------------------------
  1263. CONST WCHAR *CreduiCredentialControl::ClassName = WC_CREDENTIAL;
  1264. HINSTANCE CreduiCredentialControl::Instance = NULL;
  1265. LONG CreduiCredentialControl::Registered = FALSE;
  1266. //=============================================================================
  1267. // CreduiCredentialControl::CreduiCredentialControl
  1268. //
  1269. // Created 06/20/2000 johnstep (John Stephens)
  1270. //=============================================================================
  1271. CreduiCredentialControl::CreduiCredentialControl()
  1272. {
  1273. IsInitialized = FALSE;
  1274. DisabledControlMask = 0;
  1275. Window = NULL;
  1276. Style = 0;
  1277. UserNameStaticWindow = NULL;
  1278. UserNameControlWindow = NULL;
  1279. ViewCertControlWindow = NULL;
  1280. PasswordStaticWindow = NULL;
  1281. PasswordControlWindow = NULL;
  1282. FirstPaint = FALSE;
  1283. ShowBalloonTip = FALSE;
  1284. IsAutoComplete = FALSE;
  1285. NoEditUserName = FALSE;
  1286. KeepUserName = FALSE;
  1287. IsPassport = FALSE;
  1288. CertHashes = NULL;
  1289. CertCount = 0;
  1290. CertBaseInComboBox = 0;
  1291. UserNameCertHash = NULL;
  1292. SmartCardBaseInComboBox = 0;
  1293. SmartCardReadCount = 0;
  1294. IsChangingUserName = FALSE;
  1295. IsChangingPassword = FALSE;
  1296. UserNameSelection = 0;
  1297. ScardUiHandle = NULL;
  1298. DoingCommandLine = FALSE;
  1299. TargetName = NULL;
  1300. InitialUserName = NULL;
  1301. }
  1302. //=============================================================================
  1303. // CreduiCredentialControl::~CreduiCredentialControl
  1304. //
  1305. // Created 06/20/2000 johnstep (John Stephens)
  1306. //=============================================================================
  1307. CreduiCredentialControl::~CreduiCredentialControl()
  1308. {
  1309. }
  1310. //=============================================================================
  1311. // CreduiCredentialControl::Register
  1312. //
  1313. // Arguments:
  1314. // instance (in)
  1315. //
  1316. // Returns TRUE on success or FALSE otherwise.
  1317. //
  1318. // Created 06/20/2000 johnstep (John Stephens)
  1319. //=============================================================================
  1320. BOOL
  1321. CreduiCredentialControl::Register(
  1322. HINSTANCE instance
  1323. )
  1324. {
  1325. Instance = instance;
  1326. WNDCLASS windowClass;
  1327. ZeroMemory(&windowClass, sizeof windowClass);
  1328. if (!InterlockedCompareExchange(&Registered, TRUE, FALSE))
  1329. {
  1330. windowClass.style = CS_GLOBALCLASS;
  1331. windowClass.lpfnWndProc = MessageHandlerCallback;
  1332. windowClass.cbWndExtra = sizeof (CreduiCredentialControl *);
  1333. windowClass.hInstance = Instance;
  1334. windowClass.hIcon = NULL;
  1335. windowClass.hCursor = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));
  1336. windowClass.lpszClassName = ClassName;
  1337. InterlockedExchange(&Registered, RegisterClass(&windowClass) != 0);
  1338. if (!InterlockedCompareExchange(&Registered, FALSE, FALSE))
  1339. {
  1340. return FALSE;
  1341. }
  1342. }
  1343. return TRUE;
  1344. }
  1345. //=============================================================================
  1346. // CreduiCredentialControl::Unegister
  1347. //
  1348. // Unregisters the window class, if registered.
  1349. //
  1350. // Returns TRUE on success or FALSE otherwise.
  1351. //
  1352. // Created 06/20/2000 johnstep (John Stephens)
  1353. //=============================================================================
  1354. BOOL CreduiCredentialControl::Unregister()
  1355. {
  1356. if (InterlockedCompareExchange(&Registered, FALSE, TRUE))
  1357. {
  1358. return UnregisterClass(ClassName, Instance);
  1359. }
  1360. return TRUE;
  1361. }
  1362. //=============================================================================
  1363. // CreduiCredentialControl::ViewCertificate
  1364. //
  1365. // Views the certificate at index in our combo box.
  1366. //
  1367. // Arguments:
  1368. // index (in) - index in the user name combo box
  1369. //
  1370. // Returns TRUE if the certificate was viewed, otherwise FALSE.
  1371. //
  1372. // Created 03/27/2000 johnstep (John Stephens)
  1373. //=============================================================================
  1374. BOOL
  1375. CreduiCredentialControl::ViewCertificate(
  1376. INT index
  1377. )
  1378. {
  1379. BOOL success = FALSE;
  1380. if (index < CertBaseInComboBox)
  1381. {
  1382. return FALSE;
  1383. }
  1384. CONST CERT_CONTEXT *certContext = NULL;
  1385. HCERTSTORE certStore = NULL;
  1386. // If this is not a smart card, open the MY store and find the certificate
  1387. // from the hash. Otherwise, just grab the certificate context from the
  1388. // CERT_ENUM structure:
  1389. if ((SmartCardBaseInComboBox > 0) &&
  1390. (index >= SmartCardBaseInComboBox))
  1391. {
  1392. CERT_ENUM *certEnum =
  1393. reinterpret_cast<CERT_ENUM *>(
  1394. SendMessage(UserNameControlWindow,
  1395. CB_GETITEMDATA, index, 0));
  1396. if (certEnum != NULL)
  1397. {
  1398. certContext = certEnum->pCertContext;
  1399. }
  1400. }
  1401. else
  1402. {
  1403. certStore = CertOpenSystemStore(NULL, L"MY");
  1404. if (certStore != NULL)
  1405. {
  1406. CRYPT_HASH_BLOB hashBlob;
  1407. hashBlob.cbData = CERT_HASH_LENGTH;
  1408. hashBlob.pbData = reinterpret_cast<BYTE *>(
  1409. CertHashes[index - CertBaseInComboBox]);
  1410. certContext = CertFindCertificateInStore(
  1411. certStore,
  1412. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  1413. 0,
  1414. CERT_FIND_SHA1_HASH,
  1415. &hashBlob,
  1416. NULL);
  1417. }
  1418. }
  1419. // If we found a certificate context, view the certificate:
  1420. if (certContext != NULL)
  1421. {
  1422. // Now, show the certificate with the common UI:
  1423. CRYPTUI_VIEWCERTIFICATE_STRUCT certViewInfo;
  1424. ZeroMemory(&certViewInfo, sizeof certViewInfo);
  1425. certViewInfo.dwSize = sizeof certViewInfo;
  1426. certViewInfo.hwndParent = Window;
  1427. certViewInfo.pCertContext = certContext;
  1428. BOOL changed;
  1429. changed = FALSE;
  1430. CryptUIDlgViewCertificate(&certViewInfo, &changed);
  1431. // Get the name again, in case it changed. However, skip this if this
  1432. // is a card reader, and is now invalid:
  1433. COMBOBOXEXITEMW item;
  1434. BOOL updateName = TRUE;
  1435. if (index >= SmartCardBaseInComboBox)
  1436. {
  1437. item.mask = CBEIF_IMAGE;
  1438. item.iItem = index;
  1439. if (!SendMessage(UserNameControlWindow,
  1440. CBEM_GETITEM,
  1441. 0,
  1442. reinterpret_cast<LPARAM>(&item)) ||
  1443. (item.iImage == IMAGE_SMART_CARD_MISSING))
  1444. {
  1445. updateName = FALSE;
  1446. }
  1447. }
  1448. if (updateName)
  1449. {
  1450. WCHAR displayName[CREDUI_MAX_CERT_NAME_LENGTH];
  1451. CreduiGetCertificateDisplayName(
  1452. certContext,
  1453. displayName,
  1454. RTL_NUMBER_OF(displayName),
  1455. CreduiStrings.Certificate,
  1456. CERT_NAME_FRIENDLY_DISPLAY_TYPE);
  1457. item.mask = CBEIF_TEXT;
  1458. item.iItem = index;
  1459. item.pszText = displayName;
  1460. SendMessage(UserNameControlWindow,
  1461. CBEM_SETITEM,
  1462. 0,
  1463. reinterpret_cast<LPARAM>(&item));
  1464. }
  1465. success = TRUE;
  1466. }
  1467. // If we opened a store, free the certificate and close the store:
  1468. if (certStore != NULL)
  1469. {
  1470. if (certContext != NULL)
  1471. {
  1472. CertFreeCertificateContext(certContext);
  1473. }
  1474. if (!CertCloseStore(certStore, 0))
  1475. {
  1476. CreduiDebugLog("CreduiCredentialControl::ViewCertificate: "
  1477. "CertCloseStore failed: %u\n", GetLastError());
  1478. }
  1479. }
  1480. return success;
  1481. }
  1482. //=============================================================================
  1483. // CreduiCredentialControl::AddCertificates
  1484. //
  1485. // Adds interesting certificates to the combo box, and allocates an array of
  1486. // hashes to match. The hash is all we need to store the credential, and can
  1487. // be used to get a CERT_CONTEXT later to view the certificate.
  1488. //
  1489. // Assume CertCount is 0 upon entry.
  1490. //
  1491. // Stack space is used for temporary storage of hashes, since each hash is
  1492. // only 160 bits. We use a linked list structure, so including the next
  1493. // pointer and worst case alignment (8-byte) on 64-bit, the maximum structure
  1494. // size is 32 bytes. We don't want to consume too much stack space, so limit
  1495. // the number of entries to 256, which will consume up to 8 KB of stack space.
  1496. //
  1497. // Returns TRUE if at least one interesting certificate exists, and all were
  1498. // added to the combo box without error. Otherwise, returns FALSE.
  1499. //
  1500. // Created 03/25/2000 johnstep (John Stephens)
  1501. //=============================================================================
  1502. BOOL
  1503. CreduiCredentialControl::AddCertificates()
  1504. {
  1505. BOOL success = FALSE;
  1506. ASSERT(CertCount == 0);
  1507. HCERTSTORE certStore = CertOpenSystemStore(NULL, L"MY");
  1508. if (certStore != NULL)
  1509. {
  1510. struct HASH_ENTRY
  1511. {
  1512. UCHAR Hash[CERT_HASH_LENGTH];
  1513. HASH_ENTRY *Next;
  1514. };
  1515. HASH_ENTRY *hashList = NULL;
  1516. HASH_ENTRY *current = NULL;
  1517. HASH_ENTRY *next = NULL;
  1518. CONST CERT_CONTEXT *certContext = NULL;
  1519. // NOTE: Currently, add all client authentication certificates. This
  1520. // should be revisited.
  1521. CHAR *ekUsageIdentifiers[] = {
  1522. szOID_PKIX_KP_CLIENT_AUTH,
  1523. szOID_KP_SMARTCARD_LOGON
  1524. };
  1525. CERT_ENHKEY_USAGE ekUsage = { 2, ekUsageIdentifiers };
  1526. // We allow a maximum of 256 certificates to be added. This is a
  1527. // reasonable limit, given the current user interface. If this is an
  1528. // unreasonable limit for the personal certificate store, then this
  1529. // can always be changed.
  1530. while (CertCount < 256)
  1531. {
  1532. certContext =
  1533. CertFindCertificateInStore(
  1534. certStore,
  1535. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  1536. CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG,
  1537. CERT_FIND_ENHKEY_USAGE,
  1538. static_cast<VOID *>(&ekUsage),
  1539. certContext);
  1540. if (certContext != NULL)
  1541. {
  1542. DWORD length = CERT_HASH_LENGTH;
  1543. // Only allocate a new entry if necessary. Something may have
  1544. // failed from the previous loop iteration, so we can just
  1545. // reuse the entry allocated then:
  1546. if (next == NULL)
  1547. {
  1548. // Wrap the alloca in an exception handler because it will
  1549. // throw a stack overflow exception on failure. Of course,
  1550. // of we're out of stack space, we may not even be able to
  1551. // clean up properly without throwing an exception.
  1552. __try
  1553. {
  1554. // known use of alloca() in a loop - small struct, 24 bytes on i386
  1555. // normally small number, constrained number (limit 256)
  1556. // protected by try/except
  1557. next = static_cast<HASH_ENTRY *>(
  1558. alloca(sizeof HASH_ENTRY));
  1559. }
  1560. __except(
  1561. (GetExceptionCode() == EXCEPTION_STACK_OVERFLOW) ?
  1562. EXCEPTION_EXECUTE_HANDLER :
  1563. EXCEPTION_CONTINUE_SEARCH)
  1564. {
  1565. _resetstkoflw();
  1566. next = NULL;
  1567. }
  1568. // If this fails, for whatever reason, break out of the
  1569. // loop:
  1570. if (next == NULL)
  1571. {
  1572. CertFreeCertificateContext(certContext);
  1573. break;
  1574. }
  1575. next->Next = NULL;
  1576. }
  1577. if (!CertGetCertificateContextProperty(
  1578. certContext,
  1579. CERT_SHA1_HASH_PROP_ID,
  1580. static_cast<VOID *>(&next->Hash),
  1581. &length))
  1582. {
  1583. // If we failed to get the hash for this certificate, just
  1584. // ignore it and continue with the next. The memory we
  1585. // allocation for this entry will be used on the next
  1586. // iteration if we do not set it to NULL.
  1587. continue;
  1588. }
  1589. if (CreduiIsRemovableCertificate(certContext))
  1590. {
  1591. // If this certificate requires a removable component,
  1592. // such as a smart card, then skip it. We will enumerate
  1593. // these later.
  1594. continue;
  1595. }
  1596. WCHAR displayName[CREDUI_MAX_CERT_NAME_LENGTH];
  1597. CreduiGetCertificateDisplayName(
  1598. certContext,
  1599. displayName,
  1600. RTL_NUMBER_OF(displayName),
  1601. CreduiStrings.Certificate,
  1602. CERT_NAME_FRIENDLY_DISPLAY_TYPE);
  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 (_wcsicmp(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 (_wcsicmp(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. 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. // disable the view cert button - will enable on cert found msg
  1861. EnableWindow(ViewCertControlWindow, FALSE);
  1862. DisabledControlMask |= DISABLED_CONTROL_VIEW;
  1863. // change password prompt to PIN:
  1864. SetWindowText(
  1865. PasswordStaticWindow,
  1866. CreduiStrings.PinStatic);
  1867. // Clean password control
  1868. IsChangingPassword = TRUE;
  1869. SetWindowText(PasswordControlWindow, NULL);
  1870. IsChangingPassword = FALSE;
  1871. // enable the password control
  1872. EnableWindow(PasswordControlWindow, TRUE);
  1873. EnableWindow(PasswordStaticWindow, TRUE);
  1874. DisabledControlMask &= ~DISABLED_CONTROL_PASSWORD;
  1875. // Change Username prompt to Smartcard:
  1876. SetWindowText(
  1877. UserNameStaticWindow,
  1878. CreduiStrings.SmartCardStatic);
  1879. #if 0
  1880. // disable save if present.
  1881. if (SaveControlWindow != NULL)
  1882. {
  1883. EnableWindow(SaveControlWindow, FALSE);
  1884. DisabledControlMask |= DISABLED_CONTROL_SAVE;
  1885. }
  1886. #endif
  1887. IsChangingUserName = TRUE;
  1888. UserNameComboBox.Update(
  1889. -1,
  1890. DoingCommandLine ?
  1891. CreduiStrings.NoCard :
  1892. CreduiStrings.EmptyReader,
  1893. IMAGE_SMART_CARD_MISSING);
  1894. IsChangingUserName = FALSE;
  1895. }
  1896. }
  1897. else
  1898. {
  1899. CreduiDebugLog(
  1900. "CreduiCredentialControl::HandleSmartCardMessages: "
  1901. "Failed to add smart card\n");
  1902. }
  1903. }
  1904. else
  1905. {
  1906. CreduiDebugLog(
  1907. "CreduiCredentialControl::HandleSmartCardMessages: "
  1908. "Reader arrived more than once");
  1909. }
  1910. }
  1911. else if (message == CreduiScarduiWmReaderRemoval)
  1912. {
  1913. #ifdef SCARDREPORTS
  1914. CreduiDebugLog("CREDUI: Reader removal event for %0x\n",this->Window);
  1915. #endif
  1916. if (index != -1)
  1917. {
  1918. RemoveSmartCardFromComboBox(certEnum, TRUE);
  1919. }
  1920. else
  1921. {
  1922. CreduiDebugLog(
  1923. "CreduiCredentialControl::HandleSmartCardMessages: "
  1924. "Reader removed more than once");
  1925. }
  1926. }
  1927. else if (message == CreduiScarduiWmCardInsertion)
  1928. {
  1929. #ifdef SCARDREPORTS
  1930. CreduiDebugLog("CREDUI: card insertion event for %0x\n",this->Window);
  1931. #endif
  1932. if (index != -1)
  1933. {
  1934. //
  1935. // Reset command line Hearbeat timer.
  1936. //
  1937. Heartbeats = 0;
  1938. SmartCardReadCount++;
  1939. if (UserNameCertHash != NULL)
  1940. {
  1941. IsChangingUserName = TRUE;
  1942. UserNameComboBox.Update(
  1943. -1,
  1944. CreduiStrings.ReadingCard,
  1945. IMAGE_SMART_CARD_MISSING);
  1946. IsChangingUserName = FALSE;
  1947. }
  1948. IsChangingUserName = TRUE;
  1949. UserNameComboBox.Update(index,
  1950. CreduiStrings.ReadingCard,
  1951. IMAGE_SMART_CARD_MISSING);
  1952. IsChangingUserName = FALSE;
  1953. }
  1954. else
  1955. {
  1956. CreduiDebugLog(
  1957. "CreduiCredentialControl::HandleSmartCardMessages: "
  1958. "Card insertion to absent reader\n");
  1959. }
  1960. }
  1961. else if (message == CreduiScarduiWmCardRemoval)
  1962. {
  1963. #ifdef SCARDREPORTS
  1964. CreduiDebugLog("CREDUI: card removal event for %0x\n",this->Window);
  1965. #endif
  1966. if (index != -1)
  1967. {
  1968. if (BalloonTip.GetInfo() == &CreduiBackwardsTipInfo)
  1969. {
  1970. BalloonTip.Hide();
  1971. }
  1972. IsChangingUserName = TRUE;
  1973. UserNameComboBox.Update(index,
  1974. DoingCommandLine ?
  1975. CreduiStrings.NoCard :
  1976. CreduiStrings.EmptyReader,
  1977. IMAGE_SMART_CARD_MISSING);
  1978. IsChangingUserName = FALSE;
  1979. // Clean password control
  1980. IsChangingPassword = TRUE;
  1981. SetWindowText(PasswordControlWindow, NULL);
  1982. IsChangingPassword = FALSE;
  1983. RemoveSmartCardFromComboBox(certEnum, FALSE);
  1984. }
  1985. else
  1986. {
  1987. CreduiDebugLog(
  1988. "CreduiCredentialControl::HandleSmartCardMessages: "
  1989. "Card removal from absent reader\n");
  1990. }
  1991. }
  1992. else if (message == CreduiScarduiWmCardCertAvail)
  1993. {
  1994. #ifdef SCARDREPORTS
  1995. CreduiDebugLog("CREDUI: cert available event for %0x\n",this->Window);
  1996. #endif
  1997. // scard system still producing activity. Extend timeout.
  1998. Heartbeats = 0;
  1999. if (index != -1)
  2000. {
  2001. // Filter certificates which are not for client authentication:
  2002. if (!CreduiIsClientAuthCertificate(certEnum->pCertContext))
  2003. {
  2004. return TRUE;
  2005. }
  2006. UINT image = IMAGE_SMART_CARD_MISSING;
  2007. COMBOBOXEXITEM item;
  2008. item.mask = CBEIF_IMAGE;
  2009. item.iItem = index;
  2010. SendMessage(UserNameControlWindow, CBEM_GETITEM,
  2011. 0, reinterpret_cast<LPARAM>(&item));
  2012. //
  2013. // For command line,
  2014. // get the UPN display name since the user is expected to type it.
  2015. // For GUI,
  2016. // get the friendly display name since it is "friendly".
  2017. //
  2018. CreduiGetCertificateDisplayName(
  2019. certEnum->pCertContext,
  2020. string,
  2021. CREDUI_MAX_CERT_NAME_LENGTH,
  2022. CreduiStrings.Certificate,
  2023. DoingCommandLine ?
  2024. CERT_NAME_UPN_TYPE :
  2025. CERT_NAME_FRIENDLY_DISPLAY_TYPE);
  2026. displayString = string;
  2027. //
  2028. // Trim trailing spaces and -'s so it doesn't look cheesy
  2029. //
  2030. if ( DoingCommandLine ) {
  2031. DWORD StringLength = wcslen(string);
  2032. while ( StringLength > 0 ) {
  2033. if ( string[StringLength-1] == ' ' || string[StringLength-1] == '-' ) {
  2034. string[StringLength-1] = '\0';
  2035. StringLength--;
  2036. } else {
  2037. break;
  2038. }
  2039. }
  2040. }
  2041. #ifdef SCARDREPORTS
  2042. CreduiDebugLog("CREDUI: cert name '%ws' %0x\n", string, this->Window);
  2043. #endif
  2044. if (SendMessage(UserNameControlWindow,
  2045. CB_GETCURSEL,
  2046. 0,
  2047. 0) == index)
  2048. {
  2049. // Enable the view cert button, previously disabled on reader arrival
  2050. EnableWindow(ViewCertControlWindow, TRUE);
  2051. DisabledControlMask &= ~DISABLED_CONTROL_VIEW;
  2052. }
  2053. image =
  2054. CreduiIsExpiredCertificate(certEnum->pCertContext) ?
  2055. IMAGE_SMART_CARD_EXPIRED :
  2056. IMAGE_SMART_CARD;
  2057. INT newIndex = index;
  2058. if (item.iImage != IMAGE_SMART_CARD_MISSING)
  2059. {
  2060. newIndex = UserNameComboBox.Add(displayString,
  2061. image,
  2062. FALSE,
  2063. FALSE,
  2064. index + 1,
  2065. 1);
  2066. if (newIndex != -1)
  2067. {
  2068. SendMessage(UserNameControlWindow,
  2069. CB_SETITEMDATA,
  2070. newIndex,
  2071. reinterpret_cast<LPARAM>(certEnum));
  2072. }
  2073. else
  2074. {
  2075. newIndex = index;
  2076. }
  2077. }
  2078. if (newIndex == index)
  2079. {
  2080. IsChangingUserName = TRUE;
  2081. UserNameComboBox.Update(index, displayString, image);
  2082. IsChangingUserName = FALSE;
  2083. }
  2084. if (UserNameCertHash != NULL)
  2085. {
  2086. UCHAR hash[CERT_HASH_LENGTH];
  2087. DWORD length = CERT_HASH_LENGTH;
  2088. if (CertGetCertificateContextProperty(
  2089. certEnum->pCertContext,
  2090. CERT_SHA1_HASH_PROP_ID,
  2091. static_cast<VOID *>(hash),
  2092. &length))
  2093. {
  2094. // if the hash of an inserted card matches the one we're looking
  2095. // for, release the match pattern from memory, and force
  2096. // select the inserted card.
  2097. //
  2098. // UserNameCertHash was set by unmarshalling the marshalled username
  2099. // contained in a credential on the user keyring, and then searching
  2100. // the cert store for a matching certificate.
  2101. if (RtlCompareMemory(UserNameCertHash,
  2102. hash,
  2103. CERT_HASH_LENGTH) ==
  2104. CERT_HASH_LENGTH)
  2105. {
  2106. delete [] UserNameCertHash;
  2107. UserNameCertHash = NULL;
  2108. IsChangingUserName = TRUE;
  2109. SendMessage(UserNameControlWindow,
  2110. CB_SETCURSEL, newIndex, 0);
  2111. IsChangingUserName = FALSE;
  2112. OnUserNameSelectionChange();
  2113. }
  2114. }
  2115. }
  2116. }
  2117. else
  2118. {
  2119. CreduiDebugLog(
  2120. "CreduiCredentialControl::HandleSmartCardMessages: "
  2121. "Card certificate to absent reader\n");
  2122. }
  2123. }
  2124. else if (message == CreduiScarduiWmCardStatus)
  2125. {
  2126. #ifdef SCARDREPORTS
  2127. CreduiDebugLog("CREDUI: card status event for %0x\n",this->Window);
  2128. #endif
  2129. if (index != -1)
  2130. {
  2131. if (--SmartCardReadCount == 0)
  2132. {
  2133. if (UserNameCertHash != NULL)
  2134. {
  2135. IsChangingUserName = TRUE;
  2136. SetWindowText(UserNameControlWindow,
  2137. DoingCommandLine ?
  2138. CreduiStrings.NoCard :
  2139. CreduiStrings.EmptyReader);
  2140. IsChangingUserName = FALSE;
  2141. }
  2142. }
  2143. else
  2144. {
  2145. // if still other readers to service, extend the timeout
  2146. Heartbeats = 0;
  2147. }
  2148. UINT image = IMAGE_SMART_CARD_MISSING;
  2149. BOOL showBalloon = FALSE;
  2150. switch (certEnum->dwStatus)
  2151. {
  2152. case SCARD_S_SUCCESS:
  2153. COMBOBOXEXITEM item;
  2154. #ifdef SCARDREPORTS
  2155. CreduiDebugLog("CREDUI: card status SUCCESS: %ws\n", certEnum->pszCardName );
  2156. #endif
  2157. item.mask = CBEIF_IMAGE;
  2158. item.iItem = index;
  2159. if (SendMessage(UserNameControlWindow, CBEM_GETITEM,
  2160. 0, reinterpret_cast<LPARAM>(&item)) &&
  2161. (item.iImage != IMAGE_SMART_CARD_MISSING))
  2162. {
  2163. return TRUE;
  2164. }
  2165. displayString = CreduiStrings.EmptyCard;
  2166. break;
  2167. case SCARD_E_UNKNOWN_CARD:
  2168. #ifdef SCARDREPORTS
  2169. CreduiDebugLog("CREDUI: card status UNKNOWN CARD\n");
  2170. #endif
  2171. displayString = CreduiStrings.UnknownCard;
  2172. break;
  2173. case SCARD_W_UNRESPONSIVE_CARD:
  2174. #ifdef SCARDREPORTS
  2175. CreduiDebugLog("CREDUI: card status UNRESPONSIVE CARD\n");
  2176. #endif
  2177. displayString = CreduiStrings.BackwardsCard;
  2178. if (!DoingCommandLine) showBalloon = TRUE;
  2179. break;
  2180. case NTE_KEYSET_NOT_DEF:
  2181. #ifdef SCARDREPORTS
  2182. CreduiDebugLog("CREDUI: card status NTE_KEYSET_NOT_DEF\n");
  2183. #endif
  2184. // TODO: This case should be removed eventually.
  2185. displayString = CreduiStrings.EmptyCard;
  2186. break;
  2187. case SCARD_W_REMOVED_CARD:
  2188. #ifdef SCARDREPORTS
  2189. CreduiDebugLog("CREDUI: card status REMOVED CARD\n");
  2190. #endif
  2191. displayString = DoingCommandLine ?
  2192. CreduiStrings.NoCard :
  2193. CreduiStrings.EmptyReader;
  2194. CreduiStrings.EmptyReader;
  2195. break;
  2196. default:
  2197. #ifdef SCARDREPORTS
  2198. CreduiDebugLog("CREDUI: card status ERROR\n");
  2199. #endif
  2200. displayString = CreduiStrings.CardError;
  2201. break;
  2202. }
  2203. IsChangingUserName = TRUE;
  2204. UserNameComboBox.Update(index, displayString, image);
  2205. IsChangingUserName = FALSE;
  2206. if (showBalloon && !BalloonTip.IsVisible())
  2207. {
  2208. BalloonTip.SetInfo(UserNameControlWindow,
  2209. &CreduiBackwardsTipInfo);
  2210. BalloonTip.Show();
  2211. }
  2212. }
  2213. else
  2214. {
  2215. CreduiDebugLog(
  2216. "CreduiCredentialControl::HandleSmartCardMessages: "
  2217. "Card status to absent reader\n");
  2218. }
  2219. }
  2220. // We handled the message:
  2221. return TRUE;
  2222. }
  2223. //=============================================================================
  2224. // CreduiCredentialControl::CreateControls
  2225. //
  2226. // Created 06/23/2000 johnstep (John Stephens)
  2227. //=============================================================================
  2228. BOOL
  2229. CreduiCredentialControl::CreateControls()
  2230. {
  2231. // First we need the parent window:
  2232. HWND dialogWindow = GetParent(Window);
  2233. if (dialogWindow == NULL)
  2234. {
  2235. return FALSE;
  2236. }
  2237. // Create the various windows:
  2238. RECT clientRect;
  2239. RECT rect;
  2240. UINT add;
  2241. BOOL noViewCert = FALSE;
  2242. if ( Style & CRS_KEEPUSERNAME )
  2243. {
  2244. KeepUserName = TRUE;
  2245. }
  2246. if (!(Style & CRS_USERNAMES) )
  2247. {
  2248. NoEditUserName = TRUE;
  2249. }
  2250. else if ((Style & (CRS_CERTIFICATES | CRS_SMARTCARDS)) == 0)
  2251. {
  2252. noViewCert = TRUE;
  2253. }
  2254. if ( Style & CRS_SINGLESIGNON )
  2255. IsPassport = TRUE;
  2256. else
  2257. IsPassport = FALSE;
  2258. // Determine how much wider the control is than the minimum to resize and
  2259. // reposition controls as necessary:
  2260. GetClientRect(Window, &clientRect);
  2261. rect.left = 0;
  2262. rect.top = 0;
  2263. rect.right = CREDUI_CONTROL_MIN_WIDTH;
  2264. rect.bottom = CREDUI_CONTROL_MIN_HEIGHT;
  2265. if ( !DoingCommandLine && !MapDialogRect(dialogWindow, &rect))
  2266. {
  2267. goto ErrorExit;
  2268. }
  2269. if ((clientRect.right - clientRect.left) >
  2270. (rect.right - rect.left))
  2271. {
  2272. add = (clientRect.right - clientRect.left) -
  2273. (rect.right - rect.left);
  2274. }
  2275. else
  2276. {
  2277. add = 0;
  2278. }
  2279. // Create user name static text control:
  2280. rect.left = CREDUI_CONTROL_USERNAME_STATIC_X;
  2281. rect.top = CREDUI_CONTROL_USERNAME_STATIC_Y;
  2282. rect.right = rect.left + CREDUI_CONTROL_USERNAME_STATIC_WIDTH;
  2283. rect.bottom = rect.top + CREDUI_CONTROL_USERNAME_STATIC_HEIGHT;
  2284. if ( !DoingCommandLine && !MapDialogRect(dialogWindow, &rect))
  2285. {
  2286. goto ErrorExit;
  2287. }
  2288. WCHAR* pUserNameLabel;
  2289. if ( IsPassport )
  2290. pUserNameLabel = CreduiStrings.EmailName;
  2291. else
  2292. pUserNameLabel = CreduiStrings.UserNameStatic;
  2293. UserNameStaticWindow =
  2294. CreateWindowEx(
  2295. WS_EX_NOPARENTNOTIFY,
  2296. L"STATIC",
  2297. pUserNameLabel,
  2298. WS_VISIBLE | WS_CHILD | WS_GROUP,
  2299. rect.left,
  2300. rect.top,
  2301. rect.right - rect.left,
  2302. rect.bottom - rect.top,
  2303. Window,
  2304. reinterpret_cast<HMENU>(IDC_USERNAME_STATIC),
  2305. CreduiCredentialControl::Instance,
  2306. NULL);
  2307. if (UserNameStaticWindow == NULL)
  2308. {
  2309. goto ErrorExit;
  2310. }
  2311. // Create user name combo box:
  2312. rect.left = CREDUI_CONTROL_USERNAME_X;
  2313. rect.top = CREDUI_CONTROL_USERNAME_Y;
  2314. if (!noViewCert)
  2315. {
  2316. rect.right = rect.left + CREDUI_CONTROL_USERNAME_WIDTH;
  2317. }
  2318. else
  2319. {
  2320. rect.right = CREDUI_CONTROL_VIEW_X + CREDUI_CONTROL_VIEW_WIDTH;
  2321. }
  2322. if ( KeepUserName )
  2323. {
  2324. rect.top += 2; // fudge it to make them line up better
  2325. rect.bottom = rect.top + CREDUI_CONTROL_PASSWORD_STATIC_HEIGHT; // make it the same height as the password edit
  2326. }
  2327. else
  2328. {
  2329. rect.bottom = rect.top + CREDUI_CONTROL_USERNAME_HEIGHT; // set the height
  2330. }
  2331. if ( !DoingCommandLine && !MapDialogRect(dialogWindow, &rect))
  2332. {
  2333. goto ErrorExit;
  2334. }
  2335. // This block of statements and the usage of lExStyles : see bug 439840
  2336. LONG_PTR lExStyles = GetWindowLongPtr(Window,GWL_EXSTYLE);
  2337. SetWindowLongPtr(Window,GWL_EXSTYLE,(lExStyles | WS_EX_NOINHERITLAYOUT));
  2338. if ( KeepUserName )
  2339. {
  2340. // create an edit box instead of a combo box
  2341. UserNameControlWindow =
  2342. CreateWindowEx(
  2343. WS_EX_NOPARENTNOTIFY,
  2344. L"Edit",
  2345. L"",
  2346. WS_VISIBLE | WS_CHILD | WS_TABSTOP | ES_READONLY,
  2347. rect.left,
  2348. rect.top,
  2349. rect.right - rect.left + add,
  2350. rect.bottom - rect.top,
  2351. Window,
  2352. reinterpret_cast<HMENU>(IDC_USERNAME),
  2353. CreduiCredentialControl::Instance,
  2354. NULL);
  2355. }
  2356. else
  2357. {
  2358. UserNameControlWindow =
  2359. CreateWindowEx(
  2360. WS_EX_NOPARENTNOTIFY,
  2361. L"ComboBoxEx32",
  2362. L"",
  2363. WS_VISIBLE | WS_CHILD | WS_TABSTOP | WS_VSCROLL |
  2364. (NoEditUserName ? CBS_DROPDOWNLIST : CBS_DROPDOWN) |
  2365. CBS_AUTOHSCROLL,
  2366. rect.left,
  2367. rect.top,
  2368. rect.right - rect.left + add,
  2369. rect.bottom - rect.top,
  2370. Window,
  2371. reinterpret_cast<HMENU>(IDC_USERNAME),
  2372. CreduiCredentialControl::Instance,
  2373. NULL);
  2374. }
  2375. SetWindowLongPtr(Window,GWL_EXSTYLE,lExStyles);
  2376. if (UserNameControlWindow == NULL)
  2377. {
  2378. goto ErrorExit;
  2379. }
  2380. // Create view button:
  2381. if (!noViewCert)
  2382. {
  2383. rect.left = CREDUI_CONTROL_VIEW_X;
  2384. rect.top = CREDUI_CONTROL_VIEW_Y;
  2385. rect.right = rect.left + CREDUI_CONTROL_VIEW_WIDTH;
  2386. rect.bottom = rect.top + CREDUI_CONTROL_VIEW_HEIGHT;
  2387. if ( !DoingCommandLine && !MapDialogRect(dialogWindow, &rect))
  2388. {
  2389. goto ErrorExit;
  2390. }
  2391. ViewCertControlWindow =
  2392. CreateWindowEx(
  2393. WS_EX_NOPARENTNOTIFY,
  2394. L"BUTTON",
  2395. L"&...",
  2396. WS_VISIBLE | WS_CHILD | WS_TABSTOP | WS_GROUP |
  2397. BS_PUSHBUTTON | BS_CENTER,
  2398. rect.left + add,
  2399. rect.top,
  2400. rect.right - rect.left,
  2401. rect.bottom - rect.top,
  2402. Window,
  2403. reinterpret_cast<HMENU>(IDC_VIEW_CERT),
  2404. CreduiCredentialControl::Instance,
  2405. NULL);
  2406. if (ViewCertControlWindow == NULL)
  2407. {
  2408. goto ErrorExit;
  2409. }
  2410. EnableWindow(ViewCertControlWindow, FALSE);
  2411. DisabledControlMask |= DISABLED_CONTROL_VIEW;
  2412. }
  2413. // Create password static text control:
  2414. rect.left = CREDUI_CONTROL_PASSWORD_STATIC_X;
  2415. rect.top = CREDUI_CONTROL_PASSWORD_STATIC_Y;
  2416. rect.right = rect.left + CREDUI_CONTROL_PASSWORD_STATIC_WIDTH;
  2417. rect.bottom = rect.top + CREDUI_CONTROL_PASSWORD_STATIC_HEIGHT;
  2418. if ( !DoingCommandLine && !MapDialogRect(dialogWindow, &rect))
  2419. {
  2420. goto ErrorExit;
  2421. }
  2422. PasswordStaticWindow =
  2423. CreateWindowEx(
  2424. WS_EX_NOPARENTNOTIFY,
  2425. L"STATIC",
  2426. CreduiStrings.PasswordStatic,
  2427. WS_VISIBLE | WS_CHILD | WS_GROUP,
  2428. rect.left,
  2429. rect.top,
  2430. rect.right - rect.left,
  2431. rect.bottom - rect.top,
  2432. Window,
  2433. reinterpret_cast<HMENU>(IDC_PASSWORD_STATIC),
  2434. CreduiCredentialControl::Instance,
  2435. NULL);
  2436. if (PasswordStaticWindow == NULL)
  2437. {
  2438. goto ErrorExit;
  2439. }
  2440. // Create password edit control:
  2441. rect.left = CREDUI_CONTROL_PASSWORD_X;
  2442. rect.top = CREDUI_CONTROL_PASSWORD_Y;
  2443. if (!noViewCert)
  2444. {
  2445. rect.right = rect.left + CREDUI_CONTROL_PASSWORD_WIDTH;
  2446. }
  2447. else
  2448. {
  2449. rect.right = CREDUI_CONTROL_VIEW_X + CREDUI_CONTROL_VIEW_WIDTH;
  2450. }
  2451. rect.bottom = rect.top + CREDUI_CONTROL_PASSWORD_HEIGHT;
  2452. if (!DoingCommandLine && !MapDialogRect(dialogWindow, &rect))
  2453. {
  2454. goto ErrorExit;
  2455. }
  2456. // This block of statements and the usage of lExStyles : see bug 439840
  2457. lExStyles = GetWindowLongPtr(Window,GWL_EXSTYLE);
  2458. SetWindowLongPtr(Window,GWL_EXSTYLE,(lExStyles | WS_EX_NOINHERITLAYOUT));
  2459. PasswordControlWindow =
  2460. CreateWindowEx(
  2461. WS_EX_NOPARENTNOTIFY | WS_EX_CLIENTEDGE,
  2462. L"EDIT",
  2463. L"",
  2464. WS_VISIBLE | WS_CHILD | WS_TABSTOP | ES_PASSWORD | ES_AUTOHSCROLL,
  2465. rect.left,
  2466. rect.top,
  2467. rect.right - rect.left + add,
  2468. rect.bottom - rect.top + 1, // NOTE: Add 1 for now, investigate
  2469. Window,
  2470. reinterpret_cast<HMENU>(IDC_PASSWORD),
  2471. CreduiCredentialControl::Instance,
  2472. NULL);
  2473. SetWindowLongPtr(Window,GWL_EXSTYLE,lExStyles);
  2474. if (PasswordControlWindow == NULL)
  2475. {
  2476. goto ErrorExit;
  2477. }
  2478. // Create save check box:
  2479. if (Style & CRS_SAVECHECK )
  2480. {
  2481. rect.left = CREDUI_CONTROL_SAVE_X;
  2482. rect.top = CREDUI_CONTROL_SAVE_Y;
  2483. rect.right = rect.left + CREDUI_CONTROL_SAVE_WIDTH;
  2484. rect.bottom = rect.top + CREDUI_CONTROL_SAVE_HEIGHT;
  2485. if (!DoingCommandLine && !MapDialogRect(dialogWindow, &rect))
  2486. {
  2487. goto ErrorExit;
  2488. }
  2489. WCHAR* pSavePromptString;
  2490. if ( IsPassport )
  2491. pSavePromptString = CreduiStrings.PassportSave;
  2492. else
  2493. pSavePromptString = CreduiStrings.Save;
  2494. SaveControlWindow =
  2495. CreateWindowEx(
  2496. WS_EX_NOPARENTNOTIFY,
  2497. L"BUTTON",
  2498. pSavePromptString,
  2499. WS_VISIBLE | WS_CHILD | WS_TABSTOP | WS_GROUP |
  2500. BS_AUTOCHECKBOX,
  2501. rect.left,
  2502. rect.top,
  2503. rect.right - rect.left + add,
  2504. rect.bottom - rect.top,
  2505. Window,
  2506. reinterpret_cast<HMENU>(IDC_SAVE),
  2507. CreduiCredentialControl::Instance,
  2508. NULL);
  2509. if (SaveControlWindow == NULL)
  2510. {
  2511. goto ErrorExit;
  2512. }
  2513. SendMessage(SaveControlWindow, BM_SETCHECK, BST_UNCHECKED, 0);
  2514. }
  2515. SendMessage(
  2516. Window,
  2517. WM_SETFONT,
  2518. SendMessage(dialogWindow, WM_GETFONT, 0, 0),
  2519. FALSE);
  2520. return TRUE;
  2521. ErrorExit:
  2522. if (SaveControlWindow != NULL)
  2523. {
  2524. DestroyWindow(SaveControlWindow);
  2525. SaveControlWindow = NULL;
  2526. }
  2527. if (PasswordControlWindow != NULL)
  2528. {
  2529. DestroyWindow(PasswordControlWindow);
  2530. PasswordControlWindow = NULL;
  2531. }
  2532. if (PasswordStaticWindow != NULL)
  2533. {
  2534. DestroyWindow(PasswordStaticWindow);
  2535. PasswordStaticWindow = NULL;
  2536. }
  2537. if (ViewCertControlWindow != NULL)
  2538. {
  2539. DestroyWindow(ViewCertControlWindow);
  2540. ViewCertControlWindow = NULL;
  2541. }
  2542. if (UserNameControlWindow != NULL)
  2543. {
  2544. DestroyWindow(UserNameControlWindow);
  2545. UserNameControlWindow = NULL;
  2546. }
  2547. if (UserNameStaticWindow != NULL)
  2548. {
  2549. DestroyWindow(UserNameStaticWindow);
  2550. UserNameStaticWindow = NULL;
  2551. }
  2552. return FALSE;
  2553. }
  2554. LPWSTR
  2555. TrimUsername(
  2556. IN LPWSTR AccountDomainName OPTIONAL,
  2557. IN LPWSTR UserName
  2558. )
  2559. /*++
  2560. Routine Description:
  2561. Returns a pointer to the substring of UserName past any AccountDomainName prefix.
  2562. Arguments:
  2563. AccountDomainName - The DomainName to check to see if it prefixes the UserName.
  2564. UserName - The UserName to check
  2565. Return Values:
  2566. Return a pointer to the non-prefixed username
  2567. --*/
  2568. {
  2569. DWORD AccountDomainNameLength;
  2570. DWORD UserNameLength;
  2571. WCHAR Temp[CNLEN+1];
  2572. //
  2573. // If we couldn't determine the AccountDomainName,
  2574. // return the complete user name.
  2575. //
  2576. if ( AccountDomainName == NULL ) {
  2577. return UserName;
  2578. }
  2579. //
  2580. // If the user name isn't prefixed by the account domain name,
  2581. // return the complete user name.
  2582. //
  2583. AccountDomainNameLength = wcslen( AccountDomainName );
  2584. UserNameLength = wcslen( UserName );
  2585. if ( AccountDomainNameLength > CNLEN || AccountDomainNameLength < 1 ) {
  2586. return UserName;
  2587. }
  2588. if ( AccountDomainNameLength+2 > UserNameLength ) {
  2589. return UserName;
  2590. }
  2591. if ( UserName[AccountDomainNameLength] != '\\' ) {
  2592. return UserName;
  2593. }
  2594. RtlCopyMemory( Temp, UserName, AccountDomainNameLength*sizeof(WCHAR) );
  2595. Temp[AccountDomainNameLength] = '\0';
  2596. if ( _wcsicmp( Temp, AccountDomainName ) != 0 ) {
  2597. return UserName;
  2598. }
  2599. return &UserName[AccountDomainNameLength+1];
  2600. }
  2601. //=============================================================================
  2602. // CreduiCredentialControl::InitComboBoxUserNames
  2603. //
  2604. // Created 06/23/2000 johnstep (John Stephens)
  2605. //=============================================================================
  2606. BOOL
  2607. CreduiCredentialControl::InitComboBoxUserNames()
  2608. {
  2609. CREDENTIAL **credentialSet = NULL;
  2610. LOCALGROUP_MEMBERS_INFO_2 *groupInfo = NULL;
  2611. DWORD nameCount = 0;
  2612. LPWSTR AccountDomainName = NULL;
  2613. if (Style & CRS_ADMINISTRATORS)
  2614. {
  2615. //
  2616. // Enumerate the members of LocalAdministrators
  2617. //
  2618. if ( !CreduiGetAdministratorsGroupInfo(&groupInfo, &nameCount)) {
  2619. return FALSE;
  2620. }
  2621. }
  2622. else
  2623. {
  2624. if (!LocalCredEnumerateW(NULL, 0, &nameCount, &credentialSet))
  2625. {
  2626. return FALSE;
  2627. }
  2628. }
  2629. // Initialize COM for STA, unless there are zero names:
  2630. if ((Style & CRS_AUTOCOMPLETE) && nameCount > 0)
  2631. {
  2632. HRESULT comResult = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
  2633. if (SUCCEEDED(comResult))
  2634. {
  2635. IsAutoComplete = TRUE;
  2636. }
  2637. else
  2638. {
  2639. // The auto complete object and our string object require a STA.
  2640. // Our object could easily support a MTA, but we do not support
  2641. // marshaling between apartments.
  2642. if (comResult == RPC_E_CHANGED_MODE)
  2643. {
  2644. CreduiDebugLog("CreduiCredentialControl: "
  2645. "Auto complete disabled for MTA\n");
  2646. }
  2647. IsAutoComplete = FALSE;
  2648. }
  2649. }
  2650. else
  2651. {
  2652. IsAutoComplete = FALSE;
  2653. }
  2654. // Initialize the auto complete combo box:
  2655. if (!UserNameComboBox.Init(CreduiInstance,
  2656. UserNameControlWindow,
  2657. IsAutoComplete ? nameCount : 0,
  2658. IDB_TYPES,
  2659. IMAGE_USERNAME))
  2660. {
  2661. // If initialization failed, and we had attempted for auto complete
  2662. // support, try again without auto complete:
  2663. if (IsAutoComplete)
  2664. {
  2665. IsAutoComplete = FALSE;
  2666. CoUninitialize();
  2667. if (!UserNameComboBox.Init(CreduiInstance,
  2668. UserNameControlWindow,
  2669. 0,
  2670. IDB_TYPES,
  2671. IMAGE_USERNAME))
  2672. {
  2673. return FALSE;
  2674. }
  2675. }
  2676. else
  2677. {
  2678. return FALSE;
  2679. }
  2680. }
  2681. //
  2682. // If we'll complete the user name,
  2683. // truncate any username displayed here.
  2684. // (We'll complete it later.)
  2685. //
  2686. if ( Style & CRS_COMPLETEUSERNAME ) {
  2687. AccountDomainName = GetAccountDomainName();
  2688. }
  2689. // Add user names from credentials, if not requesting an
  2690. // Administrator:
  2691. if (!(Style & CRS_KEEPUSERNAME))
  2692. {
  2693. // only add usernames if we're not keeping the one set
  2694. UINT i = 0;
  2695. if (!(Style & CRS_ADMINISTRATORS))
  2696. {
  2697. for (i = 0; i < nameCount; ++i)
  2698. {
  2699. // Skip domain certificates:
  2700. if (credentialSet[i]->Type == CRED_TYPE_DOMAIN_CERTIFICATE)
  2701. {
  2702. continue;
  2703. }
  2704. // If this is a generic credential, look for a marshaled
  2705. // credential, and skip, if found:
  2706. if ((credentialSet[i]->Type == CRED_TYPE_GENERIC) &&
  2707. LocalCredIsMarshaledCredentialW(credentialSet[i]->UserName))
  2708. {
  2709. continue;
  2710. }
  2711. // Skip this credential if the name is empty:
  2712. if (credentialSet[i]->UserName == NULL)
  2713. {
  2714. continue;
  2715. }
  2716. // Add the user name to the combo box with auto complete. If
  2717. // this fails, do not continue:
  2718. if (UserNameComboBox.Add(
  2719. TrimUsername( AccountDomainName, credentialSet[i]->UserName),
  2720. 0, IsAutoComplete, TRUE) == -1)
  2721. {
  2722. break;
  2723. }
  2724. }
  2725. LocalCredFree(static_cast<VOID *>(credentialSet));
  2726. }
  2727. else if (groupInfo != NULL)
  2728. {
  2729. PSID adminSid = NULL;
  2730. if ( !CreduiLookupLocalSidFromRid(DOMAIN_USER_RID_ADMIN, &adminSid)) {
  2731. adminSid = NULL;
  2732. }
  2733. // Add local administrators to the combo box:
  2734. for (i = 0; i < nameCount; ++i)
  2735. {
  2736. if ( groupInfo[i].lgrmi2_sidusage == SidTypeUser )
  2737. {
  2738. DWORD ComboBoxIndex;
  2739. BOOLEAN IsAdminAccount;
  2740. BOOLEAN RememberComboBoxIndex;
  2741. //
  2742. // If this is Personal and not safe mode,
  2743. // Ignore the well-known Administrator account.
  2744. //
  2745. IsAdminAccount = (adminSid != NULL) &&
  2746. EqualSid(adminSid, groupInfo[i].lgrmi2_sid);
  2747. if ( CreduiIsPersonal &&
  2748. !CreduiIsSafeMode &&
  2749. IsAdminAccount ) {
  2750. continue;
  2751. }
  2752. //
  2753. // If the caller wants to prepopulate the edit box,
  2754. // flag that we need to remember this account
  2755. //
  2756. // Detect the well known admin account
  2757. //
  2758. RememberComboBoxIndex = FALSE;
  2759. if ( (Style & CRS_PREFILLADMIN) != 0 &&
  2760. IsAdminAccount ) {
  2761. RememberComboBoxIndex = TRUE;
  2762. }
  2763. //
  2764. // Add the name to the combo box
  2765. //
  2766. ComboBoxIndex = UserNameComboBox.Add(
  2767. TrimUsername( AccountDomainName, groupInfo[i].lgrmi2_domainandname),
  2768. 0,
  2769. IsAutoComplete,
  2770. TRUE);
  2771. if ( ComboBoxIndex == -1 ) {
  2772. break;
  2773. }
  2774. //
  2775. // If we're to remember the index,
  2776. // do so.
  2777. //
  2778. if ( RememberComboBoxIndex ) {
  2779. UserNameSelection = ComboBoxIndex;
  2780. IsChangingUserName = TRUE;
  2781. SendMessage(UserNameControlWindow,
  2782. CB_SETCURSEL,
  2783. ComboBoxIndex,
  2784. 0);
  2785. IsChangingUserName = FALSE;
  2786. }
  2787. }
  2788. }
  2789. delete [] adminSid;
  2790. NetApiBufferFree(groupInfo);
  2791. }
  2792. }
  2793. if ( AccountDomainName != NULL ) {
  2794. NetApiBufferFree( AccountDomainName );
  2795. }
  2796. return TRUE;
  2797. }
  2798. //=============================================================================
  2799. // CreduiCredentialControl::InitWindow
  2800. //
  2801. // Created 06/20/2000 johnstep (John Stephens)
  2802. //=============================================================================
  2803. BOOL
  2804. CreduiCredentialControl::InitWindow()
  2805. {
  2806. // Set that we're intialized here, even though the controls have not yet
  2807. // been created, etc.:
  2808. IsInitialized = TRUE;
  2809. // Make sure WS_EX_CONTROLPARENT is set:
  2810. SetWindowLong(Window,
  2811. GWL_EXSTYLE,
  2812. GetWindowLong(Window, GWL_EXSTYLE) |
  2813. WS_EX_CONTROLPARENT);
  2814. // Initialize the balloon tip for this window:
  2815. if (!CreateControls() ||
  2816. !BalloonTip.Init(CreduiInstance, Window))
  2817. {
  2818. return FALSE;
  2819. }
  2820. // Limit the number of characters entered into the user name and password
  2821. // edit controls:
  2822. SendMessage(UserNameControlWindow,
  2823. CB_LIMITTEXT,
  2824. CREDUI_MAX_USERNAME_LENGTH,
  2825. 0);
  2826. SendMessage(PasswordControlWindow,
  2827. EM_LIMITTEXT,
  2828. CREDUI_MAX_PASSWORD_LENGTH,
  2829. 0);
  2830. // Set the password character to something cooler:
  2831. PasswordBox.Init(PasswordControlWindow,
  2832. &BalloonTip,
  2833. &CreduiCapsLockTipInfo);
  2834. // Initialize the user name auto complete combo box:
  2835. if ( !KeepUserName )
  2836. {
  2837. if (((Style & CRS_USERNAMES) && InitComboBoxUserNames()) ||
  2838. UserNameComboBox.Init(CreduiInstance,
  2839. UserNameControlWindow,
  2840. 0,
  2841. IDB_TYPES,
  2842. IMAGE_USERNAME))
  2843. {
  2844. // Since we're finished adding auto complete names, enable it now.
  2845. // On failure, the UI can still be presented:
  2846. UserNameComboBox.Enable();
  2847. BOOL haveCertificates = FALSE;
  2848. CertBaseInComboBox = (ULONG)
  2849. SendMessage(UserNameControlWindow,
  2850. CB_GETCOUNT, 0, 0);
  2851. if (Style & CRS_CERTIFICATES)
  2852. {
  2853. haveCertificates = AddCertificates();
  2854. }
  2855. SmartCardBaseInComboBox = CertBaseInComboBox + CertCount;
  2856. if ((Style & CRS_SMARTCARDS) && CreduiHasSmartCardSupport)
  2857. {
  2858. #ifdef SCARDREPORTS
  2859. CreduiDebugLog("CREDUI: Call to SCardUIInit for %0x\n",Window);
  2860. #endif
  2861. ScardUiHandle = SCardUIInit(Window);
  2862. if (ScardUiHandle == NULL)
  2863. {
  2864. #ifdef SCARDREPORTS
  2865. CreduiDebugLog("CREDUI: Call to SCardUIInit failed\n");
  2866. #endif
  2867. CreduiDebugLog("CreduiCredentialControl::InitWindow: "
  2868. "SCardUIInit failed\n");
  2869. }
  2870. }
  2871. // If NoEditUserName is allowed, make sure we eithet have at least one certificate
  2872. // or a prefilled username for the control, otherwise fail
  2873. if (NoEditUserName )
  2874. {
  2875. if (!haveCertificates &&
  2876. (ScardUiHandle == NULL))
  2877. {
  2878. return FALSE;
  2879. }
  2880. IsChangingUserName = TRUE;
  2881. SendMessage(UserNameControlWindow,
  2882. CB_SETCURSEL,
  2883. 0,
  2884. 0);
  2885. IsChangingUserName = FALSE;
  2886. // If we have at least one certificate, enable the view control
  2887. // now. If a smart card, it will be enabled later:
  2888. if (CertCount > 0)
  2889. {
  2890. EnableWindow(ViewCertControlWindow, TRUE);
  2891. DisabledControlMask &= ~DISABLED_CONTROL_VIEW;
  2892. }
  2893. }
  2894. // Wait until everything has been initialized before
  2895. // we have the update. This will now properly determine if the default
  2896. // user name is a smart card or not.
  2897. OnUserNameSelectionChange();
  2898. }
  2899. else
  2900. {
  2901. return FALSE;
  2902. }
  2903. }
  2904. if ( !DoingCommandLine ) {
  2905. SetFocus(UserNameControlWindow);
  2906. }
  2907. return TRUE;
  2908. }
  2909. //=============================================================================
  2910. // CredioCredentialControl::Enable
  2911. //
  2912. // Enables or disables all the user controls in the control.
  2913. //
  2914. // Arguments:
  2915. // enable (in) - TRUE to enable the controls, FALSE to disable.
  2916. //
  2917. // Created 06/20/2000 johnstep (John Stephens)
  2918. //=============================================================================
  2919. VOID
  2920. CreduiCredentialControl::Enable(
  2921. BOOL enable
  2922. )
  2923. {
  2924. if (enable && (DisabledControlMask & DISABLED_CONTROL))
  2925. {
  2926. DisabledControlMask &= ~DISABLED_CONTROL;
  2927. //EnableWindow(UserNameStaticWindow, TRUE);
  2928. //EnableWindow(UserNameControlWindow, TRUE);
  2929. if (!(DisabledControlMask & DISABLED_CONTROL_USERNAME))
  2930. {
  2931. EnableWindow(UserNameControlWindow, TRUE);
  2932. EnableWindow(UserNameStaticWindow, TRUE);
  2933. }
  2934. if (!(DisabledControlMask & DISABLED_CONTROL_PASSWORD))
  2935. {
  2936. EnableWindow(PasswordControlWindow, TRUE);
  2937. EnableWindow(PasswordStaticWindow, TRUE);
  2938. }
  2939. if (!(DisabledControlMask & DISABLED_CONTROL_VIEW))
  2940. {
  2941. EnableWindow(ViewCertControlWindow, TRUE);
  2942. }
  2943. if (SaveControlWindow != NULL)
  2944. {
  2945. if (!(DisabledControlMask & DISABLED_CONTROL_SAVE))
  2946. {
  2947. EnableWindow(SaveControlWindow, TRUE);
  2948. }
  2949. }
  2950. IsChangingUserName = TRUE;
  2951. SendMessage(UserNameControlWindow,
  2952. CB_SETCURSEL,
  2953. UserNameSelection,
  2954. 0);
  2955. IsChangingUserName = FALSE;
  2956. OnUserNameSelectionChange();
  2957. }
  2958. else if (!(DisabledControlMask & DISABLED_CONTROL))
  2959. {
  2960. // Hide the balloon tip before disabling the window:
  2961. if (BalloonTip.IsVisible())
  2962. {
  2963. BalloonTip.Hide();
  2964. }
  2965. DisabledControlMask |= DISABLED_CONTROL;
  2966. UserNameSelection = (LONG) SendMessage(UserNameControlWindow,
  2967. CB_GETCURSEL, 0, 0);
  2968. EnableWindow(UserNameStaticWindow, FALSE);
  2969. EnableWindow(UserNameControlWindow, FALSE);
  2970. EnableWindow(ViewCertControlWindow, FALSE);
  2971. EnableWindow(PasswordControlWindow, FALSE);
  2972. SetFocus(UserNameControlWindow);
  2973. EnableWindow(PasswordStaticWindow, FALSE);
  2974. if (SaveControlWindow != NULL)
  2975. {
  2976. EnableWindow(SaveControlWindow, FALSE);
  2977. }
  2978. }
  2979. }
  2980. //=============================================================================
  2981. // CreduiCredentialControl::MessageHandlerCallback
  2982. //
  2983. // This is the actual callback function for the control window.
  2984. //
  2985. // Arguments:
  2986. // window (in)
  2987. // message (in)
  2988. // wParam (in)
  2989. // lParam (in)
  2990. //
  2991. // Created 06/20/2000 johnstep (John Stephens)
  2992. //=============================================================================
  2993. LRESULT
  2994. CALLBACK
  2995. CreduiCredentialControl::MessageHandlerCallback(
  2996. HWND window,
  2997. UINT message,
  2998. WPARAM wParam,
  2999. LPARAM lParam
  3000. )
  3001. {
  3002. // CreduiDebugLog( "Control Callback: %8.8lx %8.8lx %8.8lx\n", message, wParam, lParam );
  3003. CreduiCredentialControl *that =
  3004. reinterpret_cast<CreduiCredentialControl *>(
  3005. GetWindowLongPtr(window, 0));
  3006. if (that != NULL)
  3007. {
  3008. LRESULT result2;
  3009. ASSERT(window == that->Window);
  3010. // CreduiDebugLog( "Certhashes: %8.8lx %8.8lx\n", that, that->CertHashes );
  3011. result2 = that->MessageHandler(message, wParam, lParam);
  3012. // CreduiDebugLog( "Certhashes2: %8.8lx %8.8lx\n", that, that->CertHashes );
  3013. return result2;
  3014. }
  3015. if (message == WM_CREATE)
  3016. {
  3017. CreduiCredentialControl *control = new CreduiCredentialControl;
  3018. if (control != NULL)
  3019. {
  3020. // Initialize some state:
  3021. control->FirstPaint = TRUE;
  3022. control->ShowBalloonTip = FALSE;
  3023. control->Window = window;
  3024. control->Style = GetWindowLong(window, GWL_STYLE);
  3025. // Store this object's pointer in the user data window long:
  3026. SetLastError(0);
  3027. LONG_PTR retPtr = SetWindowLongPtr(window,
  3028. 0,
  3029. reinterpret_cast<LONG_PTR>(control));
  3030. if ( retPtr != 0 || GetLastError() == 0 )
  3031. {
  3032. // we sucessfully set the window pointer
  3033. // If any of the required styles are set, initialize the window
  3034. // now. Otherwise, defer until CRM_INITSTYLE:
  3035. if (control->Style & (CRS_USERNAMES |
  3036. CRS_CERTIFICATES |
  3037. CRS_SMARTCARDS))
  3038. {
  3039. if (control->InitWindow())
  3040. {
  3041. return TRUE;
  3042. }
  3043. }
  3044. else
  3045. {
  3046. return TRUE;
  3047. }
  3048. }
  3049. SetWindowLongPtr(window, 0, 0);
  3050. delete control;
  3051. control = NULL;
  3052. }
  3053. DestroyWindow(window);
  3054. return 0;
  3055. }
  3056. return DefWindowProc(window, message, wParam, lParam);
  3057. }
  3058. //=============================================================================
  3059. // CreduiCredentialControl::OnSetUserNameA
  3060. //
  3061. // Created 06/22/2000 johnstep (John Stephens)
  3062. //=============================================================================
  3063. BOOL
  3064. CreduiCredentialControl::OnSetUserNameA(
  3065. CHAR *userNameA
  3066. )
  3067. {
  3068. BOOL success = FALSE;
  3069. if (userNameA != NULL)
  3070. {
  3071. INT bufferSize =
  3072. MultiByteToWideChar(CP_ACP, 0, userNameA, -1, NULL, 0);
  3073. if (bufferSize != 0)
  3074. {
  3075. WCHAR *userName = new WCHAR[bufferSize];
  3076. if (userName != NULL)
  3077. {
  3078. if (MultiByteToWideChar(CP_ACP,
  3079. 0,
  3080. userNameA,
  3081. -1,
  3082. userName,
  3083. bufferSize) > 0)
  3084. {
  3085. success = OnSetUserName(userName);
  3086. }
  3087. delete [] userName;
  3088. }
  3089. }
  3090. }
  3091. else
  3092. {
  3093. success = OnSetUserName(NULL);
  3094. }
  3095. return success;
  3096. };
  3097. //=============================================================================
  3098. // CreduiCredentialControl::OnSetUserName
  3099. //
  3100. // Created 06/22/2000 johnstep (John Stephens)
  3101. //=============================================================================
  3102. BOOL
  3103. CreduiCredentialControl::OnSetUserName(
  3104. WCHAR *userName
  3105. )
  3106. {
  3107. if ((userName == NULL) ||
  3108. (!LocalCredIsMarshaledCredentialW(userName)))
  3109. {
  3110. if ( DoingCommandLine )
  3111. {
  3112. // Save the initial user name for command line
  3113. if (userName == NULL)
  3114. {
  3115. InitialUserName = NULL;
  3116. }
  3117. else
  3118. {
  3119. int bufferLength = wcslen(userName) + 1;
  3120. InitialUserName = new WCHAR[bufferLength];
  3121. if ( InitialUserName == NULL )
  3122. {
  3123. // error return on failure to allocate
  3124. return FALSE;
  3125. }
  3126. StringCchCopyW(InitialUserName, bufferLength, userName);
  3127. }
  3128. }
  3129. return SetWindowText(UserNameControlWindow, userName);
  3130. }
  3131. else
  3132. {
  3133. CRED_MARSHAL_TYPE credMarshalType;
  3134. CERT_CREDENTIAL_INFO *certCredInfo = NULL;
  3135. BOOL foundCert = FALSE;
  3136. if (LocalCredUnmarshalCredentialW(
  3137. userName,
  3138. &credMarshalType,
  3139. reinterpret_cast<VOID **>(&certCredInfo)))
  3140. {
  3141. // Search for the certificate. What can we do if it is a
  3142. // smart card? Well, at least we can still search for it,
  3143. // but it is a bit more work because we must retrieve the
  3144. // hash from the context.
  3145. if (credMarshalType == CertCredential)
  3146. {
  3147. for (UINT i = 0; i < CertCount; ++i)
  3148. {
  3149. if (RtlCompareMemory(CertHashes[i],
  3150. certCredInfo->rgbHashOfCert,
  3151. CERT_HASH_LENGTH) ==
  3152. CERT_HASH_LENGTH)
  3153. {
  3154. IsChangingUserName = TRUE;
  3155. SendMessage(UserNameControlWindow,
  3156. CB_SETCURSEL,
  3157. CertBaseInComboBox + i,
  3158. 0);
  3159. IsChangingUserName = FALSE;
  3160. OnUserNameSelectionChange();
  3161. EnableWindow(ViewCertControlWindow, TRUE);
  3162. DisabledControlMask &= ~DISABLED_CONTROL_VIEW;
  3163. foundCert = TRUE;
  3164. break;
  3165. }
  3166. }
  3167. // If we couldn't find the certificate in our list, determine
  3168. // if this is a smart card certificate, based on its entry in
  3169. // the MY certificate store. If it is, store the hash and
  3170. // check for it on certificate arrival messages:
  3171. if (!foundCert)
  3172. {
  3173. CONST CERT_CONTEXT *certContext = NULL;
  3174. HCERTSTORE certStore = NULL;
  3175. certStore = CertOpenSystemStore(NULL, L"MY");
  3176. if (certStore != NULL)
  3177. {
  3178. CRYPT_HASH_BLOB hashBlob;
  3179. hashBlob.cbData = CERT_HASH_LENGTH;
  3180. hashBlob.pbData = reinterpret_cast<BYTE *>(
  3181. certCredInfo->rgbHashOfCert);
  3182. certContext = CertFindCertificateInStore(
  3183. certStore,
  3184. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  3185. 0,
  3186. CERT_FIND_SHA1_HASH,
  3187. &hashBlob,
  3188. NULL);
  3189. }
  3190. // If we found a certificate context, check to see if it
  3191. // is from a smart card:
  3192. if ((certContext != NULL) &&
  3193. CreduiIsRemovableCertificate(certContext))
  3194. {
  3195. UserNameCertHash = new UCHAR [1][CERT_HASH_LENGTH];
  3196. if (UserNameCertHash != NULL)
  3197. {
  3198. CopyMemory(UserNameCertHash,
  3199. certCredInfo->rgbHashOfCert,
  3200. CERT_HASH_LENGTH);
  3201. foundCert = TRUE;
  3202. }
  3203. }
  3204. // If we opened a store, free the certificate and close
  3205. // the store:
  3206. if (certStore != NULL)
  3207. {
  3208. if (certContext != NULL)
  3209. {
  3210. CertFreeCertificateContext(certContext);
  3211. }
  3212. if (!CertCloseStore(certStore, 0))
  3213. {
  3214. CreduiDebugLog(
  3215. "CreduiCredentialControl::OnSetUserName: "
  3216. "CertCloseStore failed: %u\n",
  3217. GetLastError());
  3218. }
  3219. }
  3220. }
  3221. }
  3222. LocalCredFree(static_cast<VOID *>(certCredInfo));
  3223. }
  3224. else
  3225. {
  3226. // Could not unmarshal, so just forget it:
  3227. CreduiDebugLog(
  3228. "CreduiCredentialControl::OnSetUserName: "
  3229. "CredUnmarshalCredential failed: %u\n",
  3230. GetLastError());
  3231. }
  3232. return foundCert;
  3233. }
  3234. };
  3235. //=============================================================================
  3236. // CreduiCredentialControl::OnGetUserNameA
  3237. //
  3238. // Created 06/22/2000 johnstep (John Stephens)
  3239. //=============================================================================
  3240. BOOL
  3241. CreduiCredentialControl::OnGetUserNameA(
  3242. CHAR *userNameA,
  3243. ULONG maxChars
  3244. )
  3245. {
  3246. BOOL success = FALSE;
  3247. if ((userNameA != NULL) && (maxChars != 0))
  3248. {
  3249. WCHAR *userName = new WCHAR[maxChars + 1];
  3250. if (userName != NULL)
  3251. {
  3252. if (OnGetUserName(userName, maxChars) &&
  3253. WideCharToMultiByte(
  3254. CP_ACP,
  3255. 0,
  3256. userName,
  3257. -1,
  3258. userNameA,
  3259. maxChars + 1, NULL, NULL))
  3260. {
  3261. success = TRUE;
  3262. }
  3263. delete [] userName;
  3264. }
  3265. }
  3266. return success;
  3267. };
  3268. //=============================================================================
  3269. // CreduiCredentialControl::OnGetUserName
  3270. //
  3271. // Created 06/22/2000 johnstep (John Stephens)
  3272. //=============================================================================
  3273. BOOL
  3274. CreduiCredentialControl::OnGetUserName(
  3275. WCHAR *userName,
  3276. ULONG maxChars
  3277. )
  3278. {
  3279. if ( KeepUserName )
  3280. {
  3281. SetLastError(0);
  3282. return (GetWindowText(UserNameControlWindow,
  3283. userName,
  3284. maxChars + 1) > 0) ||
  3285. (GetLastError() == ERROR_SUCCESS);
  3286. }
  3287. else
  3288. {
  3289. COMBOBOXEXITEM item;
  3290. item.iItem = SendMessage(UserNameControlWindow, CB_GETCURSEL, 0, 0);
  3291. // If we are trying to match a smart card certificate, fail this:
  3292. if (UserNameCertHash != NULL)
  3293. {
  3294. return FALSE;
  3295. }
  3296. // If this is not a certificate, it's easy:
  3297. if ((item.iItem == CB_ERR) || (item.iItem < CertBaseInComboBox))
  3298. {
  3299. BOOL RetVal;
  3300. SetLastError(0);
  3301. RetVal = GetWindowText(UserNameControlWindow,
  3302. userName,
  3303. maxChars + 1) > 0;
  3304. if ( !RetVal ) {
  3305. return ( GetLastError() == ERROR_SUCCESS );
  3306. }
  3307. //
  3308. // Complete the typed in username
  3309. if ( Style & CRS_COMPLETEUSERNAME) {
  3310. RetVal = CompleteUserName(
  3311. userName,
  3312. maxChars,
  3313. NULL, // No target info
  3314. NULL,
  3315. 0); // No target name
  3316. } else {
  3317. RetVal = TRUE;
  3318. }
  3319. return RetVal;
  3320. }
  3321. // This is a certificate, maybe from a smart card:
  3322. item.mask = CBEIF_IMAGE | CBEIF_TEXT;
  3323. item.pszText = userName;
  3324. item.cchTextMax = maxChars + 1;
  3325. if (!SendMessage(UserNameControlWindow,
  3326. CBEM_GETITEM,
  3327. 0,
  3328. reinterpret_cast<LPARAM>(&item)))
  3329. {
  3330. return FALSE;
  3331. }
  3332. CERT_CREDENTIAL_INFO certCredInfo;
  3333. certCredInfo.cbSize = sizeof certCredInfo;
  3334. if (item.iItem >= SmartCardBaseInComboBox)
  3335. {
  3336. if (item.iImage == IMAGE_SMART_CARD_MISSING)
  3337. {
  3338. return FALSE;
  3339. }
  3340. CERT_ENUM *certEnum =
  3341. reinterpret_cast<CERT_ENUM *>(
  3342. SendMessage(UserNameControlWindow,
  3343. CB_GETITEMDATA, item.iItem, 0));
  3344. // NOTE: Consider more complete error handling here.
  3345. if (certEnum != NULL)
  3346. {
  3347. DWORD length = CERT_HASH_LENGTH;
  3348. if (!CertGetCertificateContextProperty(
  3349. certEnum->pCertContext,
  3350. CERT_SHA1_HASH_PROP_ID,
  3351. static_cast<VOID *>(
  3352. certCredInfo.rgbHashOfCert),
  3353. &length))
  3354. {
  3355. return FALSE;
  3356. }
  3357. }
  3358. else
  3359. {
  3360. return FALSE;
  3361. }
  3362. }
  3363. else
  3364. {
  3365. CopyMemory(certCredInfo.rgbHashOfCert,
  3366. &CertHashes[item.iItem - CertBaseInComboBox],
  3367. CERT_HASH_LENGTH);
  3368. }
  3369. WCHAR *marshaledCred;
  3370. if (LocalCredMarshalCredentialW(
  3371. CertCredential,
  3372. &certCredInfo,
  3373. &marshaledCred))
  3374. {
  3375. StringCchCopyW(userName, maxChars + 1, marshaledCred);
  3376. LocalCredFree(static_cast<VOID *>(marshaledCred));
  3377. return TRUE;
  3378. }
  3379. else
  3380. {
  3381. CreduiDebugLog("CreduiCredentialControl::OnGetUserName: "
  3382. "CredMarshalCredential failed: %u\n",
  3383. GetLastError());
  3384. return FALSE;
  3385. }
  3386. }
  3387. }
  3388. //=============================================================================
  3389. // CreduiCredentialControl::OnSetPasswordA
  3390. //
  3391. // Created 06/22/2000 johnstep (John Stephens)
  3392. //=============================================================================
  3393. BOOL
  3394. CreduiCredentialControl::OnSetPasswordA(
  3395. CHAR *passwordA
  3396. )
  3397. {
  3398. return SetWindowTextA(PasswordControlWindow, passwordA);
  3399. };
  3400. //=============================================================================
  3401. // CreduiCredentialControl::OnSetPassword
  3402. //
  3403. // Created 06/22/2000 johnstep (John Stephens)
  3404. //=============================================================================
  3405. BOOL
  3406. CreduiCredentialControl::OnSetPassword(
  3407. WCHAR *password
  3408. )
  3409. {
  3410. return SetWindowText(PasswordControlWindow, password);
  3411. };
  3412. //=============================================================================
  3413. // CreduiCredentialControl::OnGetPasswordA
  3414. //
  3415. // Created 06/22/2000 johnstep (John Stephens)
  3416. //=============================================================================
  3417. BOOL
  3418. CreduiCredentialControl::OnGetPasswordA(
  3419. CHAR *passwordA,
  3420. ULONG maxChars
  3421. )
  3422. {
  3423. if (DisabledControlMask & DISABLED_CONTROL_PASSWORD)
  3424. {
  3425. return FALSE;
  3426. }
  3427. SetLastError(0);
  3428. return (GetWindowTextA(PasswordControlWindow,
  3429. passwordA,
  3430. maxChars + 1) > 0) ||
  3431. (GetLastError() == ERROR_SUCCESS);
  3432. };
  3433. //=============================================================================
  3434. // CreduiCredentialControl::OnGetPassword
  3435. //
  3436. // Created 06/22/2000 johnstep (John Stephens)
  3437. //=============================================================================
  3438. BOOL
  3439. CreduiCredentialControl::OnGetPassword(
  3440. WCHAR *password,
  3441. ULONG maxChars
  3442. )
  3443. {
  3444. if (DisabledControlMask & DISABLED_CONTROL_PASSWORD)
  3445. {
  3446. return FALSE;
  3447. }
  3448. SetLastError(0);
  3449. return ((GetWindowText(PasswordControlWindow,
  3450. password,
  3451. maxChars + 1) > 0) ||
  3452. (GetLastError() == ERROR_SUCCESS)
  3453. );
  3454. };
  3455. //=============================================================================
  3456. // CreduiCredentialControl::OnGetUserNameLength
  3457. //
  3458. // Created 07/19/2000 johnstep (John Stephens)
  3459. //=============================================================================
  3460. LONG
  3461. CreduiCredentialControl::OnGetUserNameLength()
  3462. {
  3463. COMBOBOXEXITEM item;
  3464. if (UserNameCertHash != NULL)
  3465. {
  3466. return -1;
  3467. }
  3468. item.iItem = SendMessage(UserNameControlWindow, CB_GETCURSEL, 0, 0);
  3469. // If this is not a certificate, it's easy:
  3470. if ((item.iItem == CB_ERR) || (item.iItem < CertBaseInComboBox))
  3471. {
  3472. return GetWindowTextLength(UserNameControlWindow);
  3473. }
  3474. else
  3475. {
  3476. WCHAR userName[CREDUI_MAX_USERNAME_LENGTH + 1];
  3477. if (OnGetUserName(userName, CREDUI_MAX_USERNAME_LENGTH))
  3478. {
  3479. return wcslen(userName);
  3480. }
  3481. else
  3482. {
  3483. return -1;
  3484. }
  3485. }
  3486. }
  3487. //=============================================================================
  3488. // CreduiCredentialControl::OnShowBalloonA
  3489. //
  3490. // Created 06/23/2000 johnstep (John Stephens)
  3491. //=============================================================================
  3492. BOOL
  3493. CreduiCredentialControl::OnShowBalloonA(
  3494. CREDUI_BALLOONA *balloonA
  3495. )
  3496. {
  3497. // If NULL was passed, this means to hide the balloon:
  3498. if (balloonA == NULL)
  3499. {
  3500. if (BalloonTip.IsVisible())
  3501. {
  3502. BalloonTip.Hide();
  3503. }
  3504. return TRUE;
  3505. }
  3506. // Argument validation, should match OnShowBalloon:
  3507. if ((balloonA->dwVersion != 1) ||
  3508. (balloonA->pszTitleText == NULL) ||
  3509. (balloonA->pszMessageText == NULL))
  3510. {
  3511. return FALSE;
  3512. }
  3513. if ((balloonA->pszTitleText[0] == '\0') ||
  3514. (balloonA->pszMessageText[0] == '\0'))
  3515. {
  3516. return FALSE;
  3517. }
  3518. BOOL success = FALSE;
  3519. CREDUI_BALLOON balloon;
  3520. balloon.dwVersion = balloonA->dwVersion;
  3521. balloon.iControl = balloonA->iControl;
  3522. balloon.iIcon = balloonA->iIcon;
  3523. INT titleTextSize =
  3524. MultiByteToWideChar(CP_ACP,
  3525. 0,
  3526. balloonA->pszTitleText,
  3527. -1,
  3528. NULL,
  3529. 0);
  3530. INT messageTextSize =
  3531. MultiByteToWideChar(CP_ACP,
  3532. 0,
  3533. balloonA->pszMessageText,
  3534. -1,
  3535. NULL,
  3536. 0);
  3537. if ((titleTextSize != 0) && (messageTextSize != 0))
  3538. {
  3539. balloon.pszTitleText = new WCHAR[titleTextSize];
  3540. if (balloon.pszTitleText != NULL)
  3541. {
  3542. if (MultiByteToWideChar(CP_ACP,
  3543. 0,
  3544. balloonA->pszTitleText,
  3545. -1,
  3546. balloon.pszTitleText,
  3547. titleTextSize) > 0)
  3548. {
  3549. balloon.pszMessageText = new WCHAR[messageTextSize];
  3550. if (balloon.pszMessageText != NULL)
  3551. {
  3552. if (MultiByteToWideChar(CP_ACP,
  3553. 0,
  3554. balloonA->pszMessageText,
  3555. -1,
  3556. balloon.pszMessageText,
  3557. messageTextSize) > 0)
  3558. {
  3559. success = OnShowBalloon(&balloon);
  3560. }
  3561. delete [] balloon.pszMessageText;
  3562. }
  3563. }
  3564. delete [] balloon.pszTitleText;
  3565. }
  3566. }
  3567. return success;
  3568. };
  3569. //=============================================================================
  3570. // CreduiCredentialControl::OnShowBalloon
  3571. //
  3572. // Created 06/23/2000 johnstep (John Stephens)
  3573. //=============================================================================
  3574. BOOL
  3575. CreduiCredentialControl::OnShowBalloon(
  3576. CREDUI_BALLOON *balloon
  3577. )
  3578. {
  3579. // If NULL was passed, this means to hide the balloon:
  3580. if (balloon == NULL)
  3581. {
  3582. if (BalloonTip.IsVisible())
  3583. {
  3584. BalloonTip.Hide();
  3585. }
  3586. return TRUE;
  3587. }
  3588. // Argument validation:
  3589. if ((balloon->dwVersion != 1) ||
  3590. (balloon->pszTitleText == NULL) ||
  3591. (balloon->pszMessageText == NULL))
  3592. {
  3593. return FALSE;
  3594. }
  3595. if ((balloon->pszTitleText[0] == L'\0') ||
  3596. (balloon->pszMessageText[0] == L'\0'))
  3597. {
  3598. return FALSE;
  3599. }
  3600. StringCchCopyW(
  3601. CreduiCustomTipInfo.Title,
  3602. RTL_NUMBER_OF(CreduiCustomTipTitle),
  3603. balloon->pszTitleText);
  3604. StringCchCopyW(
  3605. CreduiCustomTipInfo.Text,
  3606. RTL_NUMBER_OF(CreduiCustomTipMessage),
  3607. balloon->pszMessageText);
  3608. CreduiCustomTipInfo.Icon = balloon->iIcon;
  3609. BalloonTip.SetInfo(
  3610. (balloon->iControl == CREDUI_CONTROL_PASSWORD) ?
  3611. PasswordControlWindow : UserNameControlWindow,
  3612. &CreduiCustomTipInfo);
  3613. BalloonTip.Show();
  3614. return TRUE;
  3615. };
  3616. //=============================================================================
  3617. // CreduiCredentialControl::OnUserNameSelectionChange
  3618. //
  3619. // Created 06/21/2000 johnstep (John Stephens)
  3620. //=============================================================================
  3621. VOID
  3622. CreduiCredentialControl::OnUserNameSelectionChange()
  3623. {
  3624. COMBOBOXEXITEM item;
  3625. LRESULT current;
  3626. // Delete the user name certificate hash if the user has changed the
  3627. // selection:
  3628. delete [] UserNameCertHash;
  3629. UserNameCertHash = NULL;
  3630. current = SendMessage(UserNameControlWindow,
  3631. CB_GETCURSEL, 0, 0);
  3632. item.mask = CBEIF_IMAGE;
  3633. item.iItem = current;
  3634. SendMessage(UserNameControlWindow, CBEM_GETITEM,
  3635. 0, reinterpret_cast<LPARAM>(&item));
  3636. if (current < CertBaseInComboBox)
  3637. {
  3638. EnableWindow(ViewCertControlWindow, FALSE);
  3639. DisabledControlMask |= DISABLED_CONTROL_VIEW;
  3640. SetWindowText(
  3641. PasswordStaticWindow,
  3642. CreduiStrings.PasswordStatic);
  3643. EnableWindow(PasswordControlWindow, TRUE);
  3644. EnableWindow(PasswordStaticWindow, TRUE);
  3645. DisabledControlMask &= ~DISABLED_CONTROL_PASSWORD;
  3646. WCHAR* pUserNameLabel;
  3647. if ( IsPassport )
  3648. pUserNameLabel = CreduiStrings.EmailName;
  3649. else
  3650. pUserNameLabel = CreduiStrings.UserNameStatic;
  3651. SetWindowText(
  3652. UserNameStaticWindow,
  3653. pUserNameLabel);
  3654. if (SaveControlWindow != NULL)
  3655. {
  3656. EnableWindow(SaveControlWindow, TRUE);
  3657. DisabledControlMask &= ~DISABLED_CONTROL_SAVE;
  3658. }
  3659. }
  3660. else
  3661. {
  3662. SetWindowText(
  3663. PasswordStaticWindow,
  3664. CreduiStrings.PinStatic);
  3665. if (item.iImage != IMAGE_SMART_CARD_MISSING)
  3666. {
  3667. EnableWindow(ViewCertControlWindow, TRUE);
  3668. DisabledControlMask &= ~DISABLED_CONTROL_VIEW;
  3669. }
  3670. else
  3671. {
  3672. EnableWindow(ViewCertControlWindow, FALSE);
  3673. DisabledControlMask |= DISABLED_CONTROL_VIEW;
  3674. }
  3675. #if 0
  3676. // set password control empty on cert name change now only occurs
  3677. // if user selects different dropdown item (or types new)
  3678. IsChangingPassword = TRUE;
  3679. SetWindowText(PasswordControlWindow, NULL);
  3680. IsChangingPassword = FALSE;
  3681. #endif
  3682. if (current >= SmartCardBaseInComboBox)
  3683. {
  3684. EnableWindow(PasswordControlWindow, TRUE);
  3685. EnableWindow(PasswordStaticWindow, TRUE);
  3686. DisabledControlMask &= ~DISABLED_CONTROL_PASSWORD;
  3687. }
  3688. else
  3689. {
  3690. EnableWindow(PasswordControlWindow, FALSE);
  3691. EnableWindow(PasswordStaticWindow, FALSE);
  3692. DisabledControlMask |= DISABLED_CONTROL_PASSWORD;
  3693. }
  3694. SetWindowText(
  3695. UserNameStaticWindow,
  3696. item.iImage >= IMAGE_SMART_CARD ?
  3697. CreduiStrings.SmartCardStatic :
  3698. CreduiStrings.CertificateStatic);
  3699. #if 0
  3700. if (SaveControlWindow != NULL)
  3701. {
  3702. EnableWindow(SaveControlWindow, FALSE);
  3703. DisabledControlMask |= DISABLED_CONTROL_SAVE;
  3704. }
  3705. #endif
  3706. }
  3707. }
  3708. //=============================================================================
  3709. // CreduiCredentialControl::MessageHandler
  3710. //
  3711. // Called from the control window callback to handle the window messages.
  3712. //
  3713. // Arguments:
  3714. // message (in)
  3715. // wParam (in)
  3716. // lParam (in)
  3717. //
  3718. // Created 06/20/2000 johnstep (John Stephens)
  3719. //=============================================================================
  3720. LRESULT
  3721. CreduiCredentialControl::MessageHandler(
  3722. UINT message,
  3723. WPARAM wParam,
  3724. LPARAM lParam
  3725. )
  3726. {
  3727. // Handle WM_NCDESTROY whether initialized or not:
  3728. if (message == WM_NCDESTROY)
  3729. {
  3730. delete this;
  3731. return 0;
  3732. }
  3733. // If not initialized, only handle CRM_INITSTYLE:
  3734. if (!IsInitialized)
  3735. {
  3736. if (message == CRM_INITSTYLE)
  3737. {
  3738. wParam &= CRS_USERNAMES |
  3739. CRS_CERTIFICATES |
  3740. CRS_SMARTCARDS |
  3741. CRS_ADMINISTRATORS |
  3742. CRS_PREFILLADMIN |
  3743. CRS_COMPLETEUSERNAME |
  3744. CRS_SAVECHECK |
  3745. CRS_KEEPUSERNAME;
  3746. if (wParam != 0)
  3747. {
  3748. Style |= wParam;
  3749. SetWindowLong(Window,
  3750. GWL_STYLE,
  3751. GetWindowLong(Window, GWL_STYLE) | Style);
  3752. DoingCommandLine = (BOOL) lParam;
  3753. return InitWindow();
  3754. }
  3755. return FALSE;
  3756. }
  3757. else
  3758. {
  3759. return DefWindowProc(Window, message, wParam, lParam);
  3760. }
  3761. }
  3762. else if (message == WM_ENABLE)
  3763. {
  3764. Enable((BOOL) wParam);
  3765. }
  3766. // Always handle smart card messages, if support is available:
  3767. if (ScardUiHandle != NULL)
  3768. {
  3769. // This function call will return TRUE if the message was handled:
  3770. if (HandleSmartCardMessages(
  3771. message,
  3772. reinterpret_cast<CERT_ENUM *>(wParam)))
  3773. {
  3774. return 0;
  3775. }
  3776. }
  3777. switch (message)
  3778. {
  3779. case CRM_SETUSERNAMEMAX:
  3780. SendMessage(UserNameControlWindow, CB_LIMITTEXT, wParam, 0);
  3781. return TRUE;
  3782. case CRM_SETPASSWORDMAX:
  3783. SendMessage(PasswordControlWindow, EM_LIMITTEXT, wParam, 0);
  3784. return TRUE;
  3785. case CRM_DISABLEUSERNAME:
  3786. {
  3787. DisabledControlMask |= DISABLED_CONTROL_USERNAME;
  3788. EnableWindow(UserNameControlWindow,FALSE);
  3789. EnableWindow(UserNameStaticWindow,FALSE);
  3790. return TRUE;
  3791. }
  3792. case CRM_ENABLEUSERNAME:
  3793. {
  3794. DisabledControlMask &= ~DISABLED_CONTROL_USERNAME;
  3795. EnableWindow(UserNameControlWindow,TRUE);
  3796. EnableWindow(UserNameStaticWindow,TRUE);
  3797. return TRUE;
  3798. }
  3799. case CRM_GETUSERNAMEMAX:
  3800. return
  3801. SendMessage(
  3802. reinterpret_cast<HWND>(
  3803. SendMessage(Window, CBEM_GETEDITCONTROL, 0, 0)),
  3804. EM_GETLIMITTEXT,
  3805. 0,
  3806. 0);
  3807. case CRM_GETPASSWORDMAX:
  3808. return SendMessage(UserNameControlWindow, EM_GETLIMITTEXT, 0, 0);
  3809. case CRM_SETUSERNAMEA:
  3810. return OnSetUserNameA(reinterpret_cast<CHAR *>(lParam));
  3811. case CRM_SETUSERNAMEW:
  3812. return OnSetUserName(reinterpret_cast<WCHAR *>(lParam));
  3813. case CRM_GETUSERNAMEA:
  3814. return OnGetUserNameA(reinterpret_cast<CHAR *>(lParam), (ULONG) wParam);
  3815. case CRM_GETUSERNAMEW:
  3816. return OnGetUserName(reinterpret_cast<WCHAR *>(lParam), (ULONG) wParam);
  3817. case CRM_SETPASSWORDA:
  3818. return OnSetPasswordA(reinterpret_cast<CHAR *>(lParam));
  3819. case CRM_SETPASSWORDW:
  3820. return OnSetPassword(reinterpret_cast<WCHAR *>(lParam));
  3821. case CRM_GETPASSWORDA:
  3822. return OnGetPasswordA(reinterpret_cast<CHAR *>(lParam), (ULONG) wParam);
  3823. case CRM_GETPASSWORDW:
  3824. return OnGetPassword(reinterpret_cast<WCHAR *>(lParam), (ULONG) wParam);
  3825. case CRM_GETUSERNAMELENGTH:
  3826. return OnGetUserNameLength();
  3827. case CRM_GETPASSWORDLENGTH:
  3828. if (IsWindowEnabled(PasswordControlWindow))
  3829. {
  3830. return GetWindowTextLength(PasswordControlWindow);
  3831. }
  3832. return -1;
  3833. case CRM_SETFOCUS:
  3834. if ( DoingCommandLine ) {
  3835. return 0;
  3836. }
  3837. switch (wParam)
  3838. {
  3839. case CREDUI_CONTROL_USERNAME:
  3840. SetFocus(UserNameControlWindow);
  3841. return TRUE;
  3842. case CREDUI_CONTROL_PASSWORD:
  3843. if (IsWindowEnabled(PasswordControlWindow))
  3844. {
  3845. SetFocus(PasswordControlWindow);
  3846. // NOTE: Is it OK to always select the entire password text
  3847. // on this explicit set focus message?
  3848. SendMessage(PasswordControlWindow, EM_SETSEL, 0, -1);
  3849. return TRUE;
  3850. }
  3851. break;
  3852. }
  3853. return 0;
  3854. case CRM_SHOWBALLOONA:
  3855. return OnShowBalloonA(reinterpret_cast<CREDUI_BALLOONA *>(lParam));
  3856. case CRM_SHOWBALLOONW:
  3857. return OnShowBalloon(reinterpret_cast<CREDUI_BALLOON *>(lParam));
  3858. case CRM_GETMINSIZE:
  3859. SIZE *minSize;
  3860. minSize = reinterpret_cast<SIZE *>(lParam);
  3861. if (minSize != NULL)
  3862. {
  3863. minSize->cx = CREDUI_CONTROL_MIN_WIDTH;
  3864. minSize->cy = CREDUI_CONTROL_MIN_HEIGHT;
  3865. if (Style & CRS_SAVECHECK )
  3866. {
  3867. minSize->cy += CREDUI_CONTROL_ADD_SAVE;
  3868. }
  3869. return TRUE;
  3870. }
  3871. return FALSE;
  3872. case CRM_SETCHECK:
  3873. switch (wParam)
  3874. {
  3875. case CREDUI_CONTROL_SAVE:
  3876. if ((Style & CRS_SAVECHECK ) &&
  3877. IsWindowEnabled(SaveControlWindow))
  3878. {
  3879. CheckDlgButton(Window, IDC_SAVE,
  3880. lParam ? BST_CHECKED : BST_UNCHECKED);
  3881. return TRUE;
  3882. }
  3883. break;
  3884. }
  3885. return FALSE;
  3886. case CRM_GETCHECK:
  3887. switch (wParam)
  3888. {
  3889. case CREDUI_CONTROL_SAVE:
  3890. return
  3891. (Style & CRS_SAVECHECK ) &&
  3892. IsWindowEnabled(SaveControlWindow) &&
  3893. IsDlgButtonChecked(Window, IDC_SAVE);
  3894. default:
  3895. return FALSE;
  3896. }
  3897. case CRM_DOCMDLINE:
  3898. ASSERT( DoingCommandLine );
  3899. //
  3900. // For smartcards,
  3901. // just start the timer and we'll prompt when the timer has gone off.
  3902. //
  3903. TargetName = (LPWSTR)lParam;
  3904. if ( Style & CRS_SMARTCARDS) {
  3905. DWORD WinStatus;
  3906. Heartbeats = 0;
  3907. {
  3908. WCHAR szMsg[CREDUI_MAX_CMDLINE_MSG_LENGTH + 1];
  3909. szMsg[0] = 0;
  3910. FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  3911. CreduiInstance,
  3912. IDS_READING_SMARTCARDS,
  3913. 0,
  3914. szMsg,
  3915. CREDUI_MAX_CMDLINE_MSG_LENGTH,
  3916. NULL);
  3917. CredPutStdout(szMsg);
  3918. }
  3919. if ( SetTimer ( Window, CREDUI_HEARTBEAT_TIMER, CREDUI_HEARTBEAT_TIMER_VALUE, NULL ) == 0 ) {
  3920. // bail out of our wait loop if we couldn't set a timer
  3921. return GetLastError();
  3922. }
  3923. //
  3924. // For passwords,
  3925. // just do the prompt to save.
  3926. //
  3927. } else {
  3928. CmdlineSavePrompt();
  3929. PostQuitMessage( NO_ERROR );
  3930. }
  3931. return NO_ERROR;
  3932. case WM_HELP:
  3933. return OnHelpInfo(lParam);
  3934. case WM_SETFONT:
  3935. // Forward font setting from dialog to each control, except the
  3936. // password control since we use a special font there:
  3937. if (UserNameStaticWindow != NULL)
  3938. {
  3939. SendMessage(UserNameStaticWindow, message, wParam, lParam);
  3940. }
  3941. if (UserNameControlWindow != NULL)
  3942. {
  3943. SendMessage(UserNameControlWindow, message, wParam, lParam);
  3944. }
  3945. if (ViewCertControlWindow != NULL)
  3946. {
  3947. SendMessage(ViewCertControlWindow, message, wParam, lParam);
  3948. }
  3949. if (PasswordStaticWindow != NULL)
  3950. {
  3951. SendMessage(PasswordStaticWindow, message, wParam, lParam);
  3952. }
  3953. if (PasswordControlWindow != NULL)
  3954. {
  3955. SendMessage(PasswordControlWindow, message, wParam, lParam);
  3956. }
  3957. if (SaveControlWindow != NULL)
  3958. {
  3959. SendMessage(SaveControlWindow, message, wParam, lParam);
  3960. }
  3961. break;
  3962. case WM_COMMAND:
  3963. switch (LOWORD(wParam))
  3964. {
  3965. case IDC_VIEW_CERT:
  3966. ViewCertificate((INT)
  3967. SendMessage(UserNameControlWindow,
  3968. CB_GETCURSEL, 0, 0));
  3969. return 0;
  3970. case IDC_PASSWORD:
  3971. if (HIWORD(wParam) == EN_CHANGE)
  3972. {
  3973. // Always send the change message?
  3974. SendMessage(
  3975. GetParent(Window),
  3976. WM_COMMAND,
  3977. MAKELONG(GetWindowLongPtr(Window, GWLP_ID),
  3978. CRN_PASSWORDCHANGE),
  3979. reinterpret_cast<LPARAM>(Window));
  3980. }
  3981. return 0;
  3982. case IDC_USERNAME:
  3983. switch (HIWORD(wParam))
  3984. {
  3985. case CBN_EDITCHANGE:
  3986. case CBN_DROPDOWN:
  3987. case CBN_KILLFOCUS:
  3988. if ((HIWORD(wParam) != CBN_EDITCHANGE) || !IsChangingUserName)
  3989. {
  3990. if (BalloonTip.IsVisible())
  3991. {
  3992. BalloonTip.Hide();
  3993. }
  3994. }
  3995. if (HIWORD(wParam) == CBN_EDITCHANGE)
  3996. {
  3997. // Always send the change message?
  3998. SendMessage(
  3999. GetParent(Window),
  4000. WM_COMMAND,
  4001. MAKELONG(GetWindowLongPtr(Window, GWLP_ID),
  4002. CRN_USERNAMECHANGE),
  4003. reinterpret_cast<LPARAM>(Window));
  4004. // If the name has changed as a result of user editing,
  4005. // reset to user name settings:
  4006. BOOL isDropped = (BOOL)
  4007. SendMessage(UserNameControlWindow,
  4008. CB_GETDROPPEDSTATE, 0, 0);
  4009. if (isDropped)
  4010. {
  4011. OnUserNameSelectionChange();
  4012. RECT rect;
  4013. GetClientRect(UserNameControlWindow, &rect);
  4014. InvalidateRect(UserNameControlWindow, &rect, FALSE);
  4015. SendMessage(Window,
  4016. CB_SETCURSEL,
  4017. SendMessage(Window, CB_GETCURSEL, 0, 0),
  4018. 0);
  4019. return 0;
  4020. }
  4021. if (IsChangingUserName)
  4022. {
  4023. return 0;
  4024. }
  4025. // we are seeking a cert or have selected a reader, and the droplist is
  4026. // not dropped.
  4027. if (((UserNameCertHash != NULL) ||
  4028. (SendMessage(UserNameControlWindow,
  4029. CB_GETCURSEL, 0, 0) >= CertBaseInComboBox)) &&
  4030. !isDropped)
  4031. {
  4032. delete [] UserNameCertHash;
  4033. UserNameCertHash = NULL;
  4034. if (!SendMessage(UserNameControlWindow,
  4035. CB_GETDROPPEDSTATE, 0, 0))
  4036. {
  4037. SetFocus(UserNameControlWindow);
  4038. if (SendMessage(UserNameControlWindow,
  4039. CB_GETCURSEL, 0, 0) == CB_ERR)
  4040. {
  4041. // user is typing a new user name - clear the password
  4042. IsChangingUserName = TRUE;
  4043. UserNameComboBox.Update(
  4044. -1,
  4045. L"",
  4046. IMAGE_USERNAME);
  4047. IsChangingUserName = FALSE;
  4048. IsChangingPassword = TRUE;
  4049. SetWindowText(PasswordControlWindow, NULL);
  4050. IsChangingPassword = FALSE;
  4051. OnUserNameSelectionChange();
  4052. }
  4053. }
  4054. }
  4055. }
  4056. if (HIWORD(wParam) == CBN_DROPDOWN)
  4057. {
  4058. if (UserNameCertHash != NULL)
  4059. {
  4060. delete [] UserNameCertHash;
  4061. UserNameCertHash = NULL;
  4062. IsChangingUserName = TRUE;
  4063. UserNameComboBox.Update(
  4064. -1,
  4065. L"",
  4066. IMAGE_USERNAME);
  4067. IsChangingUserName = FALSE;
  4068. IsChangingPassword = TRUE;
  4069. SetWindowText(PasswordControlWindow, NULL);
  4070. IsChangingPassword = FALSE;
  4071. OnUserNameSelectionChange();
  4072. }
  4073. }
  4074. return 0;
  4075. case CBN_SELCHANGE:
  4076. // force password clear on any select of an item from the dropdown.
  4077. IsChangingPassword = TRUE;
  4078. SetWindowText(PasswordControlWindow, NULL);
  4079. IsChangingPassword = FALSE;
  4080. OnUserNameSelectionChange();
  4081. return 0;
  4082. }
  4083. break;
  4084. case IDC_SAVE:
  4085. if (HIWORD(wParam) == BN_CLICKED)
  4086. {
  4087. return TRUE;
  4088. }
  4089. break;
  4090. }
  4091. break;
  4092. case WM_PAINT:
  4093. if (FirstPaint && GetUpdateRect(Window, NULL, FALSE))
  4094. {
  4095. FirstPaint = FALSE;
  4096. if (ShowBalloonTip)
  4097. {
  4098. ShowBalloonTip = FALSE;
  4099. BalloonTip.Show();
  4100. }
  4101. }
  4102. break;
  4103. case WM_TIMER:
  4104. if ( wParam == CREDUI_HEARTBEAT_TIMER )
  4105. {
  4106. Heartbeats++;
  4107. #ifdef SCARDREPORTS
  4108. CreduiDebugLog("CREDUI: thump thump\n",this->Window);
  4109. #endif
  4110. //
  4111. // If we've waited long enough,
  4112. // or all cards have been read,
  4113. // process the cards.
  4114. //
  4115. if ( Heartbeats > CREDUI_MAX_HEARTBEATS ||
  4116. ( Heartbeats > CREDUI_TIMEOUT_HEARTBEATS && SmartCardReadCount == 0 )) {
  4117. #ifdef SCARDREPORTS
  4118. CreduiDebugLog("CREDUI: Heartbeat timeout\n",this->Window);
  4119. #endif
  4120. fputs( "\n", stdout );
  4121. KillTimer ( Window, CREDUI_HEARTBEAT_TIMER );
  4122. CmdlineSmartCardPrompt();
  4123. //
  4124. // If we're going to wait longer,
  4125. // let the user know we're making progress.
  4126. //
  4127. } else {
  4128. fputs( ".", stdout );
  4129. }
  4130. }
  4131. break;
  4132. case WM_DESTROY:
  4133. if (PasswordControlWindow != NULL)
  4134. {
  4135. SetWindowText(PasswordControlWindow, NULL);
  4136. DestroyWindow(PasswordControlWindow);
  4137. PasswordControlWindow = NULL;
  4138. }
  4139. if (PasswordStaticWindow != NULL)
  4140. {
  4141. DestroyWindow(PasswordStaticWindow);
  4142. PasswordStaticWindow = NULL;
  4143. }
  4144. if (ViewCertControlWindow != NULL)
  4145. {
  4146. DestroyWindow(ViewCertControlWindow);
  4147. ViewCertControlWindow = NULL;
  4148. }
  4149. if (UserNameControlWindow != NULL)
  4150. {
  4151. DestroyWindow(UserNameControlWindow);
  4152. UserNameControlWindow = NULL;
  4153. }
  4154. if (UserNameStaticWindow != NULL)
  4155. {
  4156. DestroyWindow(UserNameStaticWindow);
  4157. UserNameStaticWindow = NULL;
  4158. }
  4159. if (ScardUiHandle != NULL)
  4160. {
  4161. #ifdef SCARDREPORTS
  4162. CreduiDebugLog("CREDUI: Call to SCardUIExit\n");
  4163. #endif
  4164. SCardUIExit(ScardUiHandle);
  4165. ScardUiHandle = NULL;
  4166. }
  4167. if (UserNameCertHash != NULL)
  4168. {
  4169. delete [] UserNameCertHash;
  4170. UserNameCertHash = NULL;
  4171. }
  4172. if (CertCount > 0)
  4173. {
  4174. ASSERT(CertHashes != NULL);
  4175. delete [] CertHashes;
  4176. CertHashes = NULL;
  4177. CertCount = 0;
  4178. }
  4179. delete InitialUserName;
  4180. InitialUserName = NULL;
  4181. // Only call CoUninitialize if we successfully initialized for STA:
  4182. if (IsAutoComplete)
  4183. {
  4184. CoUninitialize();
  4185. }
  4186. return 0;
  4187. }
  4188. return DefWindowProc(Window, message, wParam, lParam);
  4189. }
  4190. BOOL CreduiCredentialControl::GetSmartCardInfo(
  4191. IN DWORD SmartCardIndex,
  4192. IN DWORD BufferLength,
  4193. OUT LPWSTR Buffer,
  4194. OUT BOOL *IsACard,
  4195. OUT BOOL *IsValid,
  4196. OUT CERT_ENUM **CertEnum OPTIONAL
  4197. )
  4198. /*++
  4199. Routine Description:
  4200. Routine to get the smart card info for a smart card in the combo box
  4201. Arguments:
  4202. SmartCardIndex - Index of the smart card relative to SmartCardBaseInComboBox
  4203. BufferLength - Specifies the length of Buffer (in characters)
  4204. Buffer - Specifies the buffer to return the text for the smart card
  4205. IsValid - Return TRUE if the smartcard is valid
  4206. Returns FALSE otherwise
  4207. CertEnum - If specified, returns the description of the cert on the smartcard
  4208. This field is should be ignore if IsValid is returns false
  4209. Return Values:
  4210. Returns TRUE if Buffer and IsValid are filled in.
  4211. --*/
  4212. {
  4213. COMBOBOXEXITEM item;
  4214. //
  4215. // Get the item from the control
  4216. //
  4217. item.iItem = SmartCardBaseInComboBox + SmartCardIndex;
  4218. item.mask = CBEIF_IMAGE | CBEIF_TEXT;
  4219. item.pszText = Buffer;
  4220. item.cchTextMax = BufferLength;
  4221. if (!SendMessage(UserNameControlWindow,
  4222. CBEM_GETITEM,
  4223. 0,
  4224. reinterpret_cast<LPARAM>(&item)))
  4225. {
  4226. return FALSE;
  4227. }
  4228. *IsValid = (item.iImage == IMAGE_SMART_CARD);
  4229. *IsACard = (*IsValid || (item.iImage == IMAGE_SMART_CARD_EXPIRED));
  4230. if ( CertEnum != NULL) {
  4231. if ( *IsValid ) {
  4232. *CertEnum = (CERT_ENUM *) SendMessage( UserNameControlWindow,
  4233. CB_GETITEMDATA, item.iItem, 0);
  4234. // NOTE: Consider more complete error handling here.
  4235. if ( *CertEnum == NULL) {
  4236. return FALSE;
  4237. }
  4238. }
  4239. }
  4240. return TRUE;
  4241. }
  4242. LPWSTR CreduiCredentialControl::MatchSmartCard(
  4243. IN DWORD SmartCardCount,
  4244. IN LPWSTR UserName,
  4245. OUT LPDWORD RetCertIndex,
  4246. OUT CERT_ENUM **RetCertEnum
  4247. )
  4248. /*++
  4249. Routine Description:
  4250. Returns the smart card that matches UserName.
  4251. Arguments:
  4252. SmartCardCount - specifies the number of smart cards to search
  4253. UserName - specifies the user name to match
  4254. RetCertIndex - returns an index to the found smart card.
  4255. RetCertEnum - returns the description of the cert on the smartcard
  4256. Return Values:
  4257. Returns NULL if UserName matches one of the smart cards
  4258. On failure, returns a printf-style format string describing the error
  4259. --*/
  4260. {
  4261. WCHAR SmartCardText[CREDUI_MAX_USERNAME_LENGTH + 1];
  4262. DWORD i;
  4263. BOOL SmartCardValid;
  4264. BOOL IsACard;
  4265. CERT_ENUM *CertEnum;
  4266. CERT_ENUM *SavedCertEnum = NULL;
  4267. DWORD SavedCertIndex = 0;
  4268. //
  4269. // Loop through the list of smart cards seeing if we see a match
  4270. //
  4271. for ( i=0; i<SmartCardCount; i++ ) {
  4272. if ( !GetSmartCardInfo( i, CREDUI_MAX_USERNAME_LENGTH, SmartCardText, &IsACard, &SmartCardValid, &CertEnum ) ) {
  4273. //return CreduiStrings.NoUsernameMatch;
  4274. return (LPWSTR) IDS_NO_USERNAME_MATCH;
  4275. }
  4276. if ( !SmartCardValid ) {
  4277. continue;
  4278. }
  4279. //
  4280. // If the username is marshaled,
  4281. // compare the marshaled strings.
  4282. //
  4283. if ( LocalCredIsMarshaledCredentialW( UserName ) ) {
  4284. WCHAR szTestmarshall[CREDUI_MAX_USERNAME_LENGTH+1];
  4285. // see if this is the marshalled cred
  4286. if ( CredUIMarshallNode ( CertEnum, szTestmarshall ) )
  4287. {
  4288. if ( wcscmp ( szTestmarshall, UserName) == 0 ) {
  4289. *RetCertEnum = CertEnum;
  4290. *RetCertIndex = i;
  4291. return NULL;
  4292. }
  4293. }
  4294. //
  4295. // If the username is not marshalled,
  4296. // just match a substring of the name
  4297. //
  4298. } else if ( LookForUserNameMatch ( UserName, SmartCardText ) ) {
  4299. //
  4300. // If we already found a match,
  4301. // complain about the ambiguity.
  4302. //
  4303. if ( SavedCertEnum != NULL ) {
  4304. //return CreduiStrings.ManyUsernameMatch;
  4305. return (LPWSTR) IDS_MANY_USERNAME_MATCH;
  4306. }
  4307. SavedCertEnum = CertEnum;
  4308. SavedCertIndex = i;
  4309. }
  4310. }
  4311. //
  4312. // If we didn't find a match,
  4313. // fail
  4314. //
  4315. if ( SavedCertEnum == NULL) {
  4316. //return CreduiStrings.NoUsernameMatch;
  4317. return (LPWSTR) IDS_NO_USERNAME_MATCH;
  4318. }
  4319. *RetCertEnum = SavedCertEnum;
  4320. *RetCertIndex = SavedCertIndex;
  4321. return NULL;
  4322. }
  4323. void CreduiCredentialControl::CmdlineSmartCardPrompt()
  4324. /*++
  4325. Routine Description:
  4326. Command line code to select a smartcard from the list of ones available.
  4327. Post a WM_QUIT message to terminate message processing. The status of the operation
  4328. is returned in wParam.
  4329. UserName and Password strings set in their respective controls.
  4330. Arguments:
  4331. None
  4332. Return Values:
  4333. None
  4334. --*/
  4335. {
  4336. DWORD WinStatus;
  4337. LONG ComboBoxItemCount;
  4338. DWORD SmartCardCount;
  4339. DWORD ValidSmartCardCount = 0;
  4340. DWORD InvalidSmartCardCount = 0;
  4341. DWORD KnownGoodCard = 0;
  4342. DWORD i;
  4343. DWORD_PTR rgarg[2]; // at most 2 substitution arguments
  4344. WCHAR szMsg[CREDUI_MAX_CMDLINE_MSG_LENGTH + 1];
  4345. WCHAR UserName[CREDUI_MAX_USERNAME_LENGTH + 1];
  4346. WCHAR Password[CREDUI_MAX_PASSWORD_LENGTH + 1];
  4347. WCHAR SmartCardText[CREDUI_MAX_USERNAME_LENGTH + 1];
  4348. BOOL SmartCardValid;
  4349. BOOL IsACard;
  4350. CERT_ENUM *SavedCertEnum = NULL;
  4351. DWORD SavedCertIndex = 0;
  4352. LPWSTR ErrorString = NULL;
  4353. //
  4354. // Compute the number of smart card entries
  4355. //
  4356. ComboBoxItemCount = (LONG) SendMessage(UserNameControlWindow, CB_GETCOUNT, 0, 0);
  4357. if ( ComboBoxItemCount == CB_ERR ||
  4358. ComboBoxItemCount <= SmartCardBaseInComboBox ) {
  4359. // Didn't find any smart card readers
  4360. szMsg[0] = 0;
  4361. FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  4362. CreduiInstance,
  4363. IDS_NO_READERS_FOUND,
  4364. 0,
  4365. szMsg,
  4366. CREDUI_MAX_CMDLINE_MSG_LENGTH,
  4367. NULL);
  4368. CredPutStdout(szMsg);
  4369. WinStatus = ERROR_CANCELLED;
  4370. goto Cleanup;
  4371. }
  4372. SmartCardCount = ComboBoxItemCount - SmartCardBaseInComboBox;
  4373. //
  4374. // Get a count of the number of valid and invalid smartcards
  4375. //
  4376. for ( i=0; i<SmartCardCount; i++ ) {
  4377. if ( !GetSmartCardInfo( i, CREDUI_MAX_USERNAME_LENGTH, SmartCardText, &IsACard, &SmartCardValid, NULL ) ) {
  4378. WinStatus = ERROR_INTERNAL_ERROR;
  4379. goto Cleanup;
  4380. }
  4381. if ( SmartCardValid ) {
  4382. ValidSmartCardCount ++;
  4383. KnownGoodCard = i;
  4384. } else {
  4385. InvalidSmartCardCount ++;
  4386. }
  4387. }
  4388. //
  4389. // Get the username passed into the API
  4390. //
  4391. // Can't do a GetWindowText( UserNameControlWindow ) since the cert control has
  4392. // a non-editable window so we can't set the window text
  4393. //
  4394. if ( InitialUserName != NULL) {
  4395. StringCchCopyW(UserName, RTL_NUMBER_OF(UserName), InitialUserName);
  4396. } else {
  4397. UserName[0] = '\0';
  4398. }
  4399. //
  4400. // If the caller passed a name into the API,
  4401. // check to see if the name matches one of the smart cards.
  4402. //
  4403. if ( UserName[0] != '\0' ) {
  4404. //
  4405. // Find the smartcard that matches the username
  4406. //
  4407. ErrorString = MatchSmartCard(
  4408. SmartCardCount,
  4409. UserName,
  4410. &SavedCertIndex,
  4411. &SavedCertEnum );
  4412. if ( ErrorString == NULL ) {
  4413. WinStatus = NO_ERROR;
  4414. goto Cleanup;
  4415. }
  4416. }
  4417. //
  4418. // Report any errors to the user
  4419. //
  4420. if ( InvalidSmartCardCount ) {
  4421. szMsg[0] = 0;
  4422. FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  4423. CreduiInstance,
  4424. IDS_CMDLINE_ERRORS,
  4425. 0,
  4426. szMsg,
  4427. CREDUI_MAX_CMDLINE_MSG_LENGTH,
  4428. NULL);
  4429. CredPutStdout(szMsg);
  4430. for ( i=0; i<SmartCardCount; i++ ) {
  4431. if ( !GetSmartCardInfo( i, CREDUI_MAX_USERNAME_LENGTH, SmartCardText, &IsACard, &SmartCardValid, NULL ) ) {
  4432. WinStatus = ERROR_INTERNAL_ERROR;
  4433. goto Cleanup;
  4434. }
  4435. if ( !SmartCardValid )
  4436. {
  4437. // GetSmartCardInfo() fills SmartCardText, which may include user's name
  4438. if (IsACard)
  4439. {
  4440. szMsg[0] = 0;
  4441. FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  4442. CreduiInstance,
  4443. IDS_INVALIDCERT,
  4444. 0,
  4445. szMsg,
  4446. CREDUI_MAX_CMDLINE_MSG_LENGTH,
  4447. NULL);
  4448. CredPutStdout(szMsg);
  4449. }
  4450. else
  4451. {
  4452. CredPutStdout( SmartCardText );
  4453. }
  4454. //swprintf(szMsg,CreduiStrings.CmdLineError,i+1);
  4455. szMsg[0] = 0;
  4456. INT j = i+1;
  4457. FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  4458. CreduiInstance,
  4459. IDS_CMDLINE_ERROR,
  4460. 0,
  4461. szMsg,
  4462. CREDUI_MAX_CMDLINE_MSG_LENGTH,
  4463. (va_list *) &j);
  4464. CredPutStdout(szMsg);
  4465. CredPutStdout( L"\n" );
  4466. } // end if invalid
  4467. } // end for each reader
  4468. } // end if any bad ones
  4469. //
  4470. // If the caller passed a name into the API,
  4471. // simply report that we couldn't find the cert and return
  4472. //
  4473. if ( UserName[0] != '\0' ) {
  4474. // ErrorString is expected to be NoMatch or ManyMatch
  4475. //_snwprintf(szMsg,
  4476. // CREDUI_MAX_CMDLINE_MSG_LENGTH,
  4477. // ErrorString,
  4478. // UserName);
  4479. // szMsg[0] = 0;
  4480. //szMsg[CREDUI_MAX_CMDLINE_MSG_LENGTH] = L'\0';
  4481. szMsg[0] = 0;
  4482. rgarg[0] = (DWORD_PTR) UserName;
  4483. // Note that ErrorString returned from MatchSmartCard has type LPWSTR, but it is actually
  4484. // a message ID. We take the low word of the pointer as the ID.
  4485. FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  4486. CreduiInstance,
  4487. LOWORD(ErrorString),
  4488. 0,
  4489. szMsg,
  4490. CREDUI_MAX_CMDLINE_MSG_LENGTH,
  4491. (va_list *) rgarg);
  4492. CredPutStdout( szMsg );
  4493. WinStatus = ERROR_CANCELLED;
  4494. goto Cleanup;
  4495. }
  4496. //
  4497. // If there was only one smartcard and it was valid,
  4498. // use it
  4499. //
  4500. // if ( ValidSmartCardCount == 1 && InvalidSmartCardCount == 0 ) {
  4501. // gm: If list can only contain one item, use it.
  4502. if ( ValidSmartCardCount == 1 ) {
  4503. if ( !GetSmartCardInfo( KnownGoodCard, CREDUI_MAX_USERNAME_LENGTH, SmartCardText, &IsACard, &SmartCardValid, &SavedCertEnum ) ) {
  4504. WinStatus = ERROR_INTERNAL_ERROR;
  4505. goto Cleanup;
  4506. }
  4507. SavedCertIndex = KnownGoodCard;
  4508. WinStatus = NO_ERROR;
  4509. goto Cleanup;
  4510. //
  4511. // If there were valid smartcard,
  4512. // List the valid smartcards for the user
  4513. //
  4514. } else if ( ValidSmartCardCount ) {
  4515. //
  4516. // Tell user about all certs
  4517. //
  4518. szMsg[0] = 0;
  4519. FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  4520. CreduiInstance,
  4521. IDS_CHOOSE_A_CERT,
  4522. 0,
  4523. szMsg,
  4524. CREDUI_MAX_CMDLINE_MSG_LENGTH,
  4525. NULL);
  4526. CredPutStdout(szMsg);
  4527. for ( i=0; i<SmartCardCount; i++ ) {
  4528. if ( !GetSmartCardInfo( i, CREDUI_MAX_USERNAME_LENGTH, SmartCardText, &IsACard, &SmartCardValid, NULL ) ) {
  4529. WinStatus = ERROR_INTERNAL_ERROR;
  4530. goto Cleanup;
  4531. }
  4532. if ( SmartCardValid ) {
  4533. //swprintf(szMsg,CreduiStrings.CmdLinePreamble,i+1,SmartCardText);
  4534. szMsg[0] = 0;
  4535. rgarg[0] = i+1;
  4536. rgarg[1] = (DWORD_PTR) SmartCardText;
  4537. FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  4538. Instance,
  4539. IDS_CMDLINE_PREAMBLE,
  4540. 0,
  4541. szMsg,
  4542. CREDUI_MAX_CMDLINE_MSG_LENGTH,
  4543. (va_list *) rgarg);
  4544. CredPutStdout( szMsg );
  4545. }
  4546. }
  4547. CredPutStdout( L"\n" );
  4548. //
  4549. // Ask user to enter the reader number of one of the smartcards
  4550. //
  4551. //_snwprintf(szMsg,
  4552. // CREDUI_MAX_CMDLINE_MSG_LENGTH,
  4553. // CreduiStrings.SCardPrompt,
  4554. // TargetName);
  4555. //szMsg[CREDUI_MAX_CMDLINE_MSG_LENGTH] = L'\0';
  4556. szMsg[0] = 0;
  4557. rgarg[0] = (DWORD_PTR)TargetName;
  4558. rgarg[1] = 0;
  4559. FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  4560. Instance,
  4561. IDS_SCARD_PROMPT,
  4562. 0,
  4563. szMsg,
  4564. CREDUI_MAX_CMDLINE_MSG_LENGTH,
  4565. (va_list *) rgarg);
  4566. CredPutStdout( szMsg );
  4567. CredGetStdin( UserName, CREDUI_MAX_USERNAME_LENGTH, TRUE );
  4568. if ( wcslen (UserName ) == 0 ) {
  4569. szMsg[0] = 0;
  4570. FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  4571. CreduiInstance,
  4572. IDS_NO_SCARD_ENTERED ,
  4573. 0,
  4574. szMsg,
  4575. CREDUI_MAX_CMDLINE_MSG_LENGTH,
  4576. NULL);
  4577. CredPutStdout(szMsg);
  4578. WinStatus = ERROR_CANCELLED;
  4579. goto Cleanup;
  4580. }
  4581. //
  4582. // Find the smartcard that matches the username
  4583. //
  4584. INT iWhich = 0;
  4585. WCHAR *pc = NULL;
  4586. iWhich = wcstol(UserName,&pc,10);
  4587. if (pc == UserName) {
  4588. // Invalid if at least one char was not numeric
  4589. szMsg[0] = 0;
  4590. FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  4591. CreduiInstance,
  4592. IDS_READERINVALID,
  4593. 0,
  4594. szMsg,
  4595. CREDUI_MAX_CMDLINE_MSG_LENGTH,
  4596. NULL);
  4597. CredPutStdout(szMsg);
  4598. WinStatus = ERROR_CANCELLED;
  4599. goto Cleanup;
  4600. }
  4601. // convert 1 based UI number to 0 based internal index
  4602. if (iWhich > 0) iWhich -= 1;
  4603. if ( !GetSmartCardInfo( iWhich, CREDUI_MAX_USERNAME_LENGTH, SmartCardText, &IsACard, &SmartCardValid, &SavedCertEnum ) ) {
  4604. // Invalid if that indexed card did not read correctly
  4605. szMsg[0] = 0;
  4606. FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  4607. CreduiInstance,
  4608. IDS_READERINVALID,
  4609. 0,
  4610. szMsg,
  4611. CREDUI_MAX_CMDLINE_MSG_LENGTH,
  4612. NULL);
  4613. CredPutStdout(szMsg);
  4614. WinStatus = ERROR_CANCELLED;
  4615. goto Cleanup;
  4616. }
  4617. // At this point, a valid number was entered, and an attempt to read the card made
  4618. // GetSmartCardInfo() returned OK, but SmartCardValid may still be false
  4619. if (!SmartCardValid)
  4620. {
  4621. szMsg[0] = 0;
  4622. FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  4623. CreduiInstance,
  4624. IDS_READERINVALID,
  4625. 0,
  4626. szMsg,
  4627. CREDUI_MAX_CMDLINE_MSG_LENGTH,
  4628. NULL);
  4629. CredPutStdout(szMsg);
  4630. WinStatus = ERROR_CANCELLED;
  4631. goto Cleanup;
  4632. }
  4633. else
  4634. {
  4635. SavedCertIndex = iWhich;
  4636. WinStatus = NO_ERROR;
  4637. goto Cleanup;
  4638. }
  4639. }
  4640. WinStatus = ERROR_CANCELLED;
  4641. //
  4642. // Complete the operation.
  4643. //
  4644. // WinStatus is the status of the operation so far
  4645. // if NO_ERROR, SavedCertEnum is the description of the cert to use, and
  4646. // SavedCertIndex is the index to the selected cert.
  4647. //
  4648. Cleanup:
  4649. if ( WinStatus == NO_ERROR) {
  4650. if ( CredUIMarshallNode ( SavedCertEnum, UserName ) ) {
  4651. //
  4652. // Save the username
  4653. //
  4654. UserNameSelection = SmartCardBaseInComboBox + SavedCertIndex;
  4655. IsChangingUserName = TRUE;
  4656. SendMessage(UserNameControlWindow,
  4657. CB_SETCURSEL,
  4658. UserNameSelection,
  4659. 0);
  4660. IsChangingUserName = FALSE;
  4661. //
  4662. // Prompt for the pin
  4663. //
  4664. //CredPutStdout( CreduiStrings.PinPrompt );
  4665. //swprintf(szMsg,CreduiStrings.CmdLineThisCard,SavedCertIndex + 1);
  4666. szMsg[0] = 0;
  4667. i = SavedCertIndex + 1;
  4668. FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  4669. Instance,
  4670. IDS_CMDLINE_THISCARD,
  4671. 0,
  4672. szMsg,
  4673. CREDUI_MAX_CMDLINE_MSG_LENGTH,
  4674. (va_list *) &i);
  4675. CredPutStdout(szMsg);
  4676. CredGetStdin( Password, CREDUI_MAX_PASSWORD_LENGTH, FALSE );
  4677. //
  4678. // Save the pin
  4679. //
  4680. if (!OnSetPassword( Password ) ) {
  4681. WinStatus = GetLastError();
  4682. CreduiDebugLog("CreduiCredentialControl::CmdlineSmartCardPrompt: "
  4683. "OnSetPassword failed: %u\n",
  4684. WinStatus );
  4685. }
  4686. //
  4687. // Prompt whether the save the cred or not
  4688. //
  4689. CmdlineSavePrompt();
  4690. } else {
  4691. WinStatus = GetLastError();
  4692. CreduiDebugLog("CreduiCredentialControl::CmdlineSmartCardPrompt: "
  4693. "CredMarshalCredential failed: %u\n",
  4694. WinStatus );
  4695. }
  4696. }
  4697. //
  4698. // Tell our parent window that we're done prompting
  4699. //
  4700. PostQuitMessage( WinStatus );
  4701. return;
  4702. }
  4703. void CreduiCredentialControl::CmdlineSavePrompt()
  4704. /*++
  4705. Routine Description:
  4706. Command line code to prompt for saving the credential
  4707. Arguments:
  4708. None
  4709. Return Values:
  4710. None
  4711. --*/
  4712. {
  4713. WCHAR szMsg[CREDUI_MAX_CMDLINE_MSG_LENGTH + 1];
  4714. WCHAR szY[CREDUI_MAX_CMDLINE_MSG_LENGTH + 1];
  4715. WCHAR szN[CREDUI_MAX_CMDLINE_MSG_LENGTH + 1];
  4716. //
  4717. // Only prompt if we've been asked to display the checkbox
  4718. //
  4719. while ( Style & CRS_SAVECHECK ) {
  4720. // Fetch the strings one by one from the messages, and cobble them together
  4721. WCHAR *rgsz[2];
  4722. szY[0] = 0;
  4723. szN[0] = 0;
  4724. rgsz[0] = szY;
  4725. rgsz[1] = szN;
  4726. szMsg[0] = 0;
  4727. // Fetch yes and no strings
  4728. FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  4729. CreduiInstance,
  4730. IDS_YES_TEXT,
  4731. 0,
  4732. szY,
  4733. CREDUI_MAX_CMDLINE_MSG_LENGTH,
  4734. NULL);
  4735. FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  4736. CreduiInstance,
  4737. IDS_NO_TEXT,
  4738. 0,
  4739. szN,
  4740. CREDUI_MAX_CMDLINE_MSG_LENGTH,
  4741. NULL);
  4742. // Arg substitute them into the prompt
  4743. FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  4744. CreduiInstance,
  4745. IDS_SAVE_PROMPT,
  4746. 0,
  4747. szMsg,
  4748. CREDUI_MAX_CMDLINE_MSG_LENGTH,
  4749. (va_list *) rgsz);
  4750. szMsg[CREDUI_MAX_CMDLINE_MSG_LENGTH] = L'\0';
  4751. CredPutStdout( szMsg );
  4752. CredGetStdin( szMsg, CREDUI_MAX_CMDLINE_MSG_LENGTH, TRUE );
  4753. // if ( toupper(szMsg[0]) == toupper(CreduiStrings.YesText[0]) ) {
  4754. if ( toupper(szMsg[0]) == toupper(szY[0]) ) {
  4755. Credential_CheckSave( Window, TRUE );
  4756. break;
  4757. // } else if ( toupper(szMsg[0]) == toupper(CreduiStrings.NoText[0]) ) {
  4758. } else if ( toupper(szMsg[0]) == toupper(szN[0]) ) {
  4759. Credential_CheckSave( Window, FALSE );
  4760. break;
  4761. }
  4762. }
  4763. }
  4764. UINT CreduiCredentialControl::MapID(UINT uiID) {
  4765. switch(uiID) {
  4766. case IDC_USERNAME:
  4767. return IDH_USERNAMEEDIT;
  4768. case IDC_PASSWORD:
  4769. return IDH_PASSWORDEDIT;
  4770. case IDC_SAVE:
  4771. return IDH_SAVECHECKBOX;
  4772. default:
  4773. return IDS_NOHELP;
  4774. }
  4775. }
  4776. BOOL
  4777. CreduiCredentialControl::OnHelpInfo(LPARAM lp) {
  4778. HELPINFO* pH;
  4779. INT iMapped;
  4780. pH = (HELPINFO *) lp;
  4781. HH_POPUP stPopUp;
  4782. RECT rcW;
  4783. UINT gID;
  4784. gID = pH->iCtrlId;
  4785. iMapped = MapID(gID);
  4786. if (iMapped == 0) return TRUE;
  4787. if (IDS_NOHELP != iMapped) {
  4788. memset(&stPopUp,0,sizeof(stPopUp));
  4789. stPopUp.cbStruct = sizeof(HH_POPUP);
  4790. stPopUp.hinst = Instance;
  4791. stPopUp.idString = iMapped;
  4792. stPopUp.pszText = NULL;
  4793. stPopUp.clrForeground = -1;
  4794. stPopUp.clrBackground = -1;
  4795. stPopUp.rcMargins.top = -1;
  4796. stPopUp.rcMargins.bottom = -1;
  4797. stPopUp.rcMargins.left = -1;
  4798. stPopUp.rcMargins.right = -1;
  4799. stPopUp.pszFont = NULL;
  4800. if (GetWindowRect((HWND)pH->hItemHandle,&rcW)) {
  4801. stPopUp.pt.x = (rcW.left + rcW.right) / 2;
  4802. stPopUp.pt.y = (rcW.top + rcW.bottom) / 2;
  4803. }
  4804. else stPopUp.pt = pH->MousePos;
  4805. HtmlHelp((HWND) pH->hItemHandle,NULL,HH_DISPLAY_TEXT_POPUP,(DWORD_PTR) &stPopUp);
  4806. }
  4807. return TRUE;
  4808. }