Description: Security fix for the oarsh command
 Patches the oarsh script and oar.conf configuration file to remove a vulnerability which could allow a root exploit.
Author: pierre.neyron@free.fr
Origin: upstream
---
This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
Index: oar/sources/core/tools/oar.conf.in
===================================================================
--- oar.orig/sources/core/tools/oar.conf.in
+++ oar/sources/core/tools/oar.conf.in
@@ -532,20 +532,46 @@ CPUSET_PATH="/oar"
 # OARSH #
 ###############################################################################
 #
-# This variable must be set to enable the use of oarsh from a frontale node
-# Otherwise you must not set this variable if you are not on a frontale
+# The following variable must be set to enable the use of oarsh on frontend
+# machines. On other machines (compute nodes), it does not need to be set.
 OARSH_OARSTAT_CMD="%%BINDIR%%/oarstat"
 
-# The following variable adds options to ssh (or OPENSSH_CMD if configured).
-# If one option is not handled by your ssh version just remove it BUT be
-# careful because these options are there for security reasons
-OARSH_OPENSSH_DEFAULT_OPTIONS="-oProxyCommand=none -oPermitLocalCommand=no"
+# The following variable gives the OpenSSH options which the oarsh command must
+# understand in order to parse user commands.
+# The value of OPENSSH_OPTSTR must match the option string of OpenSSH ssh
+# command installed on the system (mind checking it is up-to-date, as OpenSSH 
+# development is very active), which can be found in the ssh.c file of the 
+# OpenSSH sources. For instance, the following command extracts the option
+# string of OpenSSH 7.2p2 :
+#
+# $ cd path/to/openssh/sources/ 
+# $ grep getopt -A1 ssh.c | sed 's/.*"\(.\+\)".*/\1/' | xargs | sed 's/ //g'
+# 1246ab:c:e:fgi:kl:m:no:p:qstvxACD:E:F:GI:KL:MNO:PQ:R:S:TVw:W:XYy
+#
+OPENSSH_OPTSTR="1246ab:c:e:fgi:kl:m:no:p:qstvxACD:E:F:GI:KL:MNO:PQ:R:S:TVw:W:XYy"
+
+# The following variable sets the OpenSSH options which oarsh actually uses.
+# Any option which is filtered out from the OPENSSH_OPTSTR variable above is 
+# just ignored (see oarsh -v for debug)
+# WARNING: if not fitlered out, some options may allow root exploit using oarsh.
+# At least the following OpenSSH options are recommanded to be fitlered out: 
+#  -a -A -i -l -o -p -E -F -G -I -w
+# For more information, see: http://oar.imag.fr/wiki:security_tips
+OPENSSH_OPTSTR_FILTERED="1246b:c:e:fgkm:nqstvxCD:KL:MNO:PQ:R:S:TVW:XYy"
+
+# The following variable forces OpenSSH configuration options for the ssh call 
+# made by in oarsh, so that, for security reasons, they cannot be set by the
+# user (whenever "o:" is not filtered out in the OPENSSH_OPTSTR_FILTERED
+# variable above).
+# WARNING: for security, do not change unless you know what you are doing
+OARSH_OPENSSH_DEFAULT_OPTIONS="-oProxyCommand=none -oPermitLocalCommand=no -oUserKnownHostsFile=%%OARHOMEDIR%%/.ssh/known_hosts"
 
-# If you set this variable to something different from 0 then oarsh will act
-# like a normal ssh **without** CPUSET restriction.
-# WARNING: this is a critical functionality (this is only useful if users want
-# to have a command to connect on every nodes without taking care of there ssh
-# configuration and act like a ssh)
+# If the following variable is set to a value which is not 0, oarsh will act
+# like a normal ssh, **without** the CPUSET isolation mechanism.
+# WARNING: this disable a critical functionality
+# This can however be useful and different from simply using ssh, as it
+# provides users with a mechanism which allows to connect to compute nodes
+# without having to care of their ssh configuration (e.g. key setup)
 #OARSH_BYPASS_WHOLE_SECURITY="0"
 
 ###############################################################################
