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 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 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 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 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 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 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 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 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 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 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 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 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