*更新*
答案已经非常有帮助,现在我的代码返回ERROR_SUCCESS
。 关键的变化似乎是切换到使用SetKernelObjectSecurity()
。 但是,现在我看到一个不同的问题。 我的代码成功,但如果我看文件系统或检查代码中的文件,它仍然有以前的所有者。
这在SO之前已经被报道过 ,但没有一个满意的答案。
这是我的代码公开要点 。 它增加了一些输出,所以你可以看到我在说什么。 您应该可以将其添加到一个空的Visual Studio C ++控制台项目并通过它进行debugging。 确保使用“以pipe理员身份运行”打开Visual Studio。
*第二次更新*
我刚刚在MSDN上为SetKernelObjectSecurity()
发现了这个注释。
注意在文件系统对象上设置安全描述符时,不应使用此函数。 而是使用
SetSecurityInfo
或SetNamedSecurityInfo
函数。
我不知道我是如何错过的…这是正确的。
*原始问题*
我需要在Windows上实现fchown()
的等效function,但经过相当多的研究和努力,我一直无法使其工作。 fchown()
更改通过打开的文件描述符指定的文件的所有权。 在Windows的情况下,这可能是一个打开的文件描述符或HANDLE
(你可以创build一个从另一个)。 看来,无论我尝试什么,我都会得到ERROR_ACCESS_DENIED
。
我已经尝试了SetSecurityInfo()
和SetUserObjectInfo()
。 我可以使用相应的Get *函数GetSecurityInfo()
和GetUserObjectSecurity()
从打开的文件描述符中获取所有权信息。
当我重写我的代码来使用SetNamedSecurityInfo()
或SetFileSecurity()
,在那里你指定文件的名称,而不是一个打开的句柄,一切工作正常。
我是否遇到了操作系统的低级文件系统访问控制规则?
是不是可以改变Windows上打开的文件的所有权?
从我所知道的情况来看,当HANDLE打开的时候我甚至不能改变DACL。 是Windows只是试图防止我从一个错误的安全感,当我认为我已经获得文件,但有人仍然有一个开放的处理?
在我看来,如果我失去了一些东西,这可能是我如何调用CreateFile()
。
预期可能发布的一些答案:
(另外,请记住我通过简单地将Win32 API的对象版本replace为带有文件名的对象)
AdjustTokenPrivileges()
来给自己SE_TAKE_OWNERSHIP_NAME
dwShareMode
传递0给CreateFile()
来显式打开文件。 这是一些代码。 我已经删除了所有的error handling,所以这个问题不会太长:
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>
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只需在打开句柄时检查对象的访问权限;从此,完全基于句柄的访问权限授予或拒绝访问权限。)
SECURITY_INFORMATION
上的文档显示了在句柄上您需要哪些访问权限以查询和设置各种信息。 在你的情况下,你需要WRITE_OWNER
分配所有权和主组, WRITE_DAC
分配DACL, READ_CONTROL
读所有权,主组和DACL。
请注意, GENERIC_WRITE
不包含WRITE_OWNER
或WRITE_DAC
因此您必须明确指定它们。
(我找不到任何有关GENERIC_ALL
包含哪些文件权限的文档,但即使它能正常工作,最好明确地请求您将要使用的权限。)
SetUserObjectInfo
和GetUserObjectSecurity
在“用户”对象上工作,广义地说,它们是窗口管理器对象。 文件是内核对象,因此您需要像SetcoreelObjectSecurity
这样的名称来使用coreel
中的函数。 请参阅对象类别 。
这就是说, SetSecurityInfo
应该工作。
SetFileSecurity
正在为你工作,所以你必须有适当的权限。
很可能,您在CreateFile
调用中没有请求正确的访问权限。 哈里·约翰斯顿写了更多的这个,所以看到他的答案的细节。