diff --git a/lib/client/client.go b/lib/client/client.go index bdf6b05f55c3d..7810166d4fcb1 100644 --- a/lib/client/client.go +++ b/lib/client/client.go @@ -726,7 +726,18 @@ func (c *NodeClient) TransferFiles(ctx context.Context, cfg *sftp.Config) error ) defer span.End() - return trace.Wrap(cfg.TransferFiles(ctx, c.Client.Client)) + if err := cfg.TransferFiles(ctx, c.Client.Client); err != nil { + // TODO(tross): DELETE IN 19.0.0 - Older versions of Teleport would return + // a trace.BadParameter error when ~user path expansion was rejected, and + // reauthentication logic is attempted on BadParameter errors. + if trace.IsBadParameter(err) && strings.Contains(err.Error(), "expanding remote ~user paths is not supported") { + return trace.Wrap(&NonRetryableError{Err: err}) + } + + return trace.Wrap(err) + } + + return nil } type netDialer interface { diff --git a/lib/sshutils/sftp/sftp.go b/lib/sshutils/sftp/sftp.go index 77bd23f3cda5a..d8390ba0308d7 100644 --- a/lib/sshutils/sftp/sftp.go +++ b/lib/sshutils/sftp/sftp.go @@ -331,7 +331,7 @@ func (c *Config) expandPaths(srcIsRemote, dstIsRemote bool) (err error) { for i, srcPath := range c.srcPaths { c.srcPaths[i], err = expandPath(srcPath) if err != nil { - return trace.Wrap(err, "error expanding %q", srcPath) + return trace.Wrap(err) } } } @@ -339,13 +339,23 @@ func (c *Config) expandPaths(srcIsRemote, dstIsRemote bool) (err error) { if dstIsRemote { c.dstPath, err = expandPath(c.dstPath) if err != nil { - return trace.Wrap(err, "error expanding %q", c.dstPath) + return trace.Wrap(err) } } return nil } +// PathExpansionError is an [error] indicating that +// path expansion was rejected. +type PathExpansionError struct { + path string +} + +func (p PathExpansionError) Error() string { + return fmt.Sprintf("expanding remote ~user paths is not supported, specify an absolute path instead of %q", p.path) +} + func expandPath(pathStr string) (string, error) { pfxLen, ok := homeDirPrefixLen(pathStr) if !ok { @@ -360,7 +370,7 @@ func expandPath(pathStr string) (string, error) { return ".", nil } if pfxLen == 1 && len(pathStr) > 1 { - return "", trace.BadParameter("expanding remote ~user paths is not supported, specify an absolute path instead") + return "", trace.Wrap(PathExpansionError{path: pathStr}) } // if an SFTP path is not absolute, it is assumed to start at the user's diff --git a/lib/sshutils/sftp/sftp_test.go b/lib/sshutils/sftp/sftp_test.go index f43a2a956ef67..9c7e38e5e394d 100644 --- a/lib/sshutils/sftp/sftp_test.go +++ b/lib/sshutils/sftp/sftp_test.go @@ -34,7 +34,6 @@ import ( "time" "github.com/google/go-cmp/cmp" - "github.com/gravitational/trace" "github.com/stretchr/testify/require" "github.com/gravitational/teleport/lib/utils" @@ -585,7 +584,7 @@ func TestHomeDirExpansion(t *testing.T) { name: "~user path", path: "~user/foo", errCheck: func(t require.TestingT, err error, i ...interface{}) { - require.True(t, trace.IsBadParameter(err)) + require.ErrorIs(t, err, PathExpansionError{path: "~user/foo"}) }, }, }