From a9deca6a167f770cabf80faf0b2db3d0a797a67e Mon Sep 17 00:00:00 2001 From: Thierry Parmentelat Date: Sat, 18 Jul 2009 10:53:35 +0000 Subject: [PATCH] Fix big leak in type-checking add/update args for taggable classes Thanks Marc for the heads up --- PLC/Methods/AddInterface.py | 18 ++++++++--------- PLC/Methods/AddNode.py | 2 ++ PLC/Methods/AddSlice.py | 2 ++ PLC/Methods/UpdateInterface.py | 4 +++- PLC/Methods/UpdateNode.py | 2 ++ PLC/Methods/UpdateSlice.py | 2 ++ PLC/Table.py | 35 +++++++++++++++++++++++----------- 7 files changed, 44 insertions(+), 21 deletions(-) diff --git a/PLC/Methods/AddInterface.py b/PLC/Methods/AddInterface.py index cd3911a..662d7fd 100644 --- a/PLC/Methods/AddInterface.py +++ b/PLC/Methods/AddInterface.py @@ -19,23 +19,21 @@ class AddInterface(Method): Adds a new network for a node. Any values specified in interface_fields are used, otherwise defaults are - used. Acceptable values for method may be retrieved via - GetNetworkMethods. Acceptable values for type may be retrieved via - GetNetworkTypes. + used. - If type is static, ip, gateway, network, broadcast, netmask, and - dns1 must all be specified in interface_fields. If type is dhcp, - these parameters, even if specified, are ignored. + If type is static, then ip, gateway, network, broadcast, netmask, + and dns1 must all be specified in interface_fields. If type is + dhcp, these parameters, even if specified, are ignored. - PIs and techs may only add networks to their own nodes. Admins may - add networks to any node. + PIs and techs may only add interfaces to their own nodes. Admins may + add interfaces to any node. Returns the new interface_id (> 0) if successful, faults otherwise. """ roles = ['admin', 'pi', 'tech'] - accepted_fields = Row.accepted_fields(can_update, [Interface.fields,Interface.tags]) + accepted_fields = Row.accepted_fields(can_update, [Interface.fields,Interface.tags], exclude=True) accepts = [ Auth(), @@ -49,6 +47,8 @@ class AddInterface(Method): def call(self, auth, node_id_or_hostname, interface_fields): + interface_fields = Row.check_fields (interface_fields, self.accepted_fields) + [native,tags,rejected]=Row.split_fields(interface_fields,[Interface.fields,Interface.tags]) if rejected: raise PLCInvalidArgument, "Cannot add Interface with column(s) %r"%rejected diff --git a/PLC/Methods/AddNode.py b/PLC/Methods/AddNode.py index e8d073a..b722585 100644 --- a/PLC/Methods/AddNode.py +++ b/PLC/Methods/AddNode.py @@ -40,6 +40,8 @@ class AddNode(Method): def call(self, auth, site_id_or_login_base, node_fields): + node_fields = Row.check_fields (node_fields, self.accepted_fields) + [native,tags,rejected]=Row.split_fields(node_fields,[Node.fields,Node.tags]) if rejected: diff --git a/PLC/Methods/AddSlice.py b/PLC/Methods/AddSlice.py index 001e0f9..3e2a89c 100644 --- a/PLC/Methods/AddSlice.py +++ b/PLC/Methods/AddSlice.py @@ -46,6 +46,8 @@ class AddSlice(Method): def call(self, auth, slice_fields): + slice_fields = Row.check_fields (slice_fields, self.accepted_fields) + [native,tags,rejected]=Row.split_fields(slice_fields,[Slice.fields,Slice.tags]) if rejected: diff --git a/PLC/Methods/UpdateInterface.py b/PLC/Methods/UpdateInterface.py index dad6420..48f3822 100644 --- a/PLC/Methods/UpdateInterface.py +++ b/PLC/Methods/UpdateInterface.py @@ -31,7 +31,7 @@ class UpdateInterface(Method): roles = ['admin', 'pi', 'tech'] - accepted_fields = Row.accepted_fields(can_update, [Interface.fields,Interface.tags]) + accepted_fields = Row.accepted_fields(can_update, [Interface.fields,Interface.tags],exclude=True) accepts = [ Auth(), @@ -43,6 +43,8 @@ class UpdateInterface(Method): def call(self, auth, interface_id, interface_fields): + interface_fields = Row.check_fields (interface_fields, self.accepted_fields) + [native,tags,rejected] = Row.split_fields(interface_fields,[Interface.fields,Interface.tags]) if rejected: diff --git a/PLC/Methods/UpdateNode.py b/PLC/Methods/UpdateNode.py index d66dd9e..ecfa6cf 100644 --- a/PLC/Methods/UpdateNode.py +++ b/PLC/Methods/UpdateNode.py @@ -40,6 +40,8 @@ class UpdateNode(Method): def call(self, auth, node_id_or_hostname, node_fields): + node_fields = Row.check_fields (node_fields, self.accepted_fields) + # split provided fields [native,related,tags,rejected] = Row.split_fields(node_fields,[Node.fields,Node.related_fields,Node.tags]) diff --git a/PLC/Methods/UpdateSlice.py b/PLC/Methods/UpdateSlice.py index 29d3bfd..feeb4da 100644 --- a/PLC/Methods/UpdateSlice.py +++ b/PLC/Methods/UpdateSlice.py @@ -48,6 +48,8 @@ class UpdateSlice(Method): def call(self, auth, slice_id_or_name, slice_fields): + slice_fields = Row.check_fields (slice_fields, self.accepted_fields) + # split provided fields [native,related,tags,rejected] = Row.split_fields(slice_fields,[Slice.fields,Slice.related_fields,Slice.tags]) diff --git a/PLC/Table.py b/PLC/Table.py index f37f206..fdd755e 100644 --- a/PLC/Table.py +++ b/PLC/Table.py @@ -239,6 +239,30 @@ class Row(dict): else: rejected.append(column) return (fields,tags,rejected) + # compute the accepts part of an update method from a list of column names, and a (list of) fields dict + # use exclude=True to exclude the column names instead + @staticmethod + def accepted_fields (update_columns, fields, exclude=False): + if not isinstance(fields,list): fields = [fields] + result={} + for fields_dict in fields: + for (k,v) in fields_dict.iteritems(): + if (not exclude and k in update_columns) or (exclude and k not in update_columns): + result[k]=v + return result + + # filter out user-provided fields that are not part of the declared acceptance list + # this could maybe have been integrated in split_fields, but for simplicity we keep it aside + @staticmethod + def check_fields (user_dict, accepted_fields): +# avoid the simple, but silent, version +# return dict ([ (k,v) for (k,v) in user_dict.items() if k in accepted_fields ]) + result={} + for (k,v) in user_dict.items(): + if k in accepted_fields: result[k]=v + else: raise PLCInvalidArgument ('Trying to set/change unaccepted key %s'%k) + return result + # given a dict (typically passed to an Update method), we check and sort # them against a list of dicts, e.g. [Node.fields, Node.related_fields] # return is a list that contains n+1 dicts, last one has the rejected fields @@ -259,17 +283,6 @@ class Row(dict): result.append(rejected) return result - # compute the accepts part of an update method from a list of column names, and a (list of) fields dict - @staticmethod - def accepted_fields (can_update_columns, fields): - result={} - if not isinstance(fields,list): fields = [fields] - for dict in fields: - for (k,v) in dict.iteritems(): - if k in can_update_columns: - result[k]=v - return result - ### class initialization : create tag-dependent cross view if needed @classmethod def tagvalue_view_name (cls, tagname): -- 2.43.0