他人の空似自作物置場

TestPrivateSharedMemory.zip/TestPrivateSharedMemory/TestPrivateSharedMemory.cpp


#include <iostream>
#include <vector>
#include <string>
#include <sstream>

#include <boost/shared_ptr.hpp>
#include <boost/filesystem.hpp>
#include <boost/foreach.hpp>

#include <Windows.h>
#include <Userenv.h>
#include <AclAPI.h>
#include <sddl.h>
#include <winerror.h>

#include "SharedStruct.h"

#pragma comment(lib, "Userenv.lib")

typedef boost::shared_ptr<boost::remove_pointer<PSID>::type> SHARED_SID;
void MyFreeSid(PSID sid) {
  if (sid != NULL) {
    ::FreeSid(sid);
  }
}
SHARED_SID ToSharedSID(PSID sid) {
  return SHARED_SID(sid, &MyFreeSid);
}

typedef boost::shared_ptr<boost::remove_pointer<PACL>::type> SHARED_ACL;
unsigned int GetACLSize(const std::vector<SHARED_SID> &list) {
  unsigned int size = sizeof(ACL)+ (sizeof(ACCESS_ALLOWED_ACE)* list.size());
  BOOST_FOREACH(const SHARED_SID &sid, list) {
    size += ::GetLengthSid(sid.get()) - sizeof(DWORD);
  }
  // align
  size = (size + sizeof(DWORD)- 1) & 0xfffffffc;
  return size;
}
SHARED_ACL CreatePACL1(const std::vector<SHARED_SID> &list) {
  std::vector<EXPLICIT_ACCESSW> * const eaList = new std::vector<EXPLICIT_ACCESSW>();

  BOOST_FOREACH(const SHARED_SID &sid, list) {
    EXPLICIT_ACCESSW ea[2];
    ea[0].grfAccessPermissions = STANDARD_RIGHTS_ALL | PAGE_READWRITE;
    ea[0].grfAccessMode = SET_ACCESS;
    ea[0].grfInheritance = NO_INHERITANCE;
    ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
    ea[0].Trustee.TrusteeType = TRUSTEE_IS_USER;
    ea[0].Trustee.ptstrName = reinterpret_cast<LPWSTR>(sid.get());

    ea[1].grfAccessPermissions = STANDARD_RIGHTS_ALL | PAGE_READWRITE;
    ea[1].grfAccessMode = SET_ACCESS;
    ea[1].grfInheritance = NO_INHERITANCE;
    ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
    ea[1].Trustee.TrusteeType = TRUSTEE_IS_GROUP;
    ea[1].Trustee.ptstrName = reinterpret_cast<LPWSTR>(sid.get());
    eaList->push_back(ea[0]);
    eaList->push_back(ea[1]);
  }
  PACL acl;
  SetEntriesInAclW(eaList->size(), &eaList->front(), NULL, &acl);
  return SHARED_ACL(acl, [](PACL acl){});
}
SHARED_ACL CreatePACLDacl(const std::vector<SHARED_SID> &list) {
  const unsigned int size = GetACLSize(list);
  const SHARED_ACL acl(reinterpret_cast<PACL>(new unsigned char[size]));
  if (::InitializeAcl(acl.get(), size, ACL_REVISION) == FALSE) {
    return SHARED_ACL();
  }
  BOOST_FOREACH(const SHARED_SID &sid, list) {
    if (::AddAccessAllowedAce(acl.get(), ACL_REVISION, GENERIC_ALL, sid.get()) == FALSE) {
      return SHARED_ACL();
    }
  }
  return acl;
}
SHARED_ACL CreatePACLSacl(const std::vector<SHARED_SID> &list) {
  const unsigned int size = GetACLSize(list);
  const SHARED_ACL acl(reinterpret_cast<PACL>(new unsigned char[size]));
  if (::InitializeAcl(acl.get(), size, ACL_REVISION) == FALSE) {
    return SHARED_ACL();
  }
  BOOST_FOREACH(const SHARED_SID &sid, list) {
    if (::AddMandatoryAce(acl.get(), ACL_REVISION, NO_PROPAGATE_INHERIT_ACE, SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP, sid.get()) == FALSE) {
      return SHARED_ACL();
    }
  }
  return acl;
}

