snmp_user_based_sm_mib.erl

来自「OTP是开放电信平台的简称」· ERL 代码 · 共 1,101 行 · 第 1/3 页

ERL
1,101
字号
						    RowIndex,						    ?usmUserSecurityName) of		    {value, Val} when Val /= noinit -> Val;		    _ -> get_user_name(RowIndex)		end,	    case get(sec_name) of % Check the securityName in the request		SecNameForUser -> ok;		_ -> noAccess(KeyChangeCol)	    end;	false ->	    ok    end.validate_key_change(RowIndex, Cols, KeyChangeCol, Type) ->    case lists:keysearch(KeyChangeCol, 1, Cols) of	{value, {_Col, KeyC}} ->	    %% Check if the row has been cloned; or if it is cloned in	    %% this set-operation.	    OldCloneFrom = snmp_generic:table_get_element(db(usmUserTable),							  RowIndex,							  ?usmUserCloneFrom),	    IsClonePresent = case lists:keysearch(?usmUserCloneFrom, 1, Cols) of				 {value, _} -> true;				 false -> false			     end,	    %% Set is ok if 1) the user already is created, 2) this is	    %% a new user, which has been cloned, or is about to be	    %% cloned.	    case {OldCloneFrom, IsClonePresent} of		{{value, Val}, _} when Val /= noinit ->		    %% The user exists, or has been cloned		    ok;		{_, true} ->		    %% The user is cloned in this operation		    ok;		_ ->		    %% The user doen't exist, or hasn't been cloned,		    %% and is not cloned in this operation.		    inconsistentName(KeyChangeCol)	    end,	    %% Check that the length makes sense	    Len = length(KeyC),	    case Type of		auth ->		    case get_auth_proto(RowIndex, Cols) of			?usmNoAuthProtocol -> ok;			?usmHMACMD5AuthProtocol when Len == 32 -> ok;			?usmHMACSHAAuthProtocol when Len == 40 -> ok;			_ -> wrongValue(KeyChangeCol)		    end;		priv ->		    case get_priv_proto(RowIndex, Cols) of			?usmNoPrivProtocol -> ok;			?usmDESPrivProtocol when Len == 32 -> ok;			?usmAesCfb128Protocol when Len == 32 -> ok;			_ -> wrongValue(KeyChangeCol)		    end	    end;	false ->	    ok    end.validate_priv_protocol(RowIndex, Cols) ->    case lists:keysearch(?usmUserPrivProtocol, 1, Cols) of	{value, {_Col, PrivProtocol}} ->	    %% Check if the row has been cloned; we can't check the	    %% old value of privhProtocol, because if the row was	    %% createAndWaited, the default value would have been	    %% written (usmNoPrivProtocol).	    OldCloneFrom = snmp_generic:table_get_element(db(usmUserTable),							  RowIndex,							  ?usmUserCloneFrom),	    case OldCloneFrom of		{value, Val} when Val /= noinit ->		    %% This means that the cloning is already done; set is ok		    %% if new protocol is usmNoPrivProtocol		    case PrivProtocol of			?usmNoPrivProtocol ->			    ok;			?usmDESPrivProtocol ->			    inconsistentValue(?usmUserPrivProtocol);			?usmAesCfb128Protocol ->			    inconsistentValue(?usmUserPrivProtocol);			_ ->			    wrongValue(?usmUserPrivProtocol)		    end;		_ ->		    %% Otherwise, check that the new protocol is known,		    %% and that the system we're running supports the		    %% crypto function.		    case PrivProtocol of			?usmNoPrivProtocol ->			    ok;			?usmDESPrivProtocol ->			    %% The 'catch' handles the case when 'crypto' is			    %% not present in the system.			    case is_crypto_supported(des_cbc_decrypt) of				true ->				    case get_auth_proto(RowIndex, Cols) of					?usmNoAuthProtocol ->					    inconsistentValue(?usmUserPrivProtocol);					_ ->					    ok				    end;				false -> 				    wrongValue(?usmUserPrivProtocol)			    end;			?usmAesCfb128Protocol ->			    %% The 'catch' handles the case when 'crypto' is			    %% not present in the system.			    case is_crypto_supported(aes_cfb_128_decrypt) of				true ->				    case get_auth_proto(RowIndex, Cols) of					?usmNoAuthProtocol ->					    inconsistentValue(?usmUserPrivProtocol);					_ ->					    ok				    end;				false -> 				    wrongValue(?usmUserPrivProtocol)			    end;			_ -> wrongValue(?usmUserPrivProtocol)		    end	    end;	false ->	    ok    end.set_clone_from(RowIndex, Cols) ->    %% If CloneFrom is modified, do the cloning.    case lists:keysearch(?usmUserCloneFrom, 1, Cols) of	{value, {_Col, RowPointer}} ->	    RowIndex2 = extract_row(RowPointer), % won't fail	    CloneRow = snmp_generic:table_get_row(db(usmUserTable), RowIndex2,						  foi(usmUserTable)),	    AuthP = element(?usmUserAuthProtocol, CloneRow),	    PrivP = element(?usmUserPrivProtocol, CloneRow),	    AuthK = element(?usmUserAuthKey, CloneRow),	    PrivK = element(?usmUserPrivKey, CloneRow),	    SCols = [{?usmUserAuthProtocol, AuthP},		     {?usmUserPrivProtocol, PrivP},		     {?usmUserAuthKey, AuthK},		     {?usmUserPrivKey, PrivK}],	    case snmp_generic:table_set_elements(db(usmUserTable),						 RowIndex,						 SCols) of		true -> ok;		false -> {commitFailed, ?usmUserCloneFrom}	    end;	false ->	    ok    end.set_auth_key_change(RowIndex, Cols) ->    set_key_change(RowIndex, Cols, ?usmUserAuthKeyChange, auth).set_own_auth_key_change(RowIndex, Cols) ->    set_key_change(RowIndex, Cols, ?usmUserOwnAuthKeyChange, auth).set_priv_key_change(RowIndex, Cols) ->    set_key_change(RowIndex, Cols, ?usmUserPrivKeyChange, priv).set_own_priv_key_change(RowIndex, Cols) ->    set_key_change(RowIndex, Cols, ?usmUserOwnPrivKeyChange, priv).set_key_change(RowIndex, Cols, KeyChangeCol, Type) ->    case lists:keysearch(KeyChangeCol, 1, Cols) of	{value, {_Col, KeyChange}} ->	    KeyCol = case Type of			 auth -> ?usmUserAuthKey;			 priv -> ?usmUserPrivKey		     end,	    [AuthP, Key] =		snmp_generic:table_get_elements(db(usmUserTable),						RowIndex,						[?usmUserAuthProtocol,						 KeyCol]),	    NewKey = extract_new_key(AuthP, Key, KeyChange),	    snmp_generic:table_set_element(db(usmUserTable), RowIndex,					   KeyCol, NewKey);	false ->	    ok    end.%% Extract the UserName part from a RowIndex.get_user_name([L1 | Rest])         -> get_user_name(L1, Rest).get_user_name(0, [_L2 | UserName]) -> UserName;get_user_name(N, [_H | T])          -> get_user_name(N-1, T).extract_row(RowPtr)                     -> extract_row(?usmUserEntry, RowPtr).extract_row([H | T], [H | T2])          -> extract_row(T, T2);extract_row([], [?usmUserSecurityName | T]) -> T;extract_row(_, _) -> wrongValue(?usmUserCloneFrom).%% Pre: the user exixtget_auth_proto(RowIndex, Cols) ->    %% The protocol can be chanegd by the request too, otherwise,    %% check the stored protocol.    case lists:keysearch(?usmUserAuthProtocol, 1, Cols) of	{value, {_, Protocol}} ->	    Protocol;	false ->	    %% OTP-3596	    case snmp_generic:table_get_element(db(usmUserTable),						RowIndex,						?usmUserAuthProtocol) of		{value, Protocol} ->		    Protocol;		_ ->		    undefined	    end    end.%% Pre: the user exixtget_priv_proto(RowIndex, Cols) ->    %% The protocol can be chanegd by the request too, otherwise,    %% check the stored protocol.    case lists:keysearch(?usmUserPrivProtocol, 1, Cols) of	{value, {_, Protocol}} ->	    Protocol;	false ->	    %% OTP-3596	    case snmp_generic:table_get_element(db(usmUserTable),						RowIndex,						?usmUserPrivProtocol) of		{value, Protocol} ->		    Protocol;		_ ->		    undefined	    end    end.db(X) -> snmpa_agent:db(X).fa(usmUserTable) -> ?usmUserSecurityName. foi(usmUserTable) -> ?usmUserEngineID. noc(usmUserTable) -> 13.stc(usmUserTable) -> ?usmUserStorageType. next(Name, RowIndex, Cols) ->    snmp_generic:handle_table_next(db(Name), RowIndex, Cols,                                   fa(Name), foi(Name), noc(Name)).table_next(Name, RestOid) ->    snmp_generic:table_next(db(Name), RestOid). get(Name, RowIndex, Cols) ->    snmp_generic:handle_table_get(db(Name), RowIndex, Cols, foi(Name)).%%-----------------------------------------------------------------%% Key change functions.  The KeyChange Texual-Convention is%% defined in the SNMP-USER-BASED-SM-MIB.%% Note that this implementation supports md5 and sha, which%% both have fixed length requirements on the length of the key;%% thus the implementation can be (and is) simplified.%%-----------------------------------------------------------------mk_key_change(Hash, OldKey, NewKey) ->    KeyLen = length(NewKey),    Alg = case Hash of	      ?usmHMACMD5AuthProtocol -> md5;	      ?usmHMACSHAAuthProtocol -> sha;	      md5 -> md5;	      sha -> sha	  end,    Random = mk_random(KeyLen),    mk_key_change(Alg, OldKey, NewKey, KeyLen, Random).%% This function is only exported for test purposes.  There is a test%% case in the standard where Random is pre-defined.mk_key_change(Alg, OldKey, NewKey, KeyLen, Random) ->    %% OldKey and Random is of length KeyLen...    Digest = lists:sublist(binary_to_list(crypto:Alg(OldKey++Random)), KeyLen),    %% ... and so is Digest    Delta = snmp_misc:str_xor(Digest, NewKey),    Random ++ Delta.%% Extracts a new Key from a KeyChange value, sent by a manager.extract_new_key(?usmNoAuthProtocol, OldKey, _KeyChange) ->    OldKey;extract_new_key(Hash, OldKey, KeyChange) ->    KeyLen = length(OldKey),    Alg = case Hash of	      ?usmHMACMD5AuthProtocol -> md5;	      ?usmHMACSHAAuthProtocol -> sha;	      md5 -> md5;	      sha -> sha	  end,    {Random, Delta} = split(KeyLen, KeyChange, []),    Digest = lists:sublist(binary_to_list(crypto:Alg(OldKey++Random)), KeyLen),    NewKey = snmp_misc:str_xor(Digest, Delta),    NewKey.-define(i16(Int), (Int bsr 8) band 255, Int band 255).-define(i8(Int), Int band 255).mk_random(Len) when Len =< 20 ->    %% Use of yield():    %% This will either schedule another process, or fail and invoke    %% the error_handler (in old versions).  In either case, it is    %% safe to assume that now, reductions and garbage_collection have    %% changed in a non-deterministically way.    {_,_,A} = erlang:now(),    catch erlang:yield(),    {_,_,B} = erlang:now(),    catch erlang:yield(),    {_,_,C} = erlang:now(),    {D,_}   = erlang:statistics(reductions),    {E,_}   = erlang:statistics(runtime),    {F,_}   = erlang:statistics(wall_clock),    {G,H,_} = erlang:statistics(garbage_collection),    catch erlang:yield(),    {_,_,C2} = erlang:now(),    {D2,_}   = erlang:statistics(reductions),    {_,H2,_} = erlang:statistics(garbage_collection),    %% X(N) means we can use N bits from variable X:    %% A(16) B(16) C(16) D(16) E(8) F(16) G(8) H(16)    Rnd20 = [?i16(A),?i16(B),?i16(C),?i16(D),?i8(E),?i16(F),	     ?i8(G),?i16(H),?i16(C2),?i16(D2),?i16(H2)],    lists:sublist(Rnd20, Len).    split(0, Rest, FirstRev) ->    {lists:reverse(FirstRev), Rest};split(N, [H | T], FirstRev) when N > 0 ->    split(N-1, T, [H | FirstRev]).is_crypto_supported(Func) ->    %% The 'catch' handles the case when 'crypto' is    %% not present in the system (or not started).    case catch lists:member(Func, crypto:info()) of	true -> true;	_ -> false    end.inconsistentValue(V) -> throw({inconsistentValue, V}).inconsistentName(N)  -> throw({inconsistentName,  N}).wrongValue(V)        -> throw({wrongValue,        V}).noAccess(C)          -> throw({noAccess,          C}).     set_sname() ->    set_sname(get(sname)).set_sname(undefined) ->    put(sname,conf);set_sname(_) -> %% Keep it, if already set.    ok.error(Reason) ->    throw({error, Reason}).%%-----------------------------------------------------------------info_msg(F, A) ->    ?snmpa_info("USM: " ++ F, A).%% --- config_err(F, A) ->    snmpa_error:config_err("[USER-BASED-SM-MIB]: " ++ F, A).

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?