Re: SNMP/VACM: bugfix for vacmViewTreeFamilyMask

Stefan Zegenhagen <[email protected]>
Newsgroups gmane.comp.lang.erlang.patches
Organization arcutronix GmbH
Message-ID <1370855220.3947.44.camel@ax-sze>
Dear all,


it's almost a year since I sent the patch attached to this e-mail, and I
just found out that I have not yet gotten a response to it.

I would consider this patch important because it fixes an issue with the
interpretation of data that might be critical for SNMPv3 operation. I
confirmed at that time that erlangs interpretation of
vacmViewTreeFamilyMask is indeed not interoperable with other SNMP
stacks.


Kind regards,


> > > the implementation of SNMP-VIEW-BASED-ACM.mib assumes that the input for
> > > vacmViewTreeFamilyMask is an OID consisting of 1's and 0's only to form
> > > the mask. However, the MIB states that the input should be a bitstring.
> > > 
> > > The OID representation of the mask is useful in the code as it speeds up
> > > time-critical code paths when checking access permissions for EACH SNMP
> > > access. Reading/writing the view mask objects is less time-critical.
> > > 
> > > Therefore, to fix the issue, convert between OID representation and
> > > bitstring when the vacmViewTreeFamilyMask objects are accessed. This is
> > > done by the patch attached to this e-mail.
> 
> 
> I'm very sorry for the troubles that I am causing but it seems that the
> previous version of the patch did more than it should: the OID-bitstring
> conversion was also applied to other tables in the same MIB on
> get/get-next requests.
> 
> The version of the patch that is attached to this e-mail restricts the
> OID-bitstring conversion to vacmViewTreeFamilyMask alone.


-- 
Dr. Stefan Zegenhagen

arcutronix GmbH
Garbsener Landstr. 10
30419 Hannover
Germany

Tel:   +49 511 277-2734
Fax:   +49 511 277-2709
Email: [email protected]
Web:   www.arcutronix.com

*Synchronize the Ethernet*

General Managers: Dipl. Ing. Juergen Schroeder, Dr. Josef Gfrerer -
Legal Form: GmbH, Registered office: Hannover, HRB 202442, Amtsgericht
Hannover; Ust-Id: DE257551767.

Please consider the environment before printing this message.

_______________________________________________
erlang-patches mailing list
[email protected]
http://erlang.org/mailman/listinfo/erlang-patches
0001-bugfix-for-vacmViewTreeFamilyMask.patch (text/x-patch, 4.6 KB)
From aa2acfb8a0b5ae05fc5ba982d78ee5607384a2be Mon Sep 17 00:00:00 2001
From: Stefan Zegenhagen <[email protected]>
Date: Wed, 1 Aug 2012 09:56:15 +0200
Subject: [PATCH] bugfix for vacmViewTreeFamilyMask

The vacmViewTreeFamilyMask is defined to be a bit string in the MIB, not
an OID. However, the MIB implementation assumed the latter, effectively
rendering all attempts to read/set masks via SNMP unsuccessful.

