diff --git a/pkg/mpio/mpio.go b/pkg/mpio/mpio.go index 017ce6de..f16a411c 100644 --- a/pkg/mpio/mpio.go +++ b/pkg/mpio/mpio.go @@ -12,9 +12,7 @@ import ( "io" "os" "sync" - "syscall" - "github.com/creack/pty" "github.com/scripthaus-dev/mshell/pkg/base" "github.com/scripthaus-dev/mshell/pkg/packet" ) @@ -31,8 +29,6 @@ type Multiplexer struct { FdWriters map[int]*FdWriter // synchronized RunData map[int]*FdReader // synchronized CloseAfterStart []*os.File // synchronized - PtyFd *os.File - CmdProc *os.Process Sender *packet.PacketSender Input *packet.PacketParser @@ -55,12 +51,6 @@ func MakeMultiplexer(ck base.CommandKey, upr packet.UnknownPacketReporter) *Mult } } -func (m *Multiplexer) SetPtyFd(ptyFd *os.File) { - m.Lock.Lock() - defer m.Lock.Unlock() - m.PtyFd = ptyFd -} - func (m *Multiplexer) Close() { m.Lock.Lock() defer m.Lock.Unlock() @@ -230,36 +220,11 @@ func (m *Multiplexer) runPacketInputLoop() *packet.CmdDonePacketType { donePacket := pk.(*packet.CmdDonePacketType) return donePacket } - if pk.GetType() == packet.SpecialInputPacketStr { - inputPacket := pk.(*packet.SpecialInputPacketType) - m.processSpecialInputPacket(inputPacket) - } m.UPR.UnknownPacket(pk) } return nil } -func (m *Multiplexer) processSpecialInputPacket(pk *packet.SpecialInputPacketType) { - m.Lock.Lock() - ptyFd := m.PtyFd - cmdProc := m.CmdProc - m.Lock.Unlock() - if ptyFd == nil { - // no pty, maybe send a message back to server, but the server always starts with a pty, so this shouldn't be an issue - return - } - if pk.WinSize != nil { - winSize := &pty.Winsize{ - //Rows: base.BoundInt(pk.WinSize.Rows, shexec.MinTermRows, shexec.MaxTermRows), - //Cols: base.BoundInt(pk.Winsize.Cols, shexec.MinTermCols, shexec.MaxTermCols), - } - pty.Setsize(ptyFd, winSize) - if cmdProc != nil { - cmdProc.Signal(syscall.SIGWINCH) - } - } -} - func (m *Multiplexer) processDataPacket(dataPacket *packet.DataPacketType) error { realData, err := base64.StdEncoding.DecodeString(dataPacket.Data64) if err != nil { diff --git a/pkg/packet/packet.go b/pkg/packet/packet.go index 3ec863b8..2d13ad5e 100644 --- a/pkg/packet/packet.go +++ b/pkg/packet/packet.go @@ -248,7 +248,7 @@ type WinSize struct { type SpecialInputPacketType struct { Type string `json:"type"` CK base.CommandKey `json:"ck"` - SigNum int `json:"signum,omitempty"` + SigName string `json:"signame,omitempty"` // passed to unix.SignalNum (needs 'SIG' prefix, e.g. "SIGTERM") WinSize *WinSize `json:"winsize,omitempty"` } diff --git a/pkg/shexec/shexec.go b/pkg/shexec/shexec.go index 378dafa9..09ca45ec 100644 --- a/pkg/shexec/shexec.go +++ b/pkg/shexec/shexec.go @@ -17,7 +17,6 @@ import ( "os/signal" "os/user" "strings" - "sync" "syscall" "time" @@ -70,7 +69,6 @@ const RunSudoCommandFmt = `sudo -n -C %d bash /dev/fd/%d` const RunSudoPasswordCommandFmt = `cat /dev/fd/%d | sudo -k -S -C %d bash -c "echo '[from-mshell]'; exec %d>&-; bash /dev/fd/%d < /dev/fd/%d"` type ShExecType struct { - Lock *sync.Mutex StartTs time.Time CK base.CommandKey FileNames *base.CommandFileNames @@ -81,6 +79,7 @@ type ShExecType struct { Detached bool DetachedOutput *packet.PacketSender RunnerOutFd *os.File + MsgSender *packet.PacketSender // where to send out-of-band messages back to calling proceess } type StdContext struct{} @@ -118,9 +117,50 @@ type FdContext interface { GetReader(fdNum int) io.ReadCloser } +type ShExecUPR struct { + ShExec *ShExecType + UPR packet.UnknownPacketReporter +} + +func (s *ShExecType) processSpecialInputPacket(pk *packet.SpecialInputPacketType) error { + if pk.WinSize != nil { + if s.CmdPty == nil { + return fmt.Errorf("cannot change winsize, cmd was not started with a pty") + } + winSize := &pty.Winsize{ + Rows: uint16(base.BoundInt(pk.WinSize.Rows, MinTermRows, MaxTermRows)), + Cols: uint16(base.BoundInt(pk.WinSize.Cols, MinTermCols, MaxTermCols)), + } + pty.Setsize(s.CmdPty, winSize) + s.Cmd.Process.Signal(syscall.SIGWINCH) + } + if pk.SigName != "" { + sigNum := unix.SignalNum(pk.SigName) + if sigNum == 0 { + return fmt.Errorf("error signal %q not found, cannot send", pk.SigName) + } + } + return nil +} + +func (s ShExecUPR) UnknownPacket(pk packet.PacketType) { + if pk.GetType() == packet.SpecialInputPacketStr { + inputPacket := pk.(*packet.SpecialInputPacketType) + err := s.ShExec.processSpecialInputPacket(inputPacket) + if err != nil && s.ShExec.MsgSender != nil { + msg := packet.MakeMessagePacket(err.Error()) + msg.CK = s.ShExec.CK + s.ShExec.MsgSender.SendPacket(msg) + } + return + } + if s.UPR != nil { + s.UPR.UnknownPacket(pk) + } +} + func MakeShExec(ck base.CommandKey, upr packet.UnknownPacketReporter) *ShExecType { return &ShExecType{ - Lock: &sync.Mutex{}, StartTs: time.Now(), CK: ck, Multiplexer: mpio.MakeMultiplexer(ck, upr), @@ -835,11 +875,13 @@ func getTermType(pk *packet.RunPacketType) string { } func RunCommandSimple(pk *packet.RunPacketType, sender *packet.PacketSender, fromServer bool) (*ShExecType, error) { - var upr packet.UnknownPacketReporter + cmd := MakeShExec(pk.CK, nil) if fromServer { - upr = packet.MessageUPR{CK: pk.CK, Sender: sender} + msgUpr := packet.MessageUPR{CK: pk.CK, Sender: sender} + upr := ShExecUPR{ShExec: cmd, UPR: msgUpr} + cmd.Multiplexer.UPR = upr + cmd.MsgSender = sender } - cmd := MakeShExec(pk.CK, upr) if pk.UsePty { cmd.Cmd = exec.Command("bash", "-i", "-c", pk.Command) } else { @@ -869,7 +911,6 @@ func RunCommandSimple(pk *packet.RunPacketType, sender *packet.PacketSender, fro cmdTty.Close() }() cmd.CmdPty = cmdPty - cmd.Multiplexer.SetPtyFd(cmdPty) UpdateCmdEnv(cmd.Cmd, map[string]string{"TERM": getTermType(pk)}) } if cmdTty != nil { @@ -1051,7 +1092,6 @@ func RunCommandDetached(pk *packet.RunPacketType, sender *packet.PacketSender) ( cmd.CmdPty = cmdPty cmd.Detached = true cmd.MaxPtySize = DefaultMaxPtySize - cmd.Multiplexer.SetPtyFd(cmdPty) if pk.TermOpts != nil && pk.TermOpts.MaxPtySize > 0 { cmd.MaxPtySize = base.BoundInt64(pk.TermOpts.MaxPtySize, MinMaxPtySize, MaxMaxPtySize) }