From 94eb1653466be909d3553fd5de4d8a061dde9c2a Mon Sep 17 00:00:00 2001 From: Sylvie Crowe <107814465+oneirocosm@users.noreply.github.com> Date: Sun, 27 Oct 2024 20:35:19 -0700 Subject: [PATCH] fix: ignore the match statement in ssh config (#1155) This change will skip over match statements in the ssh config without panicking. Note that this change still does not add match statement parsing--it merely makes it possible to continue parsing if the match keyword is present. --- go.mod | 2 +- go.sum | 4 +- pkg/remote/conncontroller/conncontroller.go | 4 +- pkg/remote/connutil.go | 5 +-- pkg/remote/sshclient.go | 42 +++++++++++++-------- 5 files changed, 34 insertions(+), 23 deletions(-) diff --git a/go.mod b/go.mod index a5c99490e..7645166bc 100644 --- a/go.mod +++ b/go.mod @@ -47,6 +47,6 @@ require ( golang.org/x/net v0.29.0 // indirect ) -replace github.com/kevinburke/ssh_config => github.com/wavetermdev/ssh_config v0.0.0-20240306041034-17e2087ebde2 +replace github.com/kevinburke/ssh_config => github.com/wavetermdev/ssh_config v0.0.0-20241027232332-ed124367682d replace github.com/creack/pty => github.com/photostorm/pty v1.1.19-0.20230903182454-31354506054b diff --git a/go.sum b/go.sum index e0175c9a5..cb329ca3f 100644 --- a/go.sum +++ b/go.sum @@ -88,8 +88,8 @@ github.com/ubuntu/gowsl v0.0.0-20240906163211-049fd49bd93b h1:wFBKF5k5xbJQU8bYgc github.com/ubuntu/gowsl v0.0.0-20240906163211-049fd49bd93b/go.mod h1:N1CYNinssZru+ikvYTgVbVeSi21thHUTCoJ9xMvWe+s= github.com/wavetermdev/htmltoken v0.1.0 h1:RMdA9zTfnYa5jRC4RRG3XNoV5NOP8EDxpaVPjuVz//Q= github.com/wavetermdev/htmltoken v0.1.0/go.mod h1:5FM0XV6zNYiNza2iaTcFGj+hnMtgqumFHO31Z8euquk= -github.com/wavetermdev/ssh_config v0.0.0-20240306041034-17e2087ebde2 h1:onqZrJVap1sm15AiIGTfWzdr6cEF0KdtddeuuOVhzyY= -github.com/wavetermdev/ssh_config v0.0.0-20240306041034-17e2087ebde2/go.mod h1:q2RIzfka+BXARoNexmF9gkxEX7DmvbW9P4hIVx2Kg4M= +github.com/wavetermdev/ssh_config v0.0.0-20241027232332-ed124367682d h1:ArHaUBaiQWUqBzM2G/oLlm3Be0kwUMDt9vTNOWIfOd0= +github.com/wavetermdev/ssh_config v0.0.0-20241027232332-ed124367682d/go.mod h1:q2RIzfka+BXARoNexmF9gkxEX7DmvbW9P4hIVx2Kg4M= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= diff --git a/pkg/remote/conncontroller/conncontroller.go b/pkg/remote/conncontroller/conncontroller.go index 545738f02..06242b292 100644 --- a/pkg/remote/conncontroller/conncontroller.go +++ b/pkg/remote/conncontroller/conncontroller.go @@ -554,7 +554,7 @@ func resolveSshConfigPatterns(configFiles []string) ([]string, error) { continue } - cfg, _ := ssh_config.Decode(fd) + cfg, _ := ssh_config.Decode(fd, true) for _, host := range cfg.Hosts { // for each host, find the first good alias for _, hostPattern := range host.Patterns { @@ -620,7 +620,7 @@ func GetConnectionsFromConfig() ([]string, error) { localConfig := filepath.Join(home, ".ssh", "config") systemConfig := filepath.Join("/etc", "ssh", "config") sshConfigFiles := []string{localConfig, systemConfig} - ssh_config.ReloadConfigs() + remote.WaveSshConfigUserSettings().ReloadConfigs() return resolveSshConfigPatterns(sshConfigFiles) } diff --git a/pkg/remote/connutil.go b/pkg/remote/connutil.go index 89a5d827a..07dbab920 100644 --- a/pkg/remote/connutil.go +++ b/pkg/remote/connutil.go @@ -16,7 +16,6 @@ import ( "strconv" "strings" - "github.com/kevinburke/ssh_config" "golang.org/x/crypto/ssh" ) @@ -339,14 +338,14 @@ func IsPowershell(shellPath string) bool { } func NormalizeConfigPattern(pattern string) string { - userName, err := ssh_config.GetStrict(pattern, "User") + userName, err := WaveSshConfigUserSettings().GetStrict(pattern, "User") if err != nil { localUser, err := user.Current() if err == nil { userName = localUser.Username } } - port, err := ssh_config.GetStrict(pattern, "Port") + port, err := WaveSshConfigUserSettings().GetStrict(pattern, "Port") if err != nil { port = "22" } diff --git a/pkg/remote/sshclient.go b/pkg/remote/sshclient.go index 13893784e..69fe5cb10 100644 --- a/pkg/remote/sshclient.go +++ b/pkg/remote/sshclient.go @@ -19,6 +19,7 @@ import ( "path/filepath" "strconv" "strings" + "sync" "time" "github.com/kevinburke/ssh_config" @@ -34,6 +35,17 @@ import ( const SshProxyJumpMaxDepth = 10 +var waveSshConfigUserSettingsInternal *ssh_config.UserSettings +var configUserSettingsOnce = &sync.Once{} + +func WaveSshConfigUserSettings() *ssh_config.UserSettings { + configUserSettingsOnce.Do(func() { + waveSshConfigUserSettingsInternal = ssh_config.DefaultUserSettings + waveSshConfigUserSettingsInternal.IgnoreMatchDirective = true + }) + return waveSshConfigUserSettingsInternal +} + type UserInputCancelError struct { Err error } @@ -724,54 +736,54 @@ func combineSshKeywords(opts *SSHOpts, configKeywords *SshKeywords) (*SshKeyword // but `var != "no"` will default to true // when given unexpected strings func findSshConfigKeywords(hostPattern string) (*SshKeywords, error) { - ssh_config.ReloadConfigs() + WaveSshConfigUserSettings().ReloadConfigs() sshKeywords := &SshKeywords{} var err error - userRaw, err := ssh_config.GetStrict(hostPattern, "User") + userRaw, err := WaveSshConfigUserSettings().GetStrict(hostPattern, "User") if err != nil { return nil, err } sshKeywords.User = trimquotes.TryTrimQuotes(userRaw) - hostNameRaw, err := ssh_config.GetStrict(hostPattern, "HostName") + hostNameRaw, err := WaveSshConfigUserSettings().GetStrict(hostPattern, "HostName") if err != nil { return nil, err } sshKeywords.HostName = trimquotes.TryTrimQuotes(hostNameRaw) - portRaw, err := ssh_config.GetStrict(hostPattern, "Port") + portRaw, err := WaveSshConfigUserSettings().GetStrict(hostPattern, "Port") if err != nil { return nil, err } sshKeywords.Port = trimquotes.TryTrimQuotes(portRaw) - identityFileRaw := ssh_config.GetAll(hostPattern, "IdentityFile") + identityFileRaw := WaveSshConfigUserSettings().GetAll(hostPattern, "IdentityFile") for i := 0; i < len(identityFileRaw); i++ { identityFileRaw[i] = trimquotes.TryTrimQuotes(identityFileRaw[i]) } sshKeywords.IdentityFile = identityFileRaw - batchModeRaw, err := ssh_config.GetStrict(hostPattern, "BatchMode") + batchModeRaw, err := WaveSshConfigUserSettings().GetStrict(hostPattern, "BatchMode") if err != nil { return nil, err } sshKeywords.BatchMode = (strings.ToLower(trimquotes.TryTrimQuotes(batchModeRaw)) == "yes") // we currently do not support host-bound or unbound but will use yes when they are selected - pubkeyAuthenticationRaw, err := ssh_config.GetStrict(hostPattern, "PubkeyAuthentication") + pubkeyAuthenticationRaw, err := WaveSshConfigUserSettings().GetStrict(hostPattern, "PubkeyAuthentication") if err != nil { return nil, err } sshKeywords.PubkeyAuthentication = (strings.ToLower(trimquotes.TryTrimQuotes(pubkeyAuthenticationRaw)) != "no") - passwordAuthenticationRaw, err := ssh_config.GetStrict(hostPattern, "PasswordAuthentication") + passwordAuthenticationRaw, err := WaveSshConfigUserSettings().GetStrict(hostPattern, "PasswordAuthentication") if err != nil { return nil, err } sshKeywords.PasswordAuthentication = (strings.ToLower(trimquotes.TryTrimQuotes(passwordAuthenticationRaw)) != "no") - kbdInteractiveAuthenticationRaw, err := ssh_config.GetStrict(hostPattern, "KbdInteractiveAuthentication") + kbdInteractiveAuthenticationRaw, err := WaveSshConfigUserSettings().GetStrict(hostPattern, "KbdInteractiveAuthentication") if err != nil { return nil, err } @@ -779,18 +791,18 @@ func findSshConfigKeywords(hostPattern string) (*SshKeywords, error) { // these are parsed as a single string and must be separated // these are case sensitive in openssh so they are here too - preferredAuthenticationsRaw, err := ssh_config.GetStrict(hostPattern, "PreferredAuthentications") + preferredAuthenticationsRaw, err := WaveSshConfigUserSettings().GetStrict(hostPattern, "PreferredAuthentications") if err != nil { return nil, err } sshKeywords.PreferredAuthentications = strings.Split(trimquotes.TryTrimQuotes(preferredAuthenticationsRaw), ",") - addKeysToAgentRaw, err := ssh_config.GetStrict(hostPattern, "AddKeysToAgent") + addKeysToAgentRaw, err := WaveSshConfigUserSettings().GetStrict(hostPattern, "AddKeysToAgent") if err != nil { return nil, err } sshKeywords.AddKeysToAgent = (strings.ToLower(trimquotes.TryTrimQuotes(addKeysToAgentRaw)) == "yes") - identityAgentRaw, err := ssh_config.GetStrict(hostPattern, "IdentityAgent") + identityAgentRaw, err := WaveSshConfigUserSettings().GetStrict(hostPattern, "IdentityAgent") if err != nil { return nil, err } @@ -815,7 +827,7 @@ func findSshConfigKeywords(hostPattern string) (*SshKeywords, error) { sshKeywords.IdentityAgent = agentPath } - proxyJumpRaw, err := ssh_config.GetStrict(hostPattern, "ProxyJump") + proxyJumpRaw, err := WaveSshConfigUserSettings().GetStrict(hostPattern, "ProxyJump") if err != nil { return nil, err } @@ -827,9 +839,9 @@ func findSshConfigKeywords(hostPattern string) (*SshKeywords, error) { } sshKeywords.ProxyJump = append(sshKeywords.ProxyJump, proxyJumpName) } - rawUserKnownHostsFile, _ := ssh_config.GetStrict(hostPattern, "UserKnownHostsFile") + rawUserKnownHostsFile, _ := WaveSshConfigUserSettings().GetStrict(hostPattern, "UserKnownHostsFile") sshKeywords.UserKnownHostsFile = strings.Fields(rawUserKnownHostsFile) // TODO - smarter splitting escaped spaces and quotes - rawGlobalKnownHostsFile, _ := ssh_config.GetStrict(hostPattern, "GlobalKnownHostsFile") + rawGlobalKnownHostsFile, _ := WaveSshConfigUserSettings().GetStrict(hostPattern, "GlobalKnownHostsFile") sshKeywords.GlobalKnownHostsFile = strings.Fields(rawGlobalKnownHostsFile) // TODO - smarter splitting escaped spaces and quotes return sshKeywords, nil