implemented working externAgent wrapper
[progcomp10.git] / src / link / pexpect / examples / bd_serv.py
diff --git a/src/link/pexpect/examples/bd_serv.py b/src/link/pexpect/examples/bd_serv.py
new file mode 100755 (executable)
index 0000000..b7def9e
--- /dev/null
@@ -0,0 +1,316 @@
+#!/usr/bin/env python
+
+"""Back door shell server
+
+This exposes an shell terminal on a socket.
+
+    --hostname : sets the remote host name to open an ssh connection to.
+    --username : sets the user name to login with
+    --password : (optional) sets the password to login with
+    --port     : set the local port for the server to listen on
+    --watch    : show the virtual screen after each client request
+"""
+
+# Having the password on the command line is not a good idea, but
+# then this entire project is probably not the most security concious thing
+# I've ever built. This should be considered an experimental tool -- at best.
+import pxssh, pexpect, ANSI
+import time, sys, os, getopt, getpass, traceback, threading, socket
+
+def exit_with_usage(exit_code=1):
+
+    print globals()['__doc__']
+    os._exit(exit_code)
+
+class roller (threading.Thread):
+
+    """This runs a function in a loop in a thread."""
+
+    def __init__(self, interval, function, args=[], kwargs={}):
+
+        """The interval parameter defines time between each call to the function.
+        """
+
+        threading.Thread.__init__(self)
+        self.interval = interval
+        self.function = function
+        self.args = args
+        self.kwargs = kwargs
+        self.finished = threading.Event()
+
+    def cancel(self):
+
+        """Stop the roller."""
+
+        self.finished.set()
+
+    def run(self):
+
+        while not self.finished.isSet():
+            # self.finished.wait(self.interval)
+            self.function(*self.args, **self.kwargs)
+
+def endless_poll (child, prompt, screen, refresh_timeout=0.1):
+
+    """This keeps the screen updated with the output of the child. This runs in
+    a separate thread. See roller(). """
+
+    #child.logfile_read = screen
+    try:
+        s = child.read_nonblocking(4000, 0.1)
+        screen.write(s)
+    except:
+        pass
+    #while True:
+    #    #child.prompt (timeout=refresh_timeout)
+    #    try:
+    #        #child.read_nonblocking(1,timeout=refresh_timeout)
+    #        child.read_nonblocking(4000, 0.1)
+    #    except:
+    #        pass
+
+def daemonize (stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):
+
+    '''This forks the current process into a daemon. Almost none of this is
+    necessary (or advisable) if your daemon is being started by inetd. In that
+    case, stdin, stdout and stderr are all set up for you to refer to the
+    network connection, and the fork()s and session manipulation should not be
+    done (to avoid confusing inetd). Only the chdir() and umask() steps remain
+    as useful. 
+
+    References:
+        UNIX Programming FAQ
+        1.7 How do I get my program to act like a daemon?
+        http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16
+
+        Advanced Programming in the Unix Environment
+        W. Richard Stevens, 1992, Addison-Wesley, ISBN 0-201-56317-7.
+
+    The stdin, stdout, and stderr arguments are file names that will be opened
+    and be used to replace the standard file descriptors in sys.stdin,
+    sys.stdout, and sys.stderr. These arguments are optional and default to
+    /dev/null. Note that stderr is opened unbuffered, so if it shares a file
+    with stdout then interleaved output may not appear in the order that you
+    expect. '''
+
+    # Do first fork.
+    try: 
+        pid = os.fork() 
+        if pid > 0:
+            sys.exit(0)   # Exit first parent.
+    except OSError, e: 
+        sys.stderr.write ("fork #1 failed: (%d) %s\n" % (e.errno, e.strerror) )
+        sys.exit(1)
+
+    # Decouple from parent environment.
+    os.chdir("/") 
+    os.umask(0) 
+    os.setsid() 
+
+    # Do second fork.
+    try: 
+        pid = os.fork() 
+        if pid > 0:
+            sys.exit(0)   # Exit second parent.
+    except OSError, e: 
+        sys.stderr.write ("fork #2 failed: (%d) %s\n" % (e.errno, e.strerror) )
+        sys.exit(1)
+
+    # Now I am a daemon!
+    
+    # Redirect standard file descriptors.
+    si = open(stdin, 'r')
+    so = open(stdout, 'a+')
+    se = open(stderr, 'a+', 0)
+    os.dup2(si.fileno(), sys.stdin.fileno())
+    os.dup2(so.fileno(), sys.stdout.fileno())
+    os.dup2(se.fileno(), sys.stderr.fileno())
+
+    # I now return as the daemon
+    return 0
+
+def add_cursor_blink (response, row, col):
+
+    i = (row-1) * 80 + col
+    return response[:i]+'<img src="http://www.noah.org/cursor.gif">'+response[i:]
+
+def main ():
+
+    try:
+        optlist, args = getopt.getopt(sys.argv[1:], 'h?d', ['help','h','?', 'hostname=', 'username=', 'password=', 'port=', 'watch'])
+    except Exception, e:
+        print str(e)
+        exit_with_usage()
+
+    command_line_options = dict(optlist)
+    options = dict(optlist)
+    # There are a million ways to cry for help. These are but a few of them.
+    if [elem for elem in command_line_options if elem in ['-h','--h','-?','--?','--help']]:
+        exit_with_usage(0)
+  
+    hostname = "127.0.0.1"
+    port = 1664
+    username = os.getenv('USER')
+    password = ""
+    daemon_mode = False
+    if '-d' in options:
+        daemon_mode = True
+    if '--watch' in options:
+        watch_mode = True
+    else:
+        watch_mode = False
+    if '--hostname' in options:
+        hostname = options['--hostname']
+    if '--port' in options:
+        port = int(options['--port'])
+    if '--username' in options:
+        username = options['--username']
+    print "Login for %s@%s:%s" % (username, hostname, port)
+    if '--password' in options:
+        password = options['--password']
+    else:
+        password = getpass.getpass('password: ')
+   
+    if daemon_mode: 
+        print "daemonizing server"
+        daemonize()
+        #daemonize('/dev/null','/tmp/daemon.log','/tmp/daemon.log')
+    
+    sys.stdout.write ('server started with pid %d\n' % os.getpid() )
+
+    virtual_screen = ANSI.ANSI (24,80) 
+    child = pxssh.pxssh()
+    child.login (hostname, username, password)
+    print 'created shell. command line prompt is', child.PROMPT
+    #child.sendline ('stty -echo')
+    #child.setecho(False)
+    virtual_screen.write (child.before)
+    virtual_screen.write (child.after)
+
+    if os.path.exists("/tmp/mysock"): os.remove("/tmp/mysock")
+    s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+    localhost = '127.0.0.1'
+    s.bind('/tmp/mysock')
+    os.chmod('/tmp/mysock',0777)
+    print 'Listen'
+    s.listen(1)
+    print 'Accept'
+    #s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+    #localhost = '127.0.0.1'
+    #s.bind((localhost, port))
+    #print 'Listen'
+    #s.listen(1)
+
+    r = roller (0.01, endless_poll, (child, child.PROMPT, virtual_screen))
+    r.start()
+    print "screen poll updater started in background thread"
+    sys.stdout.flush()
+
+    try:
+        while True:
+            conn, addr = s.accept()
+            print 'Connected by', addr
+            data = conn.recv(1024)
+            if data[0]!=':':
+                cmd = ':sendline'
+                arg = data.strip()
+            else:
+                request = data.split(' ', 1)
+                if len(request)>1:
+                    cmd = request[0].strip()
+                    arg = request[1].strip()
+                else:
+                    cmd = request[0].strip()
+            if cmd == ':exit':
+                r.cancel()
+                break
+            elif cmd == ':sendline':
+                child.sendline (arg)
+                #child.prompt(timeout=2)
+                time.sleep(0.2)
+                shell_window = str(virtual_screen)
+            elif cmd == ':send' or cmd==':xsend':
+                if cmd==':xsend':
+                    arg = arg.decode("hex")
+                child.send (arg)
+                time.sleep(0.2)
+                shell_window = str(virtual_screen)
+            elif cmd == ':cursor':
+                shell_window = '%x%x' % (virtual_screen.cur_r, virtual_screen.cur_c)
+            elif cmd == ':refresh':
+                shell_window = str(virtual_screen)
+
+            response = []
+            response.append (shell_window)
+            #response = add_cursor_blink (response, row, col)
+            sent = conn.send('\n'.join(response))
+            if watch_mode: print '\n'.join(response)
+            if sent < len (response):
+                print "Sent is too short. Some data was cut off."
+            conn.close()
+    finally:
+        r.cancel()
+        print "cleaning up socket"
+        s.close()
+        if os.path.exists("/tmp/mysock"): os.remove("/tmp/mysock")
+        print "done!"
+
+def pretty_box (rows, cols, s):
+
+    """This puts an ASCII text box around the given string, s.
+    """
+
+    top_bot = '+' + '-'*cols + '+\n'
+    return top_bot + '\n'.join(['|'+line+'|' for line in s.split('\n')]) + '\n' + top_bot
+    
+def error_response (msg):
+
+    response = []
+    response.append ("""All commands start with :
+:{REQUEST} {ARGUMENT}
+{REQUEST} may be one of the following:
+    :sendline: Run the ARGUMENT followed by a line feed.
+    :send    : send the characters in the ARGUMENT without a line feed.
+    :refresh : Use to catch up the screen with the shell if state gets out of sync.
+Example:
+    :sendline ls -l
+You may also leave off :command and it will be assumed.
+Example:
+    ls -l
+is equivalent to:
+    :sendline ls -l
+""")
+    response.append (msg)
+    return '\n'.join(response)
+
+def parse_host_connect_string (hcs):
+
+    """This parses a host connection string in the form
+    username:password@hostname:port. All fields are options expcet hostname. A
+    dictionary is returned with all four keys. Keys that were not included are
+    set to empty strings ''. Note that if your password has the '@' character
+    then you must backslash escape it. """
+
+    if '@' in hcs:
+        p = re.compile (r'(?P<username>[^@:]*)(:?)(?P<password>.*)(?!\\)@(?P<hostname>[^:]*):?(?P<port>[0-9]*)')
+    else:
+        p = re.compile (r'(?P<username>)(?P<password>)(?P<hostname>[^:]*):?(?P<port>[0-9]*)')
+    m = p.search (hcs)
+    d = m.groupdict()
+    d['password'] = d['password'].replace('\\@','@')
+    return d
+     
+if __name__ == "__main__":
+
+    try:
+        start_time = time.time()
+        print time.asctime()
+        main()
+        print time.asctime()
+        print "TOTAL TIME IN MINUTES:",
+        print (time.time() - start_time) / 60.0
+    except Exception, e:
+        print str(e)
+        tb_dump = traceback.format_exc()
+        print str(tb_dump)
+

UCC git Repository :: git.ucc.asn.au