* 更新 *
答案非常有帮助,现在我的代码正在返回 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
orSetNamedSecurityInfo
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_OWNER
或 WRITE_DAC
,因此您必须明确指定它们。
(我找不到关于 GENERIC_ALL
中包含哪些文件权限的任何文档,但即使它有效,最好明确请求您将使用的权限。)
关于c - Windows 上的 fchown() 似乎无法在 C 中实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25005916/