perform asynchronous SID lookups
authorThomas Bluemel <thomas@reactsoft.com>
Sun, 25 Dec 2005 21:20:13 +0000 (21:20 +0000)
committerThomas Bluemel <thomas@reactsoft.com>
Sun, 25 Dec 2005 21:20:13 +0000 (21:20 +0000)
svn path=/trunk/; revision=20332

reactos/lib/aclui/aclui.c
reactos/lib/aclui/aclui.xml
reactos/lib/aclui/aclui_En.rc
reactos/lib/aclui/checklist.c
reactos/lib/aclui/guid.c
reactos/lib/aclui/misc.c
reactos/lib/aclui/precomp.h
reactos/lib/aclui/resource.h
reactos/lib/aclui/sidcache.c [new file with mode: 0644]

index 89d2960..d674edf 100644 (file)
  */
 #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)
 {
@@ -77,6 +88,8 @@ DestroySecurityPage(IN PSECURITY_PAGE sp)
         ImageList_Destroy(sp->hiPrincipals);
     }
 
+    DestroySidCacheMgr(sp->SidCacheMgr);
+
     HeapFree(GetProcessHeap(),
              0,
              sp);
@@ -85,7 +98,8 @@ DestroySecurityPage(IN PSECURITY_PAGE sp)
 }
 
 static VOID
-FreePrincipalsList(IN PPRINCIPAL_LISTITEM *PrincipalsListHead)
+FreePrincipalsList(IN PSECURITY_PAGE sp,
+                   IN PPRINCIPAL_LISTITEM *PrincipalsListHead)
 {
     PPRINCIPAL_LISTITEM CurItem, NextItem;
     PACE_ENTRY AceEntry, NextAceEntry;
@@ -105,6 +119,12 @@ FreePrincipalsList(IN PPRINCIPAL_LISTITEM *PrincipalsListHead)
         }
 
         /* free the SID string if present */
+        if (CurItem->SidReqResult != NULL)
+        {
+            DereferenceSidReqResult(sp->SidCacheMgr,
+                                    CurItem->SidReqResult);
+        }
+
         if (CurItem->DisplayString != NULL)
         {
             LocalFree((HLOCAL)CurItem->DisplayString);
@@ -179,43 +199,50 @@ FindSidInPrincipalsListAddAce(IN PPRINCIPAL_LISTITEM PrincipalsListHead,
     return NULL;
 }
 
-static BOOL
+static VOID
+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)
+                   IN PACE_HEADER AceHeader,
+                   OUT BOOL *LookupDeferred  OPTIONAL)
 {
-    PPRINCIPAL_LISTITEM PrincipalListItem = NULL;
-    PACE_ENTRY AceEntry = NULL;
-    BOOL Ret = FALSE;
+    PPRINCIPAL_LISTITEM PrincipalListItem = NULL, *PrincipalLink;
+    PACE_ENTRY AceEntry;
+    BOOL Deferred = FALSE;
 
     if (!FindSidInPrincipalsListAddAce(sp->PrincipalsListHead,
                                        Sid,
                                        AceHeader))
     {
-        DWORD SidLength, AccountNameSize, DomainNameSize;
-        SID_NAME_USE SidNameUse;
-        DWORD LookupResult;
-        PPRINCIPAL_LISTITEM PrincipalListItem, *PrincipalLink;
-
-        AccountNameSize = 0;
-        DomainNameSize = 0;
-
-        /* calculate the size of the buffer we need to calculate */
-        if (!LookupAccountSid(sp->ServerName,
-                              Sid,
-                              NULL,
-                              &AccountNameSize,
-                              NULL,
-                              &DomainNameSize,
-                              &SidNameUse))
-        {
-            LookupResult = GetLastError();
-            if (LookupResult != ERROR_NONE_MAPPED &&
-                LookupResult != ERROR_INSUFFICIENT_BUFFER)
-            {
-                goto Cleanup;
-            }
-        }
+        DWORD SidLength;
         
         PrincipalLink = &sp->PrincipalsListHead;
         while (*PrincipalLink != NULL)
@@ -228,232 +255,215 @@ AddPrincipalToList(IN PSECURITY_PAGE sp,
         /* allocate the principal */
         PrincipalListItem = HeapAlloc(GetProcessHeap(),
                                       0,
-                                      sizeof(PRINCIPAL_LISTITEM) + SidLength +
-                                          ((AccountNameSize + DomainNameSize) * sizeof(WCHAR)));
+                                      sizeof(PRINCIPAL_LISTITEM) + SidLength);
         if (PrincipalListItem != NULL)
         {
-            PrincipalListItem->AccountName = (LPWSTR)((ULONG_PTR)(PrincipalListItem + 1) + SidLength);
-            PrincipalListItem->DomainName = PrincipalListItem->AccountName + AccountNameSize;
+            PrincipalListItem->DisplayString = NULL;
+            PrincipalListItem->SidReqResult = NULL;
 
             CopySid(SidLength,
                     (PSID)(PrincipalListItem + 1),
                     Sid);
 
-            LookupResult = ERROR_SUCCESS;
-            if (!LookupAccountSid(sp->ServerName,
-                                  Sid,
-                                  PrincipalListItem->AccountName,
-                                  &AccountNameSize,
-                                  PrincipalListItem->DomainName,
-                                  &DomainNameSize,
-                                  &SidNameUse))
-            {
-                LookupResult = GetLastError();
-                if (LookupResult != ERROR_NONE_MAPPED)
-                {
-                    goto Cleanup;
-                }
-            }
-
-            if (AccountNameSize == 0)
-            {
-                PrincipalListItem->AccountName = NULL;
-            }
-            if (DomainNameSize == 0)
-            {
-                PrincipalListItem->DomainName = NULL;
-            }
-
             /* allocate some memory for the ACE and copy it */
             AceEntry = HeapAlloc(GetProcessHeap(),
                                  0,
                                  sizeof(ACE_ENTRY) + AceHeader->AceSize);
-            if (AceEntry == NULL)
+            if (AceEntry != NULL)
             {
-                goto Cleanup;
-            }
-            AceEntry->Next = NULL;
-            CopyMemory(AceEntry + 1,
-                       AceHeader,
-                       AceHeader->AceSize);
+                AceEntry->Next = NULL;
+                CopyMemory(AceEntry + 1,
+                           AceHeader,
+                           AceHeader->AceSize);
 
-            /* add the ACE to the list */
-            PrincipalListItem->ACEs = AceEntry;
+                /* add the ACE to the list */
+                PrincipalListItem->ACEs = AceEntry;
 
-            PrincipalListItem->Next = NULL;
-            Ret = TRUE;
+                PrincipalListItem->Next = NULL;
 
-            if (LookupResult == ERROR_NONE_MAPPED)
-            {
-                if (!ConvertSidToStringSid(Sid,
-                                           &PrincipalListItem->DisplayString))
-                {
-                    PrincipalListItem->DisplayString = NULL;
-                }
+                /* append item to the principals list */
+                *PrincipalLink = PrincipalListItem;
+
+                /* lookup the SID now */
+                Deferred = !LookupSidCache(sp->SidCacheMgr,
+                                           Sid,
+                                           SidLookupCompletion,
+                                           sp);
             }
             else
             {
-                LSA_HANDLE LsaHandle;
-                NTSTATUS Status;
+                HeapFree(GetProcessHeap(),
+                         0,
+                         PrincipalListItem);
+                PrincipalListItem = NULL;
+            }
+        }
+    }
 
-                PrincipalListItem->DisplayString = NULL;
+    if (PrincipalListItem != NULL && LookupDeferred != NULL)
+    {
+        *LookupDeferred = Deferred;
+    }
 
-                /* read the domain of the SID */
-                if (OpenLSAPolicyHandle(sp->ServerName,
-                                        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;
-                        }
+    return PrincipalListItem;
+}
 
-                        PrincipalListItem->SidNameUse = Names->Use;
+static LPWSTR
+GetPrincipalDisplayString(IN PPRINCIPAL_LISTITEM PrincipalListItem)
+{
+    LPWSTR lpDisplayString = NULL;
 
-                        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 */
-                                        PrincipalListItem->SidNameUse = SidTypeGroup;
-                                    }
-                                }
-                                /* fall through */
-
-                            case SidTypeUser:
-                            {
-                                if (Domain != NULL)
-                                {
-                                    SIZE_T Size = (AccountNameSize + DomainName->Length +
-                                                   Names->Name.Length + 6) * sizeof(WCHAR);
-                                    PrincipalListItem->DisplayString = (LPWSTR)LocalAlloc(LMEM_FIXED,
-                                                                                    Size);
-                                    if (PrincipalListItem->DisplayString != NULL)
-                                    {
-                                        WCHAR *s;
-
-                                        /* NOTE: LSA_UNICODE_STRINGs are not always NULL-terminated! */
-
-                                        wcscpy(PrincipalListItem->DisplayString,
-                                               PrincipalListItem->AccountName);
-                                        wcscat(PrincipalListItem->DisplayString,
-                                               L" (");
-                                        s = PrincipalListItem->DisplayString + wcslen(PrincipalListItem->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';
-                                    }
-                                    else
-                                    {
-                                        Ret = FALSE;
-                                        break;
-                                    }
-
-                                    /* mark the ace as a user unless it's a
-                                       BUILTIN account */
-                                    if (PolicyAccountDomainInfo == NULL)
-                                    {
-                                        PrincipalListItem->SidNameUse = SidTypeUser;
-                                    }
-                                }
-                                break;
-                            }
+    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);
+    }
 
