Re: [Tails-dev] A quick look at uwt

Delete this message

Reply to this message
Author: anonym
Date:  
To: The Tails public development discussion list
Subject: Re: [Tails-dev] A quick look at uwt
04/09/12 21:56, adrelanos wrote:
> intrigeri:
>>>> Buggy handling of wrapped commands whose arguments contain
>>>> spaces
>> [...]
>>> Confirmed. I don't know how to fix it. Ideas?
>
>> The answer might emerge from that question of mine:
>
>>>> (is going through getopt necessary for the wrapped command at
>>>> all?):
>
>> If the answer is "yes", then I suggest having a look at the
>> various options offered by getopt for whitespace / command-line
>> words parsing.
>
> The answer is: I don't know. I don't know the alternatives.
>
> Afaik getopt does not support multiple arguments, i.e. -i ip -p port.
> Only -i ip -o. (-o just as an option flag without additional argument.)


That's incorrect. getopt's optstring behaves just like the one you
currently use in uwt, e.g. colons after an option means that it takes an
argument.

> I haven't found any similar bash scripts. Search results are more
> questions than answers. Not sure if it's possible with bash at all.


Actially the `torify` script does exactly what you want, but without
using the -c option...

> If you could help with it, that'd be great.


IMHO, the issues of quoting and whitespaces are best left to the shell,
but for that to be possible you should do what most wrappers do; don't
take the wrapped command as an argument to an option of the wrapper, but
leave it in the end after all wrapper options (so, no -c option but how
torify, sudo, etc. works). As a plus, your wrapper would then behave
like most other wrappers, which is good for everyone's sanity.

Also, getopt is not well-suited for use in wrappers since it will
confuse options from the wrapped command with those of the wrapper, so
it's better to use ad-hoc options parsing. I don't know about getopts,
but I suspect it has the same issue.

The attached patch implements all the above, and I tested that it
handles quoting and whitespaces fine. For instance in:

    uwt -i 127.0.0.1 -p 9050 -t 5 gpg --list-keys "Micah Anderson"


the argument "Micah Anderson" is sent to gpg as one argument, not two,
just like we expect.

You may want to split up the patch to something more atomistic (for that
`git add -p` is your friend.) because I couldn't resist fixing some
style issues I saw along the way. Sorry.

Cheers!
diff --git a/aos_shared/usr/local/bin/uwt b/aos_shared/usr/local/bin/uwt
index 0159602..9ea9e9d 100755
--- a/aos_shared/usr/local/bin/uwt
+++ b/aos_shared/usr/local/bin/uwt
@@ -50,6 +50,8 @@
 # Note: When running applications as root, you also have to set and
 #       export that variable as root.


+NAME=$(basename $0)
+
# Define and ensure we have tsocks
# XXX: what if we do not have which?
TORSOCKS="`which torsocks`"
@@ -65,10 +67,9 @@ fi
#echo "UWT_VERBOSE: $UWT_VERBOSE"

 usage () {
-    echo "Usage: $0 [-h] [-v] [-t server_type] [-i ip] [-p port] [-c \"<command> [<options>...\"]"
-    echo "Example: $0 [-t 5] [-i 127.0.0.1] [-p 9050] [-c \"wget https://check.torproject.org\"]"
-        echo "sudo uwt -t 5 -i 192.168.1.10 -p 9104 -c \"/usr/bin/apt-get --yes dist-upgrade\""
-    exit 0
+        echo "Usage: $NAME [-h] [-v] -t server_type -i ip -p port <command> [<options>...]"
+        echo "Example: $NAME -t 5 -i 127.0.0.1 -p 9050 wget https://check.torproject.org"
+        echo "         sudo $NAME -t 5 -i 192.168.1.10 -p 9104 /usr/bin/apt-get --yes dist-upgrade"
 }


 set_id () {
@@ -82,30 +83,36 @@ if [ "$#" = 0 ]; then
     exit 1
 fi


-# Thanks to
-# http://aplawrence.com/Unix/getopts.html
-while getopts  "hvi:p:c:t:" FLAG
-do
-  #echo "FLAG: $FLAG | OPTARG: $OPTARG"
-  if [ "$FLAG" = "h" ]; then
-      usage
-  fi
-  if [ "$FLAG" = "v" ]; then
-      set -x
-      UWT_VERBOSE="1"
-  fi
-  if [ "$FLAG" = "i" ]; then
-      ip="$OPTARG"
-  fi
-  if [ "$FLAG" = "p" ]; then
-      port="$OPTARG"
-  fi
-  if [ "$FLAG" = "c" ]; then
-      command="$OPTARG"
-  fi
-  if [ "$FLAG" = "t" ]; then
-      server_type="$OPTARG"
-  fi
+while [ -n "$1" ]; do
+  case "$1" in
+      -h)
+          usage
+          exit 0
+          ;;
+      -v)
+          set -x
+          UWT_VERBOSE="1"
+          ;;
+      -i)
+          ip="$2"
+          shift
+          ;;
+      -p)
+          port="$2"
+          shift
+          ;;
+      -t)
+          server_type="$2"
+          shift
+          ;;
+      *)
+          command="`which $1`"
+          # From now on the complete to-be wrapped command + its args
+          # are stored in $@, which will expand like we want it for
+          # handling quoted arguments with whitespaces in it, etc.
+          break
+  esac
+  shift
 done


