lars
ad3de60dd1
add "self.root_action" to the plugin specification implement non-interactive key certificate creation during startup if necessary (the produced certificate is still broken) run stunnel during startup returned environment warnings are expected to be lists
222 lines
6.5 KiB
Python
222 lines
6.5 KiB
Python
#
|
|
# Copyright 2006 sense.lab e.V.
|
|
#
|
|
# This file is part of the CryptoBox.
|
|
#
|
|
# The CryptoBox 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 2 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# The CryptoBox 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 the CryptoBox; if not, write to the Free Software
|
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
#
|
|
|
|
"""The network feature of the CryptoBox.
|
|
|
|
requires:
|
|
- ifconfig
|
|
- route
|
|
"""
|
|
|
|
__revision__ = "$Id"
|
|
|
|
import subprocess
|
|
import os
|
|
import cryptobox.plugins.base
|
|
|
|
|
|
## specify (in seconds), how long we should wait before redirecting and ip change
|
|
REDIRECT_DELAY = 10
|
|
CHANGE_IP_DELAY = 5
|
|
## default network interface (may be overriden by the "interface" setting of the
|
|
## network plugin in cryptobox.conf
|
|
DEFAULT_INTERFACE = "eth0"
|
|
|
|
class network(cryptobox.plugins.base.CryptoBoxPlugin):
|
|
"""The network feature of the CryptoBox.
|
|
"""
|
|
|
|
plugin_capabilities = [ "system" ]
|
|
plugin_visibility = [ "preferences" ]
|
|
request_auth = True
|
|
rank = 30
|
|
|
|
def do_action(self, store=None, redirected="", ip1="", ip2="", ip3="", ip4="", gw1="", gw2="", gw3="", gw4=""):
|
|
"""Show a form containing the current IP - change it if requested.
|
|
"""
|
|
## if we were redirected, then we should display the default page
|
|
self.cbox.log.debug("executing network plugin")
|
|
if redirected == "1":
|
|
self.cbox.log.debug("network plugin: redirected")
|
|
return "form_network"
|
|
## check possible actions
|
|
if store is None:
|
|
## no action was requested -> just show the form
|
|
self.cbox.log.debug("network plugin: show form")
|
|
self.__prepare_form_data()
|
|
return "form_network"
|
|
elif store == "set_ip":
|
|
## change ip address
|
|
self.cbox.log.debug("network plugin: changing IP")
|
|
try:
|
|
for ip_in in (ip1, ip2, ip3, ip4):
|
|
if (int(ip_in) < 0) or (int(ip_in) > 255):
|
|
self.cbox.log.info("invalid CryptoBox IP supplied: %s" % \
|
|
str((ip1, ip2, ip3, ip4)))
|
|
raise ValueError
|
|
new_ip = "%d.%d.%d.%d" % (int(ip1), int(ip2), int(ip3), int(ip4))
|
|
except ValueError:
|
|
self.hdf["Data.Warning"] = "Plugins.network.InvalidIP"
|
|
self.__prepare_form_data()
|
|
return "form_network"
|
|
if self.__set_ip(new_ip):
|
|
self.cbox.log.info("the IP was successfully changed: %s" % new_ip)
|
|
self.hdf["Data.Success"] = "Plugins.network.IPChanged"
|
|
self.hdf["Data.Redirect.URL"] = self.__get_redirect_destination(new_ip)
|
|
self.hdf["Data.Redirect.Delay"] = REDIRECT_DELAY
|
|
self.prefs["_address"] = new_ip
|
|
try:
|
|
self.cbox.prefs.plugin_conf.write()
|
|
except IOError:
|
|
self.cbox.log.warn("Could not write plugin configuration")
|
|
self.__prepare_form_data()
|
|
return "empty"
|
|
else:
|
|
self.cbox.log.warn("failed to change IP address to: %s" % new_ip)
|
|
self.hdf["Data.Warning"] = "Plugins.network.InvalidIP"
|
|
self.__prepare_form_data()
|
|
return "form_network"
|
|
## request for default gateway change?
|
|
elif store == "set_gw":
|
|
## TODO: route add default gw ...
|
|
pass
|
|
else:
|
|
## invalid action was requested -> show default form
|
|
self.cbox.log.debug("network plugin: invalid request (%s)" % str(store))
|
|
self.__prepare_form_data()
|
|
return "form_network"
|
|
|
|
|
|
def get_status(self):
|
|
"""The current IP is the status of this feature.
|
|
"""
|
|
return "%d.%d.%d.%d" % self.__get_current_ip()
|
|
|
|
|
|
def handle_event(self, event, event_info=None):
|
|
"""Override bootup behaviour
|
|
|
|
Apply the configured network settings
|
|
"""
|
|
if event == "bootup":
|
|
if "_address" in self.prefs:
|
|
self.__set_ip(self.prefs["_address"])
|
|
|
|
|
|
def get_warnings(self):
|
|
"""Check for missing programs
|
|
"""
|
|
warnings = []
|
|
if not os.path.isfile(self.root_action.IFCONFIG_BIN):
|
|
warnings.append((55, "MissingProgramIfconfig"))
|
|
if not os.path.isfile(self.root_action.GWCONFIG_BIN):
|
|
warnings.append((52, "Plugins.%s.MissingProgramRoute" % self.get_name()))
|
|
return warnings
|
|
|
|
|
|
def __get_redirect_destination(self, ip):
|
|
"""Put the new URL together.
|
|
"""
|
|
import cherrypy
|
|
req = cherrypy.request
|
|
base_parts = req.base.split(":")
|
|
dest = "%s://%s" % (base_parts[0], ip)
|
|
if len(base_parts) == 3:
|
|
dest += ":%s" % base_parts[2]
|
|
return dest
|
|
|
|
|
|
def __prepare_form_data(self):
|
|
"""Set some hdf values.
|
|
"""
|
|
(oc1, oc2, oc3, oc4) = self.__get_current_ip()
|
|
self.hdf[self.hdf_prefix + "ip.oc1"] = oc1
|
|
self.hdf[self.hdf_prefix + "ip.oc2"] = oc2
|
|
self.hdf[self.hdf_prefix + "ip.oc3"] = oc3
|
|
self.hdf[self.hdf_prefix + "ip.oc4"] = oc4
|
|
|
|
|
|
def __get_current_ip(self):
|
|
"""Retrieve the current IP.
|
|
"""
|
|
import re
|
|
## get the current IP of the network interface
|
|
proc = subprocess.Popen(
|
|
shell = False,
|
|
stdout = subprocess.PIPE,
|
|
args = [
|
|
self.root_action.IFCONFIG_BIN,
|
|
self.__get_interface()])
|
|
(stdout, stderr) = proc.communicate()
|
|
if proc.returncode != 0:
|
|
return (0, 0, 0, 0)
|
|
## this regex matches the four numbers of the IP
|
|
match = re.search(r'inet [\w]+:(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\s', stdout)
|
|
if match:
|
|
## use the previously matched numbers
|
|
return tuple([int(e) for e in match.groups()])
|
|
else:
|
|
return (0, 0, 0, 0)
|
|
|
|
|
|
def __set_ip(self, new_ip):
|
|
"""Change the IP.
|
|
"""
|
|
import threading
|
|
## call the root_action script after some seconds - so we can deliver the page before
|
|
def delayed_ip_change():
|
|
"""A threaded function to change the IP.
|
|
"""
|
|
import time
|
|
time.sleep(CHANGE_IP_DELAY)
|
|
proc = subprocess.Popen(
|
|
shell = False,
|
|
stderr = subprocess.PIPE,
|
|
args = [
|
|
self.cbox.prefs["Programs"]["super"],
|
|
self.cbox.prefs["Programs"]["CryptoBoxRootActions"],
|
|
"plugin",
|
|
os.path.join(self.plugin_dir, "root_action.py"),
|
|
"change_ip",
|
|
self.__get_interface(),
|
|
new_ip])
|
|
proc.wait()
|
|
if proc.returncode != 0:
|
|
self.cbox.log.warn("failed to change IP address: %s" % new_ip)
|
|
self.cbox.log.warn("error output: %s" % str(proc.stderr.read()))
|
|
return
|
|
thread = threading.Thread()
|
|
thread.run = delayed_ip_change
|
|
thread.setDaemon(True)
|
|
thread.start()
|
|
# TODO: how could we guess, if it failed?
|
|
return True
|
|
|
|
|
|
def __get_interface(self):
|
|
"""Return the name of the configured network interface
|
|
"""
|
|
if "interface" in self.defaults:
|
|
return self.defaults["interface"]
|
|
else:
|
|
return DEFAULT_INTERFACE
|
|
|
|
|