Package: release.debian.org
Severity: normal
User: release.debian....@packages.debian.org
Usertags: freeze-exception

Please unblock package ejabberd 2.1.10-4.

It fixes three important bugs:
* Broken import of JPEG images from users' vCards fetched from LDAP [1].
  The patch is trivial as it merely fixes a programming blooper.
* Creation of an extraneous file under /root during installation [2].
  The fix is rather simple as well.
* Incorrect parsing of HTTPS requests split into multiple packets [3].
  The fix for this bug is rather involved but happily the code base
  between the upstream versions 2.1.10 (affected) and 2.1.11 (received
  the fix) almost did not change so the extracted patch was applied
  OK after minimal massaging.  This bug is really several as it is
  reported to reliably break certain web chat applications and BOSH [4]
  connections so I think we should include the fix for it.

The debdiff is attached.

1. http://bugs.debian.org/660186
2. http://bugs.debian.org/691125
3. http://bugs.debian.org/698309
4. http://xmpp.org/extensions/xep-0206.html
diff -u ejabberd-2.1.10/debian/prerm ejabberd-2.1.10/debian/prerm
--- ejabberd-2.1.10/debian/prerm
+++ ejabberd-2.1.10/debian/prerm
@@ -15,15 +15,23 @@
 #          <conflicting-package> <version>
 # for details, see /usr/doc/packaging-manual/
 
+ctl() {
+       local cmd='/usr/sbin/ejabberdctl'
+       for arg in "$@"; do
+               cmd="$cmd '$arg'"
+       done
+       su ejabberd -c "$cmd"
+}
+
 case "$1" in
     remove|upgrade)
-       if ejabberdctl status >/dev/null ; then
+       if ctl status >/dev/null ; then
            # Use timestamp to make database restoring easier
            TIME=$(date +%Y-%m-%dT%H:%M:%S)
            BACKUPDIR=$(mktemp -d -p /var/backups/ ejabberd-$TIME.XXXXXX)
            chown ejabberd:ejabberd $BACKUPDIR
            BACKUP=$BACKUPDIR/ejabberd-database
-           ejabberdctl backup $BACKUP
+           ctl backup $BACKUP
            # Change ownership to root:root because ejabberd user might be
            # removed on package removal.
            chown -R root:root $BACKUPDIR
