diff --git a/bin/CryptoBoxRootActions b/bin/CryptoBoxRootActions index 894b588..d72f509 100755 --- a/bin/CryptoBoxRootActions +++ b/bin/CryptoBoxRootActions @@ -23,12 +23,10 @@ """module for executing the programs, that need root privileges Syntax: - - program - - device - - [action] - - [action args] + - TODO -this script will always return with an exitcode 0 (true), if "check" is the only argument +this script will always return with an exitcode 0 (true), +if "check" is the only argument """ __revision__ = "$Id" @@ -63,10 +61,10 @@ def checkIfFileIsSafe(fname): ## the override setting may be turned off temporarily to allow unittests if OVERRIDE_FILECHECK: return True - ## if the real user id is 0 (root), then we do not have to check this, + ## if the calling user id is 0 (root), then we do not have to check this, ## as root would be allowed to do this anyway ## this eases testing with a not-installed working copy in a uml environment - if os.getuid() == 0: + if getCallingUserInfo()[1] == 0: return True props = os.stat(fname) ## check if it is owned by non-root @@ -84,7 +82,7 @@ def checkIfFileIsSafe(fname): def checkIfPluginIsValid(plugin): import imp try: - x = imp.load_source("cbox_plugin",plugin) + x = imp.load_source("cbox_plugin", plugin) except (SyntaxError, IOError): return False try: @@ -114,7 +112,8 @@ def call_plugin(args): ## check if the plugin (and its parents) are only writeable for root ## this can be overridden by OVERRIDE_FILECHECK if not checkIfFileIsSafe(plugin): - raise Exception, "the plugin (%s) is not safe - check its (and its parents') permissions" % plugin + raise Exception, "the plugin (%s) is not safe - check its " % plugin \ + + "(and its parents') permissions" ## check if the plugin is a python program, that is marked as a cryptobox plugin if not checkIfPluginIsValid(plugin): raise Exception, "the plugin (%s) is not a correctly marked python script" % plugin @@ -135,10 +134,13 @@ def call_event(args): raise Exception, "could not find executable event script (%s)" % event ## check if the script is valid (the marker file must be in the same directory) if not checkIfEventScriptIsValid(event): - raise Exception, "the event script (%s) does not reside in a directory with the marker file (%s) - this is not allowed due to abuse prevention" % (event, EVENT_MARKER) + raise Exception, "the event script (%s) does not reside in" % event \ + + "a directory with the marker file (%s) - this " % EVENT_MARKER \ + + "is not allowed due to abuse prevention" ## check if the event (and its parents) are only writeable for root if not checkIfFileIsSafe(event): - raise Exception, "the event (%s) is not safe - check its (and its parents') permissions" % event + raise Exception, "the event (%s) is not safe - check its " % event \ + + "(and its parents') permissions" args.insert(0, event) proc = subprocess.Popen( shell = False, @@ -156,30 +158,30 @@ def isWriteable(path, force_dev_type=None): this check works nicely together with "super", as it changes (by default) only the effective uid (not the real uid) """ - # first check, if the device/file exists + ## first check, if the device/file exists if not os.path.exists(path): sys.stderr.write("%s does not exist!\n" % path) return False - # check the type of the path - if necessary + ## check the type of the path - if necessary if (not force_dev_type is None) and \ (force_dev_type != os.stat(path).st_mode % 65536 / 4096): sys.stderr.write("%s does not have the numeric type '%d'!\n" \ % (path, force_dev_type)) return False - ## if root is the (real) user, then it is ok - if os.getuid() == 0: + ## retrieve the information for the real user id + (trustUserName, trustUID, groupsOfTrustUser) = getCallingUserInfo() + ## are we called by the root user? this would be ok + if trustUID == 0: return True ## is the path owned by us? - if os.stat(path)[4] == os.getuid(): + if os.stat(path)[4] == trustUID(): return True - # retrieve the information for the real user id - (trustUserName, trustUID, groupsOfTrustUser) = getUserInfo(os.getuid()) - # set the default groups of the caller for the check (restore them later) + ## set the default groups of the caller for the check (restore them later) savedGroups = os.getgroups() os.setgroups(groupsOfTrustUser) - # check permissions + ## check permissions result = os.access(path, os.W_OK) and os.access(path, os.R_OK) - # reset the groups of this process + ## reset the groups of this process os.setgroups(savedGroups) return result @@ -190,7 +192,8 @@ def run_cryptsetup(args): @args: list of arguments - they will be treated accordingly to the first element of this list (the action)""" if not args: raise "WrongArguments", "no action for cryptsetup supplied" - if type(args) != types.ListType: raise "WrongArguments", "invalid arguments supplied: %s" % (args, ) + if type(args) != types.ListType: + raise "WrongArguments", "invalid arguments supplied: %s" % (args, ) try: action = args[0] del args[0] @@ -246,15 +249,19 @@ def run_cryptsetup(args): args = cs_args) proc.wait() ## chown the devmapper block device to the cryptobox user + calling_user = getCallingUserInfo() if (proc.returncode == 0) and (action == "luksOpen"): - os.chown(os.path.join(os.path.sep, "dev", "mapper", destination), os.getuid(), os.getgid()) + os.chown(os.path.join(os.path.sep, "dev", "mapper", destination), + calling_user[1], calling_user[2][0]) return proc.returncode == 0 -def run_sfdisk(args): +def run_sfdisk(sf_args): """execute sfdisk for partitioning - not implemented yet""" + not implemented yet + TODO: this is useless, as it is done in root_actions.py of the partition plugin? + """ print "ok - you are free to call sfdisk ..." print " not yet implemented ..." return True @@ -281,7 +288,8 @@ def run_mount(args): """execute mount """ if not args: raise "WrongArguments", "no destination for mount supplied" - if type(args) != types.ListType: raise "WrongArguments", "invalid arguments supplied: %s" % (args, ) + if type(args) != types.ListType: + raise "WrongArguments", "invalid arguments supplied: %s" % (args, ) try: device = args[0] del args[0] @@ -294,7 +302,8 @@ def run_mount(args): raise "WrongArguments", "%s is not a writeable block device" % (device, ) ## check permissions for the mountpoint if not isWriteable(destination, DEV_TYPES["dir"]): - raise "WrongArguments", "the mountpoint (%s) is not writeable" % (destination, ) + raise "WrongArguments", "the mountpoint (%s) is not writeable" \ + % (destination, ) # check for additional (not allowed) arguments if len(args) != 0: raise "WrongArguments", "too many arguments for 'mount': %s" % (args, ) @@ -343,7 +352,9 @@ def run_mount(args): 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("could not chown the mount destination (%s) " % destination \ + + "to the specified user (%d/%d): " % (trustUID, groupsOfTrustUser[0]) \ + + "%s/n" % str(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 @@ -355,13 +366,15 @@ def run_umount(args): """execute mount """ if not args: raise "WrongArguments", "no mountpoint for umount supplied" - if type(args) != types.ListType: raise "WrongArguments", "invalid arguments supplied" + if type(args) != types.ListType: + raise "WrongArguments", "invalid arguments supplied" try: destination = args[0] del args[0] # check permissions for the destination if not isWriteable(os.path.dirname(destination), DEV_TYPES["dir"]): - raise "WrongArguments", "the parent of the mountpoint (%s) is not writeable" % (destination, ) + raise "WrongArguments", "the parent of the mountpoint " \ + + "(%s) is not writeable" % (destination, ) if len(args) != 0: raise "WrongArguments", "umount does not allow arguments" except TypeError: raise "WrongArguments", "invalid arguments supplied" @@ -379,23 +392,43 @@ def run_umount(args): return proc.returncode == 0 +def getCallingUserInfo(): + """return information about the user that was calling this program via "super" + + @user: (uid or name) + @return: tuple of (name, uid, (groups)) + """ + ## are we called via 'super'? + if ("SUPERCMD" in os.environ) and ("USER" in os.environ): + ## return the user that was calling super + return getUserInfo(os.environ["USER"]) + else: + ## return the current user + return getUserInfo(os.getuid()) + + def getUserInfo(user): """return information about the specified user @user: (uid or name) @return: tuple of (name, uid, (groups)) """ - if user is None: raise "KeyError", "no user supplied" - # first check, if 'user' contains an id - then check for a name - try: + if (user is None) or (user == ""): + raise "KeyError", "no user supplied" + ## if a KeyError is raised again in the following lines, then the supplied + ## user was invalid + if type(user) is int: + # 'user' is a uid userinfo = pwd.getpwuid(user) - except TypeError: - # if a KeyError is raised again, then the supplied user was invalid + elif type(user) is str: + # 'user' is a name userinfo = pwd.getpwnam(user) u_groups = [one_group.gr_gid for one_group in grp.getgrall() if userinfo.pw_name in one_group.gr_mem] - if not userinfo.pw_gid in u_groups: u_groups.append(userinfo.pw_gid) + if not userinfo.pw_gid in u_groups: + ## put in front of the list + u_groups.insert(0,userinfo.pw_gid) return (userinfo.pw_name, userinfo.pw_uid, u_groups) @@ -406,7 +439,8 @@ if __name__ == "__main__": # do we have root privileges (effective uid is zero)? if os.geteuid() != 0: - sys.stderr.write("the effective uid is not zero - you should use 'super' to call this script (%s)" % sys.argv[0]) + sys.stderr.write("the effective uid is not zero - you should use " \ + + "'super' to call this script (%s)" % sys.argv[0]) sys.exit(100) # remove program name @@ -468,7 +502,8 @@ if __name__ == "__main__": elif progRequest == "mount": runner = run_mount elif progRequest == "umount": runner = run_umount else: - sys.stderr.write("The interface for this program (%s) is not yet implemented!\n" % progRequest) + sys.stderr.write("The interface for this program (%s) is " \ + + "not yet implemented!\n" % progRequest) sys.exit(100) try: if runner(args): diff --git a/templates/main.cs b/templates/main.cs index 7464a1d..b4b20a3 100644 --- a/templates/main.cs +++ b/templates/main.cs @@ -10,7 +10,8 @@ - + diff --git a/www-data/cryptobox.css b/www-data/cryptobox.css index 185acf1..4b95b13 100644 --- a/www-data/cryptobox.css +++ b/www-data/cryptobox.css @@ -23,6 +23,7 @@ body { text-align: center; + font-size: 0.9em; margin: 0; padding: 0; font-family: verdana, lucida, arial, helvetica, sans-serif;