【问题标题】:WinApi - Denying only "write" permission to "everyone" but allowing "read"WinApi - 仅拒绝“每个人”的“写入”权限,但允许“读取”
【发布时间】:2016-01-19 15:40:44
【问题描述】:

我正在尝试使用 WinAPI 将文件夹设为只读,然后再次使其读/写。我尝试通过拒绝写访问(对于只读部分)并授予所有访问权限(对于读/写部分)来做到这一点。第二部分有效,但对于第一部分,当我尝试打开文件夹时,它告诉我我没有访问它的权限,我什至看不到文件夹中有哪些文件。

这是代码(来自 MSDN 和其他来源):

#include <windows.h>
#include <stdio.h>
#include <accctrl.h>
#include <aclapi.h>
#include <stdio.h>

#pragma comment(lib, "advapi32.lib")

BOOL SetPrivilege(
    HANDLE hToken,          // access token handle
    LPCTSTR lpszPrivilege,  // name of privilege to enable/disable
    BOOL bEnablePrivilege   // to enable or disable privilege
    )
{
    TOKEN_PRIVILEGES tp;
    LUID luid;

    if (!LookupPrivilegeValue(
        NULL,            // lookup privilege on local system
        lpszPrivilege,   // privilege to lookup 
        &luid))        // receives LUID of privilege
    {
        printf("LookupPrivilegeValue error: %u\n", GetLastError());
        return FALSE;
    }

    tp.PrivilegeCount = 1;
    tp.Privileges[0].Luid = luid;
    if (bEnablePrivilege)
        tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    else
        tp.Privileges[0].Attributes = 0;

    // Enable the privilege or disable all privileges.

    if (!AdjustTokenPrivileges(
        hToken,
        FALSE,
        &tp,
        sizeof(TOKEN_PRIVILEGES),
        (PTOKEN_PRIVILEGES)NULL,
        (PDWORD)NULL))
    {
        printf("AdjustTokenPrivileges error: %u\n", GetLastError());
        return FALSE;
    }

    if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)

    {
        printf("The token does not have the specified privilege. \n");
        return FALSE;
    }

    return TRUE;
}

BOOL TakeOwnership(LPTSTR lpszOwnFile, bool bAllowAccess)
{
    BOOL bRetval = FALSE;

    HANDLE hToken = NULL;
    PSID pSIDAdmin = NULL;
    PSID pSIDEveryone = NULL;
    PACL pACL = NULL;
    SID_IDENTIFIER_AUTHORITY SIDAuthWorld =
        SECURITY_WORLD_SID_AUTHORITY;
    SID_IDENTIFIER_AUTHORITY SIDAuthNT = SECURITY_NT_AUTHORITY;
    const int NUM_ACES = 1;
    EXPLICIT_ACCESS ea[NUM_ACES];
    DWORD dwRes;

    ZeroMemory(&ea, NUM_ACES * sizeof(EXPLICIT_ACCESS));

    // Set read access for Everyone.
    ea[0].grfAccessPermissions = (bAllowAccess ? GENERIC_ALL : GENERIC_WRITE);
    ea[0].grfAccessMode = (bAllowAccess ? GRANT_ACCESS : DENY_ACCESS);
    ea[0].grfInheritance = NO_INHERITANCE;
    ea[0].Trustee.TrusteeForm = TRUSTEE_IS_NAME;
    ea[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
    ea[0].Trustee.ptstrName = _T("EVERYONE");// (LPTSTR)pSIDEveryone;

    dwRes = SetEntriesInAcl(NUM_ACES,
        ea,
        NULL,
        &pACL);

    if (ERROR_SUCCESS != dwRes)
    {
        printf("Failed SetEntriesInAcl with error %d\n", dwRes);
        goto Cleanup;
    }

    // Try to modify the object's DACL.
    dwRes = SetNamedSecurityInfo(
        lpszOwnFile,                 // name of the object
        SE_FILE_OBJECT,              // type of object
        DACL_SECURITY_INFORMATION,   // change only the object's DACL
        NULL, NULL,                  // do not change owner or group
        pACL,                        // DACL specified
        NULL);                       // do not change SACL

    if (ERROR_SUCCESS == dwRes)
    {
        printf("Successfully changed DACL\n");
        bRetval = TRUE;
        // No more processing needed.
        goto Cleanup;
    }
    if (dwRes != ERROR_ACCESS_DENIED)
    {
        printf("First SetNamedSecurityInfo call failed: %u\n",
            dwRes);
        goto Cleanup;
    }

    // If the preceding call failed because access was denied, 
    // enable the SE_TAKE_OWNERSHIP_NAME privilege, create a SID for 
    // the Administrators group, take ownership of the object, and 
    // disable the privilege. Then try again to set the object's DACL.

    // Open a handle to the access token for the calling process.
    if (!OpenProcessToken(GetCurrentProcess(),
        TOKEN_ADJUST_PRIVILEGES,
        &hToken))
    {
        printf("OpenProcessToken failed: %u\n", GetLastError());
        goto Cleanup;
    }

    // Enable the SE_TAKE_OWNERSHIP_NAME privilege.
    if (!SetPrivilege(hToken, SE_TAKE_OWNERSHIP_NAME, TRUE))
    {
        printf("You must be logged on as Administrator.\n");
        goto Cleanup;
    }

    // Disable the SE_TAKE_OWNERSHIP_NAME privilege.
    if (!SetPrivilege(hToken, SE_TAKE_OWNERSHIP_NAME, FALSE))
    {
        printf("Failed SetPrivilege call unexpectedly.\n");
        goto Cleanup;
    }

    // Try again to modify the object's DACL,
    // now that we are the owner.
    dwRes = SetNamedSecurityInfo(
        lpszOwnFile,                 // name of the object
        SE_FILE_OBJECT,              // type of object
        DACL_SECURITY_INFORMATION,   // change only the object's DACL
        NULL, NULL,                  // do not change owner or group
        pACL,                        // DACL specified
        NULL);                       // do not change SACL

    if (dwRes == ERROR_SUCCESS)
    {
        printf("Successfully changed DACL\n");
        bRetval = TRUE;
    }
    else
    {
        printf("Second SetNamedSecurityInfo call failed: %u\n",
            dwRes);
    }

Cleanup:

    if (pSIDAdmin)
        FreeSid(pSIDAdmin);

    if (pSIDEveryone)
        FreeSid(pSIDEveryone);

    if (pACL)
        LocalFree(pACL);

    if (hToken)
        CloseHandle(hToken);

    return bRetval;

}

int main(int argc, char* argv[])
{
    bool allow = false; //true

    TakeOwnership(argv[1], allow);

    return 0;
}

谁能告诉我我做错了什么?

【问题讨论】:

    标签: c winapi permissions


    【解决方案1】:

    您的问题是您实际上并没有授予自己对该目录的读取权限。您的代码正在做的是有效地设置一个如下所示的 DACL:

    DENY GENERIC_WRITE to Everyone
    

    现在,当您尝试列出应用程序尝试使用 GENERIC_READ 访问权限打开的目录时。操作系统将执行访问检查,它查看 DACL 中的第一个条目,没有看到读取请求和写入掩码之间的匹配,因此跳过它。操作系统现在已经用完了访问控制条目,所以它唯一能做的就是拒绝你访问。要解决此问题,您需要第二个 ACE,使其看起来像:

    DENY  GENERIC_WRITE to Everyone
    GRANT GENERIC_READ  to Everyone
    

    您应该可以通过以下方式做到这一点:

    const int NUM_ACES = 2;
    EXPLICIT_ACCESS ea[NUM_ACES];
    DWORD dwRes;
    
    ZeroMemory(&ea, NUM_ACES * sizeof(EXPLICIT_ACCESS));
    
    DWORD dwMask = FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | FILE_APPEND_DATA;
    ea[0].grfAccessPermissions = (bAllowAccess ? GENERIC_ALL : dwMask);
    ea[0].grfAccessMode = (bAllowAccess ? GRANT_ACCESS : DENY_ACCESS);
    ea[0].grfInheritance = NO_INHERITANCE;
    ea[0].Trustee.TrusteeForm = TRUSTEE_IS_NAME;
    ea[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
    ea[0].Trustee.ptstrName = _T("EVERYONE");
    
    ea[1].grfAccessPermissions = GENERIC_READ;
    ea[1].grfAccessMode = GRANT_ACCESS;
    ea[1].grfInheritance = NO_INHERITANCE;
    ea[1].Trustee.TrusteeForm = TRUSTEE_IS_NAME;
    ea[1].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
    ea[1].Trustee.ptstrName = _T("EVERYONE");
    

    【讨论】:

    • 它告诉我我没有访问它的权限,我什至看不到文件夹中有哪些文件。
    • 问题是 GENERIC_WRITE 实际上拖入了 READ_CONTROL 右侧,这也是 GENERIC_READ 的一部分。因此,当某些东西打开它进行读取时,它无法获得 GENERIC_READ。从技术上讲,您不需要第二个 ACE,但它有助于解决用户无法获得访问权限的情况。
    猜你喜欢
    • 2016-06-05
    • 2012-10-14
    • 2017-06-20
    • 2016-08-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-11
    • 1970-01-01
    相关资源
    最近更新 更多