-                            case SidTypeWellKnownGroup:
-                            {
-                                /* make the user believe this is a group */
-                                PrincipalListItem->SidNameUse = SidTypeGroup;
-                                break;
-                            }
+    return lpDisplayString;
+}
 
-                            default:
-                            {
-                                DPRINT("Unhandled SID type: 0x%x\n", Names->Use);
-                                break;
-                            }
-                        }
+static VOID
+CreatePrincipalListItem(OUT LVITEM *li,
+                        IN PSECURITY_PAGE sp,
+                        IN PPRINCIPAL_LISTITEM PrincipalListItem,
+                        IN INT Index,
+                        IN BOOL Selected)
+{
+    INT ImageIndex = 2;
 
-                        if (PolicyAccountDomainInfo != NULL)
-                        {
-                            LsaFreeMemory(PolicyAccountDomainInfo);
-                        }
+    if (PrincipalListItem->SidReqResult != NULL)
+    {
+        switch (PrincipalListItem->SidReqResult->SidNameUse)
+        {
+            case SidTypeUser:
+                ImageIndex = 0;
+                break;
+            case SidTypeWellKnownGroup:
+            case SidTypeGroup:
+                ImageIndex = 1;
+                break;
+            default:
+                break;
+        }
+    }
 
-                        LsaFreeMemory(ReferencedDomain);
-                        LsaFreeMemory(Names);
-                    }
-                    LsaClose(LsaHandle);
-                }
-            }
+    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;
+}
 
-            if (Ret)
-            {
-                /* append item to the principals list */
-                *PrincipalLink = 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);
 
-    if (!Ret)
+    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)
     {
-Cleanup:
-        if (PrincipalListItem != NULL)
-        {
-            if (PrincipalListItem->DisplayString != NULL)
-            {
-                LocalFree((HLOCAL)PrincipalListItem->DisplayString);
-            }
+        return wcscmp(Item1->DisplayString,
+                      Item2->DisplayString);
+    }
 
-            HeapFree(GetProcessHeap(),
-                     0,
-                     PrincipalListItem);
-        }
+    return 0;
+}
 
-        if (AceEntry != NULL)
-        {
-            HeapFree(GetProcessHeap(),
-                     0,
-                     AceEntry);
-        }
+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);
     }
 
-    return Ret;
+    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
@@ -465,7 +475,8 @@ ReloadPrincipalsList(IN PSECURITY_PAGE sp)
     HRESULT hRet;
 
     /* delete the cached ACL */
-    FreePrincipalsList(&sp->PrincipalsListHead);
+    FreePrincipalsList(sp,
+                       &sp->PrincipalsListHead);
 
     /* query the ACL */
     hRet = sp->psi->lpVtbl->GetSecurity(sp->psi,
@@ -493,11 +504,23 @@ ReloadPrincipalsList(IN PSECURITY_PAGE sp)
                            (LPVOID*)&AceHeader) &&
                     AceHeader != NULL)
                 {
+                    BOOL LookupDeferred;
+                    PPRINCIPAL_LISTITEM PrincipalListItem;
+
                     Sid = AceHeaderToSID(AceHeader);
 
-                    AddPrincipalToList(sp,
-                                       Sid,
-                                       AceHeader);
+                    PrincipalListItem = AddPrincipalToList(sp,
+                                                           Sid,
+                                                           AceHeader,
+                                                           &LookupDeferred);
+
+                    if (PrincipalListItem != NULL && LookupDeferred)
+                    {
+                        AddPrincipalListEntry(sp,
+                                              PrincipalListItem,
+                                              -1,
+                                              FALSE);
+                    }
                 }
             }
         }
@@ -505,74 +528,6 @@ ReloadPrincipalsList(IN PSECURITY_PAGE sp)
     }
 }
 
