c - Windows 上的 fchown() 似乎无法在 C 中实现

标签 c windows winapi

* 更新 *

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

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

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

* 第二次更新 *

我刚刚在 MSDN 上找到关于 SetKernelObjectSecurity() 的注释.

Note This function should not be used when setting a security descriptor on file system objects. Instead, use the SetSecurityInfo or SetNamedSecurityInfo functions.

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


* 原始问题 *

我需要实现 fchown() 的等效功能在 Windows 上,但经过相当多的研究和努力,我一直无法让它工作。 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 中的权限——我相信我正在以具有足够权限的用户身份运行(否则为什么它会使用文件名)
  • 我试图通过将 0 传递给 CreateFile() 来显式打开文件对于 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强制执行此操作;以这种方式打开句柄后,您只能在读取操作中使用句柄。 (这意味着 Windows 只需要在您打开句柄时检查您对该对象的访问权限;从那时起,完全根据句柄的访问权限授予或拒绝访问权限。)

documentation on SECURITY_INFORMATION显示您需要在 handle 上获得哪些访问权限,以便查询和设置各种信息。在您的情况下,您需要 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/

相关文章:

c++ - Win32 编辑控件大小写混合

C - 为什么这个循环运行两次?

c - 在 C 代码中包含 wpa_ctrl.h

c - 尝试释放链接列表时出现 SIGABRT

c# - 是否可以在 C# 中获取指定文件的资源管理器上下文菜单?

windows - Azure 虚拟机 (Windows) 的最佳工作流程是什么?

iphone - 使用arm-apple-darwin10-llvm-gcc-4.2将C交叉编译为armv7

Java 标准输入编码 Windows cmd、Netbeans

c++ - Windows 的原始鼠标输入

创建文件 - dwDesiredAccess