#!/bin/sh # # "runxas" # # version 0.09, 2001/01/10 # # Copyright (C) 2000 Peter Watkins # # 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 # # script to run an X application within the protection of an # Xnest session, as another user, to prevent unauthorized # access to system resources (e.g., data files) or X resources # # Because SSH commands run with minimal PATH values, etc., this # script opens a nested X session with a window manager and xterm # so you can run other apps from that environment # # Thanks go to Don E. Groves, Jr. and Przemek Klosowski # begin Configuration settings ------------------------------------------- # Number of diff DISPLAY numbers to try # This may depend on your system's capability, your firewall config, etc. max_tries=5 # Window manager for nest (DISPLAY used to tell it where to run) preferred_wm=twm # (I had keyboard problems using fvwm2 and sawmill, e.g. # certain events would cause keyboard presses inside the # Xnest to become unresponsive. 'twm' is very light and # seems not to have those keyboard problems. Don't even # ask about using enlightenment inside Xnest. ;-) ) # Command prompt (passed -display $displayName arguments) preferred_term=xterm # Any extra command-line args it needs # (`xterm -ls` makes xterm act as a login shell) preferred_term_args="-ls" # # (Pick your favorite; others have suggested "Eterm" with "-l" args) # Initial geometry WxH+x+y xnest_geometry="900x675+107+7" # PATH var to provide to Xnest user xnest_path="/bin:/usr/bin:/usr/X11R6/bin" # extra options for Xnest xnest_options="-fp unix/:-1" # if you get error setting default font path # end Configuration settings --------------------------------------------- # TODO # - provide ability to launch specific apps # - man page/docs # - command-line options (pass options to Xnest?) (mimic su?) # - ~/.runxas/ to keep track of state? # - protect against Xnest bugs? (wouldn't StackGuard be nice?) show_usage() { # Show usage and exit echo "Usage: $0 username [displayName]" echo "NOTE: Be careful when specifying a displayName!" exit 1 } next_display() { # This finds a new DISPLAY value based on the current value display=`echo "${display}" | awk -F: '{print $1 ":" ($2 + 1)}'` } app_available() { # takes a single argument, an app name, and tests for its availabilty [ -z $(which $1 2>/dev/null) ] && return 1 # else we found a copy return 0 } # things needed to make an xauth cookie extra_apps="" use_mcookie="Y" app_available mcookie || { # need other apps to emulate mcookie extra_apps="printf od cut" # and a source of random data if [ ! -r /dev/random ]; then echo "$0: Error: this script needs read access to /dev/random" exit 3 fi use_mcookie="N" } # are the required apps present? basic_apps="rm awk xauth mktemp ssh cat Xnest expr" for app in $basic_apps $extra_apps ${preferred_wm} ${preferred_term}; do app_available $app || { echo "$0: Error: this script requires ${app}. Please install ${app}, modify your PATH, or modify $0" exit 2 } done if [ -z "${DISPLAY}" ]; then echo "$0: Error: the DISPLAY environment variable must be set" exit 4 fi # enough arguments? if [ $# -lt 1 ]; then show_usage fi username="$1" display="" if [ $# -eq 1 ]; then # Use the next number after the current DISPLAY value display="${DISPLAY}" next_display else display="$2" if [ "$(echo ${display} | awk -F: '{print $2}')" = "$(echo ${DISPLAY} | awk -F: '{print $2}')" ]; then # attempting to use our current DISPLAY! echo "$0: Warning: display number matches that of DISPLAY (\"${DISPLAY}\"): choosing new value" next_display fi fi if [ -z "${display}" ]; then echo "No valid DISPLAY value found" show_usage fi # Create temp file for xauth information # preference is to use the current TMPDIR value if [ -z "${TMPDIR}" ]; then TMPDIR=/tmp fi TMPFILE=`mktemp -q ${TMPDIR}/runxas.XXXXXX` if [ $? -ne 0 ]; then echo "$0: Error: Can't create temp file, exiting..." exit 5 fi got_display=0 num_tries=0 while [ \( $got_display -eq 0 \) -a \( $num_tries -lt $max_tries \) ]; do # See if the display should be OK # Sample responses: # 1) If something is running on the server # Xlib: connection to ":1.0" refused by server # Xlib: Client is not authorized to connect to Server # 2) If nothing is there # _X11TransSocketUNIXConnect: Can't connect: errno = 111 # xauth: (argv):1: unable to open display ":2". # 3) If something is there & you're authorized: no output # (hopefully this won't happen! [we should test first]) num_tries=`expr $num_tries + 1` # First, grab the xauth info for ${display} so we don't hose ourselves cat /dev/null > ${TMPFILE} xauth extract ${TMPFILE} "${display}" > /dev/null 2> /dev/null xtest=`xauth generate "${display}" . 2>&1 | grep "= 111"` if [ -z "${xtest}" ]; then # No "errno = 111" errors means the server may be in use if [ -s ${TMPFILE} ]; then # restore the xauth info we backed up earlier xauth merge ${TMPFILE} fi next_display else got_display=1 fi done if [ $got_display -eq 0 ]; then echo "$0: Unable to find good display value after ${max_tries} attempts; please specify a value" show_usage fi # Create xauth information if [ $use_mcookie = "Y" ]; then # use mcookie to make an xauth cookie random_data=`mcookie` else # get some random data, format in hex, use first 64 chars # (which actually makes a longer cookie than 'mcookie') random_data=`printf %x $(od -N 65 /dev/random) | cut -c -64` fi # make the xauth key xauth -f ${TMPFILE} add "${display}" . $random_data # start the Xnest session (with xauth file removed after Xnest dies) echo "$0: starting Xnest on ${display}" (Xnest ${xnest_options} "${display}" -sss -geometry ${xnest_geometry} -auth ${TMPFILE} ; rm ${TMPFILE}) & # Find the wm and term wmpath=`which ${preferred_wm}` termpath=`which ${preferred_term}` xauthpath=`which xauth` # Start the wm and term (and pass the xauth information) xauth -f ${TMPFILE} nextract - "${display}" | ssh -x -l "${username}" localhost "${xauthpath} -q nmerge -; DISPLAY=\"${display}\" export DISPLAY; PATH=${xnest_path} export PATH;($wmpath &);($termpath -display ${display} ${preferrred_term_args} &)" # Note that the TMPFILE containing the xauth secret MUST BE KEPT # while the Xnest session is running!!! exit 0