Home > Back-end >  Named pipe client failed to send data to server: "Stream was not writable"
Named pipe client failed to send data to server: "Stream was not writable"

Time:12-30

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

  • Related