#!/bin/sh
# ***************************************************************************
# *                                                                         *
# *                                                                         *
# *   Copyright (C) 2008 by Robert Hogan                                    *
# *   robert@roberthogan.net                                                *
# *   Copyright (C) 2012 by Jacob Appelbaum <jacob@torproject.org>          *
# *   Copyright (C) 2013 by David Goulet <dgoulet@ev0ke.net>                *
# *                                                                         *
# *   This program is free software; you can redistribute it and/or modify  *
# *   it under the terms of the GNU General Public License as published by  *
# *   the Free Software Foundation; either version 2 of the License, or     *
# *   (at your option) any later version.                                   *
# *                                                                         *
# *   This program is distributed in the hope that it will be useful,       *
# *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
# *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
# *   GNU General Public License for more details.                          *
# *                                                                         *
# *   You should have received a copy of the GNU General Public License     *
# *   along with this program; if not, write to the                         *
# *   Free Software Foundation, Inc.,                                       *
# *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
# ***************************************************************************
# *                                                                         *
# *   This is a modified version of a source file from the Tor project.     *
# *   Original copyright information follows:                               *
# ***************************************************************************
# Wrapper script for use of the torsocks(8) transparent socksification library
#
# There are three forms of usage for this script:
#
# /usr/bin/torsocks program [program arguments...]
#
# This form sets the users LD_PRELOAD environment variable so that torsocks(8)
# will be loaded to socksify the application then executes the specified 
# program (with the provided arguments). The following simple example might 
# be used to ssh to www.foo.org via a torsocks.conf(5) configured socks server:
#
# /usr/bin/torsocks ssh www.foo.org
#
# The second form allows for torsocks(8) to be switched on and off for a
# session (that is, it adds and removes torsocks from the LD_PRELOAD environment
# variable). This form must be _sourced_ into the user's existing session
# (and will only work with bourne shell users):
#
# . /usr/bin/torsocks on
# telnet www.foo.org 
# . /usr/bin/torsocks off
# 
# Or
# 
# source /usr/bin/torsocks on
# telnet www.foo.org
# source /usr/bin/torsocks off
#
# This script is originally from the debian torsocks package by
# Tamas Szerb <toma@rulez.org>
# Modified by Robert Hogan <robert@roberthogan.net> April 16th 2006
# Modified by David Goulet <dgoulet@ev0ke.net> 2013

prefix=/usr
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
LIBDIR="${libdir}/torsocks"
LIB_NAME="libtorsocks"
SHLIB_EXT="so"
SHLIB="${LIBDIR}/${LIB_NAME}.${SHLIB_EXT}"

# Set LD_PRELOAD variable with torsocks library path.
set_ld_preload ()
{
	if [ -z "$LD_PRELOAD" ]; then
		export LD_PRELOAD="${SHLIB}"
	else
		echo $LD_PRELOAD | grep -q "${SHLIB}" || \
			export LD_PRELOAD="${SHLIB} $LD_PRELOAD"
	fi

	# OS X specific env variable
	case "$OSTYPE" in
		darwin*)
			export DYLD_FORCE_FLAT_NAMESPACE=1
			;;
	esac
}

# Report error due to Apple's System Integrity Protection.
macos_sip_error ()
{
	echo "ERROR: $1 is located in a directory protected by Apple's System Integrity Protection." >&2
	exit 1
}

