The previous post in this series explained how the SSH connection layer works. SSH connections can host logical data pipes called SSH channels, which can be used for interactive sessions, running remote commands, and port forwarding.
Interactive sessions include remote terminal sessions, running of remote commands, and running subsystems. Subsystems are sets of remote commands that are pre-defined on the server machine. The most common subsystem available is SFTP, which provides commands to transfer and manipulate files. SFTP is also known as the SSH File Transfer Protocol, and is a competitor to FTPS – traditional FTP over an SSL/TLS connection.
The SFTP subsystem runs over the SSH transport layer, but it is a sophisticated message-based protocol in its own right. SFTP messages are transmitted as the data field of the transport layer’s SSH_MSG_CHANNEL_DATA message
SFTP messages are in a standard format, as shown below:
uint32 length byte type uint32 request-id ... type specific fields ...
The first field is the length of the message, excluding the length field, and next is the message type. The third field is the request id – every request sent from the client has a request id, and the server’s reply must include the corresponding request id.
Some of the more important SFTP messages together with their type ids are shown and described below:
SSH_FXP_INIT 1 SSH_FXP_VERSION 2 SSH_FXP_OPEN 3 SSH_FXP_CLOSE 4 SSH_FXP_READ 5 SSH_FXP_WRITE 6 SSH_FXP_STATUS 101 SSH_FXP_DATA 103
SSH_FXP_INIT is the first message sent by the client to initiate the SFTP session, and the server replies with SSH_FXP_VERSION, indicating the versions it supports.
SSH_FXP_OPEN requests the server to open a file (or optionally create it if it does not exist), while SSH_FXP_CLOSE closes a file. SSH_FXP_READ asks to read a certain byte range from a file, and the server responds with SSH_FXP_DATA, which contains the requested bytes. SSH_FXP_WRITE is used to write data to a file, and one of its fields is the data to write (as well as the offset into the file).
If any of the above commands fail, SSH_FXP_STATUS is returned with an error code indicating the type of error that occurred. It is also used to signal a successful write in response to SSH_FXP_WRITE.
There are also commands for other standard file and directory operations, such as removing files (SSH_FXP_REMOVE), renaming files (SSH_FXP_RENAME), and creating and removing directories (SSH_FXP_MKDIR, SSH_FXP_RMDIR). Directories are read by opening them (SSH_FXP_OPENDIR) and sending SSH_FXP_READDIR requests. Again, SSH_FXP_STATUS is used to indicate success or failure of these requests.
There is no specific SFTP message to terminate an SFTP session – instead, the client closes the SSH channel being used.
It is important to note that SFTP is an entirely different protocol to traditional FTP, i.e. it is not FTP commands sent over an SSH connection. By contrast, FTPS is FTP commands sent over an SSL/TLS connection. The two protocols are easily confused, as they are both secure protocols for transferring files.