PRB: Access Denied Error When Calling LogonUser API
ID: Q223334
|
The information in this article applies to:
-
Microsoft Visual Basic Learning, Professional, and Enterprise Editions for Windows, versions 5.0, 6.0
SYMPTOMS
When attempting to make a Win32 Application Programmer Interface (API) call LogonUser from within a Visual Basic Component Object Model (COM) component with Active Server Pages (ASP), one of the following errors appears:
'5' - "Access Denied."
'1314' - "A required privilege is not held by the client."
CAUSE
The Internet Information Server (IIS) authenticated user that is making the request to LogonUser does not hold the correct privilege, which causes LogonUser to fail.
RESOLUTION
If your component is in-process, you can create a Microsoft Transaction Server (MTS) package to host your COM component, which will handle the security context switching for you.
For additional information on how to create an empty package and add components to it, please see the following
article in the Microsoft Knowledge Base:
Q223406 HOWTO: Create an Empty MTS Package to Add Components for ASP
An alternative resolution is to use the following Win32 APIs:
- RevertToSelf
- LogonUser
- ImpersonateLoggedOnUser
- First call RevertToSelf. Calling LogonUser will fail if the thread making the call does not have the correct security context. The SYSTEM account holds the correct privilege to call LogonUser successfully.
Calling RevertToSelf will cause the thread to execute as the SYSTEM account if the following conditions are true:
- The web application is running in-process.
- If the component is under MTS control, it is a library package.
- Next call LogonUser specifying the Windows NT account you want the component to run as. LogonUser will return a handle to the security token.
- Then call ImpersonateLoggedOnUser passing the security token returned by LogonUser.
Your component is now impersonating the security context of the Windows NT account you specified.
Important: After you are done with the impersonation, you must again call RevertToSelf.
STATUS
This behavior is by design.
MORE INFORMATION
Sample Code
Visual Basic 6.0 Project (ProgID = LoginAdmin.ImpersonateUser):
Code for BAS Module:
Declare Function LogonUser Lib "advapi32.dll" Alias "LogonUserA" (ByVal lpszUsername As String,
ByVal lpszDomain As String, ByVal lpszPassword As String, ByVal dwLogonType As Long, ByVal
dwLogonProvider As Long, phToken As Long) As Long
Declare Function ImpersonateLoggedOnUser Lib "advapi32.dll" (ByVal hToken As Long) As Long
Declare Function RevertToSelf Lib "advapi32.dll" () As Long
Code for Class Module:
Option Explicit
Const LOGON32_LOGON_INTERACTIVE = 2
Const LOGON32_PROVIDER_DEFAULT = 0
Public Sub Logon(ByVal strAdminUser As String, ByVal strAdminPassword As String, ByVal strAdminDomain As String)
Dim lngTokenHandle, lngLogonType, lngLogonProvider As Long
Dim blnResult As Boolean
lngLogonType = LOGON32_LOGON_INTERACTIVE
lngLogonProvider = LOGON32_PROVIDER_DEFAULT
blnResult = RevertToSelf()
blnResult = LogonUser(strAdminUser, strAdminDomain, strAdminPassword, _
lngLogonType, lngLogonProvider, _
lngTokenHandle)
blnResult = ImpersonateLoggedOnUser(lngTokenHandle)
End Sub
Public Sub Logoff()
Dim blnResult As Boolean
blnResult = RevertToSelf()
End Sub
Code for ASP:
<%
Option Explicit
Dim objLogon
Set objLogon = Server.CreateObject("LoginAdmin.ImpersonateUser")
objLogon.Logon "AdminUserid", "AdminPassword", "AdminDomain"
'Body of code for the page...
objLogon.Logoff
Set objLogon = Nothing
%>
Note that, when you call the Logoff method as coded here, you will revert to the SYSTEM userid, so do this only at the end of page processing.
Additional query words:
Keywords : kbCOMt kbVBp kbVBp500 kbVBp600 kbGrpASP
Version : WINDOWS:5.0,6.0
Platform : WINDOWS
Issue type : kbprb