func NewSSHTunnel(sshUser string, sshHost string, sshPort int, localPort int, remoteHost string, remotePort int) *SSHTunnel { localEndpoint := &Endpoint{ Host: "localhost", Port: localPort, } serverEndpoint := &Endpoint{ Host: sshHost, Port: sshPort, } remoteEndpoint := &Endpoint{ Host: remoteHost, Port: remotePort, } sshConfig := &ssh.ClientConfig{ User: sshUser, Auth: []ssh.AuthMethod{ SSHAgent(), ssh.PasswordCallback(passwordCallback), }, } return &SSHTunnel{ Config: sshConfig, Local: localEndpoint, Server: serverEndpoint, Remote: remoteEndpoint, } }
func addPasswordAuth(user, addr string, auths []ssh.AuthMethod) []ssh.AuthMethod { if terminal.IsTerminal(0) == false { return auths } host := addr if i := strings.LastIndex(host, ":"); i != -1 { host = host[:i] } prompt := fmt.Sprintf("%s@%s's password: ", user, host) passwordCallback := func() (string, error) { return getpass(prompt) } return append(auths, ssh.PasswordCallback(passwordCallback)) }
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 } }
func sshAuths(addr *url.URL) (methods []ssh.AuthMethod) { c, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK")) if err == nil { auth := ssh.PublicKeysCallback(agent.NewClient(c).Signers) methods = append(methods, auth) } auth := ssh.PasswordCallback(func() (string, error) { fmt.Printf("%s@%s password: "******"\n") return string(b), err }) methods = append(methods, auth) return }
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 sshAuths(addr *url.URL) (methods []ssh.AuthMethod) { if sock := os.Getenv("SSH_AUTH_SOCK"); sock != "" { c, err := net.Dial("unix", sock) if err != nil { log.Println("Warning: failed to contact the local SSH agent") } else { auth := ssh.PublicKeysCallback(agent.NewClient(c).Signers) methods = append(methods, auth) } } auth := ssh.PasswordCallback(func() (string, error) { fmt.Printf("%s@%s password: "******"\n") return string(b), err }) methods = append(methods, auth) return }
func NewSSHClient(addr, user string) (Client, error) { sc := new(sshClient) sc.config = new(ssh.ClientConfig) sc.addr = addr sc.config.User = user sc.agent = sshAgent() if sc.agent != nil { signers, err := sc.agent.Signers() if err != nil { fmt.Fprintf(os.Stderr, "failed to get signers from SSH agent: %s", err) } else if len(signers) > 0 { sc.config.Auth = []ssh.AuthMethod{ssh.PublicKeys(signers...)} } } sc.config.Auth = append(sc.config.Auth, ssh.PasswordCallback(sc.askForPassword)) var err error addr = fmt.Sprintf("%s:%d", sc.addr, 22) sc.client, err = ssh.Dial("tcp", addr, sc.config) return sc, errors.Wrap(err, "failed to connect to SSH host") }
func (a *PasswordCallback) clientConfig() *ssh.ClientConfig { return &ssh.ClientConfig{ User: a.User, Auth: []ssh.AuthMethod{ssh.PasswordCallback(a.Callback)}, } }
// NewSSH is a helper function that does the initial parsing into an SSH obj. // It takes as input the path to a graph definition file. func (obj *Remotes) NewSSH(file string) (*SSH, error) { // first do the parsing... config := yamlgraph.ParseConfigFromFile(file) // FIXME: GAPI-ify somehow? if config == nil { return nil, fmt.Errorf("Remote: Error parsing remote graph: %s", file) } if config.Remote == "" { return nil, fmt.Errorf("Remote: No remote endpoint in the graph: %s", file) } // do the url parsing... u, err := url.Parse(config.Remote) if err != nil { return nil, err } if u.Scheme != "" && u.Scheme != "ssh" { return nil, fmt.Errorf("Unknown remote scheme: %s", u.Scheme) } host := "" port := defaultPort // default x := strings.Split(u.Host, ":") if c := len(x); c == 0 || c > 2 { // need one or two chunks return nil, fmt.Errorf("Can't parse host pattern: %s", u.Host) } else if c == 2 { v, err := strconv.ParseUint(x[1], 10, 16) if err != nil { return nil, fmt.Errorf("Can't parse port: %s", x[1]) } port = uint16(v) } host = x[0] if host == "" { return nil, fmt.Errorf("Empty hostname!") } user := defaultUser // default if x := u.User.Username(); x != "" { user = x } auth := []ssh.AuthMethod{} if secret, b := u.User.Password(); b { auth = append(auth, ssh.Password(secret)) } // get ssh key auth if available if a, err := obj.sshKeyAuth(); err == nil { auth = append(auth, a) } // if there are no auth methods available, add interactive to be helpful if len(auth) == 0 || obj.interactive { auth = append(auth, ssh.RetryableAuthMethod(ssh.PasswordCallback(obj.passwordCallback(user, host)), maxPasswordTries)) } if len(auth) == 0 { return nil, fmt.Errorf("No authentication methods available!") } //hostname := config.Hostname // TODO: optionally specify local hostname somehow hostname := "" if hostname == "" { hostname = host // default to above } if util.StrInList(hostname, obj.hostnames) { return nil, fmt.Errorf("Remote: Hostname `%s` already exists!", hostname) } obj.hostnames = append(obj.hostnames, hostname) return &SSH{ hostname: hostname, host: host, port: port, user: user, auth: auth, file: file, clientURLs: obj.clientURLs, remoteURLs: obj.remoteURLs, noop: obj.noop, noWatch: obj.fileWatch == nil, depth: obj.depth, caching: obj.caching, converger: obj.converger, prefix: obj.prefix, flags: obj.flags, }, nil }
func CreateSession(host *Host) (*ssh.Client, *ssh.Session, error) { // if the host configuration doesn't contain a key file, check the users .ssh/config file // appends any keys found for the matching host to be used for authentication foundHostConfig := userSshConfig.MatchHost(host.Host) if host.KeyFile == "" && foundHostConfig != nil { if foundHostConfig != nil { // set the host to the hostname found in the configuration // allows for using partial host names in the host argument if foundHostConfig.HostName != "" { host.Host = foundHostConfig.HostName } if host.KeyFile == "" && foundHostConfig.IdentityFile != "" { host.KeyFile = foundHostConfig.IdentityFile } // use the port form the ssh config if it's supplied if host.Port == "" && foundHostConfig.Port != "" { host.Port = foundHostConfig.Port } // use the user found in the foundHostConfig if one isn't provided if host.User == "" && foundHostConfig.User != "" { host.User = foundHostConfig.User } } } sshConfig := &ssh.ClientConfig{User: host.User, Auth: []ssh.AuthMethod{}} if host.Password != "" { sshConfig.Auth = append(sshConfig.Auth, ssh.Password(host.Password)) } if host.KeyFile != "" { sshConfig.Auth = append(sshConfig.Auth, ssh.PublicKeysCallback(func() (signers []ssh.Signer, err error) { keyFiles, err := LoadDefaultKeyFiles() if host.KeyFile != "" { hostKeyFile, err := LoadKeyFile(host.KeyFile) if err != nil { return nil, err } keyFiles = append(keyFiles, hostKeyFile) } return keyFiles, err })) } if host.Password == "" && host.KeyFile == "" { sshConfig.Auth = append(sshConfig.Auth, ssh.PasswordCallback(func() (string, error) { password, err := getpass.GetPassWithOptions(fmt.Sprintf("enter password for %s@%s: ", host.User, host.Host), 0, 100) if err != nil { fmt.Println(err.Error()) return password, err } host.Password = password return password, err })) } client, err := ssh.Dial("tcp", host.Host+":"+host.Port, sshConfig) if err != nil { fmt.Println(err.Error()) return nil, nil, err } session, err := client.NewSession() if err != nil { return nil, nil, err } return client, session, err }
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.") }
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() { user := flag.String("l", "", "connect with specified username") pw := flag.String("pw", "", "login with specified password") port := flag.Int64("P", 22, "connect with specified port") limit := flag.Int64("limit", 0, "bandwidth limit in bytes/sec") verbose := flag.Bool("v", false, "show verbose messages") fileListing := flag.Bool("ls", false, "folder listing") flag.Parse() if flag.NArg() < 2 && !*fileListing { fmt.Println("Must specify at least one source and a destination.") flag.Usage() os.Exit(1) } args := flag.Args() targetUser, targetHost, targetFile := parseFileHostLocation(args[len(args)-1]) password := func() (secret string, err error) { if *pw != "" { return *pw, nil } fmt.Print("Password: "******"" { if targetUser != "" && *user != "" && targetUser != *user { fmt.Println("Specfied user@host and -l user that do not match.") flag.Usage() os.Exit(1) } if targetUser == "" && *user == "" { fmt.Println("Must specify username.") flag.Usage() os.Exit(1) } if *user == "" { *user = targetUser } var clientErr error targetClient, clientErr = connectToRemoteHost(ssh.PasswordCallback(password), *user, targetHost, *port) if clientErr != nil { log.Fatalln("Failed to dial: " + clientErr.Error()) } } // Handle -ls flag if *fileListing { displayListing(targetClient, targetFile) os.Exit(0) } for _, sourceFile := range args[:len(args)-1] { srcUser, srcHost, srcFile := parseFileHostLocation(sourceFile) if srcUser != "" && srcHost != "" { client, err := connectToRemoteHost(ssh.PasswordCallback(password), srcUser, srcHost, 22) if err != nil { log.Fatalln("Failed to dial: " + err.Error()) } if targetHost == "" { if targetInfo, statErr := os.Stat(targetFile); statErr == nil && targetInfo.IsDir() == true { getFileFromRemoteHost(client, filepath.Join(targetFile, srcFile), srcUser, srcHost, srcFile) } else { getFileFromRemoteHost(client, targetFile, srcUser, srcHost, srcFile) } } else { fmt.Println("Both source and destination cannot be remote, one side must be local.") os.Exit(1) } } else { sendFileToRemoteHost(targetClient, *limit, sourceFile, targetUser, targetHost, targetFile) } } //PSCP has -v flag, so we need to use it as well if *verbose == true { fmt.Println("Program completed.") } }