#!/bin/sh ########################################## ## rdesktop-wrapper 0.4, (c) 2006-2007 by Adam Katz , GPL ########################################## ## This is a wrapper around rdesktop to handle ssh tunnels and a nickname index ## * You can specify a tunneled host as if it were in your local network ## * You can specify a host mapped in your ~/.rdesktop_table file ## * You can specify user accounts as part of the hostname, like user@host ## * Three new options: --list-maps, --map-help, --completion-help ## * You can have entries in '~/.rdesktop_table' like: ## #title [user@]server[:port] # default port=3389, user=$USER ## hannibal localhost:13389 ## wipeout adam@wipeout ########################################## ### 0.1 Initial alpha-release; stable for ME, used more than daily. ### Rather messy code, known bug with spaced arguments, needs rehaul, ### and the inclusion of perl is silly (but more reliable than sed -r). ### 0.2 Better help ### 0.3 Fixed bug with more than one tunnel per host in ssh_config, zsh comp fix ### 0.4 Fixed nmap bug, there are likely more... ### You can debug this by setting $DEBUG to "true" before running this script ########################################## help() { sed -e '/^## /!d' -e 's///' "`which $0 || echo $0`"; } completion_help() { echo \ 'For hosts tab completion in zsh, add these lines to your .zshrc: function _get_rdesktops() { reply=(` rdesktop --list-maps 2>/dev/null |sed -r "s/^port.*maps ([^:]+):.*ough/\1/" _get_hosts `) } compctl -K _get_rdesktops rdesktop' } lookup_table=~/.rdesktop_table [ -n "$DEBUG" ] && debug() { echo "$*" >&2; } || debug() { true; } # get list of maps from lookup table file get_lookups() { [ -s "$lookup_table" ] && \ perl -ne 's/\W*#.*//; s/^(\S+)\s+/$1 \t/s; print if /./;' <"$lookup_table" } # get list of ssh tunnels for port 3389 from ~/.ssh/config get_tunnels() { cat ~/.ssh/config 2>/dev/null |perl -pne ' my $conf; while(<>) { s/#.*$//; $conf .= $_ if /Host\W|LocalForward.*:3389/ and ! /\*/; } $_ = $conf; s/\n\W*LocalForward\D+/ /gm; s/^[^:]*$|^\w+\W+//mg; ' |perl -pne ' s/^((\S+)\s[^:]+:\d+)\s+(.*:.*)$/$1\n$2 $3/; ' |perl -pne ' s/^(\S+)\s+(\d+)\s+([^:]+:\w+)/port $2\tmaps $3 \tthrough $1/; s/:3389(\tthrough)/$1/; ' } # just show the list and exit case x$*$args in *-completion* ) completion_help; exit 0;; *--map-help* ) help; exit 0;; *--????-maps* ) get_lookups; get_tunnels; exit 0;; --tunneltest ) get_tunnels; exit 0;; *-h* ) help=true ;; esac # list order in path, like 'which -a' w/out aliases scanpath() { for d in `echo $PATH |sed 's/:/ /g'`; do ls "$d/$1" 2>/dev/null; done } debug "finding 'rdesktop' in path" [ -n "`echo $0 |grep /`" ] && apath="$0" && aline=1 || aline=2 run=`scanpath rdesktop |grep -v "^$apath$" |sed "${aline}q;d"` [ -z "$run" ] && echo "No rdesktop executable found in path" <&2 && exit 2 debug "we will use the second hit in the path, which is '$run'" if [ -n "$help" ]; then help; echo ''; $run -h; exit 0 fi # throw all but last argument into $args # BUG: this strips out all quotes! while [ -n "$2" ]; do args="$args $1"; shift; done rd=`echo $1 |sed 's/^.*@//'` user=`echo $1 |sed -e "/@/!d" -e "s/@$rd$//" -e "s/^/-u /"` #user=`echo $1 |perl -ne 'if /\@/ { s/^([^@]+)\@.*$/-u $1/; print; }'` local=`echo $1 |perl -ne 'print if /\b(127\.0\.[0-9.]+|localhost.*)/'` [ -n "$local" ] && [ -z "`echo $local|grep :`" ] && local="$local:3389" # try lookup table if [ -s "$lookup_table" ]; then table=`get_lookups |perl -ne "print if /^\S*$rd\b/"` debug "lookup table has data, host '$rd' best match is '$table'" fi # try ssh config (but not if we are local!) if [ -z "$table" ]; then debug "no match on table lookup, trying to search for '$rd' in ssh conf" if [ -n "$local" ]; then port=`echo $local|sed 's/^.*://'` # we already set the default port above else port=`get_tunnels |perl -ne \ "if (/\b$rd\b/) "'{ s/^\S+\s(\d+).*$/$1/; print; }'` fi [ -n "$port" ] && title=`get_tunnels |perl -ne "if (/port $port\b/) { s/^.*maps\s//; s/\s+/-/g; s/-$//; s/:3389//g; print; }"` [ -n "$title" ] && table="$title localhost:$port" \ && debug "found ssh-tunnel titled '$title' matching '$rd'" \ || debug "no ssh tunnel matches query '$rd'" fi # try the host literally if [ -z "$table" ]; then debug "no match on ssh conf, testing if '$rd' is a literal host or host:port" host=`echo $rd |sed "s/:.*$//"` port=`echo $rd |sed "s/$host:*//"` [ -z "$port" ] && port=3389 debug " testing $host:$port" # nmap with timeouts (version 4+) is awesome! ... why doens't 2s work!? my_nmap() { nmap -P0 -sT -T4 --host-timeout 1501 -p"$@" 2>&1; } # fall back to telnet if nmap doesn't report on the requested port if [ -n "`my_nmap 25 localhost |grep '^25/'`" ] then p=`my_nmap $port $host |grep "^$port.*open"`; [ -n "$p" ] && go=true else echo X |telnet -e X "$1" $2 >/dev/null 2>&1 && go=true fi [ -n "$go" ] && table="$rd $host:$port" && debug "literal works, using '$rd'" fi if [ -z "$table" ]; then debug "still nothing ... is '$rd' an argument?" case $rd in # no host, let real rdesktop give errors/help -*) $run $args $rd; exit $? ;; esac debug "not an argument ... spit out error message" echo "`basename $0`: could not connect to \`$rd'" [ -s "$lookup_table" ] && match=" match in the" \ || map_help="- see `basename $0` --map-help" echo " Found no$match lookup table at \`$lookup_table' $map_help Found no match in your ssh config for a tunneled rdesktop port (3389) Server \`$host' does not appear to accept TCP connections on port \`$port'" exit 2 fi [ -z "$user" ] && [ -n "`echo $table|grep '@'`" ] && \ user=`echo $table |perl -pne 's/^.*\b([^\@]+)\@.*$/-u $1/'` [ -n "$user" ] && debug "a username will be specified with '$user'" table=`echo $table |perl -pne 's/\s[^\@]+\@/ /'` run="$run $args $user -T $table" debug "running '$run'..." $run RETVAL=$? [ $RETVAL != 0 ] && debug "command '$run' failed with exit code '$RETVAL'" >&2 exit $RETVAL