Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Show Authentication dialog in C# for windows Vista/7

Tags:

c#

pinvoke

I want to get network login credentials from a user.

I'm using .NET 3.5 with C#. Up until now I used the CredUIPromptForCredentials call (a very useful link on how to use it can be found here)

My problem is that the CredUIPromptForCredentials API call shows the old windows 2000/XP credentials dialog and not the new Vista/7 one.

I've read on msdn that I should use the CredUIPromptForWindowsCredentials function.

Can someone post an example of how to use it with C#? I also need to be able to get the credentials that were entered.

like image 232
Rubinsh Avatar asked Nov 09 '10 14:11

Rubinsh


2 Answers

I managed to implement a solution that is working for me.

Here is the source code:

    [DllImport("ole32.dll")]
    public static extern void CoTaskMemFree(IntPtr ptr);

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    private struct CREDUI_INFO
    {
        public int cbSize;
        public IntPtr hwndParent;
        public string pszMessageText;
        public string pszCaptionText;
        public IntPtr hbmBanner;
    }  


    [DllImport("credui.dll", CharSet = CharSet.Auto)]
    private static extern bool CredUnPackAuthenticationBuffer(int dwFlags,
                                                               IntPtr pAuthBuffer,
                                                               uint cbAuthBuffer,
                                                               StringBuilder pszUserName,
                                                               ref int pcchMaxUserName,
                                                               StringBuilder pszDomainName,
                                                               ref int pcchMaxDomainame,
                                                               StringBuilder pszPassword,
                                                               ref int pcchMaxPassword);

    [DllImport("credui.dll", CharSet = CharSet.Auto)]
    private static extern int CredUIPromptForWindowsCredentials(ref CREDUI_INFO notUsedHere,
                                                                 int authError,
                                                                 ref uint authPackage,
                                                                 IntPtr InAuthBuffer,
                                                                 uint InAuthBufferSize,
                                                                 out IntPtr refOutAuthBuffer,
                                                                 out uint refOutAuthBufferSize,
                                                                 ref bool fSave,
                                                                 int flags);



    public static void GetCredentialsVistaAndUp(string serverName, out NetworkCredential networkCredential)
    {
        CREDUI_INFO credui = new CREDUI_INFO();
        credui.pszCaptionText = "Please enter the credentails for " + serverName;
        credui.pszMessageText = "DisplayedMessage";
        credui.cbSize = Marshal.SizeOf(credui);
        uint authPackage = 0;
        IntPtr outCredBuffer = new IntPtr();
        uint outCredSize;
        bool save = false;
        int result = CredUIPromptForWindowsCredentials(ref credui,
                                                       0,
                                                       ref authPackage,
                                                       IntPtr.Zero,
                                                       0,
                                                       out outCredBuffer,
                                                       out outCredSize,
                                                       ref save,
                                                       1 /* Generic */);

        var usernameBuf = new StringBuilder(100);
        var passwordBuf  = new StringBuilder(100);
        var domainBuf = new StringBuilder(100);

        int maxUserName = 100;
        int maxDomain = 100;
        int maxPassword = 100;
        if (result == 0)
        {
            if (CredUnPackAuthenticationBuffer(0, outCredBuffer, outCredSize, usernameBuf, ref maxUserName,
                                               domainBuf, ref maxDomain, passwordBuf, ref maxPassword))
            {
                //TODO: ms documentation says we should call this but i can't get it to work
                //SecureZeroMem(outCredBuffer, outCredSize);

                //clear the memory allocated by CredUIPromptForWindowsCredentials 
                CoTaskMemFree(outCredBuffer);
                networkCredential = new NetworkCredential()
                                        {
                                            UserName = usernameBuf.ToString(),
                                            Password = passwordBuf.ToString(),
                                            Domain = domainBuf.ToString()
                                        };
                return;
            }
        }

        networkCredential = null;
    }

I still need to work out the fine details such as how to remember the last credentials that were entered etc...

But the major part works.

like image 95
Rubinsh Avatar answered Nov 15 '22 15:11

Rubinsh


Here is some code to go on extracted from bytes.com post:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
struct _CREDUI_INFO
{
  public int cbSize;
  public IntPtr hwndParent;
  public string pszMessageText;
  public string pszCaptionText;
  public IntPtr hbmBanner;
}
class Program
{
  [DllImport("credui.dll", CharSet=CharSet.Unicode)]
  internal static extern uint CredUIPromptForWindowsCredentials(ref
    _CREDUI_INFO notUsedHere,
    int authError,
    ref uint authPackage,
    IntPtr InAuthBuffer,
    uint InAuthBufferSize,
    out IntPtr refOutAuthBuffer,
    out uint refOutAuthBufferSize,
    ref bool fSave,
    int flags);

  const int CREDUIWIN_AUTHPACKAGE_ONLY = 0x10;

  static void Main()
  {
    _CREDUI_INFO credui = new _CREDUI_INFO();
    credui.cbSize = Marshal.SizeOf(credui);
    credui.pszCaptionText = "Testje";
    credui.pszMessageText = "Message";
    uint authPackage = 0;
    IntPtr outCredBuffer;
    uint outCredSize;
    bool save = false;

    uint ret = CredUIPromptForWindowsCredentials(ref credui,
      0,
      ref authPackage,
      IntPtr.Zero,
      0,
      out outCredBuffer,
      out outCredSize,
      ref save,
      CREDUIWIN_AUTHPACKAGE_ONLY);

    if(ret != 0)
    {
      // failed to load function...
      // ...
    }
    else
    {
      // extract credentials from the buffer returned, using more
      //   credui.dll API's .
      // ...
    }
  }
}
like image 24
Michael Goldshteyn Avatar answered Nov 15 '22 16:11

Michael Goldshteyn