Beispiel #1
0
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,
	}
}
Beispiel #2
0
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))
}
Beispiel #3
0
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
	}
}
Beispiel #4
0
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
}
Beispiel #5
0
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
}
Beispiel #7
0
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")
}
Beispiel #8
0
func (a *PasswordCallback) clientConfig() *ssh.ClientConfig {
	return &ssh.ClientConfig{
		User: a.User,
		Auth: []ssh.AuthMethod{ssh.PasswordCallback(a.Callback)},
	}
}
Beispiel #9
0
// 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
}
Beispiel #10
0
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
}
Beispiel #11
0
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.")
}
Beispiel #12
0
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)
	}
}
Beispiel #13
0
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.")
	}
}