Since the mask is used in hot paths (e.g. access permission checks for
each SNMP operation, the OID representation of the mask has benefits
(e.g. faster processing). Therefore, convert the bitstring to/from its
OID representation when reading/setting any mask object.
---
 lib/snmp/src/agent/snmp_view_based_acm_mib.erl |   91 ++++++++++++++++++++++--
 1 file changed, 85 insertions(+), 6 deletions(-)

diff --git a/lib/snmp/src/agent/snmp_view_based_acm_mib.erl b/lib/snmp/src/agent/snmp_view_based_acm_mib.erl
index 71dcc0f..56fbf90 100644
--- a/lib/snmp/src/agent/snmp_view_based_acm_mib.erl
+++ b/lib/snmp/src/agent/snmp_view_based_acm_mib.erl
@@ -949,9 +949,9 @@ verify_vacmViewTreeFamilyTable_col(?vacmViewTreeFamilyMask, Mask) ->
 	null -> [];
 	[]   -> [];
 	_ ->
-	    case (catch snmp_conf:check_oid(Mask)) of
+	    case (catch check_mask(Mask)) of
 		ok ->
-		    Mask;
+		    mask2oid(Mask);
 	        _ ->
 		    wrongValue(?vacmViewTreeFamilyMask)
 	    end
@@ -967,7 +967,54 @@ verify_vacmViewTreeFamilyTable_col(?vacmViewTreeFamilyType, Type) ->
     end;
 verify_vacmViewTreeFamilyTable_col(_, Val) ->
     Val.
-	    
+
+
+check_mask([]) ->
+    ok;
+check_mask([Head | Tail]) when is_integer(Head) ->
+% we can cause exception here because the caller catches
+    if
+        Head > -1 andalso Head < 256 ->
+            check_mask(Tail)
+    end.
+
+% internally (for easier computations), the mask is stored
+% as OID and not as bit-field. Therefore, we have to convert
+% the bitstring to a list of integers before storing it.
+mask2oid(Mask) ->
+    Func = fun(Byte) ->
+            % what's a nice syntax for extracting bits
+            % from a byte???
+            <<A:1, B:1, C:1, D:1, E:1, F:1, G:1, H:1>> = <<Byte>>,
+            [A, B, C, D, E, F, G, H]
+    end,
+    lists:flatten(lists:map(Func, Mask)).
+
+oid2mask(Oid) ->
+    % convert all suboids to either 1 or 0 for sure
+    Func = fun
+        (0) -> 0;
+        (_) -> 1
+    end,
+    oid2mask(lists:map(Func, Oid), []).
+
+oid2mask([], Mask) ->
+    % end-of-list, return bitstring
+    lists:reverse(Mask);
+oid2mask(Oid, Mask) ->
+    % check whether we've got at least 8 sub-identifiers. if not,
+    % extend with 1's until there are enough to fill a byte
+    NOid = case length(Oid) of
+        Small when Small < 8 ->
+            Oid ++ lists:duplicate(8-Small, 1);
+        _ ->
+            Oid
+    end,
+    % extract sufficient suboids for 8 bits
+    [A, B, C, D, E, F, G, H | Tail] = NOid,
+    <<Byte:8>> = <<A:1, B:1, C:1, D:1, E:1, F:1, G:1, H:1>>,
+    oid2mask(Tail, [Byte | Mask]).
+
 
 table_next(Name, RestOid) ->
     snmp_generic:table_next(db(Name), RestOid).
@@ -1006,11 +1053,43 @@ stc(vacmSecurityToGroupTable) -> ?vacmSecurityToGroupStorageType;
 stc(vacmViewTreeFamilyTable) -> ?vacmViewTreeFamilyStorageType.
  
 next(Name, RowIndex, Cols) ->
-    snmp_generic:handle_table_next(db(Name), RowIndex, Cols,
-                                   fa(Name), foi(Name), noc(Name)).
+    Ans = snmp_generic:handle_table_next(db(Name), RowIndex, Cols,
+                                   fa(Name), foi(Name), noc(Name)),
+    patch_next(Name, Ans).
  
 get(Name, RowIndex, Cols) ->
-    snmp_generic:handle_table_get(db(Name), RowIndex, Cols, foi(Name)).
+    Ans = snmp_generic:handle_table_get(db(Name), RowIndex, Cols, foi(Name)),
+    patch(Name, Cols, Ans).
+
+
+patch(Name, Cols, Ans) when is_list(Ans) ->
+    % function to patch returned values
+    Func = fun
+        ({Col, {value, Val}}) ->    {value, do_patch(Name, Col, Val)};
+        ({_, Other}) ->             Other
+    end,
+    % merge column numbers and return values. there must be as much
+    % return values as there are columns requested
+    Tmp = lists:zip(Cols, Ans),
+    % and patch all values
+    lists:map(Func, Tmp);
+patch(_, _, Ans) ->
+    Ans.
+
+patch_next(Name, Ans) when is_list(Ans) ->
+    Func = fun
+        ({[C | _] = Idx, Val}) ->   {Idx, do_patch(Name, C, Val)};
+        (Other) ->                  Other
+    end,
+    lists:map(Func, Ans);
+patch_next(_, Ans) ->
+    Ans.
+
+do_patch(vacmViewTreeFamilyTable, ?vacmViewTreeFamilyMask, Val) ->
+    oid2mask(Val);
+do_patch(_, _, Val) ->
+    Val.
+
 
 wrongValue(V) -> throw({wrongValue, V}).
 
-- 
1.7.9.5
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.