privilege dropping replaced by a separate python script for root actions

syslog support added
moved program locations to config file
removed obsolete CryptoBoxPreferences
added some requests for comments (RFC)
This commit is contained in:
lars 2006-08-21 07:41:03 +00:00
parent 975b2bb14a
commit b951efdd9c
7 changed files with 156 additions and 269 deletions

View file

@ -15,27 +15,35 @@ import os
import sys import sys
import unittest import unittest
CONF_LOCATIONS = [ "./cryptobox.conf", "~/.cryptobox.conf", "/etc/cryptobox/cryptobox.conf"] CONF_LOCATIONS = [
"./cryptobox.conf",
"~/.cryptobox.conf",
"/etc/cryptobox/cryptobox.conf"]
class CryptoBox: class CryptoBox:
'''this class rules them all! '''this class rules them all!
put things like logging, conf and oter stuff in here, put things like logging, conf and oter stuff in here,
that might be used by more classes, it will be passed on to them''' that might be used by more classes, it will be passed on to them'''
def __init__(self): def __init__(self, config_file=None):
self.__initLogging() self.__initLogging()
self.__initPreferences() self.__initPreferences(config_file)
def __initLogging(self): def __initLogging(self):
import logging import logging
# RFC: this import should be at the top of the file - or at least (for clarity) be there in a comment line [l]
'''initialises the logging system '''initialises the logging system
use it with: 'self.log.[debug|info|warning|error|critical](logmessage)' use it with: 'self.log.[debug|info|warning|error|critical](logmessage)'
from all classes the inherited from CryptoBox from all classes the inherited from CryptoBox
TODO: read the logfile from the config - this is a hen-egg problem TODO/RFC: read the logfile from the config - this is a hen-egg problem
i would prefer start logging to stdout, read the config and redirect i would prefer start logging to stdout, read the config and redirect
logging to the logfile found in the config [a] ''' logging to the logfile found in the config [a]
[l]: ok'''
## basicConfig(...) needs python >= 2.4 ## basicConfig(...) needs python >= 2.4
try: try:
logging.basicConfig(level=logging.DEBUG, logging.basicConfig(level=logging.DEBUG,
@ -49,22 +57,35 @@ class CryptoBox:
sys.stderr.write("Something with the loggingsystem went wrong. I give up.") sys.stderr.write("Something with the loggingsystem went wrong. I give up.")
sys.exit(1) sys.exit(1)
def __initPreferences(self):
try:
import configobj ## needed for reading and writing the config file
except:
self.log.error("Could't import 'configobj'! Try apt-get install python-configobj.")
sys.exit(1)
for f in CONF_LOCATIONS: def __initPreferences(self, config_file):
if os.path.exists(os.path.expanduser(f)): # RFC: this try-except should happen at the top of the script - or? [l]
conf_file = os.path.expanduser(f) try:
break import configobj ## needed for reading and writing of the config file
except:
self.log.error("Could't import 'configobj'! Try 'apt-get install python-configobj'.")
sys.exit(1)
# search for the configuration file
if config_file is None:
# no config file was specified - we will look for it in the ususal locations
conf_file_list = [os.path.expanduser(f)
for f in CONF_LOCATIONS
if os.path.exists(os.path.expanduser(f))]
if not conf_file_list:
# no possible config file found in the usual locations
self.log.error("No configuration file found - sorry!")
sys.exit(1)
config_file = conf_file_list[0]
else:
# a config file was specified (e.g. via command line)
if not os.path.exists(config_file):
self.log.error("Could not find the specified configuration file (%s)" % config_file)
sys.exit(1)
try: try:
self.cbxPrefs = configobj.ConfigObj(conf_file) self.cbxPrefs = configobj.ConfigObj(conf_file)
self.log.debug("found config: %s" % self.cbxPrefs.items()) self.log.debug("found config: %s" % self.cbxPrefs.items())
except: except:
self.log.error("Could not read configuration file. I give up.\n") self.log.error("Could not read configuration file. I give up.")
sys.exit(1) sys.exit(1)
try: try:
nameDB_file = os.path.join( nameDB_file = os.path.join(
@ -77,11 +98,16 @@ class CryptoBox:
except SyntaxError: except SyntaxError:
self.log.error("Error during parsing of name database file (%s).\n" % (nameDB_file, )) self.log.error("Error during parsing of name database file (%s).\n" % (nameDB_file, ))
sys.exit(1) sys.exit(1)
# TODO: check if nameDB file was created successfully?
# RFC: what is this method useful for?
def cbx_inheritance_test(self): def cbx_inheritance_test(self):
print "you lucky widow" print "you lucky widow"
# RFC: why should CryptoBoxProps inherit CryptoBox? [l]
# RFC: shouldn't we move all useful functions of CryptoBoxProps to CryptoBox? [l]
class CryptoBoxProps(CryptoBox): class CryptoBoxProps(CryptoBox):
'''Get and set the properties of a CryptoBox '''Get and set the properties of a CryptoBox
@ -91,23 +117,16 @@ class CryptoBoxProps(CryptoBox):
def __init__(self): def __init__(self):
'''read config and fill class variables''' '''read config and fill class variables'''
"enable it again - or remove the priv-dropping"
#if os.geteuid() != 0:
# sys.stderr.write("You need to be root to run this program!\n")
# sys.exit(1)
CryptoBox.__init__(self) CryptoBox.__init__(self)
#self.cbx_inheritance_test() #self.cbx_inheritance_test()
#print self.cbxPrefs.items() #print self.cbxPrefs.items()
#### ####
self.__cboxUID = int(self.cbxPrefs["System"]["User"])
self.__cboxGID = int(self.cbxPrefs["System"]["Group"])
self.debug = CryptoBoxLogger.CryptoBoxLogger( self.debug = CryptoBoxLogger.CryptoBoxLogger(
self.cbxPrefs["Log"]["Level"], self.cbxPrefs["Log"]["Level"],
self.cbxPrefs["Log"]["Facility"], self.cbxPrefs["Log"]["Facility"],
self.cbxPrefs["Log"]["Destination"]) self.cbxPrefs["Log"]["Destination"])
self.dropPrivileges()
self.debugMessage = self.debug.printMessage self.debugMessage = self.debug.printMessage
self.containers = [] self.containers = []
for device in self.__getAvailablePartitions(): for device in self.__getAvailablePartitions():
@ -116,7 +135,6 @@ class CryptoBoxProps(CryptoBox):
def isDeviceAllowed(self, devicename): def isDeviceAllowed(self, devicename):
"check if a device is white-listed for being used as cryptobox containers" "check if a device is white-listed for being used as cryptobox containers"
"TODO: broken!"
allowed = self.cbxPrefs["Main"]["AllowedDevices"] allowed = self.cbxPrefs["Main"]["AllowedDevices"]
if type(allowed) == types.StringType: allowed = [allowed] if type(allowed) == types.StringType: allowed = [allowed]
for a_dev in allowed: for a_dev in allowed:
@ -170,24 +188,6 @@ class CryptoBoxProps(CryptoBox):
return None return None
def dropPrivileges(self):
"change the effective uid to 'User' specified in section 'System'"
"enable it again - or remove the priv-dropping"
#if os.getuid() != os.geteuid():
# raise "PrivilegeManager", "we already dropped privileges"
os.seteuid(self.__cboxUID)
os.setegid(self.__cboxGID)
def risePrivileges(self):
"regain superuser privileges temporarily - call dropPrivileges afterwards!"
"enable it again - or remove the priv-dropping"
#if os.getuid() == os.geteuid():
# raise "PrivilegeManager", "we already have superuser privileges"
os.seteuid(os.getuid())
os.setegid(os.getgid())
""" ************ internal stuff starts here *********** """ """ ************ internal stuff starts here *********** """
def __getAvailablePartitions(self): def __getAvailablePartitions(self):
@ -310,6 +310,9 @@ DefaultCipher = aes-cbc-essiv:sha256
Level = debug Level = debug
Facility = file Facility = file
Destination = /tmp/cryptobox.log Destination = /tmp/cryptobox.log
[Programs]
blkid = /sbin/blkid
cryptsetup = /sbin/cryptsetup
""" """
def setUp(self): def setUp(self):
@ -318,19 +321,21 @@ Destination = /tmp/cryptobox.log
def tearDown(self): def tearDown(self):
if os.path.exists(self.tmpdir): os.rmdir(self.tmpdir)
if os.path.exists(self.configFile): os.remove(self.configFile) if os.path.exists(self.configFile): os.remove(self.configFile)
if os.path.exists(self.logFile): os.remove(self.logFile) if os.path.exists(self.logFile): os.remove(self.logFile)
if os.path.exists(self.nameDBFile): os.remove(self.nameDBFile) if os.path.exists(self.nameDBFile): os.remove(self.nameDBFile)
if os.path.exists(self.tmpdir): os.rmdir(self.tmpdir)
def testConfigFile(self): def testConfigFile(self):
# RFC: which 'age' did a commit with a broken unittest? [l]
CryptoBoxProps() CryptoBoxProps()
self.assertTrue(os.path.exists(self.nameDBFile)) self.assertTrue(os.path.exists(self.nameDBFile))
self.assertTrue(os.path.exists(self.logFile)) self.assertTrue(os.path.exists(self.logFile))
def testDeviceCheck(self): def testDeviceCheck(self):
# RFC: dito [l]
cb = CryptoBoxProps() cb = CryptoBoxProps()
self.assertTrue(cb.isDeviceAllowed("/dev/loop")) self.assertTrue(cb.isDeviceAllowed("/dev/loop"))
self.assertTrue(cb.isDeviceAllowed("/dev/loop1")) self.assertTrue(cb.isDeviceAllowed("/dev/loop1"))
@ -339,10 +344,10 @@ Destination = /tmp/cryptobox.log
self.assertFalse(cb.isDeviceAllowed("/dev/loopa/../hda")) self.assertFalse(cb.isDeviceAllowed("/dev/loopa/../hda"))
self.assertTrue(cb.isDeviceAllowed("/dev/usb/../loop1")) self.assertTrue(cb.isDeviceAllowed("/dev/usb/../loop1"))
self.assertFalse(cb.isDeviceAllowed("/")) self.assertFalse(cb.isDeviceAllowed("/"))
"a lot of tests are still missing - how can we provide a prepared environment?" "a lot of tests are still missing - how can we provide a prepared environment?"
# ********************* run unittest **************************** # ********************* run unittest ****************************
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()

View file

@ -19,15 +19,6 @@ import re
class CryptoBoxContainer: class CryptoBoxContainer:
Progs = {
"cryptsetup":"/sbin/cryptsetup",
"mkfs-data":"/sbin/mkfs.ext3",
"mkfs-config":"/sbin/mkfs.ext2",
"blkid":"/sbin/blkid",
"mount":"/bin/mount",
"umount":"/bin/umount"}
Types = { Types = {
"unused":0, "unused":0,
"plain":1, "plain":1,
@ -47,8 +38,7 @@ class CryptoBoxContainer:
self.device = device self.device = device
self.cbox = cbox self.cbox = cbox
self.debugMessage = self.cbox.debugMessage self.debugMessage = self.cbox.debugMessage
self.__dropPrivileges = self.cbox.dropPrivileges self.Progs = self.cbox.cbxPrefs["Programs"]
self.__risePrivileges = self.cbox.risePrivileges
self.__resetObject() self.__resetObject()
@ -119,7 +109,6 @@ class CryptoBoxContainer:
"remove any potential open luks mapping" "remove any potential open luks mapping"
self.__umountLuks() self.__umountLuks()
"create the luks header" "create the luks header"
self.__risePrivileges()
proc = subprocess.Popen( proc = subprocess.Popen(
shell = False, shell = False,
stdin = subprocess.PIPE, stdin = subprocess.PIPE,
@ -131,7 +120,6 @@ class CryptoBoxContainer:
"luksAddKey", "luksAddKey",
self.device]) self.device])
proc.stdin.write("%s\n%s" % (oldpw, newpw)) proc.stdin.write("%s\n%s" % (oldpw, newpw))
self.__dropPrivileges()
(output, errout) = proc.communicate() (output, errout) = proc.communicate()
if proc.returncode != 0: if proc.returncode != 0:
errorMsg = "Could not add a new luks key: %s - %s" % (output.strip(), errout.strip(), ) errorMsg = "Could not add a new luks key: %s - %s" % (output.strip(), errout.strip(), )
@ -143,7 +131,6 @@ class CryptoBoxContainer:
else: else:
raise "ChangePasswordError", "could not get the old key slot" raise "ChangePasswordError", "could not get the old key slot"
"remove the old key" "remove the old key"
self.__risePrivileges()
proc = subprocess.Popen( proc = subprocess.Popen(
shell = False, shell = False,
stdin = None, stdin = None,
@ -156,7 +143,6 @@ class CryptoBoxContainer:
self.device, self.device,
"%d" % (keyslot, )]) "%d" % (keyslot, )])
proc.wait() proc.wait()
self.__dropPrivileges()
if proc.returncode != 0: if proc.returncode != 0:
errorMsg = "Could not remove the old luks key: %s" % (proc.stderr.read().strip(), ) errorMsg = "Could not remove the old luks key: %s" % (proc.stderr.read().strip(), )
self.debugMessage(CryptoBoxLogger.DebugLevels["error"], errorMsg) self.debugMessage(CryptoBoxLogger.DebugLevels["error"], errorMsg)
@ -207,7 +193,6 @@ class CryptoBoxContainer:
self.debugMessage( self.debugMessage(
CryptoBoxLogger.DebugLevels["warn"], CryptoBoxLogger.DebugLevels["warn"],
"Could not open %s" % (os.devnull, )) "Could not open %s" % (os.devnull, ))
self.__risePrivileges()
proc = subprocess.Popen( proc = subprocess.Popen(
shell=False, shell=False,
stdin=None, stdin=None,
@ -221,7 +206,6 @@ class CryptoBoxContainer:
self.device]) self.device])
proc.wait() proc.wait()
result = proc.stdout.read().strip() result = proc.stdout.read().strip()
self.__dropPrivileges()
if proc.returncode != 0: if proc.returncode != 0:
self.debugMessage( self.debugMessage(
CryptoBoxLogger.DebugLevels["warn"], CryptoBoxLogger.DebugLevels["warn"],
@ -252,7 +236,6 @@ class CryptoBoxContainer:
self.debugMessage( self.debugMessage(
CryptoBoxLogger.DebugLevels["warn"], CryptoBoxLogger.DebugLevels["warn"],
"Could not open %s" % (os.devnull, )) "Could not open %s" % (os.devnull, ))
self.__risePrivileges()
proc = subprocess.Popen( proc = subprocess.Popen(
shell=False, shell=False,
stdin=None, stdin=None,
@ -266,7 +249,6 @@ class CryptoBoxContainer:
self.device]) self.device])
proc.wait() proc.wait()
output = proc.stdout.read().strip() output = proc.stdout.read().strip()
self.__dropPrivileges()
if proc.returncode != 0: if proc.returncode != 0:
self.debugMessage( self.debugMessage(
CryptoBoxLogger.DebugLevels["warn"], CryptoBoxLogger.DebugLevels["warn"],
@ -285,7 +267,6 @@ class CryptoBoxContainer:
self.debugMessage( self.debugMessage(
CryptoBoxLogger.DebugLevels["warn"], CryptoBoxLogger.DebugLevels["warn"],
"Could not open %s" % (os.devnull, )) "Could not open %s" % (os.devnull, ))
self.__risePrivileges()
proc = subprocess.Popen( proc = subprocess.Popen(
shell = False, shell = False,
stdin = None, stdin = None,
@ -297,7 +278,6 @@ class CryptoBoxContainer:
"isLuks", "isLuks",
self.device]) self.device])
proc.wait() proc.wait()
self.__dropPrivileges()
devnull.close() devnull.close()
return proc.returncode == 0 return proc.returncode == 0
@ -326,7 +306,6 @@ class CryptoBoxContainer:
errorMsg = "Could not create mountpoint (%s)" % (self.__getMountPoint(), ) errorMsg = "Could not create mountpoint (%s)" % (self.__getMountPoint(), )
self.debugMessage("error", errorMsg) self.debugMessage("error", errorMsg)
raise "MountError", errorMsg raise "MountError", errorMsg
self.__risePrivileges()
proc = subprocess.Popen( proc = subprocess.Popen(
shell = False, shell = False,
stdin = subprocess.PIPE, stdin = subprocess.PIPE,
@ -340,12 +319,10 @@ class CryptoBoxContainer:
self.name]) self.name])
proc.stdin.write(password) proc.stdin.write(password)
(output, errout) = proc.communicate() (output, errout) = proc.communicate()
self.__dropPrivileges()
if proc.returncode != 0: if proc.returncode != 0:
errorMsg = "Could not open the luks mapping: %s" % (errout.strip(), ) errorMsg = "Could not open the luks mapping: %s" % (errout.strip(), )
self.debugMessage(CryptoBoxLogger.DebugLevels["warn"], errorMsg) self.debugMessage(CryptoBoxLogger.DebugLevels["warn"], errorMsg)
raise "MountError", errorMsg raise "MountError", errorMsg
self.__risePrivileges()
proc = subprocess.Popen( proc = subprocess.Popen(
shell = False, shell = False,
stdin = None, stdin = None,
@ -356,7 +333,6 @@ class CryptoBoxContainer:
os.path.join(self.__dmDir, self.name), os.path.join(self.__dmDir, self.name),
self.__getMountPoint()]) self.__getMountPoint()])
proc.wait() proc.wait()
self.__dropPrivileges()
if proc.returncode != 0: if proc.returncode != 0:
errorMsg = "Could not mount the filesystem: %s" % (proc.stderr.read().strip(), ) errorMsg = "Could not mount the filesystem: %s" % (proc.stderr.read().strip(), )
self.debugMessage(CryptoBoxLogger.DebugLevels["warn"], errorMsg) self.debugMessage(CryptoBoxLogger.DebugLevels["warn"], errorMsg)
@ -374,7 +350,6 @@ class CryptoBoxContainer:
CryptoBoxLogger.DebugLevels["warn"], CryptoBoxLogger.DebugLevels["warn"],
"Could not open %s" % (os.devnull, )) "Could not open %s" % (os.devnull, ))
if self.isMounted(): if self.isMounted():
self.__risePrivileges()
proc = subprocess.Popen( proc = subprocess.Popen(
shell = False, shell = False,
stdin = None, stdin = None,
@ -382,13 +357,11 @@ class CryptoBoxContainer:
stderr = subprocess.PIPE, stderr = subprocess.PIPE,
args = [self.Progs["umount"], "-l", self.__getMountPoint()]) args = [self.Progs["umount"], "-l", self.__getMountPoint()])
proc.wait() proc.wait()
self.__dropPrivileges()
if proc.returncode != 0: if proc.returncode != 0:
errorMsg = "Could not umount the filesystem: %s" % (proc.stderr.read().strip(), ) errorMsg = "Could not umount the filesystem: %s" % (proc.stderr.read().strip(), )
self.debugMessage(CryptoBoxLogger.DebugLevels["warn"], errorMsg) self.debugMessage(CryptoBoxLogger.DebugLevels["warn"], errorMsg)
raise "MountError", errorMsg raise "MountError", errorMsg
if os.path.exists(os.path.join(self.__dmDir, self.name)): if os.path.exists(os.path.join(self.__dmDir, self.name)):
self.__risePrivileges()
proc = subprocess.Popen( proc = subprocess.Popen(
shell = False, shell = False,
stdin = None, stdin = None,
@ -400,7 +373,6 @@ class CryptoBoxContainer:
"luksClose", "luksClose",
self.name]) self.name])
proc.wait() proc.wait()
self.__dropPrivileges()
if proc.returncode != 0: if proc.returncode != 0:
errorMsg = "Could not remove the luks mapping: %s" % (proc.stderr.read().strip(), ) errorMsg = "Could not remove the luks mapping: %s" % (proc.stderr.read().strip(), )
self.debugMessage(CryptoBoxLogger.DebugLevels["warn"], errorMsg) self.debugMessage(CryptoBoxLogger.DebugLevels["warn"], errorMsg)
@ -425,7 +397,6 @@ class CryptoBoxContainer:
errorMsg = "Could not create mountpoint (%s)" % (self.__getMountPoint(), ) errorMsg = "Could not create mountpoint (%s)" % (self.__getMountPoint(), )
self.debugMessage("error", errorMsg) self.debugMessage("error", errorMsg)
raise "MountError", errorMsg raise "MountError", errorMsg
self.__risePrivileges()
proc = subprocess.Popen( proc = subprocess.Popen(
shell = False, shell = False,
stdin = None, stdin = None,
@ -436,7 +407,6 @@ class CryptoBoxContainer:
self.device, self.device,
self.__getMountPoint()]) self.__getMountPoint()])
proc.wait() proc.wait()
self.__dropPrivileges()
if proc.returncode != 0: if proc.returncode != 0:
errorMsg = "Could not mount the filesystem: %s" % (proc.stderr.read().strip(), ) errorMsg = "Could not mount the filesystem: %s" % (proc.stderr.read().strip(), )
self.debugMessage(CryptoBoxLogger.DebugLevels["warn"], errorMsg) self.debugMessage(CryptoBoxLogger.DebugLevels["warn"], errorMsg)
@ -454,7 +424,6 @@ class CryptoBoxContainer:
CryptoBoxLogger.DebugLevels["warn"], CryptoBoxLogger.DebugLevels["warn"],
"Could not open %s" % (os.devnull, )) "Could not open %s" % (os.devnull, ))
if self.isMounted(): if self.isMounted():
self.__risePrivileges()
proc = subprocess.Popen( proc = subprocess.Popen(
shell = False, shell = False,
stdin = None, stdin = None,
@ -465,7 +434,6 @@ class CryptoBoxContainer:
"-l", "-l",
self.__getMountPoint()]) self.__getMountPoint()])
proc.wait() proc.wait()
self.__dropPrivileges()
if proc.returncode != 0: if proc.returncode != 0:
errorMsg = "Could not umount the filesystem: %s" % (proc.stderr.read().strip(), ) errorMsg = "Could not umount the filesystem: %s" % (proc.stderr.read().strip(), )
self.debugMessage(CryptoBoxLogger.DebugLevels["warn"], errorMsg) self.debugMessage(CryptoBoxLogger.DebugLevels["warn"], errorMsg)
@ -485,7 +453,6 @@ class CryptoBoxContainer:
self.debugMessage( self.debugMessage(
CryptoBoxLogger.DebugLevels["warn"], CryptoBoxLogger.DebugLevels["warn"],
"Could not open %s" % (os.devnull, )) "Could not open %s" % (os.devnull, ))
self.__risePrivileges()
proc = subprocess.Popen( proc = subprocess.Popen(
shell = False, shell = False,
stdin = None, stdin = None,
@ -495,7 +462,6 @@ class CryptoBoxContainer:
self.Progs["mkfs-data"], self.Progs["mkfs-data"],
self.device]) self.device])
proc.wait() proc.wait()
self.__dropPrivileges()
if proc.returncode != 0: if proc.returncode != 0:
errorMsg = "Could not create the filesystem: %s" % (proc.stderr.read().strip(), ) errorMsg = "Could not create the filesystem: %s" % (proc.stderr.read().strip(), )
self.debugMessage(CryptoBoxLogger.DebugLevels["error"], errorMsg) self.debugMessage(CryptoBoxLogger.DebugLevels["error"], errorMsg)
@ -520,7 +486,6 @@ class CryptoBoxContainer:
"remove any potential open luks mapping" "remove any potential open luks mapping"
self.__umountLuks() self.__umountLuks()
"create the luks header" "create the luks header"
self.__risePrivileges()
proc = subprocess.Popen( proc = subprocess.Popen(
shell = False, shell = False,
stdin = subprocess.PIPE, stdin = subprocess.PIPE,
@ -535,13 +500,11 @@ class CryptoBoxContainer:
self.device]) self.device])
proc.stdin.write(password) proc.stdin.write(password)
(output, errout) = proc.communicate() (output, errout) = proc.communicate()
self.__dropPrivileges()
if proc.returncode != 0: if proc.returncode != 0:
errorMsg = "Could not create the luks header: %s" % (errout.strip(), ) errorMsg = "Could not create the luks header: %s" % (errout.strip(), )
self.debugMessage("error", errorMsg) self.debugMessage("error", errorMsg)
raise "CreateError", errorMsg raise "CreateError", errorMsg
"open the luks container for mkfs" "open the luks container for mkfs"
self.__risePrivileges()
proc = subprocess.Popen( proc = subprocess.Popen(
shell = False, shell = False,
stdin = subprocess.PIPE, stdin = subprocess.PIPE,
@ -555,13 +518,11 @@ class CryptoBoxContainer:
self.name]) self.name])
proc.stdin.write(password) proc.stdin.write(password)
(output, errout) = proc.communicate() (output, errout) = proc.communicate()
self.__dropPrivileges()
if proc.returncode != 0: if proc.returncode != 0:
errorMsg = "Could not open the new luks mapping: %s" % (errout.strip(), ) errorMsg = "Could not open the new luks mapping: %s" % (errout.strip(), )
self.debugMessage(CryptoBoxLogger.DebugLevels["error"], errorMsg) self.debugMessage(CryptoBoxLogger.DebugLevels["error"], errorMsg)
raise "CreateError", errorMsg raise "CreateError", errorMsg
"make the filesystem" "make the filesystem"
self.__risePrivileges()
proc = subprocess.Popen( proc = subprocess.Popen(
shell = False, shell = False,
stdin = None, stdin = None,
@ -571,7 +532,6 @@ class CryptoBoxContainer:
self.Progs["mkfs-data"], self.Progs["mkfs-data"],
os.path.join(self.__dmDir, self.name)]) os.path.join(self.__dmDir, self.name)])
proc.wait() proc.wait()
self.__dropPrivileges()
"remove the mapping - for every exit status" "remove the mapping - for every exit status"
self.__umountLuks() self.__umountLuks()
if proc.returncode != 0: if proc.returncode != 0:

