shosei

rdesktop-wrapper

May 11th, 2012
89
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Bash 8.40 KB | None | 0 0
  1. #!/bin/bash
  2. # rdesktop-wrapper
  3. # This is a wrapper around rdesktop to handle ssh tunnels and a nickname index
  4. #
  5. # * You can specify a tunneled host as if it were in your local network
  6. # * You can specify a host mapped in your ~/.rdesktop_table file
  7. # * You can specify user accounts as part of the hostname, like user@host
  8. # * Three new options:  --list-maps, --map-help, --completion-help
  9. # * You can have entries in '~/.rdesktop_table' like:
  10. ##     #title   [user@]server[:port]    # default port=3389, user=$USER
  11. ##     hannibal localhost:13389
  12. ##     wipeout  cyn@wipeout
  13. ## * If you use alternate remote desktop ports in your ssh tunnels, you can
  14. ##   put a comment that says "rdesktop" above it.  Say "rdesktop next 4" to
  15. ##   indicate that the next four nonwhitespace lines are remote desktop tunnels.
  16. ##
  17. ## v0.6, (c) 2006-2012 < cyn.cc >
  18. ##########################################
  19. ### 0.1 Initial alpha-release; stable for ME, used more than daily.
  20. ###     Rather messy code, known bug with spaced arguments, needs rehaul,
  21. ###     and the inclusion of perl is silly (but more reliable than sed -r).
  22. ### 0.2 Better help
  23. ### 0.3 Fixed bug with more than one tunnel per host in ssh_config, zsh comp fix
  24. ### 0.4 Fixed nmap bug, there are likely more...
  25. ### 0.5 Now using bash for arrays so this works with quoted (spaced) parameters
  26. ### 0.6 Rewrote ssh_config parser, allow ssh_config comment hint
  27. ### You can debug this by setting $DEBUG to "true" before running this script
  28. ##########################################
  29. ### TODO
  30. ###   * Rewrite the whole thing in perl (lots of work; it works fine as is...)
  31. ###   * Reconsider blanket exclusion of wildcard hosts in sshd_config
  32. ###   * Test to see if connected to a host before okaying its ssh tunnels
  33. ###   * Get somebody to say they use and like this script
  34. ##########################################
  35.  
  36. help() { sed -e '/^## /!d' -e 's///' "`which $0 || echo $0`"; }
  37.  
  38. completion_help() { echo \
  39. 'For hosts tab completion in zsh, add these lines to your .zshrc:
  40. function _get_rdesktops() {
  41.  reply=(`
  42.    rdesktop --list-maps 2>/dev/null |sed -r "s/^port.*maps ([^:]+):.*ough/\1/"
  43.    _get_hosts
  44.  `)
  45. }
  46. compctl -K _get_rdesktops rdesktop'
  47. }
  48.  
  49. lookup_table=~/.rdesktop_table
  50. [ -n "$DEBUG" ] && debug() { echo "$*" >&2; } || debug() { true; }
  51.  
  52. # get list of maps from lookup table file
  53. get_lookups() {
  54.   [ -s "$lookup_table" ] && \
  55.     perl -ne 's/\W*#.*//; s/^(\S+)\s+/$1   \t/s; print if /./;' <"$lookup_table"
  56. }
  57.  
  58. # get list of ssh tunnels for port 3389 (and my alt, 33389) from ~/.ssh/config
  59. get_tunnels() {
  60.   perl -e '
  61.    sub report_tunnel {
  62.      my ($forward, $target, $host) = @_;
  63.      while ( length($forward) < 8 ) { $forward .= " "; }
  64.      $target =~ s/:3389$//;
  65.      while ( length($target) < 30 ) { $target .= " "; }
  66.      print "port $forward maps $target through $host\n";
  67.    }
  68.  
  69.    open (SSH_CONFIG, "< $ENV{HOME}/.ssh/config") or die $!;
  70.    while (<SSH_CONFIG>) {
  71.      chomp;
  72.      next unless /Host\s+([^*]+)$/;
  73.      my $host = $1;
  74.      do {
  75.        $_ = <SSH_CONFIG>;
  76.        last if ! defined;
  77.        if (/#.*\brdesktop\s*(?:(?:next\s*)?(\d+\b))?/) {
  78.          my $n = 1;
  79.          $n = $1 if ( defined($1) && $1 > 1 );
  80.          for (1; $n > 0; $n--) {
  81.            $_ = <SSH_CONFIG>;
  82.            last if ! defined;
  83.            s/#.*$//;
  84.            $_ = <SSH_CONFIG> if (/^\s*$/);
  85.            last if ! defined || ! /LocalForward\s+((?:\S*:)?\d+)\s+(\S+)/;
  86.            report_tunnel ($1, $2, $host);
  87.          }
  88.        }
  89.        if (/LocalForward(?:\s+|\s*=\s*)((?:\S*:)?\d+)\s+(\S+:3?3389\d*)\b/) {
  90.          report_tunnel ($1, $2, $host);
  91.        }
  92.      } while (! /Host\s/);
  93.    }
  94.    close (SSH_CONFIG);
  95.  '
  96. }
  97.  
  98. # just show the list and exit
  99. case x$*${args[*]} in
  100.   *-completion* ) completion_help; exit 0;;
  101.   *--map-help*  ) help; exit 0;;
  102.   *--????-maps* ) get_lookups; get_tunnels; exit 0;;
  103.   *--tunneltest*) get_tunnels; exit 0;;
  104.   *-h*          ) help=true ;;
  105. esac
  106.  
  107. # list order in path, like 'which -a' w/out aliases
  108. scanpath() {
  109.   for d in `echo $PATH |sed 's/:/ /g'`; do ls "$d/$1" 2>/dev/null; done
  110. }
  111.  
  112. debug "finding 'rdesktop' in path"
  113. [ -n "`echo $0 |grep /`" ] && apath="$0" && aline=1 || aline=2
  114. run=`scanpath rdesktop |grep -v "^$apath$" |sed "${aline}q;d"`
  115. [ -z "$run" ] && echo "No rdesktop executable found in path" <&2 && exit 2
  116. debug "we will use the second hit in the path, which is '$run'"
  117.  
  118. if [ -n "$help" ]; then
  119.   help; echo ''; $run -h; exit 0
  120. fi
  121.  
  122. # throw all but last argument into $args array
  123. while [ -n "$2" ]; do
  124.   # can't have -g and -A, so nix the -g (it doesn't make any sense anyway)
  125.   echo "x$*"|grep ".-A" >/dev/null && [ "$1" != "${1#-g}" ] && shift && continue
  126.   args[${i:-1}]="$1"
  127.   i=$(($i+1))
  128.   shift
  129. done
  130.  
  131. rd=`echo $1 |sed 's/^.*@//'`
  132. user=`echo $1 |sed -e "/@/!d" -e "s/@$rd$//" -e "s/^/-u /"`
  133. #user=`echo $1 |perl -ne 'if /\@/ { s/^([^@]+)\@.*$/-u $1/; print; }'`
  134. local=`echo $1 |perl -ne 'print if /\b(127\.0\.[0-9.]+|localhost.*)/'`
  135. [ -n "$local" ] && [ -z "`echo $local|grep :`" ] && local="$local:3389"
  136.  
  137. # try lookup table
  138. if [ -s "$lookup_table" ]; then
  139.   table=`get_lookups |perl -ne "print if /^\S*$rd\b/"`
  140.   debug "lookup table has data, host '$rd' best match is '$table'"
  141. fi
  142.  
  143. # try ssh config (but not if we are local!)
  144. if [ -z "$table" ]; then
  145.   debug "no match on table lookup, trying to search for '$rd' in ssh conf"
  146.  
  147.   if [ -n "$local" ]; then
  148.     port=`echo $local|sed 's/^.*://'` # we already set the default port above
  149.   else
  150.     port=`get_tunnels |perl -ne \
  151.       "if (/\b$rd\b/) "'{ s/^\S+\s(\d+).*$/$1/; print; }'`
  152.   fi
  153.  
  154.   [ -n "$port" ] && title=`get_tunnels |perl -ne \
  155.   "if (/port $port\\b.*\\b$rd\\b/)
  156.    { s/^.*maps\s//; s/[\t ]+/-/g; s/-$//; s/:3?3389//g; print; }"`
  157.  
  158.   [ -n "$title" ] && table="$title localhost:$port" \
  159.     && debug "found ssh-tunnel titled '$title' matching '$rd'" \
  160.     || debug "no ssh tunnel matches query '$rd'"
  161.  
  162. fi
  163.  
  164. # try the host literally
  165. if [ -z "$table" ]; then
  166.   debug "no match on ssh conf, testing if '$rd' is a literal host or host:port"
  167.   host=`echo $rd |sed "s/:.*$//"`
  168.   port=`echo $rd |sed "s/$host:*//"`
  169.   [ -z "$port" ] && port=3389
  170.   debug "  testing $host:$port"
  171.  
  172.   # nmap with timeouts (version 4+) is awesome!  ... why doens't 2s work!?
  173.   my_nmap() {
  174.     $tsocks nmap -P0 -sT -T4 --host-timeout 1501 -p"$1" "$2" 2>&1 |grep "$3";
  175.   }
  176.   # fall back to telnet if nmap doesn't report on the requested port
  177.   if my_nmap 25 localhost '^25/' >/dev/null
  178.     then
  179.       p=`my_nmap $port $host "^$port.*open"`
  180.       if [ -z "$p" ]; then
  181.         tsocks=tsocks && p=`my_nmap $port $host "^$port.*open"`
  182.         [ -z "$p" ] && unset tsocks || echo "works with tsocks"
  183.       fi
  184.       [ -n "$p" ] && go=true
  185.     else echo X |telnet -e X "$1" $2 >/dev/null 2>&1 && go=true
  186.   fi
  187.   [ -n "$go" ] && table="$rd $host:$port" && debug "literal works, using '$rd'"
  188. fi
  189.  
  190. if [ -z "$table" ]; then
  191.   debug "still nothing ... is '$rd' an argument?"
  192.   case $rd in
  193.     # no host, let real rdesktop give errors/help
  194.     -*) $run "${args[@]}" $rd; exit $? ;;
  195.   esac
  196.  
  197.   debug "not an argument ... spit out error message"
  198.   echo "`basename $0`: could not connect to \`$rd'"
  199.  [ -s "$lookup_table" ] && match=" match in the" \
  200.                         || map_help="- see `basename $0` --map-help"
  201.  echo "
  202. Found no$match lookup table at \`$lookup_table' $map_help
  203. Found no match in your ssh config for a tunneled rdesktop port (3389)
  204. Server \`$host' does not appear to accept TCP connections on port \`$port'
  205. Trying ping..."
  206.   ping -n -c3 "$host" 2>/dev/null
  207.  
  208. exit 2
  209. fi
  210.  
  211. if [[ -z "$tsocks" && "$table" =~ (10\.0\.101\.[0-9]+|\.bf)(:[0-9]+)?$ ]]; then
  212.   tsocks=tsocks
  213.   debug "tsocks enabled for table '$table'"
  214. fi
  215.  
  216. [ -z "$user" ] && [ -n "`echo $table|grep '@'`" ] && \
  217.   user=`echo $table |perl -pne 's/^.*\b([^\@]+)\@.*$/-u $1/'` # extract username
  218. [ -n "$user" ] && debug "a username will be specified with '$user'"
  219.  
  220. table=`echo $table |perl -pne 's/\s[^\@]+\@/ /'` # remove username form table
  221.  
  222. dbrun="$tsocks $run ${args[@]} $user -T $table"
  223. #debug "running '$dbrun'..."
  224. if debug is-on 2>&1 |grep is-on >/dev/null; then
  225.   debug "running:  '$run \\"
  226.  for a in "${args[@]}"; do debug "    \"$a\" \\"; done
  227.   debug "    $user \\"
  228.  debug "    -T $table"
  229. fi
  230. $tsocks $run "${args[@]}" $user -T $table
  231. RETVAL=$?
  232. [ $RETVAL != 0 ] && debug "command '$dbrun' failed with exit code '$RETVAL'" >&2
  233. exit $RETVAL
Advertisement
Add Comment
Please, Sign In to add comment