SSH:TDG
SSH: The Secure Shell (The Definitive Guide)
Barrett, Silverman, & Byrnes / O’Reilly

SSH Frequently Asked Questions

How do I allow a user to use scp or sftp, but not allow regular ssh (i.e. forbid getting a shell or running other programs)?


This answer is that this is a rather tricky thing to do right. Both scp1 and scp2 run ssh as a subprocess to connect to the remote host and run the appropriate server to talk to — scp -[tf] and sftp-server, respectively. So, the best you can do is to restrict the user to only running the file-transfer server.

The simplest way to do this is to make the target account special-purpose, by giving it a shell which only allows runing the file-transfer server. SSH always uses the shell to run remote programs, so this is a reliable restriction. SSH invokes the shell program with the option -c program to run program; your replacement should accept either scp with appropriate arguments, or sftp-server, as appropriate. SSH2 comes with ssh-dummy-shell for exactly this purpose, though naturally it only handles sftp.

If you don't want to limit the account this way, then it gets harder to do this reliably. The next thing to try would be public-key authentication with a forced command. It's simple with SSH2:

  # SSH2
  [remote:~/.ssh2/authorization]
  key users_key.pub
  command /usr/local/bin/sftp-server
With SSH1, this is more complicated, because the client passes arguments to scp in the remote command. For example:
  client command             runs this on server
  ----------------------------------------------
  scp foo server:bar         scp -t bar
  scp server:bar foo         scp -f bar
  scp *.txt server:dir       scp -d -t dir
So, you need to use a wrapper program to restrict it. Here's an example:
  # SSH1
  [remote:~/.ssh/authorized_keys]
  command="/path/to/scp-wrapper" 1024 37 1440913682374...
scp-wrapper Perl script

Now, as given so far, each of these solutions has a glaring hole: the authorization and authorized_keys files are writable by the target account. These measures are easily circumvented by simply using scp to overwrite those files. So, you need to protect them from change by the target account. You can make the account's SSH control directory and its contents unwritable where it is, or you can change its location e.g. with the sshd2 UserConfigDirectory statement.

Beyond that, though, there are still more holes. For example, SSH runs the user's shell to exec the remote command, with $SHELL -c "command". So you can simply scp any commands at all that you want to run into the remote shell startup file (e.g. ~/.bashrc), and they'll be executed the next time you scp something. So really you need to lock down the remote home directory so it's not writable by the user, and create a separate area for depositing files.