View file

@ -1,8 +1,10 @@
''' '''
manages logging events of the CryptoBox manages logging events of the CryptoBox
''' '''
import sys import sys
import os import os
import syslog
import unittest import unittest
class CryptoBoxLogger: class CryptoBoxLogger:
@ -10,28 +12,35 @@ class CryptoBoxLogger:
handles logging events and prints them e.g. to a logfile handles logging events and prints them e.g. to a logfile
''' '''
DebugLevels = {"debug":0, "info":3, "warn":6, "error":9} DebugLevels = {
DebugFacilities = {"file":0} "debug": syslog.LOG_DEBUG,
"info": syslog.LOG_INFO,
"notice": syslog.LOG_NOTICE,
"warn": syslog.LOG_WARNING,
"error": syslog.LOG_ERR,
"crit": syslog.LOG_CRIT,
"alert": syslog.LOG_ALERT,
"emerg": syslog.LOG_EMERG}
DebugDestinations = {"file":0, "syslog":1}
def __init__(self, level, facility, destination=None): def __init__(self, level, destination, args=None):
"""create a CryptoBoxLogger object and connect it to an output facility """create a CryptoBoxLogger object and connect it to an output destination
level: an integer (0..9) or string ('debug', 'info', 'warn' or 'error')
facility: for now only 'file'
destination: e.g. the name of the logfile or syslog facility
level: string (debug/info/notice/warn/error/crit/alert/emerg) or syslog level
destination: the string "file" or "syslog"
args: e.g. the name of the logfile or syslog facility
""" """
try: try:
try: try:
facility = int(facility) destination = int(destination)
except Exception: except Exception:
try: try:
facility = self.DebugFacilities[facility] destination = self.DebugDestinations[destination]
except KeyError: except KeyError:
raise "LoggerError" raise "LoggerError"
if (facility != 0): raise "LoggerError" if not destination in self.DebugDestinations.values(): raise "LoggerError"
except "LoggerError": except "LoggerError":
errorMsg = "Invalid debug facility: %s" % facility errorMsg = "Invalid debug destination: %s" % destination
sys.stderr.write(errorMsg + "\n") sys.stderr.write(errorMsg + "\n")
raise "LoggerError", errorMsg raise "LoggerError", errorMsg
try: try:
@ -42,16 +51,16 @@ class CryptoBoxLogger:
level = self.DebugLevels[level] level = self.DebugLevels[level]
except KeyError: except KeyError:
raise "LoggerError" raise "LoggerError"
if (level < 0) or (level > 9): raise "LoggerError" if not level in self.DebugLevels.values(): raise "LoggerError"
except "LoggerError": except "LoggerError":
errorMsg = "Invalid debug level: %s" % level errorMsg = "Invalid debug level: %s" % level
sys.stderr.write(errorMsg + "\n") sys.stderr.write(errorMsg + "\n")
raise "LoggerError", errorMsg raise "LoggerError", errorMsg
self.debug_level = level self.debug_level = level
if facility == self.DebugFacilities["file"]: if destination == self.DebugDestinations["file"]:
self.logFunc = self.message2file self.logFunc = self.message2file
if destination is not None: if args is not None:
self.logFile = destination self.logFile = args
else: else:
self.logFile = '/var/log/cryptobox.log' self.logFile = '/var/log/cryptobox.log'
try: try:
@ -61,7 +70,12 @@ class CryptoBoxLogger:
errorMsg ="Unable to open logfile (%s) for writing." % (self.logFile,) errorMsg ="Unable to open logfile (%s) for writing." % (self.logFile,)
sys.stderr.write(errorMsg + "\n") sys.stderr.write(errorMsg + "\n")
raise "LoggerError", errorMsg raise "LoggerError", errorMsg
elif destination == self.DebugDestinations["syslog"]:
self.logFunc = self.message2syslog
if args is None:
syslog.openlog("CryptoBox", 0, syslog.LOG_USER)
else:
syslog.openlog("CryptoBox", 0, args)
else: else:
errorMsg = "Invalid logging facility: %d." % (facility, ) errorMsg = "Invalid logging facility: %d." % (facility, )
sys.stderr.write(errorMsg + "\n") sys.stderr.write(errorMsg + "\n")
@ -80,7 +94,7 @@ class CryptoBoxLogger:
errorMsg = "Invalid debug level: %s" % msg_level errorMsg = "Invalid debug level: %s" % msg_level
sys.stderr.write(errorMsg + "\n") sys.stderr.write(errorMsg + "\n")
raise "LoggerError", errorMsg raise "LoggerError", errorMsg
if (msg_level < 0) or (msg_level > 9): if not msg_level in self.DebugLevels.values():
errorMsg = "Invalid debug level: %s" % msg_level errorMsg = "Invalid debug level: %s" % msg_level
sys.stderr.write(errorMsg + "\n") sys.stderr.write(errorMsg + "\n")
raise "LoggerError", errorMsg raise "LoggerError", errorMsg
@ -88,15 +102,16 @@ class CryptoBoxLogger:
errorMsg = "Empty debug message - this is not allowed" errorMsg = "Empty debug message - this is not allowed"
sys.stderr.write(errorMsg + "\n") sys.stderr.write(errorMsg + "\n")
raise "LoggerError", errorMsg raise "LoggerError", errorMsg
if msg_level >= self.debug_level: if msg_level <= self.debug_level:
self.logFunc("[CryptoBox] - %s\n" % (text, )) self.logFunc(text, msg_level)
def message2file(self, text): def message2file(self, text, level):
# "level" gets ignored (but syslog needs it)
try: try:
log_sock = open(self.logFile, "a") log_sock = open(self.logFile, "a")
try: try:
log_sock.writelines(text) log_sock.writelines("[CryptoBox] - %s\n" % (text, ))
log_sock.close() log_sock.close()
return return
except IOError: except IOError:
@ -105,10 +120,18 @@ class CryptoBoxLogger:
raise "LoggerError", errorMsg raise "LoggerError", errorMsg
except IOError: except IOError:
errorMsg = "Unable to open logfile (%s) for writing." % (self.logFile, ) errorMsg = "Unable to open logfile (%s) for writing." % (self.logFile, )
sys.stderr.write(errorMsg + "\n") sys.stderr.write("[CryptoBox] - %s\n" % (errorMsg, ))
raise "LoggerError", errorMsg raise "LoggerError", errorMsg
def message2syslog(self, text, level):
syslog_level = [self.DebugLevels[e]
for e in self.DebugLevels.keys()
if self.DebugLevels[e] == level
][0]
syslog.syslog(syslog_level, text)
# ********************* test class ********************** # ********************* test class **********************
class CryptoBoxLoggerTest(unittest.TestCase): class CryptoBoxLoggerTest(unittest.TestCase):
@ -118,47 +141,60 @@ class CryptoBoxLoggerTest(unittest.TestCase):
def setUp(self): def setUp(self):
if os.path.exists(self.logFile): os.remove(self.logFile) if os.path.exists(self.logFile): os.remove(self.logFile)
def tearDown(self): def tearDown(self):
if os.path.exists(self.logFile): os.remove(self.logFile) if os.path.exists(self.logFile): os.remove(self.logFile)
def testInit(self): def testInit(self):
"""Initialization should fail for invalid parameters"""
try: try:
CryptoBoxLogger(0, 0) CryptoBoxLogger(syslog.LOG_ERR, 0)
except "LoggerError": except "LoggerError":
CryptoBoxLogger(0, 0, self.logFile) CryptoBoxLogger(syslog.LOG_ERR, 0, self.logFile)
os.remove(self.logFile) os.remove(self.logFile)
CryptoBoxLogger("info", "file", self.logFile) CryptoBoxLogger("info", "file", self.logFile)
self.assertRaises("LoggerError", CryptoBoxLogger, "invalid", 0, self.logFile) self.assertRaises("LoggerError", CryptoBoxLogger, "invalid", 0, self.logFile)
self.assertRaises("LoggerError", CryptoBoxLogger, 0, "invalid", self.logFile) self.assertRaises("LoggerError", CryptoBoxLogger, syslog.LOG_ERR, "invalid", self.logFile)
self.assertRaises("LoggerError", CryptoBoxLogger, 10, 0, self.logFile) self.assertRaises("LoggerError", CryptoBoxLogger, 3353, 0, self.logFile)
self.assertRaises("LoggerError", CryptoBoxLogger, -1, 0, self.logFile) self.assertRaises("LoggerError", CryptoBoxLogger, -1, 0, self.logFile)
self.assertRaises("LoggerError", CryptoBoxLogger, 0, 10, self.logFile) self.assertRaises("LoggerError", CryptoBoxLogger, syslog.LOG_INFO, self.logFile)
self.assertRaises("LoggerError", CryptoBoxLogger, 0, -1, self.logFile) self.assertRaises("LoggerError", CryptoBoxLogger, syslog.LOG_CRIT, -1, self.logFile)
self.assertRaises("LoggerError", CryptoBoxLogger, None, 0, self.logFile) self.assertRaises("LoggerError", CryptoBoxLogger, None, 0, self.logFile)
self.assertRaises("LoggerError", CryptoBoxLogger, 0, None, self.logFile) self.assertRaises("LoggerError", CryptoBoxLogger, syslog.LOG_WARNING, None, self.logFile)
self.assertRaises("LoggerError", CryptoBoxLogger, 0, 0, "/no/existing/path") self.assertRaises("LoggerError", CryptoBoxLogger, syslog.LOG_EMERG, 0, "/no/existing/path")
os.remove(self.logFile)
def testMessage(self): def testOutputParams(self):
cb = CryptoBoxLogger(3, 0, self.logFile) """Output should fail for invalid parameters"""
cb = CryptoBoxLogger(syslog.LOG_ERR, 0, self.logFile)
self.assertRaises("LoggerError", cb.printMessage, 3353, "Ausgabe")
self.assertRaises("LoggerError", cb.printMessage, -1, "Ausgabe")
self.assertRaises("LoggerError", cb.printMessage, "invalid", "Ausgabe")
self.assertRaises("LoggerError", cb.printMessage, syslog.LOG_DEBUG, None)
def testFile(self):
"""Do not write messages below specified priority to a file"""
cb = CryptoBoxLogger(syslog.LOG_ERR, 0, self.logFile)
content1 = self.readFile() content1 = self.readFile()
self.assertEquals(content1, "") self.assertEquals(content1, "")
cb.printMessage(3, "Ausgabe") cb.printMessage(syslog.LOG_ERR, "Ausgabe")
content2 = self.readFile() content2 = self.readFile()
self.assertNotEqual(content1, content2) self.assertNotEqual(content1, content2)
self.assertRaises("LoggerError", cb.printMessage, 10, "Ausgabe") cb.printMessage(syslog.LOG_DEBUG, "Ausgabe")
self.assertEquals(content2, self.readFile()) self.assertEquals(content2, self.readFile())
self.assertRaises("LoggerError", cb.printMessage, -1, "Ausgabe") cb.printMessage(syslog.LOG_CRIT, "Ausgabe")
self.assertEquals(content2, self.readFile())
self.assertRaises("LoggerError", cb.printMessage, "invalid", "Ausgabe")
self.assertEquals(content2, self.readFile())
self.assertRaises("LoggerError", cb.printMessage, 3, None)
self.assertEquals(content2, self.readFile())
cb.printMessage(2, "Ausgabe")
self.assertEquals(content2, self.readFile())
cb.printMessage(4, "Ausgabe")
self.assertNotEqual(content2, self.readFile()) self.assertNotEqual(content2, self.readFile())
os.remove(self.logFile)
def testSyslog(self):
"""Check syslog output"""
cb = CryptoBoxLogger(syslog.LOG_DEBUG, "syslog")
cb.printMessage(syslog.LOG_DEBUG, "just a verification check")
"""sorry - we do not have a way to check, if something was written somewhere
so we cannot do other checks beside initialization and writing"""
def readFile(self): def readFile(self):
fd = None fd = None

