   This file documents fsh, which provides fast and secure remote
command execution.

   Copyright (C) 1999-2001 Per Cederqvist.

   Permission is granted to make and distribute verbatim copies of this
manual provided the copyright notice and this permission notice are
preserved on all copies.

   Permission is granted to copy and distribute modified versions of
this manual under the conditions for verbatim copying, provided also
that the sections entitled "Copying" and "GNU General Public License"
are included exactly as in the original, and provided that the entire
resulting derived work is distributed under the terms of a permission
notice identical to this one.

   Permission is granted to copy and distribute translations of this
manual into another language, under the above conditions for modified
versions, except that this permission notice may be stated in a
translation approved by the Free Software Foundation.

Fsh
***

   This manual documents fsh version 1.2.

Introduction to fsh
*******************

   Remote command execution via a cryptographically strong method such
as `lsh' or `ssh' is often painfully slow, especially if either of the
involved computers is slow.  The biggest problem is that the client and
the server perform a lot of complex calculations during connection
establishment.

   `fsh' uses `lsh' or `ssh' to establish a secure tunnel to the remote
system.  This takes as long as a normal connection establishment, but
once the tunnel is established, `fsh' can reuse it to start new
sessions on the remote system almost instantaneously.  You get the
security of `ssh' and the speed of `rsh'.

   There are three programs at work.  `fshd' establish a tunnel to the
remote system.  It can use `lsh', `ssh' or even `rsh' to establish it.
It will start `in.fshd' on the remote system.  You can start `fshd'
manually, or allow `fsh' to do it automatically on an as-needed basis.

   `in.fshd' receives commands such as "create a new session running
the command `gcc foo.c', and call it session 3" or "send the following
data to standard input of session 5" via the tunnel.  You would
normally not interact directly with `in.fshd'.

   `fsh' is a drop-in replacement for `rsh'.  It connects to the local
`fshd' using a unix domain socket that is protected so that only the
user that started `fshd' can connect to it.  It uses `fshd' to forward
a request to `in.fshd', which will in turn start the requested program.

Invoking fshd
*************

   There is normally no need to invoke `fshd' manually, but it may be
useful for debugging purposes.  A typical invocation may look like one
of these:

     fshd sally.lysator.liu.se
     fshd -r lsh biffen.cendio.se
     fshd -l root biffen.cendio.se

   The `in.fshd' binary must be present in your path on the remote
system once you log in.

   If the connection is successful the message `Connection established'
