*更新*
答案非常有用,现在我的代码正在返回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()
的这条说明。
注意在文件系统对象上设置安全描述符时,不应使用此函数。相反,请使用
SetSecurityInfo
或SetNamedSecurityInfo
函数。
我不确定我是如何错过的......它位于顶部。
*原始问题*
我需要在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
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);
来明确打开文件。这是一些代码。我删除了所有错误处理,以便这个问题不会太长:
#include <Windows.h>
#include <AclAPI.h>
#include <Sddl.h>
#include <stdio.h>
你需要这些标题:
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;
}
SetPrivilege()函数是:
{{1}}
答案 0 :(得分:6)
您已通过GENERIC_READ
访问权限打开了句柄。 Windows强制执行此操作;以这种方式打开句柄,你只能在读操作中使用句柄。 (这意味着Windows只需在您打开句柄时检查您对该对象的访问权限;从那时起,完全根据句柄的访问权限授予或拒绝访问。)
documentation on SECURITY_INFORMATION
显示您在句柄上需要哪些访问权限,以便查询和设置各种信息。在您的情况下,您需要WRITE_OWNER
分配所有权和主要群组,WRITE_DAC
分配DACL,READ_CONTROL
来分配所有权,主要群组和DACL。
请注意,GENERIC_WRITE
不包含WRITE_OWNER
或WRITE_DAC
,因此您必须明确指定它们。
(我找不到GENERIC_ALL
中包含哪些文件权限的任何文档,但即使它有效,也最好明确请求您将使用的权限。)
答案 1 :(得分:3)
SetUserObjectInfo
和GetUserObjectSecurity
处理“用户”对象,一般来说,它们是窗口管理器对象。文件是内核对象,因此您需要名称为Kernel
的{{1}}函数。请参阅Object Categories。
尽管如此,SetKernelObjectSecurity
应该有用。
SetSecurityInfo
正在为您服务,因此您必须拥有相应的权限。
最有可能的是,您未在SetFileSecurity
的调用中请求正确的访问权限。哈里约翰斯顿在这方面写了更多,所以请看详细解答。