xref: /reactos/dll/win32/aclui/sidcache.c (revision 37b2c145)
1 /*
2  * ReactOS Access Control List Editor
3  * Copyright (C) 2004-2005 ReactOS Team
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18  */
19 /*
20  * PROJECT:         ReactOS Access Control List Editor
21  * FILE:            lib/aclui/sidcache.c
22  * PURPOSE:         Access Control List Editor
23  * PROGRAMMER:      Thomas Weidenmueller <w3seek@reactos.com>
24  *
25  * UPDATE HISTORY:
26  *      12/10/2005  Created
27  */
28 
29 #include "precomp.h"
30 
31 #include <ntsecapi.h>
32 
33 #define NDEBUG
34 #include <debug.h>
35 
36 #define HandleToScm(Handle) (PSIDCACHEMGR)(Handle)
37 #define ScmToHandle(Scm) (HANDLE)(Scm)
38 
39 typedef struct _SIDCACHEMGR
40 {
41     volatile LONG RefCount;
42     LSA_HANDLE LsaHandle;
43     CRITICAL_SECTION Lock;
44     LIST_ENTRY QueueListHead;
45     struct _SIDQUEUEENTRY *QueueLookingUp;
46     LIST_ENTRY CacheListHead;
47     HANDLE Heap;
48     HANDLE LookupEvent;
49     HANDLE LookupThread;
50     WCHAR SystemName[1];
51 } SIDCACHEMGR, *PSIDCACHEMGR;
52 
53 
54 typedef struct _SIDCACHECALLBACKINFO
55 {
56     PSIDREQCOMPLETIONPROC CompletionProc;
57     PVOID Context;
58 } SIDCACHECALLBACKINFO, *PSIDCACHECALLBACKINFO;
59 
60 
61 typedef struct _SIDQUEUEENTRY
62 {
63     LIST_ENTRY ListEntry;
64     ULONG CallbackCount;
65     PSIDCACHECALLBACKINFO Callbacks;
66     /* the SID is appended to this structure */
67 } SIDQUEUEENTRY, *PSIDQUEUEENTRY;
68 
69 
70 typedef struct _SIDCACHEENTRY
71 {
72     LIST_ENTRY ListEntry;
73     SID_NAME_USE SidNameUse;
74     PWSTR AccountName;
75     PWSTR DomainName;
76     /* the SID and strings are appended to this structure */
77 } SIDCACHEENTRY, *PSIDCACHEENTRY;
78 
79 
80 static VOID
81 FreeQueueEntry(IN PSIDCACHEMGR scm,
82                IN PSIDQUEUEENTRY QueueEntry)
83 {
84     if (QueueEntry->ListEntry.Flink != NULL)
85     {
86         RemoveEntryList(&QueueEntry->ListEntry);
87     }
88 
89     HeapFree(scm->Heap,
90              0,
91              QueueEntry->Callbacks);
92 
93     HeapFree(scm->Heap,
94              0,
95              QueueEntry);
96 }
97 
98 
99 static VOID
100 FreeCacheEntry(IN PSIDCACHEMGR scm,
101                IN PSIDCACHEENTRY CacheEntry)
102 {
103     RemoveEntryList(&CacheEntry->ListEntry);
104 
105     HeapFree(scm->Heap,
106              0,
107              CacheEntry);
108 }
109 
110 
111 static VOID
112 CleanupSidCacheMgr(IN PSIDCACHEMGR scm)
113 {
114     LsaClose(scm->LsaHandle);
115     CloseHandle(scm->LookupEvent);
116     CloseHandle(scm->LookupThread);
117 
118     /* delete the queue */
119     while (!IsListEmpty(&scm->QueueListHead))
120     {
121         PSIDQUEUEENTRY QueueEntry;
122 
123         QueueEntry = CONTAINING_RECORD(scm->QueueListHead.Flink,
124                                        SIDQUEUEENTRY,
125                                        ListEntry);
126         FreeQueueEntry(scm,
127                        QueueEntry);
128     }
129 
130     /* delete the cache */
131     while (!IsListEmpty(&scm->CacheListHead))
132     {
133         PSIDCACHEENTRY CacheEntry;
134 
135         CacheEntry = CONTAINING_RECORD(scm->CacheListHead.Flink,
136                                        SIDCACHEENTRY,
137                                        ListEntry);
138         FreeCacheEntry(scm,
139                        CacheEntry);
140     }
141 
142     DeleteCriticalSection(&scm->Lock);
143 }
144 
145 
146 static PSIDCACHEMGR
147 ReferenceSidCacheMgr(IN HANDLE SidCacheMgr)
148 {
149     PSIDCACHEMGR scm = HandleToScm(SidCacheMgr);
150 
151     if (InterlockedIncrement(&scm->RefCount) != 1)
152     {
153         return scm;
154     }
155 
156     return NULL;
157 }
158 
159 
160 static VOID
161 DereferenceSidCacheMgr(IN PSIDCACHEMGR scm)
162 {
163     if (InterlockedDecrement(&scm->RefCount) == 0)
164     {
165         /* Signal the lookup thread so it can terminate */
166         SetEvent(scm->LookupEvent);
167     }
168 }
169 
170 
171 static BOOL
172 OpenLSAPolicyHandle(IN LPWSTR SystemName,
173                     IN ACCESS_MASK DesiredAccess,
174                     OUT PLSA_HANDLE PolicyHandle)
175 {
176     LSA_OBJECT_ATTRIBUTES LsaObjectAttributes = {0};
177     LSA_UNICODE_STRING LsaSystemName, *psn;
178     NTSTATUS Status;
179 
180     if (SystemName != NULL && SystemName[0] != L'\0')
181     {
182         LsaSystemName.Buffer = SystemName;
183         LsaSystemName.Length = wcslen(SystemName) * sizeof(WCHAR);
184         LsaSystemName.MaximumLength = LsaSystemName.Length + sizeof(WCHAR);
185         psn = &LsaSystemName;
186     }
187     else
188     {
189         psn = NULL;
190     }
191 
192     Status = LsaOpenPolicy(psn,
193                            &LsaObjectAttributes,
194                            DesiredAccess,
195                            PolicyHandle);
196     if (!NT_SUCCESS(Status))
197     {
198         SetLastError(LsaNtStatusToWinError(Status));
199         return FALSE;
200     }
201 
202     return TRUE;
203 }
204 
205 
206 static BOOL
207 LookupSidInformation(IN PSIDCACHEMGR scm,
208                      IN PSID pSid,
209                      OUT PSIDREQRESULT *ReqResult)
210 {
211     PLSA_REFERENCED_DOMAIN_LIST ReferencedDomain;
212     PLSA_TRANSLATED_NAME Names;
213     PLSA_TRUST_INFORMATION Domain;
214     PLSA_UNICODE_STRING DomainName;
215     SID_NAME_USE SidNameUse = SidTypeUnknown;
216     PPOLICY_ACCOUNT_DOMAIN_INFO PolicyAccountDomainInfo = NULL;
217     NTSTATUS Status;
218     DWORD AccountNameSize, DomainNameSize = 0;
219     PSIDREQRESULT ReqRet = NULL;
220     BOOL Ret = FALSE;
221 
222     Status = LsaLookupSids(scm->LsaHandle,
223                            1,
224                            &pSid,
225                            &ReferencedDomain,
226                            &Names);
227     if (NT_SUCCESS(Status))
228     {
229         SidNameUse = Names->Use;
230 
231         if (ReferencedDomain != NULL &&
232             Names->DomainIndex >= 0)
233         {
234             Domain = &ReferencedDomain->Domains[Names->DomainIndex];
235             DomainName = &Domain->Name;
236         }
237         else
238         {
239             Domain = NULL;
240             DomainName = NULL;
241         }
242 
243         switch (SidNameUse)
244         {
245             case SidTypeAlias:
246             {
247                 if (Domain != NULL)
248                 {
249                     /* query the domain name for BUILTIN accounts */
250                     Status = LsaQueryInformationPolicy(scm->LsaHandle,
251                                                        PolicyAccountDomainInformation,
252                                                        (PVOID*)&PolicyAccountDomainInfo);
253                     if (NT_SUCCESS(Status))
254                     {
255                         DomainName = &PolicyAccountDomainInfo->DomainName;
256 
257                         /* make the user believe this is a group */
258                         SidNameUse = (PolicyAccountDomainInfo != NULL ? SidTypeGroup : SidTypeUser);
259                     }
260                 }
261                 break;
262             }
263 
264             default:
265             {
266                 DPRINT("Unhandled SID type: 0x%x\n", Names->Use);
267                 break;
268             }
269         }
270 
271         AccountNameSize = Names->Name.Length;
272         if (DomainName != NULL)
273         {
274             DomainNameSize = DomainName->Length;
275         }
276 
277         ReqRet = HeapAlloc(scm->Heap,
278                            0,
279                            sizeof(SIDREQRESULT) +
280                                (((AccountNameSize + DomainNameSize) + 2) * sizeof(WCHAR)));
281         if (ReqRet != NULL)
282         {
283             ReqRet->RefCount = 1;
284             ReqRet->AccountName = (LPWSTR)(ReqRet + 1);
285             ReqRet->DomainName = ReqRet->AccountName + (AccountNameSize / sizeof(WCHAR)) + 1;
286 
287             CopyMemory(ReqRet->AccountName,
288                        Names->Name.Buffer,
289                        Names->Name.Length);
290 
291             if (DomainName != NULL)
292             {
293                 CopyMemory(ReqRet->DomainName,
294                            DomainName->Buffer,
295                            DomainName->Length);
296             }
297 
298             ReqRet->AccountName[AccountNameSize / sizeof(WCHAR)] = L'\0';
299             ReqRet->DomainName[DomainNameSize / sizeof(WCHAR)] = L'\0';
300 
301             ReqRet->SidNameUse = SidNameUse;
302         }
303 
304         if (PolicyAccountDomainInfo != NULL)
305         {
306             LsaFreeMemory(PolicyAccountDomainInfo);
307         }
308 
309         LsaFreeMemory(ReferencedDomain);
310         LsaFreeMemory(Names);
311 
312         Ret = TRUE;
313     }
314     else if (Status == STATUS_NONE_MAPPED)
315     {
316         Ret = TRUE;
317     }
318 
319     if (Ret)
320     {
321         *ReqResult = ReqRet;
322     }
323 
324     return Ret;
325 }
326 
327 
328 static BOOL
329 FindSidInCache(IN PSIDCACHEMGR scm,
330                IN PSID pSid,
331                OUT PSIDREQRESULT *ReqResult)
332 {
333     PSIDCACHEENTRY CacheEntry;
334     PLIST_ENTRY CurrentEntry;
335     PSIDREQRESULT ReqRes;
336     BOOL Ret = FALSE;
337 
338     /* NOTE: assumes the lists are locked! */
339 
340     for (CurrentEntry = scm->CacheListHead.Flink;
341          CurrentEntry != &scm->CacheListHead;
342          CurrentEntry = CurrentEntry->Flink)
343     {
344         CacheEntry = CONTAINING_RECORD(CurrentEntry,
345                                        SIDCACHEENTRY,
346                                        ListEntry);
347 
348         if (EqualSid(pSid,
349                      (PSID)(CacheEntry + 1)))
350         {
351             SIZE_T ReqResultSize;
352             ULONG AccountNameLen, DomainNameLen;
353 
354             Ret = TRUE;
355 
356             AccountNameLen = wcslen(CacheEntry->AccountName);
357             DomainNameLen = wcslen(CacheEntry->DomainName);
358 
359             ReqResultSize = sizeof(SIDREQRESULT) +
360                                 (((AccountNameLen + 1) +
361                                   (DomainNameLen + 1)) * sizeof(WCHAR));
362 
363             ReqRes = HeapAlloc(scm->Heap,
364                                0,
365                                ReqResultSize);
366             if (ReqRes != NULL)
367             {
368                 PWSTR Buffer = (PWSTR)(ReqRes + 1);
369 
370                 ReqRes->RefCount = 1;
371 
372                 ReqRes->AccountName = Buffer;
373                 wcscpy(ReqRes->AccountName,
374                        CacheEntry->AccountName);
375                 Buffer += AccountNameLen + 1;
376 
377                 ReqRes->DomainName = Buffer;
378                 wcscpy(ReqRes->DomainName,
379                        CacheEntry->DomainName);
380             }
381 
382             /* return the result, even if we weren't unable to
383                allocate enough memory! */
384             *ReqResult = ReqRes;
385             break;
386         }
387     }
388 
389     return Ret;
390 }
391 
392 
393 static VOID
394 CacheLookupResults(IN PSIDCACHEMGR scm,
395                    IN PSID pSid,
396                    IN PSIDREQRESULT ReqResult)
397 {
398     PSIDCACHEENTRY CacheEntry;
399     DWORD SidLen;
400     SIZE_T AccountNameLen = 0;
401     SIZE_T DomainNameLen = 0;
402     SIZE_T CacheEntrySize = sizeof(SIDCACHEENTRY);
403 
404     /* NOTE: assumes the lists are locked! */
405 
406     SidLen = GetLengthSid(pSid);
407     CacheEntrySize += SidLen;
408 
409     AccountNameLen = wcslen(ReqResult->AccountName);
410     CacheEntrySize += (AccountNameLen + 1) * sizeof(WCHAR);
411 
412     DomainNameLen = wcslen(ReqResult->DomainName);
413     CacheEntrySize += (wcslen(ReqResult->DomainName) + 1) * sizeof(WCHAR);
414 
415     CacheEntry = HeapAlloc(scm->Heap,
416                            0,
417                            CacheEntrySize);
418     if (CacheEntry != NULL)
419     {
420         PWSTR lpBuf = (PWSTR)((ULONG_PTR)(CacheEntry + 1) + SidLen);
421 
422         CacheEntry->SidNameUse = ReqResult->SidNameUse;
423 
424         /* append the SID */
425         CopySid(SidLen,
426                 (PSID)(CacheEntry + 1),
427                 pSid);
428 
429         /* append the strings */
430         CacheEntry->AccountName = lpBuf;
431         wcscpy(lpBuf,
432                ReqResult->AccountName);
433         lpBuf += AccountNameLen + 1;
434 
435         CacheEntry->DomainName = lpBuf;
436         wcscpy(lpBuf,
437                ReqResult->DomainName);
438         lpBuf += DomainNameLen + 1;
439 
440         /* add the entry to the cache list */
441         InsertTailList(&scm->CacheListHead,
442                        &CacheEntry->ListEntry);
443     }
444 }
445 
446 
447 static DWORD WINAPI
448 LookupThreadProc(IN LPVOID lpParameter)
449 {
450     HMODULE hModule;
451     PSIDCACHEMGR scm = (PSIDCACHEMGR)lpParameter;
452 
453     /* Reference the dll to avoid problems in case of accidental
454        FreeLibrary calls... */
455     if (!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
456                             (LPCWSTR)hDllInstance,
457                             &hModule))
458     {
459         hModule = NULL;
460     }
461 
462     while (scm->RefCount != 0)
463     {
464         PSIDQUEUEENTRY QueueEntry = NULL;
465 
466         EnterCriticalSection(&scm->Lock);
467 
468         /* get the first item of the queue */
469         if (scm->QueueListHead.Flink != &scm->QueueListHead)
470         {
471             QueueEntry = CONTAINING_RECORD(scm->QueueListHead.Flink,
472                                            SIDQUEUEENTRY,
473                                            ListEntry);
474             RemoveEntryList(&QueueEntry->ListEntry);
475             QueueEntry->ListEntry.Flink = NULL;
476         }
477         else
478         {
479             LeaveCriticalSection(&scm->Lock);
480 
481             /* wait for the next asynchronous lookup queued */
482             WaitForSingleObject(scm->LookupEvent,
483                                 INFINITE);
484             continue;
485         }
486 
487         scm->QueueLookingUp = QueueEntry;
488 
489         LeaveCriticalSection(&scm->Lock);
490 
491         if (QueueEntry != NULL)
492         {
493             PSIDREQRESULT ReqResult, FoundReqResult;
494             PSID pSid = (PSID)(QueueEntry + 1);
495 
496             /* lookup the SID information */
497             if (!LookupSidInformation(scm,
498                                       pSid,
499                                       &ReqResult))
500             {
501                 ReqResult = NULL;
502             }
503 
504             EnterCriticalSection(&scm->Lock);
505 
506             /* see if the SID was added to the cache in the meanwhile */
507             if (!FindSidInCache(scm,
508                                 pSid,
509                                 &FoundReqResult))
510             {
511                 if (ReqResult != NULL)
512                 {
513                     /* cache the results */
514                     CacheLookupResults(scm,
515                                        pSid,
516                                        ReqResult);
517                 }
518             }
519             else
520             {
521                 if (ReqResult != NULL)
522                 {
523                     /* free the information of our lookup and use the cached
524                        information*/
525                     DereferenceSidReqResult(scm,
526                                             ReqResult);
527                 }
528 
529                 ReqResult = FoundReqResult;
530             }
531 
532             /* notify the callers unless the lookup was cancelled */
533             if (scm->QueueLookingUp != NULL)
534             {
535                 ULONG i = 0;
536 
537                 while (scm->QueueLookingUp != NULL &&
538                        i < QueueEntry->CallbackCount)
539                 {
540                     PVOID Context;
541                     PSIDREQCOMPLETIONPROC CompletionProc;
542 
543                     Context = QueueEntry->Callbacks[i].Context;
544                     CompletionProc = QueueEntry->Callbacks[i].CompletionProc;
545 
546                     LeaveCriticalSection(&scm->Lock);
547 
548                     /* call the completion proc without holding the lock! */
549                     CompletionProc(ScmToHandle(scm),
550                                    pSid,
551                                    ReqResult,
552                                    Context);
553 
554                     EnterCriticalSection(&scm->Lock);
555 
556                     i++;
557                 }
558 
559                 scm->QueueLookingUp = NULL;
560             }
561 
562             LeaveCriticalSection(&scm->Lock);
563 
564             /* free the queue item */
565             FreeQueueEntry(scm,
566                            QueueEntry);
567         }
568     }
569 
570     CleanupSidCacheMgr(scm);
571 
572     HeapFree(scm->Heap,
573              0,
574              scm);
575 
576     if (hModule != NULL)
577     {
578         /* dereference the library and exit */
579         FreeLibraryAndExitThread(hModule,
580                                  0);
581     }
582 
583     return 0;
584 }
585 
586 
587 
588 HANDLE
589 CreateSidCacheMgr(IN HANDLE Heap,
590                   IN LPCWSTR SystemName)
591 {
592     PSIDCACHEMGR scm;
593 
594     if (SystemName == NULL)
595         SystemName = L"";
596 
597     scm = HeapAlloc(Heap,
598                     0,
599                     FIELD_OFFSET(SIDCACHEMGR,
600                                  SystemName[wcslen(SystemName) + 1]));
601     if (scm != NULL)
602     {
603         /* zero the static part of the structure */
604         ZeroMemory(scm,
605                    FIELD_OFFSET(SIDCACHEMGR,
606                                 SystemName));
607 
608         scm->RefCount = 1;
609         scm->Heap = Heap;
610 
611         wcscpy(scm->SystemName,
612                SystemName);
613 
614         InitializeCriticalSection(&scm->Lock);
615         InitializeListHead(&scm->QueueListHead);
616         InitializeListHead(&scm->CacheListHead);
617 
618         scm->LookupEvent = CreateEvent(NULL,
619                                        FALSE,
620                                        FALSE,
621                                        NULL);
622         if (scm->LookupEvent == NULL)
623         {
624             goto Cleanup;
625         }
626 
627         if (!OpenLSAPolicyHandle(scm->SystemName,
628                                  POLICY_LOOKUP_NAMES | POLICY_VIEW_LOCAL_INFORMATION,
629                                  &scm->LsaHandle))
630         {
631             goto Cleanup;
632         }
633 
634         scm->LookupThread = CreateThread(NULL,
635                                          0,
636                                          LookupThreadProc,
637                                          scm,
638                                          0,
639                                          NULL);
640         if (scm->LookupThread == NULL)
641         {
642 Cleanup:
643             if (scm->LookupEvent != NULL)
644             {
645                 CloseHandle(scm->LookupEvent);
646             }
647 
648             if (scm->LsaHandle != NULL)
649             {
650                 LsaClose(scm->LsaHandle);
651             }
652 
653             HeapFree(Heap,
654                      0,
655                      scm);
656             scm = NULL;
657         }
658     }
659     else
660     {
661         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
662     }
663 
664     return (HANDLE)scm;
665 }
666 
667 
668 VOID
669 DestroySidCacheMgr(IN HANDLE SidCacheMgr)
670 {
671     PSIDCACHEMGR scm = HandleToScm(SidCacheMgr);
672 
673     if (scm != NULL)
674     {
675         /* remove the keep-alive reference */
676         DereferenceSidCacheMgr(scm);
677     }
678 }
679 
680 
681 static BOOL
682 QueueSidLookup(IN PSIDCACHEMGR scm,
683                IN PSID pSid,
684                IN PSIDREQCOMPLETIONPROC CompletionProc,
685                IN PVOID Context)
686 {
687     PLIST_ENTRY CurrentEntry;
688     PSIDQUEUEENTRY QueueEntry, FoundEntry = NULL;
689     BOOL Ret = FALSE;
690 
691     /* NOTE: assumes the lists are locked! */
692 
693     if (scm->QueueLookingUp != NULL &&
694         EqualSid(pSid,
695                  (PSID)(scm->QueueLookingUp + 1)))
696     {
697         FoundEntry = scm->QueueLookingUp;
698     }
699     else
700     {
701         for (CurrentEntry = scm->QueueListHead.Flink;
702              CurrentEntry != &scm->QueueListHead;
703              CurrentEntry = CurrentEntry->Flink)
704         {
705             QueueEntry = CONTAINING_RECORD(CurrentEntry,
706                                            SIDQUEUEENTRY,
707                                            ListEntry);
708 
709             if (EqualSid(pSid,
710                          (PSID)(QueueEntry + 1)))
711             {
712                 FoundEntry = QueueEntry;
713                 break;
714             }
715         }
716     }
717 
718     if (FoundEntry == NULL)
719     {
720         DWORD SidLength = GetLengthSid(pSid);
721 
722         FoundEntry = HeapAlloc(scm->Heap,
723                                0,
724                                sizeof(SIDQUEUEENTRY) + SidLength);
725         if (FoundEntry != NULL)
726         {
727             CopySid(SidLength,
728                     (PSID)(FoundEntry + 1),
729                     pSid);
730 
731             FoundEntry->CallbackCount = 1;
732             FoundEntry->Callbacks = HeapAlloc(scm->Heap,
733                                               0,
734                                               sizeof(SIDCACHECALLBACKINFO));
735 
736             if (FoundEntry->Callbacks != NULL)
737             {
738                 FoundEntry->Callbacks[0].CompletionProc = CompletionProc;
739                 FoundEntry->Callbacks[0].Context = Context;
740 
741                 /* append it to the queue */
742                 InsertTailList(&scm->QueueListHead,
743                                &FoundEntry->ListEntry);
744 
745                 /* signal the lookup event */
746                 SetEvent(scm->LookupEvent);
747 
748                 Ret = TRUE;
749             }
750             else
751             {
752                 /* unable to queue it because we couldn't allocate the callbacks
753                    array, free the memory and return */
754                 HeapFree(scm->Heap,
755                          0,
756                          FoundEntry);
757             }
758         }
759     }
760     else
761     {
762         PSIDCACHECALLBACKINFO Sidccb;
763 
764         /* add the callback */
765         Sidccb = HeapReAlloc(scm->Heap,
766                              0,
767                              FoundEntry->Callbacks,
768                              (FoundEntry->CallbackCount + 1) * sizeof(SIDCACHECALLBACKINFO));
769         if (Sidccb != NULL)
770         {
771             FoundEntry->Callbacks = Sidccb;
772             FoundEntry->Callbacks[FoundEntry->CallbackCount].CompletionProc = CompletionProc;
773             FoundEntry->Callbacks[FoundEntry->CallbackCount++].Context = Context;
774 
775             Ret = TRUE;
776         }
777     }
778 
779     return Ret;
780 }
781 
782 
783 VOID
784 DequeueSidLookup(IN HANDLE SidCacheMgr,
785                  IN PSID pSid)
786 {
787     PLIST_ENTRY CurrentEntry;
788     PSIDQUEUEENTRY QueueEntry;
789     PSIDCACHEMGR scm;
790 
791     scm = ReferenceSidCacheMgr(SidCacheMgr);
792     if (scm != NULL)
793     {
794         EnterCriticalSection(&scm->Lock);
795 
796         if (scm->QueueLookingUp != NULL &&
797             EqualSid(pSid,
798                      (PSID)(scm->QueueLookingUp + 1)))
799         {
800             /* don't free the queue lookup item! this will be
801                done in the lookup thread */
802             scm->QueueLookingUp = NULL;
803         }
804         else
805         {
806             for (CurrentEntry = scm->QueueListHead.Flink;
807                  CurrentEntry != &scm->QueueListHead;
808                  CurrentEntry = CurrentEntry->Flink)
809             {
810                 QueueEntry = CONTAINING_RECORD(CurrentEntry,
811                                                SIDQUEUEENTRY,
812                                                ListEntry);
813 
814                 if (EqualSid(pSid,
815                              (PSID)(QueueEntry + 1)))
816                 {
817                     FreeQueueEntry(scm,
818                                    QueueEntry);
819                     break;
820                 }
821             }
822         }
823 
824         LeaveCriticalSection(&scm->Lock);
825 
826         DereferenceSidCacheMgr(scm);
827     }
828 }
829 
830 
831 VOID
832 ReferenceSidReqResult(IN HANDLE SidCacheMgr,
833                       IN PSIDREQRESULT ReqResult)
834 {
835     PSIDCACHEMGR scm;
836 
837     scm = ReferenceSidCacheMgr(SidCacheMgr);
838     if (scm != NULL)
839     {
840         InterlockedIncrement(&ReqResult->RefCount);
841 
842         DereferenceSidCacheMgr(scm);
843     }
844 }
845 
846 
847 VOID
848 DereferenceSidReqResult(IN HANDLE SidCacheMgr,
849                         IN PSIDREQRESULT ReqResult)
850 {
851     PSIDCACHEMGR scm;
852 
853     scm = ReferenceSidCacheMgr(SidCacheMgr);
854     if (scm != NULL)
855     {
856         if (InterlockedDecrement(&ReqResult->RefCount) == 0)
857         {
858             HeapFree(scm->Heap,
859                      0,
860                      ReqResult);
861         }
862 
863         DereferenceSidCacheMgr(scm);
864     }
865 }
866 
867 
868 BOOL
869 LookupSidCache(IN HANDLE SidCacheMgr,
870                IN PSID pSid,
871                IN PSIDREQCOMPLETIONPROC CompletionProc,
872                IN PVOID Context)
873 {
874     BOOL Found = FALSE;
875     PSIDREQRESULT ReqResult = NULL;
876     PSIDCACHEMGR scm;
877 
878     scm = ReferenceSidCacheMgr(SidCacheMgr);
879     if (scm != NULL)
880     {
881         EnterCriticalSection(&scm->Lock);
882 
883         /* search the cache */
884         Found = FindSidInCache(scm,
885                                pSid,
886                                &ReqResult);
887 
888         if (!Found)
889         {
890             /* the sid is not in the cache, queue it if not already queued */
891             if (!QueueSidLookup(scm,
892                                 pSid,
893                                 CompletionProc,
894                                 Context))
895             {
896                 PSIDREQRESULT FoundReqResult = NULL;
897 
898                 /* unable to queue it, look it up now */
899 
900                 LeaveCriticalSection(&scm->Lock);
901 
902                 /* lookup everything we need */
903                 if (!LookupSidInformation(scm,
904                                           pSid,
905                                           &ReqResult))
906                 {
907                     ReqResult = NULL;
908                 }
909 
910                 EnterCriticalSection(&scm->Lock);
911 
912                 /* see if the SID was added to the cache in the meanwhile */
913                 if (!FindSidInCache(scm,
914                                     pSid,
915                                     &FoundReqResult))
916                 {
917                     if (ReqResult != NULL)
918                     {
919                         /* cache the results */
920                         CacheLookupResults(scm,
921                                            pSid,
922                                            ReqResult);
923                     }
924                 }
925                 else
926                 {
927                     if (ReqResult != NULL)
928                     {
929                         /* free the information of our lookup and use the cached
930                            information*/
931                         DereferenceSidReqResult(scm,
932                                                 ReqResult);
933                     }
934 
935                     ReqResult = FoundReqResult;
936                 }
937 
938                 Found = (ReqResult != NULL);
939             }
940         }
941 
942         LeaveCriticalSection(&scm->Lock);
943 
944         /* call the completion callback */
945         if (Found)
946         {
947             CompletionProc(SidCacheMgr,
948                            pSid,
949                            ReqResult,
950                            Context);
951 
952             if (ReqResult != NULL)
953             {
954                 HeapFree(scm->Heap,
955                          0,
956                          ReqResult);
957             }
958         }
959 
960         DereferenceSidCacheMgr(scm);
961     }
962 
963     return Found;
964 }
965