进程间通信 - C# 和C++.对路径的访问被拒绝
Inter-process communication - C# and C++. Access to the path is denied
我有一个使用 Pipe 连接到C++服务器应用程序的 C# 客户端应用程序。当我尝试连接时,出现错误:System.UnauthorizedAccessException:对路径的访问被拒绝。
查找后,我发现我可以通过创建一个 PipeSecurity 对象并添加一个 PipeAccessRule 来修复它。但这仅在服务器也是 C# 应用程序时才有效。
如果我将服务器作为应用程序,知道如何解决此访问问题C++任何想法?
我已经搜索过,但找不到解决方案。
C#:
int timeOut = 500;
NamedPipeClientStream pipeStream = new NamedPipeClientStream(".", pipeName, PipeDirection.Out, PipeOptions.Asynchronous);
pipeStream.Connect(timeOut);
byte[] buffer = Encoding.UTF8.GetBytes(sendStr);
pipeStream.BeginWrite(buffer, 0, buffer.Length, new AsyncCallback(AsyncSend), pipeStream);
C++:
_hPipe = ::CreateNamedPipe(configurePipeName(getPipeName()).c_str(),
PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT | PIPE_REJECT_REMOTE_CLIENTS,
1,
bufferSize,
bufferSize,
NMPWAIT_USE_DEFAULT_WAIT,
NULL);
if (_hPipe == INVALID_HANDLE_VALUE)
{
logStream << "CreateNamedPipe failed for " << sys::OperatingSystem::getLastErrorMessage() << blog::over;
return;
}
HANDLE ioEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL);
overlapped.hEvent = ioEvent;
assert(overlapped.hEvent);
if (ioEvent == INVALID_HANDLE_VALUE)
{
logStream << "CreateEvent failed for " << sys::OperatingSystem::getLastErrorMessage() << blog::over;
return;
}
while (!terminating())
{
BOOL connected = false;
DWORD waitMessage;
DWORD timeOut = 700;
if (!::ConnectNamedPipe(_hPipe, &overlapped))
{
switch (::GetLastError())
{
case ERROR_PIPE_CONNECTED:
connected = true;
break;
case ERROR_IO_PENDING:
waitMessage = ::WaitForSingleObject(overlapped.hEvent, timeOut);
if (waitMessage == WAIT_OBJECT_0)
{
DWORD dwIgnore;
BOOL conn = (::GetOverlappedResult(_hPipe, &overlapped, &dwIgnore, TRUE));
if (conn)
connected = true;
else
logStream << "ConnectedNamedPipe reported an error: " << sys::OperatingSystem::getLastErrorMessage() << blog::over;
}
else
::CancelIo(_hPipe);
break;
default:
logStream << "ConnectedNamedPipe reported an error: " << sys::OperatingSystem::getLastErrorMessage() << blog::over;
}
}
if(connected)
{
if (::ReadFile(_hPipe, buffer, sizeof(buffer) - 1, &size, NULL))
{
buffer[size] = ' ';
std::string receivedMessage(buffer);
// if message is received from client, setdirty to call detectDisplay.
if (clientUniqueMessage.compare(receivedMessage) == 0)
setDirty();
else
logStream << "Incoming message from client does not match with the expected message." << blog::over;
}
else
logStream << "ReadFile failed. " << sys::OperatingSystem::getLastErrorMessage() << blog::over;
}
::DisconnectNamedPipe(_hPipe);
}
}
[CreateNamedPipe 函数] 的最后一个参数指定:
lpSecurityAttributes [in, optional]
指向的指针 指定安全描述符的SECURITY_ATTRIBUTES结构 并确定子进程是否可以 继承返回的句柄。如果 lpSecurityAttributes 为 NULL,则 命名管道获取默认安全描述符,句柄不能 继承。命名的默认安全描述符中的 ACL 管道向本地系统帐户授予完全控制权,管理员, 和创建者所有者。它们还向 每个人组和匿名帐户。
C++命名管道服务器应用程序具有管理员权限,因为它在本地系统帐户下作为 Windows 服务运行。以标准用户身份运行的 C# 客户端应用程序没有管理员权限。默认情况下(lpSecurityAttributes
NULL
),C# 客户端应用程序对作为服务运行的C++服务器创建的命名管道只有读取访问权限。
作为快速测试,如果以管理员身份运行 C# 客户端应用程序,它应该能够成功与C++服务器应用程序通信。
若要解决此问题,C++服务器应用程序需要为命名管道对象创建安全描述符,并为 TEveryone 授予对其的写入访问权限。 请参阅 MSDN 示例以创建安全描述符。
我之前为作为服务运行的C++服务器应用程序编写了class NamedPipeServerStream
。下面是与创建命名管道相关的代码部分,供您参考。
NamedPipeServerStream::NamedPipeServerStream(const std::string & pipeName, const unsigned pipeBufferSize /*= PIPE_BUFFER_SIZE*/)
: m_hPipe(INVALID_HANDLE_VALUE)
, m_pipeName(PIPE_NAME_ROOT + pipeName)
, m_bConnected(false)
{
PSID pEveryoneSID = NULL;
PSID pAdminSID = NULL;
PACL pACL = NULL;
EXPLICIT_ACCESS ea[2];
SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY;
SID_IDENTIFIER_AUTHORITY SIDAuthNT = SECURITY_NT_AUTHORITY;
SECURITY_ATTRIBUTES sa;
SCOPE_GUARD{
if (pEveryoneSID) { FreeSid(pEveryoneSID); }
if (pAdminSID) { FreeSid(pAdminSID); }
if (pACL) { LocalFree(pACL); }
};
// Create a well-known SID for the Everyone group.
if (!AllocateAndInitializeSid(&SIDAuthWorld, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &pEveryoneSID))
{
throw std::runtime_error("AllocateAndInitializeSid failed, GLE=" + std::to_string(GetLastError()));
}
// Initialize an EXPLICIT_ACCESS structure for an ACE.
SecureZeroMemory(&ea, 2 * sizeof(EXPLICIT_ACCESS));
// The ACE will allow Everyone full access to the key.
ea[0].grfAccessPermissions = FILE_ALL_ACCESS | GENERIC_WRITE | GENERIC_READ;
ea[0].grfAccessMode = SET_ACCESS;
ea[0].grfInheritance = NO_INHERITANCE;
ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
ea[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
ea[0].Trustee.ptstrName = (LPTSTR)pEveryoneSID;
// Create a SID for the BUILTINAdministrators group.
if (!AllocateAndInitializeSid(&SIDAuthNT, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &pAdminSID))
{
throw std::runtime_error("AllocateAndInitializeSid failed, GLE=" + std::to_string(GetLastError()));
}
// The ACE will allow the Administrators group full access to the key.
ea[1].grfAccessPermissions = FILE_ALL_ACCESS | GENERIC_WRITE | GENERIC_READ;
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 = (LPTSTR)pAdminSID;
// Create a new ACL that contains the new ACEs.
DWORD dwRes = SetEntriesInAclW(2, ea, NULL, &pACL);
if (ERROR_SUCCESS != dwRes)
{
throw std::runtime_error("SetEntriesInAcl failed, GLE=" + std::to_string(GetLastError()));
}
// Initialize a security descriptor.
auto secDesc = std::vector<unsigned char>(SECURITY_DESCRIPTOR_MIN_LENGTH);
PSECURITY_DESCRIPTOR pSD = (PSECURITY_DESCRIPTOR)(&secDesc[0]);
if (nullptr == pSD)
{
throw std::runtime_error("LocalAlloc failed, GLE=" + std::to_string(GetLastError()));
}
if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION))
{
throw std::runtime_error("InitializeSecurityDescriptor failed, GLE=" + std::to_string(GetLastError()));
}
// Add the ACL to the security descriptor.
if (!SetSecurityDescriptorDacl(pSD, TRUE, pACL, FALSE)) // not a default DACL
{
throw std::runtime_error("SetSecurityDescriptorDacl failed, GLE=" + std::to_string(GetLastError()));
}
// Initialize a security attributes structure.
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = pSD;
sa.bInheritHandle = FALSE;
// Finally to create the pipe.
m_hPipe = CreateNamedPipeA(
m_pipeName.c_str(), // pipe name
PIPE_ACCESS_DUPLEX, // read/write access
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | // Byte Stream type pipe
PIPE_WAIT, // blocking mode
PIPE_UNLIMITED_INSTANCES, // max. instances
pipeBufferSize, // output buffer size
pipeBufferSize, // input buffer size
0, // client time-out
&sa); // default security attribute
if (!IsPipeCreated())
{
throw std::runtime_error("CreateNamedPipe failed, GLE=" + std::to_string(GetLastError()));
}
}
bool NamedPipeServerStream::IsPipeCreated() const
{
return (INVALID_HANDLE_VALUE != m_hPipe);
}
- 访问被拒绝后,c++中的故障保护代码
- 删除目录函数访问被拒绝
- 为什么 Windows 拒绝访问某些进程的名称?
- 我在执行任何程序时被拒绝在 devcpp 中访问
- Windows C++:文件夹移动访问被拒绝错误
- AWS AMI 中的 Windows DPAPI 失败,访问被拒绝
- C++ 17 文件系统copy_file访问被拒绝
- mysql c ++连接器异常:用户"root"@'localhost'的访问被拒绝(使用密码:NO)&&MySQL服务器已消失
- 如何修复 CopyFile() 错误 5 - 访问被拒绝错误
- CreateFile 在尝试打开目录进行读取时始终返回错误 5(访问被拒绝)
- 通过进程模块C 枚举时,访问被拒绝
- 任务计划程序:设置运行级别时拒绝访问
- 设置Windows计时器,访问被拒绝
- 访问在托管代码创建的事件上对WaitforsingLeoBject拒绝
- 进程间通信 - C# 和C++.对路径的访问被拒绝
- 清除同一属性后,设置属性时拒绝访问
- 无法生成或清理 Visual Studio 2015 解决方案(访问被拒绝)
- 使用AWS CPP SDK拒绝Amazon S3的访问
- C:文件扫描与c++,访问拒绝特定的文件
- RegOpenKeyEx访问拒绝读取HKEY_LOCAL_MACHINE