0

I tried using named pipes in C++ to transfer a message from one computer to another. But the client could not connect to the server, it returned error 1326 (invalid name or password), although the server name was specified correctly.

What does the password have to do with the channel? And if there are no errors in the code, then what else could be causing the connection error to the channel?

Also, on the Internet, I saw such a form recording the channel name \\servername\pipe\[path] pipename. servername is the name of the server, pipe determines that it is a channel, and pipename is the name of the channel, but what is [path]?

Server

#include <windows.h>
#include <iostream>
#include <cstring>

using namespace std;

int main()
{
    HANDLE hNamedPipe;
    DWORD dwBytesRead; 
    DWORD dwBytesWrite; 
    char pchMessage[80];
    int nMessageLength;

    PSECURITY_DESCRIPTOR psd;
    SECURITY_ATTRIBUTES sa;
    psd = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
    InitializeSecurityDescriptor(psd, SECURITY_DESCRIPTOR_REVISION);
    SetSecurityDescriptorDacl(psd, true, NULL, false);
    sa.nLength = sizeof(sa);
    sa.bInheritHandle = true;
    sa.lpSecurityDescriptor = psd;

    hNamedPipe= CreateNamedPipe("\\\\.\\pipe\\pipe", PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | WRITE_OWNER, PIPE_READMODE_MESSAGE | PIPE_TYPE_MESSAGE| PIPE_ACCEPT_REMOTE_CLIENTS, PIPE_UNLIMITED_INSTANCES, 2048, 2048, INFINITE, &sa);
    if (hNamedPipe == INVALID_HANDLE_VALUE)
    {
            cerr << "Create named pipe failed." << endl
            << "The last error code: " << GetLastError() << endl;
        cout << "Press any key to exit.";
        cin.get();

        return 0;
    }
    cout << "The server is waiting for connection with a client." << endl;
    if (!ConnectNamedPipe(
        hNamedPipe,
        NULL 
    ))
    {
        cerr << "Connect named pipe failed." << endl
            << "The last error code: " << GetLastError() << endl;
        CloseHandle(hNamedPipe);
        cout << "Press any key to exit.";
        cin.get();

        return 0;
    }
    if (!ReadFile(
        hNamedPipe,
        pchMessage,
        sizeof(pchMessage),
        &dwBytesRead, 
        NULL))
    {
        cerr << "Data reading from the named pipe failed." << endl
            << "The last error code: " << GetLastError() << endl;
        CloseHandle(hNamedPipe);
        cout << "Press any key to exit.";
        cin.get();

        return 0;
    }

    cout << "The server received the message from a client: "
        << endl << '\t' << pchMessage << endl;

    cout << "Input a string: ";
    cin.getline(pchMessage, 80);
    nMessageLength = strlen(pchMessage) + 1;

        if (!WriteFile(
            hNamedPipe,
            pchMessage,
            nMessageLength,
            &dwBytesWrite,
            NULL
        ))
        {
            cerr << "Write file failed." << endl
                << "The last error code: " << GetLastError() << endl;
            CloseHandle(hNamedPipe);
            cout << "Press any key to exit.";
            cin.get();

            return 0;
        }

    cout << "The server sent the message to a client: "
        << endl << '\t' << pchMessage << endl;

    CloseHandle(hNamedPipe);
    cout << "Press any key to exit.";
    cin.get();

    return 0;
}

Client

#include <windows.h>
#include <iostream>
#include <string>
using namespace std;

