Blob Blame History Raw
This bug fixes a long-standing bug with ejabberd violating
RFC 3920 by intercepting vCard request coming to a user's
full JID, which should be forwarded to the user's client instead.
This behaviour is especially noticeable in MUC rooms.

This issue is tracked upstream as EJAB-1045.

This changeset was introduced in revisions 2766-2768
branch http://svn.process-one.net/ejabberd/branches/ejabberd-2.1.x

The first stable version containing the fix is 2.1.1.

--- a/src/ejabberd_sm.erl	(revision 2762)
+++ b/src/ejabberd_sm.erl	(revision 2768)
@@ -481,7 +481,7 @@
 				_ ->
 				    Err =
 					jlib:make_error_reply(
-					  Packet, ?ERR_RECIPIENT_UNAVAILABLE),
+					  Packet, ?ERR_SERVICE_UNAVAILABLE),
 				    ejabberd_router:route(To, From, Err)
 			    end;
 			_ ->
--- a/src/mod_muc/mod_muc_room.erl	(revision 2762)
+++ b/src/mod_muc/mod_muc_room.erl	(revision 2768)
@@ -470,9 +470,10 @@
 	      {xmlelement, "iq", Attrs, _Els} = Packet},
 	     StateData) ->
     Lang = xml:get_attr_s("xml:lang", Attrs),
+    StanzaId = xml:get_attr_s("id", Attrs),
     case {(StateData#state.config)#config.allow_query_users,
-	  is_user_online(From, StateData)} of
-	{true, true} ->
+	  is_user_online_iq(StanzaId, From, StateData)} of
+	{true, {true, NewId, FromFull}} ->
 	    case find_jid_by_nick(ToNick, StateData) of
 		false ->
 		    case jlib:iq_query_info(Packet) of
@@ -489,13 +490,15 @@
 		    end;
 		ToJID ->
 		    {ok, #user{nick = FromNick}} =
-			?DICT:find(jlib:jid_tolower(From),
+			?DICT:find(jlib:jid_tolower(FromFull),
 				   StateData#state.users),
+		    {ToJID2, Packet2} = handle_iq_vcard(FromFull, ToJID,
+							StanzaId, NewId,Packet),
 		    ejabberd_router:route(
 		      jlib:jid_replace_resource(StateData#state.jid, FromNick),
-		      ToJID, Packet)
+		      ToJID2, Packet2)
 	    end;
-	{_, false} ->
+	{_, {false, _, _}} ->
 	    case jlib:iq_query_info(Packet) of
 		reply ->
 		    ok;
@@ -829,7 +832,6 @@
 	    {next_state, normal_state, StateData}
     end.
 
-
 %% @doc Check if this non participant can send message to room.
 %%
 %% XEP-0045 v1.23:
@@ -969,6 +971,50 @@
     LJID = jlib:jid_tolower(JID),
     ?DICT:is_key(LJID, StateData#state.users).
 
+
+%%%
+%%% Handle IQ queries of vCard
+%%%
+is_user_online_iq(StanzaId, JID, StateData) when JID#jid.lresource /= "" ->
+    {is_user_online(JID, StateData), StanzaId, JID};
+is_user_online_iq(StanzaId, JID, StateData) when JID#jid.lresource == "" ->
+    try stanzaid_unpack(StanzaId) of
+	{OriginalId, Resource} ->
+	    JIDWithResource = jlib:jid_replace_resource(JID, Resource),
+	    {is_user_online(JIDWithResource, StateData),
+	     OriginalId, JIDWithResource}
+    catch
+	_:_ ->
+	    {is_user_online(JID, StateData), StanzaId, JID}
+    end.
+
+handle_iq_vcard(FromFull, ToJID, StanzaId, NewId, Packet) ->
+    ToBareJID = jlib:jid_remove_resource(ToJID),
+    IQ = jlib:iq_query_info(Packet),
+    handle_iq_vcard2(FromFull, ToJID, ToBareJID, StanzaId, NewId, IQ, Packet).
+handle_iq_vcard2(_FromFull, ToJID, ToBareJID, StanzaId, _NewId,
+		 #iq{type = get, xmlns = ?NS_VCARD}, Packet)
+  when ToBareJID /= ToJID ->
+    {ToBareJID, change_stanzaid(StanzaId, ToJID, Packet)};
+handle_iq_vcard2(_FromFull, ToJID, _ToBareJID, _StanzaId, NewId, _IQ, Packet) ->
+    {ToJID, change_stanzaid(NewId, Packet)}.
+
+stanzaid_pack(OriginalId, Resource) ->
+    "berd"++base64:encode_to_string("ejab\0" ++ OriginalId ++ "\0" ++ Resource).
+stanzaid_unpack("berd"++StanzaIdBase64) ->
+    StanzaId = base64:decode_to_string(StanzaIdBase64),
+    ["ejab", OriginalId, Resource] = string:tokens(StanzaId, "\0"),
+    {OriginalId, Resource}.
+
+change_stanzaid(NewId, Packet) ->
+    {xmlelement, Name, Attrs, Els} = jlib:remove_attr("id", Packet),
+    {xmlelement, Name, [{"id", NewId} | Attrs], Els}.
+change_stanzaid(PreviousId, ToJID, Packet) ->
+    NewId = stanzaid_pack(PreviousId, ToJID#jid.lresource),
+    change_stanzaid(NewId, Packet).
+%%%
+%%%
+
 role_to_list(Role) ->
     case Role of
 	moderator ->   "moderator";
--- a/src/ejabberd_c2s.erl	(revision 2762)
+++ b/src/ejabberd_c2s.erl	(revision 2768)
@@ -1220,7 +1220,7 @@
 	    "iq" ->
 		IQ = jlib:iq_query_info(Packet),
 		case IQ of
-		    #iq{xmlns = ?NS_VCARD} ->
+		    #iq{xmlns = ?NS_VCARD} when (To#jid.luser == "") or (To#jid.lresource == "") ->
 			Host = StateData#state.server,
 			case ets:lookup(sm_iqtable, {?NS_VCARD, Host}) of
 			    [{_, Module, Function, Opts}] ->