Which protocol carries a file is a property of the client at the other end. macOS and Windows reach for SMB, a Linux fleet already has NFS, a browser or a phone has HTTP. Running four servers, each with its own configuration and its own idea of who alice is, is a way to get three of them subtly wrong. Pure Go, CGO_ENABLED=0. BSD-3-Clause.
# which protocols this binary actually has โ ask it $ fileshare --protocol nope -i photos.img -u alice -p pw fileshare: --protocol names none this binary has: it has nfs, s3, sftp, smb and webdav # what it would serve, and to whom, before a restart $ fileshare check -c fileshare.hcl this configuration can be served
fileshare check opens every image and prints every share against every protocol, and every person against every protocol. The matrix below is real output, with nothing edited but the width of this page.
FILESHARE SHARE IMAGE FILESYSTEM WHO MAY CONNECT WHO MAY WRITE SMB NFS WEBDAV SFTP S3 photos /tmp/srv/photos.img fat32 alice alice yes NO yes yes yes public /tmp/srv/pub.img fat32 anyone who authenticates anyone who authenticates yes yes yes yes yes photos is not served over nfs: it is restricted to alice, and NFSv3 on its own has no authentication: AUTH_UNIX is a claim the client makes about itself and the wire cannot disagree with it. A kerberos block lifts this: sec=krb5 carries a principal a ticket proves; so does identity = "certificate" on the nfs serve block: RPC-over-TLS with a client certificate naming the person USER FROM AUTHENTICATES WITH SMB WEBDAV SFTP S3 alice the configuration file a password from /tmp/srv/pw yes yes - yes bob the configuration file 1 key - - yes - this configuration can be served
That is a fact about the protocols, not a limitation here. What a person can be served over depends on what the directory holds for them โ so the honest thing is to compute that matrix and print it, rather than leave it to be discovered at a mount.
SMB needs NTLMv2, so it needs the password or its MD4(UTF16LE(password)). S3 needs the password itself, because SigV4 is an HMAC computed from it. SFTP takes a public key or a certificate. A person holding only a key reaches SFTP and nothing else.
A share that names who may use it is not exported over NFS. A configuration saying photos belongs to alice and a protocol handing photos to whoever connects cannot both be honoured, and quietly widening access is the worse of the two failures.
A kerberos block gives NFS something to check: sec=krb5 carries a principal a ticket proves, rather than a uid the client asserts. The realm is compared, not just the name before the @ โ two realms can each have an alice. Or identity = "certificate": RPC-over-TLS, and the person named in the client certificate, checked against its CRL at every call.
fileshare check opens every image and prints every share against every protocol and every person against every protocol. A name that belongs to no user block is refused at startup rather than locking Alice out of her own share.
fat32, exfat, ext4, ntfs, ufs, iso9660, squashfs and hfs+, with apfs, btrfs, xfs and zfs by partition โ read by go-filesystems. Every protocol shares that one open image behind one lock. A block device works the same way, and a directory is served through an os.Root, so a link out of it is refused by the kernel.
Through the admin API, a privileged fileshare provisioner creates volumes โ ZFS datasets, btrfs subvolumes, XFS and ext4 directories under a project quota, by go-fsctl โ and the server, which holds no privilege, serves shares from them. It refuses to serve one as root or with CAP_SYS_RESOURCE, which ext4 lets past the quota. Linux only; no Ceph yet.
An oidc block admits the people an identity provider vouches for โ such as go-authn/bridge in front of a SAML federation: a token over WebDAV, the provider's SSH certificate or an opkssh one over SFTP, a client certificate over NFS. Shares name its groups and domains. Certificates from the EuroHPC SSH CA can be filtered too. With ssh_domains, a certificate is accepted only where its domain grant names this host, and only from the addresses it is pinned to. That covers the CA itself and bridge issuing in its profile.
The provider's KRL and CRL are fetched, their signatures and expiry verified, never taken older than the one held โ across a restart too. A CAEP session-revoked over shared signals voids what no list can name. A list that cannot be had refuses, rather than lets everyone through.
Samba's smbclient, macOS's Finder, Windows' own redirector, OpenSSH's sftp, mount_nfs. A fixture built from one reading of a protocol can only confirm that reading โ which is how the one defect only Windows could find was found.
smbNTLMv2. Needs the password, or its MD4(UTF16LE(password)) โ an NT hash is enough, and is what a directory should hold if SMB is all it serves.
nfsNothing, on its own. AUTH_UNIX is a claim the client makes about itself and the wire cannot disagree with it โ so a restricted share is not exported here at all, unless a kerberos block gives it sec=krb5, or identity = "certificate" takes the person from a client certificate over RPC-over-TLS (RFC 9289).
webdavHTTP Basic, or a bearer token an identity provider signed. The most forgiving of the five: a verifier the directory can only check is enough.
sftpA public key or a certificate: one a trusted CA signed, the identity provider’s own, or an OpenPubkey (opkssh) one. Somebody with only authorized_keys reaches SFTP and none of the others โ and somebody with only a password does not reach it.
s3A SigV4 signature: an HMAC computed from the secret, which therefore has to be the password itself and not a hash of it. A share is a bucket.
Written once in Go with go-widgets: the same code is a page served by the portal and a native window. The console and the explorer are each tested in headless Chrome, behind the real portal binary, in front of real fileshare binaries.
portal v0.3.1The server behind the UIs. It logs a person in (OIDC), keeps the session in encrypted cookies, holds a token per fileshare server, and passes the admin API (Connect) and WebDAV through. The page never sees a token. Files are served inert: a document on a share cannot run as the portal.
console v0.3.2The admin console: shares, grants, volumes and server state on every fileshare server a portal knows, from one page. It runs in a browser behind the portal, or as a native window that logs in through the system browser.
explorer v0.3.0The file explorer: browse, upload, download, rename, copy and delete. Uploads go in pieces, so a browser never holds a whole file, and one that fails resumes where it stopped – by the same file only. A rename never replaces a file already there, and a delete takes two presses. In a browser behind the portal, or as a native window that logs in through the system browser.
fileshareNo cgo, no frameworks, no runtime to install. A build tag leaves a protocol out of the binary entirely, and --isolate gives each one its own process, opening only the images it may serve. The people can come from a user block, a database or LDAP โ the same users block authnd reads, so a site describes its directory once โ or from an identity provider. Shares can be changed live through a gRPC admin API, and TLS comes from files or ACME.