From 678c2071f4d2d2b63d9af1c3e405db776e7edb60 Mon Sep 17 00:00:00 2001 From: ivcosla Date: Sun, 11 Aug 2019 23:53:33 +0200 Subject: [PATCH] added rpc call for run function --- pkg/therealssh/client.go | 27 +++++++++++++++++ pkg/therealssh/pty_test.go | 61 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) diff --git a/pkg/therealssh/client.go b/pkg/therealssh/client.go index 830ed9bec..31d2a659c 100644 --- a/pkg/therealssh/client.go +++ b/pkg/therealssh/client.go @@ -212,6 +212,33 @@ func (rpc *RPCClient) Exec(args *ExecArgs, socketPath *string) error { return nil } +// Run defines new remote shell-less execution RPC request. +func (rpc *RPCClient) Run(args *ExecArgs, socketPath *string) error { + sshCh := rpc.c.chans.getChannel(args.ChannelID) + if sshCh == nil { + return errors.New("unknown channel") + } + + debug("requesting shell-less process execution") + if _, err := sshCh.Request(RequestExecWithoutShell, args.ToBinary()); err != nil { + return fmt.Errorf("run command request failure: %s", err) + } + + waitCh := make(chan bool) + go func() { + debug("starting socket listener") + waitCh <- true + if err := sshCh.ServeSocket(); err != nil { + log.Error("Session failure:", err) + } + }() + + *socketPath = sshCh.SocketPath() + + <-waitCh + return nil +} + // WindowChange defines window size change RPC request. func (rpc *RPCClient) WindowChange(args *WindowChangeArgs, _ *int) error { sshCh := rpc.c.chans.getChannel(args.ChannelID) diff --git a/pkg/therealssh/pty_test.go b/pkg/therealssh/pty_test.go index 86ce10cd4..8e3f25fba 100644 --- a/pkg/therealssh/pty_test.go +++ b/pkg/therealssh/pty_test.go @@ -3,6 +3,8 @@ package therealssh import ( "fmt" "net" + "net/http" + "net/rpc" "os/user" "testing" @@ -54,6 +56,65 @@ func TestRunInPTY(t *testing.T) { require.Contains(t, string(b), "pty_test.go") } +func TestRunRPC(t *testing.T) { + dialConn, acceptConn := net.Pipe() + pd := PipeDialer{PipeWithRoutingAddr{dialConn}, acceptConn} + rpcC, client, err := NewClient(":9999", pd) + require.NoError(t, err) + defer func() { + require.NoError(t, client.Close()) + }() + + server := NewServer(MockAuthorizer{}) + go func() { + err := server.Serve(PipeWithRoutingAddr{acceptConn}) + fmt.Println("server.Serve finished with err: ", err) + require.NoError(t, err) + }() + + go func() { + err = http.Serve(rpcC, nil) + require.NoError(t, err) + }() + + rpcD, err := rpc.DialHTTP("tcp", ":9999") + require.NoError(t, err) + + cuser, err := user.Current() + require.NoError(t, err) + + ptyArgs := &RequestPTYArgs{ + Username: cuser.Username, + RemotePK: cipher.PubKey{}, + Size: &pty.Winsize{ + Rows: 100, + Cols: 100, + X: 100, + Y: 100, + }, + } + var channel uint32 + err = rpcD.Call("RPCClient.RequestPTY", ptyArgs, &channel) + require.NoError(t, err) + + var socketPath string + execArgs := &ExecArgs{ + ChannelID: channel, + CommandWithArgs: []string{"ls"}, + } + + err = rpcD.Call("RPCClient.Run", execArgs, &socketPath) + require.NoError(t, err) + + conn, err := net.DialUnix("unix", nil, &net.UnixAddr{Name: socketPath, Net: "unix"}) + require.NoError(t, err) + + b := make([]byte, 6024) + _, err = conn.Read(b) + require.NoError(t, err) + require.Contains(t, string(b), "pty_test.go") +} + type MockAuthorizer struct{} func (MockAuthorizer) Authorize(pk cipher.PubKey) error {