Link to home
Start Free TrialLog in
Avatar of Sanx69
Sanx69Flag for Australia

asked on

Shutting down Windows XP - AdjustTokenPrivileges failing with error code 1300

I'm writing a very simple shell application and it needs to be able to reboot or shutdown the operating system; in this case, Windows XP SP2. The shell will be run in a standard user context - with no administrative rights.

Currently, when the code is run with EWX_SHUTDOWN or EWX_REBOOT flags passed to the DoExitWindows subroutine, absolutely nothing happens. Passing EWX_LOGOFF succesfully logs the user off.

When a reboot or shutdown is attempted, AdjustTokenPrivileges returns error 1300 - "Not all privileges referenced are assigned". After that, any attempt at calling ExitWindowsEx returns error 87 - "Invalid parameter".

Has anyone got any ideas?
Const SE_PRIVILEGE_ENABLED As Integer = &H2
Const TOKEN_QUERY As Integer = &H8
Const TOKEN_ADJUST_PRIVILEGES As Integer = &H20
Const SE_SHUTDOWN_NAME As String = "SeShutdownPrivilege"
Const EWX_LOGOFF As Integer = &H0
Const EWX_SHUTDOWN As Integer = &H1
Const EWX_REBOOT As Integer = &H2
Const EWX_FORCE As Integer = &H4
Const EWX_POWEROFF As Integer = &H8
Const EWX_FORCEIFHUNG As Integer = &H10
 
Friend Structure Luid
    Public Count As Integer
    Public Luid As Long
    Public Attr As Integer
End Structure
 
Private Declare Function GetCurrentProcess Lib "kernel32.dll" () As IntPtr
 
Private Declare Function OpenProcessToken Lib "advapi32.dll" (ByVal h As IntPtr, ByVal acc As Integer, ByRef phtok As IntPtr) As Boolean
 
Private Declare Function LookupPrivilegeValue Lib "advapi32.dll" Alias "LookupPrivilegeValueA" (ByVal host As String, ByVal name As String, ByRef pluid As Long) As Boolean
 
Private Declare Function AdjustTokenPrivileges Lib "advapi32.dll" (ByVal htok As IntPtr, ByVal disall As Boolean, ByRef newst As Luid, ByVal len As Integer, ByVal prev As IntPtr, ByVal relen As IntPtr) As Boolean
 
Private Declare Function ExitWindowsEx Lib "user32.dll" (ByVal flg As Integer, ByVal rea As Integer) As Boolean
 
Private Sub DoExitWindows(ByVal flg As Integer)
    Dim tp As Luid
    Dim hproc As IntPtr = GetCurrentProcess()
    Dim htok As IntPtr = IntPtr.Zero
 
    OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES Or TOKEN_QUERY, htok)
    tp.Count = 1
    tp.Luid = 0
    tp.Attr = SE_PRIVILEGE_ENABLED
 
    LookupPrivilegeValue(Nothing, SE_SHUTDOWN_NAME, tp.Luid)
 
    AdjustTokenPrivileges(htok, False, tp, 0, IntPtr.Zero, IntPtr.Zero)
 
    ExitWindowsEx(flg, 0)
 
End Sub

Open in new window

Avatar of jkr
jkr
Flag of Germany image

Why are you trying to enable that privilege? If it is granted to the user (which is always the case for Workstations, only on servers that's different), it'll also be enabled...
Avatar of Sanx69

ASKER

The shell application will be running on a Workstation. I'm not trying to grant the SeShutdownPrivilege just for the hell of it; it's to enable the application to reboot or shutdown the workstation. That's all I'm trying to do. If there's another way round it which doesn't involve shelling to a command script or WMI then I'd like to hear it.
Um, I don't know too much of scripting or VB, but 'InitiateSystemShutdown()' (http://msdn.microsoft.com/en-us/library/aa376873.aspx) should do all the work for you.
Avatar of Sanx69

ASKER

InitiateSystemShutdown may well work, but it requires the same process privilege as the ExitWindowsEx call, so the same problem applies. It's not the call to ExitWindowsEx that's the problem; it's assigning the process the SE_SHUTDOWN_NAME privilege that the both calls require.

Incidentally, ExitWindowsEx is designed to be used by UI-interactive applications. InitiateShutdown, InitiateSystemShutdown and their various derivatives are designed to be used by non-interactive applications, as they optionally display warnings to the users or the system shutdown dialog box prompting the user to log off. See here for more info:
http://msdn.microsoft.com/en-us/library/aa376881(VS.85).aspx

It's not the shutdown code that I'm having trouble with; it's assigning the right privilege tokens to the process.
Err, just in case I am not clear enough - there is no need to assign this privilege. Either you have it or you don't.
ASKER CERTIFIED SOLUTION
Avatar of Sanx69
Sanx69
Flag of Australia image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
A little course on NT-like privileges: You cannot grant them programatically unless you are Admin. Anyway, granting a privilege requires the affected user to log off and back on to 'see' the change in addirion, since it's security token has to be renewed for that. The only privilege that is granted yet disabled by default is 'SeDebugPrivilege' for Admins where you actively need to enable it programatically. Everything else you wrote so far - sorry for saying so - makes no sense at all... at least to me, that is...
Avatar of Sanx69

ASKER

Well, Microsoft don't agree, I'm afraid. Have a look at the documentation for the ExitWindowsEx function: http://msdn.microsoft.com/en-us/library/aa376868(VS.85).aspx

At the bottom of the remarks section, it says:
To shut down or restart the system, the calling process must use the  AdjustTokenPrivileges function to enable the SE_SHUTDOWN_NAME privilege. For more information, see  Running with Special Privileges.
I start to understand that this seems to be a VB specific issue (sorry, but I am more a C++ guy), take a look at http://forums.msdn.microsoft.com/en-US/vbgeneral/thread/c424547c-fb5b-4b7a-84a8-63274a437ef0/