Index: oar/sources/core/tools/oarsh/oarsh.in
===================================================================
--- oar.orig/sources/core/tools/oarsh/oarsh.in
+++ oar/sources/core/tools/oarsh/oarsh.in
@@ -14,7 +14,11 @@ umask 0022
 
 OARSH_OARSTAT_CMD=
 OPENSSH_CMD=/usr/bin/ssh
-OARSH_OPENSSH_DEFAULT_OPTIONS="-oProxyCommand=none -oPermitLocalCommand=no"
+OPENSSH_OPTSTR="1246ab:c:e:fgi:kl:m:no:p:qstvxACD:E:F:I:KL:MNO:PQ:R:S:TVw:W:XYy"
+# Filtered out OpenSSH options: -a -A -i -l -o -p -E -F -I -w
+OPENSSH_OPTSTR_FILTERED="1246b:c:e:fgkm:nqstvxCD:KL:MNO:PQ:R:S:TVW:XYy"
+# Forced OpenSSH configuration options
+OARSH_OPENSSH_DEFAULT_OPTIONS="-oProxyCommand=none -oPermitLocalCommand=no -oUserKnownHostsFile=%%OARHOMEDIR%%/.ssh/known_hosts"
 CPUSET_PATH=
 
 # If you set this variable to something different from 0 then oarsh will act
@@ -22,7 +26,105 @@ CPUSET_PATH=
 OARSH_BYPASS_WHOLE_SECURITY="0"
 ###############################################################################
 
