Search code examples
clibssh

stderr with libssh in pty mode


I'm using libssh to execute commands on a remote server. Here is my code (return codes are not checked here for simplification, but all of them are OK):

#include <stdio.h>
#include <stdlib.h>
#include <libssh/libssh.h>

int main() {

    /* opening session and channel */
    ssh_session session = ssh_new();
    ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
    ssh_options_set(session, SSH_OPTIONS_PORT_STR, "22");
    ssh_options_set(session, SSH_OPTIONS_USER, "julien");
    ssh_connect(session);
    ssh_userauth_autopubkey(session, NULL);
    ssh_channel channel = ssh_channel_new(session);
    ssh_channel_open_session(channel);

    /* command execution */
    ssh_channel_request_exec(channel, "echo 'foo' && whoam");

    char *buffer_stdin = calloc(1024, sizeof(char));
    ssh_channel_read(channel, buffer_stdin, 1024, 0);
    printf("stdout: %s\n", buffer_stdin);
    free(buffer_stdin);

    char *buffer_stderr = calloc(1024, sizeof(char));
    ssh_channel_read(channel, buffer_stderr, 1024, 1);
    printf("stderr: %s", buffer_stderr);
    free(buffer_stderr);

    ssh_channel_free(channel);
    ssh_free(session);
    return EXIT_SUCCESS;
}

The output is as axpected:

stdout: foo
stderr: command not found: whoam

Now if I add a call to ssh_channel_request_pty just after ssh_channel_open_session:

    ...
    ssh_channel channel = ssh_channel_new(session);
    ssh_channel_open_session(channel);
    ssh_channel_request_pty(channel);
    ssh_channel_request_exec(channel, "echo 'foo' && whoam");
    ...

There is no stderr output any more:

stdout: foo
stderr:

And if I change the command by:

ssh_channel_request_exec(channel, "whoam");

Now the error output is read on stdout!

stdout: command not found: whoam
stderr:

I am missing something with ssh_channel_request_pty?

For information, I'm using it because on some servers I get the following error when running a command with sudo:

sudo: sorry, you must have a tty to run sudo


Solution

  • Conceptually, a pty represents a terminal (or, at an even lower level, a serial port) -- there's only one channel in each direction. The standard output and standard error of a process running in a pty both go to the same place by default.

    (Consider what happens when you run a command in a terminal, for instance -- if you haven't redirected anything, both stdout and stderr will appear on screen, and there's no way to tell them apart.)

    Generally speaking, if you need to automate running commands remotely as root, you should either SSH in as root, or grant the user sudo access with the NOPASSWD option. Don't automate entering the password.