# - Mike Warot's capabilities demo version 0.008
# Copyright (C) 2008 Michael A. Warot, all rights reserved.
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
#
# Based on webserver.py Copyright Jon Berg , turtlemeat.com
# version - new capabilites
# 01 - moved to port 81 to avoid built in IIS in XP, etc.
# 02 - added code from Rogier Steehouder to allow for keyboard interrupt of the server when running from the command line
# 03 - add code to display requested path
# 04 - get a random number and display it if the request is /token
# turns out that Mersenne Twister is an available random number generator... close enough to cryptographic for a while. 8)
# 05 - keep a list of tokens we hand out, display on the main page
# 06 - allow deletion of a token from the list
# 07 - after deleting token, gets you back to the main page
# 08 - added GPL language (version 3 of the gpl, don't want this to end up in a Tivo) and startup hint in the command window
#
#
import string,cgi,time, socket, random
from os import curdir, sep
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
validtokens = [] # start with no tokens
version = '0.008'
# code from http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/499376 which allows for keyboard interrupt of the server when running from command line+
class Server(HTTPServer):
"""HTTPServer class with timeout."""
def get_request(self):
"""Get the request and client address from the socket."""
# 10 second timeout
self.socket.settimeout(10.0)
result = None
while result is None:
try:
result = self.socket.accept()
except socket.timeout:
pass
# Reset timeout on the new socket
result[0].settimeout(None)
return result
class MyHandler(BaseHTTPRequestHandler):
def do_GET(self):
global validtokens
try:
if self.path.endswith(".html"):
f = open(curdir + sep + self.path) #self.path has /test.html
#note that this potentially makes every file on your computer readable by the internet
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()
self.wfile.write(f.read())
f.close()
return
if self.path.endswith(".esp"): #our dynamic content
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()
self.wfile.write("hey, today is the" + str(time.localtime()[7]))
self.wfile.write(" day in the year " + str(time.localtime()[0]))
self.wfile.write("
Your path is : " + self.path + "")
return
if self.path.endswith("token"): # get a random number and return it
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()
x = "%032x" % (random.getrandbits(128))
validtokens = validtokens + [ x ]
self.wfile.write(x)
return
# default out to a welcome page
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()
self.wfile.write('this is the default content, not served from a file
')
self.wfile.write('Here are the valid tokens:
')
self.wfile.write('
')
return
except IOError:
self.send_error(404,'File Not Found: %s' % self.path)
def do_POST(self):
global validtokens
# Parse the form data posted
form = cgi.FieldStorage(
fp=self.rfile,
headers=self.headers,
environ={'REQUEST_METHOD':'POST',
'CONTENT_TYPE':self.headers['Content-Type'],
})
cap = form["capability"].value
if (cap in validtokens) and self.path.endswith("delete"):
validtokens.remove(cap)
self.send_response(200)
self.send_header('Refresh','2; url=/') # 2 seconds gives us time to debug this thing, and see the output
self.send_header('Content-type', 'text/html')
self.end_headers()
self.wfile.write('Please return to the index page')
pass
else:
# Begin the response if we didn't have a valid delete token request
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()
self.wfile.write('Client: %s\n' % str(self.client_address))
self.wfile.write('Path: %s\n' % self.path)
self.wfile.write('Form data:\n')
# Echo back information about what was posted in the form
for field in form.keys():
field_item = form[field]
if field_item.filename:
# The field contains an uploaded file
file_data = field_item.file.read()
file_len = len(file_data)
del file_data
self.wfile.write('\tUploaded %s (%d bytes)\n' % (field,file_len))
else:
# Regular form value
self.wfile.write('\t%s=%s\n' % (field, form[field].value))
pass
def main():
try:
server = Server(('', 81), MyHandler) # port 81 to avoid IIS, Apache, etc.
print "Welcome to Mike Warot's capability based security demo web server, version "+version
print 'You can access it at http://127.0.0.1:81'
print 'Use control-c to tell it to shut down, which may take up to 10 seconds'
print 'started httpserver...'
server.serve_forever()
except KeyboardInterrupt:
print '^C received, shutting down server'
server.socket.close()
if __name__ == '__main__':
main()