Win32 API: 正在为当前用户创建文件 public 但对其他人私有

Win32 API: Creating file public for current user but private for everyone else

我正在使用 Win32 API 在 C 语言中测试以下代码,目的是创建一个新文件,该文件可供当前用户访问,但对其他所有人私有(不可访问)。

为此我拒绝了所有人 SID 的所有权限,然后为当前的用户 SID 设置了权限。

文件创建成功,权限显然设置成功(见下面的截图),但是当我尝试用记事本打开文件时,它显示"access is denied"(我的文件浏览器是运行 在同一会话下),如果我打开命令提示符并执行 "type file_created.txt" 相同的 "access is denied" 出现。

我当然可以手动恢复权限,因为我是管理员,但我的想法是让它以编程方式工作。

具有所有人权限的图像:

当前用户权限的图像:

代码:

#include <windows.h>
#include <AccCtrl.h>
#include <aclapi.h>

#include <stdio.h>
#include <stdexcept>
#include <string>

#undef UNICODE

int GetCurrentUserSid(PSID* pSID)
{
  const int MAX_NAME = 256;
  DWORD i, dwSize = 0;
  HANDLE hToken;
  PTOKEN_USER user;
  TOKEN_INFORMATION_CLASS TokenClass = TokenUser;

  if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ | TOKEN_QUERY, &hToken))
    return GetLastError();
  else
    wprintf(L"OpenProcessToken() - got the handle to the access token!\n");

  if (!GetTokenInformation(hToken, TokenClass, NULL, 0, &dwSize))
  {
    DWORD dwResult = GetLastError();
    if (dwResult != ERROR_INSUFFICIENT_BUFFER)
    {
      wprintf(L"GetTokenInformation() failed, error %u\n", dwResult);
      return FALSE;
    }
    else
      wprintf(L"GetTokenInformation() - have an ample buffer...\n");
  }
  else
    wprintf(L"GetTokenInformation() - buffer for Token group is OK\n");

  user = (PTOKEN_USER)LocalAlloc(GPTR, dwSize);
  if (!GetTokenInformation(hToken, TokenClass, user, dwSize, &dwSize))
  {
    wprintf(L"GetTokenInformation() failed, error %u\n", GetLastError());
    return FALSE;
  }
  else
    wprintf(L"GetTokenInformation() for getting the TokenGroups is OK\n");

  DWORD dw_sid_len = GetLengthSid(user->User.Sid);
  *pSID = (SID*)LocalAlloc(GPTR, dw_sid_len);
  CopySid(dw_sid_len, *pSID, user->User.Sid);
  return 0;
}

DWORD set_file_security(LPSTR filename)
{
  PACL pNewDACL = NULL;
  PSID current_user = NULL;
  DWORD sid_size = SECURITY_MAX_SID_SIZE;
  SID everyone_sid;
  DWORD dwRes;
  if (CreateWellKnownSid(WinWorldSid, NULL, &everyone_sid, &sid_size) ==
    FALSE) {
    throw std::runtime_error("CreateWellKnownSid() failed: " +
      std::to_string(GetLastError()));
  }

  GetCurrentUserSid(&current_user);

  EXPLICIT_ACCESSA ea[2];
  ZeroMemory(&ea, 2 * sizeof(EXPLICIT_ACCESSA));

  ea[0].grfAccessPermissions = ACCESS_SYSTEM_SECURITY | READ_CONTROL | WRITE_DAC | GENERIC_ALL;
  ea[0].grfAccessMode = GRANT_ACCESS;
  ea[0].grfInheritance = NO_INHERITANCE;
  ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
  ea[0].Trustee.ptstrName = reinterpret_cast<char*>(current_user);

  ea[1].grfAccessPermissions = ACCESS_SYSTEM_SECURITY | READ_CONTROL | WRITE_DAC | GENERIC_ALL;
  ea[1].grfAccessMode = DENY_ACCESS;
  ea[1].grfInheritance = NO_INHERITANCE;
  ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
  ea[1].Trustee.ptstrName = reinterpret_cast<char*>(&everyone_sid);

  dwRes = SetEntriesInAclA(2, ea, NULL, &pNewDACL);
  if (ERROR_SUCCESS != dwRes) {
    printf("SetEntriesInAcl Error %u\n", dwRes);
    //TODO: goto Cleanup;
  }

  PSECURITY_DESCRIPTOR pSD = NULL;

  // Initialize a security descriptor.  
  pSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR,
    SECURITY_DESCRIPTOR_MIN_LENGTH);
  if (NULL == pSD)
  {
    _tprintf(_T("LocalAlloc Error %u\n"), GetLastError());
    goto Cleanup;
  }

  if (!InitializeSecurityDescriptor(pSD,
    SECURITY_DESCRIPTOR_REVISION))
  {
    _tprintf(_T("InitializeSecurityDescriptor Error %u\n"),
      GetLastError());
    goto Cleanup;
  }

  // Add the ACL to the security descriptor. 
  if (!SetSecurityDescriptorDacl(pSD,
    TRUE,     // bDaclPresent flag   
    pNewDACL,
    FALSE))   // not a default DACL
  {
    _tprintf(_T("SetSecurityDescriptorDacl Error %u\n"),
      GetLastError());
    goto Cleanup;
  }
  SECURITY_ATTRIBUTES sa;
  // Initialize a security attributes structure.
  sa.nLength = sizeof(SECURITY_ATTRIBUTES);
  sa.lpSecurityDescriptor = pSD;
  sa.bInheritHandle = FALSE;

  HANDLE hFile = CreateFileA(filename, GENERIC_ALL, 0, &sa, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);  
  CloseHandle(hFile);

  //dwRes = SetNamedSecurityInfoA(filename, SE_FILE_OBJECT,
  //  DACL_SECURITY_INFORMATION, NULL, NULL, pNewDACL, NULL);
  //if (ERROR_SUCCESS != dwRes) {
  //  printf("SetNamedSecurityInfo Error %u\n", dwRes);
  //  //goto Cleanup;
  //}

Cleanup:

  if (pNewDACL != NULL)
    LocalFree((HLOCAL)pNewDACL);

  return dwRes;
}

int main()
{
  //return 0;

  // Create Everyone SID.
  DWORD sid_size = SECURITY_MAX_SID_SIZE;
  SID everyone_sid;
  if (CreateWellKnownSid(WinWorldSid, NULL, &everyone_sid, &sid_size) ==
    FALSE) {
    throw std::runtime_error("CreateWellKnownSid() failed: " +
      std::to_string(GetLastError()));
  }

  LPSTR filename = "created_file.txt";  

  set_file_security(filename);

  return 0;
}

注意:我意识到代码存在内存泄漏和其他问题,我只是快速修改以测试这个想法。

在 Windows OS 中,显式拒绝权限优先于显式允许权限。因此,由于 "Everyone" 组包含您的帐户,因此即使您为自己启用了该文件,访问该文件也会被拒绝。事实上你完全不需要拒绝规则,如果某些用户的对象ACL中没有设置访问权限,默认情况下访问将被拒绝。