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

时间:2014-07-28 23:26:03

标签: 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()的这条说明。

  

注意在文件系统对象上设置安全描述符时,不应使用此函数。相反,请使用SetSecurityInfoSetNamedSecurityInfo函数。

我不确定我是如何错过的......它位于顶部。


*原始问题*

我需要在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
  • 我已经浏览了DACL和我的进程令牌中的权限 - 我相信我是以具有足够权限的用户身份运行的(否则为什么会使用文件名)
  • 我尝试通过将{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); 来明确打开文件。

这是一些代码。我删除了所有错误处理,以便这个问题不会太长:

#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}}

2 个答案:

答案 0 :(得分:6)

您已通过GENERIC_READ访问权限打开了句柄。 Windows强制执行此操作;以这种方式打开句柄,你只能在读操作中使用句柄。 (这意味着Windows只需在您打开句柄时检查您对该对象的访问权限;从那时起,完全根据句柄的访问权限授予或拒绝访问。)

documentation on SECURITY_INFORMATION显示您在句柄上需要哪些访问权限,以便查询和设置各种信息。在您的情况下,您需要WRITE_OWNER分配所有权和主要群组,WRITE_DAC分配DACL,READ_CONTROL来分配所有权,主要群组和DACL。

请注意,GENERIC_WRITE不包含WRITE_OWNERWRITE_DAC,因此您必须明确指定它们。

(我找不到GENERIC_ALL中包含哪些文件权限的任何文档,但即使它有效,也最好明确请求您将使用的权限。)

答案 1 :(得分:3)

SetUserObjectInfoGetUserObjectSecurity处理“用户”对象,一般来说,它们是窗口管理器对象。文件是内核对象,因此您需要名称为Kernel的{​​{1}}函数。请参阅Object Categories

尽管如此,SetKernelObjectSecurity应该有用。

SetSecurityInfo正在为您服务,因此您必须拥有相应的权限。

最有可能的是,您未在SetFileSecurity的调用中请求正确的访问权限。哈里约翰斯顿在这方面写了更多,所以请看详细解答。