ACE3/extensions/common/simplepipe_win32.cpp

184 lines
5.2 KiB
C++
Raw Normal View History

2016-05-30 16:37:03 +00:00
#ifdef _WIN32
#include "simplepipe_win32.hpp"
#include <Sddl.h>
#include <AccCtrl.h>
#include <Aclapi.h>
namespace ace {
namespace {
const wchar_t kPipePrefix[] = L"\\\\.\\pipe\\";
const int kPipeBufferSz = 4 * 1024;
} // namespace
bool checkIntegritySupport() {
OSVERSIONINFO osvi;
ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&osvi);
return osvi.dwMajorVersion > 5;
}
LONG g_pipe_seq = 0;
HANDLE pipe_pair::open_pipe_server(const wchar_t* name, bool low_integrity, bool blocking) {
SECURITY_ATTRIBUTES sa = {0};
SECURITY_ATTRIBUTES *psa = 0;
DWORD wait;
static const bool is_integrity_supported = checkIntegritySupport();
if (is_integrity_supported && low_integrity) {
psa = &sa;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.bInheritHandle = TRUE;
if (!ConvertStringSecurityDescriptorToSecurityDescriptor(
TEXT("S:(ML;;NWNR;;;LW)"), SDDL_REVISION_1, &sa.lpSecurityDescriptor, NULL))
return INVALID_HANDLE_VALUE;
}
if (blocking) {
wait = PIPE_WAIT;
} else {
wait = PIPE_NOWAIT;
}
std::wstring pipename(kPipePrefix);
pipename.append(name);
return ::CreateNamedPipeW(pipename.c_str(), PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | wait,
1, kPipeBufferSz, kPipeBufferSz, 200, psa);
}
HANDLE pipe_pair::open_pipe_client(const wchar_t* name, bool inherit, bool impersonate) {
std::wstring pipename(kPipePrefix);
pipename.append(name);
SECURITY_ATTRIBUTES sa = {sizeof(sa), NULL, inherit ? TRUE : FALSE};
for (;;) {
DWORD attributes = impersonate ? 0 : SECURITY_SQOS_PRESENT | SECURITY_IDENTIFICATION;
HANDLE pipe = ::CreateFileW(pipename.c_str(), GENERIC_READ | GENERIC_WRITE, 0, &sa,
OPEN_EXISTING, attributes, NULL);
if (INVALID_HANDLE_VALUE == pipe) {
if (ERROR_PIPE_BUSY != ::GetLastError()) {
return pipe;
}
// wait and retry.
if (! ::WaitNamedPipeW(pipename.c_str(), NMPWAIT_USE_DEFAULT_WAIT))
continue;
} else {
// success.
return pipe;
}
}
}
pipe_pair::pipe_pair(bool inherit_fd2, bool blocking) : srv_(NULL), cln_(NULL) {
// Come up with a reasonable unique name.
const wchar_t kPipePattern[] = L"ko.%x.%x.%x";
wchar_t name[8*3 + sizeof(kPipePattern)];
::wsprintfW(name, kPipePattern, ::GetCurrentProcessId(), ::GetTickCount(),
::InterlockedIncrement(&g_pipe_seq));
HANDLE server = open_pipe_server(name, blocking);
if (INVALID_HANDLE_VALUE == server) {
return;
}
// Don't allow client impersonation.
HANDLE client = open_pipe_client(name, inherit_fd2, false);
if (INVALID_HANDLE_VALUE == client) {
::CloseHandle(server);
return;
}
if (!::ConnectNamedPipe(server, NULL)) {
if (ERROR_PIPE_CONNECTED != ::GetLastError()) {
::CloseHandle(server);
::CloseHandle(client);
return;
}
}
srv_ = server;
cln_ = client;
}
pipe_win::pipe_win() : pipe_(INVALID_HANDLE_VALUE) {
}
pipe_win::~pipe_win() {
if (pipe_ != INVALID_HANDLE_VALUE) {
::DisconnectNamedPipe(pipe_); // $$$ disconect is valid on the server side.
::CloseHandle(pipe_);
}
}
bool pipe_win::open_client(HANDLE pipe) {
pipe_ = pipe;
return true;
}
bool pipe_win::open_server(HANDLE pipe, bool connect) {
pipe_ = pipe;
if (connect) {
if (!::ConnectNamedPipe(pipe, NULL)) {
if (ERROR_PIPE_CONNECTED != ::GetLastError()) {
return false;
}
}
}
return true;
}
bool pipe_win::write(const void* buf, size_t sz) {
DWORD written = 0;
return (TRUE == ::WriteFile(pipe_, buf, sz, &written, NULL));
}
bool pipe_win::CheckStatus() {
char buf[5];
uint32_t size = sizeof(buf);
BOOL ret;
ret = ::ReadFile(pipe_, buf, sizeof(buf), reinterpret_cast<DWORD*>(&size), NULL);
if (!ret) {
if (GetLastError() == ERROR_NO_DATA) {
return true;
} else {
return false;
}
} else {
return true;
}
}
bool pipe_win::read(void* buf, size_t* sz) {
BOOL ret;
ret = ::ReadFile(pipe_, buf, *sz, reinterpret_cast<DWORD*>(sz), NULL);
if (!ret) {
if (GetLastError() == ERROR_BROKEN_PIPE) {
if (!DisconnectNamedPipe(pipe_)) {
printf("DisconnectNamedPipe() failed. hr=%08x", GetLastError());
}
if (!::ConnectNamedPipe(pipe_, NULL)) {
}
}
}
return ret;
}
char* PipeTransport::receive(size_t* size) {
if (buf_.size() < kBufferSz)
buf_.resize(kBufferSz);
*size = kBufferSz;
if (!read(&buf_[0], size))
return NULL;
return &buf_[0];
}
}
#endif