|
|
@ -4,11 +4,13 @@ import (
|
|
|
|
"fmt"
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"io"
|
|
|
|
"net"
|
|
|
|
"net"
|
|
|
|
|
|
|
|
"os"
|
|
|
|
"os/exec"
|
|
|
|
"os/exec"
|
|
|
|
"runtime"
|
|
|
|
"runtime"
|
|
|
|
"syscall"
|
|
|
|
"syscall"
|
|
|
|
"time"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
"github.com/creack/pty"
|
|
|
|
"github.com/fangdingjun/go-log"
|
|
|
|
"github.com/fangdingjun/go-log"
|
|
|
|
"github.com/pkg/sftp"
|
|
|
|
"github.com/pkg/sftp"
|
|
|
|
"golang.org/x/crypto/ssh"
|
|
|
|
"golang.org/x/crypto/ssh"
|
|
|
@ -146,6 +148,22 @@ type exitStatus struct {
|
|
|
|
Status uint32
|
|
|
|
Status uint32
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
type ptyReq struct {
|
|
|
|
|
|
|
|
Term string
|
|
|
|
|
|
|
|
Columns uint32
|
|
|
|
|
|
|
|
Rows uint32
|
|
|
|
|
|
|
|
Width uint32
|
|
|
|
|
|
|
|
Height uint32
|
|
|
|
|
|
|
|
Mode string
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
type windowChange struct {
|
|
|
|
|
|
|
|
Columns uint32
|
|
|
|
|
|
|
|
Rows uint32
|
|
|
|
|
|
|
|
Width uint32
|
|
|
|
|
|
|
|
Height uint32
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (sc *Server) handleSession(newch ssh.NewChannel) {
|
|
|
|
func (sc *Server) handleSession(newch ssh.NewChannel) {
|
|
|
|
ch, req, err := newch.Accept()
|
|
|
|
ch, req, err := newch.Accept()
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
@ -153,11 +171,14 @@ func (sc *Server) handleSession(newch ssh.NewChannel) {
|
|
|
|
return
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var _cmd args
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ret := false
|
|
|
|
ret := false
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var _cmd args
|
|
|
|
var cmd *exec.Cmd
|
|
|
|
var cmd *exec.Cmd
|
|
|
|
var env []string
|
|
|
|
var env []string
|
|
|
|
|
|
|
|
var _ptyReq ptyReq
|
|
|
|
|
|
|
|
var _windowChange windowChange
|
|
|
|
|
|
|
|
var _pty, _tty *os.File
|
|
|
|
|
|
|
|
|
|
|
|
for r := range req {
|
|
|
|
for r := range req {
|
|
|
|
switch r.Type {
|
|
|
|
switch r.Type {
|
|
|
@ -168,6 +189,7 @@ func (sc *Server) handleSession(newch ssh.NewChannel) {
|
|
|
|
log.Debugf("handle sftp request")
|
|
|
|
log.Debugf("handle sftp request")
|
|
|
|
go serveSFTP(ch)
|
|
|
|
go serveSFTP(ch)
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
|
|
|
|
ret = false
|
|
|
|
log.Debugln("subsystem", _cmd.Arg, "not support")
|
|
|
|
log.Debugln("subsystem", _cmd.Arg, "not support")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
@ -182,7 +204,7 @@ func (sc *Server) handleSession(newch ssh.NewChannel) {
|
|
|
|
cmd = exec.Command("bash", "-l")
|
|
|
|
cmd = exec.Command("bash", "-l")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
cmd.Env = env
|
|
|
|
cmd.Env = env
|
|
|
|
go handleShell(cmd, ch)
|
|
|
|
go handleShell(cmd, ch, _pty, _tty)
|
|
|
|
case "signal":
|
|
|
|
case "signal":
|
|
|
|
log.Debugln("got signal")
|
|
|
|
log.Debugln("got signal")
|
|
|
|
ret = true
|
|
|
|
ret = true
|
|
|
@ -204,6 +226,35 @@ func (sc *Server) handleSession(newch ssh.NewChannel) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case "pty-req":
|
|
|
|
case "pty-req":
|
|
|
|
ret = true
|
|
|
|
ret = true
|
|
|
|
|
|
|
|
err = ssh.Unmarshal(r.Payload, &_ptyReq)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
log.Errorln(err)
|
|
|
|
|
|
|
|
ret = false
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Debugf("pty req %+v", _ptyReq)
|
|
|
|
|
|
|
|
if err == nil && (runtime.GOOS == "unix" || runtime.GOOS == "linux") {
|
|
|
|
|
|
|
|
_pty, _tty, err = pty.Open()
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
log.Errorln(err)
|
|
|
|
|
|
|
|
ret = false
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
env = append(env, fmt.Sprintf("TERM=%s", _ptyReq.Term))
|
|
|
|
|
|
|
|
size, err := pty.GetsizeFull(_pty)
|
|
|
|
|
|
|
|
if err == nil {
|
|
|
|
|
|
|
|
log.Debugf("term size %+v", size)
|
|
|
|
|
|
|
|
size.Rows = uint16(_ptyReq.Rows)
|
|
|
|
|
|
|
|
size.Cols = uint16(_ptyReq.Columns)
|
|
|
|
|
|
|
|
if err = pty.Setsize(_pty, size); err != nil {
|
|
|
|
|
|
|
|
log.Errorln(err)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if err = pty.Setsize(_tty, size); err != nil {
|
|
|
|
|
|
|
|
log.Errorln(err)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
log.Errorln(err)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
case "env":
|
|
|
|
case "env":
|
|
|
|
var arg envArgs
|
|
|
|
var arg envArgs
|
|
|
|
ret = true
|
|
|
|
ret = true
|
|
|
@ -216,6 +267,28 @@ func (sc *Server) handleSession(newch ssh.NewChannel) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case "window-change":
|
|
|
|
case "window-change":
|
|
|
|
ret = true
|
|
|
|
ret = true
|
|
|
|
|
|
|
|
err = ssh.Unmarshal(r.Payload, &_windowChange)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
ret = false
|
|
|
|
|
|
|
|
log.Errorln(err)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if err == nil && _pty != nil {
|
|
|
|
|
|
|
|
size, err := pty.GetsizeFull(_pty)
|
|
|
|
|
|
|
|
if err == nil {
|
|
|
|
|
|
|
|
log.Debugf("term size %+v", size)
|
|
|
|
|
|
|
|
size.Rows = uint16(_ptyReq.Rows)
|
|
|
|
|
|
|
|
size.Cols = uint16(_ptyReq.Columns)
|
|
|
|
|
|
|
|
if err = pty.Setsize(_pty, size); err != nil {
|
|
|
|
|
|
|
|
log.Errorln(err)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if err = pty.Setsize(_tty, size); err != nil {
|
|
|
|
|
|
|
|
log.Errorln(err)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
log.Errorln(err)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Debugf("window change %+v", _windowChange)
|
|
|
|
default:
|
|
|
|
default:
|
|
|
|
ret = false
|
|
|
|
ret = false
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -228,32 +301,36 @@ func (sc *Server) handleSession(newch ssh.NewChannel) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func handleShell(cmd *exec.Cmd, ch ssh.Channel) {
|
|
|
|
func handleShell(cmd *exec.Cmd, ch ssh.Channel, _pty, _tty *os.File) {
|
|
|
|
defer ch.Close()
|
|
|
|
defer func() {
|
|
|
|
|
|
|
|
ch.Close()
|
|
|
|
|
|
|
|
if _pty != nil {
|
|
|
|
|
|
|
|
_pty.Close()
|
|
|
|
|
|
|
|
_tty.Close()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
|
|
var _pty io.ReadWriteCloser
|
|
|
|
|
|
|
|
var err error
|
|
|
|
var err error
|
|
|
|
|
|
|
|
|
|
|
|
log.Infoln("start shell")
|
|
|
|
log.Infoln("start shell")
|
|
|
|
|
|
|
|
|
|
|
|
//_pty, err = pty.Start(cmd)
|
|
|
|
if _tty != nil {
|
|
|
|
if runtime.GOOS == "unix" || runtime.GOOS == "linux" {
|
|
|
|
cmd.Stderr = _tty
|
|
|
|
_pty, err = startPty(cmd)
|
|
|
|
cmd.Stdout = _tty
|
|
|
|
if err != nil {
|
|
|
|
cmd.Stdin = _tty
|
|
|
|
log.Debugln("start pty", err)
|
|
|
|
if cmd.SysProcAttr == nil {
|
|
|
|
ch.SendRequest("exit-status", false,
|
|
|
|
cmd.SysProcAttr = &syscall.SysProcAttr{}
|
|
|
|
ssh.Marshal(exitStatus{Status: 127}))
|
|
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cmd.SysProcAttr.Setsid = true
|
|
|
|
|
|
|
|
cmd.SysProcAttr.Setctty = true
|
|
|
|
|
|
|
|
cmd.SysProcAttr.Ctty = int(_tty.Fd())
|
|
|
|
|
|
|
|
|
|
|
|
if runtime.GOOS == "unix" || runtime.GOOS == "linux" {
|
|
|
|
|
|
|
|
defer _pty.Close()
|
|
|
|
|
|
|
|
go io.Copy(ch, _pty)
|
|
|
|
go io.Copy(ch, _pty)
|
|
|
|
go io.Copy(_pty, ch)
|
|
|
|
go io.Copy(_pty, ch)
|
|
|
|
} else { // windows
|
|
|
|
} else {
|
|
|
|
cmd.Stderr = ch
|
|
|
|
cmd.Stderr = ch
|
|
|
|
cmd.Stdout = ch
|
|
|
|
cmd.Stdout = ch
|
|
|
|
|
|
|
|
|
|
|
|
in, err := cmd.StdinPipe()
|
|
|
|
in, err := cmd.StdinPipe()
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
ch.SendRequest("exit-status", false,
|
|
|
|
ch.SendRequest("exit-status", false,
|
|
|
@ -263,14 +340,16 @@ func handleShell(cmd *exec.Cmd, ch ssh.Channel) {
|
|
|
|
go func() {
|
|
|
|
go func() {
|
|
|
|
defer in.Close()
|
|
|
|
defer in.Close()
|
|
|
|
io.Copy(in, ch)
|
|
|
|
io.Copy(in, ch)
|
|
|
|
|
|
|
|
|
|
|
|
}()
|
|
|
|
}()
|
|
|
|
|
|
|
|
}
|
|
|
|
if err := cmd.Start(); err != nil {
|
|
|
|
if err := cmd.Start(); err != nil {
|
|
|
|
log.Debugln("start command ", err)
|
|
|
|
log.Debugln("start command ", err)
|
|
|
|
ch.SendRequest("exit-status", false,
|
|
|
|
ch.SendRequest("exit-status", false,
|
|
|
|
ssh.Marshal(exitStatus{Status: 126}))
|
|
|
|
ssh.Marshal(exitStatus{Status: 126}))
|
|
|
|
return
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
code := 0
|
|
|
|
code := 0
|
|
|
|
if err = cmd.Wait(); err != nil {
|
|
|
|
if err = cmd.Wait(); err != nil {
|
|
|
|
log.Debugln(err)
|
|
|
|
log.Debugln(err)
|
|
|
|