-source "$OARCONFFILE" || exit 2
+# Source OAR config file, allowing the administrator to overwrite variables
+. "$OARCONFFILE" || exit 2
+
+# Parse OpenSSH options
+# OPENSSH_OPTSTR can be extracted from the ssh.c file of OpenSSH sources
+unset OARSH_DEBUG
+parse_opts() {
+	OPTIND=
+	while getopts ":$OPENSSH_OPTSTR" OPT; do
+    if [ "$OPT" == "v" ]; then
+      OARSH_DEBUG=1
+    fi
+    if [ "$OPT" == "i" ]; then
+      OAR_JOB_KEY_FILE=$OPTARG
+    fi
+    unset OPTFOUND
+    for ((i=0;i<${#OPENSSH_OPTSTR};i++)); do
+      if [ "x${OPENSSH_OPTSTR:$((i+1)):1}" == "x:" ]; then
+        if [ "$OPT" == "${OPENSSH_OPTSTR:$((i++)):1}" ]; then
+          OARSH_OPT[$OARSH_OPTCOUNT]=$OPT
+          OARSH_OPTARG[$((OARSH_OPTCOUNT++))]=$OPTARG
+          OPTFOUND=1
+        fi
+      else
+        if [ "$OPT" == "${OPENSSH_OPTSTR:$i:1}" ]; then
+          OARSH_OPT[OARSH_OPTCOUNT]=$OPT
+          OARSH_OPTARG[$((OARSH_OPTCOUNT++))]=""
+          OPTFOUND=1
+        fi
+      fi
+      [ -n "$OPTFOUND" ] && break
+    done
+    [ -n "$OPTFOUND" ] && continue
+    echo "oarsh: unknown option -$OPTARG" 1>&2
+    exit 7
+  done
+}
+
+# Parse command line in the OpenSSH form
+# Expected syntax: "oarsh [opts] [user@]<host> [opts] [command]"
+unset OARSH_OPT
+unset OARSH_OPTARG
+OARSH_ERROR=0
+OARSH_OPTCOUNT=0
+parse_opts "$@"
+shift $((OPTIND-1))
+OARSH_HOST="${1##*@}"
+if [ -z "$OARSH_HOST" ]; then
+  echo "oarsh: cannot retrieve host"
+  exit 7
+fi
+OARSH_USER="${1/%$OARSH_HOST/}"
+OARSH_USER="${OARSH_USER%@}"
+shift 1
+parse_opts "$@"
+shift $((OPTIND-1))
+REMOTE_CMD="$@"
+
+# Debug output
+if [ -n "$OARSH_DEBUG" ]; then
+  for ((i=0; i < $OARSH_OPTCOUNT; i++)); do
+    echo "debug oarsh: OARSH_OPT[$i]=-${OARSH_OPT[$i]}${OARSH_OPTARG[$i]}" 1>&2
+  done
+  cat 1>&2 <<EOF
+debug oarsh: OARSH_OPTCOUNT=$OARSH_OPTCOUNT
+debug oarsh: OARSH_HOST=$OARSH_HOST
+debug oarsh: OARSH_USER=$OARSH_USER
+debug oarsh: OARSH_ERROR=$OARSH_ERROR
+debug oarsh: REMOTE_CMD=$REMOTE_CMD
+EOF
+fi
+
+# Filter OpenSSH options
+unset OPT
+OPTCOUNT=0
+for ((j=0; j < $OARSH_OPTCOUNT; j++)); do
+  unset OPTFOUND
+  for ((i=0; i < ${#OPENSSH_OPTSTR_FILTERED}; i++)); do
+    if [ "${OPENSSH_OPTSTR_FILTERED:$i:1}" == ":" ]; then
+      continue
+    fi
+    if [ "${OARSH_OPT[$j]}" == "${OPENSSH_OPTSTR_FILTERED:$i:1}" ]; then
+      OPTFOUND=1
+      if [ -z "${OARSH_OPTARG[$j]}" ]; then
+        OPT[$((OPTCOUNT++))]="-${OARSH_OPT[$j]}"
+      else
+        OPT[$((OPTCOUNT++))]="-${OARSH_OPT[$j]} ${OARSH_OPTARG[$j]}"
+      fi
+    fi
+  done
+  if [ -z "$OPTFOUND" -a -n "$OARSH_DEBUG" ]; then
+    echo "debug oarsh: filtered out -${OARSH_OPT[$j]} ${OARSH_OPTARG[$j]}" 1>&2
+  fi
+done
+
+# Debug output
+if [ -n "$OARSH_DEBUG" ]; then
+  echo "debug oarsh: OPT=${OPT[@]}" 1>&2
+fi
 
 # Add security option for X11 forwarding
 XAUTH_LOCATION="%%XAUTHCMDPATH%%"
@@ -55,15 +157,15 @@ fi
 # (oarsh acts like a ssh and can connect on every nodes)
 if [ "$OARSH_BYPASS_WHOLE_SECURITY" != "0" ]; then
     export OAR_CPUSET="undef"
-    exec $OPENSSH_CMD $OARSH_OPENSSH_DEFAULT_OPTIONS -oSendEnv="OAR_CPUSET OAR_JOB_USER" "$@"
-    echo "oarsh: Failed to connect using cpuset environement"
+    exec $OPENSSH_CMD $OARSH_OPENSSH_DEFAULT_OPTIONS -oSendEnv="OAR_CPUSET OAR_JOB_USER" "${OPT[@]}" $OARSH_HOST -- "$REMOTE_CMD"
+    echo "oarsh: Failed to connect using cpuset environement" 1>&2
     exit 5
 fi
 
 # -1- try connection using a user provided job key file for a job using the job key mechanism
 if [ -n "$OAR_JOB_KEY_FILE" ] 
 then
-    # first, get rid of remaining unused .Xautority.{pid} files if any...
+    # first, get rid of remaining unused jobkey files if any...
     for f in $OAR_RUNTIME_DIRECTORY/oarsh.jobkey.*; do
         [ -e "/proc/${f#$OAR_RUNTIME_DIRECTORY/oarsh.jobkey.}" ] || rm -f $f
     done
@@ -79,8 +181,8 @@ then
     umask $TMPOLDUMASK
 
     umask $OLDUMASK
-    exec $OPENSSH_CMD $OARSH_OPENSSH_DEFAULT_OPTIONS -i $TMP_JOB_KEY_FILE "$@"
-    echo "oarsh: Failed to connect using the job key: $OAR_JOB_KEY_FILE"
+    exec $OPENSSH_CMD $OARSH_OPENSSH_DEFAULT_OPTIONS -i $TMP_JOB_KEY_FILE "${OPT[@]}" $OARSH_HOST -- "$REMOTE_CMD"
+    echo "oarsh: Failed to connect using the job key: $OAR_JOB_KEY_FILE" 1>&2
     exit 3
 fi
 
@@ -90,27 +192,31 @@ fi
 TMP_JOB_KEY_FILE="$OAR_RUNTIME_DIRECTORY/$OARDO_USER.jobkey"
 if [ -r $TMP_JOB_KEY_FILE ]; then
     umask $OLDUMASK
-    exec $OPENSSH_CMD $OARSH_OPENSSH_DEFAULT_OPTIONS -i $TMP_JOB_KEY_FILE "$@"
-    echo "oarsh: Failed to connect using the cpuset job key: $TMP_JOB_KEY_FILE"
+    exec $OPENSSH_CMD $OARSH_OPENSSH_DEFAULT_OPTIONS -i $TMP_JOB_KEY_FILE "${OPT[@]}" $OARSH_HOST -- "$REMOTE_CMD"
+    echo "oarsh: Failed to connect using the cpuset job key: $TMP_JOB_KEY_FILE" 1>&2
     exit 4
 fi
 
 if [ "$CPUSET_PATH" != "" ]; then
     if [ -r /proc/self/cpuset ]; then
-        OAR_CPUSET=$(< /proc/self/cpuset)
-        if [ "${OAR_CPUSET%/*}" = "$CPUSET_PATH" ] || [ "${OAR_CPUSET%/*}" = "$CPUSET_PATH/" ]; then
+        if [ -n "$GET_CURRENT_CPUSET_CMD" ]; then
+            OAR_CPUSET=$(bash -c "$GET_CURRENT_CPUSET_CMD")
+        else
+            OAR_CPUSET=$(< /proc/self/cpuset)
+        fi
+        if [ "${OAR_CPUSET%/*}" == "$CPUSET_PATH" ] || [ "${OAR_CPUSET%/*}" == "$CPUSET_PATH/" ]; then
             JOB_KEY_FILE="$OAR_RUNTIME_DIRECTORY/${OAR_CPUSET##*/}.jobkey"
             if [ -r $JOB_KEY_FILE ]; then
                 umask $OLDUMASK
-                exec $OPENSSH_CMD $OARSH_OPENSSH_DEFAULT_OPTIONS -i $JOB_KEY_FILE "$@"
-                echo "oarsh: Failed to connect using the cpuset job key: $JOB_KEY_FILE"
+                exec $OPENSSH_CMD $OARSH_OPENSSH_DEFAULT_OPTIONS -i $JOB_KEY_FILE "${OPT[@]}" $OARSH_HOST -- "$REMOTE_CMD"
+                echo "oarsh: Failed to connect using the cpuset job key: $JOB_KEY_FILE" 1>&2
                 exit 4
             fi
             export OAR_CPUSET
             export OAR_JOB_USER=$OARDO_USER
             umask $OLDUMASK
-            exec $OPENSSH_CMD $OARSH_OPENSSH_DEFAULT_OPTIONS -oSendEnv="OAR_CPUSET OAR_JOB_USER" "$@"
-            echo "oarsh: Failed to connect using cpuset environement"
+            exec $OPENSSH_CMD $OARSH_OPENSSH_DEFAULT_OPTIONS -oSendEnv="OAR_CPUSET OAR_JOB_USER" "${OPT[@]}" $OARSH_HOST -- "$REMOTE_CMD"
+            echo "oarsh: Failed to connect using cpuset environement" 1>&2
             exit 5
         fi
     fi
@@ -161,8 +267,8 @@ if [ -n "$OAR_JOB_ID" ]; then
     export OAR_CPUSET
 
     umask $OLDUMASK
-    exec $OPENSSH_CMD $OARSH_OPENSSH_DEFAULT_OPTIONS -oSendEnv="OAR_CPUSET OAR_JOB_USER" "$@"
-    echo "oarsh: Failed to connect using cpuset environement"
+    exec $OPENSSH_CMD $OARSH_OPENSSH_DEFAULT_OPTIONS -oSendEnv="OAR_CPUSET OAR_JOB_USER" "${OPT[@]}" $OARSH_HOST -- "$REMOTE_CMD"
+    echo "oarsh: Failed to connect using cpuset environement" 1>&2
     exit 5
 fi