-static INT
-AddPrincipalListEntry(IN PSECURITY_PAGE sp,
-                      IN PPRINCIPAL_LISTITEM PrincipalListItem,
-                      IN INT Index,
-                      IN BOOL Selected)
-{
-    LVITEM li;
-
-    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 != NULL ?
-                  PrincipalListItem->DisplayString :
-                  PrincipalListItem->AccountName);
-
-    switch (PrincipalListItem->SidNameUse)
-    {
-        case SidTypeUser:
-            li.iImage = 0;
-            break;
-        case SidTypeGroup:
-            li.iImage = 1;
-            break;
-        default:
-            li.iImage = -1;
-            break;
-    }
-    li.lParam = (LPARAM)PrincipalListItem;
-
-    return ListView_InsertItem(sp->hWndPrincipalsList,
-                               &li);
-}
-
-static VOID
-FillPrincipalsList(IN PSECURITY_PAGE sp)
-{
-    LPARAM SelLParam;
-    PPRINCIPAL_LISTITEM CurItem;
-    RECT rcLvClient;
-
-    SelLParam = ListViewGetSelectedItemData(sp->hWndPrincipalsList);
-
-    DisableRedrawWindow(sp->hWndPrincipalsList);
-
-    ListView_DeleteAllItems(sp->hWndPrincipalsList);
-
-    for (CurItem = sp->PrincipalsListHead;
-         CurItem != NULL;
-         CurItem = CurItem->Next)
-    {
-        AddPrincipalListEntry(sp,
-                              CurItem,
-                              -1,
-                              (SelLParam == (LPARAM)CurItem));
-    }
-    
-    EnableRedrawWindow(sp->hWndPrincipalsList);
-    
-    GetClientRect(sp->hWndPrincipalsList,
-                  &rcLvClient);
-    
-    ListView_SetColumnWidth(sp->hWndPrincipalsList,
-                            0,
-                            rcLvClient.right);
-}
-
 static VOID
 UpdateControlStates(IN PSECURITY_PAGE sp)
 {
@@ -586,18 +541,22 @@ UpdateControlStates(IN PSECURITY_PAGE sp)
     if (Selected != NULL)
     {
         LPWSTR szLabel;
+        LPWSTR szDisplayString;
 
+        szDisplayString = GetPrincipalDisplayString(Selected);
         if (LoadAndFormatString(hDllInstance,
                                 IDS_PERMISSIONS_FOR,
                                 &szLabel,
-                                Selected->AccountName))
+                                szDisplayString))
         {
             SetWindowText(sp->hPermissionsForLabel,
                           szLabel);
 
             LocalFree((HLOCAL)szLabel);
         }
-        
+
+        LocalFree((HLOCAL)szDisplayString);
+
         /* FIXME - update the checkboxes */
     }
     else
@@ -620,6 +579,54 @@ UpdateControlStates(IN PSECURITY_PAGE sp)
     }
 }
 
