c5f49208947df2378811403960b7da5ea5f4885b
[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., 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 volatile 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 LsaClose(scm->LsaHandle);
113 CloseHandle(scm->LookupEvent);
114 CloseHandle(scm->LookupThread);
115
116 /* delete the queue */
117 while (!IsListEmpty(&scm->QueueListHead))
118 {
119 PSIDQUEUEENTRY QueueEntry;
120
121 QueueEntry = CONTAINING_RECORD(scm->QueueListHead.Flink,
122 SIDQUEUEENTRY,
123 ListEntry);
124 FreeQueueEntry(scm,
125 QueueEntry);
126 }
127
128 /* delete the cache */
129 while (!IsListEmpty(&scm->CacheListHead))
130 {
131 PSIDCACHEENTRY CacheEntry;
132
133 CacheEntry = CONTAINING_RECORD(scm->CacheListHead.Flink,
134 SIDCACHEENTRY,
135 ListEntry);
136 FreeCacheEntry(scm,
137 CacheEntry);
138 }
139
140 DeleteCriticalSection(&scm->Lock);
141 }
142
143
144 static PSIDCACHEMGR
145 ReferenceSidCacheMgr(IN HANDLE SidCacheMgr)
146 {
147 PSIDCACHEMGR scm = HandleToScm(SidCacheMgr);
148
149 if (InterlockedIncrement(&scm->RefCount) != 1)
150 {
151 return scm;
152 }
153
154 return NULL;
155 }
156
157
158 static VOID
159 DereferenceSidCacheMgr(IN PSIDCACHEMGR scm)
160 {
161 if (InterlockedDecrement(&scm->RefCount) == 0)
162 {
163 /* Signal the lookup thread so it can terminate */
164 SetEvent(scm->LookupEvent);
165 }
166 }
167
168
169 static BOOL
170 OpenLSAPolicyHandle(IN LPWSTR SystemName,
171 IN ACCESS_MASK DesiredAccess,
172 OUT PLSA_HANDLE PolicyHandle)
173 {
174 LSA_OBJECT_ATTRIBUTES LsaObjectAttributes = {0};
175 LSA_UNICODE_STRING LsaSystemName, *psn;
176 NTSTATUS Status;
177
178 if (SystemName != NULL && SystemName[0] != L'\0')
179 {
180 LsaSystemName.Buffer = SystemName;
181 LsaSystemName.Length = (USHORT)(wcslen(SystemName) * sizeof(WCHAR)); /* FIXME: possible overflow */
182 LsaSystemName.MaximumLength = LsaSystemName.Length + sizeof(WCHAR);
183 psn = &LsaSystemName;
184 }
185 else
186 {
187 psn = NULL;
188 }
189
190 Status = LsaOpenPolicy(psn,
191 &LsaObjectAttributes,
192 DesiredAccess,
193 PolicyHandle);
194 if (!NT_SUCCESS(Status))
195 {
196 SetLastError(LsaNtStatusToWinError(Status));
197 return FALSE;
198 }
199
200 return TRUE;
201 }
202
203
204 static BOOL
205 LookupSidInformation(IN PSIDCACHEMGR scm,
206 IN PSID pSid,
207 OUT PSIDREQRESULT *ReqResult)
208 {
209 PLSA_REFERENCED_DOMAIN_LIST ReferencedDomain;
210 PLSA_TRANSLATED_NAME Names;
211 PLSA_TRUST_INFORMATION Domain;
212 PLSA_UNICODE_STRING DomainName;
213 SID_NAME_USE SidNameUse = SidTypeUnknown;
214 PPOLICY_ACCOUNT_DOMAIN_INFO PolicyAccountDomainInfo = NULL;
215 NTSTATUS Status;
216 DWORD SidLength, AccountNameSize, DomainNameSize = 0;
217 PSIDREQRESULT ReqRet = NULL;
218 BOOL Ret = FALSE;
219
220 Status = LsaLookupSids(scm->LsaHandle,
221 1,
222 &pSid,
223 &ReferencedDomain,
224 &Names);
225 if (NT_SUCCESS(Status))
226 {
227 SidLength = GetLengthSid(pSid);
228 SidNameUse = Names->Use;
229
230 if (ReferencedDomain != NULL &&
231 Names->DomainIndex >= 0)
232 {
233 Domain = &ReferencedDomain->Domains[Names->DomainIndex];
234 DomainName = &Domain->Name;
235 }
236 else
237 {
238 Domain = NULL;
239 DomainName = NULL;
240 }
241
242 switch (SidNameUse)
243 {
244 case SidTypeAlias:
245 {
246 if (Domain != NULL)
247 {
248 /* query the domain name for BUILTIN accounts */
249 Status = LsaQueryInformationPolicy(scm->LsaHandle,
250 PolicyAccountDomainInformation,
251 (PVOID*)&PolicyAccountDomainInfo);
252 if (NT_SUCCESS(Status))
253 {
254 DomainName = &PolicyAccountDomainInfo->DomainName;
255
256 /* make the user believe this is a group */
257 SidNameUse = (PolicyAccountDomainInfo != NULL ? SidTypeGroup : SidTypeUser);
258 }
259 }
260 break;
261 }
262
263 default:
264 {
265 DPRINT("Unhandled SID type: 0x%x\n", Names->Use);
266 break;
267 }
268 }
269
270 AccountNameSize = Names->Name.Length;
271 if (DomainName != NULL)
272 {
273 DomainNameSize = DomainName->Length;
274 }
275
276 ReqRet = HeapAlloc(scm->Heap,
277 0,
278 sizeof(SIDREQRESULT) +
279 (((AccountNameSize + DomainNameSize) + 2) * sizeof(WCHAR)));
280 if (ReqRet != NULL)
281 {
282 ReqRet->RefCount = 1;
283 ReqRet->AccountName = (LPWSTR)(ReqRet + 1);
284 ReqRet->DomainName = ReqRet->AccountName + (AccountNameSize / sizeof(WCHAR)) + 1;
285
286 CopyMemory(ReqRet->AccountName,
287 Names->Name.Buffer,
288 Names->Name.Length);
289
290 if (DomainName != NULL)
291 {
292 CopyMemory(ReqRet->DomainName,
293 DomainName->Buffer,
294 DomainName->Length);
295 }
296
297 ReqRet->AccountName[AccountNameSize / sizeof(WCHAR)] = L'\0';
298 ReqRet->DomainName[DomainNameSize / sizeof(WCHAR)] = L'\0';
299
300 ReqRet->SidNameUse = SidNameUse;
301 }
302
303 if (PolicyAccountDomainInfo != NULL)
304 {
305 LsaFreeMemory(PolicyAccountDomainInfo);
306 }
307
308 LsaFreeMemory(ReferencedDomain);
309 LsaFreeMemory(Names);
310
311 Ret = TRUE;
312 }
313 else if (Status == STATUS_NONE_MAPPED)
314 {
315 Ret = TRUE;
316 }
317
318 if (Ret)
319 {
320 *ReqResult = ReqRet;
321 }
322
323 return Ret;
324 }
325
326
327 static BOOL
328 FindSidInCache(IN PSIDCACHEMGR scm,
329 IN PSID pSid,
330 OUT PSIDREQRESULT *ReqResult)
331 {
332 PSIDCACHEENTRY CacheEntry;
333 PLIST_ENTRY CurrentEntry;
334 PSIDREQRESULT ReqRes;
335 BOOL Ret = FALSE;
336
337 /* NOTE: assumes the lists are locked! */
338
339 CurrentEntry = &scm->CacheListHead;
340 while (CurrentEntry != &scm->CacheListHead)
341 {
342 CacheEntry = CONTAINING_RECORD(CurrentEntry,
343 SIDCACHEENTRY,
344 ListEntry);
345
346 if (EqualSid(pSid,
347 (PSID)(CacheEntry + 1)))
348 {
349 SIZE_T ReqResultSize;
350 ULONG AccountNameLen, DomainNameLen;
351
352 Ret = TRUE;
353
354 AccountNameLen = wcslen(CacheEntry->AccountName);
355 DomainNameLen = wcslen(CacheEntry->DomainName);
356
357 ReqResultSize = sizeof(SIDREQRESULT) +
358 (((AccountNameLen + 1) +
359 (DomainNameLen + 1)) * sizeof(WCHAR));
360
361 ReqRes = HeapAlloc(scm->Heap,
362 0,
363 ReqResultSize);
364 if (ReqRes != NULL)
365 {
366 PWSTR Buffer = (PWSTR)(ReqRes + 1);
367
368 ReqRes->RefCount = 1;
369
370 ReqRes->AccountName = Buffer;
371 wcscpy(ReqRes->AccountName,
372 CacheEntry->AccountName);
373 Buffer += AccountNameLen + 1;
374
375 ReqRes->DomainName = Buffer;
376 wcscpy(ReqRes->DomainName,
377 CacheEntry->DomainName);
378 }
379
380 /* return the result, even if we weren't unable to
381 allocate enough memory! */
382 *ReqResult = ReqRes;
383 break;
384 }
385
386 CurrentEntry = CurrentEntry->Flink;
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 CurrentEntry = &scm->QueueListHead;
702 while (CurrentEntry != &scm->QueueListHead)
703 {
704 QueueEntry = CONTAINING_RECORD(CurrentEntry,
705 SIDQUEUEENTRY,
706 ListEntry);
707
708 if (EqualSid(pSid,
709 (PSID)(QueueEntry + 1)))
710 {
711 FoundEntry = QueueEntry;
712 break;
713 }
714
715 CurrentEntry = CurrentEntry->Flink;
716 }
717 }
718
719 if (FoundEntry == NULL)
720 {
721 DWORD SidLength = GetLengthSid(pSid);
722
723 FoundEntry = HeapAlloc(scm->Heap,
724 0,
725 sizeof(SIDQUEUEENTRY) + SidLength);
726 if (FoundEntry != NULL)
727 {
728 CopySid(SidLength,
729 (PSID)(FoundEntry + 1),
730 pSid);
731
732 FoundEntry->CallbackCount = 1;
733 FoundEntry->Callbacks = HeapAlloc(scm->Heap,
734 0,
735 sizeof(SIDCACHECALLBACKINFO));
736
737 if (FoundEntry->Callbacks != NULL)
738 {
739 FoundEntry->Callbacks[0].CompletionProc = CompletionProc;
740 FoundEntry->Callbacks[0].Context = Context;
741
742 /* append it to the queue */
743 InsertTailList(&scm->QueueListHead,
744 &FoundEntry->ListEntry);
745
746 /* signal the lookup event */
747 SetEvent(scm->LookupEvent);
748
749 Ret = TRUE;
750 }
751 else
752 {
753 /* unable to queue it because we couldn't allocate the callbacks
754 array, free the memory and return */
755 HeapFree(scm->Heap,
756 0,
757 FoundEntry);
758 }
759 }
760 }
761 else
762 {
763 PSIDCACHECALLBACKINFO Sidccb;
764
765 /* add the callback */
766 Sidccb = HeapReAlloc(scm->Heap,
767 0,
768 FoundEntry->Callbacks,
769 (FoundEntry->CallbackCount + 1) * sizeof(SIDCACHECALLBACKINFO));
770 if (Sidccb != NULL)
771 {
772 FoundEntry->Callbacks = Sidccb;
773 FoundEntry->Callbacks[FoundEntry->CallbackCount].CompletionProc = CompletionProc;
774 FoundEntry->Callbacks[FoundEntry->CallbackCount++].Context = Context;
775
776 Ret = TRUE;
777 }
778 }
779
780 return Ret;
781 }
782
783
784 VOID
785 DequeueSidLookup(IN HANDLE SidCacheMgr,
786 IN PSID pSid)
787 {
788 PLIST_ENTRY CurrentEntry;
789 PSIDQUEUEENTRY QueueEntry;
790 PSIDCACHEMGR scm;
791
792 scm = ReferenceSidCacheMgr(SidCacheMgr);
793 if (scm != NULL)
794 {
795 EnterCriticalSection(&scm->Lock);
796
797 if (scm->QueueLookingUp != NULL &&
798 EqualSid(pSid,
799 (PSID)(scm->QueueLookingUp + 1)))
800 {
801 /* don't free the queue lookup item! this will be
802 done in the lookup thread */
803 scm->QueueLookingUp = NULL;
804 }
805 else
806 {
807 CurrentEntry = &scm->QueueListHead;
808 while (CurrentEntry != &scm->QueueListHead)
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 CurrentEntry = CurrentEntry->Flink;
823 }
824 }
825
826 LeaveCriticalSection(&scm->Lock);
827
828 DereferenceSidCacheMgr(scm);
829 }
830 }
831
832
833 VOID
834 ReferenceSidReqResult(IN HANDLE SidCacheMgr,
835 IN PSIDREQRESULT ReqResult)
836 {
837 PSIDCACHEMGR scm;
838
839 scm = ReferenceSidCacheMgr(SidCacheMgr);
840 if (scm != NULL)
841 {
842 InterlockedIncrement(&ReqResult->RefCount);
843
844 DereferenceSidCacheMgr(scm);
845 }
846 }
847
848
849 VOID
850 DereferenceSidReqResult(IN HANDLE SidCacheMgr,
851 IN PSIDREQRESULT ReqResult)
852 {
853 PSIDCACHEMGR scm;
854
855 scm = ReferenceSidCacheMgr(SidCacheMgr);
856 if (scm != NULL)
857 {
858 if (InterlockedDecrement(&ReqResult->RefCount) == 0)
859 {
860 HeapFree(scm->Heap,
861 0,
862 ReqResult);
863 }
864
865 DereferenceSidCacheMgr(scm);
866 }
867 }
868
869
870 BOOL
871 LookupSidCache(IN HANDLE SidCacheMgr,
872 IN PSID pSid,
873 IN PSIDREQCOMPLETIONPROC CompletionProc,
874 IN PVOID Context)
875 {
876 BOOL Found = FALSE;
877 PSIDREQRESULT ReqResult = NULL;
878 PSIDCACHEMGR scm;
879
880 scm = ReferenceSidCacheMgr(SidCacheMgr);
881 if (scm != NULL)
882 {
883 EnterCriticalSection(&scm->Lock);
884
885 /* search the cache */
886 Found = FindSidInCache(scm,
887 pSid,
888 &ReqResult);
889
890 if (!Found)
891 {
892 /* the sid is not in the cache, queue it if not already queued */
893 if (!QueueSidLookup(scm,
894 pSid,
895 CompletionProc,
896 Context))
897 {
898 PSIDREQRESULT FoundReqResult = NULL;
899
900 /* unable to queue it, look it up now */
901
902 LeaveCriticalSection(&scm->Lock);
903
904 /* lookup everything we need */
905 if (!LookupSidInformation(scm,
906 pSid,
907 &ReqResult))
908 {
909 ReqResult = NULL;
910 }
911
912 EnterCriticalSection(&scm->Lock);
913
914 /* see if the SID was added to the cache in the meanwhile */
915 if (!FindSidInCache(scm,
916 pSid,
917 &FoundReqResult))
918 {
919 if (ReqResult != NULL)
920 {
921 /* cache the results */
922 CacheLookupResults(scm,
923 pSid,
924 ReqResult);
925 }
926 }
927 else
928 {
929 if (ReqResult != NULL)
930 {
931 /* free the information of our lookup and use the cached
932 information*/
933 DereferenceSidReqResult(scm,
934 ReqResult);
935 }
936
937 ReqResult = FoundReqResult;
938 }
939
940 Found = (ReqResult != NULL);
941 }
942 }
943
944 LeaveCriticalSection(&scm->Lock);
945
946 /* call the completion callback */
947 if (Found)
948 {
949 CompletionProc(SidCacheMgr,
950 pSid,
951 ReqResult,
952 Context);
953
954 if (ReqResult != NULL)
955 {
956 HeapFree(scm->Heap,
957 0,
958 ReqResult);
959 }
960 }
961
962 DereferenceSidCacheMgr(scm);
963 }
964
965 return Found;
966 }