From 1a4eee059e1a61733249a54301089ad6364443e2 Mon Sep 17 00:00:00 2001 From: Peter Lemenkov Date: Jan 29 2010 13:15:24 +0000 Subject: Fixed RHBZ #559925 (EJAB-1173) and RHBZ #559944 --- diff --git a/ejabberd-c2s_dos_fix.diff b/ejabberd-c2s_dos_fix.diff new file mode 100644 index 0000000..2fe5f26 --- /dev/null +++ b/ejabberd-c2s_dos_fix.diff @@ -0,0 +1,83 @@ +Index: branches/ejabberd-2.1.x/src/ejabberd_c2s.erl +=================================================================== +diff -u -N -r2911 -r2936 +--- branches/ejabberd-2.1.x/src/ejabberd_c2s.erl (.../ejabberd_c2s.erl) (revision 2911) ++++ branches/ejabberd-2.1.x/src/ejabberd_c2s.erl (.../ejabberd_c2s.erl) (revision 2936) +@@ -28,8 +28,10 @@ + -author('alexey@process-one.net'). + -update_info({update, 0}). + +--behaviour(gen_fsm). ++-define(GEN_FSM, p1_fsm). + ++-behaviour(?GEN_FSM). ++ + %% External exports + -export([start/2, + stop/1, +@@ -104,8 +106,8 @@ + + %% Module start with or without supervisor: + -ifdef(NO_TRANSIENT_SUPERVISORS). +--define(SUPERVISOR_START, gen_fsm:start(ejabberd_c2s, [SockData, Opts], +- ?FSMOPTS)). ++-define(SUPERVISOR_START, ?GEN_FSM:start(ejabberd_c2s, [SockData, Opts], ++ fsm_limit_opts() ++ ?FSMOPTS)). + -else. + -define(SUPERVISOR_START, supervisor:start_child(ejabberd_c2s_sup, + [SockData, Opts])). +@@ -140,17 +142,18 @@ + ?SUPERVISOR_START. + + start_link(SockData, Opts) -> +- gen_fsm:start_link(ejabberd_c2s, [SockData, Opts], ?FSMOPTS). ++ ?GEN_FSM:start_link(ejabberd_c2s, [SockData, Opts], ++ fsm_limit_opts() ++ ?FSMOPTS). + + socket_type() -> + xml_stream. + + %% Return Username, Resource and presence information + get_presence(FsmRef) -> +- gen_fsm:sync_send_all_state_event(FsmRef, {get_presence}, 1000). ++ ?GEN_FSM:sync_send_all_state_event(FsmRef, {get_presence}, 1000). + + stop(FsmRef) -> +- gen_fsm:send_event(FsmRef, closed). ++ ?GEN_FSM:send_event(FsmRef, closed). + + %%%---------------------------------------------------------------------- + %%% Callback functions from gen_fsm +@@ -221,7 +224,7 @@ + + %% Return list of all available resources of contacts, + get_subscribed(FsmRef) -> +- gen_fsm:sync_send_all_state_event(FsmRef, get_subscribed, 1000). ++ ?GEN_FSM:sync_send_all_state_event(FsmRef, get_subscribed, 1000). + + %%---------------------------------------------------------------------- + %% Func: StateName/2 +@@ -903,7 +906,7 @@ + session_established(timeout, StateData) -> + %% TODO: Options must be stored in state: + Options = [], +- proc_lib:hibernate(gen_fsm, enter_loop, ++ proc_lib:hibernate(?GEN_FSM, enter_loop, + [?MODULE, Options, session_established, StateData]), + fsm_next_state(session_established, StateData); + +@@ -2153,6 +2156,14 @@ + end + end. + ++fsm_limit_opts() -> ++ case ejabberd_config:get_local_option(max_fsm_queue) of ++ N when is_integer(N) -> ++ [{max_queue, N}]; ++ _ -> ++ [] ++ end. ++ + %%%---------------------------------------------------------------------- + %%% JID Set memory footprint reduction code + %%%---------------------------------------------------------------------- diff --git a/ejabberd-ejabberdctl_fix.diff b/ejabberd-ejabberdctl_fix.diff index f431415..515f894 100644 --- a/ejabberd-ejabberdctl_fix.diff +++ b/ejabberd-ejabberdctl_fix.diff @@ -1,5 +1,5 @@ ---- src/ejabberdctl.template~ 2010-01-18 16:03:20.000000000 +0300 -+++ src/ejabberdctl.template 2010-01-25 15:24:48.967746180 +0300 +--- src/ejabberdctl.template~ 2010-01-29 15:03:48.000000000 +0300 ++++ src/ejabberdctl.template 2010-01-29 15:07:58.867786945 +0300 @@ -9,10 +9,10 @@ # define default environment variables @@ -11,9 +11,9 @@ -INSTALLUSER=@installuser@ +INSTALLUSER=ejabberd - # parse command line parameters - ARGS= -@@ -46,7 +46,7 @@ + # Control number of connections identifiers + # using flock if available. Expects a linux-style +@@ -53,7 +53,7 @@ LOGS_DIR=@LOCALSTATEDIR@/log/ejabberd fi if [ "$SPOOLDIR" = "" ] ; then @@ -22,7 +22,7 @@ fi if [ "$EJABBERD_DOC_PATH" = "" ] ; then EJABBERD_DOC_PATH=@DOCDIR@ -@@ -62,7 +62,7 @@ +@@ -69,7 +69,7 @@ EXEC_CMD="false" for GID in $GIDS; do if [ $GID -eq 0 ] ; then @@ -31,7 +31,7 @@ fi done if [ "$ID" -eq "$EJID" ] ; then -@@ -70,7 +70,7 @@ +@@ -77,7 +77,7 @@ fi if [ "$EXEC_CMD" = "false" ] ; then echo "This command can only be run by root or the user $INSTALLUSER" >&2 diff --git a/ejabberd.spec b/ejabberd.spec index 63919fb..3386704 100644 --- a/ejabberd.spec +++ b/ejabberd.spec @@ -12,7 +12,7 @@ Name: ejabberd Version: 2.1.2 -Release: 1%{?dist} +Release: 2%{?dist} Summary: A distributed, fault-tolerant Jabber/XMPP server Group: Applications/Internet @@ -49,6 +49,11 @@ Patch5: ejabberd-mod_ctlextra_mentioning_in_ejabberd_app.diff Patch8: ejabberd-fixed_delays_in_s2s.patch # Introducing mod_admin_extra Patch10: ejabberd-mod_admin_extra.patch +# see https://support.process-one.net/browse/EJAB-1173 +# https://forge.process-one.net/rdiff/ejabberd/branches/ejabberd-2.1.x/src/ejabberd_c2s.erl?r1=2911&r2=2936&u&N +Patch11: ejabberd-c2s_dos_fix.diff +# See this link: http://lists.jabber.ru/pipermail/ejabberd/2010-January/005819.html +Patch12: ejabberdctl-support-concurrent-connections.patch BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) @@ -75,6 +80,8 @@ Provides: group(%{name}) = %{uid} Requires: erlang Requires: usermode +# for flock in ejabberdctl +Requires: util-linux-ng %description @@ -90,79 +97,15 @@ Group: Documentation %description doc Documentation for ejabberd. -%pre -%{__fe_groupadd} %{uid} -r %{name} &>/dev/null || : -%{__fe_useradd} %{uid} -r -s /sbin/nologin -d /var/lib/ejabberd -M \ - -c 'ejabberd' -g %{name} %{name} &>/dev/null || : -# we should backup DB in every upgrade -if ejabberdctl status >/dev/null ; then - # Use timestamp to make database restoring easier - TIME=$(date +%Y-%m-%dT%H:%M:%S) - BACKUPDIR=$(mktemp -d -p /var/tmp/ ejabberd-$TIME.XXXXXX) - chown ejabberd:ejabberd $BACKUPDIR - BACKUP=$BACKUPDIR/ejabberd-database - ejabberdctl backup $BACKUP - # Change ownership to root:root because ejabberd user might be - # removed on package removal. - chown -R root:root $BACKUPDIR - chmod 700 $BACKUPDIR - echo - echo The ejabberd database has been backed up to $BACKUP. - echo -fi - -# fix cookie path (since ver. 2.1.0 cookie stored in /var/lib/ejabberd/spool -# rather than in /var/lib/ejabberd -if [ -f /var/lib/ejabberd/.erlang.cookie ]; then - cp -pf /var/lib/ejabberd/{,spool/}.erlang.cookie - echo - echo The ejabberd cookie file was moved. - echo Please remove old one from /var/lib/ejabberd/.erlang.cookie - echo -fi - - -%post -/sbin/chkconfig --add %{name} - -(cd /etc/ejabberd -if [ ! -f ejabberd.pem ] -then - echo "Generating SSL certificate /etc/ejabberd/ejabberd.pem..." - HOSTNAME=$(hostname -s 2>/dev/null || echo "localhost") - DOMAINNAME=$(hostname -d 2>/dev/null || echo "localdomain") - openssl req -new -x509 -days 365 -nodes -out ejabberd.pem \ - -keyout ejabberd.pem > /dev/null 2>&1 <<+++ -. -. -. -$DOMAINNAME -$HOSTNAME -ejabberd -root@$HOSTNAME.$DOMAINNAME -+++ -chown ejabberd:ejabberd ejabberd.pem -chmod 600 ejabberd.pem -fi) - -%preun -if [ $1 = 0 ]; then - /sbin/service %{name} stop >/dev/null 2>&1 - /sbin/chkconfig --del %{name} -fi - -%postun -if [ "$1" -ge "1" ]; then - /sbin/service %{name} condrestart >/dev/null 2>&1 -fi - %prep %setup -q -%patch2 -p0 -b .fix_ctl %patch3 -p0 -b .pam_name %patch5 -p0 -b .mod_ctlextra %patch8 -p0 -b .s2s %patch10 -p1 -b .mod_admin_extra +%patch11 -p2 -b .EJAB_1173 +%patch12 -p1 -b .concurrent +%patch2 -p0 -b .fix_ctl dos2unix src/odbc/mssql2000.sql @@ -171,6 +114,7 @@ cp %{S:5} src cp %{S:6} src cp %{S:7} src + %build pushd src %configure --enable-odbc --enable-debug --enable-pam @@ -185,6 +129,7 @@ make html pdf popd %endif + %install rm -rf %{buildroot} @@ -230,9 +175,80 @@ install -p -m 0644 src/odbc/pg.sql %{buildroot}%{_datadir}/%{name} # removed files, which would be packaged later (see 'files' section) rm -rf %{buildroot}%{_docdir}/%{name} + +%pre +%{__fe_groupadd} %{uid} -r %{name} &>/dev/null || : +%{__fe_useradd} %{uid} -r -s /sbin/nologin -d /var/lib/ejabberd -M \ + -c 'ejabberd' -g %{name} %{name} &>/dev/null || : +# we should backup DB in every upgrade +if ejabberdctl status >/dev/null ; then + # Use timestamp to make database restoring easier + TIME=$(date +%Y-%m-%dT%H:%M:%S) + BACKUPDIR=$(mktemp -d -p /var/tmp/ ejabberd-$TIME.XXXXXX) + chown ejabberd:ejabberd $BACKUPDIR + BACKUP=$BACKUPDIR/ejabberd-database + ejabberdctl backup $BACKUP + # Change ownership to root:root because ejabberd user might be + # removed on package removal. + chown -R root:root $BACKUPDIR + chmod 700 $BACKUPDIR + echo + echo The ejabberd database has been backed up to $BACKUP. + echo +fi + +# fix cookie path (since ver. 2.1.0 cookie stored in /var/lib/ejabberd/spool +# rather than in /var/lib/ejabberd +if [ -f /var/lib/ejabberd/.erlang.cookie ]; then + cp -pf /var/lib/ejabberd/{,spool/}.erlang.cookie + echo + echo The ejabberd cookie file was moved. + echo Please remove old one from /var/lib/ejabberd/.erlang.cookie + echo +fi + + +%post +/sbin/chkconfig --add %{name} + +(cd /etc/ejabberd +if [ ! -f ejabberd.pem ] +then + echo "Generating SSL certificate /etc/ejabberd/ejabberd.pem..." + HOSTNAME=$(hostname -s 2>/dev/null || echo "localhost") + DOMAINNAME=$(hostname -d 2>/dev/null || echo "localdomain") + openssl req -new -x509 -days 365 -nodes -out ejabberd.pem \ + -keyout ejabberd.pem > /dev/null 2>&1 <<+++ +. +. +. +$DOMAINNAME +$HOSTNAME +ejabberd +root@$HOSTNAME.$DOMAINNAME ++++ +chown ejabberd:ejabberd ejabberd.pem +chmod 600 ejabberd.pem +fi) + + +%preun +if [ $1 = 0 ]; then + /sbin/service %{name} stop >/dev/null 2>&1 + /sbin/chkconfig --del %{name} +fi + + +%postun +if [ "$1" -ge "1" ]; then + /sbin/service %{name} condrestart >/dev/null 2>&1 +fi + + %clean rm -rf %{buildroot} + %files %defattr(-,root,root,-) %doc COPYING @@ -299,6 +315,7 @@ rm -rf %{buildroot} %attr(750,ejabberd,ejabberd) %dir /var/lib/ejabberd %attr(750,ejabberd,ejabberd) %dir /var/lib/ejabberd/spool +%attr(750,ejabberd,ejabberd) %dir /var/lock/ejabberdctl %attr(750,ejabberd,ejabberd) %dir /var/log/ejabberd %files doc @@ -333,6 +350,10 @@ rm -rf %{buildroot} %doc doc/yozhikheader.png %changelog +* Fri Jan 29 2010 Peter Lemenkov 2.1.2-2 +- Fixed BZ #559925 (EJAB-1173) +- Changed order of rpmbuild targets in sthis spec to more natural one. + * Mon Jan 18 2010 Peter Lemenkov 2.1.2-1 - Ver. 2.1.2 diff --git a/ejabberdctl-support-concurrent-connections.patch b/ejabberdctl-support-concurrent-connections.patch new file mode 100644 index 0000000..313e844 --- /dev/null +++ b/ejabberdctl-support-concurrent-connections.patch @@ -0,0 +1,156 @@ +From 5990c7f1e5b2fa106806d9ed03a4a59cfa75959a Mon Sep 17 00:00:00 2001 +From: Martin Langhoff +Date: Sun, 24 Jan 2010 14:39:15 +0100 +Subject: [PATCH] ejabberdctl: support concurrent connections with bound conn names + +If flock is available, ejabberdctl will use it to grab one +of a bound number of connection names. This allows concurrent +connections while using a bound number of atoms. + +Using PID, timestamps or random strings for transient connection IDs +(which would avoid the need for flock) uses an unbound number of atoms. +This can effectively DoS servers, as these connection names are +not garbage collected. +--- + src/Makefile.in | 10 ++++++ + src/ejabberdctl.template | 75 +++++++++++++++++++++++++++++++++++++++++---- + 2 files changed, 78 insertions(+), 7 deletions(-) + +diff --git a/src/Makefile.in b/src/Makefile.in +index 8485caa..02f05e8 100644 +--- a/src/Makefile.in ++++ b/src/Makefile.in +@@ -110,6 +110,9 @@ MSGSDIR = $(PRIVDIR)/msgs + # /var/lib/ejabberd/ + SPOOLDIR = $(DESTDIR)@localstatedir@/lib/ejabberd + ++# /var/lock/ejabberdctl ++CTLLOCKDIR = $(DESTDIR)@localstatedir@/lock/ejabberdctl ++ + # /var/lib/ejabberd/.erlang.cookie + COOKIEFILE = $(SPOOLDIR)/.erlang.cookie + +@@ -230,6 +233,12 @@ install: all + install -d -m 750 $(O_USER) $(SPOOLDIR) + $(CHOWN_COMMAND) -R @INSTALLUSER@ $(SPOOLDIR) >$(CHOWN_OUTPUT) + chmod -R 750 $(SPOOLDIR) ++ ++ # ejabberdctl lock directory ++ install -d -m 750 $(O_USER) $(CTLLOCKDIR) ++ $(CHOWN_COMMAND) -R @INSTALLUSER@ $(CTLLOCKDIR) >$(CHOWN_OUTPUT) ++ chmod -R 750 $(CTLLOCKDIR) ++ + [ ! -f $(COOKIEFILE) ] || { $(CHOWN_COMMAND) @INSTALLUSER@ $(COOKIEFILE) >$(CHOWN_OUTPUT) ; chmod 400 $(COOKIEFILE) ; } + # + # Log directory +@@ -265,6 +274,7 @@ uninstall-all: uninstall-binary + rm -rf $(ETCDIR) + rm -rf $(EJABBERDDIR) + rm -rf $(SPOOLDIR) ++ rm -rf $(CTLLOCKDIR) + rm -rf $(LOGDIR) + + clean: clean-recursive clean-local +diff --git a/src/ejabberdctl.template b/src/ejabberdctl.template +index 438481b..d2aa5fe 100644 +--- a/src/ejabberdctl.template ++++ b/src/ejabberdctl.template +@@ -14,6 +14,13 @@ ERLANG_NODE=$NODE@$HOST + ERL=@erl@ + INSTALLUSER=@installuser@ + ++# Control number of connections identifiers ++# using flock if available. Expects a linux-style ++# flock that can lock a file descriptor. ++MAXCONNID=100 ++CONNLOCKDIR=@LOCALSTATEDIR@/lock/ejabberdctl ++FLOCK=`type -p flock` ++ + # parse command line parameters + ARGS= + while [ $# -ne 0 ] ; do +@@ -228,13 +235,55 @@ help () + ctl () + { + COMMAND=$@ +- $EXEC_CMD "$ERL \ +- $NAME ctl-${ERLANG_NODE} \ +- -noinput \ +- -hidden \ +- -pa $EJABBERD_EBIN_PATH \ +- -s ejabberd_ctl -extra $ERLANG_NODE $COMMAND" +- result=$? ++ ++ if [ ! "$FLOCK" ];then ++ # no flock, simply invoke ctlexec() ++ CTL_CONN="ctl-${EJABBERD_NODE}" ++ ctlexec $CTL_CONN $COMMAND ++ result=$? ++ else ++ # we have flock so we get a lock ++ # on one of a limited number of ++ # conn names -- this allows ++ # concurrent invokations using a bound ++ # number of atoms ++ for N in $(seq 1 $MAXCONNID); do ++ CTL_CONN="ejabberdctl-$N" ++ CTL_LOCKFILE="$CONNLOCKDIR/$CTL_CONN" ++ ( ++ if flock --nb 200; then ++ # see the '200' file descriptor ++ # at the bottom of the block ++ ctlexec $CTL_CONN $COMMAND ++ ssresult=$? ++ # segregate from possible flock exit(1) ++ ssresult=$(expr $ssresult \* 10) ++ exit $ssresult ++ else ++ exit 1 ++ fi ++ ) 200>"$CTL_LOCKFILE" ++ result=$? ++ if [ $result -eq 1 ]; then ++ # means we errored out in flock ++ # rather than in the exec - stay in the loop ++ # trying other conn names... ++ badlock=1 ++ else ++ badlock="" ++ break; ++ fi ++ done ++ result=$(expr $result / 10) ++ fi ++ ++ if [ "$badlock" ];then ++ echo "Ran out of connections to try. Your ejabberd processes" >&2 ++ echo "may be stuck or this is a very busy server. For very" >&2 ++ echo "busy servers, consider raising MAXCONNIDS" >&2 ++ exit 1; ++ fi ++ + case $result in + 0) :;; + 1) :;; +@@ -244,6 +293,18 @@ ctl () + return $result + } + ++ctlexec () ++{ ++ CONN_NAME=$1; shift ++ COMMAND=$@ ++ $EXEC_CMD "$ERL \ ++ $NAME ${CONN_NAME} \ ++ -noinput \ ++ -hidden \ ++ -pa $EJABBERD_EBIN_PATH \ ++ -s ejabberd_ctl -extra $ERLANG_NODE $COMMAND" ++} ++ + # display ctl usage + usage () + { +-- +1.6.2.5 + diff --git a/import.log b/import.log index 69bc2ee..17c7a5d 100644 --- a/import.log +++ b/import.log @@ -15,3 +15,4 @@ ejabberd-2_1_0-1_fc12:F-11:ejabberd-2.1.0-1.fc12.src.rpm:1258790645 ejabberd-2_1_0-2_fc12:F-11:ejabberd-2.1.0-2.fc12.src.rpm:1260472235 ejabberd-2_1_1-1_fc12:F-11:ejabberd-2.1.1-1.fc12.src.rpm:1261656564 ejabberd-2_1_2-1_fc12:F-11:ejabberd-2.1.2-1.fc12.src.rpm:1264423698 +ejabberd-2_1_2-2_fc12:F-11:ejabberd-2.1.2-2.fc12.src.rpm:1264770903