The App Compat Guy

Chris Jackson's Semantic Consonance

How to Determine if a User is a Member of the Administrators Group with UAC Enabled on Windows Vista

How to Determine if a User is a Member of the Administrators Group with UAC Enabled on Windows Vista

  • Comments 36

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.

  • Nice... I have to ask though, what is the scenario where you need to distinguish between an admin user that can elevate and a non-admin user that cannot?

    At the end of the day, you need to know if the process is not elevated right now, so you can show shields where appropriate and take elevation actions behind those shield presses (i.e. even if they can't elevate, the elevation action will result in the UAC dialog that by default requires entering the admin username and pwd). So I don't see the scenario where I need to distinguish... but I am sure you'll enlighten me :) Cheers.

  • Daniel, if I understand the sample (and your question) right, nTokenElevationTypeLimited and nTokenElevationTypeFull define administrators that can elevate (or are elevated). A return value of TokenElevationTypeDefault should result in the UAC dialog to enter administrator credentials.

  • Some developers have expressed an interest in being able to offer an application update only if the user is able to obtain admin privileges. In a standard user enterprise, where the nearest administrator may be several floors or buildings away, prompting for elevation to install an application update isn't that helpful.

    It also may be useful when doing lower level work. For example, when you manifest an application for highestAvailable, internally we have to do a similar check. If you can become an admin, then we launch prompting for credentials. If you can't, then we just launch as standard user.

    Yes, there are a host of scenarios where using this knowledge can be harmful, but there are still some where it is useful.

  • Is there a nice managed code .NET API to to this very same thing?

  • There is not a managed code API to achieve this - this function is new in Windows Vista, so no wrapper from the 2.0 framework (which was released a while ago) is going to be aware of this API. So, the answer is to use p/invoke to access these functions.

  • Once a process knows that it CAN be elevated how does it really elevate itself and perform an Admin task. Can we expect a code-snippet/APIs for the same.

    Lets say the process whats to spawn/launch a child with an elevated token.

    Thanks,

    Shashi.

  • You never elevate a process in place. What you would need to do is ShellExecute another process that is manifested as requireAdministrator, and package all of your administrator functionality into this exe.

  • I was tring to modify the hToken in your code by using AdjustTokenGroups() and enable the Admin Group such that the token can be used in a CreateProcessAsUser() and this created process be launched elevated.

    Is this the right approach.

    Thanks,

    Shashi

  • No need to muck around adjusting token groups manually. In fact, this won't get you a full admin token. We do more than just set the deny-only flag on the Administrator ACE. We also set the IL to medium instead of high, and we strip out a number of privileges.

    If you are launching a particular admin process, just manifest that process to requireAdministrator. If you want to launch a particular exe elevated just that time, then call ShellExecuteEx and specify the verb as "runas."

  • I have a question about a similar issue.  Is there a way to programmatically check if UAC is enabled/disabled?  As a short term fix for an upcoming product release, I have been asked to check for UAC when running on Vista and to MessageBox() the user and exit the application if UAC is enabled.  There doesn't seem to be any documented method of checking and I thought maybe you could help.

    Thanks in advance,

    Dylan Bourque

    dbourque-at-lewis-dot-com

    Lewis Computer Services, Inc.

  • Does your application not work if UAC is enabled at all, or does it just not work if the user is not an administrator? TokenElevationTypeDefault && IsUserAnAdmin == True indicates that UAC is turned off, but I would think you'd be doing your users a disservice by requiring that they disable an important security feature of the OS to run your software. Would a check for IsUserAnAdmin be sufficient to overcome any issues at the moment? Or could you just manifest the exe to requireAdministrator until you eradicate all of the LUA Bugs? (Standard User Analyzer from ACT 5.0 can help with this.) I'd love to understand more about your scenario here.

  • Thanks for the reply.  This is intended (according to or PM) to be a short term band-aid.  We have a fair number of LUA issues that we won't have time to address before our next release, which will be in March.  Also, the application in question is slated for a major overhaul as part of our next release, so there isn't really any incentive to put a lot of effort into the current codebase.

    We have several new client installs lined up in the next several months, all of which will more than likely be buying new laptops with Vista pre-installed.  For the short term, instead of updating the application to work correctly under UAC, our PM decided to require that they disable UAC if they are running under Vista.

    I have been lobbying here to either ask the new clients to buy XP laptops and wait on Vista until our next release or to manifest the exe, but I'm too low on the totem pole to force the issue.

    Thanks again for you help,

    Dylan Bourque

    dbourque-at-lewis-dot-com

    Lewis Computer Services, Inc.

  • (Followed up offline.)

  • Programmatically determine if UAC is enabled

  • The moth says, This is a question I get often: "How can I determine if User Account Control is on or

Page 1 of 3 (36 items) 123