RFC 913

Simple File Transfer Protocol

πŸ“… published September 1984, from ietf

Simple File Transfer Protocol πŸŽ€

Okay bestie, this one is by Mark K. Lottor from MIT, dated September 1984. It's RFC 913 in the Network Working Group πŸ’… It's a proposed protocol for the ARPA-Internet community, and it's asking everyone for discussion and suggestions. It doesn't say it obsoletes or updates anything, so it's a fresh start 🌸

Status of This Memo ✨

This RFC suggests a proposed protocol for the ARPA-Internet community, and requests discussion and suggestions for improvements. Distribution of this memo is unlimited.

Introduction πŸ’–

SFTP is a simple file transfer protocol πŸ¦‹ It's for people who want something more useful than TFTP, but easier to build (and less powerful) than FTP. SFTP supports user access control, file transfers, directory listing, directory changing, file renaming, and deleting. Iconic, right?

SFTP can run on top of any reliable 8-bit byte stream oriented protocol, but this document describes its TCP specification. SFTP only uses one TCP connection πŸ™Œ Compare that to TFTP, which runs a connection over UDP, and FTP, which uses two TCP connections (one of them using the TELNET protocol). Main character energy, honestly πŸ‘‘

The Protocol 🧚

Okay, so you use SFTP by opening a TCP connection to the remote host's SFTP port, which is 115 decimal. Then you send SFTP commands and wait for replies. Commands sent to the remote server are always 4 ASCII letters (any case) followed by a space, the argument(s), and a <NULL>. The argument can sometimes be null, in which case the command is just the 4 characters followed by <NULL>. Replies from the server are always a response character, immediately followed by an ASCII message string that ends with a <NULL>. A reply can also be just a response character and a <NULL> πŸ’…

Here's the whole grammar, iykyk:

<command> : = <cmd> [<SPACE> <args>] <NULL>

<cmd> : =  USER ! ACCT ! PASS ! TYPE ! LIST ! CDIR
           KILL ! NAME ! DONE ! RETR ! STOR

<response> : = <response-code> [<message>] <NULL>

<response-code> : =  + | - |   | !

<message> can contain <CRLF>

The server replies to each command with one of the response codes listed under that command's message. The server should also optionally send back a message explaining the error in more detail. The example message texts are just examples, so you don't have to follow them. All characters in messages are ASCII 7-bit with the high-order bit zero, in an 8-bit field πŸŽ€

Here are the response codes and what they mean:

  • + Success.
  • - Error.
    • An error occurred while processing your command.
    • Number.
      • The number-sign is followed immediately by ASCII digits representing a decimal number.
  • ! Logged in.
    • You've sent enough info to log yourself in. This also means you've sent enough info to connect to a directory πŸ”‘

Greeting πŸ‘‹

To use SFTP, you first open a connection to the remote SFTP server. The server greets you with either a positive or a negative greeting, like:

+MIT-XX SFTP Service
-MIT-XX Out to Lunch

The first word should be the host name, btw. And if the server sends back a - response, it also closes the connection. Otherwise, you send a USER command next πŸ¦‹

USER πŸ™‹β€β™€οΈ

USER user-id

user-id is your userid on the remote system.

The reply to this will be one of these:

  • !<user-id> logged in: You don't need an account or password, or you gave a user-id that doesn't need them πŸŽ‰
  • +User-id valid, send account and password
  • -Invalid user-id, try again

If the remote system doesn't have user-ids, you should send some identification (like your personal name or host name) as the argument, and the remote system will reply with + 🌈

ACCT πŸ’Ό

ACCT account

account is the account you want to use on the remote system. It's usually used for billing πŸ’Έ

Valid replies are:

  • ! Account valid, logged-in: The account was ok or not needed. Skip the password.
  • +Account valid, send password: The account is ok or not needed. Send your password next.
  • -Invalid account, try again

PASS πŸ”

PASS password

password is your password on the remote system.

Valid replies are:

  • ! Logged in: The password is ok and you can start transferring files πŸš€
  • +Send account: The password is ok, but you haven't specified the account.
  • -Wrong password, try again

You can't specify any of the following commands until you get a ! response from the remote system. Wait for that vibe check first πŸ’…

