Impersonate

Hi.
I have a strange problem.  I'm able to call LogonUser without any problems, but the account stays the same. I'm running as SYSTEM account in machine.config.  Here is my code:

Const LOGON32_LOGON_INTERACTIVE As Integer = 2
  Const LOGON32_LOGON_NETWORK As Integer = 3
  Const LOGON32_LOGON_BATCH As Integer = 4
  Const LOGON32_LOGON_SERVICE As Integer = 5
  Const LOGON32_LOGON_UNLOCK As Integer = 7
  Const LOGON32_LOGON_NETWORK_CLEARTEXT As Integer = 8
  Const LOGON32_LOGON_NEW_CREDENTIALS As Integer = 9
  Const LOGON32_PROVIDER_DEFAULT As Integer = 0

  <DllImport("advapi32.dll", SetLastError:=True)> _
 Public Shared Function LogonUser( _
  ByVal lpszUsername As String, _
  ByVal lpszDomain As String, _
  ByVal lpszPassword As String, _
  ByVal dwLogonType As Integer, _
  ByVal dwLogonProvider As Integer, _
  ByRef phToken As IntPtr _
  ) As Int32
  End Function

  <DllImport("advapi32.dll", SetLastError:=True)> _
 Public Shared Function ImpersonateLoggedOnUser( _
  ByRef hToken As IntPtr _
  ) As Int32
  End Function

  <DllImport("advapi32.dll", SetLastError:=True)> _
 Public Shared Function RevertToSelf() As Int32
  End Function

  <DllImport("kernel32.dll", SetLastError:=True)> _
 Public Shared Function CloseHandle(ByVal hObject As IntPtr) As Int32
  End Function

Private Sub Button2_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button2.Click
    Dim username As String
    Dim domain As String
    Dim pass As String

    username = "John"
    domain = "WORK-DOMAIN"
    pass = "p88776"

    Response.Write(Environment.UserName & "<br>")

    Dim lnToken As IntPtr
    Dim TResult As Integer = LogonUser(username, domain, pass, LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT, lnToken)
    If TResult > 0 Then
      ImpersonateLoggedOnUser(lnToken)
      Dim Size As Int32 = 79
      Response.Write(Environment.UserName & "<br>")
     
      RevertToSelf()
      Response.Write("<br>" & Environment.UserName)
      CloseHandle(lnToken)
    Else
      Response.Write("Not logged on: " & Environment.UserName)
    End If
  End Sub

In a perfect world this code should result in:
SYSTEM
John
SYSTEM

But instead it just returns:
SYSTEM
SYSTEM
SYSTEM

Does anyone know what might cause this?

Thanks,
Shawn
LVL 1
ShawnGAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

ihenryCommented:
So when executing the code, are you really sure LogonUser is returning non zero value?
ShawnGAuthor Commented:
LogonUser returns 1
ihenryCommented:
And what does ImpersonateLoggedOnUser return?
Rowby Goren Makes an Impact on Screen and Online

Learn about longtime user Rowby Goren and his great contributions to the site. We explore his method for posing questions that are likely to yield a solution, and take a look at how his career transformed from a Hollywood writer to a website entrepreneur.

ShawnGAuthor Commented:
it returns 0
ihenryCommented:
Ok, at least we have something to start with. It looks like a privilege problem though you're running under local system user account. Have you tried impersonating using local admin privilege in web.config and see if it works.

And you might want to investigate more on why ImpersonateLoggedOnUser is returning zero using the following code.

    <DllImport("kernel32.dll")> _
    Public Shared Function FormatMessage(ByVal dwFlags As Integer, ByRef lpSource As IntPtr, _
        ByVal dwMessageId As Integer, ByVal dwLanguageId As Integer, ByRef lpBuffer As [String], _
        ByVal nSize As Integer, ByRef Arguments As IntPtr) As Integer
    End Function

    Public Shared Function GetErrorMessage(ByVal errorCode As Integer) As String
        Dim FORMAT_MESSAGE_ALLOCATE_BUFFER As Integer = &H100
        Dim FORMAT_MESSAGE_IGNORE_INSERTS As Integer = &H200
        Dim FORMAT_MESSAGE_FROM_SYSTEM As Integer = &H1000

        Dim messageSize As Integer = 255
        Dim lpMsgBuf As String
        Dim dwFlags As Integer = FORMAT_MESSAGE_ALLOCATE_BUFFER Or FORMAT_MESSAGE_FROM_SYSTEM Or FORMAT_MESSAGE_IGNORE_INSERTS

        Dim ptrlpSource As IntPtr = IntPtr.Zero
        Dim prtArguments As IntPtr = IntPtr.Zero

        Dim retVal As Integer = FormatMessage(dwFlags, ptrlpSource, errorCode, 0, lpMsgBuf, _
            messageSize, prtArguments)
        If 0 = retVal Then
            Throw New Exception("Failed to format message for error code " + errorCode.ToString() + ". ")
        End If

        Return lpMsgBuf
    End Function

ShawnGAuthor Commented:
Not sure what errorcode you want me to pass to that function..  If i pass 0 it returns "The operation completed successfully."
I tried impersonating using local admin privilege in web.config.  Although it runs under the local account, I'm still unable to impersonate from code.  Now it returns:
Administrator
Administrator
SYSTEM
ihenryCommented:
:o) sorry, forgot to post this

Dim ret As Integer = Marshal.GetLastWin32Error()
GetErrorMessage(ret)

ShawnGAuthor Commented:
It gives me the error message: "The handle is invalid"
ihenryCommented:
Your code looks about right to me. Can you check what lnToken returns after calling LogonUser?
And also can you try to call RevertToSelf before calling LogonUser and also call it once more after ImpersonateLoggedOnUser.
ShawnGAuthor Commented:
lnToken returns different values everytime, 1034, 3694 etc.  I put in RevertToSelf before calling LogonUser and after ImpersonateLoggedOnUser.  It just returns:
SYSTEM
SYSTEM
SYSTEM
ihenryCommented:
I'm not sure why it's not working, the token seems to have a non zero value too. You might want to try the sample code from MSDN and I think that's the best impersonation sample code I have seen so far.

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemsecurityprincipalwindowsimpersonationcontextclasstopic.asp

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
ShawnGAuthor Commented:
Finally an example that works for me too!!
Thank you so much ihenry, you saved my day :-)

Shawn
ihenryCommented:
Shawn, I think I need to mention this.
The sample code does not really do a perfect job. In fact, there's a flaw that could causes the process thread to be running under the privileged user rights outside the method call. For example, if for some reasons the code throws exception before the Undo call takes place. Just make sure you close the token handle and undo the impersonating context in catch and finally block.


HTH
Henry
ShawnGAuthor Commented:
Thanks for the tip!
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
ASP.NET

From novice to tech pro — start learning today.