Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 398
duck Avatar asked Jan 08 '15 22:01

duck


1 Answers

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);
 }
like image 112
Ilian Avatar answered Oct 04 '22 20:10

Ilian