SHARED_SID GetWellKnownSid(const WELL_KNOWN_SID_TYPE type) {
  SHARED_SID sid(new unsigned char[SECURITY_MAX_SID_SIZE]);
  DWORD sidSize = SECURITY_MAX_SID_SIZE;
  if (::CreateWellKnownSid(type, NULL, sid.get(), &sidSize) == FALSE) {
    return SHARED_SID();
  }
  return sid;
}

bool CreateSecurityDescriptor(boost::shared_ptr<SECURITY_DESCRIPTOR> &desc, SHARED_ACL &dacl, SHARED_ACL &sacl, const std::vector<SHARED_SID> &daclSidList, const std::vector<SHARED_SID> &saclSidList, const SHARED_SID owner) {
  dacl = CreatePACLDacl(daclSidList);
  if (!dacl) {
    return false;
  }
  sacl = CreatePACLSacl(saclSidList);
  if (!sacl) {
    return false;
  }
  desc.reset(new SECURITY_DESCRIPTOR());
  if (::InitializeSecurityDescriptor(desc.get(), SECURITY_DESCRIPTOR_REVISION) == FALSE) {
    return false;
  }
  if (::SetSecurityDescriptorDacl(desc.get(), TRUE, dacl.get(), FALSE) == FALSE) {
    return false;
  }
  if (::SetSecurityDescriptorSacl(desc.get(), TRUE, sacl.get(), FALSE) == FALSE) {
    return false;
  }
  return true;
}

SHARED_SID GetUserSid(const wchar_t * const name) {
  DWORD bufSize = 0;
  wchar_t domain[256];
  DWORD domainSize = _countof(domain);
  SID_NAME_USE type;
  ::LookupAccountNameW(NULL, name, NULL, &bufSize, domain, &domainSize, &type);
  SHARED_SID sid(new unsigned char[bufSize]);
  ::LookupAccountNameW(NULL, name, sid.get(), &bufSize, domain, &domainSize, &type);
  return sid;
}

SHARED_SID GetCurrentUserSid() {
  wchar_t name[256];
  DWORD size = _countof(name);
  if (::GetUserNameW(name, &size) == FALSE) {
    return SHARED_SID();
  }
  return GetUserSid(name);
}

typedef boost::shared_ptr<boost::remove_pointer<HANDLE>::type> SHARED_HANDLE;
void MyCloseHandle(const HANDLE handle) {
  if (handle != NULL) {
    ::CloseHandle(handle);
  }
}

void MyDeleteProcThreadAttributeList(const LPPROC_THREAD_ATTRIBUTE_LIST attrList) {
  if (attrList != NULL) {
    ::DeleteProcThreadAttributeList(attrList);
  }
}
class DeleteAppContainer {
public:
  DeleteAppContainer(const wchar_t * const name) : name(name) { }
  ~DeleteAppContainer() {
    ::DeleteAppContainerProfile(name);
  }
private:
  const wchar_t * const name;
};

bool RunImpl(SHARED_HANDLE &processHandle, const SHARED_SID sid, const boost::filesystem::path &path) {
  const unsigned int attrCount = 3;
  SIZE_T size;
  ::InitializeProcThreadAttributeList(NULL, attrCount, 0, &size);
  typedef boost::shared_ptr<boost::remove_pointer<LPPROC_THREAD_ATTRIBUTE_LIST>::type> SHARED_ATTR_LIST;
  const SHARED_ATTR_LIST attrList(reinterpret_cast<LPPROC_THREAD_ATTRIBUTE_LIST>(new unsigned char[size]), &MyDeleteProcThreadAttributeList);
  if (::InitializeProcThreadAttributeList(attrList.get(), attrCount, 0, &size) == FALSE) {
    return false;
  }
  SECURITY_CAPABILITIES sc;
  sc.AppContainerSid = sid.get();
  sc.Capabilities = NULL;
  sc.CapabilityCount = 0;
  sc.Reserved = 0;
  if (::UpdateProcThreadAttribute(attrList.get(), 0, PROC_THREAD_ATTRIBUTE_SECURITY_CAPABILITIES, &sc, sizeof(sc), NULL, NULL) == FALSE) {
    return false;
  }
  STARTUPINFOEXW startupInfoEx = { 0 };
  startupInfoEx.StartupInfo.cb = sizeof(STARTUPINFOEXW); // StartupInfoのサイズではなくstartupInfoExのサイズである点に注意
  startupInfoEx.lpAttributeList = attrList.get();
  PROCESS_INFORMATION pi = { 0 };
  if (::CreateProcessW(path.wstring().c_str(), NULL, NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT, NULL, NULL, reinterpret_cast<LPSTARTUPINFO>(&startupInfoEx), &pi) == FALSE) {
    return false;
  }
  processHandle.reset(pi.hProcess, &MyCloseHandle);
  ::CloseHandle(pi.hThread);
  return true;
}

