diff --git a/configure.in b/configure.in index 84ac5f95d2..7736873e8b 100644 --- a/configure.in +++ b/configure.in @@ -65,6 +65,24 @@ AC_ARG_WITH(ssl-dir, ] ) +TORUSER=_tor +AC_ARG_WITH(tor-user, + [ --with-tor-user=NAME Specify username for tor daemon ], + [ + TORUSER=$withval + ] +) +AC_SUBST(TORUSER) + +TORGROUP=_tor +AC_ARG_WITH(tor-group, + [ --with-tor-group=NAME Specify group name for tor daemon ], + [ + TORGROUP=$withval + ] +) +AC_SUBST(TORGROUP) + AC_SEARCH_LIBS(socket, [socket]) AC_SEARCH_LIBS(gethostbyname, [nsl]) AC_SEARCH_LIBS(dlopen, [dl]) @@ -523,7 +541,7 @@ CFLAGS="$CFLAGS -Wall -g -O2" echo "confdir: $CONFDIR" -AC_OUTPUT(Makefile tor.spec contrib/tor.sh contrib/torctl contrib/torify contrib/Makefile contrib/osx/Makefile contrib/osx/TorBundleDesc.plist contrib/osx/TorBundleInfo.plist contrib/osx/TorDesc.plist contrib/osx/TorInfo.plist contrib/osx/TorStartupDesc.plist src/config/torrc.sample doc/tor.1 src/Makefile doc/Makefile doc/design-paper/Makefile src/config/Makefile src/common/Makefile src/or/Makefile src/win32/Makefile src/tools/Makefile) +AC_OUTPUT(Makefile tor.spec contrib/tor.sh contrib/torctl contrib/torify contrib/tor.logrotate contrib/Makefile contrib/osx/Makefile contrib/osx/TorBundleDesc.plist contrib/osx/TorBundleInfo.plist contrib/osx/TorDesc.plist contrib/osx/TorInfo.plist contrib/osx/TorStartupDesc.plist src/config/torrc.sample doc/tor.1 src/Makefile doc/Makefile doc/design-paper/Makefile src/config/Makefile src/common/Makefile src/or/Makefile src/win32/Makefile src/tools/Makefile) if test -x /usr/bin/perl && test -x ./contrib/updateVersions.pl ; then ./contrib/updateVersions.pl diff --git a/contrib/tor.sh.in b/contrib/tor.sh.in index 2fc35b8410..e9e604dd5b 100644 --- a/contrib/tor.sh.in +++ b/contrib/tor.sh.in @@ -1,28 +1,35 @@ #!/bin/sh # -#tor The Onion Router +# tor The Onion Router +# +# Startup/shutdown script for tor. This is a wrapper around torctl; +# torctl does the actual work in a relatively system-independent, or at least +# distribution-independent, way, and this script deals with fitting the +# whole thing into the conventions of the particular system at hand. +# This particular script is written for Red Hat/Fedora Linux, and may +# also work on Mandrake, but not SuSE. +# +# These next couple of lines "declare" tor for the "chkconfig" program, +# originally from SGI, used on Red Hat/Fedora and probably elsewhere. # # chkconfig: 2345 90 10 -# description: Onion Router +# description: Onion Router - A low-latency anonymous proxy +# -TORUSER= -TORGROUP= -TORBIN=@BINDIR@/tor -TORPID=@LOCALSTATEDIR@/run/tor/tor.pid -TORLOG=@LOCALSTATEDIR@/log/tor/tor.log -TORDATA=@LOCALSTATEDIR@/lib/tor +# Library functions +if [ -f /etc/rc.d/init.d/functions ]; then + . /etc/rc.d/init.d/functions +elif [ -f /etc/init.d/functions ]; then + . /etc/init.d/functions +fi -TORCONF=@CONFDIR@/torrc -# Strictly speaking, we don't need to su if we have --user and --group. -# "Belt and suspenders," says jbash. -TORARGS="--pidfile $TORPID --log \"notice file $TORLOG \" --runasdaemon 1 --datadirectory $TORDATA" -if [ "x$TORUSER" != "x" ]; then - TORARGS="$TORARGS --user $TORUSER" -fi -if [ "x$TORGROUP" != "x" ]; then - TORARGS="$TORARGS --group $TORGROUP" -fi -RETVAL=0 +TORCTL=@BINDIR@/torctl + +# torctl will use these environment variables +TORUSER=@TORUSER@ +export TORUSER +TORGROUP=@TORGROUP@ +export TORGROUP if [ -x /bin/su ] ; then SUPROG=/bin/su @@ -39,87 +46,33 @@ fi case "$1" in start) - if [ -f $TORPID ]; then - echo "tor appears to be already running (pid file exists)" - echo "Maybe you should run: $0 restart ?" - RETVAL=1 - else - echo -n "Starting tor..." - if [ "x$TORUSER" = "x" ]; then - $TORBIN -f $TORCONF $TORARGS - else - $SUPROG -c "$TORBIN -f $TORCONF $TORARGS" $TORUSER - fi - RETVAL=$? - if [ $RETVAL -eq 0 ]; then - echo " ok" - else - echo " ERROR!" - fi - fi + action $"Starting tor:" $TORCTL start + RETVAL=$? ;; stop) - if [ -f $TORPID ]; then - echo -n "Killing tor..." - kill `cat $TORPID` - RETVAL=$? - if [ $RETVAL -eq 0 ]; then - echo " ok" - else - echo " ERROR!" - fi - else - echo "Unable to kill tor: $TORPID does not exist. Assuming already dead." - RETVAL=0 - fi - ;; - - reload) - if [ -f $TORPID ]; then - echo -n "Sending HUP to tor..." - kill -HUP `cat $TORPID` - RETVAL=$? - if [ $RETVAL -eq 0 ]; then - echo " ok" - else - echo " ERROR!" - fi - else - echo "Unable to kill tor: $TORPID does not exist" - RETVAL=1 - fi + action $"Stopping tor:" $TORCTL stop + RETVAL=$? ;; restart) - $0 stop - if [ -f $TORPID ]; then - rm -f $TORPID - fi - $0 start + action $"Restarting tor:" $TORCTL restart + RETVAL=$? + ;; + + reload) + action $"Reloading tor:" $TORCTL reload + RETVAL=$? ;; status) - PID=`cat $TORPID 2>/dev/null` - if [ "$PID" != "" ]; then - torstat=`ps -p $PID | grep -c "^$PID"` - if [ $torstat ]; then - echo "tor is running ($PID)" - else - echo "tor is not running (looks like it crashed, look for core? $PID)" - fi - else - echo "tor is not running (exited gracefully)" - fi - ;; - - log) - cat $TORLOG + $TORCTL status + RETVAL=$? ;; *) - echo "Usage: $0 (start|stop|restart|status|log)" - exit 1 + echo "Usage: $0 (start|stop|restart|reload|status)" + RETVAL=1 esac exit $RETVAL diff --git a/contrib/torctl.in b/contrib/torctl.in index 4faa8f0a0b..4136bd9434 100644 --- a/contrib/torctl.in +++ b/contrib/torctl.in @@ -4,15 +4,15 @@ # to controlling The Onion Router # # The exit codes returned are: -# 0 - operation completed successfully -# 1 - -# 2 - Command not supported -# 3 - Could not be started -# 4 - Could not be stopped -# 5 - -# 6 - -# 7 - -# 8 - +# 0 - operation completed successfully. For "status", tor running. +# 1 - For "status", tor not running. +# 2 - Command not supported +# 3 - Could not be started or reloaded +# 4 - Could not be stopped +# 5 - +# 6 - +# 7 - +# 8 - # # When multiple arguments are given, only the error from the _last_ # one is reported. @@ -27,26 +27,30 @@ EXEC=tor TORBIN="@BINDIR@/$EXEC" # # the path to the configuration file -TORCONF=@CONFDIR@/torrc +TORCONF="@CONFDIR@/torrc" # # the path to your PID file -PIDFILE=@LOCALSTATEDIR@/run/tor/tor.pid +PIDFILE="@LOCALSTATEDIR@/run/tor/tor.pid" # # The path to the log file -LOGFILE=@LOCALSTATEDIR@/log/tor/tor.log +LOGFILE="@LOCALSTATEDIR@/log/tor/tor.log" # # The path to the datadirectory -TORDATA=@LOCALSTATEDIR@/lib/tor +TORDATA="@LOCALSTATEDIR@/lib/tor" # -# The USER and GROUP names: -# TORUSER and TORGROUP if defined in the environment, else LOGNAME and GROUP -# respectively. -TORUSER= -TORGROUP= - -TORARGS="--pidfile $PIDFILE --log \"notice file $LOGFILE \" --runasdaemon 1" +TORARGS="--pidfile $PIDFILE --log \"notice file $LOGFILE\" --runasdaemon 1" TORARGS="$TORARGS --datadirectory $TORDATA" +# If user and group names are set in the environment, then use them; +# otherwise run as the invoking user (or whatever user the config +# file says)... unless the invoking user is root. The idea here is to +# let an unprivileged user run tor for her own use using this script, +# while still providing for it to be used as a system daemon. +if [ "x`id -u`" = "x0" ]; then + TORUSER=@TORUSER@ + TORGROUP=@TORGROUP@ +fi + if [ "x$TORUSER" != "x" ]; then TORARGS="$TORARGS --user $TORUSER" fi @@ -54,24 +58,10 @@ if [ "x$TORGROUP" != "x" ]; then TORARGS="$TORARGS --group $TORGROUP" fi -if [ -x /bin/su ] ; then - SUPROG=/bin/su -elif [ -x /sbin/su ] ; then - SUPROG=/sbin/su -elif [ -x /usr/bin/su ] ; then - SUPROG=/usr/bin/su -elif [ -x /usr/sbin/su ] ; then - SUPROG=/usr/sbin/su -else - SUPROG=/bin/su -fi - -# the command used to start -if [ "x$TORUSER" = "x" ]; then - START="$TORBIN -f $TORCONF $TORARGS" -else - START="$SUPROG -c \\"$TORBIN -f $TORCONF $TORARGS\\" $TORUSER" -fi +# We no longer wrap the Tor daemon startup in an su when running as +# root, because it's too painful to make the use of su portable. +# Just let the daemon set the UID and GID. +START="$TORBIN -f $TORCONF $TORARGS" # # -------------------- -------------------- @@ -86,23 +76,23 @@ fi checkIfRunning ( ) { # check for pidfile PID=unknown - if [ -f $PIDFILE ] ; then + if [ -f $PIDFILE ] ; then PID=`/bin/cat $PIDFILE` if [ "x$PID" != "x" ] ; then - if kill -0 $PID 2>/dev/null ; then - STATUS="$EXEC (pid $PID) running" - RUNNING=1 - else - STATUS="PID file ($PIDFILE) present, but $EXEC ($PID) not running" - RUNNING=0 - fi + if kill -0 $PID 2>/dev/null ; then + STATUS="$EXEC (pid $PID) running" + RUNNING=1 + else + STATUS="PID file ($PIDFILE) present, but $EXEC ($PID) not running" + RUNNING=0 + fi else STATUS="$EXEC (pid $PID?) not running" RUNNING=0 fi else - STATUS="$EXEC apparently not running (no pid file)" - RUNNING=0 + STATUS="$EXEC apparently not running (no pid file)" + RUNNING=0 fi return } @@ -117,14 +107,14 @@ do echo "$0 $ARG: $EXEC (pid $PID) already running" continue fi - if $START ; then + if eval "$START" ; then echo "$0 $ARG: $EXEC started" - # Make sure it stayed up! - /bin/sleep 1 - checkIfRunning - if [ $RUNNING -eq 0 ]; then - echo "$0 $ARG: $EXEC (pid $PID) quit unexpectedly" - fi + # Make sure it stayed up! + /bin/sleep 1 + checkIfRunning + if [ $RUNNING -eq 0 ]; then + echo "$0 $ARG: $EXEC (pid $PID) quit unexpectedly" + fi else echo "$0 $ARG: $EXEC could not be started" ERROR=3 @@ -138,40 +128,68 @@ do if kill -15 $PID ; then echo "$0 $ARG: $EXEC stopped" else - /bin/sleep 1 - if kill -9 $PID ; then - echo "$0 $ARG: $EXEC stopped" - else - echo "$0 $ARG: $EXEC could not be stopped" - ERROR=4 - fi + /bin/sleep 1 + if kill -9 $PID ; then + echo "$0 $ARG: $EXEC stopped" + else + echo "$0 $ARG: $EXEC could not be stopped" + ERROR=4 + fi fi # Make sure it really died! /bin/sleep 1 checkIfRunning if [ $RUNNING -eq 1 ]; then echo "$0 $ARG: $EXEC (pid $PID) unexpectedly still running" + ERROR=4 fi ;; restart) $0 stop start ;; + reload) + if [ $RUNNING -eq 0 ]; then + echo "$0 $ARG: $STATUS" + continue + fi + if kill -1 $PID; then + /bin/sleep 1 + echo "$EXEC (PID $PID) reloaded" + else + echo "Can't reload $EXEC" + ERROR=3 + fi + ;; status) echo $STATUS + if [ $RUNNING -eq 1 ]; then + ERROR=0 + else + ERROR=1 + fi ;; - *) + log) + cat $LOGFILE + ;; + help) echo "usage: $0 (start|stop|restart|status|help)" /bin/cat < Packager: Nick Mathewson Requires: openssl >= 0.9.6 -BuildRequires: openssl-devel >= 0.9.6, rpm-build >= 4.0 -Requires(pre): shadow-utils, /usr/bin/id, /bin/date, /bin/sh +BuildRequires: openssl-devel >= 0.9.6 +%if %{is_fc} +BuildRequires: rpm-build >= 4.0 +%endif +Requires(pre): /usr/bin/id, /bin/date, /bin/sh Requires(pre): %{_sbindir}/useradd, %{_sbindir}/groupadd Source0: http://tor.eff.org/dist/%{name}-%{native_version}.tar.gz @@ -114,8 +118,9 @@ BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root Tor is a connection-based low-latency anonymous communication system. This package provides the "tor" program, which serves as both a client and -a relay node. Scripts will automatically create a "%{runuser}" user and -group, and set tor up to run as a daemon when the system is rebooted. +a relay node. Scripts will automatically create a "%{toruser}" user and +a "%{torgroup}" group, and set tor up to run as a daemon when the system +is rebooted. Applications connect to the local Tor proxy using the SOCKS protocol. The local proxy chooses a path through a set of relays, in @@ -135,49 +140,24 @@ for high-stakes anonymity. %prep %setup -q -n %{name}-%{native_version} -# Patch the startup script to use the right user and group IDs. Force -# the use of /bin/sh as the shell for the "tor" account. -ed -s contrib/tor.sh.in << '/EOF/' > /dev/null -,s/^TORUSER=$/TORUSER=%{runuser}/ -,s/^TORGROUP=$/TORGROUP=%{runuser}/ -,s:\$SUPROG:$SUPROG -s /bin/sh: -# -# Save and exit ed -w -q -/EOF/ - %build -%configure +%configure --with-tor-user=%{toruser} --with-tor-group=%{torgroup} %make %install %makeinstall -# Install init script. +# Install init script and control script %__mkdir_p ${RPM_BUILD_ROOT}%{_initrddir} %__install -p -m 755 contrib/tor.sh ${RPM_BUILD_ROOT}%{_initrddir}/%{name} +%__install -p -m 755 contrib/torctl ${RPM_BUILD_ROOT}%{_bindir} # Set up config file; "sample" file implements a basic user node. %__install -p -m 644 ${RPM_BUILD_ROOT}%{_sysconfdir}/%{name}/torrc.sample ${RPM_BUILD_ROOT}%{_sysconfdir}/%{name}/torrc -# Create a logrotate file. This should really be a source file, -# but hey... +# Install the logrotate control file. %__mkdir_p -m 755 ${RPM_BUILD_ROOT}%{_sysconfdir}/logrotate.d -%__cat > ${RPM_BUILD_ROOT}%{_sysconfdir}/logrotate.d/%{name} << /EOF/ -%{_localstatedir}/log/%{name}/*log { - daily - rotate 5 - compress - delaycompress - missingok - notifempty - sharedscripts - postrotate - /etc/rc.d/init.d/tor reload > /dev/null - endscript -} -/EOF/ +%__install -p -m 644 contrib/tor.logrotate ${RPM_BUILD_ROOT}%{_sysconfdir}/logrotate.d/%{name} # Directories that don't have any preinstalled files %__mkdir_p -m 700 ${RPM_BUILD_ROOT}%{_localstatedir}/lib/%{name} @@ -187,37 +167,76 @@ q %clean [ "${RPM_BUILD_ROOT}" != "/" ] && rm -rf ${RPM_BUILD_ROOT} -# These scripts are probably wrong for Mandrake or SuSe. They're certainly +# These scripts are probably wrong for Mandrake or SuSE. They're certainly # wrong for Debian, but what are you doing using RPM on Debian? + %pre -[ -f %{_initrddir}/%{name} ] && /sbin/service %{name} stop -if [ ! -n "`/usr/bin/id -g %{runuser} 2>/dev/null`" ]; then + +# If tor is already installed and running (whether installed by RPM +# or not), then kill it, but remember that it was running. +%__rm -f /tmp/${name}-was-running-%{version}-%{release} +if [ -f %{_initrddir}/%{name} ] && /sbin/service %{name} status ; then + /sbin/service %{name} stop + touch /tmp/${name}-was-running-%{version}-%{release} +fi + +# +# Create a user and group if need be +# +if [ ! -n "`/usr/bin/id -g %{torgroup} 2>/dev/null`" ]; then # One would like to default the GID, but doing that properly would # require thought. - %{_sbindir}/groupadd %{runuser} 2> /dev/null + %{_sbindir}/groupadd %{torgroup} 2> /dev/null fi -if [ ! -n "`/usr/bin/id -u %{runuser} 2>/dev/null`" ]; then +if [ ! -n "`/usr/bin/id -u %{toruser} 2>/dev/null`" ]; then # One would also like to default the UID, but doing that properly would # also require thought. - if [ -x /sbin/nologin ]; then - %{_sbindir}/useradd -r -g %{runuser} -d %{_localstatedir}/lib/%{name} -s /sbin/nologin %{runuser} 2> /dev/null + if [ -x %{_sbindir}/nologin ]; then + %{_sbindir}/useradd -r -g %{torgroup} -d% {_localstatedir}/lib/%{name} -s %{_sbindir}/nologin %{toruser} 2> /dev/null else - %{_sbindir}/useradd -r -g %{runuser} -d %{_localstatedir}/lib/%{name} -s /bin/false %{runuser} 2> /dev/null + %{_sbindir}/useradd -r -g %{torgroup} -d %{_localstatedir}/lib/%{name} -s /bin/false %{toruser} 2> /dev/null fi fi exit 0 %post -/sbin/chkconfig --add %{name} + +# If this is a new installation, use chkconfig to put tor in the +# default set of runlevels. If it's an upgrade, leave the existing +# configuration alone. +if [ $1 -eq 1 ]; then + /sbin/chkconfig --add %{name} +fi + +# Older tor RPMS used a different username for the tor daemon. +# Make sure the runtime data have the right ownership. +%__chown -R %{toruser}.%{torgroup} %{_localstatedir}/{lib,log,run}/%{name} + +if [ -f /tmp/${name}-was-running-%{version}-%{release} ]; then + /sbin/service %{name} start + %__rm -f /tmp/${name}-was-running-%{version}-%{release} +fi exit 0 %preun -/sbin/chkconfig --del %{name} -%__rm -f ${_localstatedir}/lib/%{name}/cached-directory -%__rm -f ${_localstatedir}/lib/%{name}/bw_accounting -%__rm -f ${_localstatedir}/lib/%{name}/control_auth_cookie -%__rm -f ${_localstatedir}/lib/%{name}/router.desc -%__rm -f ${_localstatedir}/lib/%{name}/fingerprint + +# If no instances of tor will be installed when we're done, make +# sure that it gets killed. We *don't* want to kill it or delete +# any of its data on uninstall if it's being upgraded to a new +# version, because the new version will actually already have +# been installed and started before the uninstall script for +# the old version is run, and we'd end up hosing it. +if [ $1 -le 0 ]; then + if [ -f %{_initrddir}/%{name} ] && /sbin/service %{name} status ; then + /sbin/service %{name} stop + fi + %/sbin/chkconfig --del %{name} + %__rm -f ${_localstatedir}/lib/%{name}/cached-directory + %__rm -f ${_localstatedir}/lib/%{name}/bw_accounting + %__rm -f ${_localstatedir}/lib/%{name}/control_auth_cookie + %__rm -f ${_localstatedir}/lib/%{name}/router.desc + %__rm -f ${_localstatedir}/lib/%{name}/fingerprint +fi exit 0 %files @@ -225,17 +244,30 @@ exit 0 %doc AUTHORS INSTALL LICENSE README ChangeLog doc/HACKING doc/TODO doc/FAQ %{_mandir}/man*/* %{_bindir}/tor +%{_bindir}/torctl %{_bindir}/torify %{_bindir}/tor-resolve %config %{_initrddir}/%{name} %config(noreplace) %attr(0644,root,root) %{_sysconfdir}/logrotate.d/%{name} -%dir %attr(0755,root,%{runuser}) %{_sysconfdir}/%{name}/ -%config(noreplace) %attr(0644,root,%{runuser}) %{_sysconfdir}/%{name}/* -%attr(0700,%{runuser},%{runuser}) %dir %{_localstatedir}/lib/%{name} -%attr(0750,%{runuser},%{runuser}) %dir %{_localstatedir}/run/%{name} -%attr(0750,%{runuser},%{runuser}) %dir %{_localstatedir}/log/%{name} +%dir %attr(0755,root,%{torgroup}) %{_sysconfdir}/%{name}/ +%config(noreplace) %attr(0644,root,%{torgroup}) %{_sysconfdir}/%{name}/* +%attr(0700,%{toruser},%{torgroup}) %dir %{_localstatedir}/lib/%{name} +%attr(0750,%{toruser},%{torgroup}) %dir %{_localstatedir}/run/%{name} +%attr(0750,%{toruser},%{torgroup}) %dir %{_localstatedir}/log/%{name} %changelog + +* Mon Jan 17 2005 John Bashinski +- Take runtime user and group names from configure system. Default + user/group names are now "_tor"; blame Roger... +- Make logrotate control file a separate file in the source distribution, + rather than creating it from the spec file. +- Properly handle the order in which RPM executes scriptlets on upgrade. + The old code would kill the daemon on upgrade. +- Start the tor daemon after installation if and only if it was + running before installation. Preserve runlevel setup on upgrade. +- Package the torctl script; the init script is now a wrapper around it. + * Tue Nov 5 2004 John Bashinski - Add skeletal support for multiple distributions - Even more ridiculous level of macro-ization @@ -258,4 +290,3 @@ exit 0 * Sat Jan 17 2004 John Bashinski - Basic spec file; tested with Red Hat 9. -