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
FreeQueueEntry(IN PSIDCACHEMGR scm,IN PSIDQUEUEENTRY QueueEntry)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
FreeCacheEntry(IN PSIDCACHEMGR scm,IN PSIDCACHEENTRY CacheEntry)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
CleanupSidCacheMgr(IN PSIDCACHEMGR scm)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
ReferenceSidCacheMgr(IN HANDLE SidCacheMgr)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
DereferenceSidCacheMgr(IN PSIDCACHEMGR scm)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
OpenLSAPolicyHandle(IN LPWSTR SystemName,IN ACCESS_MASK DesiredAccess,OUT PLSA_HANDLE PolicyHandle)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 SIZE_T NameLength;
180
181 if (SystemName != NULL && SystemName[0] != L'\0')
182 {
183 NameLength = wcslen(SystemName);
184 if (NameLength > UNICODE_STRING_MAX_CHARS)
185 {
186 return FALSE;
187 }
188
189 LsaSystemName.Buffer = SystemName;
190 LsaSystemName.Length = NameLength * 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
LookupSidInformation(IN PSIDCACHEMGR scm,IN PSID pSid,OUT PSIDREQRESULT * ReqResult)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 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 SidNameUse = Names->Use;
237
238 if (ReferencedDomain != NULL &&
239 Names->DomainIndex >= 0)
240 {
241 Domain = &ReferencedDomain->Domains[Names->DomainIndex];
242 DomainName = &Domain->Name;
243 }
244 else
245 {
246 Domain = NULL;
247 DomainName = NULL;
248 }
249
250 switch (SidNameUse)
251 {
252 case SidTypeAlias:
253 {
254 if (Domain != NULL)
255 {
256 /* query the domain name for BUILTIN accounts */
257 Status = LsaQueryInformationPolicy(scm->LsaHandle,
258 PolicyAccountDomainInformation,
259 (PVOID*)&PolicyAccountDomainInfo);
260 if (NT_SUCCESS(Status))
261 {
262 DomainName = &PolicyAccountDomainInfo->DomainName;
263
264 /* make the user believe this is a group */
265 SidNameUse = (PolicyAccountDomainInfo != NULL ? SidTypeGroup : SidTypeUser);
266 }
267 }
268 break;
269 }
270
271 default:
272 {
273 DPRINT("Unhandled SID type: 0x%x\n", Names->Use);
274 break;
275 }
276 }
277
278 AccountNameSize = Names->Name.Length;
279 if (DomainName != NULL)
280 {
281 DomainNameSize = DomainName->Length;
282 }
283
284 ReqRet = HeapAlloc(scm->Heap,
285 0,
286 sizeof(SIDREQRESULT) +
287 (((AccountNameSize + DomainNameSize) + 2) * sizeof(WCHAR)));
288 if (ReqRet != NULL)
289 {
290 ReqRet->RefCount = 1;
291 ReqRet->AccountName = (LPWSTR)(ReqRet + 1);
292 ReqRet->DomainName = ReqRet->AccountName + (AccountNameSize / sizeof(WCHAR)) + 1;
293
294 CopyMemory(ReqRet->AccountName,
295 Names->Name.Buffer,
296 Names->Name.Length);
297
298 if (DomainName != NULL)
299 {
300 CopyMemory(ReqRet->DomainName,
301 DomainName->Buffer,
302 DomainName->Length);
303 }
304
305 ReqRet->AccountName[AccountNameSize / sizeof(WCHAR)] = L'\0';
306 ReqRet->DomainName[DomainNameSize / sizeof(WCHAR)] = L'\0';
307
308 ReqRet->SidNameUse = SidNameUse;
309 }
310
311 if (PolicyAccountDomainInfo != NULL)
312 {
313 LsaFreeMemory(PolicyAccountDomainInfo);
314 }
315
316 LsaFreeMemory(ReferencedDomain);
317 LsaFreeMemory(Names);
318
319 Ret = TRUE;
320 }
321 else if (Status == STATUS_NONE_MAPPED)
322 {
323 Ret = TRUE;
324 }
325
326 if (Ret)
327 {
328 *ReqResult = ReqRet;
329 }
330
331 return Ret;
332 }
333
334
335 static BOOL
FindSidInCache(IN PSIDCACHEMGR scm,IN PSID pSid,OUT PSIDREQRESULT * ReqResult)336 FindSidInCache(IN PSIDCACHEMGR scm,
337 IN PSID pSid,
338 OUT PSIDREQRESULT *ReqResult)
339 {
340 PSIDCACHEENTRY CacheEntry;
341 PLIST_ENTRY CurrentEntry;
342 PSIDREQRESULT ReqRes;
343 BOOL Ret = FALSE;
344
345 /* NOTE: assumes the lists are locked! */
346
347 for (CurrentEntry = scm->CacheListHead.Flink;
348 CurrentEntry != &scm->CacheListHead;
349 CurrentEntry = CurrentEntry->Flink)
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
396 return Ret;
397 }
398
399
400 static VOID
CacheLookupResults(IN PSIDCACHEMGR scm,IN PSID pSid,IN PSIDREQRESULT ReqResult)401 CacheLookupResults(IN PSIDCACHEMGR scm,
402 IN PSID pSid,
403 IN PSIDREQRESULT ReqResult)
404 {
405 PSIDCACHEENTRY CacheEntry;
406 DWORD SidLen;
407 SIZE_T AccountNameLen = 0;
408 SIZE_T DomainNameLen = 0;
409 SIZE_T CacheEntrySize = sizeof(SIDCACHEENTRY);
410
411 /* NOTE: assumes the lists are locked! */
412
413 SidLen = GetLengthSid(pSid);
414 CacheEntrySize += SidLen;
415
416 AccountNameLen = wcslen(ReqResult->AccountName);
417 CacheEntrySize += (AccountNameLen + 1) * sizeof(WCHAR);
418
419 DomainNameLen = wcslen(ReqResult->DomainName);
420 CacheEntrySize += (wcslen(ReqResult->DomainName) + 1) * sizeof(WCHAR);
421
422 CacheEntry = HeapAlloc(scm->Heap,
423 0,
424 CacheEntrySize);
425 if (CacheEntry != NULL)
426 {
427 PWSTR lpBuf = (PWSTR)((ULONG_PTR)(CacheEntry + 1) + SidLen);
428
429 CacheEntry->SidNameUse = ReqResult->SidNameUse;
430
431 /* append the SID */
432 CopySid(SidLen,
433 (PSID)(CacheEntry + 1),
434 pSid);
435
436 /* append the strings */
437 CacheEntry->AccountName = lpBuf;
438 wcscpy(lpBuf,
439 ReqResult->AccountName);
440 lpBuf += AccountNameLen + 1;
441
442 CacheEntry->DomainName = lpBuf;
443 wcscpy(lpBuf,
444 ReqResult->DomainName);
445 lpBuf += DomainNameLen + 1;
446
447 /* add the entry to the cache list */
448 InsertTailList(&scm->CacheListHead,
449 &CacheEntry->ListEntry);
450 }
451 }
452
453
454 static DWORD WINAPI
LookupThreadProc(IN LPVOID lpParameter)455 LookupThreadProc(IN LPVOID lpParameter)
456 {
457 HMODULE hModule;
458 PSIDCACHEMGR scm = (PSIDCACHEMGR)lpParameter;
459
460 /* Reference the dll to avoid problems in case of accidental
461 FreeLibrary calls... */
462 if (!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
463 (LPCWSTR)hDllInstance,
464 &hModule))
465 {
466 hModule = NULL;
467 }
468
469 while (scm->RefCount != 0)
470 {
471 PSIDQUEUEENTRY QueueEntry = NULL;
472
473 EnterCriticalSection(&scm->Lock);
474
475 /* get the first item of the queue */
476 if (scm->QueueListHead.Flink != &scm->QueueListHead)
477 {
478 QueueEntry = CONTAINING_RECORD(scm->QueueListHead.Flink,
479 SIDQUEUEENTRY,
480 ListEntry);
481 RemoveEntryList(&QueueEntry->ListEntry);
482 QueueEntry->ListEntry.Flink = NULL;
483 }
484 else
485 {
486 LeaveCriticalSection(&scm->Lock);
487
488 /* wait for the next asynchronous lookup queued */
489 WaitForSingleObject(scm->LookupEvent,
490 INFINITE);
491 continue;
492 }
493
494 scm->QueueLookingUp = QueueEntry;
495
496 LeaveCriticalSection(&scm->Lock);
497
498 if (QueueEntry != NULL)
499 {
500 PSIDREQRESULT ReqResult, FoundReqResult;
501 PSID pSid = (PSID)(QueueEntry + 1);
502
503 /* lookup the SID information */
504 if (!LookupSidInformation(scm,
505 pSid,
506 &ReqResult))
507 {
508 ReqResult = NULL;
509 }
510
511 EnterCriticalSection(&scm->Lock);
512
513 /* see if the SID was added to the cache in the meanwhile */
514 if (!FindSidInCache(scm,
515 pSid,
516 &FoundReqResult))
517 {
518 if (ReqResult != NULL)
519 {
520 /* cache the results */
521 CacheLookupResults(scm,
522 pSid,
523 ReqResult);
524 }
525 }
526 else
527 {
528 if (ReqResult != NULL)
529 {
530 /* free the information of our lookup and use the cached
531 information*/
532 DereferenceSidReqResult(scm,
533 ReqResult);
534 }
535
536 ReqResult = FoundReqResult;
537 }
538
539 /* notify the callers unless the lookup was cancelled */
540 if (scm->QueueLookingUp != NULL)
541 {
542 ULONG i = 0;
543
544 while (scm->QueueLookingUp != NULL &&
545 i < QueueEntry->CallbackCount)
546 {
547 PVOID Context;
548 PSIDREQCOMPLETIONPROC CompletionProc;
549
550 Context = QueueEntry->Callbacks[i].Context;
551 CompletionProc = QueueEntry->Callbacks[i].CompletionProc;
552
553 LeaveCriticalSection(&scm->Lock);
554
555 /* call the completion proc without holding the lock! */
556 CompletionProc(ScmToHandle(scm),
557 pSid,
558 ReqResult,
559 Context);
560
561 EnterCriticalSection(&scm->Lock);
562
563 i++;
564 }
565
566 scm->QueueLookingUp = NULL;
567 }
568
569 LeaveCriticalSection(&scm->Lock);
570
571 /* free the queue item */
572 FreeQueueEntry(scm,
573 QueueEntry);
574 }
575 }
576
577 CleanupSidCacheMgr(scm);
578
579 HeapFree(scm->Heap,
580 0,
581 scm);
582
583 if (hModule != NULL)
584 {
585 /* dereference the library and exit */
586 FreeLibraryAndExitThread(hModule,
587 0);
588 }
589
590 return 0;
591 }
592
593
594
595 HANDLE
CreateSidCacheMgr(IN HANDLE Heap,IN LPCWSTR SystemName)596 CreateSidCacheMgr(IN HANDLE Heap,
597 IN LPCWSTR SystemName)
598 {
599 PSIDCACHEMGR scm;
600
601 if (SystemName == NULL)
602 SystemName = L"";
603
604 scm = HeapAlloc(Heap,
605 0,
606 FIELD_OFFSET(SIDCACHEMGR,
607 SystemName[wcslen(SystemName) + 1]));
608 if (scm != NULL)
609 {
610 /* zero the static part of the structure */
611 ZeroMemory(scm,
612 FIELD_OFFSET(SIDCACHEMGR,
613 SystemName));
614
615 scm->RefCount = 1;
616 scm->Heap = Heap;
617
618 wcscpy(scm->SystemName,
619 SystemName);
620
621 InitializeCriticalSection(&scm->Lock);
622 InitializeListHead(&scm->QueueListHead);
623 InitializeListHead(&scm->CacheListHead);
624
625 scm->LookupEvent = CreateEvent(NULL,
626 FALSE,
627 FALSE,
628 NULL);
629 if (scm->LookupEvent == NULL)
630 {
631 goto Cleanup;
632 }
633
634 if (!OpenLSAPolicyHandle(scm->SystemName,
635 POLICY_LOOKUP_NAMES | POLICY_VIEW_LOCAL_INFORMATION,
636 &scm->LsaHandle))
637 {
638 goto Cleanup;
639 }
640
641 scm->LookupThread = CreateThread(NULL,
642 0,
643 LookupThreadProc,
644 scm,
645 0,
646 NULL);
647 if (scm->LookupThread == NULL)
648 {
649 Cleanup:
650 if (scm->LookupEvent != NULL)
651 {
652 CloseHandle(scm->LookupEvent);
653 }
654
655 if (scm->LsaHandle != NULL)
656 {
657 LsaClose(scm->LsaHandle);
658 }
659
660 HeapFree(Heap,
661 0,
662 scm);
663 scm = NULL;
664 }
665 }
666 else
667 {
668 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
669 }
670
671 return (HANDLE)scm;
672 }
673
674
675 VOID
DestroySidCacheMgr(IN HANDLE SidCacheMgr)676 DestroySidCacheMgr(IN HANDLE SidCacheMgr)
677 {
678 PSIDCACHEMGR scm = HandleToScm(SidCacheMgr);
679
680 if (scm != NULL)
681 {
682 /* remove the keep-alive reference */
683 DereferenceSidCacheMgr(scm);
684 }
685 }
686
687
688 static BOOL
QueueSidLookup(IN PSIDCACHEMGR scm,IN PSID pSid,IN PSIDREQCOMPLETIONPROC CompletionProc,IN PVOID Context)689 QueueSidLookup(IN PSIDCACHEMGR scm,
690 IN PSID pSid,
691 IN PSIDREQCOMPLETIONPROC CompletionProc,
692 IN PVOID Context)
693 {
694 PLIST_ENTRY CurrentEntry;
695 PSIDQUEUEENTRY QueueEntry, FoundEntry = NULL;
696 BOOL Ret = FALSE;
697
698 /* NOTE: assumes the lists are locked! */
699
700 if (scm->QueueLookingUp != NULL &&
701 EqualSid(pSid,
702 (PSID)(scm->QueueLookingUp + 1)))
703 {
704 FoundEntry = scm->QueueLookingUp;
705 }
706 else
707 {
708 for (CurrentEntry = scm->QueueListHead.Flink;
709 CurrentEntry != &scm->QueueListHead;
710 CurrentEntry = CurrentEntry->Flink)
711 {
712 QueueEntry = CONTAINING_RECORD(CurrentEntry,
713 SIDQUEUEENTRY,
714 ListEntry);
715
716 if (EqualSid(pSid,
717 (PSID)(QueueEntry + 1)))
718 {
719 FoundEntry = QueueEntry;
720 break;
721 }
722 }
723 }
724
725 if (FoundEntry == NULL)
726 {
727 DWORD SidLength = GetLengthSid(pSid);
728
729 FoundEntry = HeapAlloc(scm->Heap,
730 0,
731 sizeof(SIDQUEUEENTRY) + SidLength);
732 if (FoundEntry != NULL)
733 {
734 CopySid(SidLength,
735 (PSID)(FoundEntry + 1),
736 pSid);
737
738 FoundEntry->CallbackCount = 1;
739 FoundEntry->Callbacks = HeapAlloc(scm->Heap,
740 0,
741 sizeof(SIDCACHECALLBACKINFO));
742
743 if (FoundEntry->Callbacks != NULL)
744 {
745 FoundEntry->Callbacks[0].CompletionProc = CompletionProc;
746 FoundEntry->Callbacks[0].Context = Context;
747
748 /* append it to the queue */
749 InsertTailList(&scm->QueueListHead,
750 &FoundEntry->ListEntry);
751
752 /* signal the lookup event */
753 SetEvent(scm->LookupEvent);
754
755 Ret = TRUE;
756 }
757 else
758 {
759 /* unable to queue it because we couldn't allocate the callbacks
760 array, free the memory and return */
761 HeapFree(scm->Heap,
762 0,
763 FoundEntry);
764 }
765 }
766 }
767 else
768 {
769 PSIDCACHECALLBACKINFO Sidccb;
770
771 /* add the callback */
772 Sidccb = HeapReAlloc(scm->Heap,
773 0,
774 FoundEntry->Callbacks,
775 (FoundEntry->CallbackCount + 1) * sizeof(SIDCACHECALLBACKINFO));
776 if (Sidccb != NULL)
777 {
778 FoundEntry->Callbacks = Sidccb;
779 FoundEntry->Callbacks[FoundEntry->CallbackCount].CompletionProc = CompletionProc;
780 FoundEntry->Callbacks[FoundEntry->CallbackCount++].Context = Context;
781
782 Ret = TRUE;
783 }
784 }
785
786 return Ret;
787 }
788
789
790 VOID
DequeueSidLookup(IN HANDLE SidCacheMgr,IN PSID pSid)791 DequeueSidLookup(IN HANDLE SidCacheMgr,
792 IN PSID pSid)
793 {
794 PLIST_ENTRY CurrentEntry;
795 PSIDQUEUEENTRY QueueEntry;
796 PSIDCACHEMGR scm;
797
798 scm = ReferenceSidCacheMgr(SidCacheMgr);
799 if (scm != NULL)
800 {
801 EnterCriticalSection(&scm->Lock);
802
803 if (scm->QueueLookingUp != NULL &&
804 EqualSid(pSid,
805 (PSID)(scm->QueueLookingUp + 1)))
806 {
807 /* don't free the queue lookup item! this will be
808 done in the lookup thread */
809 scm->QueueLookingUp = NULL;
810 }
811 else
812 {
813 for (CurrentEntry = scm->QueueListHead.Flink;
814 CurrentEntry != &scm->QueueListHead;
815 CurrentEntry = CurrentEntry->Flink)
816 {
817 QueueEntry = CONTAINING_RECORD(CurrentEntry,
818 SIDQUEUEENTRY,
819 ListEntry);
820
821 if (EqualSid(pSid,
822 (PSID)(QueueEntry + 1)))
823 {
824 FreeQueueEntry(scm,
825 QueueEntry);
826 break;
827 }
828 }
829 }
830
831 LeaveCriticalSection(&scm->Lock);
832
833 DereferenceSidCacheMgr(scm);
834 }
835 }
836
837
838 VOID
ReferenceSidReqResult(IN HANDLE SidCacheMgr,IN PSIDREQRESULT ReqResult)839 ReferenceSidReqResult(IN HANDLE SidCacheMgr,
840 IN PSIDREQRESULT ReqResult)
841 {
842 PSIDCACHEMGR scm;
843
844 scm = ReferenceSidCacheMgr(SidCacheMgr);
845 if (scm != NULL)
846 {
847 InterlockedIncrement(&ReqResult->RefCount);
848
849 DereferenceSidCacheMgr(scm);
850 }
851 }
852
853
854 VOID
DereferenceSidReqResult(IN HANDLE SidCacheMgr,IN PSIDREQRESULT ReqResult)855 DereferenceSidReqResult(IN HANDLE SidCacheMgr,
856 IN PSIDREQRESULT ReqResult)
857 {
858 PSIDCACHEMGR scm;
859
860 scm = ReferenceSidCacheMgr(SidCacheMgr);
861 if (scm != NULL)
862 {
863 if (InterlockedDecrement(&ReqResult->RefCount) == 0)
864 {
865 HeapFree(scm->Heap,
866 0,
867 ReqResult);
868 }
869
870 DereferenceSidCacheMgr(scm);
871 }
872 }
873
874
875 BOOL
LookupSidCache(IN HANDLE SidCacheMgr,IN PSID pSid,IN PSIDREQCOMPLETIONPROC CompletionProc,IN PVOID Context)876 LookupSidCache(IN HANDLE SidCacheMgr,
877 IN PSID pSid,
878 IN PSIDREQCOMPLETIONPROC CompletionProc,
879 IN PVOID Context)
880 {
881 BOOL Found = FALSE;
882 PSIDREQRESULT ReqResult = NULL;
883 PSIDCACHEMGR scm;
884
885 scm = ReferenceSidCacheMgr(SidCacheMgr);
886 if (scm != NULL)
887 {
888 EnterCriticalSection(&scm->Lock);
889
890 /* search the cache */
891 Found = FindSidInCache(scm,
892 pSid,
893 &ReqResult);
894
895 if (!Found)
896 {
897 /* the sid is not in the cache, queue it if not already queued */
898 if (!QueueSidLookup(scm,
899 pSid,
900 CompletionProc,
901 Context))
902 {
903 PSIDREQRESULT FoundReqResult = NULL;
904
905 /* unable to queue it, look it up now */
906
907 LeaveCriticalSection(&scm->Lock);
908
909 /* lookup everything we need */
910 if (!LookupSidInformation(scm,
911 pSid,
912 &ReqResult))
913 {
914 ReqResult = NULL;
915 }
916
917 EnterCriticalSection(&scm->Lock);
918
919 /* see if the SID was added to the cache in the meanwhile */
920 if (!FindSidInCache(scm,
921 pSid,
922 &FoundReqResult))
923 {
924 if (ReqResult != NULL)
925 {
926 /* cache the results */
927 CacheLookupResults(scm,
928 pSid,
929 ReqResult);
930 }
931 }
932 else
933 {
934 if (ReqResult != NULL)
935 {
936 /* free the information of our lookup and use the cached
937 information*/
938 DereferenceSidReqResult(scm,
939 ReqResult);
940 }
941
942 ReqResult = FoundReqResult;
943 }
944
945 Found = (ReqResult != NULL);
946 }
947 }
948
949 LeaveCriticalSection(&scm->Lock);
950
951 /* call the completion callback */
952 if (Found)
953 {
954 CompletionProc(SidCacheMgr,
955 pSid,
956 ReqResult,
957 Context);
958
959 if (ReqResult != NULL)
960 {
961 HeapFree(scm->Heap,
962 0,
963 ReqResult);
964 }
965 }
966
967 DereferenceSidCacheMgr(scm);
968 }
969
970 return Found;
971 }
972