Fixes for #33 based on suggestions from @sclarke81

pull/38/head
David Hall 2019-01-28 10:12:35 -07:00
parent dd78ab07c9
commit aa2b8dac98
2 changed files with 52 additions and 57 deletions

View File

@ -1,22 +1,21 @@
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
using Vanara.Extensions;
using Vanara.InteropServices;
using Vanara.PInvoke;
using static Vanara.PInvoke.CredUI;
namespace Vanara.Security
{
/// <summary>
/// Safe container for an authentication buffer. Allows for creation using native <c>CredPackAuthenticationBuffer</c> method or assignment from an existing
/// <c>IntPtr</c>. Can unpack to <see cref="string"/> or <see cref="SecureString"/> values.
/// Safe container for an authentication buffer. Allows for creation using native <c>CredPackAuthenticationBuffer</c> method or
/// assignment from an existing <c>IntPtr</c>. Can unpack to <see cref="string"/> or <see cref="SecureString"/> values.
/// </summary>
public class AuthenticationBuffer : IDisposable
{
private IntPtr buffer = IntPtr.Zero;
private int bufferSize;
private SafeCoTaskMemHandle buffer;
public AuthenticationBuffer(string userName, string password)
{
@ -32,26 +31,19 @@ namespace Vanara.Security
Init(0, pUserName, pPassword);
}
public AuthenticationBuffer(IntPtr authBuffer, int authBufferSize)
public AuthenticationBuffer(IntPtr authBuffer, int authBufferSize) => buffer = new SafeCoTaskMemHandle(authBuffer, authBufferSize);
public IntPtr DangerousHandle => buffer?.DangerousGetHandle() ?? IntPtr.Zero;
public int Size => buffer?.Size ?? 0;
public static implicit operator IntPtr(AuthenticationBuffer b) => b.DangerousHandle;
public void Dispose()
{
buffer = authBuffer;
bufferSize = authBufferSize;
}
public IntPtr DangerousHandle => buffer;
public int Size => bufferSize;
private void Init(CredPackFlags flags, string pUserName, string pPassword)
{
if (!CredPackAuthenticationBuffer(flags, pUserName, pPassword, IntPtr.Zero, ref bufferSize) && Marshal.GetLastWin32Error() == 122) /*ERROR_INSUFFICIENT_BUFFER*/
{
buffer = Marshal.AllocCoTaskMem(bufferSize);
if (!CredPackAuthenticationBuffer(flags, pUserName, pPassword, buffer, ref bufferSize))
throw new Win32Exception();
}
else
throw new Win32Exception();
if (buffer is null) return;
buffer.Zero();
buffer = null;
}
public void UnPack(bool decryptProtectedCredentials, out string userName, out string domainName, out string password)
@ -63,7 +55,7 @@ namespace Vanara.Security
var domainNameSize = pDomainName.Capacity;
var passwordSize = pPassword.Capacity;
if (!CredUnPackAuthenticationBuffer(decryptProtectedCredentials ? CredPackFlags.CRED_PACK_PROTECTED_CREDENTIALS : 0x0, buffer, bufferSize,
if (!CredUnPackAuthenticationBuffer(decryptProtectedCredentials ? CredPackFlags.CRED_PACK_PROTECTED_CREDENTIALS : 0x0, DangerousHandle, Size,
pUserName, ref userNameSize, pDomainName, ref domainNameSize, pPassword, ref passwordSize))
throw new Win32Exception();
@ -81,7 +73,7 @@ namespace Vanara.Security
var domainNameSize = pDomainName.CharCapacity;
var passwordSize = pPassword.CharCapacity;
if (!CredUnPackAuthenticationBuffer(decryptProtectedCredentials ? CredPackFlags.CRED_PACK_PROTECTED_CREDENTIALS : 0x0, buffer, bufferSize,
if (!CredUnPackAuthenticationBuffer(decryptProtectedCredentials ? CredPackFlags.CRED_PACK_PROTECTED_CREDENTIALS : 0x0, DangerousHandle, Size,
(IntPtr)pUserName, ref userNameSize, (IntPtr)pDomainName, ref domainNameSize, (IntPtr)pPassword, ref passwordSize))
throw new Win32Exception();
@ -90,12 +82,17 @@ namespace Vanara.Security
password = pPassword.DangerousGetHandle().ToSecureString();
}
public void Dispose()
private void Init(CredPackFlags flags, string pUserName, string pPassword)
{
if (buffer != IntPtr.Zero)
Marshal.FreeCoTaskMem(buffer);
var bufferSize = 0;
if (!CredPackAuthenticationBuffer(flags, pUserName, pPassword, IntPtr.Zero, ref bufferSize) && Win32Error.GetLastError() == Win32Error.ERROR_INSUFFICIENT_BUFFER)
{
buffer = new SafeCoTaskMemHandle(bufferSize);
if (!CredPackAuthenticationBuffer(flags, pUserName, pPassword, DangerousHandle, ref bufferSize))
throw new Win32Exception();
}
else
throw new Win32Exception();
}
public static implicit operator IntPtr(AuthenticationBuffer b) => b.buffer;
}
}

View File

@ -238,34 +238,32 @@ namespace Vanara.Windows.Forms
if (ShowSaveCheckBox)
flag |= WindowsCredentialsDialogOptions.CREDUIWIN_CHECKBOX;
AuthenticationBuffer buf;
if (EncryptPassword && SecurePassword != null)
buf = new AuthenticationBuffer(UserName.ToSecureString(), SecurePassword);
else
buf = new AuthenticationBuffer(UserName, Password);
var retVal = CredUIPromptForWindowsCredentials(info, 0, ref authPackage, buf, (uint)buf.Size, out var outAuthBuffer, out var outAuthBufferSize, ref saveChecked, flag);
if (retVal == Win32Error.ERROR_CANCELLED)
return false;
retVal.ThrowIfFailed();
var outAuth = new AuthenticationBuffer(outAuthBuffer, (int)outAuthBufferSize);
if (EncryptPassword)
using (var buf = EncryptPassword && SecurePassword != null ? new AuthenticationBuffer(UserName.ToSecureString(), SecurePassword)
: new AuthenticationBuffer(UserName, Password))
{
outAuth.UnPack(true, out SecureString u, out var d, out var p);
Password = null;
SecurePassword = p;
UserName = d?.Length > 0 ? $"{d.ToInsecureString()}\\{u.ToInsecureString()}" : u.ToInsecureString();
}
else
{
outAuth.UnPack(true, out string u, out var d, out var p);
Password = p;
SecurePassword = null;
UserName = string.IsNullOrEmpty(d) ? u : $"{d}\\{u}";
}
var retVal = CredUIPromptForWindowsCredentials(info, 0, ref authPackage, buf, (uint)buf.Size, out var outAuthBuffer, out var outAuthBufferSize, ref saveChecked, flag);
if (retVal == Win32Error.ERROR_CANCELLED)
return false;
retVal.ThrowIfFailed();
using (var outAuth = new AuthenticationBuffer(outAuthBuffer, (int)outAuthBufferSize))
{
if (EncryptPassword)
{
outAuth.UnPack(true, out SecureString u, out var d, out var p);
Password = null;
SecurePassword = p;
UserName = d?.Length > 0 ? $"{d.ToInsecureString()}\\{u.ToInsecureString()}" : u.ToInsecureString();
}
else
{
outAuth.UnPack(true, out string u, out var d, out var p);
Password = p;
SecurePassword = null;
UserName = string.IsNullOrEmpty(d) ? u : $"{d}\\{u}";
}
}
}
if (ValidatePassword != null)
{
var pve = new PasswordValidatorEventArgs(UserName, Password, SecurePassword);