v0.5.0
Adds the smb package: an embeddable SMB2/SMB3 server that makes a Go application mountable by Windows Explorer and the macOS Finder without an installed agent.
New: the smb package, experimental
smb.Server serves one disk share from a facetfs.FileSystem on listeners and connections the application binds. The package speaks dialects 2.1 and 3.1.1 over direct TCP and implements session setup, tree and handle lifetime, create/read/write/flush/close, share modes, byte-range locks, directory enumeration with DOS wildcards, metadata queries and changes, and FSCTL_VALIDATE_NEGOTIATE_INFO.
server := &smb.Server{
FileSystem: served,
Authenticator: credentials, // answers: what is the NT hash of this user
ShareName: "share",
}
log.Fatal(server.Serve(ctx, listener))Authentication keeps the credential split. No package in this module verifies a credential, but SMB derives the key that signs every message from the NTLM exchange, so the package cannot delegate the exchange. The split is drawn one level lower: the application owns the credential store and answers one question — the NT hash of a user — and the package owns the protocol: the challenge, the constant-time comparison, and the key derivation. smb.NTHash derives the stored value from a password.
Signing, not encryption. Every message of a signing session is signed on its own — HMAC-SHA256 for 2.1, AES-128-CMAC for 3.1.1 with the SP 800-108 key derivation over the pre-authentication integrity hash. Each message of a compound chain carries its own signature, as [MS-SMB2] requires. Encryption is not implemented and not advertised, so the transport is not confidential: serve it on a trusted network.
The SMB1 clients get one answer. Windows Explorer and the macOS Finder open every connection with an SMB1 multi-protocol negotiate by default. The server answers that one message in SMB2 with the wildcard revision, and the client negotiates again in SMB2. Nothing else of SMB1 exists in the package — the server reads one dialect list and refuses every other SMB1 frame.
Every client-controlled allocation is bounded. Frame sizes, chain lengths, credits, dialect lists, contexts, security buffers, paths, lock batches, and handles per session all have fixed limits. Every offset and length pair from the wire passes one validated accessor. Four fuzz targets drive the frame walk, the transport, the negotiation, and the NTLM and path decoders, and make fuzz runs them.
Why experimental: the protocol and race suites pass, but the acceptance matrix against real Windows, macOS, and Linux clients has not yet run. The notice drops when it has.
Benchmarks
make bench now measures the smb package, and a new make bench-protocols compares warm, end-to-end operations — one metadata lookup, one full-file read, one full-file write — through NFSv4, SFTP, and WebDAV against the same in-memory filesystem over loopback.
The SMB numbers include what a default modern client session actually costs: four MAC passes over every payload (both sides sign, both sides verify) and the open–transfer–close round trips of the protocol. The other packages exclude their transport crypto, because SSH and TLS belong to the application; SMB signing belongs to this package.
Also
examples/smbserves a directory with one user from environment variables.- Byte-range locks are advisory, as in every other package here: the contract cannot mediate local access, and the documentation says so.