diff -u ejabberd-2.1.10/debian/changelog ejabberd-2.1.10/debian/changelog
--- ejabberd-2.1.10/debian/changelog
+++ ejabberd-2.1.10/debian/changelog
@@ -1,3 +1,15 @@
+ejabberd (2.1.10-4) unstable; urgency=low
+
+  [ Konstantin Khomoutov ]
+  * Do not run ejabberdctl as root in prerm and logrotate scripts
+    (closes: #691125, thanks to Michael Stapelberg and Felix Geyer).
+  * Add upstream patch fixing receiving JPEG vCard photos via LDAP
+    (closes: #660186).
+  * Add upstream patch fixing parsing HTTPS requests split into
+    multiple packets (closes: #698309).
+
+ -- Konstantin Khomoutov <flatw...@users.sourceforge.net>  Sat, 16 Feb 2013 
16:59:21 +0000
+
 ejabberd (2.1.10-3) unstable; urgency=low
 
   [ Konstantin Khomoutov ]
diff -u ejabberd-2.1.10/debian/logrotate ejabberd-2.1.10/debian/logrotate
--- ejabberd-2.1.10/debian/logrotate
+++ ejabberd-2.1.10/debian/logrotate
@@ -10,5 +10,5 @@
        sharedscripts
        postrotate
-               /usr/sbin/ejabberdctl reopen-log > /dev/null
+               su ejabberd -c '/usr/sbin/ejabberdctl reopen-log' > /dev/null
        endscript
 }
diff -u ejabberd-2.1.10/debian/patches/series 
ejabberd-2.1.10/debian/patches/series
--- ejabberd-2.1.10/debian/patches/series
+++ ejabberd-2.1.10/debian/patches/series
@@ -7,0 +8,2 @@
+fix-ldap-vcard-jpeg-photos.patch
+fix-parsing-split-https-requests.patch
only in patch2:
unchanged:
--- ejabberd-2.1.10.orig/debian/patches/fix-ldap-vcard-jpeg-photos.patch
+++ ejabberd-2.1.10/debian/patches/fix-ldap-vcard-jpeg-photos.patch
@@ -0,0 +1,16 @@
+Description: Fix fetching JPEG vCard photos via LDAP
+Origin: upstream, 
https://github.com/processone/ejabberd/commit/be33ab890e35ae5c41285dd5ed422db910534040
+Bug-ProcessOne: https://support.process-one.net/browse/EJAB-1526
+Applied-Upstream: 2.1.11
+Last-Update: 2013-02-17
+diff --git a/src/eldap/eldap_filter.erl b/src/eldap/eldap_filter.erl
+index f8f20be..e78ee7e 100644
+--- a/src/eldap/eldap_filter.erl
++++ b/src/eldap/eldap_filter.erl
+@@ -181,5 +181,6 @@ do_sub(S, {RegExp, New, Times}, Iter) ->
+ replace_amps(String) ->
+     lists:flatmap(
+       fun($&) -> "\\&";
++         ($\\) -> "\\\\";
+        (Chr) -> [Chr]
+       end, String).
only in patch2:
unchanged:
--- ejabberd-2.1.10.orig/debian/patches/fix-parsing-split-https-requests.patch
+++ ejabberd-2.1.10/debian/patches/fix-parsing-split-https-requests.patch
@@ -0,0 +1,312 @@
+Description: Fix parsing HTTPS requests split into multiple packets
+  This fixes case when SockMod:recv() calls returns only
+  part of first line of http request (GET/POST/OPTION/HEAD line).
+  Before that change request like that (and if keep-alive was active,
+  all further request) were dropped.
+
+  The patch extracted from the upstream commit has been slightly
+  massaged to apply cleanly to the stock 2.1.10 source code.
+Origin: upstream, 
https://github.com/processone/ejabberd/commit/5f828467327bbd0fb8df6afc20559c2208bc0603
+Bug-ProcessOne: https://support.process-one.net/browse/EJAB-1537
+Applied-Upstream: 2.1.11
+Last-Update: 2013-02-17
+--- a/src/web/ejabberd_http.erl
++++ b/src/web/ejabberd_http.erl
+@@ -65,7 +65,7 @@
+               request_tp,
+               request_headers = [],
+               end_of_request = false,
+-              trail = ""
++              trail = <<>>
+              }).
+ 
+ 
+@@ -164,12 +164,12 @@
+           exit(normal)
+     end.
+ 
+-receive_headers(State) ->
++receive_headers(#state{trail=Trail} = State) ->
+     SockMod = State#state.sockmod,
+     Socket = State#state.socket,
+     Data = SockMod:recv(Socket, 0, 300000),
+     case State#state.sockmod of
+-      gen_tcp ->
++        gen_tcp ->
+           NewState = process_header(State, Data),
+           case NewState#state.end_of_request of
+               true ->
+@@ -177,31 +177,35 @@
+               _ ->
+                   receive_headers(NewState)
+           end;
+-      _ ->
+-          case Data of
+-              {ok, Binary} ->
+-                  {Request, Trail} = parse_request(
+-                                       State,
+-                                       State#state.trail ++ 
binary_to_list(Binary)),
+-                  State1 = State#state{trail = Trail},
+-                  NewState = lists:foldl(
+-                               fun(D, S) ->
+-                                      case S#state.end_of_request of
+-                                          true ->
+-                                              S;
+-                                          _ ->
+-                                              process_header(S, D)
+-                                      end
+-                               end, State1, Request),
+-                  case NewState#state.end_of_request of
+-                      true ->
+-                          ok;
+-                      _ ->
+-                          receive_headers(NewState)
+-                  end;
++        _ ->
++            case Data of
++                {ok, D} ->
++                    parse_headers(State#state{trail = <<Trail/binary, 
D/binary>>});
++                {error, _} ->
++                    ok
++            end
++    end.
++
++parse_headers(#state{trail = <<>>} = State) ->
++    receive_headers(State);
++parse_headers(#state{request_method = Method, trail = Data} = State) ->
++    PktType = case Method of
++                  undefined -> http;
++                  _ -> httph
++              end,
++    case decode_packet(PktType, Data) of
++        {ok, Pkt, Rest} ->
++            NewState = process_header(State#state{trail = Rest}, {ok, Pkt}),
++          case NewState#state.end_of_request of
++              true ->
++                  ok;
+               _ ->
+-                  ok
+-          end
++                    parse_headers(NewState)
++          end;
++        {more, _} ->
++            receive_headers(State#state{trail = Data});
++        _ ->
++            ok
+     end.
+ 
+ process_header(State, Data) ->
+@@ -506,16 +510,16 @@
+     binary_to_list(list_to_binary(Acc));
+ recv_data(State, Len, Acc) ->
+     case State#state.trail of
+-      [] ->
+-          case (State#state.sockmod):recv(State#state.socket,   Len, 300000) 
of
++      <<>> ->
++          case (State#state.sockmod):recv(State#state.socket, Len, 300000) of
+               {ok, Data} ->
+                   recv_data(State, Len - size(Data), [Acc | [Data]]);
+               _ ->
+                   ""
+           end;
+       _ ->
+-          Trail = State#state.trail,
+-          recv_data(State#state{trail = ""}, Len - length(Trail), [Acc | 
Trail])
++          Trail = binary_to_list(State#state.trail),
++          recv_data(State#state{trail = <<>>}, Len - length(Trail), [Acc | 
Trail])
+     end.
+ 
+ 
+@@ -796,7 +800,7 @@
+ decode_base64([]) ->
+   [];
+ decode_base64([Sextet1,Sextet2,$=,$=|Rest]) ->
+-  Bits2x6=
++    Bits2x6=
+     (d(Sextet1) bsl 18) bor
+     (d(Sextet2) bsl 12),
+   Octet1=Bits2x6 bsr 16,
+@@ -906,42 +910,29 @@
+ 
+ % The following code is mostly taken from yaws_ssl.erl
+ 
+-parse_request(State, Data) ->
+-    case Data of
+-      [] ->
+-          {[], []};
+-      _ ->
+-          ?DEBUG("GOT ssl data ~p~n", [Data]),
+-          {R, Trail} = case State#state.request_method of
+-                           undefined ->
+-                               {R1, Trail1} = get_req(Data),
+-                               ?DEBUG("Parsed request ~p~n", [R1]),
+-                               {[R1], Trail1};
+-                           _ ->
+-                               {[], Data}
+-                       end,
+-          {H, Trail2} = get_headers(Trail),
+-          {R ++ H, Trail2}
++decode_packet(_, <<"\r\n", Rest/binary>>) ->
++    {ok, http_eoh, Rest};
++decode_packet(Type, Data) ->
++    case binary:match(Data, <<"\r\n">>) of
++        {Start, _Len} ->
++            <<LineB:Start/binary, _:2/binary, Rest/binary>> = Data,
++            Line = binary_to_list(LineB),
++            Result = case Type of
++                         http ->
++                             parse_req(Line);
++                         httph ->
++                             parse_line(Line)
++                     end,
++            case Result of
++                {ok, H} ->
++                    {ok, H, Rest};
++                Err ->
++                    {error, Err}
++            end;
++        _ ->
++            {more, undefined}
+     end.
+ 
+-get_req("\r\n\r\n" ++ _) ->
+-    bad_request;
+-get_req("\r\n" ++ Data) ->
+-    get_req(Data);
+-get_req(Data) ->
+-    {FirstLine, Trail} = lists:splitwith(fun not_eol/1, Data),
+-    R = parse_req(FirstLine),
+-    {R, Trail}.
+-
+-
+-not_eol($\r)->
+-    false;
+-not_eol($\n) ->
+-    false;
+-not_eol(_) ->
+-    true.
+-
+-
+ get_word(Line)->
+     {Word, T} = lists:splitwith(fun(X)-> X /= $\  end, Line),
+     {Word, lists:dropwhile(fun(X) -> X == $\  end, T)}.
+@@ -1012,68 +1003,54 @@
+     end.
+ 
+ 
+-get_headers(Tail) ->
+-    get_headers([], Tail).
+-
+-get_headers(H, Tail) ->
+-    case get_line(Tail) of
+-      {incomplete, Tail2} ->
+-          {H, Tail2};
+-      {line, Line, Tail2} ->
+-          get_headers(H ++ parse_line(Line), Tail2);
+-      {lastline, Line, Tail2} ->
+-          {H ++ parse_line(Line) ++ [{ok, http_eoh}], Tail2}
+-    end.
+-
+-
+ parse_line("Connection:" ++ Con) ->
+-    [{ok, {http_header,  undefined, 'Connection', undefined, 
strip_spaces(Con)}}];
++    {ok, {http_header,  undefined, 'Connection', undefined, 
strip_spaces(Con)}};
+ parse_line("Host:" ++ Con) ->
+-    [{ok, {http_header,  undefined, 'Host', undefined, strip_spaces(Con)}}];
++    {ok, {http_header,  undefined, 'Host', undefined, strip_spaces(Con)}};
+ parse_line("Accept:" ++ Con) ->
+-    [{ok, {http_header,  undefined, 'Accept', undefined, strip_spaces(Con)}}];
++    {ok, {http_header,  undefined, 'Accept', undefined, strip_spaces(Con)}};
+ parse_line("If-Modified-Since:" ++ Con) ->
+-    [{ok, {http_header,  undefined, 'If-Modified-Since', undefined, 
strip_spaces(Con)}}];
++    {ok, {http_header,  undefined, 'If-Modified-Since', undefined, 
strip_spaces(Con)}};
+ parse_line("If-Match:" ++ Con) ->
+-    [{ok, {http_header,  undefined, 'If-Match', undefined, 
strip_spaces(Con)}}];
++    {ok, {http_header,  undefined, 'If-Match', undefined, strip_spaces(Con)}};
+ parse_line("If-None-Match:" ++ Con) ->
+-    [{ok, {http_header,  undefined, 'If-None-Match', undefined, 
strip_spaces(Con)}}];
++    {ok, {http_header,  undefined, 'If-None-Match', undefined, 
strip_spaces(Con)}};
+ parse_line("If-Range:" ++ Con) ->
+-    [{ok, {http_header,  undefined, 'If-Range', undefined, 
strip_spaces(Con)}}];
++    {ok, {http_header,  undefined, 'If-Range', undefined, strip_spaces(Con)}};
+ parse_line("If-Unmodified-Since:" ++ Con) ->
+-    [{ok, {http_header,  undefined, 'If-Unmodified-Since', undefined, 
strip_spaces(Con)}}];
++    {ok, {http_header,  undefined, 'If-Unmodified-Since', undefined, 
strip_spaces(Con)}};
+ parse_line("Range:" ++ Con) ->
+-    [{ok, {http_header,  undefined, 'Range', undefined, strip_spaces(Con)}}];
++    {ok, {http_header,  undefined, 'Range', undefined, strip_spaces(Con)}};
+ parse_line("User-Agent:" ++ Con) ->
+-    [{ok, {http_header,  undefined, 'User-Agent', undefined, 
strip_spaces(Con)}}];
++    {ok, {http_header,  undefined, 'User-Agent', undefined, 
strip_spaces(Con)}};
+ parse_line("Accept-Ranges:" ++ Con) ->
+-    [{ok, {http_header,  undefined, 'Accept-Ranges', undefined, 
strip_spaces(Con)}}];
++    {ok, {http_header,  undefined, 'Accept-Ranges', undefined, 
strip_spaces(Con)}};
+ parse_line("Authorization:" ++ Con) ->
+-    [{ok, {http_header,  undefined, 'Authorization', undefined, 
strip_spaces(Con)}}];
++    {ok, {http_header,  undefined, 'Authorization', undefined, 
strip_spaces(Con)}};
+ parse_line("Keep-Alive:" ++ Con) ->
+-    [{ok, {http_header,  undefined, 'Keep-Alive', undefined, 
strip_spaces(Con)}}];
++    {ok, {http_header,  undefined, 'Keep-Alive', undefined, 
strip_spaces(Con)}};
+ parse_line("Referer:" ++ Con) ->
+-    [{ok, {http_header,  undefined, 'Referer', undefined, 
strip_spaces(Con)}}];
++    {ok, {http_header,  undefined, 'Referer', undefined, strip_spaces(Con)}};
+ parse_line("Content-type:"++Con) ->
+-    [{ok, {http_header,  undefined, 'Content-Type', undefined, 
strip_spaces(Con)}}];
++    {ok, {http_header,  undefined, 'Content-Type', undefined, 
strip_spaces(Con)}};
+ parse_line("Content-Type:"++Con) ->
+-    [{ok, {http_header,  undefined, 'Content-Type', undefined, 
strip_spaces(Con)}}];
++    {ok, {http_header,  undefined, 'Content-Type', undefined, 
strip_spaces(Con)}};
+ parse_line("Content-Length:"++Con) ->
+-    [{ok, {http_header,  undefined, 'Content-Length', undefined, 
strip_spaces(Con)}}];
++    {ok, {http_header,  undefined, 'Content-Length', undefined, 
strip_spaces(Con)}};
+ parse_line("Content-length:"++Con) ->
+-    [{ok, {http_header,  undefined, 'Content-Length', undefined, 
strip_spaces(Con)}}];
++    {ok, {http_header,  undefined, 'Content-Length', undefined, 
strip_spaces(Con)}};
+ parse_line("Cookie:"++Con) ->
+-    [{ok, {http_header,  undefined, 'Cookie', undefined, strip_spaces(Con)}}];
++    {ok, {http_header,  undefined, 'Cookie', undefined, strip_spaces(Con)}};
+ parse_line("Accept-Language:"++Con) ->
+-    [{ok, {http_header,  undefined, 'Accept-Language', undefined, 
strip_spaces(Con)}}];
++    {ok, {http_header,  undefined, 'Accept-Language', undefined, 
strip_spaces(Con)}};
+ parse_line("Accept-Encoding:"++Con) ->
+-    [{ok, {http_header,  undefined, 'Accept-Encoding', undefined, 
strip_spaces(Con)}}];
++    {ok, {http_header,  undefined, 'Accept-Encoding', undefined, 
strip_spaces(Con)}};
+ parse_line(S) ->
+     case lists:splitwith(fun(C)->C /= $: end, S) of
+       {Name, [$:|Val]} ->
+-          [{ok, {http_header,  undefined, Name, undefined, 
strip_spaces(Val)}}];
++          {ok, {http_header,  undefined, Name, undefined, strip_spaces(Val)}};
+       _ ->
+-          []
++          bad_request
+     end.
+ 
+ 
+@@ -1109,27 +1086,3 @@
+           YS
+     end.
+ 
+-is_nb_space(X) ->
+-    lists:member(X, [$\s, $\t]).
+-
+-
+-% ret: {line, Line, Trail} | {lastline, Line, Trail}
+-
+-get_line(L) ->
+-    get_line(L, []).
+-get_line("\r\n\r\n" ++ Tail, Cur) ->
+-    {lastline, lists:reverse(Cur), Tail};
+-get_line("\r\n" ++ Tail, Cur) ->
+-    case Tail of
+-      [] ->
+-          {incomplete, lists:reverse(Cur) ++ "\r\n"};
+-      _ ->
+-          case is_nb_space(hd(Tail)) of
+-              true ->  %% multiline ... continue
+-                  get_line(Tail, [$\n, $\r | Cur]);
+-              false ->
+-                  {line, lists:reverse(Cur), Tail}
+-          end
+-    end;
+-get_line([H|T], Cur) ->
+-    get_line(T, [H|Cur]).

Reply via email to