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:
lars 2006-11-03 14:27:19 +00:00
parent 2c350207c9
commit 0fe6d426ed
5 changed files with 180 additions and 66 deletions

View File

@ -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()

View File

@ -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"

View File

@ -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

View File

@ -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")

View File

@ -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"]