func (d *ESX5Driver) connect() error { address := fmt.Sprintf("%s:%d", d.Host, d.Port) auth := []gossh.AuthMethod{ gossh.Password(d.Password), gossh.KeyboardInteractive( ssh.PasswordKeyboardInteractive(d.Password)), } if d.PrivateKey != "" { signer, err := commonssh.FileSigner(d.PrivateKey) if err != nil { return err } auth = append(auth, gossh.PublicKeys(signer)) } sshConfig := &ssh.Config{ Connection: ssh.ConnectFunc("tcp", address), SSHConfig: &gossh.ClientConfig{ User: d.Username, Auth: auth, }, } comm, err := ssh.New(address, sshConfig) if err != nil { return err } d.comm = comm return nil }
// SSHConfig returns a function that can be used for the SSH communicator // config for connecting to the instance created over SSH using the private key // or password. func SSHConfig(username, password string) func(multistep.StateBag) (*ssh.ClientConfig, error) { return func(state multistep.StateBag) (*ssh.ClientConfig, error) { privateKey, hasKey := state.GetOk("privateKey") if hasKey { signer, err := ssh.ParsePrivateKey([]byte(privateKey.(string))) if err != nil { return nil, fmt.Errorf("Error setting up SSH config: %s", err) } return &ssh.ClientConfig{ User: username, Auth: []ssh.AuthMethod{ ssh.PublicKeys(signer), }, }, nil } else { return &ssh.ClientConfig{ User: username, Auth: []ssh.AuthMethod{ ssh.Password(password), ssh.KeyboardInteractive( packerssh.PasswordKeyboardInteractive(password)), }}, nil } } }
func (d *ESX5Driver) connect() error { address := fmt.Sprintf("%s:%d", d.Host, d.Port) auth := []gossh.AuthMethod{ gossh.Password(d.Password), gossh.KeyboardInteractive( ssh.PasswordKeyboardInteractive(d.Password)), } // TODO(dougm) KeyPath support sshConfig := &ssh.Config{ Connection: ssh.ConnectFunc("tcp", address), SSHConfig: &gossh.ClientConfig{ User: d.Username, Auth: auth, }, } comm, err := ssh.New(address, sshConfig) if err != nil { return err } d.comm = comm return nil }
func sshOnConn(conn net.Conn, h conf.Host) (*ssh.Client, error) { var auths []ssh.AuthMethod if h.Pass != "" { auths = append(auths, ssh.Password(h.Pass)) auths = append(auths, ssh.KeyboardInteractive(kbdInteractive(h.Pass))) } if h.Key != "" { k := &keyring{} err := k.loadPEM([]byte(h.Key)) if err != nil { return nil, err } for _, k := range k.keys { s, _ := ssh.NewSignerFromKey(k) auths = append(auths, ssh.PublicKeys(s)) } } config := &ssh.ClientConfig{ User: h.User, Auth: auths, } debugln("handshake & authenticate") cc, nc, reqs, err := ssh.NewClientConn(conn, conn.RemoteAddr().String(), config) if err != nil { return nil, err } client := ssh.NewClient(cc, nc, reqs) return client, nil }
func buildSSHClientConfig(opts sshClientConfigOpts) (*ssh.ClientConfig, error) { conf := &ssh.ClientConfig{ User: opts.user, } if opts.privateKey != "" { pubKeyAuth, err := readPrivateKey(opts.privateKey) if err != nil { return nil, err } conf.Auth = append(conf.Auth, pubKeyAuth) } if opts.password != "" { conf.Auth = append(conf.Auth, ssh.Password(opts.password)) conf.Auth = append(conf.Auth, ssh.KeyboardInteractive( PasswordKeyboardInteractive(opts.password))) } if opts.sshAgent != nil { conf.Auth = append(conf.Auth, opts.sshAgent.Auth()) } return conf, nil }
func sshConfig(state multistep.StateBag) (*gossh.ClientConfig, error) { config := state.Get("config").(*Config) var privateKey string var auth []gossh.AuthMethod if config.Comm.SSHPassword != "" { auth = []gossh.AuthMethod{ gossh.Password(config.Comm.SSHPassword), gossh.KeyboardInteractive( ssh.PasswordKeyboardInteractive(config.Comm.SSHPassword)), } } if config.Comm.SSHPrivateKey != "" { if priv, ok := state.GetOk("privateKey"); ok { privateKey = priv.(string) } signer, err := gossh.ParsePrivateKey([]byte(privateKey)) if err != nil { return nil, fmt.Errorf("Error setting up SSH config: %s", err) } if err != nil { return nil, err } auth = append(auth, gossh.PublicKeys(signer)) } return &gossh.ClientConfig{ User: config.Comm.SSHUsername, Auth: auth, }, nil }
func sshConfig(comm *communicator.Config) func(state multistep.StateBag) (*gossh.ClientConfig, error) { return func(state multistep.StateBag) (*gossh.ClientConfig, error) { if comm.SSHPrivateKey != "" { // key based auth bytes, err := ioutil.ReadFile(comm.SSHPrivateKey) if err != nil { return nil, fmt.Errorf("Error setting up SSH config: %s", err) } privateKey := string(bytes) signer, err := gossh.ParsePrivateKey([]byte(privateKey)) if err != nil { return nil, fmt.Errorf("Error setting up SSH config: %s", err) } return &gossh.ClientConfig{ User: comm.SSHUsername, Auth: []gossh.AuthMethod{ gossh.PublicKeys(signer), }, }, nil } else { // password based auth return &gossh.ClientConfig{ User: comm.SSHUsername, Auth: []gossh.AuthMethod{ gossh.Password(comm.SSHPassword), gossh.KeyboardInteractive( ssh.PasswordKeyboardInteractive(comm.SSHPassword)), }, }, nil } } }
func connectToRemoteHost(auth ssh.AuthMethod, user, host string, port int64) (*ssh.Client, error) { clientConfig := &ssh.ClientConfig{ User: user, Auth: []ssh.AuthMethod{auth, ssh.KeyboardInteractive(kic)}, } return ssh.Dial("tcp", fmt.Sprintf("%s:%d", host, port), clientConfig) }
func main() { listen := flag.String("listen", ":2022", "listen address") dest := flag.String("dest", ":22", "destination address") key := flag.String("key", "host_key", "rsa key to use") flag.Parse() privateBytes, err := ioutil.ReadFile(*key) if err != nil { panic("Failed to load private key") } private, err := ssh.ParsePrivateKey(privateBytes) if err != nil { panic("Failed to parse private key") } sessions := map[net.Addr]map[string]interface{}{} config := &ssh.ServerConfig{ PasswordCallback: func(c ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) { fmt.Printf("Login attempt: %s, user %s password: %s\n", c.RemoteAddr(), c.User(), string(pass)) sessions[c.RemoteAddr()] = map[string]interface{}{ "username": c.User(), "password": string(pass), } clientConfig := &ssh.ClientConfig{ User: c.User(), Auth: []ssh.AuthMethod{ ssh.KeyboardInteractive(func(user, instruction string, questions []string, echos []bool) ([]string, error) { if len(questions) == 1 && questions[0] == "Password:"******"tcp", *dest, clientConfig) if err != nil { return nil, err } sessions[c.RemoteAddr()]["client"] = client return nil, nil }, } config.AddHostKey(private) sshproxy.ListenAndServe(*listen, config, func(c ssh.ConnMetadata) (*ssh.Client, error) { meta, ok := sessions[c.RemoteAddr()] if !ok { return nil, fmt.Errorf("session not found") } client := meta["client"].(*ssh.Client) fmt.Printf("Connection accepted from: %s", c.RemoteAddr()) return client, nil }, nil, nil) }
// NewClientConfig creates a barebones ssh.ClientConfig to be used with ssh.Dial. func NewClientConfig(name string) *ssh.ClientConfig { return &ssh.ClientConfig{ User: name, Auth: []ssh.AuthMethod{ ssh.KeyboardInteractive(func(user, instruction string, questions []string, echos []bool) (answers []string, err error) { return }), }, } }
func openLog(path string) (io.WriteCloser, error) { m := scpPathRe.FindStringSubmatch(path) if m == nil { return os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0600) } else { user, pass, host, port, path := m[1], m[2], m[3], m[4], m[5] if path == "" { return nil, errors.New("blank remote file path") } if port == "" { port = "22" } else { port = port[1:] } config := ssh.ClientConfig{ User: user, Auth: []ssh.AuthMethod{ssh.KeyboardInteractive(sshKeyboardAuth)}, } if pass != "" { config.Auth = append([]ssh.AuthMethod{ssh.Password(pass[1:])}, config.Auth...) } else { config.Auth = append([]ssh.AuthMethod{ssh.PasswordCallback(func() (string, error) { fmt.Printf("Password: "******"tcp", net.JoinHostPort(host, port), &config) if err != nil { return nil, err } session, err := client.NewSession() if err != nil { return nil, err } inputStream, err := session.StdinPipe() if err != nil { session.Close() return nil, err } cmd := fmt.Sprintf("cat > %s", shellEscape(path)) if err := session.Start(cmd); err != nil { session.Close() return nil, err } return inputStream, nil } }
// SSHConfig returns a function that can be used for the SSH communicator // config for connecting to the instance created over SSH using the private key // or password. func SSHConfig(useAgent bool, username, password string) func(multistep.StateBag) (*ssh.ClientConfig, error) { return func(state multistep.StateBag) (*ssh.ClientConfig, error) { if useAgent { authSock := os.Getenv("SSH_AUTH_SOCK") if authSock == "" { return nil, fmt.Errorf("SSH_AUTH_SOCK is not set") } sshAgent, err := net.Dial("unix", authSock) if err != nil { return nil, fmt.Errorf("Cannot connect to SSH Agent socket %q: %s", authSock, err) } return &ssh.ClientConfig{ User: username, Auth: []ssh.AuthMethod{ ssh.PublicKeysCallback(agent.NewClient(sshAgent).Signers), }, }, nil } privateKey, hasKey := state.GetOk("privateKey") if hasKey { signer, err := ssh.ParsePrivateKey([]byte(privateKey.(string))) if err != nil { return nil, fmt.Errorf("Error setting up SSH config: %s", err) } return &ssh.ClientConfig{ User: username, Auth: []ssh.AuthMethod{ ssh.PublicKeys(signer), }, }, nil } else { return &ssh.ClientConfig{ User: username, Auth: []ssh.AuthMethod{ ssh.Password(password), ssh.KeyboardInteractive( packerssh.PasswordKeyboardInteractive(password)), }}, nil } } }
func main() { // Show the current version: log.Println(`SSHTunnel v1.3.0`) // Allow Go to use all CPUs: runtime.GOMAXPROCS(runtime.NumCPU()) // Read the configuration from the command-line args: readFlags() // Check if the password was provided: for true { if password == `` { // Promt for the password: fmt.Println(`Please provide the password for the connection:`) if pass, errPass := gopass.GetPasswd(); errPass != nil { log.Println(`There was an error reading the password securely: ` + errPass.Error()) os.Exit(1) return } else { password = string(pass) } } else { break } } // Create the SSH configuration: Tunnel.SetPassword4Callback(password) config := &ssh.ClientConfig{ User: username, Auth: []ssh.AuthMethod{ ssh.Password(password), ssh.PasswordCallback(Tunnel.PasswordCallback), ssh.KeyboardInteractive(Tunnel.KeyboardInteractiveChallenge), }, } // Create the local end-point: localListener := Tunnel.CreateLocalEndPoint(localAddrString) // Accept client connections (will block forever): Tunnel.AcceptClients(localListener, config, serverAddrString, remoteAddrString) }
func sshConfig(state multistep.StateBag) (*gossh.ClientConfig, error) { config := state.Get("config").(*Config) auth := []gossh.AuthMethod{ gossh.Password(config.Comm.SSHPassword), gossh.KeyboardInteractive( ssh.PasswordKeyboardInteractive(config.Comm.SSHPassword)), } if config.Comm.SSHPrivateKey != "" { signer, err := commonssh.FileSigner(config.Comm.SSHPrivateKey) if err != nil { return nil, err } auth = append(auth, gossh.PublicKeys(signer)) } return &gossh.ClientConfig{ User: config.Comm.SSHUsername, Auth: auth, }, nil }
func sshBastionConfig(config *Config) (*gossh.ClientConfig, error) { auth := make([]gossh.AuthMethod, 0, 2) if config.SSHBastionPassword != "" { auth = append(auth, gossh.Password(config.SSHBastionPassword), gossh.KeyboardInteractive( ssh.PasswordKeyboardInteractive(config.SSHBastionPassword))) } if config.SSHBastionPrivateKey != "" { signer, err := commonssh.FileSigner(config.SSHBastionPrivateKey) if err != nil { return nil, err } auth = append(auth, gossh.PublicKeys(signer)) } return &gossh.ClientConfig{ User: config.SSHBastionUsername, Auth: auth, }, nil }
func SSHConfigFunc(config SSHConfig) func(multistep.StateBag) (*gossh.ClientConfig, error) { return func(state multistep.StateBag) (*gossh.ClientConfig, error) { auth := []gossh.AuthMethod{ gossh.Password(config.Comm.SSHPassword), gossh.KeyboardInteractive( ssh.PasswordKeyboardInteractive(config.Comm.SSHPassword)), } if config.SSHKeyPath != "" { signer, err := commonssh.FileSigner(config.Comm.SSHPrivateKey) if err != nil { return nil, err } auth = append(auth, gossh.PublicKeys(signer)) } return &gossh.ClientConfig{ User: config.Comm.SSHUsername, Auth: auth, }, nil } }
func sshConfig(state multistep.StateBag) (*ssh.ClientConfig, error) { config := state.Get("config").(config) privateKey := state.Get("ssh_private_key").(string) auth := []ssh.AuthMethod{ ssh.Password(config.SSHPassword), ssh.KeyboardInteractive( packerssh.PasswordKeyboardInteractive(config.SSHPassword)), } if privateKey != "" { signer, err := ssh.ParsePrivateKey([]byte(privateKey)) if err != nil { return nil, fmt.Errorf("Error setting up SSH config: %s", err) } auth = append(auth, ssh.PublicKeys(signer)) } return &ssh.ClientConfig{ User: config.SSHUsername, Auth: auth, }, nil }
func main() { flag.Parse() logger, cl := makeLogger() if flagTrace { cl.SetMinLevel(colog.LTrace) } else if flagVerbose { cl.SetMinLevel(colog.LDebug) } else if flagQuiet { cl.SetMinLevel(colog.LWarning) } else { cl.SetMinLevel(colog.LInfo) } if len(flagAllowedSourceIPs) > 0 { log.Println("info: Allowed source IPs:") for _, host := range flagAllowedSourceIPs { log.Printf(" - %s", host) } } if len(flagAllowedDestinationIPs) > 0 { log.Println("info: Allowed destination IPs:") for _, host := range flagAllowedDestinationIPs { log.Printf(" - %s", host) } } addr := fmt.Sprintf("%s:%d", flagHost, flagPort) // Create a SOCKS5 server conf := &socks5.Config{ Rules: Rules{}, Logger: logger, } server, err := socks5.New(conf) if err != nil { log.Fatalf("error: could not create SOCKS server: %s", err) } // Create the listener var ( l net.Listener listenHost string ) if flagRemoteListener != "" { u, err := url.Parse(flagRemoteListener) if err != nil { log.Fatalf("error: error parsing url: %s", err) } if u.Scheme != "ssh" { log.Fatalf("error: url is not an SSH url: %s", flagRemoteListener) } if u.User == nil { log.Fatalf("error: no username provided in remote listener", err) } if u.Path != "" || u.RawQuery != "" || u.Fragment != "" { log.Printf("warning: path, query, and fragment have no meaning in remote listener URL") } listenHost = u.Host // TODO: uber-hack atm find a better way, pass as cmd line argument answers := keyboardInteractive(map[string]string{ "Verification code: ": "", }) config := &ssh.ClientConfig{ User: u.User.Username(), //User: "******", Auth: []ssh.AuthMethod{ SSHAgent(), ssh.KeyboardInteractive(answers.Challenge), }, } sshConn, err := ssh.Dial("tcp", u.Host, config) if err != nil { log.Fatalf("error: error dialing remote host: %s", err) } defer sshConn.Close() l, err = sshConn.Listen("tcp", addr) if err != nil { log.Fatalf("error: error listening on remote host: %s", err) } } else { // Listen on a local port listenHost = "localhost" l, err = net.Listen("tcp", addr) } defer l.Close() log.Printf("info: starting socks proxy on: %s (proxy addr: %s)", listenHost, addr) if err := server.Serve(l); err != nil { log.Fatalf("error: could not serve socks proxy: %s", err) } log.Println("debug: done") }
func runMain(cmd *cobra.Command, args []string) { if len(args) != 1 { log.Printf("error: invalid number of arguments (expected 1, got %d)", len(args)) os.Exit(1) } sshHost := args[0] // Add a default ':22' after the end if we don't have a colon. if !strings.Contains(sshHost, ":") { sshHost += ":22" } config := &ssh.ClientConfig{ User: flagSSHUsername, Auth: nil, } // Password auth or prompt callback if flagSSHPassword != "" { log.Println("trace: adding password auth") config.Auth = append(config.Auth, ssh.Password(flagSSHPassword)) } else { log.Println("trace: adding password callback auth") config.Auth = append(config.Auth, ssh.PasswordCallback(func() (string, error) { prompt := fmt.Sprintf("%s@%s's password: "******"" { auth, err := loadPrivateKey(flagSSHIdentityFile) if err != nil { log.Fatalf("error: could not load identity file '%s': %s", flagSSHIdentityFile, err) } log.Println("trace: adding identity file auth") config.Auth = append(config.Auth, auth) } // SSH agent auth if agentConn, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK")); err != nil { log.Println("trace: adding ssh agent auth") config.Auth = append(config.Auth, ssh.PublicKeysCallback(agent.NewClient(agentConn).Signers)) } config.Auth = append(config.Auth, ssh.KeyboardInteractive(func(user, instruction string, questions []string, echos []bool) (answers []string, err error) { var ( ans string b []byte ) for i, q := range questions { prompt := fmt.Sprintf("[question %d/%d] %s", i+1, len(questions), q) if echos[i] { fmt.Print(prompt) bio := bufio.NewReader(os.Stdin) b, _, err = bio.ReadLine() ans = string(b) } else { ans, err = speakeasy.Ask(prompt) } if err != nil { return } answers = append(answers, ans) } return })) // TODO: keyboard-interactive auth, e.g. for two-factor // Dial the SSH connection log.Printf("debug: attempting %d authentication methods (%+v)", len(config.Auth), config.Auth) sshConn, err := ssh.Dial("tcp", sshHost, config) if err != nil { log.Fatalf("error: error dialing remote host: %s", err) } defer sshConn.Close() // Listen on remote l, err := sshConn.Listen("tcp", flagAddr) if err != nil { log.Fatalf("error: error listening on remote host: %s", err) } // Start accepting shell connections log.Printf("info: listening for connections on %s (remote listen address: %s)", sshHost, flagAddr) for { conn, err := l.Accept() if err != nil { log.Printf("error: error accepting connection: %s", err) continue } log.Printf("info: accepted connection from: %s", conn.RemoteAddr()) go handleConnection(conn) } }
func main() { // Show the current version: log.Println(`Sync v1.2.0`) // Allow Go to use all CPUs: runtime.GOMAXPROCS(runtime.NumCPU()) // Read the configuration from the command-line args: readFlags() // Check if the directories are provided: if localDir == `` || remoteDir == `` { log.Println(`Please provide the local and remote directory.`) os.Exit(1) return } // Should I use the current working dir? if localDir == `.` { if currentWD, currentWDError := os.Getwd(); currentWDError != nil { log.Println("Cannot use the current working directory as local directory: " + currentWDError.Error()) os.Exit(2) return } else { log.Println("I use the current working directory as local directory: " + currentWD) localDir = currentWD } } // Remove trailing separators from both directories localDir = correctPath(localDir) remoteDir = correctPath(remoteDir) // Check if local dir exist if dirInfo, dirError := os.Stat(localDir); dirError != nil { log.Println("There is an error with the local directory: " + dirError.Error()) os.Exit(3) return } else { if !dirInfo.IsDir() { log.Println("There is an error with the local directory: You provided a file instead!") os.Exit(4) return } } // Check if the password was provided: for true { if password == `` { // Promt for the password: fmt.Print(`Please provide the password for the connection: `) if pass, errPass := gopass.GetPasswd(); errPass != nil { log.Println(`There was an error reading the password securely: ` + errPass.Error()) os.Exit(5) return } else { password = string(pass) } } else { break } } // Give some information about the state if supervised { log.Println("I use the supervised mode.") } else { log.Println("I do not use the supervised mode.") } if pushOnly { log.Println("I use the push only mode i.e. backup mode. Any remote change will be ignored.") } else { log.Println("I use the full mode and consider also remote changes.") } // Create the SSH configuration: Sync.SetPassword4Callback(password) config := &ssh.ClientConfig{ User: username, Auth: []ssh.AuthMethod{ ssh.Password(password), ssh.PasswordCallback(Sync.PasswordCallback), ssh.KeyboardInteractive(Sync.KeyboardInteractiveChallenge), }, } // Connect to the SSH server: ssh := Sync.ConnectSSH(config, serverAddrString) if ssh == nil { log.Println(`It was not possible to connect to the SSH server.`) os.Exit(6) return } defer ssh.Close() Sync.Synchronise(ssh, supervised, pushOnly, localDir, remoteDir) log.Println("Synchronising done.") }
// PrepareConfig is used to turn the *SSHConfig provided into a // usable *Config for client initialization. func PrepareConfig(conf *SSHConfig) (*Config, error) { var conn net.Conn var err error sshConf := &ssh.ClientConfig{ User: conf.User, } if conf.Agent { sshAuthSock := os.Getenv("SSH_AUTH_SOCK") if sshAuthSock == "" { return nil, fmt.Errorf("SSH Requested but SSH_AUTH_SOCK not-specified") } conn, err = net.Dial("unix", sshAuthSock) if err != nil { return nil, fmt.Errorf("Error connecting to SSH_AUTH_SOCK: %v", err) } // I need to close this but, later after all connections have been made // defer conn.Close() signers, err := agent.NewClient(conn).Signers() if err != nil { return nil, fmt.Errorf("Error getting keys from ssh agent: %v", err) } sshConf.Auth = append(sshConf.Auth, ssh.PublicKeys(signers...)) } if conf.KeyFile != "" { fullPath, err := homedir.Expand(conf.KeyFile) if err != nil { return nil, fmt.Errorf("Failed to expand home directory: %v", err) } key, err := ioutil.ReadFile(fullPath) if err != nil { return nil, fmt.Errorf("Failed to read key file '%s': %v", conf.KeyFile, err) } // We parse the private key on our own first so that we can // show a nicer error if the private key has a password. block, _ := pem.Decode(key) if block == nil { return nil, fmt.Errorf( "Failed to read key '%s': no key found", conf.KeyFile) } if block.Headers["Proc-Type"] == "4,ENCRYPTED" { return nil, fmt.Errorf( "Failed to read key '%s': password protected keys are\n"+ "not supported. Please decrypt the key prior to use.", conf.KeyFile) } signer, err := ssh.ParsePrivateKey(key) if err != nil { return nil, fmt.Errorf("Failed to parse key file '%s': %v", conf.KeyFile, err) } sshConf.Auth = append(sshConf.Auth, ssh.PublicKeys(signer)) } if conf.Password != "" { sshConf.Auth = append(sshConf.Auth, ssh.Password(conf.Password)) sshConf.Auth = append(sshConf.Auth, ssh.KeyboardInteractive(PasswordKeyboardInteractive(conf.Password))) } host := fmt.Sprintf("%s:%d", conf.Host, conf.Port) config := &Config{ SSHConfig: sshConf, Connection: ConnectFunc("tcp", host), SSHAgentConn: conn, } return config, nil }
func (s *sshTunnel) Start(readyErrCh chan<- error, errCh chan<- error) { authMethods := []ssh.AuthMethod{} if s.options.PrivateKey != "" { s.logger.Debug(s.logTag, "Reading private key file '%s'", s.options.PrivateKey) keyContents, err := ioutil.ReadFile(s.options.PrivateKey) if err != nil { readyErrCh <- bosherr.WrapErrorf(err, "Reading private key file '%s'", s.options.PrivateKey) return } s.logger.Debug(s.logTag, "Parsing private key file '%s'", s.options.PrivateKey) signer, err := ssh.ParsePrivateKey(keyContents) if err != nil { readyErrCh <- bosherr.WrapErrorf(err, "Parsing private key file '%s'", s.options.PrivateKey) return } authMethods = append(authMethods, ssh.PublicKeys(signer)) } if s.options.Password != "" { s.logger.Debug(s.logTag, "Adding password auth method to ssh tunnel config") keyboardInteractiveChallenge := func( user, instruction string, questions []string, echos []bool, ) (answers []string, err error) { if len(questions) == 0 { return []string{}, nil } return []string{s.options.Password}, nil } authMethods = append(authMethods, ssh.KeyboardInteractive(keyboardInteractiveChallenge)) authMethods = append(authMethods, ssh.Password(s.options.Password)) } sshConfig := &ssh.ClientConfig{ User: s.options.User, Auth: authMethods, } s.logger.Debug(s.logTag, "Dialing remote server at %s:%d", s.options.Host, s.options.Port) remoteAddr := fmt.Sprintf("%s:%d", s.options.Host, s.options.Port) retryStrategy := &SSHRetryStrategy{ TimeService: s.timeService, ConnectionRefusedTimeout: s.connectionRefusedTimeout, AuthFailureTimeout: s.authFailureTimeout, } var conn *ssh.Client var err error for i := 0; ; i++ { s.logger.Debug(s.logTag, "Making attempt #%d", i) conn, err = ssh.Dial("tcp", remoteAddr, sshConfig) if err == nil { break } if !retryStrategy.IsRetryable(err) { readyErrCh <- bosherr.WrapError(err, "Failed to connect to remote server") return } s.logger.Debug(s.logTag, "Attempt failed #%d: Dialing remote server: %s", i, err.Error()) time.Sleep(s.startDialDelay) } remoteListenAddr := fmt.Sprintf("127.0.0.1:%d", s.options.RemoteForwardPort) s.logger.Debug(s.logTag, "Listening on remote server %s", remoteListenAddr) s.remoteListener, err = conn.Listen("tcp", remoteListenAddr) if err != nil { readyErrCh <- bosherr.WrapError(err, "Listening on remote server") return } readyErrCh <- nil for { remoteConn, err := s.remoteListener.Accept() s.logger.Debug(s.logTag, "Received connection") if err != nil { errCh <- bosherr.WrapError(err, "Accepting connection on remote server") } defer func() { if err = remoteConn.Close(); err != nil { s.logger.Warn(s.logTag, "Failed to close remote listener connection: %s", err.Error()) } }() s.logger.Debug(s.logTag, "Dialing local server") localDialAddr := fmt.Sprintf("127.0.0.1:%d", s.options.LocalForwardPort) localConn, err := net.Dial("tcp", localDialAddr) if err != nil { errCh <- bosherr.WrapError(err, "Dialing local server") return } go func() { bytesNum, err := io.Copy(remoteConn, localConn) defer func() { if err = localConn.Close(); err != nil { s.logger.Warn(s.logTag, "Failed to close local dial connection: %s", err.Error()) } }() s.logger.Debug(s.logTag, "Copying bytes from local to remote %d", bytesNum) if err != nil { errCh <- bosherr.WrapError(err, "Copying bytes from local to remote") } }() go func() { bytesNum, err := io.Copy(localConn, remoteConn) defer func() { if err = localConn.Close(); err != nil { s.logger.Warn(s.logTag, "Failed to close local dial connection: %s", err.Error()) } }() s.logger.Debug(s.logTag, "Copying bytes from remote to local %d", bytesNum) if err != nil { errCh <- bosherr.WrapError(err, "Copying bytes from remote to local") } }() } }
func SSHExec(ws *websocket.Conn) { var dump_out, dump_in io.WriteCloser defer func() { ws.Close() if nil != dump_out { dump_out.Close() } if nil != dump_in { dump_in.Close() } }() hostname := ws.Request().URL.Query().Get("hostname") port := ws.Request().URL.Query().Get("port") if "" == port { port = "22" } user := ws.Request().URL.Query().Get("user") pwd := ws.Request().URL.Query().Get("password") debug := *is_debug if "true" == strings.ToLower(ws.Request().URL.Query().Get("debug")) { debug = true } cmd := ws.Request().URL.Query().Get("cmd") cmd_alias := ws.Request().URL.Query().Get("dump_file") if "" == cmd_alias { cmd_alias = strings.Replace(cmd, " ", "_", -1) } password_count := 0 empty_interactive_count := 0 reader := bufio.NewReader(ws) // Dial code is taken from the ssh package example config := &ssh.ClientConfig{ Config: ssh.Config{Ciphers: supportedCiphers}, User: user, Auth: []ssh.AuthMethod{ ssh.Password(pwd), ssh.KeyboardInteractive(func(user, instruction string, questions []string, echos []bool) (answers []string, err error) { if len(questions) == 0 { empty_interactive_count++ if empty_interactive_count++; empty_interactive_count > 50 { return nil, errors.New("interactive count is too much") } return []string{}, nil } for _, question := range questions { io.WriteString(ws, question) switch strings.ToLower(strings.TrimSpace(question)) { case "password:"******"password as": password_count++ if password_count == 1 { answers = append(answers, pwd) break } fallthrough default: line, _, e := reader.ReadLine() if nil != e { return nil, e } answers = append(answers, string(line)) } } return answers, nil })}, } client, err := ssh.Dial("tcp", hostname+":"+port, config) if err != nil { logString(ws, "Failed to dial: "+err.Error()) return } session, err := client.NewSession() if err != nil { logString(ws, "Failed to create session: "+err.Error()) return } defer session.Close() var combinedOut io.Writer = ws if debug { dump_out, err = os.OpenFile(logs_dir+hostname+"_"+cmd_alias+".dump_ssh_out.txt", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666) if nil == err { fmt.Println("log to file", logs_dir+hostname+"_"+cmd_alias+".dump_ssh_out.txt") combinedOut = io.MultiWriter(dump_out, ws) } else { fmt.Println("failed to open log file,", err) } dump_in, err = os.OpenFile(logs_dir+hostname+"_"+cmd_alias+".dump_ssh_in.txt", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666) if nil != err { dump_in = nil fmt.Println("failed to open log file,", err) } else { fmt.Println("log to file", logs_dir+hostname+"_"+cmd_alias+".dump_ssh_in.txt") } } session.Stdout = combinedOut session.Stderr = combinedOut session.Stdin = warp(ws, dump_in) if err := session.Start(cmd); nil != err { logString(combinedOut, "Unable to execute command:"+err.Error()) return } if err := session.Wait(); nil != err { logString(combinedOut, "Unable to execute command:"+err.Error()) return } fmt.Println("exec ok") }
func SSHShell(ws *websocket.Conn) { var dump_out, dump_in io.WriteCloser defer func() { ws.Close() if nil != dump_out { dump_out.Close() } if nil != dump_in { dump_in.Close() } }() hostname := ws.Request().URL.Query().Get("hostname") port := ws.Request().URL.Query().Get("port") if "" == port { port = "22" } user := ws.Request().URL.Query().Get("user") pwd := ws.Request().URL.Query().Get("password") columns := toInt(ws.Request().URL.Query().Get("columns"), 120) rows := toInt(ws.Request().URL.Query().Get("rows"), 80) debug := *is_debug if "true" == strings.ToLower(ws.Request().URL.Query().Get("debug")) { debug = true } password_count := 0 empty_interactive_count := 0 reader := bufio.NewReader(ws) // Dial code is taken from the ssh package example config := &ssh.ClientConfig{ Config: ssh.Config{Ciphers: supportedCiphers}, User: user, Auth: []ssh.AuthMethod{ ssh.Password(pwd), ssh.KeyboardInteractive(func(user, instruction string, questions []string, echos []bool) (answers []string, err error) { if len(questions) == 0 { empty_interactive_count++ if empty_interactive_count++; empty_interactive_count > 50 { return nil, errors.New("interactive count is too much") } return []string{}, nil } for _, question := range questions { io.WriteString(ws, question) switch strings.ToLower(strings.TrimSpace(question)) { case "password:"******"password as": password_count++ if password_count == 1 { answers = append(answers, pwd) break } fallthrough default: line, _, e := reader.ReadLine() if nil != e { return nil, e } answers = append(answers, string(line)) } } return answers, nil }), }, } client, err := ssh.Dial("tcp", hostname+":"+port, config) if err != nil { logString(ws, "Failed to dial: "+err.Error()) return } session, err := client.NewSession() if err != nil { logString(ws, "Failed to create session: "+err.Error()) return } defer session.Close() // Set up terminal modes modes := ssh.TerminalModes{ ssh.ECHO: 1, // disable echoing ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud } // Request pseudo terminal if err = session.RequestPty("xterm", rows, columns, modes); err != nil { logString(ws, "request for pseudo terminal failed:"+err.Error()) return } var combinedOut io.Writer = ws if debug { dump_out, err = os.OpenFile(logs_dir+hostname+".dump_ssh_out.txt", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666) if nil == err { combinedOut = io.MultiWriter(dump_out, ws) } dump_in, err = os.OpenFile(logs_dir+hostname+".dump_ssh_in.txt", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666) if nil != err { dump_in = nil } } session.Stdout = combinedOut session.Stderr = combinedOut session.Stdin = warp(ws, dump_in) if err := session.Shell(); nil != err { logString(ws, "Unable to execute command:"+err.Error()) return } if err := session.Wait(); nil != err { logString(ws, "Unable to execute command:"+err.Error()) } }