mirror of
https://github.com/processone/ejabberd.git
synced 2024-11-30 16:36:29 +01:00
First bunch of modifications to use exmpp. All FSM state function are
updated. But other functions are not for now. Users are able to connect to ejabberd but some features may not work. SVN Revision: 1368
This commit is contained in:
parent
a19f280fcc
commit
389b5e6448
@ -4,6 +4,10 @@
|
|||||||
|
|
||||||
* src/ejabberd_receiver.erl: Enable the new #xmlel record.
|
* src/ejabberd_receiver.erl: Enable the new #xmlel record.
|
||||||
|
|
||||||
|
* src/ejabberd_c2s.erl: First bunch of modifications to use exmpp. All
|
||||||
|
FSM state function are updated. But other functions are not for now.
|
||||||
|
Users are able to connect to ejabberd but some features may not work.
|
||||||
|
|
||||||
2008-06-19 Jean-Sébastien Pédron <js.pedron@meetic-corp.com>
|
2008-06-19 Jean-Sébastien Pédron <js.pedron@meetic-corp.com>
|
||||||
|
|
||||||
* src/ejabberd_receiver.erl: Replace the use of xml_stream by
|
* src/ejabberd_receiver.erl: Replace the use of xml_stream by
|
||||||
|
@ -54,8 +54,9 @@
|
|||||||
handle_info/3,
|
handle_info/3,
|
||||||
terminate/3]).
|
terminate/3]).
|
||||||
|
|
||||||
|
-include("exmpp.hrl").
|
||||||
|
|
||||||
-include("ejabberd.hrl").
|
-include("ejabberd.hrl").
|
||||||
-include("jlib.hrl").
|
|
||||||
-include("mod_privacy.hrl").
|
-include("mod_privacy.hrl").
|
||||||
|
|
||||||
-define(SETS, gb_sets).
|
-define(SETS, gb_sets).
|
||||||
@ -93,11 +94,11 @@
|
|||||||
|
|
||||||
%-define(DBGFSM, true).
|
%-define(DBGFSM, true).
|
||||||
|
|
||||||
-ifdef(DBGFSM).
|
%-ifdef(DBGFSM).
|
||||||
-define(FSMOPTS, [{debug, [trace]}]).
|
-define(FSMOPTS, [{debug, [trace]}]).
|
||||||
-else.
|
%-else.
|
||||||
-define(FSMOPTS, []).
|
%-define(FSMOPTS, []).
|
||||||
-endif.
|
%-endif.
|
||||||
|
|
||||||
%% Module start with or without supervisor:
|
%% Module start with or without supervisor:
|
||||||
-ifdef(NO_TRANSIENT_SUPERVISORS).
|
-ifdef(NO_TRANSIENT_SUPERVISORS).
|
||||||
@ -113,6 +114,11 @@
|
|||||||
-define(C2S_OPEN_TIMEOUT, 60000).
|
-define(C2S_OPEN_TIMEOUT, 60000).
|
||||||
-define(C2S_HIBERNATE_TIMEOUT, 90000).
|
-define(C2S_HIBERNATE_TIMEOUT, 90000).
|
||||||
|
|
||||||
|
% These are the namespace already declared by the stream opening. This is
|
||||||
|
% used at serialization time.
|
||||||
|
-define(DEFAULT_NS, ['jabber:client']).
|
||||||
|
-define(PREFIXED_NS, [{?NS_XMPP, "stream"}]).
|
||||||
|
|
||||||
-define(STREAM_HEADER,
|
-define(STREAM_HEADER,
|
||||||
"<?xml version='1.0'?>"
|
"<?xml version='1.0'?>"
|
||||||
"<stream:stream xmlns='jabber:client' "
|
"<stream:stream xmlns='jabber:client' "
|
||||||
@ -131,6 +137,50 @@
|
|||||||
-define(POLICY_VIOLATION_ERR(Lang, Text),
|
-define(POLICY_VIOLATION_ERR(Lang, Text),
|
||||||
xml:element_to_string(?SERRT_POLICY_VIOLATION(Lang, Text))).
|
xml:element_to_string(?SERRT_POLICY_VIOLATION(Lang, Text))).
|
||||||
|
|
||||||
|
% XXX OLD FORMAT
|
||||||
|
-define(NS_STREAM, "http://etherx.jabber.org/streams").
|
||||||
|
-define(NS_AUTH, "jabber:iq:auth").
|
||||||
|
-define(NS_FEATURE_COMPRESS, "http://jabber.org/features/compress").
|
||||||
|
-define(NS_PRIVACY, "jabber:iq:privacy").
|
||||||
|
-define(NS_VCARD, "vcard-temp").
|
||||||
|
|
||||||
|
-define(STREAM_ERROR(Condition),
|
||||||
|
exmpp_xml:xmlel_to_xmlelement(exmpp_stream:error(Condition),
|
||||||
|
[?NS_JABBER_CLIENT], [{?NS_XMPP, "stream"}])).
|
||||||
|
-define(SERR_XML_NOT_WELL_FORMED, ?STREAM_ERROR('xml-not-well-formed')).
|
||||||
|
-define(SERR_HOST_UNKNOWN, ?STREAM_ERROR('host-unknown')).
|
||||||
|
-define(SERR_INVALID_NAMESPACE, ?STREAM_ERROR('invalid-namespace')).
|
||||||
|
|
||||||
|
-define(STREAM_ERRORT(Condition, Lang, Text),
|
||||||
|
exmpp_xml:xmlel_to_xmlelement(exmpp_stream:error(Condition, {Lang, Text}),
|
||||||
|
[?NS_JABBER_CLIENT], [{?NS_XMPP, "stream"}])).
|
||||||
|
-define(SERRT_POLICY_VIOLATION(Lang, Text),
|
||||||
|
?STREAM_ERRORT('policy-violation', Lang, Text)).
|
||||||
|
-define(SERRT_CONFLICT(Lang, Text),
|
||||||
|
?STREAM_ERRORT('conflict', Lang, Text)).
|
||||||
|
|
||||||
|
-define(STANZA_ERROR(Condition),
|
||||||
|
exmpp_xml:xmlel_to_xmlelement(exmpp_stanza:error(Condition),
|
||||||
|
[?NS_JABBER_CLIENT], [{?NS_XMPP, "stream"}])).
|
||||||
|
-define(ERR_BAD_REQUEST, ?STANZA_ERROR('bad-request')).
|
||||||
|
-define(ERR_NOT_ALLOWED, ?STANZA_ERROR('not-allowed')).
|
||||||
|
-define(ERR_JID_MALFORMED, ?STANZA_ERROR('jid-malformed')).
|
||||||
|
-define(ERR_NOT_AUTHORIZED, ?STANZA_ERROR('not-authorized')).
|
||||||
|
-define(ERR_FEATURE_NOT_IMPLEMENTED, ?STANZA_ERROR('feature-not-implemented')).
|
||||||
|
-define(ERR_SERVICE_UNAVAILABLE, ?STANZA_ERROR('service-unavialable')).
|
||||||
|
|
||||||
|
-define(STANZA_ERRORT(Condition, Lang, Text),
|
||||||
|
exmpp_xml:xmlel_to_xmlelement(exmpp_stanza:error(Condition, {Lang, Text}),
|
||||||
|
[?NS_JABBER_CLIENT], [{?NS_XMPP, "stream"}])).
|
||||||
|
-define(ERR_AUTH_NO_RESOURCE_PROVIDED(Lang),
|
||||||
|
?STANZA_ERRORT('not-acceptable', Lang, "No resource provided")).
|
||||||
|
|
||||||
|
-record(iq, {id = "",
|
||||||
|
type,
|
||||||
|
xmlns = "",
|
||||||
|
lang = "",
|
||||||
|
sub_el}).
|
||||||
|
|
||||||
%%%----------------------------------------------------------------------
|
%%%----------------------------------------------------------------------
|
||||||
%%% API
|
%%% API
|
||||||
%%%----------------------------------------------------------------------
|
%%%----------------------------------------------------------------------
|
||||||
@ -220,28 +270,28 @@ get_subscribed_and_online(FsmRef) ->
|
|||||||
%% {stop, Reason, NewStateData}
|
%% {stop, Reason, NewStateData}
|
||||||
%%----------------------------------------------------------------------
|
%%----------------------------------------------------------------------
|
||||||
|
|
||||||
wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
|
wait_for_stream({xmlstreamstart, #xmlel{ns = NS} = Opening}, StateData) ->
|
||||||
DefaultLang = case ?MYLANG of
|
DefaultLang = case ?MYLANG of
|
||||||
undefined ->
|
undefined ->
|
||||||
" xml:lang='en'";
|
" xml:lang='en'";
|
||||||
DL ->
|
DL ->
|
||||||
" xml:lang='" ++ DL ++ "'"
|
" xml:lang='" ++ DL ++ "'"
|
||||||
end,
|
end,
|
||||||
case xml:get_attr_s("xmlns:stream", Attrs) of
|
Header = exmpp_stream:opening_reply(Opening,
|
||||||
?NS_STREAM ->
|
StateData#state.streamid),
|
||||||
Server = jlib:nameprep(xml:get_attr_s("to", Attrs)),
|
Header1 = exmpp_stream:set_lang(Header, DefaultLang),
|
||||||
|
case NS of
|
||||||
|
?NS_XMPP ->
|
||||||
|
Server = exmpp_stringprep:nameprep(
|
||||||
|
exmpp_stream:get_receiving_entity(Opening)),
|
||||||
case lists:member(Server, ?MYHOSTS) of
|
case lists:member(Server, ?MYHOSTS) of
|
||||||
true ->
|
true ->
|
||||||
Lang = xml:get_attr_s("xml:lang", Attrs),
|
Lang = exmpp_stream:get_lang(Opening),
|
||||||
change_shaper(StateData, jlib:make_jid("", Server, "")),
|
change_shaper(StateData,
|
||||||
case xml:get_attr_s("version", Attrs) of
|
exmpp_jid:make_jid("", Server, "")),
|
||||||
"1.0" ->
|
case exmpp_stream:get_version(Opening) of
|
||||||
Header = io_lib:format(?STREAM_HEADER,
|
{1, 0} ->
|
||||||
[StateData#state.streamid,
|
send_element(StateData, Header1),
|
||||||
Server,
|
|
||||||
" version='1.0'",
|
|
||||||
DefaultLang]),
|
|
||||||
send_text(StateData, Header),
|
|
||||||
case StateData#state.authenticated of
|
case StateData#state.authenticated of
|
||||||
false ->
|
false ->
|
||||||
SASLState =
|
SASLState =
|
||||||
@ -255,11 +305,8 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
|
|||||||
ejabberd_auth:check_password_with_authmodule(
|
ejabberd_auth:check_password_with_authmodule(
|
||||||
U, Server, P)
|
U, Server, P)
|
||||||
end),
|
end),
|
||||||
Mechs = lists:map(
|
SASL_Mechs = [exmpp_server_sasl:feature(
|
||||||
fun(S) ->
|
cyrsasl:listmech(Server))],
|
||||||
{xmlelement, "mechanism", [],
|
|
||||||
[{xmlcdata, S}]}
|
|
||||||
end, cyrsasl:listmech(Server)),
|
|
||||||
SockMod =
|
SockMod =
|
||||||
(StateData#state.sockmod):get_sockmod(
|
(StateData#state.sockmod):get_sockmod(
|
||||||
StateData#state.socket),
|
StateData#state.socket),
|
||||||
@ -268,10 +315,7 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
|
|||||||
case Zlib andalso
|
case Zlib andalso
|
||||||
(SockMod == gen_tcp) of
|
(SockMod == gen_tcp) of
|
||||||
true ->
|
true ->
|
||||||
[{xmlelement, "compression",
|
[exmpp_server_compression:feature(["zlib"])];
|
||||||
[{"xmlns", ?NS_FEATURE_COMPRESS}],
|
|
||||||
[{xmlelement, "method",
|
|
||||||
[], [{xmlcdata, "zlib"}]}]}];
|
|
||||||
_ ->
|
_ ->
|
||||||
[]
|
[]
|
||||||
end,
|
end,
|
||||||
@ -283,29 +327,19 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
|
|||||||
(TLSEnabled == false) andalso
|
(TLSEnabled == false) andalso
|
||||||
(SockMod == gen_tcp) of
|
(SockMod == gen_tcp) of
|
||||||
true ->
|
true ->
|
||||||
case TLSRequired of
|
[exmpp_server_tls:feature(TLSRequired)];
|
||||||
true ->
|
|
||||||
[{xmlelement, "starttls",
|
|
||||||
[{"xmlns", ?NS_TLS}],
|
|
||||||
[{xmlelement, "required",
|
|
||||||
[], []}]}];
|
|
||||||
_ ->
|
|
||||||
[{xmlelement, "starttls",
|
|
||||||
[{"xmlns", ?NS_TLS}], []}]
|
|
||||||
end;
|
|
||||||
false ->
|
false ->
|
||||||
[]
|
[]
|
||||||
end,
|
end,
|
||||||
send_element(StateData,
|
send_element(StateData,
|
||||||
{xmlelement, "stream:features", [],
|
exmpp_stream:features(
|
||||||
TLSFeature ++ CompressFeature ++
|
TLSFeature ++
|
||||||
[{xmlelement, "mechanisms",
|
CompressFeature ++
|
||||||
[{"xmlns", ?NS_SASL}],
|
SASL_Mechs ++
|
||||||
Mechs}] ++
|
|
||||||
ejabberd_hooks:run_fold(
|
ejabberd_hooks:run_fold(
|
||||||
c2s_stream_features,
|
c2s_stream_features,
|
||||||
Server,
|
Server,
|
||||||
[], [])}),
|
[], []))),
|
||||||
fsm_next_state(wait_for_feature_request,
|
fsm_next_state(wait_for_feature_request,
|
||||||
StateData#state{
|
StateData#state{
|
||||||
server = Server,
|
server = Server,
|
||||||
@ -316,11 +350,10 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
|
|||||||
"" ->
|
"" ->
|
||||||
send_element(
|
send_element(
|
||||||
StateData,
|
StateData,
|
||||||
{xmlelement, "stream:features", [],
|
exmpp_stream:features([
|
||||||
[{xmlelement, "bind",
|
exmpp_server_binding:feature(),
|
||||||
[{"xmlns", ?NS_BIND}], []},
|
exmpp_server_session:feature()
|
||||||
{xmlelement, "session",
|
])),
|
||||||
[{"xmlns", ?NS_SESSION}], []}]}),
|
|
||||||
fsm_next_state(wait_for_bind,
|
fsm_next_state(wait_for_bind,
|
||||||
StateData#state{
|
StateData#state{
|
||||||
server = Server,
|
server = Server,
|
||||||
@ -328,7 +361,7 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
|
|||||||
_ ->
|
_ ->
|
||||||
send_element(
|
send_element(
|
||||||
StateData,
|
StateData,
|
||||||
{xmlelement, "stream:features", [], []}),
|
exmpp_stream:features([])),
|
||||||
fsm_next_state(wait_for_session,
|
fsm_next_state(wait_for_session,
|
||||||
StateData#state{
|
StateData#state{
|
||||||
server = Server,
|
server = Server,
|
||||||
@ -336,22 +369,16 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
|
|||||||
end
|
end
|
||||||
end;
|
end;
|
||||||
_ ->
|
_ ->
|
||||||
Header = io_lib:format(
|
|
||||||
?STREAM_HEADER,
|
|
||||||
[StateData#state.streamid, Server, "",
|
|
||||||
DefaultLang]),
|
|
||||||
if
|
if
|
||||||
(not StateData#state.tls_enabled) and
|
(not StateData#state.tls_enabled) and
|
||||||
StateData#state.tls_required ->
|
StateData#state.tls_required ->
|
||||||
send_text(StateData,
|
send_element(StateData,
|
||||||
Header ++
|
exmpp_xml:append_child(Header1,
|
||||||
?POLICY_VIOLATION_ERR(
|
exmpp_stream:error('policy-violation',
|
||||||
Lang,
|
Lang, "Use of STARTTLS required"))),
|
||||||
"Use of STARTTLS required") ++
|
|
||||||
?STREAM_TRAILER),
|
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
true ->
|
true ->
|
||||||
send_text(StateData, Header),
|
send_element(StateData, Header1),
|
||||||
fsm_next_state(wait_for_auth,
|
fsm_next_state(wait_for_auth,
|
||||||
StateData#state{
|
StateData#state{
|
||||||
server = Server,
|
server = Server,
|
||||||
@ -359,20 +386,16 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
|
|||||||
end
|
end
|
||||||
end;
|
end;
|
||||||
_ ->
|
_ ->
|
||||||
Header = io_lib:format(
|
Header2 = exmpp_stream:set_initiating_entity(Header1,
|
||||||
?STREAM_HEADER,
|
?MYNAME),
|
||||||
[StateData#state.streamid, ?MYNAME, "",
|
send_element(StateData, exmpp_xml:append_child(Header2,
|
||||||
DefaultLang]),
|
exmpp_stream:error('host-unknown'))),
|
||||||
send_text(StateData,
|
|
||||||
Header ++ ?HOST_UNKNOWN_ERR ++ ?STREAM_TRAILER),
|
|
||||||
{stop, normal, StateData}
|
{stop, normal, StateData}
|
||||||
end;
|
end;
|
||||||
_ ->
|
_ ->
|
||||||
Header = io_lib:format(
|
Header2 = exmpp_stream:set_initiating_entity(Header1, ?MYNAME),
|
||||||
?STREAM_HEADER,
|
send_element(StateData, exmpp_xml:append_child(Header2,
|
||||||
[StateData#state.streamid, ?MYNAME, "", DefaultLang]),
|
exmpp_stream:error('invalid-namespace'))),
|
||||||
send_text(StateData,
|
|
||||||
Header ++ ?INVALID_NS_ERR ++ ?STREAM_TRAILER),
|
|
||||||
{stop, normal, StateData}
|
{stop, normal, StateData}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -380,18 +403,21 @@ wait_for_stream(timeout, StateData) ->
|
|||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
wait_for_stream({xmlstreamelement, _}, StateData) ->
|
wait_for_stream({xmlstreamelement, _}, StateData) ->
|
||||||
send_text(StateData, ?INVALID_XML_ERR ++ ?STREAM_TRAILER),
|
send_element(StateData, exmpp_stream:error('xml-not-well-formed')),
|
||||||
|
send_element(StateData, exmpp_stream:closing()),
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
wait_for_stream({xmlstreamend, _}, StateData) ->
|
wait_for_stream({xmlstreamend, _}, StateData) ->
|
||||||
send_text(StateData, ?INVALID_XML_ERR ++ ?STREAM_TRAILER),
|
send_element(StateData, exmpp_stream:error('xml-not-well-formed')),
|
||||||
|
send_element(StateData, exmpp_stream:closing()),
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
wait_for_stream({xmlstreamerror, _}, StateData) ->
|
wait_for_stream({xmlstreamerror, _}, StateData) ->
|
||||||
Header = io_lib:format(?STREAM_HEADER,
|
Header = exmpp_stream:opening_reply(?MYNAME, 'jabber:client', "1.0",
|
||||||
["none", ?MYNAME, " version='1.0'", ""]),
|
"none"),
|
||||||
send_text(StateData,
|
Header1 = exmpp_xml:append_child(Header,
|
||||||
Header ++ ?INVALID_XML_ERR ++ ?STREAM_TRAILER),
|
exmpp_stream:error('xml-not-well-formed')),
|
||||||
|
send_element(StateData, Header1),
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
wait_for_stream(closed, StateData) ->
|
wait_for_stream(closed, StateData) ->
|
||||||
@ -400,46 +426,26 @@ wait_for_stream(closed, StateData) ->
|
|||||||
|
|
||||||
wait_for_auth({xmlstreamelement, El}, StateData) ->
|
wait_for_auth({xmlstreamelement, El}, StateData) ->
|
||||||
case is_auth_packet(El) of
|
case is_auth_packet(El) of
|
||||||
{auth, _ID, get, {U, _, _, _}} ->
|
{auth, _ID, get, {_U, _, _, _}} ->
|
||||||
{xmlelement, Name, Attrs, _Els} = jlib:make_result_iq_reply(El),
|
Fields = case ejabberd_auth:plain_password_required(
|
||||||
case U of
|
|
||||||
"" ->
|
|
||||||
UCdata = [];
|
|
||||||
_ ->
|
|
||||||
UCdata = [{xmlcdata, U}]
|
|
||||||
end,
|
|
||||||
Res = case ejabberd_auth:plain_password_required(
|
|
||||||
StateData#state.server) of
|
StateData#state.server) of
|
||||||
false ->
|
false -> both;
|
||||||
{xmlelement, Name, Attrs,
|
true -> plain
|
||||||
[{xmlelement, "query", [{"xmlns", ?NS_AUTH}],
|
|
||||||
[{xmlelement, "username", [], UCdata},
|
|
||||||
{xmlelement, "password", [], []},
|
|
||||||
{xmlelement, "digest", [], []},
|
|
||||||
{xmlelement, "resource", [], []}
|
|
||||||
]}]};
|
|
||||||
true ->
|
|
||||||
{xmlelement, Name, Attrs,
|
|
||||||
[{xmlelement, "query", [{"xmlns", ?NS_AUTH}],
|
|
||||||
[{xmlelement, "username", [], UCdata},
|
|
||||||
{xmlelement, "password", [], []},
|
|
||||||
{xmlelement, "resource", [], []}
|
|
||||||
]}]}
|
|
||||||
end,
|
end,
|
||||||
send_element(StateData, Res),
|
send_element(StateData,
|
||||||
|
exmpp_server_legacy_auth:fields(El, Fields)),
|
||||||
fsm_next_state(wait_for_auth, StateData);
|
fsm_next_state(wait_for_auth, StateData);
|
||||||
{auth, _ID, set, {_U, _P, _D, ""}} ->
|
{auth, _ID, set, {_U, _P, _D, ""}} ->
|
||||||
Err = jlib:make_error_reply(
|
Err = exmpp_stanza:error('not-acceptable',
|
||||||
El,
|
{StateData#state.lang, "No resource provided"}),
|
||||||
?ERR_AUTH_NO_RESOURCE_PROVIDED(StateData#state.lang)),
|
send_element(StateData, exmpp_iq:error(El, Err)),
|
||||||
send_element(StateData, Err),
|
|
||||||
fsm_next_state(wait_for_auth, StateData);
|
fsm_next_state(wait_for_auth, StateData);
|
||||||
{auth, _ID, set, {U, P, D, R}} ->
|
{auth, _ID, set, {U, P, D, R}} ->
|
||||||
JID = jlib:make_jid(U, StateData#state.server, R),
|
try
|
||||||
case (JID /= error) andalso
|
JID = exmpp_jid:make_jid(U, StateData#state.server, R),
|
||||||
(acl:match_rule(StateData#state.server,
|
case acl:match_rule(StateData#state.server,
|
||||||
StateData#state.access, JID) == allow) of
|
StateData#state.access, JID) of
|
||||||
true ->
|
allow ->
|
||||||
case ejabberd_auth:check_password_with_authmodule(
|
case ejabberd_auth:check_password_with_authmodule(
|
||||||
U, StateData#state.server, P,
|
U, StateData#state.server, P,
|
||||||
StateData#state.streamid, D) of
|
StateData#state.streamid, D) of
|
||||||
@ -447,15 +453,14 @@ wait_for_auth({xmlstreamelement, El}, StateData) ->
|
|||||||
?INFO_MSG(
|
?INFO_MSG(
|
||||||
"(~w) Accepted legacy authentication for ~s",
|
"(~w) Accepted legacy authentication for ~s",
|
||||||
[StateData#state.socket,
|
[StateData#state.socket,
|
||||||
jlib:jid_to_string(JID)]),
|
exmpp_jid:jid_to_string(JID)]),
|
||||||
SID = {now(), self()},
|
SID = {now(), self()},
|
||||||
Conn = get_conn_type(StateData),
|
Conn = get_conn_type(StateData),
|
||||||
Info = [{ip, StateData#state.ip}, {conn, Conn},
|
Info = [{ip, StateData#state.ip}, {conn, Conn},
|
||||||
{auth_module, AuthModule}],
|
{auth_module, AuthModule}],
|
||||||
ejabberd_sm:open_session(
|
ejabberd_sm:open_session(
|
||||||
SID, U, StateData#state.server, R, Info),
|
SID, U, StateData#state.server, R, Info),
|
||||||
Res1 = jlib:make_result_iq_reply(El),
|
Res = exmpp_server_legacy_auth:success(El),
|
||||||
Res = setelement(4, Res1, []),
|
|
||||||
send_element(StateData, Res),
|
send_element(StateData, Res),
|
||||||
change_shaper(StateData, JID),
|
change_shaper(StateData, JID),
|
||||||
{Fs, Ts} = ejabberd_hooks:run_fold(
|
{Fs, Ts} = ejabberd_hooks:run_fold(
|
||||||
@ -463,12 +468,10 @@ wait_for_auth({xmlstreamelement, El}, StateData) ->
|
|||||||
StateData#state.server,
|
StateData#state.server,
|
||||||
{[], []},
|
{[], []},
|
||||||
[U, StateData#state.server]),
|
[U, StateData#state.server]),
|
||||||
LJID = jlib:jid_tolower(
|
LJID = {JID#jid.lnode, JID#jid.ldomain, ""},
|
||||||
jlib:jid_remove_resource(JID)),
|
|
||||||
Fs1 = [LJID | Fs],
|
Fs1 = [LJID | Fs],
|
||||||
Ts1 = [LJID | Ts],
|
Ts1 = [LJID | Ts],
|
||||||
PrivList =
|
PrivList = ejabberd_hooks:run_fold(
|
||||||
ejabberd_hooks:run_fold(
|
|
||||||
privacy_get_user_list, StateData#state.server,
|
privacy_get_user_list, StateData#state.server,
|
||||||
#userlist{},
|
#userlist{},
|
||||||
[U, StateData#state.server]),
|
[U, StateData#state.server]),
|
||||||
@ -487,31 +490,32 @@ wait_for_auth({xmlstreamelement, El}, StateData) ->
|
|||||||
?INFO_MSG(
|
?INFO_MSG(
|
||||||
"(~w) Failed legacy authentication for ~s",
|
"(~w) Failed legacy authentication for ~s",
|
||||||
[StateData#state.socket,
|
[StateData#state.socket,
|
||||||
jlib:jid_to_string(JID)]),
|
exmpp_jid:jid_to_string(JID)]),
|
||||||
Err = jlib:make_error_reply(
|
Err = exmpp_stanza:error('not-authorized'),
|
||||||
El, ?ERR_NOT_AUTHORIZED),
|
Res = exmpp_iq:error_without_original(El, Err),
|
||||||
send_element(StateData, Err),
|
send_element(StateData, Res),
|
||||||
fsm_next_state(wait_for_auth, StateData)
|
fsm_next_state(wait_for_auth, StateData)
|
||||||
end;
|
end;
|
||||||
_ ->
|
_ ->
|
||||||
if
|
?INFO_MSG(
|
||||||
JID == error ->
|
"(~w) Forbidden legacy authentication for ~s",
|
||||||
|
[StateData#state.socket,
|
||||||
|
exmpp_jid:jid_to_string(JID)]),
|
||||||
|
Err = exmpp_stanza:error('not-allowed'),
|
||||||
|
Res = exmpp_iq:error_without_original(El, Err),
|
||||||
|
send_element(StateData, Res),
|
||||||
|
fsm_next_state(wait_for_auth, StateData)
|
||||||
|
end
|
||||||
|
catch
|
||||||
|
throw:_Exception ->
|
||||||
?INFO_MSG(
|
?INFO_MSG(
|
||||||
"(~w) Forbidden legacy authentication for "
|
"(~w) Forbidden legacy authentication for "
|
||||||
"username '~s' with resource '~s'",
|
"username '~s' with resource '~s'",
|
||||||
[StateData#state.socket, U, R]),
|
[StateData#state.socket, U, R]),
|
||||||
Err = jlib:make_error_reply(El, ?ERR_JID_MALFORMED),
|
Err1 = exmpp_stanza:error('jid-malformed'),
|
||||||
send_element(StateData, Err),
|
Res1 = exmpp_iq:error_without_original(El, Err1),
|
||||||
fsm_next_state(wait_for_auth, StateData);
|
send_element(StateData, Res1),
|
||||||
true ->
|
|
||||||
?INFO_MSG(
|
|
||||||
"(~w) Forbidden legacy authentication for ~s",
|
|
||||||
[StateData#state.socket,
|
|
||||||
jlib:jid_to_string(JID)]),
|
|
||||||
Err = jlib:make_error_reply(El, ?ERR_NOT_ALLOWED),
|
|
||||||
send_element(StateData, Err),
|
|
||||||
fsm_next_state(wait_for_auth, StateData)
|
fsm_next_state(wait_for_auth, StateData)
|
||||||
end
|
|
||||||
end;
|
end;
|
||||||
_ ->
|
_ ->
|
||||||
process_unauthenticated_stanza(StateData, El),
|
process_unauthenticated_stanza(StateData, El),
|
||||||
@ -522,38 +526,36 @@ wait_for_auth(timeout, StateData) ->
|
|||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
wait_for_auth({xmlstreamend, _Name}, StateData) ->
|
wait_for_auth({xmlstreamend, _Name}, StateData) ->
|
||||||
send_text(StateData, ?STREAM_TRAILER),
|
send_element(StateData, exmpp_stream:closing()),
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
wait_for_auth({xmlstreamerror, _}, StateData) ->
|
wait_for_auth({xmlstreamerror, _}, StateData) ->
|
||||||
send_text(StateData, ?INVALID_XML_ERR ++ ?STREAM_TRAILER),
|
send_element(StateData, exmpp_stream:error('xml-not-well-formed')),
|
||||||
|
send_element(StateData, exmpp_stream:closing()),
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
wait_for_auth(closed, StateData) ->
|
wait_for_auth(closed, StateData) ->
|
||||||
{stop, normal, StateData}.
|
{stop, normal, StateData}.
|
||||||
|
|
||||||
|
|
||||||
wait_for_feature_request({xmlstreamelement, El}, StateData) ->
|
wait_for_feature_request({xmlstreamelement, #xmlel{ns = NS, name = Name} = El},
|
||||||
{xmlelement, Name, Attrs, Els} = El,
|
StateData) ->
|
||||||
Zlib = StateData#state.zlib,
|
Zlib = StateData#state.zlib,
|
||||||
TLS = StateData#state.tls,
|
TLS = StateData#state.tls,
|
||||||
TLSEnabled = StateData#state.tls_enabled,
|
TLSEnabled = StateData#state.tls_enabled,
|
||||||
TLSRequired = StateData#state.tls_required,
|
TLSRequired = StateData#state.tls_required,
|
||||||
SockMod = (StateData#state.sockmod):get_sockmod(StateData#state.socket),
|
SockMod = (StateData#state.sockmod):get_sockmod(StateData#state.socket),
|
||||||
case {xml:get_attr_s("xmlns", Attrs), Name} of
|
case {NS, Name} of
|
||||||
{?NS_SASL, "auth"} when not ((SockMod == gen_tcp) and TLSRequired) ->
|
{?NS_SASL, 'auth'} when not ((SockMod == gen_tcp) and TLSRequired) ->
|
||||||
Mech = xml:get_attr_s("mechanism", Attrs),
|
{auth, Mech, ClientIn} = exmpp_server_sasl:next_step(El),
|
||||||
ClientIn = jlib:decode_base64(xml:get_cdata(Els)),
|
|
||||||
case cyrsasl:server_start(StateData#state.sasl_state,
|
case cyrsasl:server_start(StateData#state.sasl_state,
|
||||||
Mech,
|
Mech,
|
||||||
ClientIn) of
|
ClientIn) of
|
||||||
{ok, Props} ->
|
{ok, Props} ->
|
||||||
(StateData#state.sockmod):reset_stream(
|
(StateData#state.sockmod):reset_stream(
|
||||||
StateData#state.socket),
|
StateData#state.socket),
|
||||||
send_element(StateData,
|
send_element(StateData, exmpp_server_sasl:success()),
|
||||||
{xmlelement, "success",
|
U = proplists:get_value(username, Props),
|
||||||
[{"xmlns", ?NS_SASL}], []}),
|
|
||||||
U = xml:get_attr_s(username, Props),
|
|
||||||
?INFO_MSG("(~w) Accepted authentication for ~s",
|
?INFO_MSG("(~w) Accepted authentication for ~s",
|
||||||
[StateData#state.socket, U]),
|
[StateData#state.socket, U]),
|
||||||
fsm_next_state(wait_for_stream,
|
fsm_next_state(wait_for_stream,
|
||||||
@ -563,10 +565,7 @@ wait_for_feature_request({xmlstreamelement, El}, StateData) ->
|
|||||||
user = U });
|
user = U });
|
||||||
{continue, ServerOut, NewSASLState} ->
|
{continue, ServerOut, NewSASLState} ->
|
||||||
send_element(StateData,
|
send_element(StateData,
|
||||||
{xmlelement, "challenge",
|
exmpp_server_sasl:challenge(ServerOut)),
|
||||||
[{"xmlns", ?NS_SASL}],
|
|
||||||
[{xmlcdata,
|
|
||||||
jlib:encode_base64(ServerOut)}]}),
|
|
||||||
fsm_next_state(wait_for_sasl_response,
|
fsm_next_state(wait_for_sasl_response,
|
||||||
StateData#state{
|
StateData#state{
|
||||||
sasl_state = NewSASLState});
|
sasl_state = NewSASLState});
|
||||||
@ -575,20 +574,18 @@ wait_for_feature_request({xmlstreamelement, El}, StateData) ->
|
|||||||
"(~w) Failed authentication for ~s@~s",
|
"(~w) Failed authentication for ~s@~s",
|
||||||
[StateData#state.socket,
|
[StateData#state.socket,
|
||||||
Username, StateData#state.server]),
|
Username, StateData#state.server]),
|
||||||
|
% XXX OLD FORMAT: list_to_atom(Error).
|
||||||
send_element(StateData,
|
send_element(StateData,
|
||||||
{xmlelement, "failure",
|
exmpp_server_sasl:failure(list_to_atom(Error))),
|
||||||
[{"xmlns", ?NS_SASL}],
|
|
||||||
[{xmlelement, Error, [], []}]}),
|
|
||||||
{next_state, wait_for_feature_request, StateData,
|
{next_state, wait_for_feature_request, StateData,
|
||||||
?C2S_OPEN_TIMEOUT};
|
?C2S_OPEN_TIMEOUT};
|
||||||
{error, Error} ->
|
{error, Error} ->
|
||||||
|
% XXX OLD FORMAT: list_to_atom(Error).
|
||||||
send_element(StateData,
|
send_element(StateData,
|
||||||
{xmlelement, "failure",
|
exmpp_server_sasl:failure(list_to_atom(Error))),
|
||||||
[{"xmlns", ?NS_SASL}],
|
|
||||||
[{xmlelement, Error, [], []}]}),
|
|
||||||
fsm_next_state(wait_for_feature_request, StateData)
|
fsm_next_state(wait_for_feature_request, StateData)
|
||||||
end;
|
end;
|
||||||
{?NS_TLS, "starttls"} when TLS == true,
|
{?NS_TLS, 'starttls'} when TLS == true,
|
||||||
TLSEnabled == false,
|
TLSEnabled == false,
|
||||||
SockMod == gen_tcp ->
|
SockMod == gen_tcp ->
|
||||||
TLSOpts = case ejabberd_config:get_local_option(
|
TLSOpts = case ejabberd_config:get_local_option(
|
||||||
@ -601,55 +598,45 @@ wait_for_feature_request({xmlstreamelement, El}, StateData) ->
|
|||||||
certfile, 1, StateData#state.tls_options)]
|
certfile, 1, StateData#state.tls_options)]
|
||||||
end,
|
end,
|
||||||
Socket = StateData#state.socket,
|
Socket = StateData#state.socket,
|
||||||
|
Proceed = exmpp_xml:document_fragment_to_list(
|
||||||
|
exmpp_server_tls:proceed(), ?DEFAULT_NS, ?PREFIXED_NS),
|
||||||
TLSSocket = (StateData#state.sockmod):starttls(
|
TLSSocket = (StateData#state.sockmod):starttls(
|
||||||
Socket, TLSOpts,
|
Socket, TLSOpts,
|
||||||
xml:element_to_string(
|
Proceed),
|
||||||
{xmlelement, "proceed", [{"xmlns", ?NS_TLS}], []})),
|
|
||||||
fsm_next_state(wait_for_stream,
|
fsm_next_state(wait_for_stream,
|
||||||
StateData#state{socket = TLSSocket,
|
StateData#state{socket = TLSSocket,
|
||||||
streamid = new_id(),
|
streamid = new_id(),
|
||||||
tls_enabled = true
|
tls_enabled = true
|
||||||
});
|
});
|
||||||
{?NS_COMPRESS, "compress"} when Zlib == true,
|
{?NS_COMPRESS, 'compress'} when Zlib == true,
|
||||||
SockMod == gen_tcp ->
|
SockMod == gen_tcp ->
|
||||||
case xml:get_subtag(El, "method") of
|
case exmpp_server_compression:selected_method(El) of
|
||||||
false ->
|
undefined ->
|
||||||
send_element(StateData,
|
send_element(StateData,
|
||||||
{xmlelement, "failure",
|
exmpp_server_compression:failure('steup-failed')),
|
||||||
[{"xmlns", ?NS_COMPRESS}],
|
|
||||||
[{xmlelement, "setup-failed", [], []}]}),
|
|
||||||
fsm_next_state(wait_for_feature_request, StateData);
|
fsm_next_state(wait_for_feature_request, StateData);
|
||||||
Method ->
|
|
||||||
case xml:get_tag_cdata(Method) of
|
|
||||||
"zlib" ->
|
"zlib" ->
|
||||||
Socket = StateData#state.socket,
|
Socket = StateData#state.socket,
|
||||||
ZlibSocket = (StateData#state.sockmod):compress(
|
ZlibSocket = (StateData#state.sockmod):compress(
|
||||||
Socket,
|
Socket,
|
||||||
xml:element_to_string(
|
exmpp_server_compression:compressed()),
|
||||||
{xmlelement, "compressed",
|
|
||||||
[{"xmlns", ?NS_COMPRESS}], []})),
|
|
||||||
fsm_next_state(wait_for_stream,
|
fsm_next_state(wait_for_stream,
|
||||||
StateData#state{socket = ZlibSocket,
|
StateData#state{socket = ZlibSocket,
|
||||||
streamid = new_id()
|
streamid = new_id()
|
||||||
});
|
});
|
||||||
_ ->
|
_ ->
|
||||||
send_element(StateData,
|
send_element(StateData,
|
||||||
{xmlelement, "failure",
|
exmpp_server_compression:failure('unsupported-method')),
|
||||||
[{"xmlns", ?NS_COMPRESS}],
|
|
||||||
[{xmlelement, "unsupported-method",
|
|
||||||
[], []}]}),
|
|
||||||
fsm_next_state(wait_for_feature_request,
|
fsm_next_state(wait_for_feature_request,
|
||||||
StateData)
|
StateData)
|
||||||
end
|
|
||||||
end;
|
end;
|
||||||
_ ->
|
_ ->
|
||||||
if
|
if
|
||||||
(SockMod == gen_tcp) and TLSRequired ->
|
(SockMod == gen_tcp) and TLSRequired ->
|
||||||
Lang = StateData#state.lang,
|
Lang = StateData#state.lang,
|
||||||
send_text(StateData, ?POLICY_VIOLATION_ERR(
|
send_element(StateData, exmpp_stream:error(
|
||||||
Lang,
|
'policy-violation', Lang, "Use of STARTTLS required")),
|
||||||
"Use of STARTTLS required") ++
|
send_element(StateData, exmpp_stream:closing()),
|
||||||
?STREAM_TRAILER),
|
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
true ->
|
true ->
|
||||||
process_unauthenticated_stanza(StateData, El),
|
process_unauthenticated_stanza(StateData, El),
|
||||||
@ -661,32 +648,31 @@ wait_for_feature_request(timeout, StateData) ->
|
|||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
wait_for_feature_request({xmlstreamend, _Name}, StateData) ->
|
wait_for_feature_request({xmlstreamend, _Name}, StateData) ->
|
||||||
send_text(StateData, ?STREAM_TRAILER),
|
send_element(StateData, exmpp_stream:closing()),
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
wait_for_feature_request({xmlstreamerror, _}, StateData) ->
|
wait_for_feature_request({xmlstreamerror, _}, StateData) ->
|
||||||
send_text(StateData, ?INVALID_XML_ERR ++ ?STREAM_TRAILER),
|
send_element(StateData, exmpp_stream:error('xml-not-well-formed')),
|
||||||
|
send_element(StateData, exmpp_stream:closing()),
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
wait_for_feature_request(closed, StateData) ->
|
wait_for_feature_request(closed, StateData) ->
|
||||||
{stop, normal, StateData}.
|
{stop, normal, StateData}.
|
||||||
|
|
||||||
|
|
||||||
wait_for_sasl_response({xmlstreamelement, El}, StateData) ->
|
wait_for_sasl_response({xmlstreamelement, #xmlel{ns = NS, name = Name} = El},
|
||||||
{xmlelement, Name, Attrs, Els} = El,
|
StateData) ->
|
||||||
case {xml:get_attr_s("xmlns", Attrs), Name} of
|
case {NS, Name} of
|
||||||
{?NS_SASL, "response"} ->
|
{?NS_SASL, 'response'} ->
|
||||||
ClientIn = jlib:decode_base64(xml:get_cdata(Els)),
|
{response, ClientIn} = exmpp_server_sasl:next_step(El),
|
||||||
case cyrsasl:server_step(StateData#state.sasl_state,
|
case cyrsasl:server_step(StateData#state.sasl_state,
|
||||||
ClientIn) of
|
ClientIn) of
|
||||||
{ok, Props} ->
|
{ok, Props} ->
|
||||||
(StateData#state.sockmod):reset_stream(
|
(StateData#state.sockmod):reset_stream(
|
||||||
StateData#state.socket),
|
StateData#state.socket),
|
||||||
send_element(StateData,
|
send_element(StateData, exmpp_server_sasl:success()),
|
||||||
{xmlelement, "success",
|
U = proplists:get_value(username, Props),
|
||||||
[{"xmlns", ?NS_SASL}], []}),
|
AuthModule = proplists:get_value(auth_module, Props),
|
||||||
U = xml:get_attr_s(username, Props),
|
|
||||||
AuthModule = xml:get_attr_s(auth_module, Props),
|
|
||||||
?INFO_MSG("(~w) Accepted authentication for ~s",
|
?INFO_MSG("(~w) Accepted authentication for ~s",
|
||||||
[StateData#state.socket, U]),
|
[StateData#state.socket, U]),
|
||||||
fsm_next_state(wait_for_stream,
|
fsm_next_state(wait_for_stream,
|
||||||
@ -697,10 +683,7 @@ wait_for_sasl_response({xmlstreamelement, El}, StateData) ->
|
|||||||
user = U});
|
user = U});
|
||||||
{continue, ServerOut, NewSASLState} ->
|
{continue, ServerOut, NewSASLState} ->
|
||||||
send_element(StateData,
|
send_element(StateData,
|
||||||
{xmlelement, "challenge",
|
exmpp_server_sasl:challenge(ServerOut)),
|
||||||
[{"xmlns", ?NS_SASL}],
|
|
||||||
[{xmlcdata,
|
|
||||||
jlib:encode_base64(ServerOut)}]}),
|
|
||||||
fsm_next_state(wait_for_sasl_response,
|
fsm_next_state(wait_for_sasl_response,
|
||||||
StateData#state{sasl_state = NewSASLState});
|
StateData#state{sasl_state = NewSASLState});
|
||||||
{error, Error, Username} ->
|
{error, Error, Username} ->
|
||||||
@ -708,16 +691,14 @@ wait_for_sasl_response({xmlstreamelement, El}, StateData) ->
|
|||||||
"(~w) Failed authentication for ~s@~s",
|
"(~w) Failed authentication for ~s@~s",
|
||||||
[StateData#state.socket,
|
[StateData#state.socket,
|
||||||
Username, StateData#state.server]),
|
Username, StateData#state.server]),
|
||||||
|
% XXX OLD FORMAT: list_to_atom(Error).
|
||||||
send_element(StateData,
|
send_element(StateData,
|
||||||
{xmlelement, "failure",
|
exmpp_server_sasl:failure(list_to_atom(Error))),
|
||||||
[{"xmlns", ?NS_SASL}],
|
|
||||||
[{xmlelement, Error, [], []}]}),
|
|
||||||
fsm_next_state(wait_for_feature_request, StateData);
|
fsm_next_state(wait_for_feature_request, StateData);
|
||||||
{error, Error} ->
|
{error, Error} ->
|
||||||
|
% XXX OLD FORMAT: list_to_atom(Error).
|
||||||
send_element(StateData,
|
send_element(StateData,
|
||||||
{xmlelement, "failure",
|
exmpp_server_sasl:failure(list_to_atom(Error))),
|
||||||
[{"xmlns", ?NS_SASL}],
|
|
||||||
[{xmlelement, Error, [], []}]}),
|
|
||||||
fsm_next_state(wait_for_feature_request, StateData)
|
fsm_next_state(wait_for_feature_request, StateData)
|
||||||
end;
|
end;
|
||||||
_ ->
|
_ ->
|
||||||
@ -729,11 +710,12 @@ wait_for_sasl_response(timeout, StateData) ->
|
|||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
wait_for_sasl_response({xmlstreamend, _Name}, StateData) ->
|
wait_for_sasl_response({xmlstreamend, _Name}, StateData) ->
|
||||||
send_text(StateData, ?STREAM_TRAILER),
|
send_element(StateData, exmpp_stream:closing()),
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
wait_for_sasl_response({xmlstreamerror, _}, StateData) ->
|
wait_for_sasl_response({xmlstreamerror, _}, StateData) ->
|
||||||
send_text(StateData, ?INVALID_XML_ERR ++ ?STREAM_TRAILER),
|
send_element(StateData, exmpp_stream:error('xml-not-well-formed')),
|
||||||
|
send_element(StateData, exmpp_stream:closing()),
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
wait_for_sasl_response(closed, StateData) ->
|
wait_for_sasl_response(closed, StateData) ->
|
||||||
@ -742,35 +724,25 @@ wait_for_sasl_response(closed, StateData) ->
|
|||||||
|
|
||||||
|
|
||||||
wait_for_bind({xmlstreamelement, El}, StateData) ->
|
wait_for_bind({xmlstreamelement, El}, StateData) ->
|
||||||
case jlib:iq_query_info(El) of
|
try
|
||||||
#iq{type = set, xmlns = ?NS_BIND, sub_el = SubEl} = IQ ->
|
|
||||||
U = StateData#state.user,
|
U = StateData#state.user,
|
||||||
R1 = xml:get_path_s(SubEl, [{elem, "resource"}, cdata]),
|
R = case exmpp_server_binding:wished_resource(El) of
|
||||||
R = case jlib:resourceprep(R1) of
|
undefined ->
|
||||||
error -> error;
|
lists:concat([randoms:get_string() | tuple_to_list(now())]);
|
||||||
"" ->
|
Resource ->
|
||||||
lists:concat(
|
Resource
|
||||||
[randoms:get_string() | tuple_to_list(now())]);
|
|
||||||
Resource -> Resource
|
|
||||||
end,
|
end,
|
||||||
case R of
|
JID = exmpp_jid:make_jid(U, StateData#state.server, R),
|
||||||
error ->
|
Res = exmpp_server_binding:bind(El, JID),
|
||||||
Err = jlib:make_error_reply(El, ?ERR_BAD_REQUEST),
|
send_element(StateData, Res),
|
||||||
send_element(StateData, Err),
|
|
||||||
fsm_next_state(wait_for_bind, StateData);
|
|
||||||
_ ->
|
|
||||||
JID = jlib:make_jid(U, StateData#state.server, R),
|
|
||||||
Res = IQ#iq{type = result,
|
|
||||||
sub_el = [{xmlelement, "bind",
|
|
||||||
[{"xmlns", ?NS_BIND}],
|
|
||||||
[{xmlelement, "jid", [],
|
|
||||||
[{xmlcdata,
|
|
||||||
jlib:jid_to_string(JID)}]}]}]},
|
|
||||||
send_element(StateData, jlib:iq_to_xml(Res)),
|
|
||||||
fsm_next_state(wait_for_session,
|
fsm_next_state(wait_for_session,
|
||||||
StateData#state{resource = R, jid = JID})
|
StateData#state{resource = R, jid = JID})
|
||||||
end;
|
catch
|
||||||
_ ->
|
throw:{stringprep, resourceprep, _, _} ->
|
||||||
|
Err = exmpp_server_binding:error(El, 'bad-request'),
|
||||||
|
send_element(StateData, Err),
|
||||||
|
fsm_next_state(wait_for_bind, StateData);
|
||||||
|
throw:Exception ->
|
||||||
fsm_next_state(wait_for_bind, StateData)
|
fsm_next_state(wait_for_bind, StateData)
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -778,11 +750,12 @@ wait_for_bind(timeout, StateData) ->
|
|||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
wait_for_bind({xmlstreamend, _Name}, StateData) ->
|
wait_for_bind({xmlstreamend, _Name}, StateData) ->
|
||||||
send_text(StateData, ?STREAM_TRAILER),
|
send_element(StateData, exmpp_stream:closing()),
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
wait_for_bind({xmlstreamerror, _}, StateData) ->
|
wait_for_bind({xmlstreamerror, _}, StateData) ->
|
||||||
send_text(StateData, ?INVALID_XML_ERR ++ ?STREAM_TRAILER),
|
send_element(StateData, exmpp_stream:error('xml-not-well-formed')),
|
||||||
|
send_element(StateData, exmpp_stream:closing()),
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
wait_for_bind(closed, StateData) ->
|
wait_for_bind(closed, StateData) ->
|
||||||
@ -791,24 +764,24 @@ wait_for_bind(closed, StateData) ->
|
|||||||
|
|
||||||
|
|
||||||
wait_for_session({xmlstreamelement, El}, StateData) ->
|
wait_for_session({xmlstreamelement, El}, StateData) ->
|
||||||
case jlib:iq_query_info(El) of
|
try
|
||||||
#iq{type = set, xmlns = ?NS_SESSION} ->
|
|
||||||
U = StateData#state.user,
|
U = StateData#state.user,
|
||||||
R = StateData#state.resource,
|
R = StateData#state.resource,
|
||||||
JID = StateData#state.jid,
|
JID = StateData#state.jid,
|
||||||
|
exmpp_server_session:want_establishment(El),
|
||||||
case acl:match_rule(StateData#state.server,
|
case acl:match_rule(StateData#state.server,
|
||||||
StateData#state.access, JID) of
|
StateData#state.access, JID) of
|
||||||
allow ->
|
allow ->
|
||||||
?INFO_MSG("(~w) Opened session for ~s",
|
?INFO_MSG("(~w) Opened session for ~s",
|
||||||
[StateData#state.socket,
|
[StateData#state.socket,
|
||||||
jlib:jid_to_string(JID)]),
|
exmpp_jid:jid_to_string(JID)]),
|
||||||
SID = {now(), self()},
|
SID = {now(), self()},
|
||||||
Conn = get_conn_type(StateData),
|
Conn = get_conn_type(StateData),
|
||||||
Info = [{ip, StateData#state.ip}, {conn, Conn},
|
Info = [{ip, StateData#state.ip}, {conn, Conn},
|
||||||
{auth_module, StateData#state.auth_module}],
|
{auth_module, StateData#state.auth_module}],
|
||||||
ejabberd_sm:open_session(
|
ejabberd_sm:open_session(
|
||||||
SID, U, StateData#state.server, R, Info),
|
SID, U, StateData#state.server, R, Info),
|
||||||
Res = jlib:make_result_iq_reply(El),
|
Res = exmpp_server_session:establish(El),
|
||||||
send_element(StateData, Res),
|
send_element(StateData, Res),
|
||||||
change_shaper(StateData, JID),
|
change_shaper(StateData, JID),
|
||||||
{Fs, Ts} = ejabberd_hooks:run_fold(
|
{Fs, Ts} = ejabberd_hooks:run_fold(
|
||||||
@ -816,7 +789,7 @@ wait_for_session({xmlstreamelement, El}, StateData) ->
|
|||||||
StateData#state.server,
|
StateData#state.server,
|
||||||
{[], []},
|
{[], []},
|
||||||
[U, StateData#state.server]),
|
[U, StateData#state.server]),
|
||||||
LJID = jlib:jid_tolower(jlib:jid_remove_resource(JID)),
|
LJID = {JID#jid.lnode, JID#jid.ldomain, ""},
|
||||||
Fs1 = [LJID | Fs],
|
Fs1 = [LJID | Fs],
|
||||||
Ts1 = [LJID | Ts],
|
Ts1 = [LJID | Ts],
|
||||||
PrivList =
|
PrivList =
|
||||||
@ -836,12 +809,13 @@ wait_for_session({xmlstreamelement, El}, StateData) ->
|
|||||||
StateData#state.server, [JID]),
|
StateData#state.server, [JID]),
|
||||||
?INFO_MSG("(~w) Forbidden session for ~s",
|
?INFO_MSG("(~w) Forbidden session for ~s",
|
||||||
[StateData#state.socket,
|
[StateData#state.socket,
|
||||||
jlib:jid_to_string(JID)]),
|
exmpp_jid:jid_to_string(JID)]),
|
||||||
Err = jlib:make_error_reply(El, ?ERR_NOT_ALLOWED),
|
Err = exmpp_server_session:error(El, 'not-allowed'),
|
||||||
send_element(StateData, Err),
|
send_element(StateData, Err),
|
||||||
fsm_next_state(wait_for_session, StateData)
|
fsm_next_state(wait_for_session, StateData)
|
||||||
end;
|
end
|
||||||
_ ->
|
catch
|
||||||
|
throw:_Exception ->
|
||||||
fsm_next_state(wait_for_session, StateData)
|
fsm_next_state(wait_for_session, StateData)
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -849,11 +823,12 @@ wait_for_session(timeout, StateData) ->
|
|||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
wait_for_session({xmlstreamend, _Name}, StateData) ->
|
wait_for_session({xmlstreamend, _Name}, StateData) ->
|
||||||
send_text(StateData, ?STREAM_TRAILER),
|
send_element(StateData, exmpp_stream:closing()),
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
wait_for_session({xmlstreamerror, _}, StateData) ->
|
wait_for_session({xmlstreamerror, _}, StateData) ->
|
||||||
send_text(StateData, ?INVALID_XML_ERR ++ ?STREAM_TRAILER),
|
send_element(StateData, exmpp_stream:error('xml-not-well-formed')),
|
||||||
|
send_element(StateData, exmpp_stream:closing()),
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
wait_for_session(closed, StateData) ->
|
wait_for_session(closed, StateData) ->
|
||||||
@ -861,90 +836,121 @@ wait_for_session(closed, StateData) ->
|
|||||||
|
|
||||||
|
|
||||||
session_established({xmlstreamelement, El}, StateData) ->
|
session_established({xmlstreamelement, El}, StateData) ->
|
||||||
{xmlelement, Name, Attrs, _Els} = El,
|
try
|
||||||
User = StateData#state.user,
|
User = StateData#state.user,
|
||||||
Server = StateData#state.server,
|
Server = StateData#state.server,
|
||||||
% TODO: check 'from' attribute in stanza
|
% TODO: check 'from' attribute in stanza
|
||||||
FromJID = StateData#state.jid,
|
FromJID = StateData#state.jid,
|
||||||
To = xml:get_attr_s("to", Attrs),
|
To = exmpp_stanza:get_recipient(El),
|
||||||
ToJID = case To of
|
ToJID = case To of
|
||||||
"" ->
|
"" ->
|
||||||
jlib:make_jid(User, Server, "");
|
exmpp_jid:make_jid(User, Server, "");
|
||||||
_ ->
|
_ ->
|
||||||
jlib:string_to_jid(To)
|
exmpp_jid:string_to_jid(To)
|
||||||
end,
|
end,
|
||||||
NewEl1 = jlib:remove_attr("xmlns", El),
|
NewEl = case exmpp_stanza:get_lang(El) of
|
||||||
NewEl = case xml:get_attr_s("xml:lang", Attrs) of
|
|
||||||
"" ->
|
"" ->
|
||||||
case StateData#state.lang of
|
case StateData#state.lang of
|
||||||
"" -> NewEl1;
|
"" -> El;
|
||||||
Lang ->
|
Lang ->
|
||||||
xml:replace_tag_attr("xml:lang", Lang, NewEl1)
|
exmpp_stanza:set_lang(El, Lang)
|
||||||
end;
|
end;
|
||||||
_ ->
|
_ ->
|
||||||
NewEl1
|
El
|
||||||
end,
|
end,
|
||||||
NewState =
|
NewState = case El of
|
||||||
case ToJID of
|
#xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence'} ->
|
||||||
error ->
|
% XXX OLD FORMAT: NewEl.
|
||||||
case xml:get_attr_s("type", Attrs) of
|
PresenceElOld = ejabberd_hooks:run_fold(
|
||||||
"error" -> StateData;
|
|
||||||
"result" -> StateData;
|
|
||||||
_ ->
|
|
||||||
Err = jlib:make_error_reply(NewEl, ?ERR_JID_MALFORMED),
|
|
||||||
send_element(StateData, Err),
|
|
||||||
StateData
|
|
||||||
end;
|
|
||||||
_ ->
|
|
||||||
case Name of
|
|
||||||
"presence" ->
|
|
||||||
PresenceEl = ejabberd_hooks:run_fold(
|
|
||||||
c2s_update_presence,
|
c2s_update_presence,
|
||||||
Server,
|
Server,
|
||||||
NewEl,
|
exmpp_xml:xmlel_to_xmlelement(NewEl,
|
||||||
|
?DEFAULT_NS, ?PREFIXED_NS),
|
||||||
[User, Server]),
|
[User, Server]),
|
||||||
|
PresenceEl = exmpp_xml:xmlelement_to_xmlel(PresenceElOld,
|
||||||
|
?DEFAULT_NS, ?PREFIXED_NS),
|
||||||
|
% XXX OLD FORMAT: PresenceElOld.
|
||||||
ejabberd_hooks:run(
|
ejabberd_hooks:run(
|
||||||
user_send_packet,
|
user_send_packet,
|
||||||
Server,
|
Server,
|
||||||
[FromJID, ToJID, PresenceEl]),
|
[FromJID, ToJID, PresenceElOld]),
|
||||||
case ToJID of
|
case ToJID of
|
||||||
#jid{user = User,
|
#jid{node = User,
|
||||||
server = Server,
|
domain = Server,
|
||||||
resource = ""} ->
|
resource = ""} ->
|
||||||
?DEBUG("presence_update(~p,~n\t~p,~n\t~p)",
|
?DEBUG("presence_update(~p,~n\t~p,~n\t~p)",
|
||||||
[FromJID, PresenceEl, StateData]),
|
[FromJID, PresenceEl, StateData]),
|
||||||
presence_update(FromJID, PresenceEl,
|
% XXX OLD FORMAT: PresenceElOld.
|
||||||
|
presence_update(FromJID, PresenceElOld,
|
||||||
StateData);
|
StateData);
|
||||||
_ ->
|
_ ->
|
||||||
presence_track(FromJID, ToJID, PresenceEl,
|
% XXX OLD FORMAT: PresenceElOld.
|
||||||
|
presence_track(FromJID, ToJID, PresenceElOld,
|
||||||
StateData)
|
StateData)
|
||||||
end;
|
end;
|
||||||
"iq" ->
|
#xmlel{ns = ?NS_JABBER_CLIENT, name = 'iq'} ->
|
||||||
case jlib:iq_query_info(NewEl) of
|
IQ_Content = case exmpp_iq:get_type(El) of
|
||||||
#iq{xmlns = ?NS_PRIVACY} = IQ ->
|
'get' -> exmpp_iq:get_request(El);
|
||||||
|
'set' -> exmpp_iq:get_request(El);
|
||||||
|
'result' -> exmpp_iq:get_result(El);
|
||||||
|
'error' -> exmpp_stanza:get_error(El)
|
||||||
|
end,
|
||||||
|
case IQ_Content of
|
||||||
|
#xmlel{ns = ?NS_PRIVACY} = IQ ->
|
||||||
|
% XXX OLD FORMAT: IQ was #iq.
|
||||||
process_privacy_iq(
|
process_privacy_iq(
|
||||||
FromJID, ToJID, IQ, StateData);
|
FromJID, ToJID, IQ, StateData);
|
||||||
_ ->
|
_ ->
|
||||||
|
% XXX OLD FORMAT: NewElOld.
|
||||||
|
NewElOld = exmpp_xml:xmlel_to_xmlelement(NewEl,
|
||||||
|
?DEFAULT_NS, ?PREFIXED_NS),
|
||||||
ejabberd_hooks:run(
|
ejabberd_hooks:run(
|
||||||
user_send_packet,
|
user_send_packet,
|
||||||
Server,
|
Server,
|
||||||
[FromJID, ToJID, NewEl]),
|
[FromJID, ToJID, NewElOld]),
|
||||||
|
% XXX OLD FORMAT: NewElOld.
|
||||||
ejabberd_router:route(
|
ejabberd_router:route(
|
||||||
FromJID, ToJID, NewEl),
|
FromJID, ToJID, NewElOld),
|
||||||
StateData
|
StateData
|
||||||
end;
|
end;
|
||||||
"message" ->
|
#xmlel{ns = ?NS_JABBER_CLIENT, name = 'message'} ->
|
||||||
|
% XXX OLD FORMAT: NewElOld.
|
||||||
|
NewElOld = exmpp_xml:xmlel_to_xmlelement(NewEl,
|
||||||
|
?DEFAULT_NS, ?PREFIXED_NS),
|
||||||
ejabberd_hooks:run(user_send_packet,
|
ejabberd_hooks:run(user_send_packet,
|
||||||
Server,
|
Server,
|
||||||
[FromJID, ToJID, NewEl]),
|
[FromJID, ToJID, NewElOld]),
|
||||||
ejabberd_router:route(FromJID, ToJID, NewEl),
|
% XXX OLD FORMAT: NewElOld.
|
||||||
|
ejabberd_router:route(FromJID, ToJID, NewElOld),
|
||||||
StateData;
|
StateData;
|
||||||
_ ->
|
_ ->
|
||||||
StateData
|
StateData
|
||||||
end
|
|
||||||
end,
|
end,
|
||||||
ejabberd_hooks:run(c2s_loop_debug, [{xmlstreamelement, El}]),
|
% XXX OLD FORMAT: El.
|
||||||
fsm_next_state(session_established, NewState);
|
ElOld = exmpp_xml:xmlel_to_xmlelement(El,
|
||||||
|
?DEFAULT_NS, ?PREFIXED_NS),
|
||||||
|
ejabberd_hooks:run(c2s_loop_debug, [{xmlstreamelement, ElOld}]),
|
||||||
|
fsm_next_state(session_established, NewState)
|
||||||
|
catch
|
||||||
|
throw:{stringprep, _, _, _} ->
|
||||||
|
case exmpp_stanza:get_type(El) of
|
||||||
|
"error" ->
|
||||||
|
ok;
|
||||||
|
"result" ->
|
||||||
|
ok;
|
||||||
|
_ ->
|
||||||
|
Err = exmpp_stanza:reply_with_error(El, 'jid-malformed'),
|
||||||
|
send_element(StateData, Err)
|
||||||
|
end,
|
||||||
|
% XXX OLD FORMAT: ElOld1.
|
||||||
|
ElOld1 = exmpp_xml:xmlel_to_xmlelement(El,
|
||||||
|
?DEFAULT_NS, ?PREFIXED_NS),
|
||||||
|
ejabberd_hooks:run(c2s_loop_debug, [{xmlstreamelement, ElOld1}]),
|
||||||
|
fsm_next_state(session_established, StateData);
|
||||||
|
throw:Exception ->
|
||||||
|
io:format("SESSION ESTABLISHED: Exception=~p~n", [Exception]),
|
||||||
|
fsm_next_state(session_established, StateData)
|
||||||
|
end;
|
||||||
|
|
||||||
%% We hibernate the process to reduce memory consumption after a
|
%% We hibernate the process to reduce memory consumption after a
|
||||||
%% configurable activity timeout
|
%% configurable activity timeout
|
||||||
@ -956,11 +962,12 @@ session_established(timeout, StateData) ->
|
|||||||
fsm_next_state(session_established, StateData);
|
fsm_next_state(session_established, StateData);
|
||||||
|
|
||||||
session_established({xmlstreamend, _Name}, StateData) ->
|
session_established({xmlstreamend, _Name}, StateData) ->
|
||||||
send_text(StateData, ?STREAM_TRAILER),
|
send_element(StateData, exmpp_stream:closing()),
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
session_established({xmlstreamerror, _}, StateData) ->
|
session_established({xmlstreamerror, _}, StateData) ->
|
||||||
send_text(StateData, ?INVALID_XML_ERR ++ ?STREAM_TRAILER),
|
send_element(StateData, exmpp_stream:error('xml-not-well-formed')),
|
||||||
|
send_element(StateData, exmpp_stream:closing()),
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
|
||||||
session_established(closed, StateData) ->
|
session_established(closed, StateData) ->
|
||||||
|
Loading…
Reference in New Issue
Block a user