Win32 API:为当前用户创建公共文件,但为其他人创建私有文件

时间:2016-10-17 02:34:18

标签: c++ winapi visual-c++ sid dacl

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

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

文件创建成功并且显然已成功设置权限(请参阅下面的屏幕截图),但是当我尝试使用记事本打开文件时,它表示"访问被拒绝" (我的文件浏览器在同一会话下运行),如果我打开命令提示符并执行"键入file_created.txt"相同的"访问被拒绝"出现。

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

包含所有人权限的图片: enter image description here

具有当前用户权限的图片: enter image description here

代码:

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

注意:我意识到代码有内存泄漏和其他问题,我只是很快就黑客去测试这个想法。

1 个答案:

答案 0 :(得分:6)

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