forked from OSchip/llvm-project
763 lines
24 KiB
Python
Executable File
763 lines
24 KiB
Python
Executable File
#!/usr/bin/python
|
|
##!/usr/bin/env python
|
|
"""CGI shell server
|
|
|
|
This exposes a shell terminal on a web page.
|
|
It uses AJAX to send keys and receive screen updates.
|
|
The client web browser needs nothing but CSS and Javascript.
|
|
|
|
--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
|
|
|
|
This project is probably not the most security concious thing I've ever built.
|
|
This should be considered an experimental tool -- at best.
|
|
"""
|
|
import sys,os
|
|
sys.path.insert (0,os.getcwd()) # let local modules precede any installed modules
|
|
import socket, random, string, traceback, cgi, time, getopt, getpass, threading, resource, signal
|
|
import pxssh, pexpect, ANSI
|
|
|
|
def exit_with_usage(exit_code=1):
|
|
print globals()['__doc__']
|
|
os._exit(exit_code)
|
|
|
|
def client (command, host='localhost', port=-1):
|
|
"""This sends a request to the server and returns the response.
|
|
If port <= 0 then host is assumed to be the filename of a Unix domain socket.
|
|
If port > 0 then host is an inet hostname.
|
|
"""
|
|
if port <= 0:
|
|
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
|
s.connect(host)
|
|
else:
|
|
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
s.connect((host, port))
|
|
s.send(command)
|
|
data = s.recv (2500)
|
|
s.close()
|
|
return data
|
|
|
|
def server (hostname, username, password, socket_filename='/tmp/server_sock', daemon_mode = True, verbose=False):
|
|
"""This starts and services requests from a client.
|
|
If daemon_mode is True then this forks off a separate daemon process and returns the daemon's pid.
|
|
If daemon_mode is False then this does not return until the server is done.
|
|
"""
|
|
if daemon_mode:
|
|
mypid_name = '/tmp/%d.pid' % os.getpid()
|
|
daemon_pid = daemonize(daemon_pid_filename=mypid_name)
|
|
time.sleep(1)
|
|
if daemon_pid != 0:
|
|
os.unlink(mypid_name)
|
|
return daemon_pid
|
|
|
|
virtual_screen = ANSI.ANSI (24,80)
|
|
child = pxssh.pxssh()
|
|
try:
|
|
child.login (hostname, username, password, login_naked=True)
|
|
except:
|
|
return
|
|
if verbose: print 'login OK'
|
|
virtual_screen.write (child.before)
|
|
virtual_screen.write (child.after)
|
|
|
|
if os.path.exists(socket_filename): os.remove(socket_filename)
|
|
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
|
s.bind(socket_filename)
|
|
os.chmod(socket_filename, 0777)
|
|
if verbose: print 'Listen'
|
|
s.listen(1)
|
|
|
|
r = roller (endless_poll, (child, child.PROMPT, virtual_screen))
|
|
r.start()
|
|
if verbose: print "started screen-poll-updater in background thread"
|
|
sys.stdout.flush()
|
|
try:
|
|
while True:
|
|
conn, addr = s.accept()
|
|
if verbose: print 'Connected by', addr
|
|
data = conn.recv(1024)
|
|
request = data.split(' ', 1)
|
|
if len(request)>1:
|
|
cmd = request[0].strip()
|
|
arg = request[1].strip()
|
|
else:
|
|
cmd = request[0].strip()
|
|
arg = ''
|
|
|
|
if cmd == 'exit':
|
|
r.cancel()
|
|
break
|
|
elif cmd == 'sendline':
|
|
child.sendline (arg)
|
|
time.sleep(0.1)
|
|
shell_window = str(virtual_screen)
|
|
elif cmd == 'send' or cmd=='xsend':
|
|
if cmd=='xsend':
|
|
arg = arg.decode("hex")
|
|
child.send (arg)
|
|
time.sleep(0.1)
|
|
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)
|
|
elif cmd == 'hash':
|
|
shell_window = str(hash(str(virtual_screen)))
|
|
|
|
response = []
|
|
response.append (shell_window)
|
|
if verbose: print '\n'.join(response)
|
|
sent = conn.send('\n'.join(response))
|
|
if sent < len (response):
|
|
if verbose: print "Sent is too short. Some data was cut off."
|
|
conn.close()
|
|
except e:
|
|
pass
|
|
r.cancel()
|
|
if verbose: print "cleaning up socket"
|
|
s.close()
|
|
if os.path.exists(socket_filename): os.remove(socket_filename)
|
|
if verbose: print "server done!"
|
|
|
|
class roller (threading.Thread):
|
|
"""This class continuously loops a function in a thread.
|
|
This is basically a thin layer around Thread with a
|
|
while loop and a cancel.
|
|
"""
|
|
def __init__(self, function, args=[], kwargs={}):
|
|
threading.Thread.__init__(self)
|
|
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.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 will be run in a separate thread. See roller class.
|
|
"""
|
|
#child.logfile_read = screen
|
|
try:
|
|
s = child.read_nonblocking(4000, 0.1)
|
|
screen.write(s)
|
|
except:
|
|
pass
|
|
|
|
def daemonize (stdin=None, stdout=None, stderr=None, daemon_pid_filename=None):
|
|
"""This runs the current process in the background as a daemon.
|
|
The arguments stdin, stdout, stderr allow you to set the filename that the daemon reads and writes to.
|
|
If they are set to None then all stdio for the daemon will be directed to /dev/null.
|
|
If daemon_pid_filename is set then the pid of the daemon will be written to it as plain text
|
|
and the pid will be returned. If daemon_pid_filename is None then this will return None.
|
|
"""
|
|
UMASK = 0
|
|
WORKINGDIR = "/"
|
|
MAXFD = 1024
|
|
|
|
# The stdio file descriptors are redirected to /dev/null by default.
|
|
if hasattr(os, "devnull"):
|
|
DEVNULL = os.devnull
|
|
else:
|
|
DEVNULL = "/dev/null"
|
|
if stdin is None: stdin = DEVNULL
|
|
if stdout is None: stdout = DEVNULL
|
|
if stderr is None: stderr = DEVNULL
|
|
|
|
try:
|
|
pid = os.fork()
|
|
except OSError, e:
|
|
raise Exception, "%s [%d]" % (e.strerror, e.errno)
|
|
|
|
if pid != 0: # The first child.
|
|
os.waitpid(pid,0)
|
|
if daemon_pid_filename is not None:
|
|
daemon_pid = int(file(daemon_pid_filename,'r').read())
|
|
return daemon_pid
|
|
else:
|
|
return None
|
|
|
|
# first child
|
|
os.setsid()
|
|
signal.signal(signal.SIGHUP, signal.SIG_IGN)
|
|
|
|
try:
|
|
pid = os.fork() # fork second child
|
|
except OSError, e:
|
|
raise Exception, "%s [%d]" % (e.strerror, e.errno)
|
|
|
|
if pid != 0:
|
|
if daemon_pid_filename is not None:
|
|
file(daemon_pid_filename,'w').write(str(pid))
|
|
os._exit(0) # exit parent (the first child) of the second child.
|
|
|
|
# second child
|
|
os.chdir(WORKINGDIR)
|
|
os.umask(UMASK)
|
|
|
|
maxfd = resource.getrlimit(resource.RLIMIT_NOFILE)[1]
|
|
if maxfd == resource.RLIM_INFINITY:
|
|
maxfd = MAXFD
|
|
|
|
# close all file descriptors
|
|
for fd in xrange(0, maxfd):
|
|
try:
|
|
os.close(fd)
|
|
except OSError: # fd wasn't open to begin with (ignored)
|
|
pass
|
|
|
|
os.open (DEVNULL, os.O_RDWR) # standard input
|
|
|
|
# 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())
|
|
|
|
return 0
|
|
|
|
def client_cgi ():
|
|
"""This handles the request if this script was called as a cgi.
|
|
"""
|
|
sys.stderr = sys.stdout
|
|
ajax_mode = False
|
|
TITLE="Shell"
|
|
SHELL_OUTPUT=""
|
|
SID="NOT"
|
|
print "Content-type: text/html;charset=utf-8\r\n"
|
|
try:
|
|
form = cgi.FieldStorage()
|
|
if form.has_key('ajax'):
|
|
ajax_mode = True
|
|
ajax_cmd = form['ajax'].value
|
|
SID=form['sid'].value
|
|
if ajax_cmd == 'send':
|
|
command = 'xsend'
|
|
arg = form['arg'].value.encode('hex')
|
|
result = client (command + ' ' + arg, '/tmp/'+SID)
|
|
print result
|
|
elif ajax_cmd == 'refresh':
|
|
command = 'refresh'
|
|
result = client (command, '/tmp/'+SID)
|
|
print result
|
|
elif ajax_cmd == 'cursor':
|
|
command = 'cursor'
|
|
result = client (command, '/tmp/'+SID)
|
|
print result
|
|
elif ajax_cmd == 'exit':
|
|
command = 'exit'
|
|
result = client (command, '/tmp/'+SID)
|
|
print result
|
|
elif ajax_cmd == 'hash':
|
|
command = 'hash'
|
|
result = client (command, '/tmp/'+SID)
|
|
print result
|
|
elif not form.has_key('sid'):
|
|
SID=random_sid()
|
|
print LOGIN_HTML % locals();
|
|
else:
|
|
SID=form['sid'].value
|
|
if form.has_key('start_server'):
|
|
USERNAME = form['username'].value
|
|
PASSWORD = form['password'].value
|
|
dpid = server ('127.0.0.1', USERNAME, PASSWORD, '/tmp/'+SID)
|
|
SHELL_OUTPUT="daemon pid: " + str(dpid)
|
|
else:
|
|
if form.has_key('cli'):
|
|
command = 'sendline ' + form['cli'].value
|
|
else:
|
|
command = 'sendline'
|
|
SHELL_OUTPUT = client (command, '/tmp/'+SID)
|
|
print CGISH_HTML % locals()
|
|
except:
|
|
tb_dump = traceback.format_exc()
|
|
if ajax_mode:
|
|
print str(tb_dump)
|
|
else:
|
|
SHELL_OUTPUT=str(tb_dump)
|
|
print CGISH_HTML % locals()
|
|
|
|
def server_cli():
|
|
"""This is the command line interface to starting the server.
|
|
This handles things if the script was not called as a CGI
|
|
(if you run it from the command line).
|
|
"""
|
|
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']
|
|
if '--password' in options:
|
|
password = options['--password']
|
|
else:
|
|
password = getpass.getpass('password: ')
|
|
|
|
server (hostname, username, password, '/tmp/mysock', daemon_mode)
|
|
|
|
def random_sid ():
|
|
a=random.randint(0,65535)
|
|
b=random.randint(0,65535)
|
|
return '%04x%04x.sid' % (a,b)
|
|
|
|
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
|
|
|
|
def pretty_box (s, rows=24, cols=80):
|
|
"""This puts an ASCII text box around the given string.
|
|
"""
|
|
top_bot = '+' + '-'*cols + '+\n'
|
|
return top_bot + '\n'.join(['|'+line+'|' for line in s.split('\n')]) + '\n' + top_bot
|
|
|
|
def main ():
|
|
if os.getenv('REQUEST_METHOD') is None:
|
|
server_cli()
|
|
else:
|
|
client_cgi()
|
|
|
|
# It's mostly HTML and Javascript from here on out.
|
|
CGISH_HTML="""<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
|
<html>
|
|
<head>
|
|
<title>%(TITLE)s %(SID)s</title>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
|
<style type=text/css>
|
|
a {color: #9f9; text-decoration: none}
|
|
a:hover {color: #0f0}
|
|
hr {color: #0f0}
|
|
html,body,textarea,input,form
|
|
{
|
|
font-family: "Courier New", Courier, mono;
|
|
font-size: 8pt;
|
|
color: #0c0;
|
|
background-color: #020;
|
|
margin:0;
|
|
padding:0;
|
|
border:0;
|
|
}
|
|
input { background-color: #010; }
|
|
textarea {
|
|
border-width:1;
|
|
border-style:solid;
|
|
border-color:#0c0;
|
|
padding:3;
|
|
margin:3;
|
|
}
|
|
</style>
|
|
|
|
<script language="JavaScript">
|
|
function focus_first()
|
|
{if (document.forms.length > 0)
|
|
{var TForm = document.forms[0];
|
|
for (i=0;i<TForm.length;i++){
|
|
if ((TForm.elements[i].type=="text")||
|
|
(TForm.elements[i].type=="textarea")||
|
|
(TForm.elements[i].type.toString().charAt(0)=="s"))
|
|
{document.forms[0].elements[i].focus();break;}}}}
|
|
|
|
// JavaScript Virtual Keyboard
|
|
// If you like this code then buy me a sandwich.
|
|
// Noah Spurrier <noah@noah.org>
|
|
var flag_shift=0;
|
|
var flag_shiftlock=0;
|
|
var flag_ctrl=0;
|
|
var ButtonOnColor="#ee0";
|
|
|
|
function init ()
|
|
{
|
|
// hack to set quote key to show both single quote and double quote
|
|
document.form['quote'].value = "'" + ' "';
|
|
//refresh_screen();
|
|
poll();
|
|
document.form["cli"].focus();
|
|
}
|
|
function get_password ()
|
|
{
|
|
var username = prompt("username?","");
|
|
var password = prompt("password?","");
|
|
start_server (username, password);
|
|
}
|
|
function multibrowser_ajax ()
|
|
{
|
|
var xmlHttp = false;
|
|
/*@cc_on @*/
|
|
/*@if (@_jscript_version >= 5)
|
|
try
|
|
{
|
|
xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
|
|
}
|
|
catch (e)
|
|
{
|
|
try
|
|
{
|
|
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
|
|
}
|
|
catch (e2)
|
|
{
|
|
xmlHttp = false;
|
|
}
|
|
}
|
|
@end @*/
|
|
|
|
if (!xmlHttp && typeof XMLHttpRequest != 'undefined')
|
|
{
|
|
xmlHttp = new XMLHttpRequest();
|
|
}
|
|
return xmlHttp;
|
|
}
|
|
function load_url_to_screen(url)
|
|
{
|
|
xmlhttp = multibrowser_ajax();
|
|
//window.XMLHttpRequest?new XMLHttpRequest(): new ActiveXObject("Microsoft.XMLHTTP");
|
|
xmlhttp.onreadystatechange = update_virtual_screen;
|
|
xmlhttp.open("GET", url);
|
|
xmlhttp.setRequestHeader("If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT");
|
|
xmlhttp.send(null);
|
|
}
|
|
function update_virtual_screen()
|
|
{
|
|
if ((xmlhttp.readyState == 4) && (xmlhttp.status == 200))
|
|
{
|
|
var screen_text = xmlhttp.responseText;
|
|
document.form["screen_text"].value = screen_text;
|
|
//var json_data = json_parse(xmlhttp.responseText);
|
|
}
|
|
}
|
|
function poll()
|
|
{
|
|
refresh_screen();
|
|
timerID = setTimeout("poll()", 2000);
|
|
// clearTimeout(timerID);
|
|
}
|
|
//function start_server (username, password)
|
|
//{
|
|
// load_url_to_screen('cgishell.cgi?ajax=serverstart&username=' + escape(username) + '&password=' + escape(password);
|
|
//}
|
|
function refresh_screen()
|
|
{
|
|
load_url_to_screen('cgishell.cgi?ajax=refresh&sid=%(SID)s');
|
|
}
|
|
function query_hash()
|
|
{
|
|
load_url_to_screen('cgishell.cgi?ajax=hash&sid=%(SID)s');
|
|
}
|
|
function query_cursor()
|
|
{
|
|
load_url_to_screen('cgishell.cgi?ajax=cursor&sid=%(SID)s');
|
|
}
|
|
function exit_server()
|
|
{
|
|
load_url_to_screen('cgishell.cgi?ajax=exit&sid=%(SID)s');
|
|
}
|
|
function type_key (chars)
|
|
{
|
|
var ch = '?';
|
|
if (flag_shiftlock || flag_shift)
|
|
{
|
|
ch = chars.substr(1,1);
|
|
}
|
|
else if (flag_ctrl)
|
|
{
|
|
ch = chars.substr(2,1);
|
|
}
|
|
else
|
|
{
|
|
ch = chars.substr(0,1);
|
|
}
|
|
load_url_to_screen('cgishell.cgi?ajax=send&sid=%(SID)s&arg=' + escape(ch));
|
|
if (flag_shift || flag_ctrl)
|
|
{
|
|
flag_shift = 0;
|
|
flag_ctrl = 0;
|
|
}
|
|
update_button_colors();
|
|
}
|
|
|
|
function key_shiftlock()
|
|
{
|
|
flag_ctrl = 0;
|
|
flag_shift = 0;
|
|
if (flag_shiftlock)
|
|
{
|
|
flag_shiftlock = 0;
|
|
}
|
|
else
|
|
{
|
|
flag_shiftlock = 1;
|
|
}
|
|
update_button_colors();
|
|
}
|
|
|
|
function key_shift()
|
|
{
|
|
if (flag_shift)
|
|
{
|
|
flag_shift = 0;
|
|
}
|
|
else
|
|
{
|
|
flag_ctrl = 0;
|
|
flag_shiftlock = 0;
|
|
flag_shift = 1;
|
|
}
|
|
update_button_colors();
|
|
}
|
|
function key_ctrl ()
|
|
{
|
|
if (flag_ctrl)
|
|
{
|
|
flag_ctrl = 0;
|
|
}
|
|
else
|
|
{
|
|
flag_ctrl = 1;
|
|
flag_shiftlock = 0;
|
|
flag_shift = 0;
|
|
}
|
|
|
|
update_button_colors();
|
|
}
|
|
function update_button_colors ()
|
|
{
|
|
if (flag_ctrl)
|
|
{
|
|
document.form['Ctrl'].style.backgroundColor = ButtonOnColor;
|
|
document.form['Ctrl2'].style.backgroundColor = ButtonOnColor;
|
|
}
|
|
else
|
|
{
|
|
document.form['Ctrl'].style.backgroundColor = document.form.style.backgroundColor;
|
|
document.form['Ctrl2'].style.backgroundColor = document.form.style.backgroundColor;
|
|
}
|
|
if (flag_shift)
|
|
{
|
|
document.form['Shift'].style.backgroundColor = ButtonOnColor;
|
|
document.form['Shift2'].style.backgroundColor = ButtonOnColor;
|
|
}
|
|
else
|
|
{
|
|
document.form['Shift'].style.backgroundColor = document.form.style.backgroundColor;
|
|
document.form['Shift2'].style.backgroundColor = document.form.style.backgroundColor;
|
|
}
|
|
if (flag_shiftlock)
|
|
{
|
|
document.form['ShiftLock'].style.backgroundColor = ButtonOnColor;
|
|
}
|
|
else
|
|
{
|
|
document.form['ShiftLock'].style.backgroundColor = document.form.style.backgroundColor;
|
|
}
|
|
|
|
}
|
|
function keyHandler(e)
|
|
{
|
|
var pressedKey;
|
|
if (document.all) { e = window.event; }
|
|
if (document.layers) { pressedKey = e.which; }
|
|
if (document.all) { pressedKey = e.keyCode; }
|
|
pressedCharacter = String.fromCharCode(pressedKey);
|
|
type_key(pressedCharacter+pressedCharacter+pressedCharacter);
|
|
alert(pressedCharacter);
|
|
// alert(' Character = ' + pressedCharacter + ' [Decimal value = ' + pressedKey + ']');
|
|
}
|
|
//document.onkeypress = keyHandler;
|
|
//if (document.layers)
|
|
// document.captureEvents(Event.KEYPRESS);
|
|
//http://sniptools.com/jskeys
|
|
//document.onkeyup = KeyCheck;
|
|
function KeyCheck(e)
|
|
{
|
|
var KeyID = (window.event) ? event.keyCode : e.keyCode;
|
|
type_key(String.fromCharCode(KeyID));
|
|
e.cancelBubble = true;
|
|
window.event.cancelBubble = true;
|
|
}
|
|
</script>
|
|
|
|
</head>
|
|
|
|
<body onload="init()">
|
|
<form id="form" name="form" action="/cgi-bin/cgishell.cgi" method="POST">
|
|
<input name="sid" value="%(SID)s" type="hidden">
|
|
<textarea name="screen_text" cols="81" rows="25">%(SHELL_OUTPUT)s</textarea>
|
|
<hr noshade="1">
|
|
<input name="cli" id="cli" type="text" size="80"><br>
|
|
<table border="0" align="left">
|
|
<tr>
|
|
<td width="86%%" align="center">
|
|
<input name="submit" type="submit" value="Submit">
|
|
<input name="refresh" type="button" value="REFRESH" onclick="refresh_screen()">
|
|
<input name="refresh" type="button" value="CURSOR" onclick="query_cursor()">
|
|
<input name="hash" type="button" value="HASH" onclick="query_hash()">
|
|
<input name="exit" type="button" value="EXIT" onclick="exit_server()">
|
|
<br>
|
|
<input type="button" value="Esc" onclick="type_key('\\x1b\\x1b')" />
|
|
<input type="button" value="` ~" onclick="type_key('`~')" />
|
|
<input type="button" value="1!" onclick="type_key('1!')" />
|
|
<input type="button" value="2@" onclick="type_key('2@\\x00')" />
|
|
<input type="button" value="3#" onclick="type_key('3#')" />
|
|
<input type="button" value="4$" onclick="type_key('4$')" />
|
|
<input type="button" value="5%%" onclick="type_key('5%%')" />
|
|
<input type="button" value="6^" onclick="type_key('6^\\x1E')" />
|
|
<input type="button" value="7&" onclick="type_key('7&')" />
|
|
<input type="button" value="8*" onclick="type_key('8*')" />
|
|
<input type="button" value="9(" onclick="type_key('9(')" />
|
|
<input type="button" value="0)" onclick="type_key('0)')" />
|
|
<input type="button" value="-_" onclick="type_key('-_\\x1F')" />
|
|
<input type="button" value="=+" onclick="type_key('=+')" />
|
|
<input type="button" value="BkSp" onclick="type_key('\\x08\\x08\\x08')" />
|
|
<br>
|
|
<input type="button" value="Tab" onclick="type_key('\\t\\t')" />
|
|
<input type="button" value="Q" onclick="type_key('qQ\\x11')" />
|
|
<input type="button" value="W" onclick="type_key('wW\\x17')" />
|
|
<input type="button" value="E" onclick="type_key('eE\\x05')" />
|
|
<input type="button" value="R" onclick="type_key('rR\\x12')" />
|
|
<input type="button" value="T" onclick="type_key('tT\\x14')" />
|
|
<input type="button" value="Y" onclick="type_key('yY\\x19')" />
|
|
<input type="button" value="U" onclick="type_key('uU\\x15')" />
|
|
<input type="button" value="I" onclick="type_key('iI\\x09')" />
|
|
<input type="button" value="O" onclick="type_key('oO\\x0F')" />
|
|
<input type="button" value="P" onclick="type_key('pP\\x10')" />
|
|
<input type="button" value="[ {" onclick="type_key('[{\\x1b')" />
|
|
<input type="button" value="] }" onclick="type_key(']}\\x1d')" />
|
|
<input type="button" value="\\ |" onclick="type_key('\\\\|\\x1c')" />
|
|
<br>
|
|
<input type="button" id="Ctrl" value="Ctrl" onclick="key_ctrl()" />
|
|
<input type="button" value="A" onclick="type_key('aA\\x01')" />
|
|
<input type="button" value="S" onclick="type_key('sS\\x13')" />
|
|
<input type="button" value="D" onclick="type_key('dD\\x04')" />
|
|
<input type="button" value="F" onclick="type_key('fF\\x06')" />
|
|
<input type="button" value="G" onclick="type_key('gG\\x07')" />
|
|
<input type="button" value="H" onclick="type_key('hH\\x08')" />
|
|
<input type="button" value="J" onclick="type_key('jJ\\x0A')" />
|
|
<input type="button" value="K" onclick="type_key('kK\\x0B')" />
|
|
<input type="button" value="L" onclick="type_key('lL\\x0C')" />
|
|
<input type="button" value="; :" onclick="type_key(';:')" />
|
|
<input type="button" id="quote" value="'" onclick="type_key('\\x27\\x22')" />
|
|
<input type="button" value="Enter" onclick="type_key('\\n\\n')" />
|
|
<br>
|
|
<input type="button" id="ShiftLock" value="Caps Lock" onclick="key_shiftlock()" />
|
|
<input type="button" id="Shift" value="Shift" onclick="key_shift()" />
|
|
<input type="button" value="Z" onclick="type_key('zZ\\x1A')" />
|
|
<input type="button" value="X" onclick="type_key('xX\\x18')" />
|
|
<input type="button" value="C" onclick="type_key('cC\\x03')" />
|
|
<input type="button" value="V" onclick="type_key('vV\\x16')" />
|
|
<input type="button" value="B" onclick="type_key('bB\\x02')" />
|
|
<input type="button" value="N" onclick="type_key('nN\\x0E')" />
|
|
<input type="button" value="M" onclick="type_key('mM\\x0D')" />
|
|
<input type="button" value=", <" onclick="type_key(',<')" />
|
|
<input type="button" value=". >" onclick="type_key('.>')" />
|
|
<input type="button" value="/ ?" onclick="type_key('/?')" />
|
|
<input type="button" id="Shift2" value="Shift" onclick="key_shift()" />
|
|
<input type="button" id="Ctrl2" value="Ctrl" onclick="key_ctrl()" />
|
|
<br>
|
|
<input type="button" value=" FINAL FRONTIER " onclick="type_key(' ')" />
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</form>
|
|
</body>
|
|
</html>
|
|
"""
|
|
|
|
LOGIN_HTML="""<html>
|
|
<head>
|
|
<title>Shell Login</title>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
|
<style type=text/css>
|
|
a {color: #9f9; text-decoration: none}
|
|
a:hover {color: #0f0}
|
|
hr {color: #0f0}
|
|
html,body,textarea,input,form
|
|
{
|
|
font-family: "Courier New", Courier, mono;
|
|
font-size: 8pt;
|
|
color: #0c0;
|
|
background-color: #020;
|
|
margin:3;
|
|
padding:0;
|
|
border:0;
|
|
}
|
|
input { background-color: #010; }
|
|
input,textarea {
|
|
border-width:1;
|
|
border-style:solid;
|
|
border-color:#0c0;
|
|
padding:3;
|
|
margin:3;
|
|
}
|
|
</style>
|
|
<script language="JavaScript">
|
|
function init ()
|
|
{
|
|
document.login_form["username"].focus();
|
|
}
|
|
</script>
|
|
</head>
|
|
<body onload="init()">
|
|
<form name="login_form" method="POST">
|
|
<input name="start_server" value="1" type="hidden">
|
|
<input name="sid" value="%(SID)s" type="hidden">
|
|
username: <input name="username" type="text" size="30"><br>
|
|
password: <input name="password" type="password" size="30"><br>
|
|
<input name="submit" type="submit" value="enter">
|
|
</form>
|
|
<br>
|
|
</body>
|
|
</html>
|
|
"""
|
|
|
|
if __name__ == "__main__":
|
|
try:
|
|
main()
|
|
except Exception, e:
|
|
print str(e)
|
|
tb_dump = traceback.format_exc()
|
|
print str(tb_dump)
|
|
|