diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/cyrsasl.erl | 77 | ||||
-rw-r--r-- | src/cyrsasl_plain.erl | 56 | ||||
-rw-r--r-- | src/ejabberd_app.erl | 1 | ||||
-rw-r--r-- | src/ejabberd_auth.erl | 10 | ||||
-rw-r--r-- | src/ejabberd_c2s.erl | 232 | ||||
-rw-r--r-- | src/ejabberd_local.erl | 6 | ||||
-rw-r--r-- | src/jd2ejd.erl | 2 | ||||
-rw-r--r-- | src/jlib.erl | 82 | ||||
-rw-r--r-- | src/mod_configure.erl | 54 | ||||
-rw-r--r-- | src/mod_disco.erl | 43 | ||||
-rw-r--r-- | src/mod_echo.erl | 2 | ||||
-rw-r--r-- | src/mod_irc/mod_irc.erl | 24 | ||||
-rw-r--r-- | src/mod_irc/mod_irc_connection.erl | 18 | ||||
-rw-r--r-- | src/mod_offline.erl | 2 | ||||
-rw-r--r-- | src/mod_private.erl | 2 | ||||
-rw-r--r-- | src/mod_register.erl | 13 | ||||
-rw-r--r-- | src/mod_roster.erl | 2 | ||||
-rw-r--r-- | src/mod_stats.erl | 10 | ||||
-rw-r--r-- | src/mod_time.erl | 2 | ||||
-rw-r--r-- | src/mod_vcard.erl | 2 | ||||
-rw-r--r-- | src/mod_version.erl | 2 |
21 files changed, 500 insertions, 142 deletions
diff --git a/src/cyrsasl.erl b/src/cyrsasl.erl new file mode 100644 index 000000000..537ad4f1b --- /dev/null +++ b/src/cyrsasl.erl @@ -0,0 +1,77 @@ +%%%---------------------------------------------------------------------- +%%% File : cyrsasl.erl +%%% Author : Alexey Shchepin <alexey@sevcom.net> +%%% Purpose : Cyrus SASL-like library +%%% Created : 8 Mar 2003 by Alexey Shchepin <alexey@sevcom.net> +%%% Id : $Id$ +%%%---------------------------------------------------------------------- + +-module(cyrsasl). +-author('alexey@sevcom.net'). +-vsn('$Revision$ '). + +-export([start/0, + register_mechanism/2, + listmech/0, + server_new/4, + server_start/3, + server_step/2]). + +-record(sasl_mechanism, {mechanism, module}). +-record(sasl_state, {service, myname, realm, mech_mod, mech_state}). + +-export([behaviour_info/1]). + +behaviour_info(callbacks) -> + [{mech_new, 0}, + {mech_step, 2}]; +behaviour_info(Other) -> + undefined. + +start() -> + ets:new(sasl_mechanism, [named_table, + public, + {keypos, #sasl_mechanism.mechanism}]), + cyrsasl_plain:start([]), + ok. + +register_mechanism(Mechanism, Module) -> + ets:insert(sasl_mechanism, #sasl_mechanism{mechanism = Mechanism, + module = Module}). + +listmech() -> + ets:select(sasl_mechanism, + [{#sasl_mechanism{mechanism = '$1', _ = '_'}, [], ['$1']}]). + + +server_new(Service, ServerFQDN, UserRealm, SecFlags) -> + #sasl_state{service = Service, + myname = ServerFQDN, + realm = UserRealm}. + +server_start(State, Mech, ClientIn) -> + case ets:lookup(sasl_mechanism, Mech) of + [#sasl_mechanism{module = Module}] -> + MechState = Module:mech_new(), + server_step(State#sasl_state{mech_mod = Module, + mech_state = MechState}, + ClientIn); + _ -> + {error, "454"} + end. + +server_step(State, ClientIn) -> + Module = State#sasl_state.mech_mod, + MechState = State#sasl_state.mech_state, + case Module:mech_step(MechState, ClientIn) of + {ok, Props} -> + {ok, Props}; + {continue, ServerOut, NewMechState} -> + {continue, ServerOut, + State#sasl_state{mech_state = NewMechState}}; + {error, Code} -> + {error, Code} + end. + + + diff --git a/src/cyrsasl_plain.erl b/src/cyrsasl_plain.erl new file mode 100644 index 000000000..46461e1c0 --- /dev/null +++ b/src/cyrsasl_plain.erl @@ -0,0 +1,56 @@ +%%%---------------------------------------------------------------------- +%%% File : cyrsasl_plain.erl +%%% Author : Alexey Shchepin <alexey@sevcom.net> +%%% Purpose : PLAIN SASL mechanism +%%% Created : 8 Mar 2003 by Alexey Shchepin <alexey@sevcom.net> +%%% Id : $Id$ +%%%---------------------------------------------------------------------- + +-module(cyrsasl_plain). +-author('alexey@sevcom.net'). +-vsn('$Revision$ '). + +-export([start/1, stop/0, mech_new/0, mech_step/2, parse/1]). + +-behaviour(cyrsasl). +%-behaviour(gen_mod). + +start(Opts) -> + cyrsasl:register_mechanism("PLAIN", ?MODULE), + ok. + +stop() -> + ok. + +mech_new() -> + {ok, []}. + +mech_step(State, ClientIn) -> + case parse(ClientIn) of + [_, User, Password] -> + case ejabberd_auth:check_password(User, Password) of + true -> + {ok, [{username, User}]}; + _ -> + {error, "454"} + end; + _ -> + {error, "454"} + end. + + +parse(S) -> + parse1(S, "", []). + +parse1([0 | Cs], S, T) -> + parse1(Cs, "", [lists:reverse(S) | T]); +parse1([C | Cs], S, T) -> + parse1(Cs, [C | S], T); +%parse1([], [], T) -> +% lists:reverse(T); +parse1([], S, T) -> + lists:reverse([lists:reverse(S) | T]). + + + + diff --git a/src/ejabberd_app.erl b/src/ejabberd_app.erl index 7fa071675..80f8e42fb 100644 --- a/src/ejabberd_app.erl +++ b/src/ejabberd_app.erl @@ -26,6 +26,7 @@ start(normal, Args) -> gen_mod:start(), ejabberd_config:start(), ejabberd_auth:start(), + cyrsasl:start(), Sup = ejabberd_sup:start_link(), start(), load_modules(), diff --git a/src/ejabberd_auth.erl b/src/ejabberd_auth.erl index 49d293def..efe9e407b 100644 --- a/src/ejabberd_auth.erl +++ b/src/ejabberd_auth.erl @@ -109,14 +109,8 @@ terminate(Reason, State) -> check_password(User, Password) -> LUser = jlib:tolower(User), - F = fun() -> - case mnesia:read({passwd, LUser}) of - [E] -> - E#passwd.password - end - end, - case mnesia:transaction(F) of - {atomic, Password} -> + case catch mnesia:dirty_read({passwd, LUser}) of + [#passwd{password = Password}] -> true; _ -> false diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index aa8e241a5..e4150ffda 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -16,7 +16,12 @@ -export([start/2, receiver/4, send_text/2, send_element/2]). %% gen_fsm callbacks --export([init/1, wait_for_stream/2, wait_for_auth/2, session_established/2, +-export([init/1, + wait_for_stream/2, + wait_for_auth/2, + wait_for_sasl_auth/2, + wait_for_resource_auth/2, + session_established/2, handle_event/3, handle_sync_event/4, code_change/4, @@ -24,11 +29,12 @@ terminate/3]). -include("ejabberd.hrl"). --include("namespaces.hrl"). +-include("jlib.hrl"). -define(SETS, gb_sets). -record(state, {socket, receiver, streamid, + sasl_state, access, shaper, user = "", server = ?MYNAME, resource = "", @@ -52,14 +58,16 @@ "<?xml version='1.0'?>" "<stream:stream xmlns='jabber:client' " "xmlns:stream='http://etherx.jabber.org/streams' " - "id='~s' from='~s'>" + "id='~s' from='~s'~s>" ). -define(STREAM_TRAILER, "</stream:stream>"). -define(INVALID_NS_ERR, "<stream:error>Invalid Namespace</stream:error>"). +%-define(INVALID_XML_ERR, +% "<stream:error code='400'>Invalid XML</stream:error>"). -define(INVALID_XML_ERR, - "<stream:error code='400'>Invalid XML</stream:error>"). + xml:element_to_string(?SERR_XML_NOT_WELL_FORMED)). %%%---------------------------------------------------------------------- %%% API @@ -102,21 +110,48 @@ init([{SockMod, Socket}, Opts]) -> %%---------------------------------------------------------------------- wait_for_stream({xmlstreamstart, Name, Attrs}, StateData) -> - % TODO - Header = io_lib:format(?STREAM_HEADER, - [StateData#state.streamid, ?MYNAME]), - send_text(StateData#state.socket, Header), - case lists:keysearch("xmlns:stream", 1, Attrs) of - {value, {"xmlns:stream", "http://etherx.jabber.org/streams"}} -> - % TODO - {next_state, wait_for_auth, StateData}; + case xml:get_attr_s("xmlns:stream", Attrs) of + ?NS_STREAM -> + case xml:get_attr_s("version", Attrs) of + "1.0" -> + Header = io_lib:format(?STREAM_HEADER, + [StateData#state.streamid, + ?MYNAME, + " version='1.0'"]), + send_text(StateData#state.socket, Header), + SASLState = cyrsasl:server_new("jabber", ?MYNAME, "", []), + Mechs = lists:map(fun(S) -> + {xmlelement, "mechanism", [], + [{xmlcdata, S}]} + end, cyrsasl:listmech()), + send_element(StateData#state.socket, + {xmlelement, "stream:features", [], + [{xmlelement, "mechanisms", + [{"xmlns", ?NS_SASL_MECHANISMS}], + Mechs}]}), + {next_state, wait_for_sasl_auth, + StateData#state{sasl_state = SASLState}}; + _ -> + Header = io_lib:format( + ?STREAM_HEADER, + [StateData#state.streamid, ?MYNAME, ""]), + send_text(StateData#state.socket, Header), + {next_state, wait_for_auth, StateData} + end; _ -> - send_text(StateData#state.socket, ?INVALID_NS_ERR ?STREAM_TRAILER), + Header = io_lib:format( + ?STREAM_HEADER, + [StateData#state.streamid, ?MYNAME, ""]), + send_text(StateData#state.socket, + Header ++ ?INVALID_NS_ERR ?STREAM_TRAILER), {stop, normal, StateData} end; wait_for_stream({xmlstreamerror, _}, StateData) -> - send_text(StateData#state.socket, ?INVALID_XML_ERR), + Header = io_lib:format(?STREAM_HEADER, + ["none", ?MYNAME, " version='1.0'"]), + send_text(StateData#state.socket, + Header ++ ?INVALID_XML_ERR ++ ?STREAM_TRAILER), {stop, normal, StateData}; wait_for_stream(closed, StateData) -> @@ -125,11 +160,26 @@ wait_for_stream(closed, StateData) -> wait_for_auth({xmlstreamelement, El}, StateData) -> case is_auth_packet(El) of - {auth, ID, {U, P, D, ""}} -> + {auth, ID, get, {"", _, _, _}} -> + Err = jlib:make_error_reply(El, "406", "Not Acceptable"), + send_element(StateData#state.socket, Err), + {next_state, wait_for_auth, StateData}; + {auth, ID, get, {U, _, _, _}} -> + {xmlelement, Name, Attrs, Els} = jlib:make_result_iq_reply(El), + Res = {xmlelement, Name, Attrs, + [{xmlelement, "query", [{"xmlns", ?NS_AUTH}], + [{xmlelement, "username", [], [{xmlcdata, U}]}, + {xmlelement, "password", [], []}, + {xmlelement, "digest", [], []}, + {xmlelement, "resource", [], []} + ]}]}, + send_element(StateData#state.socket, Res), + {next_state, wait_for_auth, StateData}; + {auth, ID, set, {U, P, D, ""}} -> Err = jlib:make_error_reply(El, "406", "Not Acceptable"), send_element(StateData#state.socket, Err), {next_state, wait_for_auth, StateData}; - {auth, ID, {U, P, D, R}} -> + {auth, ID, set, {U, P, D, R}} -> io:format("AUTH: ~p~n", [{U, P, D, R}]), JID = {U, ?MYNAME, R}, case acl:match_rule(StateData#state.access, JID) of @@ -149,12 +199,12 @@ wait_for_auth({xmlstreamelement, El}, StateData) -> pres_t = ?SETS:from_list(Ts)}}; _ -> Err = jlib:make_error_reply( - El, "401", "Unauthorized"), + El, ?ERR_FORBIDDEN), send_element(StateData#state.socket, Err), {next_state, wait_for_auth, StateData} end; _ -> - Err = jlib:make_error_reply(El, "405", "Not Allowed"), + Err = jlib:make_error_reply(El, ?ERR_NOT_ALLOWED), send_element(StateData#state.socket, Err), {next_state, wait_for_auth, StateData} end; @@ -180,12 +230,152 @@ wait_for_auth({xmlstreamend, Name}, StateData) -> {stop, normal, StateData}; wait_for_auth({xmlstreamerror, _}, StateData) -> - send_text(StateData#state.socket, ?INVALID_XML_ERR ?STREAM_TRAILER), + send_text(StateData#state.socket, ?INVALID_XML_ERR ++ ?STREAM_TRAILER), {stop, normal, StateData}; wait_for_auth(closed, StateData) -> {stop, normal, StateData}. + +wait_for_sasl_auth({xmlstreamelement, El}, StateData) -> + {xmlelement, Name, Attrs, Els} = El, + case {xml:get_attr_s("xmlns", Attrs), Name} of + {?NS_SASL_MECHANISMS, "auth"} -> + Mech = xml:get_attr_s("mechanism", Attrs), + ClientIn = jlib:decode_base64(xml:get_cdata(Els)), + case cyrsasl:server_start(StateData#state.sasl_state, + Mech, + 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}; + {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_auth({xmlstreamend, Name}, StateData) -> + send_text(StateData#state.socket, ?STREAM_TRAILER), + {stop, normal, StateData}; + +wait_for_sasl_auth({xmlstreamerror, _}, StateData) -> + send_text(StateData#state.socket, ?INVALID_XML_ERR ++ ?STREAM_TRAILER), + {stop, normal, StateData}; + +wait_for_sasl_auth(closed, StateData) -> + {stop, normal, StateData}. + + +wait_for_resource_auth({xmlstreamelement, El}, StateData) -> + case is_auth_packet(El) of + {auth, ID, get, {"", _, _, _}} -> + Err = jlib:make_error_reply(El, "406", "Not Acceptable"), + send_element(StateData#state.socket, Err), + {next_state, wait_for_resource_auth, StateData}; + {auth, ID, get, {U, _, _, _}} -> + {xmlelement, Name, Attrs, Els} = jlib:make_result_iq_reply(El), + Res = {xmlelement, Name, Attrs, + [{xmlelement, "query", [{"xmlns", ?NS_AUTH}], + [{xmlelement, "username", [], + [{xmlcdata, StateData#state.user}]}, + {xmlelement, "resource", [], []} + ]}]}, + send_element(StateData#state.socket, Res), + {next_state, wait_for_resource_auth, StateData}; + {auth, ID, set, {U, _, _, ""}} -> + Err = jlib:make_error_reply(El, "406", "Not Acceptable"), + send_element(StateData#state.socket, Err), + {next_state, wait_for_resource_auth, StateData}; + {auth, ID, set, {U, _, _, R}} -> + case StateData#state.user of + U -> + io:format("SASLAUTH: ~p~n", [{U, R}]), + JID = {U, ?MYNAME, R}, + case acl:match_rule(StateData#state.access, JID) of + allow -> + ejabberd_sm:open_session(U, R), + Res = jlib:make_result_iq_reply(El), + send_element(StateData#state.socket, Res), + change_shaper(StateData, JID), + {Fs, Ts} = mod_roster:get_subscription_lists(U), + {next_state, session_established, + StateData#state{user = U, + resource = R, + pres_f = ?SETS:from_list(Fs), + pres_t = ?SETS:from_list(Ts)}}; + _ -> + Err = jlib:make_error_reply(El, ?ERR_NOT_ALLOWED), + send_element(StateData#state.socket, Err), + {next_state, wait_for_resource_auth, StateData} + end; + _ -> + Err = jlib:make_error_reply(El, "406", "Not Acceptable"), + send_element(StateData#state.socket, Err), + {next_state, wait_for_resource_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_resource_auth, StateData}; + _ -> + {next_state, wait_for_resource_auth, StateData} + end + end; + +wait_for_resource_auth({xmlstreamend, Name}, StateData) -> + send_text(StateData#state.socket, ?STREAM_TRAILER), + {stop, normal, StateData}; + +wait_for_resource_auth({xmlstreamerror, _}, StateData) -> + send_text(StateData#state.socket, ?INVALID_XML_ERR ++ ?STREAM_TRAILER), + {stop, normal, StateData}; + +wait_for_resource_auth(closed, StateData) -> + {stop, normal, StateData}. + + +% TODO: wait_for_sasl_response + + + session_established({xmlstreamelement, El}, StateData) -> {xmlelement, Name, Attrs, Els} = El, Server = StateData#state.server, @@ -227,7 +417,7 @@ session_established({xmlstreamend, Name}, StateData) -> {stop, normal, StateData}; session_established({xmlstreamerror, _}, StateData) -> - send_text(StateData#state.socket, ?INVALID_XML_ERR ?STREAM_TRAILER), + send_text(StateData#state.socket, ?INVALID_XML_ERR ++ ?STREAM_TRAILER), {stop, normal, StateData}; session_established(closed, StateData) -> @@ -427,7 +617,7 @@ is_auth_packet(El) -> case jlib:iq_query_info(El) of {iq, ID, Type, ?NS_AUTH, SubEl} -> {xmlelement, _, _, Els} = SubEl, - {auth, ID, + {auth, ID, Type, get_auth_tags(Els, "", "", "", "")}; _ -> false diff --git a/src/ejabberd_local.erl b/src/ejabberd_local.erl index f2b4de026..0a1b6f63a 100644 --- a/src/ejabberd_local.erl +++ b/src/ejabberd_local.erl @@ -18,6 +18,7 @@ ]). -include("ejabberd.hrl"). +-include("jlib.hrl"). -record(state, {mydomain, iqtable}). @@ -78,7 +79,7 @@ do_route(State, From, To, Packet) -> ok end; {"", _, _} -> - Err = jlib:make_error_reply(Packet, "404", "Not Found"), + Err = jlib:make_error_reply(Packet, ?ERR_JID_NOT_FOUND), ejabberd_router ! {route, {"", State#state.mydomain, ""}, From, Err}, ok; @@ -116,13 +117,12 @@ process_iq(State, From, To, Packet) -> Err} end; _ -> - % TODO ok end; reply -> ok; _ -> - Err = jlib:make_error_reply(Packet, "400", "Bad Request"), + Err = jlib:make_error_reply(Packet, ?ERR_BAD_REQUEST), ejabberd_router ! {route, {"", State#state.mydomain, ""}, From, Err}, ok diff --git a/src/jd2ejd.erl b/src/jd2ejd.erl index ac9f81be2..456fc0a65 100644 --- a/src/jd2ejd.erl +++ b/src/jd2ejd.erl @@ -29,7 +29,7 @@ terminate/3]). -include("ejabberd.hrl"). --include("namespaces.hrl"). +-include("jlib.hrl"). -record(state, {socket, pid, user = "", server = ?MYNAME, resource = "" diff --git a/src/jlib.erl b/src/jlib.erl index b9fb8b990..91fd5f076 100644 --- a/src/jlib.erl +++ b/src/jlib.erl @@ -12,6 +12,7 @@ -export([make_result_iq_reply/1, make_error_reply/3, + make_error_reply/2, make_error_element/2, make_correct_from_to_attrs/3, replace_from_to_attrs/3, @@ -29,9 +30,11 @@ iq_to_xml/1, parse_xdata_submit/1, timestamp_to_iso/1, - timestamp_to_xml/1]). + timestamp_to_xml/1, + decode_base64/1, + encode_base64/1]). --include("namespaces.hrl"). +-include("jlib.hrl"). %send_iq(From, To, ID, SubTags) -> % ok. @@ -67,6 +70,10 @@ make_error_reply({xmlelement, Name, Attrs, SubTags}, Code, Desc) -> [{"code", Code}], [{xmlcdata, Desc}]}]}. +make_error_reply({xmlelement, Name, Attrs, SubTags}, Error) -> + NewAttrs = make_error_reply_attrs(Attrs), + {xmlelement, Name, NewAttrs, SubTags ++ [Error]}. + make_error_reply_attrs(Attrs) -> To = xml:get_attr("to", Attrs), From = xml:get_attr("from", Attrs), @@ -362,3 +369,74 @@ timestamp_to_xml({{Year, Month, Day}, {Hour, Minute, Second}}) -> [Year, Month, Day, Hour, Minute, Second]))}], []}. + +% +% Base64 stuff (based on httpd_util.erl) +% + +decode_base64(S) -> + decode1_base64([C || C <- S, + C /= $ , + C /= $\t, + C /= $\n, + C /= $\r]). + +decode1_base64([]) -> + []; +decode1_base64([Sextet1,Sextet2,$=,$=|Rest]) -> + Bits2x6= + (d(Sextet1) bsl 18) bor + (d(Sextet2) bsl 12), + Octet1=Bits2x6 bsr 16, + [Octet1|decode_base64(Rest)]; +decode1_base64([Sextet1,Sextet2,Sextet3,$=|Rest]) -> + Bits3x6= + (d(Sextet1) bsl 18) bor + (d(Sextet2) bsl 12) bor + (d(Sextet3) bsl 6), + Octet1=Bits3x6 bsr 16, + Octet2=(Bits3x6 bsr 8) band 16#ff, + [Octet1,Octet2|decode_base64(Rest)]; +decode1_base64([Sextet1,Sextet2,Sextet3,Sextet4|Rest]) -> + Bits4x6= + (d(Sextet1) bsl 18) bor + (d(Sextet2) bsl 12) bor + (d(Sextet3) bsl 6) bor + d(Sextet4), + Octet1=Bits4x6 bsr 16, + Octet2=(Bits4x6 bsr 8) band 16#ff, + Octet3=Bits4x6 band 16#ff, + [Octet1,Octet2,Octet3|decode_base64(Rest)]; +decode1_base64(CatchAll) -> + "". + +d(X) when X >= $A, X =<$Z -> + X-65; +d(X) when X >= $a, X =<$z -> + X-71; +d(X) when X >= $0, X =<$9 -> + X+4; +d($+) -> 62; +d($/) -> 63; +d(_) -> 63. + + +encode_base64([]) -> + []; +encode_base64([A]) -> + [e(A bsr 2), e((A band 3) bsl 4), $=, $=]; +encode_base64([A,B]) -> + [e(A bsr 2), e(((A band 3) bsl 4) bor (B bsr 4)), e((B band 15) bsl 2), $=]; +encode_base64([A,B,C|Ls]) -> + encode_base64_do(A,B,C, Ls). +encode_base64_do(A,B,C, Rest) -> + BB = (A bsl 16) bor (B bsl 8) bor C, + [e(BB bsr 18), e((BB bsr 12) band 63), + e((BB bsr 6) band 63), e(BB band 63)|encode_base64(Rest)]. + +e(X) when X >= 0, X < 26 -> X+65; +e(X) when X>25, X<52 -> X+71; +e(X) when X>51, X<62 -> X-4; +e(62) -> $+; +e(63) -> $/; +e(X) -> exit({bad_encode_base64_token, X}). diff --git a/src/mod_configure.erl b/src/mod_configure.erl index 248c9e3b6..71ee8f523 100644 --- a/src/mod_configure.erl +++ b/src/mod_configure.erl @@ -18,7 +18,7 @@ process_sm_iq/3]). -include("ejabberd.hrl"). --include("namespaces.hrl"). +-include("jlib.hrl"). start(Opts) -> @@ -37,9 +37,7 @@ stop() -> process_local_iq(From, To, {iq, ID, Type, XMLNS, SubEl}) -> case acl:match_rule(configure, From) of deny -> - {iq, ID, error, XMLNS, [SubEl, {xmlelement, "error", - [{"code", "405"}], - [{xmlcdata, "Not Allowed"}]}]}; + {iq, ID, error, XMLNS, [SubEl, ?ERR_NOT_ALLOWED]}; allow -> Lang = xml:get_tag_attr_s("xml:lang", SubEl), case Type of @@ -68,11 +66,9 @@ process_local_iq(From, To, {iq, ID, Type, XMLNS, SubEl}) -> [{"xmlns", XMLNS}], Res }]}; - {error, Code, Desc} -> + {error, Error} -> {iq, ID, error, XMLNS, - [SubEl, {xmlelement, "error", - [{"code", Code}], - [{xmlcdata, Desc}]}]} + [SubEl, Error]} end end; _ -> @@ -90,11 +86,9 @@ process_local_iq(From, To, {iq, ID, Type, XMLNS, SubEl}) -> [{xmlelement, "query", [{"xmlns", XMLNS}], Res }]}; - {error, Code, Desc} -> + {error, Error} -> {iq, ID, error, XMLNS, - [SubEl, {xmlelement, "error", - [{"code", Code}], - [{xmlcdata, Desc}]}]} + [SubEl, Error]} end end end. @@ -140,7 +134,7 @@ get_form(["running nodes", ENode, "DB"], Lang) -> Node -> case rpc:call(Node, mnesia, system_info, [tables]) of {badrpc, Reason} -> - {error, "500", "Internal Server Error"}; + {error, ?ERR_INTERNAL_SERVER_ERROR}; Tables -> STables = lists:sort(Tables), {result, [{xmlelement, "title", [], @@ -174,7 +168,7 @@ get_form(["running nodes", ENode, "modules", "stop"], Lang) -> Node -> case rpc:call(Node, gen_mod, loaded_modules, []) of {badrpc, Reason} -> - {error, "500", "Internal Server Error"}; + {error, ?ERR_INTERNAL_SERVER_ERROR}; Modules -> SModules = lists:sort(Modules), {result, [{xmlelement, "title", [], @@ -390,7 +384,7 @@ get_form(["config", "remusers"], Lang) -> }; get_form(_, Lang) -> - {error, "503", "Service Unavailable"}. + {error, ?ERR_SERVICE_UNAVAILABLE}. @@ -493,9 +487,9 @@ set_form(["running nodes", ENode, "backup", "backup"], Lang, XData) -> {value, {_, [String]}} -> case rpc:call(Node, mnesia, backup, [String]) of {badrpc, Reason} -> - {error, "500", "Internal Server Error"}; + {error, ?ERR_INTERNAL_SERVER_ERROR}; {error, Reason} -> - {error, "500", "Internal Server Error"}; + {error, ?ERR_INTERNAL_SERVER_ERROR}; _ -> {result, []} end; @@ -517,9 +511,9 @@ set_form(["running nodes", ENode, "backup", "restore"], Lang, XData) -> case rpc:call(Node, mnesia, restore, [String, [{default_op, keep_tables}]]) of {badrpc, Reason} -> - {error, "500", "Internal Server Error"}; + {error, ?ERR_INTERNAL_SERVER_ERROR}; {error, Reason} -> - {error, "500", "Internal Server Error"}; + {error, ?ERR_INTERNAL_SERVER_ERROR}; _ -> {result, []} end; @@ -540,9 +534,9 @@ set_form(["running nodes", ENode, "backup", "textfile"], Lang, XData) -> {value, {_, [String]}} -> case rpc:call(Node, mnesia, dump_to_textfile, [String]) of {badrpc, Reason} -> - {error, "500", "Internal Server Error"}; + {error, ?ERR_INTERNAL_SERVER_ERROR}; {error, Reason} -> - {error, "500", "Internal Server Error"}; + {error, ?ERR_INTERNAL_SERVER_ERROR}; _ -> {result, []} end; @@ -689,7 +683,7 @@ set_form(["config", "remusers"], Lang, XData) -> {result, []}; set_form(_, Lang, XData) -> - {error, "503", "Service Unavailable"}. + {error, ?ERR_SERVICE_UNAVAILABLE}. @@ -744,11 +738,9 @@ process_sm_iq(From, To, {iq, ID, Type, XMLNS, SubEl}) -> [{"xmlns", XMLNS}], Res }]}; - {error, Code, Desc} -> + {error, Error} -> {iq, ID, error, XMLNS, - [SubEl, {xmlelement, "error", - [{"code", Code}], - [{xmlcdata, Desc}]}]} + [SubEl, Error]} end end; _ -> @@ -766,11 +758,9 @@ process_sm_iq(From, To, {iq, ID, Type, XMLNS, SubEl}) -> [{xmlelement, "query", [{"xmlns", XMLNS}], Res }]}; - {error, Code, Desc} -> + {error, Error} -> {iq, ID, error, XMLNS, - [SubEl, {xmlelement, "error", - [{"code", Code}], - [{xmlcdata, Desc}]}]} + [SubEl, Error]} end end end. @@ -807,8 +797,8 @@ get_sm_form(User, [], Lang) -> ]}; get_sm_form(_, _, Lang) -> - {error, "503", "Service Unavailable"}. + {error, ?ERR_SERVICE_UNAVAILABLE}. set_sm_form(_, _, Lang, XData) -> - {error, "503", "Service Unavailable"}. + {error, ?ERR_SERVICE_UNAVAILABLE}. diff --git a/src/mod_disco.erl b/src/mod_disco.erl index ec8887276..153ca8ab3 100644 --- a/src/mod_disco.erl +++ b/src/mod_disco.erl @@ -22,7 +22,7 @@ unregister_feature/1]). -include("ejabberd.hrl"). --include("namespaces.hrl"). +-include("jlib.hrl"). -define(EMPTY_INFO_RESULT, {iq, ID, result, XMLNS, [{xmlelement, "query", @@ -62,9 +62,7 @@ process_local_iq_items(From, To, {iq, ID, Type, XMLNS, SubEl}) -> Lang = xml:get_tag_attr_s("xml:lang", SubEl), case Type of set -> - {iq, ID, error, XMLNS, [SubEl, {xmlelement, "error", - [{"code", "405"}], - [{xmlcdata, "Not Allowed"}]}]}; + {iq, ID, error, XMLNS, [SubEl, ?ERR_NOT_ALLOWED]}; get -> Node = string:tokens(xml:get_tag_attr_s("node", SubEl), "/"), @@ -74,11 +72,9 @@ process_local_iq_items(From, To, {iq, ID, Type, XMLNS, SubEl}) -> [{xmlelement, "query", [{"xmlns", ?NS_DISCO_ITEMS}], Res }]}; - {error, Code, Desc} -> + {error, Error} -> {iq, ID, error, XMLNS, - [SubEl, {xmlelement, "error", - [{"code", Code}], - [{xmlcdata, Desc}]}]} + [SubEl, Error]} end end. @@ -86,9 +82,7 @@ process_local_iq_items(From, To, {iq, ID, Type, XMLNS, SubEl}) -> process_local_iq_info(From, To, {iq, ID, Type, XMLNS, SubEl}) -> case Type of set -> - {iq, ID, error, XMLNS, [SubEl, {xmlelement, "error", - [{"code", "405"}], - [{xmlcdata, "Not Allowed"}]}]}; + {iq, ID, error, XMLNS, [SubEl, ?ERR_NOT_ALLOWED]}; get -> case string:tokens(xml:get_tag_attr_s("node", SubEl), "/") of [] -> @@ -149,9 +143,7 @@ process_local_iq_info(From, To, {iq, ID, Type, XMLNS, SubEl}) -> [feature_to_xml({?NS_IQDATA})]}]}; _ -> {iq, ID, error, XMLNS, - [SubEl, {xmlelement, "error", - [{"code", "501"}], - [{xmlcdata, "Not Implemented"}]}]} + [SubEl, ?ERR_FEATURE_NOT_IMPLEMENTED]} end end. @@ -204,7 +196,7 @@ get_local_items(["all users"], Server, Lang) -> get_local_items(["all users", [$@ | Diap]], Server, Lang) -> case catch ejabberd_auth:dirty_get_registered_users() of {'EXIT', Reason} -> - {error, "500", "Internal Server Error"}; + ?ERR_INTERNAL_SERVER_ERROR; Users -> SUsers = lists:sort(Users), case catch begin @@ -219,7 +211,8 @@ get_local_items(["all users", [$@ | Diap]], Server, Lang) -> end, Sub) end of {'EXIT', Reason} -> - {error, "406", "Not Acceptable"}; + % TODO: must be "not acceptable" + ?ERR_BAD_REQUEST; Res -> {result, Res} end @@ -279,7 +272,7 @@ get_local_items(["running nodes", ENode, "import", _], Server, Lang) -> {result, []}; get_local_items(_, _, _) -> - {error, "501", "Not Implemented"}. + {error, ?ERR_FEATURE_NOT_IMPLEMENTED}. @@ -413,9 +406,7 @@ process_sm_iq_items(From, To, {iq, ID, Type, XMLNS, SubEl}) -> {User, _, _} = To, case Type of set -> - {iq, ID, error, XMLNS, [SubEl, {xmlelement, "error", - [{"code", "405"}], - [{xmlcdata, "Not Allowed"}]}]}; + {iq, ID, error, XMLNS, [SubEl, ?ERR_NOT_ALLOWED]}; get -> case xml:get_tag_attr_s("node", SubEl) of "" -> @@ -425,9 +416,7 @@ process_sm_iq_items(From, To, {iq, ID, Type, XMLNS, SubEl}) -> }]}; _ -> {iq, ID, error, XMLNS, - [SubEl, {xmlelement, "error", - [{"code", "501"}], - [{xmlcdata, "Not Implemented"}]}]} + [SubEl, ?ERR_FEATURE_NOT_IMPLEMENTED]} end end. @@ -435,9 +424,7 @@ process_sm_iq_items(From, To, {iq, ID, Type, XMLNS, SubEl}) -> process_sm_iq_info(From, To, {iq, ID, Type, XMLNS, SubEl}) -> case Type of set -> - {iq, ID, error, XMLNS, [SubEl, {xmlelement, "error", - [{"code", "405"}], - [{xmlcdata, "Not Allowed"}]}]}; + {iq, ID, error, XMLNS, [SubEl, ?ERR_NOT_ALLOWED]}; get -> case xml:get_tag_attr_s("node", SubEl) of "" -> @@ -446,9 +433,7 @@ process_sm_iq_info(From, To, {iq, ID, Type, XMLNS, SubEl}) -> [feature_to_xml({?NS_IQDATA})]}]}; _ -> {iq, ID, error, XMLNS, - [SubEl, {xmlelement, "error", - [{"code", "501"}], - [{xmlcdata, "Not Implemented"}]}]} + [SubEl, ?ERR_FEATURE_NOT_IMPLEMENTED]} end end. diff --git a/src/mod_echo.erl b/src/mod_echo.erl index 5f02c4002..1b6143a53 100644 --- a/src/mod_echo.erl +++ b/src/mod_echo.erl @@ -15,7 +15,7 @@ -export([start/1, init/1, stop/0]). -include("ejabberd.hrl"). --include("namespaces.hrl"). +-include("jlib.hrl"). diff --git a/src/mod_irc/mod_irc.erl b/src/mod_irc/mod_irc.erl index bd3e69854..f2181ca3e 100644 --- a/src/mod_irc/mod_irc.erl +++ b/src/mod_irc/mod_irc.erl @@ -16,7 +16,7 @@ get_user_and_encoding/2]). -include("ejabberd.hrl"). --include("namespaces.hrl"). +-include("jlib.hrl"). -define(DEFAULT_IRC_ENCODING, "koi8-r"). @@ -200,18 +200,14 @@ process_iq_data(From, To, ID, XMLNS, Type, SubEl) -> [{"xmlns", XMLNS}], Res }]}; - {error, Code, Desc} -> + {error, Error} -> {iq, ID, error, XMLNS, - [SubEl, {xmlelement, "error", - [{"code", Code}], - [{xmlcdata, Desc}]}]} + [SubEl, Error]} end end; _ -> {iq, ID, error, XMLNS, - [SubEl, {xmlelement, "error", - [{"code", "405"}], - [{xmlcdata, "Not Allowed"}]}]} + [SubEl, ?ERR_NOT_ALLOWED]} end; get -> Node = @@ -222,11 +218,9 @@ process_iq_data(From, To, ID, XMLNS, Type, SubEl) -> [{xmlelement, "query", [{"xmlns", XMLNS}], Res }]}; - {error, Code, Desc} -> + {error, Error} -> {iq, ID, error, XMLNS, - [SubEl, {xmlelement, "error", - [{"code", Code}], - [{xmlcdata, Desc}]}]} + [SubEl, Error]} end end. @@ -238,7 +232,7 @@ get_form(From, [], Lang) -> Customs = case catch mnesia:dirty_read({irc_custom, {LUser, LServer}}) of {'EXIT', Reason} -> - {error, "500", "Internal Server Error"}; + {error, ?ERR_INTERNAL_SERVER_ERROR}; [] -> {User, []}; [#irc_custom{data = Data}] -> @@ -302,7 +296,7 @@ get_form(From, [], Lang) -> get_form(_, _, Lang) -> - {error, "503", "Service Unavailable"}. + {error, ?ERR_SERVICE_UNAVAILABLE}. @@ -347,7 +341,7 @@ set_form(From, [], Lang, XData) -> set_form(_, _, Lang, XData) -> - {error, "503", "Service Unavailable"}. + {error, ?ERR_SERVICE_UNAVAILABLE}. get_user_and_encoding(From, IRCServer) -> diff --git a/src/mod_irc/mod_irc_connection.erl b/src/mod_irc/mod_irc_connection.erl index 172c823a3..b261ae33c 100644 --- a/src/mod_irc/mod_irc_connection.erl +++ b/src/mod_irc/mod_irc_connection.erl @@ -27,7 +27,7 @@ code_change/4]). -include("ejabberd.hrl"). --include("namespaces.hrl"). +-include("jlib.hrl"). -define(SETS, gb_sets). @@ -285,7 +285,7 @@ handle_info({route_chan, Channel, Resource, ID, XMLNS, Type, SubEl); _ -> Err = jlib:make_error_reply( - El, "503", "Service Unavailable"), + El, ?ERR_SERVICE_UNAVAILABLE), ejabberd_router:route(To, From, Err) end, {next_state, StateName, StateData}; @@ -835,11 +835,9 @@ iq_admin(StateData, Channel, From, To, ID, XMLNS, Type, SubEl) -> [{"xmlns", XMLNS}], ResEls }]}; - {error, Code, Desc} -> + {error, Error} -> {iq, ID, error, XMLNS, - [SubEl, {xmlelement, "error", - [{"code", Code}], - [{xmlcdata, Desc}]}]} + [SubEl, Error]} end, ejabberd_router:route(To, From, jlib:iq_to_xml(ResIQ)); @@ -852,7 +850,7 @@ iq_admin(StateData, Channel, From, To, ID, XMLNS, Type, SubEl) -> process_iq_admin(StateData, Channel, set, SubEl) -> case xml:get_subtag(SubEl, "item") of false -> - {error, "400", "Bad Request"}; + {error, ?ERR_BAD_REQUEST}; ItemEl -> Nick = xml:get_tag_attr_s("nick", ItemEl), Affiliation = xml:get_tag_attr_s("affiliation", ItemEl), @@ -861,12 +859,12 @@ process_iq_admin(StateData, Channel, set, SubEl) -> process_admin(StateData, Channel, Nick, Affiliation, Role, Reason) end; process_iq_admin(StateData, Channel, get, SubEl) -> - {error, "501", "Not Implemented"}. + {error, ?ERR_FEATURE_NOT_IMPLEMENTED}. process_admin(StateData, Channel, "", Affiliation, Role, Reason) -> - {error, "501", "Not Implemented"}; + {error, ?ERR_FEATURE_NOT_IMPLEMENTED}; process_admin(StateData, Channel, Nick, Affiliation, "none", Reason) -> case Reason of @@ -884,7 +882,7 @@ process_admin(StateData, Channel, Nick, Affiliation, "none", Reason) -> process_admin(StateData, Channel, Nick, Affiliation, Role, Reason) -> - {error, "501", "Not Implemented"}. + {error, ?ERR_FEATURE_NOT_IMPLEMENTED}. diff --git a/src/mod_offline.erl b/src/mod_offline.erl index e85c9488e..bdddf8e69 100644 --- a/src/mod_offline.erl +++ b/src/mod_offline.erl @@ -18,7 +18,7 @@ resend_offline_messages/1, remove_user/1]). --include("namespaces.hrl"). +-include("jlib.hrl"). -record(offline_msg, {user, timestamp, from, to, packet}). diff --git a/src/mod_private.erl b/src/mod_private.erl index d265088d0..54eb8c05b 100644 --- a/src/mod_private.erl +++ b/src/mod_private.erl @@ -17,7 +17,7 @@ process_local_iq/3]). -include("ejabberd.hrl"). --include("namespaces.hrl"). +-include("jlib.hrl"). -record(private_storage, {userns, xml}). diff --git a/src/mod_register.erl b/src/mod_register.erl index c585cb715..febc58dd6 100644 --- a/src/mod_register.erl +++ b/src/mod_register.erl @@ -15,7 +15,7 @@ -export([start/1, init/0, process_iq/3]). -include("ejabberd.hrl"). --include("namespaces.hrl"). +-include("jlib.hrl"). start(Opts) -> IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), @@ -97,12 +97,9 @@ process_iq(From, To, {iq, ID, Type, XMLNS, SubEl}) -> case try_register(User, Password) of ok -> {iq, ID, result, XMLNS, [SubEl]}; - {error, Code, Reason} -> + {error, Error} -> {iq, ID, error, XMLNS, - [SubEl, {xmlelement, - "error", - [{"code", Code}], - [{xmlcdata, Reason}]}]} + [SubEl, Error]} end end end; @@ -128,9 +125,9 @@ try_register(User, Password) -> {atomic, ok} -> ok; {atomic, exists} -> - {error, "400", "Bad Request"}; + {error, ?ERR_BAD_REQUEST}; {error, Reason} -> - {error, "500", "Internal Server Error"} + {error, ?ERR_INTERNAL_SERVER_ERROR} end end. diff --git a/src/mod_roster.erl b/src/mod_roster.erl index dda0e988a..38b6e36aa 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -23,7 +23,7 @@ -include_lib("mnemosyne/include/mnemosyne.hrl"). -include("ejabberd.hrl"). --include("namespaces.hrl"). +-include("jlib.hrl"). -record(roster, {uj, user, diff --git a/src/mod_stats.erl b/src/mod_stats.erl index ff5b65369..c2f432c1c 100644 --- a/src/mod_stats.erl +++ b/src/mod_stats.erl @@ -16,7 +16,7 @@ stop/0, process_local_iq/3]). --include("namespaces.hrl"). +-include("jlib.hrl"). start(Opts) -> IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), @@ -43,11 +43,9 @@ process_local_iq(From, To, {iq, ID, Type, XMLNS, SubEl}) -> {result, Res} -> {iq, ID, result, XMLNS, [{xmlelement, "query", [{"xmlns", XMLNS}], Res}]}; - {error, Code, Desc} -> + {error, Error} -> {iq, ID, error, XMLNS, - [SubEl, {xmlelement, "error", - [{"code", Code}], - [{xmlcdata, Desc}]}]} + [SubEl, Error]} end end. @@ -98,7 +96,7 @@ get_local_stats(["running nodes", ENode], Names) -> end; get_local_stats(_, _) -> - {error, "501", "Not Implemented"}. + {error, ?ERR_FEATURE_NOT_IMPLEMENTED}. diff --git a/src/mod_time.erl b/src/mod_time.erl index a9959398f..36c190774 100644 --- a/src/mod_time.erl +++ b/src/mod_time.erl @@ -17,7 +17,7 @@ process_local_iq/3]). -include("ejabberd.hrl"). --include("namespaces.hrl"). +-include("jlib.hrl"). start(Opts) -> diff --git a/src/mod_vcard.erl b/src/mod_vcard.erl index b41b21011..409c77b93 100644 --- a/src/mod_vcard.erl +++ b/src/mod_vcard.erl @@ -19,7 +19,7 @@ remove_user/1]). -include("ejabberd.hrl"). --include("namespaces.hrl"). +-include("jlib.hrl"). -record(vcard_search, {user, luser, diff --git a/src/mod_version.erl b/src/mod_version.erl index a00d4a08a..53c3a7535 100644 --- a/src/mod_version.erl +++ b/src/mod_version.erl @@ -17,7 +17,7 @@ process_local_iq/3]). -include("ejabberd.hrl"). --include("namespaces.hrl"). +-include("jlib.hrl"). |