View file

@ -1,131 +0,0 @@
#!/usr/bin/env python
'''
read and write configuration
This Class is derived mainly from 'gimini' project.
Thanx to Dutoit! <dutoitc(at)hotmail.com>
'''
from ConfigParser import *
import sys, os
### Set the Preferences filename
class Preferences:
"""
This class handles preferences and stores them into given configfile
To use it :
- instanciate a Preferences object :
myPP=Preferences()
- to get a preference :
mypref=myPP["ma_preference"]
- to set a preference :
myPP["ma_preference"]=xxx
The preferences are automatically loaded on the first instanciation of this
class and are saved when a value is added or changed automatically, too.
"""
def __init__(self, filename):
"""
Constructor
@author C.Dutoit <dutoitc@hotmail.com>
"""
self.prefsfilename = filename
self._config = None
self.__loadConfig()
#>--------------------------------------------------------------------------
def __getitem__(self, name):
"""
Return the preferences for the given item
@param String name : Name of the item for which we return a value
@return String : value of the pref, or None if inexistant
@since 1.1.2.7
@author C.Dutoit <dutoitc@hotmail.com>
"""
if not self._config.has_section("Main"):
print "No section: \"[Main]\""
return None
try:
return self._config.get("Main", name)
except NoOptionError:
print "No such option: \"" + name +"\""
return None
#>--------------------------------------------------------------------------
def __setitem__(self, name, value):
"""
Return the preferences for the given item
@param String name : Name of the item WITHOUT SPACES
@param String Value : Value for the given name
@raises TypeError : if the name contains spaces
@since 1.1.2.7
@author C.Dutoit <dutoitc@hotmail.com>
"""
# Add 'Main' section ?
if not self._config.has_section("Main"):
self._config.add_section("Main")
if " " in list(name):
raise TypeError, "Name cannot contain a space"
# Save
self._config.set("Main", name, str(value))
self.__saveConfig()
#>--------------------------------------------------------------------------
def __saveConfig(self):
"""
Save datas to config file
@since 1.1.2.5
@author C.Dutoit <dutoitc@hotmail.com>
"""
f=open(self.prefsfilename, "w")
self._config.write(f)
f.close()
#>--------------------------------------------------------------------------
def __loadConfig(self):
"""
Load datas from config file
@since 1.1.2.5
@author C.Dutoit <dutoitc@hotmail.com>
"""
# Make sure that the configuration file exist
try:
f = open(self.prefsfilename, "r")
f.close()
except:
try:
f = open(self.prefsfilename, "w")
f.write("")
f.close()
except:
print "Can't make %s for saving preferences !" % self.prefsfilename
return
# Read datas
self._config=ConfigParser()
self._config.read(self.prefsfilename)
#>--------------------------------------------------------------------------
if __name__ == "__main__":
myPP=Preferences()
mypref=myPP["ma_preference"]
myPP["ma_preference"]="xxx"

