I am merging the changes made by Cody Cutrer into Wix 3.0.4610, and I noticed that the code for SchedSecureObjects has been cleaned up considerably.

I have a couple of comments / questions:

* Shouldn't there be a check on the return value of GetTargetPath on line 383?

* Do you see any problems with only storing rollback information once per table / path pair?

In Cody's code, the rollback information is only stored once per object (table and path); I have altered the code in SchedSecureObjectsRollback to reflect this behavior.

Attached is a unified diff of the changes to secureobj.cpp. It includes a check of the HRESULT from GetTargetPath.

Thanks,

--
Thomas S. Trias
Senior Developer
Artizan Internet Services
http://www.artizan.com/

--- src\ca\wixca\dll\secureobj.cpp      2008-10-21 10:50:42.000000000 -0700
+++ src\ca\wixca\dll\secureobj.cpp      2008-10-22 09:16:06.000000000 -0700
@@ -17,15 +17,16 @@
 
//-------------------------------------------------------------------------------------------------
 
 #include "precomp.h"
 
 // structs
 LPCWSTR wzQUERY_SECUREOBJECTS = L"SELECT `SecureObjects`.`SecureObject`, 
`SecureObjects`.`Table`, `SecureObjects`.`Domain`, `SecureObjects`.`User`, "
-                                L"`SecureObjects`.`Permission`, 
`SecureObjects`.`Component_`, `Component`.`Attributes` FROM 
`SecureObjects`,`Component` WHERE "
-                                
L"`SecureObjects`.`Component_`=`Component`.`Component`";
-enum eQUERY_SECUREOBJECTS { QSO_SECUREOBJECT = 1, QSO_TABLE, QSO_DOMAIN, 
QSO_USER, QSO_PERMISSION, QSO_COMPONENT, QSO_COMPATTRIBUTES };
+                                L"`SecureObjects`.`Permission`, 
`SecureObjects`.`Component_`, `SecureObjects`.`Type`, `SecureObjects`.`Flags`, 
`Component`.`Attributes` "
+                                L"FROM `SecureObjects`,`Component` WHERE 
`SecureObjects`.`Component_`=`Component`.`Component` "
+                                L"ORDER BY `SecureObjects`.`Table`, 
`SecureObjects`.`SecureObject`, `SecureObjects`.`Type`";
+enum eQUERY_SECUREOBJECTS { QSO_SECUREOBJECT = 1, QSO_TABLE, QSO_DOMAIN, 
QSO_USER, QSO_PERMISSION, QSO_COMPONENT, QSO_TYPE, QSO_FLAGS, 
QSO_COMPATTRIBUTES };
 
 LPCWSTR wzQUERY_REGISTRY = L"SELECT `Registry`.`Registry`, `Registry`.`Root`, 
`Registry`.`Key` FROM `Registry` WHERE `Registry`.`Registry`=?";
 enum eQUERY_OBJECTCOMPONENT { QSOC_REGISTRY = 1, QSOC_REGROOT, QSOC_REGKEY};
 
 enum eOBJECTTYPE { OT_UNKNOWN, OT_SERVICE, OT_FOLDER, OT_FILE, OT_REGISTRY };
 
