Advertisement

08.07.2008 at 10:23AM PDT, ID: 23630236
[x]
Attachment Details
[x]
The Solution Rating System

With so many solutions, how can you tell which solutions are most likely to help you and which ones are not? To provide you with a tool to use, we rate our solutions based on various elements that most accurately determine if a solution is a quality solution. To explain what factors affect the solution rating, here are the elements we take into consideration when formulating our solution rating.

  • The Grade of the Solution
  • The Zone Rank of the Expert Providing the Solution
  • The Number of Author and Expert Comments
  • The Number of Experts Contributing
  • The Feedback of the Community

Your Input Matters
Because of the way the system is set up, the most important variable in this equation is you. As a member of Experts Exchange, you are able to cast your vote on the quality of the solutions in regard to how complete, accurate, helpful and easy to understand each solution is. When you provide your feedback, each rating is adjusted accordingly. So, if you see a solution that has a poor rating that you think is a good solution, let us know by rating it. As you do, the rating will be adjusted and will become more accurate for other members of our site.

If you have any suggestions that you would like to make for our rating system, please ask a question in the Suggestions Zone of Community Support.

Thank you!

9.0

User impersonation with LogonUser from within a .Net service assembly

Asked by kkamm in .Net Editors & IDEs, Microsoft Visual Basic.Net

Tags:

I have a .Net system service that requires calls to start and stop 2 other services. I want to run this service in a limited context, but still be able to control the other 2 services. I am using the ServiceProcess.ServiceController object to control the other services.

To that end, I set up an impersonation class that uses  the LogonUser API call to impersonate a user that would have sufficient privileges to control services. I have not been able to do a successful impersonation session, regardless of the context the service was running in or the user context requested for impersonation.

That led me to consider if .Net permissions prevent this sort of access. The service is running under full trust, but are there any other .Net security gotchas that would prevent me from doing context impersonation from within the executing service assembly?

