minor fixes and use a .spec file
[reactos.git] / reactos / lib / aclui / aclui.c
index 710e7d9..69b99fe 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * ReactOS Access Control List Editor
- * Copyright (C) 2004 ReactOS Team
+ * Copyright (C) 2004-2005 ReactOS Team
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * UPDATE HISTORY:
  *      08/10/2004  Created
  */
-#include "acluilib.h"
+#include <precomp.h>
+
+#define NDEBUG
+#include <debug.h>
 
 HINSTANCE hDllInstance;
 
+#define SIDN_LOOKUPSUCCEEDED    (0x101)
+typedef struct _SIDLOOKUPNOTIFYINFO
+{
+    NMHDR nmh;
+    PSID Sid;
+    PSIDREQRESULT SidRequestResult;
+} SIDLOOKUPNOTIFYINFO, *PSIDLOOKUPNOTIFYINFO;
+
+static PSID
+AceHeaderToSID(IN PACE_HEADER AceHeader)
+{
+    PSID Sid = NULL;
+    switch (AceHeader->AceType)
+    {
+        case ACCESS_ALLOWED_ACE_TYPE:
+            Sid = (PSID)&((PACCESS_ALLOWED_ACE)AceHeader)->SidStart;
+            break;
+#if 0
+        case ACCESS_ALLOWED_CALLBACK_ACE_TYPE:
+            Sid = (PSID)&((PACCESS_ALLOWED_CALLBACK_ACE)AceHeader)->SidStart;
+            break;
+        case ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE:
+            Sid = (PSID)&((PACCESS_ALLOWED_CALLBACK_OBJECT_ACE)AceHeader)->SidStart;
+            break;
+#endif
+        case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
+            Sid = (PSID)&((PACCESS_ALLOWED_OBJECT_ACE)AceHeader)->SidStart;
+            break;
+        case ACCESS_DENIED_ACE_TYPE:
+            Sid = (PSID)&((PACCESS_DENIED_ACE)AceHeader)->SidStart;
+            break;
+#if 0
+        case ACCESS_DENIED_CALLBACK_ACE_TYPE:
+            Sid = (PSID)&((PACCESS_DENIED_CALLBACK_ACE)AceHeader)->SidStart;
+            break;
+        case ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE:
+            Sid = (PSID)&((PACCESS_DENIED_CALLBACK_OBJECT_ACE)AceHeader)->SidStart;
+            break;
+#endif
+        case SYSTEM_AUDIT_OBJECT_ACE_TYPE:
+            Sid = (PSID)&((PACCESS_DENIED_OBJECT_ACE)AceHeader)->SidStart;
+            break;
+    }
+
+    return Sid;
+}
+
 static VOID
 DestroySecurityPage(IN PSECURITY_PAGE sp)
 {
-    if(sp->hiUsrs != NULL)
+    if(sp->hiPrincipals != NULL)
     {
-        ImageList_Destroy(sp->hiUsrs);
+        ImageList_Destroy(sp->hiPrincipals);
     }
 
+    DestroySidCacheMgr(sp->SidCacheMgr);
+
     HeapFree(GetProcessHeap(),
              0,
              sp);
+
+    CoUninitialize();
 }
 
 static VOID
