Short: Lightweight TCP/IP network file server and mounter
Author: Timm S. Mueller, Claude Sonnet
Uploader: tmueller@schulze-mueller.de
Type: comm/tcp
Version: 1.2pre1
Architecture: m68k-amigaos, Unixoid (Linux, FreeBSD, macOS, etc.)


Overview
--------------------------------------------------------------------------

Fitz is a lightweight TCP/IP network file server and mounter.

No configuration files, no daemons, no hassle - just a single command
line program for sharing and mounting directories ad-hoc style.

For use on trusted LANs - at home behind a NAT gateway, in guest
networks that you can trust, or via SSH tunnel or VPN. Also use
the READONLY option when appropriate.

Currently supported: Amiga, Unixoid (FUSE3 for mounting e.g. on
Linux, FreeBSD, macOS)

Fitz goes both ways: You can share and mount - on all supported
platforms, both directions are supported. So of course you can share
an Amiga directory with other Amigas. You can run as many instances
as you like. There is no central server.

Fitz supports Amiga case-insensitive filenames, permission bits and
comments, not only when serving from an Amiga, but from Unix servers
as well. Support (through xattrs) is provided for Linux, FreeBSD,
macOS and probably others, and the required capabilities are detected
and negotiated with clients at runtime.


Simplest possible use
--------------------------------------------------------------------------

It's really very simple. Assume you have three computers in your home
network, the Amigas named atze and keule, and the Linux machine lotte:

keule # fitz serve RAM:

atze # fitz mount keule KEULE:

lotte $ mkdir ~/keule
lotte $ fitz mount keule ~/keule

lotte $ mkdir ~/shared
lotte $ fitz serve ~/shared

atze # fitz mount lotte LOTTE:

keule # fitz mount lotte LOTTE:


Requirements
--------------------------------------------------------------------------

Amiga:
OS >= v37, bsdsocket.library v3, 68000 CPU

POSIX/FUSE, build requirements:
gcc or clang, FUSE3 library and headers (libfuse3-dev/fuse3-devel),
pkg-config, pthreads. Use macFUSE on macOS. If your OS does not support
FUSE for mounting, you may still try running the server, as it is largely
POSIX compliant with just a few additional code paths for xattrs support. 


Build and install
--------------------------------------------------------------------------

On Amiga, just:

  # copy fitz C:

On macOS, install macFUSE:

  $ brew install macfuse
  
On Unixoid fitz goes into /usr/local/bin:

  $ make all
  $ sudo make install
  
Building for Amiga requires the vbcc toolchain:

  $ make amiga

Use 'make help' to see a list of targets.


Getting started
--------------------------------------------------------------------------

1. Start by sharing an empty directory.

2. Make sure you don't expose a share on a host or network interface
that is reachable from untrusted networks, such as the internet.
Typically it is safe to use behind a home router which is also a NAT
gateway, but make sure that this is the case.

3. Copy the things to share into the shared directory. By default,
clients have no means to create links inside a share, but if you place
symlinks in a share, these can be traversed by clients, even if they
cannot create them or resolve them to their actual paths.

4. When there is no need for clients to write to a share, use the
read-only option, so data can't be devastated, not even by accident.

5. You can enable a thin layer of security by specifying ASKPASS in the
server command line. This will prompt you for a password, and clients
will be prompted for that password as well. Authentication implies
encryption. You can also specify ENCRYPT in the command lines of either
server or client, which will require encryption from the other side -
even without authentication. See also Encryption for more details.


Usage
--------------------------------------------------------------------------

Share a directory:

  $ fitz serve [rootdir] [PORT num] [RO] [IFACE addr[:port]] [ASKPASS]
               [SERVICE name]
  Amiga:
  # fitz serve [rootdir] [PORT num] [RO] [IFACE addr[:port]] [ASKPASS]
               [SERVICE name] [TZOFFS sec]

  rootdir defaults to the current directory.
  PORT num defaults to 17711.
  Keyword RO (or --readonly) rejects all write operations.
  IFACE (or --interface) binds to a specific address (e.g. 127.0.0.1),
  and optionally a port number. If not specified, the server binds to all
  of the machine's interfaces.
  TZOFFS (Amiga only) specifies a time zone offset in seconds, see below.
  ASKPASS will prompt for a password that clients will be required to
  specify, too.
  SERVICE will give the service a name. With this option, several named
  services can coexist on a machine without you to remember port numbers.

  Examples:
  $ fitz serve                        share current directory
  $ fitz serve /home/shared           share a specific directory
  # fitz serve RAM: service ramdisk   share RAM:, service name "ramdisk"
  $ fitz serve /srv/pub port 8888     share on a different port
  # fitz serve SYS:T RO TZOFFS 7200   read-only share, CEST (Amiga)
  $ fitz serve iface 127.0.0.1:6666   localhost only
  # fitz serve df0: askpass           serve df0:, with password
  $ fitz serve encrypt                require encryption from clients

