unpack tar files copied via sftp subsystem, too (not just older scp)
For compatibility with OpenSSH ≥ 9
This commit is contained in:
parent
7dbbe9b4b3
commit
48c5124500
64
scp.go
64
scp.go
@ -66,36 +66,9 @@ func scpSink(channel ssh.Channel, req *ssh.Request, cmdline []string) error {
|
||||
|
||||
// Retrieve file contents
|
||||
var cw countingWriter
|
||||
tr := tar.NewReader(io.TeeReader(channel, &cw))
|
||||
for {
|
||||
h, err := tr.Next()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Printf("extracting %q", h.Name)
|
||||
if err := os.MkdirAll(filepath.Dir(h.Name), 0700); err != nil {
|
||||
return err
|
||||
}
|
||||
if strings.HasSuffix(h.Name, "/") {
|
||||
continue // directory, don’t try to OpenFile() it
|
||||
}
|
||||
mode := h.FileInfo().Mode() & os.ModePerm
|
||||
out, err := renameio.NewPendingFile(h.Name, renameio.WithStaticPermissions(mode))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := io.Copy(out, tr); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := out.CloseAtomicallyReplace(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := unpackTar(io.TeeReader(channel, &cw)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if rest := size - int64(cw); rest > 0 {
|
||||
buf := make([]byte, rest)
|
||||
if _, err := channel.Read(buf); err != nil {
|
||||
@ -125,3 +98,36 @@ func scpSink(channel ssh.Channel, req *ssh.Request, cmdline []string) error {
|
||||
req.Reply(true, nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
func unpackTar(r io.Reader) error {
|
||||
tr := tar.NewReader(r)
|
||||
for {
|
||||
h, err := tr.Next()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Printf("extracting %q", h.Name)
|
||||
if err := os.MkdirAll(filepath.Dir(h.Name), 0700); err != nil {
|
||||
return err
|
||||
}
|
||||
if strings.HasSuffix(h.Name, "/") {
|
||||
continue // directory, don’t try to OpenFile() it
|
||||
}
|
||||
mode := h.FileInfo().Mode() & os.ModePerm
|
||||
out, err := renameio.NewPendingFile(h.Name, renameio.WithStaticPermissions(mode))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := io.Copy(out, tr); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := out.CloseAtomicallyReplace(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
29
ssh.go
29
ssh.go
@ -292,9 +292,34 @@ func (s *session) request(ctx context.Context, req *ssh.Request) error {
|
||||
}
|
||||
}
|
||||
|
||||
// Special case for breakglass usage: unpack all .tar files that were
|
||||
// transferred into $PWD (which is a /tmp/breakglass… temporary
|
||||
// directory), so that the binaries included in the tar file can be used
|
||||
// for debugging.
|
||||
dirents, err := os.ReadDir(".")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, dirent := range dirents {
|
||||
if !strings.HasSuffix(dirent.Name(), ".tar") {
|
||||
continue
|
||||
}
|
||||
f, err := os.Open(dirent.Name())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
if err := unpackTar(f); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// See https://tools.ietf.org/html/rfc4254#section-6.10
|
||||
_, err = s.channel.SendRequest("exit-status", false /* wantReply */, ssh.Marshal(exitStatus{exitCode}))
|
||||
return err
|
||||
if _, err := s.channel.SendRequest("exit-status", false /* wantReply */, ssh.Marshal(exitStatus{exitCode})); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
case "shell":
|
||||
req.Payload = []byte("\x00\x00\x00\x02sh")
|
||||
|
Loading…
x
Reference in New Issue
Block a user