@@ -104,13 +105,13 @@
     Assert(pwzObject && pwzTable);
 
     SE_OBJECT_TYPE objectType = SEObjectTypeFromString(const_cast<LPCWSTR> 
(pwzTable));
 
     if (SE_UNKNOWN_OBJECT_TYPE != objectType)
     {
-        er = ::GetNamedSecurityInfoW(pwzObject, objectType, 
DACL_SECURITY_INFORMATION, NULL, NULL, NULL, NULL, &psd);
+        er = ::GetNamedSecurityInfoW(pwzObject, objectType, 
DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION, NULL, NULL, NULL, NULL, 
&psd);
         if (ERROR_FILE_NOT_FOUND == er || ERROR_PATH_NOT_FOUND == er || 
ERROR_SERVICE_DOES_NOT_EXIST == HRESULT_CODE(er))
         {
             // If the file, path or service doesn't exist yet, skip rollback 
without a message
             hr = HRESULT_FROM_WIN32(er);
             ExitFunction();
         }
@@ -121,13 +122,13 @@
         if(!::GetSecurityDescriptorControl(psd, &sdc, &dwRevision))
         {
             ExitOnLastError1(hr, "Unable to schedule rollback for object 
(failed to get security descriptor control): %S", pwzObject);
         }
 
         // Convert the security information to a string, and write this to the 
custom action data
-        if 
(!::ConvertSecurityDescriptorToStringSecurityDescriptorW(psd,SDDL_REVISION_1,DACL_SECURITY_INFORMATION,&pwzSecurityInfo,NULL))
+        if 
(!::ConvertSecurityDescriptorToStringSecurityDescriptorW(psd,SDDL_REVISION_1,DACL_SECURITY_INFORMATION
 | SACL_SECURITY_INFORMATION,&pwzSecurityInfo,NULL))
         {
             hr = E_UNEXPECTED;
             ExitOnFailure1(hr, "Unable to schedule rollback for object (failed 
to convert security descriptor to a valid security descriptor string): %S", 
pwzObject);
         }
 
         hr = WcaWriteStringToCaData(pwzObject, &pwzCustomActionData);
@@ -138,12 +139,24 @@
 
         hr = WcaWriteStringToCaData(pwzSecurityInfo,&pwzCustomActionData);
         ExitOnFailure(hr, "failed to add data to rollback CustomActionData");
 
         // Write a 1 if DACL is protected, 0 otherwise
         if (sdc & SE_DACL_PROTECTED)
+        {
+            hr = WcaWriteIntegerToCaData(1,&pwzCustomActionData);
+            ExitOnFailure(hr, "failed to add data to 
rollbackCustomActionData");
+        }
+        else
+        {
+            hr = WcaWriteIntegerToCaData(0,&pwzCustomActionData);
+            ExitOnFailure(hr, "failed to add data to rollback 
CustomActionData");
+        }
+
+        // Write a 1 if SACL is protected, 0 otherwise
+        if (sdc & SE_SACL_PROTECTED)
         {
             hr = WcaWriteIntegerToCaData(1,&pwzCustomActionData);
             ExitOnFailure(hr, "failed to add data to 
rollbackCustomActionData");
         }
         else
         {
@@ -377,13 +390,14 @@
 #endif
 
         // Get the object to secure
         hr = WcaGetRecordString(hRec, QSO_SECUREOBJECT, &pwzSecureObject);
         ExitOnFailure(hr, "failed to get name of object");
 
-        GetTargetPath(eType, pwzSecureObject, &pwzTargetPath);
+        hr = GetTargetPath(eType, pwzSecureObject, &pwzTargetPath);
+        ExitOnFailure(hr, "failed to get Target path for secure object");
 
         hr = WcaGetRecordString(hRec, QSO_COMPONENT, &pwzData);
         ExitOnFailure(hr, "failed to get Component name for secure object");
 
         //
         // if we are installing this Component
@@ -412,12 +426,22 @@
             ExitOnFailure(hr, "failed to get user to configure object");
             hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData);
             ExitOnFailure(hr, "failed to add data to CustomActionData");
 
             hr = WcaGetRecordString(hRec, QSO_PERMISSION, &pwzData);
             ExitOnFailure(hr, "failed to get permission to configure object");
+            hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData);
+            ExitOnFailure(hr, "failed to add data to CustomActionData");
+
+            hr = WcaGetRecordString(hRec, QSO_TYPE, &pwzData);
+            ExitOnFailure(hr, "failed to get ACE type to configure object");
+            hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData);
+            ExitOnFailure(hr, "failed to add data to CustomActionData");
+
+            hr = WcaGetRecordString(hRec, QSO_FLAGS, &pwzData);
+            ExitOnFailure(hr, "failed to get flags to configure object");
             hr = WcaWriteStringToCaData(pwzData, &pwzCustomActionData);
             ExitOnFailure(hr, "failed to add data to CustomActionData");
 
             cObjects++;
         }
     }
@@ -470,12 +494,15 @@
     UINT er = ERROR_SUCCESS;
 
     LPWSTR pwzSecureObject = NULL;
     LPWSTR pwzTable = NULL;
     LPWSTR pwzTargetPath = NULL;
 