Mount a share (client side):

  # fitz mount host[:/name] [VOLNAME] [OH] [LOCKING] [ENCRYPT] [TZOFFS sec]
  Unix:
  $ fitz mount host[:/name] mountpoint [OH] [ENCRYPT] [fuse-args]

  host[:/name] can be just a host name, a hostname:/servicename, or a
  host:port combination.
  mountpoint must exist and should be an empty directory.
  OH (or --omithidden) hides dot-files from listings (still accessible).
  LOCKING enables client-side locking (Amiga only).
  fuse-args are additional arguments passed to FUSE.
  ENCRYPT or CIPHER=name will require encryption - which can be
  opportunistic (no authentication).

  The client reconnects automatically if the server restarts; operations
  block during reconnect and resume transparently (open files excepted).

  Examples:
  # fitz mount hostname:/service      mount to FITZ: (Amiga)
  # fitz mount klappstulle NETZ:      mount klappstulle to NETZ: (Amiga)
  $ fitz mount 192.168.1.5:8888 ~/net mount 192.168.1.5:8888 to ~/net
  $ fitz mount a1200 ~/net -f         mount a1200, running in foreground
  $ fitz mount NEED=unix server       require the "unix" capability
  # fitz mount server encrypt         require encryption from the server
  
  Unmount on Unixoid:
  $ umount ~/net
  $ fusermount3 -u ~/net              if needed (I don't)

  Unmount on Amiga:
  press CTRL-C or send a break signal.


Amiga-specific notes
--------------------------------------------------------------------------

- A good place for setting up shares on an Amiga is in
AmiTCP:db/user-startnet, e.g.:

run <>NIL: fitz mount hostname SHARE: tzoffs 7200

With this method shares can come up and go away by starting and
stopping the network.
 
- For correct timestamps on Amiga, use the TZOFFS argument to
normalise time towards UTC. The server always carries timestamps in
UTC. The offset is specified in seconds. If your Amiga is running in
CEST, you would specify TZOFFS 7200 for both clients and servers
running on this Amiga. (Ideally you get the system time per NTP sync,
and calculate TZOFFS with some help from TZUtil or similar.)

- The best way to specify TZOFFS is by having an ENV variable 'TZOFFS'
with the timezone offset in seconds, which will be honoured by client
and server automatically.

- On the Amiga client side, use the option LOCKING/S to enable full
file-lock semantics locally, per client mount. No locking goes over
the wire protocol and so isn't enforced between remote clients, only
between applications on the same Amiga.

- OH (--omithidden) can give confusing results when recursively deleting
directories which are not empty due to invisible dot-files.

- Remember that you will probably want to include xattrs for backups
and copies of Amiga directories on a Unix server with cp, rsync, tar.


Capability management:
--------------------------------------------------------------------------

The protocols and defaults are adjusted in such way that things are
expected to just work, hopefully. For more insight and control over
your mounted filesystems, show a server's protocol and capabilities:

  # fitz query hostname
  
With the arguments USE and NEED you can request server capabilities
opportunistically or strictly. For example, USE=amiga-case would use
a server's offer of Amiga-style case insensitive file names. The same
with NEED=amiga-case, but mounting would fail if the server cannot
provide the requested feature.
  
Amiga servers offer (and Amiga clients by default use)
"iso-8859-1,amiga-case,amiga-comment,amiga-flags".
Unix servers offer "unix,case,amiga-case" (and possibly a few more),
and additionally "amiga-comment,amiga-flags" (given the required
support). Unix clients by default use the capabilities "unix,case".
  
So by default Amiga clients get case-insensitive names, Amiga comments
and file flags even from Unix servers, provided that the server and
filesystem can support them - and fall back to  'Unix-like' verbatim
filenames and no support for comments and special Amiga file flags.
If you strictly require them, you would specify
NEED=amiga-case,amiga-comment,amiga-flags.
  
Unix servers and clients talk to each other in a pretty standard
way, except for that chown and chgrp are not supported by the
protocol.
  

Encryption
--------------------------------------------------------------------------

1. By default, connections are NOT authenticated and NOT encrypted.
2. Authentication always implies encryption of the data stream. 
3. The data stream can also be encrypted opportunistically, without
prior authentication.
4. If you use passwords or request encryption, encryption is rather
solid - but it can be prohibitively slow on a 7MHz 68000.
5. You can request a weaker than the default cipher - which might be
sufficient to obfuscate the data on the network for casual attackers.
6. Weaker ciphers do not mean weaker authentication.

Authentication is BLAKE2-MAC, and stream cipher is SPECK64 big endian.
Of course this unusual combination is geared towards slow Amigas.
"So the NSA will be able to read my traffic?", you may ask. The answer
is: Yes, most probably, and SPECK64 is but one of the many reasons.

Really, if you mistrust it - and you have every reason to - then don't
use it, as it also degrades performance. Ensure security by not exposing
Fitz to untrusted networks, use it only at home behind a NAT gateway, in
guest networks that you can trust, or via SSH tunnel or VPN.

The original intent was just to obfuscate the data rather than to
encrypt it by modern standards - so it won't get picked up too easily
with packet sniffing.

Use the ENCRYPT keyword to make sure that the traffic will be encrypted.
Clients, if required to encrypt, will pick the first from the server's
list of possible ciphers. Use CIPHER=name to choose another.

Here are some examples:

$ fitz serve nocrypt   - deny clients encryption
$ fitz serve askpass   - prompt server (and clients) for password
$ fitz serve encrypt   - require (opportunistic) encryption from clients
$ fitz mount encrypt   - require (opportunistic) encryption from server
$ fitz serve password xxx    - use the given password as the secret
$ fitz mount password xxx    - use the given password as the secret
$ fitz serve secret filename - use secret from file (max. 1024 bytes)
$ fitz mount secret filename - use secret from file (max. 1024 bytes)

Get a list of ciphers offered by a server with the 'query' command.
You can also change the list of ciphers offered to clients:
$ fitz serve cipher=speck64-27,speck64-11

Clients are still free to use no encryption at all - use the 'encrypt'
keyword at the server to enforce it:
$ fitz serve cipher=speck64-27 encrypt

Clients can also choose one from the offered ciphers:
$ fitz mount cipher=speck64-11


Disclaimer
--------------------------------------------------------------------------

See also COPYRIGHT.

The only thing that can be guaranteed is that it can corrupt your
data, silently, when you least expect it.

Consider everything here experimental, and don't entrust it important
data that you cannot recover.


Rationale
--------------------------------------------------------------------------

Created for lack of a better tool.

Samba: The smbfs mounter on Amiga is great. But the Samba server is a
pile of bloat and obsolescence, and a nuisance to configure. You are
building megabytes of cruft, and then try to make sense of weird
compatibility options to disable 95% of that. And you keep wondering
when your distribution will finally drop them for godawful security -
which you couldn't care less about in your home network.

NFS: ch_nfsmount on Amiga is great. NFSv2 is fast and easy to setup -
for the 1993 Unix aficionado. In the kernel you enable options nobody
has bothered to switch on in a decade or two. The NFSv2 userland
support, which any sane distribution has abandoned a long time ago,
you build yourself from sources you picked up in a back-alley
scrapyard on the internet. After that it's awesome.

I haven't tried many newer mounters (NFSv3, possibly some other for
Samba). What I've found is that I had to write mount list entries, so
shares cannot be terminated by the break signal, and the network stack
cannot remove them automatically. And then it still doesn't work the
other way round - and setting up a Samba or NFS server on an Amiga
would be even more insane.

ch_nfsmount and smbfs show how it's done: They are not handlers that
go into L:, but are started as regular programs that provide the
volumes dynamically, and so go away when the break signal arrives.
That way starting/stopping the network can bring up and remove shares
naturally and cleanly.

These were the reasons why I wanted to write such a thing for a long
time. Now with the arrival of some modern programming languages
(English) and methods (betreutes Coden) I found a good reason to give
these things a try and craft it in exactly the way I wanted.

The result is an Amiga binary about 70k in size which is both server
and client, and works swiftly and nicely even on an Amiga 500. With
it I can not only mount my Unix machines, but even the smallest
Amigas can exchange data with each other. Of course you can also
use it for sharing a directory on your laptop in a guest LAN - for
you and your friends to collaborate on some project.


Authors
--------------------------------------------------------------------------

- Timm S. Mueller <tmueller et schulze-mueller piste de>
  Concept, architecture, testing, refactoring, documentation
  
- Claude Sonnet
  Coding, test-bedding, interface and architecture consulting

No emulators were harmed during development.

