]> granicus.if.org Git - ejabberd/commitdiff
* src/ejabberd_s2s_out.erl: Fixed ports leak
authorAlexey Shchepin <alexey@process-one.net>
Wed, 12 Mar 2003 19:48:05 +0000 (19:48 +0000)
committerAlexey Shchepin <alexey@process-one.net>
Wed, 12 Mar 2003 19:48:05 +0000 (19:48 +0000)
* src/ejabberd_listener.erl: Likewise

* src/ejabberd_c2s.erl: Fixes for SASL support

* src/cyrsasl.erl: Fixes

* src/cyrsasl_digest.erl: DIGEST-MD5 SASL mechanism support

SVN Revision: 87

ChangeLog
src/cyrsasl.erl
src/cyrsasl_digest.erl [new file with mode: 0644]
src/ejabberd_auth.erl
src/ejabberd_c2s.erl
src/ejabberd_listener.erl
src/ejabberd_s2s_out.erl
src/xml_stream.erl

index 5032cca2e11b72ff8645bcf16ff503c23f29b967..65fd89058fea6ae05a67c25ff37c67e21b6880ff 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2003-03-12  Alexey Shchepin  <alexey@sevcom.net>
+
+       * src/ejabberd_s2s_out.erl: Fixed ports leak
+       * src/ejabberd_listener.erl: Likewise
+
+       * src/ejabberd_c2s.erl: Fixes for SASL support
+
+       * src/cyrsasl.erl: Fixes
+
+       * src/cyrsasl_digest.erl: DIGEST-MD5 SASL mechanism support
+
 2003-03-09  Alexey Shchepin  <alexey@sevcom.net>
 
        * src/cyrsasl*.erl: SASL support (currently support only PLAIN
index 537ad4f1b300b98d755cad7e314562b19e80abcc..bc6a80be9a3e05ed4d55d46166fafd2df3969e61 100644 (file)
@@ -33,6 +33,7 @@ start() ->
                             public,
                             {keypos, #sasl_mechanism.mechanism}]),
     cyrsasl_plain:start([]),
+    cyrsasl_digest:start([]),
     ok.
 
 register_mechanism(Mechanism, Module) ->
@@ -52,7 +53,7 @@ server_new(Service, ServerFQDN, UserRealm, SecFlags) ->
 server_start(State, Mech, ClientIn) ->
     case ets:lookup(sasl_mechanism, Mech) of
        [#sasl_mechanism{module = Module}] ->
-           MechState = Module:mech_new(),
+           {ok, MechState} = Module:mech_new(),
            server_step(State#sasl_state{mech_mod = Module,
                                         mech_state = MechState},
                        ClientIn);
diff --git a/src/cyrsasl_digest.erl b/src/cyrsasl_digest.erl
new file mode 100644 (file)
index 0000000..c4593c3
--- /dev/null
@@ -0,0 +1,144 @@
+%%%----------------------------------------------------------------------
+%%% File    : cyrsasl_digest.erl
+%%% Author  : Alexey Shchepin <alexey@sevcom.net>
+%%% Purpose : DIGEST-MD5 SASL mechanism
+%%% Created : 11 Mar 2003 by Alexey Shchepin <alexey@sevcom.net>
+%%% Id      : $Id$
+%%%----------------------------------------------------------------------
+
+-module(cyrsasl_digest).
+-author('alexey@sevcom.net').
+-vsn('$Revision$ ').
+
+-export([start/1,
+        stop/0,
+        mech_new/0,
+        mech_step/2]).
+
+-behaviour(cyrsasl).
+%-behaviour(gen_mod).
+
+-record(state, {step, nonce, username}).
+
+start(Opts) ->
+    cyrsasl:register_mechanism("DIGEST-MD5", ?MODULE),
+    ok.
+
+stop() ->
+    ok.
+
+mech_new() ->
+    {ok, #state{step = 1,
+               nonce = randoms:get_string()}}.
+
+mech_step(#state{step = 1, nonce = Nonce} = State, "") ->
+    {continue,
+     "nonce=\"" ++ jlib:encode_base64(Nonce) ++
+     "\",qop=\"auth,auth-int\",charset=utf-8,algorithm=md5-sess",
+     State#state{step = 3}};
+mech_step(#state{step = 3, nonce = Nonce} = State, ClientIn) ->
+    case parse(ClientIn) of
+       bad ->
+           {error, "454"};
+       KeyVals ->
+           UserName = xml:get_attr_s("username", KeyVals),
+           case ejabberd_auth:get_password(UserName) of
+               false ->
+                   {error, "454"};
+               Passwd ->
+                   Response = response(KeyVals, UserName, Passwd,
+                                       "AUTHENTICATE"),
+                   case xml:get_attr_s("response", KeyVals) of
+                       Response ->
+                           RspAuth = response(KeyVals, UserName, Passwd, ""),
+                           {continue,
+                            "rspauth=" ++ RspAuth,
+                            State#state{step = 5, username = UserName}};
+                       _ ->
+                           {error, "454"}
+                   end
+           end
+    end;
+mech_step(#state{step = 5, username = UserName} = State, "") ->
+    {ok, [{username, UserName}]};
+mech_step(A, B) ->
+    io:format("SASL DIGEST: A ~p B ~p", [A,B]),
+    {error, "454"}.
+
+
+parse(S) ->
+    parse1(S, "", []).
+
+parse1([$= | Cs], S, Ts) ->
+    parse2(Cs, lists:reverse(S), "", Ts);
+parse1([C | Cs], S, Ts) ->
+    parse1(Cs, [C | S], Ts);
+parse1([], [], T) ->
+    lists:reverse(T);
+parse1([], S, T) ->
+    bad.
+
+parse2([$" | Cs], Key, Val, Ts) ->
+    parse3(Cs, Key, Val, Ts);
+parse2([C | Cs], Key, Val, Ts) ->
+    parse4(Cs, Key, [C | Val], Ts);
+parse2([], _, _, _) ->
+    bad.
+
+parse3([$" | Cs], Key, Val, Ts) ->
+    parse4(Cs, Key, Val, Ts);
+parse3([C | Cs], Key, Val, Ts) ->
+    parse3(Cs, Key, [C | Val], Ts);
+parse3([], _, _, _) ->
+    bad.
+
+parse4([$, | Cs], Key, Val, Ts) ->
+    parse1(Cs, "", [{Key, lists:reverse(Val)} | Ts]);
+parse4([C | Cs], Key, Val, Ts) ->
+    parse4(Cs, Key, [C | Val], Ts);
+parse4([], Key, Val, Ts) ->
+    parse1([], "", [{Key, lists:reverse(Val)} | Ts]).
+
+
+
+
+
+
+digit_to_xchar(D) when (D >= 0) and (D < 10) ->
+    D + 48;
+digit_to_xchar(D) ->
+    D + 87.
+
+hex(S) ->
+    hex(S, []).
+
+hex([], Res) ->
+    lists:reverse(Res);
+hex([N | Ns], Res) ->
+    hex(Ns, [digit_to_xchar(N rem 16),
+            digit_to_xchar(N div 16) | Res]).
+
+
+response(KeyVals, User, Passwd, A2Prefix) ->
+    Realm = xml:get_attr_s("realm", KeyVals),
+    Nonce = xml:get_attr_s("nonce", KeyVals),
+    CNonce = xml:get_attr_s("cnonce", KeyVals),
+    DigestURI = xml:get_attr_s("digest-uri", KeyVals),
+    NC = xml:get_attr_s("nc", KeyVals),
+    QOP = xml:get_attr_s("qop", KeyVals),
+    A1 = binary_to_list(crypto:md5(User ++ ":" ++ Realm ++ ":" ++ Passwd)) ++
+       ":" ++ Nonce ++ ":" ++ CNonce,
+    case QOP of
+       "auth" ->
+           A2 = A2Prefix ++ ":" ++ DigestURI;
+       _ ->
+           A2 = A2Prefix ++ ":" ++ DigestURI ++
+               ":00000000000000000000000000000000"
+    end,
+    T = hex(binary_to_list(crypto:md5(A1))) ++ ":" ++ Nonce ++ ":" ++
+       NC ++ ":" ++ CNonce ++ ":" ++ QOP ++ ":" ++
+       hex(binary_to_list(crypto:md5(A2))),
+    hex(binary_to_list(crypto:md5(T))).
+
+
+
index efe9e407b74963f3a7b6ed4e3cd8cd492bfdd85b..e080b8028539496a5d442a2382d6a91552adbc70 100644 (file)
@@ -19,6 +19,7 @@
         check_password/4,
         try_register/2,
         dirty_get_registered_users/0,
+        get_password/1,
         get_password_s/1,
         is_user_exists/1,
         remove_user/1,
@@ -166,6 +167,15 @@ try_register(User, Password) ->
 dirty_get_registered_users() ->
     mnesia:dirty_all_keys(passwd).
 
+get_password(User) ->
+    LUser = jlib:tolower(User),
+    case catch mnesia:dirty_read(passwd, LUser) of
+       [#passwd{password = Password}] ->
+           Password;
+       _ ->
+           false
+    end.
+
 get_password_s(User) ->
     LUser = jlib:tolower(User),
     case catch mnesia:dirty_read(passwd, LUser) of
index e4150ffdabe886d536c281742e3ebb436749605c..27395bae6c298c1e8c56b15e26bae4ae832defcc 100644 (file)
@@ -21,6 +21,7 @@
         wait_for_auth/2,
         wait_for_sasl_auth/2,
         wait_for_resource_auth/2,
+        wait_for_sasl_response/2,
         session_established/2,
         handle_event/3,
         handle_sync_event/4,
@@ -258,7 +259,8 @@ wait_for_sasl_auth({xmlstreamelement, El}, StateData) ->
                                  [{"xmlns", ?NS_SASL_MECHANISMS}],
                                  [{xmlcdata,
                                    jlib:encode_base64(ServerOut)}]}),
-                   {next_state, wait_for_sasl_response, StateData};
+                   {next_state, wait_for_sasl_response,
+                    StateData#state{sasl_state = NewSASLState}};
                {error, Code} ->
                    send_element(StateData#state.socket,
                                 {xmlelement, "failure",
@@ -373,6 +375,63 @@ wait_for_resource_auth(closed, StateData) ->
 
 
 % TODO: wait_for_sasl_response
+wait_for_sasl_response({xmlstreamelement, El}, StateData) ->
+    {xmlelement, Name, Attrs, Els} = El,
+    case {xml:get_attr_s("xmlns", Attrs), Name} of
+       {?NS_SASL_MECHANISMS, "response"} ->
+           ClientIn = jlib:decode_base64(xml:get_cdata(Els)),
+           case cyrsasl:server_step(StateData#state.sasl_state,
+                                    ClientIn) of
+               {ok, Props} ->
+                   send_element(StateData#state.socket,
+                                {xmlelement, "success",
+                                 [{"xmlns", ?NS_SASL_MECHANISMS}], []}),
+                   {next_state, wait_for_resource_auth,
+                    StateData#state{user = xml:get_attr_s(username, Props)}};
+               {continue, ServerOut, NewSASLState} ->
+                   send_element(StateData#state.socket,
+                                {xmlelement, "challenge",
+                                 [{"xmlns", ?NS_SASL_MECHANISMS}],
+                                 [{xmlcdata,
+                                   jlib:encode_base64(ServerOut)}]}),
+                   {next_state, wait_for_sasl_response,
+                    StateData#state{sasl_state = NewSASLState}};
+               {error, Code} ->
+                   send_element(StateData#state.socket,
+                                {xmlelement, "failure",
+                                 [{"xmlns", ?NS_SASL_MECHANISMS},
+                                  {"code", Code}],
+                                 []}),
+                   {next_state, wait_for_sasl_auth, StateData}
+           end;
+       _ ->
+           case jlib:iq_query_info(El) of
+               {iq, ID, Type, ?NS_REGISTER, SubEl} ->
+                   ResIQ = mod_register:process_iq(
+                             {"", "", ""}, {"", ?MYNAME, ""},
+                             {iq, ID, Type, ?NS_REGISTER, SubEl}),
+                   Res1 = jlib:replace_from_to({"", ?MYNAME, ""},
+                                               {"", "", ""},
+                                               jlib:iq_to_xml(ResIQ)),
+                   Res = jlib:remove_attr("to", Res1),
+                   send_element(StateData#state.socket, Res),
+                   {next_state, wait_for_sasl_auth, StateData};
+               _ ->
+                   {next_state, wait_for_sasl_auth, StateData}
+           end
+    end;
+
+wait_for_sasl_response({xmlstreamend, Name}, StateData) ->
+    send_text(StateData#state.socket, ?STREAM_TRAILER),
+    {stop, normal, StateData};
+
+wait_for_sasl_response({xmlstreamerror, _}, StateData) ->
+    send_text(StateData#state.socket, ?INVALID_XML_ERR ++ ?STREAM_TRAILER),
+    {stop, normal, StateData};
+
+wait_for_sasl_response(closed, StateData) ->
+    {stop, normal, StateData}.
+
 
 
 
index 004ddba38ea1ad6180d469951a27c65dca23af54..ffa9cbb17aad6a0db8f946950d449b4eacbc9155 100644 (file)
@@ -55,8 +55,9 @@ init(Port, Module, Fun, Opts) ->
 
 accept(ListenSocket, Module, Fun, Opts) ->
     case gen_tcp:accept(ListenSocket) of
-       {ok,Socket} ->
-           apply(Module, Fun, [{gen_tcp, Socket}, Opts]),
+       {ok, Socket} ->
+           {ok, Pid} = apply(Module, Fun, [{gen_tcp, Socket}, Opts]),
+           gen_tcp:controlling_process(Socket, Pid),
            accept(ListenSocket, Module, Fun, Opts)
     end.
 
@@ -73,7 +74,7 @@ init_ssl(Port, Module, Fun, Opts, SSLOpts) ->
 
 accept_ssl(ListenSocket, Module, Fun, Opts) ->
     case ssl:accept(ListenSocket) of
-       {ok,Socket} ->
+       {ok, Socket} ->
            apply(Module, Fun, [{ssl, Socket}, Opts]),
            accept_ssl(ListenSocket, Module, Fun, Opts)
     end.
index d88967b0fda09477da6d136156589ee151b2e300..458113b7e974dcfad9446b775bb1a10589f124a5 100644 (file)
@@ -13,7 +13,7 @@
 -behaviour(gen_fsm).
 
 %% External exports
--export([start/3, receiver/2, send_text/2, send_element/2]).
+-export([start/3, send_text/2, send_element/2]).
 
 %% gen_fsm callbacks
 -export([init/1,
@@ -350,7 +350,8 @@ terminate(Reason, StateName, StateData) ->
        undefined ->
            ok;
        Socket ->
-           gen_tcp:close(Socket)
+           gen_tcp:close(Socket),
+           exit(StateData#state.xmlpid, closed)
     end,
     ok.
 
@@ -358,21 +359,6 @@ terminate(Reason, StateName, StateData) ->
 %%% Internal functions
 %%%----------------------------------------------------------------------
 
-receiver(Socket, C2SPid) ->
-    XMLStreamPid = xml_stream:start(C2SPid),
-    receiver(Socket, C2SPid, XMLStreamPid).
-
-receiver(Socket, C2SPid, XMLStreamPid) ->
-    case gen_tcp:recv(Socket, 0) of
-        {ok, Text} ->
-           xml_stream:send_text(XMLStreamPid, Text),
-           receiver(Socket, C2SPid, XMLStreamPid);
-        {error, Reason} ->
-           exit(XMLStreamPid, closed),
-           gen_fsm:send_event(C2SPid, closed),
-           ok
-    end.
-
 send_text(Socket, Text) ->
     gen_tcp:send(Socket,Text).
 
index bb3776157eb111b20c38e3d0b250fff8f1fa504b..583fc7cf0868f1ef1311ecd205fd7f75dce9454b 100644 (file)
@@ -16,6 +16,7 @@ start(CallbackPid) ->
     spawn(?MODULE, init, [CallbackPid]).
 
 init(CallbackPid) ->
+    link(CallbackPid),
     Port = open_port({spawn, expat_erl}, [binary]),
     loop(CallbackPid, Port, []).