Synchronize with trunk r58528.
[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 #include "precomp.h"
29
30 #define NDEBUG
31 #include <debug.h>
32
33 #define HandleToScm(Handle) (PSIDCACHEMGR)(Handle)
34 #define ScmToHandle(Scm) (HANDLE)(Scm)
35
36 typedef struct _SIDCACHEMGR
37 {
38 volatile LONG RefCount;
39 LSA_HANDLE LsaHandle;
40 CRITICAL_SECTION Lock;
41 LIST_ENTRY QueueListHead;
42 struct _SIDQUEUEENTRY *QueueLookingUp;
43 LIST_ENTRY CacheListHead;
44 HANDLE Heap;
45 HANDLE LookupEvent;
46 HANDLE LookupThread;
47 WCHAR SystemName[1];
48 } SIDCACHEMGR, *PSIDCACHEMGR;
49
50
51 typedef struct _SIDCACHECALLBACKINFO
52 {
53 PSIDREQCOMPLETIONPROC CompletionProc;
54 PVOID Context;
55 } SIDCACHECALLBACKINFO, *PSIDCACHECALLBACKINFO;
56
57
58 typedef struct _SIDQUEUEENTRY
59 {
60 LIST_ENTRY ListEntry;
61 ULONG CallbackCount;
62 PSIDCACHECALLBACKINFO Callbacks;
63 /* the SID is appended to this structure */
64 } SIDQUEUEENTRY, *PSIDQUEUEENTRY;
65
66
67 typedef struct _SIDCACHEENTRY
68 {
69 LIST_ENTRY ListEntry;
70 SID_NAME_USE SidNameUse;
71 PWSTR AccountName;
72 PWSTR DomainName;
73 /* the SID and strings are appended to this structure */
74 } SIDCACHEENTRY, *PSIDCACHEENTRY;
75
76
77 static VOID
78 FreeQueueEntry(IN PSIDCACHEMGR scm,
79 IN PSIDQUEUEENTRY QueueEntry)
80 {
81 if (QueueEntry->ListEntry.Flink != NULL)
82 {
83 RemoveEntryList(&QueueEntry->ListEntry);
84 }
85
86 HeapFree(scm->Heap,
87 0,
88 QueueEntry->Callbacks);
89
90 HeapFree(scm->Heap,
91 0,
92 QueueEntry);
93 }
94
95
96 static VOID
97 FreeCacheEntry(IN PSIDCACHEMGR scm,
98 IN PSIDCACHEENTRY CacheEntry)
99 {
100 RemoveEntryList(&CacheEntry->ListEntry);
101
102 HeapFree(scm->Heap,
103 0,
104 CacheEntry);
105 }
106
107
108 static VOID
109 CleanupSidCacheMgr(IN PSIDCACHEMGR scm)
110 {
111 LsaClose(scm->LsaHandle);
112 CloseHandle(scm->LookupEvent);
113 CloseHandle(scm->LookupThread);
114
115 /* delete the queue */
116 while (!IsListEmpty(&scm->QueueListHead))
117 {
118 PSIDQUEUEENTRY QueueEntry;
119
120 QueueEntry = CONTAINING_RECORD(scm->QueueListHead.Flink,
121 SIDQUEUEENTRY,
122 ListEntry);
123 FreeQueueEntry(scm,
124 QueueEntry);
125 }
126
127 /* delete the cache */
128 while (!IsListEmpty(&scm->CacheListHead))
129 {
130 PSIDCACHEENTRY CacheEntry;
131
132 CacheEntry = CONTAINING_RECORD(scm->CacheListHead.Flink,
133 SIDCACHEENTRY,
134 ListEntry);
135 FreeCacheEntry(scm,
136 CacheEntry);
137 }
138
139 DeleteCriticalSection(&scm->Lock);
140 }
141
142
143 static PSIDCACHEMGR
144 ReferenceSidCacheMgr(IN HANDLE SidCacheMgr)
145 {
146 PSIDCACHEMGR scm = HandleToScm(SidCacheMgr);
147
148 if (InterlockedIncrement(&scm->RefCount) != 1)
149 {
150 return scm;
151 }
152
153 return NULL;
154 }
155
156
157 static VOID
158 DereferenceSidCacheMgr(IN PSIDCACHEMGR scm)
159 {
160 if (InterlockedDecrement(&scm->RefCount) == 0)
161 {
162 /* Signal the lookup thread so it can terminate */
163 SetEvent(scm->LookupEvent);
164 }
165 }
166
167
168 static BOOL
169 OpenLSAPolicyHandle(IN LPWSTR SystemName,
170 IN ACCESS_MASK DesiredAccess,
171 OUT PLSA_HANDLE PolicyHandle)
172 {
173 LSA_OBJECT_ATTRIBUTES LsaObjectAttributes = {0};
174 LSA_UNICODE_STRING LsaSystemName, *psn;
175 NTSTATUS Status;
176
177 if (SystemName != NULL && SystemName[0] != L'\0')
178 {
179 LsaSystemName.Buffer = SystemName;
180 LsaSystemName.Length = wcslen(SystemName) * sizeof(WCHAR);
181 LsaSystemName.MaximumLength = LsaSystemName.Length + sizeof(WCHAR);
182 psn = &LsaSystemName;
183 }
184 else
185 {
186 psn = NULL;
187 }
188
189 Status = LsaOpenPolicy(psn,
190 &LsaObjectAttributes,
191 DesiredAccess,
192 PolicyHandle);
193 if (!NT_SUCCESS(Status))
194 {
195 SetLastError(LsaNtStatusToWinError(Status));
196 return FALSE;
197 }
198
199 return TRUE;
200 }
201
202
203 static BOOL
204 LookupSidInformation(IN PSIDCACHEMGR scm,
205 IN PSID pSid,
206 OUT PSIDREQRESULT *ReqResult)
207 {
208 PLSA_REFERENCED_DOMAIN_LIST ReferencedDomain;
209 PLSA_TRANSLATED_NAME Names;
210 PLSA_TRUST_INFORMATION Domain;
211 PLSA_UNICODE_STRING DomainName;
212 SID_NAME_USE SidNameUse = SidTypeUnknown;
213 PPOLICY_ACCOUNT_DOMAIN_INFO PolicyAccountDomainInfo = NULL;
214 NTSTATUS Status;
215 DWORD SidLength, AccountNameSize, DomainNameSize = 0;
216 PSIDREQRESULT ReqRet = NULL;
217 BOOL Ret = FALSE;
218
219 Status = LsaLookupSids(scm->LsaHandle,
220 1,
221 &pSid,
222 &ReferencedDomain,
223 &Names);
224 if (NT_SUCCESS(Status))
225 {
226 SidLength = GetLengthSid(pSid);
227 SidNameUse = Names->Use;
228
229 if (ReferencedDomain != NULL &&
230 Names->DomainIndex >= 0)
231 {
232 Domain = &ReferencedDomain->Domains[Names->DomainIndex];
233 DomainName = &Domain->Name;
234 }
235 else
236 {
237 Domain = NULL;
238 DomainName = NULL;
239 }
240
241 switch (SidNameUse)
242 {
243 case SidTypeAlias:
244 {
245 if (Domain != NULL)
246 {
247 /* query the domain name for BUILTIN accounts */
248 Status = LsaQueryInformationPolicy(scm->LsaHandle,
249 PolicyAccountDomainInformation,
250 (PVOID*)&PolicyAccountDomainInfo);
251 if (NT_SUCCESS(Status))
252 {
253 DomainName = &PolicyAccountDomainInfo->DomainName;
254
255 /* make the user believe this is a group */
256 SidNameUse = (PolicyAccountDomainInfo != NULL ? SidTypeGroup : SidTypeUser);
257 }
258 }
259 break;
260 }
261
262 default:
263 {
264 DPRINT("Unhandled SID type: 0x%x\n", Names->Use);
265 break;
266 }
267 }
268
269 AccountNameSize = Names->Name.Length;
270 if (DomainName != NULL)
271 {
272 DomainNameSize = DomainName->Length;
273 }
274
275 ReqRet = HeapAlloc(scm->Heap,
276 0,
277 sizeof(SIDREQRESULT) +
278 (((AccountNameSize + DomainNameSize) + 2) * sizeof(WCHAR)));
279 if (ReqRet != NULL)
280 {
281 ReqRet->RefCount = 1;
282 ReqRet->AccountName = (LPWSTR)(ReqRet + 1);
283 ReqRet->DomainName = ReqRet->AccountName + (AccountNameSize / sizeof(WCHAR)) + 1;
284
285 CopyMemory(ReqRet->AccountName,
286 Names->Name.Buffer,
287 Names->Name.Length);
288
289 if (DomainName != NULL)
290 {
291 CopyMemory(ReqRet->DomainName,
292 DomainName->Buffer,
293 DomainName->Length);
294 }
295
296 ReqRet->AccountName[AccountNameSize / sizeof(WCHAR)] = L'\0';
297 ReqRet->DomainName[DomainNameSize / sizeof(WCHAR)] = L'\0';
298
299 ReqRet->SidNameUse = SidNameUse;
300 }
301
302 if (PolicyAccountDomainInfo != NULL)
303 {
304 LsaFreeMemory(PolicyAccountDomainInfo);
305 }
306
307 LsaFreeMemory(ReferencedDomain);
308 LsaFreeMemory(Names);
309
310 Ret = TRUE;
311 }
312 else if (Status == STATUS_NONE_MAPPED)
313 {
314 Ret = TRUE;
315 }
316
317 if (Ret)
318 {
319 *ReqResult = ReqRet;
320 }
321
322 return Ret;
323 }
324
325
326 static BOOL
327 FindSidInCache(IN PSIDCACHEMGR scm,
328 IN PSID pSid,
329 OUT PSIDREQRESULT *ReqResult)
330 {
331 PSIDCACHEENTRY CacheEntry;
332 PLIST_ENTRY CurrentEntry;
333 PSIDREQRESULT ReqRes;
334 BOOL Ret = FALSE;
335
336 /* NOTE: assumes the lists are locked! */
337
338 CurrentEntry = &scm->CacheListHead;
339 while (CurrentEntry != &scm->CacheListHead)
340 {
341 CacheEntry = CONTAINING_RECORD(CurrentEntry,
342 SIDCACHEENTRY,
343 ListEntry);
344
345 if (EqualSid(pSid,
346 (PSID)(CacheEntry + 1)))
347 {
348 SIZE_T ReqResultSize;
349 ULONG AccountNameLen, DomainNameLen;
350
351 Ret = TRUE;
352
353 AccountNameLen = wcslen(CacheEntry->AccountName);
354 DomainNameLen = wcslen(CacheEntry->DomainName);
355
356 ReqResultSize = sizeof(SIDREQRESULT) +
357 (((AccountNameLen + 1) +
358 (DomainNameLen + 1)) * sizeof(WCHAR));
359
360 ReqRes = HeapAlloc(scm->Heap,
361 0,
362 ReqResultSize);
363 if (ReqRes != NULL)
364 {
365 PWSTR Buffer = (PWSTR)(ReqRes + 1);
366
367 ReqRes->RefCount = 1;
368
369 ReqRes->AccountName = Buffer;
370 wcscpy(ReqRes->AccountName,
371 CacheEntry->AccountName);
372 Buffer += AccountNameLen + 1;
373
374 ReqRes->DomainName = Buffer;
375 wcscpy(ReqRes->DomainName,
376 CacheEntry->DomainName);
377 }
378
379 /* return the result, even if we weren't unable to
380 allocate enough memory! */
381 *ReqResult = ReqRes;
382 break;
383 }
384
385 CurrentEntry = CurrentEntry->Flink;
386 }
387
388 return Ret;
389 }
390
391
392 static VOID
393 CacheLookupResults(IN PSIDCACHEMGR scm,
394 IN PSID pSid,
395 IN PSIDREQRESULT ReqResult)
396 {
397 PSIDCACHEENTRY CacheEntry;
398 DWORD SidLen;
399 SIZE_T AccountNameLen = 0;
400 SIZE_T DomainNameLen = 0;
401 SIZE_T CacheEntrySize = sizeof(SIDCACHEENTRY);
402
403 /* NOTE: assumes the lists are locked! */
404
405 SidLen = GetLengthSid(pSid);
406 CacheEntrySize += SidLen;
407
408 AccountNameLen = wcslen(ReqResult->AccountName);
409 CacheEntrySize += (AccountNameLen + 1) * sizeof(WCHAR);
410
411 DomainNameLen = wcslen(ReqResult->DomainName);
412 CacheEntrySize += (wcslen(ReqResult->DomainName) + 1) * sizeof(WCHAR);
413
414 CacheEntry = HeapAlloc(scm->Heap,
415 0,
416 CacheEntrySize);
417 if (CacheEntry != NULL)
418 {
419 PWSTR lpBuf = (PWSTR)((ULONG_PTR)(CacheEntry + 1) + SidLen);
420
421 CacheEntry->SidNameUse = ReqResult->SidNameUse;
422
423 /* append the SID */
424 CopySid(SidLen,
425 (PSID)(CacheEntry + 1),
426 pSid);
427
428 /* append the strings */
429 CacheEntry->AccountName = lpBuf;
430 wcscpy(lpBuf,
431 ReqResult->AccountName);
432 lpBuf += AccountNameLen + 1;
433
434 CacheEntry->DomainName = lpBuf;
435 wcscpy(lpBuf,
436 ReqResult->DomainName);
437 lpBuf += DomainNameLen + 1;
438
439 /* add the entry to the cache list */
440 InsertTailList(&scm->CacheListHead,
441 &CacheEntry->ListEntry);
442 }
443 }
444
445
446 static DWORD WINAPI
447 LookupThreadProc(IN LPVOID lpParameter)
448 {
449 HMODULE hModule;
450 PSIDCACHEMGR scm = (PSIDCACHEMGR)lpParameter;
451
452 /* Reference the dll to avoid problems in case of accidental
453 FreeLibrary calls... */
454 if (!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
455 (LPCWSTR)hDllInstance,
456 &hModule))
457 {
458 hModule = NULL;
459 }
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 CleanupSidCacheMgr(scm);
570
571 HeapFree(scm->Heap,
572 0,
573 scm);
574
575 if (hModule != NULL)
576 {
577 /* dereference the library and exit */
578 FreeLibraryAndExitThread(hModule,
579 0);
580 }
581
582 return 0;
583 }
584
585
586
587 HANDLE
588 CreateSidCacheMgr(IN HANDLE Heap,
589 IN LPCWSTR SystemName)
590 {
591 PSIDCACHEMGR scm;
592
593 if (SystemName == NULL)
594 SystemName = L"";
595
596 scm = HeapAlloc(Heap,
597 0,
598 FIELD_OFFSET(SIDCACHEMGR,
599 SystemName[wcslen(SystemName) + 1]));
600 if (scm != NULL)
601 {
602 /* zero the static part of the structure */
603 ZeroMemory(scm,
604 FIELD_OFFSET(SIDCACHEMGR,
605 SystemName));
606
607 scm->RefCount = 1;
608 scm->Heap = Heap;
609
610 wcscpy(scm->SystemName,
611 SystemName);
612
613 InitializeCriticalSection(&scm->Lock);
614 InitializeListHead(&scm->QueueListHead);
615 InitializeListHead(&scm->CacheListHead);
616
617 scm->LookupEvent = CreateEvent(NULL,
618 FALSE,
619 FALSE,
620 NULL);
621 if (scm->LookupEvent == NULL)
622 {
623 goto Cleanup;
624 }
625
626 if (!OpenLSAPolicyHandle(scm->SystemName,
627 POLICY_LOOKUP_NAMES | POLICY_VIEW_LOCAL_INFORMATION,
628 &scm->LsaHandle))
629 {
630 goto Cleanup;
631 }
632
633 scm->LookupThread = CreateThread(NULL,
634 0,
635 LookupThreadProc,
636 scm,
637 0,
638 NULL);
639 if (scm->LookupThread == NULL)
640 {
641 Cleanup:
642 if (scm->LookupEvent != NULL)
643 {
644 CloseHandle(scm->LookupEvent);
645 }
646
647 if (scm->LsaHandle != NULL)
648 {
649 LsaClose(scm->LsaHandle);
650 }
651
652 HeapFree(Heap,
653 0,
654 scm);
655 scm = NULL;
656 }
657 }
658 else
659 {
660 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
661 }
662
663 return (HANDLE)scm;
664 }
665
666
667 VOID
668 DestroySidCacheMgr(IN HANDLE SidCacheMgr)
669 {
670 PSIDCACHEMGR scm = HandleToScm(SidCacheMgr);
671
672 if (scm != NULL)
673 {
674 /* remove the keep-alive reference */
675 DereferenceSidCacheMgr(scm);
676 }
677 }
678
679
680 static BOOL
681 QueueSidLookup(IN PSIDCACHEMGR scm,
682 IN PSID pSid,
683 IN PSIDREQCOMPLETIONPROC CompletionProc,
684 IN PVOID Context)
685 {
686 PLIST_ENTRY CurrentEntry;
687 PSIDQUEUEENTRY QueueEntry, FoundEntry = NULL;
688 BOOL Ret = FALSE;
689
690 /* NOTE: assumes the lists are locked! */
691
692 if (scm->QueueLookingUp != NULL &&
693 EqualSid(pSid,
694 (PSID)(scm->QueueLookingUp + 1)))
695 {
696 FoundEntry = scm->QueueLookingUp;
697 }
698 else
699 {
700 CurrentEntry = &scm->QueueListHead;
701 while (CurrentEntry != &scm->QueueListHead)
702 {
703 QueueEntry = CONTAINING_RECORD(CurrentEntry,
704 SIDQUEUEENTRY,
705 ListEntry);
706
707 if (EqualSid(pSid,
708 (PSID)(QueueEntry + 1)))
709 {
710 FoundEntry = QueueEntry;
711 break;
712 }
713
714 CurrentEntry = CurrentEntry->Flink;
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 CurrentEntry = &scm->QueueListHead;
807 while (CurrentEntry != &scm->QueueListHead)
808 {
809 QueueEntry = CONTAINING_RECORD(CurrentEntry,
810 SIDQUEUEENTRY,
811 ListEntry);
812
813 if (EqualSid(pSid,
814 (PSID)(QueueEntry + 1)))
815 {
816 FreeQueueEntry(scm,
817 QueueEntry);
818 break;
819 }
820
821 CurrentEntry = CurrentEntry->Flink;
822 }
823 }
824
825 LeaveCriticalSection(&scm->Lock);
826
827 DereferenceSidCacheMgr(scm);
828 }
829 }
830
831
832 VOID
833 ReferenceSidReqResult(IN HANDLE SidCacheMgr,
834 IN PSIDREQRESULT ReqResult)
835 {
836 PSIDCACHEMGR scm;
837
838 scm = ReferenceSidCacheMgr(SidCacheMgr);
839 if (scm != NULL)
840 {
841 InterlockedIncrement(&ReqResult->RefCount);
842
843 DereferenceSidCacheMgr(scm);
844 }
845 }
846
847
848 VOID
849 DereferenceSidReqResult(IN HANDLE SidCacheMgr,
850 IN PSIDREQRESULT ReqResult)
851 {
852 PSIDCACHEMGR scm;
853
854 scm = ReferenceSidCacheMgr(SidCacheMgr);
855 if (scm != NULL)
856 {
857 if (InterlockedDecrement(&ReqResult->RefCount) == 0)
858 {
859 HeapFree(scm->Heap,
860 0,
861 ReqResult);
862 }
863
864 DereferenceSidCacheMgr(scm);
865 }
866 }
867
868
869 BOOL
870 LookupSidCache(IN HANDLE SidCacheMgr,
871 IN PSID pSid,
872 IN PSIDREQCOMPLETIONPROC CompletionProc,
873 IN PVOID Context)
874 {
875 BOOL Found = FALSE;
876 PSIDREQRESULT ReqResult = NULL;
877 PSIDCACHEMGR scm;
878
879 scm = ReferenceSidCacheMgr(SidCacheMgr);
880 if (scm != NULL)
881 {
882 EnterCriticalSection(&scm->Lock);
883
884 /* search the cache */
885 Found = FindSidInCache(scm,
886 pSid,
887 &ReqResult);
888
889 if (!Found)
890 {
891 /* the sid is not in the cache, queue it if not already queued */
892 if (!QueueSidLookup(scm,
893 pSid,
894 CompletionProc,
895 Context))
896 {
897 PSIDREQRESULT FoundReqResult = NULL;
898
899 /* unable to queue it, look it up now */
900
901 LeaveCriticalSection(&scm->Lock);
902
903 /* lookup everything we need */
904 if (!LookupSidInformation(scm,
905 pSid,
906 &ReqResult))
907 {
908 ReqResult = NULL;
909 }
910
911 EnterCriticalSection(&scm->Lock);
912
913 /* see if the SID was added to the cache in the meanwhile */
914 if (!FindSidInCache(scm,
915 pSid,
916 &FoundReqResult))
917 {
918 if (ReqResult != NULL)
919 {
920 /* cache the results */
921 CacheLookupResults(scm,
922 pSid,
923 ReqResult);
924 }
925 }
926 else
927 {
928 if (ReqResult != NULL)
929 {
930 /* free the information of our lookup and use the cached
931 information*/
932 DereferenceSidReqResult(scm,
933 ReqResult);
934 }
935
936 ReqResult = FoundReqResult;
937 }
938
939 Found = (ReqResult != NULL);
940 }
941 }
942
943 LeaveCriticalSection(&scm->Lock);
944
945 /* call the completion callback */
946 if (Found)
947 {
948 CompletionProc(SidCacheMgr,
949 pSid,
950 ReqResult,
951 Context);
952
953 if (ReqResult != NULL)
954 {
955 HeapFree(scm->Heap,
956 0,
957 ReqResult);
958 }
959 }
960
961 DereferenceSidCacheMgr(scm);
962 }
963
964 return Found;
965 }