will be displayed (unless the option `-b' was given).  This typically
takes a few seconds.  The tunnel is closed if you kill `fshd', or if no
session has used the tunnel for so long that a timeout is reached.

   The basic invocation syntax is:

     fshd [ options ] server

   `fshd' understands the following options:

`-r METHOD'
     The METHOD argument should be an `rsh'-compatible program.  The
     default value is `ssh'.

     The METHOD argument will be unquoted using the quoted-printable
     encoding, so if it contains an equal sign (`=') you have to write
     it as `=3D'.

`-l LOGIN'
     Specify the user name that should be used on the remote system.

`-b'
`--background'
     Tell fshd to detach from the controlling terminal and run in the
     background as soon as a connection to the remote system has been
     established.  This option is used by `fsh' when it auto-starts an
     `fshd'.  If this option is not given `fshd' will print some
     messages as connections are established.

`-T TIMEOUT'
`--timeout=TIMEOUT'
     If this instance of `fshd' has been unused for more than TIMEOUT
     seconds, `fshd' will terminate.  The default timeout can be set at
     configure time, but is normally ten hours.

     Use `--timeout=0' to disable the timeout.

Invoking fsh
************

   You can use `fsh' to connect to a remote system via a tunnel.  If no
`fshd' with the approriate options is running one will be started by
`fsh'.  The exit value of `fsh' will be the exit value of the command
that is executed remotely.

   The remote command will be executed via whatever `$SHELL' is set to
when the user logs in to the remote system.  It might be instructive to
run `fsh sally env' to see what the remote environment really looks
like.  If you do not like it, you should consult the documentation for
the underlying transport (such as `ssh')-`fsh' does not alter the
environment.

   Here are a few examples of how `fsh' can be used:

     fsh sally.lysator.liu.se echo hej
     fsh -r lsh biffen.cendio.se head -43 /etc/termcap
     fsh -l root -r lsh biffen.cendio.se head -43 /etc/termcap

   The basic invocation syntax is:

     fsh [ options ] server command args...

`-r METHOD'
     The `method' argument should be an `rsh'-compatible program.  The
     default value is `ssh'.

`-l LOGIN'
     The `login' argument specifies the user name that should be used on
     the remote system.

`-T TIMEOUT'
`--timeout=TIMEOUT'
     If there is no tunnel `fsh' will automatically start `fshd', and
     pass this option to `fshd'.  Once that `fshd' has been unused for
     more than TIMEOUT seconds, it will terminate.  The default timeout
     can be set at configure time, but is normally ten hours.

     Use `--timeout=0' to disable the timeout.

     This option is ignored if `fshd' is already running.

Invoking fcp
************

   You can use `fcp' to copy files to a remote system via a tunnel.

     fcp [scp-options] f1 f2
     fcp [scp-options] f1 f2... dir

   `fcp' is a very simple wrapper that starts `scp' with the `-S
path-to-ssh' argument, telling it to use `fshwrap', which is another
simple wrapper that gets rid of all flags that `ssh' accepts but `fsh'
doesn't implement, and then calls `fsh'.

   The net result is that you can use `fcp' as you use `scp', for most
uses, but sometimes all these wrappers might get in the way.  See the
`scp' documentation for information about the flags that `scp' accepts.

Sample application: CVS
***********************

   The reason why `fsh' was written was to make it possible to use
remote CVS fast and securely.  This chapter outlines all necessary steps
towards that end.  It is assumed that you already have a working CVS
repository on a server, and that CVS is installed on the client as well.

   * Install `fsh' on the server and client.  Make sure it exists in
     your default path.

   * Test that you really can log in to the server from the client.

          bash$ ssh server.domain echo it is working
          it is working
          bash$

     You may have to enter a password or passphrase.  That is OK.

   * Make sure that `in.fshd' is found when you log in to the server.

          bash$ ssh server.domain in.fshd
          fsh 1

     You may have to enter a password or passphrase.  That is OK.

     Once you receive the line `fsh 1' you can press end-of-file to end
     the session.

   * Start a tunnel to the remote system.

          bash$ fshd server.domain
          Connection established

     This step is not really necessary, but since your are reading this
     you probably have a problem with your connection.  Running `fshd'
     manually may help troubleshooting any problem you have.

     You may have to enter a password or passphrase.  That is OK.

   * Switch to another screen (or virtual console, or xterm, or
     whatever) on the client.  Set the environment variable `CVS_RSH'
     to the value FSH:

          bash$ export CVS_RSH=fsh

   * Run cvs to export a module.

          bash$ cvs -d server.domain:/path/to/cvs/repository co module-name

   * Access the module and experience the speed.

          bash$ cd module-name
          bash$ cvs log foo.c
          bash$ cvs status bar.c

     If you switch back to the screen running `fshd', you will notice
     that a few lines of texts was written each time a remote command
     was executed.

   If you are using a modem or a slow internet connection to connect to
the remote server, you probably want to use `Compression' in
`.ssh/config'.  See ssh(1).

Reporting bugs
**************

   Bugs should preferably be reported using the Bugzilla installation at
<http://bugzilla.lysator.liu.se/>.  You can also query Bugzilla for
known bugs.

   Bugs can also be reported to <fsh-bugs@lists.lysator.liu.se>, if for
some reason you cannot use Bugzilla.  If you don't want the bug report
to be public you can try <ceder@lysator.liu.se> instead.  Expect a
response time of at least one to two weeks.  I have been known to reply
to mail after a couple of years in the past.

   Before you report a bug, please check if there is a new release
available first.  The home page of `fsh' is
<http://www.lysator.liu.se/fsh/>.  You can find info about the fsh
mailing lists there as well.

The remote protocol
*******************

   This chapter documents the protocol between `fshd' and `in.fshd'.
This protocol is normally only of interest to the developer of `fsh',
and may be a little out of date.

   In the description below, `fshd' is the client and `in.fshd' is the
server.  You can try out the protocol manually if you like by starting
`in.fshd' interactively.  In the example, the text that is output by
`in.fshd' appears after the print symbol `-|'.

     bash$ in.fshd
      -| fsh 1
     new 2 8Hcat -vet
     stdin 2 4Hfoo

      -| stdout 2 5Hfoo$
      -|
     eof-stdin 2
      -| eof-stdout 2
      -| eof-stderr 2
      -| exit 2 1H0
      -| eos 2

Basic syntax
============

   The protocol assumes an 8-bit-clean connection.  All commands (except
the initial greeting) have the same overall structure.  This protocol
uses ASCII, but it is capable of transmitting any byte-stream.  This is
the overall structure:

   * The command name (a string).

   * A space.

   * The session number, coded as a decimal string.

   * A space, if there is a data chunk.

   * An optional data chunk, coded as the length (expressed as a decimal
     string), the ASCII letter `H', and the data.  The data may contain
     any character, including NULs and newlines.

   * A newline.

   Some commands require the data chunk, while others don't allow it.
There is no command that only uses a data chunk sometimes.

Connection establishment
========================

   The server starts by sending a greeting to the client.  This is the
only thing that doesn't adhere to the basic syntax.  It contains the
word `fsh' followed by the version number of the protocol, which is 1.
The client does not respond.

     fsh 1

Session management
==================

   Each remote command that should be executed is contained in a
session.  There can be several simultaneous sessions.  The client
associates each session with a unique session id, which is an integer.

   A new session is created by sending a `new' command to the server.

     new SESSION-ID COMMAND

   The COMMAND is a string, suitable to pass to whatever `$SHELL' is
set to on the remote system.

   Once a session is established data can be sent by either the client
or the server.  The client uses `stdin' to send data.  The server uses
`stdout' or `stderr'.  The format of these three commands is the same:

     stdin SESSION-ID STRLENHDATA
     stdout SESSION-ID STRLENHDATA
     stderr SESSION-ID STRLENHDATA

   STRLEN is a decimal string, that specifies how long DATA is.  The
DATA can contain any byte, including NUL, newline and carriage return.

   The client can send signals to the session:

     signal SESSION-ID SIGNAL-NAME

   The following values are defined for SIGNAL-NAME:

   * HUP

   * INT

   * QUIT

   * ILL

   * TRAP

   * IOT

   * BUS

   * FPE

   * KILL

   * USR1

   * SEGV

   * USR2

   * PIPE

   * ALRM

   * TERM

   * CHLD

   * CONT

   * STOP

   * TSTP

   * TTIN

   * TTOU

   * URG

   * XCPU

   * XFSZ

   * VTALRM

   * PROF

   * WINCH

   * IO

   * PWR

   End-of-file can be specified for each of the three data channels
separately:

     eof-stdin SESSION-ID
     eof-stdout SESSION-ID
     eof-stderr SESSION-ID

   When the child dies the server will send the exit status to the
client.

     exit SESSION-ID EXIT-STATUS
     signal-exit SESSION-ID SIGNAL-NAME

Session termination
===================

   The server always sends an end-of-session to the client when it
discards a session.

     eos SESSION-ID

   The `eos' will be generated spontaneously by the server when it has
sent `eof-stdout', `eof-stderr' and one of `exit' or `signal-exit'.
The client should never reuse a session id until it has seen an `eos'
from the server.

   The client can also request that the session is terminated by
sending an `eos' to the server.  This should only be used in abnormal
situations, such as if the fsh program responsible for this session
unexpectedly died (indicating that there is nobody awaiting the result
of the program).  When the server receives an `eos' it will kill the
program (with something similar to `kill -KILL PID') if it is alive,
close all ptys to the program (without trying to drain them), and send
back an `eos' response to the client as confirmation.

Flow control
============

   To avoid pileup of unprocessed data in the endpoints (stdin data in
`in.fshd' and stdout/stderr data in `fsh') a strict flow control
protocol must be adhered to.

   When a session is created it is initially allowed to send 128 KB
(that is, 131072 bytes) to the stdin of the remote system.  When it
receives an `stdin-flow' statement the limit is increased to the value
sent in it.  The `fsh' process is responsible for counting the bytes and
pause if it doesn't receive an `stdin-flow' statement in time.  The
`in.fshd' process is responsible for sending `stdin-flow' statements.
They should ideally be sent in advance, so that `in.fshd' always
maintains a buffer of pending input to the process.

   Similarly, `in.fshd' may only send 128 KB of stdout data and 128 KB
of stderr data, until it receives `stdout-flow' and `stderr-flow'
commands from `fsh'.

     stdin-flow session-no new-limit
     stdout-flow session-no new-limit
     stderr-flow session-no new-limit

   Please note that `fshd' is not directly involved in the flow control
protocol.  It only relays messages between all the `fsh' processes an
the `in.fshd' process.

   These limits exists so that both `in.fshd' and all `fsh' processes
always should be able to read anything that `fshd' wants to send to
them.  The initially allowed window of 128 KB is included so that a new
session can start sending data at once, without a need for any
round-trip delay.

The local protocol
******************

   The protocol used between `fsh' and `fshd' is identicaly to the
remote protocol, with one exception: there is no session number.

   `fshd' creates an AF_UNIX socket in
`/tmp/fshd-UID/SERVER.METHOD.LOGIN' (with funny characters encoded with
a QP-like encoding).  The protection of `/tmp/fshd-UID' is set so that
it is only accessible by the user with the proper uid.