c++windowswinapiuser-accounts

WINAPI Read all access rights for a custom file or a folder


I have a task based on an algorithm to receive the access rights for a certain file or folder and I've tried to implement it but some parts don't seem to be clear. What I've been asked for:

1) Use the function GetNamedSecurityInfo(), for example: GetNamedSecurityInfo(path,SE_FILE_OBJECT,DACL_SECURITY_INFORMATION,NULL, NULL,&a,NULL, &pSD)

2) Futher, use an SID to receive the rights: Use these functions to receive the SID: GetAclInformation(), then GetAce().

3) Now you can use the LookupAccountSid() function and if is was successfull, compare pACE->Mask with all the constants, for example "GENERIC_ALL, GENERIC_READ, GENERIC_WRITE, GENERIC_EXECUTE for files etc." displaying the access rights.

And how I tried to implement this algorithm: // First getting process SID

PSID g_pSID;
BOOL GetCurrentProcessSID()
{
    DWORD dwSize = 0, dwError, dwResult = 0;
    HANDLE hToken;

    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
    {
        printf("OpenProcessToken Error %u\n", GetLastError());
        return FALSE;
    }

    // Call GetTokenInformation to get the buffer size.
    TOKEN_USER tU;
    if (!GetTokenInformation(hToken, TokenUser, &tU, 0, &dwSize))
    {
        dwError = GetLastError();
        if (dwError != ERROR_INSUFFICIENT_BUFFER)
        {
            std::cout << "GetTokenInformation failed, error " << dwError;
            CloseHandle(hToken);
            return 0;
        }
    }

    PTOKEN_OWNER to = (PTOKEN_OWNER)LocalAlloc(LPTR, dwSize);
    if (!to)
    {
        dwError = GetLastError();
        std::cout << "LocalAlloc failed, error " << dwError;
        CloseHandle(hToken);
        return 0;
    }

    if (!GetTokenInformation(hToken, TokenOwner, to, dwSize, &dwSize))
    {
        dwError = GetLastError();
        std::cout << "GetTokenInformation failed, error " << dwError;
        LocalFree(to);
        CloseHandle(hToken);
        return 0;
    }

    g_pSID = to->Owner;
    return TRUE;
}

//Then I used the iteration through the ACL list:

std::stringstream g_TestSecurityResult;
void TestSecurity( wchar_t* path )
{
    g_TestSecurityResult = std::stringstream();
    GetCurrentProcessSID();
    PACL pDacl; 
    PSECURITY_DESCRIPTOR pSD;
    GetNamedSecurityInfoW(path, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, &pDacl, NULL, &pSD);

    ACL_SIZE_INFORMATION aclSizeInfo = { sizeof(ACL) };

    BOOL fResult = GetAclInformation( pDacl, &aclSizeInfo, sizeof(ACL_SIZE_INFORMATION), ACL_INFORMATION_CLASS::AclSizeInformation );

    if (fResult)
    {
        for (DWORD dwIndex = 0; dwIndex < aclSizeInfo.AceCount; ++dwIndex)
        {
            LPVOID pTempAce = nullptr;

            fResult = ::GetAce(pDacl, dwIndex, &pTempAce);
            if (fResult)
            {
                PSID pSid = &((ACCESS_ALLOWED_ACE*)pTempAce)->SidStart;

                if (EqualSid(pSid, &g_pSID))
                {
                    g_TestSecurityResult << "User: " << userNameFromSid(&g_pSID) << std::endl;
                    g_TestSecurityResult << "\tAccess mode: " << ((EXPLICIT_ACCESS*)pTempAce)->grfAccessMode << "\n";
                    g_TestSecurityResult << "\tAccess permissions: " << ((EXPLICIT_ACCESS*)pTempAce)->grfAccessPermissions << "\n";
                    g_TestSecurityResult << "\tInheritance: " << ((EXPLICIT_ACCESS*)pTempAce)->grfInheritance << "\n";
                    g_TestSecurityResult << std::endl;
                }
            }
            else
            {
                g_TestSecurityResult << "GetAce() failed." << GetLastError();
                break;
            }
        }
    } else {
        g_TestSecurityResult << "Error in GetAclInformation(): " << GetLastError();
    }
}

std::string userNameFromSid(PSID userSid)
{
    char buffName[MAX_BUFF_SIZE];
    DWORD buffNameSize = MAX_BUFF_SIZE;
    char buffDomain[MAX_BUFF_SIZE];
    DWORD buffDomainSize = MAX_BUFF_SIZE;
    SID_NAME_USE SidType;

    if (LookupAccountSid(NULL, userSid, buffName, &buffNameSize, buffDomain, &buffDomainSize, &SidType)) {
        return buffName;
    } else {
        DWORD dwResult = GetLastError();
        printf("GetTokenInformation Error %u\n", dwResult);
    }

    /*Here some code to print error in a Message box*/
    return "";
}

The problem: The code is working but at the line if (EqualSid(pSid, &g_pSID)) debugger goes through and skips the SID that I've received from my process. In other words, I can't get any information from the ACL list, even though I'm running the process and Visual Studio under Administrator account (not using the "Run as Administrator", and I'll try it but still... The received SID is valid and I can get the name of the process owner using the above function. What could be something that I'm doing wrong here?

Code sources: https://gist.github.com/m4x1m1l14n/37f39c5d25855c2b1d3a6334851f7549 How to get the logged-on user's SID in Windows GetTokenInformation, TOKEN_OWNER, и LookupAccountSidA


Solution

  • Thanks to @(Rita Han - MSFT) comment, I've forgotten to remove the ampersand mark from the pSID comparison

    EqualSid(pSid, g_pSID);
    

    instead of

    EqualSid(pSid, &g_pSID);
    

    And It's properly working for now