You are currently offline, waiting for your internet to reconnect

How To Modify Default DACL for Sharing Objects

This article was previously published under Q193073
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.
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 thedefault 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;   }				

Article ID: 193073 - Last Review: 11/21/2006 15:29:16 - Revision: 3.2

Microsoft Win32 Application Programming Interface

  • kbacl kbapi kbcode kbfaq kbhowto kbsecurity KB193073