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