duckwizzle duckwizzle - 2 months ago 15
C# Question

Using SecureString with LogonUser

For learning purposes I am writing my own Active Directory client. In order to execute commands like unlocking accounts and resetting passwords, I have to put in my admin account and password and use and

WindowsIdentity.Impersonate
run the code as my admin account. I am wondering about my options for securing my password, as it has to be used many times across my program.

From what I understand, I can use
SecureString
to store the password. But to run code as my admin account, I have use
WindowsIdentity.Impersonate
, and to use that I have to get a token from
LogonUser
which requires a regular
string
and not
SecureString
.

So I would have to:


  1. Login at start up

  2. Convert input to a
    SecureString

  3. Clear the input



Then later when I want to preform a function that requires elevation:


  1. Convert previously created
    SecureString
    to
    string

  2. Pass the converted string to
    LogonUser

  3. Clear the convert string to
    null

  4. Execute command

  5. Clear the
    LogonUser
    object



Is this the correct way to approach this? It seems weird to have to have to convert the
SecureString
to
string
to use it... seems like it would defeat the purpose and leave the password more vulnerable while I am converting it.

EDIT: Fixed the name for LogonUser

Answer

In your UserImpersonation class, change how you declare LogonUser to use IntPtr instead of string for password.

The code sample for Marshal.SecureStringToGlobalAllocUnicode has exactly what you need. Here's the relevant snippet:

[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern bool LogonUser(String username, String domain,
                                      IntPtr password, int logonType,
                                      int logonProvider, ref IntPtr token);

...

IntPtr tokenHandle = IntPtr.Zero;

IntPtr passwordPtr = IntPtr.Zero;

try
{
    // Marshal the SecureString to unmanaged memory.
    passwordPtr = Marshal.SecureStringToGlobalAllocUnicode(password);

    returnValue = LogonUser(userName, domainName, passwordPtr,
                            LOGON32_LOGON_INTERACTIVE,
                            LOGON32_PROVIDER_DEFAULT, ref tokenHandle);

 }
 finally
 {
     // Zero-out and free the unmanaged string reference.
     Marshal.ZeroFreeGlobalAllocUnicode(passwordPtr);

     // Close the token handle.
     CloseHandle(tokenHandle);
 }
Comments