2

I'm trying to create a true interactive remote shell using Python. When I say true, I mean I don't want to just execute a single command and send the results- I have that working already. I also don't want to abstract executing single commands by having the server interpret directory changes or what not.

I am trying to have a client start an interactive /bin/bash and have the server send commands which are then executed by the same persistent shell. For instance, so if I run cd /foo/bar then pwd would return /foo/bar because I would be interacting with the same bash shell.

Here's some slimmed down example code that currently only will do single command execution...

# client.py
import socket
import subprocess

s = socket.socket()
s.connect(('localhost', 1337))

while True:
    cmd = s.recv(1024)

    # single command execution currently (not interactive shell)
    results = subprocess.Popen(cmd, shell=True,
              stdout=subprocess.PIPE, stderr=subprocess.PIPE,
              stdin=subprocess.PIPE)
    results = results.stdout.read() + results.stderr.read()

    s.sendall(results)

# server.py
import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('localhost', 1337))
s.listen(5)

conn, _ = s.accept()

while True:
    cmd = raw_input('> ').rstrip()
    conn.send(cmd)

    results = conn.recv(4096)
    print results

I've tried many solutions none of which have worked. The subprocess module had a communication method, but it kills the shell after a single command. I'd really like to be able to accomplish this with stdlib, but I've looked at the pexpect module after reading this thread. However, I can't get that to work either? It also doesn't look like it's primary use case is for creating an interactive shell, but rather catching specific command line output for interaction. I can't even get single command execution working with pexpect...

import pexpect, sys
proc = pexpect.spawn('/bin/bash')
proc.logfile = sys.stdout
proc.expect('$ ')
proc.sendline('pwd\n')

If anyone can help it would be appreciated, I feel like there could be a way to multi-thread and spawn off a /bin/bash -i with subprocess and then some how write to stdin and read from stdout? Thanks in advance, and sorry for the length.

Community
  • 1
  • 1
vesche
  • 1,842
  • 1
  • 13
  • 19

1 Answers1

3

Try this code:

# client.py
import socket
import subprocess

s = socket.socket()
s.connect(('localhost', 1337))

process = subprocess.Popen(['/bin/bash', '-i'],
              stdout=s.makefile('wb'), stderr=subprocess.STDOUT,
              stdin=s.makefile('rb'))
process.wait()
# server.py
import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('localhost', 1337))
s.listen(5)

conn, _ = s.accept()

fp = conn.makefile('wb')

proc1 = subprocess.Popen('cat', stdin=conn.makefile('rb'))
while True:
    fp.write(sys.stdin.read(4096))
proc1.wait()

Arusekk
  • 827
  • 4
  • 22