⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sidcache.c

📁 winNT技术操作系统,国外开放的原代码和LIUX一样
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
 * 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 + -