aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexey Shchepin <alexey@process-one.net>2003-06-07 17:30:25 +0000
committerAlexey Shchepin <alexey@process-one.net>2003-06-07 17:30:25 +0000
commitbc7333721419bbdd5a3288b8702b786242f8eabe (patch)
tree45a95639508330ba41e0a75ba40320470b9290f3
parent* src/msgs/fr.msg: New french translation (thanks to Vincent Ricard) (diff)
* src/ejabberd_c2s.erl: SASL support updated to xmpp-core-13
* src/cyrsasl*.erl: Support for authzid SVN Revision: 114
-rw-r--r--ChangeLog8
-rw-r--r--src/cyrsasl.erl39
-rw-r--r--src/cyrsasl_digest.erl41
-rw-r--r--src/cyrsasl_plain.erl8
-rw-r--r--src/ejabberd_c2s.erl206
-rw-r--r--src/jlib.hrl3
6 files changed, 176 insertions, 129 deletions
diff --git a/ChangeLog b/ChangeLog
index 3481b35e9..71b8021e6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2003-06-07 Alexey Shchepin <alexey@sevcom.net>
+
+ * src/ejabberd_c2s.erl: SASL support updated to xmpp-core-13
+
+2003-06-06 Alexey Shchepin <alexey@sevcom.net>
+
+ * src/cyrsasl*.erl: Support for authzid
+
2003-06-03 Alexey Shchepin <alexey@sevcom.net>
* src/msgs/fr.msg: New french translation (thanks to Vincent Ricard)
diff --git a/src/cyrsasl.erl b/src/cyrsasl.erl
index bc6a80be9..b87133621 100644
--- a/src/cyrsasl.erl
+++ b/src/cyrsasl.erl
@@ -40,6 +40,30 @@ register_mechanism(Mechanism, Module) ->
ets:insert(sasl_mechanism, #sasl_mechanism{mechanism = Mechanism,
module = Module}).
+% TODO: use callbacks
+-include("ejabberd.hrl").
+-include("jlib.hrl").
+check_authzid(State, Props) ->
+ AuthzId = xml:get_attr_s(authzid, Props),
+ case jlib:string_to_jid(AuthzId) of
+ error ->
+ {error, "invalid-authzid"};
+ JID ->
+ LUser = xml:get_attr_s(username, Props),
+ {U, S, R} = jlib:jid_tolower(JID),
+ case R of
+ "" ->
+ {error, "invalid-authzid"};
+ _ ->
+ case {LUser, ?MYNAME} of
+ {U, S} ->
+ ok;
+ _ ->
+ {error, "invalid-authzid"}
+ end
+ end
+ end.
+
listmech() ->
ets:select(sasl_mechanism,
[{#sasl_mechanism{mechanism = '$1', _ = '_'}, [], ['$1']}]).
@@ -58,7 +82,7 @@ server_start(State, Mech, ClientIn) ->
mech_state = MechState},
ClientIn);
_ ->
- {error, "454"}
+ {error, "no-mechanism"}
end.
server_step(State, ClientIn) ->
@@ -66,13 +90,16 @@ server_step(State, ClientIn) ->
MechState = State#sasl_state.mech_state,
case Module:mech_step(MechState, ClientIn) of
{ok, Props} ->
- {ok, Props};
+ case check_authzid(State, Props) of
+ ok ->
+ {ok, Props};
+ {error, Error} ->
+ {error, Error}
+ end;
{continue, ServerOut, NewMechState} ->
{continue, ServerOut,
State#sasl_state{mech_state = NewMechState}};
- {error, Code} ->
- {error, Code}
+ {error, Error} ->
+ {error, Error}
end.
-
-
diff --git a/src/cyrsasl_digest.erl b/src/cyrsasl_digest.erl
index c4593c36d..b9f0730d0 100644
--- a/src/cyrsasl_digest.erl
+++ b/src/cyrsasl_digest.erl
@@ -18,7 +18,7 @@
-behaviour(cyrsasl).
%-behaviour(gen_mod).
--record(state, {step, nonce, username}).
+-record(state, {step, nonce, username, authzid}).
start(Opts) ->
cyrsasl:register_mechanism("DIGEST-MD5", ?MODULE),
@@ -39,31 +39,38 @@ mech_step(#state{step = 1, nonce = Nonce} = State, "") ->
mech_step(#state{step = 3, nonce = Nonce} = State, ClientIn) ->
case parse(ClientIn) of
bad ->
- {error, "454"};
+ {error, "bad-protocol"};
KeyVals ->
UserName = xml:get_attr_s("username", KeyVals),
+ AuthzId = xml:get_attr_s("authzid", KeyVals),
case ejabberd_auth:get_password(UserName) of
false ->
- {error, "454"};
+ {error, "no-user"};
Passwd ->
- Response = response(KeyVals, UserName, Passwd,
+ Response = response(KeyVals, UserName, Passwd, AuthzId,
"AUTHENTICATE"),
case xml:get_attr_s("response", KeyVals) of
Response ->
- RspAuth = response(KeyVals, UserName, Passwd, ""),
+ RspAuth = response(KeyVals,
+ UserName, Passwd,
+ AuthzId, ""),
{continue,
"rspauth=" ++ RspAuth,
- State#state{step = 5, username = UserName}};
+ State#state{step = 5,
+ username = UserName,
+ authzid = AuthzId}};
_ ->
- {error, "454"}
+ {error, "bad-auth"}
end
end
end;
-mech_step(#state{step = 5, username = UserName} = State, "") ->
- {ok, [{username, UserName}]};
+mech_step(#state{step = 5,
+ username = UserName,
+ authzid = AuthzId} = State, "") ->
+ {ok, [{username, UserName}, {authzid, AuthzId}]};
mech_step(A, B) ->
io:format("SASL DIGEST: A ~p B ~p", [A,B]),
- {error, "454"}.
+ {error, "bad-protocol"}.
parse(S) ->
@@ -119,15 +126,23 @@ hex([N | Ns], Res) ->
digit_to_xchar(N div 16) | Res]).
-response(KeyVals, User, Passwd, A2Prefix) ->
+response(KeyVals, User, Passwd, AuthzId, 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,
+ A1 = case AuthzId of
+ "" ->
+ binary_to_list(
+ crypto:md5(User ++ ":" ++ Realm ++ ":" ++ Passwd)) ++
+ ":" ++ Nonce ++ ":" ++ CNonce;
+ _ ->
+ binary_to_list(
+ crypto:md5(User ++ ":" ++ Realm ++ ":" ++ Passwd)) ++
+ ":" ++ Nonce ++ ":" ++ CNonce ++ ":" ++ AuthzId
+ end,
case QOP of
"auth" ->
A2 = A2Prefix ++ ":" ++ DigestURI;
diff --git a/src/cyrsasl_plain.erl b/src/cyrsasl_plain.erl
index 46461e1c0..71e4a6baf 100644
--- a/src/cyrsasl_plain.erl
+++ b/src/cyrsasl_plain.erl
@@ -27,15 +27,15 @@ mech_new() ->
mech_step(State, ClientIn) ->
case parse(ClientIn) of
- [_, User, Password] ->
+ [AuthzId, User, Password] ->
case ejabberd_auth:check_password(User, Password) of
true ->
- {ok, [{username, User}]};
+ {ok, [{username, User}, {authzid, AuthzId}]};
_ ->
- {error, "454"}
+ {error, "bad-auth"}
end;
_ ->
- {error, "454"}
+ {error, "bad-protocol"}
end.
diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl
index 23b350d63..fb6bec275 100644
--- a/src/ejabberd_c2s.erl
+++ b/src/ejabberd_c2s.erl
@@ -20,7 +20,7 @@
wait_for_stream/2,
wait_for_auth/2,
wait_for_sasl_auth/2,
- wait_for_resource_auth/2,
+ wait_for_session/2,
wait_for_sasl_response/2,
session_established/2,
handle_event/3,
@@ -40,6 +40,7 @@
sasl_state,
access,
shaper,
+ authentificated = false,
user = "", server = ?MYNAME, resource = "",
pres_t = ?SETS:new(),
pres_f = ?SETS:new(),
@@ -129,13 +130,18 @@ wait_for_stream({xmlstreamstart, Name, Attrs}, StateData) ->
{xmlelement, "mechanism", [],
[{xmlcdata, S}]}
end, cyrsasl:listmech()),
- send_element(StateData,
- {xmlelement, "stream:features", [],
- [{xmlelement, "mechanisms",
- [{"xmlns", ?NS_SASL_MECHANISMS}],
- Mechs}]}),
- {next_state, wait_for_sasl_auth,
- StateData#state{sasl_state = SASLState}};
+ case StateData#state.authentificated of
+ false ->
+ send_element(StateData,
+ {xmlelement, "stream:features", [],
+ [{xmlelement, "mechanisms",
+ [{"xmlns", ?NS_SASL}],
+ Mechs}]}),
+ {next_state, wait_for_sasl_auth,
+ StateData#state{sasl_state = SASLState}};
+ _ ->
+ {next_state, wait_for_session, StateData}
+ end;
_ ->
Header = io_lib:format(
?STREAM_HEADER,
@@ -245,32 +251,37 @@ wait_for_auth(closed, 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"} ->
+ {?NS_SASL, "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} ->
+ StateData#state.receiver ! reset_stream,
send_element(StateData,
{xmlelement, "success",
- [{"xmlns", ?NS_SASL_MECHANISMS}], []}),
- {next_state, wait_for_resource_auth,
- StateData#state{user = xml:get_attr_s(username, Props)}};
+ [{"xmlns", ?NS_SASL}], []}),
+ {U, _, R} = jlib:string_to_jid(
+ xml:get_attr_s(authzid, Props)),
+ {next_state, wait_for_stream,
+ StateData#state{authentificated = true,
+ user = U,
+ resource = R
+ }};
{continue, ServerOut, NewSASLState} ->
send_element(StateData,
{xmlelement, "challenge",
- [{"xmlns", ?NS_SASL_MECHANISMS}],
+ [{"xmlns", ?NS_SASL}],
[{xmlcdata,
jlib:encode_base64(ServerOut)}]}),
{next_state, wait_for_sasl_response,
StateData#state{sasl_state = NewSASLState}};
- {error, Code} ->
+ {error, Error} ->
send_element(StateData,
{xmlelement, "failure",
- [{"xmlns", ?NS_SASL_MECHANISMS},
- {"code", Code}],
- []}),
+ [{"xmlns", ?NS_SASL}],
+ [{xmlelement, Error, [], []}]}),
{next_state, wait_for_sasl_auth, StateData}
end;
_ ->
@@ -302,110 +313,38 @@ 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, ?ERR_BAD_REQUEST),
- send_element(StateData, 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, Res),
- {next_state, wait_for_resource_auth, StateData};
- {auth, ID, set, {U, _, _, ""}} ->
- Err = jlib:make_error_reply(El, ?ERR_AUTH_NO_RESOURCE_PROVIDED),
- send_element(StateData, 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, 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, Err),
- {next_state, wait_for_resource_auth, StateData}
- end;
- _ ->
- Err = jlib:make_error_reply(El, ?ERR_BAD_REQUEST),
- send_element(StateData, 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, 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, ?STREAM_TRAILER),
- {stop, normal, StateData};
-
-wait_for_resource_auth({xmlstreamerror, _}, StateData) ->
- send_text(StateData, ?INVALID_XML_ERR ++ ?STREAM_TRAILER),
- {stop, normal, StateData};
-
-wait_for_resource_auth(closed, StateData) ->
- {stop, normal, StateData}.
-
-
-% TODO: wait_for_sasl_response
wait_for_sasl_response({xmlstreamelement, El}, StateData) ->
{xmlelement, Name, Attrs, Els} = El,
case {xml:get_attr_s("xmlns", Attrs), Name} of
- {?NS_SASL_MECHANISMS, "response"} ->
+ {?NS_SASL, "response"} ->
ClientIn = jlib:decode_base64(xml:get_cdata(Els)),
case cyrsasl:server_step(StateData#state.sasl_state,
ClientIn) of
{ok, Props} ->
+ StateData#state.receiver ! reset_stream,
send_element(StateData,
{xmlelement, "success",
- [{"xmlns", ?NS_SASL_MECHANISMS}], []}),
- {next_state, wait_for_resource_auth,
- StateData#state{user = xml:get_attr_s(username, Props)}};
+ [{"xmlns", ?NS_SASL}], []}),
+ {U, _, R} = jlib:string_to_jid(
+ xml:get_attr_s(authzid, Props)),
+ {next_state, wait_for_stream,
+ StateData#state{authentificated = true,
+ user = U,
+ resource = R
+ }};
{continue, ServerOut, NewSASLState} ->
send_element(StateData,
{xmlelement, "challenge",
- [{"xmlns", ?NS_SASL_MECHANISMS}],
+ [{"xmlns", ?NS_SASL}],
[{xmlcdata,
jlib:encode_base64(ServerOut)}]}),
{next_state, wait_for_sasl_response,
StateData#state{sasl_state = NewSASLState}};
- {error, Code} ->
+ {error, Error} ->
send_element(StateData,
{xmlelement, "failure",
- [{"xmlns", ?NS_SASL_MECHANISMS},
- {"code", Code}],
- []}),
+ [{"xmlns", ?NS_SASL}],
+ [{xmlelement, Error, [], []}]}),
{next_state, wait_for_sasl_auth, StateData}
end;
_ ->
@@ -438,6 +377,56 @@ wait_for_sasl_response(closed, StateData) ->
+wait_for_session({xmlstreamelement, El}, StateData) ->
+ case jlib:iq_query_info(El) of
+ {iq, ID, set, ?NS_SESSION, SubEl} ->
+ U = StateData#state.user,
+ R = StateData#state.resource,
+ 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, Res),
+ change_shaper(StateData, JID),
+ {Fs, Ts} = mod_roster:get_subscription_lists(U),
+ {next_state, session_established,
+ StateData#state{pres_f = ?SETS:from_list(Fs),
+ pres_t = ?SETS:from_list(Ts)}};
+ _ ->
+ Err = jlib:make_error_reply(El, ?ERR_NOT_ALLOWED),
+ send_element(StateData, Err),
+ {next_state, wait_for_session, StateData}
+ end;
+ % TODO: is this needed?
+ {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, Res),
+ {next_state, wait_for_session, StateData};
+ _ ->
+ {next_state, wait_for_session, StateData}
+ end;
+
+wait_for_session({xmlstreamend, Name}, StateData) ->
+ send_text(StateData, ?STREAM_TRAILER),
+ {stop, normal, StateData};
+
+wait_for_session({xmlstreamerror, _}, StateData) ->
+ send_text(StateData, ?INVALID_XML_ERR ++ ?STREAM_TRAILER),
+ {stop, normal, StateData};
+
+wait_for_session(closed, StateData) ->
+ {stop, normal, StateData}.
+
+
+
session_established({xmlstreamelement, El}, StateData) ->
{xmlelement, Name, Attrs, Els} = El,
@@ -659,8 +648,15 @@ receiver(Socket, SockMod, ShaperState, C2SPid, XMLStreamPid, Timeout) ->
ShaperState
end,
NewShaperState = shaper:update(ShaperSt1, size(Text)),
- xml_stream:send_text(XMLStreamPid, Text),
- receiver(Socket, SockMod, NewShaperState, C2SPid, XMLStreamPid,
+ XMLStreamPid1 = receive
+ reset_stream ->
+ exit(XMLStreamPid, closed),
+ xml_stream:start(C2SPid)
+ after 0 ->
+ XMLStreamPid
+ end,
+ xml_stream:send_text(XMLStreamPid1, Text),
+ receiver(Socket, SockMod, NewShaperState, C2SPid, XMLStreamPid1,
Timeout);
{error, timeout} ->
receiver(Socket, SockMod, ShaperState, C2SPid, XMLStreamPid,
diff --git a/src/jlib.hrl b/src/jlib.hrl
index db35bba46..3c2dbc5b1 100644
--- a/src/jlib.hrl
+++ b/src/jlib.hrl
@@ -32,7 +32,8 @@
-define(NS_STANZAS, "urn:ietf:params:xml:ns:xmpp-stanzas").
-define(NS_STREAMS, "urn:ietf:params:xml:ns:xmpp-streams").
--define(NS_SASL_MECHANISMS, "urn:ietf:params:xml:ns:xmpp-sasl").
+-define(NS_SASL, "urn:ietf:params:xml:ns:xmpp-sasl").
+-define(NS_SESSION, "urn:ietf:params:xml:ns:xmpp-session").
% TODO: remove "code" attribute (currently it used for backward-compatibility)
-define(STANZA_ERROR(Code, Class, Condition),