TYPE 🎨

TYPE { A | B | C }

The type controls how the stored file gets mapped to the transmission byte stream. The default is binary if you don't specify a type 🧠

A - ASCII πŸ”€

The ASCII bytes are taken from the file on the source system, sent over the connection, and stored in the file on the destination system.

The data is 7-bit ASCII codes, sent in the low-order 7 bits of 8-bit bytes. The high-order bit of the transmission byte must be zero, and it doesn't need to be stored in the file.

The data is "NETASCII," and it follows the same rules as data sent on Telnet connections. The key thing here is that the local end-of-line gets converted to the pair of ASCII characters CR and LF when it's transmitted on the connection. Super important 🫢

Here's an example with TOPS-20 machines, which have 36-bit words. On TOPS-20, the standard way of labeling bits is 0 through 35, from high-order to low-order. The normal way of storing ASCII data on TOPS-20 is 5 7-bit bytes per word. In ASCII mode, the bytes transmitted would be:

[0-6], [7-13], [14-20], [21-27], [28-34]

Bit 35 wouldn't be transmitted. Each of these 7-bit quantities is sent as the low-order 7 bits of an 8-bit byte, with the high-order bit zero.

Another TOPS-20 example: one disk page of a TOPS-20 file is 512 36-bit words. But if you only use 35 bits per word for 7-bit bytes, a page is 17920 bits, or 2560 bytes πŸ“„

B - BINARY πŸ€–

The 8-bit bytes are taken from the file on the source system, sent over the connection, and stored in the file on the destination system.

The data is in 8-bit units. On systems with word sizes that aren't a multiple of 8, some bits of the word won't be transmitted πŸ™ƒ

For TOPS-20 machines (36-bit words), in binary mode the bytes transmitted would be:

[0-7], [8-15], [16-23], [24-31]

Bits 32-35 wouldn't be transmitted.

Another example: one disk page of a TOPS-20 file is 512 36-bit words. But if you only use 32 bits per word for 8-bit bytes, a page is 16384 bits, or 2048 bytes.

C - CONTINUOUS 🌊

The bits are taken from the file on the source system continuously, ignoring word boundaries, and sent over the connection packed into 8-bit bytes. The destination system stores the received bits into the file continuously, also ignoring word boundaries.

For systems with a word size that's a multiple of 8 bits, the implementation of binary and continuous modes should be identical.

TOPS-20 example (36-bit words). In continuous mode, the bytes transmitted would be:

[first word, bits 0-7], [first word, bits 8-15], [first word, bits 16-23],
[first word, bits 24-31], [first word, bits 32-35 + second word, bits 0-3],
[second word, bits 4-11], [second word, bits 12-19], [second word, bits 20-27],
[second word, bits 28-35], then the pattern repeats.

One disk page of a TOPS-20 file is 512 36-bit words. That's 18432 bits, or 2304 8-bit bytes 🧩

Replies are:

  • +Using { Ascii | Binary | Continuous } mode
  • -Type not valid
That's the end of part 1! TYPE is wrapped up, and we still have LIST, CDIR, KILL, NAME, DONE, and RETR to get through. Stay tuned, bestie πŸ’œβœ¨

The file then arrives as a stream of exactly the number of 8-bit bytes specified πŸ“¨βœ¨ When every byte has landed, control passes back to you, and the remote system is waiting for your next command πŸ’– If you don't receive a byte within a reasonable amount of time, you should abort the file transfer by closing the connection πŸ™ˆ

