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