implemented root actions for plugins

finished network and date plugins
renamed old 'bin' direcory
This commit is contained in:
lars 2006-09-13 10:38:05 +00:00
parent 2b4180a83b
commit e80b8874ff
13 changed files with 211 additions and 23 deletions

View file

@ -1,4 +1,5 @@
#!/usr/bin/env python2.4
"""module for executing the programs, that need root privileges
Syntax:
@ -28,13 +29,67 @@ allowedProgs = {
DEV_TYPES = { "pipe":1, "char":2, "dir":4, "block":6, "file":8, "link":10, "socket":12}
def checkIfPluginIsSafe(plugin):
"""check if the plugin and its parents are only writeable for root"""
#FIXME: for now we may skip this test - but users will not like it this way :)
return True
props = os.stat(plugin)
## check if it is owned by non-root
if props.st_uid != 0: return False
## check group-write permission if gid is not zero
if (props.st_gid != 0) and (props.st_mode % 32 / 16 > 0): return False
## check if it is world-writeable
if props.st_mode % 4 / 2 > 0: return False
## are we at root-level (directory-wise)? If yes, then we are ok ...
if plugin == os.path.sep: return True
## check if the parent directory is ok - recursively :)
return checkIfPluginIsSafe(os.path.dirname(os.path.abspath(plugin)))
def checkIfPluginIsValid(plugin):
import imp
try:
x = imp.load_source("cbox_plugin",plugin)
except Exception:
return False
try:
if getattr(x, "PLUGIN_TYPE") == "cryptobox":
return True
else:
return False
except Exception:
return False
def call_plugin(args):
"""check if the plugin may be called - and do it finally ..."""
plugin = os.path.abspath(args[0])
del args[0]
## check existence and excutability
if not os.access(plugin, os.X_OK):
raise Exception, "could not find executable plugin (%s)" % plugin
## check if the plugin (and its parents) are only writeable for root
if not checkIfPluginIsSafe(plugin):
raise Exception, "the plugin (%s) was not safe - check its (and its parents') permissions" % plugin
## 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
args.insert(0,plugin)
proc = subprocess.Popen(
shell = False,
args = args)
proc.communicate()
return proc.returncode == 0
def isWriteable(device, force_dev_type=None):
"""check if the calling user (not root!) has write access to the device/file
the real (not the effictive) user id is used for the check
additionally the permissions of the default groups of the real uid are checked
this check works nicely together with "super", as it changes (by default) only
the effective uid (not the real uid)"""
the effective uid (not the real uid)
"""
# first check, if the device/file exists
if not os.path.exists(device):
return False
@ -221,7 +276,7 @@ if __name__ == "__main__":
sys.exit(100)
# remove program name
sys.argv.remove(sys.argv[0])
args = sys.argv[1:]
# do not allow to use root permissions (real uid may not be zero)
if os.getuid() == 0:
@ -229,17 +284,29 @@ if __name__ == "__main__":
sys.exit(100)
# did the user call the "check" action?
if (len(sys.argv) == 1) and (sys.argv[0].lower() == "check"):
if (len(args) == 1) and (args[0].lower() == "check"):
# exit silently
sys.exit(0)
if args[0].lower() == "plugin":
del args[0]
try:
isOK = call_plugin(args)
except Exception, errMsg:
sys.stderr.write("Execution of plugin failed: %s\n" % errMsg)
sys.exit(100)
if isOK:
sys.exit(0)
else:
sys.exit(1)
# check parameters count
if len(sys.argv) < 2:
sys.stderr.write("Not enough arguments supplied (%s)!\n" % " ".join(sys.argv))
if len(args) < 2:
sys.stderr.write("Not enough arguments supplied (%s)!\n" % " ".join(args))
sys.exit(100)
progRequest = sys.argv[0]
del sys.argv[0]
progRequest = args[0]
del args[0]
if not progRequest in allowedProgs.keys():
sys.stderr.write("Invalid program requested: %s\n" % progRequest)
@ -253,7 +320,7 @@ if __name__ == "__main__":
sys.stderr.write("The interface for this program (%s) is not yet implemented!\n" % progRequest)
sys.exit(100)
try:
if runner(sys.argv):
if runner(args):
sys.exit(0)
else:
sys.exit(1)

View file

@ -1,4 +1,6 @@
from CryptoBoxExceptions import CBPluginActionError
import subprocess
import os
def prepareForm(hdf, cbox):
@ -19,9 +21,19 @@ def doAction(cbox, store=None, year=0, month=0, day=0, hour=0, minute=0):
new_date = datetime.datetime(year, month, day, hour, minute)
except ValueError:
raise CBPluginActionError, "InvalidDate"
# TODO: how to set the current time? (and how to become root?)
## we will continue with the system menue
proc = subprocess.Popen(
shell = False,
args = [
cbox.prefs["Programs"]["super"],
cbox.prefs["Programs"]["CryptoBoxRootActions"],
"plugin",
os.path.join(os.path.dirname(__file__), "root_action.py"),
"%02d%02d%02d%02d%d" % (month, day, hour, minute, year)])
proc.communicate()
if proc.returncode == 0:
return "form_system"
else:
raise CBPluginActionError, "InvalidDate"
else:
return "form_date"

