From 73d7e1161e4e208338eb3e28c37462277499eeb5 Mon Sep 17 00:00:00 2001 From: Alexey Shchepin Date: Sun, 1 Aug 2004 20:12:20 +0000 Subject: [PATCH] * src/tls/tls.erl: Added recv_data/2 function * src/jlib.erl: Added NS_TLS macro * src/ejabberd_receiver.erl: Support for STARTTLS * src/ejabberd_c2s.erl: Likewise SVN Revision: 252 --- ChangeLog | 9 +++++++ src/ejabberd_c2s.erl | 55 ++++++++++++++++++++++++++++++--------- src/ejabberd_receiver.erl | 31 ++++++++++++++++++++-- src/jlib.hrl | 1 + src/tls/tls.erl | 41 +++++++++++++++-------------- 5 files changed, 104 insertions(+), 33 deletions(-) diff --git a/ChangeLog b/ChangeLog index 98386a68f..9f00cb106 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2004-08-01 Alexey Shchepin + + * src/tls/tls.erl: Added recv_data/2 function + + * src/jlib.erl: Added NS_TLS macro + + * src/ejabberd_receiver.erl: Support for STARTTLS + * src/ejabberd_c2s.erl: Likewise + 2004-07-30 Alexey Shchepin * examples/extauth/check_pass_null.pl: A reference "null" diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index a920597f4..b5b3128da 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -23,7 +23,7 @@ -export([init/1, wait_for_stream/2, wait_for_auth/2, - wait_for_sasl_auth/2, + wait_for_feature_request/2, wait_for_bind/2, wait_for_session/2, wait_for_sasl_response/2, @@ -178,12 +178,26 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) -> {xmlelement, "mechanism", [], [{xmlcdata, S}]} end, cyrsasl:listmech()), + TLS = StateData#state.tls, + TLSEnabled = StateData#state.tls_enabled, + SockMod = StateData#state.sockmod, + TLSFeature = + case (TLS == true) andalso + (TLSEnabled == false) andalso + (SockMod == gen_tcp) of + true -> + [{xmlelement, "starttls", + [{"xmlns", ?NS_TLS}], []}]; + false -> + [] + end, send_element(StateData, {xmlelement, "stream:features", [], + TLSFeature ++ [{xmlelement, "mechanisms", [{"xmlns", ?NS_SASL}], Mechs}]}), - {next_state, wait_for_sasl_auth, + {next_state, wait_for_feature_request, StateData#state{sasl_state = SASLState, lang = Lang}}; _ -> @@ -357,8 +371,11 @@ wait_for_auth(closed, StateData) -> {stop, normal, StateData}. -wait_for_sasl_auth({xmlstreamelement, El}, StateData) -> +wait_for_feature_request({xmlstreamelement, El}, StateData) -> {xmlelement, Name, Attrs, Els} = El, + TLS = StateData#state.tls, + TLSEnabled = StateData#state.tls_enabled, + SockMod = StateData#state.sockmod, case {xml:get_attr_s("xmlns", Attrs), Name} of {?NS_SASL, "auth"} -> Mech = xml:get_attr_s("mechanism", Attrs), @@ -391,8 +408,22 @@ wait_for_sasl_auth({xmlstreamelement, El}, StateData) -> {xmlelement, "failure", [{"xmlns", ?NS_SASL}], [{xmlelement, Error, [], []}]}), - {next_state, wait_for_sasl_auth, StateData} + {next_state, wait_for_feature_request, StateData} end; + {?NS_TLS, "starttls"} when TLS == true, + TLSEnabled == false, + SockMod == gen_tcp -> + Socket = StateData#state.socket, + TLSOpts = StateData#state.tls_options, + {ok, TLSSocket} = tls:tcp_to_tls(Socket, TLSOpts), + ejabberd_receiver:starttls(StateData#state.receiver, TLSSocket), + send_element(StateData, + {xmlelement, "proceed", [{"xmlns", ?NS_TLS}], []}), + {next_state, wait_for_stream, + StateData#state{sockmod = tls, + socket = TLSSocket, + tls_enabled = true + }}; _ -> case jlib:iq_query_info(El) of #iq{xmlns = ?NS_REGISTER} = IQ -> @@ -403,21 +434,21 @@ wait_for_sasl_auth({xmlstreamelement, El}, StateData) -> jlib:iq_to_xml(ResIQ)), Res = jlib:remove_attr("to", Res1), send_element(StateData, Res), - {next_state, wait_for_sasl_auth, StateData}; + {next_state, wait_for_feature_request, StateData}; _ -> - {next_state, wait_for_sasl_auth, StateData} + {next_state, wait_for_feature_request, StateData} end end; -wait_for_sasl_auth({xmlstreamend, _Name}, StateData) -> +wait_for_feature_request({xmlstreamend, _Name}, StateData) -> send_text(StateData, ?STREAM_TRAILER), {stop, normal, StateData}; -wait_for_sasl_auth({xmlstreamerror, _}, StateData) -> +wait_for_feature_request({xmlstreamerror, _}, StateData) -> send_text(StateData, ?INVALID_XML_ERR ++ ?STREAM_TRAILER), {stop, normal, StateData}; -wait_for_sasl_auth(closed, StateData) -> +wait_for_feature_request(closed, StateData) -> {stop, normal, StateData}. @@ -453,7 +484,7 @@ wait_for_sasl_response({xmlstreamelement, El}, StateData) -> {xmlelement, "failure", [{"xmlns", ?NS_SASL}], [{xmlelement, Error, [], []}]}), - {next_state, wait_for_sasl_auth, StateData} + {next_state, wait_for_feature_request, StateData} end; _ -> case jlib:iq_query_info(El) of @@ -465,9 +496,9 @@ wait_for_sasl_response({xmlstreamelement, El}, StateData) -> jlib:iq_to_xml(ResIQ)), Res = jlib:remove_attr("to", Res1), send_element(StateData, Res), - {next_state, wait_for_sasl_auth, StateData}; + {next_state, wait_for_feature_request, StateData}; _ -> - {next_state, wait_for_sasl_auth, StateData} + {next_state, wait_for_feature_request, StateData} end end; diff --git a/src/ejabberd_receiver.erl b/src/ejabberd_receiver.erl index 308d1b94c..8217bb7e8 100644 --- a/src/ejabberd_receiver.erl +++ b/src/ejabberd_receiver.erl @@ -13,7 +13,8 @@ -export([start/3, receiver/4, change_shaper/2, - reset_stream/1]). + reset_stream/1, + starttls/2]). -include("ejabberd.hrl"). @@ -34,7 +35,30 @@ receiver(Socket, SockMod, Shaper, C2SPid) -> receiver(Socket, SockMod, ShaperState, C2SPid, XMLStreamPid, Timeout). receiver(Socket, SockMod, ShaperState, C2SPid, XMLStreamPid, Timeout) -> - case catch SockMod:recv(Socket, 0, Timeout) of + Res = (catch SockMod:recv(Socket, 0, Timeout)), + case Res of + {ok, Data} -> + receive + {starttls, TLSSocket} -> + exit(XMLStreamPid, closed), + XMLStreamPid1 = xml_stream:start(self(), C2SPid), + TLSRes = tls:recv_data(TLSSocket, Data), + receiver1(TLSSocket, tls, + ShaperState, C2SPid, XMLStreamPid1, Timeout, + TLSRes) + after 0 -> + receiver1(Socket, SockMod, + ShaperState, C2SPid, XMLStreamPid, Timeout, + Res) + end; + _ -> + receiver1(Socket, SockMod, + ShaperState, C2SPid, XMLStreamPid, Timeout, Res) + end. + + +receiver1(Socket, SockMod, ShaperState, C2SPid, XMLStreamPid, Timeout, Res) -> + case Res of {ok, Text} -> ShaperSt1 = receive {change_shaper, Shaper} -> @@ -75,4 +99,7 @@ change_shaper(Pid, Shaper) -> reset_stream(Pid) -> Pid ! reset_stream. +starttls(Pid, TLSSocket) -> + Pid ! {starttls, TLSSocket}. + diff --git a/src/jlib.hrl b/src/jlib.hrl index 29afc3dc4..c684a7f3b 100644 --- a/src/jlib.hrl +++ b/src/jlib.hrl @@ -40,6 +40,7 @@ -define(NS_STANZAS, "urn:ietf:params:xml:ns:xmpp-stanzas"). -define(NS_STREAMS, "urn:ietf:params:xml:ns:xmpp-streams"). +-define(NS_TLS, "urn:ietf:params:xml:ns:xmpp-tls"). -define(NS_SASL, "urn:ietf:params:xml:ns:xmpp-sasl"). -define(NS_SESSION, "urn:ietf:params:xml:ns:xmpp-session"). -define(NS_BIND, "urn:ietf:params:xml:ns:xmpp-bind"). diff --git a/src/tls/tls.erl b/src/tls/tls.erl index edf94a169..361c92fcf 100644 --- a/src/tls/tls.erl +++ b/src/tls/tls.erl @@ -15,7 +15,7 @@ -export([start/0, start_link/0, tcp_to_tls/2, tls_to_tcp/1, send/2, - recv/2, recv/3, + recv/2, recv/3, recv_data/2, close/1, test/0]). @@ -86,7 +86,6 @@ tcp_to_tls(TCPSocket, Options) -> {value, {certfile, CertFile}} -> ok = erl_ddll:load_driver(ejabberd:get_so_path(), tls_drv), Port = open_port({spawn, tls_drv}, [binary]), - io:format("open_port: ~p~n", [Port]), case port_control(Port, ?SET_CERTIFICATE_FILE, CertFile ++ [0]) of <<0>> -> @@ -104,23 +103,27 @@ tls_to_tcp(#tlssock{tcpsock = TCPSocket, tlsport = Port}) -> recv(Socket, Length) -> recv(Socket, Length, infinity). -recv(#tlssock{tcpsock = TCPSocket, tlsport = Port}, Length, Timeout) -> +recv(#tlssock{tcpsock = TCPSocket, tlsport = Port} = TLSSock, + Length, Timeout) -> case gen_tcp:recv(TCPSocket, Length, Timeout) of {ok, Packet} -> - case port_control(Port, ?SET_ENCRYPTED_INPUT, Packet) of - <<0>> -> - case port_control(Port, ?GET_DECRYPTED_INPUT, []) of - <<0, In/binary>> -> - case port_control(Port, ?GET_ENCRYPTED_OUTPUT, []) of - <<0, Out/binary>> -> - case gen_tcp:send(TCPSocket, Out) of - ok -> - {ok, In}; - Error -> - Error - end; - <<1, Error/binary>> -> - {error, binary_to_list(Error)} + recv_data(TLSSock, Packet); + {error, _Reason} = Error -> + Error + end. + +recv_data(#tlssock{tcpsock = TCPSocket, tlsport = Port}, Packet) -> + case port_control(Port, ?SET_ENCRYPTED_INPUT, Packet) of + <<0>> -> + case port_control(Port, ?GET_DECRYPTED_INPUT, []) of + <<0, In/binary>> -> + case port_control(Port, ?GET_ENCRYPTED_OUTPUT, []) of + <<0, Out/binary>> -> + case gen_tcp:send(TCPSocket, Out) of + ok -> + {ok, In}; + Error -> + Error end; <<1, Error/binary>> -> {error, binary_to_list(Error)} @@ -128,8 +131,8 @@ recv(#tlssock{tcpsock = TCPSocket, tlsport = Port}, Length, Timeout) -> <<1, Error/binary>> -> {error, binary_to_list(Error)} end; - {error, _Reason} = Error -> - Error + <<1, Error/binary>> -> + {error, binary_to_list(Error)} end. send(#tlssock{tcpsock = TCPSocket, tlsport = Port}, Packet) ->