int main()
{
    string machineName;
    getline(cin, machineName, '\n');
    machineName= "\\\\"+machineName+"\\pipe\\pipe";
    cout << machineName << endl;
    char pipeName[80];
    strcpy_s(pipeName, machineName.c_str());
    HANDLE hNamedPipe;
    DWORD dwBytesWritten;
    DWORD dwBytesRead;
    char pchMessage[80];
    int nMessageLength;

    hNamedPipe = CreateFile(
        pipeName, // имя канала
        GENERIC_READ | GENERIC_WRITE, 
        FILE_SHARE_READ | FILE_SHARE_WRITE, 
        NULL, 
        OPEN_EXISTING, 
        FILE_ATTRIBUTE_NORMAL, 
        NULL);

    if (hNamedPipe == INVALID_HANDLE_VALUE)
    {
        cerr << "Connection with the named pipe failed." << endl
            << "The last error code: " << GetLastError() << endl;
        cout << "Press any key to exit.";
        cin.get();
        return 0;
    }
    cin.get();
    cout << "Input a string: ";
    cin.getline(pchMessage, 80);
    nMessageLength = strlen(pchMessage) + 1;
    if (!WriteFile(
        hNamedPipe, 
        pchMessage, 
        nMessageLength,
        &dwBytesWritten,
        NULL)) 
    {
            cerr << "Write file failed: " << endl
            << "The last error code: " << GetLastError() << endl;
        CloseHandle(hNamedPipe);
        cout << "Press any key to exit.";
        cin.get();
        return 0;
    }
        cout << "The client sent the message to a server: "
        << endl << '\t' << pchMessage << endl;
    if (!ReadFile(
        hNamedPipe, 
        pchMessage,
        sizeof(pchMessage), 
        &dwBytesRead,
        NULL))
    {
        cerr << "Read file failed: " << endl
            << "The last error code: " << GetLastError() << endl;
        CloseHandle(hNamedPipe);
        cout << "Press any key to exit.";
        cin.get();
        return 0;
    }
    cout << "The client received the message from a server: "
        << endl << '\t' << pchMessage << endl;
    CloseHandle(hNamedPipe);
    cout << "Press any key to exit.";
    cin.get();
    return 0;
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
hael
  • 1
  • 2
  • 2
    Unrelated: `PSECURITY_DESCRIPTOR psd; psd = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH); InitializeSecurityDescriptor(psd, ...` is better like this: `SECURITY_DESCRIPTOR sd; InitializeSecurityDescriptor(&sd, ...` - Don't use pointers and manual allocs unless you _really_ have to. – Ted Lyngmo Apr 30 '20 at 14:11
  • 2
    Named pipes are securable objects. The security of the client has to match the security of the server or else the connection will fail. – Remy Lebeau Apr 30 '20 at 17:03
  • 3
    Also, you are creating the server pipe with `FILE_FLAG_OVERLAPPED` but you are not using an `OVERLAPPED` struct with `ConnectNamedPipe()` (or `ReadFile()` or `WriteFile()`), which is a mistake: "*If hNamedPipe was opened with FILE_FLAG_OVERLAPPED, **the lpOverlapped parameter must not be NULL**. It must point to a valid OVERLAPPED structure. If hNamedPipe was opened with FILE_FLAG_OVERLAPPED and lpOverlapped is NULL, the function can incorrectly report that the connect operation is complete.*" – Remy Lebeau Apr 30 '20 at 17:04
  • 1
    "*What is `[path]`?*" - a typo. Named Pipe names don't have a `[path]` component, as backslashes are not allowed in the `pipename` component. Read the documentation: [Pipe Names](https://learn.microsoft.com/en-us/windows/win32/ipc/pipe-names). – Remy Lebeau Apr 30 '20 at 17:09
  • you need first call `NetUseAdd` for `\\servername\IPC$` – RbMm Apr 30 '20 at 17:32
  • Like this:```BYTE buf; string machineName, lyu; getline(cin, machineName, '\n'); lyu = "\\\\"+machineName+"\\pipe"; NetUseAdd(const_cast(lyu.c_str()), 1, &buf, NULL);``` – hael May 01 '20 at 15:38

1 Answers1

0

After my testing, there are two places in your code that need to be corrected.

The NetUseAdd function establishes a connection between the local computer and a remote server. You can specify a local drive letter or a printer device to connect. If you do not specify a local drive letter or printer device, the function authenticates the client with the server for future connections.

In addition, file and print sharing need be turned on.

Refer: SMB named pipe with no connection restrictions

After everything is configured, the code can work normally.

Strive Sun
  • 5,988
  • 1
  • 9
  • 26