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.

2040 lines
56 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. (wcslen(uiInfo->pszMessageText) > CREDUI_MAX_MESSAGE_LENGTH))
  283. {
  284. return FALSE;
  285. }
  286. if ((uiInfo->pszCaptionText != NULL) &&
  287. (wcslen(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. INT bufferSize;
  325. if (uiInfoA->pszMessageText != NULL)
  326. {
  327. bufferSize =
  328. MultiByteToWideChar(
  329. CP_ACP, 0, uiInfoA->pszMessageText, -1, NULL, 0);
  330. if (bufferSize == 0)
  331. {
  332. goto ErrorExit;
  333. }
  334. uiInfoW->pszMessageText = new WCHAR[bufferSize];
  335. if (uiInfoW->pszMessageText == NULL)
  336. {
  337. goto ErrorExit;
  338. }
  339. if (MultiByteToWideChar(
  340. CP_ACP, 0, uiInfoA->pszMessageText, -1,
  341. const_cast<WCHAR *>(uiInfoW->pszMessageText),
  342. bufferSize) == 0)
  343. {
  344. goto ErrorExit;
  345. }
  346. }
  347. else
  348. {
  349. uiInfoW->pszMessageText = NULL;
  350. }
  351. if (uiInfoA->pszCaptionText != NULL)
  352. {
  353. bufferSize =
  354. MultiByteToWideChar(
  355. CP_ACP, 0, uiInfoA->pszCaptionText, -1, NULL, 0);
  356. if (bufferSize == 0)
  357. {
  358. goto ErrorExit;
  359. }
  360. uiInfoW->pszCaptionText = new WCHAR[bufferSize];
  361. if (uiInfoW->pszCaptionText == NULL)
  362. {
  363. goto ErrorExit;
  364. }
  365. if (MultiByteToWideChar(
  366. CP_ACP, 0, uiInfoA->pszCaptionText, -1,
  367. const_cast<WCHAR *>(uiInfoW->pszCaptionText),
  368. bufferSize) == 0)
  369. {
  370. goto ErrorExit;
  371. }
  372. }
  373. else
  374. {
  375. uiInfoW->pszCaptionText = NULL;
  376. }
  377. return TRUE;
  378. ErrorExit:
  379. if (uiInfoW->pszCaptionText != NULL)
  380. {
  381. delete [] const_cast<WCHAR *>(uiInfoW->pszCaptionText);
  382. uiInfoW->pszCaptionText = NULL;
  383. }
  384. if (uiInfoW->pszMessageText != NULL)
  385. {
  386. delete [] const_cast<WCHAR *>(uiInfoW->pszMessageText);
  387. uiInfoW->pszMessageText = NULL;
  388. }
  389. return FALSE;
  390. }
  391. //=============================================================================
  392. // CredUIPromptForCredentials
  393. //
  394. // Presents a user interface to get credentials from an application.
  395. //
  396. // CredUIPromptForCredentialsW for wide
  397. // CredUIPromptForCredentialsA for ANSI
  398. //
  399. // Arguments:
  400. // uiInfo (in,optional)
  401. // targetName (in) - if specified, securityContext must be NULL
  402. // securityContext (in) - if specified, targetName must be NULL
  403. // error (in) - the authentication error
  404. // userName (in,out)
  405. // userNameBufferSize (in) - maximum length of userName
  406. // password (in,out)
  407. // passwordBufferSize (in) - maximum length of password
  408. // save (in/out) - TRUE if save check box was checked
  409. // flags (in)
  410. //
  411. // Returns:
  412. // ERROR_SUCCESS
  413. // ERROR_CANCELLED
  414. // ERROR_NO_SUCH_LOGON_SESSION - if credential manager cannot be used
  415. // ERROR_GEN_FAILURE
  416. // ERROR_INVALID_FLAGS
  417. // ERROR_INVALID_PARAMETER
  418. // ERROR_OUTOFMEMORY
  419. //
  420. // Created 10/17/2000 johnhaw
  421. DWORD
  422. CredUIPromptForCredentialsWorker(
  423. IN BOOL doingCommandLine,
  424. CREDUI_INFOW *uiInfo,
  425. CONST WCHAR *targetName,
  426. CtxtHandle *securityContext,
  427. DWORD authError,
  428. PWSTR pszUserName,
  429. ULONG ulUserNameBufferSize,
  430. PWSTR pszPassword,
  431. ULONG ulPasswordBufferSize,
  432. BOOL *save,
  433. DWORD flags
  434. )
  435. /*++
  436. Routine Description:
  437. This routine implements the GUI and command line prompt for credentials.
  438. Arguments:
  439. DoingCommandLine - TRUE if prompting is to be done via the command line
  440. FALSE if prompting is to be done via GUI
  441. ... - Other parameters are the same a CredUIPromptForCredentials API
  442. Return Values:
  443. Same as CredUIPromptForCredentials.
  444. --*/
  445. {
  446. ULONG CertFlags;
  447. ULONG CredCategory;
  448. ULONG PersistFlags;
  449. CreduiDebugLog("CUIPFCWorker: Flags: %x, Target: %S doingCommandLine: %i\n", flags, targetName, doingCommandLine);
  450. if ((NULL == pszUserName) || (NULL == pszPassword))
  451. {
  452. return ERROR_INVALID_PARAMETER;
  453. }
  454. if (!CreduiApiInit())
  455. {
  456. return ERROR_GEN_FAILURE;
  457. }
  458. // Validate arguments:
  459. if ((flags & ~CREDUI_FLAGS_PROMPT_VALID) != 0)
  460. {
  461. CreduiDebugLog("CreduiPromptForCredentials: flags not valid %lx.\n", flags );
  462. return ERROR_INVALID_FLAGS;
  463. }
  464. //
  465. // Ensure there is is only one bit defining cert support
  466. //
  467. CertFlags = flags & (CREDUI_FLAGS_REQUIRE_SMARTCARD|CREDUI_FLAGS_REQUIRE_CERTIFICATE|CREDUI_FLAGS_EXCLUDE_CERTIFICATES);
  468. if ( CertFlags != 0 && !JUST_ONE_BIT(CertFlags) ) {
  469. CreduiDebugLog("CreduiPromptForCredentials: require smartcard, require certificate, and exclude certificates are mutually exclusive %lx.\n", flags );
  470. return ERROR_INVALID_FLAGS;
  471. }
  472. //
  473. // For the command line version,
  474. // limit cert support further.
  475. //
  476. if ( doingCommandLine ) {
  477. if ( CertFlags == 0 ||
  478. (CertFlags & CREDUI_FLAGS_REQUIRE_CERTIFICATE) != 0 ) {
  479. CreduiDebugLog("CreduiPromptForCredentials: need either require smartcard or exclude certificates for command line %lx.\n", flags );
  480. return ERROR_INVALID_FLAGS;
  481. }
  482. }
  483. //
  484. // Ensure there is only one bit defining the credential category
  485. CredCategory = flags & (CREDUI_FLAGS_GENERIC_CREDENTIALS|CREDUI_FLAGS_USERNAME_TARGET_CREDENTIALS);
  486. if ( CredCategory != 0 && !JUST_ONE_BIT(CredCategory) ) {
  487. CreduiDebugLog("CreduiPromptForCredentials: generic creds and username target are mutually exclusive %lx.\n", flags );
  488. return ERROR_INVALID_FLAGS;
  489. }
  490. //
  491. // Ensure there is only one bit set saying whether the cred is to persist or not
  492. //
  493. PersistFlags = flags & (CREDUI_FLAGS_DO_NOT_PERSIST|CREDUI_FLAGS_PERSIST);
  494. if ( PersistFlags != 0 && !JUST_ONE_BIT(PersistFlags) ) {
  495. CreduiDebugLog("CreduiPromptForCredentials: DoNotPersist and Persist are mutually exclusive %lx.\n", flags );
  496. return ERROR_INVALID_FLAGS;
  497. }
  498. //
  499. // Ensure AlwaysShowUi is only specified for generic credentials
  500. //
  501. if ( flags & CREDUI_FLAGS_ALWAYS_SHOW_UI ) {
  502. if ( (flags & CREDUI_FLAGS_GENERIC_CREDENTIALS) == 0) {
  503. CreduiDebugLog("CreduiPromptForCredentials: AlwaysShowUi is only supported for generic credentials %lx.\n", flags );
  504. return ERROR_INVALID_FLAGS;
  505. }
  506. }
  507. //
  508. // Don't support a half-implemented feature
  509. //
  510. if ( securityContext != NULL ) {
  511. CreduiDebugLog("CreduiPromptForCredentials: securityContext must be null.\n" );
  512. return ERROR_INVALID_PARAMETER;
  513. }
  514. //
  515. // Validate the passed in UI info
  516. //
  517. if (!CreduiValidateUiInfoW(uiInfo))
  518. {
  519. CreduiDebugLog("CreduiPromptForCredentials: UI info is invalid.\n" );
  520. return ERROR_INVALID_PARAMETER;
  521. }
  522. //
  523. // Ensure there are strings defined for the caption
  524. //
  525. if (flags & CREDUI_FLAGS_DO_NOT_PERSIST)
  526. {
  527. if ((targetName == NULL) &&
  528. ((uiInfo == NULL) ||
  529. (uiInfo->pszMessageText == NULL) ||
  530. (uiInfo->pszCaptionText == NULL)))
  531. {
  532. CreduiDebugLog("CreduiPromptForCredentials: DoNotPersist and target data empty.\n" );
  533. return ERROR_INVALID_PARAMETER;
  534. }
  535. }
  536. else if (targetName != NULL)
  537. {
  538. if ((securityContext != NULL) ||
  539. (targetName[0] == L'\0') ||
  540. (wcslen(targetName) > CREDUI_MAX_DOMAIN_TARGET_LENGTH))
  541. {
  542. CreduiDebugLog("CreduiPromptForCredentials: target name bad %ws.\n", targetName );
  543. return ERROR_INVALID_PARAMETER;
  544. }
  545. }
  546. else if (securityContext == NULL)
  547. {
  548. CreduiDebugLog("CreduiPromptForCredentials: no target data.\n" );
  549. return ERROR_INVALID_PARAMETER;
  550. }
  551. //
  552. // Ensure the caller supplied the default value for the save check box
  553. //
  554. if (flags & CREDUI_FLAGS_SHOW_SAVE_CHECK_BOX)
  555. {
  556. if (save == NULL)
  557. {
  558. CreduiDebugLog("CreduiPromptForCredentials: ShowSaveCheckbox and save is NULL.\n" );
  559. return ERROR_INVALID_PARAMETER;
  560. }
  561. }
  562. //
  563. // Ensure the user supplied a username if they set CREDUI_FLAGS_KEEP_USERNAME
  564. //
  565. if ( flags & CREDUI_FLAGS_KEEP_USERNAME )
  566. {
  567. if ( pszUserName == NULL )
  568. {
  569. CreduiDebugLog("CreduiPromptForCredentials: CREDUI_FLAGS_KEEP_USERNAME and pszUserName is NULL.\n" );
  570. return ERROR_INVALID_PARAMETER;
  571. }
  572. }
  573. // Use the stack for user name and password:
  574. WCHAR userName[CREDUI_MAX_USERNAME_LENGTH + 1];
  575. WCHAR password[CREDUI_MAX_PASSWORD_LENGTH + 1];
  576. ZeroMemory(userName, sizeof userName);
  577. ZeroMemory(password, sizeof password);
  578. DWORD result = ERROR_OUTOFMEMORY;
  579. if (FAILED(StringCchCopyW(userName, RTL_NUMBER_OF(userName), pszUserName)) ||
  580. FAILED(StringCchCopyW(password, RTL_NUMBER_OF(password), pszPassword)))
  581. {
  582. result = ERROR_INVALID_PARAMETER;
  583. goto Cleanup;
  584. }
  585. // Do the password dialog box:
  586. //
  587. // Delay actually writing the credential to cred man if we're returning
  588. // the credential to the caller.
  589. // Otherwise, the CredWrite is just harvesting credentials for the next caller.
  590. // So delay the CredWrite until this caller confirms the validity.
  591. //
  592. CreduiPasswordDialog* pDlg = new CreduiPasswordDialog(
  593. doingCommandLine,
  594. (pszUserName != NULL && pszPassword != NULL ),
  595. CredCategory,
  596. uiInfo,
  597. targetName,
  598. userName,
  599. sizeof(userName)/sizeof(WCHAR)-sizeof(WCHAR), // Pass MaxChars instead of buffer size
  600. password,
  601. sizeof(password)/sizeof(WCHAR)-sizeof(WCHAR), // Pass MaxChars instead of buffer size
  602. save,
  603. flags,
  604. (flags & CREDUI_FLAGS_GENERIC_CREDENTIALS) ? NULL : securityContext,
  605. authError,
  606. &result);
  607. if ( pDlg != NULL )
  608. {
  609. delete pDlg;
  610. pDlg = NULL;
  611. }
  612. else
  613. {
  614. // couldn't create dialog, return.
  615. result = ERROR_OUTOFMEMORY;
  616. goto Cleanup;
  617. }
  618. // copy outbound username
  619. if ( pszUserName != NULL )
  620. {
  621. if (FAILED(StringCchCopyExW(
  622. pszUserName,
  623. ulUserNameBufferSize,
  624. userName,
  625. NULL,
  626. NULL,
  627. STRSAFE_FILL_ON_FAILURE)))
  628. {
  629. CreduiDebugLog("CreduiPromptForCredentials: type username is too long.\n" );
  630. result = ERROR_INVALID_PARAMETER;
  631. goto Cleanup;
  632. }
  633. }
  634. if ( pszPassword != NULL )
  635. {
  636. if (FAILED(StringCchCopyExW(
  637. pszPassword,
  638. ulPasswordBufferSize,
  639. password,
  640. NULL,
  641. NULL,
  642. STRSAFE_FILL_ON_FAILURE)))
  643. {
  644. CreduiDebugLog("CreduiPromptForCredentials: type password is too long.\n" );
  645. result = ERROR_INVALID_PARAMETER;
  646. goto Cleanup;
  647. }
  648. }
  649. Cleanup:
  650. SecureZeroMemory(password, sizeof password);
  651. return result;
  652. }
  653. //=============================================================================
  654. CREDUIAPI
  655. DWORD
  656. WINAPI
  657. CredUIPromptForCredentialsW(
  658. CREDUI_INFOW *uiInfo,
  659. CONST WCHAR *targetName,
  660. CtxtHandle *securityContext,
  661. DWORD authError,
  662. PWSTR pszUserName,
  663. ULONG ulUserNameBufferSize,
  664. PWSTR pszPassword,
  665. ULONG ulPasswordBufferSize,
  666. BOOL *save,
  667. DWORD flags
  668. )
  669. {
  670. //
  671. // Call the common code indicating this is the GUI interface
  672. //
  673. return CredUIPromptForCredentialsWorker(
  674. FALSE, // GUI version
  675. uiInfo,
  676. targetName,
  677. securityContext,
  678. authError,
  679. pszUserName,
  680. ulUserNameBufferSize,
  681. pszPassword,
  682. ulPasswordBufferSize,
  683. save,
  684. flags );
  685. }
  686. CREDUIAPI
  687. DWORD
  688. WINAPI
  689. CredUIPromptForCredentialsA(
  690. CREDUI_INFOA *uiInfo,
  691. CONST CHAR *targetName,
  692. CtxtHandle *securityContext,
  693. DWORD authError,
  694. PSTR pszUserName,
  695. ULONG ulUserNameBufferSize,
  696. PSTR pszPassword,
  697. ULONG ulPasswordBufferSize,
  698. BOOL *save,
  699. DWORD flags
  700. )
  701. {
  702. DWORD result;
  703. WCHAR targetNameW[CREDUI_MAX_DOMAIN_TARGET_LENGTH + 1];
  704. WCHAR userName[CREDUI_MAX_USERNAME_LENGTH + 1];
  705. WCHAR password[CREDUI_MAX_PASSWORD_LENGTH + 1];
  706. UINT ConsoleCodePage = CP_ACP;
  707. CREDUI_INFOW uiInfoW = {0};
  708. if ((NULL == pszUserName) || (NULL == pszPassword))
  709. {
  710. result = ERROR_INVALID_PARAMETER;
  711. goto Exit;
  712. }
  713. // Convert in paramters to Unicode:
  714. // If a CREDUI_INFO structure was passed, convert it to wide now:
  715. if (uiInfo != NULL) {
  716. if (!CreduiConvertUiInfoToWide(uiInfo, &uiInfoW)) {
  717. result = ERROR_OUTOFMEMORY;
  718. goto Exit;
  719. }
  720. }
  721. // If a target name was passed, convert it to wide now:
  722. if (targetName != NULL)
  723. {
  724. if (!MultiByteToWideChar(ConsoleCodePage,
  725. 0,
  726. targetName,
  727. -1,
  728. targetNameW,
  729. CREDUI_MAX_DOMAIN_TARGET_LENGTH + 1) )
  730. {
  731. result = GetLastError();
  732. goto Exit;
  733. }
  734. }
  735. userName[0] ='\0';
  736. password[0] = '\0';
  737. if (strlen(pszUserName) > 0 )
  738. {
  739. if ( !MultiByteToWideChar( ConsoleCodePage,
  740. 0,
  741. pszUserName,
  742. -1,
  743. userName,
  744. sizeof(userName)/sizeof(WCHAR) ) )
  745. {
  746. result = GetLastError();
  747. goto Exit;
  748. }
  749. }
  750. if (strlen(pszPassword) > 0)
  751. {
  752. if ( !MultiByteToWideChar( ConsoleCodePage,
  753. 0,
  754. pszPassword,
  755. -1,
  756. password,
  757. sizeof(password)/sizeof(WCHAR) ) )
  758. {
  759. result = GetLastError();
  760. goto Exit;
  761. }
  762. }
  763. //
  764. // Call the common code indicating this is the GUI interface
  765. //
  766. result = CredUIPromptForCredentialsWorker(
  767. FALSE, // GUI version
  768. (uiInfo != NULL) ? &uiInfoW : NULL,
  769. (targetName != NULL) ? targetNameW : NULL,
  770. securityContext,
  771. authError,
  772. userName,
  773. ulUserNameBufferSize,
  774. password,
  775. ulPasswordBufferSize,
  776. save,
  777. flags );
  778. if ( result == NO_ERROR && pszUserName != NULL )
  779. {
  780. if (!WideCharToMultiByte(ConsoleCodePage,
  781. 0,
  782. userName,
  783. -1,
  784. pszUserName,
  785. ulUserNameBufferSize,
  786. NULL,
  787. NULL) )
  788. {
  789. CreduiDebugLog("CreduiPromptForCredentials: type username cannot be converted to ANSI.\n" );
  790. result = GetLastError();
  791. }
  792. }
  793. if ( result == NO_ERROR && pszPassword != NULL )
  794. {
  795. if (!WideCharToMultiByte(ConsoleCodePage,
  796. 0,
  797. password,
  798. -1,
  799. pszPassword,
  800. ulPasswordBufferSize,
  801. NULL,
  802. NULL) )
  803. {
  804. CreduiDebugLog("CreduiPromptForCredentials: type password cannot be converted to ANSI.\n" );
  805. result = GetLastError();
  806. }
  807. }
  808. Exit:
  809. SecureZeroMemory(password, sizeof password);
  810. // Free the CREDUI_INFO allocations:
  811. if (uiInfo != NULL)
  812. {
  813. if (uiInfoW.pszMessageText != NULL)
  814. {
  815. delete [] const_cast<WCHAR *>(uiInfoW.pszMessageText);
  816. }
  817. if (uiInfoW.pszCaptionText != NULL)
  818. {
  819. delete [] const_cast<WCHAR *>(uiInfoW.pszCaptionText);
  820. }
  821. }
  822. return result;
  823. }
  824. DWORD
  825. WINAPI
  826. CredUIParseUserNameW(
  827. CONST WCHAR *UserName,
  828. WCHAR *user,
  829. ULONG userBufferSize,
  830. WCHAR *domain,
  831. ULONG domainBufferSize
  832. )
  833. /*++
  834. Routine Description:
  835. CredUIParseUserName is used to breakup a username returned by the cred management APIs
  836. into a username and domain part that can be used as input to other system APIs that
  837. require the full broken-up user credential.
  838. The following formats are supported:
  839. @@<MarshalledCredentialReference>: This is a marshaled credential reference as
  840. as defined by the CredIsMarshaledCredential API. Such a credential is returned
  841. in the 'user' parameter. The 'domain' parameter is set to an empty string.
  842. <DomainName>\<UserName>: The <UserName> is returned in the 'user' parameter and
  843. the <DomainName> is returned in the 'domain' parameter. The name is considered
  844. to have the this syntax if the 'UserName' string contains a \.
  845. <UserName>@<DnsDomainName>: The entire string is returned in the 'user' parameter.
  846. The 'domain' parameter is set to an empty string.
  847. For this syntax, the last @ in the string is used since <UserName> may
  848. contain an @ but <DnsDomainName> cannot.
  849. <UserName>: The <UserName> is returned in the 'user' parameter.
  850. The 'domain' parameter is set to an empty string.
  851. Arguments:
  852. UserName - The user name to be parsed.
  853. user - Specifies a buffer to copy the user name portion of the parsed string to.
  854. userBufferSize - Specifies the size of the 'user' array in characters.
  855. The caller can ensure the passed in array is large enough by using an array
  856. that is CRED_MAX_USERNAME_LENGTH+1 characters long or by passing in an array that
  857. is wcslen(UserName)+1 characters long.
  858. domain - Specifies a buffer to copy the domain name portion of the parsed string to.
  859. domainBufferSize - Specifies the size of the 'domain' array in characters.
  860. The caller can ensure the passed in array is large enough by using an array
  861. that is CRED_MAX_USERNAME_LENGTH+1 characters long or by passing in an array that
  862. is wcslen(UserName)+1 characters long.
  863. Return Values:
  864. The following status codes may be returned:
  865. ERROR_INVALID_ACCOUNT_NAME - The user name is not valid.
  866. ERROR_INVALID_PARAMETER - One of the parameters is invalid.
  867. ERROR_INSUFFICIENT_BUFFER - One of the buffers is too small.
  868. --*/
  869. {
  870. DWORD Status;
  871. CREDUI_USERNAME_TYPE UsernameType;
  872. //
  873. // Use the low level routine to do the work
  874. //
  875. Status = CredUIParseUserNameWithType(
  876. UserName,
  877. user,
  878. userBufferSize,
  879. domain,
  880. domainBufferSize,
  881. &UsernameType );
  882. if ( Status != NO_ERROR ) {
  883. return Status;
  884. }
  885. //
  886. // Avoid relative user names (for backward compatibility)
  887. //
  888. if ( UsernameType == CreduiRelativeUsername ) {
  889. user[0] = L'\0';
  890. domain[0] = L'\0';
  891. return ERROR_INVALID_ACCOUNT_NAME;
  892. }
  893. return NO_ERROR;
  894. }
  895. DWORD
  896. WINAPI
  897. CredUIParseUserNameA(
  898. CONST CHAR *userName,
  899. CHAR *user,
  900. ULONG userBufferSize,
  901. CHAR *domain,
  902. ULONG domainBufferSize
  903. )
  904. /*++
  905. Routine Description:
  906. Ansi version of CredUIParseUserName.
  907. Arguments:
  908. Same as wide version except userBufferSize and domainBufferSize are in terms of bytes.
  909. Return Values:
  910. Same as wide version.
  911. --*/
  912. {
  913. DWORD Status;
  914. WCHAR LocalUserName[CRED_MAX_USERNAME_LENGTH + 1];
  915. WCHAR RetUserName[CRED_MAX_USERNAME_LENGTH + 1];
  916. WCHAR RetDomainName[CRED_MAX_USERNAME_LENGTH + 1];
  917. //
  918. // Convert the passed in username to unicode
  919. //
  920. if ( MultiByteToWideChar( CP_ACP,
  921. MB_ERR_INVALID_CHARS,
  922. userName,
  923. -1,
  924. LocalUserName,
  925. CRED_MAX_USERNAME_LENGTH + 1 ) == 0 ) {
  926. Status = GetLastError();
  927. goto Cleanup;
  928. }
  929. //
  930. // Call the unicode version of the API
  931. //
  932. Status = CredUIParseUserNameW(
  933. LocalUserName,
  934. RetUserName,
  935. CRED_MAX_USERNAME_LENGTH + 1,
  936. RetDomainName,
  937. CRED_MAX_USERNAME_LENGTH + 1 );
  938. if ( Status != NO_ERROR ) {
  939. goto Cleanup;
  940. }
  941. //
  942. // Convert the answers back to ANSI
  943. //
  944. if ( WideCharToMultiByte( CP_ACP,
  945. 0,
  946. RetUserName,
  947. -1,
  948. user,
  949. userBufferSize,
  950. NULL,
  951. NULL ) == 0 ) {
  952. Status = GetLastError();
  953. goto Cleanup;
  954. }
  955. if ( WideCharToMultiByte( CP_ACP,
  956. 0,
  957. RetDomainName,
  958. -1,
  959. domain,
  960. domainBufferSize,
  961. NULL,
  962. NULL ) == 0 ) {
  963. Status = GetLastError();
  964. goto Cleanup;
  965. }
  966. Status = NO_ERROR;
  967. Cleanup:
  968. if ( Status != NO_ERROR ) {
  969. user[0] = L'\0';
  970. domain[0] = L'\0';
  971. }
  972. return Status;
  973. }
  974. ////////////////////////
  975. // Command Line functions
  976. //=============================================================================
  977. // CredUIInitControls
  978. //
  979. // Returns TRUE on success or FALSE otherwise.
  980. //
  981. // Created 06/21/2000 johnstep (John Stephens)
  982. //=============================================================================
  983. extern "C"
  984. BOOL
  985. WINAPI
  986. CredUIInitControls()
  987. {
  988. if (CreduiApiInit())
  989. {
  990. // Register the Credential controls:
  991. if (CreduiCredentialControl::Register(CreduiInstance))
  992. {
  993. return TRUE;
  994. }
  995. }
  996. return FALSE;
  997. }
  998. //=============================================================================
  999. // DllMain
  1000. //
  1001. // The DLL entry function. Since we are linked to the CRT, we must define a
  1002. // function with this name, which will be called from _DllMainCRTStartup.
  1003. //
  1004. // Arguments:
  1005. // instance (in)
  1006. // reason (in)
  1007. // (unused)
  1008. //
  1009. // Returns TRUE on success, or FALSE otherwise.
  1010. //
  1011. // Created 02/29/2000 johnstep (John Stephens)
  1012. //=============================================================================
  1013. extern "C"
  1014. BOOL
  1015. WINAPI
  1016. DllMain(
  1017. HINSTANCE instance,
  1018. DWORD reason,
  1019. VOID *
  1020. )
  1021. {
  1022. BOOL success = TRUE;
  1023. switch (reason)
  1024. {
  1025. case DLL_PROCESS_ATTACH:
  1026. DisableThreadLibraryCalls(instance);
  1027. CreduiInstance = instance;
  1028. // Create a global event which will be set when first-time
  1029. // initialization is completed by the first API call:
  1030. CreduiInitEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  1031. if (CreduiInitEvent == NULL)
  1032. {
  1033. success = FALSE;
  1034. goto failinit;
  1035. }
  1036. SHFusionInitialize(NULL);
  1037. // Register the Credential controls:
  1038. if (!CreduiCredentialControl::Register(instance))
  1039. {
  1040. CloseHandle(CreduiInitEvent);
  1041. CreduiInitEvent = NULL;
  1042. success = FALSE;
  1043. goto failinit;
  1044. }
  1045. //
  1046. // Initialize the confirmation list
  1047. //
  1048. if ( !InitConfirmationList() ) {
  1049. CreduiCredentialControl::Unregister();
  1050. CloseHandle(CreduiInitEvent);
  1051. CreduiInitEvent = NULL;
  1052. success = FALSE;
  1053. }
  1054. failinit:
  1055. break;
  1056. case DLL_PROCESS_DETACH:
  1057. CleanUpConfirmationList();
  1058. if (CreduiFirstTime == FALSE)
  1059. {
  1060. CreduiIconParentWindow::Unregister();
  1061. }
  1062. // Unregister the Credential controls:
  1063. CreduiCredentialControl::Unregister();
  1064. SHFusionUninitialize();
  1065. // Make sure to free the global initialization event:
  1066. if (CreduiInitEvent != NULL)
  1067. {
  1068. CloseHandle(CreduiInitEvent);
  1069. }
  1070. UninitializeCredMgr();
  1071. break;
  1072. };
  1073. return success;
  1074. }
  1075. //=============================================================================
  1076. // DllCanUnloadNow (COM)
  1077. //
  1078. // Created 04/03/2000 johnstep (John Stephens)
  1079. //=============================================================================
  1080. STDAPI
  1081. DllCanUnloadNow()
  1082. {
  1083. return (CreduiComReferenceCount == 0) ? S_OK : S_FALSE;
  1084. }
  1085. //=============================================================================
  1086. // DllGetClassObject (COM)
  1087. //
  1088. // Created 04/03/2000 johnstep (John Stephens)
  1089. //=============================================================================
  1090. STDAPI
  1091. DllGetClassObject(
  1092. CONST CLSID &classId,
  1093. CONST IID &interfaceId,
  1094. VOID **outInterface
  1095. )
  1096. {
  1097. if (classId != CreduiStringArrayClassId)
  1098. {
  1099. return CLASS_E_CLASSNOTAVAILABLE;
  1100. }
  1101. CreduiStringArrayFactory *factory = new CreduiStringArrayFactory;
  1102. if (factory == NULL)
  1103. {
  1104. return E_OUTOFMEMORY;
  1105. }
  1106. HRESULT result = factory->QueryInterface(interfaceId, outInterface);
  1107. factory->Release();
  1108. // Release the string array object in any case, because of the
  1109. // QueryInterface succeeded, it already took another reference count on
  1110. // the object:
  1111. return result;
  1112. }
  1113. //=============================================================================
  1114. // DllRegisterServer (COM)
  1115. //
  1116. // Created 04/03/2000 johnstep (John Stephens)
  1117. //=============================================================================
  1118. STDAPI
  1119. DllRegisterServer()
  1120. {
  1121. HRESULT result = E_FAIL;
  1122. WCHAR fileName[MAX_PATH + 1];
  1123. if (GetModuleFileName(CreduiInstance, fileName, MAX_PATH))
  1124. {
  1125. HKEY regKey;
  1126. if (RegCreateKeyEx(
  1127. HKEY_CLASSES_ROOT,
  1128. L"CLSID\\" CREDUI_STRING_ARRAY_CLASS_STRING
  1129. L"\\InProcServer32",
  1130. 0,
  1131. NULL,
  1132. REG_OPTION_NON_VOLATILE,
  1133. KEY_SET_VALUE,
  1134. NULL,
  1135. &regKey,
  1136. NULL) == ERROR_SUCCESS)
  1137. {
  1138. if (RegSetValueEx(
  1139. regKey,
  1140. NULL,
  1141. 0,
  1142. REG_SZ,
  1143. reinterpret_cast<CONST BYTE *>(fileName),
  1144. (wcslen(fileName) + 1) * 2) == ERROR_SUCCESS)
  1145. {
  1146. if (RegSetValueEx(
  1147. regKey,
  1148. L"ThreadingModel",
  1149. 0,
  1150. REG_SZ,
  1151. reinterpret_cast<CONST BYTE *>(L"Apartment"),
  1152. 18) == ERROR_SUCCESS)
  1153. {
  1154. result = S_OK;
  1155. }
  1156. }
  1157. RegCloseKey(regKey);
  1158. }
  1159. }
  1160. return result;
  1161. }
  1162. //=============================================================================
  1163. // DllUnregisterServer (COM)
  1164. //
  1165. // Created 04/03/2000 johnstep (John Stephens)
  1166. //=============================================================================
  1167. STDAPI
  1168. DllUnregisterServer()
  1169. {
  1170. HRESULT result = S_OK;
  1171. LONG error;
  1172. // Delete our InProcServer32 key:
  1173. error =
  1174. RegDeleteKey(
  1175. HKEY_CLASSES_ROOT,
  1176. L"CLSID\\" CREDUI_STRING_ARRAY_CLASS_STRING L"\\InProcServer32");
  1177. if ((error != ERROR_SUCCESS) &&
  1178. (error != ERROR_FILE_NOT_FOUND))
  1179. {
  1180. result = E_FAIL;
  1181. }
  1182. // Delete our class ID key:
  1183. error =
  1184. RegDeleteKey(
  1185. HKEY_CLASSES_ROOT,
  1186. L"CLSID\\" CREDUI_STRING_ARRAY_CLASS_STRING);
  1187. if ((error != ERROR_SUCCESS) &&
  1188. (error != ERROR_FILE_NOT_FOUND))
  1189. {
  1190. result = E_FAIL;
  1191. }
  1192. return result;
  1193. }
  1194. CREDUIAPI
  1195. DWORD
  1196. WINAPI
  1197. CredUIConfirmCredentialsW(
  1198. PCWSTR pszTargetName,
  1199. BOOL bConfirm
  1200. )
  1201. {
  1202. CreduiDebugLog("CredUIConfirmCredentialsW called for %S, confirm= %x\n",pszTargetName,bConfirm);
  1203. if (NULL == pszTargetName) return ERROR_INVALID_PARAMETER;
  1204. return ConfirmCred ( pszTargetName, bConfirm, TRUE );
  1205. }
  1206. CREDUIAPI
  1207. DWORD
  1208. WINAPI
  1209. CredUIConfirmCredentialsA(
  1210. PCSTR pszTargetName,
  1211. BOOL bConfirm
  1212. )
  1213. {
  1214. WCHAR targetNameW[CRED_MAX_STRING_LENGTH+1+CRED_MAX_STRING_LENGTH];
  1215. // If a target name was passed, convert it to wide now:
  1216. if (pszTargetName != NULL)
  1217. {
  1218. if (MultiByteToWideChar(
  1219. CP_ACP, 0, pszTargetName, -1,
  1220. targetNameW,
  1221. CRED_MAX_STRING_LENGTH+1+CRED_MAX_STRING_LENGTH) == 0)
  1222. {
  1223. return GetLastError();
  1224. }
  1225. }
  1226. return CredUIConfirmCredentialsW ( targetNameW, bConfirm );
  1227. }
  1228. CREDUIAPI
  1229. DWORD
  1230. WINAPI
  1231. CredUICmdLinePromptForCredentialsW(
  1232. PCWSTR targetName,
  1233. PCtxtHandle securityContext,
  1234. DWORD dwAuthError,
  1235. PWSTR UserName,
  1236. ULONG ulUserBufferSize,
  1237. PWSTR pszPassword,
  1238. ULONG ulPasswordBufferSize,
  1239. PBOOL pfSave,
  1240. DWORD flags
  1241. )
  1242. {
  1243. //
  1244. // Call the common code indicating this is the command line interface
  1245. //
  1246. return CredUIPromptForCredentialsWorker(
  1247. TRUE, // Command line version
  1248. NULL, // Command line version has no uiInfo,
  1249. targetName,
  1250. securityContext,
  1251. dwAuthError,
  1252. UserName,
  1253. ulUserBufferSize,
  1254. pszPassword,
  1255. ulPasswordBufferSize,
  1256. pfSave,
  1257. flags );
  1258. }
  1259. CREDUIAPI
  1260. DWORD
  1261. WINAPI
  1262. CredUICmdLinePromptForCredentialsA(
  1263. PCSTR targetName,
  1264. PCtxtHandle pContext,
  1265. DWORD dwAuthError,
  1266. PSTR UserName,
  1267. ULONG ulUserBufferSize,
  1268. PSTR pszPassword,
  1269. ULONG ulPasswordBufferSize,
  1270. PBOOL pfSave,
  1271. DWORD flags
  1272. )
  1273. {
  1274. DWORD result = ERROR_GEN_FAILURE;
  1275. WCHAR *targetNameW = NULL;
  1276. if (!CreduiApiInit())
  1277. {
  1278. return ERROR_GEN_FAILURE;
  1279. }
  1280. // convert to unicode
  1281. WCHAR userNameW[CREDUI_MAX_USERNAME_LENGTH + 1];
  1282. WCHAR *pUserNameW;
  1283. if ( UserName != NULL )
  1284. {
  1285. if (MultiByteToWideChar(CP_ACP, 0, UserName, -1,
  1286. userNameW, sizeof(userNameW)/sizeof(WCHAR)) == 0)
  1287. {
  1288. result = GetLastError();
  1289. goto Exit;
  1290. }
  1291. pUserNameW = userNameW;
  1292. }
  1293. else
  1294. {
  1295. pUserNameW = NULL;
  1296. }
  1297. WCHAR passwordW[CREDUI_MAX_PASSWORD_LENGTH + 1];
  1298. WCHAR *ppasswordW;
  1299. if ( pszPassword != NULL )
  1300. {
  1301. if (MultiByteToWideChar(CP_ACP, 0, pszPassword, -1,
  1302. passwordW, sizeof(passwordW)/sizeof(WCHAR)) == 0)
  1303. {
  1304. result = GetLastError();
  1305. goto Exit;
  1306. }
  1307. ppasswordW = passwordW;
  1308. }
  1309. else
  1310. {
  1311. ppasswordW = NULL;
  1312. }
  1313. // Allocate the target name memory because it can be up to 32 KB:
  1314. if (targetName != NULL)
  1315. {
  1316. INT targetNameSize =
  1317. MultiByteToWideChar(CP_ACP, 0, targetName, -1, NULL, 0);
  1318. if (targetNameSize == 0)
  1319. {
  1320. result = GetLastError();
  1321. goto Exit;
  1322. }
  1323. targetNameW = new WCHAR[targetNameSize];
  1324. if (targetNameW != NULL)
  1325. {
  1326. if (MultiByteToWideChar(CP_ACP, 0, targetName, -1,
  1327. targetNameW, targetNameSize) == 0)
  1328. {
  1329. result = GetLastError();
  1330. goto Exit;
  1331. }
  1332. }
  1333. else
  1334. {
  1335. result = ERROR_NOT_ENOUGH_MEMORY;
  1336. goto Exit;
  1337. }
  1338. }
  1339. else
  1340. {
  1341. targetNameW = NULL;
  1342. }
  1343. result = CredUICmdLinePromptForCredentialsW ( targetNameW,
  1344. pContext,
  1345. dwAuthError,
  1346. userNameW,
  1347. ulUserBufferSize,
  1348. passwordW,
  1349. ulPasswordBufferSize,
  1350. pfSave,
  1351. flags );
  1352. if ( UserName != NULL )
  1353. {
  1354. if (!WideCharToMultiByte(CP_ACP, 0, userNameW, -1, UserName,
  1355. ulUserBufferSize, NULL, NULL) ) {
  1356. result = GetLastError();
  1357. goto Exit;
  1358. }
  1359. }
  1360. if ( pszPassword != NULL )
  1361. {
  1362. if (!WideCharToMultiByte(CP_ACP, 0, passwordW, -1, pszPassword,
  1363. ulPasswordBufferSize, NULL, NULL)) {
  1364. result = GetLastError();
  1365. goto Exit;
  1366. }
  1367. }
  1368. Exit:
  1369. SecureZeroMemory(passwordW, sizeof passwordW);
  1370. // Free the target name memory:
  1371. delete [] targetNameW;
  1372. return result;
  1373. }
  1374. // call this api to store a single-sign-on credential
  1375. // retruns ERROR_SUCCESS if success
  1376. CREDUIAPI
  1377. DWORD
  1378. WINAPI
  1379. CredUIStoreSSOCredW (
  1380. PCWSTR pszRealm,
  1381. PCWSTR pszUsername,
  1382. PCWSTR pszPassword,
  1383. BOOL bPersist
  1384. )
  1385. {
  1386. CreduiDebugLog ( "CredUIStoreSSOCredW\n" );
  1387. DWORD dwResult = ERROR_GEN_FAILURE;
  1388. if ( pszUsername == NULL || pszPassword == NULL )
  1389. return dwResult;
  1390. // temporarily cache them locally
  1391. if (FAILED(StringCchCopyW(
  1392. gszSSOUserName,
  1393. RTL_NUMBER_OF(gszSSOUserName),
  1394. pszUsername)) ||
  1395. FAILED(StringCchCopyW(
  1396. gszSSOPassword,
  1397. RTL_NUMBER_OF(gszSSOPassword),
  1398. pszPassword)))
  1399. {
  1400. dwResult = ERROR_INVALID_PARAMETER;
  1401. goto Exit;
  1402. }
  1403. WCHAR szTargetName[CREDUI_MAX_DOMAIN_TARGET_LENGTH];
  1404. gbStoredSSOCreds = TRUE;
  1405. if ( gbWaitingForSSOCreds || !bPersist)
  1406. {
  1407. dwResult = ERROR_SUCCESS;
  1408. }
  1409. else
  1410. {
  1411. // otherwise store them in credmgr
  1412. if ( pszRealm )
  1413. {
  1414. // validate it's not zero length
  1415. if ((pszRealm[0] == L'\0') ||
  1416. FAILED(StringCchCopyExW(
  1417. szTargetName,
  1418. RTL_NUMBER_OF(szTargetName) - 2,
  1419. pszRealm,
  1420. NULL,
  1421. NULL,
  1422. STRSAFE_NO_TRUNCATION)))
  1423. {
  1424. dwResult = ERROR_INVALID_PARAMETER;
  1425. goto Exit;
  1426. }
  1427. }
  1428. else
  1429. {
  1430. GetDeaultSSORealm(szTargetName, TRUE);
  1431. }
  1432. // finalize the target name
  1433. // ensure that the tail will fit first
  1434. if (FAILED(StringCchCatExW(
  1435. szTargetName,
  1436. RTL_NUMBER_OF(szTargetName),
  1437. L"\\*",
  1438. NULL,
  1439. NULL,
  1440. STRSAFE_NO_TRUNCATION)))
  1441. {
  1442. dwResult = ERROR_INVALID_PARAMETER;
  1443. goto Exit;
  1444. }
  1445. // encrypt the password
  1446. PVOID pEncryptedPassword;
  1447. DWORD dwESize = wcslen(pszPassword)+1;
  1448. if (EncryptPassword ( (PWSTR)pszPassword, &pEncryptedPassword, &dwESize ) == ERROR_SUCCESS)
  1449. {
  1450. // write it out
  1451. CREDENTIALW NewCredential;
  1452. memset ( (void*)&NewCredential, 0, sizeof(CREDENTIALW));
  1453. DWORD dwFlags = 0;
  1454. NewCredential.TargetName = szTargetName;
  1455. NewCredential.Type = CRED_TYPE_DOMAIN_VISIBLE_PASSWORD;
  1456. NewCredential.Persist = bPersist ? CRED_PERSIST_ENTERPRISE : CRED_PERSIST_SESSION;
  1457. NewCredential.Flags = 0;
  1458. NewCredential.CredentialBlobSize = dwESize;
  1459. NewCredential.UserName = (LPWSTR)pszUsername;
  1460. NewCredential.CredentialBlob = reinterpret_cast<BYTE *>(pEncryptedPassword);
  1461. if ( CredWriteW(&NewCredential, dwFlags))
  1462. {
  1463. dwResult = ERROR_SUCCESS;
  1464. }
  1465. LocalFree (pEncryptedPassword);
  1466. }
  1467. }
  1468. Exit:
  1469. SecureZeroMemory(gszSSOUserName, sizeof gszSSOUserName);
  1470. SecureZeroMemory(gszSSOPassword, sizeof gszSSOPassword);
  1471. return dwResult;
  1472. }
  1473. CREDUIAPI
  1474. DWORD
  1475. WINAPI
  1476. CredUIStoreSSOCredA (
  1477. PCSTR pszRealm,
  1478. PCSTR pszUsername,
  1479. PCSTR pszPassword,
  1480. BOOL bPersist
  1481. )
  1482. {
  1483. DWORD dwResult = ERROR_GEN_FAILURE;
  1484. // convert to unicode
  1485. WCHAR realmW[CREDUI_MAX_DOMAIN_TARGET_LENGTH];
  1486. WCHAR *prealmW;
  1487. if ( pszRealm != NULL )
  1488. {
  1489. if (MultiByteToWideChar(CP_ACP, 0, pszRealm, -1,
  1490. realmW, RTL_NUMBER_OF(realmW)) == 0)
  1491. {
  1492. goto Exit;
  1493. }
  1494. prealmW = realmW;
  1495. }
  1496. else
  1497. {
  1498. prealmW = NULL;
  1499. }
  1500. WCHAR userNameW[CREDUI_MAX_USERNAME_LENGTH + 1];
  1501. WCHAR *pUserNameW;
  1502. if ( pszUsername != NULL )
  1503. {
  1504. if (MultiByteToWideChar(CP_ACP, 0, pszUsername, -1,
  1505. userNameW, RTL_NUMBER_OF(userNameW)) == 0)
  1506. {
  1507. goto Exit;
  1508. }
  1509. pUserNameW = userNameW;
  1510. }
  1511. else
  1512. {
  1513. pUserNameW = NULL;
  1514. }
  1515. WCHAR passwordW[CREDUI_MAX_PASSWORD_LENGTH + 1];
  1516. WCHAR *ppasswordW;
  1517. if ( pszPassword != NULL )
  1518. {
  1519. if (MultiByteToWideChar(CP_ACP, 0, pszPassword, -1,
  1520. passwordW, RTL_NUMBER_OF(passwordW)) == 0)
  1521. {
  1522. goto Exit;
  1523. }
  1524. ppasswordW = passwordW;
  1525. }
  1526. else
  1527. {
  1528. ppasswordW = NULL;
  1529. }
  1530. dwResult = CredUIStoreSSOCredW ( prealmW, pUserNameW, ppasswordW, bPersist );
  1531. Exit:
  1532. // clean up passwords in memory
  1533. SecureZeroMemory(passwordW, sizeof passwordW);
  1534. return dwResult;
  1535. }
  1536. // call this api to retrieve the username for a single-sign-on credential
  1537. // retruns ERROR_SUCCESS if success, ERROR_NOT_FOUND if none was found
  1538. CREDUIAPI
  1539. DWORD
  1540. WINAPI
  1541. CredUIReadSSOCredW (
  1542. PCWSTR pszRealm,
  1543. PWSTR* ppszUsername
  1544. )
  1545. {
  1546. DWORD dwReturn = ERROR_NOT_FOUND;
  1547. WCHAR szTargetName[CREDUI_MAX_DOMAIN_TARGET_LENGTH];
  1548. if ( pszRealm )
  1549. {
  1550. // validate it's not zero length
  1551. if ((pszRealm[0] == L'\0') ||
  1552. FAILED(StringCchCopyExW(
  1553. szTargetName,
  1554. RTL_NUMBER_OF(szTargetName) - 2,
  1555. pszRealm,
  1556. NULL,
  1557. NULL,
  1558. STRSAFE_NO_TRUNCATION)))
  1559. {
  1560. return ERROR_INVALID_PARAMETER;
  1561. }
  1562. }
  1563. else
  1564. {
  1565. GetDeaultSSORealm(szTargetName, FALSE);
  1566. }
  1567. // validate it's not zero length
  1568. if (szTargetName[0] != L'\0')
  1569. {
  1570. // finalize the target name
  1571. // ensure that the tail will fit first
  1572. if (FAILED(StringCchCatExW(
  1573. szTargetName,
  1574. RTL_NUMBER_OF(szTargetName),
  1575. L"\\*",
  1576. NULL,
  1577. NULL,
  1578. STRSAFE_NO_TRUNCATION)))
  1579. {
  1580. return ERROR_INVALID_PARAMETER;
  1581. }
  1582. PCREDENTIALW pCred;
  1583. DWORD dwFlags = 0;
  1584. if ( CredReadW ( szTargetName,
  1585. CRED_TYPE_DOMAIN_VISIBLE_PASSWORD,
  1586. dwFlags,
  1587. &pCred ) )
  1588. {
  1589. size_t len = wcslen(pCred->UserName);
  1590. *ppszUsername = (PWSTR)LocalAlloc(LMEM_ZEROINIT, sizeof(WCHAR)*(len+1));
  1591. if ( *ppszUsername )
  1592. {
  1593. dwReturn = ERROR_SUCCESS;
  1594. StringCchCopyW(*ppszUsername, len + 1, pCred->UserName);
  1595. }
  1596. CredFree ( pCred );
  1597. }
  1598. }
  1599. return dwReturn;
  1600. }
  1601. // call this api to retrieve the username for a single-sign-on credential
  1602. // retruns ERROR_SUCCESS if success, ERROR_NOT_FOUND if none was found
  1603. CREDUIAPI
  1604. DWORD
  1605. WINAPI
  1606. CredUIReadSSOCredA (
  1607. PCSTR pszRealm,
  1608. PSTR* ppszUsername
  1609. )
  1610. {
  1611. DWORD dwReturn = ERROR_NOT_FOUND;
  1612. WCHAR szTargetName[CREDUI_MAX_DOMAIN_TARGET_LENGTH];
  1613. PCREDENTIALW pCred;
  1614. DWORD dwFlags = 0;
  1615. UINT uiConsoleCodePage = CP_ACP;
  1616. if ( pszRealm )
  1617. {
  1618. // validate it's not zero length
  1619. int len = strlen(pszRealm);
  1620. if ( len == 0 )
  1621. {
  1622. return ERROR_INVALID_PARAMETER;
  1623. }
  1624. if (MultiByteToWideChar(uiConsoleCodePage,
  1625. 0,
  1626. pszRealm,
  1627. len + 1,
  1628. szTargetName,
  1629. RTL_NUMBER_OF(szTargetName) - 2)
  1630. == 0)
  1631. {
  1632. dwReturn = GetLastError();
  1633. goto Exit;
  1634. }
  1635. }
  1636. else
  1637. {
  1638. GetDeaultSSORealm(szTargetName, FALSE);
  1639. }
  1640. if (szTargetName[0] != L'\0')
  1641. {
  1642. // finalize the target name
  1643. // ensure that the tail will fit first
  1644. if (FAILED(StringCchCatExW(
  1645. szTargetName,
  1646. RTL_NUMBER_OF(szTargetName),
  1647. L"\\*",
  1648. NULL,
  1649. NULL,
  1650. STRSAFE_NO_TRUNCATION)))
  1651. {
  1652. dwReturn = ERROR_INVALID_PARAMETER;
  1653. goto Exit;
  1654. }
  1655. // first call credmgr to set the target info
  1656. if ( CredReadW ( szTargetName,
  1657. CRED_TYPE_DOMAIN_VISIBLE_PASSWORD,
  1658. dwFlags,
  1659. &pCred ) )
  1660. {
  1661. DWORD dwConvertedLength = 0;
  1662. dwConvertedLength = WideCharToMultiByte(uiConsoleCodePage,
  1663. 0,
  1664. pCred->UserName,
  1665. -1,
  1666. *ppszUsername,
  1667. 0,
  1668. NULL,
  1669. NULL);
  1670. if (dwConvertedLength == 0)
  1671. {
  1672. // string does not convert or other error - all map to this
  1673. dwReturn = ERROR_INVALID_PARAMETER;
  1674. }
  1675. else
  1676. {
  1677. // have proper buffer size and string will convert without loss
  1678. *ppszUsername = (PSTR)LocalAlloc(LMEM_ZEROINIT, dwConvertedLength);
  1679. if (*ppszUsername)
  1680. {
  1681. dwReturn = WideCharToMultiByte(uiConsoleCodePage,
  1682. 0,
  1683. pCred->UserName,
  1684. -1,
  1685. *ppszUsername,
  1686. dwConvertedLength,
  1687. NULL,
  1688. NULL);
  1689. if (dwReturn)
  1690. {
  1691. // nonzero return is success
  1692. dwReturn = ERROR_SUCCESS;
  1693. }
  1694. else
  1695. {
  1696. dwReturn = GetLastError();
  1697. }
  1698. }
  1699. }
  1700. CredFree ( pCred );
  1701. }
  1702. // end cred read
  1703. }
  1704. // end target name not empty
  1705. Exit:
  1706. return dwReturn;
  1707. }