Upclapi/ssh.go

120 lines
2.9 KiB
Go

package main
import (
"bufio"
"fmt"
"io"
"io/ioutil"
"log"
"os"
"strings"
"time"
"golang.org/x/crypto/ssh"
// "github.com/mitchellh/go-homedir"
// "github.com/davecgh/go-spew/spew"
)
func publicKeyAuthGet(kPath string) ssh.AuthMethod {
// keyPath, err := homedir.Expand(kPath)
// if err != nil {
// log.Fatal("find key's home dir failed", err)
// }
// key, err := ioutil.ReadFile(keyPath )
key, err := ioutil.ReadFile(kPath )
if err != nil {
log.Fatal("ssh key file read failed: " , err)
return nil
}
// Create the Signer for this private key.
signer, err := ssh.ParsePrivateKey(key)
if err != nil {
log.Fatal("ssh key signer failed: ", err)
return nil
}
return ssh.PublicKeys(signer)
}
func runSSH(runFlags RunFlags, cfg SSHAccess, cmds ...string ) ([]byte, error) {
// fmt.Fprintf(os.Stderr, "SSH: %#v\n", cfg)
fmt.Fprintf(os.Stderr, "%s - running : %s\n\n", cfg.Host, cmds)
// Create SSHP login configuration
config := &ssh.ClientConfig{
Timeout: time.Second, //ssh connection time out time is one second, if SSH validation error returns in one second
User: cfg.User,
HostKeyCallback: ssh.InsecureIgnoreHostKey(), // This is OK, but not safe enough.
// HostKeyCallback: hostKeyCallBackFunc(h.Host),
}
if cfg.UType == "password" {
config.Auth = []ssh.AuthMethod{ssh.Password(cfg.Password)}
} else {
sshkey := cfg.KeyPath
if len(sshkey) == 0 {
sid := runFlags.sid
if len(sid) == 0 {
sid="id_rsa"
}
sshkey = fmt.Sprintf("%s/.ssh/%s", os.Getenv("HOME"),sid)
}
config.Auth = []ssh.AuthMethod{publicKeyAuthGet(sshkey)}
}
addr := fmt.Sprintf("%s:%d", cfg.Host, cfg.Port)
conn, err := ssh.Dial("tcp", addr,config)
if err != nil {
log.Fatal("Failed to dial SSH client", err)
return []byte{}, err
}
session, err := conn.NewSession()
if err != nil {
log.Fatal(err)
}
defer session.Close()
modes := ssh.TerminalModes{
ssh.ECHO: 0, // disable echoing
ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud
ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud
}
err = session.RequestPty("xterm", 80, 40, modes)
if err != nil {
return []byte{}, err
}
in, err := session.StdinPipe()
if err != nil {
log.Fatal(err)
}
out, err := session.StdoutPipe()
if err != nil {
log.Fatal(err)
}
var output []byte
go func(in io.WriteCloser, out io.Reader, output *[]byte) {
var (
line string
r = bufio.NewReader(out)
)
for {
b, err := r.ReadByte()
if err != nil {
break
}
*output = append(*output, b)
if b == byte('\n') {
line = ""
continue
}
line += string(b)
if strings.HasPrefix(line, "[sudo] password for ") && strings.HasSuffix(line, ": ") {
_, err = in.Write([]byte(cfg.Password+ "\n"))
if err != nil {
break
}
}
}
}(in, out, &output)
cmd := strings.Join(cmds, "; ")
_, err = session.Output(cmd)
if err != nil {
return []byte{}, err
}
return output, nil
}