mirror of
https://github.com/processone/ejabberd.git
synced 2024-11-28 16:34:13 +01:00
* 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 SVN Revision: 87
This commit is contained in:
parent
f3916bddd2
commit
8b26ac9e97
11
ChangeLog
11
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>
|
2003-03-09 Alexey Shchepin <alexey@sevcom.net>
|
||||||
|
|
||||||
* src/cyrsasl*.erl: SASL support (currently support only PLAIN
|
* src/cyrsasl*.erl: SASL support (currently support only PLAIN
|
||||||
|
@ -33,6 +33,7 @@ start() ->
|
|||||||
public,
|
public,
|
||||||
{keypos, #sasl_mechanism.mechanism}]),
|
{keypos, #sasl_mechanism.mechanism}]),
|
||||||
cyrsasl_plain:start([]),
|
cyrsasl_plain:start([]),
|
||||||
|
cyrsasl_digest:start([]),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
register_mechanism(Mechanism, Module) ->
|
register_mechanism(Mechanism, Module) ->
|
||||||
@ -52,7 +53,7 @@ server_new(Service, ServerFQDN, UserRealm, SecFlags) ->
|
|||||||
server_start(State, Mech, ClientIn) ->
|
server_start(State, Mech, ClientIn) ->
|
||||||
case ets:lookup(sasl_mechanism, Mech) of
|
case ets:lookup(sasl_mechanism, Mech) of
|
||||||
[#sasl_mechanism{module = Module}] ->
|
[#sasl_mechanism{module = Module}] ->
|
||||||
MechState = Module:mech_new(),
|
{ok, MechState} = Module:mech_new(),
|
||||||
server_step(State#sasl_state{mech_mod = Module,
|
server_step(State#sasl_state{mech_mod = Module,
|
||||||
mech_state = MechState},
|
mech_state = MechState},
|
||||||
ClientIn);
|
ClientIn);
|
||||||
|
144
src/cyrsasl_digest.erl
Normal file
144
src/cyrsasl_digest.erl
Normal file
@ -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))).
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -19,6 +19,7 @@
|
|||||||
check_password/4,
|
check_password/4,
|
||||||
try_register/2,
|
try_register/2,
|
||||||
dirty_get_registered_users/0,
|
dirty_get_registered_users/0,
|
||||||
|
get_password/1,
|
||||||
get_password_s/1,
|
get_password_s/1,
|
||||||
is_user_exists/1,
|
is_user_exists/1,
|
||||||
remove_user/1,
|
remove_user/1,
|
||||||
@ -166,6 +167,15 @@ try_register(User, Password) ->
|
|||||||
dirty_get_registered_users() ->
|
dirty_get_registered_users() ->
|
||||||
mnesia:dirty_all_keys(passwd).
|
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) ->
|
get_password_s(User) ->
|
||||||
LUser = jlib:tolower(User),
|
LUser = jlib:tolower(User),
|
||||||
case catch mnesia:dirty_read(passwd, LUser) of
|
case catch mnesia:dirty_read(passwd, LUser) of
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
wait_for_auth/2,
|
wait_for_auth/2,
|
||||||
wait_for_sasl_auth/2,
|
wait_for_sasl_auth/2,
|
||||||
wait_for_resource_auth/2,
|
wait_for_resource_auth/2,
|
||||||
|
wait_for_sasl_response/2,
|
||||||
session_established/2,
|
session_established/2,
|
||||||
handle_event/3,
|
handle_event/3,
|
||||||
handle_sync_event/4,
|
handle_sync_event/4,
|
||||||
@ -258,7 +259,8 @@ wait_for_sasl_auth({xmlstreamelement, El}, StateData) ->
|
|||||||
[{"xmlns", ?NS_SASL_MECHANISMS}],
|
[{"xmlns", ?NS_SASL_MECHANISMS}],
|
||||||
[{xmlcdata,
|
[{xmlcdata,
|
||||||
jlib:encode_base64(ServerOut)}]}),
|
jlib:encode_base64(ServerOut)}]}),
|
||||||
{next_state, wait_for_sasl_response, StateData};
|
{next_state, wait_for_sasl_response,
|
||||||
|
StateData#state{sasl_state = NewSASLState}};
|
||||||
{error, Code} ->
|
{error, Code} ->
|
||||||
send_element(StateData#state.socket,
|
send_element(StateData#state.socket,
|
||||||
{xmlelement, "failure",
|
{xmlelement, "failure",
|
||||||
@ -373,6 +375,63 @@ wait_for_resource_auth(closed, StateData) ->
|
|||||||
|
|
||||||
|
|
||||||
% TODO: wait_for_sasl_response
|
% 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}.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -56,7 +56,8 @@ init(Port, Module, Fun, Opts) ->
|
|||||||
accept(ListenSocket, Module, Fun, Opts) ->
|
accept(ListenSocket, Module, Fun, Opts) ->
|
||||||
case gen_tcp:accept(ListenSocket) of
|
case gen_tcp:accept(ListenSocket) of
|
||||||
{ok, Socket} ->
|
{ok, Socket} ->
|
||||||
apply(Module, Fun, [{gen_tcp, Socket}, Opts]),
|
{ok, Pid} = apply(Module, Fun, [{gen_tcp, Socket}, Opts]),
|
||||||
|
gen_tcp:controlling_process(Socket, Pid),
|
||||||
accept(ListenSocket, Module, Fun, Opts)
|
accept(ListenSocket, Module, Fun, Opts)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
-behaviour(gen_fsm).
|
-behaviour(gen_fsm).
|
||||||
|
|
||||||
%% External exports
|
%% 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
|
%% gen_fsm callbacks
|
||||||
-export([init/1,
|
-export([init/1,
|
||||||
@ -350,7 +350,8 @@ terminate(Reason, StateName, StateData) ->
|
|||||||
undefined ->
|
undefined ->
|
||||||
ok;
|
ok;
|
||||||
Socket ->
|
Socket ->
|
||||||
gen_tcp:close(Socket)
|
gen_tcp:close(Socket),
|
||||||
|
exit(StateData#state.xmlpid, closed)
|
||||||
end,
|
end,
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
@ -358,21 +359,6 @@ terminate(Reason, StateName, StateData) ->
|
|||||||
%%% Internal functions
|
%%% 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) ->
|
send_text(Socket, Text) ->
|
||||||
gen_tcp:send(Socket,Text).
|
gen_tcp:send(Socket,Text).
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ start(CallbackPid) ->
|
|||||||
spawn(?MODULE, init, [CallbackPid]).
|
spawn(?MODULE, init, [CallbackPid]).
|
||||||
|
|
||||||
init(CallbackPid) ->
|
init(CallbackPid) ->
|
||||||
|
link(CallbackPid),
|
||||||
Port = open_port({spawn, expat_erl}, [binary]),
|
Port = open_port({spawn, expat_erl}, [binary]),
|
||||||
loop(CallbackPid, Port, []).
|
loop(CallbackPid, Port, []).
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user