+    LPWSTR pwzPreviousTable = NULL;
+    LPWSTR pwzPreviousTargetPath = NULL;
+
     PMSIHANDLE hView = NULL;
     PMSIHANDLE hRec = NULL;
 
     LPWSTR pwzCustomActionData = NULL;
 
     eOBJECTTYPE eType = OT_UNKNOWN;
@@ -526,25 +553,39 @@
         hr = WcaGetRecordString(hRec, QSO_SECUREOBJECT, &pwzSecureObject);
         ExitOnFailure(hr, "failed to get name of object");
 
         hr = GetTargetPath(eType, pwzSecureObject, &pwzTargetPath);
         ExitOnFailure1(hr, "failed to get target path of object '%S' in order 
to schedule rollback - ignoring", pwzSecureObject);
 
-        StoreACLRollbackInfo(pwzTargetPath, pwzTable);
+        // Only store rollback information once for each object
+        if (NULL == pwzPreviousTargetPath ||
+            0 != lstrcmpW(pwzTargetPath, pwzPreviousTargetPath) ||
+            0 != lstrcmpW(pwzTable, pwzPreviousTable)) {
+            StoreACLRollbackInfo(pwzTargetPath, pwzTable);
+            ReleaseStr(pwzPreviousTargetPath);
+            ReleaseStr(pwzPreviousTable);
+            pwzPreviousTargetPath = pwzTargetPath;
+            pwzPreviousTable = pwzTable;
+            pwzTargetPath = NULL;
+            pwzTable = NULL;
+        }
     }
 
     // if we looped through all records all is well
     if (E_NOMOREITEMS == hr)
         hr = S_OK;
     ExitOnFailure(hr, "failed while looping through all objects to schedule 
rollback for");
 
 LExit:
     ReleaseStr(pwzCustomActionData);
     ReleaseStr(pwzSecureObject);
     ReleaseStr(pwzTable);
     ReleaseStr(pwzTargetPath);
+
+    ReleaseStr(pwzPreviousTable);
+    ReleaseStr(pwzPreviousTargetPath);
 
     if (FAILED(hr))
         er = ERROR_INSTALL_FAILURE;
     return WcaFinalize(er);
 }
 
@@ -563,27 +604,36 @@
     HRESULT hr = S_OK;
     DWORD er = ERROR_SUCCESS;
 
     LPWSTR pwz = NULL;
     LPWSTR pwzData = NULL;
     LPWSTR pwzObject = NULL;
+    LPWSTR pwzPreviousObject = NULL;
     LPWSTR pwzTable = NULL;
+    LPWSTR pwzPreviousTable = NULL;
     LPWSTR pwzDomain = NULL;
     DWORD dwRevision = 0;
     LPWSTR pwzUser = NULL;
     DWORD dwPermissions = 0;
+    DWORD dwFlags = 0;
+    DWORD dwType = 0;
     LPWSTR pwzAccount = NULL;
     PSID psid = NULL;
 
     EXPLICIT_ACCESSW ea = {0};
     SE_OBJECT_TYPE objectType = SE_UNKNOWN_OBJECT_TYPE;
     PSECURITY_DESCRIPTOR psd = NULL;
     SECURITY_DESCRIPTOR_CONTROL sdc = {0};
     SECURITY_INFORMATION si = {0};
-    PACL pAclExisting = NULL;   // doesn't get freed
-    PACL pAclNew = NULL;
+    PACL pDaclExisting = NULL;   // doesn't get freed
+    PACL pDaclNew = NULL;
+    PACL pSaclExisting = NULL;   // doesn't get freed
+    PACL pSaclNew = NULL;
+    PACL pAclExisting = NULL;    // doesn't get freed
+    PACL *pAclNew = NULL;         // doesn't get freed
+    PACL pAclTemp = NULL;        // doesn't get freed
 
     PMSIHANDLE hActionRec = ::MsiCreateRecord(1);
 
     //
     // initialize
     //
