scp-restricted

Moving data files securely from one environment to another is a frequent business application requirement, so I was disappointed to learn scp doesn’t support a ‘least privilege’ approach ‘out-of-the-box’. The authors of O’Reilly’s book give an incomplete solution and note various issues, but that’s about it. Other solutions involve jailing SSH, a custom SSH shell like rssh or switching to WebDAV or ftps and using certificates. I thought these were overkill so I came up with this alternative to scp-wrapper

#!/bin/ksh
#
# scp-restricted
# 1.0  Piers C  Oct-07  Original
# Inspired by http://www.snailbook.com/faq/restricted-scp.auto.html
# Tested with OpenSSH 3.x server and Putty client
#
integer argc=0
typeset command="exec /usr/bin/scp"
typeset filename
readonly SCRIPTNAME=$(basename $0)

function fail {
  print "$SCRIPTNAME: $2" >&2
  print "$SCRIPTNAME: SSH original command should be 'scp [-v] [-t|-f] filename'" >&2
exit $1
}
if [[ "$1" == "-T" ]]; then # see test-scp-retricted
  command="print "${command}
fi

if [[ -z $SSH_ORIGINAL_COMMAND ]]; then
  fail 1 "environment variable SSH_ORIGINAL_COMMAND not set"
fi

for arg in $SSH_ORIGINAL_COMMAND; do
  argv[$argc]=$arg
  argc=argc+1
done

if (( $argc == 4 )); then
  if [[ ${argv[1]} != "-v" ]]; then
    fail 6 "arg 2 of 4 not '-v'"
  fi
  command=${command}" -v"
elif (( $argc != 3 )); then
  fail 2 "wrong number of args"
fi

if [[ ${argv[0]} != "scp" ]]; then
  fail 3 "arg[0] must be 'scp'"
fi

filename=${argv[argc-1]}
# be very conservative with filenames that we'll accept
if print ${filename} | egrep -vs '^[a-zA-Z0-9][.a-zA-Z0-9]*$'; then
  fail 5 "bad filename: $filename 
(must be alphanum, may include but not start with period)"
fi

if [[ ${argv[1]} == "-t" ||  ${argv[2]} == "-t" ]]; then
  cd $HOME/inbound || fail 7 "unable to cd ~/inbound"
  ${command} -t ${filename}
elif [[ ${argv[1]} == "-f" || ${argv[2]} == "-f" ]]; then
  cd $HOME/outbound || fail 8 "unable to cd ~/outbound"
  ${command} -f ${filename}
else
 fail 4 "args must include -t or -f"
fi
#end#
#!/bin/ksh
#
# test-scp-restricted
#
integer succeeded=0
integer failed=0

function dotest {
  export SSH_ORIGINAL_COMMAND=$1
  print "======================================"
  print 'SSH_ORIGINAL_COMMAND="'$SSH_ORIGINAL_COMMAND'"'
  print "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=="
  ./scp-restricted -T; rc=$?
  print "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=="
  if (( $rc == $2 )); then
    print 'exited ('$rc') - test **SUCCESS**'
    succeeded=$succeeded+1
  else
    print 'exited ('$rc') - test **FAILED**'
    failed=$failed+1
  fi
}
dotest "" 1
dotest "x" 2
dotest "x y z" 3
dotest "scp -p z" 4
dotest 'scp -t foo.dat' 0
dotest 'scp -t 7' 0
dotest "scp -t .." 5
dotest "scp -t a;ls" 5
dotest 'scp -t a*ls' 5
dotest 'scp -t a/ls' 5
dotest 'scp -t a�73ls' 5
dotest 'scp -f bar.dat' 0
print "Succeeded: $succeeded"
print "Failed: $failed"

Leave a Reply

Your email address will not be published.

Scroll to top