# Check if SIP is enabled and if the user is about to violate the blacklist.
macos_sip_check ()
{
	local app_path="$1"

	case "$OSTYPE" in
		darwin*)
			# We need to figure out if Apple's System Integrity Protection is
			# enabled on the users' system.
			if /usr/bin/csrutil status | grep -q enabled; then
				local abs_app_dir=`cd "$(dirname "$app_path")" && pwd -P`

				# It seems like /usr/** (with an exception of /usr/local/**),
				# /System/**, /sbin/**, and /bin/** are currently protected
				# using SIP.
				case "$abs_app_dir/`basename $app_path`" in
					/usr/local/*)
						# Must be listed before the match on /usr/*
						;;
					/usr/*|/System/*|/sbin/*|/bin/*)
						macos_sip_error $app_path
						;;
				esac
			fi
			;;
	esac
}

# Spawn a torified shell.
tor_shell ()
{
	set_ld_preload
	echo "$0: New torified shell coming right up..."
	${SHELL:-/bin/sh}
}

torify_app ()
{
	local app_path=`which $1`
	local getcap=`PATH="$PATH:/usr/sbin:/sbin" which getcap`
	local caps=

	if [ -z $1 ]; then
		echo "Please provide an application to torify." >&2
	elif [ -z $app_path ]; then
		echo "ERROR: $1 cannot be found." >&2
		exit 1
	fi

	# This must be before torifying because getcap uses cap_get_file(3)
	# via syscall(2) which breaks torsocks.
	if [ -n "$getcap" ]; then
		caps=`$getcap $app_path`
	fi

	# Check if Apple's System Integrity Protection is enabled if the user is
	# running on macOS.
	macos_sip_check $app_path

	# NEVER remove that line or else nothing it torified.
	set_ld_preload

	if [ -u $app_path ]; then
		echo "ERROR: $1 is setuid. torsocks will not work on a setuid executable." >&2
		exit 1
	elif [ -g $app_path ]; then
		echo "ERROR: $1 is setgid. torsocks will not work on a setgid executable." >&2
		exit 1
	elif [ -n "$caps" ]; then
		echo "ERROR: $1 gains the following elevated capabilities. torsocks will \
not work with privledged executables.
$caps" >&2
		exit 1
	fi

	exec "$@"
}

usage ()
{
	echo "torsocks 2.2.0"
	echo ""
	echo "$0 [OPTIONS] [COMMAND [arg ...]]"
	echo ""
	echo "usage: $0 command args"
	echo ""
	echo "Options:"
	echo "  -h, --help         Show this help"
	echo "      --shell        Spawn a torified shell"
	echo "      --version      Show version"
	echo "  -d, --debug        Set debug mode."
	echo "  -u, --user NAME    Username for the SOCKS5 authentication"
	echo "  -p, --pass NAME    Password for the SOCKS5 authentication"
	echo "  -i, --isolate      Automatic tor isolation. Can't be used with -u/-p"
	echo "  -a, --address HOST Specify Tor address"
	echo "  -P, --port PORT    Specify Tor port"
	echo "  on, off            Set/Unset your shell to use Torsocks by default"
	echo "                     Make sure to source the call when using this option. (See Examples)"
	echo "  show, sh           Show the current value of the LD_PRELOAD"
	echo ""
	echo "Examples:"
	echo ""
	echo "Simple use of torsocks with SSH"
	echo "    $ torsocks ssh user@host.com -p 1234"
	echo ""
	echo "Set your current shell in Tor mode."
	echo "    $ . torsocks on"
	echo ""
	echo "Please see torsocks(1), torsocks.conf(5) and torsocks(8) for more information."
}

# Check if we are being sourced.
check_script_sourced()
{
	if [ "$_" = "$0" ]; then
		echo "Torsocks MUST be sourced for this command to work" >&2
		echo "  $ . torsocks $1" >&2
		exit 1
	fi
}

if [ $# -eq 0 ] ; then
	usage
	exit 1
fi

# Ensure libtorsocks exists,
if [ ! -f $SHLIB ]; then
   echo "$0: $SHLIB does not exist! Try re-installing torsocks."
   exit
fi

while true;
do
	case "$1" in
		on)
			check_script_sourced $1
			set_ld_preload
			echo "Tor mode activated. Every command will be torified for this shell."
			break
			;;
		off)
			check_script_sourced $1
			export LD_PRELOAD=`echo -n $LD_PRELOAD | sed "s#$SHLIB *##"`
			if [ -z "$LD_PRELOAD" ]; then
				unset LD_PRELOAD
				case "$OSTYPE" in
					darwin*)
						unset DYLD_FORCE_FLAT_NAMESPACE
						;;
				esac
			fi
			echo "Tor mode deactivated. Command will NOT go through Tor anymore."
			break
			;;
		show|sh)
			echo "LD_PRELOAD=\"$LD_PRELOAD\""
			break
			;;
		-h|--help)
			usage
			break
			;;
		-u|--user)
			if [ -z $2 ]; then
				echo "Missing username to -u" >&2
				exit 1
			fi
			export TORSOCKS_USERNAME=$2
			shift
			;;
		-p|--pass)
			if [ -z $2 ]; then
				echo "Missing password to -p" >&2
				exit 1
			fi
			export TORSOCKS_PASSWORD=$2
			shift
			;;
		-a|--address)
			if [ -z $2 ]; then
				echo "Missing address to -a" >&2
				exit 1
			fi
			export TORSOCKS_TOR_ADDRESS=$2
			shift
			;;
		-P|--port)
			if [ -z $2 ]; then
				echo "Missing port to -P" >&2
				exit 1
			fi
			export TORSOCKS_TOR_PORT=$2
			shift
			;;
		-i|--isolate)
			export TORSOCKS_ISOLATE_PID=1
			;;
		-d|--debug)
			# Set full DEBUG with 5 being the highest possible level.
			export TORSOCKS_LOG_LEVEL=5
			;;
		--shell)
			tor_shell
			break
			;;
		--version)
			echo "Torsocks 2.2.0"
			break
			;;
		*)
			torify_app "$@"
			break
			;;
	esac
	shift
done
