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 + -
显示快捷键?