if [ -z "$ip" ]; then
@@ -124,35 +131,25 @@ if [ -z "$server_type" ]; then
fi

 if [ -z "$command" ]; then
-    echo "ERROR: command (-c) missing." >&2
+    echo "ERROR: command is missing." >&2
     exit 1
 fi


if [ "$UWT_VERBOSE" = "1" ]; then
- echo "uwt command: \"$command\""
+ echo "uwt command: \"$@\""
fi

-# Thanks to
-# http://ask.metafilter.com/80862/how-split-a-string-in-bash
-set -- $command
-
-exe="`which $1`"
-if [ "$exe" = "" ]; then
-    echo "UWT ERROR: $1 does not exist!" >&2
+if [ ! -x "$command" ]; then
+        echo "UWT ERROR: $1 is not an executable." >&2
     exit 1
-fi
-
-if [ -u `which "$1"` ]; then
+elif [ -u "$command" ]; then
     set_id $1 u
-elif [ -g `which "$1"` ]; then
+elif [ -g "$command" ]; then
     set_id $1 g
 fi


-if [ -x "$TORSOCKS" ]; then
-    # torsocks is installed.
-    true
-else
-    echo "$0: Unable to find torsocks in PATH." >&2
+if [ ! -x "$TORSOCKS" ]; then
+    echo "$NAME: Unable to find torsocks in PATH." >&2
     echo "    Perhaps you have not installed it?" >&2
     exit 1
 fi
@@ -180,14 +177,10 @@ echo "
 " > "$TORSOCKS_CONF_FILE"


# Check that we have got a torsocks config file
-if [ -r "$TORSOCKS_CONF_FILE" ]; then
- # ok
- # echo "TORSOCKS_CONF_FILE found."
- true
-else
+if [ ! -r "$TORSOCKS_CONF_FILE" ]; then
# Since identity corelation through circuit sharing is at risk,
# we should no longer let torsocks default to 9050.
- echo "$0: Missing torsocks configuration file \"$TORSOCKS_CONF_FILE\."
+ echo "$NAME: Missing torsocks configuration file \"$TORSOCKS_CONF_FILE\."
exit 1
fi

@@ -219,17 +212,14 @@ if [ "$UWT_LOCALHOST" = "1" ]; then
     echo "exec torsocks \"$@\""
   fi


-  if [ -f "/usr/share/aos/aos_workstation" ]; then
-    true
-  elif [ -f "/usr/share/aos/aos_gateway" ]; then
-    true
-  else
+  if [ ! -f "/usr/share/aos/aos_workstation" ] && \
+     [ ! -f "/usr/share/aos/aos_gateway" ]; then
     echo "uwt will not work for localhost connections." >&2
     exit 1
   fi
-  
+
   # Safe in aos.
-  exec "$@"  
+  exec "$@"


else

@@ -243,4 +233,4 @@ else

fi

-# End of uwt script.
\ No newline at end of file
+# End of uwt script.