Sync with trunk r63174.
[reactos.git] / dll / win32 / 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., 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 CurrentEntry = &scm->CacheListHead;
341 while (CurrentEntry != &scm->CacheListHead)
342 {
343 CacheEntry = CONTAINING_RECORD(CurrentEntry,
344 SIDCACHEENTRY,
345 ListEntry);
346
347 if (EqualSid(pSid,
348 (PSID)(CacheEntry + 1)))
349 {
350 SIZE_T ReqResultSize;
351 ULONG AccountNameLen, DomainNameLen;
352
353 Ret = TRUE;
354
355 AccountNameLen = wcslen(CacheEntry->AccountName);
356 DomainNameLen = wcslen(CacheEntry->DomainName);
357
358 ReqResultSize = sizeof(SIDREQRESULT) +
359 (((AccountNameLen + 1) +
360 (DomainNameLen + 1)) * sizeof(WCHAR));
361
362 ReqRes = HeapAlloc(scm->Heap,
363 0,
364 ReqResultSize);
365 if (ReqRes != NULL)
366 {
367 PWSTR Buffer = (PWSTR)(ReqRes + 1);
368
369 ReqRes->RefCount = 1;
370
371 ReqRes->AccountName = Buffer;
372 wcscpy(ReqRes->AccountName,
373 CacheEntry->AccountName);
374 Buffer += AccountNameLen + 1;
375
376 ReqRes->DomainName = Buffer;
377 wcscpy(ReqRes->DomainName,
378 CacheEntry->DomainName);
379 }
380
381 /* return the result, even if we weren't unable to
382 allocate enough memory! */
383 *ReqResult = ReqRes;
384 break;
385 }
386
387 CurrentEntry = CurrentEntry->Flink;
388 }
389
390 return Ret;
391 }
392
393
394 static VOID
395 CacheLookupResults(IN PSIDCACHEMGR scm,
396 IN PSID pSid,
397 IN PSIDREQRESULT ReqResult)
398 {
399 PSIDCACHEENTRY CacheEntry;
400 DWORD SidLen;
401 SIZE_T AccountNameLen = 0;
402 SIZE_T DomainNameLen = 0;
403 SIZE_T CacheEntrySize = sizeof(SIDCACHEENTRY);
404
405 /* NOTE: assumes the lists are locked! */
406
407 SidLen = GetLengthSid(pSid);
408 CacheEntrySize += SidLen;
409
410 AccountNameLen = wcslen(ReqResult->AccountName);
411 CacheEntrySize += (AccountNameLen + 1) * sizeof(WCHAR);
412
413 DomainNameLen = wcslen(ReqResult->DomainName);
414 CacheEntrySize += (wcslen(ReqResult->DomainName) + 1) * sizeof(WCHAR);
415
416 CacheEntry = HeapAlloc(scm->Heap,
417 0,
418 CacheEntrySize);
419 if (CacheEntry != NULL)
420 {
421 PWSTR lpBuf = (PWSTR)((ULONG_PTR)(CacheEntry + 1) + SidLen);
422
423 CacheEntry->SidNameUse = ReqResult->SidNameUse;
424
425 /* append the SID */
426 CopySid(SidLen,
427 (PSID)(CacheEntry + 1),
428 pSid);
429
430 /* append the strings */
431 CacheEntry->AccountName = lpBuf;
432 wcscpy(lpBuf,
433 ReqResult->AccountName);
434 lpBuf += AccountNameLen + 1;
435
436 CacheEntry->DomainName = lpBuf;
437 wcscpy(lpBuf,
438 ReqResult->DomainName);
439 lpBuf += DomainNameLen + 1;
440
441 /* add the entry to the cache list */
442 InsertTailList(&scm->CacheListHead,
443 &CacheEntry->ListEntry);
444 }
445 }
446
447
448 static DWORD WINAPI
449 LookupThreadProc(IN LPVOID lpParameter)
450 {
451 HMODULE hModule;
452 PSIDCACHEMGR scm = (PSIDCACHEMGR)lpParameter;
453
454 /* Reference the dll to avoid problems in case of accidental
455 FreeLibrary calls... */
456 if (!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
457 (LPCWSTR)hDllInstance,
458 &hModule))
459 {
460 hModule = NULL;
461 }
462
463 while (scm->RefCount != 0)
464 {
465 PSIDQUEUEENTRY QueueEntry = NULL;
466
467 EnterCriticalSection(&scm->Lock);
468
469 /* get the first item of the queue */
470 if (scm->QueueListHead.Flink != &scm->QueueListHead)
471 {
472 QueueEntry = CONTAINING_RECORD(scm->QueueListHead.Flink,
473 SIDQUEUEENTRY,
474 ListEntry);
475 RemoveEntryList(&QueueEntry->ListEntry);
476 QueueEntry->ListEntry.Flink = NULL;
477 }
478 else
479 {
480 LeaveCriticalSection(&scm->Lock);
481
482 /* wait for the next asynchronous lookup queued */
483 WaitForSingleObject(scm->LookupEvent,
484 INFINITE);
485 continue;
486 }
487
488 scm->QueueLookingUp = QueueEntry;
489
490 LeaveCriticalSection(&scm->Lock);
491
492 if (QueueEntry != NULL)
493 {
494 PSIDREQRESULT ReqResult, FoundReqResult;
495 PSID pSid = (PSID)(QueueEntry + 1);
496
497 /* lookup the SID information */
498 if (!LookupSidInformation(scm,
499 pSid,
500 &ReqResult))
501 {
502 ReqResult = NULL;
503 }
504
505 EnterCriticalSection(&scm->Lock);
506
507 /* see if the SID was added to the cache in the meanwhile */
508 if (!FindSidInCache(scm,
509 pSid,
510 &FoundReqResult))
511 {
512 if (ReqResult != NULL)
513 {
514 /* cache the results */
515 CacheLookupResults(scm,
516 pSid,
517 ReqResult);
518 }
519 }
520 else
521 {
522 if (ReqResult != NULL)
523 {
524 /* free the information of our lookup and use the cached
525 information*/
526 DereferenceSidReqResult(scm,
527 ReqResult);
528 }
529
530 ReqResult = FoundReqResult;
531 }
532
533 /* notify the callers unless the lookup was cancelled */
534 if (scm->QueueLookingUp != NULL)
535 {
536 ULONG i = 0;
537
538 while (scm->QueueLookingUp != NULL &&
539 i < QueueEntry->CallbackCount)
540 {
541 PVOID Context;
542 PSIDREQCOMPLETIONPROC CompletionProc;
543
544 Context = QueueEntry->Callbacks[i].Context;
545 CompletionProc = QueueEntry->Callbacks[i].CompletionProc;
546
547 LeaveCriticalSection(&scm->Lock);
548
549 /* call the completion proc without holding the lock! */
550 CompletionProc(ScmToHandle(scm),
551 pSid,
552 ReqResult,
553 Context);
554
555 EnterCriticalSection(&scm->Lock);
556
557 i++;
558 }
559
560 scm->QueueLookingUp = NULL;
561 }
562
563 LeaveCriticalSection(&scm->Lock);
564
565 /* free the queue item */
566 FreeQueueEntry(scm,
567 QueueEntry);
568 }
569 }
570
571 CleanupSidCacheMgr(scm);
572
573 HeapFree(scm->Heap,
574 0,
575 scm);
576
577 if (hModule != NULL)
578 {
579 /* dereference the library and exit */
580 FreeLibraryAndExitThread(hModule,
581 0);
582 }
583
584 return 0;
585 }
586
587
588
589 HANDLE
590 CreateSidCacheMgr(IN HANDLE Heap,
591 IN LPCWSTR SystemName)
592 {
593 PSIDCACHEMGR scm;
594
595 if (SystemName == NULL)
596 SystemName = L"";
597
598 scm = HeapAlloc(Heap,
599 0,
600 FIELD_OFFSET(SIDCACHEMGR,
601 SystemName[wcslen(SystemName) + 1]));
602 if (scm != NULL)
603 {
604 /* zero the static part of the structure */
605 ZeroMemory(scm,
606 FIELD_OFFSET(SIDCACHEMGR,
607 SystemName));
608
609 scm->RefCount = 1;
610 scm->Heap = Heap;
611
612 wcscpy(scm->SystemName,
613 SystemName);
614
615 InitializeCriticalSection(&scm->Lock);
616 InitializeListHead(&scm->QueueListHead);
617 InitializeListHead(&scm->CacheListHead);
618
619 scm->LookupEvent = CreateEvent(NULL,
620 FALSE,
621 FALSE,
622 NULL);
623 if (scm->LookupEvent == NULL)
624 {
625 goto Cleanup;
626 }
627
628 if (!OpenLSAPolicyHandle(scm->SystemName,
629 POLICY_LOOKUP_NAMES | POLICY_VIEW_LOCAL_INFORMATION,
630 &scm->LsaHandle))
631 {
632 goto Cleanup;
633 }
634
635 scm->LookupThread = CreateThread(NULL,
636 0,
637 LookupThreadProc,
638 scm,
639 0,
640 NULL);
641 if (scm->LookupThread == NULL)
642 {
643 Cleanup:
644 if (scm->LookupEvent != NULL)
645 {
646 CloseHandle(scm->LookupEvent);
647 }
648
649 if (scm->LsaHandle != NULL)
650 {
651 LsaClose(scm->LsaHandle);
652 }
653
654 HeapFree(Heap,
655 0,
656 scm);
657 scm = NULL;
658 }
659 }
660 else
661 {
662 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
663 }
664
665 return (HANDLE)scm;
666 }
667
668
669 VOID
670 DestroySidCacheMgr(IN HANDLE SidCacheMgr)
671 {
672 PSIDCACHEMGR scm = HandleToScm(SidCacheMgr);
673
674 if (scm != NULL)
675 {
676 /* remove the keep-alive reference */
677 DereferenceSidCacheMgr(scm);
678 }
679 }
680
681
682 static BOOL
683 QueueSidLookup(IN PSIDCACHEMGR scm,
684 IN PSID pSid,
685 IN PSIDREQCOMPLETIONPROC CompletionProc,
686 IN PVOID Context)
687 {
688 PLIST_ENTRY CurrentEntry;
689 PSIDQUEUEENTRY QueueEntry, FoundEntry = NULL;
690 BOOL Ret = FALSE;
691
692 /* NOTE: assumes the lists are locked! */
693
694 if (scm->QueueLookingUp != NULL &&
695 EqualSid(pSid,
696 (PSID)(scm->QueueLookingUp + 1)))
697 {
698 FoundEntry = scm->QueueLookingUp;
699 }
700 else
701 {
702 CurrentEntry = &scm->QueueListHead;
703 while (CurrentEntry != &scm->QueueListHead)
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 CurrentEntry = CurrentEntry->Flink;
717 }
718 }
719
720 if (FoundEntry == NULL)
721 {
722 DWORD SidLength = GetLengthSid(pSid);
723
724 FoundEntry = HeapAlloc(scm->Heap,
725 0,
726 sizeof(SIDQUEUEENTRY) + SidLength);
727 if (FoundEntry != NULL)
728 {
729 CopySid(SidLength,
730 (PSID)(FoundEntry + 1),
731 pSid);
732
733 FoundEntry->CallbackCount = 1;
734 FoundEntry->Callbacks = HeapAlloc(scm->Heap,
735 0,
736 sizeof(SIDCACHECALLBACKINFO));
737
738 if (FoundEntry->Callbacks != NULL)
739 {
740 FoundEntry->Callbacks[0].CompletionProc = CompletionProc;
741 FoundEntry->Callbacks[0].Context = Context;
742
743 /* append it to the queue */
744 InsertTailList(&scm->QueueListHead,
745 &FoundEntry->ListEntry);
746
747 /* signal the lookup event */
748 SetEvent(scm->LookupEvent);
749
750 Ret = TRUE;
751 }
752 else
753 {
754 /* unable to queue it because we couldn't allocate the callbacks
755 array, free the memory and return */
756 HeapFree(scm->Heap,
757 0,
758 FoundEntry);
759 }
760 }
761 }
762 else
763 {
764 PSIDCACHECALLBACKINFO Sidccb;
765
766 /* add the callback */
767 Sidccb = HeapReAlloc(scm->Heap,
768 0,
769 FoundEntry->Callbacks,
770 (FoundEntry->CallbackCount + 1) * sizeof(SIDCACHECALLBACKINFO));
771 if (Sidccb != NULL)
772 {
773 FoundEntry->Callbacks = Sidccb;
774 FoundEntry->Callbacks[FoundEntry->CallbackCount].CompletionProc = CompletionProc;
775 FoundEntry->Callbacks[FoundEntry->CallbackCount++].Context = Context;
776
777 Ret = TRUE;
778 }
779 }
780
781 return Ret;
782 }
783
784
785 VOID
786 DequeueSidLookup(IN HANDLE SidCacheMgr,
787 IN PSID pSid)
788 {
789 PLIST_ENTRY CurrentEntry;
790 PSIDQUEUEENTRY QueueEntry;
791 PSIDCACHEMGR scm;
792
793 scm = ReferenceSidCacheMgr(SidCacheMgr);
794 if (scm != NULL)
795 {
796 EnterCriticalSection(&scm->Lock);
797
798 if (scm->QueueLookingUp != NULL &&
799 EqualSid(pSid,
800 (PSID)(scm->QueueLookingUp + 1)))
801 {
802 /* don't free the queue lookup item! this will be
803 done in the lookup thread */
804 scm->QueueLookingUp = NULL;
805 }
806 else
807 {
808 CurrentEntry = &scm->QueueListHead;
809 while (CurrentEntry != &scm->QueueListHead)
810 {
811 QueueEntry = CONTAINING_RECORD(CurrentEntry,
812 SIDQUEUEENTRY,
813 ListEntry);
814
815 if (EqualSid(pSid,
816 (PSID)(QueueEntry + 1)))
817 {
818 FreeQueueEntry(scm,
819 QueueEntry);
820 break;
821 }
822
823 CurrentEntry = CurrentEntry->Flink;
824 }
825 }
826
827 LeaveCriticalSection(&scm->Lock);
828
829 DereferenceSidCacheMgr(scm);
830 }
831 }
832
833
834 VOID
835 ReferenceSidReqResult(IN HANDLE SidCacheMgr,
836 IN PSIDREQRESULT ReqResult)
837 {
838 PSIDCACHEMGR scm;
839
840 scm = ReferenceSidCacheMgr(SidCacheMgr);
841 if (scm != NULL)
842 {
843 InterlockedIncrement(&ReqResult->RefCount);
844
845 DereferenceSidCacheMgr(scm);
846 }
847 }
848
849
850 VOID
851 DereferenceSidReqResult(IN HANDLE SidCacheMgr,
852 IN PSIDREQRESULT ReqResult)
853 {
854 PSIDCACHEMGR scm;
855
856 scm = ReferenceSidCacheMgr(SidCacheMgr);
857 if (scm != NULL)
858 {
859 if (InterlockedDecrement(&ReqResult->RefCount) == 0)
860 {
861 HeapFree(scm->Heap,
862 0,
863 ReqResult);
864 }
865
866 DereferenceSidCacheMgr(scm);
867 }
868 }
869
870
871 BOOL
872 LookupSidCache(IN HANDLE SidCacheMgr,
873 IN PSID pSid,
874 IN PSIDREQCOMPLETIONPROC CompletionProc,
875 IN PVOID Context)
876 {
877 BOOL Found = FALSE;
878 PSIDREQRESULT ReqResult = NULL;
879 PSIDCACHEMGR scm;
880
881 scm = ReferenceSidCacheMgr(SidCacheMgr);
882 if (scm != NULL)
883 {
884 EnterCriticalSection(&scm->Lock);
885
886 /* search the cache */
887 Found = FindSidInCache(scm,
888 pSid,
889 &ReqResult);
890
891 if (!Found)
892 {
893 /* the sid is not in the cache, queue it if not already queued */
894 if (!QueueSidLookup(scm,
895 pSid,
896 CompletionProc,
897 Context))
898 {
899 PSIDREQRESULT FoundReqResult = NULL;
900
901 /* unable to queue it, look it up now */
902
903 LeaveCriticalSection(&scm->Lock);
904
905 /* lookup everything we need */
906 if (!LookupSidInformation(scm,
907 pSid,
908 &ReqResult))
909 {
910 ReqResult = NULL;
911 }
912
913 EnterCriticalSection(&scm->Lock);
914
915 /* see if the SID was added to the cache in the meanwhile */
916 if (!FindSidInCache(scm,
917 pSid,
918 &FoundReqResult))
919 {
920 if (ReqResult != NULL)
921 {
922 /* cache the results */
923 CacheLookupResults(scm,
924 pSid,
925 ReqResult);
926 }
927 }
928 else
929 {
930 if (ReqResult != NULL)
931 {
932 /* free the information of our lookup and use the cached
933 information*/
934 DereferenceSidReqResult(scm,
935 ReqResult);
936 }
937
938 ReqResult = FoundReqResult;
939 }
940
941 Found = (ReqResult != NULL);
942 }
943 }
944
945 LeaveCriticalSection(&scm->Lock);
946
947 /* call the completion callback */
948 if (Found)
949 {
950 CompletionProc(SidCacheMgr,
951 pSid,
952 ReqResult,
953 Context);
954
955 if (ReqResult != NULL)
956 {
957 HeapFree(scm->Heap,
958 0,
959 ReqResult);
960 }
961 }
962
963 DereferenceSidCacheMgr(scm);
964 }
965
966 return Found;
967 }