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