private bool PromptForCredentialsCredUIWin(IntPtr owner, bool storedCredentials)
{
if (AllowStoredCredentials)
{
Log.Debug("Stored credentials are allowed");
var credentials = ReadCredential(Target, true);
if (credentials != null)
{
Log.Debug("Successfully read stored credentials: '{0}'", credentials);
UserName = credentials.UserName;
Password = credentials.Password;
return true;
}
}
if (!IsAuthenticationRequired)
{
Log.Debug("No authentication is required, no need to prompt for credentials");
return false;
}
var info = CreateCredUIInfo(owner, false);
var flags = CredUi.CredUiWinFlags.Generic;
if (ShowSaveCheckBox)
{
flags |= CredUi.CredUiWinFlags.Checkbox;
}
var inBuffer = IntPtr.Zero;
var outBuffer = IntPtr.Zero;
try
{
uint inBufferSize = 0;
if (UserName.Length > 0)
{
// First call is only to get the required buffer size
CredUi.CredPackAuthenticationBuffer(0, UserName, Password, IntPtr.Zero, ref inBufferSize);
if (inBufferSize > 0)
{
inBuffer = Marshal.AllocCoTaskMem((int)inBufferSize);
if (!CredUi.CredPackAuthenticationBuffer(0, UserName, Password, inBuffer, ref inBufferSize))
{
throw Log.ErrorAndCreateException(x => new CredentialException(Marshal.GetLastWin32Error()),
"Failed to create the authentication buffer before prompting");
}
}
}
uint outBufferSize = 0;
uint package = 0;
Log.Debug("Prompting user for credentials");
var result = CredUi.CredUIPromptForWindowsCredentials(ref info, 0, ref package, inBuffer, inBufferSize,
out outBuffer, out outBufferSize, ref _isSaveChecked, flags);
switch (result)
{
case CredUi.CredUiReturnCodes.NO_ERROR:
var userName = new StringBuilder(CredUi.CREDUI_MAX_USERNAME_LENGTH);
var password = new StringBuilder(CredUi.CREDUI_MAX_PASSWORD_LENGTH);
var userNameSize = (uint)userName.Capacity;
var passwordSize = (uint)password.Capacity;
uint domainSize = 0;
if (!CredUi.CredUnPackAuthenticationBuffer(0, outBuffer, outBufferSize, userName, ref userNameSize, null, ref domainSize, password, ref passwordSize))
{
throw Log.ErrorAndCreateException(x => new CredentialException(Marshal.GetLastWin32Error()),
"Failed to create the authentication buffer after prompting");
}
UserName = userName.ToString();
Password = password.ToString();
Log.Debug("User entered credentials with username '{0}'", UserName);
if (ShowSaveCheckBox)
{
_confirmTarget = Target;
// If the NativeCredential was stored previously but the user has now cleared the save checkbox,
// we want to delete the NativeCredential.
if (storedCredentials && !IsSaveChecked)
{
DeleteCredential(Target);
}
if (IsSaveChecked)
{
WriteCredential(Target, UserName, Password);
}
}
return true;
case CredUi.CredUiReturnCodes.ERROR_CANCELLED:
Log.Debug("User canceled the credentials prompt");
return false;
default:
throw Log.ErrorAndCreateException(x => new CredentialException((int)result),
"Failed to prompt for credentials, error code '{0}'", result);
}
}
finally
{
if (inBuffer != IntPtr.Zero)
{
Marshal.FreeCoTaskMem(inBuffer);
}
if (outBuffer != IntPtr.Zero)
{
Marshal.FreeCoTaskMem(outBuffer);
}
}
}