Microsoft KB Archive/193073

From BetaArchive Wiki
Knowledge Base


Article ID: 193073

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



This article was previously published under Q193073


SUMMARY

The discretionary access control list (DACL) on a kernel object determines which users can access the object. This list contains a number of access control entries (ACEs) which either grant or deny a user or group access to the object. Rather than explicitly constructing a DACL for an object, it is a common practice to create the object by using the default DACL for the process. Typically, this will allow only the creator and the system to obtain access to the object.

To grant other users access to a kernel object (mutex, event, file mapping, and so forth) that is created under your security context, you can do either of the following:

  • Explicitly add an access-allowed ACE to the object's DACL. -or-


  • Modify the default DACL for the process before creating the object.


MORE INFORMATION

When creating an object, you can explicitly add an access-allowed ACE to the DACL so that it can be accessed by another user or group. An example of how to add an access-allowed ACE to a file object is given in the following Microsoft Knowledge Base article:

102102 How To Add an Access-Allowed ACE to a File


However, if you don't have control over the code that creates the object, and the object was created to use the default DACL for the process (by passing a NULL pointer for the security descriptor), other users may not be able to access the object.

For example, suppose a third-party DLL that you use in your service creates a mutex through the following call:

hMutex = CreateMutex(NULL, FALSE, "ThirdPartyDLLMutex");


If the service is installed under the local system account, the mutex will be created with the default DACL for the local system account. Now, suppose you attempt to share this mutex by using this DLL in a process that is running under a user account. Because the mutex was created by the service, the CreateMutex() call will fail with error code 5 (ERROR_ACCESS_DENIED) when running under the user account and the third-party DLL might not be able to continue. To work around this problem, you can modify the default DACL for the process prior to creating the mutex. An example of how to modify the default DACL for a process is given in the sample code at the end of this article.

If the DLL is implicitly linked with your service, this approach may not entirely solve the access problem because the DLL might make the CreateMutex() call before you have a chance to modify the default DACL for the process. In this case, you can do one of the following:

  • Dynamically load the DLL so that you can modify the default DACL before the object is created by the DLL. -or-


  • Create a stub service that spawns a process that contains all of the functionality of your original service. Note that the process must be spawned with the CREATE_SUSPENDED flag, which prohibits the process from running and thereby eliminates the chance that the object could be created before the default DACL is properly modified. The stub service would then modify the default DACL for the process before allowing it to resume execution.

Sample Code

