minor fixes and use a .spec file
[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[wcslen(SystemName) + 1]));
587 if (scm != NULL)
588 {
589 /* zero the static part of the structure */
590 ZeroMemory(scm,
591 sizeof(SIDCACHEMGR));
592
593 scm->RefCount = 1;
594 scm->Heap = Heap;
595
596 wcscpy(scm->SystemName,
597 SystemName);
598
599 InitializeCriticalSection(&scm->Lock);
600 InitializeListHead(&scm->QueueListHead);
601 InitializeListHead(&scm->CacheListHead);
602
603 scm->LookupEvent = CreateEvent(NULL,
604 FALSE,
605 FALSE,
606 NULL);
607 if (scm->LookupEvent == NULL)
608 {
609 goto Cleanup;
610 }
611
612 if (!OpenLSAPolicyHandle(scm->SystemName,
613 POLICY_LOOKUP_NAMES | POLICY_VIEW_LOCAL_INFORMATION,
614 &scm->LsaHandle))
615 {
616 goto Cleanup;
617 }
618
619 scm->LookupThread = CreateThread(NULL,
620 0,
621 LookupThreadProc,
622 scm,
623 0,
624 NULL);
625 if (scm->LookupThread == NULL)
626 {
627 Cleanup:
628 if (scm->LookupEvent != NULL)
629 {
630 CloseHandle(scm->LookupEvent);
631 }
632
633 if (scm->LsaHandle != NULL)
634 {
635 LsaClose(scm->LsaHandle);
636 }
637
638 HeapFree(Heap,
639 0,
640 scm);
641 scm = NULL;
642 }
643 }
644 else
645 {
646 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
647 }
648
649 return (HANDLE)scm;
650 }
651
652
653 VOID
654 DestroySidCacheMgr(IN HANDLE SidCacheMgr)
655 {
656 PSIDCACHEMGR scm = HandleToScm(SidCacheMgr);
657
658 if (scm != NULL)
659 {
660 /* remove the keep-alive reference */
661 DereferenceSidCacheMgr(scm);
662 }
663 }
664
665
666 static BOOL
667 QueueSidLookup(IN PSIDCACHEMGR scm,
668 IN PSID pSid,
669 IN PSIDREQCOMPLETIONPROC CompletionProc,
670 IN PVOID Context)
671 {
672 PLIST_ENTRY CurrentEntry;
673 PSIDQUEUEENTRY QueueEntry, FoundEntry = NULL;
674 BOOL Ret = FALSE;
675
676 /* NOTE: assumes the lists are locked! */
677
678 if (scm->QueueLookingUp != NULL &&
679 EqualSid(pSid,
680 (PSID)(scm->QueueLookingUp + 1)))
681 {
682 FoundEntry = scm->QueueLookingUp;
683 }
684 else
685 {
686 CurrentEntry = &scm->QueueListHead;
687 while (CurrentEntry != &scm->QueueListHead)
688 {
689 QueueEntry = CONTAINING_RECORD(CurrentEntry,
690 SIDQUEUEENTRY,
691 ListEntry);
692
693 if (EqualSid(pSid,
694 (PSID)(QueueEntry + 1)))
695 {
696 FoundEntry = QueueEntry;
697 break;
698 }
699
700 CurrentEntry = CurrentEntry->Flink;
701 }
702 }
703
704 if (FoundEntry == NULL)
705 {
706 DWORD SidLength = GetLengthSid(pSid);
707
708 FoundEntry = HeapAlloc(scm->Heap,
709 0,
710 sizeof(SIDQUEUEENTRY) + SidLength);
711 if (FoundEntry != NULL)
712 {
713 CopySid(SidLength,
714 (PSID)(FoundEntry + 1),
715 pSid);
716
717 FoundEntry->CallbackCount = 1;
718 FoundEntry->Callbacks = HeapAlloc(scm->Heap,
719 0,
720 sizeof(SIDCACHECALLBACKINFO));
721
722 if (FoundEntry->Callbacks != NULL)
723 {
724 FoundEntry->Callbacks[0].CompletionProc = CompletionProc;
725 FoundEntry->Callbacks[0].Context = Context;
726
727 /* append it to the queue */
728 InsertTailList(&scm->QueueListHead,
729 &FoundEntry->ListEntry);
730
731 /* signal the lookup event */
732 SetEvent(scm->LookupEvent);
733
734 Ret = TRUE;
735 }
736 else
737 {
738 /* unable to queue it because we couldn't allocate the callbacks
739 array, free the memory and return */
740 HeapFree(scm->Heap,
741 0,
742 FoundEntry);
743 }
744 }
745 }
746 else
747 {
748 PSIDCACHECALLBACKINFO Sidccb;
749
750 /* add the callback */
751 Sidccb = HeapReAlloc(scm->Heap,
752 0,
753 FoundEntry->Callbacks,
754 (FoundEntry->CallbackCount + 1) * sizeof(SIDCACHECALLBACKINFO));
755 if (Sidccb != NULL)
756 {
757 FoundEntry->Callbacks = Sidccb;
758 FoundEntry->Callbacks[FoundEntry->CallbackCount].CompletionProc = CompletionProc;
759 FoundEntry->Callbacks[FoundEntry->CallbackCount++].Context = Context;
760
761 Ret = TRUE;
762 }
763 }
764
765 return Ret;
766 }
767
768
769 VOID
770 DequeueSidLookup(IN HANDLE SidCacheMgr,
771 IN PSID pSid)
772 {
773 PLIST_ENTRY CurrentEntry;
774 PSIDQUEUEENTRY QueueEntry;
775 PSIDCACHEMGR scm;
776
777 scm = ReferenceSidCacheMgr(SidCacheMgr);
778 if (scm != NULL)
779 {
780 EnterCriticalSection(&scm->Lock);
781
782 if (scm->QueueLookingUp != NULL &&
783 EqualSid(pSid,
784 (PSID)(scm->QueueLookingUp + 1)))
785 {
786 /* don't free the queue lookup item! this will be
787 done in the lookup thread */
788 scm->QueueLookingUp = NULL;
789 }
790 else
791 {
792 CurrentEntry = &scm->QueueListHead;
793 while (CurrentEntry != &scm->QueueListHead)
794 {
795 QueueEntry = CONTAINING_RECORD(CurrentEntry,
796 SIDQUEUEENTRY,
797 ListEntry);
798
799 if (EqualSid(pSid,
800 (PSID)(QueueEntry + 1)))
801 {
802 FreeQueueEntry(scm,
803 QueueEntry);
804 break;
805 }
806
807 CurrentEntry = CurrentEntry->Flink;
808 }
809 }
810
811 LeaveCriticalSection(&scm->Lock);
812
813 DereferenceSidCacheMgr(scm);
814 }
815 }
816
817
818 VOID
819 ReferenceSidReqResult(IN HANDLE SidCacheMgr,
820 IN PSIDREQRESULT ReqResult)
821 {
822 PSIDCACHEMGR scm;
823
824 scm = ReferenceSidCacheMgr(SidCacheMgr);
825 if (scm != NULL)
826 {
827 InterlockedIncrement(&ReqResult->RefCount);
828
829 DereferenceSidCacheMgr(scm);
830 }
831 }
832
833
834 VOID
835 DereferenceSidReqResult(IN HANDLE SidCacheMgr,
836 IN PSIDREQRESULT ReqResult)
837 {
838 PSIDCACHEMGR scm;
839
840 scm = ReferenceSidCacheMgr(SidCacheMgr);
841 if (scm != NULL)
842 {
843 if (InterlockedDecrement(&ReqResult->RefCount) == 0)
844 {
845 HeapFree(scm->Heap,
846 0,
847 ReqResult);
848 }
849
850 DereferenceSidCacheMgr(scm);
851 }
852 }
853
854
855 BOOL
856 LookupSidCache(IN HANDLE SidCacheMgr,
857 IN PSID pSid,
858 IN PSIDREQCOMPLETIONPROC CompletionProc,
859 IN PVOID Context)
860 {
861 BOOL Found = FALSE;
862 PSIDREQRESULT ReqResult = NULL;
863 PSIDCACHEMGR scm;
864
865 scm = ReferenceSidCacheMgr(SidCacheMgr);
866 if (scm != NULL)
867 {
868 EnterCriticalSection(&scm->Lock);
869
870 /* search the cache */
871 Found = FindSidInCache(scm,
872 pSid,
873 &ReqResult);
874
875 if (!Found)
876 {
877 /* the sid is not in the cache, queue it if not already queued */
878 if (!QueueSidLookup(scm,
879 pSid,
880 CompletionProc,
881 Context))
882 {
883 PSIDREQRESULT FoundReqResult = NULL;
884
885 /* unable to queue it, look it up now */
886
887 LeaveCriticalSection(&scm->Lock);
888
889 /* lookup everything we need */
890 if (!LookupSidInformation(scm,
891 pSid,
892 &ReqResult))
893 {
894 ReqResult = NULL;
895 }
896
897 EnterCriticalSection(&scm->Lock);
898
899 /* see if the SID was added to the cache in the meanwhile */
900 if (!FindSidInCache(scm,
901 pSid,
902 &FoundReqResult))
903 {
904 if (ReqResult != NULL)
905 {
906 /* cache the results */
907 CacheLookupResults(scm,
908 pSid,
909 ReqResult);
910 }
911 }
912 else
913 {
914 if (ReqResult != NULL)
915 {
916 /* free the information of our lookup and use the cached
917 information*/
918 DereferenceSidReqResult(scm,
919 ReqResult);
920 }
921
922 ReqResult = FoundReqResult;
923 }
924
925 Found = (ReqResult != NULL);
926 }
927 }
928
929 LeaveCriticalSection(&scm->Lock);
930
931 /* call the completion callback */
932 if (Found)
933 {
934 CompletionProc(SidCacheMgr,
935 pSid,
936 ReqResult,
937 Context);
938
939 if (ReqResult != NULL)
940 {
941 HeapFree(scm->Heap,
942 0,
943 ReqResult);
944 }
945 }
946
947 DereferenceSidCacheMgr(scm);
948 }
949
950 return Found;
951 }