HOWTO: Modify Default DACL for Sharing Objects

ID: Q193073

The information in this article applies to:

SUMMARY

To share objects (mutex, event, and so forth) that you create under another security context, you can do one of the following:

MORE INFORMATION

If you have access to the source code, the easiest method is to place a NULL DACL in the security descriptor when the object is created. For additional information about how to use a NULL DACL, please see the following article in the Microsoft Knowledge Base:

   ARTICLE-ID: Q106387
   TITLE     : HOWTO: Share Objects with a Service

Alternatively, you can add an access-allowed ACE to the object so that it can be appropriately shared. For additional information about how to add an access-allowed ACE to a file object, please see the following article in the Microsoft Knowledge Base:

   ARTICLE-ID: Q102102
   TITLE     : HOWTO: Add an Access-Allowed ACE to a File

However, if you don't have access to the source code, and the object was created to use the default DACL (that is, passing a NULL pointer for the security descriptor parameter), you may not be able to access the object. For example, you have a third-party DLL that you use in your service program and this DLL makes the following API call:

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

If the service is installed under the Local System account, the mutex should be successfully created with the default DACL of the Local System account when the service starts.

Now, suppose you also use this DLL in one of your interactive process. In this scenario, the CreateMutex() call listed above will fail with error code 5 (ERROR_ACCESS_DENIED) and the third-party DLL might or might not be able to continue. The problem is that the first parameter has been hard coded as NULL, which means that the mutex will be created with the Default DACL. The default DACL only allows access to Local System account and the Owner.

To work around this problem, you can modify the default DACL to grant access to the desired individuals or groups so that the default DACL already contains the desired access permissions when you use it to create any object.

If the DLL is implicitly linked to your service program, this work around will not entirely solve the DLL problem mentioned above because the DLL might make the CreateMutex() call before you have a chance to modify the default DACL. In this case, you can do one of the following:

Following is a function and sample code that calls the function to demonstrate how you can modify the default DACL so that the EVERYONE group can access an object created with the default DACL.

Sample Code

   // 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;
   }

REFERENCES

For additional information, please see the following article in the Microsoft Knowledge Base:

   ARTICLE-ID: Q106387
   TITLE     : HOWTO: Share Objects with a Service

   ARTICLE-ID: Q102102
   TITLE     : HOWTO: Add an Access-Allowed ACE to a File

Additional query words:
Keywords          : kbAccCtrl kbAPI kbSDKPlatform kbSDKWin32 kbSecurity kbCodeSam kbfaq
Issue type        : kbhowto

Last Reviewed: September 27, 1998