-FreeAceList(IN PACE_LISTITEM *AceListHead)
+FreePrincipalsList(IN PSECURITY_PAGE sp,
+                   IN PPRINCIPAL_LISTITEM *PrincipalsListHead)
 {
-    PACE_LISTITEM CurItem, NextItem;
+    PPRINCIPAL_LISTITEM CurItem, NextItem;
+    PACE_ENTRY AceEntry, NextAceEntry;
     
-    CurItem = *AceListHead;
+    CurItem = *PrincipalsListHead;
     while (CurItem != NULL)
     {
+        /* Free all ACEs */
+        AceEntry = CurItem->ACEs;
+        while (AceEntry != NULL)
+        {
+            NextAceEntry = AceEntry->Next;
+            HeapFree(GetProcessHeap(),
+                     0,
+                     AceEntry);
+            AceEntry = NextAceEntry;
+        }
+
         /* free the SID string if present */
+        if (CurItem->SidReqResult != NULL)
+        {
+            DereferenceSidReqResult(sp->SidCacheMgr,
+                                    CurItem->SidReqResult);
+        }
+
         if (CurItem->DisplayString != NULL)
         {
             LocalFree((HLOCAL)CurItem->DisplayString);
@@ -65,23 +138,61 @@ FreeAceList(IN PACE_LISTITEM *AceListHead)
         CurItem = NextItem;
     }
     
-    *AceListHead = NULL;
+    *PrincipalsListHead = NULL;
+}
+
+static PACE_ENTRY
+AddAceToPrincipal(IN PPRINCIPAL_LISTITEM Principal,
+                  IN PACE_HEADER AceHeader)
+{
+    PACE_ENTRY AceEntry, *AceLink;
+
+    AceEntry = HeapAlloc(GetProcessHeap(),
+                         0,
+                         sizeof(ACE_ENTRY) + AceHeader->AceSize);
+    if (AceEntry != NULL)
+    {
+        AceEntry->Next = NULL;
+
+        /* copy the ACE */
+        CopyMemory(AceEntry + 1,
+                   AceHeader,
+                   AceHeader->AceSize);
+
+        /* append it to the list */
+        AceLink = &Principal->ACEs;
+        while (*AceLink != NULL)
+        {
+            AceLink = &(*AceLink)->Next;
+        }
+        *AceLink = AceEntry;
+    }
+
+    return AceEntry;
 }
 
-static PACE_LISTITEM
-FindSidInAceList(IN PACE_LISTITEM AceListHead,
-                 IN PSID Sid)
+static PPRINCIPAL_LISTITEM
+FindSidInPrincipalsListAddAce(IN PPRINCIPAL_LISTITEM PrincipalsListHead,
+                              IN PSID Sid,
+                              IN PACE_HEADER AceHeader)
 {
-    PACE_LISTITEM CurItem;
+    PPRINCIPAL_LISTITEM CurItem;
     
-    for (CurItem = AceListHead;
+    for (CurItem = PrincipalsListHead;
          CurItem != NULL;
          CurItem = CurItem->Next)
     {
         if (EqualSid((PSID)(CurItem + 1),
                      Sid))
         {
-            return CurItem;
+            if (AddAceToPrincipal(CurItem,
+                                  AceHeader) != NULL)
+            {
+                return CurItem;
+            }
+
+            /* unable to add the ACE to the principal */
+            break;
         }
     }
     
@@ -89,7 +200,295 @@ FindSidInAceList(IN PACE_LISTITEM AceListHead,
 }
 
 static VOID
-ReloadUsersGroupsList(IN PSECURITY_PAGE sp)
+SidLookupCompletion(IN HANDLE SidCacheMgr,
+                    IN PSID Sid,
+                    IN PSIDREQRESULT SidRequestResult,
+                    IN PVOID Context)
+{
+    PSECURITY_PAGE sp = (PSECURITY_PAGE)Context;
+
+    /* NOTE: this routine may be executed in a different thread
+             than the GUI! */
+
+    if (SidRequestResult != NULL)
+    {
+        SIDLOOKUPNOTIFYINFO LookupInfo;
+
+        LookupInfo.nmh.hwndFrom = sp->hWnd;
+        LookupInfo.nmh.idFrom = 0;
+        LookupInfo.nmh.code = SIDN_LOOKUPSUCCEEDED;
+        LookupInfo.Sid = Sid;
+        LookupInfo.SidRequestResult = SidRequestResult;
+
+        /* notify the page that the sid lookup succeeded */
+        SendMessage(sp->hWnd,
+                    WM_NOTIFY,
+                    (WPARAM)LookupInfo.nmh.idFrom,
+                    (LPARAM)&LookupInfo.nmh);
+    }
+}
+
+static PPRINCIPAL_LISTITEM
+AddPrincipalToList(IN PSECURITY_PAGE sp,
+                   IN PSID Sid,
+                   IN PACE_HEADER AceHeader,
+                   OUT BOOL *LookupDeferred  OPTIONAL)
+{
+    PPRINCIPAL_LISTITEM PrincipalListItem = NULL, *PrincipalLink;
+    PACE_ENTRY AceEntry;
+    BOOL Deferred = FALSE;
+
+    if (!FindSidInPrincipalsListAddAce(sp->PrincipalsListHead,
+                                       Sid,
+                                       AceHeader))
+    {
+        DWORD SidLength;
+        
+        PrincipalLink = &sp->PrincipalsListHead;
+        while (*PrincipalLink != NULL)
+        {
+            PrincipalLink = &(*PrincipalLink)->Next;
+        }
+        
+        SidLength = GetLengthSid(Sid);
+
+        /* allocate the principal */
+        PrincipalListItem = HeapAlloc(GetProcessHeap(),
+                                      0,
+                                      sizeof(PRINCIPAL_LISTITEM) + SidLength);
+        if (PrincipalListItem != NULL)
+        {
+            PrincipalListItem->DisplayString = NULL;
+            PrincipalListItem->SidReqResult = NULL;
+
+            CopySid(SidLength,
+                    (PSID)(PrincipalListItem + 1),
+                    Sid);
+
+            /* allocate some memory for the ACE and copy it */
+            AceEntry = HeapAlloc(GetProcessHeap(),
+                                 0,
+                                 sizeof(ACE_ENTRY) + AceHeader->AceSize);
+            if (AceEntry != NULL)
+            {
+                AceEntry->Next = NULL;
+                CopyMemory(AceEntry + 1,
+                           AceHeader,
+                           AceHeader->AceSize);
+
+                /* add the ACE to the list */
+                PrincipalListItem->ACEs = AceEntry;
+
+                PrincipalListItem->Next = NULL;
+
+                /* append item to the principals list */
+                *PrincipalLink = PrincipalListItem;
+
+                /* lookup the SID now */
+                Deferred = !LookupSidCache(sp->SidCacheMgr,
+                                           Sid,
+                                           SidLookupCompletion,
+                                           sp);
+            }
+            else
+            {
+                HeapFree(GetProcessHeap(),
+                         0,
+                         PrincipalListItem);
+                PrincipalListItem = NULL;
+            }
+        }
+    }
+
+    if (PrincipalListItem != NULL && LookupDeferred != NULL)
+    {
+        *LookupDeferred = Deferred;
+    }
+
+    return PrincipalListItem;
+}
+
+static LPWSTR
+GetPrincipalDisplayString(IN PPRINCIPAL_LISTITEM PrincipalListItem)
+{
+    LPWSTR lpDisplayString = NULL;
+
+    if (PrincipalListItem->SidReqResult != NULL)
+    {
+        if (PrincipalListItem->SidReqResult->SidNameUse == SidTypeUser ||
+            PrincipalListItem->SidReqResult->SidNameUse == SidTypeGroup)
+        {
+            LoadAndFormatString(hDllInstance,
+                                IDS_USERDOMAINFORMAT,
+                                &lpDisplayString,
+                                PrincipalListItem->SidReqResult->AccountName,
+                                PrincipalListItem->SidReqResult->DomainName,
+                                PrincipalListItem->SidReqResult->AccountName);
+        }
+        else
+        {
+            LoadAndFormatString(hDllInstance,
+                                IDS_USERFORMAT,
+                                &lpDisplayString,
+                                PrincipalListItem->SidReqResult->AccountName);
+        }
+    }
+    else
+    {
+        ConvertSidToStringSid((PSID)(PrincipalListItem + 1),
+                              &lpDisplayString);
+    }
+
+    return lpDisplayString;
+}
+
+static LPWSTR
+GetPrincipalAccountNameString(IN PPRINCIPAL_LISTITEM PrincipalListItem)
+{
+    LPWSTR lpDisplayString = NULL;
+
+    if (PrincipalListItem->SidReqResult != NULL)
+    {
+        LoadAndFormatString(hDllInstance,
+                            IDS_USERFORMAT,
+                            &lpDisplayString,
+                            PrincipalListItem->SidReqResult->AccountName);
+    }
+    else
+    {
+        ConvertSidToStringSid((PSID)(PrincipalListItem + 1),
+                              &lpDisplayString);
+    }
+
+    return lpDisplayString;
+}
+
+static VOID
+CreatePrincipalListItem(OUT LVITEM *li,
+                        IN PSECURITY_PAGE sp,
+                        IN PPRINCIPAL_LISTITEM PrincipalListItem,
+                        IN INT Index,
+                        IN BOOL Selected)
+{
+    INT ImageIndex = 2;
+
+    if (PrincipalListItem->SidReqResult != NULL)
+    {
+        switch (PrincipalListItem->SidReqResult->SidNameUse)
+        {
+            case SidTypeUser:
+                ImageIndex = 0;
+                break;
+            case SidTypeWellKnownGroup:
+            case SidTypeGroup:
+                ImageIndex = 1;
+                break;
+            default:
+                break;
+        }
+    }
+
+    li->mask = LVIF_IMAGE | LVIF_PARAM | LVIF_STATE | LVIF_TEXT;
+    li->iItem = Index;
+    li->iSubItem = 0;
+    li->state = (Selected ? LVIS_SELECTED : 0);
+    li->stateMask = LVIS_SELECTED;
+    li->pszText = PrincipalListItem->DisplayString;
+    li->iImage = ImageIndex;
+    li->lParam = (LPARAM)PrincipalListItem;
+}
+
+static INT
+AddPrincipalListEntry(IN PSECURITY_PAGE sp,
+                      IN PPRINCIPAL_LISTITEM PrincipalListItem,
+                      IN INT Index,
+                      IN BOOL Selected)
+{
+    LVITEM li;
+    INT Ret;
+
+    if (PrincipalListItem->DisplayString != NULL)
+    {
+        LocalFree((HLOCAL)PrincipalListItem->DisplayString);
+    }
+    PrincipalListItem->DisplayString = GetPrincipalDisplayString(PrincipalListItem);
+
+    CreatePrincipalListItem(&li,
+                            sp,
+                            PrincipalListItem,
+                            Index,
+                            Selected);
+
+    Ret = ListView_InsertItem(sp->hWndPrincipalsList,
+                              &li);
+
+    return Ret;
+}
+
+static int CALLBACK
+PrincipalCompare(IN LPARAM lParam1,
+                 IN LPARAM lParam2,
+                 IN LPARAM lParamSort)
+{
+    PPRINCIPAL_LISTITEM Item1 = (PPRINCIPAL_LISTITEM)lParam1;
+    PPRINCIPAL_LISTITEM Item2 = (PPRINCIPAL_LISTITEM)lParam2;
+
+    if (Item1->DisplayString != NULL && Item2->DisplayString != NULL)
+    {
+        return wcscmp(Item1->DisplayString,
+                      Item2->DisplayString);
+    }
+
+    return 0;
+}
+
+static VOID
+UpdatePrincipalListItem(IN PSECURITY_PAGE sp,
+                        IN INT PrincipalIndex,
+                        IN PPRINCIPAL_LISTITEM PrincipalListItem,
+                        IN PSIDREQRESULT SidReqResult)
+{
+    LVITEM li;
+
+    /* replace the request result structure */
+    if (PrincipalListItem->SidReqResult != NULL)
+    {
+        DereferenceSidReqResult(sp->SidCacheMgr,
+                                PrincipalListItem->SidReqResult);
+    }
+
+    ReferenceSidReqResult(sp->SidCacheMgr,
+                          SidReqResult);
+    PrincipalListItem->SidReqResult = SidReqResult;
+
+    /* update the display string */
+    if (PrincipalListItem->DisplayString != NULL)
+    {
+        LocalFree((HLOCAL)PrincipalListItem->DisplayString);
+    }
+    PrincipalListItem->DisplayString = GetPrincipalDisplayString(PrincipalListItem);
+
+    /* update the list item */
+    CreatePrincipalListItem(&li,
+                            sp,
+                            PrincipalListItem,
+                            PrincipalIndex,
+                            FALSE);
+
+    /* don't change the list item state */
+    li.mask &= ~(LVIF_STATE | LVIF_PARAM);
+
+    ListView_SetItem(sp->hWndPrincipalsList,
+                     &li);
+
+    /* sort the principals list view again */
+    ListView_SortItems(sp->hWndPrincipalsList,
+                       PrincipalCompare,
+                       (LPARAM)sp);
+}
+
+static VOID
+ReloadPrincipalsList(IN PSECURITY_PAGE sp)
 {
     PSECURITY_DESCRIPTOR SecurityDescriptor;
     BOOL DaclPresent, DaclDefaulted;
@@ -97,7 +496,8 @@ ReloadUsersGroupsList(IN PSECURITY_PAGE sp)
     HRESULT hRet;
 
     /* delete the cached ACL */
-    FreeAceList(&sp->AceListHead);
+    FreePrincipalsList(sp,
+                       &sp->PrincipalsListHead);
 
     /* query the ACL */
     hRet = sp->psi->lpVtbl->GetSecurity(sp->psi,
@@ -109,226 +509,38 @@ ReloadUsersGroupsList(IN PSECURITY_PAGE sp)
         if (GetSecurityDescriptorDacl(SecurityDescriptor,
                                       &DaclPresent,
                                       &Dacl,
-                                      &DaclDefaulted))
+                                      &DaclDefaulted) &&
+            DaclPresent && Dacl != NULL)
         {
-            PACE_LISTITEM AceListItem, *NextAcePtr;
             PSID Sid;
-            PVOID Ace;
+            PACE_HEADER AceHeader;
             ULONG AceIndex;
-            DWORD AccountNameSize, DomainNameSize, SidLength;
-            SID_NAME_USE SidNameUse;
-            DWORD LookupResult;
-            
-            NextAcePtr = &sp->AceListHead;
             
             for (AceIndex = 0;
                  AceIndex < Dacl->AceCount;
                  AceIndex++)
             {
-                GetAce(Dacl,
-                       AceIndex,
-                       &Ace);
-
-                Sid = (PSID)&((PACCESS_ALLOWED_ACE)Ace)->SidStart;
-
-                if (!FindSidInAceList(sp->AceListHead,
-                                      Sid))
+                if (GetAce(Dacl,
+                           AceIndex,
+                           (LPVOID*)&AceHeader) &&
+                    AceHeader != NULL)
                 {
-                    SidLength = GetLengthSid(Sid);
-                    
-                    AccountNameSize = 0;
-                    DomainNameSize = 0;
-
-                    /* calculate the size of the buffer we need to calculate */
-                    LookupAccountSid(NULL, /* FIXME */
-                                     Sid,
-                                     NULL,
-                                     &AccountNameSize,
-                                     NULL,
-                                     &DomainNameSize,
-                                     &SidNameUse);
-
-                    /* allocate the ace */
-                    AceListItem = HeapAlloc(GetProcessHeap(),
-                                            0,
-                                            sizeof(ACE_LISTITEM) +
-                                            SidLength +
-                                            ((AccountNameSize + DomainNameSize) * sizeof(WCHAR)));
-                    if (AceListItem != NULL)
-                    {
-                        AceListItem->AccountName = (LPWSTR)((ULONG_PTR)(AceListItem + 1) + SidLength);
-                        AceListItem->DomainName = AceListItem->AccountName + AccountNameSize;
-
-                        CopySid(SidLength,
-                                (PSID)(AceListItem + 1),
-                                Sid);
-
-                        LookupResult = ERROR_SUCCESS;
-                        if (!LookupAccountSid(NULL, /* FIXME */
-                                              Sid,
-                                              AceListItem->AccountName,
-                                              &AccountNameSize,
-                                              AceListItem->DomainName,
-                                              &DomainNameSize,
-                                              &SidNameUse))
-                        {
-                            LookupResult = GetLastError();
-                            if (LookupResult != ERROR_NONE_MAPPED)
-                            {
-                                HeapFree(GetProcessHeap(),
-                                         0,
-                                         AceListItem);
-                                continue;
-                            }
-                        }
-                        
-                        if (AccountNameSize == 0)
-                        {
-                            AceListItem->AccountName = NULL;
-                        }
-                        if (DomainNameSize == 0)
-                        {
-                            AceListItem->DomainName = NULL;
-                        }
+                    BOOL LookupDeferred;
+                    PPRINCIPAL_LISTITEM PrincipalListItem;
 
-                        AceListItem->Next = NULL;
-                        if (LookupResult == ERROR_NONE_MAPPED)
-                        {
-                            if (!ConvertSidToStringSid(Sid,
-                                                       &AceListItem->DisplayString))
-                            {
-                                AceListItem->DisplayString = NULL;
-                            }
-                        }
-                        else
-                        {
-                            LSA_HANDLE LsaHandle;
-                            NTSTATUS Status;
-                            
-                            AceListItem->DisplayString = NULL;
-                            
-                            /* read the domain of the SID */
-                            if (OpenLSAPolicyHandle(NULL, /* FIXME */
-                                                    POLICY_LOOKUP_NAMES | POLICY_VIEW_LOCAL_INFORMATION,
-                                                    &LsaHandle))
-                            {
-                                PLSA_REFERENCED_DOMAIN_LIST ReferencedDomain;
-                                PLSA_TRANSLATED_NAME Names;
-                                PLSA_TRUST_INFORMATION Domain;
-                                PLSA_UNICODE_STRING DomainName;
-                                PPOLICY_ACCOUNT_DOMAIN_INFO PolicyAccountDomainInfo = NULL;
-
-                                Status = LsaLookupSids(LsaHandle,
-                                                       1,
-                                                       &Sid,
-                                                       &ReferencedDomain,
-                                                       &Names);
-                                if (NT_SUCCESS(Status))
-                                {
-                                    if (ReferencedDomain != NULL &&
-                                        Names->DomainIndex >= 0)
-                                    {
-                                        Domain = &ReferencedDomain->Domains[Names->DomainIndex];
-                                        DomainName = &Domain->Name;
-                                    }
-                                    else
-                                    {
-                                        Domain = NULL;
-                                        DomainName = NULL;
-                                    }
-                                    
-                                    AceListItem->SidNameUse = Names->Use;
-
-                                    switch (Names->Use)
-                                    {
-                                        case SidTypeAlias:
-                                            if (Domain != NULL)
-                                            {
-                                                /* query the domain name for BUILTIN accounts */
-                                                Status = LsaQueryInformationPolicy(LsaHandle,
-                                                                                   PolicyAccountDomainInformation,
-                                                                                   (PVOID*)&PolicyAccountDomainInfo);
-                                                if (NT_SUCCESS(Status))
-                                                {
-                                                    DomainName = &PolicyAccountDomainInfo->DomainName;
-
-                                                    /* make the user believe this is a group */
-                                                    AceListItem->SidNameUse = SidTypeGroup;
-                                                }
-                                            }
-                                            /* fall through */
-
-                                        case SidTypeUser:
-                                        {
-                                            if (Domain != NULL)
-                                            {
-                                                AceListItem->DisplayString = (LPWSTR)LocalAlloc(LMEM_FIXED,
-                                                                                                (AccountNameSize * sizeof(WCHAR)) +
-                                                                                                (DomainName->Length + sizeof(WCHAR)) +
-                                                                                                (Names->Name.Length + sizeof(WCHAR)) +
-                                                                                                (4 * sizeof(WCHAR)));
-                                                if (AceListItem->DisplayString != NULL)
-                                                {
-                                                    WCHAR *s;
-                                                    
-                                                    /* NOTE: LSA_UNICODE_STRINGs are not always NULL-terminated! */
-
-                                                    wcscpy(AceListItem->DisplayString,
-                                                           AceListItem->AccountName);
-                                                    wcscat(AceListItem->DisplayString,
-                                                           L" (");
-                                                    s = AceListItem->DisplayString + wcslen(AceListItem->DisplayString);
-                                                    CopyMemory(s,
-                                                               DomainName->Buffer,
-                                                               DomainName->Length);
-                                                    s += DomainName->Length / sizeof(WCHAR);
-                                                    *(s++) = L'\\';
-                                                    CopyMemory(s,
-                                                               Names->Name.Buffer,
-                                                               Names->Name.Length);
-                                                    s += Names->Name.Length / sizeof(WCHAR);
-                                                    *(s++) = L')';
-                                                    *s = L'\0';
-                                                }
-                                                
-                                                /* mark the ace as a user unless it's a
-                                                   BUILTIN account */
-                                                if (PolicyAccountDomainInfo == NULL)
-                                                {
-                                                    AceListItem->SidNameUse = SidTypeUser;
-                                                }
-                                            }
-                                            break;
-                                        }
-                                        
-                                        case SidTypeWellKnownGroup:
-                                        {
-                                            /* make the user believe this is a group */
-                                            AceListItem->SidNameUse = SidTypeGroup;
-                                            break;
-                                        }
-                                        
-                                        default:
-                                        {
-                                            break;
-                                        }
-                                    }
-                                    
-                                    if (PolicyAccountDomainInfo != NULL)
-                                    {
-                                        LsaFreeMemory(PolicyAccountDomainInfo);
-                                    }
-                                    
-                                    LsaFreeMemory(ReferencedDomain);
-                                    LsaFreeMemory(Names);
-                                }
-                                LsaClose(LsaHandle);
-                            }
-                        }
+                    Sid = AceHeaderToSID(AceHeader);
+
+                    PrincipalListItem = AddPrincipalToList(sp,
+                                                           Sid,
+                                                           AceHeader,
+                                                           &LookupDeferred);
 
-                        /* append item to the cached ACL */
-                        *NextAcePtr = AceListItem;
-                        NextAcePtr = &AceListItem->Next;
+                    if (PrincipalListItem != NULL && LookupDeferred)
+                    {
+                        AddPrincipalListEntry(sp,
+                                              PrincipalListItem,
+                                              -1,
+                                              FALSE);
                     }
                 }
             }
@@ -337,80 +549,103 @@ ReloadUsersGroupsList(IN PSECURITY_PAGE sp)
     }
 }
 
-static INT
-AddAceListEntry(IN PSECURITY_PAGE sp,
-                IN PACE_LISTITEM AceListItem,
-                IN INT Index,
-                IN BOOL Selected)
+static VOID
+UpdateControlStates(IN PSECURITY_PAGE sp)
 {
-    LVITEM li;
+    PPRINCIPAL_LISTITEM Selected = (PPRINCIPAL_LISTITEM)ListViewGetSelectedItemData(sp->hWndPrincipalsList);
 
-    li.mask = LVIF_IMAGE | LVIF_PARAM | LVIF_STATE | LVIF_TEXT;
-    li.iItem = Index;
-    li.iSubItem = 0;
-    li.state = (Selected ? LVIS_SELECTED : 0);
-    li.stateMask = LVIS_SELECTED;
-    li.pszText = (AceListItem->DisplayString != NULL ? AceListItem->DisplayString : AceListItem->AccountName);
-    switch (AceListItem->SidNameUse)
+    EnableWindow(sp->hBtnRemove,
+                 Selected != NULL);
+    EnableWindow(sp->hAceCheckList,
+                 Selected != NULL);
+    
+    if (Selected != NULL)
     {
-        case SidTypeUser:
-            li.iImage = 0;
-            break;
-        case SidTypeGroup:
-            li.iImage = 1;
-            break;
-        default:
-            li.iImage = -1;
-            break;
-    }
-    li.lParam = (LPARAM)AceListItem;
-
-    return ListView_InsertItem(sp->hWndAceList,
-                               &li);
-}
+        LPWSTR szLabel;
+        LPWSTR szDisplayString;
+
+        szDisplayString = GetPrincipalAccountNameString(Selected);
+        if (LoadAndFormatString(hDllInstance,
+                                IDS_PERMISSIONS_FOR,
+                                &szLabel,
+                                szDisplayString))
+        {
+            SetWindowText(sp->hPermissionsForLabel,
+                          szLabel);
 
-static VOID
-FillUsersGroupsList(IN PSECURITY_PAGE sp)
-{
-    LPARAM SelLParam;
-    PACE_LISTITEM CurItem;
-    RECT rcLvClient;
+            LocalFree((HLOCAL)szLabel);
+        }
 
-    SelLParam = ListViewGetSelectedItemData(sp->hWndAceList);
+        LocalFree((HLOCAL)szDisplayString);
 
-    DisableRedrawWindow(sp->hWndAceList);
+        /* FIXME - update the checkboxes */
+    }
+    else
+    {
+        WCHAR szPermissions[255];
+        
+        if (LoadString(hDllInstance,
+                       IDS_PERMISSIONS,
+                       szPermissions,
+                       sizeof(szPermissions) / sizeof(szPermissions[0])))
+        {
+            SetWindowText(sp->hPermissionsForLabel,
+                          szPermissions);
+        }
 
-    ListView_DeleteAllItems(sp->hWndAceList);
+        SendMessage(sp->hAceCheckList,
+                    CLM_CLEARCHECKBOXES,
+                    0,
+                    0);
+    }
+}
 
-    ReloadUsersGroupsList(sp);
+static void
+UpdatePrincipalInfo(IN PSECURITY_PAGE sp,
+                    IN PSIDLOOKUPNOTIFYINFO LookupInfo)
+{
+    PPRINCIPAL_LISTITEM CurItem;
 
-    for (CurItem = sp->AceListHead;
+    for (CurItem = sp->PrincipalsListHead;
          CurItem != NULL;
          CurItem = CurItem->Next)
     {
-        AddAceListEntry(sp,
-                        CurItem,
-                        -1,
-                        (SelLParam == (LPARAM)CurItem));
-    }
-    
-    EnableRedrawWindow(sp->hWndAceList);
-    
-    GetClientRect(sp->hWndAceList, &rcLvClient);
-    
-    ListView_SetColumnWidth(sp->hWndAceList,
-                            0,
-                            rcLvClient.right);
-}
+        if (EqualSid((PSID)(CurItem + 1),
+                     LookupInfo->Sid))
+        {
+            INT PrincipalIndex;
+            LVFINDINFO lvfi;
 
-static VOID
-UpdateControlStates(IN PSECURITY_PAGE sp)
-{
-    BOOL UserOrGroupSelected;
-    
-    UserOrGroupSelected = (ListViewGetSelectedItemData(sp->hWndAceList) != 0);
+            /* find the principal in the list */
+            lvfi.flags = LVFI_PARAM;
+            lvfi.lParam = (LPARAM)CurItem;
+            PrincipalIndex = ListView_FindItem(sp->hWndPrincipalsList,
+                                               -1,
+                                               &lvfi);
+
+            if (PrincipalIndex != -1)
+            {
+                /* update the principal in the list view control */
+                UpdatePrincipalListItem(sp,
+                                        PrincipalIndex,
+                                        CurItem,
+                                        LookupInfo->SidRequestResult);
 
-    EnableWindow(sp->hBtnRemove, UserOrGroupSelected);
+                if (ListViewGetSelectedItemData(sp->hWndPrincipalsList) == (LPARAM)CurItem)
+                {
+                    UpdateControlStates(sp);
+                }
+            }
+            else
+            {
+                AddPrincipalListEntry(sp,
+                                      CurItem,
+                                      -1,
+                                      FALSE);
+            }
+            break;
+        }
+    }
 }
 
 static UINT CALLBACK
@@ -420,7 +655,7 @@ SecurityPageCallback(IN HWND hwnd,
 {
     PSECURITY_PAGE sp = (PSECURITY_PAGE)ppsp->lParam;
     
-    switch(uMsg)
+    switch (uMsg)
     {
         case PSPCB_CREATE:
         {
@@ -429,7 +664,6 @@ SecurityPageCallback(IN HWND hwnd,
         case PSPCB_RELEASE:
         {
             DestroySecurityPage(sp);
-            UnregisterCheckListControl();
             return FALSE;
         }
     }
@@ -460,6 +694,421 @@ SetAceCheckListColumns(IN HWND hAceCheckList,
                 pt.x);
 }
 
+static VOID
+LoadPermissionsList(IN PSECURITY_PAGE sp,
+                    IN GUID *GuidObjectType,
+                    IN DWORD dwFlags,
+                    OUT SI_ACCESS *DefaultAccess)
+{
+    HRESULT hRet;
+    PSI_ACCESS AccessList;
+    ULONG nAccessList, DefaultAccessIndex;
+    WCHAR szSpecialPermissions[255];
+    BOOLEAN SpecialPermissionsPresent = FALSE;
+    ACCESS_MASK SpecialPermissionsMask = 0;
+
+    /* clear the permissions list */
+
+    SendMessage(sp->hAceCheckList,
+                CLM_CLEAR,
+                0,
+                0);
+
+    /* query the access rights from the server */
+    hRet = sp->psi->lpVtbl->GetAccessRights(sp->psi,
+                                            GuidObjectType,
+                                            dwFlags, /* FIXME */
+                                            &AccessList,
+                                            &nAccessList,
+                                            &DefaultAccessIndex);
+    if (SUCCEEDED(hRet) && nAccessList != 0)
+    {
+        LPCWSTR NameStr;
+        PSI_ACCESS CurAccess, LastAccess;
+        WCHAR NameBuffer[MAX_PATH];
+
+        /* save the default access rights to be used when adding ACEs later */
+        if (DefaultAccess != NULL)
+        {
+            *DefaultAccess = AccessList[DefaultAccessIndex];
+        }
+
+        LastAccess = AccessList + nAccessList;
+        for (CurAccess = &AccessList[0];
+             CurAccess != LastAccess;
+             CurAccess++)
+        {
+            if (CurAccess->dwFlags & dwFlags)
+            {
+                /* get the permission name, load it from a string table if necessary */
+                if (IS_INTRESOURCE(CurAccess->pszName))
+                {
+                    if (!LoadString(sp->ObjectInfo.hInstance,
+                                    (UINT)((ULONG_PTR)CurAccess->pszName),
+                                    NameBuffer,
+                                    sizeof(NameBuffer) / sizeof(NameBuffer[0])))
+                    {
+                        LoadString(hDllInstance,
+                                   IDS_UNKNOWN,
+                                   NameBuffer,
+                                   sizeof(NameBuffer) / sizeof(NameBuffer[0]));
+                    }
+                    NameStr = NameBuffer;
+                }
+                else
+                {
+                    NameStr = CurAccess->pszName;
+                }
+
+                SendMessage(sp->hAceCheckList,
+                            CLM_ADDITEM,
+                            (WPARAM)CurAccess->mask,
+                            (LPARAM)NameStr);
+            }
+            else if (CurAccess->dwFlags & SI_ACCESS_SPECIFIC)
+            {
+                SpecialPermissionsPresent = TRUE;
+                SpecialPermissionsMask |= CurAccess->mask;
+            }
+        }
+    }
+
+    /* add the special permissions check item in case the specific access rights
+       aren't displayed */
+    if (SpecialPermissionsPresent &&
+        LoadString(hDllInstance,
+                   IDS_SPECIAL_PERMISSIONS,
+                   szSpecialPermissions,
+                   sizeof(szSpecialPermissions) / sizeof(szSpecialPermissions[0])))
+    {
+        /* add the special permissions check item */
+        sp->SpecialPermCheckIndex = (INT)SendMessage(sp->hAceCheckList,
+                                                     CLM_ADDITEM,
+                                                     (WPARAM)SpecialPermissionsMask,
+                                                     (LPARAM)szSpecialPermissions);
+        if (sp->SpecialPermCheckIndex != -1)
+        {
+            SendMessage(sp->hAceCheckList,
+                        CLM_SETITEMSTATE,
+                        (WPARAM)sp->SpecialPermCheckIndex,
+                        CIS_ALLOWDISABLED | CIS_DENYDISABLED | CIS_NONE);
+        }
+    }
+}
+
+static VOID
+ResizeControls(IN PSECURITY_PAGE sp,
+               IN INT Width,
+               IN INT Height)
+{
+    HWND hWndAllow, hWndDeny;
+    RECT rcControl, rcControl2, rcControl3, rcWnd;
+    INT cxWidth, cxEdge, btnSpacing;
+    POINT pt, pt2;
+    HDWP dwp;
+    INT nControls = 7;
+    LVCOLUMN lvc;
+    
+    hWndAllow = GetDlgItem(sp->hWnd,
+                           IDC_LABEL_ALLOW);
+    hWndDeny = GetDlgItem(sp->hWnd,
+                          IDC_LABEL_DENY);
+    
+    GetWindowRect(sp->hWnd,
+                  &rcWnd);
+
+    cxEdge = GetSystemMetrics(SM_CXEDGE);
+    
+    /* use the left margin of the principal list view control for all control
+       margins */
+    pt.x = 0;
+    pt.y = 0;
+    MapWindowPoints(sp->hWndPrincipalsList,
+                    sp->hWnd,
+                    &pt,
+                    1);
+    cxWidth = Width - (2 * pt.x);
+    
+    if (sp->ObjectInfo.dwFlags & SI_ADVANCED)
+    {
+        nControls += 2;
+    }
+    
+    if ((dwp = BeginDeferWindowPos(nControls)))
+    {
+        /* resize the Principal list view */
+        GetWindowRect(sp->hWndPrincipalsList,
+                      &rcControl);
+        if (!(dwp = DeferWindowPos(dwp,
+                                   sp->hWndPrincipalsList,
+                                   NULL,
+                                   0,
+                                   0,
+                                   cxWidth,
+                                   rcControl.bottom - rcControl.top,
+                                   SWP_NOMOVE | SWP_NOZORDER)))
+        {
+            goto EndDeferWnds;
+        }
+
+        /* move the Add Principal button */
+        GetWindowRect(sp->hBtnAdd,
+                      &rcControl);
+        GetWindowRect(sp->hBtnRemove,
+                      &rcControl2);
+        btnSpacing = rcControl2.left - rcControl.right;
+        pt2.x = 0;
+        pt2.y = 0;
+        MapWindowPoints(sp->hBtnAdd,
+                        sp->hWnd,
+                        &pt2,
+                        1);
+        if (!(dwp = DeferWindowPos(dwp,
+                                   sp->hBtnAdd,
+                                   NULL,
+                                   pt.x + cxWidth - (rcControl2.right - rcControl2.left) -
+                                       (rcControl.right - rcControl.left) -
+                                       btnSpacing - cxEdge,
+                                   pt2.y,
+                                   0,
+                                   0,
+                                   SWP_NOSIZE | SWP_NOZORDER)))
+        {
+            goto EndDeferWnds;
+        }
+
+        /* move the Delete Principal button */
+        pt2.x = 0;
+        pt2.y = 0;
+        MapWindowPoints(sp->hBtnRemove,
+                        sp->hWnd,
+                        &pt2,
+                        1);
+        if (!(dwp = DeferWindowPos(dwp,
+                                   sp->hBtnRemove,
+                                   NULL,
+                                   pt.x + cxWidth - (rcControl2.right - rcControl2.left) - cxEdge,
+                                   pt2.y,
+                                   0,
+                                   0,
+                                   SWP_NOSIZE | SWP_NOZORDER)))
+        {
+            goto EndDeferWnds;
+        }
+
+        /* move the Permissions For label */
+        GetWindowRect(hWndAllow,
+                      &rcControl);
+        GetWindowRect(hWndDeny,
+                      &rcControl2);
+        GetWindowRect(sp->hPermissionsForLabel,
+                      &rcControl3);
+        pt2.x = 0;
+        pt2.y = 0;
+        MapWindowPoints(sp->hPermissionsForLabel,
+                        sp->hWnd,
+                        &pt2,
+                        1);
+        if (!(dwp = DeferWindowPos(dwp,
+                                   sp->hPermissionsForLabel,
+                                   NULL,
+                                   0,
+                                   0,
+                                   cxWidth - (rcControl2.right - rcControl2.left) -
+                                       (rcControl.right - rcControl.left) -
+                                       (2 * btnSpacing) - cxEdge,
+                                   rcControl3.bottom - rcControl3.top,
+                                   SWP_NOMOVE | SWP_NOZORDER)))
+        {
+            goto EndDeferWnds;
+        }
+
+        /* move the Allow label */
+        pt2.x = 0;
+        pt2.y = 0;
+        MapWindowPoints(hWndAllow,
+                        sp->hWnd,
+                        &pt2,
+                        1);
+        if (!(dwp = DeferWindowPos(dwp,
+                                   hWndAllow,
+                                   NULL,
+                                   cxWidth - (rcControl2.right - rcControl2.left) -
+                                       (rcControl.right - rcControl.left) -
+                                       btnSpacing - cxEdge,
+                                   pt2.y,
+                                   0,
+                                   0,
+                                   SWP_NOSIZE | SWP_NOZORDER)))
+        {
+            goto EndDeferWnds;
+        }
+
+        /* move the Deny label */
+        pt2.x = 0;
+        pt2.y = 0;
+        MapWindowPoints(hWndDeny,
+                        sp->hWnd,
+                        &pt2,
+                        1);
+        if (!(dwp = DeferWindowPos(dwp,
+                                   hWndDeny,
+                                   NULL,
+                                   cxWidth - (rcControl2.right - rcControl2.left) - cxEdge,
+                                   pt2.y,
+                                   0,
+                                   0,
+                                   SWP_NOSIZE | SWP_NOZORDER)))
+        {
+            goto EndDeferWnds;
+        }
+
+        /* resize the Permissions check list box */
+        GetWindowRect(sp->hAceCheckList,
+                      &rcControl);
+        GetWindowRect(sp->hBtnAdvanced,
+                      &rcControl2);
+        GetWindowRect(GetDlgItem(sp->hWnd,
+                                 IDC_LABEL_ADVANCED),
+                      &rcControl3);
+        if (!(dwp = DeferWindowPos(dwp,
+                                   sp->hAceCheckList,
+                                   NULL,
+                                   0,
+                                   0,
+                                   cxWidth,
+                                   ((sp->ObjectInfo.dwFlags & SI_ADVANCED) ?
+                                       Height - (rcControl.top - rcWnd.top) -
+                                           (rcControl3.bottom - rcControl3.top) - pt.x - btnSpacing :
+                                       Height - (rcControl.top - rcWnd.top) - pt.x),
+                                   SWP_NOMOVE | SWP_NOZORDER)))
+        {
+            goto EndDeferWnds;
+        }
+
+        if (sp->ObjectInfo.dwFlags & SI_ADVANCED)
+        {
+            /* move and resize the Advanced label */
+            if (!(dwp = DeferWindowPos(dwp,
+                                       GetDlgItem(sp->hWnd,
+                                                  IDC_LABEL_ADVANCED),
+                                       NULL,
+                                       pt.x,
+                                       Height - (rcControl3.bottom - rcControl3.top) - pt.x,
+                                       cxWidth - (rcControl2.right - rcControl2.left) - cxEdge,
+                                       rcControl3.bottom - rcControl3.top,
+                                       SWP_NOZORDER)))
+            {
+                goto EndDeferWnds;
+            }
+
+            /* move and resize the Advanced button */
+            if (!(dwp = DeferWindowPos(dwp,
+                                       sp->hBtnAdvanced,
+                                       NULL,
+                                       cxWidth - (rcControl2.right - rcControl2.left) + pt.x,
+                                       Height - (rcControl2.bottom - rcControl2.top) - pt.x,
+                                       0,
+                                       0,
+                                       SWP_NOSIZE | SWP_NOZORDER)))
+            {
+                goto EndDeferWnds;
+            }
+        }
+
+        EndDeferWindowPos(dwp);
+    }
+
+EndDeferWnds:
+    /* update the width of the principal list view column */
+    GetClientRect(sp->hWndPrincipalsList,
+                  &rcControl);
+    lvc.mask = LVCF_WIDTH;
+    lvc.cx = rcControl.right;
+    ListView_SetColumn(sp->hWndPrincipalsList,
+                       0,
+                       &lvc);
+
+    /* calculate the columns of the allow/deny checkboxes */
+    SetAceCheckListColumns(sp->hAceCheckList,
+                           CLB_ALLOW,
+                           hWndAllow);
+    SetAceCheckListColumns(sp->hAceCheckList,
+                           CLB_DENY,
+                           hWndDeny);
+}
+
+static PACE_HEADER
+BuildDefaultPrincipalAce(IN PSECURITY_PAGE sp,
+                         IN PSID pSid)
+{
+    PACCESS_ALLOWED_ACE Ace;
+    DWORD SidLen;
+    WORD AceSize;
+
+    SidLen = GetLengthSid(pSid);
+    AceSize = sizeof(ACCESS_ALLOWED_ACE) + (WORD)SidLen - sizeof(DWORD);
+    Ace = HeapAlloc(GetProcessHeap(),
+                    0,
+                    AceSize);
+    if (Ace != NULL)
+    {
+        Ace->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
+        Ace->Header.AceFlags = 0; /* FIXME */
+        Ace->Header.AceSize = AceSize;
+        Ace->Mask = sp->DefaultAccess.mask;
+
+        if (CopySid(SidLen,
+                    (PSID)&Ace->SidStart,
+                    pSid))
+        {
+            return &Ace->Header;
+        }
+
+        HeapFree(GetProcessHeap(),
+                 0,
+                 Ace);
+    }
+
+    return NULL;
+}
+
+static BOOL
+AddSelectedPrincipal(IN IDsObjectPicker *pDsObjectPicker,
+                     IN HWND hwndParent  OPTIONAL,
+                     IN PSID pSid,
+                     IN PVOID Context  OPTIONAL)
+{
+    PACE_HEADER AceHeader;
+    PSECURITY_PAGE sp = (PSECURITY_PAGE)Context;
+    
+    AceHeader = BuildDefaultPrincipalAce(sp,
+                                         pSid);
+    if (AceHeader != NULL)
+    {
+        PPRINCIPAL_LISTITEM PrincipalListItem;
+        BOOL LookupDeferred;
+
+        PrincipalListItem = AddPrincipalToList(sp,
+                                               pSid,
+                                               AceHeader,
+                                               &LookupDeferred);
+
+        if (PrincipalListItem != NULL && LookupDeferred)
+        {
+            AddPrincipalListEntry(sp,
+                                  PrincipalListItem,
+                                  -1,
+                                  FALSE);
+        }
+
+        HeapFree(GetProcessHeap(),
+                 0,
+                 AceHeader);
+    }
+
+    return TRUE;
+}
 
 static INT_PTR CALLBACK
 SecurityPageProc(IN HWND hwndDlg,
@@ -468,90 +1117,232 @@ SecurityPageProc(IN HWND hwndDlg,
                  IN LPARAM lParam)
 {
     PSECURITY_PAGE sp;
+    INT_PTR Ret = FALSE;
 
-    switch(uMsg)
+    sp = (PSECURITY_PAGE)GetWindowLongPtr(hwndDlg,
+                                          DWL_USER);
+    if (sp != NULL || uMsg == WM_INITDIALOG)
     {
-        case WM_NOTIFY:
+        switch (uMsg)
         {
-            NMHDR *pnmh = (NMHDR*)lParam;
-            if (pnmh->idFrom == IDC_ACELIST)
+            case WM_NOTIFY:
             {
-                sp = (PSECURITY_PAGE)GetWindowLongPtr(hwndDlg,
-                                                      DWL_USER);
-                if (sp != NULL)
+                NMHDR *pnmh = (NMHDR*)lParam;
+
+                if (pnmh->hwndFrom == sp->hWndPrincipalsList)
                 {
-                    switch(pnmh->code)
+                    switch (pnmh->code)
                     {
                         case LVN_ITEMCHANGED:
                         {
-                            UpdateControlStates(sp);
+                            LPNMLISTVIEW pnmv = (LPNMLISTVIEW)lParam;
+                            
+                            if ((pnmv->uChanged & LVIF_STATE) &&
+                                ((pnmv->uOldState & (LVIS_FOCUSED | LVIS_SELECTED)) ||
+                                 (pnmv->uNewState & (LVIS_FOCUSED | LVIS_SELECTED))))
+                            {
+                                UpdateControlStates(sp);
+                            }
+                            break;
+                        }
+                    }
+                }
+                else if (pnmh->hwndFrom == sp->hAceCheckList)
+                {
+                    switch (pnmh->code)
+                    {
+                        case CLN_CHANGINGITEMCHECKBOX:
+                        {
+                            PNMCHANGEITEMCHECKBOX pcicb = (PNMCHANGEITEMCHECKBOX)lParam;
+                            
+                            /* make sure only one of both checkboxes is only checked
+                               at the same time */
+                            if (pcicb->Checked)
+                            {
+                                pcicb->NewState &= ~((pcicb->CheckBox != CLB_DENY) ? CIS_DENY : CIS_ALLOW);
+                            }
                             break;
                         }
                     }
                 }
+                else if (pnmh->hwndFrom == sp->hWnd)
+                {
+                    switch(pnmh->code)
+                    {
+                        case SIDN_LOOKUPSUCCEEDED:
+                        {
+                            PSIDLOOKUPNOTIFYINFO LookupInfo = CONTAINING_RECORD(lParam,
+                                                                                SIDLOOKUPNOTIFYINFO,
+                                                                                nmh);
+
+                            /* a SID lookup succeeded, update the information */
+                            UpdatePrincipalInfo(sp,
+                                                LookupInfo);
+                            break;
+                        }
+                    }
+                }
+                break;
             }
-            break;
-        }
-        
-        case WM_INITDIALOG:
-        {
-            sp = (PSECURITY_PAGE)((LPPROPSHEETPAGE)lParam)->lParam;
-            if(sp != NULL)
+            
+            case WM_COMMAND:
             {
-                LV_COLUMN lvc;
-                RECT rcLvClient;
-                
-                sp->hWnd = hwndDlg;
-                sp->hWndAceList = GetDlgItem(hwndDlg, IDC_ACELIST);
-                sp->hBtnRemove = GetDlgItem(hwndDlg, IDC_ACELIST_REMOVE);
-                sp->hAceCheckList = GetDlgItem(hwndDlg, IDC_ACE_CHECKLIST);
-
-                /* save the pointer to the structure */
-                SetWindowLongPtr(hwndDlg,
-                                 DWL_USER,
-                                 (DWORD_PTR)sp);
-
-                sp->hiUsrs = ImageList_LoadBitmap(hDllInstance,
-                                                  MAKEINTRESOURCE(IDB_USRGRPIMAGES),
-                                                  16,
-                                                  3,
-                                                  0);
-
-                /* setup the listview control */
-                ListView_SetExtendedListViewStyleEx(sp->hWndAceList,
-                                                    LVS_EX_FULLROWSELECT,
-                                                    LVS_EX_FULLROWSELECT);
-                ListView_SetImageList(sp->hWndAceList,
-                                      sp->hiUsrs,
-                                      LVSIL_SMALL);
-
-                GetClientRect(sp->hWndAceList, &rcLvClient);
-                
-                /* add a column to the list view */
-                lvc.mask = LVCF_FMT | LVCF_WIDTH;
-                lvc.fmt = LVCFMT_LEFT;
-                lvc.cx = rcLvClient.right;
-                ListView_InsertColumn(sp->hWndAceList, 0, &lvc);
-
-                FillUsersGroupsList(sp);
-                
-                ListViewSelectItem(sp->hWndAceList,
-                                   0);
-
-                /* calculate the columns of the allow/deny checkboxes */
-                SetAceCheckListColumns(sp->hAceCheckList,
-                                       CLB_ALLOW,
-                                       GetDlgItem(hwndDlg, IDC_LABEL_ALLOW));
-                SetAceCheckListColumns(sp->hAceCheckList,
-                                       CLB_DENY,
-                                       GetDlgItem(hwndDlg, IDC_LABEL_DENY));
-
-                /* FIXME - hide controls in case the flags aren't present */
+                switch (LOWORD(wParam))
+                {
+                    case IDC_ADD_PRINCIPAL:
+                    {
+                        HRESULT hRet;
+                        
+                        hRet = InitializeObjectPicker(sp->ServerName,
+                                                      &sp->ObjectInfo,
+                                                      &sp->pDsObjectPicker);
+                        if (SUCCEEDED(hRet))
+                        {
+                            hRet = InvokeObjectPickerDialog(sp->pDsObjectPicker,
+                                                            hwndDlg,
+                                                            AddSelectedPrincipal,
+                                                            sp);
+                            if (FAILED(hRet))
+                            {
+                                MessageBox(hwndDlg, L"InvokeObjectPickerDialog failed!\n", NULL, 0);
+                            }
+                            
+                            /* delete the instance */
+                            FreeObjectPicker(sp->pDsObjectPicker);
+                        }
+                        else
+                        {
+                            MessageBox(hwndDlg, L"InitializeObjectPicker failed!\n", NULL, 0);
+                        }
+                        break;
+                    }
+
+                    case IDC_REMOVE_PRINCIPAL:
+                    {
+                        PPRINCIPAL_LISTITEM SelectedPrincipal;
+
+                        SelectedPrincipal = (PPRINCIPAL_LISTITEM)ListViewGetSelectedItemData(sp->hWndPrincipalsList);
+                        if (SelectedPrincipal != NULL)
+                        {
+                            /* FIXME */
+                        }
+                        break;
+                    }
+                }
+                break;
+            }
+            
+            case WM_SIZE:
+            {
+                ResizeControls(sp,
+                               (INT)LOWORD(lParam),
+                               (INT)HIWORD(lParam));
+                break;
+            }
+            
+            case WM_INITDIALOG:
+            {
+                sp = (PSECURITY_PAGE)((LPPROPSHEETPAGE)lParam)->lParam;
+                if(sp != NULL)
+                {
+                    LV_COLUMN lvc;
+                    RECT rcLvClient;
+                    
+                    sp->hWnd = hwndDlg;
+                    sp->hWndPrincipalsList = GetDlgItem(hwndDlg, IDC_PRINCIPALS);
+                    sp->hBtnAdd = GetDlgItem(hwndDlg, IDC_ADD_PRINCIPAL);
+                    sp->hBtnRemove = GetDlgItem(hwndDlg, IDC_REMOVE_PRINCIPAL);
+                    sp->hBtnAdvanced = GetDlgItem(hwndDlg, IDC_ADVANCED);
+                    sp->hAceCheckList = GetDlgItem(hwndDlg, IDC_ACE_CHECKLIST);
+                    sp->hPermissionsForLabel = GetDlgItem(hwndDlg, IDC_LABEL_PERMISSIONS_FOR);
+                    
+                    sp->SpecialPermCheckIndex = -1;
+
+                    /* save the pointer to the structure */
+                    SetWindowLongPtr(hwndDlg,
+                                     DWL_USER,
+                                     (DWORD_PTR)sp);
+
+                    ListView_SetExtendedListViewStyleEx(sp->hWndPrincipalsList,
+                                                        LVS_EX_FULLROWSELECT,
+                                                        LVS_EX_FULLROWSELECT);
+
+                    sp->hiPrincipals = ImageList_LoadBitmap(hDllInstance,
+                                                            MAKEINTRESOURCE(IDB_USRGRPIMAGES),
+                                                            16,
+                                                            3,
+                                                            RGB(255,
+                                                                0,
+                                                                255));
+
+                    /* setup the listview control */
+                    if (sp->hiPrincipals != NULL)
+                    {
+                        ListView_SetImageList(sp->hWndPrincipalsList,
+                                              sp->hiPrincipals,
+                                              LVSIL_SMALL);
+                    }
+
+                    GetClientRect(sp->hWndPrincipalsList,
+                                  &rcLvClient);
+                    
+                    /* add a column to the list view */
+                    lvc.mask = LVCF_FMT | LVCF_WIDTH;
+                    lvc.fmt = LVCFMT_LEFT;
+                    lvc.cx = rcLvClient.right;
+                    ListView_InsertColumn(sp->hWndPrincipalsList,
+                                          0,
+                                          &lvc);
+                    
+                    ReloadPrincipalsList(sp);
+                    
+                    ListViewSelectItem(sp->hWndPrincipalsList,
+                                       0);
+
+                    /* calculate the columns of the allow/deny checkboxes */
+                    SetAceCheckListColumns(sp->hAceCheckList,
+                                           CLB_ALLOW,
+                                           GetDlgItem(hwndDlg, IDC_LABEL_ALLOW));
+                    SetAceCheckListColumns(sp->hAceCheckList,
+                                           CLB_DENY,
+                                           GetDlgItem(hwndDlg, IDC_LABEL_DENY));
+
+                    LoadPermissionsList(sp,
+                                        NULL,
+                                        SI_ACCESS_GENERAL |
+                                        ((sp->ObjectInfo.dwFlags & SI_CONTAINER) ? SI_ACCESS_CONTAINER : 0),
+                                        &sp->DefaultAccess);
+
+                    /* hide controls in case the flags aren't present */
+                    if (sp->ObjectInfo.dwFlags & SI_ADVANCED)
+                    {
+                        /* editing the permissions is least the user can do when
+                           the advanced button is showed */
+                        sp->ObjectInfo.dwFlags |= SI_EDIT_PERMS;
+                    }
+                    else
+                    {
+                        ShowWindow(sp->hBtnAdvanced,
+                                   SW_HIDE);
+                        ShowWindow(GetDlgItem(hwndDlg, IDC_LABEL_ADVANCED),
+                                   SW_HIDE);
+                    }
+                    
+                    /* enable quicksearch for the permissions checklist control */
+                    SendMessage(sp->hAceCheckList,
+                                CLM_ENABLEQUICKSEARCH,
+                                TRUE,
+                                0);
+
+                    UpdateControlStates(sp);
+                }
+
+                Ret = TRUE;
+                break;
             }
-            break;
         }
     }
-    return 0;
+    return Ret;
 }
 
 
@@ -564,12 +1355,14 @@ HPROPSHEETPAGE
 WINAPI
 CreateSecurityPage(IN LPSECURITYINFO psi)
 {
-    PROPSHEETPAGE psp;
+    PROPSHEETPAGE psp = {0};
     PSECURITY_PAGE sPage;
-    SI_OBJECT_INFO ObjectInfo;
+    SI_OBJECT_INFO ObjectInfo = {0};
+    HANDLE SidCacheMgr;
+    LPCWSTR SystemName = NULL;
     HRESULT hRet;
 
-    if(psi == NULL)
+    if (psi == NULL)
     {
         SetLastError(ERROR_INVALID_PARAMETER);
 
@@ -577,20 +1370,40 @@ CreateSecurityPage(IN LPSECURITYINFO psi)
         return NULL;
     }
 
-    /* get the object information from the server interface */
-    hRet = psi->lpVtbl->GetObjectInformation(psi, &ObjectInfo);
+    /* get the object information from the server. Zero the structure before
+       because some applications seem to return SUCCESS but only seem to set the
+       fields they care about. */
+    hRet = psi->lpVtbl->GetObjectInformation(psi,
+                                             &ObjectInfo);
 
-    if(FAILED(hRet))
+    if (FAILED(hRet))
     {
         SetLastError(hRet);
 
         DPRINT("CreateSecurityPage() failed! Failed to query the object information!\n");
         return NULL;
     }
-    
-    if (!RegisterCheckListControl(hDllInstance))
+
+    if ((ObjectInfo.dwFlags & SI_SERVER_IS_DC) &&
+         ObjectInfo.pszServerName != NULL &&
+         ObjectInfo.pszServerName[0] != L'\0')
     {
-        DPRINT("Registering the CHECKLIST_ACLUI class failed!\n");
+        SystemName = ObjectInfo.pszServerName;
+    }
+
+    SidCacheMgr = CreateSidCacheMgr(GetProcessHeap(),
+                                    SystemName);
+    if (SidCacheMgr == NULL)
+    {
+        DPRINT("Creating the SID cache failed!\n");
+        return NULL;
+    }
+
+    hRet = CoInitialize(NULL);
+    if (FAILED(hRet))
+    {
+        DestroySidCacheMgr(SidCacheMgr);
+        DPRINT("CoInitialize failed!\n");
         return NULL;
     }
     
@@ -599,13 +1412,19 @@ CreateSecurityPage(IN LPSECURITYINFO psi)
                       sizeof(SECURITY_PAGE));
     if (sPage == NULL)
     {
+        DestroySidCacheMgr(SidCacheMgr);
+        CoUninitialize();
+
         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
         
         DPRINT("Not enough memory to allocate a SECURITY_PAGE!\n");
         return NULL;
     }
+
     sPage->psi = psi;
     sPage->ObjectInfo = ObjectInfo;
+    sPage->ServerName = SystemName;
+    sPage->SidCacheMgr = SidCacheMgr;
 
     psp.dwSize = sizeof(PROPSHEETPAGE);
     psp.dwFlags = PSP_USECALLBACK;
@@ -615,12 +1434,18 @@ CreateSecurityPage(IN LPSECURITYINFO psi)
     psp.lParam = (LPARAM)sPage;
     psp.pfnCallback = SecurityPageCallback;
 
-    if((ObjectInfo.dwFlags & SI_PAGE_TITLE) &&
-       ObjectInfo.pszPageTitle != NULL && ObjectInfo.pszPageTitle[0] != L'\0')
+    if (ObjectInfo.dwFlags & SI_PAGE_TITLE)
     {
-        /* Set the page title if the flag is present and the string isn't empty */
         psp.pszTitle = ObjectInfo.pszPageTitle;
-        psp.dwFlags |= PSP_USETITLE;
+
+        if (psp.pszTitle != NULL)
+        {
+            psp.dwFlags |= PSP_USETITLE;
+        }
+    }
+    else
+    {
+        psp.pszTitle = NULL;
     }
     
     /* NOTE: the SECURITY_PAGE structure will be freed by the property page
@@ -641,13 +1466,13 @@ EditSecurity(IN HWND hwndOwner,
              IN LPSECURITYINFO psi)
 {
     HRESULT hRet;
-    SI_OBJECT_INFO ObjectInfo;
+    SI_OBJECT_INFO ObjectInfo = {0};
     PROPSHEETHEADER psh;
     HPROPSHEETPAGE hPages[1];
-    LPWSTR lpCaption;
+    LPWSTR lpCaption = NULL;
     BOOL Ret;
 
-    if(psi == NULL)
+    if (psi == NULL)
     {
         SetLastError(ERROR_INVALID_PARAMETER);
 
@@ -655,10 +1480,13 @@ EditSecurity(IN HWND hwndOwner,
         return FALSE;
     }
 
-    /* get the object information from the server interface */
-    hRet = psi->lpVtbl->GetObjectInformation(psi, &ObjectInfo);
+    /* get the object information from the server. Zero the structure before
+       because some applications seem to return SUCCESS but only seem to set the
+       fields they care about. */
+    hRet = psi->lpVtbl->GetObjectInformation(psi,
+                                             &ObjectInfo);
 
-    if(FAILED(hRet))
+    if (FAILED(hRet))
     {
         SetLastError(hRet);
 
@@ -668,7 +1496,7 @@ EditSecurity(IN HWND hwndOwner,
 
     /* create the page */
     hPages[0] = CreateSecurityPage(psi);
-    if(hPages[0] == NULL)
+    if (hPages[0] == NULL)
     {
         DPRINT("CreateSecurityPage(), couldn't create property sheet!\n");
         return FALSE;
@@ -678,23 +1506,20 @@ EditSecurity(IN HWND hwndOwner,
     psh.dwFlags = PSH_DEFAULT;
     psh.hwndParent = hwndOwner;
     psh.hInstance = hDllInstance;
-    if((ObjectInfo.dwFlags & SI_PAGE_TITLE) &&
-       ObjectInfo.pszPageTitle != NULL && ObjectInfo.pszPageTitle[0] != L'\0')
+
+    /* Set the page title to the object name, make sure the format string
+       has "%1" NOT "%s" because it uses FormatMessage() to automatically
+       allocate the right amount of memory. */
+    if (LoadAndFormatString(hDllInstance,
+                            IDS_PSP_TITLE,
+                            &lpCaption,
+                            ObjectInfo.pszObjectName))
     {
-        /* Set the page title if the flag is present and the string isn't empty */
-        psh.pszCaption = ObjectInfo.pszPageTitle;
-        lpCaption = NULL;
+        psh.pszCaption = lpCaption;
     }
     else
     {
-        /* Set the page title to the object name, make sure the format string
-           has "%1" NOT "%s" because it uses FormatMessage() to automatically
-           allocate the right amount of memory. */
-        LoadAndFormatString(hDllInstance,
-                            IDS_PSP_TITLE,
-                            &lpCaption,
-                            ObjectInfo.pszObjectName);
-        psh.pszCaption = lpCaption;
+        psh.pszCaption = ObjectInfo.pszObjectName;
     }
 
     psh.nPages = sizeof(hPages) / sizeof(HPROPSHEETPAGE);
@@ -703,7 +1528,7 @@ EditSecurity(IN HWND hwndOwner,
 
     Ret = (PropertySheet(&psh) != -1);
 
-    if(lpCaption != NULL)
+    if (lpCaption != NULL)
     {
         LocalFree((HLOCAL)lpCaption);
     }
@@ -711,7 +1536,8 @@ EditSecurity(IN HWND hwndOwner,
     return Ret;
 }
 
-BOOL STDCALL
+BOOL
+WINAPI
 DllMain(IN HINSTANCE hinstDLL,
         IN DWORD dwReason,
         IN LPVOID lpvReserved)
@@ -720,12 +1546,21 @@ DllMain(IN HINSTANCE hinstDLL,
     {
         case DLL_PROCESS_ATTACH:
             hDllInstance = hinstDLL;
+
+            DisableThreadLibraryCalls(hinstDLL);
+
+            if (!RegisterCheckListControl(hinstDLL))
+            {
+                DPRINT("Registering the CHECKLIST_ACLUI class failed!\n");
+                return FALSE;
+            }
             break;
-        case DLL_THREAD_ATTACH:
-        case DLL_THREAD_DETACH:
+
         case DLL_PROCESS_DETACH:
+            UnregisterCheckListControl();
             break;
     }
+
     return TRUE;
 }