+static void
+UpdatePrincipalInfo(IN PSECURITY_PAGE sp,
+                    IN PSIDLOOKUPNOTIFYINFO LookupInfo)
+{
+    PPRINCIPAL_LISTITEM CurItem;
+
+    for (CurItem = sp->PrincipalsListHead;
+         CurItem != NULL;
+         CurItem = CurItem->Next)
+    {
+        if (EqualSid((PSID)(CurItem + 1),
+                     LookupInfo->Sid))
+        {
+            INT PrincipalIndex;
+            LVFINDINFO lvfi;
+
+            /* 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);
+
+                if (ListViewGetSelectedItemData(sp->hWndPrincipalsList) == (LPARAM)CurItem)
+                {
+                    UpdateControlStates(sp);
+                }
+            }
+            else
+            {
+                AddPrincipalListEntry(sp,
+                                      CurItem,
+                                      -1,
+                                      FALSE);
+            }
+            break;
+        }
+    }
+}
+
 static UINT CALLBACK
 SecurityPageCallback(IN HWND hwnd,
                      IN UINT uMsg,
@@ -1058,9 +1065,21 @@ AddSelectedPrincipal(IN IDsObjectPicker *pDsObjectPicker,
                                          pSid);
     if (AceHeader != NULL)
     {
-        AddPrincipalToList(sp,
-                           pSid,
-                           AceHeader);
+        PPRINCIPAL_LISTITEM PrincipalListItem;
+        BOOL LookupDeferred;
+
+        PrincipalListItem = AddPrincipalToList(sp,
+                                               pSid,
+                                               AceHeader,
+                                               &LookupDeferred);
+
+        if (PrincipalListItem != NULL && LookupDeferred)
+        {
+            AddPrincipalListEntry(sp,
+                                  PrincipalListItem,
+                                  -1,
+                                  FALSE);
+        }
 
         HeapFree(GetProcessHeap(),
                  0,
@@ -1125,6 +1144,23 @@ SecurityPageProc(IN HWND hwndDlg,
                         }
                     }
                 }
+                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;
             }
             
@@ -1152,9 +1188,6 @@ SecurityPageProc(IN HWND hwndDlg,
                             
                             /* delete the instance */
                             FreeObjectPicker(sp->pDsObjectPicker);
-                            
-                            /* reload the principal list */
-                            FillPrincipalsList(sp);
                         }
                         else
                         {
@@ -1203,13 +1236,6 @@ SecurityPageProc(IN HWND hwndDlg,
                     sp->hPermissionsForLabel = GetDlgItem(hwndDlg, IDC_LABEL_PERMISSIONS_FOR);
                     
                     sp->SpecialPermCheckIndex = -1;
-                    
-                    if ((sp->ObjectInfo.dwFlags & SI_SERVER_IS_DC) &&
-                        sp->ObjectInfo.pszServerName != NULL &&
-                        sp->ObjectInfo.pszServerName[0] != L'\0')
-                    {
-                        sp->ServerName = sp->ObjectInfo.pszServerName;
-                    }
 
                     /* save the pointer to the structure */
                     SetWindowLongPtr(hwndDlg,
@@ -1248,8 +1274,6 @@ SecurityPageProc(IN HWND hwndDlg,
                                           &lvc);
                     
                     ReloadPrincipalsList(sp);
-
-                    FillPrincipalsList(sp);
                     
                     ListViewSelectItem(sp->hWndPrincipalsList,
                                        0);
@@ -1313,6 +1337,8 @@ CreateSecurityPage(IN LPSECURITYINFO psi)
     PROPSHEETPAGE psp = {0};
     PSECURITY_PAGE sPage;
     SI_OBJECT_INFO ObjectInfo = {0};
+    HANDLE SidCacheMgr;
+    LPCWSTR SystemName = NULL;
     HRESULT hRet;
 
     if (psi == NULL)
@@ -1336,10 +1362,26 @@ CreateSecurityPage(IN LPSECURITYINFO psi)
         DPRINT("CreateSecurityPage() failed! Failed to query the object information!\n");
         return NULL;
     }
-    
+
+    if ((ObjectInfo.dwFlags & SI_SERVER_IS_DC) &&
+         ObjectInfo.pszServerName != NULL &&
+         ObjectInfo.pszServerName[0] != L'\0')
+    {
+        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;
     }
@@ -1349,13 +1391,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;
index cf31362..ecf94a2 100644 (file)
@@ -20,6 +20,7 @@
        <file>checklist.c</file>
        <file>guid.c</file>
        <file>misc.c</file>
+       <file>sidcache.c</file>
        <file>aclui.rc</file>
        <pch>precomp.h</pch>
 </module>
index a1d18ac..88a99b5 100644 (file)
@@ -24,5 +24,7 @@ STRINGTABLE DISCARDABLE
   IDS_SPECIAL_PERMISSIONS "Special Permissions"
   IDS_PERMISSIONS_FOR "Permissions for %1"
   IDS_PERMISSIONS "Permissions"
+  IDS_USERDOMAINFORMAT "%1 (%2\\%3)"
+  IDS_USERFORMAT "%1"
 }
 
index 53a7e68..8c8a5c7 100644 (file)
@@ -28,6 +28,9 @@
  */
 #include <precomp.h>
 
+#define NDEBUG
+#include <debug.h>
+
 #define CI_TEXT_MARGIN_WIDTH    (8)
 #define CI_TEXT_MARGIN_HEIGHT   (3)
 #define CI_TEXT_SELECTIONMARGIN (1)
@@ -1476,10 +1479,7 @@ CheckListWndProc(IN HWND hwnd,
     
     if (infoPtr == NULL && uMsg != WM_CREATE)
     {
-        return DefWindowProc(hwnd,
-                             uMsg,
-                             wParam,
-                             lParam);
+        goto HandleDefaultMessage;
     }
     
     Ret = 0;
@@ -2224,11 +2224,7 @@ CheckListWndProc(IN HWND hwnd,
                 
                 default:
                 {
-                    Ret = DefWindowProc(hwnd,
-                                        uMsg,
-                                        wParam,
-                                        lParam);
-                    break;
+                    goto HandleDefaultMessage;
                 }
             }
             break;
@@ -2568,6 +2564,7 @@ CheckListWndProc(IN HWND hwnd,
         
         default:
         {
+HandleDefaultMessage:
             Ret = DefWindowProc(hwnd,
                                 uMsg,
                                 wParam,
index 29b1371..6bc4a38 100644 (file)
@@ -17,6 +17,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+/* DO NOT USE THE PRECOMPILED HEADER FOR THIS FILE! */
+
 #include <initguid.h>
 #include <windows.h>
 #include <aclui.h>
index f5e2f0a..143ee42 100644 (file)
@@ -28,6 +28,9 @@
  */
 #include <precomp.h>
 
+#define NDEBUG
+#include <debug.h>
+
 static PCWSTR ObjectPickerAttributes[] =
 {
     L"ObjectSid",
@@ -127,40 +130,6 @@ LoadAndFormatString(IN HINSTANCE hInstance,
     return Ret;
 }
 
-BOOL
-OpenLSAPolicyHandle(IN LPWSTR SystemName,
-                    IN ACCESS_MASK DesiredAccess,
-                    OUT PLSA_HANDLE PolicyHandle)
-{
-    LSA_OBJECT_ATTRIBUTES LsaObjectAttributes = {0};
-    LSA_UNICODE_STRING LsaSystemName, *psn;
-    NTSTATUS Status;
-
-    if (SystemName != NULL)
-    {
-        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,
-                           PolicyHandle);
-    if (!NT_SUCCESS(Status))
-    {
-        SetLastError(LsaNtStatusToWinError(Status));
-        return FALSE;
-    }
-
-    return TRUE;
-}
-
 LPARAM
 ListViewGetSelectedItemData(IN HWND hwnd)
 {
index 1581d31..5367cff 100644 (file)
@@ -1,4 +1,7 @@
+#define WIN32_NO_STATUS
+#define NTOS_MODE_USER
 #include <windows.h>
+#include <ndk/ntndk.h>
 #include <commctrl.h>
 #include <oleauto.h>
 #include <objsel.h>
 #endif
 #include "resource.h"
 
-ULONG DbgPrint(PCH Format,...);
-#define DPRINT DbgPrint
-
-#ifndef NT_SUCCESS
-#define NT_SUCCESS(status) ((LONG)(status) >= 0)
-#endif
-
 #define EnableRedrawWindow(hwnd) \
     SendMessage((hwnd), WM_SETREDRAW, TRUE, 0)
 
@@ -35,11 +31,9 @@ typedef struct _ACE_ENTRY
 typedef struct _PRINCIPAL_LISTITEM
 {
     struct _PRINCIPAL_LISTITEM *Next;
+    struct _SIDREQRESULT *SidReqResult;
     PACE_ENTRY ACEs;
-    SID_NAME_USE SidNameUse;
-    WCHAR *DisplayString;
-    WCHAR *AccountName;
-    WCHAR *DomainName;
+    LPWSTR DisplayString;
 } PRINCIPAL_LISTITEM, *PPRINCIPAL_LISTITEM;
 
 typedef struct _SECURITY_PAGE
@@ -54,9 +48,9 @@ typedef struct _SECURITY_PAGE
     /* Main Principals List */
     HWND hWndPrincipalsList;
     PPRINCIPAL_LISTITEM PrincipalsListHead;
-    
+
     INT ControlsMargin;
-    
+
     INT SpecialPermCheckIndex;
 
     HIMAGELIST hiPrincipals;
@@ -64,19 +58,15 @@ typedef struct _SECURITY_PAGE
     LPSECURITYINFO psi;
     SI_OBJECT_INFO ObjectInfo;
     IDsObjectPicker *pDsObjectPicker;
-    
+
     SI_ACCESS DefaultAccess;
-    
-    LPWSTR ServerName;
+
+    HANDLE SidCacheMgr;
+    LPCWSTR ServerName;
 } SECURITY_PAGE, *PSECURITY_PAGE;
 
 /* MISC ***********************************************************************/
 
-BOOL
-OpenLSAPolicyHandle(IN LPWSTR SystemName,
-                    IN ACCESS_MASK DesiredAccess,
-                    OUT PLSA_HANDLE PolicyHandle);
-
 DWORD
 LoadAndFormatString(IN HINSTANCE hInstance,
                     IN UINT uID,
@@ -163,4 +153,44 @@ DllMain(IN HINSTANCE hinstDLL,
         IN DWORD dwReason,
         IN LPVOID lpvReserved);
 
+/* SIDCACHE *******************************************************************/
+
+typedef struct _SIDREQRESULT
+{
+    LONG RefCount;
+    SID_NAME_USE SidNameUse;
+    LPWSTR AccountName;
+    LPWSTR DomainName;
+} SIDREQRESULT, *PSIDREQRESULT;
+
+typedef VOID (*PSIDREQCOMPLETIONPROC)(IN HANDLE SidCacheMgr,
+                                      IN PSID Sid,
+                                      IN PSIDREQRESULT SidRequestResult,
+                                      IN PVOID Context);
+
+HANDLE
+CreateSidCacheMgr(IN HANDLE Heap,
+                  IN LPCWSTR SystemName);
+
+VOID
+DestroySidCacheMgr(IN HANDLE SidCacheMgr);
+
+VOID
+DequeueSidLookup(IN HANDLE SidCacheMgr,
+                 IN PSID pSid);
+
+BOOL
+LookupSidCache(IN HANDLE SidCacheMgr,
+               IN PSID pSid,
+               IN PSIDREQCOMPLETIONPROC CompletionProc,
+               IN PVOID Context);
+
+VOID
+ReferenceSidReqResult(IN HANDLE SidCacheMgr,
+                      IN PSIDREQRESULT ReqResult);
+
+VOID
+DereferenceSidReqResult(IN HANDLE SidCacheMgr,
+                        IN PSIDREQRESULT ReqResult);
+
 /* EOF */
index 9265727..517e5a9 100644 (file)
@@ -18,6 +18,8 @@
 #define IDS_SPECIAL_PERMISSIONS 1003
 #define IDS_PERMISSIONS_FOR     1004
 #define IDS_PERMISSIONS 1005
+#define IDS_USERDOMAINFORMAT    1006
+#define IDS_USERFORMAT  1007
 
 #define IDB_USRGRPIMAGES       1001
 
diff --git a/reactos/lib/aclui/sidcache.c b/reactos/lib/aclui/sidcache.c
new file mode 100644 (file)
index 0000000..1ab245e
--- /dev/null
@@ -0,0 +1,952 @@
+/*
+ * ReactOS Access Control List Editor
+ * 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
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * 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
+ */
+/* $Id: aclui.c 19715 2005-11-28 01:10:49Z weiden $
+ *
+ * PROJECT:         ReactOS Access Control List Editor
+ * FILE:            lib/aclui/sidcache.c
+ * PURPOSE:         Access Control List Editor
+ * PROGRAMMER:      Thomas Weidenmueller <w3seek@reactos.com>
+ *
+ * UPDATE HISTORY:
+ *      12/10/2005  Created
+ */
+#include <precomp.h>
+
+#define NDEBUG
+#include <debug.h>
+
+#define HandleToScm(Handle) (PSIDCACHEMGR)(Handle)
+#define ScmToHandle(Scm) (HANDLE)(Scm)
+
+typedef struct _SIDCACHEMGR
+{
+    LONG RefCount;
+    LSA_HANDLE LsaHandle;
+    CRITICAL_SECTION Lock;
+    LIST_ENTRY QueueListHead;
+    struct _SIDQUEUEENTRY *QueueLookingUp;
+    LIST_ENTRY CacheListHead;
+    HANDLE Heap;
+    HANDLE LookupEvent;
+    HANDLE LookupThread;
+    WCHAR SystemName[1];
+} SIDCACHEMGR, *PSIDCACHEMGR;
+
+
+typedef struct _SIDCACHECALLBACKINFO
+{
+    PSIDREQCOMPLETIONPROC CompletionProc;
+    PVOID Context;
+} SIDCACHECALLBACKINFO, *PSIDCACHECALLBACKINFO;
+
+
+typedef struct _SIDQUEUEENTRY
+{
+    LIST_ENTRY ListEntry;
+    ULONG CallbackCount;
+    PSIDCACHECALLBACKINFO Callbacks;
+    /* the SID is appended to this structure */
+} SIDQUEUEENTRY, *PSIDQUEUEENTRY;
+
+
+typedef struct _SIDCACHEENTRY
+{
+    LIST_ENTRY ListEntry;
+    SID_NAME_USE SidNameUse;
+    PWSTR AccountName;
+    PWSTR DomainName;
+    /* the SID and strings are appended to this structure */
+} SIDCACHEENTRY, *PSIDCACHEENTRY;
+
+
+static VOID
+FreeQueueEntry(IN PSIDCACHEMGR scm,
+               IN PSIDQUEUEENTRY QueueEntry)
+{
+    if (QueueEntry->ListEntry.Flink != NULL)
+    {
+        RemoveEntryList(&QueueEntry->ListEntry);
+    }
+
+    HeapFree(scm->Heap,
+             0,
+             QueueEntry->Callbacks);
+
+    HeapFree(scm->Heap,
+             0,
+             QueueEntry);
+}
+
+
+static VOID
+FreeCacheEntry(IN PSIDCACHEMGR scm,
+               IN PSIDCACHEENTRY CacheEntry)
+{
+    RemoveEntryList(&CacheEntry->ListEntry);
+
+    HeapFree(scm->Heap,
+             0,
+             CacheEntry);
+}
+
+
+static VOID
+CleanupSidCacheMgr(IN PSIDCACHEMGR scm)
+{
+    /* make sure the lookup thread runs down */
+    SetEvent(scm->LookupEvent);
+    WaitForSingleObject(scm->LookupThread,
+                        INFINITE);
+
+
+    LsaClose(scm->LsaHandle);
+    CloseHandle(scm->LookupEvent);
+    CloseHandle(scm->LookupThread);
+
+    /* delete the queue */
+    while (!IsListEmpty(&scm->QueueListHead))
+    {
+        PSIDQUEUEENTRY QueueEntry;
+
+        QueueEntry = CONTAINING_RECORD(scm->QueueListHead.Flink,
+                                       SIDQUEUEENTRY,
+                                       ListEntry);
+        FreeQueueEntry(scm,
+                       QueueEntry);
+    }
+
+    /* delete the cache */
+    while (!IsListEmpty(&scm->CacheListHead))
+    {
+        PSIDCACHEENTRY CacheEntry;
+
+        CacheEntry = CONTAINING_RECORD(scm->CacheListHead.Flink,
+                                       SIDCACHEENTRY,
+                                       ListEntry);
+        FreeCacheEntry(scm,
+                       CacheEntry);
+    }
+
+    DeleteCriticalSection(&scm->Lock);
+}
+
+
+static PSIDCACHEMGR
+ReferenceSidCacheMgr(IN HANDLE SidCacheMgr)
+{
+    PSIDCACHEMGR scm = HandleToScm(SidCacheMgr);
+
+    if (InterlockedIncrement(&scm->RefCount) != 1)
+    {
+        return scm;
+    }
+
+    return NULL;
+}
+
+
+static VOID
+DereferenceSidCacheMgr(IN PSIDCACHEMGR scm)
+{
+    if (InterlockedDecrement(&scm->RefCount) == 0)
+    {
+        CleanupSidCacheMgr(scm);
+
+        HeapFree(scm->Heap,
+                 0,
+                 scm);
+    }
+}
+
+
+static BOOL
+OpenLSAPolicyHandle(IN LPWSTR SystemName,
+                    IN ACCESS_MASK DesiredAccess,
+                    OUT PLSA_HANDLE PolicyHandle)
+{
+    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,
+                           PolicyHandle);
+    if (!NT_SUCCESS(Status))
+    {
+        SetLastError(LsaNtStatusToWinError(Status));
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+
+static BOOL
+LookupSidInformation(IN PSIDCACHEMGR scm,
+                     IN PSID pSid,
+                     OUT PSIDREQRESULT *ReqResult)
+{
+    PLSA_REFERENCED_DOMAIN_LIST ReferencedDomain;
+    PLSA_TRANSLATED_NAME Names;
+    PLSA_TRUST_INFORMATION Domain;
+    PLSA_UNICODE_STRING DomainName;
+    SID_NAME_USE SidNameUse = SidTypeUnknown;
+    PPOLICY_ACCOUNT_DOMAIN_INFO PolicyAccountDomainInfo = NULL;
+    NTSTATUS Status;
+    DWORD SidLength, AccountNameSize, DomainNameSize = 0;
+    PSIDREQRESULT ReqRet = NULL;
+    BOOL Ret = FALSE;
+
+    Status = LsaLookupSids(scm->LsaHandle,
+                           1,
+                           &pSid,
+                           &ReferencedDomain,
+                           &Names);
+    if (NT_SUCCESS(Status))
+    {
+        SidLength = GetLengthSid(pSid);
+        SidNameUse = Names->Use;
+
+        if (ReferencedDomain != NULL &&
+            Names->DomainIndex >= 0)
+        {
+            Domain = &ReferencedDomain->Domains[Names->DomainIndex];
+            DomainName = &Domain->Name;
+        }
+        else
+        {
+            Domain = NULL;
+            DomainName = NULL;
+        }
+
+        switch (SidNameUse)
+        {
+            case SidTypeAlias:
+            {
+                if (Domain != NULL)
+                {
+                    /* query the domain name for BUILTIN accounts */
+                    Status = LsaQueryInformationPolicy(scm->LsaHandle,
+                                                       PolicyAccountDomainInformation,
+                                                       (PVOID*)&PolicyAccountDomainInfo);
+                    if (NT_SUCCESS(Status))
+                    {
+                        DomainName = &PolicyAccountDomainInfo->DomainName;
+
+                        /* make the user believe this is a group */
+                        SidNameUse = (PolicyAccountDomainInfo != NULL ? SidTypeGroup : SidTypeUser);
+                    }
+                }
+                break;
+            }
+
+            default:
+            {
+                DPRINT("Unhandled SID type: 0x%x\n", Names->Use);
+                break;
+            }
+        }
+
+        AccountNameSize = Names->Name.Length;
+        if (DomainName != NULL)
+        {
+            DomainNameSize = DomainName->Length;
+        }
+
+        ReqRet = HeapAlloc(scm->Heap,
+                           0,
+                           sizeof(SIDREQRESULT) +
+                               (((AccountNameSize + DomainNameSize) + 2) * sizeof(WCHAR)));
+        if (ReqRet != NULL)
+        {
+            ReqRet->RefCount = 1;
+            ReqRet->AccountName = (LPWSTR)(ReqRet + 1);
+            ReqRet->DomainName = ReqRet->AccountName + (AccountNameSize / sizeof(WCHAR)) + 1;
+
+            CopyMemory(ReqRet->AccountName,
+                       Names->Name.Buffer,
+                       Names->Name.Length);
+
+            if (DomainName != NULL)
+            {
+                CopyMemory(ReqRet->DomainName,
+                           DomainName->Buffer,
+                           DomainName->Length);
+            }
+
+            ReqRet->AccountName[AccountNameSize / sizeof(WCHAR)] = L'\0';
+            ReqRet->DomainName[DomainNameSize / sizeof(WCHAR)] = L'\0';
+
+            ReqRet->SidNameUse = SidNameUse;
+        }
+
+        if (PolicyAccountDomainInfo != NULL)
+        {
+            LsaFreeMemory(PolicyAccountDomainInfo);
+        }
+
+        LsaFreeMemory(ReferencedDomain);
+        LsaFreeMemory(Names);
+
+        Ret = TRUE;
+    }
+    else if (Status == STATUS_NONE_MAPPED)
+    {
+        Ret = TRUE;
+    }
+
+    if (Ret)
+    {
+        *ReqResult = ReqRet;
+    }
+
+    return Ret;
+}
+
+
+static BOOL
+FindSidInCache(IN PSIDCACHEMGR scm,
+               IN PSID pSid,
+               OUT PSIDREQRESULT *ReqResult)
+{
+    PSIDCACHEENTRY CacheEntry;
+    PLIST_ENTRY CurrentEntry;
+    PSIDREQRESULT ReqRes;
+    BOOL Ret = FALSE;
+
+    /* NOTE: assumes the lists are locked! */
+
+    CurrentEntry = &scm->CacheListHead;
+    while (CurrentEntry != &scm->CacheListHead)
+    {
+        CacheEntry = CONTAINING_RECORD(CurrentEntry,
+                                       SIDCACHEENTRY,
+                                       ListEntry);
+
+        if (EqualSid(pSid,
+                     (PSID)(CacheEntry + 1)))
+        {
+            SIZE_T ReqResultSize;
+            ULONG AccountNameLen, DomainNameLen;
+
+            Ret = TRUE;
+
+            AccountNameLen = wcslen(CacheEntry->AccountName);
+            DomainNameLen = wcslen(CacheEntry->DomainName);
+
+            ReqResultSize = sizeof(SIDREQRESULT) +
+                                (((AccountNameLen + 1) +
+                                  (DomainNameLen + 1)) * sizeof(WCHAR));
+
+            ReqRes = HeapAlloc(scm->Heap,
+                               0,
+                               ReqResultSize);
+            if (ReqRes != NULL)
+            {
+                PWSTR Buffer = (PWSTR)(ReqRes + 1);
+
+                ReqRes->RefCount = 1;
+
+                ReqRes->AccountName = Buffer;
+                wcscpy(ReqRes->AccountName,
+                       CacheEntry->AccountName);
+                Buffer += AccountNameLen + 1;
+
+                ReqRes->DomainName = Buffer;
+                wcscpy(ReqRes->DomainName,
+                       CacheEntry->DomainName);
+            }
+
+            /* return the result, even if we weren't unable to
+               allocate enough memory! */
+            *ReqResult = ReqRes;
+            break;
+        }
+
+        CurrentEntry = CurrentEntry->Flink;
+    }
+
+    return Ret;
+}
+
+
+static VOID
+CacheLookupResults(IN PSIDCACHEMGR scm,
+                   IN PSID pSid,
+                   IN PSIDREQRESULT ReqResult)
+{
+    PSIDCACHEENTRY CacheEntry;
+    DWORD SidLen;
+    SIZE_T AccountNameLen = 0;
+    SIZE_T DomainNameLen = 0;
+    SIZE_T CacheEntrySize = sizeof(SIDCACHEENTRY);
+
+    /* NOTE: assumes the lists are locked! */
+
+    SidLen = GetLengthSid(pSid);
+    CacheEntrySize += SidLen;
+
+    AccountNameLen = wcslen(ReqResult->AccountName);
+    CacheEntrySize += (AccountNameLen + 1) * sizeof(WCHAR);
+
+    DomainNameLen = wcslen(ReqResult->DomainName);
+    CacheEntrySize += (wcslen(ReqResult->DomainName) + 1) * sizeof(WCHAR);
+
+    CacheEntry = HeapAlloc(scm->Heap,
+                           0,
+                           CacheEntrySize);
+    if (CacheEntry != NULL)
+    {
+        PWSTR lpBuf = (PWSTR)((ULONG_PTR)(CacheEntry + 1) + SidLen);
+
+        CacheEntry->SidNameUse = ReqResult->SidNameUse;
+
+        /* append the SID */
+        CopySid(SidLen,
+                (PSID)(CacheEntry + 1),
+                pSid);
+
+        /* append the strings */
+        CacheEntry->AccountName = lpBuf;
+        wcscpy(lpBuf,
+               ReqResult->AccountName);
+        lpBuf += AccountNameLen + 1;
+
+        CacheEntry->DomainName = lpBuf;
+        wcscpy(lpBuf,
+               ReqResult->DomainName);
+        lpBuf += DomainNameLen + 1;
+
+        /* add the entry to the cache list */
+        InsertTailList(&scm->CacheListHead,
+                       &CacheEntry->ListEntry);
+    }
+}
+
+
+static DWORD WINAPI
+LookupThreadProc(IN LPVOID lpParameter)
+{
+    PSIDCACHEMGR scm = (PSIDCACHEMGR)lpParameter;
+
+    while (scm->RefCount != 0)
+    {
+        PSIDQUEUEENTRY QueueEntry = NULL;
+
+        EnterCriticalSection(&scm->Lock);
+
+        /* get the first item of the queue */
+        if (scm->QueueListHead.Flink != &scm->QueueListHead)
+        {
+            QueueEntry = CONTAINING_RECORD(scm->QueueListHead.Flink,
+                                           SIDQUEUEENTRY,
+                                           ListEntry);
+            RemoveEntryList(&QueueEntry->ListEntry);
+            QueueEntry->ListEntry.Flink = NULL;
+        }
+        else
+        {
+            LeaveCriticalSection(&scm->Lock);
+
+            /* wait for the next asynchronous lookup queued */
+            WaitForSingleObject(scm->LookupEvent,
+                                INFINITE);
+            continue;
+        }
+
+        scm->QueueLookingUp = QueueEntry;
+
+        LeaveCriticalSection(&scm->Lock);
+
+        if (QueueEntry != NULL)
+        {
+            PSIDREQRESULT ReqResult, FoundReqResult;
+            PSID pSid = (PSID)(QueueEntry + 1);
+
+            /* lookup the SID information */
+            if (!LookupSidInformation(scm,
+                                      pSid,
+                                      &ReqResult))
+            {
+                ReqResult = NULL;
+            }
+
+            EnterCriticalSection(&scm->Lock);
+
+            /* see if the SID was added to the cache in the meanwhile */
+            if (!FindSidInCache(scm,
+                                pSid,
+                                &FoundReqResult))
+            {
+                if (ReqResult != NULL)
+                {
+                    /* cache the results */
+                    CacheLookupResults(scm,
+                                       pSid,
+                                       ReqResult);
+                }
+            }
+            else
+            {
+                if (ReqResult != NULL)
+                {
+                    /* free the information of our lookup and use the cached
+                       information*/
+                    DereferenceSidReqResult(scm,
+                                            ReqResult);
+                }
+
+                ReqResult = FoundReqResult;
+            }
+
+            /* notify the callers unless the lookup was cancelled */
+            if (scm->QueueLookingUp != NULL)
+            {
+                ULONG i = 0;
+
+                while (scm->QueueLookingUp != NULL &&
+                       i < QueueEntry->CallbackCount)
+                {
+                    PVOID Context;
+                    PSIDREQCOMPLETIONPROC CompletionProc;
+
+                    Context = QueueEntry->Callbacks[i].Context;
+                    CompletionProc = QueueEntry->Callbacks[i].CompletionProc;
+
+                    LeaveCriticalSection(&scm->Lock);
+
+                    /* call the completion proc without holding the lock! */
+                    CompletionProc(ScmToHandle(scm),
+                                   pSid,
+                                   ReqResult,
+                                   Context);
+
+                    EnterCriticalSection(&scm->Lock);
+
+                    i++;
+                }
+
+                scm->QueueLookingUp = NULL;
+            }
+
+            LeaveCriticalSection(&scm->Lock);
+
+            /* free the queue item */
+            FreeQueueEntry(scm,
+                           QueueEntry);
+        }
+    }
+
+    return 0;
+}
+
+
+
+HANDLE
+CreateSidCacheMgr(IN HANDLE Heap,
+                  IN LPCWSTR SystemName)
+{
+    PSIDCACHEMGR scm;
+
+    if (SystemName == NULL)
+        SystemName = L"";
+
+    scm = HeapAlloc(Heap,
+                    0,
+                    FIELD_OFFSET(SIDCACHEMGR,
+                                 SystemName[0]) +
+                        ((wcslen(SystemName) + 1) * sizeof(WCHAR)));
+    if (scm != NULL)
+    {
+        /* zero the static part of the structure */
+        ZeroMemory(scm,
+                   sizeof(SIDCACHEMGR));
+
+        scm->RefCount = 1;
+        scm->Heap = Heap;
+
+        wcscpy(scm->SystemName,
+               SystemName);
+
+        InitializeCriticalSection(&scm->Lock);
+        InitializeListHead(&scm->QueueListHead);
+        InitializeListHead(&scm->CacheListHead);
+
+        scm->LookupEvent = CreateEvent(NULL,
+                                       FALSE,
+                                       FALSE,
+                                       NULL);
+        if (scm->LookupEvent == NULL)
+        {
+            goto Cleanup;
+        }
+
+        if (!OpenLSAPolicyHandle(scm->SystemName,
+                                 POLICY_LOOKUP_NAMES | POLICY_VIEW_LOCAL_INFORMATION,
+                                 &scm->LsaHandle))
+        {
+            goto Cleanup;
+        }
+
+        scm->LookupThread = CreateThread(NULL,
+                                         0,
+                                         LookupThreadProc,
+                                         scm,
+                                         0,
+                                         NULL);
+        if (scm->LookupThread == NULL)
+        {
+Cleanup:
+            if (scm->LookupEvent != NULL)
+            {
+                CloseHandle(scm->LookupEvent);
+            }
+
+            if (scm->LsaHandle != NULL)
+            {
+                LsaClose(scm->LsaHandle);
+            }
+
+            HeapFree(Heap,
+                     0,
+                     scm);
+            scm = NULL;
+        }
+    }
+    else
+    {
+        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+    }
+
+    return (HANDLE)scm;
+}
+
+
+VOID
+DestroySidCacheMgr(IN HANDLE SidCacheMgr)
+{
+    PSIDCACHEMGR scm = HandleToScm(SidCacheMgr);
+
+    if (scm != NULL)
+    {
+        /* remove the keep-alive reference */
+        DereferenceSidCacheMgr(scm);
+    }
+}
+
+
+static BOOL
+QueueSidLookup(IN PSIDCACHEMGR scm,
+               IN PSID pSid,
+               IN PSIDREQCOMPLETIONPROC CompletionProc,
+               IN PVOID Context)
+{
+    PLIST_ENTRY CurrentEntry;
+    PSIDQUEUEENTRY QueueEntry, FoundEntry = NULL;
+    BOOL Ret = FALSE;
+
+    /* NOTE: assumes the lists are locked! */
+
+    if (scm->QueueLookingUp != NULL &&
+        EqualSid(pSid,
+                 (PSID)(scm->QueueLookingUp + 1)))
+    {
+        FoundEntry = scm->QueueLookingUp;
+    }
+    else
+    {
+        CurrentEntry = &scm->QueueListHead;
+        while (CurrentEntry != &scm->QueueListHead)
+        {
+            QueueEntry = CONTAINING_RECORD(CurrentEntry,
+                                           SIDQUEUEENTRY,
+                                           ListEntry);
+
+            if (EqualSid(pSid,
+                         (PSID)(QueueEntry + 1)))
+            {
+                FoundEntry = QueueEntry;
+                break;
+            }
+
+            CurrentEntry = CurrentEntry->Flink;
+        }
+    }
+
+    if (FoundEntry == NULL)
+    {
+        DWORD SidLength = GetLengthSid(pSid);
+
+        FoundEntry = HeapAlloc(scm->Heap,
+                               0,
+                               sizeof(SIDQUEUEENTRY) + SidLength);
+        if (FoundEntry != NULL)
+        {
+            CopySid(SidLength,
+                    (PSID)(FoundEntry + 1),
+                    pSid);
+
+            FoundEntry->CallbackCount = 1;
+            FoundEntry->Callbacks = HeapAlloc(scm->Heap,
+                                              0,
+                                              sizeof(SIDCACHECALLBACKINFO));
+
+            if (FoundEntry->Callbacks != NULL)
+            {
+                FoundEntry->Callbacks[0].CompletionProc = CompletionProc;
+                FoundEntry->Callbacks[0].Context = Context;
+
+                /* append it to the queue */
+                InsertTailList(&scm->QueueListHead,
+                               &FoundEntry->ListEntry);
+
+                /* signal the lookup event */
+                SetEvent(scm->LookupEvent);
+
+                Ret = TRUE;
+            }
+            else
+            {
+                /* unable to queue it because we couldn't allocate the callbacks
+                   array, free the memory and return */
+                HeapFree(scm->Heap,
+                         0,
+                         FoundEntry);
+            }
+        }
+    }
+    else
+    {
+        PSIDCACHECALLBACKINFO Sidccb;
+
+        /* add the callback */
+        Sidccb = HeapReAlloc(scm->Heap,
+                             0,
+                             FoundEntry->Callbacks,
+                             (FoundEntry->CallbackCount + 1) * sizeof(SIDCACHECALLBACKINFO));
+        if (Sidccb != NULL)
+        {
+            FoundEntry->Callbacks = Sidccb;
+            FoundEntry->Callbacks[FoundEntry->CallbackCount].CompletionProc = CompletionProc;
+            FoundEntry->Callbacks[FoundEntry->CallbackCount++].Context = Context;
+
+            Ret = TRUE;
+        }
+    }
+
+    return Ret;
+}
+
+
+VOID
+DequeueSidLookup(IN HANDLE SidCacheMgr,
+                 IN PSID pSid)
+{
+    PLIST_ENTRY CurrentEntry;
+    PSIDQUEUEENTRY QueueEntry;
+    PSIDCACHEMGR scm;
+
+    scm = ReferenceSidCacheMgr(SidCacheMgr);
+    if (scm != NULL)
+    {
+        EnterCriticalSection(&scm->Lock);
+
+        if (scm->QueueLookingUp != NULL &&
+            EqualSid(pSid,
+                     (PSID)(scm->QueueLookingUp + 1)))
+        {
+            /* don't free the queue lookup item! this will be
+               done in the lookup thread */
+            scm->QueueLookingUp = NULL;
+        }
+        else
+        {
+            CurrentEntry = &scm->QueueListHead;
+            while (CurrentEntry != &scm->QueueListHead)
+            {
+                QueueEntry = CONTAINING_RECORD(CurrentEntry,
+                                               SIDQUEUEENTRY,
+                                               ListEntry);
+
+                if (EqualSid(pSid,
+                             (PSID)(QueueEntry + 1)))
+                {
+                    FreeQueueEntry(scm,
+                                   QueueEntry);
+                    break;
+                }
+
+                CurrentEntry = CurrentEntry->Flink;
+            }
+        }
+
+        LeaveCriticalSection(&scm->Lock);
+
+        DereferenceSidCacheMgr(scm);
+    }
+}
+
+
+VOID
+ReferenceSidReqResult(IN HANDLE SidCacheMgr,
+                      IN PSIDREQRESULT ReqResult)
+{
+    PSIDCACHEMGR scm;
+
+    scm = ReferenceSidCacheMgr(SidCacheMgr);
+    if (scm != NULL)
+    {
+        InterlockedIncrement(&ReqResult->RefCount);
+
+        DereferenceSidCacheMgr(scm);
+    }
+}
+
+
+VOID
+DereferenceSidReqResult(IN HANDLE SidCacheMgr,
+                        IN PSIDREQRESULT ReqResult)
+{
+    PSIDCACHEMGR scm;
+
+    scm = ReferenceSidCacheMgr(SidCacheMgr);
+    if (scm != NULL)
+    {
+        if (InterlockedDecrement(&ReqResult->RefCount) == 0)
+        {
+            HeapFree(scm->Heap,
+                     0,
+                     ReqResult);
+        }
+
+        DereferenceSidCacheMgr(scm);
+    }
+}
+
+
+BOOL
+LookupSidCache(IN HANDLE SidCacheMgr,
+               IN PSID pSid,
+               IN PSIDREQCOMPLETIONPROC CompletionProc,
+               IN PVOID Context)
+{
+    BOOL Found = FALSE;
+    PSIDREQRESULT ReqResult = NULL;
+    PSIDCACHEMGR scm;
+
+    scm = ReferenceSidCacheMgr(SidCacheMgr);
+    if (scm != NULL)
+    {
+        EnterCriticalSection(&scm->Lock);
+
+        /* search the cache */
+        Found = FindSidInCache(scm,
+                               pSid,
+                               &ReqResult);
+
+        if (!Found)
+        {
+            /* the sid is not in the cache, queue it if not already queued */
+            if (!QueueSidLookup(scm,
+                                pSid,
+                                CompletionProc,
+                                Context))
+            {
+                PSIDREQRESULT FoundReqResult = NULL;
+
+                /* unable to queue it, look it up now */
+
+                LeaveCriticalSection(&scm->Lock);
+
+                /* lookup everything we need */
+                if (!LookupSidInformation(scm,
+                                          pSid,
+                                          &ReqResult))
+                {
+                    ReqResult = NULL;
+                }
+
+                EnterCriticalSection(&scm->Lock);
+
+                /* see if the SID was added to the cache in the meanwhile */
+                if (!FindSidInCache(scm,
+                                    pSid,
+                                    &FoundReqResult))
+                {
+                    if (ReqResult != NULL)
+                    {
+                        /* cache the results */
+                        CacheLookupResults(scm,
+                                           pSid,
+                                           ReqResult);
+                    }
+                }
+                else
+                {
+                    if (ReqResult != NULL)
+                    {
+                        /* free the information of our lookup and use the cached
+                           information*/
+                        DereferenceSidReqResult(scm,
+                                                ReqResult);
+                    }
+
+                    ReqResult = FoundReqResult;
+                }
+
+                Found = (ReqResult != NULL);
+            }
+        }
+
+        LeaveCriticalSection(&scm->Lock);
+
+        /* call the completion callback */
+        if (Found)
+        {
+            CompletionProc(SidCacheMgr,
+                           pSid,
+                           ReqResult,
+                           Context);
+
+            if (ReqResult != NULL)
+            {
+                HeapFree(scm->Heap,
+                         0,
+                         ReqResult);
+            }
+        }
+
+        DereferenceSidCacheMgr(scm);
+    }
+
+    return Found;
+}