From 3e1358e9274da95deeee9b6a75d0197d4cbb12f0 Mon Sep 17 00:00:00 2001 From: David Howells Date: Mon, 14 Apr 2014 09:23:54 +0100 Subject: [PATCH] Provide argument exception class and check argument length restrictions Create an argument error class specifically for the indication of command line argument problems and catch it in main.py. Further, provide checking for string arguments that have length restrictions in the protocol. Signed-off-by: David Howells --- suite/argparse.py | 43 +++++++++++++++++++++---------- suite/commands/bos/addhost.py | 4 +++ suite/commands/bos/adduser.py | 4 +++ suite/commands/bos/create.py | 7 +++++ suite/commands/bos/delete.py | 4 +++ suite/commands/bos/getdate.py | 5 ++++ suite/commands/bos/removeuser.py | 4 +++ suite/commands/bos/setcellname.py | 4 +++ suite/commands/bos/shutdown.py | 4 +++ suite/commands/bos/start.py | 4 +++ suite/commands/bos/startup.py | 4 +++ suite/commands/bos/status.py | 4 +++ suite/commands/bos/stop.py | 4 +++ suite/commands/vos/examine.py | 4 +++ suite/commands/vos/listvldb.py | 4 +++ suite/exception.py | 4 +++ suite/lib/partition.py | 26 +++++++++++-------- suite/lib/uuid.py | 4 ++- suite/main.py | 20 +++++++++----- 19 files changed, 125 insertions(+), 32 deletions(-) diff --git a/suite/argparse.py b/suite/argparse.py index bcc2fa1..43a7aff 100644 --- a/suite/argparse.py +++ b/suite/argparse.py @@ -13,6 +13,8 @@ as published by the Free Software Foundation; either version 2 of the Licence, or (at your option) any later version. """ +from exception import AFSArgumentError + def get_cell(switch, params): from afs.lib.cell import cell return cell(params[0]) @@ -129,7 +131,8 @@ def get_dummy(switch, params): # another value for the preceding argument. # ############################################################################### -def parse_arguments(args, available_arguments): +def parse_arguments(args, available_arguments, argument_size_limits, + cant_combine_arguments): result = {} need_switch = False i = 0 # Given arguments index @@ -139,7 +142,7 @@ def parse_arguments(args, available_arguments): if len(args) == 0: if len(available_arguments) > 0 and available_arguments[0][0] == "r": - raise RuntimeError("Missing required parameters") + raise AFSArgumentError("Missing required parameters") return result # Process all the optional arguments or switch-based required arguments @@ -150,13 +153,13 @@ def parse_arguments(args, available_arguments): if args[i][0] != "-": # Deal with positional arguments if need_switch: - raise RuntimeError("Need switch before argument " + i) + raise AFSArgumentError("Need switch before argument " + i) if av >= len(available_arguments): - raise RuntimeError("Unexpected positional argument") + raise AFSArgumentError("Unexpected positional argument") match = available_arguments[av] pattern = match[2] if pattern[0] == "f": - raise RuntimeError("Unexpected positional argument") + raise AFSArgumentError("Unexpected positional argument") av = av + 1 params.append(args[i]) @@ -177,9 +180,9 @@ def parse_arguments(args, available_arguments): i = i + 1 if switch == "help": - raise RuntimeError("Print help message") + raise AFSArgumentError("Print help message") if switch == "": - raise RuntimeError("Missing switch name") + raise AFSArgumentError("Missing switch name") # Look up the switch in the table of possible arguments and flags for j in available_arguments: @@ -188,14 +191,14 @@ def parse_arguments(args, available_arguments): break if j[0].startswith(switch): if match: - raise RuntimeError("Ambiguous switch name abbreviation '-" + switch + "'") + raise AFSArgumentError("Ambiguous switch name abbreviation '-" + switch + "'") match = j if not match: - raise RuntimeError("Unsupported switch '-" + switch + "'") + raise AFSArgumentError("Unsupported switch '-" + switch + "'") # Reject repeat flags if match[0] in result: - raise RuntimeError("Duplicate switch '-" + switch + "' not permitted") + raise AFSArgumentError("Duplicate switch '-" + switch + "' not permitted") # Arrange the parameters associated with the switch into a list while i < len(args): @@ -207,11 +210,18 @@ def parse_arguments(args, available_arguments): # Check that we have the number of arguments we're expecting pattern = match[2] if pattern[1] == "n" and len(params) != 0: - raise RuntimeError("Switch '-" + switch + "' expects no arguments") + raise AFSArgumentError("Switch '-" + switch + "' expects no arguments") if pattern[1] == "s" and len(params) != 1: - raise RuntimeError("Switch '-" + switch + "' expects one argument") + raise AFSArgumentError("Switch '-" + switch + "' expects one argument") if pattern[1] == "m" and len(params) < 1: - raise RuntimeError("Switch '-" + switch + "' expects one or more arguments") + raise AFSArgumentError("Switch '-" + switch + "' expects one or more arguments") + + # Check that none of the arguments are too big + if match[0] in argument_size_limits: + limit = argument_size_limits[match[0]] + for j in params: + if len(j) > limit: + raise AFSArgumentError("Switch '-" + switch + "' has an overlong argument") # Call the syntax checker syntax = match[1] @@ -225,6 +235,11 @@ def parse_arguments(args, available_arguments): if j[2][0] != "r": break if switch not in result: - raise RuntimeError("Missing '-" + switch + "' argument") + raise AFSArgumentError("Missing '-" + switch + "' argument") + + # Check for invalid argument combinations + for i in cant_combine_arguments: + if i[0] in params and i[1] in params: + raise AFSArgumentError("Can't combine -" + i[0], "with -" + i[1], file=sys.stderr) return result diff --git a/suite/commands/bos/addhost.py b/suite/commands/bos/addhost.py index 7bc037d..34ef6bb 100644 --- a/suite/commands/bos/addhost.py +++ b/suite/commands/bos/addhost.py @@ -42,6 +42,10 @@ cant_combine_arguments = [ ( "noauth", "localauth" ), ] +argument_size_limits = { + "host" : kafs.BOZO_BSSIZE, +} + description = r""" Add a database server machine to the CellServDB file """ diff --git a/suite/commands/bos/adduser.py b/suite/commands/bos/adduser.py index 907db17..0fadb63 100644 --- a/suite/commands/bos/adduser.py +++ b/suite/commands/bos/adduser.py @@ -42,6 +42,10 @@ cant_combine_arguments = [ ( "noauth", "localauth" ), ] +argument_size_limits = { + "user" : kafs.BOZO_BSSIZE, +} + description = r""" Add a privileged user to the UserList file """ diff --git a/suite/commands/bos/create.py b/suite/commands/bos/create.py index df3e9c7..e5e5e0e 100644 --- a/suite/commands/bos/create.py +++ b/suite/commands/bos/create.py @@ -45,6 +45,13 @@ cant_combine_arguments = [ ( "noauth", "localauth" ), ] +argument_size_limits = { + "instance" : kafs.BOZO_BSSIZE, + "type" : kafs.BOZO_BSSIZE, + "cmd" : kafs.BOZO_BSSIZE, + "notifier" : kafs.BOZO_BSSIZE, +} + description = r""" Define a new process in the BosConfig file and start it """ diff --git a/suite/commands/bos/delete.py b/suite/commands/bos/delete.py index b73965b..539e495 100644 --- a/suite/commands/bos/delete.py +++ b/suite/commands/bos/delete.py @@ -42,6 +42,10 @@ cant_combine_arguments = [ ( "noauth", "localauth" ), ] +argument_size_limits = { + "instance" : kafs.BOZO_BSSIZE, +} + description = r""" Delete a server process from the BosConfig file """ diff --git a/suite/commands/bos/getdate.py b/suite/commands/bos/getdate.py index 9b1fd96..cad020e 100644 --- a/suite/commands/bos/getdate.py +++ b/suite/commands/bos/getdate.py @@ -43,6 +43,11 @@ cant_combine_arguments = [ ( "noauth", "localauth" ), ] +argument_size_limits = { + "file" : kafs.BOZO_BSSIZE, + "dir" : kafs.BOZO_BSSIZE, +} + description = r""" Display the time stamps on an AFS binary file installed on the server. """ diff --git a/suite/commands/bos/removeuser.py b/suite/commands/bos/removeuser.py index 1b2612d..e144a32 100644 --- a/suite/commands/bos/removeuser.py +++ b/suite/commands/bos/removeuser.py @@ -42,6 +42,10 @@ cant_combine_arguments = [ ( "noauth", "localauth" ), ] +argument_size_limits = { + "user" : kafs.BOZO_BSSIZE, +} + description = r""" Remove a privileged user from the UserList file """ diff --git a/suite/commands/bos/setcellname.py b/suite/commands/bos/setcellname.py index 073a180..69fa080 100644 --- a/suite/commands/bos/setcellname.py +++ b/suite/commands/bos/setcellname.py @@ -41,6 +41,10 @@ cant_combine_arguments = [ ( "noauth", "localauth" ), ] +argument_size_limits = { + "name" : kafs.BOZO_BSSIZE, +} + description = r""" Display whether a bos server is restricted or not """ diff --git a/suite/commands/bos/shutdown.py b/suite/commands/bos/shutdown.py index 062d388..2097d62 100644 --- a/suite/commands/bos/shutdown.py +++ b/suite/commands/bos/shutdown.py @@ -43,6 +43,10 @@ cant_combine_arguments = [ ( "noauth", "localauth" ), ] +argument_size_limits = { + "instance" : kafs.BOZO_BSSIZE, +} + description = r""" Stop a process without changing its status flag """ diff --git a/suite/commands/bos/start.py b/suite/commands/bos/start.py index 8a775bc..7381f80 100644 --- a/suite/commands/bos/start.py +++ b/suite/commands/bos/start.py @@ -42,6 +42,10 @@ cant_combine_arguments = [ ( "noauth", "localauth" ), ] +argument_size_limits = { + "instance" : kafs.BOZO_BSSIZE, +} + description = r""" Start a process after setting its status flag """ diff --git a/suite/commands/bos/startup.py b/suite/commands/bos/startup.py index db9fb74..45c6017 100644 --- a/suite/commands/bos/startup.py +++ b/suite/commands/bos/startup.py @@ -42,6 +42,10 @@ cant_combine_arguments = [ ( "noauth", "localauth" ), ] +argument_size_limits = { + "instance" : kafs.BOZO_BSSIZE, +} + description = r""" Start a process without changing its status flag """ diff --git a/suite/commands/bos/status.py b/suite/commands/bos/status.py index 789b453..1ab6243 100644 --- a/suite/commands/bos/status.py +++ b/suite/commands/bos/status.py @@ -45,6 +45,10 @@ cant_combine_arguments = [ ( "noauth", "localauth" ), ] +argument_size_limits = { + "instance" : kafs.BOZO_BSSIZE, +} + description = r""" Display the status of server processes """ diff --git a/suite/commands/bos/stop.py b/suite/commands/bos/stop.py index e501f36..8cfdf19 100644 --- a/suite/commands/bos/stop.py +++ b/suite/commands/bos/stop.py @@ -43,6 +43,10 @@ cant_combine_arguments = [ ( "noauth", "localauth" ), ] +argument_size_limits = { + "instance" : kafs.BOZO_BSSIZE, +} + description = r""" Stop a process after changing its status flag """ diff --git a/suite/commands/vos/examine.py b/suite/commands/vos/examine.py index 86c6d5e..3fb9a59 100644 --- a/suite/commands/vos/examine.py +++ b/suite/commands/vos/examine.py @@ -47,6 +47,10 @@ cant_combine_arguments = [ ( "noauth", "localauth" ), ] +argument_size_limits = { + "id" : kafs.VLDB_MAXNAMELEN, +} + description = r""" Show volume header and VLDB entry information for a volume """ diff --git a/suite/commands/vos/listvldb.py b/suite/commands/vos/listvldb.py index db310e9..fa062c5 100644 --- a/suite/commands/vos/listvldb.py +++ b/suite/commands/vos/listvldb.py @@ -50,6 +50,10 @@ cant_combine_arguments = [ ( "name", "locked" ), ] +argument_size_limits = { + "name" : kafs.VLDB_MAXNAMELEN, +} + description = r""" Displays a volume's VLDB entry """ diff --git a/suite/exception.py b/suite/exception.py index b031378..88bba14 100644 --- a/suite/exception.py +++ b/suite/exception.py @@ -1,3 +1,7 @@ class AFSException(Exception): """Base class for all AFS Toolkit exceptions.""" pass + +class AFSArgumentError(AFSException): + """Base class for all AFS Toolkit exceptions.""" + pass diff --git a/suite/lib/partition.py b/suite/lib/partition.py index 6af4e97..4463c33 100644 --- a/suite/lib/partition.py +++ b/suite/lib/partition.py @@ -21,28 +21,32 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """ +from exception import AFSArgumentError + def part2id(name): """Convert a partition name or number string into a numeric ID""" if name.isnumeric(): n = int(name) else: if name.startswith("/vicep"): - name = name[6:] + a = name[6:] elif name.startswith("vicep"): - name = name[5:] - - if len(name) == 1 and name >= "a" and name <= "z": - n = int(name, 36) - 10 - elif (len(name) == 2 and - name[0] >= "a" and name[0] <= "z" and - name[1] >= "a" and name[1] <= "z"): - n = (int(name[0], 36) - 10) * 26 + (int(name[1], 36) - 10) + a = name[5:] + else: + a = name + + if len(a) == 1 and a >= "a" and a <= "z": + n = int(a, 36) - 10 + elif (len(a) == 2 and + a[0] >= "a" and a[0] <= "z" and + a[1] >= "a" and a[1] <= "z"): + n = (int(a[0], 36) - 10) * 26 + (int(a[1], 36) - 10) n += 26 else: - raise RuntimeError("Unparseable partition ID '" + params[0] + "'") + raise AFSArgumentError("Unparseable partition ID '" + name + "'") if n < 0 or n > 255: - raise RuntimeError("Partition ID '" + params[0] + "' out of range") + raise AFSArgumentError("Partition ID '" + name + "' out of range") return n def id2part(n): diff --git a/suite/lib/uuid.py b/suite/lib/uuid.py index 35db3ba..82cf05f 100644 --- a/suite/lib/uuid.py +++ b/suite/lib/uuid.py @@ -21,6 +21,8 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """ +from exception import AFSArgumentError + def uuid2str(uuid): """Convert an afsUUID-class object into a UUID string""" s = "{:08x}-{:04x}-{:04x}-{:02x}-{:02x}-".format(uuid.time_low, @@ -40,7 +42,7 @@ def str2uuid(s): s[18] != "-" or s[21] != "-" or s[24] != "-"): - raise RuntimeError("Invalid UUID format") + raise AFSArgumentError("Invalid UUID format") from kafs import afsUUID uuid = afsUUID() diff --git a/suite/main.py b/suite/main.py index 113e03d..582fd1e 100644 --- a/suite/main.py +++ b/suite/main.py @@ -29,6 +29,7 @@ import sys, os, traceback import afs.commands from afs.lib.debug import debug, debugging_level +from exception import AFSArgumentError # # The commands map @@ -151,13 +152,20 @@ def _main(): command = cmdsetmod.get_command(cmd) #print("MOD:", command) - # Parse the parameters - params = afs.argparse.parse_arguments(sys.argv[1:], command.command_arguments) + if hasattr(command, "argument_size_limits"): + argument_size_limits = command.argument_size_limits + else: + argument_size_limits = {} - for i in command.cant_combine_arguments: - if i[0] in params and i[1] in params: - print("Can't combine -" + i[0], "with -" + i[1], file=sys.stderr) - sys.exit(2) + # Parse the parameters + try: + params = afs.argparse.parse_arguments(sys.argv[1:], + command.command_arguments, + argument_size_limits, + command.cant_combine_arguments) + except AFSArgumentError as e: + print(prog + ":", e, file=sys.stderr) + sys.exit(2) # Stick in the default cell if there isn't one if "cell" not in params: -- 2.49.0