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
2040 lines
56 KiB
//=============================================================================
|
|
// Copyright (c) 2000 Microsoft Corporation
|
|
//
|
|
// api.cpp
|
|
//
|
|
// Win32 API function implementation and the DLL entry function.
|
|
//
|
|
// Created 02/29/2000 johnstep (John Stephens)
|
|
//=============================================================================
|
|
|
|
#include "precomp.hpp"
|
|
#include "dialogs.hpp"
|
|
#include "resource.h"
|
|
//#include "utils.hpp"
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Global Variables
|
|
//-----------------------------------------------------------------------------
|
|
|
|
HMODULE CreduiInstance = NULL;
|
|
ULONG CreduiComReferenceCount = 0;
|
|
|
|
BOOL CreduiIsPersonal = FALSE;
|
|
BOOL CreduiIsDomainController = FALSE;
|
|
BOOL CreduiIsSafeMode = FALSE;
|
|
|
|
CREDUI_STRINGS CreduiStrings;
|
|
|
|
UINT CreduiScarduiWmReaderArrival = 0;
|
|
UINT CreduiScarduiWmReaderRemoval = 0;
|
|
UINT CreduiScarduiWmCardInsertion = 0;
|
|
UINT CreduiScarduiWmCardRemoval = 0;
|
|
UINT CreduiScarduiWmCardCertAvail = 0;
|
|
UINT CreduiScarduiWmCardStatus = 0;
|
|
|
|
BOOL CreduiHasSmartCardSupport = FALSE;
|
|
|
|
static LONG CreduiFirstTime = TRUE;
|
|
static HANDLE CreduiInitEvent = NULL;
|
|
|
|
BOOL gbWaitingForSSOCreds = FALSE;
|
|
WCHAR gszSSOUserName[CREDUI_MAX_USERNAME_LENGTH];
|
|
WCHAR gszSSOPassword[CREDUI_MAX_PASSWORD_LENGTH];
|
|
BOOL gbStoredSSOCreds = FALSE;
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Functions
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//=============================================================================
|
|
// CreduiInitStringTable
|
|
//
|
|
// This function loads all the string resources into the global string table.
|
|
// It only needs to be called once per process.
|
|
//
|
|
// Return TRUE if the string table was successfully initialized or FALSE
|
|
// otherwise.
|
|
//
|
|
// Created 03/26/2000 johnstep (John Stephens)
|
|
//=============================================================================
|
|
|
|
BOOL
|
|
CreduiInitStringTable()
|
|
{
|
|
#define CREDUI_STRING(id, name) {\
|
|
id, CreduiStrings.##name, (sizeof CreduiStrings.##name) / (sizeof WCHAR)\
|
|
}
|
|
|
|
static struct
|
|
{
|
|
UINT Id;
|
|
WCHAR *String;
|
|
ULONG Length;
|
|
} stringInfo[] = {
|
|
// Static labels for controls
|
|
CREDUI_STRING(IDS_USERNAME_STATIC, UserNameStatic),
|
|
CREDUI_STRING(IDS_PASSWORD_STATIC, PasswordStatic),
|
|
CREDUI_STRING(IDS_CERTIFICATE_STATIC, CertificateStatic),
|
|
CREDUI_STRING(IDS_PIN_STATIC, PinStatic),
|
|
CREDUI_STRING(IDS_CARD_STATIC, SmartCardStatic),
|
|
// Caption strings
|
|
CREDUI_STRING(IDS_DNS_CAPTION, DnsCaption),
|
|
CREDUI_STRING(IDS_NETBIOS_CAPTION, NetbiosCaption),
|
|
CREDUI_STRING(IDS_GENERIC_CAPTION, GenericCaption),
|
|
CREDUI_STRING(IDS_WELCOME, Welcome),
|
|
CREDUI_STRING(IDS_WELCOME_BACK, WelcomeBack),
|
|
CREDUI_STRING(IDS_CONNECTING, Connecting),
|
|
CREDUI_STRING(IDS_LOOKUP_NAME, LookupName),
|
|
CREDUI_STRING(IDS_CARD_ERROR, CardError),
|
|
CREDUI_STRING(IDS_SAVE, Save),
|
|
CREDUI_STRING(IDS_PASSPORT_SAVE, PassportSave ),
|
|
CREDUI_STRING(IDS_EMAIL_NAME, EmailName ),
|
|
// Tooltip strings
|
|
CREDUI_STRING(IDS_USERNAME_TIP_TITLE, UserNameTipTitle),
|
|
CREDUI_STRING(IDS_USERNAME_TIP_TEXT, UserNameTipText),
|
|
CREDUI_STRING(IDS_PASSWORD_TIP_TITLE, PasswordTipTitle),
|
|
CREDUI_STRING(IDS_PASSWORD_TIP_TEXT, PasswordTipText),
|
|
CREDUI_STRING(IDS_CAPSLOCK_TIP_TITLE, CapsLockTipTitle),
|
|
CREDUI_STRING(IDS_CAPSLOCK_TIP_TEXT, CapsLockTipText),
|
|
CREDUI_STRING(IDS_LOGON_TIP_TITLE, LogonTipTitle),
|
|
CREDUI_STRING(IDS_LOGON_TIP_TEXT, LogonTipText),
|
|
CREDUI_STRING(IDS_LOGON_TIP_CAPS, LogonTipCaps),
|
|
CREDUI_STRING(IDS_BACKWARDS_TIP_TITLE, BackwardsTipTitle),
|
|
CREDUI_STRING(IDS_BACKWARDS_TIP_TEXT, BackwardsTipText),
|
|
CREDUI_STRING(IDS_WRONG_OLD_TIP_TITLE, WrongOldTipTitle),
|
|
CREDUI_STRING(IDS_WRONG_OLD_TIP_TEXT, WrongOldTipText),
|
|
CREDUI_STRING(IDS_NOT_SAME_TIP_TITLE, NotSameTipTitle),
|
|
CREDUI_STRING(IDS_NOT_SAME_TIP_TEXT, NotSameTipText),
|
|
CREDUI_STRING(IDS_TOO_SHORT_TIP_TITLE, TooShortTipTitle),
|
|
CREDUI_STRING(IDS_TOO_SHORT_TIP_TEXT, TooShortTipText),
|
|
CREDUI_STRING(IDS_DOWNGRADE_TIP_TEXT, DowngradeTipText),
|
|
CREDUI_STRING(IDS_EMAILNAME_TIP_TITLE, EmailNameTipTitle),
|
|
CREDUI_STRING(IDS_EMAILNAME_TIP_TEXT, EmailNameTipText),
|
|
// strings that can appear in GUI or be copied from GUI and presented on cmdline
|
|
CREDUI_STRING(IDS_CMDLINE_NOCARD,NoCard),
|
|
CREDUI_STRING(IDS_EMPTY_READER, EmptyReader),
|
|
CREDUI_STRING(IDS_READING_CARD, ReadingCard),
|
|
CREDUI_STRING(IDS_CERTIFICATE, Certificate),
|
|
CREDUI_STRING(IDS_EMPTY_CARD, EmptyCard),
|
|
CREDUI_STRING(IDS_UNKNOWN_CARD, UnknownCard),
|
|
CREDUI_STRING(IDS_BACKWARDS_CARD, BackwardsCard)
|
|
};
|
|
|
|
#undef CREDUI_STRING
|
|
|
|
for (UINT i = 0; i < (sizeof stringInfo) / (sizeof stringInfo[0]); ++i)
|
|
{
|
|
// Read all strings into string array from resources of application
|
|
// Some strings which are GUI-only taken from resources
|
|
// Strings that are may be output to cmdline are taken from MC file, which also
|
|
// permits more flexible argument substitution during localization
|
|
if (stringInfo[i].Id >= 2500)
|
|
{
|
|
stringInfo[i].String[0] = 0;
|
|
FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY,
|
|
CreduiInstance,
|
|
stringInfo[i].Id,
|
|
0,
|
|
stringInfo[i].String,
|
|
stringInfo[i].Length - 1,
|
|
NULL);
|
|
}
|
|
else if (!LoadString(CreduiInstance,
|
|
stringInfo[i].Id,
|
|
stringInfo[i].String,
|
|
stringInfo[i].Length))
|
|
{
|
|
CreduiDebugLog("CreduiInitStringTable: Load string %u failed\n",
|
|
stringInfo[i].Id);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//=============================================================================
|
|
// CreduiInitSmartCardWindowMessages
|
|
//
|
|
// Return TRUE on success or FALSE otherwise.
|
|
//
|
|
// Created 03/26/2000 johnstep (John Stephens)
|
|
//=============================================================================
|
|
|
|
BOOL
|
|
CreduiInitSmartCardWindowMessages()
|
|
{
|
|
struct
|
|
{
|
|
UINT *message;
|
|
CHAR *string;
|
|
} messageInfo[] = {
|
|
&CreduiScarduiWmReaderArrival, SCARDUI_READER_ARRIVAL,
|
|
&CreduiScarduiWmReaderRemoval, SCARDUI_READER_REMOVAL,
|
|
&CreduiScarduiWmCardInsertion, SCARDUI_SMART_CARD_INSERTION,
|
|
&CreduiScarduiWmCardRemoval, SCARDUI_SMART_CARD_REMOVAL,
|
|
&CreduiScarduiWmCardCertAvail, SCARDUI_SMART_CARD_CERT_AVAIL,
|
|
&CreduiScarduiWmCardStatus, SCARDUI_SMART_CARD_STATUS
|
|
};
|
|
|
|
for (UINT i = 0; i < (sizeof messageInfo) / (sizeof messageInfo[0]); ++i)
|
|
{
|
|
*messageInfo[i].message =
|
|
RegisterWindowMessageA(messageInfo[i].string);
|
|
|
|
if (*messageInfo[i].message == 0)
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//=============================================================================
|
|
// CreduiApiInit
|
|
//
|
|
// This function is called at API entry points to ensure the common controls
|
|
// we need are initialized. Currently, the only initialization done is only
|
|
// needed once per process, but this macro will handle per thread
|
|
// initialization in the future, if necessary:
|
|
//
|
|
// Returns TRUE on success or FALSE otherwise.
|
|
//
|
|
// Created 03/10/2000 johnstep (John Stephens)
|
|
//=============================================================================
|
|
|
|
static
|
|
BOOL
|
|
CreduiApiInit()
|
|
{
|
|
// First time initialization:
|
|
|
|
ASSERT(CreduiInitEvent != NULL);
|
|
|
|
if (InterlockedCompareExchange(&CreduiFirstTime, FALSE, TRUE))
|
|
{
|
|
INITCOMMONCONTROLSEX init;
|
|
init.dwSize = sizeof init;
|
|
init.dwICC = ICC_USEREX_CLASSES;
|
|
|
|
if (!InitCommonControlsEx(&init))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// Check for Personal SKU:
|
|
|
|
OSVERSIONINFOEXW versionInfo;
|
|
|
|
versionInfo.dwOSVersionInfoSize = sizeof OSVERSIONINFOEXW;
|
|
|
|
if (GetVersionEx(reinterpret_cast<OSVERSIONINFOW *>(&versionInfo)))
|
|
{
|
|
CreduiIsPersonal =
|
|
(versionInfo.wProductType == VER_NT_WORKSTATION) &&
|
|
(versionInfo.wSuiteMask & VER_SUITE_PERSONAL);
|
|
CreduiIsDomainController =
|
|
(versionInfo.wProductType == VER_NT_DOMAIN_CONTROLLER);
|
|
}
|
|
|
|
// Check for safe mode:
|
|
|
|
HKEY key;
|
|
|
|
if (RegOpenKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
L"SYSTEM\\CurrentControlSet\\Control\\SafeBoot\\Option",
|
|
0,
|
|
KEY_READ,
|
|
&key) == ERROR_SUCCESS)
|
|
{
|
|
if (RegQueryValueEx(
|
|
key,
|
|
L"OptionValue",
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL) == ERROR_SUCCESS)
|
|
{
|
|
CreduiIsSafeMode = TRUE;
|
|
}
|
|
|
|
RegCloseKey(key);
|
|
}
|
|
|
|
// Do other initialization:
|
|
|
|
InitializeCredMgr();
|
|
if (!CreduiInitStringTable())
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
CreduiHasSmartCardSupport = CreduiInitSmartCardWindowMessages();
|
|
|
|
CreduiIconParentWindow::Register(CreduiInstance);
|
|
|
|
SetEvent(CreduiInitEvent);
|
|
}
|
|
else
|
|
{
|
|
WaitForSingleObject(CreduiInitEvent, INFINITE);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//=============================================================================
|
|
// CreduiValidateUiInfo
|
|
//
|
|
// This function validates the CREDUI_INFO structure passed in. A NULL value
|
|
// is acceptable, and impies defaults.
|
|
//
|
|
// CredValidateUiInfoW for wide
|
|
// CredValidateUiInfoA for ANSI
|
|
//
|
|
// Arguments:
|
|
// uiInfo (in) - structure to validate
|
|
//
|
|
// Returns TRUE if the structure is valid, or FALSE otherwise.
|
|
//
|
|
// Created 03/25/2000 johnstep (John Stephens)
|
|
//=============================================================================
|
|
|
|
static
|
|
BOOL
|
|
CreduiValidateUiInfoW(
|
|
CREDUI_INFOW *uiInfo
|
|
)
|
|
{
|
|
|
|
if (uiInfo != NULL)
|
|
{
|
|
if (uiInfo->cbSize != sizeof(*uiInfo) )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if ((uiInfo->hbmBanner != NULL) &&
|
|
(GetObjectType(uiInfo->hbmBanner) != OBJ_BITMAP))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if ((uiInfo->pszMessageText != NULL) &&
|
|
(wcslen(uiInfo->pszMessageText) > CREDUI_MAX_MESSAGE_LENGTH))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
if ((uiInfo->pszCaptionText != NULL) &&
|
|
(wcslen(uiInfo->pszCaptionText) > CREDUI_MAX_CAPTION_LENGTH))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//=============================================================================
|
|
// CreduiConvertUiInfoToWide
|
|
//
|
|
// This function converts a CREDUI_INFOA structure to CREDUI_INFOW. On
|
|
// success,The caller is responsible for freeing pszMessageText and
|
|
// pszCaptionText via the delete [] operator.
|
|
//
|
|
// Arguments:
|
|
// uiInfoA (in) - structure to convert
|
|
// uiInfoW (out) - storage for converted structure. The pszMessageText and
|
|
// pszCaptionText will be set to NULL on failure or valid
|
|
// pointers (unless the in pointer is NULL) on success,
|
|
// allocated via the new [] operator.
|
|
//
|
|
// Returns TRUE if the structure is valid, or FALSE otherwise.
|
|
//
|
|
// Created 03/26/2000 johnstep (John Stephens)
|
|
//=============================================================================
|
|
|
|
static
|
|
BOOL
|
|
CreduiConvertUiInfoToWide(
|
|
CREDUI_INFOA *uiInfoA,
|
|
CREDUI_INFOW *uiInfoW
|
|
)
|
|
{
|
|
uiInfoW->cbSize = uiInfoA->cbSize;
|
|
uiInfoW->hwndParent = uiInfoA->hwndParent;
|
|
uiInfoW->pszMessageText = NULL;
|
|
uiInfoW->pszCaptionText = NULL;
|
|
uiInfoW->hbmBanner = uiInfoA->hbmBanner;
|
|
|
|
INT bufferSize;
|
|
|
|
if (uiInfoA->pszMessageText != NULL)
|
|
{
|
|
bufferSize =
|
|
MultiByteToWideChar(
|
|
CP_ACP, 0, uiInfoA->pszMessageText, -1, NULL, 0);
|
|
|
|
if (bufferSize == 0)
|
|
{
|
|
goto ErrorExit;
|
|
}
|
|
|
|
uiInfoW->pszMessageText = new WCHAR[bufferSize];
|
|
|
|
if (uiInfoW->pszMessageText == NULL)
|
|
{
|
|
goto ErrorExit;
|
|
}
|
|
|
|
if (MultiByteToWideChar(
|
|
CP_ACP, 0, uiInfoA->pszMessageText, -1,
|
|
const_cast<WCHAR *>(uiInfoW->pszMessageText),
|
|
bufferSize) == 0)
|
|
{
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
uiInfoW->pszMessageText = NULL;
|
|
}
|
|
|
|
if (uiInfoA->pszCaptionText != NULL)
|
|
{
|
|
bufferSize =
|
|
MultiByteToWideChar(
|
|
CP_ACP, 0, uiInfoA->pszCaptionText, -1, NULL, 0);
|
|
|
|
if (bufferSize == 0)
|
|
{
|
|
goto ErrorExit;
|
|
}
|
|
|
|
uiInfoW->pszCaptionText = new WCHAR[bufferSize];
|
|
|
|
if (uiInfoW->pszCaptionText == NULL)
|
|
{
|
|
goto ErrorExit;
|
|
}
|
|
|
|
if (MultiByteToWideChar(
|
|
CP_ACP, 0, uiInfoA->pszCaptionText, -1,
|
|
const_cast<WCHAR *>(uiInfoW->pszCaptionText),
|
|
bufferSize) == 0)
|
|
{
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
uiInfoW->pszCaptionText = NULL;
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
ErrorExit:
|
|
|
|
if (uiInfoW->pszCaptionText != NULL)
|
|
{
|
|
delete [] const_cast<WCHAR *>(uiInfoW->pszCaptionText);
|
|
uiInfoW->pszCaptionText = NULL;
|
|
}
|
|
|
|
if (uiInfoW->pszMessageText != NULL)
|
|
{
|
|
delete [] const_cast<WCHAR *>(uiInfoW->pszMessageText);
|
|
uiInfoW->pszMessageText = NULL;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
//=============================================================================
|
|
// CredUIPromptForCredentials
|
|
//
|
|
// Presents a user interface to get credentials from an application.
|
|
//
|
|
// CredUIPromptForCredentialsW for wide
|
|
// CredUIPromptForCredentialsA for ANSI
|
|
//
|
|
// Arguments:
|
|
// uiInfo (in,optional)
|
|
// targetName (in) - if specified, securityContext must be NULL
|
|
// securityContext (in) - if specified, targetName must be NULL
|
|
// error (in) - the authentication error
|
|
// userName (in,out)
|
|
// userNameBufferSize (in) - maximum length of userName
|
|
// password (in,out)
|
|
// passwordBufferSize (in) - maximum length of password
|
|
// save (in/out) - TRUE if save check box was checked
|
|
// flags (in)
|
|
//
|
|
// Returns:
|
|
// ERROR_SUCCESS
|
|
// ERROR_CANCELLED
|
|
// ERROR_NO_SUCH_LOGON_SESSION - if credential manager cannot be used
|
|
// ERROR_GEN_FAILURE
|
|
// ERROR_INVALID_FLAGS
|
|
// ERROR_INVALID_PARAMETER
|
|
// ERROR_OUTOFMEMORY
|
|
//
|
|
// Created 10/17/2000 johnhaw
|
|
|
|
DWORD
|
|
CredUIPromptForCredentialsWorker(
|
|
IN BOOL doingCommandLine,
|
|
CREDUI_INFOW *uiInfo,
|
|
CONST WCHAR *targetName,
|
|
CtxtHandle *securityContext,
|
|
DWORD authError,
|
|
PWSTR pszUserName,
|
|
ULONG ulUserNameBufferSize,
|
|
PWSTR pszPassword,
|
|
ULONG ulPasswordBufferSize,
|
|
BOOL *save,
|
|
DWORD flags
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine implements the GUI and command line prompt for credentials.
|
|
|
|
Arguments:
|
|
|
|
DoingCommandLine - TRUE if prompting is to be done via the command line
|
|
FALSE if prompting is to be done via GUI
|
|
|
|
... - Other parameters are the same a CredUIPromptForCredentials API
|
|
|
|
Return Values:
|
|
|
|
Same as CredUIPromptForCredentials.
|
|
|
|
--*/
|
|
{
|
|
ULONG CertFlags;
|
|
ULONG CredCategory;
|
|
ULONG PersistFlags;
|
|
|
|
CreduiDebugLog("CUIPFCWorker: Flags: %x, Target: %S doingCommandLine: %i\n", flags, targetName, doingCommandLine);
|
|
|
|
if ((NULL == pszUserName) || (NULL == pszPassword))
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (!CreduiApiInit())
|
|
{
|
|
return ERROR_GEN_FAILURE;
|
|
}
|
|
|
|
// Validate arguments:
|
|
if ((flags & ~CREDUI_FLAGS_PROMPT_VALID) != 0)
|
|
{
|
|
CreduiDebugLog("CreduiPromptForCredentials: flags not valid %lx.\n", flags );
|
|
return ERROR_INVALID_FLAGS;
|
|
}
|
|
|
|
//
|
|
// Ensure there is is only one bit defining cert support
|
|
//
|
|
CertFlags = flags & (CREDUI_FLAGS_REQUIRE_SMARTCARD|CREDUI_FLAGS_REQUIRE_CERTIFICATE|CREDUI_FLAGS_EXCLUDE_CERTIFICATES);
|
|
|
|
if ( CertFlags != 0 && !JUST_ONE_BIT(CertFlags) ) {
|
|
CreduiDebugLog("CreduiPromptForCredentials: require smartcard, require certificate, and exclude certificates are mutually exclusive %lx.\n", flags );
|
|
return ERROR_INVALID_FLAGS;
|
|
}
|
|
|
|
//
|
|
// For the command line version,
|
|
// limit cert support further.
|
|
//
|
|
|
|
if ( doingCommandLine ) {
|
|
if ( CertFlags == 0 ||
|
|
(CertFlags & CREDUI_FLAGS_REQUIRE_CERTIFICATE) != 0 ) {
|
|
CreduiDebugLog("CreduiPromptForCredentials: need either require smartcard or exclude certificates for command line %lx.\n", flags );
|
|
return ERROR_INVALID_FLAGS;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Ensure there is only one bit defining the credential category
|
|
|
|
CredCategory = flags & (CREDUI_FLAGS_GENERIC_CREDENTIALS|CREDUI_FLAGS_USERNAME_TARGET_CREDENTIALS);
|
|
|
|
if ( CredCategory != 0 && !JUST_ONE_BIT(CredCategory) ) {
|
|
CreduiDebugLog("CreduiPromptForCredentials: generic creds and username target are mutually exclusive %lx.\n", flags );
|
|
return ERROR_INVALID_FLAGS;
|
|
}
|
|
|
|
//
|
|
// Ensure there is only one bit set saying whether the cred is to persist or not
|
|
//
|
|
|
|
PersistFlags = flags & (CREDUI_FLAGS_DO_NOT_PERSIST|CREDUI_FLAGS_PERSIST);
|
|
|
|
if ( PersistFlags != 0 && !JUST_ONE_BIT(PersistFlags) ) {
|
|
CreduiDebugLog("CreduiPromptForCredentials: DoNotPersist and Persist are mutually exclusive %lx.\n", flags );
|
|
return ERROR_INVALID_FLAGS;
|
|
}
|
|
|
|
//
|
|
// Ensure AlwaysShowUi is only specified for generic credentials
|
|
//
|
|
|
|
if ( flags & CREDUI_FLAGS_ALWAYS_SHOW_UI ) {
|
|
if ( (flags & CREDUI_FLAGS_GENERIC_CREDENTIALS) == 0) {
|
|
CreduiDebugLog("CreduiPromptForCredentials: AlwaysShowUi is only supported for generic credentials %lx.\n", flags );
|
|
return ERROR_INVALID_FLAGS;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Don't support a half-implemented feature
|
|
//
|
|
|
|
if ( securityContext != NULL ) {
|
|
CreduiDebugLog("CreduiPromptForCredentials: securityContext must be null.\n" );
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
|
|
//
|
|
// Validate the passed in UI info
|
|
//
|
|
|
|
if (!CreduiValidateUiInfoW(uiInfo))
|
|
{
|
|
CreduiDebugLog("CreduiPromptForCredentials: UI info is invalid.\n" );
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Ensure there are strings defined for the caption
|
|
//
|
|
|
|
if (flags & CREDUI_FLAGS_DO_NOT_PERSIST)
|
|
{
|
|
if ((targetName == NULL) &&
|
|
((uiInfo == NULL) ||
|
|
(uiInfo->pszMessageText == NULL) ||
|
|
(uiInfo->pszCaptionText == NULL)))
|
|
{
|
|
CreduiDebugLog("CreduiPromptForCredentials: DoNotPersist and target data empty.\n" );
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
}
|
|
else if (targetName != NULL)
|
|
{
|
|
if ((securityContext != NULL) ||
|
|
(targetName[0] == L'\0') ||
|
|
(wcslen(targetName) > CREDUI_MAX_DOMAIN_TARGET_LENGTH))
|
|
{
|
|
CreduiDebugLog("CreduiPromptForCredentials: target name bad %ws.\n", targetName );
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
else if (securityContext == NULL)
|
|
{
|
|
CreduiDebugLog("CreduiPromptForCredentials: no target data.\n" );
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Ensure the caller supplied the default value for the save check box
|
|
//
|
|
if (flags & CREDUI_FLAGS_SHOW_SAVE_CHECK_BOX)
|
|
{
|
|
if (save == NULL)
|
|
{
|
|
CreduiDebugLog("CreduiPromptForCredentials: ShowSaveCheckbox and save is NULL.\n" );
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Ensure the user supplied a username if they set CREDUI_FLAGS_KEEP_USERNAME
|
|
//
|
|
if ( flags & CREDUI_FLAGS_KEEP_USERNAME )
|
|
{
|
|
if ( pszUserName == NULL )
|
|
{
|
|
CreduiDebugLog("CreduiPromptForCredentials: CREDUI_FLAGS_KEEP_USERNAME and pszUserName is NULL.\n" );
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
}
|
|
|
|
// Use the stack for user name and password:
|
|
|
|
WCHAR userName[CREDUI_MAX_USERNAME_LENGTH + 1];
|
|
WCHAR password[CREDUI_MAX_PASSWORD_LENGTH + 1];
|
|
|
|
ZeroMemory(userName, sizeof userName);
|
|
ZeroMemory(password, sizeof password);
|
|
|
|
DWORD result = ERROR_OUTOFMEMORY;
|
|
|
|
if (FAILED(StringCchCopyW(userName, RTL_NUMBER_OF(userName), pszUserName)) ||
|
|
FAILED(StringCchCopyW(password, RTL_NUMBER_OF(password), pszPassword)))
|
|
{
|
|
result = ERROR_INVALID_PARAMETER;
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Do the password dialog box:
|
|
//
|
|
// Delay actually writing the credential to cred man if we're returning
|
|
// the credential to the caller.
|
|
// Otherwise, the CredWrite is just harvesting credentials for the next caller.
|
|
// So delay the CredWrite until this caller confirms the validity.
|
|
//
|
|
|
|
CreduiPasswordDialog* pDlg = new CreduiPasswordDialog(
|
|
doingCommandLine,
|
|
(pszUserName != NULL && pszPassword != NULL ),
|
|
CredCategory,
|
|
uiInfo,
|
|
targetName,
|
|
userName,
|
|
sizeof(userName)/sizeof(WCHAR)-sizeof(WCHAR), // Pass MaxChars instead of buffer size
|
|
password,
|
|
sizeof(password)/sizeof(WCHAR)-sizeof(WCHAR), // Pass MaxChars instead of buffer size
|
|
save,
|
|
flags,
|
|
(flags & CREDUI_FLAGS_GENERIC_CREDENTIALS) ? NULL : securityContext,
|
|
authError,
|
|
&result);
|
|
|
|
if ( pDlg != NULL )
|
|
{
|
|
delete pDlg;
|
|
pDlg = NULL;
|
|
}
|
|
else
|
|
{
|
|
// couldn't create dialog, return.
|
|
result = ERROR_OUTOFMEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
// copy outbound username
|
|
if ( pszUserName != NULL )
|
|
{
|
|
if (FAILED(StringCchCopyExW(
|
|
pszUserName,
|
|
ulUserNameBufferSize,
|
|
userName,
|
|
NULL,
|
|
NULL,
|
|
STRSAFE_FILL_ON_FAILURE)))
|
|
{
|
|
CreduiDebugLog("CreduiPromptForCredentials: type username is too long.\n" );
|
|
result = ERROR_INVALID_PARAMETER;
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
if ( pszPassword != NULL )
|
|
{
|
|
if (FAILED(StringCchCopyExW(
|
|
pszPassword,
|
|
ulPasswordBufferSize,
|
|
password,
|
|
NULL,
|
|
NULL,
|
|
STRSAFE_FILL_ON_FAILURE)))
|
|
{
|
|
CreduiDebugLog("CreduiPromptForCredentials: type password is too long.\n" );
|
|
result = ERROR_INVALID_PARAMETER;
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
Cleanup:
|
|
SecureZeroMemory(password, sizeof password);
|
|
|
|
return result;
|
|
}
|
|
|
|
//=============================================================================
|
|
|
|
CREDUIAPI
|
|
DWORD
|
|
WINAPI
|
|
CredUIPromptForCredentialsW(
|
|
CREDUI_INFOW *uiInfo,
|
|
CONST WCHAR *targetName,
|
|
CtxtHandle *securityContext,
|
|
DWORD authError,
|
|
PWSTR pszUserName,
|
|
ULONG ulUserNameBufferSize,
|
|
PWSTR pszPassword,
|
|
ULONG ulPasswordBufferSize,
|
|
BOOL *save,
|
|
DWORD flags
|
|
)
|
|
{
|
|
//
|
|
// Call the common code indicating this is the GUI interface
|
|
//
|
|
|
|
return CredUIPromptForCredentialsWorker(
|
|
FALSE, // GUI version
|
|
uiInfo,
|
|
targetName,
|
|
securityContext,
|
|
authError,
|
|
pszUserName,
|
|
ulUserNameBufferSize,
|
|
pszPassword,
|
|
ulPasswordBufferSize,
|
|
save,
|
|
flags );
|
|
|
|
}
|
|
|
|
CREDUIAPI
|
|
DWORD
|
|
WINAPI
|
|
CredUIPromptForCredentialsA(
|
|
CREDUI_INFOA *uiInfo,
|
|
CONST CHAR *targetName,
|
|
CtxtHandle *securityContext,
|
|
DWORD authError,
|
|
PSTR pszUserName,
|
|
ULONG ulUserNameBufferSize,
|
|
PSTR pszPassword,
|
|
ULONG ulPasswordBufferSize,
|
|
BOOL *save,
|
|
DWORD flags
|
|
)
|
|
{
|
|
DWORD result;
|
|
WCHAR targetNameW[CREDUI_MAX_DOMAIN_TARGET_LENGTH + 1];
|
|
|
|
WCHAR userName[CREDUI_MAX_USERNAME_LENGTH + 1];
|
|
WCHAR password[CREDUI_MAX_PASSWORD_LENGTH + 1];
|
|
|
|
UINT ConsoleCodePage = CP_ACP;
|
|
CREDUI_INFOW uiInfoW = {0};
|
|
|
|
if ((NULL == pszUserName) || (NULL == pszPassword))
|
|
{
|
|
result = ERROR_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
|
|
// Convert in paramters to Unicode:
|
|
// If a CREDUI_INFO structure was passed, convert it to wide now:
|
|
|
|
if (uiInfo != NULL) {
|
|
if (!CreduiConvertUiInfoToWide(uiInfo, &uiInfoW)) {
|
|
result = ERROR_OUTOFMEMORY;
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// If a target name was passed, convert it to wide now:
|
|
|
|
if (targetName != NULL)
|
|
{
|
|
if (!MultiByteToWideChar(ConsoleCodePage,
|
|
0,
|
|
targetName,
|
|
-1,
|
|
targetNameW,
|
|
CREDUI_MAX_DOMAIN_TARGET_LENGTH + 1) )
|
|
{
|
|
result = GetLastError();
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
|
|
userName[0] ='\0';
|
|
password[0] = '\0';
|
|
|
|
if (strlen(pszUserName) > 0 )
|
|
{
|
|
if ( !MultiByteToWideChar( ConsoleCodePage,
|
|
0,
|
|
pszUserName,
|
|
-1,
|
|
userName,
|
|
sizeof(userName)/sizeof(WCHAR) ) )
|
|
{
|
|
result = GetLastError();
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if (strlen(pszPassword) > 0)
|
|
{
|
|
if ( !MultiByteToWideChar( ConsoleCodePage,
|
|
0,
|
|
pszPassword,
|
|
-1,
|
|
password,
|
|
sizeof(password)/sizeof(WCHAR) ) )
|
|
{
|
|
result = GetLastError();
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Call the common code indicating this is the GUI interface
|
|
//
|
|
result = CredUIPromptForCredentialsWorker(
|
|
FALSE, // GUI version
|
|
(uiInfo != NULL) ? &uiInfoW : NULL,
|
|
(targetName != NULL) ? targetNameW : NULL,
|
|
securityContext,
|
|
authError,
|
|
userName,
|
|
ulUserNameBufferSize,
|
|
password,
|
|
ulPasswordBufferSize,
|
|
save,
|
|
flags );
|
|
|
|
|
|
if ( result == NO_ERROR && pszUserName != NULL )
|
|
{
|
|
if (!WideCharToMultiByte(ConsoleCodePage,
|
|
0,
|
|
userName,
|
|
-1,
|
|
pszUserName,
|
|
ulUserNameBufferSize,
|
|
NULL,
|
|
NULL) )
|
|
{
|
|
CreduiDebugLog("CreduiPromptForCredentials: type username cannot be converted to ANSI.\n" );
|
|
result = GetLastError();
|
|
}
|
|
}
|
|
|
|
if ( result == NO_ERROR && pszPassword != NULL )
|
|
{
|
|
if (!WideCharToMultiByte(ConsoleCodePage,
|
|
0,
|
|
password,
|
|
-1,
|
|
pszPassword,
|
|
ulPasswordBufferSize,
|
|
NULL,
|
|
NULL) )
|
|
{
|
|
CreduiDebugLog("CreduiPromptForCredentials: type password cannot be converted to ANSI.\n" );
|
|
result = GetLastError();
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
SecureZeroMemory(password, sizeof password);
|
|
|
|
// Free the CREDUI_INFO allocations:
|
|
|
|
if (uiInfo != NULL)
|
|
{
|
|
if (uiInfoW.pszMessageText != NULL)
|
|
{
|
|
delete [] const_cast<WCHAR *>(uiInfoW.pszMessageText);
|
|
}
|
|
|
|
if (uiInfoW.pszCaptionText != NULL)
|
|
{
|
|
delete [] const_cast<WCHAR *>(uiInfoW.pszCaptionText);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
DWORD
|
|
WINAPI
|
|
CredUIParseUserNameW(
|
|
CONST WCHAR *UserName,
|
|
WCHAR *user,
|
|
ULONG userBufferSize,
|
|
WCHAR *domain,
|
|
ULONG domainBufferSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
CredUIParseUserName is used to breakup a username returned by the cred management APIs
|
|
into a username and domain part that can be used as input to other system APIs that
|
|
require the full broken-up user credential.
|
|
|
|
The following formats are supported:
|
|
|
|
@@<MarshalledCredentialReference>: This is a marshaled credential reference as
|
|
as defined by the CredIsMarshaledCredential API. Such a credential is returned
|
|
in the 'user' parameter. The 'domain' parameter is set to an empty string.
|
|
|
|
|
|
<DomainName>\<UserName>: The <UserName> is returned in the 'user' parameter and
|
|
the <DomainName> is returned in the 'domain' parameter. The name is considered
|
|
to have the this syntax if the 'UserName' string contains a \.
|
|
|
|
<UserName>@<DnsDomainName>: The entire string is returned in the 'user' parameter.
|
|
The 'domain' parameter is set to an empty string.
|
|
For this syntax, the last @ in the string is used since <UserName> may
|
|
contain an @ but <DnsDomainName> cannot.
|
|
|
|
<UserName>: The <UserName> is returned in the 'user' parameter.
|
|
The 'domain' parameter is set to an empty string.
|
|
|
|
|
|
Arguments:
|
|
|
|
UserName - The user name to be parsed.
|
|
|
|
user - Specifies a buffer to copy the user name portion of the parsed string to.
|
|
|
|
userBufferSize - Specifies the size of the 'user' array in characters.
|
|
The caller can ensure the passed in array is large enough by using an array
|
|
that is CRED_MAX_USERNAME_LENGTH+1 characters long or by passing in an array that
|
|
is wcslen(UserName)+1 characters long.
|
|
|
|
domain - Specifies a buffer to copy the domain name portion of the parsed string to.
|
|
|
|
domainBufferSize - Specifies the size of the 'domain' array in characters.
|
|
The caller can ensure the passed in array is large enough by using an array
|
|
that is CRED_MAX_USERNAME_LENGTH+1 characters long or by passing in an array that
|
|
is wcslen(UserName)+1 characters long.
|
|
|
|
Return Values:
|
|
|
|
The following status codes may be returned:
|
|
|
|
ERROR_INVALID_ACCOUNT_NAME - The user name is not valid.
|
|
|
|
ERROR_INVALID_PARAMETER - One of the parameters is invalid.
|
|
|
|
ERROR_INSUFFICIENT_BUFFER - One of the buffers is too small.
|
|
|
|
|
|
--*/
|
|
{
|
|
DWORD Status;
|
|
CREDUI_USERNAME_TYPE UsernameType;
|
|
|
|
|
|
//
|
|
// Use the low level routine to do the work
|
|
//
|
|
|
|
Status = CredUIParseUserNameWithType(
|
|
UserName,
|
|
user,
|
|
userBufferSize,
|
|
domain,
|
|
domainBufferSize,
|
|
&UsernameType );
|
|
|
|
if ( Status != NO_ERROR ) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Avoid relative user names (for backward compatibility)
|
|
//
|
|
|
|
if ( UsernameType == CreduiRelativeUsername ) {
|
|
user[0] = L'\0';
|
|
domain[0] = L'\0';
|
|
return ERROR_INVALID_ACCOUNT_NAME;
|
|
}
|
|
|
|
return NO_ERROR;
|
|
|
|
}
|
|
|
|
DWORD
|
|
WINAPI
|
|
CredUIParseUserNameA(
|
|
CONST CHAR *userName,
|
|
CHAR *user,
|
|
ULONG userBufferSize,
|
|
CHAR *domain,
|
|
ULONG domainBufferSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Ansi version of CredUIParseUserName.
|
|
|
|
Arguments:
|
|
|
|
Same as wide version except userBufferSize and domainBufferSize are in terms of bytes.
|
|
|
|
Return Values:
|
|
|
|
Same as wide version.
|
|
|
|
--*/
|
|
{
|
|
DWORD Status;
|
|
|
|
WCHAR LocalUserName[CRED_MAX_USERNAME_LENGTH + 1];
|
|
WCHAR RetUserName[CRED_MAX_USERNAME_LENGTH + 1];
|
|
WCHAR RetDomainName[CRED_MAX_USERNAME_LENGTH + 1];
|
|
|
|
|
|
//
|
|
// Convert the passed in username to unicode
|
|
//
|
|
|
|
if ( MultiByteToWideChar( CP_ACP,
|
|
MB_ERR_INVALID_CHARS,
|
|
userName,
|
|
-1,
|
|
LocalUserName,
|
|
CRED_MAX_USERNAME_LENGTH + 1 ) == 0 ) {
|
|
|
|
|
|
Status = GetLastError();
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Call the unicode version of the API
|
|
//
|
|
|
|
Status = CredUIParseUserNameW(
|
|
LocalUserName,
|
|
RetUserName,
|
|
CRED_MAX_USERNAME_LENGTH + 1,
|
|
RetDomainName,
|
|
CRED_MAX_USERNAME_LENGTH + 1 );
|
|
|
|
if ( Status != NO_ERROR ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Convert the answers back to ANSI
|
|
//
|
|
|
|
if ( WideCharToMultiByte( CP_ACP,
|
|
0,
|
|
RetUserName,
|
|
-1,
|
|
user,
|
|
userBufferSize,
|
|
NULL,
|
|
NULL ) == 0 ) {
|
|
|
|
Status = GetLastError();
|
|
goto Cleanup;
|
|
}
|
|
|
|
if ( WideCharToMultiByte( CP_ACP,
|
|
0,
|
|
RetDomainName,
|
|
-1,
|
|
domain,
|
|
domainBufferSize,
|
|
NULL,
|
|
NULL ) == 0 ) {
|
|
|
|
Status = GetLastError();
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
|
|
Status = NO_ERROR;
|
|
|
|
Cleanup:
|
|
if ( Status != NO_ERROR ) {
|
|
user[0] = L'\0';
|
|
domain[0] = L'\0';
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
////////////////////////
|
|
// Command Line functions
|
|
|
|
//=============================================================================
|
|
// CredUIInitControls
|
|
//
|
|
// Returns TRUE on success or FALSE otherwise.
|
|
//
|
|
// Created 06/21/2000 johnstep (John Stephens)
|
|
//=============================================================================
|
|
|
|
extern "C"
|
|
BOOL
|
|
WINAPI
|
|
CredUIInitControls()
|
|
{
|
|
if (CreduiApiInit())
|
|
{
|
|
// Register the Credential controls:
|
|
|
|
if (CreduiCredentialControl::Register(CreduiInstance))
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//=============================================================================
|
|
// DllMain
|
|
//
|
|
// The DLL entry function. Since we are linked to the CRT, we must define a
|
|
// function with this name, which will be called from _DllMainCRTStartup.
|
|
//
|
|
// Arguments:
|
|
// instance (in)
|
|
// reason (in)
|
|
// (unused)
|
|
//
|
|
// Returns TRUE on success, or FALSE otherwise.
|
|
//
|
|
// Created 02/29/2000 johnstep (John Stephens)
|
|
//=============================================================================
|
|
|
|
extern "C"
|
|
BOOL
|
|
WINAPI
|
|
DllMain(
|
|
HINSTANCE instance,
|
|
DWORD reason,
|
|
VOID *
|
|
)
|
|
{
|
|
BOOL success = TRUE;
|
|
|
|
switch (reason)
|
|
{
|
|
case DLL_PROCESS_ATTACH:
|
|
DisableThreadLibraryCalls(instance);
|
|
CreduiInstance = instance;
|
|
|
|
// Create a global event which will be set when first-time
|
|
// initialization is completed by the first API call:
|
|
|
|
CreduiInitEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
|
|
if (CreduiInitEvent == NULL)
|
|
{
|
|
success = FALSE;
|
|
goto failinit;
|
|
}
|
|
|
|
SHFusionInitialize(NULL);
|
|
|
|
// Register the Credential controls:
|
|
if (!CreduiCredentialControl::Register(instance))
|
|
{
|
|
CloseHandle(CreduiInitEvent);
|
|
CreduiInitEvent = NULL;
|
|
success = FALSE;
|
|
goto failinit;
|
|
}
|
|
|
|
//
|
|
// Initialize the confirmation list
|
|
//
|
|
|
|
if ( !InitConfirmationList() ) {
|
|
|
|
CreduiCredentialControl::Unregister();
|
|
CloseHandle(CreduiInitEvent);
|
|
CreduiInitEvent = NULL;
|
|
success = FALSE;
|
|
}
|
|
failinit:
|
|
break;
|
|
|
|
case DLL_PROCESS_DETACH:
|
|
|
|
CleanUpConfirmationList();
|
|
|
|
if (CreduiFirstTime == FALSE)
|
|
{
|
|
CreduiIconParentWindow::Unregister();
|
|
}
|
|
|
|
// Unregister the Credential controls:
|
|
|
|
CreduiCredentialControl::Unregister();
|
|
|
|
SHFusionUninitialize();
|
|
// Make sure to free the global initialization event:
|
|
|
|
if (CreduiInitEvent != NULL)
|
|
{
|
|
CloseHandle(CreduiInitEvent);
|
|
}
|
|
|
|
UninitializeCredMgr();
|
|
|
|
break;
|
|
};
|
|
|
|
return success;
|
|
}
|
|
|
|
//=============================================================================
|
|
// DllCanUnloadNow (COM)
|
|
//
|
|
// Created 04/03/2000 johnstep (John Stephens)
|
|
//=============================================================================
|
|
|
|
STDAPI
|
|
DllCanUnloadNow()
|
|
{
|
|
return (CreduiComReferenceCount == 0) ? S_OK : S_FALSE;
|
|
}
|
|
|
|
//=============================================================================
|
|
// DllGetClassObject (COM)
|
|
//
|
|
// Created 04/03/2000 johnstep (John Stephens)
|
|
//=============================================================================
|
|
|
|
STDAPI
|
|
DllGetClassObject(
|
|
CONST CLSID &classId,
|
|
CONST IID &interfaceId,
|
|
VOID **outInterface
|
|
)
|
|
{
|
|
if (classId != CreduiStringArrayClassId)
|
|
{
|
|
return CLASS_E_CLASSNOTAVAILABLE;
|
|
}
|
|
|
|
CreduiStringArrayFactory *factory = new CreduiStringArrayFactory;
|
|
|
|
if (factory == NULL)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
HRESULT result = factory->QueryInterface(interfaceId, outInterface);
|
|
|
|
factory->Release();
|
|
|
|
// Release the string array object in any case, because of the
|
|
// QueryInterface succeeded, it already took another reference count on
|
|
// the object:
|
|
|
|
return result;
|
|
}
|
|
|
|
//=============================================================================
|
|
// DllRegisterServer (COM)
|
|
//
|
|
// Created 04/03/2000 johnstep (John Stephens)
|
|
//=============================================================================
|
|
|
|
STDAPI
|
|
DllRegisterServer()
|
|
{
|
|
HRESULT result = E_FAIL;
|
|
|
|
WCHAR fileName[MAX_PATH + 1];
|
|
|
|
if (GetModuleFileName(CreduiInstance, fileName, MAX_PATH))
|
|
{
|
|
HKEY regKey;
|
|
|
|
if (RegCreateKeyEx(
|
|
HKEY_CLASSES_ROOT,
|
|
L"CLSID\\" CREDUI_STRING_ARRAY_CLASS_STRING
|
|
L"\\InProcServer32",
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_SET_VALUE,
|
|
NULL,
|
|
®Key,
|
|
NULL) == ERROR_SUCCESS)
|
|
{
|
|
if (RegSetValueEx(
|
|
regKey,
|
|
NULL,
|
|
0,
|
|
REG_SZ,
|
|
reinterpret_cast<CONST BYTE *>(fileName),
|
|
(wcslen(fileName) + 1) * 2) == ERROR_SUCCESS)
|
|
{
|
|
if (RegSetValueEx(
|
|
regKey,
|
|
L"ThreadingModel",
|
|
0,
|
|
REG_SZ,
|
|
reinterpret_cast<CONST BYTE *>(L"Apartment"),
|
|
18) == ERROR_SUCCESS)
|
|
{
|
|
result = S_OK;
|
|
}
|
|
}
|
|
|
|
RegCloseKey(regKey);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
//=============================================================================
|
|
// DllUnregisterServer (COM)
|
|
//
|
|
// Created 04/03/2000 johnstep (John Stephens)
|
|
//=============================================================================
|
|
|
|
STDAPI
|
|
DllUnregisterServer()
|
|
{
|
|
HRESULT result = S_OK;
|
|
LONG error;
|
|
|
|
// Delete our InProcServer32 key:
|
|
|
|
error =
|
|
RegDeleteKey(
|
|
HKEY_CLASSES_ROOT,
|
|
L"CLSID\\" CREDUI_STRING_ARRAY_CLASS_STRING L"\\InProcServer32");
|
|
|
|
if ((error != ERROR_SUCCESS) &&
|
|
(error != ERROR_FILE_NOT_FOUND))
|
|
{
|
|
result = E_FAIL;
|
|
}
|
|
|
|
// Delete our class ID key:
|
|
|
|
error =
|
|
RegDeleteKey(
|
|
HKEY_CLASSES_ROOT,
|
|
L"CLSID\\" CREDUI_STRING_ARRAY_CLASS_STRING);
|
|
|
|
if ((error != ERROR_SUCCESS) &&
|
|
(error != ERROR_FILE_NOT_FOUND))
|
|
{
|
|
result = E_FAIL;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
CREDUIAPI
|
|
DWORD
|
|
WINAPI
|
|
CredUIConfirmCredentialsW(
|
|
PCWSTR pszTargetName,
|
|
BOOL bConfirm
|
|
)
|
|
{
|
|
CreduiDebugLog("CredUIConfirmCredentialsW called for %S, confirm= %x\n",pszTargetName,bConfirm);
|
|
if (NULL == pszTargetName) return ERROR_INVALID_PARAMETER;
|
|
return ConfirmCred ( pszTargetName, bConfirm, TRUE );
|
|
}
|
|
|
|
CREDUIAPI
|
|
DWORD
|
|
WINAPI
|
|
CredUIConfirmCredentialsA(
|
|
PCSTR pszTargetName,
|
|
BOOL bConfirm
|
|
)
|
|
{
|
|
WCHAR targetNameW[CRED_MAX_STRING_LENGTH+1+CRED_MAX_STRING_LENGTH];
|
|
|
|
// If a target name was passed, convert it to wide now:
|
|
|
|
if (pszTargetName != NULL)
|
|
{
|
|
if (MultiByteToWideChar(
|
|
CP_ACP, 0, pszTargetName, -1,
|
|
targetNameW,
|
|
CRED_MAX_STRING_LENGTH+1+CRED_MAX_STRING_LENGTH) == 0)
|
|
{
|
|
return GetLastError();
|
|
}
|
|
}
|
|
|
|
return CredUIConfirmCredentialsW ( targetNameW, bConfirm );
|
|
}
|
|
|
|
CREDUIAPI
|
|
DWORD
|
|
WINAPI
|
|
CredUICmdLinePromptForCredentialsW(
|
|
PCWSTR targetName,
|
|
PCtxtHandle securityContext,
|
|
DWORD dwAuthError,
|
|
PWSTR UserName,
|
|
ULONG ulUserBufferSize,
|
|
PWSTR pszPassword,
|
|
ULONG ulPasswordBufferSize,
|
|
PBOOL pfSave,
|
|
DWORD flags
|
|
)
|
|
{
|
|
//
|
|
// Call the common code indicating this is the command line interface
|
|
//
|
|
|
|
return CredUIPromptForCredentialsWorker(
|
|
TRUE, // Command line version
|
|
NULL, // Command line version has no uiInfo,
|
|
targetName,
|
|
securityContext,
|
|
dwAuthError,
|
|
UserName,
|
|
ulUserBufferSize,
|
|
pszPassword,
|
|
ulPasswordBufferSize,
|
|
pfSave,
|
|
flags );
|
|
}
|
|
|
|
CREDUIAPI
|
|
DWORD
|
|
WINAPI
|
|
CredUICmdLinePromptForCredentialsA(
|
|
PCSTR targetName,
|
|
PCtxtHandle pContext,
|
|
DWORD dwAuthError,
|
|
PSTR UserName,
|
|
ULONG ulUserBufferSize,
|
|
PSTR pszPassword,
|
|
ULONG ulPasswordBufferSize,
|
|
PBOOL pfSave,
|
|
DWORD flags
|
|
)
|
|
{
|
|
DWORD result = ERROR_GEN_FAILURE;
|
|
WCHAR *targetNameW = NULL;
|
|
|
|
if (!CreduiApiInit())
|
|
{
|
|
return ERROR_GEN_FAILURE;
|
|
}
|
|
|
|
// convert to unicode
|
|
|
|
WCHAR userNameW[CREDUI_MAX_USERNAME_LENGTH + 1];
|
|
WCHAR *pUserNameW;
|
|
|
|
if ( UserName != NULL )
|
|
{
|
|
if (MultiByteToWideChar(CP_ACP, 0, UserName, -1,
|
|
userNameW, sizeof(userNameW)/sizeof(WCHAR)) == 0)
|
|
{
|
|
result = GetLastError();
|
|
goto Exit;
|
|
}
|
|
pUserNameW = userNameW;
|
|
}
|
|
else
|
|
{
|
|
pUserNameW = NULL;
|
|
}
|
|
|
|
WCHAR passwordW[CREDUI_MAX_PASSWORD_LENGTH + 1];
|
|
WCHAR *ppasswordW;
|
|
|
|
if ( pszPassword != NULL )
|
|
{
|
|
if (MultiByteToWideChar(CP_ACP, 0, pszPassword, -1,
|
|
passwordW, sizeof(passwordW)/sizeof(WCHAR)) == 0)
|
|
{
|
|
result = GetLastError();
|
|
goto Exit;
|
|
}
|
|
ppasswordW = passwordW;
|
|
}
|
|
else
|
|
{
|
|
ppasswordW = NULL;
|
|
}
|
|
|
|
// Allocate the target name memory because it can be up to 32 KB:
|
|
|
|
if (targetName != NULL)
|
|
{
|
|
INT targetNameSize =
|
|
MultiByteToWideChar(CP_ACP, 0, targetName, -1, NULL, 0);
|
|
|
|
if (targetNameSize == 0)
|
|
{
|
|
result = GetLastError();
|
|
goto Exit;
|
|
}
|
|
|
|
targetNameW = new WCHAR[targetNameSize];
|
|
|
|
if (targetNameW != NULL)
|
|
{
|
|
if (MultiByteToWideChar(CP_ACP, 0, targetName, -1,
|
|
targetNameW, targetNameSize) == 0)
|
|
{
|
|
result = GetLastError();
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
targetNameW = NULL;
|
|
}
|
|
|
|
result = CredUICmdLinePromptForCredentialsW ( targetNameW,
|
|
pContext,
|
|
dwAuthError,
|
|
userNameW,
|
|
ulUserBufferSize,
|
|
passwordW,
|
|
ulPasswordBufferSize,
|
|
pfSave,
|
|
flags );
|
|
|
|
if ( UserName != NULL )
|
|
{
|
|
if (!WideCharToMultiByte(CP_ACP, 0, userNameW, -1, UserName,
|
|
ulUserBufferSize, NULL, NULL) ) {
|
|
result = GetLastError();
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if ( pszPassword != NULL )
|
|
{
|
|
if (!WideCharToMultiByte(CP_ACP, 0, passwordW, -1, pszPassword,
|
|
ulPasswordBufferSize, NULL, NULL)) {
|
|
result = GetLastError();
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
SecureZeroMemory(passwordW, sizeof passwordW);
|
|
|
|
// Free the target name memory:
|
|
delete [] targetNameW;
|
|
|
|
return result;
|
|
}
|
|
|
|
// call this api to store a single-sign-on credential
|
|
// retruns ERROR_SUCCESS if success
|
|
|
|
CREDUIAPI
|
|
DWORD
|
|
WINAPI
|
|
CredUIStoreSSOCredW (
|
|
PCWSTR pszRealm,
|
|
PCWSTR pszUsername,
|
|
PCWSTR pszPassword,
|
|
BOOL bPersist
|
|
)
|
|
{
|
|
CreduiDebugLog ( "CredUIStoreSSOCredW\n" );
|
|
|
|
DWORD dwResult = ERROR_GEN_FAILURE;
|
|
|
|
if ( pszUsername == NULL || pszPassword == NULL )
|
|
return dwResult;
|
|
|
|
// temporarily cache them locally
|
|
if (FAILED(StringCchCopyW(
|
|
gszSSOUserName,
|
|
RTL_NUMBER_OF(gszSSOUserName),
|
|
pszUsername)) ||
|
|
FAILED(StringCchCopyW(
|
|
gszSSOPassword,
|
|
RTL_NUMBER_OF(gszSSOPassword),
|
|
pszPassword)))
|
|
{
|
|
dwResult = ERROR_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
|
|
WCHAR szTargetName[CREDUI_MAX_DOMAIN_TARGET_LENGTH];
|
|
|
|
gbStoredSSOCreds = TRUE;
|
|
|
|
if ( gbWaitingForSSOCreds || !bPersist)
|
|
{
|
|
dwResult = ERROR_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
// otherwise store them in credmgr
|
|
|
|
if ( pszRealm )
|
|
{
|
|
// validate it's not zero length
|
|
if ((pszRealm[0] == L'\0') ||
|
|
FAILED(StringCchCopyExW(
|
|
szTargetName,
|
|
RTL_NUMBER_OF(szTargetName) - 2,
|
|
pszRealm,
|
|
NULL,
|
|
NULL,
|
|
STRSAFE_NO_TRUNCATION)))
|
|
{
|
|
dwResult = ERROR_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
GetDeaultSSORealm(szTargetName, TRUE);
|
|
}
|
|
|
|
// finalize the target name
|
|
// ensure that the tail will fit first
|
|
if (FAILED(StringCchCatExW(
|
|
szTargetName,
|
|
RTL_NUMBER_OF(szTargetName),
|
|
L"\\*",
|
|
NULL,
|
|
NULL,
|
|
STRSAFE_NO_TRUNCATION)))
|
|
{
|
|
dwResult = ERROR_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
|
|
// encrypt the password
|
|
PVOID pEncryptedPassword;
|
|
DWORD dwESize = wcslen(pszPassword)+1;
|
|
if (EncryptPassword ( (PWSTR)pszPassword, &pEncryptedPassword, &dwESize ) == ERROR_SUCCESS)
|
|
{
|
|
// write it out
|
|
|
|
CREDENTIALW NewCredential;
|
|
|
|
memset ( (void*)&NewCredential, 0, sizeof(CREDENTIALW));
|
|
|
|
DWORD dwFlags = 0;
|
|
|
|
NewCredential.TargetName = szTargetName;
|
|
NewCredential.Type = CRED_TYPE_DOMAIN_VISIBLE_PASSWORD;
|
|
NewCredential.Persist = bPersist ? CRED_PERSIST_ENTERPRISE : CRED_PERSIST_SESSION;
|
|
NewCredential.Flags = 0;
|
|
NewCredential.CredentialBlobSize = dwESize;
|
|
NewCredential.UserName = (LPWSTR)pszUsername;
|
|
NewCredential.CredentialBlob = reinterpret_cast<BYTE *>(pEncryptedPassword);
|
|
|
|
if ( CredWriteW(&NewCredential, dwFlags))
|
|
{
|
|
dwResult = ERROR_SUCCESS;
|
|
}
|
|
|
|
LocalFree (pEncryptedPassword);
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
SecureZeroMemory(gszSSOUserName, sizeof gszSSOUserName);
|
|
SecureZeroMemory(gszSSOPassword, sizeof gszSSOPassword);
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
CREDUIAPI
|
|
DWORD
|
|
WINAPI
|
|
CredUIStoreSSOCredA (
|
|
PCSTR pszRealm,
|
|
PCSTR pszUsername,
|
|
PCSTR pszPassword,
|
|
BOOL bPersist
|
|
)
|
|
{
|
|
DWORD dwResult = ERROR_GEN_FAILURE;
|
|
|
|
// convert to unicode
|
|
|
|
WCHAR realmW[CREDUI_MAX_DOMAIN_TARGET_LENGTH];
|
|
WCHAR *prealmW;
|
|
|
|
if ( pszRealm != NULL )
|
|
{
|
|
if (MultiByteToWideChar(CP_ACP, 0, pszRealm, -1,
|
|
realmW, RTL_NUMBER_OF(realmW)) == 0)
|
|
{
|
|
goto Exit;
|
|
}
|
|
prealmW = realmW;
|
|
}
|
|
else
|
|
{
|
|
prealmW = NULL;
|
|
}
|
|
|
|
WCHAR userNameW[CREDUI_MAX_USERNAME_LENGTH + 1];
|
|
WCHAR *pUserNameW;
|
|
|
|
if ( pszUsername != NULL )
|
|
{
|
|
if (MultiByteToWideChar(CP_ACP, 0, pszUsername, -1,
|
|
userNameW, RTL_NUMBER_OF(userNameW)) == 0)
|
|
{
|
|
goto Exit;
|
|
}
|
|
pUserNameW = userNameW;
|
|
}
|
|
else
|
|
{
|
|
pUserNameW = NULL;
|
|
}
|
|
|
|
WCHAR passwordW[CREDUI_MAX_PASSWORD_LENGTH + 1];
|
|
WCHAR *ppasswordW;
|
|
|
|
if ( pszPassword != NULL )
|
|
{
|
|
if (MultiByteToWideChar(CP_ACP, 0, pszPassword, -1,
|
|
passwordW, RTL_NUMBER_OF(passwordW)) == 0)
|
|
{
|
|
goto Exit;
|
|
}
|
|
ppasswordW = passwordW;
|
|
}
|
|
else
|
|
{
|
|
ppasswordW = NULL;
|
|
}
|
|
|
|
dwResult = CredUIStoreSSOCredW ( prealmW, pUserNameW, ppasswordW, bPersist );
|
|
|
|
Exit:
|
|
// clean up passwords in memory
|
|
SecureZeroMemory(passwordW, sizeof passwordW);
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
// call this api to retrieve the username for a single-sign-on credential
|
|
// retruns ERROR_SUCCESS if success, ERROR_NOT_FOUND if none was found
|
|
|
|
CREDUIAPI
|
|
DWORD
|
|
WINAPI
|
|
CredUIReadSSOCredW (
|
|
PCWSTR pszRealm,
|
|
PWSTR* ppszUsername
|
|
)
|
|
{
|
|
DWORD dwReturn = ERROR_NOT_FOUND;
|
|
WCHAR szTargetName[CREDUI_MAX_DOMAIN_TARGET_LENGTH];
|
|
|
|
if ( pszRealm )
|
|
{
|
|
// validate it's not zero length
|
|
if ((pszRealm[0] == L'\0') ||
|
|
FAILED(StringCchCopyExW(
|
|
szTargetName,
|
|
RTL_NUMBER_OF(szTargetName) - 2,
|
|
pszRealm,
|
|
NULL,
|
|
NULL,
|
|
STRSAFE_NO_TRUNCATION)))
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
GetDeaultSSORealm(szTargetName, FALSE);
|
|
}
|
|
|
|
// validate it's not zero length
|
|
if (szTargetName[0] != L'\0')
|
|
{
|
|
// finalize the target name
|
|
// ensure that the tail will fit first
|
|
if (FAILED(StringCchCatExW(
|
|
szTargetName,
|
|
RTL_NUMBER_OF(szTargetName),
|
|
L"\\*",
|
|
NULL,
|
|
NULL,
|
|
STRSAFE_NO_TRUNCATION)))
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
PCREDENTIALW pCred;
|
|
DWORD dwFlags = 0;
|
|
|
|
if ( CredReadW ( szTargetName,
|
|
CRED_TYPE_DOMAIN_VISIBLE_PASSWORD,
|
|
dwFlags,
|
|
&pCred ) )
|
|
{
|
|
size_t len = wcslen(pCred->UserName);
|
|
*ppszUsername = (PWSTR)LocalAlloc(LMEM_ZEROINIT, sizeof(WCHAR)*(len+1));
|
|
if ( *ppszUsername )
|
|
{
|
|
dwReturn = ERROR_SUCCESS;
|
|
StringCchCopyW(*ppszUsername, len + 1, pCred->UserName);
|
|
}
|
|
|
|
CredFree ( pCred );
|
|
}
|
|
}
|
|
|
|
return dwReturn;
|
|
}
|
|
|
|
// call this api to retrieve the username for a single-sign-on credential
|
|
// retruns ERROR_SUCCESS if success, ERROR_NOT_FOUND if none was found
|
|
|
|
CREDUIAPI
|
|
DWORD
|
|
WINAPI
|
|
CredUIReadSSOCredA (
|
|
PCSTR pszRealm,
|
|
PSTR* ppszUsername
|
|
)
|
|
{
|
|
DWORD dwReturn = ERROR_NOT_FOUND;
|
|
WCHAR szTargetName[CREDUI_MAX_DOMAIN_TARGET_LENGTH];
|
|
|
|
PCREDENTIALW pCred;
|
|
DWORD dwFlags = 0;
|
|
UINT uiConsoleCodePage = CP_ACP;
|
|
|
|
if ( pszRealm )
|
|
{
|
|
// validate it's not zero length
|
|
int len = strlen(pszRealm);
|
|
if ( len == 0 )
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (MultiByteToWideChar(uiConsoleCodePage,
|
|
0,
|
|
pszRealm,
|
|
len + 1,
|
|
szTargetName,
|
|
RTL_NUMBER_OF(szTargetName) - 2)
|
|
== 0)
|
|
{
|
|
dwReturn = GetLastError();
|
|
goto Exit;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
GetDeaultSSORealm(szTargetName, FALSE);
|
|
}
|
|
|
|
if (szTargetName[0] != L'\0')
|
|
{
|
|
// finalize the target name
|
|
// ensure that the tail will fit first
|
|
if (FAILED(StringCchCatExW(
|
|
szTargetName,
|
|
RTL_NUMBER_OF(szTargetName),
|
|
L"\\*",
|
|
NULL,
|
|
NULL,
|
|
STRSAFE_NO_TRUNCATION)))
|
|
{
|
|
dwReturn = ERROR_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
|
|
// first call credmgr to set the target info
|
|
if ( CredReadW ( szTargetName,
|
|
CRED_TYPE_DOMAIN_VISIBLE_PASSWORD,
|
|
dwFlags,
|
|
&pCred ) )
|
|
{
|
|
DWORD dwConvertedLength = 0;
|
|
|
|
dwConvertedLength = WideCharToMultiByte(uiConsoleCodePage,
|
|
0,
|
|
pCred->UserName,
|
|
-1,
|
|
*ppszUsername,
|
|
0,
|
|
NULL,
|
|
NULL);
|
|
|
|
if (dwConvertedLength == 0)
|
|
{
|
|
// string does not convert or other error - all map to this
|
|
dwReturn = ERROR_INVALID_PARAMETER;
|
|
}
|
|
else
|
|
{
|
|
// have proper buffer size and string will convert without loss
|
|
*ppszUsername = (PSTR)LocalAlloc(LMEM_ZEROINIT, dwConvertedLength);
|
|
if (*ppszUsername)
|
|
{
|
|
dwReturn = WideCharToMultiByte(uiConsoleCodePage,
|
|
0,
|
|
pCred->UserName,
|
|
-1,
|
|
*ppszUsername,
|
|
dwConvertedLength,
|
|
NULL,
|
|
NULL);
|
|
|
|
if (dwReturn)
|
|
{
|
|
// nonzero return is success
|
|
dwReturn = ERROR_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
dwReturn = GetLastError();
|
|
}
|
|
}
|
|
}
|
|
CredFree ( pCred );
|
|
}
|
|
// end cred read
|
|
}
|
|
// end target name not empty
|
|
|
|
Exit:
|
|
|
|
return dwReturn;
|
|
}
|