Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2005 lines
50 KiB

  1. //=============================================================================
  2. // Copyright (c) 2000 Microsoft Corporation
  3. //
  4. // api.cpp
  5. //
  6. // Win32 API function implementation and the DLL entry function.
  7. //
  8. // Created 02/29/2000 johnstep (John Stephens)
  9. //=============================================================================
  10. #include "precomp.hpp"
  11. #include "dialogs.hpp"
  12. #include "resource.h"
  13. //#include "utils.hpp"
  14. //-----------------------------------------------------------------------------
  15. // Global Variables
  16. //-----------------------------------------------------------------------------
  17. HMODULE CreduiInstance = NULL;
  18. ULONG CreduiComReferenceCount = 0;
  19. BOOL CreduiIsPersonal = FALSE;
  20. BOOL CreduiIsDomainController = FALSE;
  21. BOOL CreduiIsSafeMode = FALSE;
  22. CREDUI_STRINGS CreduiStrings;
  23. UINT CreduiScarduiWmReaderArrival = 0;
  24. UINT CreduiScarduiWmReaderRemoval = 0;
  25. UINT CreduiScarduiWmCardInsertion = 0;
  26. UINT CreduiScarduiWmCardRemoval = 0;
  27. UINT CreduiScarduiWmCardCertAvail = 0;
  28. UINT CreduiScarduiWmCardStatus = 0;
  29. BOOL CreduiHasSmartCardSupport = FALSE;
  30. static LONG CreduiFirstTime = TRUE;
  31. static HANDLE CreduiInitEvent = NULL;
  32. BOOL gbWaitingForSSOCreds = FALSE;
  33. WCHAR gszSSOUserName[CREDUI_MAX_USERNAME_LENGTH];
  34. WCHAR gszSSOPassword[CREDUI_MAX_PASSWORD_LENGTH];
  35. BOOL gbStoredSSOCreds = FALSE;
  36. //-----------------------------------------------------------------------------
  37. // Functions
  38. //-----------------------------------------------------------------------------
  39. //=============================================================================
  40. // CreduiInitStringTable
  41. //
  42. // This function loads all the string resources into the global string table.
  43. // It only needs to be called once per process.
  44. //
  45. // Return TRUE if the string table was successfully initialized or FALSE
  46. // otherwise.
  47. //
  48. // Created 03/26/2000 johnstep (John Stephens)
  49. //=============================================================================
  50. BOOL
  51. CreduiInitStringTable()
  52. {
  53. #define CREDUI_STRING(id, name) {\
  54. id, CreduiStrings.##name, (sizeof CreduiStrings.##name) / (sizeof WCHAR)\
  55. }
  56. static struct
  57. {
  58. UINT Id;
  59. WCHAR *String;
  60. ULONG Length;
  61. } stringInfo[] = {
  62. // Static labels for controls
  63. CREDUI_STRING(IDS_USERNAME_STATIC, UserNameStatic),
  64. CREDUI_STRING(IDS_PASSWORD_STATIC, PasswordStatic),
  65. CREDUI_STRING(IDS_CERTIFICATE_STATIC, CertificateStatic),
  66. CREDUI_STRING(IDS_PIN_STATIC, PinStatic),
  67. CREDUI_STRING(IDS_CARD_STATIC, SmartCardStatic),
  68. // Caption strings
  69. CREDUI_STRING(IDS_DNS_CAPTION, DnsCaption),
  70. CREDUI_STRING(IDS_NETBIOS_CAPTION, NetbiosCaption),
  71. CREDUI_STRING(IDS_GENERIC_CAPTION, GenericCaption),
  72. CREDUI_STRING(IDS_WELCOME, Welcome),
  73. CREDUI_STRING(IDS_WELCOME_BACK, WelcomeBack),
  74. CREDUI_STRING(IDS_CONNECTING, Connecting),
  75. CREDUI_STRING(IDS_LOOKUP_NAME, LookupName),
  76. CREDUI_STRING(IDS_CARD_ERROR, CardError),
  77. CREDUI_STRING(IDS_SAVE, Save),
  78. CREDUI_STRING(IDS_PASSPORT_SAVE, PassportSave ),
  79. CREDUI_STRING(IDS_EMAIL_NAME, EmailName ),
  80. // Tooltip strings
  81. CREDUI_STRING(IDS_USERNAME_TIP_TITLE, UserNameTipTitle),
  82. CREDUI_STRING(IDS_USERNAME_TIP_TEXT, UserNameTipText),
  83. CREDUI_STRING(IDS_PASSWORD_TIP_TITLE, PasswordTipTitle),
  84. CREDUI_STRING(IDS_PASSWORD_TIP_TEXT, PasswordTipText),
  85. CREDUI_STRING(IDS_CAPSLOCK_TIP_TITLE, CapsLockTipTitle),
  86. CREDUI_STRING(IDS_CAPSLOCK_TIP_TEXT, CapsLockTipText),
  87. CREDUI_STRING(IDS_LOGON_TIP_TITLE, LogonTipTitle),
  88. CREDUI_STRING(IDS_LOGON_TIP_TEXT, LogonTipText),
  89. CREDUI_STRING(IDS_LOGON_TIP_CAPS, LogonTipCaps),
  90. CREDUI_STRING(IDS_BACKWARDS_TIP_TITLE, BackwardsTipTitle),
  91. CREDUI_STRING(IDS_BACKWARDS_TIP_TEXT, BackwardsTipText),
  92. CREDUI_STRING(IDS_WRONG_OLD_TIP_TITLE, WrongOldTipTitle),
  93. CREDUI_STRING(IDS_WRONG_OLD_TIP_TEXT, WrongOldTipText),
  94. CREDUI_STRING(IDS_NOT_SAME_TIP_TITLE, NotSameTipTitle),
  95. CREDUI_STRING(IDS_NOT_SAME_TIP_TEXT, NotSameTipText),
  96. CREDUI_STRING(IDS_TOO_SHORT_TIP_TITLE, TooShortTipTitle),
  97. CREDUI_STRING(IDS_TOO_SHORT_TIP_TEXT, TooShortTipText),
  98. CREDUI_STRING(IDS_DOWNGRADE_TIP_TEXT, DowngradeTipText),
  99. CREDUI_STRING(IDS_EMAILNAME_TIP_TITLE, EmailNameTipTitle),
  100. CREDUI_STRING(IDS_EMAILNAME_TIP_TEXT, EmailNameTipText),
  101. // strings that can appear in GUI or be copied from GUI and presented on cmdline
  102. CREDUI_STRING(IDS_CMDLINE_NOCARD,NoCard),
  103. CREDUI_STRING(IDS_EMPTY_READER, EmptyReader),
  104. CREDUI_STRING(IDS_READING_CARD, ReadingCard),
  105. CREDUI_STRING(IDS_CERTIFICATE, Certificate),
  106. CREDUI_STRING(IDS_EMPTY_CARD, EmptyCard),
  107. CREDUI_STRING(IDS_UNKNOWN_CARD, UnknownCard),
  108. CREDUI_STRING(IDS_BACKWARDS_CARD, BackwardsCard)
  109. };
  110. #undef CREDUI_STRING
  111. for (UINT i = 0; i < (sizeof stringInfo) / (sizeof stringInfo[0]); ++i)
  112. {
  113. // Read all strings into string array from resources of application
  114. // Some strings which are GUI-only taken from resources
  115. // Strings that are may be output to cmdline are taken from MC file, which also
  116. // permits more flexible argument substitution during localization
  117. if (stringInfo[i].Id >= 2500)
  118. {
  119. stringInfo[i].String[0] = 0;
  120. FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  121. CreduiInstance,
  122. stringInfo[i].Id,
  123. 0,
  124. stringInfo[i].String,
  125. stringInfo[i].Length - 1,
  126. NULL);
  127. }
  128. else if (!LoadString(CreduiInstance,
  129. stringInfo[i].Id,
  130. stringInfo[i].String,
  131. stringInfo[i].Length))
  132. {
  133. CreduiDebugLog("CreduiInitStringTable: Load string %u failed\n",
  134. stringInfo[i].Id);
  135. return FALSE;
  136. }
  137. }
  138. return TRUE;
  139. }
  140. //=============================================================================
  141. // CreduiInitSmartCardWindowMessages
  142. //
  143. // Return TRUE on success or FALSE otherwise.
  144. //
  145. // Created 03/26/2000 johnstep (John Stephens)
  146. //=============================================================================
  147. BOOL
  148. CreduiInitSmartCardWindowMessages()
  149. {
  150. struct
  151. {
  152. UINT *message;
  153. CHAR *string;
  154. } messageInfo[] = {
  155. &CreduiScarduiWmReaderArrival, SCARDUI_READER_ARRIVAL,
  156. &CreduiScarduiWmReaderRemoval, SCARDUI_READER_REMOVAL,
  157. &CreduiScarduiWmCardInsertion, SCARDUI_SMART_CARD_INSERTION,
  158. &CreduiScarduiWmCardRemoval, SCARDUI_SMART_CARD_REMOVAL,
  159. &CreduiScarduiWmCardCertAvail, SCARDUI_SMART_CARD_CERT_AVAIL,
  160. &CreduiScarduiWmCardStatus, SCARDUI_SMART_CARD_STATUS
  161. };
  162. for (UINT i = 0; i < (sizeof messageInfo) / (sizeof messageInfo[0]); ++i)
  163. {
  164. *messageInfo[i].message =
  165. RegisterWindowMessageA(messageInfo[i].string);
  166. if (*messageInfo[i].message == 0)
  167. {
  168. return FALSE;
  169. }
  170. }
  171. return TRUE;
  172. }
  173. //=============================================================================
  174. // CreduiApiInit
  175. //
  176. // This function is called at API entry points to ensure the common controls
  177. // we need are initialized. Currently, the only initialization done is only
  178. // needed once per process, but this macro will handle per thread
  179. // initialization in the future, if necessary:
  180. //
  181. // Returns TRUE on success or FALSE otherwise.
  182. //
  183. // Created 03/10/2000 johnstep (John Stephens)
  184. //=============================================================================
  185. static
  186. BOOL
  187. CreduiApiInit()
  188. {
  189. // First time initialization:
  190. ASSERT(CreduiInitEvent != NULL);
  191. if (InterlockedCompareExchange(&CreduiFirstTime, FALSE, TRUE))
  192. {
  193. INITCOMMONCONTROLSEX init;
  194. init.dwSize = sizeof init;
  195. init.dwICC = ICC_USEREX_CLASSES;
  196. if (!InitCommonControlsEx(&init))
  197. {
  198. return FALSE;
  199. }
  200. // Check for Personal SKU:
  201. OSVERSIONINFOEXW versionInfo;
  202. versionInfo.dwOSVersionInfoSize = sizeof OSVERSIONINFOEXW;
  203. if (GetVersionEx(reinterpret_cast<OSVERSIONINFOW *>(&versionInfo)))
  204. {
  205. CreduiIsPersonal =
  206. (versionInfo.wProductType == VER_NT_WORKSTATION) &&
  207. (versionInfo.wSuiteMask & VER_SUITE_PERSONAL);
  208. CreduiIsDomainController =
  209. (versionInfo.wProductType == VER_NT_DOMAIN_CONTROLLER);
  210. }
  211. // Check for safe mode:
  212. HKEY key;
  213. if (RegOpenKeyEx(
  214. HKEY_LOCAL_MACHINE,
  215. L"SYSTEM\\CurrentControlSet\\Control\\SafeBoot\\Option",
  216. 0,
  217. KEY_READ,
  218. &key) == ERROR_SUCCESS)
  219. {
  220. if (RegQueryValueEx(
  221. key,
  222. L"OptionValue",
  223. NULL,
  224. NULL,
  225. NULL,
  226. NULL) == ERROR_SUCCESS)
  227. {
  228. CreduiIsSafeMode = TRUE;
  229. }
  230. RegCloseKey(key);
  231. }
  232. // Do other initialization:
  233. InitializeCredMgr();
  234. if (!CreduiInitStringTable())
  235. {
  236. return FALSE;
  237. }
  238. CreduiHasSmartCardSupport = CreduiInitSmartCardWindowMessages();
  239. CreduiIconParentWindow::Register(CreduiInstance);
  240. SetEvent(CreduiInitEvent);
  241. }
  242. else
  243. {
  244. WaitForSingleObject(CreduiInitEvent, INFINITE);
  245. }
  246. return TRUE;
  247. }
  248. //=============================================================================
  249. // CreduiValidateUiInfo
  250. //
  251. // This function validates the CREDUI_INFO structure passed in. A NULL value
  252. // is acceptable, and impies defaults.
  253. //
  254. // CredValidateUiInfoW for wide
  255. // CredValidateUiInfoA for ANSI
  256. //
  257. // Arguments:
  258. // uiInfo (in) - structure to validate
  259. //
  260. // Returns TRUE if the structure is valid, or FALSE otherwise.
  261. //
  262. // Created 03/25/2000 johnstep (John Stephens)
  263. //=============================================================================
  264. static
  265. BOOL
  266. CreduiValidateUiInfoW(
  267. CREDUI_INFOW *uiInfo
  268. )
  269. {
  270. if (uiInfo != NULL)
  271. {
  272. if (uiInfo->cbSize != sizeof(*uiInfo) )
  273. {
  274. return FALSE;
  275. }
  276. if ((uiInfo->hbmBanner != NULL) &&
  277. (GetObjectType(uiInfo->hbmBanner) != OBJ_BITMAP))
  278. {
  279. return FALSE;
  280. }
  281. if ((uiInfo->pszMessageText != NULL) &&
  282. (lstrlenW(uiInfo->pszMessageText) > CREDUI_MAX_MESSAGE_LENGTH))
  283. {
  284. return FALSE;
  285. }
  286. if ((uiInfo->pszCaptionText != NULL) &&
  287. (lstrlenW(uiInfo->pszCaptionText) > CREDUI_MAX_CAPTION_LENGTH))
  288. {
  289. return FALSE;
  290. }
  291. }
  292. return TRUE;
  293. }
  294. //=============================================================================
  295. // CreduiConvertUiInfoToWide
  296. //
  297. // This function converts a CREDUI_INFOA structure to CREDUI_INFOW. On
  298. // success,The caller is responsible for freeing pszMessageText and
  299. // pszCaptionText via the delete [] operator.
  300. //
  301. // Arguments:
  302. // uiInfoA (in) - structure to convert
  303. // uiInfoW (out) - storage for converted structure. The pszMessageText and
  304. // pszCaptionText will be set to NULL on failure or valid
  305. // pointers (unless the in pointer is NULL) on success,
  306. // allocated via the new [] operator.
  307. //
  308. // Returns TRUE if the structure is valid, or FALSE otherwise.
  309. //
  310. // Created 03/26/2000 johnstep (John Stephens)
  311. //=============================================================================
  312. static
  313. BOOL
  314. CreduiConvertUiInfoToWide(
  315. CREDUI_INFOA *uiInfoA,
  316. CREDUI_INFOW *uiInfoW
  317. )
  318. {
  319. uiInfoW->cbSize = uiInfoA->cbSize;
  320. uiInfoW->hwndParent = uiInfoA->hwndParent;
  321. uiInfoW->pszMessageText = NULL;
  322. uiInfoW->pszCaptionText = NULL;
  323. uiInfoW->hbmBanner = uiInfoA->hbmBanner;
  324. if (uiInfoA->pszMessageText != NULL)
  325. {
  326. uiInfoW->pszMessageText =
  327. new WCHAR[lstrlenA(uiInfoA->pszMessageText) + 1];
  328. if (uiInfoW->pszMessageText == NULL)
  329. {
  330. goto ErrorExit;
  331. }
  332. if (MultiByteToWideChar(
  333. CP_ACP, 0, uiInfoA->pszMessageText, -1,
  334. const_cast<WCHAR *>(uiInfoW->pszMessageText),
  335. CREDUI_MAX_MESSAGE_LENGTH + 1) == 0)
  336. {
  337. goto ErrorExit;
  338. }
  339. }
  340. else
  341. {
  342. uiInfoW->pszMessageText = NULL;
  343. }
  344. if (uiInfoA->pszCaptionText != NULL)
  345. {
  346. uiInfoW->pszCaptionText =
  347. new WCHAR[lstrlenA(uiInfoA->pszCaptionText) + 1];
  348. if (uiInfoW->pszCaptionText == NULL)
  349. {
  350. goto ErrorExit;
  351. }
  352. if (MultiByteToWideChar(
  353. CP_ACP, 0, uiInfoA->pszCaptionText, -1,
  354. const_cast<WCHAR *>(uiInfoW->pszCaptionText),
  355. CREDUI_MAX_CAPTION_LENGTH + 1) == 0)
  356. {
  357. goto ErrorExit;
  358. }
  359. }
  360. else
  361. {
  362. uiInfoW->pszCaptionText = NULL;
  363. }
  364. return TRUE;
  365. ErrorExit:
  366. if (uiInfoW->pszCaptionText != NULL)
  367. {
  368. delete [] const_cast<WCHAR *>(uiInfoW->pszCaptionText);
  369. uiInfoW->pszCaptionText = NULL;
  370. }
  371. if (uiInfoW->pszMessageText != NULL)
  372. {
  373. delete [] const_cast<WCHAR *>(uiInfoW->pszMessageText);
  374. uiInfoW->pszMessageText = NULL;
  375. }
  376. return FALSE;
  377. }
  378. //=============================================================================
  379. // CredUIPromptForCredentials
  380. //
  381. // Presents a user interface to get credentials from an application.
  382. //
  383. // CredUIPromptForCredentialsW for wide
  384. // CredUIPromptForCredentialsA for ANSI
  385. //
  386. // Arguments:
  387. // uiInfo (in,optional)
  388. // targetName (in) - if specified, securityContext must be NULL
  389. // securityContext (in) - if specified, targetName must be NULL
  390. // error (in) - the authentication error
  391. // userName (in,out)
  392. // userNameBufferSize (in) - maximum length of userName
  393. // password (in,out)
  394. // passwordBufferSize (in) - maximum length of password
  395. // save (in/out) - TRUE if save check box was checked
  396. // flags (in)
  397. //
  398. // Returns:
  399. // ERROR_SUCCESS
  400. // ERROR_CANCELLED
  401. // ERROR_NO_SUCH_LOGON_SESSION - if credential manager cannot be used
  402. // ERROR_GEN_FAILURE
  403. // ERROR_INVALID_FLAGS
  404. // ERROR_INVALID_PARAMETER
  405. // ERROR_OUTOFMEMORY
  406. //
  407. // Created 10/17/2000 johnhaw
  408. DWORD
  409. CredUIPromptForCredentialsWorker(
  410. IN BOOL doingCommandLine,
  411. CREDUI_INFOW *uiInfo,
  412. CONST WCHAR *targetName,
  413. CtxtHandle *securityContext,
  414. DWORD authError,
  415. PWSTR pszUserName,
  416. ULONG ulUserNameBufferSize,
  417. PWSTR pszPassword,
  418. ULONG ulPasswordBufferSize,
  419. BOOL *save,
  420. DWORD flags
  421. )
  422. /*++
  423. Routine Description:
  424. This routine implements the GUI and command line prompt for credentials.
  425. Arguments:
  426. DoingCommandLine - TRUE if prompting is to be done via the command line
  427. FALSE if prompting is to be done via GUI
  428. ... - Other parameters are the same a CredUIPromptForCredentials API
  429. Return Values:
  430. Same as CredUIPromptForCredentials.
  431. --*/
  432. {
  433. ULONG CertFlags;
  434. ULONG CredCategory;
  435. ULONG PersistFlags;
  436. CreduiDebugLog("CUIPFCWorker: Flags: %x, Target: %S doingCommandLine: %i\n", flags, targetName, doingCommandLine);
  437. if ((NULL == pszUserName) || (NULL == pszPassword))
  438. {
  439. return ERROR_INVALID_PARAMETER;
  440. }
  441. if (!CreduiApiInit())
  442. {
  443. return ERROR_GEN_FAILURE;
  444. }
  445. // Validate arguments:
  446. if ((flags & ~CREDUI_FLAGS_PROMPT_VALID) != 0)
  447. {
  448. CreduiDebugLog("CreduiPromptForCredentials: flags not valid %lx.\n", flags );
  449. return ERROR_INVALID_FLAGS;
  450. }
  451. //
  452. // Ensure there is is only one bit defining cert support
  453. //
  454. CertFlags = flags & (CREDUI_FLAGS_REQUIRE_SMARTCARD|CREDUI_FLAGS_REQUIRE_CERTIFICATE|CREDUI_FLAGS_EXCLUDE_CERTIFICATES);
  455. if ( CertFlags != 0 && !JUST_ONE_BIT(CertFlags) ) {
  456. CreduiDebugLog("CreduiPromptForCredentials: require smartcard, require certificate, and exclude certificates are mutually exclusive %lx.\n", flags );
  457. return ERROR_INVALID_FLAGS;
  458. }
  459. //
  460. // For the command line version,
  461. // limit cert support further.
  462. //
  463. if ( doingCommandLine ) {
  464. if ( CertFlags == 0 ||
  465. (CertFlags & CREDUI_FLAGS_REQUIRE_CERTIFICATE) != 0 ) {
  466. CreduiDebugLog("CreduiPromptForCredentials: need either require smartcard or exclude certificates for command line %lx.\n", flags );
  467. return ERROR_INVALID_FLAGS;
  468. }
  469. }
  470. //
  471. // Ensure there is only one bit defining the credential category
  472. CredCategory = flags & (CREDUI_FLAGS_GENERIC_CREDENTIALS|CREDUI_FLAGS_USERNAME_TARGET_CREDENTIALS);
  473. if ( CredCategory != 0 && !JUST_ONE_BIT(CredCategory) ) {
  474. CreduiDebugLog("CreduiPromptForCredentials: generic creds and username target are mutually exclusive %lx.\n", flags );
  475. return ERROR_INVALID_FLAGS;
  476. }
  477. //
  478. // Ensure there is only one bit set saying whether the cred is to persist or not
  479. //
  480. PersistFlags = flags & (CREDUI_FLAGS_DO_NOT_PERSIST|CREDUI_FLAGS_PERSIST);
  481. if ( PersistFlags != 0 && !JUST_ONE_BIT(PersistFlags) ) {
  482. CreduiDebugLog("CreduiPromptForCredentials: DoNotPersist and Persist are mutually exclusive %lx.\n", flags );
  483. return ERROR_INVALID_FLAGS;
  484. }
  485. //
  486. // Ensure AlwaysShowUi is only specified for generic credentials
  487. //
  488. if ( flags & CREDUI_FLAGS_ALWAYS_SHOW_UI ) {
  489. if ( (flags & CREDUI_FLAGS_GENERIC_CREDENTIALS) == 0) {
  490. CreduiDebugLog("CreduiPromptForCredentials: AlwaysShowUi is only supported for generic credentials %lx.\n", flags );
  491. return ERROR_INVALID_FLAGS;
  492. }
  493. }
  494. //
  495. // Don't support a half-implemented feature
  496. //
  497. if ( securityContext != NULL ) {
  498. CreduiDebugLog("CreduiPromptForCredentials: securityContext must be null.\n" );
  499. return ERROR_INVALID_PARAMETER;
  500. }
  501. //
  502. // Validate the passed in UI info
  503. //
  504. if (!CreduiValidateUiInfoW(uiInfo))
  505. {
  506. CreduiDebugLog("CreduiPromptForCredentials: UI info is invalid.\n" );
  507. return ERROR_INVALID_PARAMETER;
  508. }
  509. //
  510. // Ensure there are strings defined for the caption
  511. //
  512. if (flags & CREDUI_FLAGS_DO_NOT_PERSIST)
  513. {
  514. if ((targetName == NULL) &&
  515. ((uiInfo == NULL) ||
  516. (uiInfo->pszMessageText == NULL) ||
  517. (uiInfo->pszCaptionText == NULL)))
  518. {
  519. CreduiDebugLog("CreduiPromptForCredentials: DoNotPersist and target data empty.\n" );
  520. return ERROR_INVALID_PARAMETER;
  521. }
  522. }
  523. else if (targetName != NULL)
  524. {
  525. if ((securityContext != NULL) ||
  526. (targetName[0] == L'\0') ||
  527. (lstrlen(targetName) > CREDUI_MAX_DOMAIN_TARGET_LENGTH))
  528. {
  529. CreduiDebugLog("CreduiPromptForCredentials: target name bad %ws.\n", targetName );
  530. return ERROR_INVALID_PARAMETER;
  531. }
  532. }
  533. else if (securityContext == NULL)
  534. {
  535. CreduiDebugLog("CreduiPromptForCredentials: no target data.\n" );
  536. return ERROR_INVALID_PARAMETER;
  537. }
  538. //
  539. // Ensure the caller supplied the default value for the save check box
  540. //
  541. if (flags & CREDUI_FLAGS_SHOW_SAVE_CHECK_BOX)
  542. {
  543. if (save == NULL)
  544. {
  545. CreduiDebugLog("CreduiPromptForCredentials: ShowSaveCheckbox and save is NULL.\n" );
  546. return ERROR_INVALID_PARAMETER;
  547. }
  548. }
  549. //
  550. // Ensure the user supplied a username if they set CREDUI_FLAGS_KEEP_USERNAME
  551. //
  552. if ( flags & CREDUI_FLAGS_KEEP_USERNAME )
  553. {
  554. if ( pszUserName == NULL )
  555. {
  556. CreduiDebugLog("CreduiPromptForCredentials: CREDUI_FLAGS_KEEP_USERNAME and pszUserName is NULL.\n" );
  557. return ERROR_INVALID_PARAMETER;
  558. }
  559. }
  560. // Use the stack for user name and password:
  561. WCHAR userName[CREDUI_MAX_USERNAME_LENGTH + 1];
  562. WCHAR password[CREDUI_MAX_PASSWORD_LENGTH + 1];
  563. ZeroMemory(userName, sizeof(userName));
  564. ZeroMemory(password, sizeof(password));
  565. if ( pszUserName != NULL && wcslen(pszUserName) > 0 )
  566. {
  567. wcscpy ( userName, pszUserName );
  568. }
  569. if ( pszPassword != NULL && wcslen(pszPassword) > 0)
  570. {
  571. wcscpy ( password, pszPassword );
  572. }
  573. // Do the password dialog box:
  574. //
  575. // Delay actually writing the credential to cred man if we're returning
  576. // the credential to the caller.
  577. // Otherwise, the CredWrite is just harvesting credentials for the next caller.
  578. // So delay the CredWrite until this caller confirms the validity.
  579. //
  580. DWORD result = ERROR_OUTOFMEMORY;
  581. CreduiPasswordDialog* pDlg = new CreduiPasswordDialog(
  582. doingCommandLine,
  583. (pszUserName != NULL && pszPassword != NULL ),
  584. CredCategory,
  585. uiInfo,
  586. targetName,
  587. userName,
  588. sizeof(userName)/sizeof(WCHAR)-sizeof(WCHAR), // Pass MaxChars instead of buffer size
  589. password,
  590. sizeof(password)/sizeof(WCHAR)-sizeof(WCHAR), // Pass MaxChars instead of buffer size
  591. save,
  592. flags,
  593. (flags & CREDUI_FLAGS_GENERIC_CREDENTIALS) ? NULL : securityContext,
  594. authError,
  595. &result);
  596. if ( pDlg != NULL )
  597. {
  598. delete pDlg;
  599. pDlg = NULL;
  600. }
  601. else
  602. {
  603. // couldn't create dialog, return.
  604. result = ERROR_OUTOFMEMORY;
  605. goto Cleanup;
  606. }
  607. // copy outbound username
  608. if ( pszUserName != NULL )
  609. {
  610. if (ulUserNameBufferSize > wcslen ( userName ) )
  611. {
  612. wcscpy ( pszUserName, userName );
  613. }
  614. else
  615. {
  616. CreduiDebugLog("CreduiPromptForCredentials: type username is too long.\n" );
  617. result = ERROR_INVALID_PARAMETER;
  618. goto Cleanup;
  619. }
  620. }
  621. if ( pszPassword != NULL )
  622. {
  623. if (ulPasswordBufferSize > wcslen ( password ) )
  624. {
  625. wcscpy ( pszPassword, password );
  626. }
  627. else
  628. {
  629. CreduiDebugLog("CreduiPromptForCredentials: type password is too long.\n" );
  630. result = ERROR_INVALID_PARAMETER;
  631. goto Cleanup;
  632. }
  633. }
  634. Cleanup:
  635. ZeroMemory(password, sizeof(password) );
  636. return result;
  637. }
  638. //=============================================================================
  639. CREDUIAPI
  640. DWORD
  641. WINAPI
  642. CredUIPromptForCredentialsW(
  643. CREDUI_INFOW *uiInfo,
  644. CONST WCHAR *targetName,
  645. CtxtHandle *securityContext,
  646. DWORD authError,
  647. PWSTR pszUserName,
  648. ULONG ulUserNameBufferSize,
  649. PWSTR pszPassword,
  650. ULONG ulPasswordBufferSize,
  651. BOOL *save,
  652. DWORD flags
  653. )
  654. {
  655. //
  656. // Call the common code indicating this is the GUI interface
  657. //
  658. return CredUIPromptForCredentialsWorker(
  659. FALSE, // GUI version
  660. uiInfo,
  661. targetName,
  662. securityContext,
  663. authError,
  664. pszUserName,
  665. ulUserNameBufferSize,
  666. pszPassword,
  667. ulPasswordBufferSize,
  668. save,
  669. flags );
  670. }
  671. CREDUIAPI
  672. DWORD
  673. WINAPI
  674. CredUIPromptForCredentialsA(
  675. CREDUI_INFOA *uiInfo,
  676. CONST CHAR *targetName,
  677. CtxtHandle *securityContext,
  678. DWORD authError,
  679. PSTR pszUserName,
  680. ULONG ulUserNameBufferSize,
  681. PSTR pszPassword,
  682. ULONG ulPasswordBufferSize,
  683. BOOL *save,
  684. DWORD flags
  685. )
  686. {
  687. DWORD result;
  688. WCHAR targetNameW[CREDUI_MAX_DOMAIN_TARGET_LENGTH + 1];
  689. WCHAR userName[CREDUI_MAX_USERNAME_LENGTH + 1];
  690. WCHAR password[CREDUI_MAX_PASSWORD_LENGTH + 1];
  691. CREDUI_INFOW uiInfoW = {0};
  692. if ((NULL == pszUserName) || (NULL == pszPassword))
  693. {
  694. result = ERROR_INVALID_PARAMETER;
  695. goto Exit;
  696. }
  697. // Convert in paramters to Unicode:
  698. // If a CREDUI_INFO structure was passed, convert it to wide now:
  699. if (uiInfo != NULL) {
  700. if (!CreduiConvertUiInfoToWide(uiInfo, &uiInfoW)) {
  701. result = ERROR_OUTOFMEMORY;
  702. goto Exit;
  703. }
  704. }
  705. // If a target name was passed, convert it to wide now:
  706. if (targetName != NULL)
  707. {
  708. if (MultiByteToWideChar(
  709. CP_ACP, 0, targetName, -1,
  710. targetNameW,
  711. CREDUI_MAX_DOMAIN_TARGET_LENGTH + 1) == 0)
  712. {
  713. result = ERROR_OUTOFMEMORY;
  714. goto Exit;
  715. }
  716. }
  717. userName[0] ='\0';
  718. password[0] = '\0';
  719. if (lstrlenA(pszUserName) > 0 )
  720. {
  721. if ( !MultiByteToWideChar( CP_ACP, 0, pszUserName, -1,
  722. userName, sizeof(userName)/sizeof(WCHAR) ) ) {
  723. result = ERROR_OUTOFMEMORY;
  724. goto Exit;
  725. }
  726. }
  727. if (lstrlenA(pszPassword) > 0)
  728. {
  729. if ( !MultiByteToWideChar( CP_ACP, 0, pszPassword, -1,
  730. password, sizeof(password)/sizeof(WCHAR) ) ) {
  731. result = ERROR_OUTOFMEMORY;
  732. goto Exit;
  733. }
  734. }
  735. //
  736. // Call the common code indicating this is the GUI interface
  737. //
  738. result = CredUIPromptForCredentialsWorker(
  739. FALSE, // GUI version
  740. (uiInfo != NULL) ? &uiInfoW : NULL,
  741. (targetName != NULL) ? targetNameW : NULL,
  742. securityContext,
  743. authError,
  744. userName,
  745. ulUserNameBufferSize,
  746. password,
  747. ulPasswordBufferSize,
  748. save,
  749. flags );
  750. if ( result == NO_ERROR && pszUserName != NULL )
  751. {
  752. if ( wcslen(userName) < ulUserNameBufferSize )
  753. {
  754. if (!WideCharToMultiByte(CP_ACP, 0, userName, -1, pszUserName,
  755. ulUserNameBufferSize, NULL, NULL) ) {
  756. CreduiDebugLog("CreduiPromptForCredentials: type username cannot be converted to ANSI.\n" );
  757. result = ERROR_INVALID_PARAMETER;
  758. }
  759. }
  760. else
  761. {
  762. CreduiDebugLog("CreduiPromptForCredentials: type username is too long.\n" );
  763. result = ERROR_INVALID_PARAMETER;
  764. }
  765. }
  766. if ( result == NO_ERROR && pszPassword != NULL )
  767. {
  768. if ( wcslen ( password ) < ulPasswordBufferSize )
  769. {
  770. if (!WideCharToMultiByte(CP_ACP, 0, password, -1, pszPassword,
  771. ulPasswordBufferSize, NULL, NULL) ) {
  772. CreduiDebugLog("CreduiPromptForCredentials: type password cannot be converted to ANSI.\n" );
  773. result = ERROR_INVALID_PARAMETER;
  774. }
  775. }
  776. else
  777. {
  778. CreduiDebugLog("CreduiPromptForCredentials: type password is too long.\n" );
  779. result = ERROR_INVALID_PARAMETER;
  780. }
  781. }
  782. Exit:
  783. ZeroMemory(password, sizeof(password) );
  784. // Free the CREDUI_INFO allocations:
  785. if (uiInfo != NULL)
  786. {
  787. if (uiInfoW.pszMessageText != NULL)
  788. {
  789. delete [] const_cast<WCHAR *>(uiInfoW.pszMessageText);
  790. }
  791. if (uiInfoW.pszCaptionText != NULL)
  792. {
  793. delete [] const_cast<WCHAR *>(uiInfoW.pszCaptionText);
  794. }
  795. }
  796. return result;
  797. }
  798. DWORD
  799. WINAPI
  800. CredUIParseUserNameW(
  801. CONST WCHAR *UserName,
  802. WCHAR *user,
  803. ULONG userBufferSize,
  804. WCHAR *domain,
  805. ULONG domainBufferSize
  806. )
  807. /*++
  808. Routine Description:
  809. CredUIParseUserName is used to breakup a username returned by the cred management APIs
  810. into a username and domain part that can be used as input to other system APIs that
  811. require the full broken-up user credential.
  812. The following formats are supported:
  813. @@<MarshalledCredentialReference>: This is a marshaled credential reference as
  814. as defined by the CredIsMarshaledCredential API. Such a credential is returned
  815. in the 'user' parameter. The 'domain' parameter is set to an empty string.
  816. <DomainName>\<UserName>: The <UserName> is returned in the 'user' parameter and
  817. the <DomainName> is returned in the 'domain' parameter. The name is considered
  818. to have the this syntax if the 'UserName' string contains a \.
  819. <UserName>@<DnsDomainName>: The entire string is returned in the 'user' parameter.
  820. The 'domain' parameter is set to an empty string.
  821. For this syntax, the last @ in the string is used since <UserName> may
  822. contain an @ but <DnsDomainName> cannot.
  823. <UserName>: The <UserName> is returned in the 'user' parameter.
  824. The 'domain' parameter is set to an empty string.
  825. Arguments:
  826. UserName - The user name to be parsed.
  827. user - Specifies a buffer to copy the user name portion of the parsed string to.
  828. userBufferSize - Specifies the size of the 'user' array in characters.
  829. The caller can ensure the passed in array is large enough by using an array
  830. that is CRED_MAX_USERNAME_LENGTH+1 characters long or by passing in an array that
  831. is wcslen(UserName)+1 characters long.
  832. domain - Specifies a buffer to copy the domain name portion of the parsed string to.
  833. domainBufferSize - Specifies the size of the 'domain' array in characters.
  834. The caller can ensure the passed in array is large enough by using an array
  835. that is CRED_MAX_USERNAME_LENGTH+1 characters long or by passing in an array that
  836. is wcslen(UserName)+1 characters long.
  837. Return Values:
  838. The following status codes may be returned:
  839. ERROR_INVALID_ACCOUNT_NAME - The user name is not valid.
  840. ERROR_INVALID_PARAMETER - One of the parameters is invalid.
  841. ERROR_INSUFFICIENT_BUFFER - One of the buffers is too small.
  842. --*/
  843. {
  844. DWORD Status;
  845. CREDUI_USERNAME_TYPE UsernameType;
  846. //
  847. // Use the low level routine to do the work
  848. //
  849. Status = CredUIParseUserNameWithType(
  850. UserName,
  851. user,
  852. userBufferSize,
  853. domain,
  854. domainBufferSize,
  855. &UsernameType );
  856. if ( Status != NO_ERROR ) {
  857. return Status;
  858. }
  859. //
  860. // Avoid relative user names (for backward compatibility)
  861. //
  862. if ( UsernameType == CreduiRelativeUsername ) {
  863. user[0] = L'\0';
  864. domain[0] = L'\0';
  865. return ERROR_INVALID_ACCOUNT_NAME;
  866. }
  867. return NO_ERROR;
  868. }
  869. DWORD
  870. WINAPI
  871. CredUIParseUserNameA(
  872. CONST CHAR *userName,
  873. CHAR *user,
  874. ULONG userBufferSize,
  875. CHAR *domain,
  876. ULONG domainBufferSize
  877. )
  878. /*++
  879. Routine Description:
  880. Ansi version of CredUIParseUserName.
  881. Arguments:
  882. Same as wide version except userBufferSize and domainBufferSize are in terms of bytes.
  883. Return Values:
  884. Same as wide version.
  885. --*/
  886. {
  887. DWORD Status;
  888. WCHAR LocalUserName[CRED_MAX_USERNAME_LENGTH + 1];
  889. WCHAR RetUserName[CRED_MAX_USERNAME_LENGTH + 1];
  890. WCHAR RetDomainName[CRED_MAX_USERNAME_LENGTH + 1];
  891. //
  892. // Convert the passed in username to unicode
  893. //
  894. if ( MultiByteToWideChar( CP_ACP,
  895. MB_ERR_INVALID_CHARS,
  896. userName,
  897. -1,
  898. LocalUserName,
  899. CRED_MAX_USERNAME_LENGTH + 1 ) == 0 ) {
  900. Status = GetLastError();
  901. goto Cleanup;
  902. }
  903. //
  904. // Call the unicode version of the API
  905. //
  906. Status = CredUIParseUserNameW(
  907. LocalUserName,
  908. RetUserName,
  909. CRED_MAX_USERNAME_LENGTH + 1,
  910. RetDomainName,
  911. CRED_MAX_USERNAME_LENGTH + 1 );
  912. if ( Status != NO_ERROR ) {
  913. goto Cleanup;
  914. }
  915. //
  916. // Convert the answers back to ANSI
  917. //
  918. if ( WideCharToMultiByte( CP_ACP,
  919. 0,
  920. RetUserName,
  921. -1,
  922. user,
  923. userBufferSize,
  924. NULL,
  925. NULL ) == 0 ) {
  926. Status = GetLastError();
  927. goto Cleanup;
  928. }
  929. if ( WideCharToMultiByte( CP_ACP,
  930. 0,
  931. RetDomainName,
  932. -1,
  933. domain,
  934. domainBufferSize,
  935. NULL,
  936. NULL ) == 0 ) {
  937. Status = GetLastError();
  938. goto Cleanup;
  939. }
  940. Status = NO_ERROR;
  941. Cleanup:
  942. if ( Status != NO_ERROR ) {
  943. user[0] = L'\0';
  944. domain[0] = L'\0';
  945. }
  946. return Status;
  947. }
  948. ////////////////////////
  949. // Command Line functions
  950. //=============================================================================
  951. // CredUIInitControls
  952. //
  953. // Returns TRUE on success or FALSE otherwise.
  954. //
  955. // Created 06/21/2000 johnstep (John Stephens)
  956. //=============================================================================
  957. extern "C"
  958. BOOL
  959. WINAPI
  960. CredUIInitControls()
  961. {
  962. if (CreduiApiInit())
  963. {
  964. // Register the Credential controls:
  965. if (CreduiCredentialControl::Register(CreduiInstance))
  966. {
  967. return TRUE;
  968. }
  969. }
  970. return FALSE;
  971. }
  972. //=============================================================================
  973. // DllMain
  974. //
  975. // The DLL entry function. Since we are linked to the CRT, we must define a
  976. // function with this name, which will be called from _DllMainCRTStartup.
  977. //
  978. // Arguments:
  979. // instance (in)
  980. // reason (in)
  981. // (unused)
  982. //
  983. // Returns TRUE on success, or FALSE otherwise.
  984. //
  985. // Created 02/29/2000 johnstep (John Stephens)
  986. //=============================================================================
  987. extern "C"
  988. BOOL
  989. WINAPI
  990. DllMain(
  991. HINSTANCE instance,
  992. DWORD reason,
  993. VOID *
  994. )
  995. {
  996. BOOL success = TRUE;
  997. switch (reason)
  998. {
  999. case DLL_PROCESS_ATTACH:
  1000. DisableThreadLibraryCalls(instance);
  1001. CreduiInstance = instance;
  1002. // Create a global event which will be set when first-time
  1003. // initialization is completed by the first API call:
  1004. CreduiInitEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  1005. if (CreduiInitEvent == NULL)
  1006. {
  1007. success = FALSE;
  1008. }
  1009. SHFusionInitialize(NULL);
  1010. // Register the Credential controls:
  1011. if (!CreduiCredentialControl::Register(instance))
  1012. {
  1013. CloseHandle(CreduiInitEvent);
  1014. CreduiInitEvent = NULL;
  1015. success = FALSE;
  1016. }
  1017. // InitializeCredMgr();
  1018. //
  1019. // Initialize the confirmation list
  1020. //
  1021. if ( !InitConfirmationList() ) {
  1022. CreduiCredentialControl::Unregister();
  1023. CloseHandle(CreduiInitEvent);
  1024. CreduiInitEvent = NULL;
  1025. success = FALSE;
  1026. }
  1027. break;
  1028. case DLL_PROCESS_DETACH:
  1029. CleanUpConfirmationList();
  1030. if (CreduiFirstTime == FALSE)
  1031. {
  1032. CreduiIconParentWindow::Unregister();
  1033. }
  1034. // Unregister the Credential controls:
  1035. CreduiCredentialControl::Unregister();
  1036. SHFusionUninitialize();
  1037. // Make sure to free the global initialization event:
  1038. if (CreduiInitEvent != NULL)
  1039. {
  1040. CloseHandle(CreduiInitEvent);
  1041. }
  1042. UninitializeCredMgr();
  1043. break;
  1044. };
  1045. return success;
  1046. }
  1047. //=============================================================================
  1048. // DllCanUnloadNow (COM)
  1049. //
  1050. // Created 04/03/2000 johnstep (John Stephens)
  1051. //=============================================================================
  1052. STDAPI
  1053. DllCanUnloadNow()
  1054. {
  1055. return (CreduiComReferenceCount == 0) ? S_OK : S_FALSE;
  1056. }
  1057. //=============================================================================
  1058. // DllGetClassObject (COM)
  1059. //
  1060. // Created 04/03/2000 johnstep (John Stephens)
  1061. //=============================================================================
  1062. STDAPI
  1063. DllGetClassObject(
  1064. CONST CLSID &classId,
  1065. CONST IID &interfaceId,
  1066. VOID **outInterface
  1067. )
  1068. {
  1069. if (classId != CreduiStringArrayClassId)
  1070. {
  1071. return CLASS_E_CLASSNOTAVAILABLE;
  1072. }
  1073. CreduiStringArrayFactory *factory = new CreduiStringArrayFactory;
  1074. if (factory == NULL)
  1075. {
  1076. return E_OUTOFMEMORY;
  1077. }
  1078. HRESULT result = factory->QueryInterface(interfaceId, outInterface);
  1079. factory->Release();
  1080. // Release the string array object in any case, because of the
  1081. // QueryInterface succeeded, it already took another reference count on
  1082. // the object:
  1083. return result;
  1084. }
  1085. //=============================================================================
  1086. // DllRegisterServer (COM)
  1087. //
  1088. // Created 04/03/2000 johnstep (John Stephens)
  1089. //=============================================================================
  1090. STDAPI
  1091. DllRegisterServer()
  1092. {
  1093. HRESULT result = E_FAIL;
  1094. WCHAR fileName[MAX_PATH + 1];
  1095. if (GetModuleFileName(CreduiInstance, fileName, MAX_PATH))
  1096. {
  1097. HKEY regKey;
  1098. if (RegCreateKeyEx(
  1099. HKEY_CLASSES_ROOT,
  1100. L"CLSID\\" CREDUI_STRING_ARRAY_CLASS_STRING
  1101. L"\\InProcServer32",
  1102. 0,
  1103. NULL,
  1104. REG_OPTION_NON_VOLATILE,
  1105. KEY_SET_VALUE,
  1106. NULL,
  1107. &regKey,
  1108. NULL) == ERROR_SUCCESS)
  1109. {
  1110. if (RegSetValueEx(
  1111. regKey,
  1112. NULL,
  1113. 0,
  1114. REG_SZ,
  1115. reinterpret_cast<CONST BYTE *>(fileName),
  1116. (lstrlen(fileName) + 1) * 2) == ERROR_SUCCESS)
  1117. {
  1118. if (RegSetValueEx(
  1119. regKey,
  1120. L"ThreadingModel",
  1121. 0,
  1122. REG_SZ,
  1123. reinterpret_cast<CONST BYTE *>(L"Apartment"),
  1124. 18) == ERROR_SUCCESS)
  1125. {
  1126. result = S_OK;
  1127. }
  1128. }
  1129. RegCloseKey(regKey);
  1130. }
  1131. }
  1132. return result;
  1133. }
  1134. //=============================================================================
  1135. // DllUnregisterServer (COM)
  1136. //
  1137. // Created 04/03/2000 johnstep (John Stephens)
  1138. //=============================================================================
  1139. STDAPI
  1140. DllUnregisterServer()
  1141. {
  1142. HRESULT result = S_OK;
  1143. LONG error;
  1144. // Delete our InProcServer32 key:
  1145. error =
  1146. RegDeleteKey(
  1147. HKEY_CLASSES_ROOT,
  1148. L"CLSID\\" CREDUI_STRING_ARRAY_CLASS_STRING L"\\InProcServer32");
  1149. if ((error != ERROR_SUCCESS) &&
  1150. (error != ERROR_FILE_NOT_FOUND))
  1151. {
  1152. result = E_FAIL;
  1153. }
  1154. // Delete our class ID key:
  1155. error =
  1156. RegDeleteKey(
  1157. HKEY_CLASSES_ROOT,
  1158. L"CLSID\\" CREDUI_STRING_ARRAY_CLASS_STRING);
  1159. if ((error != ERROR_SUCCESS) &&
  1160. (error != ERROR_FILE_NOT_FOUND))
  1161. {
  1162. result = E_FAIL;
  1163. }
  1164. return result;
  1165. }
  1166. CREDUIAPI
  1167. DWORD
  1168. WINAPI
  1169. CredUIConfirmCredentialsW(
  1170. PCWSTR pszTargetName,
  1171. BOOL bConfirm
  1172. )
  1173. {
  1174. return ConfirmCred ( pszTargetName, bConfirm, TRUE );
  1175. }
  1176. CREDUIAPI
  1177. DWORD
  1178. WINAPI
  1179. CredUIConfirmCredentialsA(
  1180. PCSTR pszTargetName,
  1181. BOOL bConfirm
  1182. )
  1183. {
  1184. WCHAR targetNameW[CRED_MAX_STRING_LENGTH+1+CRED_MAX_STRING_LENGTH];
  1185. // If a target name was passed, convert it to wide now:
  1186. if (pszTargetName != NULL)
  1187. {
  1188. if (MultiByteToWideChar(
  1189. CP_ACP, 0, pszTargetName, -1,
  1190. targetNameW,
  1191. CRED_MAX_STRING_LENGTH+1+CRED_MAX_STRING_LENGTH) == 0)
  1192. {
  1193. return GetLastError();
  1194. }
  1195. }
  1196. return CredUIConfirmCredentialsW ( targetNameW, bConfirm );
  1197. }
  1198. CREDUIAPI
  1199. DWORD
  1200. WINAPI
  1201. CredUICmdLinePromptForCredentialsW(
  1202. PCWSTR targetName,
  1203. PCtxtHandle securityContext,
  1204. DWORD dwAuthError,
  1205. PWSTR UserName,
  1206. ULONG ulUserBufferSize,
  1207. PWSTR pszPassword,
  1208. ULONG ulPasswordBufferSize,
  1209. PBOOL pfSave,
  1210. DWORD flags
  1211. )
  1212. {
  1213. //
  1214. // Call the common code indicating this is the command line interface
  1215. //
  1216. return CredUIPromptForCredentialsWorker(
  1217. TRUE, // Command line version
  1218. NULL, // Command line version has no uiInfo,
  1219. targetName,
  1220. securityContext,
  1221. dwAuthError,
  1222. UserName,
  1223. ulUserBufferSize,
  1224. pszPassword,
  1225. ulPasswordBufferSize,
  1226. pfSave,
  1227. flags );
  1228. }
  1229. CREDUIAPI
  1230. DWORD
  1231. WINAPI
  1232. CredUICmdLinePromptForCredentialsA(
  1233. PCSTR targetName,
  1234. PCtxtHandle pContext,
  1235. DWORD dwAuthError,
  1236. PSTR UserName,
  1237. ULONG ulUserBufferSize,
  1238. PSTR pszPassword,
  1239. ULONG ulPasswordBufferSize,
  1240. PBOOL pfSave,
  1241. DWORD flags
  1242. )
  1243. {
  1244. DWORD result = ERROR_GEN_FAILURE;
  1245. INT targetNameLength = lstrlenA(targetName);
  1246. WCHAR *targetNameW = NULL;
  1247. if (!CreduiApiInit())
  1248. {
  1249. return ERROR_GEN_FAILURE;
  1250. }
  1251. // convert to unicode
  1252. WCHAR userNameW[CREDUI_MAX_USERNAME_LENGTH + 1];
  1253. WCHAR *pUserNameW;
  1254. if ( UserName != NULL )
  1255. {
  1256. if (MultiByteToWideChar(CP_ACP, 0, UserName, -1,
  1257. userNameW, sizeof(userNameW)/sizeof(WCHAR)) == 0)
  1258. {
  1259. result = GetLastError();
  1260. goto Exit;
  1261. }
  1262. pUserNameW = userNameW;
  1263. }
  1264. else
  1265. {
  1266. pUserNameW = NULL;
  1267. }
  1268. WCHAR passwordW[CREDUI_MAX_PASSWORD_LENGTH + 1];
  1269. WCHAR *ppasswordW;
  1270. if ( pszPassword != NULL )
  1271. {
  1272. if (MultiByteToWideChar(CP_ACP, 0, pszPassword, -1,
  1273. passwordW, sizeof(passwordW)/sizeof(WCHAR)) == 0)
  1274. {
  1275. result = GetLastError();
  1276. goto Exit;
  1277. }
  1278. ppasswordW = passwordW;
  1279. }
  1280. else
  1281. {
  1282. ppasswordW = NULL;
  1283. }
  1284. // Allocate the target name memory because it can be up to 32 KB:
  1285. if (targetName != NULL)
  1286. {
  1287. targetNameW = new WCHAR[targetNameLength + 1];
  1288. if (targetNameW != NULL)
  1289. {
  1290. if (MultiByteToWideChar(CP_ACP, 0, targetName, -1,
  1291. targetNameW, sizeof(targetNameW)/sizeof(WCHAR)) == 0)
  1292. {
  1293. result = GetLastError();
  1294. goto Exit;
  1295. }
  1296. }
  1297. else
  1298. {
  1299. result = ERROR_NOT_ENOUGH_MEMORY;
  1300. goto Exit;
  1301. }
  1302. }
  1303. else
  1304. {
  1305. targetNameW = NULL;
  1306. }
  1307. result = CredUICmdLinePromptForCredentialsW ( targetNameW,
  1308. pContext,
  1309. dwAuthError,
  1310. userNameW,
  1311. ulUserBufferSize,
  1312. passwordW,
  1313. ulPasswordBufferSize,
  1314. pfSave,
  1315. flags );
  1316. if ( UserName != NULL )
  1317. {
  1318. if ( wcslen(userNameW) < ulUserBufferSize )
  1319. {
  1320. if (!WideCharToMultiByte(CP_ACP, 0, userNameW, -1, UserName,
  1321. ulUserBufferSize, NULL, NULL) ) {
  1322. result = GetLastError();
  1323. goto Exit;
  1324. }
  1325. }
  1326. else
  1327. {
  1328. CreduiDebugLog("CreduiPromptForCredentials: typed username is too long.\n" );
  1329. result = ERROR_INVALID_PARAMETER;
  1330. goto Exit;
  1331. }
  1332. }
  1333. if ( pszPassword != NULL )
  1334. {
  1335. if ( wcslen ( passwordW ) < ulPasswordBufferSize )
  1336. {
  1337. if (!WideCharToMultiByte(CP_ACP, 0, passwordW, -1, pszPassword,
  1338. ulPasswordBufferSize, NULL, NULL)) {
  1339. result = GetLastError();
  1340. goto Exit;
  1341. }
  1342. }
  1343. else
  1344. {
  1345. CreduiDebugLog("CreduiPromptForCredentials: typed password is too long.\n" );
  1346. result = ERROR_INVALID_PARAMETER;
  1347. goto Exit;
  1348. }
  1349. }
  1350. Exit:
  1351. ZeroMemory(passwordW, sizeof(passwordW) );
  1352. // Free the target name memory:
  1353. if (targetNameW != NULL)
  1354. {
  1355. delete [] targetNameW;
  1356. }
  1357. return result;
  1358. }
  1359. // call this api to store a single-sign-on credential
  1360. // retruns ERROR_SUCCESS if success
  1361. CREDUIAPI
  1362. DWORD
  1363. WINAPI
  1364. CredUIStoreSSOCredW (
  1365. PCWSTR pszRealm,
  1366. PCWSTR pszUsername,
  1367. PCWSTR pszPassword,
  1368. BOOL bPersist
  1369. )
  1370. {
  1371. DWORD dwResult = ERROR_GEN_FAILURE;
  1372. if ( pszUsername == NULL || pszPassword == NULL )
  1373. return dwResult;
  1374. WCHAR szTargetName[CREDUI_MAX_DOMAIN_TARGET_LENGTH];
  1375. PVOID password = (PVOID)pszPassword;
  1376. // temporarily cache them locally
  1377. wcsncpy ( gszSSOUserName, pszUsername, CREDUI_MAX_USERNAME_LENGTH );
  1378. wcsncpy ( gszSSOPassword, pszPassword, CREDUI_MAX_PASSWORD_LENGTH );
  1379. gbStoredSSOCreds = TRUE;
  1380. if ( gbWaitingForSSOCreds || !bPersist)
  1381. {
  1382. dwResult = ERROR_SUCCESS;
  1383. }
  1384. else
  1385. {
  1386. // otherwise store them in credmgr
  1387. if ( pszRealm )
  1388. {
  1389. // validate it's not zero length
  1390. int len = wcslen(pszRealm);
  1391. if ( len == 0 || len > CREDUI_MAX_DOMAIN_TARGET_LENGTH - 3 )
  1392. {
  1393. return ERROR_INVALID_PARAMETER;
  1394. }
  1395. wcsncpy ( szTargetName, pszRealm, len+1 );
  1396. }
  1397. else
  1398. {
  1399. GetDeaultSSORealm(szTargetName, TRUE);
  1400. }
  1401. // finalize the target name
  1402. wcscat ( szTargetName, L"\\*" );
  1403. // encrypt the password
  1404. PVOID pEncryptedPassword;
  1405. DWORD dwESize = wcslen(pszPassword)+1;
  1406. DWORD dwEncrypt = EncryptPassword ( (PWSTR)pszPassword, &pEncryptedPassword, &dwESize );
  1407. if ( dwEncrypt == ERROR_SUCCESS )
  1408. {
  1409. password = pEncryptedPassword;
  1410. }
  1411. // write it out
  1412. CREDENTIALW NewCredential;
  1413. memset ( (void*)&NewCredential, 0, sizeof(CREDENTIALW));
  1414. DWORD dwFlags = 0;
  1415. NewCredential.TargetName = szTargetName;
  1416. NewCredential.Type = CRED_TYPE_DOMAIN_VISIBLE_PASSWORD;
  1417. NewCredential.Persist = bPersist ? CRED_PERSIST_ENTERPRISE : CRED_PERSIST_SESSION;
  1418. NewCredential.Flags = 0;
  1419. NewCredential.CredentialBlobSize = dwESize;
  1420. NewCredential.UserName = (LPWSTR)pszUsername;
  1421. NewCredential.CredentialBlob = reinterpret_cast<BYTE *>(password);
  1422. if ( CredWriteW(&NewCredential, dwFlags))
  1423. {
  1424. dwResult = ERROR_SUCCESS;
  1425. }
  1426. if ( dwEncrypt == ERROR_SUCCESS )
  1427. {
  1428. LocalFree (pEncryptedPassword);
  1429. }
  1430. }
  1431. return dwResult;
  1432. }
  1433. CREDUIAPI
  1434. DWORD
  1435. WINAPI
  1436. CredUIStoreSSOCredA (
  1437. PCSTR pszRealm,
  1438. PCSTR pszUsername,
  1439. PCSTR pszPassword,
  1440. BOOL bPersist
  1441. )
  1442. {
  1443. DWORD dwResult = ERROR_GEN_FAILURE;
  1444. // convert to unicode
  1445. WCHAR realmW[CREDUI_MAX_DOMAIN_TARGET_LENGTH];
  1446. WCHAR *prealmW;
  1447. if ( pszRealm != NULL )
  1448. {
  1449. if (MultiByteToWideChar(CP_ACP, 0, pszRealm, -1,
  1450. realmW, lstrlenA(pszRealm) + 1) == 0)
  1451. {
  1452. goto Exit;
  1453. }
  1454. prealmW = realmW;
  1455. }
  1456. else
  1457. {
  1458. prealmW = NULL;
  1459. }
  1460. WCHAR userNameW[CREDUI_MAX_USERNAME_LENGTH + 1];
  1461. WCHAR *pUserNameW;
  1462. if ( pszUsername != NULL )
  1463. {
  1464. if (MultiByteToWideChar(CP_ACP, 0, pszUsername, -1,
  1465. userNameW, lstrlenA(pszUsername) + 1) == 0)
  1466. {
  1467. goto Exit;
  1468. }
  1469. pUserNameW = userNameW;
  1470. }
  1471. else
  1472. {
  1473. pUserNameW = NULL;
  1474. }
  1475. WCHAR passwordW[CREDUI_MAX_PASSWORD_LENGTH + 1];
  1476. WCHAR *ppasswordW;
  1477. if ( pszPassword != NULL )
  1478. {
  1479. if (MultiByteToWideChar(CP_ACP, 0, pszPassword, -1,
  1480. passwordW, lstrlenA(pszPassword) + 1) == 0)
  1481. {
  1482. goto Exit;
  1483. }
  1484. ppasswordW = passwordW;
  1485. }
  1486. else
  1487. {
  1488. ppasswordW = NULL;
  1489. }
  1490. dwResult = CredUIStoreSSOCredW ( prealmW, pUserNameW, ppasswordW, bPersist );
  1491. Exit:
  1492. // clean up passwords in memory
  1493. ZeroMemory(passwordW, CREDUI_MAX_PASSWORD_LENGTH * sizeof (WCHAR) + 1);
  1494. return dwResult;
  1495. }
  1496. // call this api to retrieve the username for a single-sign-on credential
  1497. // retruns ERROR_SUCCESS if success, ERROR_NOT_FOUND if none was found
  1498. CREDUIAPI
  1499. DWORD
  1500. WINAPI
  1501. CredUIReadSSOCredW (
  1502. PCWSTR pszRealm,
  1503. PWSTR* ppszUsername
  1504. )
  1505. {
  1506. DWORD dwReturn = ERROR_NOT_FOUND;
  1507. WCHAR szTargetName[CREDUI_MAX_DOMAIN_TARGET_LENGTH];
  1508. if ( pszRealm )
  1509. {
  1510. // validate it's not zero length
  1511. int len = wcslen(pszRealm);
  1512. if ( len == 0 || len > CREDUI_MAX_DOMAIN_TARGET_LENGTH - 3 )
  1513. {
  1514. return ERROR_INVALID_PARAMETER;
  1515. }
  1516. wcsncpy ( szTargetName, pszRealm, len+1 );
  1517. }
  1518. else
  1519. {
  1520. GetDeaultSSORealm(szTargetName, FALSE);
  1521. }
  1522. if ( wcslen ( szTargetName ) != 0 )
  1523. {
  1524. // finalize the target name
  1525. wcscat ( szTargetName, L"\\*" );
  1526. PCREDENTIALW pCred;
  1527. DWORD dwFlags = 0;
  1528. if ( CredReadW ( szTargetName,
  1529. CRED_TYPE_DOMAIN_VISIBLE_PASSWORD,
  1530. dwFlags,
  1531. &pCred ) )
  1532. {
  1533. *ppszUsername = (PWSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WCHAR)*(wcslen(pCred->UserName)+1));
  1534. if ( *ppszUsername )
  1535. {
  1536. dwReturn = ERROR_SUCCESS;
  1537. wcscpy ( *ppszUsername, pCred->UserName );
  1538. }
  1539. CredFree ( pCred );
  1540. }
  1541. }
  1542. return dwReturn;
  1543. }
  1544. // call this api to retrieve the username for a single-sign-on credential
  1545. // retruns ERROR_SUCCESS if success, ERROR_NOT_FOUND if none was found
  1546. CREDUIAPI
  1547. DWORD
  1548. WINAPI
  1549. CredUIReadSSOCredA (
  1550. PCSTR pszRealm,
  1551. PSTR* ppszUsername
  1552. )
  1553. {
  1554. DWORD dwReturn = ERROR_NOT_FOUND;
  1555. WCHAR szTargetName[CREDUI_MAX_DOMAIN_TARGET_LENGTH];
  1556. PCREDENTIALW pCred;
  1557. DWORD dwFlags = 0;
  1558. if ( pszRealm )
  1559. {
  1560. // validate it's not zero length
  1561. int len = lstrlenA(pszRealm);
  1562. if ( len == 0 || len > CREDUI_MAX_DOMAIN_TARGET_LENGTH - 3 )
  1563. {
  1564. return ERROR_INVALID_PARAMETER;
  1565. }
  1566. if (MultiByteToWideChar(CP_ACP, 0, pszRealm, -1,
  1567. szTargetName, len + 1) == 0)
  1568. {
  1569. goto Exit;
  1570. }
  1571. }
  1572. else
  1573. {
  1574. GetDeaultSSORealm(szTargetName, FALSE);
  1575. }
  1576. if ( wcslen ( szTargetName ) != 0 )
  1577. {
  1578. // finalize the target name
  1579. wcscat ( szTargetName, L"\\*" );
  1580. // first call credmgr to set the target info
  1581. if ( CredReadW ( szTargetName,
  1582. CRED_TYPE_DOMAIN_VISIBLE_PASSWORD,
  1583. dwFlags,
  1584. &pCred ) )
  1585. {
  1586. DWORD dwLen = wcslen(pCred->UserName);
  1587. *ppszUsername = (PSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHAR)*(dwLen+1));
  1588. if ( *ppszUsername )
  1589. {
  1590. WideCharToMultiByte(CP_ACP, 0, pCred->UserName, -1, *ppszUsername,
  1591. dwLen, NULL, NULL);
  1592. dwReturn = ERROR_SUCCESS;
  1593. }
  1594. CredFree ( pCred );
  1595. }
  1596. }
  1597. Exit:
  1598. return dwReturn;
  1599. }