The following sample code demonstrates how you can modify the default DACL for a process so that the EVERYONE group can access an object created with default security:

   // Somewhere in your service program.
   ...
   ...
   ...

   SECURITY_ATTRIBUTES sa;
   STARTUPINFO si;
   PROCESS_INFORMATION pi;

   ZeroMemory(&sa, sizeof(sa));
   sa.nLength = sizeof(sa);

   ZeroMemory(&si, sizeof(si));
   si.cb = sizeof(si);

   if (!CreateProcess(NULL, "MyProg.exe", &sa, &sa, TRUE, CREATE_SUSPENDED,
                      NULL, NULL, &si, &pi))
   {
     return GetLastError();
   }
   else
   {
     ModifyDefaultDacl(pi.hProcess);

     ResumeThread(pi.hThread);

     CloseHandle(pi.hThread);
     CloseHandle(pi.hProcess);
   }

   // Continue processing.
   ...
   ...
   ...


   /*++

     Function : ModifyDefaultDacl

     Synopsis : Add EVERYONE ACE to the process token DACL.

     Parameter: hProcess - Handle to process to modify the DACL.

     Return   : 0 if successful, otherwise error code.

   --*/ 


   DWORD ModifyDefaultDacl(HANDLE hProcess)
   {
      int                      i;
      ACL_SIZE_INFORMATION     asi;
      ACCESS_ALLOWED_ACE       *pace;
      DWORD                    dwNewAclSize;
      DWORD                    dwSize            = 0;
      DWORD                    dwTokenInfoLength = 0;
      DWORD                    dwResult          = 0;
      HANDLE                   hToken            = NULL;
      PACL                     pacl              = NULL;
      PSID                     psidEveryone      = NULL;
      SID_IDENTIFIER_AUTHORITY siaWorld = SECURITY_WORLD_SID_AUTHORITY;
      TOKEN_DEFAULT_DACL       tddNew;
      TOKEN_DEFAULT_DACL       *ptdd    = NULL;
      TOKEN_INFORMATION_CLASS  tic      = TokenDefaultDacl;

      __try
      {
         // 
         // Obtain an access token.
         // 
         if (!OpenProcessToken(hProcess, TOKEN_QUERY |
                               TOKEN_ADJUST_DEFAULT, &hToken))
         {
            dwResult = GetLastError();
            __leave;
         }

         // 
         // Obtain buffer size for DACL information.
         // 
         if (!GetTokenInformation(hToken, tic, (LPVOID)NULL,
                                  dwTokenInfoLength, &dwSize))
         {
            if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
            {
               ptdd = (TOKEN_DEFAULT_DACL *) LocalAlloc(LPTR, dwSize);
               if (ptdd == NULL)
               {
                  dwResult = GetLastError();
                  __leave;
               }

               if (!GetTokenInformation(hToken, tic, (LPVOID)ptdd, dwSize,
                                        &dwSize))
               {
                  dwResult = GetLastError();
                  __leave;
               }
            }
            else
            {
               dwResult = GetLastError();
               __leave;
            }
         }

         // 
         // Obtain ACL information.
         // 
         if (!GetAclInformation(ptdd->DefaultDacl, (LPVOID)&asi,
                                (DWORD)sizeof(ACL_SIZE_INFORMATION),
                                AclSizeInformation))
         {
            dwResult = GetLastError();
            __leave;
         }

         // 
         // Create SID for the Everyone group.
         // 
         if (!AllocateAndInitializeSid(&siaWorld, 1, SECURITY_WORLD_RID, 0,
                                       0, 0, 0, 0, 0, 0, &psidEveryone))
         {
            dwResult = GetLastError();
            __leave;
         }

         // 
         // Compute the size of the new ACL.
         // 
         dwNewAclSize = asi.AclBytesInUse + sizeof(ACCESS_ALLOWED_ACE) +
                        GetLengthSid(psidEveryone) - sizeof(DWORD);

         // 
         // Allocate buffer for the new ACL.
         // 
         pacl = (PACL) LocalAlloc(LPTR, dwNewAclSize);
         if (pacl == NULL)
         {
            dwResult = GetLastError();
            __leave;
         }

         // 
         // Intialize the ACL.
         // 
         if (!InitializeAcl(pacl, dwNewAclSize, ACL_REVISION))
         {
            dwResult = GetLastError();
            __leave;
         }

         // 
         // Loop through all the ACEs.
         // 
         for (i = 0; i < (int) asi.AceCount; i++)
         {
            // 
            // Get current ACE.
            // 
            if (!GetAce(ptdd->DefaultDacl, i, (LPVOID *)&pace))
            {
               dwResult = GetLastError();
               __leave;
            }

            // 
            // Build the new ACL.
            // 
            if (!AddAce(pacl, ACL_REVISION, MAXDWORD, pace,
                        ((PACE_HEADER)pace)->AceSize))
            {
               dwResult = GetLastError();
               __leave;
            }
         }

         // 
         // Add the new ACE.
         // 
         if (!AddAccessAllowedAce(pacl, ACL_REVISION, GENERIC_ALL,
                                  psidEveryone))
         {
            dwResult = GetLastError();
            __leave;
         }

         // 
         // Set the new Default DACL.
         // 
         tddNew.DefaultDacl = pacl;

         if (!SetTokenInformation(hToken, tic, (LPVOID)&tddNew,
                                  dwNewAclSize))
         {
            dwResult = GetLastError();
            __leave;
         }
      }

      __finally
      {
         // 
         // Free the buffer for the sid.
         // 
         if (psidEveryone)
         {
            FreeSid(psidEveryone);
         }

         // 
         // Free the buffers.
         // 
         if (pacl)
         {
            LocalFree((HLOCAL)pacl);
         }

         if (ptdd)
         {
            LocalFree((HLOCAL)ptdd);
         }

         // 
         // Close the access token.
         // 
         if (hToken)
         {
            CloseHandle(hToken);
         }
      }

      return dwResult;
   }
                

Keywords: kbacl kbapi kbcode kbfaq kbhowto kbsecurity KB193073