diff options
Diffstat (limited to 'lib/ssh/src/ssh_auth.erl')
-rw-r--r-- | lib/ssh/src/ssh_auth.erl | 129 |
1 files changed, 60 insertions, 69 deletions
diff --git a/lib/ssh/src/ssh_auth.erl b/lib/ssh/src/ssh_auth.erl index 0c16e19701..4967a2e4cd 100644 --- a/lib/ssh/src/ssh_auth.erl +++ b/lib/ssh/src/ssh_auth.erl @@ -44,15 +44,15 @@ publickey_msg([Alg, #ssh{user = User, Hash = sha, %% Maybe option?! KeyCb = proplists:get_value(key_cb, Opts, ssh_file), case KeyCb:user_key(Alg, Opts) of - {ok, Key} -> - StrAlgo = algorithm_string(Alg), - case encode_public_key(StrAlgo, Key) of + {ok, PrivKey} -> + StrAlgo = atom_to_list(Alg), + case encode_public_key(StrAlgo, ssh_transport:extract_public_key(PrivKey)) of not_ok -> not_ok; PubKeyBlob -> SigData = build_sig_data(SessionId, User, Service, PubKeyBlob, StrAlgo), - Sig = ssh_transport:sign(SigData, Hash, Key), + Sig = ssh_transport:sign(SigData, Hash, PrivKey), SigBlob = list_to_binary([?string(StrAlgo), ?binary(Sig)]), ssh_transport:ssh_packet( #ssh_msg_userauth_request{user = User, @@ -174,15 +174,15 @@ handle_userauth_request(#ssh_msg_userauth_request{user = User, #ssh{opts = Opts, userauth_supported_methods = Methods} = Ssh) -> Password = unicode:characters_to_list(BinPwd), - case check_password(User, Password, Opts) of - true -> + case check_password(User, Password, Opts, Ssh) of + {true,Ssh1} -> {authorized, User, - ssh_transport:ssh_packet(#ssh_msg_userauth_success{}, Ssh)}; - false -> + ssh_transport:ssh_packet(#ssh_msg_userauth_success{}, Ssh1)}; + {false,Ssh1} -> {not_authorized, {User, {error,"Bad user or password"}}, ssh_transport:ssh_packet(#ssh_msg_userauth_failure{ authentications = Methods, - partial_success = false}, Ssh)} + partial_success = false}, Ssh1)} end; handle_userauth_request(#ssh_msg_userauth_request{user = User, @@ -335,16 +335,16 @@ handle_userauth_info_response(#ssh_msg_userauth_info_response{num_responses = 1, kb_tries_left = KbTriesLeft, user = User, userauth_supported_methods = Methods} = Ssh) -> - case check_password(User, unicode:characters_to_list(Password), Opts) of - true -> + case check_password(User, unicode:characters_to_list(Password), Opts, Ssh) of + {true,Ssh1} -> {authorized, User, - ssh_transport:ssh_packet(#ssh_msg_userauth_success{}, Ssh)}; - false -> + ssh_transport:ssh_packet(#ssh_msg_userauth_success{}, Ssh1)}; + {false,Ssh1} -> {not_authorized, {User, {error,"Bad user or password"}}, ssh_transport:ssh_packet(#ssh_msg_userauth_failure{ authentications = Methods, partial_success = false}, - Ssh#ssh{kb_tries_left = max(KbTriesLeft-1, 0)} + Ssh1#ssh{kb_tries_left = max(KbTriesLeft-1, 0)} )} end; @@ -364,6 +364,11 @@ method_preference(Algs) -> [{"publickey", ?MODULE, publickey_msg, [A]} | Acc] end, [{"password", ?MODULE, password_msg, []}, + {"keyboard-interactive", ?MODULE, keyboard_interactive_msg, []}, + {"keyboard-interactive", ?MODULE, keyboard_interactive_msg, []}, + {"keyboard-interactive", ?MODULE, keyboard_interactive_msg, []}, + {"keyboard-interactive", ?MODULE, keyboard_interactive_msg, []}, + {"keyboard-interactive", ?MODULE, keyboard_interactive_msg, []}, {"keyboard-interactive", ?MODULE, keyboard_interactive_msg, []} ], Algs). @@ -387,13 +392,34 @@ user_name(Opts) -> {ok, User} end. -check_password(User, Password, Opts) -> +check_password(User, Password, Opts, Ssh) -> case proplists:get_value(pwdfun, Opts) of undefined -> Static = get_password_option(Opts, User), - Password == Static; - Cheker -> - Cheker(User, Password) + {Password == Static, Ssh}; + + Checker when is_function(Checker,2) -> + {Checker(User, Password), Ssh}; + + Checker when is_function(Checker,4) -> + #ssh{pwdfun_user_state = PrivateState, + peer = {_,PeerAddr={_,_}} + } = Ssh, + case Checker(User, Password, PeerAddr, PrivateState) of + true -> + {true,Ssh}; + false -> + {false,Ssh}; + {true,NewState} -> + {true, Ssh#ssh{pwdfun_user_state=NewState}}; + {false,NewState} -> + {false, Ssh#ssh{pwdfun_user_state=NewState}}; + disconnect -> + throw(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_SERVICE_NOT_AVAILABLE, + description = + "Unable to connect using the available authentication methods", + language = ""}) + end end. get_password_option(Opts, User) -> @@ -430,12 +456,6 @@ build_sig_data(SessionId, User, Service, KeyBlob, Alg) -> ?binary(KeyBlob)], list_to_binary(Sig). -algorithm_string('ssh-rsa') -> "ssh-rsa"; -algorithm_string('ssh-dss') -> "ssh-dss"; -algorithm_string('ecdsa-sha2-nistp256') -> "ecdsa-sha2-nistp256"; -algorithm_string('ecdsa-sha2-nistp384') -> "ecdsa-sha2-nistp384"; -algorithm_string('ecdsa-sha2-nistp521') -> "ecdsa-sha2-nistp521". - decode_keyboard_interactive_prompts(_NumPrompts, Data) -> @@ -457,14 +477,14 @@ keyboard_interact_get_responses(false, undefined, undefined, _, _, _, [Prompt|_] ssh_no_io:read_line(Prompt, Opts); %% Throws error as keyboard interaction is not allowed keyboard_interact_get_responses(true, undefined, _,IoCb, Name, Instr, PromptInfos, Opts, _) -> keyboard_interact(IoCb, Name, Instr, PromptInfos, Opts); -keyboard_interact_get_responses(true, Fun, _, Name, Instr, PromptInfos, _, _, NumPrompts) -> +keyboard_interact_get_responses(true, Fun, _Pwd, _IoCb, Name, Instr, PromptInfos, _Opts, NumPrompts) -> keyboard_interact_fun(Fun, Name, Instr, PromptInfos, NumPrompts). keyboard_interact(IoCb, Name, Instr, Prompts, Opts) -> - if Name /= "" -> IoCb:format("~s", [Name]); + if Name /= "" -> IoCb:format("~s~n", [Name]); true -> ok end, - if Instr /= "" -> IoCb:format("~s", [Instr]); + if Instr /= "" -> IoCb:format("~s~n", [Instr]); true -> ok end, lists:map(fun({Prompt, true}) -> IoCb:read_line(Prompt, Opts); @@ -487,47 +507,18 @@ keyboard_interact_fun(KbdInteractFun, Name, Instr, PromptInfos, NumPrompts) -> language = "en"}}) end. -decode_public_key_v2(<<?UINT32(Len0), _:Len0/binary, - ?UINT32(Len1), E:Len1/big-signed-integer-unit:8, - ?UINT32(Len2), N:Len2/big-signed-integer-unit:8>> - ,"ssh-rsa") -> - {ok, #'RSAPublicKey'{publicExponent = E, modulus = N}}; -decode_public_key_v2(<<?UINT32(Len0), _:Len0/binary, - ?UINT32(Len1), P:Len1/big-signed-integer-unit:8, - ?UINT32(Len2), Q:Len2/big-signed-integer-unit:8, - ?UINT32(Len3), G:Len3/big-signed-integer-unit:8, - ?UINT32(Len4), Y:Len4/big-signed-integer-unit:8>> - , "ssh-dss") -> - {ok, {Y, #'Dss-Parms'{p = P, q = Q, g = G}}}; -decode_public_key_v2(<<?UINT32(Len0), _:Len0/binary, - ?UINT32(Len1), Id:Len1/binary, %% Id = <<"nistp256">> for example - ?UINT32(Len2), Blob:Len2/binary>>, - Curve) -> - Id = - case Curve of - "ecdsa-sha2-nistp256" -> <<"nistp256">>; - "ecdsa-sha2-nistp384" -> <<"nistp384">>; - "ecdsa-sha2-nistp521" -> <<"nistp521">> - end, - {ok, {#'ECPoint'{point=Blob}, Id}}; -decode_public_key_v2(_, _) -> - {error, bad_format}. - -encode_public_key("ssh-rsa", #'RSAPrivateKey'{publicExponent = E, modulus = N}) -> - ssh_bits:encode(["ssh-rsa",E,N], [string,mpint,mpint]); -encode_public_key("ssh-dss", #'DSAPrivateKey'{p = P, q = Q, g = G, y = Y}) -> - ssh_bits:encode(["ssh-dss",P,Q,G,Y], [string,mpint,mpint,mpint,mpint]); -encode_public_key("ecdsa-sha2-"++Curve, #'ECPrivateKey'{parameters = Params, - publicKey = Pub}) -> - Id = ecdsa_id(Params), - if - Id =/= Curve -> - not_ok; - true -> - ssh_bits:encode(["ecdsa-sha2-"++Id, Id, Pub], - [string, string, binary]) +decode_public_key_v2(Bin, _Type) -> + try + public_key:ssh_decode(Bin, ssh2_pubkey) + of + Key -> {ok, Key} + catch + _:_ -> {error, bad_format} end. -ecdsa_id({namedCurve,?'secp256r1'}) -> "nistp256"; -ecdsa_id({namedCurve,?'secp384r1'}) -> "nistp384"; -ecdsa_id({namedCurve,?'secp521r1'}) -> "nistp521". +encode_public_key(_Alg, Key) -> + try + public_key:ssh_encode(Key, ssh2_pubkey) + catch + _:_ -> not_ok + end. |