Microsoft KB Archive/106387

From BetaArchive Wiki
< Microsoft KB Archive
Revision as of 12:25, 21 July 2020 by X010 (talk | contribs) (Text replacement - "&" to "&")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Knowledge Base


Article ID: 106387

Article Last Modified on 11/21/2006



APPLIES TO

  • Microsoft Win32 Application Programming Interface, when used with:
    • Microsoft Windows NT 4.0
    • Microsoft Windows 2000 Standard Edition
    • Microsoft Windows XP Professional



This article was previously published under Q106387

SUMMARY

This article demonstrates how to construct a security descriptor that grants a given group access to a kernel object so that the object can be shared between processes that are running under different user accounts.

MORE INFORMATION

Sometimes it is necessary for a service to create a kernel object that can be accessed by a process running under a different user account. To allow an object to be shared in this manner, the service must create the object by using a security descriptor that explicitly grants the user access to the object. Alternatively, the security descriptor can grant access to an entire group of users.

The sample code in this article is very specific in that it grants the authenticated users group access to a mutex. This code makes use of numerous security APIs to construct the security descriptor for the mutex. For complete documentation on these security functions, see "Access Control" section of the Platform SDK Documentation in the MSDN Library:

You must have a full understanding of these calls (and the Access Control technology, in general) in order to adapt the code for other users, groups, and kernel objects.

Sample Code

The following sample code demonstrates how to construct a security descriptor that grants the authenticated users group GENERIC_READ, GENERIC_WRITE, and GENERIC_EXECUTE access. The newly constructed security descriptor is then applied to a mutex.

For demonstration purposes, this sample code uses generic access rights. These generic rights take advantage of generic mappings that can be used for all kernel objects. In a real-world application, it is preferable to use object-specific access rights when creating an object.

It is possible that a given resource manager may interpret a given set of generic rights to include other standard access rights when mapping to object-specific access rights. For example, specifying GENERIC_READ, GENERIC_WRITE, and GENERIC_EXECUTE rights for a mutex is the same as specifying the object-specific rights MUTEX_MODIFY_STATE and SYNCHRONIZE. As a result, another thread can only obtain a handle to the mutex by specifying MUTEX_MODIFY_STATE and/or SYNCHRONIZE for the dwDesiredAccess parameter in OpenMutex(). An attempt to open the mutex with MUTEX_ALL_ACCESS will fail with error code 5 (ERROR_ACCESS_DENIED).

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

// The following function initializes the supplied security descriptor
// with a DACL that grants the Authenticated Users group GENERIC_READ,
// GENERIC_WRITE, and GENERIC_EXECUTE access.
// 
// The function returns NULL if any of the access control APIs fail.
// Otherwise, it returns a PVOID pointer that should be freed by calling
// FreeRestrictedSD() after the security descriptor has been used to
// create the object.

PVOID BuildRestrictedSD(PSECURITY_DESCRIPTOR pSD) {

   DWORD  dwAclLength;

   PSID   pAuthenticatedUsersSID = NULL;

   PACL   pDACL   = NULL;
   BOOL   bResult = FALSE;

   PACCESS_ALLOWED_ACE pACE = NULL;

   SID_IDENTIFIER_AUTHORITY siaNT = SECURITY_NT_AUTHORITY;
   
   SECURITY_INFORMATION si = DACL_SECURITY_INFORMATION;
   
   __try {

      // initialize the security descriptor
      if (!InitializeSecurityDescriptor(pSD, 
            SECURITY_DESCRIPTOR_REVISION)) {
         printf("InitializeSecurityDescriptor() failed with error %d\n",
               GetLastError());
         __leave;
      }

      // obtain a sid for the Authenticated Users Group
      if (!AllocateAndInitializeSid(&siaNT, 1, 
            SECURITY_AUTHENTICATED_USER_RID, 0, 0, 0, 0, 0, 0, 0, 
            &pAuthenticatedUsersSID)) {
         printf("AllocateAndInitializeSid() failed with error %d\n",
               GetLastError());
         __leave;
      }

      // NOTE:
      // 
      // The Authenticated Users group includes all user accounts that
      // have been successfully authenticated by the system. If access
      // must be restricted to a specific user or group other than 
      // Authenticated Users, the SID can be constructed using the
      // LookupAccountSid() API based on a user or group name.

      // calculate the DACL length
      dwAclLength = sizeof(ACL)
            // add space for Authenticated Users group ACE
            + sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)
            + GetLengthSid(pAuthenticatedUsersSID);

      // allocate memory for the DACL
      pDACL = (PACL) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 
            dwAclLength);
      if (!pDACL) {
         printf("HeapAlloc() failed with error %d\n", GetLastError());
         __leave;
      }

      // initialize the DACL
      if (!InitializeAcl(pDACL, dwAclLength, ACL_REVISION)) {
         printf("InitializeAcl() failed with error %d\n", 
               GetLastError());
         __leave;
      }
      
      // add the Authenticated Users group ACE to the DACL with
      // GENERIC_READ, GENERIC_WRITE, and GENERIC_EXECUTE access
      if (!AddAccessAllowedAce(pDACL, ACL_REVISION,
            GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE,
            pAuthenticatedUsersSID)) {
         printf("AddAccessAllowedAce() failed with error %d\n",
               GetLastError());
         __leave;
      }

      // set the DACL in the security descriptor
      if (!SetSecurityDescriptorDacl(pSD, TRUE, pDACL, FALSE)) {
         printf("SetSecurityDescriptorDacl() failed with error %d\n",
               GetLastError());
         __leave;
      }

      bResult = TRUE;
     
   } __finally {

      if (pAuthenticatedUsersSID) FreeSid(pAuthenticatedUsersSID);
   }

   if (bResult == FALSE) {
      if (pDACL) HeapFree(GetProcessHeap(), 0, pDACL);
      pDACL = NULL;
   }

   return (PVOID) pDACL;
}

// The following function frees memory allocated in the
// BuildRestrictedSD() function
VOID FreeRestrictedSD(PVOID ptr) {

   if (ptr) HeapFree(GetProcessHeap(), 0, ptr);

   return;
}

void main(void)
{
   SECURITY_ATTRIBUTES sa;
   SECURITY_DESCRIPTOR sd;

   PVOID  ptr;
   HANDLE hMutex;

   // build a restricted security descriptor
   ptr = BuildRestrictedSD(&sd);
   if (!ptr) {
      printf("BuildRestrictedSD() failed\n");
      return;
   }

   // create a mutex using the security descriptor
   sa.nLength = sizeof(sa);
   sa.lpSecurityDescriptor = &sd;
   sa.bInheritHandle = FALSE;

   hMutex = CreateMutex(&sa, FALSE, "RestrictedMutex");
   if (!hMutex)
      printf("CreateMutex() failed with error %d\n", GetLastError());

   // free the memory allocated by BuildRestrictedSD
   FreeRestrictedSD(ptr);

   // use the mutex ...

   printf("Press the return key to close the mutex handle...\n");
   getchar();

   // close the mutex handle
   CloseHandle(hMutex);
}
                

Keywords: kbacl kbapi kbhowto kbkernbase kbsecurity kbservice KB106387