It is funny that, to write a programming task as trivial as rebooting a Win32 box, one needs to write some non-trivial code.
You could always choose to just copy the code from some place and forget about it. But, many years ago when I was a beginner to the windows SDK, I found that understanding how this one program worked gave me a lot of insight into the workinga of the Win32 system.
Okay, so we want to write code that reboots a machine. Where do we start? We start by messing with the “access token.”
I quote, “An access token contains the security information for a logon session. The system creates an access token when a user logs on, and every process executed on behalf of the user has a copy of the token. The token identifies the user, the user’s groups, and the user’s privileges. The system uses the token to control access to securable objects and to control the ability of the user to perform various system-related operations on the local computer.”
For more information about access control mechanisms, please refer to:
In short, the access token is an annoying piece of gooey stuff that sticks to all processes that you launch. It is this token that makes you see messages such as “you do not have permission to …..” So, you can start by “adjusting” your access token.
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) { printf("OpenProcessToken failed!"); return 0; }
With this call, you have in effect requested permission to enable or disable the privileges in an access token for the current process.
Why do you do this? Well, you guessed it. You need to do this so that you can now “tweak” the acces token. By default, the access token does not contain system shutdown privileges.
But, as with most “system” calls, you need to use some convoluted language to communicate with the API. To adjust access tokens, you need to use the TOKEN_PRIVILEGES structure and retrieve the LUID used on a specified system to locally represent the specified privilege name.
TOKEN_PRIVILEGES tkp; LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid);
Now, you have the privilege you want in the language that the system wants. Looks like a piece of cake You now need to set up your TOKEN_PRIVILEGES structure to tell the system that you want to enable the shutdown privilege based on the LUID you just retrieved.
tkp.PrivilegeCount = 1; // one privilege to set tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
Now that you have the LUID and speak the “system” language, your wishes will be respected. So, now you can use this power and do what you have been waiting to do all this time—tweak the access token. You will use AdjustTokenPrivileges for this.
The AdjustTokenPrivileges function enables or disables privileges in the specified access token. Enabling or disabling privileges in an access token requires TOKEN_ADJUST_PRIVILEGES access. You already verified this privilege by using OpenProcessToken.
AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0);
Weirdly enough, this method returns a BOOL. I say weird because the return value is just TRUE/FALSE, but if you had more than one PRIVILEGE that you tried to set, there could be more than two outcomes.
- All privileges were successfully set
- Some privileges could not be set
- The API failed altogether
Agreed, you are setting just one privilege here. But, you are also learning more about the Win32 API on the way. So, instead of relying on the return value, you use the old faithful “GetLastError.”
if(GetLastError() != ERROR_SUCCESS) { printf("AdjustTokenPrivileges failed"); return 0; }
You are almost there. You tweaked the access token and you are now in control. The actual method that you will use to reboot the machine is pretty straightforward. Here it is:
BOOL b = ExitWindowsEx( EWX_REBOOT|EWX_FORCE, SHTDN_REASON_MINOR_MAINTENANCE | SHTDN_REASON_FLAG_PLANNED);
The ExitWindowsEx function either logs off the current user, shuts down the system, or shuts down and restarts the system.
You Did It!! Wasn’t it cool?
Well, as always, you could check the help on each of these APIs and dig deeper into them. This article is meant just to initiate the beginner or the beginner-intermediate developer into a facet of the Win32 API that is not often used. Hopefully, the article served its purpose.