#!/bin/sh -u # Script to fetch information from a student VM. # Put this on a web site and use wget to pull it and send it into /bin/sh: # # wget -nv -O - http://thisfile | /bin/sh # Uses ssh to connect to the CLS, pulls a one-line command line to run, # runs it and sends all stdout back to the CLS. Any stderr causes abort. # For debugging, set ASSIGNMENTFETCH=debug in the environment. # -Ian! D. Allen - idallen@idallen.ca - www.idallen.com PATH=/bin:/usr/bin:/sbin:/usr/sbin ; export PATH LC_ALL=C ; export LC_ALL umask 077 VERSION='1' TEACHUSER='idallen' COURSETERM='cst8177/13w' ASSIGNMENT='assignment09' CLSREMOTE=cst8177.idallen.ca CLSLOCAL=cst8177-alg.idallen.ca HOSTNAME=$( hostname ) cmd="$HOSTNAME ${0##*/}" # This fetch below sends us some script stuff to execute locally, and we # send the output back. # FETCH="~$TEACHUSER/$COURSETERM/$ASSIGNMENT/${ASSIGNMENT}check --fetch" if [ "${ASSIGNMENTFETCH-}" = 'debug' ] ; then FETCH="$FETCH -i" VERSION="$VERSION DEBUG" fi # Do a bit of user-friendly USER setting in case run with USER=root # case "${USER-}" in root | "" ) echo 1>&2 "$cmd: Cannot use USER='${USER-}' to ssh into CLS" echo 1>&2 "$cmd: Run this as root with USER set to your CLS account userid" USER=${SUDO_USER-$HOSTNAME} echo 1>&2 "$cmd: Trying USER='${USER-}' instead ..." ;; esac echo " " echo "---------------------------------------------------------------------------" echo "$HOSTNAME: FETCH version $VERSION. Connecting to CLS as USER='${USER-}' using ssh" echo "---------------------------------------------------------------------------" WHOAMI=$( whoami ) if [ "$WHOAMI" != 'root' ] ; then echo 1>&2 "$cmd: ERROR: Run this as root with USER set to your CLS account userid" echo 1>&2 "$cmd: Running as user '$WHOAMI' with USER='${USER-}' -- nothing done" exit 1 fi # USER should be set to your own CLS userid, not "root". # Have to be fussy about USER since too many bad login attempts will get # you locked out of the CLS. # If USER isn't set correctly, try SUDO_USER, then, HOSTNAME, since it # should be the same as USER. # while : ; do case "${USER-}" in [a-z][a-z][a-z0-9][a-z0-9][0-9][0-9][0-9][0-9] ) break ;; # students cst8207[abc] | cst8177[abc] ) break ;; # test accounts $TEACHUSER | idallen | kelleyt | donnelr ) break ;; # instructors $HOSTNAME | ${SUDO_USER-xxzxzxzxzxzxzx} ) echo 1>&2 "$cmd: ERROR: Cannot use USER='${USER-}' to ssh into CLS" echo 1>&2 "$cmd: Run this as root with USER set to your CLS account userid" exit 1 ;; * ) # is this "use the SUDO_USER or HOSTNAME on bad USER" trick useful? echo 1>&2 "$cmd: ERROR: Cannot use USER='${USER-}' to ssh into CLS" echo 1>&2 "$cmd: Run this as root with USER set to your CLS account userid" NEWUSER=${SUDO_USER-$HOSTNAME} echo 1>&2 "$cmd: Incorrect USER '${USER-}'; trying USER=$NEWUSER" USER=$NEWUSER echo " " ;; esac done # Unit 0 stdin has the script being read when run as "cat script | sh", # so we need to find the real tty if issuing a prompt. # Unit 2 could still be a real tty; could use it to read the answer. # # Don't prompt if unit 1 stdout is not also a tty because the prompt # appears out-of-sequence before buffered stdout when doing "script | more". # CLS=$CLSREMOTE if [ -t 1 -a -t 2 ] ; then read 0<&2 -p "$HOSTNAME: Use local Algonquin IP $CLSLOCAL [y/N]? " ans || exit $? if [ "$ans" = 'y' ] ; then CLS=$CLSLOCAL fi fi REMOTE="$USER@$CLS" echo "$HOSTNAME: Please wait; using ssh to connect to user '$USER' on $CLS ..." tmp=/tmp/ifoo$$ tmp2=$tmp.errs # Send error message to both stderr (for user) and stdout (back to CLS). # Error () { echo 1>&2 "$cmd: ERROR: $*" echo 1>&2 "$cmd: ERROR: try again or contact instructor" echo "$cmd: ERROR: $(date): $*" echo "REMOTE: $REMOTE" echo "FETCH: $FETCH" hostname ; id ; uptime ; ifconfig ; printenv ; ps -efww } # The tricky part. Use a prefix nc to feed output back into # the remote system *after* having read the command to run with "read". # This means we use the same ssh connection to both read a command to # run and then send its stdout back to the CLS (via the prefix nc). # There has to be a better way to do this. -IAN! # nc -d -l 12345 | ssh -e none -2 -4 -k -T -x "$REMOTE" $FETCH | { read -r line if [ "${line-}" = "" ] ; then { Error "Cannot read line from remote '$REMOTE'" ; } \ | nc localhost 12345 exit 1 fi { printf "%s" "$line" | sh >$tmp ; } 2>$tmp2 if [ -s $tmp2 ] ; then { Error "Errors executing commands from '$REMOTE'" ; cat $tmp2 ; } \ | nc localhost 12345 exit 1 fi if [ ! -s $tmp ] ; then { Error "Empty output file generated from '$REMOTE'" ; } \ | nc localhost 12345 exit 1 fi sum=$( sum <$tmp ) nc localhost 12345 <$tmp read -r remsum if [ "$sum" != "$remsum" ] ; then Error "Checksum local '$sum' != checksum remote '$remsum'" >/dev/null else rm $tmp $tmp2 fi exec cat }