I am attaching a code snippet for the impersonation class.Start Free Trial
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
188:
189:
190:
191:
192:
193:
194:
195:
196:
197:
198:
199:
200:
201:
202:
''' <summary>
''' Class clsImpersonate encapsulates data and methods to log in as a given user and run the program in that context.
''' ''' </summary>
''' <remarks></remarks>
Public Class clsImpersonate
 
    Shared impersonationContext As Security.Principal.WindowsImpersonationContext
 
    Public Enum LogonType As Integer
        'This logon type is intended for users who will be interactively using the computer, such as a user being logged on
        'by a terminal server, remote shell, or similar process.
        'This logon type has the additional expense of caching logon information for disconnected operations;
        'therefore, it is inappropriate for some client/server applications,
        'such as a mail server.
        LOGON32_LOGON_INTERACTIVE = 2
 
        'This logon type is intended for high performance servers to authenticate plaintext passwords.
        'The LogonUser function does not cache credentials for this logon type.
        LOGON32_LOGON_NETWORK = 3
 
        'This logon type is intended for batch servers, where processes may be executing on behalf of a user without
        'their direct intervention. This type is also for higher performance servers that process many plaintext
        'authentication attempts at a time, such as mail or Web servers.
        'The LogonUser function does not cache credentials for this logon type.
        LOGON32_LOGON_BATCH = 4
 
        'Indicates a service-type logon. The account provided must have the service privilege enabled.
        LOGON32_LOGON_SERVICE = 5
 
        'This logon type is for GINA DLLs that log on users who will be interactively using the computer.
        'This logon type can generate a unique audit record that shows when the workstation was unlocked.
        LOGON32_LOGON_UNLOCK = 7
 
        'This logon type preserves the name and password in the authentication package, which allows the server to make
        'connections to other network servers while impersonating the client. A server can accept plaintext credentials
        'from a client, call LogonUser, verify that the user can access the system across the network, and still
        'communicate with other servers.
        'NOTE: Windows NT:  This value is not supported.
        LOGON32_LOGON_NETWORK_CLEARTEXT = 8
 
        'This logon type allows the caller to clone its current token and specify new credentials for outbound connections.
        'The new logon session has the same local identifier but uses different credentials for other network connections.
        'NOTE: This logon type is supported only by the LOGON32_PROVIDER_WINNT50 logon provider.
        'NOTE: Windows NT:  This value is not supported.
        LOGON32_LOGON_NEW_CREDENTIALS = 9
 
    End Enum
 
    Public Enum LogonProvider As Integer
        'Use the standard logon provider for the system.
        'The default security provider is negotiate, unless you pass NULL for the domain name and the user name
        'is not in UPN format. In this case, the default provider is NTLM.
        'NOTE: Windows 2000/NT:   The default security provider is NTLM.
        LOGON32_PROVIDER_DEFAULT = 0
        LOGON32_PROVIDER_WINNT50 = 3
        LOGON32_PROVIDER_WINNT40 = 2
        LOGON32_PROVIDER_WINNT35 = 1
    End Enum
    Public Enum ImpersonationLevel As Integer
       
        LOGON32_SECURITY_ANONYMOUS = 0
        LOGON32_SECURITY_IDENTIFICATION = 1
        LOGON32_SECURITY_IMPERSONATION = 2
        LOGON32_SECURITY_DELEGATION = 3
 
    End Enum
 
 
    Declare Auto Function LogonUser Lib "advapi32.dll" (ByVal lpszUsername As String, _
                            ByVal lpszDomain As String, ByVal lpszPassword As String, ByVal dwLogonType As LogonType, _
                            ByVal dwLogonProvider As LogonProvider, ByRef phToken As IntPtr) As Integer
 
 
    Declare Auto Function DuplicateToken Lib "advapi32.dll" ( _
                            ByVal ExistingTokenHandle As IntPtr, _
                            ByVal ImpersonationLevel As Integer, _
                            ByRef DuplicateTokenHandle As IntPtr) As Integer
 
    Declare Auto Function RevertToSelf Lib "advapi32.dll" () As Long
    Declare Auto Function CloseHandle Lib "kernel32.dll" (ByVal handle As IntPtr) As Long
 
 
    Public Shared Property p_impersonationContext() As Security.Principal.WindowsImpersonationContext
 
        Get
 
            Return impersonationContext
 
        End Get
 
        Set(ByVal value As Security.Principal.WindowsImpersonationContext)
 
            impersonationContext = value
 
        End Set
 
    End Property
 
    Public Shared Function impersonateValidUser(ByVal userName As String, ByVal domain As String, ByVal password As String) As Boolean
 
        'API calls used to log user in as another user and run program in that context.
 
        Dim token As IntPtr = IntPtr.Zero
        Dim tokenDuplicate As IntPtr = IntPtr.Zero
 
        impersonateValidUser = False
 
        Try
 
            If CBool(RevertToSelf()) Then
 
#If DEBUG Then
                Diagnostics.EventLog.WriteEntry("RFIDWatchDogLog", "DEBUG:Attempting to logon as " & userName & "with password " & password, EventLogEntryType.Warning)
#End If
 
                If LogonUser(userName, domain, password, LogonType.LOGON32_LOGON_SERVICE, LogonProvider.LOGON32_PROVIDER_DEFAULT, token) <> 0 Then
 
                    If DuplicateToken(token, ImpersonationLevel.LOGON32_SECURITY_IMPERSONATION, tokenDuplicate) <> 0 Then
 
                        Dim tempWindowsIdentity As System.Security.Principal.WindowsIdentity = New Security.Principal.WindowsIdentity(tokenDuplicate)
                        impersonationContext = tempWindowsIdentity.Impersonate()
                        tempWindowsIdentity = Nothing
 
                        If Not impersonationContext Is Nothing Then
 
                            impersonateValidUser = True
 
 
                        End If
 
                    End If
 
                Else
 
#If DEBUG Then
                    Diagnostics.EventLog.WriteEntry("RFIDWatchDogLog", "DEBUG:Impersonation not successful", EventLogEntryType.Warning)
#End If
 
                End If
 
            End If
 
        Catch ex As Exception
 
            Diagnostics.EventLog.WriteEntry("RFIDWatchDogLog", "ERROR:impersonateValidUser: " & ex.Message, EventLogEntryType.Error)
 
        End Try
 
 
        If Not tokenDuplicate.Equals(IntPtr.Zero) Then
 
            CloseHandle(tokenDuplicate)
 
        End If
 
        If Not token.Equals(IntPtr.Zero) Then
 
            CloseHandle(token)
 
        End If
 
 
    End Function
 
    Public Shared Function GetCurrentUserInfo() As String
 
        'Generate a message string showing current user identity. Generally used for DEBUG only.
 
        Try
 
            Dim UserIdentityInfo As System.Security.Principal.WindowsIdentity
            Dim strMsg As String
 
            UserIdentityInfo = System.Security.Principal.WindowsIdentity.GetCurrent()
 
            strMsg = "User Name: " & UserIdentityInfo.Name & ControlChars.CrLf
 
            strMsg = strMsg & " Token: " & UserIdentityInfo.Token.ToString() & ControlChars.CrLf
 
            strMsg = strMsg & " Authenticated: " & UserIdentityInfo.AuthenticationType & ControlChars.CrLf
 
            strMsg = strMsg & " System: " & UserIdentityInfo.IsSystem & ControlChars.CrLf
 
            strMsg = strMsg & " Guest: " & UserIdentityInfo.IsGuest & ControlChars.CrLf
 
            strMsg = strMsg & " Anonymous: " & UserIdentityInfo.IsAnonymous & ControlChars.CrLf
 
            GetCurrentUserInfo = strMsg
 
        Catch ex As Exception
 
            Diagnostics.EventLog.WriteEntry("RFIDWatchDogLog", "GetCurrentUserInfo ERROR: " & ex.Message, EventLogEntryType.Error)
 
            GetCurrentUserInfo = Nothing
 
        End Try
 
 
    End Function
 
 
End Class
 
 
[+][-]08.08.2008 at 12:21AM PDT, ID: 22188009

View this solution now by starting your 7-day free trial. Setting up your free trial is quick, easy, and secure. We will return you to this solution, unlocked, when you're done.

 

About this solution

Zones: .Net Editors & IDEs, Microsoft Visual Basic.Net
Tags: VB.Net
Sign Up Now!
Solution Provided By: AkisC
Participating Experts: 1
Solution Grade: B
 
 
[+][-]08.11.2008 at 09:20AM PDT, ID: 22205732

Often, when Experts are collaborating with members who have asked questions, they will request additional information about the problem. Askers respond with an author comment like this one.

Start your 7-day free trial to view this Author Comment or ask the Experts your question.

 
 
Loading Advertisement...
20080716-EE-VQP-32 / EE_QW_2_20070628