@@ -35,29 +35,36 @@ import (
3535// in place of the 'ssh' executable.
3636const EnvShellSSH = "SSH"
3737
38- func SSHArguments () (arg0 string , arg0Args []string , err error ) {
38+ type SSHExe struct {
39+ Executable string
40+ Args []string
41+ }
42+
43+ func SSHArguments () (SSHExe , error ) {
44+ var sshExe SSHExe
45+
3946 if sshShell := os .Getenv (EnvShellSSH ); sshShell != "" {
4047 sshShellFields , err := shellwords .Parse (sshShell )
4148 switch {
4249 case err != nil :
4350 logrus .WithError (err ).Warnf ("Failed to split %s variable into shell tokens. " +
4451 "Falling back to 'ssh' command" , EnvShellSSH )
4552 case len (sshShellFields ) > 0 :
46- arg0 = sshShellFields [0 ]
53+ sshExe . Executable = sshShellFields [0 ]
4754 if len (sshShellFields ) > 1 {
48- arg0Args = sshShellFields [1 :]
55+ sshExe . Args = sshShellFields [1 :]
4956 }
57+ return sshExe , nil
5058 }
5159 }
5260
53- if arg0 == "" {
54- arg0 , err = exec .LookPath ("ssh" )
55- if err != nil {
56- return "" , []string {"" }, err
57- }
61+ executable , err := exec .LookPath ("ssh" )
62+ if err != nil {
63+ return SSHExe {}, err
5864 }
65+ sshExe .Executable = executable
5966
60- return arg0 , arg0Args , nil
67+ return sshExe , nil
6168}
6269
6370type PubKey struct {
@@ -177,7 +184,7 @@ var sshInfo struct {
177184//
178185// The result always contains the IdentityFile option.
179186// The result never contains the Port option.
180- func CommonOpts (sshPath string , useDotSSH bool ) ([]string , error ) {
187+ func CommonOpts (sshExe SSHExe , useDotSSH bool ) ([]string , error ) {
181188 configDir , err := dirnames .LimaConfigDir ()
182189 if err != nil {
183190 return nil , err
@@ -243,7 +250,7 @@ func CommonOpts(sshPath string, useDotSSH bool) ([]string, error) {
243250
244251 sshInfo .Do (func () {
245252 sshInfo .aesAccelerated = detectAESAcceleration ()
246- sshInfo .openSSH = detectOpenSSHInfo (sshPath )
253+ sshInfo .openSSH = detectOpenSSHInfo (sshExe )
247254 })
248255
249256 if sshInfo .openSSH .GSSAPISupported {
@@ -287,12 +294,12 @@ func identityFileEntry(privateKeyPath string) (string, error) {
287294}
288295
289296// SSHOpts adds the following options to CommonOptions: User, ControlMaster, ControlPath, ControlPersist.
290- func SSHOpts (sshPath , instDir , username string , useDotSSH , forwardAgent , forwardX11 , forwardX11Trusted bool ) ([]string , error ) {
297+ func SSHOpts (sshExe SSHExe , instDir , username string , useDotSSH , forwardAgent , forwardX11 , forwardX11Trusted bool ) ([]string , error ) {
291298 controlSock := filepath .Join (instDir , filenames .SSHSock )
292299 if len (controlSock ) >= osutil .UnixPathMax {
293300 return nil , fmt .Errorf ("socket path %q is too long: >= UNIX_PATH_MAX=%d" , controlSock , osutil .UnixPathMax )
294301 }
295- opts , err := CommonOpts (sshPath , useDotSSH )
302+ opts , err := CommonOpts (sshExe , useDotSSH )
296303 if err != nil {
297304 return nil , err
298305 }
@@ -361,13 +368,15 @@ var (
361368 openSSHInfosRW sync.RWMutex
362369)
363370
364- func detectOpenSSHInfo (ssh string ) openSSHInfo {
371+ func detectOpenSSHInfo (sshExe SSHExe ) openSSHInfo {
365372 var (
366373 info openSSHInfo
367374 exe sshExecutable
368375 stderr bytes.Buffer
369376 )
370- path , err := exec .LookPath (ssh )
377+ // TODO: Fix this function to properly handle complex SSH commands like "kitten ssh"
378+ // The current LookPath, os.Stat, and caching logic doesn't work well for multi-word commands
379+ path , err := exec .LookPath (sshExe .Executable )
371380 if err != nil {
372381 logrus .Warnf ("failed to find ssh executable: %v" , err )
373382 } else {
@@ -381,7 +390,8 @@ func detectOpenSSHInfo(ssh string) openSSHInfo {
381390 }
382391 }
383392 // -V should be last
384- cmd := exec .Command (path , "-o" , "GSSAPIAuthentication=no" , "-V" )
393+ allArgs := append (sshExe .Args , "-o" , "GSSAPIAuthentication=no" , "-V" )
394+ cmd := exec .Command (sshExe .Executable , allArgs ... )
385395 cmd .Stderr = & stderr
386396 if err := cmd .Run (); err != nil {
387397 logrus .Warnf ("failed to run %v: stderr=%q" , cmd .Args , stderr .String ())
@@ -398,8 +408,8 @@ func detectOpenSSHInfo(ssh string) openSSHInfo {
398408 return info
399409}
400410
401- func DetectOpenSSHVersion (ssh string ) semver.Version {
402- return detectOpenSSHInfo (ssh ).Version
411+ func DetectOpenSSHVersion (sshExe SSHExe ) semver.Version {
412+ return detectOpenSSHInfo (sshExe ).Version
403413}
404414
405415// detectValidPublicKey returns whether content represent a public key.
0 commit comments