User Account Control (UAC) on Windows Vista changes the paradigm of being an administrator on a Microsoft Windows operating system. Rather than wielding full administrative privileges all of the time, the token is "split" and there are two of them. If you run an application normally, it is given the token that has fewer privileges (a "standard user" token, if you will, although the Administrators group is still present and set to "deny only" so securable objects that an administrator is explicitly forbidden from accessing will still be denied to this user). If you create a process elevated, you are prompted to approve the elevation, after which the process is provided with an "unfiltered" token that grants this application full administrator credentials.

This is a huge win for security. However, it does break some of the paradigms that you may be used to using when developing applications. One example is checking to see if the user is an administrator explicitly. Most of the tools that help identify more LUA bugs (and these tools are becoming pretty indispensible now that pretty much everybody is running as a standard user the majority of the time) will flag this as a potential LUA bug. You see, this is something that can be done for good (you are checking to see if the user is an administrator to determine whether or not you want to offer them the option of launching another process elevated to provide additional functionality), and it is something that can be done for evil (you are checking to see if the user is an administrator, because it is easier just to fail than to fix the LUA bug). For now, let's assume that you are using this power for good.

If you happen to be using the handy shell32 API IsUserAnAdmin, you will find that it will return true if the process is elevated, and false if it is not. Note that the Boolean return value doesn't provide you with any information that will help you determine if the user CAN elevate - it just tells you if you already have. What can you do if you want to know if the user CAN elevate, whether or not they already have?

The GetTokenInformation API provides a new ability to return a TokenElevationType structure. As of Windows Vista RC1, I do not see this documented in the Windows SDK, but you can find it in the Windows header files (winbase.h and winnt.h). So, I whipped together a little sample that you can run from the command line to determine not only whether the current process is elevated, but also whether the user happens to be a member of the administrators group:

 

#include <windows.h>
#include <stdio.h>

int main() {
  HANDLE hToken;
  TOKEN_ELEVATION_TYPE elevationType;
  DWORD dwSize;

  OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken);
  GetTokenInformation(hToken, TokenElevationType, &elevationType, sizeof(elevationType), &dwSize);

  switch (elevationType) {
    case TokenElevationTypeDefault:
      wprintf(TEXT("\nTokenElevationTypeDefault - User is not using a split token.\n"));
      break;
    case TokenElevationTypeFull:
      wprintf(TEXT("\nTokenElevationTypeFull - User has a split token, and the process is running elevated.\n"));
      break;
    case TokenElevationTypeLimited:
      wprintf(TEXT("\nTokenElevationTypeLimited - User has a split token, but the process is not running elevated.\n"));
      break;
  }

  if (hToken) {
    CloseHandle(hToken);
  }
}

 

As you can see, it's fairly straightforward. (I have elided error handling and return value checking for clarity.) If you are looking to use this information for good, I hope this helps. If you are looking to use this information for evil, I hope you don't find this post!

Update: Note that this technique detects if the token is split or not. In the vast majority of situations, this will determine whether the user is running as an administrator. However, there are other user types with advanced permissions which may generate a split token during an interactive login (for example, the Network Configuration Operators group). If you are using one of these advanced permission groups, this technique will determine the elevation type, and not the presence (or absence) of the administrator credentials.

Updated 03-March-2010

Apparently my previous update didn’t scare enough people away from this approach, so here goes: be very afraid of this approach. It will correctly tell you if you have a split token, but that doesn’t necessarily mean anything useful. For example, what happens if you disable UAC? You won’t have a split token. You’d get TokenElevationTypeDefault. What happens if you are logged in as the .\Administrators account? Same thing. Neither one means you’re a standard user, which is a common mistake by misapplying the above logic for the “typical” case. What about if you happen to have one, and only one, super privilege, and you elevated to get that into your token? Then you’d have TokenElevationTypeFull – which is frequently interpreted as meaning you’re an admin.

The *right* thing to do is not care. If you think you need admin rights, then manifest your binary, and ask for them. Does the current user’s capabilities matter? If they have a second admin account, then why does it matter if their current one is a standard user?

And you certainly don’t want to go looking for the Administrators ACE in the token in order to authorize something. Because, you know, it has a flag that says “Deny Only” on it. If you go granting access, then that’s directly violating the “Deny Only” intent. Kind of like saying, “oh, I see you’re on the no gambling list – come on into the casino…”

In other words, despite the fact that I wrote this (back in my youth), unless you know precisely what it is doing, please don’t use this. Because it probably doesn’t do what you think it does.