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 for (CurrentEntry = scm->CacheListHead.Flink; 341 CurrentEntry != &scm->CacheListHead; 342 CurrentEntry = CurrentEntry->Flink) 343 { 344 CacheEntry = CONTAINING_RECORD(CurrentEntry, 345 SIDCACHEENTRY, 346 ListEntry); 347 348 if (EqualSid(pSid, 349 (PSID)(CacheEntry + 1))) 350 { 351 SIZE_T ReqResultSize; 352 ULONG AccountNameLen, DomainNameLen; 353 354 Ret = TRUE; 355 356 AccountNameLen = wcslen(CacheEntry->AccountName); 357 DomainNameLen = wcslen(CacheEntry->DomainName); 358 359 ReqResultSize = sizeof(SIDREQRESULT) + 360 (((AccountNameLen + 1) + 361 (DomainNameLen + 1)) * sizeof(WCHAR)); 362 363 ReqRes = HeapAlloc(scm->Heap, 364 0, 365 ReqResultSize); 366 if (ReqRes != NULL) 367 { 368 PWSTR Buffer = (PWSTR)(ReqRes + 1); 369 370 ReqRes->RefCount = 1; 371 372 ReqRes->AccountName = Buffer; 373 wcscpy(ReqRes->AccountName, 374 CacheEntry->AccountName); 375 Buffer += AccountNameLen + 1; 376 377 ReqRes->DomainName = Buffer; 378 wcscpy(ReqRes->DomainName, 379 CacheEntry->DomainName); 380 } 381 382 /* return the result, even if we weren't unable to 383 allocate enough memory! */ 384 *ReqResult = ReqRes; 385 break; 386 } 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 for (CurrentEntry = scm->QueueListHead.Flink; 702 CurrentEntry != &scm->QueueListHead; 703 CurrentEntry = CurrentEntry->Flink) 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 } 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 for (CurrentEntry = scm->QueueListHead.Flink; 807 CurrentEntry != &scm->QueueListHead; 808 CurrentEntry = CurrentEntry->Flink) 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 } 823 824 LeaveCriticalSection(&scm->Lock); 825 826 DereferenceSidCacheMgr(scm); 827 } 828 } 829 830 831 VOID 832 ReferenceSidReqResult(IN HANDLE SidCacheMgr, 833 IN PSIDREQRESULT ReqResult) 834 { 835 PSIDCACHEMGR scm; 836 837 scm = ReferenceSidCacheMgr(SidCacheMgr); 838 if (scm != NULL) 839 { 840 InterlockedIncrement(&ReqResult->RefCount); 841 842 DereferenceSidCacheMgr(scm); 843 } 844 } 845 846 847 VOID 848 DereferenceSidReqResult(IN HANDLE SidCacheMgr, 849 IN PSIDREQRESULT ReqResult) 850 { 851 PSIDCACHEMGR scm; 852 853 scm = ReferenceSidCacheMgr(SidCacheMgr); 854 if (scm != NULL) 855 { 856 if (InterlockedDecrement(&ReqResult->RefCount) == 0) 857 { 858 HeapFree(scm->Heap, 859 0, 860 ReqResult); 861 } 862 863 DereferenceSidCacheMgr(scm); 864 } 865 } 866 867 868 BOOL 869 LookupSidCache(IN HANDLE SidCacheMgr, 870 IN PSID pSid, 871 IN PSIDREQCOMPLETIONPROC CompletionProc, 872 IN PVOID Context) 873 { 874 BOOL Found = FALSE; 875 PSIDREQRESULT ReqResult = NULL; 876 PSIDCACHEMGR scm; 877 878 scm = ReferenceSidCacheMgr(SidCacheMgr); 879 if (scm != NULL) 880 { 881 EnterCriticalSection(&scm->Lock); 882 883 /* search the cache */ 884 Found = FindSidInCache(scm, 885 pSid, 886 &ReqResult); 887 888 if (!Found) 889 { 890 /* the sid is not in the cache, queue it if not already queued */ 891 if (!QueueSidLookup(scm, 892 pSid, 893 CompletionProc, 894 Context)) 895 { 896 PSIDREQRESULT FoundReqResult = NULL; 897 898 /* unable to queue it, look it up now */ 899 900 LeaveCriticalSection(&scm->Lock); 901 902 /* lookup everything we need */ 903 if (!LookupSidInformation(scm, 904 pSid, 905 &ReqResult)) 906 { 907 ReqResult = NULL; 908 } 909 910 EnterCriticalSection(&scm->Lock); 911 912 /* see if the SID was added to the cache in the meanwhile */ 913 if (!FindSidInCache(scm, 914 pSid, 915 &FoundReqResult)) 916 { 917 if (ReqResult != NULL) 918 { 919 /* cache the results */ 920 CacheLookupResults(scm, 921 pSid, 922 ReqResult); 923 } 924 } 925 else 926 { 927 if (ReqResult != NULL) 928 { 929 /* free the information of our lookup and use the cached 930 information*/ 931 DereferenceSidReqResult(scm, 932 ReqResult); 933 } 934 935 ReqResult = FoundReqResult; 936 } 937 938 Found = (ReqResult != NULL); 939 } 940 } 941 942 LeaveCriticalSection(&scm->Lock); 943 944 /* call the completion callback */ 945 if (Found) 946 { 947 CompletionProc(SidCacheMgr, 948 pSid, 949 ReqResult, 950 Context); 951 952 if (ReqResult != NULL) 953 { 954 HeapFree(scm->Heap, 955 0, 956 ReqResult); 957 } 958 } 959 960 DereferenceSidCacheMgr(scm); 961 } 962 963 return Found; 964 } 965