📄 sidcache.c
字号:
/*
* ReactOS Access Control List Editor
* Copyright (C) 2004-2005 ReactOS Team
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* $Id: aclui.c 19715 2005-11-28 01:10:49Z weiden $
*
* PROJECT: ReactOS Access Control List Editor
* FILE: lib/aclui/sidcache.c
* PURPOSE: Access Control List Editor
* PROGRAMMER: Thomas Weidenmueller <w3seek@reactos.com>
*
* UPDATE HISTORY:
* 12/10/2005 Created
*/
#include <precomp.h>
#define NDEBUG
#include <debug.h>
#define HandleToScm(Handle) (PSIDCACHEMGR)(Handle)
#define ScmToHandle(Scm) (HANDLE)(Scm)
typedef struct _SIDCACHEMGR
{
LONG RefCount;
LSA_HANDLE LsaHandle;
CRITICAL_SECTION Lock;
LIST_ENTRY QueueListHead;
struct _SIDQUEUEENTRY *QueueLookingUp;
LIST_ENTRY CacheListHead;
HANDLE Heap;
HANDLE LookupEvent;
HANDLE LookupThread;
WCHAR SystemName[1];
} SIDCACHEMGR, *PSIDCACHEMGR;
typedef struct _SIDCACHECALLBACKINFO
{
PSIDREQCOMPLETIONPROC CompletionProc;
PVOID Context;
} SIDCACHECALLBACKINFO, *PSIDCACHECALLBACKINFO;
typedef struct _SIDQUEUEENTRY
{
LIST_ENTRY ListEntry;
ULONG CallbackCount;
PSIDCACHECALLBACKINFO Callbacks;
/* the SID is appended to this structure */
} SIDQUEUEENTRY, *PSIDQUEUEENTRY;
typedef struct _SIDCACHEENTRY
{
LIST_ENTRY ListEntry;
SID_NAME_USE SidNameUse;
PWSTR AccountName;
PWSTR DomainName;
/* the SID and strings are appended to this structure */
} SIDCACHEENTRY, *PSIDCACHEENTRY;
static VOID
FreeQueueEntry(IN PSIDCACHEMGR scm,
IN PSIDQUEUEENTRY QueueEntry)
{
if (QueueEntry->ListEntry.Flink != NULL)
{
RemoveEntryList(&QueueEntry->ListEntry);
}
HeapFree(scm->Heap,
0,
QueueEntry->Callbacks);
HeapFree(scm->Heap,
0,
QueueEntry);
}
static VOID
FreeCacheEntry(IN PSIDCACHEMGR scm,
IN PSIDCACHEENTRY CacheEntry)
{
RemoveEntryList(&CacheEntry->ListEntry);
HeapFree(scm->Heap,
0,
CacheEntry);
}
static VOID
CleanupSidCacheMgr(IN PSIDCACHEMGR scm)
{
/* make sure the lookup thread runs down */
SetEvent(scm->LookupEvent);
WaitForSingleObject(scm->LookupThread,
INFINITE);
LsaClose(scm->LsaHandle);
CloseHandle(scm->LookupEvent);
CloseHandle(scm->LookupThread);
/* delete the queue */
while (!IsListEmpty(&scm->QueueListHead))
{
PSIDQUEUEENTRY QueueEntry;
QueueEntry = CONTAINING_RECORD(scm->QueueListHead.Flink,
SIDQUEUEENTRY,
ListEntry);
FreeQueueEntry(scm,
QueueEntry);
}
/* delete the cache */
while (!IsListEmpty(&scm->CacheListHead))
{
PSIDCACHEENTRY CacheEntry;
CacheEntry = CONTAINING_RECORD(scm->CacheListHead.Flink,
SIDCACHEENTRY,
ListEntry);
FreeCacheEntry(scm,
CacheEntry);
}
DeleteCriticalSection(&scm->Lock);
}
static PSIDCACHEMGR
ReferenceSidCacheMgr(IN HANDLE SidCacheMgr)
{
PSIDCACHEMGR scm = HandleToScm(SidCacheMgr);
if (InterlockedIncrement(&scm->RefCount) != 1)
{
return scm;
}
return NULL;
}
static VOID
DereferenceSidCacheMgr(IN PSIDCACHEMGR scm)
{
if (InterlockedDecrement(&scm->RefCount) == 0)
{
CleanupSidCacheMgr(scm);
HeapFree(scm->Heap,
0,
scm);
}
}
static BOOL
OpenLSAPolicyHandle(IN LPWSTR SystemName,
IN ACCESS_MASK DesiredAccess,
OUT PLSA_HANDLE PolicyHandle)
{
LSA_OBJECT_ATTRIBUTES LsaObjectAttributes = {0};
LSA_UNICODE_STRING LsaSystemName, *psn;
NTSTATUS Status;
if (SystemName != NULL && SystemName[0] != L'\0')
{
LsaSystemName.Buffer = SystemName;
LsaSystemName.Length = wcslen(SystemName) * sizeof(WCHAR);
LsaSystemName.MaximumLength = LsaSystemName.Length + sizeof(WCHAR);
psn = &LsaSystemName;
}
else
{
psn = NULL;
}
Status = LsaOpenPolicy(psn,
&LsaObjectAttributes,
DesiredAccess,
PolicyHandle);
if (!NT_SUCCESS(Status))
{
SetLastError(LsaNtStatusToWinError(Status));
return FALSE;
}
return TRUE;
}
static BOOL
LookupSidInformation(IN PSIDCACHEMGR scm,
IN PSID pSid,
OUT PSIDREQRESULT *ReqResult)
{
PLSA_REFERENCED_DOMAIN_LIST ReferencedDomain;
PLSA_TRANSLATED_NAME Names;
PLSA_TRUST_INFORMATION Domain;
PLSA_UNICODE_STRING DomainName;
SID_NAME_USE SidNameUse = SidTypeUnknown;
PPOLICY_ACCOUNT_DOMAIN_INFO PolicyAccountDomainInfo = NULL;
NTSTATUS Status;
DWORD SidLength, AccountNameSize, DomainNameSize = 0;
PSIDREQRESULT ReqRet = NULL;
BOOL Ret = FALSE;
Status = LsaLookupSids(scm->LsaHandle,
1,
&pSid,
&ReferencedDomain,
&Names);
if (NT_SUCCESS(Status))
{
SidLength = GetLengthSid(pSid);
SidNameUse = Names->Use;
if (ReferencedDomain != NULL &&
Names->DomainIndex >= 0)
{
Domain = &ReferencedDomain->Domains[Names->DomainIndex];
DomainName = &Domain->Name;
}
else
{
Domain = NULL;
DomainName = NULL;
}
switch (SidNameUse)
{
case SidTypeAlias:
{
if (Domain != NULL)
{
/* query the domain name for BUILTIN accounts */
Status = LsaQueryInformationPolicy(scm->LsaHandle,
PolicyAccountDomainInformation,
(PVOID*)&PolicyAccountDomainInfo);
if (NT_SUCCESS(Status))
{
DomainName = &PolicyAccountDomainInfo->DomainName;
/* make the user believe this is a group */
SidNameUse = (PolicyAccountDomainInfo != NULL ? SidTypeGroup : SidTypeUser);
}
}
break;
}
default:
{
DPRINT("Unhandled SID type: 0x%x\n", Names->Use);
break;
}
}
AccountNameSize = Names->Name.Length;
if (DomainName != NULL)
{
DomainNameSize = DomainName->Length;
}
ReqRet = HeapAlloc(scm->Heap,
0,
sizeof(SIDREQRESULT) +
(((AccountNameSize + DomainNameSize) + 2) * sizeof(WCHAR)));
if (ReqRet != NULL)
{
ReqRet->RefCount = 1;
ReqRet->AccountName = (LPWSTR)(ReqRet + 1);
ReqRet->DomainName = ReqRet->AccountName + (AccountNameSize / sizeof(WCHAR)) + 1;
CopyMemory(ReqRet->AccountName,
Names->Name.Buffer,
Names->Name.Length);
if (DomainName != NULL)
{
CopyMemory(ReqRet->DomainName,
DomainName->Buffer,
DomainName->Length);
}
ReqRet->AccountName[AccountNameSize / sizeof(WCHAR)] = L'\0';
ReqRet->DomainName[DomainNameSize / sizeof(WCHAR)] = L'\0';
ReqRet->SidNameUse = SidNameUse;
}
if (PolicyAccountDomainInfo != NULL)
{
LsaFreeMemory(PolicyAccountDomainInfo);
}
LsaFreeMemory(ReferencedDomain);
LsaFreeMemory(Names);
Ret = TRUE;
}
else if (Status == STATUS_NONE_MAPPED)
{
Ret = TRUE;
}
if (Ret)
{
*ReqResult = ReqRet;
}
return Ret;
}
static BOOL
FindSidInCache(IN PSIDCACHEMGR scm,
IN PSID pSid,
OUT PSIDREQRESULT *ReqResult)
{
PSIDCACHEENTRY CacheEntry;
PLIST_ENTRY CurrentEntry;
PSIDREQRESULT ReqRes;
BOOL Ret = FALSE;
/* NOTE: assumes the lists are locked! */
CurrentEntry = &scm->CacheListHead;
while (CurrentEntry != &scm->CacheListHead)
{
CacheEntry = CONTAINING_RECORD(CurrentEntry,
SIDCACHEENTRY,
ListEntry);
if (EqualSid(pSid,
(PSID)(CacheEntry + 1)))
{
SIZE_T ReqResultSize;
ULONG AccountNameLen, DomainNameLen;
Ret = TRUE;
AccountNameLen = wcslen(CacheEntry->AccountName);
DomainNameLen = wcslen(CacheEntry->DomainName);
ReqResultSize = sizeof(SIDREQRESULT) +
(((AccountNameLen + 1) +
(DomainNameLen + 1)) * sizeof(WCHAR));
ReqRes = HeapAlloc(scm->Heap,
0,
ReqResultSize);
if (ReqRes != NULL)
{
PWSTR Buffer = (PWSTR)(ReqRes + 1);
ReqRes->RefCount = 1;
ReqRes->AccountName = Buffer;
wcscpy(ReqRes->AccountName,
CacheEntry->AccountName);
Buffer += AccountNameLen + 1;
ReqRes->DomainName = Buffer;
wcscpy(ReqRes->DomainName,
CacheEntry->DomainName);
}
/* return the result, even if we weren't unable to
allocate enough memory! */
*ReqResult = ReqRes;
break;
}
CurrentEntry = CurrentEntry->Flink;
}
return Ret;
}
static VOID
CacheLookupResults(IN PSIDCACHEMGR scm,
IN PSID pSid,
IN PSIDREQRESULT ReqResult)
{
PSIDCACHEENTRY CacheEntry;
DWORD SidLen;
SIZE_T AccountNameLen = 0;
SIZE_T DomainNameLen = 0;
SIZE_T CacheEntrySize = sizeof(SIDCACHEENTRY);
/* NOTE: assumes the lists are locked! */
SidLen = GetLengthSid(pSid);
CacheEntrySize += SidLen;
AccountNameLen = wcslen(ReqResult->AccountName);
CacheEntrySize += (AccountNameLen + 1) * sizeof(WCHAR);
DomainNameLen = wcslen(ReqResult->DomainName);
CacheEntrySize += (wcslen(ReqResult->DomainName) + 1) * sizeof(WCHAR);
CacheEntry = HeapAlloc(scm->Heap,
0,
CacheEntrySize);
if (CacheEntry != NULL)
{
PWSTR lpBuf = (PWSTR)((ULONG_PTR)(CacheEntry + 1) + SidLen);
CacheEntry->SidNameUse = ReqResult->SidNameUse;
/* append the SID */
CopySid(SidLen,
(PSID)(CacheEntry + 1),
pSid);
/* append the strings */
CacheEntry->AccountName = lpBuf;
wcscpy(lpBuf,
ReqResult->AccountName);
lpBuf += AccountNameLen + 1;
CacheEntry->DomainName = lpBuf;
wcscpy(lpBuf,
ReqResult->DomainName);
lpBuf += DomainNameLen + 1;
/* add the entry to the cache list */
InsertTailList(&scm->CacheListHead,
&CacheEntry->ListEntry);
}
}
static DWORD WINAPI
LookupThreadProc(IN LPVOID lpParameter)
{
PSIDCACHEMGR scm = (PSIDCACHEMGR)lpParameter;
while (scm->RefCount != 0)
{
PSIDQUEUEENTRY QueueEntry = NULL;
EnterCriticalSection(&scm->Lock);
/* get the first item of the queue */
if (scm->QueueListHead.Flink != &scm->QueueListHead)
{
QueueEntry = CONTAINING_RECORD(scm->QueueListHead.Flink,
SIDQUEUEENTRY,
ListEntry);
RemoveEntryList(&QueueEntry->ListEntry);
QueueEntry->ListEntry.Flink = NULL;
}
else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -