*更新*

答案非常有帮助,现在我的代码返回了ERROR_SUCCESS。关键的变化似乎是切换到使用SetKernelObjectSecurity()。但是,现在我看到了另一个问题。我的代码成功,但是如果我在文件系统上查看或检查代码中的文件,则该文件仍具有先前的所有者。

This has been reported before on SO,但没有令人满意的答案。

Here is a public gist with my code。它添加了一些输出,因此您可以看到我在说什么。您应该能够将其添加到一个空的Visual Studio C++ Console项目中并通过它进行调试。确保使用“以管理员身份运行”打开Visual Studio。

*第2次更新*

我刚刚在MSDN上找到了 SetKernelObjectSecurity() 的注释。



我不确定我是怎么错过的...它在顶部。

*原始问题*

我需要在Windows上实现 fchown() 的等效功能,但是经过大量的研究和努力,我无法使其工作。 fchown()更改通过打开的文件描述符指定的文件的所有权。对于Windows,这可以是打开的文件描述符,也可以是HANDLE(可以从另一个创建)。看来,不管我尝试什么,我都会得到ERROR_ACCESS_DENIED

我已经尝试了 SetSecurityInfo() SetUserObjectInfo() 。我可以使用相应的Get *函数从打开的文件描述符中获取所有权信息: GetSecurityInfo() GetUserObjectSecurity()

当我重新编写代码以使用 SetNamedSecurityInfo() SetFileSecurity() 时,在其中为文件指定名称而不是打开的HANDLE,一切正常。

我是否遇到了操作系统的低级文件系统访问控制规则?

是否可以在Windows上更改打开文件的所有权?

据我所知,当HANDLE打开时,我什至无法更改DACL。 当我认为我已经保护了文件但有人仍然有打开的HANDLE时,Windows是否只是试图防止我产生错误的安全感?

在我看来,如果我缺少某些东西,可能就是我如何调用CreateFile()

预期可能会发布一些答案:

(此外,请记住,我只是通过将Win32 API的对象版本替换为带有文件名的对象版本来完成此工作)

  • 我正在提升的进程中运行
  • 我叫 AdjustTokenPrivileges() 给自己SE_TAKE_OWNERSHIP_NAME
  • 我已经通过了DACL和流程 token 中的权限-我相信我正在以具有足够权限的用户身份运行(否则为什么它将与文件名一起使用)
  • 我试图通过将CreateFile()的0传递给 dwShareMode 来显式打开文件。

  • 这是一些代码。我删除了所有错误处理,因此这个问题不会太长:
    wchar_t* filename = L"test.txt";
    HANDLE hFile = CreateFile(filename, GENERIC_READ, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    HANDLE hToken = NULL;
    OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken);
    SetPrivilege(hToken, SE_BACKUP_NAME, TRUE);
    SetPrivilege(hToken, SE_RESTORE_NAME, TRUE);
    SetPrivilege(hToken, SE_SECURITY_NAME, TRUE);
    SetPrivilege(hToken, SE_TAKE_OWNERSHIP_NAME, TRUE);
    DWORD bufSize = 0;
    SECURITY_INFORMATION info = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION;
    GetUserObjectSecurity(hFile, &info, NULL, 0, &bufSize); /* get buffer size */
    PSECURITY_DESCRIPTOR desc = (PSECURITY_DESCRIPTOR)calloc(bufSize, sizeof(BYTE));
    GetUserObjectSecurity(hFile, &info, desc, bufSize, &bufSize);
    TRUSTEE trustee = { 0 };
    BuildTrusteeWithSid(&trustee, newOwnerSid);
    PSECURITY_DESCRIPTOR newdesc = NULL;
    BuildSecurityDescriptor(&trustee, NULL, 0, NULL, 0, NULL, desc, &bufSize, &newdesc);
    SetUserObjectSecurity(hFile, &info, newdesc);
    free(desc);
    LocalFree(newdesc);
    CloseHandle(hToken);
    CloseHandle(hFile);
    

    您将需要以下 header :
    #include <Windows.h>
    #include <AclAPI.h>
    #include <Sddl.h>
    #include <stdio.h>
    

    SetPrivilege()函数为:
    static
    BOOL
    SetPrivilege(HANDLE hToken, LPCTSTR lpszPrivilege, BOOL bEnablePrivilege) {
        TOKEN_PRIVILEGES newState = { 0 };
        LUID luid;
        if (!LookupPrivilegeValue(NULL, lpszPrivilege, &luid)) {
             return FALSE;
        }
        newState.PrivilegeCount = 1;
        newState.Privileges[0].Luid = luid;
        if (bEnablePrivilege) {
             newState.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
        }
        else {
             newState.Privileges[0].Attributes = 0;
        }
        /* If this returns a failure then your process does not have the ability to grant the privilege. */
        if (!AdjustTokenPrivileges(hToken, FALSE, &newState, sizeof(TOKEN_PRIVILEGES), NULL, NULL)) {
            return FALSE;
        }
        if (GetLastError() == ERROR_NOT_ALL_ASSIGNED) {
            return FALSE;
        }
        return TRUE;
    }
    

    最佳答案

    您已使用GENERIC_READ访问权限打开了句柄。 Windows强制执行此操作;以这种方式打开 handle 后,您只能在读取操作中使用该 handle 。 (这意味着Windows仅在打开句柄时才检查对对象的访问;从那时起,完全基于句柄的访问权限来授予或拒绝访问。)

    documentation on SECURITY_INFORMATION 显示在句柄上需要哪些访问权限才能查询和设置各种信息。在您的情况下,您将需要WRITE_OWNER来分配所有权和主要组,WRITE_DAC来分配DACL,以及READ_CONTROL来读取所有权,主要组和DACL。

    请注意,GENERIC_WRITE不包括WRITE_OWNERWRITE_DAC,因此您必须明确指定它们。

    (我找不到关于GENERIC_ALL中包含哪些文件权限的任何文档,但是即使它起作用,也最好显式地请求您将使用的权限。)

    关于c - Windows上的fchown()似乎无法在C中实现,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/25005916/

    10-15 00:18
    查看更多