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