STOP (you don't have enough space to store the file) πŸ’€

Replies could be:

  • +ok, RETR aborted

You're then ready to send another command to the remote host πŸ¦‹

STOR { NEW | OLD | APP } file-spec

This tells the remote system to receive the following file and save it under that name πŸŽ€

Receiving a - should abort the STOR command sequence, and the server should wait for the next command 😭

NEW means it should create a new generation of the file and not delete the existing one 🌸

Replies could be:

  • +File exists, will create new generation of file
  • +File does not exist, will create new file
  • -File exists, but system doesn't support generations

OLD means it should write over the existing file, if any, or else create a new file with the specified name 🧚

Replies could be:

  • +Will write over old file
  • +Will create new file

(OLD should always return a +.)

APP means that what you send should be appended to the file on the remote site πŸ’œ If the file doesn't exist, it will be created.

Replies could be:

  • +Will append to file
  • +Will create file

(APP should always return a +.)

Then you send:

SIZE <number-of-bytes-in-file> (as ASCII digits)

where number-of-bytes-in-file is the exact number of 8-bit bytes you will be sending πŸ“

The remote system replies:

  • +ok, waiting for file

You then send the file as exactly the number of bytes specified above 🌈

When you're done, the remote system should reply:

  • +Saved <file-spec>
  • -Couldn't save because (reason)
  • -Not enough room, don't send it

This aborts the STOR sequence, and the server is waiting for your next command 😀

You're then ready to send another command to the remote host ✨


AN EXAMPLE πŸŽ€

Okay, here's an example file transfer! πŸ¦‹ S is the sender, the user process. R is the reply from the remote server. Remember, all server replies are terminated with <NULL>. If the reply is more than one line, each line ends with a <CRLF>. πŸ’…

   R: (listening for connection)
   S: (opens connection to R)
   R: +MIT-XX SFTP Service
   S: USER MKL
   R: +MKL ok, send password
   S: PASS foo
   R: ! MKL logged in
   S: LIST F PS: <MKL>
   R: +PS: <MKL>
      Small.File
      Large.File
   S: LIST V
   R: +PS: <MKL>
      Small.File  1        69(7)  P775240  2-Aug-84 20:08  MKL
      Large.File  100  255999(8)  P770000  9-Dec-84 06:04  MKL
   S: RETR SMALL.FILE
   R:  69
   S: SEND
   R: This is a small file, the file is sent without
      a terminating null.
   S: DONE
   R: +MIT-XX closing connection

Look at that transfer, it's so clean 🌈✨


EDITORS NOTE πŸ‘‘

Okay, bestie, the credit goes to Mark Lotter 🫢 He gets full credit for all the good ideas in this memo. As RFC editor, I made a number of format changes, a few wording changes, and one or two technical changes (mostly in the TYPEs). I accept full responsibility for any flaws I may have introduced πŸ™ˆ

A draft form of this memo was circulated for comments. I'll try to list the issues raised, summarize the pros and cons, and give the resolution for each πŸ“

ASCII Commands vs Binary Operation Codes

The ASCII command style is easier to debug, the extra programming cost is minimal, and the extra transmission cost is trivial πŸ“

Binary operation codes are more efficient, and a few days of debugging should not outweigh years of use 😀

Resolution: I have kept the ASCII Commands. πŸ’–

Additional Modes

Pro: For some machines you can't send all the bits in a word using this protocol. There should be some additional mode to allow it.

Con: Forget it, this is supposed to be SIMPLE file transfer. If you need those complex modes, use real FTP πŸ’€

Resolution: I have added the Continuous mode. 🌸

CRLF Conversion

Pro: In ASCII type, convert the local end-of-line indicator to CRLF on the way out of the host and onto the network.

Con: If you require that, you have to look at the bytes as you send them; otherwise you can just send them. Most of the time both sides will have the same end-of-line convention anyway. If someone needs a conversion, it can be done with a TECO macro separately 🧚

Resolution: I have required CRLF conversion in ASCII type. If you have the same kind of machines and the same end-of-line convention, you can avoid the extra cost of conversion by using the binary or continuous type ⭐

TCP Urgent

Pro: Use TCP Urgent to abort a transfer, instead of aborting the connection. Then one could retry the file, or try a different file, without having to log in again πŸ¦‹

Con: That would couple SFTP to TCP too much. SFTP is supposed to be able to work over any reliable 8-bit data stream πŸ’…

Resolution: I have not made use of TCP Urgent. πŸ™ˆ

Random Access

Pro: Wouldn't it be nice if (WIBNIF) SFTP had a way of accessing parts of a file? πŸ₯Ί

Con: Forget it, this is supposed to be SIMPLE file transfer. If you need random access, use real FTP (oops, real FTP doesn't have random access either -- invent another protocol?) πŸ’€

Resolution: I have not made any provision for Random Access. πŸ‘‘


-- jon postel. πŸ’œ

πŸ“¦ where this page comes from