Почему LookupAccountSid предоставляет странные данные дескриптора безопасности в Win32 API с использованием C? - PullRequest
0 голосов
/ 05 октября 2018

Я пытаюсь получить правильное имя SID (принципала) для каждого экземпляра SACL (для аудита безопасности) в Windows, используя встроенную LookupAccountSid функцию WinAPI.

См. Скриншот ниже одного примера файла, который я хочудля проверки:

enter image description here

Но мой код выдает неверную информацию, как показано ниже:

enter image description here

Вот что должно было произойти.

sidName = Everyone, size = 9
sidName = Everyone, size = 9
sidName = trevm, size = 6

Мне кажется, я внимательно следил за документацией MSDN, но это не помогает?

https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-lookupaccountsidw

Мой код может получить дескриптор безопасности, используя GetSecurityDescriptorSacl без проблем, но LookupAccountSid проблематично.Что я ошибся?Ниже мой код CКто-нибудь знает почему?

int getSACLinfo(HANDLE rToken, SE_OBJECT_TYPE objectType, ACEVALUE*& aceRef, int* count)
{
    int arrSize = 0;
    int retVal = ERROR_SUCCESS;
    PACL sacl = NULL;
    SYSTEM_AUDIT_ACE* ace = NULL;
    PSECURITY_DESCRIPTOR pSS = NULL;
    PSID sid;
    PSID sidOwner;
    BOOL saclPresent;
    BOOL saclDefaulted;
    wchar_t sidName[512];
    wchar_t domainName[512];

    ULONG result = GetSecurityInfo(rToken, objectType,
        OWNER_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION,
        &sidOwner, NULL, NULL, &sacl, &pSS);

    if (result == ERROR_SUCCESS)
    {
        /* Get SACL security descriptor */
        GetSecurityDescriptorSacl(pSS, &saclPresent, &sacl, &saclDefaulted);

        if (saclPresent && (sacl != NULL))
        {
            for (int i = 0; i < sacl->AceCount; i++)
            {
                GetAce(sacl, i, (PVOID*)&ace);

                /* Get SID from Ace */
                sid = (PSID)&ace->SidStart;

                if (IsValidSid(sid) && ace->Header.AceType == SYSTEM_AUDIT_ACE_TYPE)
                {
                    arrSize++;
                }
            }

            // Allocate memory for the data structures to be exported
            aceRef = (ACEVALUE*)malloc(arrSize * sizeof(ACEVALUE));

            if (arrSize > 0 && aceRef != NULL)
            {
                size_t len;
                wchar_t* buf;
                DWORD namelen;
                DWORD domainnamelen;
                SID_NAME_USE peUse;

                for (int i = 0; i < sacl->AceCount; i++)
                {
                    GetAce(sacl, i, (PVOID*)&ace);

                    sid = (PSID)&ace->SidStart;

                    if (IsValidSid(sid) && ace->Header.AceType == SYSTEM_AUDIT_ACE_TYPE)
                    {
                        LookupAccountSid(NULL, sid, sidName, &namelen, domainName, &domainnamelen, &peUse);

                        wprintf(L"sidName = %s, size = %d\n", sidName, namelen);

                        len = wcslen(sidName) + 1;
                        buf = (wchar_t*)malloc(len * sizeof(wchar_t));

                        if (buf != NULL)
                        {
                            wcscpy_s(buf, len, sidName);
                            aceRef[i].Name = buf;
                        }

                        aceRef[i].AceMask = ace->Mask;
                        aceRef[i].AceType = ace->Header.AceType;
                        aceRef[i].AceFlags = ace->Header.AceFlags;
                    }
                }
            }
        }
    }

    else
    {
        retVal = GetLastError();
    }

    *count = arrSize;

    if (pSS != NULL)
    {
        LocalFree((HLOCAL)pSS);
        wprintf(L"FREED!\n");
    }

    return retVal;
}

1 Ответ

0 голосов
/ 07 октября 2018

ОБНОВЛЕНИЕ: Ниже приведен обновленный код для исправления моей ошибки.Проведя дальнейшие исследования, я узнал, что проблема была в том, что я не указал размер буфера для 2 переменных: namelen и domainnamelen в моем исходном коде (спасибо@RbMm и @jwdonahue для указания).

