I created a named pipe server like that \\.\pipe\mypipe
in C and I am trying to connect it using PowerShell.
I succeed to connect but I want to send it some data and this is where it throws an error in PowerShell:
PS > $pipe = New-Object System.IO.Pipes.NamedPipeClientStream '.','mypipe','In'
PS > $pipe.Connect()
PS > $sw = New-Object System.IO.StreamWriter $pipe
New-Object : Exception calling ".ctor" with "1" argument(s): "Stream was not writable."
At line:1 char:7
$sw = New-Object System.IO.StreamWriter $pipe
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CategoryInfo : InvalidOperation: (:) [New-Object], MethodInvocationException
FullyQualifiedErrorId : ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommand
What does it mean "Stream was not writable" ? I set the permissions on the server to be for Everyone so I don't think it should be a permissions issue.
My named pipe server:
DWORD dwRes, dwDisposition;
PSID pEveryoneSID = NULL, pAdminSID = NULL;
PACL pACL = NULL;
PSECURITY_DESCRIPTOR pSD = NULL;
EXPLICIT_ACCESS ea[2];
SID_IDENTIFIER_AUTHORITY SIDAuthWorld =
SECURITY_WORLD_SID_AUTHORITY;
SID_IDENTIFIER_AUTHORITY SIDAuthNT = SECURITY_NT_AUTHORITY;
SECURITY_ATTRIBUTES sa;
LONG lRes;
HKEY hkSub = NULL;
// Create a well-known SID for the Everyone group.
if (!AllocateAndInitializeSid(&SIDAuthWorld, 1,
SECURITY_WORLD_RID,
0, 0, 0, 0, 0, 0, 0,
&pEveryoneSID))
{
..
}
// Initialize an EXPLICIT_ACCESS structure for an ACE.
// The ACE will allow Everyone read access to the key.
ZeroMemory(&ea, 2 * sizeof(EXPLICIT_ACCESS));
//ea[0].grfAccessPermissions = KEY_READ;
ea[0].grfAccessPermissions = GENERIC_READ | FILE_WRITE_DATA;
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 new ACL that contains the new ACEs.
dwRes = SetEntriesInAcl(1, ea, NULL, &pACL);
if (ERROR_SUCCESS != dwRes)
{
...
}
// Initialize a security descriptor.
pSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR,
SECURITY_DESCRIPTOR_MIN_LENGTH);
if (NULL == pSD)
{
...
}
if (!InitializeSecurityDescriptor(pSD,
SECURITY_DESCRIPTOR_REVISION))
{
...
}
// Add the ACL to the security descriptor.
if (!SetSecurityDescriptorDacl(pSD,
TRUE, // bDaclPresent flag
pACL,
//NULL,
FALSE)) // not a default DACL
{
...
}
SECURITY_ATTRIBUTES SecurityAttrs = {
sizeof(SECURITY_ATTRIBUTES),
NULL, // assigned access token of calling process
FALSE
};
DWORD openMode = PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE | WRITE_OWNER;
DWORD pipeMode = PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT;
std::cout << "[ ] Creating pipe server\n";
for (;;) {
// create the named pipe
HANDLE pipe = NULL;
DWORD msgSize = 1024;
pipe = CreateNamedPipeA(
"\\\\.\\pipe\\mypipe",
openMode,
pipeMode,
2, // max instances
msgSize, // out buffer size
msgSize, // in buffer size
0, // timeout. 0 ~= 50ms
&SecurityAttrs);
if (pipe == INVALID_HANDLE_VALUE) {
DWORD err = GetLastError();
std::cout << "[!] Pipe creation failed! " << err << std::endl;
return err;
}
// wait for docker to connect to the client
std::cout << "[ ] Waiting for docker to connect\n";
bool connected = ConnectNamedPipe(pipe, NULL) ? true : (
GetLastError() == ERROR_PIPE_CONNECTED);
if (!connected)
continue;
std::cout << "[ ] Client connected\n";
// read byte from pipe
char buf[1024];
DWORD bytesread = 0;
bool status = ReadFile(
pipe,
&buf,
msgSize,
&bytesread,
NULL);
...
CodePudding user response:
You got the direction backwards - In
means "receive only" (or read-only).
For a bi-directional pipe (which is what PIPE_ACCESS_DUPLEX
specifies on the server side), use InOut
:
$pipe = [System.IO.Pipes.NamedPipeClientStream]::new('.', 'mypipe', 'InOut')
The resulting stream object should now be both readable and writable