HI guys,
I'm relatively new to the .net development realm. I am creating an
application in vb.net to monitor services on remote servers.
The application works great when I am logged in and using it - I am a
Domain Admin, and as a result a local admin on the remote computers.
However when I try to run the application as a standard domain user I
receive a priviledges error.
I have attempted to implement impersonation, using credentials
supplied by the application under 'My.Settings' however this seems not
to work either; I recieve a bad username or password error, despite
the fact I know that the passwords and username are correct.
The error clearly displays a valid username in the form of server_name
\userName (note that these remote machines are not part of a domain)
but my username and password are the same for the domain and remote
machines.
I have attched the relevant areas of my code for your viewing, and I
would be really grateful if anyone can point me in the right
direction!
Thanks,
-Chris
NB: Please note the error occurs on the line "aa.BeginImpers onation()"
------------------------------ Beging Code ------------------
Function service2(ByVal srvname)
Dim aa As New AliasAccount(My .Settings.userN ame,
My.Settings.pas sword, serverName)
Try
aa.BeginImperso nation()
arrRemoteServic es =
System.ServiceP rocess.ServiceC ontroller.GetSe rvices(serverNa me)
For Each Service In arrRemoteServic es
Dim x As New ListViewItem
Dim y As New ListViewItem
If Service.Service Name = srvname Then
'Can use DisplayName (long name of service)
If Service.Status =
System.ServiceP rocess.ServiceC ontrollerStatus .Running Then
If chkLogging.Chec ked = True Then
x.Text = TimeOfDay & "," & serverName & "
" & Service.Service Name & ": Running"
x.BackColor = Color.Green
x.ForeColor = Color.White
lstView1.Items. Add(x)
End If
y.Text = TimeOfDay & "," & serverName & " " &
Service.Service Name & ": Running"
y.BackColor = Color.Green
y.ForeColor = Color.White
frmHist.lstView 1.Items.Add(y)
serverStatus = serverStatus + 1
ElseIf Service.Status =
System.ServiceP rocess.ServiceC ontrollerStatus .StartPending Then
x.Text = TimeOfDay & "," & serverName & " " &
Service.Service Name & ": Starting"
x.BackColor = Color.Blue
x.ForeColor = Color.White
lstView1.Items. Add(x)
y.Text = TimeOfDay & "," & serverName & " " &
Service.Service Name & ": Starting"
y.BackColor = Color.Green
y.ForeColor = Color.White
frmHist.lstView 1.Items.Add(y)
ElseIf Service.Status =
System.ServiceP rocess.ServiceC ontrollerStatus .Stopped Then
x.Text = TimeOfDay & "," & serverName & " " &
Service.Service Name & ": Stopped"
x.BackColor = Color.Red
x.ForeColor = Color.White
lstView1.Items. Add(x)
y.Text = TimeOfDay & "," & serverName & " " &
Service.Service Name & ": Stopped"
y.BackColor = Color.Green
y.ForeColor = Color.White
frmHist.lstView 1.Items.Add(y)
ElseIf Service.Status =
System.ServiceP rocess.ServiceC ontrollerStatus .StopPending Then
x.Text = TimeOfDay & "," & serverName & " " &
Service.Service Name & ": Stopping"
x.BackColor = Color.Red
x.ForeColor = Color.White
lstView1.Items. Add(x)
y.Text = TimeOfDay & "," & serverName & " " &
Service.Service Name & ": Stopping"
y.BackColor = Color.Green
y.ForeColor = Color.White
frmHist.lstView 1.Items.Add(y)
End If
Failures2()
End If
Next
Catch x As Exception
MsgBox("Failed to obtain service information on server: "
& serverName & ", the error returned was: " & Err.Description )
Timer1.Enabled = False
End Try
aa.EndImpersona tion()
End Function
Public Class AliasAccount
Private _username, _password, _domainname As String
Private _tokenHandle As New IntPtr(0)
Private _dupeTokenHandl e As New IntPtr(0)
Private _impersonatedUs er As
System.Security .Principal.Wind owsImpersonatio nContext
Public Sub New(ByVal username As String, ByVal password As String)
Dim nameparts() As String = username.Split( "\")
If nameparts.Lengt h 1 Then
_domainname = nameparts(0)
_username = nameparts(1)
Else
_username = username
End If
_password = password
End Sub
Public Sub New(ByVal username As String, ByVal password As String,
ByVal domainname As String)
_username = username
_password = password
_domainname = domainname
End Sub
Public Sub BeginImpersonat ion()
Const LOGON32_PROVIDE R_DEFAULT As Integer = 0
Const LOGON32_LOGON_I NTERACTIVE As Integer = 2
Const SecurityImperso nation As Integer = 2
Dim win32ErrorNumbe r As Integer
_tokenHandle = IntPtr.Zero
_dupeTokenHandl e = IntPtr.Zero
If Not LogonUser(_user name, _domainname, _password,
LOGON32_LOGON_I NTERACTIVE, LOGON32_PROVIDE R_DEFAULT, _tokenHandle)
Then
win32ErrorNumbe r =
System.Runtime. InteropServices .Marshal.GetLas tWin32Error()
Throw New ImpersonationEx ception(win32Er rorNumber,
GetErrorMessage (win32ErrorNumb er), _username, _domainname)
End If
If Not DuplicateToken( _tokenHandle, SecurityImperso nation,
_dupeTokenHandl e) Then
win32ErrorNumbe r =
System.Runtime. InteropServices .Marshal.GetLas tWin32Error()
CloseHandle(_to kenHandle)
Throw New ImpersonationEx ception(win32Er rorNumber, "Unable
to duplicate token!", _username, _domainname)
End If
Dim newId As New
System.Security .Principal.Wind owsIdentity(_du peTokenHandle)
_impersonatedUs er = newId.Impersona te()
End Sub
Public Sub EndImpersonatio n()
If Not _impersonatedUs er Is Nothing Then
_impersonatedUs er.Undo()
_impersonatedUs er = Nothing
If Not System.IntPtr.o p_Equality(_tok enHandle,
IntPtr.Zero) Then
CloseHandle(_to kenHandle)
End If
If Not System.IntPtr.o p_Equality(_dup eTokenHandle,
IntPtr.Zero) Then
CloseHandle(_du peTokenHandle)
End If
End If
End Sub
Public ReadOnly Property username() As String
Get
Return _username
End Get
End Property
Public ReadOnly Property domainname() As String
Get
Return _domainname
End Get
End Property
Public ReadOnly Property currentWindowsU sername() As String
Get
Return
System.Security .Principal.Wind owsIdentity.Get Current().Name
End Get
End Property
#Region "Exception Class"
Public Class ImpersonationEx ception
Inherits System.Exceptio n
Public ReadOnly win32ErrorNumbe r As Integer
Public Sub New(ByVal win32ErrorNumbe r As Integer, ByVal msg As
String, ByVal username As String, ByVal domainname As String)
MyBase.New(Stri ng.Format("Impe rsonation of {1}\{0} failed!
[{2}] {3}", username, domainname, win32ErrorNumbe r, msg))
Me.win32ErrorNu mber = win32ErrorNumbe r
End Sub
End Class
#End Region
#Region "External Declarations and Helpers"
Private Declare Auto Function LogonUser Lib "advapi32.d ll" (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 Boolean
Private Declare Auto Function DuplicateToken Lib
"advapi32.d ll" (ByVal ExistingTokenHa ndle As IntPtr, _
ByVal SECURITY_IMPERS ONATION_LEVEL As Integer, _
ByRef DuplicateTokenH andle As IntPtr) As Boolean
Private Declare Auto Function CloseHandle Lib
"kernel32.d ll" (ByVal handle As IntPtr) As Boolean
<System.Runtime .InteropService s.DllImport("ke rnel32.dll")_
Private Shared Function FormatMessage(B yVal 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
Private 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(d wFlags, ptrlpSource,
errorCode, 0, lpMsgBuf, messageSize, prtArguments)
If 0 = retVal Then
Throw New System.Exceptio n("Failed to format message for
error code " + errorCode.ToStr ing() + ". ")
End If
Return lpMsgBuf
End Function
#End Region
End Class