Microsoft KB Archive/118626

{|
 * width="100%"|

HOWTO: Determine Whether a Thread Is Running in User Context of Local Administrator Account

 * }

Q118626

-

The information in this article applies to:


 * Microsoft Win32 Application Programming Interface (API), used with:
 * Microsoft Windows NT Server versions 3.51, 4.0
 * Microsoft Windows NT Workstation versions 3.51, 4.0
 * the operating system: Microsoft Windows 2000

-

SUMMARY
To determine whether a thread is running under a local administrator account, you need to examine the access token that is associated with the thread. This article describes how to do this.

MORE INFORMATION
By default, the token that is associated with a thread is that of its containing process. This "user context" is superceded by any token that is attached directly to the thread. Therefore, to determine a thread's user context, you should first attempt to obtain a token for the thread with the OpenThreadToken function. If this method fails and the GetLastError function reports ERROR_NO_TOKEN, then you can obtain the token for the process with the OpenProcessToken function.

Once you have obtained the token of the current user, you can use the AccessCheck function to detect whether the user is an administrator. To do this, first create a security identifier (SID) for the local administrator group by using the AllocateAndInitializeSid function. Then, construct a new security descriptor (SD) with a Discretionary Access Control List (DACL) that contains an Access Control Entry (ACE) for the administrator group's SID. AccessCheck can then be called with the token of the current user and the newly constructed SD to detect whether the user is an administrator.

The following sample code uses the functions mentioned previously to test whether the current thread is running as a user who is an administrator on the local computer.

Sample code
#include 
 * 1) include 

// // Make up some private access rights. //
 * 1) define ACCESS_READ 1
 * 2) define ACCESS_WRITE 2

//********************************************************************** // // FUNCTION: IsAdmin - This function checks the token of the //           calling thread to see if the caller belongs to //            the Administrators group. // // PARAMETERS:  none // // RETURN VALUE: TRUE if the caller is an administrator on the local //           machine. Otherwise, FALSE. // //********************************************************************** BOOL IsAdmin(void) {

HANDLE hToken; DWORD dwStatus; DWORD dwAccessMask; DWORD dwAccessDesired; DWORD dwACLSize; DWORD dwStructureSize = sizeof(PRIVILEGE_SET); PACL  pACL            = NULL; PSID  psidAdmin       = NULL; BOOL  bReturn         = FALSE;

PRIVILEGE_SET  ps; GENERIC_MAPPING GenericMapping;

PSECURITY_DESCRIPTOR    psdAdmin           = NULL; SID_IDENTIFIER_AUTHORITY SystemSidAuthority = SECURITY_NT_AUTHORITY; __try {

// AccessCheck requires an impersonation token. ImpersonateSelf(SecurityImpersonation);

if (!OpenThreadToken(GetCurrentThread, TOKEN_QUERY, FALSE, &hToken)) {

if (GetLastError != ERROR_NO_TOKEN) __leave;

// If the thread does not have an access token, we'll         // examine the access token associated with the process. if (!OpenProcessToken(GetCurrentProcess, TOKEN_QUERY, &hToken)) __leave; }

if (!AllocateAndInitializeSid(&SystemSidAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &psidAdmin)) __leave;

psdAdmin = LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH); if (psdAdmin == NULL) __leave;

if (!InitializeSecurityDescriptor(psdAdmin, SECURITY_DESCRIPTOR_REVISION)) __leave; // Compute size needed for the ACL. dwACLSize = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(psidAdmin) - sizeof(DWORD);

// Allocate memory for ACL. pACL = (PACL)LocalAlloc(LPTR, dwACLSize); if (pACL == NULL) __leave;

// Initialize the new ACL. if (!InitializeAcl(pACL, dwACLSize, ACL_REVISION2)) __leave;

dwAccessMask= ACCESS_READ | ACCESS_WRITE; // Add the access-allowed ACE to the DACL. if (!AddAccessAllowedAce(pACL, ACL_REVISION2, dwAccessMask, psidAdmin)) __leave;

// Set our DACL to the SD. if (!SetSecurityDescriptorDacl(psdAdmin, TRUE, pACL, FALSE)) __leave;

// AccessCheck is sensitive about what is in the SD; set // the group and owner. SetSecurityDescriptorGroup(psdAdmin, psidAdmin, FALSE); SetSecurityDescriptorOwner(psdAdmin, psidAdmin, FALSE);

if (!IsValidSecurityDescriptor(psdAdmin)) __leave;

dwAccessDesired = ACCESS_READ;

//      // Initialize GenericMapping structure even though we      // won't be using generic rights. //      GenericMapping.GenericRead    = ACCESS_READ; GenericMapping.GenericWrite  = ACCESS_WRITE; GenericMapping.GenericExecute = 0; GenericMapping.GenericAll    = ACCESS_READ | ACCESS_WRITE;

if (!AccessCheck(psdAdmin, hToken, dwAccessDesired, &GenericMapping, &ps, &dwStructureSize, &dwStatus, &bReturn)) { printf("AccessCheck failed with error %lu\n", GetLastError); __leave; }

RevertToSelf; } __finally {

// Cleanup if (pACL) LocalFree(pACL); if (psdAdmin) LocalFree(psdAdmin); if (psidAdmin) FreeSid(psidAdmin); }

return bReturn; }

void main {

if (IsAdmin) printf("You are an administrator\n"); else printf("You are not an administrator\n"); } Additional query words:

Keywords : kbAPI kbKernBase kbSecurity kbDSupport kbGrpDSKernBase

Issue type : kbhowto

Technology : kbAudDeveloper kbWin32sSearch kbWin32API