DWORD getSACLinfo(HANDLE rToken, SE_OBJECT_TYPE objectType, ACEVALUE*& aceRef, int* count)
{
    size_t len;
    int arrSize = 0;
    wchar_t* buf;
    wchar_t* sidName = NULL;
    wchar_t* domainName = NULL;
    PSID sid;
    PSID sidOwner;
    PACL sacl = NULL;
    DWORD retValue;
    DWORD dwRevision;
    DWORD namelen;
    DWORD domainnamelen;
    SYSTEM_AUDIT_ACE* ace = NULL;
    PSECURITY_DESCRIPTOR pSS = NULL;
    SECURITY_DESCRIPTOR_CONTROL sdControl;

    /* Get SACL security descriptor */
    retValue = GetSecurityInfo(rToken, objectType,
        OWNER_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION,
        &sidOwner, NULL, NULL, &sacl, &pSS);

    if (retValue == ERROR_SUCCESS)
    {
        if (GetSecurityDescriptorControl(pSS, &sdControl, &dwRevision) == FALSE)
        {
            retValue = ERROR_INVALID_FUNCTION;
        }

        else if (sacl != NULL && (sdControl & SE_SACL_PRESENT) == SE_SACL_PRESENT)
        {
            for (int i = 0; i < sacl->AceCount; i++)
            {
                GetAce(sacl, i, (PVOID*)&ace);

                /* Get SID from Ace */
                sid = (PSID)&ace->SidStart;

                if (IsValidSid(sid) && ace->Header.AceType == SYSTEM_AUDIT_ACE_TYPE)
                {
                    arrSize++;
                }
            }

            // Allocate memory for the data structures to be exported
            aceRef = (ACEVALUE*)malloc(arrSize * sizeof(ACEVALUE));

            if (arrSize > 0 && aceRef != NULL)
            {
                for (int i = 0; i < sacl->AceCount; i++)
                {
                    GetAce(sacl, i, (PVOID*)&ace);

                    sid = (PSID)&ace->SidStart;

                    if (IsValidSid(sid) && ace->Header.AceType == SYSTEM_AUDIT_ACE_TYPE)
                    {
                        // ADDED TO FIX THE PROBLEM
                        getNameBySID(sid, sidName, &namelen, domainName, &domainnamelen);

                        wprintf(L"size = %d, Owner = %s\n", namelen, sidName);

                        len = wcslen(sidName) + 1;
                        buf = (wchar_t*)malloc(len * sizeof(wchar_t));

                        if (buf != NULL)
                        {
                            wcscpy_s(buf, len, sidName);
                            aceRef[i].Name = buf;
                        }

                        aceRef[i].AceMask = ace->Mask;
                        aceRef[i].AceType = ace->Header.AceType;
                        aceRef[i].AceFlags = ace->Header.AceFlags;
                    }
                }
            }
        }
    }

    else
    {
        retValue = GetLastError();
    }

    *count = arrSize;

    // Memory deallocations
    free(sidName);
    free(domainName);
    LocalFree((HLOCAL)pSS);

    wprintf(L"FREED!\n");

    return retValue;
}

Чтобы исправить, я добавил новую функцию getNameBySID, чтобы она обеспечивала правильное пространство памяти для буферов sidName и Домен .Логика просто включает цикл do-while для продолжения итерации, пока она не удовлетворяет требованию LookupAccountSid, где размер буфера является правильным для этих 2 буферов.Если предыдущий размер буфера слишком мал для заполнения буфера, он освобождает ранее выделенный буфер, а затем перераспределяется с правильным размером и пытается снова.

DWORD getNameBySID(PSID sid, wchar_t *&oNameBuf, DWORD *owNameSize, wchar_t *&dNameBuf, DWORD *dnNameSize)
{
    const DWORD DEFAULT_SIZE = 256;
    const wchar_t NONAME[] = L"Unknown";

    bool status;
    SID_NAME_USE peUse;
    DWORD retValue;
    DWORD ownerBufSize = *owNameSize;
    DWORD domainBufSize = *dnNameSize;

    // Create buffers that may be large enough
    if (oNameBuf == NULL || dNameBuf == NULL)
    {
        ownerBufSize = domainBufSize = DEFAULT_SIZE;

        oNameBuf = (wchar_t*)malloc(ownerBufSize * sizeof(wchar_t));
        dNameBuf = (wchar_t*)malloc(domainBufSize * sizeof(wchar_t));

        if (oNameBuf == NULL)
        {
            return ERROR_INSUFFICIENT_BUFFER;
        }

        if (dNameBuf == NULL)
        {
            free(oNameBuf);
            return ERROR_INSUFFICIENT_BUFFER;
        }

        *owNameSize = ownerBufSize;
        *dnNameSize = domainBufSize;

        memset(oNameBuf, 0, ownerBufSize * sizeof(wchar_t));
        memset(dNameBuf, 0, domainBufSize * sizeof(wchar_t));
    }

    do
    {
        status = (LookupAccountSid(NULL, sid, oNameBuf, owNameSize, dNameBuf, dnNameSize, &peUse) == TRUE);

        if (!status)
        {
            retValue = GetLastError();

            if (*owNameSize > ownerBufSize)
            {
                // Reallocate memory for the buffer and try again.
                //wprintf(L"The account name buffer was too small. It will be reallocated.\n");
                free(oNameBuf);

                oNameBuf = (wchar_t*)malloc(*owNameSize * sizeof(wchar_t));

                if (oNameBuf == NULL)
                {
                    return ERROR_INSUFFICIENT_BUFFER;
                }

                ownerBufSize = *owNameSize;
                memset(oNameBuf, 0, ownerBufSize * sizeof(wchar_t));
            }

            else if (*dnNameSize > domainBufSize)
            {
                // Reallocate memory for the buffer and try again.
                //wprintf(L"The domain name buffer was too small. It will be reallocated.\n");
                free(dNameBuf);

                dNameBuf = (wchar_t*)malloc(*dnNameSize * sizeof(wchar_t));

                if (dNameBuf == NULL)
                {
                    return ERROR_INSUFFICIENT_BUFFER;
                }

                domainBufSize = *dnNameSize;
                memset(dNameBuf, 0, domainBufSize * sizeof(wchar_t));
            }

            else if (retValue == ERROR_NONE_MAPPED)
            {
                // A name could not be found for the SID due to an unexpected error occurred.
                if (ownerBufSize > wcslen(NONAME))
                {
                    wcscpy_s(oNameBuf, wcslen(NONAME) + 1, NONAME);
                    oNameBuf[wcslen(NONAME)] = L'\0';
                }

                dNameBuf[0] = L'\0';
                break;
            }

            else
            {
                wprintf(L"LookupAccountSid failed. GetLastError returned: %d\n", retValue);
                break;
            }
        }

    } while (!status);

    *owNameSize = ownerBufSize;
    *dnNameSize = domainBufSize;

    return (status ? ERROR_SUCCESS : retValue);
}

По сути, моя getSACLinfo функция остается практически неизменной, за исключением вызова getNameBySID для получения буферов правильного размера для этих 2 имен.

Ниже приводится ожидаемая информация.

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...