View file

@ -0,0 +1,35 @@
#!/usr/bin/env python2.4
## necessary: otherwise CryptoBoxRootActions.py will refuse to execute this script
PLUGIN_TYPE = "cryptobox"
DATE_BIN = "/bin/date"
import subprocess
import re
import sys
import os
if __name__ == "__main__":
args = sys.argv[1:]
self_bin = sys.argv[0]
if len(args) > 1:
sys.stderr.write("%s: too many arguments (%s)\n" % (self_bin, args))
sys.exit(1)
if len(args) == 0:
sys.stderr.write("%s: no argument supplied\n" % self_bin)
sys.exit(1)
if re.search(u'\D', args[0]):
sys.stderr.write("%s: illegal argument (%s)\n" % (self_bin, args[0]))
sys.exit(1)
proc = subprocess.Popen(
shell = False,
args = [DATE_BIN, args[0]])
proc.communicate()
sys.exit(proc.returncode)

View file

@ -6,7 +6,7 @@ Lang {
Modules.logs {
Name = Show the content of the log file
Link = Show the log file
Link = Show log file
Rank = 90
}

View file

@ -12,7 +12,7 @@ Lang {
Rank = 30
}
Warning.InvalidIP {
WarningMessage.InvalidIP {
Title = Invalid value
Text = An invalid network address (IP) was supplied. Please try again.
}

View file

@ -1,8 +1,12 @@
from CryptoBoxExceptions import CBPluginActionError
import re
import subprocess
import imp
import os
def prepareForm(hdf, cbox):
(oc1, oc2, oc3, oc4) = __getCurrentIP()
(oc1, oc2, oc3, oc4) = __getCurrentIP(cbox)
hdf["Data.Modules.network.ip.oc1"] = oc1
hdf["Data.Modules.network.ip.oc2"] = oc2
hdf["Data.Modules.network.ip.oc3"] = oc3
@ -12,22 +16,51 @@ def prepareForm(hdf, cbox):
def doAction(cbox, store=None, ip1="", ip2="", ip3="", ip4=""):
if store:
try:
# TODO: check the IP here
pass
for ip_in in (ip1, ip2, ip3, ip4):
if (int(ip_in) < 0) or (int(ip_in) > 255):
cbox.log.debug("invalid IP supplied: %s" % str((ip1,ip2,ip3,ip4)))
raise ValueError
ip = "%d.%d.%d.%d" % (int(ip1), int(ip2), int(ip3), int(ip4))
except ValueError:
raise CBPluginActionError, "InvalidIP"
# TODO: how to set the new IP? (and how to become root?)
## we will continue with the system menue
if __setIP(cbox, ip):
return "form_system"
else:
raise CBPluginActionError, "InvalidIP"
else:
return "form_network"
def getStatus(cbox):
return "%d.%d.%d.%d" % __getCurrentIP()
return "%d.%d.%d.%d" % __getCurrentIP(cbox)
def __getCurrentIP():
# TODO: for now we only provide a dummy
return (192,168,0,23)
def __getCurrentIP(cbox):
root_action_mod = imp.load_source("root_action", os.path.join(os.path.dirname(__file__), "root_action.py"))
proc = subprocess.Popen(
shell = False,
stdout = subprocess.PIPE,
args = [
root_action_mod.IFCONFIG_BIN,
root_action_mod.IFACE])
(output, error) = proc.communicate()
if proc.returncode != 0: return (0,0,0,0)
match = re.search(u'inet [\w]+:(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\s',output)
if match:
return tuple([int(e) for e in match.groups()])
else:
return (0,0,0,0)
def __setIP(cbox, ip):
proc = subprocess.Popen(
shell = False,
args = [
cbox.prefs["Programs"]["super"],
cbox.prefs["Programs"]["CryptoBoxRootActions"],
"plugin",
os.path.join(os.path.dirname(__file__), "root_action.py"),
ip])
proc.communicate()
return proc.returncode == 0

View file

@ -0,0 +1,41 @@
#!/usr/bin/env python2.4
#TODO: add netmask and gateway
## necessary: otherwise CryptoBoxRootActions.py will refuse to execute this script
PLUGIN_TYPE = "cryptobox"
IFCONFIG_BIN = "/sbin/ifconfig"
IFACE = "eth0"
import subprocess
import re
import sys
import os
if __name__ == "__main__":
args = sys.argv[1:]
self_bin =sys.argv[0]
if len(args) > 1:
sys.stderr.write("%s: too many arguments (%s)\n" % (self_bin, args))
sys.exit(1)
if len(args) == 0:
sys.stderr.write("%s: no argument supplied\n" % self_bin)
sys.exit(1)
match = re.search(u'^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$', args[0])
## did we match? If yes, then: are there wrong values inside?
if not match or [e for e in match.groups() if int(e) > 255]:
sys.stderr.write("%s: illegal argument (%s)\n" % (self_bin, args[0]))
sys.exit(1)
proc = subprocess.Popen(
shell = False,
args = [IFCONFIG_BIN, IFACE, args[0]])
proc.communicate()
sys.exit(proc.returncode)