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 }