ft@0: #!/usr/bin/python ft@0: ft@0: # ------------------------------------------------------------ ft@0: # opensecurity package file ft@0: # ft@0: # Autor: X-Net Services GmbH ft@0: # ft@0: # Copyright 2013-2014 X-Net and AIT Austrian Institute of Technology ft@0: # ft@0: # ft@0: # X-Net Technologies GmbH ft@0: # Elisabethstrasse 1 ft@0: # 4020 Linz ft@0: # AUSTRIA ft@0: # https://www.x-net.at ft@0: # ft@0: # AIT Austrian Institute of Technology ft@0: # Donau City Strasse 1 ft@0: # 1220 Wien ft@0: # AUSTRIA ft@0: # http://www.ait.ac.at ft@0: # ft@0: # ft@0: # Licensed under the Apache License, Version 2.0 (the "License"); ft@0: # you may not use this file except in compliance with the License. ft@0: # You may obtain a copy of the License at ft@0: # ft@0: # http://www.apache.org/licenses/LICENSE-2.0 ft@0: # ft@0: # Unless required by applicable law or agreed to in writing, software ft@0: # distributed under the License is distributed on an "AS IS" BASIS, ft@0: # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ft@0: # See the License for the specific language governing permissions and ft@0: # limitations under the License. ft@0: # ------------------------------------------------------------ ft@0: ft@0: ft@0: import subprocess ft@0: import web ft@0: import netifaces ft@0: import os ft@0: import sys ft@0: import base64 ft@1: import thread ft@1: import urllib3 ft@1: import netaddr ft@0: ft@0: opensecurity_urls = ( ft@0: '/password', 'os_password', ft@0: '/init', 'os_init' ft@0: ) ft@0: ft@1: STATUS_CODE_OK = 200 ft@1: ft@1: ft@1: def sendDataToRest (urlpath, data): ft@1: netifaces.ifaddresses("eth0")[2][0]["addr"] ft@1: ft@1: # Get first address in network (0 = network ip -> 192.168.0.0) ft@1: remote_ip = netaddr.IPNetwork("%s/%s" %(netifaces.ifaddresses("eth0")[2][0]["addr"], netifaces.ifaddresses("eth0")[2][0]["netmask"]))[1] ft@1: ft@1: url = ("http://%s:8090//%s" %(remote_ip, urlpath)) ft@1: ft@1: try: ft@1: response = httpPool.request_encode_body("POST", url, fields=data, retries=0) ft@1: except Exception, e: ft@1: return ft@1: ft@1: if response.status == STATUS_CODE_OK: ft@1: return True ft@1: else: ft@1: return False ft@1: ft@1: ft@1: def sendNotification (type, message): ft@1: data = {"msgtype" : type, "text" : message} ft@1: ft@1: if (type == "information"): ft@1: sendDataToRest ("message", data) ft@1: else: ft@1: sendDataToRest ("notification", data) ft@1: ft@1: def sendInitialisationFailedError(): ft@1: sendNotification("critical", "Initialisation of the stick failed.") ft@1: ft@1: ft@1: ft@1: ft@1: ft@1: ft@0: ft@0: class os_password: ft@0: ft@0: # delete the key file in a secure way (will not working on ssd's :/ ,but ram only vm -> should be ok) ft@0: def deleteKeyfile(self, keyfilepath): ft@0: filesize = os.path.getsize(keyfilepath) ft@0: keyfile = open (keyfilepath, "w+") ft@0: for i in range (0, 10): ft@0: keyfile.seek(0) ft@0: keyfile.write(os.urandom(filesize)) ft@0: keyfile.flush() ft@0: keyfile.close() ft@0: os.remove(keyfilepath) ft@0: ft@0: ft@0: def GET(self, settings): ft@0: return self.POST(settings) ft@0: ft@0: def POST(self, settings): ft@0: ft@0: # pick the arguments ft@0: args = web.input() ft@0: ft@0: if not "password" in args: ft@0: raise web.badrequest() ft@0: ft@0: if "keyfile" in args: ft@0: keyfile = open (settings["keyfilepath"], "w+") ft@0: keyfile.write(base64.b64decode(args["keyfile"])) ft@0: keyfile.close() ft@0: command = [settings["script"], settings["device"], settings["mountpoint"], args["password"], settings["keyfilepath"]] ft@0: else: ft@0: command = [settings["script"], settings["device"], settings["mountpoint"], args["password"]] ft@0: ft@0: process = subprocess.Popen( command, stdout=subprocess.PIPE, stderr=subprocess.PIPE ) ft@0: retval = process.wait() ft@0: ( stdout, stderr ) = process.communicate() ft@0: ft@0: if "keyfile" in args: ft@0: self.deleteKeyfile(settings["keyfilepath"]) ft@0: ft@0: if (retval != 0): ft@0: raise web.badrequest(stderr) ft@0: ft@0: return "Success: Encrypted Stick is mounted" ft@0: ft@0: class os_init: ft@0: # delete the key file in a secure way (will not working on ssd's :/ ,but ram only vm -> should be ok) ft@0: def deleteKeyfile(self, keyfilepath): ft@0: filesize = os.path.getsize(keyfilepath) ft@0: keyfile = open (keyfilepath, "w+") ft@0: for i in range (0, 10): ft@0: keyfile.seek(0) ft@0: keyfile.write(os.urandom(filesize)) ft@0: keyfile.flush() ft@0: keyfile.close() ft@0: os.remove(keyfilepath) ft@0: ft@0: def runPreInitScript(self, preinitscript, device): ft@0: ft@0: command = [preinitscript, device] ft@0: process = subprocess.Popen( command, stdout=subprocess.PIPE, stderr=subprocess.PIPE ) ft@0: retval = process.wait() ft@0: ( stdout, stderr ) = process.communicate() ft@0: ft@0: if (retval != 0): ft@0: raise web.badrequest(stderr) ft@0: ft@0: def runPostInitScript(self, postinitscript): ft@0: command = [postinitscript] ft@0: process = subprocess.Popen( command, stdout=subprocess.PIPE, stderr=subprocess.PIPE ) ft@0: retval = process.wait() ft@0: ( stdout, stderr ) = process.communicate() ft@0: ft@0: if (retval != 0): ft@1: return False ft@1: else: ft@1: return True ft@0: ft@0: def GET(self, settings): ft@0: return self.POST(settings) ft@0: ft@0: def POST(self, settings): ft@0: ft@0: # pick the arguments ft@0: args = web.input() ft@0: ft@0: if not "password" in args: ft@0: raise web.badrequest() ft@0: ft@0: # Do the preinit stuff ft@0: self.runPreInitScript(settings["preinitscript"], settings["device"]) ft@0: ft@0: if "keyfile" in args: ft@0: keyfile = open (settings["keyfilepath"], "w+") ft@0: keyfile.write(base64.b64decode(args["keyfile"])) ft@0: keyfile.close() ft@0: command = [settings["script"], settings["device"], settings["mountpoint"], args["password"], settings["keyfilepath"]] ft@0: else: ft@0: command = [settings["script"], settings["device"], settings["mountpoint"], args["password"]] ft@0: ft@1: thread.start_new_thread(self.initStick, (command,settings,args,)) ft@1: ft@1: return "Success: Init started" ft@1: ft@1: def initStick(self, command, settings, args): ft@0: process = subprocess.Popen( command, stdout=subprocess.PIPE, stderr=subprocess.PIPE ) ft@0: retval = process.wait() ft@0: ( stdout, stderr ) = process.communicate() ft@0: ft@0: if "keyfile" in args: ft@0: self.deleteKeyfile(settings["keyfilepath"]) ft@0: ft@0: if (retval != 0): ft@1: sendInitialisationFailedError(); ft@0: ft@0: # Do the postinit stuff ft@1: if (self.runPostInitScript(settings["postinitscript"]) != True): ft@1: sendInitialisationFailedError(); ft@0: ft@0: class MyRestListener(web.application): ft@0: def __init__(self, mapping=(), fvars={}, autoreload=None, script=None, device=None, mountpoint=None, tries=None, keyfilepath=None, preinitscript=None, postinitscript=None): ft@0: web.application.__init__(self, mapping, fvars, autoreload) ft@0: self.device = device ft@0: self.mountpoint = mountpoint ft@0: self.script = script ft@0: self.tries = tries ft@0: self.keyfilepath = keyfilepath ft@0: self.preinitscript = preinitscript ft@0: self.postinitscript = postinitscript ft@0: ft@0: def run(self, interface, port, *middleware): ft@0: func = self.wsgifunc(*middleware) ft@0: ifaceip = netifaces.ifaddresses(interface)[2][0]["addr"] ft@0: return web.httpserver.runsimple(func, (ifaceip, port)) ft@0: ft@0: def handle(self): ft@0: fn, args = self._match(self.mapping, web.ctx.path) ft@0: args.append({"script": self.script, "device": self.device, "mountpoint": self.mountpoint, "tries": self.tries, "keyfilepath": self.keyfilepath, "preinitscript": self.preinitscript, "postinitscript": self.postinitscript}) ft@0: return self._delegate(fn, self.fvars, args)