bool Run(SHARED_HANDLE &processHandle, const wchar_t * const appContainerName, const boost::filesystem::path &path) {
  PSID sidImpl;
  if (FAILED(::CreateAppContainerProfile(appContainerName, appContainerName, appContainerName, NULL, 0, &sidImpl))) {
    return false;
  }
  DeleteAppContainer deleteAppContainer(appContainerName);
  const SHARED_SID sid = ToSharedSID(sidImpl);
  if (!RunImpl(processHandle, sid, path)) {
    return false;
  }
  return true;
}

SHARED_SID GetAppContainerSid(const wchar_t * const name) {
  PSID sidImpl;
  if (FAILED(::DeriveAppContainerSidFromAppContainerName(name, &sidImpl))) {
    return SHARED_SID();
  }
  return ToSharedSID(sidImpl);
}

bool RunExist(SHARED_HANDLE &processHandle, const wchar_t * const appContainerName, const boost::filesystem::path &path) {
  const SHARED_SID sid = GetAppContainerSid(appContainerName);
  if (!sid) {
    return false;
  }
  if (!RunImpl(processHandle, sid, path)) {
    return false;
  }
  return true;
}

bool GetSharedMemoryPtr(void *&ptr, const HANDLE handle) {
  ptr = ::MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
  if (ptr == NULL) {
    return false;
  }
  return true;
}

bool CreateSharedMemory(HANDLE &handle, const wchar_t * const sharedMemoryName, const unsigned int sharedMemorySize, const boost::shared_ptr<SECURITY_DESCRIPTOR> desc) {
  SECURITY_ATTRIBUTES attr;
  attr.nLength = sizeof(SECURITY_ATTRIBUTES);
  attr.bInheritHandle = FALSE;
  attr.lpSecurityDescriptor = desc.get();
  handle = ::CreateFileMappingW(INVALID_HANDLE_VALUE, &attr, PAGE_READWRITE, 0, sharedMemorySize, sharedMemoryName);
  if (handle == NULL) {
    return false;
  }
  return true;
}

bool AuthzAnyPackage(const char * const path) {
  return true;
}

void MyDeleteBoundaryDescriptor(const HANDLE handle) {
  if (handle != NULL) {
    ::DeleteBoundaryDescriptor(handle);
  }
}

void MyClosePrivateNamespace(const HANDLE handle) {
  if (handle != NULL) {
    ::ClosePrivateNamespace(handle, PRIVATE_NAMESPACE_FLAG_DESTROY);
  }
}