@@ -609,19 +659,93 @@
         ExitOnFailure(hr, "failed to process CustomActionData");
         hr = WcaReadStringFromCaData(&pwz, &pwzDomain);
         ExitOnFailure(hr, "failed to process CustomActionData");
         hr = WcaReadStringFromCaData(&pwz, &pwzUser);
         ExitOnFailure(hr, "failed to process CustomActionData");
         hr = WcaReadIntegerFromCaData(&pwz, 
reinterpret_cast<int*>(&dwPermissions));
-        ExitOnFailure(hr, "failed to processCustomActionData");
+        ExitOnFailure(hr, "failed to process CustomActionData");
+        hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int*>(&dwType));
+        ExitOnFailure(hr, "failed to process CustomActionData");
+        hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int*>(&dwFlags));
+        ExitOnFailure(hr, "failed to process CustomActionData");
 
         WcaLog(LOGMSG_VERBOSE, "Securing Object: %S Type: %S User: %S", 
pwzObject, pwzTable, pwzUser);
 
+        if (NULL == pwzPreviousObject ||
+            0 != lstrcmpW(pwzPreviousObject, pwzObject) ||
+            0 != lstrcmpW(pwzPreviousTable, pwzTable))
+        {
+            if (NULL != pwzPreviousObject)
+            {
+                // commit the ACLs
+                if (!pDaclNew)
+                {
+                    si &= ~(DACL_SECURITY_INFORMATION | 
PROTECTED_DACL_SECURITY_INFORMATION);
+                }
+                if (!pSaclNew)
+                {
+                    si &= ~(SACL_SECURITY_INFORMATION | 
PROTECTED_SACL_SECURITY_INFORMATION);
+                }
+                er = ::SetNamedSecurityInfoW(pwzPreviousObject, objectType, 
si, NULL, NULL, pDaclNew, pSaclNew);
+                MessageExitOnFailure1(hr = HRESULT_FROM_WIN32(er), 
msierrSecureObjectsFailedSet, "failed to set security info for object: %S", 
pwzPreviousObject);
+                if (pDaclNew)
+                    ::LocalFree(pDaclNew);
+                if (pSaclNew)
+                    ::LocalFree(pSaclNew);
+                if (psd)
+                    ::LocalFree(psd);
+                pDaclNew = NULL;
+                pSaclNew = NULL;
+                psd = NULL;
+                objectType = SE_UNKNOWN_OBJECT_TYPE;
+            }
+
+            objectType = SEObjectTypeFromString(const_cast<LPCWSTR> 
(pwzTable));
+            if (SE_UNKNOWN_OBJECT_TYPE != objectType)
+            {
+                er = ::GetNamedSecurityInfoW(pwzObject, objectType, 
DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION, NULL, NULL, 
&pDaclExisting, &pSaclExisting, &psd);
+                ExitOnFailure1(hr = HRESULT_FROM_WIN32(er), "failed to get 
security info for object: %S", pwzObject);
+
+                // Need to see if ACL is protected so getting Descriptor 
information
+                if(!::GetSecurityDescriptorControl(psd, &sdc, &dwRevision))
+                {
+                    ExitOnLastError1(hr, "failed to get security descriptor 
control for object: %S", pwzObject);
+                }
+
+                si = DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION;
+                if ((sdc & SE_DACL_PROTECTED) || (dwFlags & 
SOF_PROTECTED_DACL)) {
+                    si |= PROTECTED_DACL_SECURITY_INFORMATION;
+                }
+                if ((sdc & SE_SACL_PROTECTED) || (dwFlags & 
SOF_PROTECTED_SACL)) {
+                    si |= PROTECTED_SACL_SECURITY_INFORMATION;
+                }
+
+                if (dwFlags & SOF_PROTECTED_DACL) {
+                    pDaclExisting = NULL;
+                }
+                if (dwFlags & SOF_PROTECTED_SACL) {
+                    pSaclExisting = NULL;
+                }
+            }
+            else
+            {
+                MessageExitOnFailure1(hr = E_UNEXPECTED, 
msierrSecureObjectsUnknownType, "unknown object type: %S", pwzTable);
+            }
+
+            hr = StrAllocString(&pwzPreviousObject, pwzObject, 0);
+            ExitOnFailure1(hr, "failed to allocate string to store previous 
object: %S", pwzObject);
+            hr = StrAllocString(&pwzPreviousTable, pwzTable, 0);
+            ExitOnFailure1(hr, "failed to allocate string to store previous 
table: %S", pwzTable);
+        }
+
         //
         // create the appropriate SID
         //
+        if (psid)
+            AclFreeSid(psid);
+        psid = NULL;
 
         // figure out the right user to put into the access block
         if (!*pwzDomain && 0 == lstrcmpW(pwzUser, L"Everyone"))
         {
             hr = AclGetWellKnownSid(WinWorldSid, &psid);
         }
@@ -658,100 +782,130 @@
             hr = AclGetWellKnownSid(WinInteractiveSid, &psid);
         }
         else if(!*pwzDomain && 0 == lstrcmpW(pwzUser, L"Users"))
         {
             hr = AclGetWellKnownSid(WinBuiltinUsersSid, &psid);
         }
+        else if(!*pwzDomain && (hr = AclGetSidFromString(pwzUser, &psid)) == 
S_OK)
+        {
+            // hr is already S_OK
+        }
         else
         {
             hr = StrAllocFormatted(&pwzAccount, L"%s\\%s", *pwzDomain ? 
pwzDomain : L".", pwzUser);
             ExitOnFailure(hr, "failed to build domain user name");
 
             hr = AclGetAccountSid(NULL, pwzAccount, &psid);
         }
         ExitOnFailure3(hr, "failed to get sid for account: %S%S%S", pwzDomain, 
*pwzDomain ? L"\\" : L"", pwzUser);
 
         //
         // build up the explicit access
         //
-        ea.grfAccessMode = SET_ACCESS;
+        switch (dwType) {
+            case SOT_ALLOW:
+                ea.grfAccessMode = SET_ACCESS;
+                break;
+            case SOT_DENY:
+                ea.grfAccessMode = DENY_ACCESS;
+                break;
+            case SOT_AUDIT_SUCCESS:
+                ea.grfAccessMode = SET_AUDIT_SUCCESS;
+                break;
+            case SOT_AUDIT_FAILURE:
+                ea.grfAccessMode = SET_AUDIT_FAILURE;
+                break;
+        }
 
-        if (0 == lstrcmpW(L"CreateFolder", pwzTable))
+        ea.grfInheritance = NO_INHERITANCE;
+        if (!(dwFlags & SOF_SELF_INHERIT))
         {
-            ea.grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
+            ea.grfInheritance |= INHERIT_ONLY;
         }
-        else
+        if (dwFlags & SOF_CONTAINER_INHERIT)
+        {
+            ea.grfInheritance |= SUB_CONTAINERS_ONLY_INHERIT;
+        }
+        if (dwFlags & SOF_OBJECT_INHERIT)
         {
-            ea.grfInheritance = NO_INHERITANCE;
+            ea.grfInheritance |= SUB_OBJECTS_ONLY_INHERIT;
         }
 
 #pragma prefast(push)
 #pragma prefast(disable:25029)
         ::BuildTrusteeWithSidW(&ea.Trustee, psid);
 #pragma prefast(pop)
-
-        objectType = SEObjectTypeFromString(const_cast<LPCWSTR> (pwzTable));
 
         // always add these permissions for services
         // these are basic permissions that are often forgotten
         if (0 == lstrcmpW(L"ServiceInstall", pwzTable))
         {
             dwPermissions |= SERVICE_QUERY_CONFIG | SERVICE_QUERY_STATUS | 
SERVICE_ENUMERATE_DEPENDENTS | SERVICE_INTERROGATE;
         }
 
         ea.grfAccessPermissions = dwPermissions;
 
-        if (SE_UNKNOWN_OBJECT_TYPE != objectType)
-        {
-            er = ::GetNamedSecurityInfoW(pwzObject, objectType, 
DACL_SECURITY_INFORMATION, NULL, NULL, &pAclExisting, NULL, &psd);
-            ExitOnFailure1(hr = HRESULT_FROM_WIN32(er), "failed to get 
security info for object: %S", pwzObject);
-
-            //Need to see if DACL is protected so getting Descriptor 
information
-            if(!::GetSecurityDescriptorControl(psd, &sdc, &dwRevision))
-            {
-                ExitOnLastError1(hr, "failed to get security descriptor 
control for object: %S", pwzObject);
-            }
+        switch (dwType) {
+            case SOT_ALLOW:
+            case SOT_DENY:
+                pAclExisting = pDaclNew;
+                pAclNew = &pDaclNew;
+                if (!pAclExisting)
+                    pAclExisting = pDaclExisting;
+                break;
+            case SOT_AUDIT_SUCCESS:
+            case SOT_AUDIT_FAILURE:
+                pAclExisting = pSaclNew;
+                pAclNew = &pSaclNew;
+                if (!pAclExisting)
+                    pAclExisting = pSaclExisting;
+                break;
+        }
 
 #pragma prefast(push)
 #pragma prefast(disable:25029)
-            er = ::SetEntriesInAclW(1, &ea, pAclExisting, &pAclNew);
+        er = ::SetEntriesInAclW(1, &ea, pAclExisting, &pAclTemp);
 #pragma prefast(pop)
-            ExitOnFailure1(hr = HRESULT_FROM_WIN32(er), "failed to add ACLs 
for object: %S", pwzObject);
+        ExitOnFailure1(hr = HRESULT_FROM_WIN32(er), "failed to add ACLs for 
object: %S", pwzObject);
 
-            if (sdc & SE_DACL_PROTECTED)
-            {
-                si = DACL_SECURITY_INFORMATION | 
PROTECTED_DACL_SECURITY_INFORMATION;
-            }
-            else
-            {
-                si = DACL_SECURITY_INFORMATION;
-            }
-            er = ::SetNamedSecurityInfoW(pwzObject, objectType, si, NULL, 
NULL, pAclNew, NULL);
-            MessageExitOnFailure1(hr = HRESULT_FROM_WIN32(er), 
msierrSecureObjectsFailedSet, "failed to set security info for object: %S", 
pwzObject);
+        if (*pAclNew)
+            ::LocalFree(*pAclNew);
+        *pAclNew = pAclTemp;
+
+        hr = WcaProgressMessage(COST_SECUREOBJECT, FALSE);
+        ExitOnFailure(hr, "failed to send progress message");
+    }
+    if (NULL != pwzObject)
+    {
+        // commit the ACLs
+        if (!pDaclNew)
+        {
+            si &= ~(DACL_SECURITY_INFORMATION | 
PROTECTED_DACL_SECURITY_INFORMATION);
         }
-        else
+        if (!pSaclNew)
         {
-            MessageExitOnFailure1(hr = E_UNEXPECTED, 
msierrSecureObjectsUnknownType, "unknown object type: %S", pwzTable);
+            si &= ~(SACL_SECURITY_INFORMATION | 
PROTECTED_SACL_SECURITY_INFORMATION);
         }
-
-        hr = WcaProgressMessage(COST_SECUREOBJECT, FALSE);
-        ExitOnFailure(hr, "failed to send progress message");
-
-        objectType = SE_UNKNOWN_OBJECT_TYPE;
+        er = ::SetNamedSecurityInfoW(pwzObject, objectType, si, NULL, NULL, 
pDaclNew, pSaclNew);
+        MessageExitOnFailure1(hr = HRESULT_FROM_WIN32(er), 
msierrSecureObjectsFailedSet, "failed to set security info for object: %S", 
pwzPreviousObject);
     }
 
 LExit:
     ReleaseStr(pwzUser);
     ReleaseStr(pwzDomain);
     ReleaseStr(pwzTable);
+    ReleaseStr(pwzPreviousTable);
     ReleaseStr(pwzObject);
+    ReleaseStr(pwzPreviousObject);
     ReleaseStr(pwzData);
     ReleaseStr(pwzAccount);
 
-    if (pAclNew)
-        ::LocalFree(pAclNew);
+    if (pDaclNew)
+        ::LocalFree(pDaclNew);
+    if (pSaclNew)
+        ::LocalFree(pSaclNew);
     if (psd)
         ::LocalFree(psd);
     if (psid)
         AclFreeSid(psid);
 
     if (FAILED(hr))
@@ -775,18 +929,22 @@
 
     EXPLICIT_ACCESSW ea = {0};
     SE_OBJECT_TYPE objectType = SE_UNKNOWN_OBJECT_TYPE;
     PSECURITY_DESCRIPTOR psd = NULL;
     ULONG psdSize;
     SECURITY_DESCRIPTOR_CONTROL sdc = {0};
-    SECURITY_INFORMATION si = DACL_SECURITY_INFORMATION;
+    SECURITY_INFORMATION si = DACL_SECURITY_INFORMATION | 
SACL_SECURITY_INFORMATION;
     PACL pDacl = NULL;
     BOOL bDaclPresent = false;
     BOOL bDaclDefaulted = false;
+    PACL pSacl = NULL;
+    BOOL bSaclPresent = false;
+    BOOL bSaclDefaulted = false;
     DWORD dwRevision = 0;
-    int iProtected;
+    int iDaclProtected;
+    int iSaclProtected;
 
     // initialize
     hr = WcaInitialize(hInstall, "ExecSecureObjectsRollback");
     ExitOnFailure(hr, "failed to initialize");
 
     hr = WcaGetProperty(L"CustomActionData", &pwzData);
@@ -806,13 +964,16 @@
 
     if (SE_UNKNOWN_OBJECT_TYPE != objectType)
     {
         hr = WcaReadStringFromCaData(&pwz, &pwzSecurityInfo);
         ExitOnFailure(hr, "failed to process CustomActionData");
 
-        hr = WcaReadIntegerFromCaData(&pwz, &iProtected);
+        hr = WcaReadIntegerFromCaData(&pwz, &iDaclProtected);
+        ExitOnFailure(hr, "failed to process CustomActionData");
+
+        hr = WcaReadIntegerFromCaData(&pwz, &iSaclProtected);
         ExitOnFailure(hr, "failed to process CustomActionData");
 
         if 
(!::ConvertStringSecurityDescriptorToSecurityDescriptorW(pwzSecurityInfo,SDDL_REVISION_1,&psd,&psdSize))
         {
             ExitOnLastError(hr, "failed to convert security descriptor string 
to a valid security descriptor");
         }
@@ -834,13 +995,13 @@
         if(!::GetSecurityDescriptorControl(psd, &sdc, &dwRevision))
         {
             ExitOnLastError1(hr, "failed to get security descriptor control 
for object: %S", pwzObject);
         }
 
         // Write a 1 if DACL is protected, 0 otherwise
-        switch (iProtected)
+        switch (iDaclProtected)
         {
         case 0:
             // Unnecessary to do anything - leave si to the default flags
             break;
 
         case 1:
@@ -850,13 +1011,43 @@
         default:
             hr = E_UNEXPECTED;
             ExitOnFailure(hr, "unrecognized value in CustomActionData");
             break;
         }
 
-        er = ::SetNamedSecurityInfoW(pwzObject, objectType, si, NULL, NULL, 
pDacl, NULL);
+        if 
(!::GetSecurityDescriptorSacl(psd,&bSaclPresent,&pSacl,&bSaclDefaulted))
+        {
+            hr = E_UNEXPECTED;
+            ExitOnFailure2(hr, "failed to get security descriptor's SACL - 
error code: %d",pwzSecurityInfo,GetLastError());
+        }
+
+        // The below situation may always be caught by the above if block - 
the documentation isn't very clear. To be safe, we're going to test for it.
+        if (!bSaclPresent)
+        {
+            hr = E_UNEXPECTED;
+            ExitOnFailure(hr, "security descriptor does not contain a SACL");
+        }
+
+        // Write a 1 if DACL is protected, 0 otherwise
+        switch (iSaclProtected)
+        {
+        case 0:
+            // Unnecessary to do anything - leave si to the default flags
+            break;
+
+        case 1:
+            si = si | PROTECTED_SACL_SECURITY_INFORMATION;
+            break;
+
+        default:
+            hr = E_UNEXPECTED;
+            ExitOnFailure(hr, "unrecognized value in CustomActionData");
+            break;
+        }
+
+        er = ::SetNamedSecurityInfoW(pwzObject, objectType, si, NULL, NULL, 
pDacl, pSacl);
         ExitOnFailure2(hr = HRESULT_FROM_WIN32(er), "failed to set security 
info for object: %S error code: %d", pwzObject, GetLastError());
     }
     else
     {
         MessageExitOnFailure1(hr = E_UNEXPECTED, 
msierrSecureObjectsUnknownType, "unknown object type: %S", pwzTable);
     }
-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________
WiX-devs mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/wix-devs

Reply via email to