added mounting and unmounting of config partition
moved config partition handling to CryptoBoxSettings implemented environment checks (writeable config, https (off for now)) chown mounted directory after mount to the cryptobox user
This commit is contained in:
parent
2c350207c9
commit
0fe6d426ed
5 changed files with 180 additions and 66 deletions
|
@ -19,6 +19,7 @@ from CryptoBoxExceptions import *
|
|||
import re
|
||||
import os
|
||||
import CryptoBoxTools
|
||||
import subprocess
|
||||
|
||||
|
||||
|
||||
|
@ -75,7 +76,6 @@ class CryptoBox:
|
|||
|
||||
def __runTestRootPriv(self):
|
||||
"""try to run 'super' with 'CryptoBoxRootActions'"""
|
||||
import subprocess
|
||||
try:
|
||||
devnull = open(os.devnull, "w")
|
||||
except IOError:
|
||||
|
@ -130,25 +130,7 @@ class CryptoBoxProps(CryptoBox):
|
|||
self.containers.sort(cmp = lambda x,y: x.getName() < y.getName() and -1 or 1)
|
||||
|
||||
|
||||
def getConfigPartitions(self):
|
||||
"""returns a sequence of found config partitions"""
|
||||
import subprocess
|
||||
proc = subprocess.Popen(
|
||||
shell = False,
|
||||
stdout = subprocess.PIPE,
|
||||
args = [
|
||||
self.prefs["Programs"]["blkid"],
|
||||
"-c", os.path.devnull,
|
||||
"-t", "LABEL=%s" % self.prefs["Main"]["ConfigVolumeLabel"] ])
|
||||
(output, error) = proc.communicate()
|
||||
if output:
|
||||
return [e.strip().split(":",1)[0] for e in output.splitlines()]
|
||||
else:
|
||||
return []
|
||||
|
||||
|
||||
def isConfigPartition(self, device):
|
||||
import subprocess
|
||||
proc = subprocess.Popen(
|
||||
shell = False,
|
||||
stdout = subprocess.PIPE,
|
||||
|
@ -270,9 +252,9 @@ class CryptoBoxProps(CryptoBox):
|
|||
'''reads all files in path LangDir and returns a list of
|
||||
basenames from existing hdf files, that should are all available
|
||||
languages'''
|
||||
languages = []
|
||||
for file in os.listdir(self.prefs["Locations"]["LangDir"]):
|
||||
if file.endswith(".hdf"): languages.append(file.rstrip(".hdf"))
|
||||
languages = [ f.rstrip(".hdf")
|
||||
for f in os.listdir(self.prefs["Locations"]["LangDir"])
|
||||
if f.endswith(".hdf") ]
|
||||
if len(languages) < 1:
|
||||
self.log.error("No .hdf files found! The website won't render properly.")
|
||||
return languages
|
||||
|
@ -280,5 +262,5 @@ class CryptoBoxProps(CryptoBox):
|
|||
|
||||
|
||||
if __name__ == "__main__":
|
||||
cb = CryptoBox()
|
||||
cb = CryptoBoxProps()
|
||||
|
||||
|
|
|
@ -45,7 +45,6 @@ class CryptoBoxContainer:
|
|||
self.device = device
|
||||
self.cbox = cbox
|
||||
self.log = logging.getLogger("CryptoBox")
|
||||
self.Progs = self.cbox.prefs["Programs"]
|
||||
self.resetObject()
|
||||
|
||||
|
||||
|
@ -157,8 +156,8 @@ class CryptoBoxContainer:
|
|||
stdout = subprocess.PIPE,
|
||||
stderr = subprocess.PIPE,
|
||||
args = [
|
||||
self.Progs["super"],
|
||||
self.Progs["CryptoBoxRootActions"],
|
||||
self.cbox.prefs["Programs"]["super"],
|
||||
self.cbox.prefs["Programs"]["CryptoBoxRootActions"],
|
||||
"cryptsetup",
|
||||
"luksAddKey",
|
||||
self.device,
|
||||
|
@ -182,7 +181,7 @@ class CryptoBoxContainer:
|
|||
stdout = devnull,
|
||||
stderr = subprocess.PIPE,
|
||||
args = [
|
||||
self.Progs["cryptsetup"],
|
||||
self.cbox.prefs["Programs"]["cryptsetup"],
|
||||
"--batch-mode",
|
||||
"luksDelKey",
|
||||
self.device,
|
||||
|
@ -228,7 +227,7 @@ class CryptoBoxContainer:
|
|||
stdin=None,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
args=[self.Progs["blkid"],
|
||||
args=[self.cbox.prefs["Programs"]["blkid"],
|
||||
"-s", "UUID",
|
||||
"-o", "value",
|
||||
"-c", os.devnull,
|
||||
|
@ -267,7 +266,7 @@ class CryptoBoxContainer:
|
|||
stdin=None,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
args=[self.Progs["blkid"],
|
||||
args=[self.cbox.prefs["Programs"]["blkid"],
|
||||
"-s", "TYPE",
|
||||
"-o", "value",
|
||||
"-c", os.devnull,
|
||||
|
@ -295,7 +294,7 @@ class CryptoBoxContainer:
|
|||
stdout = devnull,
|
||||
stderr = devnull,
|
||||
args = [
|
||||
self.Progs["cryptsetup"],
|
||||
self.cbox.prefs["Programs"]["cryptsetup"],
|
||||
"--batch-mode",
|
||||
"isLuks",
|
||||
self.device])
|
||||
|
@ -332,8 +331,8 @@ class CryptoBoxContainer:
|
|||
stdout = devnull,
|
||||
stderr = subprocess.PIPE,
|
||||
args = [
|
||||
self.Progs["super"],
|
||||
self.Progs["CryptoBoxRootActions"],
|
||||
self.cbox.prefs["Programs"]["super"],
|
||||
self.cbox.prefs["Programs"]["CryptoBoxRootActions"],
|
||||
"cryptsetup",
|
||||
"luksOpen",
|
||||
self.device,
|
||||
|
@ -351,8 +350,8 @@ class CryptoBoxContainer:
|
|||
stdout = devnull,
|
||||
stderr = subprocess.PIPE,
|
||||
args = [
|
||||
self.Progs["super"],
|
||||
self.Progs["CryptoBoxRootActions"],
|
||||
self.cbox.prefs["Programs"]["super"],
|
||||
self.cbox.prefs["Programs"]["CryptoBoxRootActions"],
|
||||
"mount",
|
||||
os.path.join(self.__dmDir, self.name),
|
||||
self.__getMountPoint()])
|
||||
|
@ -378,8 +377,8 @@ class CryptoBoxContainer:
|
|||
stdout = devnull,
|
||||
stderr = subprocess.PIPE,
|
||||
args = [
|
||||
self.Progs["super"],
|
||||
self.Progs["CryptoBoxRootActions"],
|
||||
self.cbox.prefs["Programs"]["super"],
|
||||
self.cbox.prefs["Programs"]["CryptoBoxRootActions"],
|
||||
"umount",
|
||||
self.__getMountPoint()])
|
||||
proc.wait()
|
||||
|
@ -394,8 +393,8 @@ class CryptoBoxContainer:
|
|||
stdout = devnull,
|
||||
stderr = subprocess.PIPE,
|
||||
args = [
|
||||
self.Progs["super"],
|
||||
self.Progs["CryptoBoxRootActions"],
|
||||
self.cbox.prefs["Programs"]["super"],
|
||||
self.cbox.prefs["Programs"]["CryptoBoxRootActions"],
|
||||
"cryptsetup",
|
||||
"luksClose",
|
||||
self.name,
|
||||
|
@ -429,8 +428,8 @@ class CryptoBoxContainer:
|
|||
stdout = devnull,
|
||||
stderr = subprocess.PIPE,
|
||||
args = [
|
||||
self.Progs["super"],
|
||||
self.Progs["CryptoBoxRootActions"],
|
||||
self.cbox.prefs["Programs"]["super"],
|
||||
self.cbox.prefs["Programs"]["CryptoBoxRootActions"],
|
||||
"mount",
|
||||
self.device,
|
||||
self.__getMountPoint()])
|
||||
|
@ -456,8 +455,8 @@ class CryptoBoxContainer:
|
|||
stdout = devnull,
|
||||
stderr = subprocess.PIPE,
|
||||
args = [
|
||||
self.Progs["super"],
|
||||
self.Progs["CryptoBoxRootActions"],
|
||||
self.cbox.prefs["Programs"]["super"],
|
||||
self.cbox.prefs["Programs"]["CryptoBoxRootActions"],
|
||||
"umount",
|
||||
self.__getMountPoint()])
|
||||
proc.wait()
|
||||
|
@ -483,7 +482,7 @@ class CryptoBoxContainer:
|
|||
stdout = devnull,
|
||||
stderr = subprocess.PIPE,
|
||||
args = [
|
||||
self.Progs["mkfs-data"],
|
||||
self.cbox.prefs["Programs"]["mkfs-data"],
|
||||
self.device])
|
||||
proc.wait()
|
||||
if proc.returncode != 0:
|
||||
|
@ -513,8 +512,8 @@ class CryptoBoxContainer:
|
|||
stdout = devnull,
|
||||
stderr = subprocess.PIPE,
|
||||
args = [
|
||||
self.Progs["super"],
|
||||
self.Progs["CryptoBoxRootActions"],
|
||||
self.cbox.prefs["Programs"]["super"],
|
||||
self.cbox.prefs["Programs"]["CryptoBoxRootActions"],
|
||||
"cryptsetup",
|
||||
"luksFormat",
|
||||
self.device,
|
||||
|
@ -534,8 +533,8 @@ class CryptoBoxContainer:
|
|||
stdout = devnull,
|
||||
stderr = subprocess.PIPE,
|
||||
args = [
|
||||
self.Progs["super"],
|
||||
self.Progs["CryptoBoxRootActions"],
|
||||
self.cbox.prefs["Programs"]["super"],
|
||||
self.cbox.prefs["Programs"]["CryptoBoxRootActions"],
|
||||
"cryptsetup",
|
||||
"luksOpen",
|
||||
self.device,
|
||||
|
@ -554,7 +553,7 @@ class CryptoBoxContainer:
|
|||
stdout = devnull,
|
||||
stderr = subprocess.PIPE,
|
||||
args = [
|
||||
self.Progs["mkfs-data"],
|
||||
self.cbox.prefs["Programs"]["mkfs-data"],
|
||||
os.path.join(self.__dmDir, self.name)])
|
||||
proc.wait()
|
||||
"remove the mapping - for every exit status"
|
||||
|
|
|
@ -78,7 +78,7 @@ def call_plugin(args):
|
|||
proc = subprocess.Popen(
|
||||
shell = False,
|
||||
args = args)
|
||||
proc.communicate()
|
||||
proc.wait()
|
||||
return proc.returncode == 0
|
||||
|
||||
|
||||
|
@ -169,7 +169,7 @@ def run_cryptsetup(args):
|
|||
proc = subprocess.Popen(
|
||||
shell = False,
|
||||
args = cs_args)
|
||||
proc.communicate()
|
||||
proc.wait()
|
||||
## chown the devmapper block device to the cryptobox user
|
||||
if (proc.returncode == 0) and (action == "luksOpen"):
|
||||
os.chown(os.path.join(os.path.sep, "dev", "mapper", destination), os.getuid(), os.getgid())
|
||||
|
@ -214,10 +214,23 @@ def run_mount(args):
|
|||
proc = subprocess.Popen(
|
||||
shell = False,
|
||||
args = [allowedProgs["mount"], device, destination])
|
||||
proc.communicate()
|
||||
# restore previous real uid
|
||||
os.setuid(savedUID)
|
||||
return proc.returncode == 0
|
||||
proc.wait()
|
||||
## return in case of an error
|
||||
if proc.returncode != 0:
|
||||
return False
|
||||
## chown the mounted directory - otherwise it will not be writeable for
|
||||
## the cryptobox user (at least for the configuration partition this is
|
||||
## absolutely necessary) TODO: check if this is valid for data, too
|
||||
(trustUserName, trustUID, groupsOfTrustUser) = getUserInfo(savedUID)
|
||||
try:
|
||||
os.chown(destination, trustUID, groupsOfTrustUser[0])
|
||||
except OSError, errMsg:
|
||||
sys.stderr.write("could not chown the mount destination (%s) to the specified user (%d/%d): %s\n" % (destination, trustUID, groupsOfTrustUser[0], errMsg))
|
||||
sys.stderr.write("UID: %d\n" % (os.geteuid(),))
|
||||
return False
|
||||
## BEWARE: it would be nice, if we could restore the previous uid (not euid) but
|
||||
## this would also override the euid (see 'man 2 setuid') - any ideas?
|
||||
return True
|
||||
|
||||
|
||||
def run_umount(args):
|
||||
|
@ -242,7 +255,7 @@ def run_umount(args):
|
|||
proc = subprocess.Popen(
|
||||
shell = False,
|
||||
args = [allowedProgs["umount"], "-l", destination])
|
||||
proc.communicate()
|
||||
proc.wait()
|
||||
# restore previous real uid
|
||||
os.setuid(savedUID)
|
||||
return proc.returncode == 0
|
||||
|
|
|
@ -5,6 +5,7 @@ except:
|
|||
raise CryptoBoxExceptions.CBEnvironmentError("couldn't import 'validate'! Try 'apt-get install python-formencode'.")
|
||||
import os
|
||||
import CryptoBoxExceptions
|
||||
import subprocess
|
||||
try:
|
||||
import configobj ## needed for reading and writing of the config file
|
||||
except:
|
||||
|
@ -65,6 +66,92 @@ class CryptoBoxSettings:
|
|||
return ok
|
||||
|
||||
|
||||
def isWriteable(self):
|
||||
return os.access(self.prefs["Locations"]["SettingsDir"], os.W_OK)
|
||||
|
||||
|
||||
def getActivePartition(self):
|
||||
settings_dir = self.prefs["Locations"]["SettingsDir"]
|
||||
if not os.path.ismount(settings_dir): return None
|
||||
for line in file("/proc/mounts"):
|
||||
fields = line.split(" ")
|
||||
mount_dir = fields[1]
|
||||
try:
|
||||
if os.path.samefile(mount_dir, settings_dir): return fields[0]
|
||||
except OSError:
|
||||
pass
|
||||
## no matching entry found
|
||||
return None
|
||||
|
||||
|
||||
def mountPartition(self):
|
||||
if self.isWriteable():
|
||||
self.log.warn("mountConfigPartition: configuration is already writeable - mounting anyway")
|
||||
if self.getActivePartition():
|
||||
self.log.warn("mountConfigPartition: configuration partition already mounted - not mounting again")
|
||||
return False
|
||||
confPartitions = self.getAvailablePartitions()
|
||||
if not confPartitions:
|
||||
self.log.error("no configuration partitions found - you have to create it first")
|
||||
return False
|
||||
partition = confPartitions[0]
|
||||
proc = subprocess.Popen(
|
||||
shell = False,
|
||||
stdout = subprocess.PIPE,
|
||||
stderr = subprocess.PIPE,
|
||||
args = [
|
||||
self.prefs["Programs"]["super"],
|
||||
self.prefs["Programs"]["CryptoBoxRootActions"],
|
||||
"mount",
|
||||
partition,
|
||||
self.prefs["Locations"]["SettingsDir"]])
|
||||
(stdout, stderr) = proc.communicate()
|
||||
if proc.returncode != 0:
|
||||
self.log.error("failed to mount the configuration partition: %s" % partition)
|
||||
self.log.error("output of mount: %s" % (stderr,))
|
||||
return False
|
||||
self.log.info("configuration partition mounted: %s" % partition)
|
||||
return True
|
||||
|
||||
|
||||
def umountPartition(self):
|
||||
if not self.getActivePartition():
|
||||
self.log.warn("umountConfigPartition: no configuration partition mounted")
|
||||
return False
|
||||
proc = subprocess.Popen(
|
||||
shell = False,
|
||||
stdout = subprocess.PIPE,
|
||||
stderr = subprocess.PIPE,
|
||||
args = [
|
||||
self.prefs["Programs"]["super"],
|
||||
self.prefs["Programs"]["CryptoBoxRootActions"],
|
||||
"umount",
|
||||
self.prefs["Locations"]["SettingsDir"]])
|
||||
(stdout, stderr) = proc.communicate()
|
||||
if proc.returncode != 0:
|
||||
self.log.error("failed to unmount the configuration partition")
|
||||
self.log.error("output of mount: %s" % (stderr,))
|
||||
return False
|
||||
self.log.info("configuration partition unmounted")
|
||||
return True
|
||||
|
||||
|
||||
def getAvailablePartitions(self):
|
||||
"""returns a sequence of found config partitions"""
|
||||
proc = subprocess.Popen(
|
||||
shell = False,
|
||||
stdout = subprocess.PIPE,
|
||||
args = [
|
||||
self.prefs["Programs"]["blkid"],
|
||||
"-c", os.path.devnull,
|
||||
"-t", "LABEL=%s" % self.prefs["Main"]["ConfigVolumeLabel"] ])
|
||||
(output, error) = proc.communicate()
|
||||
if output:
|
||||
return [e.strip().split(":",1)[0] for e in output.splitlines()]
|
||||
else:
|
||||
return []
|
||||
|
||||
|
||||
def __getitem__(self, key):
|
||||
"""redirect all requests to the 'prefs' attribute"""
|
||||
return self.prefs[key]
|
||||
|
@ -282,6 +369,7 @@ Language = string(min=1, default="en")
|
|||
cryptsetup = fileExecutable(default="/sbin/cryptsetup")
|
||||
mkfs-data = fileExecutable(default="/sbin/mkfs.ext3")
|
||||
blkid = fileExecutable(default="/sbin/blkid")
|
||||
blockdev = fileExecutable(default="/sbin/blockdev")
|
||||
mount = fileExecutable(default="/bin/mount")
|
||||
umount = fileExecutable(default="/bin/umount")
|
||||
super = fileExecutable(default="/usr/bin/super")
|
||||
|
|
|
@ -5,6 +5,16 @@ import Plugins
|
|||
from CryptoBoxExceptions import *
|
||||
import cherrypy
|
||||
import types
|
||||
import os
|
||||
|
||||
try:
|
||||
import neo_cgi, neo_util, neo_cs
|
||||
except ImportError:
|
||||
errorMsg = "Could not import clearsilver module. Try 'apt-get install python-clearsilver'."
|
||||
self.log.error(errorMsg)
|
||||
sys.stderr.write(errorMsg)
|
||||
raise ImportError, errorMsg
|
||||
|
||||
|
||||
|
||||
class WebInterfacePlugins:
|
||||
|
@ -115,6 +125,7 @@ class WebInterfaceSites:
|
|||
def index(self, weblang=""):
|
||||
self.__resetDataset()
|
||||
self.__setWebLang(weblang)
|
||||
self.__checkEnvironment()
|
||||
## do not forget the language!
|
||||
param_dict = {"weblang":weblang}
|
||||
## render "disks" plugin by default
|
||||
|
@ -124,6 +135,7 @@ class WebInterfaceSites:
|
|||
def return_plugin_action(self, plugin):
|
||||
def handler(self, **args):
|
||||
self.__resetDataset()
|
||||
self.__checkEnvironment()
|
||||
args_orig = dict(args)
|
||||
try:
|
||||
self.__setWebLang(args["weblang"])
|
||||
|
@ -180,6 +192,7 @@ class WebInterfaceSites:
|
|||
def test(self, weblang=""):
|
||||
self.__resetDataset()
|
||||
self.__setWebLang(weblang)
|
||||
self.__checkEnvironment()
|
||||
return "test passed"
|
||||
|
||||
|
||||
|
@ -197,6 +210,36 @@ class WebInterfaceSites:
|
|||
|
||||
|
||||
##################### input checker ##########################
|
||||
|
||||
def __checkEnvironment(self):
|
||||
"""here we should place all interesting checks to inform the user of problems
|
||||
|
||||
examples are: non-https, readonly-config, ...
|
||||
"""
|
||||
if not self.cbox.prefs.isWriteable():
|
||||
self.dataset["Data.EnvironmentWarning"] = "ReadOnlyConfig"
|
||||
# TODO: turn this on soon (add "not") - for now it is annoying
|
||||
if self.__checkHTTPS():
|
||||
self.dataset["Data.EnvironmentWarning"] = "NoSSL"
|
||||
|
||||
|
||||
def __checkHTTPS(self):
|
||||
## check the request scheme
|
||||
if cherrypy.request.scheme == "https": return True
|
||||
## check an environment setting - this is quite common behind proxies
|
||||
try:
|
||||
if os.environ["HTTPS"]: return True
|
||||
except KeyError:
|
||||
pass
|
||||
## check http header TODO (check pound for the name)
|
||||
try:
|
||||
if cherrypy.request.headers["TODO"]: return True
|
||||
except KeyError:
|
||||
pass
|
||||
## the connection seems to be unencrypted
|
||||
return False
|
||||
|
||||
|
||||
def __setWebLang(self, value):
|
||||
guess = value
|
||||
availLangs = self.cbox.getAvailableLanguages()
|
||||
|
@ -229,7 +272,6 @@ class WebInterfaceSites:
|
|||
"""guess the preferred language of the user (as sent by the browser)
|
||||
take the first language, that is part of 'availLangs'
|
||||
"""
|
||||
import cherrypy
|
||||
try:
|
||||
pref_lang_header = cherrypy.request.headers["Accept-Language"]
|
||||
except KeyError:
|
||||
|
@ -277,7 +319,6 @@ class WebInterfaceSites:
|
|||
|
||||
|
||||
def __getLanguageData(self, web_lang="en"):
|
||||
import neo_cgi, neo_util, os
|
||||
default_lang = "en"
|
||||
conf_lang = self.prefs["WebSettings"]["Language"]
|
||||
hdf = neo_util.HDF()
|
||||
|
@ -302,15 +343,6 @@ class WebInterfaceSites:
|
|||
def __render(self, renderInfo, plugin=None):
|
||||
'''renders from clearsilver templates and returns the resulting html
|
||||
'''
|
||||
import os, types
|
||||
try:
|
||||
import neo_cgi, neo_util, neo_cs
|
||||
except ImportError:
|
||||
errorMsg = "Could not import clearsilver module. Try 'apt-get install python-clearsilver'."
|
||||
self.log.error(errorMsg)
|
||||
sys.stderr.write(errorMsg)
|
||||
raise ImportError, errorMsg
|
||||
|
||||
## is renderInfo a string (filename of the template) or a dictionary?
|
||||
if type(renderInfo) == types.DictType:
|
||||
template = renderInfo["template"]
|
||||
|
|
Loading…
Reference in a new issue