View file

@ -46,7 +46,7 @@ Facility = file
# file: $FILENAME # file: $FILENAME
# syslog: $LOG_FACILITY # syslog: $LOG_FACILITY
# The log file will get created as root and then handed over to the # The log file will get created as root and then handed over to the
# cryptobox user 8see above) # cryptobox user (see above)
#Destination = /var/log/cryptobox.log #Destination = /var/log/cryptobox.log
Destination = ./cryptobox.log Destination = ./cryptobox.log
@ -62,4 +62,13 @@ Language = de
#path to documentation files #path to documentation files
DocDir = ../doc/html DocDir = ../doc/html
#default language for documentation #default language for documentation
DocLang = en DocLang = en
[Programs]
cryptsetup = /sbin/cryptsetup
mkfs-data = /sbin/mkfs.ext3
mkfs-config = /sbin/mkfs.ext2
blkid = /sbin/blkid
mount = /bin/mount
umount = /bin/umount

View file

@ -1,6 +1,9 @@
import os,tempfile,dircache,string,commands import os,tempfile,dircache,string,commands
"""I suppose this stuff should be inside some class?""" """I suppose this stuff should be inside some class?"""
# RFC: which of these methods do we need more than once?
# or: these actions are too short for methods - or not? [l]
def read_file(filename): def read_file(filename):
""" """
read from the file whose name is given read from the file whose name is given

View file

@ -33,15 +33,15 @@ def main():
testElement = cb.getContainerList()[0] testElement = cb.getContainerList()[0]
print "\nRunning some tests now ..." print "\nRunning some tests now ..."
if not luke_tests(testElement): if not plain_tests(testElement):
print "some previous tests failed - we should stop now" print "some previous tests failed - we should stop now"
sys.exit(1) sys.exit(1)
plain_tests(testElement) luks_tests(testElement)
" ***************** some functions ******************** " " ***************** some functions ******************** "
def luke_tests(e): def luks_tests(e):
e.create(e.Types["luks"], "alt") e.create(e.Types["luks"], "alt")
print "\tluks create:\tok" print "\tluks create:\tok"
@ -90,4 +90,9 @@ def plain_tests(e):
if e.isMounted(): print "\tplain umount:\tfailed" if e.isMounted(): print "\tplain umount:\tfailed"
else: print "\tplain umount:\tok" else: print "\tplain umount:\tok"
if e.isMounted(): return False
else: return True
# ************ main ****************
main() main()