1

This question is about golang.org/x/crypto/ssh package and maybe pseudo-terminal behaviour.

The code

Here is the demo code. You can run it on your local machine just change credentials to access SSH.

package main

import (
    "bufio"
    "fmt"
    "golang.org/x/crypto/ssh"
    "io"
)

func main() {
    var pipe io.Reader
    whichPipe := "error" // error or out

    address := "192.168.1.62:22"
    username := "username"
    password := "password"

    sshConfig := &ssh.ClientConfig{
        User: username,
        Auth: []ssh.AuthMethod{ssh.Password(password)},
    }

    connection, err := ssh.Dial("tcp", address, sshConfig)
    if err != nil {
        panic(err)
    }

    session, err := connection.NewSession()
    if err != nil {
        panic(err)
    }

    modes := ssh.TerminalModes{
        ssh.ECHO: 0,
        ssh.ECHOCTL: 0,
        ssh.TTY_OP_ISPEED: 14400,
        ssh.TTY_OP_OSPEED: 14400,
    }

    if err := session.RequestPty("xterm", 80, 0, modes); err != nil {
        session.Close()
        panic(err)
    }

    switch whichPipe {
    case "error":
        pipe, _ = session.StderrPipe()
    case "out":
        pipe, _ = session.StdoutPipe()
    }

    err = session.Run("whoami23")

    scanner := bufio.NewScanner(pipe)
    for scanner.Scan() {
        fmt.Println(scanner.Text())
    }
}

Actual result

Empty line

Expected result

bash: whoami23: command not found

Current "solution"

To get expected result you have two options:

  1. Change whichPipe value to out. Yes, all errors going to stdout in case if you use tty.
  2. Remove session.RequestPty. But in my case, I need to run sudo commands which require tty (servers are out of my control so I can't disable this requirement).

I use third way. I check err from err = session.Run("whoami23") and if it's not nil I mark content of session.StdoutPipe() as STDERR one.

But this method has limits. For example, if I run something like sudo sh -c 'uname -r; whoami23;' the whole result will be marked as error while uname -r returns output to STDOUT.

The question

While the behaviour looks logical to me (all that SSH client sees from pty is output without differentiations) I'm still not sure if I may miss something and there is a trick that allows to split these outputs.

CrazyCrow
  • 4,125
  • 1
  • 28
  • 39

0 Answers0