[NTMARTA]
[reactos.git] / reactos / dll / win32 / ntmarta / ntmarta.c
index b61eb5e..f6e77d4 100644 (file)
@@ -14,9 +14,9 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  */
-/* $Id$
+/* $Id: ntmarta.c 31176 2007-12-12 07:04:12Z weiden $
  *
  * PROJECT:         ReactOS MARTA provider
  * FILE:            lib/ntmarta/ntmarta.c
@@ -140,6 +140,11 @@ AccpGetAceStructureSize(IN PACE_HEADER AceHeader)
                 Size += sizeof(Ace->InheritedObjectType);
             break;
         }
+
+        case SYSTEM_MANDATORY_LABEL_ACE_TYPE:
+            Size = FIELD_OFFSET(SYSTEM_MANDATORY_LABEL_ACE,
+                                SidStart);
+            break;
     }
 
     return Size;
@@ -157,6 +162,377 @@ AccpGetAceAccessMask(IN PACE_HEADER AceHeader)
     return *((PACCESS_MASK)(AceHeader + 1));
 }
 
+static BOOL
+AccpIsObjectAce(IN PACE_HEADER AceHeader)
+{
+    BOOL Ret;
+
+    switch (AceHeader->AceType)
+    {
+        case ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE:
+        case ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE:
+        case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
+        case ACCESS_DENIED_OBJECT_ACE_TYPE:
+        case SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE:
+        case SYSTEM_AUDIT_OBJECT_ACE_TYPE:
+            Ret = TRUE;
+            break;
+
+        default:
+            Ret = FALSE;
+            break;
+    }
+
+    return Ret;
+}
+
+static DWORD
+AccpGetTrusteeObjects(IN PTRUSTEE_W Trustee,
+                      OUT GUID *pObjectTypeGuid  OPTIONAL,
+                      OUT GUID *pInheritedObjectTypeGuid  OPTIONAL)
+{
+    DWORD Ret;
+
+    switch (Trustee->TrusteeForm)
+    {
+        case TRUSTEE_IS_OBJECTS_AND_NAME:
+        {
+            POBJECTS_AND_NAME_W pOan = (POBJECTS_AND_NAME_W)Trustee->ptstrName;
+
+            /* pOan->ObjectsPresent should always be 0 here because a previous
+               call to AccpGetTrusteeSid should have rejected these trustees
+               already. */
+            ASSERT(pOan->ObjectsPresent == 0);
+
+            Ret = pOan->ObjectsPresent;
+            break;
+        }
+
+        case TRUSTEE_IS_OBJECTS_AND_SID:
+        {
+            POBJECTS_AND_SID pOas = (POBJECTS_AND_SID)Trustee->ptstrName;
+
+            if (pObjectTypeGuid != NULL && pOas->ObjectsPresent & ACE_OBJECT_TYPE_PRESENT)
+                *pObjectTypeGuid = pOas->ObjectTypeGuid;
+
+            if (pInheritedObjectTypeGuid != NULL && pOas->ObjectsPresent & ACE_INHERITED_OBJECT_TYPE_PRESENT)
+                *pObjectTypeGuid = pOas->InheritedObjectTypeGuid;
+
+            Ret = pOas->ObjectsPresent;
+            break;
+        }
+
+        default:
+            /* Any other trustee forms have no objects attached... */
+            Ret = 0;
+            break;
+    }
+
+    return Ret;
+}
+
+static DWORD
+AccpCalcNeededAceSize(IN PSID Sid,
+                      IN DWORD ObjectsPresent)
+{
+    DWORD Ret;
+
+    Ret = sizeof(ACE) + GetLengthSid(Sid);
+
+    /* This routine calculates the generic size of the ACE needed.
+       If no objects are present it is assumed that only a standard
+       ACE is to be created. */
+
+    if (ObjectsPresent & ACE_OBJECT_TYPE_PRESENT)
+        Ret += sizeof(GUID);
+    if (ObjectsPresent & ACE_INHERITED_OBJECT_TYPE_PRESENT)
+        Ret += sizeof(GUID);
+
+    if (ObjectsPresent != 0)
+        Ret += sizeof(DWORD); /* Include the Flags member to make it an object ACE */
+
+    return Ret;
+}
+
+static GUID*
+AccpGetObjectAceObjectType(IN PACE_HEADER AceHeader)
+{
+    GUID *ObjectType = NULL;
+
+    switch (AceHeader->AceType)
+    {
+        case ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE:
+        case ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE:
+        {
+            PACCESS_ALLOWED_CALLBACK_OBJECT_ACE Ace = (PACCESS_ALLOWED_CALLBACK_OBJECT_ACE)AceHeader;
+            if (Ace->Flags & ACE_OBJECT_TYPE_PRESENT)
+                ObjectType = &Ace->ObjectType;
+            break;
+        }
+        case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
+        case ACCESS_DENIED_OBJECT_ACE_TYPE:
+        {
+            PACCESS_ALLOWED_OBJECT_ACE Ace = (PACCESS_ALLOWED_OBJECT_ACE)AceHeader;
+            if (Ace->Flags & ACE_OBJECT_TYPE_PRESENT)
+                ObjectType = &Ace->ObjectType;
+            break;
+        }
+
+        case SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE:
+        {
+            PSYSTEM_AUDIT_CALLBACK_OBJECT_ACE Ace = (PSYSTEM_AUDIT_CALLBACK_OBJECT_ACE)AceHeader;
+            if (Ace->Flags & ACE_OBJECT_TYPE_PRESENT)
+                ObjectType = &Ace->ObjectType;
+            break;
+        }
+        case SYSTEM_AUDIT_OBJECT_ACE_TYPE:
+        {
+            PSYSTEM_AUDIT_OBJECT_ACE Ace = (PSYSTEM_AUDIT_OBJECT_ACE)AceHeader;
+            if (Ace->Flags & ACE_OBJECT_TYPE_PRESENT)
+                ObjectType = &Ace->ObjectType;
+            break;
+        }
+    }
+
+    return ObjectType;
+}
+
+static GUID*
+AccpGetObjectAceInheritedObjectType(IN PACE_HEADER AceHeader)
+{
+    GUID *ObjectType = NULL;
+
+    switch (AceHeader->AceType)
+    {
+        case ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE:
+        case ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE:
+        {
+            PACCESS_ALLOWED_CALLBACK_OBJECT_ACE Ace = (PACCESS_ALLOWED_CALLBACK_OBJECT_ACE)AceHeader;
+            if (Ace->Flags & ACE_INHERITED_OBJECT_TYPE_PRESENT)
+            {
+                if (Ace->Flags & ACE_OBJECT_TYPE_PRESENT)
+                    ObjectType = &Ace->InheritedObjectType;
+                else
+                    ObjectType = &Ace->ObjectType;
+            }
+            break;
+        }
+        case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
+        case ACCESS_DENIED_OBJECT_ACE_TYPE:
+        {
+            PACCESS_ALLOWED_OBJECT_ACE Ace = (PACCESS_ALLOWED_OBJECT_ACE)AceHeader;
+            if (Ace->Flags & ACE_INHERITED_OBJECT_TYPE_PRESENT)
+            {
+                if (Ace->Flags & ACE_OBJECT_TYPE_PRESENT)
+                    ObjectType = &Ace->InheritedObjectType;
+                else
+                    ObjectType = &Ace->ObjectType;
+            }
+            break;
+        }
+
+        case SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE:
+        {
+            PSYSTEM_AUDIT_CALLBACK_OBJECT_ACE Ace = (PSYSTEM_AUDIT_CALLBACK_OBJECT_ACE)AceHeader;
+            if (Ace->Flags & ACE_INHERITED_OBJECT_TYPE_PRESENT)
+            {
+                if (Ace->Flags & ACE_OBJECT_TYPE_PRESENT)
+                    ObjectType = &Ace->InheritedObjectType;
+                else
+                    ObjectType = &Ace->ObjectType;
+            }
+            break;
+        }
+        case SYSTEM_AUDIT_OBJECT_ACE_TYPE:
+        {
+            PSYSTEM_AUDIT_OBJECT_ACE Ace = (PSYSTEM_AUDIT_OBJECT_ACE)AceHeader;
+            if (Ace->Flags & ACE_INHERITED_OBJECT_TYPE_PRESENT)
+            {
+                if (Ace->Flags & ACE_OBJECT_TYPE_PRESENT)
+                    ObjectType = &Ace->InheritedObjectType;
+                else
+                    ObjectType = &Ace->ObjectType;
+            }
+            break;
+        }
+    }
+
+    return ObjectType;
+}
+
+static DWORD
+AccpOpenLSAPolicyHandle(IN LPWSTR SystemName,
+                        IN ACCESS_MASK DesiredAccess,
+                        OUT PLSA_HANDLE pPolicyHandle)
+{
+    LSA_OBJECT_ATTRIBUTES LsaObjectAttributes = {0};
+    LSA_UNICODE_STRING LsaSystemName, *psn;
+    NTSTATUS Status;
+
+    if (SystemName != NULL && SystemName[0] != L'\0')
+    {
+        LsaSystemName.Buffer = SystemName;
+        LsaSystemName.Length = wcslen(SystemName) * sizeof(WCHAR);
+        LsaSystemName.MaximumLength = LsaSystemName.Length + sizeof(WCHAR);
+        psn = &LsaSystemName;
+    }
+    else
+    {
+        psn = NULL;
+    }
+
+    Status = LsaOpenPolicy(psn,
+                           &LsaObjectAttributes,
+                           DesiredAccess,
+                           pPolicyHandle);
+    if (!NT_SUCCESS(Status))
+        return LsaNtStatusToWinError(Status);
+
+    return ERROR_SUCCESS;
+}
+
+static LPWSTR
+AccpGetTrusteeName(IN PTRUSTEE_W Trustee)
+{
+    switch (Trustee->TrusteeForm)
+    {
+        case TRUSTEE_IS_NAME:
+            return Trustee->ptstrName;
+
+        case TRUSTEE_IS_OBJECTS_AND_NAME:
+            return ((POBJECTS_AND_NAME_W)Trustee->ptstrName)->ptstrName;
+
+        default:
+            return NULL;
+    }
+}
+
+static DWORD
+AccpLookupSidByName(IN LSA_HANDLE PolicyHandle,
+                    IN LPWSTR Name,
+                    OUT PSID *pSid)
+{
+    NTSTATUS Status;
+    LSA_UNICODE_STRING LsaNames[1];
+    PLSA_REFERENCED_DOMAIN_LIST ReferencedDomains = NULL;
+    PLSA_TRANSLATED_SID2 TranslatedSid = NULL;
+    DWORD SidLen;
+    DWORD Ret = ERROR_SUCCESS;
+
+    LsaNames[0].Buffer = Name;
+    LsaNames[0].Length = wcslen(Name) * sizeof(WCHAR);
+    LsaNames[0].MaximumLength = LsaNames[0].Length + sizeof(WCHAR);
+
+    Status = LsaLookupNames2(PolicyHandle,
+                             0,
+                             sizeof(LsaNames) / sizeof(LsaNames[0]),
+                             LsaNames,
+                             &ReferencedDomains,
+                             &TranslatedSid);
+
+    if (!NT_SUCCESS(Status))
+        return LsaNtStatusToWinError(Status);
+
+    if (TranslatedSid->Use == SidTypeUnknown || TranslatedSid->Use == SidTypeInvalid)
+    {
+        Ret = LsaNtStatusToWinError(STATUS_NONE_MAPPED); /* FIXME- what error code? */
+        goto Cleanup;
+    }
+
+    SidLen = GetLengthSid(TranslatedSid->Sid);
+    ASSERT(SidLen != 0);
+
+    *pSid = LocalAlloc(LMEM_FIXED, (SIZE_T)SidLen);
+    if (*pSid != NULL)
+    {
+        if (!CopySid(SidLen,
+                     *pSid,
+                     TranslatedSid->Sid))
+        {
+            Ret = GetLastError();
+
+            LocalFree((HLOCAL)*pSid);
+            *pSid = NULL;
+        }
+    }
+    else
+        Ret = ERROR_NOT_ENOUGH_MEMORY;
+
+Cleanup:
+    LsaFreeMemory(ReferencedDomains);
+    LsaFreeMemory(TranslatedSid);
+
+    return Ret;
+}
+
+
+static DWORD
+AccpGetTrusteeSid(IN PTRUSTEE_W Trustee,
+                  IN OUT PLSA_HANDLE pPolicyHandle,
+                  OUT PSID *ppSid,
+                  OUT BOOL *Allocated)
+{
+    DWORD Ret = ERROR_SUCCESS;
+
+    *ppSid = NULL;
+    *Allocated = FALSE;
+
+    if (Trustee->pMultipleTrustee || Trustee->MultipleTrusteeOperation != NO_MULTIPLE_TRUSTEE)
+    {
+        /* This is currently not supported */
+        return ERROR_INVALID_PARAMETER;
+    }
+
+    switch (Trustee->TrusteeForm)
+    {
+        case TRUSTEE_IS_OBJECTS_AND_NAME:
+            if (((POBJECTS_AND_NAME_W)Trustee->ptstrName)->ObjectsPresent != 0)
+            {
+                /* This is not supported as there is no way to interpret the
+                   strings provided, and we need GUIDs for the ACEs... */
+                Ret = ERROR_INVALID_PARAMETER;
+                break;
+            }
+            /* fall through */
+
+        case TRUSTEE_IS_NAME:
+            if (*pPolicyHandle == NULL)
+            {
+                Ret = AccpOpenLSAPolicyHandle(NULL, /* FIXME - always local? */
+                                              POLICY_LOOKUP_NAMES,
+                                              pPolicyHandle);
+                if (Ret != ERROR_SUCCESS)
+                    return Ret;
+
+                ASSERT(*pPolicyHandle != NULL);
+            }
+
+            Ret = AccpLookupSidByName(*pPolicyHandle,
+                                      AccpGetTrusteeName(Trustee),
+                                      ppSid);
+            if (Ret == ERROR_SUCCESS)
+            {
+                ASSERT(*ppSid != NULL);
+                *Allocated = TRUE;
+            }
+            break;
+
+        case TRUSTEE_IS_OBJECTS_AND_SID:
+            *ppSid = ((POBJECTS_AND_SID)Trustee->ptstrName)->pSid;
+            break;
+
+        case TRUSTEE_IS_SID:
+            *ppSid = (PSID)Trustee->ptstrName;
+            break;
+
+        default:
+            Ret = ERROR_INVALID_PARAMETER;
+            break;
+    }
+
+    return Ret;
+}
+
 
 /**********************************************************************
  * AccRewriteGetHandleRights                           EXPORTED
@@ -437,6 +813,7 @@ AccpOpenNamedObject(LPWSTR pObjectName,
                     BOOL Write)
 {
     LPWSTR lpPath;
+    NTSTATUS Status;
     ACCESS_MASK DesiredAccess = (ACCESS_MASK)0;
     DWORD Ret = ERROR_SUCCESS;
 
@@ -450,20 +827,13 @@ AccpOpenNamedObject(LPWSTR pObjectName,
         case SE_WINDOW_OBJECT:
             if (Write)
             {
-                if (SecurityInfo & (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION))
-                    DesiredAccess |= WRITE_OWNER;
-                if (SecurityInfo & DACL_SECURITY_INFORMATION)
-                    DesiredAccess |= WRITE_DAC;
-                if (SecurityInfo & SACL_SECURITY_INFORMATION)
-                    DesiredAccess |= ACCESS_SYSTEM_SECURITY;
+                SetSecurityAccessMask(SecurityInfo,
+                                      (PDWORD)&DesiredAccess);
             }
             else
             {
-                if (SecurityInfo & (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
-                                    DACL_SECURITY_INFORMATION))
-                    DesiredAccess |= READ_CONTROL;
-                if (SecurityInfo & SACL_SECURITY_INFORMATION)
-                    DesiredAccess |= ACCESS_SYSTEM_SECURITY;
+                QuerySecurityAccessMask(SecurityInfo,
+                                        (PDWORD)&DesiredAccess);
             }
             break;
 
@@ -496,6 +866,45 @@ AccpOpenNamedObject(LPWSTR pObjectName,
     /* open a handle to the path depending on the object type */
     switch (ObjectType)
     {
+        case SE_FILE_OBJECT:
+        {
+            IO_STATUS_BLOCK IoStatusBlock;
+            OBJECT_ATTRIBUTES ObjectAttributes;
+            UNICODE_STRING FileName;
+
+            if (!RtlDosPathNameToNtPathName_U(pObjectName,
+                                              &FileName,
+                                              NULL,
+                                              NULL))
+            {
+                Ret = ERROR_INVALID_NAME;
+                goto Cleanup;
+            }
+
+            InitializeObjectAttributes(&ObjectAttributes,
+                                       &FileName,
+                                       OBJ_CASE_INSENSITIVE,
+                                       NULL,
+                                       NULL);
+
+            Status = NtOpenFile(Handle,
+                                DesiredAccess,
+                                &ObjectAttributes,
+                                &IoStatusBlock,
+                                FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+                                FILE_SYNCHRONOUS_IO_NONALERT);
+
+            RtlFreeHeap(RtlGetProcessHeap(),
+                        0,
+                        FileName.Buffer);
+
+            if (!NT_SUCCESS(Status))
+            {
+                Ret = RtlNtStatusToDosError(Status);
+            }
+            break;
+        }
+
         case SE_REGISTRY_KEY:
         {
             static const struct
@@ -653,7 +1062,7 @@ FailOpenService:
     }
 
 Cleanup:
-    if (lpPath != NULL)
+    if (lpPath != NULL && lpPath != pObjectName)
     {
         LocalFree((HLOCAL)lpPath);
     }
@@ -679,6 +1088,9 @@ AccpCloseObjectHandle(SE_OBJECT_TYPE ObjectType,
             break;
 
         case SE_FILE_OBJECT:
+            NtClose(Handle);
+            break;
+
         case SE_KERNEL_OBJECT:
         case SE_WINDOW_OBJECT:
             CloseHandle(Handle);
@@ -807,7 +1219,7 @@ AccRewriteSetNamedRights(LPWSTR pObjectName,
 /**********************************************************************
  * AccRewriteSetEntriesInAcl                           EXPORTED
  *
- * @unimplemented
+ * @implemented
  */
 DWORD WINAPI
 AccRewriteSetEntriesInAcl(ULONG cCountOfExplicitEntries,
@@ -815,13 +1227,240 @@ AccRewriteSetEntriesInAcl(ULONG cCountOfExplicitEntries,
                           PACL OldAcl,
                           PACL* NewAcl)
 {
-    UNIMPLEMENTED;
-    return ERROR_CALL_NOT_IMPLEMENTED;
+    PACL pNew = NULL;
+    ACL_SIZE_INFORMATION SizeInformation;
+    PACE_HEADER pAce;
+    BOOLEAN KeepAceBuf[8];
+    BOOLEAN *pKeepAce = NULL;
+    GUID ObjectTypeGuid, InheritedObjectTypeGuid;
+    DWORD ObjectsPresent;
+    BOOL needToClean;
+    PSID pSid1, pSid2;
+    ULONG i, j;
+    LSA_HANDLE PolicyHandle = NULL;
+    BOOL bRet;
+    DWORD LastErr;
+    DWORD Ret = ERROR_SUCCESS;
+
+    /* save the last error code */
+    LastErr = GetLastError();
+
+    *NewAcl = NULL;
+
+    /* Get information about previous ACL */
+    if (OldAcl)
+    {
+        if (!GetAclInformation(OldAcl, &SizeInformation, sizeof(ACL_SIZE_INFORMATION), AclSizeInformation))
+        {
+            Ret = GetLastError();
+            goto Cleanup;
+        }
+
+        if (SizeInformation.AceCount > sizeof(KeepAceBuf) / sizeof(KeepAceBuf[0]))
+        {
+            pKeepAce = (BOOLEAN *)LocalAlloc(LMEM_FIXED, SizeInformation.AceCount * sizeof(*pKeepAce));
+            if (!pKeepAce)
+            {
+                Ret = ERROR_NOT_ENOUGH_MEMORY;
+                goto Cleanup;
+            }
+        }
+        else
+            pKeepAce = KeepAceBuf;
+
+        memset(pKeepAce, TRUE, SizeInformation.AceCount * sizeof(*pKeepAce));
+    }
+    else
+    {
+        ZeroMemory(&SizeInformation, sizeof(ACL_SIZE_INFORMATION));
+        SizeInformation.AclBytesInUse = sizeof(ACL);
+    }
+
+    /* Get size required for new entries */
+    for (i = 0; i < cCountOfExplicitEntries; i++)
+    {
+        Ret = AccpGetTrusteeSid(&pListOfExplicitEntries[i].Trustee,
+                                &PolicyHandle,
+                                &pSid1,
+                                &needToClean);
+        if (Ret != ERROR_SUCCESS)
+            goto Cleanup;
+
+        ObjectsPresent = AccpGetTrusteeObjects(&pListOfExplicitEntries[i].Trustee,
+                                               NULL,
+                                               NULL);
+
+        switch (pListOfExplicitEntries[i].grfAccessMode)
+        {
+            case REVOKE_ACCESS:
+            case SET_ACCESS:
+                /* Discard all accesses for the trustee... */
+                for (j = 0; j < SizeInformation.AceCount; j++)
+                {
+                    if (!pKeepAce[j])
+                        continue;
+                    if (!GetAce(OldAcl, j, (PVOID*)&pAce))
+                    {
+                        Ret = GetLastError();
+                        goto Cleanup;
+                    }
+
+                    pSid2 = AccpGetAceSid(pAce);
+                    if (RtlEqualSid(pSid1, pSid2))
+                    {
+                        pKeepAce[j] = FALSE;
+                        SizeInformation.AclBytesInUse -= pAce->AceSize;
+                    }
+                }
+                if (pListOfExplicitEntries[i].grfAccessMode == REVOKE_ACCESS)
+                    break;
+                /* ...and replace by the current access */
+            case GRANT_ACCESS:
+            case DENY_ACCESS:
+                /* Add to ACL */
+                SizeInformation.AclBytesInUse += AccpCalcNeededAceSize(pSid1, ObjectsPresent);
+                break;
+            case SET_AUDIT_SUCCESS:
+            case SET_AUDIT_FAILURE:
+                /* FIXME */
+                DPRINT1("Case not implemented!\n");
+                break;
+            default:
+                DPRINT1("Unknown access mode 0x%x. Ignoring it\n", pListOfExplicitEntries[i].grfAccessMode);
+                break;
+        }
+
+        if (needToClean)
+            LocalFree((HLOCAL)pSid1);
+    }
+
+    /* OK, now create the new ACL */
+    DPRINT("Allocating %u bytes for the new ACL\n", SizeInformation.AclBytesInUse);
+    pNew = (PACL)LocalAlloc(LMEM_FIXED, SizeInformation.AclBytesInUse);
+    if (!pNew)
+    {
+        Ret = ERROR_NOT_ENOUGH_MEMORY;
+        goto Cleanup;
+    }
+    if (!InitializeAcl(pNew, SizeInformation.AclBytesInUse, ACL_REVISION))
+    {
+        Ret = GetLastError();
+        goto Cleanup;
+    }
+
+    /* Fill it */
+    /* 1a) New audit entries (SET_AUDIT_SUCCESS, SET_AUDIT_FAILURE) */
+    /* FIXME */
+
+    /* 1b) Existing audit entries */
+    /* FIXME */
+
+    /* 2a) New denied entries (DENY_ACCESS) */
+    for (i = 0; i < cCountOfExplicitEntries; i++)
+    {
+        if (pListOfExplicitEntries[i].grfAccessMode == DENY_ACCESS)
+        {
+            /* FIXME: take care of pListOfExplicitEntries[i].grfInheritance */
+            Ret = AccpGetTrusteeSid(&pListOfExplicitEntries[i].Trustee,
+                                    &PolicyHandle,
+                                    &pSid1,
+                                    &needToClean);
+            if (Ret != ERROR_SUCCESS)
+                goto Cleanup;
+
+            ObjectsPresent = AccpGetTrusteeObjects(&pListOfExplicitEntries[i].Trustee,
+                                                   &ObjectTypeGuid,
+                                                   &InheritedObjectTypeGuid);
+
+            if (ObjectsPresent == 0)
+            {
+                /* FIXME: Call AddAccessDeniedAceEx instead! */
+                bRet = AddAccessDeniedAce(pNew, ACL_REVISION, pListOfExplicitEntries[i].grfAccessPermissions, pSid1);
+            }
+            else
+            {
+                /* FIXME: Call AddAccessDeniedObjectAce */
+                DPRINT1("Object ACEs not yet supported!\n");
+                SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+                bRet = FALSE;
+            }
+
+            if (needToClean) LocalFree((HLOCAL)pSid1);
+            if (!bRet)
+            {
+                Ret = GetLastError();
+                goto Cleanup;
+            }
+        }
+    }
+
+    /* 2b) Existing denied entries */
+    /* FIXME */
+
+    /* 3a) New allow entries (GRANT_ACCESS, SET_ACCESS) */
+    for (i = 0; i < cCountOfExplicitEntries; i++)
+    {
+        if (pListOfExplicitEntries[i].grfAccessMode == SET_ACCESS ||
+            pListOfExplicitEntries[i].grfAccessMode == GRANT_ACCESS)
+        {
+            /* FIXME: take care of pListOfExplicitEntries[i].grfInheritance */
+            Ret = AccpGetTrusteeSid(&pListOfExplicitEntries[i].Trustee,
+                                    &PolicyHandle,
+                                    &pSid1,
+                                    &needToClean);
+            if (Ret != ERROR_SUCCESS)
+                goto Cleanup;
+
+            ObjectsPresent = AccpGetTrusteeObjects(&pListOfExplicitEntries[i].Trustee,
+                                                   &ObjectTypeGuid,
+                                                   &InheritedObjectTypeGuid);
+
+            if (ObjectsPresent == 0)
+            {
+                /* FIXME: Call AddAccessAllowedAceEx instead! */
+                bRet = AddAccessAllowedAce(pNew, ACL_REVISION, pListOfExplicitEntries[i].grfAccessPermissions, pSid1);
+            }
+            else
+            {
+                /* FIXME: Call AddAccessAllowedObjectAce */
+                DPRINT1("Object ACEs not yet supported!\n");
+                SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+                bRet = FALSE;
+            }
+
+            if (needToClean) LocalFree((HLOCAL)pSid1);
+            if (!bRet)
+            {
+                Ret = GetLastError();
+                goto Cleanup;
+            }
+        }
+    }
+
+    /* 3b) Existing allow entries */
+    /* FIXME */
+
+    *NewAcl = pNew;
+
+Cleanup:
+    if (pKeepAce && pKeepAce != KeepAceBuf)
+        LocalFree((HLOCAL)pKeepAce);
+
+    if (pNew && Ret != ERROR_SUCCESS)
+        LocalFree((HLOCAL)pNew);
+
+    if (PolicyHandle)
+        LsaClose(PolicyHandle);
+
+    /* restore the last error code */
+    SetLastError(LastErr);
+
+    return Ret;
 }
 
 
 /**********************************************************************
- * AccRewriteSetEntriesInAcl                           EXPORTED
+ * AccGetInheritanceSource                             EXPORTED
  *
  * @unimplemented
  */
@@ -852,9 +1491,12 @@ AccFreeIndexArray(PINHERITED_FROMW pInheritArray,
                   USHORT AceCnt,
                   PFN_OBJECT_MGR_FUNCTS pfnArray  OPTIONAL)
 {
+    PINHERITED_FROMW pLast;
+
     UNREFERENCED_PARAMETER(pfnArray);
 
-    while (AceCnt != 0)
+    pLast = pInheritArray + AceCnt;
+    while (pInheritArray != pLast)
     {
         if (pInheritArray->AncestorName != NULL)
         {
@@ -863,7 +1505,6 @@ AccFreeIndexArray(PINHERITED_FROMW pInheritArray,
         }
 
         pInheritArray++;
-        AceCnt--;
     }
 
     return ERROR_SUCCESS;
@@ -882,6 +1523,8 @@ AccRewriteGetExplicitEntriesFromAcl(PACL pacl,
 {
     PACE_HEADER AceHeader;
     PSID Sid, SidTarget;
+    ULONG ObjectAceCount = 0;
+    POBJECTS_AND_SID ObjSid;
     SIZE_T Size;
     PEXPLICIT_ACCESS_W peaw;
     DWORD LastErr, SidLen;
@@ -904,10 +1547,15 @@ AccRewriteGetExplicitEntriesFromAcl(PACL pacl,
             {
                 Sid = AccpGetAceSid(AceHeader);
                 Size += GetLengthSid(Sid);
-                /* FIXME - take size of opaque data in account? */
+
+                if (AccpIsObjectAce(AceHeader))
+                    ObjectAceCount++;
+
                 AceIndex++;
             }
 
+            Size += ObjectAceCount * sizeof(OBJECTS_AND_SID);
+
             ASSERT(pacl->AceCount == AceIndex);
 
             /* allocate the array */
@@ -916,9 +1564,10 @@ AccRewriteGetExplicitEntriesFromAcl(PACL pacl,
             if (peaw != NULL)
             {
                 AceIndex = 0;
-                SidTarget = (PSID)(peaw + pacl->AceCount);
+                ObjSid = (POBJECTS_AND_SID)(peaw + pacl->AceCount);
+                SidTarget = (PSID)(ObjSid + ObjectAceCount);
 
-                /* initialize the array */\
+                /* initialize the array */
                 while (GetAce(pacl,
                               AceIndex,
                               (LPVOID*)&AceHeader))
@@ -934,8 +1583,20 @@ AccRewriteGetExplicitEntriesFromAcl(PACL pacl,
                                 SidTarget,
                                 Sid))
                     {
-                        BuildTrusteeWithSid(&peaw[AceIndex].Trustee,
-                                            SidTarget);
+                        if (AccpIsObjectAce(AceHeader))
+                        {
+                            BuildTrusteeWithObjectsAndSid(&peaw[AceIndex].Trustee,
+                                                          ObjSid++,
+                                                          AccpGetObjectAceObjectType(AceHeader),
+                                                          AccpGetObjectAceInheritedObjectType(AceHeader),
+                                                          SidTarget);
+                        }
+                        else
+                        {
+                            BuildTrusteeWithSid(&peaw[AceIndex].Trustee,
+                                                SidTarget);
+                        }
+
                         SidTarget = (PSID)((ULONG_PTR)SidTarget + SidLen);
                     }
                     else
@@ -961,10 +1622,15 @@ AccRewriteGetExplicitEntriesFromAcl(PACL pacl,
         }
         else
         {
-            *pcCountOfExplicitEntries = 0;
-            *pListOfExplicitEntries = NULL;
+            goto EmptyACL;
         }
     }
+    else
+    {
+EmptyACL:
+        *pcCountOfExplicitEntries = 0;
+        *pListOfExplicitEntries = NULL;
+    }
 
     /* restore the last error code */
     SetLastError(LastErr);