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

pet*_*snd 8 c windows winapi

*更新*

答案非常有用,现在我的代码正在返回ERROR_SUCCESS.关键的变化似乎是转向使用SetKernelObjectSecurity().但是,现在我看到了一个不同的问题; 我的代码成功,但如果我查看文件系统或在代码中检查文件,它仍然有以前的所有者.

之前已经报道了SO,但没有一个令人满意的答案.

这是我的代码的公开要点.它增加了一些输出,所以你可以看到我在说什么.您应该能够将它添加到空的Visual Studio C++控制台项目并通过它进行调试.务必使用"以管理员身份运行"打开Visual Studio.

*第二次更新*

我刚刚在MSDN上找到了这个注释SetKernelObjectSecurity().

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

我不确定我是怎么错过的......它就在顶部.


*原始问题*

我需要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和我的进程令牌中的权限 - 我相信我作为具有足够权限的用户运行(否则为什么它会与文件名一起使用)
  • 我想明确地通过传递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);
Run Code Online (Sandbox Code Playgroud)

你需要这些标题:

#include <Windows.h>
#include <AclAPI.h>
#include <Sddl.h>
#include <stdio.h>
Run Code Online (Sandbox Code Playgroud)

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;
}
Run Code Online (Sandbox Code Playgroud)

Har*_*ton 6

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

对文档SECURITY_INFORMATION哪些访问权限显示您需要在手柄上,以便查询和设置的各种信息.在您的情况下,您需要WRITE_OWNER分配所有权和主要组,WRITE_DAC分配DACL,以及READ_CONTROL读取所有权,主要组和DACL.

请注意,GENERIC_WRITE不包括任何WRITE_OWNER或者WRITE_DAC所以你必须明确指定.

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