Although I normally only use
scp
, I'm periodically reminded that OpenSSH actually supports two file transfer mechanisms, because there's also SFTP. If you are someone like me, you may eventually wind up wondering if these two ways of transferring files with (Open)SSH fundamentally work in the same way, or if there is some real difference between them.
I will skip to the end: sort of yes and sort of no. As usually configured,
scp
and SFTP wind up working in the same way on the server side but they get there through different fundamental mechanisms in the SSH protocol and thus they take somewhat different paths in OpenSSH. What happens when you use
scp
is simpler to explain, so let's start there.
How
scp
works is the same as how
rsync
does. When you do '
scp
file apps0:/tmp/
',
scp
uses
ssh
to connect to the remote host and run a copy of
scp
with a special undocumented flag that means 'the other end of this conversation is another
scp
, talk to it with your protocol'. You can see this in
ps
output on your machine, where it will look something like this:
/usr/bin/ssh -x -oForwardAgent=no -oPermitLocalCommand=no -oClearAllForwardings=yes -- apps0 scp -t /tmp/
(This is how the traditional BSD
rcp
command works under the hood, and the HISTORY section of the
scp
manpage says that
scp
was originally based on
rcp
.)
By contrast, how SFTP works is that it is what is called a SSH subsystem , which is a specific part of the SSH connection protocol . More specifically it is the "sftp" subsystem, for which there is actually a draft protocol specification ( with OpenSSH extensions ). Since the client explicitly asks the server for SFTP (instead of just saying 'please run this random Unix command'), the server knows what is going on and can implement support for its end of the SFTP protocol in whatever way it wants to.
As it happens, the normal OpenSSH server configuration implements the "sftp" subsystem by running
sftp-server
(this is configured in
/etc/ssh/sshd_config
). For various reasons it does so via your login shell, so if you peek at your server's process list while you're running a
sftp
session, it will look like this:
cks 25346 sshd: cks@notty | 25347 sh -c /usr/lib/openssh/sftp-server | 25348 /usr/lib/openssh/sftp-server
On your local machine, the OpenSSH
sftp
command doesn't bother to have its own implementation of the SSH protocol and so on; instead it runs
ssh
in a special mode to invoke a remote subsystem instead of a remote command:
/usr/bin/ssh -oForwardX11 no -oForwardAgent no -oPermitLocalCommand no -oClearAllForwardings yes -oProtocol 2 -s -- apps0 sftp
However, this is not a universal property of SFTP client programs. A SFTP client program may embed its own implementation of SSH, and this implementation may support different key exchange methods, ciphers, and authentication methods than the user's regular full SSH does.
(We ran into a case recently where a user had a SFTP client that only supported weak Diffie-Hellman key exchange methods that modern versions of OpenSSH
sshd
don't normally support. The user's regular SSH client worked fine.)
So in the end,
scp
and SFTP both wind up running magic server programs under shells on the SSH server, and they both run
ssh
on the client. They give slightly different arguments to
ssh
and obviously run different programs (with different arguments) on the server. However, SFTP makes it more straightforward for the server to implement things differently because the client explicitly asks 'please talk this documented protocol with me'; unlike with
scp
, it is the server that decides to implement the protocol by running '
sh -c sftp-server
'. OpenSSH
sshd
has an option to implement SFTP internally, and you could easily write an alternate SSH daemon that handled SFTP in a different way.
It's theoretically possible to handle
scp
in a different way in your SSH server, but you would have to recognize
scp
by knowing that a request to run the command '
scp -t <something>
' was special. This is not unheard of; git operates over SSH by running internal git commands on the remote end ( cf ), and so if you want to provide remote git repositories without exposing full Unix accounts you're going to have to interpret requests for those commands and do special things. Github does this along with other magic, especially since everyone uses the same remote SSH login (that being git@github.com).