Home > Enterprise >  Exact way to get permissions of a file in windows using C and api
Exact way to get permissions of a file in windows using C and api

Time:10-25

My project is like i need to modify the file permissions from a web application. I'm using java for backend and emberjs for client side. To get the file permissions I'm using C native code with windows api with JNI. Here is my problem,

I need to get the permissions of the files in a directory in windows using api. I'm new to windows api so I've googled and got the below code and modified it to my needs. Now the problem is when i run this, it gives me the results when the file has "Full Control" as permission otherwise the permissions are not showing. Please help me with this. What need to be modified in here or if there are any other possible solutions, please suggest me that too. Thanks in advance.

Here is my code,

#include <Windows.h>
#include <vector>
#include <map>
#include <iostream>
#include <aclapi.h>
#include <windows.h>
#include <string>
#include <memory>
#include <tchar.h>


using namespace std;

bool CanAccessFolder(LPCTSTR folderName, DWORD genericAccessRights,DWORD& grantedRights)
{
    bool bRet = false;
    DWORD length = 0;
    if (!::GetFileSecurity(folderName, OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION
        | DACL_SECURITY_INFORMATION, NULL, NULL, &length) &&
        ERROR_INSUFFICIENT_BUFFER == ::GetLastError()) {
        PSECURITY_DESCRIPTOR security = static_cast< PSECURITY_DESCRIPTOR >(::malloc(length));
        if (security && ::GetFileSecurity(folderName, OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION
            | DACL_SECURITY_INFORMATION, security, length, &length)) {
            HANDLE hToken = NULL;
            if (::OpenProcessToken(::GetCurrentProcess(), TOKEN_IMPERSONATE | TOKEN_QUERY |
                TOKEN_DUPLICATE | STANDARD_RIGHTS_READ, &hToken)) {
                HANDLE hImpersonatedToken = NULL;
                if (::DuplicateToken(hToken, SecurityImpersonation, &hImpersonatedToken)) {
                    GENERIC_MAPPING mapping = { 0xFFFFFFFF };
                    PRIVILEGE_SET privileges = { 0 };
                    DWORD grantedAccess = 0, privilegesLength = sizeof(privileges);
                    BOOL result = FALSE;

                    mapping.GenericRead = FILE_GENERIC_READ;
                    mapping.GenericWrite = FILE_GENERIC_WRITE;
                    mapping.GenericExecute = FILE_GENERIC_EXECUTE;
                    mapping.GenericAll = FILE_ALL_ACCESS;

                    ::MapGenericMask(&genericAccessRights, &mapping);
                    if (::AccessCheck(security, hImpersonatedToken, genericAccessRights,
                        &mapping, &privileges, &privilegesLength, &grantedAccess, &result)) 
                    {
                        bRet = (result == TRUE);
                        grantedRights = grantedAccess;
                    }
                    ::CloseHandle(hImpersonatedToken);
                }
                ::CloseHandle(hToken);
            }
            ::free(security);
        }
    }

    return bRet;
}

 vector<string> printMasks(DWORD Mask)
 {
     // This evaluation of the ACCESS_MASK is an example.
     // Applications should evaluate the ACCESS_MASK as necessary.
     vector<string> access;
    std::wcout << "Effective Allowed Access Mask :  "<< Mask << std::hex << std::endl;
     if (((Mask & GENERIC_ALL) == GENERIC_ALL)
         || ((Mask & FILE_ALL_ACCESS) == FILE_ALL_ACCESS))
     {
        //  wprintf_s(L"Full Control\n");
         access.push_back("Full Control");
        //  return access;
     }
     if (((Mask & GENERIC_READ) == GENERIC_READ)
         || ((Mask & FILE_GENERIC_READ) == FILE_GENERIC_READ))
        //  wprintf_s(L"Read\n");
         access.push_back("Read");
     if (((Mask & GENERIC_WRITE) == GENERIC_WRITE)
         || ((Mask & FILE_GENERIC_WRITE) == FILE_GENERIC_WRITE))
        //  wprintf_s(L"Write\n");
         access.push_back("Write");
     if (((Mask & GENERIC_EXECUTE) == GENERIC_EXECUTE)
         || ((Mask & FILE_GENERIC_EXECUTE) == FILE_GENERIC_EXECUTE))
        //  wprintf_s(L"Execute\n");
         access.push_back("Execute");

    return access;
 }


std::map<std::string, std::vector<std::string>>
list_directory(const std::string &directory)
{
    DWORD access_mask = FILE_GENERIC_READ | FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE | FILE_ALL_ACCESS;
    std::map<std::string, std::vector<std::string>> files;
    WIN32_FIND_DATAA findData;
    HANDLE hFind = INVALID_HANDLE_VALUE;
    std::string full_path = directory   "\\*";

    hFind = FindFirstFileA(full_path.c_str(), &findData);

    if (hFind == INVALID_HANDLE_VALUE)
        throw std::runtime_error("Invalid handle value! Please check your path...");

    while (FindNextFileA(hFind, &findData) != 0)
    {
        std::string file = findData.cFileName;
        std::string filepath = directory   "/"   file;
        DWORD grant = 0;
        bool b = CanAccessFolder(filepath.c_str(), access_mask, grant);
        files[file] = printMasks(grant);
    }

    FindClose(hFind);

    return files;
}


int main() {
    std::map<std::string, std::vector<std::string>> files;
    files = list_directory("C:/Users/Vicky/Desktop/samples");

    int i = 1;

    map<string, vector<string>> :: iterator it=files.begin();
    //iteration using traditional for loop
    for(it=files.begin();it!=files.end();it  )
    {
        //accessing keys
        cout << it->first << " : \t";
        //accessing values (vectors)
        for (auto &&i : it->second)
        {
            cout << i << "\t";
        }
        cout << endl;
    }
}

Here are the results,

Result Screenshot

sample1.txt permissions

sample2.txt permissions

CodePudding user response:

When you are performing the access check the line

    DWORD access_mask = FILE_GENERIC_READ | FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE | FILE_ALL_ACCESS;

Is specifying that you are checking that the if you have read/write/execute/full control access to each item you are checking.

As a result when you call AccessCheck on sample2.txt where you don't have all those permissions AccessCheck reports in its last parameter that you don't have access. In that case MSDN for the GrantedAccess parameter states

[out] GrantedAccess

A pointer to an access mask that receives the granted access rights. If >AccessStatus is set to FALSE, the function sets the access mask to zero. If the function fails, it does not set the access mask.

That access mask of all zero's is what you are printing out for sample2.txt

If you want to see what you can actually do for each file change the line above to

DWORD access_mask = MAXIMUM_ALLOWED;

This causes the file to be checked for whatever access it can get hold of rather than full control which it does not have.

  • Related