bool CreatePrivateNamespace(SHARED_HANDLE &privateNamespace, const boost::shared_ptr<SECURITY_DESCRIPTOR> desc, const wchar_t * const boundaryName, const wchar_t * const name) {
  SECURITY_ATTRIBUTES attr;
  attr.nLength = sizeof(SECURITY_ATTRIBUTES);
  attr.bInheritHandle = FALSE;
  attr.lpSecurityDescriptor = desc.get();
  std::vector<SHARED_SID> sidList;
  sidList.push_back(GetWellKnownSid(WinBuiltinAnyPackageSid));
  HANDLE boundaryImpl = ::CreateBoundaryDescriptorW(boundaryName, 0);
  if (boundaryImpl == NULL) {
    return false;
  }
  BOOST_FOREACH(const SHARED_SID sid, sidList) {
    if (::AddSIDToBoundaryDescriptor(&boundaryImpl, sid.get()) == FALSE) {
      ::DeleteBoundaryDescriptor(boundaryImpl);
      return false;
    }
  }
  const SHARED_HANDLE boundary(boundaryImpl, &MyDeleteBoundaryDescriptor);
  privateNamespace.reset(::CreatePrivateNamespaceW(&attr, boundary.get(), name), &MyClosePrivateNamespace);
  if (!privateNamespace) {
    return false;
  }
  return true;
}

int main(const unsigned int argc, const char * const * const argv) {
  std::locale::global(std::locale("japanese"));
  if (argc != 2) {
    std::wcout << L"usage: TestSharedMemory.exe exe_path" << std::endl;
    std::wcin.ignore();
    return 1;
  }
  const boost::filesystem::path path(argv[1]);
  if (!boost::filesystem::is_regular_file(path)) {
    std::wcout << L"Error: ファイルが見つかりませんでした" << std::endl;
    std::wcin.ignore();
    return 1;
  }
  const wchar_t * const appContainerName = L"AppConteinerTest";
  const SHARED_SID owner = GetCurrentUserSid();
  boost::shared_ptr<SECURITY_DESCRIPTOR> desc;
  SHARED_ACL dacl;
  SHARED_ACL sacl;
  std::vector<SHARED_SID> daclSidList;
  daclSidList.push_back(GetAppContainerSid(appContainerName));
  daclSidList.push_back(GetWellKnownSid(WinBuiltinAnyPackageSid));
  daclSidList.push_back(GetWellKnownSid(WinLocalSystemSid));
  daclSidList.push_back(owner);
  daclSidList.push_back(GetWellKnownSid(WinBuiltinAdministratorsSid));
  std::vector<SHARED_SID> saclSidList;
  saclSidList.push_back(GetWellKnownSid(WinLowLabelSid));
  if (!CreateSecurityDescriptor(desc, dacl, sacl, daclSidList, saclSidList, owner)) {
    std::wcout << L"Error: Daclの構築に失敗しました" << std::endl;
    std::wcout << ::GetLastError() << std::endl;
    std::wcin.ignore();
    return 1;
  }
  SHARED_HANDLE privateNamespace;
  if (!CreatePrivateNamespace(privateNamespace, desc, L"boundaryName", L"privateNamespaceName")) {
    std::wcout << L"Error: PrivateNamespaceの生成に失敗しました" << std::endl;
    std::wcout << ::GetLastError() << std::endl;
    std::wcin.ignore();
    return 1;
  }
  const wchar_t * const sharedMemoryName = L"privateNamespaceName\\AppConteinerTestMemory";
  HANDLE handle;
  if (!CreateSharedMemory(handle, sharedMemoryName, sizeof(SharedStruct), desc)) {
    std::wcout << L"Error: 共有メモリーの生成に失敗しました" << std::endl;
    std::wcout << ::GetLastError() << std::endl;
    std::wcin.ignore();
    return 1;
  }
  SHARED_HANDLE processHandle;
  if (!Run(processHandle, appContainerName, path)) {
    if (!RunExist(processHandle, appContainerName, path)) {
      std::wcout << L"Error: アプリの起動に失敗しました" << std::endl;
      std::wcin.ignore();
      return 1;
    }
  }
  void *ptr;
  if (!GetSharedMemoryPtr(ptr, handle)) {
    std::wcout << L"Error: 共有メモリーの取得に失敗しました" << std::endl;
    std::wcin.ignore();
    return 1;
  }
  SharedStruct &sharedStruct = *reinterpret_cast<SharedStruct *>(ptr);
  while (::WaitForSingleObject(processHandle.get(), 100) == WAIT_TIMEOUT) {
    if (sharedStruct.changeFlag) {
      sharedStruct.changeFlag = false;
      std::wcout << sharedStruct.value << std::endl;
    }
  }
  return 0;
}